scoutline 0.23.0 → 0.24.1
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/README.md +49 -1
- package/dist/capabilities/investigation.d.ts +134 -0
- package/dist/capabilities/investigation.d.ts.map +1 -0
- package/dist/capabilities/investigation.js +278 -0
- package/dist/capabilities/investigation.js.map +1 -0
- package/dist/commands/archive.d.ts +18 -1
- package/dist/commands/archive.d.ts.map +1 -1
- package/dist/commands/archive.js +23 -12
- package/dist/commands/archive.js.map +1 -1
- package/dist/commands/investigate.d.ts +232 -0
- package/dist/commands/investigate.d.ts.map +1 -0
- package/dist/commands/investigate.js +838 -0
- package/dist/commands/investigate.js.map +1 -0
- package/dist/commands/search.d.ts +16 -0
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +10 -2
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/vision.d.ts.map +1 -1
- package/dist/commands/vision.js +15 -2
- package/dist/commands/vision.js.map +1 -1
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +379 -10
- package/dist/index.js.map +1 -1
- package/dist/lib/context-file.d.ts +21 -0
- package/dist/lib/context-file.d.ts.map +1 -1
- package/dist/lib/context-file.js +84 -6
- package/dist/lib/context-file.js.map +1 -1
- package/dist/lib/equals-form.d.ts +34 -0
- package/dist/lib/equals-form.d.ts.map +1 -0
- package/dist/lib/equals-form.js +49 -0
- package/dist/lib/equals-form.js.map +1 -0
- package/dist/lib/investigate-claims.d.ts +98 -0
- package/dist/lib/investigate-claims.d.ts.map +1 -0
- package/dist/lib/investigate-claims.js +166 -0
- package/dist/lib/investigate-claims.js.map +1 -0
- package/dist/lib/investigate-extract.d.ts +58 -0
- package/dist/lib/investigate-extract.d.ts.map +1 -0
- package/dist/lib/investigate-extract.js +126 -0
- package/dist/lib/investigate-extract.js.map +1 -0
- package/dist/lib/investigate-planner.d.ts +60 -0
- package/dist/lib/investigate-planner.d.ts.map +1 -0
- package/dist/lib/investigate-planner.js +125 -0
- package/dist/lib/investigate-planner.js.map +1 -0
- package/dist/lib/journal.d.ts.map +1 -1
- package/dist/lib/journal.js +10 -9
- package/dist/lib/journal.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +4 -1
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/types.d.ts +45 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/providers/zai/adapter.d.ts.map +1 -1
- package/dist/providers/zai/adapter.js +245 -3
- package/dist/providers/zai/adapter.js.map +1 -1
- package/dist/providers/zai/layout-parsing.d.ts +76 -0
- package/dist/providers/zai/layout-parsing.d.ts.map +1 -0
- package/dist/providers/zai/layout-parsing.js +151 -0
- package/dist/providers/zai/layout-parsing.js.map +1 -0
- package/dist/providers/zai/media.d.ts +19 -0
- package/dist/providers/zai/media.d.ts.map +1 -1
- package/dist/providers/zai/media.js +61 -0
- package/dist/providers/zai/media.js.map +1 -1
- package/package.json +1 -1
- package/skills/scoutline/SKILL.md +71 -1
package/README.md
CHANGED
|
@@ -416,7 +416,7 @@ executor preflight, Provider selection, and `doctor`.
|
|
|
416
416
|
| `search` | Yes | Yes | Yes | Yes | Yes (incl. `type: "video"`) | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Parallel (declarative semantic), Jina (neural web search) |
|
|
417
417
|
| `vision.interpret-image` (analyze) | Yes | Yes | No | No | No | No | No | No | No | No | No | No | No | No | No | Provider-specific media limits; uncached |
|
|
418
418
|
| `vision.ui-artifact` (ui-to-code) | Yes | Available | No | No | No | No | No | No | No | No | No | No | No | No | No | Live-attested; conformance-gated |
|
|
419
|
-
| `vision.extract-text` | Yes | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
|
|
419
|
+
| `vision.extract-text` | Yes (GLM-OCR engine: PDF ≤50MB, images ≤10MB, content-hash cached; exhaustion falls back to the vision model) | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
|
|
420
420
|
| `vision.diagnose-error` | Yes | Available | No | No | No | No | No | No | No | No | No | No | No | No | No | Live-attested; conformance-gated |
|
|
421
421
|
| `vision.diagram` | Yes | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
|
|
422
422
|
| `vision.chart` | Yes | Pending | No | No | No | No | No | No | No | No | No | No | No | No | No | Implemented, pending live conformance |
|
|
@@ -428,6 +428,7 @@ executor preflight, Provider selection, and `doctor`.
|
|
|
428
428
|
| `crawl` | **No** | **No** | Yes | No | No | Yes (async) | No | No | No | No | No | Yes (sync) | No | **No** | No | Tavily sync; Firecrawl async (resumable after Ctrl-C) |
|
|
429
429
|
| `map` | **No** | **No** | Yes | No | No | Yes | No | No | No | No | No | Yes | No | **No** | No | URL-set discovery; no per-page content |
|
|
430
430
|
| `research` | **No** | **No** | Yes | Yes | **No** | **No** | Yes | Yes | Yes | Yes | Yes | No | No | **No** | No | Tavily, Exa, Parallel, Perplexity (Agent API `high` preset), Jina DeepSearch, You.com, and Linkup research report synthesis |
|
|
431
|
+
| `investigation` (EvidencePack) | Yes | **No** (no reader) | Yes | Yes | **No** (no reader) | Yes | Yes | **No** (no reader) | Yes | Yes | Yes | Yes | **No** (no reader) | **No** (no reader) | **No** (no reader) | Provider-composed — supplied by the search+reader supplier union (Z.AI, Tavily, Exa, Firecrawl, Parallel, Jina AI, You.com, Linkup, Spider.cloud); `--synthesize` is Z.AI-only |
|
|
431
432
|
| `repo search` / `repo read` / `repo tree` / `repo brief` | Yes | **No** | **No** | **No** | **No** | **No** | **No** | **No** | **No** | No | No | No | No | No | No | Participates in selection; only Z.AI supplies `repository-exploration` |
|
|
432
433
|
| `tools`, `tool`, `call` (Raw tools) | Yes | No | No | No | No | No | No | No | No | No | No | No | No | No | No | Z.AI-only; accepts but ignores `--provider` |
|
|
433
434
|
| `code` (Code Mode) | Yes | No | No | No | No | No | No | No | No | No | No | No | No | No | No | Z.AI-only; accepts but ignores `--provider` |
|
|
@@ -525,6 +526,53 @@ the supplier wire supports them (rejected with `UNSUPPORTED_OPTION`
|
|
|
525
526
|
elsewhere — never silently dropped). `science get <identifier>` fetches
|
|
526
527
|
one work by bare DOI, numeric PMID, or arXiv id.
|
|
527
528
|
|
|
529
|
+
### Investigation (`investigate`)
|
|
530
|
+
|
|
531
|
+
`scoutline investigate <question>` runs a local, transparent,
|
|
532
|
+
cache-resumable pipeline ([ADR-0013](https://github.com/vikasagarwal101/scoutline/blob/main/docs/adr/0013-local-investigation-pipeline.md)):
|
|
533
|
+
plan sub-queries → fan-out search → Fusion merge → read the top
|
|
534
|
+
`--sources` (default 5) → deterministic passage extraction → an
|
|
535
|
+
EvidencePack (`schemaVersion` 1). No provider-side job runs — distinct
|
|
536
|
+
from Research, an opaque billed provider job. The pack is data, not
|
|
537
|
+
prose: agents consume it directly and text output modes fall back to
|
|
538
|
+
JSON (agent-synthesis is the default; you write the prose). Warm re-runs
|
|
539
|
+
replay the response cache (`coverage.cacheHits` reflects it).
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
scoutline investigate "rust async runtime benchmarks"
|
|
543
|
+
scoutline investigate "rust async | rust tokio" # pipes split explicit sub-queries
|
|
544
|
+
scoutline investigate "topic" --provider tavily,exa --sources 8
|
|
545
|
+
scoutline investigate "topic" --max-chars 20000 --synthesize
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Sub-query planning precedence: explicit pipes (the `--merge` grammar) >
|
|
549
|
+
`--context <path>` (a local notes file — it never leaves the machine,
|
|
550
|
+
only the derived sub-query strings are searched) > deterministic
|
|
551
|
+
templates of the bare question (original, key terms,
|
|
552
|
+
overview/evidence/criticism; deduped, capped at 5). Provider selection
|
|
553
|
+
reuses search's fan-out activation tiers verbatim (comma-list/`all`
|
|
554
|
+
fan-out, single pin, `config set fanout true`). Cost is stated in one
|
|
555
|
+
stderr notice before any billable work: N sub-queries × M arms billable
|
|
556
|
+
searches + up to K reads.
|
|
557
|
+
|
|
558
|
+
Controls: `--sources <n>`, `--max-chars <n>` (passages trim first, late
|
|
559
|
+
sources drop; the full untrimmed pack is saved and recoverable via
|
|
560
|
+
`scoutline history show <ref>`), `--no-cache`, `--no-journal`, `--save`,
|
|
561
|
+
`--isolated`. Sources surfaced but unread land in `coverage.unread` with
|
|
562
|
+
a reason code — never silently dropped. `--synthesize` attaches an
|
|
563
|
+
additive `brief` via Z.AI chat (Z.AI-only; absent by default; a
|
|
564
|
+
synthesis failure is the run's terminal error, never a degraded pack).
|
|
565
|
+
`--depth`, `--arms`, and `--budget-tokens` are rejected with
|
|
566
|
+
`VALIDATION_ERROR` by design.
|
|
567
|
+
|
|
568
|
+
`--verify` turns the positional into a statement: sentence-claims
|
|
569
|
+
(≤ 8, fail-loud) are searched verbatim and matched to the extracted
|
|
570
|
+
passages; the pack gains an additive `verify` block — per claim, a
|
|
571
|
+
verdict (`corroborated` / `contradicted` / `unresolved`), evidence
|
|
572
|
+
pointers, and a negation-cue count. `contradicted` is a disclosed
|
|
573
|
+
negation-cue heuristic (hint-grade), not semantic judgment;
|
|
574
|
+
`--context` + `--verify` is a mode-conflict VALIDATION_ERROR.
|
|
575
|
+
|
|
528
576
|
## Usage
|
|
529
577
|
|
|
530
578
|
The CLI is self-documenting. Use `--help` at any level:
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EvidencePack schema + total decoder (T1, docs/plans/investigate-pipeline
|
|
3
|
+
* PRD AC-6; ADR-0013 §7).
|
|
4
|
+
*
|
|
5
|
+
* The EvidencePack is the self-contained deliverable of an Investigation
|
|
6
|
+
* (CONTEXT.md glossary): question, sub-queries, sources with per-source
|
|
7
|
+
* content hashes and extracted passages, and a coverage block. The pack is
|
|
8
|
+
* data, not prose — agent-synthesis is the contract; `--synthesize` (T7)
|
|
9
|
+
* attaches a `brief` additively and is not part of this schema.
|
|
10
|
+
*
|
|
11
|
+
* This module declares the pack type, its total decoder, and the
|
|
12
|
+
* contentSha256 shape predicate. It imports NOTHING from other src modules
|
|
13
|
+
* (self-contained by ticket contract; hashing itself lands in T5 — this
|
|
14
|
+
* module only validates hash *shape*).
|
|
15
|
+
*
|
|
16
|
+
* Decoder discipline mirrors capabilities/reader.ts exactly:
|
|
17
|
+
* - accepts `unknown`, returns the pack or `null`, never throws,
|
|
18
|
+
* never trusts a generic cast;
|
|
19
|
+
* - reject primitives and arrays at the top level;
|
|
20
|
+
* - `schemaVersion` MUST be the literal number 1 (rejects "1", 1.5,
|
|
21
|
+
* bigints, any future version);
|
|
22
|
+
* - `title: null` is a valid decoded value (reader parity);
|
|
23
|
+
* - optional fields preserved verbatim when present.
|
|
24
|
+
*/
|
|
25
|
+
/** `[start, end)` character offsets into the source `content` string. */
|
|
26
|
+
export type CharRange = readonly [number, number];
|
|
27
|
+
/**
|
|
28
|
+
* One extracted passage. `quote` is pinned to the content by `charRange`:
|
|
29
|
+
* `content.slice(...charRange) === quote` for every passage (D4). The pin
|
|
30
|
+
* is enforced where content is available (assembly in T5, extraction in
|
|
31
|
+
* T3); the decoder enforces the shape so a decoded pack is at least
|
|
32
|
+
* structurally sound.
|
|
33
|
+
*/
|
|
34
|
+
export interface EvidencePassage {
|
|
35
|
+
readonly quote: string;
|
|
36
|
+
readonly charRange: CharRange;
|
|
37
|
+
}
|
|
38
|
+
/** One read source: reader-envelope fields + passages. */
|
|
39
|
+
export interface EvidenceSource {
|
|
40
|
+
readonly url: string;
|
|
41
|
+
/** The URL the Reader actually fetched (provider rewrite possible). */
|
|
42
|
+
readonly finalUrl: string;
|
|
43
|
+
/** Page title if the provider returned one; `null` if absent (reader parity). */
|
|
44
|
+
readonly title: string | null;
|
|
45
|
+
/** ISO-8601 UTC Z timestamp captured when the read resolved (D5). */
|
|
46
|
+
readonly fetchedAt: string;
|
|
47
|
+
/** Provider id that surfaced the source (search-arm winner). */
|
|
48
|
+
readonly provider: string;
|
|
49
|
+
/** Mirrors the read `format`; `"markdown"` or `"text"`. */
|
|
50
|
+
readonly contentFormat: "markdown" | "text";
|
|
51
|
+
/** Lowercase hex SHA-256 of the UTF-8 normalized content string (D5). */
|
|
52
|
+
readonly contentSha256: string;
|
|
53
|
+
readonly passages: readonly EvidencePassage[];
|
|
54
|
+
}
|
|
55
|
+
/** Coverage block: how much of the planned grid actually produced evidence. */
|
|
56
|
+
export interface EvidenceCoverage {
|
|
57
|
+
/** Number of planned sub-queries. */
|
|
58
|
+
readonly subQueries: number;
|
|
59
|
+
/** Number of search arms actually used. */
|
|
60
|
+
readonly armsUsed: number;
|
|
61
|
+
/** Number of post-cluster candidate sources surfaced. */
|
|
62
|
+
readonly sourcesConsidered: number;
|
|
63
|
+
/** Number of sources whose read resolved successfully. */
|
|
64
|
+
readonly sourcesRead: number;
|
|
65
|
+
/** Count of search arms + reads served warm from cache (D5). */
|
|
66
|
+
readonly cacheHits: number;
|
|
67
|
+
/**
|
|
68
|
+
* Sources surfaced but not read, each with a reason code only —
|
|
69
|
+
* redacted, no error prose crossing the interface (house rule, D5).
|
|
70
|
+
*/
|
|
71
|
+
readonly unread: readonly {
|
|
72
|
+
readonly url: string;
|
|
73
|
+
readonly reason: string;
|
|
74
|
+
}[];
|
|
75
|
+
}
|
|
76
|
+
/** The self-contained Investigation deliverable (PRD AC-6). */
|
|
77
|
+
export interface EvidencePack {
|
|
78
|
+
readonly schemaVersion: 1;
|
|
79
|
+
readonly question: string;
|
|
80
|
+
readonly subQueries: readonly string[];
|
|
81
|
+
readonly sources: readonly EvidenceSource[];
|
|
82
|
+
readonly coverage: EvidenceCoverage;
|
|
83
|
+
/**
|
|
84
|
+
* investigate-verify lane T2 (PRD AC-6): the additive claim-
|
|
85
|
+
* corroboration block. ABSENT on question-mode packs (byte-identity
|
|
86
|
+
* pin); present only when `investigate --verify` assembled the pack.
|
|
87
|
+
*/
|
|
88
|
+
readonly verify?: VerifyBlock;
|
|
89
|
+
}
|
|
90
|
+
/** The deterministic verdict vocabulary (cue heuristic, PRD AC-5). */
|
|
91
|
+
export type ClaimVerdict = "corroborated" | "contradicted" | "unresolved";
|
|
92
|
+
/** One evidence pointer into the pack's own `sources` array. */
|
|
93
|
+
export interface ClaimEvidencePointer {
|
|
94
|
+
readonly sourceIndex: number;
|
|
95
|
+
readonly passageIndex: number;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* One claim row: the claim text, its verdict, the count of cue-bearing
|
|
99
|
+
* matching passages (agent re-judgment input — the cue heuristic is
|
|
100
|
+
* DISCLOSED hint-grade), and first-encounter evidence pointers.
|
|
101
|
+
*/
|
|
102
|
+
export interface ClaimRow {
|
|
103
|
+
readonly text: string;
|
|
104
|
+
readonly verdict: ClaimVerdict;
|
|
105
|
+
readonly negationCues: number;
|
|
106
|
+
readonly evidence: readonly ClaimEvidencePointer[];
|
|
107
|
+
}
|
|
108
|
+
/** The additive verify block: the statement plus one row per claim. */
|
|
109
|
+
export interface VerifyBlock {
|
|
110
|
+
readonly statement: string;
|
|
111
|
+
readonly claims: readonly ClaimRow[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* `contentSha256` validity: a 64-character lowercase hex string —
|
|
115
|
+
* the exact shape of `createHash("sha256")…digest("hex")` output.
|
|
116
|
+
* Ruling (ticket T1): hex-shape is enforced at decode, so an
|
|
117
|
+
* uppercased, truncated, or non-hex string fails closed. Full
|
|
118
|
+
* recompute-vs-content binding belongs to assembly (T5), which is the
|
|
119
|
+
* only place the paired content string exists.
|
|
120
|
+
*/
|
|
121
|
+
export declare function isValidContentSha256(value: unknown): value is string;
|
|
122
|
+
/**
|
|
123
|
+
* Decode an `unknown` value into a canonical `EvidencePack`. Returns the
|
|
124
|
+
* typed pack on success, `null` for any malformed value. NEVER throws,
|
|
125
|
+
* NEVER trusts a generic cast.
|
|
126
|
+
*
|
|
127
|
+
* `title: null` is valid (reader parity). `sources` and `passages` may be
|
|
128
|
+
* empty arrays (a pack whose every read failed is still a valid, sad pack).
|
|
129
|
+
* `brief` (T7) is additive: unknown keys are NOT rejected — a decoded pack
|
|
130
|
+
* carries exactly the AC-6 keys, and an input carrying extra keys decodes
|
|
131
|
+
* to the canonical subset.
|
|
132
|
+
*/
|
|
133
|
+
export declare function decodeInvestigationPack(value: unknown): EvidencePack | null;
|
|
134
|
+
//# sourceMappingURL=investigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"investigation.d.ts","sourceRoot":"","sources":["../../src/capabilities/investigation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EvidencePack schema + total decoder (T1, docs/plans/investigate-pipeline
|
|
3
|
+
* PRD AC-6; ADR-0013 §7).
|
|
4
|
+
*
|
|
5
|
+
* The EvidencePack is the self-contained deliverable of an Investigation
|
|
6
|
+
* (CONTEXT.md glossary): question, sub-queries, sources with per-source
|
|
7
|
+
* content hashes and extracted passages, and a coverage block. The pack is
|
|
8
|
+
* data, not prose — agent-synthesis is the contract; `--synthesize` (T7)
|
|
9
|
+
* attaches a `brief` additively and is not part of this schema.
|
|
10
|
+
*
|
|
11
|
+
* This module declares the pack type, its total decoder, and the
|
|
12
|
+
* contentSha256 shape predicate. It imports NOTHING from other src modules
|
|
13
|
+
* (self-contained by ticket contract; hashing itself lands in T5 — this
|
|
14
|
+
* module only validates hash *shape*).
|
|
15
|
+
*
|
|
16
|
+
* Decoder discipline mirrors capabilities/reader.ts exactly:
|
|
17
|
+
* - accepts `unknown`, returns the pack or `null`, never throws,
|
|
18
|
+
* never trusts a generic cast;
|
|
19
|
+
* - reject primitives and arrays at the top level;
|
|
20
|
+
* - `schemaVersion` MUST be the literal number 1 (rejects "1", 1.5,
|
|
21
|
+
* bigints, any future version);
|
|
22
|
+
* - `title: null` is a valid decoded value (reader parity);
|
|
23
|
+
* - optional fields preserved verbatim when present.
|
|
24
|
+
*/
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Field predicates
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
function isPlainObject(value) {
|
|
29
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
function isNonEmptyString(value) {
|
|
32
|
+
return typeof value === "string" && value.length > 0;
|
|
33
|
+
}
|
|
34
|
+
function isFiniteNumber(value) {
|
|
35
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* `contentSha256` validity: a 64-character lowercase hex string —
|
|
39
|
+
* the exact shape of `createHash("sha256")…digest("hex")` output.
|
|
40
|
+
* Ruling (ticket T1): hex-shape is enforced at decode, so an
|
|
41
|
+
* uppercased, truncated, or non-hex string fails closed. Full
|
|
42
|
+
* recompute-vs-content binding belongs to assembly (T5), which is the
|
|
43
|
+
* only place the paired content string exists.
|
|
44
|
+
*/
|
|
45
|
+
export function isValidContentSha256(value) {
|
|
46
|
+
if (typeof value !== "string" || value.length !== 64)
|
|
47
|
+
return false;
|
|
48
|
+
for (const ch of value) {
|
|
49
|
+
const code = ch.charCodeAt(0);
|
|
50
|
+
const isDigit = code >= 48 && code <= 57;
|
|
51
|
+
const isLowerHex = (code >= 97 && code <= 102) || isDigit;
|
|
52
|
+
if (!isLowerHex)
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Total decoder
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
function decodeCharRange(value) {
|
|
61
|
+
// PR #264 F2: the documented `[start, end)` invariant, enforced at
|
|
62
|
+
// decode — safe integers, non-negative start, strictly increasing
|
|
63
|
+
// (an empty range cannot quote a non-empty passage).
|
|
64
|
+
return (Array.isArray(value) &&
|
|
65
|
+
value.length === 2 &&
|
|
66
|
+
Number.isSafeInteger(value[0]) &&
|
|
67
|
+
Number.isSafeInteger(value[1]) &&
|
|
68
|
+
value[0] >= 0 &&
|
|
69
|
+
value[1] > value[0]);
|
|
70
|
+
}
|
|
71
|
+
function decodePassage(value) {
|
|
72
|
+
if (!isPlainObject(value))
|
|
73
|
+
return null;
|
|
74
|
+
if (!isNonEmptyString(value.quote))
|
|
75
|
+
return null;
|
|
76
|
+
if (!decodeCharRange(value.charRange))
|
|
77
|
+
return null;
|
|
78
|
+
return { quote: value.quote, charRange: [value.charRange[0], value.charRange[1]] };
|
|
79
|
+
}
|
|
80
|
+
function decodeSource(value) {
|
|
81
|
+
if (!isPlainObject(value))
|
|
82
|
+
return null;
|
|
83
|
+
if (!isNonEmptyString(value.url))
|
|
84
|
+
return null;
|
|
85
|
+
if (!isNonEmptyString(value.finalUrl))
|
|
86
|
+
return null;
|
|
87
|
+
const title = value.title;
|
|
88
|
+
if (title !== null && typeof title !== "string")
|
|
89
|
+
return null;
|
|
90
|
+
if (!isNonEmptyString(value.fetchedAt))
|
|
91
|
+
return null;
|
|
92
|
+
if (!isNonEmptyString(value.provider))
|
|
93
|
+
return null;
|
|
94
|
+
if (value.contentFormat !== "markdown" && value.contentFormat !== "text")
|
|
95
|
+
return null;
|
|
96
|
+
if (!isValidContentSha256(value.contentSha256))
|
|
97
|
+
return null;
|
|
98
|
+
if (!Array.isArray(value.passages))
|
|
99
|
+
return null;
|
|
100
|
+
const passages = [];
|
|
101
|
+
for (const raw of value.passages) {
|
|
102
|
+
const passage = decodePassage(raw);
|
|
103
|
+
if (passage === null)
|
|
104
|
+
return null;
|
|
105
|
+
passages.push(passage);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
url: value.url,
|
|
109
|
+
finalUrl: value.finalUrl,
|
|
110
|
+
title: title,
|
|
111
|
+
fetchedAt: value.fetchedAt,
|
|
112
|
+
provider: value.provider,
|
|
113
|
+
contentFormat: value.contentFormat,
|
|
114
|
+
contentSha256: value.contentSha256,
|
|
115
|
+
passages,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function decodeCoverage(value) {
|
|
119
|
+
if (!isPlainObject(value))
|
|
120
|
+
return null;
|
|
121
|
+
if (!isFiniteNumber(value.subQueries))
|
|
122
|
+
return null;
|
|
123
|
+
if (!isFiniteNumber(value.armsUsed))
|
|
124
|
+
return null;
|
|
125
|
+
if (!isFiniteNumber(value.sourcesConsidered))
|
|
126
|
+
return null;
|
|
127
|
+
if (!isFiniteNumber(value.sourcesRead))
|
|
128
|
+
return null;
|
|
129
|
+
if (!isFiniteNumber(value.cacheHits))
|
|
130
|
+
return null;
|
|
131
|
+
if (!Array.isArray(value.unread))
|
|
132
|
+
return null;
|
|
133
|
+
const unread = [];
|
|
134
|
+
for (const raw of value.unread) {
|
|
135
|
+
if (!isPlainObject(raw))
|
|
136
|
+
return null;
|
|
137
|
+
if (!isNonEmptyString(raw.url))
|
|
138
|
+
return null;
|
|
139
|
+
if (!isNonEmptyString(raw.reason))
|
|
140
|
+
return null;
|
|
141
|
+
unread.push({ url: raw.url, reason: raw.reason });
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
subQueries: value.subQueries,
|
|
145
|
+
armsUsed: value.armsUsed,
|
|
146
|
+
sourcesConsidered: value.sourcesConsidered,
|
|
147
|
+
sourcesRead: value.sourcesRead,
|
|
148
|
+
cacheHits: value.cacheHits,
|
|
149
|
+
unread,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Decode an `unknown` value into a canonical `EvidencePack`. Returns the
|
|
154
|
+
* typed pack on success, `null` for any malformed value. NEVER throws,
|
|
155
|
+
* NEVER trusts a generic cast.
|
|
156
|
+
*
|
|
157
|
+
* `title: null` is valid (reader parity). `sources` and `passages` may be
|
|
158
|
+
* empty arrays (a pack whose every read failed is still a valid, sad pack).
|
|
159
|
+
* `brief` (T7) is additive: unknown keys are NOT rejected — a decoded pack
|
|
160
|
+
* carries exactly the AC-6 keys, and an input carrying extra keys decodes
|
|
161
|
+
* to the canonical subset.
|
|
162
|
+
*/
|
|
163
|
+
export function decodeInvestigationPack(value) {
|
|
164
|
+
// PR #264 F1: total containment for the never-throws contract — a
|
|
165
|
+
// throwing getter or Proxy trap on untrusted input must surface as
|
|
166
|
+
// a fail-closed null, never as an exception out of the decoder.
|
|
167
|
+
try {
|
|
168
|
+
return decodeInvestigationPackInner(value);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function decodeInvestigationPackInner(value) {
|
|
175
|
+
if (!isPlainObject(value))
|
|
176
|
+
return null;
|
|
177
|
+
if (value.schemaVersion !== 1)
|
|
178
|
+
return null;
|
|
179
|
+
if (!isNonEmptyString(value.question))
|
|
180
|
+
return null;
|
|
181
|
+
if (!Array.isArray(value.subQueries))
|
|
182
|
+
return null;
|
|
183
|
+
for (const q of value.subQueries) {
|
|
184
|
+
if (!isNonEmptyString(q))
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
if (!Array.isArray(value.sources))
|
|
188
|
+
return null;
|
|
189
|
+
const sources = [];
|
|
190
|
+
for (const raw of value.sources) {
|
|
191
|
+
const source = decodeSource(raw);
|
|
192
|
+
if (source === null)
|
|
193
|
+
return null;
|
|
194
|
+
sources.push(source);
|
|
195
|
+
}
|
|
196
|
+
const coverage = decodeCoverage(value.coverage);
|
|
197
|
+
if (coverage === null)
|
|
198
|
+
return null;
|
|
199
|
+
// investigate-verify lane T2 (D4): additive-optional `verify` — absent
|
|
200
|
+
// keeps the canonical subset (question-mode byte identity); present is
|
|
201
|
+
// validated row-by-row and fails closed on any malformed row.
|
|
202
|
+
const verify = decodeVerifyBlock(value.verify, sources.length, (sourceIndex) => sources[sourceIndex] === undefined ? 0 : sources[sourceIndex].passages.length);
|
|
203
|
+
if (verify === undefined)
|
|
204
|
+
return null;
|
|
205
|
+
return {
|
|
206
|
+
schemaVersion: 1,
|
|
207
|
+
question: value.question,
|
|
208
|
+
subQueries: [...value.subQueries],
|
|
209
|
+
sources,
|
|
210
|
+
coverage,
|
|
211
|
+
...(verify !== null ? { verify } : {}),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const CLAIM_VERDICTS = ["corroborated", "contradicted", "unresolved"];
|
|
215
|
+
/**
|
|
216
|
+
* Decode the additive verify block. `undefined` = malformed (the caller
|
|
217
|
+
* fails closed); `null` = absent (the canonical subset stands); the
|
|
218
|
+
* decoded block = present + valid.
|
|
219
|
+
*
|
|
220
|
+
* PR #270 babysit: pointer RANGE is cross-checked against the decoded
|
|
221
|
+
* sources of the SAME pack (sourceIndex < sourceCount; passageIndex <
|
|
222
|
+
* that source's passage count) — a shape-safe but out-of-range pointer
|
|
223
|
+
* is malformed, INCLUDING any pointer into a zero-source pack (it can
|
|
224
|
+
* never dereference; assembly emits empty evidence there by
|
|
225
|
+
* construction, so only hand-built input reaches that arm).
|
|
226
|
+
*/
|
|
227
|
+
function decodeVerifyBlock(value, sourceCount, passageCountAt) {
|
|
228
|
+
if (value === undefined)
|
|
229
|
+
return null;
|
|
230
|
+
if (!isPlainObject(value))
|
|
231
|
+
return undefined;
|
|
232
|
+
if (!isNonEmptyString(value.statement))
|
|
233
|
+
return undefined;
|
|
234
|
+
if (!Array.isArray(value.claims))
|
|
235
|
+
return undefined;
|
|
236
|
+
const claims = [];
|
|
237
|
+
for (const raw of value.claims) {
|
|
238
|
+
if (!isPlainObject(raw))
|
|
239
|
+
return undefined;
|
|
240
|
+
if (!isNonEmptyString(raw.text))
|
|
241
|
+
return undefined;
|
|
242
|
+
if (typeof raw.verdict !== "string" || !CLAIM_VERDICTS.includes(raw.verdict)) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
if (typeof raw.negationCues !== "number" ||
|
|
246
|
+
!Number.isSafeInteger(raw.negationCues) ||
|
|
247
|
+
raw.negationCues < 0) {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
if (!Array.isArray(raw.evidence))
|
|
251
|
+
return undefined;
|
|
252
|
+
const evidence = [];
|
|
253
|
+
for (const pointer of raw.evidence) {
|
|
254
|
+
if (!isPlainObject(pointer))
|
|
255
|
+
return undefined;
|
|
256
|
+
if (!isSafeIndex(pointer.sourceIndex) || !isSafeIndex(pointer.passageIndex)) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
if (pointer.sourceIndex >= sourceCount ||
|
|
260
|
+
pointer.passageIndex >= passageCountAt(pointer.sourceIndex)) {
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
263
|
+
evidence.push({ sourceIndex: pointer.sourceIndex, passageIndex: pointer.passageIndex });
|
|
264
|
+
}
|
|
265
|
+
claims.push({
|
|
266
|
+
text: raw.text,
|
|
267
|
+
verdict: raw.verdict,
|
|
268
|
+
negationCues: raw.negationCues,
|
|
269
|
+
evidence,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return { statement: value.statement, claims };
|
|
273
|
+
}
|
|
274
|
+
/** Finite, safe, non-negative integer index (evidence pointer guard). */
|
|
275
|
+
function isSafeIndex(value) {
|
|
276
|
+
return (typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=investigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"investigation.js","sourceRoot":"","sources":["../../src/capabilities/investigation.ts"],"names":[],"mappings":"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"}
|
|
@@ -80,6 +80,13 @@ export declare function fetchWithArchiveBackoff<T = Response>(url: string, optio
|
|
|
80
80
|
timeout?: number;
|
|
81
81
|
headers?: Record<string, string>;
|
|
82
82
|
sleep?: (ms: number) => Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Abort-timer seam (the flake class: rows exercising non-timeout
|
|
85
|
+
* paths must not arm raceable real timers against local mocks —
|
|
86
|
+
* inject a recording never-fires stub; the default is the real
|
|
87
|
+
* setTimeout). The returned handle flows to clearTimeout verbatim.
|
|
88
|
+
*/
|
|
89
|
+
armTimer?: (ms: number, abort: () => void) => ReturnType<typeof setTimeout>;
|
|
83
90
|
}, consumer?: (res: Response) => Promise<T>): Promise<T>;
|
|
84
91
|
/**
|
|
85
92
|
* Enumerate captures via CDX server.
|
|
@@ -171,8 +178,18 @@ export declare function parseArchiveArgs(args: readonly string[]): {
|
|
|
171
178
|
readonly flags: Record<string, string | boolean>;
|
|
172
179
|
readonly showHelp: boolean;
|
|
173
180
|
};
|
|
181
|
+
export declare function parseArchiveTokens(tokens: readonly string[]): {
|
|
182
|
+
readonly subcommand?: string;
|
|
183
|
+
readonly positional: readonly string[];
|
|
184
|
+
readonly flags: Record<string, string | boolean>;
|
|
185
|
+
readonly showHelp: boolean;
|
|
186
|
+
};
|
|
174
187
|
/**
|
|
175
|
-
* Dispatcher handler for `archive` in `src/index.ts`.
|
|
188
|
+
* Dispatcher handler for `archive` in `src/index.ts`. INPUT CONTRACT:
|
|
189
|
+
* `args` are main()-normalized dispatch tokens (the equals-form seam has
|
|
190
|
+
* run). Raw-argv callers use {@link parseArchiveArgs} — the normalizing
|
|
191
|
+
* boundary; re-normalizing here would re-split produced values that
|
|
192
|
+
* start with `--` (the double-application defect, PR-278 review).
|
|
176
193
|
*/
|
|
177
194
|
export declare function handleArchive(args: string[], outputMode: OutputMode, deps: HandlerDependencies, forceRaw?: boolean): Promise<number>;
|
|
178
195
|
//# sourceMappingURL=archive.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/commands/archive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,0BAA0B,CAAC;AAE9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/commands/archive.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/archive.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
import { invokeCommand } from "../command-invocation.js";
|
|
19
19
|
import { ValidationError, TimeoutError, NetworkError } from "../lib/errors.js";
|
|
20
20
|
import { rejectSmuggledMaxChars } from "../lib/output-budget.js";
|
|
21
|
+
import { normalizeEqualsFormFlags } from "../lib/equals-form.js";
|
|
21
22
|
import { MAX_BUFFERED_RESPONSE_BYTES, readBoundedResponseBody } from "../lib/bounded-body.js";
|
|
22
23
|
import { DEFAULT_USER_AGENT, DEFAULT_FETCH_TIMEOUT_MS } from "./fetch.js";
|
|
23
24
|
import { extractSections, extractSectionsHashOnly, diffDocuments, isHtmlContentType, } from "../lib/section-diff.js";
|
|
@@ -58,11 +59,12 @@ export const DEFAULT_ARCHIVE_TIMEOUT_MS = 30000;
|
|
|
58
59
|
export async function fetchWithArchiveBackoff(url, options = {}, consumer) {
|
|
59
60
|
const timeoutMs = options.timeout ?? DEFAULT_ARCHIVE_TIMEOUT_MS;
|
|
60
61
|
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
62
|
+
const armTimer = options.armTimer ?? ((ms, abort) => setTimeout(abort, ms));
|
|
61
63
|
const maxRetries = 3;
|
|
62
64
|
let delay = 1000;
|
|
63
65
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
64
66
|
const controller = new AbortController();
|
|
65
|
-
const timer =
|
|
67
|
+
const timer = armTimer(timeoutMs, () => controller.abort());
|
|
66
68
|
try {
|
|
67
69
|
const res = await fetch(url, {
|
|
68
70
|
headers: {
|
|
@@ -766,12 +768,21 @@ export async function archiveDiffCommand(url, options = {}) {
|
|
|
766
768
|
* Parse CLI args for archive command.
|
|
767
769
|
*/
|
|
768
770
|
export function parseArchiveArgs(args) {
|
|
771
|
+
// #263: `--flag=value` ≡ `--flag value` (central seam). The EXPORTED
|
|
772
|
+
// entry normalizes for direct raw-argv callers (tests); main()'s
|
|
773
|
+
// dispatch path calls parseArchiveTokens with already-normalized
|
|
774
|
+
// tokens — the seam is single-application by construction (a second
|
|
775
|
+
// pass would re-split a produced VALUE that starts with `--` and
|
|
776
|
+
// contains `=`, breaking value preservation: `--foo=--bar=baz`).
|
|
777
|
+
return parseArchiveTokens(normalizeEqualsFormFlags(args));
|
|
778
|
+
}
|
|
779
|
+
export function parseArchiveTokens(tokens) {
|
|
769
780
|
let showHelp = false;
|
|
770
781
|
const flags = {};
|
|
771
782
|
const positional = [];
|
|
772
783
|
let i = 0;
|
|
773
|
-
while (i <
|
|
774
|
-
const arg =
|
|
784
|
+
while (i < tokens.length) {
|
|
785
|
+
const arg = tokens[i];
|
|
775
786
|
if (arg === undefined)
|
|
776
787
|
break;
|
|
777
788
|
if (arg === "--help" || arg === "-h") {
|
|
@@ -779,14 +790,8 @@ export function parseArchiveArgs(args) {
|
|
|
779
790
|
i++;
|
|
780
791
|
}
|
|
781
792
|
else if (arg.startsWith("--")) {
|
|
782
|
-
if (arg.includes("=")) {
|
|
783
|
-
// The `--flag=value` form is not supported: without this gate the
|
|
784
|
-
// token parses as a boolean flag under a garbage key
|
|
785
|
-
// ("timeout=300") and is silently dropped (#172 review F6).
|
|
786
|
-
throw new ValidationError(`Invalid flag "${arg}": the --flag=value form is not supported; pass the value as the next argument.`);
|
|
787
|
-
}
|
|
788
793
|
const key = arg.slice(2);
|
|
789
|
-
const next =
|
|
794
|
+
const next = tokens[i + 1];
|
|
790
795
|
if (next && !next.startsWith("-")) {
|
|
791
796
|
flags[key] = next;
|
|
792
797
|
i += 2;
|
|
@@ -841,10 +846,16 @@ function parseArchiveTimeout(raw) {
|
|
|
841
846
|
return undefined;
|
|
842
847
|
}
|
|
843
848
|
/**
|
|
844
|
-
* Dispatcher handler for `archive` in `src/index.ts`.
|
|
849
|
+
* Dispatcher handler for `archive` in `src/index.ts`. INPUT CONTRACT:
|
|
850
|
+
* `args` are main()-normalized dispatch tokens (the equals-form seam has
|
|
851
|
+
* run). Raw-argv callers use {@link parseArchiveArgs} — the normalizing
|
|
852
|
+
* boundary; re-normalizing here would re-split produced values that
|
|
853
|
+
* start with `--` (the double-application defect, PR-278 review).
|
|
845
854
|
*/
|
|
846
855
|
export async function handleArchive(args, outputMode, deps, forceRaw = false) {
|
|
847
|
-
|
|
856
|
+
// Single-application: main() normalized argv before dispatch; raw
|
|
857
|
+
// argv callers use parseArchiveArgs (the normalizing wrapper).
|
|
858
|
+
const { subcommand, positional, flags, showHelp } = parseArchiveTokens(args);
|
|
848
859
|
if (showHelp || subcommand === undefined) {
|
|
849
860
|
deps.invocation.writeStdout(ARCHIVE_HELP);
|
|
850
861
|
return 0;
|