talos-code 0.0.1 → 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/LICENSE +661 -0
- package/README.md +111 -3
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/archive/zip.js +73 -0
- package/dist/args.js +97 -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 +185 -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 +43 -0
- package/dist/i18n/en/common.js +9 -0
- package/dist/i18n/en/credentials.js +82 -0
- package/dist/i18n/en/errors.js +246 -0
- package/dist/i18n/en/firstrun.js +89 -0
- package/dist/i18n/en/providers.js +37 -0
- package/dist/i18n/en/screen.js +736 -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 +330 -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/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-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 +262 -0
- package/dist/runtime/talos-composition.js +1006 -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/app.js +3761 -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 +559 -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 +32 -0
- package/dist/tui/components/terminal-shell.js +205 -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/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 +139 -0
- package/dist/tui/line-diff.js +57 -0
- package/dist/tui/live-activity.js +45 -0
- package/dist/tui/metrics.js +123 -0
- package/dist/tui/onboarding.js +36 -0
- package/dist/tui/overlays/agent-tree.js +39 -0
- package/dist/tui/overlays/approval-dialog.js +640 -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 +72 -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 +145 -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 +287 -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 +778 -0
- package/dist/tui/session-export.js +54 -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 +80 -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 +25 -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 +63 -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,236 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { findTalosRepoRoot, importTalosModule } from "../runtime/repo.js";
|
|
5
|
+
const SCHEMA = 'talos.cli.task-board-edge.v1';
|
|
6
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,160}$/u;
|
|
7
|
+
const KINDS = new Set(['depends-on', 'evidence', 'agent', 'schedule']);
|
|
8
|
+
const STATUSES = new Set(['todo', 'doing', 'done']);
|
|
9
|
+
const PRIORITIES = new Set(['low', 'normal', 'high']);
|
|
10
|
+
function fail(code, message = code) { throw Object.assign(new Error(message), { code }); }
|
|
11
|
+
function validId(value, code = 'TASK_BOARD_ID_INVALID') { if (!ID.test(value) || value.includes('..'))
|
|
12
|
+
fail(code); return value; }
|
|
13
|
+
function edgeKind(value) { if (!KINDS.has(value))
|
|
14
|
+
fail('TASK_BOARD_EDGE_KIND_INVALID'); return value; }
|
|
15
|
+
function stringOrNull(value) { return typeof value === 'string' ? value : null; }
|
|
16
|
+
function numberOrNull(value) { return Number.isFinite(value) ? Number(value) : null; }
|
|
17
|
+
function requiredString(value, field) { if (typeof value !== 'string' || value.length === 0)
|
|
18
|
+
throw new TypeError('malformed task board row: ' + field); return value; }
|
|
19
|
+
function edgeKey(record) { return createHash('sha256').update(record.taskId + '\0' + record.kind + '\0' + record.targetId).digest('hex'); }
|
|
20
|
+
function parseEdge(value) {
|
|
21
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) || value.schema !== SCHEMA)
|
|
22
|
+
throw new TypeError('malformed task board edge');
|
|
23
|
+
return { schema: SCHEMA, taskId: validId(String(value.taskId ?? ''), 'TASK_BOARD_EDGE_INVALID'), kind: edgeKind(String(value.kind ?? '')), targetId: validId(String(value.targetId ?? ''), 'TASK_BOARD_EDGE_INVALID'), createdAt: requiredString(value.createdAt, 'createdAt') };
|
|
24
|
+
}
|
|
25
|
+
function edgeSort(a, b) { return a.kind.localeCompare(b.kind) || a.targetId.localeCompare(b.targetId) || a.createdAt.localeCompare(b.createdAt); }
|
|
26
|
+
function headerOf(records) { return Array.isArray(records) ? records.find(row => row?.tipo === 'intestazione') ?? null : null; }
|
|
27
|
+
function agentOutcome(records) {
|
|
28
|
+
if (!Array.isArray(records))
|
|
29
|
+
return 'unknown';
|
|
30
|
+
const terminal = [...records].reverse().find(row => row?.type === 'RunFinished' || row?.type === 'RunError');
|
|
31
|
+
if (!terminal)
|
|
32
|
+
return 'running';
|
|
33
|
+
return terminal.type === 'RunFinished' ? 'completed' : terminal.type === 'RunError' ? 'failed' : 'unknown';
|
|
34
|
+
}
|
|
35
|
+
function createsCycle(edges, source, target) {
|
|
36
|
+
const adjacency = new Map();
|
|
37
|
+
for (const edge of edges) {
|
|
38
|
+
if (edge.kind !== 'depends-on')
|
|
39
|
+
continue;
|
|
40
|
+
const rows = adjacency.get(edge.taskId);
|
|
41
|
+
if (rows)
|
|
42
|
+
rows.push(edge.targetId);
|
|
43
|
+
else
|
|
44
|
+
adjacency.set(edge.taskId, [edge.targetId]);
|
|
45
|
+
}
|
|
46
|
+
const seen = new Set(), stack = [target];
|
|
47
|
+
while (stack.length) {
|
|
48
|
+
const current = stack.pop();
|
|
49
|
+
if (current === source)
|
|
50
|
+
return true;
|
|
51
|
+
if (seen.has(current))
|
|
52
|
+
continue;
|
|
53
|
+
seen.add(current);
|
|
54
|
+
for (const next of adjacency.get(current) ?? [])
|
|
55
|
+
stack.push(next);
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
export function createTaskBoardFacade(input, deps = {}) {
|
|
60
|
+
const tasksRoot = join(input.paths.dataRoot, 'tasks');
|
|
61
|
+
const automationRoot = join(input.paths.dataRoot, 'automations');
|
|
62
|
+
const edgeRoot = join(input.paths.dataRoot, 'task-board-edges');
|
|
63
|
+
const repoRoot = () => input.repoRoot ?? (input.projectRoot ? findTalosRepoRoot(input.projectRoot) : fail('TASK_BOARD_REPO_ROOT_REQUIRED'));
|
|
64
|
+
let taskPromise = null, sessionPromise = null, automationPromise = null, evidenceModulePromise = null;
|
|
65
|
+
const taskStore = () => taskPromise ??= (deps.loadTaskStore ? deps.loadTaskStore() : importTalosModule(repoRoot(), 'tasks-store.mjs'));
|
|
66
|
+
const sessionStore = () => sessionPromise ??= (deps.loadSessionStore ? deps.loadSessionStore() : importTalosModule(repoRoot(), 'session-store.mjs'));
|
|
67
|
+
const automationStore = () => automationPromise ??= (deps.loadAutomationStore ? deps.loadAutomationStore() : (async () => { const mod = await importTalosModule(repoRoot(), 'automation-store.mjs'); return mod.createAutomationStore({ cartella: automationRoot }); })());
|
|
68
|
+
const measureEvidence = async (records) => {
|
|
69
|
+
if (deps.analyzeEvidence)
|
|
70
|
+
return deps.analyzeEvidence(records);
|
|
71
|
+
evidenceModulePromise ??= importTalosModule(repoRoot(), 'subagent-orchestrator.mjs');
|
|
72
|
+
const mod = await evidenceModulePromise;
|
|
73
|
+
return mod.analizzaEvidenzaDelega(records);
|
|
74
|
+
};
|
|
75
|
+
const defaultListEdges = async () => {
|
|
76
|
+
let names;
|
|
77
|
+
try {
|
|
78
|
+
names = await readdir(edgeRoot);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error?.code === 'ENOENT')
|
|
82
|
+
return [];
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
const edges = [];
|
|
86
|
+
for (const name of names.sort()) {
|
|
87
|
+
if (!name.endsWith('.json'))
|
|
88
|
+
continue;
|
|
89
|
+
edges.push(parseEdge(JSON.parse(await readFile(join(edgeRoot, name), 'utf8'))));
|
|
90
|
+
}
|
|
91
|
+
return edges.sort(edgeSort);
|
|
92
|
+
};
|
|
93
|
+
const defaultWriteEdge = async (record) => {
|
|
94
|
+
await mkdir(edgeRoot, { recursive: true, mode: 0o700 });
|
|
95
|
+
const key = edgeKey(record), final = join(edgeRoot, key + '.json'), tmp = join(edgeRoot, '.' + key + '.' + randomUUID() + '.tmp');
|
|
96
|
+
await writeFile(tmp, JSON.stringify(record, null, 2) + '\n', { encoding: 'utf8', mode: 0o600, flag: 'wx' });
|
|
97
|
+
try {
|
|
98
|
+
await rename(tmp, final);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
await rm(tmp, { force: true });
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const defaultDeleteEdge = async (record) => { await rm(join(edgeRoot, edgeKey(record) + '.json'), { force: true }); };
|
|
106
|
+
const listEdges = async () => { const raw = await (deps.listEdges ? deps.listEdges() : defaultListEdges()); if (!Array.isArray(raw))
|
|
107
|
+
throw new TypeError('malformed task board edge store'); return raw.map(parseEdge).sort(edgeSort); };
|
|
108
|
+
const writeEdge = deps.writeEdge ?? defaultWriteEdge;
|
|
109
|
+
const deleteEdge = deps.deleteEdge ?? defaultDeleteEdge;
|
|
110
|
+
const now = deps.now ?? (() => new Date());
|
|
111
|
+
function publicTask(raw, store) {
|
|
112
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
113
|
+
throw new TypeError('malformed persisted task row: object');
|
|
114
|
+
const shaped = typeof store.formaPubblicaAttivita === 'function' ? store.formaPubblicaAttivita(raw) : raw;
|
|
115
|
+
const id = validId(requiredString(shaped?.id, 'id'), 'TASK_ID_INVALID'), title = requiredString(shaped?.titolo, 'titolo');
|
|
116
|
+
if (!STATUSES.has(shaped?.stato))
|
|
117
|
+
throw new TypeError('malformed persisted task row: stato');
|
|
118
|
+
if (!PRIORITIES.has(shaped?.priorita))
|
|
119
|
+
throw new TypeError('malformed persisted task row: priorita');
|
|
120
|
+
const writer = shaped?.origine === 'persona' ? 'persona' : 'modello';
|
|
121
|
+
const writerEvidence = (raw.origine === 'persona' || raw.origine === 'modello') ? 'persisted' : 'derived-legacy-default';
|
|
122
|
+
return { id, title, description: stringOrNull(shaped?.descrizione), status: shaped.stato, priority: shaped.priorita, writer, writerEvidence, createdAt: stringOrNull(shaped?.creataAlle), updatedAt: stringOrNull(shaped?.aggiornataAlle) };
|
|
123
|
+
}
|
|
124
|
+
async function exactTask(taskId) { const wanted = validId(taskId, 'TASK_ID_INVALID'), store = await taskStore(), raw = await store.leggiAttivita({ cartella: tasksRoot, id: wanted }); if (!raw || raw.id !== wanted)
|
|
125
|
+
fail('TASK_NOT_FOUND'); return { wanted, store, raw }; }
|
|
126
|
+
async function sessionRecords(sessionId, required = false) { const records = await (await sessionStore()).leggiRegistro({ cartellaStore: input.paths.sessionsRoot, sessionId }), header = headerOf(records); const exact = Array.isArray(records) && header?.sessionId === sessionId ? records : null; if (!exact && required)
|
|
127
|
+
fail('TASK_BOARD_TARGET_NOT_FOUND'); return exact; }
|
|
128
|
+
async function dependencyView(edge) {
|
|
129
|
+
const row = await (await taskStore()).leggiAttivita({ cartella: tasksRoot, id: edge.targetId });
|
|
130
|
+
const exact = row?.id === edge.targetId ? row : null;
|
|
131
|
+
return { taskId: edge.taskId, targetTaskId: edge.targetId, state: exact ? 'available' : 'dangling', label: exact ? stringOrNull(exact.titolo) : null, createdAt: edge.createdAt };
|
|
132
|
+
}
|
|
133
|
+
async function evidenceView(edge) {
|
|
134
|
+
const records = await sessionRecords(edge.targetId, false);
|
|
135
|
+
return { taskId: edge.taskId, sessionId: edge.targetId, state: records ? 'available' : 'dangling', measurement: records ? await measureEvidence(records) : null, createdAt: edge.createdAt };
|
|
136
|
+
}
|
|
137
|
+
async function agentView(edge) {
|
|
138
|
+
const records = await sessionRecords(edge.targetId, false), header = headerOf(records);
|
|
139
|
+
const delegated = header && typeof header.padreId === 'string' && header.padreId.length > 0 && Number.isSafeInteger(header.profonditaDelega) && header.profonditaDelega > 0 && typeof header.taskId === 'string' && header.taskId.startsWith('delega:');
|
|
140
|
+
return { taskId: edge.taskId, sessionId: edge.targetId, state: delegated ? 'available' : 'dangling', parentSessionId: delegated ? header.padreId : null, depth: delegated ? Number(header.profonditaDelega) : null, task: delegated ? stringOrNull(header.task?.consegnaCorta ?? header.task?.consegna) : null, outcome: delegated ? agentOutcome(records) : 'unknown', createdAt: edge.createdAt };
|
|
141
|
+
}
|
|
142
|
+
async function scheduleView(edge) {
|
|
143
|
+
const row = await (await automationStore()).leggi(edge.targetId), exact = row?.id === edge.targetId ? row : null;
|
|
144
|
+
return { taskId: edge.taskId, automationId: edge.targetId, state: exact ? 'available' : 'dangling', executionTaskId: exact ? stringOrNull(exact.taskId) : null, name: exact ? stringOrNull(exact.nome) : null, intervalMinutes: exact ? numberOrNull(exact.intervalloMinuti) : null, dailyLimit: exact ? numberOrNull(exact.limiteAlGiorno) : null, active: exact ? Boolean(exact.attiva) : null, lastExecution: exact ? stringOrNull(exact.ultimaEsecuzione) : null, nextExecution: exact ? stringOrNull(exact.prossimaEsecuzione) : null, createdAt: edge.createdAt };
|
|
145
|
+
}
|
|
146
|
+
async function projectTask(raw, store, edges) {
|
|
147
|
+
const base = publicTask(raw, store), mine = edges.filter(edge => edge.taskId === base.id);
|
|
148
|
+
const dependencies = [], evidence = [], agents = [], schedules = [];
|
|
149
|
+
for (const edge of mine) {
|
|
150
|
+
if (edge.kind === 'depends-on')
|
|
151
|
+
dependencies.push(await dependencyView(edge));
|
|
152
|
+
else if (edge.kind === 'evidence')
|
|
153
|
+
evidence.push(await evidenceView(edge));
|
|
154
|
+
else if (edge.kind === 'agent')
|
|
155
|
+
agents.push(await agentView(edge));
|
|
156
|
+
else
|
|
157
|
+
schedules.push(await scheduleView(edge));
|
|
158
|
+
}
|
|
159
|
+
return { ...base, dependencies, evidence, agents, schedules };
|
|
160
|
+
}
|
|
161
|
+
function invalid(error) { return { state: 'invalid', rows: [], error: { code: 'TASK_BOARD_INVALID', message: error instanceof Error ? error.message : String(error) }, legacyRows: [] }; }
|
|
162
|
+
const list = async () => {
|
|
163
|
+
try {
|
|
164
|
+
const store = await taskStore(), raw = await store.elencaAttivita({ cartella: tasksRoot });
|
|
165
|
+
if (!Array.isArray(raw))
|
|
166
|
+
throw new TypeError('malformed persisted task list');
|
|
167
|
+
const edges = await listEdges(), rows = [];
|
|
168
|
+
for (const item of raw)
|
|
169
|
+
rows.push(await projectTask(item, store, edges));
|
|
170
|
+
return { state: 'ready', rows, error: null, legacyRows: raw };
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return invalid(error);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const add = async (value) => { const store = await taskStore(), legacy = await store.creaAttivita({ cartella: tasksRoot, title: value.title, description: value.description ?? null, priority: value.priority ?? 'normal', origine: 'persona' }); return { legacy }; };
|
|
177
|
+
const update = async (taskId, value) => { const store = await taskStore(), wanted = validId(taskId, 'TASK_ID_INVALID'), legacy = await store.aggiornaAttivita({ cartella: tasksRoot, id: wanted, ...(value.title !== undefined ? { title: value.title } : {}), ...(value.description !== undefined ? { description: value.description } : {}), ...(value.priority !== undefined ? { priority: value.priority } : {}) }); return { legacy }; };
|
|
178
|
+
const complete = async (taskId, status = 'done') => { const store = await taskStore(), wanted = validId(taskId, 'TASK_ID_INVALID'), legacy = await store.completaAttivita({ cartella: tasksRoot, id: wanted, status }); return { legacy }; };
|
|
179
|
+
const deleteTask = async (taskId) => { const store = await taskStore(), wanted = validId(taskId, 'TASK_ID_INVALID'); await store.eliminaAttivita({ cartella: tasksRoot, id: wanted }); return { legacy: { ok: true, id: wanted } }; };
|
|
180
|
+
async function validateTarget(kind, targetId) {
|
|
181
|
+
if (kind === 'depends-on') {
|
|
182
|
+
const row = await (await taskStore()).leggiAttivita({ cartella: tasksRoot, id: targetId });
|
|
183
|
+
if (!row || row.id !== targetId)
|
|
184
|
+
fail('TASK_BOARD_TARGET_NOT_FOUND');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (kind === 'schedule') {
|
|
188
|
+
const row = await (await automationStore()).leggi(targetId);
|
|
189
|
+
if (!row || row.id !== targetId)
|
|
190
|
+
fail('TASK_BOARD_TARGET_NOT_FOUND');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const records = await sessionRecords(targetId, true);
|
|
194
|
+
if (kind === 'evidence') {
|
|
195
|
+
await measureEvidence(records);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (kind === 'agent') {
|
|
199
|
+
const header = headerOf(records);
|
|
200
|
+
if (!header || typeof header.padreId !== 'string' || !header.padreId || !Number.isSafeInteger(header.profonditaDelega) || header.profonditaDelega <= 0 || typeof header.taskId !== 'string' || !header.taskId.startsWith('delega:'))
|
|
201
|
+
fail('TASK_AGENT_NOT_DELEGATED');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async function addEdge(taskId, kind, targetId) {
|
|
205
|
+
const source = await exactTask(taskId), target = validId(targetId, 'TASK_BOARD_TARGET_INVALID'), typed = edgeKind(kind);
|
|
206
|
+
if (typed === 'depends-on' && source.wanted === target)
|
|
207
|
+
fail('TASK_DEPENDENCY_SELF');
|
|
208
|
+
await validateTarget(typed, target);
|
|
209
|
+
const edges = await listEdges(), existing = edges.find(edge => edge.taskId === source.wanted && edge.kind === typed && edge.targetId === target);
|
|
210
|
+
if (existing)
|
|
211
|
+
return { changed: false, edge: existing };
|
|
212
|
+
if (typed === 'depends-on' && createsCycle(edges, source.wanted, target))
|
|
213
|
+
fail('TASK_DEPENDENCY_CYCLE');
|
|
214
|
+
const record = { schema: SCHEMA, taskId: source.wanted, kind: typed, targetId: target, createdAt: now().toISOString() };
|
|
215
|
+
await writeEdge(record);
|
|
216
|
+
return { changed: true, edge: record };
|
|
217
|
+
}
|
|
218
|
+
async function removeEdge(taskId, kind, targetId) {
|
|
219
|
+
const source = validId(taskId, 'TASK_ID_INVALID'), target = validId(targetId, 'TASK_BOARD_TARGET_INVALID'), typed = edgeKind(kind), existing = (await listEdges()).find(edge => edge.taskId === source && edge.kind === typed && edge.targetId === target);
|
|
220
|
+
if (!existing)
|
|
221
|
+
return { changed: false, taskId: source, kind: typed, targetId: target };
|
|
222
|
+
await deleteEdge(existing);
|
|
223
|
+
return { changed: true, taskId: source, kind: typed, targetId: target };
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
list, add, update, complete, delete: deleteTask,
|
|
227
|
+
depend: (taskId, targetTaskId) => addEdge(taskId, 'depends-on', targetTaskId),
|
|
228
|
+
undepend: (taskId, targetTaskId) => removeEdge(taskId, 'depends-on', targetTaskId),
|
|
229
|
+
addEvidence: (taskId, sessionId) => addEdge(taskId, 'evidence', sessionId),
|
|
230
|
+
removeEvidence: (taskId, sessionId) => removeEdge(taskId, 'evidence', sessionId),
|
|
231
|
+
assignAgent: (taskId, sessionId) => addEdge(taskId, 'agent', sessionId),
|
|
232
|
+
unassignAgent: (taskId, sessionId) => removeEdge(taskId, 'agent', sessionId),
|
|
233
|
+
attachSchedule: (taskId, automationId) => addEdge(taskId, 'schedule', automationId),
|
|
234
|
+
detachSchedule: (taskId, automationId) => removeEdge(taskId, 'schedule', automationId),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { readdir } from 'node:fs/promises';
|
|
2
|
+
import { basename, join, relative } from 'node:path';
|
|
3
|
+
import { findTalosRepoRoot, importTalosModule } from "../runtime/repo.js";
|
|
4
|
+
import { createTrustAuthority } from "../security/trust-authority.js";
|
|
5
|
+
import { loadCommandFile, renderProjectCommand } from "../commands/project-commands.js";
|
|
6
|
+
function fail(code, message = code) { throw Object.assign(new Error(message), { code }); }
|
|
7
|
+
function errorCode(error, fallback) {
|
|
8
|
+
const code = error?.code;
|
|
9
|
+
if (typeof code === 'string' && code)
|
|
10
|
+
return code;
|
|
11
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12
|
+
const match = /^([A-Z][A-Z0-9_]+)/u.exec(message);
|
|
13
|
+
return match?.[1] ?? fallback;
|
|
14
|
+
}
|
|
15
|
+
function errorMessage(error) { return error instanceof Error ? error.message : String(error); }
|
|
16
|
+
function slash(value) { return value.split('\\').join('/'); }
|
|
17
|
+
function stripMd(value) { return value.toLowerCase().endsWith('.md') ? value.slice(0, -3) : value; }
|
|
18
|
+
async function markdownFiles(root) {
|
|
19
|
+
const out = [];
|
|
20
|
+
async function walk(dir) {
|
|
21
|
+
let entries;
|
|
22
|
+
try {
|
|
23
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error.code === 'ENOENT')
|
|
27
|
+
return;
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const file = join(dir, entry.name);
|
|
32
|
+
if (entry.isDirectory())
|
|
33
|
+
await walk(file);
|
|
34
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md'))
|
|
35
|
+
out.push(file);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
await walk(root);
|
|
39
|
+
return out.sort();
|
|
40
|
+
}
|
|
41
|
+
function stableId(scope, root, file) { return scope + ':' + stripMd(slash(relative(root, file))); }
|
|
42
|
+
function projectPath(root, file) { return '.talos-cli/commands/' + slash(relative(root, file)); }
|
|
43
|
+
function invalidName(file) { return stripMd(basename(file)); }
|
|
44
|
+
function vars(args) { return Object.fromEntries(args.map((value, index) => ['arg' + (index + 1), value])); }
|
|
45
|
+
function expandText(template, values) {
|
|
46
|
+
return template.replace(/\{\{([a-zA-Z0-9_-]+)\}\}/gu, (_match, name) => {
|
|
47
|
+
if (!Object.hasOwn(values, name))
|
|
48
|
+
throw Object.assign(new Error('COMMAND_VARIABLE_UNKNOWN:' + name), { code: 'COMMAND_VARIABLE_UNKNOWN' });
|
|
49
|
+
return values[name];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function resourceTrust(snapshot, path) {
|
|
53
|
+
const resource = snapshot.resources.find(row => row.kind === 'command' && row.relativePath === path);
|
|
54
|
+
if (!resource)
|
|
55
|
+
return { required: true, trusted: false, state: 'untracked', currentFingerprint: null, trustedFingerprint: null };
|
|
56
|
+
return { required: true, trusted: resource.state === 'trusted', state: resource.state, currentFingerprint: resource.currentFingerprint ?? null, trustedFingerprint: resource.trustedFingerprint ?? null };
|
|
57
|
+
}
|
|
58
|
+
function userTrust() { return { required: false, trusted: true, state: 'user-controlled', currentFingerprint: null, trustedFingerprint: null }; }
|
|
59
|
+
function skillTrust() { return { required: false, trusted: true, state: 'inert-text', currentFingerprint: null, trustedFingerprint: null }; }
|
|
60
|
+
function validation(valid, code = null, message = null) { return { valid, code, message }; }
|
|
61
|
+
export function createWorkflowCatalog(input, deps = {}) {
|
|
62
|
+
const authority = deps.authority ?? createTrustAuthority({ projectRoot: input.projectRoot, trustRoot: input.paths.trust.projects });
|
|
63
|
+
const repoRoot = () => input.repoRoot ?? findTalosRepoRoot(input.projectRoot);
|
|
64
|
+
const loadSkills = deps.loadSkills ?? (async () => {
|
|
65
|
+
const mod = await importTalosModule(repoRoot(), 'skill-registry.mjs');
|
|
66
|
+
const loaded = await mod.caricaSkill({ cartella: input.projectRoot });
|
|
67
|
+
if (!loaded || !Array.isArray(loaded.skills))
|
|
68
|
+
fail('SKILL_REGISTRY_INVALID');
|
|
69
|
+
return { skills: loaded.skills };
|
|
70
|
+
});
|
|
71
|
+
async function build() {
|
|
72
|
+
const projectRoot = join(input.projectRoot, '.talos-cli', 'commands');
|
|
73
|
+
const userRoot = join(input.paths.configRoot, 'commands');
|
|
74
|
+
const [projectFiles, userFiles, snapshot] = await Promise.all([markdownFiles(projectRoot), markdownFiles(userRoot), authority.inspect()]);
|
|
75
|
+
const sources = new Map();
|
|
76
|
+
async function addCommand(scope, root, file) {
|
|
77
|
+
const id = stableId(scope, root, file);
|
|
78
|
+
const provenance = scope === 'project'
|
|
79
|
+
? { scope: 'project-command', path: projectPath(projectRoot, file) }
|
|
80
|
+
: { scope: 'user-command', path: 'commands/' + slash(relative(userRoot, file)) };
|
|
81
|
+
const trust = scope === 'project' ? resourceTrust(snapshot, provenance.path) : userTrust();
|
|
82
|
+
try {
|
|
83
|
+
const command = await loadCommandFile(file);
|
|
84
|
+
const row = {
|
|
85
|
+
id, kind: command.kind, name: command.name, description: command.description, arguments: command.arguments,
|
|
86
|
+
provenance, validation: validation(true), trust,
|
|
87
|
+
executableSteps: command.kind === 'workflow' ? command.steps.filter(step => step.type === 'command').length : 1,
|
|
88
|
+
references: []
|
|
89
|
+
};
|
|
90
|
+
sources.set(id, { row, command, steps: command.steps });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
const code = errorCode(error, 'COMMAND_INVALID');
|
|
94
|
+
const row = {
|
|
95
|
+
id, kind: 'command', name: invalidName(file), description: null, arguments: '', provenance,
|
|
96
|
+
validation: validation(false, code, errorMessage(error)), trust, executableSteps: 0, references: []
|
|
97
|
+
};
|
|
98
|
+
sources.set(id, { row });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
for (const file of projectFiles)
|
|
102
|
+
await addCommand('project', projectRoot, file);
|
|
103
|
+
for (const file of userFiles)
|
|
104
|
+
await addCommand('user', userRoot, file);
|
|
105
|
+
try {
|
|
106
|
+
const loaded = await loadSkills();
|
|
107
|
+
for (const skill of loaded.skills) {
|
|
108
|
+
if (!skill || typeof skill.id !== 'string' || typeof skill.name !== 'string' || typeof skill.description !== 'string' || typeof skill.corpo !== 'string') {
|
|
109
|
+
fail('SKILL_REGISTRY_INVALID');
|
|
110
|
+
}
|
|
111
|
+
const id = 'skill:' + skill.id;
|
|
112
|
+
const row = {
|
|
113
|
+
id, kind: 'skill', name: skill.name, description: skill.description, arguments: '',
|
|
114
|
+
provenance: { scope: 'project-skill', path: '.harness-ui-skills/' + skill.id + '/SKILL.md' },
|
|
115
|
+
validation: validation(true), trust: skillTrust(), executableSteps: 0, references: []
|
|
116
|
+
};
|
|
117
|
+
sources.set(id, { row, skill });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
const code = errorCode(error, 'SKILL_REGISTRY_INVALID');
|
|
122
|
+
const row = {
|
|
123
|
+
id: 'skill:registry-error', kind: 'skill', name: 'registry-error', description: null, arguments: '',
|
|
124
|
+
provenance: { scope: 'project-skill', path: '.harness-ui-skills' },
|
|
125
|
+
validation: validation(false, code, errorMessage(error)), trust: skillTrust(), executableSteps: 0, references: []
|
|
126
|
+
};
|
|
127
|
+
sources.set(row.id, { row });
|
|
128
|
+
}
|
|
129
|
+
const commandByName = (name) => [...sources.values()].filter(source => source.row.kind === 'command' && source.row.name === name);
|
|
130
|
+
const skillByName = (name) => [...sources.values()].filter(source => source.row.kind === 'skill' && source.row.validation.valid && source.row.name === name);
|
|
131
|
+
for (const source of sources.values()) {
|
|
132
|
+
if (source.row.kind !== 'workflow' || !source.row.validation.valid || !source.steps)
|
|
133
|
+
continue;
|
|
134
|
+
const refs = [];
|
|
135
|
+
let invalid = null;
|
|
136
|
+
for (const step of source.steps) {
|
|
137
|
+
if (step.type === 'prompt')
|
|
138
|
+
continue;
|
|
139
|
+
if (step.type === 'skill') {
|
|
140
|
+
const matches = skillByName(step.name);
|
|
141
|
+
const id = matches.length === 1 ? matches[0].row.id : null;
|
|
142
|
+
refs.push({ type: 'skill', name: step.name, id });
|
|
143
|
+
if (matches.length === 0)
|
|
144
|
+
invalid = validation(false, 'WORKFLOW_SKILL_NOT_FOUND', 'Workflow skill not found: ' + step.name);
|
|
145
|
+
else if (matches.length > 1)
|
|
146
|
+
invalid = validation(false, 'WORKFLOW_SKILL_AMBIGUOUS', 'Workflow skill reference is ambiguous: ' + step.name);
|
|
147
|
+
if (invalid)
|
|
148
|
+
break;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const matches = commandByName(step.name);
|
|
152
|
+
const id = matches.length === 1 ? matches[0].row.id : null;
|
|
153
|
+
refs.push({ type: 'command', name: step.name, id });
|
|
154
|
+
if (matches.length === 0)
|
|
155
|
+
invalid = validation(false, 'WORKFLOW_COMMAND_NOT_FOUND', 'Workflow command not found: ' + step.name);
|
|
156
|
+
else if (matches.length > 1)
|
|
157
|
+
invalid = validation(false, 'WORKFLOW_COMMAND_AMBIGUOUS', 'Workflow command reference is ambiguous: ' + step.name);
|
|
158
|
+
else if (!matches[0].row.validation.valid)
|
|
159
|
+
invalid = validation(false, 'WORKFLOW_COMMAND_INVALID', 'Workflow command target is invalid: ' + step.name);
|
|
160
|
+
if (invalid)
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
source.row.references = refs;
|
|
164
|
+
if (invalid)
|
|
165
|
+
source.row.validation = invalid;
|
|
166
|
+
}
|
|
167
|
+
const rows = [...sources.values()].map(source => source.row).sort((a, b) => a.id.localeCompare(b.id));
|
|
168
|
+
return { rows, sources };
|
|
169
|
+
}
|
|
170
|
+
function resolve(build, selector, { runnable = false } = {}) {
|
|
171
|
+
const direct = build.sources.get(selector);
|
|
172
|
+
if (direct) {
|
|
173
|
+
if (runnable && direct.row.kind === 'skill')
|
|
174
|
+
fail('WORKFLOW_ENTRY_NOT_RUNNABLE');
|
|
175
|
+
return direct;
|
|
176
|
+
}
|
|
177
|
+
const matches = [...build.sources.values()].filter(source => source.row.name === selector && (!runnable || source.row.kind !== 'skill'));
|
|
178
|
+
if (matches.length === 0)
|
|
179
|
+
fail('WORKFLOW_ENTRY_NOT_FOUND');
|
|
180
|
+
if (matches.length > 1)
|
|
181
|
+
fail('WORKFLOW_ENTRY_AMBIGUOUS');
|
|
182
|
+
return matches[0];
|
|
183
|
+
}
|
|
184
|
+
function assertValid(source) { if (!source.row.validation.valid)
|
|
185
|
+
fail(source.row.validation.code ?? 'WORKFLOW_ENTRY_INVALID', source.row.validation.message ?? source.row.validation.code ?? 'WORKFLOW_ENTRY_INVALID'); }
|
|
186
|
+
function assertRunnableTrust(source, step = false) {
|
|
187
|
+
if (source.row.trust.required && !source.row.trust.trusted)
|
|
188
|
+
fail(step ? 'WORKFLOW_STEP_TRUST_REQUIRED' : 'WORKFLOW_TRUST_REQUIRED');
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
async list() { return (await build()).rows; },
|
|
192
|
+
async show(selector) { const built = await build(); return resolve(built, selector).row; },
|
|
193
|
+
async run(selector, args = []) {
|
|
194
|
+
const built = await build();
|
|
195
|
+
const source = resolve(built, selector, { runnable: true });
|
|
196
|
+
assertValid(source);
|
|
197
|
+
assertRunnableTrust(source);
|
|
198
|
+
if (!source.command)
|
|
199
|
+
fail('WORKFLOW_ENTRY_INVALID');
|
|
200
|
+
const values = vars(args);
|
|
201
|
+
if (source.row.kind === 'command') {
|
|
202
|
+
const prompt = renderProjectCommand(source.command, values);
|
|
203
|
+
return { id: source.row.id, kind: 'command', prompt, steps: [] };
|
|
204
|
+
}
|
|
205
|
+
const rendered = [];
|
|
206
|
+
const chunks = [];
|
|
207
|
+
for (const step of source.steps ?? []) {
|
|
208
|
+
if (step.type === 'prompt') {
|
|
209
|
+
const text = expandText(step.template, values);
|
|
210
|
+
chunks.push(text);
|
|
211
|
+
rendered.push({ type: 'prompt', name: null, id: null, text });
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (step.type === 'skill') {
|
|
215
|
+
const matches = [...built.sources.values()].filter(candidate => candidate.row.kind === 'skill' && candidate.row.validation.valid && candidate.row.name === step.name);
|
|
216
|
+
if (matches.length === 0)
|
|
217
|
+
fail('WORKFLOW_SKILL_NOT_FOUND');
|
|
218
|
+
if (matches.length > 1)
|
|
219
|
+
fail('WORKFLOW_SKILL_AMBIGUOUS');
|
|
220
|
+
const target = matches[0];
|
|
221
|
+
if (!target.skill)
|
|
222
|
+
fail('WORKFLOW_SKILL_INVALID');
|
|
223
|
+
const text = target.skill.corpo;
|
|
224
|
+
chunks.push(text);
|
|
225
|
+
rendered.push({ type: 'skill', name: step.name, id: target.row.id, text });
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const matches = [...built.sources.values()].filter(candidate => candidate.row.kind === 'command' && candidate.row.name === step.name);
|
|
229
|
+
if (matches.length === 0)
|
|
230
|
+
fail('WORKFLOW_COMMAND_NOT_FOUND');
|
|
231
|
+
if (matches.length > 1)
|
|
232
|
+
fail('WORKFLOW_COMMAND_AMBIGUOUS');
|
|
233
|
+
const target = matches[0];
|
|
234
|
+
assertValid(target);
|
|
235
|
+
assertRunnableTrust(target, true);
|
|
236
|
+
if (!target.command)
|
|
237
|
+
fail('WORKFLOW_COMMAND_INVALID');
|
|
238
|
+
const expandedArgs = step.args.map(value => expandText(value, values));
|
|
239
|
+
const text = renderProjectCommand(target.command, vars(expandedArgs));
|
|
240
|
+
chunks.push(text);
|
|
241
|
+
rendered.push({ type: 'command', name: step.name, id: target.row.id, text });
|
|
242
|
+
}
|
|
243
|
+
return { id: source.row.id, kind: 'workflow', prompt: chunks.join('\n\n'), steps: rendered };
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* R5b D1 (owner decision Q-R5-12, gate E16): a session as Markdown that a person can read — their own messages, TALOS's
|
|
3
|
+
* answers and the tools in English with their target, in order. Before R5b `session-cli.ts` exportMarkdown wrote only the
|
|
4
|
+
* model's text deltas and `> Tool: leggi`: the person's messages (kept by the kernel only as `RunStarted.input`, R1 lane R)
|
|
5
|
+
* were lost. Secrets are redacted with the same redactor the rest of the CLI uses. Shared by `talos session export --format
|
|
6
|
+
* md` and the TUI's `/export`. JSON and JSONL stay the kernel's own lossless rows.
|
|
7
|
+
*/
|
|
8
|
+
import { createRedactor } from "../diagnostics/redact.js";
|
|
9
|
+
import { describeError, errorViewLines } from "../i18n/error-view.js";
|
|
10
|
+
import { runPrompt } from "../tui/event-adapter.js";
|
|
11
|
+
import { toolDisplay } from "../tui/tool-display.js";
|
|
12
|
+
const text = (value) => typeof value === 'string' ? value : '';
|
|
13
|
+
export function exportMarkdown(payload, { secrets = [] } = {}) {
|
|
14
|
+
const redactor = createRedactor(secrets);
|
|
15
|
+
const title = text(payload?.name).trim();
|
|
16
|
+
const out = [`# TALOS session ${text(payload?.sessionId)}${title ? ` · ${title}` : ''}`];
|
|
17
|
+
const events = Array.isArray(payload?.eventi) ? payload.eventi : [];
|
|
18
|
+
const answers = new Map(), toolNames = new Map(), toolArgs = new Map();
|
|
19
|
+
let speaker = null;
|
|
20
|
+
const say = (who, body) => {
|
|
21
|
+
if (!body.trim())
|
|
22
|
+
return;
|
|
23
|
+
if (speaker !== who) {
|
|
24
|
+
out.push('', who === 'you' ? '## You' : '## TALOS', '');
|
|
25
|
+
speaker = who;
|
|
26
|
+
}
|
|
27
|
+
out.push(body.trim());
|
|
28
|
+
};
|
|
29
|
+
const toolLine = (id) => {
|
|
30
|
+
const name = toolNames.get(id) ?? 'tool';
|
|
31
|
+
let args = {};
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(toolArgs.get(id) ?? '{}');
|
|
34
|
+
if (parsed && typeof parsed === 'object')
|
|
35
|
+
args = parsed;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
args = {};
|
|
39
|
+
}
|
|
40
|
+
const shown = toolDisplay(name, args);
|
|
41
|
+
return `- ${[shown.label, shown.primaryArg].filter(Boolean).join(' ')}`;
|
|
42
|
+
};
|
|
43
|
+
for (const event of events) {
|
|
44
|
+
const type = text(event?.type);
|
|
45
|
+
if (type === 'RunStarted') {
|
|
46
|
+
const prompt = runPrompt(event.input);
|
|
47
|
+
if (prompt)
|
|
48
|
+
say('you', prompt);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (type === 'TextMessageStart') {
|
|
52
|
+
if (event.role === 'user')
|
|
53
|
+
continue;
|
|
54
|
+
answers.set(text(event.messageId), '');
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (type === 'TextMessageContent') {
|
|
58
|
+
const id = text(event.messageId);
|
|
59
|
+
if (answers.has(id) || !id)
|
|
60
|
+
answers.set(id, (answers.get(id) ?? '') + text(event.delta));
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (type === 'TextMessageEnd') {
|
|
64
|
+
const id = text(event.messageId);
|
|
65
|
+
say('talos', answers.get(id) ?? '');
|
|
66
|
+
answers.delete(id);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (type === 'ToolCallStart') {
|
|
70
|
+
toolNames.set(text(event.toolCallId), text(event.toolCallName) || text(event.name));
|
|
71
|
+
toolArgs.set(text(event.toolCallId), '');
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (type === 'ToolCallArgs') {
|
|
75
|
+
const id = text(event.toolCallId);
|
|
76
|
+
toolArgs.set(id, (toolArgs.get(id) ?? '') + text(event.delta));
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (type === 'ToolCallEnd') {
|
|
80
|
+
const id = text(event.toolCallId);
|
|
81
|
+
if (toolNames.has(id)) {
|
|
82
|
+
say('talos', toolLine(id));
|
|
83
|
+
toolNames.delete(id);
|
|
84
|
+
}
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (type === 'RunError') {
|
|
88
|
+
say('talos', `**${errorViewLines(describeError({ code: event.code, message: event.message }))[0] ?? 'The run failed.'}**`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/* An answer still streaming when the log ended is kept, not dropped. */
|
|
93
|
+
for (const body of answers.values())
|
|
94
|
+
say('talos', body);
|
|
95
|
+
for (const id of toolNames.keys())
|
|
96
|
+
say('talos', toolLine(id));
|
|
97
|
+
return redactor.text(`${out.join('\n')}\n`);
|
|
98
|
+
}
|