talos-code 0.0.1 → 0.2.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/CHANGELOG.md +87 -0
- package/LICENSE +661 -0
- package/README.md +116 -3
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/archive/zip.js +73 -0
- package/dist/args.js +100 -0
- package/dist/automations/history-store.js +34 -0
- package/dist/automations/policy-store.js +43 -0
- package/dist/automations/runner.js +107 -0
- package/dist/automations/schedule.js +85 -0
- package/dist/automations/windows-task.js +53 -0
- package/dist/commands/advanced-cli.js +233 -0
- package/dist/commands/checkpoint-cli.js +45 -0
- package/dist/commands/config-cli.js +107 -0
- package/dist/commands/context.js +17 -0
- package/dist/commands/extensions-cli.js +207 -0
- package/dist/commands/project-cli.js +74 -0
- package/dist/commands/project-commands.js +143 -0
- package/dist/commands/provider-cli.js +244 -0
- package/dist/commands/services-cli.js +248 -0
- package/dist/commands/session-cli.js +171 -0
- package/dist/commands/system-cli.js +405 -0
- package/dist/config/commands.js +60 -0
- package/dist/config/load.js +382 -0
- package/dist/config/migrations.js +48 -0
- package/dist/config/types.js +11 -0
- package/dist/diagnostics/development-log.js +154 -0
- package/dist/diagnostics/doctor.js +104 -0
- package/dist/diagnostics/redact.js +80 -0
- package/dist/diagnostics/zip.js +52 -0
- package/dist/errors.js +156 -0
- package/dist/events/bridge.js +130 -0
- package/dist/extensions/installer.js +178 -0
- package/dist/extensions/package-schema.js +24 -0
- package/dist/headless/result.js +84 -0
- package/dist/headless/run.js +230 -0
- package/dist/i18n/en/approval.js +46 -0
- package/dist/i18n/en/common.js +9 -0
- package/dist/i18n/en/credentials.js +92 -0
- package/dist/i18n/en/errors.js +267 -0
- package/dist/i18n/en/firstrun.js +101 -0
- package/dist/i18n/en/providers.js +37 -0
- package/dist/i18n/en/screen.js +774 -0
- package/dist/i18n/en/tools.js +127 -0
- package/dist/i18n/en.js +14 -0
- package/dist/i18n/error-view.js +307 -0
- package/dist/i18n/index.js +19 -0
- package/dist/i18n/kernel-map.js +139 -0
- package/dist/io.js +45 -0
- package/dist/main.js +331 -0
- package/dist/paths.js +41 -0
- package/dist/protocol/v2/codec.js +9 -0
- package/dist/protocol/v2/events.js +555 -0
- package/dist/protocol/v2/index.js +4 -0
- package/dist/protocol/v2/replay.js +28 -0
- package/dist/protocol/v2/types.js +1 -0
- package/dist/provider/control-plane.js +135 -0
- package/dist/provider/environment-keys.js +275 -0
- package/dist/provider/health.js +110 -0
- package/dist/provider/missing-key.js +48 -0
- package/dist/provider/model-catalog.js +168 -0
- package/dist/provider/openrouter-login.js +172 -0
- package/dist/provider/provider-text.js +13 -0
- package/dist/provider/store.js +95 -0
- package/dist/provider/system-keyring.js +214 -0
- package/dist/runtime/active-run.js +63 -0
- package/dist/runtime/agent-tree.js +74 -0
- package/dist/runtime/attachments.js +84 -0
- package/dist/runtime/brokered-executor.js +395 -0
- package/dist/runtime/context-archive.js +69 -0
- package/dist/runtime/context-status.js +76 -0
- package/dist/runtime/create-runtime.js +111 -0
- package/dist/runtime/model-profile.js +361 -0
- package/dist/runtime/output-store.js +137 -0
- package/dist/runtime/provider-attempts.js +185 -0
- package/dist/runtime/replay-buffer.js +153 -0
- package/dist/runtime/repo.js +95 -0
- package/dist/runtime/session-facade.js +135 -0
- package/dist/runtime/session-summary.js +125 -0
- package/dist/runtime/supervisor.js +265 -0
- package/dist/runtime/talos-composition.js +1011 -0
- package/dist/runtime/types.js +5 -0
- package/dist/runtime/usage-snapshot.js +82 -0
- package/dist/security/auto-classifier.js +38 -0
- package/dist/security/credential-free-environment.js +54 -0
- package/dist/security/evaluate.js +243 -0
- package/dist/security/execution-backends.js +236 -0
- package/dist/security/execution-broker.js +102 -0
- package/dist/security/forge-scan.js +74 -0
- package/dist/security/from-approval.js +39 -0
- package/dist/security/mxc-execution-backend.js +281 -0
- package/dist/security/permission-engine.js +138 -0
- package/dist/security/permission-explanation.js +54 -0
- package/dist/security/persist.js +179 -0
- package/dist/security/plugin-guard.js +230 -0
- package/dist/security/process-tree-evidence-store.js +74 -0
- package/dist/security/process-tree-probe.js +554 -0
- package/dist/security/project-resource-inventory.js +186 -0
- package/dist/security/project-trust-gate.js +38 -0
- package/dist/security/project-trust.js +367 -0
- package/dist/security/rule-parser.js +201 -0
- package/dist/security/shell-segmentation.js +68 -0
- package/dist/security/trust-authority.js +324 -0
- package/dist/security/types.js +1 -0
- package/dist/security/workspace-identity.js +102 -0
- package/dist/services/automation-facade.js +59 -0
- package/dist/services/forge-facade.js +77 -0
- package/dist/services/hook-facade.js +240 -0
- package/dist/services/index.js +16 -0
- package/dist/services/library-facade.js +174 -0
- package/dist/services/mcp-facade.js +348 -0
- package/dist/services/memory-facade.js +126 -0
- package/dist/services/notes-facade.js +157 -0
- package/dist/services/plugin-facade.js +308 -0
- package/dist/services/research-facade.js +110 -0
- package/dist/services/task-board-facade.js +236 -0
- package/dist/services/workflow-catalog.js +246 -0
- package/dist/sessions/export-format.js +98 -0
- package/dist/sessions/metadata-store.js +160 -0
- package/dist/sessions/share.js +122 -0
- package/dist/sessions/transfer.js +16 -0
- package/dist/subcommands.js +62 -0
- package/dist/tui/agent-roster.js +36 -0
- package/dist/tui/agent-view.js +51 -0
- package/dist/tui/app.js +4098 -0
- package/dist/tui/approval.js +36 -0
- package/dist/tui/boot/boot-sequence.js +76 -0
- package/dist/tui/boot/cinematic.js +243 -0
- package/dist/tui/boot/desktop-logo.js +82 -0
- package/dist/tui/boot.js +3 -0
- package/dist/tui/busy-input.js +58 -0
- package/dist/tui/catalog-service.js +560 -0
- package/dist/tui/components/assistant-stream.js +1 -0
- package/dist/tui/components/command-menu.js +68 -0
- package/dist/tui/components/composer.js +219 -0
- package/dist/tui/components/diff.js +35 -0
- package/dist/tui/components/footer.js +48 -0
- package/dist/tui/components/header.js +6 -0
- package/dist/tui/components/markdown.js +305 -0
- package/dist/tui/components/status-indicator.js +38 -0
- package/dist/tui/components/terminal-shell.js +214 -0
- package/dist/tui/components/thinking-row.js +19 -0
- package/dist/tui/components/tool-row.js +97 -0
- package/dist/tui/components/transcript-virtualizer.js +165 -0
- package/dist/tui/components/transcript.js +43 -0
- package/dist/tui/descendant-approvals.js +104 -0
- package/dist/tui/diff-model.js +77 -0
- package/dist/tui/editor-history.js +21 -0
- package/dist/tui/editor.js +210 -0
- package/dist/tui/event-adapter.js +436 -0
- package/dist/tui/exit-output.js +58 -0
- package/dist/tui/external-editor.js +53 -0
- package/dist/tui/file-completion.js +89 -0
- package/dist/tui/focus-manager.js +5 -0
- package/dist/tui/highlight.js +30 -0
- package/dist/tui/input-router.js +18 -0
- package/dist/tui/interrupt.js +99 -0
- package/dist/tui/keybindings.js +194 -0
- package/dist/tui/keymap-resolver.js +91 -0
- package/dist/tui/launch-state.js +148 -0
- package/dist/tui/line-diff.js +57 -0
- package/dist/tui/live-activity.js +56 -0
- package/dist/tui/metrics.js +123 -0
- package/dist/tui/onboarding.js +36 -0
- package/dist/tui/overlays/agent-tree.js +43 -0
- package/dist/tui/overlays/approval-dialog.js +642 -0
- package/dist/tui/overlays/automation-center.js +51 -0
- package/dist/tui/overlays/checkpoint-picker.js +47 -0
- package/dist/tui/overlays/context-inspector.js +36 -0
- package/dist/tui/overlays/effort-line.js +110 -0
- package/dist/tui/overlays/forge-center.js +46 -0
- package/dist/tui/overlays/help-dialog.js +16 -0
- package/dist/tui/overlays/history-picker.js +37 -0
- package/dist/tui/overlays/hook-center.js +70 -0
- package/dist/tui/overlays/library-center.js +55 -0
- package/dist/tui/overlays/mcp-center.js +60 -0
- package/dist/tui/overlays/memory-center.js +63 -0
- package/dist/tui/overlays/model-picker.js +77 -0
- package/dist/tui/overlays/notes-center.js +53 -0
- package/dist/tui/overlays/overlay-host.js +8 -0
- package/dist/tui/overlays/plugin-center.js +76 -0
- package/dist/tui/overlays/provider-picker.js +171 -0
- package/dist/tui/overlays/queue-editor.js +32 -0
- package/dist/tui/overlays/research-center.js +59 -0
- package/dist/tui/overlays/scroll-window.js +234 -0
- package/dist/tui/overlays/session-picker.js +115 -0
- package/dist/tui/overlays/tasks-center.js +83 -0
- package/dist/tui/overlays/theme-picker.js +21 -0
- package/dist/tui/overlays/transcript-search.js +58 -0
- package/dist/tui/overlays/trust-center.js +29 -0
- package/dist/tui/overlays/workflow-center.js +46 -0
- package/dist/tui/project-file-index.js +214 -0
- package/dist/tui/project-references.js +85 -0
- package/dist/tui/project-trust-prompt.js +289 -0
- package/dist/tui/prompt-history-store.js +116 -0
- package/dist/tui/queue-store.js +110 -0
- package/dist/tui/regions/budget.js +59 -0
- package/dist/tui/regions/views.js +96 -0
- package/dist/tui/render-coordinator.js +148 -0
- package/dist/tui/render-scheduler.js +4 -0
- package/dist/tui/run.js +69 -0
- package/dist/tui/selection-list.js +29 -0
- package/dist/tui/session-controller.js +791 -0
- package/dist/tui/session-export.js +54 -0
- package/dist/tui/setup-wizard.js +46 -0
- package/dist/tui/shell-input.js +35 -0
- package/dist/tui/shell-layout.js +48 -0
- package/dist/tui/shell-model.js +98 -0
- package/dist/tui/slash-commands.js +82 -0
- package/dist/tui/state.js +151 -0
- package/dist/tui/status-bar.js +125 -0
- package/dist/tui/status-view.js +40 -0
- package/dist/tui/terminal-capabilities.js +9 -0
- package/dist/tui/terminal-session.js +11 -0
- package/dist/tui/text-width.js +66 -0
- package/dist/tui/theme-catalog.js +27 -0
- package/dist/tui/theme-store.js +23 -0
- package/dist/tui/theme.js +23 -0
- package/dist/tui/tool-display.js +135 -0
- package/dist/tui/tool-facts.js +1 -0
- package/dist/tui/tools/bash-renderer.js +32 -0
- package/dist/tui/tools/change.js +61 -0
- package/dist/tui/tools/edit-renderer.js +17 -0
- package/dist/tui/tools/generic-renderer.js +13 -0
- package/dist/tui/tools/list-renderer.js +14 -0
- package/dist/tui/tools/read-renderer.js +13 -0
- package/dist/tui/tools/registry.js +20 -0
- package/dist/tui/tools/row-format.js +187 -0
- package/dist/tui/tools/search-renderer.js +38 -0
- package/dist/tui/tools/shared.js +97 -0
- package/dist/tui/tools/write-renderer.js +15 -0
- package/dist/tui/transcript-model.js +441 -0
- package/dist/tui/ui-preferences.js +79 -0
- package/dist/tui/usage-view.js +77 -0
- package/dist/tui/vim-mode.js +99 -0
- package/dist/update/check.js +15 -0
- package/dist/update/npm.js +51 -0
- package/dist/update/run.js +129 -0
- package/dist/version.js +2 -0
- package/dist/workspace/checkpoint-store.js +210 -0
- package/dist/workspace/checkpoint.js +413 -0
- package/dist/workspace/restore.js +232 -0
- package/package.json +64 -5
- package/vendor/context-engine/package.json +11 -0
- package/vendor/context-engine/src/compaction-planner.mjs +57 -0
- package/vendor/context-engine/src/contracts.mjs +48 -0
- package/vendor/context-engine/src/engine.mjs +445 -0
- package/vendor/context-engine/src/node/context-export.mjs +164 -0
- package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
- package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
- package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
- package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
- package/vendor/context-engine/src/profiles.mjs +10 -0
- package/vendor/context-engine/src/retrieval.mjs +104 -0
- package/vendor/context-engine/src/summary.mjs +97 -0
- package/vendor/context-engine/src/usage.mjs +34 -0
- package/vendor/harness-ui/package.json +38 -0
- package/vendor/harness-ui/src/acp-agent.mjs +350 -0
- package/vendor/harness-ui/src/agent-service.mjs +2188 -0
- package/vendor/harness-ui/src/agui-events.mjs +452 -0
- package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
- package/vendor/harness-ui/src/artifact-store.mjs +39 -0
- package/vendor/harness-ui/src/assistenza.mjs +123 -0
- package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
- package/vendor/harness-ui/src/automation-store.mjs +145 -0
- package/vendor/harness-ui/src/browser-annota.mjs +639 -0
- package/vendor/harness-ui/src/browser-frame.mjs +211 -0
- package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
- package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
- package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
- package/vendor/harness-ui/src/browser-stream.mjs +445 -0
- package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
- package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
- package/vendor/harness-ui/src/config.mjs +697 -0
- package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
- package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
- package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
- package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
- package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
- package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
- package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
- package/vendor/harness-ui/src/context-runtime.mjs +118 -0
- package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
- package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
- package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
- package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
- package/vendor/harness-ui/src/custom-task.mjs +171 -0
- package/vendor/harness-ui/src/doctor.mjs +142 -0
- package/vendor/harness-ui/src/document-filename.mjs +97 -0
- package/vendor/harness-ui/src/document-generator.mjs +493 -0
- package/vendor/harness-ui/src/document-report.mjs +331 -0
- package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
- package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
- package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
- package/vendor/harness-ui/src/forge-contract.mjs +221 -0
- package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
- package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
- package/vendor/harness-ui/src/generation-idle.mjs +332 -0
- package/vendor/harness-ui/src/gguf-header.mjs +207 -0
- package/vendor/harness-ui/src/git-service.mjs +626 -0
- package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
- package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
- package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
- package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
- package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
- package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
- package/vendor/harness-ui/src/hook-registry.mjs +186 -0
- package/vendor/harness-ui/src/http-app.mjs +6259 -0
- package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
- package/vendor/harness-ui/src/id-archivio.mjs +27 -0
- package/vendor/harness-ui/src/image-generator.mjs +143 -0
- package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
- package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
- package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
- package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
- package/vendor/harness-ui/src/library-store.mjs +652 -0
- package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
- package/vendor/harness-ui/src/local-model-store.mjs +339 -0
- package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
- package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
- package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
- package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
- package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
- package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
- package/vendor/harness-ui/src/mcp-client.mjs +98 -0
- package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
- package/vendor/harness-ui/src/mcp-session.mjs +177 -0
- package/vendor/harness-ui/src/memory-store.mjs +227 -0
- package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
- package/vendor/harness-ui/src/model-catalog.mjs +129 -0
- package/vendor/harness-ui/src/model-destination.mjs +189 -0
- package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
- package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
- package/vendor/harness-ui/src/notes-store.mjs +250 -0
- package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
- package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
- package/vendor/harness-ui/src/path-policy.mjs +442 -0
- package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
- package/vendor/harness-ui/src/plugin-session.mjs +180 -0
- package/vendor/harness-ui/src/process-policy.mjs +345 -0
- package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
- package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
- package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
- package/vendor/harness-ui/src/provider-probe.mjs +582 -0
- package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
- package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
- package/vendor/harness-ui/src/public-problem.mjs +109 -0
- package/vendor/harness-ui/src/research/card.mjs +235 -0
- package/vendor/harness-ui/src/research/citations.mjs +142 -0
- package/vendor/harness-ui/src/research/collector.mjs +275 -0
- package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
- package/vendor/harness-ui/src/research/dossier.mjs +114 -0
- package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
- package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
- package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
- package/vendor/harness-ui/src/research/independence.mjs +159 -0
- package/vendor/harness-ui/src/research/ledger.mjs +166 -0
- package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
- package/vendor/harness-ui/src/research/narration.mjs +181 -0
- package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
- package/vendor/harness-ui/src/research/opposing.mjs +305 -0
- package/vendor/harness-ui/src/research/outline.mjs +111 -0
- package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
- package/vendor/harness-ui/src/research/pdf.mjs +291 -0
- package/vendor/harness-ui/src/research/plan.mjs +301 -0
- package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
- package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
- package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
- package/vendor/harness-ui/src/research/recheck.mjs +194 -0
- package/vendor/harness-ui/src/research/report.mjs +203 -0
- package/vendor/harness-ui/src/research/run.mjs +527 -0
- package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
- package/vendor/harness-ui/src/research/verification.mjs +572 -0
- package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
- package/vendor/harness-ui/src/research-store.mjs +1133 -0
- package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
- package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
- package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
- package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
- package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
- package/vendor/harness-ui/src/search-source-store.mjs +172 -0
- package/vendor/harness-ui/src/session-registry.mjs +6095 -0
- package/vendor/harness-ui/src/session-store.mjs +220 -0
- package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
- package/vendor/harness-ui/src/setup-stato.mjs +31 -0
- package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
- package/vendor/harness-ui/src/skill-registry.mjs +120 -0
- package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
- package/vendor/harness-ui/src/static-files.mjs +96 -0
- package/vendor/harness-ui/src/stream-partition.mjs +123 -0
- package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
- package/vendor/harness-ui/src/task-catalog.mjs +65 -0
- package/vendor/harness-ui/src/tasks-store.mjs +220 -0
- package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
- package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
- package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
- package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
- package/vendor/harness-ui/src/usage-cache.mjs +315 -0
- package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
- package/vendor/harness-ui/src/workspace-context.mjs +124 -0
- package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
- package/vendor/harness-ui/src/workspace-files.mjs +589 -0
- package/vendor/harness-ui/src/workspace-info.mjs +189 -0
- package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
- package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
- package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
- package/vendor/manifest.json +170 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { rm } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { assertNoUnknownOptions, writeValue } from "./context.js";
|
|
4
|
+
import { installExtension, removeInstalledExtension } from "../extensions/installer.js";
|
|
5
|
+
import { createTrustAuthority } from "../security/trust-authority.js";
|
|
6
|
+
import { createMcpFacade } from "../services/mcp-facade.js";
|
|
7
|
+
import { createHookFacade } from "../services/hook-facade.js";
|
|
8
|
+
import { createPluginFacade } from "../services/plugin-facade.js";
|
|
9
|
+
import { createWorkflowCatalog } from "../services/workflow-catalog.js";
|
|
10
|
+
import { createWorkflowCenterModel, renderWorkflowCenterLines } from "../tui/overlays/workflow-center.js";
|
|
11
|
+
function id(v) { if (!v || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,120}$/u.test(v) || v.includes('..'))
|
|
12
|
+
throw new Error('EXTENSION_ID_INVALID'); return v; }
|
|
13
|
+
function authority(ctx) { return createTrustAuthority({ projectRoot: ctx.projectRoot, trustRoot: ctx.paths.trust.projects }); }
|
|
14
|
+
async function removeMirror(root, value) { const clean = id(value); await rm(join(root, `${clean}.json`), { force: true }); }
|
|
15
|
+
async function mirrorRoot(ctx, kind) { const roots = await authority(ctx).compatibilityRoots(); return kind === 'hook' ? roots.hooks : kind === 'mcp' ? roots.mcp : roots.plugins; }
|
|
16
|
+
export async function runMcpCommand(ctx, args0, facade = createMcpFacade({ projectRoot: ctx.projectRoot, repoRoot: ctx.repoRoot, paths: ctx.paths })) {
|
|
17
|
+
const a = [...args0], op = a.shift() ?? 'list';
|
|
18
|
+
if (op === 'list') {
|
|
19
|
+
assertNoUnknownOptions(a);
|
|
20
|
+
writeValue(ctx, await facade.list());
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
const sid = id(a.shift());
|
|
24
|
+
assertNoUnknownOptions(a);
|
|
25
|
+
if (op === 'trust') {
|
|
26
|
+
const result = await facade.trust(sid);
|
|
27
|
+
writeValue(ctx, { ok: true, id: sid, changed: result.changed }, result.changed ? 'Trusted MCP ' + sid + '\n' : 'MCP ' + sid + ' already trusted by the project authority\n');
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
if (op === 'untrust') {
|
|
31
|
+
const result = await facade.untrust(sid);
|
|
32
|
+
writeValue(ctx, { ok: true, id: sid, changed: result.changed }, 'Untrusted MCP ' + sid + '\n');
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
if (op === 'test') {
|
|
36
|
+
const result = await facade.probe(sid);
|
|
37
|
+
const ok = result.health.state === 'healthy' || result.health.state === 'degraded';
|
|
38
|
+
const output = {
|
|
39
|
+
ok, id: sid, health: result.health, server: result.server, protocol: result.protocol, capabilities: result.capabilities,
|
|
40
|
+
tools: result.permission.effectiveTools, missingAllowlistedTools: result.permission.missingAllowlistedTools,
|
|
41
|
+
trust: result.trust, permission: result.permission, logs: result.logs, error: ok ? null : result.health.message
|
|
42
|
+
};
|
|
43
|
+
writeValue(ctx, output);
|
|
44
|
+
return ok ? 0 : 15;
|
|
45
|
+
}
|
|
46
|
+
throw new Error('Unsupported mcp operation: ' + op);
|
|
47
|
+
}
|
|
48
|
+
export async function runHookCommand(ctx, args0, facade = createHookFacade({ projectRoot: ctx.projectRoot, repoRoot: ctx.repoRoot, paths: ctx.paths })) {
|
|
49
|
+
const a = [...args0], op = a.shift() ?? 'list';
|
|
50
|
+
if (op === 'list') {
|
|
51
|
+
assertNoUnknownOptions(a);
|
|
52
|
+
if (a.length)
|
|
53
|
+
throw new Error('HOOK_LIST_TAKES_NO_ARGUMENTS');
|
|
54
|
+
writeValue(ctx, await facade.list());
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
const hid = id(a.shift());
|
|
58
|
+
if (op === 'trust') {
|
|
59
|
+
assertNoUnknownOptions(a);
|
|
60
|
+
if (a.length)
|
|
61
|
+
throw new Error('HOOK_TRUST_TAKES_ONE_ID');
|
|
62
|
+
const result = await facade.trust(hid);
|
|
63
|
+
writeValue(ctx, { ok: true, id: hid, changed: result.changed }, result.changed ? 'Trusted hook ' + hid + '\n' : 'Hook ' + hid + ' already trusted by the project authority\n');
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
if (op === 'untrust') {
|
|
67
|
+
assertNoUnknownOptions(a);
|
|
68
|
+
if (a.length)
|
|
69
|
+
throw new Error('HOOK_UNTRUST_TAKES_ONE_ID');
|
|
70
|
+
const result = await facade.untrust(hid);
|
|
71
|
+
writeValue(ctx, { ok: true, id: hid, changed: result.changed }, 'Untrusted hook ' + hid + '\n');
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
if (op === 'dry-run') {
|
|
75
|
+
const eventType = a.shift();
|
|
76
|
+
if (!eventType)
|
|
77
|
+
throw new Error('HOOK_EVENT_REQUIRED');
|
|
78
|
+
const action = a.length ? a.join(' ') : null;
|
|
79
|
+
const result = await facade.dryRun(hid, { eventType, action });
|
|
80
|
+
writeValue(ctx, { ok: true, id: hid, ...result }, 'Executed hook ' + hid + ' with a synthetic ' + eventType + ' event through the real hook process path.\n');
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
if (op === 'history') {
|
|
84
|
+
const rawLimit = a.shift();
|
|
85
|
+
assertNoUnknownOptions(a);
|
|
86
|
+
if (a.length)
|
|
87
|
+
throw new Error('HOOK_HISTORY_ARGUMENTS_INVALID');
|
|
88
|
+
let limit;
|
|
89
|
+
if (rawLimit !== undefined) {
|
|
90
|
+
limit = Number(rawLimit);
|
|
91
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 50)
|
|
92
|
+
throw new Error('HOOK_HISTORY_LIMIT_INVALID');
|
|
93
|
+
}
|
|
94
|
+
const rows = await facade.history(hid, limit === undefined ? {} : { limit });
|
|
95
|
+
writeValue(ctx, rows);
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
if (op === 'quarantine') {
|
|
99
|
+
const reason = a.length ? a.join(' ') : null;
|
|
100
|
+
const result = await facade.quarantine(hid, reason);
|
|
101
|
+
writeValue(ctx, { ok: true, id: hid, changed: result.changed, quarantine: result.record }, 'Quarantined hook ' + hid + '. It remains denied until quarantine is explicitly released, and release does not restore trust.\n');
|
|
102
|
+
return 0;
|
|
103
|
+
}
|
|
104
|
+
if (op === 'release' || op === 'release-quarantine') {
|
|
105
|
+
assertNoUnknownOptions(a);
|
|
106
|
+
if (a.length)
|
|
107
|
+
throw new Error('HOOK_RELEASE_TAKES_ONE_ID');
|
|
108
|
+
const result = await facade.releaseQuarantine(hid);
|
|
109
|
+
writeValue(ctx, { ok: true, id: hid, changed: result.changed }, 'Released hook quarantine for ' + hid + '. The hook remains untrusted until explicitly trusted again.\n');
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
throw new Error('Unsupported hook operation: ' + op);
|
|
113
|
+
}
|
|
114
|
+
export async function runPluginCommand(ctx, args0, facade = createPluginFacade({ projectRoot: ctx.projectRoot, repoRoot: ctx.repoRoot, paths: ctx.paths })) {
|
|
115
|
+
const a = [...args0], op = a.shift() ?? 'list';
|
|
116
|
+
if (op === 'install') {
|
|
117
|
+
const source = a.shift();
|
|
118
|
+
if (!source)
|
|
119
|
+
throw new Error('PLUGIN_SOURCE_REQUIRED');
|
|
120
|
+
assertNoUnknownOptions(a);
|
|
121
|
+
const result = await installExtension({ source, projectRoot: ctx.projectRoot });
|
|
122
|
+
writeValue(ctx, result, 'Installed ' + result.id + ' ' + result.version + '; project trust must cover the new package before it can run\n');
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
if (op === 'remove') {
|
|
126
|
+
const pid = id(a.shift());
|
|
127
|
+
assertNoUnknownOptions(a);
|
|
128
|
+
const result = await removeInstalledExtension({ projectRoot: ctx.projectRoot, id: pid });
|
|
129
|
+
const trust = authority(ctx);
|
|
130
|
+
await trust.untrustScope({ kind: 'plugin', id: pid });
|
|
131
|
+
await removeMirror(await mirrorRoot(ctx, 'plugin'), pid);
|
|
132
|
+
writeValue(ctx, result, 'Removed ' + pid + '\n');
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
if (op === 'list') {
|
|
136
|
+
assertNoUnknownOptions(a);
|
|
137
|
+
if (a.length)
|
|
138
|
+
throw new Error('PLUGIN_LIST_TAKES_NO_ARGUMENTS');
|
|
139
|
+
writeValue(ctx, await facade.list());
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
const pid = id(a.shift());
|
|
143
|
+
if (op === 'trust') {
|
|
144
|
+
assertNoUnknownOptions(a);
|
|
145
|
+
if (a.length)
|
|
146
|
+
throw new Error('PLUGIN_TRUST_TAKES_ONE_ID');
|
|
147
|
+
const result = await facade.trust(pid);
|
|
148
|
+
writeValue(ctx, { ok: true, id: pid, guard: result.guard, changed: result.changed }, result.changed ? 'Trusted plugin ' + pid + '\n' : 'Plugin ' + pid + ' already trusted by the project authority\n');
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
if (op === 'untrust') {
|
|
152
|
+
assertNoUnknownOptions(a);
|
|
153
|
+
if (a.length)
|
|
154
|
+
throw new Error('PLUGIN_UNTRUST_TAKES_ONE_ID');
|
|
155
|
+
const result = await facade.untrust(pid);
|
|
156
|
+
writeValue(ctx, { ok: true, id: pid, changed: result.changed }, 'Untrusted plugin ' + pid + '\n');
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
if (op === 'quarantine') {
|
|
160
|
+
const reason = a.length ? a.join(' ') : null;
|
|
161
|
+
const result = await facade.quarantine(pid, reason);
|
|
162
|
+
writeValue(ctx, { ok: true, id: pid, changed: result.changed, quarantine: result.record }, 'Quarantined plugin ' + pid + '. It cannot regain trust until quarantine is explicitly released.\n');
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
if (op === 'release' || op === 'release-quarantine') {
|
|
166
|
+
assertNoUnknownOptions(a);
|
|
167
|
+
if (a.length)
|
|
168
|
+
throw new Error('PLUGIN_RELEASE_TAKES_ONE_ID');
|
|
169
|
+
const result = await facade.releaseQuarantine(pid);
|
|
170
|
+
writeValue(ctx, { ok: true, id: pid, changed: result.changed }, 'Released plugin quarantine for ' + pid + '. The plugin remains untrusted until explicitly trusted again.\n');
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
throw new Error('Unsupported plugin operation: ' + op);
|
|
174
|
+
}
|
|
175
|
+
export async function runCustomCommand(ctx, args0, catalog = createWorkflowCatalog({ projectRoot: ctx.projectRoot, repoRoot: ctx.repoRoot, paths: ctx.paths })) {
|
|
176
|
+
const a = [...args0], op = a.shift() ?? 'list';
|
|
177
|
+
if (op === 'list') {
|
|
178
|
+
assertNoUnknownOptions(a);
|
|
179
|
+
if (a.length)
|
|
180
|
+
throw new Error('COMMAND_LIST_TAKES_NO_ARGUMENTS');
|
|
181
|
+
const rows = await catalog.list();
|
|
182
|
+
const human = renderWorkflowCenterLines(createWorkflowCenterModel(rows, 0)).join('\n') + '\n';
|
|
183
|
+
writeValue(ctx, rows, human);
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
if (op === 'show') {
|
|
187
|
+
const selector = a.shift();
|
|
188
|
+
if (!selector)
|
|
189
|
+
throw new Error('COMMAND_NAME_REQUIRED');
|
|
190
|
+
assertNoUnknownOptions(a);
|
|
191
|
+
if (a.length)
|
|
192
|
+
throw new Error('COMMAND_SHOW_TAKES_ONE_NAME');
|
|
193
|
+
const row = await catalog.show(selector);
|
|
194
|
+
const human = renderWorkflowCenterLines(createWorkflowCenterModel([row], 0)).join('\n') + '\n';
|
|
195
|
+
writeValue(ctx, row, human);
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
if (op === 'run') {
|
|
199
|
+
const selector = a.shift();
|
|
200
|
+
if (!selector)
|
|
201
|
+
throw new Error('COMMAND_NAME_REQUIRED');
|
|
202
|
+
const result = await catalog.run(selector, a);
|
|
203
|
+
writeValue(ctx, result, result.prompt.endsWith('\n') ? result.prompt : result.prompt + '\n');
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
throw new Error('Unsupported command operation: ' + op);
|
|
207
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { assertNoUnknownOptions, takeFlag, writeValue } from "./context.js";
|
|
2
|
+
import { createTrustAuthority } from "../security/trust-authority.js";
|
|
3
|
+
import { t } from "../i18n/index.js";
|
|
4
|
+
import { inertProjectTrustText } from "../tui/project-trust-prompt.js";
|
|
5
|
+
function publicSnapshot(value, folder) {
|
|
6
|
+
return {
|
|
7
|
+
trusted: value.trusted, reason: value.reason, project: value.workspace.canonicalRoot, identity: value.workspace.identityHash,
|
|
8
|
+
nestedRepository: value.workspace.nestedRepository, nestedRepositories: value.nestedRepositories.map(entry => entry.relativePath),
|
|
9
|
+
resourceCount: value.resources.filter(row => row.current).length,
|
|
10
|
+
storeSchema: value.storeSchema, migrationRequired: value.migrationRequired, rollbackAvailable: value.rollbackAvailable,
|
|
11
|
+
resources: value.resources.map(row => ({ kind: row.kind, id: row.id, path: row.relativePath, state: row.state })),
|
|
12
|
+
/* R4 (gate E2): the folder decision, apart from the per-file snapshot. */
|
|
13
|
+
folder: { decided: folder.decided, source: folder.source, path: folder.path, sessionOnly: folder.sessionOnly }
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** `deps.homeDir` exists for tests: which folder counts as the home folder (default: the user's home). */
|
|
17
|
+
export async function runProjectCommand(ctx, args0, deps = {}) {
|
|
18
|
+
const args = [...args0];
|
|
19
|
+
const operation = args.shift() ?? 'status';
|
|
20
|
+
const includeNested = operation === 'trust' || operation === 'migrate-trust' ? takeFlag(args, '--include-nested') : false;
|
|
21
|
+
assertNoUnknownOptions(args);
|
|
22
|
+
if (args.length)
|
|
23
|
+
throw new Error('PROJECT_COMMAND_ARGUMENT_INVALID');
|
|
24
|
+
const authority = createTrustAuthority({ projectRoot: ctx.projectRoot, trustRoot: ctx.paths.trust.projects, ...(deps.homeDir ? { homeDir: deps.homeDir } : {}) });
|
|
25
|
+
const view = async (snapshot) => publicSnapshot(snapshot, await authority.folderDecision(snapshot));
|
|
26
|
+
if (operation === 'status') {
|
|
27
|
+
writeValue(ctx, await view(await authority.inspect()));
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
if (operation === 'trust') {
|
|
31
|
+
const before = await authority.inspect();
|
|
32
|
+
const folder = await authority.folderDecision(before);
|
|
33
|
+
/* Q-R4-1: the home folder and a drive root are never saved. Their project files still follow the snapshot rule. */
|
|
34
|
+
if (folder.sessionOnly) {
|
|
35
|
+
const sessionLine = t('firstrun.project.sessionOnly', { path: inertProjectTrustText(before.workspace.canonicalRoot) }) + '\n';
|
|
36
|
+
/* Q-R4-17: its files are trusted only by the interactive question, for that session; this command saves nothing. */
|
|
37
|
+
writeValue(ctx, publicSnapshot(before, folder), sessionLine);
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
if (before.trusted && folder.decided) {
|
|
41
|
+
writeValue(ctx, publicSnapshot(before, folder), before.migrationRequired ? `Project already trusted; run talos project migrate-trust to migrate the legacy store explicitly\n` : `Project already trusted ${before.workspace.canonicalRoot}\n`);
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
const verified = await authority.trustProject({ expected: before, includeNested });
|
|
45
|
+
writeValue(ctx, await view(verified), `Trusted project ${verified.workspace.canonicalRoot}\n`);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
if (operation === 'revoke') {
|
|
49
|
+
const revoked = await authority.revokeProject();
|
|
50
|
+
writeValue(ctx, await view(revoked), `Revoked project ${revoked.workspace.canonicalRoot}\n`);
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
if (operation === 'migrate-trust') {
|
|
54
|
+
const before = await authority.inspect();
|
|
55
|
+
if (before.storeSchema !== 'v1') {
|
|
56
|
+
writeValue(ctx, await view(before), before.storeSchema === 'v2' ? 'Project trust store is already v2; no migration was performed\n' : 'No legacy trust record to migrate\n');
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
const migrated = await authority.migrateLegacy({ includeNested });
|
|
60
|
+
writeValue(ctx, await view(migrated), `Project trust store migrated to v2; rollback backup: ${await authority.migrationBackupPath()}\n`);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
if (operation === 'rollback-trust-migration') {
|
|
64
|
+
const before = await authority.inspect();
|
|
65
|
+
if (!before.rollbackAvailable) {
|
|
66
|
+
writeValue(ctx, await view(before), 'No migration rollback backup is available\n');
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
const rolledBack = await authority.rollbackMigration();
|
|
70
|
+
writeValue(ctx, await view(rolledBack), `Rolled project trust store back to legacy v1\n`);
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Unsupported project operation: ${operation}`);
|
|
74
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const NAME = /^[a-z0-9][a-z0-9-]{0,63}$/u;
|
|
4
|
+
const MAX_FILE_BYTES = 65_536;
|
|
5
|
+
export const WORKFLOW_MAX_STEPS = 64;
|
|
6
|
+
export const WORKFLOW_MAX_TEXT_BYTES = 16_384;
|
|
7
|
+
function fail(code, message = code) { throw Object.assign(new Error(message), { code }); }
|
|
8
|
+
function textBytes(value) { return Buffer.byteLength(value, 'utf8'); }
|
|
9
|
+
function assertBoundedText(value, code, { allowEmpty = false } = {}) {
|
|
10
|
+
if (typeof value !== 'string' || (!allowEmpty && !value.trim()) || textBytes(value) > WORKFLOW_MAX_TEXT_BYTES)
|
|
11
|
+
fail(code);
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function exactKeys(value, allowed, code) {
|
|
15
|
+
if (Object.keys(value).some(key => !allowed.includes(key)))
|
|
16
|
+
fail(code);
|
|
17
|
+
}
|
|
18
|
+
function workflowSteps(raw) {
|
|
19
|
+
let value;
|
|
20
|
+
try {
|
|
21
|
+
value = JSON.parse(raw);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
fail('WORKFLOW_STEPS_INVALID');
|
|
25
|
+
}
|
|
26
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
27
|
+
fail('WORKFLOW_STEPS_INVALID');
|
|
28
|
+
if (value.length > WORKFLOW_MAX_STEPS)
|
|
29
|
+
fail('WORKFLOW_TOO_MANY_STEPS');
|
|
30
|
+
const steps = [];
|
|
31
|
+
for (const entry of value) {
|
|
32
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
33
|
+
fail('WORKFLOW_STEP_INVALID');
|
|
34
|
+
const row = entry;
|
|
35
|
+
if (row.type === 'prompt') {
|
|
36
|
+
exactKeys(row, ['type', 'template'], 'WORKFLOW_STEP_UNKNOWN_KEY');
|
|
37
|
+
steps.push({ type: 'prompt', template: assertBoundedText(row.template, 'WORKFLOW_PROMPT_INVALID') });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (row.type === 'skill') {
|
|
41
|
+
exactKeys(row, ['type', 'name'], 'WORKFLOW_STEP_UNKNOWN_KEY');
|
|
42
|
+
const name = assertBoundedText(row.name, 'WORKFLOW_SKILL_INVALID');
|
|
43
|
+
if (!NAME.test(name))
|
|
44
|
+
fail('WORKFLOW_SKILL_INVALID');
|
|
45
|
+
steps.push({ type: 'skill', name });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (row.type === 'command') {
|
|
49
|
+
exactKeys(row, ['type', 'name', 'args'], 'WORKFLOW_STEP_UNKNOWN_KEY');
|
|
50
|
+
const name = assertBoundedText(row.name, 'WORKFLOW_COMMAND_INVALID');
|
|
51
|
+
if (!NAME.test(name))
|
|
52
|
+
fail('WORKFLOW_COMMAND_INVALID');
|
|
53
|
+
const args = row.args ?? [];
|
|
54
|
+
if (!Array.isArray(args) || args.length > WORKFLOW_MAX_STEPS || !args.every(arg => typeof arg === 'string' && textBytes(arg) <= WORKFLOW_MAX_TEXT_BYTES))
|
|
55
|
+
fail('WORKFLOW_COMMAND_ARGS_INVALID');
|
|
56
|
+
steps.push({ type: 'command', name, args: [...args] });
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
fail('WORKFLOW_STEP_TYPE_INVALID');
|
|
60
|
+
}
|
|
61
|
+
return steps;
|
|
62
|
+
}
|
|
63
|
+
function parse(text, file) {
|
|
64
|
+
if (Buffer.byteLength(text) > MAX_FILE_BYTES)
|
|
65
|
+
throw new Error('COMMAND_TOO_LARGE');
|
|
66
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)([\s\S]*)$/u.exec(text);
|
|
67
|
+
if (!m)
|
|
68
|
+
throw new Error(`COMMAND_FRONT_MATTER_INVALID:${file}`);
|
|
69
|
+
const meta = {};
|
|
70
|
+
for (const line of m[1].split(/\r?\n/u)) {
|
|
71
|
+
if (!line.trim())
|
|
72
|
+
continue;
|
|
73
|
+
const mm = /^([A-Za-z]+):\s*(.*)$/u.exec(line);
|
|
74
|
+
if (!mm)
|
|
75
|
+
throw new Error('COMMAND_FRONT_MATTER_INVALID');
|
|
76
|
+
if (!['name', 'description', 'arguments', 'kind', 'steps'].includes(mm[1]))
|
|
77
|
+
throw new Error('COMMAND_FIELD_UNKNOWN');
|
|
78
|
+
if (Object.hasOwn(meta, mm[1]))
|
|
79
|
+
throw new Error('COMMAND_FIELD_DUPLICATE');
|
|
80
|
+
meta[mm[1]] = mm[2].replace(/^['"]|['"]$/gu, '');
|
|
81
|
+
}
|
|
82
|
+
if (!meta.name || !NAME.test(meta.name) || !meta.description)
|
|
83
|
+
throw new Error('COMMAND_FRONT_MATTER_INVALID');
|
|
84
|
+
const kind = meta.kind ?? 'command';
|
|
85
|
+
if (kind !== 'command' && kind !== 'workflow')
|
|
86
|
+
fail('WORKFLOW_KIND_INVALID');
|
|
87
|
+
const body = m[2].trim();
|
|
88
|
+
if (kind === 'command') {
|
|
89
|
+
if (meta.steps !== undefined)
|
|
90
|
+
fail('WORKFLOW_STEPS_FORBIDDEN');
|
|
91
|
+
return { name: meta.name, description: meta.description, arguments: meta.arguments ?? '', body, file, kind: 'command', steps: [] };
|
|
92
|
+
}
|
|
93
|
+
if (meta.steps === undefined)
|
|
94
|
+
fail('WORKFLOW_STEPS_REQUIRED');
|
|
95
|
+
if (body)
|
|
96
|
+
fail('WORKFLOW_BODY_FORBIDDEN');
|
|
97
|
+
return { name: meta.name, description: meta.description, arguments: meta.arguments ?? '', body: '', file, kind: 'workflow', steps: workflowSteps(meta.steps) };
|
|
98
|
+
}
|
|
99
|
+
export async function loadCommandFile(file) { return parse(await readFile(file, 'utf8'), file); }
|
|
100
|
+
async function markdownFiles(root) {
|
|
101
|
+
const out = [];
|
|
102
|
+
async function walk(dir) {
|
|
103
|
+
let entries;
|
|
104
|
+
try {
|
|
105
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
if (e?.code === 'ENOENT')
|
|
109
|
+
return;
|
|
110
|
+
throw e;
|
|
111
|
+
}
|
|
112
|
+
for (const e of entries) {
|
|
113
|
+
const p = join(dir, e.name);
|
|
114
|
+
if (e.isDirectory())
|
|
115
|
+
await walk(p);
|
|
116
|
+
else if (e.isFile() && e.name.endsWith('.md'))
|
|
117
|
+
out.push(p);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
await walk(root);
|
|
121
|
+
return out.sort();
|
|
122
|
+
}
|
|
123
|
+
export async function loadProjectCommands(root) {
|
|
124
|
+
const files = await markdownFiles(join(root, '.talos-cli', 'commands'));
|
|
125
|
+
const out = [];
|
|
126
|
+
const names = new Set();
|
|
127
|
+
for (const f of files) {
|
|
128
|
+
const c = await loadCommandFile(f);
|
|
129
|
+
if (names.has(c.name))
|
|
130
|
+
throw new Error('COMMAND_NAME_DUPLICATE');
|
|
131
|
+
names.add(c.name);
|
|
132
|
+
out.push(c);
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
export function expandCommand(c, vars) {
|
|
137
|
+
return c.body.replace(/\{\{([a-zA-Z0-9_-]+)\}\}/gu, (_m, n) => {
|
|
138
|
+
if (!Object.hasOwn(vars, n))
|
|
139
|
+
throw new Error(`COMMAND_VARIABLE_UNKNOWN:${n}`);
|
|
140
|
+
return vars[n];
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
export const renderProjectCommand = expandCommand;
|