@hawkeyexl/manni 4.5.0 → 4.7.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/README.md +1 -1
- package/dist/batch-U6S2JUUN.js +41 -0
- package/dist/build-4RN6WBCP.js +32 -0
- package/dist/calibrate-6VIZYR4L.js +36 -0
- package/dist/capture-DP3NXAZE.js +34 -0
- package/dist/{check-RQIIIURI.js → check-ERVNGKLC.js} +13 -14
- package/dist/check-IWHUPAZM.js +886 -0
- package/dist/check-IWHUPAZM.js.map +1 -0
- package/dist/{check-ESNS7ZBC.js → check-OAJWC3WD.js} +7 -5
- package/dist/check-STHXZIZO.js +26 -0
- package/dist/{chunk-TA42STP7.js → chunk-2ZWTSRE5.js} +4 -4
- package/dist/{chunk-F2OVHJNC.js → chunk-4Z2MN5FR.js} +11 -11
- package/dist/{chunk-HVFR66GQ.js → chunk-5UB47BEV.js} +3280 -283
- package/dist/chunk-5UB47BEV.js.map +1 -0
- package/dist/{chunk-TCC737IS.js → chunk-5VWDIWOH.js} +4 -4
- package/dist/{chunk-B7XUEQF3.js → chunk-6KKZXB2O.js} +7 -5
- package/dist/{chunk-B7XUEQF3.js.map → chunk-6KKZXB2O.js.map} +1 -1
- package/dist/{chunk-ELZ2IIOF.js → chunk-6URSCTTX.js} +2 -2
- package/dist/{chunk-K3U5F2QT.js → chunk-6VDBP5UV.js} +12 -12
- package/dist/chunk-7EL5LLKD.js +233 -0
- package/dist/chunk-7EL5LLKD.js.map +1 -0
- package/dist/{chunk-C3KI45RF.js → chunk-7XZ6INKO.js} +4 -4
- package/dist/{chunk-ZX43SRZR.js → chunk-AMEILOVV.js} +8 -6
- package/dist/{chunk-ZX43SRZR.js.map → chunk-AMEILOVV.js.map} +1 -1
- package/dist/{chunk-SNEHX4VE.js → chunk-B5CMM57M.js} +2 -2
- package/dist/chunk-BWCWTHYS.js +146 -0
- package/dist/chunk-BWCWTHYS.js.map +1 -0
- package/dist/{chunk-QLUMKWQQ.js → chunk-C2TJG5KV.js} +10 -6
- package/dist/{chunk-QLUMKWQQ.js.map → chunk-C2TJG5KV.js.map} +1 -1
- package/dist/{chunk-GAZFKZHM.js → chunk-CEVU3GFF.js} +6 -6
- package/dist/chunk-CI55ABCK.js +502 -0
- package/dist/chunk-CI55ABCK.js.map +1 -0
- package/dist/{chunk-QCBICNKC.js → chunk-CR3HZERW.js} +202 -54
- package/dist/chunk-CR3HZERW.js.map +1 -0
- package/dist/chunk-CU57HT2E.js +116 -0
- package/dist/chunk-CU57HT2E.js.map +1 -0
- package/dist/chunk-CWXZ2MRT.js +222 -0
- package/dist/chunk-CWXZ2MRT.js.map +1 -0
- package/dist/chunk-D2LBN44V.js +134 -0
- package/dist/chunk-D2LBN44V.js.map +1 -0
- package/dist/chunk-D6RO54QD.js +674 -0
- package/dist/chunk-D6RO54QD.js.map +1 -0
- package/dist/{chunk-52PDIZKV.js → chunk-ECVQNGTH.js} +3 -3
- package/dist/chunk-FQGLRJGX.js +174 -0
- package/dist/chunk-FQGLRJGX.js.map +1 -0
- package/dist/{chunk-NGK3N6F2.js → chunk-GCC52YZD.js} +3 -3
- package/dist/chunk-HX44GB4Z.js +30 -0
- package/dist/chunk-HX44GB4Z.js.map +1 -0
- package/dist/{chunk-NN4ASVTY.js → chunk-IIFADWWI.js} +4 -4
- package/dist/{chunk-OIZ3XMKB.js → chunk-IOL74S4J.js} +4 -4
- package/dist/{chunk-UK2I3ACY.js → chunk-IZBBXKMJ.js} +4 -4
- package/dist/{chunk-YA63PVWI.js → chunk-K52CS4KT.js} +12 -10
- package/dist/{chunk-YA63PVWI.js.map → chunk-K52CS4KT.js.map} +1 -1
- package/dist/{chunk-7OQAU4EA.js → chunk-LDKIIZDW.js} +16 -12
- package/dist/{chunk-7OQAU4EA.js.map → chunk-LDKIIZDW.js.map} +1 -1
- package/dist/{chunk-QY3DOZMS.js → chunk-LONRQBGV.js} +4 -4
- package/dist/{chunk-EL2BZTDL.js → chunk-LXJEAV2V.js} +13 -11
- package/dist/{chunk-EL2BZTDL.js.map → chunk-LXJEAV2V.js.map} +1 -1
- package/dist/{chunk-XWFNO5PO.js → chunk-MIBWI5H7.js} +3 -3
- package/dist/{chunk-527HHQPS.js → chunk-MSMB6XOS.js} +6 -4
- package/dist/{chunk-527HHQPS.js.map → chunk-MSMB6XOS.js.map} +1 -1
- package/dist/{chunk-C6HZ6C5T.js → chunk-NIFEEIGQ.js} +2 -2
- package/dist/{chunk-JQU7FHYH.js → chunk-NZ6TNSCU.js} +10 -10
- package/dist/{chunk-3R5Y3XOL.js → chunk-OOEMKOX6.js} +29 -591
- package/dist/chunk-OOEMKOX6.js.map +1 -0
- package/dist/{chunk-MZC62HPZ.js → chunk-PAOVVHQX.js} +2 -2
- package/dist/chunk-PNX43DYW.js +849 -0
- package/dist/chunk-PNX43DYW.js.map +1 -0
- package/dist/chunk-QCHVR4ZM.js +286 -0
- package/dist/chunk-QCHVR4ZM.js.map +1 -0
- package/dist/{chunk-SJO2FTPG.js → chunk-QP5X66TO.js} +73 -1304
- package/dist/chunk-QP5X66TO.js.map +1 -0
- package/dist/{chunk-HQFVJDEN.js → chunk-QQNPVW3J.js} +19 -19
- package/dist/chunk-TPVOOTMN.js +532 -0
- package/dist/chunk-TPVOOTMN.js.map +1 -0
- package/dist/{chunk-IA7BMIPE.js → chunk-UZKQSWHJ.js} +2 -2
- package/dist/chunk-WQWKYAAK.js +86 -0
- package/dist/chunk-WQWKYAAK.js.map +1 -0
- package/dist/{chunk-CP4ZM43V.js → chunk-WTEILBKC.js} +2 -2
- package/dist/{chunk-LJ2RDH3F.js → chunk-XG6PVB5S.js} +1 -23
- package/dist/chunk-XG6PVB5S.js.map +1 -0
- package/dist/{chunk-Q35YIDBV.js → chunk-XKBEHKWO.js} +29 -264
- package/dist/chunk-XKBEHKWO.js.map +1 -0
- package/dist/{chunk-BOIF2XGG.js → chunk-XXDXIIQ4.js} +2 -2
- package/dist/{chunk-6XTQDFGP.js → chunk-YSCZL4U5.js} +3 -3
- package/dist/{chunk-6XTQDFGP.js.map → chunk-YSCZL4U5.js.map} +1 -1
- package/dist/{chunk-7ZUCEMCY.js → chunk-ZEXGGGLW.js} +9 -11
- package/dist/{chunk-7ZUCEMCY.js.map → chunk-ZEXGGGLW.js.map} +1 -1
- package/dist/{chunk-DX32P2DT.js → chunk-ZKAKA54B.js} +2 -2
- package/dist/{chunk-TVIX653Q.js → chunk-ZKCNPKUO.js} +4 -4
- package/dist/{chunk-DE7JSWXV.js → chunk-ZNE25EAR.js} +8 -6
- package/dist/{chunk-DE7JSWXV.js.map → chunk-ZNE25EAR.js.map} +1 -1
- package/dist/{chunk-FLF6AECQ.js → chunk-ZPP75QWG.js} +17 -15
- package/dist/{chunk-FLF6AECQ.js.map → chunk-ZPP75QWG.js.map} +1 -1
- package/dist/{cli-PRZHQ3QB.js → cli-37SRAYNE.js} +14 -15
- package/dist/{cli-PRZHQ3QB.js.map → cli-37SRAYNE.js.map} +1 -1
- package/dist/{cli-TYGOHJOJ.js → cli-HXWYUKGJ.js} +225 -58
- package/dist/cli-HXWYUKGJ.js.map +1 -0
- package/dist/{cli-HUIMNJT6.js → cli-IRHPPUFJ.js} +19 -20
- package/dist/{cli-HUIMNJT6.js.map → cli-IRHPPUFJ.js.map} +1 -1
- package/dist/{cli-6PGVHP7Y.js → cli-KIID535Y.js} +17 -19
- package/dist/{cli-6PGVHP7Y.js.map → cli-KIID535Y.js.map} +1 -1
- package/dist/{cli-AAG3N4NB.js → cli-MTDGQIIV.js} +17 -18
- package/dist/{cli-AAG3N4NB.js.map → cli-MTDGQIIV.js.map} +1 -1
- package/dist/{cli-E3H6ZP4I.js → cli-NM6FZ54R.js} +5 -3
- package/dist/{cli-E3H6ZP4I.js.map → cli-NM6FZ54R.js.map} +1 -1
- package/dist/{cli-MHTYPVOD.js → cli-XIODOEUG.js} +113 -20
- package/dist/{cli-MHTYPVOD.js.map → cli-XIODOEUG.js.map} +1 -1
- package/dist/{cli-YW6VWBHX.js → cli-YL3IDR52.js} +10 -10
- package/dist/{cli-QKIJOXGW.js → cli-ZQUJYQBA.js} +17 -17
- package/dist/cli.js +11 -11
- package/dist/config-O6UBGEDK.js +26 -0
- package/dist/conformance-ALLPNGEQ.js +18 -0
- package/dist/docmeta.js +9 -9
- package/dist/github-UCYLM3DR.js +26 -0
- package/dist/github-VEJFO6JJ.js +31 -0
- package/dist/host-6GURH5HE.js +23 -0
- package/dist/index.d.ts +72 -4
- package/dist/index.js +176 -166
- package/dist/index.js.map +1 -1
- package/dist/{json-4DCKDGUV.js → json-6F52FSXZ.js} +12 -13
- package/dist/lint-X2GNINK6.js +29 -0
- package/dist/list-DP3O3CWB.js +30 -0
- package/dist/list-P77RZFZF.js +28 -0
- package/dist/{page-QEDB7EVU.js → page-WQCMBNRD.js} +11 -12
- package/dist/prepare-52QOK7M4.js +155 -0
- package/dist/prepare-52QOK7M4.js.map +1 -0
- package/dist/{pretty-SQX33UM2.js → pretty-5MMMNSWF.js} +13 -14
- package/dist/{pretty-5DGEBZSV.js → pretty-H4DQREMW.js} +12 -13
- package/dist/provider-AMGRDY6V.js +34 -0
- package/dist/release-CTYRHZL4.js +36 -0
- package/dist/release-CTYRHZL4.js.map +1 -0
- package/dist/{reporters-YELDDYJD.js → reporters-SU3VUKKX.js} +7 -5
- package/dist/{reporters-OHSI3RMV.js → reporters-WIHBEMPG.js} +11 -12
- package/dist/reporters-WIHBEMPG.js.map +1 -0
- package/dist/run-L2DWJ26K.js +32 -0
- package/dist/run-L2DWJ26K.js.map +1 -0
- package/dist/{term-2WMDZ4PY.js → term-PJIJQZNF.js} +16 -17
- package/dist/{term-2WMDZ4PY.js.map → term-PJIJQZNF.js.map} +1 -1
- package/dist/validate-XCDSPURG.js +17 -0
- package/dist/validate-XCDSPURG.js.map +1 -0
- package/package.json +2 -2
- package/plugin/manni/.claude-plugin/plugin.json +1 -1
- package/plugin/manni/hooks/hooks.json +47 -0
- package/dist/batch-GOE3UXOD.js +0 -36
- package/dist/build-M7BMEHL2.js +0 -33
- package/dist/calibrate-6RRAILUY.js +0 -31
- package/dist/capture-RJPQ6B4N.js +0 -32
- package/dist/check-BQD64X3N.js +0 -27
- package/dist/chunk-3R5Y3XOL.js.map +0 -1
- package/dist/chunk-3YHAYXBC.js +0 -164
- package/dist/chunk-3YHAYXBC.js.map +0 -1
- package/dist/chunk-HVFR66GQ.js.map +0 -1
- package/dist/chunk-LJ2RDH3F.js.map +0 -1
- package/dist/chunk-NAZRLJAK.js +0 -3090
- package/dist/chunk-NAZRLJAK.js.map +0 -1
- package/dist/chunk-Q35YIDBV.js.map +0 -1
- package/dist/chunk-QCBICNKC.js.map +0 -1
- package/dist/chunk-SJO2FTPG.js.map +0 -1
- package/dist/chunk-TU2WUBVZ.js +0 -2
- package/dist/cli-TYGOHJOJ.js.map +0 -1
- package/dist/github-3WMSTNTK.js +0 -32
- package/dist/github-OXSJQ4PS.js +0 -27
- package/dist/lint-YDHVVZHT.js +0 -30
- package/dist/list-3ZO2NIYO.js +0 -31
- package/dist/list-EJH6VAOW.js +0 -29
- package/dist/run-IP6NZHAG.js +0 -33
- package/dist/validate-G6HH3YXL.js +0 -16
- /package/dist/{batch-GOE3UXOD.js.map → batch-U6S2JUUN.js.map} +0 -0
- /package/dist/{build-M7BMEHL2.js.map → build-4RN6WBCP.js.map} +0 -0
- /package/dist/{calibrate-6RRAILUY.js.map → calibrate-6VIZYR4L.js.map} +0 -0
- /package/dist/{capture-RJPQ6B4N.js.map → capture-DP3NXAZE.js.map} +0 -0
- /package/dist/{check-BQD64X3N.js.map → check-ERVNGKLC.js.map} +0 -0
- /package/dist/{check-ESNS7ZBC.js.map → check-OAJWC3WD.js.map} +0 -0
- /package/dist/{check-RQIIIURI.js.map → check-STHXZIZO.js.map} +0 -0
- /package/dist/{chunk-TA42STP7.js.map → chunk-2ZWTSRE5.js.map} +0 -0
- /package/dist/{chunk-F2OVHJNC.js.map → chunk-4Z2MN5FR.js.map} +0 -0
- /package/dist/{chunk-TCC737IS.js.map → chunk-5VWDIWOH.js.map} +0 -0
- /package/dist/{chunk-ELZ2IIOF.js.map → chunk-6URSCTTX.js.map} +0 -0
- /package/dist/{chunk-K3U5F2QT.js.map → chunk-6VDBP5UV.js.map} +0 -0
- /package/dist/{chunk-C3KI45RF.js.map → chunk-7XZ6INKO.js.map} +0 -0
- /package/dist/{chunk-SNEHX4VE.js.map → chunk-B5CMM57M.js.map} +0 -0
- /package/dist/{chunk-GAZFKZHM.js.map → chunk-CEVU3GFF.js.map} +0 -0
- /package/dist/{chunk-52PDIZKV.js.map → chunk-ECVQNGTH.js.map} +0 -0
- /package/dist/{chunk-NGK3N6F2.js.map → chunk-GCC52YZD.js.map} +0 -0
- /package/dist/{chunk-NN4ASVTY.js.map → chunk-IIFADWWI.js.map} +0 -0
- /package/dist/{chunk-OIZ3XMKB.js.map → chunk-IOL74S4J.js.map} +0 -0
- /package/dist/{chunk-UK2I3ACY.js.map → chunk-IZBBXKMJ.js.map} +0 -0
- /package/dist/{chunk-QY3DOZMS.js.map → chunk-LONRQBGV.js.map} +0 -0
- /package/dist/{chunk-XWFNO5PO.js.map → chunk-MIBWI5H7.js.map} +0 -0
- /package/dist/{chunk-C6HZ6C5T.js.map → chunk-NIFEEIGQ.js.map} +0 -0
- /package/dist/{chunk-JQU7FHYH.js.map → chunk-NZ6TNSCU.js.map} +0 -0
- /package/dist/{chunk-MZC62HPZ.js.map → chunk-PAOVVHQX.js.map} +0 -0
- /package/dist/{chunk-HQFVJDEN.js.map → chunk-QQNPVW3J.js.map} +0 -0
- /package/dist/{chunk-IA7BMIPE.js.map → chunk-UZKQSWHJ.js.map} +0 -0
- /package/dist/{chunk-CP4ZM43V.js.map → chunk-WTEILBKC.js.map} +0 -0
- /package/dist/{chunk-BOIF2XGG.js.map → chunk-XXDXIIQ4.js.map} +0 -0
- /package/dist/{chunk-DX32P2DT.js.map → chunk-ZKAKA54B.js.map} +0 -0
- /package/dist/{chunk-TVIX653Q.js.map → chunk-ZKCNPKUO.js.map} +0 -0
- /package/dist/{chunk-TU2WUBVZ.js.map → cli-YL3IDR52.js.map} +0 -0
- /package/dist/{cli-QKIJOXGW.js.map → cli-ZQUJYQBA.js.map} +0 -0
- /package/dist/{cli-YW6VWBHX.js.map → config-O6UBGEDK.js.map} +0 -0
- /package/dist/{github-3WMSTNTK.js.map → conformance-ALLPNGEQ.js.map} +0 -0
- /package/dist/{github-OXSJQ4PS.js.map → github-UCYLM3DR.js.map} +0 -0
- /package/dist/{json-4DCKDGUV.js.map → github-VEJFO6JJ.js.map} +0 -0
- /package/dist/{lint-YDHVVZHT.js.map → host-6GURH5HE.js.map} +0 -0
- /package/dist/{list-3ZO2NIYO.js.map → json-6F52FSXZ.js.map} +0 -0
- /package/dist/{list-EJH6VAOW.js.map → lint-X2GNINK6.js.map} +0 -0
- /package/dist/{page-QEDB7EVU.js.map → list-DP3O3CWB.js.map} +0 -0
- /package/dist/{pretty-5DGEBZSV.js.map → list-P77RZFZF.js.map} +0 -0
- /package/dist/{pretty-SQX33UM2.js.map → page-WQCMBNRD.js.map} +0 -0
- /package/dist/{reporters-OHSI3RMV.js.map → pretty-5MMMNSWF.js.map} +0 -0
- /package/dist/{reporters-YELDDYJD.js.map → pretty-H4DQREMW.js.map} +0 -0
- /package/dist/{run-IP6NZHAG.js.map → provider-AMGRDY6V.js.map} +0 -0
- /package/dist/{validate-G6HH3YXL.js.map → reporters-SU3VUKKX.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tracevals/trace/claude.ts","../src/tracevals/trace/detect.ts","../src/tracevals/judge/render.ts"],"sourcesContent":["/**\n * Claude Code trace adapter. Parses both dialects behind one entry point:\n * session files (~/.claude/projects/<slug>/*.jsonl) and legacy `claude -p`\n * stream-json transcripts. Produces the normalized Trace model.\n */\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { detectContentFormat } from \"./detect.js\";\nimport {\n applyAvailabilityRecord,\n foldBranchAvailability,\n newAvailability,\n newReplay,\n remapAvailability,\n} from \"./availability.js\";\nimport type {\n AgentSpawn,\n FileAccess,\n SkillInvocation,\n SubagentBranch,\n ToolCall,\n Trace,\n TraceEvent,\n} from \"./types.js\";\n\ntype Rec = Record<string, unknown>;\n\nexport async function parseTraceFile(filePath: string): Promise<Trace> {\n const absolute = resolve(filePath);\n const content = await readFile(absolute, \"utf-8\");\n const trace = parseTraceContent(content, absolute);\n await mergeSidecarBranches(trace, absolute);\n return trace;\n}\n\nexport function parseTraceContent(content: string, filePath: string): Trace {\n const format = detectContentFormat(content);\n const { records, unparseable } = parseLines(content);\n const trace =\n format === \"claude-session\"\n ? parseSession(records, filePath)\n : parseStream(records, filePath);\n if (unparseable > 0) {\n trace.warnings.push(\n `${unparseable} unparseable JSONL line(s) were skipped`,\n );\n }\n return trace;\n}\n\nfunction parseLines(content: string): { records: Rec[]; unparseable: number } {\n const records: Rec[] = [];\n let unparseable = 0;\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const rec = JSON.parse(trimmed) as unknown;\n if (typeof rec === \"object\" && rec !== null) records.push(rec as Rec);\n else unparseable += 1;\n } catch {\n unparseable += 1;\n }\n }\n return { records, unparseable };\n}\n\n/** Record types that carry no conversation content. */\nconst SESSION_META_TYPES = new Set([\n \"queue-operation\",\n \"attachment\",\n \"last-prompt\",\n \"custom-title\",\n \"summary\",\n \"mode\",\n \"pr-link\",\n]);\n\nconst COMMAND_NAME_RE = /<command-name>([^<]+)<\\/command-name>/;\nconst COMMAND_ARGS_RE = /<command-args>([^<]*)<\\/command-args>/;\n\n/**\n * An `Agent` tool_use waiting for the sidechain records it spawned. `claimed`\n * disambiguates the case where one assistant turn spawns several subagents at\n * once and their records interleave.\n */\ninterface PendingBranch {\n toolUseId: string;\n prompt?: string;\n claimed: boolean;\n}\n\n/**\n * Subagent branch attribution. A sidechain record chains by `parentUuid` back\n * to the assistant record that carried the spawning `Agent` tool_use, so that\n * tool_use id is the branch identity. Records are written parent-first, which\n * is what lets one forward pass resolve the whole tree.\n */\ninterface BranchIndex {\n /** Agent spawns keyed by the uuid of the assistant record carrying them. */\n spawns: Map<string, PendingBranch[]>;\n /** Branch already resolved for a record, so its children inherit it. */\n resolved: Map<string, string>;\n}\n\n/** What a single on-disk record contributes to every event it produces. */\ninterface RecordContext {\n sidechain: boolean;\n timestamp?: string;\n branchId?: string;\n /** Session records only: lets `Agent` spawns be indexed by record uuid. */\n uuid?: string;\n branches?: BranchIndex;\n}\n\nfunction newTrace(filePath: string): Trace {\n return {\n source: \"claude-code\",\n file: filePath,\n cwd: \"\",\n events: [],\n toolCalls: [],\n skillInvocations: [],\n agentSpawns: [],\n subagentBranches: [],\n availability: newAvailability(),\n fileAccesses: [],\n userMessages: [],\n assistantTexts: [],\n turnCount: 0,\n warnings: [],\n };\n}\n\n/** Append an event, stamping its own ordinal, and hand that ordinal back. */\nfunction pushEvent(trace: Trace, event: Omit<TraceEvent, \"index\">): number {\n const index = trace.events.length;\n trace.events.push({ ...event, index });\n return index;\n}\n\n/** A sidechain root's message is the Agent prompt verbatim — the tiebreak. */\nfunction plainMessageText(rec: Rec): string | undefined {\n const content = (rec.message as Rec | undefined)?.content;\n return typeof content === \"string\" ? content : undefined;\n}\n\nfunction resolveBranch(\n branches: BranchIndex,\n parentUuid: unknown,\n rootText: string | undefined,\n): string | undefined {\n if (typeof parentUuid !== \"string\") return undefined;\n const inherited = branches.resolved.get(parentUuid);\n if (inherited !== undefined) return inherited;\n const pending = branches.spawns.get(parentUuid);\n if (pending === undefined || pending.length === 0) return undefined;\n const byPrompt =\n rootText !== undefined\n ? pending.find((b) => !b.claimed && b.prompt === rootText)\n : undefined;\n const branch = byPrompt ?? pending.find((b) => !b.claimed) ?? pending[0];\n if (branch === undefined) return undefined;\n branch.claimed = true;\n return branch.toolUseId;\n}\n\nfunction parseSession(records: Rec[], filePath: string): Trace {\n const trace = newTrace(filePath);\n const branches: BranchIndex = { spawns: new Map(), resolved: new Map() };\n // Availability is replayed in record order: `isInitial` replaces the set,\n // a delta adds or removes, and each entry keeps the ordinal it changed at\n // (ADR 01016).\n const availability = newReplay();\n // Resolving a continuation pointer needs the whole file's uuids up front.\n const uuids = new Set<string>();\n for (const rec of records) {\n if (typeof rec.uuid === \"string\") uuids.add(rec.uuid);\n }\n // A leading `summary` record describes the *previous* session and its\n // `leafUuid` names a record there; a pointer that resolves in this file is\n // this session's own summary, not a continuation.\n const continuations: string[] = [];\n let sawMessage = false;\n let compactions = 0;\n let inputTokens = 0;\n let outputTokens = 0;\n let sawUsage = false;\n\n for (const rec of records) {\n const type = rec.type as string | undefined;\n const timestamp = rec.timestamp as string | undefined;\n if (timestamp) {\n trace.startedAt ??= timestamp;\n trace.endedAt = timestamp;\n }\n if (rec.sessionId) trace.sessionId ??= rec.sessionId as string;\n if (rec.subtype === \"compact_boundary\") compactions += 1;\n\n if (type !== undefined && SESSION_META_TYPES.has(type)) {\n if (\n type === \"summary\" &&\n !sawMessage &&\n typeof rec.leafUuid === \"string\" &&\n !uuids.has(rec.leafUuid)\n ) {\n continuations.push(rec.leafUuid);\n }\n const index = pushEvent(trace, { kind: \"meta\", timestamp, raw: rec });\n // An `attachment` record is bookkeeping to every other consumer, but the\n // listing ones are the only record of what the session was *offered*.\n if (\n type === \"attachment\" &&\n applyAvailabilityRecord(availability, rec.attachment, index)\n ) {\n availability.roster.recorded = true;\n }\n continue;\n }\n\n const sidechain = rec.isSidechain === true;\n // cwd/gitBranch follow the latest non-sidechain message record.\n if (!sidechain && typeof rec.cwd === \"string\") trace.cwd = rec.cwd;\n if (!sidechain && typeof rec.gitBranch === \"string\") {\n trace.gitBranch = rec.gitBranch;\n }\n\n const context: RecordContext = { sidechain, timestamp, branches };\n if (typeof rec.uuid === \"string\") context.uuid = rec.uuid;\n if (sidechain) {\n const branchId = resolveBranch(\n branches,\n rec.parentUuid,\n plainMessageText(rec),\n );\n if (branchId !== undefined) {\n context.branchId = branchId;\n if (context.uuid) branches.resolved.set(context.uuid, branchId);\n }\n }\n\n const message = rec.message as Rec | undefined;\n if (type === \"user\" && message) {\n sawMessage = true;\n handleUserMessage(trace, message, context, rec);\n } else if (type === \"assistant\" && message) {\n sawMessage = true;\n const usage = handleAssistantMessage(trace, message, context, rec);\n if (usage && !sidechain) {\n inputTokens += usage.input;\n outputTokens += usage.output;\n sawUsage = true;\n }\n } else {\n pushEvent(trace, { kind: \"system\", timestamp, raw: rec });\n }\n }\n\n if (sawUsage) trace.usage = { inputTokens, outputTokens };\n // Grading a fragment as if it were the whole session is a false verdict, so\n // both ways of losing earlier turns are reported rather than assumed away.\n for (const leaf of continuations) {\n trace.warnings.push(\n `this trace is a fragment of a longer session: it resumes an earlier ` +\n `one recorded elsewhere (summary leafUuid ${leaf} is not in this ` +\n `file), so evals see only the turns recorded here`,\n );\n }\n if (compactions > 0) {\n trace.warnings.push(\n `the conversation was compacted ${compactions} time(s): the agent ` +\n `stopped seeing the turns before each boundary, so early transcript ` +\n `content is not what it was working from`,\n );\n }\n trace.availability = availability.roster;\n trace.subagentBranches = buildBranches(trace);\n return trace;\n}\n\n/**\n * Derive the branch list from whatever branch identity the events already\n * carry. Runs for inline sidechains at parse time and again after sidecar\n * transcripts are spliced in, so both shapes produce the same descriptions.\n */\nfunction buildBranches(\n trace: Trace,\n sidecars: Map<string, Partial<SubagentBranch>> = new Map(),\n): SubagentBranch[] {\n const ranges = new Map<string, { min: number; max: number }>();\n for (const event of trace.events) {\n const id = event.branchId;\n if (id === undefined) continue;\n const range = ranges.get(id);\n if (range === undefined) ranges.set(id, { min: event.index, max: event.index });\n else range.max = Math.max(range.max, event.index);\n }\n if (ranges.size === 0) return [];\n\n const spawnFor = new Map<string, AgentSpawn>();\n for (const spawn of trace.agentSpawns) {\n if (spawn.toolUseId) spawnFor.set(spawn.toolUseId, spawn);\n }\n\n // A branch's parent is whichever branch owns its spawning `Agent` call.\n const parentOf = new Map<string, string | undefined>();\n for (const id of ranges.keys()) {\n const spawn = spawnFor.get(id);\n parentOf.set(\n id,\n spawn ? trace.events[spawn.index]?.branchId : undefined,\n );\n }\n const depthOf = (id: string): number => {\n let depth = 1;\n let cursor = parentOf.get(id);\n const seen = new Set<string>([id]);\n while (cursor !== undefined && !seen.has(cursor)) {\n seen.add(cursor);\n depth += 1;\n cursor = parentOf.get(cursor);\n }\n return depth;\n };\n\n const branches: SubagentBranch[] = [];\n for (const [id, range] of ranges) {\n const spawn = spawnFor.get(id);\n const sidecar = sidecars.get(id);\n const branch: SubagentBranch = {\n branchId: id,\n agentType: sidecar?.agentType ?? spawn?.subagentType ?? id,\n origin: sidecar ? \"sidecar\" : \"inline\",\n spawnDepth: sidecar?.spawnDepth ?? depthOf(id),\n spawnIndex: spawn?.index ?? range.min,\n startIndex: range.min,\n endIndex: range.max + 1,\n };\n const description = sidecar?.description ?? spawn?.description;\n if (description !== undefined) branch.description = description;\n if (sidecar?.agentId) branch.agentId = sidecar.agentId;\n if (sidecar?.parentAgentId) branch.parentAgentId = sidecar.parentAgentId;\n if (sidecar?.file) branch.file = sidecar.file;\n branches.push(branch);\n }\n\n // A branch's span covers the branches nested under it, so widen deepest\n // first and every ancestor inherits the reach of its whole subtree.\n branches.sort((a, b) => b.spawnDepth - a.spawnDepth);\n const byId = new Map(branches.map((b) => [b.branchId, b]));\n for (const branch of branches) {\n const parentId = parentOf.get(branch.branchId);\n const parent = parentId === undefined ? undefined : byId.get(parentId);\n if (parent === undefined) continue;\n parent.startIndex = Math.min(parent.startIndex, branch.startIndex);\n parent.endIndex = Math.max(parent.endIndex, branch.endIndex);\n }\n branches.sort((a, b) => a.startIndex - b.startIndex);\n return branches;\n}\n\nfunction handleUserMessage(\n trace: Trace,\n message: Rec,\n context: RecordContext,\n raw: Rec,\n): void {\n const { sidechain, timestamp, branchId } = context;\n const content = message.content;\n if (typeof content === \"string\") {\n const index = pushEvent(trace, {\n kind: \"user\",\n timestamp,\n text: content,\n sidechain,\n branchId,\n raw,\n });\n if (sidechain) return;\n const command = COMMAND_NAME_RE.exec(content);\n if (command?.[1]) {\n const invocation: SkillInvocation = {\n name: command[1].replace(/^\\//, \"\"),\n via: \"command-injection\",\n index,\n };\n const args = COMMAND_ARGS_RE.exec(content)?.[1]?.trim();\n if (args) invocation.args = args;\n trace.skillInvocations.push(invocation);\n }\n trace.userMessages.push(content);\n trace.turnCount += 1;\n return;\n }\n if (Array.isArray(content)) {\n // Tool results (and mixed blocks). Text blocks alongside tool results are\n // rare; only pure text turns count as prompts.\n let hasToolResult = false;\n const texts: string[] = [];\n // `Rec | null`, because a JSON array really can hold a null and the\n // guards below are what handle it.\n for (const block of content as (Rec | null)[]) {\n if (block?.type === \"tool_result\") hasToolResult = true;\n if (block?.type === \"text\" && typeof block.text === \"string\") {\n texts.push(block.text);\n }\n }\n if (hasToolResult) {\n pushEvent(trace, {\n kind: \"tool_result\",\n timestamp,\n sidechain,\n branchId,\n raw,\n });\n return;\n }\n const text = texts.join(\"\\n\");\n pushEvent(trace, {\n kind: \"user\",\n timestamp,\n text,\n sidechain,\n branchId,\n raw,\n });\n if (!sidechain && text) {\n trace.userMessages.push(text);\n trace.turnCount += 1;\n }\n }\n}\n\nfunction handleAssistantMessage(\n trace: Trace,\n message: Rec,\n context: RecordContext,\n raw: Rec,\n): { input: number; output: number } | undefined {\n const { sidechain, timestamp, branchId } = context;\n if (!sidechain && typeof message.model === \"string\") {\n trace.model ??= message.model;\n }\n const content = message.content;\n if (Array.isArray(content)) {\n for (const block of content as (Rec | null)[]) {\n if (block?.type === \"text\" && typeof block.text === \"string\") {\n pushEvent(trace, {\n kind: \"assistant\",\n timestamp,\n text: block.text,\n sidechain,\n branchId,\n raw,\n });\n if (!sidechain) trace.assistantTexts.push(block.text);\n } else if (block?.type === \"tool_use\") {\n extractToolUse(trace, block, context);\n }\n }\n }\n const usage = message.usage as Rec | undefined;\n if (usage) {\n return {\n input: typeof usage.input_tokens === \"number\" ? usage.input_tokens : 0,\n output: typeof usage.output_tokens === \"number\" ? usage.output_tokens : 0,\n };\n }\n return undefined;\n}\n\nfunction extractToolUse(\n trace: Trace,\n block: Rec,\n context: RecordContext,\n): void {\n const { sidechain, timestamp, branchId } = context;\n const name = block.name as string;\n const input = (block.input as Rec | undefined) ?? {};\n const toolUseId = typeof block.id === \"string\" ? block.id : undefined;\n const index = pushEvent(trace, {\n kind: \"tool_call\",\n timestamp,\n toolName: name,\n sidechain,\n branchId,\n raw: block,\n });\n const call: ToolCall = { name, input, index, sidechain };\n if (timestamp) call.timestamp = timestamp;\n if (branchId) call.branchId = branchId;\n trace.toolCalls.push(call);\n\n switch (name) {\n case \"Skill\": {\n if (typeof input.skill === \"string\") {\n const invocation: SkillInvocation = {\n name: input.skill,\n via: \"skill-tool\",\n index,\n };\n if (toolUseId) invocation.toolUseId = toolUseId;\n if (typeof input.args === \"string\" && input.args) {\n invocation.args = input.args;\n }\n trace.skillInvocations.push(invocation);\n }\n break;\n }\n case \"Agent\": {\n if (typeof input.subagent_type === \"string\") {\n const spawn: AgentSpawn = {\n subagentType: input.subagent_type,\n index,\n };\n if (typeof input.description === \"string\") {\n spawn.description = input.description;\n }\n if (toolUseId) spawn.toolUseId = toolUseId;\n trace.agentSpawns.push(spawn);\n }\n // The spawn opens a branch its sidechain records chain back to.\n if (context.branches && context.uuid && toolUseId) {\n const pending = context.branches.spawns.get(context.uuid) ?? [];\n pending.push({\n toolUseId,\n prompt: typeof input.prompt === \"string\" ? input.prompt : undefined,\n claimed: false,\n });\n context.branches.spawns.set(context.uuid, pending);\n }\n break;\n }\n case \"Read\":\n case \"Write\":\n case \"Edit\": {\n if (typeof input.file_path === \"string\") {\n const op: FileAccess[\"op\"] =\n name === \"Read\" ? \"read\" : name === \"Write\" ? \"write\" : \"edit\";\n trace.fileAccesses.push({ path: input.file_path, op, index });\n }\n break;\n }\n }\n}\n\nfunction parseStream(records: Rec[], filePath: string): Trace {\n const trace = newTrace(filePath);\n // stream-json has no sidechains, so every record shares one flat context.\n const context: RecordContext = { sidechain: false };\n let inputTokens = 0;\n let outputTokens = 0;\n let sawMessageUsage = false;\n\n for (const rec of records) {\n const type = rec.type as string | undefined;\n\n if (type === \"system\" && (rec.subtype === \"init\" || !rec.subtype)) {\n if (typeof rec.cwd === \"string\") trace.cwd = rec.cwd;\n if (typeof rec.model === \"string\") trace.model = rec.model;\n if (typeof rec.session_id === \"string\") trace.sessionId = rec.session_id;\n pushEvent(trace, { kind: \"system\", raw: rec });\n continue;\n }\n\n if (type === \"assistant\" || type === \"user\") {\n const message = (rec.message as Rec | undefined) ?? rec;\n if (type === \"assistant\") {\n const usage = handleAssistantMessage(trace, message, context, rec);\n if (usage) {\n inputTokens += usage.input;\n outputTokens += usage.output;\n sawMessageUsage = true;\n }\n } else {\n handleUserMessage(trace, message, context, rec);\n }\n continue;\n }\n\n if (type === \"result\") {\n trace.isError = rec.is_error === true;\n if (typeof rec.num_turns === \"number\") trace.turnCount = rec.num_turns;\n const usage = rec.usage as Rec | undefined;\n const totalCost =\n typeof rec.total_cost_usd === \"number\" ? rec.total_cost_usd : undefined;\n if (usage) {\n trace.usage = {\n inputTokens:\n typeof usage.input_tokens === \"number\" ? usage.input_tokens : 0,\n outputTokens:\n typeof usage.output_tokens === \"number\" ? usage.output_tokens : 0,\n };\n if (totalCost !== undefined) trace.usage.totalCostUsd = totalCost;\n } else if (sawMessageUsage) {\n trace.usage = { inputTokens, outputTokens };\n if (totalCost !== undefined) trace.usage.totalCostUsd = totalCost;\n }\n pushEvent(trace, { kind: \"meta\", raw: rec });\n continue;\n }\n\n pushEvent(trace, { kind: \"meta\", raw: rec });\n }\n\n if (!trace.usage && sawMessageUsage) {\n trace.usage = { inputTokens, outputTokens };\n }\n return trace;\n}\n\n/* ------------------------------------------------------------------------ *\n * Sidecar subagent transcripts (ADR 01014)\n *\n * Current Claude Code no longer writes subagent turns into the session file.\n * It writes each branch to `<session>/subagents/agent-<id>.jsonl` beside an\n * `agent-<id>.meta.json` naming the `Agent` tool_use that spawned it, so the\n * join is exact rather than heuristic. Every branch is spliced into\n * `trace.events` immediately after that spawning call, which keeps a branch\n * (and any branch nested inside it) contiguous and keeps `index` a gap-free\n * ordinal over the merged list.\n * ------------------------------------------------------------------------ */\n\n/** `agent-<id>.meta.json`. Every member is optional in real stores. */\ninterface SidecarMeta {\n agentType?: string;\n description?: string;\n toolUseId?: string;\n parentAgentId?: string;\n spawnDepth?: number;\n}\n\n/** One transcript to splice: the base session file, or a loaded sidecar. */\ninterface MergeSource {\n id: string;\n events: TraceEvent[];\n toolCalls: ToolCall[];\n fileAccesses: FileAccess[];\n skillInvocations: SkillInvocation[];\n agentSpawns: AgentSpawn[];\n}\n\ninterface LoadedSidecar {\n agentId: string;\n file: string;\n meta: SidecarMeta;\n sub: Trace;\n source: MergeSource;\n}\n\nconst AGENT_META_RE = /^agent-(.+)\\.meta\\.json$/;\nconst AGENT_JSONL_RE = /^agent-(.+)\\.jsonl$/;\n\n/** `<dir>/<session>.jsonl` -> `<dir>/<session>/subagents`. */\nfunction sidecarDirFor(traceFile: string): string {\n const stem = basename(traceFile).replace(/\\.jsonl$/i, \"\");\n return join(dirname(traceFile), stem, \"subagents\");\n}\n\nfunction asSource(id: string, trace: Trace): MergeSource {\n return {\n id,\n events: trace.events,\n toolCalls: trace.toolCalls,\n fileAccesses: trace.fileAccesses,\n skillInvocations: trace.skillInvocations,\n agentSpawns: trace.agentSpawns,\n };\n}\n\n/**\n * Every record in one sidecar carries the same `agentId`, so the whole file is\n * one branch and that file-level fact overrides anything inferred inside it.\n * It has to: `isSidechain` is uniformly true within a sidecar, so the inline\n * `parentUuid` heuristic would hand this agent's own later turns to a nested\n * `Agent` call whose records actually live in a different file.\n */\nfunction stampBranch(sub: Trace, branchId: string): void {\n for (const event of sub.events) {\n event.sidechain = true;\n event.branchId = branchId;\n }\n for (const call of sub.toolCalls) {\n call.sidechain = true;\n call.branchId = branchId;\n }\n}\n\n/**\n * Read every `agent-*.meta.json` beside a session file and parse its\n * transcript. A directory that is not there is the ordinary case and says\n * nothing; anything else that goes wrong becomes a warning (ADR 01003).\n */\nasync function loadSidecars(\n dir: string,\n trace: Trace,\n): Promise<LoadedSidecar[]> {\n let names: string[];\n try {\n names = await readdir(dir);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\" && code !== \"ENOTDIR\") {\n trace.warnings.push(\n `could not read the subagent transcript directory ${dir} ` +\n `(${code ?? \"unknown error\"}), so subagent turns are missing here`,\n );\n }\n return [];\n }\n\n const metas = new Set<string>();\n const transcripts = new Set<string>();\n for (const name of names) {\n const meta = AGENT_META_RE.exec(name);\n if (meta?.[1] !== undefined) {\n metas.add(meta[1]);\n continue;\n }\n const jsonl = AGENT_JSONL_RE.exec(name);\n if (jsonl?.[1] !== undefined) transcripts.add(jsonl[1]);\n }\n for (const orphan of [...transcripts].sort()) {\n if (!metas.has(orphan)) {\n trace.warnings.push(\n `subagent transcript agent-${orphan}.jsonl has no ` +\n `agent-${orphan}.meta.json, so it names no Agent spawn and was ` +\n `not merged`,\n );\n }\n }\n\n const loaded: LoadedSidecar[] = [];\n for (const agentId of [...metas].sort()) {\n let meta: SidecarMeta;\n try {\n const raw = await readFile(\n join(dir, `agent-${agentId}.meta.json`),\n \"utf-8\",\n );\n const parsed: unknown = JSON.parse(raw);\n // An array is `typeof \"object\"` too, and would merge with every member\n // undefined while the warning below never fired.\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(\"shape\");\n }\n meta = parsed;\n } catch {\n trace.warnings.push(\n `subagent metadata agent-${agentId}.meta.json is unreadable or not ` +\n `an object, so that branch was not merged`,\n );\n continue;\n }\n const file = join(dir, `agent-${agentId}.jsonl`);\n let sub: Trace;\n try {\n sub = parseTraceContent(await readFile(file, \"utf-8\"), file);\n } catch {\n trace.warnings.push(\n `subagent transcript agent-${agentId}.jsonl is missing or ` +\n `unreadable, so that branch was not merged`,\n );\n continue;\n }\n for (const warning of sub.warnings) {\n trace.warnings.push(`subagent ${meta.agentType ?? agentId}: ${warning}`);\n }\n loaded.push({ agentId, file, meta, sub, source: asSource(agentId, sub) });\n }\n return loaded;\n}\n\nasync function mergeSidecarBranches(\n trace: Trace,\n traceFile: string,\n): Promise<void> {\n const loaded = await loadSidecars(sidecarDirFor(traceFile), trace);\n if (loaded.length === 0) return;\n\n const base = asSource(\"\", trace);\n const sources = new Map<string, MergeSource>([[\"\", base]]);\n // Which transcript holds the `Agent` call a branch hangs off, and where in\n // that transcript. A depth-2 branch's spawn lives inside a depth-1 sidecar,\n // never in the session file, so ascending depth is what makes the join work.\n const spawnOwner = new Map<string, { sourceId: string; local: number }>();\n const registerSpawns = (source: MergeSource): void => {\n for (const spawn of source.agentSpawns) {\n if (spawn.toolUseId !== undefined) {\n spawnOwner.set(spawn.toolUseId, {\n sourceId: source.id,\n local: spawn.index,\n });\n }\n }\n };\n registerSpawns(base);\n\n // Ownership is resolved **iteratively**, not in one depth-sorted pass.\n //\n // The pass assumed `meta.spawnDepth` was always there, but `SidecarMeta`\n // documents every member as optional — and with the depths equal the order\n // fell to the agent-id tiebreak, so a depth-2 branch whose id happened to\n // sort first was visited before its parent had registered the `Agent` call\n // it hangs off, and was discarded with a warning. Renaming the same file\n // made it merge. Repeating until nothing new attaches reaches every branch\n // whose owner is reachable at all, whatever the metadata says.\n const children = new Map<string, LoadedSidecar[]>();\n const attached: Array<{ sidecar: LoadedSidecar; branchId: string }> = [];\n // Byte comparison, not `localeCompare`: sibling modules already sort this\n // way so the ubuntu and windows CI legs order reports identically.\n const pending = [...loaded].sort(\n (a, b) =>\n (a.meta.spawnDepth ?? 1) - (b.meta.spawnDepth ?? 1) ||\n (a.agentId < b.agentId ? -1 : a.agentId > b.agentId ? 1 : 0),\n );\n let progress = true;\n while (progress) {\n progress = false;\n for (let i = 0; i < pending.length; i += 1) {\n const sidecar = pending[i] as LoadedSidecar;\n const branchId = sidecar.meta.toolUseId;\n const owner = branchId === undefined ? undefined : spawnOwner.get(branchId);\n if (branchId === undefined || owner === undefined) continue;\n pending.splice(i, 1);\n i -= 1;\n progress = true;\n stampBranch(sidecar.sub, branchId);\n sources.set(sidecar.agentId, sidecar.source);\n const key = `${owner.sourceId}\\u0000${owner.local}`;\n children.set(key, [...(children.get(key) ?? []), sidecar]);\n registerSpawns(sidecar.source);\n attached.push({ sidecar, branchId });\n }\n }\n // Whatever is left names an `Agent` call no reachable transcript makes.\n for (const sidecar of pending) {\n trace.warnings.push(\n `subagent transcript agent-${sidecar.agentId}.jsonl names Agent call ` +\n `${sidecar.meta.toolUseId ?? \"(none recorded)\"}, which is not in this ` +\n `trace, so that branch was not merged`,\n );\n }\n if (attached.length === 0) return;\n\n // Depth-first assembly: a transcript's own events in order, and after each\n // one the whole subtree of any branch that event spawned.\n const slots: Array<{ sourceId: string; local: number }> = [];\n const emit = (sourceId: string): void => {\n const source = sources.get(sourceId);\n if (source === undefined) return;\n for (let local = 0; local < source.events.length; local += 1) {\n slots.push({ sourceId, local });\n for (const kid of children.get(`${sourceId}\\u0000${local}`) ?? []) {\n emit(kid.agentId);\n }\n }\n };\n emit(\"\");\n\n const remap = new Map<string, number[]>();\n slots.forEach((slot, final) => {\n const row = remap.get(slot.sourceId) ?? [];\n row[slot.local] = final;\n remap.set(slot.sourceId, row);\n });\n const finalIndex = (sourceId: string, local: number): number =>\n remap.get(sourceId)?.[local] ?? local;\n\n trace.events = slots.map((slot, final) => {\n const event = sources.get(slot.sourceId)?.events[slot.local];\n return { ...(event as TraceEvent), index: final };\n });\n\n const gather = <T extends { index: number }>(\n pick: (source: MergeSource) => T[],\n ): T[] =>\n [...sources.values()]\n .flatMap((source) =>\n pick(source).map((item) => ({\n ...item,\n index: finalIndex(source.id, item.index),\n })),\n )\n .sort((a, b) => a.index - b.index);\n\n trace.toolCalls = gather((s) => s.toolCalls);\n trace.fileAccesses = gather((s) => s.fileAccesses);\n trace.skillInvocations = gather((s) => s.skillInvocations);\n trace.agentSpawns = gather((s) => s.agentSpawns);\n\n // The roster's ordinals are positions in `trace.events`, which the splice\n // just renumbered. Then each branch's own roster contributes whatever the\n // session never saw elsewhere, anchored at the spawn (ADR 01016).\n trace.availability = remapAvailability(trace.availability, (index) =>\n finalIndex(\"\", index),\n );\n for (const { sidecar, branchId } of attached) {\n const owner = spawnOwner.get(branchId);\n foldBranchAvailability(\n trace.availability,\n sidecar.sub.availability,\n branchId,\n owner === undefined ? 0 : finalIndex(owner.sourceId, owner.local),\n );\n }\n\n const described = new Map<string, Partial<SubagentBranch>>();\n for (const { sidecar, branchId } of attached) {\n const info: Partial<SubagentBranch> = {\n agentId: sidecar.agentId,\n file: sidecar.file,\n };\n if (sidecar.meta.agentType) info.agentType = sidecar.meta.agentType;\n if (sidecar.meta.description) info.description = sidecar.meta.description;\n if (sidecar.meta.parentAgentId) {\n info.parentAgentId = sidecar.meta.parentAgentId;\n }\n if (typeof sidecar.meta.spawnDepth === \"number\") {\n info.spawnDepth = sidecar.meta.spawnDepth;\n }\n described.set(branchId, info);\n }\n trace.subagentBranches = buildBranches(trace, described);\n}\n","/**\n * Trace format sniffing. Session files and stream-json are both JSONL, but\n * session records carry camelCase `sessionId` (and `parentUuid` on message\n * records) while stream-json uses snake_case `session_id`.\n */\nimport { TracevalsError } from \"../types.js\";\nimport type { TraceFormat } from \"./types.js\";\n\nconst SUPPORTED =\n \"supported formats: Claude Code session files (~/.claude/projects/**.jsonl) and claude -p stream-json\";\n\n/** Detect the dialect from one JSONL line (typically the first parseable). */\nexport function detectFormat(line: string): TraceFormat {\n // Parsed as `unknown`, not asserted to an object: `JSON.parse(\"5\")` and\n // `JSON.parse(\"null\")` both succeed, and a cast here would make the guard\n // below look dead while leaving the bug.\n let rec: unknown;\n try {\n rec = JSON.parse(line);\n } catch {\n throw new TracevalsError(`trace is not JSONL (${SUPPORTED})`);\n }\n if (typeof rec !== \"object\" || rec === null) {\n throw new TracevalsError(`unrecognized trace format (${SUPPORTED})`);\n }\n if (\"parentUuid\" in rec || \"sessionId\" in rec) return \"claude-session\";\n if (\"session_id\" in rec) return \"claude-stream\";\n throw new TracevalsError(`unrecognized trace format (${SUPPORTED})`);\n}\n\n/**\n * Detect the dialect of a whole file's content: the first line that *identifies*\n * a format decides. Malformed lines and parseable-but-unidentifiable records\n * (e.g. a leading `{\"type\":\"summary\",…}`, which real session files carry) are\n * skipped, so a metadata record at the top never masks the format below it.\n */\nexport function detectContentFormat(content: string): TraceFormat {\n let sawParseable = false;\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let rec: unknown;\n try {\n rec = JSON.parse(trimmed);\n } catch {\n continue; // Malformed line — keep scanning.\n }\n if (typeof rec !== \"object\" || rec === null) continue;\n sawParseable = true;\n const r = rec as Record<string, unknown>;\n if (\"parentUuid\" in r || \"sessionId\" in r) return \"claude-session\";\n if (\"session_id\" in r) return \"claude-stream\";\n // Parseable but unidentifiable (summary, and other metadata records) —\n // keep scanning for a line that names the format.\n }\n throw new TracevalsError(\n sawParseable\n ? `unrecognized trace format (${SUPPORTED})`\n : `empty or unparseable trace file (${SUPPORTED})`,\n );\n}\n","/**\n * Render a trace into judge-readable text. Session files can be tens of MB,\n * so every block is capped and the whole digest is bounded by a head/tail\n * window — the opening (instructions, intent) and the ending (outcome) matter\n * most for adherence judging.\n *\n * Given an eval plan, only the turns that plan's artifact was governing are\n * rendered (ADR 01015). That is both the correct evidence to judge against and\n * a large cut in tokens: a skill's window is usually a fraction of a session.\n *\n * This is also the only place trace content is turned into text bound for a\n * third-party API, so it is where redaction happens (ADR 01020). Every block is\n * scrubbed *before* it is clipped, so truncation can never bisect a secret and\n * leave a usable prefix behind.\n */\nimport type { Trace, TraceEvent } from \"../trace/types.js\";\nimport type { EvalPlan } from \"../core/plan.js\";\nimport { windowFor, type TraceWindow } from \"../graders/util.js\";\nimport { makeRedactor } from \"./redact.js\";\n\nexport interface RenderOptions {\n /** Per-block character cap (messages, tool inputs). */\n maxBlockChars?: number;\n /** Whole-digest character cap; overflow keeps head and tail. */\n maxTotalChars?: number;\n /**\n * Extra redaction patterns, applied on top of the built-in shapes rather\n * than instead of them. Sources are compiled with the `g` flag.\n */\n redact?: string[];\n /**\n * A window cut elsewhere, such as the turn a Stop judges (proposal 0079).\n * It takes the place of the plan's window when both are given.\n */\n window?: TraceWindow;\n /**\n * Called when `maxTotalChars` cut the digest: the header, the timeline, or\n * both. The cut is already visible as a marker in the text; this lets a\n * caller say so in a warning as well.\n */\n onTruncated?: () => void;\n}\n\nconst DEFAULTS: Required<Omit<RenderOptions, \"window\" | \"onTruncated\">> = {\n maxBlockChars: 2_000,\n maxTotalChars: 150_000,\n redact: [],\n};\n\n/**\n * The smallest timeline the head/tail window will ever leave.\n *\n * The cap used to be skipped outright when the header grew past it — the guard\n * was `budget > 0`, so a non-positive budget *disabled* truncation and shipped\n * the entire unclipped transcript to a third-party provider, precisely when the\n * user had asked for the tightest cap. A floor keeps truncation running; the\n * header is bounded separately so the whole digest still honours the cap.\n */\nconst MIN_TIMELINE_CHARS = 200;\n\nconst HEADER_TRUNCATED = \"\\n[... header truncated ...]\";\nconst TIMELINE_SHELL = \"\\n\\n## Timeline\\n\";\n\nexport function renderTrace(\n trace: Trace,\n options: RenderOptions = {},\n plan?: EvalPlan,\n): string {\n const { maxBlockChars, maxTotalChars, redact } = { ...DEFAULTS, ...options };\n const scrub = makeRedactor(redact);\n // Redact, then truncate. The other order would let a cap land mid-secret and\n // ship the surviving prefix.\n const clip = (text: string, max: number): string => {\n const safe = scrub(text);\n if (safe.length <= max) return safe;\n return `${safe.slice(0, max)} [... truncated ${safe.length - max} chars ...]`;\n };\n const window =\n options.window ?? (plan === undefined ? undefined : windowFor(trace, plan));\n // Project rules govern the whole session, so their digest is the session's —\n // byte-identical to an unscoped render, and cached as such.\n const scoped =\n window !== undefined && window.scope !== \"session\" ? window : undefined;\n const events: TraceEvent[] = scoped?.events ?? trace.events;\n\n // Scrubbed too: `cwd` and a branch name are author-supplied strings, and the\n // header is as much a thing that leaves the machine as the timeline is.\n const fullHeader = scrub(\n [\n \"# Session\",\n `source: ${trace.source}`,\n trace.model ? `model: ${trace.model}` : undefined,\n `cwd: ${trace.cwd}`,\n trace.gitBranch ? `branch: ${trace.gitBranch}` : undefined,\n scoped\n ? `scope: ${scoped.label} — ${events.length} of ${trace.events.length} session events`\n : undefined,\n // Everything below describes what the judge can actually see. On a\n // scoped render the timeline is the window, so a session-wide count here\n // reads as evidence that the rest was truncated away — the judge would\n // discount a digest that is complete for what it was asked about. The\n // session totals stay, in parentheses, because \"3 of 87\" is context the\n // window count alone does not carry.\n scoped\n ? `turns: ${scoped.turnCount} (of ${trace.turnCount} in the session)`\n : `turns: ${trace.turnCount}`,\n ((): string => {\n const used = (scoped ?? trace).skillInvocations.map((s) => s.name);\n return used.length > 0\n ? `skills used: ${used.join(\", \")}`\n : \"skills used: none\";\n })(),\n ((): string | undefined => {\n // Spawns and branches inside the window only: an agent the parent\n // session started after this skill handed over is not this artifact's\n // to answer for.\n const inWindow = new Set(events.map((e) => e.index));\n const spawns = trace.agentSpawns.filter(\n (a) => !scoped || inWindow.has(a.index),\n );\n return spawns.length > 0\n ? `agents spawned: ${spawns.map((a) => a.subagentType).join(\", \")}`\n : undefined;\n })(),\n ((): string | undefined => {\n const inWindow = new Set(events.map((e) => e.index));\n const branches = trace.subagentBranches.filter(\n (b) => !scoped || inWindow.has(b.spawnIndex),\n );\n return branches.length > 0\n ? `subagent transcripts: ${branches\n .map((b) => `${b.agentType} (depth ${b.spawnDepth})`)\n .join(\", \")}`\n : undefined;\n })(),\n ]\n .filter((line): line is string => line !== undefined)\n .join(\"\\n\"),\n );\n\n // The header lists every skill name, agent type and branch, so on a busy\n // session it can outgrow a tight cap on its own. Bound it first, leaving the\n // timeline its floor, so `maxTotalChars` stays a cap on the whole digest\n // rather than on one half of it.\n const headerRoom = Math.max(\n maxTotalChars - TIMELINE_SHELL.length - MIN_TIMELINE_CHARS,\n 0,\n );\n if (fullHeader.length > headerRoom) options.onTruncated?.();\n const header =\n fullHeader.length <= headerRoom\n ? fullHeader\n : fullHeader.slice(\n 0,\n Math.max(headerRoom - HEADER_TRUNCATED.length, 0),\n ) + HEADER_TRUNCATED;\n\n // Two concurrent subagents are indistinguishable under a flat `:sidechain`\n // tag, so each branch becomes a labelled block named for the subagent that\n // ran it. The header can fall outside the head/tail window below, so every\n // line keeps a short tag of its own as well. Inline and sidecar branches\n // render through this one path; a sidecar branch is named by its meta file's\n // `agentType`, which is the recorder's own statement of what ran.\n const branchTypes = new Map<string, string>();\n for (const spawn of trace.agentSpawns) {\n if (spawn.toolUseId) branchTypes.set(spawn.toolUseId, spawn.subagentType);\n }\n for (const branch of trace.subagentBranches) {\n branchTypes.set(branch.branchId, branch.agentType);\n }\n const label = (branchId: string): string =>\n branchTypes.get(branchId) ?? branchId;\n const callAt = new Map(trace.toolCalls.map((call) => [call.index, call]));\n\n if (scoped?.empty === true) {\n return `${header}${TIMELINE_SHELL}[no turns: ${scrub(scoped.reason ?? \"\")}]`;\n }\n\n const lines: string[] = [];\n let branch: string | undefined;\n for (const event of events) {\n const tag = event.branchId\n ? `:${label(event.branchId)}`\n : event.sidechain\n ? \":sidechain\"\n : \"\";\n let line: string | undefined;\n switch (event.kind) {\n case \"user\":\n if (event.text) line = `[user${tag}] ${clip(event.text, maxBlockChars)}`;\n break;\n case \"assistant\":\n if (event.text) {\n line = `[assistant${tag}] ${clip(event.text, maxBlockChars)}`;\n }\n break;\n case \"tool_call\": {\n const call = callAt.get(event.index);\n const input = call ? JSON.stringify(call.input) : \"\";\n line = `[tool${tag}] ${event.toolName ?? call?.name ?? \"?\"} ${clip(input, Math.min(maxBlockChars, 500))}`;\n break;\n }\n default:\n break;\n }\n if (line === undefined) continue;\n if (event.branchId !== branch) {\n if (branch !== undefined) lines.push(`[/subagent ${label(branch)}]`);\n branch = event.branchId;\n if (branch !== undefined) {\n lines.push(`[subagent ${label(branch)} (${branch})]`);\n }\n }\n lines.push(line);\n }\n if (branch !== undefined) lines.push(`[/subagent ${label(branch)}]`);\n\n // One more pass over the assembled timeline. Every message and tool input\n // already went through `clip`, so this pass is the belt to that pair of\n // braces: it covers what is assembled here rather than clipped — tool names,\n // branch labels — and anything a later change adds to this loop without\n // remembering to scrub it. Redaction is idempotent, so it costs nothing.\n let timeline = scrub(lines.join(\"\\n\"));\n // A floor, never a switch: `budget > 0` used to turn truncation *off* for a\n // non-positive budget, which is the one case where it matters most.\n const budget = Math.max(\n maxTotalChars - header.length - TIMELINE_SHELL.length,\n MIN_TIMELINE_CHARS,\n );\n if (timeline.length > budget) {\n options.onTruncated?.();\n // The marker counts against the budget, so the digest never exceeds what\n // the caller asked for. `omitted` is at most `timeline.length`, so the\n // width reserved for it is always enough.\n const marker = (omitted: number): string =>\n `\\n[... truncated ${omitted} chars of transcript ...]\\n`;\n const room = Math.max(budget - marker(timeline.length).length, 0);\n const headLen = Math.floor(room * 0.6);\n const tailLen = room - headLen;\n const omitted = timeline.length - headLen - tailLen;\n timeline = `${timeline.slice(0, headLen)}${marker(omitted)}${\n tailLen > 0 ? timeline.slice(-tailLen) : \"\"\n }`;\n }\n\n return `${header}${TIMELINE_SHELL}${timeline}`;\n}\n"],"mappings":"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","names":["branch","omitted"]}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
errorMessage
|
|
4
|
+
} from "./chunk-G3T47CFV.js";
|
|
5
|
+
|
|
6
|
+
// src/shared/duration.ts
|
|
7
|
+
var UNITS = {
|
|
8
|
+
m: 6e4,
|
|
9
|
+
h: 60 * 6e4,
|
|
10
|
+
d: 24 * 60 * 6e4,
|
|
11
|
+
w: 7 * 24 * 60 * 6e4
|
|
12
|
+
};
|
|
13
|
+
function durationMessage(value, label = "--newer-than") {
|
|
14
|
+
return `${label} must be a duration such as 30m, 24h, 7d or 2w, got "${value}"`;
|
|
15
|
+
}
|
|
16
|
+
function parseDuration(text, makeError, label) {
|
|
17
|
+
const match = /^(\d+(?:\.\d+)?)([mhdw])$/.exec(text.trim());
|
|
18
|
+
const count = match?.[1];
|
|
19
|
+
const unit = match?.[2];
|
|
20
|
+
const ms = unit === void 0 ? void 0 : UNITS[unit];
|
|
21
|
+
if (count === void 0 || ms === void 0) {
|
|
22
|
+
throw makeError(durationMessage(text, label));
|
|
23
|
+
}
|
|
24
|
+
return Number(count) * ms;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/shared/providers.ts
|
|
28
|
+
import { resolve } from "node:path";
|
|
29
|
+
import {
|
|
30
|
+
DEFAULT_JEV_BASE_URL,
|
|
31
|
+
DEFAULT_MODELS,
|
|
32
|
+
DEFAULT_OPENAI_BASE_URL,
|
|
33
|
+
InferenceError,
|
|
34
|
+
resolveProviderIdentityAsync
|
|
35
|
+
} from "@hawkeyexl/inference";
|
|
36
|
+
var DEFAULT_PROVIDER = "auto";
|
|
37
|
+
var DECISION_ONLY_PROVIDERS = /* @__PURE__ */ new Set(["jev"]);
|
|
38
|
+
var PROVIDERS = /* @__PURE__ */ new Set([
|
|
39
|
+
...Object.keys(DEFAULT_MODELS).filter((name) => !DECISION_ONLY_PROVIDERS.has(name)),
|
|
40
|
+
DEFAULT_PROVIDER
|
|
41
|
+
]);
|
|
42
|
+
var NAMEABLE_PROVIDERS = Object.keys(DEFAULT_MODELS).filter(
|
|
43
|
+
(name) => name !== "mock" && !DECISION_ONLY_PROVIDERS.has(name)
|
|
44
|
+
);
|
|
45
|
+
function assertKnownProvider(name, toError, options = {}) {
|
|
46
|
+
if (DECISION_ONLY_PROVIDERS.has(name)) {
|
|
47
|
+
if (options.decisions === true) return;
|
|
48
|
+
throw toError(
|
|
49
|
+
`Provider "${name}" answers decisions only, so it cannot generate. Available: ${[...NAMEABLE_PROVIDERS, DEFAULT_PROVIDER].join(", ")}.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (PROVIDERS.has(name)) return;
|
|
53
|
+
throw toError(
|
|
54
|
+
`Unknown provider "${name}". Available: ${[...NAMEABLE_PROVIDERS, DEFAULT_PROVIDER].join(", ")}.`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
function assertModelHasProvider(name, model, configKey, toError) {
|
|
58
|
+
if (name !== DEFAULT_PROVIDER || model == null) return;
|
|
59
|
+
throw toError(
|
|
60
|
+
`Model "${model}" was given without a provider: a model name does not say which provider owns it. Set --provider or ${configKey} to one of ${NAMEABLE_PROVIDERS.join(", ")}, or drop the model to take the detected provider's default.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
var PROVIDERS_KEY = "providers";
|
|
64
|
+
var CONNECTION_KEYS = {
|
|
65
|
+
anthropic: ["apiKeyEnv"],
|
|
66
|
+
openai: ["baseUrl", "apiKeyEnv"],
|
|
67
|
+
"claude-cli": ["command"],
|
|
68
|
+
jev: ["apiKeyEnv", "baseUrl"],
|
|
69
|
+
"llama-cpp": ["modelsDir", "thoughtTokens", "keepAlive"]
|
|
70
|
+
};
|
|
71
|
+
var CONNECTION_NAMES = Object.keys(CONNECTION_KEYS);
|
|
72
|
+
var TOP_LEVEL_KEYS = ["provider", "model", ...CONNECTION_NAMES];
|
|
73
|
+
function isMapping(value) {
|
|
74
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
75
|
+
}
|
|
76
|
+
function rejectUnknown(raw, allowed, label, source, toError) {
|
|
77
|
+
for (const key of Object.keys(raw)) {
|
|
78
|
+
if (!allowed.includes(key)) {
|
|
79
|
+
throw toError(
|
|
80
|
+
`${source}: "${label}" has unknown key "${key}". Supported keys: ${allowed.join(", ")}.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function parseProviders(value, source, dir, toError) {
|
|
86
|
+
if (value == null) return {};
|
|
87
|
+
if (!isMapping(value)) {
|
|
88
|
+
throw toError(`${source}: "${PROVIDERS_KEY}" must be a mapping.`);
|
|
89
|
+
}
|
|
90
|
+
rejectUnknown(value, TOP_LEVEL_KEYS, PROVIDERS_KEY, source, toError);
|
|
91
|
+
const string = (raw, key, label) => {
|
|
92
|
+
const v = raw[key];
|
|
93
|
+
if (v === void 0) return void 0;
|
|
94
|
+
if (typeof v !== "string") {
|
|
95
|
+
throw toError(`${source}: "${label}" must be a string.`);
|
|
96
|
+
}
|
|
97
|
+
return v;
|
|
98
|
+
};
|
|
99
|
+
const parsed = {};
|
|
100
|
+
const provider = string(value, "provider", `${PROVIDERS_KEY}.provider`);
|
|
101
|
+
if (provider !== void 0) {
|
|
102
|
+
assertKnownProvider(provider, (message) => toError(`${source}: ${message}`));
|
|
103
|
+
parsed.provider = provider;
|
|
104
|
+
}
|
|
105
|
+
const model = string(value, "model", `${PROVIDERS_KEY}.model`);
|
|
106
|
+
if (model !== void 0) {
|
|
107
|
+
if (provider === void 0 || provider === DEFAULT_PROVIDER) {
|
|
108
|
+
throw toError(
|
|
109
|
+
`${source}: "${PROVIDERS_KEY}.model" was given without a provider: a model name does not say which provider owns it. Set ${PROVIDERS_KEY}.provider to one of ${NAMEABLE_PROVIDERS.join(", ")}, or drop the model to take the detected provider's default.`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
parsed.model = model;
|
|
113
|
+
}
|
|
114
|
+
for (const name of CONNECTION_NAMES) {
|
|
115
|
+
const section = value[name];
|
|
116
|
+
if (section == null) continue;
|
|
117
|
+
const label = `${PROVIDERS_KEY}.${name}`;
|
|
118
|
+
if (!isMapping(section)) {
|
|
119
|
+
throw toError(`${source}: "${label}" must be a mapping.`);
|
|
120
|
+
}
|
|
121
|
+
rejectUnknown(section, CONNECTION_KEYS[name], label, source, toError);
|
|
122
|
+
const field = (key) => string(section, key, `${label}.${key}`);
|
|
123
|
+
switch (name) {
|
|
124
|
+
case "anthropic": {
|
|
125
|
+
const apiKeyEnv = field("apiKeyEnv");
|
|
126
|
+
parsed.anthropic = apiKeyEnv === void 0 ? {} : { apiKeyEnv };
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case "openai": {
|
|
130
|
+
const baseUrl = field("baseUrl");
|
|
131
|
+
const apiKeyEnv = field("apiKeyEnv");
|
|
132
|
+
parsed.openai = {
|
|
133
|
+
...baseUrl !== void 0 ? { baseUrl } : {},
|
|
134
|
+
...apiKeyEnv !== void 0 ? { apiKeyEnv } : {}
|
|
135
|
+
};
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
case "claude-cli": {
|
|
139
|
+
const command = field("command");
|
|
140
|
+
parsed["claude-cli"] = command === void 0 ? {} : { command };
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case "jev": {
|
|
144
|
+
const apiKeyEnv = field("apiKeyEnv");
|
|
145
|
+
const baseUrl = field("baseUrl");
|
|
146
|
+
parsed.jev = {
|
|
147
|
+
...apiKeyEnv !== void 0 ? { apiKeyEnv } : {},
|
|
148
|
+
...baseUrl !== void 0 ? { baseUrl } : {}
|
|
149
|
+
};
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "llama-cpp": {
|
|
153
|
+
const modelsDir = field("modelsDir");
|
|
154
|
+
const thoughtTokens = section["thoughtTokens"];
|
|
155
|
+
if (thoughtTokens !== void 0 && (typeof thoughtTokens !== "number" || !Number.isInteger(thoughtTokens) || thoughtTokens < 0)) {
|
|
156
|
+
throw toError(
|
|
157
|
+
`${source}: "${label}.thoughtTokens" must be a whole number of 0 or more, got ${JSON.stringify(thoughtTokens)}.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
const keepAlive = keepAliveOf(section["keepAlive"], `${label}.keepAlive`, source, toError);
|
|
161
|
+
parsed["llama-cpp"] = {
|
|
162
|
+
...modelsDir !== void 0 ? { modelsDir: resolve(dir, modelsDir) } : {},
|
|
163
|
+
...thoughtTokens !== void 0 ? { thoughtTokens } : {},
|
|
164
|
+
...keepAlive !== void 0 ? { keepAlive } : {}
|
|
165
|
+
};
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return parsed;
|
|
171
|
+
}
|
|
172
|
+
var DEFAULT_KEEP_ALIVE_MS = 10 * 6e4;
|
|
173
|
+
function keepAliveOf(value, label, source, toError) {
|
|
174
|
+
if (value === void 0) return void 0;
|
|
175
|
+
if (value === 0 || value === "0") return 0;
|
|
176
|
+
const refuse = () => toError(
|
|
177
|
+
`${source}: "${label}" must be 0 or a duration such as 30m, 24h, 7d or 2w, got "${typeof value === "string" ? value : JSON.stringify(value)}"`
|
|
178
|
+
);
|
|
179
|
+
if (typeof value !== "string") throw refuse();
|
|
180
|
+
return parseDuration(value, refuse);
|
|
181
|
+
}
|
|
182
|
+
var LOCAL_PROVIDER = "llama-cpp";
|
|
183
|
+
var LOCAL_FLAG_HELP = "run inference on this machine (llama-cpp); overrides any configured or eval-level provider";
|
|
184
|
+
var LOCAL_COMPATIBLE = /* @__PURE__ */ new Set([LOCAL_PROVIDER, DEFAULT_PROVIDER, "mock"]);
|
|
185
|
+
function assertLocalFlag(flag, toError) {
|
|
186
|
+
if (flag.local !== true || flag.provider === void 0) return;
|
|
187
|
+
assertKnownProvider(flag.provider, toError);
|
|
188
|
+
if (LOCAL_COMPATIBLE.has(flag.provider)) return;
|
|
189
|
+
throw toError(
|
|
190
|
+
`--local and --provider ${flag.provider} contradict each other: --local runs inference on this machine with ${LOCAL_PROVIDER}. Drop one of them.`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
function selectProvider(flag, levels) {
|
|
194
|
+
if (flag.local === true) return selectLocal(flag, levels);
|
|
195
|
+
const provider = flag.provider ?? levels.find((level) => level.provider !== void 0)?.provider ?? DEFAULT_PROVIDER;
|
|
196
|
+
const model = flag.model ?? levels.find(
|
|
197
|
+
(level) => level.model !== void 0 && (level.provider === void 0 || level.provider === provider)
|
|
198
|
+
)?.model;
|
|
199
|
+
return { provider, model };
|
|
200
|
+
}
|
|
201
|
+
function selectLocal(flag, levels) {
|
|
202
|
+
const provider = flag.provider === "mock" ? "mock" : LOCAL_PROVIDER;
|
|
203
|
+
const model = flag.model ?? levels.find((level) => level.model !== void 0 && level.provider === provider)?.model;
|
|
204
|
+
const chosen = flag.provider === void 0 ? levels.find((level) => level.provider !== void 0) : void 0;
|
|
205
|
+
const replaced = chosen?.provider !== void 0 && chosen.origin !== void 0 && chosen.provider !== provider && chosen.provider !== DEFAULT_PROVIDER ? { provider: chosen.provider, source: chosen.origin } : void 0;
|
|
206
|
+
return replaced === void 0 ? { provider, model } : { provider, model, replaced };
|
|
207
|
+
}
|
|
208
|
+
function localNotice(selection) {
|
|
209
|
+
const { replaced } = selection;
|
|
210
|
+
if (replaced === void 0) return void 0;
|
|
211
|
+
return `--local: using ${LOCAL_PROVIDER} instead of "${replaced.provider}" from ${replaced.source}.`;
|
|
212
|
+
}
|
|
213
|
+
function providerSpecFor(connections, selection) {
|
|
214
|
+
const { provider, model } = selection;
|
|
215
|
+
const local = connections["llama-cpp"] ?? {};
|
|
216
|
+
const llamaCpp = {
|
|
217
|
+
thoughtTokens: local.thoughtTokens ?? 0,
|
|
218
|
+
...local.modelsDir !== void 0 ? { modelsDirectory: local.modelsDir } : {}
|
|
219
|
+
};
|
|
220
|
+
switch (provider) {
|
|
221
|
+
case "anthropic":
|
|
222
|
+
return {
|
|
223
|
+
provider,
|
|
224
|
+
model,
|
|
225
|
+
apiKeyEnv: connections.anthropic?.apiKeyEnv ?? "ANTHROPIC_API_KEY"
|
|
226
|
+
};
|
|
227
|
+
case "openai":
|
|
228
|
+
return {
|
|
229
|
+
provider,
|
|
230
|
+
model,
|
|
231
|
+
apiKeyEnv: connections.openai?.apiKeyEnv ?? "OPENAI_API_KEY",
|
|
232
|
+
baseUrl: connections.openai?.baseUrl ?? DEFAULT_OPENAI_BASE_URL
|
|
233
|
+
};
|
|
234
|
+
case "claude-cli":
|
|
235
|
+
return { provider, model, command: connections["claude-cli"]?.command ?? "claude" };
|
|
236
|
+
case "jev":
|
|
237
|
+
return {
|
|
238
|
+
provider,
|
|
239
|
+
model,
|
|
240
|
+
apiKeyEnv: connections.jev?.apiKeyEnv ?? "TYPESAFE_API_KEY",
|
|
241
|
+
baseUrl: connections.jev?.baseUrl ?? DEFAULT_JEV_BASE_URL
|
|
242
|
+
};
|
|
243
|
+
case "llama-cpp":
|
|
244
|
+
return { provider, model, llamaCpp };
|
|
245
|
+
case "mock":
|
|
246
|
+
return { provider, model };
|
|
247
|
+
case "auto": {
|
|
248
|
+
const baseUrl = connections.openai?.baseUrl;
|
|
249
|
+
const command = connections["claude-cli"]?.command;
|
|
250
|
+
const configuredLocal = local.thoughtTokens !== void 0 || local.modelsDir !== void 0;
|
|
251
|
+
return {
|
|
252
|
+
provider,
|
|
253
|
+
model,
|
|
254
|
+
...baseUrl !== void 0 ? { baseUrl } : {},
|
|
255
|
+
...command !== void 0 ? { command } : {},
|
|
256
|
+
...configuredLocal ? { llamaCpp } : {}
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async function resolveIdentity(spec, toError) {
|
|
262
|
+
try {
|
|
263
|
+
return await resolveProviderIdentityAsync(spec);
|
|
264
|
+
} catch (err) {
|
|
265
|
+
throw toError(
|
|
266
|
+
err instanceof InferenceError ? err.message : `Could not resolve provider "${String(spec.provider)}": ${errorMessage(err)}`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export {
|
|
272
|
+
parseDuration,
|
|
273
|
+
DECISION_ONLY_PROVIDERS,
|
|
274
|
+
assertKnownProvider,
|
|
275
|
+
assertModelHasProvider,
|
|
276
|
+
PROVIDERS_KEY,
|
|
277
|
+
parseProviders,
|
|
278
|
+
DEFAULT_KEEP_ALIVE_MS,
|
|
279
|
+
LOCAL_FLAG_HELP,
|
|
280
|
+
assertLocalFlag,
|
|
281
|
+
selectProvider,
|
|
282
|
+
localNotice,
|
|
283
|
+
providerSpecFor,
|
|
284
|
+
resolveIdentity
|
|
285
|
+
};
|
|
286
|
+
//# sourceMappingURL=chunk-QCHVR4ZM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/duration.ts","../src/shared/providers.ts"],"sourcesContent":["/**\n * `--newer-than <duration>`: a window of time back from now, shared by every\n * domain that selects its inputs by age.\n *\n * Deliberately strict. A duration this refuses is a usage error, because the\n * alternative (reading `7y` as zero, or as \"everything\") silently changes what\n * a gate looked at.\n */\n\nconst UNITS: Readonly<Record<string, number>> = {\n m: 60_000,\n h: 60 * 60_000,\n d: 24 * 60 * 60_000,\n w: 7 * 24 * 60 * 60_000,\n};\n\n/**\n * The usage error for a value that is not a duration. `label` is what the\n * user wrote it under, a flag or a config key.\n */\nexport function durationMessage(value: string, label = \"--newer-than\"): string {\n return `${label} must be a duration such as 30m, 24h, 7d or 2w, got \"${value}\"`;\n}\n\n/**\n * `7d` to milliseconds. A count, which may carry a fraction, then one unit:\n * `m` minutes, `h` hours, `d` days or `w` weeks. `makeError` builds the\n * domain's own `ToolError` subclass, so the refusal exits 2 under its name.\n */\nexport function parseDuration(\n text: string,\n makeError: (message: string) => Error,\n label?: string,\n): number {\n const match = /^(\\d+(?:\\.\\d+)?)([mhdw])$/.exec(text.trim());\n const count = match?.[1];\n const unit = match?.[2];\n const ms = unit === undefined ? undefined : UNITS[unit];\n if (count === undefined || ms === undefined) {\n throw makeError(durationMessage(text, label));\n }\n return Number(count) * ms;\n}\n","/**\n * Choosing an inference provider and model, for every tool that sends content\n * to one: `manni meta fill` and `manni docevals`.\n *\n * The names a tool accepts, the refusals, what `--local` overrides and the\n * detection call are one implementation, so a provider added upstream reaches both tools on the same\n * day and a message reads the same in both. What differs is only what the\n * caller passes in: the config key its user writes, and its own error class,\n * which is what maps the refusal to exit 2.\n */\nimport { resolve } from \"node:path\";\nimport {\n DEFAULT_JEV_BASE_URL,\n DEFAULT_MODELS,\n DEFAULT_OPENAI_BASE_URL,\n InferenceError,\n resolveProviderIdentityAsync,\n type ProviderName,\n type ProviderSelector,\n type ProviderSpec,\n} from \"@hawkeyexl/inference\";\nimport { parseDuration } from \"./duration.js\";\nimport { errorMessage } from \"./errors.js\";\n\n/** Builds the caller's own error from a message. */\nexport type ToErrorFn = (message: string) => Error;\n\n/**\n * `auto` detects the highest-priority provider this machine can actually use —\n * an Anthropic key, then an OpenAI key, then the Claude CLI, then a local model\n * that needs no credentials at all. Defaulting to a named provider instead meant\n * a tool failed outright for anyone who did not happen to hold that vendor's\n * key.\n */\nexport const DEFAULT_PROVIDER = \"auto\";\n\n/**\n * Providers that answer decisions and never generate text. Every family tool\n * but one generates, so these are refused unless the caller asks for decisions,\n * as tracevals' in-loop judge does (proposal 0079).\n */\nexport const DECISION_ONLY_PROVIDERS: ReadonlySet<string> = new Set([\"jev\"]);\n\n/**\n * Provider names the inference layer accepts for generation, taken from the\n * library rather than copied. A hardcoded list silently went stale when `llama-cpp` was added\n * upstream; deriving it means a new provider works the day it ships.\n */\nexport const PROVIDERS: ReadonlySet<string> = new Set<string>([\n ...Object.keys(DEFAULT_MODELS).filter((name) => !DECISION_ONLY_PROVIDERS.has(name)),\n DEFAULT_PROVIDER,\n]);\n\n/**\n * The providers a user can name for a model, which is what every message lists.\n * `mock` is the library's test double: accepted when asked for by name, so the\n * suite and the docs' own tests can run without a provider, but never offered.\n */\nconst NAMEABLE_PROVIDERS: readonly string[] = Object.keys(DEFAULT_MODELS).filter(\n (name) => name !== \"mock\" && !DECISION_ONLY_PROVIDERS.has(name),\n);\n\n/**\n * Refuse a name the library does not offer, or a decision-only provider where\n * the caller generates.\n */\nexport function assertKnownProvider(\n name: string,\n toError: ToErrorFn,\n options: { decisions?: boolean } = {},\n): asserts name is ProviderSelector {\n if (DECISION_ONLY_PROVIDERS.has(name)) {\n if (options.decisions === true) return;\n throw toError(\n `Provider \"${name}\" answers decisions only, so it cannot generate. Available: ${[...NAMEABLE_PROVIDERS, DEFAULT_PROVIDER].join(\", \")}.`,\n );\n }\n if (PROVIDERS.has(name)) return;\n throw toError(\n `Unknown provider \"${name}\". Available: ${[...NAMEABLE_PROVIDERS, DEFAULT_PROVIDER].join(\", \")}.`,\n );\n}\n\n/**\n * A model name belongs to exactly one provider, so it cannot be handed to\n * whichever provider detection picks: `--model gpt-4o-mini` on a machine with an\n * Anthropic key selected anthropic and then 404'd mid-run, after file discovery\n * had already been paid for.\n *\n * The library enforces this too. It is repeated here to name the flag and the\n * config key rather than the API fields, since that is what the user typed.\n *\n * `name` is the EFFECTIVE provider, so a provider in config satisfies this just\n * as `--provider` does; only an unresolved `auto` is ambiguous. `configKey` is\n * the key as the user writes it (`fill.provider`, `docevals.provider`).\n */\nexport function assertModelHasProvider(\n name: ProviderSelector,\n model: string | undefined,\n configKey: string,\n toError: ToErrorFn,\n): void {\n if (name !== DEFAULT_PROVIDER || model == null) return;\n throw toError(\n `Model \"${model}\" was given without a provider: a model name does not say ` +\n `which provider owns it. Set --provider or ${configKey} to one of ` +\n `${NAMEABLE_PROVIDERS.join(\", \")}, or drop the model to take the ` +\n `detected provider's default.`,\n );\n}\n\n/**\n * Connection settings, per provider, as the family's top-level `providers:`\n * map states them. Only what the user wrote: `providerSpecFor` supplies the\n * defaults, so detection can tell a configured value from a default one.\n */\nexport interface ProviderConnections {\n anthropic?: { apiKeyEnv?: string };\n openai?: { baseUrl?: string; apiKeyEnv?: string };\n \"claude-cli\"?: { command?: string };\n /** A decide-only provider: it judges, and never generates. */\n jev?: { apiKeyEnv?: string; baseUrl?: string };\n /**\n * `modelsDir` is absolute: resolved against the config file's directory.\n * `keepAlive` is milliseconds, parsed from a duration; `0` unloads a model\n * as soon as no session holds it. It belongs to the model host, so it\n * never reaches a provider spec.\n */\n \"llama-cpp\"?: { modelsDir?: string; thoughtTokens?: number; keepAlive?: number };\n}\n\n/** The family's top-level `providers:` map, parsed. */\nexport interface ProvidersConfig extends ProviderConnections {\n /** Absent when not written. */\n provider?: ProviderSelector;\n /** Absent when not written. Never present without a named `provider`. */\n model?: string;\n}\n\n/** The family's top-level key for provider settings. */\nexport const PROVIDERS_KEY = \"providers\";\n\n/** What each provider's section may carry, in the order messages list it. */\nconst CONNECTION_KEYS = {\n anthropic: [\"apiKeyEnv\"],\n openai: [\"baseUrl\", \"apiKeyEnv\"],\n \"claude-cli\": [\"command\"],\n jev: [\"apiKeyEnv\", \"baseUrl\"],\n \"llama-cpp\": [\"modelsDir\", \"thoughtTokens\", \"keepAlive\"],\n} as const;\n\ntype ConnectionName = keyof typeof CONNECTION_KEYS;\n\nconst CONNECTION_NAMES = Object.keys(CONNECTION_KEYS) as ConnectionName[];\n\nconst TOP_LEVEL_KEYS: readonly string[] = [\"provider\", \"model\", ...CONNECTION_NAMES];\n\nfunction isMapping(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction rejectUnknown(\n raw: Record<string, unknown>,\n allowed: readonly string[],\n label: string,\n source: string,\n toError: ToErrorFn,\n): void {\n for (const key of Object.keys(raw)) {\n if (!allowed.includes(key)) {\n throw toError(\n `${source}: \"${label}\" has unknown key \"${key}\". Supported keys: ${allowed.join(\", \")}.`,\n );\n }\n }\n}\n\n/**\n * Parse the family's `providers:` map. Every message names `source`, and a\n * relative `llama-cpp.modelsDir` resolves from `dir`, the directory holding\n * the file, as every other path written in the config does.\n */\nexport function parseProviders(\n value: unknown,\n source: string,\n dir: string,\n toError: ToErrorFn,\n): ProvidersConfig {\n if (value == null) return {};\n if (!isMapping(value)) {\n throw toError(`${source}: \"${PROVIDERS_KEY}\" must be a mapping.`);\n }\n rejectUnknown(value, TOP_LEVEL_KEYS, PROVIDERS_KEY, source, toError);\n\n const string = (raw: Record<string, unknown>, key: string, label: string): string | undefined => {\n const v = raw[key];\n if (v === undefined) return undefined;\n if (typeof v !== \"string\") {\n throw toError(`${source}: \"${label}\" must be a string.`);\n }\n return v;\n };\n\n const parsed: ProvidersConfig = {};\n const provider = string(value, \"provider\", `${PROVIDERS_KEY}.provider`);\n if (provider !== undefined) {\n assertKnownProvider(provider, (message) => toError(`${source}: ${message}`));\n parsed.provider = provider;\n }\n const model = string(value, \"model\", `${PROVIDERS_KEY}.model`);\n if (model !== undefined) {\n if (provider === undefined || provider === DEFAULT_PROVIDER) {\n throw toError(\n `${source}: \"${PROVIDERS_KEY}.model\" was given without a provider: a model name does not ` +\n `say which provider owns it. Set ${PROVIDERS_KEY}.provider to one of ` +\n `${NAMEABLE_PROVIDERS.join(\", \")}, or drop the model to take the detected provider's default.`,\n );\n }\n parsed.model = model;\n }\n\n for (const name of CONNECTION_NAMES) {\n const section = value[name];\n if (section == null) continue;\n const label = `${PROVIDERS_KEY}.${name}`;\n if (!isMapping(section)) {\n throw toError(`${source}: \"${label}\" must be a mapping.`);\n }\n rejectUnknown(section, CONNECTION_KEYS[name], label, source, toError);\n const field = (key: string): string | undefined => string(section, key, `${label}.${key}`);\n switch (name) {\n case \"anthropic\": {\n const apiKeyEnv = field(\"apiKeyEnv\");\n parsed.anthropic = apiKeyEnv === undefined ? {} : { apiKeyEnv };\n break;\n }\n case \"openai\": {\n const baseUrl = field(\"baseUrl\");\n const apiKeyEnv = field(\"apiKeyEnv\");\n parsed.openai = {\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n ...(apiKeyEnv !== undefined ? { apiKeyEnv } : {}),\n };\n break;\n }\n case \"claude-cli\": {\n const command = field(\"command\");\n parsed[\"claude-cli\"] = command === undefined ? {} : { command };\n break;\n }\n case \"jev\": {\n const apiKeyEnv = field(\"apiKeyEnv\");\n const baseUrl = field(\"baseUrl\");\n parsed.jev = {\n ...(apiKeyEnv !== undefined ? { apiKeyEnv } : {}),\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n };\n break;\n }\n case \"llama-cpp\": {\n const modelsDir = field(\"modelsDir\");\n const thoughtTokens = section[\"thoughtTokens\"];\n if (\n thoughtTokens !== undefined &&\n (typeof thoughtTokens !== \"number\" || !Number.isInteger(thoughtTokens) || thoughtTokens < 0)\n ) {\n throw toError(\n `${source}: \"${label}.thoughtTokens\" must be a whole number of 0 or more, got ${JSON.stringify(thoughtTokens)}.`,\n );\n }\n const keepAlive = keepAliveOf(section[\"keepAlive\"], `${label}.keepAlive`, source, toError);\n parsed[\"llama-cpp\"] = {\n ...(modelsDir !== undefined ? { modelsDir: resolve(dir, modelsDir) } : {}),\n ...(thoughtTokens !== undefined ? { thoughtTokens } : {}),\n ...(keepAlive !== undefined ? { keepAlive } : {}),\n };\n break;\n }\n }\n }\n return parsed;\n}\n\n/** `providers.llama-cpp.keepAlive` when unset: ten minutes. */\nexport const DEFAULT_KEEP_ALIVE_MS = 10 * 60_000;\n\n/**\n * `keepAlive`, in milliseconds: `0`, or a duration as `--newer-than` takes\n * one. YAML reads a bare `0` as a number, so both spellings of zero count.\n */\nfunction keepAliveOf(\n value: unknown,\n label: string,\n source: string,\n toError: ToErrorFn,\n): number | undefined {\n if (value === undefined) return undefined;\n if (value === 0 || value === \"0\") return 0;\n const refuse = (): Error =>\n toError(\n `${source}: \"${label}\" must be 0 or a duration such as 30m, 24h, 7d or 2w, got \"${typeof value === \"string\" ? value : JSON.stringify(value)}\"`,\n );\n if (typeof value !== \"string\") throw refuse();\n return parseDuration(value, refuse);\n}\n\n/** A provider and a model as one level states them; either half may be absent. */\nexport interface ProviderChoice {\n provider?: string;\n model?: string;\n /**\n * Where the level's provider was written, as a `--local` notice names it:\n * `providers.provider`, `docevals.provider`, `fill.provider`, or\n * `eval \"<id>\" in <file>`.\n */\n origin?: string;\n}\n\n/** The command line's say: `--provider`, `--model` and `--local`. */\nexport interface ProviderFlags {\n provider?: string;\n model?: string;\n /** Run inference on this machine, with llama-cpp, whatever a level asks for. */\n local?: boolean;\n}\n\n/** A configured choice that `--local` set aside. */\nexport interface ReplacedChoice {\n provider: string;\n source: string;\n}\n\n/** The effective choice, before it is checked or detected. */\nexport interface ProviderSelection {\n provider: string;\n model: string | undefined;\n /** Under `--local`, the configured provider that would otherwise have run. */\n replaced?: ReplacedChoice;\n}\n\n/**\n * The provider `--local` runs. `claude-cli` does not qualify: the binary runs\n * on this machine, the inference does not (proposal 0017).\n */\nexport const LOCAL_PROVIDER = \"llama-cpp\";\n\n/** `--local`'s help, one wording on every command that takes the flag. */\nexport const LOCAL_FLAG_HELP =\n \"run inference on this machine (llama-cpp); overrides any configured or eval-level provider\";\n\n/**\n * Names `--provider` may carry beside `--local`. `auto` under `--local` can\n * only mean the local provider, and `mock` is the library's test double, which\n * sends nothing anywhere.\n */\nconst LOCAL_COMPATIBLE: ReadonlySet<string> = new Set([LOCAL_PROVIDER, DEFAULT_PROVIDER, \"mock\"]);\n\n/**\n * Refuse `--local` beside a `--provider` it contradicts. An unknown name is\n * refused as unknown first: `--local` would otherwise set it aside unread.\n */\nexport function assertLocalFlag(flag: ProviderFlags, toError: ToErrorFn): void {\n if (flag.local !== true || flag.provider === undefined) return;\n assertKnownProvider(flag.provider, toError);\n if (LOCAL_COMPATIBLE.has(flag.provider)) return;\n throw toError(\n `--local and --provider ${flag.provider} contradict each other: --local runs inference ` +\n `on this machine with ${LOCAL_PROVIDER}. Drop one of them.`,\n );\n}\n\n/**\n * The provider and model in force.\n *\n * `flag` is the command line. `levels` are the config's statements, highest\n * precedence first: for docevals an eval's own choice, then `docevals.provider`,\n * then the family's `providers:`; for `meta fill`, `meta.fill`, then the\n * family's. The provider is the flag's, else the first level that names one,\n * else `auto`.\n *\n * A model belongs to the provider its level names, so it is carried only to\n * that provider: a level whose provider lost does not lend its model to the\n * winner, which could not run it. A level naming no provider gives its model\n * to whichever provider is in force, which is how `--provider` supplies the\n * provider a configured model needs. The flag's model applies to whatever\n * wins.\n *\n * `--local` makes the provider llama-cpp, over every level. A level's model\n * then applies only where that level named llama-cpp, and the level whose\n * provider would otherwise have run is returned as `replaced`, unless it was\n * `auto`, which chose no hosted provider. Check the flag with\n * `assertLocalFlag` first: a contradicting `--provider` is not selected here.\n */\nexport function selectProvider(\n flag: ProviderFlags,\n levels: readonly ProviderChoice[],\n): ProviderSelection {\n if (flag.local === true) return selectLocal(flag, levels);\n const provider =\n flag.provider ?? levels.find((level) => level.provider !== undefined)?.provider ?? DEFAULT_PROVIDER;\n const model =\n flag.model ??\n levels.find(\n (level) =>\n level.model !== undefined && (level.provider === undefined || level.provider === provider),\n )?.model;\n return { provider, model };\n}\n\nfunction selectLocal(flag: ProviderFlags, levels: readonly ProviderChoice[]): ProviderSelection {\n // The mock seam survives, so a test can drive `--local` without a runtime.\n const provider = flag.provider === \"mock\" ? \"mock\" : LOCAL_PROVIDER;\n const model =\n flag.model ??\n levels.find((level) => level.model !== undefined && level.provider === provider)?.model;\n // A flag's provider is the command line's own choice, never a replaced one.\n const chosen =\n flag.provider === undefined ? levels.find((level) => level.provider !== undefined) : undefined;\n const replaced =\n chosen?.provider !== undefined &&\n chosen.origin !== undefined &&\n chosen.provider !== provider &&\n chosen.provider !== DEFAULT_PROVIDER\n ? { provider: chosen.provider, source: chosen.origin }\n : undefined;\n return replaced === undefined ? { provider, model } : { provider, model, replaced };\n}\n\n/** What a selection's `--local` notice says, if it replaced anything. */\nexport function localNotice(selection: ProviderSelection): string | undefined {\n const { replaced } = selection;\n if (replaced === undefined) return undefined;\n return `--local: using ${LOCAL_PROVIDER} instead of \"${replaced.provider}\" from ${replaced.source}.`;\n}\n\n/**\n * The library's spec for a selection, with the connection settings from\n * `connections` for the provider it names.\n *\n * A named provider gets its own section, defaults filled. Under `auto` the\n * spec carries every setting detection reads, but only as the user wrote it:\n * the library counts a `baseUrl` as a reason openai is usable, so the default\n * endpoint must not reach detection. `apiKeyEnv` is left out there: the spec\n * has one for every provider, and detection looks for the default variables.\n */\nexport function providerSpecFor(\n connections: ProviderConnections,\n selection: { provider: ProviderSelector; model: string | null },\n): ProviderSpec {\n const { provider, model } = selection;\n const local = connections[\"llama-cpp\"] ?? {};\n const llamaCpp = {\n thoughtTokens: local.thoughtTokens ?? 0,\n ...(local.modelsDir !== undefined ? { modelsDirectory: local.modelsDir } : {}),\n };\n switch (provider) {\n case \"anthropic\":\n return {\n provider,\n model,\n apiKeyEnv: connections.anthropic?.apiKeyEnv ?? \"ANTHROPIC_API_KEY\",\n };\n case \"openai\":\n return {\n provider,\n model,\n apiKeyEnv: connections.openai?.apiKeyEnv ?? \"OPENAI_API_KEY\",\n baseUrl: connections.openai?.baseUrl ?? DEFAULT_OPENAI_BASE_URL,\n };\n case \"claude-cli\":\n return { provider, model, command: connections[\"claude-cli\"]?.command ?? \"claude\" };\n case \"jev\":\n return {\n provider,\n model,\n apiKeyEnv: connections.jev?.apiKeyEnv ?? \"TYPESAFE_API_KEY\",\n baseUrl: connections.jev?.baseUrl ?? DEFAULT_JEV_BASE_URL,\n };\n case \"llama-cpp\":\n // Local weights, in-process: no API key, and no network once they are\n // downloaded.\n return { provider, model, llamaCpp };\n case \"mock\":\n return { provider, model };\n case \"auto\": {\n const baseUrl = connections.openai?.baseUrl;\n const command = connections[\"claude-cli\"]?.command;\n const configuredLocal = local.thoughtTokens !== undefined || local.modelsDir !== undefined;\n return {\n provider,\n model,\n ...(baseUrl !== undefined ? { baseUrl } : {}),\n ...(command !== undefined ? { command } : {}),\n ...(configuredLocal ? { llamaCpp } : {}),\n };\n }\n }\n}\n\n/**\n * The concrete provider and model a spec resolves to, without constructing the\n * provider: a fully cached run needs no API key. Under `auto` this is where\n * detection runs. It probes the environment, the Claude CLI and the local\n * runtime, but never authenticates.\n *\n * The model returned is the RESOLVED one (the provider's default when none was\n * named, a llama-cpp tier's concrete weights), which is what makes it safe as\n * cache-key material: a library default that changes changes the key.\n */\nexport async function resolveIdentity(\n spec: ProviderSpec,\n toError: ToErrorFn,\n): Promise<{ provider: ProviderName; model: string }> {\n try {\n return await resolveProviderIdentityAsync(spec);\n } catch (err) {\n // Detection failing with nothing available is operational, not per-file:\n // the aggregate message names every provider it tried and why each was out.\n throw toError(\n err instanceof InferenceError\n ? err.message\n : `Could not resolve provider \"${String(spec.provider)}\": ${errorMessage(err)}`,\n );\n }\n}\n"],"mappings":"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","names":[]}
|