@promptwheel/cli 0.7.2 → 0.7.4
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/bin/promptwheel.js +1 -1
- package/dist/lib/display-adapter-log.d.ts +2 -1
- package/dist/lib/display-adapter-log.d.ts.map +1 -1
- package/dist/lib/display-adapter-log.js +3 -0
- package/dist/lib/display-adapter-log.js.map +1 -1
- package/dist/lib/display-adapter-spinner.d.ts +4 -1
- package/dist/lib/display-adapter-spinner.d.ts.map +1 -1
- package/dist/lib/display-adapter-spinner.js +14 -0
- package/dist/lib/display-adapter-spinner.js.map +1 -1
- package/dist/lib/display-adapter-tui.d.ts +2 -1
- package/dist/lib/display-adapter-tui.d.ts.map +1 -1
- package/dist/lib/display-adapter-tui.js +3 -0
- package/dist/lib/display-adapter-tui.js.map +1 -1
- package/dist/lib/display-adapter.d.ts +22 -0
- package/dist/lib/display-adapter.d.ts.map +1 -1
- package/dist/lib/display-adapter.js +64 -1
- package/dist/lib/display-adapter.js.map +1 -1
- package/dist/lib/run-history.d.ts +1 -1
- package/dist/lib/run-history.d.ts.map +1 -1
- package/dist/lib/run-state.d.ts +7 -1
- package/dist/lib/run-state.d.ts.map +1 -1
- package/dist/lib/run-state.js +13 -5
- package/dist/lib/run-state.js.map +1 -1
- package/dist/lib/solo-auto-between-cycles.js +70 -65
- package/dist/lib/solo-auto-between-cycles.js.map +1 -1
- package/dist/lib/solo-auto-drill.d.ts +1 -1
- package/dist/lib/solo-auto-drill.d.ts.map +1 -1
- package/dist/lib/solo-auto-drill.js +45 -36
- package/dist/lib/solo-auto-drill.js.map +1 -1
- package/dist/lib/solo-auto-execute.d.ts +1 -0
- package/dist/lib/solo-auto-execute.d.ts.map +1 -1
- package/dist/lib/solo-auto-execute.js +60 -10
- package/dist/lib/solo-auto-execute.js.map +1 -1
- package/dist/lib/solo-auto-filter.d.ts.map +1 -1
- package/dist/lib/solo-auto-filter.js +24 -14
- package/dist/lib/solo-auto-filter.js.map +1 -1
- package/dist/lib/solo-auto-finalize.js +3 -3
- package/dist/lib/solo-auto-finalize.js.map +1 -1
- package/dist/lib/solo-auto-scout.d.ts.map +1 -1
- package/dist/lib/solo-auto-scout.js +7 -4
- package/dist/lib/solo-auto-scout.js.map +1 -1
- package/dist/lib/solo-auto-state.js +25 -19
- package/dist/lib/solo-auto-state.js.map +1 -1
- package/dist/lib/solo-auto.d.ts.map +1 -1
- package/dist/lib/solo-auto.js +34 -7
- package/dist/lib/solo-auto.js.map +1 -1
- package/dist/lib/solo-session-summary.d.ts.map +1 -1
- package/dist/lib/solo-session-summary.js +11 -1
- package/dist/lib/solo-session-summary.js.map +1 -1
- package/dist/tui/screens/auto.d.ts +4 -0
- package/dist/tui/screens/auto.d.ts.map +1 -1
- package/dist/tui/screens/auto.js +21 -1
- package/dist/tui/screens/auto.js.map +1 -1
- package/package.json +3 -3
|
@@ -56,7 +56,7 @@ export async function runPreCycleMaintenance(state) {
|
|
|
56
56
|
if (qualityRate < 0.5) {
|
|
57
57
|
state.effectiveMinConfidence += 10;
|
|
58
58
|
if (state.options.verbose) {
|
|
59
|
-
|
|
59
|
+
state.displayAdapter.log(chalk.gray(` Quality rate ${(qualityRate * 100).toFixed(0)}% — raising confidence +10`));
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -66,7 +66,8 @@ export async function runPreCycleMaintenance(state) {
|
|
|
66
66
|
const confDelta = calibrateConfidence(state.repoRoot, state.effectiveMinConfidence, state.autoConf.minConfidence ?? 20);
|
|
67
67
|
if (confDelta !== 0) {
|
|
68
68
|
state.effectiveMinConfidence += confDelta;
|
|
69
|
-
|
|
69
|
+
if (state.options.verbose)
|
|
70
|
+
state.displayAdapter.log(chalk.gray(` Confidence calibration: ${confDelta > 0 ? '+' : ''}${confDelta} → ${state.effectiveMinConfidence}`));
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
catch {
|
|
@@ -77,7 +78,7 @@ export async function runPreCycleMaintenance(state) {
|
|
|
77
78
|
if (state.runMode === 'spin' && state.pendingPrUrls.length > 0 && state.deliveryMode !== 'direct') {
|
|
78
79
|
const openRatio = state.pendingPrUrls.length / state.maxPrs;
|
|
79
80
|
if (openRatio > 0.7) {
|
|
80
|
-
|
|
81
|
+
state.displayAdapter.log(chalk.yellow(` Backpressure: ${state.pendingPrUrls.length}/${state.maxPrs} PRs open — waiting for reviews...`));
|
|
81
82
|
await sleep(15000);
|
|
82
83
|
state.cycleCount--; // undo increment so the cycle reruns
|
|
83
84
|
return { shouldSkipCycle: true };
|
|
@@ -85,7 +86,7 @@ export async function runPreCycleMaintenance(state) {
|
|
|
85
86
|
else if (openRatio > 0.4) {
|
|
86
87
|
state.effectiveMinConfidence += 15;
|
|
87
88
|
if (state.options.verbose) {
|
|
88
|
-
|
|
89
|
+
state.displayAdapter.log(chalk.gray(` Light backpressure (${state.pendingPrUrls.length}/${state.maxPrs} open) — raising confidence +15`));
|
|
89
90
|
}
|
|
90
91
|
}
|
|
91
92
|
}
|
|
@@ -94,7 +95,7 @@ export async function runPreCycleMaintenance(state) {
|
|
|
94
95
|
const CONFIDENCE_CEILING = 80;
|
|
95
96
|
if (state.effectiveMinConfidence > CONFIDENCE_CEILING) {
|
|
96
97
|
if (state.options.verbose) {
|
|
97
|
-
|
|
98
|
+
state.displayAdapter.log(chalk.gray(` Confidence clamped: ${state.effectiveMinConfidence} → ${CONFIDENCE_CEILING} (ceiling)`));
|
|
98
99
|
}
|
|
99
100
|
state.effectiveMinConfidence = CONFIDENCE_CEILING;
|
|
100
101
|
}
|
|
@@ -107,7 +108,7 @@ export async function runPreCycleMaintenance(state) {
|
|
|
107
108
|
state.tasteProfile = buildTasteProfile(state.sectorState, state.allLearnings, rs.formulaStats);
|
|
108
109
|
saveTasteProfile(state.repoRoot, state.tasteProfile);
|
|
109
110
|
if (state.options.verbose) {
|
|
110
|
-
|
|
111
|
+
state.displayAdapter.log(chalk.gray(` Taste profile rebuilt: prefer [${state.tasteProfile.preferredCategories.join(', ')}], avoid [${state.tasteProfile.avoidCategories.join(', ')}]`));
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
// Periodic pull
|
|
@@ -122,21 +123,21 @@ export async function runPreCycleMaintenance(state) {
|
|
|
122
123
|
if (mergeResult.status === 0) {
|
|
123
124
|
const summary = mergeResult.stdout?.trim();
|
|
124
125
|
if (summary && !summary.includes('Already up to date')) {
|
|
125
|
-
|
|
126
|
+
state.displayAdapter.log(chalk.cyan(` ⬇ Pulled latest from origin/${state.detectedBaseBranch}`));
|
|
126
127
|
}
|
|
127
128
|
}
|
|
128
129
|
else {
|
|
129
130
|
const errMsg = mergeResult.stderr?.trim() || 'fast-forward not possible';
|
|
130
131
|
if (state.pullPolicy === 'halt') {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
132
|
+
state.displayAdapter.log('');
|
|
133
|
+
state.displayAdapter.log(chalk.red(`✗ HCF — Base branch has diverged from origin/${state.detectedBaseBranch}`));
|
|
134
|
+
state.displayAdapter.log(chalk.gray(` ${errMsg}`));
|
|
135
|
+
state.displayAdapter.log('');
|
|
136
|
+
state.displayAdapter.log(chalk.bold('Resolution:'));
|
|
137
|
+
state.displayAdapter.log(` 1. Resolve the divergence (rebase, merge, or reset)`);
|
|
138
|
+
state.displayAdapter.log(` 2. Re-run: promptwheel`);
|
|
139
|
+
state.displayAdapter.log('');
|
|
140
|
+
state.displayAdapter.log(chalk.gray(` To keep going despite divergence, set pullPolicy: "warn" in config.`));
|
|
140
141
|
// Signal orchestrator to break — finalizeSession handles cleanup
|
|
141
142
|
state.shutdownRequested = true;
|
|
142
143
|
if (state.shutdownReason === null)
|
|
@@ -144,14 +145,14 @@ export async function runPreCycleMaintenance(state) {
|
|
|
144
145
|
return { shouldSkipCycle: true };
|
|
145
146
|
}
|
|
146
147
|
else {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
state.displayAdapter.log(chalk.yellow(` ⚠ Base branch diverged from origin/${state.detectedBaseBranch} — continuing on stale base`));
|
|
149
|
+
state.displayAdapter.log(chalk.gray(` ${errMsg}`));
|
|
150
|
+
state.displayAdapter.log(chalk.gray(` Subsequent work may produce merge conflicts`));
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
|
-
else if (state.options.verbose) {
|
|
154
|
-
|
|
154
|
+
else if (state.options.verbose) { // already verbose-gated
|
|
155
|
+
state.displayAdapter.log(chalk.yellow(` ⚠ Fetch failed (network?): ${fetchResult.stderr?.trim()}`));
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
catch {
|
|
@@ -240,7 +241,7 @@ export async function runPreCycleMaintenance(state) {
|
|
|
240
241
|
try {
|
|
241
242
|
state.guidelines = loadGuidelines(state.repoRoot, state.guidelinesOpts);
|
|
242
243
|
if (state.guidelines && state.options.verbose) {
|
|
243
|
-
|
|
244
|
+
state.displayAdapter.log(chalk.gray(` Refreshed project guidelines (${state.guidelines.source})`));
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
catch {
|
|
@@ -306,7 +307,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
309
|
if (healed.length > 0) {
|
|
309
|
-
|
|
310
|
+
state.displayAdapter.log(chalk.green(` Baseline healed: ${healed.join(', ')} now passing`));
|
|
310
311
|
if (state.autoConf.learningsEnabled) {
|
|
311
312
|
addLearning(state.repoRoot, {
|
|
312
313
|
text: `Baseline healed in ${scope}: ${healed.join(', ')} now pass after cycle ${state.cycleCount}`.slice(0, 200),
|
|
@@ -337,7 +338,8 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
337
338
|
}
|
|
338
339
|
}
|
|
339
340
|
catch (err) {
|
|
340
|
-
|
|
341
|
+
if (state.options.verbose)
|
|
342
|
+
console.warn(chalk.gray(` Baseline healing skipped: ${err instanceof Error ? err.message : String(err)}`));
|
|
341
343
|
}
|
|
342
344
|
}
|
|
343
345
|
// Meta-learning extraction (aggregate pattern detection)
|
|
@@ -352,7 +354,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
352
354
|
existingLearnings: state.allLearnings,
|
|
353
355
|
});
|
|
354
356
|
if (metaInsightsAdded > 0 && state.options.verbose) {
|
|
355
|
-
|
|
357
|
+
state.displayAdapter.log(chalk.gray(` Meta-learnings: ${metaInsightsAdded} process insight(s) extracted`));
|
|
356
358
|
}
|
|
357
359
|
}
|
|
358
360
|
catch {
|
|
@@ -365,13 +367,13 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
365
367
|
state.consecutiveLowYieldCycles++;
|
|
366
368
|
const MAX_LOW_YIELD_CYCLES = state.drillMode ? 5 : 3;
|
|
367
369
|
if (state.consecutiveLowYieldCycles >= MAX_LOW_YIELD_CYCLES) {
|
|
368
|
-
|
|
370
|
+
state.displayAdapter.log(chalk.yellow(` ${state.consecutiveLowYieldCycles} consecutive low-yield cycles — diminishing returns, stopping`));
|
|
369
371
|
state.shutdownRequested = true;
|
|
370
372
|
if (state.shutdownReason === null)
|
|
371
373
|
state.shutdownReason = 'low_yield';
|
|
372
374
|
}
|
|
373
375
|
else if (state.options.verbose) {
|
|
374
|
-
|
|
376
|
+
state.displayAdapter.log(chalk.gray(` Low-yield cycle (${state.consecutiveLowYieldCycles}/${MAX_LOW_YIELD_CYCLES})`));
|
|
375
377
|
}
|
|
376
378
|
}
|
|
377
379
|
else if (completedThisCount > 0) {
|
|
@@ -389,7 +391,8 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
389
391
|
const confValue = state.effectiveMinConfidence;
|
|
390
392
|
const insightsStr = metaInsightsAdded > 0 ? ` | insights +${metaInsightsAdded}` : '';
|
|
391
393
|
const baselineStr = baselineFailing > 0 ? ` | baseline failing ${baselineFailing}` : '';
|
|
392
|
-
|
|
394
|
+
if (state.options.verbose)
|
|
395
|
+
state.displayAdapter.log(chalk.gray(` Spin: quality ${qualityPct}% | confidence ${confValue}${baselineStr}${insightsStr}`));
|
|
393
396
|
}
|
|
394
397
|
// Convergence metrics
|
|
395
398
|
if (state.cycleCount >= 3 && state.sectorState) {
|
|
@@ -413,7 +416,8 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
413
416
|
};
|
|
414
417
|
}
|
|
415
418
|
const metrics = computeConvergenceMetrics(state.sectorState, state.allLearnings.length, rs.recentCycles ?? [], sessionCtx, drillCtx);
|
|
416
|
-
|
|
419
|
+
if (state.options.verbose)
|
|
420
|
+
state.displayAdapter.log(chalk.gray(` ${formatConvergenceOneLiner(metrics)}`));
|
|
417
421
|
if (metrics.suggestedAction === 'stop') {
|
|
418
422
|
if (state.activeTrajectory && state.activeTrajectoryState) {
|
|
419
423
|
// Adaptive threshold: use historical completion rate to decide when to abandon
|
|
@@ -431,13 +435,13 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
431
435
|
const completedSteps = state.activeTrajectory.steps.filter(s => state.activeTrajectoryState.stepStates[s.id]?.status === 'completed').length;
|
|
432
436
|
const progressPct = totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0;
|
|
433
437
|
if (progressPct < abandonThreshold) {
|
|
434
|
-
|
|
438
|
+
state.displayAdapter.log(chalk.yellow(` Convergence suggests stopping — trajectory "${state.activeTrajectory.name}" only ${progressPct}% complete, skipping it`));
|
|
435
439
|
if (state.drillMode) {
|
|
436
440
|
try {
|
|
437
441
|
finishDrillTrajectory(state, 'stalled');
|
|
438
442
|
}
|
|
439
443
|
catch (err) {
|
|
440
|
-
|
|
444
|
+
state.displayAdapter.log(chalk.yellow(` Drill: failed to record trajectory outcome — ${err instanceof Error ? err.message : String(err)}`));
|
|
441
445
|
}
|
|
442
446
|
}
|
|
443
447
|
state.activeTrajectory = null;
|
|
@@ -448,11 +452,11 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
448
452
|
state.shutdownReason = 'convergence';
|
|
449
453
|
}
|
|
450
454
|
else {
|
|
451
|
-
|
|
455
|
+
state.displayAdapter.log(chalk.gray(` Convergence suggests stopping, but trajectory "${state.activeTrajectory.name}" is ${progressPct}% complete — continuing`));
|
|
452
456
|
}
|
|
453
457
|
}
|
|
454
458
|
else {
|
|
455
|
-
|
|
459
|
+
state.displayAdapter.log(chalk.yellow(` Convergence suggests stopping — most sectors polished, low yield.`));
|
|
456
460
|
state.shutdownRequested = true;
|
|
457
461
|
if (state.shutdownReason === null)
|
|
458
462
|
state.shutdownReason = 'convergence';
|
|
@@ -466,19 +470,19 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
466
470
|
// In drill mode with active trajectory, don't widen — stay focused on trajectory scope
|
|
467
471
|
if (state.drillMode && state.currentTrajectoryStep?.scope) {
|
|
468
472
|
if (state.options.verbose)
|
|
469
|
-
|
|
473
|
+
state.displayAdapter.log(chalk.gray(` Scope adjustment: drill mode — staying focused on trajectory scope`));
|
|
470
474
|
}
|
|
471
475
|
else {
|
|
472
476
|
state.effectiveMinConfidence = state.autoConf.minConfidence ?? 20;
|
|
473
477
|
if (state.options.verbose)
|
|
474
|
-
|
|
478
|
+
state.displayAdapter.log(chalk.gray(` Scope adjustment: widening (resetting confidence threshold)`));
|
|
475
479
|
}
|
|
476
480
|
}
|
|
477
481
|
else if (scopeAdj === 'narrow' && state.drillMode && state.currentTrajectoryStep) {
|
|
478
482
|
// In drill mode, tighten confidence when trajectory-guided to focus on high-quality proposals
|
|
479
483
|
state.effectiveMinConfidence += 5;
|
|
480
484
|
if (state.options.verbose)
|
|
481
|
-
|
|
485
|
+
state.displayAdapter.log(chalk.gray(` Scope adjustment: drill-narrowed (confidence +5)`));
|
|
482
486
|
}
|
|
483
487
|
}
|
|
484
488
|
// Cross-sector pattern learning
|
|
@@ -531,12 +535,12 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
531
535
|
try {
|
|
532
536
|
state.codebaseIndex = refreshCodebaseIndex(state.codebaseIndex, state.repoRoot, state.excludeDirs);
|
|
533
537
|
if (state.options.verbose) {
|
|
534
|
-
|
|
538
|
+
state.displayAdapter.log(chalk.gray(` Codebase index refreshed: ${state.codebaseIndex.modules.length} modules`));
|
|
535
539
|
}
|
|
536
540
|
if (state.sectorState) {
|
|
537
541
|
state.sectorState = refreshSectors(state.repoRoot, state.sectorState, state.codebaseIndex.modules);
|
|
538
542
|
if (state.options.verbose) {
|
|
539
|
-
|
|
543
|
+
state.displayAdapter.log(chalk.gray(` Sectors refreshed: ${state.sectorState.sectors.length} sector(s)`));
|
|
540
544
|
}
|
|
541
545
|
}
|
|
542
546
|
}
|
|
@@ -558,7 +562,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
558
562
|
const arrow = state.activeGoal.measure.direction === 'up'
|
|
559
563
|
? (delta > 0 ? chalk.green('↑') : delta < 0 ? chalk.yellow('↓') : '→')
|
|
560
564
|
: (delta < 0 ? chalk.green('↓') : delta > 0 ? chalk.yellow('↑') : '→');
|
|
561
|
-
|
|
565
|
+
state.displayAdapter.log(chalk.cyan(` 🎯 ${state.activeGoal.name}: ${value} ${arrow} (${deltaSign}${delta.toFixed(1)}) target: ${state.activeGoal.measure.target}`));
|
|
562
566
|
// Check if goal is now met
|
|
563
567
|
const { target, direction } = state.activeGoal.measure;
|
|
564
568
|
const met = direction === 'up' ? value >= target : value <= target;
|
|
@@ -566,7 +570,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
566
570
|
const measurement = { ...state.activeGoalMeasurement, current: value, measuredAt: Date.now(), met };
|
|
567
571
|
recordGoalMeasurement(state.repoRoot, measurement);
|
|
568
572
|
if (met) {
|
|
569
|
-
|
|
573
|
+
state.displayAdapter.log(chalk.green(` ✓ Goal "${state.activeGoal.name}" met!`));
|
|
570
574
|
// Re-evaluate all goals and pivot to next
|
|
571
575
|
const allMeasurements = measureGoals(state.goals, state.repoRoot);
|
|
572
576
|
for (const m of allMeasurements) {
|
|
@@ -576,12 +580,12 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
576
580
|
if (next) {
|
|
577
581
|
state.activeGoal = state.goals.find(g => g.name === next.goalName) ?? null;
|
|
578
582
|
state.activeGoalMeasurement = next;
|
|
579
|
-
|
|
583
|
+
state.displayAdapter.log(chalk.cyan(` → Pivoting to: ${next.goalName} (gap: ${next.gapPercent}%)`));
|
|
580
584
|
}
|
|
581
585
|
else {
|
|
582
586
|
const allMet = allMeasurements.every(m => m.met);
|
|
583
587
|
if (allMet) {
|
|
584
|
-
|
|
588
|
+
state.displayAdapter.log(chalk.green(` ✓ All goals met!`));
|
|
585
589
|
}
|
|
586
590
|
state.activeGoal = null;
|
|
587
591
|
state.activeGoalMeasurement = null;
|
|
@@ -616,7 +620,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
616
620
|
}
|
|
617
621
|
}
|
|
618
622
|
else {
|
|
619
|
-
|
|
623
|
+
state.displayAdapter.log(chalk.yellow(` ⚠ Goal "${state.activeGoal.name}" re-measurement failed${error ? `: ${error}` : ''}`));
|
|
620
624
|
}
|
|
621
625
|
}
|
|
622
626
|
// Trajectory cycle budget — abandon if consuming too many cycles.
|
|
@@ -630,13 +634,13 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
630
634
|
if (totalCyclesUsed >= maxCycles) {
|
|
631
635
|
const completedSteps = state.activeTrajectory.steps.filter(s => state.activeTrajectoryState.stepStates[s.id]?.status === 'completed').length;
|
|
632
636
|
const pct = Math.round((completedSteps / state.activeTrajectory.steps.length) * 100);
|
|
633
|
-
|
|
637
|
+
state.displayAdapter.log(chalk.yellow(` Drill: trajectory "${state.activeTrajectory.name}" hit cycle budget (${totalCyclesUsed}/${maxCycles} cycles, ${pct}% complete) — abandoning`));
|
|
634
638
|
saveTrajectoryState(state.repoRoot, state.activeTrajectoryState);
|
|
635
639
|
try {
|
|
636
640
|
finishDrillTrajectory(state, 'stalled');
|
|
637
641
|
}
|
|
638
642
|
catch (err) {
|
|
639
|
-
|
|
643
|
+
state.displayAdapter.log(chalk.yellow(` Drill: failed to record trajectory outcome — ${err instanceof Error ? err.message : String(err)}`));
|
|
640
644
|
}
|
|
641
645
|
state.activeTrajectory = null;
|
|
642
646
|
state.activeTrajectoryState = null;
|
|
@@ -662,18 +666,18 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
662
666
|
// Timeout or spawn error
|
|
663
667
|
allPassed = false;
|
|
664
668
|
const reason = result.error.message?.includes('TIMEOUT') ? 'timeout (30s)' : result.error.message;
|
|
665
|
-
|
|
669
|
+
state.displayAdapter.log(chalk.yellow(` ✗ ${cmd} (${reason})`));
|
|
666
670
|
verificationOutputParts.push(`$ ${cmd}\n${reason}`);
|
|
667
671
|
}
|
|
668
672
|
else if (result.status !== 0) {
|
|
669
673
|
allPassed = false;
|
|
670
674
|
const stderr = (result.stderr || '').trim().slice(0, 500);
|
|
671
675
|
const stdout = (result.stdout || '').trim().slice(0, 200);
|
|
672
|
-
|
|
676
|
+
state.displayAdapter.log(chalk.yellow(` ✗ ${cmd} (exit ${result.status})`));
|
|
673
677
|
if (stderr)
|
|
674
|
-
|
|
678
|
+
state.displayAdapter.log(chalk.gray(` ${stderr.split('\n')[0]}`));
|
|
675
679
|
else if (stdout)
|
|
676
|
-
|
|
680
|
+
state.displayAdapter.log(chalk.gray(` ${stdout.split('\n')[0]}`));
|
|
677
681
|
verificationOutputParts.push(`$ ${cmd} (exit ${result.status})\n${stderr || stdout}`);
|
|
678
682
|
}
|
|
679
683
|
}
|
|
@@ -689,12 +693,12 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
689
693
|
: value <= step.measure.target;
|
|
690
694
|
stepState.measurement = { value, timestamp: Date.now() };
|
|
691
695
|
if (!measureMet) {
|
|
692
|
-
|
|
696
|
+
state.displayAdapter.log(chalk.yellow(` measure: ${value} (target: ${arrow} ${step.measure.target})`));
|
|
693
697
|
}
|
|
694
698
|
}
|
|
695
699
|
else {
|
|
696
700
|
measureMet = false;
|
|
697
|
-
|
|
701
|
+
state.displayAdapter.log(chalk.yellow(` measure failed${error ? `: ${error}` : ''}`));
|
|
698
702
|
}
|
|
699
703
|
}
|
|
700
704
|
if (allPassed && measureMet) {
|
|
@@ -705,7 +709,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
705
709
|
stepState.lastVerificationOutput = undefined;
|
|
706
710
|
const completedCount = state.activeTrajectory.steps.filter(s => state.activeTrajectoryState.stepStates[s.id]?.status === 'completed').length;
|
|
707
711
|
const totalCount = state.activeTrajectory.steps.length;
|
|
708
|
-
|
|
712
|
+
state.displayAdapter.log(chalk.green(` Trajectory step ${completedCount}/${totalCount} "${step.title}" completed`));
|
|
709
713
|
// Pick next step
|
|
710
714
|
const next = getTrajectoryNextStep(state.activeTrajectory, state.activeTrajectoryState.stepStates);
|
|
711
715
|
state.currentTrajectoryStep = next;
|
|
@@ -714,16 +718,16 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
714
718
|
if (state.activeTrajectoryState.stepStates[next.id]) {
|
|
715
719
|
state.activeTrajectoryState.stepStates[next.id].status = 'active';
|
|
716
720
|
}
|
|
717
|
-
|
|
721
|
+
state.displayAdapter.log(chalk.cyan(` -> Next step: ${next.title}`));
|
|
718
722
|
}
|
|
719
723
|
else if (trajectoryComplete(state.activeTrajectory, state.activeTrajectoryState.stepStates)) {
|
|
720
724
|
const fullySucceeded = trajectoryFullySucceeded(state.activeTrajectory, state.activeTrajectoryState.stepStates);
|
|
721
725
|
const outcome = fullySucceeded ? 'completed' : 'stalled';
|
|
722
726
|
if (fullySucceeded) {
|
|
723
|
-
|
|
727
|
+
state.displayAdapter.log(chalk.green(` Trajectory "${state.activeTrajectory.name}" complete!`));
|
|
724
728
|
}
|
|
725
729
|
else {
|
|
726
|
-
|
|
730
|
+
state.displayAdapter.log(chalk.yellow(` Trajectory "${state.activeTrajectory.name}" finished with some failed steps`));
|
|
727
731
|
}
|
|
728
732
|
// Save final state before clearing (so completed status persists on disk)
|
|
729
733
|
saveTrajectoryState(state.repoRoot, state.activeTrajectoryState);
|
|
@@ -732,7 +736,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
732
736
|
finishDrillTrajectory(state, outcome);
|
|
733
737
|
}
|
|
734
738
|
catch (err) {
|
|
735
|
-
|
|
739
|
+
state.displayAdapter.log(chalk.yellow(` Drill: failed to record trajectory outcome — ${err instanceof Error ? err.message : String(err)}`));
|
|
736
740
|
}
|
|
737
741
|
}
|
|
738
742
|
state.activeTrajectory = null;
|
|
@@ -742,14 +746,14 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
742
746
|
else {
|
|
743
747
|
// No next step available but trajectory isn't complete — shouldn't happen now
|
|
744
748
|
// (failed deps unblock dependents), but handle as fallback
|
|
745
|
-
|
|
749
|
+
state.displayAdapter.log(chalk.yellow(` Trajectory "${state.activeTrajectory.name}" stalled (remaining steps blocked)`));
|
|
746
750
|
saveTrajectoryState(state.repoRoot, state.activeTrajectoryState);
|
|
747
751
|
if (state.drillMode) {
|
|
748
752
|
try {
|
|
749
753
|
finishDrillTrajectory(state, 'stalled');
|
|
750
754
|
}
|
|
751
755
|
catch (err) {
|
|
752
|
-
|
|
756
|
+
state.displayAdapter.log(chalk.yellow(` Drill: failed to record trajectory outcome — ${err instanceof Error ? err.message : String(err)}`));
|
|
753
757
|
}
|
|
754
758
|
}
|
|
755
759
|
state.activeTrajectory = null;
|
|
@@ -776,7 +780,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
776
780
|
const stuckStep = state.activeTrajectory.steps.find(s => s.id === stuckId);
|
|
777
781
|
const stuckTitle = stuckStep?.title ?? stuckId;
|
|
778
782
|
const stuckAttempts = stuckStepState?.cyclesAttempted ?? stepState.cyclesAttempted;
|
|
779
|
-
|
|
783
|
+
state.displayAdapter.log(chalk.yellow(` Trajectory step "${stuckTitle}" stuck after ${stuckAttempts} cycles`));
|
|
780
784
|
if (stuckStepState) {
|
|
781
785
|
stuckStepState.status = 'failed';
|
|
782
786
|
stuckStepState.failureReason = 'max retries exceeded';
|
|
@@ -789,18 +793,18 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
789
793
|
if (state.activeTrajectoryState.stepStates[next.id]) {
|
|
790
794
|
state.activeTrajectoryState.stepStates[next.id].status = 'active';
|
|
791
795
|
}
|
|
792
|
-
|
|
796
|
+
state.displayAdapter.log(chalk.cyan(` -> Skipping to next step: ${next.title}`));
|
|
793
797
|
}
|
|
794
798
|
else {
|
|
795
799
|
// No more steps — trajectory is done (all remaining steps failed or completed)
|
|
796
|
-
|
|
800
|
+
state.displayAdapter.log(chalk.yellow(` Trajectory "${state.activeTrajectory.name}" ended (no remaining steps)`));
|
|
797
801
|
saveTrajectoryState(state.repoRoot, state.activeTrajectoryState);
|
|
798
802
|
if (state.drillMode) {
|
|
799
803
|
try {
|
|
800
804
|
finishDrillTrajectory(state, 'stalled');
|
|
801
805
|
}
|
|
802
806
|
catch (err) {
|
|
803
|
-
|
|
807
|
+
state.displayAdapter.log(chalk.yellow(` Drill: failed to record trajectory outcome — ${err instanceof Error ? err.message : String(err)}`));
|
|
804
808
|
}
|
|
805
809
|
}
|
|
806
810
|
state.activeTrajectory = null;
|
|
@@ -817,7 +821,7 @@ export async function runPostCycleMaintenance(state, scope, isDocsAuditCycle) {
|
|
|
817
821
|
// Pause between cycles — shorter when trajectory-guided (work is pre-planned)
|
|
818
822
|
if (state.runMode === 'spin' && !state.shutdownRequested) {
|
|
819
823
|
const pauseMs = state.currentTrajectoryStep ? 1000 : 5000;
|
|
820
|
-
|
|
824
|
+
state.displayAdapter.log(chalk.gray('Pausing before next cycle...'));
|
|
821
825
|
await sleep(pauseMs);
|
|
822
826
|
}
|
|
823
827
|
}
|
|
@@ -903,8 +907,9 @@ function finishDrillTrajectory(state, outcome) {
|
|
|
903
907
|
}
|
|
904
908
|
}
|
|
905
909
|
const rate = stepsTotal > 0 ? Math.round((stepsCompleted / stepsTotal) * 100) : 0;
|
|
906
|
-
|
|
907
|
-
|
|
910
|
+
state.displayAdapter.log(chalk.cyan(` Drill: trajectory ${outcome} (${stepsCompleted}/${stepsTotal} steps, ${rate}% completion)`));
|
|
911
|
+
if (state.options.verbose)
|
|
912
|
+
state.displayAdapter.log(chalk.cyan(' Drill: will survey for next trajectory on next cycle'));
|
|
908
913
|
// Notify display adapter that trajectory finished (back to idle)
|
|
909
914
|
state.displayAdapter.drillStateChanged({ active: true });
|
|
910
915
|
// Reload learnings immediately so next trajectory generation has fresh context
|