@spencer-kit/coder-studio 0.3.10 → 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/CHANGELOG.md +6 -0
- package/dist/esm/bin.mjs +1147 -194
- package/dist/esm/bin.mjs.map +4 -4
- package/dist/esm/server-runner.mjs +1131 -178
- package/dist/esm/server-runner.mjs.map +4 -4
- package/dist/web/assets/index-3VcBsCCu.js +111 -0
- package/dist/web/assets/index-3VcBsCCu.js.map +1 -0
- package/dist/web/assets/index-BfhlsaFt.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-DBpngHWV.js +0 -111
- package/dist/web/assets/index-DBpngHWV.js.map +0 -1
- package/dist/web/assets/index-DUGzjla1.css +0 -1
|
@@ -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 {
|
|
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);
|
|
@@ -2010,12 +2038,12 @@ var init_auto_fetch = __esm({
|
|
|
2010
2038
|
}
|
|
2011
2039
|
acquireWorkspaceOperation(workspaceId) {
|
|
2012
2040
|
const state = this.getOrCreateState(workspaceId);
|
|
2013
|
-
return new Promise((
|
|
2041
|
+
return new Promise((resolve5) => {
|
|
2014
2042
|
const grant = () => {
|
|
2015
2043
|
state.inFlight = true;
|
|
2016
2044
|
state.nextFetchAt = void 0;
|
|
2017
2045
|
let released = false;
|
|
2018
|
-
|
|
2046
|
+
resolve5(() => {
|
|
2019
2047
|
if (released) {
|
|
2020
2048
|
return;
|
|
2021
2049
|
}
|
|
@@ -2043,7 +2071,7 @@ var init_auto_fetch = __esm({
|
|
|
2043
2071
|
// packages/server/src/provider-runtime/command-runner.ts
|
|
2044
2072
|
import { spawn } from "node:child_process";
|
|
2045
2073
|
async function runCommandAsString(file, args, options) {
|
|
2046
|
-
return new Promise((
|
|
2074
|
+
return new Promise((resolve5, reject) => {
|
|
2047
2075
|
const child = spawn(file, args, {
|
|
2048
2076
|
shell: shouldUseShellForCommand(file, process.platform),
|
|
2049
2077
|
windowsHide: options?.windowsHide ?? true
|
|
@@ -2068,7 +2096,7 @@ async function runCommandAsString(file, args, options) {
|
|
|
2068
2096
|
const stdout = Buffer.concat(stdoutChunks).toString("utf8");
|
|
2069
2097
|
const stderr = Buffer.concat(stderrChunks).toString("utf8");
|
|
2070
2098
|
if (code === 0) {
|
|
2071
|
-
|
|
2099
|
+
resolve5({ stdout, stderr });
|
|
2072
2100
|
return;
|
|
2073
2101
|
}
|
|
2074
2102
|
reject(
|
|
@@ -2677,6 +2705,13 @@ ${details.stdout}`.toLowerCase();
|
|
|
2677
2705
|
}
|
|
2678
2706
|
});
|
|
2679
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
|
+
|
|
2680
2715
|
// packages/core/src/domain/events.ts
|
|
2681
2716
|
var init_events = __esm({
|
|
2682
2717
|
"packages/core/src/domain/events.ts"() {
|
|
@@ -2927,6 +2962,7 @@ var init_idle_heuristics2 = __esm({
|
|
|
2927
2962
|
var init_src3 = __esm({
|
|
2928
2963
|
"packages/core/src/index.ts"() {
|
|
2929
2964
|
"use strict";
|
|
2965
|
+
init_diagnostics();
|
|
2930
2966
|
init_events();
|
|
2931
2967
|
init_mcp();
|
|
2932
2968
|
init_provider_install();
|
|
@@ -5010,13 +5046,13 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
5010
5046
|
return;
|
|
5011
5047
|
}
|
|
5012
5048
|
const arch = deps.arch ?? process.arch;
|
|
5013
|
-
const
|
|
5049
|
+
const resolve5 = deps.resolve ?? ((id) => require2.resolve(id));
|
|
5014
5050
|
const fileExists = deps.existsSync ?? existsSync4;
|
|
5015
|
-
const
|
|
5051
|
+
const stat8 = deps.statSync ?? statSync;
|
|
5016
5052
|
const chmod = deps.chmodSync ?? chmodSync2;
|
|
5017
5053
|
let packageJsonPath;
|
|
5018
5054
|
try {
|
|
5019
|
-
packageJsonPath =
|
|
5055
|
+
packageJsonPath = resolve5(NODE_PTY_PKG);
|
|
5020
5056
|
} catch {
|
|
5021
5057
|
return;
|
|
5022
5058
|
}
|
|
@@ -5030,7 +5066,7 @@ function ensureNodePtySpawnHelperExecutable(deps = {}) {
|
|
|
5030
5066
|
if (!fileExists(helperPath)) {
|
|
5031
5067
|
return;
|
|
5032
5068
|
}
|
|
5033
|
-
const currentMode =
|
|
5069
|
+
const currentMode = stat8(helperPath).mode;
|
|
5034
5070
|
const executableMode = currentMode | 73;
|
|
5035
5071
|
if (executableMode === currentMode) {
|
|
5036
5072
|
return;
|
|
@@ -5081,7 +5117,7 @@ async function escalateKillWithPolling(pid, signal, options) {
|
|
|
5081
5117
|
const startTime = Date.now();
|
|
5082
5118
|
const deadline = startTime + timeoutMs;
|
|
5083
5119
|
while (Date.now() < deadline) {
|
|
5084
|
-
await new Promise((
|
|
5120
|
+
await new Promise((resolve5) => setTimeout(resolve5, pollIntervalMs));
|
|
5085
5121
|
if (!isProcessAlive(pid)) {
|
|
5086
5122
|
return true;
|
|
5087
5123
|
}
|
|
@@ -5233,38 +5269,107 @@ var init_settings = __esm({
|
|
|
5233
5269
|
|
|
5234
5270
|
// packages/server/src/supervisor/evaluator.ts
|
|
5235
5271
|
import { spawn as spawn2 } from "node:child_process";
|
|
5236
|
-
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
|
+
}
|
|
5237
5326
|
const lines = [
|
|
5238
5327
|
"You are an autonomous supervisor for a target-scoped software task.",
|
|
5239
5328
|
"Your job is to keep the agent moving toward the objective until the objective is complete.",
|
|
5240
5329
|
"",
|
|
5241
5330
|
"Return JSON only.",
|
|
5331
|
+
"No prose before or after the JSON.",
|
|
5242
5332
|
"",
|
|
5243
5333
|
"Decision policy:",
|
|
5244
|
-
'- Prefer "continue" whenever there is a
|
|
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.',
|
|
5245
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.",
|
|
5246
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.",
|
|
5247
5342
|
"- Stop only when the objective is complete, or when continuing would likely push the agent in an unsafe or clearly unsupported direction.",
|
|
5248
5343
|
"",
|
|
5249
5344
|
"Stage decision policy:",
|
|
5250
5345
|
"- Use the target memory as the current supervision state.",
|
|
5251
|
-
"- Base your decision on the objective, current
|
|
5252
|
-
"- Identify which
|
|
5253
|
-
"-
|
|
5254
|
-
"-
|
|
5255
|
-
|
|
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.",
|
|
5256
5359
|
"- If the agent appears stuck or repeated the same action, give a different concrete next action.",
|
|
5257
|
-
"-
|
|
5360
|
+
"- Do not rewrite the decomposition structure during normal evaluation cycles.",
|
|
5258
5361
|
"",
|
|
5259
5362
|
"Allowed statuses:",
|
|
5260
|
-
'- "continue":
|
|
5363
|
+
'- "continue": supervision should continue; include "reason" and "guidance".',
|
|
5261
5364
|
'- "stop": supervision should stop; include "stopReason" and "reason".',
|
|
5262
5365
|
"",
|
|
5263
5366
|
"Allowed stop reasons:",
|
|
5264
5367
|
'- "objective_complete"',
|
|
5265
5368
|
'- "supervisor_uncertain"',
|
|
5266
5369
|
"",
|
|
5267
|
-
'Use "objective_complete" only when the objective
|
|
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.",
|
|
5268
5373
|
'Use "supervisor_uncertain" only as a last resort when no useful next action can be inferred and additional guidance would likely be misleading.',
|
|
5269
5374
|
"",
|
|
5270
5375
|
'Guidance requirements for "continue":',
|
|
@@ -5272,30 +5377,32 @@ function buildPrompt(context) {
|
|
|
5272
5377
|
"- Focus on the highest-value step toward completing the objective.",
|
|
5273
5378
|
"- Be specific enough for the supervised agent to act without asking the user.",
|
|
5274
5379
|
"- Avoid generic reminders, encouragement, or restating the objective.",
|
|
5275
|
-
"- 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.",
|
|
5276
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.",
|
|
5277
5383
|
"",
|
|
5278
|
-
"
|
|
5279
|
-
"-
|
|
5280
|
-
"-
|
|
5281
|
-
"-
|
|
5282
|
-
"-
|
|
5283
|
-
"-
|
|
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.",
|
|
5284
5390
|
"",
|
|
5285
5391
|
"Output schema:",
|
|
5286
5392
|
"For continue:",
|
|
5287
5393
|
"{",
|
|
5394
|
+
' "mode": "evaluate",',
|
|
5288
5395
|
' "status": "continue",',
|
|
5289
5396
|
' "reason": "brief explanation of why more work is needed",',
|
|
5290
5397
|
' "guidance": "specific next action for the supervised agent",',
|
|
5291
|
-
' "
|
|
5292
|
-
' "activeStepId": optional step id,',
|
|
5398
|
+
' "activeItemId": optional item id,',
|
|
5293
5399
|
' "progressSummary": optional brief progress summary,',
|
|
5294
|
-
' "
|
|
5400
|
+
' "itemUpdates": optional array of { "id": string, "status": "pending" | "in_progress" | "done" }',
|
|
5295
5401
|
"}",
|
|
5296
5402
|
"",
|
|
5297
5403
|
"For stop:",
|
|
5298
5404
|
"{",
|
|
5405
|
+
' "mode": "evaluate",',
|
|
5299
5406
|
' "status": "stop",',
|
|
5300
5407
|
' "stopReason": "objective_complete" | "supervisor_uncertain",',
|
|
5301
5408
|
' "reason": "brief explanation"',
|
|
@@ -5319,7 +5426,7 @@ async function runCommand(command, timeoutMs, options = {}) {
|
|
|
5319
5426
|
if (options.signal?.aborted) {
|
|
5320
5427
|
throw createSupervisorEvalAbortedError();
|
|
5321
5428
|
}
|
|
5322
|
-
return await new Promise((
|
|
5429
|
+
return await new Promise((resolve5, reject) => {
|
|
5323
5430
|
const child = spawn2(command.argv[0], command.argv.slice(1), {
|
|
5324
5431
|
cwd: command.cwd,
|
|
5325
5432
|
detached: process.platform !== "win32",
|
|
@@ -5349,7 +5456,7 @@ async function runCommand(command, timeoutMs, options = {}) {
|
|
|
5349
5456
|
}
|
|
5350
5457
|
settled = true;
|
|
5351
5458
|
cleanup();
|
|
5352
|
-
|
|
5459
|
+
resolve5(value);
|
|
5353
5460
|
};
|
|
5354
5461
|
const terminate = (error) => {
|
|
5355
5462
|
if (terminationError) {
|
|
@@ -5380,7 +5487,10 @@ async function runCommand(command, timeoutMs, options = {}) {
|
|
|
5380
5487
|
settleReject(terminationError);
|
|
5381
5488
|
return;
|
|
5382
5489
|
}
|
|
5383
|
-
settleReject(
|
|
5490
|
+
settleReject({
|
|
5491
|
+
code: "supervisor_eval_failed",
|
|
5492
|
+
message: error instanceof Error ? error.message : "Evaluator process failed to start"
|
|
5493
|
+
});
|
|
5384
5494
|
});
|
|
5385
5495
|
child.on("exit", (code) => {
|
|
5386
5496
|
if (terminationError) {
|
|
@@ -5558,7 +5668,7 @@ function extractSupervisorPayload(output, providerId) {
|
|
|
5558
5668
|
}
|
|
5559
5669
|
throw new Error("Supervisor did not return a recognizable message");
|
|
5560
5670
|
}
|
|
5561
|
-
function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
|
|
5671
|
+
function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars, requestedMode) {
|
|
5562
5672
|
let parsed;
|
|
5563
5673
|
try {
|
|
5564
5674
|
parsed = JSON.parse(stripCodeFence(payloadText));
|
|
@@ -5571,9 +5681,49 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
|
|
|
5571
5681
|
throw new Error("Supervisor returned invalid evaluation payload");
|
|
5572
5682
|
}
|
|
5573
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
|
+
}
|
|
5574
5724
|
const status = record.status;
|
|
5575
5725
|
const reason = record.reason;
|
|
5576
|
-
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()) {
|
|
5577
5727
|
throw new Error("Supervisor returned invalid evaluation payload");
|
|
5578
5728
|
}
|
|
5579
5729
|
if (status === "stop") {
|
|
@@ -5582,23 +5732,14 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
|
|
|
5582
5732
|
throw new Error("Supervisor stop result is missing a valid stopReason");
|
|
5583
5733
|
}
|
|
5584
5734
|
return {
|
|
5735
|
+
mode: "evaluate",
|
|
5585
5736
|
status,
|
|
5586
5737
|
stopReason,
|
|
5587
5738
|
reason: reason.trim()
|
|
5588
5739
|
};
|
|
5589
5740
|
}
|
|
5590
5741
|
const guidance = typeof record.guidance === "string" && record.guidance.trim() ? record.guidance.trim().slice(0, guidanceMaxChars) : void 0;
|
|
5591
|
-
const
|
|
5592
|
-
if (!value || typeof value !== "object") {
|
|
5593
|
-
return [];
|
|
5594
|
-
}
|
|
5595
|
-
const step = value;
|
|
5596
|
-
if (typeof step.id !== "string" || typeof step.title !== "string" || step.status !== "pending" && step.status !== "in_progress" && step.status !== "done") {
|
|
5597
|
-
return [];
|
|
5598
|
-
}
|
|
5599
|
-
return [{ id: step.id, title: step.title, status: step.status }];
|
|
5600
|
-
}) : void 0;
|
|
5601
|
-
const stepUpdates = Array.isArray(record.stepUpdates) ? record.stepUpdates.flatMap((value) => {
|
|
5742
|
+
const itemUpdates = Array.isArray(record.itemUpdates) ? record.itemUpdates.flatMap((value) => {
|
|
5602
5743
|
if (!value || typeof value !== "object") {
|
|
5603
5744
|
return [];
|
|
5604
5745
|
}
|
|
@@ -5609,13 +5750,13 @@ function parseSupervisorEvaluationResult(payloadText, guidanceMaxChars) {
|
|
|
5609
5750
|
return [{ id: update.id, status: update.status }];
|
|
5610
5751
|
}) : void 0;
|
|
5611
5752
|
return {
|
|
5753
|
+
mode: "evaluate",
|
|
5612
5754
|
status,
|
|
5613
5755
|
reason: reason.trim(),
|
|
5614
5756
|
guidance,
|
|
5615
|
-
|
|
5616
|
-
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,
|
|
5617
5758
|
progressSummary: typeof record.progressSummary === "string" && record.progressSummary.trim() ? record.progressSummary.trim() : void 0,
|
|
5618
|
-
|
|
5759
|
+
itemUpdates
|
|
5619
5760
|
};
|
|
5620
5761
|
}
|
|
5621
5762
|
var NOOP_LOGGER2, SupervisorEvaluator;
|
|
@@ -5667,7 +5808,8 @@ var init_evaluator = __esm({
|
|
|
5667
5808
|
provider,
|
|
5668
5809
|
this.deps.providerConfigRepo.get(provider.id)
|
|
5669
5810
|
);
|
|
5670
|
-
const
|
|
5811
|
+
const mode = options.mode ?? "evaluate";
|
|
5812
|
+
const prompt = buildPrompt(context, mode);
|
|
5671
5813
|
const command = provider.buildSupervisorEvalCommand(config, {
|
|
5672
5814
|
prompt,
|
|
5673
5815
|
sessionId: supervisor.sessionId,
|
|
@@ -5701,7 +5843,7 @@ var init_evaluator = __esm({
|
|
|
5701
5843
|
);
|
|
5702
5844
|
throw error;
|
|
5703
5845
|
}
|
|
5704
|
-
return parseSupervisorEvaluationResult(payloadText, this.config.guidanceMaxChars);
|
|
5846
|
+
return parseSupervisorEvaluationResult(payloadText, this.config.guidanceMaxChars, mode);
|
|
5705
5847
|
}
|
|
5706
5848
|
};
|
|
5707
5849
|
}
|
|
@@ -5872,12 +6014,12 @@ var init_scheduler = __esm({
|
|
|
5872
6014
|
|
|
5873
6015
|
// packages/server/src/supervisor/manager.ts
|
|
5874
6016
|
function createDeferredCompletion() {
|
|
5875
|
-
let
|
|
6017
|
+
let resolve5 = () => {
|
|
5876
6018
|
};
|
|
5877
6019
|
const promise = new Promise((innerResolve) => {
|
|
5878
|
-
|
|
6020
|
+
resolve5 = innerResolve;
|
|
5879
6021
|
});
|
|
5880
|
-
return { promise, resolve:
|
|
6022
|
+
return { promise, resolve: resolve5 };
|
|
5881
6023
|
}
|
|
5882
6024
|
function generateSupervisorId() {
|
|
5883
6025
|
return `sup_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
@@ -5903,6 +6045,12 @@ function messageOf(error, fallback) {
|
|
|
5903
6045
|
function logFailure(logger, error, context, message) {
|
|
5904
6046
|
logger.error({ ...context, err: error }, message);
|
|
5905
6047
|
}
|
|
6048
|
+
function isDecomposeResult(result) {
|
|
6049
|
+
return result.mode === "decompose";
|
|
6050
|
+
}
|
|
6051
|
+
function isEvaluateStopResult(result) {
|
|
6052
|
+
return "status" in result && result.status === "stop";
|
|
6053
|
+
}
|
|
5906
6054
|
function isSupervisorEvalAborted(error) {
|
|
5907
6055
|
return !!error && typeof error === "object" && error.code === "supervisor_eval_aborted";
|
|
5908
6056
|
}
|
|
@@ -6406,7 +6554,12 @@ var init_manager2 = __esm({
|
|
|
6406
6554
|
turnId: context.lastTurnId,
|
|
6407
6555
|
createdAt: Date.now()
|
|
6408
6556
|
});
|
|
6409
|
-
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
|
+
});
|
|
6410
6563
|
return {
|
|
6411
6564
|
cycle: activeCycle,
|
|
6412
6565
|
supervisor: hydratedSupervisor,
|
|
@@ -6604,6 +6757,8 @@ var init_manager2 = __esm({
|
|
|
6604
6757
|
}
|
|
6605
6758
|
async executeCycleWithRetry(started, signal) {
|
|
6606
6759
|
const supervisor = started.supervisor;
|
|
6760
|
+
let context = started.context;
|
|
6761
|
+
let currentMemory = context.targetMemory;
|
|
6607
6762
|
for (let attemptIndex = 0; ; attemptIndex += 1) {
|
|
6608
6763
|
const attempt = this.deps.cycleAttemptRepo.create({
|
|
6609
6764
|
id: generateAttemptId(),
|
|
@@ -6612,23 +6767,79 @@ var init_manager2 = __esm({
|
|
|
6612
6767
|
status: "evaluating",
|
|
6613
6768
|
startedAt: Date.now()
|
|
6614
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
|
+
});
|
|
6615
6776
|
try {
|
|
6616
|
-
|
|
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
|
+
});
|
|
6617
6817
|
this.deps.cycleAttemptRepo.update(attempt.id, {
|
|
6618
6818
|
status: "completed",
|
|
6619
6819
|
completedAt: Date.now(),
|
|
6620
6820
|
providerModel: supervisor.evaluatorModel ?? null
|
|
6621
6821
|
});
|
|
6622
|
-
if (evaluation
|
|
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)) {
|
|
6623
6832
|
return {
|
|
6624
6833
|
evaluation,
|
|
6625
|
-
injected: false
|
|
6834
|
+
injected: false,
|
|
6835
|
+
targetMemory: nextTargetMemory
|
|
6626
6836
|
};
|
|
6627
6837
|
}
|
|
6628
6838
|
if (!evaluation.guidance?.trim()) {
|
|
6629
6839
|
return {
|
|
6630
6840
|
evaluation,
|
|
6631
|
-
injected: false
|
|
6841
|
+
injected: false,
|
|
6842
|
+
targetMemory: nextTargetMemory
|
|
6632
6843
|
};
|
|
6633
6844
|
}
|
|
6634
6845
|
if (signal?.aborted || this.pendingPauses.has(supervisor.id)) {
|
|
@@ -6638,7 +6849,8 @@ var init_manager2 = __esm({
|
|
|
6638
6849
|
if (currentSupervisor.targetId !== started.targetId) {
|
|
6639
6850
|
return {
|
|
6640
6851
|
evaluation,
|
|
6641
|
-
injected: false
|
|
6852
|
+
injected: false,
|
|
6853
|
+
targetMemory: nextTargetMemory
|
|
6642
6854
|
};
|
|
6643
6855
|
}
|
|
6644
6856
|
const injectingSupervisor = this.attachCycles(
|
|
@@ -6651,6 +6863,12 @@ var init_manager2 = __esm({
|
|
|
6651
6863
|
);
|
|
6652
6864
|
this.storeSnapshot(injectingSupervisor);
|
|
6653
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
|
+
});
|
|
6654
6872
|
const recentCycles = this.deps.cycleRepo.listRecentForSupervisor(supervisor.id, this.config.guidanceDedupeWindow + 1).filter((cycle) => cycle.id !== started.cycle.id);
|
|
6655
6873
|
const injection = await this.injector.inject(
|
|
6656
6874
|
injectingSupervisor,
|
|
@@ -6663,7 +6881,13 @@ var init_manager2 = __esm({
|
|
|
6663
6881
|
return {
|
|
6664
6882
|
evaluation,
|
|
6665
6883
|
injected: injection.injected,
|
|
6666
|
-
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
|
+
)
|
|
6667
6891
|
};
|
|
6668
6892
|
} catch (error) {
|
|
6669
6893
|
if (isSupervisorEvalAborted(error)) {
|
|
@@ -6684,6 +6908,15 @@ var init_manager2 = __esm({
|
|
|
6684
6908
|
if (!this.shouldRetryAttempt(error, attemptIndex, started.retry)) {
|
|
6685
6909
|
throw error;
|
|
6686
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
|
+
});
|
|
6687
6920
|
await this.sleep(started.retry.retryDelayMs, signal);
|
|
6688
6921
|
const evaluatingSupervisor = this.attachCycles(
|
|
6689
6922
|
this.withCurrentTargetState(
|
|
@@ -6701,9 +6934,9 @@ var init_manager2 = __esm({
|
|
|
6701
6934
|
async finalizeSuccessfulCycle(activeCycle, context, result, targetId) {
|
|
6702
6935
|
const workspace = this.requireWorkspace(context.workspaceId);
|
|
6703
6936
|
const currentSupervisor = this.supervisors.get(activeCycle.supervisorId) ?? this.requireSupervisor(activeCycle.supervisorId);
|
|
6704
|
-
const
|
|
6937
|
+
const evaluation = result.evaluation;
|
|
6705
6938
|
const finalStatus = result.injected ? "injected" : "completed";
|
|
6706
|
-
const cycleReason =
|
|
6939
|
+
const cycleReason = isEvaluateStopResult(evaluation) ? evaluation.reason : result.injected ? result.injectedText : evaluation.guidance ? `Skipped duplicate: ${evaluation.guidance}` : void 0;
|
|
6707
6940
|
const finishedCycle = this.deps.cycleRepo.update(activeCycle.id, {
|
|
6708
6941
|
status: finalStatus,
|
|
6709
6942
|
result: cycleReason ?? null,
|
|
@@ -6711,24 +6944,22 @@ var init_manager2 = __esm({
|
|
|
6711
6944
|
errorReason: null,
|
|
6712
6945
|
completedAt: Date.now()
|
|
6713
6946
|
});
|
|
6714
|
-
const nextTargetMemory =
|
|
6715
|
-
targetMemory,
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
finishedCycle.completedAt ?? Date.now()
|
|
6719
|
-
);
|
|
6947
|
+
const nextTargetMemory = {
|
|
6948
|
+
...result.targetMemory,
|
|
6949
|
+
updatedAt: finishedCycle.completedAt ?? Date.now()
|
|
6950
|
+
};
|
|
6720
6951
|
await this.deps.targetStore.saveTargetMemory(workspace.path, targetId, nextTargetMemory);
|
|
6721
|
-
const cycleRecord =
|
|
6952
|
+
const cycleRecord = isEvaluateStopResult(evaluation) ? {
|
|
6722
6953
|
cycleId: activeCycle.id,
|
|
6723
6954
|
targetId,
|
|
6724
6955
|
startedAt: activeCycle.createdAt,
|
|
6725
6956
|
completedAt: finishedCycle.completedAt ?? Date.now(),
|
|
6726
6957
|
result: "stop",
|
|
6727
|
-
stopReason:
|
|
6728
|
-
reason:
|
|
6729
|
-
progressSummary:
|
|
6730
|
-
|
|
6731
|
-
|
|
6958
|
+
stopReason: evaluation.stopReason,
|
|
6959
|
+
reason: evaluation.reason,
|
|
6960
|
+
progressSummary: nextTargetMemory.progressSummary,
|
|
6961
|
+
decompositionMode: nextTargetMemory.decompositionMode,
|
|
6962
|
+
activeItemId: nextTargetMemory.activeItemId,
|
|
6732
6963
|
injected: false,
|
|
6733
6964
|
attemptCount: this.deps.cycleAttemptRepo.listForCycle(activeCycle.id).length
|
|
6734
6965
|
} : {
|
|
@@ -6737,18 +6968,19 @@ var init_manager2 = __esm({
|
|
|
6737
6968
|
startedAt: activeCycle.createdAt,
|
|
6738
6969
|
completedAt: finishedCycle.completedAt ?? Date.now(),
|
|
6739
6970
|
result: "continue",
|
|
6740
|
-
reason:
|
|
6741
|
-
guidance: result.injected ? result.injectedText :
|
|
6971
|
+
reason: evaluation.reason,
|
|
6972
|
+
guidance: result.injected ? result.injectedText : evaluation.guidance,
|
|
6742
6973
|
progressSummary: nextTargetMemory.progressSummary,
|
|
6743
|
-
|
|
6744
|
-
|
|
6974
|
+
decompositionMode: nextTargetMemory.decompositionMode,
|
|
6975
|
+
activeItemId: nextTargetMemory.activeItemId,
|
|
6976
|
+
itemUpdates: evaluation.itemUpdates,
|
|
6745
6977
|
injected: result.injected,
|
|
6746
6978
|
attemptCount: this.deps.cycleAttemptRepo.listForCycle(activeCycle.id).length
|
|
6747
6979
|
};
|
|
6748
6980
|
await this.deps.targetStore.appendTargetCycleRecord(workspace.path, targetId, cycleRecord);
|
|
6749
|
-
if (
|
|
6981
|
+
if (isEvaluateStopResult(evaluation)) {
|
|
6750
6982
|
await this.updateTargetMetaStatus(workspace.path, targetId, {
|
|
6751
|
-
status:
|
|
6983
|
+
status: evaluation.stopReason === "objective_complete" ? "completed" : "cancelled",
|
|
6752
6984
|
completedAt: finishedCycle.completedAt ?? Date.now()
|
|
6753
6985
|
});
|
|
6754
6986
|
}
|
|
@@ -6765,9 +6997,9 @@ var init_manager2 = __esm({
|
|
|
6765
6997
|
const finishedSupervisor = this.attachCycles(
|
|
6766
6998
|
this.withCurrentTargetState(
|
|
6767
6999
|
this.deps.supervisorRepo.update(activeCycle.supervisorId, {
|
|
6768
|
-
state: result.evaluation
|
|
7000
|
+
state: isEvaluateStopResult(result.evaluation) ? "stopped" : "idle",
|
|
6769
7001
|
completedSupervisionCount: (this.supervisors.get(activeCycle.supervisorId)?.completedSupervisionCount ?? 0) + 1,
|
|
6770
|
-
stopReason:
|
|
7002
|
+
stopReason: isEvaluateStopResult(evaluation) ? evaluation.stopReason : null,
|
|
6771
7003
|
lastCycleAt: finishedCycle.completedAt,
|
|
6772
7004
|
lastEvaluatedTurnId: context.lastTurnId ?? void 0,
|
|
6773
7005
|
errorReason: null,
|
|
@@ -6921,23 +7153,46 @@ var init_manager2 = __esm({
|
|
|
6921
7153
|
};
|
|
6922
7154
|
}
|
|
6923
7155
|
applyEvaluationToTargetMemory(memory, evaluation, injectedText, updatedAt) {
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
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
|
|
6931
7185
|
);
|
|
6932
7186
|
}
|
|
6933
7187
|
const progressSummary = evaluation.progressSummary ?? memory.progressSummary;
|
|
6934
|
-
const lastGuidance =
|
|
6935
|
-
const stalledCount =
|
|
7188
|
+
const lastGuidance = injectedText ?? evaluation.guidance ?? memory.lastGuidance;
|
|
7189
|
+
const stalledCount = !evaluation.progressSummary && !evaluation.itemUpdates?.length ? memory.stalledCount + 1 : 0;
|
|
6936
7190
|
return {
|
|
6937
7191
|
...memory,
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
7192
|
+
decompositionGenerated: memory.decompositionGenerated,
|
|
7193
|
+
decompositionMode: memory.decompositionMode,
|
|
7194
|
+
items,
|
|
7195
|
+
activeItemId: evaluation.activeItemId ?? memory.activeItemId,
|
|
6941
7196
|
progressSummary,
|
|
6942
7197
|
lastGuidance,
|
|
6943
7198
|
stalledCount,
|
|
@@ -7060,10 +7315,10 @@ var init_manager2 = __esm({
|
|
|
7060
7315
|
{ supervisor, event }
|
|
7061
7316
|
);
|
|
7062
7317
|
}
|
|
7063
|
-
broadcastCycle(supervisor, cycle, event) {
|
|
7318
|
+
broadcastCycle(supervisor, cycle, event, runtime) {
|
|
7064
7319
|
this.deps.broadcaster.broadcast(
|
|
7065
7320
|
Topics.supervisorCycle(supervisor.workspaceId, supervisor.sessionId),
|
|
7066
|
-
{ cycle, event }
|
|
7321
|
+
{ cycle: runtime ? { ...cycle, runtime } : cycle, event }
|
|
7067
7322
|
);
|
|
7068
7323
|
}
|
|
7069
7324
|
shouldRetryAttempt(error, attemptIndex, retry) {
|
|
@@ -7089,10 +7344,10 @@ var init_manager2 = __esm({
|
|
|
7089
7344
|
if (signal?.aborted) {
|
|
7090
7345
|
throw { code: "supervisor_eval_aborted", message: "Supervisor evaluator aborted" };
|
|
7091
7346
|
}
|
|
7092
|
-
await new Promise((
|
|
7347
|
+
await new Promise((resolve5, reject) => {
|
|
7093
7348
|
const timer = setTimeout(() => {
|
|
7094
7349
|
signal?.removeEventListener("abort", onAbort);
|
|
7095
|
-
|
|
7350
|
+
resolve5();
|
|
7096
7351
|
}, delayMs);
|
|
7097
7352
|
timer.unref?.();
|
|
7098
7353
|
const onAbort = () => {
|
|
@@ -7160,6 +7415,119 @@ function errorMessage(error, fallback) {
|
|
|
7160
7415
|
}
|
|
7161
7416
|
return fallback;
|
|
7162
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
|
+
}
|
|
7163
7531
|
async function writeJsonIfMissing(path10, value) {
|
|
7164
7532
|
try {
|
|
7165
7533
|
await writeFile3(path10, JSON.stringify(value, null, 2) + "\n", {
|
|
@@ -7188,8 +7556,12 @@ function buildTargetMeta(input) {
|
|
|
7188
7556
|
function buildTargetMemory(targetId, createdAt) {
|
|
7189
7557
|
return {
|
|
7190
7558
|
targetId,
|
|
7191
|
-
|
|
7192
|
-
|
|
7559
|
+
decompositionGenerated: false,
|
|
7560
|
+
decompositionMode: void 0,
|
|
7561
|
+
items: [],
|
|
7562
|
+
activeItemId: void 0,
|
|
7563
|
+
progressSummary: void 0,
|
|
7564
|
+
lastGuidance: void 0,
|
|
7193
7565
|
stalledCount: 0,
|
|
7194
7566
|
updatedAt: createdAt
|
|
7195
7567
|
};
|
|
@@ -7278,8 +7650,9 @@ async function readTargetMeta(workspacePath, targetId) {
|
|
|
7278
7650
|
);
|
|
7279
7651
|
}
|
|
7280
7652
|
async function loadTargetMemory(workspacePath, targetId) {
|
|
7281
|
-
return
|
|
7282
|
-
await readFile2(memoryPath(workspacePath, targetId), "utf-8")
|
|
7653
|
+
return normalizeTargetMemory(
|
|
7654
|
+
JSON.parse(await readFile2(memoryPath(workspacePath, targetId), "utf-8")),
|
|
7655
|
+
targetId
|
|
7283
7656
|
);
|
|
7284
7657
|
}
|
|
7285
7658
|
async function saveTargetMemory(workspacePath, targetId, memory) {
|
|
@@ -7616,8 +7989,8 @@ var init_terminal_snapshot_buffer = __esm({
|
|
|
7616
7989
|
if (this.pendingWriteCount === 0) {
|
|
7617
7990
|
return Promise.resolve();
|
|
7618
7991
|
}
|
|
7619
|
-
return new Promise((
|
|
7620
|
-
this.drainResolvers.push(
|
|
7992
|
+
return new Promise((resolve5) => {
|
|
7993
|
+
this.drainResolvers.push(resolve5);
|
|
7621
7994
|
});
|
|
7622
7995
|
}
|
|
7623
7996
|
resolveDrainIfIdle() {
|
|
@@ -7626,8 +7999,8 @@ var init_terminal_snapshot_buffer = __esm({
|
|
|
7626
7999
|
}
|
|
7627
8000
|
const resolvers = this.drainResolvers;
|
|
7628
8001
|
this.drainResolvers = [];
|
|
7629
|
-
for (const
|
|
7630
|
-
|
|
8002
|
+
for (const resolve5 of resolvers) {
|
|
8003
|
+
resolve5();
|
|
7631
8004
|
}
|
|
7632
8005
|
}
|
|
7633
8006
|
requireTerminal() {
|
|
@@ -7946,10 +8319,10 @@ var init_manager3 = __esm({
|
|
|
7946
8319
|
}
|
|
7947
8320
|
return existing.promise;
|
|
7948
8321
|
}
|
|
7949
|
-
let
|
|
8322
|
+
let resolve5 = () => {
|
|
7950
8323
|
};
|
|
7951
8324
|
const promise = new Promise((innerResolve) => {
|
|
7952
|
-
|
|
8325
|
+
resolve5 = innerResolve;
|
|
7953
8326
|
});
|
|
7954
8327
|
let markKillCompleted = () => {
|
|
7955
8328
|
};
|
|
@@ -7962,7 +8335,7 @@ var init_manager3 = __esm({
|
|
|
7962
8335
|
markKillCompleted,
|
|
7963
8336
|
finalized: false,
|
|
7964
8337
|
promise,
|
|
7965
|
-
resolve:
|
|
8338
|
+
resolve: resolve5
|
|
7966
8339
|
});
|
|
7967
8340
|
void terminal.pty.kill(signal).finally(() => {
|
|
7968
8341
|
const waiter = this.explicitCloseWaiters.get(terminalId);
|
|
@@ -8235,11 +8608,11 @@ var init_watcher = __esm({
|
|
|
8235
8608
|
this.pendingReason = "fs_change";
|
|
8236
8609
|
}
|
|
8237
8610
|
const elapsed = now - this.firstDirtyTime;
|
|
8238
|
-
const
|
|
8611
|
+
const delay2 = Math.min(this.DEBOUNCE_MS, Math.max(0, this.MAX_WAIT_MS - elapsed));
|
|
8239
8612
|
if (this.dirtyTimer) {
|
|
8240
8613
|
clearTimeout(this.dirtyTimer);
|
|
8241
8614
|
}
|
|
8242
|
-
this.dirtyTimer = setTimeout(() => this.flushDirty(),
|
|
8615
|
+
this.dirtyTimer = setTimeout(() => this.flushDirty(), delay2);
|
|
8243
8616
|
}
|
|
8244
8617
|
flushDirty() {
|
|
8245
8618
|
this.broadcaster?.broadcast(Topics.workspaceFsDirty(this.workspaceId), {
|
|
@@ -8837,7 +9210,8 @@ var init_fencing = __esm({
|
|
|
8837
9210
|
});
|
|
8838
9211
|
|
|
8839
9212
|
// packages/server/src/commands/terminal.ts
|
|
8840
|
-
import {
|
|
9213
|
+
import { stat as stat6 } from "node:fs/promises";
|
|
9214
|
+
import { basename, isAbsolute as isAbsolute3 } from "node:path";
|
|
8841
9215
|
import { z as z5 } from "zod";
|
|
8842
9216
|
function decodeTerminalInput(args) {
|
|
8843
9217
|
if ("bytes" in args) {
|
|
@@ -8908,6 +9282,7 @@ var init_terminal = __esm({
|
|
|
8908
9282
|
"packages/server/src/commands/terminal.ts"() {
|
|
8909
9283
|
"use strict";
|
|
8910
9284
|
init_src3();
|
|
9285
|
+
init_file_io();
|
|
8911
9286
|
init_dispatch();
|
|
8912
9287
|
TerminalInputActivitySchema = z5.enum(TERMINAL_INPUT_ACTIVITIES).optional();
|
|
8913
9288
|
TerminalInputSchema = z5.union([
|
|
@@ -8942,20 +9317,44 @@ var init_terminal = __esm({
|
|
|
8942
9317
|
z5.object({
|
|
8943
9318
|
workspaceId: z5.string(),
|
|
8944
9319
|
cols: z5.number().int().positive().optional(),
|
|
8945
|
-
rows: z5.number().int().positive().optional()
|
|
9320
|
+
rows: z5.number().int().positive().optional(),
|
|
9321
|
+
cwdPath: z5.string().optional()
|
|
8946
9322
|
}),
|
|
8947
9323
|
async (args, ctx) => {
|
|
8948
9324
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
8949
9325
|
if (!workspace) {
|
|
8950
9326
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
8951
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
|
+
}
|
|
8952
9351
|
const shell = resolveShellCommand();
|
|
8953
9352
|
const terminal = ctx.terminalMgr.create({
|
|
8954
9353
|
workspaceId: args.workspaceId,
|
|
8955
9354
|
kind: "shell",
|
|
8956
9355
|
argv: shell.argv,
|
|
8957
9356
|
title: shell.title,
|
|
8958
|
-
cwd
|
|
9357
|
+
cwd,
|
|
8959
9358
|
cols: args.cols ?? 120,
|
|
8960
9359
|
rows: args.rows ?? 30
|
|
8961
9360
|
});
|
|
@@ -9641,7 +10040,7 @@ var init_hub = __esm({
|
|
|
9641
10040
|
}
|
|
9642
10041
|
}
|
|
9643
10042
|
awaitBinaryPayload(clientId) {
|
|
9644
|
-
return new Promise((
|
|
10043
|
+
return new Promise((resolve5, reject) => {
|
|
9645
10044
|
const timer = setTimeout(() => {
|
|
9646
10045
|
const waiters = this.pendingBinaryWaiters.get(clientId);
|
|
9647
10046
|
if (!waiters) return;
|
|
@@ -9653,7 +10052,7 @@ var init_hub = __esm({
|
|
|
9653
10052
|
}
|
|
9654
10053
|
reject(new Error("Timeout waiting for terminal input binary payload"));
|
|
9655
10054
|
}, BINARY_PAYLOAD_TIMEOUT_MS);
|
|
9656
|
-
const waiter = { resolve:
|
|
10055
|
+
const waiter = { resolve: resolve5, reject, timer };
|
|
9657
10056
|
const queue = this.pendingBinaryWaiters.get(clientId);
|
|
9658
10057
|
if (queue) {
|
|
9659
10058
|
queue.push(waiter);
|
|
@@ -9931,10 +10330,34 @@ var init_hub = __esm({
|
|
|
9931
10330
|
});
|
|
9932
10331
|
|
|
9933
10332
|
// packages/server/src/commands/workspace.ts
|
|
9934
|
-
import { readdir as readdir2 } from "node:fs/promises";
|
|
10333
|
+
import { readdir as readdir2, realpath as realpath2 } from "node:fs/promises";
|
|
9935
10334
|
import { homedir as homedir2 } from "node:os";
|
|
9936
|
-
import { join as join6 } from "node:path";
|
|
10335
|
+
import { isAbsolute as isAbsolute4, join as join6, resolve as resolve3 } from "node:path";
|
|
9937
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
|
+
}
|
|
9938
10361
|
var init_workspace = __esm({
|
|
9939
10362
|
"packages/server/src/commands/workspace.ts"() {
|
|
9940
10363
|
"use strict";
|
|
@@ -9948,7 +10371,7 @@ var init_workspace = __esm({
|
|
|
9948
10371
|
path: z6.string().optional()
|
|
9949
10372
|
}),
|
|
9950
10373
|
async (args) => {
|
|
9951
|
-
const basePath = args.path
|
|
10374
|
+
const basePath = resolveBrowsePath(args.path);
|
|
9952
10375
|
const entries = await readdir2(basePath, { withFileTypes: true });
|
|
9953
10376
|
const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => ({
|
|
9954
10377
|
name: entry.name,
|
|
@@ -9957,7 +10380,8 @@ var init_workspace = __esm({
|
|
|
9957
10380
|
return {
|
|
9958
10381
|
currentPath: basePath,
|
|
9959
10382
|
parentPath: basePath !== "/" ? join6(basePath, "..") : null,
|
|
9960
|
-
directories
|
|
10383
|
+
directories,
|
|
10384
|
+
rootPaths: await buildRootPaths(basePath)
|
|
9961
10385
|
};
|
|
9962
10386
|
}
|
|
9963
10387
|
);
|
|
@@ -10254,16 +10678,105 @@ var init_runtime_status = __esm({
|
|
|
10254
10678
|
}
|
|
10255
10679
|
});
|
|
10256
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
|
+
|
|
10257
10760
|
// packages/server/src/commands/session.ts
|
|
10258
10761
|
import { z as z10 } from "zod";
|
|
10762
|
+
function delay(ms) {
|
|
10763
|
+
return new Promise((resolve5) => {
|
|
10764
|
+
setTimeout(resolve5, ms);
|
|
10765
|
+
});
|
|
10766
|
+
}
|
|
10259
10767
|
function getProviderFromRegistry(providerId, registry) {
|
|
10260
10768
|
return registry.find((provider) => provider.id === providerId);
|
|
10261
10769
|
}
|
|
10770
|
+
var SESSION_CLOSE_POLL_INTERVAL_MS, SESSION_CLOSE_TIMEOUT_MS;
|
|
10262
10771
|
var init_session = __esm({
|
|
10263
10772
|
"packages/server/src/commands/session.ts"() {
|
|
10264
10773
|
"use strict";
|
|
10265
10774
|
init_runtime_status();
|
|
10775
|
+
init_database();
|
|
10776
|
+
init_pane_layout();
|
|
10266
10777
|
init_dispatch();
|
|
10778
|
+
SESSION_CLOSE_POLL_INTERVAL_MS = 100;
|
|
10779
|
+
SESSION_CLOSE_TIMEOUT_MS = 5e3;
|
|
10267
10780
|
registerCommand(
|
|
10268
10781
|
"session.list",
|
|
10269
10782
|
z10.object({
|
|
@@ -10335,11 +10848,75 @@ var init_session = __esm({
|
|
|
10335
10848
|
ctx.sessionMgr.delete(args.sessionId);
|
|
10336
10849
|
}
|
|
10337
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
|
+
);
|
|
10338
10915
|
}
|
|
10339
10916
|
});
|
|
10340
10917
|
|
|
10341
10918
|
// packages/server/src/fs/tree.ts
|
|
10342
|
-
import { readdir as readdir3, stat as
|
|
10919
|
+
import { readdir as readdir3, stat as stat7 } from "fs/promises";
|
|
10343
10920
|
import { join as join7, relative as relative4 } from "path";
|
|
10344
10921
|
async function readTree(rootPath, subdir) {
|
|
10345
10922
|
const targetPath = subdir ? join7(rootPath, subdir) : rootPath;
|
|
@@ -10361,7 +10938,7 @@ async function readTree(rootPath, subdir) {
|
|
|
10361
10938
|
// Not loaded yet - client will request on expand
|
|
10362
10939
|
});
|
|
10363
10940
|
} else if (entry.isFile()) {
|
|
10364
|
-
const stats = await
|
|
10941
|
+
const stats = await stat7(fullPath);
|
|
10365
10942
|
nodes.push({
|
|
10366
10943
|
name: entry.name,
|
|
10367
10944
|
path: relPath,
|
|
@@ -10430,7 +11007,7 @@ async function searchFiles(rootPath, query, limit = 10) {
|
|
|
10430
11007
|
}
|
|
10431
11008
|
return a.path.toLowerCase().localeCompare(b.path.toLowerCase());
|
|
10432
11009
|
}).slice(0, limit)) {
|
|
10433
|
-
const stats = await
|
|
11010
|
+
const stats = await stat7(match.fullPath);
|
|
10434
11011
|
files.push({
|
|
10435
11012
|
name: match.name,
|
|
10436
11013
|
path: match.path,
|
|
@@ -10597,6 +11174,27 @@ var init_file = __esm({
|
|
|
10597
11174
|
return { ok: true };
|
|
10598
11175
|
}
|
|
10599
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
|
+
);
|
|
10600
11198
|
registerCommand(
|
|
10601
11199
|
"file.write",
|
|
10602
11200
|
z11.object({
|
|
@@ -10778,7 +11376,7 @@ import { mkdir as mkdir4, mkdtemp as mkdtemp2, rm as rm5, writeFile as writeFile
|
|
|
10778
11376
|
import os2 from "os";
|
|
10779
11377
|
import path6 from "path";
|
|
10780
11378
|
async function runGit(cwd, args, options = {}) {
|
|
10781
|
-
return new Promise((
|
|
11379
|
+
return new Promise((resolve5, reject) => {
|
|
10782
11380
|
const gitArgs = [
|
|
10783
11381
|
...options.config?.flatMap(([key, value]) => ["-c", `${key}=${value}`]) ?? [],
|
|
10784
11382
|
...args
|
|
@@ -10805,7 +11403,7 @@ async function runGit(cwd, args, options = {}) {
|
|
|
10805
11403
|
if (err) {
|
|
10806
11404
|
reject(new GitError(err.message, stderr));
|
|
10807
11405
|
} else {
|
|
10808
|
-
|
|
11406
|
+
resolve5({ stdout, stderr });
|
|
10809
11407
|
}
|
|
10810
11408
|
}
|
|
10811
11409
|
);
|
|
@@ -12149,20 +12747,373 @@ var init_settings2 = __esm({
|
|
|
12149
12747
|
}
|
|
12150
12748
|
});
|
|
12151
12749
|
|
|
12152
|
-
// packages/server/src/commands/
|
|
12750
|
+
// packages/server/src/commands/diagnostics.ts
|
|
12153
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";
|
|
12154
13105
|
var init_provider = __esm({
|
|
12155
13106
|
"packages/server/src/commands/provider.ts"() {
|
|
12156
13107
|
"use strict";
|
|
12157
13108
|
init_runtime_status();
|
|
12158
13109
|
init_dispatch();
|
|
12159
|
-
registerCommand("provider.runtimeStatus",
|
|
13110
|
+
registerCommand("provider.runtimeStatus", z15.object({}), async (_args, ctx) => {
|
|
12160
13111
|
return buildProviderRuntimeStatus(ctx.providerRegistry, ctx.providerRuntimeDeps);
|
|
12161
13112
|
});
|
|
12162
13113
|
registerCommand(
|
|
12163
13114
|
"provider.install.start",
|
|
12164
|
-
|
|
12165
|
-
providerId:
|
|
13115
|
+
z15.object({
|
|
13116
|
+
providerId: z15.string()
|
|
12166
13117
|
}),
|
|
12167
13118
|
async (args, ctx) => {
|
|
12168
13119
|
if (!ctx.providerInstallMgr) {
|
|
@@ -12176,8 +13127,8 @@ var init_provider = __esm({
|
|
|
12176
13127
|
);
|
|
12177
13128
|
registerCommand(
|
|
12178
13129
|
"provider.install.get",
|
|
12179
|
-
|
|
12180
|
-
jobId:
|
|
13130
|
+
z15.object({
|
|
13131
|
+
jobId: z15.string()
|
|
12181
13132
|
}),
|
|
12182
13133
|
async (args, ctx) => {
|
|
12183
13134
|
if (!ctx.providerInstallMgr) {
|
|
@@ -12200,35 +13151,35 @@ var init_provider = __esm({
|
|
|
12200
13151
|
});
|
|
12201
13152
|
|
|
12202
13153
|
// packages/server/src/commands/supervisor.ts
|
|
12203
|
-
import { z as
|
|
13154
|
+
import { z as z16 } from "zod";
|
|
12204
13155
|
var supervisorObjectiveSchema, createSupervisorSchema, updateSupervisorSchema, sessionIdSchema, supervisorIdSchema;
|
|
12205
13156
|
var init_supervisor2 = __esm({
|
|
12206
13157
|
"packages/server/src/commands/supervisor.ts"() {
|
|
12207
13158
|
"use strict";
|
|
12208
13159
|
init_dispatch();
|
|
12209
|
-
supervisorObjectiveSchema =
|
|
12210
|
-
createSupervisorSchema =
|
|
12211
|
-
sessionId:
|
|
12212
|
-
workspaceId:
|
|
13160
|
+
supervisorObjectiveSchema = z16.string().trim().min(1).max(4e3);
|
|
13161
|
+
createSupervisorSchema = z16.object({
|
|
13162
|
+
sessionId: z16.string(),
|
|
13163
|
+
workspaceId: z16.string(),
|
|
12213
13164
|
objective: supervisorObjectiveSchema,
|
|
12214
|
-
evaluatorProviderId:
|
|
12215
|
-
evaluatorModel:
|
|
12216
|
-
maxSupervisionCount:
|
|
12217
|
-
scheduledAt:
|
|
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()
|
|
12218
13169
|
}).strict();
|
|
12219
|
-
updateSupervisorSchema =
|
|
12220
|
-
id:
|
|
13170
|
+
updateSupervisorSchema = z16.object({
|
|
13171
|
+
id: z16.string(),
|
|
12221
13172
|
objective: supervisorObjectiveSchema.optional(),
|
|
12222
|
-
evaluatorProviderId:
|
|
12223
|
-
evaluatorModel:
|
|
12224
|
-
maxSupervisionCount:
|
|
12225
|
-
scheduledAt:
|
|
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()
|
|
12226
13177
|
}).strict().refine(
|
|
12227
13178
|
(input) => input.objective !== void 0 || input.evaluatorProviderId !== void 0 || input.evaluatorModel !== void 0 || input.maxSupervisionCount !== void 0 || input.scheduledAt !== void 0,
|
|
12228
13179
|
"at least one supervisor field is required"
|
|
12229
13180
|
);
|
|
12230
|
-
sessionIdSchema =
|
|
12231
|
-
supervisorIdSchema =
|
|
13181
|
+
sessionIdSchema = z16.object({ sessionId: z16.string() });
|
|
13182
|
+
supervisorIdSchema = z16.object({ id: z16.string() });
|
|
12232
13183
|
registerCommand("supervisor.create", createSupervisorSchema, async (args, ctx) => {
|
|
12233
13184
|
return {
|
|
12234
13185
|
supervisor: await ctx.supervisorMgr.create({
|
|
@@ -12412,7 +13363,7 @@ var init_worktree = __esm({
|
|
|
12412
13363
|
|
|
12413
13364
|
// packages/server/src/commands/worktree.ts
|
|
12414
13365
|
import path9 from "node:path";
|
|
12415
|
-
import { z as
|
|
13366
|
+
import { z as z17 } from "zod";
|
|
12416
13367
|
async function findRelatedWorkspaceIds(ctx, workspacePath) {
|
|
12417
13368
|
const targetCommonDir = await getGitCommonDirPath(workspacePath);
|
|
12418
13369
|
const relatedWorkspaceIds = await Promise.all(
|
|
@@ -12445,7 +13396,7 @@ var init_worktree2 = __esm({
|
|
|
12445
13396
|
init_worktree();
|
|
12446
13397
|
init_dispatch();
|
|
12447
13398
|
init_git_events();
|
|
12448
|
-
registerCommand("worktree.list",
|
|
13399
|
+
registerCommand("worktree.list", z17.object({ workspaceId: z17.string() }), async (args, ctx) => {
|
|
12449
13400
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
12450
13401
|
if (!workspace) {
|
|
12451
13402
|
throw { code: "workspace_not_found", message: `Workspace not found: ${args.workspaceId}` };
|
|
@@ -12454,7 +13405,7 @@ var init_worktree2 = __esm({
|
|
|
12454
13405
|
});
|
|
12455
13406
|
registerCommand(
|
|
12456
13407
|
"worktree.status",
|
|
12457
|
-
|
|
13408
|
+
z17.object({ workspaceId: z17.string(), worktreePath: z17.string() }),
|
|
12458
13409
|
async (args, ctx) => {
|
|
12459
13410
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
12460
13411
|
if (!workspace) {
|
|
@@ -12466,10 +13417,10 @@ var init_worktree2 = __esm({
|
|
|
12466
13417
|
);
|
|
12467
13418
|
registerCommand(
|
|
12468
13419
|
"worktree.diff",
|
|
12469
|
-
|
|
12470
|
-
workspaceId:
|
|
12471
|
-
worktreePath:
|
|
12472
|
-
staged:
|
|
13420
|
+
z17.object({
|
|
13421
|
+
workspaceId: z17.string(),
|
|
13422
|
+
worktreePath: z17.string(),
|
|
13423
|
+
staged: z17.boolean().optional().default(false)
|
|
12473
13424
|
}),
|
|
12474
13425
|
async (args, ctx) => {
|
|
12475
13426
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -12482,7 +13433,7 @@ var init_worktree2 = __esm({
|
|
|
12482
13433
|
);
|
|
12483
13434
|
registerCommand(
|
|
12484
13435
|
"worktree.tree",
|
|
12485
|
-
|
|
13436
|
+
z17.object({ workspaceId: z17.string(), worktreePath: z17.string() }),
|
|
12486
13437
|
async (args, ctx) => {
|
|
12487
13438
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
12488
13439
|
if (!workspace) {
|
|
@@ -12494,10 +13445,10 @@ var init_worktree2 = __esm({
|
|
|
12494
13445
|
);
|
|
12495
13446
|
registerCommand(
|
|
12496
13447
|
"worktree.create",
|
|
12497
|
-
|
|
12498
|
-
workspaceId:
|
|
12499
|
-
branch:
|
|
12500
|
-
path:
|
|
13448
|
+
z17.object({
|
|
13449
|
+
workspaceId: z17.string(),
|
|
13450
|
+
branch: z17.string(),
|
|
13451
|
+
path: z17.string()
|
|
12501
13452
|
}),
|
|
12502
13453
|
async (args, ctx) => {
|
|
12503
13454
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -12512,10 +13463,10 @@ var init_worktree2 = __esm({
|
|
|
12512
13463
|
);
|
|
12513
13464
|
registerCommand(
|
|
12514
13465
|
"worktree.remove",
|
|
12515
|
-
|
|
12516
|
-
workspaceId:
|
|
12517
|
-
worktreePath:
|
|
12518
|
-
force:
|
|
13466
|
+
z17.object({
|
|
13467
|
+
workspaceId: z17.string(),
|
|
13468
|
+
worktreePath: z17.string(),
|
|
13469
|
+
force: z17.boolean().optional().default(false)
|
|
12519
13470
|
}),
|
|
12520
13471
|
async (args, ctx) => {
|
|
12521
13472
|
const workspace = ctx.workspaceMgr.get(args.workspaceId);
|
|
@@ -12539,7 +13490,7 @@ var init_worktree2 = __esm({
|
|
|
12539
13490
|
});
|
|
12540
13491
|
|
|
12541
13492
|
// packages/server/src/commands/fencing.ts
|
|
12542
|
-
import { z as
|
|
13493
|
+
import { z as z18 } from "zod";
|
|
12543
13494
|
function createMockFencingRequest() {
|
|
12544
13495
|
return {
|
|
12545
13496
|
ip: "127.0.0.1",
|
|
@@ -12552,9 +13503,9 @@ var init_fencing2 = __esm({
|
|
|
12552
13503
|
init_dispatch();
|
|
12553
13504
|
registerCommand(
|
|
12554
13505
|
"fencing.request",
|
|
12555
|
-
|
|
12556
|
-
workspaceId:
|
|
12557
|
-
tabId:
|
|
13506
|
+
z18.object({
|
|
13507
|
+
workspaceId: z18.string(),
|
|
13508
|
+
tabId: z18.string()
|
|
12558
13509
|
}),
|
|
12559
13510
|
async (args, ctx, clientId) => {
|
|
12560
13511
|
return ctx.fencingMgr.requestControl(
|
|
@@ -12567,7 +13518,7 @@ var init_fencing2 = __esm({
|
|
|
12567
13518
|
);
|
|
12568
13519
|
registerCommand(
|
|
12569
13520
|
"fencing.heartbeat",
|
|
12570
|
-
|
|
13521
|
+
z18.object({ workspaceId: z18.string() }),
|
|
12571
13522
|
async (args, ctx, clientId) => {
|
|
12572
13523
|
const success = ctx.fencingMgr.heartbeat(args.workspaceId, clientId);
|
|
12573
13524
|
return { success };
|
|
@@ -12575,13 +13526,13 @@ var init_fencing2 = __esm({
|
|
|
12575
13526
|
);
|
|
12576
13527
|
registerCommand(
|
|
12577
13528
|
"fencing.release",
|
|
12578
|
-
|
|
13529
|
+
z18.object({ workspaceId: z18.string() }),
|
|
12579
13530
|
async (args, ctx, clientId) => {
|
|
12580
13531
|
ctx.fencingMgr.release(args.workspaceId, clientId);
|
|
12581
13532
|
return {};
|
|
12582
13533
|
}
|
|
12583
13534
|
);
|
|
12584
|
-
registerCommand("fencing.status",
|
|
13535
|
+
registerCommand("fencing.status", z18.object({ workspaceId: z18.string() }), async (args, ctx) => {
|
|
12585
13536
|
const controller = ctx.fencingMgr.getController(args.workspaceId);
|
|
12586
13537
|
const isUnresponsive = ctx.fencingMgr.isControllerUnresponsive(args.workspaceId);
|
|
12587
13538
|
return {
|
|
@@ -12592,9 +13543,9 @@ var init_fencing2 = __esm({
|
|
|
12592
13543
|
});
|
|
12593
13544
|
registerCommand(
|
|
12594
13545
|
"fencing.takeover",
|
|
12595
|
-
|
|
12596
|
-
workspaceId:
|
|
12597
|
-
tabId:
|
|
13546
|
+
z18.object({
|
|
13547
|
+
workspaceId: z18.string(),
|
|
13548
|
+
tabId: z18.string()
|
|
12598
13549
|
}),
|
|
12599
13550
|
async (args, ctx, clientId) => {
|
|
12600
13551
|
return ctx.fencingMgr.forceTakeover(
|
|
@@ -12621,6 +13572,7 @@ var init_commands = __esm({
|
|
|
12621
13572
|
init_file();
|
|
12622
13573
|
init_git2();
|
|
12623
13574
|
init_settings2();
|
|
13575
|
+
init_diagnostics2();
|
|
12624
13576
|
init_provider();
|
|
12625
13577
|
init_supervisor2();
|
|
12626
13578
|
init_worktree2();
|
|
@@ -12764,7 +13716,8 @@ async function createServer(configOverrides) {
|
|
|
12764
13716
|
autoFetch,
|
|
12765
13717
|
providerRuntimeDeps,
|
|
12766
13718
|
providerInstallMgr,
|
|
12767
|
-
activationMgr
|
|
13719
|
+
activationMgr,
|
|
13720
|
+
config
|
|
12768
13721
|
};
|
|
12769
13722
|
wsHub.setCommandContext(commandContext);
|
|
12770
13723
|
await app.listen({
|
|
@@ -13269,11 +14222,11 @@ function readCliConfig() {
|
|
|
13269
14222
|
|
|
13270
14223
|
// packages/cli/src/embed.ts
|
|
13271
14224
|
import { existsSync as existsSync8 } from "fs";
|
|
13272
|
-
import { dirname as dirname6, resolve as
|
|
14225
|
+
import { dirname as dirname6, resolve as resolve4 } from "path";
|
|
13273
14226
|
import { fileURLToPath } from "url";
|
|
13274
14227
|
var __filename = fileURLToPath(import.meta.url);
|
|
13275
14228
|
var __dirname = dirname6(__filename);
|
|
13276
|
-
var WEB_ASSETS_DIR =
|
|
14229
|
+
var WEB_ASSETS_DIR = resolve4(__dirname, "../web");
|
|
13277
14230
|
function getStaticAssetsDir() {
|
|
13278
14231
|
return WEB_ASSETS_DIR;
|
|
13279
14232
|
}
|