@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
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { diagnostic } from "../types.js";
|
|
6
|
+
import { FEATURE_KEYS, profileFor } from "../targets/index.js";
|
|
7
|
+
import { isInside } from "../../config-schema.js";
|
|
8
|
+
import { renderBundle } from "../render.js";
|
|
9
|
+
import { buildCatalogs, checkAssets, checkCaseCollisions, checkExecutables, checkPinning, } from "../package/index.js";
|
|
10
|
+
import { placeSymlink, writeArtifactsAtomically } from "../writer.js";
|
|
11
|
+
import { packageName, packageVersion } from "../../version.js";
|
|
12
|
+
export const INSTALL_MANIFEST = ".cairn-install.json";
|
|
13
|
+
/** The pre-rename manifest, still read so existing installs stay removable. */
|
|
14
|
+
export const LEGACY_INSTALL_MANIFEST = ".claude-cli-install.json";
|
|
15
|
+
/**
|
|
16
|
+
* The manifest file in `destination`, preferring the current name.
|
|
17
|
+
*
|
|
18
|
+
* Only the paths this module reads off *disk* go through here. Comparisons
|
|
19
|
+
* against `artifact.path` elsewhere in this file stay exact equality against
|
|
20
|
+
* `INSTALL_MANIFEST` on purpose: those artifacts come from a plan this run just
|
|
21
|
+
* built, which never emits the legacy name.
|
|
22
|
+
*/
|
|
23
|
+
export function installManifestIn(destination) {
|
|
24
|
+
for (const name of [INSTALL_MANIFEST, LEGACY_INSTALL_MANIFEST]) {
|
|
25
|
+
const candidate = path.join(destination, name);
|
|
26
|
+
if (existsAt(candidate))
|
|
27
|
+
return candidate;
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
export const INSTALL_CACHE = ".install";
|
|
32
|
+
export const INSTALL_SCOPES = ["user", "project"];
|
|
33
|
+
/**
|
|
34
|
+
* The plugin keys a registration activates, whichever spelling recorded them.
|
|
35
|
+
* A manifest written before collections carries only `pluginKey`.
|
|
36
|
+
*/
|
|
37
|
+
export function registeredPluginKeys(registration) {
|
|
38
|
+
return registration.pluginKeys ?? (registration.pluginKey ? [registration.pluginKey] : []);
|
|
39
|
+
}
|
|
40
|
+
function sha256(content) {
|
|
41
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
42
|
+
}
|
|
43
|
+
function octal(mode) {
|
|
44
|
+
return `0${(mode & 0o777).toString(8)}`;
|
|
45
|
+
}
|
|
46
|
+
function byPath(a, b) {
|
|
47
|
+
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
48
|
+
}
|
|
49
|
+
function error(code, message, extra = {}) {
|
|
50
|
+
return { ...diagnostic(code, message, "unsupported", extra), severity: "error" };
|
|
51
|
+
}
|
|
52
|
+
function existsAt(file) {
|
|
53
|
+
try {
|
|
54
|
+
fs.lstatSync(file);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function isResolved(value) {
|
|
62
|
+
return "location" in value;
|
|
63
|
+
}
|
|
64
|
+
function toEntry(manifest) {
|
|
65
|
+
return {
|
|
66
|
+
name: manifest.bundle.name,
|
|
67
|
+
version: manifest.bundle.version,
|
|
68
|
+
target: manifest.target,
|
|
69
|
+
profile: manifest.profile,
|
|
70
|
+
scope: manifest.scope,
|
|
71
|
+
layout: manifest.layout,
|
|
72
|
+
mode: manifest.mode,
|
|
73
|
+
destination: manifest.destination,
|
|
74
|
+
registered: Boolean(manifest.registration),
|
|
75
|
+
files: manifest.files.length,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function resolveScope(value, fallback) {
|
|
79
|
+
const scope = value ?? fallback;
|
|
80
|
+
if (!scope)
|
|
81
|
+
throw new Error("Unknown --scope. Use user or project.");
|
|
82
|
+
if (scope !== "user" && scope !== "project")
|
|
83
|
+
throw new Error(`Unknown --scope '${scope}'. Use user or project.`);
|
|
84
|
+
return scope;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Expands a profile install root. `~` is the caller's home, `.` is `cwd`, and
|
|
88
|
+
* anything else is resolved against `cwd`.
|
|
89
|
+
*/
|
|
90
|
+
export function expandInstallRoot(root, context = {}) {
|
|
91
|
+
const home = context.home ?? os.homedir();
|
|
92
|
+
const cwd = context.cwd ?? process.cwd();
|
|
93
|
+
if (root === "~")
|
|
94
|
+
return home;
|
|
95
|
+
if (root.startsWith("~/"))
|
|
96
|
+
return path.resolve(home, root.slice(2));
|
|
97
|
+
if (root === ".")
|
|
98
|
+
return path.resolve(cwd);
|
|
99
|
+
return path.resolve(cwd, root);
|
|
100
|
+
}
|
|
101
|
+
export function locationFor(target, scope) {
|
|
102
|
+
return profileFor(target).install?.[scope] ?? null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* True when `relative` would land outside `root`. Lexical: a `..` segment or an
|
|
106
|
+
* absolute path is enough, matching the overlay boundary.
|
|
107
|
+
*/
|
|
108
|
+
export function pathEscapesRoot(root, relative) {
|
|
109
|
+
const normalized = relative.split(path.sep).join("/");
|
|
110
|
+
if (!normalized || normalized.startsWith("/") || /^[A-Za-z]:/.test(normalized))
|
|
111
|
+
return true;
|
|
112
|
+
if (normalized.includes("\\") || normalized.includes("\0"))
|
|
113
|
+
return true;
|
|
114
|
+
if (normalized.split("/").some((segment) => segment === ".." || segment === "."))
|
|
115
|
+
return true;
|
|
116
|
+
const resolved = path.resolve(root, ...normalized.split("/"));
|
|
117
|
+
return !isInside(path.resolve(root), resolved);
|
|
118
|
+
}
|
|
119
|
+
function relocate(artifacts, prefix) {
|
|
120
|
+
const head = `${prefix}/`;
|
|
121
|
+
return artifacts
|
|
122
|
+
.filter((artifact) => artifact.path.startsWith(head))
|
|
123
|
+
.map((artifact) => ({ ...artifact, path: artifact.path.slice(head.length) }))
|
|
124
|
+
.sort(byPath);
|
|
125
|
+
}
|
|
126
|
+
function retargetCatalog(artifacts, entriesKey, source) {
|
|
127
|
+
return artifacts.map((artifact) => {
|
|
128
|
+
if (!artifact.path.endsWith("/marketplace.json") && artifact.path !== "marketplace.json")
|
|
129
|
+
return artifact;
|
|
130
|
+
const document = JSON.parse(artifact.content.toString());
|
|
131
|
+
const entries = document[entriesKey];
|
|
132
|
+
if (!Array.isArray(entries))
|
|
133
|
+
return artifact;
|
|
134
|
+
const next = {
|
|
135
|
+
...document,
|
|
136
|
+
[entriesKey]: entries.map((entry) => entry && typeof entry === "object" ? { ...entry, source } : entry),
|
|
137
|
+
};
|
|
138
|
+
return { ...artifact, content: Buffer.from(JSON.stringify(next, null, 2) + "\n") };
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function bundleProvides(bundle, key) {
|
|
142
|
+
switch (key) {
|
|
143
|
+
case "skills":
|
|
144
|
+
return bundle.skills.length > 0;
|
|
145
|
+
case "agents":
|
|
146
|
+
return bundle.agents.length > 0;
|
|
147
|
+
case "rules":
|
|
148
|
+
return bundle.rules.length > 0;
|
|
149
|
+
case "hooks":
|
|
150
|
+
return Boolean(bundle.hooks) || bundle.hookFiles.length > 0;
|
|
151
|
+
case "policies":
|
|
152
|
+
return bundle.policies.length > 0;
|
|
153
|
+
case "mcp":
|
|
154
|
+
return Boolean(bundle.mcp);
|
|
155
|
+
case "assets":
|
|
156
|
+
return bundle.assets.length > 0;
|
|
157
|
+
case "placeholders":
|
|
158
|
+
case "native":
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function featureDiagnostics(bundle, target, profile) {
|
|
163
|
+
const diagnostics = [];
|
|
164
|
+
const features = profileFor(target).features;
|
|
165
|
+
for (const key of FEATURE_KEYS) {
|
|
166
|
+
if (!bundleProvides(bundle, key))
|
|
167
|
+
continue;
|
|
168
|
+
if (features[key].profiles.includes(profile))
|
|
169
|
+
continue;
|
|
170
|
+
diagnostics.push(diagnostic("AB803", `Bundle feature '${key}' does not render in the ${profile} profile`, "unsupported", {
|
|
171
|
+
target,
|
|
172
|
+
profile,
|
|
173
|
+
remediation: `Install a scope that uses a profile '${key}' reaches, or drop the component.`,
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
return diagnostics;
|
|
177
|
+
}
|
|
178
|
+
function inventoryOf(artifacts) {
|
|
179
|
+
return artifacts
|
|
180
|
+
.filter((artifact) => artifact.path !== INSTALL_MANIFEST)
|
|
181
|
+
.map((artifact) => ({
|
|
182
|
+
path: artifact.path,
|
|
183
|
+
mode: octal(artifact.mode),
|
|
184
|
+
sha256: sha256(artifact.content),
|
|
185
|
+
}))
|
|
186
|
+
.sort(byPath);
|
|
187
|
+
}
|
|
188
|
+
function parseManifest(value) {
|
|
189
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
190
|
+
return null;
|
|
191
|
+
const doc = value;
|
|
192
|
+
const generator = doc.generator;
|
|
193
|
+
const bundle = doc.bundle;
|
|
194
|
+
const files = doc.files;
|
|
195
|
+
if (!generator ||
|
|
196
|
+
typeof generator.name !== "string" ||
|
|
197
|
+
typeof generator.version !== "string" ||
|
|
198
|
+
!bundle ||
|
|
199
|
+
typeof bundle.name !== "string" ||
|
|
200
|
+
typeof bundle.version !== "string" ||
|
|
201
|
+
typeof doc.target !== "string" ||
|
|
202
|
+
typeof doc.profile !== "string" ||
|
|
203
|
+
typeof doc.scope !== "string" ||
|
|
204
|
+
typeof doc.layout !== "string" ||
|
|
205
|
+
typeof doc.mode !== "string" ||
|
|
206
|
+
typeof doc.destination !== "string" ||
|
|
207
|
+
!Array.isArray(files))
|
|
208
|
+
return null;
|
|
209
|
+
const inventory = [];
|
|
210
|
+
for (const entry of files) {
|
|
211
|
+
if (!entry || typeof entry !== "object")
|
|
212
|
+
return null;
|
|
213
|
+
const row = entry;
|
|
214
|
+
if (typeof row.path !== "string" ||
|
|
215
|
+
typeof row.mode !== "string" ||
|
|
216
|
+
typeof row.sha256 !== "string")
|
|
217
|
+
return null;
|
|
218
|
+
inventory.push({ path: row.path, mode: row.mode, sha256: row.sha256 });
|
|
219
|
+
}
|
|
220
|
+
const registration = doc.registration;
|
|
221
|
+
const keys = Array.isArray(registration?.pluginKeys)
|
|
222
|
+
? registration.pluginKeys.filter((key) => typeof key === "string")
|
|
223
|
+
: undefined;
|
|
224
|
+
const parsedRegistration = registration &&
|
|
225
|
+
typeof registration.file === "string" &&
|
|
226
|
+
typeof registration.marketplaceKey === "string" &&
|
|
227
|
+
(typeof registration.pluginKey === "string" || keys !== undefined)
|
|
228
|
+
? {
|
|
229
|
+
file: registration.file,
|
|
230
|
+
marketplaceKey: registration.marketplaceKey,
|
|
231
|
+
...(typeof registration.pluginKey === "string"
|
|
232
|
+
? { pluginKey: registration.pluginKey }
|
|
233
|
+
: {}),
|
|
234
|
+
...(keys ? { pluginKeys: keys } : {}),
|
|
235
|
+
}
|
|
236
|
+
: undefined;
|
|
237
|
+
const collection = doc.collection;
|
|
238
|
+
const plugins = collection && Array.isArray(collection.plugins)
|
|
239
|
+
? collection.plugins.flatMap((entry) => {
|
|
240
|
+
const row = entry;
|
|
241
|
+
return row && typeof row.name === "string" && typeof row.version === "string"
|
|
242
|
+
? [{ name: row.name, version: row.version }]
|
|
243
|
+
: [];
|
|
244
|
+
})
|
|
245
|
+
: undefined;
|
|
246
|
+
return {
|
|
247
|
+
generator: { name: generator.name, version: generator.version },
|
|
248
|
+
...(doc.kind === "collection" ? { kind: "collection" } : {}),
|
|
249
|
+
bundle: { name: bundle.name, version: bundle.version },
|
|
250
|
+
...(plugins ? { collection: { plugins } } : {}),
|
|
251
|
+
target: doc.target,
|
|
252
|
+
profile: doc.profile,
|
|
253
|
+
scope: doc.scope,
|
|
254
|
+
layout: doc.layout,
|
|
255
|
+
mode: doc.mode,
|
|
256
|
+
destination: doc.destination,
|
|
257
|
+
files: inventory,
|
|
258
|
+
...(typeof doc.materialized === "string" ? { materialized: doc.materialized } : {}),
|
|
259
|
+
...(parsedRegistration ? { registration: parsedRegistration } : {}),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
export function readInstallManifest(destination) {
|
|
263
|
+
// Two manifests in one destination is the "two matches is an error rather than
|
|
264
|
+
// a guess" rule again: only a hand edit produces it, and picking one would
|
|
265
|
+
// silently orphan the other install's file list.
|
|
266
|
+
if (existsAt(path.join(destination, INSTALL_MANIFEST)) &&
|
|
267
|
+
existsAt(path.join(destination, LEGACY_INSTALL_MANIFEST)))
|
|
268
|
+
return "malformed";
|
|
269
|
+
const file = installManifestIn(destination);
|
|
270
|
+
if (!file)
|
|
271
|
+
return "missing";
|
|
272
|
+
try {
|
|
273
|
+
const parsed = parseManifest(JSON.parse(fs.readFileSync(file, "utf8")));
|
|
274
|
+
return parsed ?? "malformed";
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
return "malformed";
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
export function resolveInstallDestination(target, scope, name, options = {}) {
|
|
281
|
+
const location = locationFor(target, scope);
|
|
282
|
+
if (!location)
|
|
283
|
+
return error("AB800", `No recorded install location for ${target} ${scope} scope`, {
|
|
284
|
+
target,
|
|
285
|
+
remediation: scope === "user" && target === "codex"
|
|
286
|
+
? "Codex has no user-scope install; use --scope project, or pick another target."
|
|
287
|
+
: "Use a target and scope the profile declares, or pass --into only after one exists.",
|
|
288
|
+
});
|
|
289
|
+
const locationRoot = options.into
|
|
290
|
+
? path.resolve(options.into)
|
|
291
|
+
: expandInstallRoot(location.root, options);
|
|
292
|
+
const destination = location.layout === "merge" ? locationRoot : path.join(locationRoot, name);
|
|
293
|
+
return { location, locationRoot, destination };
|
|
294
|
+
}
|
|
295
|
+
function occupied(destination, layout, artifacts, prior, bundleName) {
|
|
296
|
+
if (layout === "merge") {
|
|
297
|
+
if (prior !== "missing" && prior !== "malformed" && prior.bundle.name !== bundleName)
|
|
298
|
+
return true;
|
|
299
|
+
const owned = prior !== "missing" && prior !== "malformed" && prior.bundle.name === bundleName
|
|
300
|
+
? new Set(prior.files.map((file) => file.path))
|
|
301
|
+
: new Set();
|
|
302
|
+
return artifacts.some((artifact) => {
|
|
303
|
+
if (artifact.path === INSTALL_MANIFEST)
|
|
304
|
+
return false;
|
|
305
|
+
if (owned.has(artifact.path))
|
|
306
|
+
return false;
|
|
307
|
+
return existsAt(path.join(destination, artifact.path));
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (!existsAt(destination))
|
|
311
|
+
return false;
|
|
312
|
+
if (prior !== "missing" && prior !== "malformed" && prior.bundle.name === bundleName)
|
|
313
|
+
return false;
|
|
314
|
+
const listing = fs.lstatSync(destination);
|
|
315
|
+
if (listing.isDirectory() && fs.readdirSync(destination).length === 0)
|
|
316
|
+
return false;
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
function writeJsonAtomically(file, value) {
|
|
320
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
321
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
322
|
+
fs.writeFileSync(temporary, JSON.stringify(value, null, 2) + "\n", { mode: 0o644 });
|
|
323
|
+
fs.renameSync(temporary, file);
|
|
324
|
+
}
|
|
325
|
+
function readJsonObject(file) {
|
|
326
|
+
if (!existsAt(file))
|
|
327
|
+
return {};
|
|
328
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
329
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
330
|
+
throw new Error(`Activation file is not a JSON object: ${file}`);
|
|
331
|
+
return parsed;
|
|
332
|
+
}
|
|
333
|
+
function applyRegistration(settings, destination) {
|
|
334
|
+
const current = readJsonObject(settings.file);
|
|
335
|
+
const extra = {
|
|
336
|
+
...(current.extraKnownMarketplaces ?? {}),
|
|
337
|
+
};
|
|
338
|
+
extra[settings.marketplaceKey] = {
|
|
339
|
+
source: { source: "directory", path: destination },
|
|
340
|
+
};
|
|
341
|
+
const enabled = {
|
|
342
|
+
...(current.enabledPlugins ?? {}),
|
|
343
|
+
};
|
|
344
|
+
for (const key of registeredPluginKeys(settings))
|
|
345
|
+
enabled[key] = true;
|
|
346
|
+
writeJsonAtomically(settings.file, {
|
|
347
|
+
...current,
|
|
348
|
+
extraKnownMarketplaces: extra,
|
|
349
|
+
enabledPlugins: enabled,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function revertRegistration(registration, destination) {
|
|
353
|
+
if (!existsAt(registration.file))
|
|
354
|
+
return;
|
|
355
|
+
const current = readJsonObject(registration.file);
|
|
356
|
+
const extra = {
|
|
357
|
+
...(current.extraKnownMarketplaces ?? {}),
|
|
358
|
+
};
|
|
359
|
+
const listed = extra[registration.marketplaceKey];
|
|
360
|
+
if (listed?.source?.path === destination)
|
|
361
|
+
delete extra[registration.marketplaceKey];
|
|
362
|
+
const enabled = {
|
|
363
|
+
...(current.enabledPlugins ?? {}),
|
|
364
|
+
};
|
|
365
|
+
for (const key of registeredPluginKeys(registration))
|
|
366
|
+
delete enabled[key];
|
|
367
|
+
writeJsonAtomically(registration.file, {
|
|
368
|
+
...current,
|
|
369
|
+
extraKnownMarketplaces: extra,
|
|
370
|
+
enabledPlugins: enabled,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
function registrationCurrent(settings, destination) {
|
|
374
|
+
if (!existsAt(settings.file))
|
|
375
|
+
return false;
|
|
376
|
+
try {
|
|
377
|
+
const current = readJsonObject(settings.file);
|
|
378
|
+
const extra = current.extraKnownMarketplaces;
|
|
379
|
+
const enabled = current.enabledPlugins;
|
|
380
|
+
return (extra?.[settings.marketplaceKey]?.source?.path === destination &&
|
|
381
|
+
registeredPluginKeys(settings).every((key) => enabled?.[key] === true));
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function pruneEmptyAncestors(root, relative) {
|
|
388
|
+
let current = path.dirname(path.join(root, relative));
|
|
389
|
+
const stop = path.resolve(root);
|
|
390
|
+
while (current !== stop && isInside(stop, current)) {
|
|
391
|
+
if (!existsAt(current) || !fs.statSync(current).isDirectory())
|
|
392
|
+
break;
|
|
393
|
+
if (fs.readdirSync(current).length)
|
|
394
|
+
break;
|
|
395
|
+
fs.rmdirSync(current);
|
|
396
|
+
current = path.dirname(current);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function payloadMatches(destination, artifacts) {
|
|
400
|
+
for (const artifact of artifacts) {
|
|
401
|
+
if (artifact.path === INSTALL_MANIFEST) {
|
|
402
|
+
if (!existsAt(path.join(destination, artifact.path)))
|
|
403
|
+
return false;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
const file = path.join(destination, artifact.path);
|
|
407
|
+
if (!existsAt(file))
|
|
408
|
+
return false;
|
|
409
|
+
if (!fs.readFileSync(file).equals(artifact.content))
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
export function installIsCurrent(plan) {
|
|
415
|
+
if (!payloadMatches(plan.destination, plan.artifacts))
|
|
416
|
+
return false;
|
|
417
|
+
if (plan.register && plan.settings && !registrationCurrent(plan.settings, plan.destination))
|
|
418
|
+
return false;
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
function buildPayload(bundle, target, profile, layout) {
|
|
422
|
+
const rendered = renderBundle(bundle, [target], [profile]);
|
|
423
|
+
const prefix = `${target}/${profile}`;
|
|
424
|
+
const diagnostics = [...rendered.diagnostics];
|
|
425
|
+
let artifacts = relocate(rendered.artifacts, prefix);
|
|
426
|
+
if (layout === "marketplace") {
|
|
427
|
+
const catalogs = buildCatalogs(bundle, [target], [profile], "local");
|
|
428
|
+
diagnostics.push(...catalogs.diagnostics);
|
|
429
|
+
const relocated = retargetCatalog(relocate(catalogs.artifacts, prefix), profileFor(target).marketplace?.entriesKey ?? "plugins", "./");
|
|
430
|
+
artifacts = [...artifacts, ...relocated].sort(byPath);
|
|
431
|
+
diagnostics.push(...checkAssets(bundle, [target], artifacts));
|
|
432
|
+
}
|
|
433
|
+
diagnostics.push(...checkExecutables(artifacts), ...checkCaseCollisions(artifacts), ...checkPinning(bundle), ...featureDiagnostics(bundle, target, profile));
|
|
434
|
+
return { artifacts, diagnostics };
|
|
435
|
+
}
|
|
436
|
+
function manifestArtifact(manifest) {
|
|
437
|
+
return {
|
|
438
|
+
path: INSTALL_MANIFEST,
|
|
439
|
+
content: Buffer.from(JSON.stringify(manifest, null, 2) + "\n"),
|
|
440
|
+
mode: 0o644,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Plans an install: renders and packages in memory, resolves the destination
|
|
445
|
+
* from profile data, and records AB8xx findings. Nothing is written.
|
|
446
|
+
*/
|
|
447
|
+
export function planInstall(bundle, target, options) {
|
|
448
|
+
const scope = resolveScope(options.scope, "user");
|
|
449
|
+
const resolved = resolveInstallDestination(target, scope, bundle.name, options);
|
|
450
|
+
const diagnostics = [];
|
|
451
|
+
if (!isResolved(resolved)) {
|
|
452
|
+
return {
|
|
453
|
+
bundle,
|
|
454
|
+
target,
|
|
455
|
+
profile: "plugin",
|
|
456
|
+
scope,
|
|
457
|
+
layout: "plugin-dir",
|
|
458
|
+
mode: options.link ? "link" : "copy",
|
|
459
|
+
destination: "",
|
|
460
|
+
artifacts: [],
|
|
461
|
+
manifest: {
|
|
462
|
+
generator: { name: packageName, version: packageVersion },
|
|
463
|
+
bundle: { name: bundle.name, version: bundle.version },
|
|
464
|
+
target,
|
|
465
|
+
profile: "plugin",
|
|
466
|
+
scope,
|
|
467
|
+
layout: "plugin-dir",
|
|
468
|
+
mode: "copy",
|
|
469
|
+
destination: "",
|
|
470
|
+
files: [],
|
|
471
|
+
},
|
|
472
|
+
diagnostics: [resolved],
|
|
473
|
+
register: Boolean(options.register),
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
const { location, destination } = resolved;
|
|
477
|
+
if (options.profile && options.profile !== "both" && options.profile !== location.profile)
|
|
478
|
+
throw new Error(`Install location for ${target}/${scope} uses the ${location.profile} profile`);
|
|
479
|
+
if (options.profile === "both")
|
|
480
|
+
throw new Error("Install uses one profile per destination; pass plugin or project, or omit --profile");
|
|
481
|
+
const mode = options.link ? "link" : "copy";
|
|
482
|
+
const built = buildPayload(bundle, target, location.profile, location.layout);
|
|
483
|
+
diagnostics.push(...built.diagnostics);
|
|
484
|
+
for (const artifact of built.artifacts)
|
|
485
|
+
if (pathEscapesRoot(destination, artifact.path))
|
|
486
|
+
diagnostics.push(error("AB804", `Destination path escapes the install root: ${artifact.path}`, {
|
|
487
|
+
path: artifact.path,
|
|
488
|
+
target,
|
|
489
|
+
profile: location.profile,
|
|
490
|
+
}));
|
|
491
|
+
const prior = existsAt(destination) ? readInstallManifest(destination) : "missing";
|
|
492
|
+
if (occupied(destination, location.layout, built.artifacts, prior, bundle.name)) {
|
|
493
|
+
if (!options.force)
|
|
494
|
+
diagnostics.push(error("AB801", `Destination is occupied by something that is not a prior install of '${bundle.name}'`, {
|
|
495
|
+
path: destination,
|
|
496
|
+
target,
|
|
497
|
+
remediation: "Pass --force to replace it, or uninstall the occupant first.",
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
else if (prior !== "missing" && prior !== "malformed" && prior.bundle.name === bundle.name)
|
|
501
|
+
diagnostics.push(diagnostic("AB802", `Replacing existing install of ${prior.bundle.name} ${prior.bundle.version} with ${bundle.version}`, "exact", { target, profile: location.profile, path: destination }));
|
|
502
|
+
const settingsFile = location.activation
|
|
503
|
+
? expandInstallRoot(location.activation.file, options)
|
|
504
|
+
: undefined;
|
|
505
|
+
const settings = location.layout === "marketplace" && settingsFile
|
|
506
|
+
? {
|
|
507
|
+
file: settingsFile,
|
|
508
|
+
marketplaceKey: bundle.name,
|
|
509
|
+
pluginKey: `${bundle.name}@${bundle.name}`,
|
|
510
|
+
}
|
|
511
|
+
: undefined;
|
|
512
|
+
const register = Boolean(options.register) && Boolean(settings);
|
|
513
|
+
if (settings && !options.register)
|
|
514
|
+
diagnostics.push(diagnostic("AB805", `Host activation edit required but --register was not given. Add extraKnownMarketplaces.${bundle.name} (directory ${destination}) and enabledPlugins["${bundle.name}@${bundle.name}"] to ${settingsFile}.`, "unsupported", {
|
|
515
|
+
target,
|
|
516
|
+
path: settingsFile,
|
|
517
|
+
remediation: "Re-run with --register, or apply the edit yourself.",
|
|
518
|
+
}));
|
|
519
|
+
if (mode === "link")
|
|
520
|
+
diagnostics.push(diagnostic("AB807", "--link is in use; edits to the materialized tree are live and the host may not follow symlinks", "exact", { target, profile: location.profile, path: destination }));
|
|
521
|
+
const materialized = mode === "link" ? path.join(bundle.root, INSTALL_CACHE, target, location.profile) : undefined;
|
|
522
|
+
const manifest = {
|
|
523
|
+
generator: { name: packageName, version: packageVersion },
|
|
524
|
+
bundle: { name: bundle.name, version: bundle.version },
|
|
525
|
+
target,
|
|
526
|
+
profile: location.profile,
|
|
527
|
+
scope,
|
|
528
|
+
layout: location.layout,
|
|
529
|
+
mode,
|
|
530
|
+
destination,
|
|
531
|
+
files: inventoryOf(built.artifacts),
|
|
532
|
+
...(materialized ? { materialized } : {}),
|
|
533
|
+
...(register && settings ? { registration: settings } : {}),
|
|
534
|
+
};
|
|
535
|
+
const artifacts = [...built.artifacts, manifestArtifact(manifest)].sort(byPath);
|
|
536
|
+
return {
|
|
537
|
+
bundle,
|
|
538
|
+
target,
|
|
539
|
+
profile: location.profile,
|
|
540
|
+
scope,
|
|
541
|
+
layout: location.layout,
|
|
542
|
+
mode,
|
|
543
|
+
destination,
|
|
544
|
+
artifacts,
|
|
545
|
+
manifest,
|
|
546
|
+
diagnostics,
|
|
547
|
+
register,
|
|
548
|
+
settings,
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Plans an install of a whole collection into one host marketplace.
|
|
553
|
+
*
|
|
554
|
+
* The difference from {@link planInstall} is entirely in the registration:
|
|
555
|
+
* a bundle install keys `extraKnownMarketplaces` on the bundle name and enables
|
|
556
|
+
* one plugin, so installing five bundles yields five marketplaces. A collection
|
|
557
|
+
* keys it on the collection name once and enables every plugin under it, which
|
|
558
|
+
* is the shape a host actually offers to a user.
|
|
559
|
+
*
|
|
560
|
+
* Everything else — the occupied check, the manifest, the inventory, uninstall —
|
|
561
|
+
* is shared, because the manifest's `bundle` field records the installed unit's
|
|
562
|
+
* identity and a collection simply puts its own there.
|
|
563
|
+
*/
|
|
564
|
+
export function planCollectionInstall(collection, options = {}) {
|
|
565
|
+
const scope = resolveScope(options.scope);
|
|
566
|
+
const diagnostics = [];
|
|
567
|
+
const resolved = resolveInstallDestination(collection.target, scope, collection.name, options);
|
|
568
|
+
if ("code" in resolved)
|
|
569
|
+
return {
|
|
570
|
+
target: collection.target,
|
|
571
|
+
profile: "plugin",
|
|
572
|
+
scope,
|
|
573
|
+
layout: "plugin-dir",
|
|
574
|
+
mode: "copy",
|
|
575
|
+
destination: "",
|
|
576
|
+
artifacts: [],
|
|
577
|
+
manifest: {
|
|
578
|
+
generator: { name: packageName, version: packageVersion },
|
|
579
|
+
kind: "collection",
|
|
580
|
+
bundle: { name: collection.name, version: collection.version },
|
|
581
|
+
collection: { plugins: collection.plugins },
|
|
582
|
+
target: collection.target,
|
|
583
|
+
profile: "plugin",
|
|
584
|
+
scope,
|
|
585
|
+
layout: "plugin-dir",
|
|
586
|
+
mode: "copy",
|
|
587
|
+
destination: "",
|
|
588
|
+
files: [],
|
|
589
|
+
},
|
|
590
|
+
diagnostics: [resolved],
|
|
591
|
+
register: Boolean(options.register),
|
|
592
|
+
};
|
|
593
|
+
const { location, destination } = resolved;
|
|
594
|
+
if (location.profile !== "plugin")
|
|
595
|
+
throw new Error(`Install location for ${collection.target}/${scope} uses the ${location.profile} profile; a collection is plugin-only`);
|
|
596
|
+
const mode = options.link ? "link" : "copy";
|
|
597
|
+
for (const artifact of collection.artifacts)
|
|
598
|
+
if (pathEscapesRoot(destination, artifact.path))
|
|
599
|
+
diagnostics.push(error("AB804", `Destination path escapes the install root: ${artifact.path}`, {
|
|
600
|
+
path: artifact.path,
|
|
601
|
+
target: collection.target,
|
|
602
|
+
profile: "plugin",
|
|
603
|
+
}));
|
|
604
|
+
const prior = existsAt(destination) ? readInstallManifest(destination) : "missing";
|
|
605
|
+
if (occupied(destination, location.layout, collection.artifacts, prior, collection.name)) {
|
|
606
|
+
if (!options.force)
|
|
607
|
+
diagnostics.push(error("AB801", `Destination is occupied by something that is not a prior install of '${collection.name}'`, {
|
|
608
|
+
path: destination,
|
|
609
|
+
target: collection.target,
|
|
610
|
+
remediation: "Pass --force to replace it, or uninstall the occupant first.",
|
|
611
|
+
}));
|
|
612
|
+
}
|
|
613
|
+
else if (prior !== "missing" && prior !== "malformed" && prior.bundle.name === collection.name)
|
|
614
|
+
diagnostics.push(diagnostic("AB802", `Replacing existing install of ${prior.bundle.name} ${prior.bundle.version} with ${collection.version}`, "exact", { target: collection.target, profile: "plugin", path: destination }));
|
|
615
|
+
const settingsFile = location.activation
|
|
616
|
+
? expandInstallRoot(location.activation.file, options)
|
|
617
|
+
: undefined;
|
|
618
|
+
const pluginKeys = collection.plugins.map((plugin) => `${plugin.name}@${collection.name}`);
|
|
619
|
+
const settings = location.layout === "marketplace" && settingsFile
|
|
620
|
+
? { file: settingsFile, marketplaceKey: collection.name, pluginKeys }
|
|
621
|
+
: undefined;
|
|
622
|
+
const register = Boolean(options.register) && Boolean(settings);
|
|
623
|
+
if (settings && !options.register)
|
|
624
|
+
diagnostics.push(diagnostic("AB805", `Host activation edit required but --register was not given. Add extraKnownMarketplaces.${collection.name} (directory ${destination}) and enabledPlugins for ${pluginKeys.join(", ")} to ${settingsFile}.`, "unsupported", {
|
|
625
|
+
target: collection.target,
|
|
626
|
+
path: settingsFile,
|
|
627
|
+
remediation: "Re-run with --register, or apply the edit yourself.",
|
|
628
|
+
}));
|
|
629
|
+
if (mode === "link")
|
|
630
|
+
diagnostics.push(diagnostic("AB807", "--link is in use; edits to the materialized tree are live and the host may not follow symlinks", "exact", { target: collection.target, profile: "plugin", path: destination }));
|
|
631
|
+
const materialized = mode === "link" ? options.materializeInto : undefined;
|
|
632
|
+
if (mode === "link" && !materialized)
|
|
633
|
+
throw new Error("A --link collection install needs a materialization directory");
|
|
634
|
+
const manifest = {
|
|
635
|
+
generator: { name: packageName, version: packageVersion },
|
|
636
|
+
kind: "collection",
|
|
637
|
+
bundle: { name: collection.name, version: collection.version },
|
|
638
|
+
collection: { plugins: collection.plugins },
|
|
639
|
+
target: collection.target,
|
|
640
|
+
profile: "plugin",
|
|
641
|
+
scope,
|
|
642
|
+
layout: location.layout,
|
|
643
|
+
mode,
|
|
644
|
+
destination,
|
|
645
|
+
files: inventoryOf(collection.artifacts),
|
|
646
|
+
...(materialized ? { materialized } : {}),
|
|
647
|
+
...(register && settings ? { registration: settings } : {}),
|
|
648
|
+
};
|
|
649
|
+
return {
|
|
650
|
+
target: collection.target,
|
|
651
|
+
profile: "plugin",
|
|
652
|
+
scope,
|
|
653
|
+
layout: location.layout,
|
|
654
|
+
mode,
|
|
655
|
+
destination,
|
|
656
|
+
artifacts: [...collection.artifacts, manifestArtifact(manifest)].sort(byPath),
|
|
657
|
+
manifest,
|
|
658
|
+
diagnostics,
|
|
659
|
+
register,
|
|
660
|
+
settings,
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function writeCopy(plan) {
|
|
664
|
+
const payload = plan.artifacts;
|
|
665
|
+
if (plan.layout === "merge")
|
|
666
|
+
writeArtifactsAtomically(plan.destination, payload, {
|
|
667
|
+
managedRoots: [],
|
|
668
|
+
looseFiles: payload.map((artifact) => artifact.path),
|
|
669
|
+
force: true,
|
|
670
|
+
});
|
|
671
|
+
else
|
|
672
|
+
writeArtifactsAtomically(plan.destination, payload, { managedRoots: ["."], force: true });
|
|
673
|
+
}
|
|
674
|
+
function writeLink(plan) {
|
|
675
|
+
const materialized = plan.manifest.materialized;
|
|
676
|
+
if (!materialized)
|
|
677
|
+
throw new Error("Link install is missing a materialized tree");
|
|
678
|
+
writeArtifactsAtomically(materialized, plan.artifacts, { managedRoots: ["."], force: true });
|
|
679
|
+
if (plan.layout === "merge") {
|
|
680
|
+
for (const artifact of plan.artifacts) {
|
|
681
|
+
if (artifact.path === INSTALL_MANIFEST)
|
|
682
|
+
continue;
|
|
683
|
+
placeSymlink(path.join(plan.destination, artifact.path), path.join(materialized, artifact.path));
|
|
684
|
+
}
|
|
685
|
+
const manifest = plan.artifacts.find((artifact) => artifact.path === INSTALL_MANIFEST);
|
|
686
|
+
if (manifest)
|
|
687
|
+
writeArtifactsAtomically(plan.destination, [manifest], {
|
|
688
|
+
managedRoots: [],
|
|
689
|
+
looseFiles: [INSTALL_MANIFEST],
|
|
690
|
+
force: true,
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
else
|
|
694
|
+
placeSymlink(plan.destination, materialized);
|
|
695
|
+
}
|
|
696
|
+
function retirePrior(plan) {
|
|
697
|
+
if (!existsAt(plan.destination))
|
|
698
|
+
return;
|
|
699
|
+
const prior = readInstallManifest(plan.destination);
|
|
700
|
+
if (prior === "missing" || prior === "malformed")
|
|
701
|
+
return;
|
|
702
|
+
const next = new Set(plan.manifest.files.map((file) => file.path));
|
|
703
|
+
if (prior.bundle.name !== plan.manifest.bundle.name) {
|
|
704
|
+
commitUninstall({
|
|
705
|
+
name: prior.bundle.name,
|
|
706
|
+
target: prior.target,
|
|
707
|
+
destination: plan.destination,
|
|
708
|
+
manifest: prior,
|
|
709
|
+
diagnostics: [],
|
|
710
|
+
missing: false,
|
|
711
|
+
});
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
for (const file of prior.files) {
|
|
715
|
+
if (next.has(file.path))
|
|
716
|
+
continue;
|
|
717
|
+
removePath(path.join(plan.destination, file.path));
|
|
718
|
+
pruneEmptyAncestors(plan.destination, file.path);
|
|
719
|
+
}
|
|
720
|
+
if (prior.materialized && prior.materialized !== plan.manifest.materialized)
|
|
721
|
+
removePath(prior.materialized);
|
|
722
|
+
if (prior.registration && !plan.manifest.registration)
|
|
723
|
+
revertRegistration(prior.registration, plan.destination);
|
|
724
|
+
}
|
|
725
|
+
/** Writes a planned install. Caller must have already decided the run is not blocked. */
|
|
726
|
+
export function commitInstall(plan) {
|
|
727
|
+
retirePrior(plan);
|
|
728
|
+
if (plan.mode === "link")
|
|
729
|
+
writeLink(plan);
|
|
730
|
+
else
|
|
731
|
+
writeCopy(plan);
|
|
732
|
+
if (plan.register && plan.settings)
|
|
733
|
+
applyRegistration(plan.settings, plan.destination);
|
|
734
|
+
}
|
|
735
|
+
export function planToEntry(plan) {
|
|
736
|
+
return toEntry(plan.manifest);
|
|
737
|
+
}
|
|
738
|
+
function candidatesFor(target, name, scopes, options) {
|
|
739
|
+
const found = [];
|
|
740
|
+
for (const scope of scopes) {
|
|
741
|
+
const resolved = resolveInstallDestination(target, scope, name, options);
|
|
742
|
+
if (!isResolved(resolved))
|
|
743
|
+
continue;
|
|
744
|
+
found.push({ scope, destination: resolved.destination });
|
|
745
|
+
}
|
|
746
|
+
return found;
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Locates a named install. `--scope` is optional: when omitted, both scopes
|
|
750
|
+
* are searched and two matches is an error rather than a guess.
|
|
751
|
+
*/
|
|
752
|
+
export function planUninstall(name, target, options) {
|
|
753
|
+
const scopes = options.scope
|
|
754
|
+
? [resolveScope(options.scope)]
|
|
755
|
+
: [...INSTALL_SCOPES];
|
|
756
|
+
const diagnostics = [];
|
|
757
|
+
const matches = [];
|
|
758
|
+
for (const candidate of candidatesFor(target, name, scopes, options)) {
|
|
759
|
+
const read = existsAt(candidate.destination)
|
|
760
|
+
? readInstallManifest(candidate.destination)
|
|
761
|
+
: "missing";
|
|
762
|
+
if (read === "malformed")
|
|
763
|
+
diagnostics.push(error("AB806", `Install manifest missing or malformed at ${candidate.destination}`, {
|
|
764
|
+
path: installManifestIn(candidate.destination) ??
|
|
765
|
+
path.join(candidate.destination, INSTALL_MANIFEST),
|
|
766
|
+
target,
|
|
767
|
+
remediation: "Inspect the destination; uninstall refuses to guess.",
|
|
768
|
+
}));
|
|
769
|
+
else if (read !== "missing" && read.bundle.name === name)
|
|
770
|
+
matches.push({ ...candidate, manifest: read });
|
|
771
|
+
}
|
|
772
|
+
if (diagnostics.length)
|
|
773
|
+
return { name, target, destination: "", manifest: null, diagnostics, missing: false };
|
|
774
|
+
if (matches.length > 1)
|
|
775
|
+
throw new Error(`Install '${name}' exists in more than one scope for ${target}; pass --scope user or --scope project.`);
|
|
776
|
+
if (!matches.length) {
|
|
777
|
+
if (scopes.length === 1) {
|
|
778
|
+
const resolved = resolveInstallDestination(target, scopes[0], name, options);
|
|
779
|
+
if (!isResolved(resolved))
|
|
780
|
+
return {
|
|
781
|
+
name,
|
|
782
|
+
target,
|
|
783
|
+
destination: "",
|
|
784
|
+
manifest: null,
|
|
785
|
+
diagnostics: [resolved],
|
|
786
|
+
missing: false,
|
|
787
|
+
};
|
|
788
|
+
return {
|
|
789
|
+
name,
|
|
790
|
+
target,
|
|
791
|
+
destination: resolved.destination,
|
|
792
|
+
manifest: null,
|
|
793
|
+
diagnostics: [],
|
|
794
|
+
missing: true,
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
return {
|
|
798
|
+
name,
|
|
799
|
+
target,
|
|
800
|
+
destination: "",
|
|
801
|
+
manifest: null,
|
|
802
|
+
diagnostics: [],
|
|
803
|
+
missing: true,
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
name,
|
|
808
|
+
target,
|
|
809
|
+
destination: matches[0].destination,
|
|
810
|
+
manifest: matches[0].manifest,
|
|
811
|
+
diagnostics: [],
|
|
812
|
+
missing: false,
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
export function missingInstallDiagnostic(name, target, destination) {
|
|
816
|
+
return error("AB806", destination
|
|
817
|
+
? `Install manifest missing or malformed at ${destination}`
|
|
818
|
+
: `No install named '${name}' for ${target}`, {
|
|
819
|
+
...(destination
|
|
820
|
+
? { path: installManifestIn(destination) ?? path.join(destination, INSTALL_MANIFEST) }
|
|
821
|
+
: {}),
|
|
822
|
+
target,
|
|
823
|
+
remediation: "Nothing to uninstall, or the destination is not a Cairn install.",
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
function removePath(file) {
|
|
827
|
+
if (existsAt(file))
|
|
828
|
+
fs.rmSync(file, { recursive: true, force: true });
|
|
829
|
+
}
|
|
830
|
+
export function commitUninstall(plan) {
|
|
831
|
+
const manifest = plan.manifest;
|
|
832
|
+
if (!manifest)
|
|
833
|
+
return;
|
|
834
|
+
const destination = plan.destination;
|
|
835
|
+
const listing = fs.lstatSync(destination, { throwIfNoEntry: false });
|
|
836
|
+
if (listing?.isSymbolicLink())
|
|
837
|
+
removePath(destination);
|
|
838
|
+
else {
|
|
839
|
+
for (const file of manifest.files) {
|
|
840
|
+
removePath(path.join(destination, file.path));
|
|
841
|
+
pruneEmptyAncestors(destination, file.path);
|
|
842
|
+
}
|
|
843
|
+
const manifestFile = installManifestIn(destination);
|
|
844
|
+
if (manifestFile)
|
|
845
|
+
removePath(manifestFile);
|
|
846
|
+
if (manifest.layout !== "merge" &&
|
|
847
|
+
existsAt(destination) &&
|
|
848
|
+
fs.statSync(destination).isDirectory() &&
|
|
849
|
+
fs.readdirSync(destination).length === 0)
|
|
850
|
+
fs.rmdirSync(destination);
|
|
851
|
+
}
|
|
852
|
+
if (manifest.materialized)
|
|
853
|
+
removePath(manifest.materialized);
|
|
854
|
+
if (manifest.registration)
|
|
855
|
+
revertRegistration(manifest.registration, destination);
|
|
856
|
+
}
|
|
857
|
+
function scanRoot(target, scope, location, locationRoot) {
|
|
858
|
+
const entries = [];
|
|
859
|
+
if (location.layout === "merge") {
|
|
860
|
+
const read = existsAt(locationRoot) ? readInstallManifest(locationRoot) : "missing";
|
|
861
|
+
if (read !== "missing" &&
|
|
862
|
+
read !== "malformed" &&
|
|
863
|
+
read.target === target &&
|
|
864
|
+
read.scope === scope)
|
|
865
|
+
entries.push(toEntry({ ...read, destination: locationRoot }));
|
|
866
|
+
return entries;
|
|
867
|
+
}
|
|
868
|
+
if (!existsAt(locationRoot) || !fs.statSync(locationRoot).isDirectory())
|
|
869
|
+
return entries;
|
|
870
|
+
for (const name of fs.readdirSync(locationRoot).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
871
|
+
const destination = path.join(locationRoot, name);
|
|
872
|
+
const listing = fs.lstatSync(destination);
|
|
873
|
+
if (!listing.isDirectory() && !listing.isSymbolicLink())
|
|
874
|
+
continue;
|
|
875
|
+
const read = readInstallManifest(destination);
|
|
876
|
+
if (read === "missing" || read === "malformed")
|
|
877
|
+
continue;
|
|
878
|
+
if (read.target !== target || read.scope !== scope)
|
|
879
|
+
continue;
|
|
880
|
+
entries.push(toEntry({ ...read, destination }));
|
|
881
|
+
}
|
|
882
|
+
return entries;
|
|
883
|
+
}
|
|
884
|
+
/** Lists installs found at the roots the target profiles declare. */
|
|
885
|
+
export function listInstalled(targets, options = {}) {
|
|
886
|
+
const scopes = options.scope
|
|
887
|
+
? [resolveScope(options.scope)]
|
|
888
|
+
: [...INSTALL_SCOPES];
|
|
889
|
+
const entries = [];
|
|
890
|
+
for (const target of targets) {
|
|
891
|
+
for (const scope of scopes) {
|
|
892
|
+
const location = locationFor(target, scope);
|
|
893
|
+
if (!location)
|
|
894
|
+
continue;
|
|
895
|
+
const locationRoot = options.into
|
|
896
|
+
? path.resolve(options.into)
|
|
897
|
+
: expandInstallRoot(location.root, options);
|
|
898
|
+
entries.push(...scanRoot(target, scope, location, locationRoot));
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return entries.sort((a, b) => {
|
|
902
|
+
const left = `${a.target}/${a.scope}/${a.name}`;
|
|
903
|
+
const right = `${b.target}/${b.scope}/${b.name}`;
|
|
904
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
//# sourceMappingURL=index.js.map
|