@spencer-kit/coder-studio 0.3.9 → 0.3.11

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/esm/bin.mjs CHANGED
@@ -1018,7 +1018,14 @@ var init_image = __esm({
1018
1018
 
1019
1019
  // packages/server/src/fs/file-io.ts
1020
1020
  import { createHash } from "crypto";
1021
- import { readFile as fsReadFile, writeFile as fsWriteFile, mkdir, rm, stat } from "fs/promises";
1021
+ import {
1022
+ readFile as fsReadFile,
1023
+ rename as fsRename,
1024
+ writeFile as fsWriteFile,
1025
+ mkdir,
1026
+ rm,
1027
+ stat
1028
+ } from "fs/promises";
1022
1029
  import { dirname as dirname2, isAbsolute, relative, resolve as resolve2 } from "path";
1023
1030
  async function statSafe(path10) {
1024
1031
  try {
@@ -1052,6 +1059,27 @@ async function deleteEntry(rootPath, relPath) {
1052
1059
  }
1053
1060
  await rm(abs, { recursive: true });
1054
1061
  }
1062
+ async function renameEntry(rootPath, fromPath, toPath) {
1063
+ const fromAbs = resolveSafe(rootPath, fromPath);
1064
+ const toAbs = resolveSafe(rootPath, toPath);
1065
+ const source = await statSafe(fromAbs);
1066
+ const target = await statSafe(toAbs);
1067
+ const fromParent = dirname2(fromAbs);
1068
+ const toParent = dirname2(toAbs);
1069
+ if (!source) {
1070
+ throw { code: "not_found", message: "Source not found" };
1071
+ }
1072
+ if (fromParent !== toParent) {
1073
+ throw {
1074
+ code: "rename_across_directories_not_supported",
1075
+ message: "Rename must stay within the current directory"
1076
+ };
1077
+ }
1078
+ if (target) {
1079
+ throw { code: "already_exists", message: "Target already exists" };
1080
+ }
1081
+ await fsRename(fromAbs, toAbs);
1082
+ }
1055
1083
  function resolveSafe(root, relPath) {
1056
1084
  const absRoot = resolve2(root);
1057
1085
  const abs = resolve2(absRoot, relPath);
@@ -1065,7 +1093,7 @@ async function readFile(workspaceId, rootPath, relPath) {
1065
1093
  const abs = resolveSafe(rootPath, relPath);
1066
1094
  const imageType = getImageTypeInfo(relPath);
1067
1095
  if (imageType) {
1068
- const stats = await stat(abs);
1096
+ const bytes = await fsReadFile(abs);
1069
1097
  const params = new URLSearchParams({
1070
1098
  workspaceId,
1071
1099
  path: relPath
@@ -1074,8 +1102,9 @@ async function readFile(workspaceId, rootPath, relPath) {
1074
1102
  kind: "image",
1075
1103
  mime: imageType.mime,
1076
1104
  url: `/api/file?${params.toString()}`,
1077
- size: stats.size,
1078
- isTextBacked: imageType.isTextBacked
1105
+ size: bytes.byteLength,
1106
+ isTextBacked: imageType.isTextBacked,
1107
+ version: createHash("sha256").update(bytes).digest("hex")
1079
1108
  };
1080
1109
  }
1081
1110
  const content = await fsReadFile(abs, "utf-8");
@@ -2031,12 +2060,12 @@ var init_auto_fetch = __esm({
2031
2060
  }
2032
2061
  acquireWorkspaceOperation(workspaceId) {
2033
2062
  const state = this.getOrCreateState(workspaceId);
2034
- return new Promise((resolve4) => {
2063
+ return new Promise((resolve5) => {
2035
2064
  const grant = () => {
2036
2065
  state.inFlight = true;
2037
2066
  state.nextFetchAt = void 0;
2038
2067
  let released = false;
2039
- resolve4(() => {
2068
+ resolve5(() => {
2040
2069
  if (released) {
2041
2070
  return;
2042
2071
  }
@@ -2064,7 +2093,7 @@ var init_auto_fetch = __esm({
2064
2093
  // packages/server/src/provider-runtime/command-runner.ts
2065
2094
  import { spawn } from "node:child_process";
2066
2095
  async function runCommandAsString(file, args, options) {
2067
- return new Promise((resolve4, reject) => {
2096
+ return new Promise((resolve5, reject) => {
2068
2097
  const child = spawn(file, args, {
2069
2098
  shell: shouldUseShellForCommand(file, process.platform),
2070
2099
  windowsHide: options?.windowsHide ?? true
@@ -2089,7 +2118,7 @@ async function runCommandAsString(file, args, options) {
2089
2118
  const stdout = Buffer.concat(stdoutChunks).toString("utf8");
2090
2119
  const stderr = Buffer.concat(stderrChunks).toString("utf8");
2091
2120
  if (code === 0) {
2092
- resolve4({ stdout, stderr });
2121
+ resolve5({ stdout, stderr });
2093
2122
  return;
2094
2123
  }
2095
2124
  reject(
@@ -2698,6 +2727,13 @@ ${details.stdout}`.toLowerCase();
2698
2727
  }
2699
2728
  });
2700
2729
 
2730
+ // packages/core/src/domain/diagnostics.ts
2731
+ var init_diagnostics = __esm({
2732
+ "packages/core/src/domain/diagnostics.ts"() {
2733
+ "use strict";
2734
+ }
2735
+ });
2736
+
2701
2737
  // packages/core/src/domain/events.ts
2702
2738
  var init_events = __esm({
2703
2739
  "packages/core/src/domain/events.ts"() {
@@ -2948,6 +2984,7 @@ var init_idle_heuristics2 = __esm({
2948
2984
  var init_src3 = __esm({
2949
2985
  "packages/core/src/index.ts"() {
2950
2986
  "use strict";
2987
+ init_diagnostics();
2951
2988
  init_events();
2952
2989
  init_mcp();
2953
2990
  init_provider_install();
@@ -5031,13 +5068,13 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
5031
5068
  return;
5032
5069
  }
5033
5070
  const arch = deps.arch ?? process.arch;
5034
- const resolve4 = deps.resolve ?? ((id) => require2.resolve(id));
5071
+ const resolve5 = deps.resolve ?? ((id) => require2.resolve(id));
5035
5072
  const fileExists = deps.existsSync ?? existsSync4;
5036
- const stat7 = deps.statSync ?? statSync;
5073
+ const stat8 = deps.statSync ?? statSync;
5037
5074
  const chmod = deps.chmodSync ?? chmodSync2;
5038
5075
  let packageJsonPath;
5039
5076
  try {
5040
- packageJsonPath = resolve4(NODE_PTY_PKG);
5077
+ packageJsonPath = resolve5(NODE_PTY_PKG);
5041
5078
  } catch {
5042
5079
  return;
5043
5080
  }
@@ -5051,7 +5088,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
5051
5088
  if (!fileExists(helperPath)) {
5052
5089
  return;
5053
5090
  }
5054
- const currentMode = stat7(helperPath).mode;
5091
+ const currentMode = stat8(helperPath).mode;
5055
5092
  const executableMode = currentMode | 73;
5056
5093
  if (executableMode === currentMode) {
5057
5094
  return;
@@ -5102,7 +5139,7 @@ async function escalateKillWithPolling(pid, signal, options) {
5102
5139
  const startTime = Date.now();
5103
5140
  const deadline = startTime + timeoutMs;
5104
5141
  while (Date.now() < deadline) {
5105
- await new Promise((resolve4) => setTimeout(resolve4, pollIntervalMs));
5142
+ await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
5106
5143
  if (!isProcessAlive(pid)) {
5107
5144
  return true;
5108
5145
  }
@@ -5254,38 +5291,107 @@ var init_settings = __esm({
5254
5291
 
5255
5292
  // packages/server/src/supervisor/evaluator.ts
5256
5293
  import { spawn as spawn2 } from "node:child_process";
5257
- function buildPrompt(context) {
5294
+ function buildPrompt(context, mode) {
5295
+ if (mode === "decompose") {
5296
+ return [
5297
+ "You are an autonomous supervisor for a target-scoped software task.",
5298
+ "Your first job is to decompose the target into a supervision structure before evaluation begins.",
5299
+ "",
5300
+ "Return JSON only.",
5301
+ "No prose before or after the JSON.",
5302
+ "",
5303
+ "Decomposition policy:",
5304
+ "- Do not ask the user any questions.",
5305
+ "- Do not ask for clarification, confirmation, or approval.",
5306
+ "- Do not propose options for the user to choose from.",
5307
+ "- If information is incomplete, make the most conservative reasonable assumptions and decide the decomposition yourself.",
5308
+ "- Your job is to return the best useful decomposition now, not to begin a discussion or planning workflow.",
5309
+ "- Keep the user-visible target as the top-level supervision owner.",
5310
+ '- Choose "stage" by default.',
5311
+ '- Choose "subtarget" only when the work clearly breaks into independently deliverable and independently verifiable workstreams.',
5312
+ "- If the distinction is unclear, choose stage.",
5313
+ "- Produce 1 to 7 decomposition items.",
5314
+ "- Each item must be concrete, milestone-sized, and useful for subsequent evaluation.",
5315
+ "- Do not leave the structure empty.",
5316
+ "",
5317
+ "Item requirements:",
5318
+ '- Each item must include "id", "kind", "title", "objective", "deliverable", "acceptanceCriteria", and "status".',
5319
+ '- "kind" must match the selected decompositionMode: all "stage" or all "subtarget".',
5320
+ '- "acceptanceCriteria" must be a non-empty string array.',
5321
+ '- Use statuses "pending", "in_progress", or "done".',
5322
+ "- Usually mark the first active item as in_progress and the rest as pending.",
5323
+ "",
5324
+ "Output schema:",
5325
+ "{",
5326
+ ' "mode": "decompose",',
5327
+ ' "decompositionMode": "stage" | "subtarget",',
5328
+ ' "items": [',
5329
+ ' { "id": string, "kind": "stage" | "subtarget", "title": string, "objective": string, "deliverable": string, "acceptanceCriteria": string[], "status": "pending" | "in_progress" | "done" }',
5330
+ " ],",
5331
+ ' "activeItemId": optional string,',
5332
+ ' "progressSummary": optional brief summary',
5333
+ "}",
5334
+ "",
5335
+ "Current objective:",
5336
+ context.objective,
5337
+ "",
5338
+ "Current target memory:",
5339
+ JSON.stringify(context.targetMemory, null, 2),
5340
+ "",
5341
+ "Latest user input:",
5342
+ context.latestUserInput?.trim() || "(none)",
5343
+ "",
5344
+ "Current terminal snapshot:",
5345
+ context.terminalExcerpt || "(no output yet)"
5346
+ ].join("\n");
5347
+ }
5258
5348
  const lines = [
5259
5349
  "You are an autonomous supervisor for a target-scoped software task.",
5260
5350
  "Your job is to keep the agent moving toward the objective until the objective is complete.",
5261
5351
  "",
5262
5352
  "Return JSON only.",
5353
+ "No prose before or after the JSON.",
5263
5354
  "",
5264
5355
  "Decision policy:",
5265
- '- Prefer "continue" whenever there is a reasonable next action.',
5356
+ '- Prefer "continue" over "stop" whenever the objective is not yet verified complete and there is a concrete next action.',
5357
+ '- "continue" may mean continuing the current item, verifying the current item, unblocking the current item, or advancing to the next item only after the current item is verified done.',
5266
5358
  "- Do not ask the user to decide, clarify, or choose among implementation options.",
5359
+ "- Do not tell the agent to ask the user to decide, clarify, or choose among implementation options unless continuing would likely be unsafe or clearly unsupported.",
5360
+ "- If the agent asks a question or presents multiple options, choose the most conservative reasonable option yourself and direct the next action.",
5361
+ "- If multiple reasonable paths exist, pick one and move forward unless doing so would be unsafe or clearly unsupported.",
5267
5362
  "- When information is incomplete, choose a conservative next action based on the objective, target memory, latest user input, and terminal snapshot.",
5363
+ "- Do not treat the agent's claims, summaries, or self-reports as sufficient evidence of completion.",
5268
5364
  "- Stop only when the objective is complete, or when continuing would likely push the agent in an unsafe or clearly unsupported direction.",
5269
5365
  "",
5270
5366
  "Stage decision policy:",
5271
5367
  "- Use the target memory as the current supervision state.",
5272
- "- Base your decision on the objective, current plan, activeStepId, progressSummary, lastGuidance, stalledCount, latest user input, and terminal snapshot.",
5273
- "- Identify which plan step is currently active.",
5274
- "- Decide whether the active step is done, still in progress, blocked, or obsolete.",
5275
- "- If the active step is done, advance to the next useful step.",
5276
- "- If the active step is still in progress, give guidance that moves it forward.",
5368
+ "- Base your decision on the objective, current decompositionMode, items, activeItemId, progressSummary, lastGuidance, stalledCount, latest user input, and terminal snapshot.",
5369
+ "- Identify which decomposition item is currently active.",
5370
+ "- Keep the current active item unless there is evidence that it is done, blocked, or obsolete.",
5371
+ "- Decide whether the active item is done, still in progress, blocked, or obsolete based on observable evidence.",
5372
+ '- Treat statements like "done", "fixed", "implemented", or "should pass" as unverified unless supported by observable evidence.',
5373
+ '- Mark an item as "done" only when there is observable evidence that its deliverable or acceptanceCriteria were satisfied.',
5374
+ "- Prefer evidence from terminal output, test results, build results, explicit verification output, or other observable artifacts in the terminal snapshot.",
5375
+ "- If evidence is missing or ambiguous, keep the item in_progress and direct the agent to gather or produce the missing verification evidence.",
5376
+ "- If the current item appears nearly complete but is not yet verified, keep the same active item and direct targeted verification.",
5377
+ "- Advance to the next item only after the current item's deliverable or acceptanceCriteria are supported by observable evidence.",
5378
+ '- When advancing to the next item, mark the previous item as "done" and set activeItemId to the next item explicitly.',
5379
+ "- If the active item is blocked, give guidance that is most likely to unblock it.",
5380
+ "- If the active item is obsolete, explain the reason briefly and move to the next useful item.",
5277
5381
  "- If the agent appears stuck or repeated the same action, give a different concrete next action.",
5278
- "- If the plan is obsolete, update only the affected steps unless a full replacement is necessary.",
5382
+ "- Do not rewrite the decomposition structure during normal evaluation cycles.",
5279
5383
  "",
5280
5384
  "Allowed statuses:",
5281
- '- "continue": more work is needed; include "reason" and "guidance".',
5385
+ '- "continue": supervision should continue; include "reason" and "guidance".',
5282
5386
  '- "stop": supervision should stop; include "stopReason" and "reason".',
5283
5387
  "",
5284
5388
  "Allowed stop reasons:",
5285
5389
  '- "objective_complete"',
5286
5390
  '- "supervisor_uncertain"',
5287
5391
  "",
5288
- 'Use "objective_complete" only when the objective has been satisfied.',
5392
+ 'Use "objective_complete" only when there is evidence that the objective and relevant acceptanceCriteria have been satisfied.',
5393
+ "- Do not stop only because the agent says the work is complete or because code changes exist without verification evidence.",
5394
+ "- If completion looks plausible but remains unverified, continue and require targeted verification.",
5289
5395
  'Use "supervisor_uncertain" only as a last resort when no useful next action can be inferred and additional guidance would likely be misleading.',
5290
5396
  "",
5291
5397
  'Guidance requirements for "continue":',
@@ -5293,30 +5399,32 @@ function buildPrompt(context) {
5293
5399
  "- Focus on the highest-value step toward completing the objective.",
5294
5400
  "- Be specific enough for the supervised agent to act without asking the user.",
5295
5401
  "- Avoid generic reminders, encouragement, or restating the objective.",
5296
- "- If verification is needed, tell the agent exactly what to verify next.",
5402
+ "- If verification is needed, tell the agent exactly what command, file, behavior, or artifact to verify next.",
5297
5403
  "- If implementation is needed, point to the likely area, behavior, or file/module based on available evidence.",
5404
+ "- If the agent asked a question, answer it directly in the guidance and continue with a concrete next action.",
5298
5405
  "",
5299
- "Planning policy:",
5300
- "- If planGenerated is false, include a plan with 3 to 7 milestone-sized steps.",
5301
- "- If planGenerated is true, update progress incrementally.",
5302
- "- Do not rewrite the full plan unless the existing plan is clearly wrong or obsolete.",
5303
- "- Use stepUpdates to mark completed or active steps when the terminal snapshot shows progress.",
5304
- "- Keep activeStepId aligned with the next useful step.",
5406
+ "Evaluation policy:",
5407
+ "- Update progress incrementally against the existing decomposition.",
5408
+ "- Use itemUpdates to reflect evidence-backed status changes only.",
5409
+ "- Keep activeItemId on the current item by default.",
5410
+ "- Change activeItemId only when there is a clear reason to switch items.",
5411
+ "- If evidence is missing or ambiguous, prefer verification over further implementation.",
5305
5412
  "",
5306
5413
  "Output schema:",
5307
5414
  "For continue:",
5308
5415
  "{",
5416
+ ' "mode": "evaluate",',
5309
5417
  ' "status": "continue",',
5310
5418
  ' "reason": "brief explanation of why more work is needed",',
5311
5419
  ' "guidance": "specific next action for the supervised agent",',
5312
- ' "plan": optional array of plan steps,',
5313
- ' "activeStepId": optional step id,',
5420
+ ' "activeItemId": optional item id,',
5314
5421
  ' "progressSummary": optional brief progress summary,',
5315
- ' "stepUpdates": optional array of { "id": string, "status": "pending" | "in_progress" | "done" }',
5422
+ ' "itemUpdates": optional array of { "id": string, "status": "pending" | "in_progress" | "done" }',
5316
5423
  "}",
5317
5424
  "",
5318
5425
  "For stop:",
5319
5426
  "{",
5427
+ ' "mode": "evaluate",',
5320
5428
  ' "status": "stop",',
5321
5429
  ' "stopReason": "objective_complete" | "supervisor_uncertain",',
5322
5430
  ' "reason": "brief explanation"',
@@ -5340,7 +5448,7 @@ async function runCommand(command, timeoutMs, options = {}) {
5340
5448
  if (options.signal?.aborted) {
5341
5449
  throw createSupervisorEvalAbortedError();
5342
5450
  }
5343
- return await new Promise((resolve4, reject) => {
5451
+ return await new Promise((resolve5, reject) => {
5344
5452
  const child = spawn2(command.argv[0], command.argv.slice(1), {
5345
5453
  cwd: command.cwd,
5346
5454
  detached: process.platform !== "win32",
@@ -5370,7 +5478,7 @@ async function runCommand(command, timeoutMs, options = {}) {
5370
5478
  }
5371
5479
  settled = true;
5372
5480
  cleanup();
5373
- resolve4(value);
5481
+ resolve5(value);
5374
5482
  };
5375
5483
  const terminate = (error) => {
5376
5484
  if (terminationError) {
@@ -5401,7 +5509,10 @@ async function runCommand(command, timeoutMs, options = {}) {
5401
5509
  settleReject(terminationError);
5402
5510
  return;
5403
5511
  }
5404
- settleReject(error);
5512
+ settleReject({
5513
+ code: "supervisor_eval_failed",
5514
+ message: error instanceof Error ? error.message : "Evaluator process failed to start"
5515
+ });
5405
5516
  });
5406
5517
  child.on("exit", (code) => {
5407
5518
  if (terminationError) {
@@ -5579,7 +5690,7 @@ function extractSupervisorPayload(output2, providerId) {
5579
5690
  }
5580
5691
  throw new Error("Supervisor did not return a recognizable message");
5581
5692
  }
5582
- function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5693
+ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars, requestedMode) {
5583
5694
  let parsed;
5584
5695
  try {
5585
5696
  parsed = JSON.parse(stripCodeFence(payloadText));
@@ -5592,9 +5703,49 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5592
5703
  throw new Error("Supervisor returned invalid evaluation payload");
5593
5704
  }
5594
5705
  const record = parsed;
5706
+ const payloadMode = record.mode;
5707
+ if (requestedMode === "decompose") {
5708
+ if (payloadMode !== "decompose") {
5709
+ throw new Error("Supervisor returned invalid decompose payload");
5710
+ }
5711
+ const decompositionMode = record.decompositionMode;
5712
+ if (decompositionMode !== "stage" && decompositionMode !== "subtarget") {
5713
+ throw new Error("Supervisor decompose result is missing a valid decompositionMode");
5714
+ }
5715
+ const items = Array.isArray(record.items) ? record.items.flatMap((value) => {
5716
+ if (!value || typeof value !== "object") {
5717
+ return [];
5718
+ }
5719
+ const item = value;
5720
+ if (typeof item.id !== "string" || item.kind !== "stage" && item.kind !== "subtarget" || item.kind !== decompositionMode || typeof item.title !== "string" || typeof item.objective !== "string" || typeof item.deliverable !== "string" || !Array.isArray(item.acceptanceCriteria) || item.acceptanceCriteria.length === 0 || item.acceptanceCriteria.some((entry) => typeof entry !== "string") || item.status !== "pending" && item.status !== "in_progress" && item.status !== "done") {
5721
+ return [];
5722
+ }
5723
+ return [
5724
+ {
5725
+ id: item.id,
5726
+ kind: item.kind,
5727
+ title: item.title,
5728
+ objective: item.objective,
5729
+ deliverable: item.deliverable,
5730
+ acceptanceCriteria: item.acceptanceCriteria,
5731
+ status: item.status
5732
+ }
5733
+ ];
5734
+ }) : [];
5735
+ if (items.length === 0) {
5736
+ throw new Error("Supervisor decompose result must include at least one valid item");
5737
+ }
5738
+ return {
5739
+ mode: "decompose",
5740
+ decompositionMode,
5741
+ items,
5742
+ activeItemId: typeof record.activeItemId === "string" && record.activeItemId.trim() ? record.activeItemId : void 0,
5743
+ progressSummary: typeof record.progressSummary === "string" && record.progressSummary.trim() ? record.progressSummary.trim() : void 0
5744
+ };
5745
+ }
5595
5746
  const status = record.status;
5596
5747
  const reason = record.reason;
5597
- if (status !== "continue" && status !== "stop" || typeof reason !== "string" || !reason.trim()) {
5748
+ if (payloadMode !== void 0 && payloadMode !== "evaluate" || status !== "continue" && status !== "stop" || typeof reason !== "string" || !reason.trim()) {
5598
5749
  throw new Error("Supervisor returned invalid evaluation payload");
5599
5750
  }
5600
5751
  if (status === "stop") {
@@ -5603,23 +5754,14 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5603
5754
  throw new Error("Supervisor stop result is missing a valid stopReason");
5604
5755
  }
5605
5756
  return {
5757
+ mode: "evaluate",
5606
5758
  status,
5607
5759
  stopReason,
5608
5760
  reason: reason.trim()
5609
5761
  };
5610
5762
  }
5611
5763
  const guidance = typeof record.guidance === "string" && record.guidance.trim() ? record.guidance.trim().slice(0, guidanceMaxChars) : void 0;
5612
- const plan = Array.isArray(record.plan) ? record.plan.flatMap((value) => {
5613
- if (!value || typeof value !== "object") {
5614
- return [];
5615
- }
5616
- const step = value;
5617
- if (typeof step.id !== "string" || typeof step.title !== "string" || step.status !== "pending" && step.status !== "in_progress" && step.status !== "done") {
5618
- return [];
5619
- }
5620
- return [{ id: step.id, title: step.title, status: step.status }];
5621
- }) : void 0;
5622
- const stepUpdates = Array.isArray(record.stepUpdates) ? record.stepUpdates.flatMap((value) => {
5764
+ const itemUpdates = Array.isArray(record.itemUpdates) ? record.itemUpdates.flatMap((value) => {
5623
5765
  if (!value || typeof value !== "object") {
5624
5766
  return [];
5625
5767
  }
@@ -5630,13 +5772,13 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5630
5772
  return [{ id: update.id, status: update.status }];
5631
5773
  }) : void 0;
5632
5774
  return {
5775
+ mode: "evaluate",
5633
5776
  status,
5634
5777
  reason: reason.trim(),
5635
5778
  guidance,
5636
- plan,
5637
- activeStepId: typeof record.activeStepId === "string" && record.activeStepId.trim() ? record.activeStepId : void 0,
5779
+ activeItemId: typeof record.activeItemId === "string" && record.activeItemId.trim() ? record.activeItemId : void 0,
5638
5780
  progressSummary: typeof record.progressSummary === "string" && record.progressSummary.trim() ? record.progressSummary.trim() : void 0,
5639
- stepUpdates
5781
+ itemUpdates
5640
5782
  };
5641
5783
  }
5642
5784
  var NOOP_LOGGER2, SupervisorEvaluator;
@@ -5688,7 +5830,8 @@ var init_evaluator = __esm({
5688
5830
  provider,
5689
5831
  this.deps.providerConfigRepo.get(provider.id)
5690
5832
  );
5691
- const prompt = buildPrompt(context);
5833
+ const mode = options.mode ?? "evaluate";
5834
+ const prompt = buildPrompt(context, mode);
5692
5835
  const command = provider.buildSupervisorEvalCommand(config, {
5693
5836
  prompt,
5694
5837
  sessionId: supervisor.sessionId,
@@ -5722,7 +5865,7 @@ var init_evaluator = __esm({
5722
5865
  );
5723
5866
  throw error;
5724
5867
  }
5725
- return parseSupervisorEvaluationResult(payloadText, this.config.guidanceMaxChars);
5868
+ return parseSupervisorEvaluationResult(payloadText, this.config.guidanceMaxChars, mode);
5726
5869
  }
5727
5870
  };
5728
5871
  }
@@ -5893,12 +6036,12 @@ var init_scheduler = __esm({
5893
6036
 
5894
6037
  // packages/server/src/supervisor/manager.ts
5895
6038
  function createDeferredCompletion() {
5896
- let resolve4 = () => {
6039
+ let resolve5 = () => {
5897
6040
  };
5898
6041
  const promise = new Promise((innerResolve) => {
5899
- resolve4 = innerResolve;
6042
+ resolve5 = innerResolve;
5900
6043
  });
5901
- return { promise, resolve: resolve4 };
6044
+ return { promise, resolve: resolve5 };
5902
6045
  }
5903
6046
  function generateSupervisorId() {
5904
6047
  return `sup_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
@@ -5924,6 +6067,12 @@ function messageOf(error, fallback) {
5924
6067
  function logFailure(logger, error, context, message) {
5925
6068
  logger.error({ ...context, err: error }, message);
5926
6069
  }
6070
+ function isDecomposeResult(result) {
6071
+ return result.mode === "decompose";
6072
+ }
6073
+ function isEvaluateStopResult(result) {
6074
+ return "status" in result && result.status === "stop";
6075
+ }
5927
6076
  function isSupervisorEvalAborted(error) {
5928
6077
  return !!error && typeof error === "object" && error.code === "supervisor_eval_aborted";
5929
6078
  }
@@ -6427,7 +6576,12 @@ var init_manager2 = __esm({
6427
6576
  turnId: context.lastTurnId,
6428
6577
  createdAt: Date.now()
6429
6578
  });
6430
- this.broadcastCycle(evaluatingSupervisor, activeCycle, "created");
6579
+ this.broadcastCycle(evaluatingSupervisor, activeCycle, "created", {
6580
+ phase: "waiting_evaluator",
6581
+ currentAttemptIndex: 0,
6582
+ attemptCount: 1,
6583
+ maxAttempts: 1 + retrySettings.retryMaxCount
6584
+ });
6431
6585
  return {
6432
6586
  cycle: activeCycle,
6433
6587
  supervisor: hydratedSupervisor,
@@ -6625,6 +6779,8 @@ var init_manager2 = __esm({
6625
6779
  }
6626
6780
  async executeCycleWithRetry(started, signal) {
6627
6781
  const supervisor = started.supervisor;
6782
+ let context = started.context;
6783
+ let currentMemory = context.targetMemory;
6628
6784
  for (let attemptIndex = 0; ; attemptIndex += 1) {
6629
6785
  const attempt = this.deps.cycleAttemptRepo.create({
6630
6786
  id: generateAttemptId(),
@@ -6633,23 +6789,79 @@ var init_manager2 = __esm({
6633
6789
  status: "evaluating",
6634
6790
  startedAt: Date.now()
6635
6791
  });
6792
+ this.broadcastCycle(started.supervisor, started.cycle, "updated", {
6793
+ phase: "waiting_evaluator",
6794
+ currentAttemptIndex: attemptIndex,
6795
+ attemptCount: attemptIndex + 1,
6796
+ maxAttempts: 1 + started.retry.retryMaxCount
6797
+ });
6636
6798
  try {
6637
- const evaluation = await this.evaluator.evaluate(supervisor, started.context, { signal });
6799
+ if (!currentMemory.decompositionGenerated || currentMemory.items.length === 0) {
6800
+ const decomposition = await this.evaluator.evaluate(supervisor, context, {
6801
+ signal,
6802
+ mode: "decompose"
6803
+ });
6804
+ if (!isDecomposeResult(decomposition)) {
6805
+ throw new Error("Supervisor decompose pass did not return a decomposition result");
6806
+ }
6807
+ currentMemory = {
6808
+ ...currentMemory,
6809
+ decompositionGenerated: true,
6810
+ decompositionMode: decomposition.decompositionMode,
6811
+ items: decomposition.items,
6812
+ activeItemId: decomposition.activeItemId,
6813
+ progressSummary: decomposition.progressSummary ?? currentMemory.progressSummary,
6814
+ updatedAt: Date.now()
6815
+ };
6816
+ const workspace = this.requireWorkspace(context.workspaceId);
6817
+ await this.deps.targetStore.saveTargetMemory(
6818
+ workspace.path,
6819
+ started.targetId,
6820
+ currentMemory
6821
+ );
6822
+ const currentSupervisor2 = this.supervisors.get(supervisor.id) ?? this.requireSupervisor(supervisor.id);
6823
+ if (currentSupervisor2.targetId === started.targetId) {
6824
+ const refreshed = this.attachCycles({
6825
+ ...currentSupervisor2,
6826
+ currentTargetMemory: currentMemory
6827
+ });
6828
+ this.storeSnapshot(refreshed);
6829
+ }
6830
+ context = {
6831
+ ...context,
6832
+ targetMemory: currentMemory
6833
+ };
6834
+ }
6835
+ const evaluation = await this.evaluator.evaluate(supervisor, context, {
6836
+ signal,
6837
+ mode: "evaluate"
6838
+ });
6638
6839
  this.deps.cycleAttemptRepo.update(attempt.id, {
6639
6840
  status: "completed",
6640
6841
  completedAt: Date.now(),
6641
6842
  providerModel: supervisor.evaluatorModel ?? null
6642
6843
  });
6643
- if (evaluation.status === "stop") {
6844
+ if (isDecomposeResult(evaluation)) {
6845
+ throw new Error("Supervisor evaluate pass returned a decompose result");
6846
+ }
6847
+ const nextTargetMemory = this.applyEvaluationToTargetMemory(
6848
+ currentMemory,
6849
+ evaluation,
6850
+ void 0,
6851
+ Date.now()
6852
+ );
6853
+ if (isEvaluateStopResult(evaluation)) {
6644
6854
  return {
6645
6855
  evaluation,
6646
- injected: false
6856
+ injected: false,
6857
+ targetMemory: nextTargetMemory
6647
6858
  };
6648
6859
  }
6649
6860
  if (!evaluation.guidance?.trim()) {
6650
6861
  return {
6651
6862
  evaluation,
6652
- injected: false
6863
+ injected: false,
6864
+ targetMemory: nextTargetMemory
6653
6865
  };
6654
6866
  }
6655
6867
  if (signal?.aborted || this.pendingPauses.has(supervisor.id)) {
@@ -6659,7 +6871,8 @@ var init_manager2 = __esm({
6659
6871
  if (currentSupervisor.targetId !== started.targetId) {
6660
6872
  return {
6661
6873
  evaluation,
6662
- injected: false
6874
+ injected: false,
6875
+ targetMemory: nextTargetMemory
6663
6876
  };
6664
6877
  }
6665
6878
  const injectingSupervisor = this.attachCycles(
@@ -6672,6 +6885,12 @@ var init_manager2 = __esm({
6672
6885
  );
6673
6886
  this.storeSnapshot(injectingSupervisor);
6674
6887
  this.broadcastState(injectingSupervisor, "state_changed");
6888
+ this.broadcastCycle(injectingSupervisor, started.cycle, "updated", {
6889
+ phase: "injecting",
6890
+ currentAttemptIndex: attemptIndex,
6891
+ attemptCount: attemptIndex + 1,
6892
+ maxAttempts: 1 + started.retry.retryMaxCount
6893
+ });
6675
6894
  const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== started.cycle.id);
6676
6895
  const injection = await this.injector.inject(
6677
6896
  injectingSupervisor,
@@ -6684,7 +6903,13 @@ var init_manager2 = __esm({
6684
6903
  return {
6685
6904
  evaluation,
6686
6905
  injected: injection.injected,
6687
- injectedText: injection.injected ? injection.text : void 0
6906
+ injectedText: injection.injected ? injection.text : void 0,
6907
+ targetMemory: this.applyEvaluationToTargetMemory(
6908
+ currentMemory,
6909
+ evaluation,
6910
+ injection.injected ? injection.text : void 0,
6911
+ Date.now()
6912
+ )
6688
6913
  };
6689
6914
  } catch (error) {
6690
6915
  if (isSupervisorEvalAborted(error)) {
@@ -6705,6 +6930,15 @@ var init_manager2 = __esm({
6705
6930
  if (!this.shouldRetryAttempt(error, attemptIndex, started.retry)) {
6706
6931
  throw error;
6707
6932
  }
6933
+ const nextRetryAt = Date.now() + started.retry.retryDelayMs;
6934
+ this.broadcastCycle(supervisor, started.cycle, "updated", {
6935
+ phase: "retry_wait",
6936
+ currentAttemptIndex: attemptIndex,
6937
+ attemptCount: attemptIndex + 1,
6938
+ maxAttempts: 1 + started.retry.retryMaxCount,
6939
+ lastAttemptError: reason,
6940
+ nextRetryAt
6941
+ });
6708
6942
  await this.sleep(started.retry.retryDelayMs, signal);
6709
6943
  const evaluatingSupervisor = this.attachCycles(
6710
6944
  this.withCurrentTargetState(
@@ -6722,9 +6956,9 @@ var init_manager2 = __esm({
6722
6956
  async finalizeSuccessfulCycle(activeCycle, context, result, targetId) {
6723
6957
  const workspace = this.requireWorkspace(context.workspaceId);
6724
6958
  const currentSupervisor = this.supervisors.get(activeCycle.supervisorId) ?? this.requireSupervisor(activeCycle.supervisorId);
6725
- const targetMemory = targetId === currentSupervisor.targetId && currentSupervisor.currentTargetMemory ? currentSupervisor.currentTargetMemory : await this.deps.targetStore.loadTargetMemory(workspace.path, targetId);
6959
+ const evaluation = result.evaluation;
6726
6960
  const finalStatus = result.injected ? "injected" : "completed";
6727
- const cycleReason = result.evaluation.status === "stop" ? result.evaluation.reason : result.injected ? result.injectedText : result.evaluation.guidance ? `Skipped duplicate: ${result.evaluation.guidance}` : void 0;
6961
+ const cycleReason = isEvaluateStopResult(evaluation) ? evaluation.reason : result.injected ? result.injectedText : evaluation.guidance ? `Skipped duplicate: ${evaluation.guidance}` : void 0;
6728
6962
  const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
6729
6963
  status: finalStatus,
6730
6964
  result: cycleReason ?? null,
@@ -6732,24 +6966,22 @@ var init_manager2 = __esm({
6732
6966
  errorReason: null,
6733
6967
  completedAt: Date.now()
6734
6968
  });
6735
- const nextTargetMemory = this.applyEvaluationToTargetMemory(
6736
- targetMemory,
6737
- result.evaluation,
6738
- result.injectedText,
6739
- finishedCycle.completedAt ?? Date.now()
6740
- );
6969
+ const nextTargetMemory = {
6970
+ ...result.targetMemory,
6971
+ updatedAt: finishedCycle.completedAt ?? Date.now()
6972
+ };
6741
6973
  await this.deps.targetStore.saveTargetMemory(workspace.path, targetId, nextTargetMemory);
6742
- const cycleRecord = result.evaluation.status === "stop" ? {
6974
+ const cycleRecord = isEvaluateStopResult(evaluation) ? {
6743
6975
  cycleId: activeCycle.id,
6744
6976
  targetId,
6745
6977
  startedAt: activeCycle.createdAt,
6746
6978
  completedAt: finishedCycle.completedAt ?? Date.now(),
6747
6979
  result: "stop",
6748
- stopReason: result.evaluation.stopReason,
6749
- reason: result.evaluation.reason,
6750
- progressSummary: result.evaluation.progressSummary ?? nextTargetMemory.progressSummary,
6751
- activeStepId: result.evaluation.activeStepId ?? nextTargetMemory.activeStepId,
6752
- stepUpdates: result.evaluation.stepUpdates,
6980
+ stopReason: evaluation.stopReason,
6981
+ reason: evaluation.reason,
6982
+ progressSummary: nextTargetMemory.progressSummary,
6983
+ decompositionMode: nextTargetMemory.decompositionMode,
6984
+ activeItemId: nextTargetMemory.activeItemId,
6753
6985
  injected: false,
6754
6986
  attemptCount: this.deps.cycleAttemptRepo.listForCycle(activeCycle.id).length
6755
6987
  } : {
@@ -6758,18 +6990,19 @@ var init_manager2 = __esm({
6758
6990
  startedAt: activeCycle.createdAt,
6759
6991
  completedAt: finishedCycle.completedAt ?? Date.now(),
6760
6992
  result: "continue",
6761
- reason: result.evaluation.reason,
6762
- guidance: result.injected ? result.injectedText : result.evaluation.guidance,
6993
+ reason: evaluation.reason,
6994
+ guidance: result.injected ? result.injectedText : evaluation.guidance,
6763
6995
  progressSummary: nextTargetMemory.progressSummary,
6764
- activeStepId: nextTargetMemory.activeStepId,
6765
- stepUpdates: result.evaluation.stepUpdates,
6996
+ decompositionMode: nextTargetMemory.decompositionMode,
6997
+ activeItemId: nextTargetMemory.activeItemId,
6998
+ itemUpdates: evaluation.itemUpdates,
6766
6999
  injected: result.injected,
6767
7000
  attemptCount: this.deps.cycleAttemptRepo.listForCycle(activeCycle.id).length
6768
7001
  };
6769
7002
  await this.deps.targetStore.appendTargetCycleRecord(workspace.path, targetId, cycleRecord);
6770
- if (result.evaluation.status === "stop") {
7003
+ if (isEvaluateStopResult(evaluation)) {
6771
7004
  await this.updateTargetMetaStatus(workspace.path, targetId, {
6772
- status: result.evaluation.stopReason === "objective_complete" ? "completed" : "cancelled",
7005
+ status: evaluation.stopReason === "objective_complete" ? "completed" : "cancelled",
6773
7006
  completedAt: finishedCycle.completedAt ?? Date.now()
6774
7007
  });
6775
7008
  }
@@ -6786,9 +7019,9 @@ var init_manager2 = __esm({
6786
7019
  const finishedSupervisor = this.attachCycles(
6787
7020
  this.withCurrentTargetState(
6788
7021
  this.deps.supervisorRepo.update(activeCycle.supervisorId, {
6789
- state: result.evaluation.status === "stop" ? "stopped" : "idle",
7022
+ state: isEvaluateStopResult(result.evaluation) ? "stopped" : "idle",
6790
7023
  completedSupervisionCount: (this.supervisors.get(activeCycle.supervisorId)?.completedSupervisionCount ?? 0) + 1,
6791
- stopReason: result.evaluation.status === "stop" ? result.evaluation.stopReason : null,
7024
+ stopReason: isEvaluateStopResult(evaluation) ? evaluation.stopReason : null,
6792
7025
  lastCycleAt: finishedCycle.completedAt,
6793
7026
  lastEvaluatedTurnId: context.lastTurnId ?? void 0,
6794
7027
  errorReason: null,
@@ -6942,23 +7175,46 @@ var init_manager2 = __esm({
6942
7175
  };
6943
7176
  }
6944
7177
  applyEvaluationToTargetMemory(memory, evaluation, injectedText, updatedAt) {
6945
- let plan = memory.plan;
6946
- if (evaluation.plan && evaluation.plan.length > 0) {
6947
- plan = evaluation.plan;
6948
- } else if (evaluation.stepUpdates?.length) {
6949
- const updates = new Map(evaluation.stepUpdates.map((step) => [step.id, step.status]));
6950
- plan = memory.plan.map(
6951
- (step) => updates.has(step.id) ? { ...step, status: updates.get(step.id) } : step
7178
+ if (isDecomposeResult(evaluation)) {
7179
+ return {
7180
+ ...memory,
7181
+ decompositionGenerated: true,
7182
+ decompositionMode: evaluation.decompositionMode,
7183
+ items: evaluation.items,
7184
+ activeItemId: evaluation.activeItemId,
7185
+ progressSummary: evaluation.progressSummary ?? memory.progressSummary,
7186
+ updatedAt
7187
+ };
7188
+ }
7189
+ if (isEvaluateStopResult(evaluation)) {
7190
+ return {
7191
+ ...memory,
7192
+ decompositionGenerated: memory.decompositionGenerated,
7193
+ decompositionMode: memory.decompositionMode,
7194
+ items: memory.items,
7195
+ activeItemId: memory.activeItemId,
7196
+ progressSummary: memory.progressSummary,
7197
+ lastGuidance: memory.lastGuidance,
7198
+ stalledCount: 0,
7199
+ updatedAt
7200
+ };
7201
+ }
7202
+ let items = memory.items;
7203
+ if (evaluation.itemUpdates?.length) {
7204
+ const updates = new Map(evaluation.itemUpdates.map((item) => [item.id, item.status]));
7205
+ items = memory.items.map(
7206
+ (item) => updates.has(item.id) ? { ...item, status: updates.get(item.id) } : item
6952
7207
  );
6953
7208
  }
6954
7209
  const progressSummary = evaluation.progressSummary ?? memory.progressSummary;
6955
- const lastGuidance = evaluation.status === "continue" ? injectedText ?? evaluation.guidance ?? memory.lastGuidance : memory.lastGuidance;
6956
- const stalledCount = evaluation.status === "continue" && !evaluation.progressSummary && !evaluation.stepUpdates?.length ? memory.stalledCount + 1 : 0;
7210
+ const lastGuidance = injectedText ?? evaluation.guidance ?? memory.lastGuidance;
7211
+ const stalledCount = !evaluation.progressSummary && !evaluation.itemUpdates?.length ? memory.stalledCount + 1 : 0;
6957
7212
  return {
6958
7213
  ...memory,
6959
- planGenerated: memory.planGenerated || Boolean(evaluation.plan?.length),
6960
- plan,
6961
- activeStepId: evaluation.activeStepId ?? memory.activeStepId,
7214
+ decompositionGenerated: memory.decompositionGenerated,
7215
+ decompositionMode: memory.decompositionMode,
7216
+ items,
7217
+ activeItemId: evaluation.activeItemId ?? memory.activeItemId,
6962
7218
  progressSummary,
6963
7219
  lastGuidance,
6964
7220
  stalledCount,
@@ -7081,10 +7337,10 @@ var init_manager2 = __esm({
7081
7337
  { supervisor, event }
7082
7338
  );
7083
7339
  }
7084
- broadcastCycle(supervisor, cycle, event) {
7340
+ broadcastCycle(supervisor, cycle, event, runtime) {
7085
7341
  this.deps.broadcaster.broadcast(
7086
7342
  Topics.supervisorCycle(supervisor.workspaceId, supervisor.sessionId),
7087
- { cycle, event }
7343
+ { cycle: runtime ? { ...cycle, runtime } : cycle, event }
7088
7344
  );
7089
7345
  }
7090
7346
  shouldRetryAttempt(error, attemptIndex, retry) {
@@ -7110,10 +7366,10 @@ var init_manager2 = __esm({
7110
7366
  if (signal?.aborted) {
7111
7367
  throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
7112
7368
  }
7113
- await new Promise((resolve4, reject) => {
7369
+ await new Promise((resolve5, reject) => {
7114
7370
  const timer = setTimeout(() => {
7115
7371
  signal?.removeEventListener("abort", onAbort);
7116
- resolve4();
7372
+ resolve5();
7117
7373
  }, delayMs);
7118
7374
  timer.unref?.();
7119
7375
  const onAbort = () => {
@@ -7181,6 +7437,119 @@ function errorMessage(error, fallback) {
7181
7437
  }
7182
7438
  return fallback;
7183
7439
  }
7440
+ function isRecord(value) {
7441
+ return Boolean(value) && typeof value === "object";
7442
+ }
7443
+ function readNonEmptyString(value) {
7444
+ if (typeof value !== "string") {
7445
+ return void 0;
7446
+ }
7447
+ const next = value.trim();
7448
+ return next ? next : void 0;
7449
+ }
7450
+ function readStatus(value) {
7451
+ return value === "in_progress" || value === "done" || value === "pending" ? value : "pending";
7452
+ }
7453
+ function readDecompositionMode(value) {
7454
+ return value === "stage" || value === "subtarget" ? value : void 0;
7455
+ }
7456
+ function readNonNegativeInteger(value, fallback) {
7457
+ if (!Number.isSafeInteger(value) || typeof value !== "number" || value < 0) {
7458
+ return fallback;
7459
+ }
7460
+ return value;
7461
+ }
7462
+ function readTimestamp(value, fallback) {
7463
+ if (!Number.isSafeInteger(value) || typeof value !== "number") {
7464
+ return fallback;
7465
+ }
7466
+ return value;
7467
+ }
7468
+ function fallbackAcceptanceCriteria(title) {
7469
+ return [`${title} is complete`];
7470
+ }
7471
+ function normalizeItem(value, fallbackKind) {
7472
+ if (!isRecord(value)) {
7473
+ return null;
7474
+ }
7475
+ const id = readNonEmptyString(value.id);
7476
+ const title = readNonEmptyString(value.title);
7477
+ if (!id || !title) {
7478
+ return null;
7479
+ }
7480
+ const kind = readDecompositionMode(value.kind) ?? fallbackKind ?? "stage";
7481
+ const objective = readNonEmptyString(value.objective) ?? title;
7482
+ const deliverable = readNonEmptyString(value.deliverable) ?? `${title} completed`;
7483
+ const acceptanceCriteria = Array.isArray(value.acceptanceCriteria) ? value.acceptanceCriteria.flatMap((entry) => {
7484
+ const next = readNonEmptyString(entry);
7485
+ return next ? [next] : [];
7486
+ }) : [];
7487
+ return {
7488
+ id,
7489
+ kind,
7490
+ title,
7491
+ objective,
7492
+ deliverable,
7493
+ acceptanceCriteria: acceptanceCriteria.length > 0 ? acceptanceCriteria : fallbackAcceptanceCriteria(title),
7494
+ status: readStatus(value.status)
7495
+ };
7496
+ }
7497
+ function normalizeLegacyPlanItems(plan) {
7498
+ if (!Array.isArray(plan)) {
7499
+ return [];
7500
+ }
7501
+ return plan.flatMap((value) => {
7502
+ const item = normalizeItem(
7503
+ isRecord(value) ? {
7504
+ id: value.id,
7505
+ kind: "stage",
7506
+ title: value.title,
7507
+ objective: value.title,
7508
+ deliverable: `${readNonEmptyString(value.title) ?? "Legacy step"} completed`,
7509
+ acceptanceCriteria: fallbackAcceptanceCriteria(
7510
+ readNonEmptyString(value.title) ?? "Legacy step"
7511
+ ),
7512
+ status: value.status
7513
+ } : value,
7514
+ "stage"
7515
+ );
7516
+ return item ? [item] : [];
7517
+ });
7518
+ }
7519
+ function resolveActiveItemId(items, candidate) {
7520
+ const next = readNonEmptyString(candidate);
7521
+ if (next && items.some((item) => item.id === next)) {
7522
+ return next;
7523
+ }
7524
+ return items.find((item) => item.status === "in_progress")?.id ?? items.find((item) => item.status === "pending")?.id ?? items[0]?.id;
7525
+ }
7526
+ function normalizeTargetMemory(raw, targetId) {
7527
+ if (!isRecord(raw)) {
7528
+ return buildTargetMemory(targetId, 0);
7529
+ }
7530
+ const updatedAt = readTimestamp(raw.updatedAt, 0);
7531
+ const declaredMode = readDecompositionMode(raw.decompositionMode);
7532
+ let items = Array.isArray(raw.items) ? raw.items.flatMap((value) => {
7533
+ const item = normalizeItem(value, declaredMode);
7534
+ return item ? [item] : [];
7535
+ }) : [];
7536
+ let decompositionMode = declaredMode ?? items[0]?.kind;
7537
+ if (items.length === 0) {
7538
+ items = normalizeLegacyPlanItems(raw.plan);
7539
+ decompositionMode = items.length > 0 ? "stage" : void 0;
7540
+ }
7541
+ return {
7542
+ targetId: readNonEmptyString(raw.targetId) ?? targetId,
7543
+ decompositionGenerated: items.length > 0,
7544
+ decompositionMode,
7545
+ items,
7546
+ activeItemId: resolveActiveItemId(items, raw.activeItemId ?? raw.activeStepId),
7547
+ progressSummary: readNonEmptyString(raw.progressSummary),
7548
+ lastGuidance: readNonEmptyString(raw.lastGuidance),
7549
+ stalledCount: readNonNegativeInteger(raw.stalledCount, 0),
7550
+ updatedAt
7551
+ };
7552
+ }
7184
7553
  async function writeJsonIfMissing(path10, value) {
7185
7554
  try {
7186
7555
  await writeFile3(path10, JSON.stringify(value, null, 2) + "\n", {
@@ -7209,8 +7578,12 @@ function buildTargetMeta(input2) {
7209
7578
  function buildTargetMemory(targetId, createdAt) {
7210
7579
  return {
7211
7580
  targetId,
7212
- planGenerated: false,
7213
- plan: [],
7581
+ decompositionGenerated: false,
7582
+ decompositionMode: void 0,
7583
+ items: [],
7584
+ activeItemId: void 0,
7585
+ progressSummary: void 0,
7586
+ lastGuidance: void 0,
7214
7587
  stalledCount: 0,
7215
7588
  updatedAt: createdAt
7216
7589
  };
@@ -7299,8 +7672,9 @@ async function readTargetMeta(workspacePath, targetId) {
7299
7672
  );
7300
7673
  }
7301
7674
  async function loadTargetMemory(workspacePath, targetId) {
7302
- return JSON.parse(
7303
- await readFile2(memoryPath(workspacePath, targetId), "utf-8")
7675
+ return normalizeTargetMemory(
7676
+ JSON.parse(await readFile2(memoryPath(workspacePath, targetId), "utf-8")),
7677
+ targetId
7304
7678
  );
7305
7679
  }
7306
7680
  async function saveTargetMemory(workspacePath, targetId, memory) {
@@ -7637,8 +8011,8 @@ var init_terminal_snapshot_buffer = __esm({
7637
8011
  if (this.pendingWriteCount === 0) {
7638
8012
  return Promise.resolve();
7639
8013
  }
7640
- return new Promise((resolve4) => {
7641
- this.drainResolvers.push(resolve4);
8014
+ return new Promise((resolve5) => {
8015
+ this.drainResolvers.push(resolve5);
7642
8016
  });
7643
8017
  }
7644
8018
  resolveDrainIfIdle() {
@@ -7647,8 +8021,8 @@ var init_terminal_snapshot_buffer = __esm({
7647
8021
  }
7648
8022
  const resolvers = this.drainResolvers;
7649
8023
  this.drainResolvers = [];
7650
- for (const resolve4 of resolvers) {
7651
- resolve4();
8024
+ for (const resolve5 of resolvers) {
8025
+ resolve5();
7652
8026
  }
7653
8027
  }
7654
8028
  requireTerminal() {
@@ -7967,10 +8341,10 @@ var init_manager3 = __esm({
7967
8341
  }
7968
8342
  return existing.promise;
7969
8343
  }
7970
- let resolve4 = () => {
8344
+ let resolve5 = () => {
7971
8345
  };
7972
8346
  const promise = new Promise((innerResolve) => {
7973
- resolve4 = innerResolve;
8347
+ resolve5 = innerResolve;
7974
8348
  });
7975
8349
  let markKillCompleted = () => {
7976
8350
  };
@@ -7983,7 +8357,7 @@ var init_manager3 = __esm({
7983
8357
  markKillCompleted,
7984
8358
  finalized: false,
7985
8359
  promise,
7986
- resolve: resolve4
8360
+ resolve: resolve5
7987
8361
  });
7988
8362
  void terminal.pty.kill(signal).finally(() => {
7989
8363
  const waiter = this.explicitCloseWaiters.get(terminalId);
@@ -8190,20 +8564,8 @@ function createTreeVisibilityFilter() {
8190
8564
  return (name) => !isTreeHidden(name);
8191
8565
  }
8192
8566
  function createWatcherIgnoreFilter(rootPath) {
8193
- const gitignorePath = join5(rootPath, ".gitignore");
8194
- if (!existsSync5(gitignorePath)) {
8195
- return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
8196
- }
8197
- const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
8198
- const ig = ignore().add(gitignoreContent);
8199
- return (path10) => {
8200
- const normalizedPath = normalizePath(path10);
8201
- if (DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizedPath))) {
8202
- return true;
8203
- }
8204
- const relativePath = relativeToRoot(rootPath, path10);
8205
- return isIgnoredByGitignore(ig, relativePath);
8206
- };
8567
+ void rootPath;
8568
+ return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
8207
8569
  }
8208
8570
  var DEFAULT_WATCHER_IGNORED_PATTERNS;
8209
8571
  var init_gitignore = __esm({
@@ -8268,11 +8630,11 @@ var init_watcher = __esm({
8268
8630
  this.pendingReason = "fs_change";
8269
8631
  }
8270
8632
  const elapsed = now - this.firstDirtyTime;
8271
- const delay = Math.min(this.DEBOUNCE_MS, Math.max(0, this.MAX_WAIT_MS - elapsed));
8633
+ const delay2 = Math.min(this.DEBOUNCE_MS, Math.max(0, this.MAX_WAIT_MS - elapsed));
8272
8634
  if (this.dirtyTimer) {
8273
8635
  clearTimeout(this.dirtyTimer);
8274
8636
  }
8275
- this.dirtyTimer = setTimeout(() => this.flushDirty(), delay);
8637
+ this.dirtyTimer = setTimeout(() => this.flushDirty(), delay2);
8276
8638
  }
8277
8639
  flushDirty() {
8278
8640
  this.broadcaster?.broadcast(Topics.workspaceFsDirty(this.workspaceId), {
@@ -8870,7 +9232,8 @@ var init_fencing = __esm({
8870
9232
  });
8871
9233
 
8872
9234
  // packages/server/src/commands/terminal.ts
8873
- import { basename } from "node:path";
9235
+ import { stat as stat6 } from "node:fs/promises";
9236
+ import { basename, isAbsolute as isAbsolute3 } from "node:path";
8874
9237
  import { z as z5 } from "zod";
8875
9238
  function decodeTerminalInput(args) {
8876
9239
  if ("bytes" in args) {
@@ -8941,6 +9304,7 @@ var init_terminal = __esm({
8941
9304
  "packages/server/src/commands/terminal.ts"() {
8942
9305
  "use strict";
8943
9306
  init_src3();
9307
+ init_file_io();
8944
9308
  init_dispatch();
8945
9309
  TerminalInputActivitySchema = z5.enum(TERMINAL_INPUT_ACTIVITIES).optional();
8946
9310
  TerminalInputSchema = z5.union([
@@ -8975,20 +9339,44 @@ var init_terminal = __esm({
8975
9339
  z5.object({
8976
9340
  workspaceId: z5.string(),
8977
9341
  cols: z5.number().int().positive().optional(),
8978
- rows: z5.number().int().positive().optional()
9342
+ rows: z5.number().int().positive().optional(),
9343
+ cwdPath: z5.string().optional()
8979
9344
  }),
8980
9345
  async (args, ctx) => {
8981
9346
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
8982
9347
  if (!workspace) {
8983
9348
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
8984
9349
  }
9350
+ let cwd = workspace.path;
9351
+ if (args.cwdPath && args.cwdPath !== ".") {
9352
+ if (isAbsolute3(args.cwdPath)) {
9353
+ throw { code: "invalid_cwd_path", message: "cwdPath must be workspace-relative" };
9354
+ }
9355
+ let resolvedCwd;
9356
+ try {
9357
+ resolvedCwd = resolveSafe(workspace.path, args.cwdPath);
9358
+ } catch (error) {
9359
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "path_escape") {
9360
+ throw { code: "invalid_cwd_path", message: "cwdPath must be workspace-relative" };
9361
+ }
9362
+ throw error;
9363
+ }
9364
+ const cwdStats = await stat6(resolvedCwd).catch(() => null);
9365
+ if (!cwdStats) {
9366
+ throw { code: "cwd_not_found", message: `Directory not found: ${args.cwdPath}` };
9367
+ }
9368
+ if (!cwdStats.isDirectory()) {
9369
+ throw { code: "cwd_not_directory", message: `Not a directory: ${args.cwdPath}` };
9370
+ }
9371
+ cwd = resolvedCwd;
9372
+ }
8985
9373
  const shell = resolveShellCommand();
8986
9374
  const terminal = ctx.terminalMgr.create({
8987
9375
  workspaceId: args.workspaceId,
8988
9376
  kind: "shell",
8989
9377
  argv: shell.argv,
8990
9378
  title: shell.title,
8991
- cwd: workspace.path,
9379
+ cwd,
8992
9380
  cols: args.cols ?? 120,
8993
9381
  rows: args.rows ?? 30
8994
9382
  });
@@ -9674,7 +10062,7 @@ var init_hub = __esm({
9674
10062
  }
9675
10063
  }
9676
10064
  awaitBinaryPayload(clientId) {
9677
- return new Promise((resolve4, reject) => {
10065
+ return new Promise((resolve5, reject) => {
9678
10066
  const timer = setTimeout(() => {
9679
10067
  const waiters = this.pendingBinaryWaiters.get(clientId);
9680
10068
  if (!waiters) return;
@@ -9686,7 +10074,7 @@ var init_hub = __esm({
9686
10074
  }
9687
10075
  reject(new Error("Timeout waiting for terminal input binary payload"));
9688
10076
  }, BINARY_PAYLOAD_TIMEOUT_MS);
9689
- const waiter = { resolve: resolve4, reject, timer };
10077
+ const waiter = { resolve: resolve5, reject, timer };
9690
10078
  const queue = this.pendingBinaryWaiters.get(clientId);
9691
10079
  if (queue) {
9692
10080
  queue.push(waiter);
@@ -9964,10 +10352,34 @@ var init_hub = __esm({
9964
10352
  });
9965
10353
 
9966
10354
  // packages/server/src/commands/workspace.ts
9967
- import { readdir as readdir2 } from "node:fs/promises";
10355
+ import { readdir as readdir2, realpath as realpath2 } from "node:fs/promises";
9968
10356
  import { homedir as homedir2 } from "node:os";
9969
- import { join as join6 } from "node:path";
10357
+ import { isAbsolute as isAbsolute4, join as join6, resolve as resolve3 } from "node:path";
9970
10358
  import { z as z6 } from "zod";
10359
+ function resolveBrowsePath(path10) {
10360
+ const home = homedir2();
10361
+ if (!path10 || path10 === "~") {
10362
+ return home;
10363
+ }
10364
+ if (path10.startsWith("~/")) {
10365
+ return join6(home, path10.slice(2));
10366
+ }
10367
+ return isAbsolute4(path10) ? path10 : resolve3(home, path10);
10368
+ }
10369
+ async function buildRootPaths(currentPath) {
10370
+ const roots = /* @__PURE__ */ new Set(["/"]);
10371
+ const home = homedir2();
10372
+ roots.add(home);
10373
+ try {
10374
+ roots.add(await realpath2(home));
10375
+ } catch {
10376
+ }
10377
+ const currentSegments = currentPath.split("/").filter(Boolean);
10378
+ if (currentSegments.length > 0) {
10379
+ roots.add(`/${currentSegments[0]}`);
10380
+ }
10381
+ return Array.from(roots);
10382
+ }
9971
10383
  var init_workspace = __esm({
9972
10384
  "packages/server/src/commands/workspace.ts"() {
9973
10385
  "use strict";
@@ -9981,7 +10393,7 @@ var init_workspace = __esm({
9981
10393
  path: z6.string().optional()
9982
10394
  }),
9983
10395
  async (args) => {
9984
- const basePath = args.path || homedir2();
10396
+ const basePath = resolveBrowsePath(args.path);
9985
10397
  const entries = await readdir2(basePath, { withFileTypes: true });
9986
10398
  const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
9987
10399
  name: entry.name,
@@ -9990,7 +10402,8 @@ var init_workspace = __esm({
9990
10402
  return {
9991
10403
  currentPath: basePath,
9992
10404
  parentPath: basePath !== "/" ? join6(basePath, "..") : null,
9993
- directories
10405
+ directories,
10406
+ rootPaths: await buildRootPaths(basePath)
9994
10407
  };
9995
10408
  }
9996
10409
  );
@@ -10023,6 +10436,7 @@ var init_workspace = __esm({
10023
10436
  bottomPanelHeight: z6.number(),
10024
10437
  focusMode: z6.boolean(),
10025
10438
  activeSessionId: z6.string().optional(),
10439
+ fileTreeExpandedDirs: z6.array(z6.string()).optional(),
10026
10440
  paneLayout: z6.object({
10027
10441
  id: z6.string(),
10028
10442
  type: z6.enum(["leaf", "split"]),
@@ -10286,16 +10700,105 @@ var init_runtime_status = __esm({
10286
10700
  }
10287
10701
  });
10288
10702
 
10703
+ // packages/server/src/workspace/pane-layout.ts
10704
+ function applyPaneDisposition(layout, sessionId, disposition) {
10705
+ if (!layout) {
10706
+ return layout;
10707
+ }
10708
+ return disposition === "remove" ? removePaneBySessionId(layout, sessionId) : closePaneBySessionId(layout, sessionId);
10709
+ }
10710
+ function closePaneBySessionId(node, sessionId) {
10711
+ return replaceSessionWithDraft(node, sessionId);
10712
+ }
10713
+ function replaceSessionWithDraft(node, sessionId) {
10714
+ if (node.type === "leaf") {
10715
+ if (node.sessionId === sessionId) {
10716
+ return {
10717
+ id: node.id,
10718
+ type: "leaf"
10719
+ };
10720
+ }
10721
+ return node;
10722
+ }
10723
+ const children = node.children ?? [];
10724
+ let changed = false;
10725
+ const nextChildren = children.map((child) => {
10726
+ const nextChild = replaceSessionWithDraft(child, sessionId);
10727
+ if (nextChild !== child) {
10728
+ changed = true;
10729
+ }
10730
+ return nextChild;
10731
+ });
10732
+ if (!changed) {
10733
+ return node;
10734
+ }
10735
+ return {
10736
+ ...node,
10737
+ children: nextChildren
10738
+ };
10739
+ }
10740
+ function removePaneBySessionId(node, sessionId) {
10741
+ return removeSessionPane(node, sessionId) ?? { id: node.id, type: "leaf" };
10742
+ }
10743
+ function removeSessionPane(node, sessionId) {
10744
+ if (node.type === "leaf") {
10745
+ if (node.sessionId === sessionId) {
10746
+ return null;
10747
+ }
10748
+ return node;
10749
+ }
10750
+ const children = node.children ?? [];
10751
+ let changed = false;
10752
+ const nextChildren = [];
10753
+ for (const child of children) {
10754
+ const nextChild = removeSessionPane(child, sessionId);
10755
+ if (nextChild !== child) {
10756
+ changed = true;
10757
+ }
10758
+ if (nextChild !== null) {
10759
+ nextChildren.push(nextChild);
10760
+ }
10761
+ }
10762
+ if (!changed) {
10763
+ return node;
10764
+ }
10765
+ if (nextChildren.length === 1) {
10766
+ return nextChildren[0];
10767
+ }
10768
+ if (nextChildren.length === 0) {
10769
+ return null;
10770
+ }
10771
+ return {
10772
+ ...node,
10773
+ children: nextChildren
10774
+ };
10775
+ }
10776
+ var init_pane_layout = __esm({
10777
+ "packages/server/src/workspace/pane-layout.ts"() {
10778
+ "use strict";
10779
+ }
10780
+ });
10781
+
10289
10782
  // packages/server/src/commands/session.ts
10290
10783
  import { z as z10 } from "zod";
10784
+ function delay(ms) {
10785
+ return new Promise((resolve5) => {
10786
+ setTimeout(resolve5, ms);
10787
+ });
10788
+ }
10291
10789
  function getProviderFromRegistry(providerId, registry) {
10292
10790
  return registry.find((provider) => provider.id === providerId);
10293
10791
  }
10792
+ var SESSION_CLOSE_POLL_INTERVAL_MS, SESSION_CLOSE_TIMEOUT_MS;
10294
10793
  var init_session = __esm({
10295
10794
  "packages/server/src/commands/session.ts"() {
10296
10795
  "use strict";
10297
10796
  init_runtime_status();
10797
+ init_database();
10798
+ init_pane_layout();
10298
10799
  init_dispatch();
10800
+ SESSION_CLOSE_POLL_INTERVAL_MS = 100;
10801
+ SESSION_CLOSE_TIMEOUT_MS = 5e3;
10299
10802
  registerCommand(
10300
10803
  "session.list",
10301
10804
  z10.object({
@@ -10367,11 +10870,75 @@ var init_session = __esm({
10367
10870
  ctx.sessionMgr.delete(args.sessionId);
10368
10871
  }
10369
10872
  );
10873
+ registerCommand(
10874
+ "session.close",
10875
+ z10.object({
10876
+ sessionId: z10.string(),
10877
+ paneDisposition: z10.enum(["draft", "remove"]).default("draft")
10878
+ }),
10879
+ async (args, ctx) => {
10880
+ let session = ctx.sessionMgr.get(args.sessionId);
10881
+ if (!session) {
10882
+ throw { code: "session_not_found", message: `Session not found: ${args.sessionId}` };
10883
+ }
10884
+ if (session.state !== "ended") {
10885
+ try {
10886
+ await ctx.sessionMgr.stop(args.sessionId);
10887
+ } catch (error) {
10888
+ const candidate = error;
10889
+ throw {
10890
+ code: "session_close_failed",
10891
+ message: candidate.message ?? `Failed to stop session: ${args.sessionId}`
10892
+ };
10893
+ }
10894
+ const deadline = Date.now() + SESSION_CLOSE_TIMEOUT_MS;
10895
+ while (Date.now() < deadline) {
10896
+ session = ctx.sessionMgr.get(args.sessionId);
10897
+ if (!session) {
10898
+ return;
10899
+ }
10900
+ if (session.state === "ended") {
10901
+ break;
10902
+ }
10903
+ await delay(SESSION_CLOSE_POLL_INTERVAL_MS);
10904
+ }
10905
+ session = ctx.sessionMgr.get(args.sessionId);
10906
+ if (!session) {
10907
+ return;
10908
+ }
10909
+ if (session.state !== "ended") {
10910
+ throw {
10911
+ code: "session_close_timeout",
10912
+ message: `Timed out waiting for session to end before closing: ${args.sessionId}`
10913
+ };
10914
+ }
10915
+ }
10916
+ const workspace = ctx.workspaceMgr.get(session.workspaceId);
10917
+ if (!workspace) {
10918
+ throw {
10919
+ code: "workspace_not_found",
10920
+ message: `Workspace not found: ${session.workspaceId}`
10921
+ };
10922
+ }
10923
+ const nextUiState = {
10924
+ ...workspace.uiState,
10925
+ paneLayout: applyPaneDisposition(
10926
+ workspace.uiState.paneLayout,
10927
+ args.sessionId,
10928
+ args.paneDisposition
10929
+ )
10930
+ };
10931
+ withTransaction(ctx.db, () => {
10932
+ ctx.workspaceMgr.updateUiState(session.workspaceId, nextUiState);
10933
+ ctx.sessionMgr.delete(args.sessionId);
10934
+ });
10935
+ }
10936
+ );
10370
10937
  }
10371
10938
  });
10372
10939
 
10373
10940
  // packages/server/src/fs/tree.ts
10374
- import { readdir as readdir3, stat as stat6 } from "fs/promises";
10941
+ import { readdir as readdir3, stat as stat7 } from "fs/promises";
10375
10942
  import { join as join7, relative as relative4 } from "path";
10376
10943
  async function readTree(rootPath, subdir) {
10377
10944
  const targetPath = subdir ? join7(rootPath, subdir) : rootPath;
@@ -10393,7 +10960,7 @@ async function readTree(rootPath, subdir) {
10393
10960
  // Not loaded yet - client will request on expand
10394
10961
  });
10395
10962
  } else if (entry.isFile()) {
10396
- const stats = await stat6(fullPath);
10963
+ const stats = await stat7(fullPath);
10397
10964
  nodes.push({
10398
10965
  name: entry.name,
10399
10966
  path: relPath,
@@ -10462,7 +11029,7 @@ async function searchFiles(rootPath, query, limit = 10) {
10462
11029
  }
10463
11030
  return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
10464
11031
  }).slice(0, limit)) {
10465
- const stats = await stat6(match.fullPath);
11032
+ const stats = await stat7(match.fullPath);
10466
11033
  files.push({
10467
11034
  name: match.name,
10468
11035
  path: match.path,
@@ -10629,6 +11196,27 @@ var init_file = __esm({
10629
11196
  return { ok: true };
10630
11197
  }
10631
11198
  );
11199
+ registerCommand(
11200
+ "file.rename",
11201
+ z11.object({
11202
+ workspaceId: z11.string(),
11203
+ fromPath: z11.string(),
11204
+ toPath: z11.string()
11205
+ }),
11206
+ async (args, ctx) => {
11207
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
11208
+ if (!workspace) {
11209
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
11210
+ }
11211
+ await renameEntry(workspace.path, args.fromPath, args.toPath);
11212
+ ctx.eventBus.emit({
11213
+ type: "fs.dirty",
11214
+ workspaceId: args.workspaceId,
11215
+ reason: "fs_change"
11216
+ });
11217
+ return { ok: true };
11218
+ }
11219
+ );
10632
11220
  registerCommand(
10633
11221
  "file.write",
10634
11222
  z11.object({
@@ -10810,7 +11398,7 @@ import { mkdir as mkdir4, mkdtemp as mkdtemp2, rm as rm5, writeFile as writeFile
10810
11398
  import os2 from "os";
10811
11399
  import path6 from "path";
10812
11400
  async function runGit(cwd, args, options = {}) {
10813
- return new Promise((resolve4, reject) => {
11401
+ return new Promise((resolve5, reject) => {
10814
11402
  const gitArgs = [
10815
11403
  ...options.config?.flatMap(([key, value]) => ["-c", `${key}=${value}`]) ?? [],
10816
11404
  ...args
@@ -10837,7 +11425,7 @@ async function runGit(cwd, args, options = {}) {
10837
11425
  if (err) {
10838
11426
  reject(new GitError(err.message, stderr));
10839
11427
  } else {
10840
- resolve4({ stdout, stderr });
11428
+ resolve5({ stdout, stderr });
10841
11429
  }
10842
11430
  }
10843
11431
  );
@@ -12038,6 +12626,9 @@ var init_settings2 = __esm({
12038
12626
  themeId: z13.string().optional(),
12039
12627
  terminalRenderer: z13.enum(["standard", "compatibility"]).optional(),
12040
12628
  terminalCopyOnSelect: z13.boolean().optional(),
12629
+ terminalFontSize: z13.number().int().min(10).max(18).optional(),
12630
+ desktopTerminalFontSize: z13.number().int().min(10).max(18).optional(),
12631
+ mobileTerminalFontSize: z13.number().int().min(10).max(18).optional(),
12041
12632
  locale: z13.enum(["zh", "en"]).optional()
12042
12633
  }).optional(),
12043
12634
  providers: ProviderSettingsSchema.optional()
@@ -12178,20 +12769,373 @@ var init_settings2 = __esm({
12178
12769
  }
12179
12770
  });
12180
12771
 
12181
- // packages/server/src/commands/provider.ts
12772
+ // packages/server/src/commands/diagnostics.ts
12182
12773
  import { z as z14 } from "zod";
12774
+ function isLoopbackHost(host) {
12775
+ return host === void 0 || host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0";
12776
+ }
12777
+ async function resolveWorkspacePathCheck(workspacePath) {
12778
+ if (!workspacePath) {
12779
+ return {
12780
+ canContinue: false,
12781
+ checks: [
12782
+ {
12783
+ id: "workspace-selection",
12784
+ code: "workspace_selection_missing",
12785
+ status: "needs_attention"
12786
+ }
12787
+ ]
12788
+ };
12789
+ }
12790
+ const validation = await validatePath(workspacePath);
12791
+ if (validation.valid) {
12792
+ return {
12793
+ canContinue: true,
12794
+ checks: [
12795
+ {
12796
+ id: "workspace-path",
12797
+ code: "workspace_path_ready",
12798
+ status: "ready",
12799
+ workspacePath
12800
+ }
12801
+ ]
12802
+ };
12803
+ }
12804
+ return {
12805
+ canContinue: false,
12806
+ checks: [
12807
+ {
12808
+ id: "workspace-path",
12809
+ code: validation.error === "Path does not exist" ? "workspace_path_not_found" : "workspace_path_unreadable",
12810
+ status: "needs_attention",
12811
+ workspacePath
12812
+ }
12813
+ ]
12814
+ };
12815
+ }
12816
+ function buildProviderCheck(providerStatus, providerId) {
12817
+ if (providerStatus.available) {
12818
+ return {
12819
+ canContinue: true,
12820
+ checks: [
12821
+ {
12822
+ id: `provider:${providerId}`,
12823
+ code: "provider_runtime_ready",
12824
+ status: "ready",
12825
+ providerId,
12826
+ autoInstallSupported: providerStatus.autoInstallSupported,
12827
+ installReadiness: providerStatus.installReadiness
12828
+ }
12829
+ ]
12830
+ };
12831
+ }
12832
+ if (providerStatus.missingPrerequisites.length > 0) {
12833
+ return {
12834
+ canContinue: false,
12835
+ checks: [
12836
+ {
12837
+ id: `provider:${providerId}`,
12838
+ code: "provider_prerequisite_missing",
12839
+ status: "needs_attention",
12840
+ providerId,
12841
+ autoInstallSupported: providerStatus.autoInstallSupported,
12842
+ installReadiness: providerStatus.installReadiness,
12843
+ missingCommands: providerStatus.missingCommands,
12844
+ missingPrerequisites: providerStatus.missingPrerequisites,
12845
+ manualGuideKeys: providerStatus.manualGuideKeys,
12846
+ docUrl: providerStatus.docUrls.provider
12847
+ }
12848
+ ]
12849
+ };
12850
+ }
12851
+ return {
12852
+ canContinue: false,
12853
+ checks: [
12854
+ {
12855
+ id: `provider:${providerId}`,
12856
+ code: "provider_cli_missing",
12857
+ status: "needs_attention",
12858
+ providerId,
12859
+ autoInstallSupported: providerStatus.autoInstallSupported,
12860
+ installReadiness: providerStatus.installReadiness,
12861
+ missingCommands: providerStatus.missingCommands,
12862
+ missingPrerequisites: providerStatus.missingPrerequisites,
12863
+ manualGuideKeys: providerStatus.manualGuideKeys,
12864
+ docUrl: providerStatus.docUrls.provider
12865
+ }
12866
+ ]
12867
+ };
12868
+ }
12869
+ async function buildWorkspaceSelectionChecks(args, ctx) {
12870
+ if (args.workspacePath) {
12871
+ const workspaceResult = await resolveWorkspacePathCheck(args.workspacePath);
12872
+ return {
12873
+ canContinue: workspaceResult.canContinue,
12874
+ checks: workspaceResult.checks,
12875
+ workspacePath: args.workspacePath
12876
+ };
12877
+ }
12878
+ const workspace = args.workspaceId ? ctx.workspaceMgr.get(args.workspaceId) : void 0;
12879
+ if (!args.workspaceId) {
12880
+ return {
12881
+ canContinue: true,
12882
+ checks: []
12883
+ };
12884
+ }
12885
+ if (!workspace) {
12886
+ return {
12887
+ canContinue: false,
12888
+ checks: [
12889
+ {
12890
+ id: "session-workspace",
12891
+ code: "session_workspace_missing",
12892
+ status: "needs_attention",
12893
+ workspaceId: args.workspaceId
12894
+ }
12895
+ ]
12896
+ };
12897
+ }
12898
+ const pathCheck = await resolveWorkspacePathCheck(workspace.path);
12899
+ return {
12900
+ canContinue: pathCheck.canContinue,
12901
+ checks: [
12902
+ {
12903
+ id: "session-workspace",
12904
+ code: "session_workspace_ready",
12905
+ status: "ready",
12906
+ workspaceId: workspace.id,
12907
+ workspacePath: workspace.path
12908
+ },
12909
+ ...pathCheck.checks.map(
12910
+ (check) => check.id === "workspace-path" ? {
12911
+ ...check,
12912
+ id: `workspace-path:${workspace.id}`
12913
+ } : check
12914
+ )
12915
+ ],
12916
+ workspacePath: workspace.path
12917
+ };
12918
+ }
12919
+ async function buildAllProviderChecks(ctx, preferredProviderId) {
12920
+ const checks = [];
12921
+ let canContinueForPreferredProvider = preferredProviderId ? false : true;
12922
+ const runtimeStatus = await buildProviderRuntimeStatus(
12923
+ ctx.providerRegistry,
12924
+ ctx.providerRuntimeDeps
12925
+ );
12926
+ for (const provider of ctx.providerRegistry) {
12927
+ const providerStatus = runtimeStatus.providers[provider.id];
12928
+ if (!providerStatus) {
12929
+ checks.push({
12930
+ id: `provider:${provider.id}`,
12931
+ code: "provider_unknown",
12932
+ status: "needs_attention",
12933
+ providerId: provider.id
12934
+ });
12935
+ if (provider.id === preferredProviderId) {
12936
+ canContinueForPreferredProvider = false;
12937
+ }
12938
+ continue;
12939
+ }
12940
+ const providerCheck = buildProviderCheck(providerStatus, provider.id);
12941
+ checks.push(...providerCheck.checks);
12942
+ if (provider.id === preferredProviderId) {
12943
+ canContinueForPreferredProvider = providerCheck.canContinue;
12944
+ }
12945
+ }
12946
+ if (preferredProviderId && !ctx.providerRegistry.find((provider) => provider.id === preferredProviderId)) {
12947
+ checks.unshift({
12948
+ id: "session-provider",
12949
+ code: "provider_unknown",
12950
+ status: "needs_attention",
12951
+ providerId: preferredProviderId
12952
+ });
12953
+ canContinueForPreferredProvider = false;
12954
+ }
12955
+ return { checks, canContinueForPreferredProvider };
12956
+ }
12957
+ function buildServerAuthCheck(ctx) {
12958
+ return {
12959
+ id: "server-auth",
12960
+ code: ctx.config?.auth.enabled ? "server_auth_ready" : "server_auth_not_required",
12961
+ status: "ready"
12962
+ };
12963
+ }
12964
+ function buildMobileHostCheck(ctx) {
12965
+ if (isLoopbackHost(ctx.config?.host)) {
12966
+ return {
12967
+ canContinue: false,
12968
+ check: {
12969
+ id: "mobile-host",
12970
+ code: "mobile_host_local_only",
12971
+ status: "needs_attention"
12972
+ }
12973
+ };
12974
+ }
12975
+ return {
12976
+ canContinue: true,
12977
+ check: {
12978
+ id: "mobile-host",
12979
+ code: "mobile_host_ready",
12980
+ status: "ready"
12981
+ }
12982
+ };
12983
+ }
12984
+ async function buildSessionStartDiagnostics(args, ctx) {
12985
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
12986
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
12987
+ const mobileHost = buildMobileHostCheck(ctx);
12988
+ const checks = [
12989
+ ...workspaceSelection.checks,
12990
+ ...providerChecks.checks,
12991
+ buildServerAuthCheck(ctx),
12992
+ mobileHost.check
12993
+ ];
12994
+ const canContinue = workspaceSelection.canContinue && providerChecks.canContinueForPreferredProvider;
12995
+ return {
12996
+ context: "session_start",
12997
+ canContinue,
12998
+ checks,
12999
+ metadata: {
13000
+ providerId: args.providerId,
13001
+ workspaceId: args.workspaceId,
13002
+ workspacePath: workspaceSelection.workspacePath,
13003
+ authEnabled: ctx.config?.auth.enabled ?? false,
13004
+ host: ctx.config?.host
13005
+ }
13006
+ };
13007
+ }
13008
+ async function buildManualDiagnostics(args, ctx) {
13009
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
13010
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
13011
+ const mobileHost = buildMobileHostCheck(ctx);
13012
+ const checks = [
13013
+ ...workspaceSelection.checks,
13014
+ ...providerChecks.checks,
13015
+ buildServerAuthCheck(ctx),
13016
+ mobileHost.check
13017
+ ];
13018
+ return {
13019
+ context: "manual_check",
13020
+ canContinue: checks.every((check) => check.status !== "needs_attention"),
13021
+ checks,
13022
+ metadata: {
13023
+ authEnabled: ctx.config?.auth.enabled ?? false,
13024
+ host: ctx.config?.host,
13025
+ providerId: args.providerId,
13026
+ workspaceId: args.workspaceId,
13027
+ workspacePath: workspaceSelection.workspacePath ?? args.workspacePath
13028
+ }
13029
+ };
13030
+ }
13031
+ async function buildMobileDiagnostics(args, ctx) {
13032
+ const host = ctx.config?.host;
13033
+ const authEnabled = ctx.config?.auth.enabled ?? false;
13034
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
13035
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
13036
+ const mobileHost = buildMobileHostCheck(ctx);
13037
+ const checks = [
13038
+ ...workspaceSelection.checks,
13039
+ ...providerChecks.checks,
13040
+ buildServerAuthCheck(ctx),
13041
+ mobileHost.check
13042
+ ];
13043
+ let canContinue = mobileHost.canContinue;
13044
+ if (!authEnabled) {
13045
+ canContinue = false;
13046
+ checks.push({
13047
+ id: "mobile-auth",
13048
+ code: "mobile_auth_disabled",
13049
+ status: "needs_attention"
13050
+ });
13051
+ } else {
13052
+ checks.push({
13053
+ id: "mobile-auth",
13054
+ code: "server_auth_ready",
13055
+ status: "ready"
13056
+ });
13057
+ }
13058
+ return {
13059
+ context: "mobile_continue",
13060
+ canContinue,
13061
+ checks,
13062
+ metadata: {
13063
+ authEnabled,
13064
+ host,
13065
+ workspaceId: args.workspaceId,
13066
+ workspacePath: workspaceSelection.workspacePath,
13067
+ providerId: args.providerId
13068
+ }
13069
+ };
13070
+ }
13071
+ async function buildDiagnostics(args, ctx) {
13072
+ switch (args.context) {
13073
+ case "workspace_open": {
13074
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
13075
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
13076
+ const mobileHost = buildMobileHostCheck(ctx);
13077
+ return {
13078
+ context: "workspace_open",
13079
+ canContinue: workspaceSelection.canContinue,
13080
+ checks: [
13081
+ ...workspaceSelection.checks,
13082
+ ...providerChecks.checks,
13083
+ buildServerAuthCheck(ctx),
13084
+ mobileHost.check
13085
+ ],
13086
+ metadata: {
13087
+ workspacePath: workspaceSelection.workspacePath ?? args.workspacePath,
13088
+ authEnabled: ctx.config?.auth.enabled ?? false,
13089
+ host: ctx.config?.host,
13090
+ providerId: args.providerId,
13091
+ workspaceId: args.workspaceId
13092
+ }
13093
+ };
13094
+ }
13095
+ case "session_start":
13096
+ return buildSessionStartDiagnostics(args, ctx);
13097
+ case "mobile_continue":
13098
+ return buildMobileDiagnostics(args, ctx);
13099
+ case "manual_check":
13100
+ return buildManualDiagnostics(args, ctx);
13101
+ }
13102
+ }
13103
+ var DiagnosticsRequestSchema;
13104
+ var init_diagnostics2 = __esm({
13105
+ "packages/server/src/commands/diagnostics.ts"() {
13106
+ "use strict";
13107
+ init_runtime_status();
13108
+ init_validator();
13109
+ init_dispatch();
13110
+ DiagnosticsRequestSchema = z14.object({
13111
+ context: z14.enum(["workspace_open", "session_start", "mobile_continue", "manual_check"]),
13112
+ workspaceId: z14.string().optional(),
13113
+ workspacePath: z14.string().optional(),
13114
+ providerId: z14.string().optional()
13115
+ });
13116
+ registerCommand("diagnostics.get", DiagnosticsRequestSchema, async (args, ctx) => {
13117
+ return buildDiagnostics(args, ctx);
13118
+ });
13119
+ registerCommand("diagnostics.recheck", DiagnosticsRequestSchema, async (args, ctx) => {
13120
+ return buildDiagnostics(args, ctx);
13121
+ });
13122
+ }
13123
+ });
13124
+
13125
+ // packages/server/src/commands/provider.ts
13126
+ import { z as z15 } from "zod";
12183
13127
  var init_provider = __esm({
12184
13128
  "packages/server/src/commands/provider.ts"() {
12185
13129
  "use strict";
12186
13130
  init_runtime_status();
12187
13131
  init_dispatch();
12188
- registerCommand("provider.runtimeStatus", z14.object({}), async (_args, ctx) => {
13132
+ registerCommand("provider.runtimeStatus", z15.object({}), async (_args, ctx) => {
12189
13133
  return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
12190
13134
  });
12191
13135
  registerCommand(
12192
13136
  "provider.install.start",
12193
- z14.object({
12194
- providerId: z14.string()
13137
+ z15.object({
13138
+ providerId: z15.string()
12195
13139
  }),
12196
13140
  async (args, ctx) => {
12197
13141
  if (!ctx.providerInstallMgr) {
@@ -12205,8 +13149,8 @@ var init_provider = __esm({
12205
13149
  );
12206
13150
  registerCommand(
12207
13151
  "provider.install.get",
12208
- z14.object({
12209
- jobId: z14.string()
13152
+ z15.object({
13153
+ jobId: z15.string()
12210
13154
  }),
12211
13155
  async (args, ctx) => {
12212
13156
  if (!ctx.providerInstallMgr) {
@@ -12229,35 +13173,35 @@ var init_provider = __esm({
12229
13173
  });
12230
13174
 
12231
13175
  // packages/server/src/commands/supervisor.ts
12232
- import { z as z15 } from "zod";
13176
+ import { z as z16 } from "zod";
12233
13177
  var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, supervisorIdSchema;
12234
13178
  var init_supervisor2 = __esm({
12235
13179
  "packages/server/src/commands/supervisor.ts"() {
12236
13180
  "use strict";
12237
13181
  init_dispatch();
12238
- supervisorObjectiveSchema = z15.string().trim().min(1).max(4e3);
12239
- createSupervisorSchema = z15.object({
12240
- sessionId: z15.string(),
12241
- workspaceId: z15.string(),
13182
+ supervisorObjectiveSchema = z16.string().trim().min(1).max(4e3);
13183
+ createSupervisorSchema = z16.object({
13184
+ sessionId: z16.string(),
13185
+ workspaceId: z16.string(),
12242
13186
  objective: supervisorObjectiveSchema,
12243
- evaluatorProviderId: z15.string(),
12244
- evaluatorModel: z15.string().trim().min(1).max(200).optional(),
12245
- maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
12246
- scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
13187
+ evaluatorProviderId: z16.string(),
13188
+ evaluatorModel: z16.string().trim().min(1).max(200).optional(),
13189
+ maxSupervisionCount: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
13190
+ scheduledAt: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
12247
13191
  }).strict();
12248
- updateSupervisorSchema = z15.object({
12249
- id: z15.string(),
13192
+ updateSupervisorSchema = z16.object({
13193
+ id: z16.string(),
12250
13194
  objective: supervisorObjectiveSchema.optional(),
12251
- evaluatorProviderId: z15.string().optional(),
12252
- evaluatorModel: z15.string().trim().min(1).max(200).nullable().optional(),
12253
- maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
12254
- scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
13195
+ evaluatorProviderId: z16.string().optional(),
13196
+ evaluatorModel: z16.string().trim().min(1).max(200).nullable().optional(),
13197
+ maxSupervisionCount: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
13198
+ scheduledAt: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
12255
13199
  }).strict().refine(
12256
13200
  (input2) => input2.objective !== void 0 || input2.evaluatorProviderId !== void 0 || input2.evaluatorModel !== void 0 || input2.maxSupervisionCount !== void 0 || input2.scheduledAt !== void 0,
12257
13201
  "at least one supervisor field is required"
12258
13202
  );
12259
- sessionIdSchema = z15.object({ sessionId: z15.string() });
12260
- supervisorIdSchema = z15.object({ id: z15.string() });
13203
+ sessionIdSchema = z16.object({ sessionId: z16.string() });
13204
+ supervisorIdSchema = z16.object({ id: z16.string() });
12261
13205
  registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
12262
13206
  return {
12263
13207
  supervisor: await ctx.supervisorMgr.create({
@@ -12441,7 +13385,7 @@ var init_worktree = __esm({
12441
13385
 
12442
13386
  // packages/server/src/commands/worktree.ts
12443
13387
  import path9 from "node:path";
12444
- import { z as z16 } from "zod";
13388
+ import { z as z17 } from "zod";
12445
13389
  async function findRelatedWorkspaceIds(ctx, workspacePath) {
12446
13390
  const targetCommonDir = await getGitCommonDirPath(workspacePath);
12447
13391
  const relatedWorkspaceIds = await Promise.all(
@@ -12474,7 +13418,7 @@ var init_worktree2 = __esm({
12474
13418
  init_worktree();
12475
13419
  init_dispatch();
12476
13420
  init_git_events();
12477
- registerCommand("worktree.list", z16.object({ workspaceId: z16.string() }), async (args, ctx) => {
13421
+ registerCommand("worktree.list", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
12478
13422
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
12479
13423
  if (!workspace) {
12480
13424
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
@@ -12483,7 +13427,7 @@ var init_worktree2 = __esm({
12483
13427
  });
12484
13428
  registerCommand(
12485
13429
  "worktree.status",
12486
- z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
13430
+ z17.object({ workspaceId: z17.string(), worktreePath: z17.string() }),
12487
13431
  async (args, ctx) => {
12488
13432
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
12489
13433
  if (!workspace) {
@@ -12495,10 +13439,10 @@ var init_worktree2 = __esm({
12495
13439
  );
12496
13440
  registerCommand(
12497
13441
  "worktree.diff",
12498
- z16.object({
12499
- workspaceId: z16.string(),
12500
- worktreePath: z16.string(),
12501
- staged: z16.boolean().optional().default(false)
13442
+ z17.object({
13443
+ workspaceId: z17.string(),
13444
+ worktreePath: z17.string(),
13445
+ staged: z17.boolean().optional().default(false)
12502
13446
  }),
12503
13447
  async (args, ctx) => {
12504
13448
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -12511,7 +13455,7 @@ var init_worktree2 = __esm({
12511
13455
  );
12512
13456
  registerCommand(
12513
13457
  "worktree.tree",
12514
- z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
13458
+ z17.object({ workspaceId: z17.string(), worktreePath: z17.string() }),
12515
13459
  async (args, ctx) => {
12516
13460
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
12517
13461
  if (!workspace) {
@@ -12523,10 +13467,10 @@ var init_worktree2 = __esm({
12523
13467
  );
12524
13468
  registerCommand(
12525
13469
  "worktree.create",
12526
- z16.object({
12527
- workspaceId: z16.string(),
12528
- branch: z16.string(),
12529
- path: z16.string()
13470
+ z17.object({
13471
+ workspaceId: z17.string(),
13472
+ branch: z17.string(),
13473
+ path: z17.string()
12530
13474
  }),
12531
13475
  async (args, ctx) => {
12532
13476
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -12541,10 +13485,10 @@ var init_worktree2 = __esm({
12541
13485
  );
12542
13486
  registerCommand(
12543
13487
  "worktree.remove",
12544
- z16.object({
12545
- workspaceId: z16.string(),
12546
- worktreePath: z16.string(),
12547
- force: z16.boolean().optional().default(false)
13488
+ z17.object({
13489
+ workspaceId: z17.string(),
13490
+ worktreePath: z17.string(),
13491
+ force: z17.boolean().optional().default(false)
12548
13492
  }),
12549
13493
  async (args, ctx) => {
12550
13494
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -12568,7 +13512,7 @@ var init_worktree2 = __esm({
12568
13512
  });
12569
13513
 
12570
13514
  // packages/server/src/commands/fencing.ts
12571
- import { z as z17 } from "zod";
13515
+ import { z as z18 } from "zod";
12572
13516
  function createMockFencingRequest() {
12573
13517
  return {
12574
13518
  ip: "127.0.0.1",
@@ -12581,9 +13525,9 @@ var init_fencing2 = __esm({
12581
13525
  init_dispatch();
12582
13526
  registerCommand(
12583
13527
  "fencing.request",
12584
- z17.object({
12585
- workspaceId: z17.string(),
12586
- tabId: z17.string()
13528
+ z18.object({
13529
+ workspaceId: z18.string(),
13530
+ tabId: z18.string()
12587
13531
  }),
12588
13532
  async (args, ctx, clientId) => {
12589
13533
  return ctx.fencingMgr.requestControl(
@@ -12596,7 +13540,7 @@ var init_fencing2 = __esm({
12596
13540
  );
12597
13541
  registerCommand(
12598
13542
  "fencing.heartbeat",
12599
- z17.object({ workspaceId: z17.string() }),
13543
+ z18.object({ workspaceId: z18.string() }),
12600
13544
  async (args, ctx, clientId) => {
12601
13545
  const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
12602
13546
  return { success };
@@ -12604,13 +13548,13 @@ var init_fencing2 = __esm({
12604
13548
  );
12605
13549
  registerCommand(
12606
13550
  "fencing.release",
12607
- z17.object({ workspaceId: z17.string() }),
13551
+ z18.object({ workspaceId: z18.string() }),
12608
13552
  async (args, ctx, clientId) => {
12609
13553
  ctx.fencingMgr.release(args.workspaceId, clientId);
12610
13554
  return {};
12611
13555
  }
12612
13556
  );
12613
- registerCommand("fencing.status", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
13557
+ registerCommand("fencing.status", z18.object({ workspaceId: z18.string() }), async (args, ctx) => {
12614
13558
  const controller = ctx.fencingMgr.getController(args.workspaceId);
12615
13559
  const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
12616
13560
  return {
@@ -12621,9 +13565,9 @@ var init_fencing2 = __esm({
12621
13565
  });
12622
13566
  registerCommand(
12623
13567
  "fencing.takeover",
12624
- z17.object({
12625
- workspaceId: z17.string(),
12626
- tabId: z17.string()
13568
+ z18.object({
13569
+ workspaceId: z18.string(),
13570
+ tabId: z18.string()
12627
13571
  }),
12628
13572
  async (args, ctx, clientId) => {
12629
13573
  return ctx.fencingMgr.forceTakeover(
@@ -12650,6 +13594,7 @@ var init_commands = __esm({
12650
13594
  init_file();
12651
13595
  init_git2();
12652
13596
  init_settings2();
13597
+ init_diagnostics2();
12653
13598
  init_provider();
12654
13599
  init_supervisor2();
12655
13600
  init_worktree2();
@@ -12793,7 +13738,8 @@ async function createServer(configOverrides) {
12793
13738
  autoFetch,
12794
13739
  providerRuntimeDeps,
12795
13740
  providerInstallMgr,
12796
- activationMgr
13741
+ activationMgr,
13742
+ config
12797
13743
  };
12798
13744
  wsHub.setCommandContext(commandContext);
12799
13745
  await app.listen({
@@ -13368,7 +14314,7 @@ function getOpenCommand(url) {
13368
14314
  }
13369
14315
  async function openBrowser(url) {
13370
14316
  const { command, args } = getOpenCommand(url);
13371
- await new Promise((resolve4, reject) => {
14317
+ await new Promise((resolve5, reject) => {
13372
14318
  const child = spawn3(command, args, {
13373
14319
  detached: true,
13374
14320
  stdio: "ignore",
@@ -13377,7 +14323,7 @@ async function openBrowser(url) {
13377
14323
  child.once("error", reject);
13378
14324
  child.once("spawn", () => {
13379
14325
  child.unref();
13380
- resolve4();
14326
+ resolve5();
13381
14327
  });
13382
14328
  });
13383
14329
  }
@@ -13746,29 +14692,29 @@ async function loadPm2() {
13746
14692
  }
13747
14693
  var connectPm2 = async () => {
13748
14694
  const pm2 = await loadPm2();
13749
- return new Promise((resolve4, reject) => {
14695
+ return new Promise((resolve5, reject) => {
13750
14696
  pm2.connect((error) => {
13751
14697
  if (error) {
13752
14698
  reject(error);
13753
14699
  return;
13754
14700
  }
13755
- resolve4();
14701
+ resolve5();
13756
14702
  });
13757
14703
  });
13758
14704
  };
13759
- var sleep = async (ms) => new Promise((resolve4) => {
13760
- setTimeout(resolve4, ms);
14705
+ var sleep = async (ms) => new Promise((resolve5) => {
14706
+ setTimeout(resolve5, ms);
13761
14707
  });
13762
14708
  var disconnectPm2 = async () => {
13763
14709
  const pm2 = await loadPm2();
13764
- await new Promise((resolve4) => {
14710
+ await new Promise((resolve5) => {
13765
14711
  let settled = false;
13766
14712
  const finish = () => {
13767
14713
  if (settled) {
13768
14714
  return;
13769
14715
  }
13770
14716
  settled = true;
13771
- resolve4();
14717
+ resolve5();
13772
14718
  };
13773
14719
  const timer = setTimeout(finish, PM2_DISCONNECT_WAIT_MS);
13774
14720
  try {
@@ -13782,29 +14728,29 @@ var disconnectPm2 = async () => {
13782
14728
  }
13783
14729
  });
13784
14730
  };
13785
- var describeManagedServer = async (pm2) => new Promise((resolve4, reject) => {
14731
+ var describeManagedServer = async (pm2) => new Promise((resolve5, reject) => {
13786
14732
  pm2.describe(MANAGED_SERVER_NAME, (error, result) => {
13787
14733
  if (error) {
13788
14734
  reject(error);
13789
14735
  return;
13790
14736
  }
13791
- resolve4(result ?? []);
14737
+ resolve5(result ?? []);
13792
14738
  });
13793
14739
  });
13794
- var removeManagedServer = async (pm2) => new Promise((resolve4, reject) => {
14740
+ var removeManagedServer = async (pm2) => new Promise((resolve5, reject) => {
13795
14741
  pm2.delete(MANAGED_SERVER_NAME, (error) => {
13796
14742
  if (error) {
13797
14743
  reject(error);
13798
14744
  return;
13799
14745
  }
13800
- resolve4();
14746
+ resolve5();
13801
14747
  });
13802
14748
  });
13803
14749
  var killPm2Daemon = async () => {
13804
14750
  const pm2 = await loadPm2();
13805
- return new Promise((resolve4) => {
14751
+ return new Promise((resolve5) => {
13806
14752
  pm2.kill(() => {
13807
- resolve4();
14753
+ resolve5();
13808
14754
  });
13809
14755
  });
13810
14756
  };
@@ -13950,7 +14896,7 @@ var startManagedServer = async ({
13950
14896
  ensureLogDirectory();
13951
14897
  const { outFile, errFile } = getLogPaths();
13952
14898
  const logOffsets = captureStartupLogOffsets();
13953
- await new Promise((resolve4, reject) => {
14899
+ await new Promise((resolve5, reject) => {
13954
14900
  pm2.start(
13955
14901
  {
13956
14902
  name: MANAGED_SERVER_NAME,
@@ -13973,7 +14919,7 @@ var startManagedServer = async ({
13973
14919
  reject(error);
13974
14920
  return;
13975
14921
  }
13976
- resolve4();
14922
+ resolve5();
13977
14923
  }
13978
14924
  );
13979
14925
  });
@@ -14091,11 +15037,11 @@ import { fileURLToPath as fileURLToPath2 } from "url";
14091
15037
 
14092
15038
  // packages/cli/src/embed.ts
14093
15039
  import { existsSync as existsSync10 } from "fs";
14094
- import { dirname as dirname6, resolve as resolve3 } from "path";
15040
+ import { dirname as dirname6, resolve as resolve4 } from "path";
14095
15041
  import { fileURLToPath } from "url";
14096
15042
  var __filename = fileURLToPath(import.meta.url);
14097
15043
  var __dirname = dirname6(__filename);
14098
- var WEB_ASSETS_DIR = resolve3(__dirname, "../web");
15044
+ var WEB_ASSETS_DIR = resolve4(__dirname, "../web");
14099
15045
  function getStaticAssetsDir() {
14100
15046
  return WEB_ASSETS_DIR;
14101
15047
  }