@wrongstack/webui-server 0.313.1 → 0.316.2
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 +4717 -1291
- 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 +4301 -1075
- 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 +16 -15
|
@@ -19,6 +19,32 @@ export interface PendingConfirm {
|
|
|
19
19
|
payload?: Record<string, unknown> | undefined;
|
|
20
20
|
}
|
|
21
21
|
export declare function isDestructivePendingConfirm(confirm: PendingConfirm): boolean;
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Answer "yes" to the prompts YOLO now covers — for ONE session.
|
|
24
|
+
*
|
|
25
|
+
* `pendingConfirms` is one process-wide map holding the prompts of every open
|
|
26
|
+
* tab. YOLO is a per-tab preference, so sweeping the whole map meant turning
|
|
27
|
+
* it on in one tab silently approved the tool waiting on a prompt in another —
|
|
28
|
+
* a conversation the user was not even looking at. Passing no session keeps
|
|
29
|
+
* the old blanket behaviour for single-session hosts.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveYoloEligiblePendingConfirms(pendingConfirms: Map<string, PendingConfirm>, sessionId?: string | undefined): void;
|
|
23
32
|
export declare function resolveAllPendingConfirms(pendingConfirms: Map<string, PendingConfirm>, decision: ConfirmDecision): void;
|
|
33
|
+
/**
|
|
34
|
+
* Answer the prompts of a session that no surface displays any more.
|
|
35
|
+
*
|
|
36
|
+
* A permission prompt raised in a background tab is PARKED on that tab's lane
|
|
37
|
+
* (`chat.setPendingConfirm`). Closing the tab disposes the lane, so the parked
|
|
38
|
+
* prompt is gone from the client while the server's resolver stays pending
|
|
39
|
+
* forever — `agent.run` never settles, its run lock is never released, and the
|
|
40
|
+
* session becomes an unkillable ghost: `session.delete` refuses it with "an
|
|
41
|
+
* agent run is active" and `retireUndisplayedSessions` skips it. The blanket
|
|
42
|
+
* `resolveAllPendingConfirms` drain only fires when the LAST socket goes away,
|
|
43
|
+
* which never happens while the other three tabs are open.
|
|
44
|
+
*
|
|
45
|
+
* `no` (not `deny`) on purpose: the tool fails this once and the model can
|
|
46
|
+
* react, without minting a session-scoped denial for a tool+pattern the user
|
|
47
|
+
* never actually refused.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolvePendingConfirmsForSession(pendingConfirms: Map<string, PendingConfirm>, sessionId: string, decision?: ConfirmDecision): number;
|
|
24
50
|
//# sourceMappingURL=pending-confirms.d.ts.map
|
|
@@ -52,7 +52,7 @@ export declare function getSurfaceDefaultPorts(surface: SurfaceKind): {
|
|
|
52
52
|
};
|
|
53
53
|
/** Resolve true when `port` can be bound on `host`, false on EADDRINUSE/EACCES. */
|
|
54
54
|
export declare function isPortFree(host: string, port: number): Promise<boolean>;
|
|
55
|
-
|
|
55
|
+
interface FindFreePortOptions {
|
|
56
56
|
/** Ports to skip even if free (e.g. one already chosen for the sibling server). */
|
|
57
57
|
exclude?: Set<number> | undefined;
|
|
58
58
|
/** How many consecutive ports to try before giving up. Default 200. */
|
|
@@ -63,9 +63,17 @@ export interface FindFreePortOptions {
|
|
|
63
63
|
* `exclude`. Throws if nothing is free within `maxTries` steps.
|
|
64
64
|
*/
|
|
65
65
|
export declare function findFreePort(host: string, startPort: number, opts?: FindFreePortOptions): Promise<number>;
|
|
66
|
-
|
|
66
|
+
interface ListenWithRetryOptions {
|
|
67
67
|
/** Bind attempts before giving up on EADDRINUSE. Default 10. */
|
|
68
68
|
maxTries?: number | undefined;
|
|
69
|
+
/**
|
|
70
|
+
* Same-port re-binds attempted before advancing, when the pre-bind probe
|
|
71
|
+
* said the port was free and the real bind still reported EADDRINUSE.
|
|
72
|
+
* Default 2 (see the phantom-EADDRINUSE note in `listenWithRetry`).
|
|
73
|
+
*/
|
|
74
|
+
phantomRetries?: number | undefined;
|
|
75
|
+
/** Delay between those same-port re-binds, ms. Default 30. */
|
|
76
|
+
phantomRetryDelayMs?: number | undefined;
|
|
69
77
|
}
|
|
70
78
|
/**
|
|
71
79
|
* Listen `server` on `host` starting at `port`, advancing one port on each
|
|
@@ -74,6 +82,12 @@ export interface ListenWithRetryOptions {
|
|
|
74
82
|
* error (EACCES, EAFNOSUPPORT, …) rejects immediately; EADDRINUSE past the
|
|
75
83
|
* final attempt rejects with the last error. Resolves with the port the
|
|
76
84
|
* server actually bound, which exceeds the request when a retry advanced.
|
|
85
|
+
*
|
|
86
|
+
* Two hazards this must survive, both observed under Bun on Windows:
|
|
87
|
+
* - a co-listener that throws from the server's 'error' emit (see the
|
|
88
|
+
* prependOnceListener note below) — settlement must not depend on it;
|
|
89
|
+
* - a phantom EADDRINUSE on a port the pre-bind probe just released.
|
|
77
90
|
*/
|
|
78
91
|
export declare function listenWithRetry(server: net.Server, host: string, port: number, opts?: ListenWithRetryOptions): Promise<number>;
|
|
92
|
+
export {};
|
|
79
93
|
//# sourceMappingURL=port-utils.d.ts.map
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { SecretVault } from '@wrongstack/core/types';
|
|
19
19
|
/** Pref keys exposed to the settings panel via prefs.get / prefs.updated. */
|
|
20
|
-
export declare const PREF_KEYS: readonly ['autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations', 'chime', 'confirmExit', 'nextPrediction', 'nextStepsTool', 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage', 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills', 'featureModelsRegistry', 'indexOnStart', 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier', 'maxConcurrent', 'titleAnimation', 'uiLocale', 'logLevel', 'auditLevel', 'hqEnabled', 'hqUrl', 'hqRawContent', 'tgConfigured', 'tgSessionEnd', 'tgDelegate', 'tgLongToolMs', 'reasoningMode', 'reasoningEffort', 'reasoningPreserve', 'cacheTtl', 'fallbackModels', 'fallbackProfiles', 'favoriteModels', 'favoriteModelsOnly', 'modelAvailabilitySchedule', 'modelMatrix', 'fallbackAuto', 'refinerProvider', 'refinerModel', 'refinerFallbackProfile', 'thinkingWord', 'statuslineMode', 'animationStyle', 'showModelReasoning', 'breakerEnabled', 'breakerAutoKillResetMs', 'fsAccess', 'debugStream', 'chimeraEnabled', 'chimeraProvider', 'chimeraModel', 'chimeraMaxFiles', 'chimeraAutoFix', 'autoReviewEnabled', 'autoReviewProvider', 'autoReviewModel', 'autoReviewFallbackProfile', 'autoReviewModelSelection', 'autoReviewFallbackModels', 'autoReviewDebounceMs', 'autoReviewMaxFilesPerBatch', 'autoReviewMaxConcurrentReviews', 'autoReviewCascadeOn', 'groupToolCalls', 'showThinkingLogs', 'autoCollapseInput', 'pluginsEnabled', 'fleetChatVerbosity', 'wrongProxyEnabled', 'wrongProxyUrl'];
|
|
20
|
+
export declare const PREF_KEYS: readonly ['autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations', 'chime', 'confirmExit', 'nextPrediction', 'nextStepsTool', 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage', 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills', 'featureModelsRegistry', 'indexOnStart', 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier', 'systemPromptVariant', 'maxConcurrent', 'titleAnimation', 'uiLocale', 'logLevel', 'auditLevel', 'hqEnabled', 'hqUrl', 'hqRawContent', 'tgConfigured', 'tgSessionEnd', 'tgDelegate', 'tgLongToolMs', 'reasoningMode', 'reasoningEffort', 'reasoningPreserve', 'cacheTtl', 'fallbackModels', 'fallbackProfiles', 'favoriteModels', 'favoriteModelsOnly', 'modelAvailabilitySchedule', 'modelMatrix', 'modelTiers', 'fallbackAuto', 'refinerProvider', 'refinerModel', 'refinerFallbackProfile', 'thinkingWord', 'statuslineMode', 'animationStyle', 'showModelReasoning', 'breakerEnabled', 'breakerAutoKillResetMs', 'fsAccess', 'debugStream', 'chimeraEnabled', 'chimeraProvider', 'chimeraModel', 'chimeraMaxFiles', 'chimeraAutoFix', 'autoReviewEnabled', 'autoReviewProvider', 'autoReviewModel', 'autoReviewFallbackProfile', 'autoReviewModelSelection', 'autoReviewFallbackModels', 'autoReviewDebounceMs', 'autoReviewMaxFilesPerBatch', 'autoReviewMaxConcurrentReviews', 'autoReviewCascadeOn', 'groupToolCalls', 'showThinkingLogs', 'autoCollapseInput', 'pluginsEnabled', 'fleetChatVerbosity', 'wrongProxyEnabled', 'wrongProxyUrl', 'showAgentSwarmPanel', 'readSymbols', 'showSageMemoryInject', 'sageMemoryInjectThreshold', 'preRefineSeconds', 'multiDiffSummaryThreshold', 'enhanceCountdownMs', 'keyboardShortcuts'];
|
|
21
21
|
export interface PrefHelperDeps {
|
|
22
22
|
/** Path to the active profile config; the sole settings mutation target. */
|
|
23
23
|
profileConfigPath: string;
|
|
@@ -1,15 +1,44 @@
|
|
|
1
1
|
import type { ConfigStore } from '@wrongstack/core/types';
|
|
2
2
|
import type { WebSocket } from 'ws';
|
|
3
3
|
import { type PendingConfirm } from './pending-confirms.js';
|
|
4
|
+
import { type SystemPromptSurface } from './system-prompt-handlers.js';
|
|
4
5
|
import type { WSServerMessage } from './types.js';
|
|
6
|
+
export { SESSION_SCOPED_PREF_KEYS } from './session-scoped-prefs.js';
|
|
5
7
|
export interface PrefsHandlerContext {
|
|
6
8
|
meta: Record<string, unknown>;
|
|
7
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Meta bag of a specific session, for the session-scoped keys above.
|
|
11
|
+
* Falls back to the process-wide `meta` when the host has not wired
|
|
12
|
+
* per-session contexts (the embedded single-session runtimes).
|
|
13
|
+
*/
|
|
14
|
+
metaFor?: ((sessionId?: string) => Record<string, unknown>) | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Read the pref snapshot for ONE session. The session-scoped keys live on
|
|
17
|
+
* that session's meta, so a snapshot taken without an id describes whichever
|
|
18
|
+
* session the runtime is on — which is a different tab from the asking one
|
|
19
|
+
* as often as not once four are open.
|
|
20
|
+
*/
|
|
21
|
+
snapshot: (sessionId?: string) => Record<string, unknown>;
|
|
8
22
|
persist: (payload: Record<string, unknown>) => Promise<void>;
|
|
9
23
|
pendingConfirms: Map<string, PendingConfirm>;
|
|
10
24
|
configStore?: ConfigStore | undefined;
|
|
11
|
-
|
|
12
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Flip the host's process-wide YOLO fallback.
|
|
27
|
+
*
|
|
28
|
+
* `sessionId` names the tab that asked. A host whose "apply" path also
|
|
29
|
+
* writes a context meta must NOT write the leader's when a tab is named —
|
|
30
|
+
* the leader context is the boot tab's runtime, so that write would turn
|
|
31
|
+
* YOLO on for a conversation the user was not in.
|
|
32
|
+
*/
|
|
33
|
+
setYolo?: ((enabled: boolean, sessionId?: string | undefined) => void) | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Flip the RUNTIME autonomy mode. Session-scoped for the same reason
|
|
36
|
+
* `setYolo` is: the mode is a per-tab preference, and the runtime knob
|
|
37
|
+
* behind this seam is process-wide, so an unaddressed call let a background
|
|
38
|
+
* tab put the whole process — and every other tab's system prompt — into
|
|
39
|
+
* eternal mode.
|
|
40
|
+
*/
|
|
41
|
+
setAutonomy?: ((mode: string, sessionId?: string | undefined) => void) | undefined;
|
|
13
42
|
applyConfigPrefs?: ((payload: Record<string, unknown>) => void) | undefined;
|
|
14
43
|
setAutoCompact?: ((enabled: boolean) => void) | undefined;
|
|
15
44
|
setLogLevel?: ((level: 'debug' | 'info' | 'warn' | 'error') => void) | undefined;
|
|
@@ -23,10 +52,18 @@ export interface PrefsHandlerContext {
|
|
|
23
52
|
* prefs-dependent request (e.g. an immediate model.switch).
|
|
24
53
|
*/
|
|
25
54
|
applyWrongProxyPrefs?: ((payload: Record<string, unknown>) => void | Promise<void>) | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Identity-prompt picker. Optional so a host that has not wired it still
|
|
57
|
+
* compiles; `system_prompt.get` then answers with an explicit "unavailable"
|
|
58
|
+
* payload rather than leaving the browser's request unanswered.
|
|
59
|
+
*/
|
|
60
|
+
systemPrompt?: SystemPromptSurface | undefined;
|
|
26
61
|
send: (ws: WebSocket, message: WSServerMessage) => void;
|
|
27
62
|
broadcast: (message: WSServerMessage) => void;
|
|
28
63
|
}
|
|
29
|
-
export declare function handlePrefsGet(ctx: PrefsHandlerContext, ws: WebSocket): void;
|
|
30
|
-
|
|
31
|
-
export declare function
|
|
64
|
+
export declare function handlePrefsGet(ctx: PrefsHandlerContext, ws: WebSocket, sessionId?: string): void;
|
|
65
|
+
/** Answer `system_prompt.get` with the variant catalogue and token estimates. */
|
|
66
|
+
export declare function handleSystemPromptGet(ctx: PrefsHandlerContext, ws: WebSocket, sessionId?: string): Promise<void>;
|
|
67
|
+
export declare function handlePrefsUpdate(ctx: PrefsHandlerContext, ws: WebSocket, input: Record<string, unknown>, sessionId?: string): Promise<void>;
|
|
68
|
+
export declare function handleAutonomySwitch(ctx: PrefsHandlerContext, ws: WebSocket, mode: string, sessionId?: string): void;
|
|
32
69
|
//# sourceMappingURL=prefs-handlers.d.ts.map
|
|
@@ -2,8 +2,8 @@ import type { WebSocket } from 'ws';
|
|
|
2
2
|
import { type PrefsHandlerContext } from './prefs-handlers.js';
|
|
3
3
|
import type { WSClientMessage } from './types.js';
|
|
4
4
|
export interface PrefsRouteHandlers {
|
|
5
|
-
/** Respond to the WS client with
|
|
6
|
-
getPrefs: (ws: WebSocket) => Promise<void>;
|
|
5
|
+
/** Respond to the WS client with one session's pref snapshot. */
|
|
6
|
+
getPrefs: (ws: WebSocket, sessionId?: string) => Promise<void>;
|
|
7
7
|
/**
|
|
8
8
|
* Merge the supplied pref payload into context.meta, persist the durable
|
|
9
9
|
* keys to config.json, apply any runtime effects (YOLO toggle, feature-flag
|
|
@@ -11,6 +11,14 @@ export interface PrefsRouteHandlers {
|
|
|
11
11
|
* logger.level), then broadcast the full current snapshot to all clients.
|
|
12
12
|
*/
|
|
13
13
|
updatePrefs: (ws: WebSocket, payload: Record<string, unknown>) => Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Reply with the identity-prompt variant catalogue: label, hint and an
|
|
16
|
+
* upper-bound token estimate per variant, plus which one is live and whether
|
|
17
|
+
* the user has ever chosen. Setting a variant goes through `prefs.update`
|
|
18
|
+
* with `systemPromptVariant`, so this side stays read-only.
|
|
19
|
+
*/
|
|
20
|
+
/** `sessionId` names the tab asking: the live variant is per session. */
|
|
21
|
+
getSystemPrompt: (ws: WebSocket, sessionId?: string | undefined) => Promise<void>;
|
|
14
22
|
/** Preview/apply canonical defaults in the active profile config. */
|
|
15
23
|
doctorConfig?: ((ws: WebSocket, apply: boolean) => Promise<void>) | undefined;
|
|
16
24
|
}
|
|
@@ -24,6 +32,7 @@ export declare function createPrefsRouteHandlers(ctx: PrefsHandlerContext, docto
|
|
|
24
32
|
* Owned prefixes:
|
|
25
33
|
* - `prefs.get`
|
|
26
34
|
* - `prefs.update`
|
|
35
|
+
* - `system_prompt.get`
|
|
27
36
|
* - `config.doctor`
|
|
28
37
|
*
|
|
29
38
|
* Regression-tested by packages/webui/tests/server/dispatcher-routing.test.ts.
|
|
@@ -2,21 +2,28 @@
|
|
|
2
2
|
* Process-registry WebSocket handlers for the WebUI server, extracted from the
|
|
3
3
|
* `handleMessage` switch in `index.ts` as part of splitting that file (#31).
|
|
4
4
|
*
|
|
5
|
-
* case 'process.list': return handleProcessList(ws);
|
|
5
|
+
* case 'process.list': return handleProcessList(ws, msg);
|
|
6
6
|
* case 'process.kill': return handleProcessKill(ws, msg.payload);
|
|
7
|
-
* case 'process.killAll': return handleProcessKillAll(ws);
|
|
7
|
+
* case 'process.killAll': return handleProcessKillAll(ws, …, msg.payload);
|
|
8
|
+
*
|
|
9
|
+
* Four tabs share one registry. A list/kill that ignores sessionId lets tab 2
|
|
10
|
+
* see (and terminate) tab 1's bash. When the request names a session, list
|
|
11
|
+
* and kill-all are confined to that session's children; a kill of a PID that
|
|
12
|
+
* belongs to a different session is refused.
|
|
8
13
|
*
|
|
9
14
|
* Registry failures never escape the handler; they are reported over the
|
|
10
15
|
* socket using the existing protocol envelopes.
|
|
11
16
|
*/
|
|
12
|
-
import type { Logger } from '@wrongstack/core/types';
|
|
13
17
|
import { type TrustBoundary } from '@wrongstack/core/security';
|
|
18
|
+
import type { Logger } from '@wrongstack/core/types';
|
|
14
19
|
import type { WebSocket } from 'ws';
|
|
15
20
|
import { type WebUIPrivilegedAction } from './privileged-actions.js';
|
|
16
21
|
/** Broadcast the tracked-process list; an empty list on any registry failure. */
|
|
17
|
-
export declare function handleProcessList(ws: WebSocket
|
|
22
|
+
export declare function handleProcessList(ws: WebSocket, msg?: {
|
|
23
|
+
payload?: unknown;
|
|
24
|
+
}): void;
|
|
18
25
|
/** Kill one tracked PID. Rejects invalid payloads and protected processes. */
|
|
19
26
|
export declare function handleProcessKill(ws: WebSocket, payload: unknown, trustBoundary?: TrustBoundary, logger?: Logger | undefined, metadata?: WebUIPrivilegedAction['metadata'] | undefined): Promise<void>;
|
|
20
27
|
/** Kill every tracked process. */
|
|
21
|
-
export declare function handleProcessKillAll(ws: WebSocket, trustBoundary?: TrustBoundary, logger?: Logger | undefined, metadata?: WebUIPrivilegedAction['metadata'] | undefined): Promise<void>;
|
|
28
|
+
export declare function handleProcessKillAll(ws: WebSocket, trustBoundary?: TrustBoundary, logger?: Logger | undefined, metadata?: WebUIPrivilegedAction['metadata'] | undefined, payload?: unknown): Promise<void>;
|
|
22
29
|
//# sourceMappingURL=process-handlers.d.ts.map
|
|
@@ -41,6 +41,18 @@ export interface ProjectHandlersContext {
|
|
|
41
41
|
onSessionSwapped?: (sessionId: string, target?: SessionIdentityTarget) => void | Promise<void>;
|
|
42
42
|
allowProjectMutations?: boolean;
|
|
43
43
|
sessionStartPayload: (overrides?: Record<string, unknown>) => Promise<unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* Deliver to EVERY connection, bypassing the session filter.
|
|
46
|
+
*
|
|
47
|
+
* Both hosts now route a broadcast by the `sessionId` on its payload, which
|
|
48
|
+
* is right for everything that describes one tab and wrong for the project
|
|
49
|
+
* switch: it announces a session created a millisecond ago, so no client can
|
|
50
|
+
* be subscribed to it and the filter dropped the switch on the floor —
|
|
51
|
+
* exactly the "changed NOTHING in the browser" failure this handler exists
|
|
52
|
+
* to prevent. Optional; falls back to the plain broadcast for hosts that do
|
|
53
|
+
* not filter.
|
|
54
|
+
*/
|
|
55
|
+
broadcastEveryone?: (message: OutboundMessage) => void;
|
|
44
56
|
}
|
|
45
57
|
export declare function createProjectHandlers(ctx: ProjectHandlersContext): ProjectRouteHandlers;
|
|
46
58
|
export {};
|
|
@@ -3,19 +3,27 @@
|
|
|
3
3
|
* files are created, modified, or deleted inside the project root, so
|
|
4
4
|
* the WebUI file explorer refreshes its tree without manual navigation.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* Subscribes to core's SHARED recursive project watcher rather than opening
|
|
7
|
+
* its own. This file used to call `fs.watch(root, {recursive:true})` directly,
|
|
8
|
+
* which meant a running WebUI put a SECOND recursive watch on the same tree:
|
|
9
|
+
* the OS then tracked it independently and delivered every event twice — and
|
|
10
|
+
* on Windows `ReadDirectoryChangesW` reports `node_modules` too, so a `pnpm
|
|
11
|
+
* install` or a build paid that twice over. Core's registry keeps ONE watcher
|
|
12
|
+
* per resolved root per process and fans out to subscribers, which is exactly
|
|
13
|
+
* why it exists; the codebase indexer and the chronicle file observer were
|
|
14
|
+
* already using it.
|
|
12
15
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
+
* Events are debounced (400ms) to coalesce bursts from build tools, git
|
|
17
|
+
* checkouts, and agent writes. Heavyweight directories (`node_modules`,
|
|
18
|
+
* `.git`, `dist`, …) are ignored to avoid event storms — the same `SKIP_DIRS`
|
|
19
|
+
* set the tree builder uses.
|
|
20
|
+
*
|
|
21
|
+
* The shared watcher is non-persistent and never keeps the process alive. The
|
|
22
|
+
* returned disposer drops this subscription; the underlying handle closes once
|
|
23
|
+
* the last subscriber leaves.
|
|
16
24
|
*/
|
|
17
25
|
import type { ConnectedClient, WSServerMessage } from './types.js';
|
|
18
|
-
|
|
26
|
+
interface ProjectWatcherDeps {
|
|
19
27
|
/** Absolute project root to watch. */
|
|
20
28
|
projectRoot: string;
|
|
21
29
|
/** Broadcast a message to all connected WS clients. */
|
|
@@ -28,4 +36,5 @@ export interface ProjectWatcherDeps {
|
|
|
28
36
|
* disposer that closes all native watch handles.
|
|
29
37
|
*/
|
|
30
38
|
export declare function startProjectWatcher(deps: ProjectWatcherDeps): () => void;
|
|
39
|
+
export {};
|
|
31
40
|
//# sourceMappingURL=project-watcher.d.ts.map
|
|
@@ -30,5 +30,4 @@ export interface ProviderServiceContext {
|
|
|
30
30
|
broadcastSaved(providers: Record<string, ProviderConfig>): void;
|
|
31
31
|
}
|
|
32
32
|
export declare function createProviderServiceContext(deps: ProviderOperationsDeps): ProviderServiceContext;
|
|
33
|
-
export type { ProviderServiceContext as ProviderMutationsContext };
|
|
34
33
|
//# sourceMappingURL=mutations.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Give every conversation the rebuilt provider.
|
|
3
|
+
*
|
|
4
|
+
* A WrongProxy toggle and a credential hot-reload are PROJECT-wide facts: the
|
|
5
|
+
* same provider, rebuilt with a different base URL or a new key. Both used to
|
|
6
|
+
* assign the result to the root context alone.
|
|
7
|
+
*
|
|
8
|
+
* That is enough for a host with one conversation and wrong for four. A
|
|
9
|
+
* session's `Context` is created with the root's provider REFERENCE, so every
|
|
10
|
+
* tab opened before the toggle kept running the old object — routed the old
|
|
11
|
+
* way, authenticated with the old key — while the leader used the new one.
|
|
12
|
+
* Nothing on screen distinguishes them, and the divergence lasts until each
|
|
13
|
+
* tab happens to switch models.
|
|
14
|
+
*
|
|
15
|
+
* The fan-out is deliberately conservative: only contexts still pointing at
|
|
16
|
+
* the exact provider object being replaced are moved. A tab that chose its own
|
|
17
|
+
* model owns its own provider and must keep it — that choice is per
|
|
18
|
+
* conversation, and overwriting it here would be the very cross-tab write this
|
|
19
|
+
* exists to prevent.
|
|
20
|
+
*
|
|
21
|
+
* @module provider-fanout
|
|
22
|
+
*/
|
|
23
|
+
import type { Context } from '@wrongstack/core/agent';
|
|
24
|
+
import type { Provider } from '@wrongstack/core/types';
|
|
25
|
+
interface ProviderFanoutInput {
|
|
26
|
+
/** Conversations holding a live agent; absent on single-conversation hosts. */
|
|
27
|
+
sessionAgentIds?: (() => string[]) | undefined;
|
|
28
|
+
/** Read-only agent lookup — must never materialise one. */
|
|
29
|
+
peekAgent?: ((sessionId?: string) => {
|
|
30
|
+
ctx: Context;
|
|
31
|
+
} | undefined) | undefined;
|
|
32
|
+
/** The provider object being replaced. */
|
|
33
|
+
previous: Provider | undefined;
|
|
34
|
+
/** The rebuilt provider. */
|
|
35
|
+
next: Provider;
|
|
36
|
+
/** The context that already received `next` and must not be revisited. */
|
|
37
|
+
applied: Context;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Move every other conversation off `previous` and onto `next`.
|
|
41
|
+
*
|
|
42
|
+
* Returns the session ids that were moved, for logging and tests.
|
|
43
|
+
*/
|
|
44
|
+
export declare function fanOutProviderRebuild(input: ProviderFanoutInput): string[];
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=provider-fanout.d.ts.map
|
|
@@ -49,7 +49,7 @@ export declare function createProviderOperations(deps: ProviderOperationsDeps):
|
|
|
49
49
|
broadcastSaved: (providers: Record<string, ProviderConfig>) => void;
|
|
50
50
|
loadConfigProviders: () => Promise<Record<string, ProviderConfig>>;
|
|
51
51
|
};
|
|
52
|
-
|
|
52
|
+
interface ProviderHandlerDeps {
|
|
53
53
|
/** Path to the active profile config; the only provider mutation target. */
|
|
54
54
|
profileConfigPath: string;
|
|
55
55
|
vault: import('@wrongstack/core/types').SecretVault;
|
|
@@ -57,7 +57,11 @@ export interface ProviderHandlerDeps {
|
|
|
57
57
|
setConfigWriteLock: (lock: Promise<void>) => void;
|
|
58
58
|
getConfigWriteLock: () => Promise<void>;
|
|
59
59
|
/** Broadcast a message to all connected WebUI clients */
|
|
60
|
-
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage
|
|
60
|
+
broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage,
|
|
61
|
+
/** Deliver to the tab that owns this session, overriding the id on the
|
|
62
|
+
* payload. Needed when the payload names a SUBAGENT's session, which no
|
|
63
|
+
* tab subscribes to. */
|
|
64
|
+
targetSessionId?: string) => void;
|
|
61
65
|
/** Connected WebUI clients map */
|
|
62
66
|
clients: Map<WebSocket, ConnectedClient>;
|
|
63
67
|
/** Used by the ChatGPT OAuth flow's tier-2 model lookup (best-effort). */
|
|
@@ -48,6 +48,9 @@ export interface ProviderRouteHandlers {
|
|
|
48
48
|
/** Live provider/model health tracker (the "waiting room"). Undefined when
|
|
49
49
|
* the host is not wired with a tracker (e.g. test harnesses). */
|
|
50
50
|
statusTracker?: ProviderModelStatusTracker | undefined;
|
|
51
|
+
/** Durable block/open audit trail (JSONL) next to the profile config.
|
|
52
|
+
* Undefined when the host did not provide a profile path (test harnesses). */
|
|
53
|
+
providerAuditFile?: string | undefined;
|
|
51
54
|
}
|
|
52
55
|
export declare function handleProviderRoute(ws: WebSocket, msg: WSClientMessage, routes: ProviderRouteHandlers): Promise<boolean>;
|
|
53
56
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DefaultSecretVault } from '@wrongstack/core/security';
|
|
2
2
|
import type { ProviderApiKey, ProviderConfig } from '@wrongstack/core/types';
|
|
3
|
-
|
|
3
|
+
interface ProviderStoreDeps {
|
|
4
4
|
/** Active profile config path. */
|
|
5
5
|
profileConfigPath: string;
|
|
6
6
|
vault: DefaultSecretVault;
|
|
@@ -24,4 +24,5 @@ export interface ProviderStore {
|
|
|
24
24
|
maskedKey(key: string | undefined): string;
|
|
25
25
|
}
|
|
26
26
|
export declare function createProviderStore(deps: ProviderStoreDeps): ProviderStore;
|
|
27
|
+
export {};
|
|
27
28
|
//# sourceMappingURL=provider-store.d.ts.map
|
|
@@ -19,8 +19,6 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import type * as http from 'node:http';
|
|
21
21
|
import { type RequirementIntakeService } from '@wrongstack/requirement-intake';
|
|
22
|
-
/** Map a domain error to an HTTP status + JSON error body. */
|
|
23
|
-
export declare function sendIntakeError(res: http.ServerResponse, error: unknown): void;
|
|
24
22
|
/**
|
|
25
23
|
* List intake records for the server's own project. The webui-server serves
|
|
26
24
|
* one project; the canonical `proj_<ulid>` id lives in `.wrongstack/project.json`,
|
|
@@ -2,6 +2,7 @@ import type { WebSocket } from 'ws';
|
|
|
2
2
|
import { type AgentRosterRouteHandlers } from './agent-roster-routes.js';
|
|
3
3
|
import { type AutonomyRouteHandlers } from './autonomy-routes.js';
|
|
4
4
|
import { type BrainRouteHandlers } from './brain-routes.js';
|
|
5
|
+
import { type ChimeraRouteHandlers } from './chimera-routes.js';
|
|
5
6
|
import { type ChronicleRouteContext } from './chronicle-routes.js';
|
|
6
7
|
import { type ClientTransportRouteHandlers } from './client-transport-routes.js';
|
|
7
8
|
import { type CompletionRouteHandlers } from './completion-routes.js';
|
|
@@ -40,6 +41,7 @@ export interface RouteFamilyTable {
|
|
|
40
41
|
mode: ModeRouteHandlers;
|
|
41
42
|
prefs: PrefsRouteHandlers;
|
|
42
43
|
brain: BrainRouteHandlers;
|
|
44
|
+
chimera: ChimeraRouteHandlers | undefined;
|
|
43
45
|
worklist: WorklistRouteHandlers;
|
|
44
46
|
process: ProcessRouteHandlers;
|
|
45
47
|
host: HostRouteHandlers;
|
package/dist/server/routes.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { Config } from '@wrongstack/core/types';
|
|
|
13
13
|
import type { MCPRegistry } from '@wrongstack/mcp';
|
|
14
14
|
import { type AutonomyRouteHandlers } from './autonomy-routes.js';
|
|
15
15
|
import type { BrainRouteHandlers } from './brain-routes.js';
|
|
16
|
+
import { type ChimeraRouteHandlers } from './chimera-routes.js';
|
|
16
17
|
import type { CollaborationWebSocketHandler } from './collaboration-ws-handler.js';
|
|
17
18
|
import type { CustomModeStore } from './custom-context-modes.js';
|
|
18
19
|
import type { GoalRouteHandlers } from './goal-routes.js';
|
|
@@ -20,7 +21,7 @@ import type { GoalWebSocketHandler } from './goal-ws-handler.js';
|
|
|
20
21
|
import { type MailboxRouteHandlers } from './mailbox-routes.js';
|
|
21
22
|
import type { McpRouteHandlers } from './mcp-routes.js';
|
|
22
23
|
import type { ModeRouteHandlers } from './mode-routes.js';
|
|
23
|
-
import type
|
|
24
|
+
import { type PendingConfirm } from './pending-confirms.js';
|
|
24
25
|
import { type PrefsRouteHandlers } from './prefs-routes.js';
|
|
25
26
|
import type { ProjectRouteHandlers } from './project-routes.js';
|
|
26
27
|
import type { ProviderRouteHandlers } from './provider-routes.js';
|
|
@@ -67,9 +68,17 @@ export interface WebuiMutableState {
|
|
|
67
68
|
* refactor moves that into the projectHandlers setter chain so the
|
|
68
69
|
* route layer just calls a single hook.
|
|
69
70
|
*/
|
|
70
|
-
abortRunLock: () => void;
|
|
71
|
-
/** True while
|
|
72
|
-
isRunActive: () => boolean;
|
|
71
|
+
abortRunLock: (sessionId?: string) => void;
|
|
72
|
+
/** True while `sessionId` (or any session, when omitted) owns a run lock. */
|
|
73
|
+
isRunActive: (sessionId?: string) => boolean;
|
|
74
|
+
/** Every session id with an in-flight run — one per busy WebUI tab. */
|
|
75
|
+
getRunningSessionIds: () => string[];
|
|
76
|
+
/**
|
|
77
|
+
* Host-wide serialiser for session transitions. Shared by the session
|
|
78
|
+
* handlers and the conversation ops so run setup never lands on a context
|
|
79
|
+
* that a concurrent session swap is halfway through re-pointing.
|
|
80
|
+
*/
|
|
81
|
+
withSessionTransition: <T>(operation: () => Promise<T>) => Promise<T>;
|
|
73
82
|
/** Read-only reference to the live WS clients map. */
|
|
74
83
|
getClients(): Map<WebSocket, ConnectedClient>;
|
|
75
84
|
}
|
|
@@ -80,6 +89,27 @@ export interface WebuiMutableState {
|
|
|
80
89
|
export interface WebuiDeps {
|
|
81
90
|
trustBoundary: import('@wrongstack/core/security').TrustBoundary;
|
|
82
91
|
agent: Agent;
|
|
92
|
+
getAgent?: ((sessionId?: string) => Agent) | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* The Agent for a session WITHOUT creating one. Read-only callers use this;
|
|
95
|
+
* `getAgent` creates, so asking about a stale id materialises an agent for
|
|
96
|
+
* it and can evict a live tab's.
|
|
97
|
+
*/
|
|
98
|
+
peekAgent?: ((sessionId?: string) => Agent | undefined) | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Every conversation currently holding an agent.
|
|
101
|
+
*
|
|
102
|
+
* A project-wide provider rebuild (WrongProxy toggle, credential
|
|
103
|
+
* hot-reload) used to swap `context.provider` and stop there. Session
|
|
104
|
+
* contexts copy the root's provider REFERENCE when they are created, so
|
|
105
|
+
* every tab opened before the toggle kept the old, unrouted provider while
|
|
106
|
+
* the leader used the new one — four tabs, two different providers, no way
|
|
107
|
+
* to tell from the UI. Hosts with one conversation omit this.
|
|
108
|
+
*/
|
|
109
|
+
sessionAgentIds?: (() => string[]) | undefined;
|
|
110
|
+
hasSession?: ((id: string) => boolean) | undefined;
|
|
111
|
+
/** Does this host already hold an open journal writer for that session? */
|
|
112
|
+
isSessionLive?: ((id: string) => boolean) | undefined;
|
|
83
113
|
context: Context;
|
|
84
114
|
container: Container;
|
|
85
115
|
toolRegistry: ToolRegistry;
|
|
@@ -149,7 +179,12 @@ export interface WebuiDeps {
|
|
|
149
179
|
* delegates without storing state of its own.
|
|
150
180
|
*/
|
|
151
181
|
export interface WebuiCallbacks {
|
|
152
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Build a `session.start` payload. `overrides.sessionId` selects WHICH
|
|
184
|
+
* session it describes — with four tabs live, the runtime's own "current"
|
|
185
|
+
* session is not necessarily the one being reported on.
|
|
186
|
+
*/
|
|
187
|
+
sessionStartPayload: (overrides?: Record<string, unknown>) => Promise<{
|
|
153
188
|
sessionId: string;
|
|
154
189
|
model: string;
|
|
155
190
|
provider: string;
|
|
@@ -186,6 +221,7 @@ export interface AllRoutes {
|
|
|
186
221
|
prefsRoutes: PrefsRouteHandlers;
|
|
187
222
|
autonomyRoutes: AutonomyRouteHandlers;
|
|
188
223
|
shellGitRoutes: ShellGitRouteHandlers;
|
|
224
|
+
chimeraRoutes: ChimeraRouteHandlers;
|
|
189
225
|
mailboxRoutes: MailboxRouteHandlers;
|
|
190
226
|
mcpRoutes: McpRouteHandlers;
|
|
191
227
|
brainRoutes: BrainRouteHandlers;
|
|
@@ -7,7 +7,7 @@ interface SddBoardWSMessage {
|
|
|
7
7
|
payload?: Record<string, unknown>;
|
|
8
8
|
}
|
|
9
9
|
/** Project paths the handler needs to apply lifecycle ops directly. */
|
|
10
|
-
|
|
10
|
+
interface SddBoardLifecycleDeps {
|
|
11
11
|
projectRoot: string;
|
|
12
12
|
/** Explicit compatibility hook for file-codec tests and old integrations. */
|
|
13
13
|
controlTransport?: 'kanban' | 'legacy-file' | undefined;
|
|
@@ -20,7 +20,7 @@ export interface SddBoardLifecycleDeps {
|
|
|
20
20
|
projectSddBoards: string;
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
interface SddBoardSecurityDeps {
|
|
24
24
|
trustBoundary: TrustBoundary;
|
|
25
25
|
logger?: Logger | undefined;
|
|
26
26
|
}
|
|
@@ -46,13 +46,25 @@ interface SessionStartPayloadGetters {
|
|
|
46
46
|
getContextMode(): string;
|
|
47
47
|
getNeedsSetup(): boolean;
|
|
48
48
|
modelsRegistry: ModelsRegistry;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a session's own Context. Each WebUI tab runs its own session with
|
|
51
|
+
* its own model, mode and context strategy; without this the payload would
|
|
52
|
+
* describe the runtime's current session for every tab.
|
|
53
|
+
*/
|
|
54
|
+
getSessionContext?: ((sessionId: string) => SessionRuntimeContext | undefined) | undefined;
|
|
49
55
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
/** The slice of a session Context this payload reads. */
|
|
57
|
+
interface SessionRuntimeContext {
|
|
58
|
+
model?: string | undefined;
|
|
59
|
+
provider?: {
|
|
60
|
+
id?: string | undefined;
|
|
61
|
+
} | undefined;
|
|
62
|
+
session?: {
|
|
63
|
+
startedAt?: string | undefined;
|
|
64
|
+
} | undefined;
|
|
65
|
+
meta?: Record<string, unknown> | undefined;
|
|
66
|
+
}
|
|
67
|
+
export declare function createSessionStartPayload(g: SessionStartPayloadGetters): (overrides?: Record<string, unknown>) => Promise<{
|
|
56
68
|
sessionId: string;
|
|
57
69
|
model: string;
|
|
58
70
|
provider: string;
|
|
@@ -69,6 +81,11 @@ export declare function createSessionStartPayload(g: SessionStartPayloadGetters)
|
|
|
69
81
|
protocolCapabilities: string[];
|
|
70
82
|
needsSetup?: boolean | undefined;
|
|
71
83
|
reasoningEffortLevels?: string[] | undefined;
|
|
84
|
+
/** Tri-state effort-support signal (see SessionLaneData.effortSupported). */
|
|
85
|
+
effortSupported?: boolean | undefined;
|
|
86
|
+
/** Project-wide effort — display-only hint for the composer's auto option. */
|
|
87
|
+
projectReasoningEffort?: string | undefined;
|
|
88
|
+
[key: string]: unknown;
|
|
72
89
|
}>;
|
|
73
90
|
interface WsServerResult {
|
|
74
91
|
wssPrimary: WebSocketServer;
|