@zhushanwen/pi-session-reader 0.11.0 → 0.13.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/package.json +5 -5
- package/src/__tests__/archive-ledger.test.ts +447 -0
- package/src/__tests__/cross-package-subagent-core.test.ts +34 -25
- package/src/__tests__/entry-anchor.test.ts +3 -3
- package/src/__tests__/execution-tree.test.ts +85 -86
- package/src/__tests__/family-zcode.test.ts +24 -14
- package/src/__tests__/family.test.ts +4 -4
- package/src/__tests__/find.test.ts +50 -5
- package/src/__tests__/index.test.ts +3 -3
- package/src/__tests__/rebuild-manifest-dual-write.test.ts +29 -22
- package/src/__tests__/render.test.ts +2 -2
- package/src/__tests__/result.test.ts +20 -11
- package/src/__tests__/roots.test.ts +64 -26
- package/src/__tests__/subagents.test.ts +108 -52
- package/src/__tests__/tool-handler.test.ts +133 -83
- package/src/__tests__/workflow.test.ts +5 -5
- package/src/__tests__/zcode-manifest.test.ts +18 -10
- package/src/__tests__/zcode-routing.test.ts +21 -19
- package/src/__tests__/zcode-whitelist.test.ts +1 -1
- package/src/core/family.ts +6 -6
- package/src/core/render.ts +2 -2
- package/src/core/toolcall.ts +1 -1
- package/src/core/workflow.ts +9 -9
- package/src/discovery/archive-ledger.ts +221 -0
- package/src/discovery/archive-match.ts +84 -0
- package/src/discovery/entry-anchor.ts +5 -5
- package/src/discovery/find.ts +12 -1
- package/src/discovery/roots.ts +149 -14
- package/src/discovery/subagents.ts +24 -17
- package/src/discovery/whitelist.ts +4 -4
- package/src/discovery/workflows.ts +8 -8
- package/src/discovery/zcode-manifest.ts +22 -27
- package/src/doctor.ts +3 -0
- package/src/extract.ts +1 -1
- package/src/index.ts +5 -2
- package/src/no-match.ts +29 -4
- package/src/result-action.ts +7 -1
- package/src/search-across.ts +3 -3
- package/src/tool-format.ts +24 -13
- package/src/tool-handler.ts +68 -29
- package/src/tui/session-command.ts +1 -1
- package/src/zcode-anchor-classify.ts +2 -2
package/src/tool-handler.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 域模块拆分(max-lines 拆分轮机械提取,零行为变更,result-action.ts 先例同型):
|
|
12
12
|
* result-action.ts(result)/ doctor.ts(doctor + SessionReadSignals)/
|
|
13
13
|
* search-across.ts(search 管线 + u12 跨会话)/ extract.ts(extract 预设)/
|
|
14
|
-
* tool-format.ts(各 action 输出文本渲染 +
|
|
14
|
+
* tool-format.ts(各 action 输出文本渲染 + 错误范围 message + F2 消歧与
|
|
15
15
|
* find 零匹配包装)/ no-match.ts(F1 自检行)/ zcode-anchor-classify.ts(entry
|
|
16
16
|
* 兜底归因的 entry 级纯判定)/ handler-utils.ts(pad/err/
|
|
17
17
|
* stripHash/requireStr/SESSION_ID_PREFIX_LEN/turn 索引解析低层小工具)。
|
|
@@ -20,13 +20,15 @@
|
|
|
20
20
|
* 本模块 re-export 供 index.ts 生产消费)。
|
|
21
21
|
*
|
|
22
22
|
* 错误规格 F1-F6:handler 抛 Error(message 含 👉 恢复指引),index.ts 的 execute 闭包
|
|
23
|
-
* 原样传播给 pi——
|
|
24
|
-
*
|
|
23
|
+
* 原样传播给 pi——execute throw → agent-loop catch 置 isError:true(pi-agent-core dist/
|
|
24
|
+
* agent-loop.js executePreparedToolCall,1.0.0 实读 catch :581-588;1.0.0 起正常 return 的
|
|
25
|
+
* isError 也被尊重——:579 isError: result.isError === true,0.84.4 才硬编码 false——本包
|
|
26
|
+
* 失败恒走 throw,行为不变)。handler 可抛(纯逻辑可测)。
|
|
25
27
|
* 例外:F2 多匹配与 F1 find 零匹配「不视为错误」,返回消歧/提示结果而非抛错。
|
|
26
28
|
*/
|
|
27
29
|
import { existsSync } from 'node:fs'
|
|
28
30
|
import { mkdir, readFile, stat, writeFile } from 'node:fs/promises'
|
|
29
|
-
import { join, isAbsolute } from 'node:path'
|
|
31
|
+
import { join, dirname, isAbsolute } from 'node:path'
|
|
30
32
|
import { homedir } from 'node:os'
|
|
31
33
|
import { toErrorMessage } from '@zhushanwen/pi-ext-guards'
|
|
32
34
|
import { getLogger } from '@zhushanwen/pi-extension-logger'
|
|
@@ -38,6 +40,10 @@ import {
|
|
|
38
40
|
type SessionMetadataEntry,
|
|
39
41
|
type SessionMetadataProvider,
|
|
40
42
|
} from './discovery/find.js'
|
|
43
|
+
import {
|
|
44
|
+
resolveArchiveFragment,
|
|
45
|
+
type ArchiveResolve,
|
|
46
|
+
} from './discovery/archive-match.js'
|
|
41
47
|
import { resolveSessionRoots } from './discovery/roots.js'
|
|
42
48
|
import { readSessionHeaderIdSync } from './discovery/session-header.js'
|
|
43
49
|
import { findZcodeEntryAnchor, type ZcodeAnchor } from './discovery/entry-anchor.js'
|
|
@@ -102,7 +108,7 @@ import {
|
|
|
102
108
|
extractUserMessages,
|
|
103
109
|
type ExtractWhat,
|
|
104
110
|
} from './extract.js'
|
|
105
|
-
// 同轮拆分的渲染域模块(format* 纯函数簇,含 zcode
|
|
111
|
+
// 同轮拆分的渲染域模块(format* 纯函数簇,含 zcode 错误范围 message 与
|
|
106
112
|
// zcodeReadErrorMessage 错误映射):运行时依赖方向本模块 → tool-format,
|
|
107
113
|
// tool-format 对本模块仅 type import(ToolResult),无循环。
|
|
108
114
|
import {
|
|
@@ -122,6 +128,7 @@ import {
|
|
|
122
128
|
formatZcodeRecordNotFound,
|
|
123
129
|
formatZcodeSessionNotFound,
|
|
124
130
|
isToolResultSummary,
|
|
131
|
+
resolveNonOkResult,
|
|
125
132
|
zcodeReadErrorMessage,
|
|
126
133
|
} from './tool-format.js'
|
|
127
134
|
import { doDoctor, type SessionReadSignals } from './doctor.js'
|
|
@@ -132,7 +139,7 @@ import { firstIncompleteAnchorReason } from './zcode-anchor-classify.js'
|
|
|
132
139
|
export type { SessionReadSignals }
|
|
133
140
|
|
|
134
141
|
// zcode 读链的结构化日志(「事后排查」通道:degradations 留痕 / L2-L3 恢复成功 /
|
|
135
|
-
// anchor-missing 归因——§3.4 可观测性 + P2 降级隔离契约 F13,均不进 LLM
|
|
142
|
+
// anchor-missing 归因——§3.4 可观测性 + P2 降级隔离契约 F13,均不进 LLM 可见部分)。
|
|
136
143
|
// pi handle 由 index.ts 初始化时 setPiHandle 注入(appendEntry 通道);未注入时
|
|
137
144
|
// warn/error 降级文件日志,双开关缺省 no-op(纯 pi 独立用户零行为影响)。
|
|
138
145
|
const logger = getLogger('session-reader')
|
|
@@ -215,6 +222,13 @@ export type ResolveResult =
|
|
|
215
222
|
zcodeAnchor?: ZcodeAnchor
|
|
216
223
|
}
|
|
217
224
|
| { kind: 'multi'; query: string; candidates: MatchedSession[] }
|
|
225
|
+
/**
|
|
226
|
+
* [session-archive D7] 片段命中归档 session(在场零命中后的归档回退层,两支
|
|
227
|
+
* 形态见 ArchiveResolve):消费方(各 do* 的 non-ok 分发 resolveNonOkResult /
|
|
228
|
+
* result-action)统一返回归档态摘要——不读压缩体,头部显式标注归档态
|
|
229
|
+
* (agent 区分摘要与完整历史的硬契约)。
|
|
230
|
+
*/
|
|
231
|
+
| ArchiveResolve
|
|
218
232
|
|
|
219
233
|
// readSessionHeaderIdSync(同步读首行 header 取 id,resolveSessionId 形态①/②消费)
|
|
220
234
|
// 在 discovery/session-header.ts(基座 readFirstJsonlLineSync 的谓词/降级薄包装,G2 单源)。
|
|
@@ -267,7 +281,7 @@ async function resolveSessionId(
|
|
|
267
281
|
|
|
268
282
|
// §3.4 第 0 段:sess_ 形态 id 无第一梯队直读入口(agent 从不持有 sess id,F14;
|
|
269
283
|
// 且无 zcode 候选发现,D6)→ zcode_param_invalid。pi 的 session id 是 uuid(无
|
|
270
|
-
// sess_
|
|
284
|
+
// sess_ 前缀),此检测只改变错误输入的错误范围文案。
|
|
271
285
|
if (session.startsWith('sess_')) {
|
|
272
286
|
throw err(formatZcodeParamInvalid(session))
|
|
273
287
|
}
|
|
@@ -287,7 +301,7 @@ async function resolveSessionId(
|
|
|
287
301
|
* `resolveByRecordId`(engine 缺省/'pi' 形态,行为与今天逐字节一致)。
|
|
288
302
|
* ③ pi 无命中(今天此处直接 ES2)→ entry 兜底(§3.5 第②层,仅 liveSessionDir 内,
|
|
289
303
|
* 越界显式失败):命中 → zcode 读链;未命中 → `zcode_record_not_found` + 👉
|
|
290
|
-
* (§3.4:sa-id
|
|
304
|
+
* (§3.4:sa-id 语境的统一错误范围——F14 agent 唯一持有的 id 就是 sa-id,指引动作
|
|
291
305
|
* 覆盖除 find 指针外的全部恢复路径(find 按 §3.4 刻意不保留)。
|
|
292
306
|
*/
|
|
293
307
|
async function resolveSaIdRoute(
|
|
@@ -299,7 +313,7 @@ async function resolveSaIdRoute(
|
|
|
299
313
|
): Promise<ResolveResult> {
|
|
300
314
|
const zm = await readZcodeManifest(agentDir, session)
|
|
301
315
|
if (zm.kind === 'anchor-missing') {
|
|
302
|
-
// 归因进结构化日志不进 LLM
|
|
316
|
+
// 归因进结构化日志不进 LLM 可见部分(§3.4):reason 逐键归因(missing-engineHandle /
|
|
303
317
|
// missing-sessionRef / missing-sessionId / missing-dbPath,见 zcode-manifest.ts)
|
|
304
318
|
logger.warn('zcode manifest anchor-missing', { saId: session, reason: zm.reason })
|
|
305
319
|
throw err(formatZcodeAnchorMissing(session))
|
|
@@ -391,7 +405,7 @@ async function resolveZcodeRoute(
|
|
|
391
405
|
const zcodeNodes = await listZcodeManifests(agentDir)
|
|
392
406
|
const rootSessionId = zcodeNodes.find((n) => n.id === saId)?.rootSessionId
|
|
393
407
|
// 枚举未含该 id(直读命中与枚举之间 manifest 被迁移的极端窗口)→ 退回锚 sessionId,
|
|
394
|
-
// 后续 byId 查不到走既有 not-found
|
|
408
|
+
// 后续 byId 查不到走既有 not-found 错误范围(不静默伪造家族)
|
|
395
409
|
if (rootSessionId === undefined) {
|
|
396
410
|
return { kind: 'ok', sessionId: anchor.sessionId, fileName: '' }
|
|
397
411
|
}
|
|
@@ -467,6 +481,11 @@ async function resolveByRecordId(session: string, agentDir: string, prefetchedMa
|
|
|
467
481
|
* 形态③:其余片段 → findSessions 透传 source/liveSessionDir 沿用 F1(零匹配)/ F2(多匹配消歧)。
|
|
468
482
|
* liveSessionDir 透传保证片段匹配与 find 同一 roots;F1 自检行同理须含 [live] 根行
|
|
469
483
|
*(否则 [live]≠[default] 环境下自检行看不到最高优先级根,计数失真)。
|
|
484
|
+
*
|
|
485
|
+
* [session-archive D7] 归档回退层:在场匹配零命中 → 查归档簿记(archive-match)。
|
|
486
|
+
* 在场优先保证既有行为零变化(归档 session 不在 sessions/ 扫描范围,「在场零命中」
|
|
487
|
+
* 与「已归档」对同一 session 互斥成立——D9 不变量 1);命中归档不走 F1(历史引用
|
|
488
|
+
* 不断链,D7 方案否决项「agent 完全不可见」)。
|
|
470
489
|
*/
|
|
471
490
|
async function resolveByFragment(
|
|
472
491
|
session: string,
|
|
@@ -481,6 +500,10 @@ async function resolveByFragment(
|
|
|
481
500
|
}
|
|
482
501
|
const { matches } = await findSessions(session, agentDir, opts)
|
|
483
502
|
if (matches.length === 0) {
|
|
503
|
+
// [session-archive D7] 归档回退层:单命中返回归档态、多命中返回归档消歧
|
|
504
|
+
//(实现与匹配口径在 discovery/archive-match.ts);无簿记命中落 F1。
|
|
505
|
+
const archive = await resolveArchiveFragment(session, agentDir)
|
|
506
|
+
if (archive !== undefined) return archive
|
|
484
507
|
// F1 自检行需要发现层实况:无 options 的 resolveSessionRoots 恒实扫(根扫描无
|
|
485
508
|
// 缓存——doctor 缓存机已删除,ext-simplify-04 U3),与 find 刚完成的扫描同一数据
|
|
486
509
|
// 源(roots.ts 薄包装语义);信号包同源(liveSessionDir 透传)——findSessions
|
|
@@ -501,8 +524,8 @@ async function resolveByFragment(
|
|
|
501
524
|
/**
|
|
502
525
|
* zcode 锚 → ParseResult(既有 turns/render 管线的统一内容入口)。
|
|
503
526
|
*
|
|
504
|
-
* 检查顺序三段递进(§3.4,实现与测试双锚定):第 1 段存在性 → 第 2
|
|
505
|
-
* (whitelist.ts)→ 第 3 段开库与查询(四级恢复阶梯 + schema
|
|
527
|
+
* 检查顺序三段递进(§3.4,实现与测试双锚定):第 1 段存在性 → 第 2 段路径门禁
|
|
528
|
+
* (whitelist.ts)→ 第 3 段开库与查询(四级恢复阶梯 + schema 已知集门禁在
|
|
506
529
|
* openZcodeSessionDb 单点)。读库发生在 ext 进程内(§3.5 关键论断),不经 taiji。
|
|
507
530
|
*/
|
|
508
531
|
async function loadZcodeParsed(anchor: ZcodeAnchor, agentDir: string): Promise<ParseResult> {
|
|
@@ -515,7 +538,7 @@ async function loadZcodeParsed(anchor: ZcodeAnchor, agentDir: string): Promise<P
|
|
|
515
538
|
}
|
|
516
539
|
try {
|
|
517
540
|
// 恢复成功不再是静默事件(§3.4 硬要求):结构化日志(恢复方式 + db 路径),不进
|
|
518
|
-
// LLM
|
|
541
|
+
// LLM 可见部分。用 warn 而非 debug——L2/L3 是恢复降级路径,语义表 warn=内部降级与
|
|
519
542
|
// 失败(appendEntry 持久化);debug 缺省 no-op 会让恢复成功重新变回静默事件。
|
|
520
543
|
if (handle.via !== 'L1-direct') {
|
|
521
544
|
logger.warn('zcode session db recovered via recovery ladder', {
|
|
@@ -545,7 +568,7 @@ async function loadZcodeParsed(anchor: ZcodeAnchor, agentDir: string): Promise<P
|
|
|
545
568
|
// converter 保证),totalBytes/skippedLines 恒 0
|
|
546
569
|
return { entries: normalized.entries, totalBytes: 0, skippedLines: 0, lastLinePartial: false }
|
|
547
570
|
} catch (e) {
|
|
548
|
-
if (e instanceof Error && e.message.startsWith('[zcode_')) throw e //
|
|
571
|
+
if (e instanceof Error && e.message.startsWith('[zcode_')) throw e // 本函数产出的错误范围原样传播
|
|
549
572
|
throw err(zcodeReadErrorMessage(e, agentDir))
|
|
550
573
|
} finally {
|
|
551
574
|
handle.dispose()
|
|
@@ -719,7 +742,8 @@ async function doFamily(
|
|
|
719
742
|
undefined,
|
|
720
743
|
liveSessionDir,
|
|
721
744
|
)
|
|
722
|
-
|
|
745
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
746
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
723
747
|
|
|
724
748
|
// recursive=true:嵌套执行树(U7/U8)
|
|
725
749
|
if (params.recursive) {
|
|
@@ -766,7 +790,8 @@ async function doOutline(
|
|
|
766
790
|
undefined,
|
|
767
791
|
liveSessionDir,
|
|
768
792
|
)
|
|
769
|
-
|
|
793
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
794
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
770
795
|
const { entries, totalBytes, skippedLines } = await loadParsed(resolved, agentDir)
|
|
771
796
|
const tree = buildTreeView(entries)
|
|
772
797
|
const turns = segmentTurns(entries, new Set(tree.leafPath))
|
|
@@ -802,7 +827,8 @@ async function doExpand(
|
|
|
802
827
|
undefined,
|
|
803
828
|
liveSessionDir,
|
|
804
829
|
)
|
|
805
|
-
|
|
830
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
831
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
806
832
|
const turnIdx = parseTurnIndex(requireStr(params.turn, 'turn', 'expand'))
|
|
807
833
|
const { entries } = await loadParsed(resolved, agentDir)
|
|
808
834
|
const tree = buildTreeView(entries)
|
|
@@ -835,7 +861,8 @@ async function doDetail(
|
|
|
835
861
|
undefined,
|
|
836
862
|
liveSessionDir,
|
|
837
863
|
)
|
|
838
|
-
|
|
864
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
865
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
839
866
|
const range = parseTurnsRange(requireStr(params.turns, 'turns', 'detail'))
|
|
840
867
|
const { entries } = await loadParsed(resolved, agentDir)
|
|
841
868
|
const tree = buildTreeView(entries)
|
|
@@ -893,7 +920,8 @@ async function doSearch(
|
|
|
893
920
|
undefined,
|
|
894
921
|
signals.liveSessionDir,
|
|
895
922
|
)
|
|
896
|
-
|
|
923
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
924
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
897
925
|
const scope = params.scope ?? 'all'
|
|
898
926
|
const limit = params.limit ?? SEARCH_DEFAULT_LIMIT
|
|
899
927
|
const { entries } = await loadParsed(resolved, agentDir)
|
|
@@ -912,7 +940,7 @@ async function doSearch(
|
|
|
912
940
|
/** export full 模式的 entry 分隔线('=' 重复)宽度。 */
|
|
913
941
|
const EXPORT_SEPARATOR_LEN = 40
|
|
914
942
|
|
|
915
|
-
/** export:物化摘要到 <
|
|
943
|
+
/** export:物化摘要到 <dataDir>/ext-sessions/<id>/session-view.md(session-store-layout-inversion 域 6;文件名去 sid——sid 已在路径)。 */
|
|
916
944
|
async function doExport(
|
|
917
945
|
params: SessionReadParams,
|
|
918
946
|
agentDir: string,
|
|
@@ -927,7 +955,8 @@ async function doExport(
|
|
|
927
955
|
undefined,
|
|
928
956
|
liveSessionDir,
|
|
929
957
|
)
|
|
930
|
-
|
|
958
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
959
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
931
960
|
|
|
932
961
|
let text: string
|
|
933
962
|
let label: string
|
|
@@ -972,8 +1001,16 @@ async function doExport(
|
|
|
972
1001
|
label = 'outline'
|
|
973
1002
|
}
|
|
974
1003
|
|
|
975
|
-
|
|
976
|
-
|
|
1004
|
+
// [session-store-layout-inversion 域 6] 导出落 session 存储树(<root>/<sid>/session-view.md,
|
|
1005
|
+
// 文件名去 sid——sid 已在路径):基址 = agentDir 剥一层(taiji dataDir,托管态
|
|
1006
|
+
// PI_CODING_AGENT_DIR = <dataDir>/agent)。session-reader 零 shared 依赖(extension 包
|
|
1007
|
+
// 边界),公式与 shared getSessionViewPath 同字面镜像;sessionId 过 isPiSessionId 同域
|
|
1008
|
+
// 校验(解析器产出的 sid 正常路径恒合法,此处是路径穿越纵深防线)。
|
|
1009
|
+
if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(resolved.sessionId)) {
|
|
1010
|
+
throw err(`导出拒绝:sessionId 形态非法(${resolved.sessionId})👉 检查 session 参数或用 find 重新定位`)
|
|
1011
|
+
}
|
|
1012
|
+
const outDir = join(dirname(agentDir), 'ext-sessions', resolved.sessionId)
|
|
1013
|
+
const outPath = join(outDir, 'session-view.md')
|
|
977
1014
|
await mkdir(outDir, { recursive: true })
|
|
978
1015
|
await writeFile(outPath, text, 'utf8')
|
|
979
1016
|
const sizeBytes = Buffer.byteLength(text, 'utf8')
|
|
@@ -996,7 +1033,7 @@ async function doExport(
|
|
|
996
1033
|
//(max-lines 拆分轮机械提取);本段保留 F7 what 校验与 doExtract 编排(定位依赖
|
|
997
1034
|
// tool-handler 私有的 resolveSessionId/safeParse/segmentTurns)。纯提取,不调 LLM。
|
|
998
1035
|
|
|
999
|
-
/** what
|
|
1036
|
+
/** what 类型检查(直接比较,避开不安全断言;schema 已校验,此处防御 + 可单测绕过)。 */
|
|
1000
1037
|
function isExtractWhat(v: unknown): v is ExtractWhat {
|
|
1001
1038
|
return (
|
|
1002
1039
|
v === 'user-messages' ||
|
|
@@ -1026,7 +1063,8 @@ async function doExtract(
|
|
|
1026
1063
|
undefined,
|
|
1027
1064
|
liveSessionDir,
|
|
1028
1065
|
)
|
|
1029
|
-
|
|
1066
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
1067
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
1030
1068
|
const { entries } = await loadParsed(resolved, agentDir)
|
|
1031
1069
|
// extract 遍历全量 entry(含旁支/压缩历史),与 outline/expand/detail 的 leaf 视图不同:
|
|
1032
1070
|
// 素材提取要全量(design §2.3 实测全量 519 toolCall / 26 user / 515 toolResult),
|
|
@@ -1109,7 +1147,7 @@ interface SkippedRun {
|
|
|
1109
1147
|
* session 会抛「session not found in family index」)——resolveSessionId 已把 session 解析到
|
|
1110
1148
|
* 真实文件(kind==='ok' 保证文件存在,三形态:绝对路径/sa-id 均 existsSync 校验,片段匹配
|
|
1111
1149
|
* 来自实际 fs 扫描),直接用 resolved.fileName 构造单条目 sessionIdToPath 调 resolveWorkflows
|
|
1112
|
-
*(与 buildFamilyFromFs 步骤 6 的 workflow
|
|
1150
|
+
*(与 buildFamilyFromFs 步骤 6 的 workflow 路径同源)。pathToRef 传空 Map(单条目链路无其他
|
|
1113
1151
|
* 文件可反查),call 引用 100% 走 sessionRefFromPath 文件名最小回退(sessionId+fileName,
|
|
1114
1152
|
* 足够 LLM 跳 outline/detail 深读)。
|
|
1115
1153
|
*
|
|
@@ -1131,7 +1169,7 @@ async function renderSingleWorkflowRun(
|
|
|
1131
1169
|
): Promise<void> {
|
|
1132
1170
|
// [D16③] 概览链换源:v2 档的 stateFile = record 流路径(recordPath 锚点语义
|
|
1133
1171
|
// 重定义)——直读流经 parseRunRecordStream 概览([D2] 三态 status;空流/读失败
|
|
1134
|
-
|
|
1172
|
+
// 映射 running,活跃 run 概览不退化为 skipped——红线)。record 后缀以外的
|
|
1135
1173
|
// stateFile(v1 快照档空串 / 旧指针档 link path)走原快照链。
|
|
1136
1174
|
if (wf.stateFile.endsWith('.record.jsonl')) {
|
|
1137
1175
|
await renderRunFromRecordStream(wf, ctx)
|
|
@@ -1205,7 +1243,8 @@ async function doWorkflow(
|
|
|
1205
1243
|
undefined,
|
|
1206
1244
|
liveSessionDir,
|
|
1207
1245
|
)
|
|
1208
|
-
|
|
1246
|
+
// non-ok 支统一分发(multi 消歧 / 归档态两支,[session-archive D7] 归并点)
|
|
1247
|
+
if (resolved.kind !== 'ok') return resolveNonOkResult(resolved)
|
|
1209
1248
|
|
|
1210
1249
|
let workflows: WorkflowRef[]
|
|
1211
1250
|
try {
|
|
@@ -1391,7 +1430,7 @@ export async function handleSessionRead(
|
|
|
1391
1430
|
case 'workflow':
|
|
1392
1431
|
return doWorkflow(params, agentDir, signals.liveSessionDir)
|
|
1393
1432
|
case 'result': {
|
|
1394
|
-
// per-call
|
|
1433
|
+
// per-call 构造注入点(仅剩 tool-handler 文件私有 helper,纯函数经 handler-utils
|
|
1395
1434
|
// 直接 import——ext-simplify-04 E5):resolveSessionId 包装把信号包中的
|
|
1396
1435
|
// liveSessionDir 闭包进解析调用(ResultActionDeps 接口签名固定 5 参,包装保持
|
|
1397
1436
|
// 同形、末位补传),result 的片段形态与 find/outline 消费同一 roots
|
|
@@ -77,7 +77,7 @@ export function createSessionCommand(
|
|
|
77
77
|
const chosen = await ctx.ui.select('选择一个 session 插入 # 引用', labels)
|
|
78
78
|
if (chosen === undefined) return
|
|
79
79
|
// chosen 必属 labels(select 契约返回列表成员或 undefined,后者上一行已拦截),
|
|
80
|
-
// indexOf 恒命中——不再保留 idx<0
|
|
80
|
+
// indexOf 恒命中——不再保留 idx<0 永不命中的防御机制分支
|
|
81
81
|
const idx = labels.indexOf(chosen)
|
|
82
82
|
// 选中后插入 # + 完整 uuid(剥 # 算片段,再补 # 插入编辑器)
|
|
83
83
|
const frag = toCandidate(top[idx]).insertText.slice(1)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 判定与 entry-anchor.ts 的 zcodeAnchorOfEntry 双键判据同构(v1 快照 / v2 终态条
|
|
7
7
|
* 双版本门),协议字面量同值(写侧 subagent-core record-entry.ts
|
|
8
|
-
* SUBAGENT_RECORD_CUSTOM_TYPE,漂移由 entry-anchor.test.ts
|
|
8
|
+
* SUBAGENT_RECORD_CUSTOM_TYPE,漂移由 entry-anchor.test.ts 检查)。
|
|
9
9
|
*/
|
|
10
10
|
import type { Entry } from '@zhushanwen/session-core'
|
|
11
11
|
import type { ZcodeAnchorMissingReason } from './discovery/zcode-manifest.js'
|
|
@@ -13,7 +13,7 @@ import type { ZcodeAnchorMissingReason } from './discovery/zcode-manifest.js'
|
|
|
13
13
|
/**
|
|
14
14
|
* v2 条目 data 的认识版本词表(W1 起 = 2)。与写侧 subagent-core
|
|
15
15
|
* SUBAGENT_RECORD_ENTRY_VERSION 同值——本地持有 + entry-anchor.test.ts 跨包断言
|
|
16
|
-
*
|
|
16
|
+
* 检查漂移(生产依赖范围不引 subagent-core,同 entry-anchor.ts 的协议字面量模式)。
|
|
17
17
|
*/
|
|
18
18
|
const SUBAGENT_RECORD_ENTRY_V2 = 2
|
|
19
19
|
|