@hashicorp/kits 0.1.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/README.md +619 -0
- package/bin/kits.js +8 -0
- package/dist/adapters/base-adapter.d.ts +231 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +703 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/claude-code/detection.d.ts +63 -0
- package/dist/adapters/claude-code/detection.d.ts.map +1 -0
- package/dist/adapters/claude-code/detection.js +154 -0
- package/dist/adapters/claude-code/detection.js.map +1 -0
- package/dist/adapters/claude-code/index.d.ts +178 -0
- package/dist/adapters/claude-code/index.d.ts.map +1 -0
- package/dist/adapters/claude-code/index.js +643 -0
- package/dist/adapters/claude-code/index.js.map +1 -0
- package/dist/adapters/claude-code/installer.d.ts +161 -0
- package/dist/adapters/claude-code/installer.d.ts.map +1 -0
- package/dist/adapters/claude-code/installer.js +413 -0
- package/dist/adapters/claude-code/installer.js.map +1 -0
- package/dist/adapters/claude-code/model-mapping.d.ts +7 -0
- package/dist/adapters/claude-code/model-mapping.d.ts.map +1 -0
- package/dist/adapters/claude-code/model-mapping.js +14 -0
- package/dist/adapters/claude-code/model-mapping.js.map +1 -0
- package/dist/adapters/claude-code/tool-mapping.d.ts +18 -0
- package/dist/adapters/claude-code/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/claude-code/tool-mapping.js +31 -0
- package/dist/adapters/claude-code/tool-mapping.js.map +1 -0
- package/dist/adapters/codex/detection.d.ts +60 -0
- package/dist/adapters/codex/detection.d.ts.map +1 -0
- package/dist/adapters/codex/detection.js +146 -0
- package/dist/adapters/codex/detection.js.map +1 -0
- package/dist/adapters/codex/index.d.ts +167 -0
- package/dist/adapters/codex/index.d.ts.map +1 -0
- package/dist/adapters/codex/index.js +344 -0
- package/dist/adapters/codex/index.js.map +1 -0
- package/dist/adapters/codex/installer.d.ts +147 -0
- package/dist/adapters/codex/installer.d.ts.map +1 -0
- package/dist/adapters/codex/installer.js +229 -0
- package/dist/adapters/codex/installer.js.map +1 -0
- package/dist/adapters/codex/model-mapping.d.ts +7 -0
- package/dist/adapters/codex/model-mapping.d.ts.map +1 -0
- package/dist/adapters/codex/model-mapping.js +14 -0
- package/dist/adapters/codex/model-mapping.js.map +1 -0
- package/dist/adapters/codex/tool-mapping.d.ts +19 -0
- package/dist/adapters/codex/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/codex/tool-mapping.js +32 -0
- package/dist/adapters/codex/tool-mapping.js.map +1 -0
- package/dist/adapters/command-parser.d.ts +72 -0
- package/dist/adapters/command-parser.d.ts.map +1 -0
- package/dist/adapters/command-parser.js +222 -0
- package/dist/adapters/command-parser.js.map +1 -0
- package/dist/adapters/file-operations.d.ts +164 -0
- package/dist/adapters/file-operations.d.ts.map +1 -0
- package/dist/adapters/file-operations.js +526 -0
- package/dist/adapters/file-operations.js.map +1 -0
- package/dist/adapters/gemini-cli/detection.d.ts +57 -0
- package/dist/adapters/gemini-cli/detection.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/detection.js +143 -0
- package/dist/adapters/gemini-cli/detection.js.map +1 -0
- package/dist/adapters/gemini-cli/index.d.ts +182 -0
- package/dist/adapters/gemini-cli/index.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/index.js +598 -0
- package/dist/adapters/gemini-cli/index.js.map +1 -0
- package/dist/adapters/gemini-cli/installer.d.ts +158 -0
- package/dist/adapters/gemini-cli/installer.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/installer.js +457 -0
- package/dist/adapters/gemini-cli/installer.js.map +1 -0
- package/dist/adapters/gemini-cli/model-mapping.d.ts +7 -0
- package/dist/adapters/gemini-cli/model-mapping.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/model-mapping.js +14 -0
- package/dist/adapters/gemini-cli/model-mapping.js.map +1 -0
- package/dist/adapters/gemini-cli/tool-mapping.d.ts +18 -0
- package/dist/adapters/gemini-cli/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/tool-mapping.js +31 -0
- package/dist/adapters/gemini-cli/tool-mapping.js.map +1 -0
- package/dist/adapters/github-copilot/detection.d.ts +58 -0
- package/dist/adapters/github-copilot/detection.d.ts.map +1 -0
- package/dist/adapters/github-copilot/detection.js +144 -0
- package/dist/adapters/github-copilot/detection.js.map +1 -0
- package/dist/adapters/github-copilot/index.d.ts +203 -0
- package/dist/adapters/github-copilot/index.d.ts.map +1 -0
- package/dist/adapters/github-copilot/index.js +595 -0
- package/dist/adapters/github-copilot/index.js.map +1 -0
- package/dist/adapters/github-copilot/installer.d.ts +124 -0
- package/dist/adapters/github-copilot/installer.d.ts.map +1 -0
- package/dist/adapters/github-copilot/installer.js +343 -0
- package/dist/adapters/github-copilot/installer.js.map +1 -0
- package/dist/adapters/github-copilot/model-mapping.d.ts +7 -0
- package/dist/adapters/github-copilot/model-mapping.d.ts.map +1 -0
- package/dist/adapters/github-copilot/model-mapping.js +14 -0
- package/dist/adapters/github-copilot/model-mapping.js.map +1 -0
- package/dist/adapters/github-copilot/tool-mapping.d.ts +18 -0
- package/dist/adapters/github-copilot/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/github-copilot/tool-mapping.js +31 -0
- package/dist/adapters/github-copilot/tool-mapping.js.map +1 -0
- package/dist/adapters/index.d.ts +39 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +76 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/interface.d.ts +9 -0
- package/dist/adapters/interface.d.ts.map +1 -0
- package/dist/adapters/interface.js +8 -0
- package/dist/adapters/interface.js.map +1 -0
- package/dist/adapters/model-templating.d.ts +16 -0
- package/dist/adapters/model-templating.d.ts.map +1 -0
- package/dist/adapters/model-templating.js +52 -0
- package/dist/adapters/model-templating.js.map +1 -0
- package/dist/adapters/opencode/detection.d.ts +57 -0
- package/dist/adapters/opencode/detection.d.ts.map +1 -0
- package/dist/adapters/opencode/detection.js +140 -0
- package/dist/adapters/opencode/detection.js.map +1 -0
- package/dist/adapters/opencode/index.d.ts +168 -0
- package/dist/adapters/opencode/index.d.ts.map +1 -0
- package/dist/adapters/opencode/index.js +494 -0
- package/dist/adapters/opencode/index.js.map +1 -0
- package/dist/adapters/opencode/installer.d.ts +91 -0
- package/dist/adapters/opencode/installer.d.ts.map +1 -0
- package/dist/adapters/opencode/installer.js +290 -0
- package/dist/adapters/opencode/installer.js.map +1 -0
- package/dist/adapters/opencode/model-mapping.d.ts +7 -0
- package/dist/adapters/opencode/model-mapping.d.ts.map +1 -0
- package/dist/adapters/opencode/model-mapping.js +14 -0
- package/dist/adapters/opencode/model-mapping.js.map +1 -0
- package/dist/adapters/opencode/tool-mapping.d.ts +18 -0
- package/dist/adapters/opencode/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/opencode/tool-mapping.js +31 -0
- package/dist/adapters/opencode/tool-mapping.js.map +1 -0
- package/dist/adapters/registry.d.ts +154 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +223 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/skill-frontmatter.d.ts +34 -0
- package/dist/adapters/skill-frontmatter.d.ts.map +1 -0
- package/dist/adapters/skill-frontmatter.js +110 -0
- package/dist/adapters/skill-frontmatter.js.map +1 -0
- package/dist/adapters/subagent-frontmatter.d.ts +22 -0
- package/dist/adapters/subagent-frontmatter.d.ts.map +1 -0
- package/dist/adapters/subagent-frontmatter.js +80 -0
- package/dist/adapters/subagent-frontmatter.js.map +1 -0
- package/dist/adapters/tool-templating.d.ts +162 -0
- package/dist/adapters/tool-templating.d.ts.map +1 -0
- package/dist/adapters/tool-templating.js +273 -0
- package/dist/adapters/tool-templating.js.map +1 -0
- package/dist/adapters/types.d.ts +347 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +33 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +261 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/info.d.ts +20 -0
- package/dist/cli/info.d.ts.map +1 -0
- package/dist/cli/info.js +194 -0
- package/dist/cli/info.js.map +1 -0
- package/dist/cli/install.d.ts +21 -0
- package/dist/cli/install.d.ts.map +1 -0
- package/dist/cli/install.js +1624 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/list.d.ts +19 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +216 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/types.d.ts +246 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +25 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/uninstall.d.ts +20 -0
- package/dist/cli/uninstall.d.ts.map +1 -0
- package/dist/cli/uninstall.js +393 -0
- package/dist/cli/uninstall.js.map +1 -0
- package/dist/cli/upgrade.d.ts +20 -0
- package/dist/cli/upgrade.d.ts.map +1 -0
- package/dist/cli/upgrade.js +372 -0
- package/dist/cli/upgrade.js.map +1 -0
- package/dist/cli/validate.d.ts +14 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +307 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/core/debug.d.ts +23 -0
- package/dist/core/debug.d.ts.map +1 -0
- package/dist/core/debug.js +69 -0
- package/dist/core/debug.js.map +1 -0
- package/dist/core/hook-instance.d.ts +8 -0
- package/dist/core/hook-instance.d.ts.map +1 -0
- package/dist/core/hook-instance.js +62 -0
- package/dist/core/hook-instance.js.map +1 -0
- package/dist/core/mcp-instance.d.ts +13 -0
- package/dist/core/mcp-instance.d.ts.map +1 -0
- package/dist/core/mcp-instance.js +80 -0
- package/dist/core/mcp-instance.js.map +1 -0
- package/dist/core/types.d.ts +461 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +42 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/upgrade-executor.d.ts +70 -0
- package/dist/core/upgrade-executor.d.ts.map +1 -0
- package/dist/core/upgrade-executor.js +368 -0
- package/dist/core/upgrade-executor.js.map +1 -0
- package/dist/discovery/fetcher-registry.d.ts +87 -0
- package/dist/discovery/fetcher-registry.d.ts.map +1 -0
- package/dist/discovery/fetcher-registry.js +119 -0
- package/dist/discovery/fetcher-registry.js.map +1 -0
- package/dist/discovery/git-fetcher.d.ts +61 -0
- package/dist/discovery/git-fetcher.d.ts.map +1 -0
- package/dist/discovery/git-fetcher.js +150 -0
- package/dist/discovery/git-fetcher.js.map +1 -0
- package/dist/discovery/index.d.ts +13 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +15 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/kit-scanner.d.ts +55 -0
- package/dist/discovery/kit-scanner.d.ts.map +1 -0
- package/dist/discovery/kit-scanner.js +305 -0
- package/dist/discovery/kit-scanner.js.map +1 -0
- package/dist/discovery/local-fetcher.d.ts +38 -0
- package/dist/discovery/local-fetcher.d.ts.map +1 -0
- package/dist/discovery/local-fetcher.js +100 -0
- package/dist/discovery/local-fetcher.js.map +1 -0
- package/dist/discovery/source-parser.d.ts +33 -0
- package/dist/discovery/source-parser.d.ts.map +1 -0
- package/dist/discovery/source-parser.js +136 -0
- package/dist/discovery/source-parser.js.map +1 -0
- package/dist/discovery/types.d.ts +145 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +18 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/index.d.ts +79 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +200 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/read.d.ts +32 -0
- package/dist/manifest/read.d.ts.map +1 -0
- package/dist/manifest/read.js +88 -0
- package/dist/manifest/read.js.map +1 -0
- package/dist/manifest/types.d.ts +119 -0
- package/dist/manifest/types.d.ts.map +1 -0
- package/dist/manifest/types.js +44 -0
- package/dist/manifest/types.js.map +1 -0
- package/dist/manifest/upgrade-check.d.ts +72 -0
- package/dist/manifest/upgrade-check.d.ts.map +1 -0
- package/dist/manifest/upgrade-check.js +215 -0
- package/dist/manifest/upgrade-check.js.map +1 -0
- package/dist/manifest/utils.d.ts +35 -0
- package/dist/manifest/utils.d.ts.map +1 -0
- package/dist/manifest/utils.js +57 -0
- package/dist/manifest/utils.js.map +1 -0
- package/dist/manifest/write.d.ts +44 -0
- package/dist/manifest/write.d.ts.map +1 -0
- package/dist/manifest/write.js +77 -0
- package/dist/manifest/write.js.map +1 -0
- package/dist/resolution/env-resolver.d.ts +81 -0
- package/dist/resolution/env-resolver.d.ts.map +1 -0
- package/dist/resolution/env-resolver.js +233 -0
- package/dist/resolution/env-resolver.js.map +1 -0
- package/dist/resolution/index.d.ts +55 -0
- package/dist/resolution/index.d.ts.map +1 -0
- package/dist/resolution/index.js +412 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/multi-kit-resolver.d.ts +43 -0
- package/dist/resolution/multi-kit-resolver.d.ts.map +1 -0
- package/dist/resolution/multi-kit-resolver.js +258 -0
- package/dist/resolution/multi-kit-resolver.js.map +1 -0
- package/dist/resolution/primitive-paths.d.ts +17 -0
- package/dist/resolution/primitive-paths.d.ts.map +1 -0
- package/dist/resolution/primitive-paths.js +59 -0
- package/dist/resolution/primitive-paths.js.map +1 -0
- package/dist/resolution/primitives-registry.d.ts +137 -0
- package/dist/resolution/primitives-registry.d.ts.map +1 -0
- package/dist/resolution/primitives-registry.js +295 -0
- package/dist/resolution/primitives-registry.js.map +1 -0
- package/dist/resolution/reference-parser.d.ts +62 -0
- package/dist/resolution/reference-parser.d.ts.map +1 -0
- package/dist/resolution/reference-parser.js +182 -0
- package/dist/resolution/reference-parser.js.map +1 -0
- package/dist/resolution/types.d.ts +77 -0
- package/dist/resolution/types.d.ts.map +1 -0
- package/dist/resolution/types.js +13 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/resolution/version-resolver.d.ts +76 -0
- package/dist/resolution/version-resolver.d.ts.map +1 -0
- package/dist/resolution/version-resolver.js +269 -0
- package/dist/resolution/version-resolver.js.map +1 -0
- package/dist/tui/compatibility.d.ts +80 -0
- package/dist/tui/compatibility.d.ts.map +1 -0
- package/dist/tui/compatibility.js +355 -0
- package/dist/tui/compatibility.js.map +1 -0
- package/dist/tui/env-prompt.d.ts +129 -0
- package/dist/tui/env-prompt.d.ts.map +1 -0
- package/dist/tui/env-prompt.js +488 -0
- package/dist/tui/env-prompt.js.map +1 -0
- package/dist/tui/harness-select.d.ts +54 -0
- package/dist/tui/harness-select.d.ts.map +1 -0
- package/dist/tui/harness-select.js +171 -0
- package/dist/tui/harness-select.js.map +1 -0
- package/dist/tui/index.d.ts +112 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +213 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/kit-select.d.ts +72 -0
- package/dist/tui/kit-select.d.ts.map +1 -0
- package/dist/tui/kit-select.js +209 -0
- package/dist/tui/kit-select.js.map +1 -0
- package/dist/tui/progress.d.ts +75 -0
- package/dist/tui/progress.d.ts.map +1 -0
- package/dist/tui/progress.js +267 -0
- package/dist/tui/progress.js.map +1 -0
- package/dist/tui/resolution.d.ts +62 -0
- package/dist/tui/resolution.d.ts.map +1 -0
- package/dist/tui/resolution.js +261 -0
- package/dist/tui/resolution.js.map +1 -0
- package/dist/tui/scope-compatibility.d.ts +139 -0
- package/dist/tui/scope-compatibility.d.ts.map +1 -0
- package/dist/tui/scope-compatibility.js +230 -0
- package/dist/tui/scope-compatibility.js.map +1 -0
- package/dist/tui/scope-select.d.ts +67 -0
- package/dist/tui/scope-select.d.ts.map +1 -0
- package/dist/tui/scope-select.js +134 -0
- package/dist/tui/scope-select.js.map +1 -0
- package/dist/tui/spinner.d.ts +114 -0
- package/dist/tui/spinner.d.ts.map +1 -0
- package/dist/tui/spinner.js +186 -0
- package/dist/tui/spinner.js.map +1 -0
- package/dist/tui/summary.d.ts +71 -0
- package/dist/tui/summary.d.ts.map +1 -0
- package/dist/tui/summary.js +343 -0
- package/dist/tui/summary.js.map +1 -0
- package/dist/tui/types.d.ts +234 -0
- package/dist/tui/types.d.ts.map +1 -0
- package/dist/tui/types.js +7 -0
- package/dist/tui/types.js.map +1 -0
- package/dist/tui/upgrade-select.d.ts +73 -0
- package/dist/tui/upgrade-select.d.ts.map +1 -0
- package/dist/tui/upgrade-select.js +324 -0
- package/dist/tui/upgrade-select.js.map +1 -0
- package/dist/validation/index.d.ts +13 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +13 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/source.d.ts +14 -0
- package/dist/validation/source.d.ts.map +1 -0
- package/dist/validation/source.js +51 -0
- package/dist/validation/source.js.map +1 -0
- package/dist/validation/utils.d.ts +29 -0
- package/dist/validation/utils.d.ts.map +1 -0
- package/dist/validation/utils.js +89 -0
- package/dist/validation/utils.js.map +1 -0
- package/dist/validation/validate-commands.d.ts +28 -0
- package/dist/validation/validate-commands.d.ts.map +1 -0
- package/dist/validation/validate-commands.js +151 -0
- package/dist/validation/validate-commands.js.map +1 -0
- package/dist/validation/validate-hooks.d.ts +13 -0
- package/dist/validation/validate-hooks.d.ts.map +1 -0
- package/dist/validation/validate-hooks.js +272 -0
- package/dist/validation/validate-hooks.js.map +1 -0
- package/dist/validation/validate-kits.d.ts +15 -0
- package/dist/validation/validate-kits.d.ts.map +1 -0
- package/dist/validation/validate-kits.js +185 -0
- package/dist/validation/validate-kits.js.map +1 -0
- package/dist/validation/validate-mcp.d.ts +12 -0
- package/dist/validation/validate-mcp.d.ts.map +1 -0
- package/dist/validation/validate-mcp.js +132 -0
- package/dist/validation/validate-mcp.js.map +1 -0
- package/dist/validation/validate-skills.d.ts +24 -0
- package/dist/validation/validate-skills.d.ts.map +1 -0
- package/dist/validation/validate-skills.js +223 -0
- package/dist/validation/validate-skills.js.map +1 -0
- package/dist/validation/validate-subagents.d.ts +27 -0
- package/dist/validation/validate-subagents.d.ts.map +1 -0
- package/dist/validation/validate-subagents.js +269 -0
- package/dist/validation/validate-subagents.js.map +1 -0
- package/package.json +91 -0
- package/schemas/command.schema.json +23 -0
- package/schemas/examples/hook-binding-valid.json +20 -0
- package/schemas/examples/hook-program-valid.json +25 -0
- package/schemas/examples/http-server-valid.json +82 -0
- package/schemas/examples/invalid-sensitive-header-no-envvar.json +16 -0
- package/schemas/examples/invalid-sensitive-header-with-value.json +17 -0
- package/schemas/examples/invalid-sensitive-var-with-default.json +19 -0
- package/schemas/examples/stdio-server-valid.json +55 -0
- package/schemas/hook-binding.schema.json +63 -0
- package/schemas/hook-program.schema.json +104 -0
- package/schemas/kit.schema.json +338 -0
- package/schemas/kits.schema.json +117 -0
- package/schemas/manifest.schema.json +200 -0
- package/schemas/mcp-server.schema.json +305 -0
- package/schemas/primitives.schema.json +118 -0
- package/schemas/skill.schema.json +96 -0
- package/schemas/subagent.schema.json +107 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File operation utilities for adapter implementations.
|
|
3
|
+
*
|
|
4
|
+
* This module provides atomic file operations with rollback support
|
|
5
|
+
* for installing primitives into AI agent harnesses.
|
|
6
|
+
*/
|
|
7
|
+
import type { FileOperationResult, FileOperation } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* A completed operation that can be rolled back.
|
|
10
|
+
*/
|
|
11
|
+
export interface CompletedOperation {
|
|
12
|
+
type: "file" | "directory" | "backup";
|
|
13
|
+
path: string;
|
|
14
|
+
previousContent?: string;
|
|
15
|
+
createdNew: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result of an atomic file operation batch.
|
|
19
|
+
*/
|
|
20
|
+
export interface AtomicOperationResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
results: FileOperationResult[];
|
|
23
|
+
completedOps: CompletedOperation[];
|
|
24
|
+
error?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Expand ~ to the user's home directory.
|
|
28
|
+
*
|
|
29
|
+
* @param filePath - Path that may contain ~
|
|
30
|
+
*/
|
|
31
|
+
export declare function expandPath(filePath: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Check if a path exists.
|
|
34
|
+
*
|
|
35
|
+
* @param filePath - Path to check (supports ~)
|
|
36
|
+
*/
|
|
37
|
+
export declare function pathExists(filePath: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Check if a path is a directory.
|
|
40
|
+
*
|
|
41
|
+
* @param filePath - Path to check
|
|
42
|
+
*/
|
|
43
|
+
export declare function isDirectory(filePath: string): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Check if a path is a file.
|
|
46
|
+
*
|
|
47
|
+
* @param filePath - Path to check
|
|
48
|
+
*/
|
|
49
|
+
export declare function isFile(filePath: string): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Ensure a directory exists, creating it if necessary.
|
|
52
|
+
*
|
|
53
|
+
* @param dirPath - Directory path to ensure (supports ~)
|
|
54
|
+
* @returns true if directory was created, false if it already existed
|
|
55
|
+
*/
|
|
56
|
+
export declare function ensureDirectory(dirPath: string): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Copy a single file.
|
|
59
|
+
*
|
|
60
|
+
* @param source - Source file path
|
|
61
|
+
* @param destination - Destination file path (supports ~)
|
|
62
|
+
* @param overwrite - Whether to overwrite existing files (default: true)
|
|
63
|
+
*/
|
|
64
|
+
export declare function copyFile(source: string, destination: string, overwrite?: boolean): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Copy a directory recursively.
|
|
67
|
+
*
|
|
68
|
+
* Used for skills which are directories containing SKILL.md and assets.
|
|
69
|
+
*
|
|
70
|
+
* @param source - Source directory path
|
|
71
|
+
* @param destination - Destination directory path (supports ~)
|
|
72
|
+
* @param overwrite - Whether to overwrite existing files (default: true)
|
|
73
|
+
*/
|
|
74
|
+
export declare function copyDirectory(source: string, destination: string, overwrite?: boolean): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Write transformed content to a file.
|
|
77
|
+
*
|
|
78
|
+
* @param destination - Destination file path (supports ~)
|
|
79
|
+
* @param content - Content to write
|
|
80
|
+
* @param encoding - File encoding (default: utf-8)
|
|
81
|
+
*/
|
|
82
|
+
export declare function writeTransformed(destination: string, content: string, encoding?: BufferEncoding): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Read file content.
|
|
85
|
+
*
|
|
86
|
+
* @param filePath - File path to read (supports ~)
|
|
87
|
+
* @param encoding - File encoding (default: utf-8)
|
|
88
|
+
*/
|
|
89
|
+
export declare function readFile(filePath: string, encoding?: BufferEncoding): Promise<string>;
|
|
90
|
+
/**
|
|
91
|
+
* Create a timestamped backup of a file.
|
|
92
|
+
*
|
|
93
|
+
* @param filePath - File to backup (supports ~)
|
|
94
|
+
* @returns The backup file path, or undefined if file didn't exist
|
|
95
|
+
*/
|
|
96
|
+
export declare function backupFile(filePath: string): Promise<string | undefined>;
|
|
97
|
+
/**
|
|
98
|
+
* Create a simple backup (with .backup extension).
|
|
99
|
+
*
|
|
100
|
+
* @param filePath - File to backup (supports ~)
|
|
101
|
+
* @returns The backup file path, or undefined if file didn't exist
|
|
102
|
+
*/
|
|
103
|
+
export declare function createSimpleBackup(filePath: string): Promise<string | undefined>;
|
|
104
|
+
/**
|
|
105
|
+
* Restore a file from backup.
|
|
106
|
+
*
|
|
107
|
+
* @param backupPath - Path to backup file
|
|
108
|
+
* @param originalPath - Original file path to restore to
|
|
109
|
+
*/
|
|
110
|
+
export declare function restoreFromBackup(backupPath: string, originalPath: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Remove a file or directory.
|
|
113
|
+
*
|
|
114
|
+
* @param filePath - Path to remove (supports ~)
|
|
115
|
+
*/
|
|
116
|
+
export declare function remove(filePath: string): Promise<void>;
|
|
117
|
+
/**
|
|
118
|
+
* Remove a directory if it's empty.
|
|
119
|
+
*
|
|
120
|
+
* @param dirPath - Directory path (supports ~)
|
|
121
|
+
* @returns true if directory was removed, false if not empty or didn't exist
|
|
122
|
+
*/
|
|
123
|
+
export declare function removeIfEmpty(dirPath: string): Promise<boolean>;
|
|
124
|
+
/**
|
|
125
|
+
* Rollback a list of completed operations.
|
|
126
|
+
*
|
|
127
|
+
* Operations are rolled back in reverse order.
|
|
128
|
+
*
|
|
129
|
+
* @param completedOps - Operations to roll back
|
|
130
|
+
*/
|
|
131
|
+
export declare function rollbackOperations(completedOps: CompletedOperation[]): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Execute a list of file operations atomically.
|
|
134
|
+
*
|
|
135
|
+
* All operations succeed or all are rolled back.
|
|
136
|
+
*
|
|
137
|
+
* @param operations - Operations to execute
|
|
138
|
+
* @param options - Execution options
|
|
139
|
+
*/
|
|
140
|
+
export declare function executeFileOperations(operations: FileOperation[], options?: {
|
|
141
|
+
createDirs?: boolean;
|
|
142
|
+
backup?: boolean;
|
|
143
|
+
}): Promise<AtomicOperationResult>;
|
|
144
|
+
/**
|
|
145
|
+
* Deep merge two objects.
|
|
146
|
+
*
|
|
147
|
+
* @param target - Target object
|
|
148
|
+
* @param source - Source object to merge in
|
|
149
|
+
*/
|
|
150
|
+
export declare function deepMerge<T extends Record<string, unknown>>(target: T, source: Record<string, unknown>): T;
|
|
151
|
+
/**
|
|
152
|
+
* Get the size of a file or directory in bytes.
|
|
153
|
+
*
|
|
154
|
+
* @param filePath - Path to measure (supports ~)
|
|
155
|
+
*/
|
|
156
|
+
export declare function getSize(filePath: string): Promise<number>;
|
|
157
|
+
/**
|
|
158
|
+
* List all files in a directory recursively.
|
|
159
|
+
*
|
|
160
|
+
* @param dirPath - Directory to list (supports ~)
|
|
161
|
+
* @param pattern - Optional glob pattern to filter files
|
|
162
|
+
*/
|
|
163
|
+
export declare function listFiles(dirPath: string): Promise<string[]>;
|
|
164
|
+
//# sourceMappingURL=file-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-operations.d.ts","sourceRoot":"","sources":["../../src/adapters/file-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File operation utilities for adapter implementations.
|
|
3
|
+
*
|
|
4
|
+
* This module provides atomic file operations with rollback support
|
|
5
|
+
* for installing primitives into AI agent harnesses.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import * as os from "node:os";
|
|
11
|
+
/**
|
|
12
|
+
* Expand ~ to the user's home directory.
|
|
13
|
+
*
|
|
14
|
+
* @param filePath - Path that may contain ~
|
|
15
|
+
*/
|
|
16
|
+
export function expandPath(filePath) {
|
|
17
|
+
if (!filePath)
|
|
18
|
+
return filePath;
|
|
19
|
+
if (filePath === "~") {
|
|
20
|
+
return os.homedir();
|
|
21
|
+
}
|
|
22
|
+
if (filePath.startsWith("~/")) {
|
|
23
|
+
return path.join(os.homedir(), filePath.slice(2));
|
|
24
|
+
}
|
|
25
|
+
return filePath;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Check if a path exists.
|
|
29
|
+
*
|
|
30
|
+
* @param filePath - Path to check (supports ~)
|
|
31
|
+
*/
|
|
32
|
+
export function pathExists(filePath) {
|
|
33
|
+
return existsSync(expandPath(filePath));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if a path is a directory.
|
|
37
|
+
*
|
|
38
|
+
* @param filePath - Path to check
|
|
39
|
+
*/
|
|
40
|
+
export async function isDirectory(filePath) {
|
|
41
|
+
try {
|
|
42
|
+
const stats = await fs.stat(expandPath(filePath));
|
|
43
|
+
return stats.isDirectory();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if a path is a file.
|
|
51
|
+
*
|
|
52
|
+
* @param filePath - Path to check
|
|
53
|
+
*/
|
|
54
|
+
export async function isFile(filePath) {
|
|
55
|
+
try {
|
|
56
|
+
const stats = await fs.stat(expandPath(filePath));
|
|
57
|
+
return stats.isFile();
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Ensure a directory exists, creating it if necessary.
|
|
65
|
+
*
|
|
66
|
+
* @param dirPath - Directory path to ensure (supports ~)
|
|
67
|
+
* @returns true if directory was created, false if it already existed
|
|
68
|
+
*/
|
|
69
|
+
export async function ensureDirectory(dirPath) {
|
|
70
|
+
const expanded = expandPath(dirPath);
|
|
71
|
+
const existed = existsSync(expanded);
|
|
72
|
+
if (!existed) {
|
|
73
|
+
await fs.mkdir(expanded, { recursive: true });
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Copy a single file.
|
|
80
|
+
*
|
|
81
|
+
* @param source - Source file path
|
|
82
|
+
* @param destination - Destination file path (supports ~)
|
|
83
|
+
* @param overwrite - Whether to overwrite existing files (default: true)
|
|
84
|
+
*/
|
|
85
|
+
export async function copyFile(source, destination, overwrite = true) {
|
|
86
|
+
const expandedDest = expandPath(destination);
|
|
87
|
+
// Ensure destination directory exists
|
|
88
|
+
await ensureDirectory(path.dirname(expandedDest));
|
|
89
|
+
// Check if destination exists and overwrite is false
|
|
90
|
+
if (!overwrite && existsSync(expandedDest)) {
|
|
91
|
+
throw new Error(`destination already exists; path=${expandedDest}`);
|
|
92
|
+
}
|
|
93
|
+
await fs.copyFile(source, expandedDest);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Copy a directory recursively.
|
|
97
|
+
*
|
|
98
|
+
* Used for skills which are directories containing SKILL.md and assets.
|
|
99
|
+
*
|
|
100
|
+
* @param source - Source directory path
|
|
101
|
+
* @param destination - Destination directory path (supports ~)
|
|
102
|
+
* @param overwrite - Whether to overwrite existing files (default: true)
|
|
103
|
+
*/
|
|
104
|
+
export async function copyDirectory(source, destination, overwrite = true) {
|
|
105
|
+
const expandedDest = expandPath(destination);
|
|
106
|
+
// Ensure destination directory exists
|
|
107
|
+
await ensureDirectory(expandedDest);
|
|
108
|
+
// Get all entries in source directory
|
|
109
|
+
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
const srcPath = path.join(source, entry.name);
|
|
112
|
+
const destPath = path.join(expandedDest, entry.name);
|
|
113
|
+
if (entry.isDirectory()) {
|
|
114
|
+
await copyDirectory(srcPath, destPath, overwrite);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
if (!overwrite && existsSync(destPath)) {
|
|
118
|
+
continue; // Skip existing files if not overwriting
|
|
119
|
+
}
|
|
120
|
+
await fs.copyFile(srcPath, destPath);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Write transformed content to a file.
|
|
126
|
+
*
|
|
127
|
+
* @param destination - Destination file path (supports ~)
|
|
128
|
+
* @param content - Content to write
|
|
129
|
+
* @param encoding - File encoding (default: utf-8)
|
|
130
|
+
*/
|
|
131
|
+
export async function writeTransformed(destination, content, encoding = "utf-8") {
|
|
132
|
+
const expandedDest = expandPath(destination);
|
|
133
|
+
// Ensure destination directory exists
|
|
134
|
+
await ensureDirectory(path.dirname(expandedDest));
|
|
135
|
+
await fs.writeFile(expandedDest, content, { encoding });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Read file content.
|
|
139
|
+
*
|
|
140
|
+
* @param filePath - File path to read (supports ~)
|
|
141
|
+
* @param encoding - File encoding (default: utf-8)
|
|
142
|
+
*/
|
|
143
|
+
export async function readFile(filePath, encoding = "utf-8") {
|
|
144
|
+
const expanded = expandPath(filePath);
|
|
145
|
+
return fs.readFile(expanded, { encoding });
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Create a timestamped backup of a file.
|
|
149
|
+
*
|
|
150
|
+
* @param filePath - File to backup (supports ~)
|
|
151
|
+
* @returns The backup file path, or undefined if file didn't exist
|
|
152
|
+
*/
|
|
153
|
+
export async function backupFile(filePath) {
|
|
154
|
+
const expanded = expandPath(filePath);
|
|
155
|
+
if (!existsSync(expanded)) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
159
|
+
const backupPath = `${expanded}.backup.${timestamp}`;
|
|
160
|
+
await fs.copyFile(expanded, backupPath);
|
|
161
|
+
return backupPath;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Create a simple backup (with .backup extension).
|
|
165
|
+
*
|
|
166
|
+
* @param filePath - File to backup (supports ~)
|
|
167
|
+
* @returns The backup file path, or undefined if file didn't exist
|
|
168
|
+
*/
|
|
169
|
+
export async function createSimpleBackup(filePath) {
|
|
170
|
+
const expanded = expandPath(filePath);
|
|
171
|
+
if (!existsSync(expanded)) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
const backupPath = `${expanded}.backup`;
|
|
175
|
+
// If backup already exists, remove it
|
|
176
|
+
if (existsSync(backupPath)) {
|
|
177
|
+
await fs.rm(backupPath, { recursive: true, force: true });
|
|
178
|
+
}
|
|
179
|
+
const stats = await fs.stat(expanded);
|
|
180
|
+
if (stats.isDirectory()) {
|
|
181
|
+
await copyDirectory(expanded, backupPath);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
await fs.copyFile(expanded, backupPath);
|
|
185
|
+
}
|
|
186
|
+
return backupPath;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Restore a file from backup.
|
|
190
|
+
*
|
|
191
|
+
* @param backupPath - Path to backup file
|
|
192
|
+
* @param originalPath - Original file path to restore to
|
|
193
|
+
*/
|
|
194
|
+
export async function restoreFromBackup(backupPath, originalPath) {
|
|
195
|
+
const expandedBackup = expandPath(backupPath);
|
|
196
|
+
const expandedOriginal = expandPath(originalPath);
|
|
197
|
+
if (!existsSync(expandedBackup)) {
|
|
198
|
+
throw new Error(`backup not found; path=${expandedBackup}`);
|
|
199
|
+
}
|
|
200
|
+
const stats = await fs.stat(expandedBackup);
|
|
201
|
+
if (stats.isDirectory()) {
|
|
202
|
+
// Remove original directory if exists
|
|
203
|
+
if (existsSync(expandedOriginal)) {
|
|
204
|
+
await fs.rm(expandedOriginal, { recursive: true, force: true });
|
|
205
|
+
}
|
|
206
|
+
await copyDirectory(expandedBackup, expandedOriginal);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
await fs.copyFile(expandedBackup, expandedOriginal);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Remove a file or directory.
|
|
214
|
+
*
|
|
215
|
+
* @param filePath - Path to remove (supports ~)
|
|
216
|
+
*/
|
|
217
|
+
export async function remove(filePath) {
|
|
218
|
+
const expanded = expandPath(filePath);
|
|
219
|
+
if (!existsSync(expanded)) {
|
|
220
|
+
return; // Already doesn't exist
|
|
221
|
+
}
|
|
222
|
+
await fs.rm(expanded, { recursive: true, force: true });
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Remove a directory if it's empty.
|
|
226
|
+
*
|
|
227
|
+
* @param dirPath - Directory path (supports ~)
|
|
228
|
+
* @returns true if directory was removed, false if not empty or didn't exist
|
|
229
|
+
*/
|
|
230
|
+
export async function removeIfEmpty(dirPath) {
|
|
231
|
+
const expanded = expandPath(dirPath);
|
|
232
|
+
if (!existsSync(expanded)) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const entries = await fs.readdir(expanded);
|
|
237
|
+
if (entries.length === 0) {
|
|
238
|
+
await fs.rmdir(expanded);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// Ignore errors (e.g., not a directory)
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Rollback a list of completed operations.
|
|
249
|
+
*
|
|
250
|
+
* Operations are rolled back in reverse order.
|
|
251
|
+
*
|
|
252
|
+
* @param completedOps - Operations to roll back
|
|
253
|
+
*/
|
|
254
|
+
export async function rollbackOperations(completedOps) {
|
|
255
|
+
// Rollback in reverse order
|
|
256
|
+
for (const op of completedOps.reverse()) {
|
|
257
|
+
try {
|
|
258
|
+
switch (op.type) {
|
|
259
|
+
case "file":
|
|
260
|
+
if (op.createdNew) {
|
|
261
|
+
// File was newly created - remove it
|
|
262
|
+
await remove(op.path);
|
|
263
|
+
}
|
|
264
|
+
else if (op.previousContent !== undefined) {
|
|
265
|
+
// File was modified - restore previous content
|
|
266
|
+
await writeTransformed(op.path, op.previousContent);
|
|
267
|
+
}
|
|
268
|
+
break;
|
|
269
|
+
case "directory":
|
|
270
|
+
if (op.createdNew) {
|
|
271
|
+
// Directory was newly created - remove if empty
|
|
272
|
+
await removeIfEmpty(op.path);
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
case "backup":
|
|
276
|
+
{
|
|
277
|
+
// Restore from backup
|
|
278
|
+
const originalPath = op.path.replace(/\.backup(\.[^.]+)?$/, "");
|
|
279
|
+
await restoreFromBackup(op.path, originalPath);
|
|
280
|
+
}
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
// Log but continue rollback
|
|
286
|
+
console.error(`rollback failed for ${op.path}; error=${error}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Execute a list of file operations atomically.
|
|
292
|
+
*
|
|
293
|
+
* All operations succeed or all are rolled back.
|
|
294
|
+
*
|
|
295
|
+
* @param operations - Operations to execute
|
|
296
|
+
* @param options - Execution options
|
|
297
|
+
*/
|
|
298
|
+
export async function executeFileOperations(operations, options = {}) {
|
|
299
|
+
const { createDirs = true, backup = true } = options;
|
|
300
|
+
const results = [];
|
|
301
|
+
const completedOps = [];
|
|
302
|
+
try {
|
|
303
|
+
for (const op of operations) {
|
|
304
|
+
const expandedDest = expandPath(op.destination);
|
|
305
|
+
// Create parent directories if needed
|
|
306
|
+
if (createDirs && op.type !== "mkdir") {
|
|
307
|
+
const dirPath = path.dirname(expandedDest);
|
|
308
|
+
const created = await ensureDirectory(dirPath);
|
|
309
|
+
if (created) {
|
|
310
|
+
completedOps.push({
|
|
311
|
+
type: "directory",
|
|
312
|
+
path: dirPath,
|
|
313
|
+
createdNew: true,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
switch (op.type) {
|
|
318
|
+
case "copy": {
|
|
319
|
+
if (!op.source) {
|
|
320
|
+
throw new Error("copy operation requires source");
|
|
321
|
+
}
|
|
322
|
+
// Backup existing file if needed
|
|
323
|
+
const fileExisted = existsSync(expandedDest);
|
|
324
|
+
let previousContent;
|
|
325
|
+
if (backup && fileExisted) {
|
|
326
|
+
previousContent = await readFile(expandedDest);
|
|
327
|
+
}
|
|
328
|
+
await copyFile(op.source, expandedDest);
|
|
329
|
+
const completedOp = {
|
|
330
|
+
type: "file",
|
|
331
|
+
path: expandedDest,
|
|
332
|
+
createdNew: !fileExisted,
|
|
333
|
+
};
|
|
334
|
+
if (previousContent !== undefined) {
|
|
335
|
+
completedOp.previousContent = previousContent;
|
|
336
|
+
}
|
|
337
|
+
completedOps.push(completedOp);
|
|
338
|
+
results.push({
|
|
339
|
+
operation: "copy",
|
|
340
|
+
source: op.source,
|
|
341
|
+
destination: expandedDest,
|
|
342
|
+
success: true,
|
|
343
|
+
});
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
case "transform": {
|
|
347
|
+
if (!op.source || !op.transform) {
|
|
348
|
+
throw new Error("transform operation requires source and transform function");
|
|
349
|
+
}
|
|
350
|
+
// Backup existing file if needed
|
|
351
|
+
const fileExisted = existsSync(expandedDest);
|
|
352
|
+
let previousContent;
|
|
353
|
+
if (backup && fileExisted) {
|
|
354
|
+
previousContent = await readFile(expandedDest);
|
|
355
|
+
}
|
|
356
|
+
// Read source, transform, and write
|
|
357
|
+
const sourceContent = await readFile(op.source);
|
|
358
|
+
const transformedContent = op.transform(sourceContent);
|
|
359
|
+
await writeTransformed(expandedDest, transformedContent);
|
|
360
|
+
const completedOp = {
|
|
361
|
+
type: "file",
|
|
362
|
+
path: expandedDest,
|
|
363
|
+
createdNew: !fileExisted,
|
|
364
|
+
};
|
|
365
|
+
if (previousContent !== undefined) {
|
|
366
|
+
completedOp.previousContent = previousContent;
|
|
367
|
+
}
|
|
368
|
+
completedOps.push(completedOp);
|
|
369
|
+
results.push({
|
|
370
|
+
operation: "transform",
|
|
371
|
+
source: op.source,
|
|
372
|
+
destination: expandedDest,
|
|
373
|
+
success: true,
|
|
374
|
+
});
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
case "mkdir": {
|
|
378
|
+
const created = await ensureDirectory(expandedDest);
|
|
379
|
+
completedOps.push({
|
|
380
|
+
type: "directory",
|
|
381
|
+
path: expandedDest,
|
|
382
|
+
createdNew: created,
|
|
383
|
+
});
|
|
384
|
+
results.push({
|
|
385
|
+
operation: "mkdir",
|
|
386
|
+
destination: expandedDest,
|
|
387
|
+
success: true,
|
|
388
|
+
});
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
case "merge": {
|
|
392
|
+
// Merge operations are typically handled by config merging
|
|
393
|
+
// For now, treat as a copy with merge strategy
|
|
394
|
+
if (!op.source) {
|
|
395
|
+
throw new Error("merge operation requires source");
|
|
396
|
+
}
|
|
397
|
+
const fileExisted = existsSync(expandedDest);
|
|
398
|
+
let previousContent;
|
|
399
|
+
if (fileExisted) {
|
|
400
|
+
previousContent = await readFile(expandedDest);
|
|
401
|
+
if (op.mergeStrategy === "deep-merge") {
|
|
402
|
+
// Deep merge JSON/YAML files
|
|
403
|
+
const existingContent = JSON.parse(previousContent);
|
|
404
|
+
const newContent = JSON.parse(await readFile(op.source));
|
|
405
|
+
const merged = deepMerge(existingContent, newContent);
|
|
406
|
+
await writeTransformed(expandedDest, JSON.stringify(merged, null, 2));
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
// Replace strategy - just copy
|
|
410
|
+
await copyFile(op.source, expandedDest);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
await copyFile(op.source, expandedDest);
|
|
415
|
+
}
|
|
416
|
+
const completedOp = {
|
|
417
|
+
type: "file",
|
|
418
|
+
path: expandedDest,
|
|
419
|
+
createdNew: !fileExisted,
|
|
420
|
+
};
|
|
421
|
+
if (previousContent !== undefined) {
|
|
422
|
+
completedOp.previousContent = previousContent;
|
|
423
|
+
}
|
|
424
|
+
completedOps.push(completedOp);
|
|
425
|
+
results.push({
|
|
426
|
+
operation: "merge",
|
|
427
|
+
source: op.source,
|
|
428
|
+
destination: expandedDest,
|
|
429
|
+
success: true,
|
|
430
|
+
});
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
success: true,
|
|
437
|
+
results,
|
|
438
|
+
completedOps,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
// Rollback all completed operations
|
|
443
|
+
await rollbackOperations(completedOps);
|
|
444
|
+
return {
|
|
445
|
+
success: false,
|
|
446
|
+
results,
|
|
447
|
+
completedOps: [],
|
|
448
|
+
error: error instanceof Error ? error.message : String(error),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Deep merge two objects.
|
|
454
|
+
*
|
|
455
|
+
* @param target - Target object
|
|
456
|
+
* @param source - Source object to merge in
|
|
457
|
+
*/
|
|
458
|
+
export function deepMerge(target, source) {
|
|
459
|
+
const result = { ...target };
|
|
460
|
+
for (const key of Object.keys(source)) {
|
|
461
|
+
const sourceValue = source[key];
|
|
462
|
+
const targetValue = result[key];
|
|
463
|
+
if (sourceValue &&
|
|
464
|
+
typeof sourceValue === "object" &&
|
|
465
|
+
!Array.isArray(sourceValue) &&
|
|
466
|
+
targetValue &&
|
|
467
|
+
typeof targetValue === "object" &&
|
|
468
|
+
!Array.isArray(targetValue)) {
|
|
469
|
+
// Recursively merge objects
|
|
470
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
// Override with source value
|
|
474
|
+
result[key] = sourceValue;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Get the size of a file or directory in bytes.
|
|
481
|
+
*
|
|
482
|
+
* @param filePath - Path to measure (supports ~)
|
|
483
|
+
*/
|
|
484
|
+
export async function getSize(filePath) {
|
|
485
|
+
const expanded = expandPath(filePath);
|
|
486
|
+
const stats = await fs.stat(expanded);
|
|
487
|
+
if (stats.isFile()) {
|
|
488
|
+
return stats.size;
|
|
489
|
+
}
|
|
490
|
+
if (stats.isDirectory()) {
|
|
491
|
+
let totalSize = 0;
|
|
492
|
+
const entries = await fs.readdir(expanded, { withFileTypes: true });
|
|
493
|
+
for (const entry of entries) {
|
|
494
|
+
const entryPath = path.join(expanded, entry.name);
|
|
495
|
+
totalSize += await getSize(entryPath);
|
|
496
|
+
}
|
|
497
|
+
return totalSize;
|
|
498
|
+
}
|
|
499
|
+
return 0;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* List all files in a directory recursively.
|
|
503
|
+
*
|
|
504
|
+
* @param dirPath - Directory to list (supports ~)
|
|
505
|
+
* @param pattern - Optional glob pattern to filter files
|
|
506
|
+
*/
|
|
507
|
+
export async function listFiles(dirPath) {
|
|
508
|
+
const expanded = expandPath(dirPath);
|
|
509
|
+
const files = [];
|
|
510
|
+
if (!existsSync(expanded)) {
|
|
511
|
+
return files;
|
|
512
|
+
}
|
|
513
|
+
const entries = await fs.readdir(expanded, { withFileTypes: true });
|
|
514
|
+
for (const entry of entries) {
|
|
515
|
+
const entryPath = path.join(expanded, entry.name);
|
|
516
|
+
if (entry.isDirectory()) {
|
|
517
|
+
const subFiles = await listFiles(entryPath);
|
|
518
|
+
files.push(...subFiles);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
files.push(entryPath);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return files;
|
|
525
|
+
}
|
|
526
|
+
//# sourceMappingURL=file-operations.js.map
|