@cairn-tool/cairn 2.0.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/.markdownlintrc +7 -0
- package/LICENSE +21 -0
- package/README.md +1431 -0
- package/dist/agent/audit/baseline.d.ts +69 -0
- package/dist/agent/audit/baseline.js +128 -0
- package/dist/agent/audit/baseline.js.map +1 -0
- package/dist/agent/audit/index.d.ts +126 -0
- package/dist/agent/audit/index.js +625 -0
- package/dist/agent/audit/index.js.map +1 -0
- package/dist/agent/import/detect.d.ts +49 -0
- package/dist/agent/import/detect.js +159 -0
- package/dist/agent/import/detect.js.map +1 -0
- package/dist/agent/import/normalize.d.ts +72 -0
- package/dist/agent/import/normalize.js +475 -0
- package/dist/agent/import/normalize.js.map +1 -0
- package/dist/agent/install/index.d.ts +211 -0
- package/dist/agent/install/index.js +907 -0
- package/dist/agent/install/index.js.map +1 -0
- package/dist/agent/manifest.d.ts +75 -0
- package/dist/agent/manifest.js +210 -0
- package/dist/agent/manifest.js.map +1 -0
- package/dist/agent/marketplace/index.d.ts +69 -0
- package/dist/agent/marketplace/index.js +212 -0
- package/dist/agent/marketplace/index.js.map +1 -0
- package/dist/agent/marketplace/spec.d.ts +48 -0
- package/dist/agent/marketplace/spec.js +237 -0
- package/dist/agent/marketplace/spec.js.map +1 -0
- package/dist/agent/output.d.ts +36 -0
- package/dist/agent/output.js +56 -0
- package/dist/agent/output.js.map +1 -0
- package/dist/agent/overlays.d.ts +38 -0
- package/dist/agent/overlays.js +223 -0
- package/dist/agent/overlays.js.map +1 -0
- package/dist/agent/package/index.d.ts +105 -0
- package/dist/agent/package/index.js +339 -0
- package/dist/agent/package/index.js.map +1 -0
- package/dist/agent/package/tar.d.ts +36 -0
- package/dist/agent/package/tar.js +137 -0
- package/dist/agent/package/tar.js.map +1 -0
- package/dist/agent/parser.d.ts +13 -0
- package/dist/agent/parser.js +559 -0
- package/dist/agent/parser.js.map +1 -0
- package/dist/agent/render.d.ts +16 -0
- package/dist/agent/render.js +721 -0
- package/dist/agent/render.js.map +1 -0
- package/dist/agent/sarif.d.ts +18 -0
- package/dist/agent/sarif.js +56 -0
- package/dist/agent/sarif.js.map +1 -0
- package/dist/agent/scaffold.d.ts +86 -0
- package/dist/agent/scaffold.js +250 -0
- package/dist/agent/scaffold.js.map +1 -0
- package/dist/agent/targets/antigravity.d.ts +17 -0
- package/dist/agent/targets/antigravity.js +218 -0
- package/dist/agent/targets/antigravity.js.map +1 -0
- package/dist/agent/targets/claude-code.d.ts +2 -0
- package/dist/agent/targets/claude-code.js +220 -0
- package/dist/agent/targets/claude-code.js.map +1 -0
- package/dist/agent/targets/codex.d.ts +2 -0
- package/dist/agent/targets/codex.js +212 -0
- package/dist/agent/targets/codex.js.map +1 -0
- package/dist/agent/targets/cursor.d.ts +2 -0
- package/dist/agent/targets/cursor.js +210 -0
- package/dist/agent/targets/cursor.js.map +1 -0
- package/dist/agent/targets/index.d.ts +31 -0
- package/dist/agent/targets/index.js +64 -0
- package/dist/agent/targets/index.js.map +1 -0
- package/dist/agent/targets/opencode.d.ts +15 -0
- package/dist/agent/targets/opencode.js +215 -0
- package/dist/agent/targets/opencode.js.map +1 -0
- package/dist/agent/targets/schema.d.ts +315 -0
- package/dist/agent/targets/schema.js +179 -0
- package/dist/agent/targets/schema.js.map +1 -0
- package/dist/agent/test/assert.d.ts +46 -0
- package/dist/agent/test/assert.js +288 -0
- package/dist/agent/test/assert.js.map +1 -0
- package/dist/agent/test/index.d.ts +73 -0
- package/dist/agent/test/index.js +181 -0
- package/dist/agent/test/index.js.map +1 -0
- package/dist/agent/test/schema.d.ts +81 -0
- package/dist/agent/test/schema.js +235 -0
- package/dist/agent/test/schema.js.map +1 -0
- package/dist/agent/types.d.ts +204 -0
- package/dist/agent/types.js +11 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/agent/upgrade.d.ts +29 -0
- package/dist/agent/upgrade.js +72 -0
- package/dist/agent/upgrade.js.map +1 -0
- package/dist/agent/writer.d.ts +30 -0
- package/dist/agent/writer.js +73 -0
- package/dist/agent/writer.js.map +1 -0
- package/dist/archive/db.d.ts +20 -0
- package/dist/archive/db.js +98 -0
- package/dist/archive/db.js.map +1 -0
- package/dist/archive/progress.d.ts +62 -0
- package/dist/archive/progress.js +151 -0
- package/dist/archive/progress.js.map +1 -0
- package/dist/archive/query.d.ts +86 -0
- package/dist/archive/query.js +241 -0
- package/dist/archive/query.js.map +1 -0
- package/dist/archive/run.d.ts +91 -0
- package/dist/archive/run.js +331 -0
- package/dist/archive/run.js.map +1 -0
- package/dist/archive/segments.d.ts +89 -0
- package/dist/archive/segments.js +144 -0
- package/dist/archive/segments.js.map +1 -0
- package/dist/archive/sets.d.ts +58 -0
- package/dist/archive/sets.js +344 -0
- package/dist/archive/sets.js.map +1 -0
- package/dist/archive/tar-read.d.ts +35 -0
- package/dist/archive/tar-read.js +90 -0
- package/dist/archive/tar-read.js.map +1 -0
- package/dist/audit-baseline.d.ts +66 -0
- package/dist/audit-baseline.js +124 -0
- package/dist/audit-baseline.js.map +1 -0
- package/dist/automation.d.ts +16 -0
- package/dist/automation.js +38 -0
- package/dist/automation.js.map +1 -0
- package/dist/backlinks.d.ts +15 -0
- package/dist/backlinks.js +30 -0
- package/dist/backlinks.js.map +1 -0
- package/dist/checkers/katex.d.ts +3 -0
- package/dist/checkers/katex.js +71 -0
- package/dist/checkers/katex.js.map +1 -0
- package/dist/checkers/markdown-lint.d.ts +28 -0
- package/dist/checkers/markdown-lint.js +53 -0
- package/dist/checkers/markdown-lint.js.map +1 -0
- package/dist/checkers/mermaid.d.ts +6 -0
- package/dist/checkers/mermaid.js +53 -0
- package/dist/checkers/mermaid.js.map +1 -0
- package/dist/checkers/references.d.ts +3 -0
- package/dist/checkers/references.js +55 -0
- package/dist/checkers/references.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1117 -0
- package/dist/cli.js.map +1 -0
- package/dist/command-result.d.ts +6 -0
- package/dist/command-result.js +13 -0
- package/dist/command-result.js.map +1 -0
- package/dist/commands/agent-audit.d.ts +21 -0
- package/dist/commands/agent-audit.js +119 -0
- package/dist/commands/agent-audit.js.map +1 -0
- package/dist/commands/agent-doctor.d.ts +25 -0
- package/dist/commands/agent-doctor.js +217 -0
- package/dist/commands/agent-doctor.js.map +1 -0
- package/dist/commands/agent-import.d.ts +21 -0
- package/dist/commands/agent-import.js +212 -0
- package/dist/commands/agent-import.js.map +1 -0
- package/dist/commands/agent-install.d.ts +18 -0
- package/dist/commands/agent-install.js +59 -0
- package/dist/commands/agent-install.js.map +1 -0
- package/dist/commands/agent-installed.d.ts +6 -0
- package/dist/commands/agent-installed.js +17 -0
- package/dist/commands/agent-installed.js.map +1 -0
- package/dist/commands/agent-marketplace.d.ts +11 -0
- package/dist/commands/agent-marketplace.js +178 -0
- package/dist/commands/agent-marketplace.js.map +1 -0
- package/dist/commands/agent-package.d.ts +16 -0
- package/dist/commands/agent-package.js +159 -0
- package/dist/commands/agent-package.js.map +1 -0
- package/dist/commands/agent-scaffold.d.ts +17 -0
- package/dist/commands/agent-scaffold.js +181 -0
- package/dist/commands/agent-scaffold.js.map +1 -0
- package/dist/commands/agent-specs.d.ts +7 -0
- package/dist/commands/agent-specs.js +20 -0
- package/dist/commands/agent-specs.js.map +1 -0
- package/dist/commands/agent-test.d.ts +21 -0
- package/dist/commands/agent-test.js +50 -0
- package/dist/commands/agent-test.js.map +1 -0
- package/dist/commands/agent-uninstall.d.ts +6 -0
- package/dist/commands/agent-uninstall.js +45 -0
- package/dist/commands/agent-uninstall.js.map +1 -0
- package/dist/commands/agent-upgrade.d.ts +5 -0
- package/dist/commands/agent-upgrade.js +105 -0
- package/dist/commands/agent-upgrade.js.map +1 -0
- package/dist/commands/agent.d.ts +27 -0
- package/dist/commands/agent.js +549 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/archive.d.ts +47 -0
- package/dist/commands/archive.js +311 -0
- package/dist/commands/archive.js.map +1 -0
- package/dist/commands/audit.d.ts +25 -0
- package/dist/commands/audit.js +325 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/check-snippets.d.ts +58 -0
- package/dist/commands/check-snippets.js +247 -0
- package/dist/commands/check-snippets.js.map +1 -0
- package/dist/commands/check-urls.d.ts +52 -0
- package/dist/commands/check-urls.js +205 -0
- package/dist/commands/check-urls.js.map +1 -0
- package/dist/commands/code-blocks.d.ts +8 -0
- package/dist/commands/code-blocks.js +66 -0
- package/dist/commands/code-blocks.js.map +1 -0
- package/dist/commands/completion.d.ts +15 -0
- package/dist/commands/completion.js +20 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/context.d.ts +16 -0
- package/dist/commands/context.js +131 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/describe.d.ts +12 -0
- package/dist/commands/describe.js +62 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/diff.d.ts +11 -0
- package/dist/commands/diff.js +185 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/fix.d.ts +59 -0
- package/dist/commands/fix.js +173 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/frontmatter.d.ts +7 -0
- package/dist/commands/frontmatter.js +84 -0
- package/dist/commands/frontmatter.js.map +1 -0
- package/dist/commands/graph.d.ts +12 -0
- package/dist/commands/graph.js +122 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/headers.d.ts +7 -0
- package/dist/commands/headers.js +48 -0
- package/dist/commands/headers.js.map +1 -0
- package/dist/commands/index.d.ts +8 -0
- package/dist/commands/index.js +32 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/links.d.ts +9 -0
- package/dist/commands/links.js +123 -0
- package/dist/commands/links.js.map +1 -0
- package/dist/commands/lint-dir.d.ts +15 -0
- package/dist/commands/lint-dir.js +156 -0
- package/dist/commands/lint-dir.js.map +1 -0
- package/dist/commands/lint.d.ts +14 -0
- package/dist/commands/lint.js +45 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/orphans.d.ts +10 -0
- package/dist/commands/orphans.js +74 -0
- package/dist/commands/orphans.js.map +1 -0
- package/dist/commands/outline.d.ts +7 -0
- package/dist/commands/outline.js +54 -0
- package/dist/commands/outline.js.map +1 -0
- package/dist/commands/query.d.ts +18 -0
- package/dist/commands/query.js +341 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/refs-to.d.ts +8 -0
- package/dist/commands/refs-to.js +65 -0
- package/dist/commands/refs-to.js.map +1 -0
- package/dist/commands/refs.d.ts +10 -0
- package/dist/commands/refs.js +103 -0
- package/dist/commands/refs.js.map +1 -0
- package/dist/commands/rename-file.d.ts +16 -0
- package/dist/commands/rename-file.js +215 -0
- package/dist/commands/rename-file.js.map +1 -0
- package/dist/commands/rename-heading.d.ts +10 -0
- package/dist/commands/rename-heading.js +182 -0
- package/dist/commands/rename-heading.js.map +1 -0
- package/dist/commands/schema.d.ts +10 -0
- package/dist/commands/schema.js +34 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/scripts.d.ts +59 -0
- package/dist/commands/scripts.js +222 -0
- package/dist/commands/scripts.js.map +1 -0
- package/dist/commands/section.d.ts +9 -0
- package/dist/commands/section.js +49 -0
- package/dist/commands/section.js.map +1 -0
- package/dist/commands/serve.d.ts +6 -0
- package/dist/commands/serve.js +48 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/stats.d.ts +6 -0
- package/dist/commands/stats.js +109 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/structure.d.ts +6 -0
- package/dist/commands/structure.js +130 -0
- package/dist/commands/structure.js.map +1 -0
- package/dist/commands/tables.d.ts +8 -0
- package/dist/commands/tables.js +77 -0
- package/dist/commands/tables.js.map +1 -0
- package/dist/commands/tasks.d.ts +8 -0
- package/dist/commands/tasks.js +59 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/commands/toc.d.ts +18 -0
- package/dist/commands/toc.js +105 -0
- package/dist/commands/toc.js.map +1 -0
- package/dist/commands/update-check.d.ts +36 -0
- package/dist/commands/update-check.js +119 -0
- package/dist/commands/update-check.js.map +1 -0
- package/dist/commands/usage.d.ts +56 -0
- package/dist/commands/usage.js +883 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/commands/validate-frontmatter.d.ts +13 -0
- package/dist/commands/validate-frontmatter.js +34 -0
- package/dist/commands/validate-frontmatter.js.map +1 -0
- package/dist/completion/model.d.ts +49 -0
- package/dist/completion/model.js +194 -0
- package/dist/completion/model.js.map +1 -0
- package/dist/completion/shells.d.ts +2 -0
- package/dist/completion/shells.js +280 -0
- package/dist/completion/shells.js.map +1 -0
- package/dist/config-schema.d.ts +15 -0
- package/dist/config-schema.js +44 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +102 -0
- package/dist/config.js +614 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +106 -0
- package/dist/context.js +202 -0
- package/dist/context.js.map +1 -0
- package/dist/contract/describe.d.ts +84 -0
- package/dist/contract/describe.js +104 -0
- package/dist/contract/describe.js.map +1 -0
- package/dist/contract/registry.d.ts +2 -0
- package/dist/contract/registry.js +622 -0
- package/dist/contract/registry.js.map +1 -0
- package/dist/contract/schemas/agent.d.ts +2 -0
- package/dist/contract/schemas/agent.js +572 -0
- package/dist/contract/schemas/agent.js.map +1 -0
- package/dist/contract/schemas/archive.d.ts +3 -0
- package/dist/contract/schemas/archive.js +227 -0
- package/dist/contract/schemas/archive.js.map +1 -0
- package/dist/contract/schemas/index.d.ts +11 -0
- package/dist/contract/schemas/index.js +49 -0
- package/dist/contract/schemas/index.js.map +1 -0
- package/dist/contract/schemas/markdown.d.ts +15 -0
- package/dist/contract/schemas/markdown.js +1035 -0
- package/dist/contract/schemas/markdown.js.map +1 -0
- package/dist/contract/schemas/meta.d.ts +5 -0
- package/dist/contract/schemas/meta.js +233 -0
- package/dist/contract/schemas/meta.js.map +1 -0
- package/dist/contract/schemas/scripts.d.ts +4 -0
- package/dist/contract/schemas/scripts.js +183 -0
- package/dist/contract/schemas/scripts.js.map +1 -0
- package/dist/contract/schemas/shared.d.ts +11 -0
- package/dist/contract/schemas/shared.js +26 -0
- package/dist/contract/schemas/shared.js.map +1 -0
- package/dist/contract/schemas/usage.d.ts +6 -0
- package/dist/contract/schemas/usage.js +489 -0
- package/dist/contract/schemas/usage.js.map +1 -0
- package/dist/contract/types.d.ts +63 -0
- package/dist/contract/types.js +2 -0
- package/dist/contract/types.js.map +1 -0
- package/dist/contract/version.d.ts +20 -0
- package/dist/contract/version.js +21 -0
- package/dist/contract/version.js.map +1 -0
- package/dist/diff.d.ts +156 -0
- package/dist/diff.js +500 -0
- package/dist/diff.js.map +1 -0
- package/dist/edit-plan.d.ts +133 -0
- package/dist/edit-plan.js +245 -0
- package/dist/edit-plan.js.map +1 -0
- package/dist/fix/markdownlint-fixer.d.ts +34 -0
- package/dist/fix/markdownlint-fixer.js +125 -0
- package/dist/fix/markdownlint-fixer.js.map +1 -0
- package/dist/fix/registry.d.ts +48 -0
- package/dist/fix/registry.js +28 -0
- package/dist/fix/registry.js.map +1 -0
- package/dist/fix/relative-links-fixer.d.ts +21 -0
- package/dist/fix/relative-links-fixer.js +96 -0
- package/dist/fix/relative-links-fixer.js.map +1 -0
- package/dist/fix/snippets-fixer.d.ts +2 -0
- package/dist/fix/snippets-fixer.js +64 -0
- package/dist/fix/snippets-fixer.js.map +1 -0
- package/dist/fix/toc-fixer.d.ts +2 -0
- package/dist/fix/toc-fixer.js +94 -0
- package/dist/fix/toc-fixer.js.map +1 -0
- package/dist/formats.d.ts +22 -0
- package/dist/formats.js +34 -0
- package/dist/formats.js.map +1 -0
- package/dist/formatters.d.ts +11 -0
- package/dist/formatters.js +48 -0
- package/dist/formatters.js.map +1 -0
- package/dist/frontmatter-validation.d.ts +11 -0
- package/dist/frontmatter-validation.js +188 -0
- package/dist/frontmatter-validation.js.map +1 -0
- package/dist/git.d.ts +40 -0
- package/dist/git.js +124 -0
- package/dist/git.js.map +1 -0
- package/dist/graph.d.ts +50 -0
- package/dist/graph.js +200 -0
- package/dist/graph.js.map +1 -0
- package/dist/input-selection.d.ts +9 -0
- package/dist/input-selection.js +122 -0
- package/dist/input-selection.js.map +1 -0
- package/dist/input.d.ts +2 -0
- package/dist/input.js +32 -0
- package/dist/input.js.map +1 -0
- package/dist/link-target.d.ts +39 -0
- package/dist/link-target.js +68 -0
- package/dist/link-target.js.map +1 -0
- package/dist/lint.d.ts +13 -0
- package/dist/lint.js +27 -0
- package/dist/lint.js.map +1 -0
- package/dist/markdown-ast.d.ts +73 -0
- package/dist/markdown-ast.js +187 -0
- package/dist/markdown-ast.js.map +1 -0
- package/dist/object-path.d.ts +14 -0
- package/dist/object-path.js +14 -0
- package/dist/object-path.js.map +1 -0
- package/dist/option-utils.d.ts +13 -0
- package/dist/option-utils.js +25 -0
- package/dist/option-utils.js.map +1 -0
- package/dist/outline.d.ts +16 -0
- package/dist/outline.js +32 -0
- package/dist/outline.js.map +1 -0
- package/dist/query/entities.d.ts +60 -0
- package/dist/query/entities.js +219 -0
- package/dist/query/entities.js.map +1 -0
- package/dist/query/execute.d.ts +22 -0
- package/dist/query/execute.js +0 -0
- package/dist/query/execute.js.map +1 -0
- package/dist/query/plan.d.ts +76 -0
- package/dist/query/plan.js +183 -0
- package/dist/query/plan.js.map +1 -0
- package/dist/query/render.d.ts +3 -0
- package/dist/query/render.js +39 -0
- package/dist/query/render.js.map +1 -0
- package/dist/refs.d.ts +19 -0
- package/dist/refs.js +10 -0
- package/dist/refs.js.map +1 -0
- package/dist/result.d.ts +49 -0
- package/dist/result.js +47 -0
- package/dist/result.js.map +1 -0
- package/dist/runtime.d.ts +35 -0
- package/dist/runtime.js +77 -0
- package/dist/runtime.js.map +1 -0
- package/dist/sarif.d.ts +36 -0
- package/dist/sarif.js +30 -0
- package/dist/sarif.js.map +1 -0
- package/dist/scripts/execute.d.ts +65 -0
- package/dist/scripts/execute.js +235 -0
- package/dist/scripts/execute.js.map +1 -0
- package/dist/scripts/registry.d.ts +55 -0
- package/dist/scripts/registry.js +103 -0
- package/dist/scripts/registry.js.map +1 -0
- package/dist/scripts/resolve.d.ts +90 -0
- package/dist/scripts/resolve.js +288 -0
- package/dist/scripts/resolve.js.map +1 -0
- package/dist/sections.d.ts +53 -0
- package/dist/sections.js +100 -0
- package/dist/sections.js.map +1 -0
- package/dist/serve/errors.d.ts +25 -0
- package/dist/serve/errors.js +45 -0
- package/dist/serve/errors.js.map +1 -0
- package/dist/serve/paths.d.ts +32 -0
- package/dist/serve/paths.js +71 -0
- package/dist/serve/paths.js.map +1 -0
- package/dist/serve/server.d.ts +31 -0
- package/dist/serve/server.js +123 -0
- package/dist/serve/server.js.map +1 -0
- package/dist/serve/tools.d.ts +19 -0
- package/dist/serve/tools.js +597 -0
- package/dist/serve/tools.js.map +1 -0
- package/dist/snippets.d.ts +184 -0
- package/dist/snippets.js +454 -0
- package/dist/snippets.js.map +1 -0
- package/dist/sqlite-store.d.ts +62 -0
- package/dist/sqlite-store.js +104 -0
- package/dist/sqlite-store.js.map +1 -0
- package/dist/sqlite.d.ts +59 -0
- package/dist/sqlite.js +51 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/toc.d.ts +58 -0
- package/dist/toc.js +83 -0
- package/dist/toc.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/update-notifier.d.ts +95 -0
- package/dist/update-notifier.js +301 -0
- package/dist/update-notifier.js.map +1 -0
- package/dist/url-cache.d.ts +14 -0
- package/dist/url-cache.js +70 -0
- package/dist/url-cache.js.map +1 -0
- package/dist/usage/aggregate.d.ts +107 -0
- package/dist/usage/aggregate.js +435 -0
- package/dist/usage/aggregate.js.map +1 -0
- package/dist/usage/db/index.d.ts +49 -0
- package/dist/usage/db/index.js +118 -0
- package/dist/usage/db/index.js.map +1 -0
- package/dist/usage/db/migrations.d.ts +29 -0
- package/dist/usage/db/migrations.js +38 -0
- package/dist/usage/db/migrations.js.map +1 -0
- package/dist/usage/db/open.d.ts +33 -0
- package/dist/usage/db/open.js +37 -0
- package/dist/usage/db/open.js.map +1 -0
- package/dist/usage/db/schema.d.ts +18 -0
- package/dist/usage/db/schema.js +147 -0
- package/dist/usage/db/schema.js.map +1 -0
- package/dist/usage/db/store.d.ts +74 -0
- package/dist/usage/db/store.js +280 -0
- package/dist/usage/db/store.js.map +1 -0
- package/dist/usage/events.d.ts +202 -0
- package/dist/usage/events.js +243 -0
- package/dist/usage/events.js.map +1 -0
- package/dist/usage/filter.d.ts +43 -0
- package/dist/usage/filter.js +97 -0
- package/dist/usage/filter.js.map +1 -0
- package/dist/usage/providers/antigravity.d.ts +2 -0
- package/dist/usage/providers/antigravity.js +431 -0
- package/dist/usage/providers/antigravity.js.map +1 -0
- package/dist/usage/providers/claude-code.d.ts +2 -0
- package/dist/usage/providers/claude-code.js +400 -0
- package/dist/usage/providers/claude-code.js.map +1 -0
- package/dist/usage/providers/codex.d.ts +2 -0
- package/dist/usage/providers/codex.js +387 -0
- package/dist/usage/providers/codex.js.map +1 -0
- package/dist/usage/providers/gemini-cli.d.ts +2 -0
- package/dist/usage/providers/gemini-cli.js +466 -0
- package/dist/usage/providers/gemini-cli.js.map +1 -0
- package/dist/usage/providers/index.d.ts +23 -0
- package/dist/usage/providers/index.js +46 -0
- package/dist/usage/providers/index.js.map +1 -0
- package/dist/usage/providers/opencode.d.ts +2 -0
- package/dist/usage/providers/opencode.js +422 -0
- package/dist/usage/providers/opencode.js.map +1 -0
- package/dist/usage/providers/protobuf.d.ts +35 -0
- package/dist/usage/providers/protobuf.js +125 -0
- package/dist/usage/providers/protobuf.js.map +1 -0
- package/dist/usage/providers/types.d.ts +74 -0
- package/dist/usage/providers/types.js +2 -0
- package/dist/usage/providers/types.js.map +1 -0
- package/dist/usage/scan.d.ts +54 -0
- package/dist/usage/scan.js +216 -0
- package/dist/usage/scan.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/dist/workspace-index.d.ts +39 -0
- package/dist/workspace-index.js +265 -0
- package/dist/workspace-index.js.map +1 -0
- package/dist/workspace.d.ts +89 -0
- package/dist/workspace.js +219 -0
- package/dist/workspace.js.map +1 -0
- package/package.json +92 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { TARGETS } from "./agent/types.js";
|
|
5
|
+
import { lintAction } from "./commands/lint.js";
|
|
6
|
+
import { lintDirAction } from "./commands/lint-dir.js";
|
|
7
|
+
import { refsAction } from "./commands/refs.js";
|
|
8
|
+
import { refsToAction } from "./commands/refs-to.js";
|
|
9
|
+
import { headersAction } from "./commands/headers.js";
|
|
10
|
+
import { outlineAction } from "./commands/outline.js";
|
|
11
|
+
import { tocAction } from "./commands/toc.js";
|
|
12
|
+
import { statsAction } from "./commands/stats.js";
|
|
13
|
+
import { codeBlocksAction } from "./commands/code-blocks.js";
|
|
14
|
+
import { structureAction } from "./commands/structure.js";
|
|
15
|
+
import { linksAction } from "./commands/links.js";
|
|
16
|
+
import { sectionAction } from "./commands/section.js";
|
|
17
|
+
import { frontmatterAction } from "./commands/frontmatter.js";
|
|
18
|
+
import { tasksAction } from "./commands/tasks.js";
|
|
19
|
+
import { tablesAction } from "./commands/tables.js";
|
|
20
|
+
import { checkUrlsAction } from "./commands/check-urls.js";
|
|
21
|
+
import { orphansAction } from "./commands/orphans.js";
|
|
22
|
+
import { renameHeadingAction } from "./commands/rename-heading.js";
|
|
23
|
+
import { renameFileAction } from "./commands/rename-file.js";
|
|
24
|
+
import { graphAction } from "./commands/graph.js";
|
|
25
|
+
import { validateFrontmatterAction } from "./commands/validate-frontmatter.js";
|
|
26
|
+
import { auditAction } from "./commands/audit.js";
|
|
27
|
+
import { queryAction } from "./commands/query.js";
|
|
28
|
+
import { contextAction } from "./commands/context.js";
|
|
29
|
+
import { diffAction } from "./commands/diff.js";
|
|
30
|
+
import { fixAction } from "./commands/fix.js";
|
|
31
|
+
import { checkSnippetsAction } from "./commands/check-snippets.js";
|
|
32
|
+
import { indexAction } from "./commands/index.js";
|
|
33
|
+
import { checkUpdateAction, refreshUpdateCacheAction } from "./commands/update-check.js";
|
|
34
|
+
import { installUpdateNotifier, CHECK_COMMAND, REFRESH_COMMAND } from "./update-notifier.js";
|
|
35
|
+
import { loadConfig, selectConfig, selectRoot, defaultLintConcurrency } from "./config.js";
|
|
36
|
+
import { commandOptions, initializeRuntime, runtime } from "./runtime.js";
|
|
37
|
+
import { CommandExit } from "./command-result.js";
|
|
38
|
+
import { collect } from "./option-utils.js";
|
|
39
|
+
import { formatsFor } from "./formats.js";
|
|
40
|
+
import { packageName, packageVersion as version } from "./version.js";
|
|
41
|
+
import { agentCompatAction, agentConvertAction, agentInspectAction, agentValidateAction, agentActionBoundary, } from "./commands/agent.js";
|
|
42
|
+
import { agentSpecsAction } from "./commands/agent-specs.js";
|
|
43
|
+
import { agentAddAction, agentInitAction } from "./commands/agent-scaffold.js";
|
|
44
|
+
import { agentUpgradeAction } from "./commands/agent-upgrade.js";
|
|
45
|
+
import { agentImportAction } from "./commands/agent-import.js";
|
|
46
|
+
import { agentPackageAction } from "./commands/agent-package.js";
|
|
47
|
+
import { agentMarketplaceAction } from "./commands/agent-marketplace.js";
|
|
48
|
+
import { agentAuditAction } from "./commands/agent-audit.js";
|
|
49
|
+
import { agentTestAction } from "./commands/agent-test.js";
|
|
50
|
+
import { agentDoctorAction } from "./commands/agent-doctor.js";
|
|
51
|
+
import { agentInstallAction } from "./commands/agent-install.js";
|
|
52
|
+
import { agentUninstallAction } from "./commands/agent-uninstall.js";
|
|
53
|
+
import { agentInstalledAction } from "./commands/agent-installed.js";
|
|
54
|
+
import { describeAction } from "./commands/describe.js";
|
|
55
|
+
import { schemaAction } from "./commands/schema.js";
|
|
56
|
+
import { completionAction } from "./commands/completion.js";
|
|
57
|
+
import { serveAction } from "./commands/serve.js";
|
|
58
|
+
import { scriptsListAction, scriptsRunAction, scriptsWhichAction, } from "./commands/scripts.js";
|
|
59
|
+
import { archiveExtractAction, archiveListAction, archiveMigrateAction, archiveRunAction, archiveStatusAction, archiveVerifyAction, } from "./commands/archive.js";
|
|
60
|
+
import { usageAgentsAction, usageCommandsAction, usageHooksAction, usageImportAction, usageIndexAction, usageMigrateAction, usageProjectsAction, usageProvidersAction, usageSessionsAction, usageSkillsAction, usageSummaryAction, usageTokensAction, usageToolsAction, } from "./commands/usage.js";
|
|
61
|
+
// Pre-process argv to expand -fh/-fj shorthands into --format values
|
|
62
|
+
// before Commander sees them (Commander doesn't support multi-char short flags).
|
|
63
|
+
// Bounded to the tokens before the first `--`: everything after it is forwarded
|
|
64
|
+
// verbatim to a child process by `scripts run`, and rewriting a token there would
|
|
65
|
+
// hand the child `--format=json` in place of the `-fj` the user typed.
|
|
66
|
+
const forwardedFrom = process.argv.indexOf("--");
|
|
67
|
+
const argv = process.argv.map((arg, index) => {
|
|
68
|
+
if (forwardedFrom !== -1 && index >= forwardedFrom)
|
|
69
|
+
return arg;
|
|
70
|
+
if (arg === "-fh")
|
|
71
|
+
return "--format=human";
|
|
72
|
+
if (arg === "-fj")
|
|
73
|
+
return "--format=json";
|
|
74
|
+
return arg;
|
|
75
|
+
});
|
|
76
|
+
// `serve` loads configuration for the same reason `md` does: it answers with the
|
|
77
|
+
// workspace's own checks and exclusions, so a tool call and the equivalent `md`
|
|
78
|
+
// command agree. Discovery starts at --root rather than the cwd, because the host
|
|
79
|
+
// spawns the server from an arbitrary directory.
|
|
80
|
+
const servesWorkspace = argv[2] === "md" || argv[2] === "serve";
|
|
81
|
+
let projectConfig;
|
|
82
|
+
try {
|
|
83
|
+
projectConfig = servesWorkspace
|
|
84
|
+
? loadConfig(selectConfig(argv.slice(2)), argv[2] === "serve" ? selectRoot(argv.slice(2)) : process.cwd())
|
|
85
|
+
: loadConfig({ disabled: true });
|
|
86
|
+
initializeRuntime(projectConfig);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
process.stderr.write(`Error: ${error.message}\n`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
const explicitFormat = argv.some((arg, index) => arg.startsWith("--format=") ||
|
|
93
|
+
arg === "-fh" ||
|
|
94
|
+
arg === "-fj" ||
|
|
95
|
+
(arg === "--format" && argv[index + 1]));
|
|
96
|
+
const mdIndex = argv.indexOf("md");
|
|
97
|
+
let configuredCommand;
|
|
98
|
+
for (let index = mdIndex + 1; mdIndex !== -1 && index < argv.length; index++) {
|
|
99
|
+
if (argv[index] === "--config") {
|
|
100
|
+
index++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (argv[index].startsWith("--config=") || argv[index] === "--no-config")
|
|
104
|
+
continue;
|
|
105
|
+
if (!argv[index].startsWith("-")) {
|
|
106
|
+
configuredCommand = argv[index];
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const configuredFormat = (configuredCommand ? projectConfig.commands[configuredCommand]?.format : undefined) ??
|
|
111
|
+
projectConfig.output.format;
|
|
112
|
+
const notifierArgv = ["json", "jsonl", "sarif"].includes(String(configuredFormat)) && !explicitFormat
|
|
113
|
+
? [...argv, `--format=${String(configuredFormat)}`]
|
|
114
|
+
: argv;
|
|
115
|
+
// A downstream reader closing the pipe early is normal shell usage, not an error:
|
|
116
|
+
// `describe -fj | head` and `... | jq '.commands[0]'` both do it. Payloads under the
|
|
117
|
+
// pipe buffer are written synchronously and never notice, but larger ones (describe
|
|
118
|
+
// is ~150KB) would otherwise surface an unhandled EPIPE and crash.
|
|
119
|
+
for (const stream of [process.stdout, process.stderr])
|
|
120
|
+
stream.on("error", (error) => {
|
|
121
|
+
if (error.code !== "EPIPE")
|
|
122
|
+
throw error;
|
|
123
|
+
});
|
|
124
|
+
// Reads the cached result and may schedule a detached refresh. Never blocks and
|
|
125
|
+
// never writes to a machine-readable stream — see src/update-notifier.ts.
|
|
126
|
+
installUpdateNotifier({
|
|
127
|
+
currentVersion: version,
|
|
128
|
+
packageName,
|
|
129
|
+
argv: notifierArgv,
|
|
130
|
+
entryPoint: fileURLToPath(import.meta.url),
|
|
131
|
+
});
|
|
132
|
+
const program = new Command()
|
|
133
|
+
.name("cairn")
|
|
134
|
+
.description("An agent-agnostic CLI toolkit for working with markdown files and related assets")
|
|
135
|
+
.version(version);
|
|
136
|
+
const agent = program
|
|
137
|
+
.command("agent")
|
|
138
|
+
.description("Convert and inspect portable agent bundles")
|
|
139
|
+
.addHelpText("after", `\nTargets: ${TARGETS.join(", ")}, or all\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json`);
|
|
140
|
+
agent
|
|
141
|
+
.command("convert")
|
|
142
|
+
.description("Convert an agent bundle into target-native artifacts")
|
|
143
|
+
.argument("<source>", "Bundle root containing agent-bundle.yaml or a legacy Claude plugin")
|
|
144
|
+
.requiredOption("--target <target>", "Target (repeatable, or all)", collect)
|
|
145
|
+
.requiredOption("--output <dir>", "Output root")
|
|
146
|
+
.option("--profile <profile>", "Output profile: plugin, project, both", "both")
|
|
147
|
+
.option("--strict", "Treat approximations as blocking findings")
|
|
148
|
+
.option("--force", "Replace nonempty selected destinations")
|
|
149
|
+
.option("--dry-run", "Render fully without writing")
|
|
150
|
+
.option("--check", "Compare generated bytes and modes without writing")
|
|
151
|
+
.option("--report <file>", "Also write the conversion report to this path")
|
|
152
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
153
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
154
|
+
.addHelpText("after", "\n--report writes the same document as conversion-report.json, provenance included, to\nan arbitrary path, so CI can keep the report without keeping the rendered tree. It is\nwritten in every mode, including --dry-run, --check, and a strict failure, and is never\nlisted in the artifacts. It must not be inside the source tree or the output directory.\n\nExit codes:\n 0 Successful and lossless\n 1 Invocation or I/O error\n 2 Validation, compatibility, strict, or stale-output finding")
|
|
155
|
+
.action((source, opts) => agentActionBoundary("convert", opts, () => agentConvertAction(source, opts)));
|
|
156
|
+
agent
|
|
157
|
+
.command("validate")
|
|
158
|
+
.description("Validate an agent bundle without generating output")
|
|
159
|
+
.argument("<source>", "Bundle root")
|
|
160
|
+
.option("--target <target>", "Also validate target mappings (repeatable, or all)", collect)
|
|
161
|
+
.option("--strict", "Treat approximations as blocking findings")
|
|
162
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
163
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
164
|
+
.action((source, opts) => agentActionBoundary("validate", opts, () => agentValidateAction(source, opts)));
|
|
165
|
+
agent
|
|
166
|
+
.command("inspect")
|
|
167
|
+
.description("Show the normalized bundle, references, overrides, and graph")
|
|
168
|
+
.argument("<source>", "Bundle root")
|
|
169
|
+
.option("--target <target>", "Narrow to a target (repeatable, or all)", collect)
|
|
170
|
+
.option("--profile <profile>", "Output profile: plugin, project, both")
|
|
171
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
172
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
173
|
+
.addHelpText("after", "\n--target narrows a large bundle to the components that reach the selected targets,\nusing the same predicate the renderer uses, and reports what it excluded under\n`filter`. --profile drops the sections a profile never emits, such as hooks and MCP\noutside the plugin profile, and requires --target. Without either flag the output is\nunchanged.\n\nExit codes:\n 0 Bundle inspected\n 1 Invocation or I/O error\n 2 Bundle findings")
|
|
174
|
+
.action((source, opts) => agentActionBoundary("inspect", opts, () => agentInspectAction(source, opts)));
|
|
175
|
+
agent
|
|
176
|
+
.command("compat")
|
|
177
|
+
.description("Show platform compatibility or analyze a bundle")
|
|
178
|
+
.argument("[source]", "Optional bundle root")
|
|
179
|
+
.option("--target <target>", "Target (repeatable, or all)", collect)
|
|
180
|
+
.option("--strict", "Treat approximations as blocking findings")
|
|
181
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
182
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
183
|
+
.action((source, opts) => agentActionBoundary("compat", opts, () => agentCompatAction(source, opts)));
|
|
184
|
+
agent
|
|
185
|
+
.command("doctor")
|
|
186
|
+
.description("Check a bundle and generated output against the target conformance profiles")
|
|
187
|
+
.argument("[source]", "Optional bundle root")
|
|
188
|
+
.option("--target <target>", "Target (repeatable, or all)", collect)
|
|
189
|
+
.option("--profile <profile>", "Output profile: plugin, project, both", "both")
|
|
190
|
+
.option("--output <dir>", "Also check an existing generated output root")
|
|
191
|
+
.option("--host-version <spec>", "Installed host version: <target>@<version>", collect)
|
|
192
|
+
.option("--strict", "Treat warnings as blocking findings")
|
|
193
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
194
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
195
|
+
.addHelpText("after", "\nRuns without a bundle: profile self-checks and host version reporting still apply.\nNever executes a host's own tooling, so results do not depend on what is installed.\n\nExit codes:\n 0 No blocking conformance findings\n 1 Invocation or I/O error\n 2 Profile, drift, host, or strict finding")
|
|
196
|
+
.action((source, opts) => agentActionBoundary("doctor", opts, () => agentDoctorAction(source, opts)));
|
|
197
|
+
agent
|
|
198
|
+
.command("init")
|
|
199
|
+
.description("Scaffold a new portable agent bundle")
|
|
200
|
+
.argument("<name>", "Bundle name in lowercase kebab-case")
|
|
201
|
+
.option("--output <dir>", "Destination root (default: ./<name>)")
|
|
202
|
+
.option("--description <text>", "Bundle description")
|
|
203
|
+
.option("--bundle-version <semver>", "Initial bundle version", "0.1.0")
|
|
204
|
+
.option("--license <spdx>", "License recorded in marketplace metadata", "MIT")
|
|
205
|
+
.option("--component <kind>", "Component to scaffold (repeatable, or none)", collect)
|
|
206
|
+
.option("--target <target>", "Target (repeatable, or all)", collect)
|
|
207
|
+
.option("--profile <profile>", "Output profile: plugin, project, both", "both")
|
|
208
|
+
.option("--overlays", "Create a native/<target>/ overlay root per target")
|
|
209
|
+
.option("--force", "Scaffold into a nonempty destination")
|
|
210
|
+
.option("--dry-run", "Report the plan without writing")
|
|
211
|
+
.option("--check", "Report whether the scaffold is already present and current")
|
|
212
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
213
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
214
|
+
.addHelpText("after", "\nNever prompts. Placeholder marketplace metadata is valid here; publish\nreadiness is checked by agent package.\n\nExit codes:\n 0 Bundle scaffolded, or dry run completed\n 1 Invocation or I/O error\n 2 --check found a missing or differing scaffold")
|
|
215
|
+
.action((name, opts) => agentActionBoundary("init", opts, () => agentInitAction(name, opts)));
|
|
216
|
+
agent
|
|
217
|
+
.command("add")
|
|
218
|
+
.description("Add one component to an existing bundle")
|
|
219
|
+
.argument("<kind>", "skill, agent, rule, hook, policy, mcp, or overlay")
|
|
220
|
+
.argument("<name>", "Component name, or the portable event name for a hook")
|
|
221
|
+
.argument("[bundle]", "Bundle root (default: .)")
|
|
222
|
+
.option("--description <text>", "Component description")
|
|
223
|
+
.option("--path <dir>", "Component root override; records it in the manifest")
|
|
224
|
+
.option("--activation <mode>", "Rule activation: always, files, model, manual", "always")
|
|
225
|
+
.option("--glob <glob>", "Rule glob (repeatable)", collect)
|
|
226
|
+
.option("--command <cmd>", "Command for a hook, policy prefix, or MCP server")
|
|
227
|
+
.option("--target <target>", "Overlay target, required for kind 'overlay'", collect)
|
|
228
|
+
.option("--profile <profile>", "Overlay output profile: plugin or project", "plugin")
|
|
229
|
+
.option("--force", "Replace an existing component")
|
|
230
|
+
.option("--dry-run", "Report the plan without writing")
|
|
231
|
+
.option("--check", "Report whether the component is already present and current")
|
|
232
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
233
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
234
|
+
.addHelpText("after", "\nagent-bundle.yaml is edited through a comment-preserving YAML document and is\nleft byte-untouched when no manifest change is needed.\n\nExit codes:\n 0 Component added, or dry run completed\n 1 Invocation or I/O error\n 2 --check found a missing or differing component")
|
|
235
|
+
.action((kind, name, bundle, opts) => agentActionBoundary("add", opts, () => agentAddAction(kind, name, bundle, opts)));
|
|
236
|
+
agent
|
|
237
|
+
.command("import")
|
|
238
|
+
.description("Import an existing native plugin or project into a portable bundle")
|
|
239
|
+
.argument("<source>", "Native plugin or project root")
|
|
240
|
+
.requiredOption("--output <dir>", "Bundle root to create")
|
|
241
|
+
.option("--from <spec>", "Source layout: auto, <target>, or <target>-<profile>", "auto")
|
|
242
|
+
.option("--scope <scope>", "Source scope: auto, plugin, project", "auto")
|
|
243
|
+
.option("--merge <strategy>", "refuse, skip-existing, overwrite, native-only", "refuse")
|
|
244
|
+
.option("--bundle-name <name>", "Bundle name; defaults to the source directory name")
|
|
245
|
+
.option("--native-only", "Skip normalization and preserve everything as an overlay")
|
|
246
|
+
.option("--strict", "Treat approximations as blocking findings")
|
|
247
|
+
.option("--dry-run", "Report the import without writing")
|
|
248
|
+
.option("--check", "Compare against an existing bundle without writing")
|
|
249
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
250
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
251
|
+
.addHelpText("after", "\nDetection is driven by the target conformance profiles, so it cannot drift\nfrom what agent convert emits. Untranslatable pieces are preserved under\nnative/<target>/ rather than dropped.\n\nExit codes:\n 0 Imported, or dry run completed\n 1 Invocation or I/O error\n 2 Blocking finding, or --check found drift")
|
|
252
|
+
.action((source, opts) => agentActionBoundary("import", opts, () => agentImportAction(source, opts)));
|
|
253
|
+
agent
|
|
254
|
+
.command("upgrade")
|
|
255
|
+
.description("Migrate a bundle between neutral schema versions")
|
|
256
|
+
.argument("<source>", "Bundle root")
|
|
257
|
+
.requiredOption("--to-schema <version>", "Target bundle schema version")
|
|
258
|
+
.option("--dry-run", "Report the migration without writing")
|
|
259
|
+
.option("--check", "Exit 2 when the bundle is not already at the target schema")
|
|
260
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
261
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
262
|
+
.addHelpText("after", "\nOnly agent-bundle.yaml is rewritten; no component file is touched. The\nmigration is verified in memory to produce byte-identical generated output\nbefore it writes.\n\nExit codes:\n 0 Migrated, already current, or dry run completed\n 1 Invocation or I/O error\n 2 --check found a bundle below the target schema, or a blocking finding")
|
|
263
|
+
.action((source, opts) => agentActionBoundary("upgrade", opts, () => agentUpgradeAction(source, opts)));
|
|
264
|
+
agent
|
|
265
|
+
.command("package")
|
|
266
|
+
.description("Build a distributable package with catalogs, checksums, and archives")
|
|
267
|
+
.argument("<source>", "Bundle root")
|
|
268
|
+
.requiredOption("--target <target>", "Target (repeatable, or all)", collect)
|
|
269
|
+
.requiredOption("--output <dir>", "Package root")
|
|
270
|
+
.option("--profile <profile>", "Output profile: plugin, project, both", "both")
|
|
271
|
+
.option("--marketplace <mode>", "Catalog mode: repo, local, none", "repo")
|
|
272
|
+
.option("--archive", "Also emit a deterministic .tar.gz per target and profile")
|
|
273
|
+
.option("--from-dist <dir>", "Verify an existing agent convert tree matches this bundle")
|
|
274
|
+
.option("--strict", "Treat warnings as blocking findings")
|
|
275
|
+
.option("--force", "Replace nonempty selected destinations")
|
|
276
|
+
.option("--dry-run", "Build in memory without writing")
|
|
277
|
+
.option("--check", "Compare against an existing package without writing")
|
|
278
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
279
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
280
|
+
.addHelpText("after", "\nRenders the bundle itself, so a package can never certify a stale tree.\nNever contacts the network and never publishes.\n\nExit codes:\n 0 Package written, or checks passed\n 1 Invocation or I/O error\n 2 Publish-readiness, integrity, or stale finding")
|
|
281
|
+
.action((source, opts) => agentActionBoundary("package", opts, () => agentPackageAction(source, opts)));
|
|
282
|
+
agent
|
|
283
|
+
.command("marketplace")
|
|
284
|
+
.description("Build a marketplace of several bundles from a collection spec")
|
|
285
|
+
.argument("<spec>", "agent-marketplace.yaml, or a directory holding one")
|
|
286
|
+
.option("--output <dir>", "Collection root; required unless --install")
|
|
287
|
+
.option("--target <target>", "Narrow the spec's targets (repeatable)", collect)
|
|
288
|
+
.option("--marketplace <mode>", "Catalog mode: repo, local", "repo")
|
|
289
|
+
.option("--archive", "Also emit a deterministic .tar.gz per plugin")
|
|
290
|
+
.option("--install", "Install the collection into the host marketplace directory")
|
|
291
|
+
.option("--scope <scope>", "Install scope: user, project")
|
|
292
|
+
.option("--into <dir>", "Override the install root the profile declares")
|
|
293
|
+
.option("--link", "Symlink the installed tree instead of copying it")
|
|
294
|
+
.option("--register", "Edit host config to activate the collection")
|
|
295
|
+
.option("--strict", "Treat warnings as blocking findings")
|
|
296
|
+
.option("--force", "Replace a nonempty destination")
|
|
297
|
+
.option("--dry-run", "Build in memory without writing")
|
|
298
|
+
.option("--check", "Compare against an existing collection without writing")
|
|
299
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
300
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
301
|
+
.addHelpText("after", "\nRenders every bundle itself, so a catalog can never certify a stale tree.\nOne aggregated catalog per target, not one per bundle. Never contacts the\nnetwork and never publishes.\n\n--install registers one marketplace offering every plugin, where installing\neach bundle separately would register one marketplace per bundle.\n\nExit codes:\n 0 Collection written or installed, or checks passed\n 1 Invocation or I/O error\n 2 Spec, publish-readiness, install, or stale finding")
|
|
302
|
+
.action((spec, opts) => agentActionBoundary("marketplace", opts, () => agentMarketplaceAction(spec, opts)));
|
|
303
|
+
agent
|
|
304
|
+
.command("audit")
|
|
305
|
+
.description("Review a bundle's executable surface, permissions, and supply chain")
|
|
306
|
+
.argument("<source>", "Bundle root")
|
|
307
|
+
.option("--target <target>", "Target (repeatable, or all); enables the rendered checks", collect)
|
|
308
|
+
.option("--profile <profile>", "Output profile: plugin, project, both", "both")
|
|
309
|
+
.option("--baseline <file>", "Compare executables against a previous package sbom.json")
|
|
310
|
+
.option("--strict", "Treat warnings as blocking findings")
|
|
311
|
+
.option("--format <fmt>", "Output format: llm, human, json, sarif", "llm")
|
|
312
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
313
|
+
.addHelpText("after", "\nExplainable static analysis: nothing is executed and no network request is\nmade. Exit 2 means findings to review, not proof that a bundle is malicious.\n\nExit codes:\n 0 No blocking review findings\n 1 Invocation or I/O error\n 2 Review findings")
|
|
314
|
+
.action((source, opts) => agentActionBoundary("audit", opts, () => agentAuditAction(source, opts)));
|
|
315
|
+
agent
|
|
316
|
+
.command("test")
|
|
317
|
+
.description("Run the model-free contract tests stored with a bundle")
|
|
318
|
+
.argument("<source>", "Bundle root")
|
|
319
|
+
.option("--tests <path>", "Test file or directory (default: tests/ in the bundle)")
|
|
320
|
+
.option("--target <target>", "Target (repeatable, or all)", collect)
|
|
321
|
+
.option("--profile <profile>", "Output profile: plugin, project, both", "both")
|
|
322
|
+
.option("--case <name>", "Run only this case (repeatable)", collect)
|
|
323
|
+
.option("--strict", "Treat warnings as blocking findings")
|
|
324
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
325
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
326
|
+
.addHelpText("after", "\nEvery expectation is evaluated against the same in-memory render agent convert\nwould write. Nothing is executed, no model is called, and no file is written; a\nchanged golden digest is reported with both the expected and the actual value.\n--target and --profile narrow each case's own selection rather than widening it.\n\nExit codes:\n 0 Every selected case passed\n 1 Invocation or I/O error\n 2 A failing case, an invalid test file, or a warning under --strict")
|
|
327
|
+
.action((source, opts) => agentActionBoundary("test", opts, () => agentTestAction(source, opts)));
|
|
328
|
+
agent
|
|
329
|
+
.command("install")
|
|
330
|
+
.description("Install a bundle into a host plugin or project directory")
|
|
331
|
+
.argument("<source>", "Bundle root")
|
|
332
|
+
.requiredOption("--target <target>", `Target: ${TARGETS.join(", ")}`, collect)
|
|
333
|
+
.option("--scope <scope>", "Install scope: user or project", "user")
|
|
334
|
+
.option("--into <dir>", "Override the install root declared by the target profile")
|
|
335
|
+
.option("--profile <profile>", "Must match the location's profile when given")
|
|
336
|
+
.option("--link", "Symlink the rendered tree instead of copying")
|
|
337
|
+
.option("--register", "Edit host config to activate a marketplace install")
|
|
338
|
+
.option("--strict", "Treat warnings as blocking findings")
|
|
339
|
+
.option("--force", "Replace a destination that is not a prior install of this bundle")
|
|
340
|
+
.option("--dry-run", "Plan the install without writing")
|
|
341
|
+
.option("--check", "Compare against an existing install without writing")
|
|
342
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
343
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
344
|
+
.addHelpText("after", "\nRenders and packages in memory, so an install is always derived from the\nbundle rather than from a possibly-drifted dist tree. Destinations come from\nthe target profiles. --register is the only flag that edits host config.\n\nExit codes:\n 0 Installed, or checks passed\n 1 Invocation or I/O error\n 2 Install finding, or --check found drift")
|
|
345
|
+
.action((source, opts) => agentActionBoundary("install", opts, () => agentInstallAction(source, opts)));
|
|
346
|
+
agent
|
|
347
|
+
.command("uninstall")
|
|
348
|
+
.description("Remove a previously installed bundle")
|
|
349
|
+
.argument("<name>", "Installed bundle name")
|
|
350
|
+
.requiredOption("--target <target>", `Target: ${TARGETS.join(", ")}`, collect)
|
|
351
|
+
.option("--scope <scope>", "Install scope: user or project")
|
|
352
|
+
.option("--into <dir>", "Override the install root declared by the target profile")
|
|
353
|
+
.option("--dry-run", "Report the removal without writing")
|
|
354
|
+
.option("--check", "Exit 2 when the named install is still present")
|
|
355
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
356
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
357
|
+
.addHelpText("after", "\nRemoves exactly the inventory recorded in .cairn-install.json and\nnothing else. --scope is optional: both scopes are searched, and two matches\nis an error rather than a guess.\n\nExit codes:\n 0 Removed, already absent under --check, or dry run completed\n 1 Invocation or I/O error\n 2 Manifest missing or malformed, or --check found the install still present")
|
|
358
|
+
.action((name, opts) => agentActionBoundary("uninstall", opts, () => agentUninstallAction(name, opts)));
|
|
359
|
+
agent
|
|
360
|
+
.command("installed")
|
|
361
|
+
.description("List bundles installed by this CLI")
|
|
362
|
+
.option("--target <target>", "Target (repeatable, or all)", collect)
|
|
363
|
+
.option("--scope <scope>", "Install scope: user or project")
|
|
364
|
+
.option("--into <dir>", "Override the install root declared by the target profile")
|
|
365
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
366
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
367
|
+
.addHelpText("after", "\nScans the install roots declared on the target profiles and lists every\n.cairn-install.json it finds.\n\nExit codes:\n 0 Listing written to stdout\n 1 Invocation error")
|
|
368
|
+
.action((opts) => agentActionBoundary("installed", opts, () => agentInstalledAction(opts)));
|
|
369
|
+
agent
|
|
370
|
+
.command("specs")
|
|
371
|
+
.description("Print the versioned target conformance profiles")
|
|
372
|
+
.option("--target <target>", "Target (repeatable, or all)", collect)
|
|
373
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
374
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
375
|
+
.addHelpText("after", "\nThe profiles are the source of truth for target behavior; --format json is the\nform to depend on.\n\nExit codes:\n 0 Profiles written to stdout\n 1 Invocation error")
|
|
376
|
+
.action((opts) => agentActionBoundary("specs", opts, () => agentSpecsAction(opts)));
|
|
377
|
+
program
|
|
378
|
+
.command(CHECK_COMMAND)
|
|
379
|
+
.description("Check whether a newer version of this CLI has been published")
|
|
380
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
381
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
382
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nQueries the registry directly rather than using the 24h cache.\n\nExit codes:\n 0 Already on the latest version\n 1 Could not reach the registry\n 2 A newer version is available")
|
|
383
|
+
.action((opts) => checkUpdateAction(packageName, version, opts));
|
|
384
|
+
program
|
|
385
|
+
.command("describe")
|
|
386
|
+
.description("Describe the CLI contract: commands, options, exit codes, and output schemas")
|
|
387
|
+
.argument("[command...]", "Optional command path, for example: md graph")
|
|
388
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
389
|
+
.addHelpText("after", "\nExamples:\n cairn describe --format json\n cairn describe md graph --format json\n\nReports the static contract; project configuration is not applied.\n\nExit codes:\n 0 Description written to stdout\n 1 Unknown command path or invalid format")
|
|
390
|
+
.action((commandPath, opts) => describeAction(program, commandPath, {
|
|
391
|
+
...opts,
|
|
392
|
+
toolName: packageName,
|
|
393
|
+
toolVersion: version,
|
|
394
|
+
}));
|
|
395
|
+
program
|
|
396
|
+
.command("schema")
|
|
397
|
+
.description("Print a published output schema, or list the available schemas")
|
|
398
|
+
.argument("[id]", "Schema id, for example: agent-result")
|
|
399
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
400
|
+
.addHelpText("after", "\nWith an id, the schema document is written regardless of --format.\nSchema ids are identifiers, not fetchable URLs.\n\nExit codes:\n 0 Schema or index written to stdout\n 1 Unknown schema id or invalid format")
|
|
401
|
+
.action((id, opts) => schemaAction(id, opts));
|
|
402
|
+
program
|
|
403
|
+
.command("completion")
|
|
404
|
+
.description("Print a shell completion script for bash, zsh, fish, or powershell")
|
|
405
|
+
.argument("<shell>", "Shell: bash, zsh, fish, or powershell")
|
|
406
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
407
|
+
.addHelpText("after", "\nThe script is written to stdout regardless of --format, and is generated from the\nsame command tree `describe` walks, so it cannot drift from the real options.\n\nInstall:\n cairn completion bash >> ~/.bashrc (or a bash-completion.d file)\n cairn completion zsh > ~/.zfunc/_cairn (a directory on $fpath)\n cairn completion fish > ~/.config/fish/completions/cairn.fish\n cairn completion powershell >> $PROFILE\n\nRegenerate after upgrading; the script embeds the command tree rather than calling\nback into the CLI, so a shell never pays a process spawn per keystroke.\n\nExit codes:\n 0 Script written to stdout\n 1 Unknown shell or invalid format")
|
|
408
|
+
.action((shell, opts) => completionAction(program, shell, {
|
|
409
|
+
...opts,
|
|
410
|
+
toolName: packageName,
|
|
411
|
+
toolVersion: version,
|
|
412
|
+
}));
|
|
413
|
+
program
|
|
414
|
+
.command("serve")
|
|
415
|
+
.description("Serve the workspace engine over a machine protocol")
|
|
416
|
+
.argument("<protocol>", "Protocol: mcp")
|
|
417
|
+
.option("--root <dir>", "Directory to serve; every path is confined to it", ".")
|
|
418
|
+
.option("--config <file>", "Path to a configuration file")
|
|
419
|
+
.option("--no-config", "Ignore any configuration file")
|
|
420
|
+
.option("--max-documents <n>", "Parsed documents held in memory before eviction")
|
|
421
|
+
.option("--concurrency <n>", "Parallel lints during audit_markdown")
|
|
422
|
+
.addHelpText("after", "\nSpeaks the Model Context Protocol over stdio, exposing the Markdown workspace\nengine as read-only tools. stdout carries JSON-RPC frames rather than a payload,\nso --format does not apply; diagnostics go to stderr.\n\nEvery tool is read-only and every path argument is confined to --root, resolved\nthrough symlinks. Configuration is discovered from --root, so a tool answers the\nsame as the equivalent md command in that workspace.\n\nRegister with a host:\n claude mcp add markdown -- cairn serve mcp --root docs\n\nExit codes:\n 0 The client closed the connection\n 1 Unknown protocol, unreadable root, or invalid configuration")
|
|
423
|
+
.action((protocol, opts) => serveAction(protocol, opts));
|
|
424
|
+
const scripts = program
|
|
425
|
+
.command("scripts")
|
|
426
|
+
.description("Resolve and run named scripts declared in .cairn.yml")
|
|
427
|
+
.addHelpText("after", "\nA script name resolves the same from any directory: every .cairn.yml from the\nworking directory up to the repository root is consulted, and the nearest file that\ndefines the name wins. The script runs with its working directory pinned to the\nregistry that declared it, which is what makes a hook survive a change of directory.\n\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json");
|
|
428
|
+
const scriptsCommon = (command) => command
|
|
429
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
430
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
431
|
+
.option("--root <dir>", "Stop the upward walk at this directory")
|
|
432
|
+
.option("--config <file>", "Use a specific .cairn.yml configuration file")
|
|
433
|
+
.option("--no-config", "Disable project configuration discovery");
|
|
434
|
+
scriptsCommon(scripts.command("run"))
|
|
435
|
+
.description("Run a named script from anywhere in the tree")
|
|
436
|
+
.argument("<name>", "Script name declared under scripts: in a .cairn.yml")
|
|
437
|
+
.argument("[args...]", "Arguments forwarded to the script, after --")
|
|
438
|
+
.addHelpText("after", "\nExamples:\n cairn scripts run gather-context\n cairn scripts run lint-changed -- --since main\n\nIn llm and human formats the script's streams pass through untouched and its exit\nstatus becomes this process's exit status, so a hook reads the real code. With\n--format json the streams are captured into the payload instead.\n\nRefuses to run outside a Git repository unless --root sets the boundary explicitly.\n\nExit codes:\n * llm and human: the script's own exit status, verbatim\n 0 --format json: the script exited 0\n 1 Unresolvable name, or the script could not be started\n 2 --format json: the script exited non-zero or was killed by a signal")
|
|
439
|
+
.action((name, args, opts) => scriptsRunAction(name, args, opts));
|
|
440
|
+
scriptsCommon(scripts.command("which"))
|
|
441
|
+
.description("Show which registry defines a script, without running it")
|
|
442
|
+
.argument("<name>", "Script name")
|
|
443
|
+
.addHelpText("after", "\nReports the winning .cairn.yml, the working directory the script would run in,\nand any same-named definitions it shadows.\n\nExit codes:\n 0 The name resolved\n 1 Invocation error\n 2 No script by that name")
|
|
444
|
+
.action((name, opts) => scriptsWhichAction(name, opts));
|
|
445
|
+
scriptsCommon(scripts.command("list"))
|
|
446
|
+
.description("List every script visible from the working directory")
|
|
447
|
+
.addHelpText("after", "\nNearest definition wins, so a name declared in a nested registry hides the one above\nit. Files that could not be parsed are reported rather than skipped silently.\n\nExit codes:\n 0 Listing written to stdout\n 1 Invocation error\n 2 A consulted configuration file could not be read")
|
|
448
|
+
.action((opts) => scriptsListAction(opts));
|
|
449
|
+
const usage = program
|
|
450
|
+
.command("usage")
|
|
451
|
+
.description("Report on Claude Code usage from its own session logs")
|
|
452
|
+
.addHelpText("after", "\nReads the session transcripts an assistant leaves on disk and reports on them:\ntokens by model and day, tool and MCP calls, skills, subagents, hooks, and slash\ncommands. Nothing is sent anywhere and nothing outside the usage store is written.\n\nEvery transcript is reduced once into a SQLite store under XDG_DATA_HOME, keyed on\neach file's size and modification time, so the first scan is slow and later ones are\nnot. The store keeps day buckets for these reports and per-occurrence event rows for\nquestions a day bucket cannot express; query the file directly for those.\n\nProviders:\n --provider selects the log source; `usage providers` lists what is registered.\n\nWindows:\n --since and --until take a relative span (7d, 2w, 3m, 1y) or an ISO date, and are\n inclusive day bounds.\n\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json");
|
|
453
|
+
/**
|
|
454
|
+
* Options every `usage` subcommand shares.
|
|
455
|
+
*
|
|
456
|
+
* `--project` uses the unwrapped `collect` because `src/contract/describe.ts`
|
|
457
|
+
* detects a repeatable option by comparing its coercion against that function by
|
|
458
|
+
* identity.
|
|
459
|
+
*/
|
|
460
|
+
const usageCommon = (command) => command
|
|
461
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
462
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
463
|
+
.option("--provider <name>", "Log source to report on, or all", "claude-code")
|
|
464
|
+
.option("--project <path>", "Limit to a project path, slug, or name (repeatable)", collect)
|
|
465
|
+
.option("--since <spec>", "Earliest day: a span such as 7d, 2w, 3m, 1y, or an ISO date")
|
|
466
|
+
.option("--until <spec>", "Latest day, same forms as --since")
|
|
467
|
+
.option("--last <n>", "Keep only the n most recently active sessions")
|
|
468
|
+
.option("--top <n>", "Rows to show; 0 for all", "20")
|
|
469
|
+
.option("--logs <dir>", "Read logs from this directory instead of the discovered one")
|
|
470
|
+
.option("--no-subagents", "Exclude subagent transcripts")
|
|
471
|
+
.option("--no-index", "Bypass the usage store; neither read it nor write it")
|
|
472
|
+
.option("--strict", "Exit 2 when a transcript could not be fully read");
|
|
473
|
+
const usageExitCodes = "\n\nExit codes:\n 0 Report written to stdout\n 1 Invocation error, or no logs found\n 2 --strict was given and a transcript could not be fully read";
|
|
474
|
+
usageCommon(usage.command("summary"))
|
|
475
|
+
.description("Headline totals: sessions, tokens, tools, and features")
|
|
476
|
+
.addHelpText("after", "\nToken counts deduplicate the per-response fan-out in the source transcripts, where\none API response is written as several lines each carrying an identical copy of its\nusage. Subagent transcripts are included; --no-subagents excludes them." +
|
|
477
|
+
usageExitCodes)
|
|
478
|
+
.action((opts) => usageSummaryAction(opts));
|
|
479
|
+
usageCommon(usage.command("tokens"))
|
|
480
|
+
.description("Token usage rolled up by model, time, project, or session")
|
|
481
|
+
.option("--by <dimension>", "model, day, week, month, project, session, provider", "model")
|
|
482
|
+
.addHelpText("after", "\nCache writes report an authoritative total alongside a best-effort split by TTL,\nwhich the oldest records do not carry." +
|
|
483
|
+
usageExitCodes)
|
|
484
|
+
.action((opts) => usageTokensAction(opts));
|
|
485
|
+
usageCommon(usage.command("tools"))
|
|
486
|
+
.description("Tool calls rolled up by name, kind, server, day, or session")
|
|
487
|
+
.option("--by <dimension>", "name, kind, server, day, session, provider", "name")
|
|
488
|
+
.option("--kind <kind>", "Limit to builtin, mcp, agent, or skill calls")
|
|
489
|
+
.addHelpText("after", "\nAn MCP tool named mcp__<server>__<tool> is split into its server and tool halves,\nso --by server and --kind mcp are how that surface is queried." +
|
|
490
|
+
usageExitCodes)
|
|
491
|
+
.action((opts) => usageToolsAction(opts));
|
|
492
|
+
usageCommon(usage.command("sessions"))
|
|
493
|
+
.description("One row per session, with its subagent transcripts folded in")
|
|
494
|
+
.option("--sort <order>", "recent, tokens, tools, duration", "recent")
|
|
495
|
+
.addHelpText("after", "\n--last n selects the n most recently active sessions rather than the n most recent\nfiles, so a session's subagent spend is never dropped from its own row." +
|
|
496
|
+
usageExitCodes)
|
|
497
|
+
.action((opts) => usageSessionsAction(opts));
|
|
498
|
+
usageCommon(usage.command("projects"))
|
|
499
|
+
.description("Usage rolled up by the directory each session ran in")
|
|
500
|
+
.addHelpText("after", "\nProject identity is the working directory recorded inside the transcripts, not the\nlog directory name, whose separator substitution is not reliably invertible." +
|
|
501
|
+
usageExitCodes)
|
|
502
|
+
.action((opts) => usageProjectsAction(opts));
|
|
503
|
+
usageCommon(usage.command("skills"))
|
|
504
|
+
.description("Skill invocations by name")
|
|
505
|
+
.addHelpText("after", "\nCounted from every surface that records one: the Skill tool, the invoked-skill\nattachments, and the slash-command form." +
|
|
506
|
+
usageExitCodes)
|
|
507
|
+
.action((opts) => usageSkillsAction(opts));
|
|
508
|
+
usageCommon(usage.command("agents"))
|
|
509
|
+
.description("Subagent activity by agent type, with real token cost")
|
|
510
|
+
.option("--by <dimension>", "role, path", "role")
|
|
511
|
+
.addHelpText("after", "\nSpawn counts come from the parent's tool calls; tokens come from the subagent\ntranscripts themselves. The parent's own tool result records only the subagent's\nfinal message and understates its spend several-fold, so it is not used.\n\n--by role groups by the reusable agent type; --by path groups by the task-specific\nidentifier, which only some providers record." +
|
|
512
|
+
usageExitCodes)
|
|
513
|
+
.action((opts) => usageAgentsAction(opts));
|
|
514
|
+
usageCommon(usage.command("hooks"))
|
|
515
|
+
.description("Hook executions by event and tool, with failures and latency")
|
|
516
|
+
.addHelpText("after", "\nKeyed by <Event>:<Tool>. Stop hooks report through a session summary record rather\nthan a per-execution one and are counted under Stop." +
|
|
517
|
+
usageExitCodes)
|
|
518
|
+
.action((opts) => usageHooksAction(opts));
|
|
519
|
+
usageCommon(usage.command("commands"))
|
|
520
|
+
.description("Slash command usage by name")
|
|
521
|
+
.addHelpText("after", "\nSlash commands are not a field in the logs; they are a marker block inside the\nuser's message text, and are extracted from it." +
|
|
522
|
+
usageExitCodes)
|
|
523
|
+
.action((opts) => usageCommandsAction(opts));
|
|
524
|
+
usage
|
|
525
|
+
.command("providers")
|
|
526
|
+
.description("List the log sources usage can report on")
|
|
527
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
528
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
529
|
+
.option("--logs <dir>", "Test discovery against this directory")
|
|
530
|
+
.addHelpText("after", "\nReports whether each provider has left anything on this machine and what its logs\ncan answer. Reports read those capabilities rather than branching on a provider\nname, so registering a second assistant is one module and one registry line.\n\nExit codes:\n 0 Listing written to stdout\n 1 Invocation error")
|
|
531
|
+
.action((opts) => usageProvidersAction(opts));
|
|
532
|
+
usageCommon(usage.command("index"))
|
|
533
|
+
.description("Show, rebuild, or clear the usage store")
|
|
534
|
+
.option("--rebuild", "Re-parse every transcript and rewrite its rows")
|
|
535
|
+
.option("--clear", "Drop the selected providers' rows")
|
|
536
|
+
.addHelpText("after", "\nThe store keys on each transcript's path, size, and modification time. Transcripts\nare append-only, so an unchanged file cannot hold a record the stored aggregate is\nmissing, and only files that grew are reopened.\n\nOne SQLite store under XDG_DATA_HOME holds every provider, so --clear is scoped by\n--provider and the size it reports is the whole file's.\n\nExit codes:\n 0 Status written, or the store was rebuilt or cleared\n 1 Invocation error")
|
|
537
|
+
.action((opts) => usageIndexAction(opts));
|
|
538
|
+
usageCommon(usage.command("import"))
|
|
539
|
+
.description("Import transcripts into the usage store")
|
|
540
|
+
.option("--rebuild", "Re-parse every transcript, not only the ones that changed")
|
|
541
|
+
.addHelpText("after", "\nReports populate the store on first use, so this is never required. It exists to do\nthat work deliberately: to warm a cold store before a timed report, to run on a\nschedule, and to see the import counters without a report wrapped around them.\n\nThe store keeps two grains. Day buckets answer every report this tool offers; the\nevent rows answer what a day bucket cannot, and are there for anything querying the\nSQLite file directly.\n\nExit codes:\n 0 Import completed\n 1 Invocation error, or no logs found\n 2 --strict was given and a transcript could not be fully read")
|
|
542
|
+
.action((opts) => usageImportAction(opts));
|
|
543
|
+
usage
|
|
544
|
+
.command("migrate")
|
|
545
|
+
.description("Apply pending usage store migrations")
|
|
546
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
547
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
548
|
+
.option("--check", "Report what is pending without writing")
|
|
549
|
+
.addHelpText("after", "\nEvery command that opens the store migrates it, so this is needed only to migrate\ndeliberately, or with --check to see what is pending first.\n\nThe store is migrated rather than discarded. Once transcripts have been archived and\npruned it may be the only record of that usage left, so a version bump carries the\ndata forward instead of throwing it away. A store written by a newer cairn is\nrefused rather than guessed at.\n\nExit codes:\n 0 Store is current, or was migrated\n 1 Invocation error, or the store is newer than this build understands")
|
|
550
|
+
.action((opts) => usageMigrateAction(opts));
|
|
551
|
+
const archive = program
|
|
552
|
+
.command("archive")
|
|
553
|
+
.description("Archive plans, artifacts, and logs into long-term compressed storage")
|
|
554
|
+
.addHelpText("after", "\nStores what an assistant leaves behind — plan documents, the files tools produced, and\noptionally transcripts and logs — as append-only .tar.gz segments with a SQLite index.\n\nWhat gets archived is declared per provider, not discovered by sweeping a home directory:\nonly named directories are walked, so plugin payloads and build scratch cannot be picked\nup by accident.\n\nSegments are ordinary archives. `tar tzf` recovers their contents with no index and no\ncairn, which is the point of a store meant to outlive the tool that wrote it.\n\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json");
|
|
555
|
+
/** Options every `archive` subcommand shares. */
|
|
556
|
+
const archiveCommon = (command) => command
|
|
557
|
+
.option("--format <fmt>", "Output format: llm, human, json", "llm")
|
|
558
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
559
|
+
.option("--archive <dir>", "Archive location; defaults to XDG_DATA_HOME/cairn/archive");
|
|
560
|
+
archiveCommon(archive.command("run"))
|
|
561
|
+
.description("Archive new and changed artifacts")
|
|
562
|
+
.option("--provider <name>", "Log source to archive, or all", "claude-code")
|
|
563
|
+
.option("--include <classes>", "plans, artifacts, transcripts, logs", "plans,artifacts")
|
|
564
|
+
.option("--logs <dir>", "Read logs from this directory instead of the discovered one")
|
|
565
|
+
.option("--dry-run", "Report what would be archived without storing anything")
|
|
566
|
+
.option("--segment-size <bytes>", "Seal a segment once it reaches this many uncompressed bytes")
|
|
567
|
+
.option("-v, --verbose", "Print one line per artifact to stderr")
|
|
568
|
+
.option("--no-progress", "Suppress the progress line")
|
|
569
|
+
.addHelpText("after", "\nplans and artifacts are archived by default; transcripts and logs are opt-in because\nthey are three orders of magnitude larger.\n\nIncremental twice over: a file whose size and modification time already match the index\nis never opened, and a file whose content is already stored is never written again, so a\nsecond run over an unchanged corpus costs one stat per file.\n\nA file that changes gets a new row against a new blob, so the archive keeps every version\nit ever saw.\n\nProgress:\n A run over a full corpus is tens of thousands of files and takes minutes, so it draws a\n progress line on stderr. That line rewrites itself in place, so it appears only when\n stderr is a terminal, --format is not json, and CI is unset; --no-progress suppresses it.\n\n -v prints one durable line per artifact instead, giving its disposition (stored,\n duplicate, unchanged, skipped), size, hash, and path. It is not gated on a terminal,\n so `cairn archive run -v 2> archive.log` is the way to keep a record of a long run.\n\nExit codes:\n 0 Run completed\n 1 Invocation error, or no logs found")
|
|
570
|
+
.action((opts) => archiveRunAction(opts));
|
|
571
|
+
archiveCommon(archive.command("status"))
|
|
572
|
+
.description("Report what the archive holds")
|
|
573
|
+
.addHelpText("after", "\nExit codes:\n 0 Status written\n 1 Invocation error")
|
|
574
|
+
.action((opts) => archiveStatusAction(opts));
|
|
575
|
+
archiveCommon(archive.command("list"))
|
|
576
|
+
.description("List archived artifacts")
|
|
577
|
+
.option("--provider <name>", "Limit to one log source, or all", "all")
|
|
578
|
+
.option("--class <name>", "plan, artifact, transcript, or log")
|
|
579
|
+
.option("--since <day>", "Only artifacts last seen on or after this ISO day")
|
|
580
|
+
.option("--top <n>", "Rows to show; 0 for all", "20")
|
|
581
|
+
.addHelpText("after", "\nOne row per archived path, newest first. A path the archive holds several versions of is\nlisted once, with the count.\n\nExit codes:\n 0 Listing written\n 1 Invocation error")
|
|
582
|
+
.action((opts) => archiveListAction(opts));
|
|
583
|
+
archiveCommon(archive.command("extract"))
|
|
584
|
+
.argument("<target>", "Original path, or a sha256 prefix")
|
|
585
|
+
.description("Write an archived file back out")
|
|
586
|
+
.option("--out <dir>", "Directory to write into", ".")
|
|
587
|
+
.addHelpText("after", "\nA path resolves to its newest version; name a hash to reach an older one. The content is\nre-hashed on the way out, so an archive whose index and bytes disagree reports that rather\nthan handing back the wrong file.\n\nExit codes:\n 0 File written\n 1 Invocation error, or nothing matched")
|
|
588
|
+
.action((target, opts) => archiveExtractAction(target, opts));
|
|
589
|
+
archiveCommon(archive.command("verify"))
|
|
590
|
+
.description("Check the archive against its index")
|
|
591
|
+
.option("--deep", "Also decompress every segment and re-hash each blob")
|
|
592
|
+
.addHelpText("after", "\nThe default pass hashes each segment file, catching truncation and corruption for the cost\nof reading it. --deep additionally re-hashes every member, which catches an index whose\noffsets no longer point where it claims.\n\nExit codes:\n 0 Archive matches its index\n 1 Invocation error\n 2 The archive and its index disagree")
|
|
593
|
+
.action((opts) => archiveVerifyAction(opts));
|
|
594
|
+
archiveCommon(archive.command("migrate"))
|
|
595
|
+
.description("Apply pending archive index migrations")
|
|
596
|
+
.option("--check", "Report what is pending without writing")
|
|
597
|
+
.addHelpText("after", "\nThe index is migrated rather than discarded: it is the only map from an original path to\nthe segment holding that file's bytes. An index written by a newer cairn is refused rather\nthan guessed at.\n\nExit codes:\n 0 Index is current, or was migrated\n 1 Invocation error, or the index is newer than this build understands")
|
|
598
|
+
.action((opts) => archiveMigrateAction(opts));
|
|
599
|
+
// Internal: refreshes the cached latest version. Spawned detached by the notifier.
|
|
600
|
+
program
|
|
601
|
+
.command(REFRESH_COMMAND, { hidden: true })
|
|
602
|
+
.description("Internal: refresh the cached latest-version check")
|
|
603
|
+
.action(() => refreshUpdateCacheAction(packageName));
|
|
604
|
+
const md = program
|
|
605
|
+
.command("md")
|
|
606
|
+
.description("Agent-agnostic Markdown validation and analysis commands")
|
|
607
|
+
.option("--config <file>", "Use a specific .cairn.yml configuration file")
|
|
608
|
+
.option("--no-config", "Disable project configuration discovery")
|
|
609
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json");
|
|
610
|
+
function common(command) {
|
|
611
|
+
const formats = formatsFor(command.name()).join(", ");
|
|
612
|
+
return command
|
|
613
|
+
.option("--format <fmt>", `Output format: ${formats}`)
|
|
614
|
+
.option("--envelope", "Wrap --format json output in the versioned result envelope")
|
|
615
|
+
.option("--paths <style>", "Path display: absolute, relative")
|
|
616
|
+
.option("--stdin-name <path>", "Logical workspace path for stdin input");
|
|
617
|
+
}
|
|
618
|
+
common(md.command("lint"))
|
|
619
|
+
.description("Run all checks on a single markdown file or multiple Markdown inputs")
|
|
620
|
+
.argument("<files...>", "Markdown files or globs to validate")
|
|
621
|
+
.option("-s, --style", "Include markdown style checks (markdownlint)")
|
|
622
|
+
.option("--no-style", "Disable markdown style checks (markdownlint)")
|
|
623
|
+
.option("--mermaid", "Enable Mermaid checks")
|
|
624
|
+
.option("--no-mermaid", "Disable Mermaid checks")
|
|
625
|
+
.option("--katex", "Enable KaTeX checks")
|
|
626
|
+
.option("--no-katex", "Disable KaTeX checks")
|
|
627
|
+
.option("--references", "Enable reference checks")
|
|
628
|
+
.option("--no-references", "Disable reference checks")
|
|
629
|
+
.option("--changed-since <revision>", "Only files changed since a Git revision")
|
|
630
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
631
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
632
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 All checks pass\n 2 One or more issues found")
|
|
633
|
+
.action((files, opts) => lintAction(files, commandOptions("lint", {
|
|
634
|
+
style: projectConfig.checks.markdownlint,
|
|
635
|
+
mermaid: projectConfig.checks.mermaid,
|
|
636
|
+
katex: projectConfig.checks.katex,
|
|
637
|
+
references: projectConfig.checks.references,
|
|
638
|
+
include: projectConfig.files.include,
|
|
639
|
+
exclude: projectConfig.files.exclude,
|
|
640
|
+
}, opts)));
|
|
641
|
+
common(md.command("lint-dir"))
|
|
642
|
+
.description("Run all checks on all markdown files in a directory")
|
|
643
|
+
.argument("[directory]", "Path to the directory to scan (default: workspace root)")
|
|
644
|
+
.option("-s, --style", "Include markdown style checks (markdownlint)")
|
|
645
|
+
.option("--no-style", "Disable markdown style checks (markdownlint)")
|
|
646
|
+
.option("--mermaid", "Enable Mermaid checks")
|
|
647
|
+
.option("--no-mermaid", "Disable Mermaid checks")
|
|
648
|
+
.option("--katex", "Enable KaTeX checks")
|
|
649
|
+
.option("--no-katex", "Disable KaTeX checks")
|
|
650
|
+
.option("--references", "Enable reference checks")
|
|
651
|
+
.option("--no-references", "Disable reference checks")
|
|
652
|
+
.option("--summary", "Show one line per file with pass/fail and issue count")
|
|
653
|
+
.option("--no-summary", "Disable summary output")
|
|
654
|
+
.option("--concurrency <n>", "Maximum files checked concurrently")
|
|
655
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
656
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
657
|
+
.option("--changed-since <revision>", "Only files changed since a Git revision")
|
|
658
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 All files pass all checks\n 2 One or more issues found in any file")
|
|
659
|
+
.action((directory, opts) => lintDirAction(directory ?? projectConfig.root, commandOptions("lint-dir", {
|
|
660
|
+
style: projectConfig.checks.markdownlint,
|
|
661
|
+
summary: false,
|
|
662
|
+
concurrency: String(defaultLintConcurrency()),
|
|
663
|
+
include: projectConfig.files.include,
|
|
664
|
+
exclude: projectConfig.files.exclude,
|
|
665
|
+
mermaid: projectConfig.checks.mermaid,
|
|
666
|
+
katex: projectConfig.checks.katex,
|
|
667
|
+
references: projectConfig.checks.references,
|
|
668
|
+
}, opts)));
|
|
669
|
+
common(md.command("refs"))
|
|
670
|
+
.description("List all references from a markdown file and check if targets exist")
|
|
671
|
+
.argument("<file>", "Path to the markdown file to inspect")
|
|
672
|
+
.option("-e, --external", "Include external URLs")
|
|
673
|
+
.option("--no-external", "Exclude external URLs")
|
|
674
|
+
.option("-a, --anchors", "Include anchor-only references")
|
|
675
|
+
.option("--no-anchors", "Exclude anchor-only references")
|
|
676
|
+
.option("-i, --images", "Include image references")
|
|
677
|
+
.option("--no-images", "Exclude image references")
|
|
678
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 All referenced targets exist\n 2 One or more targets missing")
|
|
679
|
+
.action((file, opts) => refsAction(file, commandOptions("refs", { external: false, anchors: false, images: false }, opts)));
|
|
680
|
+
common(md.command("refs-to"))
|
|
681
|
+
.description("Find all markdown files that reference a given file")
|
|
682
|
+
.argument("<file>", "Path to the file to find references to")
|
|
683
|
+
.argument("[directory]", "Directory to search (default: current directory)")
|
|
684
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
685
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
686
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
687
|
+
.action((file, directory, opts) => refsToAction(file, directory ?? projectConfig.root, commandOptions("refs-to", { include: projectConfig.files.include, exclude: projectConfig.files.exclude }, opts)));
|
|
688
|
+
common(md.command("headers"))
|
|
689
|
+
.description("Extract headings from a markdown file with line numbers")
|
|
690
|
+
.argument("<file>", "Path to the markdown file")
|
|
691
|
+
.option("--max-depth <n>", "Maximum heading depth to include (1-6)")
|
|
692
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
693
|
+
.action((file, opts) => headersAction(file, commandOptions("headers", { maxDepth: "6" }, opts)));
|
|
694
|
+
common(md.command("outline"))
|
|
695
|
+
.description("Show headings in an indented outline format")
|
|
696
|
+
.argument("<file>", "Path to the markdown file")
|
|
697
|
+
.option("--max-depth <n>", "Maximum heading depth to include (1-6)")
|
|
698
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
699
|
+
.action((file, opts) => outlineAction(file, commandOptions("outline", { maxDepth: "6" }, opts)));
|
|
700
|
+
common(md.command("toc"))
|
|
701
|
+
.description("Generate a markdown table of contents from headings")
|
|
702
|
+
.argument("<file>", "Path to the markdown file")
|
|
703
|
+
.option("--max-depth <n>", "Maximum heading depth to include (1-6)")
|
|
704
|
+
.option("--min-depth <n>", "Minimum heading depth to include (1-6)")
|
|
705
|
+
.option("--ordered", "Use numbered lists instead of bullets")
|
|
706
|
+
.option("--no-ordered", "Use bullet lists")
|
|
707
|
+
.option("--check", "Check marker-based TOC synchronization")
|
|
708
|
+
.option("--write", "Update the content between TOC markers")
|
|
709
|
+
.option("--dry-run", "Print the proposed marker block without writing")
|
|
710
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
711
|
+
.action((file, opts) => tocAction(file, commandOptions("toc", { maxDepth: "6", minDepth: "1", ordered: false, check: false, write: false, dryRun: false }, opts)));
|
|
712
|
+
common(md.command("graph"))
|
|
713
|
+
.description("Analyze the workspace Markdown document graph")
|
|
714
|
+
.argument("[directory]", "Directory to scan (default: workspace root)")
|
|
715
|
+
.option("--output <mode>", "Graph output: report, mermaid, dot")
|
|
716
|
+
.option("--entry <file>", "Entry point for reachability (repeatable)", collect)
|
|
717
|
+
.option("--focus <file>", "Restrict to the neighborhood of a document (repeatable)", collect)
|
|
718
|
+
.option("--depth <n>", "Undirected hops around --focus")
|
|
719
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
720
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
721
|
+
.addHelpText("after", "\n--focus narrows the report and the mermaid/dot diagrams to the documents within\n--depth undirected hops, so backlinks are included. The graph is analyzed in full\nfirst, so inbound/outbound counts, components, and cycles remain whole-workspace\nfacts rather than artifacts of the narrowing.\n\nExit codes:\n 0 No broken or unreachable documents\n 2 Broken or unreachable documents found")
|
|
722
|
+
.action((directory, opts) => graphAction(directory ?? projectConfig.root, commandOptions("graph", {
|
|
723
|
+
output: "report",
|
|
724
|
+
depth: "1",
|
|
725
|
+
focus: [],
|
|
726
|
+
entry: projectConfig.files.entryPoints,
|
|
727
|
+
include: projectConfig.files.include,
|
|
728
|
+
exclude: projectConfig.files.exclude,
|
|
729
|
+
}, opts)));
|
|
730
|
+
common(md.command("validate-frontmatter"))
|
|
731
|
+
.description("Validate Markdown frontmatter with schema and workspace rules")
|
|
732
|
+
.argument("<paths...>", "Markdown files, directories, or globs")
|
|
733
|
+
.option("--schema <file>", "JSON or YAML Schema file")
|
|
734
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
735
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
736
|
+
.option("--changed-since <revision>", "Only files changed since a Git revision")
|
|
737
|
+
.addHelpText("after", "\nExit codes:\n 0 Frontmatter is valid\n 1 Configuration or schema error\n 2 Validation findings")
|
|
738
|
+
.action((target, opts) => validateFrontmatterAction(target, commandOptions("validate-frontmatter", {
|
|
739
|
+
schema: projectConfig.frontmatter.schema,
|
|
740
|
+
include: projectConfig.files.include,
|
|
741
|
+
exclude: projectConfig.files.exclude,
|
|
742
|
+
}, opts)));
|
|
743
|
+
common(md.command("audit"))
|
|
744
|
+
.description("Run composable checks across a Markdown workspace")
|
|
745
|
+
.argument("[directory]", "Directory to scan (default: workspace root)")
|
|
746
|
+
.option("--summary", "Show per-check and per-file counts")
|
|
747
|
+
.option("--no-summary", "Show detailed findings")
|
|
748
|
+
.option("--external", "Check external URLs")
|
|
749
|
+
.option("--no-external", "Do not check external URLs")
|
|
750
|
+
.option("--frontmatter", "Enable configured frontmatter checks")
|
|
751
|
+
.option("--no-frontmatter", "Disable frontmatter checks")
|
|
752
|
+
.option("--graph", "Enable graph checks")
|
|
753
|
+
.option("--no-graph", "Disable graph checks")
|
|
754
|
+
.option("--toc", "Enable configured TOC checks")
|
|
755
|
+
.option("--no-toc", "Disable TOC checks")
|
|
756
|
+
.option("--snippets", "Enable source-linked snippet checks")
|
|
757
|
+
.option("--no-snippets", "Disable source-linked snippet checks")
|
|
758
|
+
.option("-s, --style", "Include markdown style checks")
|
|
759
|
+
.option("--no-style", "Disable markdown style checks")
|
|
760
|
+
.option("--mermaid", "Enable Mermaid checks")
|
|
761
|
+
.option("--no-mermaid", "Disable Mermaid checks")
|
|
762
|
+
.option("--katex", "Enable KaTeX checks")
|
|
763
|
+
.option("--no-katex", "Disable KaTeX checks")
|
|
764
|
+
.option("--references", "Enable reference checks")
|
|
765
|
+
.option("--no-references", "Disable reference checks")
|
|
766
|
+
.option("--concurrency <n>", "Maximum concurrent checks")
|
|
767
|
+
.option("--timeout <ms>", "External URL timeout")
|
|
768
|
+
.option("--retry <n>", "External URL retry count")
|
|
769
|
+
.option("--changed-since <revision>", "Only files changed since a Git revision")
|
|
770
|
+
.option("--entry <file>", "Graph entry point (repeatable)", collect)
|
|
771
|
+
.option("--baseline <file>", "Suppress findings already recorded in a baseline")
|
|
772
|
+
.option("--write-baseline <file>", "Record the current findings as a baseline and exit 0")
|
|
773
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
774
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
775
|
+
.addHelpText("after", "\nA baseline suppresses findings it already records, so only regressions fail. Entries\nare keyed on checker, workspace-relative path, and message — not line number — so\nediting prose above a known finding does not resurface it. Recording is explicit:\n--write-baseline writes the file and exits 0, and the two flags cannot be combined.\n\nExit codes:\n 0 Audit passed, or a baseline was written\n 1 Operational error\n 2 Actionable findings")
|
|
776
|
+
.action((directory, opts) => auditAction(directory ?? projectConfig.root, commandOptions("audit", {
|
|
777
|
+
summary: false,
|
|
778
|
+
external: projectConfig.checks.external,
|
|
779
|
+
frontmatter: projectConfig.checks.frontmatter,
|
|
780
|
+
graph: projectConfig.checks.graph,
|
|
781
|
+
toc: projectConfig.checks.toc,
|
|
782
|
+
snippets: projectConfig.checks.snippets,
|
|
783
|
+
style: projectConfig.checks.markdownlint,
|
|
784
|
+
mermaid: projectConfig.checks.mermaid,
|
|
785
|
+
katex: projectConfig.checks.katex,
|
|
786
|
+
references: projectConfig.checks.references,
|
|
787
|
+
concurrency: String(defaultLintConcurrency()),
|
|
788
|
+
timeout: "5000",
|
|
789
|
+
retry: "1",
|
|
790
|
+
entry: projectConfig.files.entryPoints,
|
|
791
|
+
include: projectConfig.files.include,
|
|
792
|
+
exclude: projectConfig.files.exclude,
|
|
793
|
+
maxDepth: String(projectConfig.commands.toc?.maxDepth ?? "6"),
|
|
794
|
+
minDepth: String(projectConfig.commands.toc?.minDepth ?? "1"),
|
|
795
|
+
ordered: Boolean(projectConfig.commands.toc?.ordered ?? false),
|
|
796
|
+
}, opts)));
|
|
797
|
+
common(md.command("stats"))
|
|
798
|
+
.description("Show document statistics (words, headings, links, code blocks)")
|
|
799
|
+
.argument("<file>", "Path to the markdown file")
|
|
800
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
801
|
+
.action((file, opts) => statsAction(file, commandOptions("stats", {}, opts)));
|
|
802
|
+
common(md.command("code-blocks"))
|
|
803
|
+
.description("List fenced code blocks with language and line ranges")
|
|
804
|
+
.argument("<file>", "Path to the markdown file")
|
|
805
|
+
.option("--lang <language>", "Filter by code block language")
|
|
806
|
+
.option("--content", "Include code block content in output")
|
|
807
|
+
.option("--no-content", "Exclude code block content from output")
|
|
808
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
809
|
+
.action((file, opts) => codeBlocksAction(file, commandOptions("code-blocks", { content: false }, opts)));
|
|
810
|
+
common(md.command("structure"))
|
|
811
|
+
.description("Show document structure skeleton (headings, code blocks, lists, math)")
|
|
812
|
+
.argument("<file>", "Path to the markdown file")
|
|
813
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
814
|
+
.action((file, opts) => structureAction(file, commandOptions("structure", {}, opts)));
|
|
815
|
+
common(md.command("links"))
|
|
816
|
+
.description("List all links with context, grouped by type")
|
|
817
|
+
.argument("<file>", "Path to the markdown file")
|
|
818
|
+
.option("--broken-only", "Only show broken links")
|
|
819
|
+
.option("--no-broken-only", "Include valid links")
|
|
820
|
+
.option("--type <type>", "Filter by type: internal, external, image, anchor")
|
|
821
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 All link targets exist (or not checked)\n 2 One or more broken links found")
|
|
822
|
+
.action((file, opts) => linksAction(file, commandOptions("links", { brokenOnly: false }, opts)));
|
|
823
|
+
common(md.command("section"))
|
|
824
|
+
.description("Extract content of a section by heading text or slug")
|
|
825
|
+
.argument("<file>", "Path to the markdown file")
|
|
826
|
+
.argument("<heading>", "Heading text or anchor slug (case-insensitive)")
|
|
827
|
+
.option("--include-heading", "Include the heading line in output")
|
|
828
|
+
.option("--no-include-heading", "Exclude the heading line from output")
|
|
829
|
+
.option("--children", "Include nested subsections")
|
|
830
|
+
.option("--no-children", "Exclude nested subsections")
|
|
831
|
+
.option("--raw", "Output raw markdown only (no metadata)")
|
|
832
|
+
.option("--no-raw", "Include section metadata")
|
|
833
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 Section found and extracted\n 1 File not found or heading not found")
|
|
834
|
+
.action((file, heading, opts) => sectionAction(file, heading, commandOptions("section", { includeHeading: true, children: true, raw: false }, opts)));
|
|
835
|
+
common(md.command("context"))
|
|
836
|
+
.description("Assemble a reproducible context pack from the workspace graph")
|
|
837
|
+
.argument("[seeds...]", "Markdown files, directories, or globs to start from")
|
|
838
|
+
.option("--depth <n>", "Graph hops to follow from the seeds (0-6)")
|
|
839
|
+
.option("--section <heading>", "Restrict seeds to this heading (repeatable)", collect)
|
|
840
|
+
.option("--target <path>", "Seed with documents referencing this path[#fragment]")
|
|
841
|
+
.option("--budget <bytes>", "Maximum UTF-8 bytes of unit content, or 0 for unlimited")
|
|
842
|
+
.option("--backlinks", "Also follow references backwards")
|
|
843
|
+
.option("--no-backlinks", "Follow references forwards only")
|
|
844
|
+
.option("--children", "Expand --section through its subsections")
|
|
845
|
+
.option("--no-children", "Limit --section to the named section")
|
|
846
|
+
.option("--frontmatter", "Emit each document's frontmatter as a unit")
|
|
847
|
+
.option("--no-frontmatter", "Omit frontmatter")
|
|
848
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
849
|
+
.option("--exclude <glob>", "Workspace exclude glob (repeatable)", collect)
|
|
850
|
+
.addHelpText("after", "\nUnits are ordered by graph distance, then discovery order, then document order.\n" +
|
|
851
|
+
"The pack is a prefix of that order: the first unit that would exceed --budget stops\n" +
|
|
852
|
+
"inclusion, and the rest are reported under `omitted`.\n\n" +
|
|
853
|
+
"The token estimate is bytes/4, not a model tokenizer, and never affects inclusion.\n\n" +
|
|
854
|
+
"Exit codes:\n" +
|
|
855
|
+
" 0 Pack written to stdout, whether or not it was truncated\n" +
|
|
856
|
+
" 1 No seeds given, or a --section heading matched nothing")
|
|
857
|
+
.action((seeds, opts) => contextAction(seeds, commandOptions("context", {
|
|
858
|
+
depth: "1",
|
|
859
|
+
section: [],
|
|
860
|
+
budget: "0",
|
|
861
|
+
backlinks: false,
|
|
862
|
+
children: true,
|
|
863
|
+
frontmatter: false,
|
|
864
|
+
include: projectConfig.files.include,
|
|
865
|
+
exclude: projectConfig.files.exclude,
|
|
866
|
+
}, opts)));
|
|
867
|
+
common(md.command("diff"))
|
|
868
|
+
.description("Summarize Markdown changes by structure rather than by text")
|
|
869
|
+
.argument("[a]", "First file, or the directory to scan with --since")
|
|
870
|
+
.argument("[b]", "Second file; omit when using --since")
|
|
871
|
+
.option("--since <revision>", "Compare the worktree against a Git revision")
|
|
872
|
+
.option("--summary", "Show per-file totals without individual changes")
|
|
873
|
+
.option("--no-summary", "Show individual changes")
|
|
874
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
875
|
+
.option("--exclude <glob>", "Workspace exclude glob (repeatable)", collect)
|
|
876
|
+
.addHelpText("after", "\nModes:\n" +
|
|
877
|
+
" md diff <a> <b> Compare two files.\n" +
|
|
878
|
+
" md diff --since <rev> [dir] Compare a revision against the worktree.\n" +
|
|
879
|
+
"Giving two paths and --since together is an error, as is giving neither.\n\n" +
|
|
880
|
+
"--since names the base of the comparison. It is not --changed-since, which\n" +
|
|
881
|
+
"only filters an input set.\n\n" +
|
|
882
|
+
"Renames are matched conservatively and a positional match is reported as a\n" +
|
|
883
|
+
"heuristic, not a fact.\n\n" +
|
|
884
|
+
"Exit codes:\n" +
|
|
885
|
+
" 0 Report written to stdout, whether or not anything changed\n" +
|
|
886
|
+
" 1 Bad invocation, a missing file, or an unreadable revision")
|
|
887
|
+
.action((a, b, opts) => diffAction(a, b, commandOptions("diff", {
|
|
888
|
+
summary: false,
|
|
889
|
+
include: projectConfig.files.include,
|
|
890
|
+
exclude: projectConfig.files.exclude,
|
|
891
|
+
}, opts)));
|
|
892
|
+
common(md.command("frontmatter"))
|
|
893
|
+
.description("Parse and display YAML frontmatter from a markdown file")
|
|
894
|
+
.argument("<file>", "Path to the markdown file")
|
|
895
|
+
.option("--key <key>", "Extract a specific key (dot notation for nested keys)")
|
|
896
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 Frontmatter found (or no frontmatter)\n 1 File not found or key not found")
|
|
897
|
+
.action((file, opts) => frontmatterAction(file, commandOptions("frontmatter", {}, opts)));
|
|
898
|
+
common(md.command("tasks"))
|
|
899
|
+
.description("Extract GFM task list items with completion status")
|
|
900
|
+
.argument("<file>", "Path to the markdown file")
|
|
901
|
+
.option("--status <status>", "Filter by status: done, pending")
|
|
902
|
+
.option("--summary", "Show only summary counts")
|
|
903
|
+
.option("--no-summary", "Show individual tasks")
|
|
904
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
905
|
+
.action((file, opts) => tasksAction(file, commandOptions("tasks", { summary: false }, opts)));
|
|
906
|
+
common(md.command("tables"))
|
|
907
|
+
.description("List or extract GFM tables with location and dimensions")
|
|
908
|
+
.argument("<file>", "Path to the markdown file")
|
|
909
|
+
.option("--content", "Include table content in output")
|
|
910
|
+
.option("--no-content", "Exclude table content from output")
|
|
911
|
+
.option("--index <n>", "Extract only the nth table (1-based)")
|
|
912
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json")
|
|
913
|
+
.action((file, opts) => tablesAction(file, commandOptions("tables", { content: false }, opts)));
|
|
914
|
+
common(md.command("check-urls"))
|
|
915
|
+
.description("Validate external URLs across Markdown inputs")
|
|
916
|
+
.argument("<inputs...>", "Markdown files, directories, globs, or -")
|
|
917
|
+
.option("--timeout <ms>", "Request timeout per URL in milliseconds")
|
|
918
|
+
.option("--concurrency <n>", "Maximum concurrent requests")
|
|
919
|
+
.option("--retry <n>", "Number of retries on failure")
|
|
920
|
+
.option("--include-ok", "Include successful URLs in output")
|
|
921
|
+
.option("--no-include-ok", "Exclude successful URLs from output")
|
|
922
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
923
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
924
|
+
.option("--changed-since <revision>", "Only files changed since a Git revision")
|
|
925
|
+
.option("--ignore <glob>", "Ignore matching URL (repeatable)", collect)
|
|
926
|
+
.option("--ignore-domain <domain>", "Ignore domain and subdomains (repeatable)", collect)
|
|
927
|
+
.option("--allowed-status <code>", "Treat HTTP status as allowed (repeatable)", collect)
|
|
928
|
+
.option("--cache", "Use the URL result cache")
|
|
929
|
+
.option("--no-cache", "Disable the URL result cache")
|
|
930
|
+
.option("--cache-ttl <ms>", "URL cache lifetime in milliseconds")
|
|
931
|
+
.option("--head-fallback-status <code>", "HEAD status that triggers GET (repeatable)", collect)
|
|
932
|
+
.option("--report-redirects", "Report redirects and final destinations")
|
|
933
|
+
.option("--no-report-redirects", "Do not report redirects")
|
|
934
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 All URLs reachable (or no external URLs)\n 2 One or more URLs are broken")
|
|
935
|
+
.action((file, opts) => checkUrlsAction(file, commandOptions("check-urls", {
|
|
936
|
+
timeout: "5000",
|
|
937
|
+
concurrency: "5",
|
|
938
|
+
retry: "1",
|
|
939
|
+
includeOk: false,
|
|
940
|
+
include: projectConfig.files.include,
|
|
941
|
+
exclude: projectConfig.files.exclude,
|
|
942
|
+
ignore: projectConfig.urls.ignore,
|
|
943
|
+
ignoreDomain: projectConfig.urls.ignoreDomains,
|
|
944
|
+
allowedStatus: projectConfig.urls.allowedStatuses,
|
|
945
|
+
cache: projectConfig.urls.cache,
|
|
946
|
+
cacheTtl: String(projectConfig.urls.cacheTtl),
|
|
947
|
+
headFallbackStatus: projectConfig.urls.headFallbackStatuses,
|
|
948
|
+
reportRedirects: projectConfig.urls.reportRedirects,
|
|
949
|
+
}, opts)));
|
|
950
|
+
common(md.command("orphans"))
|
|
951
|
+
.description("Find markdown files not referenced by any other markdown file")
|
|
952
|
+
.argument("[directory]", "Directory to scan (default: workspace root)")
|
|
953
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
954
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
955
|
+
.option("--ignore <glob>", "Glob pattern to exclude (repeatable)", collect, [])
|
|
956
|
+
.option("--entry <file>", "Entry-point file not considered orphan (repeatable)", collect, [])
|
|
957
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 No orphans found\n 2 One or more orphans found")
|
|
958
|
+
.action((directory, opts) => orphansAction(directory ?? projectConfig.root, commandOptions("orphans", {
|
|
959
|
+
ignore: [],
|
|
960
|
+
include: projectConfig.files.include,
|
|
961
|
+
exclude: projectConfig.files.exclude,
|
|
962
|
+
entry: projectConfig.files.entryPoints,
|
|
963
|
+
}, opts)));
|
|
964
|
+
common(md.command("query"))
|
|
965
|
+
.description("Run a focused query across the Markdown workspace")
|
|
966
|
+
.argument("<kind>", "Query kind: links-to, duplicates, unused-assets, code-blocks, tasks, missing-h1, frontmatter-keys")
|
|
967
|
+
.argument("[directory]", "Directory to query (default: workspace root)")
|
|
968
|
+
.option("--target <path>", "Target path and optional heading fragment for links-to")
|
|
969
|
+
.option("--field <field>", "Duplicate field: title, slug, heading-slug, frontmatter:<key>")
|
|
970
|
+
.option("--lang <language>", "Code-block language filter")
|
|
971
|
+
.option("--content", "Include code-block content")
|
|
972
|
+
.option("--no-content", "Exclude code-block content")
|
|
973
|
+
.option("--status <status>", "Task status: all, done, pending")
|
|
974
|
+
.option("--summary", "Show task totals without individual tasks")
|
|
975
|
+
.option("--no-summary", "Include individual tasks")
|
|
976
|
+
.option("--asset-extension <ext>", "Asset extension override (repeatable)", collect)
|
|
977
|
+
.option("--where <predicate>", "Filter predicate (repeatable, AND-ed)", collect)
|
|
978
|
+
.option("--select <fields>", "Comma-separated fields to emit (repeatable)", collect)
|
|
979
|
+
.option("--group-by <field>", "Group rows by one field")
|
|
980
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
981
|
+
.option("--exclude <glob>", "Workspace exclude glob (repeatable)", collect)
|
|
982
|
+
.addHelpText("after", "\nQuery matches are informational and exit 0.\n\n" +
|
|
983
|
+
"Two modes share the kind argument. Without --where, --select, or --group-by the\n" +
|
|
984
|
+
"shortcut kinds emit their historical shapes unchanged. With any of them the\n" +
|
|
985
|
+
"kind names an entity: documents, headings, links, tasks, code-blocks, frontmatter.\n\n" +
|
|
986
|
+
"Predicates are <field><op><value> with one of = != ~ > >= < <=, or has:<field> /\n" +
|
|
987
|
+
"links-to:<path>, optionally negated with a leading '!'. Repeating --where ANDs\n" +
|
|
988
|
+
"them. `frontmatter.<key>` is a field on every entity.\n\n" +
|
|
989
|
+
"Examples:\n" +
|
|
990
|
+
" md query documents --where has:h1 --select file,title\n" +
|
|
991
|
+
" md query links --where links-to:docs/api.md --select file,line\n" +
|
|
992
|
+
" md query tasks --where status=pending --group-by frontmatter.owner\n\n" +
|
|
993
|
+
"An unknown field, predicate, or operator exits 1 rather than matching nothing.")
|
|
994
|
+
.action((kind, directory, opts) => queryAction(kind, directory ?? projectConfig.root, commandOptions("query", {
|
|
995
|
+
include: projectConfig.files.include,
|
|
996
|
+
exclude: projectConfig.files.exclude,
|
|
997
|
+
field: "title",
|
|
998
|
+
content: false,
|
|
999
|
+
status: "all",
|
|
1000
|
+
summary: false,
|
|
1001
|
+
assetExtension: projectConfig.assets.extensions,
|
|
1002
|
+
// Predicates are per-question by nature, so they are deliberately not
|
|
1003
|
+
// configurable: a checked-in `commands.query.where` would silently
|
|
1004
|
+
// filter every query anyone ran in the workspace.
|
|
1005
|
+
where: [],
|
|
1006
|
+
select: [],
|
|
1007
|
+
}, opts)));
|
|
1008
|
+
common(md.command("index"))
|
|
1009
|
+
.description("Inspect or manage the persistent workspace index")
|
|
1010
|
+
.argument("<action>", "Index action: status, build, clear")
|
|
1011
|
+
.argument("[directory]", "Directory to inspect or build (default: workspace root)")
|
|
1012
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
1013
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
1014
|
+
.addHelpText("after", "\nActions:\n status Inspect cache coverage\n build Force a rebuild\n clear Clear this workspace cache")
|
|
1015
|
+
.action((action, directory, opts) => indexAction(action, directory ?? projectConfig.root, commandOptions("index", { include: projectConfig.files.include, exclude: projectConfig.files.exclude }, opts)));
|
|
1016
|
+
common(md.command("fix"))
|
|
1017
|
+
.description("Plan and apply deterministic Markdown fixes")
|
|
1018
|
+
.argument("<inputs...>", "Markdown files, directories, or globs")
|
|
1019
|
+
.option("--rule <name>", "Fixer to run (repeatable); default: every fixer", collect)
|
|
1020
|
+
.option("--check", "Report pending fixes without writing (default)")
|
|
1021
|
+
.option("--dry-run", "Print the full plan without writing")
|
|
1022
|
+
.option("--write", "Apply the plan as one transaction")
|
|
1023
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
1024
|
+
.option("--exclude <glob>", "Workspace exclude glob (repeatable)", collect)
|
|
1025
|
+
.option("--changed-since <revision>", "Only files changed since a Git revision")
|
|
1026
|
+
.addHelpText("after", "\nThe mode defaults to --check, and --check, --dry-run, and --write are mutually\n" +
|
|
1027
|
+
"exclusive. The mode cannot be set from project configuration, so a checked-in\n" +
|
|
1028
|
+
"config file can never turn md fix into a writer.\n\n" +
|
|
1029
|
+
"--write applies every file's edits as one transaction, and refuses to write at\n" +
|
|
1030
|
+
"all if any input changed after planning, any two edits overlap, or any target\n" +
|
|
1031
|
+
"resolves outside the workspace root.\n\n" +
|
|
1032
|
+
"Exit codes:\n" +
|
|
1033
|
+
" 0 No pending fixes, or --write/--dry-run completed\n" +
|
|
1034
|
+
" 2 --check found pending fixes, or any mode found a conflict")
|
|
1035
|
+
.action((inputs, opts) => fixAction(inputs, commandOptions("fix", {
|
|
1036
|
+
rule: [],
|
|
1037
|
+
include: projectConfig.files.include,
|
|
1038
|
+
exclude: projectConfig.files.exclude,
|
|
1039
|
+
// Config may supply these as numbers; the fixer parses strings, so
|
|
1040
|
+
// coerce here exactly as `md audit` does.
|
|
1041
|
+
maxDepth: String(projectConfig.commands.toc?.maxDepth ?? "6"),
|
|
1042
|
+
minDepth: String(projectConfig.commands.toc?.minDepth ?? "1"),
|
|
1043
|
+
ordered: Boolean(projectConfig.commands.toc?.ordered ?? false),
|
|
1044
|
+
}, opts)));
|
|
1045
|
+
common(md.command("check-snippets"))
|
|
1046
|
+
.description("Compare fenced code blocks against the source regions they declare")
|
|
1047
|
+
.argument("[inputs...]", "Markdown files, directories, or globs (default: workspace root)")
|
|
1048
|
+
.option("--check", "Report drift without writing (default)")
|
|
1049
|
+
.option("--dry-run", "Print the full plan without writing")
|
|
1050
|
+
.option("--write", "Refresh linked blocks as one transaction")
|
|
1051
|
+
.option("--include-ok", "Include up-to-date snippets in output")
|
|
1052
|
+
.option("--no-include-ok", "Exclude up-to-date snippets from output")
|
|
1053
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
1054
|
+
.option("--exclude <glob>", "Workspace exclude glob (repeatable)", collect)
|
|
1055
|
+
.addHelpText("after", "\nOnly fences whose info string carries cairn:snippet=<path>[#<region>] are\n" +
|
|
1056
|
+
"considered. A snippet is never executed; the source file is only read.\n\n" +
|
|
1057
|
+
"The mode defaults to --check, and --check, --dry-run, and --write are mutually\n" +
|
|
1058
|
+
"exclusive. The mode cannot be set from project configuration, so a checked-in\n" +
|
|
1059
|
+
"config file can never turn this checker into a writer.\n\n" +
|
|
1060
|
+
"Source reads are confined to the workspace root; writes are confined to the\n" +
|
|
1061
|
+
"directory containing the selected documents.\n\n" +
|
|
1062
|
+
"Format shorthands:\n" +
|
|
1063
|
+
" -fh Shorthand for --format=human\n" +
|
|
1064
|
+
" -fj Shorthand for --format=json\n\n" +
|
|
1065
|
+
"Exit codes:\n" +
|
|
1066
|
+
" 0 Every linked snippet matches, or --write refreshed them\n" +
|
|
1067
|
+
" 2 --check or --dry-run found drift, or any mode found a link it\n" +
|
|
1068
|
+
" could not resolve, a malformed link, a fence it cannot rewrite,\n" +
|
|
1069
|
+
" or an edit-plan conflict")
|
|
1070
|
+
.action((inputs, opts) => checkSnippetsAction(inputs.length ? inputs : [projectConfig.root], commandOptions("check-snippets", {
|
|
1071
|
+
includeOk: false,
|
|
1072
|
+
include: projectConfig.files.include,
|
|
1073
|
+
exclude: projectConfig.files.exclude,
|
|
1074
|
+
}, opts)));
|
|
1075
|
+
common(md.command("rename-heading"))
|
|
1076
|
+
.description("Rename a heading and update all internal anchor references")
|
|
1077
|
+
.argument("<file>", "Path to the markdown file containing the heading")
|
|
1078
|
+
.argument("<old-heading>", "Current heading text (case-insensitive)")
|
|
1079
|
+
.argument("<new-heading>", "New heading text")
|
|
1080
|
+
.option("--directory <dir>", "Also update references in other files within this directory")
|
|
1081
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
1082
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
1083
|
+
.option("--dry-run", "Show what would change without modifying files")
|
|
1084
|
+
.option("--no-dry-run", "Apply changes")
|
|
1085
|
+
.addHelpText("after", "\nFormat shorthands:\n -fh Shorthand for --format=human\n -fj Shorthand for --format=json\n\nExit codes:\n 0 Heading renamed successfully (or dry-run completed)\n 1 File/heading not found or new heading slug already exists")
|
|
1086
|
+
.action((file, oldHeading, newHeading, opts) => renameHeadingAction(file, oldHeading, newHeading, commandOptions("rename-heading", {
|
|
1087
|
+
dryRun: false,
|
|
1088
|
+
include: projectConfig.files.include,
|
|
1089
|
+
exclude: projectConfig.files.exclude,
|
|
1090
|
+
}, opts)));
|
|
1091
|
+
common(md.command("rename-file"))
|
|
1092
|
+
.description("Move a workspace file and update Markdown references")
|
|
1093
|
+
.argument("<source>", "Existing Markdown document or referenced asset")
|
|
1094
|
+
.argument("<destination>", "New path (parent directory must exist)")
|
|
1095
|
+
.option("--include <glob>", "Markdown include glob (repeatable)", collect)
|
|
1096
|
+
.option("--exclude <glob>", "Markdown exclude glob (repeatable)", collect)
|
|
1097
|
+
.option("--dry-run", "Show changes without modifying files")
|
|
1098
|
+
.option("--no-dry-run", "Apply changes")
|
|
1099
|
+
.action((source, destination, opts) => renameFileAction(source, destination, commandOptions("rename-file", {
|
|
1100
|
+
dryRun: false,
|
|
1101
|
+
include: projectConfig.files.include,
|
|
1102
|
+
exclude: projectConfig.files.exclude,
|
|
1103
|
+
}, opts)));
|
|
1104
|
+
try {
|
|
1105
|
+
await program.parseAsync(argv);
|
|
1106
|
+
}
|
|
1107
|
+
catch (error) {
|
|
1108
|
+
if (error instanceof CommandExit) {
|
|
1109
|
+
process.exitCode = error.exitCode;
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
process.stderr.write(`Error: ${error.message}\n`);
|
|
1113
|
+
process.exitCode = 1;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
runtime().workspace.flush();
|
|
1117
|
+
//# sourceMappingURL=cli.js.map
|