@wrongstack/cli 0.300.0 → 0.302.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/{acp-IDNS2YVE.js → acp-DATHHPNT.js} +34 -15
- package/dist/acp-server-agent.d.ts +1 -1
- package/dist/{audit-2ZSFGNIF.js → audit-QRCLEHHW.js} +5 -1
- package/dist/{auth-6T6ZOT2R.js → auth-PJD3JRH2.js} +150 -37
- package/dist/boot/dispatch-webui.d.ts +3 -16
- package/dist/boot/launch-menu.d.ts +2 -4
- package/dist/boot/tool-registry.d.ts +3 -0
- package/dist/boot/webui-session-child.d.ts +91 -0
- package/dist/chimera-reviewer-policy.d.ts +10 -3
- package/dist/chimera-work-registry.d.ts +19 -0
- package/dist/{chronicle-QQEQFSSE.js → chronicle-63MFCZN6.js} +26 -5
- package/dist/{chunk-YWUPHRGB.js → chunk-263G3FMB.js} +33 -10
- package/dist/{chunk-GYDQABMA.js → chunk-2KDOFTTM.js} +44 -32
- package/dist/{chunk-V76R7DC5.js → chunk-3MOUBRKZ.js} +311 -309
- package/dist/chunk-CSAPOCBP.js +24 -0
- package/dist/{chunk-N7ULWBO5.js → chunk-ETOEGL3V.js} +3 -7
- package/dist/{chunk-3MWUZMOL.js → chunk-GUHQQG63.js} +14 -3
- package/dist/chunk-KE7E7DPX.js +38 -0
- package/dist/{chunk-PEMN4T5O.js → chunk-MT6FGXO3.js} +23 -4
- package/dist/chunk-PFVVUH5B.js +127 -0
- package/dist/{chunk-DPJZQCVP.js → chunk-YMXXOOFN.js} +1 -1
- package/dist/{chunk-4WJKVQJY.js → chunk-ZECLGUTF.js} +15 -3
- package/dist/cli-context.d.ts +2 -0
- package/dist/{cli-main-7B3G2YSG.js → cli-main-EOJ74CI4.js} +336 -99
- package/dist/execute-deps.d.ts +3 -0
- package/dist/{execution-SHGM7BVC.js → execution-CQ772VPS.js} +246 -97
- package/dist/execution-chimera-cascade.d.ts +3 -4
- package/dist/execution-chimera-review.d.ts +2 -3
- package/dist/execution-cleanup.d.ts +3 -2
- package/dist/execution.d.ts +1 -1
- package/dist/{export-TPORYVRZ.js → export-DOBGPY23.js} +12 -1
- package/dist/fleet/host-context.d.ts +1 -1
- package/dist/fleet/host-helpers.d.ts +14 -0
- package/dist/fleet/status-broadcast.d.ts +1 -1
- package/dist/{hq-DVDD4XPV.js → hq-LN5CJHCM.js} +2 -2
- package/dist/hq-server/routes.d.ts +10 -1
- package/dist/hq-server/ws.d.ts +17 -6
- package/dist/{hq-server-DQHLNHDL.js → hq-server-S7HZG3PA.js} +3 -2
- package/dist/index.js +142 -100
- package/dist/live-settings-input.d.ts +5 -0
- package/dist/{mcp-CYLPUEHC.js → mcp-OHPJH73U.js} +6 -2
- package/dist/{modeldiag-YOQZHBQV.js → modeldiag-3DOK4BWW.js} +2 -2
- package/dist/{plugin-usage-EOG4ET4S.js → plugin-usage-YEVLOR33.js} +7 -3
- package/dist/{plugins-56CMWMPR.js → plugins-K3BAUP4D.js} +3 -3
- package/dist/profile-config-path.d.ts +0 -2
- package/dist/provider-helpers.d.ts +0 -5
- package/dist/{providers-models-K6RT7ABI.js → providers-models-WEZ4EGLL.js} +6 -5
- package/dist/{replay-KCTXNMZQ.js → replay-FCBNHW3K.js} +5 -1
- package/dist/{rewind-EJMVFVLS.js → rewind-AOD3JIYX.js} +5 -1
- package/dist/{sessions-config-NLCMK3BY.js → sessions-config-XXN7267N.js} +8 -3
- package/dist/subcommands/flags.d.ts +23 -0
- package/dist/terminal-format.d.ts +15 -0
- package/dist/{webui-server-G3EKFXLL.js → webui-server-NFNRGNNT.js} +54 -29
- package/dist/webui-server-options.d.ts +7 -0
- package/dist/wiring/brain-and-orchestration.d.ts +1 -1
- package/dist/wiring/mailbox-bridge-bootstrap.d.ts +3 -1
- package/dist/wiring/management-tools.d.ts +9 -1
- package/dist/wiring/pipeline.d.ts +5 -5
- package/dist/wiring/plugins.d.ts +2 -3
- package/dist/wiring/provider-utility-tools.d.ts +1 -0
- package/dist/wiring/tools.d.ts +4 -5
- package/package.json +23 -23
|
@@ -32,13 +32,14 @@ import { WebSocketServer } from "ws";
|
|
|
32
32
|
|
|
33
33
|
// src/acp-server-agent.ts
|
|
34
34
|
import { Agent, Context, createDefaultPipelines } from "@wrongstack/core/agent";
|
|
35
|
-
import {
|
|
36
|
-
import { DefaultLogger } from "@wrongstack/core/infrastructure";
|
|
35
|
+
import { ToolExecutor } from "@wrongstack/core/execution";
|
|
36
|
+
import { DefaultLogger, DefaultTokenCounter } from "@wrongstack/core/infrastructure";
|
|
37
37
|
import { EventBus, TOKENS } from "@wrongstack/core/kernel";
|
|
38
|
-
import { ToolValidationError } from "@wrongstack/core/types";
|
|
39
38
|
import { ToolRegistry } from "@wrongstack/core/registry";
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
39
|
+
import { AutoApprovePermissionPolicy, ToolCapabilities } from "@wrongstack/core/security";
|
|
40
|
+
import {
|
|
41
|
+
ToolValidationError
|
|
42
|
+
} from "@wrongstack/core/types";
|
|
42
43
|
import { createDefaultContainer } from "@wrongstack/runtime";
|
|
43
44
|
var AcpServerConfigError = class extends Error {
|
|
44
45
|
constructor(message) {
|
|
@@ -123,7 +124,8 @@ function makeAcpRead(base, api) {
|
|
|
123
124
|
mutating: false,
|
|
124
125
|
execute: async (input) => {
|
|
125
126
|
const i = input ?? {};
|
|
126
|
-
if (!i.path)
|
|
127
|
+
if (!i.path)
|
|
128
|
+
throw new ToolValidationError({ message: "read: path is required", field: "path" });
|
|
127
129
|
const content = await api.readTextFile({
|
|
128
130
|
path: i.path,
|
|
129
131
|
...typeof i.offset === "number" ? { line: i.offset } : {},
|
|
@@ -142,7 +144,8 @@ function makeAcpWrite(base, api) {
|
|
|
142
144
|
...base,
|
|
143
145
|
execute: async (input) => {
|
|
144
146
|
const i = input ?? {};
|
|
145
|
-
if (!i.path)
|
|
147
|
+
if (!i.path)
|
|
148
|
+
throw new ToolValidationError({ message: "write: path is required", field: "path" });
|
|
146
149
|
await api.writeTextFile({ path: i.path, content: i.content ?? "" });
|
|
147
150
|
return { path: i.path, ok: true };
|
|
148
151
|
}
|
|
@@ -153,8 +156,13 @@ function makeAcpEdit(base, api) {
|
|
|
153
156
|
...base,
|
|
154
157
|
execute: async (input) => {
|
|
155
158
|
const i = input ?? {};
|
|
156
|
-
if (!i.path)
|
|
157
|
-
|
|
159
|
+
if (!i.path)
|
|
160
|
+
throw new ToolValidationError({ message: "edit: path is required", field: "path" });
|
|
161
|
+
if (!i.old_string)
|
|
162
|
+
throw new ToolValidationError({
|
|
163
|
+
message: "edit: old_string is required",
|
|
164
|
+
field: "old_string"
|
|
165
|
+
});
|
|
158
166
|
const before = await api.readTextFile({ path: i.path });
|
|
159
167
|
const occurrences = before.split(i.old_string).length - 1;
|
|
160
168
|
if (occurrences === 0) {
|
|
@@ -182,7 +190,8 @@ function makeAcpBash(base, api) {
|
|
|
182
190
|
...base,
|
|
183
191
|
execute: async (input) => {
|
|
184
192
|
const i = input ?? {};
|
|
185
|
-
if (!i.command)
|
|
193
|
+
if (!i.command)
|
|
194
|
+
throw new ToolValidationError({ message: "bash: command is required", field: "command" });
|
|
186
195
|
const { output, exitCode } = await api.runTerminal({
|
|
187
196
|
command: "sh",
|
|
188
197
|
args: ["-c", i.command],
|
|
@@ -219,8 +228,7 @@ function buildAcpServerAgentFactory(deps, options = {}) {
|
|
|
219
228
|
const { provider, providerRegistry } = await bootProvider();
|
|
220
229
|
const events = new EventBus();
|
|
221
230
|
const source = deps.toolRegistry ?? new ToolRegistry();
|
|
222
|
-
const tools =
|
|
223
|
-
for (const t of source.list()) tools.register(t);
|
|
231
|
+
const tools = source.clone();
|
|
224
232
|
if (api) {
|
|
225
233
|
wireClientBackedTools(tools, api);
|
|
226
234
|
}
|
|
@@ -242,7 +250,7 @@ function buildAcpServerAgentFactory(deps, options = {}) {
|
|
|
242
250
|
projectRoot: cwd,
|
|
243
251
|
allowOutsideProjectRoot: config.features?.allowOutsideProjectRoot ?? false,
|
|
244
252
|
model: config.model,
|
|
245
|
-
tools: [...tools.
|
|
253
|
+
tools: [...tools.listForProvider()],
|
|
246
254
|
agentId: "acp-server",
|
|
247
255
|
agentName: "wrongstack-acp"
|
|
248
256
|
});
|
|
@@ -481,7 +489,12 @@ async function runACPWebSocketServer(deps, port) {
|
|
|
481
489
|
return;
|
|
482
490
|
}
|
|
483
491
|
transport.receive(msg);
|
|
484
|
-
void handler.handleMessage(msg)
|
|
492
|
+
void handler.handleMessage(msg).catch((err) => {
|
|
493
|
+
deps.renderer.writeWarning(
|
|
494
|
+
`ACP: failed to handle message: ${err instanceof Error ? err.message : String(err)}
|
|
495
|
+
`
|
|
496
|
+
);
|
|
497
|
+
});
|
|
485
498
|
});
|
|
486
499
|
const teardown = () => {
|
|
487
500
|
handler.close();
|
|
@@ -499,6 +512,12 @@ async function runACPWebSocketServer(deps, port) {
|
|
|
499
512
|
await new Promise((resolve) => {
|
|
500
513
|
const shutdown = () => {
|
|
501
514
|
deps.renderer.writeWarning("\nShutting down ACP WebSocket server...");
|
|
515
|
+
for (const client of wss.clients) {
|
|
516
|
+
try {
|
|
517
|
+
client.terminate();
|
|
518
|
+
} catch {
|
|
519
|
+
}
|
|
520
|
+
}
|
|
502
521
|
wss.close();
|
|
503
522
|
resolve();
|
|
504
523
|
};
|
|
@@ -889,4 +908,4 @@ ${renderAcpBenchText(result)}
|
|
|
889
908
|
export {
|
|
890
909
|
acpCmd
|
|
891
910
|
};
|
|
892
|
-
//# sourceMappingURL=acp-
|
|
911
|
+
//# sourceMappingURL=acp-DATHHPNT.js.map
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* belong in the interactive host. The ACP server is a headless single-turn
|
|
14
14
|
* surface; a future PR can layer richer session behaviour if needed.
|
|
15
15
|
*/
|
|
16
|
+
import type { RunTurnApi } from '@wrongstack/acp/agent';
|
|
16
17
|
import { Agent } from '@wrongstack/core/agent';
|
|
17
18
|
import { type Logger, type PermissionDecision, type PermissionPolicy, type Tool } from '@wrongstack/core/types';
|
|
18
|
-
import type { RunTurnApi } from '@wrongstack/acp/agent';
|
|
19
19
|
import type { SubcommandDeps } from './subcommands/index.js';
|
|
20
20
|
/**
|
|
21
21
|
* Error thrown when the server cannot start because no model provider is
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
restoreFlags
|
|
3
|
+
} from "./chunk-CSAPOCBP.js";
|
|
1
4
|
import "./chunk-7OCVIDC7.js";
|
|
2
5
|
|
|
3
6
|
// src/subcommands/handlers/audit.ts
|
|
4
7
|
import { color, resolveWstackPaths } from "@wrongstack/core/utils";
|
|
5
8
|
import { ToolAuditLog } from "@wrongstack/core/storage";
|
|
6
9
|
var auditCmd = async (args, deps) => {
|
|
10
|
+
args = restoreFlags(args, deps, ["list", "l"]);
|
|
7
11
|
const wpaths = resolveWstackPaths({
|
|
8
12
|
projectRoot: deps.projectRoot,
|
|
9
13
|
userHome: deps.userHome
|
|
@@ -99,4 +103,4 @@ async function listAudits(log, dir, deps) {
|
|
|
99
103
|
export {
|
|
100
104
|
auditCmd
|
|
101
105
|
};
|
|
102
|
-
//# sourceMappingURL=audit-
|
|
106
|
+
//# sourceMappingURL=audit-QRCLEHHW.js.map
|
|
@@ -13,11 +13,11 @@ import {
|
|
|
13
13
|
runOAuthLoginKind,
|
|
14
14
|
runOAuthLoginMenu,
|
|
15
15
|
validateFamily
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-3MOUBRKZ.js";
|
|
17
17
|
import {
|
|
18
18
|
parseAuthFlags
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import "./chunk-
|
|
19
|
+
} from "./chunk-MT6FGXO3.js";
|
|
20
|
+
import "./chunk-ETOEGL3V.js";
|
|
21
21
|
import "./chunk-PYTFS4MC.js";
|
|
22
22
|
import {
|
|
23
23
|
loadConfigProviders,
|
|
@@ -27,14 +27,17 @@ import {
|
|
|
27
27
|
nowIso,
|
|
28
28
|
writeKeysBack
|
|
29
29
|
} from "./chunk-PJHET45A.js";
|
|
30
|
-
import
|
|
30
|
+
import {
|
|
31
|
+
restoreFlags
|
|
32
|
+
} from "./chunk-CSAPOCBP.js";
|
|
33
|
+
import "./chunk-263G3FMB.js";
|
|
31
34
|
import {
|
|
32
35
|
activeProfileConfigPath
|
|
33
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-YMXXOOFN.js";
|
|
34
37
|
import "./chunk-7OCVIDC7.js";
|
|
35
38
|
|
|
36
39
|
// src/subcommands/handlers/auth.ts
|
|
37
|
-
import { color as
|
|
40
|
+
import { color as color4 } from "@wrongstack/core/utils";
|
|
38
41
|
|
|
39
42
|
// src/auth-menu/direct.ts
|
|
40
43
|
async function runAuthDirect(deps, opts) {
|
|
@@ -311,8 +314,94 @@ ${color2.amber("?")} Pick: `)).trim().toLowerCase();
|
|
|
311
314
|
}
|
|
312
315
|
}
|
|
313
316
|
|
|
317
|
+
// src/subcommands/handlers/auth-local-help.ts
|
|
318
|
+
import { color as color3 } from "@wrongstack/core/utils";
|
|
319
|
+
var LOCAL_AUTH_FLAGS = [
|
|
320
|
+
{
|
|
321
|
+
flag: "--name <ollama|vllm|lmstudio>",
|
|
322
|
+
description: "Pick a preset (skip the interactive picker). Defaults to the first run; set this for scripting."
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
flag: "--base-url <url>",
|
|
326
|
+
description: "Override the preset default (e.g. `http://gpu-host:8000/v1` for a remote vLLM). Empty falls back to the preset."
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
flag: "--no-key / --skip-key",
|
|
330
|
+
description: "Skip the API-key prompt even for presets that accept one. Use for non-TTY scripted setups."
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
flag: "--no-probe / --skip-probe",
|
|
334
|
+
description: "Skip the health probe. Use when the local server is not running yet but the config must be persisted."
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
flag: "--probe-only",
|
|
338
|
+
description: "Run the probe and report, do not save. Use to re-check a previously-saved provider."
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
flag: "--model <spec> / -m <spec>",
|
|
342
|
+
description: "Pre-populate the saved `models` allowlist. `--model first` / `<N>` consume the probe; `<csv>` is a literal list; bare `--model` clears the allowlist."
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
flag: "--audit [target]",
|
|
346
|
+
description: "Emit JSONL audit events for the save lifecycle. Bare / `stdout` \u2192 stdout; `stderr` \u2192 stderr; `<path>` \u2192 file. Default is silent."
|
|
347
|
+
}
|
|
348
|
+
];
|
|
349
|
+
var LOCAL_FLAG_COLUMN_WIDTH = 38;
|
|
350
|
+
var LOCAL_AUTH_HELP_USAGE = "wstack auth local [--name <id>] [--base-url <url>] [--no-key] [--no-probe|--probe-only] [--model <spec>] [--audit [target]]";
|
|
351
|
+
function wantsLocalHelp(args) {
|
|
352
|
+
return args.includes("--help") || args.includes("-h");
|
|
353
|
+
}
|
|
354
|
+
function renderAuthLocalHelpToString() {
|
|
355
|
+
const lines = [
|
|
356
|
+
color3.bold("wstack auth local \u2014 quick-add Ollama / vLLM / LM Studio"),
|
|
357
|
+
color3.dim(" Pre-fills the base URL, runs a health probe (`GET /v1/models`),"),
|
|
358
|
+
color3.dim(" and persists the allowlist so you can `wstack --provider <id>`"),
|
|
359
|
+
color3.dim(" right away. Use `--no-probe` to skip when the local server is not"),
|
|
360
|
+
color3.dim(" running yet; use `--audit <file>` to capture the save lifecycle."),
|
|
361
|
+
"",
|
|
362
|
+
color3.bold("Usage"),
|
|
363
|
+
` ${LOCAL_AUTH_HELP_USAGE}`,
|
|
364
|
+
"",
|
|
365
|
+
color3.bold("Flags")
|
|
366
|
+
];
|
|
367
|
+
for (const { flag, description } of LOCAL_AUTH_FLAGS) {
|
|
368
|
+
const padded = flag.padEnd(LOCAL_FLAG_COLUMN_WIDTH, " ");
|
|
369
|
+
lines.push(` ${color3.cyan(padded)}${description}`);
|
|
370
|
+
}
|
|
371
|
+
lines.push("");
|
|
372
|
+
lines.push(color3.dim(" See also: `wstack --help` for the top-level command list."));
|
|
373
|
+
lines.push(
|
|
374
|
+
color3.dim(
|
|
375
|
+
" Examples: `wstack auth local --name ollama --no-probe --model 'llama3.1:8b'`"
|
|
376
|
+
)
|
|
377
|
+
);
|
|
378
|
+
lines.push(
|
|
379
|
+
color3.dim(
|
|
380
|
+
" `wstack auth local --name ollama --audit /var/log/wstack-auth.jsonl`"
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
return lines.join("\n") + "\n";
|
|
384
|
+
}
|
|
385
|
+
|
|
314
386
|
// src/subcommands/handlers/auth.ts
|
|
315
387
|
var authCmd = async (args, deps) => {
|
|
388
|
+
args = restoreFlags(args, deps, [
|
|
389
|
+
"label",
|
|
390
|
+
"family",
|
|
391
|
+
"base-url",
|
|
392
|
+
"env",
|
|
393
|
+
// `auth local` flags — see the `local` branch below.
|
|
394
|
+
"name",
|
|
395
|
+
"no-key",
|
|
396
|
+
"skip-key",
|
|
397
|
+
"no-probe",
|
|
398
|
+
"skip-probe",
|
|
399
|
+
"probe-only",
|
|
400
|
+
"model",
|
|
401
|
+
"m",
|
|
402
|
+
"help",
|
|
403
|
+
"h"
|
|
404
|
+
]);
|
|
316
405
|
const flags = parseAuthFlags(args);
|
|
317
406
|
const profileConfigPath = activeProfileConfigPath(deps.paths, deps.config);
|
|
318
407
|
const menuDeps = {
|
|
@@ -329,6 +418,30 @@ var authCmd = async (args, deps) => {
|
|
|
329
418
|
if (first === "list" || first === "ls") {
|
|
330
419
|
return runAuthList(menuDeps);
|
|
331
420
|
}
|
|
421
|
+
if (first === "local") {
|
|
422
|
+
if (wantsLocalHelp(args)) {
|
|
423
|
+
deps.renderer.write(`${renderAuthLocalHelpToString()}
|
|
424
|
+
`);
|
|
425
|
+
return 0;
|
|
426
|
+
}
|
|
427
|
+
const value = (name) => {
|
|
428
|
+
const i = args.indexOf(`--${name}`);
|
|
429
|
+
return i >= 0 ? args[i + 1] : void 0;
|
|
430
|
+
};
|
|
431
|
+
const has = (...names) => names.some((n) => args.includes(`--${n}`));
|
|
432
|
+
const modelIdx = args.indexOf("--model") >= 0 ? args.indexOf("--model") : args.indexOf("-m");
|
|
433
|
+
return runAuthLocal(menuDeps, {
|
|
434
|
+
name: flags.positional[1] ?? value("name"),
|
|
435
|
+
baseUrl: flags.baseUrl ?? value("base-url"),
|
|
436
|
+
label: flags.label,
|
|
437
|
+
skipKey: has("no-key", "skip-key"),
|
|
438
|
+
noProbe: has("no-probe", "skip-probe"),
|
|
439
|
+
probeOnly: has("probe-only"),
|
|
440
|
+
// Bare `--model` (no value, or followed by another flag) clears the
|
|
441
|
+
// allowlist, which is why an empty string is meaningful here.
|
|
442
|
+
...modelIdx >= 0 ? { models: args[modelIdx + 1]?.startsWith("-") ? "" : args[modelIdx + 1] ?? "" } : {}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
332
445
|
if (first === "status") {
|
|
333
446
|
const pid = flags.positional[1];
|
|
334
447
|
if (!pid) {
|
|
@@ -352,7 +465,7 @@ var authCmd = async (args, deps) => {
|
|
|
352
465
|
if (kind) return runOAuthLoginKind(menuDeps, kind);
|
|
353
466
|
deps.renderer.writeError("OAuth login is only supported for ChatGPT, Claude, and GitHub Copilot.");
|
|
354
467
|
deps.renderer.write(
|
|
355
|
-
|
|
468
|
+
color4.dim(" Sign in with ChatGPT: ") + color4.bold("wstack auth login chatgpt") + "\n" + color4.dim(" Sign in with Claude: ") + color4.bold("wstack auth login claude") + "\n" + color4.dim(" Sign in with Copilot: ") + color4.bold("wstack auth login copilot") + "\n" + color4.dim(" For an API key instead: ") + color4.bold(`wstack auth ${pid}`) + "\n"
|
|
356
469
|
);
|
|
357
470
|
return 1;
|
|
358
471
|
}
|
|
@@ -375,14 +488,14 @@ async function runAuthList(deps) {
|
|
|
375
488
|
const ids = Object.keys(providers).sort();
|
|
376
489
|
if (ids.length === 0) {
|
|
377
490
|
deps.renderer.write(
|
|
378
|
-
`${
|
|
379
|
-
${
|
|
491
|
+
`${color4.dim("No providers configured.")}
|
|
492
|
+
${color4.dim("Run")} ${color4.bold("wstack auth")} ${color4.dim("to add one.")}
|
|
380
493
|
`
|
|
381
494
|
);
|
|
382
495
|
return 0;
|
|
383
496
|
}
|
|
384
497
|
deps.renderer.write(`
|
|
385
|
-
${
|
|
498
|
+
${color4.bold("Saved providers")} ${color4.dim(`(${ids.length})`)}
|
|
386
499
|
|
|
387
500
|
`);
|
|
388
501
|
for (const id of ids) {
|
|
@@ -390,34 +503,34 @@ ${color3.bold("Saved providers")} ${color3.dim(`(${ids.length})`)}
|
|
|
390
503
|
if (!cfg) continue;
|
|
391
504
|
const keys = normalizeKeys(cfg);
|
|
392
505
|
const active = cfg.activeKey ?? keys[0]?.label;
|
|
393
|
-
const famTag = cfg.family ? `${cfg.family}` :
|
|
394
|
-
const aliasHint = cfg.type && cfg.type !== id ?
|
|
395
|
-
const modelHint = cfg.models && cfg.models.length > 0 ?
|
|
396
|
-
deps.renderer.write(` ${
|
|
506
|
+
const famTag = cfg.family ? `${cfg.family}` : color4.amber("no-family");
|
|
507
|
+
const aliasHint = cfg.type && cfg.type !== id ? color4.dim(` (\u2192 ${cfg.type})`) : "";
|
|
508
|
+
const modelHint = cfg.models && cfg.models.length > 0 ? color4.dim(` [${cfg.models.length} models]`) : "";
|
|
509
|
+
deps.renderer.write(` ${color4.bold(id)}${aliasHint}
|
|
397
510
|
`);
|
|
398
511
|
deps.renderer.write(
|
|
399
|
-
` family: ${famTag} baseUrl: ${cfg.baseUrl ??
|
|
512
|
+
` family: ${famTag} baseUrl: ${cfg.baseUrl ?? color4.dim("unset")}${modelHint}
|
|
400
513
|
`
|
|
401
514
|
);
|
|
402
515
|
if (keys.length === 0) {
|
|
403
|
-
deps.renderer.write(` ${
|
|
516
|
+
deps.renderer.write(` ${color4.amber("no keys")}
|
|
404
517
|
`);
|
|
405
518
|
} else {
|
|
406
519
|
deps.renderer.write(
|
|
407
|
-
` ${
|
|
520
|
+
` ${color4.dim(`${keys.length} key${keys.length === 1 ? "" : "s"}:`)}
|
|
408
521
|
`
|
|
409
522
|
);
|
|
410
523
|
for (const k of keys) {
|
|
411
|
-
const marker = k.label === active ?
|
|
524
|
+
const marker = k.label === active ? color4.green("\u25CF") : color4.dim("\u25CB");
|
|
412
525
|
deps.renderer.write(
|
|
413
|
-
` ${marker} ${k.label.padEnd(18)} ${maskedKey(k.apiKey)} ${
|
|
526
|
+
` ${marker} ${k.label.padEnd(18)} ${maskedKey(k.apiKey)} ${color4.dim(k.createdAt)}
|
|
414
527
|
`
|
|
415
528
|
);
|
|
416
529
|
}
|
|
417
530
|
}
|
|
418
531
|
deps.renderer.write("\n");
|
|
419
532
|
}
|
|
420
|
-
deps.renderer.write(
|
|
533
|
+
deps.renderer.write(color4.dim(`Manage: wstack auth Add key: wstack auth <provider>
|
|
421
534
|
`));
|
|
422
535
|
return 0;
|
|
423
536
|
}
|
|
@@ -433,7 +546,7 @@ async function runAuthStatus(deps, providerId) {
|
|
|
433
546
|
if (!cfg) {
|
|
434
547
|
deps.renderer.writeError(`Provider "${providerId}" not found in config.`);
|
|
435
548
|
deps.renderer.write(
|
|
436
|
-
|
|
549
|
+
color4.dim(`Run ${color4.bold("wstack auth list")} to see saved providers.
|
|
437
550
|
`)
|
|
438
551
|
);
|
|
439
552
|
return 1;
|
|
@@ -442,32 +555,32 @@ async function runAuthStatus(deps, providerId) {
|
|
|
442
555
|
const active = cfg.activeKey ?? keys[0]?.label;
|
|
443
556
|
const lines = [
|
|
444
557
|
`
|
|
445
|
-
${
|
|
558
|
+
${color4.bold(providerId)} ${cfg.family ? color4.dim(`[${cfg.family}]`) : color4.amber("[no family]")}`,
|
|
446
559
|
"",
|
|
447
|
-
` type: ${
|
|
448
|
-
` family: ${cfg.family ?
|
|
449
|
-
` baseUrl: ${cfg.baseUrl ?
|
|
560
|
+
` type: ${color4.cyan(cfg.type ?? providerId)}`,
|
|
561
|
+
` family: ${cfg.family ? color4.cyan(cfg.family) : color4.dim("unset")}`,
|
|
562
|
+
` baseUrl: ${cfg.baseUrl ? color4.cyan(cfg.baseUrl) : color4.dim("unset")}`
|
|
450
563
|
];
|
|
451
564
|
if (cfg.models?.length) {
|
|
452
|
-
lines.push(` models: ${
|
|
565
|
+
lines.push(` models: ${color4.cyan(cfg.models.join(", "))}`);
|
|
453
566
|
}
|
|
454
567
|
if (cfg.envVars?.length) {
|
|
455
|
-
lines.push(` envVars: ${
|
|
568
|
+
lines.push(` envVars: ${color4.cyan(cfg.envVars.join(", "))}`);
|
|
456
569
|
}
|
|
457
570
|
lines.push("");
|
|
458
571
|
if (keys.length === 0) {
|
|
459
|
-
lines.push(
|
|
572
|
+
lines.push(color4.amber(" (no keys saved)"));
|
|
460
573
|
} else {
|
|
461
|
-
lines.push(` ${
|
|
574
|
+
lines.push(` ${color4.dim("Keys:")}`);
|
|
462
575
|
for (const k of keys) {
|
|
463
|
-
const marker = k.label === active ?
|
|
576
|
+
const marker = k.label === active ? color4.green("\u25CF") : color4.dim("\u25CB");
|
|
464
577
|
lines.push(
|
|
465
|
-
` ${marker} ${
|
|
578
|
+
` ${marker} ${color4.bold(k.label.padEnd(18))} ${maskedKey(k.apiKey)} ${color4.dim(k.createdAt)}`
|
|
466
579
|
);
|
|
467
580
|
}
|
|
468
581
|
}
|
|
469
582
|
lines.push("");
|
|
470
|
-
lines.push(
|
|
583
|
+
lines.push(color4.dim(`Manage: wstack auth \u2192 pick ${providerId}`));
|
|
471
584
|
deps.renderer.write(lines.join("\n") + "\n");
|
|
472
585
|
return 0;
|
|
473
586
|
}
|
|
@@ -478,19 +591,19 @@ async function runAuthRemove(deps, providerId) {
|
|
|
478
591
|
return 1;
|
|
479
592
|
}
|
|
480
593
|
deps.renderer.write(
|
|
481
|
-
`${
|
|
594
|
+
`${color4.amber("!")} This will remove "${providerId}" and all its saved keys.
|
|
482
595
|
`
|
|
483
596
|
);
|
|
484
|
-
const answer = (await deps.reader.readLine(` ${
|
|
597
|
+
const answer = (await deps.reader.readLine(` ${color4.amber("?")} Confirm removal? ${color4.dim("[y/N]")} `)).trim().toLowerCase();
|
|
485
598
|
if (answer !== "y" && answer !== "yes") {
|
|
486
|
-
deps.renderer.write(
|
|
599
|
+
deps.renderer.write(color4.dim("Cancelled.\n"));
|
|
487
600
|
return 0;
|
|
488
601
|
}
|
|
489
602
|
try {
|
|
490
603
|
await mutateConfigProviders(deps.profileConfigPath, deps.vault, (all) => {
|
|
491
604
|
delete all[providerId];
|
|
492
605
|
});
|
|
493
|
-
deps.renderer.write(` ${
|
|
606
|
+
deps.renderer.write(` ${color4.green("\u2713")} Removed ${color4.bold(providerId)}.
|
|
494
607
|
`);
|
|
495
608
|
return 0;
|
|
496
609
|
} catch (err) {
|
|
@@ -501,4 +614,4 @@ async function runAuthRemove(deps, providerId) {
|
|
|
501
614
|
export {
|
|
502
615
|
authCmd
|
|
503
616
|
};
|
|
504
|
-
//# sourceMappingURL=auth-
|
|
617
|
+
//# sourceMappingURL=auth-PJD3JRH2.js.map
|
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* WebUI dispatch — extracted from the tail of `execute()`.
|
|
3
|
-
*
|
|
4
|
-
* PR 6 of Issue #29 (partial). The TUI-vs-REPL-vs-WebUI fork at the
|
|
5
|
-
* end of `execute()` is a ~1,600-line `if/else if/else if/else`
|
|
6
|
-
* chain. The WebUI branch is the most self-contained of the four: it
|
|
7
|
-
* constructs a `runWebUI` options object from already-available deps,
|
|
8
|
-
* wires SIGINT handling, and returns an exit code. Extracting it
|
|
9
|
-
* first lets `execute()` shrink by ~100 lines and isolates the
|
|
10
|
-
* WebUI-specific wiring (port resolution, browser banner and autonomy
|
|
11
|
-
* forwarding) in a single named module.
|
|
12
|
-
*
|
|
13
|
-
* The TUI branch (~1,388 lines) and the single-shot branch are left
|
|
14
|
-
* inline — they are too deeply coupled to local mutable state for a
|
|
15
|
-
* single-PR extraction.
|
|
16
|
-
*/
|
|
1
|
+
import { type WebuiSessionChildOptions } from './webui-session-child.js';
|
|
17
2
|
import type { Agent } from '@wrongstack/core/agent';
|
|
18
3
|
import type { BrainArbiter } from '@wrongstack/core/coordination';
|
|
19
4
|
import type { JournalEntry } from '@wrongstack/core/goal';
|
|
@@ -99,6 +84,8 @@ export interface WebUIDispatchContext {
|
|
|
99
84
|
}) => Promise<string>) | undefined;
|
|
100
85
|
/** Live fleet budget for WebUI concurrency/spawn gauges (issue #323). */
|
|
101
86
|
getFleetBudget?: CliWebUIOptions['getFleetBudget'];
|
|
87
|
+
/** Internal one-session child launch metadata, when --webui-session-child is active. */
|
|
88
|
+
webuiSessionChild?: WebuiSessionChildOptions | undefined;
|
|
102
89
|
}
|
|
103
90
|
/**
|
|
104
91
|
* Run the WebUI server and block until it shuts down.
|
|
@@ -50,13 +50,11 @@ declare const DEFAULT_PORTS: Record<Exclude<LaunchMenuMode, 'tui-repl'>, number>
|
|
|
50
50
|
* - `--webui`, `--simpleui`, `--hq`, or `--desktop` flag is set
|
|
51
51
|
* (the user already chose a surface)
|
|
52
52
|
* - stdin is not a TTY (CI, pipes, redirects)
|
|
53
|
-
* - the first positional looks like a known subcommand (auth,
|
|
54
|
-
* init, mcp, plugin, doctor, version, help, …)
|
|
55
53
|
* - `--no-interactive` or `--skip` (existing "skip all prompts"
|
|
56
54
|
* contract from boot.ts)
|
|
57
55
|
* - a one-shot prompt (`--prompt <x>`) is supplied
|
|
58
|
-
* -
|
|
59
|
-
*
|
|
56
|
+
* - ANY positional argument is present — a subcommand or a one-shot
|
|
57
|
+
* query. The user already said what they wanted.
|
|
60
58
|
*/
|
|
61
59
|
export declare function shouldSkipMenu(argv: string[], flags: Record<string, string | boolean>, positional: string[]): boolean;
|
|
62
60
|
interface RunLaunchMenuDeps {
|
|
@@ -15,6 +15,9 @@ interface RegisterBuiltinToolsDeps {
|
|
|
15
15
|
descriptionMode?: ToolDescriptionModeConfig | undefined;
|
|
16
16
|
resultRenderMode?: ToolResultRenderModeConfig | undefined;
|
|
17
17
|
disabledTools?: string[] | undefined;
|
|
18
|
+
nextsteps?: {
|
|
19
|
+
enabled?: boolean | undefined;
|
|
20
|
+
} | undefined;
|
|
18
21
|
exec?: {
|
|
19
22
|
allow?: string[] | undefined;
|
|
20
23
|
deny?: string[] | undefined;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export declare const WEBUI_SESSION_CHILD_PROTOCOL_VERSION = 1;
|
|
2
|
+
export declare const WEBUI_SESSION_CHILD_CAPABILITIES: readonly ['multi-session-child', 'single-port-http-ws', 'session-affinity', 'graceful-shutdown'];
|
|
3
|
+
export type WebuiSessionChildPhase = 'validate_args' | 'boot_config' | 'claim_session' | 'create_session' | 'resume_session' | 'bind_port' | 'register_instance' | 'register_session' | 'start_server' | 'unknown';
|
|
4
|
+
export interface WebuiSessionChildOptions {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
projectRoot: string;
|
|
7
|
+
workingDir: string;
|
|
8
|
+
sessionId?: string | undefined;
|
|
9
|
+
resume: boolean;
|
|
10
|
+
host?: string | undefined;
|
|
11
|
+
port?: number | undefined;
|
|
12
|
+
token?: string | undefined;
|
|
13
|
+
publicUrl?: string | undefined;
|
|
14
|
+
publicWsUrl?: string | undefined;
|
|
15
|
+
requireToken?: boolean | undefined;
|
|
16
|
+
strictPort: boolean;
|
|
17
|
+
parentPid: number;
|
|
18
|
+
parentShellId: string;
|
|
19
|
+
runtimeId: string;
|
|
20
|
+
readyFile: string;
|
|
21
|
+
attachable: boolean;
|
|
22
|
+
protocolVersion: number;
|
|
23
|
+
}
|
|
24
|
+
export interface WebuiSessionChildReadyPayload {
|
|
25
|
+
type: 'webui.session_child.ready';
|
|
26
|
+
protocolVersion: number;
|
|
27
|
+
runtime: {
|
|
28
|
+
role: 'session-child';
|
|
29
|
+
runtimeId: string;
|
|
30
|
+
pid: number;
|
|
31
|
+
parentPid: number;
|
|
32
|
+
parentShellId: string;
|
|
33
|
+
startedAt: string;
|
|
34
|
+
};
|
|
35
|
+
project: {
|
|
36
|
+
projectRoot: string;
|
|
37
|
+
workingDir: string;
|
|
38
|
+
projectSlug: string;
|
|
39
|
+
projectName: string;
|
|
40
|
+
};
|
|
41
|
+
session: {
|
|
42
|
+
sessionId: string;
|
|
43
|
+
created: boolean;
|
|
44
|
+
resumed: boolean;
|
|
45
|
+
title?: string | undefined;
|
|
46
|
+
provider?: string | undefined;
|
|
47
|
+
model?: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
endpoint: {
|
|
50
|
+
surface: 'webui';
|
|
51
|
+
host: string;
|
|
52
|
+
httpPort: number;
|
|
53
|
+
url: string;
|
|
54
|
+
publicUrl?: string | undefined;
|
|
55
|
+
publicWsUrl?: string | undefined;
|
|
56
|
+
requireToken: boolean;
|
|
57
|
+
auth: {
|
|
58
|
+
scheme: 'registry-token' | 'cookie-bootstrap' | 'none';
|
|
59
|
+
tokenPresent: boolean;
|
|
60
|
+
token?: string | undefined;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
registry: {
|
|
64
|
+
webuiInstanceRegistered: boolean;
|
|
65
|
+
sessionRegistered: boolean;
|
|
66
|
+
};
|
|
67
|
+
capabilities: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface WebuiSessionChildErrorPayload {
|
|
70
|
+
type: 'webui.session_child.error';
|
|
71
|
+
protocolVersion: number;
|
|
72
|
+
runtimeId?: string | undefined;
|
|
73
|
+
parentShellId?: string | undefined;
|
|
74
|
+
pid: number;
|
|
75
|
+
phase: WebuiSessionChildPhase;
|
|
76
|
+
recoverable: boolean;
|
|
77
|
+
message: string;
|
|
78
|
+
details?: Record<string, unknown> | undefined;
|
|
79
|
+
}
|
|
80
|
+
export declare function parseWebuiSessionChildOptions(flags: Record<string, string | boolean>): WebuiSessionChildOptions | null;
|
|
81
|
+
export declare function writeWebuiSessionChildReady(readyFile: string, payload: WebuiSessionChildReadyPayload): Promise<void>;
|
|
82
|
+
export declare function writeWebuiSessionChildError(readyFile: string, input: {
|
|
83
|
+
protocolVersion?: number | undefined;
|
|
84
|
+
runtimeId?: string | undefined;
|
|
85
|
+
parentShellId?: string | undefined;
|
|
86
|
+
phase: WebuiSessionChildPhase;
|
|
87
|
+
recoverable: boolean;
|
|
88
|
+
error: unknown;
|
|
89
|
+
details?: Record<string, unknown> | undefined;
|
|
90
|
+
}): Promise<void>;
|
|
91
|
+
//# sourceMappingURL=webui-session-child.d.ts.map
|
|
@@ -17,9 +17,10 @@ export declare function __resetReviewerRoundRobinCursor(value?: number): void;
|
|
|
17
17
|
/**
|
|
18
18
|
* Assign provider/model/fallbackModels for a Chimera reviewer spawn.
|
|
19
19
|
*
|
|
20
|
-
* Builds the pool from the configured primary + fallback chain, then
|
|
21
|
-
* the next
|
|
22
|
-
*
|
|
20
|
+
* Builds the pool from the configured primary + fallback chain, then chooses
|
|
21
|
+
* either the next round-robin entry or a random starting entry. The injected
|
|
22
|
+
* random source keeps the random policy deterministic in tests. When the pool
|
|
23
|
+
* has <=1 usable entry the original primary/fallbacks are returned unchanged.
|
|
23
24
|
*
|
|
24
25
|
* When a {@link ProviderModelStatusTracker} is supplied, blocked entries
|
|
25
26
|
* (waiting-room / token-reset-limit room) are filtered from both the pool
|
|
@@ -27,6 +28,12 @@ export declare function __resetReviewerRoundRobinCursor(value?: number): void;
|
|
|
27
28
|
* a concurrent reviewer turn. Without the tracker, the legacy pre-waiting-
|
|
28
29
|
* room behavior is preserved.
|
|
29
30
|
*/
|
|
31
|
+
export declare function assignReviewerModels(provider: string, model: string, fallbackModels: readonly string[], selection?: 'round-robin' | 'random', statusTracker?: ProviderModelStatusTracker | undefined, random?: () => number): {
|
|
32
|
+
provider: string;
|
|
33
|
+
model: string;
|
|
34
|
+
fallbackModels: string[];
|
|
35
|
+
};
|
|
36
|
+
/** Backward-compatible round-robin entry point for existing callers. */
|
|
30
37
|
export declare function assignReviewerModelsRoundRobin(provider: string, model: string, fallbackModels: readonly string[], statusTracker?: ProviderModelStatusTracker | undefined): {
|
|
31
38
|
provider: string;
|
|
32
39
|
model: string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ChimeraWorkRegistry {
|
|
2
|
+
/** Track one review/cascade promise until it settles. */
|
|
3
|
+
track(work: Promise<void>): boolean;
|
|
4
|
+
/** Snapshot currently pending work for parent-before-child ordering. */
|
|
5
|
+
pending(): Promise<void> | undefined;
|
|
6
|
+
/** Stop accepting new roots after draining all accepted work to a fixed point. */
|
|
7
|
+
drainAndClose(): Promise<void>;
|
|
8
|
+
readonly size: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Session-scoped registry for Chimera review and cascade work.
|
|
12
|
+
*
|
|
13
|
+
* A single Promise slot loses overlapping reviews. A single Promise.all snapshot
|
|
14
|
+
* can also miss cascades or re-reviews registered while an earlier batch is
|
|
15
|
+
* settling. This registry retains every accepted promise and drains repeatedly
|
|
16
|
+
* until no accepted work remains, then seals admission.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createChimeraWorkRegistry(): ChimeraWorkRegistry;
|
|
19
|
+
//# sourceMappingURL=chimera-work-registry.d.ts.map
|