@wrongstack/core 0.8.2 → 0.8.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.
package/dist/index.js CHANGED
@@ -93,7 +93,7 @@ async function renameWithRetry(from, to) {
93
93
  if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
94
94
  throw err;
95
95
  }
96
- await new Promise((resolve6) => setTimeout(resolve6, delays[i]));
96
+ await new Promise((resolve7) => setTimeout(resolve7, delays[i]));
97
97
  }
98
98
  }
99
99
  throw lastErr;
@@ -2692,7 +2692,7 @@ var InMemoryAgentBridge = class {
2692
2692
  );
2693
2693
  }
2694
2694
  this.inflightGuards.add(correlationId);
2695
- return new Promise((resolve6, reject) => {
2695
+ return new Promise((resolve7, reject) => {
2696
2696
  const timer = setTimeout(() => {
2697
2697
  this.inflightGuards.delete(correlationId);
2698
2698
  this.pendingRequests.delete(correlationId);
@@ -2704,7 +2704,7 @@ var InMemoryAgentBridge = class {
2704
2704
  return;
2705
2705
  }
2706
2706
  this.pendingRequests.set(correlationId, {
2707
- resolve: resolve6,
2707
+ resolve: resolve7,
2708
2708
  reject,
2709
2709
  timer
2710
2710
  });
@@ -2930,7 +2930,7 @@ var ToolExecutor = class {
2930
2930
  return { result, tool, durationMs: Date.now() - start };
2931
2931
  }
2932
2932
  if (hasMalformedArguments(use.input)) {
2933
- const result = this.malformedInputResult(use);
2933
+ const result = this.malformedInputResult(use, extractMalformedRaw(use.input));
2934
2934
  budget = this.decrementBudget(result, budget);
2935
2935
  return { result, tool, durationMs: Date.now() - start };
2936
2936
  }
@@ -3137,11 +3137,18 @@ var ToolExecutor = class {
3137
3137
  is_error: true
3138
3138
  };
3139
3139
  }
3140
- malformedInputResult(use) {
3140
+ malformedInputResult(use, raw) {
3141
+ let content = `Tool "${use.name}" received arguments that were not a valid JSON object, so they could not be parsed. Re-issue the call with the arguments encoded as a single well-formed JSON object matching the tool's input schema.`;
3142
+ if (raw) {
3143
+ const max = 800;
3144
+ const excerpt = raw.length > max ? `${raw.slice(0, max)}\u2026 (truncated, ${raw.length} chars total)` : raw;
3145
+ content += ` Common cause: a string field (e.g. code in old_string/new_string) contains literal newlines, quotes, or backslashes that must be JSON-escaped, or the payload was cut off mid-stream. The raw arguments received were:
3146
+ ${excerpt}`;
3147
+ }
3141
3148
  return {
3142
3149
  type: "tool_result",
3143
3150
  tool_use_id: use.id,
3144
- content: `Tool "${use.name}" received arguments that were not a valid JSON object, so they could not be parsed. Re-issue the call with the arguments encoded as a single well-formed JSON object matching the tool's input schema.`,
3151
+ content,
3145
3152
  is_error: true
3146
3153
  };
3147
3154
  }
@@ -3197,6 +3204,18 @@ function hasMalformedArguments(input) {
3197
3204
  const keys = Object.keys(obj);
3198
3205
  return keys.length === 1 && MALFORMED_ARG_MARKERS.includes(keys[0]);
3199
3206
  }
3207
+ function extractMalformedRaw(input) {
3208
+ if (!hasMalformedArguments(input)) return void 0;
3209
+ const obj = input;
3210
+ const value = obj[Object.keys(obj)[0]];
3211
+ if (value === void 0 || value === null) return void 0;
3212
+ if (typeof value === "string") return value;
3213
+ try {
3214
+ return JSON.stringify(value);
3215
+ } catch {
3216
+ return String(value);
3217
+ }
3218
+ }
3200
3219
 
3201
3220
  // src/utils/regex-guard.ts
3202
3221
  var MAX_PATTERN_LEN = 512;
@@ -3536,6 +3555,7 @@ function sanitizeJsonString(s) {
3536
3555
  let out = s.trim();
3537
3556
  out = stripSingleLineComments(out);
3538
3557
  out = out.replace(/,(\s*[}\]])/g, "$1");
3558
+ out = escapeControlCharsInStrings(out);
3539
3559
  try {
3540
3560
  JSON.parse(out);
3541
3561
  return out;
@@ -3543,6 +3563,43 @@ function sanitizeJsonString(s) {
3543
3563
  return null;
3544
3564
  }
3545
3565
  }
3566
+ function escapeControlCharsInStrings(s) {
3567
+ let inString = false;
3568
+ let out = "";
3569
+ for (let i = 0; i < s.length; i++) {
3570
+ const c = s[i];
3571
+ if (c === '"' && (i === 0 || s[i - 1] !== "\\")) {
3572
+ inString = !inString;
3573
+ out += c;
3574
+ continue;
3575
+ }
3576
+ const code = c.charCodeAt(0);
3577
+ if (inString && code < 32) {
3578
+ switch (c) {
3579
+ case "\n":
3580
+ out += "\\n";
3581
+ break;
3582
+ case "\r":
3583
+ out += "\\r";
3584
+ break;
3585
+ case " ":
3586
+ out += "\\t";
3587
+ break;
3588
+ case "\b":
3589
+ out += "\\b";
3590
+ break;
3591
+ case "\f":
3592
+ out += "\\f";
3593
+ break;
3594
+ default:
3595
+ out += `\\u${code.toString(16).padStart(4, "0")}`;
3596
+ }
3597
+ continue;
3598
+ }
3599
+ out += c;
3600
+ }
3601
+ return out;
3602
+ }
3546
3603
  function stripSingleLineComments(s) {
3547
3604
  let inString = false;
3548
3605
  const chars = [];
@@ -3868,7 +3925,8 @@ function resolveWstackPaths(opts) {
3868
3925
  projectSpecs: path6.join(projectDir, "specs"),
3869
3926
  projectTaskGraphs: path6.join(projectDir, "task-graphs"),
3870
3927
  projectSddSession: path6.join(projectDir, "sdd-session.json"),
3871
- projectPlan: path6.join(projectDir, "plan.json")
3928
+ projectPlan: path6.join(projectDir, "plan.json"),
3929
+ projectAutophase: path6.join(projectDir, "autophase")
3872
3930
  };
3873
3931
  }
3874
3932
 
@@ -3965,11 +4023,11 @@ function validateAgainstSchema(value, schema) {
3965
4023
  walk2(value, schema, "", errors);
3966
4024
  return { ok: errors.length === 0, errors };
3967
4025
  }
3968
- function walk2(value, schema, path26, errors) {
4026
+ function walk2(value, schema, path28, errors) {
3969
4027
  if (schema.enum !== void 0) {
3970
4028
  if (!schema.enum.some((e) => deepEqual(e, value))) {
3971
4029
  errors.push({
3972
- path: path26 || "<root>",
4030
+ path: path28 || "<root>",
3973
4031
  message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
3974
4032
  });
3975
4033
  return;
@@ -3978,7 +4036,7 @@ function walk2(value, schema, path26, errors) {
3978
4036
  if (typeof schema.type === "string") {
3979
4037
  if (!checkType(value, schema.type)) {
3980
4038
  errors.push({
3981
- path: path26 || "<root>",
4039
+ path: path28 || "<root>",
3982
4040
  message: `expected ${schema.type}, got ${describeType(value)}`
3983
4041
  });
3984
4042
  return;
@@ -3988,19 +4046,19 @@ function walk2(value, schema, path26, errors) {
3988
4046
  const obj = value;
3989
4047
  for (const req of schema.required ?? []) {
3990
4048
  if (!(req in obj)) {
3991
- errors.push({ path: joinPath(path26, req), message: "required property missing" });
4049
+ errors.push({ path: joinPath(path28, req), message: "required property missing" });
3992
4050
  }
3993
4051
  }
3994
4052
  if (schema.properties) {
3995
4053
  for (const [key, subSchema] of Object.entries(schema.properties)) {
3996
4054
  if (key in obj) {
3997
- walk2(obj[key], subSchema, joinPath(path26, key), errors);
4055
+ walk2(obj[key], subSchema, joinPath(path28, key), errors);
3998
4056
  }
3999
4057
  }
4000
4058
  }
4001
4059
  }
4002
4060
  if (schema.type === "array" && Array.isArray(value) && schema.items) {
4003
- value.forEach((item, i) => walk2(item, schema.items, `${path26}[${i}]`, errors));
4061
+ value.forEach((item, i) => walk2(item, schema.items, `${path28}[${i}]`, errors));
4004
4062
  }
4005
4063
  }
4006
4064
  function checkType(value, type) {
@@ -5321,9 +5379,7 @@ var RecoveryLock = class {
5321
5379
  hostname: this.hostname,
5322
5380
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
5323
5381
  };
5324
- const tmp = `${this.file}.tmp`;
5325
- await fsp2.writeFile(tmp, JSON.stringify(lock), { mode: 384 });
5326
- await fsp2.rename(tmp, this.file);
5382
+ await atomicWrite(this.file, JSON.stringify(lock), { mode: 384 });
5327
5383
  }
5328
5384
  /**
5329
5385
  * Release the lock. Idempotent — silently succeeds if the file is
@@ -6565,8 +6621,8 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
6565
6621
  try {
6566
6622
  await Promise.race([
6567
6623
  Promise.resolve(iter.return?.()),
6568
- new Promise((resolve6) => {
6569
- drainTimer = setTimeout(resolve6, 500);
6624
+ new Promise((resolve7) => {
6625
+ drainTimer = setTimeout(resolve7, 500);
6570
6626
  })
6571
6627
  ]);
6572
6628
  } finally {
@@ -6627,7 +6683,7 @@ async function runProviderWithRetry(opts) {
6627
6683
  description
6628
6684
  });
6629
6685
  }
6630
- await new Promise((resolve6, reject) => {
6686
+ await new Promise((resolve7, reject) => {
6631
6687
  let settled = false;
6632
6688
  const onAbort = () => {
6633
6689
  if (settled) return;
@@ -6640,7 +6696,7 @@ async function runProviderWithRetry(opts) {
6640
6696
  settled = true;
6641
6697
  clearTimeout(t2);
6642
6698
  signal.removeEventListener("abort", onAbort);
6643
- resolve6();
6699
+ resolve7();
6644
6700
  }, delay);
6645
6701
  if (signal.aborted) {
6646
6702
  onAbort();
@@ -7303,12 +7359,18 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
7303
7359
  failureMode;
7304
7360
  policyProvider;
7305
7361
  /**
7306
- * Overhead factor applied to the rough message-token estimate to produce a
7307
- * figure comparable to the real API request size (system prompt + tool defs).
7308
- * Without this factor, raw message tokens undercount real load by 15-50% in
7309
- * short conversations, causing premature compaction triggers.
7362
+ * Calibration factor applied to the estimator output. The estimator is now
7363
+ * expected to already include messages + system prompt + tool definitions
7364
+ * (see `estimateRequestTokens.total`), so no overhead boost is needed. Kept
7365
+ * as a constant so a future calibration against real provider tokenization
7366
+ * (BPE vs the chars/3.5 rough estimator) can dial this without touching the
7367
+ * threshold-check math.
7368
+ *
7369
+ * Historical note: was 1.3 when the estimator only counted messages — that
7370
+ * double-counted system+tools once the estimator was upgraded, firing
7371
+ * compaction ~30% earlier than intended (e.g. real 56% load showed as 73%).
7310
7372
  */
7311
- static OVERHEAD_FACTOR = 1.3;
7373
+ static OVERHEAD_FACTOR = 1;
7312
7374
  /**
7313
7375
  * Once a compaction attempt reduces nothing (preserveK protects everything,
7314
7376
  * no oversized tool_results remain to elide), retrying on every iteration
@@ -8255,8 +8317,8 @@ ${recentJournal}` : "No prior iterations.",
8255
8317
  await saveGoal(this.goalPath, abandoned);
8256
8318
  }
8257
8319
  try {
8258
- const { unlink: unlink10 } = await import('fs/promises');
8259
- await unlink10(this.goalPath);
8320
+ const { unlink: unlink12 } = await import('fs/promises');
8321
+ await unlink12(this.goalPath);
8260
8322
  } catch {
8261
8323
  }
8262
8324
  this.opts.onEternalStop?.();
@@ -8278,7 +8340,7 @@ ${recentJournal}` : "No prior iterations.",
8278
8340
  }
8279
8341
  };
8280
8342
  function sleep(ms) {
8281
- return new Promise((resolve6) => setTimeout(resolve6, ms));
8343
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
8282
8344
  }
8283
8345
 
8284
8346
  // src/coordination/subagent-budget.ts
@@ -8428,12 +8490,12 @@ var SubagentBudget = class _SubagentBudget {
8428
8490
  if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
8429
8491
  return Promise.resolve("stop");
8430
8492
  }
8431
- return new Promise((resolve6) => {
8493
+ return new Promise((resolve7) => {
8432
8494
  let resolved = false;
8433
8495
  const respond = (d) => {
8434
8496
  if (resolved) return;
8435
8497
  resolved = true;
8436
- resolve6(d);
8498
+ resolve7(d);
8437
8499
  };
8438
8500
  const fallback = setTimeout(
8439
8501
  () => respond("stop"),
@@ -11474,7 +11536,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
11474
11536
  taskIds.map((id) => {
11475
11537
  const cached = this.completedResults.find((r) => r.taskId === id);
11476
11538
  if (cached) return cached;
11477
- return new Promise((resolve6, reject) => {
11539
+ return new Promise((resolve7, reject) => {
11478
11540
  const timeout = setTimeout(() => {
11479
11541
  this.off("task.completed", handler);
11480
11542
  reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
@@ -11483,7 +11545,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
11483
11545
  if (result.taskId === id) {
11484
11546
  clearTimeout(timeout);
11485
11547
  this.off("task.completed", handler);
11486
- resolve6(result);
11548
+ resolve7(result);
11487
11549
  }
11488
11550
  };
11489
11551
  this.on("task.completed", handler);
@@ -11913,7 +11975,7 @@ function providerErrorToSubagentError(err, message, cause) {
11913
11975
 
11914
11976
  // src/execution/parallel-eternal-engine.ts
11915
11977
  function sleep2(ms) {
11916
- return new Promise((resolve6) => setTimeout(resolve6, ms));
11978
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
11917
11979
  }
11918
11980
  var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
11919
11981
  var ParallelEternalEngine = class {
@@ -12694,7 +12756,7 @@ function makeSpawnTool(director, roster) {
12694
12756
  catalog: roster
12695
12757
  });
12696
12758
  const dispatchRole = dispatchResult.role;
12697
- if (roster && roster[dispatchRole]) {
12759
+ if (roster?.[dispatchRole]) {
12698
12760
  cfg = instantiateRosterConfig(dispatchRole, roster[dispatchRole]);
12699
12761
  } else {
12700
12762
  const def = dispatchResult.definition;
@@ -13184,6 +13246,13 @@ var Director = class {
13184
13246
  extendCounts.delete(guardKey);
13185
13247
  return;
13186
13248
  }
13249
+ if (payload.kind === "cost" && this.maxFleetCostUsd < Number.POSITIVE_INFINITY) {
13250
+ const totalCost = this.usage.snapshot().total?.cost ?? 0;
13251
+ if (totalCost >= this.maxFleetCostUsd) {
13252
+ payload.deny();
13253
+ return;
13254
+ }
13255
+ }
13187
13256
  extendCounts.set(guardKey, prior + 1);
13188
13257
  setImmediate(() => {
13189
13258
  const extra = {};
@@ -13548,11 +13617,11 @@ var Director = class {
13548
13617
  if (cached) return cached;
13549
13618
  const existing = this.taskWaiters.get(id);
13550
13619
  if (existing) return existing.promise;
13551
- let resolve6;
13620
+ let resolve7;
13552
13621
  const promise = new Promise((res) => {
13553
- resolve6 = res;
13622
+ resolve7 = res;
13554
13623
  });
13555
- this.taskWaiters.set(id, { promise, resolve: resolve6 });
13624
+ this.taskWaiters.set(id, { promise, resolve: resolve7 });
13556
13625
  return promise;
13557
13626
  })
13558
13627
  );
@@ -13868,7 +13937,7 @@ function createDelegateTool(opts) {
13868
13937
  subagentId
13869
13938
  });
13870
13939
  const dir = director;
13871
- const result = await new Promise((resolve6) => {
13940
+ const result = await new Promise((resolve7) => {
13872
13941
  let settled = false;
13873
13942
  let timer;
13874
13943
  const finish = (value) => {
@@ -13877,7 +13946,7 @@ function createDelegateTool(opts) {
13877
13946
  if (timer) clearTimeout(timer);
13878
13947
  offTool();
13879
13948
  offIter();
13880
- resolve6(value);
13949
+ resolve7(value);
13881
13950
  };
13882
13951
  const arm = () => {
13883
13952
  if (timer) clearTimeout(timer);
@@ -14682,6 +14751,13 @@ var TaskTracker = class {
14682
14751
  opts;
14683
14752
  graph = null;
14684
14753
  transitions = [];
14754
+ /**
14755
+ * Attach an existing graph (used by PhaseOrchestrator to associate a tracker
14756
+ * with a phase's pre-built task graph without re-creating it).
14757
+ */
14758
+ setGraph(graph) {
14759
+ this.graph = graph;
14760
+ }
14685
14761
  async createGraph(specId, title) {
14686
14762
  this.graph = {
14687
14763
  id: crypto.randomUUID(),
@@ -14754,10 +14830,6 @@ var TaskTracker = class {
14754
14830
  this.graph.updatedAt = now;
14755
14831
  this.persist();
14756
14832
  }
14757
- /**
14758
- * Update node fields (title, description, priority, estimateHours, tags).
14759
- * Does NOT change status. Use updateNodeStatus for status changes.
14760
- */
14761
14833
  updateNode(id, patch) {
14762
14834
  if (!this.graph) throw new Error("No graph loaded");
14763
14835
  const node = this.graph.nodes.get(id);
@@ -14835,8 +14907,7 @@ var TaskTracker = class {
14835
14907
  }
14836
14908
  return computeTaskProgress(this.graph);
14837
14909
  }
14838
- getTransitions(taskId) {
14839
- if (!taskId) return [...this.transitions];
14910
+ getTransitions(_taskId) {
14840
14911
  return [...this.transitions];
14841
14912
  }
14842
14913
  unblockDependents(completedId) {
@@ -14876,18 +14947,12 @@ var TaskTracker = class {
14876
14947
  * Fire-and-forget persistence with attached error handler.
14877
14948
  * Synchronous mutators (addNode/addEdge/updateNodeStatus) use this to
14878
14949
  * avoid forcing an async cascade through every caller; if the store
14879
- * rejects, the configured `onPersistError` is invoked so failures are
14880
- * surfaced instead of swallowed by an unhandled promise rejection.
14950
+ * is missing or throwing, the error is surfaced via onPersistError.
14881
14951
  */
14882
14952
  persist() {
14883
14953
  if (!this.graph) return;
14884
14954
  this.opts.store.saveGraph(this.graph).catch((err) => {
14885
- if (this.opts.onPersistError) this.opts.onPersistError(err);
14886
- else
14887
- console.warn(
14888
- "[task-tracker] saveGraph failed:",
14889
- err instanceof Error ? err.message : String(err)
14890
- );
14955
+ this.opts.onPersistError ? this.opts.onPersistError(err) : console.warn("[task-tracker] saveGraph failed:", err instanceof Error ? err.message : String(err));
14891
14956
  });
14892
14957
  }
14893
14958
  };
@@ -15508,10 +15573,10 @@ var AISpecBuilder = class {
15508
15573
  async saveSession() {
15509
15574
  if (!this.sessionPath) return;
15510
15575
  try {
15511
- const fsp16 = await import('fs/promises');
15512
- const path26 = await import('path');
15576
+ const fsp18 = await import('fs/promises');
15577
+ const path28 = await import('path');
15513
15578
  const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
15514
- await fsp16.mkdir(path26.dirname(this.sessionPath), { recursive: true });
15579
+ await fsp18.mkdir(path28.dirname(this.sessionPath), { recursive: true });
15515
15580
  await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
15516
15581
  } catch {
15517
15582
  }
@@ -15520,8 +15585,8 @@ var AISpecBuilder = class {
15520
15585
  async loadSession() {
15521
15586
  if (!this.sessionPath) return false;
15522
15587
  try {
15523
- const fsp16 = await import('fs/promises');
15524
- const raw = await fsp16.readFile(this.sessionPath, "utf8");
15588
+ const fsp18 = await import('fs/promises');
15589
+ const raw = await fsp18.readFile(this.sessionPath, "utf8");
15525
15590
  const loaded = JSON.parse(raw);
15526
15591
  if (loaded?.id && loaded?.phase && loaded?.title) {
15527
15592
  this.session = loaded;
@@ -15535,8 +15600,8 @@ var AISpecBuilder = class {
15535
15600
  async deleteSession() {
15536
15601
  if (!this.sessionPath) return;
15537
15602
  try {
15538
- const fsp16 = await import('fs/promises');
15539
- await fsp16.unlink(this.sessionPath);
15603
+ const fsp18 = await import('fs/promises');
15604
+ await fsp18.unlink(this.sessionPath);
15540
15605
  } catch {
15541
15606
  }
15542
15607
  }
@@ -16221,15 +16286,15 @@ function computeCriticalPath(graph, topoOrder, blockedByMap) {
16221
16286
  maxId = id;
16222
16287
  }
16223
16288
  }
16224
- const path26 = [];
16289
+ const path28 = [];
16225
16290
  let current = maxId;
16226
16291
  const visited = /* @__PURE__ */ new Set();
16227
16292
  while (current && !visited.has(current)) {
16228
16293
  visited.add(current);
16229
- path26.unshift(current);
16294
+ path28.unshift(current);
16230
16295
  current = prev.get(current) ?? null;
16231
16296
  }
16232
- return path26;
16297
+ return path28;
16233
16298
  }
16234
16299
  function computeParallelGroups(graph, blockedByMap) {
16235
16300
  const groups = [];
@@ -17024,9 +17089,9 @@ var DefaultHealthRegistry = class {
17024
17089
  }
17025
17090
  async runOne(check) {
17026
17091
  let timer = null;
17027
- const timeout = new Promise((resolve6) => {
17092
+ const timeout = new Promise((resolve7) => {
17028
17093
  timer = setTimeout(
17029
- () => resolve6({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
17094
+ () => resolve7({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
17030
17095
  this.timeoutMs
17031
17096
  );
17032
17097
  });
@@ -17209,7 +17274,7 @@ async function startMetricsServer(opts) {
17209
17274
  const tls = opts.tls;
17210
17275
  const useHttps = !!(tls?.cert && tls?.key);
17211
17276
  const host = opts.host ?? "127.0.0.1";
17212
- const path26 = opts.path ?? "/metrics";
17277
+ const path28 = opts.path ?? "/metrics";
17213
17278
  const healthPath = opts.healthPath ?? "/healthz";
17214
17279
  const healthRegistry = opts.healthRegistry;
17215
17280
  const listener = (req, res) => {
@@ -17219,7 +17284,7 @@ async function startMetricsServer(opts) {
17219
17284
  return;
17220
17285
  }
17221
17286
  const url = req.url.split("?")[0];
17222
- if (url === path26) {
17287
+ if (url === path28) {
17223
17288
  let body;
17224
17289
  try {
17225
17290
  body = renderPrometheus(opts.sink.snapshot());
@@ -17265,14 +17330,14 @@ async function startMetricsServer(opts) {
17265
17330
  const { createServer } = await import('http');
17266
17331
  server = createServer(listener);
17267
17332
  }
17268
- await new Promise((resolve6, reject) => {
17333
+ await new Promise((resolve7, reject) => {
17269
17334
  const onError = (err) => {
17270
17335
  server.off("listening", onListening);
17271
17336
  reject(err);
17272
17337
  };
17273
17338
  const onListening = () => {
17274
17339
  server.off("error", onError);
17275
- resolve6();
17340
+ resolve7();
17276
17341
  };
17277
17342
  server.once("error", onError);
17278
17343
  server.once("listening", onListening);
@@ -17283,9 +17348,9 @@ async function startMetricsServer(opts) {
17283
17348
  const protocol = useHttps ? "https" : "http";
17284
17349
  return {
17285
17350
  port: boundPort,
17286
- url: `${protocol}://${host}:${boundPort}${path26}`,
17287
- close: () => new Promise((resolve6, reject) => {
17288
- server.close((err) => err ? reject(err) : resolve6());
17351
+ url: `${protocol}://${host}:${boundPort}${path28}`,
17352
+ close: () => new Promise((resolve7, reject) => {
17353
+ server.close((err) => err ? reject(err) : resolve7());
17289
17354
  })
17290
17355
  };
17291
17356
  }
@@ -17984,6 +18049,12 @@ async function extractTar(buf, destDir) {
17984
18049
  const relPath = stripTopDir(fullPath);
17985
18050
  if (relPath && relPath !== "." && relPath !== "..") {
17986
18051
  const destPath = path6.join(destDir, relPath);
18052
+ const resolvedDest = path6.resolve(destPath);
18053
+ const resolvedRoot = path6.resolve(destDir);
18054
+ if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path6.sep)) {
18055
+ offset += 512 + Math.ceil(size / 512) * 512;
18056
+ continue;
18057
+ }
17987
18058
  if (typeflag === 53 || typeflag === 0) {
17988
18059
  if (relPath.endsWith("/") || typeflag === 53) {
17989
18060
  await fsp2.mkdir(destPath, { recursive: true });
@@ -19403,8 +19474,8 @@ var ReportGenerator = class {
19403
19474
  try {
19404
19475
  await stat(this.options.outputDir);
19405
19476
  } catch {
19406
- const { mkdir: mkdir11 } = await import('fs/promises');
19407
- await mkdir11(this.options.outputDir, { recursive: true });
19477
+ const { mkdir: mkdir13 } = await import('fs/promises');
19478
+ await mkdir13(this.options.outputDir, { recursive: true });
19408
19479
  }
19409
19480
  }
19410
19481
  generateMarkdown(result) {
@@ -19680,7 +19751,7 @@ var SecurityScannerOrchestrator = class {
19680
19751
  const delay = Math.round(policy.delayMs(attempt));
19681
19752
  const status = isProviderErr ? err.status : 0;
19682
19753
  console.warn(`[SecurityScanner] retry ${attempt + 1} after ${delay}ms (status=${status}) \u2014 ${errAsErr.message}`);
19683
- await new Promise((resolve6) => setTimeout(resolve6, delay));
19754
+ await new Promise((resolve7) => setTimeout(resolve7, delay));
19684
19755
  return this.completeWithRetry(provider, request, abortController, attempt + 1);
19685
19756
  }
19686
19757
  }
@@ -20326,16 +20397,16 @@ Use \`/security report <number>\` to view a specific report.` };
20326
20397
  }
20327
20398
  const index = Number.parseInt(reportId, 10) - 1;
20328
20399
  if (!Number.isNaN(index) && reports[index]) {
20329
- const { readFile: readFile30 } = await import('fs/promises');
20330
- const content = await readFile30(join(reportsDir, reports[index]), "utf-8");
20400
+ const { readFile: readFile32 } = await import('fs/promises');
20401
+ const content = await readFile32(join(reportsDir, reports[index]), "utf-8");
20331
20402
  return { message: `# Security Report
20332
20403
 
20333
20404
  ${content}` };
20334
20405
  }
20335
20406
  const match = reports.find((r) => r.includes(reportId));
20336
20407
  if (match) {
20337
- const { readFile: readFile30 } = await import('fs/promises');
20338
- const content = await readFile30(join(reportsDir, match), "utf-8");
20408
+ const { readFile: readFile32 } = await import('fs/promises');
20409
+ const content = await readFile32(join(reportsDir, match), "utf-8");
20339
20410
  return { message: `# Security Report
20340
20411
 
20341
20412
  ${content}` };
@@ -21177,12 +21248,12 @@ function makeContinueToNextIterationTool() {
21177
21248
  // src/core/iteration-limit.ts
21178
21249
  function requestLimitExtension(opts) {
21179
21250
  const { events, currentIterations, currentLimit, autoExtend, timeoutMs = 3e4 } = opts;
21180
- return new Promise((resolve6) => {
21251
+ return new Promise((resolve7) => {
21181
21252
  let resolved = false;
21182
21253
  const timerFired = () => {
21183
21254
  if (!resolved) {
21184
21255
  resolved = true;
21185
- resolve6(0);
21256
+ resolve7(0);
21186
21257
  }
21187
21258
  };
21188
21259
  const timer = setTimeout(timerFired, timeoutMs);
@@ -21191,14 +21262,14 @@ function requestLimitExtension(opts) {
21191
21262
  if (!resolved) {
21192
21263
  resolved = true;
21193
21264
  clearTimeout(timer);
21194
- resolve6(0);
21265
+ resolve7(0);
21195
21266
  }
21196
21267
  };
21197
21268
  const grant = (extra) => {
21198
21269
  if (!resolved) {
21199
21270
  resolved = true;
21200
21271
  clearTimeout(timer);
21201
- resolve6(Math.max(0, extra));
21272
+ resolve7(Math.max(0, extra));
21202
21273
  }
21203
21274
  };
21204
21275
  events.emit("iteration.limit_reached", {
@@ -21212,7 +21283,7 @@ function requestLimitExtension(opts) {
21212
21283
  if (!resolved) {
21213
21284
  resolved = true;
21214
21285
  clearTimeout(timer);
21215
- resolve6(100);
21286
+ resolve7(100);
21216
21287
  }
21217
21288
  });
21218
21289
  }
@@ -21781,13 +21852,13 @@ var Agent = class {
21781
21852
  }
21782
21853
  }
21783
21854
  waitForConfirm(info) {
21784
- return new Promise((resolve6) => {
21855
+ return new Promise((resolve7) => {
21785
21856
  this.events.emit("tool.confirm_needed", {
21786
21857
  tool: info.tool,
21787
21858
  input: info.input,
21788
21859
  toolUseId: info.toolUseId,
21789
21860
  suggestedPattern: info.suggestedPattern,
21790
- resolve: resolve6
21861
+ resolve: resolve7
21791
21862
  });
21792
21863
  });
21793
21864
  }
@@ -22504,12 +22575,12 @@ ${mem}`);
22504
22575
  }
22505
22576
  }
22506
22577
  async gitStatus(root) {
22507
- return new Promise((resolve6) => {
22578
+ return new Promise((resolve7) => {
22508
22579
  let settled = false;
22509
22580
  const finish = (s) => {
22510
22581
  if (settled) return;
22511
22582
  settled = true;
22512
- resolve6(s);
22583
+ resolve7(s);
22513
22584
  };
22514
22585
  let proc;
22515
22586
  const timer = setTimeout(() => {
@@ -23261,6 +23332,1174 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
23261
23332
  });
23262
23333
  }
23263
23334
 
23264
- 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 };
23335
+ // src/autophase/phase-graph-builder.ts
23336
+ var PhaseGraphBuilder = class _PhaseGraphBuilder {
23337
+ constructor(opts) {
23338
+ this.opts = opts;
23339
+ }
23340
+ opts;
23341
+ async build() {
23342
+ const graphId = crypto.randomUUID();
23343
+ const phases = /* @__PURE__ */ new Map();
23344
+ const phaseIds = [];
23345
+ for (let i = 0; i < this.opts.phases.length; i++) {
23346
+ const tmpl = this.opts.phases[i];
23347
+ const phaseId = crypto.randomUUID();
23348
+ phaseIds.push(phaseId);
23349
+ const store = this.opts.externalTaskStore ?? new DefaultTaskStore();
23350
+ const tracker = new TaskTracker({ store });
23351
+ const taskGraph = await tracker.createGraph(phaseId, `${tmpl.name} Tasks`);
23352
+ if (tmpl.taskTemplates && tmpl.taskTemplates.length > 0) {
23353
+ for (const tt of tmpl.taskTemplates) {
23354
+ tracker.addNode({
23355
+ title: tt.title,
23356
+ description: tt.description,
23357
+ type: tt.type,
23358
+ priority: tt.priority,
23359
+ status: "pending",
23360
+ estimateHours: tt.estimateHours,
23361
+ tags: tt.tags ?? []
23362
+ });
23363
+ }
23364
+ }
23365
+ const phase = {
23366
+ id: phaseId,
23367
+ name: tmpl.name,
23368
+ description: tmpl.description,
23369
+ status: "pending",
23370
+ taskGraph,
23371
+ dependsOn: i > 0 ? [phaseIds[i - 1]] : [],
23372
+ nextPhases: i < this.opts.phases.length - 1 ? [phaseIds[i + 1]] : [],
23373
+ parallelizable: tmpl.parallelizable,
23374
+ priority: tmpl.priority,
23375
+ estimateHours: tmpl.estimateHours,
23376
+ assignedAgents: [],
23377
+ createdAt: Date.now(),
23378
+ updatedAt: Date.now()
23379
+ };
23380
+ phases.set(phaseId, phase);
23381
+ }
23382
+ const phaseArray = Array.from(phases.values());
23383
+ for (let i = 0; i < phaseArray.length; i++) {
23384
+ const phase = phaseArray[i];
23385
+ phase.nextPhases = i < phaseArray.length - 1 ? [phaseArray[i + 1].id] : [];
23386
+ phase.dependsOn = i > 0 ? [phaseArray[i - 1].id] : [];
23387
+ }
23388
+ const graph = {
23389
+ id: graphId,
23390
+ title: this.opts.title,
23391
+ description: this.opts.description ?? "",
23392
+ phases,
23393
+ rootPhaseIds: phaseIds.length > 0 ? [phaseIds[0]] : [],
23394
+ activePhaseIds: [],
23395
+ completedPhaseIds: [],
23396
+ failedPhaseIds: [],
23397
+ autonomous: this.opts.autonomous ?? true,
23398
+ stopOnComplete: true,
23399
+ createdAt: Date.now(),
23400
+ updatedAt: Date.now()
23401
+ };
23402
+ return graph;
23403
+ }
23404
+ /**
23405
+ * Var olan bir TaskGraph'tan fazlar oluştur.
23406
+ * Task'ları priority/type göre gruplayarak fazlara ayırır.
23407
+ */
23408
+ static fromTaskGraph(taskGraph, options) {
23409
+ const tasksPerPhase = options.tasksPerPhase ?? 5;
23410
+ const nodes = Array.from(taskGraph.nodes.values());
23411
+ const sorted = [...nodes].sort((a, b) => {
23412
+ const prioOrder = { critical: 0, high: 1, medium: 2, low: 3 };
23413
+ return (prioOrder[a.priority] ?? 4) - (prioOrder[b.priority] ?? 4);
23414
+ });
23415
+ const groups = [];
23416
+ for (let i = 0; i < sorted.length; i += tasksPerPhase) {
23417
+ groups.push(sorted.slice(i, i + tasksPerPhase));
23418
+ }
23419
+ const phaseTemplates = groups.map((group, idx) => {
23420
+ const hasCritical = group.some((t2) => t2.priority === "critical");
23421
+ const totalHours = group.reduce((sum, t2) => sum + (t2.estimateHours ?? 2), 0);
23422
+ return {
23423
+ name: `Phase ${idx + 1}: ${group[0]?.title.slice(0, 30) ?? "Tasks"}`,
23424
+ description: group.map((t2) => t2.title).join(", "),
23425
+ priority: hasCritical ? "critical" : "high",
23426
+ estimateHours: totalHours,
23427
+ parallelizable: false,
23428
+ taskTemplates: group.map((t2) => ({
23429
+ title: t2.title,
23430
+ description: t2.description,
23431
+ type: t2.type,
23432
+ priority: t2.priority,
23433
+ estimateHours: t2.estimateHours ?? 2,
23434
+ tags: t2.tags ?? []
23435
+ }))
23436
+ };
23437
+ });
23438
+ const builder = new _PhaseGraphBuilder({
23439
+ ...options,
23440
+ phases: phaseTemplates
23441
+ });
23442
+ return builder.build();
23443
+ }
23444
+ };
23445
+
23446
+ // src/autophase/phase-orchestrator.ts
23447
+ var PhaseOrchestrator = class {
23448
+ graph;
23449
+ ctx;
23450
+ opts;
23451
+ events;
23452
+ stopped = false;
23453
+ paused = false;
23454
+ runningPhases = /* @__PURE__ */ new Set();
23455
+ tickInterval = null;
23456
+ trackerCache = /* @__PURE__ */ new Map();
23457
+ taskRetryCounts = /* @__PURE__ */ new Map();
23458
+ constructor(opts) {
23459
+ this.graph = opts.graph;
23460
+ this.ctx = opts.ctx;
23461
+ this.events = opts.events ?? this.createNoopEventBus();
23462
+ this.opts = {
23463
+ maxConcurrentPhases: opts.maxConcurrentPhases ?? 1,
23464
+ maxConcurrentTasks: opts.maxConcurrentTasks ?? 2,
23465
+ maxRetries: opts.maxRetries ?? 2,
23466
+ autonomous: opts.autonomous ?? true,
23467
+ phaseDelayMs: opts.phaseDelayMs ?? 0,
23468
+ stopOnFailure: opts.stopOnFailure ?? true,
23469
+ events: this.events
23470
+ };
23471
+ }
23472
+ // ─── Lifecycle ────────────────────────────────────────────────────────────
23473
+ /**
23474
+ * Tüm faz akışını başlat.
23475
+ * Autonomous mode'da: kök faz(lar)ı başlatır, bitince sonrakini otomatik başlatır.
23476
+ */
23477
+ async start() {
23478
+ this.stopped = false;
23479
+ this.paused = false;
23480
+ this.graph.startedAt = Date.now();
23481
+ this.graph.updatedAt = Date.now();
23482
+ let readyPhases = this.getReadyPhases();
23483
+ while (readyPhases.length > 0 && !this.stopped) {
23484
+ const batch = readyPhases.slice(0, this.opts.maxConcurrentPhases);
23485
+ await Promise.all(batch.map((p) => this.startPhase(p)));
23486
+ if (this.opts.phaseDelayMs > 0) {
23487
+ await this.delay(this.opts.phaseDelayMs);
23488
+ }
23489
+ readyPhases = this.getReadyPhases().filter(
23490
+ (p) => !this.runningPhases.has(p.id) && p.status !== "completed" && p.status !== "failed"
23491
+ );
23492
+ }
23493
+ if (this.opts.autonomous) {
23494
+ this.tickInterval = setInterval(() => this.tick(), 1e3);
23495
+ }
23496
+ }
23497
+ /** Duraklat — aktif fazlar çalışmaya devam eder ama yeni faz başlamaz */
23498
+ pause() {
23499
+ this.paused = true;
23500
+ }
23501
+ /** Devam et — yeni fazlar başlayabilir */
23502
+ resume() {
23503
+ this.paused = false;
23504
+ this.tick().catch((err) => {
23505
+ console.error("[phase-orchestrator] tick failed:", err instanceof Error ? err.message : String(err));
23506
+ });
23507
+ }
23508
+ /** Tamamen durdur — aktif fazlar da durdurulur */
23509
+ stop() {
23510
+ this.stopped = true;
23511
+ if (this.tickInterval) {
23512
+ clearInterval(this.tickInterval);
23513
+ this.tickInterval = null;
23514
+ }
23515
+ for (const phaseId of this.runningPhases) {
23516
+ const phase = this.graph.phases.get(phaseId);
23517
+ if (phase) {
23518
+ this.updatePhaseStatus(phase, "paused");
23519
+ }
23520
+ }
23521
+ }
23522
+ // ─── Tick Loop (Autonomous) ───────────────────────────────────────────────
23523
+ async tick() {
23524
+ if (this.stopped || this.paused) return;
23525
+ const active = this.getActivePhases();
23526
+ const queued = this.getReadyPhases();
23527
+ this.emit("autonomous.tick", {
23528
+ activePhases: active.map((p) => p.id),
23529
+ queuedPhases: queued.map((p) => p.id)
23530
+ });
23531
+ this.ctx.onTick?.({ activePhases: active, readyPhases: queued });
23532
+ const availableSlots = this.opts.maxConcurrentPhases - active.length;
23533
+ if (availableSlots > 0 && queued.length > 0) {
23534
+ for (const phase of queued.slice(0, availableSlots)) {
23535
+ if (phase.status === "pending") {
23536
+ await this.startPhase(phase);
23537
+ }
23538
+ }
23539
+ }
23540
+ if (this.isComplete()) {
23541
+ this.onGraphComplete();
23542
+ return;
23543
+ }
23544
+ if (this.opts.stopOnFailure && this.graph.failedPhaseIds.length > 0) {
23545
+ const failedPhase = this.graph.phases.get(this.graph.failedPhaseIds[0]);
23546
+ if (failedPhase) {
23547
+ this.onGraphFailed(failedPhase);
23548
+ }
23549
+ return;
23550
+ }
23551
+ }
23552
+ // ─── Phase Execution ──────────────────────────────────────────────────────
23553
+ async startPhase(phase) {
23554
+ if (phase.status !== "pending" && phase.status !== "ready") return;
23555
+ this.updatePhaseStatus(phase, "running");
23556
+ phase.startedAt = Date.now();
23557
+ this.runningPhases.add(phase.id);
23558
+ this.graph.activePhaseIds.push(phase.id);
23559
+ this.emit("phase.started", { phaseId: phase.id, name: phase.name });
23560
+ try {
23561
+ await this.executePhaseTasks(phase);
23562
+ const failedTasks = this.getFailedTaskCount(phase);
23563
+ const completedTasks = this.getCompletedTaskCount(phase);
23564
+ this.emit("phase.allTasksDone", {
23565
+ phaseId: phase.id,
23566
+ completed: completedTasks,
23567
+ failed: failedTasks
23568
+ });
23569
+ if (failedTasks > 0 && this.opts.stopOnFailure) {
23570
+ this.updatePhaseStatus(phase, "failed");
23571
+ phase.completedAt = Date.now();
23572
+ phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23573
+ this.runningPhases.delete(phase.id);
23574
+ this.graph.activePhaseIds = this.graph.activePhaseIds.filter((id) => id !== phase.id);
23575
+ this.emit("phase.failed", {
23576
+ phaseId: phase.id,
23577
+ name: phase.name,
23578
+ error: `${failedTasks} task(s) failed`
23579
+ });
23580
+ this.ctx.onPhaseFail?.(phase, new Error(`${failedTasks} task(s) failed`));
23581
+ } else {
23582
+ this.updatePhaseStatus(phase, "completed");
23583
+ phase.completedAt = Date.now();
23584
+ phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23585
+ this.runningPhases.delete(phase.id);
23586
+ this.graph.activePhaseIds = this.graph.activePhaseIds.filter((id) => id !== phase.id);
23587
+ this.graph.completedPhaseIds.push(phase.id);
23588
+ this.emit("phase.completed", {
23589
+ phaseId: phase.id,
23590
+ name: phase.name,
23591
+ durationMs: phase.actualDurationMs
23592
+ });
23593
+ this.ctx.onPhaseComplete?.(phase);
23594
+ }
23595
+ } catch (error) {
23596
+ this.updatePhaseStatus(phase, "failed");
23597
+ phase.completedAt = Date.now();
23598
+ phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23599
+ this.runningPhases.delete(phase.id);
23600
+ this.graph.activePhaseIds = this.graph.activePhaseIds.filter((id) => id !== phase.id);
23601
+ this.graph.failedPhaseIds.push(phase.id);
23602
+ this.emit("phase.failed", {
23603
+ phaseId: phase.id,
23604
+ name: phase.name,
23605
+ error: error instanceof Error ? error.message : String(error)
23606
+ });
23607
+ this.ctx.onPhaseFail?.(phase, error instanceof Error ? error : new Error(String(error)));
23608
+ }
23609
+ }
23610
+ async executePhaseTasks(phase) {
23611
+ const pendingTasks = this.getExecutableTasks(phase);
23612
+ while (pendingTasks.length > 0 && !this.stopped) {
23613
+ const batch = pendingTasks.splice(0, this.opts.maxConcurrentTasks);
23614
+ const results = await Promise.allSettled(
23615
+ batch.map((task) => this.executeSingleTask(task, phase))
23616
+ );
23617
+ for (let i = 0; i < results.length; i++) {
23618
+ const result = results[i];
23619
+ const task = batch[i];
23620
+ if (!result || !task) continue;
23621
+ if (result.status === "fulfilled") {
23622
+ this.markTaskCompleted(phase, task);
23623
+ } else {
23624
+ this.markTaskFailed(phase, task, result.reason);
23625
+ }
23626
+ }
23627
+ const newReady = this.getExecutableTasks(phase);
23628
+ pendingTasks.length = 0;
23629
+ pendingTasks.push(...newReady);
23630
+ }
23631
+ }
23632
+ async executeSingleTask(task, phase) {
23633
+ const tracker = this.getTrackerForPhase(phase);
23634
+ tracker.updateNodeStatus(task.id, "in_progress");
23635
+ return this.ctx.executeTask(task, phase.id);
23636
+ }
23637
+ markTaskCompleted(phase, task) {
23638
+ const tracker = this.getTrackerForPhase(phase);
23639
+ tracker.updateNodeStatus(task.id, "completed");
23640
+ this.emit("phase.taskCompleted", {
23641
+ phaseId: phase.id,
23642
+ taskId: task.id,
23643
+ taskTitle: task.title
23644
+ });
23645
+ }
23646
+ markTaskFailed(phase, task, error) {
23647
+ const tracker = this.getTrackerForPhase(phase);
23648
+ const taskKey = `${phase.id}:${task.id}`;
23649
+ const currentRetries = this.taskRetryCounts.get(taskKey) ?? 0;
23650
+ if (currentRetries < this.opts.maxRetries) {
23651
+ this.taskRetryCounts.set(taskKey, currentRetries + 1);
23652
+ tracker.updateNodeStatus(task.id, "pending", `Retry ${currentRetries + 1}/${this.opts.maxRetries}`);
23653
+ this.emit("phase.taskRetrying", {
23654
+ phaseId: phase.id,
23655
+ taskId: task.id,
23656
+ taskTitle: task.title,
23657
+ attempt: currentRetries + 1,
23658
+ maxRetries: this.opts.maxRetries
23659
+ });
23660
+ } else {
23661
+ tracker.updateNodeStatus(task.id, "failed", error instanceof Error ? error.message : String(error));
23662
+ this.emit("phase.taskFailed", {
23663
+ phaseId: phase.id,
23664
+ taskId: task.id,
23665
+ taskTitle: task.title,
23666
+ error: error instanceof Error ? error.message : String(error)
23667
+ });
23668
+ }
23669
+ }
23670
+ // ─── Helpers ──────────────────────────────────────────────────────────────
23671
+ getReadyPhases() {
23672
+ const ready = [];
23673
+ for (const phase of this.graph.phases.values()) {
23674
+ if (phase.status !== "pending") continue;
23675
+ const depsDone = phase.dependsOn.every((depId) => {
23676
+ const dep = this.graph.phases.get(depId);
23677
+ return dep?.status === "completed" || dep?.status === "skipped";
23678
+ });
23679
+ if (depsDone || phase.parallelizable) {
23680
+ ready.push(phase);
23681
+ }
23682
+ }
23683
+ const prioOrder = { critical: 0, high: 1, medium: 2, low: 3 };
23684
+ ready.sort((a, b) => (prioOrder[a.priority] ?? 4) - (prioOrder[b.priority] ?? 4));
23685
+ return ready;
23686
+ }
23687
+ getActivePhases() {
23688
+ return Array.from(this.graph.phases.values()).filter((p) => p.status === "running");
23689
+ }
23690
+ getExecutableTasks(phase) {
23691
+ const tracker = this.getTrackerForPhase(phase);
23692
+ return tracker.getAllNodes({ status: ["pending", "blocked"] }).filter((n) => n.status === "pending" && tracker.canStart(n.id)).sort((a, b) => {
23693
+ const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
23694
+ return (priorityOrder[a.priority] ?? 4) - (priorityOrder[b.priority] ?? 4);
23695
+ });
23696
+ }
23697
+ getTrackerForPhase(phase) {
23698
+ if (this.trackerCache.has(phase.id)) {
23699
+ return this.trackerCache.get(phase.id);
23700
+ }
23701
+ const store = new DefaultTaskStore();
23702
+ const tracker = new TaskTracker({ store });
23703
+ tracker.setGraph(phase.taskGraph);
23704
+ this.trackerCache.set(phase.id, tracker);
23705
+ return tracker;
23706
+ }
23707
+ getFailedTaskCount(phase) {
23708
+ return this.getTrackerForPhase(phase).getAllNodes({ status: ["failed"] }).length;
23709
+ }
23710
+ getCompletedTaskCount(phase) {
23711
+ return this.getTrackerForPhase(phase).getAllNodes({ status: ["completed"] }).length;
23712
+ }
23713
+ updatePhaseStatus(phase, status) {
23714
+ const from = phase.status;
23715
+ phase.status = status;
23716
+ phase.updatedAt = Date.now();
23717
+ this.graph.updatedAt = Date.now();
23718
+ this.emit("phase.statusChange", { phaseId: phase.id, from, to: status });
23719
+ }
23720
+ isComplete() {
23721
+ const allPhases = Array.from(this.graph.phases.values());
23722
+ return allPhases.every(
23723
+ (p) => p.status === "completed" || p.status === "skipped" || p.status === "failed"
23724
+ );
23725
+ }
23726
+ onGraphComplete() {
23727
+ this.graph.completedAt = Date.now();
23728
+ const durationMs = this.graph.completedAt - (this.graph.startedAt ?? this.graph.completedAt);
23729
+ this.emit("graph.completed", { graphId: this.graph.id, durationMs });
23730
+ this.stop();
23731
+ }
23732
+ onGraphFailed(failedPhase) {
23733
+ this.emit("graph.failed", {
23734
+ graphId: this.graph.id,
23735
+ failedPhaseId: failedPhase.id,
23736
+ error: `Phase "${failedPhase.name}" failed`
23737
+ });
23738
+ this.stop();
23739
+ }
23740
+ // ─── Progress ─────────────────────────────────────────────────────────────
23741
+ getProgress() {
23742
+ const phases = Array.from(this.graph.phases.values());
23743
+ let pending = 0;
23744
+ let ready = 0;
23745
+ let running = 0;
23746
+ let paused = 0;
23747
+ let completed = 0;
23748
+ let failed = 0;
23749
+ let skipped = 0;
23750
+ let totalTasks = 0;
23751
+ let completedTasks = 0;
23752
+ let failedTasks = 0;
23753
+ let estimatedHours = 0;
23754
+ let actualHours = 0;
23755
+ for (const p of phases) {
23756
+ switch (p.status) {
23757
+ case "pending":
23758
+ pending++;
23759
+ break;
23760
+ case "ready":
23761
+ ready++;
23762
+ break;
23763
+ case "running":
23764
+ running++;
23765
+ break;
23766
+ case "paused":
23767
+ paused++;
23768
+ break;
23769
+ case "completed":
23770
+ completed++;
23771
+ break;
23772
+ case "failed":
23773
+ failed++;
23774
+ break;
23775
+ case "skipped":
23776
+ skipped++;
23777
+ break;
23778
+ }
23779
+ estimatedHours += p.estimateHours;
23780
+ if (p.actualDurationMs) actualHours += p.actualDurationMs / 36e5;
23781
+ const tracker = this.getTrackerForPhase(p);
23782
+ const progress = tracker.getProgress();
23783
+ totalTasks += progress.total;
23784
+ completedTasks += progress.completed;
23785
+ failedTasks += progress.failed;
23786
+ }
23787
+ const totalPhases = phases.length;
23788
+ const done = completed + skipped;
23789
+ return {
23790
+ totalPhases,
23791
+ pending,
23792
+ ready,
23793
+ running,
23794
+ paused,
23795
+ completed,
23796
+ failed,
23797
+ skipped,
23798
+ percentComplete: totalPhases > 0 ? Math.round(done / totalPhases * 100) : 0,
23799
+ totalTasks,
23800
+ completedTasks,
23801
+ failedTasks,
23802
+ estimatedHours,
23803
+ actualHours
23804
+ };
23805
+ }
23806
+ getGraph() {
23807
+ return this.graph;
23808
+ }
23809
+ isRunning() {
23810
+ return !this.stopped && this.runningPhases.size > 0;
23811
+ }
23812
+ isPaused() {
23813
+ return this.paused;
23814
+ }
23815
+ // ─── Agent Assignment ─────────────────────────────────────────────────────
23816
+ assignAgent(phaseId, agentId) {
23817
+ const phase = this.graph.phases.get(phaseId);
23818
+ if (!phase) return;
23819
+ if (!phase.assignedAgents.includes(agentId)) {
23820
+ phase.assignedAgents.push(agentId);
23821
+ this.emit("agent.assigned", { phaseId, agentId });
23822
+ }
23823
+ }
23824
+ releaseAgent(phaseId, agentId) {
23825
+ const phase = this.graph.phases.get(phaseId);
23826
+ if (!phase) return;
23827
+ phase.assignedAgents = phase.assignedAgents.filter((id) => id !== agentId);
23828
+ this.emit("agent.released", { phaseId, agentId });
23829
+ }
23830
+ // ─── Events ───────────────────────────────────────────────────────────────
23831
+ emit(event, payload) {
23832
+ this.events.emit(event, payload);
23833
+ }
23834
+ createNoopEventBus() {
23835
+ return {
23836
+ emit: () => {
23837
+ },
23838
+ on: () => {
23839
+ },
23840
+ off: () => {
23841
+ },
23842
+ once: () => {
23843
+ },
23844
+ listeners: /* @__PURE__ */ new Map(),
23845
+ wildcards: /* @__PURE__ */ new Set(),
23846
+ setLogger: () => {
23847
+ },
23848
+ onAny: () => {
23849
+ },
23850
+ offAny: () => {
23851
+ },
23852
+ emitAsync: async () => [],
23853
+ waitFor: async () => {
23854
+ }
23855
+ };
23856
+ }
23857
+ delay(ms) {
23858
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
23859
+ }
23860
+ };
23861
+
23862
+ // src/autophase/auto-phase-runner.ts
23863
+ var AutoPhaseRunner = class {
23864
+ graph = null;
23865
+ orchestrator = null;
23866
+ opts;
23867
+ progressInterval = null;
23868
+ graphCompletedHandler = (payload) => {
23869
+ const p = payload;
23870
+ if (this.graph && p.graphId === this.graph.id) {
23871
+ this.opts.onComplete?.(this.graph);
23872
+ this.cleanup();
23873
+ }
23874
+ };
23875
+ graphFailedHandler = (payload) => {
23876
+ const p = payload;
23877
+ if (this.graph && p.graphId === this.graph.id) {
23878
+ const failedPhase = this.graph.phases.get(p.failedPhaseId);
23879
+ if (failedPhase) {
23880
+ this.opts.onFail?.(this.graph, failedPhase, new Error(p.error));
23881
+ }
23882
+ this.cleanup();
23883
+ }
23884
+ };
23885
+ /** Stores the unsubscribe function returned by EventBus.on() */
23886
+ unsubscribeCompleted = null;
23887
+ unsubscribeFailed = null;
23888
+ constructor(opts) {
23889
+ this.opts = opts;
23890
+ }
23891
+ async start() {
23892
+ const builder = new PhaseGraphBuilder({
23893
+ title: this.opts.title,
23894
+ description: this.opts.description,
23895
+ phases: this.opts.phases,
23896
+ autonomous: this.opts.autonomous,
23897
+ stopOnFailure: this.opts.stopOnFailure
23898
+ });
23899
+ this.graph = await builder.build();
23900
+ const ctx = {
23901
+ executeTask: this.opts.executeTask,
23902
+ onPhaseComplete: (phase) => {
23903
+ this.opts.onPhaseComplete?.(phase);
23904
+ },
23905
+ onPhaseFail: (phase, error) => {
23906
+ this.opts.onPhaseFail?.(phase, error);
23907
+ },
23908
+ onTick: (tickCtx) => {
23909
+ this.opts.onTick?.(tickCtx);
23910
+ }
23911
+ };
23912
+ this.orchestrator = new PhaseOrchestrator({
23913
+ graph: this.graph,
23914
+ ctx,
23915
+ maxConcurrentPhases: this.opts.maxConcurrentPhases,
23916
+ maxConcurrentTasks: this.opts.maxConcurrentTasks,
23917
+ maxRetries: this.opts.maxRetries,
23918
+ autonomous: this.opts.autonomous,
23919
+ phaseDelayMs: this.opts.phaseDelayMs,
23920
+ stopOnFailure: this.opts.stopOnFailure,
23921
+ events: this.opts.events
23922
+ });
23923
+ if (this.opts.onProgress) {
23924
+ this.progressInterval = setInterval(() => {
23925
+ const progress = this.orchestrator.getProgress();
23926
+ this.opts.onProgress(progress);
23927
+ }, 2e3);
23928
+ }
23929
+ if (this.opts.events) {
23930
+ const events = this.opts.events;
23931
+ const onUntyped = events.on;
23932
+ this.unsubscribeCompleted = onUntyped("graph.completed", this.graphCompletedHandler);
23933
+ this.unsubscribeFailed = onUntyped("graph.failed", this.graphFailedHandler);
23934
+ }
23935
+ await this.orchestrator.start();
23936
+ return this.graph;
23937
+ }
23938
+ pause() {
23939
+ this.orchestrator?.pause();
23940
+ }
23941
+ resume() {
23942
+ this.orchestrator?.resume();
23943
+ }
23944
+ stop() {
23945
+ this.orchestrator?.stop();
23946
+ this.cleanup();
23947
+ }
23948
+ getProgress() {
23949
+ return this.orchestrator?.getProgress() ?? null;
23950
+ }
23951
+ getGraph() {
23952
+ return this.graph;
23953
+ }
23954
+ isRunning() {
23955
+ return this.orchestrator?.isRunning() ?? false;
23956
+ }
23957
+ isPaused() {
23958
+ return this.orchestrator?.isPaused() ?? false;
23959
+ }
23960
+ assignAgent(phaseId, agentId) {
23961
+ this.orchestrator?.assignAgent(phaseId, agentId);
23962
+ }
23963
+ releaseAgent(phaseId, agentId) {
23964
+ this.orchestrator?.releaseAgent(phaseId, agentId);
23965
+ }
23966
+ cleanup() {
23967
+ if (this.progressInterval) {
23968
+ clearInterval(this.progressInterval);
23969
+ this.progressInterval = null;
23970
+ }
23971
+ this.unsubscribeCompleted?.();
23972
+ this.unsubscribeCompleted = null;
23973
+ this.unsubscribeFailed?.();
23974
+ this.unsubscribeFailed = null;
23975
+ }
23976
+ };
23977
+ async function createAutoPhaseFromTaskGraph(taskGraph, options) {
23978
+ const graph = await PhaseGraphBuilder.fromTaskGraph(taskGraph, {
23979
+ title: options.title ?? taskGraph.title,
23980
+ tasksPerPhase: options.tasksPerPhase
23981
+ });
23982
+ const phases = Array.from(graph.phases.values()).map((p) => ({
23983
+ name: p.name,
23984
+ description: p.description,
23985
+ priority: p.priority,
23986
+ estimateHours: p.estimateHours,
23987
+ parallelizable: p.parallelizable
23988
+ }));
23989
+ return new AutoPhaseRunner({
23990
+ ...options,
23991
+ title: options.title ?? taskGraph.title,
23992
+ phases
23993
+ });
23994
+ }
23995
+
23996
+ // src/autophase/auto-phase-planner.ts
23997
+ var VALID_TASK_TYPES = /* @__PURE__ */ new Set([
23998
+ "feature",
23999
+ "bugfix",
24000
+ "refactor",
24001
+ "docs",
24002
+ "test",
24003
+ "chore"
24004
+ ]);
24005
+ var VALID_PRIORITIES = /* @__PURE__ */ new Set([
24006
+ "critical",
24007
+ "high",
24008
+ "medium",
24009
+ "low"
24010
+ ]);
24011
+ var AutoPhasePlanner = class {
24012
+ constructor(opts) {
24013
+ this.opts = opts;
24014
+ }
24015
+ opts;
24016
+ /** Hedefi faz+todo planına dönüştür. */
24017
+ async plan() {
24018
+ const prompt = this.buildPrompt();
24019
+ const raw = await this.opts.runOnce(prompt);
24020
+ const phases = this.parse(raw);
24021
+ return { phases, raw, parseFailed: phases.length === 0 };
24022
+ }
24023
+ /** Modelin üreteceği plan için talimat prompt'u. */
24024
+ buildPrompt() {
24025
+ const minP = this.opts.minPhases ?? 3;
24026
+ const maxP = this.opts.maxPhases ?? 8;
24027
+ const todos = this.opts.todosPerPhase ?? 6;
24028
+ const ctx = this.opts.projectContext?.trim();
24029
+ return [
24030
+ "You are an expert software project planner. Break the following goal into",
24031
+ `a dependency-ordered list of ${minP}\u2013${maxP} PHASES. Each phase must contain`,
24032
+ `roughly ${todos} concrete, individually-actionable TODO tasks.`,
24033
+ "",
24034
+ `GOAL: ${this.opts.goal}`,
24035
+ ctx ? `
24036
+ PROJECT CONTEXT:
24037
+ ${ctx}
24038
+ ` : "",
24039
+ "Rules:",
24040
+ "- Phases run in order; earlier phases are prerequisites for later ones.",
24041
+ "- Each todo must be small enough for one focused work session.",
24042
+ "- Each todo must be self-contained (an agent will execute it in isolation).",
24043
+ '- Prefer concrete verbs ("Add X", "Refactor Y", "Write tests for Z").',
24044
+ "",
24045
+ "Respond with ONLY a JSON array inside a ```json code fence. No prose before",
24046
+ "or after. Schema (TypeScript):",
24047
+ "",
24048
+ "```json",
24049
+ "[",
24050
+ " {",
24051
+ ' "name": "Phase name",',
24052
+ ' "description": "What this phase accomplishes",',
24053
+ ' "priority": "critical" | "high" | "medium" | "low",',
24054
+ ' "estimateHours": number,',
24055
+ ' "parallelizable": boolean,',
24056
+ ' "tasks": [',
24057
+ " {",
24058
+ ' "title": "Short task title",',
24059
+ ' "description": "What to do and how to know it is done",',
24060
+ ' "type": "feature" | "bugfix" | "refactor" | "docs" | "test" | "chore",',
24061
+ ' "priority": "critical" | "high" | "medium" | "low",',
24062
+ ' "estimateHours": number,',
24063
+ ' "tags": ["optional", "labels"]',
24064
+ " }",
24065
+ " ]",
24066
+ " }",
24067
+ "]",
24068
+ "```"
24069
+ ].filter((l) => l !== "").join("\n");
24070
+ }
24071
+ /** Ham çıktıdan JSON'u çıkar, doğrula ve PhaseTemplate[]'e dönüştür. */
24072
+ parse(raw) {
24073
+ const json = extractJSONArray(raw);
24074
+ if (!json) return [];
24075
+ let data;
24076
+ try {
24077
+ data = JSON.parse(json);
24078
+ } catch {
24079
+ return [];
24080
+ }
24081
+ if (!Array.isArray(data)) return [];
24082
+ const phases = [];
24083
+ for (const entry of data) {
24084
+ const phase = this.coercePhase(entry);
24085
+ if (phase) phases.push(phase);
24086
+ }
24087
+ return phases;
24088
+ }
24089
+ coercePhase(entry) {
24090
+ if (!entry || typeof entry !== "object") return null;
24091
+ const e = entry;
24092
+ const name = typeof e.name === "string" ? e.name.trim() : "";
24093
+ if (!name) return null;
24094
+ const rawTasks = Array.isArray(e.tasks) ? e.tasks : Array.isArray(e.taskTemplates) ? e.taskTemplates : [];
24095
+ const taskTemplates = rawTasks.map((t2) => this.coerceTask(t2)).filter((t2) => t2 !== null);
24096
+ return {
24097
+ name,
24098
+ description: typeof e.description === "string" ? e.description : "",
24099
+ priority: coercePriority(e.priority),
24100
+ estimateHours: coerceHours(e.estimateHours, 4),
24101
+ parallelizable: e.parallelizable === true,
24102
+ taskTemplates
24103
+ };
24104
+ }
24105
+ coerceTask(t2) {
24106
+ if (!t2 || typeof t2 !== "object") return null;
24107
+ const o = t2;
24108
+ const title = typeof o.title === "string" ? o.title.trim() : "";
24109
+ if (!title) return null;
24110
+ const type = VALID_TASK_TYPES.has(o.type) ? o.type : "feature";
24111
+ return {
24112
+ title,
24113
+ description: typeof o.description === "string" ? o.description : "",
24114
+ type,
24115
+ priority: coercePriority(o.priority),
24116
+ estimateHours: coerceHours(o.estimateHours, 2),
24117
+ tags: Array.isArray(o.tags) ? o.tags.map(String) : []
24118
+ };
24119
+ }
24120
+ };
24121
+ function coercePriority(value) {
24122
+ return VALID_PRIORITIES.has(value) ? value : "medium";
24123
+ }
24124
+ function coerceHours(value, fallback) {
24125
+ const n = Number(value);
24126
+ return Number.isFinite(n) && n > 0 ? n : fallback;
24127
+ }
24128
+ function extractJSONArray(text) {
24129
+ const fence = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
24130
+ const candidates = [];
24131
+ if (fence?.[1]) candidates.push(fence[1]);
24132
+ candidates.push(text);
24133
+ for (const candidate of candidates) {
24134
+ const balanced = firstBalancedArray(candidate);
24135
+ if (balanced) return balanced;
24136
+ }
24137
+ return null;
24138
+ }
24139
+ function firstBalancedArray(text) {
24140
+ const start = text.indexOf("[");
24141
+ if (start === -1) return null;
24142
+ let depth = 0;
24143
+ let inString = false;
24144
+ let escaped = false;
24145
+ for (let i = start; i < text.length; i++) {
24146
+ const ch = text[i];
24147
+ if (inString) {
24148
+ if (escaped) {
24149
+ escaped = false;
24150
+ } else if (ch === "\\") {
24151
+ escaped = true;
24152
+ } else if (ch === '"') {
24153
+ inString = false;
24154
+ }
24155
+ continue;
24156
+ }
24157
+ if (ch === '"') {
24158
+ inString = true;
24159
+ } else if (ch === "[") {
24160
+ depth++;
24161
+ } else if (ch === "]") {
24162
+ depth--;
24163
+ if (depth === 0) {
24164
+ return text.slice(start, i + 1);
24165
+ }
24166
+ }
24167
+ }
24168
+ return null;
24169
+ }
24170
+ var PhaseStore = class {
24171
+ baseDir;
24172
+ constructor(opts) {
24173
+ this.baseDir = opts.baseDir;
24174
+ }
24175
+ async save(graph) {
24176
+ const filePath = this.getFilePath(graph.id);
24177
+ await fsp2.mkdir(path6.dirname(filePath), { recursive: true });
24178
+ const serialized = this.serializeGraph(graph);
24179
+ await fsp2.writeFile(filePath, JSON.stringify(serialized, null, 2), "utf8");
24180
+ }
24181
+ async load(graphId) {
24182
+ const filePath = this.getFilePath(graphId);
24183
+ try {
24184
+ const raw = await fsp2.readFile(filePath, "utf8");
24185
+ const serialized = JSON.parse(raw);
24186
+ return this.deserializeGraph(serialized);
24187
+ } catch {
24188
+ return null;
24189
+ }
24190
+ }
24191
+ async delete(graphId) {
24192
+ const filePath = this.getFilePath(graphId);
24193
+ try {
24194
+ await fsp2.unlink(filePath);
24195
+ } catch {
24196
+ }
24197
+ }
24198
+ async list() {
24199
+ try {
24200
+ const entries = await fsp2.readdir(this.baseDir, { withFileTypes: true });
24201
+ const graphs = [];
24202
+ for (const entry of entries) {
24203
+ if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
24204
+ try {
24205
+ const raw = await fsp2.readFile(path6.join(this.baseDir, entry.name), "utf8");
24206
+ const serialized = JSON.parse(raw);
24207
+ const done = serialized.completedPhaseIds.length;
24208
+ const total = serialized.phases.length;
24209
+ graphs.push({
24210
+ id: serialized.id,
24211
+ title: serialized.title,
24212
+ updatedAt: serialized.updatedAt,
24213
+ status: done === total ? "completed" : done > 0 ? "in_progress" : "pending"
24214
+ });
24215
+ } catch {
24216
+ }
24217
+ }
24218
+ return graphs.sort((a, b) => b.updatedAt - a.updatedAt);
24219
+ } catch {
24220
+ return [];
24221
+ }
24222
+ }
24223
+ getFilePath(graphId) {
24224
+ return path6.join(this.baseDir, `${graphId}.json`);
24225
+ }
24226
+ serializeGraph(graph) {
24227
+ return {
24228
+ id: graph.id,
24229
+ title: graph.title,
24230
+ description: graph.description,
24231
+ phases: Array.from(graph.phases.values()).map((p) => this.serializePhase(p)),
24232
+ rootPhaseIds: graph.rootPhaseIds,
24233
+ activePhaseIds: graph.activePhaseIds,
24234
+ completedPhaseIds: graph.completedPhaseIds,
24235
+ failedPhaseIds: graph.failedPhaseIds,
24236
+ autonomous: graph.autonomous,
24237
+ stopOnComplete: graph.stopOnComplete,
24238
+ createdAt: graph.createdAt,
24239
+ updatedAt: graph.updatedAt,
24240
+ startedAt: graph.startedAt,
24241
+ completedAt: graph.completedAt
24242
+ };
24243
+ }
24244
+ serializePhase(phase) {
24245
+ return {
24246
+ id: phase.id,
24247
+ name: phase.name,
24248
+ description: phase.description,
24249
+ status: phase.status,
24250
+ taskGraph: this.serializeTaskGraph(phase.taskGraph),
24251
+ dependsOn: phase.dependsOn,
24252
+ nextPhases: phase.nextPhases,
24253
+ parallelizable: phase.parallelizable,
24254
+ priority: phase.priority,
24255
+ estimateHours: phase.estimateHours,
24256
+ actualDurationMs: phase.actualDurationMs,
24257
+ startedAt: phase.startedAt,
24258
+ completedAt: phase.completedAt,
24259
+ assignedAgents: phase.assignedAgents,
24260
+ metadata: phase.metadata,
24261
+ createdAt: phase.createdAt,
24262
+ updatedAt: phase.updatedAt
24263
+ };
24264
+ }
24265
+ serializeTaskGraph(graph) {
24266
+ return {
24267
+ id: graph.id,
24268
+ specId: graph.specId,
24269
+ title: graph.title,
24270
+ nodes: Array.from(graph.nodes.values()).map((n) => this.serializeTaskNode(n)),
24271
+ edges: graph.edges,
24272
+ rootNodes: graph.rootNodes,
24273
+ createdAt: graph.createdAt,
24274
+ updatedAt: graph.updatedAt
24275
+ };
24276
+ }
24277
+ serializeTaskNode(node) {
24278
+ return { ...node };
24279
+ }
24280
+ deserializeGraph(serialized) {
24281
+ const phases = /* @__PURE__ */ new Map();
24282
+ for (const sp of serialized.phases) {
24283
+ phases.set(sp.id, this.deserializePhase(sp));
24284
+ }
24285
+ return {
24286
+ id: serialized.id,
24287
+ title: serialized.title,
24288
+ description: serialized.description,
24289
+ phases,
24290
+ rootPhaseIds: serialized.rootPhaseIds,
24291
+ activePhaseIds: serialized.activePhaseIds,
24292
+ completedPhaseIds: serialized.completedPhaseIds,
24293
+ failedPhaseIds: serialized.failedPhaseIds,
24294
+ autonomous: serialized.autonomous,
24295
+ stopOnComplete: serialized.stopOnComplete,
24296
+ createdAt: serialized.createdAt,
24297
+ updatedAt: serialized.updatedAt,
24298
+ startedAt: serialized.startedAt,
24299
+ completedAt: serialized.completedAt
24300
+ };
24301
+ }
24302
+ deserializePhase(serialized) {
24303
+ return {
24304
+ id: serialized.id,
24305
+ name: serialized.name,
24306
+ description: serialized.description,
24307
+ status: serialized.status,
24308
+ taskGraph: this.deserializeTaskGraph(serialized.taskGraph),
24309
+ dependsOn: serialized.dependsOn,
24310
+ nextPhases: serialized.nextPhases,
24311
+ parallelizable: serialized.parallelizable,
24312
+ priority: serialized.priority,
24313
+ estimateHours: serialized.estimateHours,
24314
+ actualDurationMs: serialized.actualDurationMs,
24315
+ startedAt: serialized.startedAt,
24316
+ completedAt: serialized.completedAt,
24317
+ assignedAgents: serialized.assignedAgents,
24318
+ metadata: serialized.metadata,
24319
+ createdAt: serialized.createdAt,
24320
+ updatedAt: serialized.updatedAt
24321
+ };
24322
+ }
24323
+ deserializeTaskGraph(serialized) {
24324
+ const nodes = /* @__PURE__ */ new Map();
24325
+ for (const sn of serialized.nodes) {
24326
+ nodes.set(sn.id, sn);
24327
+ }
24328
+ return {
24329
+ id: serialized.id,
24330
+ specId: serialized.specId,
24331
+ title: serialized.title,
24332
+ nodes,
24333
+ edges: serialized.edges ?? [],
24334
+ rootNodes: serialized.rootNodes ?? [],
24335
+ createdAt: serialized.createdAt,
24336
+ updatedAt: serialized.updatedAt
24337
+ };
24338
+ }
24339
+ };
24340
+ var CheckpointManager = class {
24341
+ store;
24342
+ maxCheckpoints;
24343
+ checkpoints = /* @__PURE__ */ new Map();
24344
+ baseDir;
24345
+ constructor(opts) {
24346
+ this.store = opts.store;
24347
+ this.maxCheckpoints = opts.maxCheckpoints ?? 10;
24348
+ this.baseDir = opts.baseDir ?? path6.join(opts.store.baseDir, ".checkpoints");
24349
+ }
24350
+ async initialize() {
24351
+ await fsp2.mkdir(this.baseDir, { recursive: true });
24352
+ await this.loadFromDisk();
24353
+ }
24354
+ async saveCheckpoint(graph, label) {
24355
+ await this.store.save(graph);
24356
+ const activePhase = Array.from(graph.phases.values()).find(
24357
+ (p) => p.status === "running" || p.status === "paused"
24358
+ );
24359
+ const checkpoint = {
24360
+ id: crypto.randomUUID(),
24361
+ graphId: graph.id,
24362
+ phaseId: activePhase?.id ?? graph.rootPhaseIds[0] ?? "",
24363
+ phaseStatus: activePhase?.status ?? "pending",
24364
+ taskStatuses: activePhase ? Array.from(activePhase.taskGraph.nodes.values()).map((t2) => ({
24365
+ taskId: t2.id,
24366
+ status: t2.status,
24367
+ title: t2.title
24368
+ })) : [],
24369
+ timestamp: Date.now(),
24370
+ label
24371
+ };
24372
+ this.checkpoints.set(checkpoint.id, checkpoint);
24373
+ await this.saveToDisk(checkpoint);
24374
+ await this.pruneCheckpoints();
24375
+ return checkpoint;
24376
+ }
24377
+ async restoreCheckpoint(checkpointId) {
24378
+ let checkpoint = this.checkpoints.get(checkpointId);
24379
+ if (!checkpoint) {
24380
+ await this.loadFromDisk();
24381
+ checkpoint = this.checkpoints.get(checkpointId);
24382
+ }
24383
+ if (!checkpoint) return null;
24384
+ const graph = await this.store.load(checkpoint.graphId);
24385
+ if (!graph) return null;
24386
+ const phase = graph.phases.get(checkpoint.phaseId);
24387
+ if (phase) {
24388
+ phase.status = checkpoint.phaseStatus;
24389
+ phase.updatedAt = Date.now();
24390
+ for (const ts of checkpoint.taskStatuses) {
24391
+ const task = phase.taskGraph.nodes.get(ts.taskId);
24392
+ if (task) {
24393
+ task.status = ts.status;
24394
+ task.updatedAt = Date.now();
24395
+ }
24396
+ }
24397
+ }
24398
+ graph.updatedAt = Date.now();
24399
+ return graph;
24400
+ }
24401
+ listCheckpoints(graphId) {
24402
+ const all = Array.from(this.checkpoints.values());
24403
+ const filtered = graphId ? all.filter((c) => c.graphId === graphId) : all;
24404
+ return filtered.sort((a, b) => b.timestamp - a.timestamp);
24405
+ }
24406
+ async deleteCheckpoint(checkpointId) {
24407
+ const checkpoint = this.checkpoints.get(checkpointId);
24408
+ if (!checkpoint) return false;
24409
+ this.checkpoints.delete(checkpointId);
24410
+ await this.deleteFromDisk(checkpointId);
24411
+ return true;
24412
+ }
24413
+ async saveToDisk(checkpoint) {
24414
+ await fsp2.mkdir(this.baseDir, { recursive: true });
24415
+ const filePath = path6.join(this.baseDir, `${checkpoint.graphId}.json`);
24416
+ const serialized = {
24417
+ ...checkpoint
24418
+ };
24419
+ let existing = [];
24420
+ try {
24421
+ const raw = await fsp2.readFile(filePath, "utf8");
24422
+ const parsed = JSON.parse(raw);
24423
+ if (Array.isArray(parsed)) {
24424
+ existing = parsed;
24425
+ }
24426
+ } catch {
24427
+ }
24428
+ existing.push(serialized);
24429
+ await fsp2.writeFile(filePath, JSON.stringify(existing, null, 2), "utf8");
24430
+ }
24431
+ async deleteFromDisk(checkpointId) {
24432
+ let entries;
24433
+ try {
24434
+ entries = await fsp2.readdir(this.baseDir);
24435
+ } catch {
24436
+ return;
24437
+ }
24438
+ for (const filename of entries) {
24439
+ if (!filename.endsWith(".json")) continue;
24440
+ const filePath = path6.join(this.baseDir, filename);
24441
+ try {
24442
+ const raw = await fsp2.readFile(filePath, "utf8");
24443
+ const parsed = JSON.parse(raw);
24444
+ if (!Array.isArray(parsed)) continue;
24445
+ const existing = parsed;
24446
+ const filtered = existing.filter((c) => c.id !== checkpointId);
24447
+ if (filtered.length !== existing.length) {
24448
+ if (filtered.length === 0) {
24449
+ await fsp2.unlink(filePath);
24450
+ } else {
24451
+ await fsp2.writeFile(filePath, JSON.stringify(filtered, null, 2), "utf8");
24452
+ }
24453
+ }
24454
+ } catch {
24455
+ }
24456
+ }
24457
+ }
24458
+ async loadFromDisk() {
24459
+ let entries;
24460
+ try {
24461
+ entries = await fsp2.readdir(this.baseDir);
24462
+ } catch {
24463
+ return;
24464
+ }
24465
+ for (const filename of entries) {
24466
+ if (!filename.endsWith(".json")) continue;
24467
+ const filePath = path6.join(this.baseDir, filename);
24468
+ try {
24469
+ const raw = await fsp2.readFile(filePath, "utf8");
24470
+ const parsed = JSON.parse(raw);
24471
+ if (!Array.isArray(parsed)) continue;
24472
+ const checkpoints = parsed;
24473
+ for (const sc of checkpoints) {
24474
+ const checkpoint = {
24475
+ id: sc.id,
24476
+ graphId: sc.graphId,
24477
+ phaseId: sc.phaseId,
24478
+ phaseStatus: sc.phaseStatus,
24479
+ taskStatuses: sc.taskStatuses,
24480
+ timestamp: sc.timestamp,
24481
+ label: sc.label
24482
+ };
24483
+ this.checkpoints.set(checkpoint.id, checkpoint);
24484
+ }
24485
+ } catch {
24486
+ }
24487
+ }
24488
+ }
24489
+ async pruneCheckpoints() {
24490
+ const all = Array.from(this.checkpoints.values()).sort(
24491
+ (a, b) => a.timestamp - b.timestamp
24492
+ );
24493
+ while (all.length > this.maxCheckpoints) {
24494
+ const oldest = all.shift();
24495
+ if (oldest) {
24496
+ this.checkpoints.delete(oldest.id);
24497
+ await this.deleteFromDisk(oldest.id);
24498
+ }
24499
+ }
24500
+ }
24501
+ };
24502
+
24503
+ export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, 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 };
23265
24504
  //# sourceMappingURL=index.js.map
23266
24505
  //# sourceMappingURL=index.js.map