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,102 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { lstat, realpath } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { normalizeProjectRoot } from "../paths.js";
|
|
5
|
+
async function exists(pathname) {
|
|
6
|
+
try {
|
|
7
|
+
await lstat(pathname);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error.code === 'ENOENT')
|
|
12
|
+
return false;
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function inside(root, candidate) {
|
|
17
|
+
const relative = path.relative(root, candidate);
|
|
18
|
+
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
|
|
19
|
+
}
|
|
20
|
+
function strictlyInside(root, candidate) {
|
|
21
|
+
return candidate !== root && inside(root, candidate);
|
|
22
|
+
}
|
|
23
|
+
function canonicalWorkspaceCandidate(workspace, candidate) {
|
|
24
|
+
const resolved = path.resolve(candidate);
|
|
25
|
+
if (!inside(workspace.requestedRoot, resolved))
|
|
26
|
+
return resolved;
|
|
27
|
+
const relative = path.relative(workspace.requestedRoot, resolved);
|
|
28
|
+
return path.resolve(workspace.canonicalRoot, relative);
|
|
29
|
+
}
|
|
30
|
+
export function isPathInsideWorkspace(workspace, candidate) {
|
|
31
|
+
return inside(workspace.canonicalRoot, canonicalWorkspaceCandidate(workspace, candidate));
|
|
32
|
+
}
|
|
33
|
+
/** Resolves an existing candidate through the filesystem and accepts it only when the real target stays inside the canonical workspace. */
|
|
34
|
+
export async function resolvePathInsideWorkspace(workspace, candidate) {
|
|
35
|
+
const resolved = path.resolve(candidate);
|
|
36
|
+
if (!inside(workspace.requestedRoot, resolved) && !inside(workspace.canonicalRoot, resolved))
|
|
37
|
+
return null;
|
|
38
|
+
let canonical;
|
|
39
|
+
try {
|
|
40
|
+
canonical = await realpath(resolved);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return inside(workspace.canonicalRoot, canonical) ? canonical : null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Innermost repository root strictly between the workspace root and the given resource, or null when the
|
|
49
|
+
* resource is covered by the workspace's own repository. Every comparison happens on paths already rooted at
|
|
50
|
+
* `canonicalRoot`, which `realpath` has collapsed, so short 8.3 names, the `\\?\` prefix, the UNC form and
|
|
51
|
+
* case differences are all resolved before this walk starts.
|
|
52
|
+
*/
|
|
53
|
+
async function innerRepositoryRoot(canonicalRoot, resource) {
|
|
54
|
+
let cursor = path.dirname(resource);
|
|
55
|
+
while (strictlyInside(canonicalRoot, cursor)) {
|
|
56
|
+
if (await exists(path.join(cursor, '.git')))
|
|
57
|
+
return cursor;
|
|
58
|
+
const parent = path.dirname(cursor);
|
|
59
|
+
if (parent === cursor)
|
|
60
|
+
break;
|
|
61
|
+
cursor = parent;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Groups the project's resources by the repository boundary they sit behind. An empty result means every
|
|
67
|
+
* resource belongs to the project's own repository, which is the common case and must stay indistinguishable
|
|
68
|
+
* from the behaviour before this function existed.
|
|
69
|
+
*/
|
|
70
|
+
export async function findNestedRepositories(workspace, resourcePaths) {
|
|
71
|
+
const found = new Map();
|
|
72
|
+
for (const relativePath of [...resourcePaths].sort()) {
|
|
73
|
+
const absolute = path.resolve(workspace.canonicalRoot, ...relativePath.split('/'));
|
|
74
|
+
if (!strictlyInside(workspace.canonicalRoot, absolute))
|
|
75
|
+
continue;
|
|
76
|
+
const root = await innerRepositoryRoot(workspace.canonicalRoot, absolute);
|
|
77
|
+
if (root === null)
|
|
78
|
+
continue;
|
|
79
|
+
const key = path.relative(workspace.canonicalRoot, root).split(path.sep).join('/');
|
|
80
|
+
const entry = found.get(key) ?? { relativePath: key, root, resources: [] };
|
|
81
|
+
entry.resources.push(relativePath);
|
|
82
|
+
found.set(key, entry);
|
|
83
|
+
}
|
|
84
|
+
return [...found.values()].sort((left, right) => left.relativePath.localeCompare(right.relativePath));
|
|
85
|
+
}
|
|
86
|
+
export async function resolveWorkspaceIdentity({ projectRoot }) {
|
|
87
|
+
const requestedRoot = path.resolve(projectRoot);
|
|
88
|
+
const canonicalRoot = await realpath(requestedRoot);
|
|
89
|
+
const repositoryRoots = [];
|
|
90
|
+
let cursor = canonicalRoot;
|
|
91
|
+
for (;;) {
|
|
92
|
+
if (await exists(path.join(cursor, '.git')))
|
|
93
|
+
repositoryRoots.push(cursor);
|
|
94
|
+
const parent = path.dirname(cursor);
|
|
95
|
+
if (parent === cursor)
|
|
96
|
+
break;
|
|
97
|
+
cursor = parent;
|
|
98
|
+
}
|
|
99
|
+
const normalized = normalizeProjectRoot(canonicalRoot);
|
|
100
|
+
const identityHash = createHash('sha256').update(`talos-workspace-v1\0${normalized}`).digest('hex');
|
|
101
|
+
return { requestedRoot, canonicalRoot, gitRoot: repositoryRoots[0] ?? null, nestedRepository: repositoryRoots.length > 1, identityHash };
|
|
102
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { findTalosRepoRoot, importTalosModule } from "../runtime/repo.js";
|
|
3
|
+
import { createAutomationPolicyStore } from "../automations/policy-store.js";
|
|
4
|
+
import { createAutomationHistoryStore } from "../automations/history-store.js";
|
|
5
|
+
import { dryRunAutomation } from "../automations/runner.js";
|
|
6
|
+
import { probeWindowsAutomationRunner } from "../automations/windows-task.js";
|
|
7
|
+
import { validateTimeZone } from "../automations/schedule.js";
|
|
8
|
+
function fail(code) { throw Object.assign(new Error(code), { code }); }
|
|
9
|
+
function rowOf(row, policy) {
|
|
10
|
+
if (!row || typeof row.id !== 'string' || typeof row.taskId !== 'string')
|
|
11
|
+
fail('AUTOMATION_STORE_INVALID');
|
|
12
|
+
const daily = policy?.schedule.kind === 'daily' ? policy.schedule : null;
|
|
13
|
+
return { id: row.id, taskId: row.taskId, name: typeof row.nome === 'string' ? row.nome : row.taskId, active: Boolean(row.attiva), schedule: daily ? 'daily ' + daily.at : 'interval ' + String(row.intervalloMinuti ?? '?') + 'm', timezone: daily?.timezone ?? null, nextRunAt: typeof row.prossimaEsecuzione === 'string' ? row.prossimaEsecuzione : null };
|
|
14
|
+
}
|
|
15
|
+
export function createAutomationFacade(input, deps = {}) {
|
|
16
|
+
const policyStore = deps.policyStore ?? createAutomationPolicyStore(join(input.dataRoot, 'automation-policies'));
|
|
17
|
+
const historyStore = deps.historyStore ?? createAutomationHistoryStore(join(input.dataRoot, 'automation-history'));
|
|
18
|
+
let storePromise = null;
|
|
19
|
+
const store = () => storePromise ??= (deps.loadAutomationStore ? deps.loadAutomationStore() : (async () => { const mod = await importTalosModule(input.repoRoot ?? findTalosRepoRoot(input.projectRoot), 'automation-store.mjs'); return mod.createAutomationStore({ cartella: join(input.dataRoot, 'automations') }); })());
|
|
20
|
+
const dry = deps.dryRun ?? dryRunAutomation, healthProbe = deps.probeHealth ?? probeWindowsAutomationRunner;
|
|
21
|
+
async function list() {
|
|
22
|
+
try {
|
|
23
|
+
const rows = await (await store()).elenca();
|
|
24
|
+
const joined = [];
|
|
25
|
+
for (const raw of rows) {
|
|
26
|
+
const policy = await policyStore.get(raw.id);
|
|
27
|
+
joined.push(rowOf(raw, policy));
|
|
28
|
+
}
|
|
29
|
+
return { state: 'ready', rows: joined, error: null };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return { state: 'invalid', rows: [], error: { code: 'AUTOMATION_STORE_INVALID', message: error instanceof Error ? error.message : String(error) } };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function read(id) {
|
|
36
|
+
const raw = await (await store()).leggi(id);
|
|
37
|
+
if (!raw)
|
|
38
|
+
fail('AUTOMATION_NOT_FOUND');
|
|
39
|
+
const policy = await policyStore.get(id), base = rowOf(raw, policy);
|
|
40
|
+
const [history, dryRun, adapterHealth] = await Promise.all([historyStore.list(id), dry({ row: raw, policy, now: Date.now() }), healthProbe({ platform: process.platform })]);
|
|
41
|
+
return { ...base, policy, missedRun: policy?.missedRun ?? null, backoff: policy?.backoff ?? null, history, dryRun, adapterHealth };
|
|
42
|
+
}
|
|
43
|
+
async function configureDaily(id, options) {
|
|
44
|
+
const raw = await (await store()).leggi(id);
|
|
45
|
+
if (!raw)
|
|
46
|
+
fail('AUTOMATION_NOT_FOUND');
|
|
47
|
+
validateTimeZone(options.timezone);
|
|
48
|
+
const policy = await policyStore.put(id, { version: 1, schedule: { kind: 'daily', at: options.at, timezone: options.timezone }, missedRun: { mode: options.missed, graceMinutes: options.graceMinutes, catchupWindowMinutes: options.catchupWindowMinutes }, backoff: { baseSeconds: options.baseSeconds, maxSeconds: options.maxSeconds, consecutiveFailures: 0, nextRetryAt: null }, lastHandledSlot: null });
|
|
49
|
+
return { ...rowOf(raw, policy), policy };
|
|
50
|
+
}
|
|
51
|
+
async function dryRun(id) { const raw = await (await store()).leggi(id); if (!raw)
|
|
52
|
+
fail('AUTOMATION_NOT_FOUND'); const policy = await policyStore.get(id); return dry({ row: raw, policy, now: Date.now() }); }
|
|
53
|
+
const history = (id) => historyStore.list(id);
|
|
54
|
+
const health = () => healthProbe({ platform: process.platform });
|
|
55
|
+
async function setEnabled(id, active) { const s = await store(); if (typeof s.imposta !== 'function')
|
|
56
|
+
fail('AUTOMATION_STORE_INVALID'); const updated = await s.imposta(id, active); if (!updated)
|
|
57
|
+
fail('AUTOMATION_NOT_FOUND'); return rowOf(updated, await policyStore.get(id)); }
|
|
58
|
+
return { list, read, configureDaily, dryRun, history, health, setEnabled, policyStore, historyStore };
|
|
59
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { findTalosRepoRoot, importTalosModule } from "../runtime/repo.js";
|
|
3
|
+
import { scanForgeManifest, validateForgeOwnerPackage } from "../security/forge-scan.js";
|
|
4
|
+
function err(code, message = code) { throw Object.assign(new Error(code + ': ' + message), { code }); }
|
|
5
|
+
function stable(value) { if (Array.isArray(value))
|
|
6
|
+
return '[' + value.map(stable).join(',') + ']'; if (value && typeof value === 'object') {
|
|
7
|
+
return '{' + Object.keys(value).sort().map(k => JSON.stringify(k) + ':' + stable(value[k])).join(',') + '}';
|
|
8
|
+
} const encoded = JSON.stringify(value); return encoded === undefined ? 'null' : encoded; }
|
|
9
|
+
function digest(pkg) { return createHash('sha256').update(stable(pkg)).digest('hex'); }
|
|
10
|
+
function handle(result) { if (result?.erroreAvvio)
|
|
11
|
+
err(typeof result.code === 'string' ? result.code : 'FORGE_OWNER_ACTION_FAILED', String(result.erroreAvvio)); return result; }
|
|
12
|
+
export function createForgeFacade(input, deps = {}) {
|
|
13
|
+
const repoRoot = () => input.repoRoot ?? findTalosRepoRoot(input.forgeRoot);
|
|
14
|
+
let storeP = null, contractP = null;
|
|
15
|
+
const store = () => storeP ??= (deps.loadStore ? deps.loadStore() : importTalosModule(repoRoot(), 'tool-forge-store.mjs'));
|
|
16
|
+
const contract = () => contractP ??= (deps.loadContract ? deps.loadContract() : importTalosModule(repoRoot(), 'forge-contract.mjs'));
|
|
17
|
+
const now = deps.now ?? (() => new Date());
|
|
18
|
+
async function analyzePackage(value) {
|
|
19
|
+
const pkg = validateForgeOwnerPackage(value), c = await contract(), validation = c.validaManifestForgeLocale(pkg.manifest), scan = scanForgeManifest(pkg.manifest, validation);
|
|
20
|
+
const capabilityRequests = [];
|
|
21
|
+
let simulation = { ok: false, status: 'blocked', trace: [], capabilityRequests, error: null };
|
|
22
|
+
if (validation?.ok && scan.ok) {
|
|
23
|
+
try {
|
|
24
|
+
const result = await c.eseguiFlowForgeLocale(pkg.manifest, pkg.simulation.input, { capacitaFn: async (capability, request) => {
|
|
25
|
+
const simulated = Object.prototype.hasOwnProperty.call(pkg.simulation.capabilityResults, capability) ? pkg.simulation.capabilityResults[capability] : null;
|
|
26
|
+
capabilityRequests.push({ capability, input: request, result: simulated });
|
|
27
|
+
return simulated;
|
|
28
|
+
} });
|
|
29
|
+
const ok = result?.ok === true || result?.status === 'succeeded';
|
|
30
|
+
simulation = { ok, status: String(result?.status ?? (ok ? 'succeeded' : 'failed')), trace: Array.isArray(result?.trace) ? result.trace : [], capabilityRequests, ...(result?.error ? { error: result.error } : {}), ...(result?.output !== undefined ? { output: result.output } : {}), ...(result?.value !== undefined ? { value: result.value } : {}) };
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
simulation = { ok: false, status: 'failed', trace: [], capabilityRequests, error: { message: error instanceof Error ? error.message : String(error) } };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const evidence = { packageDigest: digest(pkg), ownerRevision: pkg.revision, analyzedAt: now().toISOString(), sideEffects: false, sandbox: { kind: 'declarative-fake-capability-boundary', osProcessSandbox: false }, validation: { ok: Boolean(validation?.ok), diagnostics: Array.isArray(validation?.diagnostica) ? validation.diagnostica : [] }, scan, simulation: { ok: simulation.ok, status: simulation.status, trace: simulation.trace, capabilityRequests } };
|
|
37
|
+
return { package: pkg, validation, scan, simulation, evidence };
|
|
38
|
+
}
|
|
39
|
+
const validatePackage = (value) => validateForgeOwnerPackage(value);
|
|
40
|
+
const scanPackage = async (value) => { const pkg = validateForgeOwnerPackage(value), validation = (await contract()).validaManifestForgeLocale(pkg.manifest); return { package: pkg, validation, scan: scanForgeManifest(pkg.manifest, validation) }; };
|
|
41
|
+
async function installPackage(sessionId, value) {
|
|
42
|
+
const analysis = await analyzePackage(value);
|
|
43
|
+
if (!analysis.validation?.ok || !analysis.scan.ok || !analysis.simulation.ok)
|
|
44
|
+
err('FORGE_ANALYSIS_BLOCKED', 'package must pass canonical validation, static scan and side-effect-free simulation');
|
|
45
|
+
const fn = deps.registry?.installaVersioneToolForgiato;
|
|
46
|
+
if (typeof fn !== 'function')
|
|
47
|
+
err('FORGE_OWNER_API_UNAVAILABLE');
|
|
48
|
+
const result = handle(await fn.call(deps.registry, sessionId, { revision: analysis.package.revision, manifest: analysis.package.manifest, capacita: analysis.validation.capacita ?? [], azioni: analysis.validation.azioni ?? [], rischio: analysis.validation.rischio ?? 'R1', evidence: analysis.evidence }));
|
|
49
|
+
return { instrument: result.strumento, analysis };
|
|
50
|
+
}
|
|
51
|
+
async function list() { try {
|
|
52
|
+
const rows = await (await store()).elencaToolForgiati({ cartella: input.forgeRoot });
|
|
53
|
+
return { state: 'ready', rows: rows.map((x) => ({ id: String(x.id), title: String(x.manifest?.title ?? x.id), enabled: x.abilitato === true, ownerRevision: Number.isSafeInteger(x.ownerRevision) ? Number(x.ownerRevision) : null, risk: String(x.rischio ?? 'R1'), ownerManaged: x.ownerManaged === true })), error: null };
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return { state: 'invalid', rows: [], error: { code: 'FORGE_STORE_INVALID', message: error instanceof Error ? error.message : String(error) } };
|
|
57
|
+
} }
|
|
58
|
+
async function read(id) {
|
|
59
|
+
const s = await store();
|
|
60
|
+
let row = typeof s.leggiToolForgiato === 'function' ? await s.leggiToolForgiato({ cartella: input.forgeRoot, id }) : null;
|
|
61
|
+
if (!row) {
|
|
62
|
+
const all = await s.elencaToolForgiati({ cartella: input.forgeRoot });
|
|
63
|
+
row = all.find((x) => x?.id === id) ?? null;
|
|
64
|
+
}
|
|
65
|
+
if (!row)
|
|
66
|
+
err('FORGE_NOT_FOUND');
|
|
67
|
+
const versions = row.ownerManaged === true && typeof s.elencaVersioniToolForgiatoOwner === 'function' ? await s.elencaVersioniToolForgiatoOwner({ cartella: input.forgeRoot, id }) : [];
|
|
68
|
+
return { id: String(row.id), title: String(row.manifest?.title ?? row.id), description: String(row.manifest?.description ?? ''), enabled: row.abilitato === true, ownerManaged: row.ownerManaged === true, ownerRevision: Number.isSafeInteger(row.ownerRevision) ? Number(row.ownerRevision) : null, risk: String(row.rischio ?? 'R1'), capabilities: Array.isArray(row.capacita) ? row.capacita : [], actions: Array.isArray(row.azioni) ? row.azioni : [], evidence: row.evidence ?? null, scan: row.evidence?.scan ?? null, versions };
|
|
69
|
+
}
|
|
70
|
+
async function versions(sessionId, id) { const fn = deps.registry?.versioniToolForgiato; if (typeof fn !== 'function')
|
|
71
|
+
err('FORGE_OWNER_API_UNAVAILABLE'); return handle(await fn.call(deps.registry, sessionId, id)).versioni ?? []; }
|
|
72
|
+
async function rollback(sessionId, id, revision) { const fn = deps.registry?.ripristinaVersioneToolForgiato; if (typeof fn !== 'function')
|
|
73
|
+
err('FORGE_OWNER_API_UNAVAILABLE'); return handle(await fn.call(deps.registry, sessionId, id, revision)); }
|
|
74
|
+
async function setEnabled(sessionId, id, enabled) { const fn = deps.registry?.abilitaToolForgiato; if (typeof fn !== 'function')
|
|
75
|
+
err('FORGE_OWNER_API_UNAVAILABLE'); return handle(await fn.call(deps.registry, sessionId, id, enabled)); }
|
|
76
|
+
return { validatePackage, scanPackage, analyzePackage, installPackage, list, read, versions, rollback, setEnabled };
|
|
77
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { readdir, realpath, rm, stat } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { normalizeProjectRoot } from "../paths.js";
|
|
4
|
+
import { createRedactor, redactObject, secretValuesFromEnvironment } from "../diagnostics/redact.js";
|
|
5
|
+
import { findTalosRepoRoot, importTalosModule } from "../runtime/repo.js";
|
|
6
|
+
import { fingerprintExecutableResourceContent } from "../security/project-trust.js";
|
|
7
|
+
import { createTrustAuthority } from "../security/trust-authority.js";
|
|
8
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,120}$/u;
|
|
9
|
+
const VALID_EVENTS = new Set(['pre_tool_call', 'post_tool_call', 'session_start', 'session_end']);
|
|
10
|
+
const MAX_HISTORY = 50;
|
|
11
|
+
const MAX_SESSION_FILES = 5000;
|
|
12
|
+
const MAX_SESSION_READS = 200;
|
|
13
|
+
function fail(code, message = code) { throw Object.assign(new Error(message), { code }); }
|
|
14
|
+
function hookId(value) { if (!ID.test(value) || value.includes('..'))
|
|
15
|
+
fail('HOOK_ID_INVALID'); return value; }
|
|
16
|
+
function text(value) { return typeof value === 'string' ? value : null; }
|
|
17
|
+
function safeResult(value, secrets) { return redactObject(value, secrets); }
|
|
18
|
+
function configuredHook(value) {
|
|
19
|
+
if (!value || typeof value !== 'object')
|
|
20
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
21
|
+
const id = hookId(String(value.id ?? ''));
|
|
22
|
+
const eventi = value.eventi;
|
|
23
|
+
if (!Array.isArray(eventi) || !eventi.length || !eventi.every((row) => typeof row === 'string' && VALID_EVENTS.has(row))
|
|
24
|
+
|| new Set(eventi).size !== eventi.length || typeof value.comando !== 'string' || !value.comando.trim())
|
|
25
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
26
|
+
return { id, eventi: [...eventi], comando: value.comando, ...(typeof value.hash === 'string' ? { hash: value.hash } : {}) };
|
|
27
|
+
}
|
|
28
|
+
export function createHookFacade(input, deps = {}) {
|
|
29
|
+
const authority = deps.authority ?? createTrustAuthority({ projectRoot: input.projectRoot, trustRoot: input.paths.trust.projects });
|
|
30
|
+
const secrets = secretValuesFromEnvironment(input.env ?? process.env);
|
|
31
|
+
const redactor = createRedactor(secrets);
|
|
32
|
+
const repoRoot = () => input.repoRoot ?? findTalosRepoRoot(input.projectRoot);
|
|
33
|
+
let registryPromise = null;
|
|
34
|
+
let storePromise = null;
|
|
35
|
+
const registry = () => registryPromise ??= importTalosModule(repoRoot(), 'hook-registry.mjs');
|
|
36
|
+
const store = () => storePromise ??= importTalosModule(repoRoot(), 'session-store.mjs');
|
|
37
|
+
async function defaultLoadHooks() {
|
|
38
|
+
try {
|
|
39
|
+
const loaded = await (await registry()).caricaHooks({ cartella: input.projectRoot });
|
|
40
|
+
if (!loaded || !Array.isArray(loaded.hooks))
|
|
41
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
42
|
+
return { hooks: loaded.hooks.map(configuredHook) };
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error?.code === 'HOOK_MALFORMED' || error?.code === 'RESOURCE_CONFIG_MALFORMED')
|
|
46
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const loadHooks = deps.loadHooks ?? defaultLoadHooks;
|
|
51
|
+
async function compatibilityRoot() { return (await authority.compatibilityRoots()).hooks; }
|
|
52
|
+
async function defaultUntrustCompatibility(id) { await rm(join(await compatibilityRoot(), hookId(id) + '.json'), { force: true }); }
|
|
53
|
+
async function defaultTrustCompatibility(hook) {
|
|
54
|
+
if (!hook.hash)
|
|
55
|
+
fail('HOOK_COMPATIBILITY_HASH_MISSING');
|
|
56
|
+
const root = await compatibilityRoot();
|
|
57
|
+
await rm(join(root, hookId(hook.id) + '.json'), { force: true });
|
|
58
|
+
await (await registry()).fidaHook({ cartellaTrust: root, hookId: hook.id, hash: hook.hash });
|
|
59
|
+
}
|
|
60
|
+
const untrustCompatibility = deps.untrustCompatibility ?? defaultUntrustCompatibility;
|
|
61
|
+
const trustCompatibility = deps.trustCompatibility ?? defaultTrustCompatibility;
|
|
62
|
+
async function defaultFingerprintHook(hook, snapshot) {
|
|
63
|
+
const resource = await fingerprintExecutableResourceContent({
|
|
64
|
+
workspace: snapshot.workspace, kind: 'hook', id: hook.id,
|
|
65
|
+
path: join(snapshot.workspace.canonicalRoot, '.harness-ui-hooks.json'),
|
|
66
|
+
content: JSON.stringify({ eventi: hook.eventi, comando: hook.comando })
|
|
67
|
+
});
|
|
68
|
+
return resource.fingerprint;
|
|
69
|
+
}
|
|
70
|
+
const fingerprintHook = deps.fingerprintHook ?? defaultFingerprintHook;
|
|
71
|
+
const executeHook = deps.executeHook ?? (async (input) => (await registry()).eseguiHook(input));
|
|
72
|
+
async function defaultListSessionIds() {
|
|
73
|
+
try {
|
|
74
|
+
const rows = (await readdir(input.paths.sessionsRoot, { withFileTypes: true }))
|
|
75
|
+
.filter(row => row.isFile() && row.name.endsWith('.jsonl'))
|
|
76
|
+
.map(row => row.name.slice(0, -6))
|
|
77
|
+
.slice(0, MAX_SESSION_FILES);
|
|
78
|
+
const measured = await Promise.all(rows.map(async (id) => {
|
|
79
|
+
try {
|
|
80
|
+
return { id, mtimeMs: (await stat(join(input.paths.sessionsRoot, id + '.jsonl'))).mtimeMs };
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { id, mtimeMs: 0 };
|
|
84
|
+
}
|
|
85
|
+
}));
|
|
86
|
+
return measured.sort((a, b) => b.mtimeMs - a.mtimeMs || a.id.localeCompare(b.id)).slice(0, MAX_SESSION_READS).map(row => row.id);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error.code === 'ENOENT')
|
|
90
|
+
return [];
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const listSessionIds = deps.listSessionIds ?? defaultListSessionIds;
|
|
95
|
+
const readSession = deps.readSession ?? (async (id) => (await store()).leggiRegistro({ cartellaStore: input.paths.sessionsRoot, sessionId: id }));
|
|
96
|
+
async function hooks() {
|
|
97
|
+
try {
|
|
98
|
+
const loaded = await loadHooks();
|
|
99
|
+
if (!loaded || !Array.isArray(loaded.hooks))
|
|
100
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
101
|
+
const rows = loaded.hooks.map(configuredHook);
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const hook of rows) {
|
|
104
|
+
if (seen.has(hook.id))
|
|
105
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
106
|
+
seen.add(hook.id);
|
|
107
|
+
}
|
|
108
|
+
return rows;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error?.code === 'HOOK_MALFORMED' || error?.code === 'RESOURCE_CONFIG_MALFORMED')
|
|
112
|
+
fail('HOOK_CONFIG_MALFORMED');
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function target(id) { const wanted = hookId(id); const rows = await hooks(); const row = rows.find(item => item.id === wanted); if (!row)
|
|
117
|
+
fail('HOOK_NOT_FOUND'); return row; }
|
|
118
|
+
function trustRow(snapshot, id) { return snapshot.resources.find(row => row.kind === 'hook' && row.id === id && row.current); }
|
|
119
|
+
async function assertLoadedFingerprint(hook, snapshot) {
|
|
120
|
+
const row = trustRow(snapshot, hook.id);
|
|
121
|
+
if (!row?.currentFingerprint)
|
|
122
|
+
fail('HOOK_RESOURCE_NOT_FOUND');
|
|
123
|
+
const loaded = await fingerprintHook(hook, snapshot);
|
|
124
|
+
if (!loaded || loaded !== row.currentFingerprint)
|
|
125
|
+
fail('HOOK_TRUST_INVALIDATED');
|
|
126
|
+
return row;
|
|
127
|
+
}
|
|
128
|
+
async function quarantineOf(id) { return authority.quarantineStatus({ kind: 'hook', id }); }
|
|
129
|
+
async function historyFor(id, limit = 8) {
|
|
130
|
+
const wanted = hookId(id);
|
|
131
|
+
const snapshot = await authority.inspect();
|
|
132
|
+
const canonical = normalizeProjectRoot(snapshot.workspace.canonicalRoot);
|
|
133
|
+
const sessionIds = (await listSessionIds()).slice(0, MAX_SESSION_READS);
|
|
134
|
+
const out = [];
|
|
135
|
+
for (const sessionId of sessionIds) {
|
|
136
|
+
let records = null;
|
|
137
|
+
try {
|
|
138
|
+
records = await readSession(sessionId);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (!Array.isArray(records) || !records.length)
|
|
144
|
+
continue;
|
|
145
|
+
const header = records.find(row => row?.tipo === 'intestazione');
|
|
146
|
+
if (!header || typeof header.cartella !== 'string')
|
|
147
|
+
continue;
|
|
148
|
+
let sessionRoot = normalizeProjectRoot(header.cartella);
|
|
149
|
+
if (sessionRoot !== canonical) {
|
|
150
|
+
try {
|
|
151
|
+
sessionRoot = normalizeProjectRoot(await realpath(header.cartella));
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (sessionRoot !== canonical)
|
|
158
|
+
continue;
|
|
159
|
+
const started = text(header.avviataAlle);
|
|
160
|
+
for (const row of records) {
|
|
161
|
+
if (row?.type !== 'HookInvoked' || row.hookId !== wanted || !Number.isSafeInteger(row._sequenza))
|
|
162
|
+
continue;
|
|
163
|
+
out.push({
|
|
164
|
+
sessionId: String(header.sessionId ?? sessionId), sessionStartedAt: started, sequence: row._sequenza,
|
|
165
|
+
eventType: String(row.tipo ?? ''), action: text(row.azione), result: safeResult(row.esito, secrets), executedAt: null
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
out.sort((a, b) => String(b.sessionStartedAt ?? '').localeCompare(String(a.sessionStartedAt ?? '')) || b.sequence - a.sequence);
|
|
170
|
+
return out.slice(0, Math.max(0, Math.min(MAX_HISTORY, limit)));
|
|
171
|
+
}
|
|
172
|
+
async function view(hook, snapshot, history) {
|
|
173
|
+
const row = trustRow(snapshot, hook.id);
|
|
174
|
+
const state = (row?.state ?? 'added');
|
|
175
|
+
const quarantine = await quarantineOf(hook.id);
|
|
176
|
+
const current = row?.currentFingerprint ?? null;
|
|
177
|
+
const trusted = row?.trustedFingerprint ?? null;
|
|
178
|
+
return {
|
|
179
|
+
id: hook.id, events: [...hook.eventi], launch: { command: redactor.text(hook.comando) },
|
|
180
|
+
trust: { projectTrusted: snapshot.trusted, state, trusted: state === 'trusted' && !quarantine, currentFingerprint: current, trustedFingerprint: trusted, changed: state === 'changed' || Boolean(current && trusted && current !== trusted) },
|
|
181
|
+
quarantine: { active: Boolean(quarantine), reason: quarantine?.reason ?? null, quarantinedAt: quarantine?.quarantinedAt ?? null, reviewedFingerprint: quarantine?.reviewedFingerprint ?? null },
|
|
182
|
+
lastExecutions: history, lastDryRun: null
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
async list() {
|
|
187
|
+
const [rows, snapshot] = await Promise.all([hooks(), authority.inspect()]);
|
|
188
|
+
const histories = await Promise.all(rows.map(row => historyFor(row.id, 8)));
|
|
189
|
+
return Promise.all(rows.map((row, index) => view(row, snapshot, histories[index] ?? [])));
|
|
190
|
+
},
|
|
191
|
+
async history(id, options = {}) {
|
|
192
|
+
await target(id);
|
|
193
|
+
return historyFor(id, options.limit ?? 8);
|
|
194
|
+
},
|
|
195
|
+
async dryRun(id, { eventType, action }) {
|
|
196
|
+
const hook = await target(id);
|
|
197
|
+
const snapshot = await authority.inspect();
|
|
198
|
+
if (await quarantineOf(hook.id))
|
|
199
|
+
fail('HOOK_QUARANTINED');
|
|
200
|
+
if (!snapshot.trusted)
|
|
201
|
+
fail('PROJECT_TRUST_REQUIRED');
|
|
202
|
+
if (!await authority.verifyScope({ kind: 'hook', id: hook.id }))
|
|
203
|
+
fail('HOOK_TRUST_REQUIRED');
|
|
204
|
+
await assertLoadedFingerprint(hook, snapshot);
|
|
205
|
+
if (!hook.eventi.includes(eventType))
|
|
206
|
+
fail('HOOK_EVENT_NOT_DECLARED');
|
|
207
|
+
const event = { tipo: eventType, ...(action ? { azione: action } : {}), dryRun: true };
|
|
208
|
+
const result = await executeHook({ hook, evento: event, cartella: input.projectRoot });
|
|
209
|
+
return { realProcess: true, syntheticEvent: true, eventType, action: action ?? null, result: safeResult(result, secrets) };
|
|
210
|
+
},
|
|
211
|
+
async trust(id) {
|
|
212
|
+
const hook = await target(id);
|
|
213
|
+
const reviewed = await authority.inspect();
|
|
214
|
+
await assertLoadedFingerprint(hook, reviewed);
|
|
215
|
+
const result = await authority.trustScope({ kind: 'hook', id: hook.id }, { expected: reviewed });
|
|
216
|
+
await trustCompatibility(hook);
|
|
217
|
+
return { ok: true, id: hook.id, changed: result.changed, snapshot: result.snapshot };
|
|
218
|
+
},
|
|
219
|
+
async untrust(id) {
|
|
220
|
+
const hook = await target(id);
|
|
221
|
+
const result = await authority.untrustScope({ kind: 'hook', id: hook.id });
|
|
222
|
+
await untrustCompatibility(hook.id);
|
|
223
|
+
return { ok: true, id: hook.id, changed: result.changed, snapshot: result.snapshot };
|
|
224
|
+
},
|
|
225
|
+
async quarantine(id, reason = null) {
|
|
226
|
+
const hook = await target(id);
|
|
227
|
+
const reviewed = await authority.inspect();
|
|
228
|
+
await assertLoadedFingerprint(hook, reviewed);
|
|
229
|
+
const result = await authority.quarantineScope({ kind: 'hook', id: hook.id }, { reason, expected: reviewed });
|
|
230
|
+
await untrustCompatibility(hook.id);
|
|
231
|
+
return { ok: true, id: hook.id, changed: result.changed, record: result.record, snapshot: result.snapshot };
|
|
232
|
+
},
|
|
233
|
+
async releaseQuarantine(id) {
|
|
234
|
+
const hook = await target(id);
|
|
235
|
+
const result = await authority.releaseQuarantine({ kind: 'hook', id: hook.id });
|
|
236
|
+
await untrustCompatibility(hook.id);
|
|
237
|
+
return { ok: true, id: hook.id, changed: result.changed };
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function publicRow(x) { if (!x || typeof x !== 'object')
|
|
2
|
+
return x; const o = {}; for (const [k, v] of Object.entries(x)) {
|
|
3
|
+
if (/path|percorso/i.test(k))
|
|
4
|
+
continue;
|
|
5
|
+
o[k === 'titolo' ? 'title' : k === 'testo' ? 'body' : k] = v;
|
|
6
|
+
} return o; }
|
|
7
|
+
export function createServiceFacades(stores) {
|
|
8
|
+
return {
|
|
9
|
+
notes: { list: async () => ((await stores.notes.list()) ?? []).map(publicRow), add: async (v) => publicRow(await stores.notes.create(v)) },
|
|
10
|
+
tasks: { list: async () => ((await stores.tasks.list()) ?? []).map(publicRow) },
|
|
11
|
+
memory: { search: async (q) => ((await stores.memory.search(q)) ?? []).map(publicRow) },
|
|
12
|
+
library: { list: async () => ((await stores.library.list()) ?? []).map(publicRow) },
|
|
13
|
+
research: { list: async () => ((await stores.research.list()) ?? []).map(publicRow) },
|
|
14
|
+
forge: { list: async () => ((await stores.forge.list()) ?? []).map(publicRow) },
|
|
15
|
+
};
|
|
16
|
+
}
|