maestro-flow 0.4.8 → 0.4.9
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/dashboard/dist/assets/{ArtifactsPage-CVh0Z2I2.js → ArtifactsPage-BLvAqQlQ.js} +1 -1
- package/dashboard/dist/assets/{ChatInput-CBI3qHQQ.js → ChatInput-DU9YGZKX.js} +1 -1
- package/dashboard/dist/assets/{ChatPage-BjJ9CYox.js → ChatPage-DYHfheXC.js} +1 -1
- package/dashboard/dist/assets/{CollabPage-CprGGO9y.js → CollabPage-CSlmvEa-.js} +1 -1
- package/dashboard/dist/assets/{ExecutionPanel-CClxD7cH.js → ExecutionPanel-RYWf0dYC.js} +1 -1
- package/dashboard/dist/assets/{KanbanPage-copqjdPg.js → KanbanPage-N55Iv0-X.js} +1 -1
- package/dashboard/dist/assets/{MaestroCoordinatePage-CioZjQ9N.js → MaestroCoordinatePage-BxwZ6yy5.js} +1 -1
- package/dashboard/dist/assets/{MarkdownRenderer-CtUhoxCT.js → MarkdownRenderer-ZGtOY7Ti.js} +1 -1
- package/dashboard/dist/assets/{McpPage-BcPPcJpr.js → McpPage-Im6s4pGR.js} +1 -1
- package/dashboard/dist/assets/{MeetingRoomPage-BgmAKxU-.js → MeetingRoomPage-CxHRn1xx.js} +1 -1
- package/dashboard/dist/assets/{OutputPanel-DgT3gMyp.js → OutputPanel-DaL8c1i5.js} +1 -1
- package/dashboard/dist/assets/{ProblemsPanel-BmG7rxoG.js → ProblemsPanel-BQTd5812.js} +1 -1
- package/dashboard/dist/assets/{RequirementBoardPage-k8YoeQ0r.js → RequirementBoardPage-22y9u1qh.js} +1 -1
- package/dashboard/dist/assets/{RequirementPage-Da2354px.js → RequirementPage-_mO743Xm.js} +1 -1
- package/dashboard/dist/assets/{RoomsPage-BtqDiYaU.js → RoomsPage-CExTbOGr.js} +1 -1
- package/dashboard/dist/assets/{SpecsPage-ByPVH_M3.js → SpecsPage-gr4KX51-.js} +1 -1
- package/dashboard/dist/assets/{TeamsPage-sFDLN30L.js → TeamsPage-BxEXLb5g.js} +1 -1
- package/dashboard/dist/assets/{TreeBrowser-oEx8YJXV.js → TreeBrowser-CVtPF5C9.js} +1 -1
- package/dashboard/dist/assets/{WorkflowPage-JrX7CVHh.js → WorkflowPage-BoN18Lhs.js} +1 -1
- package/dashboard/dist/assets/{arrow-left-DYvgSdIH.js → arrow-left-C5ROg97G.js} +1 -1
- package/dashboard/dist/assets/{check-jcgYBWVR.js → check-Bs8PM0tQ.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-DvZ5sMOg.js → chevron-right-SmErd_1F.js} +1 -1
- package/dashboard/dist/assets/{circle-DYT-zoRZ.js → circle-CjpslL_D.js} +1 -1
- package/dashboard/dist/assets/{circle-alert-Bfbv3gt4.js → circle-alert-CuzAg2fd.js} +1 -1
- package/dashboard/dist/assets/{circle-check-D82WnpbI.js → circle-check-BIkDU5D5.js} +1 -1
- package/dashboard/dist/assets/{circle-check-big-CPVD1GKF.js → circle-check-big-CYctV8bK.js} +1 -1
- package/dashboard/dist/assets/{code-B3bKFGI4.js → code-DoB7rfxt.js} +1 -1
- package/dashboard/dist/assets/{columns-3-BeMAQCix.js → columns-3-Ch5KIyRa.js} +1 -1
- package/dashboard/dist/assets/{download-BCtpoWYB.js → download-DadtG2Nr.js} +1 -1
- package/dashboard/dist/assets/{folder-CTj6SNNu.js → folder-B8ODoZfb.js} +1 -1
- package/dashboard/dist/assets/{index-BxR_3IbJ.js → index-BL4h1OKY.js} +1 -1
- package/dashboard/dist/assets/{index-DpcPd-UG.js → index-DQIlX2w_.js} +4 -4
- package/dashboard/dist/assets/{index-CWBJLu42.js → index-DaFwSmVJ.js} +10 -10
- package/dashboard/dist/assets/{list-BMv8pIQn.js → list-CI-XIPZh.js} +1 -1
- package/dashboard/dist/assets/{loader-DdM4VOgF.js → loader-DpdMoQvh.js} +1 -1
- package/dashboard/dist/assets/{minus-D15s2E__.js → minus-BVbfXGrC.js} +1 -1
- package/dashboard/dist/assets/{pen-line-DO6o4xWz.js → pen-line-CR8GaHt-.js} +1 -1
- package/dashboard/dist/assets/{pencil-qGxg9jOe.js → pencil-I7GE0y29.js} +1 -1
- package/dashboard/dist/assets/{proxy-DOffTzwA.js → proxy-CcYyZZWI.js} +1 -1
- package/dashboard/dist/assets/{refresh-cw-C9UNdLCy.js → refresh-cw-BG9V_T4R.js} +1 -1
- package/dashboard/dist/assets/{rows-2-CifAA5SL.js → rows-2-DP6NjQFk.js} +1 -1
- package/dashboard/dist/assets/{search-pe7pU1YN.js → search-b78eLlw2.js} +1 -1
- package/dashboard/dist/assets/{shallow-r7YynQYA.js → shallow-CJEesgtu.js} +1 -1
- package/dashboard/dist/assets/{table-Bh772iIw.js → table-B_lk-a1d.js} +1 -1
- package/dashboard/dist/assets/{team-types-C_HqX2p2.js → team-types-Se7f9LfJ.js} +1 -1
- package/dashboard/dist/assets/{terminal-EpmtGBlw.js → terminal-DXx4tvzq.js} +1 -1
- package/dashboard/dist/assets/{trash-2-Xen46iNQ.js → trash-2-CVh9mnRj.js} +1 -1
- package/dashboard/dist/assets/{users-BLueDPxF.js → users-Da9zGME5.js} +1 -1
- package/dashboard/dist/assets/{zap-DsQCPF61.js → zap-C0zaC7gJ.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/dashboard/dist-server/dashboard/src/server/agents/adapter-factory.js +4 -0
- package/dashboard/dist-server/dashboard/src/server/agents/adapter-factory.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/agents/agy-adapter.d.ts +39 -0
- package/dashboard/dist-server/dashboard/src/server/agents/agy-adapter.js +423 -0
- package/dashboard/dist-server/dashboard/src/server/agents/agy-adapter.js.map +1 -0
- package/dashboard/dist-server/dashboard/src/server/agents/codex-cli-adapter.d.ts +6 -0
- package/dashboard/dist-server/dashboard/src/server/agents/codex-cli-adapter.js +109 -0
- package/dashboard/dist-server/dashboard/src/server/agents/codex-cli-adapter.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/shared/constants.js +2 -0
- package/dashboard/dist-server/dashboard/src/shared/constants.js.map +1 -1
- package/dashboard/dist-server/shared/agent-types.d.ts +1 -1
- package/dist/shared/agent-types.d.ts +1 -1
- package/dist/shared/agent-types.d.ts.map +1 -1
- package/dist/src/agents/cli-agent-runner.d.ts.map +1 -1
- package/dist/src/agents/cli-agent-runner.js +3 -0
- package/dist/src/agents/cli-agent-runner.js.map +1 -1
- package/dist/src/commands/hooks.d.ts +64 -0
- package/dist/src/commands/hooks.d.ts.map +1 -1
- package/dist/src/commands/hooks.js +107 -0
- package/dist/src/commands/hooks.js.map +1 -1
- package/dist/src/commands/install.d.ts.map +1 -1
- package/dist/src/commands/install.js +17 -3
- package/dist/src/commands/install.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +53 -0
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/config/cli-tools-config.d.ts +19 -5
- package/dist/src/config/cli-tools-config.d.ts.map +1 -1
- package/dist/src/config/cli-tools-config.js +77 -32
- package/dist/src/config/cli-tools-config.js.map +1 -1
- package/dist/src/config/cli-tools-defaults.json +2 -1
- package/dist/src/core/component-defs.d.ts.map +1 -1
- package/dist/src/core/component-defs.js +53 -0
- package/dist/src/core/component-defs.js.map +1 -1
- package/dist/src/tui/install-ui/InstallExecution.d.ts.map +1 -1
- package/dist/src/tui/install-ui/InstallExecution.js +5 -3
- package/dist/src/tui/install-ui/InstallExecution.js.map +1 -1
- package/dist/src/utils/update-notices.d.ts +62 -0
- package/dist/src/utils/update-notices.d.ts.map +1 -0
- package/dist/src/utils/update-notices.js +178 -0
- package/dist/src/utils/update-notices.js.map +1 -0
- package/package.json +82 -82
- package/shared/agent-types.ts +1 -1
- package/workflows/agy-instructions.md +124 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// AgyAdapter — spawns the Antigravity (agy) CLI in non-interactive --print mode
|
|
3
|
+
//
|
|
4
|
+
// agy output strategy (transcript-first):
|
|
5
|
+
// In non-TTY mode (i.e. spawned by Node with piped stdio), agy writes
|
|
6
|
+
// **nothing** to stdout. The full conversation — user input, planner
|
|
7
|
+
// responses, tool calls, tool results — lands in
|
|
8
|
+
// ~/.gemini/antigravity-cli/brain/<conv>/.system_generated/logs/transcript.jsonl
|
|
9
|
+
//
|
|
10
|
+
// We locate the conversation for the current workspace via
|
|
11
|
+
// ~/.gemini/antigravity-cli/cache/last_conversations.json[workdir]
|
|
12
|
+
// (agy updates this map every run), then replay transcript entries that
|
|
13
|
+
// landed after our spawn timestamp.
|
|
14
|
+
//
|
|
15
|
+
// stdout is still wired up as a fallback in case a future agy build emits
|
|
16
|
+
// text there, but PLANNER_RESPONSE.content from the transcript is the
|
|
17
|
+
// authoritative assistant reply.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
import { spawn } from 'node:child_process';
|
|
20
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
21
|
+
import { join, resolve } from 'node:path';
|
|
22
|
+
import { homedir } from 'node:os';
|
|
23
|
+
import { createInterface } from 'node:readline';
|
|
24
|
+
import { BaseAgentAdapter } from './base-adapter.js';
|
|
25
|
+
import { EntryNormalizer } from './entry-normalizer.js';
|
|
26
|
+
import { loadEnvFile } from './env-file-loader.js';
|
|
27
|
+
import { StreamMonitor, DEFAULT_STREAM_TIMEOUT_MS } from './stream-monitor.js';
|
|
28
|
+
import { createStaleHandler } from './stale-handler.js';
|
|
29
|
+
import { killProcessTree } from './process-tree-kill.js';
|
|
30
|
+
import { cleanSpawnEnv } from './env-cleanup.js';
|
|
31
|
+
// Tool result-bearing entry types (model emits content as the result text).
|
|
32
|
+
const TOOL_RESULT_TYPES = new Set([
|
|
33
|
+
'LIST_DIRECTORY',
|
|
34
|
+
'VIEW_FILE',
|
|
35
|
+
'CODE_ACTION',
|
|
36
|
+
'GENERIC',
|
|
37
|
+
'GREP_SEARCH',
|
|
38
|
+
'SEARCH_WEB',
|
|
39
|
+
'RUN_COMMAND',
|
|
40
|
+
'READ_URL_CONTENT',
|
|
41
|
+
]);
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Path resolution
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
const DEFAULT_AGY_BIN_CANDIDATES = () => {
|
|
46
|
+
const candidates = [];
|
|
47
|
+
if (process.platform === 'win32') {
|
|
48
|
+
candidates.push(join(process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local'), 'agy', 'bin', 'agy.exe'));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
candidates.push(join(homedir(), '.local', 'bin', 'agy'));
|
|
52
|
+
candidates.push('/usr/local/bin/agy');
|
|
53
|
+
}
|
|
54
|
+
return candidates;
|
|
55
|
+
};
|
|
56
|
+
function resolveAgyBinary() {
|
|
57
|
+
for (const p of DEFAULT_AGY_BIN_CANDIDATES()) {
|
|
58
|
+
if (existsSync(p))
|
|
59
|
+
return p;
|
|
60
|
+
}
|
|
61
|
+
// Fall back to PATH resolution via shell.
|
|
62
|
+
return 'agy';
|
|
63
|
+
}
|
|
64
|
+
const AGY_BRAIN_DIR = join(homedir(), '.gemini', 'antigravity-cli', 'brain');
|
|
65
|
+
const AGY_LAST_CONV_FILE = join(homedir(), '.gemini', 'antigravity-cli', 'cache', 'last_conversations.json');
|
|
66
|
+
/** Case-insensitive path equality on Windows. */
|
|
67
|
+
function samePath(a, b) {
|
|
68
|
+
const left = resolve(a);
|
|
69
|
+
const right = resolve(b);
|
|
70
|
+
return process.platform === 'win32'
|
|
71
|
+
? left.toLowerCase() === right.toLowerCase()
|
|
72
|
+
: left === right;
|
|
73
|
+
}
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// Adapter implementation
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
export class AgyAdapter extends BaseAgentAdapter {
|
|
78
|
+
agentType = 'agy';
|
|
79
|
+
childProcesses = new Map();
|
|
80
|
+
readlineInterfaces = new Map();
|
|
81
|
+
streamMonitors = new Map();
|
|
82
|
+
stoppedEmitted = new Set();
|
|
83
|
+
spawnTimestamps = new Map();
|
|
84
|
+
textBuffers = new Map();
|
|
85
|
+
workDirs = new Map();
|
|
86
|
+
// --- Lifecycle hooks -----------------------------------------------------
|
|
87
|
+
async doSpawn(processId, config) {
|
|
88
|
+
// --print-timeout: convert ms → "<n>s" (agy uses Go duration format)
|
|
89
|
+
// Floor at 60s to give the agent room; ceiling at config.streamTimeoutMs.
|
|
90
|
+
const timeoutMs = config.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;
|
|
91
|
+
const timeoutSec = Math.max(60, Math.floor(timeoutMs / 1000));
|
|
92
|
+
const args = ['--print-timeout', `${timeoutSec}s`];
|
|
93
|
+
// approvalMode='auto' (write mode) → bypass permission prompts.
|
|
94
|
+
// 'suggest' (analysis mode) keeps defaults.
|
|
95
|
+
if (config.approvalMode === 'auto') {
|
|
96
|
+
args.push('--dangerously-skip-permissions');
|
|
97
|
+
}
|
|
98
|
+
// includeDirs and resume are threaded through config.metadata by the runner
|
|
99
|
+
// (see src/agents/cli-agent-runner.ts:331). Pick them up here.
|
|
100
|
+
const metadata = (config.metadata ?? {});
|
|
101
|
+
// Windows symlink workaround: agy's project discovery creates a symlink
|
|
102
|
+
// at <cwd>/.antigravitycli/<uuid>.json → ~/.gemini/config/projects/<uuid>.json.
|
|
103
|
+
// Without Developer Mode or admin, that symlink call fails and agy
|
|
104
|
+
// silently degrades — no auth, no API call, empty transcript. The home
|
|
105
|
+
// directory already has a working symlink from agy's first interactive
|
|
106
|
+
// run, so launching from there and exposing the real workdir via
|
|
107
|
+
// --add-dir gives agy a valid project context.
|
|
108
|
+
const requestedWorkDir = resolve(config.workDir ?? process.cwd());
|
|
109
|
+
const homeProjectDir = resolve(homedir());
|
|
110
|
+
const launchCwd = process.platform === 'win32' && !samePath(requestedWorkDir, homeProjectDir)
|
|
111
|
+
? homeProjectDir
|
|
112
|
+
: requestedWorkDir;
|
|
113
|
+
const includeDirs = new Set();
|
|
114
|
+
if (!samePath(launchCwd, requestedWorkDir)) {
|
|
115
|
+
includeDirs.add(requestedWorkDir);
|
|
116
|
+
}
|
|
117
|
+
if (metadata.includeDirs && metadata.includeDirs.length > 0) {
|
|
118
|
+
for (const dir of metadata.includeDirs) {
|
|
119
|
+
includeDirs.add(resolve(dir));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const dir of includeDirs) {
|
|
123
|
+
args.push('--add-dir', dir);
|
|
124
|
+
}
|
|
125
|
+
// Resume: agy supports -c (last) and --conversation <id>.
|
|
126
|
+
if (metadata.agyConversationId) {
|
|
127
|
+
args.push('--conversation', metadata.agyConversationId);
|
|
128
|
+
}
|
|
129
|
+
else if (metadata.agyResumeLast) {
|
|
130
|
+
args.push('-c');
|
|
131
|
+
}
|
|
132
|
+
// Prompt MUST use --prompt (or -p), NOT --print. agy's flag parser
|
|
133
|
+
// registers `--print` as boolean, so `--print "hi"` parses as
|
|
134
|
+
// `--print=true` + positional "hi", which hangs the run. `--prompt`
|
|
135
|
+
// and `-p` take the value as expected.
|
|
136
|
+
args.push('--prompt', config.prompt);
|
|
137
|
+
// Environment
|
|
138
|
+
const envFromFile = config.envFile ? loadEnvFile(config.envFile) : {};
|
|
139
|
+
const envOverrides = { ...envFromFile, ...config.env };
|
|
140
|
+
if (config.apiKey)
|
|
141
|
+
envOverrides.GEMINI_API_KEY = config.apiKey;
|
|
142
|
+
const childEnv = cleanSpawnEnv(envOverrides);
|
|
143
|
+
const bin = resolveAgyBinary();
|
|
144
|
+
const usesPath = bin === 'agy';
|
|
145
|
+
const spawnedAt = Date.now();
|
|
146
|
+
this.spawnTimestamps.set(processId, spawnedAt);
|
|
147
|
+
// last_conversations.json is keyed by the cwd agy was launched with —
|
|
148
|
+
// when we redirect to homedir, look up the conversation under that key.
|
|
149
|
+
this.workDirs.set(processId, launchCwd);
|
|
150
|
+
const child = spawn(bin, args, {
|
|
151
|
+
cwd: launchCwd,
|
|
152
|
+
env: childEnv,
|
|
153
|
+
// stdin must NOT be a pipe — agy --print waits for stdin EOF before
|
|
154
|
+
// processing the prompt argv, so leaving stdin open hangs the process.
|
|
155
|
+
// Using 'ignore' detaches stdin entirely (equivalent to closing it).
|
|
156
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
157
|
+
// Use shell only when falling back to PATH lookup; resolved absolute
|
|
158
|
+
// paths spawn directly so killProcessTree owns the whole tree.
|
|
159
|
+
shell: usesPath,
|
|
160
|
+
windowsHide: true,
|
|
161
|
+
detached: process.platform !== 'win32',
|
|
162
|
+
});
|
|
163
|
+
if (!child.stdout || !child.stderr) {
|
|
164
|
+
throw new Error('Failed to spawn agy: stdio streams not available');
|
|
165
|
+
}
|
|
166
|
+
// Stale-stream monitor — shared cascade with other adapters.
|
|
167
|
+
const monitor = new StreamMonitor(createStaleHandler({
|
|
168
|
+
processId,
|
|
169
|
+
child,
|
|
170
|
+
timeoutMs,
|
|
171
|
+
onStaleDetected: (message) => this.emitEntry(processId, EntryNormalizer.error(processId, message, 'stream_stale')),
|
|
172
|
+
isStopped: () => this.stoppedEmitted.has(processId),
|
|
173
|
+
emitStopped: (reason) => this.emitStopped(processId, reason),
|
|
174
|
+
}), timeoutMs);
|
|
175
|
+
this.streamMonitors.set(processId, monitor);
|
|
176
|
+
// stdout = plain-text assistant reply. We buffer chunks and re-emit each
|
|
177
|
+
// line as a (partial=false) assistant_message so the dashboard / TUI sees
|
|
178
|
+
// the response as it lands. A single combined message is emitted after
|
|
179
|
+
// exit to make the final transcript self-contained.
|
|
180
|
+
this.textBuffers.set(processId, '');
|
|
181
|
+
const rl = createInterface({ input: child.stdout });
|
|
182
|
+
rl.on('line', (line) => {
|
|
183
|
+
monitor.heartbeat();
|
|
184
|
+
const trimmed = line.trim();
|
|
185
|
+
if (trimmed.length === 0)
|
|
186
|
+
return;
|
|
187
|
+
const buf = this.textBuffers.get(processId) ?? '';
|
|
188
|
+
this.textBuffers.set(processId, buf.length === 0 ? trimmed : `${buf}\n${trimmed}`);
|
|
189
|
+
this.emitEntry(processId, EntryNormalizer.assistantMessage(processId, trimmed, true));
|
|
190
|
+
});
|
|
191
|
+
// stderr → error entries (skipped for transient progress noise).
|
|
192
|
+
child.stderr.on('data', (chunk) => {
|
|
193
|
+
const text = chunk.toString().trim();
|
|
194
|
+
if (text.length === 0)
|
|
195
|
+
return;
|
|
196
|
+
// agy prints progress lines like "Thinking..." to stderr — filter them.
|
|
197
|
+
if (/^(thinking|processing|loading|connecting)\b/i.test(text))
|
|
198
|
+
return;
|
|
199
|
+
this.emitEntry(processId, EntryNormalizer.error(processId, text, 'stderr'));
|
|
200
|
+
});
|
|
201
|
+
this.setupProcessListeners(child, processId);
|
|
202
|
+
this.childProcesses.set(processId, child);
|
|
203
|
+
this.readlineInterfaces.set(processId, rl);
|
|
204
|
+
return {
|
|
205
|
+
id: processId,
|
|
206
|
+
type: 'agy',
|
|
207
|
+
status: 'running',
|
|
208
|
+
config,
|
|
209
|
+
startedAt: new Date().toISOString(),
|
|
210
|
+
pid: child.pid,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async doStop(processId) {
|
|
214
|
+
const child = this.childProcesses.get(processId);
|
|
215
|
+
if (!child)
|
|
216
|
+
return;
|
|
217
|
+
const proc = this.getProcess(processId);
|
|
218
|
+
if (proc) {
|
|
219
|
+
proc.status = 'stopping';
|
|
220
|
+
this.emitEntry(processId, EntryNormalizer.statusChange(processId, 'stopping', 'User requested stop'));
|
|
221
|
+
}
|
|
222
|
+
killProcessTree(child.pid, 'SIGTERM');
|
|
223
|
+
const killTimer = setTimeout(() => {
|
|
224
|
+
if (!child.killed)
|
|
225
|
+
killProcessTree(child.pid, 'SIGKILL');
|
|
226
|
+
}, 5000);
|
|
227
|
+
child.once('exit', () => clearTimeout(killTimer));
|
|
228
|
+
this.cleanup(processId);
|
|
229
|
+
}
|
|
230
|
+
async doSendMessage(_processId, _content) {
|
|
231
|
+
// agy --print is single-shot; interactive mode would require -i (--prompt-interactive)
|
|
232
|
+
// which is out of scope for the headless delegate path.
|
|
233
|
+
throw new Error('agy does not support interactive messages in --print mode');
|
|
234
|
+
}
|
|
235
|
+
async doRespondApproval(_decision) {
|
|
236
|
+
// Approvals are gated client-side via --dangerously-skip-permissions.
|
|
237
|
+
}
|
|
238
|
+
// --- Transcript enrichment ----------------------------------------------
|
|
239
|
+
/**
|
|
240
|
+
* Locate the conversationId agy used for this workspace on this run.
|
|
241
|
+
*
|
|
242
|
+
* Strategy:
|
|
243
|
+
* 1. Read cache/last_conversations.json — agy writes the
|
|
244
|
+
* workspace→conversationId map on every run. If the cache mtime is
|
|
245
|
+
* after our spawn and the workdir key resolves, return that id.
|
|
246
|
+
* 2. Fall back to scanning brain/ directories for a transcript.jsonl
|
|
247
|
+
* touched after our spawn (legacy heuristic; handles edge cases where
|
|
248
|
+
* the cache write is delayed).
|
|
249
|
+
*/
|
|
250
|
+
resolveConversationId(processId) {
|
|
251
|
+
const spawnedAt = this.spawnTimestamps.get(processId) ?? 0;
|
|
252
|
+
const workdir = this.workDirs.get(processId);
|
|
253
|
+
if (workdir && existsSync(AGY_LAST_CONV_FILE)) {
|
|
254
|
+
try {
|
|
255
|
+
const stat = statSync(AGY_LAST_CONV_FILE);
|
|
256
|
+
// Allow ±1s clock skew between Node's Date.now() and agy's file write.
|
|
257
|
+
if (stat.mtimeMs >= spawnedAt - 1000) {
|
|
258
|
+
const data = JSON.parse(readFileSync(AGY_LAST_CONV_FILE, 'utf8'));
|
|
259
|
+
if (data[workdir])
|
|
260
|
+
return data[workdir];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// fall through to brain scan
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!existsSync(AGY_BRAIN_DIR))
|
|
268
|
+
return undefined;
|
|
269
|
+
let latest = null;
|
|
270
|
+
try {
|
|
271
|
+
for (const entry of readdirSync(AGY_BRAIN_DIR, { withFileTypes: true })) {
|
|
272
|
+
if (!entry.isDirectory())
|
|
273
|
+
continue;
|
|
274
|
+
const transcriptPath = join(AGY_BRAIN_DIR, entry.name, '.system_generated', 'logs', 'transcript.jsonl');
|
|
275
|
+
if (!existsSync(transcriptPath))
|
|
276
|
+
continue;
|
|
277
|
+
const mtime = statSync(transcriptPath).mtimeMs;
|
|
278
|
+
if (mtime < spawnedAt - 1000)
|
|
279
|
+
continue;
|
|
280
|
+
if (!latest || mtime > latest.mtime)
|
|
281
|
+
latest = { id: entry.name, mtime };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
return latest?.id;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* After the agy process exits, locate the conversation transcript for our
|
|
291
|
+
* workspace and replay the entries that landed during our turn. The
|
|
292
|
+
* PLANNER_RESPONSE.content carries the model's actual reply text — that's
|
|
293
|
+
* the primary assistant_message source since stdout is empty in non-TTY
|
|
294
|
+
* mode. Tool calls and intermediate results become tool_use entries.
|
|
295
|
+
*/
|
|
296
|
+
enrichFromTranscript(processId) {
|
|
297
|
+
const spawnedAt = this.spawnTimestamps.get(processId) ?? 0;
|
|
298
|
+
const conversationId = this.resolveConversationId(processId);
|
|
299
|
+
if (!conversationId)
|
|
300
|
+
return;
|
|
301
|
+
const transcriptPath = join(AGY_BRAIN_DIR, conversationId, '.system_generated', 'logs', 'transcript.jsonl');
|
|
302
|
+
if (!existsSync(transcriptPath))
|
|
303
|
+
return;
|
|
304
|
+
let content;
|
|
305
|
+
try {
|
|
306
|
+
content = readFileSync(transcriptPath, 'utf8');
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
// Replay entries written after our spawn (with 1s skew tolerance).
|
|
312
|
+
const cutoff = new Date(spawnedAt - 1000).toISOString();
|
|
313
|
+
const ourEntries = [];
|
|
314
|
+
for (const line of content.split('\n')) {
|
|
315
|
+
if (line.trim().length === 0)
|
|
316
|
+
continue;
|
|
317
|
+
let entry;
|
|
318
|
+
try {
|
|
319
|
+
entry = JSON.parse(line);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (entry.created_at && entry.created_at >= cutoff) {
|
|
325
|
+
ourEntries.push(entry);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
let emittedAssistant = false;
|
|
329
|
+
for (const entry of ourEntries) {
|
|
330
|
+
if (entry.source === 'MODEL' && entry.type === 'PLANNER_RESPONSE') {
|
|
331
|
+
if (entry.thinking && entry.thinking.trim().length > 0) {
|
|
332
|
+
this.emitEntry(processId, EntryNormalizer.thinking(processId, entry.thinking.trim()));
|
|
333
|
+
}
|
|
334
|
+
if (entry.content && entry.content.trim().length > 0) {
|
|
335
|
+
this.emitEntry(processId, EntryNormalizer.assistantMessage(processId, entry.content.trim(), false));
|
|
336
|
+
emittedAssistant = true;
|
|
337
|
+
}
|
|
338
|
+
if (entry.tool_calls && entry.tool_calls.length > 0) {
|
|
339
|
+
for (const call of entry.tool_calls) {
|
|
340
|
+
const name = call.name ?? 'unknown';
|
|
341
|
+
const input = call.args ?? {};
|
|
342
|
+
this.emitEntry(processId, EntryNormalizer.toolUse(processId, name, input, 'running'));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (entry.source === 'MODEL' && TOOL_RESULT_TYPES.has(entry.type)) {
|
|
348
|
+
const result = entry.content ?? '';
|
|
349
|
+
const status = entry.status === 'ERROR' ? 'failed' : 'completed';
|
|
350
|
+
this.emitEntry(processId, EntryNormalizer.toolUse(processId, entry.type.toLowerCase(), {}, status, result.slice(0, 4000)));
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (entry.source === 'SYSTEM' && entry.type === 'ERROR_MESSAGE') {
|
|
354
|
+
const msg = entry.error ?? entry.content ?? 'Unknown agy error';
|
|
355
|
+
this.emitEntry(processId, EntryNormalizer.error(processId, msg, 'agy_transcript_error'));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Fallback: if the transcript produced no PLANNER_RESPONSE.content but
|
|
359
|
+
// stdout buffered something (future TTY support), surface that.
|
|
360
|
+
if (!emittedAssistant) {
|
|
361
|
+
const buffered = this.textBuffers.get(processId);
|
|
362
|
+
if (buffered && buffered.trim().length > 0) {
|
|
363
|
+
this.emitEntry(processId, EntryNormalizer.assistantMessage(processId, buffered.trim(), false));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Record conversationId so a follow-up `maestro delegate --resume`
|
|
367
|
+
// can pass it via --conversation.
|
|
368
|
+
this.emitEntry(processId, EntryNormalizer.statusChange(processId, 'running', `agy.conversationId=${conversationId}`));
|
|
369
|
+
}
|
|
370
|
+
// --- Helpers -------------------------------------------------------------
|
|
371
|
+
setupProcessListeners(child, processId) {
|
|
372
|
+
child.on('exit', (code, signal) => {
|
|
373
|
+
const reason = signal ? `Terminated by signal: ${signal}` : `Exited with code: ${code ?? 'unknown'}`;
|
|
374
|
+
this.emitStopped(processId, reason);
|
|
375
|
+
});
|
|
376
|
+
child.on('close', (code, signal) => {
|
|
377
|
+
const reason = signal ? `Terminated by signal: ${signal}` : `Exited with code: ${code ?? 'unknown'}`;
|
|
378
|
+
this.emitStopped(processId, reason);
|
|
379
|
+
});
|
|
380
|
+
child.on('error', (err) => {
|
|
381
|
+
this.emitEntry(processId, EntryNormalizer.error(processId, err.message, 'spawn_error'));
|
|
382
|
+
const proc = this.getProcess(processId);
|
|
383
|
+
if (proc)
|
|
384
|
+
proc.status = 'error';
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
emitStopped(processId, reason) {
|
|
388
|
+
if (this.stoppedEmitted.has(processId))
|
|
389
|
+
return;
|
|
390
|
+
this.stoppedEmitted.add(processId);
|
|
391
|
+
// Enrich with transcript-derived entries BEFORE emitting the terminal
|
|
392
|
+
// status change so consumers see tool history before stop.
|
|
393
|
+
try {
|
|
394
|
+
this.enrichFromTranscript(processId);
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
// enrichment is best-effort and must never block the stop signal
|
|
398
|
+
}
|
|
399
|
+
this.emitEntry(processId, EntryNormalizer.statusChange(processId, 'stopped', reason));
|
|
400
|
+
const proc = this.getProcess(processId);
|
|
401
|
+
if (proc)
|
|
402
|
+
proc.status = 'stopped';
|
|
403
|
+
this.cleanup(processId);
|
|
404
|
+
this.removeProcess(processId);
|
|
405
|
+
}
|
|
406
|
+
cleanup(processId) {
|
|
407
|
+
const rl = this.readlineInterfaces.get(processId);
|
|
408
|
+
if (rl) {
|
|
409
|
+
rl.close();
|
|
410
|
+
this.readlineInterfaces.delete(processId);
|
|
411
|
+
}
|
|
412
|
+
const monitor = this.streamMonitors.get(processId);
|
|
413
|
+
if (monitor) {
|
|
414
|
+
monitor.dispose();
|
|
415
|
+
this.streamMonitors.delete(processId);
|
|
416
|
+
}
|
|
417
|
+
this.childProcesses.delete(processId);
|
|
418
|
+
this.spawnTimestamps.delete(processId);
|
|
419
|
+
this.textBuffers.delete(processId);
|
|
420
|
+
this.workDirs.delete(processId);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
//# sourceMappingURL=agy-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agy-adapter.js","sourceRoot":"","sources":["../../../../../src/server/agents/agy-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,12 @@ export declare class CodexCliAdapter extends BaseAgentAdapter {
|
|
|
14
14
|
protected doRespondApproval(_decision: ApprovalDecision): Promise<void>;
|
|
15
15
|
private parseCodexMessage;
|
|
16
16
|
private classifyItem;
|
|
17
|
+
/** Map codex item status/error fields to ToolUseEntry status. */
|
|
18
|
+
private codexStatusToToolStatus;
|
|
19
|
+
/** Parse codex function/tool `arguments` (JSON string) into an object; tolerate non-JSON. */
|
|
20
|
+
private parseArguments;
|
|
21
|
+
/** Heuristic: does this item.type look like a tool/shell call we should treat as a boundary? */
|
|
22
|
+
private isToolLikeType;
|
|
17
23
|
private isCommandCall;
|
|
18
24
|
private isFileCall;
|
|
19
25
|
private inferFileAction;
|
|
@@ -320,6 +320,41 @@ export class CodexCliAdapter extends BaseAgentAdapter {
|
|
|
320
320
|
classifyItem(item, processId) {
|
|
321
321
|
const itemType = item.type ?? '';
|
|
322
322
|
const itemName = (item.name ?? '').toLowerCase();
|
|
323
|
+
// Reasoning / thinking content — route to thinking, not assistant_message.
|
|
324
|
+
// Codex newer builds may surface model reasoning as items; without this
|
|
325
|
+
// branch, reasoning text would pollute the final assistant reply extraction.
|
|
326
|
+
if (itemType === 'reasoning' || itemType === 'agent_reasoning') {
|
|
327
|
+
const text = this.extractItemText(item);
|
|
328
|
+
if (text.length > 0) {
|
|
329
|
+
this.emitEntry(processId, EntryNormalizer.thinking(processId, text));
|
|
330
|
+
}
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
// Codex shell tool: explicit `command_execution` item shape
|
|
334
|
+
// (id, command, aggregated_output, exit_code, status). Emit as command_exec
|
|
335
|
+
// boundary so extractLastReply can split segments correctly.
|
|
336
|
+
if (itemType === 'command_execution') {
|
|
337
|
+
const command = item.command ?? item.name ?? 'shell';
|
|
338
|
+
this.emitEntry(processId, EntryNormalizer.commandExec(processId, command, typeof item.exit_code === 'number' ? item.exit_code : undefined, item.aggregated_output ?? item.output ?? ''));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
// Codex MCP tool call: explicit `mcp_tool_call` item shape
|
|
342
|
+
// (server, tool, arguments, result, error, status). Emit as tool_use
|
|
343
|
+
// boundary so extractLastReply can split segments correctly.
|
|
344
|
+
if (itemType === 'mcp_tool_call') {
|
|
345
|
+
const name = `${item.server ?? 'mcp'}/${item.tool ?? itemName ?? '?'}`;
|
|
346
|
+
const input = this.parseArguments(item.arguments);
|
|
347
|
+
const status = this.codexStatusToToolStatus(item);
|
|
348
|
+
const resultText = item.error
|
|
349
|
+
? String(item.error)
|
|
350
|
+
: item.result === undefined
|
|
351
|
+
? ''
|
|
352
|
+
: typeof item.result === 'string'
|
|
353
|
+
? item.result
|
|
354
|
+
: JSON.stringify(item.result);
|
|
355
|
+
this.emitEntry(processId, EntryNormalizer.toolUse(processId, name, input, status, resultText));
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
323
358
|
// Function call that looks like a command execution
|
|
324
359
|
if (itemType === 'function_call_output' ||
|
|
325
360
|
(itemType === 'function_call' && this.isCommandCall(itemName)) ||
|
|
@@ -336,6 +371,25 @@ export class CodexCliAdapter extends BaseAgentAdapter {
|
|
|
336
371
|
this.emitEntry(processId, EntryNormalizer.fileChange(processId, filePath, action, item.diff));
|
|
337
372
|
return;
|
|
338
373
|
}
|
|
374
|
+
// Safety net: any item whose type smells like a tool/shell call but isn't
|
|
375
|
+
// handled above (e.g. future codex types like `web_search_call`,
|
|
376
|
+
// `local_shell_call`, `custom_tool_call`, `*_output`). Emit as boundary
|
|
377
|
+
// tool_use to prevent JSON.stringify pollution of assistant_message.
|
|
378
|
+
if (this.isToolLikeType(itemType)) {
|
|
379
|
+
const name = item.name ?? item.tool ?? itemType;
|
|
380
|
+
const output = typeof item.output === 'string'
|
|
381
|
+
? item.output
|
|
382
|
+
: typeof item.aggregated_output === 'string'
|
|
383
|
+
? item.aggregated_output
|
|
384
|
+
: item.result !== undefined
|
|
385
|
+
? typeof item.result === 'string'
|
|
386
|
+
? item.result
|
|
387
|
+
: JSON.stringify(item.result)
|
|
388
|
+
: '';
|
|
389
|
+
const status = this.codexStatusToToolStatus(item);
|
|
390
|
+
this.emitEntry(processId, EntryNormalizer.toolUse(processId, name, this.parseArguments(item.arguments), status, output));
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
339
393
|
// Default: treat as assistant message — accumulate within turn,
|
|
340
394
|
// emit as partial now (for streaming display) and flush final on turn.completed
|
|
341
395
|
const text = this.extractItemText(item);
|
|
@@ -350,6 +404,61 @@ export class CodexCliAdapter extends BaseAgentAdapter {
|
|
|
350
404
|
this.emitEntry(processId, EntryNormalizer.assistantMessage(processId, text, true));
|
|
351
405
|
}
|
|
352
406
|
}
|
|
407
|
+
/** Map codex item status/error fields to ToolUseEntry status. */
|
|
408
|
+
codexStatusToToolStatus(item) {
|
|
409
|
+
if (item.error)
|
|
410
|
+
return 'failed';
|
|
411
|
+
switch (item.status) {
|
|
412
|
+
case 'error':
|
|
413
|
+
case 'failed':
|
|
414
|
+
return 'failed';
|
|
415
|
+
case 'pending':
|
|
416
|
+
case 'queued':
|
|
417
|
+
return 'pending';
|
|
418
|
+
case 'running':
|
|
419
|
+
case 'in_progress':
|
|
420
|
+
return 'running';
|
|
421
|
+
case 'success':
|
|
422
|
+
case 'completed':
|
|
423
|
+
case 'done':
|
|
424
|
+
default:
|
|
425
|
+
return 'completed';
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
/** Parse codex function/tool `arguments` (JSON string) into an object; tolerate non-JSON. */
|
|
429
|
+
parseArguments(raw) {
|
|
430
|
+
if (raw === undefined || raw === null)
|
|
431
|
+
return {};
|
|
432
|
+
if (typeof raw === 'object')
|
|
433
|
+
return raw;
|
|
434
|
+
if (typeof raw === 'string') {
|
|
435
|
+
const trimmed = raw.trim();
|
|
436
|
+
if (!trimmed)
|
|
437
|
+
return {};
|
|
438
|
+
try {
|
|
439
|
+
const parsed = JSON.parse(trimmed);
|
|
440
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
441
|
+
return parsed;
|
|
442
|
+
}
|
|
443
|
+
return { value: parsed };
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
return { raw };
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return { value: raw };
|
|
450
|
+
}
|
|
451
|
+
/** Heuristic: does this item.type look like a tool/shell call we should treat as a boundary? */
|
|
452
|
+
isToolLikeType(type) {
|
|
453
|
+
if (!type)
|
|
454
|
+
return false;
|
|
455
|
+
return (type.endsWith('_call') ||
|
|
456
|
+
type.endsWith('_call_output') ||
|
|
457
|
+
type.endsWith('_call_end') ||
|
|
458
|
+
type.endsWith('_execution') ||
|
|
459
|
+
type.endsWith('_output') ||
|
|
460
|
+
/tool|shell|exec|search|patch|file_change/.test(type));
|
|
461
|
+
}
|
|
353
462
|
isCommandCall(name) {
|
|
354
463
|
return /exec|shell|command|run|bash/.test(name);
|
|
355
464
|
}
|