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,192 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PORTO FEDELE di AVM/mobile/src/lib/research/researchRecheckHistory.ts (176 righe, 11/09/2026).
|
|
3
|
+
*
|
|
4
|
+
* ⛔⛔ TENUTA-NEL-TEMPO-01 — quanto vale OGGI un rapporto di ieri.
|
|
5
|
+
*
|
|
6
|
+
* ## Cosa dice la letteratura, e perché cambia il calcolo
|
|
7
|
+
*
|
|
8
|
+
* Il decadimento delle citazioni web ha DUE assi, e confonderli è l'errore
|
|
9
|
+
* standard: il *link rot* è l'indirizzo che muore, il *content drift* è la
|
|
10
|
+
* pagina che risponde ancora e non dice più ciò che era stato citato. Lo studio
|
|
11
|
+
* di riferimento (Zittrain et al., Harvard Law Review 127 — il lavoro da cui è
|
|
12
|
+
* nato Perma.cc) misura il secondo a mano, controllando se il link «produce
|
|
13
|
+
* ancora la fonte originale»: fra i link ancora VIVI, solo il **29,9%**
|
|
14
|
+
* conteneva davvero il materiale citato. L'emivita dei riferimenti web è
|
|
15
|
+
* stimata fra i ~5 e i ~14 anni a seconda del corpus, e la regola pratica è che
|
|
16
|
+
* i primi cinque anni una bibliografia li attraversa quasi intatta.
|
|
17
|
+
*
|
|
18
|
+
* ⇒ Da qui la scelta che conta: **la tenuta si conta sui PASSAGGI, non sulle
|
|
19
|
+
* pagine**. Una pagina «cambiata» che conserva tutte le frasi su cui il
|
|
20
|
+
* rapporto si appoggia non gli ha tolto niente, e contarla come una perdita
|
|
21
|
+
* farebbe scendere un numero che nella sostanza non è sceso. È la stessa
|
|
22
|
+
* domanda che quegli studi pongono a mano — noi la possiamo porre da soli
|
|
23
|
+
* perché il testo di allora ce l'abbiamo.
|
|
24
|
+
*
|
|
25
|
+
* ## ⛔ Il ricontrollo c'era già, e non si poteva rileggere
|
|
26
|
+
*
|
|
27
|
+
* Ogni ricontrollo scriveva il suo documento in Libreria — in prosa, per una
|
|
28
|
+
* persona. Bello da leggere e impossibile da confrontare: ricavare i numeri
|
|
29
|
+
* ripassando l'italiano stampato è esattamente il modo in cui una misura
|
|
30
|
+
* diventa un'invenzione.
|
|
31
|
+
*
|
|
32
|
+
* ⇒ Il documento resta identico per chi lo legge, e in fondo porta un blocco
|
|
33
|
+
* che si rilegge ESATTO. Blocco recintato in coda, non frontmatter: è il posto
|
|
34
|
+
* in cui il Markdown conserva i dati strutturati (lo stesso trattamento che
|
|
35
|
+
* riceve JSON-LD), mentre il frontmatter è per i metadati e passerebbe sopra
|
|
36
|
+
* all'intestazione che la persona legge.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { talosResearchRecheckStanding } from './recheck.mjs';
|
|
40
|
+
|
|
41
|
+
/** @typedef {import('./recheck.mjs').TalosResearchRecheck} TalosResearchRecheck */
|
|
42
|
+
|
|
43
|
+
const FENCE_OPEN = '```talos-research-recheck';
|
|
44
|
+
const FENCE_CLOSE = '```';
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Una tappa della storia: un ricontrollo, con quanto reggeva quel giorno.
|
|
48
|
+
*
|
|
49
|
+
* @typedef {object} TalosResearchRecheckTappa
|
|
50
|
+
* @property {string} at
|
|
51
|
+
* @property {number} total
|
|
52
|
+
* @property {number} intact
|
|
53
|
+
* @property {number} changed
|
|
54
|
+
* @property {number} unreachable
|
|
55
|
+
* @property {number} passagesStanding
|
|
56
|
+
* @property {number} passagesLost
|
|
57
|
+
* @property {number | null} tenuta
|
|
58
|
+
* Quanti passaggi citati reggono ancora, da 0 a 1 — `null` quando non ce
|
|
59
|
+
* n'era nessuno da controllare.
|
|
60
|
+
* ⛔ `null` e 0 sono due cose diverse: «non c'era niente da controllare» e
|
|
61
|
+
* «non regge più niente». Un `null` letto come zero disegna un crollo che
|
|
62
|
+
* non è mai avvenuto.
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* La tappa col suo `runId`, come sta scritta nel documento.
|
|
67
|
+
*
|
|
68
|
+
* @typedef {TalosResearchRecheckTappa & {runId: string}} TalosResearchRecheckRecord
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* La tappa, e quanto è cambiata rispetto a quella prima di lei.
|
|
73
|
+
*
|
|
74
|
+
* @typedef {TalosResearchRecheckTappa & {primo: boolean, delta: number | null}} TalosResearchRecheckPasso
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} runId
|
|
79
|
+
* @param {TalosResearchRecheck} recheck
|
|
80
|
+
* @returns {TalosResearchRecheckRecord}
|
|
81
|
+
*/
|
|
82
|
+
function tappaDi(runId, recheck) {
|
|
83
|
+
const standing = talosResearchRecheckStanding(recheck);
|
|
84
|
+
// ⛔ `standing` aggrega solo i passaggi PERSI: quelli che reggono stanno
|
|
85
|
+
// sulle singole fonti e vanno sommati qui. Senza il totale, «3 persi» non
|
|
86
|
+
// dice niente — tre su quattro e tre su trecento sono due rapporti diversi.
|
|
87
|
+
const reggono = recheck.sources.reduce((totale, fonte) => totale + fonte.passagesStanding, 0);
|
|
88
|
+
const passaggi = reggono + standing.passagesLost;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
runId,
|
|
92
|
+
at: recheck.at,
|
|
93
|
+
total: standing.total,
|
|
94
|
+
intact: standing.intact,
|
|
95
|
+
changed: standing.changed,
|
|
96
|
+
unreachable: standing.unreachable,
|
|
97
|
+
passagesStanding: reggono,
|
|
98
|
+
passagesLost: standing.passagesLost,
|
|
99
|
+
tenuta: passaggi > 0 ? reggono / passaggi : null,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Il blocco da appendere al documento del ricontrollo.
|
|
105
|
+
*
|
|
106
|
+
* ⛔ Porta il `runId`: il nome del file è la domanda, e due ricerche possono
|
|
107
|
+
* farsi la stessa domanda. Legare la storia al nome vorrebbe dire mescolare i
|
|
108
|
+
* ricontrolli di ricerche diverse e non accorgersene mai.
|
|
109
|
+
*
|
|
110
|
+
* @param {string} runId
|
|
111
|
+
* @param {TalosResearchRecheck} recheck
|
|
112
|
+
* @returns {string}
|
|
113
|
+
*/
|
|
114
|
+
export function talosResearchRecheckBlock(runId, recheck) {
|
|
115
|
+
return [FENCE_OPEN, JSON.stringify(tappaDi(runId, recheck)), FENCE_CLOSE].join('\n');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* La tappa dentro un documento, o `null` se lì non c'è.
|
|
120
|
+
*
|
|
121
|
+
* ⛔ Un documento vecchio — scritto prima che il blocco esistesse — torna
|
|
122
|
+
* `null`, non un oggetto a zero. Uno zero finirebbe nella storia come un
|
|
123
|
+
* crollo, e sarebbe un crollo inventato dal nostro formato.
|
|
124
|
+
*
|
|
125
|
+
* @param {string | null | undefined} text
|
|
126
|
+
* @returns {TalosResearchRecheckRecord | null}
|
|
127
|
+
*/
|
|
128
|
+
export function talosResearchParseRecheckBlock(text) {
|
|
129
|
+
if (!text) return null;
|
|
130
|
+
const apre = text.indexOf(FENCE_OPEN);
|
|
131
|
+
if (apre < 0) return null;
|
|
132
|
+
const daCapo = text.indexOf('\n', apre);
|
|
133
|
+
if (daCapo < 0) return null;
|
|
134
|
+
const chiude = text.indexOf(FENCE_CLOSE, daCapo);
|
|
135
|
+
if (chiude < 0) return null;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const letto = JSON.parse(text.slice(daCapo + 1, chiude).trim());
|
|
139
|
+
if (typeof letto.runId !== 'string' || typeof letto.at !== 'string') return null;
|
|
140
|
+
/** @param {string} chiave */
|
|
141
|
+
const numero = (chiave) => (typeof letto[chiave] === 'number' ? letto[chiave] : 0);
|
|
142
|
+
return {
|
|
143
|
+
runId: letto.runId,
|
|
144
|
+
at: letto.at,
|
|
145
|
+
total: numero('total'),
|
|
146
|
+
intact: numero('intact'),
|
|
147
|
+
changed: numero('changed'),
|
|
148
|
+
unreachable: numero('unreachable'),
|
|
149
|
+
passagesStanding: numero('passagesStanding'),
|
|
150
|
+
passagesLost: numero('passagesLost'),
|
|
151
|
+
tenuta: typeof letto.tenuta === 'number' ? letto.tenuta : null,
|
|
152
|
+
};
|
|
153
|
+
} catch {
|
|
154
|
+
// Un blocco rotto è un blocco che non c'è. Non si indovina.
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* La storia in ordine di tempo, con il salto da una tappa all'altra.
|
|
161
|
+
*
|
|
162
|
+
* ⛔ Il delta si calcola solo fra due tappe che hanno ENTRAMBE una tenuta: da
|
|
163
|
+
* `null` a 0,86 non è un guadagno dell'86%, è la prima misura.
|
|
164
|
+
*
|
|
165
|
+
* @param {readonly TalosResearchRecheckTappa[]} tappe
|
|
166
|
+
* @returns {readonly TalosResearchRecheckPasso[]}
|
|
167
|
+
*/
|
|
168
|
+
export function talosResearchRecheckStoria(tappe) {
|
|
169
|
+
const ordinate = [...tappe]
|
|
170
|
+
.filter((tappa) => Number.isFinite(Date.parse(tappa.at)))
|
|
171
|
+
.sort((a, b) => Date.parse(a.at) - Date.parse(b.at));
|
|
172
|
+
|
|
173
|
+
// Lo stesso istante due volte è lo stesso ricontrollo salvato due volte:
|
|
174
|
+
// due righe identiche nella storia sono rumore, non un secondo controllo.
|
|
175
|
+
/** @type {Set<string>} */
|
|
176
|
+
const viste = new Set();
|
|
177
|
+
const distinte = ordinate.filter((tappa) => {
|
|
178
|
+
if (viste.has(tappa.at)) return false;
|
|
179
|
+
viste.add(tappa.at);
|
|
180
|
+
return true;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return distinte.map((tappa, indice) => {
|
|
184
|
+
const prima = indice > 0 ? distinte[indice - 1] : null;
|
|
185
|
+
const confrontabile = prima !== null && prima.tenuta !== null && tappa.tenuta !== null;
|
|
186
|
+
return {
|
|
187
|
+
...tappa,
|
|
188
|
+
primo: indice === 0,
|
|
189
|
+
delta: confrontabile ? tappa.tenuta - prima.tenuta : null,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PORTO FEDELE di AVM/mobile/src/lib/research/researchRecheck.ts (176 righe, 11/09/2026).
|
|
3
|
+
*
|
|
4
|
+
* R12 — chiedere, più tardi, se le fonti dicono ancora quello che dicevano.
|
|
5
|
+
*
|
|
6
|
+
* Il motivo misurato per cui conta: **oltre il 75% dei contenuti web citati era
|
|
7
|
+
* cambiato entro tre anni**, e la raggiungibilità di una citazione scende
|
|
8
|
+
* dall'87% nei suoi primi cinque anni al 38% dopo dieci. Il link morto è la
|
|
9
|
+
* metà visibile; il link vivo che ora dice un'altra cosa è quello pericoloso,
|
|
10
|
+
* perché niente in lui sembra sbagliato.
|
|
11
|
+
*
|
|
12
|
+
* Nessun altro può fare questo controllo. Ogni prodotto di ricerca conserva
|
|
13
|
+
* URL, quindi il massimo che può dirti è se una richiesta riesce — e un soft
|
|
14
|
+
* 404 o una pagina riscritta in silenzio rispondono 200. Noi abbiamo tenuto il
|
|
15
|
+
* testo estratto, quindi la domanda che possiamo porre è quella che conta:
|
|
16
|
+
* *quello che abbiamo letto è ancora lì?*
|
|
17
|
+
*
|
|
18
|
+
* Due misure, di natura deliberatamente diversa:
|
|
19
|
+
*
|
|
20
|
+
* - **Quanta parte del testo tenuto sopravvive**, come proporzione. Un'euristica,
|
|
21
|
+
* e dichiarata tale. Usa il CONTENIMENTO invece di una somiglianza
|
|
22
|
+
* simmetrica: una pagina che ha aggiunto tre paragrafi non ha perso niente
|
|
23
|
+
* di ciò su cui ci appoggiavamo, e chiamarla «cambiata» griderebbe al lupo
|
|
24
|
+
* su ogni sito vivo.
|
|
25
|
+
* - **Se ogni passaggio citato è ancora ritrovabile**, esattamente, con lo
|
|
26
|
+
* stesso controllo meccanico che usa R-4. Nessuna euristica, nessuna soglia,
|
|
27
|
+
* nessuna opinione. È la risposta che decide se il rapporto regge ancora:
|
|
28
|
+
* una pagina può essere riscritta da cima a fondo, e se le frasi che abbiamo
|
|
29
|
+
* citato sono sopravvissute, le citazioni valgono quanto il giorno in cui
|
|
30
|
+
* sono state fatte.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { talosResearchLocate } from './verification.mjs';
|
|
34
|
+
|
|
35
|
+
/** @typedef {import('./report.mjs').TalosResearchReportRecord} TalosResearchReportRecord */
|
|
36
|
+
|
|
37
|
+
/** @typedef {'intact' | 'changed' | 'unreachable'} TalosRecheckState */
|
|
38
|
+
|
|
39
|
+
/** Quanta parte del testo tenuto deve sopravvivere perché una pagina conti come invariata. */
|
|
40
|
+
const INTACT_AT = 0.95;
|
|
41
|
+
|
|
42
|
+
/** Parole per shingle. Cinque è la misura consueta per il quasi-duplicato sulla prosa. */
|
|
43
|
+
const SHINGLE = 5;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @typedef {object} TalosResearchSourceRecheck
|
|
47
|
+
* @property {string} url
|
|
48
|
+
* @property {string} title
|
|
49
|
+
* @property {TalosRecheckState} state
|
|
50
|
+
* @property {number | null} survived 0…1 del testo tenuto ancora presente. Null quando la pagina non si è potuta leggere.
|
|
51
|
+
* @property {string | null} reason Perché non si è potuta leggere, quando è quella la risposta.
|
|
52
|
+
* @property {number} passagesStanding Passaggi citati ancora ritrovabili nella pagina di oggi.
|
|
53
|
+
* @property {number} passagesLost Passaggi citati che non ci sono più. Il numero che conta.
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {object} TalosResearchRecheck
|
|
58
|
+
* @property {string} at
|
|
59
|
+
* @property {readonly TalosResearchSourceRecheck[]} sources
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} text
|
|
64
|
+
* @returns {Set<string>}
|
|
65
|
+
*/
|
|
66
|
+
function shingles(text) {
|
|
67
|
+
const words = text.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, ' ').split(/\s+/).filter(Boolean);
|
|
68
|
+
/** @type {Set<string>} */
|
|
69
|
+
const out = new Set();
|
|
70
|
+
for (let index = 0; index + SHINGLE <= words.length; index += 1) {
|
|
71
|
+
out.add(words.slice(index, index + SHINGLE).join(' '));
|
|
72
|
+
}
|
|
73
|
+
// Un testo troppo corto per gli shingle si confronta intero invece di essere
|
|
74
|
+
// dichiarato vuoto.
|
|
75
|
+
if (out.size === 0 && words.length > 0) out.add(words.join(' '));
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Quanto di `kept` è ancora presente in `now`, da 0 a 1.
|
|
81
|
+
*
|
|
82
|
+
* Monodirezionale di proposito. La domanda non è «queste due pagine sono la
|
|
83
|
+
* stessa» — è «quello su cui ci appoggiavamo è ancora lì», e una pagina che è
|
|
84
|
+
* cresciuta non è una pagina che è cambiata sotto i nostri piedi.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} kept
|
|
87
|
+
* @param {string} now
|
|
88
|
+
* @returns {number}
|
|
89
|
+
*/
|
|
90
|
+
export function talosResearchSurvival(kept, now) {
|
|
91
|
+
const before = shingles(kept);
|
|
92
|
+
if (before.size === 0) return 1;
|
|
93
|
+
const after = shingles(now);
|
|
94
|
+
let found = 0;
|
|
95
|
+
for (const piece of before) if (after.has(piece)) found += 1;
|
|
96
|
+
return found / before.size;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @typedef {object} TalosResearchRecheckDeps
|
|
101
|
+
* @property {(url: string) => Promise<{text: string} | null>} read Rilegge la pagina. Null o un lancio vogliono dire entrambi «non si è potuta leggere».
|
|
102
|
+
* @property {() => string} at
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Ricontrolla ogni fonte di un rapporto finito.
|
|
107
|
+
*
|
|
108
|
+
* IN SEQUENZA, come la verifica: questo gira su un telefono contro i server di
|
|
109
|
+
* altre persone, e una dozzina di richieste simultanee è il modo in cui una
|
|
110
|
+
* connessione domestica e un sito di notizie decidono entrambi che sei uno
|
|
111
|
+
* scraper.
|
|
112
|
+
*
|
|
113
|
+
* Una fonte che non si può leggere si registra, non si butta mai — e vale la
|
|
114
|
+
* pena dire perché questa non è una perdita: il testo estratto è ancora qui,
|
|
115
|
+
* quindi il dossier resta leggibile e citabile dopo che la pagina stessa è
|
|
116
|
+
* sparita. È tutta la ragione per cui il testo era stato tenuto.
|
|
117
|
+
*
|
|
118
|
+
* @param {TalosResearchRecheckDeps} deps
|
|
119
|
+
* @param {TalosResearchReportRecord} report
|
|
120
|
+
* @param {ReadonlyMap<string, string>} keptByUrl Il testo tenuto, per url — vive nei dossier, non nel rapporto.
|
|
121
|
+
* @returns {Promise<TalosResearchRecheck>}
|
|
122
|
+
*/
|
|
123
|
+
export async function talosResearchRecheckReport(deps, report, keptByUrl) {
|
|
124
|
+
/** @type {TalosResearchSourceRecheck[]} */
|
|
125
|
+
const sources = [];
|
|
126
|
+
|
|
127
|
+
for (const source of report.sources) {
|
|
128
|
+
const kept = keptByUrl.get(source.url) ?? '';
|
|
129
|
+
const quoted = report.claims
|
|
130
|
+
.filter((claim) => report.sources[claim.sourceIndex - 1]?.url === source.url)
|
|
131
|
+
.map((claim) => claim.passage)
|
|
132
|
+
.filter((passage) => passage.length > 0);
|
|
133
|
+
|
|
134
|
+
/** @type {{text: string} | null} */
|
|
135
|
+
let fresh = null;
|
|
136
|
+
/** @type {string | null} */
|
|
137
|
+
let reason = null;
|
|
138
|
+
try {
|
|
139
|
+
fresh = await deps.read(source.url);
|
|
140
|
+
if (!fresh) reason = 'unreadable';
|
|
141
|
+
} catch (failure) {
|
|
142
|
+
reason = failure instanceof Error ? failure.message : 'unreadable';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!fresh) {
|
|
146
|
+
sources.push({
|
|
147
|
+
url: source.url,
|
|
148
|
+
title: source.title,
|
|
149
|
+
state: 'unreachable',
|
|
150
|
+
survived: null,
|
|
151
|
+
reason,
|
|
152
|
+
// Non contati come persi: non riusciamo a vedere la pagina, che è una
|
|
153
|
+
// cosa diversa dall'aver guardato e non averli trovati.
|
|
154
|
+
passagesStanding: 0,
|
|
155
|
+
passagesLost: 0,
|
|
156
|
+
});
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const survived = talosResearchSurvival(kept, fresh.text);
|
|
161
|
+
const standing = quoted.filter((passage) => talosResearchLocate(fresh.text, passage) !== null).length;
|
|
162
|
+
|
|
163
|
+
sources.push({
|
|
164
|
+
url: source.url,
|
|
165
|
+
title: source.title,
|
|
166
|
+
state: survived >= INTACT_AT ? 'intact' : 'changed',
|
|
167
|
+
survived,
|
|
168
|
+
reason: null,
|
|
169
|
+
passagesStanding: standing,
|
|
170
|
+
passagesLost: quoted.length - standing,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { at: deps.at(), sources };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* La riga che il lettore riceve per prima: cos'è successo al dossier da allora.
|
|
179
|
+
*
|
|
180
|
+
* @param {TalosResearchRecheck} recheck
|
|
181
|
+
* @returns {{total:number, intact:number, changed:number, unreachable:number, passagesLost:number}}
|
|
182
|
+
*/
|
|
183
|
+
export function talosResearchRecheckStanding(recheck) {
|
|
184
|
+
/** @param {TalosRecheckState} state */
|
|
185
|
+
const count = (state) => recheck.sources.filter((entry) => entry.state === state).length;
|
|
186
|
+
return {
|
|
187
|
+
total: recheck.sources.length,
|
|
188
|
+
intact: count('intact'),
|
|
189
|
+
changed: count('changed'),
|
|
190
|
+
unreachable: count('unreachable'),
|
|
191
|
+
// Citazioni che non risolvono più alle parole che citavano.
|
|
192
|
+
passagesLost: recheck.sources.reduce((total, entry) => total + entry.passagesLost, 0),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { talosResearchVerifiedStanding } from './verification.mjs'
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* PORTO FEDELE di AVM/mobile/src/lib/research/researchReport.ts (175 righe, 11/09/2026).
|
|
5
|
+
*
|
|
6
|
+
* ⛔ `verification.mjs` (porto di `researchVerification.ts`) lo cura un'altra
|
|
7
|
+
* sessione, in parallelo: qui se ne importa solo il nome concordato, senza
|
|
8
|
+
* duplicarne una riga.
|
|
9
|
+
*
|
|
10
|
+
* ⛔⛔ Questo è il pezzo che il cancello di consegna userà (disegno §6.5): il
|
|
11
|
+
* record recintato ` ```talos-research-report ` deve scriversi e rileggersi
|
|
12
|
+
* IDENTICO al mobile. Ogni carattere del recinto, l'ordine dei campi del
|
|
13
|
+
* record e il `null` invece di un recupero parziale sono parte del contratto,
|
|
14
|
+
* non stile.
|
|
15
|
+
*
|
|
16
|
+
* Il rapporto, scritto una volta per due lettori — e che porta il proprio verdetto.
|
|
17
|
+
*
|
|
18
|
+
* Stessa decisione del dossier, per la stessa ragione: prosa per una persona,
|
|
19
|
+
* un record recintato per il processo, scritti entrambi da un oggetto solo così
|
|
20
|
+
* che non possano divergere. Quello che cambia è CHE COSA tiene il record. Ogni
|
|
21
|
+
* affermazione porta il suo passaggio, dove quel passaggio sta nel testo tenuto
|
|
22
|
+
* della fonte, il verdetto, e il nome del giudice che l'ha dato.
|
|
23
|
+
*
|
|
24
|
+
* È la scommessa strutturale di questa fase. Verificare mentre si scrive lo
|
|
25
|
+
* sanno fare tutti; poi la verifica evapora, e un mese dopo il lettore ha un
|
|
26
|
+
* rapporto e nessun modo di chiedere come sia stato controllato. Siccome noi
|
|
27
|
+
* teniamo il passaggio E il verdetto E il giudice, il controllo è un artefatto:
|
|
28
|
+
* si può rileggere, rifare con un giudice diverso, e confrontare con quello che
|
|
29
|
+
* diceva la prima volta. Un prodotto che conserva gli URL non può farlo a
|
|
30
|
+
* nessun prezzo, perché la prova che ha controllato non c'è più.
|
|
31
|
+
*
|
|
32
|
+
* La prosa è stratificata dall'alto — risposta, poi affermazioni, poi fonti —
|
|
33
|
+
* perché 5.000 parole in una colonna su un telefono sono un muro, e perché la
|
|
34
|
+
* stratificazione deve sopravvivere alla lettura come semplice file Markdown
|
|
35
|
+
* fuori dall'app.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @import { TalosResearchSource } from './collector.mjs'
|
|
40
|
+
* @import { TalosResearchChecks, TalosResearchVerifiedClaim } from './verification.mjs'
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {object} TalosResearchReportSourceRecord
|
|
45
|
+
* @property {string} url
|
|
46
|
+
* @property {string} title
|
|
47
|
+
* @property {string | null} publishedAt
|
|
48
|
+
* @property {'page' | 'snippet'} obtained
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @typedef {object} TalosResearchReportClaimRecord
|
|
53
|
+
* @property {string} text
|
|
54
|
+
* @property {number} sourceIndex
|
|
55
|
+
* @property {string} passage Il passaggio com'è nella fonte. Vuoto quando non ci è mai stato trovato.
|
|
56
|
+
* @property {TalosResearchChecks} checks
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {object} TalosResearchReportRecord
|
|
61
|
+
* @property {1} version
|
|
62
|
+
* @property {string} question
|
|
63
|
+
* @property {string} summary
|
|
64
|
+
* @property {string | null} judge Chi era disponibile a giudicare questa corsa,
|
|
65
|
+
* o `null` se nessuno lo era. Registrato qui invece che dedotto dalle
|
|
66
|
+
* affermazioni, perché sono due fatti diversi e dedurre l'uno dall'altro dice
|
|
67
|
+
* una bugia in un caso vero: una corsa con un giudice perfettamente buono le
|
|
68
|
+
* cui citazioni abbiano tutte fallito il controllo meccanico non ha nemmeno
|
|
69
|
+
* un giudice per affermazione, e si leggerebbe come «nessun giudice
|
|
70
|
+
* indipendente era disponibile». Mai verificato e mai avuto bisogno di
|
|
71
|
+
* verifica non devono sembrare la stessa cosa.
|
|
72
|
+
* @property {readonly TalosResearchReportClaimRecord[]} claims
|
|
73
|
+
* @property {readonly TalosResearchReportSourceRecord[]} sources
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
const FENCE_OPEN = '```talos-research-report'
|
|
77
|
+
const FENCE_CLOSE = '```'
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Come si legge un verdetto per una persona. Parole, non simboli: questo file
|
|
81
|
+
* viene letto anche fuori dall'app.
|
|
82
|
+
*
|
|
83
|
+
* @param {TalosResearchChecks} checks
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
export function talosResearchSupportLabel(checks) {
|
|
87
|
+
switch (checks.claimSupported) {
|
|
88
|
+
case 'yes': return 'sostenuta dalla fonte'
|
|
89
|
+
case 'partial': return 'sostenuta solo in parte'
|
|
90
|
+
case 'no': return 'NON sostenuta dalla fonte'
|
|
91
|
+
// ⛔ CONTESA-01: la parola dice anche PERCHÉ, se no «contesa» da sola
|
|
92
|
+
// si legge come una sfumatura di «parziale», che è ciò che non è.
|
|
93
|
+
case 'contested': return 'contesa — le fonti non concordano'
|
|
94
|
+
default: return 'non verificata'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param {{
|
|
100
|
+
* question: string,
|
|
101
|
+
* summary: string,
|
|
102
|
+
* judge: string | null,
|
|
103
|
+
* claims: readonly TalosResearchVerifiedClaim[],
|
|
104
|
+
* sources: readonly TalosResearchSource[],
|
|
105
|
+
* }} input
|
|
106
|
+
* @returns {string}
|
|
107
|
+
*/
|
|
108
|
+
export function talosResearchReportDocument(input) {
|
|
109
|
+
const standing = talosResearchVerifiedStanding(input.claims)
|
|
110
|
+
|
|
111
|
+
/** @type {TalosResearchReportRecord} */
|
|
112
|
+
const record = {
|
|
113
|
+
version: 1,
|
|
114
|
+
question: input.question,
|
|
115
|
+
summary: input.summary,
|
|
116
|
+
judge: input.judge,
|
|
117
|
+
claims: input.claims.map((entry) => ({
|
|
118
|
+
text: entry.claim.text,
|
|
119
|
+
sourceIndex: entry.claim.sourceIndex,
|
|
120
|
+
passage: entry.passage,
|
|
121
|
+
checks: entry.checks,
|
|
122
|
+
})),
|
|
123
|
+
sources: input.sources.map((source) => ({
|
|
124
|
+
url: source.url,
|
|
125
|
+
title: source.title,
|
|
126
|
+
publishedAt: source.publishedAt,
|
|
127
|
+
obtained: source.obtained,
|
|
128
|
+
})),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const verdictLine = [
|
|
132
|
+
`Affermazioni: ${standing.total}`,
|
|
133
|
+
`sostenute: ${standing.supported}`,
|
|
134
|
+
`in parte: ${standing.partial}`,
|
|
135
|
+
`non sostenute: ${standing.unsupported}`,
|
|
136
|
+
`non verificate: ${standing.unchecked}`,
|
|
137
|
+
].join(' · ')
|
|
138
|
+
|
|
139
|
+
const prose = [
|
|
140
|
+
`# ${input.question}`,
|
|
141
|
+
'',
|
|
142
|
+
input.summary,
|
|
143
|
+
'',
|
|
144
|
+
verdictLine,
|
|
145
|
+
input.judge
|
|
146
|
+
? `Verifica eseguita da: ${input.judge} — mai dal modello che ha scritto il rapporto.`
|
|
147
|
+
: 'Verifica non eseguita: nessun giudice indipendente era disponibile.',
|
|
148
|
+
'',
|
|
149
|
+
'## Le affermazioni',
|
|
150
|
+
...input.claims.map((entry, index) => {
|
|
151
|
+
const source = input.sources[entry.claim.sourceIndex - 1]
|
|
152
|
+
return [
|
|
153
|
+
'',
|
|
154
|
+
`### ${index + 1}. ${entry.claim.text}`,
|
|
155
|
+
`Esito: ${talosResearchSupportLabel(entry.checks)}${entry.checks.supportReason ? ` — ${entry.checks.supportReason}` : ''}`,
|
|
156
|
+
entry.passage
|
|
157
|
+
? `\n> ${entry.passage}`
|
|
158
|
+
: `\n> (il passaggio citato non è nel testo della fonte: "${entry.claim.quote}")`,
|
|
159
|
+
'',
|
|
160
|
+
source
|
|
161
|
+
? `Fonte: ${source.title} — ${source.url}${source.obtained === 'snippet' ? ' (solo estratto dal motore di ricerca)' : ''}`
|
|
162
|
+
: 'Fonte: citata ma mai raccolta.',
|
|
163
|
+
].join('\n')
|
|
164
|
+
}),
|
|
165
|
+
'',
|
|
166
|
+
`## Fonti (${input.sources.length})`,
|
|
167
|
+
...input.sources.map((source, index) => [
|
|
168
|
+
`${index + 1}. ${source.title} — ${source.url}`,
|
|
169
|
+
` ${source.publishedAt ? `data dichiarata: ${source.publishedAt}` : 'data non dichiarata'}`,
|
|
170
|
+
` ${source.obtained === 'page' ? 'pagina letta' : 'solo estratto dal motore di ricerca'}`,
|
|
171
|
+
].join('\n')),
|
|
172
|
+
].join('\n')
|
|
173
|
+
|
|
174
|
+
return `${prose}\n\n${FENCE_OPEN}\n${JSON.stringify(record)}\n${FENCE_CLOSE}\n`
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Rilegge un rapporto, o ammette di non poterlo fare.
|
|
179
|
+
*
|
|
180
|
+
* `null` invece di un recupero parziale, per la ragione che attraversa tutta
|
|
181
|
+
* questa fase: un rapporto letto a metà mostrerebbe verdetti accanto ad
|
|
182
|
+
* affermazioni a cui non appartengono, e un segno di verifica sbagliato è
|
|
183
|
+
* peggio di nessuno.
|
|
184
|
+
*
|
|
185
|
+
* @param {string} document
|
|
186
|
+
* @returns {TalosResearchReportRecord | null}
|
|
187
|
+
*/
|
|
188
|
+
export function talosResearchParseReport(document) {
|
|
189
|
+
const start = document.indexOf(FENCE_OPEN)
|
|
190
|
+
if (start < 0) return null
|
|
191
|
+
const from = start + FENCE_OPEN.length
|
|
192
|
+
const end = document.indexOf(FENCE_CLOSE, from)
|
|
193
|
+
if (end < 0) return null
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
/** @type {TalosResearchReportRecord} */
|
|
197
|
+
const parsed = JSON.parse(document.slice(from, end))
|
|
198
|
+
if (parsed?.version !== 1 || !Array.isArray(parsed.claims) || !Array.isArray(parsed.sources)) return null
|
|
199
|
+
return { ...parsed, judge: parsed.judge ?? null }
|
|
200
|
+
} catch {
|
|
201
|
+
return null
|
|
202
|
+
}
|
|
203
|
+
}
|