@wrongstack/core 0.310.0 → 0.310.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
@@ -3484,6 +3484,7 @@ function resolveTokenSavingTier(val, maxContext) {
3484
3484
  }
3485
3485
  var DEFAULT_TUI_THINKING_WORD = "thinking";
3486
3486
  var MAX_TUI_THINKING_WORD_LENGTH = 16;
3487
+ var MAX_WRONGPROXY_URL_LENGTH = 2048;
3487
3488
  function normalizeTuiThinkingWord(value) {
3488
3489
  if (typeof value !== "string") return DEFAULT_TUI_THINKING_WORD;
3489
3490
  const word = value.trim();
@@ -92933,6 +92934,7 @@ export {
92933
92934
  MAX_SUBAGENT_STRUCTURED_REPORT_CHARS,
92934
92935
  MAX_SUBJECT_LEN,
92935
92936
  MAX_TUI_THINKING_WORD_LENGTH,
92937
+ MAX_WRONGPROXY_URL_LENGTH,
92936
92938
  MEDIUM_BUDGET,
92937
92939
  MEMORY_EVIDENCE_TAG,
92938
92940
  MEMORY_TYPE_LABELS,
@@ -162,6 +162,13 @@ export declare function normalizeTokenSavingTier(val?: TokenSavingTier | boolean
162
162
  export declare function resolveTokenSavingTier(val: TokenSavingTier | boolean | undefined, maxContext: number | undefined): ConcreteTokenSavingTier;
163
163
  export declare const DEFAULT_TUI_THINKING_WORD = "thinking";
164
164
  export declare const MAX_TUI_THINKING_WORD_LENGTH = 16;
165
+ /**
166
+ * Hard cap on the WrongProxy / WrongTrace URL draft. URLs don't have a
167
+ * strict length limit, but capping to a sane 2 KiB prevents a runaway
168
+ * paste from bloating the `settingsPicker` slice. The runtime probe
169
+ * accepts any well-formed URL up to whatever the OS / fetch allow.
170
+ */
171
+ export declare const MAX_WRONGPROXY_URL_LENGTH = 2048;
165
172
  /**
166
173
  * Normalize the configurable statusline word shown while the TUI is working.
167
174
  * The value must be a single short word; invalid values fall back to the default.
@@ -109,6 +109,36 @@ export interface ToolsConfig {
109
109
  * in the next session (same as `features.tokenSavingMode`).
110
110
  */
111
111
  nextsteps?: NextStepsToolConfig | undefined;
112
+ /**
113
+ * WrongProxy / WrongTrace: automatic base-URL rerouting through a
114
+ * local proxy daemon (default `http://localhost:8000`). When
115
+ * `enabled` is true AND the daemon at `url` is reachable, every
116
+ * provider's base URL is rewritten through
117
+ * `${url}/proxy/<host><path>`. openai-codex is excluded by spec.
118
+ *
119
+ * Mirrors the WebUI `LocalPrefs` shape (single object with two
120
+ * fields, not two top-level keys). Persisted to the encrypted
121
+ * profile config and mirrored into `ctx.meta` by the TUI settings
122
+ * adapter so the runtime probe can read it mid-session.
123
+ */
124
+ wrongProxy?: WrongProxyToolConfig | undefined;
125
+ }
126
+ /** WrongProxy / WrongTrace tool-config (`tools.wrongProxy`). */
127
+ export interface WrongProxyToolConfig {
128
+ /**
129
+ * Master switch. When true AND the daemon at `url` is reachable,
130
+ * every provider's base URL is rewritten through
131
+ * `${url}/proxy/<host><path>`. openai-codex is excluded by spec.
132
+ * Default: false.
133
+ */
134
+ enabled?: boolean | undefined;
135
+ /**
136
+ * Where the local proxy daemon listens. Default
137
+ * `http://localhost:8000`. The CLI's periodic probe targets
138
+ * `<url>/api/health`; a 2xx response flips the runtime's
139
+ * `active` flag.
140
+ */
141
+ url?: string | undefined;
112
142
  }
113
143
  /** Opt-in switch for the agent-callable `nextsteps` tool (`tools.nextsteps`). */
114
144
  export interface NextStepsToolConfig {
@@ -4,7 +4,7 @@ export type { ContentBlock, ImageBlock, TextBlock, ThinkingBlock, ToolResultBloc
4
4
  export { isImageBlock, isTextBlock, isToolResultBlock, isToolUseBlock } from './blocks.js';
5
5
  export type { Compactor, CompactReport } from './compactor.js';
6
6
  export type { AdaptiveConcurrencyConfig, AgentLearningConfig, AutonomyConfig, BrainConfig, BrainCouncilConfig, BrainCouncilVoterConfig, BrainModelEntry, CircuitBreakerRuntimeConfig, ConcreteTokenSavingTier, Config, ConfigLoader, ConfigStore, ContextConfig, CouncilPersonaDefinition, CouncilToolConfig, CouncilToolProfileDefinition, CustomModelDefinition, ExecDangerConfig, ExecToolConfig, FeaturesConfig, FleetChatVerbosity, FleetConfig, FleetSupervisorConfig, GitBehaviorConfig, HqClientConfig, IndexingConfig, InputHistoryConfig, LaunchConfig, LaunchMenuChoice, LogConfig, LoopDetectionConfig, MCPHealthConfig, MCPHealthThresholds, MCPServerConfig, ModelMatrixEntry, ModelRuntimeCacheConfig, ModelRuntimeConfig, ModelRuntimeParametersConfig, ModelRuntimeReasoningConfig, NextStepsToolConfig, PluginConfig, PluginManagerConfig, ProviderApiKey, ProviderConfig, SageConfig, SessionLoggingConfig, SkillsConfig, SyncCategory, SyncConfig, ThemePresetId, TokenSavingTier, ToolDescriptionMode, ToolDescriptionModeConfig, ToolResultRenderMode, ToolResultRenderModeConfig, ToolsConfig, } from './config.js';
7
- export { DEFAULT_TUI_THINKING_WORD, FLEET_CHAT_VERBOSITY_VALUES, MAX_TUI_THINKING_WORD_LENGTH, normalizeTokenSavingTier, normalizeTuiThinkingWord, resolveFleetChatVerbosity, resolveTokenSavingTier, THEME_PRESET_IDS, } from './config.js';
7
+ export { DEFAULT_TUI_THINKING_WORD, FLEET_CHAT_VERBOSITY_VALUES, MAX_TUI_THINKING_WORD_LENGTH, MAX_WRONGPROXY_URL_LENGTH, normalizeTokenSavingTier, normalizeTuiThinkingWord, resolveFleetChatVerbosity, resolveTokenSavingTier, THEME_PRESET_IDS, } from './config.js';
8
8
  export type { CompletedWorkEvidence, CompletedWorkSource, ContextEvidenceState, ContextFileEvidence, ContextIntentEvidence, ContextRepeatedReadEvidence, ToolEvidenceStatus, ToolOutputMetadata, } from './context-evidence.js';
9
9
  export type { ContextSnapshot, ContextWindowAggressiveOn, ContextWindowConfigLike, ContextWindowMode, ContextWindowModeId, ContextWindowModeSelectionId, ContextWindowPolicy, ContextWindowThresholds, DeprecatedContextWindowModeId, } from './context-window.js';
10
10
  export { CONTEXT_WINDOW_MODE_PINNED_META_KEY, CONTEXT_WINDOW_MODES, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEPRECATED_CONTEXT_WINDOW_MODE_ALIASES, formatContextWindowModeList, getContextWindowMode, isContextWindowModeId, isContextWindowModeSelectionId, isDeprecatedContextWindowModeId, LARGE_WINDOW_DEEP_MODE_THRESHOLD, listContextWindowModes, normalizeContextWindowModeId, resolveContextWindowPolicy, } from './context-window.js';
@@ -49,6 +49,7 @@ function resolveTokenSavingTier(val, maxContext) {
49
49
  }
50
50
  var DEFAULT_TUI_THINKING_WORD = "thinking";
51
51
  var MAX_TUI_THINKING_WORD_LENGTH = 16;
52
+ var MAX_WRONGPROXY_URL_LENGTH = 2048;
52
53
  function normalizeTuiThinkingWord(value) {
53
54
  if (typeof value !== "string") return DEFAULT_TUI_THINKING_WORD;
54
55
  const word = value.trim();
@@ -1367,6 +1368,7 @@ export {
1367
1368
  LARGE_WINDOW_DEEP_MODE_THRESHOLD,
1368
1369
  MALFORMED_ARG_MARKERS,
1369
1370
  MAX_TUI_THINKING_WORD_LENGTH,
1371
+ MAX_WRONGPROXY_URL_LENGTH,
1370
1372
  MEMORY_TYPE_LABELS,
1371
1373
  PROMPT_CATEGORY_LABELS,
1372
1374
  ParseError,
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Automatic proxy/trace rerouting for provider base URLs.
3
+ *
4
+ * Lives in `@wrongstack/core` so both `cli` and `runtime` packages can
5
+ * import the same pure-logic rewriter without reaching across workspaces.
6
+ * The CLI's `proxy-probe` (side-effectful, owns `setInterval`) lives in
7
+ * `@wrongstack/cli` and pushes state into this module via `applyProxyConfig`.
8
+ *
9
+ * Example:
10
+ * original = "https://api.openai.com/v1"
11
+ * proxyUrl = "http://localhost:8000"
12
+ * output = "http://localhost:8000/proxy/api.openai.com/v1"
13
+ *
14
+ * The host appears *without* a scheme in the path; the proxy terminates
15
+ * TLS (or speaks plain HTTP for localhost) and forwards the original
16
+ * scheme in the `X-Forwarded-Proto` header.
17
+ */
18
+ /**
19
+ * Providers whose base URLs MUST NOT be rewritten. openai-codex talks
20
+ * directly to the ChatGPT backend over an OAuth-issued token, and the
21
+ * `client_id` / audience in the token constrains the request origin —
22
+ * routing it through a generic proxy breaks the auth check.
23
+ */
24
+ export declare const PROXY_EXCLUDED_PROVIDERS: ReadonlySet<string>;
25
+ /**
26
+ * Decide whether a provider id is eligible for proxy rerouting.
27
+ *
28
+ * - `openai-codex` is excluded by spec.
29
+ * - Everything else (openai, anthropic, google, openai-compatible,
30
+ * custom saved-config aliases) flows through.
31
+ */
32
+ export declare function isProxyEligible(providerId: string): boolean;
33
+ /**
34
+ * Rewrite a provider base URL through the proxy.
35
+ *
36
+ * Returns the original input (passthrough) when the input is missing or
37
+ * malformed — we never want the proxy rewriter to be the reason a request
38
+ * fails when the proxy itself is misconfigured. The guards below are
39
+ * deliberately permissive: a misconfigured proxy must NOT silently turn
40
+ * into a hard error during provider construction.
41
+ */
42
+ export declare function rewriteBaseUrl(originalBaseUrl: string | undefined, proxyUrl: string | undefined): string | undefined;
43
+ /**
44
+ * Active proxy configuration consumed by `resolveProviderCfg`. Module-scoped
45
+ * so the wiring layer can read it without threading state through every
46
+ * call site; updates from `applyProxyConfig()` are atomic from the JS
47
+ * perspective (a single assignment).
48
+ */
49
+ export interface ProxyConfig {
50
+ /** Master switch — when false, no rewrite happens regardless of url. */
51
+ enabled: boolean;
52
+ /** Where the proxy listens. Empty string = unset (treated as disabled). */
53
+ url: string;
54
+ /** Last-known reachability state from the periodic probe. */
55
+ active: boolean;
56
+ }
57
+ /** Read the current proxy configuration. Safe to call from any layer. */
58
+ export declare function getProxyConfig(): ProxyConfig;
59
+ /**
60
+ * Apply a new proxy configuration. Returns the previous config so callers
61
+ * (notably the probe) can decide whether the change requires an immediate
62
+ * probe vs. waiting for the next tick.
63
+ */
64
+ export declare function applyProxyConfig(next: Partial<ProxyConfig>): ProxyConfig;
65
+ /**
66
+ * Convenience: should the rewriter run for a given provider id given the
67
+ * current configuration? Centralizes the "is proxy on AND active AND not
68
+ * excluded" rule so future call sites can't accidentally skip a check.
69
+ */
70
+ export declare function shouldRewriteFor(providerId: string): boolean;
71
+ /**
72
+ * Reset to defaults. Intended for tests; do NOT call from production code
73
+ * (the singleton lives for the lifetime of the process).
74
+ */
75
+ export declare function __resetProxyConfigForTests(): void;
76
+ //# sourceMappingURL=proxy-rewrite.d.ts.map
@@ -0,0 +1,70 @@
1
+ // src/wiring/proxy-rewrite.ts
2
+ var PROXY_PATH_PREFIX = "/proxy/";
3
+ var PROXY_EXCLUDED_PROVIDERS = /* @__PURE__ */ new Set(["openai-codex"]);
4
+ function isProxyEligible(providerId) {
5
+ if (!providerId) return false;
6
+ if (PROXY_EXCLUDED_PROVIDERS.has(providerId)) return false;
7
+ return true;
8
+ }
9
+ function rewriteBaseUrl(originalBaseUrl, proxyUrl) {
10
+ if (!originalBaseUrl) return void 0;
11
+ if (!proxyUrl) return originalBaseUrl;
12
+ if (!isProxyEligibleForRewrite(originalBaseUrl, proxyUrl)) return originalBaseUrl;
13
+ return composeRewrittenUrl(originalBaseUrl, proxyUrl);
14
+ }
15
+ function isProxyEligibleForRewrite(originalBaseUrl, proxyUrl) {
16
+ if (!originalBaseUrl.includes("://")) return false;
17
+ if (!proxyUrl.includes("://")) return false;
18
+ const normalizedProxy = proxyUrl.replace(/\/+$/, "");
19
+ if (originalBaseUrl.startsWith(`${normalizedProxy}${PROXY_PATH_PREFIX}`)) {
20
+ return false;
21
+ }
22
+ try {
23
+ const parsed = new URL(originalBaseUrl);
24
+ const isLoopback = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || // WHATWG URL serializes IPv6 hosts with brackets — `[::1]`, not `::1`.
25
+ parsed.hostname === "[::1]";
26
+ if (isLoopback && parsed.port !== "") return false;
27
+ } catch {
28
+ }
29
+ return true;
30
+ }
31
+ function composeRewrittenUrl(originalBaseUrl, proxyUrl) {
32
+ const parsedOriginal = new URL(originalBaseUrl);
33
+ const hostAndPath = `${parsedOriginal.host}${parsedOriginal.pathname}`;
34
+ const trailingQuery = parsedOriginal.search || "";
35
+ const trailingHash = parsedOriginal.hash || "";
36
+ const proxyRoot = proxyUrl.replace(/\/+$/, "");
37
+ return `${proxyRoot}${PROXY_PATH_PREFIX}${hostAndPath}${trailingQuery}${trailingHash}`;
38
+ }
39
+ var DEFAULT_PROXY_CONFIG = { enabled: false, url: "", active: false };
40
+ var currentConfig = { ...DEFAULT_PROXY_CONFIG };
41
+ function getProxyConfig() {
42
+ return currentConfig;
43
+ }
44
+ function applyProxyConfig(next) {
45
+ const previous = currentConfig;
46
+ currentConfig = {
47
+ enabled: next.enabled ?? previous.enabled,
48
+ url: next.url ?? previous.url,
49
+ active: next.active ?? previous.active
50
+ };
51
+ return previous;
52
+ }
53
+ function shouldRewriteFor(providerId) {
54
+ const cfg = currentConfig;
55
+ if (!cfg.enabled || !cfg.active || !cfg.url) return false;
56
+ return isProxyEligible(providerId);
57
+ }
58
+ function __resetProxyConfigForTests() {
59
+ currentConfig = { ...DEFAULT_PROXY_CONFIG };
60
+ }
61
+ export {
62
+ PROXY_EXCLUDED_PROVIDERS,
63
+ __resetProxyConfigForTests,
64
+ applyProxyConfig,
65
+ getProxyConfig,
66
+ isProxyEligible,
67
+ rewriteBaseUrl,
68
+ shouldRewriteFor
69
+ };
70
+ //# sourceMappingURL=proxy-rewrite.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/core",
3
- "version": "0.310.0",
3
+ "version": "0.310.1",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack core: kernel, types, and shared utilities for the WrongStack CLI agent.",
6
6
  "repository": {
@@ -165,6 +165,10 @@
165
165
  "./replay": {
166
166
  "types": "./dist/replay/index.d.ts",
167
167
  "import": "./dist/replay/index.js"
168
+ },
169
+ "./wiring/proxy-rewrite": {
170
+ "types": "./dist/wiring/proxy-rewrite.d.ts",
171
+ "import": "./dist/wiring/proxy-rewrite.js"
168
172
  }
169
173
  },
170
174
  "files": [
@@ -178,9 +182,9 @@
178
182
  "wrongstackApiVersion": "0.1.10",
179
183
  "dependencies": {
180
184
  "zod": "4.4.3",
181
- "@wrongstack/primitives": "0.310.0",
182
- "@wrongstack/kanban": "0.310.0",
183
- "@wrongstack/persistence": "0.310.0"
185
+ "@wrongstack/primitives": "0.310.1",
186
+ "@wrongstack/kanban": "0.310.1",
187
+ "@wrongstack/persistence": "0.310.1"
184
188
  },
185
189
  "devDependencies": {
186
190
  "@types/node": "^22.19.0",