@wrongstack/cli 0.10.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +209 -22
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -3007,8 +3007,12 @@ function buildFleetCommand(opts) {
|
|
|
3007
3007
|
}
|
|
3008
3008
|
if (cmd === "kill" || cmd === "stop-all") {
|
|
3009
3009
|
const targetId = subargs[0];
|
|
3010
|
-
if (
|
|
3011
|
-
|
|
3010
|
+
if (targetId) {
|
|
3011
|
+
if (opts.onFleet) {
|
|
3012
|
+
const msg4 = await opts.onFleet("kill", targetId);
|
|
3013
|
+
return { message: msg4 };
|
|
3014
|
+
}
|
|
3015
|
+
const msg3 = `${color.amber("\u26A0 /fleet kill is not wired in this session.")}`;
|
|
3012
3016
|
opts.renderer.writeWarning(msg3);
|
|
3013
3017
|
return { message: msg3 };
|
|
3014
3018
|
}
|
|
@@ -3018,10 +3022,6 @@ function buildFleetCommand(opts) {
|
|
|
3018
3022
|
opts.renderer.write(msg3);
|
|
3019
3023
|
return { message: msg3 };
|
|
3020
3024
|
}
|
|
3021
|
-
if (opts.onFleet) {
|
|
3022
|
-
const msg3 = await opts.onFleet("kill", targetId);
|
|
3023
|
-
return { message: msg3 };
|
|
3024
|
-
}
|
|
3025
3025
|
const msg2 = `${color.amber("\u26A0 /fleet kill is not wired in this session.")}`;
|
|
3026
3026
|
opts.renderer.writeWarning(msg2);
|
|
3027
3027
|
return { message: msg2 };
|
|
@@ -4127,6 +4127,55 @@ function buildBtwCommand(opts) {
|
|
|
4127
4127
|
}
|
|
4128
4128
|
};
|
|
4129
4129
|
}
|
|
4130
|
+
function buildNextCommand(opts) {
|
|
4131
|
+
return {
|
|
4132
|
+
name: "next",
|
|
4133
|
+
description: "Toggle next-task prediction \u2014 show likely next steps after each turn.",
|
|
4134
|
+
argsHint: "[on|off|toggle]",
|
|
4135
|
+
help: [
|
|
4136
|
+
"Usage:",
|
|
4137
|
+
" /next Show whether next-task prediction is on or off",
|
|
4138
|
+
" /next on Enable \u2014 after each turn, show 1-3 predicted next steps",
|
|
4139
|
+
" /next off Disable (default)",
|
|
4140
|
+
" /next toggle Flip the current state",
|
|
4141
|
+
"",
|
|
4142
|
+
"Predictions are informational only. They come from a cheap single-shot",
|
|
4143
|
+
"model call (no tools, no context replay) and are never run automatically \u2014",
|
|
4144
|
+
"copy or retype one to act on it. The setting persists across sessions."
|
|
4145
|
+
].join("\n"),
|
|
4146
|
+
async run(args) {
|
|
4147
|
+
if (!opts.onNextPredict) {
|
|
4148
|
+
const msg2 = "Next-task prediction is not available in this session.";
|
|
4149
|
+
opts.renderer.writeWarning(msg2);
|
|
4150
|
+
return { message: msg2 };
|
|
4151
|
+
}
|
|
4152
|
+
const arg = args.trim().toLowerCase();
|
|
4153
|
+
const current = opts.onNextPredict();
|
|
4154
|
+
const label = (on) => on ? `${color.cyan("ON")} ${color.dim("(predicted next steps shown after each turn)")}` : `${color.green("OFF")} ${color.dim("(no predictions)")}`;
|
|
4155
|
+
if (!arg || arg === "status") {
|
|
4156
|
+
const msg2 = `Next-task prediction: ${label(current)}`;
|
|
4157
|
+
opts.renderer.write(msg2);
|
|
4158
|
+
return { message: msg2 };
|
|
4159
|
+
}
|
|
4160
|
+
let target;
|
|
4161
|
+
if (arg === "on" || arg === "enable" || arg === "true") {
|
|
4162
|
+
target = true;
|
|
4163
|
+
} else if (arg === "off" || arg === "disable" || arg === "false") {
|
|
4164
|
+
target = false;
|
|
4165
|
+
} else if (arg === "toggle" || arg === "cycle") {
|
|
4166
|
+
target = !current;
|
|
4167
|
+
} else {
|
|
4168
|
+
const msg2 = `Unknown argument: ${arg}. Use /next on, off, or toggle.`;
|
|
4169
|
+
opts.renderer.writeWarning(msg2);
|
|
4170
|
+
return { message: msg2 };
|
|
4171
|
+
}
|
|
4172
|
+
const now = opts.onNextPredict(target);
|
|
4173
|
+
const msg = `Next-task prediction: ${label(now)}`;
|
|
4174
|
+
opts.renderer.write(msg);
|
|
4175
|
+
return { message: msg };
|
|
4176
|
+
}
|
|
4177
|
+
};
|
|
4178
|
+
}
|
|
4130
4179
|
var KNOWN_VERBS = /* @__PURE__ */ new Set([
|
|
4131
4180
|
"",
|
|
4132
4181
|
"show",
|
|
@@ -5876,6 +5925,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
5876
5925
|
buildAutonomyCommand(opts),
|
|
5877
5926
|
buildGoalCommand(opts),
|
|
5878
5927
|
buildBtwCommand(opts),
|
|
5928
|
+
buildNextCommand(opts),
|
|
5879
5929
|
buildModeCommand(opts),
|
|
5880
5930
|
buildExitCommand(opts),
|
|
5881
5931
|
buildFixCommand(opts),
|
|
@@ -9708,22 +9758,22 @@ function fmtDuration(ms) {
|
|
|
9708
9758
|
const remMin = m - h * 60;
|
|
9709
9759
|
return `${h}h${remMin}m`;
|
|
9710
9760
|
}
|
|
9711
|
-
function fmtTaskResultLine(r,
|
|
9761
|
+
function fmtTaskResultLine(r, color42) {
|
|
9712
9762
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
9713
9763
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
9714
9764
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
9715
9765
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
9716
|
-
const errKindChip = errKind ?
|
|
9717
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
9766
|
+
const errKindChip = errKind ? color42.dim(` [${errKind}]`) : "";
|
|
9767
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color42.dim(errTail)}` : "";
|
|
9718
9768
|
switch (r.status) {
|
|
9719
9769
|
case "success":
|
|
9720
|
-
return { mark:
|
|
9770
|
+
return { mark: color42.green("\u2713"), stats, tail: "" };
|
|
9721
9771
|
case "timeout":
|
|
9722
|
-
return { mark:
|
|
9772
|
+
return { mark: color42.yellow("\u23F1"), stats: `${color42.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
9723
9773
|
case "stopped":
|
|
9724
|
-
return { mark:
|
|
9774
|
+
return { mark: color42.dim("\u2298"), stats: `${color42.dim("stopped")} ${stats}`, tail: errSnip };
|
|
9725
9775
|
case "failed":
|
|
9726
|
-
return { mark:
|
|
9776
|
+
return { mark: color42.red("\u2717"), stats: `${color42.red("failed")} ${stats}`, tail: errSnip };
|
|
9727
9777
|
}
|
|
9728
9778
|
}
|
|
9729
9779
|
|
|
@@ -10140,7 +10190,88 @@ var FleetStatusLine = class {
|
|
|
10140
10190
|
}
|
|
10141
10191
|
};
|
|
10142
10192
|
|
|
10143
|
-
// src/
|
|
10193
|
+
// src/next-task-predictor.ts
|
|
10194
|
+
var SYSTEM_PROMPT = `You predict the developer's most likely NEXT actions in a coding session. Given what they just asked and what the assistant just did, output the 1-3 most probable next steps. Each must be a concrete, actionable task phrased as an imperative the user could hand back to the assistant (e.g. "Add tests for the new parser", "Wire the command into the CLI"). Output ONLY a numbered list, one step per line, no preamble, no explanation. Prefer steps that follow naturally from unfinished todos or obvious gaps. If there is genuinely nothing meaningful left to do, output exactly: NONE`;
|
|
10195
|
+
var MAX_REQUEST_CHARS = 1200;
|
|
10196
|
+
var MAX_SUMMARY_CHARS = 1200;
|
|
10197
|
+
function clamp(text, n) {
|
|
10198
|
+
const t = text.trim();
|
|
10199
|
+
return t.length <= n ? t : `${t.slice(0, n)}\u2026`;
|
|
10200
|
+
}
|
|
10201
|
+
function buildPredictionPrompt(input) {
|
|
10202
|
+
const parts = [];
|
|
10203
|
+
parts.push(`The user asked:
|
|
10204
|
+
${clamp(input.userRequest, MAX_REQUEST_CHARS) || "(no text)"}`);
|
|
10205
|
+
if (input.assistantSummary.trim()) {
|
|
10206
|
+
parts.push(
|
|
10207
|
+
`The assistant just finished and reported:
|
|
10208
|
+
${clamp(input.assistantSummary, MAX_SUMMARY_CHARS)}`
|
|
10209
|
+
);
|
|
10210
|
+
}
|
|
10211
|
+
const pending = input.todos.filter((t) => t.status !== "completed");
|
|
10212
|
+
if (pending.length > 0) {
|
|
10213
|
+
const list = pending.slice(0, 8).map((t) => `- [${t.status}] ${t.content}`).join("\n");
|
|
10214
|
+
parts.push(`Open todo items:
|
|
10215
|
+
${list}`);
|
|
10216
|
+
}
|
|
10217
|
+
parts.push("Predict the 1-3 most likely next steps.");
|
|
10218
|
+
return parts.join("\n\n");
|
|
10219
|
+
}
|
|
10220
|
+
function parsePredictions(raw, max = 3) {
|
|
10221
|
+
const text = raw.trim();
|
|
10222
|
+
if (!text) return [];
|
|
10223
|
+
if (/^none\b/i.test(text) || /no further steps/i.test(text)) return [];
|
|
10224
|
+
const out = [];
|
|
10225
|
+
for (const lineRaw of text.split("\n")) {
|
|
10226
|
+
const line = lineRaw.trim();
|
|
10227
|
+
if (!line) continue;
|
|
10228
|
+
const stripped = line.replace(/^\s*(?:\d+[.)]|[-*•])\s+/, "").trim();
|
|
10229
|
+
const candidate = stripped || line;
|
|
10230
|
+
if (/^none$/i.test(candidate)) continue;
|
|
10231
|
+
if (candidate) out.push(candidate);
|
|
10232
|
+
if (out.length >= max) break;
|
|
10233
|
+
}
|
|
10234
|
+
return out;
|
|
10235
|
+
}
|
|
10236
|
+
function extractText(content) {
|
|
10237
|
+
if (Array.isArray(content)) {
|
|
10238
|
+
return content[0]?.text ?? "";
|
|
10239
|
+
}
|
|
10240
|
+
if (content && typeof content === "object") {
|
|
10241
|
+
return content.text ?? "";
|
|
10242
|
+
}
|
|
10243
|
+
return typeof content === "string" ? content : "";
|
|
10244
|
+
}
|
|
10245
|
+
async function predictNextTasks(input, opts) {
|
|
10246
|
+
const max = opts.maxPredictions ?? 3;
|
|
10247
|
+
const internal = new AbortController();
|
|
10248
|
+
const timeout = setTimeout(() => internal.abort(), 12e3);
|
|
10249
|
+
const onParentAbort = () => internal.abort();
|
|
10250
|
+
if (opts.signal) {
|
|
10251
|
+
if (opts.signal.aborted) internal.abort();
|
|
10252
|
+
else opts.signal.addEventListener("abort", onParentAbort, { once: true });
|
|
10253
|
+
}
|
|
10254
|
+
try {
|
|
10255
|
+
const resp = await opts.provider.complete(
|
|
10256
|
+
{
|
|
10257
|
+
model: opts.model,
|
|
10258
|
+
system: [{ type: "text", text: SYSTEM_PROMPT }],
|
|
10259
|
+
messages: [
|
|
10260
|
+
{ role: "user", content: [{ type: "text", text: buildPredictionPrompt(input) }] }
|
|
10261
|
+
],
|
|
10262
|
+
maxTokens: 160,
|
|
10263
|
+
temperature: 0.3
|
|
10264
|
+
},
|
|
10265
|
+
{ signal: internal.signal }
|
|
10266
|
+
);
|
|
10267
|
+
return parsePredictions(extractText(resp.content), max);
|
|
10268
|
+
} catch {
|
|
10269
|
+
return [];
|
|
10270
|
+
} finally {
|
|
10271
|
+
clearTimeout(timeout);
|
|
10272
|
+
if (opts.signal) opts.signal.removeEventListener("abort", onParentAbort);
|
|
10273
|
+
}
|
|
10274
|
+
}
|
|
10144
10275
|
init_sdd();
|
|
10145
10276
|
async function runRepl(opts) {
|
|
10146
10277
|
if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
|
|
@@ -10549,6 +10680,37 @@ ${suggestResult.finalText}
|
|
|
10549
10680
|
}
|
|
10550
10681
|
}
|
|
10551
10682
|
}
|
|
10683
|
+
if (result.status === "done" && opts.getNextPredict?.()) {
|
|
10684
|
+
const autonomy = opts.getAutonomy?.() ?? "off";
|
|
10685
|
+
if (autonomy === "off") {
|
|
10686
|
+
const predictCtrl = new AbortController();
|
|
10687
|
+
activeCtrl = predictCtrl;
|
|
10688
|
+
try {
|
|
10689
|
+
const predictions = await predictNextTasks(
|
|
10690
|
+
{
|
|
10691
|
+
userRequest: trimmed,
|
|
10692
|
+
assistantSummary: result.finalText ?? "",
|
|
10693
|
+
todos: opts.agent.ctx.todos
|
|
10694
|
+
},
|
|
10695
|
+
{
|
|
10696
|
+
provider: opts.agent.ctx.provider,
|
|
10697
|
+
model: opts.agent.ctx.model,
|
|
10698
|
+
signal: predictCtrl.signal
|
|
10699
|
+
}
|
|
10700
|
+
);
|
|
10701
|
+
if (predictions.length > 0) {
|
|
10702
|
+
const lines = predictions.map((p, i) => ` ${i + 1}. ${p}`).join("\n");
|
|
10703
|
+
opts.renderer.write(`
|
|
10704
|
+
${color.dim(" \u21B3 likely next:")}
|
|
10705
|
+
${color.dim(lines)}
|
|
10706
|
+
`);
|
|
10707
|
+
}
|
|
10708
|
+
} catch {
|
|
10709
|
+
} finally {
|
|
10710
|
+
activeCtrl = void 0;
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10713
|
+
}
|
|
10552
10714
|
} catch (err) {
|
|
10553
10715
|
opts.renderer.writeError(err instanceof Error ? err.message : String(err));
|
|
10554
10716
|
} finally {
|
|
@@ -10731,6 +10893,7 @@ async function execute(deps) {
|
|
|
10731
10893
|
getYolo,
|
|
10732
10894
|
getAutonomy,
|
|
10733
10895
|
onAutonomy,
|
|
10896
|
+
getNextPredict,
|
|
10734
10897
|
getEternalEngine,
|
|
10735
10898
|
getParallelEngine,
|
|
10736
10899
|
subscribeEternalIteration,
|
|
@@ -10888,6 +11051,20 @@ async function execute(deps) {
|
|
|
10888
11051
|
yolo: !!config.yolo,
|
|
10889
11052
|
getYolo,
|
|
10890
11053
|
getAutonomy,
|
|
11054
|
+
// Next-task prediction (/next). Host owns the gating: returns [] when
|
|
11055
|
+
// the toggle is off or autonomy is self-driving, so the TUI can call
|
|
11056
|
+
// this unconditionally after a done turn. Display-only.
|
|
11057
|
+
predictNext: async (input) => {
|
|
11058
|
+
if (!getNextPredict?.()) return [];
|
|
11059
|
+
if ((getAutonomy?.() ?? "off") !== "off") return [];
|
|
11060
|
+
return predictNextTasks(
|
|
11061
|
+
{ ...input, todos: context.todos },
|
|
11062
|
+
{
|
|
11063
|
+
provider: context.provider,
|
|
11064
|
+
model: context.model
|
|
11065
|
+
}
|
|
11066
|
+
);
|
|
11067
|
+
},
|
|
10891
11068
|
getEternalEngine,
|
|
10892
11069
|
subscribeEternalIteration,
|
|
10893
11070
|
subscribeEternalStage,
|
|
@@ -10932,13 +11109,11 @@ async function execute(deps) {
|
|
|
10932
11109
|
// resize/overlay-leak artifacts can opt back into alt-screen with
|
|
10933
11110
|
// `--alt-screen`. `--no-alt-screen` still wins when both are passed.
|
|
10934
11111
|
altScreen: flags["alt-screen"] === true && flags["no-alt-screen"] !== true,
|
|
10935
|
-
//
|
|
10936
|
-
//
|
|
10937
|
-
//
|
|
10938
|
-
//
|
|
10939
|
-
|
|
10940
|
-
// native scroll/copy until `/mouse off`.
|
|
10941
|
-
mouse: flags.mouse === true,
|
|
11112
|
+
// Mouse mode is DISABLED. It was unreliable on Windows consoles
|
|
11113
|
+
// (freezes / constant repaint in the managed viewport) and is not
|
|
11114
|
+
// wanted, so `--mouse` is intentionally ignored and never engages —
|
|
11115
|
+
// the TUI stays keyboard-only. Do not re-wire `flags.mouse` here.
|
|
11116
|
+
mouse: false,
|
|
10942
11117
|
director,
|
|
10943
11118
|
fleetRoster,
|
|
10944
11119
|
onAfterExit: () => {
|
|
@@ -11016,6 +11191,7 @@ async function execute(deps) {
|
|
|
11016
11191
|
projectRoot,
|
|
11017
11192
|
getAutonomy,
|
|
11018
11193
|
onAutonomy,
|
|
11194
|
+
getNextPredict,
|
|
11019
11195
|
getEternalEngine,
|
|
11020
11196
|
getParallelEngine,
|
|
11021
11197
|
skillLoader,
|
|
@@ -11039,6 +11215,7 @@ async function execute(deps) {
|
|
|
11039
11215
|
projectName: path24.basename(projectRoot) || void 0,
|
|
11040
11216
|
getAutonomy,
|
|
11041
11217
|
onAutonomy,
|
|
11218
|
+
getNextPredict,
|
|
11042
11219
|
getEternalEngine,
|
|
11043
11220
|
getParallelEngine,
|
|
11044
11221
|
skillLoader,
|
|
@@ -13017,6 +13194,7 @@ async function main(argv) {
|
|
|
13017
13194
|
return "off";
|
|
13018
13195
|
})();
|
|
13019
13196
|
autonomyModeRef.current = autonomyMode;
|
|
13197
|
+
let nextPredictEnabled = config.nextPrediction === true;
|
|
13020
13198
|
let eternalEngine = null;
|
|
13021
13199
|
let parallelEngine = null;
|
|
13022
13200
|
const eternalListeners = /* @__PURE__ */ new Set();
|
|
@@ -13341,7 +13519,7 @@ async function main(argv) {
|
|
|
13341
13519
|
for (const sa of s.subagents) {
|
|
13342
13520
|
if (sa.status === "running" || sa.status === "idle") {
|
|
13343
13521
|
try {
|
|
13344
|
-
director.
|
|
13522
|
+
director.remove(sa.id);
|
|
13345
13523
|
killed++;
|
|
13346
13524
|
} catch {
|
|
13347
13525
|
}
|
|
@@ -13608,6 +13786,14 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
13608
13786
|
}
|
|
13609
13787
|
return policy.getYolo();
|
|
13610
13788
|
},
|
|
13789
|
+
onNextPredict: (setTo) => {
|
|
13790
|
+
if (setTo !== void 0) {
|
|
13791
|
+
nextPredictEnabled = setTo;
|
|
13792
|
+
config = patchConfig(config, { nextPrediction: setTo });
|
|
13793
|
+
return setTo;
|
|
13794
|
+
}
|
|
13795
|
+
return nextPredictEnabled;
|
|
13796
|
+
},
|
|
13611
13797
|
onAutonomy: (setTo) => {
|
|
13612
13798
|
if (setTo !== void 0) {
|
|
13613
13799
|
autonomyMode = setTo;
|
|
@@ -13838,6 +14024,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
13838
14024
|
}
|
|
13839
14025
|
return autonomyMode;
|
|
13840
14026
|
},
|
|
14027
|
+
getNextPredict: () => nextPredictEnabled,
|
|
13841
14028
|
getEternalEngine: () => eternalEngine,
|
|
13842
14029
|
getParallelEngine: () => parallelEngine,
|
|
13843
14030
|
subscribeEternalIteration: (fn) => {
|