substrate-ai 0.20.85 → 0.20.86

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/cli/index.js CHANGED
@@ -3,7 +3,7 @@ import { FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipel
3
3
  import { createLogger } from "../logger-KeHncl-f.js";
4
4
  import { createEventBus } from "../helpers-CElYrONe.js";
5
5
  import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, swallowDebug, tagRunAsBaseline, updatePipelineRun } from "../dist-DCBSXUiX.js";
6
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-B_B7Jr_K.js";
6
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DtkAIssJ.js";
7
7
  import "../adapter-registry-DIcrxjH8.js";
8
8
  import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-Boipz5aP.js";
9
9
  import "../errors-D7xD-utp.js";
@@ -8436,7 +8436,7 @@ async function runSupervisorAction(options, deps = {}) {
8436
8436
  await initSchema(expAdapter);
8437
8437
  const { runRunAction: runPipeline } = await import(
8438
8438
  /* @vite-ignore */
8439
- "../run-PzGF_iNE.js"
8439
+ "../run-DmnPDKr3.js"
8440
8440
  );
8441
8441
  const runStoryFn = async (opts) => {
8442
8442
  const exitCode = await runPipeline({
@@ -2,7 +2,7 @@ import "./health-CuKzY0Fn.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
4
  import "./dist-DCBSXUiX.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-B_B7Jr_K.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DtkAIssJ.js";
6
6
  import "./manifest-read-Boipz5aP.js";
7
7
  import "./routing-DFxoKHDt.js";
8
8
  import "./work-graph-repository-DZyJv5pV.js";
@@ -17,7 +17,7 @@ import { exec, execFile, execFileSync, execSync, spawn } from "node:child_proces
17
17
  import * as path$5 from "node:path";
18
18
  import * as path$4 from "node:path";
19
19
  import * as path$2 from "node:path";
20
- import path, { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, posix, resolve as resolve$1, win32 } from "node:path";
20
+ import path, { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, posix, relative, resolve as resolve$1, win32 } from "node:path";
21
21
  import { tmpdir } from "node:os";
22
22
  import { createHash, randomUUID } from "node:crypto";
23
23
  import { z } from "zod";
@@ -7275,6 +7275,137 @@ async function isValidStoryFile(filePath) {
7275
7275
  //#region src/modules/compiled-workflows/git-helpers.ts
7276
7276
  const logger$20 = createLogger("compiled-workflows:git-helpers");
7277
7277
  /**
7278
+ * Commit the agent's working-tree output for a dev-story dispatch.
7279
+ *
7280
+ * Path E Bug #5 (post-v0.20.85): substrate's per-story worktree flow assumed
7281
+ * the dispatched agent would run `git commit` itself. Empirical audit across
7282
+ * substrate + 4 consumer projects (strata, agent-mesh, boardgame-sandbox,
7283
+ * lucky-numbers) found 1 `feat(story-X-Y)` commit total in 2 months — agents
7284
+ * don't reliably commit. Path E's merge-to-main has been a silent no-op
7285
+ * since v0.20.79 because the branch never advanced past the orchestrator's
7286
+ * start commit. Result: pipelines reported succeeded, work was lost on
7287
+ * worktree cleanup.
7288
+ *
7289
+ * Fix: substrate commits programmatically before merge-to-main fires. The
7290
+ * commit captures every uncommitted file under the worktree that isn't
7291
+ * `.gitignored` (git add respects ignore rules) and isn't outside the
7292
+ * worktree boundary (absolute paths to /tmp/... are filtered out so they
7293
+ * don't trip 'fatal: outside repository'). Pre-commit hooks are NOT
7294
+ * bypassed — they exist in the operator's repo for a reason and should
7295
+ * gate substrate-generated commits too. A hook failure surfaces as a
7296
+ * dev-story-no-commit escalation with the hook output as evidence.
7297
+ *
7298
+ * @param storyKey Story key (e.g. "10-2") for the canonical commit-msg pattern
7299
+ * @param storyTitle Title from create-story result (or fallback string)
7300
+ * @param filesModified Files the agent declared (or recovered via git-status fallback)
7301
+ * @param workingDir The worktree path (or projectRoot when --no-worktree)
7302
+ * @returns Structured result for the orchestrator to inspect
7303
+ */
7304
+ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, workingDir) {
7305
+ const insideWorktree = [];
7306
+ for (const p of filesModified) {
7307
+ const abs = isAbsolute(p) ? p : resolve$1(workingDir, p);
7308
+ const rel = relative(workingDir, abs);
7309
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
7310
+ logger$20.debug({
7311
+ path: p,
7312
+ abs,
7313
+ workingDir
7314
+ }, "commitDevStoryOutput: filtered out path outside worktree");
7315
+ continue;
7316
+ }
7317
+ insideWorktree.push(rel);
7318
+ }
7319
+ if (insideWorktree.length === 0) return {
7320
+ status: "no-changes",
7321
+ reason: "no-files-inside-worktree"
7322
+ };
7323
+ try {
7324
+ execSync(`git add ${insideWorktree.map((p) => JSON.stringify(p)).join(" ")}`, {
7325
+ cwd: workingDir,
7326
+ stdio: [
7327
+ "ignore",
7328
+ "pipe",
7329
+ "pipe"
7330
+ ],
7331
+ timeout: 3e4
7332
+ });
7333
+ } catch (err) {
7334
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr ?? err.message) : err instanceof Error ? err.message : String(err);
7335
+ return {
7336
+ status: "failed",
7337
+ stderr: `git add failed: ${stderr}`
7338
+ };
7339
+ }
7340
+ const cachedCheck = spawn("git", [
7341
+ "diff",
7342
+ "--cached",
7343
+ "--quiet"
7344
+ ], {
7345
+ cwd: workingDir,
7346
+ stdio: [
7347
+ "ignore",
7348
+ "pipe",
7349
+ "pipe"
7350
+ ]
7351
+ });
7352
+ const cachedStatus = await new Promise((res) => {
7353
+ cachedCheck.on("close", (code) => res(code ?? 0));
7354
+ cachedCheck.on("error", () => res(0));
7355
+ });
7356
+ if (cachedStatus === 0) return {
7357
+ status: "no-changes",
7358
+ reason: "staging-produced-no-diff"
7359
+ };
7360
+ const title = storyTitle ?? "implementation";
7361
+ const message = `feat(story-${storyKey}): ${title}`;
7362
+ try {
7363
+ execSync(`git commit -m ${JSON.stringify(message)}`, {
7364
+ cwd: workingDir,
7365
+ stdio: [
7366
+ "ignore",
7367
+ "pipe",
7368
+ "pipe"
7369
+ ],
7370
+ timeout: 12e4
7371
+ });
7372
+ } catch (err) {
7373
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr ?? err.message) : err instanceof Error ? err.message : String(err);
7374
+ return {
7375
+ status: "failed",
7376
+ stderr: `git commit failed: ${stderr}`
7377
+ };
7378
+ }
7379
+ let sha = "";
7380
+ try {
7381
+ sha = execSync("git rev-parse HEAD", {
7382
+ cwd: workingDir,
7383
+ encoding: "utf-8",
7384
+ stdio: [
7385
+ "ignore",
7386
+ "pipe",
7387
+ "pipe"
7388
+ ],
7389
+ timeout: 5e3
7390
+ }).trim();
7391
+ } catch (err) {
7392
+ logger$20.warn({
7393
+ storyKey,
7394
+ err
7395
+ }, "commitDevStoryOutput: commit succeeded but rev-parse HEAD failed");
7396
+ }
7397
+ logger$20.info({
7398
+ storyKey,
7399
+ sha,
7400
+ fileCount: insideWorktree.length
7401
+ }, "commitDevStoryOutput: committed dev-story output");
7402
+ return {
7403
+ status: "committed",
7404
+ sha,
7405
+ filesStaged: insideWorktree
7406
+ };
7407
+ }
7408
+ /**
7278
7409
  * Check whether the repo at `cwd` has at least one commit (HEAD resolves).
7279
7410
  * Returns false for fresh repos with no commits, avoiding `fatal: bad revision 'HEAD'`.
7280
7411
  * Synchronous (execSync) to keep it simple — this is a fast local check.
@@ -13995,6 +14126,7 @@ function createImplementationOrchestrator(deps) {
13995
14126
  const wt = await _worktreeManager.createWorktree(storyKey);
13996
14127
  effectiveProjectRoot = wt.worktreePath;
13997
14128
  }
14129
+ let _capturedStoryTitle;
13998
14130
  await waitIfPaused();
13999
14131
  if (_state !== "RUNNING") return;
14000
14132
  stateStore?.branchForStory(storyKey).catch((err) => logger$27.warn({
@@ -14291,6 +14423,7 @@ function createImplementationOrchestrator(deps) {
14291
14423
  }
14292
14424
  }
14293
14425
  storyFilePath = createResult.story_file;
14426
+ _capturedStoryTitle = createResult.story_title;
14294
14427
  if (createResult.story_title) try {
14295
14428
  const epicId = storyKey.split("-")[0] ?? storyKey;
14296
14429
  const implDecisions = await getDecisionsByPhase(db, "implementation");
@@ -16045,6 +16178,101 @@ function createImplementationOrchestrator(deps) {
16045
16178
  }
16046
16179
  if (!noWorktree && _worktreeManager !== void 0 && _orchestratorStartBranch !== void 0 && projectRoot !== void 0) {
16047
16180
  const branchName = `${BRANCH_PREFIX}${storyKey}`;
16181
+ if (effectiveProjectRoot !== void 0) {
16182
+ const dirty = await getGitChangedFiles(effectiveProjectRoot);
16183
+ const commitResult = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirty, effectiveProjectRoot);
16184
+ if (commitResult.status === "no-changes") {
16185
+ logger$27.warn({
16186
+ storyKey,
16187
+ reason: commitResult.reason
16188
+ }, "dev-story produced no committable changes — escalating instead of running merge-to-main on an unchanged branch");
16189
+ updateStory(storyKey, {
16190
+ phase: "ESCALATED",
16191
+ error: `dev-story-no-commit: ${commitResult.reason}`,
16192
+ completedAt: new Date().toISOString()
16193
+ });
16194
+ await emitEscalation({
16195
+ storyKey,
16196
+ lastVerdict: "dev-story-no-commit",
16197
+ reviewCycles: completedReviewCycles,
16198
+ issues: [`dev-story phase completed with verdict ${reviewVerdict} but produced no committable changes (reason: ${commitResult.reason})`]
16199
+ });
16200
+ await persistState();
16201
+ return;
16202
+ }
16203
+ if (commitResult.status === "failed") {
16204
+ logger$27.error({
16205
+ storyKey,
16206
+ stderr: commitResult.stderr
16207
+ }, "substrate auto-commit failed — escalating story");
16208
+ updateStory(storyKey, {
16209
+ phase: "ESCALATED",
16210
+ error: "dev-story-commit-failed",
16211
+ completedAt: new Date().toISOString()
16212
+ });
16213
+ await emitEscalation({
16214
+ storyKey,
16215
+ lastVerdict: "dev-story-commit-failed",
16216
+ reviewCycles: completedReviewCycles,
16217
+ issues: [`substrate auto-commit failed: ${commitResult.stderr}`]
16218
+ });
16219
+ await persistState();
16220
+ return;
16221
+ }
16222
+ logger$27.info({
16223
+ storyKey,
16224
+ sha: commitResult.sha,
16225
+ fileCount: commitResult.filesStaged.length
16226
+ }, "substrate auto-committed dev-story output before merge-to-main");
16227
+ }
16228
+ try {
16229
+ const branchSha = execSync(`git rev-parse ${branchName}`, {
16230
+ cwd: effectiveProjectRoot ?? projectRoot,
16231
+ encoding: "utf-8",
16232
+ stdio: [
16233
+ "ignore",
16234
+ "pipe",
16235
+ "pipe"
16236
+ ],
16237
+ timeout: 5e3
16238
+ }).trim();
16239
+ const startSha = execSync(`git rev-parse ${_orchestratorStartBranch}`, {
16240
+ cwd: projectRoot,
16241
+ encoding: "utf-8",
16242
+ stdio: [
16243
+ "ignore",
16244
+ "pipe",
16245
+ "pipe"
16246
+ ],
16247
+ timeout: 5e3
16248
+ }).trim();
16249
+ if (branchSha === startSha) {
16250
+ logger$27.warn({
16251
+ storyKey,
16252
+ branchSha,
16253
+ startSha,
16254
+ branchName
16255
+ }, "merge-to-main gate: branch did not advance from start commit — escalating instead of running a no-op merge");
16256
+ updateStory(storyKey, {
16257
+ phase: "ESCALATED",
16258
+ error: "dev-story-no-commit",
16259
+ completedAt: new Date().toISOString()
16260
+ });
16261
+ await emitEscalation({
16262
+ storyKey,
16263
+ lastVerdict: "dev-story-no-commit",
16264
+ reviewCycles: completedReviewCycles,
16265
+ issues: [`branch ${branchName} did not advance past start commit ${startSha} — merge-to-main would be a no-op`]
16266
+ });
16267
+ await persistState();
16268
+ return;
16269
+ }
16270
+ } catch (gateErr) {
16271
+ logger$27.warn({
16272
+ storyKey,
16273
+ err: gateErr instanceof Error ? gateErr.message : String(gateErr)
16274
+ }, "merge-to-main pre-flight verification failed — proceeding with merge phase");
16275
+ }
16048
16276
  logger$27.info({
16049
16277
  storyKey,
16050
16278
  branchName,
@@ -47154,4 +47382,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
47154
47382
 
47155
47383
  //#endregion
47156
47384
  export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
47157
- //# sourceMappingURL=run-B_B7Jr_K.js.map
47385
+ //# sourceMappingURL=run-DtkAIssJ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.85",
3
+ "version": "0.20.86",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",