@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.
@@ -996,7 +996,14 @@ var init_image = __esm({
996
996
 
997
997
  // packages/server/src/fs/file-io.ts
998
998
  import { createHash } from "crypto";
999
- import { readFile as fsReadFile, writeFile as fsWriteFile, mkdir, rm, stat } from "fs/promises";
999
+ import {
1000
+ readFile as fsReadFile,
1001
+ rename as fsRename,
1002
+ writeFile as fsWriteFile,
1003
+ mkdir,
1004
+ rm,
1005
+ stat
1006
+ } from "fs/promises";
1000
1007
  import { dirname as dirname2, isAbsolute, relative, resolve as resolve2 } from "path";
1001
1008
  async function statSafe(path10) {
1002
1009
  try {
@@ -1030,6 +1037,27 @@ async function deleteEntry(rootPath, relPath) {
1030
1037
  }
1031
1038
  await rm(abs, { recursive: true });
1032
1039
  }
1040
+ async function renameEntry(rootPath, fromPath, toPath) {
1041
+ const fromAbs = resolveSafe(rootPath, fromPath);
1042
+ const toAbs = resolveSafe(rootPath, toPath);
1043
+ const source = await statSafe(fromAbs);
1044
+ const target = await statSafe(toAbs);
1045
+ const fromParent = dirname2(fromAbs);
1046
+ const toParent = dirname2(toAbs);
1047
+ if (!source) {
1048
+ throw { code: "not_found", message: "Source not found" };
1049
+ }
1050
+ if (fromParent !== toParent) {
1051
+ throw {
1052
+ code: "rename_across_directories_not_supported",
1053
+ message: "Rename must stay within the current directory"
1054
+ };
1055
+ }
1056
+ if (target) {
1057
+ throw { code: "already_exists", message: "Target already exists" };
1058
+ }
1059
+ await fsRename(fromAbs, toAbs);
1060
+ }
1033
1061
  function resolveSafe(root, relPath) {
1034
1062
  const absRoot = resolve2(root);
1035
1063
  const abs = resolve2(absRoot, relPath);
@@ -1043,7 +1071,7 @@ async function readFile(workspaceId, rootPath, relPath) {
1043
1071
  const abs = resolveSafe(rootPath, relPath);
1044
1072
  const imageType = getImageTypeInfo(relPath);
1045
1073
  if (imageType) {
1046
- const stats = await stat(abs);
1074
+ const bytes = await fsReadFile(abs);
1047
1075
  const params = new URLSearchParams({
1048
1076
  workspaceId,
1049
1077
  path: relPath
@@ -1052,8 +1080,9 @@ async function readFile(workspaceId, rootPath, relPath) {
1052
1080
  kind: "image",
1053
1081
  mime: imageType.mime,
1054
1082
  url: `/api/file?${params.toString()}`,
1055
- size: stats.size,
1056
- isTextBacked: imageType.isTextBacked
1083
+ size: bytes.byteLength,
1084
+ isTextBacked: imageType.isTextBacked,
1085
+ version: createHash("sha256").update(bytes).digest("hex")
1057
1086
  };
1058
1087
  }
1059
1088
  const content = await fsReadFile(abs, "utf-8");
@@ -2009,12 +2038,12 @@ var init_auto_fetch = __esm({
2009
2038
  }
2010
2039
  acquireWorkspaceOperation(workspaceId) {
2011
2040
  const state = this.getOrCreateState(workspaceId);
2012
- return new Promise((resolve4) => {
2041
+ return new Promise((resolve5) => {
2013
2042
  const grant = () => {
2014
2043
  state.inFlight = true;
2015
2044
  state.nextFetchAt = void 0;
2016
2045
  let released = false;
2017
- resolve4(() => {
2046
+ resolve5(() => {
2018
2047
  if (released) {
2019
2048
  return;
2020
2049
  }
@@ -2042,7 +2071,7 @@ var init_auto_fetch = __esm({
2042
2071
  // packages/server/src/provider-runtime/command-runner.ts
2043
2072
  import { spawn } from "node:child_process";
2044
2073
  async function runCommandAsString(file, args, options) {
2045
- return new Promise((resolve4, reject) => {
2074
+ return new Promise((resolve5, reject) => {
2046
2075
  const child = spawn(file, args, {
2047
2076
  shell: shouldUseShellForCommand(file, process.platform),
2048
2077
  windowsHide: options?.windowsHide ?? true
@@ -2067,7 +2096,7 @@ async function runCommandAsString(file, args, options) {
2067
2096
  const stdout = Buffer.concat(stdoutChunks).toString("utf8");
2068
2097
  const stderr = Buffer.concat(stderrChunks).toString("utf8");
2069
2098
  if (code === 0) {
2070
- resolve4({ stdout, stderr });
2099
+ resolve5({ stdout, stderr });
2071
2100
  return;
2072
2101
  }
2073
2102
  reject(
@@ -2676,6 +2705,13 @@ ${details.stdout}`.toLowerCase();
2676
2705
  }
2677
2706
  });
2678
2707
 
2708
+ // packages/core/src/domain/diagnostics.ts
2709
+ var init_diagnostics = __esm({
2710
+ "packages/core/src/domain/diagnostics.ts"() {
2711
+ "use strict";
2712
+ }
2713
+ });
2714
+
2679
2715
  // packages/core/src/domain/events.ts
2680
2716
  var init_events = __esm({
2681
2717
  "packages/core/src/domain/events.ts"() {
@@ -2926,6 +2962,7 @@ var init_idle_heuristics2 = __esm({
2926
2962
  var init_src3 = __esm({
2927
2963
  "packages/core/src/index.ts"() {
2928
2964
  "use strict";
2965
+ init_diagnostics();
2929
2966
  init_events();
2930
2967
  init_mcp();
2931
2968
  init_provider_install();
@@ -5009,13 +5046,13 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
5009
5046
  return;
5010
5047
  }
5011
5048
  const arch = deps.arch ?? process.arch;
5012
- const resolve4 = deps.resolve ?? ((id) => require2.resolve(id));
5049
+ const resolve5 = deps.resolve ?? ((id) => require2.resolve(id));
5013
5050
  const fileExists = deps.existsSync ?? existsSync4;
5014
- const stat7 = deps.statSync ?? statSync;
5051
+ const stat8 = deps.statSync ?? statSync;
5015
5052
  const chmod = deps.chmodSync ?? chmodSync2;
5016
5053
  let packageJsonPath;
5017
5054
  try {
5018
- packageJsonPath = resolve4(NODE_PTY_PKG);
5055
+ packageJsonPath = resolve5(NODE_PTY_PKG);
5019
5056
  } catch {
5020
5057
  return;
5021
5058
  }
@@ -5029,7 +5066,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
5029
5066
  if (!fileExists(helperPath)) {
5030
5067
  return;
5031
5068
  }
5032
- const currentMode = stat7(helperPath).mode;
5069
+ const currentMode = stat8(helperPath).mode;
5033
5070
  const executableMode = currentMode | 73;
5034
5071
  if (executableMode === currentMode) {
5035
5072
  return;
@@ -5080,7 +5117,7 @@ async function escalateKillWithPolling(pid, signal, options) {
5080
5117
  const startTime = Date.now();
5081
5118
  const deadline = startTime + timeoutMs;
5082
5119
  while (Date.now() < deadline) {
5083
- await new Promise((resolve4) => setTimeout(resolve4, pollIntervalMs));
5120
+ await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
5084
5121
  if (!isProcessAlive(pid)) {
5085
5122
  return true;
5086
5123
  }
@@ -5232,38 +5269,107 @@ var init_settings = __esm({
5232
5269
 
5233
5270
  // packages/server/src/supervisor/evaluator.ts
5234
5271
  import { spawn as spawn2 } from "node:child_process";
5235
- function buildPrompt(context) {
5272
+ function buildPrompt(context, mode) {
5273
+ if (mode === "decompose") {
5274
+ return [
5275
+ "You are an autonomous supervisor for a target-scoped software task.",
5276
+ "Your first job is to decompose the target into a supervision structure before evaluation begins.",
5277
+ "",
5278
+ "Return JSON only.",
5279
+ "No prose before or after the JSON.",
5280
+ "",
5281
+ "Decomposition policy:",
5282
+ "- Do not ask the user any questions.",
5283
+ "- Do not ask for clarification, confirmation, or approval.",
5284
+ "- Do not propose options for the user to choose from.",
5285
+ "- If information is incomplete, make the most conservative reasonable assumptions and decide the decomposition yourself.",
5286
+ "- Your job is to return the best useful decomposition now, not to begin a discussion or planning workflow.",
5287
+ "- Keep the user-visible target as the top-level supervision owner.",
5288
+ '- Choose "stage" by default.',
5289
+ '- Choose "subtarget" only when the work clearly breaks into independently deliverable and independently verifiable workstreams.',
5290
+ "- If the distinction is unclear, choose stage.",
5291
+ "- Produce 1 to 7 decomposition items.",
5292
+ "- Each item must be concrete, milestone-sized, and useful for subsequent evaluation.",
5293
+ "- Do not leave the structure empty.",
5294
+ "",
5295
+ "Item requirements:",
5296
+ '- Each item must include "id", "kind", "title", "objective", "deliverable", "acceptanceCriteria", and "status".',
5297
+ '- "kind" must match the selected decompositionMode: all "stage" or all "subtarget".',
5298
+ '- "acceptanceCriteria" must be a non-empty string array.',
5299
+ '- Use statuses "pending", "in_progress", or "done".',
5300
+ "- Usually mark the first active item as in_progress and the rest as pending.",
5301
+ "",
5302
+ "Output schema:",
5303
+ "{",
5304
+ ' "mode": "decompose",',
5305
+ ' "decompositionMode": "stage" | "subtarget",',
5306
+ ' "items": [',
5307
+ ' { "id": string, "kind": "stage" | "subtarget", "title": string, "objective": string, "deliverable": string, "acceptanceCriteria": string[], "status": "pending" | "in_progress" | "done" }',
5308
+ " ],",
5309
+ ' "activeItemId": optional string,',
5310
+ ' "progressSummary": optional brief summary',
5311
+ "}",
5312
+ "",
5313
+ "Current objective:",
5314
+ context.objective,
5315
+ "",
5316
+ "Current target memory:",
5317
+ JSON.stringify(context.targetMemory, null, 2),
5318
+ "",
5319
+ "Latest user input:",
5320
+ context.latestUserInput?.trim() || "(none)",
5321
+ "",
5322
+ "Current terminal snapshot:",
5323
+ context.terminalExcerpt || "(no output yet)"
5324
+ ].join("\n");
5325
+ }
5236
5326
  const lines = [
5237
5327
  "You are an autonomous supervisor for a target-scoped software task.",
5238
5328
  "Your job is to keep the agent moving toward the objective until the objective is complete.",
5239
5329
  "",
5240
5330
  "Return JSON only.",
5331
+ "No prose before or after the JSON.",
5241
5332
  "",
5242
5333
  "Decision policy:",
5243
- '- Prefer "continue" whenever there is a reasonable next action.',
5334
+ '- Prefer "continue" over "stop" whenever the objective is not yet verified complete and there is a concrete next action.',
5335
+ '- "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.',
5244
5336
  "- Do not ask the user to decide, clarify, or choose among implementation options.",
5337
+ "- 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.",
5338
+ "- If the agent asks a question or presents multiple options, choose the most conservative reasonable option yourself and direct the next action.",
5339
+ "- If multiple reasonable paths exist, pick one and move forward unless doing so would be unsafe or clearly unsupported.",
5245
5340
  "- When information is incomplete, choose a conservative next action based on the objective, target memory, latest user input, and terminal snapshot.",
5341
+ "- Do not treat the agent's claims, summaries, or self-reports as sufficient evidence of completion.",
5246
5342
  "- Stop only when the objective is complete, or when continuing would likely push the agent in an unsafe or clearly unsupported direction.",
5247
5343
  "",
5248
5344
  "Stage decision policy:",
5249
5345
  "- Use the target memory as the current supervision state.",
5250
- "- Base your decision on the objective, current plan, activeStepId, progressSummary, lastGuidance, stalledCount, latest user input, and terminal snapshot.",
5251
- "- Identify which plan step is currently active.",
5252
- "- Decide whether the active step is done, still in progress, blocked, or obsolete.",
5253
- "- If the active step is done, advance to the next useful step.",
5254
- "- If the active step is still in progress, give guidance that moves it forward.",
5346
+ "- Base your decision on the objective, current decompositionMode, items, activeItemId, progressSummary, lastGuidance, stalledCount, latest user input, and terminal snapshot.",
5347
+ "- Identify which decomposition item is currently active.",
5348
+ "- Keep the current active item unless there is evidence that it is done, blocked, or obsolete.",
5349
+ "- Decide whether the active item is done, still in progress, blocked, or obsolete based on observable evidence.",
5350
+ '- Treat statements like "done", "fixed", "implemented", or "should pass" as unverified unless supported by observable evidence.',
5351
+ '- Mark an item as "done" only when there is observable evidence that its deliverable or acceptanceCriteria were satisfied.',
5352
+ "- Prefer evidence from terminal output, test results, build results, explicit verification output, or other observable artifacts in the terminal snapshot.",
5353
+ "- If evidence is missing or ambiguous, keep the item in_progress and direct the agent to gather or produce the missing verification evidence.",
5354
+ "- If the current item appears nearly complete but is not yet verified, keep the same active item and direct targeted verification.",
5355
+ "- Advance to the next item only after the current item's deliverable or acceptanceCriteria are supported by observable evidence.",
5356
+ '- When advancing to the next item, mark the previous item as "done" and set activeItemId to the next item explicitly.',
5357
+ "- If the active item is blocked, give guidance that is most likely to unblock it.",
5358
+ "- If the active item is obsolete, explain the reason briefly and move to the next useful item.",
5255
5359
  "- If the agent appears stuck or repeated the same action, give a different concrete next action.",
5256
- "- If the plan is obsolete, update only the affected steps unless a full replacement is necessary.",
5360
+ "- Do not rewrite the decomposition structure during normal evaluation cycles.",
5257
5361
  "",
5258
5362
  "Allowed statuses:",
5259
- '- "continue": more work is needed; include "reason" and "guidance".',
5363
+ '- "continue": supervision should continue; include "reason" and "guidance".',
5260
5364
  '- "stop": supervision should stop; include "stopReason" and "reason".',
5261
5365
  "",
5262
5366
  "Allowed stop reasons:",
5263
5367
  '- "objective_complete"',
5264
5368
  '- "supervisor_uncertain"',
5265
5369
  "",
5266
- 'Use "objective_complete" only when the objective has been satisfied.',
5370
+ 'Use "objective_complete" only when there is evidence that the objective and relevant acceptanceCriteria have been satisfied.',
5371
+ "- Do not stop only because the agent says the work is complete or because code changes exist without verification evidence.",
5372
+ "- If completion looks plausible but remains unverified, continue and require targeted verification.",
5267
5373
  'Use "supervisor_uncertain" only as a last resort when no useful next action can be inferred and additional guidance would likely be misleading.',
5268
5374
  "",
5269
5375
  'Guidance requirements for "continue":',
@@ -5271,30 +5377,32 @@ function buildPrompt(context) {
5271
5377
  "- Focus on the highest-value step toward completing the objective.",
5272
5378
  "- Be specific enough for the supervised agent to act without asking the user.",
5273
5379
  "- Avoid generic reminders, encouragement, or restating the objective.",
5274
- "- If verification is needed, tell the agent exactly what to verify next.",
5380
+ "- If verification is needed, tell the agent exactly what command, file, behavior, or artifact to verify next.",
5275
5381
  "- If implementation is needed, point to the likely area, behavior, or file/module based on available evidence.",
5382
+ "- If the agent asked a question, answer it directly in the guidance and continue with a concrete next action.",
5276
5383
  "",
5277
- "Planning policy:",
5278
- "- If planGenerated is false, include a plan with 3 to 7 milestone-sized steps.",
5279
- "- If planGenerated is true, update progress incrementally.",
5280
- "- Do not rewrite the full plan unless the existing plan is clearly wrong or obsolete.",
5281
- "- Use stepUpdates to mark completed or active steps when the terminal snapshot shows progress.",
5282
- "- Keep activeStepId aligned with the next useful step.",
5384
+ "Evaluation policy:",
5385
+ "- Update progress incrementally against the existing decomposition.",
5386
+ "- Use itemUpdates to reflect evidence-backed status changes only.",
5387
+ "- Keep activeItemId on the current item by default.",
5388
+ "- Change activeItemId only when there is a clear reason to switch items.",
5389
+ "- If evidence is missing or ambiguous, prefer verification over further implementation.",
5283
5390
  "",
5284
5391
  "Output schema:",
5285
5392
  "For continue:",
5286
5393
  "{",
5394
+ ' "mode": "evaluate",',
5287
5395
  ' "status": "continue",',
5288
5396
  ' "reason": "brief explanation of why more work is needed",',
5289
5397
  ' "guidance": "specific next action for the supervised agent",',
5290
- ' "plan": optional array of plan steps,',
5291
- ' "activeStepId": optional step id,',
5398
+ ' "activeItemId": optional item id,',
5292
5399
  ' "progressSummary": optional brief progress summary,',
5293
- ' "stepUpdates": optional array of { "id": string, "status": "pending" | "in_progress" | "done" }',
5400
+ ' "itemUpdates": optional array of { "id": string, "status": "pending" | "in_progress" | "done" }',
5294
5401
  "}",
5295
5402
  "",
5296
5403
  "For stop:",
5297
5404
  "{",
5405
+ ' "mode": "evaluate",',
5298
5406
  ' "status": "stop",',
5299
5407
  ' "stopReason": "objective_complete" | "supervisor_uncertain",',
5300
5408
  ' "reason": "brief explanation"',
@@ -5318,7 +5426,7 @@ async function runCommand(command, timeoutMs, options = {}) {
5318
5426
  if (options.signal?.aborted) {
5319
5427
  throw createSupervisorEvalAbortedError();
5320
5428
  }
5321
- return await new Promise((resolve4, reject) => {
5429
+ return await new Promise((resolve5, reject) => {
5322
5430
  const child = spawn2(command.argv[0], command.argv.slice(1), {
5323
5431
  cwd: command.cwd,
5324
5432
  detached: process.platform !== "win32",
@@ -5348,7 +5456,7 @@ async function runCommand(command, timeoutMs, options = {}) {
5348
5456
  }
5349
5457
  settled = true;
5350
5458
  cleanup();
5351
- resolve4(value);
5459
+ resolve5(value);
5352
5460
  };
5353
5461
  const terminate = (error) => {
5354
5462
  if (terminationError) {
@@ -5379,7 +5487,10 @@ async function runCommand(command, timeoutMs, options = {}) {
5379
5487
  settleReject(terminationError);
5380
5488
  return;
5381
5489
  }
5382
- settleReject(error);
5490
+ settleReject({
5491
+ code: "supervisor_eval_failed",
5492
+ message: error instanceof Error ? error.message : "Evaluator process failed to start"
5493
+ });
5383
5494
  });
5384
5495
  child.on("exit", (code) => {
5385
5496
  if (terminationError) {
@@ -5557,7 +5668,7 @@ function extractSupervisorPayload(output, providerId) {
5557
5668
  }
5558
5669
  throw new Error("Supervisor did not return a recognizable message");
5559
5670
  }
5560
- function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5671
+ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars, requestedMode) {
5561
5672
  let parsed;
5562
5673
  try {
5563
5674
  parsed = JSON.parse(stripCodeFence(payloadText));
@@ -5570,9 +5681,49 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5570
5681
  throw new Error("Supervisor returned invalid evaluation payload");
5571
5682
  }
5572
5683
  const record = parsed;
5684
+ const payloadMode = record.mode;
5685
+ if (requestedMode === "decompose") {
5686
+ if (payloadMode !== "decompose") {
5687
+ throw new Error("Supervisor returned invalid decompose payload");
5688
+ }
5689
+ const decompositionMode = record.decompositionMode;
5690
+ if (decompositionMode !== "stage" && decompositionMode !== "subtarget") {
5691
+ throw new Error("Supervisor decompose result is missing a valid decompositionMode");
5692
+ }
5693
+ const items = Array.isArray(record.items) ? record.items.flatMap((value) => {
5694
+ if (!value || typeof value !== "object") {
5695
+ return [];
5696
+ }
5697
+ const item = value;
5698
+ 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") {
5699
+ return [];
5700
+ }
5701
+ return [
5702
+ {
5703
+ id: item.id,
5704
+ kind: item.kind,
5705
+ title: item.title,
5706
+ objective: item.objective,
5707
+ deliverable: item.deliverable,
5708
+ acceptanceCriteria: item.acceptanceCriteria,
5709
+ status: item.status
5710
+ }
5711
+ ];
5712
+ }) : [];
5713
+ if (items.length === 0) {
5714
+ throw new Error("Supervisor decompose result must include at least one valid item");
5715
+ }
5716
+ return {
5717
+ mode: "decompose",
5718
+ decompositionMode,
5719
+ items,
5720
+ activeItemId: typeof record.activeItemId === "string" && record.activeItemId.trim() ? record.activeItemId : void 0,
5721
+ progressSummary: typeof record.progressSummary === "string" && record.progressSummary.trim() ? record.progressSummary.trim() : void 0
5722
+ };
5723
+ }
5573
5724
  const status = record.status;
5574
5725
  const reason = record.reason;
5575
- if (status !== "continue" && status !== "stop" || typeof reason !== "string" || !reason.trim()) {
5726
+ if (payloadMode !== void 0 && payloadMode !== "evaluate" || status !== "continue" && status !== "stop" || typeof reason !== "string" || !reason.trim()) {
5576
5727
  throw new Error("Supervisor returned invalid evaluation payload");
5577
5728
  }
5578
5729
  if (status === "stop") {
@@ -5581,23 +5732,14 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5581
5732
  throw new Error("Supervisor stop result is missing a valid stopReason");
5582
5733
  }
5583
5734
  return {
5735
+ mode: "evaluate",
5584
5736
  status,
5585
5737
  stopReason,
5586
5738
  reason: reason.trim()
5587
5739
  };
5588
5740
  }
5589
5741
  const guidance = typeof record.guidance === "string" && record.guidance.trim() ? record.guidance.trim().slice(0, guidanceMaxChars) : void 0;
5590
- const plan = Array.isArray(record.plan) ? record.plan.flatMap((value) => {
5591
- if (!value || typeof value !== "object") {
5592
- return [];
5593
- }
5594
- const step = value;
5595
- if (typeof step.id !== "string" || typeof step.title !== "string" || step.status !== "pending" && step.status !== "in_progress" && step.status !== "done") {
5596
- return [];
5597
- }
5598
- return [{ id: step.id, title: step.title, status: step.status }];
5599
- }) : void 0;
5600
- const stepUpdates = Array.isArray(record.stepUpdates) ? record.stepUpdates.flatMap((value) => {
5742
+ const itemUpdates = Array.isArray(record.itemUpdates) ? record.itemUpdates.flatMap((value) => {
5601
5743
  if (!value || typeof value !== "object") {
5602
5744
  return [];
5603
5745
  }
@@ -5608,13 +5750,13 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
5608
5750
  return [{ id: update.id, status: update.status }];
5609
5751
  }) : void 0;
5610
5752
  return {
5753
+ mode: "evaluate",
5611
5754
  status,
5612
5755
  reason: reason.trim(),
5613
5756
  guidance,
5614
- plan,
5615
- activeStepId: typeof record.activeStepId === "string" && record.activeStepId.trim() ? record.activeStepId : void 0,
5757
+ activeItemId: typeof record.activeItemId === "string" && record.activeItemId.trim() ? record.activeItemId : void 0,
5616
5758
  progressSummary: typeof record.progressSummary === "string" && record.progressSummary.trim() ? record.progressSummary.trim() : void 0,
5617
- stepUpdates
5759
+ itemUpdates
5618
5760
  };
5619
5761
  }
5620
5762
  var NOOP_LOGGER2, SupervisorEvaluator;
@@ -5666,7 +5808,8 @@ var init_evaluator = __esm({
5666
5808
  provider,
5667
5809
  this.deps.providerConfigRepo.get(provider.id)
5668
5810
  );
5669
- const prompt = buildPrompt(context);
5811
+ const mode = options.mode ?? "evaluate";
5812
+ const prompt = buildPrompt(context, mode);
5670
5813
  const command = provider.buildSupervisorEvalCommand(config, {
5671
5814
  prompt,
5672
5815
  sessionId: supervisor.sessionId,
@@ -5700,7 +5843,7 @@ var init_evaluator = __esm({
5700
5843
  );
5701
5844
  throw error;
5702
5845
  }
5703
- return parseSupervisorEvaluationResult(payloadText, this.config.guidanceMaxChars);
5846
+ return parseSupervisorEvaluationResult(payloadText, this.config.guidanceMaxChars, mode);
5704
5847
  }
5705
5848
  };
5706
5849
  }
@@ -5871,12 +6014,12 @@ var init_scheduler = __esm({
5871
6014
 
5872
6015
  // packages/server/src/supervisor/manager.ts
5873
6016
  function createDeferredCompletion() {
5874
- let resolve4 = () => {
6017
+ let resolve5 = () => {
5875
6018
  };
5876
6019
  const promise = new Promise((innerResolve) => {
5877
- resolve4 = innerResolve;
6020
+ resolve5 = innerResolve;
5878
6021
  });
5879
- return { promise, resolve: resolve4 };
6022
+ return { promise, resolve: resolve5 };
5880
6023
  }
5881
6024
  function generateSupervisorId() {
5882
6025
  return `sup_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
@@ -5902,6 +6045,12 @@ function messageOf(error, fallback) {
5902
6045
  function logFailure(logger, error, context, message) {
5903
6046
  logger.error({ ...context, err: error }, message);
5904
6047
  }
6048
+ function isDecomposeResult(result) {
6049
+ return result.mode === "decompose";
6050
+ }
6051
+ function isEvaluateStopResult(result) {
6052
+ return "status" in result && result.status === "stop";
6053
+ }
5905
6054
  function isSupervisorEvalAborted(error) {
5906
6055
  return !!error && typeof error === "object" && error.code === "supervisor_eval_aborted";
5907
6056
  }
@@ -6405,7 +6554,12 @@ var init_manager2 = __esm({
6405
6554
  turnId: context.lastTurnId,
6406
6555
  createdAt: Date.now()
6407
6556
  });
6408
- this.broadcastCycle(evaluatingSupervisor, activeCycle, "created");
6557
+ this.broadcastCycle(evaluatingSupervisor, activeCycle, "created", {
6558
+ phase: "waiting_evaluator",
6559
+ currentAttemptIndex: 0,
6560
+ attemptCount: 1,
6561
+ maxAttempts: 1 + retrySettings.retryMaxCount
6562
+ });
6409
6563
  return {
6410
6564
  cycle: activeCycle,
6411
6565
  supervisor: hydratedSupervisor,
@@ -6603,6 +6757,8 @@ var init_manager2 = __esm({
6603
6757
  }
6604
6758
  async executeCycleWithRetry(started, signal) {
6605
6759
  const supervisor = started.supervisor;
6760
+ let context = started.context;
6761
+ let currentMemory = context.targetMemory;
6606
6762
  for (let attemptIndex = 0; ; attemptIndex += 1) {
6607
6763
  const attempt = this.deps.cycleAttemptRepo.create({
6608
6764
  id: generateAttemptId(),
@@ -6611,23 +6767,79 @@ var init_manager2 = __esm({
6611
6767
  status: "evaluating",
6612
6768
  startedAt: Date.now()
6613
6769
  });
6770
+ this.broadcastCycle(started.supervisor, started.cycle, "updated", {
6771
+ phase: "waiting_evaluator",
6772
+ currentAttemptIndex: attemptIndex,
6773
+ attemptCount: attemptIndex + 1,
6774
+ maxAttempts: 1 + started.retry.retryMaxCount
6775
+ });
6614
6776
  try {
6615
- const evaluation = await this.evaluator.evaluate(supervisor, started.context, { signal });
6777
+ if (!currentMemory.decompositionGenerated || currentMemory.items.length === 0) {
6778
+ const decomposition = await this.evaluator.evaluate(supervisor, context, {
6779
+ signal,
6780
+ mode: "decompose"
6781
+ });
6782
+ if (!isDecomposeResult(decomposition)) {
6783
+ throw new Error("Supervisor decompose pass did not return a decomposition result");
6784
+ }
6785
+ currentMemory = {
6786
+ ...currentMemory,
6787
+ decompositionGenerated: true,
6788
+ decompositionMode: decomposition.decompositionMode,
6789
+ items: decomposition.items,
6790
+ activeItemId: decomposition.activeItemId,
6791
+ progressSummary: decomposition.progressSummary ?? currentMemory.progressSummary,
6792
+ updatedAt: Date.now()
6793
+ };
6794
+ const workspace = this.requireWorkspace(context.workspaceId);
6795
+ await this.deps.targetStore.saveTargetMemory(
6796
+ workspace.path,
6797
+ started.targetId,
6798
+ currentMemory
6799
+ );
6800
+ const currentSupervisor2 = this.supervisors.get(supervisor.id) ?? this.requireSupervisor(supervisor.id);
6801
+ if (currentSupervisor2.targetId === started.targetId) {
6802
+ const refreshed = this.attachCycles({
6803
+ ...currentSupervisor2,
6804
+ currentTargetMemory: currentMemory
6805
+ });
6806
+ this.storeSnapshot(refreshed);
6807
+ }
6808
+ context = {
6809
+ ...context,
6810
+ targetMemory: currentMemory
6811
+ };
6812
+ }
6813
+ const evaluation = await this.evaluator.evaluate(supervisor, context, {
6814
+ signal,
6815
+ mode: "evaluate"
6816
+ });
6616
6817
  this.deps.cycleAttemptRepo.update(attempt.id, {
6617
6818
  status: "completed",
6618
6819
  completedAt: Date.now(),
6619
6820
  providerModel: supervisor.evaluatorModel ?? null
6620
6821
  });
6621
- if (evaluation.status === "stop") {
6822
+ if (isDecomposeResult(evaluation)) {
6823
+ throw new Error("Supervisor evaluate pass returned a decompose result");
6824
+ }
6825
+ const nextTargetMemory = this.applyEvaluationToTargetMemory(
6826
+ currentMemory,
6827
+ evaluation,
6828
+ void 0,
6829
+ Date.now()
6830
+ );
6831
+ if (isEvaluateStopResult(evaluation)) {
6622
6832
  return {
6623
6833
  evaluation,
6624
- injected: false
6834
+ injected: false,
6835
+ targetMemory: nextTargetMemory
6625
6836
  };
6626
6837
  }
6627
6838
  if (!evaluation.guidance?.trim()) {
6628
6839
  return {
6629
6840
  evaluation,
6630
- injected: false
6841
+ injected: false,
6842
+ targetMemory: nextTargetMemory
6631
6843
  };
6632
6844
  }
6633
6845
  if (signal?.aborted || this.pendingPauses.has(supervisor.id)) {
@@ -6637,7 +6849,8 @@ var init_manager2 = __esm({
6637
6849
  if (currentSupervisor.targetId !== started.targetId) {
6638
6850
  return {
6639
6851
  evaluation,
6640
- injected: false
6852
+ injected: false,
6853
+ targetMemory: nextTargetMemory
6641
6854
  };
6642
6855
  }
6643
6856
  const injectingSupervisor = this.attachCycles(
@@ -6650,6 +6863,12 @@ var init_manager2 = __esm({
6650
6863
  );
6651
6864
  this.storeSnapshot(injectingSupervisor);
6652
6865
  this.broadcastState(injectingSupervisor, "state_changed");
6866
+ this.broadcastCycle(injectingSupervisor, started.cycle, "updated", {
6867
+ phase: "injecting",
6868
+ currentAttemptIndex: attemptIndex,
6869
+ attemptCount: attemptIndex + 1,
6870
+ maxAttempts: 1 + started.retry.retryMaxCount
6871
+ });
6653
6872
  const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== started.cycle.id);
6654
6873
  const injection = await this.injector.inject(
6655
6874
  injectingSupervisor,
@@ -6662,7 +6881,13 @@ var init_manager2 = __esm({
6662
6881
  return {
6663
6882
  evaluation,
6664
6883
  injected: injection.injected,
6665
- injectedText: injection.injected ? injection.text : void 0
6884
+ injectedText: injection.injected ? injection.text : void 0,
6885
+ targetMemory: this.applyEvaluationToTargetMemory(
6886
+ currentMemory,
6887
+ evaluation,
6888
+ injection.injected ? injection.text : void 0,
6889
+ Date.now()
6890
+ )
6666
6891
  };
6667
6892
  } catch (error) {
6668
6893
  if (isSupervisorEvalAborted(error)) {
@@ -6683,6 +6908,15 @@ var init_manager2 = __esm({
6683
6908
  if (!this.shouldRetryAttempt(error, attemptIndex, started.retry)) {
6684
6909
  throw error;
6685
6910
  }
6911
+ const nextRetryAt = Date.now() + started.retry.retryDelayMs;
6912
+ this.broadcastCycle(supervisor, started.cycle, "updated", {
6913
+ phase: "retry_wait",
6914
+ currentAttemptIndex: attemptIndex,
6915
+ attemptCount: attemptIndex + 1,
6916
+ maxAttempts: 1 + started.retry.retryMaxCount,
6917
+ lastAttemptError: reason,
6918
+ nextRetryAt
6919
+ });
6686
6920
  await this.sleep(started.retry.retryDelayMs, signal);
6687
6921
  const evaluatingSupervisor = this.attachCycles(
6688
6922
  this.withCurrentTargetState(
@@ -6700,9 +6934,9 @@ var init_manager2 = __esm({
6700
6934
  async finalizeSuccessfulCycle(activeCycle, context, result, targetId) {
6701
6935
  const workspace = this.requireWorkspace(context.workspaceId);
6702
6936
  const currentSupervisor = this.supervisors.get(activeCycle.supervisorId) ?? this.requireSupervisor(activeCycle.supervisorId);
6703
- const targetMemory = targetId === currentSupervisor.targetId && currentSupervisor.currentTargetMemory ? currentSupervisor.currentTargetMemory : await this.deps.targetStore.loadTargetMemory(workspace.path, targetId);
6937
+ const evaluation = result.evaluation;
6704
6938
  const finalStatus = result.injected ? "injected" : "completed";
6705
- const cycleReason = result.evaluation.status === "stop" ? result.evaluation.reason : result.injected ? result.injectedText : result.evaluation.guidance ? `Skipped duplicate: ${result.evaluation.guidance}` : void 0;
6939
+ const cycleReason = isEvaluateStopResult(evaluation) ? evaluation.reason : result.injected ? result.injectedText : evaluation.guidance ? `Skipped duplicate: ${evaluation.guidance}` : void 0;
6706
6940
  const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
6707
6941
  status: finalStatus,
6708
6942
  result: cycleReason ?? null,
@@ -6710,24 +6944,22 @@ var init_manager2 = __esm({
6710
6944
  errorReason: null,
6711
6945
  completedAt: Date.now()
6712
6946
  });
6713
- const nextTargetMemory = this.applyEvaluationToTargetMemory(
6714
- targetMemory,
6715
- result.evaluation,
6716
- result.injectedText,
6717
- finishedCycle.completedAt ?? Date.now()
6718
- );
6947
+ const nextTargetMemory = {
6948
+ ...result.targetMemory,
6949
+ updatedAt: finishedCycle.completedAt ?? Date.now()
6950
+ };
6719
6951
  await this.deps.targetStore.saveTargetMemory(workspace.path, targetId, nextTargetMemory);
6720
- const cycleRecord = result.evaluation.status === "stop" ? {
6952
+ const cycleRecord = isEvaluateStopResult(evaluation) ? {
6721
6953
  cycleId: activeCycle.id,
6722
6954
  targetId,
6723
6955
  startedAt: activeCycle.createdAt,
6724
6956
  completedAt: finishedCycle.completedAt ?? Date.now(),
6725
6957
  result: "stop",
6726
- stopReason: result.evaluation.stopReason,
6727
- reason: result.evaluation.reason,
6728
- progressSummary: result.evaluation.progressSummary ?? nextTargetMemory.progressSummary,
6729
- activeStepId: result.evaluation.activeStepId ?? nextTargetMemory.activeStepId,
6730
- stepUpdates: result.evaluation.stepUpdates,
6958
+ stopReason: evaluation.stopReason,
6959
+ reason: evaluation.reason,
6960
+ progressSummary: nextTargetMemory.progressSummary,
6961
+ decompositionMode: nextTargetMemory.decompositionMode,
6962
+ activeItemId: nextTargetMemory.activeItemId,
6731
6963
  injected: false,
6732
6964
  attemptCount: this.deps.cycleAttemptRepo.listForCycle(activeCycle.id).length
6733
6965
  } : {
@@ -6736,18 +6968,19 @@ var init_manager2 = __esm({
6736
6968
  startedAt: activeCycle.createdAt,
6737
6969
  completedAt: finishedCycle.completedAt ?? Date.now(),
6738
6970
  result: "continue",
6739
- reason: result.evaluation.reason,
6740
- guidance: result.injected ? result.injectedText : result.evaluation.guidance,
6971
+ reason: evaluation.reason,
6972
+ guidance: result.injected ? result.injectedText : evaluation.guidance,
6741
6973
  progressSummary: nextTargetMemory.progressSummary,
6742
- activeStepId: nextTargetMemory.activeStepId,
6743
- stepUpdates: result.evaluation.stepUpdates,
6974
+ decompositionMode: nextTargetMemory.decompositionMode,
6975
+ activeItemId: nextTargetMemory.activeItemId,
6976
+ itemUpdates: evaluation.itemUpdates,
6744
6977
  injected: result.injected,
6745
6978
  attemptCount: this.deps.cycleAttemptRepo.listForCycle(activeCycle.id).length
6746
6979
  };
6747
6980
  await this.deps.targetStore.appendTargetCycleRecord(workspace.path, targetId, cycleRecord);
6748
- if (result.evaluation.status === "stop") {
6981
+ if (isEvaluateStopResult(evaluation)) {
6749
6982
  await this.updateTargetMetaStatus(workspace.path, targetId, {
6750
- status: result.evaluation.stopReason === "objective_complete" ? "completed" : "cancelled",
6983
+ status: evaluation.stopReason === "objective_complete" ? "completed" : "cancelled",
6751
6984
  completedAt: finishedCycle.completedAt ?? Date.now()
6752
6985
  });
6753
6986
  }
@@ -6764,9 +6997,9 @@ var init_manager2 = __esm({
6764
6997
  const finishedSupervisor = this.attachCycles(
6765
6998
  this.withCurrentTargetState(
6766
6999
  this.deps.supervisorRepo.update(activeCycle.supervisorId, {
6767
- state: result.evaluation.status === "stop" ? "stopped" : "idle",
7000
+ state: isEvaluateStopResult(result.evaluation) ? "stopped" : "idle",
6768
7001
  completedSupervisionCount: (this.supervisors.get(activeCycle.supervisorId)?.completedSupervisionCount ?? 0) + 1,
6769
- stopReason: result.evaluation.status === "stop" ? result.evaluation.stopReason : null,
7002
+ stopReason: isEvaluateStopResult(evaluation) ? evaluation.stopReason : null,
6770
7003
  lastCycleAt: finishedCycle.completedAt,
6771
7004
  lastEvaluatedTurnId: context.lastTurnId ?? void 0,
6772
7005
  errorReason: null,
@@ -6920,23 +7153,46 @@ var init_manager2 = __esm({
6920
7153
  };
6921
7154
  }
6922
7155
  applyEvaluationToTargetMemory(memory, evaluation, injectedText, updatedAt) {
6923
- let plan = memory.plan;
6924
- if (evaluation.plan && evaluation.plan.length > 0) {
6925
- plan = evaluation.plan;
6926
- } else if (evaluation.stepUpdates?.length) {
6927
- const updates = new Map(evaluation.stepUpdates.map((step) => [step.id, step.status]));
6928
- plan = memory.plan.map(
6929
- (step) => updates.has(step.id) ? { ...step, status: updates.get(step.id) } : step
7156
+ if (isDecomposeResult(evaluation)) {
7157
+ return {
7158
+ ...memory,
7159
+ decompositionGenerated: true,
7160
+ decompositionMode: evaluation.decompositionMode,
7161
+ items: evaluation.items,
7162
+ activeItemId: evaluation.activeItemId,
7163
+ progressSummary: evaluation.progressSummary ?? memory.progressSummary,
7164
+ updatedAt
7165
+ };
7166
+ }
7167
+ if (isEvaluateStopResult(evaluation)) {
7168
+ return {
7169
+ ...memory,
7170
+ decompositionGenerated: memory.decompositionGenerated,
7171
+ decompositionMode: memory.decompositionMode,
7172
+ items: memory.items,
7173
+ activeItemId: memory.activeItemId,
7174
+ progressSummary: memory.progressSummary,
7175
+ lastGuidance: memory.lastGuidance,
7176
+ stalledCount: 0,
7177
+ updatedAt
7178
+ };
7179
+ }
7180
+ let items = memory.items;
7181
+ if (evaluation.itemUpdates?.length) {
7182
+ const updates = new Map(evaluation.itemUpdates.map((item) => [item.id, item.status]));
7183
+ items = memory.items.map(
7184
+ (item) => updates.has(item.id) ? { ...item, status: updates.get(item.id) } : item
6930
7185
  );
6931
7186
  }
6932
7187
  const progressSummary = evaluation.progressSummary ?? memory.progressSummary;
6933
- const lastGuidance = evaluation.status === "continue" ? injectedText ?? evaluation.guidance ?? memory.lastGuidance : memory.lastGuidance;
6934
- const stalledCount = evaluation.status === "continue" && !evaluation.progressSummary && !evaluation.stepUpdates?.length ? memory.stalledCount + 1 : 0;
7188
+ const lastGuidance = injectedText ?? evaluation.guidance ?? memory.lastGuidance;
7189
+ const stalledCount = !evaluation.progressSummary && !evaluation.itemUpdates?.length ? memory.stalledCount + 1 : 0;
6935
7190
  return {
6936
7191
  ...memory,
6937
- planGenerated: memory.planGenerated || Boolean(evaluation.plan?.length),
6938
- plan,
6939
- activeStepId: evaluation.activeStepId ?? memory.activeStepId,
7192
+ decompositionGenerated: memory.decompositionGenerated,
7193
+ decompositionMode: memory.decompositionMode,
7194
+ items,
7195
+ activeItemId: evaluation.activeItemId ?? memory.activeItemId,
6940
7196
  progressSummary,
6941
7197
  lastGuidance,
6942
7198
  stalledCount,
@@ -7059,10 +7315,10 @@ var init_manager2 = __esm({
7059
7315
  { supervisor, event }
7060
7316
  );
7061
7317
  }
7062
- broadcastCycle(supervisor, cycle, event) {
7318
+ broadcastCycle(supervisor, cycle, event, runtime) {
7063
7319
  this.deps.broadcaster.broadcast(
7064
7320
  Topics.supervisorCycle(supervisor.workspaceId, supervisor.sessionId),
7065
- { cycle, event }
7321
+ { cycle: runtime ? { ...cycle, runtime } : cycle, event }
7066
7322
  );
7067
7323
  }
7068
7324
  shouldRetryAttempt(error, attemptIndex, retry) {
@@ -7088,10 +7344,10 @@ var init_manager2 = __esm({
7088
7344
  if (signal?.aborted) {
7089
7345
  throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
7090
7346
  }
7091
- await new Promise((resolve4, reject) => {
7347
+ await new Promise((resolve5, reject) => {
7092
7348
  const timer = setTimeout(() => {
7093
7349
  signal?.removeEventListener("abort", onAbort);
7094
- resolve4();
7350
+ resolve5();
7095
7351
  }, delayMs);
7096
7352
  timer.unref?.();
7097
7353
  const onAbort = () => {
@@ -7159,6 +7415,119 @@ function errorMessage(error, fallback) {
7159
7415
  }
7160
7416
  return fallback;
7161
7417
  }
7418
+ function isRecord(value) {
7419
+ return Boolean(value) && typeof value === "object";
7420
+ }
7421
+ function readNonEmptyString(value) {
7422
+ if (typeof value !== "string") {
7423
+ return void 0;
7424
+ }
7425
+ const next = value.trim();
7426
+ return next ? next : void 0;
7427
+ }
7428
+ function readStatus(value) {
7429
+ return value === "in_progress" || value === "done" || value === "pending" ? value : "pending";
7430
+ }
7431
+ function readDecompositionMode(value) {
7432
+ return value === "stage" || value === "subtarget" ? value : void 0;
7433
+ }
7434
+ function readNonNegativeInteger(value, fallback) {
7435
+ if (!Number.isSafeInteger(value) || typeof value !== "number" || value < 0) {
7436
+ return fallback;
7437
+ }
7438
+ return value;
7439
+ }
7440
+ function readTimestamp(value, fallback) {
7441
+ if (!Number.isSafeInteger(value) || typeof value !== "number") {
7442
+ return fallback;
7443
+ }
7444
+ return value;
7445
+ }
7446
+ function fallbackAcceptanceCriteria(title) {
7447
+ return [`${title} is complete`];
7448
+ }
7449
+ function normalizeItem(value, fallbackKind) {
7450
+ if (!isRecord(value)) {
7451
+ return null;
7452
+ }
7453
+ const id = readNonEmptyString(value.id);
7454
+ const title = readNonEmptyString(value.title);
7455
+ if (!id || !title) {
7456
+ return null;
7457
+ }
7458
+ const kind = readDecompositionMode(value.kind) ?? fallbackKind ?? "stage";
7459
+ const objective = readNonEmptyString(value.objective) ?? title;
7460
+ const deliverable = readNonEmptyString(value.deliverable) ?? `${title} completed`;
7461
+ const acceptanceCriteria = Array.isArray(value.acceptanceCriteria) ? value.acceptanceCriteria.flatMap((entry) => {
7462
+ const next = readNonEmptyString(entry);
7463
+ return next ? [next] : [];
7464
+ }) : [];
7465
+ return {
7466
+ id,
7467
+ kind,
7468
+ title,
7469
+ objective,
7470
+ deliverable,
7471
+ acceptanceCriteria: acceptanceCriteria.length > 0 ? acceptanceCriteria : fallbackAcceptanceCriteria(title),
7472
+ status: readStatus(value.status)
7473
+ };
7474
+ }
7475
+ function normalizeLegacyPlanItems(plan) {
7476
+ if (!Array.isArray(plan)) {
7477
+ return [];
7478
+ }
7479
+ return plan.flatMap((value) => {
7480
+ const item = normalizeItem(
7481
+ isRecord(value) ? {
7482
+ id: value.id,
7483
+ kind: "stage",
7484
+ title: value.title,
7485
+ objective: value.title,
7486
+ deliverable: `${readNonEmptyString(value.title) ?? "Legacy step"} completed`,
7487
+ acceptanceCriteria: fallbackAcceptanceCriteria(
7488
+ readNonEmptyString(value.title) ?? "Legacy step"
7489
+ ),
7490
+ status: value.status
7491
+ } : value,
7492
+ "stage"
7493
+ );
7494
+ return item ? [item] : [];
7495
+ });
7496
+ }
7497
+ function resolveActiveItemId(items, candidate) {
7498
+ const next = readNonEmptyString(candidate);
7499
+ if (next && items.some((item) => item.id === next)) {
7500
+ return next;
7501
+ }
7502
+ return items.find((item) => item.status === "in_progress")?.id ?? items.find((item) => item.status === "pending")?.id ?? items[0]?.id;
7503
+ }
7504
+ function normalizeTargetMemory(raw, targetId) {
7505
+ if (!isRecord(raw)) {
7506
+ return buildTargetMemory(targetId, 0);
7507
+ }
7508
+ const updatedAt = readTimestamp(raw.updatedAt, 0);
7509
+ const declaredMode = readDecompositionMode(raw.decompositionMode);
7510
+ let items = Array.isArray(raw.items) ? raw.items.flatMap((value) => {
7511
+ const item = normalizeItem(value, declaredMode);
7512
+ return item ? [item] : [];
7513
+ }) : [];
7514
+ let decompositionMode = declaredMode ?? items[0]?.kind;
7515
+ if (items.length === 0) {
7516
+ items = normalizeLegacyPlanItems(raw.plan);
7517
+ decompositionMode = items.length > 0 ? "stage" : void 0;
7518
+ }
7519
+ return {
7520
+ targetId: readNonEmptyString(raw.targetId) ?? targetId,
7521
+ decompositionGenerated: items.length > 0,
7522
+ decompositionMode,
7523
+ items,
7524
+ activeItemId: resolveActiveItemId(items, raw.activeItemId ?? raw.activeStepId),
7525
+ progressSummary: readNonEmptyString(raw.progressSummary),
7526
+ lastGuidance: readNonEmptyString(raw.lastGuidance),
7527
+ stalledCount: readNonNegativeInteger(raw.stalledCount, 0),
7528
+ updatedAt
7529
+ };
7530
+ }
7162
7531
  async function writeJsonIfMissing(path10, value) {
7163
7532
  try {
7164
7533
  await writeFile3(path10, JSON.stringify(value, null, 2) + "\n", {
@@ -7187,8 +7556,12 @@ function buildTargetMeta(input) {
7187
7556
  function buildTargetMemory(targetId, createdAt) {
7188
7557
  return {
7189
7558
  targetId,
7190
- planGenerated: false,
7191
- plan: [],
7559
+ decompositionGenerated: false,
7560
+ decompositionMode: void 0,
7561
+ items: [],
7562
+ activeItemId: void 0,
7563
+ progressSummary: void 0,
7564
+ lastGuidance: void 0,
7192
7565
  stalledCount: 0,
7193
7566
  updatedAt: createdAt
7194
7567
  };
@@ -7277,8 +7650,9 @@ async function readTargetMeta(workspacePath, targetId) {
7277
7650
  );
7278
7651
  }
7279
7652
  async function loadTargetMemory(workspacePath, targetId) {
7280
- return JSON.parse(
7281
- await readFile2(memoryPath(workspacePath, targetId), "utf-8")
7653
+ return normalizeTargetMemory(
7654
+ JSON.parse(await readFile2(memoryPath(workspacePath, targetId), "utf-8")),
7655
+ targetId
7282
7656
  );
7283
7657
  }
7284
7658
  async function saveTargetMemory(workspacePath, targetId, memory) {
@@ -7615,8 +7989,8 @@ var init_terminal_snapshot_buffer = __esm({
7615
7989
  if (this.pendingWriteCount === 0) {
7616
7990
  return Promise.resolve();
7617
7991
  }
7618
- return new Promise((resolve4) => {
7619
- this.drainResolvers.push(resolve4);
7992
+ return new Promise((resolve5) => {
7993
+ this.drainResolvers.push(resolve5);
7620
7994
  });
7621
7995
  }
7622
7996
  resolveDrainIfIdle() {
@@ -7625,8 +7999,8 @@ var init_terminal_snapshot_buffer = __esm({
7625
7999
  }
7626
8000
  const resolvers = this.drainResolvers;
7627
8001
  this.drainResolvers = [];
7628
- for (const resolve4 of resolvers) {
7629
- resolve4();
8002
+ for (const resolve5 of resolvers) {
8003
+ resolve5();
7630
8004
  }
7631
8005
  }
7632
8006
  requireTerminal() {
@@ -7945,10 +8319,10 @@ var init_manager3 = __esm({
7945
8319
  }
7946
8320
  return existing.promise;
7947
8321
  }
7948
- let resolve4 = () => {
8322
+ let resolve5 = () => {
7949
8323
  };
7950
8324
  const promise = new Promise((innerResolve) => {
7951
- resolve4 = innerResolve;
8325
+ resolve5 = innerResolve;
7952
8326
  });
7953
8327
  let markKillCompleted = () => {
7954
8328
  };
@@ -7961,7 +8335,7 @@ var init_manager3 = __esm({
7961
8335
  markKillCompleted,
7962
8336
  finalized: false,
7963
8337
  promise,
7964
- resolve: resolve4
8338
+ resolve: resolve5
7965
8339
  });
7966
8340
  void terminal.pty.kill(signal).finally(() => {
7967
8341
  const waiter = this.explicitCloseWaiters.get(terminalId);
@@ -8168,20 +8542,8 @@ function createTreeVisibilityFilter() {
8168
8542
  return (name) => !isTreeHidden(name);
8169
8543
  }
8170
8544
  function createWatcherIgnoreFilter(rootPath) {
8171
- const gitignorePath = join5(rootPath, ".gitignore");
8172
- if (!existsSync5(gitignorePath)) {
8173
- return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
8174
- }
8175
- const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
8176
- const ig = ignore().add(gitignoreContent);
8177
- return (path10) => {
8178
- const normalizedPath = normalizePath(path10);
8179
- if (DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizedPath))) {
8180
- return true;
8181
- }
8182
- const relativePath = relativeToRoot(rootPath, path10);
8183
- return isIgnoredByGitignore(ig, relativePath);
8184
- };
8545
+ void rootPath;
8546
+ return (path10) => DEFAULT_WATCHER_IGNORED_PATTERNS.some((p) => p.test(normalizePath(path10)));
8185
8547
  }
8186
8548
  var DEFAULT_WATCHER_IGNORED_PATTERNS;
8187
8549
  var init_gitignore = __esm({
@@ -8246,11 +8608,11 @@ var init_watcher = __esm({
8246
8608
  this.pendingReason = "fs_change";
8247
8609
  }
8248
8610
  const elapsed = now - this.firstDirtyTime;
8249
- const delay = Math.min(this.DEBOUNCE_MS, Math.max(0, this.MAX_WAIT_MS - elapsed));
8611
+ const delay2 = Math.min(this.DEBOUNCE_MS, Math.max(0, this.MAX_WAIT_MS - elapsed));
8250
8612
  if (this.dirtyTimer) {
8251
8613
  clearTimeout(this.dirtyTimer);
8252
8614
  }
8253
- this.dirtyTimer = setTimeout(() => this.flushDirty(), delay);
8615
+ this.dirtyTimer = setTimeout(() => this.flushDirty(), delay2);
8254
8616
  }
8255
8617
  flushDirty() {
8256
8618
  this.broadcaster?.broadcast(Topics.workspaceFsDirty(this.workspaceId), {
@@ -8848,7 +9210,8 @@ var init_fencing = __esm({
8848
9210
  });
8849
9211
 
8850
9212
  // packages/server/src/commands/terminal.ts
8851
- import { basename } from "node:path";
9213
+ import { stat as stat6 } from "node:fs/promises";
9214
+ import { basename, isAbsolute as isAbsolute3 } from "node:path";
8852
9215
  import { z as z5 } from "zod";
8853
9216
  function decodeTerminalInput(args) {
8854
9217
  if ("bytes" in args) {
@@ -8919,6 +9282,7 @@ var init_terminal = __esm({
8919
9282
  "packages/server/src/commands/terminal.ts"() {
8920
9283
  "use strict";
8921
9284
  init_src3();
9285
+ init_file_io();
8922
9286
  init_dispatch();
8923
9287
  TerminalInputActivitySchema = z5.enum(TERMINAL_INPUT_ACTIVITIES).optional();
8924
9288
  TerminalInputSchema = z5.union([
@@ -8953,20 +9317,44 @@ var init_terminal = __esm({
8953
9317
  z5.object({
8954
9318
  workspaceId: z5.string(),
8955
9319
  cols: z5.number().int().positive().optional(),
8956
- rows: z5.number().int().positive().optional()
9320
+ rows: z5.number().int().positive().optional(),
9321
+ cwdPath: z5.string().optional()
8957
9322
  }),
8958
9323
  async (args, ctx) => {
8959
9324
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
8960
9325
  if (!workspace) {
8961
9326
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
8962
9327
  }
9328
+ let cwd = workspace.path;
9329
+ if (args.cwdPath && args.cwdPath !== ".") {
9330
+ if (isAbsolute3(args.cwdPath)) {
9331
+ throw { code: "invalid_cwd_path", message: "cwdPath must be workspace-relative" };
9332
+ }
9333
+ let resolvedCwd;
9334
+ try {
9335
+ resolvedCwd = resolveSafe(workspace.path, args.cwdPath);
9336
+ } catch (error) {
9337
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "path_escape") {
9338
+ throw { code: "invalid_cwd_path", message: "cwdPath must be workspace-relative" };
9339
+ }
9340
+ throw error;
9341
+ }
9342
+ const cwdStats = await stat6(resolvedCwd).catch(() => null);
9343
+ if (!cwdStats) {
9344
+ throw { code: "cwd_not_found", message: `Directory not found: ${args.cwdPath}` };
9345
+ }
9346
+ if (!cwdStats.isDirectory()) {
9347
+ throw { code: "cwd_not_directory", message: `Not a directory: ${args.cwdPath}` };
9348
+ }
9349
+ cwd = resolvedCwd;
9350
+ }
8963
9351
  const shell = resolveShellCommand();
8964
9352
  const terminal = ctx.terminalMgr.create({
8965
9353
  workspaceId: args.workspaceId,
8966
9354
  kind: "shell",
8967
9355
  argv: shell.argv,
8968
9356
  title: shell.title,
8969
- cwd: workspace.path,
9357
+ cwd,
8970
9358
  cols: args.cols ?? 120,
8971
9359
  rows: args.rows ?? 30
8972
9360
  });
@@ -9652,7 +10040,7 @@ var init_hub = __esm({
9652
10040
  }
9653
10041
  }
9654
10042
  awaitBinaryPayload(clientId) {
9655
- return new Promise((resolve4, reject) => {
10043
+ return new Promise((resolve5, reject) => {
9656
10044
  const timer = setTimeout(() => {
9657
10045
  const waiters = this.pendingBinaryWaiters.get(clientId);
9658
10046
  if (!waiters) return;
@@ -9664,7 +10052,7 @@ var init_hub = __esm({
9664
10052
  }
9665
10053
  reject(new Error("Timeout waiting for terminal input binary payload"));
9666
10054
  }, BINARY_PAYLOAD_TIMEOUT_MS);
9667
- const waiter = { resolve: resolve4, reject, timer };
10055
+ const waiter = { resolve: resolve5, reject, timer };
9668
10056
  const queue = this.pendingBinaryWaiters.get(clientId);
9669
10057
  if (queue) {
9670
10058
  queue.push(waiter);
@@ -9942,10 +10330,34 @@ var init_hub = __esm({
9942
10330
  });
9943
10331
 
9944
10332
  // packages/server/src/commands/workspace.ts
9945
- import { readdir as readdir2 } from "node:fs/promises";
10333
+ import { readdir as readdir2, realpath as realpath2 } from "node:fs/promises";
9946
10334
  import { homedir as homedir2 } from "node:os";
9947
- import { join as join6 } from "node:path";
10335
+ import { isAbsolute as isAbsolute4, join as join6, resolve as resolve3 } from "node:path";
9948
10336
  import { z as z6 } from "zod";
10337
+ function resolveBrowsePath(path10) {
10338
+ const home = homedir2();
10339
+ if (!path10 || path10 === "~") {
10340
+ return home;
10341
+ }
10342
+ if (path10.startsWith("~/")) {
10343
+ return join6(home, path10.slice(2));
10344
+ }
10345
+ return isAbsolute4(path10) ? path10 : resolve3(home, path10);
10346
+ }
10347
+ async function buildRootPaths(currentPath) {
10348
+ const roots = /* @__PURE__ */ new Set(["/"]);
10349
+ const home = homedir2();
10350
+ roots.add(home);
10351
+ try {
10352
+ roots.add(await realpath2(home));
10353
+ } catch {
10354
+ }
10355
+ const currentSegments = currentPath.split("/").filter(Boolean);
10356
+ if (currentSegments.length > 0) {
10357
+ roots.add(`/${currentSegments[0]}`);
10358
+ }
10359
+ return Array.from(roots);
10360
+ }
9949
10361
  var init_workspace = __esm({
9950
10362
  "packages/server/src/commands/workspace.ts"() {
9951
10363
  "use strict";
@@ -9959,7 +10371,7 @@ var init_workspace = __esm({
9959
10371
  path: z6.string().optional()
9960
10372
  }),
9961
10373
  async (args) => {
9962
- const basePath = args.path || homedir2();
10374
+ const basePath = resolveBrowsePath(args.path);
9963
10375
  const entries = await readdir2(basePath, { withFileTypes: true });
9964
10376
  const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
9965
10377
  name: entry.name,
@@ -9968,7 +10380,8 @@ var init_workspace = __esm({
9968
10380
  return {
9969
10381
  currentPath: basePath,
9970
10382
  parentPath: basePath !== "/" ? join6(basePath, "..") : null,
9971
- directories
10383
+ directories,
10384
+ rootPaths: await buildRootPaths(basePath)
9972
10385
  };
9973
10386
  }
9974
10387
  );
@@ -10001,6 +10414,7 @@ var init_workspace = __esm({
10001
10414
  bottomPanelHeight: z6.number(),
10002
10415
  focusMode: z6.boolean(),
10003
10416
  activeSessionId: z6.string().optional(),
10417
+ fileTreeExpandedDirs: z6.array(z6.string()).optional(),
10004
10418
  paneLayout: z6.object({
10005
10419
  id: z6.string(),
10006
10420
  type: z6.enum(["leaf", "split"]),
@@ -10264,16 +10678,105 @@ var init_runtime_status = __esm({
10264
10678
  }
10265
10679
  });
10266
10680
 
10681
+ // packages/server/src/workspace/pane-layout.ts
10682
+ function applyPaneDisposition(layout, sessionId, disposition) {
10683
+ if (!layout) {
10684
+ return layout;
10685
+ }
10686
+ return disposition === "remove" ? removePaneBySessionId(layout, sessionId) : closePaneBySessionId(layout, sessionId);
10687
+ }
10688
+ function closePaneBySessionId(node, sessionId) {
10689
+ return replaceSessionWithDraft(node, sessionId);
10690
+ }
10691
+ function replaceSessionWithDraft(node, sessionId) {
10692
+ if (node.type === "leaf") {
10693
+ if (node.sessionId === sessionId) {
10694
+ return {
10695
+ id: node.id,
10696
+ type: "leaf"
10697
+ };
10698
+ }
10699
+ return node;
10700
+ }
10701
+ const children = node.children ?? [];
10702
+ let changed = false;
10703
+ const nextChildren = children.map((child) => {
10704
+ const nextChild = replaceSessionWithDraft(child, sessionId);
10705
+ if (nextChild !== child) {
10706
+ changed = true;
10707
+ }
10708
+ return nextChild;
10709
+ });
10710
+ if (!changed) {
10711
+ return node;
10712
+ }
10713
+ return {
10714
+ ...node,
10715
+ children: nextChildren
10716
+ };
10717
+ }
10718
+ function removePaneBySessionId(node, sessionId) {
10719
+ return removeSessionPane(node, sessionId) ?? { id: node.id, type: "leaf" };
10720
+ }
10721
+ function removeSessionPane(node, sessionId) {
10722
+ if (node.type === "leaf") {
10723
+ if (node.sessionId === sessionId) {
10724
+ return null;
10725
+ }
10726
+ return node;
10727
+ }
10728
+ const children = node.children ?? [];
10729
+ let changed = false;
10730
+ const nextChildren = [];
10731
+ for (const child of children) {
10732
+ const nextChild = removeSessionPane(child, sessionId);
10733
+ if (nextChild !== child) {
10734
+ changed = true;
10735
+ }
10736
+ if (nextChild !== null) {
10737
+ nextChildren.push(nextChild);
10738
+ }
10739
+ }
10740
+ if (!changed) {
10741
+ return node;
10742
+ }
10743
+ if (nextChildren.length === 1) {
10744
+ return nextChildren[0];
10745
+ }
10746
+ if (nextChildren.length === 0) {
10747
+ return null;
10748
+ }
10749
+ return {
10750
+ ...node,
10751
+ children: nextChildren
10752
+ };
10753
+ }
10754
+ var init_pane_layout = __esm({
10755
+ "packages/server/src/workspace/pane-layout.ts"() {
10756
+ "use strict";
10757
+ }
10758
+ });
10759
+
10267
10760
  // packages/server/src/commands/session.ts
10268
10761
  import { z as z10 } from "zod";
10762
+ function delay(ms) {
10763
+ return new Promise((resolve5) => {
10764
+ setTimeout(resolve5, ms);
10765
+ });
10766
+ }
10269
10767
  function getProviderFromRegistry(providerId, registry) {
10270
10768
  return registry.find((provider) => provider.id === providerId);
10271
10769
  }
10770
+ var SESSION_CLOSE_POLL_INTERVAL_MS, SESSION_CLOSE_TIMEOUT_MS;
10272
10771
  var init_session = __esm({
10273
10772
  "packages/server/src/commands/session.ts"() {
10274
10773
  "use strict";
10275
10774
  init_runtime_status();
10775
+ init_database();
10776
+ init_pane_layout();
10276
10777
  init_dispatch();
10778
+ SESSION_CLOSE_POLL_INTERVAL_MS = 100;
10779
+ SESSION_CLOSE_TIMEOUT_MS = 5e3;
10277
10780
  registerCommand(
10278
10781
  "session.list",
10279
10782
  z10.object({
@@ -10345,11 +10848,75 @@ var init_session = __esm({
10345
10848
  ctx.sessionMgr.delete(args.sessionId);
10346
10849
  }
10347
10850
  );
10851
+ registerCommand(
10852
+ "session.close",
10853
+ z10.object({
10854
+ sessionId: z10.string(),
10855
+ paneDisposition: z10.enum(["draft", "remove"]).default("draft")
10856
+ }),
10857
+ async (args, ctx) => {
10858
+ let session = ctx.sessionMgr.get(args.sessionId);
10859
+ if (!session) {
10860
+ throw { code: "session_not_found", message: `Session not found: ${args.sessionId}` };
10861
+ }
10862
+ if (session.state !== "ended") {
10863
+ try {
10864
+ await ctx.sessionMgr.stop(args.sessionId);
10865
+ } catch (error) {
10866
+ const candidate = error;
10867
+ throw {
10868
+ code: "session_close_failed",
10869
+ message: candidate.message ?? `Failed to stop session: ${args.sessionId}`
10870
+ };
10871
+ }
10872
+ const deadline = Date.now() + SESSION_CLOSE_TIMEOUT_MS;
10873
+ while (Date.now() < deadline) {
10874
+ session = ctx.sessionMgr.get(args.sessionId);
10875
+ if (!session) {
10876
+ return;
10877
+ }
10878
+ if (session.state === "ended") {
10879
+ break;
10880
+ }
10881
+ await delay(SESSION_CLOSE_POLL_INTERVAL_MS);
10882
+ }
10883
+ session = ctx.sessionMgr.get(args.sessionId);
10884
+ if (!session) {
10885
+ return;
10886
+ }
10887
+ if (session.state !== "ended") {
10888
+ throw {
10889
+ code: "session_close_timeout",
10890
+ message: `Timed out waiting for session to end before closing: ${args.sessionId}`
10891
+ };
10892
+ }
10893
+ }
10894
+ const workspace = ctx.workspaceMgr.get(session.workspaceId);
10895
+ if (!workspace) {
10896
+ throw {
10897
+ code: "workspace_not_found",
10898
+ message: `Workspace not found: ${session.workspaceId}`
10899
+ };
10900
+ }
10901
+ const nextUiState = {
10902
+ ...workspace.uiState,
10903
+ paneLayout: applyPaneDisposition(
10904
+ workspace.uiState.paneLayout,
10905
+ args.sessionId,
10906
+ args.paneDisposition
10907
+ )
10908
+ };
10909
+ withTransaction(ctx.db, () => {
10910
+ ctx.workspaceMgr.updateUiState(session.workspaceId, nextUiState);
10911
+ ctx.sessionMgr.delete(args.sessionId);
10912
+ });
10913
+ }
10914
+ );
10348
10915
  }
10349
10916
  });
10350
10917
 
10351
10918
  // packages/server/src/fs/tree.ts
10352
- import { readdir as readdir3, stat as stat6 } from "fs/promises";
10919
+ import { readdir as readdir3, stat as stat7 } from "fs/promises";
10353
10920
  import { join as join7, relative as relative4 } from "path";
10354
10921
  async function readTree(rootPath, subdir) {
10355
10922
  const targetPath = subdir ? join7(rootPath, subdir) : rootPath;
@@ -10371,7 +10938,7 @@ async function readTree(rootPath, subdir) {
10371
10938
  // Not loaded yet - client will request on expand
10372
10939
  });
10373
10940
  } else if (entry.isFile()) {
10374
- const stats = await stat6(fullPath);
10941
+ const stats = await stat7(fullPath);
10375
10942
  nodes.push({
10376
10943
  name: entry.name,
10377
10944
  path: relPath,
@@ -10440,7 +11007,7 @@ async function searchFiles(rootPath, query, limit = 10) {
10440
11007
  }
10441
11008
  return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
10442
11009
  }).slice(0, limit)) {
10443
- const stats = await stat6(match.fullPath);
11010
+ const stats = await stat7(match.fullPath);
10444
11011
  files.push({
10445
11012
  name: match.name,
10446
11013
  path: match.path,
@@ -10607,6 +11174,27 @@ var init_file = __esm({
10607
11174
  return { ok: true };
10608
11175
  }
10609
11176
  );
11177
+ registerCommand(
11178
+ "file.rename",
11179
+ z11.object({
11180
+ workspaceId: z11.string(),
11181
+ fromPath: z11.string(),
11182
+ toPath: z11.string()
11183
+ }),
11184
+ async (args, ctx) => {
11185
+ const workspace = ctx.workspaceMgr.get(args.workspaceId);
11186
+ if (!workspace) {
11187
+ throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
11188
+ }
11189
+ await renameEntry(workspace.path, args.fromPath, args.toPath);
11190
+ ctx.eventBus.emit({
11191
+ type: "fs.dirty",
11192
+ workspaceId: args.workspaceId,
11193
+ reason: "fs_change"
11194
+ });
11195
+ return { ok: true };
11196
+ }
11197
+ );
10610
11198
  registerCommand(
10611
11199
  "file.write",
10612
11200
  z11.object({
@@ -10788,7 +11376,7 @@ import { mkdir as mkdir4, mkdtemp as mkdtemp2, rm as rm5, writeFile as writeFile
10788
11376
  import os2 from "os";
10789
11377
  import path6 from "path";
10790
11378
  async function runGit(cwd, args, options = {}) {
10791
- return new Promise((resolve4, reject) => {
11379
+ return new Promise((resolve5, reject) => {
10792
11380
  const gitArgs = [
10793
11381
  ...options.config?.flatMap(([key, value]) => ["-c", `${key}=${value}`]) ?? [],
10794
11382
  ...args
@@ -10815,7 +11403,7 @@ async function runGit(cwd, args, options = {}) {
10815
11403
  if (err) {
10816
11404
  reject(new GitError(err.message, stderr));
10817
11405
  } else {
10818
- resolve4({ stdout, stderr });
11406
+ resolve5({ stdout, stderr });
10819
11407
  }
10820
11408
  }
10821
11409
  );
@@ -12016,6 +12604,9 @@ var init_settings2 = __esm({
12016
12604
  themeId: z13.string().optional(),
12017
12605
  terminalRenderer: z13.enum(["standard", "compatibility"]).optional(),
12018
12606
  terminalCopyOnSelect: z13.boolean().optional(),
12607
+ terminalFontSize: z13.number().int().min(10).max(18).optional(),
12608
+ desktopTerminalFontSize: z13.number().int().min(10).max(18).optional(),
12609
+ mobileTerminalFontSize: z13.number().int().min(10).max(18).optional(),
12019
12610
  locale: z13.enum(["zh", "en"]).optional()
12020
12611
  }).optional(),
12021
12612
  providers: ProviderSettingsSchema.optional()
@@ -12156,20 +12747,373 @@ var init_settings2 = __esm({
12156
12747
  }
12157
12748
  });
12158
12749
 
12159
- // packages/server/src/commands/provider.ts
12750
+ // packages/server/src/commands/diagnostics.ts
12160
12751
  import { z as z14 } from "zod";
12752
+ function isLoopbackHost(host) {
12753
+ return host === void 0 || host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "0.0.0.0";
12754
+ }
12755
+ async function resolveWorkspacePathCheck(workspacePath) {
12756
+ if (!workspacePath) {
12757
+ return {
12758
+ canContinue: false,
12759
+ checks: [
12760
+ {
12761
+ id: "workspace-selection",
12762
+ code: "workspace_selection_missing",
12763
+ status: "needs_attention"
12764
+ }
12765
+ ]
12766
+ };
12767
+ }
12768
+ const validation = await validatePath(workspacePath);
12769
+ if (validation.valid) {
12770
+ return {
12771
+ canContinue: true,
12772
+ checks: [
12773
+ {
12774
+ id: "workspace-path",
12775
+ code: "workspace_path_ready",
12776
+ status: "ready",
12777
+ workspacePath
12778
+ }
12779
+ ]
12780
+ };
12781
+ }
12782
+ return {
12783
+ canContinue: false,
12784
+ checks: [
12785
+ {
12786
+ id: "workspace-path",
12787
+ code: validation.error === "Path does not exist" ? "workspace_path_not_found" : "workspace_path_unreadable",
12788
+ status: "needs_attention",
12789
+ workspacePath
12790
+ }
12791
+ ]
12792
+ };
12793
+ }
12794
+ function buildProviderCheck(providerStatus, providerId) {
12795
+ if (providerStatus.available) {
12796
+ return {
12797
+ canContinue: true,
12798
+ checks: [
12799
+ {
12800
+ id: `provider:${providerId}`,
12801
+ code: "provider_runtime_ready",
12802
+ status: "ready",
12803
+ providerId,
12804
+ autoInstallSupported: providerStatus.autoInstallSupported,
12805
+ installReadiness: providerStatus.installReadiness
12806
+ }
12807
+ ]
12808
+ };
12809
+ }
12810
+ if (providerStatus.missingPrerequisites.length > 0) {
12811
+ return {
12812
+ canContinue: false,
12813
+ checks: [
12814
+ {
12815
+ id: `provider:${providerId}`,
12816
+ code: "provider_prerequisite_missing",
12817
+ status: "needs_attention",
12818
+ providerId,
12819
+ autoInstallSupported: providerStatus.autoInstallSupported,
12820
+ installReadiness: providerStatus.installReadiness,
12821
+ missingCommands: providerStatus.missingCommands,
12822
+ missingPrerequisites: providerStatus.missingPrerequisites,
12823
+ manualGuideKeys: providerStatus.manualGuideKeys,
12824
+ docUrl: providerStatus.docUrls.provider
12825
+ }
12826
+ ]
12827
+ };
12828
+ }
12829
+ return {
12830
+ canContinue: false,
12831
+ checks: [
12832
+ {
12833
+ id: `provider:${providerId}`,
12834
+ code: "provider_cli_missing",
12835
+ status: "needs_attention",
12836
+ providerId,
12837
+ autoInstallSupported: providerStatus.autoInstallSupported,
12838
+ installReadiness: providerStatus.installReadiness,
12839
+ missingCommands: providerStatus.missingCommands,
12840
+ missingPrerequisites: providerStatus.missingPrerequisites,
12841
+ manualGuideKeys: providerStatus.manualGuideKeys,
12842
+ docUrl: providerStatus.docUrls.provider
12843
+ }
12844
+ ]
12845
+ };
12846
+ }
12847
+ async function buildWorkspaceSelectionChecks(args, ctx) {
12848
+ if (args.workspacePath) {
12849
+ const workspaceResult = await resolveWorkspacePathCheck(args.workspacePath);
12850
+ return {
12851
+ canContinue: workspaceResult.canContinue,
12852
+ checks: workspaceResult.checks,
12853
+ workspacePath: args.workspacePath
12854
+ };
12855
+ }
12856
+ const workspace = args.workspaceId ? ctx.workspaceMgr.get(args.workspaceId) : void 0;
12857
+ if (!args.workspaceId) {
12858
+ return {
12859
+ canContinue: true,
12860
+ checks: []
12861
+ };
12862
+ }
12863
+ if (!workspace) {
12864
+ return {
12865
+ canContinue: false,
12866
+ checks: [
12867
+ {
12868
+ id: "session-workspace",
12869
+ code: "session_workspace_missing",
12870
+ status: "needs_attention",
12871
+ workspaceId: args.workspaceId
12872
+ }
12873
+ ]
12874
+ };
12875
+ }
12876
+ const pathCheck = await resolveWorkspacePathCheck(workspace.path);
12877
+ return {
12878
+ canContinue: pathCheck.canContinue,
12879
+ checks: [
12880
+ {
12881
+ id: "session-workspace",
12882
+ code: "session_workspace_ready",
12883
+ status: "ready",
12884
+ workspaceId: workspace.id,
12885
+ workspacePath: workspace.path
12886
+ },
12887
+ ...pathCheck.checks.map(
12888
+ (check) => check.id === "workspace-path" ? {
12889
+ ...check,
12890
+ id: `workspace-path:${workspace.id}`
12891
+ } : check
12892
+ )
12893
+ ],
12894
+ workspacePath: workspace.path
12895
+ };
12896
+ }
12897
+ async function buildAllProviderChecks(ctx, preferredProviderId) {
12898
+ const checks = [];
12899
+ let canContinueForPreferredProvider = preferredProviderId ? false : true;
12900
+ const runtimeStatus = await buildProviderRuntimeStatus(
12901
+ ctx.providerRegistry,
12902
+ ctx.providerRuntimeDeps
12903
+ );
12904
+ for (const provider of ctx.providerRegistry) {
12905
+ const providerStatus = runtimeStatus.providers[provider.id];
12906
+ if (!providerStatus) {
12907
+ checks.push({
12908
+ id: `provider:${provider.id}`,
12909
+ code: "provider_unknown",
12910
+ status: "needs_attention",
12911
+ providerId: provider.id
12912
+ });
12913
+ if (provider.id === preferredProviderId) {
12914
+ canContinueForPreferredProvider = false;
12915
+ }
12916
+ continue;
12917
+ }
12918
+ const providerCheck = buildProviderCheck(providerStatus, provider.id);
12919
+ checks.push(...providerCheck.checks);
12920
+ if (provider.id === preferredProviderId) {
12921
+ canContinueForPreferredProvider = providerCheck.canContinue;
12922
+ }
12923
+ }
12924
+ if (preferredProviderId && !ctx.providerRegistry.find((provider) => provider.id === preferredProviderId)) {
12925
+ checks.unshift({
12926
+ id: "session-provider",
12927
+ code: "provider_unknown",
12928
+ status: "needs_attention",
12929
+ providerId: preferredProviderId
12930
+ });
12931
+ canContinueForPreferredProvider = false;
12932
+ }
12933
+ return { checks, canContinueForPreferredProvider };
12934
+ }
12935
+ function buildServerAuthCheck(ctx) {
12936
+ return {
12937
+ id: "server-auth",
12938
+ code: ctx.config?.auth.enabled ? "server_auth_ready" : "server_auth_not_required",
12939
+ status: "ready"
12940
+ };
12941
+ }
12942
+ function buildMobileHostCheck(ctx) {
12943
+ if (isLoopbackHost(ctx.config?.host)) {
12944
+ return {
12945
+ canContinue: false,
12946
+ check: {
12947
+ id: "mobile-host",
12948
+ code: "mobile_host_local_only",
12949
+ status: "needs_attention"
12950
+ }
12951
+ };
12952
+ }
12953
+ return {
12954
+ canContinue: true,
12955
+ check: {
12956
+ id: "mobile-host",
12957
+ code: "mobile_host_ready",
12958
+ status: "ready"
12959
+ }
12960
+ };
12961
+ }
12962
+ async function buildSessionStartDiagnostics(args, ctx) {
12963
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
12964
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
12965
+ const mobileHost = buildMobileHostCheck(ctx);
12966
+ const checks = [
12967
+ ...workspaceSelection.checks,
12968
+ ...providerChecks.checks,
12969
+ buildServerAuthCheck(ctx),
12970
+ mobileHost.check
12971
+ ];
12972
+ const canContinue = workspaceSelection.canContinue && providerChecks.canContinueForPreferredProvider;
12973
+ return {
12974
+ context: "session_start",
12975
+ canContinue,
12976
+ checks,
12977
+ metadata: {
12978
+ providerId: args.providerId,
12979
+ workspaceId: args.workspaceId,
12980
+ workspacePath: workspaceSelection.workspacePath,
12981
+ authEnabled: ctx.config?.auth.enabled ?? false,
12982
+ host: ctx.config?.host
12983
+ }
12984
+ };
12985
+ }
12986
+ async function buildManualDiagnostics(args, ctx) {
12987
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
12988
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
12989
+ const mobileHost = buildMobileHostCheck(ctx);
12990
+ const checks = [
12991
+ ...workspaceSelection.checks,
12992
+ ...providerChecks.checks,
12993
+ buildServerAuthCheck(ctx),
12994
+ mobileHost.check
12995
+ ];
12996
+ return {
12997
+ context: "manual_check",
12998
+ canContinue: checks.every((check) => check.status !== "needs_attention"),
12999
+ checks,
13000
+ metadata: {
13001
+ authEnabled: ctx.config?.auth.enabled ?? false,
13002
+ host: ctx.config?.host,
13003
+ providerId: args.providerId,
13004
+ workspaceId: args.workspaceId,
13005
+ workspacePath: workspaceSelection.workspacePath ?? args.workspacePath
13006
+ }
13007
+ };
13008
+ }
13009
+ async function buildMobileDiagnostics(args, ctx) {
13010
+ const host = ctx.config?.host;
13011
+ const authEnabled = ctx.config?.auth.enabled ?? false;
13012
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
13013
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
13014
+ const mobileHost = buildMobileHostCheck(ctx);
13015
+ const checks = [
13016
+ ...workspaceSelection.checks,
13017
+ ...providerChecks.checks,
13018
+ buildServerAuthCheck(ctx),
13019
+ mobileHost.check
13020
+ ];
13021
+ let canContinue = mobileHost.canContinue;
13022
+ if (!authEnabled) {
13023
+ canContinue = false;
13024
+ checks.push({
13025
+ id: "mobile-auth",
13026
+ code: "mobile_auth_disabled",
13027
+ status: "needs_attention"
13028
+ });
13029
+ } else {
13030
+ checks.push({
13031
+ id: "mobile-auth",
13032
+ code: "server_auth_ready",
13033
+ status: "ready"
13034
+ });
13035
+ }
13036
+ return {
13037
+ context: "mobile_continue",
13038
+ canContinue,
13039
+ checks,
13040
+ metadata: {
13041
+ authEnabled,
13042
+ host,
13043
+ workspaceId: args.workspaceId,
13044
+ workspacePath: workspaceSelection.workspacePath,
13045
+ providerId: args.providerId
13046
+ }
13047
+ };
13048
+ }
13049
+ async function buildDiagnostics(args, ctx) {
13050
+ switch (args.context) {
13051
+ case "workspace_open": {
13052
+ const workspaceSelection = await buildWorkspaceSelectionChecks(args, ctx);
13053
+ const providerChecks = await buildAllProviderChecks(ctx, args.providerId);
13054
+ const mobileHost = buildMobileHostCheck(ctx);
13055
+ return {
13056
+ context: "workspace_open",
13057
+ canContinue: workspaceSelection.canContinue,
13058
+ checks: [
13059
+ ...workspaceSelection.checks,
13060
+ ...providerChecks.checks,
13061
+ buildServerAuthCheck(ctx),
13062
+ mobileHost.check
13063
+ ],
13064
+ metadata: {
13065
+ workspacePath: workspaceSelection.workspacePath ?? args.workspacePath,
13066
+ authEnabled: ctx.config?.auth.enabled ?? false,
13067
+ host: ctx.config?.host,
13068
+ providerId: args.providerId,
13069
+ workspaceId: args.workspaceId
13070
+ }
13071
+ };
13072
+ }
13073
+ case "session_start":
13074
+ return buildSessionStartDiagnostics(args, ctx);
13075
+ case "mobile_continue":
13076
+ return buildMobileDiagnostics(args, ctx);
13077
+ case "manual_check":
13078
+ return buildManualDiagnostics(args, ctx);
13079
+ }
13080
+ }
13081
+ var DiagnosticsRequestSchema;
13082
+ var init_diagnostics2 = __esm({
13083
+ "packages/server/src/commands/diagnostics.ts"() {
13084
+ "use strict";
13085
+ init_runtime_status();
13086
+ init_validator();
13087
+ init_dispatch();
13088
+ DiagnosticsRequestSchema = z14.object({
13089
+ context: z14.enum(["workspace_open", "session_start", "mobile_continue", "manual_check"]),
13090
+ workspaceId: z14.string().optional(),
13091
+ workspacePath: z14.string().optional(),
13092
+ providerId: z14.string().optional()
13093
+ });
13094
+ registerCommand("diagnostics.get", DiagnosticsRequestSchema, async (args, ctx) => {
13095
+ return buildDiagnostics(args, ctx);
13096
+ });
13097
+ registerCommand("diagnostics.recheck", DiagnosticsRequestSchema, async (args, ctx) => {
13098
+ return buildDiagnostics(args, ctx);
13099
+ });
13100
+ }
13101
+ });
13102
+
13103
+ // packages/server/src/commands/provider.ts
13104
+ import { z as z15 } from "zod";
12161
13105
  var init_provider = __esm({
12162
13106
  "packages/server/src/commands/provider.ts"() {
12163
13107
  "use strict";
12164
13108
  init_runtime_status();
12165
13109
  init_dispatch();
12166
- registerCommand("provider.runtimeStatus", z14.object({}), async (_args, ctx) => {
13110
+ registerCommand("provider.runtimeStatus", z15.object({}), async (_args, ctx) => {
12167
13111
  return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
12168
13112
  });
12169
13113
  registerCommand(
12170
13114
  "provider.install.start",
12171
- z14.object({
12172
- providerId: z14.string()
13115
+ z15.object({
13116
+ providerId: z15.string()
12173
13117
  }),
12174
13118
  async (args, ctx) => {
12175
13119
  if (!ctx.providerInstallMgr) {
@@ -12183,8 +13127,8 @@ var init_provider = __esm({
12183
13127
  );
12184
13128
  registerCommand(
12185
13129
  "provider.install.get",
12186
- z14.object({
12187
- jobId: z14.string()
13130
+ z15.object({
13131
+ jobId: z15.string()
12188
13132
  }),
12189
13133
  async (args, ctx) => {
12190
13134
  if (!ctx.providerInstallMgr) {
@@ -12207,35 +13151,35 @@ var init_provider = __esm({
12207
13151
  });
12208
13152
 
12209
13153
  // packages/server/src/commands/supervisor.ts
12210
- import { z as z15 } from "zod";
13154
+ import { z as z16 } from "zod";
12211
13155
  var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, supervisorIdSchema;
12212
13156
  var init_supervisor2 = __esm({
12213
13157
  "packages/server/src/commands/supervisor.ts"() {
12214
13158
  "use strict";
12215
13159
  init_dispatch();
12216
- supervisorObjectiveSchema = z15.string().trim().min(1).max(4e3);
12217
- createSupervisorSchema = z15.object({
12218
- sessionId: z15.string(),
12219
- workspaceId: z15.string(),
13160
+ supervisorObjectiveSchema = z16.string().trim().min(1).max(4e3);
13161
+ createSupervisorSchema = z16.object({
13162
+ sessionId: z16.string(),
13163
+ workspaceId: z16.string(),
12220
13164
  objective: supervisorObjectiveSchema,
12221
- evaluatorProviderId: z15.string(),
12222
- evaluatorModel: z15.string().trim().min(1).max(200).optional(),
12223
- maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
12224
- scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
13165
+ evaluatorProviderId: z16.string(),
13166
+ evaluatorModel: z16.string().trim().min(1).max(200).optional(),
13167
+ maxSupervisionCount: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
13168
+ scheduledAt: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional()
12225
13169
  }).strict();
12226
- updateSupervisorSchema = z15.object({
12227
- id: z15.string(),
13170
+ updateSupervisorSchema = z16.object({
13171
+ id: z16.string(),
12228
13172
  objective: supervisorObjectiveSchema.optional(),
12229
- evaluatorProviderId: z15.string().optional(),
12230
- evaluatorModel: z15.string().trim().min(1).max(200).nullable().optional(),
12231
- maxSupervisionCount: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
12232
- scheduledAt: z15.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
13173
+ evaluatorProviderId: z16.string().optional(),
13174
+ evaluatorModel: z16.string().trim().min(1).max(200).nullable().optional(),
13175
+ maxSupervisionCount: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).optional(),
13176
+ scheduledAt: z16.number().int().min(0).max(Number.MAX_SAFE_INTEGER).nullable().optional()
12233
13177
  }).strict().refine(
12234
13178
  (input) => input.objective !== void 0 || input.evaluatorProviderId !== void 0 || input.evaluatorModel !== void 0 || input.maxSupervisionCount !== void 0 || input.scheduledAt !== void 0,
12235
13179
  "at least one supervisor field is required"
12236
13180
  );
12237
- sessionIdSchema = z15.object({ sessionId: z15.string() });
12238
- supervisorIdSchema = z15.object({ id: z15.string() });
13181
+ sessionIdSchema = z16.object({ sessionId: z16.string() });
13182
+ supervisorIdSchema = z16.object({ id: z16.string() });
12239
13183
  registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
12240
13184
  return {
12241
13185
  supervisor: await ctx.supervisorMgr.create({
@@ -12419,7 +13363,7 @@ var init_worktree = __esm({
12419
13363
 
12420
13364
  // packages/server/src/commands/worktree.ts
12421
13365
  import path9 from "node:path";
12422
- import { z as z16 } from "zod";
13366
+ import { z as z17 } from "zod";
12423
13367
  async function findRelatedWorkspaceIds(ctx, workspacePath) {
12424
13368
  const targetCommonDir = await getGitCommonDirPath(workspacePath);
12425
13369
  const relatedWorkspaceIds = await Promise.all(
@@ -12452,7 +13396,7 @@ var init_worktree2 = __esm({
12452
13396
  init_worktree();
12453
13397
  init_dispatch();
12454
13398
  init_git_events();
12455
- registerCommand("worktree.list", z16.object({ workspaceId: z16.string() }), async (args, ctx) => {
13399
+ registerCommand("worktree.list", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
12456
13400
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
12457
13401
  if (!workspace) {
12458
13402
  throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
@@ -12461,7 +13405,7 @@ var init_worktree2 = __esm({
12461
13405
  });
12462
13406
  registerCommand(
12463
13407
  "worktree.status",
12464
- z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
13408
+ z17.object({ workspaceId: z17.string(), worktreePath: z17.string() }),
12465
13409
  async (args, ctx) => {
12466
13410
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
12467
13411
  if (!workspace) {
@@ -12473,10 +13417,10 @@ var init_worktree2 = __esm({
12473
13417
  );
12474
13418
  registerCommand(
12475
13419
  "worktree.diff",
12476
- z16.object({
12477
- workspaceId: z16.string(),
12478
- worktreePath: z16.string(),
12479
- staged: z16.boolean().optional().default(false)
13420
+ z17.object({
13421
+ workspaceId: z17.string(),
13422
+ worktreePath: z17.string(),
13423
+ staged: z17.boolean().optional().default(false)
12480
13424
  }),
12481
13425
  async (args, ctx) => {
12482
13426
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -12489,7 +13433,7 @@ var init_worktree2 = __esm({
12489
13433
  );
12490
13434
  registerCommand(
12491
13435
  "worktree.tree",
12492
- z16.object({ workspaceId: z16.string(), worktreePath: z16.string() }),
13436
+ z17.object({ workspaceId: z17.string(), worktreePath: z17.string() }),
12493
13437
  async (args, ctx) => {
12494
13438
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
12495
13439
  if (!workspace) {
@@ -12501,10 +13445,10 @@ var init_worktree2 = __esm({
12501
13445
  );
12502
13446
  registerCommand(
12503
13447
  "worktree.create",
12504
- z16.object({
12505
- workspaceId: z16.string(),
12506
- branch: z16.string(),
12507
- path: z16.string()
13448
+ z17.object({
13449
+ workspaceId: z17.string(),
13450
+ branch: z17.string(),
13451
+ path: z17.string()
12508
13452
  }),
12509
13453
  async (args, ctx) => {
12510
13454
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -12519,10 +13463,10 @@ var init_worktree2 = __esm({
12519
13463
  );
12520
13464
  registerCommand(
12521
13465
  "worktree.remove",
12522
- z16.object({
12523
- workspaceId: z16.string(),
12524
- worktreePath: z16.string(),
12525
- force: z16.boolean().optional().default(false)
13466
+ z17.object({
13467
+ workspaceId: z17.string(),
13468
+ worktreePath: z17.string(),
13469
+ force: z17.boolean().optional().default(false)
12526
13470
  }),
12527
13471
  async (args, ctx) => {
12528
13472
  const workspace = ctx.workspaceMgr.get(args.workspaceId);
@@ -12546,7 +13490,7 @@ var init_worktree2 = __esm({
12546
13490
  });
12547
13491
 
12548
13492
  // packages/server/src/commands/fencing.ts
12549
- import { z as z17 } from "zod";
13493
+ import { z as z18 } from "zod";
12550
13494
  function createMockFencingRequest() {
12551
13495
  return {
12552
13496
  ip: "127.0.0.1",
@@ -12559,9 +13503,9 @@ var init_fencing2 = __esm({
12559
13503
  init_dispatch();
12560
13504
  registerCommand(
12561
13505
  "fencing.request",
12562
- z17.object({
12563
- workspaceId: z17.string(),
12564
- tabId: z17.string()
13506
+ z18.object({
13507
+ workspaceId: z18.string(),
13508
+ tabId: z18.string()
12565
13509
  }),
12566
13510
  async (args, ctx, clientId) => {
12567
13511
  return ctx.fencingMgr.requestControl(
@@ -12574,7 +13518,7 @@ var init_fencing2 = __esm({
12574
13518
  );
12575
13519
  registerCommand(
12576
13520
  "fencing.heartbeat",
12577
- z17.object({ workspaceId: z17.string() }),
13521
+ z18.object({ workspaceId: z18.string() }),
12578
13522
  async (args, ctx, clientId) => {
12579
13523
  const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
12580
13524
  return { success };
@@ -12582,13 +13526,13 @@ var init_fencing2 = __esm({
12582
13526
  );
12583
13527
  registerCommand(
12584
13528
  "fencing.release",
12585
- z17.object({ workspaceId: z17.string() }),
13529
+ z18.object({ workspaceId: z18.string() }),
12586
13530
  async (args, ctx, clientId) => {
12587
13531
  ctx.fencingMgr.release(args.workspaceId, clientId);
12588
13532
  return {};
12589
13533
  }
12590
13534
  );
12591
- registerCommand("fencing.status", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
13535
+ registerCommand("fencing.status", z18.object({ workspaceId: z18.string() }), async (args, ctx) => {
12592
13536
  const controller = ctx.fencingMgr.getController(args.workspaceId);
12593
13537
  const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
12594
13538
  return {
@@ -12599,9 +13543,9 @@ var init_fencing2 = __esm({
12599
13543
  });
12600
13544
  registerCommand(
12601
13545
  "fencing.takeover",
12602
- z17.object({
12603
- workspaceId: z17.string(),
12604
- tabId: z17.string()
13546
+ z18.object({
13547
+ workspaceId: z18.string(),
13548
+ tabId: z18.string()
12605
13549
  }),
12606
13550
  async (args, ctx, clientId) => {
12607
13551
  return ctx.fencingMgr.forceTakeover(
@@ -12628,6 +13572,7 @@ var init_commands = __esm({
12628
13572
  init_file();
12629
13573
  init_git2();
12630
13574
  init_settings2();
13575
+ init_diagnostics2();
12631
13576
  init_provider();
12632
13577
  init_supervisor2();
12633
13578
  init_worktree2();
@@ -12771,7 +13716,8 @@ async function createServer(configOverrides) {
12771
13716
  autoFetch,
12772
13717
  providerRuntimeDeps,
12773
13718
  providerInstallMgr,
12774
- activationMgr
13719
+ activationMgr,
13720
+ config
12775
13721
  };
12776
13722
  wsHub.setCommandContext(commandContext);
12777
13723
  await app.listen({
@@ -13276,11 +14222,11 @@ function readCliConfig() {
13276
14222
 
13277
14223
  // packages/cli/src/embed.ts
13278
14224
  import { existsSync as existsSync8 } from "fs";
13279
- import { dirname as dirname6, resolve as resolve3 } from "path";
14225
+ import { dirname as dirname6, resolve as resolve4 } from "path";
13280
14226
  import { fileURLToPath } from "url";
13281
14227
  var __filename = fileURLToPath(import.meta.url);
13282
14228
  var __dirname = dirname6(__filename);
13283
- var WEB_ASSETS_DIR = resolve3(__dirname, "../web");
14229
+ var WEB_ASSETS_DIR = resolve4(__dirname, "../web");
13284
14230
  function getStaticAssetsDir() {
13285
14231
  return WEB_ASSETS_DIR;
13286
14232
  }