@wrongstack/cli 0.299.0 → 0.301.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-S4LZQB66.js → acp-DATHHPNT.js} +36 -17
- package/dist/acp-server-agent.d.ts +1 -1
- package/dist/{audit-2ZSFGNIF.js → audit-QRCLEHHW.js} +5 -1
- package/dist/{auth-G5YKKSRH.js → auth-JASC4K3F.js} +151 -38
- package/dist/auth-menu/loopback-server.d.ts +41 -55
- package/dist/auth-menu/openai-codex-oauth.d.ts +36 -123
- package/dist/auto-discover-providers-DRW4OZHG.js +8 -0
- package/dist/boot/dispatch-webui.d.ts +3 -0
- package/dist/boot/launch-menu.d.ts +2 -4
- package/dist/boot/tool-registry.d.ts +3 -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-2SLSUDYS.js → chunk-2KDOFTTM.js} +312 -211
- package/dist/{chunk-TGDHN4LM.js → chunk-4GVH7V3S.js} +4 -24
- package/dist/chunk-CSAPOCBP.js +24 -0
- package/dist/{chunk-66T43Q4Y.js → chunk-ETOEGL3V.js} +6 -9
- package/dist/{chunk-PEKUKUCH.js → chunk-GUHQQG63.js} +32 -14
- package/dist/chunk-KE7E7DPX.js +38 -0
- package/dist/{chunk-ZNZJ34RF.js → chunk-MHF2IJDE.js} +21 -4
- package/dist/{chunk-4HH3YGG4.js → chunk-MRLYDHQ7.js} +8 -5
- package/dist/{chunk-L5CE52XW.js → chunk-O7XNGCRT.js} +317 -309
- package/dist/chunk-PYTFS4MC.js +238 -0
- package/dist/{chunk-DPJZQCVP.js → chunk-YMXXOOFN.js} +1 -1
- package/dist/{chunk-4U3DMA2Y.js → chunk-ZECLGUTF.js} +28 -21
- package/dist/{cli-main-3MQDFSYK.js → cli-main-XWC57MGE.js} +849 -242
- package/dist/{execution-ANOYMWPO.js → execution-LHMSMDHB.js} +174 -55
- 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/budget-source.d.ts +18 -0
- package/dist/fleet/host-context.d.ts +1 -1
- package/dist/fleet/host-helpers.d.ts +14 -0
- package/dist/fleet/host-status.d.ts +31 -0
- package/dist/fleet/host-types.d.ts +8 -0
- package/dist/fleet/host.d.ts +5 -0
- package/dist/fleet/status-broadcast.d.ts +1 -1
- package/dist/{hq-BDO56CX6.js → hq-LN5CJHCM.js} +22 -3
- package/dist/hq-server/auth-state.d.ts +29 -1
- package/dist/hq-server/auth.d.ts +16 -0
- package/dist/hq-server/client-address.d.ts +56 -0
- package/dist/hq-server/login-attempt-store.d.ts +30 -10
- package/dist/hq-server/routes/auth-handlers.d.ts +66 -26
- package/dist/hq-server/routes.d.ts +23 -1
- package/dist/hq-server/types.d.ts +10 -0
- package/dist/hq-server/ws.d.ts +17 -6
- package/dist/{hq-server-RJLJJZU7.js → hq-server-S7HZG3PA.js} +3 -2
- package/dist/hq-server.d.ts +19 -0
- package/dist/index.js +69 -104
- package/dist/live-settings-input.d.ts +5 -0
- package/dist/{mcp-CYLPUEHC.js → mcp-OHPJH73U.js} +6 -2
- package/dist/{modeldiag-HENYJ4N7.js → modeldiag-3DOK4BWW.js} +3 -3
- package/dist/{plugin-usage-VTL7ZTVC.js → plugin-usage-YEVLOR33.js} +7 -3
- package/dist/{plugins-ETY6W3DC.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-GDELBHZK.js → providers-models-WEZ4EGLL.js} +38 -12
- 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/slash-commands/command-context.d.ts +19 -0
- package/dist/subcommands/flags.d.ts +23 -0
- package/dist/terminal-format.d.ts +15 -0
- package/dist/webui-server/setup-events.d.ts +17 -0
- package/dist/webui-server/terminal-log-view.d.ts +29 -12
- package/dist/{webui-server-PCLSXX6L.js → webui-server-DD35QFNO.js} +113 -50
- package/dist/webui-server-options.d.ts +16 -0
- package/dist/wiring/brain-and-orchestration.d.ts +4 -1
- package/dist/wiring/director-setup.d.ts +4 -0
- package/dist/wiring/fallback-gate.d.ts +31 -0
- package/dist/wiring/fleet-command-handlers.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 +3 -10
- package/dist/wiring/provider-utility-tools.d.ts +27 -1
- package/dist/wiring/tools.d.ts +4 -5
- package/package.json +23 -23
- package/dist/chunk-GO3TJICK.js +0 -489
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
restoreFlags
|
|
3
|
+
} from "./chunk-CSAPOCBP.js";
|
|
1
4
|
import {
|
|
2
5
|
getHistoryEntry,
|
|
3
6
|
listHistory,
|
|
4
7
|
restoreFromHistory,
|
|
5
8
|
restoreLast
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-263G3FMB.js";
|
|
7
10
|
import {
|
|
8
11
|
activeProfileConfigPath
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YMXXOOFN.js";
|
|
10
13
|
import "./chunk-7OCVIDC7.js";
|
|
11
14
|
|
|
12
15
|
// src/subcommands/handlers/sessions-config.ts
|
|
@@ -233,6 +236,7 @@ Fleet Run: ${runId}
|
|
|
233
236
|
|
|
234
237
|
// src/subcommands/handlers/sessions-config.ts
|
|
235
238
|
var sessionsCmd = async (args, deps) => {
|
|
239
|
+
args = restoreFlags(args, deps, ["to", "id", "latest", "l"]);
|
|
236
240
|
const sub = args[0];
|
|
237
241
|
if (sub === "fleet") {
|
|
238
242
|
return sessionsFleetCmd(args.slice(1), deps);
|
|
@@ -302,6 +306,7 @@ var sessionsCmd = async (args, deps) => {
|
|
|
302
306
|
return 0;
|
|
303
307
|
};
|
|
304
308
|
var configCmd = async (args, deps) => {
|
|
309
|
+
args = restoreFlags(args, deps, ["id", "latest", "l"]);
|
|
305
310
|
const sub = args[0];
|
|
306
311
|
if (!sub || sub === "show") {
|
|
307
312
|
deps.renderer.write(JSON.stringify(redactKeys(deps.config), null, 2) + "\n");
|
|
@@ -406,4 +411,4 @@ export {
|
|
|
406
411
|
configCmd,
|
|
407
412
|
sessionsCmd
|
|
408
413
|
};
|
|
409
|
-
//# sourceMappingURL=sessions-config-
|
|
414
|
+
//# sourceMappingURL=sessions-config-XXN7267N.js.map
|
|
@@ -130,6 +130,25 @@ export interface SlashCommandContext {
|
|
|
130
130
|
* Get live coordinator status for /fleet. Returns null when no fleet is active.
|
|
131
131
|
*/
|
|
132
132
|
onFleetStatus?: (() => import('@wrongstack/core/types').CoordinatorStatus | null) | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Read-only concurrency + lifetime spawn budget for `/fleet status`.
|
|
135
|
+
* Returns null when no fleet host is available.
|
|
136
|
+
*/
|
|
137
|
+
onFleetBudget?: (() => {
|
|
138
|
+
maxConcurrent: number;
|
|
139
|
+
activeAgents: number;
|
|
140
|
+
maxSpawns: number;
|
|
141
|
+
usedSpawns: number;
|
|
142
|
+
remainingSpawns: number;
|
|
143
|
+
maxTokens?: number | undefined;
|
|
144
|
+
usedTokens?: number | undefined;
|
|
145
|
+
remainingTokens?: number | undefined;
|
|
146
|
+
maxCostUsd?: number | undefined;
|
|
147
|
+
usedCostUsd?: number | undefined;
|
|
148
|
+
remainingCostUsd?: number | undefined;
|
|
149
|
+
checkpointMaxSpawns?: number | undefined;
|
|
150
|
+
ceilingMismatch?: boolean | undefined;
|
|
151
|
+
} | null) | undefined;
|
|
133
152
|
/**
|
|
134
153
|
* Get fleet usage summary for /fleet usage.
|
|
135
154
|
*/
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-attach the flags `parseArgs` stripped before a subcommand handler ran.
|
|
3
|
+
*
|
|
4
|
+
* The dispatcher (`boot.ts`) hands a handler only `positional.slice(1)`, while
|
|
5
|
+
* `parseArgs` has already pulled every `--flag` into `flags`. A handler that
|
|
6
|
+
* parses its own `args` therefore saw NONE of the flags it documents:
|
|
7
|
+
* `rewind --last 2` printed usage, `export --format json --out r.json` dumped
|
|
8
|
+
* markdown to stdout, `plugin add X --disabled` wrote it enabled, and
|
|
9
|
+
* `chronicle prune --days 7 --dry-run` performed a real 30-day purge.
|
|
10
|
+
*
|
|
11
|
+
* Re-injecting every flag at the dispatcher would be wrong: top-level switches
|
|
12
|
+
* (`--verbose`, `--yolo`, `--tui`) would land in the subcommand's argv too, and
|
|
13
|
+
* handlers with an "Unknown flag" branch — `export.ts` has one — would start
|
|
14
|
+
* rejecting valid invocations. So each handler declares the flags it owns and
|
|
15
|
+
* gets back exactly those.
|
|
16
|
+
*
|
|
17
|
+
* A spelling already present in `args` always wins: a directly-invoked handler
|
|
18
|
+
* (and anything the caller placed after `--`) keeps overriding.
|
|
19
|
+
*/
|
|
20
|
+
export declare function restoreFlags(args: string[], deps: {
|
|
21
|
+
flags?: Record<string, string | boolean> | undefined;
|
|
22
|
+
}, names: readonly string[]): string[];
|
|
23
|
+
//# sourceMappingURL=flags.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type TerminalTone = 'blue' | 'cyan' | 'green' | 'magenta' | 'muted' | 'success' | 'yellow';
|
|
2
|
+
export interface TerminalStyleOptions {
|
|
3
|
+
readonly bold?: boolean;
|
|
4
|
+
/** Capability override for deterministic tests; production derives this from env/TTY. */
|
|
5
|
+
readonly enabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/** Match the CLI banner's NO_COLOR/FORCE_COLOR/TTY precedence. */
|
|
8
|
+
export declare function terminalFormattingEnabled(env?: NodeJS.ProcessEnv, isTty?: boolean): boolean;
|
|
9
|
+
/** Add semantic color while preserving plain text when formatting is disabled. */
|
|
10
|
+
export declare function terminalText(text: string, tone: TerminalTone, options?: TerminalStyleOptions): string;
|
|
11
|
+
/** Render a colored OSC 8 hyperlink, falling back to the visible URL unchanged. */
|
|
12
|
+
export declare function terminalLink(url: string, options?: TerminalStyleOptions & {
|
|
13
|
+
readonly tone?: TerminalTone;
|
|
14
|
+
}): string;
|
|
15
|
+
//# sourceMappingURL=terminal-format.d.ts.map
|
|
@@ -29,6 +29,23 @@ export interface SetupEventsDeps {
|
|
|
29
29
|
eventUnsubscribers: Array<() => void>;
|
|
30
30
|
globalConfigPath?: string | undefined;
|
|
31
31
|
onFleetBroadcaster?: ((fn: () => Promise<void>) => void) | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Live fleet budget snapshot (issue #323). Merged into
|
|
34
|
+
* `fleet.concurrency_update` so the WebUI can show used/remaining spawns
|
|
35
|
+
* without a probe spawn.
|
|
36
|
+
*/
|
|
37
|
+
getFleetBudget?: (() => {
|
|
38
|
+
maxSpawns?: number | undefined;
|
|
39
|
+
usedSpawns?: number | undefined;
|
|
40
|
+
remainingSpawns?: number | undefined;
|
|
41
|
+
maxConcurrent?: number | undefined;
|
|
42
|
+
activeAgents?: number | undefined;
|
|
43
|
+
maxSpawnsSource?: string | undefined;
|
|
44
|
+
maxConcurrentSource?: string | undefined;
|
|
45
|
+
effectiveSource?: string | undefined;
|
|
46
|
+
checkpointMaxSpawns?: number | undefined;
|
|
47
|
+
ceilingMismatch?: boolean | undefined;
|
|
48
|
+
} | null) | undefined;
|
|
32
49
|
}
|
|
33
50
|
/** CLI adapter around the canonical EventBus→WebSocket subscription graph. */
|
|
34
51
|
export declare function createSetupEvents(deps: SetupEventsDeps): () => void;
|
|
@@ -6,25 +6,42 @@ interface ConsoleTarget {
|
|
|
6
6
|
error: ConsoleMethod;
|
|
7
7
|
debug: ConsoleMethod;
|
|
8
8
|
}
|
|
9
|
-
export interface
|
|
10
|
-
maxLines?: number | undefined;
|
|
11
|
-
refreshMs?: number | undefined;
|
|
9
|
+
export interface QuietSurfaceConsoleOptions {
|
|
12
10
|
isTTY?: boolean | undefined;
|
|
11
|
+
/** Pass everything through untouched (the `WEBUI_VERBOSE=1` escape hatch). */
|
|
12
|
+
verbose?: boolean | undefined;
|
|
13
13
|
consoleTarget?: ConsoleTarget | undefined;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
clearIntervalFn?: ((timer: NodeJS.Timeout) => void) | undefined;
|
|
14
|
+
/** Ring-buffer size for {@link QuietSurfaceConsole.recent}. */
|
|
15
|
+
bufferLines?: number | undefined;
|
|
17
16
|
}
|
|
18
|
-
export interface
|
|
17
|
+
export interface QuietSurfaceConsole {
|
|
18
|
+
/** `false` when the console was left untouched (non-TTY or verbose). */
|
|
19
19
|
readonly enabled: boolean;
|
|
20
|
-
|
|
20
|
+
/** Chatter lines dropped from the terminal so far. */
|
|
21
|
+
readonly mutedCount: number;
|
|
22
|
+
/** Newest muted lines, oldest first — for a diagnostic dump on failure. */
|
|
23
|
+
recent(): readonly string[];
|
|
21
24
|
stop(): void;
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
+
* Keep an interactive WebUI/SimpleUI terminal quiet while the browser owns
|
|
28
|
+
* the output surface.
|
|
29
|
+
*
|
|
30
|
+
* Two things fill that terminal, and this handles both:
|
|
31
|
+
*
|
|
32
|
+
* - **Chatter.** Every `console.log`/`info`/`debug` from the server is
|
|
33
|
+
* progress the browser already shows. Those are dropped from the
|
|
34
|
+
* terminal (still counted, and the newest are kept in memory for a
|
|
35
|
+
* failure dump); `console.warn`/`error` are forwarded untouched.
|
|
36
|
+
*
|
|
37
|
+
* - **Repetition.** A warning that fires on a timer used to append an
|
|
38
|
+
* identical line every tick until the terminal was pages deep in the
|
|
39
|
+
* same text. Consecutive identical lines now collapse into a single
|
|
40
|
+
* `↑ previous line repeated N×` notice emitted when the streak ends.
|
|
41
|
+
*
|
|
42
|
+
* Non-TTY output is deliberately untouched so redirected output and log
|
|
43
|
+
* collectors retain the complete append-only log, as is `WEBUI_VERBOSE=1`.
|
|
27
44
|
*/
|
|
28
|
-
export declare function
|
|
45
|
+
export declare function startQuietSurfaceConsole(options?: QuietSurfaceConsoleOptions): QuietSurfaceConsole;
|
|
29
46
|
export {};
|
|
30
47
|
//# sourceMappingURL=terminal-log-view.d.ts.map
|
|
@@ -41,11 +41,12 @@ import {
|
|
|
41
41
|
resolveAuthToken,
|
|
42
42
|
SddBoardWebSocketHandler,
|
|
43
43
|
SddWizardWebSocketHandler,
|
|
44
|
+
sendSerialized,
|
|
44
45
|
SpecsWebSocketHandler,
|
|
45
46
|
TerminalWebSocketHandler,
|
|
46
47
|
WorktreeWebSocketHandler
|
|
47
48
|
} from "@wrongstack/webui-server";
|
|
48
|
-
import {
|
|
49
|
+
import { WebSocketServer } from "ws";
|
|
49
50
|
|
|
50
51
|
// src/webui-server/client-registration.ts
|
|
51
52
|
import { createWebuiClientPresence } from "@wrongstack/webui-server";
|
|
@@ -679,9 +680,23 @@ function createSetupEvents(deps) {
|
|
|
679
680
|
let fleetConcurrency = 0;
|
|
680
681
|
let fleetConcurrencyMax = 4;
|
|
681
682
|
const emitConcurrency = () => {
|
|
683
|
+
const budget = deps.getFleetBudget?.() ?? null;
|
|
682
684
|
deps.broadcast({
|
|
683
685
|
type: "fleet.concurrency_update",
|
|
684
|
-
payload: deps.sessionPayload({
|
|
686
|
+
payload: deps.sessionPayload({
|
|
687
|
+
fleetConcurrency: budget?.activeAgents ?? fleetConcurrency,
|
|
688
|
+
fleetConcurrencyMax: budget?.maxConcurrent ?? fleetConcurrencyMax,
|
|
689
|
+
...budget ? {
|
|
690
|
+
maxSpawns: budget.maxSpawns,
|
|
691
|
+
usedSpawns: budget.usedSpawns,
|
|
692
|
+
remainingSpawns: budget.remainingSpawns,
|
|
693
|
+
maxSpawnsSource: budget.maxSpawnsSource,
|
|
694
|
+
maxConcurrentSource: budget.maxConcurrentSource,
|
|
695
|
+
effectiveSource: budget.effectiveSource,
|
|
696
|
+
checkpointMaxSpawns: budget.checkpointMaxSpawns,
|
|
697
|
+
ceilingMismatch: budget.ceilingMismatch
|
|
698
|
+
} : {}
|
|
699
|
+
})
|
|
685
700
|
});
|
|
686
701
|
};
|
|
687
702
|
return function setupEvents() {
|
|
@@ -761,24 +776,35 @@ import {
|
|
|
761
776
|
|
|
762
777
|
// src/webui-server/terminal-log-view.ts
|
|
763
778
|
import { format } from "node:util";
|
|
764
|
-
var
|
|
765
|
-
var
|
|
766
|
-
var
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
779
|
+
var DEFAULT_BUFFER_LINES = 200;
|
|
780
|
+
var MUTED_LEVELS = ["log", "info", "debug"];
|
|
781
|
+
var FORWARDED_LEVELS = ["warn", "error"];
|
|
782
|
+
var DISABLED = {
|
|
783
|
+
enabled: false,
|
|
784
|
+
mutedCount: 0,
|
|
785
|
+
recent: () => [],
|
|
786
|
+
stop: () => {
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
function envVerbose() {
|
|
790
|
+
for (const name of ["WEBUI_VERBOSE", "WRONGSTACK_WEBUI_VERBOSE"]) {
|
|
791
|
+
const value = process.env[name]?.trim().toLowerCase();
|
|
792
|
+
if (value === "1" || value === "true" || value === "yes" || value === "on") return true;
|
|
773
793
|
}
|
|
774
|
-
|
|
775
|
-
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
function startQuietSurfaceConsole(options = {}) {
|
|
797
|
+
const isTTY = options.isTTY ?? process.stdout.isTTY === true;
|
|
798
|
+
const verbose = options.verbose ?? envVerbose();
|
|
799
|
+
if (!isTTY || verbose) return DISABLED;
|
|
800
|
+
const bufferLines = Math.max(1, Math.trunc(options.bufferLines ?? DEFAULT_BUFFER_LINES));
|
|
776
801
|
const target = options.consoleTarget ?? console;
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
const clearIntervalFn = options.clearIntervalFn ?? clearInterval;
|
|
780
|
-
const lines = [];
|
|
802
|
+
const muted = [];
|
|
803
|
+
let mutedCount = 0;
|
|
781
804
|
let stopped = false;
|
|
805
|
+
let lastLine = null;
|
|
806
|
+
let lastEmit = null;
|
|
807
|
+
let repeats = 0;
|
|
782
808
|
const originals = {
|
|
783
809
|
log: target.log,
|
|
784
810
|
info: target.info,
|
|
@@ -787,35 +813,47 @@ function startBoundedTerminalLogView(options = {}) {
|
|
|
787
813
|
debug: target.debug
|
|
788
814
|
};
|
|
789
815
|
const wrappers = {};
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
}
|
|
816
|
+
const flushRepeats = () => {
|
|
817
|
+
if (repeats === 0 || !lastEmit) return;
|
|
818
|
+
const count = repeats;
|
|
819
|
+
repeats = 0;
|
|
820
|
+
lastEmit.call(target, ` \u2191 previous line repeated ${count}\xD7`);
|
|
795
821
|
};
|
|
796
|
-
for (const level of
|
|
822
|
+
for (const level of MUTED_LEVELS) {
|
|
823
|
+
const wrapper = (...args) => {
|
|
824
|
+
mutedCount += 1;
|
|
825
|
+
muted.push(format(...args));
|
|
826
|
+
if (muted.length > bufferLines) muted.shift();
|
|
827
|
+
};
|
|
828
|
+
wrappers[level] = wrapper;
|
|
829
|
+
target[level] = wrapper;
|
|
830
|
+
}
|
|
831
|
+
for (const level of FORWARDED_LEVELS) {
|
|
797
832
|
const original = originals[level];
|
|
798
833
|
const wrapper = (...args) => {
|
|
799
|
-
|
|
834
|
+
const line = format(...args);
|
|
835
|
+
if (line === lastLine) {
|
|
836
|
+
repeats += 1;
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
flushRepeats();
|
|
840
|
+
lastLine = line;
|
|
841
|
+
lastEmit = original;
|
|
800
842
|
original.apply(target, args);
|
|
801
843
|
};
|
|
802
844
|
wrappers[level] = wrapper;
|
|
803
845
|
target[level] = wrapper;
|
|
804
846
|
}
|
|
805
|
-
const redraw = () => {
|
|
806
|
-
if (stopped || lines.length === 0) return;
|
|
807
|
-
write(`${CLEAR_VISIBLE_TERMINAL}${lines.join("\n")}
|
|
808
|
-
`);
|
|
809
|
-
};
|
|
810
|
-
const timer = setIntervalFn(redraw, refreshMs);
|
|
811
|
-
timer.unref?.();
|
|
812
847
|
return {
|
|
813
848
|
enabled: true,
|
|
814
|
-
|
|
849
|
+
get mutedCount() {
|
|
850
|
+
return mutedCount;
|
|
851
|
+
},
|
|
852
|
+
recent: () => [...muted],
|
|
815
853
|
stop: () => {
|
|
816
854
|
if (stopped) return;
|
|
817
855
|
stopped = true;
|
|
818
|
-
|
|
856
|
+
flushRepeats();
|
|
819
857
|
for (const level of Object.keys(originals)) {
|
|
820
858
|
if (target[level] === wrappers[level]) target[level] = originals[level];
|
|
821
859
|
}
|
|
@@ -825,6 +863,7 @@ function startBoundedTerminalLogView(options = {}) {
|
|
|
825
863
|
|
|
826
864
|
// src/webui-server.ts
|
|
827
865
|
async function runWebUI(opts) {
|
|
866
|
+
const terminalLogView = startQuietSurfaceConsole();
|
|
828
867
|
const trustBoundary = opts.trustBoundary ?? createCompatibilityTrustBoundary({ policyId: "cli-webui-trusted-host-compat-v1" });
|
|
829
868
|
const host = opts.host ?? process.env["WEBUI_HOST"] ?? process.env["WS_HOST"] ?? "127.0.0.1";
|
|
830
869
|
const publicUrl = opts.publicUrl ?? process.env["WEBUI_PUBLIC_URL"];
|
|
@@ -1060,7 +1099,10 @@ async function runWebUI(opts) {
|
|
|
1060
1099
|
publicUrl,
|
|
1061
1100
|
projectRoot: opts.projectRoot,
|
|
1062
1101
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1063
|
-
registryBaseDir
|
|
1102
|
+
registryBaseDir,
|
|
1103
|
+
// Lets a same-project TUI/REPL authenticate `POST /api/fleet/ping` now
|
|
1104
|
+
// that the API requires a token on every bind (H3).
|
|
1105
|
+
authToken: wsToken
|
|
1064
1106
|
});
|
|
1065
1107
|
}
|
|
1066
1108
|
const eventUnsubscribers = [];
|
|
@@ -1096,7 +1138,8 @@ async function runWebUI(opts) {
|
|
|
1096
1138
|
globalConfigPath: path5.join(globalRoot, "config.json"),
|
|
1097
1139
|
onFleetBroadcaster: (fn) => {
|
|
1098
1140
|
fleetBroadcastCli = fn;
|
|
1099
|
-
}
|
|
1141
|
+
},
|
|
1142
|
+
...opts.getFleetBudget ? { getFleetBudget: opts.getFleetBudget } : {}
|
|
1100
1143
|
});
|
|
1101
1144
|
const wsHandlerCtx = {
|
|
1102
1145
|
providerStore: createProviderConfigStore(
|
|
@@ -1172,7 +1215,10 @@ async function runWebUI(opts) {
|
|
|
1172
1215
|
...snapshot.baseUrl !== void 0 ? { baseUrl: snapshot.baseUrl } : {}
|
|
1173
1216
|
};
|
|
1174
1217
|
const oldMax = opts.agent.ctx.provider.capabilities?.maxContext;
|
|
1175
|
-
const prov = makeProviderFromConfig(activeId, {
|
|
1218
|
+
const prov = makeProviderFromConfig(activeId, {
|
|
1219
|
+
...newCfg,
|
|
1220
|
+
type: newCfg.type ?? activeId
|
|
1221
|
+
});
|
|
1176
1222
|
if (oldMax != null && prov.capabilities) prov.capabilities.maxContext = oldMax;
|
|
1177
1223
|
opts.agent.ctx.provider = prov;
|
|
1178
1224
|
console.log(`[WebUI] Provider credentials reloaded from config.json (${activeId})`);
|
|
@@ -1352,7 +1398,6 @@ async function runWebUI(opts) {
|
|
|
1352
1398
|
kanbanHostRoutes,
|
|
1353
1399
|
statusTracker: opts.statusTracker
|
|
1354
1400
|
});
|
|
1355
|
-
const terminalLogView = startBoundedTerminalLogView();
|
|
1356
1401
|
const stopped = new Promise((resolve) => {
|
|
1357
1402
|
let listeningAnnounced = false;
|
|
1358
1403
|
const announceListening = () => {
|
|
@@ -1431,6 +1476,28 @@ async function runWebUI(opts) {
|
|
|
1431
1476
|
flushAllStreamBuffers();
|
|
1432
1477
|
for (const unsub of eventUnsubscribers) unsub();
|
|
1433
1478
|
},
|
|
1479
|
+
// Issue #322: kill session-owned children (MCP, bash/exec, tool-spawned
|
|
1480
|
+
// dev servers) before closing the listen socket so Windows process trees
|
|
1481
|
+
// do not outlive the parent and strand the event loop on open stdio.
|
|
1482
|
+
stopOwnedChildren: async () => {
|
|
1483
|
+
try {
|
|
1484
|
+
const { getProcessRegistry } = await import("@wrongstack/tools");
|
|
1485
|
+
getProcessRegistry().killAll({ force: true, includeProtected: true });
|
|
1486
|
+
} catch (err) {
|
|
1487
|
+
console.debug(
|
|
1488
|
+
`[webui-server] process-registry killAll failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1489
|
+
);
|
|
1490
|
+
}
|
|
1491
|
+
if (opts.mcpRegistry) {
|
|
1492
|
+
try {
|
|
1493
|
+
await opts.mcpRegistry.stopAll();
|
|
1494
|
+
} catch (err) {
|
|
1495
|
+
console.debug(
|
|
1496
|
+
`[webui-server] mcpRegistry.stopAll failed: ${err instanceof Error ? err.message : String(err)}`
|
|
1497
|
+
);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
},
|
|
1434
1501
|
disposeResources: () => {
|
|
1435
1502
|
credentialWatcherClose?.();
|
|
1436
1503
|
credentialWatcherClose = void 0;
|
|
@@ -1455,8 +1522,13 @@ async function runWebUI(opts) {
|
|
|
1455
1522
|
pid: process.pid,
|
|
1456
1523
|
registryBaseDir,
|
|
1457
1524
|
onStopped: () => {
|
|
1458
|
-
terminalLogView.
|
|
1525
|
+
const muted = terminalLogView.mutedCount;
|
|
1459
1526
|
terminalLogView.stop();
|
|
1527
|
+
if (muted > 0) {
|
|
1528
|
+
console.log(
|
|
1529
|
+
`[WebUI] ${muted} progress line(s) kept out of this terminal \u2014 set WEBUI_VERBOSE=1 to see them.`
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1460
1532
|
opts.onExit?.();
|
|
1461
1533
|
resolve();
|
|
1462
1534
|
}
|
|
@@ -1464,20 +1536,11 @@ async function runWebUI(opts) {
|
|
|
1464
1536
|
registerWebuiSignalHandlers(signalShutdown);
|
|
1465
1537
|
});
|
|
1466
1538
|
function send(ws, msg) {
|
|
1467
|
-
|
|
1468
|
-
ws.send(JSON.stringify(msg));
|
|
1469
|
-
}
|
|
1539
|
+
sendSerialized(ws, JSON.stringify(msg));
|
|
1470
1540
|
}
|
|
1471
1541
|
function broadcast(msg) {
|
|
1472
1542
|
const data = JSON.stringify(msg);
|
|
1473
|
-
for (const [ws] of clients)
|
|
1474
|
-
if (ws.readyState === WebSocket.OPEN) {
|
|
1475
|
-
try {
|
|
1476
|
-
ws.send(data);
|
|
1477
|
-
} catch {
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1543
|
+
for (const [ws] of clients) sendSerialized(ws, data);
|
|
1481
1544
|
}
|
|
1482
1545
|
function sendResult(ws, success, message) {
|
|
1483
1546
|
send(ws, { type: "key.operation_result", payload: { success, message } });
|
|
@@ -1487,4 +1550,4 @@ async function runWebUI(opts) {
|
|
|
1487
1550
|
export {
|
|
1488
1551
|
runWebUI
|
|
1489
1552
|
};
|
|
1490
|
-
//# sourceMappingURL=webui-server-
|
|
1553
|
+
//# sourceMappingURL=webui-server-DD35QFNO.js.map
|
|
@@ -36,6 +36,22 @@ export interface CliWebUIOptions {
|
|
|
36
36
|
surface?: 'webui' | 'simpleui' | undefined;
|
|
37
37
|
/** Fixed access token/password. Defaults to WEBUI_TOKEN or random per process. */
|
|
38
38
|
accessToken?: string | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Live fleet concurrency + lifetime spawn budget for WebUI (issue #323).
|
|
41
|
+
* Merged into `fleet.concurrency_update` broadcasts.
|
|
42
|
+
*/
|
|
43
|
+
getFleetBudget?: (() => {
|
|
44
|
+
maxSpawns?: number | undefined;
|
|
45
|
+
usedSpawns?: number | undefined;
|
|
46
|
+
remainingSpawns?: number | undefined;
|
|
47
|
+
maxConcurrent?: number | undefined;
|
|
48
|
+
activeAgents?: number | undefined;
|
|
49
|
+
maxSpawnsSource?: string | undefined;
|
|
50
|
+
maxConcurrentSource?: string | undefined;
|
|
51
|
+
effectiveSource?: string | undefined;
|
|
52
|
+
checkpointMaxSpawns?: number | undefined;
|
|
53
|
+
ceilingMismatch?: boolean | undefined;
|
|
54
|
+
} | null) | undefined;
|
|
39
55
|
/** Browser-facing HTTP URL, used when WebUI is exposed behind a tunnel/proxy. */
|
|
40
56
|
publicUrl?: string | undefined;
|
|
41
57
|
/** Browser-facing WebSocket URL injected into the frontend. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BrainDecisionQueue, type BrainEscalationMode, ObservableBrainArbiter } from '@wrongstack/core/coordination';
|
|
2
2
|
import { type BrainAutoRisk, type BrainRuntime } from '@wrongstack/core/execution';
|
|
3
3
|
import type { ToolRegistry } from '@wrongstack/core/registry';
|
|
4
|
-
import type
|
|
4
|
+
import { type Config, type Provider, type SecretVault, type SessionWriter } from '@wrongstack/core/types';
|
|
5
5
|
import { MultiAgentHost } from '../multi-agent.js';
|
|
6
6
|
type AnyObj = any;
|
|
7
7
|
/**
|
|
@@ -49,6 +49,9 @@ export interface BrainOrchestrationDeps {
|
|
|
49
49
|
stateCheckpointPath: string | undefined;
|
|
50
50
|
fleetRootForPromotion: string;
|
|
51
51
|
maxConcurrent: number | undefined;
|
|
52
|
+
maxSpawns?: number | undefined;
|
|
53
|
+
maxConcurrentSource?: import('../fleet/budget-source.js').FleetBudgetSource | undefined;
|
|
54
|
+
maxSpawnsSource?: import('../fleet/budget-source.js').FleetBudgetSource | undefined;
|
|
52
55
|
effectiveMaxContextRef: {
|
|
53
56
|
current: number;
|
|
54
57
|
};
|
|
@@ -23,6 +23,10 @@ export interface DirectorAutonomyResult {
|
|
|
23
23
|
director: Director | null;
|
|
24
24
|
directorMode: boolean;
|
|
25
25
|
maxConcurrent: number | undefined;
|
|
26
|
+
/** Lifetime spawn ceiling resolved from flag/env/profile/default. */
|
|
27
|
+
maxSpawns: number;
|
|
28
|
+
maxConcurrentSource: import('../fleet/budget-source.js').FleetBudgetSource;
|
|
29
|
+
maxSpawnsSource: import('../fleet/budget-source.js').FleetBudgetSource;
|
|
26
30
|
autonomyMode: import('../services/autonomy-mode.js').AutonomyMode;
|
|
27
31
|
nextPredictEnabled: boolean;
|
|
28
32
|
currentSuggestions: string[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory for the fallback gate function.
|
|
3
|
+
*
|
|
4
|
+
* The gate is injected into `createFallbackModelExtension` as `fallbackGate`.
|
|
5
|
+
* When the fallback chain is about to engage, the gate:
|
|
6
|
+
*
|
|
7
|
+
* 1. Registers a `provider.fallback_choice` listener keyed on `requestId`.
|
|
8
|
+
* 2. Emits `provider.fallback_pending` on the EventBus — carrying the
|
|
9
|
+
* candidate list, countdown duration, and the caller-supplied
|
|
10
|
+
* `requestId` (generated by the fallback-model extension so the
|
|
11
|
+
* `provider.fallback` completion event can share the same id).
|
|
12
|
+
* 3. Waits for the choice event (the user manually picked a model), OR for
|
|
13
|
+
* the countdown timer to expire (auto-switch to the chain head).
|
|
14
|
+
* 4. Resolves with the chosen model reference, or `null` for auto-switch.
|
|
15
|
+
*
|
|
16
|
+
* Registration happens BEFORE the emit so a same-tick choice reply from a
|
|
17
|
+
* synchronous EventBus listener (test harness, automated UI pick) is not
|
|
18
|
+
* dropped.
|
|
19
|
+
*
|
|
20
|
+
* An absolute deadline (autoSwitchSeconds * 1.5) ensures the gate never
|
|
21
|
+
* hangs indefinitely even if neither signal arrives (headless mode, no UI
|
|
22
|
+
* listener, etc.).
|
|
23
|
+
*/
|
|
24
|
+
import type { FallbackGateFn } from '@wrongstack/core/agent';
|
|
25
|
+
import type { EventBus } from '@wrongstack/core/kernel';
|
|
26
|
+
/**
|
|
27
|
+
* Create a fallback gate that emits `provider.fallback_pending` and waits
|
|
28
|
+
* for a `provider.fallback_choice` event or the countdown timer.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createFallbackGate(_events: EventBus): FallbackGateFn;
|
|
31
|
+
//# sourceMappingURL=fallback-gate.d.ts.map
|
|
@@ -3,7 +3,7 @@ import type { EventBus } from '@wrongstack/core/kernel';
|
|
|
3
3
|
import type { MultiAgentHost } from '../multi-agent.js';
|
|
4
4
|
import type { BuiltinSlashCommandDeps } from './slash-commands.js';
|
|
5
5
|
type SlashCommandDeps = BuiltinSlashCommandDeps;
|
|
6
|
-
export type FleetCommandHandlers = Pick<SlashCommandDeps, 'onSpawn' | 'onSpawnAndWait' | 'onAgents' | 'onFleet' | 'onFleetStatus' | 'onFleetUsage' | 'onFleetKill' | 'onFleetTerminate' | 'onFleetSpawn' | 'onFleetLog' | 'onFleetRetry' | 'onDirector'>;
|
|
6
|
+
export type FleetCommandHandlers = Pick<SlashCommandDeps, 'onSpawn' | 'onSpawnAndWait' | 'onAgents' | 'onFleet' | 'onFleetStatus' | 'onFleetBudget' | 'onFleetUsage' | 'onFleetKill' | 'onFleetTerminate' | 'onFleetSpawn' | 'onFleetLog' | 'onFleetRetry' | 'onDirector'>;
|
|
7
7
|
export interface FleetCommandHandlersInput {
|
|
8
8
|
multiAgentHost: MultiAgentHost;
|
|
9
9
|
getDirector: () => Director | null;
|
|
@@ -33,7 +33,9 @@ export declare const MAILBOX_BRIDGE_META_KEY = "mailboxBridge";
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function bootstrapMailboxBridgeAtStartup(params: {
|
|
35
35
|
projectRoot: string | undefined;
|
|
36
|
-
config:
|
|
36
|
+
config: {
|
|
37
|
+
features: Pick<Config['features'], 'mailboxBridge'>;
|
|
38
|
+
} | undefined;
|
|
37
39
|
logger: Logger;
|
|
38
40
|
/** Surface label — logged for debugging when something goes wrong. */
|
|
39
41
|
source: 'cli' | 'webui' | 'eternal';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from '@wrongstack/core/types';
|
|
2
|
+
import { type PluginManagerHookRunner } from '@wrongstack/core/tools';
|
|
2
3
|
import type { ToolRegistry } from '@wrongstack/core/registry';
|
|
3
4
|
type ConfigStoreLike = {
|
|
4
5
|
get(): Config;
|
|
@@ -9,7 +10,14 @@ export interface RegisterCliManagementToolsDeps {
|
|
|
9
10
|
configStore: ConfigStoreLike;
|
|
10
11
|
profileConfigPath: string;
|
|
11
12
|
stdinInteractive: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Late-bound PreToolUse pipeline for plugin_manager's nested `use` path.
|
|
15
|
+
* The hook runner is created by `setupLifecycleAndPlugins` AFTER the
|
|
16
|
+
* management tools register, so cli-main passes a ref-backed getter that
|
|
17
|
+
* starts null and is filled once wiring completes.
|
|
18
|
+
*/
|
|
19
|
+
getHookRunner?: (() => PluginManagerHookRunner | null) | undefined;
|
|
12
20
|
}
|
|
13
|
-
export declare function registerCliManagementTools({ toolRegistry, configStore, profileConfigPath, stdinInteractive, }: RegisterCliManagementToolsDeps): void;
|
|
21
|
+
export declare function registerCliManagementTools({ toolRegistry, configStore, profileConfigPath, stdinInteractive, getHookRunner, }: RegisterCliManagementToolsDeps): void;
|
|
14
22
|
export {};
|
|
15
23
|
//# sourceMappingURL=management-tools.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Agent, type AgentPipelines, type Context } from '@wrongstack/core/agent';
|
|
2
2
|
import { AutoCompactionMiddleware } from '@wrongstack/core/execution';
|
|
3
|
-
import type { Config, Logger, ModelsRegistry, Provider } from '@wrongstack/core/types';
|
|
4
|
-
import type { SessionEventBridge } from '@wrongstack/core/storage';
|
|
5
3
|
import { type EventBus } from '@wrongstack/core/kernel';
|
|
6
4
|
import type { ProviderRegistry, ToolRegistry } from '@wrongstack/core/registry';
|
|
5
|
+
import type { SessionEventBridge } from '@wrongstack/core/storage';
|
|
6
|
+
import type { Config, Logger, ModelsRegistry, Provider } from '@wrongstack/core/types';
|
|
7
7
|
type CompactionDriver = ConstructorParameters<typeof AutoCompactionMiddleware>[0];
|
|
8
8
|
export declare function setupPipelines(params: {
|
|
9
9
|
events: EventBus;
|
|
@@ -90,9 +90,9 @@ export declare function createAgent(params: {
|
|
|
90
90
|
/**
|
|
91
91
|
* Full Config object, used for `features.mailboxBridge` gating and
|
|
92
92
|
* forwarded to `bootstrapMailboxBridgeAtStartup`. Optional — when
|
|
93
|
-
* omitted, the bootstrap defaults to '
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* omitted, the bootstrap defaults to 'off' (i.e. never run), so tests
|
|
94
|
+
* and embedders get no detached bridge process unless they ask for one
|
|
95
|
+
* with `{ features: { mailboxBridge: 'auto' } }`.
|
|
96
96
|
*/
|
|
97
97
|
fullConfig?: Pick<Config, 'features'> | undefined;
|
|
98
98
|
/** Surface label for the bootstrap log breadcrumb. */
|
package/dist/wiring/plugins.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { AgentPipelines } from '@wrongstack/core/agent';
|
|
2
|
-
import type { Config, HealthRegistry, Logger, MetricsRuntimeStatus, MetricsSinkView, ModelsRegistry, Plugin, PromptLoader, SkillLoader } from '@wrongstack/core/types';
|
|
3
2
|
import type { ExtensionRegistry } from '@wrongstack/core/extension';
|
|
4
|
-
import type { PluginHostHandle } from '@wrongstack/core/plugin';
|
|
5
|
-
import type { ConfigStore, SessionWriter } from '@wrongstack/core/types';
|
|
6
3
|
import type { Container, EventBus } from '@wrongstack/core/kernel';
|
|
4
|
+
import type { PluginAPIInit, PluginHostHandle } from '@wrongstack/core/plugin';
|
|
7
5
|
import type { ProviderRegistry, SlashCommandRegistry, ToolRegistry } from '@wrongstack/core/registry';
|
|
6
|
+
import type { Config, ConfigStore, HealthRegistry, Logger, MetricsRuntimeStatus, MetricsSinkView, ModelsRegistry, Plugin, PromptLoader, SessionWriter, SkillLoader } from '@wrongstack/core/types';
|
|
8
7
|
import type { MCPRegistry } from '@wrongstack/mcp';
|
|
9
8
|
export declare const DEPRECATED_PLUGIN_NAMES: Record<string, string>;
|
|
10
9
|
export declare const BUILTIN_PLUGIN_CONFIG_NAMES: Set<string>;
|
|
@@ -71,13 +70,7 @@ export interface PluginsWiringDeps {
|
|
|
71
70
|
* default model, and a factory for named-provider overrides. Optional —
|
|
72
71
|
* minimal hosts omit it and plugins see `api.llm === undefined`.
|
|
73
72
|
*/
|
|
74
|
-
llm?:
|
|
75
|
-
provider: import('@wrongstack/core/types').Provider;
|
|
76
|
-
model: string;
|
|
77
|
-
getProvider?: (() => import('@wrongstack/core/types').Provider) | undefined;
|
|
78
|
-
getModel?: (() => string) | undefined;
|
|
79
|
-
createProvider?: ((name: string, model?: string) => import('@wrongstack/core/types').Provider) | undefined;
|
|
80
|
-
} | undefined;
|
|
73
|
+
llm?: PluginAPIInit['llm'];
|
|
81
74
|
/** Health registry — injected so the observability built-in can run /health. */
|
|
82
75
|
healthRegistry?: HealthRegistry | undefined;
|
|
83
76
|
/** Skill loader — injected so the skills built-in can list/read skills. */
|