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,72 @@
|
|
|
1
|
+
import { t, tn } from "../../i18n/index.js";
|
|
2
|
+
import { normalizeModels } from "../catalog-service.js";
|
|
3
|
+
import { pickerSection } from "./scroll-window.js";
|
|
4
|
+
/**
|
|
5
|
+
* R4 (gate E10): `current` is the model in use; when it belongs to this provider and the list does not have it, it is still
|
|
6
|
+
* listed (not verified) and the notice says so, so the picker never hides what TALOS is set to use.
|
|
7
|
+
*/
|
|
8
|
+
export function createModelPickerModel(catalog, input) {
|
|
9
|
+
let models = [];
|
|
10
|
+
let cancelled = false;
|
|
11
|
+
let loadError = null;
|
|
12
|
+
let verified = false;
|
|
13
|
+
let notice = '';
|
|
14
|
+
let label = input.provider ?? '';
|
|
15
|
+
let abort = null;
|
|
16
|
+
return {
|
|
17
|
+
async open() {
|
|
18
|
+
cancelled = false;
|
|
19
|
+
loadError = null;
|
|
20
|
+
models = [];
|
|
21
|
+
verified = false;
|
|
22
|
+
if (!input.provider) {
|
|
23
|
+
notice = t('screen.model.chooseProviderFirst');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
abort?.abort();
|
|
27
|
+
abort = new AbortController();
|
|
28
|
+
try {
|
|
29
|
+
const list = await catalog.providerModels(input.provider, abort.signal);
|
|
30
|
+
if (cancelled)
|
|
31
|
+
return;
|
|
32
|
+
models = list.rows;
|
|
33
|
+
verified = list.verified;
|
|
34
|
+
notice = list.notice;
|
|
35
|
+
label = list.label;
|
|
36
|
+
const current = input.current;
|
|
37
|
+
if (current && current.startsWith(`${input.provider}:`) && !models.some(row => row.id === current)) {
|
|
38
|
+
models = [...models, ...normalizeModels([{ id: current }], input.provider, 'configured')];
|
|
39
|
+
verified = false;
|
|
40
|
+
notice = [notice, t('firstrun.models.chosenMissing', { model: current, label })].filter(Boolean).join(' ');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (!cancelled) {
|
|
45
|
+
loadError = error;
|
|
46
|
+
notice = t('screen.model.listFailed');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
cancel() { cancelled = true; abort?.abort(); abort = null; },
|
|
51
|
+
rows: () => models,
|
|
52
|
+
error: () => loadError,
|
|
53
|
+
verified: () => verified,
|
|
54
|
+
notice: () => notice,
|
|
55
|
+
label: () => label,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function commitModelSelection({ id, catalog, setControllerModel }) {
|
|
59
|
+
await catalog.selectModel(id, 'project-user');
|
|
60
|
+
setControllerModel(id);
|
|
61
|
+
}
|
|
62
|
+
// R1 Q-R1-3: the model list and the effort step as app.ts draws them, capped and scrolled by overlays/scroll-window.ts.
|
|
63
|
+
export function modelPickerOverlay({ label, provider, loading, verified, notice, query, rows, selected }) {
|
|
64
|
+
return {
|
|
65
|
+
head: [
|
|
66
|
+
{ text: t('screen.model.title', { label: label || provider || '', state: t(loading ? 'screen.model.stateLoading' : verified ? 'screen.model.stateLive' : 'screen.model.stateUnverified') }), tone: 'title' },
|
|
67
|
+
...(notice ? [{ text: notice, tone: loading || verified ? 'dim' : 'plain' }] : []),
|
|
68
|
+
{ text: tn('screen.model.count', rows.length, { query: query || t('screen.none') }), tone: 'dim' },
|
|
69
|
+
],
|
|
70
|
+
sections: [pickerSection(rows, selected, row => { const remote = row.id.slice(row.provider.length + 1); const efforts = row.reasoningEfforts?.length ? ` · ${t('screen.model.rowEffort', { efforts: row.reasoningEfforts.join('/') })}` : ''; return `${row.name}${row.name !== remote ? ` · ${remote}` : ''}${row.contextWindow ? ` · ${row.contextWindow}` : ''}${row.reasoning ? ` · ${t('screen.model.rowReasoning')}` : ''}${efforts}${row.images ? ` · ${t('screen.model.rowImage')}` : ''}${verified || loading ? '' : ` ${t('screen.model.rowUnverified')}`}`; })],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { en, t } from "../../i18n/index.js";
|
|
2
|
+
import { centerTones, listOverlay } from "./scroll-window.js";
|
|
3
|
+
const UNSAFE = /[\\\x00-\x1f\x7f-\x9f\u2028\u2029\p{Bidi_Control}\p{Default_Ignorable_Code_Point}]/gu;
|
|
4
|
+
function inert(value) { return String(value ?? '').replace(UNSAFE, ch => { if (ch === '\\')
|
|
5
|
+
return '\\\\'; const cp = ch.codePointAt(0) ?? 0; return cp <= 0xffff ? '\\u' + cp.toString(16).padStart(4, '0') : '\\u{' + cp.toString(16) + '}'; }); }
|
|
6
|
+
/* R2 (gate §1.5, E4): the kernel's `origine` value (modello|persona) is mapped by value, never printed raw. */
|
|
7
|
+
function writerLabel(value) { const id = `screen.writer.${String(value)}`; return Object.hasOwn(en, id) ? t(id) : inert(value); }
|
|
8
|
+
/* R2 (gate §1.5, E4): the kernel's note `formato` value (testo|markdown) is mapped by value, never printed raw. */
|
|
9
|
+
function formatLabel(value) { const id = `screen.noteFormat.${String(value)}`; return Object.hasOwn(en, id) ? t(id) : inert(value); }
|
|
10
|
+
function clamp(value, count) { return count ? Math.max(0, Math.min(count - 1, value)) : 0; }
|
|
11
|
+
export function createNotesCenterModel(snapshot, selected = 0) { return { snapshot, selected: clamp(selected, snapshot.rows.length) }; }
|
|
12
|
+
export function moveNotesCenterSelection(model, delta) { return { ...model, selected: clamp(model.selected + delta, model.snapshot.rows.length) }; }
|
|
13
|
+
export function selectedNote(model) { return model.snapshot.rows[model.selected] ?? null; }
|
|
14
|
+
export function renderNotesCenterLines(model) {
|
|
15
|
+
const lines = [t('screen.notes.title')];
|
|
16
|
+
if (model.snapshot.state === 'invalid') {
|
|
17
|
+
lines.push('Store: invalid · ' + inert(model.snapshot.error?.code ?? 'NOTES_STORE_INVALID') + ' · ' + inert(model.snapshot.error?.message ?? 'unavailable'));
|
|
18
|
+
lines.push(t('screen.center.closeRefresh'));
|
|
19
|
+
return lines;
|
|
20
|
+
}
|
|
21
|
+
if (!model.snapshot.rows.length) {
|
|
22
|
+
lines.push(t('screen.notes.empty'));
|
|
23
|
+
lines.push(t('screen.center.closeRefresh'));
|
|
24
|
+
return lines;
|
|
25
|
+
}
|
|
26
|
+
lines.push(...model.snapshot.rows.map((row, index) => (index === model.selected ? '› ' : ' ') + inert(row.id) + ' · ' + inert(row.title) + ' · ' + formatLabel(row.format)));
|
|
27
|
+
const row = selectedNote(model);
|
|
28
|
+
if (row) {
|
|
29
|
+
lines.push('ID: ' + inert(row.id));
|
|
30
|
+
lines.push('Format: ' + formatLabel(row.format) + ' (' + inert(row.formatEvidence) + ')');
|
|
31
|
+
lines.push('Writer: ' + writerLabel(row.writer) + ' (' + inert(row.writerEvidence) + ')');
|
|
32
|
+
lines.push('Created: ' + inert(row.createdAt ?? 'unavailable') + ' · Updated: ' + inert(row.updatedAt ?? 'unavailable'));
|
|
33
|
+
lines.push('Content: ' + inert(row.content));
|
|
34
|
+
if (row.relations.length) {
|
|
35
|
+
lines.push('Links:');
|
|
36
|
+
for (const relation of row.relations)
|
|
37
|
+
lines.push('- ' + inert(relation.target.kind) + ':' + inert(relation.target.id) + ' · ' + inert(relation.state) + (relation.label ? ' · ' + inert(relation.label) : ''));
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
|
+
lines.push('Links: none');
|
|
41
|
+
}
|
|
42
|
+
lines.push(t('screen.notes.keys'));
|
|
43
|
+
lines.push(t('screen.notes.linkHelp'));
|
|
44
|
+
lines.push(t('screen.notes.unlinkHelp'));
|
|
45
|
+
return lines;
|
|
46
|
+
}
|
|
47
|
+
// R1 Q-R1-3: the same lines as a capped, scrolling overlay — the list keeps the selection visible, the detail scrolls.
|
|
48
|
+
// The /notes link|unlink reference lines follow the key hint: they scroll with the detail, the hint stays.
|
|
49
|
+
export function notesCenterOverlay(model) {
|
|
50
|
+
const lines = renderNotesCenterLines(model), list = model.snapshot.state === 'invalid' ? 0 : model.snapshot.rows.length;
|
|
51
|
+
const reference = list ? 2 : 0, hint = lines.length - 1 - reference;
|
|
52
|
+
return listOverlay([...lines.slice(0, hint), ...lines.slice(hint + 1), lines[hint]], { head: 1, list, selected: model.selected, foot: 1, tones: centerTones });
|
|
53
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { centerTones, listOverlay } from "./scroll-window.js";
|
|
3
|
+
const UNSAFE = /[\\\x00-\x1f\x7f-\x9f\u2028\u2029\p{Bidi_Control}\p{Default_Ignorable_Code_Point}]/gu;
|
|
4
|
+
const BACKSLASH = String.fromCharCode(92);
|
|
5
|
+
function inert(value) {
|
|
6
|
+
return String(value).replace(UNSAFE, character => {
|
|
7
|
+
if (character === BACKSLASH)
|
|
8
|
+
return BACKSLASH + BACKSLASH;
|
|
9
|
+
const code = character.codePointAt(0);
|
|
10
|
+
return code > 0xffff ? BACKSLASH + 'u{' + code.toString(16) + '}' : BACKSLASH + 'u' + code.toString(16).padStart(4, '0');
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function shown(value) { return inert(String(value ?? '—')); }
|
|
14
|
+
function list(values) { return values.length ? values.map(shown).join(', ') : 'none'; }
|
|
15
|
+
export function createPluginCenterModel(rows, selected = 0) {
|
|
16
|
+
const copy = rows.map(row => ({ ...row }));
|
|
17
|
+
return { title: t('screen.plugins.title'), rows: copy, selected: copy.length ? Math.max(0, Math.min(copy.length - 1, selected)) : 0 };
|
|
18
|
+
}
|
|
19
|
+
export function movePluginCenterSelection(model, delta) {
|
|
20
|
+
if (!model.rows.length)
|
|
21
|
+
return model;
|
|
22
|
+
return { ...model, selected: Math.max(0, Math.min(model.rows.length - 1, model.selected + delta)) };
|
|
23
|
+
}
|
|
24
|
+
export function selectedPlugin(model) { return model.rows[model.selected] ?? null; }
|
|
25
|
+
export function replacePluginCenterRow(model, row) {
|
|
26
|
+
const index = model.rows.findIndex(value => value.id === row.id);
|
|
27
|
+
if (index < 0)
|
|
28
|
+
return model;
|
|
29
|
+
const rows = [...model.rows];
|
|
30
|
+
rows[index] = row;
|
|
31
|
+
return { ...model, rows };
|
|
32
|
+
}
|
|
33
|
+
export function renderPluginCenterLines(model) {
|
|
34
|
+
const lines = [model.title, ''];
|
|
35
|
+
if (!model.rows.length)
|
|
36
|
+
return [...lines, t('screen.plugins.empty'), '', t('screen.center.escRefresh')];
|
|
37
|
+
for (const [index, row] of model.rows.entries()) {
|
|
38
|
+
const status = row.registry.state !== 'loaded'
|
|
39
|
+
? row.registry.state
|
|
40
|
+
: row.quarantine.active ? 'quarantined'
|
|
41
|
+
: row.guard?.verdict === 'dangerous' ? 'dangerous'
|
|
42
|
+
: row.trust.effectiveTrusted ? 'trusted' : 'untrusted';
|
|
43
|
+
lines.push((index === model.selected ? '›' : ' ') + ' ' + shown(row.id) + ' · ' + status + ' · ' + row.provenance.kind);
|
|
44
|
+
}
|
|
45
|
+
const row = selectedPlugin(model);
|
|
46
|
+
if (!row)
|
|
47
|
+
return lines;
|
|
48
|
+
lines.push('', 'Selected: ' + shown(row.id) + (row.name ? ' · ' + shown(row.name) : ''), 'Registry: ' + row.registry.state + (row.registry.code ? ' · ' + shown(row.registry.code) : '') + (row.registry.message ? ' · ' + shown(row.registry.message) : ''), 'Provenance: ' + row.provenance.kind + (row.provenance.extension ? ' · ' + shown(row.provenance.extension.name) + ' ' + shown(row.provenance.extension.version) : ''), 'Package copy: ' + (row.provenance.packageCopyPresent ? 'present' : 'not verified') + ' · ' + shown(row.provenance.packageCopy), 'Recorded source (' + row.provenance.recordedSourceAuthority + '): ' + (row.provenance.recordedSource ? shown(row.provenance.recordedSource) : 'none') + ' · ' + (row.provenance.recordedSourceAvailable ? 'available' : 'unavailable / unverified'), 'Guard: ' + (row.guard ? row.guard.verdict : 'unavailable') + (row.guardError ? ' · ' + shown(row.guardError) : ''), 'Capabilities: ' + (row.guard ? list(row.guard.capabilities) : 'unavailable'), 'Trust: scope ' + (row.trust.scopeTrusted ? 'trusted' : 'not trusted') + ' · effective ' + (row.trust.effectiveTrusted ? 'trusted' : 'NOT TRUSTED') + ' · project ' + (row.trust.projectTrusted ? 'trusted' : 'not fully trusted'), 'Fingerprint current set: ' + shown(row.fingerprints.currentSetDigest), 'Fingerprint trusted set: ' + shown(row.fingerprints.trustedSetDigest));
|
|
49
|
+
if (row.fingerprints.changedPaths.length)
|
|
50
|
+
lines.push('Changed: ' + list(row.fingerprints.changedPaths));
|
|
51
|
+
if (row.fingerprints.addedPaths.length)
|
|
52
|
+
lines.push('Added: ' + list(row.fingerprints.addedPaths));
|
|
53
|
+
if (row.fingerprints.removedPaths.length)
|
|
54
|
+
lines.push('Removed: ' + list(row.fingerprints.removedPaths));
|
|
55
|
+
lines.push('Quarantine: ' + (row.quarantine.active ? 'active' : 'none') + (row.quarantine.reason ? ' · ' + shown(row.quarantine.reason) : ''));
|
|
56
|
+
if (row.guard === null)
|
|
57
|
+
lines.push('Guard findings: unavailable');
|
|
58
|
+
else if (row.guard.findings.length) {
|
|
59
|
+
lines.push('Guard findings');
|
|
60
|
+
for (const finding of row.guard.findings.slice(0, 12)) {
|
|
61
|
+
lines.push(' ' + finding.severity + ' · ' + shown(finding.code) + ' · ' + shown(finding.origin) + ' · ' + shown(finding.message));
|
|
62
|
+
}
|
|
63
|
+
if (row.guard.findings.length > 12)
|
|
64
|
+
lines.push(' … ' + (row.guard.findings.length - 12) + ' more finding(s)');
|
|
65
|
+
}
|
|
66
|
+
else if (row.guard)
|
|
67
|
+
lines.push('Guard findings: none');
|
|
68
|
+
if (row.guard?.verdict === 'dangerous')
|
|
69
|
+
lines.push(t('screen.plugins.blocked'));
|
|
70
|
+
lines.push('', t('screen.plugins.keys'));
|
|
71
|
+
return lines;
|
|
72
|
+
}
|
|
73
|
+
// R1 Q-R1-3: the same lines as a capped, scrolling overlay — the list keeps the selection visible, the detail scrolls.
|
|
74
|
+
export function pluginCenterOverlay(model) {
|
|
75
|
+
return listOverlay(renderPluginCenterLines(model), { head: 2, list: model.rows.length, selected: model.selected, foot: 1, tones: centerTones });
|
|
76
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { benchClock } from "../catalog-service.js";
|
|
3
|
+
import { pickerSection } from "./scroll-window.js";
|
|
4
|
+
import { filterItems } from "../selection-list.js";
|
|
5
|
+
const KEY_REMEDIATION_CODES = new Set(['PROVIDER_KEY_MISSING', 'PROVIDER_KEY_BENCHED', 'PROVIDER_AUTH_FAILED']);
|
|
6
|
+
export function providerPickerEnter(input) {
|
|
7
|
+
if (input.keySource === 'environment-unanswered' && !input.probe)
|
|
8
|
+
return { kind: 'environment-consent', provider: input.selectedProvider };
|
|
9
|
+
const remediation = input.probe?.remediation ?? null;
|
|
10
|
+
const readinessCode = input.probe?.readinessCode ?? null;
|
|
11
|
+
const requiresKey = input.requiresKey !== false;
|
|
12
|
+
if (readinessCode) {
|
|
13
|
+
if (requiresKey && KEY_REMEDIATION_CODES.has(readinessCode))
|
|
14
|
+
return { kind: 'provider-setup', provider: input.selectedProvider, remediation };
|
|
15
|
+
return { kind: 'provider-remediation', provider: input.selectedProvider, remediation };
|
|
16
|
+
}
|
|
17
|
+
if (input.configured)
|
|
18
|
+
return remediation && remediation.code !== 'none'
|
|
19
|
+
? { kind: 'open-model-picker', provider: input.selectedProvider, remediation }
|
|
20
|
+
: { kind: 'open-model-picker', provider: input.selectedProvider };
|
|
21
|
+
if (input.keySource === 'environment-unanswered')
|
|
22
|
+
return { kind: 'environment-consent', provider: input.selectedProvider };
|
|
23
|
+
if (requiresKey)
|
|
24
|
+
return remediation ? { kind: 'provider-setup', provider: input.selectedProvider, remediation } : { kind: 'provider-setup', provider: input.selectedProvider };
|
|
25
|
+
return { kind: 'provider-remediation', provider: input.selectedProvider, remediation };
|
|
26
|
+
}
|
|
27
|
+
/** "No" is first and preselected; the question names the variable, never any part of its value. */
|
|
28
|
+
export function consentQuestion(row) {
|
|
29
|
+
return {
|
|
30
|
+
question: t('screen.provider.consentQuestion', { variable: row.environmentVariable ?? t('screen.provider.consentVariableFallback'), provider: row.label }),
|
|
31
|
+
options: [{ choice: 'no', label: t('screen.provider.consentNo') }, { choice: 'yes', label: t('screen.provider.consentYes') }],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/* B1 slice 25: a provider whose stored keys are all benched is shown as benched, with the cause and until when, not as "key saved". */
|
|
35
|
+
export function providerKeySourceLabel(row) {
|
|
36
|
+
if (row.benched)
|
|
37
|
+
return t('screen.provider.keyBenched') + (row.benched.cause ? t('screen.provider.keyBenchedCause', { cause: row.benched.cause }) : '') + (row.benched.until !== null ? t('screen.provider.keyBenchedUntil', { clock: benchClock(row.benched.until) }) : '');
|
|
38
|
+
switch (row.keySource) {
|
|
39
|
+
case 'saved': return t('screen.provider.keySavedLabel');
|
|
40
|
+
case 'environment': return t('screen.provider.keyFrom', { variable: row.environmentVariable ?? t('screen.provider.keyFromEnvironment') });
|
|
41
|
+
case 'environment-unanswered': return t('screen.provider.keyUnanswered');
|
|
42
|
+
case 'environment-declined': return t('screen.provider.keyDeclined');
|
|
43
|
+
case 'not-required': return t('screen.provider.keyNotRequired');
|
|
44
|
+
default: return t('screen.provider.keyMissing');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/*
|
|
48
|
+
* R4 Q-R4-11 (owner, 2026-09-24): what can be used now comes first. A local engine that needs no key and answered when the
|
|
49
|
+
* list opened; then a provider with a key usable now (or a configured external agent); then a local engine not checked; then
|
|
50
|
+
* one that did not answer; then the rest. Alphabetical inside each group, and a typed query still ranks first (the same
|
|
51
|
+
* `filterItems`), so "ollama" highlights Ollama Local. The groups are sort keys only: nothing is hidden.
|
|
52
|
+
*/
|
|
53
|
+
export function providerUsabilityRank(row, reachable) {
|
|
54
|
+
if (row.local && !row.requiresKey)
|
|
55
|
+
return reachable === true ? 0 : reachable === false ? 3 : 2;
|
|
56
|
+
return row.configured ? 1 : 4;
|
|
57
|
+
}
|
|
58
|
+
export function providerPickerItems(rows, query, { reachable = () => null } = {}) {
|
|
59
|
+
return filterItems(rows.map(row => ({ id: row.id, label: row.label, searchText: `${row.id} ${row.label} ${row.description}`, group: String(providerUsabilityRank(row, reachable(row.id))), value: row })), query).map(item => item.value);
|
|
60
|
+
}
|
|
61
|
+
/* How long opening the list waits for local engines to answer; one that has not answered by then is "not checked". */
|
|
62
|
+
export const LOCAL_ENGINE_CHECK_MS = 800;
|
|
63
|
+
function reachableFrom(probe) {
|
|
64
|
+
if (!probe)
|
|
65
|
+
return null;
|
|
66
|
+
return probe.state === 'available' ? true : probe.state === 'unavailable' ? false : null;
|
|
67
|
+
}
|
|
68
|
+
export function maskedSecret(secret) { return '•'.repeat([...secret].length); }
|
|
69
|
+
export function createProviderPickerModel(catalog) {
|
|
70
|
+
let providers = [];
|
|
71
|
+
let selected = 0;
|
|
72
|
+
let abort = null;
|
|
73
|
+
const probes = new Map();
|
|
74
|
+
return {
|
|
75
|
+
async open() {
|
|
76
|
+
abort?.abort();
|
|
77
|
+
abort = null;
|
|
78
|
+
providers = await catalog.listProviders();
|
|
79
|
+
selected = 0;
|
|
80
|
+
/* R4 Q-R4-11: only local engines that need no key are checked, all at once and briefly; nothing on the network is. */
|
|
81
|
+
const locals = providers.filter(row => row.local && !row.requiresKey);
|
|
82
|
+
if (!locals.length)
|
|
83
|
+
return;
|
|
84
|
+
const check = new AbortController();
|
|
85
|
+
const timer = setTimeout(() => check.abort(), LOCAL_ENGINE_CHECK_MS);
|
|
86
|
+
const answered = Promise.all(locals.map(async (row) => { try {
|
|
87
|
+
probes.set(row.id, await catalog.probeProvider(row.id, check.signal));
|
|
88
|
+
}
|
|
89
|
+
catch { /* not checked */ } }));
|
|
90
|
+
try {
|
|
91
|
+
await Promise.race([answered, new Promise(resolve => check.signal.addEventListener('abort', () => resolve(), { once: true }))]);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
check.abort();
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
async probeSelected() { const row = providers[selected]; if (!row)
|
|
99
|
+
return null; abort?.abort(); abort = new AbortController(); const result = await catalog.probeProvider(row.id, abort.signal); probes.set(row.id, result); return result; },
|
|
100
|
+
cancel() { abort?.abort(); abort = null; },
|
|
101
|
+
rows: () => providers,
|
|
102
|
+
selected: () => selected,
|
|
103
|
+
select(index) { selected = Math.max(0, Math.min(Math.max(0, providers.length - 1), index)); },
|
|
104
|
+
probeState: id => probes.get(id),
|
|
105
|
+
reachable: id => reachableFrom(probes.get(id)),
|
|
106
|
+
async setSecret(secret) { const row = providers[selected]; if (!row)
|
|
107
|
+
return null; try {
|
|
108
|
+
return await catalog.setProviderKey(row.id, secret);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
secret = '';
|
|
112
|
+
} },
|
|
113
|
+
async clearSecret() { const row = providers[selected]; if (!row)
|
|
114
|
+
return; await catalog.clearProviderKey(row.id); },
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// R1 Q-R1-3: the three provider steps as app.ts draws them, capped and scrolled by overlays/scroll-window.ts.
|
|
118
|
+
/* R4 Q-R4-11: `chosen` marks the provider in use; `reachable` says whether a local engine is running (nothing when not checked). */
|
|
119
|
+
export function providerPickerOverlay({ query, rows, selected, chosen = null, reachable = () => null }) {
|
|
120
|
+
const running = (row) => { if (!row.local)
|
|
121
|
+
return ''; const state = reachable(row.id); return state === null ? '' : ` · ${t(state ? 'firstrun.providers.running' : 'firstrun.providers.notRunning')}`; };
|
|
122
|
+
return {
|
|
123
|
+
head: [{ text: t('screen.provider.title'), tone: 'title' }, { text: t('screen.picker.searchChoose', { query: query || t('screen.none') }), tone: 'dim' }],
|
|
124
|
+
sections: [pickerSection(rows, selected, row => `${row.label}${row.id === chosen ? ` · ${t('firstrun.providers.chosen')}` : ''} · ${providerKeySourceLabel(row)} · ${t(row.local ? 'screen.word.local' : 'screen.word.cloud')}${running(row)}${row.endpointHost ? ` · ${row.endpointHost}` : ''}`)],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// The question scrolls with its options, so a short budget keeps the chosen answer on screen before the question.
|
|
128
|
+
export function providerConsentOverlay({ provider, choice }) {
|
|
129
|
+
const asked = consentQuestion(provider), index = asked.options.findIndex(option => option.choice === choice);
|
|
130
|
+
return {
|
|
131
|
+
head: [{ text: t('screen.provider.titleNamed', { provider: provider.label }), tone: 'title' }],
|
|
132
|
+
sections: [{ lines: [{ text: asked.question, tone: 'plain' }, ...asked.options.map(option => ({ text: `${option.choice === choice ? '›' : ' '} ${option.label}`, tone: option.choice === choice ? 'selected' : 'accent' }))], selected: 1 + Math.max(0, index) }],
|
|
133
|
+
foot: [{ text: t('screen.provider.consentFoot'), tone: 'dim' }],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Only the MASK reaches this view, never the typed key. The key line is the "selected" row: it is where the person types.
|
|
137
|
+
export function providerKeyOverlay({ label, remediation, benched, masked, keyTestNotice, testing, result }) {
|
|
138
|
+
const lines = [...(remediation ? [remediation] : []), ...(benched ? [benched] : [])];
|
|
139
|
+
const keyLine = lines.length;
|
|
140
|
+
lines.push(t('screen.provider.keyPrompt', { provider: label, masked: masked || ' ' }), ...(keyTestNotice ? [keyTestNotice] : []));
|
|
141
|
+
const status = testing ? { text: t('screen.provider.keyTesting', { provider: label }), tone: 'dim' }
|
|
142
|
+
: result ? { text: t('screen.provider.keyResult', { result }), tone: 'plain' }
|
|
143
|
+
: { text: t('screen.provider.keyFoot'), tone: 'dim' };
|
|
144
|
+
return { head: [{ text: t('screen.provider.titleNamed', { provider: label }), tone: 'title' }], sections: [{ lines: lines.map(text => ({ text, tone: 'plain' })), selected: keyLine }], foot: [status] };
|
|
145
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { t, tn } from "../../i18n/index.js";
|
|
2
|
+
import { queuedActionPreview } from "../shell-model.js";
|
|
3
|
+
import { centerTones, listOverlay } from "./scroll-window.js";
|
|
4
|
+
export function queueEditorSelected(entries, selected) {
|
|
5
|
+
if (entries.length === 0)
|
|
6
|
+
return null;
|
|
7
|
+
return entries[Math.max(0, Math.min(entries.length - 1, Math.trunc(selected) || 0))] ?? null;
|
|
8
|
+
}
|
|
9
|
+
export function queueEditorLines({ entries, selected, paused, editing, draft }) {
|
|
10
|
+
const active = queueEditorSelected(entries, selected), index = active ? entries.findIndex(row => row.id === active.id) : -1;
|
|
11
|
+
const lines = [t(paused ? 'screen.queueEditor.restored' : 'screen.queueEditor.live'), entries.length ? tn('screen.queueEditor.count', entries.length) : t('screen.queue.empty')];
|
|
12
|
+
for (let i = 0; i < entries.length; i++) {
|
|
13
|
+
const row = entries[i], status = row.status === 'uncertain' ? ` · ${t('screen.queueEditor.uncertain')}` : '';
|
|
14
|
+
const attachments = row.attachments?.length ? ` · ${tn('screen.queueEditor.attachments', row.attachments.length)}` : '';
|
|
15
|
+
/* R5a Q-R5-8: a queued slash command (`kind:'slash'`) is shown as the command it is, not as a follow-up message. */
|
|
16
|
+
const label = row.kind === 'command' ? '!' : row.kind === 'slash' ? '' : t('screen.queueEditor.followUp');
|
|
17
|
+
lines.push(`${i === index ? '›' : ' '} ${i + 1}. ${label}${queuedActionPreview(row.text).slice(0, 180)}${attachments}${status}`);
|
|
18
|
+
}
|
|
19
|
+
if (editing)
|
|
20
|
+
lines.push(t('screen.queueEditor.edit', { draft: queuedActionPreview(draft).slice(0, 220) || t('screen.none') }), t('screen.queueEditor.editKeys'));
|
|
21
|
+
else
|
|
22
|
+
lines.push(t('screen.queueEditor.keys'));
|
|
23
|
+
if (paused && entries.some(row => row.status === 'uncertain'))
|
|
24
|
+
lines.push(t('screen.queueEditor.retryWarning'));
|
|
25
|
+
return lines;
|
|
26
|
+
}
|
|
27
|
+
// R1 Q-R1-3: the same lines as a capped, scrolling overlay (overlays/scroll-window.ts).
|
|
28
|
+
export function queueEditorOverlay(view) {
|
|
29
|
+
const lines = queueEditorLines(view), active = queueEditorSelected(view.entries, view.selected);
|
|
30
|
+
const selected = active ? view.entries.findIndex(row => row.id === active.id) : 0;
|
|
31
|
+
return listOverlay(lines, { head: 2, list: view.entries.length, selected, foot: lines.length - 2 - view.entries.length, tones: centerTones });
|
|
32
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { centerTones, listOverlay } from "./scroll-window.js";
|
|
3
|
+
const UNSAFE = /[\\\x00-\x1f\x7f-\x9f\u2028\u2029\p{Bidi_Control}\p{Default_Ignorable_Code_Point}]/gu;
|
|
4
|
+
function inert(value, max = 360) { const safe = String(value ?? '').replace(UNSAFE, ch => { if (ch === '\\')
|
|
5
|
+
return '\\\\'; const cp = ch.codePointAt(0) ?? 0; return cp <= 0xffff ? '\\u' + cp.toString(16).padStart(4, '0') : '\\u{' + cp.toString(16) + '}'; }); return safe.length > max ? safe.slice(0, max - 1) + '…' : safe; }
|
|
6
|
+
function clamp(value, count) { return count ? Math.max(0, Math.min(count - 1, value)) : 0; }
|
|
7
|
+
export function createResearchCenterModel(snapshot, selected = 0) { return { snapshot, selected: clamp(selected, snapshot.rows.length), detail: null }; }
|
|
8
|
+
export function moveResearchCenterSelection(model, delta) { return { ...model, selected: clamp(model.selected + delta, model.snapshot.rows.length), detail: null }; }
|
|
9
|
+
export function selectedResearch(model) { return model.snapshot.rows[model.selected] ?? null; }
|
|
10
|
+
export function setResearchCenterDetail(model, detail) { return { ...model, detail }; }
|
|
11
|
+
export function renderResearchCenterLines(model) {
|
|
12
|
+
const lines = [t('screen.research.title')];
|
|
13
|
+
if (model.snapshot.state === 'invalid') {
|
|
14
|
+
lines.push('Store: invalid · ' + inert(model.snapshot.error?.code ?? 'RESEARCH_STORE_INVALID') + ' · ' + inert(model.snapshot.error?.message ?? 'unavailable'));
|
|
15
|
+
lines.push(t('screen.center.closeRefreshU'));
|
|
16
|
+
return lines;
|
|
17
|
+
}
|
|
18
|
+
if (!model.snapshot.rows.length) {
|
|
19
|
+
lines.push(t('screen.research.empty'));
|
|
20
|
+
lines.push(t('screen.center.closeRefreshU'));
|
|
21
|
+
return lines;
|
|
22
|
+
}
|
|
23
|
+
lines.push(...model.snapshot.rows.map((row, index) => (index === model.selected ? '› ' : ' ') + inert(row.status) + ' · ' + inert(row.question ?? row.name ?? 'untitled') + ' · ' + inert(row.id)));
|
|
24
|
+
const row = selectedResearch(model), detail = model.detail?.id === row?.id ? model.detail : null;
|
|
25
|
+
if (row) {
|
|
26
|
+
lines.push('ID: ' + inert(row.id) + ' · status ' + inert(row.status));
|
|
27
|
+
if (detail) {
|
|
28
|
+
lines.push('Phase: ' + inert(detail.phase ?? 'unavailable') + ' · progress ' + (detail.progress ? detail.progress.done + '/' + detail.progress.total : 'unmeasured'));
|
|
29
|
+
lines.push('Journal: ' + (detail.journal ? detail.journal.events + ' events · skipped ' + detail.journal.skippedRows : 'unavailable'));
|
|
30
|
+
if (detail.verification)
|
|
31
|
+
lines.push('Verification: total ' + detail.verification.total + ' · yes ' + detail.verification.supported + ' · partial ' + detail.verification.partial + ' · no ' + detail.verification.unsupported + ' · unchecked ' + detail.verification.unchecked + ' · contested ' + detail.verification.contested);
|
|
32
|
+
else
|
|
33
|
+
lines.push('Verification: unmeasured');
|
|
34
|
+
if (detail.summary)
|
|
35
|
+
lines.push('Summary: ' + inert(detail.summary));
|
|
36
|
+
if (detail.claims?.length) {
|
|
37
|
+
lines.push('Claims / evidence:');
|
|
38
|
+
for (const claim of detail.claims) {
|
|
39
|
+
lines.push('- Claim ' + claim.number + ' [' + inert(claim.verification ?? 'unmeasured') + ']: ' + inert(claim.text));
|
|
40
|
+
lines.push(' Source: ' + (claim.source ? claim.source.number + ' · ' + inert(claim.source.title) + ' · ' + inert(claim.source.url) : 'unavailable'));
|
|
41
|
+
lines.push(' Passage: ' + inert(claim.passage || 'unavailable'));
|
|
42
|
+
if (claim.reason)
|
|
43
|
+
lines.push(' Reason: ' + inert(claim.reason));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
lines.push('Claims / evidence: unmeasured');
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
lines.push('Detail: loading/unavailable');
|
|
51
|
+
}
|
|
52
|
+
lines.push(t('screen.research.keys'));
|
|
53
|
+
return lines;
|
|
54
|
+
}
|
|
55
|
+
// R1 Q-R1-3: the same lines as a capped, scrolling overlay — the list keeps the selection visible, the detail scrolls.
|
|
56
|
+
export function researchCenterOverlay(model) {
|
|
57
|
+
const list = model.snapshot.state === 'invalid' ? 0 : model.snapshot.rows.length;
|
|
58
|
+
return listOverlay(renderResearchCenterLines(model), { head: 1, list, selected: model.selected, foot: 1, tones: centerTones });
|
|
59
|
+
}
|