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.
- package/dist/agent-config.d.ts +9 -1
- package/dist/agent-config.d.ts.map +1 -1
- package/dist/agent-config.js +4 -1
- package/dist/agent-config.js.map +1 -1
- package/dist/auth/auto-detect.d.ts +1 -0
- package/dist/auth/auto-detect.d.ts.map +1 -1
- package/dist/auth/auto-detect.js +16 -13
- package/dist/auth/auto-detect.js.map +1 -1
- package/dist/auto-organizer.d.ts.map +1 -1
- package/dist/auto-organizer.js +4 -3
- package/dist/auto-organizer.js.map +1 -1
- package/dist/backfill.d.ts.map +1 -1
- package/dist/backfill.js +3 -2
- package/dist/backfill.js.map +1 -1
- package/dist/bot-manager.d.ts +8 -23
- package/dist/bot-manager.d.ts.map +1 -1
- package/dist/bot-manager.js +61 -388
- package/dist/bot-manager.js.map +1 -1
- package/dist/clerk-model.d.ts +5 -1
- package/dist/clerk-model.d.ts.map +1 -1
- package/dist/clerk-model.js +40 -28
- package/dist/clerk-model.js.map +1 -1
- package/dist/cli-session-epoch.d.ts +10 -0
- package/dist/cli-session-epoch.d.ts.map +1 -0
- package/dist/cli-session-epoch.js +61 -0
- package/dist/cli-session-epoch.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +30 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pool.js +1 -1
- package/dist/commands/pool.js.map +1 -1
- package/dist/commands/setup.d.ts +37 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +154 -43
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +195 -164
- package/dist/commands/start.js.map +1 -1
- package/dist/config-cleanup.d.ts.map +1 -1
- package/dist/config-cleanup.js +2 -1
- package/dist/config-cleanup.js.map +1 -1
- package/dist/config.d.ts +6 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -30
- package/dist/config.js.map +1 -1
- package/dist/context-window.d.ts +33 -5
- package/dist/context-window.d.ts.map +1 -1
- package/dist/context-window.js +121 -20
- package/dist/context-window.js.map +1 -1
- package/dist/eval/orchestrator-front-door-replay.js +1 -1
- package/dist/eval/orchestrator-front-door-replay.js.map +1 -1
- package/dist/eval/policy-detection-replay.js +1 -1
- package/dist/eval/policy-detection-replay.js.map +1 -1
- package/dist/integration-tokens.d.ts +1 -6
- package/dist/integration-tokens.d.ts.map +1 -1
- package/dist/integration-tokens.js +38 -40
- package/dist/integration-tokens.js.map +1 -1
- package/dist/local-cli-pty-manager.d.ts +50 -0
- package/dist/local-cli-pty-manager.d.ts.map +1 -0
- package/dist/local-cli-pty-manager.js +645 -0
- package/dist/local-cli-pty-manager.js.map +1 -0
- package/dist/local-data.d.ts +30 -0
- package/dist/local-data.d.ts.map +1 -1
- package/dist/local-data.js +56 -1
- package/dist/local-data.js.map +1 -1
- package/dist/local-db.d.ts.map +1 -1
- package/dist/local-db.js +54 -1
- package/dist/local-db.js.map +1 -1
- package/dist/local-funnel.d.ts.map +1 -1
- package/dist/local-funnel.js +3 -2
- package/dist/local-funnel.js.map +1 -1
- package/dist/local-memory-search.d.ts +1 -0
- package/dist/local-memory-search.d.ts.map +1 -1
- package/dist/local-memory-search.js +101 -18
- package/dist/local-memory-search.js.map +1 -1
- package/dist/local-server.d.ts +0 -16
- package/dist/local-server.d.ts.map +1 -1
- package/dist/local-server.js +339 -287
- package/dist/local-server.js.map +1 -1
- package/dist/mcp/bridge-server.d.ts.map +1 -1
- package/dist/mcp/bridge-server.js +2 -1
- package/dist/mcp/bridge-server.js.map +1 -1
- package/dist/mcp/local-memory-server.d.ts +5 -0
- package/dist/mcp/local-memory-server.d.ts.map +1 -1
- package/dist/mcp/local-memory-server.js +15 -2
- package/dist/mcp/local-memory-server.js.map +1 -1
- package/dist/mcp/manager.d.ts +3 -22
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +66 -388
- package/dist/mcp/manager.js.map +1 -1
- package/dist/memory-extraction.d.ts +2 -0
- package/dist/memory-extraction.d.ts.map +1 -1
- package/dist/memory-extraction.js +3 -1
- package/dist/memory-extraction.js.map +1 -1
- package/dist/message-loop.d.ts +10 -6
- package/dist/message-loop.d.ts.map +1 -1
- package/dist/message-loop.js +241 -540
- package/dist/message-loop.js.map +1 -1
- package/dist/mqtt-client.d.ts +2 -31
- package/dist/mqtt-client.d.ts.map +1 -1
- package/dist/mqtt-client.js +2 -2
- package/dist/mqtt-client.js.map +1 -1
- package/dist/oauth.d.ts +6 -0
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +91 -0
- package/dist/oauth.js.map +1 -1
- package/dist/orchestration/front-door-policy.d.ts +5 -2
- package/dist/orchestration/front-door-policy.d.ts.map +1 -1
- package/dist/orchestration/front-door-policy.js +25 -28
- package/dist/orchestration/front-door-policy.js.map +1 -1
- package/dist/orchestration/orchestrator-blocked-prompt.js +1 -1
- package/dist/orchestration/orchestrator-final-response-prompt.js +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.d.ts +11 -0
- package/dist/orchestration/orchestrator-operating-prompt.d.ts.map +1 -1
- package/dist/orchestration/orchestrator-operating-prompt.js +67 -44
- package/dist/orchestration/orchestrator-operating-prompt.js.map +1 -1
- package/dist/orchestration/worker-operating-prompt.js +3 -3
- package/dist/orchestration/worker-operating-prompt.js.map +1 -1
- package/dist/orchestrator.d.ts +5 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +141 -81
- package/dist/orchestrator.js.map +1 -1
- package/dist/prompt-template.js +3 -3
- package/dist/prompt-template.js.map +1 -1
- package/dist/providers/claude-cli-prompt.d.ts.map +1 -1
- package/dist/providers/claude-cli-prompt.js +22 -6
- package/dist/providers/claude-cli-prompt.js.map +1 -1
- package/dist/providers/claude-cli.d.ts.map +1 -1
- package/dist/providers/claude-cli.js +20 -2
- package/dist/providers/claude-cli.js.map +1 -1
- package/dist/providers/codex-cli.d.ts.map +1 -1
- package/dist/providers/codex-cli.js +71 -16
- package/dist/providers/codex-cli.js.map +1 -1
- package/dist/providers/index.d.ts +11 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/runtime-context.d.ts +10 -0
- package/dist/runtime-context.d.ts.map +1 -0
- package/dist/runtime-context.js +30 -0
- package/dist/runtime-context.js.map +1 -0
- package/dist/subagent/queue.d.ts.map +1 -1
- package/dist/subagent/queue.js +1 -0
- package/dist/subagent/queue.js.map +1 -1
- package/dist/summarization-pipeline.d.ts +1 -0
- package/dist/summarization-pipeline.d.ts.map +1 -1
- package/dist/summarization-pipeline.js +94 -25
- package/dist/summarization-pipeline.js.map +1 -1
- package/dist/tool-permissions.d.ts +2 -0
- package/dist/tool-permissions.d.ts.map +1 -0
- package/dist/tool-permissions.js +25 -0
- package/dist/tool-permissions.js.map +1 -0
- package/dist/tools/index.d.ts +7 -8
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +70 -60
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/search-memory.d.ts.map +1 -1
- package/dist/tools/search-memory.js +9 -3
- package/dist/tools/search-memory.js.map +1 -1
- package/dist/tools/spawn-subagent.d.ts.map +1 -1
- package/dist/tools/spawn-subagent.js +1 -0
- package/dist/tools/spawn-subagent.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +1 -1
- package/dist/wizard-support.d.ts.map +1 -1
- package/dist/wizard-support.js +8 -6
- package/dist/wizard-support.js.map +1 -1
- package/dist/workflow-engine.d.ts +6 -2
- package/dist/workflow-engine.d.ts.map +1 -1
- package/dist/workflow-engine.js +254 -77
- package/dist/workflow-engine.js.map +1 -1
- 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
|