@sideboard-ai/core 0.1.185 → 0.1.187
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agents-R6RQMMNE.js → agents-TPK2JYL4.js} +1 -1
- package/dist/{agents-HC6HWBDB.js → agents-W3JQANEC.js} +1 -1
- package/dist/{chunk-5FTIOINZ.js → chunk-6XOSOIDJ.js} +15 -6
- package/dist/{chunk-AHV36NL3.js → chunk-7DBYKEYF.js} +7 -1
- package/dist/{chunk-G4VAMUCL.js → chunk-P56XKPWT.js} +21 -15
- package/dist/{chunk-IQC35TVQ.js → chunk-S6HYHXFO.js} +20 -14
- package/dist/index.cjs +35 -19
- package/dist/index.js +4 -4
- package/dist/mcp/run-stdio.cjs +27 -14
- package/dist/mcp/run-stdio.js +4 -4
- package/dist/{orchestrator-SVFF5CLQ.js → orchestrator-5CFTLN7B.js} +2 -2
- package/dist/{orchestrator-45PPV2LQ.js → orchestrator-6PZQ7DZS.js} +2 -2
- package/package.json +1 -1
|
@@ -599,10 +599,18 @@ function asRecord(input) {
|
|
|
599
599
|
function str(v) {
|
|
600
600
|
return typeof v === "string" && v.trim() ? v : void 0;
|
|
601
601
|
}
|
|
602
|
+
var CHAT_DETAIL_MAX = 72;
|
|
603
|
+
function clipChatLine(value, max = CHAT_DETAIL_MAX) {
|
|
604
|
+
const line = value.trim().split(/\r?\n/, 1)[0] ?? "";
|
|
605
|
+
if (line.length <= max) return line;
|
|
606
|
+
return `${line.slice(0, Math.max(1, max - 1))}\u2026`;
|
|
607
|
+
}
|
|
602
608
|
function looksLikeFilePath(value) {
|
|
603
|
-
|
|
604
|
-
if (
|
|
605
|
-
|
|
609
|
+
const trimmed = value.trim();
|
|
610
|
+
if (!trimmed || /[\s;|&<>]/.test(trimmed)) return false;
|
|
611
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("~/")) return true;
|
|
612
|
+
if (/^[A-Za-z]:[\\/]/.test(trimmed)) return true;
|
|
613
|
+
return trimmed.includes("/") || trimmed.includes("\\");
|
|
606
614
|
}
|
|
607
615
|
function stripWorktreePrefix(path, worktreePath) {
|
|
608
616
|
if (!worktreePath) return path;
|
|
@@ -616,8 +624,9 @@ function visibleToolRowDetail(detail, description, worktreePath) {
|
|
|
616
624
|
const raw = detail.trim();
|
|
617
625
|
const desc = (description ?? "").trim();
|
|
618
626
|
if (!looksLikeFilePath(raw)) {
|
|
619
|
-
|
|
620
|
-
return
|
|
627
|
+
const clipped = clipChatLine(raw);
|
|
628
|
+
if (!clipped || desc === clipped || desc === raw) return void 0;
|
|
629
|
+
return clipped;
|
|
621
630
|
}
|
|
622
631
|
const rel = stripWorktreePrefix(raw, worktreePath);
|
|
623
632
|
if (!rel) return void 0;
|
|
@@ -631,7 +640,7 @@ function visibleToolRowDetail(detail, description, worktreePath) {
|
|
|
631
640
|
function toolDetail(name, input) {
|
|
632
641
|
if (!input) return void 0;
|
|
633
642
|
const command = str(input.command) ?? str(input.cmd);
|
|
634
|
-
if (command) return command;
|
|
643
|
+
if (command) return clipChatLine(command);
|
|
635
644
|
const pattern = str(input.pattern) ?? str(input.glob) ?? str(input.glob_pattern);
|
|
636
645
|
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
637
646
|
if (isSearch && pattern) {
|
|
@@ -828,10 +828,16 @@ function asRecord(input) {
|
|
|
828
828
|
function str(v) {
|
|
829
829
|
return typeof v === "string" && v.trim() ? v : void 0;
|
|
830
830
|
}
|
|
831
|
+
var CHAT_DETAIL_MAX = 72;
|
|
832
|
+
function clipChatLine(value, max = CHAT_DETAIL_MAX) {
|
|
833
|
+
const line = value.trim().split(/\r?\n/, 1)[0] ?? "";
|
|
834
|
+
if (line.length <= max) return line;
|
|
835
|
+
return `${line.slice(0, Math.max(1, max - 1))}\u2026`;
|
|
836
|
+
}
|
|
831
837
|
function toolDetail(name, input) {
|
|
832
838
|
if (!input) return void 0;
|
|
833
839
|
const command = str(input.command) ?? str(input.cmd);
|
|
834
|
-
if (command) return command;
|
|
840
|
+
if (command) return clipChatLine(command);
|
|
835
841
|
const pattern = str(input.pattern) ?? str(input.glob) ?? str(input.glob_pattern);
|
|
836
842
|
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
837
843
|
if (isSearch && pattern) {
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
stripBrightsyNdjsonNoise,
|
|
25
25
|
sumUsageList,
|
|
26
26
|
toolDescription
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-6XOSOIDJ.js";
|
|
28
28
|
import {
|
|
29
29
|
SLACK_REPLY_FORMATTING,
|
|
30
30
|
addWorkspace,
|
|
@@ -467,7 +467,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
467
467
|
await continueOnReply(threadId, prompt);
|
|
468
468
|
return;
|
|
469
469
|
}
|
|
470
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
470
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-5CFTLN7B.js");
|
|
471
471
|
await getOrchestrator2().send(threadId, prompt);
|
|
472
472
|
} catch {
|
|
473
473
|
}
|
|
@@ -2762,8 +2762,8 @@ function mcpWaitFinishedHint(status) {
|
|
|
2762
2762
|
|
|
2763
2763
|
// src/mcp/wait-for-job.ts
|
|
2764
2764
|
var MAX_JOB_CONTINUES = 8;
|
|
2765
|
-
var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running.
|
|
2766
|
-
var MCP_STOP_JOB_HINT = "Stopped.
|
|
2765
|
+
var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. The type=log pane already appended this delta. Call wait_for_job again. If it is hanging, producing no useful output, or doing the wrong thing, call stop_job (same id) instead of looping forever. Do not end the turn or tell the user you will let them know later.";
|
|
2766
|
+
var MCP_STOP_JOB_HINT = "Stopped. The type=log pane is status=failed with the last delta. Do not wait again unless you start a new command.";
|
|
2767
2767
|
var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
2768
2768
|
function mcpWaitForJobTimeoutMs(requested) {
|
|
2769
2769
|
return mcpWaitForTurnTimeoutMs(requested);
|
|
@@ -2842,7 +2842,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
2842
2842
|
const ids = jobIds.join(", ");
|
|
2843
2843
|
return [
|
|
2844
2844
|
`Detached job still running: ${ids}.`,
|
|
2845
|
-
"Do not end this turn. Loop wait_for_job (same id)
|
|
2845
|
+
"Do not end this turn. Loop wait_for_job (same id) until stillRunning is false. The log pane updates from each wait result.",
|
|
2846
2846
|
"If the job is hanging or doing the wrong thing, call stop_job (same id) instead of looping forever.",
|
|
2847
2847
|
"Then report the result. Do not tell the user you will let them know later."
|
|
2848
2848
|
].join(" ");
|
|
@@ -2850,7 +2850,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
2850
2850
|
function formatDeferredDoneContinuePrompt() {
|
|
2851
2851
|
return [
|
|
2852
2852
|
"You ended the turn after promising to report later, but no detached job is running.",
|
|
2853
|
-
"If tests/pack/deploy still need to run: start once with detached-job.cjs,
|
|
2853
|
+
"If tests/pack/deploy still need to run: start once with detached-job.cjs, then loop wait_for_job until stillRunning is false (the log pane updates from wait JSON).",
|
|
2854
2854
|
"Do not say you will let the user know later."
|
|
2855
2855
|
].join(" ");
|
|
2856
2856
|
}
|
|
@@ -2885,6 +2885,10 @@ function tailProgress(logFile, maxLines = 12) {
|
|
|
2885
2885
|
const lines = readFileSync7(logFile, "utf8").split("\n");
|
|
2886
2886
|
return lines.slice(-maxLines).join("\n");
|
|
2887
2887
|
}
|
|
2888
|
+
function lastProgressLine(progress) {
|
|
2889
|
+
const last = progress.split("\n").map((l) => l.trim()).filter((l) => l && l !== "(no log yet)").at(-1);
|
|
2890
|
+
return last ? last.slice(0, 72) : void 0;
|
|
2891
|
+
}
|
|
2888
2892
|
function readLogLines(file) {
|
|
2889
2893
|
if (!existsSync9(file)) return [];
|
|
2890
2894
|
const lines = readFileSync7(file, "utf8").split("\n");
|
|
@@ -2921,6 +2925,7 @@ function toResult(id, snap, extra) {
|
|
|
2921
2925
|
} catch {
|
|
2922
2926
|
}
|
|
2923
2927
|
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
2928
|
+
const progress = extra?.progress ?? snap.progress;
|
|
2924
2929
|
return {
|
|
2925
2930
|
stillRunning,
|
|
2926
2931
|
ok,
|
|
@@ -2929,8 +2934,9 @@ function toResult(id, snap, extra) {
|
|
|
2929
2934
|
id,
|
|
2930
2935
|
pid: snap.pid,
|
|
2931
2936
|
exitCode: snap.exitCode ?? void 0,
|
|
2937
|
+
phase: lastProgressLine(progress),
|
|
2932
2938
|
delta,
|
|
2933
|
-
progress
|
|
2939
|
+
progress,
|
|
2934
2940
|
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
2935
2941
|
};
|
|
2936
2942
|
}
|
|
@@ -3835,7 +3841,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3835
3841
|
return readThread(thread.id) ?? thread;
|
|
3836
3842
|
}
|
|
3837
3843
|
async function listLinearIssues(agent, repoPath) {
|
|
3838
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3844
|
+
const { getAdapter: getAdapter2 } = await import("./agents-W3JQANEC.js");
|
|
3839
3845
|
await requireAgent(agent, { requireLinear: true });
|
|
3840
3846
|
const adapter = getAdapter2(agent);
|
|
3841
3847
|
if (!adapter.listLinearIssues) {
|
|
@@ -5644,7 +5650,7 @@ Wait JSON:
|
|
|
5644
5650
|
|
|
5645
5651
|
## Sideboard UI (append-only log)
|
|
5646
5652
|
|
|
5647
|
-
The side column **is** the live view.
|
|
5653
|
+
The side column **is** the live view. \`wait_for_job\` / \`stop_job\` (and shell \`detached-job\` wait JSON) open a \`type=log\` pane automatically (\`artifact_id\` = job id, content = \`delta\`). You may still call \`present_artifact\` **\`type=log\`** for a custom title. Each update **appends** \u2014 send only \`delta\`, not the full log and not HTML.
|
|
5648
5654
|
|
|
5649
5655
|
\`\`\`
|
|
5650
5656
|
present_artifact
|
|
@@ -5656,7 +5662,7 @@ present_artifact
|
|
|
5656
5662
|
phase: <wait.phase>
|
|
5657
5663
|
\`\`\`
|
|
5658
5664
|
|
|
5659
|
-
After **start**,
|
|
5665
|
+
After **start**, the first \`wait_for_job\` opens the pane (\`status=running\`). Do **not** dump the log in chat. Do **not** also fence HTML.
|
|
5660
5666
|
|
|
5661
5667
|
Ad-hoc pid/log (legacy or another tool\u2019s files):
|
|
5662
5668
|
|
|
@@ -5667,8 +5673,8 @@ node <detached-job.cjs> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
5667
5673
|
## Agent loop
|
|
5668
5674
|
|
|
5669
5675
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
5670
|
-
2.
|
|
5671
|
-
3.
|
|
5676
|
+
2. Loop \`wait_for_job\` (or shell \`wait\`). The human should see **working** in the side column from the wait JSON \u2014 do not also dump the log in chat.
|
|
5677
|
+
3. After each slice, the same log pane appends \`delta\`. Optional: \`present_artifact\` the same id for a custom title.
|
|
5672
5678
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
5673
5679
|
5. **Stop** when the job is hanging, buffering forever, watching the wrong thing, or you already have the answer. MCP \`stop_job\` (same id, optional \`reason\`) or \`detached-job.cjs stop <id>\`. Do **not** stop a pack/test/deploy that is clearly making progress.
|
|
5674
5680
|
|
|
@@ -6175,7 +6181,7 @@ function formatLongRunningDirective(opts) {
|
|
|
6175
6181
|
"Long-running jobs (mandatory when a command may run more than ~30s \u2014 pack, test, deploy, `gh pr checks --watch`):",
|
|
6176
6182
|
"A Sideboard worktree turn SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted; `block_until_ms: 0` is not enough. Detach instead, and never ask the human to poll.",
|
|
6177
6183
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree; same tool as \`scripts/detached-job.cjs\` when the worktree has it). If JSON says already-running, do not start again.`,
|
|
6178
|
-
"-
|
|
6184
|
+
"- Loop Sideboard MCP `wait_for_job` (returns in ~45s). The desktop opens a `type=log` pane from wait/stop (and shell detached-job JSON) automatically \u2014 you may still `present_artifact` with `artifact_id=<id>` for a custom title. stillRunning \u2192 wait again. Shell fallback: the same helper with `wait <id>`.",
|
|
6179
6185
|
"- Hanging, no useful output, or the wrong thing \u2192 `stop_job` (or the helper with `stop <id>`). Do not stop a pack/test/deploy that is clearly making progress.",
|
|
6180
6186
|
"- Stay in the loop until stillRunning is false (or you stopped it). ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
|
|
6181
6187
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
@@ -6183,7 +6189,7 @@ function formatLongRunningDirective(opts) {
|
|
|
6183
6189
|
}
|
|
6184
6190
|
function formatLongRunningReminder(opts) {
|
|
6185
6191
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
6186
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait)
|
|
6192
|
+
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait). The log pane updates from wait JSON; present_artifact type=log is optional. stop_job if hanging or wrong. Do not say you will let the user know later \u2014 stay in the turn.`;
|
|
6187
6193
|
}
|
|
6188
6194
|
function formatArtifactDirective() {
|
|
6189
6195
|
return [
|
|
@@ -6766,7 +6772,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6766
6772
|
${prompt}`;
|
|
6767
6773
|
}
|
|
6768
6774
|
async function defaultDeps() {
|
|
6769
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6775
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-5CFTLN7B.js");
|
|
6770
6776
|
const orch = getOrchestrator2();
|
|
6771
6777
|
return {
|
|
6772
6778
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
summarizeTurnStderr,
|
|
34
34
|
toolDescription,
|
|
35
35
|
turnFailChatText
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-7DBYKEYF.js";
|
|
37
37
|
import {
|
|
38
38
|
extractPresentedPlan,
|
|
39
39
|
readPlanFile,
|
|
@@ -402,7 +402,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
402
402
|
await continueOnReply(threadId, prompt);
|
|
403
403
|
return;
|
|
404
404
|
}
|
|
405
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
405
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-6PZQ7DZS.js");
|
|
406
406
|
await getOrchestrator2().send(threadId, prompt);
|
|
407
407
|
} catch {
|
|
408
408
|
}
|
|
@@ -2675,8 +2675,8 @@ function mcpWaitFinishedHint(status) {
|
|
|
2675
2675
|
|
|
2676
2676
|
// src/mcp/wait-for-job.ts
|
|
2677
2677
|
var MAX_JOB_CONTINUES = 8;
|
|
2678
|
-
var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running.
|
|
2679
|
-
var MCP_STOP_JOB_HINT = "Stopped.
|
|
2678
|
+
var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. The type=log pane already appended this delta. Call wait_for_job again. If it is hanging, producing no useful output, or doing the wrong thing, call stop_job (same id) instead of looping forever. Do not end the turn or tell the user you will let them know later.";
|
|
2679
|
+
var MCP_STOP_JOB_HINT = "Stopped. The type=log pane is status=failed with the last delta. Do not wait again unless you start a new command.";
|
|
2680
2680
|
var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
2681
2681
|
function mcpWaitForJobTimeoutMs(requested) {
|
|
2682
2682
|
return mcpWaitForTurnTimeoutMs(requested);
|
|
@@ -2755,7 +2755,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
2755
2755
|
const ids = jobIds.join(", ");
|
|
2756
2756
|
return [
|
|
2757
2757
|
`Detached job still running: ${ids}.`,
|
|
2758
|
-
"Do not end this turn. Loop wait_for_job (same id)
|
|
2758
|
+
"Do not end this turn. Loop wait_for_job (same id) until stillRunning is false. The log pane updates from each wait result.",
|
|
2759
2759
|
"If the job is hanging or doing the wrong thing, call stop_job (same id) instead of looping forever.",
|
|
2760
2760
|
"Then report the result. Do not tell the user you will let them know later."
|
|
2761
2761
|
].join(" ");
|
|
@@ -2763,7 +2763,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
2763
2763
|
function formatDeferredDoneContinuePrompt() {
|
|
2764
2764
|
return [
|
|
2765
2765
|
"You ended the turn after promising to report later, but no detached job is running.",
|
|
2766
|
-
"If tests/pack/deploy still need to run: start once with detached-job.cjs,
|
|
2766
|
+
"If tests/pack/deploy still need to run: start once with detached-job.cjs, then loop wait_for_job until stillRunning is false (the log pane updates from wait JSON).",
|
|
2767
2767
|
"Do not say you will let the user know later."
|
|
2768
2768
|
].join(" ");
|
|
2769
2769
|
}
|
|
@@ -2798,6 +2798,10 @@ function tailProgress(logFile, maxLines = 12) {
|
|
|
2798
2798
|
const lines = readFileSync7(logFile, "utf8").split("\n");
|
|
2799
2799
|
return lines.slice(-maxLines).join("\n");
|
|
2800
2800
|
}
|
|
2801
|
+
function lastProgressLine(progress) {
|
|
2802
|
+
const last = progress.split("\n").map((l) => l.trim()).filter((l) => l && l !== "(no log yet)").at(-1);
|
|
2803
|
+
return last ? last.slice(0, 72) : void 0;
|
|
2804
|
+
}
|
|
2801
2805
|
function readLogLines(file) {
|
|
2802
2806
|
if (!existsSync9(file)) return [];
|
|
2803
2807
|
const lines = readFileSync7(file, "utf8").split("\n");
|
|
@@ -2834,6 +2838,7 @@ function toResult(id, snap, extra) {
|
|
|
2834
2838
|
} catch {
|
|
2835
2839
|
}
|
|
2836
2840
|
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
2841
|
+
const progress = extra?.progress ?? snap.progress;
|
|
2837
2842
|
return {
|
|
2838
2843
|
stillRunning,
|
|
2839
2844
|
ok,
|
|
@@ -2842,8 +2847,9 @@ function toResult(id, snap, extra) {
|
|
|
2842
2847
|
id,
|
|
2843
2848
|
pid: snap.pid,
|
|
2844
2849
|
exitCode: snap.exitCode ?? void 0,
|
|
2850
|
+
phase: lastProgressLine(progress),
|
|
2845
2851
|
delta,
|
|
2846
|
-
progress
|
|
2852
|
+
progress,
|
|
2847
2853
|
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
2848
2854
|
};
|
|
2849
2855
|
}
|
|
@@ -5490,7 +5496,7 @@ Wait JSON:
|
|
|
5490
5496
|
|
|
5491
5497
|
## Sideboard UI (append-only log)
|
|
5492
5498
|
|
|
5493
|
-
The side column **is** the live view.
|
|
5499
|
+
The side column **is** the live view. \`wait_for_job\` / \`stop_job\` (and shell \`detached-job\` wait JSON) open a \`type=log\` pane automatically (\`artifact_id\` = job id, content = \`delta\`). You may still call \`present_artifact\` **\`type=log\`** for a custom title. Each update **appends** \u2014 send only \`delta\`, not the full log and not HTML.
|
|
5494
5500
|
|
|
5495
5501
|
\`\`\`
|
|
5496
5502
|
present_artifact
|
|
@@ -5502,7 +5508,7 @@ present_artifact
|
|
|
5502
5508
|
phase: <wait.phase>
|
|
5503
5509
|
\`\`\`
|
|
5504
5510
|
|
|
5505
|
-
After **start**,
|
|
5511
|
+
After **start**, the first \`wait_for_job\` opens the pane (\`status=running\`). Do **not** dump the log in chat. Do **not** also fence HTML.
|
|
5506
5512
|
|
|
5507
5513
|
Ad-hoc pid/log (legacy or another tool\u2019s files):
|
|
5508
5514
|
|
|
@@ -5513,8 +5519,8 @@ node <detached-job.cjs> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
5513
5519
|
## Agent loop
|
|
5514
5520
|
|
|
5515
5521
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
5516
|
-
2.
|
|
5517
|
-
3.
|
|
5522
|
+
2. Loop \`wait_for_job\` (or shell \`wait\`). The human should see **working** in the side column from the wait JSON \u2014 do not also dump the log in chat.
|
|
5523
|
+
3. After each slice, the same log pane appends \`delta\`. Optional: \`present_artifact\` the same id for a custom title.
|
|
5518
5524
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
5519
5525
|
5. **Stop** when the job is hanging, buffering forever, watching the wrong thing, or you already have the answer. MCP \`stop_job\` (same id, optional \`reason\`) or \`detached-job.cjs stop <id>\`. Do **not** stop a pack/test/deploy that is clearly making progress.
|
|
5520
5526
|
|
|
@@ -5999,7 +6005,7 @@ function formatLongRunningDirective(opts) {
|
|
|
5999
6005
|
"Long-running jobs (mandatory when a command may run more than ~30s \u2014 pack, test, deploy, `gh pr checks --watch`):",
|
|
6000
6006
|
"A Sideboard worktree turn SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted; `block_until_ms: 0` is not enough. Detach instead, and never ask the human to poll.",
|
|
6001
6007
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree; same tool as \`scripts/detached-job.cjs\` when the worktree has it). If JSON says already-running, do not start again.`,
|
|
6002
|
-
"-
|
|
6008
|
+
"- Loop Sideboard MCP `wait_for_job` (returns in ~45s). The desktop opens a `type=log` pane from wait/stop (and shell detached-job JSON) automatically \u2014 you may still `present_artifact` with `artifact_id=<id>` for a custom title. stillRunning \u2192 wait again. Shell fallback: the same helper with `wait <id>`.",
|
|
6003
6009
|
"- Hanging, no useful output, or the wrong thing \u2192 `stop_job` (or the helper with `stop <id>`). Do not stop a pack/test/deploy that is clearly making progress.",
|
|
6004
6010
|
"- Stay in the loop until stillRunning is false (or you stopped it). ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
|
|
6005
6011
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
@@ -6007,7 +6013,7 @@ function formatLongRunningDirective(opts) {
|
|
|
6007
6013
|
}
|
|
6008
6014
|
function formatLongRunningReminder(opts) {
|
|
6009
6015
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
6010
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait)
|
|
6016
|
+
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait). The log pane updates from wait JSON; present_artifact type=log is optional. stop_job if hanging or wrong. Do not say you will let the user know later \u2014 stay in the turn.`;
|
|
6011
6017
|
}
|
|
6012
6018
|
function formatArtifactDirective() {
|
|
6013
6019
|
return [
|
|
@@ -6419,7 +6425,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6419
6425
|
${prompt}`;
|
|
6420
6426
|
}
|
|
6421
6427
|
async function defaultDeps() {
|
|
6422
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6428
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-6PZQ7DZS.js");
|
|
6423
6429
|
const orch = getOrchestrator2();
|
|
6424
6430
|
return {
|
|
6425
6431
|
findThread: (id) => findThreadByRef(id),
|
package/dist/index.cjs
CHANGED
|
@@ -9929,10 +9929,17 @@ function asRecord(input) {
|
|
|
9929
9929
|
function str2(v) {
|
|
9930
9930
|
return typeof v === "string" && v.trim() ? v : void 0;
|
|
9931
9931
|
}
|
|
9932
|
+
function clipChatLine(value, max = CHAT_DETAIL_MAX) {
|
|
9933
|
+
const line = value.trim().split(/\r?\n/, 1)[0] ?? "";
|
|
9934
|
+
if (line.length <= max) return line;
|
|
9935
|
+
return `${line.slice(0, Math.max(1, max - 1))}\u2026`;
|
|
9936
|
+
}
|
|
9932
9937
|
function looksLikeFilePath(value) {
|
|
9933
|
-
|
|
9934
|
-
if (
|
|
9935
|
-
|
|
9938
|
+
const trimmed = value.trim();
|
|
9939
|
+
if (!trimmed || /[\s;|&<>]/.test(trimmed)) return false;
|
|
9940
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("~/")) return true;
|
|
9941
|
+
if (/^[A-Za-z]:[\\/]/.test(trimmed)) return true;
|
|
9942
|
+
return trimmed.includes("/") || trimmed.includes("\\");
|
|
9936
9943
|
}
|
|
9937
9944
|
function stripWorktreePrefix(path2, worktreePath) {
|
|
9938
9945
|
if (!worktreePath) return path2;
|
|
@@ -9946,8 +9953,9 @@ function visibleToolRowDetail(detail, description, worktreePath) {
|
|
|
9946
9953
|
const raw = detail.trim();
|
|
9947
9954
|
const desc = (description ?? "").trim();
|
|
9948
9955
|
if (!looksLikeFilePath(raw)) {
|
|
9949
|
-
|
|
9950
|
-
return
|
|
9956
|
+
const clipped = clipChatLine(raw);
|
|
9957
|
+
if (!clipped || desc === clipped || desc === raw) return void 0;
|
|
9958
|
+
return clipped;
|
|
9951
9959
|
}
|
|
9952
9960
|
const rel = stripWorktreePrefix(raw, worktreePath);
|
|
9953
9961
|
if (!rel) return void 0;
|
|
@@ -9961,7 +9969,7 @@ function visibleToolRowDetail(detail, description, worktreePath) {
|
|
|
9961
9969
|
function toolDetail(name, input) {
|
|
9962
9970
|
if (!input) return void 0;
|
|
9963
9971
|
const command = str2(input.command) ?? str2(input.cmd);
|
|
9964
|
-
if (command) return command;
|
|
9972
|
+
if (command) return clipChatLine(command);
|
|
9965
9973
|
const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
|
|
9966
9974
|
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
9967
9975
|
if (isSearch && pattern) {
|
|
@@ -10481,10 +10489,12 @@ function normalizeParseResult(parsed) {
|
|
|
10481
10489
|
if (!parsed) return [];
|
|
10482
10490
|
return Array.isArray(parsed) ? parsed : [parsed];
|
|
10483
10491
|
}
|
|
10492
|
+
var CHAT_DETAIL_MAX;
|
|
10484
10493
|
var init_message_parts = __esm({
|
|
10485
10494
|
"src/agents/message-parts.ts"() {
|
|
10486
10495
|
"use strict";
|
|
10487
10496
|
init_error_detail();
|
|
10497
|
+
CHAT_DETAIL_MAX = 72;
|
|
10488
10498
|
}
|
|
10489
10499
|
});
|
|
10490
10500
|
|
|
@@ -15990,7 +16000,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
15990
16000
|
const ids = jobIds.join(", ");
|
|
15991
16001
|
return [
|
|
15992
16002
|
`Detached job still running: ${ids}.`,
|
|
15993
|
-
"Do not end this turn. Loop wait_for_job (same id)
|
|
16003
|
+
"Do not end this turn. Loop wait_for_job (same id) until stillRunning is false. The log pane updates from each wait result.",
|
|
15994
16004
|
"If the job is hanging or doing the wrong thing, call stop_job (same id) instead of looping forever.",
|
|
15995
16005
|
"Then report the result. Do not tell the user you will let them know later."
|
|
15996
16006
|
].join(" ");
|
|
@@ -15998,7 +16008,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
15998
16008
|
function formatDeferredDoneContinuePrompt() {
|
|
15999
16009
|
return [
|
|
16000
16010
|
"You ended the turn after promising to report later, but no detached job is running.",
|
|
16001
|
-
"If tests/pack/deploy still need to run: start once with detached-job.cjs,
|
|
16011
|
+
"If tests/pack/deploy still need to run: start once with detached-job.cjs, then loop wait_for_job until stillRunning is false (the log pane updates from wait JSON).",
|
|
16002
16012
|
"Do not say you will let the user know later."
|
|
16003
16013
|
].join(" ");
|
|
16004
16014
|
}
|
|
@@ -16033,6 +16043,10 @@ function tailProgress(logFile, maxLines = 12) {
|
|
|
16033
16043
|
const lines = (0, import_node_fs42.readFileSync)(logFile, "utf8").split("\n");
|
|
16034
16044
|
return lines.slice(-maxLines).join("\n");
|
|
16035
16045
|
}
|
|
16046
|
+
function lastProgressLine(progress) {
|
|
16047
|
+
const last = progress.split("\n").map((l) => l.trim()).filter((l) => l && l !== "(no log yet)").at(-1);
|
|
16048
|
+
return last ? last.slice(0, 72) : void 0;
|
|
16049
|
+
}
|
|
16036
16050
|
function readLogLines(file) {
|
|
16037
16051
|
if (!(0, import_node_fs42.existsSync)(file)) return [];
|
|
16038
16052
|
const lines = (0, import_node_fs42.readFileSync)(file, "utf8").split("\n");
|
|
@@ -16069,6 +16083,7 @@ function toResult(id, snap, extra) {
|
|
|
16069
16083
|
} catch {
|
|
16070
16084
|
}
|
|
16071
16085
|
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
16086
|
+
const progress = extra?.progress ?? snap.progress;
|
|
16072
16087
|
return {
|
|
16073
16088
|
stillRunning,
|
|
16074
16089
|
ok,
|
|
@@ -16077,8 +16092,9 @@ function toResult(id, snap, extra) {
|
|
|
16077
16092
|
id,
|
|
16078
16093
|
pid: snap.pid,
|
|
16079
16094
|
exitCode: snap.exitCode ?? void 0,
|
|
16095
|
+
phase: lastProgressLine(progress),
|
|
16080
16096
|
delta,
|
|
16081
|
-
progress
|
|
16097
|
+
progress,
|
|
16082
16098
|
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
16083
16099
|
};
|
|
16084
16100
|
}
|
|
@@ -16218,8 +16234,8 @@ var init_wait_for_job = __esm({
|
|
|
16218
16234
|
init_workspace_scratch();
|
|
16219
16235
|
init_wait_for_turn();
|
|
16220
16236
|
MAX_JOB_CONTINUES = 8;
|
|
16221
|
-
MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running.
|
|
16222
|
-
MCP_STOP_JOB_HINT = "Stopped.
|
|
16237
|
+
MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. The type=log pane already appended this delta. Call wait_for_job again. If it is hanging, producing no useful output, or doing the wrong thing, call stop_job (same id) instead of looping forever. Do not end the turn or tell the user you will let them know later.";
|
|
16238
|
+
MCP_STOP_JOB_HINT = "Stopped. The type=log pane is status=failed with the last delta. Do not wait again unless you start a new command.";
|
|
16223
16239
|
JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
16224
16240
|
}
|
|
16225
16241
|
});
|
|
@@ -19472,7 +19488,7 @@ Wait JSON:
|
|
|
19472
19488
|
|
|
19473
19489
|
## Sideboard UI (append-only log)
|
|
19474
19490
|
|
|
19475
|
-
The side column **is** the live view.
|
|
19491
|
+
The side column **is** the live view. \`wait_for_job\` / \`stop_job\` (and shell \`detached-job\` wait JSON) open a \`type=log\` pane automatically (\`artifact_id\` = job id, content = \`delta\`). You may still call \`present_artifact\` **\`type=log\`** for a custom title. Each update **appends** \u2014 send only \`delta\`, not the full log and not HTML.
|
|
19476
19492
|
|
|
19477
19493
|
\`\`\`
|
|
19478
19494
|
present_artifact
|
|
@@ -19484,7 +19500,7 @@ present_artifact
|
|
|
19484
19500
|
phase: <wait.phase>
|
|
19485
19501
|
\`\`\`
|
|
19486
19502
|
|
|
19487
|
-
After **start**,
|
|
19503
|
+
After **start**, the first \`wait_for_job\` opens the pane (\`status=running\`). Do **not** dump the log in chat. Do **not** also fence HTML.
|
|
19488
19504
|
|
|
19489
19505
|
Ad-hoc pid/log (legacy or another tool\u2019s files):
|
|
19490
19506
|
|
|
@@ -19495,8 +19511,8 @@ node <detached-job.cjs> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
19495
19511
|
## Agent loop
|
|
19496
19512
|
|
|
19497
19513
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
19498
|
-
2.
|
|
19499
|
-
3.
|
|
19514
|
+
2. Loop \`wait_for_job\` (or shell \`wait\`). The human should see **working** in the side column from the wait JSON \u2014 do not also dump the log in chat.
|
|
19515
|
+
3. After each slice, the same log pane appends \`delta\`. Optional: \`present_artifact\` the same id for a custom title.
|
|
19500
19516
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
19501
19517
|
5. **Stop** when the job is hanging, buffering forever, watching the wrong thing, or you already have the answer. MCP \`stop_job\` (same id, optional \`reason\`) or \`detached-job.cjs stop <id>\`. Do **not** stop a pack/test/deploy that is clearly making progress.
|
|
19502
19518
|
|
|
@@ -20024,7 +20040,7 @@ function formatLongRunningDirective(opts) {
|
|
|
20024
20040
|
"Long-running jobs (mandatory when a command may run more than ~30s \u2014 pack, test, deploy, `gh pr checks --watch`):",
|
|
20025
20041
|
"A Sideboard worktree turn SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted; `block_until_ms: 0` is not enough. Detach instead, and never ask the human to poll.",
|
|
20026
20042
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree; same tool as \`scripts/detached-job.cjs\` when the worktree has it). If JSON says already-running, do not start again.`,
|
|
20027
|
-
"-
|
|
20043
|
+
"- Loop Sideboard MCP `wait_for_job` (returns in ~45s). The desktop opens a `type=log` pane from wait/stop (and shell detached-job JSON) automatically \u2014 you may still `present_artifact` with `artifact_id=<id>` for a custom title. stillRunning \u2192 wait again. Shell fallback: the same helper with `wait <id>`.",
|
|
20028
20044
|
"- Hanging, no useful output, or the wrong thing \u2192 `stop_job` (or the helper with `stop <id>`). Do not stop a pack/test/deploy that is clearly making progress.",
|
|
20029
20045
|
"- Stay in the loop until stillRunning is false (or you stopped it). ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
|
|
20030
20046
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
@@ -20032,7 +20048,7 @@ function formatLongRunningDirective(opts) {
|
|
|
20032
20048
|
}
|
|
20033
20049
|
function formatLongRunningReminder(opts) {
|
|
20034
20050
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
20035
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait)
|
|
20051
|
+
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait). The log pane updates from wait JSON; present_artifact type=log is optional. stop_job if hanging or wrong. Do not say you will let the user know later \u2014 stay in the turn.`;
|
|
20036
20052
|
}
|
|
20037
20053
|
function formatArtifactDirective() {
|
|
20038
20054
|
return [
|
|
@@ -28128,7 +28144,7 @@ async function startMcpServer() {
|
|
|
28128
28144
|
);
|
|
28129
28145
|
server.tool(
|
|
28130
28146
|
"wait_for_job",
|
|
28131
|
-
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. stillRunning is the source of truth \u2014 if true,
|
|
28147
|
+
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. Sideboard opens a type=log pane from this result (artifact_id = job id, content = delta). stillRunning is the source of truth \u2014 if true, call wait_for_job again. If the job is hanging, producing no useful output, or doing the wrong thing, call stop_job instead of looping forever. Do not end the turn or tell the user you will let them know later. If false, ok/failed is the result.",
|
|
28132
28148
|
{
|
|
28133
28149
|
id: import_zod9.z.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
28134
28150
|
timeoutMs: import_zod9.z.number().optional()
|
|
@@ -28142,7 +28158,7 @@ async function startMcpServer() {
|
|
|
28142
28158
|
);
|
|
28143
28159
|
server.tool(
|
|
28144
28160
|
"stop_job",
|
|
28145
|
-
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress.
|
|
28161
|
+
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress. The type=log pane updates to status=failed with the last delta. Then decide the next step.",
|
|
28146
28162
|
{
|
|
28147
28163
|
id: import_zod9.z.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
28148
28164
|
reason: import_zod9.z.string().optional().describe("Why you are stopping (hanging, no progress, wrong output, already have the error)")
|
package/dist/index.js
CHANGED
|
@@ -238,7 +238,7 @@ import {
|
|
|
238
238
|
worktreeCleanupSettings,
|
|
239
239
|
wrapReviewSkillMarkdown,
|
|
240
240
|
writeWorktreeFile
|
|
241
|
-
} from "./chunk-
|
|
241
|
+
} from "./chunk-P56XKPWT.js";
|
|
242
242
|
import {
|
|
243
243
|
LEGACY_PLAN_FILE_REL,
|
|
244
244
|
PLAN_FILE_NAME,
|
|
@@ -344,7 +344,7 @@ import {
|
|
|
344
344
|
withEventParentId,
|
|
345
345
|
withEventsParentId,
|
|
346
346
|
writeInjectedMcpConfig
|
|
347
|
-
} from "./chunk-
|
|
347
|
+
} from "./chunk-6XOSOIDJ.js";
|
|
348
348
|
import {
|
|
349
349
|
CLOUD_COORDINATOR_BUSY_REPLY,
|
|
350
350
|
CLOUD_COORDINATOR_STOPPED_REPLY,
|
|
@@ -4912,7 +4912,7 @@ async function startMcpServer() {
|
|
|
4912
4912
|
);
|
|
4913
4913
|
server.tool(
|
|
4914
4914
|
"wait_for_job",
|
|
4915
|
-
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. stillRunning is the source of truth \u2014 if true,
|
|
4915
|
+
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. Sideboard opens a type=log pane from this result (artifact_id = job id, content = delta). stillRunning is the source of truth \u2014 if true, call wait_for_job again. If the job is hanging, producing no useful output, or doing the wrong thing, call stop_job instead of looping forever. Do not end the turn or tell the user you will let them know later. If false, ok/failed is the result.",
|
|
4916
4916
|
{
|
|
4917
4917
|
id: z9.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
4918
4918
|
timeoutMs: z9.number().optional()
|
|
@@ -4926,7 +4926,7 @@ async function startMcpServer() {
|
|
|
4926
4926
|
);
|
|
4927
4927
|
server.tool(
|
|
4928
4928
|
"stop_job",
|
|
4929
|
-
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress.
|
|
4929
|
+
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress. The type=log pane updates to status=failed with the last delta. Then decide the next step.",
|
|
4930
4930
|
{
|
|
4931
4931
|
id: z9.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
4932
4932
|
reason: z9.string().optional().describe("Why you are stopping (hanging, no progress, wrong output, already have the error)")
|
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -9021,10 +9021,15 @@ function asRecord(input) {
|
|
|
9021
9021
|
function str2(v) {
|
|
9022
9022
|
return typeof v === "string" && v.trim() ? v : void 0;
|
|
9023
9023
|
}
|
|
9024
|
+
function clipChatLine(value, max = CHAT_DETAIL_MAX) {
|
|
9025
|
+
const line = value.trim().split(/\r?\n/, 1)[0] ?? "";
|
|
9026
|
+
if (line.length <= max) return line;
|
|
9027
|
+
return `${line.slice(0, Math.max(1, max - 1))}\u2026`;
|
|
9028
|
+
}
|
|
9024
9029
|
function toolDetail(name, input) {
|
|
9025
9030
|
if (!input) return void 0;
|
|
9026
9031
|
const command = str2(input.command) ?? str2(input.cmd);
|
|
9027
|
-
if (command) return command;
|
|
9032
|
+
if (command) return clipChatLine(command);
|
|
9028
9033
|
const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
|
|
9029
9034
|
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
9030
9035
|
if (isSearch && pattern) {
|
|
@@ -9461,10 +9466,12 @@ function normalizeParseResult(parsed) {
|
|
|
9461
9466
|
if (!parsed) return [];
|
|
9462
9467
|
return Array.isArray(parsed) ? parsed : [parsed];
|
|
9463
9468
|
}
|
|
9469
|
+
var CHAT_DETAIL_MAX;
|
|
9464
9470
|
var init_message_parts = __esm({
|
|
9465
9471
|
"src/agents/message-parts.ts"() {
|
|
9466
9472
|
"use strict";
|
|
9467
9473
|
init_error_detail();
|
|
9474
|
+
CHAT_DETAIL_MAX = 72;
|
|
9468
9475
|
}
|
|
9469
9476
|
});
|
|
9470
9477
|
|
|
@@ -14340,7 +14347,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
14340
14347
|
const ids = jobIds.join(", ");
|
|
14341
14348
|
return [
|
|
14342
14349
|
`Detached job still running: ${ids}.`,
|
|
14343
|
-
"Do not end this turn. Loop wait_for_job (same id)
|
|
14350
|
+
"Do not end this turn. Loop wait_for_job (same id) until stillRunning is false. The log pane updates from each wait result.",
|
|
14344
14351
|
"If the job is hanging or doing the wrong thing, call stop_job (same id) instead of looping forever.",
|
|
14345
14352
|
"Then report the result. Do not tell the user you will let them know later."
|
|
14346
14353
|
].join(" ");
|
|
@@ -14348,7 +14355,7 @@ function formatJobStillRunningContinuePrompt(jobIds) {
|
|
|
14348
14355
|
function formatDeferredDoneContinuePrompt() {
|
|
14349
14356
|
return [
|
|
14350
14357
|
"You ended the turn after promising to report later, but no detached job is running.",
|
|
14351
|
-
"If tests/pack/deploy still need to run: start once with detached-job.cjs,
|
|
14358
|
+
"If tests/pack/deploy still need to run: start once with detached-job.cjs, then loop wait_for_job until stillRunning is false (the log pane updates from wait JSON).",
|
|
14352
14359
|
"Do not say you will let the user know later."
|
|
14353
14360
|
].join(" ");
|
|
14354
14361
|
}
|
|
@@ -14383,6 +14390,10 @@ function tailProgress(logFile, maxLines = 12) {
|
|
|
14383
14390
|
const lines = (0, import_node_fs40.readFileSync)(logFile, "utf8").split("\n");
|
|
14384
14391
|
return lines.slice(-maxLines).join("\n");
|
|
14385
14392
|
}
|
|
14393
|
+
function lastProgressLine(progress) {
|
|
14394
|
+
const last = progress.split("\n").map((l) => l.trim()).filter((l) => l && l !== "(no log yet)").at(-1);
|
|
14395
|
+
return last ? last.slice(0, 72) : void 0;
|
|
14396
|
+
}
|
|
14386
14397
|
function readLogLines(file) {
|
|
14387
14398
|
if (!(0, import_node_fs40.existsSync)(file)) return [];
|
|
14388
14399
|
const lines = (0, import_node_fs40.readFileSync)(file, "utf8").split("\n");
|
|
@@ -14419,6 +14430,7 @@ function toResult(id, snap, extra) {
|
|
|
14419
14430
|
} catch {
|
|
14420
14431
|
}
|
|
14421
14432
|
const status = ok ? "ok" : failed && !stillRunning ? "failed" : stillRunning ? "running" : "idle";
|
|
14433
|
+
const progress = extra?.progress ?? snap.progress;
|
|
14422
14434
|
return {
|
|
14423
14435
|
stillRunning,
|
|
14424
14436
|
ok,
|
|
@@ -14427,8 +14439,9 @@ function toResult(id, snap, extra) {
|
|
|
14427
14439
|
id,
|
|
14428
14440
|
pid: snap.pid,
|
|
14429
14441
|
exitCode: snap.exitCode ?? void 0,
|
|
14442
|
+
phase: lastProgressLine(progress),
|
|
14430
14443
|
delta,
|
|
14431
|
-
progress
|
|
14444
|
+
progress,
|
|
14432
14445
|
hint: stillRunning ? MCP_WAIT_JOB_STILL_RUNNING_HINT : void 0
|
|
14433
14446
|
};
|
|
14434
14447
|
}
|
|
@@ -14568,8 +14581,8 @@ var init_wait_for_job = __esm({
|
|
|
14568
14581
|
init_workspace_scratch();
|
|
14569
14582
|
init_wait_for_turn();
|
|
14570
14583
|
MAX_JOB_CONTINUES = 8;
|
|
14571
|
-
MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running.
|
|
14572
|
-
MCP_STOP_JOB_HINT = "Stopped.
|
|
14584
|
+
MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. The type=log pane already appended this delta. Call wait_for_job again. If it is hanging, producing no useful output, or doing the wrong thing, call stop_job (same id) instead of looping forever. Do not end the turn or tell the user you will let them know later.";
|
|
14585
|
+
MCP_STOP_JOB_HINT = "Stopped. The type=log pane is status=failed with the last delta. Do not wait again unless you start a new command.";
|
|
14573
14586
|
JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
|
|
14574
14587
|
}
|
|
14575
14588
|
});
|
|
@@ -17755,7 +17768,7 @@ Wait JSON:
|
|
|
17755
17768
|
|
|
17756
17769
|
## Sideboard UI (append-only log)
|
|
17757
17770
|
|
|
17758
|
-
The side column **is** the live view.
|
|
17771
|
+
The side column **is** the live view. \`wait_for_job\` / \`stop_job\` (and shell \`detached-job\` wait JSON) open a \`type=log\` pane automatically (\`artifact_id\` = job id, content = \`delta\`). You may still call \`present_artifact\` **\`type=log\`** for a custom title. Each update **appends** \u2014 send only \`delta\`, not the full log and not HTML.
|
|
17759
17772
|
|
|
17760
17773
|
\`\`\`
|
|
17761
17774
|
present_artifact
|
|
@@ -17767,7 +17780,7 @@ present_artifact
|
|
|
17767
17780
|
phase: <wait.phase>
|
|
17768
17781
|
\`\`\`
|
|
17769
17782
|
|
|
17770
|
-
After **start**,
|
|
17783
|
+
After **start**, the first \`wait_for_job\` opens the pane (\`status=running\`). Do **not** dump the log in chat. Do **not** also fence HTML.
|
|
17771
17784
|
|
|
17772
17785
|
Ad-hoc pid/log (legacy or another tool\u2019s files):
|
|
17773
17786
|
|
|
@@ -17778,8 +17791,8 @@ node <detached-job.cjs> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
17778
17791
|
## Agent loop
|
|
17779
17792
|
|
|
17780
17793
|
1. \`start\` once. If JSON says \`already-running\`, do not start again.
|
|
17781
|
-
2.
|
|
17782
|
-
3.
|
|
17794
|
+
2. Loop \`wait_for_job\` (or shell \`wait\`). The human should see **working** in the side column from the wait JSON \u2014 do not also dump the log in chat.
|
|
17795
|
+
3. After each slice, the same log pane appends \`delta\`. Optional: \`present_artifact\` the same id for a custom title.
|
|
17783
17796
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
17784
17797
|
5. **Stop** when the job is hanging, buffering forever, watching the wrong thing, or you already have the answer. MCP \`stop_job\` (same id, optional \`reason\`) or \`detached-job.cjs stop <id>\`. Do **not** stop a pack/test/deploy that is clearly making progress.
|
|
17785
17798
|
|
|
@@ -18285,7 +18298,7 @@ function formatLongRunningDirective(opts) {
|
|
|
18285
18298
|
"Long-running jobs (mandatory when a command may run more than ~30s \u2014 pack, test, deploy, `gh pr checks --watch`):",
|
|
18286
18299
|
"A Sideboard worktree turn SIGTERMs the agent shell (and its process group) when the user sends another message or the turn is interrupted; `block_until_ms: 0` is not enough. Detach instead, and never ask the human to poll.",
|
|
18287
18300
|
`- Start once: \`${invoke} start <id> -- <command> [args...]\` (cwd = this worktree; same tool as \`scripts/detached-job.cjs\` when the worktree has it). If JSON says already-running, do not start again.`,
|
|
18288
|
-
"-
|
|
18301
|
+
"- Loop Sideboard MCP `wait_for_job` (returns in ~45s). The desktop opens a `type=log` pane from wait/stop (and shell detached-job JSON) automatically \u2014 you may still `present_artifact` with `artifact_id=<id>` for a custom title. stillRunning \u2192 wait again. Shell fallback: the same helper with `wait <id>`.",
|
|
18289
18302
|
"- Hanging, no useful output, or the wrong thing \u2192 `stop_job` (or the helper with `stop <id>`). Do not stop a pack/test/deploy that is clearly making progress.",
|
|
18290
18303
|
"- Stay in the loop until stillRunning is false (or you stopped it). ok \u2192 finish the task. failed / stopped \u2192 read the log, fix or narrow the command, start once.",
|
|
18291
18304
|
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
@@ -18293,7 +18306,7 @@ function formatLongRunningDirective(opts) {
|
|
|
18293
18306
|
}
|
|
18294
18307
|
function formatLongRunningReminder(opts) {
|
|
18295
18308
|
const invoke = formatDetachedJobInvoke(opts?.scriptPath);
|
|
18296
|
-
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait)
|
|
18309
|
+
return `Long jobs: \`${invoke} start <id> -- <cmd>\`, loop wait_for_job (or detached-job wait). The log pane updates from wait JSON; present_artifact type=log is optional. stop_job if hanging or wrong. Do not say you will let the user know later \u2014 stay in the turn.`;
|
|
18297
18310
|
}
|
|
18298
18311
|
function formatArtifactDirective() {
|
|
18299
18312
|
return [
|
|
@@ -25196,7 +25209,7 @@ async function startMcpServer() {
|
|
|
25196
25209
|
);
|
|
25197
25210
|
server.tool(
|
|
25198
25211
|
"wait_for_job",
|
|
25199
|
-
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. stillRunning is the source of truth \u2014 if true,
|
|
25212
|
+
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. Sideboard opens a type=log pane from this result (artifact_id = job id, content = delta). stillRunning is the source of truth \u2014 if true, call wait_for_job again. If the job is hanging, producing no useful output, or doing the wrong thing, call stop_job instead of looping forever. Do not end the turn or tell the user you will let them know later. If false, ok/failed is the result.",
|
|
25200
25213
|
{
|
|
25201
25214
|
id: import_zod9.z.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
25202
25215
|
timeoutMs: import_zod9.z.number().optional()
|
|
@@ -25210,7 +25223,7 @@ async function startMcpServer() {
|
|
|
25210
25223
|
);
|
|
25211
25224
|
server.tool(
|
|
25212
25225
|
"stop_job",
|
|
25213
|
-
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress.
|
|
25226
|
+
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress. The type=log pane updates to status=failed with the last delta. Then decide the next step.",
|
|
25214
25227
|
{
|
|
25215
25228
|
id: import_zod9.z.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
25216
25229
|
reason: import_zod9.z.string().optional().describe("Why you are stopping (hanging, no progress, wrong output, already have the error)")
|
package/dist/mcp/run-stdio.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
syncBoardPins,
|
|
38
38
|
updateSchedule,
|
|
39
39
|
waitForDetachedJob
|
|
40
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-S6HYHXFO.js";
|
|
41
41
|
import {
|
|
42
42
|
applySystemCaEnv,
|
|
43
43
|
isCursorApiKeyConfigured,
|
|
@@ -46,7 +46,7 @@ import {
|
|
|
46
46
|
materializeSystemCaBundle,
|
|
47
47
|
sideboardMcpProfile,
|
|
48
48
|
trustSystemCertificates
|
|
49
|
-
} from "../chunk-
|
|
49
|
+
} from "../chunk-7DBYKEYF.js";
|
|
50
50
|
import "../chunk-HVIEYTUK.js";
|
|
51
51
|
import "../chunk-Y4MIXGPA.js";
|
|
52
52
|
import {
|
|
@@ -3695,7 +3695,7 @@ async function startMcpServer() {
|
|
|
3695
3695
|
);
|
|
3696
3696
|
server.tool(
|
|
3697
3697
|
"wait_for_job",
|
|
3698
|
-
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. stillRunning is the source of truth \u2014 if true,
|
|
3698
|
+
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. Sideboard opens a type=log pane from this result (artifact_id = job id, content = delta). stillRunning is the source of truth \u2014 if true, call wait_for_job again. If the job is hanging, producing no useful output, or doing the wrong thing, call stop_job instead of looping forever. Do not end the turn or tell the user you will let them know later. If false, ok/failed is the result.",
|
|
3699
3699
|
{
|
|
3700
3700
|
id: z9.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
3701
3701
|
timeoutMs: z9.number().optional()
|
|
@@ -3709,7 +3709,7 @@ async function startMcpServer() {
|
|
|
3709
3709
|
);
|
|
3710
3710
|
server.tool(
|
|
3711
3711
|
"stop_job",
|
|
3712
|
-
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress.
|
|
3712
|
+
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress. The type=log pane updates to status=failed with the last delta. Then decide the next step.",
|
|
3713
3713
|
{
|
|
3714
3714
|
id: z9.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
3715
3715
|
reason: z9.string().optional().describe("Why you are stopping (hanging, no progress, wrong output, already have the error)")
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
resolveSendFollowUp,
|
|
7
7
|
startOrchestration,
|
|
8
8
|
waitForPidExit
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-P56XKPWT.js";
|
|
10
10
|
import "./chunk-DJU54RYW.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-6XOSOIDJ.js";
|
|
12
12
|
import "./chunk-VIODP5PT.js";
|
|
13
13
|
import "./chunk-WXKXSZN4.js";
|
|
14
14
|
import "./chunk-6K64FJDD.js";
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
resolveSendFollowUp,
|
|
9
9
|
startOrchestration,
|
|
10
10
|
waitForPidExit
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-S6HYHXFO.js";
|
|
12
|
+
import "./chunk-7DBYKEYF.js";
|
|
13
13
|
import "./chunk-HVIEYTUK.js";
|
|
14
14
|
import "./chunk-Y4MIXGPA.js";
|
|
15
15
|
import "./chunk-VKQGAWHY.js";
|