@wrongstack/webui-server 0.313.0 → 0.316.1
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 +4739 -1302
- package/dist/server/agent-roster-handlers.d.ts +3 -2
- package/dist/server/backend-services.d.ts +33 -1
- package/dist/server/boot.d.ts +2 -1
- package/dist/server/brain-handlers.d.ts +21 -4
- package/dist/server/chimera-routes.d.ts +88 -0
- package/dist/server/codebase-index-server-control.d.ts +2 -1
- package/dist/server/codebase-indexing.d.ts +3 -2
- package/dist/server/codemap-cache.d.ts +0 -5
- package/dist/server/codemap-handlers.d.ts +2 -1
- package/dist/server/collab/controller.d.ts +0 -2
- package/dist/server/collab/session-registry.d.ts +2 -1
- package/dist/server/connection-handler.d.ts +2 -1
- package/dist/server/connections/auto-healer.d.ts +5 -6
- package/dist/server/connections/collector.d.ts +0 -3
- package/dist/server/connections/helpers.d.ts +0 -2
- package/dist/server/connections/service-actions.d.ts +0 -4
- package/dist/server/content-routes.d.ts +6 -1
- package/dist/server/conversation-operations.d.ts +18 -2
- package/dist/server/deadcode-handlers.d.ts +2 -1
- package/dist/server/design-handlers.d.ts +6 -0
- package/dist/server/discover-mailbox-bridge.d.ts +2 -1
- package/dist/server/embedded-host-adapters.d.ts +120 -2
- package/dist/server/embedded-message-router.d.ts +15 -1
- package/dist/server/entry.js +4323 -1086
- package/dist/server/file-handlers.d.ts +5 -2
- package/dist/server/git-handlers.d.ts +19 -0
- package/dist/server/governance-runtime.d.ts +1 -1
- package/dist/server/handlers.js +6 -9
- package/dist/server/http-server/analytics-handler.d.ts +0 -2
- package/dist/server/http-server/security-helpers.d.ts +0 -6
- package/dist/server/http-server/vector-memory-handlers.d.ts +2 -56
- package/dist/server/index.d.ts +12 -5
- package/dist/server/introspection-routes.d.ts +16 -0
- package/dist/server/kanban-contract-routes.d.ts +19 -1
- package/dist/server/kanban-decomposition-routes.d.ts +4 -1
- package/dist/server/kanban-dispatch.d.ts +2 -0
- package/dist/server/kanban-route-helpers.d.ts +21 -0
- package/dist/server/kanban-routes.d.ts +13 -1
- package/dist/server/kanban-supervisor.d.ts +2 -0
- package/dist/server/kanban-task-routes.d.ts +4 -1
- package/dist/server/lifecycle.d.ts +2 -1
- package/dist/server/mcp-handlers.d.ts +2 -1
- package/dist/server/message-dispatcher.d.ts +19 -5
- package/dist/server/mode-handlers.d.ts +6 -4
- package/dist/server/mode-operations.d.ts +15 -4
- package/dist/server/model-catalog-search.d.ts +2 -1
- package/dist/server/model-operations.d.ts +6 -2
- package/dist/server/pending-confirms.d.ts +27 -1
- package/dist/server/port-utils.d.ts +16 -2
- package/dist/server/pref-helpers.d.ts +1 -1
- package/dist/server/prefs-handlers.d.ts +43 -6
- package/dist/server/prefs-routes.d.ts +11 -2
- package/dist/server/process-handlers.d.ts +12 -5
- package/dist/server/project-handlers.d.ts +12 -0
- package/dist/server/project-watcher.d.ts +19 -10
- package/dist/server/provider/mutations.d.ts +0 -1
- package/dist/server/provider-fanout.d.ts +46 -0
- package/dist/server/provider-handlers.d.ts +6 -2
- package/dist/server/provider-routes.d.ts +3 -0
- package/dist/server/provider-store.d.ts +2 -1
- package/dist/server/requirement-intake-handlers.d.ts +0 -2
- package/dist/server/route-family-dispatcher.d.ts +2 -0
- package/dist/server/routes.d.ts +41 -5
- package/dist/server/sdd-board-ws-handler.d.ts +2 -2
- package/dist/server/server-runtime.d.ts +23 -6
- package/dist/server/session-agent-registry.d.ts +145 -0
- package/dist/server/session-agent-sessions.d.ts +49 -0
- package/dist/server/session-cleanup-scheduler.d.ts +3 -2
- package/dist/server/session-deletion.d.ts +1 -0
- package/dist/server/session-handlers.d.ts +82 -1
- package/dist/server/session-history.d.ts +4 -3
- package/dist/server/session-routes.d.ts +2 -0
- package/dist/server/session-scoped-prefs.d.ts +28 -0
- package/dist/server/setup-events-core-watchers.d.ts +7 -2
- package/dist/server/setup-events-fleet-broadcaster.d.ts +7 -2
- package/dist/server/setup-events-pattern-handlers.d.ts +5 -1
- package/dist/server/setup-events-provider-handlers.d.ts +1 -1
- package/dist/server/setup-events-session-helpers.d.ts +14 -1
- package/dist/server/setup-events-status-watcher.d.ts +7 -2
- package/dist/server/setup-events-subagent-handlers.d.ts +5 -1
- package/dist/server/setup-events-tool-handlers.d.ts +14 -1
- package/dist/server/setup-events.d.ts +21 -1
- package/dist/server/setup-screen.d.ts +3 -2
- package/dist/server/shell-git-routes.d.ts +4 -0
- package/dist/server/standalone-session-identity.d.ts +3 -3
- package/dist/server/start-webui-proxy-apply.d.ts +2 -1
- package/dist/server/start-webui-shutdown.d.ts +15 -0
- package/dist/server/system-prompt-handlers.d.ts +67 -0
- package/dist/server/system-prompt-rebuild.d.ts +45 -0
- package/dist/server/terminal-dashboard.d.ts +145 -0
- package/dist/server/types.d.ts +33 -4
- package/dist/server/webui-status-logger.d.ts +61 -0
- package/dist/server/worklist-routes.d.ts +8 -2
- package/dist/server/worklist-session-context.d.ts +44 -0
- package/dist/server/worktree-ws-handler.d.ts +2 -1
- package/dist/server/ws-payload-validation.d.ts +27 -2
- package/dist/server/ws-utils.d.ts +29 -4
- package/package.json +15 -14
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type { EventBus } from '@wrongstack/core/kernel';
|
|
2
1
|
import { AgentStatusTracker } from '@wrongstack/core/coordination';
|
|
2
|
+
import type { EventBus } from '@wrongstack/core/kernel';
|
|
3
3
|
import { getSessionRegistry } from '@wrongstack/core/storage';
|
|
4
4
|
import type { Config, Logger } from '@wrongstack/core/types';
|
|
5
|
-
|
|
5
|
+
interface StandaloneSessionIdentityPaths {
|
|
6
6
|
globalRoot: string;
|
|
7
7
|
projectRoot: string;
|
|
8
8
|
projectSlug: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
interface StandaloneSessionIdentityOptions {
|
|
11
11
|
config: Config;
|
|
12
12
|
events: EventBus;
|
|
13
13
|
logger: Logger;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import type { Provider, ProviderConfig } from '@wrongstack/core/types';
|
|
24
24
|
import type { WebuiDeps, WebuiMutableState } from './routes.js';
|
|
25
|
-
|
|
25
|
+
interface WebuiProxyApplyOptions {
|
|
26
26
|
state: WebuiMutableState;
|
|
27
27
|
deps: WebuiDeps;
|
|
28
28
|
/** Mirrors `cb.updateAutoCompactionMaxContext` in start-webui.ts. */
|
|
@@ -35,4 +35,5 @@ export interface WebuiProxyApplyOptions {
|
|
|
35
35
|
* semantics (effective-URL comparison, serialized rebuilds).
|
|
36
36
|
*/
|
|
37
37
|
export declare function setupWebuiProxyInstantApply(options: WebuiProxyApplyOptions): () => void;
|
|
38
|
+
export {};
|
|
38
39
|
//# sourceMappingURL=start-webui-proxy-apply.d.ts.map
|
|
@@ -17,6 +17,9 @@ export declare function setupWebuiShutdown(options: {
|
|
|
17
17
|
detach: () => Promise<void>;
|
|
18
18
|
};
|
|
19
19
|
stopHeapWatchdog: () => Promise<void>;
|
|
20
|
+
stopLiveStatusLogger?: (() => void) | undefined;
|
|
21
|
+
/** Erase the fixed status panel and restore the raw console. */
|
|
22
|
+
stopTerminalDashboard?: (() => void) | undefined;
|
|
20
23
|
getCredentialWatcherClose: () => (() => void) | undefined;
|
|
21
24
|
getProxyInstantApplyDispose: () => () => void;
|
|
22
25
|
disposeRealtimeHandlers: () => void;
|
|
@@ -44,6 +47,18 @@ export declare function setupWebuiShutdown(options: {
|
|
|
44
47
|
vectorMemoryStore: {
|
|
45
48
|
close(): void;
|
|
46
49
|
} | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Drain every open tab's journal synchronously. Registered as a fatal-exit
|
|
52
|
+
* salvage hook: this host had none at all, so a crash truncated the buffered
|
|
53
|
+
* tail of the leader's journal AND of every other open tab.
|
|
54
|
+
*/
|
|
55
|
+
flushSessionJournalsSync?: (() => void) | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* End and close the journals of every tab that is not the leader's. Without
|
|
58
|
+
* it a clean quit left them with no trailing `session_end`, which is exactly
|
|
59
|
+
* what a crash looks like — the next launch offered them all for recovery.
|
|
60
|
+
*/
|
|
61
|
+
closeSessionJournals?: (() => Promise<void>) | undefined;
|
|
47
62
|
globalConfigPath: string;
|
|
48
63
|
}): () => void;
|
|
49
64
|
//# sourceMappingURL=start-webui-shutdown.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The identity-prompt picker surface: which variants exist, what each costs,
|
|
3
|
+
* which one this session is running, and whether the user has ever chosen.
|
|
4
|
+
*
|
|
5
|
+
* `chosen` is the non-obvious field. The config loader materializes
|
|
6
|
+
* `systemPrompt: { variant: 'default' }` for every config, so the live Config
|
|
7
|
+
* cannot tell "the user picked Standard" from "nobody has ever asked". Only the
|
|
8
|
+
* raw profile config file can — the key is written explicitly on selection — so
|
|
9
|
+
* `chosen: false` is what lets the browser open the picker once on a fresh
|
|
10
|
+
* install and never nag again. It is the same signal the CLI startup menu uses
|
|
11
|
+
* to decide between the full menu and the one-line confirmation.
|
|
12
|
+
*/
|
|
13
|
+
import { type SystemInstructionVariant, type SystemPromptVariantPaths } from '@wrongstack/core/agent';
|
|
14
|
+
/** Everything the picker needs from the host, injected so both WS hosts share it. */
|
|
15
|
+
export interface SystemPromptSurface {
|
|
16
|
+
/** Instruction dirs, resolved the way the SystemPromptBuilder resolves them. */
|
|
17
|
+
paths: () => SystemPromptVariantPaths;
|
|
18
|
+
/** Active profile config — the file whose `systemPrompt.variant` marks a choice. */
|
|
19
|
+
profileConfigPath: string;
|
|
20
|
+
/** The variant the running session is currently built from. */
|
|
21
|
+
current: () => SystemInstructionVariant;
|
|
22
|
+
/**
|
|
23
|
+
* Recompose the live system prompt for the new variant. Persistence is the
|
|
24
|
+
* prefs layer's job; this only refreshes the in-memory prompt so the change
|
|
25
|
+
* takes effect on the next turn instead of the next boot.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Rebuild the live identity prompt. `sessionId` names the tab that asked —
|
|
29
|
+
* each WebUI tab runs its own context, so the rebuild has to land on that
|
|
30
|
+
* one rather than on whichever session the runtime is currently pointing at.
|
|
31
|
+
*/
|
|
32
|
+
applyVariant?: ((variant: SystemInstructionVariant, sessionId?: string) => void | Promise<void>) | undefined;
|
|
33
|
+
}
|
|
34
|
+
export interface SystemPromptVariantInfo {
|
|
35
|
+
variant: SystemInstructionVariant;
|
|
36
|
+
label: string;
|
|
37
|
+
hint: string;
|
|
38
|
+
/** Upper-bound token estimate of the identity block this variant injects. */
|
|
39
|
+
tokens: number;
|
|
40
|
+
}
|
|
41
|
+
export interface SystemPromptInfoPayload {
|
|
42
|
+
current: SystemInstructionVariant;
|
|
43
|
+
/** False until the user has explicitly picked a variant at least once. */
|
|
44
|
+
chosen: boolean;
|
|
45
|
+
variants: SystemPromptVariantInfo[];
|
|
46
|
+
/** Set when the token estimate could not be computed; variants still list. */
|
|
47
|
+
error?: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Compose the picker payload. Token counting reads the bundled/global/project
|
|
51
|
+
* instruction files, so a failure there (unreadable override dir, for instance)
|
|
52
|
+
* degrades to zero counts rather than denying the user the picker entirely.
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* The variant catalogue, plus which variant is live.
|
|
56
|
+
*
|
|
57
|
+
* The catalogue (labels, token costs, whether the user has ever chosen) is a
|
|
58
|
+
* project fact and the same for every tab. `current` is NOT: the identity
|
|
59
|
+
* variant is a per-session preference, so a tab that picked "lite" must not be
|
|
60
|
+
* told it is on the "pro" another tab just selected. `currentOverride` carries
|
|
61
|
+
* the asking session's own value; without one the config default stands, which
|
|
62
|
+
* is what a single-session host wants.
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildSystemPromptInfo(surface: SystemPromptSurface, currentOverride?: string | undefined): Promise<SystemPromptInfoPayload>;
|
|
65
|
+
/** Payload for a host that never wired the picker — the browser hides it. */
|
|
66
|
+
export declare function unavailableSystemPromptInfo(): SystemPromptInfoPayload;
|
|
67
|
+
//# sourceMappingURL=system-prompt-handlers.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuild the live system prompt after something that feeds it changed.
|
|
3
|
+
*
|
|
4
|
+
* Two things can move underneath a running session: the active mode (which
|
|
5
|
+
* contributes a whole prompt layer) and the identity variant (Lite / Standard /
|
|
6
|
+
* Pro, which selects `system.md` vs `system-lite.md` vs `system-pro.md`). Both
|
|
7
|
+
* need the exact same eleven-dependency `DefaultSystemPromptBuilder` call, and
|
|
8
|
+
* a second copy of that call is a second place to forget `injectMemory: false`
|
|
9
|
+
* — which would double-inject SAGE memories, since its turn middleware is the
|
|
10
|
+
* single memory channel.
|
|
11
|
+
*/
|
|
12
|
+
import { type Context, DefaultSystemPromptBuilder } from '@wrongstack/core/agent';
|
|
13
|
+
import { type Container } from '@wrongstack/core/kernel';
|
|
14
|
+
import type { ToolRegistry } from '@wrongstack/core/registry';
|
|
15
|
+
import type { Config, MemoryPort, ModeStore, SkillLoader } from '@wrongstack/core/types';
|
|
16
|
+
type ModelCapabilities = NonNullable<ConstructorParameters<typeof DefaultSystemPromptBuilder>[0]>['modelCapabilities'];
|
|
17
|
+
export interface SystemPromptRebuildDeps {
|
|
18
|
+
modeStore: ModeStore | undefined;
|
|
19
|
+
memoryStore: MemoryPort | undefined;
|
|
20
|
+
skillLoader: SkillLoader | undefined;
|
|
21
|
+
modelCapabilities: ModelCapabilities;
|
|
22
|
+
context: Context;
|
|
23
|
+
toolRegistry: ToolRegistry;
|
|
24
|
+
getConfig: () => Pick<Config, 'provider' | 'model' | 'systemPrompt' | 'features'>;
|
|
25
|
+
projectRoot: string;
|
|
26
|
+
globalRoot: string;
|
|
27
|
+
/**
|
|
28
|
+
* When supplied, the freshly built builder replaces the container-bound one.
|
|
29
|
+
*
|
|
30
|
+
* Matters for the identity variant specifically: the boot-time builder has
|
|
31
|
+
* the old variant baked into its `instructionPaths`, and everything that
|
|
32
|
+
* resolves `TOKENS.SystemPromptBuilder` later — the subagent factory, most
|
|
33
|
+
* visibly — would otherwise keep composing subagent prompts from the variant
|
|
34
|
+
* the user just moved away from.
|
|
35
|
+
*/
|
|
36
|
+
container?: Container | undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Recompose `context.systemPrompt` for `modeId` using the variant that context
|
|
40
|
+
* is running. Mutates the context in place; the caller decides what to
|
|
41
|
+
* broadcast afterwards.
|
|
42
|
+
*/
|
|
43
|
+
export declare function rebuildSystemPrompt(deps: SystemPromptRebuildDeps, modeId: string): Promise<void>;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=system-prompt-rebuild.d.ts.map
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal dashboard — the WebUI host's tidy console surface.
|
|
3
|
+
*
|
|
4
|
+
* The server process talks to the terminal through raw `console.*` calls
|
|
5
|
+
* scattered across dozens of modules (structured JSON warn/error lines,
|
|
6
|
+
* `[WebUI] …` progress chatter) and, on top of that, a live status block
|
|
7
|
+
* that used to be re-printed on every state change. With four tabs running
|
|
8
|
+
* those streams interleaved into an unreadable wall of text.
|
|
9
|
+
*
|
|
10
|
+
* This module is the single coordinator for both hosts (standalone server
|
|
11
|
+
* and the CLI-embedded `wstack --webui`):
|
|
12
|
+
*
|
|
13
|
+
* - **A fixed status panel at the bottom.** Session rows (running/idle,
|
|
14
|
+
* iteration, subagents, elapsed) are redrawn IN PLACE with ANSI cursor
|
|
15
|
+
* moves instead of appended, so the stats stay visible without growing
|
|
16
|
+
* the scrollback. `setSessions` is fingerprint-gated: identical rows
|
|
17
|
+
* never rewrite the panel.
|
|
18
|
+
*
|
|
19
|
+
* - **An ordered log stream above the panel.** Every forwarded
|
|
20
|
+
* `console.*` line erases the panel, prints with a `HH:MM:SS LEVEL`
|
|
21
|
+
* prefix, then redraws the panel — a log line can never land mid-panel.
|
|
22
|
+
* Structured JSON lines (the `{level,event,message,…}` shape the log
|
|
23
|
+
* shims emit) are rendered as readable single lines.
|
|
24
|
+
*
|
|
25
|
+
* - **Noise control.** Identical consecutive lines collapse into one
|
|
26
|
+
* `↑ previous line repeated N×` notice, and `quiet` mode keeps
|
|
27
|
+
* `log/info/debug` chatter out of the terminal entirely (ring-buffered
|
|
28
|
+
* for a failure dump) while `warn/error` still flow — the contract the
|
|
29
|
+
* CLI host's quiet surface used to own.
|
|
30
|
+
*
|
|
31
|
+
* Non-TTY output and `WEBUI_VERBOSE=1` bypass everything: redirected
|
|
32
|
+
* output and log collectors keep the complete append-only log.
|
|
33
|
+
*/
|
|
34
|
+
/** Minimal console surface the dashboard can wrap (injectable for tests). */
|
|
35
|
+
export interface DashboardConsoleTarget {
|
|
36
|
+
log: (...args: unknown[]) => void;
|
|
37
|
+
info: (...args: unknown[]) => void;
|
|
38
|
+
warn: (...args: unknown[]) => void;
|
|
39
|
+
error: (...args: unknown[]) => void;
|
|
40
|
+
debug: (...args: unknown[]) => void;
|
|
41
|
+
}
|
|
42
|
+
/** Minimal stdout surface for panel drawing (injectable for tests). */
|
|
43
|
+
export interface DashboardStdout {
|
|
44
|
+
isTTY?: boolean | undefined;
|
|
45
|
+
columns?: number | undefined;
|
|
46
|
+
write(chunk: string): void;
|
|
47
|
+
}
|
|
48
|
+
/** One session row on the panel. Built by the live-status logger. */
|
|
49
|
+
export interface DashboardSessionRow {
|
|
50
|
+
id: string;
|
|
51
|
+
provider: string;
|
|
52
|
+
model: string;
|
|
53
|
+
isRunning: boolean;
|
|
54
|
+
iteration?: {
|
|
55
|
+
index: number;
|
|
56
|
+
max?: number | undefined;
|
|
57
|
+
} | undefined;
|
|
58
|
+
runningSubagents: number;
|
|
59
|
+
totalSubagents: number;
|
|
60
|
+
/** Epoch ms when the current run started, for the elapsed column. */
|
|
61
|
+
runningSince?: number | undefined;
|
|
62
|
+
agents?: readonly DashboardAgentRow[] | undefined;
|
|
63
|
+
}
|
|
64
|
+
/** One leader/subagent row nested under a session branch. */
|
|
65
|
+
export interface DashboardAgentRow {
|
|
66
|
+
id: string;
|
|
67
|
+
label: string;
|
|
68
|
+
provider: string;
|
|
69
|
+
model: string;
|
|
70
|
+
status: string;
|
|
71
|
+
iteration?: {
|
|
72
|
+
index: number;
|
|
73
|
+
max?: number | undefined;
|
|
74
|
+
} | undefined;
|
|
75
|
+
toolCalls: number;
|
|
76
|
+
/** Epoch ms while the agent is still active. */
|
|
77
|
+
startedAt?: number | undefined;
|
|
78
|
+
/** Final elapsed time for completed agents. */
|
|
79
|
+
durationMs?: number | undefined;
|
|
80
|
+
}
|
|
81
|
+
export interface TerminalDashboardOptions {
|
|
82
|
+
/** Panel title, e.g. `WebUI` / `SimpleUI`. */
|
|
83
|
+
title?: string | undefined;
|
|
84
|
+
/** Live URL shown in the panel header (token-less). */
|
|
85
|
+
getUrl?: (() => string | undefined) | undefined;
|
|
86
|
+
stdout?: DashboardStdout | undefined;
|
|
87
|
+
consoleTarget?: DashboardConsoleTarget | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Mute `log/info/debug` chatter into the ring buffer; only `warn/error`
|
|
90
|
+
* reach the terminal. The CLI-embedded host defaults this on (the browser
|
|
91
|
+
* owns the chatter), the standalone host off.
|
|
92
|
+
*/
|
|
93
|
+
quiet?: boolean | undefined;
|
|
94
|
+
/** Pass EVERYTHING through untouched — the `WEBUI_VERBOSE=1` escape hatch. */
|
|
95
|
+
verbose?: boolean | undefined;
|
|
96
|
+
/** Ring-buffer size for {@link TerminalDashboard.recent}. */
|
|
97
|
+
bufferLines?: number | undefined;
|
|
98
|
+
/** Max session rows drawn before a `+N more` overflow line. */
|
|
99
|
+
maxRows?: number | undefined;
|
|
100
|
+
/** Max visible log lines kept above the live status tree. */
|
|
101
|
+
maxLogRows?: number | undefined;
|
|
102
|
+
now?: (() => number) | undefined;
|
|
103
|
+
}
|
|
104
|
+
export interface TerminalDashboard {
|
|
105
|
+
/** `false` when the console was left untouched (non-TTY or verbose). */
|
|
106
|
+
readonly enabled: boolean;
|
|
107
|
+
/** Chatter lines dropped from the terminal so far (quiet mode). */
|
|
108
|
+
readonly mutedCount: number;
|
|
109
|
+
/** Newest muted lines, oldest first — for a diagnostic dump on failure. */
|
|
110
|
+
recent(): readonly string[];
|
|
111
|
+
/** Redraw the status panel in place. No-op when the rows are unchanged. */
|
|
112
|
+
setSessions(rows: readonly DashboardSessionRow[]): void;
|
|
113
|
+
/** Erase the panel, flush pending notices, restore the console. Idempotent. */
|
|
114
|
+
stop(): void;
|
|
115
|
+
}
|
|
116
|
+
export declare function isWebUIVerboseEnv(env?: Record<string, string | undefined>): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Render one structured `{level,event,message,…}` JSON line into a body
|
|
119
|
+
* (event, message, `sess:` tag, scalar extras) plus the record's own level.
|
|
120
|
+
* The caller stamps the timestamp and level tag exactly once — returning the
|
|
121
|
+
* full line here would double-stamp. Returns `null` when the line is not a
|
|
122
|
+
* structured record, in which case the raw text is shown as-is.
|
|
123
|
+
*/
|
|
124
|
+
export declare function prettifyStructuredLine(raw: string, colorize: boolean): {
|
|
125
|
+
level: string;
|
|
126
|
+
text: string;
|
|
127
|
+
} | null;
|
|
128
|
+
/**
|
|
129
|
+
* Build the panel lines for the current session rows. Pure — exported for
|
|
130
|
+
* tests. Lines are plain (no ANSI); the caller colorizes.
|
|
131
|
+
*/
|
|
132
|
+
export declare function renderSessionPanelLines(rows: readonly DashboardSessionRow[], options: {
|
|
133
|
+
title: string;
|
|
134
|
+
url?: string | undefined;
|
|
135
|
+
maxRows?: number | undefined;
|
|
136
|
+
width?: number | undefined;
|
|
137
|
+
now?: number | undefined;
|
|
138
|
+
}): string[];
|
|
139
|
+
/**
|
|
140
|
+
* Start the dashboard. Disabled (console untouched, panel never drawn) on a
|
|
141
|
+
* non-TTY stdout or when `verbose` is set — redirected output and log
|
|
142
|
+
* collectors keep the complete append-only log.
|
|
143
|
+
*/
|
|
144
|
+
export declare function startTerminalDashboard(options?: TerminalDashboardOptions): TerminalDashboard;
|
|
145
|
+
//# sourceMappingURL=terminal-dashboard.d.ts.map
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { WebSocket } from 'ws';
|
|
2
|
-
import type { TrustBoundary } from '@wrongstack/core/security';
|
|
3
|
-
import type { ConfigStore, ModelsRegistry, SecretVault, SessionStore } from '@wrongstack/core/types';
|
|
4
|
-
import type { JournalEntry } from '@wrongstack/core/storage';
|
|
5
1
|
import type { Agent, AgentPipelines } from '@wrongstack/core/agent';
|
|
6
2
|
import type { EventBus } from '@wrongstack/core/kernel';
|
|
7
3
|
import type { ToolRegistry } from '@wrongstack/core/registry';
|
|
4
|
+
import type { TrustBoundary } from '@wrongstack/core/security';
|
|
5
|
+
import type { JournalEntry } from '@wrongstack/core/storage';
|
|
6
|
+
import type { ConfigStore, ModelsRegistry, SecretVault, SessionStore } from '@wrongstack/core/types';
|
|
7
|
+
import type { WebSocket } from 'ws';
|
|
8
8
|
/** Compatibility envelope; new boundaries should decode to CanonicalServerMessage. */
|
|
9
9
|
export interface WSServerMessage {
|
|
10
10
|
type: string;
|
|
@@ -84,6 +84,20 @@ export interface WebUIOptions {
|
|
|
84
84
|
* webui an observer slot.
|
|
85
85
|
*/
|
|
86
86
|
subscribeEternalIteration?: ((fn: (entry: JournalEntry) => void) => () => void) | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Stop every subagent that ONE session spawned.
|
|
89
|
+
*
|
|
90
|
+
* Aborting a session's run only unwinds the workers the leader is blocked
|
|
91
|
+
* on. Anything started with `spawn_subagent` + `assign_task` keeps running
|
|
92
|
+
* because nothing asked it to stop — so a tab's Stop button silenced the
|
|
93
|
+
* leader while its fleet ground on in the background. The host owns the
|
|
94
|
+
* Director, so it supplies the cascade; the webui server only knows WHICH
|
|
95
|
+
* session was stopped.
|
|
96
|
+
*
|
|
97
|
+
* Session-scoped by contract: with four tabs live, stopping one tab must
|
|
98
|
+
* never reach into another tab's fleet.
|
|
99
|
+
*/
|
|
100
|
+
stopSessionFleet?: ((sessionId: string) => void | Promise<void>) | undefined;
|
|
87
101
|
}
|
|
88
102
|
export interface BackendServices {
|
|
89
103
|
agent: Agent;
|
|
@@ -98,7 +112,22 @@ export interface BackendServices {
|
|
|
98
112
|
}
|
|
99
113
|
export interface ConnectedClient {
|
|
100
114
|
ws: WebSocket;
|
|
115
|
+
/**
|
|
116
|
+
* The session this connection last acted on. Kept for the abort-on-close
|
|
117
|
+
* path and for surfaces that only ever show one session at a time.
|
|
118
|
+
*/
|
|
101
119
|
sessionId: string | null;
|
|
120
|
+
/**
|
|
121
|
+
* EVERY session this connection is displaying.
|
|
122
|
+
*
|
|
123
|
+
* One browser page holds up to four tabs on ONE socket, so `sessionId`
|
|
124
|
+
* alone describes only whichever tab the user last touched — filtering
|
|
125
|
+
* broadcasts by it dropped the other three tabs' runs before they left the
|
|
126
|
+
* server. The client declares its open set with `session.subscribe`; an
|
|
127
|
+
* empty set means "not declared", and such a client falls back to the
|
|
128
|
+
* single-session filter.
|
|
129
|
+
*/
|
|
130
|
+
sessionIds?: Set<string> | undefined;
|
|
102
131
|
connectedAt: number;
|
|
103
132
|
/** Remote socket address captured for verbose rejection logging. */
|
|
104
133
|
remoteAddress?: string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live status tracker for the WebUI host terminal.
|
|
3
|
+
*
|
|
4
|
+
* Subscribes to the agent/iteration events, merges them with the host's
|
|
5
|
+
* session list, and feeds one {@link DashboardSessionRow} per session to the
|
|
6
|
+
* terminal dashboard's fixed panel — running/idle state, iteration counter,
|
|
7
|
+
* subagent counts and run elapsed time. Redraws are debounced and
|
|
8
|
+
* fingerprint-gated by the dashboard, so bursts of events cost at most one
|
|
9
|
+
* panel repaint, and the heartbeat only refreshes the elapsed column.
|
|
10
|
+
*
|
|
11
|
+
* When the dashboard is disabled (non-TTY output or `WEBUI_VERBOSE=1`) the
|
|
12
|
+
* tracker falls back to printing a compact status block on change — the
|
|
13
|
+
* append-only shape redirected output and log collectors expect.
|
|
14
|
+
*/
|
|
15
|
+
import type { DashboardSessionRow, TerminalDashboard } from './terminal-dashboard.js';
|
|
16
|
+
interface EventBusLike {
|
|
17
|
+
on(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
18
|
+
off(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface StatusSessionInfo {
|
|
21
|
+
id: string;
|
|
22
|
+
model: string;
|
|
23
|
+
provider: string;
|
|
24
|
+
isRunning: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface SubagentRecord {
|
|
27
|
+
id: string;
|
|
28
|
+
role: string;
|
|
29
|
+
status: string;
|
|
30
|
+
provider?: string | undefined;
|
|
31
|
+
model?: string | undefined;
|
|
32
|
+
iteration?: {
|
|
33
|
+
index: number;
|
|
34
|
+
max?: number | undefined;
|
|
35
|
+
} | undefined;
|
|
36
|
+
toolCalls: number;
|
|
37
|
+
startedAt?: number | undefined;
|
|
38
|
+
durationMs?: number | undefined;
|
|
39
|
+
}
|
|
40
|
+
export interface WebUILiveStatusLoggerOptions {
|
|
41
|
+
events: EventBusLike;
|
|
42
|
+
getSessionList: () => StatusSessionInfo[];
|
|
43
|
+
/** The terminal dashboard that owns the fixed panel. */
|
|
44
|
+
dashboard: Pick<TerminalDashboard, 'enabled' | 'setSessions'>;
|
|
45
|
+
debounceMs?: number | undefined;
|
|
46
|
+
heartbeatMs?: number | undefined;
|
|
47
|
+
now?: (() => number) | undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Merge the host session list with the tracked subagents, iterations and
|
|
51
|
+
* run-start timestamps into panel rows. Pure — exported for tests.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildSessionRows(sessions: readonly StatusSessionInfo[], sessionSubagents: ReadonlyMap<string, Map<string, SubagentRecord>>, sessionIterations: ReadonlyMap<string, {
|
|
54
|
+
index: number;
|
|
55
|
+
max?: number | undefined;
|
|
56
|
+
}>, runStartedAt: ReadonlyMap<string, number>, sessionToolCalls?: ReadonlyMap<string, number>): DashboardSessionRow[];
|
|
57
|
+
/** Compact append-only block for non-TTY output (log files, pipes). */
|
|
58
|
+
export declare function formatSessionRowsBlock(rows: readonly DashboardSessionRow[]): string;
|
|
59
|
+
export declare function startWebUILiveStatusLogger(options: WebUILiveStatusLoggerOptions): () => void;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=webui-status-logger.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WebSocket } from 'ws';
|
|
2
|
-
import { type WorklistContext } from './handlers/worklist-handlers.js';
|
|
2
|
+
import { type WorklistContext, type WorklistMessage } from './handlers/worklist-handlers.js';
|
|
3
3
|
import type { WSClientMessage } from './types.js';
|
|
4
4
|
export interface WorklistRouteHandlers {
|
|
5
5
|
getTodos: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;
|
|
@@ -13,7 +13,13 @@ export interface WorklistRouteHandlers {
|
|
|
13
13
|
updatePlanItem: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;
|
|
14
14
|
}
|
|
15
15
|
export interface WorklistRouteContext {
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the worklist context for ONE request. The message is handed over
|
|
18
|
+
* so a multi-session host can bind to the session the payload names instead
|
|
19
|
+
* of whichever session the shared root context currently points at.
|
|
20
|
+
* Hosts that ignore it keep the single-context behaviour.
|
|
21
|
+
*/
|
|
22
|
+
getContext: (message?: WorklistMessage) => WorklistContext;
|
|
17
23
|
allowMessage?: ((ws: WebSocket, message: WSClientMessage) => boolean) | undefined;
|
|
18
24
|
}
|
|
19
25
|
export declare function createWorklistRouteHandlers(ctx: WorklistRouteContext): WorklistRouteHandlers;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Agent, Context } from '@wrongstack/core/agent';
|
|
2
|
+
import type { WebSocket } from 'ws';
|
|
3
|
+
import type { WorklistContext, WorklistMessage } from './handlers/worklist-handlers.js';
|
|
4
|
+
import type { WSServerMessage } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Per-session binding for the worklist routes (todos / tasks / plan).
|
|
7
|
+
*
|
|
8
|
+
* The worklist used to read and write through the shared ROOT context — the
|
|
9
|
+
* one `session.resume` re-points to whichever tab was switched to last. A
|
|
10
|
+
* request stamped with a background tab's session id was therefore *allowed*
|
|
11
|
+
* by the session gate but served (and mutated!) the foreground session's
|
|
12
|
+
* board: every tab showed one shared list, and a click in tab B could rewrite
|
|
13
|
+
* tab A's todos.
|
|
14
|
+
*
|
|
15
|
+
* This factory resolves the context the request actually names:
|
|
16
|
+
*
|
|
17
|
+
* - untagged requests keep the root context (single-session hosts, older
|
|
18
|
+
* clients) — identical to the previous behaviour;
|
|
19
|
+
* - a request naming the root session keeps the root context;
|
|
20
|
+
* - a request naming another session resolves that session's agent
|
|
21
|
+
* (read-only `peekAgent` first, then `getAgent`, which creates one — the
|
|
22
|
+
* four-tab registry with idle eviction is the same one the conversation
|
|
23
|
+
* routes already use).
|
|
24
|
+
*
|
|
25
|
+
* Agents minted while the root sat on a different session inherit the root's
|
|
26
|
+
* meta verbatim, including its `plan.path` / `task.path` sidecar paths. Those
|
|
27
|
+
* are re-scoped to the requested session here, before any read or write can
|
|
28
|
+
* land in the neighbouring session's `.plan.json` / `.tasks.json`.
|
|
29
|
+
*/
|
|
30
|
+
interface SessionWorklistDeps {
|
|
31
|
+
/** Shared root context — bound to whichever session the runtime last activated. */
|
|
32
|
+
rootContext: Context;
|
|
33
|
+
/** Agent for a session WITHOUT creating one; preferred for read paths. */
|
|
34
|
+
peekAgent?: ((sessionId?: string) => Agent | undefined) | undefined;
|
|
35
|
+
/** Agent for a session, creating one when absent (four-tab registry). */
|
|
36
|
+
getAgent?: ((sessionId?: string) => Agent) | undefined;
|
|
37
|
+
/** Sessions directory holding the per-session plan/task/todos sidecars. */
|
|
38
|
+
sessionsDir?: string | undefined;
|
|
39
|
+
send: (ws: WebSocket, msg: WSServerMessage) => void;
|
|
40
|
+
broadcast: (msg: WSServerMessage) => void;
|
|
41
|
+
}
|
|
42
|
+
export declare function createSessionAwareWorklistContext(deps: SessionWorklistDeps): (message?: WorklistMessage | undefined) => WorklistContext;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=worklist-session-context.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { EventBus } from '@wrongstack/core/kernel';
|
|
2
2
|
import type { Logger } from '@wrongstack/core/types';
|
|
3
3
|
import type { WebSocket } from 'ws';
|
|
4
|
-
|
|
4
|
+
interface WorktreeManagementDeps {
|
|
5
5
|
projectRoot: string;
|
|
6
6
|
/** Board snapshot dir — powers the cross-process liveness guard on cleanup. */
|
|
7
7
|
boardsDir: string;
|
|
@@ -100,4 +100,5 @@ export declare class WorktreeWebSocketHandler {
|
|
|
100
100
|
private broadcast;
|
|
101
101
|
private send;
|
|
102
102
|
}
|
|
103
|
+
export {};
|
|
103
104
|
//# sourceMappingURL=worktree-ws-handler.d.ts.map
|
|
@@ -10,9 +10,15 @@ interface ModelSwitchPayload {
|
|
|
10
10
|
provider: string;
|
|
11
11
|
model: string;
|
|
12
12
|
requestId?: string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The tab that asked. Every WebUI tab runs its own session with its own
|
|
15
|
+
* model, so a switch applies to the requesting session's context — not to
|
|
16
|
+
* whichever session the runtime last had in front.
|
|
17
|
+
*/
|
|
18
|
+
sessionId?: string | undefined;
|
|
13
19
|
}
|
|
14
20
|
export declare function validateModelSwitchPayload(payload: unknown): PayloadValidationResult<ModelSwitchPayload>;
|
|
15
|
-
|
|
21
|
+
interface ModelFallbackChoicePayload {
|
|
16
22
|
requestId: string;
|
|
17
23
|
providerId?: string | undefined;
|
|
18
24
|
model?: string | undefined;
|
|
@@ -46,6 +52,15 @@ export interface MailboxSendPayload {
|
|
|
46
52
|
body: string;
|
|
47
53
|
priority: 'low' | 'normal' | 'high';
|
|
48
54
|
replyTo?: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* The tab this message was composed in.
|
|
57
|
+
*
|
|
58
|
+
* Carried because `to: 'leader'` is AMBIGUOUS once a WebUI page holds four
|
|
59
|
+
* sessions: every tab's agent is registered as a leader, so an unscoped
|
|
60
|
+
* message addressed that way is folded into whichever of them happens to
|
|
61
|
+
* poll the mailbox — a "btw" typed in tab 3 steering the run in tab 1.
|
|
62
|
+
*/
|
|
63
|
+
sessionId?: string | undefined;
|
|
49
64
|
}
|
|
50
65
|
export declare function validateMailboxSendPayload(payload: unknown): PayloadValidationResult<MailboxSendPayload>;
|
|
51
66
|
export declare function validateMailboxAgentsPayload(payload: unknown): PayloadValidationResult<MailboxAgentsPayload | undefined>;
|
|
@@ -137,6 +152,16 @@ interface GitDiffPayload {
|
|
|
137
152
|
path: string;
|
|
138
153
|
}
|
|
139
154
|
export declare function validateGitDiffPayload(payload: unknown): PayloadValidationResult<GitDiffPayload>;
|
|
155
|
+
interface GitPathsPayload {
|
|
156
|
+
paths: string[];
|
|
157
|
+
}
|
|
158
|
+
export declare function validateGitStagePayload(payload: unknown): PayloadValidationResult<GitPathsPayload>;
|
|
159
|
+
export declare function validateGitUnstagePayload(payload: unknown): PayloadValidationResult<GitPathsPayload>;
|
|
160
|
+
export declare function validateGitDiscardPayload(payload: unknown): PayloadValidationResult<GitPathsPayload>;
|
|
161
|
+
interface GitCommitPayload {
|
|
162
|
+
message: string;
|
|
163
|
+
}
|
|
164
|
+
export declare function validateGitCommitPayload(payload: unknown): PayloadValidationResult<GitCommitPayload>;
|
|
140
165
|
interface ProjectsAddPayload {
|
|
141
166
|
root: string;
|
|
142
167
|
name?: string;
|
|
@@ -160,7 +185,7 @@ export declare function validateProjectsSelectPayload(payload: unknown): Payload
|
|
|
160
185
|
* configures. The spawn itself is hardened separately by
|
|
161
186
|
* `buildWin32CmdShimInvocation` (CMDI-005).
|
|
162
187
|
*/
|
|
163
|
-
|
|
188
|
+
interface McpServerPayload {
|
|
164
189
|
name: string;
|
|
165
190
|
[key: string]: unknown;
|
|
166
191
|
}
|
|
@@ -14,11 +14,28 @@ export declare function sendSerialized(ws: WebSocket, data: string, frameBytes?:
|
|
|
14
14
|
*/
|
|
15
15
|
export declare function send(ws: WebSocket, msg: object): void;
|
|
16
16
|
/**
|
|
17
|
-
* Broadcast a JSON message to
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Broadcast a JSON message to connected clients.
|
|
18
|
+
*
|
|
19
|
+
* When a sessionId is present in msg.payload, only clients displaying that
|
|
20
|
+
* session receive it — see `clientWantsSession`. Global messages without a
|
|
21
|
+
* sessionId are sent to all connected clients.
|
|
22
|
+
*/
|
|
23
|
+
export declare function broadcast(clients: Map<WebSocket, ConnectedClient>, msg: object, targetSessionId?: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Does this connection display the session a message is addressed to?
|
|
26
|
+
*
|
|
27
|
+
* A page with four tabs open is ONE socket. Deciding delivery from
|
|
28
|
+
* `client.sessionId` — the tab last touched — silently dropped the other
|
|
29
|
+
* three tabs' runs at the wire, which looks exactly like "the background tab
|
|
30
|
+
* stopped working". `sessionIds` is the declared open set (`session.subscribe`);
|
|
31
|
+
* a connection that has not declared one keeps the old single-session filter,
|
|
32
|
+
* so surfaces that only ever show one session are unaffected.
|
|
20
33
|
*/
|
|
21
|
-
export declare function
|
|
34
|
+
export declare function clientWantsSession(client: Pick<ConnectedClient, 'sessionId' | 'sessionIds'>, sessionId: string | undefined): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Broadcast unconditionally to all connected clients.
|
|
37
|
+
*/
|
|
38
|
+
export declare function broadcastAll(clients: Map<WebSocket, ConnectedClient>, msg: object): void;
|
|
22
39
|
/**
|
|
23
40
|
* Send a success/failure result message (used by key.* and provider.* handlers).
|
|
24
41
|
* The frontend expects `key.operation_result` with `{ success, message }`.
|
|
@@ -54,4 +71,12 @@ export declare function buildWebUIAccessUrl(opts: {
|
|
|
54
71
|
publicUrl?: string | undefined;
|
|
55
72
|
}): string;
|
|
56
73
|
export declare function envFlag(name: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The session a client message names, or undefined. Session-scoped replies
|
|
76
|
+
* (`brain.status`, `/diag`) use it so the answer describes the tab that asked
|
|
77
|
+
* rather than whichever session the runtime happens to be on.
|
|
78
|
+
*/
|
|
79
|
+
export declare function messageSessionId(msg: {
|
|
80
|
+
payload?: unknown;
|
|
81
|
+
}): string | undefined;
|
|
57
82
|
//# sourceMappingURL=ws-utils.d.ts.map
|