@wrongstack/webui-server 0.310.1 → 0.313.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -100,7 +100,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
100
100
|
"showSageMemoryInject",
|
|
101
101
|
// WrongProxy / WrongTrace master switch. When on, the CLI rewrites every
|
|
102
102
|
// provider's base URL through the configured proxy URL (default
|
|
103
|
-
// http://localhost:
|
|
103
|
+
// http://localhost:3444 → http://localhost:3444/proxy/<host><path>).
|
|
104
104
|
// Excluded providers (openai-codex) flow through unchanged.
|
|
105
105
|
"wrongProxyEnabled"
|
|
106
106
|
]);
|
|
@@ -171,7 +171,7 @@ var STRING_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
171
171
|
"autoReviewModel",
|
|
172
172
|
"autoReviewFallbackProfile",
|
|
173
173
|
// WrongProxy / WrongTrace URL. Empty = unset. Default lives in
|
|
174
|
-
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:
|
|
174
|
+
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:3444'); users
|
|
175
175
|
// can override here for non-default daemon ports / paths.
|
|
176
176
|
"wrongProxyUrl"
|
|
177
177
|
]);
|
|
@@ -187,7 +187,7 @@ var ENUM_PREF_KEYS = {
|
|
|
187
187
|
reasoningEffort: REASONING_EFFORT_VALUES,
|
|
188
188
|
cacheTtl: CACHE_TTL_VALUES,
|
|
189
189
|
statuslineMode: /* @__PURE__ */ new Set(["minimum", "detailed", "no-color"]),
|
|
190
|
-
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "cycle"]),
|
|
190
|
+
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "static", "cycle"]),
|
|
191
191
|
fsAccess: /* @__PURE__ */ new Set(["unrestricted", "project"]),
|
|
192
192
|
// Chimera autoFix + auto-review cascade threshold
|
|
193
193
|
chimeraAutoFix: /* @__PURE__ */ new Set(["off", "ask", "auto"]),
|
|
@@ -6376,7 +6376,8 @@ function estimateTokens(s) {
|
|
|
6376
6376
|
function stringifyContent(c) {
|
|
6377
6377
|
if (typeof c === "string") return c;
|
|
6378
6378
|
try {
|
|
6379
|
-
|
|
6379
|
+
const serialized = JSON.stringify(c);
|
|
6380
|
+
return serialized === void 0 ? String(c) : serialized;
|
|
6380
6381
|
} catch {
|
|
6381
6382
|
return String(c);
|
|
6382
6383
|
}
|
|
@@ -21211,7 +21212,7 @@ var PREF_KEYS = [
|
|
|
21211
21212
|
// Fleet chat verbosity: off | full (migrated from streamFleet boolean).
|
|
21212
21213
|
"fleetChatVerbosity",
|
|
21213
21214
|
// WrongProxy / WrongTrace: master switch + configurable URL (default
|
|
21214
|
-
// http://localhost:
|
|
21215
|
+
// http://localhost:3444). When `wrongProxyEnabled` is true and the daemon
|
|
21215
21216
|
// is reachable, every provider's base URL flows through
|
|
21216
21217
|
// `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is excluded by spec.
|
|
21217
21218
|
"wrongProxyEnabled",
|
|
@@ -23919,6 +23920,17 @@ function setupEvents(deps2) {
|
|
|
23919
23920
|
})
|
|
23920
23921
|
});
|
|
23921
23922
|
});
|
|
23923
|
+
on("provider.model_switched", (e) => {
|
|
23924
|
+
broadcast2(clients, {
|
|
23925
|
+
type: "provider.model_switched",
|
|
23926
|
+
payload: sessionPayload2({
|
|
23927
|
+
sessionId: e.sessionId,
|
|
23928
|
+
from: e.from,
|
|
23929
|
+
to: e.to,
|
|
23930
|
+
timestamp: e.timestamp
|
|
23931
|
+
})
|
|
23932
|
+
});
|
|
23933
|
+
});
|
|
23922
23934
|
on("provider.fallback_pending", (e) => {
|
|
23923
23935
|
broadcast2(clients, {
|
|
23924
23936
|
type: "provider.fallback_pending",
|
|
@@ -24257,6 +24269,8 @@ import {
|
|
|
24257
24269
|
// src/server/backend-services.ts
|
|
24258
24270
|
import { join as join15 } from "node:path";
|
|
24259
24271
|
import { Agent } from "@wrongstack/core/agent";
|
|
24272
|
+
import { HookRegistry, HookRunner } from "@wrongstack/core/hooks";
|
|
24273
|
+
import { createWrongTraceHookPair, recordGateDecision, snapshotGateDecisions, persistWrongTraceGateCounters } from "@wrongstack/wrongtrace";
|
|
24260
24274
|
import {
|
|
24261
24275
|
BrainDecisionLedger,
|
|
24262
24276
|
BrainMonitor,
|
|
@@ -25298,6 +25312,33 @@ async function createAgentServices(input) {
|
|
|
25298
25312
|
const secretScrubber = container.resolve(TOKENS2.SecretScrubber);
|
|
25299
25313
|
const renderer = container.has(TOKENS2.Renderer) ? container.resolve(TOKENS2.Renderer) : void 0;
|
|
25300
25314
|
const permissionPolicy = container.resolve(TOKENS2.PermissionPolicy);
|
|
25315
|
+
const wrongTraceHookRegistry = new HookRegistry();
|
|
25316
|
+
const wrongTraceHooks = createWrongTraceHookPair(() => context.session.id, {
|
|
25317
|
+
emit: (event) => {
|
|
25318
|
+
events.emit("wrongtrace.gate.decision", event);
|
|
25319
|
+
recordGateDecision(event);
|
|
25320
|
+
void persistWrongTraceGateCounters(projectRoot, snapshotGateDecisions());
|
|
25321
|
+
}
|
|
25322
|
+
});
|
|
25323
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
25324
|
+
"PreToolUse",
|
|
25325
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
25326
|
+
wrongTraceHooks.preToolUse,
|
|
25327
|
+
"wrongtrace-gate"
|
|
25328
|
+
);
|
|
25329
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
25330
|
+
"PostToolUse",
|
|
25331
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
25332
|
+
wrongTraceHooks.postToolUse,
|
|
25333
|
+
"wrongtrace-gate"
|
|
25334
|
+
);
|
|
25335
|
+
const wrongTraceHookRunner = new HookRunner({
|
|
25336
|
+
registry: wrongTraceHookRegistry,
|
|
25337
|
+
sessionId: () => context.session.id,
|
|
25338
|
+
// Coordination, not enforcement: these hooks are fail-open by
|
|
25339
|
+
// construction and must run regardless of shell-hook gating.
|
|
25340
|
+
allowNonPolicy: true
|
|
25341
|
+
});
|
|
25301
25342
|
const toolExecutor = new ToolExecutor(toolRegistry, {
|
|
25302
25343
|
permissionPolicy,
|
|
25303
25344
|
secretScrubber,
|
|
@@ -25307,6 +25348,7 @@ async function createAgentServices(input) {
|
|
|
25307
25348
|
iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,
|
|
25308
25349
|
perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,
|
|
25309
25350
|
tracer: void 0,
|
|
25351
|
+
hookRunner: wrongTraceHookRunner,
|
|
25310
25352
|
// Off unless the operator opts in. The WebUI drives the same agent as the
|
|
25311
25353
|
// CLI, so it must resolve this identically — a surface-dependent gate
|
|
25312
25354
|
// would mean the same repo governs under `wstack` and not in the browser.
|
|
@@ -25528,6 +25570,12 @@ async function createAgentServices(input) {
|
|
|
25528
25570
|
// round-robin keeps reassigning the doomed model. Mirrors the CLI
|
|
25529
25571
|
// factory wiring at host-subagent-factory.ts:337.
|
|
25530
25572
|
statusTracker: container.safeResolve(TOKENS2.ProviderModelStatusTracker),
|
|
25573
|
+
// WrongTrace lock gate for SDD-wizard workers: the standalone server
|
|
25574
|
+
// already built a dedicated WrongTrace-only HookRunner for its own
|
|
25575
|
+
// executor above; handing the same runner to the runtime factory
|
|
25576
|
+
// makes every worker edit honor peer locks with one process-wide
|
|
25577
|
+
// owner identity (context.session.id).
|
|
25578
|
+
hookRunner: wrongTraceHookRunner,
|
|
25531
25579
|
...input.installToolBoundary ? { installToolBoundary: input.installToolBoundary } : {}
|
|
25532
25580
|
}),
|
|
25533
25581
|
paths: {
|
|
@@ -27597,6 +27645,40 @@ function setupWebuiCredentialWatcher(options) {
|
|
|
27597
27645
|
return credentialWatcher.close;
|
|
27598
27646
|
}
|
|
27599
27647
|
|
|
27648
|
+
// src/server/start-webui-proxy-apply.ts
|
|
27649
|
+
import { createProxyInstantApply } from "@wrongstack/core/wiring/proxy-rewrite";
|
|
27650
|
+
import { makeProviderFromConfig as makeProviderFromConfig6, withCatalogCapabilities as withCatalogCapabilities2 } from "@wrongstack/providers";
|
|
27651
|
+
function setupWebuiProxyInstantApply(options) {
|
|
27652
|
+
const { state, deps: deps2, updateAutoCompactionMaxContext } = options;
|
|
27653
|
+
const instantApply = createProxyInstantApply({
|
|
27654
|
+
// Prefer the LIVE provider id over the config's — mirrors the CLI
|
|
27655
|
+
// wiring; the context is the source of truth once the session boots.
|
|
27656
|
+
getActiveProviderId: () => deps2.context.provider?.id ?? state.getConfig().provider ?? "",
|
|
27657
|
+
// Same raw-read rule as every other WebUI provider-build site:
|
|
27658
|
+
// savedCfg.baseUrl ?? top-level config.baseUrl.
|
|
27659
|
+
getRawBaseUrl: (providerId) => state.getConfig().providers?.[providerId]?.baseUrl ?? state.getConfig().baseUrl,
|
|
27660
|
+
rebuildProvider: async (providerId) => {
|
|
27661
|
+
await deps2.context.runModelTransition(async () => {
|
|
27662
|
+
if (deps2.context.provider?.id !== providerId) return;
|
|
27663
|
+
const cur = state.getConfig();
|
|
27664
|
+
const providerCfg = cur.providers?.[providerId] ?? { type: providerId };
|
|
27665
|
+
const routedCfg = routeProviderCfgThroughProxy(providerCfg, cur.baseUrl, providerId);
|
|
27666
|
+
const built = deps2.providerRegistry.has(providerId) ? deps2.providerRegistry.create({ ...routedCfg, type: providerId }) : makeProviderFromConfig6(providerId, routedCfg);
|
|
27667
|
+
const model = deps2.context.model ?? cur.model ?? "";
|
|
27668
|
+
const newProv = deps2.modelsRegistry ? await withCatalogCapabilities2(deps2.modelsRegistry, providerId, built, {
|
|
27669
|
+
...routedCfg,
|
|
27670
|
+
type: providerId,
|
|
27671
|
+
model
|
|
27672
|
+
}) : built;
|
|
27673
|
+
deps2.context.provider = newProv;
|
|
27674
|
+
void updateAutoCompactionMaxContext(newProv, providerId).catch(() => void 0);
|
|
27675
|
+
});
|
|
27676
|
+
},
|
|
27677
|
+
logger: deps2.logger
|
|
27678
|
+
});
|
|
27679
|
+
return () => instantApply.dispose();
|
|
27680
|
+
}
|
|
27681
|
+
|
|
27600
27682
|
// src/server/start-webui-remediation.ts
|
|
27601
27683
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
27602
27684
|
import { toLanguagePackageInput } from "@wrongstack/techstack";
|
|
@@ -27686,6 +27768,7 @@ function setupWebuiShutdown(options) {
|
|
|
27686
27768
|
await options.todosCheckpoint.detach();
|
|
27687
27769
|
await options.stopHeapWatchdog();
|
|
27688
27770
|
options.getCredentialWatcherClose()?.();
|
|
27771
|
+
options.getProxyInstantApplyDispose()();
|
|
27689
27772
|
options.disposeRealtimeHandlers();
|
|
27690
27773
|
const governanceCleanup = await options.governanceHandle?.close();
|
|
27691
27774
|
if (governanceCleanup && !governanceCleanup.ok) {
|
|
@@ -28232,6 +28315,11 @@ async function startWebUI(opts = {}) {
|
|
|
28232
28315
|
clients,
|
|
28233
28316
|
updateAutoCompactionMaxContext
|
|
28234
28317
|
});
|
|
28318
|
+
const proxyInstantApplyDispose = setupWebuiProxyInstantApply({
|
|
28319
|
+
state,
|
|
28320
|
+
deps: deps2,
|
|
28321
|
+
updateAutoCompactionMaxContext
|
|
28322
|
+
});
|
|
28235
28323
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
28236
28324
|
collectStats: () => ({
|
|
28237
28325
|
surface: opts.surface ?? "webui",
|
|
@@ -28339,6 +28427,7 @@ projectRoot: ${ev.projectRoot ?? "?"}`,
|
|
|
28339
28427
|
todosCheckpoint,
|
|
28340
28428
|
stopHeapWatchdog,
|
|
28341
28429
|
getCredentialWatcherClose: () => credentialWatcherClose,
|
|
28430
|
+
getProxyInstantApplyDispose: () => proxyInstantApplyDispose,
|
|
28342
28431
|
disposeRealtimeHandlers,
|
|
28343
28432
|
governanceHandle,
|
|
28344
28433
|
logger,
|
package/dist/server/entry.js
CHANGED
|
@@ -101,7 +101,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
101
101
|
"showSageMemoryInject",
|
|
102
102
|
// WrongProxy / WrongTrace master switch. When on, the CLI rewrites every
|
|
103
103
|
// provider's base URL through the configured proxy URL (default
|
|
104
|
-
// http://localhost:
|
|
104
|
+
// http://localhost:3444 → http://localhost:3444/proxy/<host><path>).
|
|
105
105
|
// Excluded providers (openai-codex) flow through unchanged.
|
|
106
106
|
"wrongProxyEnabled"
|
|
107
107
|
]);
|
|
@@ -172,7 +172,7 @@ var STRING_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
172
172
|
"autoReviewModel",
|
|
173
173
|
"autoReviewFallbackProfile",
|
|
174
174
|
// WrongProxy / WrongTrace URL. Empty = unset. Default lives in
|
|
175
|
-
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:
|
|
175
|
+
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:3444'); users
|
|
176
176
|
// can override here for non-default daemon ports / paths.
|
|
177
177
|
"wrongProxyUrl"
|
|
178
178
|
]);
|
|
@@ -188,7 +188,7 @@ var ENUM_PREF_KEYS = {
|
|
|
188
188
|
reasoningEffort: REASONING_EFFORT_VALUES,
|
|
189
189
|
cacheTtl: CACHE_TTL_VALUES,
|
|
190
190
|
statuslineMode: /* @__PURE__ */ new Set(["minimum", "detailed", "no-color"]),
|
|
191
|
-
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "cycle"]),
|
|
191
|
+
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "static", "cycle"]),
|
|
192
192
|
fsAccess: /* @__PURE__ */ new Set(["unrestricted", "project"]),
|
|
193
193
|
// Chimera autoFix + auto-review cascade threshold
|
|
194
194
|
chimeraAutoFix: /* @__PURE__ */ new Set(["off", "ask", "auto"]),
|
|
@@ -6191,7 +6191,8 @@ function estimateTokens(s) {
|
|
|
6191
6191
|
function stringifyContent(c) {
|
|
6192
6192
|
if (typeof c === "string") return c;
|
|
6193
6193
|
try {
|
|
6194
|
-
|
|
6194
|
+
const serialized = JSON.stringify(c);
|
|
6195
|
+
return serialized === void 0 ? String(c) : serialized;
|
|
6195
6196
|
} catch {
|
|
6196
6197
|
return String(c);
|
|
6197
6198
|
}
|
|
@@ -19497,7 +19498,7 @@ var PREF_KEYS = [
|
|
|
19497
19498
|
// Fleet chat verbosity: off | full (migrated from streamFleet boolean).
|
|
19498
19499
|
"fleetChatVerbosity",
|
|
19499
19500
|
// WrongProxy / WrongTrace: master switch + configurable URL (default
|
|
19500
|
-
// http://localhost:
|
|
19501
|
+
// http://localhost:3444). When `wrongProxyEnabled` is true and the daemon
|
|
19501
19502
|
// is reachable, every provider's base URL flows through
|
|
19502
19503
|
// `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is excluded by spec.
|
|
19503
19504
|
"wrongProxyEnabled",
|
|
@@ -22103,6 +22104,17 @@ function setupEvents(deps2) {
|
|
|
22103
22104
|
})
|
|
22104
22105
|
});
|
|
22105
22106
|
});
|
|
22107
|
+
on("provider.model_switched", (e) => {
|
|
22108
|
+
broadcast2(clients, {
|
|
22109
|
+
type: "provider.model_switched",
|
|
22110
|
+
payload: sessionPayload2({
|
|
22111
|
+
sessionId: e.sessionId,
|
|
22112
|
+
from: e.from,
|
|
22113
|
+
to: e.to,
|
|
22114
|
+
timestamp: e.timestamp
|
|
22115
|
+
})
|
|
22116
|
+
});
|
|
22117
|
+
});
|
|
22106
22118
|
on("provider.fallback_pending", (e) => {
|
|
22107
22119
|
broadcast2(clients, {
|
|
22108
22120
|
type: "provider.fallback_pending",
|
|
@@ -22441,6 +22453,8 @@ import {
|
|
|
22441
22453
|
// src/server/backend-services.ts
|
|
22442
22454
|
import { join as join12 } from "node:path";
|
|
22443
22455
|
import { Agent } from "@wrongstack/core/agent";
|
|
22456
|
+
import { HookRegistry, HookRunner } from "@wrongstack/core/hooks";
|
|
22457
|
+
import { createWrongTraceHookPair, recordGateDecision, snapshotGateDecisions, persistWrongTraceGateCounters } from "@wrongstack/wrongtrace";
|
|
22444
22458
|
import {
|
|
22445
22459
|
BrainDecisionLedger,
|
|
22446
22460
|
BrainMonitor,
|
|
@@ -23482,6 +23496,33 @@ async function createAgentServices(input) {
|
|
|
23482
23496
|
const secretScrubber = container.resolve(TOKENS.SecretScrubber);
|
|
23483
23497
|
const renderer = container.has(TOKENS.Renderer) ? container.resolve(TOKENS.Renderer) : void 0;
|
|
23484
23498
|
const permissionPolicy = container.resolve(TOKENS.PermissionPolicy);
|
|
23499
|
+
const wrongTraceHookRegistry = new HookRegistry();
|
|
23500
|
+
const wrongTraceHooks = createWrongTraceHookPair(() => context.session.id, {
|
|
23501
|
+
emit: (event) => {
|
|
23502
|
+
events.emit("wrongtrace.gate.decision", event);
|
|
23503
|
+
recordGateDecision(event);
|
|
23504
|
+
void persistWrongTraceGateCounters(projectRoot, snapshotGateDecisions());
|
|
23505
|
+
}
|
|
23506
|
+
});
|
|
23507
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
23508
|
+
"PreToolUse",
|
|
23509
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
23510
|
+
wrongTraceHooks.preToolUse,
|
|
23511
|
+
"wrongtrace-gate"
|
|
23512
|
+
);
|
|
23513
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
23514
|
+
"PostToolUse",
|
|
23515
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
23516
|
+
wrongTraceHooks.postToolUse,
|
|
23517
|
+
"wrongtrace-gate"
|
|
23518
|
+
);
|
|
23519
|
+
const wrongTraceHookRunner = new HookRunner({
|
|
23520
|
+
registry: wrongTraceHookRegistry,
|
|
23521
|
+
sessionId: () => context.session.id,
|
|
23522
|
+
// Coordination, not enforcement: these hooks are fail-open by
|
|
23523
|
+
// construction and must run regardless of shell-hook gating.
|
|
23524
|
+
allowNonPolicy: true
|
|
23525
|
+
});
|
|
23485
23526
|
const toolExecutor = new ToolExecutor(toolRegistry, {
|
|
23486
23527
|
permissionPolicy,
|
|
23487
23528
|
secretScrubber,
|
|
@@ -23491,6 +23532,7 @@ async function createAgentServices(input) {
|
|
|
23491
23532
|
iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,
|
|
23492
23533
|
perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,
|
|
23493
23534
|
tracer: void 0,
|
|
23535
|
+
hookRunner: wrongTraceHookRunner,
|
|
23494
23536
|
// Off unless the operator opts in. The WebUI drives the same agent as the
|
|
23495
23537
|
// CLI, so it must resolve this identically — a surface-dependent gate
|
|
23496
23538
|
// would mean the same repo governs under `wstack` and not in the browser.
|
|
@@ -23712,6 +23754,12 @@ async function createAgentServices(input) {
|
|
|
23712
23754
|
// round-robin keeps reassigning the doomed model. Mirrors the CLI
|
|
23713
23755
|
// factory wiring at host-subagent-factory.ts:337.
|
|
23714
23756
|
statusTracker: container.safeResolve(TOKENS.ProviderModelStatusTracker),
|
|
23757
|
+
// WrongTrace lock gate for SDD-wizard workers: the standalone server
|
|
23758
|
+
// already built a dedicated WrongTrace-only HookRunner for its own
|
|
23759
|
+
// executor above; handing the same runner to the runtime factory
|
|
23760
|
+
// makes every worker edit honor peer locks with one process-wide
|
|
23761
|
+
// owner identity (context.session.id).
|
|
23762
|
+
hookRunner: wrongTraceHookRunner,
|
|
23715
23763
|
...input.installToolBoundary ? { installToolBoundary: input.installToolBoundary } : {}
|
|
23716
23764
|
}),
|
|
23717
23765
|
paths: {
|
|
@@ -25781,6 +25829,40 @@ function setupWebuiCredentialWatcher(options) {
|
|
|
25781
25829
|
return credentialWatcher.close;
|
|
25782
25830
|
}
|
|
25783
25831
|
|
|
25832
|
+
// src/server/start-webui-proxy-apply.ts
|
|
25833
|
+
import { createProxyInstantApply } from "@wrongstack/core/wiring/proxy-rewrite";
|
|
25834
|
+
import { makeProviderFromConfig as makeProviderFromConfig4, withCatalogCapabilities as withCatalogCapabilities2 } from "@wrongstack/providers";
|
|
25835
|
+
function setupWebuiProxyInstantApply(options) {
|
|
25836
|
+
const { state, deps: deps2, updateAutoCompactionMaxContext } = options;
|
|
25837
|
+
const instantApply = createProxyInstantApply({
|
|
25838
|
+
// Prefer the LIVE provider id over the config's — mirrors the CLI
|
|
25839
|
+
// wiring; the context is the source of truth once the session boots.
|
|
25840
|
+
getActiveProviderId: () => deps2.context.provider?.id ?? state.getConfig().provider ?? "",
|
|
25841
|
+
// Same raw-read rule as every other WebUI provider-build site:
|
|
25842
|
+
// savedCfg.baseUrl ?? top-level config.baseUrl.
|
|
25843
|
+
getRawBaseUrl: (providerId) => state.getConfig().providers?.[providerId]?.baseUrl ?? state.getConfig().baseUrl,
|
|
25844
|
+
rebuildProvider: async (providerId) => {
|
|
25845
|
+
await deps2.context.runModelTransition(async () => {
|
|
25846
|
+
if (deps2.context.provider?.id !== providerId) return;
|
|
25847
|
+
const cur = state.getConfig();
|
|
25848
|
+
const providerCfg = cur.providers?.[providerId] ?? { type: providerId };
|
|
25849
|
+
const routedCfg = routeProviderCfgThroughProxy(providerCfg, cur.baseUrl, providerId);
|
|
25850
|
+
const built = deps2.providerRegistry.has(providerId) ? deps2.providerRegistry.create({ ...routedCfg, type: providerId }) : makeProviderFromConfig4(providerId, routedCfg);
|
|
25851
|
+
const model = deps2.context.model ?? cur.model ?? "";
|
|
25852
|
+
const newProv = deps2.modelsRegistry ? await withCatalogCapabilities2(deps2.modelsRegistry, providerId, built, {
|
|
25853
|
+
...routedCfg,
|
|
25854
|
+
type: providerId,
|
|
25855
|
+
model
|
|
25856
|
+
}) : built;
|
|
25857
|
+
deps2.context.provider = newProv;
|
|
25858
|
+
void updateAutoCompactionMaxContext(newProv, providerId).catch(() => void 0);
|
|
25859
|
+
});
|
|
25860
|
+
},
|
|
25861
|
+
logger: deps2.logger
|
|
25862
|
+
});
|
|
25863
|
+
return () => instantApply.dispose();
|
|
25864
|
+
}
|
|
25865
|
+
|
|
25784
25866
|
// src/server/start-webui-remediation.ts
|
|
25785
25867
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
25786
25868
|
import { toLanguagePackageInput } from "@wrongstack/techstack";
|
|
@@ -25870,6 +25952,7 @@ function setupWebuiShutdown(options) {
|
|
|
25870
25952
|
await options.todosCheckpoint.detach();
|
|
25871
25953
|
await options.stopHeapWatchdog();
|
|
25872
25954
|
options.getCredentialWatcherClose()?.();
|
|
25955
|
+
options.getProxyInstantApplyDispose()();
|
|
25873
25956
|
options.disposeRealtimeHandlers();
|
|
25874
25957
|
const governanceCleanup = await options.governanceHandle?.close();
|
|
25875
25958
|
if (governanceCleanup && !governanceCleanup.ok) {
|
|
@@ -26416,6 +26499,11 @@ async function startWebUI(opts = {}) {
|
|
|
26416
26499
|
clients,
|
|
26417
26500
|
updateAutoCompactionMaxContext
|
|
26418
26501
|
});
|
|
26502
|
+
const proxyInstantApplyDispose = setupWebuiProxyInstantApply({
|
|
26503
|
+
state,
|
|
26504
|
+
deps: deps2,
|
|
26505
|
+
updateAutoCompactionMaxContext
|
|
26506
|
+
});
|
|
26419
26507
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
26420
26508
|
collectStats: () => ({
|
|
26421
26509
|
surface: opts.surface ?? "webui",
|
|
@@ -26523,6 +26611,7 @@ projectRoot: ${ev.projectRoot ?? "?"}`,
|
|
|
26523
26611
|
todosCheckpoint,
|
|
26524
26612
|
stopHeapWatchdog,
|
|
26525
26613
|
getCredentialWatcherClose: () => credentialWatcherClose,
|
|
26614
|
+
getProxyInstantApplyDispose: () => proxyInstantApplyDispose,
|
|
26526
26615
|
disposeRealtimeHandlers,
|
|
26527
26616
|
governanceHandle,
|
|
26528
26617
|
logger,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WrongProxy instant-apply for the standalone WebUI server.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the CLI-side wiring in `setupProviderRuntime` (packages/cli/src/
|
|
5
|
+
* wiring/provider-runtime-setup.ts): subscribe to material proxy-config
|
|
6
|
+
* changes via `createProxyInstantApply` and rebuild the LIVE provider when
|
|
7
|
+
* the routing verdict for the active provider flips, so a Settings toggle
|
|
8
|
+
* or probe deactivation takes effect immediately instead of on the next
|
|
9
|
+
* incidental provider build.
|
|
10
|
+
*
|
|
11
|
+
* The rebuild sequence mirrors `applyModelSwitchCore` (routes.ts) — route
|
|
12
|
+
* the cfg through `routeProviderCfgThroughProxy`, build via registry or
|
|
13
|
+
* `makeProviderFromConfig`, overlay the live model's catalog capabilities
|
|
14
|
+
* — minus the parts that don't apply when provider+model are unchanged
|
|
15
|
+
* (no config persist, no session.start spam). The swap itself runs inside
|
|
16
|
+
* `runModelTransition` with a superseded-check so a queued rebuild can
|
|
17
|
+
* never overwrite a newer /model switch.
|
|
18
|
+
*
|
|
19
|
+
* In the CLI-hosted path this server module is NOT wired (the CLI's own
|
|
20
|
+
* `setupProviderRuntime` instant-apply covers the shared agent context),
|
|
21
|
+
* so there is exactly one rebuilder per process.
|
|
22
|
+
*/
|
|
23
|
+
import type { Provider, ProviderConfig } from '@wrongstack/core/types';
|
|
24
|
+
import type { WebuiDeps, WebuiMutableState } from './routes.js';
|
|
25
|
+
export interface WebuiProxyApplyOptions {
|
|
26
|
+
state: WebuiMutableState;
|
|
27
|
+
deps: WebuiDeps;
|
|
28
|
+
/** Mirrors `cb.updateAutoCompactionMaxContext` in start-webui.ts. */
|
|
29
|
+
updateAutoCompactionMaxContext: (provider: Provider, providerId?: string, providerCfg?: ProviderConfig | undefined) => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Wire the standalone server's WrongProxy instant-apply. Returns the
|
|
33
|
+
* dispose function for shutdown wiring. The helper itself lives in
|
|
34
|
+
* `@wrongstack/core` so both hosts share the identical change-detection
|
|
35
|
+
* semantics (effective-URL comparison, serialized rebuilds).
|
|
36
|
+
*/
|
|
37
|
+
export declare function setupWebuiProxyInstantApply(options: WebuiProxyApplyOptions): () => void;
|
|
38
|
+
//# sourceMappingURL=start-webui-proxy-apply.d.ts.map
|
|
@@ -18,6 +18,7 @@ export declare function setupWebuiShutdown(options: {
|
|
|
18
18
|
};
|
|
19
19
|
stopHeapWatchdog: () => Promise<void>;
|
|
20
20
|
getCredentialWatcherClose: () => (() => void) | undefined;
|
|
21
|
+
getProxyInstantApplyDispose: () => () => void;
|
|
21
22
|
disposeRealtimeHandlers: () => void;
|
|
22
23
|
governanceHandle?: {
|
|
23
24
|
close: () => Promise<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/webui-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.313.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": [
|
|
@@ -36,18 +36,19 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"ws": "^8.21.3",
|
|
39
|
-
"@wrongstack/core": "0.
|
|
40
|
-
"@wrongstack/
|
|
41
|
-
"@wrongstack/
|
|
42
|
-
"@wrongstack/
|
|
43
|
-
"@wrongstack/
|
|
44
|
-
"@wrongstack/
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/webui-protocol": "0.
|
|
39
|
+
"@wrongstack/core": "0.313.1",
|
|
40
|
+
"@wrongstack/providers": "0.313.1",
|
|
41
|
+
"@wrongstack/runtime": "0.313.1",
|
|
42
|
+
"@wrongstack/kanban": "0.313.1",
|
|
43
|
+
"@wrongstack/sage": "0.313.1",
|
|
44
|
+
"@wrongstack/sdd": "0.313.1",
|
|
45
|
+
"@wrongstack/vector-memory": "0.313.1",
|
|
46
|
+
"@wrongstack/mcp": "0.313.1",
|
|
47
|
+
"@wrongstack/techstack": "0.313.1",
|
|
48
|
+
"@wrongstack/requirement-intake": "0.313.1",
|
|
49
|
+
"@wrongstack/tools": "0.313.1",
|
|
50
|
+
"@wrongstack/webui-protocol": "0.313.1",
|
|
51
|
+
"@wrongstack/wrongtrace": "0.313.1"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/node": "^26.2.0",
|