@ai-devkit/agent-manager 0.41.0 → 0.42.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.
Files changed (101) hide show
  1. package/dist/AgentManager.d.ts.map +1 -1
  2. package/dist/AgentManager.js +25 -9
  3. package/dist/AgentManager.js.map +1 -1
  4. package/dist/__tests__/fixtures.test.js.map +1 -1
  5. package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -1
  6. package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -1
  7. package/dist/__tests__/harnesses/muse/MuseAdapter.test.js +247 -0
  8. package/dist/__tests__/harnesses/muse/MuseAdapter.test.js.map +1 -0
  9. package/dist/__tests__/harnesses/muse/MuseAgentMapper.test.js +81 -0
  10. package/dist/__tests__/harnesses/muse/MuseAgentMapper.test.js.map +1 -0
  11. package/dist/__tests__/harnesses/muse/MuseSessionLocator.test.js +185 -0
  12. package/dist/__tests__/harnesses/muse/MuseSessionLocator.test.js.map +1 -0
  13. package/dist/__tests__/harnesses/muse/MuseSessionParser.test.js +328 -0
  14. package/dist/__tests__/harnesses/muse/MuseSessionParser.test.js.map +1 -0
  15. package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js.map +1 -1
  16. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js +42 -1
  17. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -1
  18. package/dist/__tests__/harnesses/runtimeProfiles.test.js +12 -0
  19. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -1
  20. package/dist/__tests__/utils/process.test.js +71 -1
  21. package/dist/__tests__/utils/process.test.js.map +1 -1
  22. package/dist/adapters/AgentAdapter.d.ts +8 -1
  23. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  24. package/dist/adapters/AgentAdapter.js +2 -1
  25. package/dist/adapters/AgentAdapter.js.map +1 -1
  26. package/dist/fixtures/capture.d.ts.map +1 -1
  27. package/dist/fixtures/capture.js +5 -4
  28. package/dist/fixtures/capture.js.map +1 -1
  29. package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -1
  30. package/dist/harnesses/devin/DevinAdapter.js.map +1 -1
  31. package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -1
  32. package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -1
  33. package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -1
  34. package/dist/harnesses/devin/DevinSessionParser.js.map +1 -1
  35. package/dist/harnesses/index.d.ts.map +1 -1
  36. package/dist/harnesses/index.js +3 -1
  37. package/dist/harnesses/index.js.map +1 -1
  38. package/dist/harnesses/muse/MuseAdapter.d.ts +33 -0
  39. package/dist/harnesses/muse/MuseAdapter.d.ts.map +1 -0
  40. package/dist/harnesses/muse/MuseAdapter.js +122 -0
  41. package/dist/harnesses/muse/MuseAdapter.js.map +1 -0
  42. package/dist/harnesses/muse/MuseAgentMapper.d.ts +15 -0
  43. package/dist/harnesses/muse/MuseAgentMapper.d.ts.map +1 -0
  44. package/dist/harnesses/muse/MuseAgentMapper.js +29 -0
  45. package/dist/harnesses/muse/MuseAgentMapper.js.map +1 -0
  46. package/dist/harnesses/muse/MuseSessionLocator.d.ts +61 -0
  47. package/dist/harnesses/muse/MuseSessionLocator.d.ts.map +1 -0
  48. package/dist/harnesses/muse/MuseSessionLocator.js +233 -0
  49. package/dist/harnesses/muse/MuseSessionLocator.js.map +1 -0
  50. package/dist/harnesses/muse/MuseSessionParser.d.ts +77 -0
  51. package/dist/harnesses/muse/MuseSessionParser.d.ts.map +1 -0
  52. package/dist/harnesses/muse/MuseSessionParser.js +350 -0
  53. package/dist/harnesses/muse/MuseSessionParser.js.map +1 -0
  54. package/dist/harnesses/muse/readiness.d.ts +3 -0
  55. package/dist/harnesses/muse/readiness.d.ts.map +1 -0
  56. package/dist/harnesses/muse/readiness.js +37 -0
  57. package/dist/harnesses/muse/readiness.js.map +1 -0
  58. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -1
  59. package/dist/harnesses/readiness/AgentReadiness.js +3 -1
  60. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -1
  61. package/dist/harnesses/readiness/types.d.ts +1 -1
  62. package/dist/harnesses/readiness/types.d.ts.map +1 -1
  63. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -1
  64. package/dist/harnesses/runtimeProfiles.js +2 -1
  65. package/dist/harnesses/runtimeProfiles.js.map +1 -1
  66. package/dist/harnesses/shared.d.ts +1 -1
  67. package/dist/harnesses/shared.d.ts.map +1 -1
  68. package/dist/harnesses/shared.js +6 -5
  69. package/dist/harnesses/shared.js.map +1 -1
  70. package/dist/utils/process.d.ts +23 -1
  71. package/dist/utils/process.d.ts.map +1 -1
  72. package/dist/utils/process.js +44 -8
  73. package/dist/utils/process.js.map +1 -1
  74. package/package.json +1 -1
  75. package/src/AgentManager.ts +34 -8
  76. package/src/__tests__/fixtures.test.ts +15 -17
  77. package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +1 -3
  78. package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +3 -9
  79. package/src/__tests__/harnesses/muse/MuseAdapter.test.ts +197 -0
  80. package/src/__tests__/harnesses/muse/MuseAgentMapper.test.ts +83 -0
  81. package/src/__tests__/harnesses/muse/MuseSessionLocator.test.ts +177 -0
  82. package/src/__tests__/harnesses/muse/MuseSessionParser.test.ts +279 -0
  83. package/src/__tests__/harnesses/opencode/OpenCodeSessionParser.test.ts +3 -2
  84. package/src/__tests__/harnesses/readiness/AgentReadiness.test.ts +36 -0
  85. package/src/__tests__/harnesses/runtimeProfiles.test.ts +13 -0
  86. package/src/__tests__/utils/process.test.ts +30 -0
  87. package/src/adapters/AgentAdapter.ts +9 -0
  88. package/src/fixtures/capture.ts +32 -17
  89. package/src/harnesses/devin/DevinAdapter.ts +3 -15
  90. package/src/harnesses/devin/DevinAgentMapper.ts +1 -5
  91. package/src/harnesses/devin/DevinSessionParser.ts +3 -12
  92. package/src/harnesses/index.ts +2 -0
  93. package/src/harnesses/muse/MuseAdapter.ts +157 -0
  94. package/src/harnesses/muse/MuseAgentMapper.ts +33 -0
  95. package/src/harnesses/muse/MuseSessionLocator.ts +286 -0
  96. package/src/harnesses/muse/MuseSessionParser.ts +435 -0
  97. package/src/harnesses/muse/readiness.ts +38 -0
  98. package/src/harnesses/readiness/AgentReadiness.ts +2 -0
  99. package/src/harnesses/runtimeProfiles.ts +1 -0
  100. package/src/harnesses/shared.ts +10 -5
  101. package/src/utils/process.ts +61 -9
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Tests for harnesses/muse/MuseAdapter.ts — detection through the real
3
+ * locator/parser/mapper against a fake Muse home (no mocks).
4
+ */ import * as fs from "fs";
5
+ import * as os from "os";
6
+ import * as path from "path";
7
+ import { AgentStatus } from "../../../adapters/AgentAdapter.js";
8
+ import { MuseAdapter } from "../../../harnesses/muse/MuseAdapter.js";
9
+ const SID = "01a12618-d918-7b63-91c8-4e896326eb1a";
10
+ const PROJECT = "codeaholicguy/Code/ai-devkit";
11
+ function frame(inner) {
12
+ return JSON.stringify(inner);
13
+ }
14
+ function intent(text, recordedAtUs) {
15
+ return {
16
+ schema_version: 1,
17
+ stream: {
18
+ kind: "session",
19
+ id: SID
20
+ },
21
+ sequence: 2,
22
+ recorded_at: recordedAtUs,
23
+ record_type: "event",
24
+ payload_type: "runtime.user_intent.accepted",
25
+ payload: {
26
+ refill_blocks: [
27
+ {
28
+ kind: "text",
29
+ text
30
+ }
31
+ ]
32
+ }
33
+ };
34
+ }
35
+ describe("MuseAdapter", ()=>{
36
+ let home;
37
+ let adapter;
38
+ beforeEach(()=>{
39
+ home = fs.mkdtempSync(path.join(os.tmpdir(), "muse-adapter-test-"));
40
+ adapter = new MuseAdapter({
41
+ homeDir: home
42
+ });
43
+ });
44
+ afterEach(()=>{
45
+ fs.rmSync(home, {
46
+ recursive: true,
47
+ force: true
48
+ });
49
+ });
50
+ function writeTranscript(lines) {
51
+ const dir = path.join(home, ".local", "share", "muse", "sessions", "2026/10/10", SID);
52
+ fs.mkdirSync(dir, {
53
+ recursive: true
54
+ });
55
+ const filePath = path.join(dir, "session.jsonl");
56
+ fs.writeFileSync(filePath, lines.join("\n"));
57
+ return filePath;
58
+ }
59
+ function writeRuntimeFile(pid) {
60
+ const dir = path.join(home, ".local", "share", "muse", "runtime", "muse", "sessions");
61
+ fs.mkdirSync(dir, {
62
+ recursive: true
63
+ });
64
+ fs.writeFileSync(path.join(dir, `${SID}.json`), JSON.stringify({
65
+ schema_version: 1,
66
+ session_id: SID,
67
+ process_generation_hint: `pid=${pid}`
68
+ }));
69
+ }
70
+ function proc(overrides = {}) {
71
+ return {
72
+ pid: 16174,
73
+ command: "/Users/tester/.local/bin/muse-bin-1.4.4-R5419.1",
74
+ cwd: `/Users/tester/${PROJECT}`,
75
+ tty: "ttys001",
76
+ startTime: new Date(),
77
+ ...overrides
78
+ };
79
+ }
80
+ it("handles versioned launcher commands and rejects others", ()=>{
81
+ expect(adapter.canHandle(proc())).toBe(true);
82
+ expect(adapter.canHandle(proc({
83
+ command: "/usr/local/bin/muse"
84
+ }))).toBe(true);
85
+ expect(adapter.canHandle(proc({
86
+ command: "/usr/local/bin/claude"
87
+ }))).toBe(false);
88
+ expect(adapter.canHandle(proc({
89
+ command: "/usr/bin/museums"
90
+ }))).toBe(false);
91
+ });
92
+ it("detects a live session through the runtime file", async ()=>{
93
+ const filePath = writeTranscript([
94
+ frame({
95
+ schema_version: 1,
96
+ stream: {
97
+ kind: "session",
98
+ id: SID
99
+ },
100
+ sequence: 1,
101
+ recorded_at: 1791640525332173,
102
+ record_type: "event",
103
+ payload_type: "runtime.session.metadata",
104
+ payload: {
105
+ kind: "metadata",
106
+ record: {
107
+ workspace_root: `/Users/tester/${PROJECT}`
108
+ }
109
+ }
110
+ }),
111
+ frame(intent("hello", 1791640525332174))
112
+ ]);
113
+ writeRuntimeFile(16174);
114
+ const start = new Date(fs.statSync(filePath).birthtimeMs);
115
+ const agents = await adapter.detectAgents({
116
+ processes: [
117
+ proc({
118
+ startTime: start
119
+ })
120
+ ]
121
+ });
122
+ expect(agents).toHaveLength(1);
123
+ expect(agents[0]).toMatchObject({
124
+ type: "muse",
125
+ pid: 16174,
126
+ sessionId: SID,
127
+ projectPath: `/Users/tester/${PROJECT}`,
128
+ summary: "hello"
129
+ });
130
+ expect(agents[0].sessionFilePath).toBe(filePath);
131
+ });
132
+ it("matches a process by cwd and birthtime without a runtime file", async ()=>{
133
+ const filePath = writeTranscript([
134
+ frame({
135
+ schema_version: 1,
136
+ stream: {
137
+ kind: "session",
138
+ id: SID
139
+ },
140
+ sequence: 1,
141
+ recorded_at: 1791640525332173,
142
+ record_type: "event",
143
+ payload_type: "runtime.session.metadata",
144
+ payload: {
145
+ kind: "metadata",
146
+ record: {
147
+ workspace_root: `/Users/tester/${PROJECT}`
148
+ }
149
+ }
150
+ }),
151
+ frame(intent("legacy hello", 1791640525332174))
152
+ ]);
153
+ const start = new Date(fs.statSync(filePath).birthtimeMs);
154
+ const agents = await adapter.detectAgents({
155
+ processes: [
156
+ proc({
157
+ pid: 7777,
158
+ startTime: start
159
+ })
160
+ ]
161
+ });
162
+ expect(agents).toHaveLength(1);
163
+ expect(agents[0]).toMatchObject({
164
+ type: "muse",
165
+ pid: 7777,
166
+ sessionId: SID,
167
+ summary: "legacy hello"
168
+ });
169
+ });
170
+ it("skips transcripts with no conversation signal in history", async ()=>{
171
+ writeTranscript([
172
+ frame({
173
+ schema_version: 1,
174
+ stream: {
175
+ kind: "session",
176
+ id: SID
177
+ },
178
+ sequence: 1,
179
+ recorded_at: 1791640525332173,
180
+ record_type: "event",
181
+ payload_type: "runtime.session.metadata",
182
+ payload: {
183
+ kind: "metadata",
184
+ record: {
185
+ workspace_root: "/Users/tester/empty"
186
+ }
187
+ }
188
+ })
189
+ ]);
190
+ expect(await adapter.listSessions()).toEqual([]);
191
+ });
192
+ it("reports an unmatched process as a running placeholder", async ()=>{
193
+ const agents = await adapter.detectAgents({
194
+ processes: [
195
+ proc({
196
+ pid: 4242
197
+ })
198
+ ]
199
+ });
200
+ expect(agents).toHaveLength(1);
201
+ expect(agents[0]).toMatchObject({
202
+ type: "muse",
203
+ status: AgentStatus.RUNNING,
204
+ sessionId: "pid-4242"
205
+ });
206
+ });
207
+ it("lists historical sessions with strict cwd filtering", async ()=>{
208
+ writeTranscript([
209
+ frame({
210
+ schema_version: 1,
211
+ stream: {
212
+ kind: "session",
213
+ id: SID
214
+ },
215
+ sequence: 1,
216
+ recorded_at: 1791640525332173,
217
+ record_type: "event",
218
+ payload_type: "runtime.session.metadata",
219
+ payload: {
220
+ kind: "metadata",
221
+ record: {
222
+ workspace_root: `/Users/tester/${PROJECT}`
223
+ }
224
+ }
225
+ }),
226
+ frame(intent("hello", 1791640525332174))
227
+ ]);
228
+ const all = await adapter.listSessions();
229
+ expect(all).toHaveLength(1);
230
+ expect(all[0]).toMatchObject({
231
+ type: "muse",
232
+ sessionId: SID,
233
+ cwd: `/Users/tester/${PROJECT}`,
234
+ firstUserMessage: "hello"
235
+ });
236
+ expect(await adapter.listSessions({
237
+ cwd: "/elsewhere"
238
+ })).toEqual([]);
239
+ const found = await adapter.findSessionsById(SID);
240
+ expect(found.map((s)=>s.sessionId)).toEqual([
241
+ SID
242
+ ]);
243
+ expect(await adapter.findSessionsById("00000000-0000-0000-0000-000000000000")).toEqual([]);
244
+ });
245
+ });
246
+
247
+ //# sourceMappingURL=MuseAdapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/__tests__/harnesses/muse/MuseAdapter.test.ts"],"sourcesContent":["/**\n * Tests for harnesses/muse/MuseAdapter.ts — detection through the real\n * locator/parser/mapper against a fake Muse home (no mocks).\n */\n\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport { AgentStatus } from \"../../../adapters/AgentAdapter.js\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { MuseAdapter } from \"../../../harnesses/muse/MuseAdapter.js\";\n\nconst SID = \"01a12618-d918-7b63-91c8-4e896326eb1a\";\nconst PROJECT = \"codeaholicguy/Code/ai-devkit\";\n\nfunction frame(inner: unknown): string {\n return JSON.stringify(inner);\n}\n\nfunction intent(text: string, recordedAtUs: number): unknown {\n return {\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 2,\n recorded_at: recordedAtUs,\n record_type: \"event\",\n payload_type: \"runtime.user_intent.accepted\",\n payload: { refill_blocks: [{ kind: \"text\", text }] },\n };\n}\n\ndescribe(\"MuseAdapter\", () => {\n let home: string;\n let adapter: MuseAdapter;\n\n beforeEach(() => {\n home = fs.mkdtempSync(path.join(os.tmpdir(), \"muse-adapter-test-\"));\n adapter = new MuseAdapter({ homeDir: home });\n });\n\n afterEach(() => {\n fs.rmSync(home, { recursive: true, force: true });\n });\n\n function writeTranscript(lines: string[]): string {\n const dir = path.join(home, \".local\", \"share\", \"muse\", \"sessions\", \"2026/10/10\", SID);\n fs.mkdirSync(dir, { recursive: true });\n const filePath = path.join(dir, \"session.jsonl\");\n fs.writeFileSync(filePath, lines.join(\"\\n\"));\n return filePath;\n }\n\n function writeRuntimeFile(pid: number): void {\n const dir = path.join(home, \".local\", \"share\", \"muse\", \"runtime\", \"muse\", \"sessions\");\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(\n path.join(dir, `${SID}.json`),\n JSON.stringify({ schema_version: 1, session_id: SID, process_generation_hint: `pid=${pid}` }),\n );\n }\n\n function proc(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 16174,\n command: \"/Users/tester/.local/bin/muse-bin-1.4.4-R5419.1\",\n cwd: `/Users/tester/${PROJECT}`,\n tty: \"ttys001\",\n startTime: new Date(),\n ...overrides,\n };\n }\n\n it(\"handles versioned launcher commands and rejects others\", () => {\n expect(adapter.canHandle(proc())).toBe(true);\n expect(adapter.canHandle(proc({ command: \"/usr/local/bin/muse\" }))).toBe(true);\n expect(adapter.canHandle(proc({ command: \"/usr/local/bin/claude\" }))).toBe(false);\n expect(adapter.canHandle(proc({ command: \"/usr/bin/museums\" }))).toBe(false);\n });\n\n it(\"detects a live session through the runtime file\", async () => {\n const filePath = writeTranscript([\n frame({\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 1,\n recorded_at: 1791640525332173,\n record_type: \"event\",\n payload_type: \"runtime.session.metadata\",\n payload: {\n kind: \"metadata\",\n record: { workspace_root: `/Users/tester/${PROJECT}` },\n },\n }),\n frame(intent(\"hello\", 1791640525332174)),\n ]);\n writeRuntimeFile(16174);\n const start = new Date(fs.statSync(filePath).birthtimeMs);\n\n const agents = await adapter.detectAgents({ processes: [proc({ startTime: start })] });\n expect(agents).toHaveLength(1);\n expect(agents[0]).toMatchObject({\n type: \"muse\",\n pid: 16174,\n sessionId: SID,\n projectPath: `/Users/tester/${PROJECT}`,\n summary: \"hello\",\n });\n expect(agents[0].sessionFilePath).toBe(filePath);\n });\n\n it(\"matches a process by cwd and birthtime without a runtime file\", async () => {\n const filePath = writeTranscript([\n frame({\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 1,\n recorded_at: 1791640525332173,\n record_type: \"event\",\n payload_type: \"runtime.session.metadata\",\n payload: {\n kind: \"metadata\",\n record: { workspace_root: `/Users/tester/${PROJECT}` },\n },\n }),\n frame(intent(\"legacy hello\", 1791640525332174)),\n ]);\n const start = new Date(fs.statSync(filePath).birthtimeMs);\n\n const agents = await adapter.detectAgents({\n processes: [proc({ pid: 7777, startTime: start })],\n });\n expect(agents).toHaveLength(1);\n expect(agents[0]).toMatchObject({\n type: \"muse\",\n pid: 7777,\n sessionId: SID,\n summary: \"legacy hello\",\n });\n });\n\n it(\"skips transcripts with no conversation signal in history\", async () => {\n writeTranscript([\n frame({\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 1,\n recorded_at: 1791640525332173,\n record_type: \"event\",\n payload_type: \"runtime.session.metadata\",\n payload: { kind: \"metadata\", record: { workspace_root: \"/Users/tester/empty\" } },\n }),\n ]);\n expect(await adapter.listSessions()).toEqual([]);\n });\n\n it(\"reports an unmatched process as a running placeholder\", async () => {\n const agents = await adapter.detectAgents({ processes: [proc({ pid: 4242 })] });\n expect(agents).toHaveLength(1);\n expect(agents[0]).toMatchObject({\n type: \"muse\",\n status: AgentStatus.RUNNING,\n sessionId: \"pid-4242\",\n });\n });\n\n it(\"lists historical sessions with strict cwd filtering\", async () => {\n writeTranscript([\n frame({\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 1,\n recorded_at: 1791640525332173,\n record_type: \"event\",\n payload_type: \"runtime.session.metadata\",\n payload: {\n kind: \"metadata\",\n record: { workspace_root: `/Users/tester/${PROJECT}` },\n },\n }),\n frame(intent(\"hello\", 1791640525332174)),\n ]);\n\n const all = await adapter.listSessions();\n expect(all).toHaveLength(1);\n expect(all[0]).toMatchObject({\n type: \"muse\",\n sessionId: SID,\n cwd: `/Users/tester/${PROJECT}`,\n firstUserMessage: \"hello\",\n });\n\n expect(await adapter.listSessions({ cwd: \"/elsewhere\" })).toEqual([]);\n const found = await adapter.findSessionsById(SID);\n expect(found.map((s) => s.sessionId)).toEqual([SID]);\n expect(await adapter.findSessionsById(\"00000000-0000-0000-0000-000000000000\")).toEqual([]);\n });\n});\n"],"names":["fs","os","path","AgentStatus","MuseAdapter","SID","PROJECT","frame","inner","JSON","stringify","intent","text","recordedAtUs","schema_version","stream","kind","id","sequence","recorded_at","record_type","payload_type","payload","refill_blocks","describe","home","adapter","beforeEach","mkdtempSync","join","tmpdir","homeDir","afterEach","rmSync","recursive","force","writeTranscript","lines","dir","mkdirSync","filePath","writeFileSync","writeRuntimeFile","pid","session_id","process_generation_hint","proc","overrides","command","cwd","tty","startTime","Date","it","expect","canHandle","toBe","record","workspace_root","start","statSync","birthtimeMs","agents","detectAgents","processes","toHaveLength","toMatchObject","type","sessionId","projectPath","summary","sessionFilePath","listSessions","toEqual","status","RUNNING","all","firstUserMessage","found","findSessionsById","map","s"],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import { AgentStatus } from "../../../adapters/AgentAdapter.js";
2
+ import { MuseAgentMapper } from "../../../harnesses/muse/MuseAgentMapper.js";
3
+ const SID = "01a12618-d918-7b63-91c8-4e896326eb1a";
4
+ function session(overrides = {}) {
5
+ return {
6
+ sessionId: SID,
7
+ projectPath: "/Users/tester/proj",
8
+ sessionStart: new Date("2026-10-10T13:55:25.332Z"),
9
+ lastActive: new Date("2026-10-10T14:00:00.000Z"),
10
+ lastSignal: "assistant",
11
+ lastUserMessage: "what is this repo about",
12
+ firstUserMessage: "what is this repo about",
13
+ ...overrides
14
+ };
15
+ }
16
+ function sessionFile() {
17
+ return {
18
+ sessionId: SID,
19
+ filePath: `/home/tester/.local/share/muse/sessions/2026/10/10/${SID}/session.jsonl`,
20
+ projectDir: `/home/tester/.local/share/muse/sessions/2026/10/10/${SID}`,
21
+ birthtimeMs: 1791640525332,
22
+ resolvedCwd: "/Users/tester/proj"
23
+ };
24
+ }
25
+ function proc() {
26
+ return {
27
+ pid: 16174,
28
+ command: "/Users/tester/.local/bin/muse-bin-1.4.4-R5419.1",
29
+ cwd: "/Users/tester/proj",
30
+ tty: "ttys001"
31
+ };
32
+ }
33
+ describe("MuseAgentMapper", ()=>{
34
+ const mapper = new MuseAgentMapper();
35
+ it("maps a session to a project-named agent", ()=>{
36
+ const agent = mapper.mapSessionToAgent({
37
+ session: session(),
38
+ processInfo: proc(),
39
+ sessionFile: sessionFile()
40
+ });
41
+ expect(agent).toMatchObject({
42
+ name: "proj-16174",
43
+ type: "muse",
44
+ status: AgentStatus.WAITING,
45
+ summary: "what is this repo about",
46
+ pid: 16174,
47
+ projectPath: "/Users/tester/proj",
48
+ sessionId: SID
49
+ });
50
+ expect(agent.lastActive).toEqual(new Date("2026-10-10T14:00:00.000Z"));
51
+ expect(agent.sessionFilePath).toContain("session.jsonl");
52
+ });
53
+ it("falls back to a started summary and process cwd without workspace root", ()=>{
54
+ const agent = mapper.mapSessionToAgent({
55
+ session: session({
56
+ projectPath: "",
57
+ lastUserMessage: undefined,
58
+ lastSignal: undefined
59
+ }),
60
+ processInfo: proc(),
61
+ sessionFile: {
62
+ ...sessionFile(),
63
+ resolvedCwd: ""
64
+ }
65
+ });
66
+ expect(agent.summary).toBe("Session started");
67
+ expect(agent.projectPath).toBe("/Users/tester/proj");
68
+ expect(agent.status).toBe(AgentStatus.UNKNOWN);
69
+ });
70
+ it("maps an unmatched process to a running placeholder", ()=>{
71
+ const agent = mapper.mapProcessOnlyAgent(proc());
72
+ expect(agent).toMatchObject({
73
+ type: "muse",
74
+ status: AgentStatus.RUNNING,
75
+ pid: 16174,
76
+ sessionId: "pid-16174"
77
+ });
78
+ });
79
+ });
80
+
81
+ //# sourceMappingURL=MuseAgentMapper.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/__tests__/harnesses/muse/MuseAgentMapper.test.ts"],"sourcesContent":["import { AgentStatus } from \"../../../adapters/AgentAdapter.js\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport type { SessionFile } from \"../../../utils/session.js\";\nimport { MuseAgentMapper } from \"../../../harnesses/muse/MuseAgentMapper.js\";\nimport type { MuseSession } from \"../../../harnesses/muse/MuseSessionParser.js\";\n\nconst SID = \"01a12618-d918-7b63-91c8-4e896326eb1a\";\n\nfunction session(overrides: Partial<MuseSession> = {}): MuseSession {\n return {\n sessionId: SID,\n projectPath: \"/Users/tester/proj\",\n sessionStart: new Date(\"2026-10-10T13:55:25.332Z\"),\n lastActive: new Date(\"2026-10-10T14:00:00.000Z\"),\n lastSignal: \"assistant\",\n lastUserMessage: \"what is this repo about\",\n firstUserMessage: \"what is this repo about\",\n ...overrides,\n };\n}\n\nfunction sessionFile(): SessionFile {\n return {\n sessionId: SID,\n filePath: `/home/tester/.local/share/muse/sessions/2026/10/10/${SID}/session.jsonl`,\n projectDir: `/home/tester/.local/share/muse/sessions/2026/10/10/${SID}`,\n birthtimeMs: 1791640525332,\n resolvedCwd: \"/Users/tester/proj\",\n };\n}\n\nfunction proc(): ProcessInfo {\n return {\n pid: 16174,\n command: \"/Users/tester/.local/bin/muse-bin-1.4.4-R5419.1\",\n cwd: \"/Users/tester/proj\",\n tty: \"ttys001\",\n };\n}\n\ndescribe(\"MuseAgentMapper\", () => {\n const mapper = new MuseAgentMapper();\n\n it(\"maps a session to a project-named agent\", () => {\n const agent = mapper.mapSessionToAgent({\n session: session(),\n processInfo: proc(),\n sessionFile: sessionFile(),\n });\n expect(agent).toMatchObject({\n name: \"proj-16174\",\n type: \"muse\",\n status: AgentStatus.WAITING,\n summary: \"what is this repo about\",\n pid: 16174,\n projectPath: \"/Users/tester/proj\",\n sessionId: SID,\n });\n expect(agent.lastActive).toEqual(new Date(\"2026-10-10T14:00:00.000Z\"));\n expect(agent.sessionFilePath).toContain(\"session.jsonl\");\n });\n\n it(\"falls back to a started summary and process cwd without workspace root\", () => {\n const agent = mapper.mapSessionToAgent({\n session: session({ projectPath: \"\", lastUserMessage: undefined, lastSignal: undefined }),\n processInfo: proc(),\n sessionFile: { ...sessionFile(), resolvedCwd: \"\" },\n });\n expect(agent.summary).toBe(\"Session started\");\n expect(agent.projectPath).toBe(\"/Users/tester/proj\");\n expect(agent.status).toBe(AgentStatus.UNKNOWN);\n });\n\n it(\"maps an unmatched process to a running placeholder\", () => {\n const agent = mapper.mapProcessOnlyAgent(proc());\n expect(agent).toMatchObject({\n type: \"muse\",\n status: AgentStatus.RUNNING,\n pid: 16174,\n sessionId: \"pid-16174\",\n });\n });\n});\n"],"names":["AgentStatus","MuseAgentMapper","SID","session","overrides","sessionId","projectPath","sessionStart","Date","lastActive","lastSignal","lastUserMessage","firstUserMessage","sessionFile","filePath","projectDir","birthtimeMs","resolvedCwd","proc","pid","command","cwd","tty","describe","mapper","it","agent","mapSessionToAgent","processInfo","expect","toMatchObject","name","type","status","WAITING","summary","toEqual","sessionFilePath","toContain","undefined","toBe","UNKNOWN","mapProcessOnlyAgent","RUNNING"],"mappings":"AAAA,SAASA,WAAW,QAAQ,oCAAoC;AAGhE,SAASC,eAAe,QAAQ,6CAA6C;AAG7E,MAAMC,MAAM;AAEZ,SAASC,QAAQC,YAAkC,CAAC,CAAC;IACnD,OAAO;QACLC,WAAWH;QACXI,aAAa;QACbC,cAAc,IAAIC,KAAK;QACvBC,YAAY,IAAID,KAAK;QACrBE,YAAY;QACZC,iBAAiB;QACjBC,kBAAkB;QAClB,GAAGR,SAAS;IACd;AACF;AAEA,SAASS;IACP,OAAO;QACLR,WAAWH;QACXY,UAAU,CAAC,mDAAmD,EAAEZ,IAAI,cAAc,CAAC;QACnFa,YAAY,CAAC,mDAAmD,EAAEb,KAAK;QACvEc,aAAa;QACbC,aAAa;IACf;AACF;AAEA,SAASC;IACP,OAAO;QACLC,KAAK;QACLC,SAAS;QACTC,KAAK;QACLC,KAAK;IACP;AACF;AAEAC,SAAS,mBAAmB;IAC1B,MAAMC,SAAS,IAAIvB;IAEnBwB,GAAG,2CAA2C;QAC5C,MAAMC,QAAQF,OAAOG,iBAAiB,CAAC;YACrCxB,SAASA;YACTyB,aAAaV;YACbL,aAAaA;QACf;QACAgB,OAAOH,OAAOI,aAAa,CAAC;YAC1BC,MAAM;YACNC,MAAM;YACNC,QAAQjC,YAAYkC,OAAO;YAC3BC,SAAS;YACThB,KAAK;YACLb,aAAa;YACbD,WAAWH;QACb;QACA2B,OAAOH,MAAMjB,UAAU,EAAE2B,OAAO,CAAC,IAAI5B,KAAK;QAC1CqB,OAAOH,MAAMW,eAAe,EAAEC,SAAS,CAAC;IAC1C;IAEAb,GAAG,0EAA0E;QAC3E,MAAMC,QAAQF,OAAOG,iBAAiB,CAAC;YACrCxB,SAASA,QAAQ;gBAAEG,aAAa;gBAAIK,iBAAiB4B;gBAAW7B,YAAY6B;YAAU;YACtFX,aAAaV;YACbL,aAAa;gBAAE,GAAGA,aAAa;gBAAEI,aAAa;YAAG;QACnD;QACAY,OAAOH,MAAMS,OAAO,EAAEK,IAAI,CAAC;QAC3BX,OAAOH,MAAMpB,WAAW,EAAEkC,IAAI,CAAC;QAC/BX,OAAOH,MAAMO,MAAM,EAAEO,IAAI,CAACxC,YAAYyC,OAAO;IAC/C;IAEAhB,GAAG,sDAAsD;QACvD,MAAMC,QAAQF,OAAOkB,mBAAmB,CAACxB;QACzCW,OAAOH,OAAOI,aAAa,CAAC;YAC1BE,MAAM;YACNC,QAAQjC,YAAY2C,OAAO;YAC3BxB,KAAK;YACLd,WAAW;QACb;IACF;AACF"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Tests for harnesses/muse/MuseSessionLocator.ts — runtime-file matching,
3
+ * dated-archive discovery, and session lookup by id.
4
+ */ import * as fs from "fs";
5
+ import * as os from "os";
6
+ import * as path from "path";
7
+ import { MuseSessionLocator } from "../../../harnesses/muse/MuseSessionLocator.js";
8
+ const SID = "01a12618-d918-7b63-91c8-4e896326eb1a";
9
+ const OTHER_SID = "2288dbd2-d703-444d-afce-59e40a8ad8b1";
10
+ function frame(inner) {
11
+ return JSON.stringify(inner);
12
+ }
13
+ function intent(text, recordedAtUs) {
14
+ return {
15
+ schema_version: 1,
16
+ stream: {
17
+ kind: "session",
18
+ id: SID
19
+ },
20
+ sequence: 2,
21
+ recorded_at: recordedAtUs,
22
+ record_type: "event",
23
+ payload_type: "runtime.user_intent.accepted",
24
+ payload: {
25
+ refill_blocks: [
26
+ {
27
+ kind: "text",
28
+ text
29
+ }
30
+ ]
31
+ }
32
+ };
33
+ }
34
+ function metadata(workspaceRoot, recordedAtUs) {
35
+ return {
36
+ schema_version: 1,
37
+ stream: {
38
+ kind: "session",
39
+ id: SID
40
+ },
41
+ sequence: 1,
42
+ recorded_at: recordedAtUs,
43
+ record_type: "event",
44
+ payload_type: "runtime.session.metadata",
45
+ payload: {
46
+ kind: "metadata",
47
+ record: {
48
+ workspace_root: workspaceRoot
49
+ }
50
+ }
51
+ };
52
+ }
53
+ function proc(pid, cwd, startTime) {
54
+ return {
55
+ pid,
56
+ command: `/Users/tester/.local/bin/muse-bin-1.4.4-R5419.1`,
57
+ cwd,
58
+ tty: "ttys001",
59
+ startTime
60
+ };
61
+ }
62
+ describe("MuseSessionLocator", ()=>{
63
+ let home;
64
+ let locator;
65
+ beforeEach(()=>{
66
+ home = fs.mkdtempSync(path.join(os.tmpdir(), "muse-locator-test-"));
67
+ locator = new MuseSessionLocator({
68
+ homeDir: home
69
+ });
70
+ });
71
+ afterEach(()=>{
72
+ fs.rmSync(home, {
73
+ recursive: true,
74
+ force: true
75
+ });
76
+ });
77
+ function writeTranscript(sessionId, dayDir, lines) {
78
+ const dir = path.join(home, ".local", "share", "muse", "sessions", dayDir, sessionId);
79
+ fs.mkdirSync(dir, {
80
+ recursive: true
81
+ });
82
+ const filePath = path.join(dir, "session.jsonl");
83
+ fs.writeFileSync(filePath, lines.join("\n"));
84
+ return filePath;
85
+ }
86
+ function writeRuntimeFile(sessionId, pid) {
87
+ const dir = path.join(home, ".local", "share", "muse", "runtime", "muse", "sessions");
88
+ fs.mkdirSync(dir, {
89
+ recursive: true
90
+ });
91
+ const filePath = path.join(dir, `${sessionId}.jsonl`.replace(".jsonl", ".json"));
92
+ fs.writeFileSync(filePath, JSON.stringify({
93
+ schema_version: 1,
94
+ session_id: sessionId,
95
+ process_generation_hint: `pid=${pid}`
96
+ }));
97
+ return filePath;
98
+ }
99
+ it("matches a live process to its transcript via the runtime file", ()=>{
100
+ const now = Date.now();
101
+ const filePath = writeTranscript(SID, "2026/10/10", [
102
+ frame(metadata("/Users/tester/proj", now * 1000)),
103
+ frame(intent("hello", now * 1000))
104
+ ]);
105
+ writeRuntimeFile(SID, 16174);
106
+ // Align file birthtime with process start for the staleness guard.
107
+ const start = new Date(fs.statSync(filePath).birthtimeMs);
108
+ const { direct } = locator.matchRunningProcesses([
109
+ proc(16174, "/Users/tester/proj", start)
110
+ ]);
111
+ expect(direct).toHaveLength(1);
112
+ expect(direct[0].process.pid).toBe(16174);
113
+ expect(direct[0].sessionFile.filePath).toBe(filePath);
114
+ expect(direct[0].sessionFile.sessionId).toBe(SID);
115
+ });
116
+ it("rejects runtime matches when the pid was recycled", ()=>{
117
+ writeTranscript(SID, "2026/10/10", [
118
+ frame(intent("hello", 1791640525332173))
119
+ ]);
120
+ writeRuntimeFile(SID, 16174);
121
+ // Process started an hour after the session file was born: recycled pid.
122
+ const { direct, fallback } = locator.matchRunningProcesses([
123
+ proc(16174, "/Users/tester/proj", new Date(Date.now() + 3600_000))
124
+ ]);
125
+ expect(direct).toHaveLength(0);
126
+ expect(fallback.map((p)=>p.pid)).toContain(16174);
127
+ });
128
+ it("ignores malformed runtime files (processes fall through to legacy)", ()=>{
129
+ writeTranscript(SID, "2026/10/10", [
130
+ frame(intent("hello", 1791640525332173))
131
+ ]);
132
+ const dir = path.join(home, ".local", "share", "muse", "runtime", "muse", "sessions");
133
+ fs.mkdirSync(dir, {
134
+ recursive: true
135
+ });
136
+ fs.writeFileSync(path.join(dir, `${SID}.json`), "not json");
137
+ fs.writeFileSync(path.join(dir, "other.json"), JSON.stringify({
138
+ session_id: "other",
139
+ process_generation_hint: "nonsense"
140
+ }));
141
+ // Non-muse processes never reach the locator: the adapter pre-filters via canHandle.
142
+ const { direct, fallback } = locator.matchRunningProcesses([
143
+ proc(16174, "/Users/tester/proj", new Date())
144
+ ]);
145
+ expect(direct).toHaveLength(0);
146
+ expect(fallback.map((p)=>p.pid)).toEqual([
147
+ 16174
148
+ ]);
149
+ });
150
+ it("discovers historical sessions across dated dirs, skipping noise", ()=>{
151
+ writeTranscript(SID, "2026/10/10", [
152
+ frame(intent("hello", 1791640525332173))
153
+ ]);
154
+ writeTranscript(OTHER_SID, "2026/10/09", [
155
+ frame(intent("world", 1791640525332173))
156
+ ]);
157
+ // Noise: subagent-style nested dir without session.jsonl, stray files.
158
+ const noise = path.join(home, ".local", "share", "muse", "sessions", "2026/10/10", "not-a-uuid");
159
+ fs.mkdirSync(noise, {
160
+ recursive: true
161
+ });
162
+ fs.writeFileSync(path.join(noise, "notes.txt"), "hi");
163
+ const found = locator.discoverHistoricalSessionFiles();
164
+ expect(found.map((f)=>f.filePath).sort()).toEqual([
165
+ path.join(home, ".local", "share", "muse", "sessions", "2026/10/09", OTHER_SID, "session.jsonl"),
166
+ path.join(home, ".local", "share", "muse", "sessions", "2026/10/10", SID, "session.jsonl")
167
+ ].sort());
168
+ });
169
+ it("finds a session file by id without enumerating everything", ()=>{
170
+ const filePath = writeTranscript(SID, "2026/10/10", [
171
+ frame(intent("hello", 1791640525332173))
172
+ ]);
173
+ const found = locator.findHistoricalSessionFilesById(SID);
174
+ expect(found).toEqual([
175
+ {
176
+ filePath,
177
+ defaultCwd: ""
178
+ }
179
+ ]);
180
+ expect(locator.findHistoricalSessionFilesById("nope")).toEqual([]);
181
+ expect(locator.findHistoricalSessionFilesById("../evil")).toEqual([]);
182
+ });
183
+ });
184
+
185
+ //# sourceMappingURL=MuseSessionLocator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/__tests__/harnesses/muse/MuseSessionLocator.test.ts"],"sourcesContent":["/**\n * Tests for harnesses/muse/MuseSessionLocator.ts — runtime-file matching,\n * dated-archive discovery, and session lookup by id.\n */\n\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { MuseSessionLocator } from \"../../../harnesses/muse/MuseSessionLocator.js\";\n\nconst SID = \"01a12618-d918-7b63-91c8-4e896326eb1a\";\nconst OTHER_SID = \"2288dbd2-d703-444d-afce-59e40a8ad8b1\";\n\nfunction frame(inner: unknown): string {\n return JSON.stringify(inner);\n}\n\nfunction intent(text: string, recordedAtUs: number): unknown {\n return {\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 2,\n recorded_at: recordedAtUs,\n record_type: \"event\",\n payload_type: \"runtime.user_intent.accepted\",\n payload: { refill_blocks: [{ kind: \"text\", text }] },\n };\n}\n\nfunction metadata(workspaceRoot: string, recordedAtUs: number): unknown {\n return {\n schema_version: 1,\n stream: { kind: \"session\", id: SID },\n sequence: 1,\n recorded_at: recordedAtUs,\n record_type: \"event\",\n payload_type: \"runtime.session.metadata\",\n payload: { kind: \"metadata\", record: { workspace_root: workspaceRoot } },\n };\n}\n\nfunction proc(pid: number, cwd: string, startTime: Date): ProcessInfo {\n return {\n pid,\n command: `/Users/tester/.local/bin/muse-bin-1.4.4-R5419.1`,\n cwd,\n tty: \"ttys001\",\n startTime,\n };\n}\n\ndescribe(\"MuseSessionLocator\", () => {\n let home: string;\n let locator: MuseSessionLocator;\n\n beforeEach(() => {\n home = fs.mkdtempSync(path.join(os.tmpdir(), \"muse-locator-test-\"));\n locator = new MuseSessionLocator({ homeDir: home });\n });\n\n afterEach(() => {\n fs.rmSync(home, { recursive: true, force: true });\n });\n\n function writeTranscript(sessionId: string, dayDir: string, lines: string[]): string {\n const dir = path.join(home, \".local\", \"share\", \"muse\", \"sessions\", dayDir, sessionId);\n fs.mkdirSync(dir, { recursive: true });\n const filePath = path.join(dir, \"session.jsonl\");\n fs.writeFileSync(filePath, lines.join(\"\\n\"));\n return filePath;\n }\n\n function writeRuntimeFile(sessionId: string, pid: number): string {\n const dir = path.join(home, \".local\", \"share\", \"muse\", \"runtime\", \"muse\", \"sessions\");\n fs.mkdirSync(dir, { recursive: true });\n const filePath = path.join(dir, `${sessionId}.jsonl`.replace(\".jsonl\", \".json\"));\n fs.writeFileSync(\n filePath,\n JSON.stringify({\n schema_version: 1,\n session_id: sessionId,\n process_generation_hint: `pid=${pid}`,\n }),\n );\n return filePath;\n }\n\n it(\"matches a live process to its transcript via the runtime file\", () => {\n const now = Date.now();\n const filePath = writeTranscript(SID, \"2026/10/10\", [\n frame(metadata(\"/Users/tester/proj\", now * 1000)),\n frame(intent(\"hello\", now * 1000)),\n ]);\n writeRuntimeFile(SID, 16174);\n // Align file birthtime with process start for the staleness guard.\n const start = new Date(fs.statSync(filePath).birthtimeMs);\n\n const { direct } = locator.matchRunningProcesses([proc(16174, \"/Users/tester/proj\", start)]);\n expect(direct).toHaveLength(1);\n expect(direct[0].process.pid).toBe(16174);\n expect(direct[0].sessionFile.filePath).toBe(filePath);\n expect(direct[0].sessionFile.sessionId).toBe(SID);\n });\n\n it(\"rejects runtime matches when the pid was recycled\", () => {\n writeTranscript(SID, \"2026/10/10\", [frame(intent(\"hello\", 1791640525332173))]);\n writeRuntimeFile(SID, 16174);\n\n // Process started an hour after the session file was born: recycled pid.\n const { direct, fallback } = locator.matchRunningProcesses([\n proc(16174, \"/Users/tester/proj\", new Date(Date.now() + 3600_000)),\n ]);\n expect(direct).toHaveLength(0);\n expect(fallback.map((p) => p.pid)).toContain(16174);\n });\n\n it(\"ignores malformed runtime files (processes fall through to legacy)\", () => {\n writeTranscript(SID, \"2026/10/10\", [frame(intent(\"hello\", 1791640525332173))]);\n const dir = path.join(home, \".local\", \"share\", \"muse\", \"runtime\", \"muse\", \"sessions\");\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(path.join(dir, `${SID}.json`), \"not json\");\n fs.writeFileSync(\n path.join(dir, \"other.json\"),\n JSON.stringify({ session_id: \"other\", process_generation_hint: \"nonsense\" }),\n );\n\n // Non-muse processes never reach the locator: the adapter pre-filters via canHandle.\n const { direct, fallback } = locator.matchRunningProcesses([\n proc(16174, \"/Users/tester/proj\", new Date()),\n ]);\n expect(direct).toHaveLength(0);\n expect(fallback.map((p) => p.pid)).toEqual([16174]);\n });\n\n it(\"discovers historical sessions across dated dirs, skipping noise\", () => {\n writeTranscript(SID, \"2026/10/10\", [frame(intent(\"hello\", 1791640525332173))]);\n writeTranscript(OTHER_SID, \"2026/10/09\", [frame(intent(\"world\", 1791640525332173))]);\n // Noise: subagent-style nested dir without session.jsonl, stray files.\n const noise = path.join(\n home,\n \".local\",\n \"share\",\n \"muse\",\n \"sessions\",\n \"2026/10/10\",\n \"not-a-uuid\",\n );\n fs.mkdirSync(noise, { recursive: true });\n fs.writeFileSync(path.join(noise, \"notes.txt\"), \"hi\");\n\n const found = locator.discoverHistoricalSessionFiles();\n expect(found.map((f) => f.filePath).sort()).toEqual(\n [\n path.join(\n home,\n \".local\",\n \"share\",\n \"muse\",\n \"sessions\",\n \"2026/10/09\",\n OTHER_SID,\n \"session.jsonl\",\n ),\n path.join(home, \".local\", \"share\", \"muse\", \"sessions\", \"2026/10/10\", SID, \"session.jsonl\"),\n ].sort(),\n );\n });\n\n it(\"finds a session file by id without enumerating everything\", () => {\n const filePath = writeTranscript(SID, \"2026/10/10\", [frame(intent(\"hello\", 1791640525332173))]);\n const found = locator.findHistoricalSessionFilesById(SID);\n expect(found).toEqual([{ filePath, defaultCwd: \"\" }]);\n expect(locator.findHistoricalSessionFilesById(\"nope\")).toEqual([]);\n expect(locator.findHistoricalSessionFilesById(\"../evil\")).toEqual([]);\n });\n});\n"],"names":["fs","os","path","MuseSessionLocator","SID","OTHER_SID","frame","inner","JSON","stringify","intent","text","recordedAtUs","schema_version","stream","kind","id","sequence","recorded_at","record_type","payload_type","payload","refill_blocks","metadata","workspaceRoot","record","workspace_root","proc","pid","cwd","startTime","command","tty","describe","home","locator","beforeEach","mkdtempSync","join","tmpdir","homeDir","afterEach","rmSync","recursive","force","writeTranscript","sessionId","dayDir","lines","dir","mkdirSync","filePath","writeFileSync","writeRuntimeFile","replace","session_id","process_generation_hint","it","now","Date","start","statSync","birthtimeMs","direct","matchRunningProcesses","expect","toHaveLength","process","toBe","sessionFile","fallback","map","p","toContain","toEqual","noise","found","discoverHistoricalSessionFiles","f","sort","findHistoricalSessionFilesById","defaultCwd"],"mappings":"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"}