| Age | Commit message (Collapse) | Author |
|
When removing markdown inbox extras (embedded local images), os.Remove errors
were silently ignored. If removal failed, the image remained in the inbox and
was later published as a standalone image post.
- Check os.Remove errors and return a wrapped error.
- Rollback the already-saved post directory when extra removal fails.
- Deduplicate extras to avoid failing on duplicate references (e.g. same image
referenced twice in one markdown).
- Add a negative test that verifies the error is returned and no post is
persisted when removing an embedded image fails.
Fixes duplicate image posts caused by leftover inbox extras.
|
|
atom.Generate, syncOutput)
- generator.Run(ctx, cfg) – ctx passed through to atom.Generate
- processor.Run(ctx, cfg) – signature updated for cancellation propagation
- atom.Generate(ctx, posts, cfg) – accepts ctx for future cancellation
- syncOutput(ctx, cfg) – rsync subprocesses now use exec.CommandContext
- Updated all call sites in tests, cmd/snonux/main.go, and integration tests
- All call sites pass context.Background() / context.TODO()
All tests pass: go test ./...
|
|
Replace the large, duplicate switch statements in planPost and commitPlan
with a PostBuilder interface registered per file extension.
- PostBuilder interface: Plan(srcPath, ext) (postPlan, error) and
Commit(plan, postDir, id, now) (*post.Post, []string, error)
- Per-type builders: txtBuilder, mdBuilder, imageBuilder, audioBuilder.
- Each builder self-registers via init() into a map[string]PostBuilder.
- Core processor loops are now extension-agnostic, satisfying OCP/DIP.
- All existing tests pass.
|
|
Introduce postPlan to capture everything validated in Phase 1 before
any filesystem mutation occurs. Phase 1 scans the inbox, validates all
source files (parses text, markdown, image, audio), checks markdown
image claims for conflicts, and collects a plan per item. Phase 2
commits mutations only after every plan is validated: creates post
directories, writes assets, persists post.json, and removes sources.
If Phase 1 fails (e.g. unsupported file, missing markdown image, claim
conflict), no mutations occur and the inbox is left untouched. Roll
back the partial post directory if a mutation fails during commit.
Also refactor image and audio sub-processors into validation-only and
write-only parts (validateImage/writeImageAsset, validateAudio/copyFile)
so that Phase 1 is strictly read-only.
All existing tests pass.
|
|
The pre-scan claimedByMarkdown used to mark an image as claimed by any
markdown that referenced it, but it did not prevent two different markdown
files from referencing the same image. When that happened, the first file
processed would copy the image into its post directory and then delete it
from the inbox. The second file then failed because the source image was
already gone.
Fix: make image claiming exclusive. claimedByMarkdown now tracks the
owning markdown filename for each claimed image and returns an error
immediately during the pre-scan if a conflict is detected. This way no
sources are removed and no partial posts are created.
Also add tests:
- twoMarkdownsClaimingSameImageFails (negative)
- duplicateImageClaimsInSameMarkdownAllowed (positive)
|
|
findLocalImages used filepath.Base(ref) after stat succeeded, which
caused subdirectory or parent-directory references to pass the scan but
then fail during copy because the basename was looked up in the wrong
directory.
Fix: add isSimpleImageRef helper that accepts only flat filenames (no
path separators, no .. traversal). findLocalImages now returns the ref
unchanged, matching what copyLocalImages and claimedByMarkdown expect.
Added tests for isSimpleImageRef and negative findLocalImages cases for
subdirectory and parent-directory references.
|
|
Previously, uniqueID(postsDir, t) returned only a string and looped
forever when os.Stat returned an error other than IsNotExist
(e.g. permission denied). Change the signature to (string, error),
propagate the error, and update the caller in processFile to handle
it. Add positive and negative tests covering new ID generation,
suffix collision, and permission-based stat failure.
|
|
Amp-Thread-ID: https://ampcode.com/threads/T-019d94cc-99a9-74af-8f3d-9521cd73324f
Co-authored-by: Amp <amp@ampcode.com>
|
|
Testable CLI flags; version package under internal/version; broad tests for
atom, generator, post, processor, and cmd—overall coverage ~85%.
Made-with: Cursor
|
|
Clarify in package comment and Run docstring that files are processed in
order, successful sources are removed before later files run, and on error
the returned count reflects posts already created.
Made-with: Cursor
|
|
Markdown uses goldmark html.WithUnsafe for intentional raw HTML in
personal-inbox posts. Package and processMd comments state the trust
model and warn against untrusted input on the same path.
Made-with: Cursor
|
|
claimedByMarkdown now wraps os.ReadFile failures instead of skipping,
so Run fails fast and avoids wrong image claim state. Add regression
test using an unreadable markdown file (Unix).
Made-with: Cursor
|
|
Cover NewID; txt autolink helpers; markdown local image discovery;
pagination, page filenames, JSON script literals, time formatting,
and buildPageData nav links.
Made-with: Cursor
|
|
buildMarkdownPost no longer removes referenced images during build.
buildPost returns inboxExtras paths; processFile removes them after
p.Save(postDir) succeeds, matching source file deletion ordering and
avoiding loss of originals if Save fails.
Made-with: Cursor
|
|
Full Go implementation with:
- txt/md/image/audio input processing, URL auto-linking in .txt files
- Paginated HTML output with Atom feed
- 11 visual themes: neon, terminal, synthwave, minimal, brutalist, paper,
aurora, matrix, ocean, retro, glass (selectable via --theme flag)
- Keyboard navigation (j/k/arrows, Enter modal, h/l page nav)
- Shared nav templates (navhints, navmodal, navscript) across all themes
- Magefile build automation; integration test suite covering all themes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|