funolio-agent 1.0.47 → 1.0.49

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 (173) hide show
  1. package/dist/agent-config.d.ts +9 -1
  2. package/dist/agent-config.d.ts.map +1 -1
  3. package/dist/agent-config.js +4 -1
  4. package/dist/agent-config.js.map +1 -1
  5. package/dist/auth/auto-detect.d.ts +1 -0
  6. package/dist/auth/auto-detect.d.ts.map +1 -1
  7. package/dist/auth/auto-detect.js +16 -13
  8. package/dist/auth/auto-detect.js.map +1 -1
  9. package/dist/auto-organizer.d.ts.map +1 -1
  10. package/dist/auto-organizer.js +4 -3
  11. package/dist/auto-organizer.js.map +1 -1
  12. package/dist/backfill.d.ts.map +1 -1
  13. package/dist/backfill.js +3 -2
  14. package/dist/backfill.js.map +1 -1
  15. package/dist/bot-manager.d.ts +8 -23
  16. package/dist/bot-manager.d.ts.map +1 -1
  17. package/dist/bot-manager.js +61 -388
  18. package/dist/bot-manager.js.map +1 -1
  19. package/dist/clerk-model.d.ts +5 -1
  20. package/dist/clerk-model.d.ts.map +1 -1
  21. package/dist/clerk-model.js +40 -28
  22. package/dist/clerk-model.js.map +1 -1
  23. package/dist/cli-session-epoch.d.ts +10 -0
  24. package/dist/cli-session-epoch.d.ts.map +1 -0
  25. package/dist/cli-session-epoch.js +61 -0
  26. package/dist/cli-session-epoch.js.map +1 -0
  27. package/dist/commands/init.d.ts.map +1 -1
  28. package/dist/commands/init.js +30 -1
  29. package/dist/commands/init.js.map +1 -1
  30. package/dist/commands/pool.js +1 -1
  31. package/dist/commands/pool.js.map +1 -1
  32. package/dist/commands/setup.d.ts +37 -0
  33. package/dist/commands/setup.d.ts.map +1 -1
  34. package/dist/commands/setup.js +154 -43
  35. package/dist/commands/setup.js.map +1 -1
  36. package/dist/commands/start.d.ts.map +1 -1
  37. package/dist/commands/start.js +195 -164
  38. package/dist/commands/start.js.map +1 -1
  39. package/dist/config-cleanup.d.ts.map +1 -1
  40. package/dist/config-cleanup.js +2 -1
  41. package/dist/config-cleanup.js.map +1 -1
  42. package/dist/config.d.ts +6 -9
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +8 -30
  45. package/dist/config.js.map +1 -1
  46. package/dist/context-window.d.ts +33 -5
  47. package/dist/context-window.d.ts.map +1 -1
  48. package/dist/context-window.js +121 -20
  49. package/dist/context-window.js.map +1 -1
  50. package/dist/eval/orchestrator-front-door-replay.js +1 -1
  51. package/dist/eval/orchestrator-front-door-replay.js.map +1 -1
  52. package/dist/eval/policy-detection-replay.js +1 -1
  53. package/dist/eval/policy-detection-replay.js.map +1 -1
  54. package/dist/integration-tokens.d.ts +1 -6
  55. package/dist/integration-tokens.d.ts.map +1 -1
  56. package/dist/integration-tokens.js +38 -40
  57. package/dist/integration-tokens.js.map +1 -1
  58. package/dist/local-cli-pty-manager.d.ts +50 -0
  59. package/dist/local-cli-pty-manager.d.ts.map +1 -0
  60. package/dist/local-cli-pty-manager.js +645 -0
  61. package/dist/local-cli-pty-manager.js.map +1 -0
  62. package/dist/local-data.d.ts +30 -0
  63. package/dist/local-data.d.ts.map +1 -1
  64. package/dist/local-data.js +56 -1
  65. package/dist/local-data.js.map +1 -1
  66. package/dist/local-db.d.ts.map +1 -1
  67. package/dist/local-db.js +54 -1
  68. package/dist/local-db.js.map +1 -1
  69. package/dist/local-funnel.d.ts.map +1 -1
  70. package/dist/local-funnel.js +3 -2
  71. package/dist/local-funnel.js.map +1 -1
  72. package/dist/local-memory-search.d.ts +1 -0
  73. package/dist/local-memory-search.d.ts.map +1 -1
  74. package/dist/local-memory-search.js +101 -18
  75. package/dist/local-memory-search.js.map +1 -1
  76. package/dist/local-server.d.ts +0 -16
  77. package/dist/local-server.d.ts.map +1 -1
  78. package/dist/local-server.js +339 -287
  79. package/dist/local-server.js.map +1 -1
  80. package/dist/mcp/bridge-server.d.ts.map +1 -1
  81. package/dist/mcp/bridge-server.js +2 -1
  82. package/dist/mcp/bridge-server.js.map +1 -1
  83. package/dist/mcp/local-memory-server.d.ts +5 -0
  84. package/dist/mcp/local-memory-server.d.ts.map +1 -1
  85. package/dist/mcp/local-memory-server.js +15 -2
  86. package/dist/mcp/local-memory-server.js.map +1 -1
  87. package/dist/mcp/manager.d.ts +3 -22
  88. package/dist/mcp/manager.d.ts.map +1 -1
  89. package/dist/mcp/manager.js +66 -388
  90. package/dist/mcp/manager.js.map +1 -1
  91. package/dist/memory-extraction.d.ts +2 -0
  92. package/dist/memory-extraction.d.ts.map +1 -1
  93. package/dist/memory-extraction.js +3 -1
  94. package/dist/memory-extraction.js.map +1 -1
  95. package/dist/message-loop.d.ts +10 -6
  96. package/dist/message-loop.d.ts.map +1 -1
  97. package/dist/message-loop.js +241 -540
  98. package/dist/message-loop.js.map +1 -1
  99. package/dist/mqtt-client.d.ts +2 -31
  100. package/dist/mqtt-client.d.ts.map +1 -1
  101. package/dist/mqtt-client.js +2 -2
  102. package/dist/mqtt-client.js.map +1 -1
  103. package/dist/oauth.d.ts +6 -0
  104. package/dist/oauth.d.ts.map +1 -1
  105. package/dist/oauth.js +91 -0
  106. package/dist/oauth.js.map +1 -1
  107. package/dist/orchestration/front-door-policy.d.ts +5 -2
  108. package/dist/orchestration/front-door-policy.d.ts.map +1 -1
  109. package/dist/orchestration/front-door-policy.js +25 -28
  110. package/dist/orchestration/front-door-policy.js.map +1 -1
  111. package/dist/orchestration/orchestrator-blocked-prompt.js +1 -1
  112. package/dist/orchestration/orchestrator-final-response-prompt.js +1 -1
  113. package/dist/orchestration/orchestrator-operating-prompt.d.ts +11 -0
  114. package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
  115. package/dist/orchestration/orchestrator-operating-prompt.js +67 -44
  116. package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
  117. package/dist/orchestration/worker-operating-prompt.js +3 -3
  118. package/dist/orchestration/worker-operating-prompt.js.map +1 -1
  119. package/dist/orchestrator.d.ts +5 -1
  120. package/dist/orchestrator.d.ts.map +1 -1
  121. package/dist/orchestrator.js +141 -81
  122. package/dist/orchestrator.js.map +1 -1
  123. package/dist/prompt-template.js +3 -3
  124. package/dist/prompt-template.js.map +1 -1
  125. package/dist/providers/claude-cli-prompt.d.ts.map +1 -1
  126. package/dist/providers/claude-cli-prompt.js +22 -6
  127. package/dist/providers/claude-cli-prompt.js.map +1 -1
  128. package/dist/providers/claude-cli.d.ts.map +1 -1
  129. package/dist/providers/claude-cli.js +20 -2
  130. package/dist/providers/claude-cli.js.map +1 -1
  131. package/dist/providers/codex-cli.d.ts.map +1 -1
  132. package/dist/providers/codex-cli.js +71 -16
  133. package/dist/providers/codex-cli.js.map +1 -1
  134. package/dist/providers/index.d.ts +11 -0
  135. package/dist/providers/index.d.ts.map +1 -1
  136. package/dist/providers/index.js.map +1 -1
  137. package/dist/runtime-context.d.ts +10 -0
  138. package/dist/runtime-context.d.ts.map +1 -0
  139. package/dist/runtime-context.js +30 -0
  140. package/dist/runtime-context.js.map +1 -0
  141. package/dist/subagent/queue.d.ts.map +1 -1
  142. package/dist/subagent/queue.js +1 -0
  143. package/dist/subagent/queue.js.map +1 -1
  144. package/dist/summarization-pipeline.d.ts +1 -0
  145. package/dist/summarization-pipeline.d.ts.map +1 -1
  146. package/dist/summarization-pipeline.js +94 -25
  147. package/dist/summarization-pipeline.js.map +1 -1
  148. package/dist/tool-permissions.d.ts +2 -0
  149. package/dist/tool-permissions.d.ts.map +1 -0
  150. package/dist/tool-permissions.js +25 -0
  151. package/dist/tool-permissions.js.map +1 -0
  152. package/dist/tools/index.d.ts +7 -8
  153. package/dist/tools/index.d.ts.map +1 -1
  154. package/dist/tools/index.js +70 -60
  155. package/dist/tools/index.js.map +1 -1
  156. package/dist/tools/search-memory.d.ts.map +1 -1
  157. package/dist/tools/search-memory.js +9 -3
  158. package/dist/tools/search-memory.js.map +1 -1
  159. package/dist/tools/spawn-subagent.d.ts.map +1 -1
  160. package/dist/tools/spawn-subagent.js +1 -0
  161. package/dist/tools/spawn-subagent.js.map +1 -1
  162. package/dist/types.d.ts +3 -0
  163. package/dist/types.d.ts.map +1 -1
  164. package/dist/types.js +0 -3
  165. package/dist/types.js.map +1 -1
  166. package/dist/wizard-support.d.ts.map +1 -1
  167. package/dist/wizard-support.js +8 -6
  168. package/dist/wizard-support.js.map +1 -1
  169. package/dist/workflow-engine.d.ts +6 -2
  170. package/dist/workflow-engine.d.ts.map +1 -1
  171. package/dist/workflow-engine.js +254 -77
  172. package/dist/workflow-engine.js.map +1 -1
  173. package/package.json +2 -1
@@ -0,0 +1,645 @@
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.LocalCliPtySessionManager = void 0;
37
+ exports.parseClaudeSessionRecord = parseClaudeSessionRecord;
38
+ exports.parseCodexSessionRecord = parseCodexSessionRecord;
39
+ exports.getLocalCliPtySessionManager = getLocalCliPtySessionManager;
40
+ const fs = __importStar(require("fs"));
41
+ const os = __importStar(require("os"));
42
+ const path = __importStar(require("path"));
43
+ const claude_cli_prompt_1 = require("./providers/claude-cli-prompt");
44
+ let _ptyModule = null;
45
+ let _manager = null;
46
+ function delay(ms) {
47
+ return new Promise((resolve) => setTimeout(resolve, ms));
48
+ }
49
+ function sessionKey(conversationId, botId) {
50
+ return `${conversationId}::${botId}`;
51
+ }
52
+ function getAppDirFromExec(execDir) {
53
+ return path.basename(execDir).toLowerCase() === 'binaries'
54
+ ? path.dirname(execDir)
55
+ : execDir;
56
+ }
57
+ function findExecutableOnPath(commandName) {
58
+ const pathValue = process.env.PATH || '';
59
+ if (!pathValue)
60
+ return null;
61
+ const pathextValue = process.platform === 'win32'
62
+ ? (process.env.PATHEXT || '.COM;.EXE;.BAT;.CMD')
63
+ : '';
64
+ const pathExts = process.platform === 'win32'
65
+ ? pathextValue.split(';').filter(Boolean)
66
+ : [''];
67
+ const candidates = commandName.includes('.')
68
+ ? [commandName]
69
+ : pathExts.map((ext) => `${commandName}${ext.toLowerCase()}`);
70
+ for (const dir of pathValue.split(path.delimiter).filter(Boolean)) {
71
+ for (const candidate of candidates) {
72
+ const fullPath = path.join(dir, candidate);
73
+ if (fs.existsSync(fullPath)) {
74
+ return fullPath;
75
+ }
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ function loadNodePtyModule() {
81
+ if (_ptyModule)
82
+ return _ptyModule;
83
+ const dynamicRequire = eval('require');
84
+ try {
85
+ _ptyModule = dynamicRequire('@homebridge/node-pty-prebuilt-multiarch');
86
+ return _ptyModule;
87
+ }
88
+ catch (firstErr) {
89
+ const execDir = path.dirname(process.execPath);
90
+ const appDir = getAppDirFromExec(execDir);
91
+ const candidates = [
92
+ path.join(execDir, 'resources', 'node-pty-prebuilt', 'lib', 'index.js'),
93
+ path.join(appDir, 'resources', 'node-pty-prebuilt', 'lib', 'index.js'),
94
+ ];
95
+ for (const candidate of candidates) {
96
+ if (!fs.existsSync(candidate))
97
+ continue;
98
+ _ptyModule = dynamicRequire(candidate);
99
+ return _ptyModule;
100
+ }
101
+ throw new Error(`Failed to load PTY runtime. Tried package import and packaged resource candidates. Original error: ${firstErr instanceof Error ? firstErr.message : String(firstErr)}`);
102
+ }
103
+ }
104
+ function buildCodexSeedPrompt(systemPrompt, messages) {
105
+ let fullPrompt = '';
106
+ if (systemPrompt) {
107
+ fullPrompt += `[System Instructions]\n${systemPrompt}\n\n`;
108
+ }
109
+ const lastMessage = messages.length > 0 ? messages[messages.length - 1] : null;
110
+ if (messages.length > 0) {
111
+ const transcriptMessages = lastMessage?.role === 'user' ? messages.slice(0, -1) : messages;
112
+ if (transcriptMessages.length > 0) {
113
+ fullPrompt += '[Recent Transcript]\n';
114
+ for (const msg of transcriptMessages) {
115
+ const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
116
+ const label = msg.role === 'user' ? 'USER'
117
+ : msg.role === 'assistant' ? 'ASSISTANT'
118
+ : msg.role === 'tool' ? `TOOL (${msg.toolName || 'tool'})`
119
+ : String(msg.role || 'MESSAGE').toUpperCase();
120
+ fullPrompt += `${label}:\n${content}\n\n`;
121
+ }
122
+ }
123
+ }
124
+ if (lastMessage?.role === 'user') {
125
+ const prompt = typeof lastMessage.content === 'string' ? lastMessage.content : JSON.stringify(lastMessage.content);
126
+ fullPrompt += `[User Request]\n${prompt}`;
127
+ }
128
+ else if (lastMessage) {
129
+ const content = typeof lastMessage.content === 'string' ? lastMessage.content : JSON.stringify(lastMessage.content);
130
+ fullPrompt += `[Latest Message]\n${content}\n\nContinue from the transcript above and respond appropriately.`;
131
+ }
132
+ else {
133
+ fullPrompt += '[User Request]\n';
134
+ }
135
+ return fullPrompt;
136
+ }
137
+ function buildTurnPrompt(provider, systemPrompt, messages, freshSession) {
138
+ if (!freshSession) {
139
+ const lastMessage = messages.length > 0 ? messages[messages.length - 1] : null;
140
+ if (lastMessage?.role === 'user') {
141
+ return typeof lastMessage.content === 'string'
142
+ ? lastMessage.content
143
+ : JSON.stringify(lastMessage.content);
144
+ }
145
+ }
146
+ if (provider === 'claude-cli') {
147
+ return (0, claude_cli_prompt_1.buildClaudeCliStylePrompt)({
148
+ system: systemPrompt,
149
+ messages,
150
+ runtimeMode: 'local_desktop',
151
+ });
152
+ }
153
+ return buildCodexSeedPrompt(systemPrompt, messages);
154
+ }
155
+ function getProviderSessionRoot(provider) {
156
+ if (provider === 'claude-cli') {
157
+ return path.join(os.homedir(), '.claude', 'projects');
158
+ }
159
+ return path.join(os.homedir(), '.codex', 'sessions');
160
+ }
161
+ function listSessionFiles(provider) {
162
+ const root = getProviderSessionRoot(provider);
163
+ if (!fs.existsSync(root))
164
+ return [];
165
+ const results = [];
166
+ const stack = [root];
167
+ while (stack.length > 0) {
168
+ const current = stack.pop();
169
+ let entries = [];
170
+ try {
171
+ entries = fs.readdirSync(current, { withFileTypes: true });
172
+ }
173
+ catch {
174
+ continue;
175
+ }
176
+ for (const entry of entries) {
177
+ const fullPath = path.join(current, entry.name);
178
+ if (entry.isDirectory()) {
179
+ stack.push(fullPath);
180
+ continue;
181
+ }
182
+ if (entry.isFile() && entry.name.toLowerCase().endsWith('.jsonl')) {
183
+ results.push(fullPath);
184
+ }
185
+ }
186
+ }
187
+ return results;
188
+ }
189
+ function extractUserPromptFromRecord(provider, record) {
190
+ if (!record || typeof record !== 'object')
191
+ return '';
192
+ if (provider === 'claude-cli') {
193
+ const content = record?.message?.content;
194
+ return typeof content === 'string' ? content.trim() : '';
195
+ }
196
+ if (record.type === 'event_msg' && record.payload?.type === 'user_message' && typeof record.payload?.message === 'string') {
197
+ return record.payload.message.trim();
198
+ }
199
+ return '';
200
+ }
201
+ function recentFileContainsPrompt(provider, filePath, promptText) {
202
+ const expected = promptText.trim();
203
+ if (!expected)
204
+ return false;
205
+ let stat;
206
+ try {
207
+ stat = fs.statSync(filePath);
208
+ }
209
+ catch {
210
+ return false;
211
+ }
212
+ const readLength = Math.min(stat.size, 512 * 1024);
213
+ if (readLength <= 0)
214
+ return false;
215
+ const start = stat.size - readLength;
216
+ const fd = fs.openSync(filePath, 'r');
217
+ try {
218
+ const buffer = Buffer.alloc(readLength);
219
+ fs.readSync(fd, buffer, 0, readLength, start);
220
+ const text = buffer.toString('utf8');
221
+ for (const rawLine of text.split('\n')) {
222
+ const line = rawLine.trim();
223
+ if (!line)
224
+ continue;
225
+ try {
226
+ const record = JSON.parse(line);
227
+ if (extractUserPromptFromRecord(provider, record) === expected) {
228
+ return true;
229
+ }
230
+ }
231
+ catch {
232
+ continue;
233
+ }
234
+ }
235
+ }
236
+ finally {
237
+ fs.closeSync(fd);
238
+ }
239
+ return false;
240
+ }
241
+ function discoverSessionFile(provider, launchSnapshot, startedAtMs, promptLocator) {
242
+ const candidates = listSessionFiles(provider)
243
+ .map((candidate) => {
244
+ let mtimeMs = 0;
245
+ try {
246
+ mtimeMs = fs.statSync(candidate).mtimeMs;
247
+ }
248
+ catch {
249
+ return null;
250
+ }
251
+ return { candidate, mtimeMs, isNew: !launchSnapshot.has(candidate) };
252
+ })
253
+ .filter((item) => !!item)
254
+ .filter((item) => item.mtimeMs >= (startedAtMs - 5000))
255
+ .sort((a, b) => {
256
+ if (a.isNew !== b.isNew)
257
+ return a.isNew ? -1 : 1;
258
+ return b.mtimeMs - a.mtimeMs;
259
+ });
260
+ if (promptLocator?.trim()) {
261
+ const matched = candidates.find((item) => recentFileContainsPrompt(provider, item.candidate, promptLocator));
262
+ if (matched)
263
+ return matched.candidate;
264
+ }
265
+ return candidates[0]?.candidate || null;
266
+ }
267
+ function extractClaudeText(record) {
268
+ const blocks = Array.isArray(record?.message?.content) ? record.message.content : [];
269
+ return blocks
270
+ .map((block) => {
271
+ if (!block || typeof block !== 'object')
272
+ return '';
273
+ return block.type === 'text' && typeof block.text === 'string' ? block.text : '';
274
+ })
275
+ .join('');
276
+ }
277
+ function extractClaudeToolNames(record) {
278
+ const blocks = Array.isArray(record?.message?.content) ? record.message.content : [];
279
+ return blocks
280
+ .map((block) => (block?.type === 'tool_use' && typeof block?.name === 'string' ? block.name : ''))
281
+ .filter((name) => !!name);
282
+ }
283
+ function extractCodexAssistantText(record) {
284
+ if (!record || typeof record !== 'object')
285
+ return '';
286
+ if (record.type === 'event_msg') {
287
+ if (record.payload?.type === 'agent_message' && typeof record.payload?.message === 'string') {
288
+ return record.payload.message;
289
+ }
290
+ if (record.payload?.type === 'task_complete' && typeof record.payload?.last_agent_message === 'string') {
291
+ return record.payload.last_agent_message;
292
+ }
293
+ }
294
+ if (record.type === 'response_item' && record.payload?.type === 'message' && record.payload?.role === 'assistant') {
295
+ const blocks = Array.isArray(record.payload?.content) ? record.payload.content : [];
296
+ return blocks
297
+ .map((block) => {
298
+ if (!block || typeof block !== 'object')
299
+ return '';
300
+ if (block.type === 'output_text' && typeof block.text === 'string')
301
+ return block.text;
302
+ if (block.type === 'text' && typeof block.text === 'string')
303
+ return block.text;
304
+ return '';
305
+ })
306
+ .join('');
307
+ }
308
+ return '';
309
+ }
310
+ function normalizeAssistantContent(text) {
311
+ return text.replace(/^\s+/, '').replace(/\r/g, '');
312
+ }
313
+ async function emitDetail(tracker, detail, cb) {
314
+ const trimmed = detail.trim();
315
+ if (!trimmed)
316
+ return;
317
+ if (tracker.detailFingerprints.has(trimmed))
318
+ return;
319
+ tracker.detailFingerprints.add(trimmed);
320
+ await cb?.(trimmed);
321
+ }
322
+ function parseClaudeSessionRecord(record) {
323
+ const sessionId = typeof record?.sessionId === 'string' ? record.sessionId : undefined;
324
+ if (record?.type === 'assistant' && record?.message) {
325
+ const usage = record.message.usage
326
+ ? {
327
+ inputTokens: (record.message.usage.input_tokens || 0)
328
+ + (record.message.usage.cache_read_input_tokens || 0)
329
+ + (record.message.usage.cache_creation_input_tokens || 0),
330
+ outputTokens: record.message.usage.output_tokens || 0,
331
+ }
332
+ : undefined;
333
+ const toolNames = extractClaudeToolNames(record);
334
+ if (toolNames.length > 0) {
335
+ return {
336
+ sessionId,
337
+ detail: `Running ${toolNames.join(', ')}...`,
338
+ usage,
339
+ };
340
+ }
341
+ const text = normalizeAssistantContent(extractClaudeText(record));
342
+ if (text) {
343
+ return {
344
+ sessionId,
345
+ ...(record.message.stop_reason === 'end_turn'
346
+ ? { finalContent: text, done: true, usage }
347
+ : { detail: text, usage }),
348
+ };
349
+ }
350
+ return { sessionId, usage };
351
+ }
352
+ if (record?.type === 'user' && Array.isArray(record?.message?.content)) {
353
+ const toolResultText = record.message.content
354
+ .map((block) => {
355
+ if (!block || typeof block !== 'object')
356
+ return '';
357
+ if (typeof block.tool_use_id === 'string' && typeof block.content === 'string') {
358
+ return `Tool result (${block.tool_use_id}): ${String(block.content).slice(0, 240)}`;
359
+ }
360
+ return '';
361
+ })
362
+ .filter(Boolean)
363
+ .join('\n');
364
+ if (toolResultText) {
365
+ return { sessionId, detail: toolResultText };
366
+ }
367
+ }
368
+ return sessionId ? { sessionId } : {};
369
+ }
370
+ function parseCodexSessionRecord(record) {
371
+ if (!record || typeof record !== 'object')
372
+ return {};
373
+ if (record.type === 'session_meta' && typeof record.payload?.id === 'string') {
374
+ return { sessionId: record.payload.id };
375
+ }
376
+ if (record.type === 'event_msg' && record.payload?.type === 'task_started') {
377
+ return { detail: 'Task started' };
378
+ }
379
+ if (record.type === 'event_msg' && record.payload?.type === 'task_complete') {
380
+ const finalContent = normalizeAssistantContent(typeof record.payload?.last_agent_message === 'string' ? record.payload.last_agent_message : '');
381
+ return {
382
+ finalContent,
383
+ done: true,
384
+ };
385
+ }
386
+ if (record.type === 'event_msg' && record.payload?.type === 'token_count' && record.payload?.info?.total_token_usage) {
387
+ return {
388
+ usage: {
389
+ inputTokens: (record.payload.info.total_token_usage.input_tokens || 0)
390
+ + (record.payload.info.total_token_usage.cached_input_tokens || 0),
391
+ outputTokens: record.payload.info.total_token_usage.output_tokens || 0,
392
+ },
393
+ };
394
+ }
395
+ const assistantText = normalizeAssistantContent(extractCodexAssistantText(record));
396
+ if (assistantText) {
397
+ return { finalContent: assistantText };
398
+ }
399
+ if (record.type === 'event_msg' && typeof record.payload?.type === 'string') {
400
+ const eventType = record.payload.type;
401
+ if (!['user_message', 'agent_message', 'token_count', 'task_complete'].includes(eventType)) {
402
+ return { detail: eventType.replace(/_/g, ' ') };
403
+ }
404
+ }
405
+ return {};
406
+ }
407
+ async function waitForFirstTerminalData(session) {
408
+ await Promise.race([session.readyPromise, delay(5000)]);
409
+ await delay(session.startupDelayMs);
410
+ }
411
+ async function writeInteractivePrompt(session, promptText) {
412
+ if (session.provider === 'codex-cli') {
413
+ session.pty.write(promptText);
414
+ await delay(session.submitDelayMs);
415
+ session.pty.write('\r');
416
+ return;
417
+ }
418
+ session.pty.write(promptText);
419
+ session.pty.write('\r');
420
+ }
421
+ class LocalCliPtySessionManager {
422
+ sessions = new Map();
423
+ async runTurn(opts) {
424
+ const key = sessionKey(opts.conversationId, opts.botId);
425
+ let session = this.sessions.get(key);
426
+ if (session
427
+ && (opts.forceFreshSession || session.provider !== opts.provider || session.cwd !== opts.cwd || session.closed)) {
428
+ this.closeSession(key);
429
+ session = undefined;
430
+ }
431
+ if (!session) {
432
+ session = this.createSession(key, opts.provider, opts.cwd);
433
+ this.sessions.set(key, session);
434
+ }
435
+ const run = async () => this.runTurnInternal(session, opts);
436
+ const queued = session.chain.then(run, run);
437
+ session.chain = queued.then(() => undefined, () => undefined);
438
+ return queued;
439
+ }
440
+ closeSessionByConversation(conversationId, botId) {
441
+ this.closeSession(sessionKey(conversationId, botId));
442
+ }
443
+ closeAll() {
444
+ for (const key of [...this.sessions.keys()]) {
445
+ this.closeSession(key);
446
+ }
447
+ }
448
+ closeSession(key) {
449
+ const session = this.sessions.get(key);
450
+ if (!session)
451
+ return;
452
+ session.closed = true;
453
+ try {
454
+ session.pty.kill();
455
+ }
456
+ catch {
457
+ // best effort
458
+ }
459
+ this.sessions.delete(key);
460
+ }
461
+ createSession(key, provider, cwd) {
462
+ const ptyModule = loadNodePtyModule();
463
+ const cleanEnv = { ...process.env };
464
+ delete cleanEnv.CLAUDECODE;
465
+ delete cleanEnv.CLAUDE_CODE_ENTRYPOINT;
466
+ delete cleanEnv.CLAUDE_CODE_SESSION_ID;
467
+ let readyResolve = null;
468
+ const readyPromise = new Promise((resolve) => {
469
+ readyResolve = resolve;
470
+ });
471
+ const pty = provider === 'codex-cli'
472
+ ? ptyModule.spawn(findExecutableOnPath('codex.cmd') || 'codex.cmd', ['--no-alt-screen'], {
473
+ cwd,
474
+ cols: 160,
475
+ rows: 48,
476
+ env: cleanEnv,
477
+ useConpty: true,
478
+ name: 'xterm-color',
479
+ })
480
+ : ptyModule.spawn('cmd.exe', [], {
481
+ cwd,
482
+ cols: 160,
483
+ rows: 48,
484
+ env: cleanEnv,
485
+ useConpty: true,
486
+ name: 'xterm-color',
487
+ });
488
+ const session = {
489
+ key,
490
+ provider,
491
+ cwd,
492
+ pty,
493
+ createdAtMs: Date.now(),
494
+ lastUsedAtMs: Date.now(),
495
+ launchSnapshot: new Set(listSessionFiles(provider)),
496
+ sessionId: null,
497
+ sessionFilePath: null,
498
+ sessionFileOffset: 0,
499
+ sessionFileCarry: '',
500
+ readyPromise,
501
+ readyResolved: false,
502
+ waitForNextSendMs: 250,
503
+ startupDelayMs: provider === 'codex-cli' ? 9000 : 1200,
504
+ submitDelayMs: provider === 'codex-cli' ? 350 : 0,
505
+ currentPromptLocator: null,
506
+ currentPromptStartedAtMs: 0,
507
+ closed: false,
508
+ chain: Promise.resolve(),
509
+ };
510
+ pty.on('data', (chunk) => {
511
+ if (!session.readyResolved && chunk && chunk.trim()) {
512
+ session.readyResolved = true;
513
+ readyResolve?.();
514
+ }
515
+ });
516
+ pty.on('exit', () => {
517
+ session.closed = true;
518
+ this.sessions.delete(key);
519
+ });
520
+ if (provider === 'claude-cli') {
521
+ pty.write('claude\r');
522
+ }
523
+ return session;
524
+ }
525
+ async runTurnInternal(session, opts) {
526
+ session.lastUsedAtMs = Date.now();
527
+ await waitForFirstTerminalData(session);
528
+ if (session.closed) {
529
+ throw new Error(`${session.provider} PTY session closed before prompt was sent`);
530
+ }
531
+ if (session.waitForNextSendMs > 0) {
532
+ await delay(session.waitForNextSendMs);
533
+ }
534
+ const tracker = {
535
+ done: false,
536
+ finalContent: '',
537
+ usage: undefined,
538
+ lastAssistantText: '',
539
+ detailFingerprints: new Set(),
540
+ };
541
+ const timeoutMs = opts.timeoutMs ?? 10 * 60 * 1000;
542
+ const startedAtMs = Date.now();
543
+ const promptText = buildTurnPrompt(opts.provider, opts.systemPrompt, opts.messages, opts.forceFreshSession || !session.sessionFilePath);
544
+ session.currentPromptLocator = promptText.trim();
545
+ session.currentPromptStartedAtMs = startedAtMs;
546
+ await writeInteractivePrompt(session, promptText);
547
+ while (!tracker.done) {
548
+ if (Date.now() - startedAtMs > timeoutMs) {
549
+ throw new Error(`${opts.provider} PTY session timed out waiting for a response`);
550
+ }
551
+ if (session.closed) {
552
+ throw new Error(`${opts.provider} PTY session exited while waiting for a response`);
553
+ }
554
+ if (!session.sessionFilePath) {
555
+ const discovered = discoverSessionFile(session.provider, session.launchSnapshot, session.currentPromptStartedAtMs || session.createdAtMs, session.currentPromptLocator);
556
+ if (discovered) {
557
+ session.sessionFilePath = discovered;
558
+ session.sessionFileOffset = 0;
559
+ session.sessionFileCarry = '';
560
+ }
561
+ }
562
+ if (session.sessionFilePath && fs.existsSync(session.sessionFilePath)) {
563
+ await this.consumeSessionFile(session, tracker, opts.onDetail);
564
+ }
565
+ if (!tracker.done) {
566
+ await delay(250);
567
+ }
568
+ }
569
+ session.lastUsedAtMs = Date.now();
570
+ session.waitForNextSendMs = 400;
571
+ return {
572
+ content: tracker.finalContent.trim(),
573
+ sessionId: session.sessionId,
574
+ usage: tracker.usage,
575
+ };
576
+ }
577
+ async consumeSessionFile(session, tracker, onDetail) {
578
+ if (!session.sessionFilePath)
579
+ return;
580
+ let stat;
581
+ try {
582
+ stat = fs.statSync(session.sessionFilePath);
583
+ }
584
+ catch {
585
+ return;
586
+ }
587
+ if (stat.size <= session.sessionFileOffset)
588
+ return;
589
+ const fd = fs.openSync(session.sessionFilePath, 'r');
590
+ try {
591
+ const length = stat.size - session.sessionFileOffset;
592
+ const buffer = Buffer.alloc(length);
593
+ fs.readSync(fd, buffer, 0, length, session.sessionFileOffset);
594
+ session.sessionFileOffset = stat.size;
595
+ const text = session.sessionFileCarry + buffer.toString('utf8');
596
+ const lines = text.split('\n');
597
+ session.sessionFileCarry = lines.pop() || '';
598
+ for (const line of lines) {
599
+ const trimmed = line.trim();
600
+ if (!trimmed)
601
+ continue;
602
+ let record;
603
+ try {
604
+ record = JSON.parse(trimmed);
605
+ }
606
+ catch {
607
+ continue;
608
+ }
609
+ await this.applyRecord(session, tracker, record, onDetail);
610
+ }
611
+ }
612
+ finally {
613
+ fs.closeSync(fd);
614
+ }
615
+ }
616
+ async applyRecord(session, tracker, record, onDetail) {
617
+ const parsed = session.provider === 'claude-cli'
618
+ ? parseClaudeSessionRecord(record)
619
+ : parseCodexSessionRecord(record);
620
+ if (parsed.sessionId) {
621
+ session.sessionId = parsed.sessionId;
622
+ }
623
+ if (parsed.usage) {
624
+ tracker.usage = parsed.usage;
625
+ }
626
+ if (parsed.detail) {
627
+ await emitDetail(tracker, parsed.detail, onDetail);
628
+ }
629
+ if (parsed.finalContent) {
630
+ tracker.finalContent = parsed.finalContent;
631
+ tracker.lastAssistantText = parsed.finalContent;
632
+ }
633
+ if (parsed.done) {
634
+ tracker.done = true;
635
+ }
636
+ }
637
+ }
638
+ exports.LocalCliPtySessionManager = LocalCliPtySessionManager;
639
+ function getLocalCliPtySessionManager() {
640
+ if (!_manager) {
641
+ _manager = new LocalCliPtySessionManager();
642
+ }
643
+ return _manager;
644
+ }
645
+ //# sourceMappingURL=local-cli-pty-manager.js.map