@wrongstack/webui-server 0.298.3 → 0.300.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1375 -252
- package/dist/protocol/client-conversation.d.ts +1 -1
- package/dist/protocol/index.js +21 -1
- package/dist/protocol/projections.d.ts +8 -0
- package/dist/protocol/registry.d.ts +2 -2
- package/dist/protocol/server-conversation.d.ts +2 -2
- package/dist/server/context-editor.d.ts +9 -0
- package/dist/server/embedded-host-adapters.d.ts +1 -1
- package/dist/server/embedded-lifecycle.d.ts +23 -5
- package/dist/server/entry.js +1289 -229
- package/dist/server/fallback-choice.d.ts +19 -0
- package/dist/server/frontend-static-serve.d.ts +9 -0
- package/dist/server/http-server.d.ts +56 -0
- package/dist/server/instance-registry.d.ts +21 -0
- package/dist/server/intake-service.d.ts +13 -0
- package/dist/server/mcp-handlers.d.ts +3 -2
- package/dist/server/pref-helpers.d.ts +1 -1
- package/dist/server/provider-handlers.d.ts +2 -2
- package/dist/server/provider-routes.d.ts +3 -1
- package/dist/server/requirement-intake-handlers.d.ts +41 -0
- package/dist/server/server-runtime.d.ts +3 -0
- package/dist/server/session-history.d.ts +42 -1
- package/dist/server/session-routes.d.ts +1 -0
- package/dist/server/ws-auth.d.ts +18 -0
- package/dist/server/ws-payload-validation.d.ts +7 -0
- package/package.json +11 -10
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EventBus } from '@wrongstack/core/kernel';
|
|
2
|
+
import type { WSClientMessage } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bridge a `model.fallback_choice` client message to the
|
|
5
|
+
* `provider.fallback_choice` EventBus emission consumed by the fallback gate
|
|
6
|
+
* (`packages/cli/src/wiring/fallback-gate.ts`). Shared by the standalone route
|
|
7
|
+
* table (`routes.ts`) and the embedded message router so wire validation and
|
|
8
|
+
* the event contract live in exactly one place.
|
|
9
|
+
*
|
|
10
|
+
* Returns `true` when the payload was valid and forwarded, `false` when the
|
|
11
|
+
* payload failed validation (the caller may send an error frame).
|
|
12
|
+
*/
|
|
13
|
+
export declare function emitFallbackChoice(events: EventBus | undefined, msg: WSClientMessage): {
|
|
14
|
+
ok: true;
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=fallback-choice.d.ts.map
|
|
@@ -75,6 +75,15 @@ export interface StaticServeOptions {
|
|
|
75
75
|
deferListen?: boolean | undefined;
|
|
76
76
|
/** Package-resolution/build seams supplied by the owning host. */
|
|
77
77
|
ensureDistDeps?: EnsureDistDeps | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Requirements Intake service backing `/api/requirement-intakes*`. Omitted by
|
|
80
|
+
* every real host — a per-project service is constructed from `projectRoot` +
|
|
81
|
+
* `globalRoot` below, so the CLI-hosted WebUI serves the same intake records
|
|
82
|
+
* as the standalone server. Pass one only to override (tests/embeds); when
|
|
83
|
+
* `projectRoot` is absent there is no project to scope a store to and the
|
|
84
|
+
* routes correctly answer 503.
|
|
85
|
+
*/
|
|
86
|
+
intakeService?: CreateHttpServerOptions['intakeService'];
|
|
78
87
|
}
|
|
79
88
|
/**
|
|
80
89
|
* Resolve the webui package's built `dist` directory.
|
|
@@ -42,6 +42,19 @@ export interface CreateHttpServerOptions {
|
|
|
42
42
|
* URL-token-only flow (e.g. in tests that don't want cookie state).
|
|
43
43
|
*/
|
|
44
44
|
enableWsCookie?: boolean | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Mark the `ws_token` cookie `Secure` and give it the `__Host-` prefix.
|
|
47
|
+
*
|
|
48
|
+
* Inferred from a `wss://` {@link CreateHttpServerOptions.publicWsUrl} when
|
|
49
|
+
* omitted, which covers the tunnel deployments this server documents. Set it
|
|
50
|
+
* explicitly when TLS is terminated in front of the server by something that
|
|
51
|
+
* does not surface through `publicWsUrl` (e.g. an nginx `proxy_pass` with a
|
|
52
|
+
* separately configured WS origin).
|
|
53
|
+
*
|
|
54
|
+
* Must stay false on a plain-HTTP loopback bind: browsers do not send a
|
|
55
|
+
* `Secure` cookie over HTTP, so enabling it there breaks the WS handshake.
|
|
56
|
+
*/
|
|
57
|
+
secureCookies?: boolean | undefined;
|
|
45
58
|
/**
|
|
46
59
|
* Optional file watcher metrics object. When provided, the
|
|
47
60
|
* /debug/watcher-metrics endpoint will be enabled to expose these metrics.
|
|
@@ -74,10 +87,53 @@ export interface CreateHttpServerOptions {
|
|
|
74
87
|
} | undefined) | undefined;
|
|
75
88
|
/** Permission-governed language_package bridge for approved remediation. */
|
|
76
89
|
executePackageOperation?: import('./techstack-handlers.js').TechStackHandlerDeps['executePackageOperation'];
|
|
90
|
+
/**
|
|
91
|
+
* Optional Requirements Intake service. When provided, the
|
|
92
|
+
* /api/projects/:projectId/requirement-intakes and
|
|
93
|
+
* /api/requirement-intakes/:intakeId endpoints are enabled; otherwise they
|
|
94
|
+
* respond 503.
|
|
95
|
+
*/
|
|
96
|
+
intakeService?: import('@wrongstack/requirement-intake').RequirementIntakeService | undefined;
|
|
77
97
|
}
|
|
78
98
|
export declare function injectWsConfig(html: string, opts: {
|
|
79
99
|
publicWsUrl?: string | undefined;
|
|
80
100
|
}): string;
|
|
101
|
+
/**
|
|
102
|
+
* WS-107: the auth cookie never carried `Secure`, on the stated grounds that
|
|
103
|
+
* "the dev server is plain HTTP on loopback". True for the default bind — and
|
|
104
|
+
* wrong for the deployment this server explicitly supports, where a tunnel
|
|
105
|
+
* terminates TLS in front of it (`publicWsUrl: wss://…`). There the browser is
|
|
106
|
+
* on HTTPS, so a cookie set without `Secure` is one the browser will also
|
|
107
|
+
* attach to a plaintext request to the same host: a downgrade or a stray
|
|
108
|
+
* `http://` link leaks the token that authenticates the whole control plane.
|
|
109
|
+
*
|
|
110
|
+
* So the flag follows the deployment. On an HTTPS-fronted server the cookie is
|
|
111
|
+
* additionally `__Host-`-prefixed, which browsers only accept when it is
|
|
112
|
+
* Secure, Path=/, and Domain-less — the same hardening the HQ server adopted.
|
|
113
|
+
* On loopback HTTP neither is usable (a `Secure` cookie would simply not be
|
|
114
|
+
* sent), so the plain name is kept there.
|
|
115
|
+
*/
|
|
116
|
+
export declare const WS_TOKEN_COOKIE = "ws_token";
|
|
117
|
+
export declare const WS_TOKEN_COOKIE_SECURE = "__Host-ws_token";
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the access token presented on an HTTP request.
|
|
120
|
+
*
|
|
121
|
+
* WS-108: the `?token=` query source was accepted on EVERY route regardless of
|
|
122
|
+
* bind. On a tunnel that is the C-598 exposure the WS path already closed —
|
|
123
|
+
* the token reaches reverse-proxy access logs, browser history, and any
|
|
124
|
+
* `Referer` the page emits to a third-party origin. The header and cookie
|
|
125
|
+
* sources have none of those channels.
|
|
126
|
+
*
|
|
127
|
+
* `allowQuery` is therefore opt-in and reserved for the two places the token
|
|
128
|
+
* legitimately rides the URL: `/ws-auth`, whose entire job is to exchange it
|
|
129
|
+
* for the cookie, and the HTML page load the operator opens from the printed
|
|
130
|
+
* access URL. Everywhere else it is refused off-loopback — and when refused,
|
|
131
|
+
* resolution falls through to the header and cookie rather than returning
|
|
132
|
+
* early, so a client that sent both still authenticates.
|
|
133
|
+
*/
|
|
134
|
+
export declare function requestToken(req: http.IncomingMessage, url: URL, opts?: {
|
|
135
|
+
allowQuery?: boolean;
|
|
136
|
+
}): string | undefined;
|
|
81
137
|
/**
|
|
82
138
|
* Build the Content-Security-Policy value for the WebUI.
|
|
83
139
|
*
|
|
@@ -36,6 +36,27 @@ export interface WebUIInstanceRecord {
|
|
|
36
36
|
startedAt: string;
|
|
37
37
|
/** Convenience open-in-browser URL. */
|
|
38
38
|
url: string;
|
|
39
|
+
/**
|
|
40
|
+
* Access token for this instance's HTTP API, so a same-project sibling
|
|
41
|
+
* process (TUI/REPL) can authenticate the `POST /api/fleet/ping`
|
|
42
|
+
* push-on-write nudge.
|
|
43
|
+
*
|
|
44
|
+
* Security scan 2026-08-04, finding H3: the API used to require no
|
|
45
|
+
* credential at all on a loopback bind. Closing that meant the one
|
|
46
|
+
* legitimate non-browser caller needed a way to obtain the token, and this
|
|
47
|
+
* registry — already `0o600`, already read by exactly those siblings — is
|
|
48
|
+
* where it belongs.
|
|
49
|
+
*
|
|
50
|
+
* Be precise about what this is worth. Storing the token here raises the bar
|
|
51
|
+
* against a *different-user* or sandboxed local process, which cannot read
|
|
52
|
+
* the file. It does nothing against a process running as the same user: that
|
|
53
|
+
* process can read this file, and could read `~/.wrongstack/projects/*` —
|
|
54
|
+
* the very transcripts the API exposes — without going near the API at all.
|
|
55
|
+
* The same reasoning already applies to HQ's `auth.json`.
|
|
56
|
+
*
|
|
57
|
+
* Optional so an older record (or a surface that has no token) still parses.
|
|
58
|
+
*/
|
|
59
|
+
authToken?: string | undefined;
|
|
39
60
|
}
|
|
40
61
|
/** Default wstack home dir (`~/.wrongstack`). Callers may override the base. */
|
|
41
62
|
export declare function defaultBaseDir(): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RequirementIntakeService } from '@wrongstack/requirement-intake';
|
|
2
|
+
/**
|
|
3
|
+
* Build the intake service backed by this project's
|
|
4
|
+
* `~/.wrongstack/projects/<slug>/requirement-intakes` directory.
|
|
5
|
+
*
|
|
6
|
+
* The HTTP token gate is the authorization boundary, so the service itself
|
|
7
|
+
* runs with a permissive authorizer inside it (see requirement-intake-handlers).
|
|
8
|
+
*/
|
|
9
|
+
export declare function createProjectIntakeService(opts: {
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
globalRoot: string;
|
|
12
|
+
}): RequirementIntakeService;
|
|
13
|
+
//# sourceMappingURL=intake-service.d.ts.map
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* there; here we only map structured results to WS events the browser expects.
|
|
10
10
|
*/
|
|
11
11
|
import { type MCPRegistry, type MCPServerOperationalHealth, type McpServerInfo } from '@wrongstack/mcp';
|
|
12
|
+
import type { TrustBoundary } from '@wrongstack/core/security';
|
|
12
13
|
import type { WebSocket } from 'ws';
|
|
13
14
|
import type { WSClientMessage } from './types.js';
|
|
14
15
|
/** Wire view of a server as the browser MCP panel consumes it. */
|
|
@@ -33,9 +34,9 @@ export declare function toView(info: McpServerInfo, health?: MCPServerOperationa
|
|
|
33
34
|
/** mcp.list — configured servers merged with live registry status + tools. */
|
|
34
35
|
export declare function handleMcpList(ws: WebSocket, _msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry): Promise<void>;
|
|
35
36
|
/** mcp.add — persist a new server (incl. url/headers) and start it if enabled. */
|
|
36
|
-
export declare function handleMcpAdd(ws: WebSocket, msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry): Promise<void>;
|
|
37
|
+
export declare function handleMcpAdd(ws: WebSocket, msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry, trustBoundary?: TrustBoundary): Promise<void>;
|
|
37
38
|
/** mcp.update — re-persist config (incl. url/headers) and re-apply to registry. */
|
|
38
|
-
export declare function handleMcpUpdate(ws: WebSocket, msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry): Promise<void>;
|
|
39
|
+
export declare function handleMcpUpdate(ws: WebSocket, msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry, trustBoundary?: TrustBoundary): Promise<void>;
|
|
39
40
|
/** mcp.remove — stop the server and delete it from config. */
|
|
40
41
|
export declare function handleMcpRemove(ws: WebSocket, msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry): Promise<void>;
|
|
41
42
|
/** mcp.enable — flip enabled:true in config and start the server. */
|
|
@@ -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', 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage', 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills', 'featureModelsRegistry', 'indexOnStart', 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier', 'maxConcurrent', 'titleAnimation', 'uiLocale', 'logLevel', 'auditLevel', 'hqEnabled', 'hqUrl', 'hqToken', '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', 'autoReviewFallbackModels', 'autoReviewDebounceMs', 'autoReviewMaxFilesPerBatch', 'autoReviewMaxConcurrentReviews', 'autoReviewCascadeOn', 'groupToolCalls', 'showThinkingLogs', 'pluginsEnabled', 'fleetChatVerbosity'];
|
|
20
|
+
export declare const PREF_KEYS: readonly ['autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations', 'chime', 'confirmExit', 'nextPrediction', 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage', 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills', 'featureModelsRegistry', 'indexOnStart', 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier', 'maxConcurrent', 'titleAnimation', 'uiLocale', 'logLevel', 'auditLevel', 'hqEnabled', 'hqUrl', 'hqToken', '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', 'autoReviewFallbackModels', 'autoReviewDebounceMs', 'autoReviewMaxFilesPerBatch', 'autoReviewMaxConcurrentReviews', 'autoReviewCascadeOn', 'groupToolCalls', 'showThinkingLogs', 'autoCollapseInput', 'pluginsEnabled', 'fleetChatVerbosity'];
|
|
21
21
|
export interface PrefHelperDeps {
|
|
22
22
|
/** Path to the active profile config; the sole settings mutation target. */
|
|
23
23
|
profileConfigPath: string;
|
|
@@ -95,7 +95,7 @@ export declare function createProviderOperations(deps: ProviderOperationsDeps):
|
|
|
95
95
|
apiKey?: string | undefined;
|
|
96
96
|
models?: string[] | undefined;
|
|
97
97
|
customModels?: ProviderConfig['customModels'] | undefined;
|
|
98
|
-
}) => Promise<
|
|
98
|
+
}) => Promise<boolean>;
|
|
99
99
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
100
100
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
101
101
|
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
@@ -137,7 +137,7 @@ export declare function createProviderHandlers(deps: ProviderHandlerDeps): {
|
|
|
137
137
|
apiKey?: string | undefined;
|
|
138
138
|
models?: string[] | undefined;
|
|
139
139
|
customModels?: ProviderConfig['customModels'] | undefined;
|
|
140
|
-
}) => Promise<
|
|
140
|
+
}) => Promise<boolean>;
|
|
141
141
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
142
142
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
143
143
|
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
@@ -14,7 +14,7 @@ export interface ProviderMutationHandlers {
|
|
|
14
14
|
apiKey?: string | undefined;
|
|
15
15
|
models?: string[] | undefined;
|
|
16
16
|
customModels?: ProviderConfig['customModels'] | undefined;
|
|
17
|
-
}) => Promise<
|
|
17
|
+
}) => Promise<boolean>;
|
|
18
18
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
19
19
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
20
20
|
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
@@ -40,6 +40,8 @@ export interface ProviderRouteHandlers {
|
|
|
40
40
|
searchProviderModels: (ws: WebSocket, query: string, limit?: number | undefined) => Promise<void>;
|
|
41
41
|
switchModel: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
42
42
|
refineModel: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
43
|
+
/** Forward a model.fallback_choice client message to the EventBus. */
|
|
44
|
+
fallbackChoice: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
43
45
|
/** Adopt a just-added provider as the live default when no model is active. */
|
|
44
46
|
adoptDefaultProviderIfUnset: (providerId: string) => Promise<void>;
|
|
45
47
|
providerHandlers: ProviderMutationHandlers;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP handlers for the Requirements Intake REST API.
|
|
3
|
+
*
|
|
4
|
+
* Routes (registered in http-server.ts):
|
|
5
|
+
* POST /api/projects/:projectId/requirement-intakes
|
|
6
|
+
* GET /api/projects/:projectId/requirement-intakes
|
|
7
|
+
* GET /api/requirement-intakes/:intakeId
|
|
8
|
+
* PATCH /api/requirement-intakes/:intakeId
|
|
9
|
+
* POST /api/requirement-intakes/:intakeId/answers
|
|
10
|
+
* POST /api/requirement-intakes/:intakeId/suggestions
|
|
11
|
+
* POST /api/requirement-intakes/:intakeId/submit
|
|
12
|
+
* POST /api/requirement-intakes/:intakeId/cancel
|
|
13
|
+
* POST /api/requirement-intakes/:intakeId/archive
|
|
14
|
+
*
|
|
15
|
+
* The HTTP token gate (see http-server.ts) is the authorization boundary;
|
|
16
|
+
* the service runs with a permissive authorizer inside that boundary. Every
|
|
17
|
+
* handler maps `IntakeError` codes to conventional HTTP statuses and never
|
|
18
|
+
* echoes request content into logs.
|
|
19
|
+
*/
|
|
20
|
+
import type * as http from 'node:http';
|
|
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
|
+
/**
|
|
25
|
+
* List intake records for the server's own project. The webui-server serves
|
|
26
|
+
* one project; the canonical `proj_<ulid>` id lives in `.wrongstack/project.json`,
|
|
27
|
+
* which the frontend cannot read — so this route resolves it server-side and
|
|
28
|
+
* returns it alongside the records (the frontend uses it for the project-scoped
|
|
29
|
+
* create endpoint).
|
|
30
|
+
*/
|
|
31
|
+
export declare function handleRequirementIntakeListForServer(res: http.ServerResponse, service: RequirementIntakeService | undefined, projectRoot: string | undefined): Promise<void>;
|
|
32
|
+
export declare function handleRequirementIntakeCreate(res: http.ServerResponse, req: http.IncomingMessage, service: RequirementIntakeService | undefined, projectId: string): Promise<void>;
|
|
33
|
+
export declare function handleRequirementIntakeList(res: http.ServerResponse, service: RequirementIntakeService | undefined, projectId: string): Promise<void>;
|
|
34
|
+
export declare function handleRequirementIntakeGet(res: http.ServerResponse, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
35
|
+
export declare function handleRequirementIntakeUpdate(res: http.ServerResponse, req: http.IncomingMessage, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
36
|
+
export declare function handleRequirementIntakeAnswers(res: http.ServerResponse, req: http.IncomingMessage, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
37
|
+
export declare function handleRequirementIntakeSuggestions(res: http.ServerResponse, req: http.IncomingMessage, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
38
|
+
export declare function handleRequirementIntakeSubmit(res: http.ServerResponse, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
39
|
+
export declare function handleRequirementIntakeCancel(res: http.ServerResponse, req: http.IncomingMessage, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
40
|
+
export declare function handleRequirementIntakeArchive(res: http.ServerResponse, service: RequirementIntakeService | undefined, intakeId: string): Promise<void>;
|
|
41
|
+
//# sourceMappingURL=requirement-intake-handlers.d.ts.map
|
|
@@ -102,6 +102,9 @@ export declare function startHttpServer(opts: {
|
|
|
102
102
|
} | undefined) | undefined;
|
|
103
103
|
executePackageOperation?: import('./techstack-handlers.js').TechStackHandlerDeps['executePackageOperation'];
|
|
104
104
|
distDir?: string | undefined;
|
|
105
|
+
/** Optional pre-built intake service (tests/embeds). Defaults to a fresh
|
|
106
|
+
* per-project service backed by `projectRequirementIntakes`. */
|
|
107
|
+
intakeService?: import('@wrongstack/requirement-intake').RequirementIntakeService | undefined;
|
|
105
108
|
}): import('node:http').Server;
|
|
106
109
|
interface ShutdownDeps {
|
|
107
110
|
flushSession: () => Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionSummary } from '@wrongstack/core/types';
|
|
1
|
+
import type { SessionEvent, SessionSummary } from '@wrongstack/core/types';
|
|
2
2
|
/**
|
|
3
3
|
* Stable WebSocket projection for the WebUI history surfaces.
|
|
4
4
|
*
|
|
@@ -27,6 +27,47 @@ export interface SessionHistoryWireEntry {
|
|
|
27
27
|
outcome?: SessionSummary['outcome'];
|
|
28
28
|
isCurrent: boolean;
|
|
29
29
|
}
|
|
30
|
+
export interface SessionInspectEvent {
|
|
31
|
+
ts: string;
|
|
32
|
+
type: SessionEvent['type'];
|
|
33
|
+
label: string;
|
|
34
|
+
detail: string;
|
|
35
|
+
}
|
|
36
|
+
export interface SessionInspectFileEntry {
|
|
37
|
+
operation: string;
|
|
38
|
+
filePath: string;
|
|
39
|
+
toolName: string;
|
|
40
|
+
ts: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SessionInspectPayload {
|
|
43
|
+
id: string;
|
|
44
|
+
title: string;
|
|
45
|
+
name?: string | undefined;
|
|
46
|
+
model: string;
|
|
47
|
+
provider: string;
|
|
48
|
+
startedAt: string;
|
|
49
|
+
endedAt?: string | undefined;
|
|
50
|
+
tokenTotal: number;
|
|
51
|
+
outcome?: SessionSummary['outcome'];
|
|
52
|
+
messageCount: number;
|
|
53
|
+
iterationCount: number;
|
|
54
|
+
toolCallCount: number;
|
|
55
|
+
toolErrorCount: number;
|
|
56
|
+
fileChangeCount: number;
|
|
57
|
+
compactionCount: number;
|
|
58
|
+
toolBreakdown: Record<string, number>;
|
|
59
|
+
events: SessionInspectEvent[];
|
|
60
|
+
fileEvents: SessionInspectFileEntry[];
|
|
61
|
+
lastUserMessage?: string | undefined;
|
|
62
|
+
}
|
|
63
|
+
export declare function buildInspectPayload(summary: SessionSummary | undefined, events: SessionEvent[], fallback: {
|
|
64
|
+
id: string;
|
|
65
|
+
title: string;
|
|
66
|
+
model: string;
|
|
67
|
+
provider: string;
|
|
68
|
+
startedAt: string;
|
|
69
|
+
endedAt?: string | undefined;
|
|
70
|
+
}): SessionInspectPayload;
|
|
30
71
|
export declare function toSessionHistoryEntry(summary: SessionSummary, currentSessionId: string): SessionHistoryWireEntry;
|
|
31
72
|
export declare function toSessionHistoryEntries(summaries: SessionSummary[], currentSessionId: string): SessionHistoryWireEntry[];
|
|
32
73
|
//# sourceMappingURL=session-history.d.ts.map
|
|
@@ -19,6 +19,7 @@ export interface SessionRouteHandlers {
|
|
|
19
19
|
deleteSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
20
20
|
resumeSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
21
21
|
saveSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
22
|
+
inspectSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
22
23
|
listCheckpoints: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
23
24
|
rewindSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;
|
|
24
25
|
}
|
package/dist/server/ws-auth.d.ts
CHANGED
|
@@ -88,6 +88,24 @@ export interface VerifyClientInput {
|
|
|
88
88
|
allowedHostnames?: readonly string[] | undefined;
|
|
89
89
|
/** Allow browser WS URL tokens for explicit public WS URLs where cookies cannot cross hostnames. */
|
|
90
90
|
allowBrowserUrlToken?: boolean | undefined;
|
|
91
|
+
/**
|
|
92
|
+
* Let a valid `ws_token` cookie authenticate a loopback origin whose **port**
|
|
93
|
+
* differs from this server's (WS-003 opt-out). **Development only.**
|
|
94
|
+
*
|
|
95
|
+
* The Vite dev server and the WS server necessarily occupy different ports
|
|
96
|
+
* (`packages/webui/vite.config.ts` asks for 3456 and auto-advances when the
|
|
97
|
+
* WS server already holds it), so the dev loop cannot satisfy the port check.
|
|
98
|
+
*
|
|
99
|
+
* It must stay opt-in because the cookie proves nothing across ports: cookies
|
|
100
|
+
* are keyed by host, not port, and SameSite computes *site* without the port,
|
|
101
|
+
* so the browser attaches `ws_token` to a socket opened from **any** other
|
|
102
|
+
* localhost origin automatically. Enabling this in a shipped build re-opens
|
|
103
|
+
* exactly the hole WS-003 closed — a second dev server, a local app's UI, or
|
|
104
|
+
* an XSS in either can drive the agent.
|
|
105
|
+
*
|
|
106
|
+
* Wired from `WRONGSTACK_WEBUI_DEV_CROSS_PORT_WS=1`; never defaulted on.
|
|
107
|
+
*/
|
|
108
|
+
allowCrossPortLoopbackCookie?: boolean | undefined;
|
|
91
109
|
}
|
|
92
110
|
/**
|
|
93
111
|
* Decide whether to accept an incoming WebSocket handshake. Pure mirror of the
|
|
@@ -12,6 +12,13 @@ interface ModelSwitchPayload {
|
|
|
12
12
|
requestId?: string | undefined;
|
|
13
13
|
}
|
|
14
14
|
export declare function validateModelSwitchPayload(payload: unknown): PayloadValidationResult<ModelSwitchPayload>;
|
|
15
|
+
export interface ModelFallbackChoicePayload {
|
|
16
|
+
requestId: string;
|
|
17
|
+
providerId?: string | undefined;
|
|
18
|
+
model?: string | undefined;
|
|
19
|
+
autoSwitch?: boolean | undefined;
|
|
20
|
+
}
|
|
21
|
+
export declare function validateModelFallbackChoicePayload(payload: unknown): PayloadValidationResult<ModelFallbackChoicePayload>;
|
|
15
22
|
interface MailboxMessagesPayload {
|
|
16
23
|
limit?: number;
|
|
17
24
|
agentId?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/webui-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.300.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack WebUI HTTP/WebSocket server module — extracted from @wrongstack/webui in PR #243/244 to remove the CLI -> @wrongstack/webui/server cross-package edge (audit §3.1.1). Pure backend: HTTP routes, WebSocket handlers, MCP tool wrappers, HTML serving. The web frontend lives in @wrongstack/webui; this package is the standalone server it can run on.",
|
|
6
6
|
"keywords": [
|
|
@@ -40,15 +40,16 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"ws": "^8.21.1",
|
|
43
|
-
"@wrongstack/core": "0.
|
|
44
|
-
"@wrongstack/providers": "0.
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
51
|
-
"@wrongstack/
|
|
43
|
+
"@wrongstack/core": "0.300.0",
|
|
44
|
+
"@wrongstack/providers": "0.300.0",
|
|
45
|
+
"@wrongstack/kanban": "0.300.0",
|
|
46
|
+
"@wrongstack/requirement-intake": "0.300.0",
|
|
47
|
+
"@wrongstack/runtime": "0.300.0",
|
|
48
|
+
"@wrongstack/techstack": "0.300.0",
|
|
49
|
+
"@wrongstack/sage": "0.300.0",
|
|
50
|
+
"@wrongstack/mcp": "0.300.0",
|
|
51
|
+
"@wrongstack/tools": "0.300.0",
|
|
52
|
+
"@wrongstack/sdd": "0.300.0"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@types/node": "^26.1.2",
|