substrate-ai 0.2.8 → 0.2.10

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
@@ -2,7 +2,7 @@
2
2
  import { createLogger, deepMask } from "../logger-C6n1g8uP.js";
3
3
  import { AdapterRegistry, createEventBus } from "../event-bus-J-bw-pkp.js";
4
4
  import { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema, SUPPORTED_CONFIG_FORMAT_VERSIONS, SubstrateConfigSchema, defaultConfigMigrator } from "../version-manager-impl-BpVx2DkY.js";
5
- import { 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, runSolutioningPhase, validateStopAfterFromConflict } from "../run-DbRH_r_-.js";
5
+ import { 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, runSolutioningPhase, validateStopAfterFromConflict } from "../run-XqzHIF6m.js";
6
6
  import { ConfigError, ConfigIncompatibleFormatError } from "../errors-BPqtzQ4U.js";
7
7
  import { addTokenUsage, createDecision, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getTokenUsageSummary, listRequirements, updatePipelineRun } from "../decisions-DNYByk0U.js";
8
8
  import { aggregateTokenUsageForRun, compareRunMetrics, getBaselineRunMetrics, getRunMetrics, getStoryMetricsForRun, incrementRunRestarts, listRunMetrics, tagRunAsBaseline } from "../metrics-BSg8VIHd.js";
@@ -2833,7 +2833,7 @@ async function runSupervisorAction(options, deps = {}) {
2833
2833
  const expDb = expDbWrapper.db;
2834
2834
  const { runRunAction: runPipeline } = await import(
2835
2835
  /* @vite-ignore */
2836
- "../run-aGFwcIFG.js"
2836
+ "../run-CDdKFwfI.js"
2837
2837
  );
2838
2838
  const runStoryFn = async (opts) => {
2839
2839
  const exitCode = await runPipeline({
@@ -1,6 +1,6 @@
1
1
  import "./logger-C6n1g8uP.js";
2
2
  import "./event-bus-J-bw-pkp.js";
3
- import { registerRunCommand, runRunAction } from "./run-DbRH_r_-.js";
3
+ import { registerRunCommand, runRunAction } from "./run-XqzHIF6m.js";
4
4
  import "./decisions-DNYByk0U.js";
5
5
  import "./metrics-BSg8VIHd.js";
6
6
 
@@ -8,12 +8,12 @@ import { existsSync, mkdirSync, readFileSync } from "fs";
8
8
  import yaml from "js-yaml";
9
9
  import { createRequire } from "node:module";
10
10
  import { z } from "zod";
11
- import { spawn } from "node:child_process";
11
+ import { execSync, spawn } from "node:child_process";
12
12
  import { dirname as dirname$1, join as join$1, resolve as resolve$1 } from "node:path";
13
13
  import BetterSqlite3 from "better-sqlite3";
14
14
  import { fileURLToPath } from "node:url";
15
15
  import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "node:fs";
16
- import { freemem } from "node:os";
16
+ import { freemem, platform } from "node:os";
17
17
  import { randomUUID } from "node:crypto";
18
18
  import { readFile as readFile$1, stat as stat$1 } from "node:fs/promises";
19
19
 
@@ -874,6 +874,7 @@ function createPackLoader() {
874
874
  */
875
875
  /** Canonical pipeline phase names. This is the single source of truth for all phase lists. */
876
876
  const VALID_PHASES = [
877
+ "research",
877
878
  "analysis",
878
879
  "planning",
879
880
  "solutioning",
@@ -2843,6 +2844,50 @@ const SHUTDOWN_MAX_WAIT_MS = 3e4;
2843
2844
  const CHARS_PER_TOKEN = 4;
2844
2845
  const MIN_FREE_MEMORY_BYTES = 512 * 1024 * 1024;
2845
2846
  const MEMORY_PRESSURE_POLL_MS = 1e4;
2847
+ /**
2848
+ * Get available system memory in bytes, accounting for platform differences.
2849
+ *
2850
+ * On macOS, the previous approach (free + inactive pages) dramatically
2851
+ * overestimates availability because inactive pages may be compressed,
2852
+ * swapped, or require I/O to reclaim. With heavy agent concurrency, this
2853
+ * leads to spawning too many processes and triggering real memory pressure.
2854
+ *
2855
+ * New approach:
2856
+ * 1. Check kern.memorystatus_vm_pressure_level — the kernel's own assessment.
2857
+ * Level >= 2 (warn/critical) means the system is already pressured.
2858
+ * 2. Use a conservative page calculation: free + purgeable + speculative.
2859
+ * These categories are truly reclaimable without I/O or decompression.
2860
+ * Inactive pages are excluded because they may require disk I/O,
2861
+ * decompression, or may already be backing the compressor.
2862
+ */
2863
+ function getAvailableMemory() {
2864
+ if (platform() === "darwin") {
2865
+ try {
2866
+ const pressureLevel = parseInt(execSync("sysctl -n kern.memorystatus_vm_pressure_level", {
2867
+ timeout: 1e3,
2868
+ encoding: "utf-8"
2869
+ }).trim(), 10);
2870
+ if (pressureLevel >= 2) {
2871
+ logger$12.warn({ pressureLevel }, "macOS kernel reports memory pressure");
2872
+ return 0;
2873
+ }
2874
+ } catch {}
2875
+ try {
2876
+ const vmstat = execSync("vm_stat", {
2877
+ timeout: 2e3,
2878
+ encoding: "utf-8"
2879
+ });
2880
+ const pageSize = parseInt(vmstat.match(/page size of (\d+)/)?.[1] ?? "4096", 10);
2881
+ const free = parseInt(vmstat.match(/Pages free:\s+(\d+)/)?.[1] ?? "0", 10);
2882
+ const purgeable = parseInt(vmstat.match(/Pages purgeable:\s+(\d+)/)?.[1] ?? "0", 10);
2883
+ const speculative = parseInt(vmstat.match(/Pages speculative:\s+(\d+)/)?.[1] ?? "0", 10);
2884
+ return (free + purgeable + speculative) * pageSize;
2885
+ } catch {
2886
+ return freemem();
2887
+ }
2888
+ }
2889
+ return freemem();
2890
+ }
2846
2891
  var MutableDispatchHandle = class {
2847
2892
  id;
2848
2893
  status;
@@ -3242,7 +3287,7 @@ var DispatcherImpl = class {
3242
3287
  if (idx !== -1) this._queue.splice(idx, 1);
3243
3288
  }
3244
3289
  _isMemoryPressured() {
3245
- const free = freemem();
3290
+ const free = getAvailableMemory();
3246
3291
  if (free < MIN_FREE_MEMORY_BYTES) {
3247
3292
  logger$12.warn({
3248
3293
  freeMB: Math.round(free / 1024 / 1024),
@@ -10237,7 +10282,7 @@ async function runRunAction(options) {
10237
10282
  }
10238
10283
  }
10239
10284
  let concept;
10240
- if (startPhase === "analysis" || startPhase === void 0) {
10285
+ if (startPhase === "research" || startPhase === "analysis" || startPhase === void 0) {
10241
10286
  if (conceptFile !== void 0 && conceptFile !== "") try {
10242
10287
  concept = await readFile(conceptFile, "utf-8");
10243
10288
  } catch (err) {
@@ -10248,8 +10293,8 @@ async function runRunAction(options) {
10248
10293
  return 1;
10249
10294
  }
10250
10295
  else if (conceptArg !== void 0 && conceptArg !== "") concept = conceptArg;
10251
- else if (startPhase === "analysis") {
10252
- const errorMsg = "--concept or --concept-file required when starting from analysis phase";
10296
+ else if (startPhase === "research" || startPhase === "analysis") {
10297
+ const errorMsg = "--concept or --concept-file required when starting from research or analysis phase";
10253
10298
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
10254
10299
  else process.stderr.write(`Error: ${errorMsg}\n`);
10255
10300
  return 1;
@@ -11058,4 +11103,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
11058
11103
 
11059
11104
  //#endregion
11060
11105
  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 };
11061
- //# sourceMappingURL=run-DbRH_r_-.js.map
11106
+ //# sourceMappingURL=run-XqzHIF6m.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",