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,219 @@
|
|
|
1
|
+
import { displayWidth, splitGraphemes } from "../text-width.js";
|
|
2
|
+
import { composerSegments, copySelection, deleteBackward, deleteForward, draftText, editorFromDraft, insertPaste, killToEnd, killToStart, killWordBackward, moveCursor, moveVertical, moveWord, redoEditor, undoEditor, yank } from "../editor.js";
|
|
3
|
+
export function createComposerStore(initial) {
|
|
4
|
+
let snapshot = initial;
|
|
5
|
+
const listeners = new Set();
|
|
6
|
+
const publish = (next) => {
|
|
7
|
+
if (next === snapshot)
|
|
8
|
+
return snapshot;
|
|
9
|
+
snapshot = next;
|
|
10
|
+
for (const listener of [...listeners])
|
|
11
|
+
listener();
|
|
12
|
+
return snapshot;
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
getSnapshot: () => snapshot,
|
|
16
|
+
subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener); },
|
|
17
|
+
update(fn) { return publish(fn(snapshot)); },
|
|
18
|
+
replace(next) { return publish(next); },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function composerFastTextInput(input) {
|
|
22
|
+
if (input.bootPhase !== 'ready' || input.focus !== 'composer' || input.modalOwner || input.auxCount !== 0)
|
|
23
|
+
return null;
|
|
24
|
+
if (input.vimMode !== 'disabled' && input.vimMode !== 'insert')
|
|
25
|
+
return null;
|
|
26
|
+
if (input.key.ctrl || input.key.meta)
|
|
27
|
+
return null;
|
|
28
|
+
if (input.routed?.kind !== 'text' || typeof input.routed.text !== 'string' || input.routed.text.length !== 1)
|
|
29
|
+
return null;
|
|
30
|
+
const code = input.routed.text.charCodeAt(0);
|
|
31
|
+
return code < 32 || code === 127 ? null : input.routed.text;
|
|
32
|
+
}
|
|
33
|
+
export function composerOwnsPaste(input) {
|
|
34
|
+
if (input.bootPhase !== 'ready' || input.focus !== 'composer' || input.modalOwner || input.auxCount !== 0)
|
|
35
|
+
return false;
|
|
36
|
+
return input.vimMode === 'disabled' || input.vimMode === 'insert';
|
|
37
|
+
}
|
|
38
|
+
export function composerFastPasteInput(input) {
|
|
39
|
+
if (!composerOwnsPaste(input))
|
|
40
|
+
return null;
|
|
41
|
+
if (input.key.ctrl || input.key.meta)
|
|
42
|
+
return null;
|
|
43
|
+
if (input.routed?.kind !== 'text' || typeof input.routed.text !== 'string' || input.routed.text.length <= 1)
|
|
44
|
+
return null;
|
|
45
|
+
return input.routed.text;
|
|
46
|
+
}
|
|
47
|
+
export function applyComposerFastPasteInput(editor, text) {
|
|
48
|
+
return insertPaste(editor, text);
|
|
49
|
+
}
|
|
50
|
+
export function composerFastEditorAction(input) {
|
|
51
|
+
if (input.bootPhase !== 'ready' || input.focus !== 'composer' || input.modalOwner || input.auxCount !== 0)
|
|
52
|
+
return null;
|
|
53
|
+
if (input.vimMode !== 'disabled' && input.vimMode !== 'insert')
|
|
54
|
+
return null;
|
|
55
|
+
if (input.routed?.kind !== 'action' || typeof input.routed.action !== 'string')
|
|
56
|
+
return null;
|
|
57
|
+
const action = input.routed.action;
|
|
58
|
+
const allowed = ['backspace', 'delete-forward', 'left', 'right', 'home', 'end', 'word-left', 'word-right', 'select-left', 'select-right', 'select-home', 'select-end', 'select-up', 'select-down', 'select-word-left', 'select-word-right', 'kill-start', 'kill-end', 'kill-word', 'yank', 'undo', 'redo', 'copy-selection'];
|
|
59
|
+
if (!allowed.includes(action))
|
|
60
|
+
return null;
|
|
61
|
+
if (action === 'delete-forward' && input.editor.text.length === 0)
|
|
62
|
+
return null;
|
|
63
|
+
return action;
|
|
64
|
+
}
|
|
65
|
+
export function applyComposerFastEditorAction(editor, action) {
|
|
66
|
+
if (action === 'backspace')
|
|
67
|
+
return deleteBackward(editor);
|
|
68
|
+
if (action === 'delete-forward')
|
|
69
|
+
return deleteForward(editor);
|
|
70
|
+
if (action === 'left' || action === 'right' || action === 'home' || action === 'end')
|
|
71
|
+
return moveCursor(editor, action);
|
|
72
|
+
if (action === 'word-left')
|
|
73
|
+
return moveWord(editor, -1);
|
|
74
|
+
if (action === 'word-right')
|
|
75
|
+
return moveWord(editor, 1);
|
|
76
|
+
if (action === 'select-left')
|
|
77
|
+
return moveCursor(editor, 'left', true);
|
|
78
|
+
if (action === 'select-right')
|
|
79
|
+
return moveCursor(editor, 'right', true);
|
|
80
|
+
if (action === 'select-home')
|
|
81
|
+
return moveCursor(editor, 'home', true);
|
|
82
|
+
if (action === 'select-end')
|
|
83
|
+
return moveCursor(editor, 'end', true);
|
|
84
|
+
if (action === 'select-up')
|
|
85
|
+
return moveVertical(editor, -1, true);
|
|
86
|
+
if (action === 'select-down')
|
|
87
|
+
return moveVertical(editor, 1, true);
|
|
88
|
+
if (action === 'select-word-left')
|
|
89
|
+
return moveWord(editor, -1, true);
|
|
90
|
+
if (action === 'select-word-right')
|
|
91
|
+
return moveWord(editor, 1, true);
|
|
92
|
+
if (action === 'kill-start')
|
|
93
|
+
return killToStart(editor);
|
|
94
|
+
if (action === 'kill-end')
|
|
95
|
+
return killToEnd(editor);
|
|
96
|
+
if (action === 'kill-word')
|
|
97
|
+
return killWordBackward(editor);
|
|
98
|
+
if (action === 'yank')
|
|
99
|
+
return yank(editor);
|
|
100
|
+
if (action === 'undo')
|
|
101
|
+
return undoEditor(editor);
|
|
102
|
+
if (action === 'redo')
|
|
103
|
+
return redoEditor(editor);
|
|
104
|
+
if (action === 'copy-selection')
|
|
105
|
+
return copySelection(editor);
|
|
106
|
+
return editor;
|
|
107
|
+
}
|
|
108
|
+
export function planComposerHistoryAction(input) {
|
|
109
|
+
if (input.bootPhase !== 'ready' || input.focus !== 'composer' || input.modalOwner || input.auxCount !== 0)
|
|
110
|
+
return null;
|
|
111
|
+
if (input.vimMode !== 'disabled' && input.vimMode !== 'insert')
|
|
112
|
+
return null;
|
|
113
|
+
if (input.routed?.kind !== 'action' || typeof input.routed.action !== 'string')
|
|
114
|
+
return null;
|
|
115
|
+
const action = input.routed.action;
|
|
116
|
+
if (action !== 'history-prev' && action !== 'history-next' && action !== 'history-search')
|
|
117
|
+
return null;
|
|
118
|
+
if (action === 'history-search') {
|
|
119
|
+
const found = reverseHistoryMatch(input.history, input.editor.text, input.reverseIndex);
|
|
120
|
+
if (!found)
|
|
121
|
+
return { editor: input.editor, historyIndex: input.historyIndex, reverseIndex: 0 };
|
|
122
|
+
return { editor: editorFromDraft(input.history[found.index] ?? found.value), historyIndex: found.index, reverseIndex: found.index + 1 };
|
|
123
|
+
}
|
|
124
|
+
if (!input.key.ctrl) {
|
|
125
|
+
const moved = moveVertical(input.editor, action === 'history-prev' ? -1 : 1);
|
|
126
|
+
const hadSelection = input.editor.selectionAnchor !== undefined;
|
|
127
|
+
if (moved.cursor !== input.editor.cursor || hadSelection) {
|
|
128
|
+
return { editor: moved, historyIndex: input.historyIndex, reverseIndex: input.reverseIndex };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (input.history.length === 0)
|
|
132
|
+
return { editor: input.editor, historyIndex: input.historyIndex, reverseIndex: input.reverseIndex };
|
|
133
|
+
const delta = action === 'history-prev' ? 1 : -1;
|
|
134
|
+
const next = Math.max(-1, Math.min(input.history.length - 1, input.historyIndex + delta));
|
|
135
|
+
return {
|
|
136
|
+
editor: editorFromDraft(next >= 0 ? (input.history[next] ?? '') : ''),
|
|
137
|
+
historyIndex: next,
|
|
138
|
+
reverseIndex: 0,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export function reverseHistoryMatch(history, query, from = 0) { for (let i = Math.max(0, from); i < history.length; i++) {
|
|
142
|
+
const value = draftText(history[i]);
|
|
143
|
+
if (value.toLowerCase().includes(query.toLowerCase()))
|
|
144
|
+
return { index: i, value };
|
|
145
|
+
} return null; }
|
|
146
|
+
export function composerDisplay(state) { return composerSegments(state); }
|
|
147
|
+
export const COMPOSER_PREFIX_COLUMNS = 2;
|
|
148
|
+
/*
|
|
149
|
+
* R3 owner decision (keep TAB): a tab in the text is drawn as spaces up to the next COMPOSER_TAB_STOP, clipped at the end
|
|
150
|
+
* of the row, so the width the budget measures is the width Ink draws (string-width gives a raw tab 0 cells, the terminal
|
|
151
|
+
* up to 8). Display only: the editor keeps the tab, and the cursor on a tab is one cell at its start.
|
|
152
|
+
*/
|
|
153
|
+
export const COMPOSER_TAB_STOP = 4;
|
|
154
|
+
export function composerRows(segments, contentWidth) {
|
|
155
|
+
const width = Math.max(1, Math.floor(contentWidth));
|
|
156
|
+
const rows = [[]];
|
|
157
|
+
let used = 0, cursorRow = 0;
|
|
158
|
+
const push = (text, kind, selected) => {
|
|
159
|
+
const row = rows[rows.length - 1];
|
|
160
|
+
const last = row[row.length - 1];
|
|
161
|
+
if (last && last.kind === kind && last.selected === selected && kind !== 'cursor')
|
|
162
|
+
last.text += text;
|
|
163
|
+
else
|
|
164
|
+
row.push({ text, kind, selected });
|
|
165
|
+
};
|
|
166
|
+
const breakRow = () => { rows.push([]); used = 0; };
|
|
167
|
+
const tabCells = () => { if (used >= width)
|
|
168
|
+
breakRow(); return Math.min(COMPOSER_TAB_STOP - (used % COMPOSER_TAB_STOP), width - used); };
|
|
169
|
+
for (const segment of segments) {
|
|
170
|
+
const selected = Boolean(segment.selected);
|
|
171
|
+
if (segment.kind === 'cursor' && segment.text === '\t') {
|
|
172
|
+
const w = tabCells();
|
|
173
|
+
cursorRow = rows.length - 1;
|
|
174
|
+
push(' ', 'cursor', selected);
|
|
175
|
+
if (w > 1)
|
|
176
|
+
push(' '.repeat(w - 1), 'text', selected);
|
|
177
|
+
used += w;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (segment.kind === 'cursor') {
|
|
181
|
+
/* The cursor on a line break is drawn as a cell at the end of the row, then the row breaks. */
|
|
182
|
+
const cell = segment.text === '\n' || segment.text === '' ? ' ' : segment.text;
|
|
183
|
+
const w = Math.max(1, displayWidth(cell));
|
|
184
|
+
if (used + w > width && used > 0)
|
|
185
|
+
breakRow();
|
|
186
|
+
cursorRow = rows.length - 1;
|
|
187
|
+
push(cell, 'cursor', selected);
|
|
188
|
+
used += w;
|
|
189
|
+
if (segment.text === '\n')
|
|
190
|
+
breakRow();
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
for (const g of splitGraphemes(segment.text)) {
|
|
194
|
+
if (g === '\n' || g === '\r\n') {
|
|
195
|
+
breakRow();
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (g === '\t') {
|
|
199
|
+
const w = tabCells();
|
|
200
|
+
push(' '.repeat(w), segment.kind, selected);
|
|
201
|
+
used += w;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const w = displayWidth(g);
|
|
205
|
+
if (used + w > width && used > 0)
|
|
206
|
+
breakRow();
|
|
207
|
+
push(g, segment.kind, selected);
|
|
208
|
+
used += w;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return { rows, cursorRow };
|
|
212
|
+
}
|
|
213
|
+
export function composerLayout(segments, { contentWidth, maxRows }) {
|
|
214
|
+
const { rows, cursorRow } = composerRows(segments, contentWidth);
|
|
215
|
+
const visible = Math.max(1, Math.floor(maxRows));
|
|
216
|
+
const start = Math.max(0, Math.min(rows.length - visible, cursorRow - visible + 1));
|
|
217
|
+
const shown = rows.slice(start, start + visible);
|
|
218
|
+
return { rows: shown, total: rows.length, start, cursorRow, hiddenAbove: start, hiddenBelow: Math.max(0, rows.length - start - shown.length) };
|
|
219
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { displayWidth, truncateDisplay } from "../text-width.js";
|
|
3
|
+
/* R3: the sanitiser is imported from its leaf module (tools/shared.ts), not through transcript-model.ts, because the tool
|
|
4
|
+
rows now render diffs with this file and the transcript model imports the tool rows (no import cycle). */
|
|
5
|
+
import { sanitizeDisplayText as sanitizeTranscriptText } from "../tools/shared.js";
|
|
6
|
+
function safe(value) { return sanitizeTranscriptText(value); }
|
|
7
|
+
function prefix(row) { return row.kind === 'add' ? '+' : row.kind === 'remove' ? '-' : row.kind === 'context' ? ' ' : ' '; }
|
|
8
|
+
function fit(value, width) { const limit = Math.max(1, Math.floor(width)); return displayWidth(value) <= limit ? value : truncateDisplay(value, limit); }
|
|
9
|
+
function wideRow(row, width) {
|
|
10
|
+
if (row.kind === 'add' || row.kind === 'remove' || row.kind === 'context') {
|
|
11
|
+
const old = row.oldLine === null ? '' : String(row.oldLine), next = row.newLine === null ? '' : String(row.newLine);
|
|
12
|
+
const text = old.padStart(5) + ' ' + next.padStart(5) + ' │ ' + prefix(row) + safe(row.text);
|
|
13
|
+
return { kind: row.kind, text: fit(text, width) };
|
|
14
|
+
}
|
|
15
|
+
return { kind: row.kind, text: fit(safe(row.text), width) };
|
|
16
|
+
}
|
|
17
|
+
function narrowRow(row, width) {
|
|
18
|
+
const text = (row.kind === 'add' || row.kind === 'remove' || row.kind === 'context' ? prefix(row) : '') + safe(row.text);
|
|
19
|
+
return { kind: row.kind, text: fit(text, width) };
|
|
20
|
+
}
|
|
21
|
+
export function renderDiffModel(model, width) {
|
|
22
|
+
const limit = Math.max(1, Math.floor(width)), mode = limit >= 72 ? 'unified' : 'narrow';
|
|
23
|
+
if (model.empty)
|
|
24
|
+
return { mode, empty: true, lines: [{ kind: 'meta', text: t('screen.diff.noChanges') }] };
|
|
25
|
+
const lines = [];
|
|
26
|
+
for (const plain of model.plain)
|
|
27
|
+
lines.push(mode === 'unified' ? wideRow(plain, limit) : narrowRow(plain, limit));
|
|
28
|
+
for (const file of model.files) {
|
|
29
|
+
const label = (file.oldPath || '—') + (file.oldPath !== file.newPath ? ' → ' + (file.newPath || '—') : '');
|
|
30
|
+
lines.push({ kind: 'file', text: fit(safe(label), limit) });
|
|
31
|
+
for (const row of file.rows)
|
|
32
|
+
lines.push(mode === 'unified' ? wideRow(row, limit) : narrowRow(row, limit));
|
|
33
|
+
}
|
|
34
|
+
return { mode, empty: false, lines };
|
|
35
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { displayWidth, truncateDisplay } from "../text-width.js";
|
|
3
|
+
export function sanitizeStatus(text) {
|
|
4
|
+
return String(text).replace(/[\r\n\t]+/gu, ' ').replace(/\s{2,}/gu, ' ').trim();
|
|
5
|
+
}
|
|
6
|
+
export function layoutFooter(fields, width) {
|
|
7
|
+
const limit = Math.max(0, Math.floor(width));
|
|
8
|
+
if (limit === 0)
|
|
9
|
+
return '';
|
|
10
|
+
const kept = [...fields]
|
|
11
|
+
.filter(field => sanitizeStatus(field.text).length > 0)
|
|
12
|
+
.sort((a, b) => b.priority - a.priority);
|
|
13
|
+
const render = () => kept.map(field => sanitizeStatus(field.text)).join(' · ');
|
|
14
|
+
while (kept.length && displayWidth(render()) > limit) {
|
|
15
|
+
let lowest = 0;
|
|
16
|
+
for (let index = 1; index < kept.length; index++)
|
|
17
|
+
if (kept[index].priority < kept[lowest].priority)
|
|
18
|
+
lowest = index;
|
|
19
|
+
kept.splice(lowest, 1);
|
|
20
|
+
}
|
|
21
|
+
return truncateDisplay(render(), limit);
|
|
22
|
+
}
|
|
23
|
+
export function contextUsageLabel(usage, _contextWindow) {
|
|
24
|
+
if (!usage || typeof usage !== 'object')
|
|
25
|
+
return null;
|
|
26
|
+
const row = usage;
|
|
27
|
+
if (row.schema === 'talos.cli.context-status.v1') {
|
|
28
|
+
const measured = row.measurement && typeof row.measurement === 'object' ? row.measurement : null;
|
|
29
|
+
const input = finiteNumber(measured?.inputTokens), window = finiteNumber(measured?.windowTokens), percent = finiteNumber(measured?.percentOfWindow);
|
|
30
|
+
if (input === null || window === null || window <= 0 || percent === null)
|
|
31
|
+
return null;
|
|
32
|
+
return t(measured?.stale === true ? 'screen.footer.contextStale' : 'screen.footer.context', { input: compactCount(input), window: compactCount(window), percent });
|
|
33
|
+
}
|
|
34
|
+
const prompt = finiteNumber(row.prompt_tokens ?? row.promptTokens ?? row.input_tokens ?? row.inputTokens);
|
|
35
|
+
const completion = finiteNumber(row.completion_tokens ?? row.completionTokens ?? row.output_tokens ?? row.outputTokens);
|
|
36
|
+
if (prompt === null && completion === null)
|
|
37
|
+
return null;
|
|
38
|
+
return t('screen.footer.usage', { total: compactCount((prompt ?? 0) + (completion ?? 0)) });
|
|
39
|
+
}
|
|
40
|
+
function finiteNumber(value) { return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : null; }
|
|
41
|
+
function compactCount(value) {
|
|
42
|
+
if (value < 1000)
|
|
43
|
+
return String(Math.round(value));
|
|
44
|
+
if (value < 1_000_000)
|
|
45
|
+
return `${trimDecimal(value / 1000)}k`;
|
|
46
|
+
return `${trimDecimal(value / 1_000_000)}m`;
|
|
47
|
+
}
|
|
48
|
+
function trimDecimal(value) { return value.toFixed(1).replace(/\.0$/u, ''); }
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { highlightCodeLine } from "../highlight.js";
|
|
3
|
+
import { displayWidth } from "../text-width.js";
|
|
4
|
+
import { sanitizeTranscriptText } from "../transcript-model.js";
|
|
5
|
+
export function markdownRenderPropsEqual(previous, next) { return previous.text === next.text && previous.width === next.width; }
|
|
6
|
+
export function createMarkdownParseMemo({ parser = parseMarkdownBlocks } = {}) {
|
|
7
|
+
let cachedText = null, cachedBlocks = null;
|
|
8
|
+
return {
|
|
9
|
+
get(text) { const value = String(text); if (cachedBlocks !== null && cachedText === value)
|
|
10
|
+
return cachedBlocks; const blocks = parser(value); cachedText = value; cachedBlocks = blocks; return blocks; },
|
|
11
|
+
invalidate() { cachedText = null; cachedBlocks = null; },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function markdownSafeText(text) { return sanitizeTranscriptText(String(text)); }
|
|
15
|
+
function safeLinkDestination(value) {
|
|
16
|
+
const destination = markdownSafeText(value).trim();
|
|
17
|
+
if (!destination || /[\s\x00-\x1f\x7f]/u.test(destination))
|
|
18
|
+
return null;
|
|
19
|
+
if (destination.startsWith('#') || destination.startsWith('./') || destination.startsWith('../') || destination.startsWith('/'))
|
|
20
|
+
return destination;
|
|
21
|
+
const scheme = /^([A-Za-z][A-Za-z0-9+.-]*):/u.exec(destination)?.[1]?.toLowerCase() ?? null;
|
|
22
|
+
if (!scheme)
|
|
23
|
+
return destination;
|
|
24
|
+
return scheme === 'http' || scheme === 'https' || scheme === 'mailto' ? destination : null;
|
|
25
|
+
}
|
|
26
|
+
function mergeInlineText(tokens) { const out = []; for (const token of tokens) {
|
|
27
|
+
const previous = out.at(-1);
|
|
28
|
+
if (token.kind === 'text' && previous?.kind === 'text')
|
|
29
|
+
previous.text += token.text;
|
|
30
|
+
else
|
|
31
|
+
out.push(token);
|
|
32
|
+
} return out; }
|
|
33
|
+
export function parseMarkdownInline(text) {
|
|
34
|
+
const safe = markdownSafeText(text), tokens = [];
|
|
35
|
+
let plain = '';
|
|
36
|
+
const flush = () => { if (plain) {
|
|
37
|
+
tokens.push({ kind: 'text', text: plain });
|
|
38
|
+
plain = '';
|
|
39
|
+
} };
|
|
40
|
+
for (let index = 0; index < safe.length;) {
|
|
41
|
+
const rest = safe.slice(index);
|
|
42
|
+
if (rest.startsWith('**')) {
|
|
43
|
+
const end = safe.indexOf('**', index + 2);
|
|
44
|
+
if (end < 0) {
|
|
45
|
+
plain += rest;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
flush();
|
|
49
|
+
tokens.push({ kind: 'strong', text: safe.slice(index + 2, end) });
|
|
50
|
+
index = end + 2;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (rest.startsWith('~~')) {
|
|
54
|
+
const end = safe.indexOf('~~', index + 2);
|
|
55
|
+
if (end < 0) {
|
|
56
|
+
plain += rest;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
flush();
|
|
60
|
+
tokens.push({ kind: 'strike', text: safe.slice(index + 2, end) });
|
|
61
|
+
index = end + 2;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (rest.startsWith('`')) {
|
|
65
|
+
const end = safe.indexOf('`', index + 1);
|
|
66
|
+
if (end < 0) {
|
|
67
|
+
plain += rest;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
flush();
|
|
71
|
+
tokens.push({ kind: 'code', text: safe.slice(index + 1, end) });
|
|
72
|
+
index = end + 1;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (rest.startsWith('*')) {
|
|
76
|
+
const end = safe.indexOf('*', index + 1);
|
|
77
|
+
if (end < 0) {
|
|
78
|
+
plain += rest;
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
flush();
|
|
82
|
+
tokens.push({ kind: 'emphasis', text: safe.slice(index + 1, end) });
|
|
83
|
+
index = end + 1;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (rest.startsWith('[')) {
|
|
87
|
+
const close = safe.indexOf('](', index + 1);
|
|
88
|
+
if (close >= 0) {
|
|
89
|
+
const end = safe.indexOf(')', close + 2);
|
|
90
|
+
if (end >= 0) {
|
|
91
|
+
const label = safe.slice(index + 1, close), target = safeLinkDestination(safe.slice(close + 2, end));
|
|
92
|
+
if (target) {
|
|
93
|
+
flush();
|
|
94
|
+
tokens.push({ kind: 'link', text: label, href: target });
|
|
95
|
+
index = end + 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
plain += safe[index] ?? '';
|
|
102
|
+
index++;
|
|
103
|
+
}
|
|
104
|
+
flush();
|
|
105
|
+
return mergeInlineText(tokens);
|
|
106
|
+
}
|
|
107
|
+
export function markdownInlineText(text) { return parseMarkdownInline(text).map(token => token.kind === 'link' ? `${token.text} (${token.href})` : token.text).join(''); }
|
|
108
|
+
function splitTableRow(line) {
|
|
109
|
+
let value = line.trim();
|
|
110
|
+
if (value.startsWith('|'))
|
|
111
|
+
value = value.slice(1);
|
|
112
|
+
if (value.endsWith('|') && !value.endsWith('\\|'))
|
|
113
|
+
value = value.slice(0, -1);
|
|
114
|
+
const cells = [], current = [];
|
|
115
|
+
let escaped = false;
|
|
116
|
+
for (const character of value) {
|
|
117
|
+
if (escaped) {
|
|
118
|
+
current.push(character);
|
|
119
|
+
escaped = false;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (character === '\\') {
|
|
123
|
+
escaped = true;
|
|
124
|
+
current.push(character);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (character === '|') {
|
|
128
|
+
cells.push(current.join('').trim().replace(/\\\|/gu, '|'));
|
|
129
|
+
current.length = 0;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
current.push(character);
|
|
133
|
+
}
|
|
134
|
+
if (escaped)
|
|
135
|
+
current.push('\\');
|
|
136
|
+
cells.push(current.join('').trim().replace(/\\\|/gu, '|'));
|
|
137
|
+
return cells;
|
|
138
|
+
}
|
|
139
|
+
function delimiterRow(line) {
|
|
140
|
+
const cells = splitTableRow(line);
|
|
141
|
+
if (!cells.length)
|
|
142
|
+
return null;
|
|
143
|
+
const align = [];
|
|
144
|
+
for (const cell of cells) {
|
|
145
|
+
if (!/^:?-{3,}:?$/u.test(cell))
|
|
146
|
+
return null;
|
|
147
|
+
align.push(cell.startsWith(':') && cell.endsWith(':') ? 'center' : cell.endsWith(':') ? 'right' : 'left');
|
|
148
|
+
}
|
|
149
|
+
return align;
|
|
150
|
+
}
|
|
151
|
+
function listRow(line) {
|
|
152
|
+
const unordered = /^(\s*)[-+*]\s+(.+)$/u.exec(line);
|
|
153
|
+
if (unordered)
|
|
154
|
+
return { ordered: false, start: 1, text: unordered[2] ?? '', depth: Math.floor((unordered[1]?.replace(/\t/gu, ' ').length ?? 0) / 2) };
|
|
155
|
+
const ordered = /^(\s*)(\d{1,9})[.)]\s+(.+)$/u.exec(line);
|
|
156
|
+
if (ordered)
|
|
157
|
+
return { ordered: true, start: Number(ordered[2]), text: ordered[3] ?? '', depth: Math.floor((ordered[1]?.replace(/\t/gu, ' ').length ?? 0) / 2) };
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
export function parseMarkdownBlocks(text) {
|
|
161
|
+
const lines = String(text).split(/\r?\n/u), out = [];
|
|
162
|
+
let paragraph = [];
|
|
163
|
+
let code = null;
|
|
164
|
+
let language = '';
|
|
165
|
+
const flushParagraph = () => { if (paragraph.length) {
|
|
166
|
+
out.push({ kind: 'paragraph', text: paragraph.join('\n') });
|
|
167
|
+
paragraph = [];
|
|
168
|
+
} };
|
|
169
|
+
const flushCode = () => { if (code) {
|
|
170
|
+
out.push({ kind: 'code', language, text: code.join('\n'), tokens: code.map(line => highlightCodeLine(line, language)) });
|
|
171
|
+
code = null;
|
|
172
|
+
language = '';
|
|
173
|
+
} };
|
|
174
|
+
for (let index = 0; index < lines.length;) {
|
|
175
|
+
const line = lines[index] ?? '';
|
|
176
|
+
const fence = /^```\s*([^\s`]*)/u.exec(line);
|
|
177
|
+
if (fence) {
|
|
178
|
+
if (code) {
|
|
179
|
+
flushCode();
|
|
180
|
+
index++;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
flushParagraph();
|
|
184
|
+
code = [];
|
|
185
|
+
language = fence[1] ?? '';
|
|
186
|
+
index++;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (code) {
|
|
190
|
+
code.push(line);
|
|
191
|
+
index++;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const heading = /^(#{1,6})\s+(.*)$/u.exec(line);
|
|
195
|
+
if (heading) {
|
|
196
|
+
flushParagraph();
|
|
197
|
+
out.push({ kind: 'heading', level: heading[1].length, text: heading[2] ?? '' });
|
|
198
|
+
index++;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (line === '') {
|
|
202
|
+
flushParagraph();
|
|
203
|
+
index++;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (/^\s*>/u.test(line)) {
|
|
207
|
+
flushParagraph();
|
|
208
|
+
const quoted = [];
|
|
209
|
+
while (index < lines.length) {
|
|
210
|
+
const match = /^\s*>\s?(.*)$/u.exec(lines[index] ?? '');
|
|
211
|
+
if (!match)
|
|
212
|
+
break;
|
|
213
|
+
quoted.push(match[1] ?? '');
|
|
214
|
+
index++;
|
|
215
|
+
}
|
|
216
|
+
out.push({ kind: 'blockquote', text: quoted.join('\n') });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const list = listRow(line);
|
|
220
|
+
if (list) {
|
|
221
|
+
flushParagraph();
|
|
222
|
+
const items = [list.text], depths = [list.depth], start = list.start;
|
|
223
|
+
index++;
|
|
224
|
+
while (index < lines.length) {
|
|
225
|
+
const next = listRow(lines[index] ?? '');
|
|
226
|
+
if (!next || next.ordered !== list.ordered)
|
|
227
|
+
break;
|
|
228
|
+
items.push(next.text);
|
|
229
|
+
depths.push(next.depth);
|
|
230
|
+
index++;
|
|
231
|
+
}
|
|
232
|
+
out.push({ kind: 'list', ordered: list.ordered, start, items, depths });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const next = lines[index + 1];
|
|
236
|
+
const align = next === undefined ? null : delimiterRow(next);
|
|
237
|
+
if (line.includes('|') && align) {
|
|
238
|
+
const headers = splitTableRow(line);
|
|
239
|
+
if (headers.length === align.length) {
|
|
240
|
+
flushParagraph();
|
|
241
|
+
const rows = [];
|
|
242
|
+
index += 2;
|
|
243
|
+
while (index < lines.length && (lines[index] ?? '').trim() !== '' && (lines[index] ?? '').includes('|')) {
|
|
244
|
+
const cells = splitTableRow(lines[index] ?? '');
|
|
245
|
+
if (cells.length !== headers.length)
|
|
246
|
+
break;
|
|
247
|
+
rows.push(cells);
|
|
248
|
+
index++;
|
|
249
|
+
}
|
|
250
|
+
out.push({ kind: 'table', headers, align, rows });
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
paragraph.push(line);
|
|
255
|
+
index++;
|
|
256
|
+
}
|
|
257
|
+
if (code)
|
|
258
|
+
flushCode();
|
|
259
|
+
flushParagraph();
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
262
|
+
function padCell(value, width, align) {
|
|
263
|
+
const gap = Math.max(0, width - displayWidth(value));
|
|
264
|
+
if (align === 'right')
|
|
265
|
+
return ' '.repeat(gap) + value;
|
|
266
|
+
if (align === 'center') {
|
|
267
|
+
const left = Math.floor(gap / 2);
|
|
268
|
+
return ' '.repeat(left) + value + ' '.repeat(gap - left);
|
|
269
|
+
}
|
|
270
|
+
return value + ' '.repeat(gap);
|
|
271
|
+
}
|
|
272
|
+
export function markdownBlockLines(block, width) {
|
|
273
|
+
const limit = Math.max(1, Math.floor(width));
|
|
274
|
+
if (block.kind === 'heading')
|
|
275
|
+
return { mode: 'plain', lines: [markdownInlineText(block.text)] };
|
|
276
|
+
if (block.kind === 'paragraph')
|
|
277
|
+
return { mode: 'plain', lines: markdownInlineText(block.text).split('\n') };
|
|
278
|
+
if (block.kind === 'blockquote')
|
|
279
|
+
return { mode: 'plain', lines: markdownInlineText(block.text).split('\n').map(line => '│ ' + line) };
|
|
280
|
+
if (block.kind === 'code')
|
|
281
|
+
return { mode: 'plain', lines: block.text.split('\n').map(markdownSafeText) };
|
|
282
|
+
if (block.kind === 'list')
|
|
283
|
+
return { mode: 'plain', lines: block.items.map((item, index) => ' '.repeat(block.depths[index] ?? 0) + (block.ordered ? String(block.start + index) + '. ' : '• ') + markdownInlineText(item)) };
|
|
284
|
+
const header = block.headers.map(markdownInlineText), rows = block.rows.map(row => row.map(markdownInlineText));
|
|
285
|
+
const widths = header.map((value, column) => Math.max(3, displayWidth(value), ...rows.map(row => displayWidth(row[column] ?? ''))));
|
|
286
|
+
const natural = widths.reduce((sum, value) => sum + value, 0) + Math.max(0, widths.length - 1) * 3;
|
|
287
|
+
if (limit >= Math.max(32, natural)) {
|
|
288
|
+
const render = (row) => row.map((value, column) => padCell(value ?? '', widths[column] ?? 3, block.align[column] ?? 'left')).join(' | ');
|
|
289
|
+
/* R3 gate E13 (D-13): the separator is dashes only. The alignment colon is Markdown source syntax; alignment is shown
|
|
290
|
+
by the cell padding above (`padCell`), the way Codex, Crush, Goose and Qwen draw an aligned table (gate §7). */
|
|
291
|
+
const separator = widths.map(size => '-'.repeat(size)).join('-+-');
|
|
292
|
+
return { mode: 'wide', lines: [render(header), separator, ...rows.map(render)] };
|
|
293
|
+
}
|
|
294
|
+
const lines = [];
|
|
295
|
+
rows.forEach((row, rowIndex) => {
|
|
296
|
+
if (rowIndex > 0)
|
|
297
|
+
lines.push('');
|
|
298
|
+
for (let column = 0; column < header.length; column++)
|
|
299
|
+
lines.push((header[column] || t('screen.markdown.column', { number: column + 1 })) + ': ' + (row[column] ?? ''));
|
|
300
|
+
});
|
|
301
|
+
if (rows.length === 0)
|
|
302
|
+
for (let column = 0; column < header.length; column++)
|
|
303
|
+
lines.push(header[column] ?? '');
|
|
304
|
+
return { mode: 'narrow', lines };
|
|
305
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { t } from "../../i18n/index.js";
|
|
2
|
+
import { frameIndex, stableElapsedLabel } from "../render-scheduler.js";
|
|
3
|
+
import { retryLine } from "../live-activity.js";
|
|
4
|
+
/* A static glyph for the states that do not spin: nothing moves while TALOS waits for the person or after the turn. */
|
|
5
|
+
const STATIC_GLYPH = {
|
|
6
|
+
idle: { unicode: ' ', ascii: ' ' }, error: { unicode: '!', ascii: '!' }, waiting: { unicode: '?', ascii: '?' }, retrying: { unicode: '↻', ascii: '~' },
|
|
7
|
+
done: { unicode: '✓', ascii: '+' }, interrupted: { unicode: '■', ascii: '-' }, failed: { unicode: '✗', ascii: 'x' },
|
|
8
|
+
};
|
|
9
|
+
/** The one word for an activity, shared by the status row and the main roster row (gate E7). */
|
|
10
|
+
export function activityWord(kind, tool) { return kind === 'tool' && tool ? t('screen.busy.toolNamed', { tool }) : t(`screen.busy.${kind}`); }
|
|
11
|
+
const NO_ELAPSED = new Set(['idle', 'error']);
|
|
12
|
+
export function busyIndicatorText({ kind, elapsedMs, frame, unicode, frames, tool, retry, nowMs }) {
|
|
13
|
+
const spinnerFrames = frames?.length ? frames : (unicode ? ['⠋', '⠙', '⠹', '⠸'] : ['-', '\\', '|', '/']);
|
|
14
|
+
const fixed = STATIC_GLYPH[kind];
|
|
15
|
+
const glyph = fixed ? (unicode ? fixed.unicode : fixed.ascii) : spinnerFrames[Math.abs(frame) % spinnerFrames.length];
|
|
16
|
+
/* R5a S4: the retry line replaces word and clock (the attempt, the status and the countdown say more than elapsed). */
|
|
17
|
+
if (kind === 'retrying' && retry)
|
|
18
|
+
return `${glyph} ${retryLine(retry, nowMs ?? Date.now())}`;
|
|
19
|
+
const verb = activityWord(kind, tool).padEnd(10, ' ');
|
|
20
|
+
const elapsed = NO_ELAPSED.has(kind) ? ' ' : stableElapsedLabel(elapsedMs);
|
|
21
|
+
return `${glyph} ${verb} ${elapsed}`;
|
|
22
|
+
}
|
|
23
|
+
export function createStatusIndicatorComponent(React, Ink) {
|
|
24
|
+
return function StatusIndicator({ kind, startedAt, motion, unicode, frames, color }) {
|
|
25
|
+
const [now, setNow] = React.useState(() => Date.now());
|
|
26
|
+
React.useEffect(() => { if (!motion || STATIC_GLYPH[kind])
|
|
27
|
+
return; const timer = setInterval(() => setNow(Date.now()), 120); return () => clearInterval(timer); }, [kind, motion]);
|
|
28
|
+
const elapsed = Math.max(0, now - startedAt);
|
|
29
|
+
const frame = frameIndex(elapsed, 120, 4);
|
|
30
|
+
return React.createElement(Ink.Text, { color }, busyIndicatorText({ kind, elapsedMs: elapsed, frame, unicode, ...(frames?.length ? { frames } : {}) }));
|
|
31
|
+
};
|
|
32
|
+
}
|