@wrongstack/webui-server 0.297.0 → 0.298.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.
Files changed (190) hide show
  1. package/dist/index.js +1331 -469
  2. package/dist/protocol/index.js +1 -0
  3. package/dist/protocol/registry.d.ts +1 -1
  4. package/dist/protocol/server-conversation.d.ts +1 -1
  5. package/dist/server/backend-services.d.ts +2 -0
  6. package/dist/server/codemap-cache.d.ts +1 -0
  7. package/dist/server/connection-lifecycle.d.ts +13 -0
  8. package/dist/server/connections-health-route.d.ts +7 -1
  9. package/dist/server/context-editor.d.ts +1 -2
  10. package/dist/server/entry.js +1043 -466
  11. package/dist/server/frontend-static-serve.d.ts +7 -0
  12. package/dist/server/governance-runtime.d.ts +30 -0
  13. package/dist/server/http-server.d.ts +10 -1
  14. package/dist/server/mcp-handlers.d.ts +3 -1
  15. package/dist/server/memory-handlers.d.ts +3 -3
  16. package/dist/server/pending-confirms.d.ts +9 -0
  17. package/dist/server/sdd-board-ws-handler.d.ts +1 -0
  18. package/dist/server/sdd-wizard-ws-handler.d.ts +2 -0
  19. package/dist/server/specs-ws-handler.d.ts +1 -0
  20. package/dist/server/types.d.ts +3 -1
  21. package/dist/server/ws-auth.d.ts +24 -0
  22. package/dist/server/ws-payload-validation.d.ts +18 -0
  23. package/dist/server/ws-utils.d.ts +12 -1
  24. package/package.json +13 -12
  25. package/dist/index.d.ts.map +0 -1
  26. package/dist/index.js.map +0 -7
  27. package/dist/protocol/client-conversation.d.ts.map +0 -1
  28. package/dist/protocol/client-integrations.d.ts.map +0 -1
  29. package/dist/protocol/client-operations.d.ts.map +0 -1
  30. package/dist/protocol/client-workspace.d.ts.map +0 -1
  31. package/dist/protocol/connection-fsm.d.ts.map +0 -1
  32. package/dist/protocol/decoder.d.ts.map +0 -1
  33. package/dist/protocol/index.d.ts.map +0 -1
  34. package/dist/protocol/index.js.map +0 -7
  35. package/dist/protocol/projections.d.ts.map +0 -1
  36. package/dist/protocol/registry.d.ts.map +0 -1
  37. package/dist/protocol/replay-payload.d.ts.map +0 -1
  38. package/dist/protocol/server-conversation.d.ts.map +0 -1
  39. package/dist/protocol/server-integrations.d.ts.map +0 -1
  40. package/dist/protocol/server-operations.d.ts.map +0 -1
  41. package/dist/protocol/server-workspace.d.ts.map +0 -1
  42. package/dist/protocol/types.d.ts.map +0 -1
  43. package/dist/protocol/version.d.ts.map +0 -1
  44. package/dist/server/agent-roster-handlers.d.ts.map +0 -1
  45. package/dist/server/agent-roster-routes.d.ts.map +0 -1
  46. package/dist/server/autonomy-routes.d.ts.map +0 -1
  47. package/dist/server/backend-services.d.ts.map +0 -1
  48. package/dist/server/boot.d.ts.map +0 -1
  49. package/dist/server/brain-handlers.d.ts.map +0 -1
  50. package/dist/server/brain-routes.d.ts.map +0 -1
  51. package/dist/server/chronicle-routes.d.ts.map +0 -1
  52. package/dist/server/client-presence.d.ts.map +0 -1
  53. package/dist/server/client-transport-routes.d.ts.map +0 -1
  54. package/dist/server/codebase-index-server-control.d.ts.map +0 -1
  55. package/dist/server/codebase-indexing.d.ts.map +0 -1
  56. package/dist/server/codemap-cache.d.ts.map +0 -1
  57. package/dist/server/codemap-handlers.d.ts.map +0 -1
  58. package/dist/server/codemap-telemetry.d.ts.map +0 -1
  59. package/dist/server/collaboration-ws-handler.d.ts.map +0 -1
  60. package/dist/server/completion-handlers.d.ts.map +0 -1
  61. package/dist/server/completion-routes.d.ts.map +0 -1
  62. package/dist/server/config-doctor.d.ts.map +0 -1
  63. package/dist/server/connection-handler.d.ts.map +0 -1
  64. package/dist/server/connection-lifecycle.d.ts.map +0 -1
  65. package/dist/server/connections-health-route.d.ts.map +0 -1
  66. package/dist/server/content-routes.d.ts.map +0 -1
  67. package/dist/server/context-editor.d.ts.map +0 -1
  68. package/dist/server/context-meta.d.ts.map +0 -1
  69. package/dist/server/conversation-operations.d.ts.map +0 -1
  70. package/dist/server/conversation-routes.d.ts.map +0 -1
  71. package/dist/server/custom-context-modes.d.ts.map +0 -1
  72. package/dist/server/deadcode-handlers.d.ts.map +0 -1
  73. package/dist/server/design-handlers.d.ts.map +0 -1
  74. package/dist/server/discover-mailbox-bridge.d.ts.map +0 -1
  75. package/dist/server/embedded-host-adapters.d.ts.map +0 -1
  76. package/dist/server/embedded-lifecycle.d.ts.map +0 -1
  77. package/dist/server/embedded-message-router.d.ts.map +0 -1
  78. package/dist/server/entry.d.ts.map +0 -1
  79. package/dist/server/entry.js.map +0 -7
  80. package/dist/server/eternal-iteration-broadcast.d.ts.map +0 -1
  81. package/dist/server/file-handlers.d.ts.map +0 -1
  82. package/dist/server/file-picker.d.ts.map +0 -1
  83. package/dist/server/frontend-static-serve.d.ts.map +0 -1
  84. package/dist/server/git-handlers.d.ts.map +0 -1
  85. package/dist/server/git-process.d.ts.map +0 -1
  86. package/dist/server/goal-handlers.d.ts.map +0 -1
  87. package/dist/server/goal-routes.d.ts.map +0 -1
  88. package/dist/server/goal-snapshot-routes.d.ts.map +0 -1
  89. package/dist/server/goal-ws-handler.d.ts.map +0 -1
  90. package/dist/server/handlers/index.d.ts.map +0 -1
  91. package/dist/server/handlers/worklist-handlers.d.ts.map +0 -1
  92. package/dist/server/handlers.js.map +0 -7
  93. package/dist/server/host-routes.d.ts.map +0 -1
  94. package/dist/server/http-server/analytics-handler.d.ts.map +0 -1
  95. package/dist/server/http-server/api-handlers.d.ts.map +0 -1
  96. package/dist/server/http-server.d.ts.map +0 -1
  97. package/dist/server/index.d.ts.map +0 -1
  98. package/dist/server/instance-registry.d.ts.map +0 -1
  99. package/dist/server/introspection-routes.d.ts.map +0 -1
  100. package/dist/server/kanban-board-watcher.d.ts.map +0 -1
  101. package/dist/server/kanban-daemon-subscriber.d.ts.map +0 -1
  102. package/dist/server/kanban-decomposition-routes.d.ts.map +0 -1
  103. package/dist/server/kanban-dispatch.d.ts.map +0 -1
  104. package/dist/server/kanban-host-routes.d.ts.map +0 -1
  105. package/dist/server/kanban-route-helpers.d.ts.map +0 -1
  106. package/dist/server/kanban-route-pagination.d.ts.map +0 -1
  107. package/dist/server/kanban-route-protocol.d.ts.map +0 -1
  108. package/dist/server/kanban-routes.d.ts.map +0 -1
  109. package/dist/server/kanban-run-mirror.d.ts.map +0 -1
  110. package/dist/server/kanban-supervisor.d.ts.map +0 -1
  111. package/dist/server/kanban-task-routes.d.ts.map +0 -1
  112. package/dist/server/lifecycle.d.ts.map +0 -1
  113. package/dist/server/mailbox-handlers.d.ts.map +0 -1
  114. package/dist/server/mailbox-routes.d.ts.map +0 -1
  115. package/dist/server/mcp-handlers.d.ts.map +0 -1
  116. package/dist/server/mcp-routes.d.ts.map +0 -1
  117. package/dist/server/memory-diagnostics.d.ts.map +0 -1
  118. package/dist/server/memory-handlers.d.ts.map +0 -1
  119. package/dist/server/memory-routes.d.ts.map +0 -1
  120. package/dist/server/message-dispatcher.d.ts.map +0 -1
  121. package/dist/server/mode-handlers.d.ts.map +0 -1
  122. package/dist/server/mode-operations.d.ts.map +0 -1
  123. package/dist/server/mode-routes.d.ts.map +0 -1
  124. package/dist/server/model-auto-discovery.d.ts.map +0 -1
  125. package/dist/server/model-catalog-search.d.ts.map +0 -1
  126. package/dist/server/model-catalog.d.ts.map +0 -1
  127. package/dist/server/model-operations.d.ts.map +0 -1
  128. package/dist/server/network-info.d.ts.map +0 -1
  129. package/dist/server/open-browser.d.ts.map +0 -1
  130. package/dist/server/path-containment.d.ts.map +0 -1
  131. package/dist/server/pending-confirms.d.ts.map +0 -1
  132. package/dist/server/port-utils.d.ts.map +0 -1
  133. package/dist/server/pre-context-services.d.ts.map +0 -1
  134. package/dist/server/pref-helpers.d.ts.map +0 -1
  135. package/dist/server/prefs-handlers.d.ts.map +0 -1
  136. package/dist/server/prefs-routes.d.ts.map +0 -1
  137. package/dist/server/privileged-actions.d.ts.map +0 -1
  138. package/dist/server/process-handlers.d.ts.map +0 -1
  139. package/dist/server/process-routes.d.ts.map +0 -1
  140. package/dist/server/project-handlers.d.ts.map +0 -1
  141. package/dist/server/project-routes.d.ts.map +0 -1
  142. package/dist/server/projects-manifest.d.ts.map +0 -1
  143. package/dist/server/prompts-handlers.d.ts.map +0 -1
  144. package/dist/server/provider-config-io.d.ts.map +0 -1
  145. package/dist/server/provider-config-standalone.d.ts.map +0 -1
  146. package/dist/server/provider-handlers.d.ts.map +0 -1
  147. package/dist/server/provider-keys.d.ts.map +0 -1
  148. package/dist/server/provider-routes.d.ts.map +0 -1
  149. package/dist/server/provider-store.d.ts.map +0 -1
  150. package/dist/server/route-family-dispatcher.d.ts.map +0 -1
  151. package/dist/server/routes.d.ts.map +0 -1
  152. package/dist/server/sdd-board-routes.d.ts.map +0 -1
  153. package/dist/server/sdd-board-ws-handler.d.ts.map +0 -1
  154. package/dist/server/sdd-wizard-routes.d.ts.map +0 -1
  155. package/dist/server/sdd-wizard-wiring.d.ts.map +0 -1
  156. package/dist/server/sdd-wizard-ws-handler.d.ts.map +0 -1
  157. package/dist/server/server-runtime.d.ts.map +0 -1
  158. package/dist/server/session-handlers.d.ts.map +0 -1
  159. package/dist/server/session-history.d.ts.map +0 -1
  160. package/dist/server/session-routes.d.ts.map +0 -1
  161. package/dist/server/setup-event-projection.d.ts.map +0 -1
  162. package/dist/server/setup-events-core-watchers.d.ts.map +0 -1
  163. package/dist/server/setup-events-fleet-broadcaster.d.ts.map +0 -1
  164. package/dist/server/setup-events-provider-handlers.d.ts.map +0 -1
  165. package/dist/server/setup-events-session-helpers.d.ts.map +0 -1
  166. package/dist/server/setup-events-status-watcher.d.ts.map +0 -1
  167. package/dist/server/setup-events-watcher.d.ts.map +0 -1
  168. package/dist/server/setup-events.d.ts.map +0 -1
  169. package/dist/server/setup-screen.d.ts.map +0 -1
  170. package/dist/server/shell-git-routes.d.ts.map +0 -1
  171. package/dist/server/shell-open.d.ts.map +0 -1
  172. package/dist/server/skills-handlers.d.ts.map +0 -1
  173. package/dist/server/specs-routes.d.ts.map +0 -1
  174. package/dist/server/specs-ws-handler.d.ts.map +0 -1
  175. package/dist/server/standalone-session-identity.d.ts.map +0 -1
  176. package/dist/server/start-webui.d.ts.map +0 -1
  177. package/dist/server/stream-coalescer.d.ts.map +0 -1
  178. package/dist/server/techstack-handlers.d.ts.map +0 -1
  179. package/dist/server/terminal-ws-handler.d.ts.map +0 -1
  180. package/dist/server/token-estimator.d.ts.map +0 -1
  181. package/dist/server/types.d.ts.map +0 -1
  182. package/dist/server/usage-cost.d.ts.map +0 -1
  183. package/dist/server/worklist-routes.d.ts.map +0 -1
  184. package/dist/server/worktree-routes.d.ts.map +0 -1
  185. package/dist/server/worktree-ws-handler.d.ts.map +0 -1
  186. package/dist/server/ws-auth.d.ts.map +0 -1
  187. package/dist/server/ws-payload-preferences.d.ts.map +0 -1
  188. package/dist/server/ws-payload-validation.d.ts.map +0 -1
  189. package/dist/server/ws-utils.d.ts.map +0 -1
  190. package/dist/server/zip.d.ts.map +0 -1
@@ -59,6 +59,13 @@ export interface StaticServeOptions {
59
59
  apiToken?: string | undefined;
60
60
  /** Force token auth even when the server binds to loopback. */
61
61
  requireToken?: boolean | undefined;
62
+ /**
63
+ * Extra hostnames the HTTP CSRF/DNS-rebinding guard accepts, for operators
64
+ * fronting the WebUI with a tunnel or reverse proxy. `publicWsUrl`'s hostname
65
+ * is trusted implicitly; set this when the browser-facing HTTP origin differs
66
+ * from it (WS-001).
67
+ */
68
+ allowedHostnames?: readonly string[] | undefined;
62
69
  /**
63
70
  * When true, skip `server.listen()` — the caller is responsible for
64
71
  * calling listen after attaching the WebSocketServer. This prevents
@@ -0,0 +1,30 @@
1
+ import type { AgentPipelines } from '@wrongstack/core/agent';
2
+ import type { EventBus } from '@wrongstack/core/kernel';
3
+ import type { Logger, WorkspaceCheckpointRef } from '@wrongstack/core/types';
4
+ import type { BootstrapGovernanceRuntimeOptions, GovernanceRuntimeBootstrapCloseResult, GovernanceRuntimeBootstrapResult } from '@wrongstack/runtime/governance-bootstrap';
5
+ import { createGovernanceMutationSnapshotBridge } from '@wrongstack/runtime/governance-mutation-snapshot-bridge';
6
+ export declare const WRONGSTACK_GOVERNANCE_ENV = "WRONGSTACK_GOVERNANCE";
7
+ interface GovernanceBootstrapModule {
8
+ bootstrapGovernanceRuntime(options: BootstrapGovernanceRuntimeOptions): Promise<GovernanceRuntimeBootstrapResult>;
9
+ }
10
+ interface WebUiGovernanceDependencies {
11
+ readonly load: () => Promise<GovernanceBootstrapModule>;
12
+ readonly createMutationBridge: typeof createGovernanceMutationSnapshotBridge;
13
+ }
14
+ export interface WebUiGovernanceRuntimeHandle {
15
+ installToolBoundary(pipelines: AgentPipelines): void;
16
+ close(): Promise<GovernanceRuntimeBootstrapCloseResult>;
17
+ }
18
+ export declare function webUiGovernanceRuntimeEnabled(environment: Readonly<Record<string, string | undefined>>): boolean;
19
+ export declare function setupWebUiGovernance(input: {
20
+ readonly environment: Readonly<Record<string, string | undefined>>;
21
+ readonly projectRoot: string;
22
+ readonly projectId: string;
23
+ readonly sessionId: string;
24
+ readonly contextMeta: Record<string, unknown>;
25
+ readonly events: EventBus;
26
+ readonly logger: Pick<Logger, 'info' | 'warn'>;
27
+ readonly captureWorkspaceCheckpoint: () => Promise<WorkspaceCheckpointRef | undefined>;
28
+ }, dependencies?: WebUiGovernanceDependencies): Promise<WebUiGovernanceRuntimeHandle | undefined>;
29
+ export {};
30
+ //# sourceMappingURL=governance-runtime.d.ts.map
@@ -27,6 +27,13 @@ export interface CreateHttpServerOptions {
27
27
  apiToken?: string | undefined;
28
28
  /** Force HTTP token auth even on loopback binds, useful behind public tunnels. */
29
29
  requireToken?: boolean | undefined;
30
+ /**
31
+ * Extra `Host`/`Origin` hostnames accepted by the CSRF/rebinding guard, for
32
+ * operators fronting the WebUI with a tunnel or reverse proxy. The hostname
33
+ * of `publicWsUrl` is trusted implicitly. Mirrors the WS path's
34
+ * `allowedHostnames` (see ws-auth.ts).
35
+ */
36
+ allowedHostnames?: readonly string[] | undefined;
30
37
  /**
31
38
  * If true, the `/ws-auth` endpoint exchanges a `?token=` query param (or
32
39
  * `X-WS-Token` header) for an `HttpOnly` auth cookie. The cookie is then
@@ -82,7 +89,9 @@ export declare function injectWsConfig(html: string, opts: {
82
89
  * When set, this origin is added to `connect-src` as a `ws://`/`wss://` entry.
83
90
  * @param host - The server bind host. When it matches a known loopback address
84
91
  * (`127.0.0.1`, `::1`, `[::1]`, or `localhost`), explicit `ws://`/`wss://`
85
- * entries for all three canonical loopback hosts are added to `connect-src`.
92
+ * entries for `127.0.0.1` and `localhost` are added to `connect-src`.
93
+ * IPv6 loopback (`[::1]`) is excluded — it produces an invalid CSP source
94
+ * and is covered by `'self'` (CSP maps ws:→http:, wss:→https:).
86
95
  * @param port - The server listen port. Defaults to `3456`. Unnecessary when
87
96
  * only publicWsUrl is used (no loopback branch).
88
97
  */
@@ -8,7 +8,7 @@
8
8
  * config IO, url/header persistence, and live registry start/stop logic lives
9
9
  * there; here we only map structured results to WS events the browser expects.
10
10
  */
11
- import { type MCPRegistry, type MCPServerOperationalHealth } from '@wrongstack/mcp';
11
+ import { type MCPRegistry, type MCPServerOperationalHealth, type McpServerInfo } from '@wrongstack/mcp';
12
12
  import type { WebSocket } from 'ws';
13
13
  import type { WSClientMessage } from './types.js';
14
14
  /** Wire view of a server as the browser MCP panel consumes it. */
@@ -28,6 +28,8 @@ export interface MCPServerView {
28
28
  url?: string;
29
29
  health?: MCPServerOperationalHealth;
30
30
  }
31
+ /** Project the shared {@link McpServerInfo} into the browser wire shape. */
32
+ export declare function toView(info: McpServerInfo, health?: MCPServerOperationalHealth | undefined): MCPServerView;
31
33
  /** mcp.list — configured servers merged with live registry status + tools. */
32
34
  export declare function handleMcpList(ws: WebSocket, _msg: WSClientMessage, globalConfigPath: string, mcpRegistry?: MCPRegistry): Promise<void>;
33
35
  /** mcp.add — persist a new server (incl. url/headers) and start it if enabled. */
@@ -67,9 +67,9 @@ export declare function handleSageRemember(ws: WebSocket, msg: unknown, memorySt
67
67
  * Request: { type: 'memory.sage.delete', payload: { id, reason?, force?, neverInject? } }
68
68
  * Response: { type: 'memory.sage.delete', payload: { success, message } }
69
69
  *
70
- * `force` defaults to `true` (backward-compatible). When `false`, the
71
- * permanent-memory guard in `deleteSage` is respected and
72
- * `persistence: 'permanent'` entries cannot be deleted.
70
+ * `force` defaults to `false`. The caller must explicitly pass `force: true`
71
+ * to authorize deletion. The permanent-memory guard in `deleteSage` is
72
+ * always respected when force is not set.
73
73
  *
74
74
  * `neverInject` (default false) marks the memory so context injection
75
75
  * never loads it — used when a memory is factually wrong, not just
@@ -1,6 +1,15 @@
1
1
  export type ConfirmDecision = 'yes' | 'no' | 'always' | 'deny';
2
2
  export interface PendingConfirm {
3
3
  resolve: (decision: ConfirmDecision) => void;
4
+ /**
5
+ * Session this prompt belongs to. `pendingConfirms` is one process-wide map
6
+ * replayed to every connected client, and the resolver keyed only on a
7
+ * client-supplied id — with a session check that no-op'd whenever the client
8
+ * omitted `sessionId`. So any client could answer any session's prompt
9
+ * (WS-082). Recorded here so ownership is checked against the server's own
10
+ * record rather than against whatever the client chose to send.
11
+ */
12
+ sessionId?: string | undefined;
4
13
  decisionSource?: string | undefined;
5
14
  riskTier?: 'safe' | 'standard' | 'destructive' | undefined;
6
15
  boundaryReason?: string | undefined;
@@ -48,6 +48,7 @@ export declare class SddBoardWebSocketHandler {
48
48
  private poll;
49
49
  private pollInFlight;
50
50
  private unsub;
51
+ private disposed;
51
52
  constructor(boardsDir: string, events?: EventBus, lifecycle?: SddBoardLifecycleDeps, security?: SddBoardSecurityDeps);
52
53
  addClient(ws: WebSocket): void;
53
54
  handleMessage(msg: SddBoardWSMessage): Promise<void>;
@@ -85,11 +85,13 @@ export declare class SddWizardWebSocketHandler {
85
85
  * flight (or after the probe has settled).
86
86
  */
87
87
  private resumeProbe;
88
+ private disposed;
88
89
  constructor(deps: SddWizardDeps);
89
90
  private bootstrap;
90
91
  /** Rehydrate a persisted interview if one exists. */
91
92
  private tryResume;
92
93
  addClient(ws: WebSocket): void;
94
+ dispose(): void;
93
95
  handleMessage(msg: WizardMessage): Promise<void>;
94
96
  private parseRunOpts;
95
97
  private onStart;
@@ -19,6 +19,7 @@ export declare class SpecsWebSocketHandler {
19
19
  private clients;
20
20
  constructor(specsDir: string, taskGraphsDir: string);
21
21
  addClient(ws: WebSocket): void;
22
+ dispose(): void;
22
23
  handleMessage(msg: SpecsWSMessage): Promise<void>;
23
24
  private buildList;
24
25
  private broadcastList;
@@ -2,7 +2,7 @@ import type { WebSocket } from 'ws';
2
2
  import type { TrustBoundary } from '@wrongstack/core/security';
3
3
  import type { ConfigStore, ModelsRegistry, SecretVault, SessionStore } from '@wrongstack/core/types';
4
4
  import type { JournalEntry } from '@wrongstack/core/storage';
5
- import type { Agent } from '@wrongstack/core/agent';
5
+ import type { Agent, AgentPipelines } from '@wrongstack/core/agent';
6
6
  import type { EventBus } from '@wrongstack/core/kernel';
7
7
  import type { ToolRegistry } from '@wrongstack/core/registry';
8
8
  /** Compatibility envelope; new boundaries should decode to CanonicalServerMessage. */
@@ -20,6 +20,8 @@ export interface WebUIOptions {
20
20
  surface?: 'webui' | 'simpleui' | undefined;
21
21
  /** Policy authority for terminal/process/native-shell actions. */
22
22
  trustBoundary?: TrustBoundary | undefined;
23
+ /** Trusted host-only hook installed around leader and light-subagent tools. */
24
+ installToolBoundary?: ((pipelines: AgentPipelines) => void) | undefined;
23
25
  /** HTTP frontend port. Prefer `httpPort`; `port` is kept for compatibility. */
24
26
  port?: number | undefined;
25
27
  /** HTTP frontend port. */
@@ -42,6 +42,30 @@ export declare function hostHeaderOk(input: {
42
42
  wsHost: string;
43
43
  allowedHostnames?: readonly string[] | undefined;
44
44
  }): boolean;
45
+ /**
46
+ * CSRF / drive-by guard for the HTTP surface (WS-001).
47
+ *
48
+ * The WebSocket upgrade path has always been Origin- and Host-checked, but the
49
+ * plain HTTP `/api/*` surface was not: it built its URL from a hardcoded base,
50
+ * never read `Origin`, and (on the default loopback bind) required no token. A
51
+ * `POST` with `Content-Type: text/plain` is a CORS *simple request*, so any page
52
+ * the user visits could fire one without a preflight — the response being
53
+ * unreadable does not undo the side effect.
54
+ *
55
+ * Policy, mirroring `hasTrustedBrowserOrigin` in the HQ server:
56
+ * - the `Host` authority must already be trusted (DNS-rebinding guard), and
57
+ * - when the browser sends `Origin`, it must name that same authority.
58
+ *
59
+ * A missing `Origin` is allowed: same-origin top-level navigations and
60
+ * non-browser clients (curl, the CLI, tests) legitimately omit it, and those
61
+ * cannot be driven by a hostile page.
62
+ */
63
+ export declare function httpRequestOriginOk(input: {
64
+ origin: string | undefined;
65
+ hostHeader: string | undefined;
66
+ wsHost: string;
67
+ allowedHostnames?: readonly string[] | undefined;
68
+ }): boolean;
45
69
  export interface VerifyClientInput {
46
70
  /** Browser `Origin` header, or undefined for non-browser clients. */
47
71
  origin?: string | undefined;
@@ -140,4 +140,22 @@ interface ProjectsSelectPayload {
140
140
  name?: string;
141
141
  }
142
142
  export declare function validateProjectsSelectPayload(payload: unknown): PayloadValidationResult<ProjectsSelectPayload>;
143
+ /**
144
+ * `mcp.add` / `mcp.update` payload.
145
+ *
146
+ * WS-004: these handlers cast the raw WS payload with `as McpServerInput` and
147
+ * passed it straight to `addMcp`, which persists `command`/`args`/`env` to the
148
+ * global config and spawns them — so an unvalidated frame became a persistent
149
+ * child process that respawns on every restart. Validate the shape and the
150
+ * types before anything reaches disk.
151
+ *
152
+ * This checks structure, not policy: `command` is still whatever the operator
153
+ * configures. The spawn itself is hardened separately by
154
+ * `buildWin32CmdShimInvocation` (CMDI-005).
155
+ */
156
+ export interface McpServerPayload {
157
+ name: string;
158
+ [key: string]: unknown;
159
+ }
160
+ export declare function validateMcpServerPayload(payload: unknown, label: string): PayloadValidationResult<McpServerPayload>;
143
161
  //# sourceMappingURL=ws-payload-validation.d.ts.map
@@ -25,7 +25,18 @@ export declare function broadcast(clients: Map<WebSocket, ConnectedClient>, msg:
25
25
  */
26
26
  export declare function sendResult(ws: WebSocket, success: boolean, message: string): void;
27
27
  /**
28
- * Extract a human-readable message from an unknown thrown value.
28
+ * Extract a human-readable message from an unknown thrown value, safe to put
29
+ * in a frame that leaves the process.
30
+ *
31
+ * WS-066: this was `err instanceof Error ? err.message : String(err)` — the
32
+ * verbatim throw. A provider that echoes an `Authorization` header back in its
33
+ * error body, or a connection string with an inline password, went straight to
34
+ * the browser and into whatever the browser logs. {@link scrubErrorDetail}
35
+ * keeps the message (this is a local dev tool; opaque errors would gut it) but
36
+ * removes credentials and rewrites the home directory to `~`.
37
+ *
38
+ * For HTTP `/api/*` JSON bodies — a less authenticated surface — use
39
+ * `sanitizeApiError` instead, which returns a category and nothing else.
29
40
  */
30
41
  export declare function errMessage(err: unknown): string;
31
42
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/webui-server",
3
- "version": "0.297.0",
3
+ "version": "0.298.1",
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": [
@@ -35,22 +35,23 @@
35
35
  "./package.json": "./package.json"
36
36
  },
37
37
  "files": [
38
- "dist"
38
+ "dist",
39
+ "!dist/**/*.map"
39
40
  ],
40
41
  "dependencies": {
41
42
  "ws": "^8.21.1",
42
- "@wrongstack/core": "0.297.0",
43
- "@wrongstack/mcp": "0.297.0",
44
- "@wrongstack/runtime": "0.297.0",
45
- "@wrongstack/techstack": "0.297.0",
46
- "@wrongstack/sdd": "0.297.0",
47
- "@wrongstack/providers": "0.297.0",
48
- "@wrongstack/kanban": "0.297.0",
49
- "@wrongstack/sage": "0.297.0",
50
- "@wrongstack/tools": "0.297.0"
43
+ "@wrongstack/kanban": "0.298.1",
44
+ "@wrongstack/core": "0.298.1",
45
+ "@wrongstack/runtime": "0.298.1",
46
+ "@wrongstack/mcp": "0.298.1",
47
+ "@wrongstack/providers": "0.298.1",
48
+ "@wrongstack/techstack": "0.298.1",
49
+ "@wrongstack/sage": "0.298.1",
50
+ "@wrongstack/sdd": "0.298.1",
51
+ "@wrongstack/tools": "0.298.1"
51
52
  },
52
53
  "devDependencies": {
53
- "@types/node": "^26.1.1",
54
+ "@types/node": "^26.1.2",
54
55
  "@types/ws": "^8.18.1",
55
56
  "typescript": "^7.0.2"
56
57
  },
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC"}