@doingdev/opencode-claude-manager-plugin 0.1.64 → 0.1.66
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 +106 -120
- package/dist/claude/claude-agent-sdk-adapter.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/manager/team-orchestrator.js +1 -1
- package/dist/plugin/agents/common.d.ts +2 -2
- package/dist/plugin/agents/common.js +5 -0
- package/dist/plugin/claude-manager.plugin.js +104 -0
- package/dist/plugin/inbox-ops.d.ts +50 -0
- package/dist/plugin/inbox-ops.js +166 -0
- package/dist/types/contracts.d.ts +18 -0
- package/package.json +13 -13
- package/dist/claude/session-live-tailer.d.ts +0 -51
- package/dist/claude/session-live-tailer.js +0 -269
- package/dist/manager/session-controller.d.ts +0 -41
- package/dist/manager/session-controller.js +0 -97
- package/dist/metadata/claude-metadata.service.d.ts +0 -12
- package/dist/metadata/claude-metadata.service.js +0 -38
- package/dist/metadata/repo-claude-config-reader.d.ts +0 -7
- package/dist/metadata/repo-claude-config-reader.js +0 -154
- package/dist/plugin/orchestrator.plugin.d.ts +0 -2
- package/dist/plugin/orchestrator.plugin.js +0 -116
- package/dist/providers/claude-code-wrapper.d.ts +0 -13
- package/dist/providers/claude-code-wrapper.js +0 -13
- package/dist/safety/bash-safety.d.ts +0 -21
- package/dist/safety/bash-safety.js +0 -62
- package/dist/src/claude/claude-agent-sdk-adapter.d.ts +0 -28
- package/dist/src/claude/claude-agent-sdk-adapter.js +0 -559
- package/dist/src/claude/claude-session.service.d.ts +0 -9
- package/dist/src/claude/claude-session.service.js +0 -15
- package/dist/src/claude/session-live-tailer.d.ts +0 -51
- package/dist/src/claude/session-live-tailer.js +0 -269
- package/dist/src/claude/tool-approval-manager.d.ts +0 -30
- package/dist/src/claude/tool-approval-manager.js +0 -279
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.js +0 -3
- package/dist/src/manager/context-tracker.d.ts +0 -32
- package/dist/src/manager/context-tracker.js +0 -103
- package/dist/src/manager/git-operations.d.ts +0 -18
- package/dist/src/manager/git-operations.js +0 -86
- package/dist/src/manager/persistent-manager.d.ts +0 -39
- package/dist/src/manager/persistent-manager.js +0 -44
- package/dist/src/manager/session-controller.d.ts +0 -41
- package/dist/src/manager/session-controller.js +0 -97
- package/dist/src/manager/team-orchestrator.d.ts +0 -81
- package/dist/src/manager/team-orchestrator.js +0 -612
- package/dist/src/plugin/agent-hierarchy.d.ts +0 -1
- package/dist/src/plugin/agent-hierarchy.js +0 -2
- package/dist/src/plugin/agents/browser-qa.d.ts +0 -14
- package/dist/src/plugin/agents/browser-qa.js +0 -31
- package/dist/src/plugin/agents/common.d.ts +0 -36
- package/dist/src/plugin/agents/common.js +0 -59
- package/dist/src/plugin/agents/cto.d.ts +0 -9
- package/dist/src/plugin/agents/cto.js +0 -39
- package/dist/src/plugin/agents/engineers.d.ts +0 -9
- package/dist/src/plugin/agents/engineers.js +0 -11
- package/dist/src/plugin/agents/index.d.ts +0 -5
- package/dist/src/plugin/agents/index.js +0 -5
- package/dist/src/plugin/agents/team-planner.d.ts +0 -10
- package/dist/src/plugin/agents/team-planner.js +0 -23
- package/dist/src/plugin/claude-manager.plugin.d.ts +0 -10
- package/dist/src/plugin/claude-manager.plugin.js +0 -950
- package/dist/src/plugin/service-factory.d.ts +0 -38
- package/dist/src/plugin/service-factory.js +0 -101
- package/dist/src/prompts/registry.d.ts +0 -2
- package/dist/src/prompts/registry.js +0 -210
- package/dist/src/state/file-run-state-store.d.ts +0 -14
- package/dist/src/state/file-run-state-store.js +0 -85
- package/dist/src/state/team-state-store.d.ts +0 -14
- package/dist/src/state/team-state-store.js +0 -88
- package/dist/src/state/transcript-store.d.ts +0 -15
- package/dist/src/state/transcript-store.js +0 -44
- package/dist/src/team/roster.d.ts +0 -5
- package/dist/src/team/roster.js +0 -40
- package/dist/src/types/contracts.d.ts +0 -261
- package/dist/src/types/contracts.js +0 -2
- package/dist/src/util/fs-helpers.d.ts +0 -8
- package/dist/src/util/fs-helpers.js +0 -21
- package/dist/src/util/project-context.d.ts +0 -10
- package/dist/src/util/project-context.js +0 -105
- package/dist/src/util/transcript-append.d.ts +0 -7
- package/dist/src/util/transcript-append.js +0 -29
- package/dist/state/file-run-state-store.d.ts +0 -14
- package/dist/state/file-run-state-store.js +0 -85
- package/dist/test/claude-agent-sdk-adapter.test.d.ts +0 -1
- package/dist/test/claude-agent-sdk-adapter.test.js +0 -707
- package/dist/test/claude-manager.plugin.test.d.ts +0 -1
- package/dist/test/claude-manager.plugin.test.js +0 -316
- package/dist/test/context-tracker.test.d.ts +0 -1
- package/dist/test/context-tracker.test.js +0 -130
- package/dist/test/cto-active-team.test.d.ts +0 -1
- package/dist/test/cto-active-team.test.js +0 -199
- package/dist/test/file-run-state-store.test.d.ts +0 -1
- package/dist/test/file-run-state-store.test.js +0 -82
- package/dist/test/fs-helpers.test.d.ts +0 -1
- package/dist/test/fs-helpers.test.js +0 -56
- package/dist/test/git-operations.test.d.ts +0 -1
- package/dist/test/git-operations.test.js +0 -133
- package/dist/test/persistent-manager.test.d.ts +0 -1
- package/dist/test/persistent-manager.test.js +0 -48
- package/dist/test/project-context.test.d.ts +0 -1
- package/dist/test/project-context.test.js +0 -92
- package/dist/test/prompt-registry.test.d.ts +0 -1
- package/dist/test/prompt-registry.test.js +0 -117
- package/dist/test/report-claude-event.test.d.ts +0 -1
- package/dist/test/report-claude-event.test.js +0 -304
- package/dist/test/session-controller.test.d.ts +0 -1
- package/dist/test/session-controller.test.js +0 -149
- package/dist/test/session-live-tailer.test.d.ts +0 -1
- package/dist/test/session-live-tailer.test.js +0 -313
- package/dist/test/team-orchestrator.test.d.ts +0 -1
- package/dist/test/team-orchestrator.test.js +0 -583
- package/dist/test/team-state-store.test.d.ts +0 -1
- package/dist/test/team-state-store.test.js +0 -54
- package/dist/test/tool-approval-manager.test.d.ts +0 -1
- package/dist/test/tool-approval-manager.test.js +0 -260
- package/dist/test/transcript-append.test.d.ts +0 -1
- package/dist/test/transcript-append.test.js +0 -37
- package/dist/test/transcript-store.test.d.ts +0 -1
- package/dist/test/transcript-store.test.js +0 -50
- package/dist/test/undo-propagation.test.d.ts +0 -1
- package/dist/test/undo-propagation.test.js +0 -837
- package/dist/util/project-context.d.ts +0 -10
- package/dist/util/project-context.js +0 -105
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -11
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, rmSync, writeFileSync, appendFileSync } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
6
|
-
import { SessionLiveTailer } from '../src/claude/session-live-tailer.js';
|
|
7
|
-
// ── Helpers ─────────────────────────────────────────────────────────────
|
|
8
|
-
let tmpDir;
|
|
9
|
-
let projectsDir;
|
|
10
|
-
function sessionDir(projectName) {
|
|
11
|
-
const dir = path.join(projectsDir, projectName, 'sessions');
|
|
12
|
-
mkdirSync(dir, { recursive: true });
|
|
13
|
-
return dir;
|
|
14
|
-
}
|
|
15
|
-
function writeSession(projectName, sessionId, lines) {
|
|
16
|
-
const dir = sessionDir(projectName);
|
|
17
|
-
const filePath = path.join(dir, `${sessionId}.jsonl`);
|
|
18
|
-
writeFileSync(filePath, lines.join('\n') + '\n', 'utf8');
|
|
19
|
-
return filePath;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Build a tailer that looks in our temp dir instead of ~/.claude/projects.
|
|
23
|
-
* We override `findSessionFile` to search the temp projects dir.
|
|
24
|
-
*/
|
|
25
|
-
function createTailer() {
|
|
26
|
-
const tailer = new SessionLiveTailer();
|
|
27
|
-
// Patch the internal discovery to use our temp dir.
|
|
28
|
-
tailer.findSessionFile = (sessionId, cwd) => {
|
|
29
|
-
if (!existsSync(projectsDir))
|
|
30
|
-
return null;
|
|
31
|
-
// Fast-path: sanitised cwd
|
|
32
|
-
if (cwd) {
|
|
33
|
-
const sanitised = cwd.replace(/\//g, '-');
|
|
34
|
-
const candidate = path.join(projectsDir, sanitised, 'sessions', `${sessionId}.jsonl`);
|
|
35
|
-
if (existsSync(candidate))
|
|
36
|
-
return candidate;
|
|
37
|
-
}
|
|
38
|
-
// Scan all project directories
|
|
39
|
-
try {
|
|
40
|
-
for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
|
|
41
|
-
if (!entry.isDirectory())
|
|
42
|
-
continue;
|
|
43
|
-
const candidate = path.join(projectsDir, entry.name, 'sessions', `${sessionId}.jsonl`);
|
|
44
|
-
if (existsSync(candidate))
|
|
45
|
-
return candidate;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
// ignore
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
};
|
|
53
|
-
return tailer;
|
|
54
|
-
}
|
|
55
|
-
// ── Setup / teardown ────────────────────────────────────────────────────
|
|
56
|
-
beforeEach(() => {
|
|
57
|
-
tmpDir = mkdtempSync(path.join(os.tmpdir(), 'live-tailer-test-'));
|
|
58
|
-
projectsDir = path.join(tmpDir, '.claude', 'projects');
|
|
59
|
-
mkdirSync(projectsDir, { recursive: true });
|
|
60
|
-
});
|
|
61
|
-
afterEach(() => {
|
|
62
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
63
|
-
});
|
|
64
|
-
// ── Tests ───────────────────────────────────────────────────────────────
|
|
65
|
-
describe('SessionLiveTailer', () => {
|
|
66
|
-
describe('findSessionFile', () => {
|
|
67
|
-
it('finds a session file by scanning project directories', () => {
|
|
68
|
-
writeSession('my-project', 'ses_abc', [JSON.stringify({ type: 'system', subtype: 'init' })]);
|
|
69
|
-
const tailer = createTailer();
|
|
70
|
-
const found = tailer.findSessionFile('ses_abc');
|
|
71
|
-
expect(found).not.toBeNull();
|
|
72
|
-
expect(found).toContain('ses_abc.jsonl');
|
|
73
|
-
});
|
|
74
|
-
it('returns null when session does not exist', () => {
|
|
75
|
-
const tailer = createTailer();
|
|
76
|
-
expect(tailer.findSessionFile('ses_nonexistent')).toBeNull();
|
|
77
|
-
});
|
|
78
|
-
it('prefers sanitised cwd fast-path when cwd is provided', () => {
|
|
79
|
-
// Create two projects with the same session ID
|
|
80
|
-
writeSession('-home-user-proj', 'ses_dup', [
|
|
81
|
-
JSON.stringify({ type: 'system', data: 'fast-path' }),
|
|
82
|
-
]);
|
|
83
|
-
writeSession('other-project', 'ses_dup', [
|
|
84
|
-
JSON.stringify({ type: 'system', data: 'scan-path' }),
|
|
85
|
-
]);
|
|
86
|
-
const tailer = createTailer();
|
|
87
|
-
const found = tailer.findSessionFile('ses_dup', '/home/user/proj');
|
|
88
|
-
expect(found).not.toBeNull();
|
|
89
|
-
expect(found).toContain('-home-user-proj');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
describe('sessionFileExists', () => {
|
|
93
|
-
it('returns true when the file exists', () => {
|
|
94
|
-
writeSession('proj', 'ses_exists', [JSON.stringify({ type: 'system' })]);
|
|
95
|
-
const tailer = createTailer();
|
|
96
|
-
expect(tailer.sessionFileExists('ses_exists')).toBe(true);
|
|
97
|
-
});
|
|
98
|
-
it('returns false when the file does not exist', () => {
|
|
99
|
-
const tailer = createTailer();
|
|
100
|
-
expect(tailer.sessionFileExists('ses_missing')).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe('getLastLines', () => {
|
|
104
|
-
it('returns the last N lines from a JSONL file', async () => {
|
|
105
|
-
const lines = Array.from({ length: 20 }, (_, i) => JSON.stringify({ type: 'line', index: i }));
|
|
106
|
-
writeSession('proj', 'ses_lines', lines);
|
|
107
|
-
const tailer = createTailer();
|
|
108
|
-
const result = await tailer.getLastLines('ses_lines', undefined, 5);
|
|
109
|
-
expect(result).toHaveLength(5);
|
|
110
|
-
expect(JSON.parse(result[0])).toMatchObject({ index: 15 });
|
|
111
|
-
expect(JSON.parse(result[4])).toMatchObject({ index: 19 });
|
|
112
|
-
});
|
|
113
|
-
it('returns all lines when file has fewer than N lines', async () => {
|
|
114
|
-
writeSession('proj', 'ses_short', [
|
|
115
|
-
JSON.stringify({ type: 'a' }),
|
|
116
|
-
JSON.stringify({ type: 'b' }),
|
|
117
|
-
]);
|
|
118
|
-
const tailer = createTailer();
|
|
119
|
-
const result = await tailer.getLastLines('ses_short', undefined, 10);
|
|
120
|
-
expect(result).toHaveLength(2);
|
|
121
|
-
});
|
|
122
|
-
it('returns empty array when session file not found', async () => {
|
|
123
|
-
const tailer = createTailer();
|
|
124
|
-
const result = await tailer.getLastLines('ses_ghost', undefined, 5);
|
|
125
|
-
expect(result).toEqual([]);
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
describe('getToolOutputPreview', () => {
|
|
129
|
-
it('extracts tool_result from user messages (pattern 1)', async () => {
|
|
130
|
-
const lines = [
|
|
131
|
-
JSON.stringify({
|
|
132
|
-
type: 'assistant',
|
|
133
|
-
message: { content: [{ type: 'text', text: 'Searching...' }] },
|
|
134
|
-
}),
|
|
135
|
-
JSON.stringify({
|
|
136
|
-
type: 'user',
|
|
137
|
-
message: {
|
|
138
|
-
content: [
|
|
139
|
-
{
|
|
140
|
-
type: 'tool_result',
|
|
141
|
-
tool_use_id: 'toolu_grep_1',
|
|
142
|
-
content: 'src/main.ts:42: const result = await fetch(url);',
|
|
143
|
-
is_error: false,
|
|
144
|
-
},
|
|
145
|
-
],
|
|
146
|
-
},
|
|
147
|
-
}),
|
|
148
|
-
JSON.stringify({
|
|
149
|
-
type: 'assistant',
|
|
150
|
-
message: { content: [{ type: 'text', text: 'Found the match.' }] },
|
|
151
|
-
}),
|
|
152
|
-
];
|
|
153
|
-
writeSession('proj', 'ses_tool', lines);
|
|
154
|
-
const tailer = createTailer();
|
|
155
|
-
const previews = await tailer.getToolOutputPreview('ses_tool', undefined, 5);
|
|
156
|
-
expect(previews).toHaveLength(1);
|
|
157
|
-
expect(previews[0]).toMatchObject({
|
|
158
|
-
toolUseId: 'toolu_grep_1',
|
|
159
|
-
content: 'src/main.ts:42: const result = await fetch(url);',
|
|
160
|
-
isError: false,
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
it('extracts direct tool_result records (pattern 2)', async () => {
|
|
164
|
-
const lines = [
|
|
165
|
-
JSON.stringify({
|
|
166
|
-
type: 'tool_result',
|
|
167
|
-
tool_use_id: 'toolu_bash_1',
|
|
168
|
-
content: 'npm test: 42 passed, 0 failed',
|
|
169
|
-
is_error: false,
|
|
170
|
-
}),
|
|
171
|
-
];
|
|
172
|
-
writeSession('proj', 'ses_direct', lines);
|
|
173
|
-
const tailer = createTailer();
|
|
174
|
-
const previews = await tailer.getToolOutputPreview('ses_direct', undefined, 5);
|
|
175
|
-
expect(previews).toHaveLength(1);
|
|
176
|
-
expect(previews[0]).toMatchObject({
|
|
177
|
-
toolUseId: 'toolu_bash_1',
|
|
178
|
-
content: 'npm test: 42 passed, 0 failed',
|
|
179
|
-
isError: false,
|
|
180
|
-
});
|
|
181
|
-
});
|
|
182
|
-
it('handles error tool results', async () => {
|
|
183
|
-
const lines = [
|
|
184
|
-
JSON.stringify({
|
|
185
|
-
type: 'tool_result',
|
|
186
|
-
tool_use_id: 'toolu_err',
|
|
187
|
-
content: 'ENOENT: no such file',
|
|
188
|
-
is_error: true,
|
|
189
|
-
}),
|
|
190
|
-
];
|
|
191
|
-
writeSession('proj', 'ses_err', lines);
|
|
192
|
-
const tailer = createTailer();
|
|
193
|
-
const previews = await tailer.getToolOutputPreview('ses_err', undefined, 5);
|
|
194
|
-
expect(previews).toHaveLength(1);
|
|
195
|
-
expect(previews[0].isError).toBe(true);
|
|
196
|
-
});
|
|
197
|
-
it('limits results to maxEntries', async () => {
|
|
198
|
-
const lines = Array.from({ length: 10 }, (_, i) => JSON.stringify({
|
|
199
|
-
type: 'tool_result',
|
|
200
|
-
tool_use_id: `toolu_${i}`,
|
|
201
|
-
content: `result ${i}`,
|
|
202
|
-
is_error: false,
|
|
203
|
-
}));
|
|
204
|
-
writeSession('proj', 'ses_limit', lines);
|
|
205
|
-
const tailer = createTailer();
|
|
206
|
-
const previews = await tailer.getToolOutputPreview('ses_limit', undefined, 3);
|
|
207
|
-
expect(previews).toHaveLength(3);
|
|
208
|
-
// Should return the last 3
|
|
209
|
-
expect(previews[0].toolUseId).toBe('toolu_7');
|
|
210
|
-
expect(previews[2].toolUseId).toBe('toolu_9');
|
|
211
|
-
});
|
|
212
|
-
it('skips non-tool-result lines', async () => {
|
|
213
|
-
const lines = [
|
|
214
|
-
JSON.stringify({ type: 'system', subtype: 'init' }),
|
|
215
|
-
JSON.stringify({
|
|
216
|
-
type: 'assistant',
|
|
217
|
-
message: { content: [{ type: 'text', text: 'hi' }] },
|
|
218
|
-
}),
|
|
219
|
-
JSON.stringify({
|
|
220
|
-
type: 'tool_result',
|
|
221
|
-
tool_use_id: 'toolu_1',
|
|
222
|
-
content: 'output',
|
|
223
|
-
is_error: false,
|
|
224
|
-
}),
|
|
225
|
-
JSON.stringify({ type: 'result', subtype: 'success', result: 'Done' }),
|
|
226
|
-
];
|
|
227
|
-
writeSession('proj', 'ses_mixed', lines);
|
|
228
|
-
const tailer = createTailer();
|
|
229
|
-
const previews = await tailer.getToolOutputPreview('ses_mixed', undefined, 10);
|
|
230
|
-
expect(previews).toHaveLength(1);
|
|
231
|
-
expect(previews[0].toolUseId).toBe('toolu_1');
|
|
232
|
-
});
|
|
233
|
-
it('returns empty array when session not found', async () => {
|
|
234
|
-
const tailer = createTailer();
|
|
235
|
-
const previews = await tailer.getToolOutputPreview('ses_nope', undefined);
|
|
236
|
-
expect(previews).toEqual([]);
|
|
237
|
-
});
|
|
238
|
-
it('handles non-string content by JSON-stringifying it', async () => {
|
|
239
|
-
const lines = [
|
|
240
|
-
JSON.stringify({
|
|
241
|
-
type: 'tool_result',
|
|
242
|
-
tool_use_id: 'toolu_obj',
|
|
243
|
-
content: [{ type: 'text', text: 'structured output' }],
|
|
244
|
-
is_error: false,
|
|
245
|
-
}),
|
|
246
|
-
];
|
|
247
|
-
writeSession('proj', 'ses_obj', lines);
|
|
248
|
-
const tailer = createTailer();
|
|
249
|
-
const previews = await tailer.getToolOutputPreview('ses_obj', undefined, 5);
|
|
250
|
-
expect(previews).toHaveLength(1);
|
|
251
|
-
expect(previews[0].content).toBe(JSON.stringify([{ type: 'text', text: 'structured output' }]));
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
describe('startTailing', () => {
|
|
255
|
-
it('emits error event when session file not found', () => {
|
|
256
|
-
const tailer = createTailer();
|
|
257
|
-
const events = [];
|
|
258
|
-
const stop = tailer.startTailing('ses_missing', undefined, (e) => events.push(e));
|
|
259
|
-
expect(events).toHaveLength(1);
|
|
260
|
-
expect(events[0].type).toBe('error');
|
|
261
|
-
expect(events[0].error).toContain('ses_missing');
|
|
262
|
-
stop();
|
|
263
|
-
});
|
|
264
|
-
it('picks up new lines appended after tailing starts', async () => {
|
|
265
|
-
// Write initial content.
|
|
266
|
-
const filePath = writeSession('proj', 'ses_tail', [
|
|
267
|
-
JSON.stringify({ type: 'system', subtype: 'init' }),
|
|
268
|
-
]);
|
|
269
|
-
const tailer = createTailer();
|
|
270
|
-
const events = [];
|
|
271
|
-
// Start tailing (offset begins at end of existing content).
|
|
272
|
-
const stop = tailer.startTailing('ses_tail', undefined, (e) => events.push(e), 50);
|
|
273
|
-
// Append a new line after a short delay.
|
|
274
|
-
await sleep(80);
|
|
275
|
-
appendFileSync(filePath, JSON.stringify({
|
|
276
|
-
type: 'tool_result',
|
|
277
|
-
tool_use_id: 'toolu_new',
|
|
278
|
-
content: 'hello',
|
|
279
|
-
}) + '\n');
|
|
280
|
-
// Wait for the poll to pick it up.
|
|
281
|
-
await sleep(200);
|
|
282
|
-
stop();
|
|
283
|
-
const lineEvents = events.filter((e) => e.type === 'line');
|
|
284
|
-
expect(lineEvents.length).toBeGreaterThanOrEqual(1);
|
|
285
|
-
expect(lineEvents[0].data).toMatchObject({
|
|
286
|
-
type: 'tool_result',
|
|
287
|
-
tool_use_id: 'toolu_new',
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
it('stopTailing clears the interval', () => {
|
|
291
|
-
writeSession('proj', 'ses_stop', [JSON.stringify({ type: 'system' })]);
|
|
292
|
-
const tailer = createTailer();
|
|
293
|
-
const stop = tailer.startTailing('ses_stop', undefined, () => { }, 50);
|
|
294
|
-
// Stop should not throw and should be idempotent.
|
|
295
|
-
stop();
|
|
296
|
-
stop();
|
|
297
|
-
tailer.stopTailing('ses_stop');
|
|
298
|
-
});
|
|
299
|
-
it('stopAll clears all active tails', () => {
|
|
300
|
-
writeSession('proj', 'ses_a', [JSON.stringify({ type: 'system' })]);
|
|
301
|
-
writeSession('proj', 'ses_b', [JSON.stringify({ type: 'system' })]);
|
|
302
|
-
const tailer = createTailer();
|
|
303
|
-
tailer.startTailing('ses_a', undefined, () => { }, 50);
|
|
304
|
-
tailer.startTailing('ses_b', undefined, () => { }, 50);
|
|
305
|
-
tailer.stopAll();
|
|
306
|
-
// Verify idempotent — should not throw.
|
|
307
|
-
tailer.stopAll();
|
|
308
|
-
});
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
function sleep(ms) {
|
|
312
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
313
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|