wicked-crew 0.7.40 → 0.7.45
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/dist/api/audit.d.ts +3 -0
- package/dist/api/audit.d.ts.map +1 -1
- package/dist/api/audit.js +2 -0
- package/dist/api/audit.js.map +1 -1
- package/dist/api/capture.d.ts +149 -0
- package/dist/api/capture.d.ts.map +1 -0
- package/dist/api/capture.js +330 -0
- package/dist/api/capture.js.map +1 -0
- package/dist/api/chat-citations.d.ts +174 -0
- package/dist/api/chat-citations.d.ts.map +1 -0
- package/dist/api/chat-citations.js +528 -0
- package/dist/api/chat-citations.js.map +1 -0
- package/dist/api/chat-transcripts.d.ts +20 -1
- package/dist/api/chat-transcripts.d.ts.map +1 -1
- package/dist/api/chat-transcripts.js +29 -0
- package/dist/api/chat-transcripts.js.map +1 -1
- package/dist/api/delivery-cache.d.ts +2 -2
- package/dist/api/delivery-freeze.d.ts +66 -0
- package/dist/api/delivery-freeze.d.ts.map +1 -0
- package/dist/api/delivery-freeze.js +104 -0
- package/dist/api/delivery-freeze.js.map +1 -0
- package/dist/api/delivery-index.d.ts +53 -9
- package/dist/api/delivery-index.d.ts.map +1 -1
- package/dist/api/delivery-index.js +115 -22
- package/dist/api/delivery-index.js.map +1 -1
- package/dist/api/demo.d.ts +90 -0
- package/dist/api/demo.d.ts.map +1 -0
- package/dist/api/demo.js +492 -0
- package/dist/api/demo.js.map +1 -0
- package/dist/api/diagnostics.d.ts +64 -1
- package/dist/api/diagnostics.d.ts.map +1 -1
- package/dist/api/diagnostics.js +129 -1
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/eval-sample.d.ts +6 -6
- package/dist/api/governance-steering.d.ts +2 -2
- package/dist/api/mcp.d.ts +282 -0
- package/dist/api/mcp.d.ts.map +1 -0
- package/dist/api/mcp.js +521 -0
- package/dist/api/mcp.js.map +1 -0
- package/dist/api/plan-schema.d.ts +56 -0
- package/dist/api/plan-schema.d.ts.map +1 -0
- package/dist/api/plan-schema.js +26 -0
- package/dist/api/plan-schema.js.map +1 -0
- package/dist/api/roster-standing.d.ts +15 -2
- package/dist/api/roster-standing.d.ts.map +1 -1
- package/dist/api/roster-standing.js +55 -3
- package/dist/api/roster-standing.js.map +1 -1
- package/dist/api/routes.d.ts +630 -51
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +738 -127
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-files.d.ts.map +1 -1
- package/dist/api/run-files.js +31 -2
- package/dist/api/run-files.js.map +1 -1
- package/dist/api/run-liveness.d.ts +41 -0
- package/dist/api/run-liveness.d.ts.map +1 -0
- package/dist/api/run-liveness.js +166 -0
- package/dist/api/run-liveness.js.map +1 -0
- package/dist/api/seat-health.d.ts.map +1 -1
- package/dist/api/seat-health.js +20 -4
- package/dist/api/seat-health.js.map +1 -1
- package/dist/api/seat-probe.d.ts +141 -0
- package/dist/api/seat-probe.d.ts.map +1 -0
- package/dist/api/seat-probe.js +257 -0
- package/dist/api/seat-probe.js.map +1 -0
- package/dist/api/seat-record.d.ts +40 -0
- package/dist/api/seat-record.d.ts.map +1 -0
- package/dist/api/seat-record.js +218 -0
- package/dist/api/seat-record.js.map +1 -0
- package/dist/api/seat-signin.d.ts.map +1 -1
- package/dist/api/seat-signin.js +3 -1
- package/dist/api/seat-signin.js.map +1 -1
- package/dist/api/seat-standing.d.ts +24 -4
- package/dist/api/seat-standing.d.ts.map +1 -1
- package/dist/api/seat-standing.js +50 -3
- package/dist/api/seat-standing.js.map +1 -1
- package/dist/api/server.d.ts +34 -48
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +283 -107
- package/dist/api/server.js.map +1 -1
- package/dist/api/skills.d.ts +3 -1
- package/dist/api/skills.d.ts.map +1 -1
- package/dist/api/skills.js +7 -2
- package/dist/api/skills.js.map +1 -1
- package/dist/api/stall-watchdog.d.ts +34 -3
- package/dist/api/stall-watchdog.d.ts.map +1 -1
- package/dist/api/stall-watchdog.js +107 -8
- package/dist/api/stall-watchdog.js.map +1 -1
- package/dist/api/steering-landing.d.ts +6 -6
- package/dist/api/steering-landing.d.ts.map +1 -1
- package/dist/api/steering-landing.js +7 -9
- package/dist/api/steering-landing.js.map +1 -1
- package/dist/api/testing.d.ts +6 -4
- package/dist/api/testing.d.ts.map +1 -1
- package/dist/api/testing.js +82 -47
- package/dist/api/testing.js.map +1 -1
- package/dist/campaign/boot-resume.d.ts +34 -0
- package/dist/campaign/boot-resume.d.ts.map +1 -0
- package/dist/campaign/boot-resume.js +45 -0
- package/dist/campaign/boot-resume.js.map +1 -0
- package/dist/campaigns/rollup.d.ts +4 -1
- package/dist/campaigns/rollup.d.ts.map +1 -1
- package/dist/campaigns/rollup.js +6 -1
- package/dist/campaigns/rollup.js.map +1 -1
- package/dist/campaigns/routes.d.ts +2 -2
- package/dist/cli/bearer.d.ts +27 -1
- package/dist/cli/bearer.d.ts.map +1 -1
- package/dist/cli/bearer.js +62 -2
- package/dist/cli/bearer.js.map +1 -1
- package/dist/cli/governance.d.ts +11 -0
- package/dist/cli/governance.d.ts.map +1 -1
- package/dist/cli/governance.js +8 -2
- package/dist/cli/governance.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +140 -75
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +11 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +40 -9
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/service.d.ts +78 -0
- package/dist/cli/service.d.ts.map +1 -0
- package/dist/cli/service.js +334 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/core/adapter.d.ts +238 -12
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +619 -157
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-reaper.d.ts +4 -1
- package/dist/core/bridge-reaper.d.ts.map +1 -1
- package/dist/core/bridge-reaper.js +15 -1
- package/dist/core/bridge-reaper.js.map +1 -1
- package/dist/core/bus-notice.d.ts +27 -0
- package/dist/core/bus-notice.d.ts.map +1 -0
- package/dist/core/bus-notice.js +24 -0
- package/dist/core/bus-notice.js.map +1 -0
- package/dist/core/bus.d.ts +99 -0
- package/dist/core/bus.d.ts.map +1 -0
- package/dist/core/bus.js +176 -0
- package/dist/core/bus.js.map +1 -0
- package/dist/core/deliver-exclusions.d.ts +71 -0
- package/dist/core/deliver-exclusions.d.ts.map +1 -0
- package/dist/core/deliver-exclusions.js +110 -0
- package/dist/core/deliver-exclusions.js.map +1 -0
- package/dist/core/deliver-text.d.ts +61 -14
- package/dist/core/deliver-text.d.ts.map +1 -1
- package/dist/core/deliver-text.js +178 -30
- package/dist/core/deliver-text.js.map +1 -1
- package/dist/core/deliver-triage.d.ts +11 -2
- package/dist/core/deliver-triage.d.ts.map +1 -1
- package/dist/core/deliver-triage.js +19 -1
- package/dist/core/deliver-triage.js.map +1 -1
- package/dist/core/deliver.d.ts +161 -3
- package/dist/core/deliver.d.ts.map +1 -1
- package/dist/core/deliver.js +463 -25
- package/dist/core/deliver.js.map +1 -1
- package/dist/core/deliverable-floor.d.ts.map +1 -1
- package/dist/core/deliverable-floor.js +5 -7
- package/dist/core/deliverable-floor.js.map +1 -1
- package/dist/core/engine-bus.d.ts +40 -0
- package/dist/core/engine-bus.d.ts.map +1 -0
- package/dist/core/engine-bus.js +27 -0
- package/dist/core/engine-bus.js.map +1 -0
- package/dist/core/estate-mcp-client.d.ts +87 -5
- package/dist/core/estate-mcp-client.d.ts.map +1 -1
- package/dist/core/estate-mcp-client.js +90 -11
- package/dist/core/estate-mcp-client.js.map +1 -1
- package/dist/core/linked-issues.d.ts +46 -0
- package/dist/core/linked-issues.d.ts.map +1 -0
- package/dist/core/linked-issues.js +123 -0
- package/dist/core/linked-issues.js.map +1 -0
- package/dist/core/run-identity.d.ts +100 -0
- package/dist/core/run-identity.d.ts.map +1 -0
- package/dist/core/run-identity.js +178 -0
- package/dist/core/run-identity.js.map +1 -0
- package/dist/core/shutdown.d.ts +16 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +39 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/types.d.ts +15 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +4 -0
- package/dist/core/types.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts +67 -3
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +129 -13
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/interactive/bridge-root.d.ts +9 -0
- package/dist/interactive/bridge-root.d.ts.map +1 -1
- package/dist/interactive/bridge-root.js +11 -4
- package/dist/interactive/bridge-root.js.map +1 -1
- package/dist/interactive/chat-events.d.ts +14 -9
- package/dist/interactive/chat-events.d.ts.map +1 -1
- package/dist/interactive/chat-events.js +55 -57
- package/dist/interactive/chat-events.js.map +1 -1
- package/dist/interactive/council-outcome.d.ts +1 -0
- package/dist/interactive/council-outcome.d.ts.map +1 -1
- package/dist/interactive/council-outcome.js +33 -0
- package/dist/interactive/council-outcome.js.map +1 -1
- package/dist/interactive/draft-events.d.ts +36 -17
- package/dist/interactive/draft-events.d.ts.map +1 -1
- package/dist/interactive/draft-events.js +121 -92
- package/dist/interactive/draft-events.js.map +1 -1
- package/dist/interactive/draft-skill.d.ts +59 -0
- package/dist/interactive/draft-skill.d.ts.map +1 -1
- package/dist/interactive/draft-skill.js +233 -0
- package/dist/interactive/draft-skill.js.map +1 -1
- package/dist/interactive/edit-events.d.ts +1 -14
- package/dist/interactive/edit-events.d.ts.map +1 -1
- package/dist/interactive/edit-events.js +37 -70
- package/dist/interactive/edit-events.js.map +1 -1
- package/dist/interactive/proxy-routes.d.ts +2 -2
- package/dist/interactive/proxy-routes.d.ts.map +1 -1
- package/dist/interactive/proxy-routes.js +4 -13
- package/dist/interactive/proxy-routes.js.map +1 -1
- package/dist/interactive/ws-relay.d.ts +9 -10
- package/dist/interactive/ws-relay.d.ts.map +1 -1
- package/dist/interactive/ws-relay.js +23 -50
- package/dist/interactive/ws-relay.js.map +1 -1
- package/dist/mcp/broker.d.ts +88 -0
- package/dist/mcp/broker.d.ts.map +1 -0
- package/dist/mcp/broker.js +307 -0
- package/dist/mcp/broker.js.map +1 -0
- package/dist/mcp/call-records.d.ts +61 -0
- package/dist/mcp/call-records.d.ts.map +1 -0
- package/dist/mcp/call-records.js +135 -0
- package/dist/mcp/call-records.js.map +1 -0
- package/dist/mcp/classify.d.ts +45 -0
- package/dist/mcp/classify.d.ts.map +1 -0
- package/dist/mcp/classify.js +83 -0
- package/dist/mcp/classify.js.map +1 -0
- package/dist/mcp/discovery.d.ts +24 -0
- package/dist/mcp/discovery.d.ts.map +1 -0
- package/dist/mcp/discovery.js +78 -0
- package/dist/mcp/discovery.js.map +1 -0
- package/dist/mcp/invoke.d.ts +36 -0
- package/dist/mcp/invoke.d.ts.map +1 -0
- package/dist/mcp/invoke.js +80 -0
- package/dist/mcp/invoke.js.map +1 -0
- package/dist/mcp/policies.d.ts +110 -0
- package/dist/mcp/policies.d.ts.map +1 -0
- package/dist/mcp/policies.js +400 -0
- package/dist/mcp/policies.js.map +1 -0
- package/dist/mcp/probe.d.ts +66 -0
- package/dist/mcp/probe.d.ts.map +1 -0
- package/dist/mcp/probe.js +116 -0
- package/dist/mcp/probe.js.map +1 -0
- package/dist/mcp/redact.d.ts +34 -0
- package/dist/mcp/redact.d.ts.map +1 -0
- package/dist/mcp/redact.js +84 -0
- package/dist/mcp/redact.js.map +1 -0
- package/dist/mcp/registry-store.d.ts +69 -0
- package/dist/mcp/registry-store.d.ts.map +1 -0
- package/dist/mcp/registry-store.js +82 -0
- package/dist/mcp/registry-store.js.map +1 -0
- package/dist/mcp/registry.d.ts +147 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +509 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/rest.d.ts +111 -0
- package/dist/mcp/rest.d.ts.map +1 -0
- package/dist/mcp/rest.js +606 -0
- package/dist/mcp/rest.js.map +1 -0
- package/dist/mcp/secrets.d.ts +66 -0
- package/dist/mcp/secrets.d.ts.map +1 -0
- package/dist/mcp/secrets.js +180 -0
- package/dist/mcp/secrets.js.map +1 -0
- package/dist/mcp/tool-list.d.ts +25 -0
- package/dist/mcp/tool-list.d.ts.map +1 -0
- package/dist/mcp/tool-list.js +62 -0
- package/dist/mcp/tool-list.js.map +1 -0
- package/dist/mcp/upstream-error.d.ts +12 -0
- package/dist/mcp/upstream-error.d.ts.map +1 -0
- package/dist/mcp/upstream-error.js +14 -0
- package/dist/mcp/upstream-error.js.map +1 -0
- package/dist/mcp/usage.d.ts +31 -0
- package/dist/mcp/usage.d.ts.map +1 -0
- package/dist/mcp/usage.js +159 -0
- package/dist/mcp/usage.js.map +1 -0
- package/dist/presets/routes.d.ts +53 -0
- package/dist/presets/routes.d.ts.map +1 -0
- package/dist/presets/routes.js +115 -0
- package/dist/presets/routes.js.map +1 -0
- package/dist/projects/activity.d.ts +6 -18
- package/dist/projects/activity.d.ts.map +1 -1
- package/dist/projects/activity.js +17 -60
- package/dist/projects/activity.js.map +1 -1
- package/dist/projects/events.d.ts +6 -5
- package/dist/projects/events.d.ts.map +1 -1
- package/dist/projects/events.js +33 -58
- package/dist/projects/events.js.map +1 -1
- package/dist/projects/routes.d.ts.map +1 -1
- package/dist/projects/routes.js +19 -0
- package/dist/projects/routes.js.map +1 -1
- package/dist/projects/state-home-preflight.d.ts.map +1 -1
- package/dist/projects/state-home-preflight.js +7 -0
- package/dist/projects/state-home-preflight.js.map +1 -1
- package/dist/projects/state-home-registry.d.ts.map +1 -1
- package/dist/projects/state-home-registry.js +9 -1
- package/dist/projects/state-home-registry.js.map +1 -1
- package/dist/qe/acceptance.d.ts +28 -28
- package/dist/qe/acceptance.d.ts.map +1 -1
- package/dist/qe/acceptance.js +60 -61
- package/dist/qe/acceptance.js.map +1 -1
- package/dist/qe/test-sets.d.ts +3 -5
- package/dist/qe/test-sets.d.ts.map +1 -1
- package/dist/qe/test-sets.js +5 -7
- package/dist/qe/test-sets.js.map +1 -1
- package/dist/skills/installed.d.ts +51 -0
- package/dist/skills/installed.d.ts.map +1 -0
- package/dist/skills/installed.js +46 -0
- package/dist/skills/installed.js.map +1 -0
- package/dist/standing-orders/evaluator.d.ts +113 -0
- package/dist/standing-orders/evaluator.d.ts.map +1 -0
- package/dist/standing-orders/evaluator.js +225 -0
- package/dist/standing-orders/evaluator.js.map +1 -0
- package/dist/standing-orders/history.d.ts +58 -0
- package/dist/standing-orders/history.d.ts.map +1 -0
- package/dist/standing-orders/history.js +117 -0
- package/dist/standing-orders/history.js.map +1 -0
- package/dist/standing-orders/parse.d.ts +19 -0
- package/dist/standing-orders/parse.d.ts.map +1 -0
- package/dist/standing-orders/parse.js +75 -0
- package/dist/standing-orders/parse.js.map +1 -0
- package/dist/standing-orders/routes.d.ts +180 -0
- package/dist/standing-orders/routes.d.ts.map +1 -0
- package/dist/standing-orders/routes.js +95 -0
- package/dist/standing-orders/routes.js.map +1 -0
- package/dist/standing-orders/store.d.ts +154 -0
- package/dist/standing-orders/store.d.ts.map +1 -0
- package/dist/standing-orders/store.js +189 -0
- package/dist/standing-orders/store.js.map +1 -0
- package/dist/studio/assets/index-CvV5qITf.css +32 -0
- package/dist/studio/assets/index-jCOy6Ns7.js +568 -0
- package/dist/studio/index.html +3 -3
- package/dist/studio/testid-inventory.json +3274 -894
- package/dist/team/key.d.ts +5 -0
- package/dist/team/key.d.ts.map +1 -0
- package/dist/team/key.js +21 -0
- package/dist/team/key.js.map +1 -0
- package/dist/team/routes.d.ts +196 -0
- package/dist/team/routes.d.ts.map +1 -0
- package/dist/team/routes.js +274 -0
- package/dist/team/routes.js.map +1 -0
- package/dist/team/ws-relay.d.ts +39 -0
- package/dist/team/ws-relay.d.ts.map +1 -0
- package/dist/team/ws-relay.js +63 -0
- package/dist/team/ws-relay.js.map +1 -0
- package/endpoint-manifest.json +502 -6
- package/package.json +6 -6
- package/dist/interactive/demo-events.d.ts +0 -367
- package/dist/interactive/demo-events.d.ts.map +0 -1
- package/dist/interactive/demo-events.js +0 -1293
- package/dist/interactive/demo-events.js.map +0 -1
- package/dist/qe/gate-events.d.ts +0 -113
- package/dist/qe/gate-events.d.ts.map +0 -1
- package/dist/qe/gate-events.js +0 -172
- package/dist/qe/gate-events.js.map +0 -1
- package/dist/studio/assets/index-Bg7Z3BR-.css +0 -32
- package/dist/studio/assets/index-BvOFMjf9.js +0 -554
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat citation verification (crew#561, F-RC1-117 — Wave 1 criterion 2).
|
|
3
|
+
*
|
|
4
|
+
* # The defect
|
|
5
|
+
*
|
|
6
|
+
* A chat seat answers with citations — repo-relative paths, `path:line` refs, `path:symbol` refs
|
|
7
|
+
* and commit SHAs — and the daemon relays that text UNTOUCHED. On the RC1 Phase 6 re-run the
|
|
8
|
+
* opencode seat answered "summarize the last 10 commits across all 9 repos" with 26 SHAs, of which
|
|
9
|
+
* **2 did not exist in any repo**, and three line refs were off by a few lines. Every citation
|
|
10
|
+
* rendered as plain text, so a reader could not tell a real SHA from an invented one — and these
|
|
11
|
+
* are exactly the tokens a reader pastes into `git show`, a PR or a commit message.
|
|
12
|
+
*
|
|
13
|
+
* The daemon is the ONE place that can tell: it already knows the chat's read roots (the scope it
|
|
14
|
+
* handed the seats), and `stat` + `git cat-file -e` are cheap. So it verifies, and says what it
|
|
15
|
+
* found — it never edits the seat's text. Mark, don't rewrite.
|
|
16
|
+
*
|
|
17
|
+
* # What is verified
|
|
18
|
+
*
|
|
19
|
+
* | kind | citation | check |
|
|
20
|
+
* |----------|-----------------------------------|-------|
|
|
21
|
+
* | `path` | `crew/src/api/routes.ts` | the file exists under a read root |
|
|
22
|
+
* | `line` | `routes.ts:2264`, `x.ts:80-90` | the file exists AND has that many lines; when a symbol is named right before the ref, that the symbol is ON that line — otherwise the line it IS on, as a CORRECTION |
|
|
23
|
+
* | `symbol` | `execute_wrapped.rs:build_worker_command` | the file exists AND contains the symbol |
|
|
24
|
+
* | `sha` | `6d77153`, 7–40 hex | `git rev-parse --verify --quiet <sha>^{commit}` in the repo the text names, else in any read root |
|
|
25
|
+
*
|
|
26
|
+
* # Why a false positive is worse than a miss
|
|
27
|
+
*
|
|
28
|
+
* Prose looks like a path (`e.g`, `something.this`) and words look like SHAs. Flagging prose
|
|
29
|
+
* UNVERIFIED would train the reader to ignore the marks, which is worse than not marking. So:
|
|
30
|
+
*
|
|
31
|
+
* - a bare `name.ext` token with no directory and no `:line`/`:symbol` suffix that resolves
|
|
32
|
+
* nowhere is DROPPED, not marked — it was probably never a citation;
|
|
33
|
+
* - a hex run with no digit or no `a-f` letter is not a SHA candidate (`effaced` is a word; the
|
|
34
|
+
* price is that an all-digit short SHA — ~4% of 7-char prefixes — is not checked);
|
|
35
|
+
* - a token WITH a separator or a `:line`/`:symbol` suffix IS a citation: unresolvable means
|
|
36
|
+
* `unverified`, because that shape is not prose.
|
|
37
|
+
*
|
|
38
|
+
* # Bounded, and never in the reply's way
|
|
39
|
+
*
|
|
40
|
+
* The pass runs AFTER the `chatReply` frame is broadcast (`server.ts`), so a reply is never delayed
|
|
41
|
+
* by verification, and it is bounded twice: at most {@link DEFAULT_MAX_ITEMS} citations and
|
|
42
|
+
* {@link DEFAULT_BUDGET_MS} of wall clock. Whatever the budget did not reach is reported
|
|
43
|
+
* `unchecked` — a state of its own, never silently "verified".
|
|
44
|
+
*
|
|
45
|
+
* The verdicts ride `/ws` as ONE `chatCitations` frame per reply, stamped with the same `turn_id`
|
|
46
|
+
* the reply carries, and the studio marks the reply from it (badge + counter). The text on the wire
|
|
47
|
+
* and in the transcript is the seat's own.
|
|
48
|
+
*/
|
|
49
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
50
|
+
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
51
|
+
import { execCapped } from '../core/exec.js';
|
|
52
|
+
/** At most this many citations are checked per reply; the rest are `unchecked`. */
|
|
53
|
+
export const DEFAULT_MAX_ITEMS = 80;
|
|
54
|
+
/**
|
|
55
|
+
* Wall-clock budget for one reply's pass, ms. Overrun ⇒ the remainder is `unchecked`.
|
|
56
|
+
*
|
|
57
|
+
* 15 s, not 3: the pass runs entirely off the reply's path (nothing waits on it but the marks
|
|
58
|
+
* appearing a moment later), and the number worth protecting is COVERAGE, not latency. The RC1
|
|
59
|
+
* Phase 6 answer cited 26 SHAs over 9 repos — a fabricated one sweeps every root — and on a loaded
|
|
60
|
+
* desktop a `git cat-file` spawn is not always instant, so a 3 s budget would have reported most of
|
|
61
|
+
* that answer `unchecked`, which reads like the feature is not working. The budget exists so the
|
|
62
|
+
* work is BOUNDED, not so it is fast; it is re-read between citations AND between roots.
|
|
63
|
+
*/
|
|
64
|
+
export const DEFAULT_BUDGET_MS = 15_000;
|
|
65
|
+
/** Per-git-call timeout, ms. Generous on purpose: a spawn on a loaded desktop is not instant, and
|
|
66
|
+
* a timeout is an ERROR (`unchecked`), never an "absent" — the whole pass is bounded anyway. */
|
|
67
|
+
const GIT_TIMEOUT_MS = 10_000;
|
|
68
|
+
/** A file bigger than this is not read for a line/symbol check (it is a citation, not a corpus). */
|
|
69
|
+
const MAX_READ_BYTES = 4 * 1024 * 1024;
|
|
70
|
+
/** How far back a `line` citation looks for the symbol the sentence names. */
|
|
71
|
+
const SYMBOL_CONTEXT_CHARS = 200;
|
|
72
|
+
// ── Extraction ───────────────────────────────────────────────────────────────
|
|
73
|
+
/**
|
|
74
|
+
* A file-ish token with an optional `:line`, `:line-line` or `:symbol` suffix.
|
|
75
|
+
*
|
|
76
|
+
* The filename must carry an extension of 2–10 lowercase alphanumerics starting with a letter:
|
|
77
|
+
* that is what keeps `e.g`, `0.7.33` and a sentence's `end.Next` out (one char, digits first,
|
|
78
|
+
* uppercase respectively) while admitting `.ts`, `.rs`, `.md`, `.json`, `.tsx`, `.yml`.
|
|
79
|
+
*/
|
|
80
|
+
const PATH_RE = /(?<![\w/.:-])((?:[\w.-]+\/)*[\w-]+\.[a-z][a-z0-9]{1,9})(?::(\d+(?:-\d+)?|[A-Za-z_]\w*))?(?![\w-])/g;
|
|
81
|
+
/** A 7–40 hex run that is a whole token (never part of a path, a version or a colour). */
|
|
82
|
+
const SHA_RE = /(?<![\w/.:#-])([0-9a-f]{7,40})(?![\w-])/g;
|
|
83
|
+
/**
|
|
84
|
+
* The symbol a line ref is introduced by: the last backticked IDENTIFIER that sits within ~40
|
|
85
|
+
* characters of glue before the ref (`` `acceptancePhaseIds` is `acceptance.ts:80` ``). Deliberately
|
|
86
|
+
* tight — a symbol from further back in the sentence would "correct" the next ref to the wrong line,
|
|
87
|
+
* which is a fabricated correction of its own.
|
|
88
|
+
*/
|
|
89
|
+
const TRAILING_SYMBOL_RE = /`([A-Za-z_]\w{2,})`([^`]{0,40})$/;
|
|
90
|
+
/** The text before a citation, with the ref's own opening backtick removed. */
|
|
91
|
+
function symbolNamedBefore(text, at) {
|
|
92
|
+
const before = text.slice(Math.max(0, at - SYMBOL_CONTEXT_CHARS), at).replace(/`$/, '');
|
|
93
|
+
return TRAILING_SYMBOL_RE.exec(before)?.[1];
|
|
94
|
+
}
|
|
95
|
+
/** Prose that looks like a file but is not: extension-shaped words we never treat as citations. */
|
|
96
|
+
const PATH_STOPWORDS = new Set(['e.g', 'i.e', 'vs.']);
|
|
97
|
+
/** `wicked-crew` is cited as `crew` as often as by its name: every alias a reply may use. */
|
|
98
|
+
export function repoAliases(root) {
|
|
99
|
+
const out = new Set([root.name]);
|
|
100
|
+
if (root.name.startsWith('wicked-'))
|
|
101
|
+
out.add(root.name.slice('wicked-'.length));
|
|
102
|
+
const base = root.absRoot.split(/[\\/]/).filter((s) => s.length > 0).pop();
|
|
103
|
+
if (base !== undefined && base.length > 0) {
|
|
104
|
+
out.add(base);
|
|
105
|
+
if (base.startsWith('wicked-'))
|
|
106
|
+
out.add(base.slice('wicked-'.length));
|
|
107
|
+
}
|
|
108
|
+
return [...out].filter((a) => a.length >= 3).sort((a, b) => b.length - a.length);
|
|
109
|
+
}
|
|
110
|
+
/** The repo name the text names closest before `at`, when any (`crew \`6d77153\`` → `crew`). */
|
|
111
|
+
function repoNamedBefore(text, at, roots) {
|
|
112
|
+
const before = text.slice(Math.max(0, at - SYMBOL_CONTEXT_CHARS), at).toLowerCase();
|
|
113
|
+
let best;
|
|
114
|
+
for (const root of roots) {
|
|
115
|
+
for (const alias of repoAliases(root)) {
|
|
116
|
+
const index = before.lastIndexOf(alias.toLowerCase());
|
|
117
|
+
if (index < 0)
|
|
118
|
+
continue;
|
|
119
|
+
if (best === undefined || index > best.index)
|
|
120
|
+
best = { name: root.name, index };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return best?.name;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Every citation in a reply, in text order, deduplicated by (kind, raw).
|
|
127
|
+
*
|
|
128
|
+
* Pure: no filesystem, no git. `roots` is read only for the repo aliases a SHA's sentence may name.
|
|
129
|
+
*/
|
|
130
|
+
export function extractCitations(text, roots) {
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
const out = [];
|
|
133
|
+
const push = (c) => {
|
|
134
|
+
const key = `${c.kind}\u0000${c.raw}`;
|
|
135
|
+
if (seen.has(key))
|
|
136
|
+
return;
|
|
137
|
+
seen.add(key);
|
|
138
|
+
out.push(c);
|
|
139
|
+
};
|
|
140
|
+
for (const m of text.matchAll(PATH_RE)) {
|
|
141
|
+
const path = m[1];
|
|
142
|
+
const suffix = m[2];
|
|
143
|
+
if (PATH_STOPWORDS.has(path))
|
|
144
|
+
continue;
|
|
145
|
+
const raw = m[0];
|
|
146
|
+
if (suffix === undefined) {
|
|
147
|
+
push({ raw, kind: 'path', path });
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (/^\d/.test(suffix)) {
|
|
151
|
+
const line = Number.parseInt(suffix.split('-')[0], 10);
|
|
152
|
+
const symbol = symbolNamedBefore(text, m.index);
|
|
153
|
+
push({ raw, kind: 'line', path, line, ...(symbol !== undefined ? { symbol } : {}) });
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
push({ raw, kind: 'symbol', path, symbol: suffix });
|
|
157
|
+
}
|
|
158
|
+
for (const m of text.matchAll(SHA_RE)) {
|
|
159
|
+
const sha = m[1];
|
|
160
|
+
// A word, a date or a number is not a SHA: a real one carries both a digit and an a-f letter.
|
|
161
|
+
if (!/\d/.test(sha) || !/[a-f]/.test(sha))
|
|
162
|
+
continue;
|
|
163
|
+
const repo = repoNamedBefore(text, m.index, roots);
|
|
164
|
+
push({ raw: sha, kind: 'sha', ...(repo !== undefined ? { repo } : {}) });
|
|
165
|
+
}
|
|
166
|
+
return out.sort((a, b) => text.indexOf(a.raw) - text.indexOf(b.raw));
|
|
167
|
+
}
|
|
168
|
+
// ── Verification ─────────────────────────────────────────────────────────────
|
|
169
|
+
/** The default deps: the real filesystem and the real git. */
|
|
170
|
+
export function chatCitationDeps() {
|
|
171
|
+
return {
|
|
172
|
+
fileExists(abs) {
|
|
173
|
+
try {
|
|
174
|
+
return statSync(abs).isFile();
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
readLines(abs) {
|
|
181
|
+
try {
|
|
182
|
+
const st = statSync(abs);
|
|
183
|
+
if (!st.isFile() || st.size > MAX_READ_BYTES)
|
|
184
|
+
return null;
|
|
185
|
+
return readFileSync(abs, 'utf8').split('\n');
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
async listFiles(absRoot) {
|
|
192
|
+
try {
|
|
193
|
+
const { stdout } = await execCapped('git', ['-C', absRoot, 'ls-files'], {
|
|
194
|
+
timeout: GIT_TIMEOUT_MS,
|
|
195
|
+
windowsHide: true,
|
|
196
|
+
});
|
|
197
|
+
return stdout.split('\n').filter((l) => l.length > 0);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// A listing that FAILED is not an empty repo (see {@link CommitCheck} for the same rule).
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
async commitExists(absRoot, sha) {
|
|
205
|
+
try {
|
|
206
|
+
// `rev-parse --verify --quiet`, not `cat-file -e`: cat-file exits 128 ("Not a valid object
|
|
207
|
+
// name") for a commit that is simply absent, which is indistinguishable from 128 for "not a
|
|
208
|
+
// git repository". rev-parse separates them — 0 present, 1 absent, 128 the repo/tool is
|
|
209
|
+
// wrong — and that separation is the whole point (see {@link CommitCheck}).
|
|
210
|
+
await execCapped('git', ['-C', absRoot, 'rev-parse', '--verify', '--quiet', `${sha}^{commit}`], {
|
|
211
|
+
timeout: GIT_TIMEOUT_MS,
|
|
212
|
+
windowsHide: true,
|
|
213
|
+
});
|
|
214
|
+
return 'present';
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
// EXIT 1 is git's own "this repo has no such commit" — the only answer that means absent. A
|
|
218
|
+
// timeout (`killed`, no numeric code), a missing git, or 128 (not a repository) is an ERROR.
|
|
219
|
+
return err.code === 1 ? 'absent' : 'error';
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
now: () => Date.now(),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Resolve a cited path against the read roots. Two spellings, in order:
|
|
227
|
+
* 1. `<repo name>/<rest>` — the shape crew#618's rewrite produces;
|
|
228
|
+
* 2. `<rest>` relative to each root — a reply that dropped the repo prefix.
|
|
229
|
+
* A bare `name.ext` (no separator) falls through to the basename index instead.
|
|
230
|
+
*
|
|
231
|
+
* There is no absolute-path arm, because there can be no absolute citation to resolve: the pass
|
|
232
|
+
* runs on the crew#618-REWRITTEN reply, where every host path under a read root is already
|
|
233
|
+
* repo-relative — and a host path outside every read root is unverifiable by construction.
|
|
234
|
+
*/
|
|
235
|
+
function under(root, rest) {
|
|
236
|
+
const abs = resolve(join(root.absRoot, rest));
|
|
237
|
+
// INSIDE the root, by path boundary — not by string prefix. A cited `alpha/../alpha-secrets/x.ts`
|
|
238
|
+
// resolves to a SIBLING directory whose name merely starts with the root's ("/r/alpha-secrets"
|
|
239
|
+
// vs "/r/alpha"), which a `startsWith` admits; the chat's read roots are the scope, so a citation
|
|
240
|
+
// that leaves them is not resolvable here at all (independent review of #722, HIGH).
|
|
241
|
+
const rel = relative(root.absRoot, abs);
|
|
242
|
+
if (rel === '' || rel.startsWith('..') || isAbsolute(rel))
|
|
243
|
+
return undefined;
|
|
244
|
+
return { abs, root };
|
|
245
|
+
}
|
|
246
|
+
function resolvePath(path, roots) {
|
|
247
|
+
const slash = path.indexOf('/');
|
|
248
|
+
if (slash > 0) {
|
|
249
|
+
const head = path.slice(0, slash);
|
|
250
|
+
const rest = path.slice(slash + 1);
|
|
251
|
+
for (const root of roots) {
|
|
252
|
+
if (repoAliases(root).includes(head)) {
|
|
253
|
+
const at = under(root, rest);
|
|
254
|
+
if (at !== undefined)
|
|
255
|
+
return at;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
for (const root of roots) {
|
|
260
|
+
const at = under(root, path);
|
|
261
|
+
if (at !== undefined)
|
|
262
|
+
return at;
|
|
263
|
+
}
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
/** A word-boundary hit for `symbol`, 1-based; `0` when the file does not contain it. */
|
|
267
|
+
function lineOfSymbol(lines, symbol) {
|
|
268
|
+
const re = new RegExp(`\\b${symbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
|
|
269
|
+
for (let i = 0; i < lines.length; i++) {
|
|
270
|
+
if (re.test(lines[i]))
|
|
271
|
+
return i + 1;
|
|
272
|
+
}
|
|
273
|
+
return 0;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Verify every citation in a reply, bounded. Never throws: a broken root, an unreadable file or a
|
|
277
|
+
* git that is not there is a verdict (`unverified` / `unchecked`), not an error.
|
|
278
|
+
*/
|
|
279
|
+
export async function verifyCitations(text, roots, deps = chatCitationDeps(), opts = {}) {
|
|
280
|
+
const maxItems = opts.maxItems ?? DEFAULT_MAX_ITEMS;
|
|
281
|
+
const budgetMs = opts.budgetMs ?? DEFAULT_BUDGET_MS;
|
|
282
|
+
const started = deps.now();
|
|
283
|
+
const candidates = extractCitations(text, roots);
|
|
284
|
+
const items = [];
|
|
285
|
+
/** Basename → repo-relative paths, per root; built ONCE and only if a bare name needs it. */
|
|
286
|
+
let basenames;
|
|
287
|
+
/** A root whose listing failed: a bare name that is "in no repo" may simply be in that one. */
|
|
288
|
+
let indexPartial = false;
|
|
289
|
+
const indexBasenames = async () => {
|
|
290
|
+
if (basenames !== undefined)
|
|
291
|
+
return basenames;
|
|
292
|
+
const index = new Map();
|
|
293
|
+
for (const root of roots) {
|
|
294
|
+
const listed = await deps.listFiles(root.absRoot);
|
|
295
|
+
if (listed === null) {
|
|
296
|
+
indexPartial = true;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
for (const rel of listed) {
|
|
300
|
+
const base = rel.split('/').pop();
|
|
301
|
+
if (base === undefined)
|
|
302
|
+
continue;
|
|
303
|
+
const hits = index.get(base);
|
|
304
|
+
const entry = { abs: join(root.absRoot, rel), root };
|
|
305
|
+
if (hits === undefined)
|
|
306
|
+
index.set(base, [entry]);
|
|
307
|
+
else
|
|
308
|
+
hits.push(entry);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
basenames = index;
|
|
312
|
+
return index;
|
|
313
|
+
};
|
|
314
|
+
/** The file a path/line/symbol citation names, or how it failed. */
|
|
315
|
+
const locate = async (c) => {
|
|
316
|
+
const path = c.path;
|
|
317
|
+
const direct = resolvePath(path, roots);
|
|
318
|
+
if (direct !== undefined && deps.fileExists(direct.abs))
|
|
319
|
+
return { at: direct };
|
|
320
|
+
if (!path.includes('/')) {
|
|
321
|
+
// `git ls-files` lists what is TRACKED, which is not the same as what is on disk: a file
|
|
322
|
+
// deleted from the working tree is still listed, and reporting it `verified` would be exactly
|
|
323
|
+
// the kind of false confirmation this pass exists to stop (independent review of #722).
|
|
324
|
+
const hits = ((await indexBasenames()).get(path) ?? []).filter((h) => deps.fileExists(h.abs));
|
|
325
|
+
if (hits.length === 1)
|
|
326
|
+
return { at: hits[0] };
|
|
327
|
+
if (hits.length > 1)
|
|
328
|
+
return { miss: 'ambiguous' };
|
|
329
|
+
// A repo the daemon could not LIST cannot be said to lack the file.
|
|
330
|
+
if (indexPartial)
|
|
331
|
+
return { miss: 'unknown' };
|
|
332
|
+
// A bare name that is in no repo and carries no line/symbol suffix was probably prose.
|
|
333
|
+
return { miss: c.kind === 'path' ? 'prose' : 'none' };
|
|
334
|
+
}
|
|
335
|
+
return { miss: 'none' };
|
|
336
|
+
};
|
|
337
|
+
for (const c of candidates) {
|
|
338
|
+
if (items.length >= maxItems || deps.now() - started > budgetMs) {
|
|
339
|
+
items.push({
|
|
340
|
+
raw: c.raw,
|
|
341
|
+
kind: c.kind,
|
|
342
|
+
status: 'unchecked',
|
|
343
|
+
note: 'the verification budget for this reply ran out before this citation',
|
|
344
|
+
});
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (c.kind === 'sha') {
|
|
348
|
+
const named = c.repo !== undefined ? roots.find((r) => r.name === c.repo) : undefined;
|
|
349
|
+
const inNamed = named !== undefined ? await deps.commitExists(named.absRoot, c.raw) : 'absent';
|
|
350
|
+
if (inNamed === 'present') {
|
|
351
|
+
items.push({ raw: c.raw, kind: 'sha', status: 'verified', resolved: named.name });
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
let elsewhere;
|
|
355
|
+
// The budget is re-read BETWEEN roots, not only between citations: one fabricated SHA over
|
|
356
|
+
// nine roots is nine git calls, and a slow root must not let one citation outlast the whole
|
|
357
|
+
// reply's budget (independent review of #722). A sweep that did not FINISH — budget gone, or
|
|
358
|
+
// a repo the check errored on — says `unchecked`: "in no repo" is a claim it did not earn.
|
|
359
|
+
let swept = inNamed !== 'error';
|
|
360
|
+
for (const root of roots) {
|
|
361
|
+
if (root === named)
|
|
362
|
+
continue;
|
|
363
|
+
if (deps.now() - started > budgetMs) {
|
|
364
|
+
swept = false;
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
const found = await deps.commitExists(root.absRoot, c.raw);
|
|
368
|
+
if (found === 'present') {
|
|
369
|
+
elsewhere = root;
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
if (found === 'error')
|
|
373
|
+
swept = false;
|
|
374
|
+
}
|
|
375
|
+
if (elsewhere === undefined && !swept) {
|
|
376
|
+
items.push({
|
|
377
|
+
raw: c.raw,
|
|
378
|
+
kind: 'sha',
|
|
379
|
+
status: 'unchecked',
|
|
380
|
+
note: "this chat's repositories could not all be checked for that commit",
|
|
381
|
+
});
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (elsewhere === undefined) {
|
|
385
|
+
items.push({
|
|
386
|
+
raw: c.raw,
|
|
387
|
+
kind: 'sha',
|
|
388
|
+
status: 'unverified',
|
|
389
|
+
note: named !== undefined
|
|
390
|
+
? `no such commit in ${named.name} — or in any other repo in this chat's scope`
|
|
391
|
+
: "no such commit in any repo in this chat's scope",
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
else if (named === undefined) {
|
|
395
|
+
items.push({ raw: c.raw, kind: 'sha', status: 'verified', resolved: elsewhere.name });
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
items.push({
|
|
399
|
+
raw: c.raw,
|
|
400
|
+
kind: 'sha',
|
|
401
|
+
status: 'corrected',
|
|
402
|
+
resolved: elsewhere.name,
|
|
403
|
+
note: `the commit is in ${elsewhere.name}, not ${named.name}`,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const found = await locate(c);
|
|
409
|
+
if ('miss' in found) {
|
|
410
|
+
if (found.miss === 'prose')
|
|
411
|
+
continue; // never a mark on prose
|
|
412
|
+
if (found.miss === 'unknown') {
|
|
413
|
+
items.push({
|
|
414
|
+
raw: c.raw,
|
|
415
|
+
kind: c.kind,
|
|
416
|
+
status: 'unchecked',
|
|
417
|
+
note: "a repository in this chat's scope could not be listed, so this file was not looked for",
|
|
418
|
+
});
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
items.push({
|
|
422
|
+
raw: c.raw,
|
|
423
|
+
kind: c.kind,
|
|
424
|
+
status: 'unverified',
|
|
425
|
+
note: found.miss === 'ambiguous'
|
|
426
|
+
? "several repos in this chat's scope have a file with that name — the citation does not say which"
|
|
427
|
+
: "no such file in this chat's scope",
|
|
428
|
+
});
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const at = found.at;
|
|
432
|
+
if (c.kind === 'path') {
|
|
433
|
+
items.push({ raw: c.raw, kind: 'path', status: 'verified', resolved: `${at.root.name}` });
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
const lines = deps.readLines(at.abs);
|
|
437
|
+
if (lines === null) {
|
|
438
|
+
items.push({
|
|
439
|
+
raw: c.raw,
|
|
440
|
+
kind: c.kind,
|
|
441
|
+
status: 'unchecked',
|
|
442
|
+
note: 'the file is there, but could not be read to check the reference',
|
|
443
|
+
});
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
if (c.kind === 'symbol') {
|
|
447
|
+
const line = lineOfSymbol(lines, c.symbol);
|
|
448
|
+
if (line > 0)
|
|
449
|
+
items.push({ raw: c.raw, kind: 'symbol', status: 'verified', resolved: `${c.path}:${line}` });
|
|
450
|
+
else
|
|
451
|
+
items.push({
|
|
452
|
+
raw: c.raw,
|
|
453
|
+
kind: 'symbol',
|
|
454
|
+
status: 'unverified',
|
|
455
|
+
note: `${at.root.name} has the file, but it does not contain ${c.symbol}`,
|
|
456
|
+
});
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
// kind === 'line'
|
|
460
|
+
const line = c.line;
|
|
461
|
+
if (line < 1 || line > lines.length) {
|
|
462
|
+
items.push({
|
|
463
|
+
raw: c.raw,
|
|
464
|
+
kind: 'line',
|
|
465
|
+
status: 'unverified',
|
|
466
|
+
note: `the file has ${lines.length} lines`,
|
|
467
|
+
});
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (c.symbol === undefined) {
|
|
471
|
+
items.push({ raw: c.raw, kind: 'line', status: 'verified' });
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
const cited = lines[line - 1];
|
|
475
|
+
const re = new RegExp(`\\b${c.symbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
|
|
476
|
+
if (re.test(cited)) {
|
|
477
|
+
items.push({ raw: c.raw, kind: 'line', status: 'verified' });
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const actual = lineOfSymbol(lines, c.symbol);
|
|
481
|
+
if (actual > 0) {
|
|
482
|
+
const corrected = c.raw.replace(/:\d+(?:-\d+)?$/, `:${actual}`);
|
|
483
|
+
items.push({
|
|
484
|
+
raw: c.raw,
|
|
485
|
+
kind: 'line',
|
|
486
|
+
status: 'corrected',
|
|
487
|
+
resolved: corrected,
|
|
488
|
+
note: `${c.symbol} is on line ${actual}, not ${line}`,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
items.push({
|
|
493
|
+
raw: c.raw,
|
|
494
|
+
kind: 'line',
|
|
495
|
+
status: 'unverified',
|
|
496
|
+
note: `line ${line} does not mention ${c.symbol}, and the file does not either`,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
verified: items.filter((i) => i.status === 'verified').length,
|
|
502
|
+
unverifiable: items.filter((i) => i.status === 'unverified').length,
|
|
503
|
+
corrected: items.filter((i) => i.status === 'corrected').length,
|
|
504
|
+
unchecked: items.filter((i) => i.status === 'unchecked').length,
|
|
505
|
+
items,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* The `/ws` frame for one reply's verdicts, or `null` when there is nothing to say (no citation
|
|
510
|
+
* survived extraction — a chatty reply with no references marks nothing).
|
|
511
|
+
*/
|
|
512
|
+
export function citationsFrame(reply, result) {
|
|
513
|
+
if (result.items.length === 0)
|
|
514
|
+
return null;
|
|
515
|
+
return {
|
|
516
|
+
type: 'chatCitations',
|
|
517
|
+
chat: reply.chat,
|
|
518
|
+
cliKey: reply.cliKey,
|
|
519
|
+
...(reply.turn_id !== undefined ? { turn_id: reply.turn_id } : {}),
|
|
520
|
+
verified: result.verified,
|
|
521
|
+
unverifiable: result.unverifiable,
|
|
522
|
+
corrected: result.corrected,
|
|
523
|
+
unchecked: result.unchecked,
|
|
524
|
+
items: result.items,
|
|
525
|
+
...(reply.project_id !== undefined ? { project_id: reply.project_id } : {}),
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
//# sourceMappingURL=chat-citations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-citations.js","sourceRoot":"","sources":["../../src/api/chat-citations.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* Registered in `tests/fixtures/state-home-subtrees.json` as `chats` (crew half; the core half —
|
|
27
27
|
* the worker Read fence — landed with core-ts 0.7.26), and named in `state-home-registry.ts`.
|
|
28
28
|
*/
|
|
29
|
-
import type { ChatTranscriptRecord, CoreEvent } from '../core/types.js';
|
|
29
|
+
import type { ChatCitationItem, ChatTranscriptRecord, CoreEvent } from '../core/types.js';
|
|
30
30
|
/** The state-home entry (`<state home>/chats/`) — the name the fixture registers. */
|
|
31
31
|
export declare const CHAT_TRANSCRIPTS_DIRNAME = "chats";
|
|
32
32
|
/** One repo root → name mapping entry used for path rewriting (crew#618). */
|
|
@@ -79,6 +79,25 @@ export declare class ChatTranscriptStore {
|
|
|
79
79
|
* roots registered for the chat via {@link registerRoots}.
|
|
80
80
|
*/
|
|
81
81
|
observe(stamped: CoreEvent): void;
|
|
82
|
+
/**
|
|
83
|
+
* The citation verdicts of a reply already recorded (crew#561): appended as their OWN record,
|
|
84
|
+
* because the transcript is append-only and verification finishes AFTER the reply is stored. A
|
|
85
|
+
* reader folds it onto the `seat` record with the same `turnId` + `cliKey` — which is what keeps
|
|
86
|
+
* a fabricated SHA marked across a reload, instead of rendering as plain text again.
|
|
87
|
+
*
|
|
88
|
+
* Only a STAMPED frame is recorded: without a `turn_id` there is no reply to fold it onto (the
|
|
89
|
+
* same rule {@link observe} applies), and a straggler must never recreate a dropped file.
|
|
90
|
+
*/
|
|
91
|
+
recordCitations(frame: {
|
|
92
|
+
chat: string;
|
|
93
|
+
cliKey: string;
|
|
94
|
+
turn_id?: string;
|
|
95
|
+
verified: number;
|
|
96
|
+
unverifiable: number;
|
|
97
|
+
corrected: number;
|
|
98
|
+
unchecked: number;
|
|
99
|
+
items: ChatCitationItem[];
|
|
100
|
+
}): void;
|
|
82
101
|
/** Every record of the chat in append order; `[]` for a chat with no file (or a refused id). */
|
|
83
102
|
read(chatId: string): ChatTranscriptRecord[];
|
|
84
103
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-transcripts.d.ts","sourceRoot":"","sources":["../../src/api/chat-transcripts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,OAAO,KAAK,EAAE,oBAAoB,EAAa,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"chat-transcripts.d.ts","sourceRoot":"","sources":["../../src/api/chat-transcripts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAa,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIrG,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAEhD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,MAAM,CAezF;AAED,8FAA8F;AAC9F,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAgBD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,8FAA8F;IAC9F,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkD;gBAEhE,IAAI,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;KAAO;IAK3D;;;;;OAKG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,IAAI;IAIvE,mEAAmE;IACnE,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,6FAA6F;IAC7F,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,MAAM;IAcd,sGAAsG;IACtG,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAIxF;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAqBjC;;;;;;;;OAQG;IACH,eAAe,CAAC,KAAK,EAAE;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,gBAAgB,EAAE,CAAC;KAC3B,GAAG,IAAI;IAmBR,gGAAgG;IAChG,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,EAAE;IAe5C;;;;;;OAMG;IACH,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS;IAazC,gFAAgF;IAChF,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM1B;;;;OAIG;IACH,aAAa,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI;IAWzD,kGAAkG;IAClG,QAAQ,IAAI,IAAI;CAGjB"}
|
|
@@ -150,6 +150,35 @@ export class ChatTranscriptStore {
|
|
|
150
150
|
usage: usageOf(frame['usage']),
|
|
151
151
|
});
|
|
152
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* The citation verdicts of a reply already recorded (crew#561): appended as their OWN record,
|
|
155
|
+
* because the transcript is append-only and verification finishes AFTER the reply is stored. A
|
|
156
|
+
* reader folds it onto the `seat` record with the same `turnId` + `cliKey` — which is what keeps
|
|
157
|
+
* a fabricated SHA marked across a reload, instead of rendering as plain text again.
|
|
158
|
+
*
|
|
159
|
+
* Only a STAMPED frame is recorded: without a `turn_id` there is no reply to fold it onto (the
|
|
160
|
+
* same rule {@link observe} applies), and a straggler must never recreate a dropped file.
|
|
161
|
+
*/
|
|
162
|
+
recordCitations(frame) {
|
|
163
|
+
if (frame.turn_id === undefined)
|
|
164
|
+
return;
|
|
165
|
+
const file = this.fileOf(frame.chat);
|
|
166
|
+
// No file ⇒ no reply was ever recorded for this chat (a reclaimed id, a refused chat id): a
|
|
167
|
+
// citations record alone would recreate a transcript that has nothing to fold onto.
|
|
168
|
+
if (file === null || !existsSync(file))
|
|
169
|
+
return;
|
|
170
|
+
this.append(frame.chat, {
|
|
171
|
+
at: this.now(),
|
|
172
|
+
turnId: frame.turn_id,
|
|
173
|
+
kind: 'citations',
|
|
174
|
+
cliKey: frame.cliKey,
|
|
175
|
+
verified: frame.verified,
|
|
176
|
+
unverifiable: frame.unverifiable,
|
|
177
|
+
corrected: frame.corrected,
|
|
178
|
+
unchecked: frame.unchecked,
|
|
179
|
+
items: frame.items,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
153
182
|
/** Every record of the chat in append order; `[]` for a chat with no file (or a refused id). */
|
|
154
183
|
read(chatId) {
|
|
155
184
|
const file = this.fileOf(chatId);
|