@zhushanwen/pi-session-reader 0.6.0 → 0.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 +100 -0
- package/package.json +7 -4
- package/src/__tests__/cross-package-subagent-core.test.ts +36 -44
- package/src/__tests__/entry-anchor.test.ts +226 -0
- package/src/__tests__/env.test.ts +54 -54
- package/src/__tests__/execution-tree.test.ts +6 -0
- package/src/__tests__/family-zcode.test.ts +255 -0
- package/src/__tests__/family.test.ts +1 -1
- package/src/__tests__/find.test.ts +24 -1
- package/src/__tests__/index.test.ts +1 -1
- package/src/__tests__/parser.test.ts +1 -2
- package/src/__tests__/real-data.ts +22 -9
- package/src/__tests__/render.test.ts +1 -2
- package/src/__tests__/result.test.ts +2 -2
- package/src/__tests__/roots.test.ts +1 -1
- package/src/__tests__/subagents.test.ts +1 -4
- package/src/__tests__/tool-handler.test.ts +76 -85
- package/src/__tests__/toolcall.test.ts +1 -1
- package/src/__tests__/tree.test.ts +1 -1
- package/src/__tests__/turns.test.ts +1 -2
- package/src/__tests__/zcode-manifest.test.ts +361 -0
- package/src/__tests__/zcode-routing.test.ts +751 -0
- package/src/__tests__/zcode-whitelist.test.ts +119 -0
- package/src/core/execution-tree.ts +3 -1
- package/src/core/family.ts +80 -1
- package/src/core/render.ts +2 -3
- package/src/core/toolcall.ts +3 -4
- package/src/core/tree.ts +1 -1
- package/src/core/turns.ts +1 -1
- package/src/core/units.ts +14 -0
- package/src/discovery/entry-anchor.ts +108 -0
- package/src/discovery/env.ts +41 -41
- package/src/discovery/find.ts +1 -1
- package/src/discovery/roots.ts +2 -2
- package/src/discovery/session-header.ts +30 -69
- package/src/discovery/subagents.ts +9 -2
- package/src/discovery/whitelist.ts +87 -0
- package/src/discovery/workflows.ts +1 -1
- package/src/discovery/zcode-manifest.ts +277 -0
- package/src/doctor.ts +5 -70
- package/src/index.ts +9 -2
- package/src/result-action.ts +15 -6
- package/src/search-across.ts +2 -5
- package/src/tool-format.ts +455 -0
- package/src/tool-handler.ts +321 -325
- package/src/zcode-anchor-classify.ts +60 -0
- package/vitest.config.ts +2 -4
- package/src/core/parser.ts +0 -167
|
@@ -267,10 +267,10 @@ describe('result action(U6)', () => {
|
|
|
267
267
|
}
|
|
268
268
|
})
|
|
269
269
|
|
|
270
|
-
it('6. 不存在 id:sa-id 无 manifest →
|
|
270
|
+
it('6. 不存在 id:sa-id 无 manifest → zcode_record_not_found(U9 统一错误面);uuid 片段零匹配 → 无匹配 session', async () => {
|
|
271
271
|
await expect(
|
|
272
272
|
handleSessionRead({ action: 'result', session: 'sa-nonexist-9999' }, { agentDir: dir }),
|
|
273
|
-
).rejects.toThrow(
|
|
273
|
+
).rejects.toThrow(/zcode_record_not_found/)
|
|
274
274
|
try {
|
|
275
275
|
await handleSessionRead({ action: 'result', session: 'sa-nonexist-9999' }, { agentDir: dir })
|
|
276
276
|
} catch (e) {
|
|
@@ -214,7 +214,7 @@ const HOST_CASES: HostCase[] = [
|
|
|
214
214
|
},
|
|
215
215
|
},
|
|
216
216
|
{
|
|
217
|
-
name: '
|
|
217
|
+
name: 'taiji:live=根本身(RPC 覆盖态),default 去重,legacy 残留与 subagent 独立列出',
|
|
218
218
|
async build(tmp) {
|
|
219
219
|
const dataDir = join(tmp, 'data')
|
|
220
220
|
const agentDir = join(dataDir, 'agent')
|
|
@@ -10,16 +10,13 @@ import {
|
|
|
10
10
|
extractSessionIdFromFilename,
|
|
11
11
|
type RecordManifest,
|
|
12
12
|
} from '../discovery/subagents.js'
|
|
13
|
-
import { REAL_DATA_TIMEOUT_MS } from './real-data.js'
|
|
13
|
+
import { REAL_AGENT_DIR, REAL_DATA_TIMEOUT_MS } from './real-data.js'
|
|
14
14
|
|
|
15
15
|
// ---- fixture 常量(uuid 特征,满足 extractSessionIdFromFilename + 互不为子串)----
|
|
16
16
|
const ROOT = '0aaaaaaa-bbbb-7ccc-dddd-000000000001'
|
|
17
17
|
const FORK = '0aaaaaaa-bbbb-7ccc-dddd-000000000002'
|
|
18
18
|
const SUB_REAL = '0aaaaaaa-bbbb-7ccc-dddd-000000000003'
|
|
19
19
|
|
|
20
|
-
/** 真实 pi agent 目录(本机),用于集成测试。 */
|
|
21
|
-
const REAL_AGENT_DIR = '/Users/zhushanwen/.pi/agent'
|
|
22
|
-
|
|
23
20
|
// 同步探测真实 session 是否存在(不存在则 skip,避免在无该数据的机器上硬失败)
|
|
24
21
|
function hasRealSession(sid: string): boolean {
|
|
25
22
|
try {
|
|
@@ -30,11 +30,20 @@ import {
|
|
|
30
30
|
hasRealSession,
|
|
31
31
|
} from './real-data.js'
|
|
32
32
|
|
|
33
|
+
// fs-guard:TC6 的「~ 前缀展开」语义需要 homedir,但真实 homedir 根在白名单外(禁止向用户
|
|
34
|
+
// 主目录散落文件)。vi.mock 把 homedir 指到用例内 mkdtemp 的 tmp;fakeHome 未注入时回落真实值,
|
|
35
|
+
// real-data.ts 模块初始化时推导 REAL_AGENT_DIR 不受影响(模块初始化先于任何用例执行)。
|
|
36
|
+
const homeState = vi.hoisted(() => ({ fakeHome: undefined as string | undefined }))
|
|
37
|
+
vi.mock('node:os', async (importOriginal) => {
|
|
38
|
+
const actual = await importOriginal<typeof import('node:os')>()
|
|
39
|
+
return { ...actual, homedir: () => homeState.fakeHome ?? actual.homedir() }
|
|
40
|
+
})
|
|
41
|
+
|
|
33
42
|
/**
|
|
34
43
|
* M3 tool-handler 集成测试。
|
|
35
44
|
*
|
|
36
45
|
* 测试框架 vitest(禁止 node:test/tsx)。直接调 handleSessionRead(纯逻辑,agentDir 注入),
|
|
37
|
-
* 传真实
|
|
46
|
+
* 传真实 `~/.pi/agent` 作 agentDir——用本机真实历史 session 数据,无需 mock。
|
|
38
47
|
*
|
|
39
48
|
* 覆盖全 11 action 主路径 + F1(find 零匹配)/F4(turn 越界)/F5(缺参)/resolveSessionId 片段等价,
|
|
40
49
|
* 以及 u8 doctor / u9 归一化 / u10 find 分组 / u11 metadataProvider 缓存 / u12 跨会话检索(各见对应 describe)。
|
|
@@ -95,14 +104,21 @@ describe.skipIf(!HAS_REAL)('handleSessionRead', () => {
|
|
|
95
104
|
})
|
|
96
105
|
|
|
97
106
|
it('6. export outline materializes a .md file', async () => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
// fs-guard:export 写目标 = <agentDir>/tmp/,agentDir 传 REAL 会 mkdir 真实 ~/.pi/agent/tmp
|
|
108
|
+
// (白名单外)。读侧经 liveSessionDir=[live] 根仍扫真实数据,写侧落 mkdtemp tmp 自建自删。
|
|
109
|
+
const dir = await mkdtemp(join(tmpdir(), 'tool-handler-export-'))
|
|
110
|
+
try {
|
|
111
|
+
const r = await handleSessionRead(
|
|
112
|
+
{ action: 'export', session: E6, format: 'outline' },
|
|
113
|
+
{ agentDir: dir, liveSessionDir: join(REAL, 'sessions') },
|
|
114
|
+
)
|
|
115
|
+
const d = r.details as { path: string; sizeBytes: number }
|
|
116
|
+
expect(d.path).toMatch(/\.md$/)
|
|
117
|
+
expect(existsSync(d.path)).toBe(true)
|
|
118
|
+
expect(d.sizeBytes).toBeGreaterThan(0)
|
|
119
|
+
} finally {
|
|
120
|
+
await rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 })
|
|
121
|
+
}
|
|
106
122
|
})
|
|
107
123
|
|
|
108
124
|
// w1 合并 subagent 候选后,本机 subagent task 文本(含本用例 query 字符串本身,因当前
|
|
@@ -643,7 +659,7 @@ describe('extract commits 双路径(fixture:git-cmd 主路径 + commit-conte
|
|
|
643
659
|
message: {
|
|
644
660
|
role: 'assistant',
|
|
645
661
|
content: [
|
|
646
|
-
{ type: 'toolCall', id: 'tc-read-1', name: 'read', arguments: { path: '
|
|
662
|
+
{ type: 'toolCall', id: 'tc-read-1', name: 'read', arguments: { path: join(tmpdir(), 'log.txt') } },
|
|
647
663
|
],
|
|
648
664
|
},
|
|
649
665
|
}),
|
|
@@ -667,7 +683,7 @@ describe('extract commits 双路径(fixture:git-cmd 主路径 + commit-conte
|
|
|
667
683
|
message: {
|
|
668
684
|
role: 'assistant',
|
|
669
685
|
content: [
|
|
670
|
-
{ type: 'toolCall', id: 'tc-read-2', name: 'read', arguments: { path: '
|
|
686
|
+
{ type: 'toolCall', id: 'tc-read-2', name: 'read', arguments: { path: join(tmpdir(), 'out.txt') } },
|
|
671
687
|
],
|
|
672
688
|
},
|
|
673
689
|
}),
|
|
@@ -724,7 +740,7 @@ describe('extract commits 双路径(fixture:git-cmd 主路径 + commit-conte
|
|
|
724
740
|
message: {
|
|
725
741
|
role: 'assistant',
|
|
726
742
|
content: [
|
|
727
|
-
{ type: 'toolCall', id: 'tc-read-1', name: 'read', arguments: { path: '
|
|
743
|
+
{ type: 'toolCall', id: 'tc-read-1', name: 'read', arguments: { path: join(tmpdir(), 'deploy.txt') } },
|
|
728
744
|
],
|
|
729
745
|
},
|
|
730
746
|
}),
|
|
@@ -933,24 +949,33 @@ describe('resolveSessionId ① 绝对路径形态(w2 TC2-TC6)', () => {
|
|
|
933
949
|
})
|
|
934
950
|
|
|
935
951
|
it('TC6: ~ 前缀展开到 homedir(文件实际在 homedir 下)', async () => {
|
|
936
|
-
|
|
937
|
-
|
|
952
|
+
// fs-guard:真实 homedir 根在白名单外(禁止在用户主目录根散落 .sr-w2-test-*)——
|
|
953
|
+
// homedir 经文件头 vi.mock 指到 mkdtemp tmp(白名单内),「~ 前缀展开」断言语义不变
|
|
954
|
+
const fakeHome = await mkdtemp(join(tmpdir(), 'tool-handler-tc6-home-'))
|
|
955
|
+
homeState.fakeHome = fakeHome
|
|
938
956
|
try {
|
|
939
|
-
const
|
|
940
|
-
const
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
957
|
+
const home = homedir()
|
|
958
|
+
const tmpUnderHome = await mkdtemp(join(home, '.sr-w2-test-'))
|
|
959
|
+
try {
|
|
960
|
+
const fileId = '019e6c96-dddd-eeee-ffff-0000000006c1'
|
|
961
|
+
const sessionFile = join(tmpUnderHome, 's.jsonl')
|
|
962
|
+
await writeFile(
|
|
963
|
+
sessionFile,
|
|
964
|
+
JSON.stringify({ type: 'session', id: fileId, cwd: '/demo' }) + '\n',
|
|
965
|
+
)
|
|
966
|
+
// ~/开头的相对 homedir 路径
|
|
967
|
+
const tildePath = '~/' + sessionFile.slice(home.length + 1)
|
|
968
|
+
const r = await handleSessionRead(
|
|
969
|
+
{ action: 'export', session: tildePath, format: 'outline' },
|
|
970
|
+
{ agentDir: dir },
|
|
971
|
+
)
|
|
972
|
+
expect((r.details as { path: string }).path).toContain(fileId)
|
|
973
|
+
} finally {
|
|
974
|
+
await rm(tmpUnderHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 })
|
|
975
|
+
}
|
|
952
976
|
} finally {
|
|
953
|
-
|
|
977
|
+
homeState.fakeHome = undefined
|
|
978
|
+
await rm(fakeHome, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 })
|
|
954
979
|
}
|
|
955
980
|
})
|
|
956
981
|
})
|
|
@@ -1001,28 +1026,32 @@ describe('resolveSessionId ② sa-id 形态(w2 TC7-TC10 + CQ3)', () => {
|
|
|
1001
1026
|
}
|
|
1002
1027
|
})
|
|
1003
1028
|
|
|
1004
|
-
it('TC9: sa-id 0 命中(可能 running)→
|
|
1029
|
+
it('TC9: sa-id 0 命中(可能 running)→ zcode_record_not_found(U9:sa-id 语境统一错误面,含 family 指引 + 👉)', async () => {
|
|
1005
1030
|
await expect(
|
|
1006
1031
|
handleSessionRead({ action: 'outline', session: 'sa-nonexist-9999' }, { agentDir: dir }),
|
|
1007
|
-
).rejects.toThrow('
|
|
1032
|
+
).rejects.toThrow('zcode_record_not_found')
|
|
1008
1033
|
try {
|
|
1009
1034
|
await handleSessionRead({ action: 'outline', session: 'sa-nonexist-9999' }, { agentDir: dir })
|
|
1010
1035
|
} catch (e) {
|
|
1011
1036
|
const msg = (e as Error).message
|
|
1012
|
-
expect(msg).toContain('
|
|
1037
|
+
expect(msg).toContain('未落盘')
|
|
1013
1038
|
expect(msg).toContain('action:"family"')
|
|
1014
1039
|
expect(msg).toContain('👉')
|
|
1015
1040
|
}
|
|
1016
1041
|
})
|
|
1017
1042
|
|
|
1018
|
-
it('TC10: sa-id 片段输入(精确相等不命中)→
|
|
1043
|
+
it('TC10: sa-id 片段输入(精确相等不命中)→ zcode_record_not_found + 完整 sa- id 重试指引(U9 统一错误面)', async () => {
|
|
1019
1044
|
await makeFixtureSubagent(dir, 'sa-c8c8dfa8', {
|
|
1020
1045
|
realSessionId: '019e6c96-dddd-eeee-ffff-0000000010a3',
|
|
1021
1046
|
})
|
|
1022
|
-
// 片段 sa-c8c8 不等于完整 sa-c8c8dfa8 →
|
|
1047
|
+
// 片段 sa-c8c8 不等于完整 sa-c8c8dfa8 → 精确相等不命中(兜底亦未命中)
|
|
1023
1048
|
await expect(
|
|
1024
1049
|
handleSessionRead({ action: 'outline', session: 'sa-c8c8' }, { agentDir: dir }),
|
|
1025
|
-
).rejects.toThrow('
|
|
1050
|
+
).rejects.toThrow('zcode_record_not_found')
|
|
1051
|
+
// 片段输入恢复路径在指引内可见(A4:ES2 原文案「用完整 sa- id 重试」的覆盖补全)
|
|
1052
|
+
await expect(
|
|
1053
|
+
handleSessionRead({ action: 'outline', session: 'sa-c8c8' }, { agentDir: dir }),
|
|
1054
|
+
).rejects.toThrow(/完整 sa- id(形如 `sa-xxxx`)后重试/)
|
|
1026
1055
|
})
|
|
1027
1056
|
|
|
1028
1057
|
it('sa-id 多 manifest 命中(数据异常)→ ES2 ambiguous(C4)', async () => {
|
|
@@ -1195,11 +1224,11 @@ describe.skipIf(!HAS_REAL_SUBAGENTS_DIR)('真实数据:subagent sa-id(w2 TC1
|
|
|
1195
1224
|
).rejects.toThrow('session 文件不存在')
|
|
1196
1225
|
})
|
|
1197
1226
|
|
|
1198
|
-
it('TC18: 不存在 sa-id →
|
|
1227
|
+
it('TC18: 不存在 sa-id → zcode_record_not_found(场景 4,U9 统一错误面)', async () => {
|
|
1199
1228
|
const fakeId = `sa-nonexist-${Date.now().toString(16)}-${Math.random().toString(16).slice(2, 8)}`
|
|
1200
1229
|
await expect(
|
|
1201
1230
|
handleSessionRead({ action: 'outline', session: fakeId }, { agentDir: REAL }),
|
|
1202
|
-
).rejects.toThrow('
|
|
1231
|
+
).rejects.toThrow('zcode_record_not_found')
|
|
1203
1232
|
})
|
|
1204
1233
|
}, 60000)
|
|
1205
1234
|
|
|
@@ -1801,8 +1830,8 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1801
1830
|
}
|
|
1802
1831
|
|
|
1803
1832
|
/**
|
|
1804
|
-
*
|
|
1805
|
-
* PI_CODING_AGENT_DIR 形态判据 `<*>/.
|
|
1833
|
+
* taiji 形态四根 fixture:dataDir 目录名带 .taiji 前缀(detectEnvironment 的
|
|
1834
|
+
* PI_CODING_AGENT_DIR 形态判据 `<*>/.taiji*\/agent` 可命中,托管判定走正态)。
|
|
1806
1835
|
* live=agent/sessions 与 default 同字面路径(default 去重)、legacy 独立非空、subagent 独立。
|
|
1807
1836
|
*/
|
|
1808
1837
|
async function buildFourRootFixture(): Promise<{
|
|
@@ -1810,7 +1839,7 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1810
1839
|
agentDir: string
|
|
1811
1840
|
signals: SessionReadSignals
|
|
1812
1841
|
}> {
|
|
1813
|
-
const dataDir = join(tmp, '.
|
|
1842
|
+
const dataDir = join(tmp, '.taiji-fixture')
|
|
1814
1843
|
const agentDir = join(dataDir, 'agent')
|
|
1815
1844
|
await writeJsonl(join(agentDir, 'sessions', SLUG, 'a.jsonl'), 'aaaaaaaa')
|
|
1816
1845
|
await writeJsonl(join(agentDir, 'sessions', SLUG, 'b.jsonl'), 'bbbbbbbb')
|
|
@@ -1823,9 +1852,9 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1823
1852
|
agentDir,
|
|
1824
1853
|
liveSessionDir: join(agentDir, 'sessions'),
|
|
1825
1854
|
env: {
|
|
1826
|
-
|
|
1855
|
+
TAIJI_AGENT_EXT_LOG: '1',
|
|
1827
1856
|
PI_CODING_AGENT_DIR: agentDir,
|
|
1828
|
-
|
|
1857
|
+
TAIJI_AGENT_DATA_DIR: dataDir,
|
|
1829
1858
|
},
|
|
1830
1859
|
},
|
|
1831
1860
|
}
|
|
@@ -1843,8 +1872,8 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1843
1872
|
const r = await handleSessionRead({ action: 'doctor' }, signals)
|
|
1844
1873
|
const text = r.content[0].text
|
|
1845
1874
|
|
|
1846
|
-
// 环境判定行:双信号合取 →
|
|
1847
|
-
expect(text).toContain('环境判定:
|
|
1875
|
+
// 环境判定行:双信号合取 → taiji(托管)+ 数据目录 + evidence 正态
|
|
1876
|
+
expect(text).toContain('环境判定:taiji(托管)')
|
|
1848
1877
|
expect(text).toContain(`数据目录:${dataDir}`)
|
|
1849
1878
|
expect(text).toContain('依据:')
|
|
1850
1879
|
expect(text).toContain(`PI_CODING_AGENT_DIR='${agentDir}' → 形态匹配`)
|
|
@@ -1887,7 +1916,7 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1887
1916
|
const { signals } = await buildFourRootFixture()
|
|
1888
1917
|
const positive = await handleSessionRead({ action: 'doctor' }, signals)
|
|
1889
1918
|
expect(positive.content[0].text).toContain(
|
|
1890
|
-
`告警:[legacy] 根 ${join(tmp, '.
|
|
1919
|
+
`告警:[legacy] 根 ${join(tmp, '.taiji-fixture', 'sessions')} 非空(1 文件)`,
|
|
1891
1920
|
)
|
|
1892
1921
|
|
|
1893
1922
|
// 反态:legacy 目录不存在
|
|
@@ -1908,43 +1937,6 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1908
1937
|
expect(deduped.content[0].text).toContain('已去重')
|
|
1909
1938
|
})
|
|
1910
1939
|
|
|
1911
|
-
it('独立 glob 残留探测:pi/ 含 agent|sessions 形态列出 + 迁移指引;pi.backup-v2-* 备份列出;基点 = dirname(agentDir)', async () => {
|
|
1912
|
-
const dataDir = join(tmp, 'data')
|
|
1913
|
-
const agentDir = join(dataDir, 'agent')
|
|
1914
|
-
await writeJsonl(join(agentDir, 'sessions', SLUG, 'a.jsonl'))
|
|
1915
|
-
// 未迁移旧布局 pi/(含 agent/ 形态)
|
|
1916
|
-
await mkdir(join(dataDir, 'pi', 'agent'), { recursive: true })
|
|
1917
|
-
await writeJsonl(join(dataDir, 'pi', 'agent', 'sessions', 'old.jsonl'), 'old-id')
|
|
1918
|
-
// 迁移备份(含 sessions/ 形态——备份即原 pi/ 改名)
|
|
1919
|
-
const backup = join(dataDir, 'pi.backup-v2-1725900000000')
|
|
1920
|
-
await mkdir(join(backup, 'sessions'), { recursive: true })
|
|
1921
|
-
await writeJsonl(join(backup, 'sessions', 'bak.jsonl'), 'bak-id')
|
|
1922
|
-
|
|
1923
|
-
const r = await handleSessionRead({ action: 'doctor' }, { agentDir })
|
|
1924
|
-
const text = r.content[0].text
|
|
1925
|
-
expect(text).toContain(`旧布局残留探测(基点 ${dataDir})`)
|
|
1926
|
-
expect(text).toContain(` - ${join(dataDir, 'pi')}(未迁移旧布局 pi/)`)
|
|
1927
|
-
expect(text).toContain(` - ${backup}(迁移备份 pi.backup-v2-*)`)
|
|
1928
|
-
// 同一迁移指引(§6.11:doctor 与 u14b 启动探测同指引)
|
|
1929
|
-
expect(text).toContain('👉 关闭应用后运行 scripts/migrate-pi-layout-v2.mjs 完成迁移。')
|
|
1930
|
-
|
|
1931
|
-
const d = r.details as DoctorDetails
|
|
1932
|
-
expect(d.globBase).toBe(dataDir)
|
|
1933
|
-
expect(d.leftovers.map((l) => l.kind).sort()).toEqual(['backup', 'unmigrated'])
|
|
1934
|
-
})
|
|
1935
|
-
|
|
1936
|
-
it('残留探测反态:pi/ 空壳(无 agent|sessions 子目录)不报——防纯 pi 宿主 ~/.pi/pi/ 误报(§6.11 v9.1)', async () => {
|
|
1937
|
-
const dataDir = join(tmp, 'data')
|
|
1938
|
-
const agentDir = join(dataDir, 'agent')
|
|
1939
|
-
await writeJsonl(join(agentDir, 'sessions', SLUG, 'a.jsonl'))
|
|
1940
|
-
// 纯 pi 宿主下任意来源的 pi/ 目录:只有无关子目录,无 agent/ 与 sessions/ 形态
|
|
1941
|
-
await mkdir(join(dataDir, 'pi', 'extensions'), { recursive: true })
|
|
1942
|
-
|
|
1943
|
-
const r = await handleSessionRead({ action: 'doctor' }, { agentDir })
|
|
1944
|
-
expect(r.content[0].text).not.toContain('旧布局残留')
|
|
1945
|
-
expect((r.details as DoctorDetails).leftovers).toEqual([])
|
|
1946
|
-
})
|
|
1947
|
-
|
|
1948
1940
|
it('subagent 根默认不扫(只列路径与可扫性);includeSubagents:true 才扫出文件数(§6.3)', async () => {
|
|
1949
1941
|
const { agentDir, signals } = await buildFourRootFixture()
|
|
1950
1942
|
|
|
@@ -1995,7 +1987,7 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
1995
1987
|
const r = await handleSessionRead({ action: 'doctor' }, { agentDir })
|
|
1996
1988
|
const text = r.content[0].text
|
|
1997
1989
|
expect(text).toContain('环境判定:standalone-pi · 发行形态:未知(不猜)')
|
|
1998
|
-
expect(text).toContain('
|
|
1990
|
+
expect(text).toContain('TAIJI_AGENT_EXT_LOG=<未设置> → 未命中')
|
|
1999
1991
|
expect(text).toContain('会话根(按优先级)')
|
|
2000
1992
|
expect(text).toContain('[default]')
|
|
2001
1993
|
expect(text).toContain(
|
|
@@ -2003,13 +1995,12 @@ describe('doctor action(u8:环境判定 + 根表 + 告警 + 残留 glob)',
|
|
|
2003
1995
|
)
|
|
2004
1996
|
})
|
|
2005
1997
|
|
|
2006
|
-
it('空 agentDir
|
|
1998
|
+
it('空 agentDir 防御:无根表、诊断「无候选根」(不扫 cwd 相对路径)', async () => {
|
|
2007
1999
|
const r = await handleSessionRead({ action: 'doctor' }, { agentDir: '' })
|
|
2008
2000
|
const text = r.content[0].text
|
|
2009
2001
|
expect(text).toContain('诊断:无候选根')
|
|
2010
2002
|
expect(text).not.toContain('[default]')
|
|
2011
2003
|
expect((r.details as DoctorDetails).roots).toEqual([])
|
|
2012
|
-
expect((r.details as DoctorDetails).leftovers).toEqual([])
|
|
2013
2004
|
})
|
|
2014
2005
|
})
|
|
2015
2006
|
|
|
@@ -2641,7 +2632,7 @@ describe('E1 find 单次根解析(探针 P1:resolveSessionRoots 恰 1 次)
|
|
|
2641
2632
|
// ============================================================
|
|
2642
2633
|
describe('u11 metadataProvider 注入 + TTL 缓存(fixture,§6.6)', () => {
|
|
2643
2634
|
let tmp: string
|
|
2644
|
-
/** 平铺 main 根(
|
|
2635
|
+
/** 平铺 main 根(taiji 形态),同时作 liveSessionDir(与 [default] 根同字面路径) */
|
|
2645
2636
|
let flatMain: string
|
|
2646
2637
|
|
|
2647
2638
|
async function writeSession(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
2
|
import { extractToolCalls, formatToolCallSummary } from '../core/toolcall.js'
|
|
3
|
-
import type { Entry } from '
|
|
3
|
+
import type { Entry } from '@zhushanwen/session-core'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* D1 映射表(design §3.3)确定性测试:formatToolCallSummary 12 个 switch 分支
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
2
|
import { buildTreeView } from '../core/tree.js'
|
|
3
|
-
import type { Entry } from '
|
|
3
|
+
import type { Entry } from '@zhushanwen/session-core'
|
|
4
4
|
|
|
5
5
|
/** 构造最小 Entry(tree.ts 只消费 type/id/parentId,其余字段省略) */
|
|
6
6
|
function e(id: string, parentId: string | null): Entry {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
2
|
import { segmentTurns } from '../core/turns.js'
|
|
3
|
-
import type
|
|
4
|
-
import { parseSessionFile } from '../core/parser.js'
|
|
3
|
+
import { parseSessionFile, type Entry } from '@zhushanwen/session-core'
|
|
5
4
|
import { buildTreeView } from '../core/tree.js'
|
|
6
5
|
import { REAL_SESSION, HAS_REAL_SESSION } from './real-data.js'
|
|
7
6
|
|