@wrongstack/core 0.8.4 → 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, path27, 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: path27 || "<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, path27, errors) {
3978
4036
  if (typeof schema.type === "string") {
3979
4037
  if (!checkType(value, schema.type)) {
3980
4038
  errors.push({
3981
- path: path27 || "<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, path27, 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(path27, 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(path27, 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, `${path27}[${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();
@@ -8261,8 +8317,8 @@ ${recentJournal}` : "No prior iterations.",
8261
8317
  await saveGoal(this.goalPath, abandoned);
8262
8318
  }
8263
8319
  try {
8264
- const { unlink: unlink11 } = await import('fs/promises');
8265
- await unlink11(this.goalPath);
8320
+ const { unlink: unlink12 } = await import('fs/promises');
8321
+ await unlink12(this.goalPath);
8266
8322
  } catch {
8267
8323
  }
8268
8324
  this.opts.onEternalStop?.();
@@ -8284,7 +8340,7 @@ ${recentJournal}` : "No prior iterations.",
8284
8340
  }
8285
8341
  };
8286
8342
  function sleep(ms) {
8287
- return new Promise((resolve6) => setTimeout(resolve6, ms));
8343
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
8288
8344
  }
8289
8345
 
8290
8346
  // src/coordination/subagent-budget.ts
@@ -8434,12 +8490,12 @@ var SubagentBudget = class _SubagentBudget {
8434
8490
  if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
8435
8491
  return Promise.resolve("stop");
8436
8492
  }
8437
- return new Promise((resolve6) => {
8493
+ return new Promise((resolve7) => {
8438
8494
  let resolved = false;
8439
8495
  const respond = (d) => {
8440
8496
  if (resolved) return;
8441
8497
  resolved = true;
8442
- resolve6(d);
8498
+ resolve7(d);
8443
8499
  };
8444
8500
  const fallback = setTimeout(
8445
8501
  () => respond("stop"),
@@ -11480,7 +11536,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
11480
11536
  taskIds.map((id) => {
11481
11537
  const cached = this.completedResults.find((r) => r.taskId === id);
11482
11538
  if (cached) return cached;
11483
- return new Promise((resolve6, reject) => {
11539
+ return new Promise((resolve7, reject) => {
11484
11540
  const timeout = setTimeout(() => {
11485
11541
  this.off("task.completed", handler);
11486
11542
  reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
@@ -11489,7 +11545,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
11489
11545
  if (result.taskId === id) {
11490
11546
  clearTimeout(timeout);
11491
11547
  this.off("task.completed", handler);
11492
- resolve6(result);
11548
+ resolve7(result);
11493
11549
  }
11494
11550
  };
11495
11551
  this.on("task.completed", handler);
@@ -11919,7 +11975,7 @@ function providerErrorToSubagentError(err, message, cause) {
11919
11975
 
11920
11976
  // src/execution/parallel-eternal-engine.ts
11921
11977
  function sleep2(ms) {
11922
- return new Promise((resolve6) => setTimeout(resolve6, ms));
11978
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
11923
11979
  }
11924
11980
  var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
11925
11981
  var ParallelEternalEngine = class {
@@ -12700,7 +12756,7 @@ function makeSpawnTool(director, roster) {
12700
12756
  catalog: roster
12701
12757
  });
12702
12758
  const dispatchRole = dispatchResult.role;
12703
- if (roster && roster[dispatchRole]) {
12759
+ if (roster?.[dispatchRole]) {
12704
12760
  cfg = instantiateRosterConfig(dispatchRole, roster[dispatchRole]);
12705
12761
  } else {
12706
12762
  const def = dispatchResult.definition;
@@ -13190,6 +13246,13 @@ var Director = class {
13190
13246
  extendCounts.delete(guardKey);
13191
13247
  return;
13192
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
+ }
13193
13256
  extendCounts.set(guardKey, prior + 1);
13194
13257
  setImmediate(() => {
13195
13258
  const extra = {};
@@ -13554,11 +13617,11 @@ var Director = class {
13554
13617
  if (cached) return cached;
13555
13618
  const existing = this.taskWaiters.get(id);
13556
13619
  if (existing) return existing.promise;
13557
- let resolve6;
13620
+ let resolve7;
13558
13621
  const promise = new Promise((res) => {
13559
- resolve6 = res;
13622
+ resolve7 = res;
13560
13623
  });
13561
- this.taskWaiters.set(id, { promise, resolve: resolve6 });
13624
+ this.taskWaiters.set(id, { promise, resolve: resolve7 });
13562
13625
  return promise;
13563
13626
  })
13564
13627
  );
@@ -13874,7 +13937,7 @@ function createDelegateTool(opts) {
13874
13937
  subagentId
13875
13938
  });
13876
13939
  const dir = director;
13877
- const result = await new Promise((resolve6) => {
13940
+ const result = await new Promise((resolve7) => {
13878
13941
  let settled = false;
13879
13942
  let timer;
13880
13943
  const finish = (value) => {
@@ -13883,7 +13946,7 @@ function createDelegateTool(opts) {
13883
13946
  if (timer) clearTimeout(timer);
13884
13947
  offTool();
13885
13948
  offIter();
13886
- resolve6(value);
13949
+ resolve7(value);
13887
13950
  };
13888
13951
  const arm = () => {
13889
13952
  if (timer) clearTimeout(timer);
@@ -14688,6 +14751,13 @@ var TaskTracker = class {
14688
14751
  opts;
14689
14752
  graph = null;
14690
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
+ }
14691
14761
  async createGraph(specId, title) {
14692
14762
  this.graph = {
14693
14763
  id: crypto.randomUUID(),
@@ -14760,10 +14830,6 @@ var TaskTracker = class {
14760
14830
  this.graph.updatedAt = now;
14761
14831
  this.persist();
14762
14832
  }
14763
- /**
14764
- * Update node fields (title, description, priority, estimateHours, tags).
14765
- * Does NOT change status. Use updateNodeStatus for status changes.
14766
- */
14767
14833
  updateNode(id, patch) {
14768
14834
  if (!this.graph) throw new Error("No graph loaded");
14769
14835
  const node = this.graph.nodes.get(id);
@@ -14841,8 +14907,7 @@ var TaskTracker = class {
14841
14907
  }
14842
14908
  return computeTaskProgress(this.graph);
14843
14909
  }
14844
- getTransitions(taskId) {
14845
- if (!taskId) return [...this.transitions];
14910
+ getTransitions(_taskId) {
14846
14911
  return [...this.transitions];
14847
14912
  }
14848
14913
  unblockDependents(completedId) {
@@ -14882,18 +14947,12 @@ var TaskTracker = class {
14882
14947
  * Fire-and-forget persistence with attached error handler.
14883
14948
  * Synchronous mutators (addNode/addEdge/updateNodeStatus) use this to
14884
14949
  * avoid forcing an async cascade through every caller; if the store
14885
- * rejects, the configured `onPersistError` is invoked so failures are
14886
- * surfaced instead of swallowed by an unhandled promise rejection.
14950
+ * is missing or throwing, the error is surfaced via onPersistError.
14887
14951
  */
14888
14952
  persist() {
14889
14953
  if (!this.graph) return;
14890
14954
  this.opts.store.saveGraph(this.graph).catch((err) => {
14891
- if (this.opts.onPersistError) this.opts.onPersistError(err);
14892
- else
14893
- console.warn(
14894
- "[task-tracker] saveGraph failed:",
14895
- err instanceof Error ? err.message : String(err)
14896
- );
14955
+ this.opts.onPersistError ? this.opts.onPersistError(err) : console.warn("[task-tracker] saveGraph failed:", err instanceof Error ? err.message : String(err));
14897
14956
  });
14898
14957
  }
14899
14958
  };
@@ -15514,10 +15573,10 @@ var AISpecBuilder = class {
15514
15573
  async saveSession() {
15515
15574
  if (!this.sessionPath) return;
15516
15575
  try {
15517
- const fsp17 = await import('fs/promises');
15518
- const path27 = await import('path');
15576
+ const fsp18 = await import('fs/promises');
15577
+ const path28 = await import('path');
15519
15578
  const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
15520
- await fsp17.mkdir(path27.dirname(this.sessionPath), { recursive: true });
15579
+ await fsp18.mkdir(path28.dirname(this.sessionPath), { recursive: true });
15521
15580
  await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
15522
15581
  } catch {
15523
15582
  }
@@ -15526,8 +15585,8 @@ var AISpecBuilder = class {
15526
15585
  async loadSession() {
15527
15586
  if (!this.sessionPath) return false;
15528
15587
  try {
15529
- const fsp17 = await import('fs/promises');
15530
- const raw = await fsp17.readFile(this.sessionPath, "utf8");
15588
+ const fsp18 = await import('fs/promises');
15589
+ const raw = await fsp18.readFile(this.sessionPath, "utf8");
15531
15590
  const loaded = JSON.parse(raw);
15532
15591
  if (loaded?.id && loaded?.phase && loaded?.title) {
15533
15592
  this.session = loaded;
@@ -15541,8 +15600,8 @@ var AISpecBuilder = class {
15541
15600
  async deleteSession() {
15542
15601
  if (!this.sessionPath) return;
15543
15602
  try {
15544
- const fsp17 = await import('fs/promises');
15545
- await fsp17.unlink(this.sessionPath);
15603
+ const fsp18 = await import('fs/promises');
15604
+ await fsp18.unlink(this.sessionPath);
15546
15605
  } catch {
15547
15606
  }
15548
15607
  }
@@ -16227,15 +16286,15 @@ function computeCriticalPath(graph, topoOrder, blockedByMap) {
16227
16286
  maxId = id;
16228
16287
  }
16229
16288
  }
16230
- const path27 = [];
16289
+ const path28 = [];
16231
16290
  let current = maxId;
16232
16291
  const visited = /* @__PURE__ */ new Set();
16233
16292
  while (current && !visited.has(current)) {
16234
16293
  visited.add(current);
16235
- path27.unshift(current);
16294
+ path28.unshift(current);
16236
16295
  current = prev.get(current) ?? null;
16237
16296
  }
16238
- return path27;
16297
+ return path28;
16239
16298
  }
16240
16299
  function computeParallelGroups(graph, blockedByMap) {
16241
16300
  const groups = [];
@@ -17030,9 +17089,9 @@ var DefaultHealthRegistry = class {
17030
17089
  }
17031
17090
  async runOne(check) {
17032
17091
  let timer = null;
17033
- const timeout = new Promise((resolve6) => {
17092
+ const timeout = new Promise((resolve7) => {
17034
17093
  timer = setTimeout(
17035
- () => resolve6({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
17094
+ () => resolve7({ status: "unhealthy", detail: `timeout after ${this.timeoutMs}ms` }),
17036
17095
  this.timeoutMs
17037
17096
  );
17038
17097
  });
@@ -17215,7 +17274,7 @@ async function startMetricsServer(opts) {
17215
17274
  const tls = opts.tls;
17216
17275
  const useHttps = !!(tls?.cert && tls?.key);
17217
17276
  const host = opts.host ?? "127.0.0.1";
17218
- const path27 = opts.path ?? "/metrics";
17277
+ const path28 = opts.path ?? "/metrics";
17219
17278
  const healthPath = opts.healthPath ?? "/healthz";
17220
17279
  const healthRegistry = opts.healthRegistry;
17221
17280
  const listener = (req, res) => {
@@ -17225,7 +17284,7 @@ async function startMetricsServer(opts) {
17225
17284
  return;
17226
17285
  }
17227
17286
  const url = req.url.split("?")[0];
17228
- if (url === path27) {
17287
+ if (url === path28) {
17229
17288
  let body;
17230
17289
  try {
17231
17290
  body = renderPrometheus(opts.sink.snapshot());
@@ -17271,14 +17330,14 @@ async function startMetricsServer(opts) {
17271
17330
  const { createServer } = await import('http');
17272
17331
  server = createServer(listener);
17273
17332
  }
17274
- await new Promise((resolve6, reject) => {
17333
+ await new Promise((resolve7, reject) => {
17275
17334
  const onError = (err) => {
17276
17335
  server.off("listening", onListening);
17277
17336
  reject(err);
17278
17337
  };
17279
17338
  const onListening = () => {
17280
17339
  server.off("error", onError);
17281
- resolve6();
17340
+ resolve7();
17282
17341
  };
17283
17342
  server.once("error", onError);
17284
17343
  server.once("listening", onListening);
@@ -17289,9 +17348,9 @@ async function startMetricsServer(opts) {
17289
17348
  const protocol = useHttps ? "https" : "http";
17290
17349
  return {
17291
17350
  port: boundPort,
17292
- url: `${protocol}://${host}:${boundPort}${path27}`,
17293
- close: () => new Promise((resolve6, reject) => {
17294
- 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());
17295
17354
  })
17296
17355
  };
17297
17356
  }
@@ -17990,6 +18049,12 @@ async function extractTar(buf, destDir) {
17990
18049
  const relPath = stripTopDir(fullPath);
17991
18050
  if (relPath && relPath !== "." && relPath !== "..") {
17992
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
+ }
17993
18058
  if (typeflag === 53 || typeflag === 0) {
17994
18059
  if (relPath.endsWith("/") || typeflag === 53) {
17995
18060
  await fsp2.mkdir(destPath, { recursive: true });
@@ -19409,8 +19474,8 @@ var ReportGenerator = class {
19409
19474
  try {
19410
19475
  await stat(this.options.outputDir);
19411
19476
  } catch {
19412
- const { mkdir: mkdir12 } = await import('fs/promises');
19413
- await mkdir12(this.options.outputDir, { recursive: true });
19477
+ const { mkdir: mkdir13 } = await import('fs/promises');
19478
+ await mkdir13(this.options.outputDir, { recursive: true });
19414
19479
  }
19415
19480
  }
19416
19481
  generateMarkdown(result) {
@@ -19686,7 +19751,7 @@ var SecurityScannerOrchestrator = class {
19686
19751
  const delay = Math.round(policy.delayMs(attempt));
19687
19752
  const status = isProviderErr ? err.status : 0;
19688
19753
  console.warn(`[SecurityScanner] retry ${attempt + 1} after ${delay}ms (status=${status}) \u2014 ${errAsErr.message}`);
19689
- await new Promise((resolve6) => setTimeout(resolve6, delay));
19754
+ await new Promise((resolve7) => setTimeout(resolve7, delay));
19690
19755
  return this.completeWithRetry(provider, request, abortController, attempt + 1);
19691
19756
  }
19692
19757
  }
@@ -20332,16 +20397,16 @@ Use \`/security report <number>\` to view a specific report.` };
20332
20397
  }
20333
20398
  const index = Number.parseInt(reportId, 10) - 1;
20334
20399
  if (!Number.isNaN(index) && reports[index]) {
20335
- const { readFile: readFile31 } = await import('fs/promises');
20336
- const content = await readFile31(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");
20337
20402
  return { message: `# Security Report
20338
20403
 
20339
20404
  ${content}` };
20340
20405
  }
20341
20406
  const match = reports.find((r) => r.includes(reportId));
20342
20407
  if (match) {
20343
- const { readFile: readFile31 } = await import('fs/promises');
20344
- const content = await readFile31(join(reportsDir, match), "utf-8");
20408
+ const { readFile: readFile32 } = await import('fs/promises');
20409
+ const content = await readFile32(join(reportsDir, match), "utf-8");
20345
20410
  return { message: `# Security Report
20346
20411
 
20347
20412
  ${content}` };
@@ -21183,12 +21248,12 @@ function makeContinueToNextIterationTool() {
21183
21248
  // src/core/iteration-limit.ts
21184
21249
  function requestLimitExtension(opts) {
21185
21250
  const { events, currentIterations, currentLimit, autoExtend, timeoutMs = 3e4 } = opts;
21186
- return new Promise((resolve6) => {
21251
+ return new Promise((resolve7) => {
21187
21252
  let resolved = false;
21188
21253
  const timerFired = () => {
21189
21254
  if (!resolved) {
21190
21255
  resolved = true;
21191
- resolve6(0);
21256
+ resolve7(0);
21192
21257
  }
21193
21258
  };
21194
21259
  const timer = setTimeout(timerFired, timeoutMs);
@@ -21197,14 +21262,14 @@ function requestLimitExtension(opts) {
21197
21262
  if (!resolved) {
21198
21263
  resolved = true;
21199
21264
  clearTimeout(timer);
21200
- resolve6(0);
21265
+ resolve7(0);
21201
21266
  }
21202
21267
  };
21203
21268
  const grant = (extra) => {
21204
21269
  if (!resolved) {
21205
21270
  resolved = true;
21206
21271
  clearTimeout(timer);
21207
- resolve6(Math.max(0, extra));
21272
+ resolve7(Math.max(0, extra));
21208
21273
  }
21209
21274
  };
21210
21275
  events.emit("iteration.limit_reached", {
@@ -21218,7 +21283,7 @@ function requestLimitExtension(opts) {
21218
21283
  if (!resolved) {
21219
21284
  resolved = true;
21220
21285
  clearTimeout(timer);
21221
- resolve6(100);
21286
+ resolve7(100);
21222
21287
  }
21223
21288
  });
21224
21289
  }
@@ -21787,13 +21852,13 @@ var Agent = class {
21787
21852
  }
21788
21853
  }
21789
21854
  waitForConfirm(info) {
21790
- return new Promise((resolve6) => {
21855
+ return new Promise((resolve7) => {
21791
21856
  this.events.emit("tool.confirm_needed", {
21792
21857
  tool: info.tool,
21793
21858
  input: info.input,
21794
21859
  toolUseId: info.toolUseId,
21795
21860
  suggestedPattern: info.suggestedPattern,
21796
- resolve: resolve6
21861
+ resolve: resolve7
21797
21862
  });
21798
21863
  });
21799
21864
  }
@@ -22510,12 +22575,12 @@ ${mem}`);
22510
22575
  }
22511
22576
  }
22512
22577
  async gitStatus(root) {
22513
- return new Promise((resolve6) => {
22578
+ return new Promise((resolve7) => {
22514
22579
  let settled = false;
22515
22580
  const finish = (s) => {
22516
22581
  if (settled) return;
22517
22582
  settled = true;
22518
- resolve6(s);
22583
+ resolve7(s);
22519
22584
  };
22520
22585
  let proc;
22521
22586
  const timer = setTimeout(() => {
@@ -23281,7 +23346,7 @@ var PhaseGraphBuilder = class _PhaseGraphBuilder {
23281
23346
  const tmpl = this.opts.phases[i];
23282
23347
  const phaseId = crypto.randomUUID();
23283
23348
  phaseIds.push(phaseId);
23284
- const store = new DefaultTaskStore();
23349
+ const store = this.opts.externalTaskStore ?? new DefaultTaskStore();
23285
23350
  const tracker = new TaskTracker({ store });
23286
23351
  const taskGraph = await tracker.createGraph(phaseId, `${tmpl.name} Tasks`);
23287
23352
  if (tmpl.taskTemplates && tmpl.taskTemplates.length > 0) {
@@ -23388,6 +23453,8 @@ var PhaseOrchestrator = class {
23388
23453
  paused = false;
23389
23454
  runningPhases = /* @__PURE__ */ new Set();
23390
23455
  tickInterval = null;
23456
+ trackerCache = /* @__PURE__ */ new Map();
23457
+ taskRetryCounts = /* @__PURE__ */ new Map();
23391
23458
  constructor(opts) {
23392
23459
  this.graph = opts.graph;
23393
23460
  this.ctx = opts.ctx;
@@ -23416,6 +23483,9 @@ var PhaseOrchestrator = class {
23416
23483
  while (readyPhases.length > 0 && !this.stopped) {
23417
23484
  const batch = readyPhases.slice(0, this.opts.maxConcurrentPhases);
23418
23485
  await Promise.all(batch.map((p) => this.startPhase(p)));
23486
+ if (this.opts.phaseDelayMs > 0) {
23487
+ await this.delay(this.opts.phaseDelayMs);
23488
+ }
23419
23489
  readyPhases = this.getReadyPhases().filter(
23420
23490
  (p) => !this.runningPhases.has(p.id) && p.status !== "completed" && p.status !== "failed"
23421
23491
  );
@@ -23431,7 +23501,9 @@ var PhaseOrchestrator = class {
23431
23501
  /** Devam et — yeni fazlar başlayabilir */
23432
23502
  resume() {
23433
23503
  this.paused = false;
23434
- void this.tick();
23504
+ this.tick().catch((err) => {
23505
+ console.error("[phase-orchestrator] tick failed:", err instanceof Error ? err.message : String(err));
23506
+ });
23435
23507
  }
23436
23508
  /** Tamamen durdur — aktif fazlar da durdurulur */
23437
23509
  stop() {
@@ -23451,16 +23523,18 @@ var PhaseOrchestrator = class {
23451
23523
  async tick() {
23452
23524
  if (this.stopped || this.paused) return;
23453
23525
  const active = this.getActivePhases();
23454
- const ready = this.getReadyPhases();
23526
+ const queued = this.getReadyPhases();
23455
23527
  this.emit("autonomous.tick", {
23456
23528
  activePhases: active.map((p) => p.id),
23457
- queuedPhases: ready.map((p) => p.id)
23529
+ queuedPhases: queued.map((p) => p.id)
23458
23530
  });
23459
- this.ctx.onTick?.({ activePhases: active, readyPhases: ready });
23531
+ this.ctx.onTick?.({ activePhases: active, readyPhases: queued });
23460
23532
  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);
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
+ }
23464
23538
  }
23465
23539
  }
23466
23540
  if (this.isComplete()) {
@@ -23497,6 +23571,7 @@ var PhaseOrchestrator = class {
23497
23571
  phase.completedAt = Date.now();
23498
23572
  phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23499
23573
  this.runningPhases.delete(phase.id);
23574
+ this.graph.activePhaseIds = this.graph.activePhaseIds.filter((id) => id !== phase.id);
23500
23575
  this.emit("phase.failed", {
23501
23576
  phaseId: phase.id,
23502
23577
  name: phase.name,
@@ -23508,6 +23583,7 @@ var PhaseOrchestrator = class {
23508
23583
  phase.completedAt = Date.now();
23509
23584
  phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23510
23585
  this.runningPhases.delete(phase.id);
23586
+ this.graph.activePhaseIds = this.graph.activePhaseIds.filter((id) => id !== phase.id);
23511
23587
  this.graph.completedPhaseIds.push(phase.id);
23512
23588
  this.emit("phase.completed", {
23513
23589
  phaseId: phase.id,
@@ -23521,6 +23597,7 @@ var PhaseOrchestrator = class {
23521
23597
  phase.completedAt = Date.now();
23522
23598
  phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
23523
23599
  this.runningPhases.delete(phase.id);
23600
+ this.graph.activePhaseIds = this.graph.activePhaseIds.filter((id) => id !== phase.id);
23524
23601
  this.graph.failedPhaseIds.push(phase.id);
23525
23602
  this.emit("phase.failed", {
23526
23603
  phaseId: phase.id,
@@ -23531,7 +23608,6 @@ var PhaseOrchestrator = class {
23531
23608
  }
23532
23609
  }
23533
23610
  async executePhaseTasks(phase) {
23534
- phase.taskGraph;
23535
23611
  const pendingTasks = this.getExecutableTasks(phase);
23536
23612
  while (pendingTasks.length > 0 && !this.stopped) {
23537
23613
  const batch = pendingTasks.splice(0, this.opts.maxConcurrentTasks);
@@ -23569,13 +23645,27 @@ var PhaseOrchestrator = class {
23569
23645
  }
23570
23646
  markTaskFailed(phase, task, error) {
23571
23647
  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
- });
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
+ }
23579
23669
  }
23580
23670
  // ─── Helpers ──────────────────────────────────────────────────────────────
23581
23671
  getReadyPhases() {
@@ -23586,7 +23676,7 @@ var PhaseOrchestrator = class {
23586
23676
  const dep = this.graph.phases.get(depId);
23587
23677
  return dep?.status === "completed" || dep?.status === "skipped";
23588
23678
  });
23589
- if (depsDone) {
23679
+ if (depsDone || phase.parallelizable) {
23590
23680
  ready.push(phase);
23591
23681
  }
23592
23682
  }
@@ -23605,18 +23695,20 @@ var PhaseOrchestrator = class {
23605
23695
  });
23606
23696
  }
23607
23697
  getTrackerForPhase(phase) {
23698
+ if (this.trackerCache.has(phase.id)) {
23699
+ return this.trackerCache.get(phase.id);
23700
+ }
23608
23701
  const store = new DefaultTaskStore();
23609
23702
  const tracker = new TaskTracker({ store });
23610
- tracker.graph = phase.taskGraph;
23703
+ tracker.setGraph(phase.taskGraph);
23704
+ this.trackerCache.set(phase.id, tracker);
23611
23705
  return tracker;
23612
23706
  }
23613
23707
  getFailedTaskCount(phase) {
23614
- const tracker = this.getTrackerForPhase(phase);
23615
- return tracker.getAllNodes({ status: ["failed"] }).length;
23708
+ return this.getTrackerForPhase(phase).getAllNodes({ status: ["failed"] }).length;
23616
23709
  }
23617
23710
  getCompletedTaskCount(phase) {
23618
- const tracker = this.getTrackerForPhase(phase);
23619
- return tracker.getAllNodes({ status: ["completed"] }).length;
23711
+ return this.getTrackerForPhase(phase).getAllNodes({ status: ["completed"] }).length;
23620
23712
  }
23621
23713
  updatePhaseStatus(phase, status) {
23622
23714
  const from = phase.status;
@@ -23648,8 +23740,18 @@ var PhaseOrchestrator = class {
23648
23740
  // ─── Progress ─────────────────────────────────────────────────────────────
23649
23741
  getProgress() {
23650
23742
  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;
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;
23653
23755
  for (const p of phases) {
23654
23756
  switch (p.status) {
23655
23757
  case "pending":
@@ -23752,6 +23854,9 @@ var PhaseOrchestrator = class {
23752
23854
  }
23753
23855
  };
23754
23856
  }
23857
+ delay(ms) {
23858
+ return new Promise((resolve7) => setTimeout(resolve7, ms));
23859
+ }
23755
23860
  };
23756
23861
 
23757
23862
  // src/autophase/auto-phase-runner.ts
@@ -23760,6 +23865,26 @@ var AutoPhaseRunner = class {
23760
23865
  orchestrator = null;
23761
23866
  opts;
23762
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;
23763
23888
  constructor(opts) {
23764
23889
  this.opts = opts;
23765
23890
  }
@@ -23801,31 +23926,11 @@ var AutoPhaseRunner = class {
23801
23926
  this.opts.onProgress(progress);
23802
23927
  }, 2e3);
23803
23928
  }
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
- );
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);
23829
23934
  }
23830
23935
  await this.orchestrator.start();
23831
23936
  return this.graph;
@@ -23863,6 +23968,10 @@ var AutoPhaseRunner = class {
23863
23968
  clearInterval(this.progressInterval);
23864
23969
  this.progressInterval = null;
23865
23970
  }
23971
+ this.unsubscribeCompleted?.();
23972
+ this.unsubscribeCompleted = null;
23973
+ this.unsubscribeFailed?.();
23974
+ this.unsubscribeFailed = null;
23866
23975
  }
23867
23976
  };
23868
23977
  async function createAutoPhaseFromTaskGraph(taskGraph, options) {
@@ -23883,6 +23992,181 @@ async function createAutoPhaseFromTaskGraph(taskGraph, options) {
23883
23992
  phases
23884
23993
  });
23885
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
+ }
23886
24170
  var PhaseStore = class {
23887
24171
  baseDir;
23888
24172
  constructor(opts) {
@@ -24046,22 +24330,26 @@ var PhaseStore = class {
24046
24330
  specId: serialized.specId,
24047
24331
  title: serialized.title,
24048
24332
  nodes,
24049
- edges: serialized.edges,
24050
- rootNodes: serialized.rootNodes,
24333
+ edges: serialized.edges ?? [],
24334
+ rootNodes: serialized.rootNodes ?? [],
24051
24335
  createdAt: serialized.createdAt,
24052
24336
  updatedAt: serialized.updatedAt
24053
24337
  };
24054
24338
  }
24055
24339
  };
24056
-
24057
- // src/autophase/checkpoint.ts
24058
24340
  var CheckpointManager = class {
24059
24341
  store;
24060
24342
  maxCheckpoints;
24061
24343
  checkpoints = /* @__PURE__ */ new Map();
24344
+ baseDir;
24062
24345
  constructor(opts) {
24063
24346
  this.store = opts.store;
24064
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();
24065
24353
  }
24066
24354
  async saveCheckpoint(graph, label) {
24067
24355
  await this.store.save(graph);
@@ -24082,11 +24370,16 @@ var CheckpointManager = class {
24082
24370
  label
24083
24371
  };
24084
24372
  this.checkpoints.set(checkpoint.id, checkpoint);
24085
- this.pruneCheckpoints();
24373
+ await this.saveToDisk(checkpoint);
24374
+ await this.pruneCheckpoints();
24086
24375
  return checkpoint;
24087
24376
  }
24088
24377
  async restoreCheckpoint(checkpointId) {
24089
- const checkpoint = this.checkpoints.get(checkpointId);
24378
+ let checkpoint = this.checkpoints.get(checkpointId);
24379
+ if (!checkpoint) {
24380
+ await this.loadFromDisk();
24381
+ checkpoint = this.checkpoints.get(checkpointId);
24382
+ }
24090
24383
  if (!checkpoint) return null;
24091
24384
  const graph = await this.store.load(checkpoint.graphId);
24092
24385
  if (!graph) return null;
@@ -24110,20 +24403,103 @@ var CheckpointManager = class {
24110
24403
  const filtered = graphId ? all.filter((c) => c.graphId === graphId) : all;
24111
24404
  return filtered.sort((a, b) => b.timestamp - a.timestamp);
24112
24405
  }
24113
- deleteCheckpoint(checkpointId) {
24114
- return this.checkpoints.delete(checkpointId);
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");
24115
24430
  }
24116
- pruneCheckpoints() {
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() {
24117
24490
  const all = Array.from(this.checkpoints.values()).sort(
24118
24491
  (a, b) => a.timestamp - b.timestamp
24119
24492
  );
24120
24493
  while (all.length > this.maxCheckpoints) {
24121
24494
  const oldest = all.shift();
24122
- if (oldest) this.checkpoints.delete(oldest.id);
24495
+ if (oldest) {
24496
+ this.checkpoints.delete(oldest.id);
24497
+ await this.deleteFromDisk(oldest.id);
24498
+ }
24123
24499
  }
24124
24500
  }
24125
24501
  };
24126
24502
 
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 };
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 };
24128
24504
  //# sourceMappingURL=index.js.map
24129
24505
  //# sourceMappingURL=index.js.map