@wrongstack/core 0.8.0 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3965,11 +3965,11 @@ function validateAgainstSchema(value, schema) {
3965
3965
  walk2(value, schema, "", errors);
3966
3966
  return { ok: errors.length === 0, errors };
3967
3967
  }
3968
- function walk2(value, schema, path26, errors) {
3968
+ function walk2(value, schema, path27, errors) {
3969
3969
  if (schema.enum !== void 0) {
3970
3970
  if (!schema.enum.some((e) => deepEqual(e, value))) {
3971
3971
  errors.push({
3972
- path: path26 || "<root>",
3972
+ path: path27 || "<root>",
3973
3973
  message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
3974
3974
  });
3975
3975
  return;
@@ -3978,7 +3978,7 @@ function walk2(value, schema, path26, errors) {
3978
3978
  if (typeof schema.type === "string") {
3979
3979
  if (!checkType(value, schema.type)) {
3980
3980
  errors.push({
3981
- path: path26 || "<root>",
3981
+ path: path27 || "<root>",
3982
3982
  message: `expected ${schema.type}, got ${describeType(value)}`
3983
3983
  });
3984
3984
  return;
@@ -3988,19 +3988,19 @@ function walk2(value, schema, path26, errors) {
3988
3988
  const obj = value;
3989
3989
  for (const req of schema.required ?? []) {
3990
3990
  if (!(req in obj)) {
3991
- errors.push({ path: joinPath(path26, req), message: "required property missing" });
3991
+ errors.push({ path: joinPath(path27, req), message: "required property missing" });
3992
3992
  }
3993
3993
  }
3994
3994
  if (schema.properties) {
3995
3995
  for (const [key, subSchema] of Object.entries(schema.properties)) {
3996
3996
  if (key in obj) {
3997
- walk2(obj[key], subSchema, joinPath(path26, key), errors);
3997
+ walk2(obj[key], subSchema, joinPath(path27, key), errors);
3998
3998
  }
3999
3999
  }
4000
4000
  }
4001
4001
  }
4002
4002
  if (schema.type === "array" && Array.isArray(value) && schema.items) {
4003
- value.forEach((item, i) => walk2(item, schema.items, `${path26}[${i}]`, errors));
4003
+ value.forEach((item, i) => walk2(item, schema.items, `${path27}[${i}]`, errors));
4004
4004
  }
4005
4005
  }
4006
4006
  function checkType(value, type) {
@@ -6182,10 +6182,36 @@ var DefaultPermissionPolicy = class {
6182
6182
  return void 0;
6183
6183
  }
6184
6184
  };
6185
- var AutoApprovePermissionPolicy = class {
6185
+ var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
6186
+ /**
6187
+ * Tools that are too dangerous to auto-approve even in a delegated
6188
+ * subagent context. Subagents run non-interactively under a director
6189
+ * and cannot answer prompts, but inherited authorization does not
6190
+ * imply blanket permission for destructive or privilege-escalating
6191
+ * operations. These tools remain at their declared `permission`
6192
+ * level so the leader must explicitly allow them per-spawn.
6193
+ */
6194
+ static DENY = /* @__PURE__ */ new Set([
6195
+ "bash",
6196
+ // arbitrary shell — use exec for constrained shell
6197
+ "write",
6198
+ // arbitrary file write
6199
+ "scaffold",
6200
+ // arbitrary file generation outside project root
6201
+ "patch",
6202
+ // arbitrary diff application
6203
+ "install",
6204
+ // installs from arbitrary package sources
6205
+ "exec"
6206
+ // restricted shell but with arbitrary command args
6207
+ ]);
6186
6208
  async evaluate(tool) {
6187
- if (tool.permission === "deny") {
6188
- return { permission: "deny", source: "default", reason: "tool default deny" };
6209
+ if (tool.permission === "deny" || _AutoApprovePermissionPolicy.DENY.has(tool.name)) {
6210
+ return {
6211
+ permission: "deny",
6212
+ source: "subagent_guard",
6213
+ reason: _AutoApprovePermissionPolicy.DENY.has(tool.name) ? `tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow it explicitly` : "tool default deny"
6214
+ };
6189
6215
  }
6190
6216
  return { permission: "auto", source: "yolo" };
6191
6217
  }
@@ -7262,6 +7288,7 @@ Summarize the following message range:`;
7262
7288
  };
7263
7289
 
7264
7290
  // src/execution/auto-compaction-middleware.ts
7291
+ var LEVEL_RANK2 = { warn: 0, soft: 1, hard: 2 };
7265
7292
  var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
7266
7293
  name = "AutoCompaction";
7267
7294
  compactor;
@@ -7276,12 +7303,28 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
7276
7303
  failureMode;
7277
7304
  policyProvider;
7278
7305
  /**
7279
- * Overhead factor applied to the rough message-token estimate to produce a
7280
- * figure comparable to the real API request size (system prompt + tool defs).
7281
- * Without this factor, raw message tokens undercount real load by 15-50% in
7282
- * short conversations, causing premature compaction triggers.
7306
+ * Calibration factor applied to the estimator output. The estimator is now
7307
+ * expected to already include messages + system prompt + tool definitions
7308
+ * (see `estimateRequestTokens.total`), so no overhead boost is needed. Kept
7309
+ * as a constant so a future calibration against real provider tokenization
7310
+ * (BPE vs the chars/3.5 rough estimator) can dial this without touching the
7311
+ * threshold-check math.
7312
+ *
7313
+ * Historical note: was 1.3 when the estimator only counted messages — that
7314
+ * double-counted system+tools once the estimator was upgraded, firing
7315
+ * compaction ~30% earlier than intended (e.g. real 56% load showed as 73%).
7283
7316
  */
7284
- static OVERHEAD_FACTOR = 1.3;
7317
+ static OVERHEAD_FACTOR = 1;
7318
+ /**
7319
+ * Once a compaction attempt reduces nothing (preserveK protects everything,
7320
+ * no oversized tool_results remain to elide), retrying on every iteration
7321
+ * just spams `compaction.fired` events without making progress. We remember
7322
+ * the no-op and skip until either the pressure level escalates or context
7323
+ * has grown by at least this many tokens since the failed attempt.
7324
+ */
7325
+ static NOOP_RETRY_DELTA_TOKENS = 2e3;
7326
+ /** Tracks the most recent no-op attempt so we can avoid re-firing per turn. */
7327
+ lastNoopAttempt = null;
7285
7328
  /**
7286
7329
  * @param compactor Compactor to use for compaction.
7287
7330
  * @param maxContext Provider's max context window in tokens.
@@ -7323,19 +7366,44 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
7323
7366
  hard: this.hardThreshold
7324
7367
  };
7325
7368
  const aggressiveOn = policy?.aggressiveOn ?? this.aggressiveOn;
7326
- if (load >= thresholds.hard) {
7327
- await this.compact(ctx, true, { level: "hard", tokens, load });
7328
- } else if (load >= thresholds.soft) {
7329
- await this.compact(ctx, aggressiveOn !== "hard", { level: "soft", tokens, load });
7330
- } else if (load >= thresholds.warn) {
7331
- await this.compact(ctx, aggressiveOn === "warn", { level: "warn", tokens, load });
7369
+ const level = load >= thresholds.hard ? "hard" : load >= thresholds.soft ? "soft" : load >= thresholds.warn ? "warn" : null;
7370
+ if (!level) {
7371
+ this.lastNoopAttempt = null;
7372
+ return next(ctx);
7373
+ }
7374
+ if (this.shouldSkipNoopRetry(level, tokens)) {
7375
+ return next(ctx);
7332
7376
  }
7377
+ const aggressive = level === "hard" ? true : level === "soft" ? aggressiveOn !== "hard" : aggressiveOn === "warn";
7378
+ await this.compact(ctx, aggressive, { level, tokens, load });
7333
7379
  return next(ctx);
7334
7380
  };
7335
7381
  }
7382
+ /**
7383
+ * Returns true when the previous compaction at the same or higher pressure
7384
+ * level reduced nothing and context has not grown materially since. Prevents
7385
+ * a stuck preserveK window from spamming compaction events every iteration.
7386
+ */
7387
+ shouldSkipNoopRetry(level, tokens) {
7388
+ const stuck = this.lastNoopAttempt;
7389
+ if (!stuck) return false;
7390
+ if (LEVEL_RANK2[level] > LEVEL_RANK2[stuck.level]) return false;
7391
+ const delta = tokens - stuck.tokens;
7392
+ return delta < _AutoCompactionMiddleware.NOOP_RETRY_DELTA_TOKENS;
7393
+ }
7394
+ recordAttempt(level, tokens, report) {
7395
+ const reduced = report.before > report.after;
7396
+ const repaired = !!report.repaired;
7397
+ if (reduced || repaired) {
7398
+ this.lastNoopAttempt = null;
7399
+ } else {
7400
+ this.lastNoopAttempt = { level, tokens };
7401
+ }
7402
+ }
7336
7403
  async compact(ctx, aggressive, pressure) {
7337
7404
  try {
7338
7405
  const report = await this.compactor.compact(ctx, { aggressive });
7406
+ this.recordAttempt(pressure.level, pressure.tokens, report);
7339
7407
  this.events?.emit("compaction.fired", {
7340
7408
  level: pressure.level,
7341
7409
  tokens: pressure.tokens,
@@ -8193,8 +8261,8 @@ ${recentJournal}` : "No prior iterations.",
8193
8261
  await saveGoal(this.goalPath, abandoned);
8194
8262
  }
8195
8263
  try {
8196
- const { unlink: unlink10 } = await import('fs/promises');
8197
- await unlink10(this.goalPath);
8264
+ const { unlink: unlink11 } = await import('fs/promises');
8265
+ await unlink11(this.goalPath);
8198
8266
  } catch {
8199
8267
  }
8200
8268
  this.opts.onEternalStop?.();
@@ -15446,10 +15514,10 @@ var AISpecBuilder = class {
15446
15514
  async saveSession() {
15447
15515
  if (!this.sessionPath) return;
15448
15516
  try {
15449
- const fsp16 = await import('fs/promises');
15450
- const path26 = await import('path');
15517
+ const fsp17 = await import('fs/promises');
15518
+ const path27 = await import('path');
15451
15519
  const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
15452
- await fsp16.mkdir(path26.dirname(this.sessionPath), { recursive: true });
15520
+ await fsp17.mkdir(path27.dirname(this.sessionPath), { recursive: true });
15453
15521
  await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
15454
15522
  } catch {
15455
15523
  }
@@ -15458,8 +15526,8 @@ var AISpecBuilder = class {
15458
15526
  async loadSession() {
15459
15527
  if (!this.sessionPath) return false;
15460
15528
  try {
15461
- const fsp16 = await import('fs/promises');
15462
- const raw = await fsp16.readFile(this.sessionPath, "utf8");
15529
+ const fsp17 = await import('fs/promises');
15530
+ const raw = await fsp17.readFile(this.sessionPath, "utf8");
15463
15531
  const loaded = JSON.parse(raw);
15464
15532
  if (loaded?.id && loaded?.phase && loaded?.title) {
15465
15533
  this.session = loaded;
@@ -15473,8 +15541,8 @@ var AISpecBuilder = class {
15473
15541
  async deleteSession() {
15474
15542
  if (!this.sessionPath) return;
15475
15543
  try {
15476
- const fsp16 = await import('fs/promises');
15477
- await fsp16.unlink(this.sessionPath);
15544
+ const fsp17 = await import('fs/promises');
15545
+ await fsp17.unlink(this.sessionPath);
15478
15546
  } catch {
15479
15547
  }
15480
15548
  }
@@ -16159,15 +16227,15 @@ function computeCriticalPath(graph, topoOrder, blockedByMap) {
16159
16227
  maxId = id;
16160
16228
  }
16161
16229
  }
16162
- const path26 = [];
16230
+ const path27 = [];
16163
16231
  let current = maxId;
16164
16232
  const visited = /* @__PURE__ */ new Set();
16165
16233
  while (current && !visited.has(current)) {
16166
16234
  visited.add(current);
16167
- path26.unshift(current);
16235
+ path27.unshift(current);
16168
16236
  current = prev.get(current) ?? null;
16169
16237
  }
16170
- return path26;
16238
+ return path27;
16171
16239
  }
16172
16240
  function computeParallelGroups(graph, blockedByMap) {
16173
16241
  const groups = [];
@@ -17147,7 +17215,7 @@ async function startMetricsServer(opts) {
17147
17215
  const tls = opts.tls;
17148
17216
  const useHttps = !!(tls?.cert && tls?.key);
17149
17217
  const host = opts.host ?? "127.0.0.1";
17150
- const path26 = opts.path ?? "/metrics";
17218
+ const path27 = opts.path ?? "/metrics";
17151
17219
  const healthPath = opts.healthPath ?? "/healthz";
17152
17220
  const healthRegistry = opts.healthRegistry;
17153
17221
  const listener = (req, res) => {
@@ -17157,7 +17225,7 @@ async function startMetricsServer(opts) {
17157
17225
  return;
17158
17226
  }
17159
17227
  const url = req.url.split("?")[0];
17160
- if (url === path26) {
17228
+ if (url === path27) {
17161
17229
  let body;
17162
17230
  try {
17163
17231
  body = renderPrometheus(opts.sink.snapshot());
@@ -17221,7 +17289,7 @@ async function startMetricsServer(opts) {
17221
17289
  const protocol = useHttps ? "https" : "http";
17222
17290
  return {
17223
17291
  port: boundPort,
17224
- url: `${protocol}://${host}:${boundPort}${path26}`,
17292
+ url: `${protocol}://${host}:${boundPort}${path27}`,
17225
17293
  close: () => new Promise((resolve6, reject) => {
17226
17294
  server.close((err) => err ? reject(err) : resolve6());
17227
17295
  })
@@ -19341,8 +19409,8 @@ var ReportGenerator = class {
19341
19409
  try {
19342
19410
  await stat(this.options.outputDir);
19343
19411
  } catch {
19344
- const { mkdir: mkdir11 } = await import('fs/promises');
19345
- await mkdir11(this.options.outputDir, { recursive: true });
19412
+ const { mkdir: mkdir12 } = await import('fs/promises');
19413
+ await mkdir12(this.options.outputDir, { recursive: true });
19346
19414
  }
19347
19415
  }
19348
19416
  generateMarkdown(result) {
@@ -20264,16 +20332,16 @@ Use \`/security report <number>\` to view a specific report.` };
20264
20332
  }
20265
20333
  const index = Number.parseInt(reportId, 10) - 1;
20266
20334
  if (!Number.isNaN(index) && reports[index]) {
20267
- const { readFile: readFile30 } = await import('fs/promises');
20268
- const content = await readFile30(join(reportsDir, reports[index]), "utf-8");
20335
+ const { readFile: readFile31 } = await import('fs/promises');
20336
+ const content = await readFile31(join(reportsDir, reports[index]), "utf-8");
20269
20337
  return { message: `# Security Report
20270
20338
 
20271
20339
  ${content}` };
20272
20340
  }
20273
20341
  const match = reports.find((r) => r.includes(reportId));
20274
20342
  if (match) {
20275
- const { readFile: readFile30 } = await import('fs/promises');
20276
- const content = await readFile30(join(reportsDir, match), "utf-8");
20343
+ const { readFile: readFile31 } = await import('fs/promises');
20344
+ const content = await readFile31(join(reportsDir, match), "utf-8");
20277
20345
  return { message: `# Security Report
20278
20346
 
20279
20347
  ${content}` };
@@ -23199,6 +23267,863 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
23199
23267
  });
23200
23268
  }
23201
23269
 
23202
- export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeLLMClassifier, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, pendingBtwCount, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
23270
+ // src/autophase/phase-graph-builder.ts
23271
+ var PhaseGraphBuilder = class _PhaseGraphBuilder {
23272
+ constructor(opts) {
23273
+ this.opts = opts;
23274
+ }
23275
+ opts;
23276
+ async build() {
23277
+ const graphId = crypto.randomUUID();
23278
+ const phases = /* @__PURE__ */ new Map();
23279
+ const phaseIds = [];
23280
+ for (let i = 0; i < this.opts.phases.length; i++) {
23281
+ const tmpl = this.opts.phases[i];
23282
+ const phaseId = crypto.randomUUID();
23283
+ phaseIds.push(phaseId);
23284
+ const store = new DefaultTaskStore();
23285
+ const tracker = new TaskTracker({ store });
23286
+ const taskGraph = await tracker.createGraph(phaseId, `${tmpl.name} Tasks`);
23287
+ if (tmpl.taskTemplates && tmpl.taskTemplates.length > 0) {
23288
+ for (const tt of tmpl.taskTemplates) {
23289
+ tracker.addNode({
23290
+ title: tt.title,
23291
+ description: tt.description,
23292
+ type: tt.type,
23293
+ priority: tt.priority,
23294
+ status: "pending",
23295
+ estimateHours: tt.estimateHours,
23296
+ tags: tt.tags ?? []
23297
+ });
23298
+ }
23299
+ }
23300
+ const phase = {
23301
+ id: phaseId,
23302
+ name: tmpl.name,
23303
+ description: tmpl.description,
23304
+ status: "pending",
23305
+ taskGraph,
23306
+ dependsOn: i > 0 ? [phaseIds[i - 1]] : [],
23307
+ nextPhases: i < this.opts.phases.length - 1 ? [phaseIds[i + 1]] : [],
23308
+ parallelizable: tmpl.parallelizable,
23309
+ priority: tmpl.priority,
23310
+ estimateHours: tmpl.estimateHours,
23311
+ assignedAgents: [],
23312
+ createdAt: Date.now(),
23313
+ updatedAt: Date.now()
23314
+ };
23315
+ phases.set(phaseId, phase);
23316
+ }
23317
+ const phaseArray = Array.from(phases.values());
23318
+ for (let i = 0; i < phaseArray.length; i++) {
23319
+ const phase = phaseArray[i];
23320
+ phase.nextPhases = i < phaseArray.length - 1 ? [phaseArray[i + 1].id] : [];
23321
+ phase.dependsOn = i > 0 ? [phaseArray[i - 1].id] : [];
23322
+ }
23323
+ const graph = {
23324
+ id: graphId,
23325
+ title: this.opts.title,
23326
+ description: this.opts.description ?? "",
23327
+ phases,
23328
+ rootPhaseIds: phaseIds.length > 0 ? [phaseIds[0]] : [],
23329
+ activePhaseIds: [],
23330
+ completedPhaseIds: [],
23331
+ failedPhaseIds: [],
23332
+ autonomous: this.opts.autonomous ?? true,
23333
+ stopOnComplete: true,
23334
+ createdAt: Date.now(),
23335
+ updatedAt: Date.now()
23336
+ };
23337
+ return graph;
23338
+ }
23339
+ /**
23340
+ * Var olan bir TaskGraph'tan fazlar oluştur.
23341
+ * Task'ları priority/type göre gruplayarak fazlara ayırır.
23342
+ */
23343
+ static fromTaskGraph(taskGraph, options) {
23344
+ const tasksPerPhase = options.tasksPerPhase ?? 5;
23345
+ const nodes = Array.from(taskGraph.nodes.values());
23346
+ const sorted = [...nodes].sort((a, b) => {
23347
+ const prioOrder = { critical: 0, high: 1, medium: 2, low: 3 };
23348
+ return (prioOrder[a.priority] ?? 4) - (prioOrder[b.priority] ?? 4);
23349
+ });
23350
+ const groups = [];
23351
+ for (let i = 0; i < sorted.length; i += tasksPerPhase) {
23352
+ groups.push(sorted.slice(i, i + tasksPerPhase));
23353
+ }
23354
+ const phaseTemplates = groups.map((group, idx) => {
23355
+ const hasCritical = group.some((t2) => t2.priority === "critical");
23356
+ const totalHours = group.reduce((sum, t2) => sum + (t2.estimateHours ?? 2), 0);
23357
+ return {
23358
+ name: `Phase ${idx + 1}: ${group[0]?.title.slice(0, 30) ?? "Tasks"}`,
23359
+ description: group.map((t2) => t2.title).join(", "),
23360
+ priority: hasCritical ? "critical" : "high",
23361
+ estimateHours: totalHours,
23362
+ parallelizable: false,
23363
+ taskTemplates: group.map((t2) => ({
23364
+ title: t2.title,
23365
+ description: t2.description,
23366
+ type: t2.type,
23367
+ priority: t2.priority,
23368
+ estimateHours: t2.estimateHours ?? 2,
23369
+ tags: t2.tags ?? []
23370
+ }))
23371
+ };
23372
+ });
23373
+ const builder = new _PhaseGraphBuilder({
23374
+ ...options,
23375
+ phases: phaseTemplates
23376
+ });
23377
+ return builder.build();
23378
+ }
23379
+ };
23380
+
23381
+ // src/autophase/phase-orchestrator.ts
23382
+ var PhaseOrchestrator = class {
23383
+ graph;
23384
+ ctx;
23385
+ opts;
23386
+ events;
23387
+ stopped = false;
23388
+ paused = false;
23389
+ runningPhases = /* @__PURE__ */ new Set();
23390
+ tickInterval = null;
23391
+ constructor(opts) {
23392
+ this.graph = opts.graph;
23393
+ this.ctx = opts.ctx;
23394
+ this.events = opts.events ?? this.createNoopEventBus();
23395
+ this.opts = {
23396
+ maxConcurrentPhases: opts.maxConcurrentPhases ?? 1,
23397
+ maxConcurrentTasks: opts.maxConcurrentTasks ?? 2,
23398
+ maxRetries: opts.maxRetries ?? 2,
23399
+ autonomous: opts.autonomous ?? true,
23400
+ phaseDelayMs: opts.phaseDelayMs ?? 0,
23401
+ stopOnFailure: opts.stopOnFailure ?? true,
23402
+ events: this.events
23403
+ };
23404
+ }
23405
+ // ─── Lifecycle ────────────────────────────────────────────────────────────
23406
+ /**
23407
+ * Tüm faz akışını başlat.
23408
+ * Autonomous mode'da: kök faz(lar)ı başlatır, bitince sonrakini otomatik başlatır.
23409
+ */
23410
+ async start() {
23411
+ this.stopped = false;
23412
+ this.paused = false;
23413
+ this.graph.startedAt = Date.now();
23414
+ this.graph.updatedAt = Date.now();
23415
+ let readyPhases = this.getReadyPhases();
23416
+ while (readyPhases.length > 0 && !this.stopped) {
23417
+ const batch = readyPhases.slice(0, this.opts.maxConcurrentPhases);
23418
+ await Promise.all(batch.map((p) => this.startPhase(p)));
23419
+ readyPhases = this.getReadyPhases().filter(
23420
+ (p) => !this.runningPhases.has(p.id) && p.status !== "completed" && p.status !== "failed"
23421
+ );
23422
+ }
23423
+ if (this.opts.autonomous) {
23424
+ this.tickInterval = setInterval(() => this.tick(), 1e3);
23425
+ }
23426
+ }
23427
+ /** Duraklat — aktif fazlar çalışmaya devam eder ama yeni faz başlamaz */
23428
+ pause() {
23429
+ this.paused = true;
23430
+ }
23431
+ /** Devam et — yeni fazlar başlayabilir */
23432
+ resume() {
23433
+ this.paused = false;
23434
+ void this.tick();
23435
+ }
23436
+ /** Tamamen durdur — aktif fazlar da durdurulur */
23437
+ stop() {
23438
+ this.stopped = true;
23439
+ if (this.tickInterval) {
23440
+ clearInterval(this.tickInterval);
23441
+ this.tickInterval = null;
23442
+ }
23443
+ for (const phaseId of this.runningPhases) {
23444
+ const phase = this.graph.phases.get(phaseId);
23445
+ if (phase) {
23446
+ this.updatePhaseStatus(phase, "paused");
23447
+ }
23448
+ }
23449
+ }
23450
+ // ─── Tick Loop (Autonomous) ───────────────────────────────────────────────
23451
+ async tick() {
23452
+ if (this.stopped || this.paused) return;
23453
+ const active = this.getActivePhases();
23454
+ const ready = this.getReadyPhases();
23455
+ this.emit("autonomous.tick", {
23456
+ activePhases: active.map((p) => p.id),
23457
+ queuedPhases: ready.map((p) => p.id)
23458
+ });
23459
+ this.ctx.onTick?.({ activePhases: active, readyPhases: ready });
23460
+ const availableSlots = this.opts.maxConcurrentPhases - active.length;
23461
+ if (availableSlots > 0 && ready.length > 0) {
23462
+ for (const phase of ready.slice(0, availableSlots)) {
23463
+ await this.startPhase(phase);
23464
+ }
23465
+ }
23466
+ if (this.isComplete()) {
23467
+ this.onGraphComplete();
23468
+ return;
23469
+ }
23470
+ if (this.opts.stopOnFailure && this.graph.failedPhaseIds.length > 0) {
23471
+ const failedPhase = this.graph.phases.get(this.graph.failedPhaseIds[0]);
23472
+ if (failedPhase) {
23473
+ this.onGraphFailed(failedPhase);
23474
+ }
23475
+ return;
23476
+ }
23477
+ }
23478
+ // ─── Phase Execution ──────────────────────────────────────────────────────
23479
+ async startPhase(phase) {
23480
+ if (phase.status !== "pending" && phase.status !== "ready") return;
23481
+ this.updatePhaseStatus(phase, "running");
23482
+ phase.startedAt = Date.now();
23483
+ this.runningPhases.add(phase.id);
23484
+ this.graph.activePhaseIds.push(phase.id);
23485
+ this.emit("phase.started", { phaseId: phase.id, name: phase.name });
23486
+ try {
23487
+ await this.executePhaseTasks(phase);
23488
+ const failedTasks = this.getFailedTaskCount(phase);
23489
+ const completedTasks = this.getCompletedTaskCount(phase);
23490
+ this.emit("phase.allTasksDone", {
23491
+ phaseId: phase.id,
23492
+ completed: completedTasks,
23493
+ failed: failedTasks
23494
+ });
23495
+ if (failedTasks > 0 && this.opts.stopOnFailure) {
23496
+ this.updatePhaseStatus(phase, "failed");
23497
+ phase.completedAt = Date.now();
23498
+ phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23499
+ this.runningPhases.delete(phase.id);
23500
+ this.emit("phase.failed", {
23501
+ phaseId: phase.id,
23502
+ name: phase.name,
23503
+ error: `${failedTasks} task(s) failed`
23504
+ });
23505
+ this.ctx.onPhaseFail?.(phase, new Error(`${failedTasks} task(s) failed`));
23506
+ } else {
23507
+ this.updatePhaseStatus(phase, "completed");
23508
+ phase.completedAt = Date.now();
23509
+ phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23510
+ this.runningPhases.delete(phase.id);
23511
+ this.graph.completedPhaseIds.push(phase.id);
23512
+ this.emit("phase.completed", {
23513
+ phaseId: phase.id,
23514
+ name: phase.name,
23515
+ durationMs: phase.actualDurationMs
23516
+ });
23517
+ this.ctx.onPhaseComplete?.(phase);
23518
+ }
23519
+ } catch (error) {
23520
+ this.updatePhaseStatus(phase, "failed");
23521
+ phase.completedAt = Date.now();
23522
+ phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23523
+ this.runningPhases.delete(phase.id);
23524
+ this.graph.failedPhaseIds.push(phase.id);
23525
+ this.emit("phase.failed", {
23526
+ phaseId: phase.id,
23527
+ name: phase.name,
23528
+ error: error instanceof Error ? error.message : String(error)
23529
+ });
23530
+ this.ctx.onPhaseFail?.(phase, error instanceof Error ? error : new Error(String(error)));
23531
+ }
23532
+ }
23533
+ async executePhaseTasks(phase) {
23534
+ phase.taskGraph;
23535
+ const pendingTasks = this.getExecutableTasks(phase);
23536
+ while (pendingTasks.length > 0 && !this.stopped) {
23537
+ const batch = pendingTasks.splice(0, this.opts.maxConcurrentTasks);
23538
+ const results = await Promise.allSettled(
23539
+ batch.map((task) => this.executeSingleTask(task, phase))
23540
+ );
23541
+ for (let i = 0; i < results.length; i++) {
23542
+ const result = results[i];
23543
+ const task = batch[i];
23544
+ if (!result || !task) continue;
23545
+ if (result.status === "fulfilled") {
23546
+ this.markTaskCompleted(phase, task);
23547
+ } else {
23548
+ this.markTaskFailed(phase, task, result.reason);
23549
+ }
23550
+ }
23551
+ const newReady = this.getExecutableTasks(phase);
23552
+ pendingTasks.length = 0;
23553
+ pendingTasks.push(...newReady);
23554
+ }
23555
+ }
23556
+ async executeSingleTask(task, phase) {
23557
+ const tracker = this.getTrackerForPhase(phase);
23558
+ tracker.updateNodeStatus(task.id, "in_progress");
23559
+ return this.ctx.executeTask(task, phase.id);
23560
+ }
23561
+ markTaskCompleted(phase, task) {
23562
+ const tracker = this.getTrackerForPhase(phase);
23563
+ tracker.updateNodeStatus(task.id, "completed");
23564
+ this.emit("phase.taskCompleted", {
23565
+ phaseId: phase.id,
23566
+ taskId: task.id,
23567
+ taskTitle: task.title
23568
+ });
23569
+ }
23570
+ markTaskFailed(phase, task, error) {
23571
+ const tracker = this.getTrackerForPhase(phase);
23572
+ tracker.updateNodeStatus(task.id, "failed", error instanceof Error ? error.message : String(error));
23573
+ this.emit("phase.taskFailed", {
23574
+ phaseId: phase.id,
23575
+ taskId: task.id,
23576
+ taskTitle: task.title,
23577
+ error: error instanceof Error ? error.message : String(error)
23578
+ });
23579
+ }
23580
+ // ─── Helpers ──────────────────────────────────────────────────────────────
23581
+ getReadyPhases() {
23582
+ const ready = [];
23583
+ for (const phase of this.graph.phases.values()) {
23584
+ if (phase.status !== "pending") continue;
23585
+ const depsDone = phase.dependsOn.every((depId) => {
23586
+ const dep = this.graph.phases.get(depId);
23587
+ return dep?.status === "completed" || dep?.status === "skipped";
23588
+ });
23589
+ if (depsDone) {
23590
+ ready.push(phase);
23591
+ }
23592
+ }
23593
+ const prioOrder = { critical: 0, high: 1, medium: 2, low: 3 };
23594
+ ready.sort((a, b) => (prioOrder[a.priority] ?? 4) - (prioOrder[b.priority] ?? 4));
23595
+ return ready;
23596
+ }
23597
+ getActivePhases() {
23598
+ return Array.from(this.graph.phases.values()).filter((p) => p.status === "running");
23599
+ }
23600
+ getExecutableTasks(phase) {
23601
+ const tracker = this.getTrackerForPhase(phase);
23602
+ return tracker.getAllNodes({ status: ["pending", "blocked"] }).filter((n) => n.status === "pending" && tracker.canStart(n.id)).sort((a, b) => {
23603
+ const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
23604
+ return (priorityOrder[a.priority] ?? 4) - (priorityOrder[b.priority] ?? 4);
23605
+ });
23606
+ }
23607
+ getTrackerForPhase(phase) {
23608
+ const store = new DefaultTaskStore();
23609
+ const tracker = new TaskTracker({ store });
23610
+ tracker.graph = phase.taskGraph;
23611
+ return tracker;
23612
+ }
23613
+ getFailedTaskCount(phase) {
23614
+ const tracker = this.getTrackerForPhase(phase);
23615
+ return tracker.getAllNodes({ status: ["failed"] }).length;
23616
+ }
23617
+ getCompletedTaskCount(phase) {
23618
+ const tracker = this.getTrackerForPhase(phase);
23619
+ return tracker.getAllNodes({ status: ["completed"] }).length;
23620
+ }
23621
+ updatePhaseStatus(phase, status) {
23622
+ const from = phase.status;
23623
+ phase.status = status;
23624
+ phase.updatedAt = Date.now();
23625
+ this.graph.updatedAt = Date.now();
23626
+ this.emit("phase.statusChange", { phaseId: phase.id, from, to: status });
23627
+ }
23628
+ isComplete() {
23629
+ const allPhases = Array.from(this.graph.phases.values());
23630
+ return allPhases.every(
23631
+ (p) => p.status === "completed" || p.status === "skipped" || p.status === "failed"
23632
+ );
23633
+ }
23634
+ onGraphComplete() {
23635
+ this.graph.completedAt = Date.now();
23636
+ const durationMs = this.graph.completedAt - (this.graph.startedAt ?? this.graph.completedAt);
23637
+ this.emit("graph.completed", { graphId: this.graph.id, durationMs });
23638
+ this.stop();
23639
+ }
23640
+ onGraphFailed(failedPhase) {
23641
+ this.emit("graph.failed", {
23642
+ graphId: this.graph.id,
23643
+ failedPhaseId: failedPhase.id,
23644
+ error: `Phase "${failedPhase.name}" failed`
23645
+ });
23646
+ this.stop();
23647
+ }
23648
+ // ─── Progress ─────────────────────────────────────────────────────────────
23649
+ getProgress() {
23650
+ const phases = Array.from(this.graph.phases.values());
23651
+ let pending = 0, ready = 0, running = 0, paused = 0, completed = 0, failed = 0, skipped = 0;
23652
+ let totalTasks = 0, completedTasks = 0, failedTasks = 0, estimatedHours = 0, actualHours = 0;
23653
+ for (const p of phases) {
23654
+ switch (p.status) {
23655
+ case "pending":
23656
+ pending++;
23657
+ break;
23658
+ case "ready":
23659
+ ready++;
23660
+ break;
23661
+ case "running":
23662
+ running++;
23663
+ break;
23664
+ case "paused":
23665
+ paused++;
23666
+ break;
23667
+ case "completed":
23668
+ completed++;
23669
+ break;
23670
+ case "failed":
23671
+ failed++;
23672
+ break;
23673
+ case "skipped":
23674
+ skipped++;
23675
+ break;
23676
+ }
23677
+ estimatedHours += p.estimateHours;
23678
+ if (p.actualDurationMs) actualHours += p.actualDurationMs / 36e5;
23679
+ const tracker = this.getTrackerForPhase(p);
23680
+ const progress = tracker.getProgress();
23681
+ totalTasks += progress.total;
23682
+ completedTasks += progress.completed;
23683
+ failedTasks += progress.failed;
23684
+ }
23685
+ const totalPhases = phases.length;
23686
+ const done = completed + skipped;
23687
+ return {
23688
+ totalPhases,
23689
+ pending,
23690
+ ready,
23691
+ running,
23692
+ paused,
23693
+ completed,
23694
+ failed,
23695
+ skipped,
23696
+ percentComplete: totalPhases > 0 ? Math.round(done / totalPhases * 100) : 0,
23697
+ totalTasks,
23698
+ completedTasks,
23699
+ failedTasks,
23700
+ estimatedHours,
23701
+ actualHours
23702
+ };
23703
+ }
23704
+ getGraph() {
23705
+ return this.graph;
23706
+ }
23707
+ isRunning() {
23708
+ return !this.stopped && this.runningPhases.size > 0;
23709
+ }
23710
+ isPaused() {
23711
+ return this.paused;
23712
+ }
23713
+ // ─── Agent Assignment ─────────────────────────────────────────────────────
23714
+ assignAgent(phaseId, agentId) {
23715
+ const phase = this.graph.phases.get(phaseId);
23716
+ if (!phase) return;
23717
+ if (!phase.assignedAgents.includes(agentId)) {
23718
+ phase.assignedAgents.push(agentId);
23719
+ this.emit("agent.assigned", { phaseId, agentId });
23720
+ }
23721
+ }
23722
+ releaseAgent(phaseId, agentId) {
23723
+ const phase = this.graph.phases.get(phaseId);
23724
+ if (!phase) return;
23725
+ phase.assignedAgents = phase.assignedAgents.filter((id) => id !== agentId);
23726
+ this.emit("agent.released", { phaseId, agentId });
23727
+ }
23728
+ // ─── Events ───────────────────────────────────────────────────────────────
23729
+ emit(event, payload) {
23730
+ this.events.emit(event, payload);
23731
+ }
23732
+ createNoopEventBus() {
23733
+ return {
23734
+ emit: () => {
23735
+ },
23736
+ on: () => {
23737
+ },
23738
+ off: () => {
23739
+ },
23740
+ once: () => {
23741
+ },
23742
+ listeners: /* @__PURE__ */ new Map(),
23743
+ wildcards: /* @__PURE__ */ new Set(),
23744
+ setLogger: () => {
23745
+ },
23746
+ onAny: () => {
23747
+ },
23748
+ offAny: () => {
23749
+ },
23750
+ emitAsync: async () => [],
23751
+ waitFor: async () => {
23752
+ }
23753
+ };
23754
+ }
23755
+ };
23756
+
23757
+ // src/autophase/auto-phase-runner.ts
23758
+ var AutoPhaseRunner = class {
23759
+ graph = null;
23760
+ orchestrator = null;
23761
+ opts;
23762
+ progressInterval = null;
23763
+ constructor(opts) {
23764
+ this.opts = opts;
23765
+ }
23766
+ async start() {
23767
+ const builder = new PhaseGraphBuilder({
23768
+ title: this.opts.title,
23769
+ description: this.opts.description,
23770
+ phases: this.opts.phases,
23771
+ autonomous: this.opts.autonomous,
23772
+ stopOnFailure: this.opts.stopOnFailure
23773
+ });
23774
+ this.graph = await builder.build();
23775
+ const ctx = {
23776
+ executeTask: this.opts.executeTask,
23777
+ onPhaseComplete: (phase) => {
23778
+ this.opts.onPhaseComplete?.(phase);
23779
+ },
23780
+ onPhaseFail: (phase, error) => {
23781
+ this.opts.onPhaseFail?.(phase, error);
23782
+ },
23783
+ onTick: (tickCtx) => {
23784
+ this.opts.onTick?.(tickCtx);
23785
+ }
23786
+ };
23787
+ this.orchestrator = new PhaseOrchestrator({
23788
+ graph: this.graph,
23789
+ ctx,
23790
+ maxConcurrentPhases: this.opts.maxConcurrentPhases,
23791
+ maxConcurrentTasks: this.opts.maxConcurrentTasks,
23792
+ maxRetries: this.opts.maxRetries,
23793
+ autonomous: this.opts.autonomous,
23794
+ phaseDelayMs: this.opts.phaseDelayMs,
23795
+ stopOnFailure: this.opts.stopOnFailure,
23796
+ events: this.opts.events
23797
+ });
23798
+ if (this.opts.onProgress) {
23799
+ this.progressInterval = setInterval(() => {
23800
+ const progress = this.orchestrator.getProgress();
23801
+ this.opts.onProgress(progress);
23802
+ }, 2e3);
23803
+ }
23804
+ const events = this.opts.events;
23805
+ if (events) {
23806
+ events.on(
23807
+ "graph.completed",
23808
+ (payload) => {
23809
+ const p = payload;
23810
+ if (this.graph && p.graphId === this.graph.id) {
23811
+ this.opts.onComplete?.(this.graph);
23812
+ this.cleanup();
23813
+ }
23814
+ }
23815
+ );
23816
+ events.on(
23817
+ "graph.failed",
23818
+ (payload) => {
23819
+ const p = payload;
23820
+ if (this.graph && p.graphId === this.graph.id) {
23821
+ const failedPhase = this.graph.phases.get(p.failedPhaseId);
23822
+ if (failedPhase) {
23823
+ this.opts.onFail?.(this.graph, failedPhase, new Error(p.error));
23824
+ }
23825
+ this.cleanup();
23826
+ }
23827
+ }
23828
+ );
23829
+ }
23830
+ await this.orchestrator.start();
23831
+ return this.graph;
23832
+ }
23833
+ pause() {
23834
+ this.orchestrator?.pause();
23835
+ }
23836
+ resume() {
23837
+ this.orchestrator?.resume();
23838
+ }
23839
+ stop() {
23840
+ this.orchestrator?.stop();
23841
+ this.cleanup();
23842
+ }
23843
+ getProgress() {
23844
+ return this.orchestrator?.getProgress() ?? null;
23845
+ }
23846
+ getGraph() {
23847
+ return this.graph;
23848
+ }
23849
+ isRunning() {
23850
+ return this.orchestrator?.isRunning() ?? false;
23851
+ }
23852
+ isPaused() {
23853
+ return this.orchestrator?.isPaused() ?? false;
23854
+ }
23855
+ assignAgent(phaseId, agentId) {
23856
+ this.orchestrator?.assignAgent(phaseId, agentId);
23857
+ }
23858
+ releaseAgent(phaseId, agentId) {
23859
+ this.orchestrator?.releaseAgent(phaseId, agentId);
23860
+ }
23861
+ cleanup() {
23862
+ if (this.progressInterval) {
23863
+ clearInterval(this.progressInterval);
23864
+ this.progressInterval = null;
23865
+ }
23866
+ }
23867
+ };
23868
+ async function createAutoPhaseFromTaskGraph(taskGraph, options) {
23869
+ const graph = await PhaseGraphBuilder.fromTaskGraph(taskGraph, {
23870
+ title: options.title ?? taskGraph.title,
23871
+ tasksPerPhase: options.tasksPerPhase
23872
+ });
23873
+ const phases = Array.from(graph.phases.values()).map((p) => ({
23874
+ name: p.name,
23875
+ description: p.description,
23876
+ priority: p.priority,
23877
+ estimateHours: p.estimateHours,
23878
+ parallelizable: p.parallelizable
23879
+ }));
23880
+ return new AutoPhaseRunner({
23881
+ ...options,
23882
+ title: options.title ?? taskGraph.title,
23883
+ phases
23884
+ });
23885
+ }
23886
+ var PhaseStore = class {
23887
+ baseDir;
23888
+ constructor(opts) {
23889
+ this.baseDir = opts.baseDir;
23890
+ }
23891
+ async save(graph) {
23892
+ const filePath = this.getFilePath(graph.id);
23893
+ await fsp2.mkdir(path6.dirname(filePath), { recursive: true });
23894
+ const serialized = this.serializeGraph(graph);
23895
+ await fsp2.writeFile(filePath, JSON.stringify(serialized, null, 2), "utf8");
23896
+ }
23897
+ async load(graphId) {
23898
+ const filePath = this.getFilePath(graphId);
23899
+ try {
23900
+ const raw = await fsp2.readFile(filePath, "utf8");
23901
+ const serialized = JSON.parse(raw);
23902
+ return this.deserializeGraph(serialized);
23903
+ } catch {
23904
+ return null;
23905
+ }
23906
+ }
23907
+ async delete(graphId) {
23908
+ const filePath = this.getFilePath(graphId);
23909
+ try {
23910
+ await fsp2.unlink(filePath);
23911
+ } catch {
23912
+ }
23913
+ }
23914
+ async list() {
23915
+ try {
23916
+ const entries = await fsp2.readdir(this.baseDir, { withFileTypes: true });
23917
+ const graphs = [];
23918
+ for (const entry of entries) {
23919
+ if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
23920
+ try {
23921
+ const raw = await fsp2.readFile(path6.join(this.baseDir, entry.name), "utf8");
23922
+ const serialized = JSON.parse(raw);
23923
+ const done = serialized.completedPhaseIds.length;
23924
+ const total = serialized.phases.length;
23925
+ graphs.push({
23926
+ id: serialized.id,
23927
+ title: serialized.title,
23928
+ updatedAt: serialized.updatedAt,
23929
+ status: done === total ? "completed" : done > 0 ? "in_progress" : "pending"
23930
+ });
23931
+ } catch {
23932
+ }
23933
+ }
23934
+ return graphs.sort((a, b) => b.updatedAt - a.updatedAt);
23935
+ } catch {
23936
+ return [];
23937
+ }
23938
+ }
23939
+ getFilePath(graphId) {
23940
+ return path6.join(this.baseDir, `${graphId}.json`);
23941
+ }
23942
+ serializeGraph(graph) {
23943
+ return {
23944
+ id: graph.id,
23945
+ title: graph.title,
23946
+ description: graph.description,
23947
+ phases: Array.from(graph.phases.values()).map((p) => this.serializePhase(p)),
23948
+ rootPhaseIds: graph.rootPhaseIds,
23949
+ activePhaseIds: graph.activePhaseIds,
23950
+ completedPhaseIds: graph.completedPhaseIds,
23951
+ failedPhaseIds: graph.failedPhaseIds,
23952
+ autonomous: graph.autonomous,
23953
+ stopOnComplete: graph.stopOnComplete,
23954
+ createdAt: graph.createdAt,
23955
+ updatedAt: graph.updatedAt,
23956
+ startedAt: graph.startedAt,
23957
+ completedAt: graph.completedAt
23958
+ };
23959
+ }
23960
+ serializePhase(phase) {
23961
+ return {
23962
+ id: phase.id,
23963
+ name: phase.name,
23964
+ description: phase.description,
23965
+ status: phase.status,
23966
+ taskGraph: this.serializeTaskGraph(phase.taskGraph),
23967
+ dependsOn: phase.dependsOn,
23968
+ nextPhases: phase.nextPhases,
23969
+ parallelizable: phase.parallelizable,
23970
+ priority: phase.priority,
23971
+ estimateHours: phase.estimateHours,
23972
+ actualDurationMs: phase.actualDurationMs,
23973
+ startedAt: phase.startedAt,
23974
+ completedAt: phase.completedAt,
23975
+ assignedAgents: phase.assignedAgents,
23976
+ metadata: phase.metadata,
23977
+ createdAt: phase.createdAt,
23978
+ updatedAt: phase.updatedAt
23979
+ };
23980
+ }
23981
+ serializeTaskGraph(graph) {
23982
+ return {
23983
+ id: graph.id,
23984
+ specId: graph.specId,
23985
+ title: graph.title,
23986
+ nodes: Array.from(graph.nodes.values()).map((n) => this.serializeTaskNode(n)),
23987
+ edges: graph.edges,
23988
+ rootNodes: graph.rootNodes,
23989
+ createdAt: graph.createdAt,
23990
+ updatedAt: graph.updatedAt
23991
+ };
23992
+ }
23993
+ serializeTaskNode(node) {
23994
+ return { ...node };
23995
+ }
23996
+ deserializeGraph(serialized) {
23997
+ const phases = /* @__PURE__ */ new Map();
23998
+ for (const sp of serialized.phases) {
23999
+ phases.set(sp.id, this.deserializePhase(sp));
24000
+ }
24001
+ return {
24002
+ id: serialized.id,
24003
+ title: serialized.title,
24004
+ description: serialized.description,
24005
+ phases,
24006
+ rootPhaseIds: serialized.rootPhaseIds,
24007
+ activePhaseIds: serialized.activePhaseIds,
24008
+ completedPhaseIds: serialized.completedPhaseIds,
24009
+ failedPhaseIds: serialized.failedPhaseIds,
24010
+ autonomous: serialized.autonomous,
24011
+ stopOnComplete: serialized.stopOnComplete,
24012
+ createdAt: serialized.createdAt,
24013
+ updatedAt: serialized.updatedAt,
24014
+ startedAt: serialized.startedAt,
24015
+ completedAt: serialized.completedAt
24016
+ };
24017
+ }
24018
+ deserializePhase(serialized) {
24019
+ return {
24020
+ id: serialized.id,
24021
+ name: serialized.name,
24022
+ description: serialized.description,
24023
+ status: serialized.status,
24024
+ taskGraph: this.deserializeTaskGraph(serialized.taskGraph),
24025
+ dependsOn: serialized.dependsOn,
24026
+ nextPhases: serialized.nextPhases,
24027
+ parallelizable: serialized.parallelizable,
24028
+ priority: serialized.priority,
24029
+ estimateHours: serialized.estimateHours,
24030
+ actualDurationMs: serialized.actualDurationMs,
24031
+ startedAt: serialized.startedAt,
24032
+ completedAt: serialized.completedAt,
24033
+ assignedAgents: serialized.assignedAgents,
24034
+ metadata: serialized.metadata,
24035
+ createdAt: serialized.createdAt,
24036
+ updatedAt: serialized.updatedAt
24037
+ };
24038
+ }
24039
+ deserializeTaskGraph(serialized) {
24040
+ const nodes = /* @__PURE__ */ new Map();
24041
+ for (const sn of serialized.nodes) {
24042
+ nodes.set(sn.id, sn);
24043
+ }
24044
+ return {
24045
+ id: serialized.id,
24046
+ specId: serialized.specId,
24047
+ title: serialized.title,
24048
+ nodes,
24049
+ edges: serialized.edges,
24050
+ rootNodes: serialized.rootNodes,
24051
+ createdAt: serialized.createdAt,
24052
+ updatedAt: serialized.updatedAt
24053
+ };
24054
+ }
24055
+ };
24056
+
24057
+ // src/autophase/checkpoint.ts
24058
+ var CheckpointManager = class {
24059
+ store;
24060
+ maxCheckpoints;
24061
+ checkpoints = /* @__PURE__ */ new Map();
24062
+ constructor(opts) {
24063
+ this.store = opts.store;
24064
+ this.maxCheckpoints = opts.maxCheckpoints ?? 10;
24065
+ }
24066
+ async saveCheckpoint(graph, label) {
24067
+ await this.store.save(graph);
24068
+ const activePhase = Array.from(graph.phases.values()).find(
24069
+ (p) => p.status === "running" || p.status === "paused"
24070
+ );
24071
+ const checkpoint = {
24072
+ id: crypto.randomUUID(),
24073
+ graphId: graph.id,
24074
+ phaseId: activePhase?.id ?? graph.rootPhaseIds[0] ?? "",
24075
+ phaseStatus: activePhase?.status ?? "pending",
24076
+ taskStatuses: activePhase ? Array.from(activePhase.taskGraph.nodes.values()).map((t2) => ({
24077
+ taskId: t2.id,
24078
+ status: t2.status,
24079
+ title: t2.title
24080
+ })) : [],
24081
+ timestamp: Date.now(),
24082
+ label
24083
+ };
24084
+ this.checkpoints.set(checkpoint.id, checkpoint);
24085
+ this.pruneCheckpoints();
24086
+ return checkpoint;
24087
+ }
24088
+ async restoreCheckpoint(checkpointId) {
24089
+ const checkpoint = this.checkpoints.get(checkpointId);
24090
+ if (!checkpoint) return null;
24091
+ const graph = await this.store.load(checkpoint.graphId);
24092
+ if (!graph) return null;
24093
+ const phase = graph.phases.get(checkpoint.phaseId);
24094
+ if (phase) {
24095
+ phase.status = checkpoint.phaseStatus;
24096
+ phase.updatedAt = Date.now();
24097
+ for (const ts of checkpoint.taskStatuses) {
24098
+ const task = phase.taskGraph.nodes.get(ts.taskId);
24099
+ if (task) {
24100
+ task.status = ts.status;
24101
+ task.updatedAt = Date.now();
24102
+ }
24103
+ }
24104
+ }
24105
+ graph.updatedAt = Date.now();
24106
+ return graph;
24107
+ }
24108
+ listCheckpoints(graphId) {
24109
+ const all = Array.from(this.checkpoints.values());
24110
+ const filtered = graphId ? all.filter((c) => c.graphId === graphId) : all;
24111
+ return filtered.sort((a, b) => b.timestamp - a.timestamp);
24112
+ }
24113
+ deleteCheckpoint(checkpointId) {
24114
+ return this.checkpoints.delete(checkpointId);
24115
+ }
24116
+ pruneCheckpoints() {
24117
+ const all = Array.from(this.checkpoints.values()).sort(
24118
+ (a, b) => a.timestamp - b.timestamp
24119
+ );
24120
+ while (all.length > this.maxCheckpoints) {
24121
+ const oldest = all.shift();
24122
+ if (oldest) this.checkpoints.delete(oldest.id);
24123
+ }
24124
+ }
24125
+ };
24126
+
24127
+ export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, CheckpointManager, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeLLMClassifier, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, pendingBtwCount, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
23203
24128
  //# sourceMappingURL=index.js.map
23204
24129
  //# sourceMappingURL=index.js.map