talos-code 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/LICENSE +661 -0
- package/README.md +116 -3
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/archive/zip.js +73 -0
- package/dist/args.js +100 -0
- package/dist/automations/history-store.js +34 -0
- package/dist/automations/policy-store.js +43 -0
- package/dist/automations/runner.js +107 -0
- package/dist/automations/schedule.js +85 -0
- package/dist/automations/windows-task.js +53 -0
- package/dist/commands/advanced-cli.js +233 -0
- package/dist/commands/checkpoint-cli.js +45 -0
- package/dist/commands/config-cli.js +107 -0
- package/dist/commands/context.js +17 -0
- package/dist/commands/extensions-cli.js +207 -0
- package/dist/commands/project-cli.js +74 -0
- package/dist/commands/project-commands.js +143 -0
- package/dist/commands/provider-cli.js +244 -0
- package/dist/commands/services-cli.js +248 -0
- package/dist/commands/session-cli.js +171 -0
- package/dist/commands/system-cli.js +405 -0
- package/dist/config/commands.js +60 -0
- package/dist/config/load.js +382 -0
- package/dist/config/migrations.js +48 -0
- package/dist/config/types.js +11 -0
- package/dist/diagnostics/development-log.js +154 -0
- package/dist/diagnostics/doctor.js +104 -0
- package/dist/diagnostics/redact.js +80 -0
- package/dist/diagnostics/zip.js +52 -0
- package/dist/errors.js +156 -0
- package/dist/events/bridge.js +130 -0
- package/dist/extensions/installer.js +178 -0
- package/dist/extensions/package-schema.js +24 -0
- package/dist/headless/result.js +84 -0
- package/dist/headless/run.js +230 -0
- package/dist/i18n/en/approval.js +46 -0
- package/dist/i18n/en/common.js +9 -0
- package/dist/i18n/en/credentials.js +92 -0
- package/dist/i18n/en/errors.js +267 -0
- package/dist/i18n/en/firstrun.js +101 -0
- package/dist/i18n/en/providers.js +37 -0
- package/dist/i18n/en/screen.js +774 -0
- package/dist/i18n/en/tools.js +127 -0
- package/dist/i18n/en.js +14 -0
- package/dist/i18n/error-view.js +307 -0
- package/dist/i18n/index.js +19 -0
- package/dist/i18n/kernel-map.js +139 -0
- package/dist/io.js +45 -0
- package/dist/main.js +331 -0
- package/dist/paths.js +41 -0
- package/dist/protocol/v2/codec.js +9 -0
- package/dist/protocol/v2/events.js +555 -0
- package/dist/protocol/v2/index.js +4 -0
- package/dist/protocol/v2/replay.js +28 -0
- package/dist/protocol/v2/types.js +1 -0
- package/dist/provider/control-plane.js +135 -0
- package/dist/provider/environment-keys.js +275 -0
- package/dist/provider/health.js +110 -0
- package/dist/provider/missing-key.js +48 -0
- package/dist/provider/model-catalog.js +168 -0
- package/dist/provider/openrouter-login.js +172 -0
- package/dist/provider/provider-text.js +13 -0
- package/dist/provider/store.js +95 -0
- package/dist/provider/system-keyring.js +214 -0
- package/dist/runtime/active-run.js +63 -0
- package/dist/runtime/agent-tree.js +74 -0
- package/dist/runtime/attachments.js +84 -0
- package/dist/runtime/brokered-executor.js +395 -0
- package/dist/runtime/context-archive.js +69 -0
- package/dist/runtime/context-status.js +76 -0
- package/dist/runtime/create-runtime.js +111 -0
- package/dist/runtime/model-profile.js +361 -0
- package/dist/runtime/output-store.js +137 -0
- package/dist/runtime/provider-attempts.js +185 -0
- package/dist/runtime/replay-buffer.js +153 -0
- package/dist/runtime/repo.js +95 -0
- package/dist/runtime/session-facade.js +135 -0
- package/dist/runtime/session-summary.js +125 -0
- package/dist/runtime/supervisor.js +265 -0
- package/dist/runtime/talos-composition.js +1011 -0
- package/dist/runtime/types.js +5 -0
- package/dist/runtime/usage-snapshot.js +82 -0
- package/dist/security/auto-classifier.js +38 -0
- package/dist/security/credential-free-environment.js +54 -0
- package/dist/security/evaluate.js +243 -0
- package/dist/security/execution-backends.js +236 -0
- package/dist/security/execution-broker.js +102 -0
- package/dist/security/forge-scan.js +74 -0
- package/dist/security/from-approval.js +39 -0
- package/dist/security/mxc-execution-backend.js +281 -0
- package/dist/security/permission-engine.js +138 -0
- package/dist/security/permission-explanation.js +54 -0
- package/dist/security/persist.js +179 -0
- package/dist/security/plugin-guard.js +230 -0
- package/dist/security/process-tree-evidence-store.js +74 -0
- package/dist/security/process-tree-probe.js +554 -0
- package/dist/security/project-resource-inventory.js +186 -0
- package/dist/security/project-trust-gate.js +38 -0
- package/dist/security/project-trust.js +367 -0
- package/dist/security/rule-parser.js +201 -0
- package/dist/security/shell-segmentation.js +68 -0
- package/dist/security/trust-authority.js +324 -0
- package/dist/security/types.js +1 -0
- package/dist/security/workspace-identity.js +102 -0
- package/dist/services/automation-facade.js +59 -0
- package/dist/services/forge-facade.js +77 -0
- package/dist/services/hook-facade.js +240 -0
- package/dist/services/index.js +16 -0
- package/dist/services/library-facade.js +174 -0
- package/dist/services/mcp-facade.js +348 -0
- package/dist/services/memory-facade.js +126 -0
- package/dist/services/notes-facade.js +157 -0
- package/dist/services/plugin-facade.js +308 -0
- package/dist/services/research-facade.js +110 -0
- package/dist/services/task-board-facade.js +236 -0
- package/dist/services/workflow-catalog.js +246 -0
- package/dist/sessions/export-format.js +98 -0
- package/dist/sessions/metadata-store.js +160 -0
- package/dist/sessions/share.js +122 -0
- package/dist/sessions/transfer.js +16 -0
- package/dist/subcommands.js +62 -0
- package/dist/tui/agent-roster.js +36 -0
- package/dist/tui/agent-view.js +51 -0
- package/dist/tui/app.js +4098 -0
- package/dist/tui/approval.js +36 -0
- package/dist/tui/boot/boot-sequence.js +76 -0
- package/dist/tui/boot/cinematic.js +243 -0
- package/dist/tui/boot/desktop-logo.js +82 -0
- package/dist/tui/boot.js +3 -0
- package/dist/tui/busy-input.js +58 -0
- package/dist/tui/catalog-service.js +560 -0
- package/dist/tui/components/assistant-stream.js +1 -0
- package/dist/tui/components/command-menu.js +68 -0
- package/dist/tui/components/composer.js +219 -0
- package/dist/tui/components/diff.js +35 -0
- package/dist/tui/components/footer.js +48 -0
- package/dist/tui/components/header.js +6 -0
- package/dist/tui/components/markdown.js +305 -0
- package/dist/tui/components/status-indicator.js +38 -0
- package/dist/tui/components/terminal-shell.js +214 -0
- package/dist/tui/components/thinking-row.js +19 -0
- package/dist/tui/components/tool-row.js +97 -0
- package/dist/tui/components/transcript-virtualizer.js +165 -0
- package/dist/tui/components/transcript.js +43 -0
- package/dist/tui/descendant-approvals.js +104 -0
- package/dist/tui/diff-model.js +77 -0
- package/dist/tui/editor-history.js +21 -0
- package/dist/tui/editor.js +210 -0
- package/dist/tui/event-adapter.js +436 -0
- package/dist/tui/exit-output.js +58 -0
- package/dist/tui/external-editor.js +53 -0
- package/dist/tui/file-completion.js +89 -0
- package/dist/tui/focus-manager.js +5 -0
- package/dist/tui/highlight.js +30 -0
- package/dist/tui/input-router.js +18 -0
- package/dist/tui/interrupt.js +99 -0
- package/dist/tui/keybindings.js +194 -0
- package/dist/tui/keymap-resolver.js +91 -0
- package/dist/tui/launch-state.js +148 -0
- package/dist/tui/line-diff.js +57 -0
- package/dist/tui/live-activity.js +56 -0
- package/dist/tui/metrics.js +123 -0
- package/dist/tui/onboarding.js +36 -0
- package/dist/tui/overlays/agent-tree.js +43 -0
- package/dist/tui/overlays/approval-dialog.js +642 -0
- package/dist/tui/overlays/automation-center.js +51 -0
- package/dist/tui/overlays/checkpoint-picker.js +47 -0
- package/dist/tui/overlays/context-inspector.js +36 -0
- package/dist/tui/overlays/effort-line.js +110 -0
- package/dist/tui/overlays/forge-center.js +46 -0
- package/dist/tui/overlays/help-dialog.js +16 -0
- package/dist/tui/overlays/history-picker.js +37 -0
- package/dist/tui/overlays/hook-center.js +70 -0
- package/dist/tui/overlays/library-center.js +55 -0
- package/dist/tui/overlays/mcp-center.js +60 -0
- package/dist/tui/overlays/memory-center.js +63 -0
- package/dist/tui/overlays/model-picker.js +77 -0
- package/dist/tui/overlays/notes-center.js +53 -0
- package/dist/tui/overlays/overlay-host.js +8 -0
- package/dist/tui/overlays/plugin-center.js +76 -0
- package/dist/tui/overlays/provider-picker.js +171 -0
- package/dist/tui/overlays/queue-editor.js +32 -0
- package/dist/tui/overlays/research-center.js +59 -0
- package/dist/tui/overlays/scroll-window.js +234 -0
- package/dist/tui/overlays/session-picker.js +115 -0
- package/dist/tui/overlays/tasks-center.js +83 -0
- package/dist/tui/overlays/theme-picker.js +21 -0
- package/dist/tui/overlays/transcript-search.js +58 -0
- package/dist/tui/overlays/trust-center.js +29 -0
- package/dist/tui/overlays/workflow-center.js +46 -0
- package/dist/tui/project-file-index.js +214 -0
- package/dist/tui/project-references.js +85 -0
- package/dist/tui/project-trust-prompt.js +289 -0
- package/dist/tui/prompt-history-store.js +116 -0
- package/dist/tui/queue-store.js +110 -0
- package/dist/tui/regions/budget.js +59 -0
- package/dist/tui/regions/views.js +96 -0
- package/dist/tui/render-coordinator.js +148 -0
- package/dist/tui/render-scheduler.js +4 -0
- package/dist/tui/run.js +69 -0
- package/dist/tui/selection-list.js +29 -0
- package/dist/tui/session-controller.js +791 -0
- package/dist/tui/session-export.js +54 -0
- package/dist/tui/setup-wizard.js +46 -0
- package/dist/tui/shell-input.js +35 -0
- package/dist/tui/shell-layout.js +48 -0
- package/dist/tui/shell-model.js +98 -0
- package/dist/tui/slash-commands.js +82 -0
- package/dist/tui/state.js +151 -0
- package/dist/tui/status-bar.js +125 -0
- package/dist/tui/status-view.js +40 -0
- package/dist/tui/terminal-capabilities.js +9 -0
- package/dist/tui/terminal-session.js +11 -0
- package/dist/tui/text-width.js +66 -0
- package/dist/tui/theme-catalog.js +27 -0
- package/dist/tui/theme-store.js +23 -0
- package/dist/tui/theme.js +23 -0
- package/dist/tui/tool-display.js +135 -0
- package/dist/tui/tool-facts.js +1 -0
- package/dist/tui/tools/bash-renderer.js +32 -0
- package/dist/tui/tools/change.js +61 -0
- package/dist/tui/tools/edit-renderer.js +17 -0
- package/dist/tui/tools/generic-renderer.js +13 -0
- package/dist/tui/tools/list-renderer.js +14 -0
- package/dist/tui/tools/read-renderer.js +13 -0
- package/dist/tui/tools/registry.js +20 -0
- package/dist/tui/tools/row-format.js +187 -0
- package/dist/tui/tools/search-renderer.js +38 -0
- package/dist/tui/tools/shared.js +97 -0
- package/dist/tui/tools/write-renderer.js +15 -0
- package/dist/tui/transcript-model.js +441 -0
- package/dist/tui/ui-preferences.js +79 -0
- package/dist/tui/usage-view.js +77 -0
- package/dist/tui/vim-mode.js +99 -0
- package/dist/update/check.js +15 -0
- package/dist/update/npm.js +51 -0
- package/dist/update/run.js +129 -0
- package/dist/version.js +2 -0
- package/dist/workspace/checkpoint-store.js +210 -0
- package/dist/workspace/checkpoint.js +413 -0
- package/dist/workspace/restore.js +232 -0
- package/package.json +64 -5
- package/vendor/context-engine/package.json +11 -0
- package/vendor/context-engine/src/compaction-planner.mjs +57 -0
- package/vendor/context-engine/src/contracts.mjs +48 -0
- package/vendor/context-engine/src/engine.mjs +445 -0
- package/vendor/context-engine/src/node/context-export.mjs +164 -0
- package/vendor/context-engine/src/node/legacy-import.mjs +92 -0
- package/vendor/context-engine/src/node/migrations/001-context.sql +126 -0
- package/vendor/context-engine/src/node/sqlite-store.mjs +85 -0
- package/vendor/context-engine/src/node/sqlite-worker.mjs +559 -0
- package/vendor/context-engine/src/profiles.mjs +10 -0
- package/vendor/context-engine/src/retrieval.mjs +104 -0
- package/vendor/context-engine/src/summary.mjs +97 -0
- package/vendor/context-engine/src/usage.mjs +34 -0
- package/vendor/harness-ui/package.json +38 -0
- package/vendor/harness-ui/src/acp-agent.mjs +350 -0
- package/vendor/harness-ui/src/agent-service.mjs +2188 -0
- package/vendor/harness-ui/src/agui-events.mjs +452 -0
- package/vendor/harness-ui/src/ambiente-solo-server.mjs +121 -0
- package/vendor/harness-ui/src/artifact-store.mjs +39 -0
- package/vendor/harness-ui/src/assistenza.mjs +123 -0
- package/vendor/harness-ui/src/automation-scheduler.mjs +69 -0
- package/vendor/harness-ui/src/automation-store.mjs +145 -0
- package/vendor/harness-ui/src/browser-annota.mjs +639 -0
- package/vendor/harness-ui/src/browser-frame.mjs +211 -0
- package/vendor/harness-ui/src/browser-proxy-universale.mjs +519 -0
- package/vendor/harness-ui/src/browser-proxy.mjs +87 -0
- package/vendor/harness-ui/src/browser-sessione-viva.mjs +329 -0
- package/vendor/harness-ui/src/browser-stream.mjs +445 -0
- package/vendor/harness-ui/src/browser-vivo.mjs +694 -0
- package/vendor/harness-ui/src/chat-image-attachments.mjs +72 -0
- package/vendor/harness-ui/src/config.mjs +697 -0
- package/vendor/harness-ui/src/contesto-del-progetto.mjs +385 -0
- package/vendor/harness-ui/src/context-asset-adapter.mjs +72 -0
- package/vendor/harness-ui/src/context-desktop-service.mjs +253 -0
- package/vendor/harness-ui/src/context-embedding-runtime.mjs +252 -0
- package/vendor/harness-ui/src/context-inference-scheduler.mjs +81 -0
- package/vendor/harness-ui/src/context-native-compaction.mjs +75 -0
- package/vendor/harness-ui/src/context-provider-adapter.mjs +141 -0
- package/vendor/harness-ui/src/context-runtime.mjs +118 -0
- package/vendor/harness-ui/src/context-token-counters.mjs +184 -0
- package/vendor/harness-ui/src/context-tool-catalog.mjs +86 -0
- package/vendor/harness-ui/src/context-tool-output.mjs +72 -0
- package/vendor/harness-ui/src/costo-elenco.mjs +252 -0
- package/vendor/harness-ui/src/custom-task.mjs +171 -0
- package/vendor/harness-ui/src/doctor.mjs +142 -0
- package/vendor/harness-ui/src/document-filename.mjs +97 -0
- package/vendor/harness-ui/src/document-generator.mjs +493 -0
- package/vendor/harness-ui/src/document-report.mjs +331 -0
- package/vendor/harness-ui/src/duckduckgo-search.mjs +155 -0
- package/vendor/harness-ui/src/elenco-profondo.mjs +337 -0
- package/vendor/harness-ui/src/favicon-proxy.mjs +113 -0
- package/vendor/harness-ui/src/forge-contract.mjs +221 -0
- package/vendor/harness-ui/src/frequent-dirs.mjs +134 -0
- package/vendor/harness-ui/src/generated-image-store.mjs +147 -0
- package/vendor/harness-ui/src/generation-idle.mjs +332 -0
- package/vendor/harness-ui/src/gguf-header.mjs +207 -0
- package/vendor/harness-ui/src/git-service.mjs +626 -0
- package/vendor/harness-ui/src/gitignore-elenco.mjs +604 -0
- package/vendor/harness-ui/src/harness-receipt-keypair.mjs +207 -0
- package/vendor/harness-ui/src/hf-direct-transfer.mjs +170 -0
- package/vendor/harness-ui/src/hf-hub-client.mjs +106 -0
- package/vendor/harness-ui/src/hf-image-proxy.mjs +105 -0
- package/vendor/harness-ui/src/hf-model-transfer.mjs +245 -0
- package/vendor/harness-ui/src/hook-registry.mjs +186 -0
- package/vendor/harness-ui/src/http-app.mjs +6259 -0
- package/vendor/harness-ui/src/http-lifecycle.mjs +132 -0
- package/vendor/harness-ui/src/id-archivio.mjs +27 -0
- package/vendor/harness-ui/src/image-generator.mjs +143 -0
- package/vendor/harness-ui/src/istruzioni-di-progetto.mjs +234 -0
- package/vendor/harness-ui/src/kernel/dist/kernelPerIlBanco.js +518 -0
- package/vendor/harness-ui/src/kernel/talosHarness.mjs +10437 -0
- package/vendor/harness-ui/src/library-policy-store.mjs +175 -0
- package/vendor/harness-ui/src/library-store.mjs +652 -0
- package/vendor/harness-ui/src/llama-server-supervisor.mjs +629 -0
- package/vendor/harness-ui/src/local-model-store.mjs +339 -0
- package/vendor/harness-ui/src/local-runtime-contract.mjs +66 -0
- package/vendor/harness-ui/src/local-runtime-events.mjs +44 -0
- package/vendor/harness-ui/src/local-runtime-llama-server.mjs +244 -0
- package/vendor/harness-ui/src/local-runtime-probe.mjs +401 -0
- package/vendor/harness-ui/src/machine-capacity.mjs +66 -0
- package/vendor/harness-ui/src/mappa-cartelle.mjs +491 -0
- package/vendor/harness-ui/src/mcp-client.mjs +98 -0
- package/vendor/harness-ui/src/mcp-registry.mjs +157 -0
- package/vendor/harness-ui/src/mcp-session.mjs +177 -0
- package/vendor/harness-ui/src/memory-store.mjs +227 -0
- package/vendor/harness-ui/src/model-catalog-models-dev.mjs +276 -0
- package/vendor/harness-ui/src/model-catalog.mjs +129 -0
- package/vendor/harness-ui/src/model-destination.mjs +189 -0
- package/vendor/harness-ui/src/modifica-ancorata.mjs +177 -0
- package/vendor/harness-ui/src/native-provider-adapter.mjs +205 -0
- package/vendor/harness-ui/src/notes-store.mjs +250 -0
- package/vendor/harness-ui/src/openai-compatible-runtime.mjs +428 -0
- package/vendor/harness-ui/src/openrouter-oauth.mjs +339 -0
- package/vendor/harness-ui/src/path-policy.mjs +442 -0
- package/vendor/harness-ui/src/plugin-registry.mjs +780 -0
- package/vendor/harness-ui/src/plugin-session.mjs +180 -0
- package/vendor/harness-ui/src/process-policy.mjs +345 -0
- package/vendor/harness-ui/src/prompt-enhancer-provider.mjs +94 -0
- package/vendor/harness-ui/src/provider-auth-cloud.mjs +95 -0
- package/vendor/harness-ui/src/provider-credential-store.mjs +541 -0
- package/vendor/harness-ui/src/provider-probe.mjs +582 -0
- package/vendor/harness-ui/src/provider-registry.mjs +1633 -0
- package/vendor/harness-ui/src/pty-terminal.mjs +312 -0
- package/vendor/harness-ui/src/public-problem.mjs +109 -0
- package/vendor/harness-ui/src/research/card.mjs +235 -0
- package/vendor/harness-ui/src/research/citations.mjs +142 -0
- package/vendor/harness-ui/src/research/collector.mjs +275 -0
- package/vendor/harness-ui/src/research/deposito-a-pezzi.mjs +139 -0
- package/vendor/harness-ui/src/research/dossier.mjs +114 -0
- package/vendor/harness-ui/src/research/esportazioni.mjs +560 -0
- package/vendor/harness-ui/src/research/fetch-cache.mjs +465 -0
- package/vendor/harness-ui/src/research/fidelity.mjs +122 -0
- package/vendor/harness-ui/src/research/independence.mjs +159 -0
- package/vendor/harness-ui/src/research/ledger.mjs +166 -0
- package/vendor/harness-ui/src/research/markdown-server.mjs +565 -0
- package/vendor/harness-ui/src/research/narration.mjs +181 -0
- package/vendor/harness-ui/src/research/open-cards.mjs +131 -0
- package/vendor/harness-ui/src/research/opposing.mjs +305 -0
- package/vendor/harness-ui/src/research/outline.mjs +111 -0
- package/vendor/harness-ui/src/research/page-budget.mjs +209 -0
- package/vendor/harness-ui/src/research/pdf.mjs +291 -0
- package/vendor/harness-ui/src/research/plan.mjs +301 -0
- package/vendor/harness-ui/src/research/raccolta-viva.mjs +452 -0
- package/vendor/harness-ui/src/research/recheck-document.mjs +69 -0
- package/vendor/harness-ui/src/research/recheck-history.mjs +192 -0
- package/vendor/harness-ui/src/research/recheck.mjs +194 -0
- package/vendor/harness-ui/src/research/report.mjs +203 -0
- package/vendor/harness-ui/src/research/run.mjs +527 -0
- package/vendor/harness-ui/src/research/synthesis.mjs +318 -0
- package/vendor/harness-ui/src/research/verification.mjs +572 -0
- package/vendor/harness-ui/src/research-orchestrator.mjs +2679 -0
- package/vendor/harness-ui/src/research-store.mjs +1133 -0
- package/vendor/harness-ui/src/runtime-build-manifest.mjs +26 -0
- package/vendor/harness-ui/src/runtime-contract.mjs +59 -0
- package/vendor/harness-ui/src/runtime-owner-adapter.mjs +1348 -0
- package/vendor/harness-ui/src/runtime-owner-contract.mjs +32 -0
- package/vendor/harness-ui/src/scheda-di-lavoro.mjs +249 -0
- package/vendor/harness-ui/src/search-source-store.mjs +172 -0
- package/vendor/harness-ui/src/session-registry.mjs +6095 -0
- package/vendor/harness-ui/src/session-store.mjs +220 -0
- package/vendor/harness-ui/src/sessione-pronta.mjs +73 -0
- package/vendor/harness-ui/src/setup-stato.mjs +31 -0
- package/vendor/harness-ui/src/sezioni-istruzioni.mjs +204 -0
- package/vendor/harness-ui/src/skill-registry.mjs +120 -0
- package/vendor/harness-ui/src/sse-replay-coalescente.mjs +0 -0
- package/vendor/harness-ui/src/static-files.mjs +96 -0
- package/vendor/harness-ui/src/stream-partition.mjs +123 -0
- package/vendor/harness-ui/src/subagent-orchestrator.mjs +453 -0
- package/vendor/harness-ui/src/task-catalog.mjs +65 -0
- package/vendor/harness-ui/src/tasks-store.mjs +220 -0
- package/vendor/harness-ui/src/terminal-registry.mjs +312 -0
- package/vendor/harness-ui/src/terminal-ws.mjs +170 -0
- package/vendor/harness-ui/src/tool-forge-store.mjs +299 -0
- package/vendor/harness-ui/src/tool-schema-normalize.mjs +100 -0
- package/vendor/harness-ui/src/usage-cache.mjs +315 -0
- package/vendor/harness-ui/src/workspace-browser.mjs +213 -0
- package/vendor/harness-ui/src/workspace-context.mjs +124 -0
- package/vendor/harness-ui/src/workspace-disk.mjs +62 -0
- package/vendor/harness-ui/src/workspace-files.mjs +589 -0
- package/vendor/harness-ui/src/workspace-info.mjs +189 -0
- package/vendor/harness-ui/src/workspace-launch-store.mjs +150 -0
- package/vendor/harness-ui/src/workspace-tree.mjs +67 -0
- package/vendor/harness-ui/src/workspace-watcher.mjs +161 -0
- package/vendor/manifest.json +170 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { talosResearchIsTerminal, talosResearchStepIdFor } from './run.mjs'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* PORTO FEDELE di AVM/mobile/src/lib/research/researchOutline.ts (85 righe, 11/09/2026).
|
|
5
|
+
*
|
|
6
|
+
* ⛔ `run.mjs` è il porto di `researchRun.ts` e lo cura un'altra sessione, in
|
|
7
|
+
* parallelo: qui se ne importa solo il nome concordato, senza duplicarne una riga.
|
|
8
|
+
*
|
|
9
|
+
* Il documento, prima che esista.
|
|
10
|
+
*
|
|
11
|
+
* La ricerca visiva del 2026-08-03 fa una domanda a cui nessun concorrente
|
|
12
|
+
* risponde: che cosa si disegna nel primo mezzo secondo, quando ancora non si
|
|
13
|
+
* sa niente? Di quel momento non ha trovato uno screenshot in nessuno dei
|
|
14
|
+
* cinque prodotti — le recensioni saltano dal piano allo stato popolato e il
|
|
15
|
+
* marketing taglia la transizione. Il che fa comodo, perché vuol dire che la
|
|
16
|
+
* risposta qui è nostra.
|
|
17
|
+
*
|
|
18
|
+
* E la risposta è che qualcosa lo sappiamo. Il piano è stato approvato prima
|
|
19
|
+
* che si spendesse un centesimo: i suoi rami SONO le sezioni che il rapporto
|
|
20
|
+
* avrà. Quindi la pagina si apre sulla forma del documento, con ogni sezione
|
|
21
|
+
* che dice dov'è — invece che su una rotella, o, come faceva fino a oggi, su
|
|
22
|
+
* niente del tutto.
|
|
23
|
+
*
|
|
24
|
+
* Tutto qui dentro è aritmetica sulla corsa. Niente disco, niente rete: il
|
|
25
|
+
* primo fotogramma non può essere in ritardo perché non c'è niente da aspettare.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @import { TalosResearchRun, TalosResearchStepState } from './run.mjs'
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @typedef {object} TalosResearchSection
|
|
34
|
+
* @property {string} id
|
|
35
|
+
* @property {string} question
|
|
36
|
+
* @property {TalosResearchStepState} state
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Una sezione per ramo, nell'ordine del piano.
|
|
41
|
+
*
|
|
42
|
+
* Un ramo senza ancora un passo è `pending` invece che assente: al lettore si
|
|
43
|
+
* sta mostrando che cosa SUCCEDERÀ, e nascondere le parti non ancora partite
|
|
44
|
+
* farebbe sembrare che il documento cresca dal nulla.
|
|
45
|
+
*
|
|
46
|
+
* @param {TalosResearchRun} run
|
|
47
|
+
* @returns {readonly TalosResearchSection[]}
|
|
48
|
+
*/
|
|
49
|
+
export function talosResearchOutline(run) {
|
|
50
|
+
return run.plan.map((branch) => {
|
|
51
|
+
const step = run.steps.find((candidate) => candidate.id === talosResearchStepIdFor(branch.id, 'search'))
|
|
52
|
+
return { id: branch.id, question: branch.question, state: step?.state ?? 'pending' }
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Quando una corsa finita è finita davvero.
|
|
58
|
+
*
|
|
59
|
+
* NON `updatedAt`, che viene timbrato da ogni evento che il giornale accetta —
|
|
60
|
+
* una rinomina compresa. Una ricerca conclusa in quattro minuti ieri e
|
|
61
|
+
* rinominata oggi leggerebbe «conclusa in 1 giorno», e la pagina starebbe
|
|
62
|
+
* citando il momento in cui le hai cambiato titolo come il momento in cui ha
|
|
63
|
+
* smesso di pensare.
|
|
64
|
+
*
|
|
65
|
+
* L'ultimo passo che riporta una fine è la fine vera. Una corsa annullata prima
|
|
66
|
+
* che un passo finisse non ne ha nessuno, e lì `updatedAt` è il meglio che c'è.
|
|
67
|
+
*
|
|
68
|
+
* @param {TalosResearchRun} run
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
function endedAt(run) {
|
|
72
|
+
/** @type {string | null} */
|
|
73
|
+
let last = null
|
|
74
|
+
for (const step of run.steps) {
|
|
75
|
+
if (step.finishedAt && (last === null || step.finishedAt > last)) last = step.finishedAt
|
|
76
|
+
}
|
|
77
|
+
return last ?? run.updatedAt
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Da quanto sta andando, in secondi.
|
|
82
|
+
*
|
|
83
|
+
* Dai tempi della corsa, mai da un cronometro fatto partire quando lo schermo
|
|
84
|
+
* si è montato: una ricerca la si guarda da più posti e sopravvive a tutti,
|
|
85
|
+
* quindi una durata posseduta da un componente ripartirebbe ogni volta che
|
|
86
|
+
* qualcuno guarda. Una corsa finita misura fino a quando è finita; una viva
|
|
87
|
+
* fino ad adesso.
|
|
88
|
+
*
|
|
89
|
+
* @param {TalosResearchRun} run
|
|
90
|
+
* @param {string} now
|
|
91
|
+
* @returns {number}
|
|
92
|
+
*/
|
|
93
|
+
export function talosResearchElapsedSeconds(run, now) {
|
|
94
|
+
const started = Date.parse(run.startedAt)
|
|
95
|
+
const until = Date.parse(talosResearchIsTerminal(run.status) ? endedAt(run) : now)
|
|
96
|
+
if (!Number.isFinite(started) || !Number.isFinite(until)) return 0
|
|
97
|
+
return Math.max(0, Math.round((until - started) / 1000))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* `4 min 08 s`, oppure `38 s`. Tabellare, e mai un numero nudo di secondi oltre
|
|
102
|
+
* il minuto.
|
|
103
|
+
*
|
|
104
|
+
* @param {number} seconds
|
|
105
|
+
* @returns {string}
|
|
106
|
+
*/
|
|
107
|
+
export function talosResearchDuration(seconds) {
|
|
108
|
+
if (seconds < 60) return `${seconds} s`
|
|
109
|
+
const minutes = Math.floor(seconds / 60)
|
|
110
|
+
return `${minutes} min ${String(seconds % 60).padStart(2, '0')} s`
|
|
111
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* L6 — IL BUDGET DETERMINISTICO PER PAGINA.
|
|
3
|
+
*
|
|
4
|
+
* ## Il difetto che chiude
|
|
5
|
+
*
|
|
6
|
+
* Una pagina web è lunga quanto le pare. Il modello riceve tutto, e la finestra
|
|
7
|
+
* di contesto è la prima cosa che finisce: `naviga` nel kernel taglia già a
|
|
8
|
+
* 4.000 caratteri (`talosHarness.mjs:1296`, `uscitaUtile`) e la sintesi ne
|
|
9
|
+
* prende 4.000 in testa per fonte (`synthesis.mjs:59`). Nessuno dei due dice
|
|
10
|
+
* dove sia finito il resto, e la sintesi non guarda nemmeno la coda.
|
|
11
|
+
*
|
|
12
|
+
* ⛔ Il punto NON è tagliare — quello lo facciamo già. Il punto è che oggi il
|
|
13
|
+
* resto **sparisce**: non è da nessuna parte, quindi non si può né sfogliare né
|
|
14
|
+
* ri-verificare. Questo modulo separa tre cose che oggi sono una sola:
|
|
15
|
+
*
|
|
16
|
+
* 1. il testo INTERO, che si conserva (è il dossier: `collector.mjs`);
|
|
17
|
+
* 2. la FINESTRA, cioè quanto ne vede il modello adesso;
|
|
18
|
+
* 3. il RIFERIMENTO, cioè come arrivare al resto.
|
|
19
|
+
*
|
|
20
|
+
* ⛔ La (1) resta la fonte della verità per `talosResearchLocate`
|
|
21
|
+
* (`verification.mjs:201`): un passaggio citato si cerca nel testo intero, MAI
|
|
22
|
+
* nella finestra — altrimenti tagliare una pagina trasformerebbe una citazione
|
|
23
|
+
* vera in una citazione «non trovata», che è il verso peggiore in cui si possa
|
|
24
|
+
* sbagliare (una fonte onesta marcata come inventata).
|
|
25
|
+
*
|
|
26
|
+
* ## Perché 15.000, misurato invece che copiato
|
|
27
|
+
*
|
|
28
|
+
* Hermes v0.21 usa 15.000 caratteri per pagina, testa 75% / coda 25%, il resto
|
|
29
|
+
* su disco col percorso e la chiamata esatta per sfogliarlo, tetto 2 MB
|
|
30
|
+
* (`website/docs/user-guide/features/web-search.md:47-57` nel clone
|
|
31
|
+
* `%LOCALAPPDATA%\Temp\talos-competitor\hermes-agent-v21`, letto l'11/09/2026).
|
|
32
|
+
* Il numero è il loro, la ragione doveva essere nostra.
|
|
33
|
+
*
|
|
34
|
+
* MISURATO l'11/09/2026 su 430 pagine di documentazione vera (le `.md`/`.mdx`
|
|
35
|
+
* di `website/docs` dello stesso clone: sono pagine web pubblicate, non un
|
|
36
|
+
* campione inventato), con gli spazi compattati come fa il collettore:
|
|
37
|
+
*
|
|
38
|
+
* mediana 10.688 · p75 15.752 · p90 27.983 · p95 43.899 · max 187.135
|
|
39
|
+
*
|
|
40
|
+
* tetto pagine intere caratteri coperti
|
|
41
|
+
* 4.000 30/430 ( 7,0%) 26,1%
|
|
42
|
+
* 8.000 130/430 (30,2%) 47,9%
|
|
43
|
+
* 15.000 313/430 (72,8%) 69,4%
|
|
44
|
+
* 20.000 357/430 (83,0%) 76,3%
|
|
45
|
+
* 40.000 403/430 (93,7%) 89,3%
|
|
46
|
+
*
|
|
47
|
+
* ⇒ I 4.000 di oggi consegnano al modello il 26% dei caratteri e fanno arrivare
|
|
48
|
+
* intera UNA PAGINA SU QUATTORDICI: non è un budget, è un troncone. I 15.000 di
|
|
49
|
+
* Hermes cadono quasi esattamente sul 75° percentile (15.752): tre pagine su
|
|
50
|
+
* quattro arrivano intere e il taglio smette di essere la regola.
|
|
51
|
+
*
|
|
52
|
+
* ⛔ E la ragione per cui NON prendo i 20.000 del mobile (`collector.mjs:79`,
|
|
53
|
+
* `MAX_CHARS_PER_SOURCE`) è strutturale, non di gusto: quello è il tetto di ciò
|
|
54
|
+
* che si CONSERVA. Se il tetto mostrato fosse uguale a quello conservato, il
|
|
55
|
+
* riferimento «il resto è in …» punterebbe sempre a zero caratteri residui, e
|
|
56
|
+
* questo modulo sarebbe una bugia cortese. Il tetto mostrato deve stare
|
|
57
|
+
* STRETTAMENTE sotto quello conservato. 15.000 < 20.000.
|
|
58
|
+
*
|
|
59
|
+
* ## Perché testa 75% / coda 25%, al contrario di `uscitaUtile`
|
|
60
|
+
*
|
|
61
|
+
* `uscitaUtile` tiene un quarto in testa e tre quarti in coda, e ha ragione:
|
|
62
|
+
* misura l'uscita di una SUITE DI TEST, dove la diagnosi sta in fondo
|
|
63
|
+
* (`talosHarness.mjs:1282-1295`). Una pagina web è l'opposto — titolo, apertura
|
|
64
|
+
* e tesi stanno in cima, e la coda è note, footer, commenti. ⇒ stesso
|
|
65
|
+
* meccanismo, quote invertite, e la ragione scritta accanto a tutte e due.
|
|
66
|
+
*
|
|
67
|
+
* ## Deterministico, e la parola conta
|
|
68
|
+
*
|
|
69
|
+
* Nessun modello, nessuna sintesi, nessuna data, nessun `toLocaleString`: la
|
|
70
|
+
* stessa pagina produce la stessa identica finestra, byte per byte. Serve
|
|
71
|
+
* perché la cache del prompt dei fornitori funziona su PREFISSO ESATTO — «If
|
|
72
|
+
* your breakpoint is on content that changes every request, cache hits never
|
|
73
|
+
* occur» (platform.claude.com/docs/en/build-with-claude/prompt-caching, letta
|
|
74
|
+
* l'11/09/2026). Una finestra che cambia fra due giri identici brucia la cache
|
|
75
|
+
* di tutto ciò che le sta dopo.
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Quanti caratteri di una pagina vede il modello.
|
|
80
|
+
* Vedi la misura qui sopra: è il 75° percentile di 430 pagine vere.
|
|
81
|
+
*/
|
|
82
|
+
export const TALOS_RESEARCH_PAGE_BUDGET = 15_000;
|
|
83
|
+
|
|
84
|
+
/** Quanta parte della finestra è la testa. Una pagina dice la sua tesi in cima. */
|
|
85
|
+
export const TALOS_RESEARCH_HEAD_SHARE = 0.75;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Quanto testo si CONSERVA di una pagina. Stesso tetto di Hermes (2 MB): oltre,
|
|
89
|
+
* un solo documento patologico si mangerebbe il dossier.
|
|
90
|
+
*/
|
|
91
|
+
export const TALOS_RESEARCH_KEPT_CAP = 2 * 1024 * 1024;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @typedef {object} TalosResearchPageReference
|
|
95
|
+
* @property {string} percorso Dove il testo intero è stato depositato.
|
|
96
|
+
* @property {string} [chiamata]
|
|
97
|
+
* La chiamata ESATTA per sfogliare il mezzo, se esiste davvero un attrezzo che
|
|
98
|
+
* la accetta. ⛔ Non si inventa: oggi `leggi` non ha né offset né lunghezza
|
|
99
|
+
* (`talosHarness.mjs:1446-1451`), quindi chi non può scriverne una vera non la
|
|
100
|
+
* passa, e il marcatore tace invece di mentire.
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @typedef {object} TalosResearchPageWindow
|
|
105
|
+
* @property {string} window Ciò che il modello vede: testa + marcatore + coda.
|
|
106
|
+
* @property {number} total Caratteri della pagina intera.
|
|
107
|
+
* @property {number} shown Caratteri davvero mostrati (marcatore escluso).
|
|
108
|
+
* @property {number} omitted `total - shown`. Contato, mai stimato.
|
|
109
|
+
* @property {boolean} truncated
|
|
110
|
+
* @property {string | null} marker Il marcatore, per chi lo vuole altrove.
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Il taglio della testa, portato indietro fino a un confine di riga se ce n'è
|
|
115
|
+
* uno vicino — Hermes taglia «on markdown line boundaries», e mezza riga di
|
|
116
|
+
* markdown letta a metà è rumore. Se non c'è una riga si ripiega su uno spazio;
|
|
117
|
+
* se non c'è nemmeno quello (testo compattato, o una lingua senza spazi) si
|
|
118
|
+
* taglia netto: meglio un taglio netto che una regola che non si applica.
|
|
119
|
+
*
|
|
120
|
+
* @param {string} testo
|
|
121
|
+
* @param {number} tetto
|
|
122
|
+
* @returns {number}
|
|
123
|
+
*/
|
|
124
|
+
function tagliaInTesta(testo, tetto) {
|
|
125
|
+
if (tetto <= 0) return 0;
|
|
126
|
+
const finestra = testo.slice(0, tetto);
|
|
127
|
+
const riga = finestra.lastIndexOf('\n');
|
|
128
|
+
if (riga >= Math.floor(tetto * 0.8)) return riga;
|
|
129
|
+
const spazio = finestra.lastIndexOf(' ');
|
|
130
|
+
if (spazio >= tetto - 200) return spazio;
|
|
131
|
+
return tetto;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* L'inizio della coda, portato AVANTI (mai indietro: allargherebbe la finestra
|
|
136
|
+
* oltre il tetto) fino al primo confine di riga vicino.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} testo
|
|
139
|
+
* @param {number} tetto
|
|
140
|
+
* @returns {number}
|
|
141
|
+
*/
|
|
142
|
+
function tagliaInCoda(testo, tetto) {
|
|
143
|
+
if (tetto <= 0) return testo.length;
|
|
144
|
+
const da = testo.length - tetto;
|
|
145
|
+
const finestra = testo.slice(da);
|
|
146
|
+
const riga = finestra.indexOf('\n');
|
|
147
|
+
if (riga >= 0 && riga <= Math.floor(tetto * 0.2)) return da + riga + 1;
|
|
148
|
+
const spazio = finestra.indexOf(' ');
|
|
149
|
+
if (spazio >= 0 && spazio <= 200) return da + spazio + 1;
|
|
150
|
+
return da;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {number} valore
|
|
155
|
+
* @param {number} minimo
|
|
156
|
+
* @param {number} massimo
|
|
157
|
+
* @returns {number}
|
|
158
|
+
*/
|
|
159
|
+
function stretto(valore, minimo, massimo) {
|
|
160
|
+
if (!Number.isFinite(valore)) return minimo;
|
|
161
|
+
return Math.min(massimo, Math.max(minimo, valore));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* La finestra che il modello vede, e il conto esatto di ciò che non vede.
|
|
166
|
+
*
|
|
167
|
+
* @param {string} testo
|
|
168
|
+
* @param {{cap?: number, headShare?: number, reference?: TalosResearchPageReference | null}} [opzioni]
|
|
169
|
+
* @returns {TalosResearchPageWindow}
|
|
170
|
+
*/
|
|
171
|
+
export function talosResearchPageBudget(testo, opzioni = {}) {
|
|
172
|
+
const pagina = typeof testo === 'string' ? testo : String(testo ?? '');
|
|
173
|
+
const tetto = Math.trunc(stretto(opzioni.cap ?? TALOS_RESEARCH_PAGE_BUDGET, 1, TALOS_RESEARCH_KEPT_CAP));
|
|
174
|
+
const quotaTesta = stretto(opzioni.headShare ?? TALOS_RESEARCH_HEAD_SHARE, 0, 1);
|
|
175
|
+
const riferimento = opzioni.reference ?? null;
|
|
176
|
+
const totali = pagina.length;
|
|
177
|
+
|
|
178
|
+
if (totali <= tetto) {
|
|
179
|
+
return { window: pagina, total: totali, shown: totali, omitted: 0, truncated: false, marker: null };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const tettoTesta = Math.round(tetto * quotaTesta);
|
|
183
|
+
const testa = pagina.slice(0, tagliaInTesta(pagina, tettoTesta));
|
|
184
|
+
const coda = pagina.slice(tagliaInCoda(pagina, tetto - tettoTesta));
|
|
185
|
+
const mostrati = testa.length + coda.length;
|
|
186
|
+
const tolti = totali - mostrati;
|
|
187
|
+
|
|
188
|
+
/*
|
|
189
|
+
* ⛔ D-10G, 10/09 — la lezione già pagata su questa stessa riga di codice: il
|
|
190
|
+
* marcatore di `uscitaUtile` diceva «l'elenco completo dei test» su QUALUNQUE
|
|
191
|
+
* troncamento, ed è stato visto dall'owner su una PAGINA WEB. Un marcatore che
|
|
192
|
+
* dice COSA ha tagliato mente appena il contenuto non è quello; questo dice
|
|
193
|
+
* solo QUANTO, e dove trovare il resto quando il resto ha davvero un posto.
|
|
194
|
+
*/
|
|
195
|
+
const dove = riferimento?.percorso
|
|
196
|
+
? `Il testo intero è in ${riferimento.percorso}.${riferimento.chiamata ? ` Per sfogliare il mezzo: ${riferimento.chiamata}` : ''}`
|
|
197
|
+
: 'Il testo intero è conservato nel dossier di questa ricerca.';
|
|
198
|
+
|
|
199
|
+
const marcatore = `… [visti ${mostrati} caratteri su ${totali}: ${testa.length} in testa, ${coda.length} in coda; ${tolti} tolti dal mezzo. ${dove}] …`;
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
window: `${testa}\n\n${marcatore}\n\n${coda}`,
|
|
203
|
+
total: totali,
|
|
204
|
+
shown: mostrati,
|
|
205
|
+
omitted: tolti,
|
|
206
|
+
truncated: true,
|
|
207
|
+
marker: marcatore,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { talosResearchSupportLabel } from './report.mjs'
|
|
2
|
+
import { inlineInTestoSemplice, markdownInBlocchiReport, runsDiMarkdown } from './markdown-server.mjs'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* PORTO di AVM/mobile/src/lib/research/researchPdf.ts (246 righe, letto per intero il
|
|
6
|
+
* 12/09/2026 prima di scrivere una riga). ⛔ SOLA LETTURA sul mobile: qui non si tocca.
|
|
7
|
+
*
|
|
8
|
+
* ⛔⛔ EXPORT — una ricerca che diventa un PDF, in TRE TONI.
|
|
9
|
+
*
|
|
10
|
+
* Owner 2026-08-03 (mobile): «quando clicchi per generare il pdf appare un popup che ti fa
|
|
11
|
+
* scegliere il "tono" del pdf tra 3 template». Owner 12/09/2026 (desktop): «la ricerca
|
|
12
|
+
* approfondita deve avere una suite di esportazioni COMPLETA».
|
|
13
|
+
*
|
|
14
|
+
* I tre sono documenti DIVERSI, non tre tavolozze sullo stesso testo. Un cambio di colore
|
|
15
|
+
* travestito da scelta è una domanda posta a vuoto: chi la riceve deve fermarsi a pensare, e
|
|
16
|
+
* qualunque cosa risponda ottiene la stessa cosa.
|
|
17
|
+
*
|
|
18
|
+
* `report` — a chi deve leggerlo tutto: copertina, sintesi, ogni affermazione col suo
|
|
19
|
+
* verdetto e il passaggio, poi le fonti.
|
|
20
|
+
* `brief` — a chi ha due minuti: la risposta, cosa regge, cosa NON regge. Niente
|
|
21
|
+
* passaggi, niente elenco fonti.
|
|
22
|
+
* `dossier` — a chi deve controllare: affermazione, verdetto, fonte, in tabella. Nessuna
|
|
23
|
+
* prosa. È quello che gli altri non hanno.
|
|
24
|
+
*
|
|
25
|
+
* ⛔ Il modulo è PURO di proposito, come il suo originale: il documento si prova senza
|
|
26
|
+
* pdfmake, senza rete e senza telefono. Chi lo trasforma in byte è `esportazioni.mjs`, che
|
|
27
|
+
* passa questo `TalosReportInput` a `generateTalosDocument({format:'pdf', report})` — cioè
|
|
28
|
+
* allo STESSO impaginatore (`document-report.mjs`) che usa `document_create`. Un secondo
|
|
29
|
+
* impaginatore sarebbe un secondo aspetto per gli stessi documenti.
|
|
30
|
+
*
|
|
31
|
+
* ════════════════════════════════════════════════════════════════════════════════════════
|
|
32
|
+
* ⛔⛔⛔ L'UNICA DIVERGENZA DAL MOBILE, E NON È UNO STILE: `sourceIndex` È 1-BASED.
|
|
33
|
+
* ════════════════════════════════════════════════════════════════════════════════════════
|
|
34
|
+
*
|
|
35
|
+
* `researchPdf.ts` fa `report.sources[claim.sourceIndex]`. Ogni altro lettore dello stesso
|
|
36
|
+
* record — su mobile E qui — fa `sources[claim.sourceIndex - 1]`:
|
|
37
|
+
* · `researchReport.ts:128` / `report.mjs` (la prosa del rapporto)
|
|
38
|
+
* · `researchRecheck.ts:114`, `researchSynthesis.ts:254`, `researchVerification.ts:397,422`
|
|
39
|
+
* ⇒ Il PDF del mobile attribuisce ogni affermazione alla fonte SEGUENTE, e l'ultima a «—».
|
|
40
|
+
* Il suo test non lo vede perché la sua fixture numera le fonti da 0, cioè con una
|
|
41
|
+
* convenzione che nessun motore produce.
|
|
42
|
+
* ⛔ Portarlo «fedele» qui avrebbe importato il difetto su un record scritto da `report.mjs`,
|
|
43
|
+
* che è 1-based per costruzione. Qui si usa `- 1`, e il test lo morde con un record vero.
|
|
44
|
+
* ⛔ Il difetto resta APERTO sul mobile: non ho ownership lì, si segnala e non si corregge.
|
|
45
|
+
*
|
|
46
|
+
* ═════════════════════════════════════════════════════════════════════════════════════
|
|
47
|
+
* ⛔⛔ LA SECONDA DIVERGENZA, 12/09: IL MARKDOWN SI RENDE.
|
|
48
|
+
* ═════════════════════════════════════════════════════════════════════════════════════
|
|
49
|
+
*
|
|
50
|
+
* `researchPdf.ts` mette la sintesi in un blocco solo (`{t:'p', x: report.summary}`) e il
|
|
51
|
+
* testo di ogni affermazione dentro un titolo, così com'è. Ma quel testo lo scrive un modello,
|
|
52
|
+
* e un modello scrive **Markdown**: nel PDF di una ricerca vera (L8, 12/09) uscivano
|
|
53
|
+
* `## Executive Summary` e `**Key Components:**` LETTERALI, come nell'HTML.
|
|
54
|
+
* ⇒ Qui la sintesi passa da `markdownInBlocchiReport` (titoli, elenchi, tabelle veri) e il
|
|
55
|
+
* testo delle affermazioni da `runsDiMarkdown` / `inlineInTestoSemplice`.
|
|
56
|
+
* ⛔ Il PASSAGGIO no, mai: è la PROVA, cioè il testo com'è nella fonte. Renderlo vorrebbe dire
|
|
57
|
+
* modificare l'unica cosa che il rapporto conserva perché non sia modificabile.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @import { TalosResearchReportRecord } from './report.mjs'
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
export const TALOS_RESEARCH_PDF_TONES = Object.freeze(['report', 'brief', 'dossier'])
|
|
65
|
+
|
|
66
|
+
/** Il tono di partenza: quello completo, che non lascia fuori niente. */
|
|
67
|
+
export const TALOS_RESEARCH_PDF_DEFAULT_TONE = 'report'
|
|
68
|
+
|
|
69
|
+
/** @param {{checks?:object}} claim */
|
|
70
|
+
function verdetto(claim) {
|
|
71
|
+
return talosResearchSupportLabel(claim?.checks ?? {})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Il nome della fonte di un'affermazione. ⛔ `sourceIndex` è 1-BASED (vedi la testa del file).
|
|
76
|
+
* @param {TalosResearchReportRecord} report
|
|
77
|
+
* @param {number} numero
|
|
78
|
+
* @returns {string}
|
|
79
|
+
*/
|
|
80
|
+
function fonteDi(report, numero) {
|
|
81
|
+
const source = report.sources[Number(numero) - 1]
|
|
82
|
+
if (!source) return '—'
|
|
83
|
+
// Il titolo se c'è, altrimenti il dominio: un URL intero in una cella di tabella la
|
|
84
|
+
// sfonda, e nessuno lo legge comunque.
|
|
85
|
+
if (String(source.title ?? '').trim().length > 0) return source.title
|
|
86
|
+
/*
|
|
87
|
+
* ⛔ L'host INTERO (`altro.example.org`), non il dominio registrabile: il porto del mobile fa
|
|
88
|
+
* `new URL(url).hostname`, e qui era partita una scorciatoia verso
|
|
89
|
+
* `talosResearchRegistrableHost` di `independence.mjs` — che torna l'eTLD+1
|
|
90
|
+
* (`example.org`). Quella funzione esiste per decidere se due fonti sono INDIPENDENTI, cioè
|
|
91
|
+
* per accorpare i sottodomini apposta: usarla per un'etichetta farebbe leggere due fonti
|
|
92
|
+
* diverse come la stessa. Trovato dal test, non ragionandoci sopra.
|
|
93
|
+
*/
|
|
94
|
+
try {
|
|
95
|
+
return new URL(source.url).hostname || String(source.url ?? '—')
|
|
96
|
+
} catch {
|
|
97
|
+
return String(source.url ?? '—')
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Quante reggono, quante a metà, quante smentite, quante mai verificate.
|
|
103
|
+
* @param {TalosResearchReportRecord} report
|
|
104
|
+
* @returns {{supported:number, partial:number, contradicted:number, unverified:number}}
|
|
105
|
+
*/
|
|
106
|
+
export function talosResearchPdfTally(report) {
|
|
107
|
+
const tally = { supported: 0, partial: 0, contradicted: 0, unverified: 0 }
|
|
108
|
+
for (const claim of report.claims ?? []) {
|
|
109
|
+
switch (claim?.checks?.claimSupported) {
|
|
110
|
+
case 'yes': tally.supported += 1; break
|
|
111
|
+
case 'partial': tally.partial += 1; break
|
|
112
|
+
case 'no': tally.contradicted += 1; break
|
|
113
|
+
default: tally.unverified += 1
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return tally
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* La riga che dice come è stato giudicato, o che NON lo è stato.
|
|
121
|
+
*
|
|
122
|
+
* «Nessun giudice indipendente era disponibile» e «tutte le citazioni hanno fallito il
|
|
123
|
+
* controllo meccanico» sono due fatti diversi, e il record li tiene separati apposta. Un PDF
|
|
124
|
+
* che tace su questo consegna un verdetto senza dire chi l'ha dato.
|
|
125
|
+
*/
|
|
126
|
+
function nota(report) {
|
|
127
|
+
return {
|
|
128
|
+
t: 'note',
|
|
129
|
+
x: report.judge
|
|
130
|
+
? `Le affermazioni sono state giudicate da ${report.judge}, confrontandole con il passaggio della fonte.`
|
|
131
|
+
: 'Nessun giudice indipendente era disponibile: i verdetti vengono dal solo controllo meccanico della citazione.',
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function copertina(report, options) {
|
|
136
|
+
const titolo = String(options.title ?? '').trim()
|
|
137
|
+
return {
|
|
138
|
+
t: 'cover',
|
|
139
|
+
title: titolo || report.question,
|
|
140
|
+
subtitle: titolo ? report.question : 'Ricerca approfondita TALOS',
|
|
141
|
+
...(options.date ? { date: options.date } : {}),
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function bilancio(report) {
|
|
146
|
+
const tally = talosResearchPdfTally(report)
|
|
147
|
+
return {
|
|
148
|
+
t: 'kpi',
|
|
149
|
+
items: [
|
|
150
|
+
{ l: 'Sostenute', v: String(tally.supported) },
|
|
151
|
+
{ l: 'In parte', v: String(tally.partial) },
|
|
152
|
+
{ l: 'Smentite', v: String(tally.contradicted) },
|
|
153
|
+
{ l: 'Non verificate', v: String(tally.unverified) },
|
|
154
|
+
],
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function rapportoCompleto(report, options) {
|
|
159
|
+
const blocks = [
|
|
160
|
+
copertina(report, options),
|
|
161
|
+
{ t: 'h', lvl: 1, x: 'In breve' },
|
|
162
|
+
...markdownInBlocchiReport(report.summary, { livelloMinimo: 2 }),
|
|
163
|
+
bilancio(report),
|
|
164
|
+
nota(report),
|
|
165
|
+
{ t: 'pb' },
|
|
166
|
+
{ t: 'h', lvl: 1, x: 'Le affermazioni, una per una' },
|
|
167
|
+
]
|
|
168
|
+
report.claims.forEach((claim, index) => {
|
|
169
|
+
blocks.push({ t: 'h', lvl: 3, x: `${index + 1}. ${inlineInTestoSemplice(claim.text)}` })
|
|
170
|
+
blocks.push({ t: 'p', x: `Verdetto: ${verdetto(claim)} — fonte: ${fonteDi(report, claim.sourceIndex)}` })
|
|
171
|
+
// Il passaggio è la prova. Senza, «sostenuta» è una parola che chiede fiducia invece
|
|
172
|
+
// di darla.
|
|
173
|
+
if (String(claim.passage ?? '').trim().length > 0) blocks.push({ t: 'note', x: `«${claim.passage}»` })
|
|
174
|
+
})
|
|
175
|
+
if (report.sources.length > 0) {
|
|
176
|
+
blocks.push({ t: 'pb' }, { t: 'h', lvl: 1, x: 'Le fonti' })
|
|
177
|
+
blocks.push({
|
|
178
|
+
t: 'table',
|
|
179
|
+
head: ['#', 'Titolo', 'Indirizzo', 'Come'],
|
|
180
|
+
align: ['r', 'l', 'l', 'l'],
|
|
181
|
+
rows: report.sources.map((source, index) => [
|
|
182
|
+
String(index + 1),
|
|
183
|
+
source.title || '—',
|
|
184
|
+
source.url,
|
|
185
|
+
source.obtained === 'page' ? 'pagina letta' : 'solo estratto',
|
|
186
|
+
]),
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
return blocks
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function sintesi(report, options) {
|
|
193
|
+
const tally = talosResearchPdfTally(report)
|
|
194
|
+
const regge = report.claims.filter((claim) => claim?.checks?.claimSupported === 'yes')
|
|
195
|
+
const nonRegge = report.claims.filter((claim) => (
|
|
196
|
+
claim?.checks?.claimSupported === 'no' || claim?.checks?.claimSupported === 'partial'
|
|
197
|
+
))
|
|
198
|
+
/*
|
|
199
|
+
* Niente copertina, e non è una svista.
|
|
200
|
+
*
|
|
201
|
+
* Misurato sul OnePlus Pad 3 (2026-08-04): con la copertina la sintesi usciva di DUE
|
|
202
|
+
* pagine — il blocco `cover` ha 140 punti di margine in cima e da solo si mangia la prima.
|
|
203
|
+
* La riga nel popup promette «una pagina», e una promessa che il documento non mantiene è
|
|
204
|
+
* peggio della promessa assente.
|
|
205
|
+
*/
|
|
206
|
+
const titolo = String(options.title ?? '').trim()
|
|
207
|
+
const blocks = [
|
|
208
|
+
{ t: 'h', lvl: 1, x: titolo || report.question },
|
|
209
|
+
...(titolo ? [{ t: 'note', x: report.question }] : []),
|
|
210
|
+
...markdownInBlocchiReport(report.summary, { livelloMinimo: 3 }),
|
|
211
|
+
bilancio(report),
|
|
212
|
+
]
|
|
213
|
+
if (regge.length > 0) {
|
|
214
|
+
blocks.push({ t: 'h', lvl: 2, x: 'Quello che regge' })
|
|
215
|
+
// Quattro, non tutte: una sintesi che riporta trenta punti non è una sintesi, è il
|
|
216
|
+
// rapporto senza le prove.
|
|
217
|
+
blocks.push({ t: 'list', items: regge.slice(0, 4).map((claim) => runsDiMarkdown(claim.text)) })
|
|
218
|
+
}
|
|
219
|
+
if (nonRegge.length > 0) {
|
|
220
|
+
blocks.push({ t: 'h', lvl: 2, x: 'Quello che NON regge' })
|
|
221
|
+
blocks.push({
|
|
222
|
+
t: 'list',
|
|
223
|
+
items: nonRegge.slice(0, 4).map((claim) => `${inlineInTestoSemplice(claim.text)} — ${verdetto(claim)}`),
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
if (tally.unverified > 0) {
|
|
227
|
+
blocks.push({
|
|
228
|
+
t: 'note',
|
|
229
|
+
x: `${tally.unverified} affermazioni non è stato possibile verificarle: la fonte non è stata riaperta o il passaggio non c'era.`,
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
blocks.push(nota(report))
|
|
233
|
+
return blocks
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function dossier(report, options) {
|
|
237
|
+
return [
|
|
238
|
+
copertina(report, options),
|
|
239
|
+
{ t: 'h', lvl: 1, x: 'Affermazioni e prove' },
|
|
240
|
+
nota(report),
|
|
241
|
+
{
|
|
242
|
+
t: 'table',
|
|
243
|
+
head: ['#', 'Affermazione', 'Verdetto', 'Fonte'],
|
|
244
|
+
align: ['r', 'l', 'l', 'l'],
|
|
245
|
+
rows: report.claims.map((claim, index) => [
|
|
246
|
+
String(index + 1),
|
|
247
|
+
runsDiMarkdown(claim.text),
|
|
248
|
+
verdetto(claim),
|
|
249
|
+
fonteDi(report, claim.sourceIndex),
|
|
250
|
+
]),
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
t: 'chart',
|
|
254
|
+
kind: 'pie',
|
|
255
|
+
labels: ['Sostenute', 'In parte', 'Smentite', 'Non verificate'],
|
|
256
|
+
series: [{ data: Object.values(talosResearchPdfTally(report)) }],
|
|
257
|
+
},
|
|
258
|
+
]
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Il documento, nel tono chiesto.
|
|
263
|
+
*
|
|
264
|
+
* Un rapporto senza affermazioni non è un errore — una ricerca può finire senza che nessuna
|
|
265
|
+
* citazione regga — ma un PDF di sole intestazioni vuote non lo dice a nessuno. Quindi si dice.
|
|
266
|
+
*
|
|
267
|
+
* @param {TalosResearchReportRecord} report
|
|
268
|
+
* @param {'report'|'brief'|'dossier'} tone
|
|
269
|
+
* @param {{date?:string, title?:string|null}} [options]
|
|
270
|
+
* @returns {{theme:string, footer:object, blocks:object[]}}
|
|
271
|
+
*/
|
|
272
|
+
export function talosResearchPdfSpec(report, tone, options = {}) {
|
|
273
|
+
const blocks = (report.claims?.length ?? 0) === 0
|
|
274
|
+
? [
|
|
275
|
+
copertina(report, options),
|
|
276
|
+
...markdownInBlocchiReport(report.summary, { livelloMinimo: 2 }),
|
|
277
|
+
{ t: 'note', x: 'Questa ricerca non ha prodotto affermazioni verificabili.' },
|
|
278
|
+
]
|
|
279
|
+
: tone === 'brief'
|
|
280
|
+
? sintesi(report, options)
|
|
281
|
+
: tone === 'dossier'
|
|
282
|
+
? dossier(report, options)
|
|
283
|
+
: rapportoCompleto(report, options)
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
// Il dossier vive di tabelle larghe; gli altri due si leggono.
|
|
287
|
+
theme: tone === 'dossier' ? 'plain' : 'report',
|
|
288
|
+
footer: { text: 'TALOS · ricerca approfondita', pageNo: true },
|
|
289
|
+
blocks,
|
|
290
|
+
}
|
|
291
|
+
}
|