Skip to content

tlon-skill: Migrate the full posts command family to the pure command runner#5922

Open
patosullivan wants to merge 1 commit into
developfrom
po/tlon-5771-posts-family-completion
Open

tlon-skill: Migrate the full posts command family to the pure command runner#5922
patosullivan wants to merge 1 commit into
developfrom
po/tlon-5771-posts-family-completion

Conversation

@patosullivan

@patosullivan patosullivan commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

This finishes moving the tlon posts command family off the legacy import-side-effect module and onto the injectable run(args, deps) command contract. posts react already used the contract; this change migrates the remaining subcommands — unreact, delete, edit — plus the family shell (bare posts, posts --help, unknown subcommands, and the unsupported send/reply guidance). With the whole family on the contract, the legacy scripts/posts.ts module is deleted and scripts/main.ts routes the entire posts family through the runner with no process.argv mutation.

User-facing behavior is unchanged: help text, usage errors, unsupported-command messages, success strings, and the post-id formatting pipeline are all preserved byte-for-byte. The win is testability and the removal of an auto-running command module.

What changed

  • scripts/commands/posts.ts — grew from the react-only slice into the full family runner. Parsing produces a discriminated result covering help, react, unreact, delete, and edit; bare/unknown invocations throw a usage error and unsupported send/reply throw a command error, all before authentication. The id helpers (extractNumericId/formatUd) stay self-contained, and the existing-post lookup (around-cursor query, exact-id match, null-on-error) lives here where it is directly testable. The module imports only pure helpers (markdownToStory from ./story); the command-contract guard continues to pass.
  • scripts/posts-runtime.ts — the process-backed facade gained removeReaction, deletePost, editPost, and a thin getChannelPosts lookup, plus now() (clock) and readFile() deps for edit. API failures are wrapped in commandError exactly as the react path already did.
  • scripts/main.ts — the posts case now calls runPostsCommand(scriptArgs, createPostsDeps()) for every subcommand; the react-only special case, the process.argv rewrite, and the import('./posts') branch are gone.
  • scripts/posts.ts — deleted. Nothing imports it.
  • scripts/cli-test-matrix.ts — added nested-help, missing-arg, auth-required, and unsupported-command cases for the newly migrated subcommands, and extended HOSTILE_HELP_COMMANDS with posts unreact, posts delete, and posts edit. These flow into both the source hermetic suite and the built-binary smoke automatically.

Decision log (legacy quirks: preserved vs. tightened)

Every decision below preserves legacy behavior; each is covered by tests.

  • Help token after a subcommand prints that subcommand's help before validation/auth (family help for unknown subcommands). Covered in-process for every known subcommand and the unknown-subcommand case, and via the hostile-config matrix. A help token also short-circuits the unsupported send/reply errors (posts send --help prints family help): this follows from parse order (help is resolved before the unsupported-command branch), but that specific combination is not separately pinned by a test.
  • Edit message help-literal. posts edit <ch> <id> --help treats --help as the edit message and reaches auth — it does not print help. Its near-twin posts edit <ch> <id> --title --help does print edit help, because the message slice ends at the first option flag and the literal check never fires. Both adjacent cases are pinned in-process and as built-binary matrix cases.
  • Flag-value parsing is positional with no validation. --title --image url takes --image as the title value. Preserved and tested.
  • Trailing args after the required positionals are ignored for unreact and delete (and the emoji for react). Preserved and tested.
  • Auth runs before any filesystem read. Edit authenticates, then looks up the existing post, then reads the --content file — so a nonexistent --content file fails with Missing Urbit config in a no-config environment, never a filesystem error. Pinned with an injected call-order assertion in-process and an auth-required case through the real binary.
  • --content read/parse failures are caught after auth and the existing-post lookup and rethrown as a stable Error: <message> (exit 1, no stack/code frame). Both missing-file and invalid-JSON cases are tested.
  • Payload shapes preserved. unreact calls removeReaction with postAuthor set to the current user; delete calls deletePost with the formatted id and current user id; edit merges metadata (new --title/--image override, existing title/image/description/cover preserved, null lookup → undefined) and stamps sentAt from the injected clock.
  • Success strings unchanged: ✓ Reaction added, ✓ Reaction removed, ✓ Post edited, ✓ Post deleted.

Testing

  • pnpm --filter '@tloncorp/tlon-skill' check (typecheck + unit + hermetic + built-binary smoke from a fresh build) passes.
  • pnpm -r tsc passes for tlon-skill.
  • In-process tests cover help/shell, per-subcommand missing-arg matrices, dotted/undotted/~ship/ ids, exact success strings, payload shapes, edit metadata merge (found / null / overrides / failed lookup), content via message vs. --content file, message-slicing edges, content read/parse failures, the injected clock, the help-literal quirk, positional flag-value parsing, and expected-vs-unexpected error propagation.
  • Source and built CLI matrices cover nested help, missing-arg usage, auth-required valid invocations, the minimal edit help-literal, the auth-before-filesystem ordering, and the exact unsupported send/reply errors.

@linear-code

linear-code Bot commented Jun 10, 2026

Copy link
Copy Markdown

TLON-5771

Base automatically changed from po/tlon-5771-phase-m2-release-pipeline-port to develop June 11, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant