@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
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-agent-registry.ts — one Agent per open tab.
|
|
3
|
+
*
|
|
4
|
+
* `Agent.run()` refuses to run twice on the same instance, and it is right to:
|
|
5
|
+
* a run mutates `ctx.signal`, `ctx.messages`, the session writer, token
|
|
6
|
+
* bookkeeping and compaction state, none of which survive two runs racing
|
|
7
|
+
* through them. So "four tabs running at once" is not a matter of relaxing that
|
|
8
|
+
* guard — it is a matter of there being four Agents.
|
|
9
|
+
*
|
|
10
|
+
* The embedded WebUI host had exactly one, shared by every tab, and handed it
|
|
11
|
+
* out no matter which session asked. Starting a run in a second tab therefore
|
|
12
|
+
* hit the guard head-on:
|
|
13
|
+
*
|
|
14
|
+
* [agent.run] Agent.run() is already in progress on this instance.
|
|
15
|
+
*
|
|
16
|
+
* This registry is the missing half. It hands each session its own Agent,
|
|
17
|
+
* cloned from the leader's wiring — same container, tools, providers, events,
|
|
18
|
+
* pipelines and executor, its own `Context`. Everything shared is deliberately
|
|
19
|
+
* shared (the tool registry and provider registry are stateless surfaces; the
|
|
20
|
+
* event bus is how the host observes every tab). Everything per-run is not.
|
|
21
|
+
*/
|
|
22
|
+
import { Agent } from '@wrongstack/core/agent';
|
|
23
|
+
import type { ModelsRegistry, TokenCounter } from '@wrongstack/core/types';
|
|
24
|
+
export interface SessionAgentRegistryOptions {
|
|
25
|
+
/**
|
|
26
|
+
* The leader Agent. Supplies both the wiring every session agent inherits
|
|
27
|
+
* and the identity of the boot session, which keeps using it.
|
|
28
|
+
*/
|
|
29
|
+
template: Agent;
|
|
30
|
+
/** Hard ceiling on live agents. Matches the four-tab ceiling. */
|
|
31
|
+
maxAgents?: number | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Is this session mid-run? Consulted before eviction — a running agent owns
|
|
34
|
+
* a live transcript that exists nowhere else.
|
|
35
|
+
*/
|
|
36
|
+
isRunActive?: ((sessionId: string) => boolean) | undefined;
|
|
37
|
+
/** Called once, right after a new session agent is constructed. */
|
|
38
|
+
onCreate?: ((agent: Agent, sessionId: string) => void) | undefined;
|
|
39
|
+
/** Models registry, so a session's own counter can price its own usage. */
|
|
40
|
+
modelsRegistry?: ModelsRegistry | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Override how a session's Agent is built. The default clones the template's
|
|
43
|
+
* wiring; a caller that already owns an Agent per session (or a test that
|
|
44
|
+
* does not want a whole container) supplies its own.
|
|
45
|
+
*/
|
|
46
|
+
createAgent?: ((sessionId: string) => Agent) | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Is any connected surface currently showing this session?
|
|
49
|
+
*
|
|
50
|
+
* Consulted before eviction. Without it the victim is simply the oldest
|
|
51
|
+
* non-running entry, which is routinely a tab the user still has open while
|
|
52
|
+
* the agents of tabs they closed minutes ago sit untouched — the open tab
|
|
53
|
+
* then loses its in-memory transcript and comes back empty.
|
|
54
|
+
*/
|
|
55
|
+
isDisplayed?: ((sessionId: string) => boolean) | undefined;
|
|
56
|
+
}
|
|
57
|
+
export interface SessionAgentRegistry {
|
|
58
|
+
/**
|
|
59
|
+
* The Agent for a session; the leader's when no session is named.
|
|
60
|
+
*
|
|
61
|
+
* CREATES one when the id is unknown, so this is for callers that own the
|
|
62
|
+
* session (a run, a session transition). Read-only callers must use `peek`:
|
|
63
|
+
* `get` on a stale id materialises an agent and can evict a live one.
|
|
64
|
+
*/
|
|
65
|
+
get(sessionId?: string | undefined): Agent;
|
|
66
|
+
/** The Agent for a session, or undefined. Never creates, never evicts. */
|
|
67
|
+
peek(sessionId?: string | undefined): Agent | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Does this session have an agent with a REAL session writer?
|
|
70
|
+
*
|
|
71
|
+
* A freshly created agent carries a placeholder writer until the session
|
|
72
|
+
* transition that owns the id installs the real one, so `has` alone does not
|
|
73
|
+
* mean the session can be written to.
|
|
74
|
+
*/
|
|
75
|
+
isLive(sessionId: string): boolean;
|
|
76
|
+
has(sessionId: string): boolean;
|
|
77
|
+
ids(): string[];
|
|
78
|
+
/** Forget a session's agent, keeping its journal open. */
|
|
79
|
+
drop(sessionId: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* End a session for good: `session_end`, close, forget.
|
|
82
|
+
*
|
|
83
|
+
* What a CLOSED TAB gets. `drop` alone left the journal open with no
|
|
84
|
+
* terminal marker, which is indistinguishable from a journal a crash left
|
|
85
|
+
* hanging — so every tab the user closed on purpose came back on the
|
|
86
|
+
* recovery list, and its history entry had no outcome.
|
|
87
|
+
*/
|
|
88
|
+
endAndClose(sessionId: string): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Drain every open session journal to disk, synchronously.
|
|
91
|
+
*
|
|
92
|
+
* For fatal-exit salvage only (crash-shield, `process.on('exit')`). The
|
|
93
|
+
* per-session writers buffer non-critical records for up to a flush window,
|
|
94
|
+
* and the host's own salvage hook only knows the LEADER's writer — so a
|
|
95
|
+
* crash silently truncated the tail of every other open tab.
|
|
96
|
+
*/
|
|
97
|
+
flushAllSync(): void;
|
|
98
|
+
/**
|
|
99
|
+
* End and close every non-leader session journal.
|
|
100
|
+
*
|
|
101
|
+
* Clean shutdown only. Without it, quitting a host with three background
|
|
102
|
+
* tabs left three journals with no trailing `session_end`, which is exactly
|
|
103
|
+
* how a crash looks: the next launch offered all three for recovery. The
|
|
104
|
+
* leader's own journal is left alone — its host teardown owns it.
|
|
105
|
+
*/
|
|
106
|
+
closeAll(): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* A token counter that answers for ONE session while still feeding the
|
|
110
|
+
* process-wide one.
|
|
111
|
+
*
|
|
112
|
+
* Four tabs shared a single counter, so every per-session question it was
|
|
113
|
+
* asked came back as the sum of all four: the Inspector's token, cost and
|
|
114
|
+
* cache figures for a tab, the usage stamped into a session's `session_end`
|
|
115
|
+
* record, the before/after numbers on a compaction report. Reads here are this
|
|
116
|
+
* session's own; `account` still forwards, so process-wide consumers (budget
|
|
117
|
+
* watchdog, shutdown totals, project switch) keep seeing everything.
|
|
118
|
+
*
|
|
119
|
+
* Deliberately constructed WITHOUT an event bus: the root counter already
|
|
120
|
+
* emits `token.accounted` for every call, and a second emitter would double
|
|
121
|
+
* every downstream tally.
|
|
122
|
+
*/
|
|
123
|
+
export declare function createSessionTokenCounter(opts: {
|
|
124
|
+
root: TokenCounter;
|
|
125
|
+
sessionId: string;
|
|
126
|
+
registry?: ModelsRegistry | undefined;
|
|
127
|
+
providerId?: (() => string | undefined) | undefined;
|
|
128
|
+
}): TokenCounter;
|
|
129
|
+
/**
|
|
130
|
+
* The part of the leader's meta a NEW conversation may inherit.
|
|
131
|
+
*
|
|
132
|
+
* Host-level facts (mode, feature flags, the resolved window size) describe the
|
|
133
|
+
* project, so a fresh tab starts configured rather than bare. The
|
|
134
|
+
* SESSION-SCOPED PREFERENCES are removed, and that is the point: they are
|
|
135
|
+
* per-conversation by design (YOLO, autonomy, the iteration ceiling, the
|
|
136
|
+
* context strategy, the Lite/Standard/Pro identity), and the leader's meta is
|
|
137
|
+
* not the project's copy of them — it is whatever the FIRST TAB last chose.
|
|
138
|
+
* Copying it started a brand-new conversation under another tab's settings,
|
|
139
|
+
* YOLO included. Each of those keys already falls back to the project default
|
|
140
|
+
* when absent, so leaving them off is exactly "starts clean"; the tab's own
|
|
141
|
+
* first choice writes its own.
|
|
142
|
+
*/
|
|
143
|
+
export declare function inheritedSessionMeta(rootMeta: Record<string, unknown>): Record<string, unknown>;
|
|
144
|
+
export declare function createSessionAgentRegistry(opts: SessionAgentRegistryOptions): SessionAgentRegistry;
|
|
145
|
+
//# sourceMappingURL=session-agent-registry.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { SessionEvent } from '@wrongstack/core/types';
|
|
2
|
+
/** One transcript line, as `AgentMonitorService` stores it. */
|
|
3
|
+
export interface AgentTranscriptLine {
|
|
4
|
+
id: string;
|
|
5
|
+
subagentId: string;
|
|
6
|
+
agentName: string;
|
|
7
|
+
ts: string;
|
|
8
|
+
kind: string;
|
|
9
|
+
content: string;
|
|
10
|
+
iteration: number;
|
|
11
|
+
toolName?: string | undefined;
|
|
12
|
+
toolOk?: boolean | undefined;
|
|
13
|
+
costUsd?: number | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Structural shape of `AgentMonitorService.loadSessionsFromDisk`'s rows. */
|
|
16
|
+
export interface AgentVirtualSessionLike {
|
|
17
|
+
subagentId: string;
|
|
18
|
+
agentName?: string | undefined;
|
|
19
|
+
status?: string | undefined;
|
|
20
|
+
task?: string | undefined;
|
|
21
|
+
transcript?: AgentTranscriptLine[] | undefined;
|
|
22
|
+
}
|
|
23
|
+
/** What `session.start` carries for one subagent. */
|
|
24
|
+
export interface AgentSessionPayload {
|
|
25
|
+
subagentId: string;
|
|
26
|
+
agentName?: string | undefined;
|
|
27
|
+
status?: string | undefined;
|
|
28
|
+
task?: string | undefined;
|
|
29
|
+
role?: string | undefined;
|
|
30
|
+
provider?: string | undefined;
|
|
31
|
+
model?: string | undefined;
|
|
32
|
+
startedAt?: string | undefined;
|
|
33
|
+
endedAt?: string | undefined;
|
|
34
|
+
transcript?: AgentTranscriptLine[] | undefined;
|
|
35
|
+
}
|
|
36
|
+
export type LoadAgentSessions = (subagentIds: readonly string[]) => Promise<AgentVirtualSessionLike[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Build the `agentSessions` field of a `session.start` payload.
|
|
39
|
+
*
|
|
40
|
+
* Returns an empty array — never a partial one — when the journal names no
|
|
41
|
+
* agents, so a session that never delegated costs nothing.
|
|
42
|
+
*
|
|
43
|
+
* The journal's status wins over the monitor's. The monitor reports
|
|
44
|
+
* `'restored'` for anything it read back from disk, which says only "this
|
|
45
|
+
* process did not watch it run"; the journal knows whether the agent finished,
|
|
46
|
+
* failed, or was still going when the file ended.
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildAgentSessionsPayload(events: readonly SessionEvent[] | undefined, load: LoadAgentSessions | undefined): Promise<AgentSessionPayload[]>;
|
|
49
|
+
//# sourceMappingURL=session-agent-sessions.d.ts.map
|
|
@@ -2,11 +2,11 @@ import type { Logger } from '@wrongstack/core/types';
|
|
|
2
2
|
import { type SessionDeletionContext } from './session-deletion.js';
|
|
3
3
|
export declare const DEFAULT_EMPTY_SESSION_CLEANUP_INTERVAL_MS: number;
|
|
4
4
|
export declare const EMPTY_SESSION_CLEANUP_INTERVAL_ENV = "WRONGSTACK_EMPTY_SESSION_CLEANUP_INTERVAL_MS";
|
|
5
|
-
|
|
5
|
+
interface EmptySessionCleanupContext extends SessionDeletionContext {
|
|
6
6
|
hasParticipants: (sessionId: string) => boolean;
|
|
7
7
|
logger: Pick<Logger, 'info' | 'error'>;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
interface EmptySessionCleanupResult {
|
|
10
10
|
deleted: number;
|
|
11
11
|
errors: number;
|
|
12
12
|
}
|
|
@@ -23,4 +23,5 @@ export declare function scheduleOwnerlessEmptySessionCleanup(ctx: EmptySessionCl
|
|
|
23
23
|
dispose: () => Promise<void>;
|
|
24
24
|
runNow: () => Promise<EmptySessionCleanupResult>;
|
|
25
25
|
};
|
|
26
|
+
export {};
|
|
26
27
|
//# sourceMappingURL=session-cleanup-scheduler.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SessionStore } from '@wrongstack/core/types';
|
|
2
2
|
export interface SessionDeletionContext {
|
|
3
3
|
getActiveSessionId: () => string;
|
|
4
|
+
getActiveSessionIds?: (() => string[]) | undefined;
|
|
4
5
|
getSessionStore: () => SessionStore;
|
|
5
6
|
refreshSessions: () => Promise<void>;
|
|
6
7
|
}
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
* as getters/setters so this stays a pure function of its context. Handler
|
|
10
10
|
* bodies are a verbatim lift — only dependency references changed.
|
|
11
11
|
*/
|
|
12
|
-
import type { Context } from '@wrongstack/core/agent';
|
|
12
|
+
import type { Agent, Context } from '@wrongstack/core/agent';
|
|
13
13
|
import type { createStrategyCompactor } from '@wrongstack/core/execution';
|
|
14
14
|
import type { EventBus } from '@wrongstack/core/kernel';
|
|
15
15
|
import type { ToolRegistry } from '@wrongstack/core/registry';
|
|
16
16
|
import type { SessionStore, TokenCounter } from '@wrongstack/core/types';
|
|
17
17
|
import type { WebSocket } from 'ws';
|
|
18
18
|
import type { CustomModeStore } from './custom-context-modes.js';
|
|
19
|
+
import type { LoadAgentSessions } from './session-agent-sessions.js';
|
|
19
20
|
import type { SessionRouteHandlers } from './session-routes.js';
|
|
20
21
|
import type { SessionIdentityTarget } from './standalone-session-identity.js';
|
|
21
22
|
import type { ConnectedClient } from './types.js';
|
|
@@ -26,6 +27,7 @@ type OutboundMessage = {
|
|
|
26
27
|
};
|
|
27
28
|
type SessionStartPayload = {
|
|
28
29
|
sessionId: string;
|
|
30
|
+
startedAt?: string | undefined;
|
|
29
31
|
model: string;
|
|
30
32
|
provider: string;
|
|
31
33
|
maxContext: number;
|
|
@@ -38,6 +40,26 @@ type SessionStartPayload = {
|
|
|
38
40
|
mode: string;
|
|
39
41
|
contextMode: string;
|
|
40
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Every session a connected surface is currently displaying.
|
|
45
|
+
*
|
|
46
|
+
* `client.sessionId` alone is the tab the connection last acted on; a WebUI
|
|
47
|
+
* page holds up to four on one socket and declares them with
|
|
48
|
+
* `session.subscribe`. Deleting or garbage-collecting a session that a
|
|
49
|
+
* background tab is showing is the same class of bug as broadcasting to the
|
|
50
|
+
* wrong tab, so both guards read the declared set.
|
|
51
|
+
*/
|
|
52
|
+
export declare function collectDisplayedSessionIds(ctx: {
|
|
53
|
+
getSession: () => {
|
|
54
|
+
id: string;
|
|
55
|
+
};
|
|
56
|
+
clients?: {
|
|
57
|
+
values(): Iterable<{
|
|
58
|
+
sessionId?: string | null | undefined;
|
|
59
|
+
sessionIds?: ReadonlySet<string> | undefined;
|
|
60
|
+
}>;
|
|
61
|
+
} | undefined;
|
|
62
|
+
}): string[];
|
|
41
63
|
export interface SessionHandlersContext {
|
|
42
64
|
config: {
|
|
43
65
|
provider: string;
|
|
@@ -83,8 +105,67 @@ export interface SessionHandlersContext {
|
|
|
83
105
|
/** When sessionId is provided, abort only that session's run; otherwise abort all. */
|
|
84
106
|
abortActiveRun?: ((sessionId?: string) => void) | undefined;
|
|
85
107
|
isRunActive?: ((sessionId?: string) => boolean) | undefined;
|
|
108
|
+
hasSession?: ((id: string) => boolean) | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Does this host ALREADY hold an open writer for this session?
|
|
111
|
+
*
|
|
112
|
+
* Distinct from `hasSession`, which every multi-session host answers `true`
|
|
113
|
+
* to (it only says "this runtime can serve that id"). Re-opening the journal
|
|
114
|
+
* for a session that is already live leaks a second `FileSessionWriter` and
|
|
115
|
+
* file handle onto the same file, and with four tabs that happens on every
|
|
116
|
+
* single tab click. Hosts that cannot tell leave it undefined and keep the
|
|
117
|
+
* old behaviour.
|
|
118
|
+
*/
|
|
119
|
+
isSessionLive?: ((id: string) => boolean) | undefined;
|
|
120
|
+
/**
|
|
121
|
+
* Sessions that just stopped being displayed by ANY connection.
|
|
122
|
+
*
|
|
123
|
+
* A closed tab leaves its per-session agent — context, transcript, open
|
|
124
|
+
* journal writer — behind, and nothing ever asked for it again. The host
|
|
125
|
+
* uses this to retire them; it must still refuse to retire one whose run is
|
|
126
|
+
* live, because a background run outlives the tab that started it.
|
|
127
|
+
*/
|
|
128
|
+
onSessionsUndisplayed?: ((sessionIds: string[]) => void) | undefined;
|
|
129
|
+
getAgent?: ((sessionId?: string) => Agent) | undefined;
|
|
130
|
+
/**
|
|
131
|
+
* Non-creating registry lookup for READ paths. `getAgent` CREATES on read
|
|
132
|
+
* (and can evict a live tab's agent to make room), so a read such as
|
|
133
|
+
* `context.debug` resolves through this when the host supplies one. A miss
|
|
134
|
+
* here must surface as an explicit "not available" answer — never a silent
|
|
135
|
+
* fallback to the shared root context, which belongs to whichever session
|
|
136
|
+
* the runtime currently points at.
|
|
137
|
+
*/
|
|
138
|
+
peekAgent?: ((sessionId?: string) => Agent | undefined) | undefined;
|
|
86
139
|
sessionStartPayload: (overrides?: Record<string, unknown>) => Promise<SessionStartPayload>;
|
|
140
|
+
systemPrompt?: {
|
|
141
|
+
applyVariant?: (variant: string) => Promise<void>;
|
|
142
|
+
} | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* Host-owned serialiser shared with `createConversationOperations`. When
|
|
145
|
+
* omitted the handlers create a private one, which still orders session
|
|
146
|
+
* transitions against each other but not against run setup.
|
|
147
|
+
*/
|
|
148
|
+
withSessionTransition?: (<T>(operation: () => Promise<T>) => Promise<T>) | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* Read back the transcripts of NAMED subagents (see
|
|
151
|
+
* `session-agent-sessions.ts`). Hosts that run a fleet supply it; hosts that
|
|
152
|
+
* do not leave it undefined and their replays simply carry no subagents.
|
|
153
|
+
*/
|
|
154
|
+
loadAgentSessions?: LoadAgentSessions | undefined;
|
|
87
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Serialiser for operations that re-point a session's runtime context.
|
|
158
|
+
*
|
|
159
|
+
* Session transitions (session.new / session.resume) swap writers, contexts
|
|
160
|
+
* and todo sidecars in several steps. A turn that begins mid-swap would read
|
|
161
|
+
* a half-applied context, so `user_message` setup runs through the SAME gate
|
|
162
|
+
* — which is why this is created once per host and shared, rather than being
|
|
163
|
+
* private to the session handlers.
|
|
164
|
+
*
|
|
165
|
+
* Only the SETUP is gated; agent runs proceed outside it so four tabs still
|
|
166
|
+
* stream concurrently.
|
|
167
|
+
*/
|
|
168
|
+
export declare function createSessionTransitionGate(): <T>(operation: () => Promise<T>) => Promise<T>;
|
|
88
169
|
export declare function createSessionHandlers(ctx: SessionHandlersContext): SessionRouteHandlers;
|
|
89
170
|
export {};
|
|
90
171
|
//# sourceMappingURL=session-handlers.d.ts.map
|
|
@@ -27,19 +27,19 @@ export interface SessionHistoryWireEntry {
|
|
|
27
27
|
outcome?: SessionSummary['outcome'];
|
|
28
28
|
isCurrent: boolean;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
interface SessionInspectEvent {
|
|
31
31
|
ts: string;
|
|
32
32
|
type: SessionEvent['type'];
|
|
33
33
|
label: string;
|
|
34
34
|
detail: string;
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
interface SessionInspectFileEntry {
|
|
37
37
|
operation: string;
|
|
38
38
|
filePath: string;
|
|
39
39
|
toolName: string;
|
|
40
40
|
ts: string;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
interface SessionInspectPayload {
|
|
43
43
|
id: string;
|
|
44
44
|
title: string;
|
|
45
45
|
name?: string | undefined;
|
|
@@ -70,4 +70,5 @@ export declare function buildInspectPayload(summary: SessionSummary | undefined,
|
|
|
70
70
|
}): SessionInspectPayload;
|
|
71
71
|
export declare function toSessionHistoryEntry(summary: SessionSummary, currentSessionId: string): SessionHistoryWireEntry;
|
|
72
72
|
export declare function toSessionHistoryEntries(summaries: SessionSummary[], currentSessionId: string): SessionHistoryWireEntry[];
|
|
73
|
+
export {};
|
|
73
74
|
//# sourceMappingURL=session-history.d.ts.map
|
|
@@ -22,6 +22,8 @@ export interface SessionRouteHandlers {
|
|
|
22
22
|
inspectSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
23
23
|
listCheckpoints: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
24
24
|
rewindSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
25
|
+
/** Declare which sessions this connection is displaying (its open tabs). */
|
|
26
|
+
subscribeSessions: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
25
27
|
}
|
|
26
28
|
export declare function handleSessionRoute(ws: WebSocket, msg: WSClientMessage, handlers: SessionRouteHandlers): Promise<boolean>;
|
|
27
29
|
//# sourceMappingURL=session-routes.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The preference keys that belong to a CONVERSATION, not the project.
|
|
3
|
+
*
|
|
4
|
+
* A leaf module on purpose: this is a plain constant that both the preference
|
|
5
|
+
* handlers and the per-tab agent registry need, and importing it from
|
|
6
|
+
* `prefs-handlers.ts` dragged that module's dependencies (`@wrongstack/tools`
|
|
7
|
+
* among them) into every consumer's module graph.
|
|
8
|
+
*
|
|
9
|
+
* @module session-scoped-prefs
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Preferences that belong to ONE session rather than to the process.
|
|
13
|
+
*
|
|
14
|
+
* Every WebUI tab runs its own session with its own agent context, so these
|
|
15
|
+
* have to land on the calling tab's meta bag: flipping yolo in tab 3 must not
|
|
16
|
+
* hand tab 1's run blanket tool approval, and a context strategy chosen for a
|
|
17
|
+
* long refactor tab must not re-shape a quick question in the tab beside it.
|
|
18
|
+
*
|
|
19
|
+
* Everything NOT listed here (locale, ports, HQ, telegram, feature flags,
|
|
20
|
+
* breaker, proxy, log level…) is genuinely process-wide and keeps its single
|
|
21
|
+
* global home.
|
|
22
|
+
*
|
|
23
|
+
* The browser half is `SESSION_SCOPED_PREFS` in
|
|
24
|
+
* `webui/src/stores/local-prefs.ts`; the two sets must be identical and
|
|
25
|
+
* `webui/tests/server/session-scoped-prefs-parity.test.ts` enforces it.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SESSION_SCOPED_PREF_KEYS: ReadonlySet<string>;
|
|
28
|
+
//# sourceMappingURL=session-scoped-prefs.d.ts.map
|
|
@@ -3,13 +3,18 @@ import type { EventBus } from '@wrongstack/core/kernel';
|
|
|
3
3
|
import type { WstackPaths } from '@wrongstack/core/utils';
|
|
4
4
|
import type { WebSocket } from 'ws';
|
|
5
5
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
6
|
-
|
|
6
|
+
interface SetupEventsCoreWatcherDeps {
|
|
7
7
|
events: EventBus;
|
|
8
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
8
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
9
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
10
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
11
|
+
* tab subscribes to. */
|
|
12
|
+
targetSessionId?: string) => void;
|
|
9
13
|
clients: Map<WebSocket, ConnectedClient>;
|
|
10
14
|
context: Context;
|
|
11
15
|
wpaths?: WstackPaths | undefined;
|
|
12
16
|
}
|
|
13
17
|
export declare function registerSetupEventsCoreWatchers(deps: SetupEventsCoreWatcherDeps): Array<() => void>;
|
|
14
18
|
export declare function registerSetupEventsClientStatusWriter(deps: SetupEventsCoreWatcherDeps): () => void;
|
|
19
|
+
export {};
|
|
15
20
|
//# sourceMappingURL=setup-events-core-watchers.d.ts.map
|
|
@@ -2,14 +2,19 @@ import type { Context } from '@wrongstack/core/agent';
|
|
|
2
2
|
import type { WstackPaths } from '@wrongstack/core/utils';
|
|
3
3
|
import type { WebSocket } from 'ws';
|
|
4
4
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
5
|
-
|
|
5
|
+
interface SetupEventsFleetBroadcasterDeps {
|
|
6
6
|
globalConfigPath?: string | undefined;
|
|
7
7
|
wpaths?: WstackPaths | undefined;
|
|
8
8
|
context: Context;
|
|
9
9
|
clients: Map<WebSocket, ConnectedClient>;
|
|
10
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
10
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
11
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
12
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
13
|
+
* tab subscribes to. */
|
|
14
|
+
targetSessionId?: string) => void;
|
|
11
15
|
onFleetBroadcaster?: ((fn: () => Promise<void>) => void) | undefined;
|
|
12
16
|
isDisposed: () => boolean;
|
|
13
17
|
}
|
|
14
18
|
export declare function registerSetupEventsFleetBroadcaster(deps: SetupEventsFleetBroadcasterDeps): (() => void) | undefined;
|
|
19
|
+
export {};
|
|
15
20
|
//# sourceMappingURL=setup-events-fleet-broadcaster.d.ts.map
|
|
@@ -3,7 +3,11 @@ import type { WebSocket } from 'ws';
|
|
|
3
3
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
4
4
|
export declare function registerSetupEventsPatternHandlers(options: {
|
|
5
5
|
events: EventBus;
|
|
6
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
6
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
7
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
8
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
9
|
+
* tab subscribes to. */
|
|
10
|
+
targetSessionId?: string) => void;
|
|
7
11
|
clients: Map<WebSocket, ConnectedClient>;
|
|
8
12
|
sessionPayload: <T extends Record<string, unknown>>(payload: T) => T;
|
|
9
13
|
}): Array<() => void>;
|
|
@@ -7,7 +7,7 @@ type SetupEventBroadcast = (clients: Map<WebSocket, ConnectedClient>, msg: WSSer
|
|
|
7
7
|
type SessionPayload = <T extends Record<string, unknown>>(payload: T) => T & {
|
|
8
8
|
sessionId: string;
|
|
9
9
|
};
|
|
10
|
-
|
|
10
|
+
interface SetupEventsProviderHandlersDeps {
|
|
11
11
|
on: SetupEventOn;
|
|
12
12
|
broadcast: SetupEventBroadcast;
|
|
13
13
|
clients: Map<WebSocket, ConnectedClient>;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import type { Context } from '@wrongstack/core/agent';
|
|
2
2
|
import type { SessionEventBridge } from '@wrongstack/core/storage';
|
|
3
|
-
|
|
3
|
+
interface SetupEventSessionHelperOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Resolve an audit bridge bound to ONE session's writer.
|
|
6
|
+
*
|
|
7
|
+
* Without it, audit events can only be appended for the session the runtime
|
|
8
|
+
* is currently on, and a background tab's tool/error history is dropped —
|
|
9
|
+
* the tab keeps working, but resuming it later shows a run with no tool
|
|
10
|
+
* record. Hosts that can address a session's writer (the WebUI, via its
|
|
11
|
+
* per-session agent registry) pass this so every tab journals its own work.
|
|
12
|
+
*/
|
|
13
|
+
bridgeForSession?: ((sessionId: string) => SessionEventBridge | undefined) | undefined;
|
|
14
|
+
}
|
|
15
|
+
export declare function createSetupEventSessionHelpers(context: Context, sessionBridge: SessionEventBridge | undefined, options?: SetupEventSessionHelperOptions): {
|
|
4
16
|
currentSessionId: () => string;
|
|
5
17
|
sessionPayload: <T extends Record<string, unknown>>(payload: T) => T & {
|
|
6
18
|
sessionId: string;
|
|
7
19
|
};
|
|
8
20
|
appendForCurrentSession: (sessionId: string | undefined, event: Parameters<SessionEventBridge['append']>[0]) => void;
|
|
9
21
|
};
|
|
22
|
+
export {};
|
|
10
23
|
//# sourceMappingURL=setup-events-session-helpers.d.ts.map
|
|
@@ -3,13 +3,18 @@ import type { WstackPaths } from '@wrongstack/core/utils';
|
|
|
3
3
|
import type { WebSocket } from 'ws';
|
|
4
4
|
import { type FileWatcherMetrics } from './setup-events-watcher.js';
|
|
5
5
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
6
|
-
|
|
6
|
+
interface SetupEventsStatusWatcherDeps {
|
|
7
7
|
wpaths?: WstackPaths | undefined;
|
|
8
8
|
watcherMetrics?: FileWatcherMetrics | undefined;
|
|
9
9
|
clients: Map<WebSocket, ConnectedClient>;
|
|
10
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
10
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
11
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
12
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
13
|
+
* tab subscribes to. */
|
|
14
|
+
targetSessionId?: string) => void;
|
|
11
15
|
on: <E extends EventName>(event: E, listener: Listener<E>) => (() => void) | void;
|
|
12
16
|
isDisposed: () => boolean;
|
|
13
17
|
}
|
|
14
18
|
export declare function registerSetupEventsStatusWatcher(deps: SetupEventsStatusWatcherDeps): (() => void) | undefined;
|
|
19
|
+
export {};
|
|
15
20
|
//# sourceMappingURL=setup-events-status-watcher.d.ts.map
|
|
@@ -5,7 +5,11 @@ import type { SetupEventProjection } from './setup-event-projection.js';
|
|
|
5
5
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
6
6
|
export declare function registerSetupEventsSubagentHandlers(options: {
|
|
7
7
|
on: <E extends EventName>(event: E, listener: Listener<E>) => void;
|
|
8
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
8
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
9
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
10
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
11
|
+
* tab subscribes to. */
|
|
12
|
+
targetSessionId?: string) => void;
|
|
9
13
|
clients: Map<WebSocket, ConnectedClient>;
|
|
10
14
|
context: Context;
|
|
11
15
|
projection?: SetupEventProjection | undefined;
|
|
@@ -7,12 +7,25 @@ import type { SetupEventProjection } from './setup-event-projection.js';
|
|
|
7
7
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
8
8
|
export declare function registerSetupEventsToolHandlers(options: {
|
|
9
9
|
on: <E extends EventName>(event: E, listener: Listener<E>) => void;
|
|
10
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
10
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
11
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
12
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
13
|
+
* tab subscribes to. */
|
|
14
|
+
targetSessionId?: string) => void;
|
|
11
15
|
clients: Map<WebSocket, ConnectedClient>;
|
|
12
16
|
context: Context;
|
|
13
17
|
pendingConfirms: Map<string, PendingConfirm>;
|
|
14
18
|
projection?: SetupEventProjection | undefined;
|
|
15
19
|
sessionPayload: <T extends Record<string, unknown>>(payload: T) => T;
|
|
16
20
|
appendForCurrentSession: (sessionId: string | undefined, event: Parameters<SessionEventBridge['append']>[0]) => void;
|
|
21
|
+
/**
|
|
22
|
+
* The Context of a NAMED session, without creating one. The state blocks
|
|
23
|
+
* below (todos / tasks / plan / side effects) read a session's OWN stores;
|
|
24
|
+
* the shared root context's stores belong to whichever tab is foreground
|
|
25
|
+
* right now. Hosts without a per-session registry may omit it — an event
|
|
26
|
+
* naming an unresolvable session then broadcasts no board at all instead of
|
|
27
|
+
* mis-paired data.
|
|
28
|
+
*/
|
|
29
|
+
sessionContext?: ((sessionId: string) => Context | undefined) | undefined;
|
|
17
30
|
}): void;
|
|
18
31
|
//# sourceMappingURL=setup-events-tool-handlers.d.ts.map
|
|
@@ -10,7 +10,11 @@ import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
|
10
10
|
export type { FileWatcherMetrics } from './setup-events-watcher.js';
|
|
11
11
|
export interface SetupEventsDeps {
|
|
12
12
|
events: EventBus;
|
|
13
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
13
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
14
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
15
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
16
|
+
* tab subscribes to. */
|
|
17
|
+
targetSessionId?: string) => void;
|
|
14
18
|
clients: Map<WebSocket, ConnectedClient>;
|
|
15
19
|
config: {
|
|
16
20
|
tools?: {
|
|
@@ -28,6 +32,22 @@ export interface SetupEventsDeps {
|
|
|
28
32
|
* with no tool history.
|
|
29
33
|
*/
|
|
30
34
|
sessionBridge?: SessionEventBridge | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve an audit bridge for a NAMED session. Hosts that serve several
|
|
37
|
+
* sessions at once (the WebUI, four tabs on one runtime) pass this so a
|
|
38
|
+
* background tab's tool and error history lands in its own journal instead
|
|
39
|
+
* of being dropped for not being the session in front.
|
|
40
|
+
*/
|
|
41
|
+
bridgeForSession?: ((sessionId: string) => SessionEventBridge | undefined) | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* The Context of a NAMED session, without creating one.
|
|
44
|
+
*
|
|
45
|
+
* Event payloads describe the session that produced them, and some of what
|
|
46
|
+
* they carry is a per-tab setting — the iteration ceiling above all. Reading
|
|
47
|
+
* it off the shared root context told a background tab it was on "3 / 500"
|
|
48
|
+
* when its own cap was something else entirely.
|
|
49
|
+
*/
|
|
50
|
+
sessionContext?: ((sessionId: string) => Context | undefined) | undefined;
|
|
31
51
|
/** Optional wpaths for writing status.json file. */
|
|
32
52
|
wpaths?: WstackPaths | undefined;
|
|
33
53
|
/** Optional live file-watcher metrics sink. */
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
import type { ProviderRegistry } from '@wrongstack/core/registry';
|
|
15
15
|
import type { Provider } from '@wrongstack/core/types';
|
|
16
16
|
import type { Config } from '@wrongstack/core/types';
|
|
17
|
-
|
|
17
|
+
interface ResolveSetupProviderOptions {
|
|
18
18
|
config: Config;
|
|
19
19
|
/** True when neither provider nor model is set in config. */
|
|
20
20
|
needsProvider: boolean;
|
|
21
21
|
providerRegistry: ProviderRegistry;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
interface ResolvedSetupProvider {
|
|
24
24
|
provider: Provider;
|
|
25
25
|
/**
|
|
26
26
|
* True when no provider could be resolved and a stub was created — the
|
|
@@ -42,4 +42,5 @@ export interface ResolvedSetupProvider {
|
|
|
42
42
|
* Throws on provider-construction failure (same as the inline code).
|
|
43
43
|
*/
|
|
44
44
|
export declare function resolveSetupProvider(opts: ResolveSetupProviderOptions): ResolvedSetupProvider;
|
|
45
|
+
export {};
|
|
45
46
|
//# sourceMappingURL=setup-screen.d.ts.map
|
|
@@ -4,6 +4,10 @@ export interface ShellGitRouteHandlers {
|
|
|
4
4
|
gitInfo: (ws: WebSocket) => Promise<void>;
|
|
5
5
|
gitChanges: (ws: WebSocket) => Promise<void>;
|
|
6
6
|
gitDiff: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
7
|
+
gitStage?: ((ws: WebSocket, msg: WSClientMessage) => Promise<void>) | undefined;
|
|
8
|
+
gitUnstage?: ((ws: WebSocket, msg: WSClientMessage) => Promise<void>) | undefined;
|
|
9
|
+
gitDiscard?: ((ws: WebSocket, msg: WSClientMessage) => Promise<void>) | undefined;
|
|
10
|
+
gitCommit?: ((ws: WebSocket, msg: WSClientMessage) => Promise<void>) | undefined;
|
|
7
11
|
shellOpen: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
8
12
|
}
|
|
9
13
|
export declare function handleShellGitRoute(ws: WebSocket, msg: WSClientMessage, handlers: ShellGitRouteHandlers): Promise<boolean>;
|