@ag-eco/agentplate-cli 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +462 -0
- package/agents/ap-co-creation.md +90 -0
- package/agents/builder.md +144 -0
- package/agents/coordinator.md +377 -0
- package/agents/lead.md +435 -0
- package/agents/merger.md +164 -0
- package/agents/monitor.md +214 -0
- package/agents/orchestrator.md +239 -0
- package/agents/reviewer.md +140 -0
- package/agents/scout.md +125 -0
- package/agents/supervisor.md +427 -0
- package/package.json +66 -0
- package/src/agents/capabilities.test.ts +85 -0
- package/src/agents/capabilities.ts +125 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +101 -0
- package/src/agents/copilot-hooks-deployer.test.ts +162 -0
- package/src/agents/copilot-hooks-deployer.ts +93 -0
- package/src/agents/guard-rules.test.ts +372 -0
- package/src/agents/guard-rules.ts +97 -0
- package/src/agents/headless-mail-injector.test.ts +709 -0
- package/src/agents/headless-mail-injector.ts +377 -0
- package/src/agents/headless-prompt.test.ts +102 -0
- package/src/agents/headless-prompt.ts +68 -0
- package/src/agents/hooks-deployer.test.ts +3119 -0
- package/src/agents/hooks-deployer.ts +804 -0
- package/src/agents/identity.test.ts +604 -0
- package/src/agents/identity.ts +384 -0
- package/src/agents/lifecycle.test.ts +196 -0
- package/src/agents/lifecycle.ts +183 -0
- package/src/agents/mail-poll-detect.test.ts +153 -0
- package/src/agents/mail-poll-detect.ts +73 -0
- package/src/agents/manifest.test.ts +1026 -0
- package/src/agents/manifest.ts +376 -0
- package/src/agents/overlay.test.ts +1058 -0
- package/src/agents/overlay.ts +490 -0
- package/src/agents/scope-detect.test.ts +190 -0
- package/src/agents/scope-detect.ts +146 -0
- package/src/agents/turn-lock.test.ts +181 -0
- package/src/agents/turn-lock.ts +235 -0
- package/src/agents/turn-runner-dispatch.test.ts +182 -0
- package/src/agents/turn-runner-dispatch.ts +105 -0
- package/src/agents/turn-runner.test.ts +2312 -0
- package/src/agents/turn-runner.ts +1383 -0
- package/src/beads/client.test.ts +217 -0
- package/src/beads/client.ts +230 -0
- package/src/beads/molecules.test.ts +338 -0
- package/src/beads/molecules.ts +198 -0
- package/src/commands/agents.test.ts +328 -0
- package/src/commands/agents.ts +299 -0
- package/src/commands/clean.test.ts +797 -0
- package/src/commands/clean.ts +791 -0
- package/src/commands/completions.test.ts +348 -0
- package/src/commands/completions.ts +981 -0
- package/src/commands/coordinator.test.ts +2975 -0
- package/src/commands/coordinator.ts +1841 -0
- package/src/commands/costs.test.ts +1183 -0
- package/src/commands/costs.ts +599 -0
- package/src/commands/dashboard.test.ts +954 -0
- package/src/commands/dashboard.ts +1212 -0
- package/src/commands/discover.test.ts +288 -0
- package/src/commands/discover.ts +202 -0
- package/src/commands/doctor.test.ts +303 -0
- package/src/commands/doctor.ts +311 -0
- package/src/commands/ecosystem.test.ts +226 -0
- package/src/commands/ecosystem.ts +248 -0
- package/src/commands/errors.test.ts +654 -0
- package/src/commands/errors.ts +197 -0
- package/src/commands/feed.test.ts +709 -0
- package/src/commands/feed.ts +260 -0
- package/src/commands/group.test.ts +475 -0
- package/src/commands/group.ts +546 -0
- package/src/commands/hooks.test.ts +458 -0
- package/src/commands/hooks.ts +263 -0
- package/src/commands/init.test.ts +1011 -0
- package/src/commands/init.ts +967 -0
- package/src/commands/inspect.test.ts +1239 -0
- package/src/commands/inspect.ts +648 -0
- package/src/commands/log.test.ts +1913 -0
- package/src/commands/log.ts +958 -0
- package/src/commands/logs.test.ts +801 -0
- package/src/commands/logs.ts +483 -0
- package/src/commands/mail.test.ts +1501 -0
- package/src/commands/mail.ts +848 -0
- package/src/commands/merge.test.ts +864 -0
- package/src/commands/merge.ts +381 -0
- package/src/commands/metrics.test.ts +458 -0
- package/src/commands/metrics.ts +129 -0
- package/src/commands/monitor.test.ts +191 -0
- package/src/commands/monitor.ts +409 -0
- package/src/commands/nudge.test.ts +579 -0
- package/src/commands/nudge.ts +646 -0
- package/src/commands/orchestrator.ts +42 -0
- package/src/commands/prime.test.ts +612 -0
- package/src/commands/prime.ts +359 -0
- package/src/commands/replay.test.ts +757 -0
- package/src/commands/replay.ts +231 -0
- package/src/commands/run.test.ts +469 -0
- package/src/commands/run.ts +353 -0
- package/src/commands/serve/agent-actions.test.ts +210 -0
- package/src/commands/serve/agent-actions.ts +192 -0
- package/src/commands/serve/build.test.ts +202 -0
- package/src/commands/serve/build.ts +206 -0
- package/src/commands/serve/coordinator-actions.test.ts +339 -0
- package/src/commands/serve/coordinator-actions.ts +410 -0
- package/src/commands/serve/dev.test.ts +168 -0
- package/src/commands/serve/dev.ts +117 -0
- package/src/commands/serve/mail-actions.test.ts +312 -0
- package/src/commands/serve/mail-actions.ts +167 -0
- package/src/commands/serve/rest.test.ts +1680 -0
- package/src/commands/serve/rest.ts +1130 -0
- package/src/commands/serve/static.ts +51 -0
- package/src/commands/serve/ws.test.ts +361 -0
- package/src/commands/serve/ws.ts +332 -0
- package/src/commands/serve.test.ts +459 -0
- package/src/commands/serve.ts +654 -0
- package/src/commands/sling.test.ts +1583 -0
- package/src/commands/sling.ts +1351 -0
- package/src/commands/spec.test.ts +179 -0
- package/src/commands/spec.ts +105 -0
- package/src/commands/status.test.ts +614 -0
- package/src/commands/status.ts +403 -0
- package/src/commands/stop.test.ts +964 -0
- package/src/commands/stop.ts +319 -0
- package/src/commands/supervisor.test.ts +185 -0
- package/src/commands/supervisor.ts +537 -0
- package/src/commands/trace.test.ts +762 -0
- package/src/commands/trace.ts +205 -0
- package/src/commands/update.test.ts +466 -0
- package/src/commands/update.ts +263 -0
- package/src/commands/upgrade.test.ts +48 -0
- package/src/commands/upgrade.ts +240 -0
- package/src/commands/watch.test.ts +257 -0
- package/src/commands/watch.ts +308 -0
- package/src/commands/worktree.test.ts +1297 -0
- package/src/commands/worktree.ts +451 -0
- package/src/config.test.ts +1535 -0
- package/src/config.ts +1064 -0
- package/src/doctor/agents.test.ts +523 -0
- package/src/doctor/agents.ts +399 -0
- package/src/doctor/config-check.test.ts +191 -0
- package/src/doctor/config-check.ts +183 -0
- package/src/doctor/consistency.test.ts +807 -0
- package/src/doctor/consistency.ts +347 -0
- package/src/doctor/databases.test.ts +350 -0
- package/src/doctor/databases.ts +243 -0
- package/src/doctor/dependencies.test.ts +296 -0
- package/src/doctor/dependencies.ts +272 -0
- package/src/doctor/ecosystem.test.ts +308 -0
- package/src/doctor/ecosystem.ts +156 -0
- package/src/doctor/logs.test.ts +253 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +315 -0
- package/src/doctor/merge-queue.ts +167 -0
- package/src/doctor/providers.test.ts +409 -0
- package/src/doctor/providers.ts +250 -0
- package/src/doctor/serve.test.ts +95 -0
- package/src/doctor/serve.ts +86 -0
- package/src/doctor/structure.test.ts +423 -0
- package/src/doctor/structure.ts +285 -0
- package/src/doctor/types.ts +43 -0
- package/src/doctor/version.test.ts +241 -0
- package/src/doctor/version.ts +132 -0
- package/src/doctor/watchdog.test.ts +167 -0
- package/src/doctor/watchdog.ts +214 -0
- package/src/e2e/init-sling-lifecycle.test.ts +283 -0
- package/src/errors.test.ts +350 -0
- package/src/errors.ts +217 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +369 -0
- package/src/events/tailer.test.ts +719 -0
- package/src/events/tailer.ts +332 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/index.ts +533 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/insights/quality-gates.test.ts +141 -0
- package/src/insights/quality-gates.ts +156 -0
- package/src/json.test.ts +72 -0
- package/src/json.ts +53 -0
- package/src/loam/client.test.ts +752 -0
- package/src/loam/client.ts +664 -0
- package/src/logging/color.test.ts +252 -0
- package/src/logging/color.ts +105 -0
- package/src/logging/format.test.ts +110 -0
- package/src/logging/format.ts +255 -0
- package/src/logging/logger.test.ts +814 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +259 -0
- package/src/logging/reporter.ts +110 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/logging/theme.ts +140 -0
- package/src/mail/broadcast.test.ts +204 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +774 -0
- package/src/mail/client.ts +236 -0
- package/src/mail/store.test.ts +898 -0
- package/src/mail/store.ts +425 -0
- package/src/merge/lock.test.ts +149 -0
- package/src/merge/lock.ts +140 -0
- package/src/merge/predict.test.ts +387 -0
- package/src/merge/predict.ts +249 -0
- package/src/merge/queue.test.ts +426 -0
- package/src/merge/queue.ts +246 -0
- package/src/merge/resolver.test.ts +1993 -0
- package/src/merge/resolver.ts +926 -0
- package/src/metrics/pricing.test.ts +258 -0
- package/src/metrics/pricing.ts +135 -0
- package/src/metrics/store.test.ts +978 -0
- package/src/metrics/store.ts +501 -0
- package/src/metrics/summary.test.ts +398 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +483 -0
- package/src/metrics/transcript.ts +114 -0
- package/src/runtimes/__fixtures__/claude-stream-fixture.ts +22 -0
- package/src/runtimes/aider.test.ts +124 -0
- package/src/runtimes/aider.ts +147 -0
- package/src/runtimes/amp.test.ts +164 -0
- package/src/runtimes/amp.ts +154 -0
- package/src/runtimes/claude.test.ts +1474 -0
- package/src/runtimes/claude.ts +579 -0
- package/src/runtimes/codex.test.ts +805 -0
- package/src/runtimes/codex.ts +273 -0
- package/src/runtimes/connections.test.ts +214 -0
- package/src/runtimes/connections.ts +103 -0
- package/src/runtimes/copilot.test.ts +707 -0
- package/src/runtimes/copilot.ts +316 -0
- package/src/runtimes/cursor.test.ts +497 -0
- package/src/runtimes/cursor.ts +205 -0
- package/src/runtimes/gemini.test.ts +537 -0
- package/src/runtimes/gemini.ts +243 -0
- package/src/runtimes/goose.test.ts +133 -0
- package/src/runtimes/goose.ts +157 -0
- package/src/runtimes/headless-connection.test.ts +264 -0
- package/src/runtimes/headless-connection.ts +158 -0
- package/src/runtimes/opencode.test.ts +325 -0
- package/src/runtimes/opencode.ts +188 -0
- package/src/runtimes/pi-guards.test.ts +486 -0
- package/src/runtimes/pi-guards.ts +367 -0
- package/src/runtimes/pi.test.ts +789 -0
- package/src/runtimes/pi.ts +305 -0
- package/src/runtimes/registry.test.ts +196 -0
- package/src/runtimes/registry.ts +99 -0
- package/src/runtimes/sapling.test.ts +1267 -0
- package/src/runtimes/sapling.ts +710 -0
- package/src/runtimes/types.ts +266 -0
- package/src/schema-consistency.test.ts +246 -0
- package/src/sessions/compat.test.ts +281 -0
- package/src/sessions/compat.ts +105 -0
- package/src/sessions/store.test.ts +1748 -0
- package/src/sessions/store.ts +858 -0
- package/src/test-helpers.test.ts +124 -0
- package/src/test-helpers.ts +145 -0
- package/src/test-setup.test.ts +31 -0
- package/src/test-setup.ts +28 -0
- package/src/tools/loam/api.ts +368 -0
- package/src/tools/loam/cli.ts +278 -0
- package/src/tools/loam/commands/add.ts +52 -0
- package/src/tools/loam/commands/archive.ts +214 -0
- package/src/tools/loam/commands/audit.ts +276 -0
- package/src/tools/loam/commands/compact.ts +1062 -0
- package/src/tools/loam/commands/completions.ts +79 -0
- package/src/tools/loam/commands/config.ts +381 -0
- package/src/tools/loam/commands/delete-domain.ts +121 -0
- package/src/tools/loam/commands/delete.ts +316 -0
- package/src/tools/loam/commands/diff.ts +200 -0
- package/src/tools/loam/commands/doctor.ts +1113 -0
- package/src/tools/loam/commands/edit.ts +226 -0
- package/src/tools/loam/commands/init.ts +31 -0
- package/src/tools/loam/commands/learn.ts +179 -0
- package/src/tools/loam/commands/move.ts +323 -0
- package/src/tools/loam/commands/onboard.ts +374 -0
- package/src/tools/loam/commands/outcome.ts +185 -0
- package/src/tools/loam/commands/prime.ts +688 -0
- package/src/tools/loam/commands/prune.ts +614 -0
- package/src/tools/loam/commands/query.ts +218 -0
- package/src/tools/loam/commands/rank.ts +180 -0
- package/src/tools/loam/commands/ready.ts +189 -0
- package/src/tools/loam/commands/record.ts +1210 -0
- package/src/tools/loam/commands/restore.ts +166 -0
- package/src/tools/loam/commands/search.ts +327 -0
- package/src/tools/loam/commands/setup.ts +887 -0
- package/src/tools/loam/commands/status.ts +103 -0
- package/src/tools/loam/commands/sync.ts +298 -0
- package/src/tools/loam/commands/update.ts +19 -0
- package/src/tools/loam/commands/upgrade.ts +93 -0
- package/src/tools/loam/commands/validate.ts +190 -0
- package/src/tools/loam/index.ts +62 -0
- package/src/tools/loam/log.ts +127 -0
- package/src/tools/loam/registry/builtins.ts +409 -0
- package/src/tools/loam/registry/custom.ts +431 -0
- package/src/tools/loam/registry/init.ts +55 -0
- package/src/tools/loam/registry/template.ts +40 -0
- package/src/tools/loam/registry/type-registry.ts +113 -0
- package/src/tools/loam/schemas/config-schema.ts +489 -0
- package/src/tools/loam/schemas/config.ts +245 -0
- package/src/tools/loam/schemas/index.ts +18 -0
- package/src/tools/loam/schemas/record-schema.ts +191 -0
- package/src/tools/loam/schemas/record.ts +115 -0
- package/src/tools/loam/utils/active-work.ts +205 -0
- package/src/tools/loam/utils/anchor-validity.ts +80 -0
- package/src/tools/loam/utils/archive.ts +146 -0
- package/src/tools/loam/utils/audit.ts +667 -0
- package/src/tools/loam/utils/bm25.ts +238 -0
- package/src/tools/loam/utils/budget.ts +142 -0
- package/src/tools/loam/utils/config.ts +344 -0
- package/src/tools/loam/utils/dir-anchors.ts +62 -0
- package/src/tools/loam/utils/domain-rules.ts +114 -0
- package/src/tools/loam/utils/expertise.ts +393 -0
- package/src/tools/loam/utils/format-helpers.ts +96 -0
- package/src/tools/loam/utils/format.ts +1234 -0
- package/src/tools/loam/utils/git-context.ts +50 -0
- package/src/tools/loam/utils/git.ts +183 -0
- package/src/tools/loam/utils/hooks.ts +299 -0
- package/src/tools/loam/utils/index.ts +52 -0
- package/src/tools/loam/utils/json-output.ts +13 -0
- package/src/tools/loam/utils/lock.ts +76 -0
- package/src/tools/loam/utils/markers.ts +48 -0
- package/src/tools/loam/utils/numeric-flags.ts +20 -0
- package/src/tools/loam/utils/palette.ts +44 -0
- package/src/tools/loam/utils/prime-ranking.ts +135 -0
- package/src/tools/loam/utils/recipe-discovery.ts +195 -0
- package/src/tools/loam/utils/runtime-flags.ts +28 -0
- package/src/tools/loam/utils/scoring.ts +94 -0
- package/src/tools/loam/utils/version.ts +116 -0
- package/src/tools/sprout/commands/block.ts +64 -0
- package/src/tools/sprout/commands/blocked.ts +86 -0
- package/src/tools/sprout/commands/close.ts +129 -0
- package/src/tools/sprout/commands/completions.ts +198 -0
- package/src/tools/sprout/commands/config.ts +238 -0
- package/src/tools/sprout/commands/create.ts +164 -0
- package/src/tools/sprout/commands/dep.ts +148 -0
- package/src/tools/sprout/commands/doctor.ts +979 -0
- package/src/tools/sprout/commands/init.ts +83 -0
- package/src/tools/sprout/commands/label.ts +178 -0
- package/src/tools/sprout/commands/list.ts +210 -0
- package/src/tools/sprout/commands/migrate.ts +133 -0
- package/src/tools/sprout/commands/onboard.ts +207 -0
- package/src/tools/sprout/commands/plan-show.ts +278 -0
- package/src/tools/sprout/commands/plan.ts +2526 -0
- package/src/tools/sprout/commands/prime.ts +399 -0
- package/src/tools/sprout/commands/ready.ts +245 -0
- package/src/tools/sprout/commands/search.ts +221 -0
- package/src/tools/sprout/commands/show.ts +277 -0
- package/src/tools/sprout/commands/stats.ts +146 -0
- package/src/tools/sprout/commands/sync.ts +134 -0
- package/src/tools/sprout/commands/tpl.ts +364 -0
- package/src/tools/sprout/commands/unblock.ts +115 -0
- package/src/tools/sprout/commands/update.ts +257 -0
- package/src/tools/sprout/commands/upgrade.ts +91 -0
- package/src/tools/sprout/config-schema.ts +152 -0
- package/src/tools/sprout/config.ts +355 -0
- package/src/tools/sprout/filter.ts +107 -0
- package/src/tools/sprout/format.ts +43 -0
- package/src/tools/sprout/id.ts +22 -0
- package/src/tools/sprout/index.ts +204 -0
- package/src/tools/sprout/log.ts +76 -0
- package/src/tools/sprout/markers.ts +22 -0
- package/src/tools/sprout/output.ts +121 -0
- package/src/tools/sprout/plan-backref.ts +93 -0
- package/src/tools/sprout/plan-context.ts +81 -0
- package/src/tools/sprout/plan-domain.ts +139 -0
- package/src/tools/sprout/plan-lifecycle.ts +65 -0
- package/src/tools/sprout/plan-loam.ts +207 -0
- package/src/tools/sprout/plan-schema.ts +209 -0
- package/src/tools/sprout/sort.ts +31 -0
- package/src/tools/sprout/store.ts +172 -0
- package/src/tools/sprout/types.ts +118 -0
- package/src/tools/sprout/validation.ts +119 -0
- package/src/tools/sprout/version.ts +1 -0
- package/src/tools/sprout/yaml.ts +387 -0
- package/src/tools/trellis/commands/archive.ts +87 -0
- package/src/tools/trellis/commands/completions.ts +610 -0
- package/src/tools/trellis/commands/config.ts +382 -0
- package/src/tools/trellis/commands/create.ts +252 -0
- package/src/tools/trellis/commands/diff.ts +150 -0
- package/src/tools/trellis/commands/doctor.ts +771 -0
- package/src/tools/trellis/commands/emit.ts +365 -0
- package/src/tools/trellis/commands/history.ts +83 -0
- package/src/tools/trellis/commands/import.ts +198 -0
- package/src/tools/trellis/commands/init.ts +81 -0
- package/src/tools/trellis/commands/list.ts +103 -0
- package/src/tools/trellis/commands/onboard.ts +156 -0
- package/src/tools/trellis/commands/pin.ts +172 -0
- package/src/tools/trellis/commands/prime.ts +193 -0
- package/src/tools/trellis/commands/render.ts +122 -0
- package/src/tools/trellis/commands/schema.ts +353 -0
- package/src/tools/trellis/commands/show.ts +115 -0
- package/src/tools/trellis/commands/stats.ts +65 -0
- package/src/tools/trellis/commands/sync.ts +112 -0
- package/src/tools/trellis/commands/tree.ts +123 -0
- package/src/tools/trellis/commands/update.ts +330 -0
- package/src/tools/trellis/commands/upgrade.ts +95 -0
- package/src/tools/trellis/commands/validate.ts +166 -0
- package/src/tools/trellis/config-schema.ts +81 -0
- package/src/tools/trellis/config.ts +108 -0
- package/src/tools/trellis/frontmatter.ts +348 -0
- package/src/tools/trellis/id.ts +24 -0
- package/src/tools/trellis/index.ts +209 -0
- package/src/tools/trellis/markers.ts +28 -0
- package/src/tools/trellis/output.ts +84 -0
- package/src/tools/trellis/render.ts +212 -0
- package/src/tools/trellis/store.ts +144 -0
- package/src/tools/trellis/types.ts +82 -0
- package/src/tools/trellis/validate.ts +199 -0
- package/src/tools/trellis/yaml.ts +309 -0
- package/src/tracker/beads.test.ts +454 -0
- package/src/tracker/beads.ts +56 -0
- package/src/tracker/factory.test.ts +90 -0
- package/src/tracker/factory.ts +65 -0
- package/src/tracker/sprout.test.ts +461 -0
- package/src/tracker/sprout.ts +182 -0
- package/src/tracker/types.ts +52 -0
- package/src/trellis/client.test.ts +107 -0
- package/src/trellis/client.ts +179 -0
- package/src/types.ts +970 -0
- package/src/utils/bin.test.ts +10 -0
- package/src/utils/bin.ts +37 -0
- package/src/utils/browser.test.ts +49 -0
- package/src/utils/browser.ts +48 -0
- package/src/utils/fs.test.ts +119 -0
- package/src/utils/fs.ts +62 -0
- package/src/utils/pid.test.ts +152 -0
- package/src/utils/pid.ts +130 -0
- package/src/utils/process-scan.test.ts +53 -0
- package/src/utils/process-scan.ts +76 -0
- package/src/utils/time.test.ts +43 -0
- package/src/utils/time.ts +37 -0
- package/src/utils/version.test.ts +33 -0
- package/src/utils/version.ts +70 -0
- package/src/version.ts +5 -0
- package/src/watchdog/daemon.test.ts +3721 -0
- package/src/watchdog/daemon.ts +1257 -0
- package/src/watchdog/health.test.ts +830 -0
- package/src/watchdog/health.ts +434 -0
- package/src/watchdog/triage.test.ts +205 -0
- package/src/watchdog/triage.ts +205 -0
- package/src/worktree/manager.test.ts +720 -0
- package/src/worktree/manager.ts +405 -0
- package/src/worktree/process.test.ts +172 -0
- package/src/worktree/process.ts +131 -0
- package/src/worktree/tmux.test.ts +1616 -0
- package/src/worktree/tmux.ts +721 -0
- package/templates/CLAUDE.md.tmpl +100 -0
- package/templates/copilot-hooks.json.tmpl +13 -0
- package/templates/hooks.json.tmpl +109 -0
- package/templates/overlay.md.tmpl +88 -0
- package/ui/dist/apple-touch-icon-bdy6teep.png +0 -0
- package/ui/dist/chunk-8s31f05k.css +1 -0
- package/ui/dist/chunk-vm5rz679.js +300 -0
- package/ui/dist/favicon-nzb39vza.svg +4 -0
- package/ui/dist/index.html +17 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { Command } from "commander";
|
|
4
|
+
import { saveConfig } from "../config.ts";
|
|
5
|
+
import { errorOut, humanOut, jsonOut } from "../output.ts";
|
|
6
|
+
import { ExitError } from "../types.ts";
|
|
7
|
+
|
|
8
|
+
export default async function init(_args: string[], json: boolean): Promise<void> {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
const trellisDir = join(cwd, ".trellis");
|
|
11
|
+
|
|
12
|
+
if (_args.includes("--help") || _args.includes("-h")) {
|
|
13
|
+
humanOut(`Usage: tl init
|
|
14
|
+
|
|
15
|
+
Initializes .trellis/ in the current directory with config and empty JSONL stores.`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (existsSync(trellisDir)) {
|
|
20
|
+
if (json) {
|
|
21
|
+
jsonOut({ success: false, command: "init", error: ".trellis/ already exists" });
|
|
22
|
+
} else {
|
|
23
|
+
errorOut(".trellis/ already exists");
|
|
24
|
+
}
|
|
25
|
+
throw new ExitError(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
mkdirSync(trellisDir, { recursive: true });
|
|
29
|
+
|
|
30
|
+
// Write default config
|
|
31
|
+
await saveConfig(cwd, {
|
|
32
|
+
project: "trellis",
|
|
33
|
+
version: "1",
|
|
34
|
+
targets: {
|
|
35
|
+
default: { dir: "agents", default: true },
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Write .gitignore for .trellis/
|
|
40
|
+
await Bun.write(join(trellisDir, ".gitignore"), "*.lock\n");
|
|
41
|
+
|
|
42
|
+
// Create empty JSONL files
|
|
43
|
+
await Bun.write(join(trellisDir, "prompts.jsonl"), "");
|
|
44
|
+
await Bun.write(join(trellisDir, "schemas.jsonl"), "");
|
|
45
|
+
|
|
46
|
+
// Append .gitattributes to project root
|
|
47
|
+
const gitattrsPath = join(cwd, ".gitattributes");
|
|
48
|
+
const gitattrsEntry = ".trellis/prompts.jsonl merge=union\n.trellis/schemas.jsonl merge=union\n";
|
|
49
|
+
|
|
50
|
+
let existing = "";
|
|
51
|
+
try {
|
|
52
|
+
existing = await Bun.file(gitattrsPath).text();
|
|
53
|
+
} catch {
|
|
54
|
+
existing = "";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!existing.includes(".trellis/prompts.jsonl")) {
|
|
58
|
+
await Bun.write(gitattrsPath, existing + gitattrsEntry);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (json) {
|
|
62
|
+
jsonOut({ success: true, command: "init", dir: trellisDir });
|
|
63
|
+
} else {
|
|
64
|
+
humanOut(`Initialized .trellis/ in ${cwd}`);
|
|
65
|
+
humanOut(" config.yaml: project=trellis, targets: default → agents/");
|
|
66
|
+
humanOut(" prompts.jsonl created");
|
|
67
|
+
humanOut(" schemas.jsonl created");
|
|
68
|
+
humanOut(" .gitattributes updated with merge=union");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function registerInitCommand(program: Command): void {
|
|
73
|
+
program
|
|
74
|
+
.command("init")
|
|
75
|
+
.description("Initialize .trellis/ in current directory")
|
|
76
|
+
.action(async () => {
|
|
77
|
+
const json: boolean = program.opts().json ?? false;
|
|
78
|
+
const args = json ? ["--json"] : [];
|
|
79
|
+
await init(args, json);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
import { c, humanOut, jsonOut } from "../output.ts";
|
|
4
|
+
import { dedupById, readJsonl } from "../store.ts";
|
|
5
|
+
import type { Prompt } from "../types.ts";
|
|
6
|
+
|
|
7
|
+
export default async function list(args: string[], json: boolean): Promise<void> {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const promptsPath = join(cwd, ".trellis", "prompts.jsonl");
|
|
10
|
+
|
|
11
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
12
|
+
humanOut(`Usage: tl list [options]
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
--tag <tag> Filter by tag
|
|
16
|
+
--status <s> Filter by status (draft|active|archived)
|
|
17
|
+
--mixin <name> Filter by mixin
|
|
18
|
+
--json Output as JSON`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Parse filters
|
|
23
|
+
let filterTag: string | undefined;
|
|
24
|
+
let filterStatus: string | undefined;
|
|
25
|
+
let filterExtends: string | undefined;
|
|
26
|
+
let filterMixin: string | undefined;
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
if (args[i] === "--tag" && args[i + 1]) {
|
|
30
|
+
filterTag = args[++i];
|
|
31
|
+
} else if (args[i] === "--status" && args[i + 1]) {
|
|
32
|
+
filterStatus = args[++i];
|
|
33
|
+
} else if (args[i] === "--extends" && args[i + 1]) {
|
|
34
|
+
filterExtends = args[++i];
|
|
35
|
+
} else if (args[i] === "--mixin" && args[i + 1]) {
|
|
36
|
+
filterMixin = args[++i];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const allRecords = await readJsonl<Prompt>(promptsPath);
|
|
41
|
+
let prompts = dedupById(allRecords);
|
|
42
|
+
|
|
43
|
+
// Default: exclude archived unless explicitly requested
|
|
44
|
+
if (!filterStatus) {
|
|
45
|
+
prompts = prompts.filter((p) => p.status !== "archived");
|
|
46
|
+
} else {
|
|
47
|
+
prompts = prompts.filter((p) => p.status === filterStatus);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (filterTag) {
|
|
51
|
+
prompts = prompts.filter((p) => p.tags?.includes(filterTag as string));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (filterExtends) {
|
|
55
|
+
prompts = prompts.filter((p) => p.extends === filterExtends);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (filterMixin) {
|
|
59
|
+
prompts = prompts.filter((p) => p.mixins?.includes(filterMixin as string));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (json) {
|
|
63
|
+
jsonOut({ success: true, command: "list", prompts, count: prompts.length });
|
|
64
|
+
} else {
|
|
65
|
+
if (prompts.length === 0) {
|
|
66
|
+
humanOut("No prompts found.");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const p of prompts) {
|
|
71
|
+
const tags = p.tags?.length ? c.dim(` [${p.tags.join(", ")}]`) : "";
|
|
72
|
+
const ext = p.extends ? c.dim(` → ${p.extends}`) : "";
|
|
73
|
+
const mix = p.mixins?.length ? c.dim(` + ${p.mixins.join(", ")}`) : "";
|
|
74
|
+
const pin = p.pinned !== undefined ? c.yellow(` (pinned @${p.pinned})`) : "";
|
|
75
|
+
humanOut(
|
|
76
|
+
`${c.bold(p.name)}${ext}${mix}${tags}${pin} ${c.dim(`v${p.version} · ${p.status} · ${p.id}`)}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
humanOut(c.dim(`\n${prompts.length} prompt${prompts.length === 1 ? "" : "s"}`));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function registerListCommand(program: Command): void {
|
|
84
|
+
program
|
|
85
|
+
.command("list")
|
|
86
|
+
.description("List prompts")
|
|
87
|
+
.option("--tag <tag>", "Filter by tag")
|
|
88
|
+
.option("--status <status>", "Filter by status (draft|active|archived)")
|
|
89
|
+
.option("--extends <name>", "Filter by parent prompt")
|
|
90
|
+
.option("--mixin <name>", "Filter by mixin")
|
|
91
|
+
.action(
|
|
92
|
+
async (options: { tag?: string; status?: string; extends?: string; mixin?: string }) => {
|
|
93
|
+
const json: boolean = program.opts().json ?? false;
|
|
94
|
+
const args: string[] = [];
|
|
95
|
+
if (options.tag) args.push("--tag", options.tag);
|
|
96
|
+
if (options.status) args.push("--status", options.status);
|
|
97
|
+
if (options.extends) args.push("--extends", options.extends);
|
|
98
|
+
if (options.mixin) args.push("--mixin", options.mixin);
|
|
99
|
+
if (json) args.push("--json");
|
|
100
|
+
await list(args, json);
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { Command } from "commander";
|
|
4
|
+
import { detectStatus, replaceMarkerSection, VERSION_MARKER, wrapInMarkers } from "../markers.ts";
|
|
5
|
+
import { humanOut, isQuiet, jsonOut } from "../output.ts";
|
|
6
|
+
|
|
7
|
+
const CANDIDATE_FILES = ["CLAUDE.md", ".claude/CLAUDE.md", "AGENTS.md"] as const;
|
|
8
|
+
|
|
9
|
+
function onboardSnippet(): string {
|
|
10
|
+
return `## Prompt Management (Trellis)
|
|
11
|
+
${VERSION_MARKER}
|
|
12
|
+
|
|
13
|
+
This project uses [Trellis](https://github.com/jayminwest/trellis) for git-native prompt management.
|
|
14
|
+
|
|
15
|
+
**At the start of every session**, run:
|
|
16
|
+
\`\`\`
|
|
17
|
+
tl prime
|
|
18
|
+
\`\`\`
|
|
19
|
+
|
|
20
|
+
This injects prompt workflow context: commands, conventions, and common workflows.
|
|
21
|
+
|
|
22
|
+
**Quick reference:**
|
|
23
|
+
- \`tl list\` — List all prompts
|
|
24
|
+
- \`tl render <name>\` — View rendered prompt (resolves inheritance)
|
|
25
|
+
- \`tl emit --all\` — Render prompts to files
|
|
26
|
+
- \`tl update <name>\` — Update a prompt (creates new version)
|
|
27
|
+
- \`tl sync\` — Stage and commit .trellis/ changes
|
|
28
|
+
|
|
29
|
+
**Do not manually edit emitted files.** Use \`tl update\` to modify prompts, then \`tl emit\` to regenerate.
|
|
30
|
+
|
|
31
|
+
**Loam metadata:** Prompts can declare expertise dependencies via \`loam.prime.domains\`, \`loam.prime.files\`, \`loam.budget\`, \`loam.on_empty\`, plus a top-level \`extends_loam\` flag (override-by-default; merge with parent when \`true\`). Trellis never shells out to \`ml\` — \`tl render --json\` surfaces the resolved declaration in a top-level \`loam\` field for consumers to act on. See SPEC.md "Loam Metadata".`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function findTargetFile(projectRoot: string): string | null {
|
|
35
|
+
for (const candidate of CANDIDATE_FILES) {
|
|
36
|
+
const fullPath = join(projectRoot, candidate);
|
|
37
|
+
if (existsSync(fullPath)) {
|
|
38
|
+
return fullPath;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default async function onboard(args: string[], json: boolean): Promise<void> {
|
|
45
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
46
|
+
humanOut(`Usage: tl onboard [options]
|
|
47
|
+
|
|
48
|
+
Adds a trellis section to CLAUDE.md (or creates it) so AI agents discover prompt workflows.
|
|
49
|
+
|
|
50
|
+
Options:
|
|
51
|
+
--check Report status without writing (missing, current, outdated)
|
|
52
|
+
--stdout Print snippet to stdout without writing to file
|
|
53
|
+
--json Output as JSON`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const stdoutMode = args.includes("--stdout");
|
|
58
|
+
const checkMode = args.includes("--check");
|
|
59
|
+
const cwd = process.cwd();
|
|
60
|
+
|
|
61
|
+
const targetPath = findTargetFile(cwd);
|
|
62
|
+
const snippet = onboardSnippet();
|
|
63
|
+
|
|
64
|
+
// --check mode: report status only
|
|
65
|
+
if (checkMode) {
|
|
66
|
+
if (!targetPath) {
|
|
67
|
+
if (json) {
|
|
68
|
+
jsonOut({ success: true, command: "onboard", status: "missing", file: null });
|
|
69
|
+
} else {
|
|
70
|
+
humanOut("Status: missing (no CLAUDE.md found)");
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const content = await Bun.file(targetPath).text();
|
|
75
|
+
const status = detectStatus(content);
|
|
76
|
+
if (json) {
|
|
77
|
+
jsonOut({ success: true, command: "onboard", status, file: targetPath });
|
|
78
|
+
} else {
|
|
79
|
+
humanOut(`Status: ${status} (${targetPath})`);
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// --stdout mode: print what would be written
|
|
85
|
+
if (stdoutMode) {
|
|
86
|
+
if (!isQuiet()) {
|
|
87
|
+
process.stdout.write(wrapInMarkers(snippet));
|
|
88
|
+
process.stdout.write("\n");
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Default mode: write to file
|
|
94
|
+
const filePath = targetPath ?? join(cwd, "CLAUDE.md");
|
|
95
|
+
const fileExists = existsSync(filePath);
|
|
96
|
+
const wrappedSnippet = wrapInMarkers(snippet);
|
|
97
|
+
|
|
98
|
+
if (!fileExists) {
|
|
99
|
+
await Bun.write(filePath, `${wrappedSnippet}\n`);
|
|
100
|
+
if (json) {
|
|
101
|
+
jsonOut({ success: true, command: "onboard", action: "created", file: filePath });
|
|
102
|
+
} else {
|
|
103
|
+
humanOut(`Created ${filePath} with trellis section`);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const content = await Bun.file(filePath).text();
|
|
109
|
+
const status = detectStatus(content);
|
|
110
|
+
|
|
111
|
+
if (status === "current") {
|
|
112
|
+
if (json) {
|
|
113
|
+
jsonOut({ success: true, command: "onboard", action: "unchanged", file: filePath });
|
|
114
|
+
} else {
|
|
115
|
+
humanOut("Trellis section is already up to date");
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (status === "outdated") {
|
|
121
|
+
const updated = replaceMarkerSection(content, snippet);
|
|
122
|
+
if (updated) {
|
|
123
|
+
await Bun.write(filePath, updated);
|
|
124
|
+
if (json) {
|
|
125
|
+
jsonOut({ success: true, command: "onboard", action: "updated", file: filePath });
|
|
126
|
+
} else {
|
|
127
|
+
humanOut(`Updated trellis section in ${filePath}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// status === "missing": append
|
|
134
|
+
const separator = content.endsWith("\n") ? "\n" : "\n\n";
|
|
135
|
+
await Bun.write(filePath, `${content}${separator}${wrappedSnippet}\n`);
|
|
136
|
+
if (json) {
|
|
137
|
+
jsonOut({ success: true, command: "onboard", action: "appended", file: filePath });
|
|
138
|
+
} else {
|
|
139
|
+
humanOut(`Added trellis section to ${filePath}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function registerOnboardCommand(program: Command): void {
|
|
144
|
+
program
|
|
145
|
+
.command("onboard")
|
|
146
|
+
.description("Add trellis section to CLAUDE.md for AI agent discovery")
|
|
147
|
+
.option("--check", "Report status without writing (missing, current, outdated)")
|
|
148
|
+
.option("--stdout", "Print snippet to stdout without writing to file")
|
|
149
|
+
.action(async (opts: Record<string, unknown>) => {
|
|
150
|
+
const json: boolean = program.opts().json ?? false;
|
|
151
|
+
const args: string[] = [];
|
|
152
|
+
if (opts.check) args.push("--check");
|
|
153
|
+
if (opts.stdout) args.push("--stdout");
|
|
154
|
+
await onboard(args, json);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
import { c, errorOut, fmt, humanOut, jsonOut } from "../output.ts";
|
|
4
|
+
import { acquireLock, appendJsonl, dedupById, readJsonl, releaseLock } from "../store.ts";
|
|
5
|
+
import type { Prompt } from "../types.ts";
|
|
6
|
+
import { ExitError } from "../types.ts";
|
|
7
|
+
|
|
8
|
+
export default async function pin(args: string[], json: boolean): Promise<void> {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
const promptsPath = join(cwd, ".trellis", "prompts.jsonl");
|
|
11
|
+
|
|
12
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
13
|
+
humanOut(`Usage: tl pin <name>@<version> [options]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--json Output as JSON`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const nameArg = args.filter((a) => !a.startsWith("--"))[0];
|
|
21
|
+
if (!nameArg) {
|
|
22
|
+
if (json) {
|
|
23
|
+
jsonOut({ success: false, command: "pin", error: "Usage: tl pin <name>@<version>" });
|
|
24
|
+
} else {
|
|
25
|
+
errorOut("Usage: tl pin <name>@<version>");
|
|
26
|
+
}
|
|
27
|
+
throw new ExitError(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Parse name@version
|
|
31
|
+
const atIdx = nameArg.lastIndexOf("@");
|
|
32
|
+
if (atIdx === -1) {
|
|
33
|
+
if (json) {
|
|
34
|
+
jsonOut({ success: false, command: "pin", error: "Usage: tl pin <name>@<version>" });
|
|
35
|
+
} else {
|
|
36
|
+
errorOut("Usage: tl pin <name>@<version>");
|
|
37
|
+
}
|
|
38
|
+
throw new ExitError(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const name = nameArg.slice(0, atIdx);
|
|
42
|
+
const version = Number.parseInt(nameArg.slice(atIdx + 1), 10);
|
|
43
|
+
|
|
44
|
+
if (Number.isNaN(version)) {
|
|
45
|
+
errorOut("Version must be an integer");
|
|
46
|
+
throw new ExitError(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await acquireLock(promptsPath);
|
|
50
|
+
try {
|
|
51
|
+
const allRecords = await readJsonl<Prompt>(promptsPath);
|
|
52
|
+
const current = dedupById(allRecords);
|
|
53
|
+
|
|
54
|
+
const prompt = current.find((p) => p.name === name);
|
|
55
|
+
if (!prompt) {
|
|
56
|
+
if (json) {
|
|
57
|
+
jsonOut({ success: false, command: "pin", error: `Prompt '${name}' not found` });
|
|
58
|
+
} else {
|
|
59
|
+
errorOut(`Prompt '${name}' not found`);
|
|
60
|
+
}
|
|
61
|
+
throw new ExitError(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Verify the target version exists
|
|
65
|
+
const targetVersion = allRecords.find((p) => p.id === prompt.id && p.version === version);
|
|
66
|
+
if (!targetVersion) {
|
|
67
|
+
if (json) {
|
|
68
|
+
jsonOut({
|
|
69
|
+
success: false,
|
|
70
|
+
command: "pin",
|
|
71
|
+
error: `Version ${version} of '${name}' not found`,
|
|
72
|
+
});
|
|
73
|
+
} else {
|
|
74
|
+
errorOut(`Version ${version} of '${name}' not found`);
|
|
75
|
+
}
|
|
76
|
+
throw new ExitError(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const updated: Prompt = {
|
|
80
|
+
...prompt,
|
|
81
|
+
pinned: version,
|
|
82
|
+
version: prompt.version + 1,
|
|
83
|
+
updatedAt: new Date().toISOString(),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
await appendJsonl(promptsPath, updated);
|
|
87
|
+
|
|
88
|
+
if (json) {
|
|
89
|
+
jsonOut({ success: true, command: "pin", name, pinned: version });
|
|
90
|
+
} else {
|
|
91
|
+
humanOut(`${fmt.success("Pinned")} ${c.bold(name)} to v${version}`);
|
|
92
|
+
}
|
|
93
|
+
} finally {
|
|
94
|
+
releaseLock(promptsPath);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function defaultUnpin(args: string[], json: boolean): Promise<void> {
|
|
99
|
+
const cwd = process.cwd();
|
|
100
|
+
const promptsPath = join(cwd, ".trellis", "prompts.jsonl");
|
|
101
|
+
|
|
102
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
103
|
+
humanOut(`Usage: tl unpin <name> [options]
|
|
104
|
+
|
|
105
|
+
Options:
|
|
106
|
+
--json Output as JSON`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const name = args.filter((a) => !a.startsWith("--"))[0];
|
|
111
|
+
if (!name) {
|
|
112
|
+
if (json) {
|
|
113
|
+
jsonOut({ success: false, command: "unpin", error: "Prompt name required" });
|
|
114
|
+
} else {
|
|
115
|
+
errorOut("Usage: tl unpin <name>");
|
|
116
|
+
}
|
|
117
|
+
throw new ExitError(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await acquireLock(promptsPath);
|
|
121
|
+
try {
|
|
122
|
+
const allRecords = await readJsonl<Prompt>(promptsPath);
|
|
123
|
+
const current = dedupById(allRecords);
|
|
124
|
+
|
|
125
|
+
const prompt = current.find((p) => p.name === name);
|
|
126
|
+
if (!prompt) {
|
|
127
|
+
if (json) {
|
|
128
|
+
jsonOut({ success: false, command: "unpin", error: `Prompt '${name}' not found` });
|
|
129
|
+
} else {
|
|
130
|
+
errorOut(`Prompt '${name}' not found`);
|
|
131
|
+
}
|
|
132
|
+
throw new ExitError(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const updated: Prompt = {
|
|
136
|
+
...prompt,
|
|
137
|
+
version: prompt.version + 1,
|
|
138
|
+
updatedAt: new Date().toISOString(),
|
|
139
|
+
};
|
|
140
|
+
updated.pinned = undefined;
|
|
141
|
+
|
|
142
|
+
await appendJsonl(promptsPath, updated);
|
|
143
|
+
|
|
144
|
+
if (json) {
|
|
145
|
+
jsonOut({ success: true, command: "unpin", name });
|
|
146
|
+
} else {
|
|
147
|
+
humanOut(`${fmt.success("Unpinned")} ${c.bold(name)}`);
|
|
148
|
+
}
|
|
149
|
+
} finally {
|
|
150
|
+
releaseLock(promptsPath);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function registerPinCommand(program: Command): void {
|
|
155
|
+
program
|
|
156
|
+
.command("pin")
|
|
157
|
+
.description("Pin prompt to a specific version")
|
|
158
|
+
.argument("<name@version>", "Prompt name and version (e.g. my-prompt@2)")
|
|
159
|
+
.action(async (nameAtVersion: string) => {
|
|
160
|
+
const json: boolean = program.opts().json ?? false;
|
|
161
|
+
await pin([nameAtVersion], json);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
program
|
|
165
|
+
.command("unpin")
|
|
166
|
+
.description("Remove version pin from a prompt")
|
|
167
|
+
.argument("<name>", "Prompt name")
|
|
168
|
+
.action(async (name: string) => {
|
|
169
|
+
const json: boolean = program.opts().json ?? false;
|
|
170
|
+
await defaultUnpin([name], json);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import type { Command } from "commander";
|
|
3
|
+
import { isQuiet, jsonOut } from "../output.ts";
|
|
4
|
+
|
|
5
|
+
const PRIME_FILE = "PRIME.md";
|
|
6
|
+
|
|
7
|
+
function defaultPrimeContent(compact: boolean): string {
|
|
8
|
+
if (compact) {
|
|
9
|
+
return compactContent();
|
|
10
|
+
}
|
|
11
|
+
return fullContent();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function compactContent(): string {
|
|
15
|
+
return `# Trellis Quick Reference
|
|
16
|
+
|
|
17
|
+
\`\`\`
|
|
18
|
+
tl list # List all prompts
|
|
19
|
+
tl show <name> # View prompt record
|
|
20
|
+
tl render <name> # Render prompt (resolve inheritance)
|
|
21
|
+
tl emit <name> # Render and write to file
|
|
22
|
+
tl emit --all # Emit all active prompts
|
|
23
|
+
tl create --name "..." # Create a new prompt
|
|
24
|
+
tl update <name> # Update prompt (new version)
|
|
25
|
+
tl import <path> # Import existing .md as prompt
|
|
26
|
+
tl sync # Stage + commit .trellis/
|
|
27
|
+
\`\`\`
|
|
28
|
+
|
|
29
|
+
**Do not manually edit emitted files.** Use \`tl update\` to modify prompts.
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function fullContent(): string {
|
|
34
|
+
return `# Trellis Workflow Context
|
|
35
|
+
|
|
36
|
+
> **Context Recovery**: Run \`tl prime\` after compaction, clear, or new session
|
|
37
|
+
|
|
38
|
+
## Core Rules
|
|
39
|
+
- **Storage**: Prompts live in \`.trellis/prompts.jsonl\` — never edit this file by hand
|
|
40
|
+
- **Emit files are generated**: Do NOT manually edit files in the emit directory; use \`tl update\` instead
|
|
41
|
+
- **Composition**: Prompts are composed via sections and inheritance, not duplicated
|
|
42
|
+
- **Git-native**: JSONL storage is diffable/mergeable; \`merge=union\` gitattribute handles branch merges
|
|
43
|
+
|
|
44
|
+
## Essential Commands
|
|
45
|
+
|
|
46
|
+
### Viewing Prompts
|
|
47
|
+
- \`tl list\` — List all prompts (name, version, status, tags)
|
|
48
|
+
- \`tl show <name>\` — Show full prompt record (sections, metadata)
|
|
49
|
+
- \`tl show <name>@<v>\` — Show specific version
|
|
50
|
+
- \`tl render <name>\` — Render full prompt (resolves inheritance chain)
|
|
51
|
+
- \`tl tree <name>\` — Show inheritance tree
|
|
52
|
+
- \`tl history <name>\` — Show version timeline
|
|
53
|
+
- \`tl diff <name> <v1> <v2>\` — Section-aware diff between versions
|
|
54
|
+
|
|
55
|
+
### Creating & Updating
|
|
56
|
+
- \`tl create --name "..." --section "role:You are..." --tag agent\` — Create prompt
|
|
57
|
+
- \`tl update <name> --section "role:Updated content"\` — Update (creates new version)
|
|
58
|
+
- \`tl import <path>\` — Import existing .md file as a prompt
|
|
59
|
+
- \`tl archive <name>\` — Archive a prompt
|
|
60
|
+
|
|
61
|
+
### Emitting
|
|
62
|
+
- \`tl emit <name>\` — Render and write prompt to a file
|
|
63
|
+
- \`tl emit --all\` — Emit all active prompts
|
|
64
|
+
- \`tl emit --check\` — Check if emitted files are up to date
|
|
65
|
+
|
|
66
|
+
### Schemas & Validation
|
|
67
|
+
- \`tl schema create --name "..." --required "role,task"\` — Create validation schema
|
|
68
|
+
- \`tl validate <name>\` — Validate prompt against its schema
|
|
69
|
+
- \`tl validate --all\` — Validate all prompts with schemas
|
|
70
|
+
|
|
71
|
+
### Versioning
|
|
72
|
+
- \`tl pin <name>@<version>\` — Pin prompt to a specific version
|
|
73
|
+
- \`tl unpin <name>\` — Remove version pin
|
|
74
|
+
|
|
75
|
+
### Sync
|
|
76
|
+
- \`tl sync\` — Stage and commit .trellis/ changes
|
|
77
|
+
|
|
78
|
+
## Loam Metadata
|
|
79
|
+
|
|
80
|
+
Prompts can declare loam (expertise) dependencies inline. Trellis stores the declaration as metadata and surfaces it in the render envelope — **trellis never shells out to \`ml\`**. Consumers (warren, overstory) read the resolved \`loam\` field and run \`ml prime\` themselves.
|
|
81
|
+
|
|
82
|
+
Schema fields on a prompt record:
|
|
83
|
+
- \`loam.prime.domains[]\` — domain names to prime
|
|
84
|
+
- \`loam.prime.files[]\` — file globs that scope priming
|
|
85
|
+
- \`loam.budget\` — non-negative number, consumer-defined units
|
|
86
|
+
- \`loam.on_empty\` — \`"skip"\` | \`"warn"\` | \`"error"\`
|
|
87
|
+
- \`extends_loam\` — boolean (default false): when true, child merges with parent's loam (union domains/files, last-wins budget/on_empty); when false, child wholesale overrides
|
|
88
|
+
|
|
89
|
+
\`tl render <name> --json\` includes a top-level \`loam\` field whenever any role in the chain declared one. The field is **omitted entirely** (not null, not {}) when no role declared loam — absent vs. empty is semantically distinct.
|
|
90
|
+
|
|
91
|
+
\`tl doctor\` runs an optional \`loam-domains\` check that warns on domains not declared in \`.loam/loam.config.yaml\`. The check is a typo guard, not a hard gate.
|
|
92
|
+
|
|
93
|
+
See SPEC.md "Loam Metadata" for full semantics.
|
|
94
|
+
|
|
95
|
+
## Common Workflows
|
|
96
|
+
|
|
97
|
+
**Viewing what's available:**
|
|
98
|
+
\`\`\`bash
|
|
99
|
+
tl list # See all prompts
|
|
100
|
+
tl render <name> # See full rendered output
|
|
101
|
+
tl tree <name> # Understand inheritance
|
|
102
|
+
\`\`\`
|
|
103
|
+
|
|
104
|
+
**Creating a new prompt:**
|
|
105
|
+
\`\`\`bash
|
|
106
|
+
tl create --name "agent-v1" --section "role:You are a helpful assistant" --tag agent
|
|
107
|
+
tl emit agent-v1 # Write to agents/agent-v1.md
|
|
108
|
+
tl sync # Commit changes
|
|
109
|
+
\`\`\`
|
|
110
|
+
|
|
111
|
+
**Updating an existing prompt:**
|
|
112
|
+
\`\`\`bash
|
|
113
|
+
tl show <name> # Review current state
|
|
114
|
+
tl update <name> --section "role:Updated instructions"
|
|
115
|
+
tl emit <name> # Re-emit with changes
|
|
116
|
+
tl sync # Commit changes
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
**Importing from an existing file:**
|
|
120
|
+
\`\`\`bash
|
|
121
|
+
tl import path/to/prompt.md # Import as trellis prompt
|
|
122
|
+
tl emit <name> # Verify emit output
|
|
123
|
+
\`\`\`
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default async function prime(args: string[], json: boolean): Promise<void> {
|
|
128
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
129
|
+
if (!isQuiet()) {
|
|
130
|
+
process.stdout.write(`Usage: tl prime [options]
|
|
131
|
+
|
|
132
|
+
Outputs trellis workflow context for AI agent sessions.
|
|
133
|
+
|
|
134
|
+
Options:
|
|
135
|
+
--compact Output minimal quick-reference
|
|
136
|
+
--export Output default template (ignores custom PRIME.md)
|
|
137
|
+
--json Output as JSON
|
|
138
|
+
`);
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const compact = args.includes("--compact");
|
|
144
|
+
const exportMode = args.includes("--export");
|
|
145
|
+
|
|
146
|
+
// --export always outputs the default template
|
|
147
|
+
if (exportMode) {
|
|
148
|
+
const content = defaultPrimeContent(false);
|
|
149
|
+
if (json) {
|
|
150
|
+
jsonOut({ success: true, command: "prime", content });
|
|
151
|
+
} else if (!isQuiet()) {
|
|
152
|
+
process.stdout.write(content);
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Try to find .trellis dir for custom PRIME.md
|
|
158
|
+
let content: string | null = null;
|
|
159
|
+
try {
|
|
160
|
+
const trellisDir = join(process.cwd(), ".trellis");
|
|
161
|
+
const customFile = Bun.file(join(trellisDir, PRIME_FILE));
|
|
162
|
+
if (await customFile.exists()) {
|
|
163
|
+
content = await customFile.text();
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
// No .trellis dir — that's fine, use default
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!content) {
|
|
170
|
+
content = defaultPrimeContent(compact);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (json) {
|
|
174
|
+
jsonOut({ success: true, command: "prime", content });
|
|
175
|
+
} else if (!isQuiet()) {
|
|
176
|
+
process.stdout.write(content);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function registerPrimeCommand(program: Command): void {
|
|
181
|
+
program
|
|
182
|
+
.command("prime")
|
|
183
|
+
.description("Output workflow context for AI agents")
|
|
184
|
+
.option("--compact", "Output minimal quick-reference")
|
|
185
|
+
.option("--export", "Output default template (ignores custom PRIME.md)")
|
|
186
|
+
.action(async (opts: Record<string, unknown>) => {
|
|
187
|
+
const json: boolean = program.opts().json ?? false;
|
|
188
|
+
const args: string[] = [];
|
|
189
|
+
if (opts.compact) args.push("--compact");
|
|
190
|
+
if (opts.export) args.push("--export");
|
|
191
|
+
await prime(args, json);
|
|
192
|
+
});
|
|
193
|
+
}
|