@mndrk/agx 1.4.63 → 1.4.65
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/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/BUILD_ID +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-build-manifest.json +60 -60
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-path-routes-manifest.json +13 -13
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/build-manifest.json +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/prerender-manifest.json +9 -9
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.html +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.rsc +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/audit/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/[...nextauth]/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/daemon-secret/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/code/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/token/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/refresh/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/[id]/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/learnings/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/logs/stream/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/start/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/status/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/complete/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/stage-prompts/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/[commentId]/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/costs/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/dependencies/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/heartbeat/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/history/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/stream/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/restart-stage/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/stream/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/user-settings/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/nodes/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/callback/route_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page.js +4 -4
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.html +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.rsc +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.html +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.rsc +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.html +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.rsc +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.html +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.rsc +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.html +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.rsc +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.html +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.rsc +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app-paths-manifest.json +13 -13
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/functions-config-manifest.json +2 -2
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/middleware-manifest.json +5 -5
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/404.html +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/500.html +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.js +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.json +1 -1
- package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/{page-06eeddaf1bb867c3.js → page-bd5f443ef9da0c0a.js} +1 -1
- package/index.js +1 -0
- package/lib/cli/runCli.js +217 -3
- package/lib/cloud-sync.js +267 -0
- package/lib/executor.js +315 -9
- package/lib/prompts/resume.js +353 -0
- package/lib/storage/checkpoints.js +222 -0
- package/lib/storage/git.js +147 -0
- package/lib/storage/index.js +7 -0
- package/lib/verify-gate.js +301 -0
- package/package.json +1 -1
- /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{o_Dsarly6P4c-yqsBEkNM → FYPvFkL9PvoVJhHnr9Upx}/_buildManifest.js +0 -0
- /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{o_Dsarly6P4c-yqsBEkNM → FYPvFkL9PvoVJhHnr9Upx}/_ssgManifest.js +0 -0
package/lib/executor.js
CHANGED
|
@@ -11,6 +11,17 @@ const path = require('path');
|
|
|
11
11
|
const os = require('os');
|
|
12
12
|
const { commandExists } = require('./proc/commandExists');
|
|
13
13
|
const { interpolate, DEFAULT_STAGE_PROMPT, PROJECT_CONTEXT, EXECUTOR_PROMPT } = require('./prompts/templates');
|
|
14
|
+
const { createCheckpoint, checkpointsPath } = require('./storage/checkpoints');
|
|
15
|
+
const { captureGitState } = require('./storage/git');
|
|
16
|
+
const { createCloudSyncer } = require('./cloud-sync');
|
|
17
|
+
const { runVerifyGate } = require('./verify-gate');
|
|
18
|
+
|
|
19
|
+
let json5;
|
|
20
|
+
try {
|
|
21
|
+
json5 = require('json5');
|
|
22
|
+
} catch {
|
|
23
|
+
json5 = null;
|
|
24
|
+
}
|
|
14
25
|
|
|
15
26
|
// Engine configurations
|
|
16
27
|
const ENGINES = {
|
|
@@ -99,8 +110,143 @@ async function executeTask(options) {
|
|
|
99
110
|
onLog,
|
|
100
111
|
onProgress,
|
|
101
112
|
onStream,
|
|
113
|
+
projectSlug,
|
|
114
|
+
taskSlug,
|
|
115
|
+
iteration = 1,
|
|
116
|
+
objective,
|
|
117
|
+
constraints,
|
|
118
|
+
dontRepeat,
|
|
119
|
+
verifyFailures,
|
|
120
|
+
plan: initialPlan,
|
|
121
|
+
criteria: initialCriteria,
|
|
122
|
+
repoPath,
|
|
102
123
|
} = options;
|
|
103
124
|
|
|
125
|
+
const iterationValue = (() => {
|
|
126
|
+
const parsed = Number(iteration);
|
|
127
|
+
if (Number.isFinite(parsed) && parsed >= 1) {
|
|
128
|
+
return parsed;
|
|
129
|
+
}
|
|
130
|
+
return 1;
|
|
131
|
+
})();
|
|
132
|
+
|
|
133
|
+
const gitCwd = typeof repoPath === 'string' && repoPath ? repoPath : process.cwd();
|
|
134
|
+
|
|
135
|
+
const executionState = {
|
|
136
|
+
plan: initialPlan || null,
|
|
137
|
+
criteria: initialCriteria || null,
|
|
138
|
+
};
|
|
139
|
+
const cloudSyncer = (() => {
|
|
140
|
+
if (!projectSlug || !taskSlug || !options.cloudTaskId) return null;
|
|
141
|
+
try {
|
|
142
|
+
return createCloudSyncer({
|
|
143
|
+
taskRoot: path.dirname(checkpointsPath(projectSlug, taskSlug)),
|
|
144
|
+
cloudTaskId: options.cloudTaskId,
|
|
145
|
+
onLog,
|
|
146
|
+
});
|
|
147
|
+
} catch (err) {
|
|
148
|
+
onLog?.(`[cloud-sync] init failed: ${err?.message || err}`);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
})();
|
|
152
|
+
|
|
153
|
+
const ensureDefaultPlan = () => {
|
|
154
|
+
if (!executionState.plan && iterationValue === 1) {
|
|
155
|
+
executionState.plan = createDefaultPlan();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const captureGitStateSafe = () => {
|
|
160
|
+
try {
|
|
161
|
+
return captureGitState(gitCwd);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
onLog?.(`[checkpoint] unable to record git state: ${err?.message || err}`);
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const persistCheckpoint = async (label) => {
|
|
169
|
+
if (!projectSlug || !taskSlug) return;
|
|
170
|
+
const trimmedLabel = (label || '').toString().trim();
|
|
171
|
+
if (!trimmedLabel) return;
|
|
172
|
+
|
|
173
|
+
ensureDefaultPlan();
|
|
174
|
+
const checkpointPayload = {
|
|
175
|
+
label: trimmedLabel,
|
|
176
|
+
iteration: iterationValue,
|
|
177
|
+
objective,
|
|
178
|
+
plan: executionState.plan,
|
|
179
|
+
criteria: executionState.criteria,
|
|
180
|
+
constraints,
|
|
181
|
+
dontRepeat,
|
|
182
|
+
verifyFailures,
|
|
183
|
+
git: captureGitStateSafe(),
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const checkpoint = await createCheckpoint(projectSlug, taskSlug, checkpointPayload);
|
|
188
|
+
if (cloudSyncer && checkpoint) {
|
|
189
|
+
try {
|
|
190
|
+
await cloudSyncer.sync(checkpoint);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
onLog?.(`[cloud-sync] sync failed: ${err?.message || err}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} catch (err) {
|
|
196
|
+
onLog?.(`[checkpoint] failed to persist: ${err?.message || err}`);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const handleCheckpoint = (label) => {
|
|
201
|
+
void persistCheckpoint(label);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const handlePlanJson = (plan) => {
|
|
205
|
+
if (plan && typeof plan === 'object') {
|
|
206
|
+
executionState.plan = plan;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const handleCriteriaJson = (criteria) => {
|
|
211
|
+
if (criteria && typeof criteria === 'object') {
|
|
212
|
+
executionState.criteria = criteria;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const handleBlocked = async (blockedInfo) => {
|
|
217
|
+
// Persist rich blocked state with current checkpoint data
|
|
218
|
+
const richBlockedState = {
|
|
219
|
+
...blockedInfo,
|
|
220
|
+
iteration: iterationValue,
|
|
221
|
+
objective,
|
|
222
|
+
plan: executionState.plan,
|
|
223
|
+
criteria: executionState.criteria,
|
|
224
|
+
constraints,
|
|
225
|
+
dontRepeat,
|
|
226
|
+
verifyFailures,
|
|
227
|
+
git: captureGitStateSafe(),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Save blocked state as a special checkpoint
|
|
231
|
+
try {
|
|
232
|
+
const checkpoint = await createCheckpoint(projectSlug, taskSlug, {
|
|
233
|
+
...richBlockedState,
|
|
234
|
+
label: `blocked: ${blockedInfo.reason}`,
|
|
235
|
+
blockedAt: blockedInfo.timestamp,
|
|
236
|
+
});
|
|
237
|
+
onLog?.(`[blocked] State persisted for recovery`);
|
|
238
|
+
if (cloudSyncer && checkpoint) {
|
|
239
|
+
try {
|
|
240
|
+
await cloudSyncer.sync(checkpoint);
|
|
241
|
+
} catch (err) {
|
|
242
|
+
onLog?.(`[cloud-sync] sync failed: ${err?.message || err}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch (err) {
|
|
246
|
+
onLog?.(`[blocked] Failed to persist state: ${err?.message || err}`);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
104
250
|
const stageConfig = resolveStageConfig(options);
|
|
105
251
|
const engineConfig = ENGINES[engine] || ENGINES.claude;
|
|
106
252
|
|
|
@@ -150,7 +296,17 @@ async function executeTask(options) {
|
|
|
150
296
|
onStream?.(chunk);
|
|
151
297
|
|
|
152
298
|
// Parse output markers
|
|
153
|
-
parseMarkers(chunk, {
|
|
299
|
+
parseMarkers(chunk, {
|
|
300
|
+
onLog,
|
|
301
|
+
onProgress,
|
|
302
|
+
taskId,
|
|
303
|
+
projectSlug,
|
|
304
|
+
taskSlug,
|
|
305
|
+
onCheckpoint: handleCheckpoint,
|
|
306
|
+
onPlanJson: handlePlanJson,
|
|
307
|
+
onCriteriaJson: handleCriteriaJson,
|
|
308
|
+
onBlocked: handleBlocked,
|
|
309
|
+
});
|
|
154
310
|
|
|
155
311
|
// Increment progress as we get output
|
|
156
312
|
lastProgress = Math.min(90, lastProgress + 5);
|
|
@@ -181,24 +337,75 @@ async function executeTask(options) {
|
|
|
181
337
|
timeout = null;
|
|
182
338
|
};
|
|
183
339
|
|
|
340
|
+
// Auto-checkpoint every 5 minutes
|
|
341
|
+
const AUTO_CHECKPOINT_INTERVAL_MS = 5 * 60 * 1000;
|
|
342
|
+
let autoCheckpointTimer = null;
|
|
343
|
+
let autoCheckpointCount = 0;
|
|
344
|
+
|
|
345
|
+
const startAutoCheckpoint = () => {
|
|
346
|
+
if (autoCheckpointTimer) return;
|
|
347
|
+
autoCheckpointTimer = setInterval(async () => {
|
|
348
|
+
autoCheckpointCount++;
|
|
349
|
+
onLog?.(`[checkpoint] auto-checkpoint #${autoCheckpointCount}`);
|
|
350
|
+
await persistCheckpoint(`auto-5min-${autoCheckpointCount}`);
|
|
351
|
+
}, AUTO_CHECKPOINT_INTERVAL_MS);
|
|
352
|
+
autoCheckpointTimer.unref?.();
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const stopAutoCheckpoint = () => {
|
|
356
|
+
if (autoCheckpointTimer) {
|
|
357
|
+
clearInterval(autoCheckpointTimer);
|
|
358
|
+
autoCheckpointTimer = null;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// Start auto-checkpoint timer
|
|
363
|
+
startAutoCheckpoint();
|
|
364
|
+
|
|
184
365
|
proc.on('error', (err) => {
|
|
366
|
+
stopAutoCheckpoint();
|
|
185
367
|
clearStageTimeout();
|
|
186
368
|
require('./telemetry').track('executor_spawn_error', { engine, error: err.message });
|
|
187
369
|
settle(reject)(new Error(`Failed to spawn ${engine}: ${err.message}`));
|
|
188
370
|
});
|
|
189
371
|
|
|
190
|
-
proc.on('close', (code) => {
|
|
372
|
+
proc.on('close', async (code) => {
|
|
373
|
+
stopAutoCheckpoint();
|
|
191
374
|
clearStageTimeout();
|
|
192
375
|
onProgress?.(100);
|
|
193
376
|
|
|
194
377
|
if (code === 0 || code === null) {
|
|
195
|
-
onLog?.(`[${engine}] Stage
|
|
378
|
+
onLog?.(`[${engine}] Stage process finished`);
|
|
379
|
+
|
|
380
|
+
let gateResult = null;
|
|
381
|
+
try {
|
|
382
|
+
onLog?.(`[verify-gate] Running verification...`);
|
|
383
|
+
gateResult = await runVerifyGate({
|
|
384
|
+
criteria: executionState.criteria || [],
|
|
385
|
+
cwd: gitCwd,
|
|
386
|
+
verifyFailures: verifyFailures || 0,
|
|
387
|
+
onLog
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
if (gateResult.forceAction) {
|
|
391
|
+
onLog?.(`[verify-gate] Force action triggered: ${gateResult.reason}`);
|
|
392
|
+
// We resolve as success but pass the gate result so the loop can handle the force action
|
|
393
|
+
} else if (gateResult.passed) {
|
|
394
|
+
onLog?.(`[verify-gate] Passed all checks`);
|
|
395
|
+
} else {
|
|
396
|
+
onLog?.(`[verify-gate] Checks failed or need LLM`);
|
|
397
|
+
}
|
|
398
|
+
} catch (err) {
|
|
399
|
+
onLog?.(`[verify-gate] execution error: ${err.message}`);
|
|
400
|
+
}
|
|
401
|
+
|
|
196
402
|
require('./telemetry').track('executor_completed', { engine, stage, duration_ms: Date.now() - execStart });
|
|
197
403
|
settle(resolve)({
|
|
198
404
|
success: true,
|
|
199
405
|
output,
|
|
200
406
|
workDir,
|
|
201
407
|
exitCode: code,
|
|
408
|
+
gateResult,
|
|
202
409
|
});
|
|
203
410
|
} else {
|
|
204
411
|
onLog?.(`[${engine}] Stage failed with exit code ${code}`);
|
|
@@ -232,14 +439,95 @@ function buildPrompt(title, content, stage, stageConfig) {
|
|
|
232
439
|
});
|
|
233
440
|
}
|
|
234
441
|
|
|
442
|
+
function createDefaultPlan() {
|
|
443
|
+
return {
|
|
444
|
+
steps: [
|
|
445
|
+
{ desc: 'Analyze', status: 'done' },
|
|
446
|
+
{ desc: 'Implement', status: 'in_progress' },
|
|
447
|
+
{ desc: 'Verify', status: 'todo' },
|
|
448
|
+
],
|
|
449
|
+
current: 1,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function tryParseJsonCandidate(candidate) {
|
|
454
|
+
try {
|
|
455
|
+
return JSON.parse(candidate);
|
|
456
|
+
} catch (err) {
|
|
457
|
+
if (json5) {
|
|
458
|
+
try {
|
|
459
|
+
return json5.parse(candidate);
|
|
460
|
+
} catch (json5Err) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function extractJsonObjects(text, markerName) {
|
|
469
|
+
if (!text || !markerName) return [];
|
|
470
|
+
const lowerText = text.toLowerCase();
|
|
471
|
+
const marker = `[${markerName.toLowerCase()}:`;
|
|
472
|
+
const results = [];
|
|
473
|
+
let cursor = 0;
|
|
474
|
+
while (cursor < lowerText.length) {
|
|
475
|
+
const markerIndex = lowerText.indexOf(marker, cursor);
|
|
476
|
+
if (markerIndex === -1) break;
|
|
477
|
+
const braceStart = text.indexOf('{', markerIndex + marker.length);
|
|
478
|
+
if (braceStart === -1) {
|
|
479
|
+
cursor = markerIndex + marker.length;
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
let depth = 0;
|
|
483
|
+
let sliceEnd = -1;
|
|
484
|
+
for (let i = braceStart; i < text.length; i += 1) {
|
|
485
|
+
const ch = text[i];
|
|
486
|
+
if (ch === '{') {
|
|
487
|
+
depth += 1;
|
|
488
|
+
} else if (ch === '}') {
|
|
489
|
+
depth -= 1;
|
|
490
|
+
if (depth === 0) {
|
|
491
|
+
sliceEnd = i;
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (sliceEnd === -1) {
|
|
497
|
+
cursor = markerIndex + marker.length;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
const candidate = text.slice(braceStart, sliceEnd + 1);
|
|
501
|
+
const parsed = tryParseJsonCandidate(candidate);
|
|
502
|
+
if (parsed !== null) {
|
|
503
|
+
results.push(parsed);
|
|
504
|
+
cursor = sliceEnd + 1;
|
|
505
|
+
} else {
|
|
506
|
+
cursor = braceStart + 1;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return results;
|
|
510
|
+
}
|
|
511
|
+
|
|
235
512
|
/**
|
|
236
513
|
* Parse output markers from agent output
|
|
237
514
|
*/
|
|
238
|
-
function parseMarkers(text, {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
515
|
+
function parseMarkers(text, {
|
|
516
|
+
onLog,
|
|
517
|
+
onProgress,
|
|
518
|
+
taskId,
|
|
519
|
+
projectSlug,
|
|
520
|
+
taskSlug,
|
|
521
|
+
onCheckpoint,
|
|
522
|
+
onPlanJson,
|
|
523
|
+
onCriteriaJson,
|
|
524
|
+
onBlocked,
|
|
525
|
+
}) {
|
|
526
|
+
// [checkpoint: message] - capture all occurrences in chunk
|
|
527
|
+
const checkpointMatches = [...text.matchAll(/\[checkpoint:\s*([^\]]+)\]/gi)];
|
|
528
|
+
for (const match of checkpointMatches) {
|
|
529
|
+
onLog?.(`[checkpoint] ${match[1]}`);
|
|
530
|
+
onCheckpoint?.(match[1]);
|
|
243
531
|
}
|
|
244
532
|
|
|
245
533
|
// [learn: insight]
|
|
@@ -257,13 +545,31 @@ function parseMarkers(text, { onLog, onProgress, taskId }) {
|
|
|
257
545
|
// [blocked: reason]
|
|
258
546
|
const blockedMatch = text.match(/\[blocked:\s*([^\]]+)\]/i);
|
|
259
547
|
if (blockedMatch) {
|
|
260
|
-
|
|
548
|
+
const reason = blockedMatch[1];
|
|
549
|
+
onLog?.(`[blocked] ${reason}`);
|
|
550
|
+
onBlocked?.({
|
|
551
|
+
reason,
|
|
552
|
+
timestamp: new Date().toISOString(),
|
|
553
|
+
taskId,
|
|
554
|
+
projectSlug,
|
|
555
|
+
taskSlug,
|
|
556
|
+
});
|
|
261
557
|
}
|
|
262
558
|
|
|
263
559
|
// [done]
|
|
264
560
|
if (/\[done\]/i.test(text)) {
|
|
265
561
|
onLog?.(`[done] Stage marked complete`);
|
|
266
562
|
}
|
|
563
|
+
|
|
564
|
+
const planObjects = extractJsonObjects(text, 'plan_json');
|
|
565
|
+
for (const plan of planObjects) {
|
|
566
|
+
onPlanJson?.(plan);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const criteriaObjects = extractJsonObjects(text, 'criteria_json');
|
|
570
|
+
for (const criteria of criteriaObjects) {
|
|
571
|
+
onCriteriaJson?.(criteria);
|
|
572
|
+
}
|
|
267
573
|
}
|
|
268
574
|
|
|
269
575
|
/**
|