@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.
Files changed (89) hide show
  1. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/BUILD_ID +1 -1
  2. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-build-manifest.json +60 -60
  3. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/app-path-routes-manifest.json +13 -13
  4. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/build-manifest.json +2 -2
  5. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/prerender-manifest.json +9 -9
  6. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  7. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.html +2 -2
  8. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/_not-found.rsc +1 -1
  9. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/audit/route_client-reference-manifest.js +1 -1
  10. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/[...nextauth]/route_client-reference-manifest.js +1 -1
  11. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/daemon-secret/route_client-reference-manifest.js +1 -1
  12. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/code/route_client-reference-manifest.js +1 -1
  13. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/device/token/route_client-reference-manifest.js +1 -1
  14. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/refresh/route_client-reference-manifest.js +1 -1
  15. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  16. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/[id]/route_client-reference-manifest.js +1 -1
  17. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/domains/route_client-reference-manifest.js +1 -1
  18. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  19. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/learnings/route_client-reference-manifest.js +1 -1
  20. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/logs/stream/route_client-reference-manifest.js +1 -1
  21. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
  22. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route_client-reference-manifest.js +1 -1
  23. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/start/route_client-reference-manifest.js +1 -1
  24. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/orchestrator/tasks/[taskId]/status/route_client-reference-manifest.js +1 -1
  25. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -1
  26. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  27. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/providers/route_client-reference-manifest.js +1 -1
  28. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/complete/route_client-reference-manifest.js +1 -1
  29. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/queue/route_client-reference-manifest.js +1 -1
  30. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/stage-prompts/route_client-reference-manifest.js +1 -1
  31. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/[commentId]/route_client-reference-manifest.js +1 -1
  32. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/comments/route_client-reference-manifest.js +1 -1
  33. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/costs/route_client-reference-manifest.js +1 -1
  34. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/dependencies/route_client-reference-manifest.js +1 -1
  35. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/heartbeat/route_client-reference-manifest.js +1 -1
  36. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/history/route_client-reference-manifest.js +1 -1
  37. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/route_client-reference-manifest.js +1 -1
  38. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/logs/stream/route_client-reference-manifest.js +1 -1
  39. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/restart-stage/route_client-reference-manifest.js +1 -1
  40. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
  41. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
  42. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/tasks/stream/route_client-reference-manifest.js +1 -1
  43. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/user-settings/route_client-reference-manifest.js +1 -1
  44. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/nodes/route_client-reference-manifest.js +1 -1
  45. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/[id]/route_client-reference-manifest.js +1 -1
  46. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  47. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/callback/route_client-reference-manifest.js +1 -1
  48. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page.js +4 -4
  49. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device/page_client-reference-manifest.js +1 -1
  50. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.html +1 -1
  51. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/auth/device.rsc +2 -2
  52. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard/page_client-reference-manifest.js +1 -1
  53. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.html +2 -2
  54. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/dashboard.rsc +1 -1
  55. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.html +2 -2
  56. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/index.rsc +1 -1
  57. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login/page_client-reference-manifest.js +1 -1
  58. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.html +2 -2
  59. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/login.rsc +1 -1
  60. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/page_client-reference-manifest.js +1 -1
  61. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  62. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/tasks/page_client-reference-manifest.js +1 -1
  63. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/[slug]/workflow/page_client-reference-manifest.js +1 -1
  64. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  65. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.html +2 -2
  66. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/projects.rsc +1 -1
  67. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  68. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.html +2 -2
  69. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app/settings.rsc +1 -1
  70. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/app-paths-manifest.json +13 -13
  71. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/functions-config-manifest.json +2 -2
  72. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/middleware-manifest.json +5 -5
  73. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/404.html +1 -1
  74. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/pages/500.html +1 -1
  75. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.js +1 -1
  76. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/server/server-reference-manifest.json +1 -1
  77. package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/chunks/app/auth/device/{page-06eeddaf1bb867c3.js → page-bd5f443ef9da0c0a.js} +1 -1
  78. package/index.js +1 -0
  79. package/lib/cli/runCli.js +217 -3
  80. package/lib/cloud-sync.js +267 -0
  81. package/lib/executor.js +315 -9
  82. package/lib/prompts/resume.js +353 -0
  83. package/lib/storage/checkpoints.js +222 -0
  84. package/lib/storage/git.js +147 -0
  85. package/lib/storage/index.js +7 -0
  86. package/lib/verify-gate.js +301 -0
  87. package/package.json +1 -1
  88. /package/cloud-runtime/standalone/Projects/Agents/agx-cloud/.next/static/{o_Dsarly6P4c-yqsBEkNM → FYPvFkL9PvoVJhHnr9Upx}/_buildManifest.js +0 -0
  89. /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, { onLog, onProgress, taskId });
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 completed successfully`);
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, { onLog, onProgress, taskId }) {
239
- // [checkpoint: message]
240
- const checkpointMatch = text.match(/\[checkpoint:\s*([^\]]+)\]/i);
241
- if (checkpointMatch) {
242
- onLog?.(`[checkpoint] ${checkpointMatch[1]}`);
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
- onLog?.(`[blocked] ${blockedMatch[1]}`);
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
  /**