substrate-ai 0.2.3 → 0.2.5

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.
@@ -0,0 +1,3 @@
1
+ import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./decisions-DNYByk0U.js";
2
+
3
+ export { getLatestRun };
@@ -213,6 +213,28 @@ function createRequirement(db, input) {
213
213
  return row;
214
214
  }
215
215
  /**
216
+ * List requirements with optional filtering by type, priority, and status.
217
+ */
218
+ function listRequirements(db, filters) {
219
+ const conditions = [];
220
+ const values = [];
221
+ if (filters?.type !== void 0) {
222
+ conditions.push("type = ?");
223
+ values.push(filters.type);
224
+ }
225
+ if (filters?.priority !== void 0) {
226
+ conditions.push("priority = ?");
227
+ values.push(filters.priority);
228
+ }
229
+ if (filters?.status !== void 0) {
230
+ conditions.push("status = ?");
231
+ values.push(filters.status);
232
+ }
233
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
234
+ const stmt = db.prepare(`SELECT * FROM requirements ${where} ORDER BY created_at ASC`);
235
+ return stmt.all(...values);
236
+ }
237
+ /**
216
238
  * Register a new artifact record.
217
239
  */
218
240
  function registerArtifact(db, input) {
@@ -332,5 +354,5 @@ function getTokenUsageSummary(db, runId) {
332
354
  }
333
355
 
334
356
  //#endregion
335
- export { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getTokenUsageSummary, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision };
336
- //# sourceMappingURL=decisions-BBLMsN_c.js.map
357
+ export { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getTokenUsageSummary, listRequirements, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision };
358
+ //# sourceMappingURL=decisions-DNYByk0U.js.map
package/dist/index.d.ts CHANGED
@@ -231,6 +231,45 @@ interface StoryStallEvent {
231
231
  /** Milliseconds since the last progress event */
232
232
  elapsed_ms: number;
233
233
  }
234
+ /**
235
+ * Emitted after each `getHealth()` call in the supervisor poll loop.
236
+ * Allows agents to observe health state, story progress, and token costs
237
+ * on every cycle without needing a separate health query.
238
+ */
239
+ interface SupervisorPollEvent {
240
+ type: 'supervisor:poll';
241
+ /** ISO-8601 timestamp generated at emit time */
242
+ ts: string;
243
+ /** Current pipeline run ID, or null if no run is active */
244
+ run_id: string | null;
245
+ /** Health verdict from the most recent getHealth() call */
246
+ verdict: 'HEALTHY' | 'STALLED' | 'NO_PIPELINE_RUNNING';
247
+ /** Seconds since the last pipeline activity */
248
+ staleness_seconds: number;
249
+ /** Story counts from the health snapshot */
250
+ stories: {
251
+ active: number;
252
+ completed: number;
253
+ escalated: number;
254
+ };
255
+ /** Per-story phase and review cycle details */
256
+ story_details: Record<string, {
257
+ phase: string;
258
+ review_cycles: number;
259
+ }>;
260
+ /** Cumulative token/cost snapshot for the current run */
261
+ tokens: {
262
+ input: number;
263
+ output: number;
264
+ cost_usd: number;
265
+ };
266
+ /** Process health from the health snapshot */
267
+ process: {
268
+ orchestrator_pid: number | null;
269
+ child_count: number;
270
+ zombie_count: number;
271
+ };
272
+ }
234
273
  /**
235
274
  * Emitted when the supervisor kills a stalled pipeline process tree.
236
275
  */
@@ -389,7 +428,7 @@ interface SupervisorExperimentErrorEvent {
389
428
  * }
390
429
  * ```
391
430
  */
392
- type PipelineEvent = PipelineStartEvent | PipelineCompleteEvent | StoryPhaseEvent | StoryDoneEvent | StoryEscalationEvent | StoryWarnEvent | StoryLogEvent | PipelineHeartbeatEvent | StoryStallEvent | SupervisorKillEvent | SupervisorRestartEvent | SupervisorAbortEvent | SupervisorSummaryEvent | SupervisorAnalysisCompleteEvent | SupervisorAnalysisErrorEvent | SupervisorExperimentStartEvent | SupervisorExperimentSkipEvent | SupervisorExperimentRecommendationsEvent | SupervisorExperimentCompleteEvent | SupervisorExperimentErrorEvent; //#endregion
431
+ type PipelineEvent = PipelineStartEvent | PipelineCompleteEvent | StoryPhaseEvent | StoryDoneEvent | StoryEscalationEvent | StoryWarnEvent | StoryLogEvent | PipelineHeartbeatEvent | StoryStallEvent | SupervisorPollEvent | SupervisorKillEvent | SupervisorRestartEvent | SupervisorAbortEvent | SupervisorSummaryEvent | SupervisorAnalysisCompleteEvent | SupervisorAnalysisErrorEvent | SupervisorExperimentStartEvent | SupervisorExperimentSkipEvent | SupervisorExperimentRecommendationsEvent | SupervisorExperimentCompleteEvent | SupervisorExperimentErrorEvent; //#endregion
393
432
  //#region src/core/errors.d.ts
394
433
 
395
434
  /**
@@ -1,6 +1,6 @@
1
1
  import { createLogger } from "./logger-C6n1g8uP.js";
2
2
  import { AdapterRegistry, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning } from "./event-bus-J-bw-pkp.js";
3
- import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByPhase, getDecisionsByPhaseForRun, getPipelineRunById, getTokenUsageSummary, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./decisions-BBLMsN_c.js";
3
+ import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByPhase, getDecisionsByPhaseForRun, getPipelineRunById, getTokenUsageSummary, registerArtifact, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./decisions-DNYByk0U.js";
4
4
  import { aggregateTokenUsageForRun, aggregateTokenUsageForStory, getStoryMetricsForRun, writeRunMetrics, writeStoryMetrics } from "./metrics-BSg8VIHd.js";
5
5
  import { dirname, join } from "path";
6
6
  import { access, readFile, readdir, stat } from "fs/promises";
@@ -1024,6 +1024,21 @@ function validateStopAfterFromConflict(stopAfter, from) {
1024
1024
 
1025
1025
  //#endregion
1026
1026
  //#region src/cli/commands/pipeline-shared.ts
1027
+ /**
1028
+ * Parse a DB timestamp string to a Date, correctly treating it as UTC.
1029
+ *
1030
+ * SQLite stores timestamps as "YYYY-MM-DD HH:MM:SS" without a timezone suffix.
1031
+ * JavaScript's Date constructor parses strings without a timezone suffix as
1032
+ * *local time*, which causes staleness/duration to be calculated incorrectly
1033
+ * on machines not in UTC.
1034
+ *
1035
+ * Fix: append 'Z' if the string has no timezone marker so it is always
1036
+ * parsed as UTC.
1037
+ */
1038
+ function parseDbTimestampAsUtc(ts) {
1039
+ if (ts.endsWith("Z") || /[+-]\d{2}:\d{2}$/.test(ts)) return new Date(ts);
1040
+ return new Date(ts.replace(" ", "T") + "Z");
1041
+ }
1027
1042
  const __filename = fileURLToPath(import.meta.url);
1028
1043
  const __dirname = dirname(__filename);
1029
1044
  /**
@@ -1197,7 +1212,7 @@ function buildPipelineStatusOutput(run, tokenSummary, decisionsCount, storiesCou
1197
1212
  decisions_count: decisionsCount,
1198
1213
  stories_count: storiesCount,
1199
1214
  last_activity: run.updated_at,
1200
- staleness_seconds: Math.round((Date.now() - new Date(run.updated_at).getTime()) / 1e3)
1215
+ staleness_seconds: Math.round((Date.now() - parseDbTimestampAsUtc(run.updated_at).getTime()) / 1e3)
1201
1216
  };
1202
1217
  }
1203
1218
  /**
@@ -1817,6 +1832,53 @@ const PIPELINE_EVENT_METADATA = [
1817
1832
  }
1818
1833
  ]
1819
1834
  },
1835
+ {
1836
+ type: "supervisor:poll",
1837
+ description: "Heartbeat each poll (JSON only).",
1838
+ when: "Per cycle.",
1839
+ fields: [
1840
+ {
1841
+ name: "ts",
1842
+ type: "string",
1843
+ description: "Timestamp."
1844
+ },
1845
+ {
1846
+ name: "run_id",
1847
+ type: "string|null",
1848
+ description: "Run ID."
1849
+ },
1850
+ {
1851
+ name: "verdict",
1852
+ type: "HEALTHY|STALLED|NO_PIPELINE_RUNNING",
1853
+ description: "Verdict."
1854
+ },
1855
+ {
1856
+ name: "staleness_seconds",
1857
+ type: "number",
1858
+ description: "Seconds stale."
1859
+ },
1860
+ {
1861
+ name: "stories",
1862
+ type: "object",
1863
+ description: "active/completed/escalated."
1864
+ },
1865
+ {
1866
+ name: "story_details",
1867
+ type: "object",
1868
+ description: "phase+cycles per story."
1869
+ },
1870
+ {
1871
+ name: "tokens",
1872
+ type: "object",
1873
+ description: "input/output/cost_usd."
1874
+ },
1875
+ {
1876
+ name: "process",
1877
+ type: "object",
1878
+ description: "pid/child/zombie counts."
1879
+ }
1880
+ ]
1881
+ },
1820
1882
  {
1821
1883
  type: "supervisor:kill",
1822
1884
  description: "Supervisor killed stalled pipeline process tree.",
@@ -2238,42 +2300,34 @@ function generateInteractionPatternsSection() {
2238
2300
  Use this decision flowchart when handling events from \`substrate run --events\`:
2239
2301
 
2240
2302
  ### On \`story:done\` with \`result: success\`
2241
- - Report successful completion to the user.
2242
- - Note the story key and number of review_cycles for telemetry.
2303
+ - Report success to the user.
2243
2304
 
2244
2305
  ### On \`story:done\` with \`result: failed\`
2245
- - Report failure to the user with the story key.
2246
- - Suggest checking logs or running \`substrate status\` for details.
2306
+ - Report failure with the story key.
2247
2307
 
2248
2308
  ### On \`story:escalation\`
2249
- - Read the \`issues\` array. Each issue has \`severity\`, \`file\` (path:line), and \`desc\`.
2250
- - Present the issues to the user grouped by severity.
2251
- - Offer to fix the issues or explain them.
2252
- - Ask the user whether to retry or abandon the story.
2309
+ - Read \`issues\`: each has \`severity\`, \`file\`, \`desc\`.
2310
+ - Present grouped by severity; ask user to retry or abandon.
2253
2311
 
2254
2312
  ### On \`story:phase\` with \`verdict: NEEDS_MINOR_FIXES\`
2255
- - The story passed code review but has minor suggestions.
2256
- - Offer to apply the fixes or skip.
2257
- - This is non-blocking — pipeline continues unless you intervene.
2313
+ - Non-blocking minor suggestions. Offer to apply or skip.
2258
2314
 
2259
2315
  ### On \`story:warn\`
2260
- - Inform the user of the warning message but do NOT treat it as an error.
2261
- - Common warnings: token ceiling truncation, partial batch failures.
2262
- - Pipeline continues normally after a warn event.
2316
+ - Non-blocking warning; pipeline continues normally.
2263
2317
 
2264
2318
  ### On \`story:log\`
2265
- - These are informational only.
2266
- - Display if verbose mode is active; otherwise buffer or discard.
2319
+ - Informational only. Display in verbose mode.
2267
2320
 
2268
2321
  ### On \`pipeline:complete\`
2269
- - Summarize results: report \`succeeded.length\` successes.
2270
- - List any \`failed\` or \`escalated\` stories with reasons if available.
2271
- - This is always the last event emitted.
2322
+ - Summarize \`succeeded\`, \`failed\`, \`escalated\` counts.
2272
2323
 
2273
2324
  ## Supervisor Interaction Patterns
2274
2325
 
2275
2326
  Patterns for \`substrate supervisor --output-format json\` events:
2276
2327
 
2328
+ ### On \`supervisor:poll\`
2329
+ - Track \`verdict\` and \`tokens.cost_usd\` each cycle. JSON only.
2330
+
2277
2331
  ### On \`supervisor:summary\`
2278
2332
  - Summarize \`succeeded\`, \`failed\`, \`escalated\` counts and \`restarts\`.
2279
2333
  - Offer analysis: \`substrate metrics --analysis <run_id> --output-format json\`.
@@ -10318,7 +10372,7 @@ async function runRunAction(options) {
10318
10372
  else failedKeys.push(key);
10319
10373
  try {
10320
10374
  const runEndMs = Date.now();
10321
- const runStartMs = new Date(pipelineRun.created_at).getTime();
10375
+ const runStartMs = parseDbTimestampAsUtc(pipelineRun.created_at).getTime();
10322
10376
  const tokenAgg = aggregateTokenUsageForRun(db, pipelineRun.id);
10323
10377
  const storyMetrics = getStoryMetricsForRun(db, pipelineRun.id);
10324
10378
  const totalReviewCycles = storyMetrics.reduce((sum, m) => sum + (m.review_cycles ?? 0), 0);
@@ -10721,5 +10775,5 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
10721
10775
  }
10722
10776
 
10723
10777
  //#endregion
10724
- export { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getSubstrateDefaultSettings, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
10725
- //# sourceMappingURL=run-DlOWhkIF.js.map
10778
+ export { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
10779
+ //# sourceMappingURL=run-CDYE1PT3.js.map
@@ -0,0 +1,7 @@
1
+ import "./logger-C6n1g8uP.js";
2
+ import "./event-bus-J-bw-pkp.js";
3
+ import { registerRunCommand, runRunAction } from "./run-CDYE1PT3.js";
4
+ import "./decisions-DNYByk0U.js";
5
+ import "./metrics-BSg8VIHd.js";
6
+
7
+ export { runRunAction };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,3 +0,0 @@
1
- import { addTokenUsage, createDecision, createPipelineRun, createRequirement, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getTokenUsageSummary, registerArtifact, updateDecision, updatePipelineRun, updatePipelineRunConfig, upsertDecision } from "./decisions-BBLMsN_c.js";
2
-
3
- export { getLatestRun };
@@ -1,7 +0,0 @@
1
- import "./logger-C6n1g8uP.js";
2
- import "./event-bus-J-bw-pkp.js";
3
- import { registerRunCommand, runRunAction } from "./run-DlOWhkIF.js";
4
- import "./decisions-BBLMsN_c.js";
5
- import "./metrics-BSg8VIHd.js";
6
-
7
- export { runRunAction };