@quickchatai/quickreview 0.0.0-stage → 1.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 +23 -0
- package/README.md +385 -2
- package/THIRD-PARTY-NOTICES.md +134 -0
- package/agents/pass-abstraction.md +64 -0
- package/agents/pass-ask-human.md +134 -0
- package/agents/pass-backcompat.md +67 -0
- package/agents/pass-baseline.md +61 -0
- package/agents/pass-behaviour-delta.md +64 -0
- package/agents/pass-bounds.md +36 -0
- package/agents/pass-claims.md +31 -0
- package/agents/pass-concurrency.md +168 -0
- package/agents/pass-consistency.md +57 -0
- package/agents/pass-contracts.md +30 -0
- package/agents/pass-data-safety.md +54 -0
- package/agents/pass-deferred.md +35 -0
- package/agents/pass-delivery.md +37 -0
- package/agents/pass-duplication.md +60 -0
- package/agents/pass-intent.md +63 -0
- package/agents/pass-lint-conformance.md +46 -0
- package/agents/pass-maintainability.md +67 -0
- package/agents/pass-placement.md +68 -0
- package/agents/pass-prod-risk.md +24 -0
- package/agents/pass-rollout.md +32 -0
- package/agents/pass-roundtrip.md +46 -0
- package/agents/pass-security.md +31 -0
- package/agents/pass-simplicity.md +68 -0
- package/agents/pass-statelessness.md +27 -0
- package/agents/pass-style.md +37 -0
- package/agents/pass-sweep.md +57 -0
- package/agents/pass-tests.md +58 -0
- package/agents/pass-ui.md +23 -0
- package/agents/pass-validate.md +50 -0
- package/agents/pass-widened.md +46 -0
- package/agents/scan/pass-scan.md +86 -0
- package/bin/qcr.js +11 -0
- package/config.example.toml +1067 -0
- package/deploy/ansible/README.md +356 -0
- package/deploy/ansible/group_vars/all.yml +212 -0
- package/deploy/ansible/inventory.example.ini +25 -0
- package/deploy/ansible/playbook.yml +360 -0
- package/deploy/collect-secrets.sh +289 -0
- package/deploy/collect-slack-secrets.mjs +1190 -0
- package/deploy/github-app-manifest.json +31 -0
- package/deploy/manifest.schema.json +75 -0
- package/deploy/qcr-update.sh +803 -0
- package/deploy/reviewer/AGENTS.override.md +12 -0
- package/dist/extensions/cli/bash-guard-ambient.js +42 -0
- package/dist/extensions/cli/bash-guard-ambient.js.map +1 -0
- package/dist/extensions/cli/bash-guard.js +5 -0
- package/dist/extensions/cli/bash-guard.js.map +1 -0
- package/dist/extensions/cli/companion-guard.js +5 -0
- package/dist/extensions/cli/companion-guard.js.map +1 -0
- package/dist/extensions/cli/debug-round.js +8 -0
- package/dist/extensions/cli/debug-round.js.map +1 -0
- package/dist/extensions/cli/inject-bridge.js +5 -0
- package/dist/extensions/cli/inject-bridge.js.map +1 -0
- package/dist/extensions/cli/ledger-pin.js +5 -0
- package/dist/extensions/cli/ledger-pin.js.map +1 -0
- package/dist/extensions/cli/lens.js +13 -0
- package/dist/extensions/cli/lens.js.map +1 -0
- package/dist/extensions/cli/muted-theme.js +5 -0
- package/dist/extensions/cli/muted-theme.js.map +1 -0
- package/dist/extensions/cli/onboarding.js +5 -0
- package/dist/extensions/cli/onboarding.js.map +1 -0
- package/dist/extensions/cli/setup.js +5 -0
- package/dist/extensions/cli/setup.js.map +1 -0
- package/dist/extensions/cli/tui-view.js +5 -0
- package/dist/extensions/cli/tui-view.js.map +1 -0
- package/dist/extensions/companion-guard.js +361 -0
- package/dist/extensions/companion-guard.js.map +1 -0
- package/dist/extensions/debug-round.js +204 -0
- package/dist/extensions/debug-round.js.map +1 -0
- package/dist/extensions/inject-bridge.js +603 -0
- package/dist/extensions/inject-bridge.js.map +1 -0
- package/dist/extensions/muted-theme.js +12 -0
- package/dist/extensions/muted-theme.js.map +1 -0
- package/dist/extensions/onboarding.js +175 -0
- package/dist/extensions/onboarding.js.map +1 -0
- package/dist/extensions/setup-replay.js +269 -0
- package/dist/extensions/setup-replay.js.map +1 -0
- package/dist/extensions/setup-scan.js +998 -0
- package/dist/extensions/setup-scan.js.map +1 -0
- package/dist/extensions/setup-triage.js +175 -0
- package/dist/extensions/setup-triage.js.map +1 -0
- package/dist/extensions/setup.js +1160 -0
- package/dist/extensions/setup.js.map +1 -0
- package/dist/extensions/tui-view.js +389 -0
- package/dist/extensions/tui-view.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/client.js +376 -0
- package/dist/extensions/vendor/openviking-pi/client.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/config.js +189 -0
- package/dist/extensions/vendor/openviking-pi/config.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/index.js +421 -0
- package/dist/extensions/vendor/openviking-pi/index.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +86 -0
- package/dist/extensions/vendor/openviking-pi/lib/capture-adapter.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs +408 -0
- package/dist/extensions/vendor/openviking-pi/lib/takeover-core.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +41 -0
- package/dist/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hint.js +290 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hint.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-honest.js +148 -0
- package/dist/extensions/vendor/openviking-pi/qcr-honest.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hooks.js +68 -0
- package/dist/extensions/vendor/openviking-pi/qcr-hooks.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-leaf.js +77 -0
- package/dist/extensions/vendor/openviking-pi/qcr-leaf.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-lesson.js +216 -0
- package/dist/extensions/vendor/openviking-pi/qcr-lesson.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js +154 -0
- package/dist/extensions/vendor/openviking-pi/qcr-namespaces.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-recall.js +254 -0
- package/dist/extensions/vendor/openviking-pi/qcr-recall.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-shim.js +94 -0
- package/dist/extensions/vendor/openviking-pi/qcr-shim.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/qcr-write.js +333 -0
- package/dist/extensions/vendor/openviking-pi/qcr-write.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/recall.js +108 -0
- package/dist/extensions/vendor/openviking-pi/recall.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs +529 -0
- package/dist/extensions/vendor/openviking-pi/shared/capture-utils.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs +205 -0
- package/dist/extensions/vendor/openviking-pi/shared/credentials.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs +442 -0
- package/dist/extensions/vendor/openviking-pi/shared/pending-queue.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs +286 -0
- package/dist/extensions/vendor/openviking-pi/shared/profile-inject.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +189 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs +580 -0
- package/dist/extensions/vendor/openviking-pi/shared/recall-core.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs +11 -0
- package/dist/extensions/vendor/openviking-pi/shared/retryable.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs +63 -0
- package/dist/extensions/vendor/openviking-pi/shared/session-model.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs +58 -0
- package/dist/extensions/vendor/openviking-pi/shared/uri-guard.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
- package/dist/extensions/vendor/openviking-pi/shared/workspace-peer.mjs.map +1 -0
- package/dist/extensions/vendor/openviking-pi/sync.js +127 -0
- package/dist/extensions/vendor/openviking-pi/sync.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/takeover.js +25 -0
- package/dist/extensions/vendor/openviking-pi/takeover.js.map +1 -0
- package/dist/extensions/vendor/openviking-pi/tools.js +417 -0
- package/dist/extensions/vendor/openviking-pi/tools.js.map +1 -0
- package/dist/src/anomalies.js +483 -0
- package/dist/src/anomalies.js.map +1 -0
- package/dist/src/answerworker.js +180 -0
- package/dist/src/answerworker.js.map +1 -0
- package/dist/src/appstamp.js +68 -0
- package/dist/src/appstamp.js.map +1 -0
- package/dist/src/archive/admission.js +3 -0
- package/dist/src/archive/admission.js.map +1 -0
- package/dist/src/archive/archivedb.js +474 -0
- package/dist/src/archive/archivedb.js.map +1 -0
- package/dist/src/archive/archiver.js +1770 -0
- package/dist/src/archive/archiver.js.map +1 -0
- package/dist/src/archive/archivewrite.js +198 -0
- package/dist/src/archive/archivewrite.js.map +1 -0
- package/dist/src/archive/bundle.js +266 -0
- package/dist/src/archive/bundle.js.map +1 -0
- package/dist/src/archive/dbmove.js +638 -0
- package/dist/src/archive/dbmove.js.map +1 -0
- package/dist/src/archive/duplicatecounts.js +80 -0
- package/dist/src/archive/duplicatecounts.js.map +1 -0
- package/dist/src/archive/eligibility.js +113 -0
- package/dist/src/archive/eligibility.js.map +1 -0
- package/dist/src/archive/extract.js +288 -0
- package/dist/src/archive/extract.js.map +1 -0
- package/dist/src/archive/fsutil.js +330 -0
- package/dist/src/archive/fsutil.js.map +1 -0
- package/dist/src/archive/gzfile.js +277 -0
- package/dist/src/archive/gzfile.js.map +1 -0
- package/dist/src/archive/kinds.js +22 -0
- package/dist/src/archive/kinds.js.map +1 -0
- package/dist/src/archive/livecheckpoint.js +178 -0
- package/dist/src/archive/livecheckpoint.js.map +1 -0
- package/dist/src/archive/liveretention.js +145 -0
- package/dist/src/archive/liveretention.js.map +1 -0
- package/dist/src/archive/manifest.js +284 -0
- package/dist/src/archive/manifest.js.map +1 -0
- package/dist/src/archive/overseer.js +283 -0
- package/dist/src/archive/overseer.js.map +1 -0
- package/dist/src/archive/piglobal.js +129 -0
- package/dist/src/archive/piglobal.js.map +1 -0
- package/dist/src/archive/plan.js +398 -0
- package/dist/src/archive/plan.js.map +1 -0
- package/dist/src/archive/prarchive.js +831 -0
- package/dist/src/archive/prarchive.js.map +1 -0
- package/dist/src/archive/prfiles.js +303 -0
- package/dist/src/archive/prfiles.js.map +1 -0
- package/dist/src/archive/report.js +169 -0
- package/dist/src/archive/report.js.map +1 -0
- package/dist/src/archive/restore.js +276 -0
- package/dist/src/archive/restore.js.map +1 -0
- package/dist/src/archive/rows.js +106 -0
- package/dist/src/archive/rows.js.map +1 -0
- package/dist/src/archive/seal.js +480 -0
- package/dist/src/archive/seal.js.map +1 -0
- package/dist/src/archive/status.js +528 -0
- package/dist/src/archive/status.js.map +1 -0
- package/dist/src/archive/storepass.js +409 -0
- package/dist/src/archive/storepass.js.map +1 -0
- package/dist/src/backfill.js +217 -0
- package/dist/src/backfill.js.map +1 -0
- package/dist/src/bench/cost.js +87 -0
- package/dist/src/bench/exec.js +76 -0
- package/dist/src/bench/values.js +14 -0
- package/dist/src/botcontrol.js +127 -0
- package/dist/src/botcontrol.js.map +1 -0
- package/dist/src/botworker.js +805 -0
- package/dist/src/botworker.js.map +1 -0
- package/dist/src/capture.js +234 -0
- package/dist/src/capture.js.map +1 -0
- package/dist/src/cases.js +1491 -0
- package/dist/src/cases.js.map +1 -0
- package/dist/src/channelfs.js +27 -0
- package/dist/src/channelfs.js.map +1 -0
- package/dist/src/checklist.js +312 -0
- package/dist/src/checklist.js.map +1 -0
- package/dist/src/ciretry.js +91 -0
- package/dist/src/ciretry.js.map +1 -0
- package/dist/src/cli.js +1916 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/cliops.js +333 -0
- package/dist/src/cliops.js.map +1 -0
- package/dist/src/clonedir.js +15 -0
- package/dist/src/clonedir.js.map +1 -0
- package/dist/src/commandeffects.js +43 -0
- package/dist/src/commandeffects.js.map +1 -0
- package/dist/src/commands.js +1312 -0
- package/dist/src/commands.js.map +1 -0
- package/dist/src/companioninbox.js +203 -0
- package/dist/src/companioninbox.js.map +1 -0
- package/dist/src/compare.js +673 -0
- package/dist/src/compare.js.map +1 -0
- package/dist/src/config.js +1027 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/configcheck.js +111 -0
- package/dist/src/configcheck.js.map +1 -0
- package/dist/src/coreext.js +43 -0
- package/dist/src/coreext.js.map +1 -0
- package/dist/src/daemon.js +929 -0
- package/dist/src/daemon.js.map +1 -0
- package/dist/src/debuground.js +731 -0
- package/dist/src/debuground.js.map +1 -0
- package/dist/src/debugroundpi.js +219 -0
- package/dist/src/debugroundpi.js.map +1 -0
- package/dist/src/diagnostics.js +14 -0
- package/dist/src/diagnostics.js.map +1 -0
- package/dist/src/digest.js +139 -0
- package/dist/src/digest.js.map +1 -0
- package/dist/src/dispatch.js +1726 -0
- package/dist/src/dispatch.js.map +1 -0
- package/dist/src/engine/answerguard.js +18 -0
- package/dist/src/engine/answerguard.js.map +1 -0
- package/dist/src/engine/botsdk.js +262 -0
- package/dist/src/engine/botsdk.js.map +1 -0
- package/dist/src/engine/caserunner-sdk.js +332 -0
- package/dist/src/engine/caserunner-sdk.js.map +1 -0
- package/dist/src/engine/debugpi.js +194 -0
- package/dist/src/engine/debugpi.js.map +1 -0
- package/dist/src/eod.js +473 -0
- package/dist/src/eod.js.map +1 -0
- package/dist/src/eodpinwatch.js +391 -0
- package/dist/src/eodpinwatch.js.map +1 -0
- package/dist/src/escalation.js +1009 -0
- package/dist/src/escalation.js.map +1 -0
- package/dist/src/eventloop.js +779 -0
- package/dist/src/eventloop.js.map +1 -0
- package/dist/src/execboundary.js +430 -0
- package/dist/src/execboundary.js.map +1 -0
- package/dist/src/feedback.js +915 -0
- package/dist/src/feedback.js.map +1 -0
- package/dist/src/findingscheck.js +200 -0
- package/dist/src/findingscheck.js.map +1 -0
- package/dist/src/fsdenied.js +26 -0
- package/dist/src/fsdenied.js.map +1 -0
- package/dist/src/ghread.js +181 -0
- package/dist/src/ghread.js.map +1 -0
- package/dist/src/github.js +1063 -0
- package/dist/src/github.js.map +1 -0
- package/dist/src/homes.js +103 -0
- package/dist/src/homes.js.map +1 -0
- package/dist/src/hostroute.js +24 -0
- package/dist/src/hostroute.js.map +1 -0
- package/dist/src/improvements.js +625 -0
- package/dist/src/improvements.js.map +1 -0
- package/dist/src/install.js +946 -0
- package/dist/src/install.js.map +1 -0
- package/dist/src/installkind.js +40 -0
- package/dist/src/installkind.js.map +1 -0
- package/dist/src/ipc/capability.js +286 -0
- package/dist/src/ipc/capability.js.map +1 -0
- package/dist/src/ipc/client.js +226 -0
- package/dist/src/ipc/client.js.map +1 -0
- package/dist/src/ipc/control.js +70 -0
- package/dist/src/ipc/control.js.map +1 -0
- package/dist/src/ipc/ghreadshim.js +77 -0
- package/dist/src/ipc/ghreadshim.js.map +1 -0
- package/dist/src/ipc/launcher.js +65 -0
- package/dist/src/ipc/launcher.js.map +1 -0
- package/dist/src/ipc/permits.js +293 -0
- package/dist/src/ipc/permits.js.map +1 -0
- package/dist/src/ipc/postshim.js +137 -0
- package/dist/src/ipc/postshim.js.map +1 -0
- package/dist/src/ipc/protocol.js +239 -0
- package/dist/src/ipc/protocol.js.map +1 -0
- package/dist/src/ipc/server.js +312 -0
- package/dist/src/ipc/server.js.map +1 -0
- package/dist/src/ipc/workerspec.js +148 -0
- package/dist/src/ipc/workerspec.js.map +1 -0
- package/dist/src/learner/learner.js +1272 -0
- package/dist/src/learner/learner.js.map +1 -0
- package/dist/src/learner/miner.js +948 -0
- package/dist/src/learner/miner.js.map +1 -0
- package/dist/src/learner/packet.js +216 -0
- package/dist/src/learner/packet.js.map +1 -0
- package/dist/src/learner/receipt.js +135 -0
- package/dist/src/learner/receipt.js.map +1 -0
- package/dist/src/learner/status.js +38 -0
- package/dist/src/learner/status.js.map +1 -0
- package/dist/src/ledgercheck.js +120 -0
- package/dist/src/ledgercheck.js.map +1 -0
- package/dist/src/lessonledger.js +451 -0
- package/dist/src/lessonledger.js.map +1 -0
- package/dist/src/lessonselect.js +639 -0
- package/dist/src/lessonselect.js.map +1 -0
- package/dist/src/lessonshadow.js +540 -0
- package/dist/src/lessonshadow.js.map +1 -0
- package/dist/src/levers.js +302 -0
- package/dist/src/levers.js.map +1 -0
- package/dist/src/live/projection.js +450 -0
- package/dist/src/live/projection.js.map +1 -0
- package/dist/src/live/publish.js +83 -0
- package/dist/src/live/publish.js.map +1 -0
- package/dist/src/live/read.js +60 -0
- package/dist/src/live/read.js.map +1 -0
- package/dist/src/livecli.js +288 -0
- package/dist/src/livecli.js.map +1 -0
- package/dist/src/loginhint.js +42 -0
- package/dist/src/loginhint.js.map +1 -0
- package/dist/src/loginrefresh/atomic.js +66 -0
- package/dist/src/loginrefresh/atomic.js.map +1 -0
- package/dist/src/loginrefresh/lock.js +93 -0
- package/dist/src/loginrefresh/lock.js.map +1 -0
- package/dist/src/loginrefresh/main.js +58 -0
- package/dist/src/loginrefresh/main.js.map +1 -0
- package/dist/src/loginrefresh/pirefresh.js +49 -0
- package/dist/src/loginrefresh/pirefresh.js.map +1 -0
- package/dist/src/loginrefresh/refresher.js +286 -0
- package/dist/src/loginrefresh/refresher.js.map +1 -0
- package/dist/src/loginrefresh/supervisor.js +253 -0
- package/dist/src/loginrefresh/supervisor.js.map +1 -0
- package/dist/src/loginrefresh/types.js +4 -0
- package/dist/src/loginrefresh/types.js.map +1 -0
- package/dist/src/memory/context.js +251 -0
- package/dist/src/memory/context.js.map +1 -0
- package/dist/src/memory/datafence.js +5 -0
- package/dist/src/memory/datafence.js.map +1 -0
- package/dist/src/memory/delivery.js +131 -0
- package/dist/src/memory/delivery.js.map +1 -0
- package/dist/src/memory/eventtags.js +81 -0
- package/dist/src/memory/eventtags.js.map +1 -0
- package/dist/src/memory/health.js +713 -0
- package/dist/src/memory/health.js.map +1 -0
- package/dist/src/memory/import.js +504 -0
- package/dist/src/memory/import.js.map +1 -0
- package/dist/src/memory/layout.js +252 -0
- package/dist/src/memory/layout.js.map +1 -0
- package/dist/src/memory/legacy-file.js +100 -0
- package/dist/src/memory/legacy-file.js.map +1 -0
- package/dist/src/memory/lessons.js +370 -0
- package/dist/src/memory/lessons.js.map +1 -0
- package/dist/src/memory/ovsession.js +449 -0
- package/dist/src/memory/ovsession.js.map +1 -0
- package/dist/src/memory/relayout.js +259 -0
- package/dist/src/memory/relayout.js.map +1 -0
- package/dist/src/memory/roundactivity.js +180 -0
- package/dist/src/memory/roundactivity.js.map +1 -0
- package/dist/src/memory/selection.js +690 -0
- package/dist/src/memory/selection.js.map +1 -0
- package/dist/src/memory/shadowstatus.js +69 -0
- package/dist/src/memory/shadowstatus.js.map +1 -0
- package/dist/src/memory/store.js +83 -0
- package/dist/src/memory/store.js.map +1 -0
- package/dist/src/memory/textidentity.js +8 -0
- package/dist/src/memory/textidentity.js.map +1 -0
- package/dist/src/metrics.js +773 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/missingconfig.js +8 -0
- package/dist/src/missingconfig.js.map +1 -0
- package/dist/src/npmverbs.js +226 -0
- package/dist/src/npmverbs.js.map +1 -0
- package/dist/src/onboard/choices.js +191 -0
- package/dist/src/onboard/choices.js.map +1 -0
- package/dist/src/onboard/engine.js +344 -0
- package/dist/src/onboard/engine.js.map +1 -0
- package/dist/src/onboard/launch.js +83 -0
- package/dist/src/onboard/launch.js.map +1 -0
- package/dist/src/onboard/steps/appslug.js +211 -0
- package/dist/src/onboard/steps/appslug.js.map +1 -0
- package/dist/src/onboard/steps/bringup.js +408 -0
- package/dist/src/onboard/steps/bringup.js.map +1 -0
- package/dist/src/onboard/steps/compose.js +343 -0
- package/dist/src/onboard/steps/compose.js.map +1 -0
- package/dist/src/onboard/steps/configdelivery.js +50 -0
- package/dist/src/onboard/steps/configdelivery.js.map +1 -0
- package/dist/src/onboard/steps/configfill.js +1148 -0
- package/dist/src/onboard/steps/configfill.js.map +1 -0
- package/dist/src/onboard/steps/deploysh.js +80 -0
- package/dist/src/onboard/steps/deploysh.js.map +1 -0
- package/dist/src/onboard/steps/embeddings.js +472 -0
- package/dist/src/onboard/steps/embeddings.js.map +1 -0
- package/dist/src/onboard/steps/escalation.js +571 -0
- package/dist/src/onboard/steps/escalation.js.map +1 -0
- package/dist/src/onboard/steps/githubapp.js +1092 -0
- package/dist/src/onboard/steps/githubapp.js.map +1 -0
- package/dist/src/onboard/steps/golive.js +506 -0
- package/dist/src/onboard/steps/golive.js.map +1 -0
- package/dist/src/onboard/steps/index.js +67 -0
- package/dist/src/onboard/steps/index.js.map +1 -0
- package/dist/src/onboard/steps/ingress.js +762 -0
- package/dist/src/onboard/steps/ingress.js.map +1 -0
- package/dist/src/onboard/steps/inventory.js +420 -0
- package/dist/src/onboard/steps/inventory.js.map +1 -0
- package/dist/src/onboard/steps/llmauth.js +893 -0
- package/dist/src/onboard/steps/llmauth.js.map +1 -0
- package/dist/src/onboard/steps/memory.js +1060 -0
- package/dist/src/onboard/steps/memory.js.map +1 -0
- package/dist/src/onboard/steps/memorykeys.js +43 -0
- package/dist/src/onboard/steps/memorykeys.js.map +1 -0
- package/dist/src/onboard/steps/preflight.js +172 -0
- package/dist/src/onboard/steps/preflight.js.map +1 -0
- package/dist/src/onboard/steps/proof.js +502 -0
- package/dist/src/onboard/steps/proof.js.map +1 -0
- package/dist/src/onboard/steps/ssh.js +300 -0
- package/dist/src/onboard/steps/ssh.js.map +1 -0
- package/dist/src/onboard/steps/topology.js +291 -0
- package/dist/src/onboard/steps/topology.js.map +1 -0
- package/dist/src/onboard/steps/transport.js +511 -0
- package/dist/src/onboard/steps/transport.js.map +1 -0
- package/dist/src/onboard/steps/verifyup.js +362 -0
- package/dist/src/onboard/steps/verifyup.js.map +1 -0
- package/dist/src/onboard/steps/vmdeploy.js +368 -0
- package/dist/src/onboard/steps/vmdeploy.js.map +1 -0
- package/dist/src/onboard/toml.js +53 -0
- package/dist/src/onboard/toml.js.map +1 -0
- package/dist/src/opencli.js +508 -0
- package/dist/src/opencli.js.map +1 -0
- package/dist/src/openpr.js +457 -0
- package/dist/src/openpr.js.map +1 -0
- package/dist/src/openviking/client.js +821 -0
- package/dist/src/openviking/client.js.map +1 -0
- package/dist/src/openviking/context.js +218 -0
- package/dist/src/openviking/context.js.map +1 -0
- package/dist/src/openviking/embedder.js +457 -0
- package/dist/src/openviking/embedder.js.map +1 -0
- package/dist/src/openviking/gapsink.js +38 -0
- package/dist/src/openviking/gapsink.js.map +1 -0
- package/dist/src/openviking/health.js +69 -0
- package/dist/src/openviking/health.js.map +1 -0
- package/dist/src/openviking/index.js +24 -0
- package/dist/src/openviking/index.js.map +1 -0
- package/dist/src/openviking/lessonfind.js +54 -0
- package/dist/src/openviking/lessonfind.js.map +1 -0
- package/dist/src/openviking/probe.js +89 -0
- package/dist/src/openviking/probe.js.map +1 -0
- package/dist/src/openviking/proc.js +95 -0
- package/dist/src/openviking/proc.js.map +1 -0
- package/dist/src/openviking/provisionreport.js +144 -0
- package/dist/src/openviking/provisionreport.js.map +1 -0
- package/dist/src/openviking/reembed.js +317 -0
- package/dist/src/openviking/reembed.js.map +1 -0
- package/dist/src/openviking/relayout.js +153 -0
- package/dist/src/openviking/relayout.js.map +1 -0
- package/dist/src/openviking/sidecar-main.js +39 -0
- package/dist/src/openviking/sidecar-main.js.map +1 -0
- package/dist/src/openviking/sidecar.js +79 -0
- package/dist/src/openviking/sidecar.js.map +1 -0
- package/dist/src/openviking/store.js +1758 -0
- package/dist/src/openviking/store.js.map +1 -0
- package/dist/src/openviking/supervisor.js +422 -0
- package/dist/src/openviking/supervisor.js.map +1 -0
- package/dist/src/openviking/types.js +5 -0
- package/dist/src/openviking/types.js.map +1 -0
- package/dist/src/operator-recovery.js +172 -0
- package/dist/src/operator-recovery.js.map +1 -0
- package/dist/src/operatormessage.js +44 -0
- package/dist/src/operatormessage.js.map +1 -0
- package/dist/src/outcomes.js +1361 -0
- package/dist/src/outcomes.js.map +1 -0
- package/dist/src/piauthcopy.js +5 -0
- package/dist/src/piauthcopy.js.map +1 -0
- package/dist/src/picli.js +45 -0
- package/dist/src/picli.js.map +1 -0
- package/dist/src/picwd.js +25 -0
- package/dist/src/picwd.js.map +1 -0
- package/dist/src/pilogin.js +35 -0
- package/dist/src/pilogin.js.map +1 -0
- package/dist/src/pingpong.js +1028 -0
- package/dist/src/pingpong.js.map +1 -0
- package/dist/src/posting-journal.js +441 -0
- package/dist/src/posting-journal.js.map +1 -0
- package/dist/src/posting-outbox.js +662 -0
- package/dist/src/posting-outbox.js.map +1 -0
- package/dist/src/posting-receipt.js +203 -0
- package/dist/src/posting-receipt.js.map +1 -0
- package/dist/src/posting.js +348 -0
- package/dist/src/posting.js.map +1 -0
- package/dist/src/postops.js +637 -0
- package/dist/src/postops.js.map +1 -0
- package/dist/src/pr-activity.js +11 -0
- package/dist/src/pr-activity.js.map +1 -0
- package/dist/src/pr-author.js +5 -0
- package/dist/src/pr-author.js.map +1 -0
- package/dist/src/pr-conversation.js +355 -0
- package/dist/src/pr-conversation.js.map +1 -0
- package/dist/src/pr-session-lifecycle.js +542 -0
- package/dist/src/pr-session-lifecycle.js.map +1 -0
- package/dist/src/preflight.js +341 -0
- package/dist/src/preflight.js.map +1 -0
- package/dist/src/priorresolve.js +275 -0
- package/dist/src/priorresolve.js.map +1 -0
- package/dist/src/qcrbin.js +180 -0
- package/dist/src/qcrbin.js.map +1 -0
- package/dist/src/recheck.js +1398 -0
- package/dist/src/recheck.js.map +1 -0
- package/dist/src/reconcile.js +820 -0
- package/dist/src/reconcile.js.map +1 -0
- package/dist/src/recordedfindings.js +15 -0
- package/dist/src/recordedfindings.js.map +1 -0
- package/dist/src/regression.js +546 -0
- package/dist/src/regression.js.map +1 -0
- package/dist/src/replay.js +598 -0
- package/dist/src/replay.js.map +1 -0
- package/dist/src/requiredpasses.js +113 -0
- package/dist/src/requiredpasses.js.map +1 -0
- package/dist/src/resumecheck.js +168 -0
- package/dist/src/resumecheck.js.map +1 -0
- package/dist/src/reviewcli.js +671 -0
- package/dist/src/reviewcli.js.map +1 -0
- package/dist/src/reviewcontext.js +22 -0
- package/dist/src/reviewcontext.js.map +1 -0
- package/dist/src/reviewdetach.js +574 -0
- package/dist/src/reviewdetach.js.map +1 -0
- package/dist/src/reviewhistory.js +284 -0
- package/dist/src/reviewhistory.js.map +1 -0
- package/dist/src/reviewhome.js +26 -0
- package/dist/src/reviewhome.js.map +1 -0
- package/dist/src/reviewmemory.js +110 -0
- package/dist/src/reviewmemory.js.map +1 -0
- package/dist/src/reviewrendercli.js +104 -0
- package/dist/src/reviewrendercli.js.map +1 -0
- package/dist/src/round-work.js +20 -0
- package/dist/src/round-work.js.map +1 -0
- package/dist/src/runhost.js +72 -0
- package/dist/src/runhost.js.map +1 -0
- package/dist/src/scanauth.js +25 -0
- package/dist/src/scanauth.js.map +1 -0
- package/dist/src/scanbox.js +846 -0
- package/dist/src/scanbox.js.map +1 -0
- package/dist/src/scancli.js +1074 -0
- package/dist/src/scancli.js.map +1 -0
- package/dist/src/scandriverlog.js +30 -0
- package/dist/src/scandriverlog.js.map +1 -0
- package/dist/src/session-bridge.js +75 -0
- package/dist/src/session-bridge.js.map +1 -0
- package/dist/src/session-command-payload.js +29 -0
- package/dist/src/session-command-payload.js.map +1 -0
- package/dist/src/session-command-supervisor.js +939 -0
- package/dist/src/session-command-supervisor.js.map +1 -0
- package/dist/src/sessionjsonl.js +85 -0
- package/dist/src/sessionjsonl.js.map +1 -0
- package/dist/src/sessions.js +541 -0
- package/dist/src/sessions.js.map +1 -0
- package/dist/src/setup/adapters.js +330 -0
- package/dist/src/setup/adapters.js.map +1 -0
- package/dist/src/setup/baselines.js +64 -0
- package/dist/src/setup/baselines.js.map +1 -0
- package/dist/src/setup/caserunner.js +554 -0
- package/dist/src/setup/caserunner.js.map +1 -0
- package/dist/src/setup/configcommit.js +358 -0
- package/dist/src/setup/configcommit.js.map +1 -0
- package/dist/src/setup/engine.js +672 -0
- package/dist/src/setup/engine.js.map +1 -0
- package/dist/src/setup/facts.js +593 -0
- package/dist/src/setup/facts.js.map +1 -0
- package/dist/src/setup/findings.js +948 -0
- package/dist/src/setup/findings.js.map +1 -0
- package/dist/src/setup/history.js +338 -0
- package/dist/src/setup/history.js.map +1 -0
- package/dist/src/setup/interview.js +185 -0
- package/dist/src/setup/interview.js.map +1 -0
- package/dist/src/setup/ledger.js +207 -0
- package/dist/src/setup/ledger.js.map +1 -0
- package/dist/src/setup/pins.js +43 -0
- package/dist/src/setup/pins.js.map +1 -0
- package/dist/src/setup/portrait.js +432 -0
- package/dist/src/setup/portrait.js.map +1 -0
- package/dist/src/setup/presentation.js +9 -0
- package/dist/src/setup/presentation.js.map +1 -0
- package/dist/src/setup/profile.js +417 -0
- package/dist/src/setup/profile.js.map +1 -0
- package/dist/src/setup/replay.js +240 -0
- package/dist/src/setup/replay.js.map +1 -0
- package/dist/src/setup/replaybuild.js +311 -0
- package/dist/src/setup/replaybuild.js.map +1 -0
- package/dist/src/setup/replayrun.js +806 -0
- package/dist/src/setup/replayrun.js.map +1 -0
- package/dist/src/setup/replaysource.js +169 -0
- package/dist/src/setup/replaysource.js.map +1 -0
- package/dist/src/setup/retune.js +333 -0
- package/dist/src/setup/retune.js.map +1 -0
- package/dist/src/setup/retunelog.js +51 -0
- package/dist/src/setup/retunelog.js.map +1 -0
- package/dist/src/setup/scan.js +725 -0
- package/dist/src/setup/scan.js.map +1 -0
- package/dist/src/setup/scanbuild.js +133 -0
- package/dist/src/setup/scanbuild.js.map +1 -0
- package/dist/src/setup/scanfacts.js +96 -0
- package/dist/src/setup/scanfacts.js.map +1 -0
- package/dist/src/setup/scanlease.js +251 -0
- package/dist/src/setup/scanlease.js.map +1 -0
- package/dist/src/setup/scanreport.js +289 -0
- package/dist/src/setup/scanreport.js.map +1 -0
- package/dist/src/setup/scanrun.js +1733 -0
- package/dist/src/setup/scanrun.js.map +1 -0
- package/dist/src/setup/scantree.js +257 -0
- package/dist/src/setup/scantree.js.map +1 -0
- package/dist/src/setup/stage2.js +617 -0
- package/dist/src/setup/stage2.js.map +1 -0
- package/dist/src/setup/stage2request.js +259 -0
- package/dist/src/setup/stage2request.js.map +1 -0
- package/dist/src/setup/survey.js +307 -0
- package/dist/src/setup/survey.js.map +1 -0
- package/dist/src/setup/surveyrun.js +549 -0
- package/dist/src/setup/surveyrun.js.map +1 -0
- package/dist/src/setup/textsniff.js +89 -0
- package/dist/src/setup/textsniff.js.map +1 -0
- package/dist/src/setup/trackersink.js +395 -0
- package/dist/src/setup/trackersink.js.map +1 -0
- package/dist/src/setup/triage.js +636 -0
- package/dist/src/setup/triage.js.map +1 -0
- package/dist/src/setup/tuning.js +585 -0
- package/dist/src/setup/tuning.js.map +1 -0
- package/dist/src/setup/unitcut.js +437 -0
- package/dist/src/setup/unitcut.js.map +1 -0
- package/dist/src/singleflight.js +72 -0
- package/dist/src/singleflight.js.map +1 -0
- package/dist/src/slack/announce.js +725 -0
- package/dist/src/slack/announce.js.map +1 -0
- package/dist/src/slack/api.js +227 -0
- package/dist/src/slack/api.js.map +1 -0
- package/dist/src/slack/messages.js +158 -0
- package/dist/src/slack/messages.js.map +1 -0
- package/dist/src/slack/origin.js +550 -0
- package/dist/src/slack/origin.js.map +1 -0
- package/dist/src/slack/policy.js +225 -0
- package/dist/src/slack/policy.js.map +1 -0
- package/dist/src/slack/reply.js +153 -0
- package/dist/src/slack/reply.js.map +1 -0
- package/dist/src/slack/router.js +189 -0
- package/dist/src/slack/router.js.map +1 -0
- package/dist/src/slack/socket.js +323 -0
- package/dist/src/slack/socket.js.map +1 -0
- package/dist/src/slack/types.js +11 -0
- package/dist/src/slack/types.js.map +1 -0
- package/dist/src/sqlitehint.js +30 -0
- package/dist/src/sqlitehint.js.map +1 -0
- package/dist/src/ssh-observation.js +25 -0
- package/dist/src/ssh-observation.js.map +1 -0
- package/dist/src/state.js +5869 -0
- package/dist/src/state.js.map +1 -0
- package/dist/src/statemachine.js +220 -0
- package/dist/src/statemachine.js.map +1 -0
- package/dist/src/stubs.js +52 -0
- package/dist/src/stubs.js.map +1 -0
- package/dist/src/takeover.js +506 -0
- package/dist/src/takeover.js.map +1 -0
- package/dist/src/takeoverpi.js +249 -0
- package/dist/src/takeoverpi.js.map +1 -0
- package/dist/src/terminal-failure.js +26 -0
- package/dist/src/terminal-failure.js.map +1 -0
- package/dist/src/thread-resolution-refusal.js +4 -0
- package/dist/src/thread-resolution-refusal.js.map +1 -0
- package/dist/src/tmux.js +126 -0
- package/dist/src/tmux.js.map +1 -0
- package/dist/src/trackerid.js +43 -0
- package/dist/src/trackerid.js.map +1 -0
- package/dist/src/transcriptindex.js +512 -0
- package/dist/src/transcriptindex.js.map +1 -0
- package/dist/src/tui/actions.js +404 -0
- package/dist/src/tui/actions.js.map +1 -0
- package/dist/src/tui/alerts.js +523 -0
- package/dist/src/tui/alerts.js.map +1 -0
- package/dist/src/tui/app.js +1835 -0
- package/dist/src/tui/app.js.map +1 -0
- package/dist/src/tui/archiveops.js +164 -0
- package/dist/src/tui/archiveops.js.map +1 -0
- package/dist/src/tui/autofile.js +191 -0
- package/dist/src/tui/autofile.js.map +1 -0
- package/dist/src/tui/board.js +1143 -0
- package/dist/src/tui/board.js.map +1 -0
- package/dist/src/tui/candidates.js +699 -0
- package/dist/src/tui/candidates.js.map +1 -0
- package/dist/src/tui/cellwidth.js +151 -0
- package/dist/src/tui/cellwidth.js.map +1 -0
- package/dist/src/tui/changelog-store.js +404 -0
- package/dist/src/tui/changelog-store.js.map +1 -0
- package/dist/src/tui/chord.js +26 -0
- package/dist/src/tui/chord.js.map +1 -0
- package/dist/src/tui/clipboard.js +81 -0
- package/dist/src/tui/clipboard.js.map +1 -0
- package/dist/src/tui/cmdbar.js +253 -0
- package/dist/src/tui/cmdbar.js.map +1 -0
- package/dist/src/tui/companion.js +1275 -0
- package/dist/src/tui/companion.js.map +1 -0
- package/dist/src/tui/companionplan.js +200 -0
- package/dist/src/tui/companionplan.js.map +1 -0
- package/dist/src/tui/companiontab.js +61 -0
- package/dist/src/tui/companiontab.js.map +1 -0
- package/dist/src/tui/confighome.js +105 -0
- package/dist/src/tui/confighome.js.map +1 -0
- package/dist/src/tui/connect.js +44 -0
- package/dist/src/tui/connect.js.map +1 -0
- package/dist/src/tui/deploy-ceremony.js +75 -0
- package/dist/src/tui/deploy-ceremony.js.map +1 -0
- package/dist/src/tui/deploy-drain.js +93 -0
- package/dist/src/tui/deploy-drain.js.map +1 -0
- package/dist/src/tui/deploy-process.js +234 -0
- package/dist/src/tui/deploy-process.js.map +1 -0
- package/dist/src/tui/deploytab.js +1263 -0
- package/dist/src/tui/deploytab.js.map +1 -0
- package/dist/src/tui/design.js +111 -0
- package/dist/src/tui/design.js.map +1 -0
- package/dist/src/tui/digesttab.js +148 -0
- package/dist/src/tui/digesttab.js.map +1 -0
- package/dist/src/tui/emptystate.js +32 -0
- package/dist/src/tui/emptystate.js.map +1 -0
- package/dist/src/tui/evidence.js +790 -0
- package/dist/src/tui/evidence.js.map +1 -0
- package/dist/src/tui/feed.js +415 -0
- package/dist/src/tui/feed.js.map +1 -0
- package/dist/src/tui/feedbacktab.js +907 -0
- package/dist/src/tui/feedbacktab.js.map +1 -0
- package/dist/src/tui/filters.js +72 -0
- package/dist/src/tui/filters.js.map +1 -0
- package/dist/src/tui/ghread.js +272 -0
- package/dist/src/tui/ghread.js.map +1 -0
- package/dist/src/tui/historypull.js +61 -0
- package/dist/src/tui/historypull.js.map +1 -0
- package/dist/src/tui/inboxpull.js +197 -0
- package/dist/src/tui/inboxpull.js.map +1 -0
- package/dist/src/tui/index.js +1425 -0
- package/dist/src/tui/index.js.map +1 -0
- package/dist/src/tui/issuesink.js +206 -0
- package/dist/src/tui/issuesink.js.map +1 -0
- package/dist/src/tui/jsonfile.js +32 -0
- package/dist/src/tui/jsonfile.js.map +1 -0
- package/dist/src/tui/keys.js +97 -0
- package/dist/src/tui/keys.js.map +1 -0
- package/dist/src/tui/layout.js +70 -0
- package/dist/src/tui/layout.js.map +1 -0
- package/dist/src/tui/learning.js +469 -0
- package/dist/src/tui/learning.js.map +1 -0
- package/dist/src/tui/lessonswitch.js +103 -0
- package/dist/src/tui/lessonswitch.js.map +1 -0
- package/dist/src/tui/livecontrol.js +167 -0
- package/dist/src/tui/livecontrol.js.map +1 -0
- package/dist/src/tui/memforward.js +310 -0
- package/dist/src/tui/memforward.js.map +1 -0
- package/dist/src/tui/memincident.js +287 -0
- package/dist/src/tui/memincident.js.map +1 -0
- package/dist/src/tui/memory.js +485 -0
- package/dist/src/tui/memory.js.map +1 -0
- package/dist/src/tui/memtab.js +513 -0
- package/dist/src/tui/memtab.js.map +1 -0
- package/dist/src/tui/metricstab.js +979 -0
- package/dist/src/tui/metricstab.js.map +1 -0
- package/dist/src/tui/model.js +104 -0
- package/dist/src/tui/model.js.map +1 -0
- package/dist/src/tui/mouse.js +83 -0
- package/dist/src/tui/mouse.js.map +1 -0
- package/dist/src/tui/msg.js +196 -0
- package/dist/src/tui/msg.js.map +1 -0
- package/dist/src/tui/nativecompanion.js +321 -0
- package/dist/src/tui/nativecompanion.js.map +1 -0
- package/dist/src/tui/openurl.js +17 -0
- package/dist/src/tui/openurl.js.map +1 -0
- package/dist/src/tui/paint.js +501 -0
- package/dist/src/tui/paint.js.map +1 -0
- package/dist/src/tui/panes.js +74 -0
- package/dist/src/tui/panes.js.map +1 -0
- package/dist/src/tui/pipane.js +166 -0
- package/dist/src/tui/pipane.js.map +1 -0
- package/dist/src/tui/poll-hooks.js +11 -0
- package/dist/src/tui/poll-hooks.js.map +1 -0
- package/dist/src/tui/poll.js +113 -0
- package/dist/src/tui/poll.js.map +1 -0
- package/dist/src/tui/proposals.js +715 -0
- package/dist/src/tui/proposals.js.map +1 -0
- package/dist/src/tui/prpause.js +132 -0
- package/dist/src/tui/prpause.js.map +1 -0
- package/dist/src/tui/reload.js +351 -0
- package/dist/src/tui/reload.js.map +1 -0
- package/dist/src/tui/remote.js +312 -0
- package/dist/src/tui/remote.js.map +1 -0
- package/dist/src/tui/rollover.js +767 -0
- package/dist/src/tui/rollover.js.map +1 -0
- package/dist/src/tui/scantab.js +1053 -0
- package/dist/src/tui/scantab.js.map +1 -0
- package/dist/src/tui/setupentry.js +81 -0
- package/dist/src/tui/setupentry.js.map +1 -0
- package/dist/src/tui/sidebar.js +602 -0
- package/dist/src/tui/sidebar.js.map +1 -0
- package/dist/src/tui/sshtriage.js +393 -0
- package/dist/src/tui/sshtriage.js.map +1 -0
- package/dist/src/tui/startup.js +172 -0
- package/dist/src/tui/startup.js.map +1 -0
- package/dist/src/tui/tabs.js +41 -0
- package/dist/src/tui/tabs.js.map +1 -0
- package/dist/src/tui/termmirror.js +217 -0
- package/dist/src/tui/termmirror.js.map +1 -0
- package/dist/src/tui/theme.js +95 -0
- package/dist/src/tui/theme.js.map +1 -0
- package/dist/src/tui/ticketstab.js +224 -0
- package/dist/src/tui/ticketstab.js.map +1 -0
- package/dist/src/tui/tmuxsocket.js +101 -0
- package/dist/src/tui/tmuxsocket.js.map +1 -0
- package/dist/src/tui/trackertickets.js +77 -0
- package/dist/src/tui/trackertickets.js.map +1 -0
- package/dist/src/tui/unwedge.js +245 -0
- package/dist/src/tui/unwedge.js.map +1 -0
- package/dist/src/tui/viewer.js +479 -0
- package/dist/src/tui/viewer.js.map +1 -0
- package/dist/src/tui/viewerinput.js +125 -0
- package/dist/src/tui/viewerinput.js.map +1 -0
- package/dist/src/updatenotice.js +143 -0
- package/dist/src/updatenotice.js.map +1 -0
- package/dist/src/usage.js +1007 -0
- package/dist/src/usage.js.map +1 -0
- package/dist/src/verdicts.js +3848 -0
- package/dist/src/verdicts.js.map +1 -0
- package/dist/src/version.js +58 -0
- package/dist/src/version.js.map +1 -0
- package/dist/src/wakes.js +411 -0
- package/dist/src/wakes.js.map +1 -0
- package/dist/src/webhook.js +725 -0
- package/dist/src/webhook.js.map +1 -0
- package/dist/src/webhookheal.js +238 -0
- package/dist/src/webhookheal.js.map +1 -0
- package/dist/src/wire.js +1801 -0
- package/dist/src/wire.js.map +1 -0
- package/dist/src/worker-session-host.js +531 -0
- package/dist/src/worker-session-host.js.map +1 -0
- package/dist/src/workerbreaker.js +112 -0
- package/dist/src/workerbreaker.js.map +1 -0
- package/dist/src/workercontrol.js +49 -0
- package/dist/src/workercontrol.js.map +1 -0
- package/dist/src/workerlease.js +351 -0
- package/dist/src/workerlease.js.map +1 -0
- package/dist/src/workerliveness.js +84 -0
- package/dist/src/workerliveness.js.map +1 -0
- package/dist/src/workerlog.js +65 -0
- package/dist/src/workerlog.js.map +1 -0
- package/dist/src/workerruntime.js +10 -0
- package/dist/src/workerruntime.js.map +1 -0
- package/dist/src/workersupervisor.js +1206 -0
- package/dist/src/workersupervisor.js.map +1 -0
- package/dist/src/workerusage.js +23 -0
- package/dist/src/workerusage.js.map +1 -0
- package/dist/src/workerworld.js +332 -0
- package/dist/src/workerworld.js.map +1 -0
- package/dist/src/worktrees.js +984 -0
- package/dist/src/worktrees.js.map +1 -0
- package/docker/Dockerfile +284 -0
- package/docker/Dockerfile.dockerignore +35 -0
- package/docker/README.md +221 -0
- package/docker/companion/Dockerfile +139 -0
- package/docker/companion/agents/evidence.md +34 -0
- package/docker/companion/agents/explore.md +26 -0
- package/docker/companion/agents/pass-survey.md +49 -0
- package/docker/companion/agents/study.md +26 -0
- package/docker/companion/entrypoint.sh +343 -0
- package/docker/companion/memory-health.mjs +269 -0
- package/docker/entrypoint.sh +782 -0
- package/docker/memory/Dockerfile +191 -0
- package/docker/memory/Dockerfile.dockerignore +20 -0
- package/docker/memory/README.md +60 -0
- package/docker/memory/entrypoint.sh +163 -0
- package/docker/setid/qcr-setid.c +109 -0
- package/docker/tunnel/Dockerfile.cloudflared +51 -0
- package/docker/tunnel/Dockerfile.ngrok +40 -0
- package/docker/tunnel/sidecar.mjs +411 -0
- package/docker/vm/tmux.conf +26 -0
- package/docker-compose.yml +348 -0
- package/extensions/cli/bash-guard-ambient.ts +71 -0
- package/extensions/cli/bash-guard.ts +12 -0
- package/extensions/cli/companion-guard.ts +8 -0
- package/extensions/cli/debug-round.ts +9 -0
- package/extensions/cli/inject-bridge.ts +8 -0
- package/extensions/cli/ledger-pin.ts +13 -0
- package/extensions/cli/lens.ts +22 -0
- package/extensions/cli/muted-theme.ts +9 -0
- package/extensions/cli/onboarding.ts +8 -0
- package/extensions/cli/setup.ts +8 -0
- package/extensions/cli/tui-view.ts +8 -0
- package/extensions/companion-guard.ts +411 -0
- package/extensions/debug-round.ts +281 -0
- package/extensions/inject-bridge.ts +630 -0
- package/extensions/inline-bash.ts +102 -0
- package/extensions/muted-theme.json +68 -0
- package/extensions/muted-theme.ts +23 -0
- package/extensions/onboarding.ts +233 -0
- package/extensions/setup-replay.ts +336 -0
- package/extensions/setup-scan.ts +1236 -0
- package/extensions/setup-triage.ts +190 -0
- package/extensions/setup.ts +1428 -0
- package/extensions/tui-view.ts +489 -0
- package/extensions/vendor/openviking-pi/LICENSE +201 -0
- package/extensions/vendor/openviking-pi/NOTICE +68 -0
- package/extensions/vendor/openviking-pi/README.md +550 -0
- package/extensions/vendor/openviking-pi/client.ts +588 -0
- package/extensions/vendor/openviking-pi/config.json +28 -0
- package/extensions/vendor/openviking-pi/config.ts +271 -0
- package/extensions/vendor/openviking-pi/index.ts +523 -0
- package/extensions/vendor/openviking-pi/lib/capture-adapter.d.mts +10 -0
- package/extensions/vendor/openviking-pi/lib/capture-adapter.mjs +88 -0
- package/extensions/vendor/openviking-pi/lib/takeover-core.d.mts +80 -0
- package/extensions/vendor/openviking-pi/lib/takeover-core.mjs +406 -0
- package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.d.mts +1 -0
- package/extensions/vendor/openviking-pi/lib/uri-guard-adapter.mjs +42 -0
- package/extensions/vendor/openviking-pi/patches/0000-vendoring-and-build-conformance.patch +726 -0
- package/extensions/vendor/openviking-pi/patches/0001-remove-session-before-compact-handler.patch +101 -0
- package/extensions/vendor/openviking-pi/patches/0002-no-ambient-work-in-subagent-leaves.patch +202 -0
- package/extensions/vendor/openviking-pi/patches/0003-never-auto-create-openviking-sessions.patch +120 -0
- package/extensions/vendor/openviking-pi/patches/0004-viking-write-durable-batch-write.patch +521 -0
- package/extensions/vendor/openviking-pi/patches/0005-second-memory-namespace.patch +786 -0
- package/extensions/vendor/openviking-pi/patches/0006-writes-that-stick-and-honest-errors.patch +996 -0
- package/extensions/vendor/openviking-pi/patches/0007-bounded-recall-no-commit.patch +794 -0
- package/extensions/vendor/openviking-pi/patches/0008-pr-derived-recall.patch +379 -0
- package/extensions/vendor/openviking-pi/patches/0009-pr-session-tools-in-round-areas.patch +375 -0
- package/extensions/vendor/openviking-pi/patches/0010-typed-lessons.patch +448 -0
- package/extensions/vendor/openviking-pi/patches/0011-review-session-memory-boundary.patch +382 -0
- package/extensions/vendor/openviking-pi/patches/0012-typecheck-against-the-real-pi.patch +129 -0
- package/extensions/vendor/openviking-pi/patches/0013-createopenviking-factory.patch +1168 -0
- package/extensions/vendor/openviking-pi/qcr-hint.ts +313 -0
- package/extensions/vendor/openviking-pi/qcr-honest.ts +183 -0
- package/extensions/vendor/openviking-pi/qcr-hooks.ts +87 -0
- package/extensions/vendor/openviking-pi/qcr-leaf.ts +78 -0
- package/extensions/vendor/openviking-pi/qcr-lesson.ts +231 -0
- package/extensions/vendor/openviking-pi/qcr-namespaces.ts +198 -0
- package/extensions/vendor/openviking-pi/qcr-recall.ts +288 -0
- package/extensions/vendor/openviking-pi/qcr-shim.ts +142 -0
- package/extensions/vendor/openviking-pi/qcr-write.ts +427 -0
- package/extensions/vendor/openviking-pi/recall.ts +149 -0
- package/extensions/vendor/openviking-pi/shared/capture-utils.d.mts +9 -0
- package/extensions/vendor/openviking-pi/shared/capture-utils.mjs +515 -0
- package/extensions/vendor/openviking-pi/shared/credentials.d.mts +14 -0
- package/extensions/vendor/openviking-pi/shared/credentials.mjs +228 -0
- package/extensions/vendor/openviking-pi/shared/pending-queue.d.mts +19 -0
- package/extensions/vendor/openviking-pi/shared/pending-queue.mjs +458 -0
- package/extensions/vendor/openviking-pi/shared/profile-inject.d.mts +17 -0
- package/extensions/vendor/openviking-pi/shared/profile-inject.mjs +294 -0
- package/extensions/vendor/openviking-pi/shared/recall-compress-core.mjs +195 -0
- package/extensions/vendor/openviking-pi/shared/recall-core.d.mts +13 -0
- package/extensions/vendor/openviking-pi/shared/recall-core.mjs +609 -0
- package/extensions/vendor/openviking-pi/shared/retryable.mjs +9 -0
- package/extensions/vendor/openviking-pi/shared/session-model.d.mts +3 -0
- package/extensions/vendor/openviking-pi/shared/session-model.mjs +57 -0
- package/extensions/vendor/openviking-pi/shared/uri-guard.mjs +56 -0
- package/extensions/vendor/openviking-pi/shared/workspace-peer.d.mts +5 -0
- package/extensions/vendor/openviking-pi/shared/workspace-peer.mjs +16 -0
- package/extensions/vendor/openviking-pi/sync.ts +163 -0
- package/extensions/vendor/openviking-pi/takeover.ts +36 -0
- package/extensions/vendor/openviking-pi/tools.ts +479 -0
- package/extensions/vendor/openviking-pi/upstream.json +48 -0
- package/package.json +138 -4
- package/profiles/default/README.md +21 -0
- package/profiles/default/addenda/.gitkeep +0 -0
- package/profiles/default/profile.toml +17 -0
- package/profiles/example-django/README.md +21 -0
- package/profiles/example-django/addenda/10-migration-discipline.md +13 -0
- package/profiles/example-django/addenda/20-new-column-nullability.md +12 -0
- package/profiles/example-django/addenda/30-test-doctrine.md +12 -0
- package/profiles/example-django/addenda/40-orm-usage.md +19 -0
- package/profiles/example-django/addenda/50-declared-shape.md +10 -0
- package/profiles/example-django/addenda/60-config-placement.md +14 -0
- package/profiles/example-django/heuristics.toml +24 -0
- package/profiles/example-django/profile.toml +9 -0
- package/profiles/fast/README.md +24 -0
- package/profiles/fast/profile.toml +59 -0
- package/profiles/minimal/README.md +17 -0
- package/profiles/minimal/addenda/.gitkeep +0 -0
- package/profiles/minimal/profile.toml +8 -0
- package/profiles/snappy/README.md +24 -0
- package/profiles/snappy/addenda/10-race-as-question.md +6 -0
- package/profiles/snappy/profile.toml +46 -0
- package/prompts/companion-day-open.md +46 -0
- package/prompts/companion-first-run.md +104 -0
- package/prompts/companion.md +821 -0
- package/prompts/conversation-system.md +117 -0
- package/prompts/eod-sweep.md +120 -0
- package/prompts/onboarding.md +74 -0
- package/prompts/pass-common.md +52 -0
- package/prompts/pass-quality-common.md +22 -0
- package/prompts/round-first.md +874 -0
- package/prompts/round-follow-up.md +991 -0
- package/prompts/round-re-review.md +889 -0
- package/prompts/round-recheck.md +196 -0
- package/prompts/round-staleness.md +856 -0
- package/schemas/review-result.v1.json +391 -0
- package/schemas/scan-result.v1.json +421 -0
- package/schemas/version.v1.json +57 -0
- package/scripts/approve-pr.sh +16 -0
- package/scripts/build-stamp.mjs +67 -0
- package/scripts/commit-verdict.sh +155 -0
- package/scripts/companion-e2e.sh +250 -0
- package/scripts/companion-memory-forward.mjs +1966 -0
- package/scripts/config-fingerprint.sh +28 -0
- package/scripts/deploy-manifest.mjs +141 -0
- package/scripts/deploy.sh +1435 -0
- package/scripts/directory-lock.mjs +193 -0
- package/scripts/heartbeat-fresh.mjs +54 -0
- package/scripts/install-locator.sh +328 -0
- package/scripts/install-wrapper.sh +76 -0
- package/scripts/memory-search-check.mjs +98 -0
- package/scripts/mint-token.sh +212 -0
- package/scripts/openviking-embedder.py +392 -0
- package/scripts/openviking-ov-conf.mjs +161 -0
- package/scripts/openviking-provision.mjs +1122 -0
- package/scripts/openviking-reembed.mjs +1154 -0
- package/scripts/post-review.sh +16 -0
- package/scripts/pr-checks.sh +256 -0
- package/scripts/pr-context.py +174 -0
- package/scripts/pr-context.sh +63 -0
- package/scripts/pr-self.sh +144 -0
- package/scripts/pr-threads.sh +145 -0
- package/scripts/qcr +15 -0
- package/scripts/qcr-host.sh +769 -0
- package/scripts/render-review.sh +24 -0
- package/scripts/reply-thread.sh +16 -0
- package/scripts/required-passes.py +112 -0
- package/scripts/smoke-companion.sh +211 -0
- package/scripts/tui-deploy-runner.mjs +61 -0
- package/scripts/verify-dist.mjs +201 -0
- package/scripts/vm-ghcr-login.sh +188 -0
- package/seeds/agents/pass-baseline.md +61 -0
- package/seeds/agents/pass-contracts.md +30 -0
- package/seeds/agents/pass-data-safety.md +54 -0
- package/seeds/agents/pass-delivery.md +37 -0
- package/seeds/agents/pass-prod-risk.md +24 -0
- package/seeds/agents/pass-security.md +31 -0
- package/seeds/agents/pass-statelessness.md +27 -0
- package/seeds/agents/pass-ui.md +23 -0
- package/seeds/agents/pass-validate.md +50 -0
- package/seeds/prompts/conversation-system.md +117 -0
- package/seeds/prompts/eod-sweep.md +120 -0
- package/seeds/prompts/pass-common.md +52 -0
- package/skills/companion/adjudicate/SKILL.md +247 -0
- package/skills/companion/evidence/SKILL.md +150 -0
- package/skills/companion/land/SKILL.md +200 -0
- package/skills/companion/replay/SKILL.md +138 -0
- package/skills/companion/setup/SKILL.md +167 -0
- package/skills/companion/survey/SKILL.md +160 -0
- package/skills/selfimprove/README.md +34 -0
- package/skills/selfimprove/SKILL.md +127 -0
- package/skills/selfimprove/agents/openai.yaml +2 -0
- package/skills/selfimprove/commands/selfimprove.md +6 -0
- package/skills/selfimprove/references/fix-loop.md +49 -0
- package/skills/selfimprove/references/ledger.md +20 -0
- package/skills/selfimprove/references/setup.md +40 -0
- package/src/anomalies.ts +566 -0
- package/src/answerworker.ts +251 -0
- package/src/appstamp.ts +65 -0
- package/src/archive/admission.ts +3 -0
- package/src/archive/archivedb.ts +548 -0
- package/src/archive/archiver.ts +1963 -0
- package/src/archive/archivewrite.ts +279 -0
- package/src/archive/bundle.ts +333 -0
- package/src/archive/dbmove.ts +911 -0
- package/src/archive/duplicatecounts.ts +98 -0
- package/src/archive/eligibility.ts +181 -0
- package/src/archive/extract.ts +342 -0
- package/src/archive/fsutil.ts +415 -0
- package/src/archive/gzfile.ts +370 -0
- package/src/archive/kinds.ts +21 -0
- package/src/archive/livecheckpoint.ts +217 -0
- package/src/archive/liveretention.ts +180 -0
- package/src/archive/manifest.ts +519 -0
- package/src/archive/overseer.ts +336 -0
- package/src/archive/piglobal.ts +174 -0
- package/src/archive/plan.ts +612 -0
- package/src/archive/prarchive.ts +984 -0
- package/src/archive/prfiles.ts +406 -0
- package/src/archive/report.ts +252 -0
- package/src/archive/restore.ts +330 -0
- package/src/archive/rows.ts +187 -0
- package/src/archive/seal.ts +630 -0
- package/src/archive/status.ts +719 -0
- package/src/archive/storepass.ts +581 -0
- package/src/backfill.ts +362 -0
- package/src/bench/cost.ts +113 -0
- package/src/bench/exec.ts +90 -0
- package/src/bench/values.ts +13 -0
- package/src/botcontrol.ts +176 -0
- package/src/botworker.ts +953 -0
- package/src/capture.ts +321 -0
- package/src/cases.ts +1789 -0
- package/src/channelfs.ts +26 -0
- package/src/checklist.ts +506 -0
- package/src/ciretry.ts +141 -0
- package/src/cli.ts +2271 -0
- package/src/cliops.ts +384 -0
- package/src/clonedir.ts +15 -0
- package/src/commandeffects.ts +57 -0
- package/src/commands.ts +1678 -0
- package/src/companioninbox.ts +239 -0
- package/src/compare.ts +957 -0
- package/src/config.ts +2050 -0
- package/src/configcheck.ts +133 -0
- package/src/coreext.ts +47 -0
- package/src/daemon.ts +1302 -0
- package/src/debuground.ts +927 -0
- package/src/debugroundpi.ts +262 -0
- package/src/diagnostics.ts +14 -0
- package/src/digest.ts +183 -0
- package/src/dispatch.ts +2250 -0
- package/src/engine/answerguard.ts +27 -0
- package/src/engine/botsdk.ts +336 -0
- package/src/engine/caserunner-sdk.ts +423 -0
- package/src/engine/debugpi.ts +235 -0
- package/src/eod.ts +669 -0
- package/src/eodpinwatch.ts +556 -0
- package/src/escalation.ts +1253 -0
- package/src/eventloop.ts +1045 -0
- package/src/execboundary.ts +633 -0
- package/src/feedback.ts +1162 -0
- package/src/findingscheck.ts +298 -0
- package/src/fsdenied.ts +24 -0
- package/src/ghread.ts +242 -0
- package/src/github.ts +1497 -0
- package/src/homes.ts +175 -0
- package/src/hostroute.ts +53 -0
- package/src/improvements.ts +787 -0
- package/src/install.ts +1103 -0
- package/src/installkind.ts +50 -0
- package/src/ipc/capability.ts +333 -0
- package/src/ipc/client.ts +269 -0
- package/src/ipc/control.ts +90 -0
- package/src/ipc/ghreadshim.ts +94 -0
- package/src/ipc/launcher.ts +65 -0
- package/src/ipc/permits.ts +362 -0
- package/src/ipc/postshim.ts +164 -0
- package/src/ipc/protocol.ts +342 -0
- package/src/ipc/server.ts +371 -0
- package/src/ipc/workerspec.ts +218 -0
- package/src/learner/learner.ts +1655 -0
- package/src/learner/miner.ts +1290 -0
- package/src/learner/packet.ts +340 -0
- package/src/learner/receipt.ts +168 -0
- package/src/learner/status.ts +107 -0
- package/src/ledgercheck.ts +157 -0
- package/src/lessonledger.ts +703 -0
- package/src/lessonselect.ts +888 -0
- package/src/lessonshadow.ts +810 -0
- package/src/levers.ts +393 -0
- package/src/live/projection.ts +491 -0
- package/src/live/publish.ts +92 -0
- package/src/live/read.ts +86 -0
- package/src/livecli.ts +336 -0
- package/src/loginhint.ts +56 -0
- package/src/loginrefresh/atomic.ts +76 -0
- package/src/loginrefresh/lock.ts +104 -0
- package/src/loginrefresh/main.ts +59 -0
- package/src/loginrefresh/pirefresh.ts +57 -0
- package/src/loginrefresh/refresher.ts +326 -0
- package/src/loginrefresh/supervisor.ts +273 -0
- package/src/loginrefresh/types.ts +35 -0
- package/src/memory/context.ts +385 -0
- package/src/memory/datafence.ts +9 -0
- package/src/memory/delivery.ts +171 -0
- package/src/memory/eventtags.ts +80 -0
- package/src/memory/health.ts +953 -0
- package/src/memory/import.ts +664 -0
- package/src/memory/layout.ts +261 -0
- package/src/memory/legacy-file.ts +104 -0
- package/src/memory/lessons.ts +447 -0
- package/src/memory/ovsession.ts +601 -0
- package/src/memory/relayout.ts +335 -0
- package/src/memory/roundactivity.ts +209 -0
- package/src/memory/selection.ts +989 -0
- package/src/memory/shadowstatus.ts +125 -0
- package/src/memory/store.ts +275 -0
- package/src/memory/textidentity.ts +8 -0
- package/src/metrics.ts +1056 -0
- package/src/missingconfig.ts +7 -0
- package/src/npmverbs.ts +264 -0
- package/src/onboard/choices.ts +222 -0
- package/src/onboard/engine.ts +518 -0
- package/src/onboard/launch.ts +115 -0
- package/src/onboard/steps/appslug.ts +265 -0
- package/src/onboard/steps/bringup.ts +482 -0
- package/src/onboard/steps/compose.ts +459 -0
- package/src/onboard/steps/configdelivery.ts +58 -0
- package/src/onboard/steps/configfill.ts +1352 -0
- package/src/onboard/steps/deploysh.ts +105 -0
- package/src/onboard/steps/embeddings.ts +550 -0
- package/src/onboard/steps/escalation.ts +640 -0
- package/src/onboard/steps/githubapp.ts +1414 -0
- package/src/onboard/steps/golive.ts +577 -0
- package/src/onboard/steps/index.ts +71 -0
- package/src/onboard/steps/ingress.ts +907 -0
- package/src/onboard/steps/inventory.ts +526 -0
- package/src/onboard/steps/llmauth.ts +1095 -0
- package/src/onboard/steps/memory.ts +1290 -0
- package/src/onboard/steps/memorykeys.ts +85 -0
- package/src/onboard/steps/preflight.ts +191 -0
- package/src/onboard/steps/proof.ts +624 -0
- package/src/onboard/steps/ssh.ts +377 -0
- package/src/onboard/steps/topology.ts +337 -0
- package/src/onboard/steps/transport.ts +665 -0
- package/src/onboard/steps/verifyup.ts +448 -0
- package/src/onboard/steps/vmdeploy.ts +442 -0
- package/src/onboard/toml.ts +50 -0
- package/src/opencli.ts +591 -0
- package/src/openpr.ts +568 -0
- package/src/openviking/client.ts +1131 -0
- package/src/openviking/context.ts +263 -0
- package/src/openviking/embedder.ts +516 -0
- package/src/openviking/gapsink.ts +63 -0
- package/src/openviking/health.ts +83 -0
- package/src/openviking/index.ts +119 -0
- package/src/openviking/lessonfind.ts +92 -0
- package/src/openviking/probe.ts +129 -0
- package/src/openviking/proc.ts +110 -0
- package/src/openviking/provisionreport.ts +160 -0
- package/src/openviking/reembed.ts +412 -0
- package/src/openviking/relayout.ts +177 -0
- package/src/openviking/sidecar-main.ts +38 -0
- package/src/openviking/sidecar.ts +106 -0
- package/src/openviking/store.ts +2025 -0
- package/src/openviking/supervisor.ts +474 -0
- package/src/openviking/types.ts +174 -0
- package/src/operator-recovery.ts +237 -0
- package/src/operatormessage.ts +52 -0
- package/src/outcomes.ts +1670 -0
- package/src/piauthcopy.ts +12 -0
- package/src/picli.ts +49 -0
- package/src/picwd.ts +25 -0
- package/src/pilogin.ts +37 -0
- package/src/pingpong.ts +1339 -0
- package/src/posting-journal.ts +549 -0
- package/src/posting-outbox.ts +802 -0
- package/src/posting-receipt.ts +324 -0
- package/src/posting.ts +603 -0
- package/src/postops.ts +832 -0
- package/src/pr-activity.ts +20 -0
- package/src/pr-author.ts +6 -0
- package/src/pr-conversation.ts +432 -0
- package/src/pr-session-lifecycle.ts +631 -0
- package/src/preflight.ts +391 -0
- package/src/priorresolve.ts +343 -0
- package/src/qcrbin.ts +186 -0
- package/src/recheck.ts +1775 -0
- package/src/reconcile.ts +1030 -0
- package/src/recordedfindings.ts +27 -0
- package/src/regression.ts +833 -0
- package/src/replay.ts +816 -0
- package/src/requiredpasses.ts +148 -0
- package/src/resumecheck.ts +246 -0
- package/src/reviewcli.ts +787 -0
- package/src/reviewcontext.ts +35 -0
- package/src/reviewdetach.ts +734 -0
- package/src/reviewhistory.ts +427 -0
- package/src/reviewhome.ts +36 -0
- package/src/reviewmemory.ts +133 -0
- package/src/reviewrendercli.ts +139 -0
- package/src/round-work.ts +42 -0
- package/src/runhost.ts +108 -0
- package/src/scanauth.ts +36 -0
- package/src/scanbox.ts +1081 -0
- package/src/scancli.ts +1296 -0
- package/src/scandriverlog.ts +32 -0
- package/src/session-bridge.ts +139 -0
- package/src/session-command-payload.ts +35 -0
- package/src/session-command-supervisor.ts +1142 -0
- package/src/sessionjsonl.ts +88 -0
- package/src/sessions.ts +659 -0
- package/src/setup/adapters.ts +335 -0
- package/src/setup/baselines.ts +110 -0
- package/src/setup/caserunner.ts +611 -0
- package/src/setup/configcommit.ts +443 -0
- package/src/setup/engine.ts +1001 -0
- package/src/setup/facts.ts +627 -0
- package/src/setup/findings.ts +1264 -0
- package/src/setup/history.ts +443 -0
- package/src/setup/interview.ts +243 -0
- package/src/setup/ledger.ts +324 -0
- package/src/setup/pins.ts +66 -0
- package/src/setup/portrait.ts +635 -0
- package/src/setup/presentation.ts +18 -0
- package/src/setup/profile.ts +508 -0
- package/src/setup/replay.ts +370 -0
- package/src/setup/replaybuild.ts +392 -0
- package/src/setup/replayrun.ts +1096 -0
- package/src/setup/replaysource.ts +198 -0
- package/src/setup/retune.ts +415 -0
- package/src/setup/retunelog.ts +95 -0
- package/src/setup/scan.ts +1033 -0
- package/src/setup/scanbuild.ts +168 -0
- package/src/setup/scanfacts.ts +107 -0
- package/src/setup/scanlease.ts +297 -0
- package/src/setup/scanreport.ts +373 -0
- package/src/setup/scanrun.ts +2268 -0
- package/src/setup/scantree.ts +259 -0
- package/src/setup/stage2.ts +926 -0
- package/src/setup/stage2request.ts +347 -0
- package/src/setup/survey.ts +458 -0
- package/src/setup/surveyrun.ts +758 -0
- package/src/setup/textsniff.ts +95 -0
- package/src/setup/trackersink.ts +433 -0
- package/src/setup/triage.ts +768 -0
- package/src/setup/tuning.ts +766 -0
- package/src/setup/unitcut.ts +523 -0
- package/src/singleflight.ts +86 -0
- package/src/slack/announce.ts +911 -0
- package/src/slack/api.ts +303 -0
- package/src/slack/messages.ts +288 -0
- package/src/slack/origin.ts +599 -0
- package/src/slack/policy.ts +354 -0
- package/src/slack/reply.ts +201 -0
- package/src/slack/router.ts +285 -0
- package/src/slack/socket.ts +384 -0
- package/src/slack/types.ts +108 -0
- package/src/sqlitehint.ts +32 -0
- package/src/ssh-observation.ts +30 -0
- package/src/state.ts +8243 -0
- package/src/statemachine.ts +369 -0
- package/src/stubs.ts +68 -0
- package/src/takeover.ts +634 -0
- package/src/takeoverpi.ts +293 -0
- package/src/terminal-failure.ts +41 -0
- package/src/thread-resolution-refusal.ts +2 -0
- package/src/tmux.ts +153 -0
- package/src/trackerid.ts +41 -0
- package/src/transcriptindex.ts +665 -0
- package/src/tui/actions.ts +484 -0
- package/src/tui/alerts.ts +666 -0
- package/src/tui/app.ts +1979 -0
- package/src/tui/archiveops.ts +192 -0
- package/src/tui/autofile.ts +233 -0
- package/src/tui/board.ts +1432 -0
- package/src/tui/candidates.ts +889 -0
- package/src/tui/cellwidth.ts +148 -0
- package/src/tui/changelog-store.ts +503 -0
- package/src/tui/chord.ts +25 -0
- package/src/tui/clipboard.ts +92 -0
- package/src/tui/cmdbar.ts +296 -0
- package/src/tui/companion.ts +1427 -0
- package/src/tui/companionplan.ts +247 -0
- package/src/tui/companiontab.ts +83 -0
- package/src/tui/confighome.ts +155 -0
- package/src/tui/connect.ts +68 -0
- package/src/tui/deploy-ceremony.ts +104 -0
- package/src/tui/deploy-drain.ts +129 -0
- package/src/tui/deploy-process.ts +265 -0
- package/src/tui/deploytab.ts +1523 -0
- package/src/tui/design.ts +125 -0
- package/src/tui/digesttab.ts +214 -0
- package/src/tui/emptystate.ts +39 -0
- package/src/tui/evidence.ts +999 -0
- package/src/tui/feed.ts +604 -0
- package/src/tui/feedbacktab.ts +1077 -0
- package/src/tui/filters.ts +90 -0
- package/src/tui/ghread.ts +321 -0
- package/src/tui/historypull.ts +81 -0
- package/src/tui/inboxpull.ts +236 -0
- package/src/tui/index.ts +1565 -0
- package/src/tui/issuesink.ts +238 -0
- package/src/tui/jsonfile.ts +42 -0
- package/src/tui/keys.ts +109 -0
- package/src/tui/layout.ts +108 -0
- package/src/tui/learning.ts +627 -0
- package/src/tui/lessonswitch.ts +118 -0
- package/src/tui/livecontrol.ts +228 -0
- package/src/tui/memforward.ts +443 -0
- package/src/tui/memincident.ts +363 -0
- package/src/tui/memory.ts +620 -0
- package/src/tui/memtab.ts +606 -0
- package/src/tui/metricstab.ts +1177 -0
- package/src/tui/model.ts +131 -0
- package/src/tui/mouse.ts +98 -0
- package/src/tui/msg.ts +268 -0
- package/src/tui/nativecompanion.ts +417 -0
- package/src/tui/openurl.ts +21 -0
- package/src/tui/paint.ts +511 -0
- package/src/tui/panes.ts +98 -0
- package/src/tui/pipane.ts +219 -0
- package/src/tui/poll-hooks.ts +12 -0
- package/src/tui/poll.ts +147 -0
- package/src/tui/proposals.ts +838 -0
- package/src/tui/prpause.ts +150 -0
- package/src/tui/reload.ts +436 -0
- package/src/tui/remote.ts +413 -0
- package/src/tui/rollover.ts +969 -0
- package/src/tui/scantab.ts +1290 -0
- package/src/tui/setupentry.ts +93 -0
- package/src/tui/sidebar.ts +749 -0
- package/src/tui/sshtriage.ts +510 -0
- package/src/tui/startup.ts +231 -0
- package/src/tui/tabs.ts +45 -0
- package/src/tui/termmirror.ts +224 -0
- package/src/tui/theme.ts +95 -0
- package/src/tui/ticketstab.ts +310 -0
- package/src/tui/tmuxsocket.ts +129 -0
- package/src/tui/trackertickets.ts +84 -0
- package/src/tui/unwedge.ts +286 -0
- package/src/tui/viewer.ts +575 -0
- package/src/tui/viewerinput.ts +173 -0
- package/src/updatenotice.ts +178 -0
- package/src/usage.ts +1154 -0
- package/src/verdicts.ts +4689 -0
- package/src/version.ts +80 -0
- package/src/wakes.ts +476 -0
- package/src/webhook.ts +942 -0
- package/src/webhookheal.ts +276 -0
- package/src/wire.ts +2153 -0
- package/src/worker-session-host.ts +602 -0
- package/src/workerbreaker.ts +156 -0
- package/src/workercontrol.ts +104 -0
- package/src/workerlease.ts +441 -0
- package/src/workerliveness.ts +103 -0
- package/src/workerlog.ts +79 -0
- package/src/workerruntime.ts +30 -0
- package/src/workersupervisor.ts +1538 -0
- package/src/workerusage.ts +42 -0
- package/src/workerworld.ts +427 -0
- package/src/worktrees.ts +1138 -0
- package/tests/fixtures/regression-cases.json +795 -0
- package/tests/fixtures/seed-manifest.json +19 -0
|
@@ -0,0 +1,1236 @@
|
|
|
1
|
+
import { usd, findingLocation } from "../src/setup/presentation.js";
|
|
2
|
+
// setup-scan — the scan half of the companion's setup tool belt. Not an
|
|
3
|
+
// extension of its own: extensions/setup.ts (the one setup & scan extension)
|
|
4
|
+
// registers these beside the setup_* tools. The companion judges
|
|
5
|
+
// — when to scan, what to tell the operator about the price — and these
|
|
6
|
+
// tools act: every number, refusal and record is ScanRunner's.
|
|
7
|
+
//
|
|
8
|
+
// - scan_preview: what stage 1 would read at a sha and what it costs — or,
|
|
9
|
+
// on a repo never priced at these settings, the calibration run;
|
|
10
|
+
// - scan_start: start exactly what a preview showed (its key), in the
|
|
11
|
+
// background; hard stop at the estimate;
|
|
12
|
+
// - scan_status / scan_stop: progress, and the stop (the ledger resumes);
|
|
13
|
+
// - scan_findings: the stored findings, filterable;
|
|
14
|
+
// - scan_matches / scan_match: the pending match question — the
|
|
15
|
+
// findings a re-scan stopped reporting exactly, beside the fresh ones
|
|
16
|
+
// that might be them — and the companion's whole answer to it.
|
|
17
|
+
// - scan_suggestions: stage 1's deep-lens suggestions and the
|
|
18
|
+
// lenses and tiers stage 2 may use — the companion's input;
|
|
19
|
+
// - scan_stage2_propose: the companion's rows (file set × deep lens × tier,
|
|
20
|
+
// reason) checked, tests paired, priced from the ledger and fitted to a
|
|
21
|
+
// budget when given one — stored, so the TUI can show it. A DEEP proposal
|
|
22
|
+
// (`[scan] depth = "deep"`, or `deep: true`; `deep: false` makes it
|
|
23
|
+
// standard) adds the floor after them — every `[scan] deep_lenses` lens
|
|
24
|
+
// over every file stage 1 reads — and the companion's rows may be none;
|
|
25
|
+
// - scan_stage2_start: start the stored proposal by its key — or only the
|
|
26
|
+
// runnable rows named in `rows`, stopped hard at their total — on the
|
|
27
|
+
// operator's word. The TUI's click reaches the same start through
|
|
28
|
+
// `watchTuiRequests` (the start channel, src/setup/stage2request.ts —
|
|
29
|
+
// and the [8] scan tab's stop, src/setup/scanreport.ts).
|
|
30
|
+
//
|
|
31
|
+
// A delta re-scan is scan_preview / scan_start with `delta: true`: stage 1
|
|
32
|
+
// over the files whose content changed since the last scan, plus any file
|
|
33
|
+
// no complete reading covers yet (never read, cut short, unreadable before).
|
|
34
|
+
//
|
|
35
|
+
// Convention (setup.ts, onboarding.ts): every tool answers a refusal as its
|
|
36
|
+
// result, never a throw.
|
|
37
|
+
import { FINDING_STATES } from "../src/setup/findings.js";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
import {
|
|
40
|
+
textResult as text,
|
|
41
|
+
refusedResult as refused,
|
|
42
|
+
type QcrTool,
|
|
43
|
+
} from "@quickchatai/pi-quickreview/extensions/pi-tool.js";
|
|
44
|
+
import { sandboxRoot } from "../src/config.js";
|
|
45
|
+
import { homeProfileLookup, stateHome } from "../src/install.js";
|
|
46
|
+
import { scanCasesForEnv } from "@quickchatai/pi-quickreview/src/engine/auth.js";
|
|
47
|
+
import { piCaseRunner } from "../src/setup/caserunner.js";
|
|
48
|
+
import type { CaseRunner, SetupEngine } from "../src/setup/engine.js";
|
|
49
|
+
import type {
|
|
50
|
+
FindingsFilter,
|
|
51
|
+
FindingState,
|
|
52
|
+
MatchQuestionView,
|
|
53
|
+
ScanFinding,
|
|
54
|
+
ValidityView,
|
|
55
|
+
} from "../src/setup/findings.js";
|
|
56
|
+
import {
|
|
57
|
+
VALIDITY_ORDER,
|
|
58
|
+
clickStopScan,
|
|
59
|
+
readStopResult,
|
|
60
|
+
scanStopOutcome,
|
|
61
|
+
validityOf,
|
|
62
|
+
type ScanStopRequest,
|
|
63
|
+
} from "../src/setup/scanreport.js";
|
|
64
|
+
import { FindingsStore, dismissedLookalike, lookalikeRank } from "../src/setup/findings.js";
|
|
65
|
+
import { stateHomeFs } from "../src/setup/adapters.js";
|
|
66
|
+
import { SEVERITIES, type ScanSeverity } from "../src/setup/scan.js";
|
|
67
|
+
import { lensTiers, stage2Lenses, MAX_STAGE2_ROWS } from "../src/setup/stage2.js";
|
|
68
|
+
import {
|
|
69
|
+
priceIsMeasured,
|
|
70
|
+
priceLabel,
|
|
71
|
+
type StoredStage2Proposal,
|
|
72
|
+
} from "../src/setup/stage2request.js";
|
|
73
|
+
import {
|
|
74
|
+
buildScanAgents,
|
|
75
|
+
loadScanConfig,
|
|
76
|
+
scanSettings,
|
|
77
|
+
SCAN_AGENTS_DIR,
|
|
78
|
+
} from "../src/setup/scanbuild.js";
|
|
79
|
+
import { escapeControls } from "../src/setup/textsniff.js";
|
|
80
|
+
import {
|
|
81
|
+
SCAN_TRANSCRIPTS_DIR,
|
|
82
|
+
ScanRunner,
|
|
83
|
+
type ScanPreview,
|
|
84
|
+
type ScanRun,
|
|
85
|
+
type ScanSettings,
|
|
86
|
+
type ScanStatus,
|
|
87
|
+
type StoredSuggestion,
|
|
88
|
+
} from "../src/setup/scanrun.js";
|
|
89
|
+
import { gitScanSource } from "../src/setup/scantree.js";
|
|
90
|
+
import { ScanTriage, type CloseFixedResult } from "../src/setup/triage.js";
|
|
91
|
+
import type { MemoryStore } from "../src/memory/store.js";
|
|
92
|
+
import type { TrackerSink } from "../src/setup/engine.js";
|
|
93
|
+
import type { MatchResult } from "../src/setup/findings.js";
|
|
94
|
+
import { fileLease, type ScanLease } from "../src/setup/scanlease.js";
|
|
95
|
+
|
|
96
|
+
const NO_PARAMS = { type: "object", properties: {} } as const;
|
|
97
|
+
|
|
98
|
+
// ---- rendering ---------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
/** How a rendering names the next step: the companion's tools, or the
|
|
101
|
+
* `qcr scan` CLI's subcommands — the same words around either. */
|
|
102
|
+
export interface ScanVerbs {
|
|
103
|
+
/** How to start the previewed run. */
|
|
104
|
+
start(p: Pick<ScanPreview, "key" | "sha" | "mode">): string;
|
|
105
|
+
/** Where the pending match question is shown. */
|
|
106
|
+
matches: string;
|
|
107
|
+
/** How to answer the match question `key`: what precedes "that are the
|
|
108
|
+
* SAME finding". */
|
|
109
|
+
match(key: string): string;
|
|
110
|
+
/** How to start the stored stage-2 proposal `key`, and only some of its rows. */
|
|
111
|
+
stage2Start(key: string): string;
|
|
112
|
+
/** The progress and stop verbs a start names. */
|
|
113
|
+
status: string;
|
|
114
|
+
stop: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const TOOL_VERBS: ScanVerbs = {
|
|
118
|
+
start: (p) =>
|
|
119
|
+
`scan_start with key ${p.key} and sha ${p.sha}${p.mode === "delta" ? " and delta true" : ""}`,
|
|
120
|
+
matches: "scan_matches",
|
|
121
|
+
match: (key) => `scan_match: key ${key} and the pairs`,
|
|
122
|
+
stage2Start: (key) =>
|
|
123
|
+
`scan_stage2_start with key ${key} — only after the operator agreed to the cost ("do it"); the TUI's start click starts the same proposal. ` +
|
|
124
|
+
`To run only some rows: add rows (their ids, e.g. ["row-1"]) — only runnable rows, and the run stops hard at their total.`,
|
|
125
|
+
status: "scan_status",
|
|
126
|
+
stop: "scan_stop",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export const CLI_VERBS: ScanVerbs = {
|
|
130
|
+
start: (p) =>
|
|
131
|
+
`qcr scan start --key ${p.key} --sha ${p.sha}${p.mode === "delta" ? " --delta" : ""}`,
|
|
132
|
+
matches: "qcr scan matches",
|
|
133
|
+
match: (key) => `qcr scan match --key ${key} OLD=NEW… — the pairs`,
|
|
134
|
+
stage2Start: (key) =>
|
|
135
|
+
`qcr scan stage2 start --key ${key} — only after the operator agreed to the cost; the TUI's start click starts the same proposal. ` +
|
|
136
|
+
"To run only some rows: add --rows with their ids (e.g. --rows row-1,row-3) — only runnable rows, and the run stops hard at their total.",
|
|
137
|
+
status: "qcr scan status",
|
|
138
|
+
stop: "qcr scan stop",
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/** A delta's unchanged-but-owed files: those no reading covers, and — on a
|
|
142
|
+
* deep delta — those a standard reading covers but no deep one does yet. */
|
|
143
|
+
function owedClause(d: ScanPreview["delta"]): string {
|
|
144
|
+
if (d === null || d.owed <= 0) return "";
|
|
145
|
+
const shallow = Math.min(d.owed_shallow ?? 0, d.owed);
|
|
146
|
+
const unread = d.owed - shallow;
|
|
147
|
+
const parts: string[] = [];
|
|
148
|
+
if (unread > 0)
|
|
149
|
+
parts.push(
|
|
150
|
+
`${unread} of the files are unchanged but no reading covers them yet (never read, cut short or unreadable before)`,
|
|
151
|
+
);
|
|
152
|
+
if (shallow > 0)
|
|
153
|
+
parts.push(`${shallow} of the files are unchanged but not yet read at deep depth`);
|
|
154
|
+
return `; ${parts.join("; ")} — read first`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function renderPreview(p: ScanPreview, verbs: ScanVerbs = TOOL_VERBS): string {
|
|
158
|
+
const out: string[] = [];
|
|
159
|
+
const deep = p.depth === "deep";
|
|
160
|
+
const head = `${deep ? "(deep) " : ""}at ${p.sha.slice(0, 12)} — ${p.settings.tier} at ${p.settings.effort} effort, skeptic ${p.settings.validator ? `on (at the lens's tier, ${p.settings.validate_tier}; its cost is in the price)` : "off (findings stay unjudged — validity unknown)"}`;
|
|
161
|
+
// A rate measured at the other depth stands in until this depth is priced.
|
|
162
|
+
const across = p.rate_across_depth
|
|
163
|
+
? ` — from readings at the other depth: nothing at ${p.depth} depth is priced at these settings yet`
|
|
164
|
+
: "";
|
|
165
|
+
if (p.mode === "delta") {
|
|
166
|
+
out.push(
|
|
167
|
+
`DELTA re-scan ${head}, against the last scan at ${p.delta?.since.slice(0, 12) ?? "?"}.`,
|
|
168
|
+
`Files whose content changed since, and any not yet read whole: ${p.files} files, ${p.lines} lines in ${p.cases.length} case(s) — ` +
|
|
169
|
+
`${p.covered} already read at this content` +
|
|
170
|
+
owedClause(p.delta) +
|
|
171
|
+
`. Estimate ${usd(p.estimate_usd)}, measured at ` +
|
|
172
|
+
`${usd(p.rate?.usd_per_kline ?? null)}/kline over ${p.rate?.cases ?? 0} finished case(s)${across}. The run stops hard at the estimate. ` +
|
|
173
|
+
"No deep pass runs on a delta.",
|
|
174
|
+
);
|
|
175
|
+
} else if (p.mode === "calibration") {
|
|
176
|
+
out.push(
|
|
177
|
+
`CALIBRATION run ${head}.`,
|
|
178
|
+
`No measured price for stage 1 at these settings yet (${p.calibration.measured} of ${p.calibration.wanted} priced cases). ` +
|
|
179
|
+
`This run reads ${p.cases.length} case(s) from units spread across the size range and measures what they cost; ` +
|
|
180
|
+
`it stops hard at ${usd(p.cap_usd)}. Its findings are real stage-1 findings. Preview again afterwards for the full estimate` +
|
|
181
|
+
(p.remaining_cases > 0 ? ` (${p.remaining_cases} more case(s) after it).` : "."),
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
out.push(
|
|
185
|
+
`STAGE 1 ${head}.`,
|
|
186
|
+
`Estimate ${usd(p.estimate_usd)} for ${p.cases.length} case(s), ${p.files} files, ${p.lines} lines — measured at ` +
|
|
187
|
+
`${usd(p.rate?.usd_per_kline ?? null)}/kline over ${p.rate?.cases ?? 0} finished case(s)${across}. The run stops hard at the estimate.`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (deep) {
|
|
191
|
+
out.push(
|
|
192
|
+
"DEEP: pass-scan names a deep lens for every focus file, and a file the ledger holds only a standard reading of is read again. " +
|
|
193
|
+
"A deep stage 2 proposal then adds the floor — the [scan] deep_lenses over every file this stage reads.",
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
const rows = p.cases
|
|
197
|
+
.slice(0, 40)
|
|
198
|
+
.map(
|
|
199
|
+
(c) =>
|
|
200
|
+
` - ${c.id}: ${c.files.length} files, ${c.lines} lines${c.estimate_usd !== null ? `, ~${usd(c.estimate_usd)}` : ""}`,
|
|
201
|
+
);
|
|
202
|
+
if (p.cases.length > 40) rows.push(` … and ${p.cases.length - 40} more`);
|
|
203
|
+
out.push(rows.join("\n"));
|
|
204
|
+
const skipped = Object.entries(p.excluded)
|
|
205
|
+
.filter(([, n]) => n > 0)
|
|
206
|
+
.map(([why, n]) => `${n} ${why}`);
|
|
207
|
+
out.push(
|
|
208
|
+
`Not read: ${skipped.length ? skipped.join(", ") : "nothing excluded"}; ${p.covered} already in the ledger at this content; ` +
|
|
209
|
+
`${p.unreadable} unreadable${p.settings.exclude.length ? `; exclude globs ${p.settings.exclude.join(", ")}` : ""}.`,
|
|
210
|
+
);
|
|
211
|
+
// What the tree lists but no lens can read, by reason and by name — a
|
|
212
|
+
// binary is REPORTED as skipped, never silently absent from coverage.
|
|
213
|
+
const skippedBy = new Map<string, string[]>();
|
|
214
|
+
for (const f of p.skipped ?? []) skippedBy.set(f.why, [...(skippedBy.get(f.why) ?? []), f.path]);
|
|
215
|
+
for (const [why, paths] of skippedBy) {
|
|
216
|
+
const label =
|
|
217
|
+
why === "binary" ? "binary" : why === "too-big" ? "over the size cap" : "unreadable";
|
|
218
|
+
out.push(
|
|
219
|
+
`skipped: ${label} — ${paths.length} file(s): ${paths.slice(0, 5).map(escapeControls).join(", ")}${paths.length > 5 ? ", …" : ""}; not read by any lens.`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if (p.unassigned.length > 0) {
|
|
223
|
+
out.push(
|
|
224
|
+
`! ${p.unassigned.length} file(s) no unit owns at this sha (e.g. ${p.unassigned.slice(0, 3).join(", ")}) — the unit cut may need adjusting; they are not read.`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (p.reconcile_only) {
|
|
228
|
+
out.push(
|
|
229
|
+
`Nothing to read, but ${p.reconcile_only}: the run reads no case and only reconciles the findings (no cost).`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
for (const b of p.blockers) out.push(`✗ ${b}`);
|
|
233
|
+
if (p.blockers.length === 0) {
|
|
234
|
+
out.push(`To run it: ${verbs.start(p)} — only after the operator agreed to the cost.`);
|
|
235
|
+
}
|
|
236
|
+
return out.join("\n\n");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** A run's findings by validity tier — `(2 confirmed, 1 likely, 3 doubtful)`
|
|
240
|
+
* — from the per-case counts; `unknown` for what no skeptic judged (the
|
|
241
|
+
* validator off or failed, or a case recorded before the tiers). */
|
|
242
|
+
function tierCounts(r: NonNullable<ScanStatus["run"]>, findings: number, doubted: number): string {
|
|
243
|
+
if (!r.settings.validator)
|
|
244
|
+
return doubted ? ` (${doubted} may not be valid)` : " (skeptic off — validity unknown)";
|
|
245
|
+
const confirmed = r.cases.reduce((n, c) => n + (c.confirmed ?? 0), 0);
|
|
246
|
+
const likely = r.cases.reduce((n, c) => n + (c.likely ?? 0), 0);
|
|
247
|
+
const unknown = findings - confirmed - likely - doubted;
|
|
248
|
+
if (findings === 0) return "";
|
|
249
|
+
return ` (${confirmed} confirmed, ${likely} likely, ${doubted} doubtful${unknown > 0 ? `, ${unknown} unknown` : ""})`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function renderStatus(s: ScanStatus, verbs: ScanVerbs = TOOL_VERBS): string {
|
|
253
|
+
const out: string[] = [];
|
|
254
|
+
for (const p of s.problems) out.push(`✗ ${p}`);
|
|
255
|
+
const r = s.run;
|
|
256
|
+
if (r === null) {
|
|
257
|
+
out.push(s.problems.length > 0 ? "Latest scan: UNKNOWN — see above." : "No scan has run yet.");
|
|
258
|
+
} else {
|
|
259
|
+
const done = r.cases.filter((c) => c.status === "done").length;
|
|
260
|
+
const findings = r.cases.reduce((n, c) => n + c.findings, 0);
|
|
261
|
+
const doubted = r.cases.reduce((n, c) => n + c.doubted, 0);
|
|
262
|
+
out.push(
|
|
263
|
+
`${r.id} (${r.mode === "stage2" ? "stage 2" : r.mode}${r.settings.depth === "deep" ? ", deep" : ""}) at ${r.sha.slice(0, 12)}: ${r.display.toUpperCase()} — ${done}/${r.cases.length} cases, ` +
|
|
264
|
+
`${findings} finding(s)${tierCounts(r, findings, doubted)}, spent ${usd(r.spent_usd)} of ${usd(r.cap_usd)}` +
|
|
265
|
+
(r.unpriced_cases
|
|
266
|
+
? ` (${r.unpriced_cases} unpriced case(s) counted at their estimate)`
|
|
267
|
+
: ""),
|
|
268
|
+
);
|
|
269
|
+
// Stage 2 is re-entered by a new proposal (the rows already read are
|
|
270
|
+
// covered, free); stage 1 by a new preview.
|
|
271
|
+
const again = r.mode === "stage2" ? "Propose stage 2 again" : "Preview";
|
|
272
|
+
if (r.display === "interrupted")
|
|
273
|
+
out.push(
|
|
274
|
+
`It was interrupted (the process driving it went away — the companion restarted, or a \`qcr scan\` driver died). ${again} and start again — the ledger resumes it.`,
|
|
275
|
+
);
|
|
276
|
+
if (r.display === "capped")
|
|
277
|
+
out.push(`It stopped at its hard cap. ${again} for the price of what is left.`);
|
|
278
|
+
if (r.mode === "stage2") {
|
|
279
|
+
for (const c of r.cases.slice(0, 40)) {
|
|
280
|
+
out.push(
|
|
281
|
+
` - ${c.id} ${c.lens ?? "?"} at ${c.tier ?? "?"} (${(c.units ?? [c.unit]).join(", ")}): ${c.status}, ${c.findings} finding(s), ${usd(c.cost_usd)}` +
|
|
282
|
+
(c.reads !== undefined ? `, ${c.reads} read(s)` : "") +
|
|
283
|
+
(c.unopened?.length ? `, ${c.unopened.length} focus file(s) not opened` : ""),
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// Where to read back what a lens did, when the runner kept it.
|
|
288
|
+
if (r.cases.some((c) => c.transcript !== undefined))
|
|
289
|
+
out.push(
|
|
290
|
+
`Transcripts: ${SCAN_TRANSCRIPTS_DIR}/${r.id}/ under the state home (one .jsonl per case, .validate.jsonl for its skeptic).`,
|
|
291
|
+
);
|
|
292
|
+
const failed = r.cases.filter((c) => c.status === "failed");
|
|
293
|
+
for (const c of failed.slice(0, 10)) out.push(` ✗ ${c.id}: ${c.error}`);
|
|
294
|
+
for (const p of r.problems.slice(-5)) out.push(` ! ${p}`);
|
|
295
|
+
if (r.tickets_closed)
|
|
296
|
+
out.push(`Tickets closed as fixed at ${r.sha.slice(0, 12)}: ${r.tickets_closed}.`);
|
|
297
|
+
if (r.matching && (r.matching.fixed > 0 || r.matching.pending > 0)) {
|
|
298
|
+
out.push(
|
|
299
|
+
`Findings no longer reported: ${r.matching.fixed} fixed` +
|
|
300
|
+
(r.matching.pending > 0
|
|
301
|
+
? `, ${r.matching.pending} waiting on your match (${verbs.matches})`
|
|
302
|
+
: ""),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
// A dismissal is sticky: what would have been fixed is only stamped.
|
|
306
|
+
const dismissedGone = r.matching?.dismissed_unreported ?? 0;
|
|
307
|
+
if (dismissedGone > 0) {
|
|
308
|
+
out.push(
|
|
309
|
+
`Dismissed and no longer reported: ${dismissedGone} — kept dismissed (a scan never overwrites the operator's triage), stamped for audit.`,
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
// A record written before the stamp existed has no count: nothing to say.
|
|
313
|
+
const notReproduced = r.matching?.not_reproduced ?? 0;
|
|
314
|
+
if (notReproduced > 0) {
|
|
315
|
+
out.push(
|
|
316
|
+
`Not reproduced: ${notReproduced} open finding(s) re-read at UNCHANGED content without being reported again — ` +
|
|
317
|
+
"kept open (only changed code is fixed); dismiss any that were noise.",
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (s.ledger) {
|
|
322
|
+
out.push(
|
|
323
|
+
`Ledger: ${s.ledger.files} file(s) read by stage 1` +
|
|
324
|
+
(s.ledger.deep_files ? `, ${s.ledger.deep_files} file × lens read by stage 2` : "") +
|
|
325
|
+
`, ${usd(s.ledger.cost_usd)} recorded.`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
return out.join("\n");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** Findings in validity order — confirmed, likely, doubtful, unknown — the
|
|
332
|
+
* store's order (most severe first) kept inside each tier, a finding that
|
|
333
|
+
* looks like a dismissed one below the rest of its tier. */
|
|
334
|
+
export function byValidity(fs: readonly ScanFinding[]): ScanFinding[] {
|
|
335
|
+
return VALIDITY_ORDER.flatMap((v) => {
|
|
336
|
+
const tier = fs.filter((f) => validityOf(f) === v);
|
|
337
|
+
return [
|
|
338
|
+
...tier.filter((f) => lookalikeRank(f) === 0),
|
|
339
|
+
...tier.filter((f) => lookalikeRank(f) === 1),
|
|
340
|
+
];
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** A new finding that resembles one the operator dismissed: which, and why
|
|
345
|
+
* — flagged for triage, never dismissed by the scan. */
|
|
346
|
+
function lookalikeNote(f: ScanFinding): string {
|
|
347
|
+
const d = dismissedLookalike(f);
|
|
348
|
+
return d
|
|
349
|
+
? `, LOOKS LIKE DISMISSED ${d.fingerprint.slice(0, 12)}: ${d.reason} — not auto-dismissed`
|
|
350
|
+
: "";
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function validityNote(f: ScanFinding): string {
|
|
354
|
+
const v = validityOf(f);
|
|
355
|
+
if (v === "doubtful")
|
|
356
|
+
return `, DOUBTFUL — ${f.doubt?.word ?? "?"}${f.doubt?.class ? ` [${f.doubt.class}]` : ""}`;
|
|
357
|
+
if (v === "unknown")
|
|
358
|
+
return f.doubt
|
|
359
|
+
? `, MAY NOT BE VALID — ${f.doubt.word}`
|
|
360
|
+
: f.validated
|
|
361
|
+
? ", validity unknown"
|
|
362
|
+
: ", unvalidated";
|
|
363
|
+
return `, ${v.toUpperCase()}`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function renderFindings(fs: readonly ScanFinding[], total: number): string {
|
|
367
|
+
if (fs.length === 0) return "No stored scan findings match.";
|
|
368
|
+
const rows = fs.map(
|
|
369
|
+
(f) =>
|
|
370
|
+
`- [${f.severity}] ${findingLocation(f)} (${f.unit}, ${f.kind}, ${f.state}` +
|
|
371
|
+
validityNote(f) +
|
|
372
|
+
`${f.capped_from ? `, ${f.capped_from}→${f.severity}: ${f.reachability}` : ""}` +
|
|
373
|
+
`${f.anchor_quoted === false ? ", ANCHOR NOT QUOTED — the lines may not be the defect's" : ""}` +
|
|
374
|
+
`${f.fixed ? ` at ${f.fixed.sha.slice(0, 12)}, was ${f.fixed.from}` : ""}` +
|
|
375
|
+
`${f.state === "dismissed" && f.unreported ? `, no longer reported at ${f.unreported.sha.slice(0, 12)} — kept dismissed` : ""}` +
|
|
376
|
+
`${f.not_reproduced ? `, NOT REPRODUCED by ${f.not_reproduced.count} re-read(s) of unchanged code, latest ${f.not_reproduced.run}` : ""}` +
|
|
377
|
+
`${lookalikeNote(f)}) ` +
|
|
378
|
+
`${f.claim} [${f.fingerprint.slice(0, 12)}]`,
|
|
379
|
+
);
|
|
380
|
+
if (total > fs.length) rows.push(`… ${total - fs.length} more — narrow the filter.`);
|
|
381
|
+
return rows.join("\n");
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export function renderQuestion(q: MatchQuestionView | null, verbs: ScanVerbs = TOOL_VERBS): string {
|
|
385
|
+
if (q === null)
|
|
386
|
+
return "No match question is pending: every finding a re-scan stopped reporting has been settled.";
|
|
387
|
+
const row = (f: ScanFinding): string =>
|
|
388
|
+
` - ${f.fingerprint} [${f.severity}] ${findingLocation(f)} (${f.unit}, ${f.lens}, ${f.kind}` +
|
|
389
|
+
`${f.state === "new" ? "" : `, ${f.state}`}${lookalikeNote(f)}) ${f.claim}`;
|
|
390
|
+
return [
|
|
391
|
+
`MATCH QUESTION ${q.key} (re-scan ${q.run} at ${q.sha.slice(0, 12)}).`,
|
|
392
|
+
`No longer reported exactly (${q.unreported.length}):`,
|
|
393
|
+
...q.unreported.map(row),
|
|
394
|
+
`Fresh — first seen by the re-scan, possibly one of the above moved or reworded (${q.fresh.length}):`,
|
|
395
|
+
...q.fresh.map(row),
|
|
396
|
+
`Answer with ${verbs.match(q.key)} that are the SAME finding. Every unpaired old one becomes fixed (a dismissed one stays dismissed); every unpaired fresh one stays new.`,
|
|
397
|
+
].join("\n");
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function renderSuggestions(
|
|
401
|
+
sugs: readonly StoredSuggestion[],
|
|
402
|
+
settings: ScanSettings | null,
|
|
403
|
+
): string {
|
|
404
|
+
const out: string[] = [];
|
|
405
|
+
if (sugs.length === 0)
|
|
406
|
+
out.push("No deep-lens suggestions stored — stage 1 has not suggested any yet.");
|
|
407
|
+
else {
|
|
408
|
+
const byLens = new Map<string, StoredSuggestion[]>();
|
|
409
|
+
for (const s of sugs) byLens.set(s.lens, [...(byLens.get(s.lens) ?? []), s]);
|
|
410
|
+
for (const [lens, ss] of [...byLens.entries()].sort(
|
|
411
|
+
(a, b) => b[1].length - a[1].length || (a[0] < b[0] ? -1 : 1),
|
|
412
|
+
)) {
|
|
413
|
+
out.push(`${lens} (${ss.length}):`);
|
|
414
|
+
for (const s of ss.slice(0, 30))
|
|
415
|
+
out.push(` - [${s.unit}] ${s.files.join(", ")} — ${s.reason} (at ${s.sha.slice(0, 12)})`);
|
|
416
|
+
if (ss.length > 30) out.push(` … and ${ss.length - 30} more`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (settings) {
|
|
420
|
+
const lenses = stage2Lenses(settings.lenses);
|
|
421
|
+
out.push(
|
|
422
|
+
"",
|
|
423
|
+
`Stage 2 may run: ${lenses.map((l) => `${l} (${lensTiers(settings.lenses, l, settings.riskPasses ?? []).join("|")})`).join(", ")}.`,
|
|
424
|
+
`One row reads at most ${settings.scan.case_max_files} files / ${settings.scan.case_max_lines} lines, paired tests included; at most ${MAX_STAGE2_ROWS} rows.`,
|
|
425
|
+
settings.scan.depth === "deep"
|
|
426
|
+
? `Depth: deep — a proposal adds the floor after your rows (${settings.scan.deep_lenses.filter((l) => lenses.includes(l)).join(", ") || "no lens: every deep_lenses lens is switched off"} over every file stage 1 reads; not counted in the ${MAX_STAGE2_ROWS}), so your rows may be none. deep: false proposes a standard plan.`
|
|
427
|
+
: "Depth: standard — deep: true on a proposal makes it deep (the floor, every lens told to dig).",
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
return out.join("\n");
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** The floor's rows, one line per lens: its row ids, files, cost and what
|
|
434
|
+
* the budget left out — the floor is bounded by the tree, so its rows are
|
|
435
|
+
* summed, never listed one by one. */
|
|
436
|
+
function renderFloor(p: StoredStage2Proposal): string[] {
|
|
437
|
+
const floor = p.rows.filter((r) => r.floor);
|
|
438
|
+
const out: string[] = [];
|
|
439
|
+
const lenses = [...new Set(floor.map((r) => r.lens))];
|
|
440
|
+
for (const lens of lenses) {
|
|
441
|
+
const rows = floor.filter((r) => r.lens === lens);
|
|
442
|
+
const run = rows.filter((r) => r.status === "run");
|
|
443
|
+
const over = rows.filter((r) => r.status === "over-budget");
|
|
444
|
+
const covered = rows.filter((r) => r.status === "covered");
|
|
445
|
+
const ids = rows.length === 1 ? rows[0]!.id : `${rows[0]!.id}…${rows[rows.length - 1]!.id}`;
|
|
446
|
+
out.push(
|
|
447
|
+
` ${lens} (floor ${ids}) at ${rows[0]!.tier}: ${rows.length} row(s) over ${[...new Set(rows.flatMap((r) => r.units))].length} unit(s), ` +
|
|
448
|
+
`${rows.reduce((n, r) => n + r.files.length, 0)} file(s), ${rows.reduce((n, r) => n + r.lines, 0)} lines — ` +
|
|
449
|
+
`${run.length} to run, ~${usd(run.reduce((n, r) => n + r.estimate_usd, 0))} (${priceLabel(rows[0]!.price)})` +
|
|
450
|
+
(covered.length ? `; ${covered.length} covered (free)` : "") +
|
|
451
|
+
(over.length
|
|
452
|
+
? `; OVER BUDGET, left out: ${over.map((r) => r.id).join(", ")} (${usd(over.reduce((n, r) => n + r.estimate_usd, 0))})`
|
|
453
|
+
: ""),
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
const f = p.floor;
|
|
457
|
+
if (f) {
|
|
458
|
+
if (f.lenses.length === 0)
|
|
459
|
+
out.push(" The floor has no lens: every [scan] deep_lenses lens is switched off.");
|
|
460
|
+
if (f.skipped.length > 0)
|
|
461
|
+
out.push(` Switched off by the profile, no floor rows: ${f.skipped.join(", ")}.`);
|
|
462
|
+
if (f.covered > 0 || f.named > 0)
|
|
463
|
+
out.push(
|
|
464
|
+
` Left out of the floor: ${f.covered} file × lens already read deep at this content` +
|
|
465
|
+
(f.named > 0 ? `, ${f.named} named by your rows for the same lens` : "") +
|
|
466
|
+
".",
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
return out;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
export function renderProposal(p: StoredStage2Proposal, verbs: ScanVerbs = TOOL_VERBS): string {
|
|
473
|
+
const out: string[] = [];
|
|
474
|
+
const run = p.rows.filter((r) => r.status === "run");
|
|
475
|
+
const deep = p.depth === "deep";
|
|
476
|
+
out.push(
|
|
477
|
+
`STAGE 2 proposal ${deep ? "(deep) " : ""}at ${p.sha.slice(0, 12)} — ${run.length} row(s) to run, estimate ${usd(p.cap_usd)} (the run stops hard there)` +
|
|
478
|
+
(p.budget_usd !== null ? `, fitted to a ${usd(p.budget_usd)} budget` : "") +
|
|
479
|
+
`; validator ${p.validator ? "on" : "off"}.`,
|
|
480
|
+
);
|
|
481
|
+
if (deep) {
|
|
482
|
+
const own = run.filter((r) => !r.floor);
|
|
483
|
+
const floor = run.filter((r) => r.floor);
|
|
484
|
+
const sum = (rs: readonly { estimate_usd: number }[]): number =>
|
|
485
|
+
rs.reduce((n, r) => n + r.estimate_usd, 0);
|
|
486
|
+
out.push(
|
|
487
|
+
`DEEP: your rows ${own.length} to run, ~${usd(sum(own))}; the floor ${floor.length} to run, ~${usd(sum(floor))}. ` +
|
|
488
|
+
"Every lens is told to dig past its row's files; a standard reading covers nothing here, and the floor runs after your rows (the budget fits them first).",
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
const rows = p.rows
|
|
492
|
+
.filter((r) => !r.floor)
|
|
493
|
+
.map((r) => {
|
|
494
|
+
const mark =
|
|
495
|
+
r.status === "run"
|
|
496
|
+
? ""
|
|
497
|
+
: r.status === "covered"
|
|
498
|
+
? " — COVERED (already read at this content, free)"
|
|
499
|
+
: ` — OVER BUDGET (${usd(r.estimate_usd)}, left out)`;
|
|
500
|
+
const price = priceLabel(r.price);
|
|
501
|
+
return [
|
|
502
|
+
` ${r.id}: ${r.lens} at ${r.tier} over ${r.units.join(" + ")}${r.units.length > 1 ? " (cross-module)" : ""} — ${r.files.length} file(s)` +
|
|
503
|
+
(r.tests.length ? ` + ${r.tests.length} paired test(s)` : "") +
|
|
504
|
+
`, ${r.lines} lines, ~${usd(r.estimate_usd)} (${price})${mark}`,
|
|
505
|
+
` ${r.reason}`,
|
|
506
|
+
` files: ${r.files.map((f) => f.path).join(", ")}`,
|
|
507
|
+
...(r.tests.length ? [` tests: ${r.tests.map((f) => f.path).join(", ")}`] : []),
|
|
508
|
+
...(r.unpaired.length ? [` not paired (row full): ${r.unpaired.join(", ")}`] : []),
|
|
509
|
+
].join("\n");
|
|
510
|
+
});
|
|
511
|
+
if (rows.length > 0) out.push(rows.join("\n"));
|
|
512
|
+
if (deep) out.push(["The deep floor:", ...renderFloor(p)].join("\n"));
|
|
513
|
+
const priced = p.rows.filter((r) => r.status !== "covered");
|
|
514
|
+
const measured = priced.filter((r) => priceIsMeasured(r.price)).length;
|
|
515
|
+
if (priced.length > 0) {
|
|
516
|
+
out.push(
|
|
517
|
+
`Priced by measurement: ${measured} row(s); by estimate: ${priced.length - measured} row(s).` +
|
|
518
|
+
(measured < priced.length
|
|
519
|
+
? " An estimate stands for this run once approved; the next proposal is priced from what the run measures."
|
|
520
|
+
: ""),
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
if (p.over_budget_usd > 0) out.push(`Left out by the budget: ${usd(p.over_budget_usd)} of rows.`);
|
|
524
|
+
if (p.runnable > 0) {
|
|
525
|
+
out.push(`To run it: ${verbs.stage2Start(p.key)}`);
|
|
526
|
+
} else out.push("✗ nothing to run: every row is covered or over the budget.");
|
|
527
|
+
return out.join("\n\n");
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// ---- shared verbs ------------------------------------------------------------
|
|
531
|
+
//
|
|
532
|
+
// What a tool and its `qcr scan` subcommand (src/scancli.ts) both answer:
|
|
533
|
+
// the checks, the orders and the structured results. Each surface renders
|
|
534
|
+
// them its own way; neither carries a rule of its own.
|
|
535
|
+
|
|
536
|
+
/** A preview's structured result: its cases summarised (counts, not files). */
|
|
537
|
+
export function previewDetails(p: ScanPreview): Record<string, unknown> {
|
|
538
|
+
return {
|
|
539
|
+
...p,
|
|
540
|
+
cases: p.cases.map((c) => ({
|
|
541
|
+
id: c.id,
|
|
542
|
+
files: c.files.length,
|
|
543
|
+
lines: c.lines,
|
|
544
|
+
estimate_usd: c.estimate_usd,
|
|
545
|
+
})),
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/** A started run, as a start answers it. */
|
|
550
|
+
export function startedDetails(run: ScanRun): {
|
|
551
|
+
id: string;
|
|
552
|
+
mode: ScanRun["mode"];
|
|
553
|
+
sha: string;
|
|
554
|
+
cases: number;
|
|
555
|
+
cap_usd: number;
|
|
556
|
+
} {
|
|
557
|
+
return {
|
|
558
|
+
id: run.id,
|
|
559
|
+
mode: run.mode,
|
|
560
|
+
sha: run.sha,
|
|
561
|
+
cases: run.cases.length,
|
|
562
|
+
cap_usd: run.cap_usd,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
export { FINDING_STATES } from "../src/setup/findings.js";
|
|
567
|
+
/** How many findings a listing shows unless told otherwise, and at most. */
|
|
568
|
+
export const FINDINGS_LIMIT = 50;
|
|
569
|
+
export const FINDINGS_LIMIT_MAX = 200;
|
|
570
|
+
|
|
571
|
+
/** A findings filter from loose parameters (a tool call's, the CLI's flags),
|
|
572
|
+
* or what is wrong with one. */
|
|
573
|
+
export function findingsFilter(
|
|
574
|
+
p: Record<string, unknown>,
|
|
575
|
+
): { ok: true; filter: FindingsFilter } | { ok: false; error: string } {
|
|
576
|
+
const filter: FindingsFilter = {};
|
|
577
|
+
if (typeof p.state === "string") {
|
|
578
|
+
if (!(FINDING_STATES as readonly string[]).includes(p.state))
|
|
579
|
+
return { ok: false, error: `Unknown state ${JSON.stringify(p.state)}.` };
|
|
580
|
+
filter.state = p.state as FindingState;
|
|
581
|
+
}
|
|
582
|
+
if (typeof p.severity === "string") {
|
|
583
|
+
if (!(SEVERITIES as readonly string[]).includes(p.severity))
|
|
584
|
+
return { ok: false, error: `Unknown severity ${JSON.stringify(p.severity)}.` };
|
|
585
|
+
filter.severity = p.severity as ScanSeverity;
|
|
586
|
+
}
|
|
587
|
+
if (typeof p.lens === "string") filter.lens = p.lens;
|
|
588
|
+
if (typeof p.unit === "string") filter.unit = p.unit;
|
|
589
|
+
if (typeof p.doubted === "boolean") filter.doubted = p.doubted;
|
|
590
|
+
if (typeof p.validity === "string") {
|
|
591
|
+
if (!(VALIDITY_ORDER as readonly string[]).includes(p.validity))
|
|
592
|
+
return {
|
|
593
|
+
ok: false,
|
|
594
|
+
error: `Unknown validity ${JSON.stringify(p.validity)} — confirmed, likely, doubtful or unknown.`,
|
|
595
|
+
};
|
|
596
|
+
filter.validity = p.validity as ValidityView;
|
|
597
|
+
}
|
|
598
|
+
return { ok: true, filter };
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/** The stored findings a filter keeps, in validity order (`byValidity`),
|
|
602
|
+
* with the count in each tier — or why the store cannot be read. */
|
|
603
|
+
export function listFindings(
|
|
604
|
+
findings: FindingsStore,
|
|
605
|
+
filter: FindingsFilter,
|
|
606
|
+
):
|
|
607
|
+
| { ok: true; findings: ScanFinding[]; validity: Record<ValidityView, number> }
|
|
608
|
+
| { ok: false; error: string } {
|
|
609
|
+
const { findings: listed, error } = findings.list(filter);
|
|
610
|
+
if (error !== null) return { ok: false, error };
|
|
611
|
+
const fs = byValidity(listed);
|
|
612
|
+
const validity = Object.fromEntries(
|
|
613
|
+
VALIDITY_ORDER.map((v) => [v, fs.filter((f) => validityOf(f) === v).length]),
|
|
614
|
+
) as Record<ValidityView, number>;
|
|
615
|
+
return { ok: true, findings: fs, validity };
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/** Answer the match question whole, then close the tickets of the promoted
|
|
619
|
+
* findings it fixed — and the lines that say what was settled. */
|
|
620
|
+
export async function answerMatch(
|
|
621
|
+
findings: FindingsStore,
|
|
622
|
+
args: { key?: unknown; pairs?: unknown },
|
|
623
|
+
afterMatch: (() => Promise<CloseFixedResult>) | null,
|
|
624
|
+
): Promise<
|
|
625
|
+
| Extract<MatchResult, { ok: false }>
|
|
626
|
+
| (Extract<MatchResult, { ok: true }> & { tickets: CloseFixedResult | null; lines: string[] })
|
|
627
|
+
> {
|
|
628
|
+
const r = findings.match({ key: args.key, pairs: args.pairs ?? [] });
|
|
629
|
+
if (!r.ok) return r;
|
|
630
|
+
const lines = [
|
|
631
|
+
`Settled: ${r.matched} matched (state kept), ${r.fixed} fixed, ${r.new} new` +
|
|
632
|
+
(r.dismissed_unreported > 0
|
|
633
|
+
? `, ${r.dismissed_unreported} dismissed kept dismissed (stamped no longer reported)`
|
|
634
|
+
: "") +
|
|
635
|
+
".",
|
|
636
|
+
];
|
|
637
|
+
let tickets: CloseFixedResult | null = null;
|
|
638
|
+
if (afterMatch && r.fixed > 0) {
|
|
639
|
+
tickets = await afterMatch();
|
|
640
|
+
if (tickets.closed.length > 0)
|
|
641
|
+
lines.push(`Closed as fixed: ${tickets.closed.map((c) => c.ref).join(", ")}.`);
|
|
642
|
+
for (const p of tickets.problems) lines.push(`! ticket not closed: ${p}`);
|
|
643
|
+
}
|
|
644
|
+
return { ...r, tickets, lines };
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/** A stored proposal's summary, as a propose answers it. */
|
|
648
|
+
export function proposalDetails(p: StoredStage2Proposal): {
|
|
649
|
+
key: string;
|
|
650
|
+
sha: string;
|
|
651
|
+
cap_usd: number;
|
|
652
|
+
runnable: number;
|
|
653
|
+
rows: number;
|
|
654
|
+
depth: "standard" | "deep";
|
|
655
|
+
floor_rows: number;
|
|
656
|
+
floor_usd: number;
|
|
657
|
+
} {
|
|
658
|
+
const floor = p.rows.filter((x) => x.floor);
|
|
659
|
+
return {
|
|
660
|
+
key: p.key,
|
|
661
|
+
sha: p.sha,
|
|
662
|
+
cap_usd: p.cap_usd,
|
|
663
|
+
runnable: p.runnable,
|
|
664
|
+
rows: p.rows.length,
|
|
665
|
+
depth: p.depth ?? "standard",
|
|
666
|
+
floor_rows: floor.length,
|
|
667
|
+
floor_usd: floor.filter((x) => x.status === "run").reduce((n, x) => n + x.estimate_usd, 0),
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/** The line a stage-2 start answers: how many rows run (of how many, when
|
|
672
|
+
* narrowed), and the hard stop. */
|
|
673
|
+
export function stage2StartedLine(
|
|
674
|
+
run: ScanRun,
|
|
675
|
+
runnable: number | null,
|
|
676
|
+
narrowed: boolean,
|
|
677
|
+
verbs: ScanVerbs = TOOL_VERBS,
|
|
678
|
+
): string {
|
|
679
|
+
const count =
|
|
680
|
+
narrowed && runnable !== null
|
|
681
|
+
? `${run.cases.length} row(s) of ${runnable} (${run.cases.map((c) => c.id).join(", ")})`
|
|
682
|
+
: `${run.cases.length} row(s)`;
|
|
683
|
+
return (
|
|
684
|
+
`Stage 2 ${run.id} started at ${run.sha.slice(0, 12)}: ${count}, hard stop ${usd(run.cap_usd)}. ` +
|
|
685
|
+
`It runs in the background — ${verbs.status} shows progress, ${verbs.stop} stops it.`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/** The line a stage-1 start answers. */
|
|
690
|
+
export function startedLine(run: ScanRun, verbs: ScanVerbs = TOOL_VERBS): string {
|
|
691
|
+
return (
|
|
692
|
+
`Scan ${run.id} (${run.mode}) started at ${run.sha.slice(0, 12)}: ${run.cases.length} case(s), hard stop ${usd(run.cap_usd)}. ` +
|
|
693
|
+
`It runs in the background — ${verbs.status} shows progress, ${verbs.stop} stops it.`
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/** How often a stop through the channel looks for its answer, and how long
|
|
698
|
+
* it waits for one. */
|
|
699
|
+
export const STOP_POLL_MS = 2000;
|
|
700
|
+
export const STOP_WAIT_MS = 15_000;
|
|
701
|
+
|
|
702
|
+
/** Where a stop of a run another process drives goes: the stop channel
|
|
703
|
+
* under the state home, answered by whichever process holds the run. */
|
|
704
|
+
export interface StopChannel {
|
|
705
|
+
home: string;
|
|
706
|
+
by?: ScanStopRequest["by"];
|
|
707
|
+
sleep?: (ms: number) => Promise<void>;
|
|
708
|
+
now?: () => number;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/** Stop the recorded run: here when this runner drives it, else through the
|
|
712
|
+
* stop channel the driving process answers — the companion, or a
|
|
713
|
+
* `qcr scan` driver. No answer within STOP_WAIT_MS: nothing drives it. */
|
|
714
|
+
export async function stopScan(
|
|
715
|
+
scan: ScanRunner,
|
|
716
|
+
ch: StopChannel,
|
|
717
|
+
): Promise<{ ok: true; run: string; answer: string } | { ok: false; errors: string[] }> {
|
|
718
|
+
const sleep = ch.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
|
|
719
|
+
const now = ch.now ?? (() => Date.now());
|
|
720
|
+
const s = scan.status();
|
|
721
|
+
const run = s.run;
|
|
722
|
+
if (run === null || run.state !== "running")
|
|
723
|
+
return { ok: false, errors: ["no scan is recorded as running"] };
|
|
724
|
+
if (s.active) {
|
|
725
|
+
const r = scan.stop();
|
|
726
|
+
if (!r.ok) return r;
|
|
727
|
+
return { ok: true, run: r.id, answer: `scan ${r.id} stopped — what finished is in the ledger` };
|
|
728
|
+
}
|
|
729
|
+
const asked = clickStopScan(ch.home, run.id, new Date(now()), ch.by ?? "companion");
|
|
730
|
+
if (!asked.ok) return { ok: false, errors: [asked.line] };
|
|
731
|
+
const t0 = now();
|
|
732
|
+
for (;;) {
|
|
733
|
+
const answer = scanStopOutcome(ch.home, asked.request);
|
|
734
|
+
if (answer !== null) {
|
|
735
|
+
const read = readStopResult(ch.home);
|
|
736
|
+
const ok =
|
|
737
|
+
read.kind === "read" && read.result.request === asked.request && read.result.ok === true;
|
|
738
|
+
return ok ? { ok: true, run: run.id, answer } : { ok: false, errors: [answer] };
|
|
739
|
+
}
|
|
740
|
+
if (now() - t0 >= STOP_WAIT_MS)
|
|
741
|
+
return {
|
|
742
|
+
ok: false,
|
|
743
|
+
errors: [
|
|
744
|
+
`no process answered the stop of ${run.id} within ${STOP_WAIT_MS / 1000}s — nothing is driving it ` +
|
|
745
|
+
"(it reads as interrupted); preview and start again to resume",
|
|
746
|
+
],
|
|
747
|
+
};
|
|
748
|
+
await sleep(STOP_POLL_MS);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// ---- tool belt ---------------------------------------------------------------
|
|
753
|
+
|
|
754
|
+
const DELTA_PARAM = {
|
|
755
|
+
type: "boolean",
|
|
756
|
+
description:
|
|
757
|
+
"A DELTA re-scan: the files whose content changed since the last scan, plus any not yet read whole (priced from the ledger; never before calibration).",
|
|
758
|
+
} as const;
|
|
759
|
+
|
|
760
|
+
const SHA_PARAM = {
|
|
761
|
+
type: "string",
|
|
762
|
+
description:
|
|
763
|
+
"The commit to scan: a sha or ref of the reviewed checkout (default HEAD). The tree AT that commit is read.",
|
|
764
|
+
} as const;
|
|
765
|
+
|
|
766
|
+
export function scanToolDefinitions(
|
|
767
|
+
scan: ScanRunner,
|
|
768
|
+
findings: FindingsStore,
|
|
769
|
+
settingsOf: () => ScanSettings | null = () => null,
|
|
770
|
+
/** After a match answer: close the tickets of the promoted findings it
|
|
771
|
+
* fixed (`ScanTriage.closeFixed`). */
|
|
772
|
+
afterMatch: (() => Promise<CloseFixedResult>) | null = null,
|
|
773
|
+
/** Where a stop of a run another process drives goes; null: only a run
|
|
774
|
+
* this companion drives can be stopped. */
|
|
775
|
+
stopChannel: StopChannel | null = null,
|
|
776
|
+
): QcrTool[] {
|
|
777
|
+
const preview: QcrTool = {
|
|
778
|
+
name: "scan_preview",
|
|
779
|
+
label: "Scan preview",
|
|
780
|
+
description:
|
|
781
|
+
"What scan stage 1 would read at a commit and what it would cost: pass-scan over every unit of the saved unit cut (tests, migrations, " +
|
|
782
|
+
"excluded globs and files the coverage ledger already holds left out). On a repo never priced at these settings it offers the " +
|
|
783
|
+
"CALIBRATION run instead — a few units, a small hard cap — whose measured cost prices every later preview. Free: it runs nothing. " +
|
|
784
|
+
'Under [scan] depth = "deep" it plans a DEEP stage 1: pass-scan names a deep lens for every file, and a file only a standard ' +
|
|
785
|
+
"reading covers is read again. Show the operator the cost before starting anything.",
|
|
786
|
+
promptSnippet: "Preview a scan's cases and cost",
|
|
787
|
+
parameters: { type: "object", properties: { sha: SHA_PARAM, delta: DELTA_PARAM } },
|
|
788
|
+
execute: async (_id, params) => {
|
|
789
|
+
const r = await scan.preview({
|
|
790
|
+
sha: typeof params?.sha === "string" ? params.sha : undefined,
|
|
791
|
+
delta: params?.delta === true,
|
|
792
|
+
});
|
|
793
|
+
if (!r.ok) return refused("Scan preview", r);
|
|
794
|
+
return text(renderPreview(r.preview), { preview: previewDetails(r.preview) });
|
|
795
|
+
},
|
|
796
|
+
};
|
|
797
|
+
const start: QcrTool = {
|
|
798
|
+
name: "scan_start",
|
|
799
|
+
label: "Start a scan",
|
|
800
|
+
description:
|
|
801
|
+
"Start exactly the run a scan_preview showed — pass its key (and the same sha). It runs in the background as subagents and stops " +
|
|
802
|
+
"HARD at the previewed estimate (the calibration cap for a calibration run). Refused if anything moved since the preview. Only after " +
|
|
803
|
+
"the operator agreed to the cost ('do it').",
|
|
804
|
+
promptSnippet: "Start the previewed scan",
|
|
805
|
+
parameters: {
|
|
806
|
+
type: "object",
|
|
807
|
+
properties: { key: { type: "string" }, sha: SHA_PARAM, delta: DELTA_PARAM },
|
|
808
|
+
required: ["key"],
|
|
809
|
+
},
|
|
810
|
+
execute: async (_id, params) => {
|
|
811
|
+
const r = await scan.start({
|
|
812
|
+
key: params?.key,
|
|
813
|
+
sha: typeof params?.sha === "string" ? params.sha : undefined,
|
|
814
|
+
delta: params?.delta === true,
|
|
815
|
+
});
|
|
816
|
+
if (!r.ok) return refused("Scan start", r);
|
|
817
|
+
return text(startedLine(r.run), { run: startedDetails(r.run) });
|
|
818
|
+
},
|
|
819
|
+
};
|
|
820
|
+
const status: QcrTool = {
|
|
821
|
+
name: "scan_status",
|
|
822
|
+
label: "Scan status",
|
|
823
|
+
description:
|
|
824
|
+
"The latest scan run — cases done, findings, spend against its hard cap — and the coverage ledger's totals.",
|
|
825
|
+
promptSnippet: "Show the scan's progress",
|
|
826
|
+
parameters: NO_PARAMS,
|
|
827
|
+
execute: async () => {
|
|
828
|
+
const s = scan.status();
|
|
829
|
+
return text(renderStatus(s), {
|
|
830
|
+
status: { ...s, run: s.run ? { ...s.run, cases: undefined } : null },
|
|
831
|
+
});
|
|
832
|
+
},
|
|
833
|
+
};
|
|
834
|
+
const stop: QcrTool = {
|
|
835
|
+
name: "scan_stop",
|
|
836
|
+
label: "Stop the scan",
|
|
837
|
+
description:
|
|
838
|
+
"Stop the running scan: in-flight cases are aborted, no more start. Finished cases stay in the ledger, so a later start resumes.",
|
|
839
|
+
promptSnippet: "Stop the running scan",
|
|
840
|
+
parameters: NO_PARAMS,
|
|
841
|
+
execute: async () => {
|
|
842
|
+
if (stopChannel !== null && !scan.status().active) {
|
|
843
|
+
const via = await stopScan(scan, stopChannel);
|
|
844
|
+
return via.ok ? text(via.answer) : refused("Scan stop", via);
|
|
845
|
+
}
|
|
846
|
+
const r = scan.stop();
|
|
847
|
+
if (!r.ok) return refused("Scan stop", r);
|
|
848
|
+
return text(
|
|
849
|
+
`Stopping scan ${r.id}. What finished is kept; preview and start again to resume.`,
|
|
850
|
+
);
|
|
851
|
+
},
|
|
852
|
+
};
|
|
853
|
+
const list: QcrTool = {
|
|
854
|
+
name: "scan_findings",
|
|
855
|
+
label: "Scan findings",
|
|
856
|
+
description:
|
|
857
|
+
"The stored scan findings, grouped by the skeptic's validity tier — confirmed, then likely, then doubtful, then unknown (never " +
|
|
858
|
+
"judged) — most severe first inside each, each with its fingerprint. A new finding marked LOOKS LIKE DISMISSED resembles one the " +
|
|
859
|
+
"operator dismissed (named, with the reason) and sorts below its tier: it is NOT dismissed — put the resemblance to him, never " +
|
|
860
|
+
"dismiss it on his behalf. Filter by validity (confirmed/likely/doubtful/unknown), state " +
|
|
861
|
+
"(new/promoted/dismissed/fixed), lens, unit, severity, or doubted (true: only those marked 'may not be valid').",
|
|
862
|
+
promptSnippet: "List stored scan findings",
|
|
863
|
+
parameters: {
|
|
864
|
+
type: "object",
|
|
865
|
+
properties: {
|
|
866
|
+
state: { type: "string" },
|
|
867
|
+
lens: { type: "string" },
|
|
868
|
+
unit: { type: "string" },
|
|
869
|
+
severity: { type: "string" },
|
|
870
|
+
doubted: { type: "boolean" },
|
|
871
|
+
validity: { type: "string", description: "confirmed | likely | doubtful | unknown" },
|
|
872
|
+
limit: { type: "number" },
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
execute: async (_id, params) => {
|
|
876
|
+
const p = params ?? {};
|
|
877
|
+
const f = findingsFilter(p);
|
|
878
|
+
if (!f.ok) return text(f.error);
|
|
879
|
+
const listed = listFindings(findings, f.filter);
|
|
880
|
+
if (!listed.ok) return text(`✗ ${listed.error}`);
|
|
881
|
+
const fs = listed.findings;
|
|
882
|
+
const limit =
|
|
883
|
+
typeof p.limit === "number" && p.limit > 0
|
|
884
|
+
? Math.min(FINDINGS_LIMIT_MAX, Math.floor(p.limit))
|
|
885
|
+
: FINDINGS_LIMIT;
|
|
886
|
+
return text(renderFindings(fs.slice(0, limit), fs.length), {
|
|
887
|
+
total: fs.length,
|
|
888
|
+
validity: listed.validity,
|
|
889
|
+
});
|
|
890
|
+
},
|
|
891
|
+
};
|
|
892
|
+
const matches: QcrTool = {
|
|
893
|
+
name: "scan_matches",
|
|
894
|
+
label: "Scan match question",
|
|
895
|
+
description:
|
|
896
|
+
"The pending match question: findings a re-scan no longer reports exactly (their file changed or went away), beside the fresh " +
|
|
897
|
+
"findings of the same lens that might be them moved or reworded. Exact fingerprints were matched already and anything no fresh " +
|
|
898
|
+
"finding could be is fixed already — only these need your judgement.",
|
|
899
|
+
promptSnippet: "Show findings waiting on a sameness call",
|
|
900
|
+
parameters: NO_PARAMS,
|
|
901
|
+
execute: async () => {
|
|
902
|
+
const { question, error } = findings.question();
|
|
903
|
+
if (error !== null) return text(`✗ ${error}`);
|
|
904
|
+
return text(renderQuestion(question), { key: question?.key ?? null });
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
const match: QcrTool = {
|
|
908
|
+
name: "scan_match",
|
|
909
|
+
label: "Answer the match question",
|
|
910
|
+
description:
|
|
911
|
+
"Answer the pending match question WHOLE: its key, and the pairs {old, new} (fingerprints) that are the same finding. A pair keeps " +
|
|
912
|
+
"the old finding's state (dismissed stays dismissed, promoted stays promoted) under the new wording and position. Every unpaired " +
|
|
913
|
+
"old finding becomes fixed (an unpaired dismissed finding stays dismissed); every unpaired fresh one stays new. An empty `pairs` means none are the same. Refused whole on a stale key.",
|
|
914
|
+
promptSnippet: "Settle which re-scan findings are the same as old ones",
|
|
915
|
+
parameters: {
|
|
916
|
+
type: "object",
|
|
917
|
+
properties: {
|
|
918
|
+
key: { type: "string" },
|
|
919
|
+
pairs: {
|
|
920
|
+
type: "array",
|
|
921
|
+
items: {
|
|
922
|
+
type: "object",
|
|
923
|
+
properties: { old: { type: "string" }, new: { type: "string" } },
|
|
924
|
+
required: ["old", "new"],
|
|
925
|
+
},
|
|
926
|
+
},
|
|
927
|
+
},
|
|
928
|
+
required: ["key"],
|
|
929
|
+
},
|
|
930
|
+
execute: async (_id, params) => {
|
|
931
|
+
const r = await answerMatch(
|
|
932
|
+
findings,
|
|
933
|
+
{ key: params?.key, pairs: params?.pairs ?? [] },
|
|
934
|
+
afterMatch,
|
|
935
|
+
);
|
|
936
|
+
if (!r.ok) return refused("Match", r);
|
|
937
|
+
const { tickets, lines, ...result } = r;
|
|
938
|
+
return text(lines.join("\n"), { ...result, tickets_closed: tickets?.closed.length ?? 0 });
|
|
939
|
+
},
|
|
940
|
+
};
|
|
941
|
+
const suggestions: QcrTool = {
|
|
942
|
+
name: "scan_suggestions",
|
|
943
|
+
label: "Scan stage 2 suggestions",
|
|
944
|
+
description:
|
|
945
|
+
"Stage 1's stored deep-lens suggestions (lens, files, why) grouped by lens, and the deep lenses and tiers stage 2 may use on this " +
|
|
946
|
+
"repo. Read them before proposing stage 2.",
|
|
947
|
+
promptSnippet: "List stage 1's deep-lens suggestions",
|
|
948
|
+
parameters: NO_PARAMS,
|
|
949
|
+
execute: async () => {
|
|
950
|
+
const { suggestions: sugs, error } = scan.suggestions();
|
|
951
|
+
if (error !== null) return text(`✗ ${error}`);
|
|
952
|
+
const s = settingsOf();
|
|
953
|
+
return text(renderSuggestions(sugs, s), { suggestions: sugs.length });
|
|
954
|
+
},
|
|
955
|
+
};
|
|
956
|
+
const propose: QcrTool = {
|
|
957
|
+
name: "scan_stage2_propose",
|
|
958
|
+
label: "Propose scan stage 2",
|
|
959
|
+
description:
|
|
960
|
+
"Propose stage 2 — the scan's deep, targeted plan — as rows: each a set of files, ONE deep lens, a tier (optional) and a one-line " +
|
|
961
|
+
"reason, most valuable first. A row may span units (cross-cutting problems live between them). Name code only: each code file's " +
|
|
962
|
+
"tests are paired in automatically. Give budget_usd to fit the plan to a budget (rows that do not fit are left out). Every row is " +
|
|
963
|
+
"priced from the coverage ledger; the proposal is stored (the TUI shows it) and runs nothing. Refused as a whole if any row is bad. " +
|
|
964
|
+
'A DEEP proposal ([scan] depth = "deep", or deep: true; deep: false makes it standard) adds the floor after your rows — every ' +
|
|
965
|
+
"[scan] deep_lenses lens over every file stage 1 reads, priced and fitted like any row — so your rows may be none; every lens digs " +
|
|
966
|
+
"past its row's files, and only a deep reading covers a file.",
|
|
967
|
+
promptSnippet: "Propose a priced stage-2 plan",
|
|
968
|
+
parameters: {
|
|
969
|
+
type: "object",
|
|
970
|
+
properties: {
|
|
971
|
+
rows: {
|
|
972
|
+
type: "array",
|
|
973
|
+
items: {
|
|
974
|
+
type: "object",
|
|
975
|
+
properties: {
|
|
976
|
+
lens: { type: "string" },
|
|
977
|
+
files: { type: "array", items: { type: "string" } },
|
|
978
|
+
tier: { type: "string" },
|
|
979
|
+
reason: { type: "string" },
|
|
980
|
+
},
|
|
981
|
+
required: ["lens", "files", "reason"],
|
|
982
|
+
},
|
|
983
|
+
},
|
|
984
|
+
budget_usd: { type: "number" },
|
|
985
|
+
sha: SHA_PARAM,
|
|
986
|
+
deep: {
|
|
987
|
+
type: "boolean",
|
|
988
|
+
description:
|
|
989
|
+
"true: a DEEP proposal (the floor after your rows, every lens told to dig, coverage only from deep readings); false: a " +
|
|
990
|
+
"standard one, no floor. Left out: [scan] depth decides.",
|
|
991
|
+
},
|
|
992
|
+
},
|
|
993
|
+
required: ["rows"],
|
|
994
|
+
},
|
|
995
|
+
execute: async (_id, params) => {
|
|
996
|
+
const r = await scan.proposeStage2({
|
|
997
|
+
rows: params?.rows,
|
|
998
|
+
budget_usd: params?.budget_usd,
|
|
999
|
+
sha: typeof params?.sha === "string" ? params.sha : undefined,
|
|
1000
|
+
...(params?.deep !== undefined ? { deep: params.deep } : {}),
|
|
1001
|
+
});
|
|
1002
|
+
if (!r.ok) return refused("Stage 2 proposal", r);
|
|
1003
|
+
return text(renderProposal(r.proposal), { proposal: proposalDetails(r.proposal) });
|
|
1004
|
+
},
|
|
1005
|
+
};
|
|
1006
|
+
const start2: QcrTool = {
|
|
1007
|
+
name: "scan_stage2_start",
|
|
1008
|
+
label: "Start scan stage 2",
|
|
1009
|
+
description:
|
|
1010
|
+
"Start the stored stage-2 proposal by its key — only after the operator agreed to its cost ('do it'). It runs in the background, " +
|
|
1011
|
+
"one case per row, and stops HARD at the proposal's estimate. Give rows (row ids from the proposal) to run only those — the " +
|
|
1012
|
+
"operator's narrowed 'do it' ('only the security rows'): each must be a runnable row, and the hard stop is their total. " +
|
|
1013
|
+
"Refused if the proposal moved since it was shown.",
|
|
1014
|
+
promptSnippet: "Start the proposed stage 2",
|
|
1015
|
+
parameters: {
|
|
1016
|
+
type: "object",
|
|
1017
|
+
properties: { key: { type: "string" }, rows: { type: "array", items: { type: "string" } } },
|
|
1018
|
+
required: ["key"],
|
|
1019
|
+
},
|
|
1020
|
+
execute: async (_id, params) => {
|
|
1021
|
+
// The engine validates `rows` (a list of runnable row ids, not empty —
|
|
1022
|
+
// `keptRows`, the TUI click's own rule) and re-plans before it starts.
|
|
1023
|
+
const r = await scan.startStage2({
|
|
1024
|
+
key: params?.key,
|
|
1025
|
+
...(params?.rows !== undefined ? { rows: params.rows } : {}),
|
|
1026
|
+
});
|
|
1027
|
+
if (!r.ok) return refused("Stage 2 start", r);
|
|
1028
|
+
const runnable = scan.stage2Proposal().proposal?.runnable ?? null;
|
|
1029
|
+
const narrowed = params?.rows !== undefined && params?.rows !== null;
|
|
1030
|
+
return text(stage2StartedLine(r.run, runnable, narrowed), {
|
|
1031
|
+
run: startedDetails(r.run),
|
|
1032
|
+
});
|
|
1033
|
+
},
|
|
1034
|
+
};
|
|
1035
|
+
return [preview, start, status, stop, list, matches, match, suggestions, propose, start2];
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/** How often the belt looks for the TUI's requests (a stage-2 start click,
|
|
1039
|
+
* a stop). */
|
|
1040
|
+
export const STAGE2_POLL_MS = 2000;
|
|
1041
|
+
|
|
1042
|
+
/** Answer the TUI's requests while the companion runs: the stage-2 start
|
|
1043
|
+
* click starts the stored proposal it showed, exactly as the operator's word
|
|
1044
|
+
* would, and the `[8] scan` tab's stop stops the run it showed running,
|
|
1045
|
+
* exactly as scan_stop would. Returns the stop. */
|
|
1046
|
+
export function watchTuiRequests(
|
|
1047
|
+
scan: ScanRunner,
|
|
1048
|
+
everyMs = STAGE2_POLL_MS,
|
|
1049
|
+
/** false: answer only the stop — a `qcr scan` driver leaves the stage-2
|
|
1050
|
+
* start click to the companion. */
|
|
1051
|
+
opts: { stage2?: boolean } = {},
|
|
1052
|
+
): () => void {
|
|
1053
|
+
const timer = setInterval(() => {
|
|
1054
|
+
try {
|
|
1055
|
+
scan.consumeStopRequest();
|
|
1056
|
+
} catch (err) {
|
|
1057
|
+
console.error(`setup: scan stop request failed: ${String(err)}`);
|
|
1058
|
+
}
|
|
1059
|
+
if (opts.stage2 === false) return;
|
|
1060
|
+
scan
|
|
1061
|
+
.consumeStage2Request()
|
|
1062
|
+
.catch((err: unknown) =>
|
|
1063
|
+
console.error(`setup: stage 2 start request failed: ${String(err)}`),
|
|
1064
|
+
);
|
|
1065
|
+
}, everyMs);
|
|
1066
|
+
timer.unref?.();
|
|
1067
|
+
return () => clearInterval(timer);
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// ---- assembly ------------------------------------------------------------------
|
|
1071
|
+
|
|
1072
|
+
/** Where the scan driver's SDK leaves come from: built on first use, by
|
|
1073
|
+
* whoever owns the process they run in (scancli's detached driver). */
|
|
1074
|
+
export type SdkLeaves = (o: {
|
|
1075
|
+
agentsDir: string;
|
|
1076
|
+
cwd: string;
|
|
1077
|
+
transcriptDir: string;
|
|
1078
|
+
env: NodeJS.ProcessEnv;
|
|
1079
|
+
onExpired: (reason: string) => void;
|
|
1080
|
+
}) => CaseRunner | Promise<CaseRunner>;
|
|
1081
|
+
|
|
1082
|
+
/** The scan leaf runner: the driver's SDK runner (`sdkLeaves`, built on first
|
|
1083
|
+
* use). A process that has none — the companion's own pi, which must never host
|
|
1084
|
+
* SDK sessions — refuses every case instead. The config is read per case, as
|
|
1085
|
+
* `settingsOf` reads the live config; an unreadable config runs the process
|
|
1086
|
+
* runner (`piCaseRunner`), the runner's behaviour before the key existed. */
|
|
1087
|
+
export function scanLeafRunner(
|
|
1088
|
+
proc: CaseRunner,
|
|
1089
|
+
root: string,
|
|
1090
|
+
env: NodeJS.ProcessEnv,
|
|
1091
|
+
sdkLeaves?: () => CaseRunner | Promise<CaseRunner>,
|
|
1092
|
+
): CaseRunner {
|
|
1093
|
+
let sdk: Promise<CaseRunner> | undefined;
|
|
1094
|
+
return {
|
|
1095
|
+
async run(spec, signal, onCost) {
|
|
1096
|
+
const loaded = loadScanConfig(root, env);
|
|
1097
|
+
// `[pi] lens_runtime` is not read here: a scan leaf is a leaf and never
|
|
1098
|
+
// gets a lens tool, so the key (engine by default) changes nothing.
|
|
1099
|
+
if (!loaded.ok) return proc.run(spec, signal, onCost);
|
|
1100
|
+
if (sdkLeaves === undefined)
|
|
1101
|
+
return {
|
|
1102
|
+
ok: false,
|
|
1103
|
+
reason:
|
|
1104
|
+
"[engine] runtime = sdk is not available on the scan route in this process: scan leaves run on the SDK only in the `qcr scan` driver",
|
|
1105
|
+
cost_usd: 0,
|
|
1106
|
+
};
|
|
1107
|
+
try {
|
|
1108
|
+
sdk ??= Promise.resolve(sdkLeaves());
|
|
1109
|
+
return (await sdk).run(spec, signal, onCost);
|
|
1110
|
+
} catch (err) {
|
|
1111
|
+
sdk = undefined;
|
|
1112
|
+
return {
|
|
1113
|
+
ok: false,
|
|
1114
|
+
reason: `the SDK leaf runner could not be built: ${err instanceof Error ? err.message : String(err)}`,
|
|
1115
|
+
cost_usd: 0,
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
/** The scan runner the companion's belt drives: the reviewed checkout as a
|
|
1123
|
+
* source of trees, the state home for every record, the saved unit cut from
|
|
1124
|
+
* the setup engine, the live config under the profile, and a case runner
|
|
1125
|
+
* over the scan agent build — and the triage over its findings:
|
|
1126
|
+
* reviewer memory and the tracker sink are the engine's own, handed in. */
|
|
1127
|
+
export function buildScan(
|
|
1128
|
+
engine: SetupEngine,
|
|
1129
|
+
reviewedRepo: string,
|
|
1130
|
+
env: NodeJS.ProcessEnv,
|
|
1131
|
+
shared: { memory: MemoryStore | null; tracker: TrackerSink } | null = null,
|
|
1132
|
+
/** The driver lease; default the state home's file lease, shared with every
|
|
1133
|
+
* other runner over it. */
|
|
1134
|
+
lease: ScanLease | null = null,
|
|
1135
|
+
/** The SDK leaf runner, in a process that may host one (scancli's detached
|
|
1136
|
+
* driver). Omitted — the companion's pi — a scan on `[engine] runtime = sdk`
|
|
1137
|
+
* refuses its cases. */
|
|
1138
|
+
sdkLeaves?: SdkLeaves,
|
|
1139
|
+
): {
|
|
1140
|
+
scan: ScanRunner;
|
|
1141
|
+
findings: FindingsStore;
|
|
1142
|
+
settingsOf: () => ScanSettings | null;
|
|
1143
|
+
triage: ScanTriage | null;
|
|
1144
|
+
home: string;
|
|
1145
|
+
} {
|
|
1146
|
+
const root = env.QCR_ROOT?.trim() || sandboxRoot();
|
|
1147
|
+
const home = stateHome(env);
|
|
1148
|
+
const state = stateHomeFs(home);
|
|
1149
|
+
const agentsDir = join(home, SCAN_AGENTS_DIR);
|
|
1150
|
+
const settingsOf = (): ScanSettings | null => {
|
|
1151
|
+
const loaded = loadScanConfig(root, env);
|
|
1152
|
+
return loaded.ok ? scanSettings(loaded.cfg) : null;
|
|
1153
|
+
};
|
|
1154
|
+
const findings = new FindingsStore(state);
|
|
1155
|
+
const transcriptDir = join(home, SCAN_TRANSCRIPTS_DIR);
|
|
1156
|
+
// A token a case would not outlive stops the run, on either host.
|
|
1157
|
+
const stopOnExpired = (reason: string): void => {
|
|
1158
|
+
console.error(`scan: stopping — ${reason}`);
|
|
1159
|
+
scan.stop();
|
|
1160
|
+
};
|
|
1161
|
+
// Assigned below: the triage reads the runner's runs, the runner closes
|
|
1162
|
+
// the triage's tickets at every run's end.
|
|
1163
|
+
let triage: ScanTriage | null = null;
|
|
1164
|
+
const scan = new ScanRunner({
|
|
1165
|
+
state,
|
|
1166
|
+
clock: () => new Date(),
|
|
1167
|
+
// In the scan container: each case on a fresh refresh-disabled copy of
|
|
1168
|
+
// the companion's login; a token a case would not outlive stops the run.
|
|
1169
|
+
cases: scanCasesForEnv(
|
|
1170
|
+
scanLeafRunner(
|
|
1171
|
+
piCaseRunner({ agentsDir, cwd: root, transcriptDir }),
|
|
1172
|
+
root,
|
|
1173
|
+
env,
|
|
1174
|
+
sdkLeaves &&
|
|
1175
|
+
(() => sdkLeaves({ agentsDir, cwd: root, transcriptDir, env, onExpired: stopOnExpired })),
|
|
1176
|
+
),
|
|
1177
|
+
env,
|
|
1178
|
+
stopOnExpired,
|
|
1179
|
+
),
|
|
1180
|
+
source: gitScanSource(reviewedRepo, home),
|
|
1181
|
+
savedCut: () => {
|
|
1182
|
+
const cut = engine.savedCut();
|
|
1183
|
+
if (cut) return { ok: true, cut };
|
|
1184
|
+
const status = engine.status();
|
|
1185
|
+
return {
|
|
1186
|
+
ok: false,
|
|
1187
|
+
errors: status.cut_file_unreadable
|
|
1188
|
+
? status.problems
|
|
1189
|
+
: ["no saved unit cut — a scan reads by unit; propose, adjust and save one first"],
|
|
1190
|
+
};
|
|
1191
|
+
},
|
|
1192
|
+
settings: () => {
|
|
1193
|
+
const loaded = loadScanConfig(root, env);
|
|
1194
|
+
return loaded.ok ? { ok: true, settings: scanSettings(loaded.cfg) } : loaded;
|
|
1195
|
+
},
|
|
1196
|
+
// At the depth the runner planned at — a stage-2 proposal's own, which
|
|
1197
|
+
// its `deep` may have set apart from `[scan] depth`.
|
|
1198
|
+
buildAgents: (settings) => {
|
|
1199
|
+
const loaded = loadScanConfig(root, env);
|
|
1200
|
+
if (!loaded.ok) return loaded;
|
|
1201
|
+
const cfg = { ...loaded.cfg, scan: { ...loaded.cfg.scan, depth: settings.scan.depth } };
|
|
1202
|
+
try {
|
|
1203
|
+
buildScanAgents(root, agentsDir, cfg, homeProfileLookup(env));
|
|
1204
|
+
return { ok: true };
|
|
1205
|
+
} catch (err) {
|
|
1206
|
+
return { ok: false, errors: [err instanceof Error ? err.message : String(err)] };
|
|
1207
|
+
}
|
|
1208
|
+
},
|
|
1209
|
+
closeFixedTickets: async () => (triage ? triage.closeFixed() : { closed: [], problems: [] }),
|
|
1210
|
+
lease: lease ?? fileLease(home),
|
|
1211
|
+
log: (line) => console.error(line),
|
|
1212
|
+
});
|
|
1213
|
+
if (shared) {
|
|
1214
|
+
triage = new ScanTriage({
|
|
1215
|
+
findings,
|
|
1216
|
+
state,
|
|
1217
|
+
memory: shared.memory,
|
|
1218
|
+
tracker: shared.tracker,
|
|
1219
|
+
clock: () => new Date(),
|
|
1220
|
+
units: () => engine.savedCut()?.units.map((u) => u.name) ?? null,
|
|
1221
|
+
runs: () => scanRuns(scan),
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
return { scan, findings, settingsOf, triage, home };
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/** The runner's runs, newest first, as the triage sees them: a run left
|
|
1228
|
+
* `running` by a companion that is gone reads as interrupted. */
|
|
1229
|
+
export function scanRuns(scan: ScanRunner): Array<{ id: string; sha: string; state: string }> {
|
|
1230
|
+
const s = scan.status();
|
|
1231
|
+
const out: Array<{ id: string; sha: string; state: string }> = [];
|
|
1232
|
+
if (s.run) out.push({ id: s.run.id, sha: s.run.sha, state: s.run.display });
|
|
1233
|
+
for (const h of s.history)
|
|
1234
|
+
if (!out.some((r) => r.id === h.id)) out.push({ id: h.id, sha: h.sha, state: h.state });
|
|
1235
|
+
return out;
|
|
1236
|
+
}
|