substrate-ai 0.2.26 → 0.2.27
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.
|
@@ -539,7 +539,7 @@ const migration010RunMetrics = {
|
|
|
539
539
|
|
|
540
540
|
//#endregion
|
|
541
541
|
//#region src/persistence/migrations/index.ts
|
|
542
|
-
const logger$
|
|
542
|
+
const logger$20 = createLogger("persistence:migrations");
|
|
543
543
|
const MIGRATIONS = [
|
|
544
544
|
initialSchemaMigration,
|
|
545
545
|
costTrackerSchemaMigration,
|
|
@@ -557,7 +557,7 @@ const MIGRATIONS = [
|
|
|
557
557
|
* Safe to call multiple times — already-applied migrations are skipped.
|
|
558
558
|
*/
|
|
559
559
|
function runMigrations(db) {
|
|
560
|
-
logger$
|
|
560
|
+
logger$20.info("Starting migration runner");
|
|
561
561
|
db.exec(`
|
|
562
562
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
563
563
|
version INTEGER PRIMARY KEY,
|
|
@@ -568,12 +568,12 @@ function runMigrations(db) {
|
|
|
568
568
|
const appliedVersions = new Set(db.prepare("SELECT version FROM schema_migrations").all().map((row) => row.version));
|
|
569
569
|
const pending = MIGRATIONS.filter((m) => !appliedVersions.has(m.version)).sort((a, b) => a.version - b.version);
|
|
570
570
|
if (pending.length === 0) {
|
|
571
|
-
logger$
|
|
571
|
+
logger$20.info("No pending migrations");
|
|
572
572
|
return;
|
|
573
573
|
}
|
|
574
574
|
const insertMigration = db.prepare("INSERT INTO schema_migrations (version, name) VALUES (?, ?)");
|
|
575
575
|
for (const migration of pending) {
|
|
576
|
-
logger$
|
|
576
|
+
logger$20.info({
|
|
577
577
|
version: migration.version,
|
|
578
578
|
name: migration.name
|
|
579
579
|
}, "Applying migration");
|
|
@@ -587,14 +587,14 @@ function runMigrations(db) {
|
|
|
587
587
|
});
|
|
588
588
|
applyMigration();
|
|
589
589
|
}
|
|
590
|
-
logger$
|
|
590
|
+
logger$20.info({ version: migration.version }, "Migration applied successfully");
|
|
591
591
|
}
|
|
592
|
-
logger$
|
|
592
|
+
logger$20.info({ count: pending.length }, "All pending migrations applied");
|
|
593
593
|
}
|
|
594
594
|
|
|
595
595
|
//#endregion
|
|
596
596
|
//#region src/persistence/database.ts
|
|
597
|
-
const logger$
|
|
597
|
+
const logger$19 = createLogger("persistence:database");
|
|
598
598
|
/**
|
|
599
599
|
* Thin wrapper that opens a SQLite database, applies required PRAGMAs,
|
|
600
600
|
* and exposes the raw BetterSqlite3 instance.
|
|
@@ -611,14 +611,14 @@ var DatabaseWrapper = class {
|
|
|
611
611
|
*/
|
|
612
612
|
open() {
|
|
613
613
|
if (this._db !== null) return;
|
|
614
|
-
logger$
|
|
614
|
+
logger$19.info({ path: this._path }, "Opening SQLite database");
|
|
615
615
|
this._db = new BetterSqlite3(this._path);
|
|
616
616
|
const walResult = this._db.pragma("journal_mode = WAL");
|
|
617
|
-
if (walResult?.[0]?.journal_mode !== "wal") logger$
|
|
617
|
+
if (walResult?.[0]?.journal_mode !== "wal") logger$19.warn({ result: walResult?.[0]?.journal_mode }, "WAL pragma did not return expected \"wal\" — journal_mode may be \"memory\" or unsupported");
|
|
618
618
|
this._db.pragma("busy_timeout = 5000");
|
|
619
619
|
this._db.pragma("synchronous = NORMAL");
|
|
620
620
|
this._db.pragma("foreign_keys = ON");
|
|
621
|
-
logger$
|
|
621
|
+
logger$19.info({ path: this._path }, "SQLite database opened with WAL mode");
|
|
622
622
|
}
|
|
623
623
|
/**
|
|
624
624
|
* Close the database. Idempotent — calling close() when already closed is a no-op.
|
|
@@ -627,7 +627,7 @@ var DatabaseWrapper = class {
|
|
|
627
627
|
if (this._db === null) return;
|
|
628
628
|
this._db.close();
|
|
629
629
|
this._db = null;
|
|
630
|
-
logger$
|
|
630
|
+
logger$19.info({ path: this._path }, "SQLite database closed");
|
|
631
631
|
}
|
|
632
632
|
/**
|
|
633
633
|
* Return the raw BetterSqlite3 instance.
|
|
@@ -2277,6 +2277,75 @@ const PIPELINE_EVENT_METADATA = [
|
|
|
2277
2277
|
type: "string",
|
|
2278
2278
|
description: "Story key."
|
|
2279
2279
|
}]
|
|
2280
|
+
},
|
|
2281
|
+
{
|
|
2282
|
+
type: "story:interface-change-warning",
|
|
2283
|
+
description: "Non-blocking warning: modified files export shared TypeScript interfaces that may be referenced by test files outside the same module (potential stale mock risk). Story proceeds to code-review.",
|
|
2284
|
+
when: "After build verification passes, before code-review, when exported interfaces in modified .ts files are referenced by cross-module test files.",
|
|
2285
|
+
fields: [
|
|
2286
|
+
{
|
|
2287
|
+
name: "ts",
|
|
2288
|
+
type: "string",
|
|
2289
|
+
description: "Timestamp."
|
|
2290
|
+
},
|
|
2291
|
+
{
|
|
2292
|
+
name: "storyKey",
|
|
2293
|
+
type: "string",
|
|
2294
|
+
description: "Story key."
|
|
2295
|
+
},
|
|
2296
|
+
{
|
|
2297
|
+
name: "modifiedInterfaces",
|
|
2298
|
+
type: "string[]",
|
|
2299
|
+
description: "Exported interface/type names found in modified files."
|
|
2300
|
+
},
|
|
2301
|
+
{
|
|
2302
|
+
name: "potentiallyAffectedTests",
|
|
2303
|
+
type: "string[]",
|
|
2304
|
+
description: "Test file paths (relative to project root) that reference the modified interface names."
|
|
2305
|
+
}
|
|
2306
|
+
]
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
type: "story:metrics",
|
|
2310
|
+
description: "Per-story metrics on terminal state.",
|
|
2311
|
+
when: "After terminal state (success/escalation/failure).",
|
|
2312
|
+
fields: [
|
|
2313
|
+
{
|
|
2314
|
+
name: "ts",
|
|
2315
|
+
type: "string",
|
|
2316
|
+
description: "Timestamp."
|
|
2317
|
+
},
|
|
2318
|
+
{
|
|
2319
|
+
name: "storyKey",
|
|
2320
|
+
type: "string",
|
|
2321
|
+
description: "Story key."
|
|
2322
|
+
},
|
|
2323
|
+
{
|
|
2324
|
+
name: "wallClockMs",
|
|
2325
|
+
type: "number",
|
|
2326
|
+
description: "Wall-clock ms."
|
|
2327
|
+
},
|
|
2328
|
+
{
|
|
2329
|
+
name: "phaseBreakdown",
|
|
2330
|
+
type: "Record<string,number>",
|
|
2331
|
+
description: "Phase→ms durations."
|
|
2332
|
+
},
|
|
2333
|
+
{
|
|
2334
|
+
name: "tokens",
|
|
2335
|
+
type: "{input:number;output:number}",
|
|
2336
|
+
description: "Token counts."
|
|
2337
|
+
},
|
|
2338
|
+
{
|
|
2339
|
+
name: "reviewCycles",
|
|
2340
|
+
type: "number",
|
|
2341
|
+
description: "Review cycle count."
|
|
2342
|
+
},
|
|
2343
|
+
{
|
|
2344
|
+
name: "dispatches",
|
|
2345
|
+
type: "number",
|
|
2346
|
+
description: "Dispatch count."
|
|
2347
|
+
}
|
|
2348
|
+
]
|
|
2280
2349
|
}
|
|
2281
2350
|
];
|
|
2282
2351
|
/**
|
|
@@ -2606,7 +2675,7 @@ function truncateToTokens(text, maxTokens) {
|
|
|
2606
2675
|
|
|
2607
2676
|
//#endregion
|
|
2608
2677
|
//#region src/modules/context-compiler/context-compiler-impl.ts
|
|
2609
|
-
const logger$
|
|
2678
|
+
const logger$18 = createLogger("context-compiler");
|
|
2610
2679
|
/**
|
|
2611
2680
|
* Fraction of the original token budget that must remain (after required +
|
|
2612
2681
|
* important sections) before an optional section is included.
|
|
@@ -2698,7 +2767,7 @@ var ContextCompilerImpl = class {
|
|
|
2698
2767
|
includedParts.push(truncated);
|
|
2699
2768
|
remainingBudget -= truncatedTokens;
|
|
2700
2769
|
anyTruncated = true;
|
|
2701
|
-
logger$
|
|
2770
|
+
logger$18.warn({
|
|
2702
2771
|
section: section.name,
|
|
2703
2772
|
originalTokens: tokens,
|
|
2704
2773
|
budgetTokens: truncatedTokens
|
|
@@ -2712,7 +2781,7 @@ var ContextCompilerImpl = class {
|
|
|
2712
2781
|
});
|
|
2713
2782
|
} else {
|
|
2714
2783
|
anyTruncated = true;
|
|
2715
|
-
logger$
|
|
2784
|
+
logger$18.warn({
|
|
2716
2785
|
section: section.name,
|
|
2717
2786
|
tokens
|
|
2718
2787
|
}, "Context compiler: omitted \"important\" section — no budget remaining");
|
|
@@ -2739,7 +2808,7 @@ var ContextCompilerImpl = class {
|
|
|
2739
2808
|
} else {
|
|
2740
2809
|
if (tokens > 0) {
|
|
2741
2810
|
anyTruncated = true;
|
|
2742
|
-
logger$
|
|
2811
|
+
logger$18.warn({
|
|
2743
2812
|
section: section.name,
|
|
2744
2813
|
tokens,
|
|
2745
2814
|
budgetFractionRemaining: budgetFractionRemaining.toFixed(2)
|
|
@@ -3024,7 +3093,7 @@ function parseYamlResult(yamlText, schema) {
|
|
|
3024
3093
|
|
|
3025
3094
|
//#endregion
|
|
3026
3095
|
//#region src/modules/agent-dispatch/dispatcher-impl.ts
|
|
3027
|
-
const logger$
|
|
3096
|
+
const logger$17 = createLogger("agent-dispatch");
|
|
3028
3097
|
const SHUTDOWN_GRACE_MS = 1e4;
|
|
3029
3098
|
const SHUTDOWN_MAX_WAIT_MS = 3e4;
|
|
3030
3099
|
const CHARS_PER_TOKEN = 4;
|
|
@@ -3069,7 +3138,7 @@ function getAvailableMemory() {
|
|
|
3069
3138
|
}).trim(), 10);
|
|
3070
3139
|
_lastKnownPressureLevel = pressureLevel;
|
|
3071
3140
|
if (pressureLevel >= 4) {
|
|
3072
|
-
logger$
|
|
3141
|
+
logger$17.warn({ pressureLevel }, "macOS kernel reports critical memory pressure");
|
|
3073
3142
|
return 0;
|
|
3074
3143
|
}
|
|
3075
3144
|
} catch {}
|
|
@@ -3084,7 +3153,7 @@ function getAvailableMemory() {
|
|
|
3084
3153
|
const speculative = parseInt(vmstat.match(/Pages speculative:\s+(\d+)/)?.[1] ?? "0", 10);
|
|
3085
3154
|
const available = (free + purgeable + speculative) * pageSize;
|
|
3086
3155
|
if (pressureLevel >= 2) {
|
|
3087
|
-
logger$
|
|
3156
|
+
logger$17.warn({
|
|
3088
3157
|
pressureLevel,
|
|
3089
3158
|
availableBeforeDiscount: available
|
|
3090
3159
|
}, "macOS kernel reports memory pressure — discounting estimate");
|
|
@@ -3164,7 +3233,7 @@ var DispatcherImpl = class {
|
|
|
3164
3233
|
resolve: typedResolve,
|
|
3165
3234
|
reject
|
|
3166
3235
|
});
|
|
3167
|
-
logger$
|
|
3236
|
+
logger$17.debug({
|
|
3168
3237
|
id,
|
|
3169
3238
|
queueLength: this._queue.length
|
|
3170
3239
|
}, "Dispatch queued");
|
|
@@ -3195,7 +3264,7 @@ var DispatcherImpl = class {
|
|
|
3195
3264
|
async shutdown() {
|
|
3196
3265
|
this._shuttingDown = true;
|
|
3197
3266
|
this._stopMemoryPressureTimer();
|
|
3198
|
-
logger$
|
|
3267
|
+
logger$17.info({
|
|
3199
3268
|
running: this._running.size,
|
|
3200
3269
|
queued: this._queue.length
|
|
3201
3270
|
}, "Dispatcher shutting down");
|
|
@@ -3228,13 +3297,13 @@ var DispatcherImpl = class {
|
|
|
3228
3297
|
}
|
|
3229
3298
|
}, 50);
|
|
3230
3299
|
});
|
|
3231
|
-
logger$
|
|
3300
|
+
logger$17.info("Dispatcher shutdown complete");
|
|
3232
3301
|
}
|
|
3233
3302
|
async _startDispatch(id, request, resolve$2) {
|
|
3234
3303
|
const { prompt, agent, taskType, timeout, outputSchema, workingDirectory, model, maxTurns } = request;
|
|
3235
3304
|
const adapter = this._adapterRegistry.get(agent);
|
|
3236
3305
|
if (adapter === void 0) {
|
|
3237
|
-
logger$
|
|
3306
|
+
logger$17.warn({
|
|
3238
3307
|
id,
|
|
3239
3308
|
agent
|
|
3240
3309
|
}, "No adapter found for agent");
|
|
@@ -3280,7 +3349,7 @@ var DispatcherImpl = class {
|
|
|
3280
3349
|
});
|
|
3281
3350
|
const startedAt = Date.now();
|
|
3282
3351
|
proc.on("error", (err) => {
|
|
3283
|
-
logger$
|
|
3352
|
+
logger$17.error({
|
|
3284
3353
|
id,
|
|
3285
3354
|
binary: cmd.binary,
|
|
3286
3355
|
error: err.message
|
|
@@ -3288,7 +3357,7 @@ var DispatcherImpl = class {
|
|
|
3288
3357
|
});
|
|
3289
3358
|
if (proc.stdin !== null) {
|
|
3290
3359
|
proc.stdin.on("error", (err) => {
|
|
3291
|
-
if (err.code !== "EPIPE") logger$
|
|
3360
|
+
if (err.code !== "EPIPE") logger$17.warn({
|
|
3292
3361
|
id,
|
|
3293
3362
|
error: err.message
|
|
3294
3363
|
}, "stdin write error");
|
|
@@ -3330,7 +3399,7 @@ var DispatcherImpl = class {
|
|
|
3330
3399
|
agent,
|
|
3331
3400
|
taskType
|
|
3332
3401
|
});
|
|
3333
|
-
logger$
|
|
3402
|
+
logger$17.debug({
|
|
3334
3403
|
id,
|
|
3335
3404
|
agent,
|
|
3336
3405
|
taskType,
|
|
@@ -3347,7 +3416,7 @@ var DispatcherImpl = class {
|
|
|
3347
3416
|
dispatchId: id,
|
|
3348
3417
|
timeoutMs
|
|
3349
3418
|
});
|
|
3350
|
-
logger$
|
|
3419
|
+
logger$17.warn({
|
|
3351
3420
|
id,
|
|
3352
3421
|
agent,
|
|
3353
3422
|
taskType,
|
|
@@ -3401,7 +3470,7 @@ var DispatcherImpl = class {
|
|
|
3401
3470
|
exitCode: code,
|
|
3402
3471
|
output: stdout
|
|
3403
3472
|
});
|
|
3404
|
-
logger$
|
|
3473
|
+
logger$17.debug({
|
|
3405
3474
|
id,
|
|
3406
3475
|
agent,
|
|
3407
3476
|
taskType,
|
|
@@ -3427,7 +3496,7 @@ var DispatcherImpl = class {
|
|
|
3427
3496
|
error: stderr || `Process exited with code ${String(code)}`,
|
|
3428
3497
|
exitCode: code
|
|
3429
3498
|
});
|
|
3430
|
-
logger$
|
|
3499
|
+
logger$17.debug({
|
|
3431
3500
|
id,
|
|
3432
3501
|
agent,
|
|
3433
3502
|
taskType,
|
|
@@ -3486,7 +3555,7 @@ var DispatcherImpl = class {
|
|
|
3486
3555
|
const next = this._queue.shift();
|
|
3487
3556
|
if (next === void 0) return;
|
|
3488
3557
|
next.handle.status = "running";
|
|
3489
|
-
logger$
|
|
3558
|
+
logger$17.debug({
|
|
3490
3559
|
id: next.id,
|
|
3491
3560
|
queueLength: this._queue.length
|
|
3492
3561
|
}, "Dequeued dispatch");
|
|
@@ -3499,7 +3568,7 @@ var DispatcherImpl = class {
|
|
|
3499
3568
|
_isMemoryPressured() {
|
|
3500
3569
|
const free = getAvailableMemory();
|
|
3501
3570
|
if (free < MIN_FREE_MEMORY_BYTES) {
|
|
3502
|
-
logger$
|
|
3571
|
+
logger$17.warn({
|
|
3503
3572
|
freeMB: Math.round(free / 1024 / 1024),
|
|
3504
3573
|
thresholdMB: Math.round(MIN_FREE_MEMORY_BYTES / 1024 / 1024),
|
|
3505
3574
|
pressureLevel: _lastKnownPressureLevel
|
|
@@ -3748,7 +3817,7 @@ function pickRecommendation(distribution, profile, totalIssues, reviewCycles, la
|
|
|
3748
3817
|
|
|
3749
3818
|
//#endregion
|
|
3750
3819
|
//#region src/modules/compiled-workflows/prompt-assembler.ts
|
|
3751
|
-
const logger$
|
|
3820
|
+
const logger$16 = createLogger("compiled-workflows:prompt-assembler");
|
|
3752
3821
|
/**
|
|
3753
3822
|
* Assemble a final prompt from a template and sections map.
|
|
3754
3823
|
*
|
|
@@ -3773,7 +3842,7 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
3773
3842
|
tokenCount,
|
|
3774
3843
|
truncated: false
|
|
3775
3844
|
};
|
|
3776
|
-
logger$
|
|
3845
|
+
logger$16.warn({
|
|
3777
3846
|
tokenCount,
|
|
3778
3847
|
ceiling: tokenCeiling
|
|
3779
3848
|
}, "Prompt exceeds token ceiling — truncating optional sections");
|
|
@@ -3789,10 +3858,10 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
3789
3858
|
const targetSectionTokens = Math.max(0, currentSectionTokens - overBy);
|
|
3790
3859
|
if (targetSectionTokens === 0) {
|
|
3791
3860
|
contentMap[section.name] = "";
|
|
3792
|
-
logger$
|
|
3861
|
+
logger$16.warn({ sectionName: section.name }, "Section eliminated to fit token budget");
|
|
3793
3862
|
} else {
|
|
3794
3863
|
contentMap[section.name] = truncateToTokens(section.content, targetSectionTokens);
|
|
3795
|
-
logger$
|
|
3864
|
+
logger$16.warn({
|
|
3796
3865
|
sectionName: section.name,
|
|
3797
3866
|
targetSectionTokens
|
|
3798
3867
|
}, "Section truncated to fit token budget");
|
|
@@ -3803,7 +3872,7 @@ function assemblePrompt(template, sections, tokenCeiling = 2200) {
|
|
|
3803
3872
|
}
|
|
3804
3873
|
if (tokenCount <= tokenCeiling) break;
|
|
3805
3874
|
}
|
|
3806
|
-
if (tokenCount > tokenCeiling) logger$
|
|
3875
|
+
if (tokenCount > tokenCeiling) logger$16.warn({
|
|
3807
3876
|
tokenCount,
|
|
3808
3877
|
ceiling: tokenCeiling
|
|
3809
3878
|
}, "Required sections alone exceed token ceiling — returning over-budget prompt");
|
|
@@ -4019,7 +4088,7 @@ const TestExpansionResultSchema = z.object({
|
|
|
4019
4088
|
|
|
4020
4089
|
//#endregion
|
|
4021
4090
|
//#region src/modules/compiled-workflows/create-story.ts
|
|
4022
|
-
const logger$
|
|
4091
|
+
const logger$15 = createLogger("compiled-workflows:create-story");
|
|
4023
4092
|
/**
|
|
4024
4093
|
* Hard ceiling for the assembled create-story prompt.
|
|
4025
4094
|
*/
|
|
@@ -4043,7 +4112,7 @@ const TOKEN_CEILING$4 = 3e3;
|
|
|
4043
4112
|
*/
|
|
4044
4113
|
async function runCreateStory(deps, params) {
|
|
4045
4114
|
const { epicId, storyKey, pipelineRunId } = params;
|
|
4046
|
-
logger$
|
|
4115
|
+
logger$15.debug({
|
|
4047
4116
|
epicId,
|
|
4048
4117
|
storyKey,
|
|
4049
4118
|
pipelineRunId
|
|
@@ -4053,7 +4122,7 @@ async function runCreateStory(deps, params) {
|
|
|
4053
4122
|
template = await deps.pack.getPrompt("create-story");
|
|
4054
4123
|
} catch (err) {
|
|
4055
4124
|
const error = err instanceof Error ? err.message : String(err);
|
|
4056
|
-
logger$
|
|
4125
|
+
logger$15.error({ error }, "Failed to retrieve create-story prompt template");
|
|
4057
4126
|
return {
|
|
4058
4127
|
result: "failed",
|
|
4059
4128
|
error: `Failed to retrieve prompt template: ${error}`,
|
|
@@ -4095,7 +4164,7 @@ async function runCreateStory(deps, params) {
|
|
|
4095
4164
|
priority: "important"
|
|
4096
4165
|
}
|
|
4097
4166
|
], TOKEN_CEILING$4);
|
|
4098
|
-
logger$
|
|
4167
|
+
logger$15.debug({
|
|
4099
4168
|
tokenCount,
|
|
4100
4169
|
truncated,
|
|
4101
4170
|
tokenCeiling: TOKEN_CEILING$4
|
|
@@ -4112,7 +4181,7 @@ async function runCreateStory(deps, params) {
|
|
|
4112
4181
|
dispatchResult = await handle.result;
|
|
4113
4182
|
} catch (err) {
|
|
4114
4183
|
const error = err instanceof Error ? err.message : String(err);
|
|
4115
|
-
logger$
|
|
4184
|
+
logger$15.error({
|
|
4116
4185
|
epicId,
|
|
4117
4186
|
storyKey,
|
|
4118
4187
|
error
|
|
@@ -4133,7 +4202,7 @@ async function runCreateStory(deps, params) {
|
|
|
4133
4202
|
if (dispatchResult.status === "failed") {
|
|
4134
4203
|
const errorMsg = dispatchResult.parseError ?? `Dispatch failed with exit code ${dispatchResult.exitCode}`;
|
|
4135
4204
|
const stderrDetail = dispatchResult.output ? ` Output: ${dispatchResult.output}` : "";
|
|
4136
|
-
logger$
|
|
4205
|
+
logger$15.warn({
|
|
4137
4206
|
epicId,
|
|
4138
4207
|
storyKey,
|
|
4139
4208
|
exitCode: dispatchResult.exitCode
|
|
@@ -4145,7 +4214,7 @@ async function runCreateStory(deps, params) {
|
|
|
4145
4214
|
};
|
|
4146
4215
|
}
|
|
4147
4216
|
if (dispatchResult.status === "timeout") {
|
|
4148
|
-
logger$
|
|
4217
|
+
logger$15.warn({
|
|
4149
4218
|
epicId,
|
|
4150
4219
|
storyKey
|
|
4151
4220
|
}, "Create-story dispatch timed out");
|
|
@@ -4158,7 +4227,7 @@ async function runCreateStory(deps, params) {
|
|
|
4158
4227
|
if (dispatchResult.parsed === null) {
|
|
4159
4228
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
4160
4229
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
4161
|
-
logger$
|
|
4230
|
+
logger$15.warn({
|
|
4162
4231
|
epicId,
|
|
4163
4232
|
storyKey,
|
|
4164
4233
|
details,
|
|
@@ -4174,7 +4243,7 @@ async function runCreateStory(deps, params) {
|
|
|
4174
4243
|
const parseResult = CreateStoryResultSchema.safeParse(dispatchResult.parsed);
|
|
4175
4244
|
if (!parseResult.success) {
|
|
4176
4245
|
const details = parseResult.error.message;
|
|
4177
|
-
logger$
|
|
4246
|
+
logger$15.warn({
|
|
4178
4247
|
epicId,
|
|
4179
4248
|
storyKey,
|
|
4180
4249
|
details
|
|
@@ -4187,7 +4256,7 @@ async function runCreateStory(deps, params) {
|
|
|
4187
4256
|
};
|
|
4188
4257
|
}
|
|
4189
4258
|
const parsed = parseResult.data;
|
|
4190
|
-
logger$
|
|
4259
|
+
logger$15.info({
|
|
4191
4260
|
epicId,
|
|
4192
4261
|
storyKey,
|
|
4193
4262
|
storyFile: parsed.story_file,
|
|
@@ -4209,7 +4278,7 @@ function getImplementationDecisions(deps) {
|
|
|
4209
4278
|
try {
|
|
4210
4279
|
return getDecisionsByPhase(deps.db, "implementation");
|
|
4211
4280
|
} catch (err) {
|
|
4212
|
-
logger$
|
|
4281
|
+
logger$15.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve implementation decisions");
|
|
4213
4282
|
return [];
|
|
4214
4283
|
}
|
|
4215
4284
|
}
|
|
@@ -4252,13 +4321,13 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
4252
4321
|
if (storyKey) {
|
|
4253
4322
|
const storySection = extractStorySection(shardContent, storyKey);
|
|
4254
4323
|
if (storySection) {
|
|
4255
|
-
logger$
|
|
4324
|
+
logger$15.debug({
|
|
4256
4325
|
epicId,
|
|
4257
4326
|
storyKey
|
|
4258
4327
|
}, "Extracted per-story section from epic shard");
|
|
4259
4328
|
return storySection;
|
|
4260
4329
|
}
|
|
4261
|
-
logger$
|
|
4330
|
+
logger$15.debug({
|
|
4262
4331
|
epicId,
|
|
4263
4332
|
storyKey
|
|
4264
4333
|
}, "No matching story section found — using full epic shard");
|
|
@@ -4268,11 +4337,11 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
4268
4337
|
if (projectRoot) {
|
|
4269
4338
|
const fallback = readEpicShardFromFile(projectRoot, epicId);
|
|
4270
4339
|
if (fallback) {
|
|
4271
|
-
logger$
|
|
4340
|
+
logger$15.info({ epicId }, "Using file-based fallback for epic shard (decisions table empty)");
|
|
4272
4341
|
if (storyKey) {
|
|
4273
4342
|
const storySection = extractStorySection(fallback, storyKey);
|
|
4274
4343
|
if (storySection) {
|
|
4275
|
-
logger$
|
|
4344
|
+
logger$15.debug({
|
|
4276
4345
|
epicId,
|
|
4277
4346
|
storyKey
|
|
4278
4347
|
}, "Extracted per-story section from file-based epic shard");
|
|
@@ -4284,7 +4353,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
|
|
|
4284
4353
|
}
|
|
4285
4354
|
return "";
|
|
4286
4355
|
} catch (err) {
|
|
4287
|
-
logger$
|
|
4356
|
+
logger$15.warn({
|
|
4288
4357
|
epicId,
|
|
4289
4358
|
error: err instanceof Error ? err.message : String(err)
|
|
4290
4359
|
}, "Failed to retrieve epic shard");
|
|
@@ -4301,7 +4370,7 @@ function getPrevDevNotes(decisions, epicId) {
|
|
|
4301
4370
|
if (devNotes.length === 0) return "";
|
|
4302
4371
|
return devNotes[devNotes.length - 1].value;
|
|
4303
4372
|
} catch (err) {
|
|
4304
|
-
logger$
|
|
4373
|
+
logger$15.warn({
|
|
4305
4374
|
epicId,
|
|
4306
4375
|
error: err instanceof Error ? err.message : String(err)
|
|
4307
4376
|
}, "Failed to retrieve prev dev notes");
|
|
@@ -4321,13 +4390,13 @@ function getArchConstraints$2(deps) {
|
|
|
4321
4390
|
if (deps.projectRoot) {
|
|
4322
4391
|
const fallback = readArchConstraintsFromFile(deps.projectRoot);
|
|
4323
4392
|
if (fallback) {
|
|
4324
|
-
logger$
|
|
4393
|
+
logger$15.info("Using file-based fallback for architecture constraints (decisions table empty)");
|
|
4325
4394
|
return fallback;
|
|
4326
4395
|
}
|
|
4327
4396
|
}
|
|
4328
4397
|
return "";
|
|
4329
4398
|
} catch (err) {
|
|
4330
|
-
logger$
|
|
4399
|
+
logger$15.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
4331
4400
|
return "";
|
|
4332
4401
|
}
|
|
4333
4402
|
}
|
|
@@ -4347,7 +4416,7 @@ function readEpicShardFromFile(projectRoot, epicId) {
|
|
|
4347
4416
|
const match = pattern.exec(content);
|
|
4348
4417
|
return match ? match[0].trim() : "";
|
|
4349
4418
|
} catch (err) {
|
|
4350
|
-
logger$
|
|
4419
|
+
logger$15.warn({
|
|
4351
4420
|
epicId,
|
|
4352
4421
|
error: err instanceof Error ? err.message : String(err)
|
|
4353
4422
|
}, "File-based epic shard fallback failed");
|
|
@@ -4370,7 +4439,7 @@ function readArchConstraintsFromFile(projectRoot) {
|
|
|
4370
4439
|
const content = readFileSync$1(archPath, "utf-8");
|
|
4371
4440
|
return content.slice(0, 1500);
|
|
4372
4441
|
} catch (err) {
|
|
4373
|
-
logger$
|
|
4442
|
+
logger$15.warn({ error: err instanceof Error ? err.message : String(err) }, "File-based architecture fallback failed");
|
|
4374
4443
|
return "";
|
|
4375
4444
|
}
|
|
4376
4445
|
}
|
|
@@ -4383,7 +4452,7 @@ async function getStoryTemplate(deps) {
|
|
|
4383
4452
|
try {
|
|
4384
4453
|
return await deps.pack.getTemplate("story");
|
|
4385
4454
|
} catch (err) {
|
|
4386
|
-
logger$
|
|
4455
|
+
logger$15.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve story template from pack");
|
|
4387
4456
|
return "";
|
|
4388
4457
|
}
|
|
4389
4458
|
}
|
|
@@ -4420,7 +4489,7 @@ async function isValidStoryFile(filePath) {
|
|
|
4420
4489
|
|
|
4421
4490
|
//#endregion
|
|
4422
4491
|
//#region src/modules/compiled-workflows/git-helpers.ts
|
|
4423
|
-
const logger$
|
|
4492
|
+
const logger$14 = createLogger("compiled-workflows:git-helpers");
|
|
4424
4493
|
/**
|
|
4425
4494
|
* Capture the full git diff for HEAD (working tree vs current commit).
|
|
4426
4495
|
*
|
|
@@ -4516,7 +4585,7 @@ async function stageIntentToAdd(files, workingDirectory) {
|
|
|
4516
4585
|
if (files.length === 0) return;
|
|
4517
4586
|
const existing = files.filter((f) => {
|
|
4518
4587
|
const exists = existsSync$1(f);
|
|
4519
|
-
if (!exists) logger$
|
|
4588
|
+
if (!exists) logger$14.debug({ file: f }, "Skipping nonexistent file in stageIntentToAdd");
|
|
4520
4589
|
return exists;
|
|
4521
4590
|
});
|
|
4522
4591
|
if (existing.length === 0) return;
|
|
@@ -4550,7 +4619,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
4550
4619
|
stderr += chunk.toString("utf-8");
|
|
4551
4620
|
});
|
|
4552
4621
|
proc.on("error", (err) => {
|
|
4553
|
-
logger$
|
|
4622
|
+
logger$14.warn({
|
|
4554
4623
|
label: logLabel,
|
|
4555
4624
|
cwd,
|
|
4556
4625
|
error: err.message
|
|
@@ -4559,7 +4628,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
4559
4628
|
});
|
|
4560
4629
|
proc.on("close", (code) => {
|
|
4561
4630
|
if (code !== 0) {
|
|
4562
|
-
logger$
|
|
4631
|
+
logger$14.warn({
|
|
4563
4632
|
label: logLabel,
|
|
4564
4633
|
cwd,
|
|
4565
4634
|
code,
|
|
@@ -4575,7 +4644,7 @@ async function runGitCommand(args, cwd, logLabel) {
|
|
|
4575
4644
|
|
|
4576
4645
|
//#endregion
|
|
4577
4646
|
//#region src/modules/implementation-orchestrator/project-findings.ts
|
|
4578
|
-
const logger$
|
|
4647
|
+
const logger$13 = createLogger("project-findings");
|
|
4579
4648
|
/** Maximum character length for the findings summary */
|
|
4580
4649
|
const MAX_CHARS = 2e3;
|
|
4581
4650
|
/**
|
|
@@ -4630,7 +4699,7 @@ function getProjectFindings(db) {
|
|
|
4630
4699
|
if (summary.length > MAX_CHARS) summary = summary.slice(0, MAX_CHARS - 3) + "...";
|
|
4631
4700
|
return summary;
|
|
4632
4701
|
} catch (err) {
|
|
4633
|
-
logger$
|
|
4702
|
+
logger$13.warn({ err }, "Failed to query project findings (graceful fallback)");
|
|
4634
4703
|
return "";
|
|
4635
4704
|
}
|
|
4636
4705
|
}
|
|
@@ -4653,7 +4722,7 @@ function extractRecurringPatterns(outcomes) {
|
|
|
4653
4722
|
|
|
4654
4723
|
//#endregion
|
|
4655
4724
|
//#region src/modules/compiled-workflows/dev-story.ts
|
|
4656
|
-
const logger$
|
|
4725
|
+
const logger$12 = createLogger("compiled-workflows:dev-story");
|
|
4657
4726
|
/** Hard token ceiling for the assembled dev-story prompt */
|
|
4658
4727
|
const TOKEN_CEILING$3 = 24e3;
|
|
4659
4728
|
/** Default timeout for dev-story dispatches in milliseconds (30 min) */
|
|
@@ -4678,7 +4747,7 @@ const DEFAULT_VITEST_PATTERNS = `## Test Patterns (defaults)
|
|
|
4678
4747
|
*/
|
|
4679
4748
|
async function runDevStory(deps, params) {
|
|
4680
4749
|
const { storyKey, storyFilePath, taskScope, priorFiles } = params;
|
|
4681
|
-
logger$
|
|
4750
|
+
logger$12.info({
|
|
4682
4751
|
storyKey,
|
|
4683
4752
|
storyFilePath
|
|
4684
4753
|
}, "Starting compiled dev-story workflow");
|
|
@@ -4720,10 +4789,10 @@ async function runDevStory(deps, params) {
|
|
|
4720
4789
|
let template;
|
|
4721
4790
|
try {
|
|
4722
4791
|
template = await deps.pack.getPrompt("dev-story");
|
|
4723
|
-
logger$
|
|
4792
|
+
logger$12.debug({ storyKey }, "Retrieved dev-story prompt template from pack");
|
|
4724
4793
|
} catch (err) {
|
|
4725
4794
|
const error = err instanceof Error ? err.message : String(err);
|
|
4726
|
-
logger$
|
|
4795
|
+
logger$12.error({
|
|
4727
4796
|
storyKey,
|
|
4728
4797
|
error
|
|
4729
4798
|
}, "Failed to retrieve dev-story prompt template");
|
|
@@ -4734,14 +4803,14 @@ async function runDevStory(deps, params) {
|
|
|
4734
4803
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
4735
4804
|
} catch (err) {
|
|
4736
4805
|
if (err.code === "ENOENT") {
|
|
4737
|
-
logger$
|
|
4806
|
+
logger$12.error({
|
|
4738
4807
|
storyKey,
|
|
4739
4808
|
storyFilePath
|
|
4740
4809
|
}, "Story file not found");
|
|
4741
4810
|
return makeFailureResult("story_file_not_found");
|
|
4742
4811
|
}
|
|
4743
4812
|
const error = err instanceof Error ? err.message : String(err);
|
|
4744
|
-
logger$
|
|
4813
|
+
logger$12.error({
|
|
4745
4814
|
storyKey,
|
|
4746
4815
|
storyFilePath,
|
|
4747
4816
|
error
|
|
@@ -4749,7 +4818,7 @@ async function runDevStory(deps, params) {
|
|
|
4749
4818
|
return makeFailureResult(`story_file_read_error: ${error}`);
|
|
4750
4819
|
}
|
|
4751
4820
|
if (storyContent.trim().length === 0) {
|
|
4752
|
-
logger$
|
|
4821
|
+
logger$12.error({
|
|
4753
4822
|
storyKey,
|
|
4754
4823
|
storyFilePath
|
|
4755
4824
|
}, "Story file is empty");
|
|
@@ -4761,17 +4830,17 @@ async function runDevStory(deps, params) {
|
|
|
4761
4830
|
const testPatternDecisions = solutioningDecisions.filter((d) => d.category === "test-patterns");
|
|
4762
4831
|
if (testPatternDecisions.length > 0) {
|
|
4763
4832
|
testPatternsContent = "## Test Patterns\n" + testPatternDecisions.map((d) => `- ${d.key}: ${d.value}`).join("\n");
|
|
4764
|
-
logger$
|
|
4833
|
+
logger$12.debug({
|
|
4765
4834
|
storyKey,
|
|
4766
4835
|
count: testPatternDecisions.length
|
|
4767
4836
|
}, "Loaded test patterns from decision store");
|
|
4768
4837
|
} else {
|
|
4769
4838
|
testPatternsContent = DEFAULT_VITEST_PATTERNS;
|
|
4770
|
-
logger$
|
|
4839
|
+
logger$12.debug({ storyKey }, "No test-pattern decisions found — using default Vitest patterns");
|
|
4771
4840
|
}
|
|
4772
4841
|
} catch (err) {
|
|
4773
4842
|
const error = err instanceof Error ? err.message : String(err);
|
|
4774
|
-
logger$
|
|
4843
|
+
logger$12.warn({
|
|
4775
4844
|
storyKey,
|
|
4776
4845
|
error
|
|
4777
4846
|
}, "Failed to load test patterns — using defaults");
|
|
@@ -4786,7 +4855,7 @@ async function runDevStory(deps, params) {
|
|
|
4786
4855
|
const findings = getProjectFindings(deps.db);
|
|
4787
4856
|
if (findings.length > 0) {
|
|
4788
4857
|
priorFindingsContent = "Previous pipeline runs encountered these issues — avoid repeating them:\n\n" + findings;
|
|
4789
|
-
logger$
|
|
4858
|
+
logger$12.debug({
|
|
4790
4859
|
storyKey,
|
|
4791
4860
|
findingsLen: findings.length
|
|
4792
4861
|
}, "Injecting prior findings into dev-story prompt");
|
|
@@ -4806,7 +4875,7 @@ async function runDevStory(deps, params) {
|
|
|
4806
4875
|
if (plan.test_categories && plan.test_categories.length > 0) parts.push(`\n### Categories: ${plan.test_categories.join(", ")}`);
|
|
4807
4876
|
if (plan.coverage_notes) parts.push(`\n### Coverage Notes\n${plan.coverage_notes}`);
|
|
4808
4877
|
testPlanContent = parts.join("\n");
|
|
4809
|
-
logger$
|
|
4878
|
+
logger$12.debug({ storyKey }, "Injecting test plan into dev-story prompt");
|
|
4810
4879
|
}
|
|
4811
4880
|
} catch {}
|
|
4812
4881
|
const sections = [
|
|
@@ -4852,7 +4921,7 @@ async function runDevStory(deps, params) {
|
|
|
4852
4921
|
}
|
|
4853
4922
|
];
|
|
4854
4923
|
const { prompt, tokenCount, truncated } = assemblePrompt(template, sections, TOKEN_CEILING$3);
|
|
4855
|
-
logger$
|
|
4924
|
+
logger$12.info({
|
|
4856
4925
|
storyKey,
|
|
4857
4926
|
tokenCount,
|
|
4858
4927
|
ceiling: TOKEN_CEILING$3,
|
|
@@ -4871,7 +4940,7 @@ async function runDevStory(deps, params) {
|
|
|
4871
4940
|
dispatchResult = await handle.result;
|
|
4872
4941
|
} catch (err) {
|
|
4873
4942
|
const error = err instanceof Error ? err.message : String(err);
|
|
4874
|
-
logger$
|
|
4943
|
+
logger$12.error({
|
|
4875
4944
|
storyKey,
|
|
4876
4945
|
error
|
|
4877
4946
|
}, "Dispatch threw an unexpected error");
|
|
@@ -4882,11 +4951,11 @@ async function runDevStory(deps, params) {
|
|
|
4882
4951
|
output: dispatchResult.tokenEstimate.output
|
|
4883
4952
|
};
|
|
4884
4953
|
if (dispatchResult.status === "timeout") {
|
|
4885
|
-
logger$
|
|
4954
|
+
logger$12.error({
|
|
4886
4955
|
storyKey,
|
|
4887
4956
|
durationMs: dispatchResult.durationMs
|
|
4888
4957
|
}, "Dev-story dispatch timed out");
|
|
4889
|
-
if (dispatchResult.output.length > 0) logger$
|
|
4958
|
+
if (dispatchResult.output.length > 0) logger$12.info({
|
|
4890
4959
|
storyKey,
|
|
4891
4960
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
4892
4961
|
}, "Partial output before timeout");
|
|
@@ -4896,12 +4965,12 @@ async function runDevStory(deps, params) {
|
|
|
4896
4965
|
};
|
|
4897
4966
|
}
|
|
4898
4967
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
4899
|
-
logger$
|
|
4968
|
+
logger$12.error({
|
|
4900
4969
|
storyKey,
|
|
4901
4970
|
exitCode: dispatchResult.exitCode,
|
|
4902
4971
|
status: dispatchResult.status
|
|
4903
4972
|
}, "Dev-story dispatch failed");
|
|
4904
|
-
if (dispatchResult.output.length > 0) logger$
|
|
4973
|
+
if (dispatchResult.output.length > 0) logger$12.info({
|
|
4905
4974
|
storyKey,
|
|
4906
4975
|
partialOutput: dispatchResult.output.slice(0, 500)
|
|
4907
4976
|
}, "Partial output from failed dispatch");
|
|
@@ -4913,7 +4982,7 @@ async function runDevStory(deps, params) {
|
|
|
4913
4982
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
4914
4983
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
4915
4984
|
const rawSnippet = dispatchResult.output ? dispatchResult.output.slice(0, 1e3) : "(empty)";
|
|
4916
|
-
logger$
|
|
4985
|
+
logger$12.error({
|
|
4917
4986
|
storyKey,
|
|
4918
4987
|
parseError: details,
|
|
4919
4988
|
rawOutputSnippet: rawSnippet
|
|
@@ -4921,12 +4990,12 @@ async function runDevStory(deps, params) {
|
|
|
4921
4990
|
let filesModified = [];
|
|
4922
4991
|
try {
|
|
4923
4992
|
filesModified = await getGitChangedFiles(deps.projectRoot ?? process.cwd());
|
|
4924
|
-
if (filesModified.length > 0) logger$
|
|
4993
|
+
if (filesModified.length > 0) logger$12.info({
|
|
4925
4994
|
storyKey,
|
|
4926
4995
|
fileCount: filesModified.length
|
|
4927
4996
|
}, "Recovered files_modified from git status (YAML fallback)");
|
|
4928
4997
|
} catch (err) {
|
|
4929
|
-
logger$
|
|
4998
|
+
logger$12.warn({
|
|
4930
4999
|
storyKey,
|
|
4931
5000
|
error: err instanceof Error ? err.message : String(err)
|
|
4932
5001
|
}, "Failed to recover files_modified from git");
|
|
@@ -4943,7 +5012,7 @@ async function runDevStory(deps, params) {
|
|
|
4943
5012
|
};
|
|
4944
5013
|
}
|
|
4945
5014
|
const parsed = dispatchResult.parsed;
|
|
4946
|
-
logger$
|
|
5015
|
+
logger$12.info({
|
|
4947
5016
|
storyKey,
|
|
4948
5017
|
result: parsed.result,
|
|
4949
5018
|
acMet: parsed.ac_met.length
|
|
@@ -5082,7 +5151,7 @@ function extractFilesInScope(storyContent) {
|
|
|
5082
5151
|
|
|
5083
5152
|
//#endregion
|
|
5084
5153
|
//#region src/modules/compiled-workflows/code-review.ts
|
|
5085
|
-
const logger$
|
|
5154
|
+
const logger$11 = createLogger("compiled-workflows:code-review");
|
|
5086
5155
|
/**
|
|
5087
5156
|
* Hard token ceiling for the assembled code-review prompt (50,000 tokens).
|
|
5088
5157
|
* Quality reviews require seeing actual code diffs, not just file names.
|
|
@@ -5126,7 +5195,7 @@ function defaultFailResult(error, tokenUsage) {
|
|
|
5126
5195
|
async function runCodeReview(deps, params) {
|
|
5127
5196
|
const { storyKey, storyFilePath, workingDirectory, pipelineRunId, filesModified, previousIssues } = params;
|
|
5128
5197
|
const cwd = workingDirectory ?? process.cwd();
|
|
5129
|
-
logger$
|
|
5198
|
+
logger$11.debug({
|
|
5130
5199
|
storyKey,
|
|
5131
5200
|
storyFilePath,
|
|
5132
5201
|
cwd,
|
|
@@ -5137,7 +5206,7 @@ async function runCodeReview(deps, params) {
|
|
|
5137
5206
|
template = await deps.pack.getPrompt("code-review");
|
|
5138
5207
|
} catch (err) {
|
|
5139
5208
|
const error = err instanceof Error ? err.message : String(err);
|
|
5140
|
-
logger$
|
|
5209
|
+
logger$11.error({ error }, "Failed to retrieve code-review prompt template");
|
|
5141
5210
|
return defaultFailResult(`Failed to retrieve prompt template: ${error}`, {
|
|
5142
5211
|
input: 0,
|
|
5143
5212
|
output: 0
|
|
@@ -5148,7 +5217,7 @@ async function runCodeReview(deps, params) {
|
|
|
5148
5217
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
5149
5218
|
} catch (err) {
|
|
5150
5219
|
const error = err instanceof Error ? err.message : String(err);
|
|
5151
|
-
logger$
|
|
5220
|
+
logger$11.error({
|
|
5152
5221
|
storyFilePath,
|
|
5153
5222
|
error
|
|
5154
5223
|
}, "Failed to read story file");
|
|
@@ -5168,12 +5237,12 @@ async function runCodeReview(deps, params) {
|
|
|
5168
5237
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
5169
5238
|
if (scopedTotal <= TOKEN_CEILING$2) {
|
|
5170
5239
|
gitDiffContent = scopedDiff;
|
|
5171
|
-
logger$
|
|
5240
|
+
logger$11.debug({
|
|
5172
5241
|
fileCount: filesModified.length,
|
|
5173
5242
|
tokenCount: scopedTotal
|
|
5174
5243
|
}, "Using scoped file diff");
|
|
5175
5244
|
} else {
|
|
5176
|
-
logger$
|
|
5245
|
+
logger$11.warn({
|
|
5177
5246
|
estimatedTotal: scopedTotal,
|
|
5178
5247
|
ceiling: TOKEN_CEILING$2,
|
|
5179
5248
|
fileCount: filesModified.length
|
|
@@ -5187,7 +5256,7 @@ async function runCodeReview(deps, params) {
|
|
|
5187
5256
|
const fullTotal = nonDiffTokens + countTokens(fullDiff);
|
|
5188
5257
|
if (fullTotal <= TOKEN_CEILING$2) gitDiffContent = fullDiff;
|
|
5189
5258
|
else {
|
|
5190
|
-
logger$
|
|
5259
|
+
logger$11.warn({
|
|
5191
5260
|
estimatedTotal: fullTotal,
|
|
5192
5261
|
ceiling: TOKEN_CEILING$2
|
|
5193
5262
|
}, "Full git diff would exceed token ceiling — using stat-only summary");
|
|
@@ -5195,7 +5264,7 @@ async function runCodeReview(deps, params) {
|
|
|
5195
5264
|
}
|
|
5196
5265
|
}
|
|
5197
5266
|
if (gitDiffContent.trim().length === 0) {
|
|
5198
|
-
logger$
|
|
5267
|
+
logger$11.info({ storyKey }, "Empty git diff — skipping review with SHIP_IT");
|
|
5199
5268
|
return {
|
|
5200
5269
|
verdict: "SHIP_IT",
|
|
5201
5270
|
issues: 0,
|
|
@@ -5220,7 +5289,7 @@ async function runCodeReview(deps, params) {
|
|
|
5220
5289
|
const findings = getProjectFindings(deps.db);
|
|
5221
5290
|
if (findings.length > 0) {
|
|
5222
5291
|
priorFindingsContent = "Previous reviews found these recurring patterns — pay special attention:\n\n" + findings;
|
|
5223
|
-
logger$
|
|
5292
|
+
logger$11.debug({
|
|
5224
5293
|
storyKey,
|
|
5225
5294
|
findingsLen: findings.length
|
|
5226
5295
|
}, "Injecting prior findings into code-review prompt");
|
|
@@ -5254,11 +5323,11 @@ async function runCodeReview(deps, params) {
|
|
|
5254
5323
|
}
|
|
5255
5324
|
];
|
|
5256
5325
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING$2);
|
|
5257
|
-
if (assembleResult.truncated) logger$
|
|
5326
|
+
if (assembleResult.truncated) logger$11.warn({
|
|
5258
5327
|
storyKey,
|
|
5259
5328
|
tokenCount: assembleResult.tokenCount
|
|
5260
5329
|
}, "Code-review prompt truncated to fit token ceiling");
|
|
5261
|
-
logger$
|
|
5330
|
+
logger$11.debug({
|
|
5262
5331
|
storyKey,
|
|
5263
5332
|
tokenCount: assembleResult.tokenCount,
|
|
5264
5333
|
truncated: assembleResult.truncated
|
|
@@ -5276,7 +5345,7 @@ async function runCodeReview(deps, params) {
|
|
|
5276
5345
|
dispatchResult = await handle.result;
|
|
5277
5346
|
} catch (err) {
|
|
5278
5347
|
const error = err instanceof Error ? err.message : String(err);
|
|
5279
|
-
logger$
|
|
5348
|
+
logger$11.error({
|
|
5280
5349
|
storyKey,
|
|
5281
5350
|
error
|
|
5282
5351
|
}, "Code-review dispatch threw unexpected error");
|
|
@@ -5292,7 +5361,7 @@ async function runCodeReview(deps, params) {
|
|
|
5292
5361
|
const rawOutput = dispatchResult.output ?? void 0;
|
|
5293
5362
|
if (dispatchResult.status === "failed") {
|
|
5294
5363
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""} ${dispatchResult.output ? `Stderr: ${dispatchResult.output}` : ""}`.trim();
|
|
5295
|
-
logger$
|
|
5364
|
+
logger$11.warn({
|
|
5296
5365
|
storyKey,
|
|
5297
5366
|
exitCode: dispatchResult.exitCode
|
|
5298
5367
|
}, "Code-review dispatch failed");
|
|
@@ -5302,7 +5371,7 @@ async function runCodeReview(deps, params) {
|
|
|
5302
5371
|
};
|
|
5303
5372
|
}
|
|
5304
5373
|
if (dispatchResult.status === "timeout") {
|
|
5305
|
-
logger$
|
|
5374
|
+
logger$11.warn({ storyKey }, "Code-review dispatch timed out");
|
|
5306
5375
|
return {
|
|
5307
5376
|
...defaultFailResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage),
|
|
5308
5377
|
rawOutput
|
|
@@ -5310,7 +5379,7 @@ async function runCodeReview(deps, params) {
|
|
|
5310
5379
|
}
|
|
5311
5380
|
if (dispatchResult.parsed === null) {
|
|
5312
5381
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
5313
|
-
logger$
|
|
5382
|
+
logger$11.warn({
|
|
5314
5383
|
storyKey,
|
|
5315
5384
|
details
|
|
5316
5385
|
}, "Code-review output schema validation failed");
|
|
@@ -5327,7 +5396,7 @@ async function runCodeReview(deps, params) {
|
|
|
5327
5396
|
const parseResult = CodeReviewResultSchema.safeParse(dispatchResult.parsed);
|
|
5328
5397
|
if (!parseResult.success) {
|
|
5329
5398
|
const details = parseResult.error.message;
|
|
5330
|
-
logger$
|
|
5399
|
+
logger$11.warn({
|
|
5331
5400
|
storyKey,
|
|
5332
5401
|
details
|
|
5333
5402
|
}, "Code-review output failed schema validation");
|
|
@@ -5342,13 +5411,13 @@ async function runCodeReview(deps, params) {
|
|
|
5342
5411
|
};
|
|
5343
5412
|
}
|
|
5344
5413
|
const parsed = parseResult.data;
|
|
5345
|
-
if (parsed.agentVerdict !== parsed.verdict) logger$
|
|
5414
|
+
if (parsed.agentVerdict !== parsed.verdict) logger$11.info({
|
|
5346
5415
|
storyKey,
|
|
5347
5416
|
agentVerdict: parsed.agentVerdict,
|
|
5348
5417
|
pipelineVerdict: parsed.verdict,
|
|
5349
5418
|
issues: parsed.issues
|
|
5350
5419
|
}, "Pipeline overrode agent verdict based on issue severities");
|
|
5351
|
-
logger$
|
|
5420
|
+
logger$11.info({
|
|
5352
5421
|
storyKey,
|
|
5353
5422
|
verdict: parsed.verdict,
|
|
5354
5423
|
issues: parsed.issues
|
|
@@ -5373,14 +5442,14 @@ function getArchConstraints$1(deps) {
|
|
|
5373
5442
|
if (constraints.length === 0) return "";
|
|
5374
5443
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
5375
5444
|
} catch (err) {
|
|
5376
|
-
logger$
|
|
5445
|
+
logger$11.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
5377
5446
|
return "";
|
|
5378
5447
|
}
|
|
5379
5448
|
}
|
|
5380
5449
|
|
|
5381
5450
|
//#endregion
|
|
5382
5451
|
//#region src/modules/compiled-workflows/test-plan.ts
|
|
5383
|
-
const logger$
|
|
5452
|
+
const logger$10 = createLogger("compiled-workflows:test-plan");
|
|
5384
5453
|
/** Hard token ceiling for the assembled test-plan prompt */
|
|
5385
5454
|
const TOKEN_CEILING$1 = 8e3;
|
|
5386
5455
|
/** Default timeout for test-plan dispatches in milliseconds (5 min — lightweight call) */
|
|
@@ -5394,17 +5463,17 @@ const DEFAULT_TIMEOUT_MS = 3e5;
|
|
|
5394
5463
|
*/
|
|
5395
5464
|
async function runTestPlan(deps, params) {
|
|
5396
5465
|
const { storyKey, storyFilePath, pipelineRunId } = params;
|
|
5397
|
-
logger$
|
|
5466
|
+
logger$10.info({
|
|
5398
5467
|
storyKey,
|
|
5399
5468
|
storyFilePath
|
|
5400
5469
|
}, "Starting compiled test-plan workflow");
|
|
5401
5470
|
let template;
|
|
5402
5471
|
try {
|
|
5403
5472
|
template = await deps.pack.getPrompt("test-plan");
|
|
5404
|
-
logger$
|
|
5473
|
+
logger$10.debug({ storyKey }, "Retrieved test-plan prompt template from pack");
|
|
5405
5474
|
} catch (err) {
|
|
5406
5475
|
const error = err instanceof Error ? err.message : String(err);
|
|
5407
|
-
logger$
|
|
5476
|
+
logger$10.warn({
|
|
5408
5477
|
storyKey,
|
|
5409
5478
|
error
|
|
5410
5479
|
}, "Failed to retrieve test-plan prompt template");
|
|
@@ -5415,14 +5484,14 @@ async function runTestPlan(deps, params) {
|
|
|
5415
5484
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
5416
5485
|
} catch (err) {
|
|
5417
5486
|
if (err.code === "ENOENT") {
|
|
5418
|
-
logger$
|
|
5487
|
+
logger$10.warn({
|
|
5419
5488
|
storyKey,
|
|
5420
5489
|
storyFilePath
|
|
5421
5490
|
}, "Story file not found for test planning");
|
|
5422
5491
|
return makeTestPlanFailureResult("story_file_not_found");
|
|
5423
5492
|
}
|
|
5424
5493
|
const error = err instanceof Error ? err.message : String(err);
|
|
5425
|
-
logger$
|
|
5494
|
+
logger$10.warn({
|
|
5426
5495
|
storyKey,
|
|
5427
5496
|
storyFilePath,
|
|
5428
5497
|
error
|
|
@@ -5434,7 +5503,7 @@ async function runTestPlan(deps, params) {
|
|
|
5434
5503
|
content: storyContent,
|
|
5435
5504
|
priority: "required"
|
|
5436
5505
|
}], TOKEN_CEILING$1);
|
|
5437
|
-
logger$
|
|
5506
|
+
logger$10.info({
|
|
5438
5507
|
storyKey,
|
|
5439
5508
|
tokenCount,
|
|
5440
5509
|
ceiling: TOKEN_CEILING$1,
|
|
@@ -5453,7 +5522,7 @@ async function runTestPlan(deps, params) {
|
|
|
5453
5522
|
dispatchResult = await handle.result;
|
|
5454
5523
|
} catch (err) {
|
|
5455
5524
|
const error = err instanceof Error ? err.message : String(err);
|
|
5456
|
-
logger$
|
|
5525
|
+
logger$10.warn({
|
|
5457
5526
|
storyKey,
|
|
5458
5527
|
error
|
|
5459
5528
|
}, "Test-plan dispatch threw an unexpected error");
|
|
@@ -5464,7 +5533,7 @@ async function runTestPlan(deps, params) {
|
|
|
5464
5533
|
output: dispatchResult.tokenEstimate.output
|
|
5465
5534
|
};
|
|
5466
5535
|
if (dispatchResult.status === "timeout") {
|
|
5467
|
-
logger$
|
|
5536
|
+
logger$10.warn({
|
|
5468
5537
|
storyKey,
|
|
5469
5538
|
durationMs: dispatchResult.durationMs
|
|
5470
5539
|
}, "Test-plan dispatch timed out");
|
|
@@ -5474,7 +5543,7 @@ async function runTestPlan(deps, params) {
|
|
|
5474
5543
|
};
|
|
5475
5544
|
}
|
|
5476
5545
|
if (dispatchResult.status === "failed" || dispatchResult.exitCode !== 0) {
|
|
5477
|
-
logger$
|
|
5546
|
+
logger$10.warn({
|
|
5478
5547
|
storyKey,
|
|
5479
5548
|
exitCode: dispatchResult.exitCode,
|
|
5480
5549
|
status: dispatchResult.status
|
|
@@ -5486,7 +5555,7 @@ async function runTestPlan(deps, params) {
|
|
|
5486
5555
|
}
|
|
5487
5556
|
if (dispatchResult.parseError !== null || dispatchResult.parsed === null) {
|
|
5488
5557
|
const details = dispatchResult.parseError ?? "parsed result was null";
|
|
5489
|
-
logger$
|
|
5558
|
+
logger$10.warn({
|
|
5490
5559
|
storyKey,
|
|
5491
5560
|
parseError: details
|
|
5492
5561
|
}, "Test-plan YAML schema validation failed");
|
|
@@ -5509,19 +5578,19 @@ async function runTestPlan(deps, params) {
|
|
|
5509
5578
|
}),
|
|
5510
5579
|
rationale: `Test plan for ${storyKey}: ${parsed.test_files.length} test files, categories: ${parsed.test_categories.join(", ")}`
|
|
5511
5580
|
});
|
|
5512
|
-
logger$
|
|
5581
|
+
logger$10.info({
|
|
5513
5582
|
storyKey,
|
|
5514
5583
|
fileCount: parsed.test_files.length,
|
|
5515
5584
|
categories: parsed.test_categories
|
|
5516
5585
|
}, "Test plan stored in decision store");
|
|
5517
5586
|
} catch (err) {
|
|
5518
5587
|
const error = err instanceof Error ? err.message : String(err);
|
|
5519
|
-
logger$
|
|
5588
|
+
logger$10.warn({
|
|
5520
5589
|
storyKey,
|
|
5521
5590
|
error
|
|
5522
5591
|
}, "Failed to store test plan in decision store — proceeding anyway");
|
|
5523
5592
|
}
|
|
5524
|
-
logger$
|
|
5593
|
+
logger$10.info({
|
|
5525
5594
|
storyKey,
|
|
5526
5595
|
result: parsed.result
|
|
5527
5596
|
}, "Test-plan workflow completed");
|
|
@@ -5552,7 +5621,7 @@ function makeTestPlanFailureResult(error) {
|
|
|
5552
5621
|
|
|
5553
5622
|
//#endregion
|
|
5554
5623
|
//#region src/modules/compiled-workflows/test-expansion.ts
|
|
5555
|
-
const logger$
|
|
5624
|
+
const logger$9 = createLogger("compiled-workflows:test-expansion");
|
|
5556
5625
|
/**
|
|
5557
5626
|
* Hard token ceiling for the assembled test-expansion prompt (20,000 tokens).
|
|
5558
5627
|
*/
|
|
@@ -5586,7 +5655,7 @@ function defaultFallbackResult(error, tokenUsage) {
|
|
|
5586
5655
|
async function runTestExpansion(deps, params) {
|
|
5587
5656
|
const { storyKey, storyFilePath, pipelineRunId, filesModified, workingDirectory } = params;
|
|
5588
5657
|
const cwd = workingDirectory ?? process.cwd();
|
|
5589
|
-
logger$
|
|
5658
|
+
logger$9.debug({
|
|
5590
5659
|
storyKey,
|
|
5591
5660
|
storyFilePath,
|
|
5592
5661
|
cwd,
|
|
@@ -5597,7 +5666,7 @@ async function runTestExpansion(deps, params) {
|
|
|
5597
5666
|
template = await deps.pack.getPrompt("test-expansion");
|
|
5598
5667
|
} catch (err) {
|
|
5599
5668
|
const error = err instanceof Error ? err.message : String(err);
|
|
5600
|
-
logger$
|
|
5669
|
+
logger$9.warn({ error }, "Failed to retrieve test-expansion prompt template");
|
|
5601
5670
|
return defaultFallbackResult(`Failed to retrieve prompt template: ${error}`, {
|
|
5602
5671
|
input: 0,
|
|
5603
5672
|
output: 0
|
|
@@ -5608,7 +5677,7 @@ async function runTestExpansion(deps, params) {
|
|
|
5608
5677
|
storyContent = await readFile$1(storyFilePath, "utf-8");
|
|
5609
5678
|
} catch (err) {
|
|
5610
5679
|
const error = err instanceof Error ? err.message : String(err);
|
|
5611
|
-
logger$
|
|
5680
|
+
logger$9.warn({
|
|
5612
5681
|
storyFilePath,
|
|
5613
5682
|
error
|
|
5614
5683
|
}, "Failed to read story file");
|
|
@@ -5628,12 +5697,12 @@ async function runTestExpansion(deps, params) {
|
|
|
5628
5697
|
const scopedTotal = nonDiffTokens + countTokens(scopedDiff);
|
|
5629
5698
|
if (scopedTotal <= TOKEN_CEILING) {
|
|
5630
5699
|
gitDiffContent = scopedDiff;
|
|
5631
|
-
logger$
|
|
5700
|
+
logger$9.debug({
|
|
5632
5701
|
fileCount: filesModified.length,
|
|
5633
5702
|
tokenCount: scopedTotal
|
|
5634
5703
|
}, "Using scoped file diff");
|
|
5635
5704
|
} else {
|
|
5636
|
-
logger$
|
|
5705
|
+
logger$9.warn({
|
|
5637
5706
|
estimatedTotal: scopedTotal,
|
|
5638
5707
|
ceiling: TOKEN_CEILING,
|
|
5639
5708
|
fileCount: filesModified.length
|
|
@@ -5641,7 +5710,7 @@ async function runTestExpansion(deps, params) {
|
|
|
5641
5710
|
gitDiffContent = await getGitDiffStatSummary(cwd);
|
|
5642
5711
|
}
|
|
5643
5712
|
} catch (err) {
|
|
5644
|
-
logger$
|
|
5713
|
+
logger$9.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to get git diff — proceeding with empty diff");
|
|
5645
5714
|
}
|
|
5646
5715
|
const sections = [
|
|
5647
5716
|
{
|
|
@@ -5661,11 +5730,11 @@ async function runTestExpansion(deps, params) {
|
|
|
5661
5730
|
}
|
|
5662
5731
|
];
|
|
5663
5732
|
const assembleResult = assemblePrompt(template, sections, TOKEN_CEILING);
|
|
5664
|
-
if (assembleResult.truncated) logger$
|
|
5733
|
+
if (assembleResult.truncated) logger$9.warn({
|
|
5665
5734
|
storyKey,
|
|
5666
5735
|
tokenCount: assembleResult.tokenCount
|
|
5667
5736
|
}, "Test-expansion prompt truncated to fit token ceiling");
|
|
5668
|
-
logger$
|
|
5737
|
+
logger$9.debug({
|
|
5669
5738
|
storyKey,
|
|
5670
5739
|
tokenCount: assembleResult.tokenCount,
|
|
5671
5740
|
truncated: assembleResult.truncated
|
|
@@ -5683,7 +5752,7 @@ async function runTestExpansion(deps, params) {
|
|
|
5683
5752
|
dispatchResult = await handle.result;
|
|
5684
5753
|
} catch (err) {
|
|
5685
5754
|
const error = err instanceof Error ? err.message : String(err);
|
|
5686
|
-
logger$
|
|
5755
|
+
logger$9.warn({
|
|
5687
5756
|
storyKey,
|
|
5688
5757
|
error
|
|
5689
5758
|
}, "Test-expansion dispatch threw unexpected error");
|
|
@@ -5698,19 +5767,19 @@ async function runTestExpansion(deps, params) {
|
|
|
5698
5767
|
};
|
|
5699
5768
|
if (dispatchResult.status === "failed") {
|
|
5700
5769
|
const errorMsg = `Dispatch status: failed. Exit code: ${dispatchResult.exitCode}. ${dispatchResult.parseError ?? ""}`.trim();
|
|
5701
|
-
logger$
|
|
5770
|
+
logger$9.warn({
|
|
5702
5771
|
storyKey,
|
|
5703
5772
|
exitCode: dispatchResult.exitCode
|
|
5704
5773
|
}, "Test-expansion dispatch failed");
|
|
5705
5774
|
return defaultFallbackResult(errorMsg, tokenUsage);
|
|
5706
5775
|
}
|
|
5707
5776
|
if (dispatchResult.status === "timeout") {
|
|
5708
|
-
logger$
|
|
5777
|
+
logger$9.warn({ storyKey }, "Test-expansion dispatch timed out");
|
|
5709
5778
|
return defaultFallbackResult("Dispatch status: timeout. The agent did not complete within the allowed time.", tokenUsage);
|
|
5710
5779
|
}
|
|
5711
5780
|
if (dispatchResult.parsed === null) {
|
|
5712
5781
|
const details = dispatchResult.parseError ?? "No YAML block found in output";
|
|
5713
|
-
logger$
|
|
5782
|
+
logger$9.warn({
|
|
5714
5783
|
storyKey,
|
|
5715
5784
|
details
|
|
5716
5785
|
}, "Test-expansion output has no parseable YAML");
|
|
@@ -5719,14 +5788,14 @@ async function runTestExpansion(deps, params) {
|
|
|
5719
5788
|
const parseResult = TestExpansionResultSchema.safeParse(dispatchResult.parsed);
|
|
5720
5789
|
if (!parseResult.success) {
|
|
5721
5790
|
const details = parseResult.error.message;
|
|
5722
|
-
logger$
|
|
5791
|
+
logger$9.warn({
|
|
5723
5792
|
storyKey,
|
|
5724
5793
|
details
|
|
5725
5794
|
}, "Test-expansion output failed schema validation");
|
|
5726
5795
|
return defaultFallbackResult(`schema_validation_failed: ${details}`, tokenUsage);
|
|
5727
5796
|
}
|
|
5728
5797
|
const parsed = parseResult.data;
|
|
5729
|
-
logger$
|
|
5798
|
+
logger$9.info({
|
|
5730
5799
|
storyKey,
|
|
5731
5800
|
expansion_priority: parsed.expansion_priority,
|
|
5732
5801
|
coverage_gaps: parsed.coverage_gaps.length,
|
|
@@ -5751,7 +5820,7 @@ function getArchConstraints(deps) {
|
|
|
5751
5820
|
if (constraints.length === 0) return "";
|
|
5752
5821
|
return constraints.map((d) => `${d.key}: ${d.value}`).join("\n");
|
|
5753
5822
|
} catch (err) {
|
|
5754
|
-
logger$
|
|
5823
|
+
logger$9.warn({ error: err instanceof Error ? err.message : String(err) }, "Failed to retrieve architecture constraints");
|
|
5755
5824
|
return "";
|
|
5756
5825
|
}
|
|
5757
5826
|
}
|
|
@@ -6064,7 +6133,7 @@ function detectConflictGroups(storyKeys, config) {
|
|
|
6064
6133
|
|
|
6065
6134
|
//#endregion
|
|
6066
6135
|
//#region src/cli/commands/health.ts
|
|
6067
|
-
const logger$
|
|
6136
|
+
const logger$8 = createLogger("health-cmd");
|
|
6068
6137
|
/** Default stall threshold in seconds — also used by supervisor default */
|
|
6069
6138
|
const DEFAULT_STALL_THRESHOLD_SECONDS = 600;
|
|
6070
6139
|
/**
|
|
@@ -6329,7 +6398,7 @@ async function runHealthAction(options) {
|
|
|
6329
6398
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6330
6399
|
if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
|
|
6331
6400
|
else process.stderr.write(`Error: ${msg}\n`);
|
|
6332
|
-
logger$
|
|
6401
|
+
logger$8.error({ err }, "health action failed");
|
|
6333
6402
|
return 1;
|
|
6334
6403
|
}
|
|
6335
6404
|
}
|
|
@@ -6347,7 +6416,7 @@ function registerHealthCommand(program, _version = "0.0.0", projectRoot = proces
|
|
|
6347
6416
|
|
|
6348
6417
|
//#endregion
|
|
6349
6418
|
//#region src/modules/implementation-orchestrator/seed-methodology-context.ts
|
|
6350
|
-
const logger$
|
|
6419
|
+
const logger$7 = createLogger("implementation-orchestrator:seed");
|
|
6351
6420
|
/** Max chars for the architecture summary seeded into decisions */
|
|
6352
6421
|
const MAX_ARCH_CHARS = 6e3;
|
|
6353
6422
|
/** Max chars per epic shard (fallback when per-story extraction returns null) */
|
|
@@ -6381,12 +6450,12 @@ function seedMethodologyContext(db, projectRoot) {
|
|
|
6381
6450
|
const testCount = seedTestPatterns(db, projectRoot);
|
|
6382
6451
|
if (testCount === -1) result.skippedCategories.push("test-patterns");
|
|
6383
6452
|
else result.decisionsCreated += testCount;
|
|
6384
|
-
logger$
|
|
6453
|
+
logger$7.info({
|
|
6385
6454
|
decisionsCreated: result.decisionsCreated,
|
|
6386
6455
|
skippedCategories: result.skippedCategories
|
|
6387
6456
|
}, "Methodology context seeding complete");
|
|
6388
6457
|
} catch (err) {
|
|
6389
|
-
logger$
|
|
6458
|
+
logger$7.warn({ error: err instanceof Error ? err.message : String(err) }, "Methodology context seeding failed (non-fatal)");
|
|
6390
6459
|
}
|
|
6391
6460
|
return result;
|
|
6392
6461
|
}
|
|
@@ -6430,7 +6499,7 @@ function seedArchitecture(db, projectRoot) {
|
|
|
6430
6499
|
});
|
|
6431
6500
|
count = 1;
|
|
6432
6501
|
}
|
|
6433
|
-
logger$
|
|
6502
|
+
logger$7.debug({ count }, "Seeded architecture decisions");
|
|
6434
6503
|
return count;
|
|
6435
6504
|
}
|
|
6436
6505
|
/**
|
|
@@ -6454,11 +6523,11 @@ function seedEpicShards(db, projectRoot) {
|
|
|
6454
6523
|
const storedHashDecision = implementationDecisions.find((d) => d.category === "epic-shard-hash" && d.key === "epics-file");
|
|
6455
6524
|
const storedHash = storedHashDecision?.value;
|
|
6456
6525
|
if (storedHash === currentHash) {
|
|
6457
|
-
logger$
|
|
6526
|
+
logger$7.debug({ hash: currentHash }, "Epic shards up-to-date (hash unchanged) — skipping re-seed");
|
|
6458
6527
|
return -1;
|
|
6459
6528
|
}
|
|
6460
6529
|
if (implementationDecisions.some((d) => d.category === "epic-shard")) {
|
|
6461
|
-
logger$
|
|
6530
|
+
logger$7.debug({
|
|
6462
6531
|
storedHash,
|
|
6463
6532
|
currentHash
|
|
6464
6533
|
}, "Epics file changed — deleting stale epic-shard decisions");
|
|
@@ -6486,7 +6555,7 @@ function seedEpicShards(db, projectRoot) {
|
|
|
6486
6555
|
value: currentHash,
|
|
6487
6556
|
rationale: "SHA-256 hash of epics file content for change detection"
|
|
6488
6557
|
});
|
|
6489
|
-
logger$
|
|
6558
|
+
logger$7.debug({
|
|
6490
6559
|
count,
|
|
6491
6560
|
hash: currentHash
|
|
6492
6561
|
}, "Seeded epic shard decisions");
|
|
@@ -6510,7 +6579,7 @@ function seedTestPatterns(db, projectRoot) {
|
|
|
6510
6579
|
value: patterns.slice(0, MAX_TEST_PATTERNS_CHARS),
|
|
6511
6580
|
rationale: "Detected from project configuration at orchestrator startup"
|
|
6512
6581
|
});
|
|
6513
|
-
logger$
|
|
6582
|
+
logger$7.debug("Seeded test patterns decision");
|
|
6514
6583
|
return 1;
|
|
6515
6584
|
}
|
|
6516
6585
|
/**
|
|
@@ -6681,6 +6750,107 @@ function findArtifact(projectRoot, candidates) {
|
|
|
6681
6750
|
return void 0;
|
|
6682
6751
|
}
|
|
6683
6752
|
|
|
6753
|
+
//#endregion
|
|
6754
|
+
//#region src/modules/agent-dispatch/interface-change-detector.ts
|
|
6755
|
+
const logger$6 = createLogger("interface-change-detector");
|
|
6756
|
+
/**
|
|
6757
|
+
* Extract exported interface and type names from TypeScript source content.
|
|
6758
|
+
*
|
|
6759
|
+
* Matches:
|
|
6760
|
+
* export interface Foo { ... } → 'Foo'
|
|
6761
|
+
* export type Bar = ... → 'Bar'
|
|
6762
|
+
*
|
|
6763
|
+
* Uses simple regex (not AST) for performance (<500ms target).
|
|
6764
|
+
* Does NOT match: re-exports (`export { Foo }`), default exports, internal declarations.
|
|
6765
|
+
*/
|
|
6766
|
+
function extractExportedNames(content) {
|
|
6767
|
+
const names = [];
|
|
6768
|
+
const pattern = /^export\s+(?:interface|type)\s+(\w+)/gm;
|
|
6769
|
+
let match;
|
|
6770
|
+
while ((match = pattern.exec(content)) !== null) if (match[1] !== void 0) names.push(match[1]);
|
|
6771
|
+
return names;
|
|
6772
|
+
}
|
|
6773
|
+
/**
|
|
6774
|
+
* Detect whether modified .ts files export interfaces/types that are
|
|
6775
|
+
* referenced by test files outside the same module.
|
|
6776
|
+
*
|
|
6777
|
+
* Non-blocking: any errors during detection are caught, logged, and an empty
|
|
6778
|
+
* result is returned rather than throwing. Detection failure never blocks pipeline.
|
|
6779
|
+
*
|
|
6780
|
+
* @param options.filesModified - List of file paths modified by the dev-story (relative to projectRoot)
|
|
6781
|
+
* @param options.projectRoot - Absolute path to the project root
|
|
6782
|
+
* @param options.storyKey - Story key for logging context
|
|
6783
|
+
*/
|
|
6784
|
+
function detectInterfaceChanges(options) {
|
|
6785
|
+
try {
|
|
6786
|
+
const { filesModified, projectRoot, storyKey } = options;
|
|
6787
|
+
const tsSourceFiles = filesModified.filter((f) => f.endsWith(".ts") && !f.endsWith(".test.ts") && !f.endsWith(".spec.ts"));
|
|
6788
|
+
if (tsSourceFiles.length === 0) return {
|
|
6789
|
+
modifiedInterfaces: [],
|
|
6790
|
+
potentiallyAffectedTests: []
|
|
6791
|
+
};
|
|
6792
|
+
const allNames = new Set();
|
|
6793
|
+
const sourceDirs = [];
|
|
6794
|
+
for (const relPath of tsSourceFiles) {
|
|
6795
|
+
const absPath = join$1(projectRoot, relPath);
|
|
6796
|
+
try {
|
|
6797
|
+
const content = readFileSync$1(absPath, "utf-8");
|
|
6798
|
+
const names = extractExportedNames(content);
|
|
6799
|
+
for (const name of names) allNames.add(name);
|
|
6800
|
+
sourceDirs.push(dirname$1(relPath));
|
|
6801
|
+
} catch {
|
|
6802
|
+
logger$6.debug({
|
|
6803
|
+
absPath,
|
|
6804
|
+
storyKey
|
|
6805
|
+
}, "Could not read modified file for interface extraction");
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
if (allNames.size === 0) return {
|
|
6809
|
+
modifiedInterfaces: [],
|
|
6810
|
+
potentiallyAffectedTests: []
|
|
6811
|
+
};
|
|
6812
|
+
const affectedTests = new Set();
|
|
6813
|
+
for (const name of allNames) {
|
|
6814
|
+
let grepOutput = "";
|
|
6815
|
+
try {
|
|
6816
|
+
grepOutput = execSync(`grep -r --include="*.test.ts" --include="*.spec.ts" -l "${name}" .`, {
|
|
6817
|
+
cwd: projectRoot,
|
|
6818
|
+
encoding: "utf-8",
|
|
6819
|
+
timeout: 1e4,
|
|
6820
|
+
stdio: [
|
|
6821
|
+
"ignore",
|
|
6822
|
+
"pipe",
|
|
6823
|
+
"pipe"
|
|
6824
|
+
]
|
|
6825
|
+
});
|
|
6826
|
+
} catch (grepErr) {
|
|
6827
|
+
const e = grepErr;
|
|
6828
|
+
if (typeof e.stdout === "string" && e.stdout.trim().length > 0) grepOutput = e.stdout;
|
|
6829
|
+
else continue;
|
|
6830
|
+
}
|
|
6831
|
+
const testFiles = grepOutput.split("\n").map((l) => l.trim().replace(/^\.\//, "")).filter((l) => l.length > 0);
|
|
6832
|
+
for (const tf of testFiles) {
|
|
6833
|
+
const tfDir = dirname$1(tf);
|
|
6834
|
+
const isSameModule = sourceDirs.some((srcDir) => tfDir === srcDir || tfDir.startsWith(srcDir + "/"));
|
|
6835
|
+
if (!isSameModule) affectedTests.add(tf);
|
|
6836
|
+
}
|
|
6837
|
+
}
|
|
6838
|
+
return {
|
|
6839
|
+
modifiedInterfaces: Array.from(allNames),
|
|
6840
|
+
potentiallyAffectedTests: Array.from(affectedTests)
|
|
6841
|
+
};
|
|
6842
|
+
} catch (err) {
|
|
6843
|
+
logger$6.warn({
|
|
6844
|
+
err,
|
|
6845
|
+
storyKey: options.storyKey
|
|
6846
|
+
}, "Interface change detection failed — skipping");
|
|
6847
|
+
return {
|
|
6848
|
+
modifiedInterfaces: [],
|
|
6849
|
+
potentiallyAffectedTests: []
|
|
6850
|
+
};
|
|
6851
|
+
}
|
|
6852
|
+
}
|
|
6853
|
+
|
|
6684
6854
|
//#endregion
|
|
6685
6855
|
//#region src/modules/implementation-orchestrator/orchestrator-impl.ts
|
|
6686
6856
|
function createPauseGate() {
|
|
@@ -6702,7 +6872,7 @@ function createPauseGate() {
|
|
|
6702
6872
|
*/
|
|
6703
6873
|
function createImplementationOrchestrator(deps) {
|
|
6704
6874
|
const { db, pack, contextCompiler, dispatcher, eventBus, config, projectRoot } = deps;
|
|
6705
|
-
const logger$
|
|
6875
|
+
const logger$21 = createLogger("implementation-orchestrator");
|
|
6706
6876
|
let _state = "IDLE";
|
|
6707
6877
|
let _startedAt;
|
|
6708
6878
|
let _completedAt;
|
|
@@ -6745,7 +6915,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
6745
6915
|
const nowMs = Date.now();
|
|
6746
6916
|
for (const [phase, startMs] of starts) {
|
|
6747
6917
|
const endMs = ends?.get(phase);
|
|
6748
|
-
if (endMs === void 0) logger$
|
|
6918
|
+
if (endMs === void 0) logger$21.warn({
|
|
6749
6919
|
storyKey,
|
|
6750
6920
|
phase
|
|
6751
6921
|
}, "Phase has no end time — story may have errored mid-phase. Duration capped to now() and may be inflated.");
|
|
@@ -6760,12 +6930,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
6760
6930
|
const startedAt = storyState?.startedAt;
|
|
6761
6931
|
const completedAt = storyState?.completedAt ?? new Date().toISOString();
|
|
6762
6932
|
const wallClockSeconds = startedAt ? Math.round((new Date(completedAt).getTime() - new Date(startedAt).getTime()) / 1e3) : 0;
|
|
6933
|
+
const wallClockMs = startedAt ? new Date(completedAt).getTime() - new Date(startedAt).getTime() : 0;
|
|
6763
6934
|
const tokenAgg = aggregateTokenUsageForStory(db, config.pipelineRunId, storyKey);
|
|
6935
|
+
const phaseDurationsJson = buildPhaseDurationsJson(storyKey);
|
|
6764
6936
|
writeStoryMetrics(db, {
|
|
6765
6937
|
run_id: config.pipelineRunId,
|
|
6766
6938
|
story_key: storyKey,
|
|
6767
6939
|
result,
|
|
6768
|
-
phase_durations_json:
|
|
6940
|
+
phase_durations_json: phaseDurationsJson,
|
|
6769
6941
|
started_at: startedAt,
|
|
6770
6942
|
completed_at: completedAt,
|
|
6771
6943
|
wall_clock_seconds: wallClockSeconds,
|
|
@@ -6792,13 +6964,41 @@ function createImplementationOrchestrator(deps) {
|
|
|
6792
6964
|
rationale: `Story ${storyKey} completed with result=${result} in ${wallClockSeconds}s. Tokens: ${tokenAgg.input}+${tokenAgg.output}. Review cycles: ${reviewCycles}.`
|
|
6793
6965
|
});
|
|
6794
6966
|
} catch (decisionErr) {
|
|
6795
|
-
logger$
|
|
6967
|
+
logger$21.warn({
|
|
6796
6968
|
err: decisionErr,
|
|
6797
6969
|
storyKey
|
|
6798
6970
|
}, "Failed to write story-metrics decision (best-effort)");
|
|
6799
6971
|
}
|
|
6972
|
+
try {
|
|
6973
|
+
const phaseBreakdown = {};
|
|
6974
|
+
const starts = _phaseStartMs.get(storyKey);
|
|
6975
|
+
const ends = _phaseEndMs.get(storyKey);
|
|
6976
|
+
if (starts) {
|
|
6977
|
+
const nowMs = Date.now();
|
|
6978
|
+
for (const [phase, startMs] of starts) {
|
|
6979
|
+
const endMs = ends?.get(phase);
|
|
6980
|
+
phaseBreakdown[phase] = endMs !== void 0 ? endMs - startMs : nowMs - startMs;
|
|
6981
|
+
}
|
|
6982
|
+
}
|
|
6983
|
+
eventBus.emit("story:metrics", {
|
|
6984
|
+
storyKey,
|
|
6985
|
+
wallClockMs,
|
|
6986
|
+
phaseBreakdown,
|
|
6987
|
+
tokens: {
|
|
6988
|
+
input: tokenAgg.input,
|
|
6989
|
+
output: tokenAgg.output
|
|
6990
|
+
},
|
|
6991
|
+
reviewCycles,
|
|
6992
|
+
dispatches: _storyDispatches.get(storyKey) ?? 0
|
|
6993
|
+
});
|
|
6994
|
+
} catch (emitErr) {
|
|
6995
|
+
logger$21.warn({
|
|
6996
|
+
err: emitErr,
|
|
6997
|
+
storyKey
|
|
6998
|
+
}, "Failed to emit story:metrics event (best-effort)");
|
|
6999
|
+
}
|
|
6800
7000
|
} catch (err) {
|
|
6801
|
-
logger$
|
|
7001
|
+
logger$21.warn({
|
|
6802
7002
|
err,
|
|
6803
7003
|
storyKey
|
|
6804
7004
|
}, "Failed to write story metrics (best-effort)");
|
|
@@ -6827,7 +7027,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
6827
7027
|
rationale: `Story ${storyKey} ${outcome} after ${reviewCycles} review cycle(s).`
|
|
6828
7028
|
});
|
|
6829
7029
|
} catch (err) {
|
|
6830
|
-
logger$
|
|
7030
|
+
logger$21.warn({
|
|
6831
7031
|
err,
|
|
6832
7032
|
storyKey
|
|
6833
7033
|
}, "Failed to write story-outcome decision (best-effort)");
|
|
@@ -6853,7 +7053,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
6853
7053
|
rationale: `Escalation diagnosis for ${payload.storyKey}: ${diagnosis.recommendedAction} — ${diagnosis.rationale}`
|
|
6854
7054
|
});
|
|
6855
7055
|
} catch (err) {
|
|
6856
|
-
logger$
|
|
7056
|
+
logger$21.warn({
|
|
6857
7057
|
err,
|
|
6858
7058
|
storyKey: payload.storyKey
|
|
6859
7059
|
}, "Failed to persist escalation diagnosis (best-effort)");
|
|
@@ -6903,7 +7103,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
6903
7103
|
token_usage_json: serialized
|
|
6904
7104
|
});
|
|
6905
7105
|
} catch (err) {
|
|
6906
|
-
logger$
|
|
7106
|
+
logger$21.warn("Failed to persist orchestrator state", { err });
|
|
6907
7107
|
}
|
|
6908
7108
|
}
|
|
6909
7109
|
function recordProgress() {
|
|
@@ -6950,7 +7150,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
6950
7150
|
}
|
|
6951
7151
|
if (childActive) {
|
|
6952
7152
|
_lastProgressTs = Date.now();
|
|
6953
|
-
logger$
|
|
7153
|
+
logger$21.debug({
|
|
6954
7154
|
storyKey: key,
|
|
6955
7155
|
phase: s.phase,
|
|
6956
7156
|
childPids
|
|
@@ -6959,7 +7159,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
6959
7159
|
}
|
|
6960
7160
|
_stalledStories.add(key);
|
|
6961
7161
|
_storiesWithStall.add(key);
|
|
6962
|
-
logger$
|
|
7162
|
+
logger$21.warn({
|
|
6963
7163
|
storyKey: key,
|
|
6964
7164
|
phase: s.phase,
|
|
6965
7165
|
elapsedMs: elapsed,
|
|
@@ -7004,7 +7204,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7004
7204
|
for (let attempt = 0; attempt < MEMORY_PRESSURE_BACKOFF_MS.length; attempt++) {
|
|
7005
7205
|
const memState = dispatcher.getMemoryState();
|
|
7006
7206
|
if (!memState.isPressured) return true;
|
|
7007
|
-
logger$
|
|
7207
|
+
logger$21.warn({
|
|
7008
7208
|
storyKey,
|
|
7009
7209
|
freeMB: memState.freeMB,
|
|
7010
7210
|
thresholdMB: memState.thresholdMB,
|
|
@@ -7024,11 +7224,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
7024
7224
|
* exhausted retries the story is ESCALATED.
|
|
7025
7225
|
*/
|
|
7026
7226
|
async function processStory(storyKey) {
|
|
7027
|
-
logger$
|
|
7227
|
+
logger$21.info("Processing story", { storyKey });
|
|
7028
7228
|
{
|
|
7029
7229
|
const memoryOk = await checkMemoryPressure(storyKey);
|
|
7030
7230
|
if (!memoryOk) {
|
|
7031
|
-
logger$
|
|
7231
|
+
logger$21.warn({ storyKey }, "Memory pressure exhausted — escalating story without dispatch");
|
|
7032
7232
|
_stories.set(storyKey, {
|
|
7033
7233
|
phase: "ESCALATED",
|
|
7034
7234
|
reviewCycles: 0,
|
|
@@ -7062,14 +7262,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
7062
7262
|
if (match) {
|
|
7063
7263
|
const candidatePath = join$1(artifactsDir, match);
|
|
7064
7264
|
const validation = await isValidStoryFile(candidatePath);
|
|
7065
|
-
if (!validation.valid) logger$
|
|
7265
|
+
if (!validation.valid) logger$21.warn({
|
|
7066
7266
|
storyKey,
|
|
7067
7267
|
storyFilePath: candidatePath,
|
|
7068
7268
|
reason: validation.reason
|
|
7069
7269
|
}, `Existing story file for ${storyKey} is invalid (${validation.reason}) — re-creating`);
|
|
7070
7270
|
else {
|
|
7071
7271
|
storyFilePath = candidatePath;
|
|
7072
|
-
logger$
|
|
7272
|
+
logger$21.info({
|
|
7073
7273
|
storyKey,
|
|
7074
7274
|
storyFilePath
|
|
7075
7275
|
}, "Found existing story file — skipping create-story");
|
|
@@ -7179,10 +7379,10 @@ function createImplementationOrchestrator(deps) {
|
|
|
7179
7379
|
pipelineRunId: config.pipelineRunId
|
|
7180
7380
|
});
|
|
7181
7381
|
testPlanPhaseResult = testPlanResult.result;
|
|
7182
|
-
if (testPlanResult.result === "success") logger$
|
|
7183
|
-
else logger$
|
|
7382
|
+
if (testPlanResult.result === "success") logger$21.info({ storyKey }, "Test plan generated successfully");
|
|
7383
|
+
else logger$21.warn({ storyKey }, "Test planning returned failed result — proceeding to dev-story without test plan");
|
|
7184
7384
|
} catch (err) {
|
|
7185
|
-
logger$
|
|
7385
|
+
logger$21.warn({
|
|
7186
7386
|
storyKey,
|
|
7187
7387
|
err
|
|
7188
7388
|
}, "Test planning failed — proceeding to dev-story without test plan");
|
|
@@ -7206,7 +7406,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7206
7406
|
try {
|
|
7207
7407
|
storyContentForAnalysis = await readFile$1(storyFilePath ?? "", "utf-8");
|
|
7208
7408
|
} catch (err) {
|
|
7209
|
-
logger$
|
|
7409
|
+
logger$21.error({
|
|
7210
7410
|
storyKey,
|
|
7211
7411
|
storyFilePath,
|
|
7212
7412
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -7214,7 +7414,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7214
7414
|
}
|
|
7215
7415
|
const analysis = analyzeStoryComplexity(storyContentForAnalysis);
|
|
7216
7416
|
const batches = planTaskBatches(analysis);
|
|
7217
|
-
logger$
|
|
7417
|
+
logger$21.info({
|
|
7218
7418
|
storyKey,
|
|
7219
7419
|
estimatedScope: analysis.estimatedScope,
|
|
7220
7420
|
batchCount: batches.length,
|
|
@@ -7232,7 +7432,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7232
7432
|
if (_state !== "RUNNING") break;
|
|
7233
7433
|
const taskScope = batch.taskIds.map((id, i) => `T${id}: ${batch.taskTitles[i] ?? ""}`).join("\n");
|
|
7234
7434
|
const priorFiles = allFilesModified.size > 0 ? Array.from(allFilesModified) : void 0;
|
|
7235
|
-
logger$
|
|
7435
|
+
logger$21.info({
|
|
7236
7436
|
storyKey,
|
|
7237
7437
|
batchIndex: batch.batchIndex,
|
|
7238
7438
|
taskCount: batch.taskIds.length
|
|
@@ -7256,7 +7456,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7256
7456
|
});
|
|
7257
7457
|
} catch (batchErr) {
|
|
7258
7458
|
const errMsg = batchErr instanceof Error ? batchErr.message : String(batchErr);
|
|
7259
|
-
logger$
|
|
7459
|
+
logger$21.warn({
|
|
7260
7460
|
storyKey,
|
|
7261
7461
|
batchIndex: batch.batchIndex,
|
|
7262
7462
|
error: errMsg
|
|
@@ -7276,7 +7476,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7276
7476
|
filesModified: batchFilesModified,
|
|
7277
7477
|
result: batchResult.result === "success" ? "success" : "failed"
|
|
7278
7478
|
};
|
|
7279
|
-
logger$
|
|
7479
|
+
logger$21.info(batchMetrics, "Batch dev-story metrics");
|
|
7280
7480
|
for (const f of batchFilesModified) allFilesModified.add(f);
|
|
7281
7481
|
if (batchFilesModified.length > 0) batchFileGroups.push({
|
|
7282
7482
|
batchIndex: batch.batchIndex,
|
|
@@ -7298,13 +7498,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
7298
7498
|
})
|
|
7299
7499
|
});
|
|
7300
7500
|
} catch (tokenErr) {
|
|
7301
|
-
logger$
|
|
7501
|
+
logger$21.warn({
|
|
7302
7502
|
storyKey,
|
|
7303
7503
|
batchIndex: batch.batchIndex,
|
|
7304
7504
|
err: tokenErr
|
|
7305
7505
|
}, "Failed to record batch token usage");
|
|
7306
7506
|
}
|
|
7307
|
-
if (batchResult.result === "failed") logger$
|
|
7507
|
+
if (batchResult.result === "failed") logger$21.warn({
|
|
7308
7508
|
storyKey,
|
|
7309
7509
|
batchIndex: batch.batchIndex,
|
|
7310
7510
|
error: batchResult.error
|
|
@@ -7339,7 +7539,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7339
7539
|
});
|
|
7340
7540
|
persistState();
|
|
7341
7541
|
if (devResult.result === "success") devStoryWasSuccess = true;
|
|
7342
|
-
else logger$
|
|
7542
|
+
else logger$21.warn("Dev-story reported failure, proceeding to code review", {
|
|
7343
7543
|
storyKey,
|
|
7344
7544
|
error: devResult.error,
|
|
7345
7545
|
filesModified: devFilesModified.length
|
|
@@ -7363,10 +7563,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
7363
7563
|
persistState();
|
|
7364
7564
|
return;
|
|
7365
7565
|
}
|
|
7566
|
+
let gitDiffFiles;
|
|
7366
7567
|
if (devStoryWasSuccess) {
|
|
7367
|
-
|
|
7368
|
-
if (
|
|
7369
|
-
logger$
|
|
7568
|
+
gitDiffFiles = checkGitDiffFiles(projectRoot ?? process.cwd());
|
|
7569
|
+
if (gitDiffFiles.length === 0) {
|
|
7570
|
+
logger$21.warn({ storyKey }, "Zero-diff detected after COMPLETE dev-story — no file changes in git working tree");
|
|
7370
7571
|
eventBus.emit("orchestrator:zero-diff-escalation", {
|
|
7371
7572
|
storyKey,
|
|
7372
7573
|
reason: "zero-diff-on-complete"
|
|
@@ -7397,7 +7598,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7397
7598
|
});
|
|
7398
7599
|
if (buildVerifyResult.status === "passed") {
|
|
7399
7600
|
eventBus.emit("story:build-verification-passed", { storyKey });
|
|
7400
|
-
logger$
|
|
7601
|
+
logger$21.info({ storyKey }, "Build verification passed");
|
|
7401
7602
|
} else if (buildVerifyResult.status === "failed" || buildVerifyResult.status === "timeout") {
|
|
7402
7603
|
const truncatedOutput = (buildVerifyResult.output ?? "").slice(0, 2e3);
|
|
7403
7604
|
const reason = buildVerifyResult.reason ?? "build-verification-failed";
|
|
@@ -7406,7 +7607,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7406
7607
|
exitCode: buildVerifyResult.exitCode ?? 1,
|
|
7407
7608
|
output: truncatedOutput
|
|
7408
7609
|
});
|
|
7409
|
-
logger$
|
|
7610
|
+
logger$21.warn({
|
|
7410
7611
|
storyKey,
|
|
7411
7612
|
reason,
|
|
7412
7613
|
exitCode: buildVerifyResult.exitCode
|
|
@@ -7427,6 +7628,28 @@ function createImplementationOrchestrator(deps) {
|
|
|
7427
7628
|
return;
|
|
7428
7629
|
}
|
|
7429
7630
|
}
|
|
7631
|
+
try {
|
|
7632
|
+
const filesModified = gitDiffFiles ?? devFilesModified;
|
|
7633
|
+
if (filesModified.length > 0) {
|
|
7634
|
+
const icResult = detectInterfaceChanges({
|
|
7635
|
+
filesModified,
|
|
7636
|
+
projectRoot: projectRoot ?? process.cwd(),
|
|
7637
|
+
storyKey
|
|
7638
|
+
});
|
|
7639
|
+
if (icResult.potentiallyAffectedTests.length > 0) {
|
|
7640
|
+
logger$21.warn({
|
|
7641
|
+
storyKey,
|
|
7642
|
+
modifiedInterfaces: icResult.modifiedInterfaces,
|
|
7643
|
+
potentiallyAffectedTests: icResult.potentiallyAffectedTests
|
|
7644
|
+
}, "Interface change warning: modified exports may affect cross-module test mocks");
|
|
7645
|
+
eventBus.emit("story:interface-change-warning", {
|
|
7646
|
+
storyKey,
|
|
7647
|
+
modifiedInterfaces: icResult.modifiedInterfaces,
|
|
7648
|
+
potentiallyAffectedTests: icResult.potentiallyAffectedTests
|
|
7649
|
+
});
|
|
7650
|
+
}
|
|
7651
|
+
}
|
|
7652
|
+
} catch {}
|
|
7430
7653
|
let reviewCycles = 0;
|
|
7431
7654
|
let keepReviewing = true;
|
|
7432
7655
|
let timeoutRetried = false;
|
|
@@ -7459,7 +7682,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7459
7682
|
"NEEDS_MAJOR_REWORK": 2
|
|
7460
7683
|
};
|
|
7461
7684
|
for (const group of batchFileGroups) {
|
|
7462
|
-
logger$
|
|
7685
|
+
logger$21.info({
|
|
7463
7686
|
storyKey,
|
|
7464
7687
|
batchIndex: group.batchIndex,
|
|
7465
7688
|
fileCount: group.files.length
|
|
@@ -7496,7 +7719,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7496
7719
|
rawOutput: lastRawOutput,
|
|
7497
7720
|
tokenUsage: aggregateTokens
|
|
7498
7721
|
};
|
|
7499
|
-
logger$
|
|
7722
|
+
logger$21.info({
|
|
7500
7723
|
storyKey,
|
|
7501
7724
|
batchCount: batchFileGroups.length,
|
|
7502
7725
|
verdict: worstVerdict,
|
|
@@ -7522,7 +7745,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7522
7745
|
const isPhantomReview = reviewResult.dispatchFailed === true || reviewResult.verdict !== "SHIP_IT" && (reviewResult.issue_list === void 0 || reviewResult.issue_list.length === 0) && reviewResult.error !== void 0;
|
|
7523
7746
|
if (isPhantomReview && !timeoutRetried) {
|
|
7524
7747
|
timeoutRetried = true;
|
|
7525
|
-
logger$
|
|
7748
|
+
logger$21.warn({
|
|
7526
7749
|
storyKey,
|
|
7527
7750
|
reviewCycles,
|
|
7528
7751
|
error: reviewResult.error
|
|
@@ -7532,7 +7755,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7532
7755
|
verdict = reviewResult.verdict;
|
|
7533
7756
|
issueList = reviewResult.issue_list ?? [];
|
|
7534
7757
|
if (verdict === "NEEDS_MAJOR_REWORK" && reviewCycles > 0 && previousIssueList.length > 0 && issueList.length < previousIssueList.length) {
|
|
7535
|
-
logger$
|
|
7758
|
+
logger$21.info({
|
|
7536
7759
|
storyKey,
|
|
7537
7760
|
originalVerdict: verdict,
|
|
7538
7761
|
issuesBefore: previousIssueList.length,
|
|
@@ -7568,7 +7791,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7568
7791
|
if (_decomposition !== void 0) parts.push(`decomposed: ${_decomposition.batchCount} batches`);
|
|
7569
7792
|
parts.push(`${fileCount} files`);
|
|
7570
7793
|
parts.push(`${totalTokensK} tokens`);
|
|
7571
|
-
logger$
|
|
7794
|
+
logger$21.info({
|
|
7572
7795
|
storyKey,
|
|
7573
7796
|
verdict,
|
|
7574
7797
|
agentVerdict: reviewResult.agentVerdict
|
|
@@ -7619,7 +7842,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7619
7842
|
filesModified: devFilesModified,
|
|
7620
7843
|
workingDirectory: projectRoot
|
|
7621
7844
|
});
|
|
7622
|
-
logger$
|
|
7845
|
+
logger$21.debug({
|
|
7623
7846
|
storyKey,
|
|
7624
7847
|
expansion_priority: expansionResult.expansion_priority,
|
|
7625
7848
|
coverage_gaps: expansionResult.coverage_gaps.length
|
|
@@ -7632,7 +7855,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7632
7855
|
value: JSON.stringify(expansionResult)
|
|
7633
7856
|
});
|
|
7634
7857
|
} catch (expansionErr) {
|
|
7635
|
-
logger$
|
|
7858
|
+
logger$21.warn({
|
|
7636
7859
|
storyKey,
|
|
7637
7860
|
error: expansionErr instanceof Error ? expansionErr.message : String(expansionErr)
|
|
7638
7861
|
}, "Test expansion failed — story verdict unchanged");
|
|
@@ -7659,7 +7882,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7659
7882
|
persistState();
|
|
7660
7883
|
return;
|
|
7661
7884
|
}
|
|
7662
|
-
logger$
|
|
7885
|
+
logger$21.info({
|
|
7663
7886
|
storyKey,
|
|
7664
7887
|
reviewCycles: finalReviewCycles,
|
|
7665
7888
|
issueCount: issueList.length
|
|
@@ -7709,7 +7932,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7709
7932
|
fixPrompt = assembled.prompt;
|
|
7710
7933
|
} catch {
|
|
7711
7934
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, minor fixes needed`;
|
|
7712
|
-
logger$
|
|
7935
|
+
logger$21.warn("Failed to assemble auto-approve fix prompt, using fallback", { storyKey });
|
|
7713
7936
|
}
|
|
7714
7937
|
const handle = dispatcher.dispatch({
|
|
7715
7938
|
prompt: fixPrompt,
|
|
@@ -7726,9 +7949,9 @@ function createImplementationOrchestrator(deps) {
|
|
|
7726
7949
|
output: fixResult.tokenEstimate.output
|
|
7727
7950
|
} : void 0 }
|
|
7728
7951
|
});
|
|
7729
|
-
if (fixResult.status === "timeout") logger$
|
|
7952
|
+
if (fixResult.status === "timeout") logger$21.warn("Auto-approve fix timed out — approving anyway (issues were minor)", { storyKey });
|
|
7730
7953
|
} catch (err) {
|
|
7731
|
-
logger$
|
|
7954
|
+
logger$21.warn("Auto-approve fix dispatch failed — approving anyway (issues were minor)", {
|
|
7732
7955
|
storyKey,
|
|
7733
7956
|
err
|
|
7734
7957
|
});
|
|
@@ -7831,7 +8054,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7831
8054
|
fixPrompt = assembled.prompt;
|
|
7832
8055
|
} catch {
|
|
7833
8056
|
fixPrompt = `Fix story ${storyKey}: verdict=${verdict}, taskType=${taskType}`;
|
|
7834
|
-
logger$
|
|
8057
|
+
logger$21.warn("Failed to assemble fix prompt, using fallback", {
|
|
7835
8058
|
storyKey,
|
|
7836
8059
|
taskType
|
|
7837
8060
|
});
|
|
@@ -7861,7 +8084,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7861
8084
|
} : void 0 }
|
|
7862
8085
|
});
|
|
7863
8086
|
if (fixResult.status === "timeout") {
|
|
7864
|
-
logger$
|
|
8087
|
+
logger$21.warn("Fix dispatch timed out — escalating story", {
|
|
7865
8088
|
storyKey,
|
|
7866
8089
|
taskType
|
|
7867
8090
|
});
|
|
@@ -7883,7 +8106,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
7883
8106
|
}
|
|
7884
8107
|
if (fixResult.status === "failed") {
|
|
7885
8108
|
if (isMajorRework) {
|
|
7886
|
-
logger$
|
|
8109
|
+
logger$21.warn("Major rework dispatch failed — escalating story", {
|
|
7887
8110
|
storyKey,
|
|
7888
8111
|
exitCode: fixResult.exitCode
|
|
7889
8112
|
});
|
|
@@ -7903,14 +8126,14 @@ function createImplementationOrchestrator(deps) {
|
|
|
7903
8126
|
persistState();
|
|
7904
8127
|
return;
|
|
7905
8128
|
}
|
|
7906
|
-
logger$
|
|
8129
|
+
logger$21.warn("Fix dispatch failed", {
|
|
7907
8130
|
storyKey,
|
|
7908
8131
|
taskType,
|
|
7909
8132
|
exitCode: fixResult.exitCode
|
|
7910
8133
|
});
|
|
7911
8134
|
}
|
|
7912
8135
|
} catch (err) {
|
|
7913
|
-
logger$
|
|
8136
|
+
logger$21.warn("Fix dispatch failed, continuing to next review", {
|
|
7914
8137
|
storyKey,
|
|
7915
8138
|
taskType,
|
|
7916
8139
|
err
|
|
@@ -7973,11 +8196,11 @@ function createImplementationOrchestrator(deps) {
|
|
|
7973
8196
|
}
|
|
7974
8197
|
async function run(storyKeys) {
|
|
7975
8198
|
if (_state === "RUNNING" || _state === "PAUSED") {
|
|
7976
|
-
logger$
|
|
8199
|
+
logger$21.warn("run() called while orchestrator is already running or paused — ignoring", { state: _state });
|
|
7977
8200
|
return getStatus();
|
|
7978
8201
|
}
|
|
7979
8202
|
if (_state === "COMPLETE") {
|
|
7980
|
-
logger$
|
|
8203
|
+
logger$21.warn("run() called on a COMPLETE orchestrator — ignoring", { state: _state });
|
|
7981
8204
|
return getStatus();
|
|
7982
8205
|
}
|
|
7983
8206
|
_state = "RUNNING";
|
|
@@ -7995,13 +8218,13 @@ function createImplementationOrchestrator(deps) {
|
|
|
7995
8218
|
if (config.enableHeartbeat) startHeartbeat();
|
|
7996
8219
|
if (projectRoot !== void 0) {
|
|
7997
8220
|
const seedResult = seedMethodologyContext(db, projectRoot);
|
|
7998
|
-
if (seedResult.decisionsCreated > 0) logger$
|
|
8221
|
+
if (seedResult.decisionsCreated > 0) logger$21.info({
|
|
7999
8222
|
decisionsCreated: seedResult.decisionsCreated,
|
|
8000
8223
|
skippedCategories: seedResult.skippedCategories
|
|
8001
8224
|
}, "Methodology context seeded from planning artifacts");
|
|
8002
8225
|
}
|
|
8003
8226
|
const groups = detectConflictGroups(storyKeys, { moduleMap: pack.manifest.conflictGroups });
|
|
8004
|
-
logger$
|
|
8227
|
+
logger$21.info("Orchestrator starting", {
|
|
8005
8228
|
storyCount: storyKeys.length,
|
|
8006
8229
|
groupCount: groups.length,
|
|
8007
8230
|
maxConcurrency: config.maxConcurrency
|
|
@@ -8013,7 +8236,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
8013
8236
|
_state = "FAILED";
|
|
8014
8237
|
_completedAt = new Date().toISOString();
|
|
8015
8238
|
persistState();
|
|
8016
|
-
logger$
|
|
8239
|
+
logger$21.error("Orchestrator failed with unhandled error", { err });
|
|
8017
8240
|
return getStatus();
|
|
8018
8241
|
}
|
|
8019
8242
|
stopHeartbeat();
|
|
@@ -8040,7 +8263,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
8040
8263
|
_pauseGate = createPauseGate();
|
|
8041
8264
|
_state = "PAUSED";
|
|
8042
8265
|
eventBus.emit("orchestrator:paused", {});
|
|
8043
|
-
logger$
|
|
8266
|
+
logger$21.info("Orchestrator paused");
|
|
8044
8267
|
}
|
|
8045
8268
|
function resume() {
|
|
8046
8269
|
if (_state !== "PAUSED") return;
|
|
@@ -8051,7 +8274,7 @@ function createImplementationOrchestrator(deps) {
|
|
|
8051
8274
|
}
|
|
8052
8275
|
_state = "RUNNING";
|
|
8053
8276
|
eventBus.emit("orchestrator:resumed", {});
|
|
8054
|
-
logger$
|
|
8277
|
+
logger$21.info("Orchestrator resumed");
|
|
8055
8278
|
}
|
|
8056
8279
|
return {
|
|
8057
8280
|
run,
|
|
@@ -12530,6 +12753,27 @@ async function runRunAction(options) {
|
|
|
12530
12753
|
output: payload.output
|
|
12531
12754
|
});
|
|
12532
12755
|
});
|
|
12756
|
+
eventBus.on("story:interface-change-warning", (payload) => {
|
|
12757
|
+
ndjsonEmitter.emit({
|
|
12758
|
+
type: "story:interface-change-warning",
|
|
12759
|
+
ts: new Date().toISOString(),
|
|
12760
|
+
storyKey: payload.storyKey,
|
|
12761
|
+
modifiedInterfaces: payload.modifiedInterfaces,
|
|
12762
|
+
potentiallyAffectedTests: payload.potentiallyAffectedTests
|
|
12763
|
+
});
|
|
12764
|
+
});
|
|
12765
|
+
eventBus.on("story:metrics", (payload) => {
|
|
12766
|
+
ndjsonEmitter.emit({
|
|
12767
|
+
type: "story:metrics",
|
|
12768
|
+
ts: new Date().toISOString(),
|
|
12769
|
+
storyKey: payload.storyKey,
|
|
12770
|
+
wallClockMs: payload.wallClockMs,
|
|
12771
|
+
phaseBreakdown: payload.phaseBreakdown,
|
|
12772
|
+
tokens: payload.tokens,
|
|
12773
|
+
reviewCycles: payload.reviewCycles,
|
|
12774
|
+
dispatches: payload.dispatches
|
|
12775
|
+
});
|
|
12776
|
+
});
|
|
12533
12777
|
}
|
|
12534
12778
|
const orchestrator = createImplementationOrchestrator({
|
|
12535
12779
|
db,
|
|
@@ -12983,5 +13227,5 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
|
|
|
12983
13227
|
}
|
|
12984
13228
|
|
|
12985
13229
|
//#endregion
|
|
12986
|
-
export { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
|
|
12987
|
-
//# sourceMappingURL=run-
|
|
13230
|
+
export { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
|
|
13231
|
+
//# sourceMappingURL=run-DG5j6vJI.js.map
|