@ai-devkit/agent-manager 0.9.0 → 0.11.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 (63) hide show
  1. package/dist/AgentManager.d.ts +21 -1
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +47 -0
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/adapters/AgentAdapter.d.ts +66 -0
  6. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  7. package/dist/adapters/ClaudeCodeAdapter.d.ts +14 -43
  8. package/dist/adapters/ClaudeCodeAdapter.d.ts.map +1 -1
  9. package/dist/adapters/ClaudeCodeAdapter.js +60 -275
  10. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  11. package/dist/adapters/CodexAdapter.d.ts +14 -1
  12. package/dist/adapters/CodexAdapter.d.ts.map +1 -1
  13. package/dist/adapters/CodexAdapter.js +105 -6
  14. package/dist/adapters/CodexAdapter.js.map +1 -1
  15. package/dist/adapters/GeminiCliAdapter.d.ts +9 -1
  16. package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
  17. package/dist/adapters/GeminiCliAdapter.js +77 -6
  18. package/dist/adapters/GeminiCliAdapter.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  23. package/dist/terminal/TerminalFocusManager.js +36 -27
  24. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  25. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  26. package/dist/terminal/TtyWriter.js +3 -12
  27. package/dist/terminal/TtyWriter.js.map +1 -1
  28. package/dist/utils/ClaudeSessionParser.d.ts +114 -0
  29. package/dist/utils/ClaudeSessionParser.d.ts.map +1 -0
  30. package/dist/utils/ClaudeSessionParser.js +377 -0
  31. package/dist/utils/ClaudeSessionParser.js.map +1 -0
  32. package/dist/utils/applescript.d.ts +6 -0
  33. package/dist/utils/applescript.d.ts.map +1 -0
  34. package/dist/utils/applescript.js +14 -0
  35. package/dist/utils/applescript.js.map +1 -0
  36. package/dist/utils/process.d.ts +3 -4
  37. package/dist/utils/process.d.ts.map +1 -1
  38. package/dist/utils/process.js +11 -15
  39. package/dist/utils/process.js.map +1 -1
  40. package/dist/utils/session.d.ts +34 -5
  41. package/dist/utils/session.d.ts.map +1 -1
  42. package/dist/utils/session.js +90 -44
  43. package/dist/utils/session.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/AgentManager.ts +66 -4
  46. package/src/__tests__/AgentManager.test.ts +134 -2
  47. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +188 -32
  48. package/src/__tests__/adapters/CodexAdapter.test.ts +123 -3
  49. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +133 -0
  50. package/src/__tests__/utils/ClaudeSessionParser.test.ts +195 -0
  51. package/src/__tests__/utils/process.test.ts +27 -27
  52. package/src/__tests__/utils/session.test.ts +79 -43
  53. package/src/adapters/AgentAdapter.ts +76 -0
  54. package/src/adapters/ClaudeCodeAdapter.ts +82 -356
  55. package/src/adapters/CodexAdapter.ts +126 -8
  56. package/src/adapters/GeminiCliAdapter.ts +102 -7
  57. package/src/index.ts +9 -1
  58. package/src/terminal/TerminalFocusManager.ts +35 -26
  59. package/src/terminal/TtyWriter.ts +1 -11
  60. package/src/utils/ClaudeSessionParser.ts +437 -0
  61. package/src/utils/applescript.ts +10 -0
  62. package/src/utils/process.ts +21 -24
  63. package/src/utils/session.ts +86 -45
@@ -0,0 +1,114 @@
1
+ import type { ConversationMessage } from '../adapters/AgentAdapter';
2
+ import { AgentStatus } from '../adapters/AgentAdapter';
3
+ /**
4
+ * Content block within a Claude Code JSONL message entry.
5
+ * Handles text, tool_use, and tool_result block types.
6
+ */
7
+ export interface ContentBlock {
8
+ type?: string;
9
+ text?: string;
10
+ content?: string;
11
+ name?: string;
12
+ input?: Record<string, unknown>;
13
+ tool_use_id?: string;
14
+ is_error?: boolean;
15
+ }
16
+ /**
17
+ * A single line entry in a Claude Code session JSONL file.
18
+ *
19
+ * Each line is an independent JSON object with a type discriminator:
20
+ * - "user" / "assistant" / "system" — conversation turns
21
+ * - "progress" / "thinking" — intermediate agent state
22
+ * - "last-prompt" / "file-history-snapshot" — metadata (not conversation state)
23
+ */
24
+ export interface SessionEntry {
25
+ type?: string;
26
+ timestamp?: string;
27
+ cwd?: string;
28
+ message?: {
29
+ content?: string | ContentBlock[];
30
+ };
31
+ }
32
+ /**
33
+ * Parsed session state extracted from a JSONL file.
34
+ * Aggregates data from all entries into a single summary.
35
+ */
36
+ export interface ClaudeSession {
37
+ sessionId: string;
38
+ projectPath: string;
39
+ lastCwd?: string;
40
+ sessionStart: Date;
41
+ lastActive: Date;
42
+ lastEntryType?: string;
43
+ isInterrupted: boolean;
44
+ lastUserMessage?: string;
45
+ /** First meaningful user prompt in the session (post noise filter) */
46
+ firstUserMessage?: string;
47
+ }
48
+ /**
49
+ * Parses Claude Code session JSONL files into structured data.
50
+ *
51
+ * Session files live at ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl
52
+ * and contain one JSON object per line, each representing a conversation
53
+ * event (user turn, assistant response, tool call, etc.).
54
+ */
55
+ export declare class ClaudeSessionParser {
56
+ /**
57
+ * Parse a session JSONL file into a ClaudeSession summary.
58
+ *
59
+ * Iterates all lines to extract: session start time (from first entry),
60
+ * last activity timestamp, last entry type (for status), whether the
61
+ * session was interrupted, and the last meaningful user message.
62
+ *
63
+ * Returns null if the file is unreadable or empty.
64
+ */
65
+ readSession(filePath: string, projectPath: string): ClaudeSession | null;
66
+ /**
67
+ * Determine agent status from parsed session state.
68
+ *
69
+ * Status mapping:
70
+ * - "user" + interrupted → WAITING (agent finished, awaiting new input)
71
+ * - "user" + not interrupted → RUNNING (agent is processing)
72
+ * - "progress" / "thinking" → RUNNING
73
+ * - "assistant" → WAITING (agent responded, awaiting user)
74
+ * - "system" → IDLE
75
+ */
76
+ determineStatus(session: ClaudeSession): AgentStatus;
77
+ /**
78
+ * Read the full conversation from a session JSONL file.
79
+ *
80
+ * Default mode returns only text content from user/assistant/system messages.
81
+ * Verbose mode also includes tool_use and tool_result blocks.
82
+ */
83
+ getConversation(sessionFilePath: string, options?: {
84
+ verbose?: boolean;
85
+ }): ConversationMessage[];
86
+ /**
87
+ * Parse session start time from the first JSONL line.
88
+ *
89
+ * Claude Code may emit a "file-history-snapshot" as the first entry,
90
+ * which stores its timestamp inside "snapshot.timestamp" rather than
91
+ * at the root level.
92
+ */
93
+ private parseSessionStart;
94
+ /**
95
+ * Extract meaningful text from a user message content field.
96
+ *
97
+ * Handles multiple formats:
98
+ * - Plain string content
99
+ * - Array of content blocks (extracts first text block)
100
+ * - Skill slash-commands (<command-message> tags)
101
+ * - Expanded skill content (extracts ARGUMENTS line)
102
+ * - Filters noise messages (interruptions, tool loaded, session continued)
103
+ */
104
+ private extractUserMessageText;
105
+ /**
106
+ * Parse a <command-message> string into "/command args" format.
107
+ */
108
+ private parseCommandMessage;
109
+ /**
110
+ * Extract displayable content from a message content field for conversation output.
111
+ */
112
+ private extractConversationContent;
113
+ }
114
+ //# sourceMappingURL=ClaudeSessionParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeSessionParser.d.ts","sourceRoot":"","sources":["../../src/utils/ClaudeSessionParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;KACrC,CAAC;CACL;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAKD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC5B;;;;;;;;OAQG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAmFxE;;;;;;;;;OASG;IACH,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW;IA6BpD;;;;;OAKG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE;IAiDhG;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAwC9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;OAEG;IACH,OAAO,CAAC,0BAA0B;CAmCrC"}
@@ -0,0 +1,377 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ClaudeSessionParser = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const AgentAdapter_1 = require("../adapters/AgentAdapter");
40
+ /** Entry types that are metadata, not conversation state. */
41
+ const METADATA_ENTRY_TYPES = new Set(['last-prompt', 'file-history-snapshot']);
42
+ /**
43
+ * Parses Claude Code session JSONL files into structured data.
44
+ *
45
+ * Session files live at ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl
46
+ * and contain one JSON object per line, each representing a conversation
47
+ * event (user turn, assistant response, tool call, etc.).
48
+ */
49
+ class ClaudeSessionParser {
50
+ /**
51
+ * Parse a session JSONL file into a ClaudeSession summary.
52
+ *
53
+ * Iterates all lines to extract: session start time (from first entry),
54
+ * last activity timestamp, last entry type (for status), whether the
55
+ * session was interrupted, and the last meaningful user message.
56
+ *
57
+ * Returns null if the file is unreadable or empty.
58
+ */
59
+ readSession(filePath, projectPath) {
60
+ const sessionId = path.basename(filePath, '.jsonl');
61
+ let content;
62
+ try {
63
+ content = fs.readFileSync(filePath, 'utf-8');
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ const allLines = content.trim().split('\n');
69
+ if (allLines.length === 0) {
70
+ return null;
71
+ }
72
+ const sessionStart = this.parseSessionStart(allLines[0]);
73
+ let lastEntryType;
74
+ let lastActive;
75
+ let lastCwd;
76
+ let isInterrupted = false;
77
+ let lastUserMessage;
78
+ let firstUserMessage;
79
+ for (const line of allLines) {
80
+ try {
81
+ const entry = JSON.parse(line);
82
+ if (entry.timestamp) {
83
+ const ts = new Date(entry.timestamp);
84
+ if (!Number.isNaN(ts.getTime())) {
85
+ lastActive = ts;
86
+ }
87
+ }
88
+ if (typeof entry.cwd === 'string' && entry.cwd.trim().length > 0) {
89
+ lastCwd = entry.cwd;
90
+ }
91
+ if (entry.type && !METADATA_ENTRY_TYPES.has(entry.type)) {
92
+ lastEntryType = entry.type;
93
+ if (entry.type === 'user') {
94
+ const msgContent = entry.message?.content;
95
+ isInterrupted =
96
+ Array.isArray(msgContent) &&
97
+ msgContent.some((c) => (c.type === 'text' &&
98
+ c.text?.includes('[Request interrupted')) ||
99
+ (c.type === 'tool_result' &&
100
+ c.content?.includes('[Request interrupted')));
101
+ const text = this.extractUserMessageText(msgContent);
102
+ if (text) {
103
+ lastUserMessage = text;
104
+ if (!firstUserMessage) {
105
+ firstUserMessage = text;
106
+ }
107
+ }
108
+ }
109
+ else {
110
+ isInterrupted = false;
111
+ }
112
+ }
113
+ }
114
+ catch {
115
+ continue;
116
+ }
117
+ }
118
+ return {
119
+ sessionId,
120
+ projectPath: projectPath || lastCwd || '',
121
+ lastCwd,
122
+ sessionStart: sessionStart || lastActive || new Date(),
123
+ lastActive: lastActive || new Date(),
124
+ lastEntryType,
125
+ isInterrupted,
126
+ lastUserMessage,
127
+ firstUserMessage,
128
+ };
129
+ }
130
+ /**
131
+ * Determine agent status from parsed session state.
132
+ *
133
+ * Status mapping:
134
+ * - "user" + interrupted → WAITING (agent finished, awaiting new input)
135
+ * - "user" + not interrupted → RUNNING (agent is processing)
136
+ * - "progress" / "thinking" → RUNNING
137
+ * - "assistant" → WAITING (agent responded, awaiting user)
138
+ * - "system" → IDLE
139
+ */
140
+ determineStatus(session) {
141
+ if (!session.lastEntryType) {
142
+ return AgentAdapter_1.AgentStatus.UNKNOWN;
143
+ }
144
+ if (session.lastEntryType === 'user') {
145
+ return session.isInterrupted
146
+ ? AgentAdapter_1.AgentStatus.WAITING
147
+ : AgentAdapter_1.AgentStatus.RUNNING;
148
+ }
149
+ if (session.lastEntryType === 'progress' ||
150
+ session.lastEntryType === 'thinking') {
151
+ return AgentAdapter_1.AgentStatus.RUNNING;
152
+ }
153
+ if (session.lastEntryType === 'assistant') {
154
+ return AgentAdapter_1.AgentStatus.WAITING;
155
+ }
156
+ if (session.lastEntryType === 'system') {
157
+ return AgentAdapter_1.AgentStatus.IDLE;
158
+ }
159
+ return AgentAdapter_1.AgentStatus.UNKNOWN;
160
+ }
161
+ /**
162
+ * Read the full conversation from a session JSONL file.
163
+ *
164
+ * Default mode returns only text content from user/assistant/system messages.
165
+ * Verbose mode also includes tool_use and tool_result blocks.
166
+ */
167
+ getConversation(sessionFilePath, options) {
168
+ const verbose = options?.verbose ?? false;
169
+ let content;
170
+ try {
171
+ content = fs.readFileSync(sessionFilePath, 'utf-8');
172
+ }
173
+ catch {
174
+ return [];
175
+ }
176
+ const lines = content.trim().split('\n');
177
+ const messages = [];
178
+ for (const line of lines) {
179
+ let entry;
180
+ try {
181
+ entry = JSON.parse(line);
182
+ }
183
+ catch {
184
+ continue;
185
+ }
186
+ const entryType = entry.type;
187
+ if (!entryType || METADATA_ENTRY_TYPES.has(entryType))
188
+ continue;
189
+ if (entryType === 'progress' || entryType === 'thinking')
190
+ continue;
191
+ let role;
192
+ if (entryType === 'user') {
193
+ role = 'user';
194
+ }
195
+ else if (entryType === 'assistant') {
196
+ role = 'assistant';
197
+ }
198
+ else if (entryType === 'system') {
199
+ role = 'system';
200
+ }
201
+ else {
202
+ continue;
203
+ }
204
+ const text = this.extractConversationContent(entry.message?.content, role, verbose);
205
+ if (!text)
206
+ continue;
207
+ messages.push({
208
+ role,
209
+ content: text,
210
+ timestamp: entry.timestamp,
211
+ });
212
+ }
213
+ return messages;
214
+ }
215
+ /**
216
+ * Parse session start time from the first JSONL line.
217
+ *
218
+ * Claude Code may emit a "file-history-snapshot" as the first entry,
219
+ * which stores its timestamp inside "snapshot.timestamp" rather than
220
+ * at the root level.
221
+ */
222
+ parseSessionStart(firstLine) {
223
+ try {
224
+ const firstEntry = JSON.parse(firstLine);
225
+ const rawTs = firstEntry.timestamp || firstEntry.snapshot?.timestamp;
226
+ if (rawTs) {
227
+ const ts = new Date(rawTs);
228
+ if (!Number.isNaN(ts.getTime())) {
229
+ return ts;
230
+ }
231
+ }
232
+ }
233
+ catch {
234
+ /* malformed first line */
235
+ }
236
+ return null;
237
+ }
238
+ /**
239
+ * Extract meaningful text from a user message content field.
240
+ *
241
+ * Handles multiple formats:
242
+ * - Plain string content
243
+ * - Array of content blocks (extracts first text block)
244
+ * - Skill slash-commands (<command-message> tags)
245
+ * - Expanded skill content (extracts ARGUMENTS line)
246
+ * - Filters noise messages (interruptions, tool loaded, session continued)
247
+ */
248
+ extractUserMessageText(content) {
249
+ if (!content) {
250
+ return undefined;
251
+ }
252
+ let raw;
253
+ if (typeof content === 'string') {
254
+ raw = content.trim();
255
+ }
256
+ else if (Array.isArray(content)) {
257
+ for (const block of content) {
258
+ if (block.type === 'text' && block.text?.trim()) {
259
+ raw = block.text.trim();
260
+ break;
261
+ }
262
+ }
263
+ }
264
+ if (!raw) {
265
+ return undefined;
266
+ }
267
+ if (raw.startsWith('<command-message>')) {
268
+ return this.parseCommandMessage(raw);
269
+ }
270
+ if (raw.startsWith('Base directory for this skill:')) {
271
+ const argsMatch = raw.match(/\nARGUMENTS:\s*(.+)/);
272
+ return argsMatch?.[1]?.trim() || undefined;
273
+ }
274
+ if (isNoiseMessage(raw)) {
275
+ return undefined;
276
+ }
277
+ return raw;
278
+ }
279
+ /**
280
+ * Parse a <command-message> string into "/command args" format.
281
+ */
282
+ parseCommandMessage(raw) {
283
+ const nameMatch = raw.match(/<command-name>([^<]+)<\/command-name>/);
284
+ const argsMatch = raw.match(/<command-args>([^<]+)<\/command-args>/);
285
+ const name = nameMatch?.[1]?.trim();
286
+ if (!name) {
287
+ return undefined;
288
+ }
289
+ const args = argsMatch?.[1]?.trim();
290
+ return args ? `${name} ${args}` : name;
291
+ }
292
+ /**
293
+ * Extract displayable content from a message content field for conversation output.
294
+ */
295
+ extractConversationContent(content, role, verbose) {
296
+ if (!content)
297
+ return undefined;
298
+ if (typeof content === 'string') {
299
+ const cleaned = stripHarnessTags(content);
300
+ if (role === 'user' && isNoiseMessage(cleaned))
301
+ return undefined;
302
+ return cleaned || undefined;
303
+ }
304
+ if (!Array.isArray(content))
305
+ return undefined;
306
+ const parts = [];
307
+ for (const block of content) {
308
+ if (block.type === 'text' && block.text?.trim()) {
309
+ const cleaned = stripHarnessTags(block.text);
310
+ if (!cleaned)
311
+ continue;
312
+ if (role === 'user' && isNoiseMessage(cleaned))
313
+ continue;
314
+ parts.push(cleaned);
315
+ }
316
+ else if (block.type === 'tool_use' && verbose) {
317
+ const inputSummary = block.input?.file_path || block.input?.pattern || block.input?.command || '';
318
+ parts.push(`[Tool: ${block.name}]${inputSummary ? ' ' + inputSummary : ''}`);
319
+ }
320
+ else if (block.type === 'tool_result' && verbose) {
321
+ const truncated = truncateToolResult(block.content || '');
322
+ const prefix = block.is_error ? '[Tool Error]' : '[Tool Result]';
323
+ parts.push(`${prefix} ${truncated}`);
324
+ }
325
+ }
326
+ return parts.length > 0 ? parts.join('\n') : undefined;
327
+ }
328
+ }
329
+ exports.ClaudeSessionParser = ClaudeSessionParser;
330
+ /**
331
+ * Tags whose entire block (including content) should be dropped — they are
332
+ * harness-injected prompt context (system reminders, hook output, command
333
+ * stdout), not meaningful conversation content.
334
+ */
335
+ const HARNESS_DROP_TAGS = [
336
+ 'system-reminder',
337
+ 'local-command-stdout',
338
+ 'local-command-stderr',
339
+ 'user-prompt-submit-hook',
340
+ 'command-stdout',
341
+ 'command-stderr',
342
+ 'bash-input',
343
+ 'bash-stdout',
344
+ 'bash-stderr',
345
+ 'command-message',
346
+ ];
347
+ const HARNESS_DROP_RE = new RegExp(`<(${HARNESS_DROP_TAGS.join('|')})>[\\s\\S]*?</\\1>`, 'g');
348
+ const COMMAND_INVOCATION_RE = /<command-name>([^<]+)<\/command-name>(?:\s*<command-args>([\s\S]*?)<\/command-args>)?/g;
349
+ /**
350
+ * Remove harness-injected XML blocks from message text and collapse
351
+ * <command-name>/<command-args> pairs into a "/name args" shorthand.
352
+ *
353
+ * Returns the cleaned, trimmed text. Returns an empty string if nothing
354
+ * survives stripping.
355
+ */
356
+ function stripHarnessTags(text) {
357
+ let out = text.replace(HARNESS_DROP_RE, '');
358
+ out = out.replace(COMMAND_INVOCATION_RE, (_match, rawName, rawArgs) => {
359
+ const name = rawName.trim();
360
+ const args = rawArgs?.trim();
361
+ return args ? `${name} ${args}` : name;
362
+ });
363
+ return out.replace(/\n{3,}/g, '\n\n').trim();
364
+ }
365
+ /** Check if a message is noise (not a meaningful user intent). */
366
+ function isNoiseMessage(text) {
367
+ return (text.startsWith('[Request interrupted') ||
368
+ text === 'Tool loaded.' ||
369
+ text.startsWith('This session is being continued'));
370
+ }
371
+ function truncateToolResult(content, maxLength = 200) {
372
+ const firstLine = content.split('\n')[0] || '';
373
+ if (firstLine.length <= maxLength)
374
+ return firstLine;
375
+ return firstLine.slice(0, maxLength - 3) + '...';
376
+ }
377
+ //# sourceMappingURL=ClaudeSessionParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClaudeSessionParser.js","sourceRoot":"","sources":["../../src/utils/ClaudeSessionParser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Escape a string for safe use inside an AppleScript double-quoted string.
3
+ * Backslashes, double quotes, and newlines must be escaped.
4
+ */
5
+ export declare function escapeAppleScript(text: string): string;
6
+ //# sourceMappingURL=applescript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applescript.d.ts","sourceRoot":"","sources":["../../src/utils/applescript.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.escapeAppleScript = escapeAppleScript;
4
+ /**
5
+ * Escape a string for safe use inside an AppleScript double-quoted string.
6
+ * Backslashes, double quotes, and newlines must be escaped.
7
+ */
8
+ function escapeAppleScript(text) {
9
+ return text
10
+ .replace(/\\/g, '\\\\')
11
+ .replace(/"/g, '\\"')
12
+ .replace(/\r\n|\r|\n/g, '\\n');
13
+ }
14
+ //# sourceMappingURL=applescript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applescript.js","sourceRoot":"","sources":["../../src/utils/applescript.ts"],"names":[],"mappings":";;AAIA,8CAKC;AATD;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,IAAY;IAC1C,OAAO,IAAI;SACN,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC"}
@@ -2,15 +2,14 @@
2
2
  * Process Detection Utilities
3
3
  *
4
4
  * Shared shell command wrappers for detecting and inspecting running processes.
5
- * All execSync calls for process data live here — adapters must not call execSync directly.
5
+ * All execFileSync calls for process data live here — adapters must not call execFileSync directly.
6
6
  */
7
7
  import type { ProcessInfo } from '../adapters/AgentAdapter';
8
8
  /**
9
9
  * List running processes matching an agent executable name.
10
10
  *
11
- * Uses `ps aux | grep <pattern>` at shell level for performance, then post-filters
12
- * by checking that the executable basename matches exactly (avoids matching
13
- * `claude-helper`, `vscode-claude-extension`, or the grep process itself).
11
+ * Uses `ps aux` then filters in JS for exact executable basename match.
12
+ * This avoids shell pipelines and string interpolation.
14
13
  *
15
14
  * Returned ProcessInfo has pid, command, tty populated.
16
15
  * cwd and startTime are NOT populated — call enrichProcesses() to fill them.
@@ -1 +1 @@
1
- {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/utils/process.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CAkDrE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoCvE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAkC3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAavE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWjD"}
1
+ {"version":3,"file":"process.d.ts","sourceRoot":"","sources":["../../src/utils/process.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CA6CrE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAuCvE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAkC3E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAavE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAYjD"}
@@ -3,7 +3,7 @@
3
3
  * Process Detection Utilities
4
4
  *
5
5
  * Shared shell command wrappers for detecting and inspecting running processes.
6
- * All execSync calls for process data live here — adapters must not call execSync directly.
6
+ * All execFileSync calls for process data live here — adapters must not call execFileSync directly.
7
7
  */
8
8
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
9
  if (k2 === undefined) k2 = k;
@@ -49,9 +49,8 @@ const child_process_1 = require("child_process");
49
49
  /**
50
50
  * List running processes matching an agent executable name.
51
51
  *
52
- * Uses `ps aux | grep <pattern>` at shell level for performance, then post-filters
53
- * by checking that the executable basename matches exactly (avoids matching
54
- * `claude-helper`, `vscode-claude-extension`, or the grep process itself).
52
+ * Uses `ps aux` then filters in JS for exact executable basename match.
53
+ * This avoids shell pipelines and string interpolation.
55
54
  *
56
55
  * Returned ProcessInfo has pid, command, tty populated.
57
56
  * cwd and startTime are NOT populated — call enrichProcesses() to fill them.
@@ -62,9 +61,8 @@ function listAgentProcesses(namePattern) {
62
61
  return [];
63
62
  }
64
63
  try {
65
- // Use [c]laude trick to avoid matching the grep process itself
66
- const escapedPattern = `[${namePattern[0]}]${namePattern.slice(1)}`;
67
- const output = (0, child_process_1.execSync)(`ps aux | grep -i '${escapedPattern}'`, { encoding: 'utf-8' });
64
+ const output = (0, child_process_1.execFileSync)('ps', ['aux'], { encoding: 'utf-8' });
65
+ const lowerPattern = namePattern.toLowerCase();
68
66
  const processes = [];
69
67
  for (const line of output.trim().split('\n')) {
70
68
  if (!line.trim())
@@ -77,10 +75,10 @@ function listAgentProcesses(namePattern) {
77
75
  continue;
78
76
  const tty = parts[6];
79
77
  const command = parts.slice(10).join(' ');
80
- // Post-filter: check that the executable basename matches exactly
78
+ // Check that the executable basename matches exactly
81
79
  const executable = command.trim().split(/\s+/)[0] || '';
82
80
  const base = path.basename(executable).toLowerCase();
83
- if (base !== namePattern.toLowerCase() && base !== `${namePattern.toLowerCase()}.exe`) {
81
+ if (base !== lowerPattern && base !== `${lowerPattern}.exe`) {
84
82
  continue;
85
83
  }
86
84
  const ttyShort = tty.startsWith('/dev/') ? tty.slice(5) : tty;
@@ -108,7 +106,7 @@ function batchGetProcessCwds(pids) {
108
106
  if (pids.length === 0)
109
107
  return result;
110
108
  try {
111
- const output = (0, child_process_1.execSync)(`lsof -a -d cwd -Fn -p ${pids.join(',')} 2>/dev/null`, { encoding: 'utf-8' });
109
+ const output = (0, child_process_1.execFileSync)('lsof', ['-a', '-d', 'cwd', '-Fn', '-p', pids.join(',')], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
112
110
  // lsof output format: p{PID}\nn{path}\np{PID}\nn{path}...
113
111
  let currentPid = null;
114
112
  for (const line of output.trim().split('\n')) {
@@ -125,7 +123,7 @@ function batchGetProcessCwds(pids) {
125
123
  // Try per-PID fallback with pwdx (Linux)
126
124
  for (const pid of pids) {
127
125
  try {
128
- const output = (0, child_process_1.execSync)(`pwdx ${pid} 2>/dev/null`, { encoding: 'utf-8' });
126
+ const output = (0, child_process_1.execFileSync)('pwdx', [String(pid)], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
129
127
  const match = output.match(/^\d+:\s*(.+)$/);
130
128
  if (match) {
131
129
  result.set(pid, match[1].trim());
@@ -150,7 +148,7 @@ function batchGetProcessStartTimes(pids) {
150
148
  if (pids.length === 0)
151
149
  return result;
152
150
  try {
153
- const output = (0, child_process_1.execSync)(`ps -o pid=,lstart= -p ${pids.join(',')}`, { encoding: 'utf-8' });
151
+ const output = (0, child_process_1.execFileSync)('ps', ['-o', 'pid=,lstart=', '-p', pids.join(',')], { encoding: 'utf-8' });
154
152
  for (const rawLine of output.split('\n')) {
155
153
  const line = rawLine.trim();
156
154
  if (!line)
@@ -199,9 +197,7 @@ function enrichProcesses(processes) {
199
197
  */
200
198
  function getProcessTty(pid) {
201
199
  try {
202
- const output = (0, child_process_1.execSync)(`ps -p ${pid} -o tty=`, {
203
- encoding: 'utf-8',
204
- });
200
+ const output = (0, child_process_1.execFileSync)('ps', ['-p', String(pid), '-o', 'tty='], { encoding: 'utf-8' });
205
201
  const tty = output.trim();
206
202
  return tty.startsWith('/dev/') ? tty.slice(5) : tty;
207
203
  }