@moxxy/cli 0.12.1 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { z as z$1, defineProvider, definePlugin, defineTool, MoxxyError, writeFileAtomic, asTurnId, defineMode, asPluginId, defineChannel, defineTunnelProvider, spawnCliTunnel, isCliTunnelAvailable, createMutex, defineWorkflowExecutor, toFriendlyError, estimateTextTokens, classifyHttpStatus, createStuckLoopDetector, runCompactionIfNeeded, runElisionIfNeeded, collectProviderStream, usageEventFields, isContextOverflowError, emitRequestsAndDetectStuck, executeToolUses, buildSystemPromptWithSkills, projectMessages, defineCompactor, defineCacheStrategy, denyByDefaultResolver, createAllowListResolver, moxxyPath, zodToJsonSchema, fileDiffSummary, runSingleShotTurn, bearerTokenMatches, resolveChannelToken, rotateChannelToken, defineSurface, estimateContextTokens as estimateContextTokens$1, readRequestBody, isFileDiffDisplay, MOXXY_WS_SUBPROTOCOL, defineEmbedder, migrateModeName, bearerGuard, tokenFromWsProtocolHeader, skillFrontmatterSchema, asSkillId, getInstallHint, moxxyHome, defineTranscriber, summarizeTokensByModel, createDeferredPermissionResolver, encodeLoginPrompt, classifyNetworkError, addModelTotals, ISOLATION_RANK, moxxyPackageSchema, defineCommand, fileDiffVerb, createCallbackResolver, autoAllowResolver, asSessionId, asToolCallId, defineViewRenderer, DEFAULT_VIEW_TAGS, isSafeViewUrl, evaluateToolRule, summarizeSessionTokensFromEvents, toDiffRows, diffGutterNo, computeElisionState, toolResultStubbed, toolResultStub, toolResultBytes, conversationalStubbed, conversationalStub, asEventId } from '@moxxy/sdk';
3
+ import { z as z$1, defineProvider, definePlugin, defineTool, MoxxyError, writeFileAtomic, asTurnId, defineMode, asPluginId, defineChannel, defineTunnelProvider, spawnCliTunnel, isCliTunnelAvailable, createMutex, defineWorkflowExecutor, toFriendlyError, estimateTextTokens, classifyHttpStatus, createStuckLoopDetector, runCompactionIfNeeded, runElisionIfNeeded, collectProviderStream, usageEventFields, isContextOverflowError, emitRequestsAndDetectStuck, executeToolUses, buildSystemPromptWithSkills, projectMessages, defineCompactor, defineCacheStrategy, denyByDefaultResolver, createAllowListResolver, moxxyPath, zodToJsonSchema, fileDiffSummary, runSingleShotTurn, bearerTokenMatches, resolveChannelToken, rotateChannelToken, defineSurface, estimateContextTokens as estimateContextTokens$1, readRequestBody, isFileDiffDisplay, MOXXY_WS_SUBPROTOCOL, defineEmbedder, migrateModeName, bearerGuard, tokenFromWsProtocolHeader, skillFrontmatterSchema, asSkillId, getInstallHint, moxxyHome, defineTranscriber, summarizeTokensByModel, countNodes, createDeferredPermissionResolver, writeFileAtomicSync, encodeLoginPrompt, classifyNetworkError, addModelTotals, ISOLATION_RANK, moxxyPackageSchema, defineCommand, fileDiffVerb, createCallbackResolver, autoAllowResolver, asSessionId, asToolCallId, defineViewRenderer, DEFAULT_VIEW_TAGS, assertNever, isSafeViewUrl, evaluateToolRule, summarizeSessionTokensFromEvents, toDiffRows, diffGutterNo, computeElisionState, toolResultStubbed, toolResultStub, toolResultBytes, conversationalStubbed, conversationalStub, asEventId } from '@moxxy/sdk';
4
4
  import * as fs28 from 'fs';
5
- import fs28__default, { existsSync, promises, ReadStream, readFileSync, statSync, readdirSync, mkdirSync, writeFileSync, unlinkSync, renameSync, watch, createReadStream } from 'fs';
5
+ import fs28__default, { existsSync, promises, ReadStream, readFileSync, statSync, readdirSync, mkdirSync, writeFileSync, unlinkSync, watch, createReadStream } from 'fs';
6
6
  import * as path3 from 'path';
7
7
  import path3__default, { join, dirname, basename } from 'path';
8
8
  import { z } from 'zod';
@@ -806,7 +806,7 @@ async function* runTurn(session, prompt, opts = {}) {
806
806
  yield queue.shift();
807
807
  if (done)
808
808
  break;
809
- await new Promise((resolve12) => waiters.push(resolve12));
809
+ await new Promise((resolve13) => waiters.push(resolve13));
810
810
  }
811
811
  } finally {
812
812
  unsubscribe();
@@ -1551,44 +1551,83 @@ var init_modes = __esm({
1551
1551
  }
1552
1552
  });
1553
1553
 
1554
- // ../core/dist/registries/cache-strategies.js
1555
- var CacheStrategyRegistry;
1556
- var init_cache_strategies = __esm({
1557
- "../core/dist/registries/cache-strategies.js"() {
1558
- CacheStrategyRegistry = class {
1559
- strategies = /* @__PURE__ */ new Map();
1554
+ // ../core/dist/registries/active-def-registry.js
1555
+ var ActiveDefRegistry;
1556
+ var init_active_def_registry = __esm({
1557
+ "../core/dist/registries/active-def-registry.js"() {
1558
+ ActiveDefRegistry = class {
1559
+ defs = /* @__PURE__ */ new Map();
1560
1560
  active = null;
1561
- register(s2) {
1562
- if (this.strategies.has(s2.name)) {
1563
- throw new Error(`Cache strategy already registered: ${s2.name}`);
1561
+ noun;
1562
+ autoAdoptFirst;
1563
+ constructor(opts) {
1564
+ this.noun = opts.noun;
1565
+ this.autoAdoptFirst = opts.autoAdoptFirst ?? true;
1566
+ }
1567
+ /**
1568
+ * Register a def. Throws on duplicate — use `replace()` to overwrite.
1569
+ * Auto-activates the first registration (when `autoAdoptFirst`).
1570
+ */
1571
+ register(def) {
1572
+ if (this.defs.has(def.name)) {
1573
+ throw new Error(`${this.noun} already registered: ${def.name}`);
1564
1574
  }
1565
- this.strategies.set(s2.name, s2);
1566
- if (!this.active)
1567
- this.active = s2.name;
1575
+ this.defs.set(def.name, def);
1576
+ if (this.autoAdoptFirst && !this.active)
1577
+ this.active = def.name;
1568
1578
  }
1569
- replace(s2) {
1570
- this.strategies.set(s2.name, s2);
1571
- if (!this.active)
1572
- this.active = s2.name;
1579
+ /** Overwrite an existing def (or add a new one) without throwing.
1580
+ * Auto-activates when nothing is active yet (mirrors `register`). */
1581
+ replace(def) {
1582
+ this.defs.set(def.name, def);
1583
+ if (this.autoAdoptFirst && !this.active)
1584
+ this.active = def.name;
1573
1585
  }
1586
+ /**
1587
+ * Remove a def. If it was active, the active slot is cleared (callers must
1588
+ * `setActive()` rather than getting an arbitrary "next").
1589
+ */
1574
1590
  unregister(name) {
1575
- this.strategies.delete(name);
1591
+ this.defs.delete(name);
1576
1592
  if (this.active === name)
1577
1593
  this.active = null;
1578
1594
  }
1579
1595
  list() {
1580
- return [...this.strategies.values()];
1596
+ return [...this.defs.values()];
1597
+ }
1598
+ has(name) {
1599
+ return this.defs.has(name);
1581
1600
  }
1582
1601
  setActive(name) {
1583
- const strategy = this.strategies.get(name);
1584
- if (!strategy)
1585
- throw new Error(`Cache strategy not registered: ${name}`);
1586
- this.active = strategy.name;
1602
+ const def = this.defs.get(name);
1603
+ if (!def)
1604
+ throw new Error(`${this.noun} not registered: ${name}`);
1605
+ this.active = def.name;
1606
+ }
1607
+ /** Deactivate the current def (callers fall back to their default). */
1608
+ clearActive() {
1609
+ this.active = null;
1587
1610
  }
1588
1611
  getActive() {
1589
1612
  if (!this.active)
1590
1613
  return null;
1591
- return this.strategies.get(this.active) ?? null;
1614
+ return this.defs.get(this.active) ?? null;
1615
+ }
1616
+ getActiveName() {
1617
+ return this.active;
1618
+ }
1619
+ };
1620
+ }
1621
+ });
1622
+
1623
+ // ../core/dist/registries/cache-strategies.js
1624
+ var CacheStrategyRegistry;
1625
+ var init_cache_strategies = __esm({
1626
+ "../core/dist/registries/cache-strategies.js"() {
1627
+ init_active_def_registry();
1628
+ CacheStrategyRegistry = class extends ActiveDefRegistry {
1629
+ constructor() {
1630
+ super({ noun: "Cache strategy" });
1592
1631
  }
1593
1632
  };
1594
1633
  }
@@ -1598,40 +1637,10 @@ var init_cache_strategies = __esm({
1598
1637
  var ViewRendererRegistry;
1599
1638
  var init_view_renderers = __esm({
1600
1639
  "../core/dist/registries/view-renderers.js"() {
1601
- ViewRendererRegistry = class {
1602
- renderers = /* @__PURE__ */ new Map();
1603
- active = null;
1604
- register(r2) {
1605
- if (this.renderers.has(r2.name)) {
1606
- throw new Error(`View renderer already registered: ${r2.name}`);
1607
- }
1608
- this.renderers.set(r2.name, r2);
1609
- if (!this.active)
1610
- this.active = r2.name;
1611
- }
1612
- replace(r2) {
1613
- this.renderers.set(r2.name, r2);
1614
- if (!this.active)
1615
- this.active = r2.name;
1616
- }
1617
- unregister(name) {
1618
- this.renderers.delete(name);
1619
- if (this.active === name)
1620
- this.active = null;
1621
- }
1622
- list() {
1623
- return [...this.renderers.values()];
1624
- }
1625
- setActive(name) {
1626
- const renderer2 = this.renderers.get(name);
1627
- if (!renderer2)
1628
- throw new Error(`View renderer not registered: ${name}`);
1629
- this.active = renderer2.name;
1630
- }
1631
- getActive() {
1632
- if (!this.active)
1633
- return null;
1634
- return this.renderers.get(this.active) ?? null;
1640
+ init_active_def_registry();
1641
+ ViewRendererRegistry = class extends ActiveDefRegistry {
1642
+ constructor() {
1643
+ super({ noun: "View renderer" });
1635
1644
  }
1636
1645
  };
1637
1646
  }
@@ -2034,11 +2043,6 @@ function validateDoc(doc, allowList) {
2034
2043
  walk3(doc.root);
2035
2044
  return errors2;
2036
2045
  }
2037
- function countNodes(node) {
2038
- if (node.kind === "text")
2039
- return 1;
2040
- return 1 + node.children.reduce((sum, c2) => sum + countNodes(c2), 0);
2041
- }
2042
2046
  var ParseFail;
2043
2047
  var init_parse = __esm({
2044
2048
  "../core/dist/view/parse.js"() {
@@ -2068,40 +2072,10 @@ var init_default_renderer = __esm({
2068
2072
  var TunnelProviderRegistry;
2069
2073
  var init_tunnel_providers = __esm({
2070
2074
  "../core/dist/registries/tunnel-providers.js"() {
2071
- TunnelProviderRegistry = class {
2072
- providers = /* @__PURE__ */ new Map();
2073
- active = null;
2074
- register(p3) {
2075
- if (this.providers.has(p3.name)) {
2076
- throw new Error(`Tunnel provider already registered: ${p3.name}`);
2077
- }
2078
- this.providers.set(p3.name, p3);
2079
- if (!this.active)
2080
- this.active = p3.name;
2081
- }
2082
- replace(p3) {
2083
- this.providers.set(p3.name, p3);
2084
- if (!this.active)
2085
- this.active = p3.name;
2086
- }
2087
- unregister(name) {
2088
- this.providers.delete(name);
2089
- if (this.active === name)
2090
- this.active = null;
2091
- }
2092
- list() {
2093
- return [...this.providers.values()];
2094
- }
2095
- setActive(name) {
2096
- const provider = this.providers.get(name);
2097
- if (!provider)
2098
- throw new Error(`Tunnel provider not registered: ${name}`);
2099
- this.active = provider.name;
2100
- }
2101
- getActive() {
2102
- if (!this.active)
2103
- return null;
2104
- return this.providers.get(this.active) ?? null;
2075
+ init_active_def_registry();
2076
+ TunnelProviderRegistry = class extends ActiveDefRegistry {
2077
+ constructor() {
2078
+ super({ noun: "Tunnel provider" });
2105
2079
  }
2106
2080
  };
2107
2081
  }
@@ -2124,51 +2098,52 @@ var init_localhost = __esm({
2124
2098
  var CompactorRegistry;
2125
2099
  var init_compactors = __esm({
2126
2100
  "../core/dist/registries/compactors.js"() {
2127
- CompactorRegistry = class {
2128
- compactors = /* @__PURE__ */ new Map();
2129
- active = null;
2101
+ init_active_def_registry();
2102
+ CompactorRegistry = class extends ActiveDefRegistry {
2103
+ constructor() {
2104
+ super({ noun: "Compactor" });
2105
+ }
2106
+ };
2107
+ }
2108
+ });
2109
+
2110
+ // ../core/dist/registries/def-map-registry.js
2111
+ var DefMapRegistry;
2112
+ var init_def_map_registry = __esm({
2113
+ "../core/dist/registries/def-map-registry.js"() {
2114
+ DefMapRegistry = class {
2115
+ defs = /* @__PURE__ */ new Map();
2116
+ noun;
2117
+ keyOf;
2118
+ constructor(opts) {
2119
+ this.noun = opts.noun;
2120
+ this.keyOf = opts.keyOf;
2121
+ }
2130
2122
  /**
2131
- * Register a compactor. Throws on duplicate use `replace()` for
2132
- * overwrite. Auto-activates on first registration.
2123
+ * Register a definition. Throws on duplicate so two plugins can't silently
2124
+ * shadow each other use `replace()` when you really want to override.
2133
2125
  */
2134
- register(c2) {
2135
- if (this.compactors.has(c2.name)) {
2136
- throw new Error(`Compactor already registered: ${c2.name}`);
2126
+ register(def) {
2127
+ const key = this.keyOf(def);
2128
+ if (this.defs.has(key)) {
2129
+ throw new Error(`${this.noun} already registered: ${String(key)}`);
2137
2130
  }
2138
- this.compactors.set(c2.name, c2);
2139
- if (!this.active)
2140
- this.activate(c2);
2131
+ this.defs.set(key, def);
2141
2132
  }
2142
- replace(c2) {
2143
- this.compactors.set(c2.name, c2);
2144
- if (!this.active)
2145
- this.activate(c2);
2133
+ replace(def) {
2134
+ this.defs.set(this.keyOf(def), def);
2146
2135
  }
2147
- /**
2148
- * Remove a compactor. If it was active, the active slot is cleared
2149
- * (callers must `setActive()` rather than getting an arbitrary "next").
2150
- */
2151
- unregister(name) {
2152
- this.compactors.delete(name);
2153
- if (this.active === name)
2154
- this.active = null;
2136
+ unregister(key) {
2137
+ this.defs.delete(key);
2155
2138
  }
2156
2139
  list() {
2157
- return [...this.compactors.values()];
2158
- }
2159
- setActive(name) {
2160
- const compactor = this.compactors.get(name);
2161
- if (!compactor)
2162
- throw new Error(`Compactor not registered: ${name}`);
2163
- this.activate(compactor);
2140
+ return [...this.defs.values()];
2164
2141
  }
2165
- getActive() {
2166
- if (!this.active)
2167
- return null;
2168
- return this.compactors.get(this.active) ?? null;
2142
+ get(key) {
2143
+ return this.defs.get(key);
2169
2144
  }
2170
- activate(compactor) {
2171
- this.active = compactor.name;
2145
+ has(key) {
2146
+ return this.defs.has(key);
2172
2147
  }
2173
2148
  };
2174
2149
  }
@@ -2178,25 +2153,10 @@ var init_compactors = __esm({
2178
2153
  var ChannelRegistryImpl;
2179
2154
  var init_channels = __esm({
2180
2155
  "../core/dist/registries/channels.js"() {
2181
- ChannelRegistryImpl = class {
2182
- defs = /* @__PURE__ */ new Map();
2183
- register(def) {
2184
- if (this.defs.has(def.name)) {
2185
- throw new Error(`Channel already registered: ${def.name}`);
2186
- }
2187
- this.defs.set(def.name, def);
2188
- }
2189
- unregister(name) {
2190
- this.defs.delete(name);
2191
- }
2192
- list() {
2193
- return [...this.defs.values()];
2194
- }
2195
- get(name) {
2196
- return this.defs.get(name);
2197
- }
2198
- has(name) {
2199
- return this.defs.has(name);
2156
+ init_def_map_registry();
2157
+ ChannelRegistryImpl = class extends DefMapRegistry {
2158
+ constructor() {
2159
+ super({ noun: "Channel", keyOf: (def) => def.name });
2200
2160
  }
2201
2161
  async listWithAvailability(deps) {
2202
2162
  const out = [];
@@ -2226,25 +2186,10 @@ var init_channels = __esm({
2226
2186
  var SurfaceRegistryImpl;
2227
2187
  var init_surfaces = __esm({
2228
2188
  "../core/dist/registries/surfaces.js"() {
2229
- SurfaceRegistryImpl = class {
2230
- defs = /* @__PURE__ */ new Map();
2231
- register(def) {
2232
- if (this.defs.has(def.kind)) {
2233
- throw new Error(`Surface already registered: ${def.kind}`);
2234
- }
2235
- this.defs.set(def.kind, def);
2236
- }
2237
- unregister(kind3) {
2238
- this.defs.delete(kind3);
2239
- }
2240
- list() {
2241
- return [...this.defs.values()];
2242
- }
2243
- get(kind3) {
2244
- return this.defs.get(kind3);
2245
- }
2246
- has(kind3) {
2247
- return this.defs.has(kind3);
2189
+ init_def_map_registry();
2190
+ SurfaceRegistryImpl = class extends DefMapRegistry {
2191
+ constructor() {
2192
+ super({ noun: "Surface", keyOf: (def) => def.kind });
2248
2193
  }
2249
2194
  };
2250
2195
  }
@@ -2541,33 +2486,10 @@ var init_tools2 = __esm({
2541
2486
  var AgentRegistry;
2542
2487
  var init_agents = __esm({
2543
2488
  "../core/dist/registries/agents.js"() {
2544
- AgentRegistry = class {
2545
- agents = /* @__PURE__ */ new Map();
2546
- /**
2547
- * Register a definition. Throws on duplicate so two plugins can't
2548
- * silently shadow each other — use `replace()` when you really want
2549
- * to override (e.g. user-config overrides).
2550
- */
2551
- register(def) {
2552
- if (this.agents.has(def.name)) {
2553
- throw new Error(`Agent already registered: ${def.name}`);
2554
- }
2555
- this.agents.set(def.name, def);
2556
- }
2557
- replace(def) {
2558
- this.agents.set(def.name, def);
2559
- }
2560
- unregister(name) {
2561
- this.agents.delete(name);
2562
- }
2563
- list() {
2564
- return [...this.agents.values()];
2565
- }
2566
- get(name) {
2567
- return this.agents.get(name);
2568
- }
2569
- has(name) {
2570
- return this.agents.has(name);
2489
+ init_def_map_registry();
2490
+ AgentRegistry = class extends DefMapRegistry {
2491
+ constructor() {
2492
+ super({ noun: "Agent", keyOf: (def) => def.name });
2571
2493
  }
2572
2494
  };
2573
2495
  }
@@ -2824,46 +2746,14 @@ var init_isolators = __esm({
2824
2746
  var WorkflowExecutorRegistry;
2825
2747
  var init_workflow_executors = __esm({
2826
2748
  "../core/dist/registries/workflow-executors.js"() {
2827
- WorkflowExecutorRegistry = class {
2828
- executors = /* @__PURE__ */ new Map();
2829
- active = null;
2830
- register(def) {
2831
- if (this.executors.has(def.name)) {
2832
- throw new Error(`Workflow executor already registered: ${def.name}`);
2833
- }
2834
- this.executors.set(def.name, def);
2835
- if (!this.active)
2836
- this.active = def.name;
2837
- }
2838
- replace(def) {
2839
- this.executors.set(def.name, def);
2840
- if (!this.active)
2841
- this.active = def.name;
2842
- }
2843
- unregister(name) {
2844
- this.executors.delete(name);
2845
- if (this.active === name)
2846
- this.active = null;
2847
- }
2848
- list() {
2849
- return [...this.executors.values()];
2850
- }
2851
- setActive(name) {
2852
- const def = this.executors.get(name);
2853
- if (!def)
2854
- throw new Error(`Workflow executor not registered: ${name}`);
2855
- this.active = def.name;
2856
- }
2857
- getActive() {
2858
- if (!this.active)
2859
- return null;
2860
- return this.executors.get(this.active) ?? null;
2749
+ init_active_def_registry();
2750
+ WorkflowExecutorRegistry = class extends ActiveDefRegistry {
2751
+ constructor() {
2752
+ super({ noun: "Workflow executor" });
2861
2753
  }
2862
2754
  };
2863
2755
  }
2864
2756
  });
2865
-
2866
- // ../core/dist/requirements.js
2867
2757
  function issue(requirement, code, message) {
2868
2758
  return {
2869
2759
  requirement,
@@ -2990,6 +2880,8 @@ var init_requirements = __esm({
2990
2880
  }
2991
2881
  case "runtime":
2992
2882
  return null;
2883
+ default:
2884
+ return assertNever(kind3);
2993
2885
  }
2994
2886
  }
2995
2887
  };
@@ -3005,7 +2897,7 @@ function sanitizeRule(rule) {
3005
2897
  }
3006
2898
  return out;
3007
2899
  }
3008
- function matchRule(rule, call) {
2900
+ function matchRule(rule, call, intent) {
3009
2901
  if (!nameMatches(rule.name, call.name))
3010
2902
  return false;
3011
2903
  if (rule.inputMatches) {
@@ -3014,17 +2906,27 @@ function matchRule(rule, call) {
3014
2906
  return false;
3015
2907
  for (const [k3, v3] of Object.entries(rule.inputMatches)) {
3016
2908
  const candidate = String(input[k3] ?? "");
2909
+ let re2;
3017
2910
  try {
3018
- if (!new RegExp(v3).test(candidate))
3019
- return false;
3020
- } catch {
3021
- if (candidate !== v3)
3022
- return false;
2911
+ re2 = new RegExp(v3);
2912
+ } catch (err) {
2913
+ warnBadPattern(rule.name, k3, v3, intent, err);
2914
+ if (intent === "deny")
2915
+ continue;
2916
+ return false;
3023
2917
  }
2918
+ if (!re2.test(candidate))
2919
+ return false;
3024
2920
  }
3025
2921
  }
3026
2922
  return true;
3027
2923
  }
2924
+ function warnBadPattern(ruleName, field, pattern, intent, err) {
2925
+ const detail = err instanceof Error ? err.message : String(err);
2926
+ const resolution = intent === "deny" ? "failing closed (rule still denies)" : "this field cannot match (rule will not grant)";
2927
+ process.stderr.write(`moxxy: invalid regex in ${intent} permission rule "${ruleName}" (inputMatches.${field} = ${JSON.stringify(pattern)}): ${detail} \u2014 ${resolution}
2928
+ `);
2929
+ }
3028
2930
  function nameMatches(pattern, candidate) {
3029
2931
  if (pattern === candidate)
3030
2932
  return true;
@@ -3081,12 +2983,12 @@ var init_engine = __esm({
3081
2983
  }
3082
2984
  check(call) {
3083
2985
  for (const rule of this.policy.deny) {
3084
- if (matchRule(rule, call)) {
2986
+ if (matchRule(rule, call, "deny")) {
3085
2987
  return { mode: "deny", reason: rule.reason ?? `Denied by policy: ${rule.name}` };
3086
2988
  }
3087
2989
  }
3088
2990
  for (const rule of this.policy.allow) {
3089
- if (matchRule(rule, call)) {
2991
+ if (matchRule(rule, call, "allow")) {
3090
2992
  return { mode: "allow", reason: rule.reason ?? `Allowed by policy: ${rule.name}` };
3091
2993
  }
3092
2994
  }
@@ -3549,18 +3451,22 @@ async function loadPreferences() {
3549
3451
  }
3550
3452
  }
3551
3453
  async function savePreferences(patch) {
3552
- const current = await loadPreferences();
3553
- const next = { ...current, ...patch };
3554
- const target = preferencesPath();
3555
- try {
3556
- await writeFileAtomic(target, JSON.stringify(next, null, 2) + "\n");
3557
- } catch (err) {
3558
- process.stderr.write(`moxxy: failed to persist preferences to ${target}: ${err instanceof Error ? err.message : String(err)}
3454
+ return writeMutex.run(async () => {
3455
+ const current = await loadPreferences();
3456
+ const next = { ...current, ...patch };
3457
+ const target = preferencesPath();
3458
+ try {
3459
+ await writeFileAtomic(target, JSON.stringify(next, null, 2) + "\n");
3460
+ } catch (err) {
3461
+ process.stderr.write(`moxxy: failed to persist preferences to ${target}: ${err instanceof Error ? err.message : String(err)}
3559
3462
  `);
3560
- }
3463
+ }
3464
+ });
3561
3465
  }
3466
+ var writeMutex;
3562
3467
  var init_preferences = __esm({
3563
3468
  "../core/dist/preferences.js"() {
3469
+ writeMutex = createMutex();
3564
3470
  }
3565
3471
  });
3566
3472
  function usageStatsPath() {
@@ -3805,83 +3711,6 @@ var init_loader = __esm({
3805
3711
  }
3806
3712
  });
3807
3713
 
3808
- // ../core/dist/skills/router.js
3809
- function buildSkillIndexPrompt(skills) {
3810
- if (skills.length === 0)
3811
- return "";
3812
- const lines = skills.map((s2) => `- ${s2.frontmatter.name}: ${s2.frontmatter.description}`);
3813
- return `Available skills:
3814
- ${lines.join("\n")}`;
3815
- }
3816
- var SkillRouter;
3817
- var init_router = __esm({
3818
- "../core/dist/skills/router.js"() {
3819
- SkillRouter = class {
3820
- skills;
3821
- provider;
3822
- classifierModel;
3823
- constructor(opts) {
3824
- this.skills = opts.skills;
3825
- this.provider = opts.provider;
3826
- this.classifierModel = opts.classifierModel ?? "claude-haiku-4-5-20251001";
3827
- }
3828
- async resolve(prompt) {
3829
- const candidates = this.filterByTriggers(prompt);
3830
- if (candidates.length === 0)
3831
- return null;
3832
- if (candidates.length === 1) {
3833
- return { skill: candidates[0], confidence: 0.9, reason: "trigger_match" };
3834
- }
3835
- if (this.provider) {
3836
- const winner = await this.classify(prompt, candidates);
3837
- if (winner)
3838
- return { skill: winner, confidence: 0.7, reason: "classifier" };
3839
- }
3840
- return { skill: candidates[0], confidence: 0.5, reason: "trigger_match" };
3841
- }
3842
- filterByTriggers(prompt) {
3843
- const lower2 = prompt.toLowerCase();
3844
- const out = [];
3845
- for (const skill of this.skills) {
3846
- const triggers = skill.frontmatter.triggers ?? [];
3847
- if (triggers.some((t2) => lower2.includes(t2.toLowerCase())))
3848
- out.push(skill);
3849
- }
3850
- return out;
3851
- }
3852
- async classify(prompt, candidates) {
3853
- if (!this.provider)
3854
- return null;
3855
- const list = candidates.map((s2, i2) => `${i2 + 1}. ${s2.frontmatter.name} \u2014 ${s2.frontmatter.description}`).join("\n");
3856
- const system = "You are a skill classifier. Given a user prompt and a list of candidate skills, reply with ONLY the number of the best-fit skill, or 0 if none.";
3857
- let acc = "";
3858
- for await (const event of this.provider.stream({
3859
- model: this.classifierModel,
3860
- system,
3861
- messages: [
3862
- {
3863
- role: "user",
3864
- content: [{ type: "text", text: `Prompt:
3865
- ${prompt}
3866
-
3867
- Candidates:
3868
- ${list}` }]
3869
- }
3870
- ]
3871
- })) {
3872
- if (event.type === "text_delta")
3873
- acc += event.delta;
3874
- }
3875
- const match = /(\d+)/.exec(acc);
3876
- const index = match ? Number(match[1]) - 1 : -1;
3877
- if (index < 0 || index >= candidates.length)
3878
- return null;
3879
- return candidates[index] ?? null;
3880
- }
3881
- };
3882
- }
3883
- });
3884
-
3885
3714
  // ../core/dist/skills/synthesize-draft.js
3886
3715
  async function draftSkill(provider, model, intent, signal) {
3887
3716
  let accumulated = "";
@@ -4090,7 +3919,6 @@ var init_skills2 = __esm({
4090
3919
  "../core/dist/skills/index.js"() {
4091
3920
  init_parse2();
4092
3921
  init_loader();
4093
- init_router();
4094
3922
  init_synthesize();
4095
3923
  }
4096
3924
  });
@@ -4207,6 +4035,8 @@ var init_persistence = __esm({
4207
4035
  logPath;
4208
4036
  meta;
4209
4037
  indexUpdateScheduled = false;
4038
+ /** Handle for the in-flight debounce timer, so `flush()` can cancel it. */
4039
+ indexTimer = null;
4210
4040
  /**
4211
4041
  * In-flight writes are serialized through this mutex so the file
4212
4042
  * stays append-ordered even when events arrive faster than the disk
@@ -4268,6 +4098,23 @@ var init_persistence = __esm({
4268
4098
  this.scheduleIndexWrite();
4269
4099
  };
4270
4100
  }
4101
+ /**
4102
+ * Force the pending (debounced) index write to happen now and resolve once
4103
+ * the meta sidecar is on disk. Cancels the in-flight debounce timer so the
4104
+ * write isn't also re-run on its original schedule. Intended for awaitable
4105
+ * shutdown: `detach()` only *schedules* the final write (an `unref`'d timer
4106
+ * an immediate `process.exit` can drop), whereas `await flush()` guarantees
4107
+ * it completed. The steady-state debounce in `scheduleIndexWrite` is
4108
+ * untouched, so calling this mid-session just collapses the next write early.
4109
+ */
4110
+ async flush() {
4111
+ if (this.indexTimer) {
4112
+ clearTimeout(this.indexTimer);
4113
+ this.indexTimer = null;
4114
+ }
4115
+ this.indexUpdateScheduled = false;
4116
+ await this.writeIndex();
4117
+ }
4271
4118
  /**
4272
4119
  * Manually update header fields (provider/model) when the user
4273
4120
  * switches mid-session. The /model picker calls this so the index
@@ -4337,15 +4184,20 @@ var init_persistence = __esm({
4337
4184
  if (this.indexUpdateScheduled)
4338
4185
  return;
4339
4186
  this.indexUpdateScheduled = true;
4340
- setTimeout(() => {
4187
+ const timer = setTimeout(() => {
4341
4188
  this.indexUpdateScheduled = false;
4189
+ this.indexTimer = null;
4342
4190
  void this.writeIndex();
4343
- }, 250).unref?.();
4191
+ }, 250);
4192
+ timer.unref?.();
4193
+ this.indexTimer = timer;
4344
4194
  }
4345
4195
  async writeIndex() {
4346
4196
  try {
4347
- await this.ensureDir();
4348
- await this.ensureLogFile();
4197
+ if (!this.closed) {
4198
+ await this.ensureDir();
4199
+ await this.ensureLogFile();
4200
+ }
4349
4201
  await writeJsonAtomic(metaPath(this.dir, this.meta.id), this.meta);
4350
4202
  } catch {
4351
4203
  }
@@ -7303,8 +7155,8 @@ var require_jiti = __commonJS({
7303
7155
  }
7304
7156
  const He2 = /^[/\\]{2}/, ze2 = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/, Je2 = /^[A-Za-z]:$/, Ye2 = /.(\.[^./]+|\.)$/, pathe_M_eThtNZ_normalize = function(e5) {
7305
7157
  if (0 === e5.length) return ".";
7306
- const t4 = (e5 = pathe_M_eThtNZ_normalizeWindowsPath(e5)).match(He2), i3 = isAbsolute4(e5), n3 = "/" === e5[e5.length - 1];
7307
- return 0 === (e5 = normalizeString(e5, !i3)).length ? i3 ? "/" : n3 ? "./" : "." : (n3 && (e5 += "/"), Je2.test(e5) && (e5 += "/"), t4 ? i3 ? `//${e5}` : `//./${e5}` : i3 && !isAbsolute4(e5) ? `/${e5}` : e5);
7158
+ const t4 = (e5 = pathe_M_eThtNZ_normalizeWindowsPath(e5)).match(He2), i3 = isAbsolute5(e5), n3 = "/" === e5[e5.length - 1];
7159
+ return 0 === (e5 = normalizeString(e5, !i3)).length ? i3 ? "/" : n3 ? "./" : "." : (n3 && (e5 += "/"), Je2.test(e5) && (e5 += "/"), t4 ? i3 ? `//${e5}` : `//./${e5}` : i3 && !isAbsolute5(e5) ? `/${e5}` : e5);
7308
7160
  }, pathe_M_eThtNZ_join = function(...e5) {
7309
7161
  let t4 = "";
7310
7162
  for (const i3 of e5) if (i3) if (t4.length > 0) {
@@ -7320,9 +7172,9 @@ var require_jiti = __commonJS({
7320
7172
  let t4 = "", i3 = false;
7321
7173
  for (let n3 = (e5 = e5.map((e6) => pathe_M_eThtNZ_normalizeWindowsPath(e6))).length - 1; n3 >= -1 && !i3; n3--) {
7322
7174
  const a3 = n3 >= 0 ? e5[n3] : pathe_M_eThtNZ_cwd();
7323
- a3 && 0 !== a3.length && (t4 = `${a3}/${t4}`, i3 = isAbsolute4(a3));
7175
+ a3 && 0 !== a3.length && (t4 = `${a3}/${t4}`, i3 = isAbsolute5(a3));
7324
7176
  }
7325
- return t4 = normalizeString(t4, !i3), i3 && !isAbsolute4(t4) ? `/${t4}` : t4.length > 0 ? t4 : ".";
7177
+ return t4 = normalizeString(t4, !i3), i3 && !isAbsolute5(t4) ? `/${t4}` : t4.length > 0 ? t4 : ".";
7326
7178
  };
7327
7179
  function normalizeString(e5, t4) {
7328
7180
  let i3 = "", n3 = 0, a3 = -1, c3 = 0, l3 = null;
@@ -7353,7 +7205,7 @@ var require_jiti = __commonJS({
7353
7205
  }
7354
7206
  return i3;
7355
7207
  }
7356
- const isAbsolute4 = function(e5) {
7208
+ const isAbsolute5 = function(e5) {
7357
7209
  return ze2.test(e5);
7358
7210
  }, extname2 = function(e5) {
7359
7211
  if (".." === e5) return "";
@@ -7361,7 +7213,7 @@ var require_jiti = __commonJS({
7361
7213
  return t4 && t4[1] || "";
7362
7214
  }, pathe_M_eThtNZ_dirname = function(e5) {
7363
7215
  const t4 = pathe_M_eThtNZ_normalizeWindowsPath(e5).replace(/\/$/, "").split("/").slice(0, -1);
7364
- return 1 === t4.length && Je2.test(t4[0]) && (t4[0] += "/"), t4.join("/") || (isAbsolute4(e5) ? "/" : ".");
7216
+ return 1 === t4.length && Je2.test(t4[0]) && (t4[0] += "/"), t4.join("/") || (isAbsolute5(e5) ? "/" : ".");
7365
7217
  }, basename7 = function(e5, t4) {
7366
7218
  const i3 = pathe_M_eThtNZ_normalizeWindowsPath(e5).split("/");
7367
7219
  let n3 = "";
@@ -7837,7 +7689,7 @@ Default "index" lookups for the main are deprecated for ES modules.`, "Deprecati
7837
7689
  }
7838
7690
  if (/(?:node|data|http|https):/.test(e5)) return e5;
7839
7691
  if (st3.has(e5)) return "node:" + e5;
7840
- if (e5.startsWith("file://") && (e5 = fileURLToPath10(e5)), isAbsolute4(e5)) try {
7692
+ if (e5.startsWith("file://") && (e5 = fileURLToPath10(e5)), isAbsolute5(e5)) try {
7841
7693
  if ((0, $e2.statSync)(e5).isFile()) return pathToFileURL3(e5);
7842
7694
  } catch (e6) {
7843
7695
  if ("ENOENT" !== e6?.code) throw e6;
@@ -8074,7 +7926,7 @@ Default "index" lookups for the main are deprecated for ES modules.`, "Deprecati
8074
7926
  }
8075
7927
  function nativeImportOrRequire(e5, t4, i3) {
8076
7928
  return i3 && e5.nativeImport ? e5.nativeImport((function(e6) {
8077
- return ni && isAbsolute4(e6) ? pathToFileURL3(e6) : e6;
7929
+ return ni && isAbsolute5(e6) ? pathToFileURL3(e6) : e6;
8078
7930
  })(t4)).then((t5) => jitiInteropDefault(e5, t5)) : jitiInteropDefault(e5, e5.nativeRequire(t4));
8079
7931
  }
8080
7932
  const Ti = "9";
@@ -8364,14 +8216,12 @@ __export(dist_exports, {
8364
8216
  Session: () => Session,
8365
8217
  SessionPersistence: () => SessionPersistence,
8366
8218
  SkillRegistryImpl: () => SkillRegistryImpl,
8367
- SkillRouter: () => SkillRouter,
8368
8219
  SynthesizerRegistry: () => SynthesizerRegistry,
8369
8220
  ToolRegistryImpl: () => ToolRegistryImpl,
8370
8221
  TranscriberRegistry: () => TranscriberRegistry,
8371
8222
  TunnelProviderRegistry: () => TunnelProviderRegistry,
8372
8223
  ViewRendererRegistry: () => ViewRendererRegistry,
8373
8224
  autoAllowResolver: () => autoAllowResolver,
8374
- buildSkillIndexPrompt: () => buildSkillIndexPrompt,
8375
8225
  buildSynthesizeSkillPlugin: () => buildSynthesizeSkillPlugin,
8376
8226
  clearRetainedChildren: () => clearRetainedChildren,
8377
8227
  clearUsageStats: () => clearUsageStats,
@@ -12364,10 +12214,10 @@ var require_resolve_block_map = __commonJS({
12364
12214
  let offset = bm.offset;
12365
12215
  let commentEnd = null;
12366
12216
  for (const collItem of bm.items) {
12367
- const { start, key, sep: sep2, value } = collItem;
12217
+ const { start, key, sep: sep3, value } = collItem;
12368
12218
  const keyProps = resolveProps.resolveProps(start, {
12369
12219
  indicator: "explicit-key-ind",
12370
- next: key ?? sep2?.[0],
12220
+ next: key ?? sep3?.[0],
12371
12221
  offset,
12372
12222
  onError: onError2,
12373
12223
  parentIndent: bm.indent,
@@ -12381,7 +12231,7 @@ var require_resolve_block_map = __commonJS({
12381
12231
  else if ("indent" in key && key.indent !== bm.indent)
12382
12232
  onError2(offset, "BAD_INDENT", startColMsg);
12383
12233
  }
12384
- if (!keyProps.anchor && !keyProps.tag && !sep2) {
12234
+ if (!keyProps.anchor && !keyProps.tag && !sep3) {
12385
12235
  commentEnd = keyProps.end;
12386
12236
  if (keyProps.comment) {
12387
12237
  if (map2.comment)
@@ -12405,7 +12255,7 @@ var require_resolve_block_map = __commonJS({
12405
12255
  ctx.atKey = false;
12406
12256
  if (utilMapIncludes.mapIncludes(ctx, map2.items, keyNode))
12407
12257
  onError2(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
12408
- const valueProps = resolveProps.resolveProps(sep2 ?? [], {
12258
+ const valueProps = resolveProps.resolveProps(sep3 ?? [], {
12409
12259
  indicator: "map-value-ind",
12410
12260
  next: value,
12411
12261
  offset: keyNode.range[2],
@@ -12421,7 +12271,7 @@ var require_resolve_block_map = __commonJS({
12421
12271
  if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
12422
12272
  onError2(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
12423
12273
  }
12424
- const valueNode = value ? composeNode(ctx, value, valueProps, onError2) : composeEmptyNode(ctx, offset, sep2, null, valueProps, onError2);
12274
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError2) : composeEmptyNode(ctx, offset, sep3, null, valueProps, onError2);
12425
12275
  if (ctx.schema.compat)
12426
12276
  utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError2);
12427
12277
  offset = valueNode.range[2];
@@ -12510,7 +12360,7 @@ var require_resolve_end = __commonJS({
12510
12360
  let comment = "";
12511
12361
  if (end) {
12512
12362
  let hasSpace = false;
12513
- let sep2 = "";
12363
+ let sep3 = "";
12514
12364
  for (const token of end) {
12515
12365
  const { source, type } = token;
12516
12366
  switch (type) {
@@ -12524,13 +12374,13 @@ var require_resolve_end = __commonJS({
12524
12374
  if (!comment)
12525
12375
  comment = cb;
12526
12376
  else
12527
- comment += sep2 + cb;
12528
- sep2 = "";
12377
+ comment += sep3 + cb;
12378
+ sep3 = "";
12529
12379
  break;
12530
12380
  }
12531
12381
  case "newline":
12532
12382
  if (comment)
12533
- sep2 += source;
12383
+ sep3 += source;
12534
12384
  hasSpace = true;
12535
12385
  break;
12536
12386
  default:
@@ -12572,18 +12422,18 @@ var require_resolve_flow_collection = __commonJS({
12572
12422
  let offset = fc.offset + fc.start.source.length;
12573
12423
  for (let i2 = 0; i2 < fc.items.length; ++i2) {
12574
12424
  const collItem = fc.items[i2];
12575
- const { start, key, sep: sep2, value } = collItem;
12425
+ const { start, key, sep: sep3, value } = collItem;
12576
12426
  const props = resolveProps.resolveProps(start, {
12577
12427
  flow: fcName,
12578
12428
  indicator: "explicit-key-ind",
12579
- next: key ?? sep2?.[0],
12429
+ next: key ?? sep3?.[0],
12580
12430
  offset,
12581
12431
  onError: onError2,
12582
12432
  parentIndent: fc.indent,
12583
12433
  startOnNewline: false
12584
12434
  });
12585
12435
  if (!props.found) {
12586
- if (!props.anchor && !props.tag && !sep2 && !value) {
12436
+ if (!props.anchor && !props.tag && !sep3 && !value) {
12587
12437
  if (i2 === 0 && props.comma)
12588
12438
  onError2(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
12589
12439
  else if (i2 < fc.items.length - 1)
@@ -12637,8 +12487,8 @@ var require_resolve_flow_collection = __commonJS({
12637
12487
  }
12638
12488
  }
12639
12489
  }
12640
- if (!isMap && !sep2 && !props.found) {
12641
- const valueNode = value ? composeNode(ctx, value, props, onError2) : composeEmptyNode(ctx, props.end, sep2, null, props, onError2);
12490
+ if (!isMap && !sep3 && !props.found) {
12491
+ const valueNode = value ? composeNode(ctx, value, props, onError2) : composeEmptyNode(ctx, props.end, sep3, null, props, onError2);
12642
12492
  coll.items.push(valueNode);
12643
12493
  offset = valueNode.range[2];
12644
12494
  if (isBlock(value))
@@ -12650,7 +12500,7 @@ var require_resolve_flow_collection = __commonJS({
12650
12500
  if (isBlock(key))
12651
12501
  onError2(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
12652
12502
  ctx.atKey = false;
12653
- const valueProps = resolveProps.resolveProps(sep2 ?? [], {
12503
+ const valueProps = resolveProps.resolveProps(sep3 ?? [], {
12654
12504
  flow: fcName,
12655
12505
  indicator: "map-value-ind",
12656
12506
  next: value,
@@ -12661,8 +12511,8 @@ var require_resolve_flow_collection = __commonJS({
12661
12511
  });
12662
12512
  if (valueProps.found) {
12663
12513
  if (!isMap && !props.found && ctx.options.strict) {
12664
- if (sep2)
12665
- for (const st3 of sep2) {
12514
+ if (sep3)
12515
+ for (const st3 of sep3) {
12666
12516
  if (st3 === valueProps.found)
12667
12517
  break;
12668
12518
  if (st3.type === "newline") {
@@ -12679,7 +12529,7 @@ var require_resolve_flow_collection = __commonJS({
12679
12529
  else
12680
12530
  onError2(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
12681
12531
  }
12682
- const valueNode = value ? composeNode(ctx, value, valueProps, onError2) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep2, null, valueProps, onError2) : null;
12532
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError2) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep3, null, valueProps, onError2) : null;
12683
12533
  if (valueNode) {
12684
12534
  if (isBlock(value))
12685
12535
  onError2(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
@@ -12857,7 +12707,7 @@ var require_resolve_block_scalar = __commonJS({
12857
12707
  chompStart = i2 + 1;
12858
12708
  }
12859
12709
  let value = "";
12860
- let sep2 = "";
12710
+ let sep3 = "";
12861
12711
  let prevMoreIndented = false;
12862
12712
  for (let i2 = 0; i2 < contentStart; ++i2)
12863
12713
  value += lines[i2][0].slice(trimIndent) + "\n";
@@ -12874,24 +12724,24 @@ var require_resolve_block_scalar = __commonJS({
12874
12724
  indent = "";
12875
12725
  }
12876
12726
  if (type === Scalar.Scalar.BLOCK_LITERAL) {
12877
- value += sep2 + indent.slice(trimIndent) + content;
12878
- sep2 = "\n";
12727
+ value += sep3 + indent.slice(trimIndent) + content;
12728
+ sep3 = "\n";
12879
12729
  } else if (indent.length > trimIndent || content[0] === " ") {
12880
- if (sep2 === " ")
12881
- sep2 = "\n";
12882
- else if (!prevMoreIndented && sep2 === "\n")
12883
- sep2 = "\n\n";
12884
- value += sep2 + indent.slice(trimIndent) + content;
12885
- sep2 = "\n";
12730
+ if (sep3 === " ")
12731
+ sep3 = "\n";
12732
+ else if (!prevMoreIndented && sep3 === "\n")
12733
+ sep3 = "\n\n";
12734
+ value += sep3 + indent.slice(trimIndent) + content;
12735
+ sep3 = "\n";
12886
12736
  prevMoreIndented = true;
12887
12737
  } else if (content === "") {
12888
- if (sep2 === "\n")
12738
+ if (sep3 === "\n")
12889
12739
  value += "\n";
12890
12740
  else
12891
- sep2 = "\n";
12741
+ sep3 = "\n";
12892
12742
  } else {
12893
- value += sep2 + content;
12894
- sep2 = " ";
12743
+ value += sep3 + content;
12744
+ sep3 = " ";
12895
12745
  prevMoreIndented = false;
12896
12746
  }
12897
12747
  }
@@ -13072,25 +12922,25 @@ var require_resolve_flow_scalar = __commonJS({
13072
12922
  if (!match)
13073
12923
  return source;
13074
12924
  let res = match[1];
13075
- let sep2 = " ";
12925
+ let sep3 = " ";
13076
12926
  let pos = first.lastIndex;
13077
12927
  line.lastIndex = pos;
13078
12928
  while (match = line.exec(source)) {
13079
12929
  if (match[1] === "") {
13080
- if (sep2 === "\n")
13081
- res += sep2;
12930
+ if (sep3 === "\n")
12931
+ res += sep3;
13082
12932
  else
13083
- sep2 = "\n";
12933
+ sep3 = "\n";
13084
12934
  } else {
13085
- res += sep2 + match[1];
13086
- sep2 = " ";
12935
+ res += sep3 + match[1];
12936
+ sep3 = " ";
13087
12937
  }
13088
12938
  pos = line.lastIndex;
13089
12939
  }
13090
12940
  const last = /[ \t]*(.*)/sy;
13091
12941
  last.lastIndex = pos;
13092
12942
  match = last.exec(source);
13093
- return res + sep2 + (match?.[1] ?? "");
12943
+ return res + sep3 + (match?.[1] ?? "");
13094
12944
  }
13095
12945
  function doubleQuotedValue(source, onError2) {
13096
12946
  let res = "";
@@ -13893,14 +13743,14 @@ var require_cst_stringify = __commonJS({
13893
13743
  }
13894
13744
  }
13895
13745
  }
13896
- function stringifyItem({ start, key, sep: sep2, value }) {
13746
+ function stringifyItem({ start, key, sep: sep3, value }) {
13897
13747
  let res = "";
13898
13748
  for (const st3 of start)
13899
13749
  res += st3.source;
13900
13750
  if (key)
13901
13751
  res += stringifyToken(key);
13902
- if (sep2)
13903
- for (const st3 of sep2)
13752
+ if (sep3)
13753
+ for (const st3 of sep3)
13904
13754
  res += st3.source;
13905
13755
  if (value)
13906
13756
  res += stringifyToken(value);
@@ -15062,18 +14912,18 @@ var require_parser = __commonJS({
15062
14912
  if (this.type === "map-value-ind") {
15063
14913
  const prev = getPrevProps(this.peek(2));
15064
14914
  const start = getFirstKeyStartProps(prev);
15065
- let sep2;
14915
+ let sep3;
15066
14916
  if (scalar.end) {
15067
- sep2 = scalar.end;
15068
- sep2.push(this.sourceToken);
14917
+ sep3 = scalar.end;
14918
+ sep3.push(this.sourceToken);
15069
14919
  delete scalar.end;
15070
14920
  } else
15071
- sep2 = [this.sourceToken];
14921
+ sep3 = [this.sourceToken];
15072
14922
  const map2 = {
15073
14923
  type: "block-map",
15074
14924
  offset: scalar.offset,
15075
14925
  indent: scalar.indent,
15076
- items: [{ start, key: scalar, sep: sep2 }]
14926
+ items: [{ start, key: scalar, sep: sep3 }]
15077
14927
  };
15078
14928
  this.onKeyLine = true;
15079
14929
  this.stack[this.stack.length - 1] = map2;
@@ -15226,15 +15076,15 @@ var require_parser = __commonJS({
15226
15076
  } else if (isFlowToken(it4.key) && !includesToken(it4.sep, "newline")) {
15227
15077
  const start2 = getFirstKeyStartProps(it4.start);
15228
15078
  const key = it4.key;
15229
- const sep2 = it4.sep;
15230
- sep2.push(this.sourceToken);
15079
+ const sep3 = it4.sep;
15080
+ sep3.push(this.sourceToken);
15231
15081
  delete it4.key;
15232
15082
  delete it4.sep;
15233
15083
  this.stack.push({
15234
15084
  type: "block-map",
15235
15085
  offset: this.offset,
15236
15086
  indent: this.indent,
15237
- items: [{ start: start2, key, sep: sep2 }]
15087
+ items: [{ start: start2, key, sep: sep3 }]
15238
15088
  });
15239
15089
  } else if (start.length > 0) {
15240
15090
  it4.sep = it4.sep.concat(start, this.sourceToken);
@@ -15428,13 +15278,13 @@ var require_parser = __commonJS({
15428
15278
  const prev = getPrevProps(parent);
15429
15279
  const start = getFirstKeyStartProps(prev);
15430
15280
  fixFlowSeqItems(fc);
15431
- const sep2 = fc.end.splice(1, fc.end.length);
15432
- sep2.push(this.sourceToken);
15281
+ const sep3 = fc.end.splice(1, fc.end.length);
15282
+ sep3.push(this.sourceToken);
15433
15283
  const map2 = {
15434
15284
  type: "block-map",
15435
15285
  offset: fc.offset,
15436
15286
  indent: fc.indent,
15437
- items: [{ start, key: fc, sep: sep2 }]
15287
+ items: [{ start, key: fc, sep: sep3 }]
15438
15288
  };
15439
15289
  this.onKeyLine = true;
15440
15290
  this.stack[this.stack.length - 1] = map2;
@@ -16147,7 +15997,7 @@ var require_tr46 = __commonJS({
16147
15997
  TRANSITIONAL: 0,
16148
15998
  NONTRANSITIONAL: 1
16149
15999
  };
16150
- function normalize3(str2) {
16000
+ function normalize4(str2) {
16151
16001
  return str2.split("\0").map(function(s2) {
16152
16002
  return s2.normalize("NFC");
16153
16003
  }).join("\0");
@@ -16227,7 +16077,7 @@ var require_tr46 = __commonJS({
16227
16077
  PROCESSING_OPTIONS.NONTRANSITIONAL;
16228
16078
  }
16229
16079
  var error2 = false;
16230
- if (normalize3(label3) !== label3 || label3[3] === "-" && label3[4] === "-" || label3[0] === "-" || label3[label3.length - 1] === "-" || label3.indexOf(".") !== -1 || label3.search(combiningMarksRegex) === 0) {
16080
+ if (normalize4(label3) !== label3 || label3[3] === "-" && label3[4] === "-" || label3[0] === "-" || label3[label3.length - 1] === "-" || label3.indexOf(".") !== -1 || label3.search(combiningMarksRegex) === 0) {
16231
16081
  error2 = true;
16232
16082
  }
16233
16083
  var len = countSymbols(label3);
@@ -16245,7 +16095,7 @@ var require_tr46 = __commonJS({
16245
16095
  }
16246
16096
  function processing(domain_name, useSTD3, processing_option) {
16247
16097
  var result = mapChars(domain_name, useSTD3, processing_option);
16248
- result.string = normalize3(result.string);
16098
+ result.string = normalize4(result.string);
16249
16099
  var labels = result.string.split(".");
16250
16100
  for (var i2 = 0; i2 < labels.length; ++i2) {
16251
16101
  try {
@@ -21461,7 +21311,7 @@ function consumeBody() {
21461
21311
  let accum = [];
21462
21312
  let accumBytes = 0;
21463
21313
  let abort = false;
21464
- return new Body.Promise(function(resolve12, reject) {
21314
+ return new Body.Promise(function(resolve13, reject) {
21465
21315
  let resTimeout;
21466
21316
  if (_this4.timeout) {
21467
21317
  resTimeout = setTimeout(function() {
@@ -21495,7 +21345,7 @@ function consumeBody() {
21495
21345
  }
21496
21346
  clearTimeout(resTimeout);
21497
21347
  try {
21498
- resolve12(Buffer.concat(accum, accumBytes));
21348
+ resolve13(Buffer.concat(accum, accumBytes));
21499
21349
  } catch (err) {
21500
21350
  reject(new FetchError(`Could not create Buffer from response body for ${_this4.url}: ${err.message}`, "system", err));
21501
21351
  }
@@ -21758,7 +21608,7 @@ function fetch3(url2, opts) {
21758
21608
  throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
21759
21609
  }
21760
21610
  Body.Promise = fetch3.Promise;
21761
- return new fetch3.Promise(function(resolve12, reject) {
21611
+ return new fetch3.Promise(function(resolve13, reject) {
21762
21612
  const request = new Request2(url2, opts);
21763
21613
  const options = getNodeRequestOptions(request);
21764
21614
  const send = (options.protocol === "https:" ? https : http).request;
@@ -21891,7 +21741,7 @@ function fetch3(url2, opts) {
21891
21741
  requestOpts.body = void 0;
21892
21742
  requestOpts.headers.delete("content-length");
21893
21743
  }
21894
- resolve12(fetch3(new Request2(locationURL, requestOpts)));
21744
+ resolve13(fetch3(new Request2(locationURL, requestOpts)));
21895
21745
  finalize();
21896
21746
  return;
21897
21747
  }
@@ -21912,7 +21762,7 @@ function fetch3(url2, opts) {
21912
21762
  const codings = headers.get("Content-Encoding");
21913
21763
  if (!request.compress || request.method === "HEAD" || codings === null || res.statusCode === 204 || res.statusCode === 304) {
21914
21764
  response = new Response3(body, response_options);
21915
- resolve12(response);
21765
+ resolve13(response);
21916
21766
  return;
21917
21767
  }
21918
21768
  const zlibOptions = {
@@ -21922,7 +21772,7 @@ function fetch3(url2, opts) {
21922
21772
  if (codings == "gzip" || codings == "x-gzip") {
21923
21773
  body = body.pipe(zlib.createGunzip(zlibOptions));
21924
21774
  response = new Response3(body, response_options);
21925
- resolve12(response);
21775
+ resolve13(response);
21926
21776
  return;
21927
21777
  }
21928
21778
  if (codings == "deflate" || codings == "x-deflate") {
@@ -21934,12 +21784,12 @@ function fetch3(url2, opts) {
21934
21784
  body = body.pipe(zlib.createInflateRaw());
21935
21785
  }
21936
21786
  response = new Response3(body, response_options);
21937
- resolve12(response);
21787
+ resolve13(response);
21938
21788
  });
21939
21789
  raw.on("end", function() {
21940
21790
  if (!response) {
21941
21791
  response = new Response3(body, response_options);
21942
- resolve12(response);
21792
+ resolve13(response);
21943
21793
  }
21944
21794
  });
21945
21795
  return;
@@ -21947,11 +21797,11 @@ function fetch3(url2, opts) {
21947
21797
  if (codings == "br" && typeof zlib.createBrotliDecompress === "function") {
21948
21798
  body = body.pipe(zlib.createBrotliDecompress());
21949
21799
  response = new Response3(body, response_options);
21950
- resolve12(response);
21800
+ resolve13(response);
21951
21801
  return;
21952
21802
  }
21953
21803
  response = new Response3(body, response_options);
21954
- resolve12(response);
21804
+ resolve13(response);
21955
21805
  });
21956
21806
  writeToStream(req, request);
21957
21807
  });
@@ -29798,7 +29648,7 @@ var require_has_flag = __commonJS({
29798
29648
  // ../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js
29799
29649
  var require_supports_color = __commonJS({
29800
29650
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
29801
- var os23 = __require("os");
29651
+ var os22 = __require("os");
29802
29652
  var tty2 = __require("tty");
29803
29653
  var hasFlag2 = require_has_flag();
29804
29654
  var { env: env3 } = process;
@@ -29846,7 +29696,7 @@ var require_supports_color = __commonJS({
29846
29696
  return min;
29847
29697
  }
29848
29698
  if (process.platform === "win32") {
29849
- const osRelease = os23.release().split(".");
29699
+ const osRelease = os22.release().split(".");
29850
29700
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
29851
29701
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
29852
29702
  }
@@ -35470,7 +35320,7 @@ var require_frameworks = __commonJS({
35470
35320
  end: () => resolveResponse({ status: 204 }),
35471
35321
  respond: (json) => resolveResponse({ jsonBody: json }),
35472
35322
  unauthorized: () => resolveResponse({ status: 401, body: WRONG_TOKEN_ERROR }),
35473
- handlerReturn: new Promise((resolve12) => resolveResponse = resolve12)
35323
+ handlerReturn: new Promise((resolve13) => resolveResponse = resolve13)
35474
35324
  };
35475
35325
  };
35476
35326
  var bun = (request) => {
@@ -35494,8 +35344,8 @@ var require_frameworks = __commonJS({
35494
35344
  };
35495
35345
  var cloudflare = (event) => {
35496
35346
  let resolveResponse;
35497
- event.respondWith(new Promise((resolve12) => {
35498
- resolveResponse = resolve12;
35347
+ event.respondWith(new Promise((resolve13) => {
35348
+ resolveResponse = resolve13;
35499
35349
  }));
35500
35350
  return {
35501
35351
  get update() {
@@ -35579,12 +35429,12 @@ var require_frameworks = __commonJS({
35579
35429
  const secretHeaderFromRequest = req.headers[SECRET_HEADER_LOWERCASE];
35580
35430
  return {
35581
35431
  get update() {
35582
- return new Promise((resolve12, reject) => {
35432
+ return new Promise((resolve13, reject) => {
35583
35433
  const chunks = [];
35584
35434
  req.on("data", (chunk) => chunks.push(chunk)).once("end", () => {
35585
35435
  const raw = Buffer.concat(chunks).toString("utf-8");
35586
35436
  try {
35587
- resolve12(JSON.parse(raw));
35437
+ resolve13(JSON.parse(raw));
35588
35438
  } catch (err) {
35589
35439
  reject(err);
35590
35440
  }
@@ -35834,7 +35684,7 @@ var require_webhook = __commonJS({
35834
35684
  function timeoutIfNecessary(task, onTimeout, timeout) {
35835
35685
  if (timeout === Infinity)
35836
35686
  return task;
35837
- return new Promise((resolve12, reject) => {
35687
+ return new Promise((resolve13, reject) => {
35838
35688
  const handle2 = setTimeout(() => {
35839
35689
  debugErr(`Request timed out after ${timeout} ms`);
35840
35690
  if (onTimeout === "throw") {
@@ -35842,7 +35692,7 @@ var require_webhook = __commonJS({
35842
35692
  } else {
35843
35693
  if (typeof onTimeout === "function")
35844
35694
  onTimeout();
35845
- resolve12();
35695
+ resolve13();
35846
35696
  }
35847
35697
  const now = Date.now();
35848
35698
  task.finally(() => {
@@ -35850,7 +35700,7 @@ var require_webhook = __commonJS({
35850
35700
  debugErr(`Request completed ${diff2} ms after timeout!`);
35851
35701
  });
35852
35702
  }, timeout);
35853
- task.then(resolve12).catch(reject).finally(() => clearTimeout(handle2));
35703
+ task.then(resolve13).catch(reject).finally(() => clearTimeout(handle2));
35854
35704
  });
35855
35705
  }
35856
35706
  }
@@ -38461,7 +38311,7 @@ var init_protocol = __esm({
38461
38311
  return;
38462
38312
  }
38463
38313
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
38464
- await new Promise((resolve12) => setTimeout(resolve12, pollInterval));
38314
+ await new Promise((resolve13) => setTimeout(resolve13, pollInterval));
38465
38315
  options?.signal?.throwIfAborted();
38466
38316
  }
38467
38317
  } catch (error2) {
@@ -38478,7 +38328,7 @@ var init_protocol = __esm({
38478
38328
  */
38479
38329
  request(request, resultSchema, options) {
38480
38330
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
38481
- return new Promise((resolve12, reject) => {
38331
+ return new Promise((resolve13, reject) => {
38482
38332
  const earlyReject = (error2) => {
38483
38333
  reject(error2);
38484
38334
  };
@@ -38556,7 +38406,7 @@ var init_protocol = __esm({
38556
38406
  if (!parseResult.success) {
38557
38407
  reject(parseResult.error);
38558
38408
  } else {
38559
- resolve12(parseResult.data);
38409
+ resolve13(parseResult.data);
38560
38410
  }
38561
38411
  } catch (error2) {
38562
38412
  reject(error2);
@@ -38817,12 +38667,12 @@ var init_protocol = __esm({
38817
38667
  }
38818
38668
  } catch {
38819
38669
  }
38820
- return new Promise((resolve12, reject) => {
38670
+ return new Promise((resolve13, reject) => {
38821
38671
  if (signal.aborted) {
38822
38672
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
38823
38673
  return;
38824
38674
  }
38825
- const timeoutId = setTimeout(resolve12, interval);
38675
+ const timeoutId = setTimeout(resolve13, interval);
38826
38676
  signal.addEventListener("abort", () => {
38827
38677
  clearTimeout(timeoutId);
38828
38678
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -41083,8 +40933,8 @@ var require_resolve = __commonJS({
41083
40933
  }
41084
40934
  return count;
41085
40935
  }
41086
- function getFullPath(resolver2, id = "", normalize3) {
41087
- if (normalize3 !== false)
40936
+ function getFullPath(resolver2, id = "", normalize4) {
40937
+ if (normalize4 !== false)
41088
40938
  id = normalizeId(id);
41089
40939
  const p3 = resolver2.parse(id);
41090
40940
  return _getFullPath(resolver2, p3);
@@ -41827,7 +41677,7 @@ var require_compile = __commonJS({
41827
41677
  const schOrFunc = root.refs[ref];
41828
41678
  if (schOrFunc)
41829
41679
  return schOrFunc;
41830
- let _sch = resolve12.call(this, root, ref);
41680
+ let _sch = resolve13.call(this, root, ref);
41831
41681
  if (_sch === void 0) {
41832
41682
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
41833
41683
  const { schemaId } = this.opts;
@@ -41854,7 +41704,7 @@ var require_compile = __commonJS({
41854
41704
  function sameSchemaEnv(s1, s2) {
41855
41705
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
41856
41706
  }
41857
- function resolve12(root, ref) {
41707
+ function resolve13(root, ref) {
41858
41708
  let sch;
41859
41709
  while (typeof (sch = this.refs[ref]) == "string")
41860
41710
  ref = sch;
@@ -42472,7 +42322,7 @@ var require_fast_uri = __commonJS({
42472
42322
  "../../node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js"(exports, module) {
42473
42323
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils2();
42474
42324
  var { SCHEMES, getSchemeHandler } = require_schemes();
42475
- function normalize3(uri, options) {
42325
+ function normalize4(uri, options) {
42476
42326
  if (typeof uri === "string") {
42477
42327
  uri = /** @type {T} */
42478
42328
  normalizeString(uri, options);
@@ -42482,7 +42332,7 @@ var require_fast_uri = __commonJS({
42482
42332
  }
42483
42333
  return uri;
42484
42334
  }
42485
- function resolve12(baseURI, relativeURI, options) {
42335
+ function resolve13(baseURI, relativeURI, options) {
42486
42336
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
42487
42337
  const resolved = resolveComponent(parse2(baseURI, schemelessOptions), parse2(relativeURI, schemelessOptions), schemelessOptions, true);
42488
42338
  schemelessOptions.skipEscape = true;
@@ -42739,8 +42589,8 @@ var require_fast_uri = __commonJS({
42739
42589
  }
42740
42590
  var fastUri = {
42741
42591
  SCHEMES,
42742
- normalize: normalize3,
42743
- resolve: resolve12,
42592
+ normalize: normalize4,
42593
+ resolve: resolve13,
42744
42594
  resolveComponent,
42745
42595
  equal,
42746
42596
  serialize,
@@ -46570,12 +46420,12 @@ var require_isexe = __commonJS({
46570
46420
  if (typeof Promise !== "function") {
46571
46421
  throw new TypeError("callback not provided");
46572
46422
  }
46573
- return new Promise(function(resolve12, reject) {
46423
+ return new Promise(function(resolve13, reject) {
46574
46424
  isexe(path62, options || {}, function(er2, is) {
46575
46425
  if (er2) {
46576
46426
  reject(er2);
46577
46427
  } else {
46578
- resolve12(is);
46428
+ resolve13(is);
46579
46429
  }
46580
46430
  });
46581
46431
  });
@@ -46641,27 +46491,27 @@ var require_which = __commonJS({
46641
46491
  opt = {};
46642
46492
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
46643
46493
  const found = [];
46644
- const step = (i2) => new Promise((resolve12, reject) => {
46494
+ const step = (i2) => new Promise((resolve13, reject) => {
46645
46495
  if (i2 === pathEnv.length)
46646
- return opt.all && found.length ? resolve12(found) : reject(getNotFoundError(cmd));
46496
+ return opt.all && found.length ? resolve13(found) : reject(getNotFoundError(cmd));
46647
46497
  const ppRaw = pathEnv[i2];
46648
46498
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
46649
46499
  const pCmd = path62.join(pathPart, cmd);
46650
46500
  const p3 = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
46651
- resolve12(subStep(p3, i2, 0));
46501
+ resolve13(subStep(p3, i2, 0));
46652
46502
  });
46653
- const subStep = (p3, i2, ii) => new Promise((resolve12, reject) => {
46503
+ const subStep = (p3, i2, ii) => new Promise((resolve13, reject) => {
46654
46504
  if (ii === pathExt.length)
46655
- return resolve12(step(i2 + 1));
46505
+ return resolve13(step(i2 + 1));
46656
46506
  const ext = pathExt[ii];
46657
46507
  isexe(p3 + ext, { pathExt: pathExtExe }, (er2, is) => {
46658
46508
  if (!er2 && is) {
46659
46509
  if (opt.all)
46660
46510
  found.push(p3 + ext);
46661
46511
  else
46662
- return resolve12(p3 + ext);
46512
+ return resolve13(p3 + ext);
46663
46513
  }
46664
- return resolve12(subStep(p3, i2, ii + 1));
46514
+ return resolve13(subStep(p3, i2, ii + 1));
46665
46515
  });
46666
46516
  });
46667
46517
  return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
@@ -47057,7 +46907,7 @@ var init_stdio2 = __esm({
47057
46907
  if (this._process) {
47058
46908
  throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
47059
46909
  }
47060
- return new Promise((resolve12, reject) => {
46910
+ return new Promise((resolve13, reject) => {
47061
46911
  this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
47062
46912
  // merge default env with server env because mcp server needs some env vars
47063
46913
  env: {
@@ -47074,7 +46924,7 @@ var init_stdio2 = __esm({
47074
46924
  this.onerror?.(error2);
47075
46925
  });
47076
46926
  this._process.on("spawn", () => {
47077
- resolve12();
46927
+ resolve13();
47078
46928
  });
47079
46929
  this._process.on("close", (_code) => {
47080
46930
  this._process = void 0;
@@ -47133,22 +46983,22 @@ var init_stdio2 = __esm({
47133
46983
  if (this._process) {
47134
46984
  const processToClose = this._process;
47135
46985
  this._process = void 0;
47136
- const closePromise = new Promise((resolve12) => {
46986
+ const closePromise = new Promise((resolve13) => {
47137
46987
  processToClose.once("close", () => {
47138
- resolve12();
46988
+ resolve13();
47139
46989
  });
47140
46990
  });
47141
46991
  try {
47142
46992
  processToClose.stdin?.end();
47143
46993
  } catch {
47144
46994
  }
47145
- await Promise.race([closePromise, new Promise((resolve12) => setTimeout(resolve12, 2e3).unref())]);
46995
+ await Promise.race([closePromise, new Promise((resolve13) => setTimeout(resolve13, 2e3).unref())]);
47146
46996
  if (processToClose.exitCode === null) {
47147
46997
  try {
47148
46998
  processToClose.kill("SIGTERM");
47149
46999
  } catch {
47150
47000
  }
47151
- await Promise.race([closePromise, new Promise((resolve12) => setTimeout(resolve12, 2e3).unref())]);
47001
+ await Promise.race([closePromise, new Promise((resolve13) => setTimeout(resolve13, 2e3).unref())]);
47152
47002
  }
47153
47003
  if (processToClose.exitCode === null) {
47154
47004
  try {
@@ -47160,15 +47010,15 @@ var init_stdio2 = __esm({
47160
47010
  this._readBuffer.clear();
47161
47011
  }
47162
47012
  send(message) {
47163
- return new Promise((resolve12) => {
47013
+ return new Promise((resolve13) => {
47164
47014
  if (!this._process?.stdin) {
47165
47015
  throw new Error("Not connected");
47166
47016
  }
47167
47017
  const json = serializeMessage(message);
47168
47018
  if (this._process.stdin.write(json)) {
47169
- resolve12();
47019
+ resolve13();
47170
47020
  } else {
47171
- this._process.stdin.once("drain", resolve12);
47021
+ this._process.stdin.once("drain", resolve13);
47172
47022
  }
47173
47023
  });
47174
47024
  }
@@ -48597,7 +48447,7 @@ var init_sse = __esm({
48597
48447
  }
48598
48448
  _startOrAuth() {
48599
48449
  const fetchImpl2 = this?._eventSourceInit?.fetch ?? this._fetch ?? fetch;
48600
- return new Promise((resolve12, reject) => {
48450
+ return new Promise((resolve13, reject) => {
48601
48451
  this._eventSource = new EventSource(this._url.href, {
48602
48452
  ...this._eventSourceInit,
48603
48453
  fetch: async (url2, init3) => {
@@ -48618,7 +48468,7 @@ var init_sse = __esm({
48618
48468
  this._abortController = new AbortController();
48619
48469
  this._eventSource.onerror = (event) => {
48620
48470
  if (event.code === 401 && this._authProvider) {
48621
- this._authThenStart().then(resolve12, reject);
48471
+ this._authThenStart().then(resolve13, reject);
48622
48472
  return;
48623
48473
  }
48624
48474
  const error2 = new SseError(event.code, event.message, event);
@@ -48640,7 +48490,7 @@ var init_sse = __esm({
48640
48490
  void this.close();
48641
48491
  return;
48642
48492
  }
48643
- resolve12();
48493
+ resolve13();
48644
48494
  });
48645
48495
  this._eventSource.onmessage = (event) => {
48646
48496
  const messageEvent = event;
@@ -49234,7 +49084,7 @@ var init_types2 = __esm({
49234
49084
  }
49235
49085
  });
49236
49086
  async function runMcpCallWithFallback(callPromise, signal, toolName) {
49237
- return await new Promise((resolve12, reject) => {
49087
+ return await new Promise((resolve13, reject) => {
49238
49088
  let settled = false;
49239
49089
  const settle = (fn) => {
49240
49090
  if (settled)
@@ -49251,7 +49101,7 @@ async function runMcpCallWithFallback(callPromise, signal, toolName) {
49251
49101
  settle(() => reject(new Error(`MCP tool "${toolName}" timed out after ${MCP_CALL_TIMEOUT_MS}ms`)));
49252
49102
  }, MCP_CALL_TIMEOUT_MS);
49253
49103
  signal.addEventListener("abort", onAbort, { once: true });
49254
- callPromise.then((v3) => settle(() => resolve12(v3)), (err) => settle(() => reject(err instanceof Error ? err : new Error(String(err)))));
49104
+ callPromise.then((v3) => settle(() => resolve13(v3)), (err) => settle(() => reject(err instanceof Error ? err : new Error(String(err)))));
49255
49105
  });
49256
49106
  }
49257
49107
  async function wrapMcpServerTools(opts) {
@@ -51987,14 +51837,14 @@ var require_react_development = __commonJS({
51987
51837
  var thenableResult = result;
51988
51838
  var wasAwaited = false;
51989
51839
  var thenable = {
51990
- then: function(resolve12, reject) {
51840
+ then: function(resolve13, reject) {
51991
51841
  wasAwaited = true;
51992
51842
  thenableResult.then(function(returnValue2) {
51993
51843
  popActScope(prevActScopeDepth);
51994
51844
  if (actScopeDepth === 0) {
51995
- recursivelyFlushAsyncActWork(returnValue2, resolve12, reject);
51845
+ recursivelyFlushAsyncActWork(returnValue2, resolve13, reject);
51996
51846
  } else {
51997
- resolve12(returnValue2);
51847
+ resolve13(returnValue2);
51998
51848
  }
51999
51849
  }, function(error3) {
52000
51850
  popActScope(prevActScopeDepth);
@@ -52024,20 +51874,20 @@ var require_react_development = __commonJS({
52024
51874
  ReactCurrentActQueue.current = null;
52025
51875
  }
52026
51876
  var _thenable = {
52027
- then: function(resolve12, reject) {
51877
+ then: function(resolve13, reject) {
52028
51878
  if (ReactCurrentActQueue.current === null) {
52029
51879
  ReactCurrentActQueue.current = [];
52030
- recursivelyFlushAsyncActWork(returnValue, resolve12, reject);
51880
+ recursivelyFlushAsyncActWork(returnValue, resolve13, reject);
52031
51881
  } else {
52032
- resolve12(returnValue);
51882
+ resolve13(returnValue);
52033
51883
  }
52034
51884
  }
52035
51885
  };
52036
51886
  return _thenable;
52037
51887
  } else {
52038
51888
  var _thenable2 = {
52039
- then: function(resolve12, reject) {
52040
- resolve12(returnValue);
51889
+ then: function(resolve13, reject) {
51890
+ resolve13(returnValue);
52041
51891
  }
52042
51892
  };
52043
51893
  return _thenable2;
@@ -52053,7 +51903,7 @@ var require_react_development = __commonJS({
52053
51903
  actScopeDepth = prevActScopeDepth;
52054
51904
  }
52055
51905
  }
52056
- function recursivelyFlushAsyncActWork(returnValue, resolve12, reject) {
51906
+ function recursivelyFlushAsyncActWork(returnValue, resolve13, reject) {
52057
51907
  {
52058
51908
  var queue = ReactCurrentActQueue.current;
52059
51909
  if (queue !== null) {
@@ -52062,16 +51912,16 @@ var require_react_development = __commonJS({
52062
51912
  enqueueTask(function() {
52063
51913
  if (queue.length === 0) {
52064
51914
  ReactCurrentActQueue.current = null;
52065
- resolve12(returnValue);
51915
+ resolve13(returnValue);
52066
51916
  } else {
52067
- recursivelyFlushAsyncActWork(returnValue, resolve12, reject);
51917
+ recursivelyFlushAsyncActWork(returnValue, resolve13, reject);
52068
51918
  }
52069
51919
  });
52070
51920
  } catch (error3) {
52071
51921
  reject(error3);
52072
51922
  }
52073
51923
  } else {
52074
- resolve12(returnValue);
51924
+ resolve13(returnValue);
52075
51925
  }
52076
51926
  }
52077
51927
  }
@@ -82746,8 +82596,8 @@ var init_ink = __esm({
82746
82596
  }
82747
82597
  }
82748
82598
  async waitUntilExit() {
82749
- this.exitPromise ||= new Promise((resolve12, reject) => {
82750
- this.resolveExitPromise = resolve12;
82599
+ this.exitPromise ||= new Promise((resolve13, reject) => {
82600
+ this.resolveExitPromise = resolve13;
82751
82601
  this.rejectExitPromise = reject;
82752
82602
  });
82753
82603
  return this.exitPromise;
@@ -85409,7 +85259,7 @@ function handleSubagentEvent(e3, subagents, root, groupRef) {
85409
85259
  if (e3.subtype === "subagent_completed") {
85410
85260
  block.completedAtMs = new Date(e3.ts).getTime();
85411
85261
  block.stopReason = String(payload.stopReason ?? "");
85412
- block.tokensUsed = typeof payload.tokensUsed === "number" ? payload.tokensUsed : 0;
85262
+ block.tokensUsed = typeof payload.tokensUsed === "number" ? payload.tokensUsed : null;
85413
85263
  const text = typeof payload.text === "string" ? payload.text : "";
85414
85264
  if (text)
85415
85265
  block.finalPreview = oneLine(text);
@@ -85732,10 +85582,10 @@ function parseBlocks(src) {
85732
85582
  continue;
85733
85583
  }
85734
85584
  if (line.trim().startsWith("|") && i2 + 1 < lines.length) {
85735
- const sep2 = lines[i2 + 1];
85736
- if (isTableSeparator(sep2)) {
85585
+ const sep3 = lines[i2 + 1];
85586
+ if (isTableSeparator(sep3)) {
85737
85587
  const header = parseTableCells(line);
85738
- const aligns = parseTableAligns(sep2);
85588
+ const aligns = parseTableAligns(sep3);
85739
85589
  const rows = [];
85740
85590
  i2 += 2;
85741
85591
  while (i2 < lines.length && lines[i2].trim().startsWith("|")) {
@@ -85816,8 +85666,8 @@ function stripOuterPipes(s2) {
85816
85666
  function parseTableCells(line) {
85817
85667
  return stripOuterPipes(line).split("|").map((s2) => s2.trim());
85818
85668
  }
85819
- function parseTableAligns(sep2) {
85820
- const cells = stripOuterPipes(sep2).split("|");
85669
+ function parseTableAligns(sep3) {
85670
+ const cells = stripOuterPipes(sep3).split("|");
85821
85671
  return cells.map((c2) => {
85822
85672
  const t2 = c2.trim();
85823
85673
  const left = t2.startsWith(":");
@@ -86910,8 +86760,7 @@ function readClipboardImageLinux() {
86910
86760
  if (result.status === 0 && result.stdout && result.stdout.length > 0) {
86911
86761
  const target = nextCachePath();
86912
86762
  try {
86913
- const fs45 = __require("fs");
86914
- fs45.writeFileSync(target, result.stdout);
86763
+ writeFileSync(target, result.stdout);
86915
86764
  } catch {
86916
86765
  return null;
86917
86766
  }
@@ -87091,14 +86940,14 @@ function usePermissionQueue(session, registerInteractiveResolver) {
87091
86940
  if (yoloRef.current) {
87092
86941
  return { mode: "allow", reason: "yolo mode" };
87093
86942
  }
87094
- return new Promise((resolve12) => {
87095
- setPendingPermissions((prev) => [...prev, { call, ctx, resolve: resolve12 }]);
86943
+ return new Promise((resolve13) => {
86944
+ setPendingPermissions((prev) => [...prev, { call, ctx, resolve: resolve13 }]);
87096
86945
  });
87097
86946
  });
87098
86947
  session.setApprovalResolver({
87099
86948
  name: "tui-approval",
87100
- confirm: (request) => new Promise((resolve12) => {
87101
- setPendingApproval({ request, resolve: resolve12 });
86949
+ confirm: (request) => new Promise((resolve13) => {
86950
+ setPendingApproval({ request, resolve: resolve13 });
87102
86951
  })
87103
86952
  });
87104
86953
  return () => {
@@ -87181,14 +87030,14 @@ async function startVoiceRecording(opts = {}) {
87181
87030
  while (Buffer$1.concat(stderrChunks).byteLength > 16384)
87182
87031
  stderrChunks.shift();
87183
87032
  });
87184
- const closed = new Promise((resolve12) => {
87033
+ const closed = new Promise((resolve13) => {
87185
87034
  child.once("close", (code, signal) => {
87186
87035
  closeState = { code, signal };
87187
- resolve12();
87036
+ resolve13();
87188
87037
  });
87189
87038
  });
87190
- await new Promise((resolve12, reject) => {
87191
- child.once("spawn", resolve12);
87039
+ await new Promise((resolve13, reject) => {
87040
+ child.once("spawn", resolve13);
87192
87041
  child.once("error", (err) => reject(toSpawnError(command, err)));
87193
87042
  });
87194
87043
  let stopPromise = null;
@@ -87211,14 +87060,14 @@ async function checkVoiceCaptureAvailable(opts = {}) {
87211
87060
  const child = (opts.spawnImpl ?? spawn)(command, ["-version"], {
87212
87061
  stdio: ["ignore", "ignore", "ignore"]
87213
87062
  });
87214
- return new Promise((resolve12) => {
87063
+ return new Promise((resolve13) => {
87215
87064
  let settled = false;
87216
87065
  const done = (check) => {
87217
87066
  if (settled)
87218
87067
  return;
87219
87068
  settled = true;
87220
87069
  clearTimeout(timer);
87221
- resolve12(check);
87070
+ resolve13(check);
87222
87071
  };
87223
87072
  const timer = setTimeout(() => {
87224
87073
  if (!child.killed)
@@ -87817,9 +87666,9 @@ function makePickerHandler(deps) {
87817
87666
  }
87818
87667
  function handlePluginAction(id, deps) {
87819
87668
  const admin = deps.session.pluginsAdmin;
87820
- const sep2 = id.lastIndexOf("::");
87821
- const name = sep2 >= 0 ? id.slice(0, sep2) : id;
87822
- const action = sep2 >= 0 ? id.slice(sep2 + 2) : "";
87669
+ const sep3 = id.lastIndexOf("::");
87670
+ const name = sep3 >= 0 ? id.slice(0, sep3) : id;
87671
+ const action = sep3 >= 0 ? id.slice(sep3 + 2) : "";
87823
87672
  if (action === "install") {
87824
87673
  deps.setSystemNotice(`to install: run \`moxxy plugins install ${name}\``);
87825
87674
  return;
@@ -88103,18 +87952,13 @@ function orderByScope(skills) {
88103
87952
  }
88104
87953
  return out;
88105
87954
  }
88106
- function oneLine2(s2) {
88107
- return s2.replace(/[\r\n\t]+/g, " ").replace(/ +/g, " ").trim();
88108
- }
88109
- function truncate5(s2, n2) {
88110
- return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "\u2026";
88111
- }
88112
87955
  var import_jsx_runtime25, import_react53, NAME_COL, SCOPE_COL, WINDOW, ORDER, SkillsPanel;
88113
87956
  var init_SkillsPanel = __esm({
88114
87957
  async "../plugin-cli/dist/components/SkillsPanel.js"() {
88115
87958
  import_jsx_runtime25 = __toESM(require_jsx_runtime());
88116
87959
  import_react53 = __toESM(require_react());
88117
87960
  await init_build2();
87961
+ init_dist8();
88118
87962
  await init_Modal();
88119
87963
  await init_useScrollableList();
88120
87964
  NAME_COL = 28;
@@ -88163,7 +88007,7 @@ var init_SkillsPanel = __esm({
88163
88007
  return (0, import_jsx_runtime25.jsxs)(Modal, { title: "Skills", subtitle, hints, ...tabs ? { tabs, activeTabId: activeTab, onTabChange: (id) => setActiveTab(id) } : {}, ...onClose ? { onClose } : {}, children: [rows.length === 0 ? (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, children: activeTab === "mcp" ? "(no MCP servers attached)" : "(no skills discovered)" }) : null, scroll.canScrollUp ? (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, children: ` \u2191 ${scroll.offset} more above` }) : null, slice.map((row, i2) => {
88164
88008
  const absoluteIndex = scroll.visible.start + i2;
88165
88009
  const focused = absoluteIndex === scroll.cursor;
88166
- return (0, import_jsx_runtime25.jsxs)(Box_default, { children: [(0, import_jsx_runtime25.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime25.jsx)(Box_default, { width: NAME_COL, children: (0, import_jsx_runtime25.jsx)(Text, { bold: true, children: truncate5(row.name, NAME_COL - 1) }) }), (0, import_jsx_runtime25.jsx)(Box_default, { width: SCOPE_COL, children: (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, children: row.scope }) }), (0, import_jsx_runtime25.jsx)(Box_default, { width: descWidth, children: (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, wrap: "truncate", children: oneLine2(row.description) }) })] }, row.key);
88010
+ return (0, import_jsx_runtime25.jsxs)(Box_default, { children: [(0, import_jsx_runtime25.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime25.jsx)(Box_default, { width: NAME_COL, children: (0, import_jsx_runtime25.jsx)(Text, { bold: true, children: truncate3(row.name, NAME_COL - 2) }) }), (0, import_jsx_runtime25.jsx)(Box_default, { width: SCOPE_COL, children: (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, children: row.scope }) }), (0, import_jsx_runtime25.jsx)(Box_default, { width: descWidth, children: (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, wrap: "truncate", children: oneLine(row.description) }) })] }, row.key);
88167
88011
  }), scroll.canScrollDown ? (0, import_jsx_runtime25.jsx)(Text, { dimColor: true, children: ` \u2193 ${rows.length - scroll.visible.end} more below` }) : null] });
88168
88012
  };
88169
88013
  }
@@ -88180,18 +88024,13 @@ function matchesTab(tool, tab2) {
88180
88024
  return action === "prompt";
88181
88025
  return action === "deny";
88182
88026
  }
88183
- function oneLine3(s2) {
88184
- return s2.replace(/[\r\n\t]+/g, " ").replace(/ +/g, " ").trim();
88185
- }
88186
- function truncate6(s2, n2) {
88187
- return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "\u2026";
88188
- }
88189
88027
  var import_jsx_runtime26, import_react54, NAME_COL2, BADGE_COL, WINDOW2, ToolsPanel, ToolRow, PermissionBadge;
88190
88028
  var init_ToolsPanel = __esm({
88191
88029
  async "../plugin-cli/dist/components/ToolsPanel.js"() {
88192
88030
  import_jsx_runtime26 = __toESM(require_jsx_runtime());
88193
88031
  import_react54 = __toESM(require_react());
88194
88032
  await init_build2();
88033
+ init_dist8();
88195
88034
  init_theme();
88196
88035
  await init_Modal();
88197
88036
  await init_useScrollableList();
@@ -88243,8 +88082,8 @@ var init_ToolsPanel = __esm({
88243
88082
  const perm = tool.permission?.action ?? "allow";
88244
88083
  const termWidth = process.stdout.columns ?? 80;
88245
88084
  const descWidth = Math.max(20, termWidth - NAME_COL2 - BADGE_COL - 12);
88246
- const desc = oneLine3(tool.description ?? "");
88247
- return (0, import_jsx_runtime26.jsxs)(Box_default, { children: [(0, import_jsx_runtime26.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime26.jsx)(Box_default, { width: NAME_COL2, children: (0, import_jsx_runtime26.jsx)(Text, { bold: true, children: truncate6(tool.name, NAME_COL2 - 1) }) }), (0, import_jsx_runtime26.jsx)(Box_default, { width: BADGE_COL, children: (0, import_jsx_runtime26.jsx)(PermissionBadge, { action: perm }) }), (0, import_jsx_runtime26.jsx)(Box_default, { width: descWidth, children: (0, import_jsx_runtime26.jsx)(Text, { dimColor: true, wrap: "truncate", children: desc }) })] });
88085
+ const desc = oneLine(tool.description ?? "");
88086
+ return (0, import_jsx_runtime26.jsxs)(Box_default, { children: [(0, import_jsx_runtime26.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime26.jsx)(Box_default, { width: NAME_COL2, children: (0, import_jsx_runtime26.jsx)(Text, { bold: true, children: truncate3(tool.name, NAME_COL2 - 2) }) }), (0, import_jsx_runtime26.jsx)(Box_default, { width: BADGE_COL, children: (0, import_jsx_runtime26.jsx)(PermissionBadge, { action: perm }) }), (0, import_jsx_runtime26.jsx)(Box_default, { width: descWidth, children: (0, import_jsx_runtime26.jsx)(Text, { dimColor: true, wrap: "truncate", children: desc }) })] });
88248
88087
  };
88249
88088
  PermissionBadge = ({ action }) => {
88250
88089
  if (action === "allow")
@@ -88275,7 +88114,7 @@ function collectAgents(events) {
88275
88114
  completedAtMs: null,
88276
88115
  state: "running",
88277
88116
  activity: [
88278
- { atMs, text: `started \xB7 ${truncate7(String(payload.prompt ?? ""), 80)}` }
88117
+ { atMs, text: `started \xB7 ${truncate5(String(payload.prompt ?? ""), 80)}` }
88279
88118
  ]
88280
88119
  });
88281
88120
  continue;
@@ -88293,7 +88132,7 @@ function collectAgents(events) {
88293
88132
  const ok = payload.ok === true;
88294
88133
  agent.activity.push({
88295
88134
  atMs,
88296
- text: ok ? " \u2190 ok" : ` \u2190 error: ${truncate7(String(payload.error ?? "unknown"), 80)}`,
88135
+ text: ok ? " \u2190 ok" : ` \u2190 error: ${truncate5(String(payload.error ?? "unknown"), 80)}`,
88297
88136
  ...ok ? {} : { color: Colors.danger }
88298
88137
  });
88299
88138
  continue;
@@ -88301,10 +88140,10 @@ function collectAgents(events) {
88301
88140
  if (e3.subtype === "subagent_completed") {
88302
88141
  agent.completedAtMs = atMs;
88303
88142
  agent.state = payload.error ? "failed" : "done";
88304
- const text = typeof payload.text === "string" ? oneLine4(payload.text) : "";
88143
+ const text = typeof payload.text === "string" ? oneLine2(payload.text) : "";
88305
88144
  agent.activity.push({
88306
88145
  atMs,
88307
- text: `completed \xB7 ${truncate7(text, 100)}`,
88146
+ text: `completed \xB7 ${truncate5(text, 100)}`,
88308
88147
  ...agent.state === "failed" ? { color: Colors.danger } : {}
88309
88148
  });
88310
88149
  continue;
@@ -88323,33 +88162,33 @@ function summarizeArgs2(input) {
88323
88162
  if (input == null)
88324
88163
  return "";
88325
88164
  if (typeof input === "string")
88326
- return truncate7(oneLine4(input), 40);
88165
+ return truncate5(oneLine2(input), 40);
88327
88166
  if (typeof input !== "object")
88328
88167
  return String(input);
88329
88168
  try {
88330
88169
  const entries = Object.entries(input);
88331
88170
  if (entries.length === 0)
88332
88171
  return "";
88333
- return truncate7(oneLine4(entries.map(([k3, v3]) => `${k3}=${stringifyValue(v3)}`).join(", ")), 60);
88172
+ return truncate5(oneLine2(entries.map(([k3, v3]) => `${k3}=${stringifyValue(v3)}`).join(", ")), 60);
88334
88173
  } catch {
88335
88174
  return "[\u2026]";
88336
88175
  }
88337
88176
  }
88338
88177
  function stringifyValue(v3) {
88339
88178
  if (typeof v3 === "string")
88340
- return JSON.stringify(truncate7(oneLine4(v3), 24));
88179
+ return JSON.stringify(truncate5(oneLine2(v3), 24));
88341
88180
  if (typeof v3 === "number" || typeof v3 === "boolean" || v3 === null)
88342
88181
  return String(v3);
88343
88182
  try {
88344
- return truncate7(oneLine4(JSON.stringify(v3)), 24);
88183
+ return truncate5(oneLine2(JSON.stringify(v3)), 24);
88345
88184
  } catch {
88346
88185
  return "[\u2026]";
88347
88186
  }
88348
88187
  }
88349
- function oneLine4(s2) {
88188
+ function oneLine2(s2) {
88350
88189
  return s2.replace(/[\r\n\t]+/g, " ").replace(/ +/g, " ").trim();
88351
88190
  }
88352
- function truncate7(s2, n2) {
88191
+ function truncate5(s2, n2) {
88353
88192
  return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "\u2026";
88354
88193
  }
88355
88194
  var import_jsx_runtime27, import_react55, SUBAGENT_PLUGIN_ID3, WINDOW3, AgentsPanel, KindsList, AgentSummary;
@@ -88398,21 +88237,21 @@ var init_AgentsPanel = __esm({
88398
88237
  const absoluteIndex = scroll.visible.start + i2;
88399
88238
  const focused = absoluteIndex === scroll.cursor;
88400
88239
  const time = new Date(entry.row.atMs).toISOString().slice(11, 19);
88401
- return (0, import_jsx_runtime27.jsxs)(Box_default, { children: [(0, import_jsx_runtime27.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime27.jsx)(Box_default, { width: 10, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: time }) }), (0, import_jsx_runtime27.jsx)(Box_default, { width: labelColWidth, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: truncate7(entry.agent.label, labelColWidth - 1) }) }), (0, import_jsx_runtime27.jsx)(Box_default, { flexGrow: 1, children: (0, import_jsx_runtime27.jsx)(Text, { ...entry.row.color ? { color: entry.row.color } : {}, wrap: "truncate", children: entry.row.text }) })] }, `${entry.agent.childSessionId}:${absoluteIndex}`);
88240
+ return (0, import_jsx_runtime27.jsxs)(Box_default, { children: [(0, import_jsx_runtime27.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime27.jsx)(Box_default, { width: 10, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: time }) }), (0, import_jsx_runtime27.jsx)(Box_default, { width: labelColWidth, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: truncate5(entry.agent.label, labelColWidth - 1) }) }), (0, import_jsx_runtime27.jsx)(Box_default, { flexGrow: 1, children: (0, import_jsx_runtime27.jsx)(Text, { ...entry.row.color ? { color: entry.row.color } : {}, wrap: "truncate", children: entry.row.text }) })] }, `${entry.agent.childSessionId}:${absoluteIndex}`);
88402
88241
  }), scroll.canScrollDown ? (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: ` \u2193 ${rows.length - scroll.visible.end} more below` }) : null] });
88403
88242
  };
88404
88243
  KindsList = ({ kinds }) => {
88405
88244
  const termWidth = process.stdout.columns ?? 80;
88406
88245
  const nameCol = 20;
88407
88246
  const descCol = Math.max(20, termWidth - nameCol - 12);
88408
- return (0, import_jsx_runtime27.jsxs)(Box_default, { flexDirection: "column", children: [(0, import_jsx_runtime27.jsxs)(Box_default, { marginLeft: 2, children: [(0, import_jsx_runtime27.jsx)(Box_default, { width: nameCol, children: (0, import_jsx_runtime27.jsx)(Text, { bold: true, children: "default" }) }), (0, import_jsx_runtime27.jsx)(Box_default, { width: descCol, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, wrap: "truncate", children: "generic tool-use loop (built-in fallback)" }) })] }), kinds.map((k3) => (0, import_jsx_runtime27.jsxs)(Box_default, { marginLeft: 2, children: [(0, import_jsx_runtime27.jsx)(Box_default, { width: nameCol, children: (0, import_jsx_runtime27.jsx)(Text, { bold: true, children: truncate7(k3.name, nameCol - 1) }) }), (0, import_jsx_runtime27.jsx)(Box_default, { width: descCol, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, wrap: "truncate", children: k3.description }) })] }, k3.name)), kinds.length === 0 ? (0, import_jsx_runtime27.jsx)(Box_default, { marginLeft: 2, marginTop: 1, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: "install an agent plugin to add kinds" }) }) : null] });
88247
+ return (0, import_jsx_runtime27.jsxs)(Box_default, { flexDirection: "column", children: [(0, import_jsx_runtime27.jsxs)(Box_default, { marginLeft: 2, children: [(0, import_jsx_runtime27.jsx)(Box_default, { width: nameCol, children: (0, import_jsx_runtime27.jsx)(Text, { bold: true, children: "default" }) }), (0, import_jsx_runtime27.jsx)(Box_default, { width: descCol, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, wrap: "truncate", children: "generic tool-use loop (built-in fallback)" }) })] }), kinds.map((k3) => (0, import_jsx_runtime27.jsxs)(Box_default, { marginLeft: 2, children: [(0, import_jsx_runtime27.jsx)(Box_default, { width: nameCol, children: (0, import_jsx_runtime27.jsx)(Text, { bold: true, children: truncate5(k3.name, nameCol - 1) }) }), (0, import_jsx_runtime27.jsx)(Box_default, { width: descCol, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, wrap: "truncate", children: k3.description }) })] }, k3.name)), kinds.length === 0 ? (0, import_jsx_runtime27.jsx)(Box_default, { marginLeft: 2, marginTop: 1, children: (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: "install an agent plugin to add kinds" }) }) : null] });
88409
88248
  };
88410
88249
  AgentSummary = ({ agent }) => {
88411
88250
  const elapsedMs = (agent.completedAtMs ?? Date.now()) - agent.startedAtMs;
88412
88251
  const elapsed = formatElapsed(elapsedMs);
88413
88252
  const dot = agent.state === "running" ? Colors.busy : agent.state === "failed" ? Colors.danger : "blue";
88414
88253
  const toolCount = agent.activity.filter((r2) => r2.text.startsWith("\u2192 tool ")).length;
88415
- return (0, import_jsx_runtime27.jsxs)(Box_default, { children: [(0, import_jsx_runtime27.jsx)(Text, { color: dot, children: "\u25CF " }), (0, import_jsx_runtime27.jsx)(Box_default, { width: 20, children: (0, import_jsx_runtime27.jsx)(Text, { bold: true, children: truncate7(agent.label, 19) }) }), (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: `${agent.state} ${elapsed} \xB7 ${toolCount} tool call${toolCount === 1 ? "" : "s"}` })] });
88254
+ return (0, import_jsx_runtime27.jsxs)(Box_default, { children: [(0, import_jsx_runtime27.jsx)(Text, { color: dot, children: "\u25CF " }), (0, import_jsx_runtime27.jsx)(Box_default, { width: 20, children: (0, import_jsx_runtime27.jsx)(Text, { bold: true, children: truncate5(agent.label, 19) }) }), (0, import_jsx_runtime27.jsx)(Text, { dimColor: true, children: `${agent.state} ${elapsed} \xB7 ${toolCount} tool call${toolCount === 1 ? "" : "s"}` })] });
88416
88255
  };
88417
88256
  }
88418
88257
  });
@@ -88538,18 +88377,13 @@ var init_UsagePanel = __esm({
88538
88377
  function stepMark(status) {
88539
88378
  return status === "completed" ? "\u2713" : status === "skipped" ? "\u2013" : status === "failed" ? "\u2717" : "\xB7";
88540
88379
  }
88541
- function oneLine5(s2) {
88542
- return s2.replace(/[\r\n\t]+/g, " ").replace(/ +/g, " ").trim();
88543
- }
88544
- function truncate8(s2, n2) {
88545
- return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "\u2026";
88546
- }
88547
88380
  var import_jsx_runtime29, import_react57, NAME_COL3, SCOPE_COL2, TRIG_COL, WINDOW4, WorkflowsPanel;
88548
88381
  var init_WorkflowsPanel = __esm({
88549
88382
  async "../plugin-cli/dist/components/WorkflowsPanel.js"() {
88550
88383
  import_jsx_runtime29 = __toESM(require_jsx_runtime());
88551
88384
  import_react57 = __toESM(require_react());
88552
88385
  await init_build2();
88386
+ init_dist8();
88553
88387
  init_theme();
88554
88388
  await init_Modal();
88555
88389
  await init_useScrollableList();
@@ -88695,8 +88529,8 @@ var init_WorkflowsPanel = __esm({
88695
88529
  return (0, import_jsx_runtime29.jsxs)(Modal, { title: "Workflows", subtitle, hints, ...onClose ? { onClose } : {}, children: [!view ? (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: "(workflows unavailable in this session)" }) : loading ? (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: "loading\u2026" }) : rows.length === 0 ? (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: "(no workflows \u2014 ask the agent to \u201Ccreate a workflow that\u2026\u201D, or scaffold one in chat)" }) : null, scroll.canScrollUp ? (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: ` \u2191 ${scroll.offset} more above` }) : null, slice.map((wf, i2) => {
88696
88530
  const absoluteIndex = scroll.visible.start + i2;
88697
88531
  const focused = absoluteIndex === scroll.cursor;
88698
- return (0, import_jsx_runtime29.jsxs)(Box_default, { children: [(0, import_jsx_runtime29.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime29.jsx)(Text, { color: wf.enabled ? Colors.active : void 0, dimColor: !wf.enabled, children: wf.enabled ? "\u25CF " : "\u25CB " }), (0, import_jsx_runtime29.jsx)(Box_default, { width: NAME_COL3, children: (0, import_jsx_runtime29.jsx)(Text, { bold: focused, children: truncate8(wf.name, NAME_COL3 - 1) }) }), (0, import_jsx_runtime29.jsx)(Box_default, { width: SCOPE_COL2, children: (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: wf.scope }) }), (0, import_jsx_runtime29.jsx)(Box_default, { width: TRIG_COL, children: (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, wrap: "truncate", children: wf.triggers }) }), (0, import_jsx_runtime29.jsx)(Box_default, { width: descWidth, children: (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, wrap: "truncate", children: oneLine5(wf.description) }) })] }, wf.name);
88699
- }), scroll.canScrollDown ? (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: ` \u2193 ${rows.length - scroll.visible.end} more below` }) : null, pending ? (0, import_jsx_runtime29.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: Colors.active, paddingX: 1, children: [(0, import_jsx_runtime29.jsxs)(Text, { color: Colors.active, children: ["\u23F8 Workflow waiting \xB7 ", pending.label] }), pending.prompt ? (0, import_jsx_runtime29.jsx)(Text, { wrap: "wrap", children: oneLine5(pending.prompt).slice(0, 280) }) : null, (0, import_jsx_runtime29.jsxs)(Box_default, { marginTop: 1, children: [(0, import_jsx_runtime29.jsx)(Text, { children: "reply \u203A " }), (0, import_jsx_runtime29.jsx)(Text, { children: reply2 || " " })] }), (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: "Enter send \xB7 Esc cancel" })] }) : null, status ? (0, import_jsx_runtime29.jsx)(Box_default, { marginTop: 1, children: (0, import_jsx_runtime29.jsx)(Text, { wrap: "truncate-end", children: status }) }) : null] });
88532
+ return (0, import_jsx_runtime29.jsxs)(Box_default, { children: [(0, import_jsx_runtime29.jsx)(Text, { ...focused ? {} : { dimColor: true }, children: focused ? "\u203A " : " " }), (0, import_jsx_runtime29.jsx)(Text, { color: wf.enabled ? Colors.active : void 0, dimColor: !wf.enabled, children: wf.enabled ? "\u25CF " : "\u25CB " }), (0, import_jsx_runtime29.jsx)(Box_default, { width: NAME_COL3, children: (0, import_jsx_runtime29.jsx)(Text, { bold: focused, children: truncate3(wf.name, NAME_COL3 - 2) }) }), (0, import_jsx_runtime29.jsx)(Box_default, { width: SCOPE_COL2, children: (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: wf.scope }) }), (0, import_jsx_runtime29.jsx)(Box_default, { width: TRIG_COL, children: (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, wrap: "truncate", children: wf.triggers }) }), (0, import_jsx_runtime29.jsx)(Box_default, { width: descWidth, children: (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, wrap: "truncate", children: oneLine(wf.description) }) })] }, wf.name);
88533
+ }), scroll.canScrollDown ? (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: ` \u2193 ${rows.length - scroll.visible.end} more below` }) : null, pending ? (0, import_jsx_runtime29.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, borderStyle: "round", borderColor: Colors.active, paddingX: 1, children: [(0, import_jsx_runtime29.jsxs)(Text, { color: Colors.active, children: ["\u23F8 Workflow waiting \xB7 ", pending.label] }), pending.prompt ? (0, import_jsx_runtime29.jsx)(Text, { wrap: "wrap", children: oneLine(pending.prompt).slice(0, 280) }) : null, (0, import_jsx_runtime29.jsxs)(Box_default, { marginTop: 1, children: [(0, import_jsx_runtime29.jsx)(Text, { children: "reply \u203A " }), (0, import_jsx_runtime29.jsx)(Text, { children: reply2 || " " })] }), (0, import_jsx_runtime29.jsx)(Text, { dimColor: true, children: "Enter send \xB7 Esc cancel" })] }) : null, status ? (0, import_jsx_runtime29.jsx)(Box_default, { marginTop: 1, children: (0, import_jsx_runtime29.jsx)(Text, { wrap: "truncate-end", children: status }) }) : null] });
88700
88534
  };
88701
88535
  }
88702
88536
  });
@@ -89369,9 +89203,9 @@ var init_SessionView = __esm({
89369
89203
  }, onApprovalDecide: (decision) => {
89370
89204
  if (!pendingApproval)
89371
89205
  return;
89372
- const { resolve: resolve12 } = pendingApproval;
89206
+ const { resolve: resolve13 } = pendingApproval;
89373
89207
  permissions.setPendingApproval(null);
89374
- resolve12(decision);
89208
+ resolve13(decision);
89375
89209
  }, onPickerSelect: handlePickerSelect, onPickerCancel: () => setPicker(null), onSubmit: handleSubmit, onPasteText: images.handlePasteText }), (0, import_jsx_runtime36.jsx)(StatusLine, { busyStartedAt: turn.busy && !pendingPermission && !pendingApproval ? turn.busyStartedAt : null, queueCount: turn.queueCount, modeName, modeBadge, provider: providerName2, model: activeModel2, mcp: mcpStatus, contextUsed, ...contextWindow ? { contextWindow } : {}, ...version ? { version } : {}, ...updateAvailable ? { updateLatest: updateAvailable.latest } : {} })] });
89376
89210
  };
89377
89211
  }
@@ -94154,10 +93988,10 @@ var require_browser2 = __commonJS({
94154
93988
  text = canvas;
94155
93989
  canvas = void 0;
94156
93990
  }
94157
- return new Promise(function(resolve12, reject) {
93991
+ return new Promise(function(resolve13, reject) {
94158
93992
  try {
94159
93993
  const data = QRCode2.create(text, opts);
94160
- resolve12(renderFunc(data, canvas, opts));
93994
+ resolve13(renderFunc(data, canvas, opts));
94161
93995
  } catch (e3) {
94162
93996
  reject(e3);
94163
93997
  }
@@ -94238,11 +94072,11 @@ var require_server = __commonJS({
94238
94072
  }
94239
94073
  function render2(renderFunc, text, params) {
94240
94074
  if (!params.cb) {
94241
- return new Promise(function(resolve12, reject) {
94075
+ return new Promise(function(resolve13, reject) {
94242
94076
  try {
94243
94077
  const data = QRCode2.create(text, params.opts);
94244
94078
  return renderFunc(data, params.opts, function(err, data2) {
94245
- return err ? reject(err) : resolve12(data2);
94079
+ return err ? reject(err) : resolve13(data2);
94246
94080
  });
94247
94081
  } catch (e3) {
94248
94082
  reject(e3);
@@ -96114,9 +95948,9 @@ var require_dispatcher_base = __commonJS({
96114
95948
  }
96115
95949
  close(callback) {
96116
95950
  if (callback === void 0) {
96117
- return new Promise((resolve12, reject) => {
95951
+ return new Promise((resolve13, reject) => {
96118
95952
  this.close((err, data) => {
96119
- return err ? reject(err) : resolve12(data);
95953
+ return err ? reject(err) : resolve13(data);
96120
95954
  });
96121
95955
  });
96122
95956
  }
@@ -96154,12 +95988,12 @@ var require_dispatcher_base = __commonJS({
96154
95988
  err = null;
96155
95989
  }
96156
95990
  if (callback === void 0) {
96157
- return new Promise((resolve12, reject) => {
95991
+ return new Promise((resolve13, reject) => {
96158
95992
  this.destroy(err, (err2, data) => {
96159
95993
  return err2 ? (
96160
95994
  /* istanbul ignore next: should never error */
96161
95995
  reject(err2)
96162
- ) : resolve12(data);
95996
+ ) : resolve13(data);
96163
95997
  });
96164
95998
  });
96165
95999
  }
@@ -98409,8 +98243,8 @@ var require_util3 = __commonJS({
98409
98243
  function createDeferredPromise() {
98410
98244
  let res;
98411
98245
  let rej;
98412
- const promise = new Promise((resolve12, reject) => {
98413
- res = resolve12;
98246
+ const promise = new Promise((resolve13, reject) => {
98247
+ res = resolve13;
98414
98248
  rej = reject;
98415
98249
  });
98416
98250
  return { promise, resolve: res, reject: rej };
@@ -100582,12 +100416,12 @@ upgrade: ${upgrade}\r
100582
100416
  cb();
100583
100417
  }
100584
100418
  }
100585
- const waitForDrain = () => new Promise((resolve12, reject) => {
100419
+ const waitForDrain = () => new Promise((resolve13, reject) => {
100586
100420
  assert(callback === null);
100587
100421
  if (socket[kError]) {
100588
100422
  reject(socket[kError]);
100589
100423
  } else {
100590
- callback = resolve12;
100424
+ callback = resolve13;
100591
100425
  }
100592
100426
  });
100593
100427
  socket.on("close", onDrain).on("drain", onDrain);
@@ -101223,12 +101057,12 @@ var require_client_h2 = __commonJS({
101223
101057
  cb();
101224
101058
  }
101225
101059
  }
101226
- const waitForDrain = () => new Promise((resolve12, reject) => {
101060
+ const waitForDrain = () => new Promise((resolve13, reject) => {
101227
101061
  assert(callback === null);
101228
101062
  if (socket[kError]) {
101229
101063
  reject(socket[kError]);
101230
101064
  } else {
101231
- callback = resolve12;
101065
+ callback = resolve13;
101232
101066
  }
101233
101067
  });
101234
101068
  h2stream.on("close", onDrain).on("drain", onDrain);
@@ -101701,16 +101535,16 @@ var require_client2 = __commonJS({
101701
101535
  return this[kNeedDrain] < 2;
101702
101536
  }
101703
101537
  async [kClose]() {
101704
- return new Promise((resolve12) => {
101538
+ return new Promise((resolve13) => {
101705
101539
  if (this[kSize]) {
101706
- this[kClosedResolve] = resolve12;
101540
+ this[kClosedResolve] = resolve13;
101707
101541
  } else {
101708
- resolve12(null);
101542
+ resolve13(null);
101709
101543
  }
101710
101544
  });
101711
101545
  }
101712
101546
  async [kDestroy](err) {
101713
- return new Promise((resolve12) => {
101547
+ return new Promise((resolve13) => {
101714
101548
  const requests = this[kQueue].splice(this[kPendingIdx]);
101715
101549
  for (let i2 = 0; i2 < requests.length; i2++) {
101716
101550
  const request = requests[i2];
@@ -101721,7 +101555,7 @@ var require_client2 = __commonJS({
101721
101555
  this[kClosedResolve]();
101722
101556
  this[kClosedResolve] = null;
101723
101557
  }
101724
- resolve12(null);
101558
+ resolve13(null);
101725
101559
  };
101726
101560
  if (this[kHTTPContext]) {
101727
101561
  this[kHTTPContext].destroy(err, callback);
@@ -101772,7 +101606,7 @@ var require_client2 = __commonJS({
101772
101606
  });
101773
101607
  }
101774
101608
  try {
101775
- const socket = await new Promise((resolve12, reject) => {
101609
+ const socket = await new Promise((resolve13, reject) => {
101776
101610
  client[kConnector]({
101777
101611
  host,
101778
101612
  hostname,
@@ -101784,7 +101618,7 @@ var require_client2 = __commonJS({
101784
101618
  if (err) {
101785
101619
  reject(err);
101786
101620
  } else {
101787
- resolve12(socket2);
101621
+ resolve13(socket2);
101788
101622
  }
101789
101623
  });
101790
101624
  });
@@ -102118,8 +101952,8 @@ var require_pool_base = __commonJS({
102118
101952
  if (this[kQueue].isEmpty()) {
102119
101953
  await Promise.all(this[kClients].map((c2) => c2.close()));
102120
101954
  } else {
102121
- await new Promise((resolve12) => {
102122
- this[kClosedResolve] = resolve12;
101955
+ await new Promise((resolve13) => {
101956
+ this[kClosedResolve] = resolve13;
102123
101957
  });
102124
101958
  }
102125
101959
  }
@@ -103326,7 +103160,7 @@ var require_readable = __commonJS({
103326
103160
  if (this._readableState.closeEmitted) {
103327
103161
  return null;
103328
103162
  }
103329
- return await new Promise((resolve12, reject) => {
103163
+ return await new Promise((resolve13, reject) => {
103330
103164
  if (this[kContentLength] > limit2) {
103331
103165
  this.destroy(new AbortError2());
103332
103166
  }
@@ -103339,7 +103173,7 @@ var require_readable = __commonJS({
103339
103173
  if (signal?.aborted) {
103340
103174
  reject(signal.reason ?? new AbortError2());
103341
103175
  } else {
103342
- resolve12(null);
103176
+ resolve13(null);
103343
103177
  }
103344
103178
  }).on("error", noop3).on("data", function(chunk) {
103345
103179
  limit2 -= chunk.length;
@@ -103358,7 +103192,7 @@ var require_readable = __commonJS({
103358
103192
  }
103359
103193
  async function consume(stream, type) {
103360
103194
  assert(!stream[kConsume]);
103361
- return new Promise((resolve12, reject) => {
103195
+ return new Promise((resolve13, reject) => {
103362
103196
  if (isUnusable(stream)) {
103363
103197
  const rState = stream._readableState;
103364
103198
  if (rState.destroyed && rState.closeEmitted === false) {
@@ -103375,7 +103209,7 @@ var require_readable = __commonJS({
103375
103209
  stream[kConsume] = {
103376
103210
  type,
103377
103211
  stream,
103378
- resolve: resolve12,
103212
+ resolve: resolve13,
103379
103213
  reject,
103380
103214
  length: 0,
103381
103215
  body: []
@@ -103445,18 +103279,18 @@ var require_readable = __commonJS({
103445
103279
  return buffer;
103446
103280
  }
103447
103281
  function consumeEnd(consume2) {
103448
- const { type, body, resolve: resolve12, stream, length } = consume2;
103282
+ const { type, body, resolve: resolve13, stream, length } = consume2;
103449
103283
  try {
103450
103284
  if (type === "text") {
103451
- resolve12(chunksDecode(body, length));
103285
+ resolve13(chunksDecode(body, length));
103452
103286
  } else if (type === "json") {
103453
- resolve12(JSON.parse(chunksDecode(body, length)));
103287
+ resolve13(JSON.parse(chunksDecode(body, length)));
103454
103288
  } else if (type === "arrayBuffer") {
103455
- resolve12(chunksConcat(body, length).buffer);
103289
+ resolve13(chunksConcat(body, length).buffer);
103456
103290
  } else if (type === "blob") {
103457
- resolve12(new Blob(body, { type: stream[kContentType] }));
103291
+ resolve13(new Blob(body, { type: stream[kContentType] }));
103458
103292
  } else if (type === "bytes") {
103459
- resolve12(chunksConcat(body, length));
103293
+ resolve13(chunksConcat(body, length));
103460
103294
  }
103461
103295
  consumeFinish(consume2);
103462
103296
  } catch (err) {
@@ -103712,9 +103546,9 @@ var require_api_request = __commonJS({
103712
103546
  };
103713
103547
  function request(opts, callback) {
103714
103548
  if (callback === void 0) {
103715
- return new Promise((resolve12, reject) => {
103549
+ return new Promise((resolve13, reject) => {
103716
103550
  request.call(this, opts, (err, data) => {
103717
- return err ? reject(err) : resolve12(data);
103551
+ return err ? reject(err) : resolve13(data);
103718
103552
  });
103719
103553
  });
103720
103554
  }
@@ -103936,9 +103770,9 @@ var require_api_stream = __commonJS({
103936
103770
  };
103937
103771
  function stream(opts, factory2, callback) {
103938
103772
  if (callback === void 0) {
103939
- return new Promise((resolve12, reject) => {
103773
+ return new Promise((resolve13, reject) => {
103940
103774
  stream.call(this, opts, factory2, (err, data) => {
103941
- return err ? reject(err) : resolve12(data);
103775
+ return err ? reject(err) : resolve13(data);
103942
103776
  });
103943
103777
  });
103944
103778
  }
@@ -104221,9 +104055,9 @@ var require_api_upgrade = __commonJS({
104221
104055
  };
104222
104056
  function upgrade(opts, callback) {
104223
104057
  if (callback === void 0) {
104224
- return new Promise((resolve12, reject) => {
104058
+ return new Promise((resolve13, reject) => {
104225
104059
  upgrade.call(this, opts, (err, data) => {
104226
- return err ? reject(err) : resolve12(data);
104060
+ return err ? reject(err) : resolve13(data);
104227
104061
  });
104228
104062
  });
104229
104063
  }
@@ -104314,9 +104148,9 @@ var require_api_connect = __commonJS({
104314
104148
  };
104315
104149
  function connect(opts, callback) {
104316
104150
  if (callback === void 0) {
104317
- return new Promise((resolve12, reject) => {
104151
+ return new Promise((resolve13, reject) => {
104318
104152
  connect.call(this, opts, (err, data) => {
104319
- return err ? reject(err) : resolve12(data);
104153
+ return err ? reject(err) : resolve13(data);
104320
104154
  });
104321
104155
  });
104322
104156
  }
@@ -108138,7 +107972,7 @@ var require_fetch = __commonJS({
108138
107972
  function dispatch3({ body }) {
108139
107973
  const url2 = requestCurrentURL(request);
108140
107974
  const agent = fetchParams.controller.dispatcher;
108141
- return new Promise((resolve12, reject) => agent.dispatch(
107975
+ return new Promise((resolve13, reject) => agent.dispatch(
108142
107976
  {
108143
107977
  path: url2.pathname + url2.search,
108144
107978
  origin: url2.origin,
@@ -108214,7 +108048,7 @@ var require_fetch = __commonJS({
108214
108048
  }
108215
108049
  }
108216
108050
  const onError2 = this.onError.bind(this);
108217
- resolve12({
108051
+ resolve13({
108218
108052
  status,
108219
108053
  statusText,
108220
108054
  headersList,
@@ -108260,7 +108094,7 @@ var require_fetch = __commonJS({
108260
108094
  for (let i2 = 0; i2 < rawHeaders.length; i2 += 2) {
108261
108095
  headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i2]), rawHeaders[i2 + 1].toString("latin1"), true);
108262
108096
  }
108263
- resolve12({
108097
+ resolve13({
108264
108098
  status,
108265
108099
  statusText: STATUS_CODES2[status],
108266
108100
  headersList,
@@ -111911,8 +111745,8 @@ var require_util9 = __commonJS({
111911
111745
  return true;
111912
111746
  }
111913
111747
  function delay(ms) {
111914
- return new Promise((resolve12) => {
111915
- setTimeout(resolve12, ms).unref();
111748
+ return new Promise((resolve13) => {
111749
+ setTimeout(resolve13, ms).unref();
111916
111750
  });
111917
111751
  }
111918
111752
  module.exports = {
@@ -112860,7 +112694,7 @@ function classify(input, signals) {
112860
112694
  }
112861
112695
  var CMD_TIMEOUT_MS = 5 * 6e4;
112862
112696
  function runCmd(cmd, args, cwd2) {
112863
- return new Promise((resolve12) => {
112697
+ return new Promise((resolve13) => {
112864
112698
  const child = spawn(cmd, [...args], { cwd: cwd2, stdio: ["ignore", "pipe", "pipe"] });
112865
112699
  let output = "";
112866
112700
  const onData = (d2) => {
@@ -112871,11 +112705,11 @@ function runCmd(cmd, args, cwd2) {
112871
112705
  const timer = setTimeout(() => child.kill("SIGKILL"), CMD_TIMEOUT_MS);
112872
112706
  child.on("error", (err) => {
112873
112707
  clearTimeout(timer);
112874
- resolve12({ exitCode: -1, output: `${cmd} failed to start: ${err.message}` });
112708
+ resolve13({ exitCode: -1, output: `${cmd} failed to start: ${err.message}` });
112875
112709
  });
112876
112710
  child.on("close", (code) => {
112877
112711
  clearTimeout(timer);
112878
- resolve12({ exitCode: code ?? -1, output });
112712
+ resolve13({ exitCode: code ?? -1, output });
112879
112713
  });
112880
112714
  });
112881
112715
  }
@@ -112956,7 +112790,7 @@ function shortName(pkg) {
112956
112790
  return pkg.startsWith(SCOPE) ? pkg.slice(SCOPE.length) : pkg;
112957
112791
  }
112958
112792
  function run(cmd, args, cwd2, timeoutMs = BUILD_TIMEOUT_MS) {
112959
- return new Promise((resolve12) => {
112793
+ return new Promise((resolve13) => {
112960
112794
  const child = spawn(cmd, [...args], { cwd: cwd2, stdio: ["ignore", "pipe", "pipe"] });
112961
112795
  let output = "";
112962
112796
  const onData = (d2) => {
@@ -112967,11 +112801,11 @@ function run(cmd, args, cwd2, timeoutMs = BUILD_TIMEOUT_MS) {
112967
112801
  const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
112968
112802
  child.on("error", (err) => {
112969
112803
  clearTimeout(timer);
112970
- resolve12({ code: -1, output: `${cmd} failed to start: ${err.message}` });
112804
+ resolve13({ code: -1, output: `${cmd} failed to start: ${err.message}` });
112971
112805
  });
112972
112806
  child.on("close", (code) => {
112973
112807
  clearTimeout(timer);
112974
- resolve12({ code: code ?? -1, output });
112808
+ resolve13({ code: code ?? -1, output });
112975
112809
  });
112976
112810
  });
112977
112811
  }
@@ -114080,6 +113914,7 @@ function parseValue(raw) {
114080
113914
  function buildConfigPlugin(opts = { cwd: process.cwd() }) {
114081
113915
  const cwd2 = opts.cwd;
114082
113916
  const applier = opts.applier;
113917
+ const writeMutex4 = createMutex();
114083
113918
  return definePlugin({
114084
113919
  name: "@moxxy/plugin-config",
114085
113920
  version: "0.0.0",
@@ -114135,7 +113970,7 @@ function buildConfigPlugin(opts = { cwd: process.cwd() }) {
114135
113970
  value: z$1.string()
114136
113971
  }),
114137
113972
  permission: { action: "prompt" },
114138
- handler: async ({ scope, path: dotPath, value }) => {
113973
+ handler: async ({ scope, path: dotPath, value }) => writeMutex4.run(async () => {
114139
113974
  const target = await findScopePath(scope, cwd2) ?? scopeDefaultPath(scope, cwd2);
114140
113975
  await promises.mkdir(path3.dirname(target), { recursive: true });
114141
113976
  const { doc, text } = await readDoc(target);
@@ -114168,7 +114003,7 @@ function buildConfigPlugin(opts = { cwd: process.cwd() }) {
114168
114003
  newSize: candidate.length,
114169
114004
  runtime
114170
114005
  };
114171
- }
114006
+ })
114172
114007
  }),
114173
114008
  defineTool({
114174
114009
  name: "config_reload",
@@ -114187,7 +114022,7 @@ function buildConfigPlugin(opts = { cwd: process.cwd() }) {
114187
114022
  description: "Create a starter moxxy config file at the given scope (yaml format), if one does not already exist.",
114188
114023
  inputSchema: z$1.object({ scope: scopeSchema }),
114189
114024
  permission: { action: "prompt" },
114190
- handler: async ({ scope }) => {
114025
+ handler: async ({ scope }) => writeMutex4.run(async () => {
114191
114026
  const existing = await findScopePath(scope, cwd2);
114192
114027
  if (existing)
114193
114028
  return { path: existing, created: false };
@@ -114202,7 +114037,7 @@ mode: default
114202
114037
  `;
114203
114038
  await writeFileAtomic(target, template);
114204
114039
  return { path: target, created: true };
114205
- }
114040
+ })
114206
114041
  }),
114207
114042
  defineTool({
114208
114043
  name: "config_validate",
@@ -117100,8 +116935,8 @@ function _addRequestID(value, response) {
117100
116935
  }
117101
116936
  var APIPromise = class _APIPromise extends Promise {
117102
116937
  constructor(responsePromise, parseResponse2 = defaultParseResponse) {
117103
- super((resolve12) => {
117104
- resolve12(null);
116938
+ super((resolve13) => {
116939
+ resolve13(null);
117105
116940
  });
117106
116941
  this.responsePromise = responsePromise;
117107
116942
  this.parseResponse = parseResponse2;
@@ -117693,7 +117528,7 @@ var startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
117693
117528
  var isAbsoluteURL = (url2) => {
117694
117529
  return startsWithSchemeRegexp.test(url2);
117695
117530
  };
117696
- var sleep = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
117531
+ var sleep = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
117697
117532
  var validatePositiveInteger = (name, n2) => {
117698
117533
  if (typeof n2 !== "number" || !Number.isInteger(n2)) {
117699
117534
  throw new AnthropicError(`${name} must be an integer`);
@@ -118303,12 +118138,12 @@ var BetaMessageStream = class _BetaMessageStream {
118303
118138
  }
118304
118139
  return this._emit("error", new AnthropicError(String(error2)));
118305
118140
  });
118306
- __classPrivateFieldSet7(this, _BetaMessageStream_connectedPromise, new Promise((resolve12, reject) => {
118307
- __classPrivateFieldSet7(this, _BetaMessageStream_resolveConnectedPromise, resolve12, "f");
118141
+ __classPrivateFieldSet7(this, _BetaMessageStream_connectedPromise, new Promise((resolve13, reject) => {
118142
+ __classPrivateFieldSet7(this, _BetaMessageStream_resolveConnectedPromise, resolve13, "f");
118308
118143
  __classPrivateFieldSet7(this, _BetaMessageStream_rejectConnectedPromise, reject, "f");
118309
118144
  }));
118310
- __classPrivateFieldSet7(this, _BetaMessageStream_endPromise, new Promise((resolve12, reject) => {
118311
- __classPrivateFieldSet7(this, _BetaMessageStream_resolveEndPromise, resolve12, "f");
118145
+ __classPrivateFieldSet7(this, _BetaMessageStream_endPromise, new Promise((resolve13, reject) => {
118146
+ __classPrivateFieldSet7(this, _BetaMessageStream_resolveEndPromise, resolve13, "f");
118312
118147
  __classPrivateFieldSet7(this, _BetaMessageStream_rejectEndPromise, reject, "f");
118313
118148
  }));
118314
118149
  __classPrivateFieldGet8(this, _BetaMessageStream_connectedPromise, "f").catch(() => {
@@ -118466,11 +118301,11 @@ var BetaMessageStream = class _BetaMessageStream {
118466
118301
  * const message = await stream.emitted('message') // rejects if the stream errors
118467
118302
  */
118468
118303
  emitted(event) {
118469
- return new Promise((resolve12, reject) => {
118304
+ return new Promise((resolve13, reject) => {
118470
118305
  __classPrivateFieldSet7(this, _BetaMessageStream_catchingPromiseCreated, true);
118471
118306
  if (event !== "error")
118472
118307
  this.once("error", reject);
118473
- this.once(event, resolve12);
118308
+ this.once(event, resolve13);
118474
118309
  });
118475
118310
  }
118476
118311
  async done() {
@@ -118751,7 +118586,7 @@ var BetaMessageStream = class _BetaMessageStream {
118751
118586
  if (done) {
118752
118587
  return { value: void 0, done: true };
118753
118588
  }
118754
- return new Promise((resolve12, reject) => readQueue.push({ resolve: resolve12, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
118589
+ return new Promise((resolve13, reject) => readQueue.push({ resolve: resolve13, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
118755
118590
  }
118756
118591
  const chunk = pushQueue.shift();
118757
118592
  return { value: chunk, done: false };
@@ -119023,12 +118858,12 @@ var MessageStream = class _MessageStream {
119023
118858
  }
119024
118859
  return this._emit("error", new AnthropicError(String(error2)));
119025
118860
  });
119026
- __classPrivateFieldSet8(this, _MessageStream_connectedPromise, new Promise((resolve12, reject) => {
119027
- __classPrivateFieldSet8(this, _MessageStream_resolveConnectedPromise, resolve12, "f");
118861
+ __classPrivateFieldSet8(this, _MessageStream_connectedPromise, new Promise((resolve13, reject) => {
118862
+ __classPrivateFieldSet8(this, _MessageStream_resolveConnectedPromise, resolve13, "f");
119028
118863
  __classPrivateFieldSet8(this, _MessageStream_rejectConnectedPromise, reject, "f");
119029
118864
  }));
119030
- __classPrivateFieldSet8(this, _MessageStream_endPromise, new Promise((resolve12, reject) => {
119031
- __classPrivateFieldSet8(this, _MessageStream_resolveEndPromise, resolve12, "f");
118865
+ __classPrivateFieldSet8(this, _MessageStream_endPromise, new Promise((resolve13, reject) => {
118866
+ __classPrivateFieldSet8(this, _MessageStream_resolveEndPromise, resolve13, "f");
119032
118867
  __classPrivateFieldSet8(this, _MessageStream_rejectEndPromise, reject, "f");
119033
118868
  }));
119034
118869
  __classPrivateFieldGet9(this, _MessageStream_connectedPromise, "f").catch(() => {
@@ -119186,11 +119021,11 @@ var MessageStream = class _MessageStream {
119186
119021
  * const message = await stream.emitted('message') // rejects if the stream errors
119187
119022
  */
119188
119023
  emitted(event) {
119189
- return new Promise((resolve12, reject) => {
119024
+ return new Promise((resolve13, reject) => {
119190
119025
  __classPrivateFieldSet8(this, _MessageStream_catchingPromiseCreated, true);
119191
119026
  if (event !== "error")
119192
119027
  this.once("error", reject);
119193
- this.once(event, resolve12);
119028
+ this.once(event, resolve13);
119194
119029
  });
119195
119030
  }
119196
119031
  async done() {
@@ -119471,7 +119306,7 @@ var MessageStream = class _MessageStream {
119471
119306
  if (done) {
119472
119307
  return { value: void 0, done: true };
119473
119308
  }
119474
- return new Promise((resolve12, reject) => readQueue.push({ resolve: resolve12, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
119309
+ return new Promise((resolve13, reject) => readQueue.push({ resolve: resolve13, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
119475
119310
  }
119476
119311
  const chunk = pushQueue.shift();
119477
119312
  return { value: chunk, done: false };
@@ -121254,8 +121089,8 @@ function _addRequestID2(value, response) {
121254
121089
  }
121255
121090
  var APIPromise2 = class _APIPromise extends Promise {
121256
121091
  constructor(responsePromise, parseResponse2 = defaultParseResponse2) {
121257
- super((resolve12) => {
121258
- resolve12(null);
121092
+ super((resolve13) => {
121093
+ resolve13(null);
121259
121094
  });
121260
121095
  this.responsePromise = responsePromise;
121261
121096
  this.parseResponse = parseResponse2;
@@ -121830,7 +121665,7 @@ var startsWithSchemeRegexp2 = /^[a-z][a-z0-9+.-]*:/i;
121830
121665
  var isAbsoluteURL2 = (url2) => {
121831
121666
  return startsWithSchemeRegexp2.test(url2);
121832
121667
  };
121833
- var sleep2 = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
121668
+ var sleep2 = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
121834
121669
  var validatePositiveInteger2 = (name, n2) => {
121835
121670
  if (typeof n2 !== "number" || !Number.isInteger(n2)) {
121836
121671
  throw new OpenAIError(`${name} must be an integer`);
@@ -122261,12 +122096,12 @@ var EventStream = class {
122261
122096
  _EventStream_errored.set(this, false);
122262
122097
  _EventStream_aborted.set(this, false);
122263
122098
  _EventStream_catchingPromiseCreated.set(this, false);
122264
- __classPrivateFieldSet11(this, _EventStream_connectedPromise, new Promise((resolve12, reject) => {
122265
- __classPrivateFieldSet11(this, _EventStream_resolveConnectedPromise, resolve12, "f");
122099
+ __classPrivateFieldSet11(this, _EventStream_connectedPromise, new Promise((resolve13, reject) => {
122100
+ __classPrivateFieldSet11(this, _EventStream_resolveConnectedPromise, resolve13, "f");
122266
122101
  __classPrivateFieldSet11(this, _EventStream_rejectConnectedPromise, reject, "f");
122267
122102
  }));
122268
- __classPrivateFieldSet11(this, _EventStream_endPromise, new Promise((resolve12, reject) => {
122269
- __classPrivateFieldSet11(this, _EventStream_resolveEndPromise, resolve12, "f");
122103
+ __classPrivateFieldSet11(this, _EventStream_endPromise, new Promise((resolve13, reject) => {
122104
+ __classPrivateFieldSet11(this, _EventStream_resolveEndPromise, resolve13, "f");
122270
122105
  __classPrivateFieldSet11(this, _EventStream_rejectEndPromise, reject, "f");
122271
122106
  }));
122272
122107
  __classPrivateFieldGet12(this, _EventStream_connectedPromise, "f").catch(() => {
@@ -122350,11 +122185,11 @@ var EventStream = class {
122350
122185
  * const message = await stream.emitted('message') // rejects if the stream errors
122351
122186
  */
122352
122187
  emitted(event) {
122353
- return new Promise((resolve12, reject) => {
122188
+ return new Promise((resolve13, reject) => {
122354
122189
  __classPrivateFieldSet11(this, _EventStream_catchingPromiseCreated, true);
122355
122190
  if (event !== "error")
122356
122191
  this.once("error", reject);
122357
- this.once(event, resolve12);
122192
+ this.once(event, resolve13);
122358
122193
  });
122359
122194
  }
122360
122195
  async done() {
@@ -122505,7 +122340,7 @@ var AssistantStream = class _AssistantStream extends EventStream {
122505
122340
  if (done) {
122506
122341
  return { value: void 0, done: true };
122507
122342
  }
122508
- return new Promise((resolve12, reject) => readQueue.push({ resolve: resolve12, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
122343
+ return new Promise((resolve13, reject) => readQueue.push({ resolve: resolve13, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
122509
122344
  }
122510
122345
  const chunk = pushQueue.shift();
122511
122346
  return { value: chunk, done: false };
@@ -123909,7 +123744,7 @@ var ChatCompletionStream = class _ChatCompletionStream extends AbstractChatCompl
123909
123744
  arguments_delta: toolCallDelta.function?.arguments ?? ""
123910
123745
  });
123911
123746
  } else {
123912
- assertNever2(toolCallSnapshot?.type);
123747
+ assertNever3(toolCallSnapshot?.type);
123913
123748
  }
123914
123749
  }
123915
123750
  }
@@ -123934,7 +123769,7 @@ var ChatCompletionStream = class _ChatCompletionStream extends AbstractChatCompl
123934
123769
  parsed_arguments: isAutoParsableTool(inputTool) ? inputTool.$parseRaw(toolCallSnapshot.function.arguments) : inputTool?.function.strict ? JSON.parse(toolCallSnapshot.function.arguments) : null
123935
123770
  });
123936
123771
  } else {
123937
- assertNever2(toolCallSnapshot.type);
123772
+ assertNever3(toolCallSnapshot.type);
123938
123773
  }
123939
123774
  }, _ChatCompletionStream_emitContentDoneEvents = function _ChatCompletionStream_emitContentDoneEvents2(choiceSnapshot) {
123940
123775
  const state = __classPrivateFieldGet15(this, _ChatCompletionStream_instances, "m", _ChatCompletionStream_getChoiceEventState).call(this, choiceSnapshot);
@@ -124110,7 +123945,7 @@ var ChatCompletionStream = class _ChatCompletionStream extends AbstractChatCompl
124110
123945
  if (done) {
124111
123946
  return { value: void 0, done: true };
124112
123947
  }
124113
- return new Promise((resolve12, reject) => readQueue.push({ resolve: resolve12, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
123948
+ return new Promise((resolve13, reject) => readQueue.push({ resolve: resolve13, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });
124114
123949
  }
124115
123950
  const chunk = pushQueue.shift();
124116
123951
  return { value: chunk, done: false };
@@ -124214,7 +124049,7 @@ ${str(snapshot)}`);
124214
124049
  function str(x4) {
124215
124050
  return JSON.stringify(x4);
124216
124051
  }
124217
- function assertNever2(_x) {
124052
+ function assertNever3(_x) {
124218
124053
  }
124219
124054
 
124220
124055
  // ../../node_modules/.pnpm/openai@4.104.0_encoding@0.1.13_ws@8.20.0_zod@3.25.76/node_modules/openai/lib/ChatCompletionStreamingRunner.mjs
@@ -125756,7 +125591,7 @@ var ResponseStream = class _ResponseStream extends EventStream {
125756
125591
  if (done) {
125757
125592
  return { value: void 0, done: true };
125758
125593
  }
125759
- return new Promise((resolve12, reject) => readQueue.push({ resolve: resolve12, reject })).then((event2) => event2 ? { value: event2, done: false } : { value: void 0, done: true });
125594
+ return new Promise((resolve13, reject) => readQueue.push({ resolve: resolve13, reject })).then((event2) => event2 ? { value: event2, done: false } : { value: void 0, done: true });
125760
125595
  }
125761
125596
  const event = pushQueue.shift();
125762
125597
  return { value: event, done: false };
@@ -126670,6 +126505,34 @@ async function validateKey2(key, deps = {}) {
126670
126505
  function defaultMaker2(apiKey, baseURL) {
126671
126506
  return new openai_default({ apiKey, ...baseURL ? { baseURL } : {} });
126672
126507
  }
126508
+ function pickOpenAICompatConfig(config) {
126509
+ const str2 = (v3) => typeof v3 === "string" ? v3 : void 0;
126510
+ return {
126511
+ apiKey: str2(config.apiKey),
126512
+ baseURL: str2(config.baseURL),
126513
+ defaultModel: str2(config.defaultModel)
126514
+ };
126515
+ }
126516
+ function defineOpenAICompatProvider(spec) {
126517
+ const resolveApiKey = spec.resolveApiKey ?? ((cfg) => cfg.apiKey);
126518
+ const resolveBaseURL = spec.resolveBaseURL ?? ((cfg) => cfg.baseURL ?? spec.baseURL);
126519
+ return defineProvider({
126520
+ name: spec.name,
126521
+ models: [...spec.models],
126522
+ createClient: (config) => {
126523
+ const cfg = pickOpenAICompatConfig(config);
126524
+ return new OpenAIProvider({
126525
+ apiKey: resolveApiKey(cfg),
126526
+ name: spec.name,
126527
+ baseURL: resolveBaseURL(cfg),
126528
+ defaultModel: cfg.defaultModel ?? spec.defaultModel,
126529
+ models: spec.models
126530
+ });
126531
+ },
126532
+ ...spec.validate === false ? {} : { validateKey: (key) => validateKey2(key, { baseURL: spec.baseURL }) },
126533
+ ...spec.auth ? { auth: spec.auth } : {}
126534
+ });
126535
+ }
126673
126536
 
126674
126537
  // ../plugin-provider-openai/dist/index.js
126675
126538
  var openaiProviderDef = defineProvider({
@@ -126688,7 +126551,7 @@ var openaiPlugin = definePlugin({
126688
126551
  init_pkce();
126689
126552
  async function openInBrowser(url2) {
126690
126553
  const { cmd, args, verbatim } = browserOpenCommand(url2);
126691
- await new Promise((resolve12, reject) => {
126554
+ await new Promise((resolve13, reject) => {
126692
126555
  const child = spawn(cmd, args, {
126693
126556
  stdio: "ignore",
126694
126557
  detached: true,
@@ -126698,7 +126561,7 @@ async function openInBrowser(url2) {
126698
126561
  });
126699
126562
  child.once("error", reject);
126700
126563
  child.unref();
126701
- setTimeout(resolve12, 50);
126564
+ setTimeout(resolve13, 50);
126702
126565
  });
126703
126566
  }
126704
126567
  function browserOpenCommand(url2, platform2 = process.platform) {
@@ -126714,7 +126577,7 @@ function browserOpenCommand(url2, platform2 = process.platform) {
126714
126577
  return { cmd: "xdg-open", args: [url2] };
126715
126578
  }
126716
126579
  function waitForCallback(opts) {
126717
- return new Promise((resolve12, reject) => {
126580
+ return new Promise((resolve13, reject) => {
126718
126581
  const servers = [];
126719
126582
  let settled = false;
126720
126583
  const settle = (fn) => {
@@ -126791,7 +126654,7 @@ function waitForCallback(opts) {
126791
126654
  }
126792
126655
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
126793
126656
  res.end(htmlPage("Authorized", "You can close this window \u2014 moxxy received the token."));
126794
- settle(() => resolve12(code));
126657
+ settle(() => resolve13(code));
126795
126658
  };
126796
126659
  const onFatalError = (e3) => {
126797
126660
  if (e3.code === "EADDRINUSE") {
@@ -126979,10 +126842,10 @@ async function pollUntil(fn, opts) {
126979
126842
  throw new Error(`${label3} timed out waiting for completion`);
126980
126843
  }
126981
126844
  function sleep3(ms, signal) {
126982
- return new Promise((resolve12, reject) => {
126845
+ return new Promise((resolve13, reject) => {
126983
126846
  if (signal?.aborted)
126984
126847
  return reject(new Error("aborted"));
126985
- const t2 = setTimeout(resolve12, ms);
126848
+ const t2 = setTimeout(resolve13, ms);
126986
126849
  const onAbort = () => {
126987
126850
  clearTimeout(t2);
126988
126851
  reject(new Error("aborted"));
@@ -127117,20 +126980,19 @@ async function storeTokenSet(vault, provider, tokens, meta) {
127117
126980
  validateProvider(provider);
127118
126981
  const tag2 = `oauth:${provider}`;
127119
126982
  const base2 = `oauth/${provider}`;
126983
+ const upsert = async (key, value) => {
126984
+ if (value !== void 0) {
126985
+ await vault.set(`${base2}/${key}`, value, [tag2]);
126986
+ } else {
126987
+ await vault.delete?.(`${base2}/${key}`);
126988
+ }
126989
+ };
127120
126990
  await vault.set(`${base2}/access_token`, tokens.accessToken, [tag2]);
127121
- if (tokens.refreshToken !== void 0) {
127122
- await vault.set(`${base2}/refresh_token`, tokens.refreshToken, [tag2]);
127123
- }
127124
- if (tokens.expiresAt !== void 0) {
127125
- await vault.set(`${base2}/expires_at`, String(tokens.expiresAt), [tag2]);
127126
- }
127127
- if (tokens.scope !== void 0) {
127128
- await vault.set(`${base2}/scope`, tokens.scope, [tag2]);
127129
- }
126991
+ await upsert("refresh_token", tokens.refreshToken);
126992
+ await upsert("expires_at", tokens.expiresAt !== void 0 ? String(tokens.expiresAt) : void 0);
126993
+ await upsert("scope", tokens.scope);
127130
126994
  await vault.set(`${base2}/token_type`, tokens.tokenType, [tag2]);
127131
- if (tokens.idToken !== void 0) {
127132
- await vault.set(`${base2}/id_token`, tokens.idToken, [tag2]);
127133
- }
126995
+ await upsert("id_token", tokens.idToken);
127134
126996
  await vault.set(`${base2}/client_id`, meta.clientId, [tag2]);
127135
126997
  if (meta.clientSecret) {
127136
126998
  await vault.set(`${base2}/client_secret`, meta.clientSecret, [tag2]);
@@ -127217,8 +127079,79 @@ function parseExtras(raw) {
127217
127079
  return {};
127218
127080
  }
127219
127081
  }
127220
-
127221
- // ../plugin-oauth/dist/tools.js
127082
+ var DEFAULT_STALE_MS = 6e4;
127083
+ var DEFAULT_POLL_MS = 150;
127084
+ var DEFAULT_WAIT_MS = 3e4;
127085
+ var inProcessLocks = /* @__PURE__ */ new Map();
127086
+ async function withCredentialLock(key, fn, opts = {}) {
127087
+ const safe2 = sanitizeKey(key);
127088
+ let mutex = inProcessLocks.get(safe2);
127089
+ if (!mutex) {
127090
+ mutex = createMutex();
127091
+ inProcessLocks.set(safe2, mutex);
127092
+ }
127093
+ return mutex.run(async () => {
127094
+ const release = await acquireFileLock(join(opts.dir ?? moxxyPath("locks"), `${safe2}.lock`), opts.staleMs ?? DEFAULT_STALE_MS, opts.pollMs ?? DEFAULT_POLL_MS, opts.waitMs ?? DEFAULT_WAIT_MS);
127095
+ try {
127096
+ return await fn();
127097
+ } finally {
127098
+ await release();
127099
+ }
127100
+ });
127101
+ }
127102
+ function isAuthRejection(err) {
127103
+ return err instanceof MoxxyError && (err.code === "AUTH_INVALID" || err.code === "AUTH_DENIED" || err.code === "AUTH_EXPIRED" || err.code === "PROVIDER_BAD_REQUEST");
127104
+ }
127105
+ function sanitizeKey(key) {
127106
+ return key.replace(/[^a-zA-Z0-9._-]+/g, "_");
127107
+ }
127108
+ async function acquireFileLock(lockPath, staleMs, pollMs, waitMs) {
127109
+ const deadline = Date.now() + waitMs;
127110
+ try {
127111
+ await mkdir(dirname(lockPath), { recursive: true });
127112
+ } catch {
127113
+ return async () => {
127114
+ };
127115
+ }
127116
+ for (; ; ) {
127117
+ try {
127118
+ const handle2 = await open(lockPath, "wx");
127119
+ try {
127120
+ await handle2.writeFile(`${process.pid} ${(/* @__PURE__ */ new Date()).toISOString()}
127121
+ `, "utf8");
127122
+ } finally {
127123
+ await handle2.close().catch(() => {
127124
+ });
127125
+ }
127126
+ return async () => {
127127
+ await rm(lockPath, { force: true }).catch(() => {
127128
+ });
127129
+ };
127130
+ } catch (err) {
127131
+ if (err.code !== "EEXIST") {
127132
+ return async () => {
127133
+ };
127134
+ }
127135
+ }
127136
+ try {
127137
+ const st3 = await stat(lockPath);
127138
+ if (Date.now() - st3.mtimeMs > staleMs) {
127139
+ await rm(lockPath, { force: true }).catch(() => {
127140
+ });
127141
+ continue;
127142
+ }
127143
+ } catch {
127144
+ continue;
127145
+ }
127146
+ if (Date.now() >= deadline)
127147
+ return async () => {
127148
+ };
127149
+ await sleep4(pollMs);
127150
+ }
127151
+ }
127152
+ function sleep4(ms) {
127153
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
127154
+ }
127222
127155
  var providerNameField = z$1.string().min(1).max(60).describe('Stable provider key used as the vault namespace (e.g. "google", "github", "notion"). Lowercase letters, digits, dot/dash/underscore only.');
127223
127156
  function buildOauthAuthorizeTool(deps) {
127224
127157
  return defineTool({
@@ -127346,31 +127279,20 @@ function buildOauthGetTokenTool(deps) {
127346
127279
  context: { provider }
127347
127280
  });
127348
127281
  }
127349
- let tokens = stored.tokenSet;
127350
- if (forceRefresh || isExpired(tokens)) {
127351
- if (!tokens.refreshToken) {
127352
- throw new MoxxyError({
127353
- code: "AUTH_EXPIRED",
127354
- message: `OAuth token for "${provider}" expired and no refresh_token is stored. Re-run oauth_authorize.`,
127355
- context: { provider }
127356
- });
127357
- }
127358
- const refreshed = await refreshAccessToken({
127359
- tokenUrl: stored.tokenUrl,
127360
- clientId: stored.clientId,
127361
- ...stored.clientSecret ? { clientSecret: stored.clientSecret } : {},
127362
- refreshToken: tokens.refreshToken
127363
- });
127364
- tokens = {
127365
- ...refreshed,
127366
- refreshToken: refreshed.refreshToken ?? tokens.refreshToken
127367
- };
127368
- await storeTokenSet(deps.vault, provider, tokens, {
127369
- clientId: stored.clientId,
127370
- ...stored.clientSecret ? { clientSecret: stored.clientSecret } : {},
127371
- tokenUrl: stored.tokenUrl
127282
+ if (!forceRefresh && !isExpired(stored.tokenSet)) {
127283
+ return summarizeTokens(provider, stored.tokenSet, {
127284
+ includeAccess: true,
127285
+ ...includeRefresh ? { includeRefresh: true } : {}
127372
127286
  });
127373
127287
  }
127288
+ const tokens = await withCredentialLock(`oauth-${provider}`, async () => {
127289
+ const current = await readStoredCreds(deps.vault, provider) ?? stored;
127290
+ const rotatedMeanwhile = current.tokenSet.accessToken !== stored.tokenSet.accessToken;
127291
+ if (!isExpired(current.tokenSet) && (!forceRefresh || rotatedMeanwhile)) {
127292
+ return current.tokenSet;
127293
+ }
127294
+ return refreshAndStoreCreds(deps.vault, provider, current);
127295
+ });
127374
127296
  return summarizeTokens(provider, tokens, {
127375
127297
  includeAccess: true,
127376
127298
  ...includeRefresh ? { includeRefresh: true } : {}
@@ -127390,6 +127312,46 @@ function buildOauthClearTool(deps) {
127390
127312
  }
127391
127313
  });
127392
127314
  }
127315
+ async function refreshAndStoreCreds(vault, provider, stored, retried = false) {
127316
+ if (!stored.tokenSet.refreshToken) {
127317
+ throw new MoxxyError({
127318
+ code: "AUTH_EXPIRED",
127319
+ message: `OAuth token for "${provider}" expired and no refresh_token is stored. Re-run oauth_authorize.`,
127320
+ context: { provider }
127321
+ });
127322
+ }
127323
+ let refreshed;
127324
+ try {
127325
+ refreshed = await refreshAccessToken({
127326
+ tokenUrl: stored.tokenUrl,
127327
+ clientId: stored.clientId,
127328
+ ...stored.clientSecret ? { clientSecret: stored.clientSecret } : {},
127329
+ refreshToken: stored.tokenSet.refreshToken
127330
+ });
127331
+ } catch (err) {
127332
+ if (!retried && isAuthRejection(err)) {
127333
+ const latest = await readStoredCreds(vault, provider);
127334
+ if (latest?.tokenSet.refreshToken && latest.tokenSet.refreshToken !== stored.tokenSet.refreshToken) {
127335
+ return refreshAndStoreCreds(vault, provider, latest, true);
127336
+ }
127337
+ }
127338
+ const net3 = classifyNetworkError(err, { url: stored.tokenUrl, provider });
127339
+ if (net3)
127340
+ throw net3;
127341
+ throw err;
127342
+ }
127343
+ const merged = {
127344
+ ...refreshed,
127345
+ refreshToken: refreshed.refreshToken ?? stored.tokenSet.refreshToken
127346
+ };
127347
+ await storeTokenSet(vault, provider, merged, {
127348
+ clientId: stored.clientId,
127349
+ ...stored.clientSecret ? { clientSecret: stored.clientSecret } : {},
127350
+ tokenUrl: stored.tokenUrl,
127351
+ ...Object.keys(stored.extras).length > 0 ? { extras: stored.extras } : {}
127352
+ });
127353
+ return merged;
127354
+ }
127393
127355
  function summarizeTokens(provider, tokens, opts = {}) {
127394
127356
  return {
127395
127357
  provider,
@@ -127496,81 +127458,6 @@ Polling every ${Math.round(init3.intervalMs / 1e3)}s (${Math.round(init3.expires
127496
127458
  ...ctx.signal ? { signal: ctx.signal } : {}
127497
127459
  });
127498
127460
  }
127499
- var DEFAULT_STALE_MS = 6e4;
127500
- var DEFAULT_POLL_MS = 150;
127501
- var DEFAULT_WAIT_MS = 3e4;
127502
- var inProcessLocks = /* @__PURE__ */ new Map();
127503
- async function withCredentialLock(key, fn, opts = {}) {
127504
- const safe2 = sanitizeKey(key);
127505
- let mutex = inProcessLocks.get(safe2);
127506
- if (!mutex) {
127507
- mutex = createMutex();
127508
- inProcessLocks.set(safe2, mutex);
127509
- }
127510
- return mutex.run(async () => {
127511
- const release = await acquireFileLock(join(opts.dir ?? moxxyPath("locks"), `${safe2}.lock`), opts.staleMs ?? DEFAULT_STALE_MS, opts.pollMs ?? DEFAULT_POLL_MS, opts.waitMs ?? DEFAULT_WAIT_MS);
127512
- try {
127513
- return await fn();
127514
- } finally {
127515
- await release();
127516
- }
127517
- });
127518
- }
127519
- function isAuthRejection(err) {
127520
- return err instanceof MoxxyError && (err.code === "AUTH_INVALID" || err.code === "AUTH_DENIED" || err.code === "AUTH_EXPIRED" || err.code === "PROVIDER_BAD_REQUEST");
127521
- }
127522
- function sanitizeKey(key) {
127523
- return key.replace(/[^a-zA-Z0-9._-]+/g, "_");
127524
- }
127525
- async function acquireFileLock(lockPath, staleMs, pollMs, waitMs) {
127526
- const deadline = Date.now() + waitMs;
127527
- try {
127528
- await mkdir(dirname(lockPath), { recursive: true });
127529
- } catch {
127530
- return async () => {
127531
- };
127532
- }
127533
- for (; ; ) {
127534
- try {
127535
- const handle2 = await open(lockPath, "wx");
127536
- try {
127537
- await handle2.writeFile(`${process.pid} ${(/* @__PURE__ */ new Date()).toISOString()}
127538
- `, "utf8");
127539
- } finally {
127540
- await handle2.close().catch(() => {
127541
- });
127542
- }
127543
- return async () => {
127544
- await rm(lockPath, { force: true }).catch(() => {
127545
- });
127546
- };
127547
- } catch (err) {
127548
- if (err.code !== "EEXIST") {
127549
- return async () => {
127550
- };
127551
- }
127552
- }
127553
- try {
127554
- const st3 = await stat(lockPath);
127555
- if (Date.now() - st3.mtimeMs > staleMs) {
127556
- await rm(lockPath, { force: true }).catch(() => {
127557
- });
127558
- continue;
127559
- }
127560
- } catch {
127561
- continue;
127562
- }
127563
- if (Date.now() >= deadline)
127564
- return async () => {
127565
- };
127566
- await sleep4(pollMs);
127567
- }
127568
- }
127569
- function sleep4(ms) {
127570
- return new Promise((resolve12) => setTimeout(resolve12, ms));
127571
- }
127572
-
127573
- // ../plugin-oauth/dist/ensure-fresh.js
127574
127461
  async function ensureFreshTokens(profile, vault, opts = {}) {
127575
127462
  const stored = await readStoredCreds(vault, profile.id);
127576
127463
  if (!stored) {
@@ -128082,10 +127969,10 @@ async function* consumeResponsesSse(body, signal, emitReasoning = false) {
128082
127969
  break;
128083
127970
  buffer += decoder.decode(value, { stream: true });
128084
127971
  buffer = buffer.replace(/\r\n/g, "\n");
128085
- let sep2;
128086
- while ((sep2 = buffer.indexOf("\n\n")) !== -1) {
128087
- const frame = buffer.slice(0, sep2);
128088
- buffer = buffer.slice(sep2 + 2);
127972
+ let sep3;
127973
+ while ((sep3 = buffer.indexOf("\n\n")) !== -1) {
127974
+ const frame = buffer.slice(0, sep3);
127975
+ buffer = buffer.slice(sep3 + 2);
128089
127976
  for (const line of frame.split("\n")) {
128090
127977
  if (!line.startsWith("data:"))
128091
127978
  continue;
@@ -128591,7 +128478,7 @@ async function refreshClaudeUnderLock(vault, baseline) {
128591
128478
  }
128592
128479
  var fetchImpl = fetch;
128593
128480
  var openBrowserImpl = openInBrowser;
128594
- var sleepImpl = (ms) => new Promise((resolve12) => setTimeout(resolve12, ms));
128481
+ var sleepImpl = (ms) => new Promise((resolve13) => setTimeout(resolve13, ms));
128595
128482
  var TOKEN_POST_MAX_ATTEMPTS = 3;
128596
128483
  var TOKEN_POST_BACKOFF_MS = [600, 1800];
128597
128484
  async function exchangeClaudeCode(code, state, verifier) {
@@ -128711,20 +128598,11 @@ var glmModels = [
128711
128598
  var ZAI_OPENAI_BASE_URL = "https://api.z.ai/api/paas/v4";
128712
128599
  var ZAI_ANTHROPIC_BASE_URL = "https://api.z.ai/api/anthropic";
128713
128600
  var ZAI_DEFAULT_MODEL = "glm-4.6";
128714
- var zaiProviderDef = defineProvider({
128601
+ var zaiProviderDef = defineOpenAICompatProvider({
128715
128602
  name: "zai",
128716
- models: [...glmModels],
128717
- createClient: (config) => {
128718
- const cfg = config;
128719
- return new OpenAIProvider({
128720
- ...cfg,
128721
- name: "zai",
128722
- baseURL: cfg.baseURL ?? ZAI_OPENAI_BASE_URL,
128723
- defaultModel: cfg.defaultModel ?? ZAI_DEFAULT_MODEL,
128724
- models: glmModels
128725
- });
128726
- },
128727
- validateKey: (key) => validateKey2(key, { baseURL: ZAI_OPENAI_BASE_URL }),
128603
+ baseURL: ZAI_OPENAI_BASE_URL,
128604
+ defaultModel: ZAI_DEFAULT_MODEL,
128605
+ models: glmModels,
128728
128606
  auth: {
128729
128607
  kind: "apiKey",
128730
128608
  hint: "z.ai API key (pay-as-you-go) from https://z.ai/manage-apikey/apikey-list"
@@ -128734,9 +128612,9 @@ var zaiCodingPlanProviderDef = defineProvider({
128734
128612
  name: "zai-coding-plan",
128735
128613
  models: [...glmModels],
128736
128614
  createClient: (config) => {
128737
- const cfg = config;
128615
+ const cfg = pickOpenAICompatConfig(config);
128738
128616
  return new AnthropicProvider({
128739
- ...cfg,
128617
+ apiKey: cfg.apiKey,
128740
128618
  name: "zai-coding-plan",
128741
128619
  baseURL: cfg.baseURL ?? ZAI_ANTHROPIC_BASE_URL,
128742
128620
  defaultModel: cfg.defaultModel ?? ZAI_DEFAULT_MODEL,
@@ -128770,20 +128648,11 @@ var grokModels = [
128770
128648
  // ../plugin-provider-xai/dist/index.js
128771
128649
  var XAI_BASE_URL = "https://api.x.ai/v1";
128772
128650
  var XAI_DEFAULT_MODEL = "grok-4";
128773
- var xaiProviderDef = defineProvider({
128651
+ var xaiProviderDef = defineOpenAICompatProvider({
128774
128652
  name: "xai",
128775
- models: [...grokModels],
128776
- createClient: (config) => {
128777
- const cfg = config;
128778
- return new OpenAIProvider({
128779
- ...cfg,
128780
- name: "xai",
128781
- baseURL: cfg.baseURL ?? XAI_BASE_URL,
128782
- defaultModel: cfg.defaultModel ?? XAI_DEFAULT_MODEL,
128783
- models: grokModels
128784
- });
128785
- },
128786
- validateKey: (key) => validateKey2(key, { baseURL: XAI_BASE_URL }),
128653
+ baseURL: XAI_BASE_URL,
128654
+ defaultModel: XAI_DEFAULT_MODEL,
128655
+ models: grokModels,
128787
128656
  auth: {
128788
128657
  kind: "apiKey",
128789
128658
  hint: "xAI API key (starts with `xai-`) from https://console.x.ai"
@@ -128809,20 +128678,11 @@ var geminiModels = [
128809
128678
  // ../plugin-provider-google/dist/index.js
128810
128679
  var GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai/";
128811
128680
  var GEMINI_DEFAULT_MODEL = "gemini-2.5-flash";
128812
- var googleProviderDef = defineProvider({
128681
+ var googleProviderDef = defineOpenAICompatProvider({
128813
128682
  name: "google",
128814
- models: [...geminiModels],
128815
- createClient: (config) => {
128816
- const cfg = config;
128817
- return new OpenAIProvider({
128818
- ...cfg,
128819
- name: "google",
128820
- baseURL: cfg.baseURL ?? GEMINI_BASE_URL,
128821
- defaultModel: cfg.defaultModel ?? GEMINI_DEFAULT_MODEL,
128822
- models: geminiModels
128823
- });
128824
- },
128825
- validateKey: (key) => validateKey2(key, { baseURL: GEMINI_BASE_URL }),
128683
+ baseURL: GEMINI_BASE_URL,
128684
+ defaultModel: GEMINI_DEFAULT_MODEL,
128685
+ models: geminiModels,
128826
128686
  auth: {
128827
128687
  kind: "apiKey",
128828
128688
  hint: "Google AI Studio (Gemini) API key from https://aistudio.google.com/apikey"
@@ -128843,22 +128703,14 @@ var localModels = [
128843
128703
  { id: "deepseek-r1", contextWindow: 131072, supportsTools: true, supportsStreaming: true },
128844
128704
  { id: "gpt-oss", contextWindow: 131072, supportsTools: true, supportsStreaming: true }
128845
128705
  ];
128846
- var localProviderDef = defineProvider({
128706
+ var localProviderDef = defineOpenAICompatProvider({
128847
128707
  name: "local",
128848
- models: [...localModels],
128849
- createClient: (config) => {
128850
- const cfg = config;
128851
- return new OpenAIProvider({
128852
- ...cfg,
128853
- name: "local",
128854
- apiKey: cfg.apiKey ?? process.env.LOCAL_API_KEY ?? LOCAL_PLACEHOLDER_KEY,
128855
- baseURL: cfg.baseURL ?? process.env.LOCAL_MODEL_BASE_URL ?? DEFAULT_LOCAL_BASE_URL,
128856
- defaultModel: cfg.defaultModel ?? LOCAL_DEFAULT_MODEL,
128857
- models: localModels
128858
- });
128859
- },
128860
- // No validateKey: there is no key to validate, and probing a local server
128861
- // that may be offline would surface confusing errors during setup.
128708
+ baseURL: DEFAULT_LOCAL_BASE_URL,
128709
+ defaultModel: LOCAL_DEFAULT_MODEL,
128710
+ models: localModels,
128711
+ validate: false,
128712
+ resolveApiKey: (cfg) => cfg.apiKey ?? process.env.LOCAL_API_KEY ?? LOCAL_PLACEHOLDER_KEY,
128713
+ resolveBaseURL: (cfg) => cfg.baseURL ?? process.env.LOCAL_MODEL_BASE_URL ?? DEFAULT_LOCAL_BASE_URL,
128862
128714
  auth: {
128863
128715
  kind: "apiKey",
128864
128716
  envVar: "LOCAL_API_KEY",
@@ -129298,7 +129150,7 @@ var bashTool = defineTool({
129298
129150
  if (ctx.signal.aborted) {
129299
129151
  throw new MoxxyError({ code: "ABORTED", message: `Bash aborted before start: ${command}` });
129300
129152
  }
129301
- return await new Promise((resolve12, reject) => {
129153
+ return await new Promise((resolve13, reject) => {
129302
129154
  const child = spawn("/bin/sh", ["-lc", command], {
129303
129155
  cwd: cwd2 ?? ctx.cwd,
129304
129156
  env: env3 ? { ...process.env, ...env3 } : process.env,
@@ -129351,9 +129203,9 @@ ${err.text.trimEnd()}
129351
129203
  ` : "") + `[exit ${code ?? "null"}]`;
129352
129204
  const dropped = out.dropped + err.dropped;
129353
129205
  if (dropped === 0) {
129354
- resolve12(clampString(combined, OUTPUT_LIMIT));
129206
+ resolve13(clampString(combined, OUTPUT_LIMIT));
129355
129207
  } else {
129356
- resolve12(combined.slice(0, OUTPUT_LIMIT) + `
129208
+ resolve13(combined.slice(0, OUTPUT_LIMIT) + `
129357
129209
  ... [truncated ${combined.length + dropped - OUTPUT_LIMIT} chars]`);
129358
129210
  }
129359
129211
  });
@@ -129934,10 +129786,10 @@ var sleepTool = defineTool({
129934
129786
  if (ctx.signal.aborted) {
129935
129787
  throw new MoxxyError({ code: "ABORTED", message: "Sleep aborted before start" });
129936
129788
  }
129937
- await new Promise((resolve12, reject) => {
129789
+ await new Promise((resolve13, reject) => {
129938
129790
  const timer = setTimeout(() => {
129939
129791
  ctx.signal.removeEventListener("abort", onAbort);
129940
- resolve12();
129792
+ resolve13();
129941
129793
  }, totalMs);
129942
129794
  const onAbort = () => {
129943
129795
  clearTimeout(timer);
@@ -131415,11 +131267,11 @@ var TelegramPermissionResolver = class {
131415
131267
  if (!this.deciderFn) {
131416
131268
  return { mode: "deny", reason: "no decider attached (bot not running)" };
131417
131269
  }
131418
- const decision = await new Promise((resolve12) => {
131419
- this.pending.set(call.callId, { callId: call.callId, call, ctx, resolve: resolve12 });
131270
+ const decision = await new Promise((resolve13) => {
131271
+ this.pending.set(call.callId, { callId: call.callId, call, ctx, resolve: resolve13 });
131420
131272
  this.deciderFn(call, ctx).catch((err) => {
131421
131273
  this.pending.delete(call.callId);
131422
- resolve12({ mode: "deny", reason: err instanceof Error ? err.message : String(err) });
131274
+ resolve13({ mode: "deny", reason: err instanceof Error ? err.message : String(err) });
131423
131275
  });
131424
131276
  });
131425
131277
  if (decision.mode === "allow_session")
@@ -131457,11 +131309,11 @@ var TelegramApprovalResolver = class {
131457
131309
  return { optionId: request.defaultOptionId ?? request.options[0]?.id ?? "approve" };
131458
131310
  }
131459
131311
  const id = `appr_${this.nextId++}`;
131460
- return new Promise((resolve12) => {
131461
- this.pending.set(id, { id, request, resolve: resolve12 });
131312
+ return new Promise((resolve13) => {
131313
+ this.pending.set(id, { id, request, resolve: resolve13 });
131462
131314
  this.deciderFn(id, request).catch((err) => {
131463
131315
  this.pending.delete(id);
131464
- resolve12({
131316
+ resolve13({
131465
131317
  optionId: request.defaultOptionId ?? request.options[0]?.id ?? "cancel",
131466
131318
  text: `decider failed: ${err instanceof Error ? err.message : String(err)}`
131467
131319
  });
@@ -133928,8 +133780,8 @@ async function runPairFlow(ctx) {
133928
133780
  });
133929
133781
  session.setPermissionResolver(channel.permissionResolver);
133930
133782
  let issuedResolve = null;
133931
- const issued = new Promise((resolve12) => {
133932
- issuedResolve = resolve12;
133783
+ const issued = new Promise((resolve13) => {
133784
+ issuedResolve = resolve13;
133933
133785
  });
133934
133786
  const unsubscribe = channel.onPairingIssued((e3) => {
133935
133787
  issuedResolve?.(e3);
@@ -134502,7 +134354,7 @@ var HttpChannel = class {
134502
134354
  }
134503
134355
  });
134504
134356
  this.server = server;
134505
- const listening = new Promise((resolve12, reject) => {
134357
+ const listening = new Promise((resolve13, reject) => {
134506
134358
  server.once("error", reject);
134507
134359
  server.listen(this.port, this.host, () => {
134508
134360
  const addr = server.address();
@@ -134512,20 +134364,20 @@ var HttpChannel = class {
134512
134364
  port: this.boundPortValue,
134513
134365
  authEnabled: this.authToken !== null
134514
134366
  });
134515
- resolve12();
134367
+ resolve13();
134516
134368
  });
134517
134369
  });
134518
134370
  await listening;
134519
- const running = new Promise((resolve12) => {
134520
- server.once("close", () => resolve12());
134371
+ const running = new Promise((resolve13) => {
134372
+ server.once("close", () => resolve13());
134521
134373
  });
134522
134374
  return {
134523
134375
  running,
134524
134376
  stop: async () => {
134525
- await new Promise((resolve12) => {
134377
+ await new Promise((resolve13) => {
134526
134378
  if (!this.server)
134527
- return resolve12();
134528
- this.server.close(() => resolve12());
134379
+ return resolve13();
134380
+ this.server.close(() => resolve13());
134529
134381
  });
134530
134382
  }
134531
134383
  };
@@ -134668,17 +134520,17 @@ function isAddrInUse(err) {
134668
134520
  }
134669
134521
  async function captureStdout(cmd, args) {
134670
134522
  const { spawn: spawn15 } = await import('child_process');
134671
- return await new Promise((resolve12) => {
134523
+ return await new Promise((resolve13) => {
134672
134524
  let out = "";
134673
134525
  try {
134674
134526
  const child = spawn15(cmd, [...args], { stdio: ["ignore", "pipe", "ignore"] });
134675
134527
  child.stdout.on("data", (b3) => {
134676
134528
  out += b3.toString();
134677
134529
  });
134678
- child.on("error", () => resolve12(""));
134679
- child.on("close", () => resolve12(out));
134530
+ child.on("error", () => resolve13(""));
134531
+ child.on("close", () => resolve13(out));
134680
134532
  } catch {
134681
- resolve12("");
134533
+ resolve13("");
134682
134534
  }
134683
134535
  });
134684
134536
  }
@@ -134805,7 +134657,7 @@ var WebChannel = class {
134805
134657
  await this.openTunnel();
134806
134658
  this.publishSurface?.({ url: this.shareUrl, nextViewId: () => `v_srv_${++this.viewSeq}` });
134807
134659
  this.publishControls?.({ retunnel: () => this.retunnel() });
134808
- const running = new Promise((resolve12) => server.once("close", () => resolve12()));
134660
+ const running = new Promise((resolve13) => server.once("close", () => resolve13()));
134809
134661
  return { running, stop: () => this.stop() };
134810
134662
  }
134811
134663
  /**
@@ -134818,7 +134670,7 @@ var WebChannel = class {
134818
134670
  * surface actually got (the share URL embeds the real port either way).
134819
134671
  */
134820
134672
  async bindServerWithRetry(server) {
134821
- const tryListen = () => new Promise((resolve12, reject) => {
134673
+ const tryListen = () => new Promise((resolve13, reject) => {
134822
134674
  const onError2 = (err) => {
134823
134675
  server.off("listening", onListening);
134824
134676
  reject(err);
@@ -134829,7 +134681,7 @@ var WebChannel = class {
134829
134681
  if (addr && typeof addr === "object")
134830
134682
  this.port = addr.port;
134831
134683
  this.logger?.info?.("web channel listening", { url: this.url });
134832
- resolve12();
134684
+ resolve13();
134833
134685
  };
134834
134686
  server.once("error", onError2);
134835
134687
  server.once("listening", onListening);
@@ -134910,8 +134762,8 @@ var WebChannel = class {
134910
134762
  }
134911
134763
  }
134912
134764
  this.clients.clear();
134913
- await new Promise((resolve12) => this.wss ? this.wss.close(() => resolve12()) : resolve12());
134914
- await new Promise((resolve12) => this.server ? this.server.close(() => resolve12()) : resolve12());
134765
+ await new Promise((resolve13) => this.wss ? this.wss.close(() => resolve13()) : resolve13());
134766
+ await new Promise((resolve13) => this.server ? this.server.close(() => resolve13()) : resolve13());
134915
134767
  }
134916
134768
  validToken(reqUrl) {
134917
134769
  try {
@@ -135074,6 +134926,7 @@ var ngrokTunnel = defineTunnelProvider({
135074
134926
  })
135075
134927
  });
135076
134928
  var webSettingsSchema = z$1.object({ tunnel: z$1.string().optional() });
134929
+ var writeMutex2 = createMutex();
135077
134930
  function webSettingsPath() {
135078
134931
  return moxxyPath("web.json");
135079
134932
  }
@@ -135096,8 +134949,10 @@ function readTunnelSetting(file = webSettingsPath()) {
135096
134949
  return typeof t2 === "string" && t2 ? normalizeTunnelName(t2) : void 0;
135097
134950
  }
135098
134951
  async function writeTunnelSetting(name, file = webSettingsPath()) {
135099
- const next = { ...readWebSettings(file), tunnel: normalizeTunnelName(name) };
135100
- await writeFileAtomic(file, JSON.stringify(next, null, 2));
134952
+ await writeMutex2.run(async () => {
134953
+ const next = { ...readWebSettings(file), tunnel: normalizeTunnelName(name) };
134954
+ await writeFileAtomic(file, JSON.stringify(next, null, 2));
134955
+ });
135101
134956
  }
135102
134957
 
135103
134958
  // ../plugin-channel-web/dist/index.js
@@ -135308,9 +135163,9 @@ async function createWebSocketTransportServer(opts) {
135308
135163
  for (const handler of connectionHandlers)
135309
135164
  handler(transport);
135310
135165
  });
135311
- await new Promise((resolve12, reject) => {
135166
+ await new Promise((resolve13, reject) => {
135312
135167
  wss.once("error", reject);
135313
- wss.once("listening", resolve12);
135168
+ wss.once("listening", resolve13);
135314
135169
  });
135315
135170
  const bound = wss.address();
135316
135171
  const boundPort = typeof bound === "object" && bound !== null ? bound.port : opts.port;
@@ -135331,10 +135186,10 @@ async function createWebSocketTransportServer(opts) {
135331
135186
  return connections;
135332
135187
  },
135333
135188
  close() {
135334
- return new Promise((resolve12) => {
135189
+ return new Promise((resolve13) => {
135335
135190
  for (const client of wss.clients)
135336
135191
  client.terminate();
135337
- wss.close(() => resolve12());
135192
+ wss.close(() => resolve13());
135338
135193
  });
135339
135194
  }
135340
135195
  };
@@ -135386,8 +135241,8 @@ var JsonRpcPeer = class {
135386
135241
  if (this.closed)
135387
135242
  return Promise.reject(new RpcError("rpc peer is closed"));
135388
135243
  const id = this.nextId++;
135389
- return new Promise((resolve12, reject) => {
135390
- this.pending.set(id, { resolve: resolve12, reject });
135244
+ return new Promise((resolve13, reject) => {
135245
+ this.pending.set(id, { resolve: resolve13, reject });
135391
135246
  const frame = { id, method, ...params !== void 0 ? { params } : {} };
135392
135247
  this.transport.send(frame);
135393
135248
  });
@@ -135539,11 +135394,11 @@ async function createUnixSocketServer(socketPath, logger = stderrLogger) {
135539
135394
  for (const handler of connectionHandlers)
135540
135395
  handler(transport);
135541
135396
  });
135542
- await new Promise((resolve12, reject) => {
135397
+ await new Promise((resolve13, reject) => {
135543
135398
  server.once("error", reject);
135544
135399
  server.listen(socketPath, () => {
135545
135400
  server.removeListener("error", reject);
135546
- resolve12();
135401
+ resolve13();
135547
135402
  });
135548
135403
  });
135549
135404
  if (process.platform !== "win32") {
@@ -135562,7 +135417,7 @@ async function createUnixSocketServer(socketPath, logger = stderrLogger) {
135562
135417
  connectionHandlers.push(handler);
135563
135418
  },
135564
135419
  close() {
135565
- return new Promise((resolve12) => {
135420
+ return new Promise((resolve13) => {
135566
135421
  server.close(() => {
135567
135422
  if (process.platform !== "win32") {
135568
135423
  try {
@@ -135570,14 +135425,14 @@ async function createUnixSocketServer(socketPath, logger = stderrLogger) {
135570
135425
  } catch {
135571
135426
  }
135572
135427
  }
135573
- resolve12();
135428
+ resolve13();
135574
135429
  });
135575
135430
  });
135576
135431
  }
135577
135432
  };
135578
135433
  }
135579
135434
  function connectUnixSocket(socketPath) {
135580
- return new Promise((resolve12, reject) => {
135435
+ return new Promise((resolve13, reject) => {
135581
135436
  const socket = net.connect(socketPath);
135582
135437
  const onError2 = (err) => {
135583
135438
  socket.destroy();
@@ -135586,7 +135441,7 @@ function connectUnixSocket(socketPath) {
135586
135441
  socket.once("error", onError2);
135587
135442
  socket.once("connect", () => {
135588
135443
  socket.removeListener("error", onError2);
135589
- resolve12(new NdjsonTransport(socket));
135444
+ resolve13(new NdjsonTransport(socket));
135590
135445
  });
135591
135446
  });
135592
135447
  }
@@ -135618,11 +135473,11 @@ function warnWindowsPipeAclOnce(logger, pipePath) {
135618
135473
  async function reclaimStaleSocket(socketPath) {
135619
135474
  if (!fs28__default.existsSync(socketPath))
135620
135475
  return;
135621
- const alive = await new Promise((resolve12) => {
135476
+ const alive = await new Promise((resolve13) => {
135622
135477
  const probe = net.connect(socketPath);
135623
135478
  const finish = (up) => {
135624
135479
  probe.destroy();
135625
- resolve12(up);
135480
+ resolve13(up);
135626
135481
  };
135627
135482
  probe.once("connect", () => finish(true));
135628
135483
  probe.once("error", () => finish(false));
@@ -135647,11 +135502,11 @@ function runnerSocketPath() {
135647
135502
  return platformSocket("serve", path3__default.join(os5__default.homedir(), ".moxxy", "serve.sock"));
135648
135503
  }
135649
135504
  function isRunnerUp(socketPath = runnerSocketPath()) {
135650
- return new Promise((resolve12) => {
135505
+ return new Promise((resolve13) => {
135651
135506
  const socket = net.connect(socketPath);
135652
135507
  const finish = (up) => {
135653
135508
  socket.destroy();
135654
- resolve12(up);
135509
+ resolve13(up);
135655
135510
  };
135656
135511
  socket.once("connect", () => finish(true));
135657
135512
  socket.once("error", () => finish(false));
@@ -135898,6 +135753,23 @@ var RunnerServer = class {
135898
135753
  fallbackPermission;
135899
135754
  fallbackApproval;
135900
135755
  closed = false;
135756
+ /**
135757
+ * Serializes this runner's preferences read-modify-write handlers
135758
+ * ({@link handleProviderSetActive} / {@link handleProviderSetEnabled}).
135759
+ *
135760
+ * Invariant #5: a whole-file RMW store needs an atomic write PLUS a
135761
+ * per-instance promise-mutex. The atomic-write half lives in core's
135762
+ * `savePreferences`; the serialization half lives here because the
135763
+ * `disabledProviders` toggle reads the current set via `loadPreferences`
135764
+ * BEFORE handing the merged patch to `savePreferences` — that load→compute
135765
+ * step spans core's own critical section, so two overlapping toggles could
135766
+ * otherwise both read the same set and the second clobber the first. Running
135767
+ * the whole load→compute→save body under one mutex makes every prefs write
135768
+ * issued by this runner serialize. (Core would ideally expose a single
135769
+ * mutexed updater covering all callers; until it does, cross-process /
135770
+ * cross-runner prefs writes remain best-effort behind the atomic rename.)
135771
+ */
135772
+ prefsMutex = createMutex();
135901
135773
  constructor(session, transport) {
135902
135774
  this.session = session;
135903
135775
  this.transport = transport;
@@ -136091,7 +135963,7 @@ var RunnerServer = class {
136091
135963
  if (def)
136092
135964
  this.session.providers.replace(def);
136093
135965
  this.session.providers.setActive(name, cfg);
136094
- void savePreferences({ providerName: name });
135966
+ void this.prefsMutex.run(() => savePreferences({ providerName: name }));
136095
135967
  this.broadcastInfo();
136096
135968
  return {};
136097
135969
  }
@@ -136101,7 +135973,7 @@ var RunnerServer = class {
136101
135973
  throw new Error(`Provider not registered: ${name}`);
136102
135974
  }
136103
135975
  this.session.providers.setEnabled(name, enabled);
136104
- void (async () => {
135976
+ void this.prefsMutex.run(async () => {
136105
135977
  const prefs = await loadPreferences();
136106
135978
  const current = new Set(prefs.disabledProviders ?? []);
136107
135979
  if (enabled)
@@ -136109,7 +135981,7 @@ var RunnerServer = class {
136109
135981
  else
136110
135982
  current.add(name);
136111
135983
  await savePreferences({ disabledProviders: [...current] });
136112
- })();
135984
+ });
136113
135985
  this.broadcastInfo();
136114
135986
  return {};
136115
135987
  }
@@ -136421,12 +136293,13 @@ var TurnStream = class {
136421
136293
  yield this.queue.shift();
136422
136294
  if (this.done)
136423
136295
  break;
136424
- await new Promise((resolve12) => this.waiters.push(resolve12));
136296
+ await new Promise((resolve13) => this.waiters.push(resolve13));
136425
136297
  }
136426
136298
  if (this.error)
136427
136299
  throw new Error(this.error);
136428
136300
  }
136429
136301
  };
136302
+ var MAX_COMPLETED_TURNS = 64;
136430
136303
  var RemoteSession = class {
136431
136304
  peer;
136432
136305
  mirror = new EventLog();
@@ -136453,6 +136326,14 @@ var RemoteSession = class {
136453
136326
  * finish. We record it here and apply it the moment the stream registers -
136454
136327
  * otherwise the stream would hang forever. Maps turnId -> error (or
136455
136328
  * undefined for a clean finish).
136329
+ *
136330
+ * Bounded (insertion-ordered, drop-oldest — same shape as
136331
+ * {@link DeliveryDedupeCache} in plugin-webhooks): the server broadcasts
136332
+ * `turn.complete` to EVERY attached client, so an observer that never calls
136333
+ * `runTurn` for a turn (the desktop watching a TUI-driven session) would
136334
+ * otherwise accumulate an entry per turn forever. Only the last
136335
+ * {@link MAX_COMPLETED_TURNS} are kept; a legit fast-turn completion is
136336
+ * consumed within a tick of arriving, so it is never the one evicted.
136456
136337
  */
136457
136338
  completedTurns = /* @__PURE__ */ new Map();
136458
136339
  permissionResolver = null;
@@ -136483,7 +136364,7 @@ var RemoteSession = class {
136483
136364
  if (stream)
136484
136365
  stream.finish(error2);
136485
136366
  else
136486
- this.completedTurns.set(turnId, error2);
136367
+ this.recordCompletedTurn(turnId, error2);
136487
136368
  });
136488
136369
  this.peer.on(RunnerNotification.InfoChanged, (params) => {
136489
136370
  this.info = params.info;
@@ -136527,6 +136408,7 @@ var RemoteSession = class {
136527
136408
  for (const stream of this.turnStreams.values())
136528
136409
  stream.finish("runner disconnected");
136529
136410
  this.turnStreams.clear();
136411
+ this.completedTurns.clear();
136530
136412
  });
136531
136413
  this.providers = this.makeProvidersView();
136532
136414
  this.modes = this.makeModesView();
@@ -136542,6 +136424,23 @@ var RemoteSession = class {
136542
136424
  this.providerAdmin = this.makeProviderAdminView();
136543
136425
  this.workflows = this.makeWorkflowsView();
136544
136426
  }
136427
+ /**
136428
+ * Buffer a completion whose `runTurn` stream isn't registered yet (fast turn)
136429
+ * or that belongs to a turn this client only observes. Bounded, insertion-
136430
+ * ordered drop-oldest — mirrors {@link DeliveryDedupeCache}: re-insert on
136431
+ * update so a refreshed entry is the youngest, then evict the oldest once over
136432
+ * {@link MAX_COMPLETED_TURNS}. A pending fast-turn entry is drained by
136433
+ * `runTurn` within a tick, so it can't be the one evicted under normal load.
136434
+ */
136435
+ recordCompletedTurn(turnId, error2) {
136436
+ this.completedTurns.delete(turnId);
136437
+ this.completedTurns.set(turnId, error2);
136438
+ if (this.completedTurns.size > MAX_COMPLETED_TURNS) {
136439
+ const oldest = this.completedTurns.keys().next();
136440
+ if (!oldest.done)
136441
+ this.completedTurns.delete(oldest.value);
136442
+ }
136443
+ }
136545
136444
  /**
136546
136445
  * Providers the runner has activated. Exposed as a plain field (the TUI
136547
136446
  * model-picker reads it via a structural cast, same as it does on a local
@@ -137029,7 +136928,7 @@ async function isMoxxyProcess(pid) {
137029
136928
  }
137030
136929
  async function pidCommand2(pid) {
137031
136930
  const { spawn: spawn15 } = await import('child_process');
137032
- return await new Promise((resolve12) => {
136931
+ return await new Promise((resolve13) => {
137033
136932
  let out = "";
137034
136933
  try {
137035
136934
  const child = spawn15("ps", ["-p", String(pid), "-o", "command="], {
@@ -137038,10 +136937,10 @@ async function pidCommand2(pid) {
137038
136937
  child.stdout.on("data", (b3) => {
137039
136938
  out += b3.toString();
137040
136939
  });
137041
- child.on("error", () => resolve12(""));
137042
- child.on("close", () => resolve12(out.trim()));
136940
+ child.on("error", () => resolve13(""));
136941
+ child.on("close", () => resolve13(out.trim()));
137043
136942
  } catch {
137044
- resolve12("");
136943
+ resolve13("");
137045
136944
  }
137046
136945
  });
137047
136946
  }
@@ -137071,7 +136970,7 @@ async function pidsListeningOnPort(port) {
137071
136970
  }
137072
136971
  async function runLsof(args) {
137073
136972
  const { spawn: spawn15 } = await import('child_process');
137074
- return await new Promise((resolve12) => {
136973
+ return await new Promise((resolve13) => {
137075
136974
  let out = "";
137076
136975
  try {
137077
136976
  const child = spawn15("lsof", [...args], {
@@ -137080,10 +136979,10 @@ async function runLsof(args) {
137080
136979
  child.stdout.on("data", (b3) => {
137081
136980
  out += b3.toString();
137082
136981
  });
137083
- child.on("error", () => resolve12([]));
137084
- child.on("close", () => resolve12(parsePids(out)));
136982
+ child.on("error", () => resolve13([]));
136983
+ child.on("close", () => resolve13(parsePids(out)));
137085
136984
  } catch {
137086
- resolve12([]);
136985
+ resolve13([]);
137087
136986
  }
137088
136987
  });
137089
136988
  }
@@ -137220,6 +137119,17 @@ var ipcInputSchemas = {
137220
137119
  audioBase64: z.string().max(MAX_AUDIO_BASE64),
137221
137120
  mimeType: z.string().max(128).optional()
137222
137121
  }),
137122
+ // Read-only snapshots and the abort RPC are reachable over the remote (WS)
137123
+ // bridge — they carry free-form ids/workspaceId, so bound them like the
137124
+ // sibling validated commands so a hostile remote can't OOM/log-bloat the host
137125
+ // with an oversized string. All currently-valid payloads (a short turn id, an
137126
+ // optional workspace slug, an optional desk id, or no arg at all) still pass.
137127
+ "session.info": z.object({ workspaceId: optionalWorkspace }).optional(),
137128
+ "session.abortTurn": z.object({
137129
+ workspaceId: optionalWorkspace,
137130
+ turnId: z.string().min(1).max(256)
137131
+ }),
137132
+ "sessions.list": z.object({ deskId: z.string().min(1).max(256).optional() }).optional(),
137223
137133
  "session.setProvider": z.object({ workspaceId: optionalWorkspace, provider: providerName }),
137224
137134
  "session.setMode": z.object({ workspaceId: optionalWorkspace, mode: z.string().min(1).max(64) }),
137225
137135
  "session.newSession": z.object({ workspaceId: optionalWorkspace }),
@@ -137612,8 +137522,8 @@ var MobileSessionHost = class {
137612
137522
  for (const controller of this.turns.values())
137613
137523
  controller.abort();
137614
137524
  this.turns.clear();
137615
- for (const resolve12 of this.pendingAsks.values())
137616
- resolve12({ mode: "deny" });
137525
+ for (const resolve13 of this.pendingAsks.values())
137526
+ resolve13({ mode: "deny" });
137617
137527
  this.pendingAsks.clear();
137618
137528
  this.session.setApprovalResolver(null);
137619
137529
  }
@@ -137663,17 +137573,17 @@ var MobileSessionHost = class {
137663
137573
  }
137664
137574
  openAsk(req) {
137665
137575
  const requestId = `ask-${++this.askCounter}`;
137666
- return new Promise((resolve12) => {
137667
- this.pendingAsks.set(requestId, resolve12);
137576
+ return new Promise((resolve13) => {
137577
+ this.pendingAsks.set(requestId, resolve13);
137668
137578
  this.bus.broadcast("ask.request", { ...req, requestId });
137669
137579
  });
137670
137580
  }
137671
137581
  answerAsk(requestId, response) {
137672
- const resolve12 = this.pendingAsks.get(requestId);
137673
- if (!resolve12)
137582
+ const resolve13 = this.pendingAsks.get(requestId);
137583
+ if (!resolve13)
137674
137584
  return;
137675
137585
  this.pendingAsks.delete(requestId);
137676
- resolve12(response);
137586
+ resolve13(response);
137677
137587
  }
137678
137588
  };
137679
137589
  var TOKEN_FILE = "mobile-token";
@@ -137885,8 +137795,8 @@ var MobileChannel = class {
137885
137795
  const loopbackOnly = !tunnelUrl && isLoopbackHost(this.bindHost);
137886
137796
  await printConnectInfo(connectUrl, this.token, loopbackOnly ? "Bound to loopback \u2014 this QR only works on THIS machine (e.g. an iOS/Android\n simulator). For a real phone: opt in to a LAN bind with MOXXY_MOBILE_HOST=0.0.0.0\n (or channels.mobile.bindHost in moxxy.config.ts), or use a tunnel\n (channels.mobile.tunnel: 'cloudflared' | 'ngrok', or MOXXY_MOBILE_TUNNEL)." : void 0);
137887
137797
  let resolveRunning;
137888
- const running = new Promise((resolve12) => {
137889
- resolveRunning = resolve12;
137798
+ const running = new Promise((resolve13) => {
137799
+ resolveRunning = resolve13;
137890
137800
  });
137891
137801
  return {
137892
137802
  running,
@@ -138352,9 +138262,6 @@ var Sidecar = class {
138352
138262
  * install-progress feedback in their own logger/UI. A Set (not a single
138353
138263
  * slot) so concurrent browser_session calls don't clobber each other. */
138354
138264
  stderrListeners = /* @__PURE__ */ new Set();
138355
- /** Listeners for unsolicited sidecar EVENT lines (no `id`) — the browser
138356
- * surface's screencast frame push. */
138357
- eventListeners = /* @__PURE__ */ new Set();
138358
138265
  /** Last few sidecar stderr lines, kept so the `exit` handler can put the
138359
138266
  * ACTUAL failure (e.g. "Cannot find module …" or Playwright's "Executable
138360
138267
  * doesn't exist, run npx playwright install") into the error instead of a
@@ -138369,12 +138276,6 @@ var Sidecar = class {
138369
138276
  this.stderrListeners.add(fn);
138370
138277
  return () => this.stderrListeners.delete(fn);
138371
138278
  }
138372
- /** Subscribe to unsolicited sidecar EVENT lines (no `id`) — e.g. the browser
138373
- * surface's `screencastFrame` push. Returns an unsubscribe function. */
138374
- onEvent(fn) {
138375
- this.eventListeners.add(fn);
138376
- return () => this.eventListeners.delete(fn);
138377
- }
138378
138279
  async ensure() {
138379
138280
  if (this.child)
138380
138281
  return;
@@ -138433,15 +138334,6 @@ ${tail}` : " (no stderr captured)")
138433
138334
  } catch {
138434
138335
  return;
138435
138336
  }
138436
- if (reply2.event && !reply2.id) {
138437
- for (const fn of this.eventListeners) {
138438
- try {
138439
- fn(reply2);
138440
- } catch {
138441
- }
138442
- }
138443
- return;
138444
- }
138445
138337
  const p3 = reply2.id ? this.pending.get(reply2.id) : void 0;
138446
138338
  if (!p3 || !reply2.id)
138447
138339
  return;
@@ -138464,7 +138356,7 @@ ${tail}` : " (no stderr captured)")
138464
138356
  throw new MoxxyError({ code: "NETWORK_ABORTED", message: "browser_session aborted" });
138465
138357
  const id = randomUUID();
138466
138358
  const req = { id, method, params };
138467
- return new Promise((resolve12, reject) => {
138359
+ return new Promise((resolve13, reject) => {
138468
138360
  const onAbort = () => {
138469
138361
  if (this.pending.delete(id))
138470
138362
  reject(new MoxxyError({ code: "NETWORK_ABORTED", message: "browser_session aborted" }));
@@ -138473,7 +138365,7 @@ ${tail}` : " (no stderr captured)")
138473
138365
  this.pending.set(id, {
138474
138366
  resolve: (v3) => {
138475
138367
  cleanup();
138476
- resolve12(v3);
138368
+ resolve13(v3);
138477
138369
  },
138478
138370
  reject: (e3) => {
138479
138371
  cleanup();
@@ -138648,7 +138540,12 @@ function buildBrowserSurface(deps) {
138648
138540
  const vw = last?.width ?? 1280;
138649
138541
  const vh = last?.height ?? 720;
138650
138542
  if (msg.type === "navigate" && typeof msg.url === "string") {
138651
- await browserSidecarCall("goto", { url: msg.url }, deps).catch(() => void 0);
138543
+ try {
138544
+ await browserSidecarCall("goto", { url: msg.url }, deps);
138545
+ } catch (err) {
138546
+ const text = err instanceof Error ? err.message : String(err);
138547
+ emit2({ type: "status", text });
138548
+ }
138652
138549
  void tick();
138653
138550
  } else if (msg.type === "click" && typeof msg.fx === "number" && typeof msg.fy === "number") {
138654
138551
  await browserSidecarCall("mouse", { x: msg.fx * vw, y: msg.fy * vh }, deps).catch(() => void 0);
@@ -138876,7 +138773,7 @@ function buildTerminalTool() {
138876
138773
  });
138877
138774
  }
138878
138775
  function runCommand(proc, command, marker, timeoutMs) {
138879
- return new Promise((resolve12) => {
138776
+ return new Promise((resolve13) => {
138880
138777
  let acc = "";
138881
138778
  let settled = false;
138882
138779
  const finish = (exitCode, timedOut) => {
@@ -138885,7 +138782,7 @@ function runCommand(proc, command, marker, timeoutMs) {
138885
138782
  settled = true;
138886
138783
  unsub();
138887
138784
  clearTimeout(timer);
138888
- resolve12({ output: cleanOutput(acc, command, marker), exitCode, timedOut });
138785
+ resolve13({ output: cleanOutput(acc, command, marker), exitCode, timedOut });
138889
138786
  };
138890
138787
  const unsub = proc.onData((d2) => {
138891
138788
  acc += d2;
@@ -139032,7 +138929,7 @@ async function installPluginPackage(opts) {
139032
138929
  await ensurePackageJson(dir);
139033
138930
  const { exitCode, stderr } = await runNpm(["install", "--prefix", dir, "--no-fund", "--no-audit", "--save", spec], opts.signal);
139034
138931
  if (exitCode !== 0) {
139035
- throw new Error(`npm install failed (exit ${exitCode}): ${truncate9(stderr, 400)}`);
138932
+ throw new Error(`npm install failed (exit ${exitCode}): ${truncate6(stderr, 400)}`);
139036
138933
  }
139037
138934
  return { installed: spec, dir };
139038
138935
  }
@@ -139042,7 +138939,7 @@ async function removePluginPackage(opts) {
139042
138939
  await ensurePackageJson(dir);
139043
138940
  const { exitCode, stderr } = await runNpm(["uninstall", "--prefix", dir, "--no-fund", "--no-audit", "--save", spec], opts.signal);
139044
138941
  if (exitCode !== 0) {
139045
- throw new Error(`npm uninstall failed (exit ${exitCode}): ${truncate9(stderr, 400)}`);
138942
+ throw new Error(`npm uninstall failed (exit ${exitCode}): ${truncate6(stderr, 400)}`);
139046
138943
  }
139047
138944
  return { removed: spec, dir };
139048
138945
  }
@@ -139131,7 +139028,7 @@ async function ensurePackageJson(dir) {
139131
139028
  }
139132
139029
  }
139133
139030
  function runNpm(args, signal) {
139134
- return new Promise((resolve12, reject) => {
139031
+ return new Promise((resolve13, reject) => {
139135
139032
  if (signal?.aborted) {
139136
139033
  reject(new Error("npm aborted before start"));
139137
139034
  return;
@@ -139157,11 +139054,11 @@ function runNpm(args, signal) {
139157
139054
  });
139158
139055
  child.on("close", (code) => {
139159
139056
  signal?.removeEventListener("abort", onAbort);
139160
- resolve12({ exitCode: code ?? -1, stdout, stderr });
139057
+ resolve13({ exitCode: code ?? -1, stdout, stderr });
139161
139058
  });
139162
139059
  });
139163
139060
  }
139164
- function truncate9(s2, n2) {
139061
+ function truncate6(s2, n2) {
139165
139062
  return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "\u2026";
139166
139063
  }
139167
139064
  function buildDisablePluginTool(deps) {
@@ -139311,6 +139208,7 @@ function buildSearchPluginsTool(opts = {}) {
139311
139208
  });
139312
139209
  }
139313
139210
  var import_yaml = __toESM(require_dist());
139211
+ var configMutex2 = createMutex();
139314
139212
  function defaultUserConfigPath() {
139315
139213
  return moxxyPath("config.yaml");
139316
139214
  }
@@ -139325,21 +139223,27 @@ async function loadDisabledPackageNames(opts = {}) {
139325
139223
  }
139326
139224
  async function setPluginEnabled(packageName, enabled, opts = {}) {
139327
139225
  const configPath = opts.configPath ?? defaultUserConfigPath();
139328
- const config = await readUserConfig(configPath);
139329
- const plugins = { ...config.plugins ?? {} };
139330
- plugins[packageName] = { ...plugins[packageName] ?? {}, enabled };
139331
- await writeUserConfig(configPath, { ...config, plugins });
139226
+ await configMutex2.run(async () => {
139227
+ const config = await readUserConfig(configPath);
139228
+ const plugins = { ...config.plugins ?? {} };
139229
+ plugins[packageName] = { ...plugins[packageName] ?? {}, enabled };
139230
+ await writeUserConfig(configPath, { ...config, plugins });
139231
+ });
139332
139232
  }
139333
139233
  async function clearPluginState(packageName, opts = {}) {
139334
139234
  const configPath = opts.configPath ?? defaultUserConfigPath();
139335
- const config = await readUserConfig(configPath);
139336
- if (!config.plugins || !(packageName in config.plugins))
139337
- return;
139338
- const plugins = { ...config.plugins };
139339
- delete plugins[packageName];
139340
- await writeUserConfig(configPath, {
139341
- ...config,
139342
- ...Object.keys(plugins).length > 0 ? { plugins } : { plugins: void 0 }
139235
+ await configMutex2.run(async () => {
139236
+ const config = await readUserConfig(configPath);
139237
+ if (!config.plugins || !(packageName in config.plugins))
139238
+ return;
139239
+ const plugins = { ...config.plugins };
139240
+ delete plugins[packageName];
139241
+ const next = { ...config };
139242
+ if (Object.keys(plugins).length > 0)
139243
+ next.plugins = plugins;
139244
+ else
139245
+ delete next.plugins;
139246
+ await writeUserConfig(configPath, next);
139343
139247
  });
139344
139248
  }
139345
139249
  async function readUserConfig(configPath) {
@@ -139386,21 +139290,11 @@ function buildPluginsAdminPlugin(opts) {
139386
139290
  }
139387
139291
  function buildProviderDef(entry) {
139388
139292
  if (entry.kind === "openai-compat") {
139389
- return defineProvider({
139293
+ return defineOpenAICompatProvider({
139390
139294
  name: entry.name,
139391
- models: entry.models,
139392
- createClient: (config) => new OpenAIProvider({
139393
- ...config,
139394
- // The vendor's registered slug, NOT 'openai' — usage stats,
139395
- // provider_request/response events and error context all read
139396
- // `provider.name`, so without this every runtime vendor was
139397
- // misattributed to OpenAI.
139398
- name: entry.name,
139399
- baseURL: entry.baseURL,
139400
- defaultModel: entry.defaultModel,
139401
- models: entry.models
139402
- }),
139403
- validateKey: (key) => validateKey2(key, { baseURL: entry.baseURL })
139295
+ baseURL: entry.baseURL,
139296
+ defaultModel: entry.defaultModel,
139297
+ models: entry.models
139404
139298
  });
139405
139299
  }
139406
139300
  throw new MoxxyError({
@@ -139441,9 +139335,9 @@ async function readProvidersConfig(filePath = providersConfigPath()) {
139441
139335
  async function writeProvidersConfig(cfg, filePath = providersConfigPath()) {
139442
139336
  await writeFileAtomic(filePath, JSON.stringify(cfg, null, 2) + "\n");
139443
139337
  }
139444
- var writeMutex = createMutex();
139338
+ var writeMutex3 = createMutex();
139445
139339
  async function upsertStoredProvider(entry, filePath = providersConfigPath()) {
139446
- return writeMutex.run(async () => {
139340
+ return writeMutex3.run(async () => {
139447
139341
  const cfg = await readProvidersConfig(filePath);
139448
139342
  const next = cfg.providers.filter((p3) => p3.name !== entry.name);
139449
139343
  next.push(entry);
@@ -139453,7 +139347,7 @@ async function upsertStoredProvider(entry, filePath = providersConfigPath()) {
139453
139347
  });
139454
139348
  }
139455
139349
  async function removeStoredProvider(name, filePath = providersConfigPath()) {
139456
- return writeMutex.run(async () => {
139350
+ return writeMutex3.run(async () => {
139457
139351
  const cfg = await readProvidersConfig(filePath);
139458
139352
  const next = cfg.providers.filter((p3) => p3.name !== name);
139459
139353
  if (next.length === cfg.providers.length)
@@ -139477,6 +139371,15 @@ async function storedProviderApiKeyName(providerName2, configPath) {
139477
139371
  }
139478
139372
 
139479
139373
  // ../plugin-provider-admin/dist/index.js
139374
+ function getWarnLogger(ctx) {
139375
+ if (typeof ctx !== "object" || ctx === null)
139376
+ return void 0;
139377
+ const candidate = ctx.logger;
139378
+ if (typeof candidate === "object" && candidate !== null && typeof candidate.warn === "function") {
139379
+ return candidate;
139380
+ }
139381
+ return void 0;
139382
+ }
139480
139383
  var PROVIDER_NAME_RE = /^[a-z][a-z0-9-]*$/;
139481
139384
  var providerNameSchema = z$1.string().min(1).max(60).regex(PROVIDER_NAME_RE, "name must be slug-like (lowercase letters, digits, hyphens; must start with a letter)");
139482
139385
  var modelDescriptorSchema = z$1.object({
@@ -139511,8 +139414,15 @@ var testProviderInput = z$1.object({
139511
139414
  });
139512
139415
  function buildProviderAdminPluginWithApi(opts) {
139513
139416
  const { providerRegistry, configPath } = opts;
139417
+ const builtinNames = reservedBuiltinNames(providerRegistry);
139514
139418
  const api = {
139515
139419
  configure: async (name, patch) => {
139420
+ if (builtinNames.has(name)) {
139421
+ throw new MoxxyError({
139422
+ code: "CONFIG_INVALID",
139423
+ message: `provider-admin: "${name}" is a built-in provider and cannot be reconfigured here \u2014 built-ins are code. Only runtime-registered (providers.json) providers are editable.`
139424
+ });
139425
+ }
139516
139426
  const cfg = await readProvidersConfig(configPath);
139517
139427
  const entry = cfg.providers.find((p3) => p3.name === name);
139518
139428
  if (!entry) {
@@ -139554,8 +139464,12 @@ function buildProviderAdminPluginWithApi(opts) {
139554
139464
  };
139555
139465
  return { plugin: buildProviderAdminPlugin(opts), api };
139556
139466
  }
139467
+ function reservedBuiltinNames(providerRegistry) {
139468
+ return new Set(providerRegistry.list().map((p3) => p3.name));
139469
+ }
139557
139470
  function buildProviderAdminPlugin(opts) {
139558
139471
  const { providerRegistry, configPath } = opts;
139472
+ const builtinNames = reservedBuiltinNames(providerRegistry);
139559
139473
  return definePlugin({
139560
139474
  name: "@moxxy/plugin-provider-admin",
139561
139475
  version: "0.0.0",
@@ -139566,6 +139480,12 @@ function buildProviderAdminPlugin(opts) {
139566
139480
  inputSchema: addProviderInput,
139567
139481
  permission: { action: "prompt" },
139568
139482
  handler: async (input) => {
139483
+ if (builtinNames.has(input.name)) {
139484
+ throw new MoxxyError({
139485
+ code: "CONFIG_INVALID",
139486
+ message: `provider_add: "${input.name}" is a built-in provider and cannot be shadowed or redirected. Pick a different slug for your OpenAI-compatible vendor (e.g. "${input.name}-compat").`
139487
+ });
139488
+ }
139569
139489
  const entry = {
139570
139490
  kind: "openai-compat",
139571
139491
  name: input.name,
@@ -139671,18 +139591,22 @@ function buildProviderAdminPlugin(opts) {
139671
139591
  ],
139672
139592
  hooks: {
139673
139593
  onInit: async (ctx) => {
139674
- const log = ctx.logger;
139594
+ const log = getWarnLogger(ctx);
139675
139595
  let cfg;
139676
139596
  try {
139677
139597
  cfg = await readProvidersConfig(configPath);
139678
139598
  } catch (err) {
139679
- log?.warn?.("provider-admin: failed to read providers.json", {
139599
+ log?.warn("provider-admin: failed to read providers.json", {
139680
139600
  err: err instanceof Error ? err.message : String(err)
139681
139601
  });
139682
139602
  return;
139683
139603
  }
139684
139604
  for (const entry of cfg.providers) {
139685
139605
  try {
139606
+ if (builtinNames.has(entry.name)) {
139607
+ log?.warn(`provider-admin: skipping stored provider "${entry.name}" \u2014 it collides with a built-in`);
139608
+ continue;
139609
+ }
139686
139610
  const def = buildProviderDef(entry);
139687
139611
  const already = providerRegistry.list().some((p3) => p3.name === entry.name);
139688
139612
  if (already)
@@ -139690,7 +139614,7 @@ function buildProviderAdminPlugin(opts) {
139690
139614
  else
139691
139615
  providerRegistry.register(def);
139692
139616
  } catch (err) {
139693
- log?.warn?.(`provider-admin: failed to register "${entry.name}"`, {
139617
+ log?.warn(`provider-admin: failed to register "${entry.name}"`, {
139694
139618
  err: err instanceof Error ? err.message : String(err)
139695
139619
  });
139696
139620
  }
@@ -139867,11 +139791,6 @@ function trimFixed2(value) {
139867
139791
  function plural2(count, noun) {
139868
139792
  return count === 1 ? noun : `${noun}s`;
139869
139793
  }
139870
- function countNodes2(node) {
139871
- if (node.kind === "text")
139872
- return 1;
139873
- return 1 + node.children.reduce((sum, c2) => sum + countNodes2(c2), 0);
139874
- }
139875
139794
  function buildViewPlugin(opts) {
139876
139795
  const presentView = defineTool({
139877
139796
  name: "present_view",
@@ -139896,7 +139815,7 @@ function buildViewPlugin(opts) {
139896
139815
  rendered: surface != null,
139897
139816
  ...surface?.url ? { url: surface.url } : {},
139898
139817
  ...viewId ? { viewId } : {},
139899
- nodeCount: countNodes2(result.doc.root),
139818
+ nodeCount: countNodes(result.doc.root),
139900
139819
  ast: result.doc
139901
139820
  };
139902
139821
  }
@@ -139909,7 +139828,7 @@ function buildViewPlugin(opts) {
139909
139828
  }
139910
139829
  var IS_DARWIN = process.platform === "darwin";
139911
139830
  function runProcess(cmd, args, opts = {}) {
139912
- return new Promise((resolve12, reject) => {
139831
+ return new Promise((resolve13, reject) => {
139913
139832
  const child = spawn(cmd, [...args], { stdio: ["pipe", "pipe", "pipe"] });
139914
139833
  let stdout = Buffer.alloc(0);
139915
139834
  let stderr = "";
@@ -139953,7 +139872,7 @@ function runProcess(cmd, args, opts = {}) {
139953
139872
  if (timer)
139954
139873
  clearTimeout(timer);
139955
139874
  opts.signal?.removeEventListener("abort", onAbort);
139956
- resolve12({
139875
+ resolve13({
139957
139876
  exitCode: code ?? -1,
139958
139877
  stdout: stdout.toString("utf8"),
139959
139878
  stderr
@@ -141499,14 +141418,14 @@ var WebhookServer = class {
141499
141418
  });
141500
141419
  });
141501
141420
  this.server = server;
141502
- await new Promise((resolve12, reject) => {
141421
+ await new Promise((resolve13, reject) => {
141503
141422
  server.once("error", reject);
141504
141423
  server.listen(this.opts.port, this.opts.host, () => {
141505
141424
  this.opts.logger?.info?.("webhooks: listening", {
141506
141425
  host: this.opts.host,
141507
141426
  port: this.opts.port
141508
141427
  });
141509
- resolve12();
141428
+ resolve13();
141510
141429
  });
141511
141430
  });
141512
141431
  return {
@@ -141520,7 +141439,7 @@ var WebhookServer = class {
141520
141439
  return;
141521
141440
  const s2 = this.server;
141522
141441
  this.server = null;
141523
- await new Promise((resolve12) => s2.close(() => resolve12()));
141442
+ await new Promise((resolve13) => s2.close(() => resolve13()));
141524
141443
  }
141525
141444
  async handle(req, res) {
141526
141445
  const url2 = req.url ?? "/";
@@ -142715,23 +142634,34 @@ var inprocIsolator = {
142715
142634
  }
142716
142635
  if (caps.timeMs === void 0)
142717
142636
  return handler(call.input);
142718
- return new Promise((resolve12, reject) => {
142637
+ const internal = new AbortController();
142638
+ const handlerSignal = internal.signal;
142639
+ const onExternalAbort = () => {
142640
+ if (!internal.signal.aborted) {
142641
+ internal.abort(signal.reason ?? new Error(`[security:inproc] tool '${call.toolName}' aborted`));
142642
+ }
142643
+ };
142644
+ return new Promise((resolve13, reject) => {
142719
142645
  if (signal.aborted) {
142646
+ onExternalAbort();
142720
142647
  reject(new Error(`[security:inproc] tool '${call.toolName}' aborted`));
142721
142648
  return;
142722
142649
  }
142723
142650
  const timer = setTimeout(() => {
142724
- reject(new Error(`[security:inproc] tool '${call.toolName}' exceeded ${caps.timeMs}ms budget`));
142651
+ const budgetErr = new Error(`[security:inproc] tool '${call.toolName}' exceeded ${caps.timeMs}ms budget`);
142652
+ internal.abort(budgetErr);
142653
+ reject(budgetErr);
142725
142654
  }, caps.timeMs);
142726
142655
  const onAbort = () => {
142727
142656
  clearTimeout(timer);
142657
+ onExternalAbort();
142728
142658
  reject(new Error(`[security:inproc] tool '${call.toolName}' aborted`));
142729
142659
  };
142730
142660
  signal.addEventListener("abort", onAbort, { once: true });
142731
- handler(call.input).then((out) => {
142661
+ runHandler(handler, call.input, handlerSignal).then((out) => {
142732
142662
  clearTimeout(timer);
142733
142663
  signal.removeEventListener("abort", onAbort);
142734
- resolve12(out);
142664
+ resolve13(out);
142735
142665
  }, (err) => {
142736
142666
  clearTimeout(timer);
142737
142667
  signal.removeEventListener("abort", onAbort);
@@ -142740,6 +142670,9 @@ var inprocIsolator = {
142740
142670
  });
142741
142671
  }
142742
142672
  };
142673
+ function runHandler(handler, input, signal) {
142674
+ return Promise.resolve(handler(input, signal));
142675
+ }
142743
142676
 
142744
142677
  // ../plugin-security/dist/registry.js
142745
142678
  var IsolatorRegistry2 = class {
@@ -142760,6 +142693,8 @@ var IsolatorRegistry2 = class {
142760
142693
  return [...this.impls.values()];
142761
142694
  }
142762
142695
  };
142696
+ var MAX_BROKER_OUTPUT_BYTES = 8 * 1024 * 1024;
142697
+ var MAX_FETCH_REDIRECTS = 5;
142763
142698
  var BLOCKED_HANDLER_MODULES = Object.freeze([
142764
142699
  "node:fs",
142765
142700
  "node:fs/promises",
@@ -142828,16 +142763,78 @@ async function dispatch2(req, ctx) {
142828
142763
  }
142829
142764
  }
142830
142765
  }
142766
+ async function realpathInScope(filePath, caps, cwd2, mode, label3) {
142767
+ if (!pathInScope(filePath, caps.fs, cwd2, mode)) {
142768
+ throw new Error(`[${label3}] path '${filePath}' is outside the tool's declared fs.${mode} capability`);
142769
+ }
142770
+ const abs = path3.isAbsolute(filePath) ? path3.normalize(filePath) : path3.resolve(cwd2, filePath);
142771
+ let real;
142772
+ try {
142773
+ real = await promises.realpath(abs);
142774
+ } catch {
142775
+ real = await realpathDeepest(abs);
142776
+ }
142777
+ if (real === abs)
142778
+ return real;
142779
+ const globs = mode === "read" ? caps.fs?.read : caps.fs?.write;
142780
+ const allowed = await canonicalScopeRoots(globs ?? [], cwd2);
142781
+ if (!allowed.some((root) => isWithin(real, root))) {
142782
+ throw new Error(`[${label3}] path '${filePath}' resolves (via symlink) to '${real}', outside the tool's declared fs.${mode} capability`);
142783
+ }
142784
+ return real;
142785
+ }
142786
+ async function canonicalScopeRoots(globs, cwd2) {
142787
+ const roots = [];
142788
+ for (const glob of globs) {
142789
+ const expanded = expandPattern(glob, cwd2);
142790
+ const wildcard = expanded.search(/[*?[]/);
142791
+ const literal3 = wildcard === -1 ? expanded : expanded.slice(0, wildcard);
142792
+ const base2 = literal3.endsWith(path3.sep) ? literal3.slice(0, -1) : path3.dirname(literal3);
142793
+ const normalized = path3.normalize(base2 || path3.sep);
142794
+ try {
142795
+ roots.push(await promises.realpath(normalized));
142796
+ } catch {
142797
+ roots.push(await realpathDeepest(normalized));
142798
+ }
142799
+ }
142800
+ return roots;
142801
+ }
142802
+ function expandPattern(pattern, cwd2) {
142803
+ if (pattern.startsWith("$cwd"))
142804
+ return path3.normalize(cwd2 + pattern.slice("$cwd".length));
142805
+ if (pattern.startsWith("~/")) {
142806
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
142807
+ return path3.normalize(home + pattern.slice(1));
142808
+ }
142809
+ return path3.isAbsolute(pattern) ? path3.normalize(pattern) : path3.resolve(cwd2, pattern);
142810
+ }
142811
+ function isWithin(child, root) {
142812
+ if (child === root)
142813
+ return true;
142814
+ const withSep = root.endsWith(path3.sep) ? root : root + path3.sep;
142815
+ return child.startsWith(withSep);
142816
+ }
142817
+ async function realpathDeepest(abs) {
142818
+ const parts = abs.split(path3.sep);
142819
+ for (let i2 = parts.length; i2 > 0; i2--) {
142820
+ const candidate = parts.slice(0, i2).join(path3.sep) || path3.sep;
142821
+ try {
142822
+ const real = await promises.realpath(candidate);
142823
+ const remainder = parts.slice(i2);
142824
+ return remainder.length ? path3.join(real, ...remainder) : real;
142825
+ } catch {
142826
+ }
142827
+ }
142828
+ return abs;
142829
+ }
142831
142830
  async function brokerReadFile(args, { caps, cwd: cwd2 }) {
142832
142831
  const filePath = args[0];
142833
142832
  if (typeof filePath !== "string") {
142834
142833
  throw new Error("[broker:fs.readFile] expected (path: string) at args[0]");
142835
142834
  }
142836
- if (!pathInScope(filePath, caps.fs, cwd2, "read")) {
142837
- throw new Error(`[broker:fs.readFile] path '${filePath}' is outside the tool's declared fs.read capability`);
142838
- }
142835
+ const real = await realpathInScope(filePath, caps, cwd2, "read", "broker:fs.readFile");
142839
142836
  const opts = args[1] ?? {};
142840
- const buf = await promises.readFile(filePath);
142837
+ const buf = await promises.readFile(real);
142841
142838
  return buf.toString(opts.encoding ?? "utf8");
142842
142839
  }
142843
142840
  async function brokerWriteFile(args, { caps, cwd: cwd2 }) {
@@ -142849,31 +142846,25 @@ async function brokerWriteFile(args, { caps, cwd: cwd2 }) {
142849
142846
  if (typeof data !== "string") {
142850
142847
  throw new Error("[broker:fs.writeFile] expected (data: string) at args[1]");
142851
142848
  }
142852
- if (!pathInScope(filePath, caps.fs, cwd2, "write")) {
142853
- throw new Error(`[broker:fs.writeFile] path '${filePath}' is outside the tool's declared fs.write capability`);
142854
- }
142855
- await promises.mkdir(path3.dirname(filePath), { recursive: true });
142856
- await promises.writeFile(filePath, data, "utf8");
142849
+ const real = await realpathInScope(filePath, caps, cwd2, "write", "broker:fs.writeFile");
142850
+ await promises.mkdir(path3.dirname(real), { recursive: true });
142851
+ await promises.writeFile(real, data, "utf8");
142857
142852
  }
142858
142853
  async function brokerReaddir(args, { caps, cwd: cwd2 }) {
142859
142854
  const dirPath = args[0];
142860
142855
  if (typeof dirPath !== "string") {
142861
142856
  throw new Error("[broker:fs.readdir] expected (path: string) at args[0]");
142862
142857
  }
142863
- if (!pathInScope(dirPath, caps.fs, cwd2, "read")) {
142864
- throw new Error(`[broker:fs.readdir] path '${dirPath}' is outside the tool's declared fs.read capability`);
142865
- }
142866
- return await promises.readdir(dirPath);
142858
+ const real = await realpathInScope(dirPath, caps, cwd2, "read", "broker:fs.readdir");
142859
+ return await promises.readdir(real);
142867
142860
  }
142868
142861
  async function brokerStat(args, { caps, cwd: cwd2 }) {
142869
142862
  const filePath = args[0];
142870
142863
  if (typeof filePath !== "string") {
142871
142864
  throw new Error("[broker:fs.stat] expected (path: string) at args[0]");
142872
142865
  }
142873
- if (!pathInScope(filePath, caps.fs, cwd2, "read")) {
142874
- throw new Error(`[broker:fs.stat] path '${filePath}' is outside the tool's declared fs.read capability`);
142875
- }
142876
- const st3 = await promises.stat(filePath);
142866
+ const real = await realpathInScope(filePath, caps, cwd2, "read", "broker:fs.stat");
142867
+ const st3 = await promises.stat(real);
142877
142868
  return {
142878
142869
  size: st3.size,
142879
142870
  mtimeMs: st3.mtimeMs,
@@ -142890,13 +142881,34 @@ async function brokerFetch(args, { caps, signal }) {
142890
142881
  throw new Error(`[broker:fetch] URL '${url2}' is outside the tool's declared net capability`);
142891
142882
  }
142892
142883
  const init3 = args[1] ?? {};
142893
- const res = await fetch(url2, {
142894
- method: init3.method ?? "GET",
142895
- ...init3.headers ? { headers: init3.headers } : {},
142896
- ...init3.body !== void 0 ? { body: init3.body } : {},
142897
- signal
142898
- });
142899
- const body = await res.text();
142884
+ let current = url2;
142885
+ let res;
142886
+ for (let hop = 0; ; hop++) {
142887
+ res = await fetch(current, {
142888
+ method: init3.method ?? "GET",
142889
+ ...init3.headers ? { headers: init3.headers } : {},
142890
+ ...init3.body !== void 0 ? { body: init3.body } : {},
142891
+ redirect: "manual",
142892
+ signal
142893
+ });
142894
+ const location = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
142895
+ if (!location)
142896
+ break;
142897
+ if (hop >= MAX_FETCH_REDIRECTS) {
142898
+ throw new Error(`[broker:fetch] too many redirects (>${MAX_FETCH_REDIRECTS}) starting from '${url2}'`);
142899
+ }
142900
+ let next;
142901
+ try {
142902
+ next = new URL(location, current).toString();
142903
+ } catch {
142904
+ throw new Error(`[broker:fetch] redirect to unparseable Location '${location}'`);
142905
+ }
142906
+ if (!urlInScope(next, caps.net)) {
142907
+ throw new Error(`[broker:fetch] redirect target '${next}' is outside the tool's declared net capability`);
142908
+ }
142909
+ current = next;
142910
+ }
142911
+ const body = await readBodyCapped(res, MAX_BROKER_OUTPUT_BYTES, url2);
142900
142912
  const headers = {};
142901
142913
  res.headers.forEach((v3, k3) => {
142902
142914
  headers[k3] = v3;
@@ -142908,6 +142920,30 @@ async function brokerFetch(args, { caps, signal }) {
142908
142920
  body
142909
142921
  };
142910
142922
  }
142923
+ async function readBodyCapped(res, maxBytes, url2) {
142924
+ const reader = res.body?.getReader();
142925
+ if (!reader)
142926
+ return res.text();
142927
+ const chunks = [];
142928
+ let total = 0;
142929
+ try {
142930
+ for (; ; ) {
142931
+ const { done, value } = await reader.read();
142932
+ if (done)
142933
+ break;
142934
+ if (value) {
142935
+ total += value.byteLength;
142936
+ if (total > maxBytes) {
142937
+ throw new Error(`[broker:fetch] response body from '${url2}' exceeded the ${maxBytes}-byte limit`);
142938
+ }
142939
+ chunks.push(value);
142940
+ }
142941
+ }
142942
+ } finally {
142943
+ reader.cancel().catch(() => void 0);
142944
+ }
142945
+ return Buffer.concat(chunks).toString("utf8");
142946
+ }
142911
142947
  var BROKER_DEFAULT_ENV = ["PATH", "HOME", "USER", "SHELL", "LANG", "LC_ALL", "TERM"];
142912
142948
  function buildBrokerEnv(caps, optsEnv) {
142913
142949
  const allow = caps.env ?? BROKER_DEFAULT_ENV;
@@ -142936,7 +142972,7 @@ async function brokerExec(args, { caps, cwd: cwd2, signal }) {
142936
142972
  throw new Error(`[broker:exec] command '${command}' is outside the tool's declared commands allowlist`);
142937
142973
  }
142938
142974
  }
142939
- return await new Promise((resolve12, reject) => {
142975
+ return await new Promise((resolve13, reject) => {
142940
142976
  const child = spawn(command, [...argv], {
142941
142977
  cwd: opts.cwd ?? cwd2,
142942
142978
  // Filter the parent env through the tool's `caps.env` allowlist (or a
@@ -142946,33 +142982,49 @@ async function brokerExec(args, { caps, cwd: cwd2, signal }) {
142946
142982
  env: buildBrokerEnv(caps, opts.env),
142947
142983
  stdio: ["ignore", "pipe", "pipe"]
142948
142984
  });
142949
- let out = "";
142950
- let err = "";
142951
- child.stdout.on("data", (b3) => {
142952
- out += b3.toString("utf8");
142953
- });
142954
- child.stderr.on("data", (b3) => {
142955
- err += b3.toString("utf8");
142956
- });
142985
+ const outChunks = [];
142986
+ const errChunks = [];
142987
+ let total = 0;
142988
+ let settled = false;
142957
142989
  const timer = opts.timeoutMs ? setTimeout(() => {
142958
142990
  child.kill("SIGTERM");
142959
- reject(new Error(`[broker:exec] '${command}' exceeded ${opts.timeoutMs}ms`));
142991
+ finish(() => reject(new Error(`[broker:exec] '${command}' exceeded ${opts.timeoutMs}ms`)));
142960
142992
  }, opts.timeoutMs) : null;
142961
142993
  const onAbort = () => {
142962
142994
  child.kill("SIGTERM");
142963
142995
  };
142964
- signal.addEventListener("abort", onAbort, { once: true });
142965
- child.on("error", (e3) => {
142996
+ const finish = (settle) => {
142997
+ if (settled)
142998
+ return;
142999
+ settled = true;
142966
143000
  if (timer)
142967
143001
  clearTimeout(timer);
142968
143002
  signal.removeEventListener("abort", onAbort);
142969
- reject(e3);
143003
+ settle();
143004
+ };
143005
+ const accumulate = (chunks, b3) => {
143006
+ if (settled)
143007
+ return;
143008
+ total += b3.byteLength;
143009
+ if (total > MAX_BROKER_OUTPUT_BYTES) {
143010
+ child.kill("SIGTERM");
143011
+ finish(() => reject(new Error(`[broker:exec] '${command}' output exceeded the ${MAX_BROKER_OUTPUT_BYTES}-byte limit`)));
143012
+ return;
143013
+ }
143014
+ chunks.push(b3);
143015
+ };
143016
+ child.stdout.on("data", (b3) => accumulate(outChunks, b3));
143017
+ child.stderr.on("data", (b3) => accumulate(errChunks, b3));
143018
+ signal.addEventListener("abort", onAbort, { once: true });
143019
+ child.on("error", (e3) => {
143020
+ finish(() => reject(e3));
142970
143021
  });
142971
143022
  child.on("close", (exitCode) => {
142972
- if (timer)
142973
- clearTimeout(timer);
142974
- signal.removeEventListener("abort", onAbort);
142975
- resolve12({ stdout: out, stderr: err, exitCode });
143023
+ finish(() => resolve13({
143024
+ stdout: Buffer.concat(outChunks).toString("utf8"),
143025
+ stderr: Buffer.concat(errChunks).toString("utf8"),
143026
+ exitCode
143027
+ }));
142976
143028
  });
142977
143029
  });
142978
143030
  }
@@ -142994,6 +143046,8 @@ function buildSecurityPlugin(opts) {
142994
143046
  for (const t2 of tools.list()) {
142995
143047
  if (!t2.isolation)
142996
143048
  continue;
143049
+ if (isSecurityWrapped(t2))
143050
+ continue;
142997
143051
  const wrapped = wrapWithIsolator(t2, registry, pickIsolatorName(t2.name));
142998
143052
  if (wrapped !== t2) {
142999
143053
  tools.unregister(t2.name);
@@ -143082,12 +143136,25 @@ function wrapWithIsolator(tool, registry, isolatorName) {
143082
143136
  cwd: ctx.cwd,
143083
143137
  ...moduleRef ? { moduleRef } : {}
143084
143138
  };
143085
- const bound = (i2) => Promise.resolve(tool.handler(i2, ctx));
143139
+ const bound = (i2, derived) => Promise.resolve(tool.handler(i2, derived ? { ...ctx, signal: derived } : ctx));
143086
143140
  return iso2.run(call, bound, caps, ctx.signal);
143087
143141
  }
143088
143142
  };
143143
+ markWrapped(wrapped);
143089
143144
  return wrapped;
143090
143145
  }
143146
+ var WRAPPED_MARKER = "__moxxySecurityWrapped";
143147
+ function markWrapped(tool) {
143148
+ Object.defineProperty(tool, WRAPPED_MARKER, {
143149
+ value: true,
143150
+ enumerable: false,
143151
+ configurable: true,
143152
+ writable: false
143153
+ });
143154
+ }
143155
+ function isSecurityWrapped(tool) {
143156
+ return tool[WRAPPED_MARKER] === true;
143157
+ }
143091
143158
  var SHIM_SOURCE = `
143092
143159
  const { parentPort, workerData } = await import('node:worker_threads');
143093
143160
  const { moduleUrl, exportName, input, syntheticCtx, loaderUrl } = workerData;
@@ -143104,8 +143171,21 @@ register(loaderUrl, import.meta.url);
143104
143171
  let nextId = 1;
143105
143172
  const pending = new Map();
143106
143173
 
143174
+ // Cooperative-cancel signal handed to the handler as ctx.signal. The
143175
+ // parent posts { type: 'abort' } on timeout / host-abort (before the
143176
+ // hard worker.terminate()), giving a well-behaved handler that wired
143177
+ // ctx.signal into fetch / long loops a chance to bail out and flush.
143178
+ const abortController = new AbortController();
143179
+
143107
143180
  parentPort.on('message', (msg) => {
143108
- if (msg && msg.type === 'broker-response') {
143181
+ if (!msg) return;
143182
+ if (msg.type === 'abort') {
143183
+ abortController.abort(
143184
+ new DOMException('aborted by isolator', 'AbortError'),
143185
+ );
143186
+ return;
143187
+ }
143188
+ if (msg.type === 'broker-response') {
143109
143189
  const p = pending.get(msg.id);
143110
143190
  if (!p) return;
143111
143191
  pending.delete(msg.id);
@@ -143154,7 +143234,7 @@ try {
143154
143234
  turnId: syntheticCtx.turnId,
143155
143235
  callId: syntheticCtx.callId,
143156
143236
  cwd: syntheticCtx.cwd,
143157
- signal: new AbortController().signal,
143237
+ signal: abortController.signal,
143158
143238
  log: { length: 0, at: () => undefined, slice: () => [], ofType: () => [], byTurn: () => [], toJSON: () => [] },
143159
143239
  logger: { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} },
143160
143240
  fs: broker.fs,
@@ -143210,47 +143290,63 @@ function createWorkerIsolator(opts = {}) {
143210
143290
  maxYoungGenerationSizeMb: Math.max(16, Math.floor(memMb / 4))
143211
143291
  }
143212
143292
  });
143213
- return new Promise((resolve12, reject) => {
143293
+ return new Promise((resolve13, reject) => {
143214
143294
  const cleanup = /* @__PURE__ */ new Set();
143215
143295
  let settled = false;
143216
- const finish = (action) => {
143296
+ let terminated = false;
143297
+ const hardTerminate = () => {
143298
+ terminated = true;
143299
+ void worker.terminate();
143300
+ };
143301
+ const finish = (action, graceful = false) => {
143217
143302
  if (settled)
143218
143303
  return;
143219
143304
  settled = true;
143220
143305
  cleanup.forEach((fn) => fn());
143221
143306
  cleanup.clear();
143222
143307
  action();
143223
- void worker.terminate();
143308
+ if (graceful) {
143309
+ try {
143310
+ worker.postMessage({ type: "abort" });
143311
+ } catch {
143312
+ }
143313
+ const grace = setTimeout(hardTerminate, 150);
143314
+ grace.unref?.();
143315
+ } else {
143316
+ hardTerminate();
143317
+ }
143224
143318
  };
143225
143319
  if (signal.aborted) {
143226
- finish(() => reject(new Error(`[security:worker] tool '${call.toolName}' aborted`)));
143320
+ finish(() => reject(new Error(`[security:worker] tool '${call.toolName}' aborted`)), true);
143227
143321
  return;
143228
143322
  }
143229
143323
  const timer = setTimeout(() => {
143230
- finish(() => reject(new Error(`[security:worker] tool '${call.toolName}' exceeded ${timeMs}ms budget`)));
143324
+ finish(() => reject(new Error(`[security:worker] tool '${call.toolName}' exceeded ${timeMs}ms budget`)), true);
143231
143325
  }, timeMs);
143232
143326
  cleanup.add(() => clearTimeout(timer));
143233
143327
  const onAbort = () => {
143234
- finish(() => reject(new Error(`[security:worker] tool '${call.toolName}' aborted`)));
143328
+ finish(() => reject(new Error(`[security:worker] tool '${call.toolName}' aborted`)), true);
143235
143329
  };
143236
143330
  signal.addEventListener("abort", onAbort, { once: true });
143237
143331
  cleanup.add(() => signal.removeEventListener("abort", onAbort));
143238
143332
  worker.on("message", (msg) => {
143239
- if (settled)
143240
- return;
143241
143333
  if (msg.type === "broker-request") {
143334
+ if (terminated)
143335
+ return;
143242
143336
  void handleBrokerRequest(msg, {
143243
143337
  caps,
143244
143338
  cwd: call.cwd,
143245
143339
  signal
143246
143340
  }).then((response) => {
143247
- if (!settled)
143341
+ if (!terminated)
143248
143342
  worker.postMessage(response);
143249
143343
  });
143250
143344
  return;
143251
143345
  }
143346
+ if (settled)
143347
+ return;
143252
143348
  if (msg.ok) {
143253
- finish(() => resolve12(msg.value));
143349
+ finish(() => resolve13(msg.value));
143254
143350
  } else {
143255
143351
  const e3 = new Error(msg.errorMessage);
143256
143352
  e3.name = msg.errorName;
@@ -143370,6 +143466,7 @@ async function runTask() {
143370
143466
  }
143371
143467
  `;
143372
143468
  var DEFAULT_ENV = ["PATH", "HOME", "USER", "SHELL", "LANG", "LC_ALL", "TERM"];
143469
+ var KILL_GRACE_MS = 2e3;
143373
143470
  function createSubprocessIsolator(opts = {}) {
143374
143471
  const defaultTimeMs = opts.defaultTimeMs ?? 6e4;
143375
143472
  const envAllowlist = opts.defaultEnvAllowlist ?? DEFAULT_ENV;
@@ -143394,13 +143491,16 @@ function createSubprocessIsolator(opts = {}) {
143394
143491
  env3[key] = v3;
143395
143492
  }
143396
143493
  const child = spawn(nodePath, ["--input-type=module", "-e", SHIM_SOURCE2], {
143494
+ cwd: call.cwd,
143397
143495
  env: env3,
143398
143496
  stdio: ["pipe", "pipe", "pipe"]
143399
143497
  });
143400
- return new Promise((resolve12, reject) => {
143498
+ return new Promise((resolve13, reject) => {
143401
143499
  let stderr = "";
143402
143500
  let stdoutBuffer = "";
143403
143501
  let settled = false;
143502
+ let exited = false;
143503
+ let killEscalation;
143404
143504
  const cleanup = /* @__PURE__ */ new Set();
143405
143505
  const finish = (action) => {
143406
143506
  if (settled)
@@ -143409,8 +143509,14 @@ function createSubprocessIsolator(opts = {}) {
143409
143509
  cleanup.forEach((fn) => fn());
143410
143510
  cleanup.clear();
143411
143511
  action();
143412
- if (!child.killed)
143512
+ if (!exited) {
143413
143513
  child.kill("SIGTERM");
143514
+ killEscalation = setTimeout(() => {
143515
+ if (!exited)
143516
+ child.kill("SIGKILL");
143517
+ }, KILL_GRACE_MS);
143518
+ killEscalation.unref?.();
143519
+ }
143414
143520
  };
143415
143521
  if (signal.aborted) {
143416
143522
  finish(() => reject(new Error(`[security:subprocess] tool '${call.toolName}' aborted`)));
@@ -143463,7 +143569,7 @@ function createSubprocessIsolator(opts = {}) {
143463
143569
  return;
143464
143570
  }
143465
143571
  if (msg.ok) {
143466
- finish(() => resolve12(msg.value));
143572
+ finish(() => resolve13(msg.value));
143467
143573
  } else {
143468
143574
  const e3 = new Error(msg.errorMessage);
143469
143575
  e3.name = msg.errorName;
@@ -143496,6 +143602,9 @@ function createSubprocessIsolator(opts = {}) {
143496
143602
  finish(() => reject(e3 instanceof Error ? e3 : new Error(String(e3))));
143497
143603
  });
143498
143604
  child.once("exit", (code) => {
143605
+ exited = true;
143606
+ if (killEscalation)
143607
+ clearTimeout(killEscalation);
143499
143608
  if (!settled) {
143500
143609
  const msg = stderr.trim() || `subprocess exited with code ${code}`;
143501
143610
  finish(() => reject(new Error(`[security:subprocess] '${call.toolName}': ${msg}`)));
@@ -143618,21 +143727,29 @@ function buildWasmHostImports(memoryHolder, caps, cwd2) {
143618
143727
  }
143619
143728
  },
143620
143729
  /**
143621
- * `broker_fs_write_file(pathPtr, pathLen, dataPtr, dataLen) -> i32`
143622
- * Writes UTF-8 bytes to a file. No out-pointer pair (no result data).
143623
- * Returns 0 on success, 1 on cap-deny or IO error.
143730
+ * `broker_fs_write_file(pathPtr, pathLen, dataPtr, dataLen, outPtrOut, outLenOut) -> i32`
143731
+ *
143732
+ * Slightly extended ABI (6 args instead of 4) because the write
143733
+ * carries both a path string and a data payload, and — like every
143734
+ * other bridge — surfaces a descriptive error to the caller on
143735
+ * failure. On success no result bytes are produced (the host still
143736
+ * writes a zero-length `(0, 0)` pair to the out-pointers). On
143737
+ * cap-deny or IO error the out-pointer pair points at the error
143738
+ * message bytes. Returns 0 on success, 1 on error.
143624
143739
  */
143625
- broker_fs_write_file: (pathPtr, pathLen, dataPtr, dataLen) => {
143740
+ broker_fs_write_file: (pathPtr, pathLen, dataPtr, dataLen, outPtrOut, outLenOut) => {
143626
143741
  const filePath = readStr(pathPtr, pathLen);
143627
143742
  const data = readStr(dataPtr, dataLen);
143628
- if (!pathInScope(filePath, caps.fs, cwd2, "write"))
143629
- return ERROR;
143743
+ if (!pathInScope(filePath, caps.fs, cwd2, "write")) {
143744
+ return sendErr(outPtrOut, outLenOut, `[broker:fs.writeFile] path '${filePath}' is outside the tool's declared fs.write capability`);
143745
+ }
143630
143746
  try {
143631
143747
  mkdirSync(path3.dirname(filePath), { recursive: true });
143632
143748
  writeFileSync(filePath, data, "utf8");
143749
+ writePtrPair(memOf(), outPtrOut, outLenOut, 0, 0);
143633
143750
  return SUCCESS;
143634
- } catch {
143635
- return ERROR;
143751
+ } catch (e3) {
143752
+ return sendErr(outPtrOut, outLenOut, `[broker:fs.writeFile] ${e3.message}`);
143636
143753
  }
143637
143754
  },
143638
143755
  /**
@@ -145917,7 +146034,7 @@ async function runCmd2(deps, name) {
145917
146034
  return { kind: "text", text: `${head}
145918
146035
  ${steps}
145919
146036
 
145920
- ${truncate10(result.output, 1200)}` };
146037
+ ${truncate7(result.output, 1200)}` };
145921
146038
  }
145922
146039
  async function toggleCmd(deps, name, enabled) {
145923
146040
  if (!name)
@@ -146037,7 +146154,7 @@ ${stepLines}`;
146037
146154
  return null;
146038
146155
  }
146039
146156
  }
146040
- function truncate10(s2, max) {
146157
+ function truncate7(s2, max) {
146041
146158
  return s2.length > max ? `${s2.slice(0, max)}
146042
146159
  \u2026 (truncated)` : s2;
146043
146160
  }
@@ -147877,10 +147994,7 @@ function readCache(file) {
147877
147994
  }
147878
147995
  function writeCache(file, value) {
147879
147996
  try {
147880
- mkdirSync(path3.dirname(file), { recursive: true });
147881
- const tmp = `${file}.tmp-${process.pid}`;
147882
- writeFileSync(tmp, JSON.stringify(value, null, 2));
147883
- renameSync(tmp, file);
147997
+ writeFileAtomicSync(file, JSON.stringify(value, null, 2));
147884
147998
  } catch {
147885
147999
  }
147886
148000
  }
@@ -148179,7 +148293,7 @@ function readStdinLine() {
148179
148293
  const queued = lineQueue.shift();
148180
148294
  if (queued !== void 0) return Promise.resolve(queued);
148181
148295
  if (stdinEnded) return Promise.resolve("");
148182
- return new Promise((resolve12) => lineWaiters.push(resolve12));
148296
+ return new Promise((resolve13) => lineWaiters.push(resolve13));
148183
148297
  }
148184
148298
  async function stdinLinePrompt(question, opts) {
148185
148299
  process.stdout.write(encodeLoginPrompt({ question, mask: opts?.mask === true }));
@@ -148335,8 +148449,8 @@ function titleCase(s2) {
148335
148449
  // src/commands/run-tui.ts
148336
148450
  async function killStaleRunnerAt(socketPath) {
148337
148451
  if (!existsSync(socketPath)) return;
148338
- const pid = await new Promise((resolve12) => {
148339
- if (process.platform === "win32") return resolve12(null);
148452
+ const pid = await new Promise((resolve13) => {
148453
+ if (process.platform === "win32") return resolve13(null);
148340
148454
  let out = "";
148341
148455
  try {
148342
148456
  const child = spawn("lsof", ["-t", socketPath], {
@@ -148345,13 +148459,13 @@ async function killStaleRunnerAt(socketPath) {
148345
148459
  child.stdout.on("data", (b3) => {
148346
148460
  out += b3.toString();
148347
148461
  });
148348
- child.on("error", () => resolve12(null));
148462
+ child.on("error", () => resolve13(null));
148349
148463
  child.on("close", () => {
148350
148464
  const parsed = parseInt(out.trim().split("\n")[0] ?? "", 10);
148351
- resolve12(Number.isFinite(parsed) && parsed > 0 ? parsed : null);
148465
+ resolve13(Number.isFinite(parsed) && parsed > 0 ? parsed : null);
148352
148466
  });
148353
148467
  } catch {
148354
- resolve12(null);
148468
+ resolve13(null);
148355
148469
  }
148356
148470
  });
148357
148471
  if (pid && pid !== process.pid) {
@@ -148632,6 +148746,7 @@ var HELP2 = formatHelp({
148632
148746
  ]
148633
148747
  });
148634
148748
  var AUDIT_PATH = () => path3.join(os5.homedir(), ".moxxy", "skills", ".meta", "created.jsonl");
148749
+ var auditMutex = createMutex();
148635
148750
  async function runSkillsCommand(argv) {
148636
148751
  const sub = argv.positional[0] ?? "list";
148637
148752
  if (sub === "help" || helpRequested(argv)) {
@@ -148704,7 +148819,7 @@ async function runAudit(argv) {
148704
148819
  for (const group of groups) {
148705
148820
  const header = group.length === 1 ? "" : colors.dim(` \xB7 ${group.length} similar`);
148706
148821
  process.stdout.write(`
148707
- ${colors.bold(truncate11(group[0].originatingPrompt, 80))}${header}
148822
+ ${colors.bold(truncate8(group[0].originatingPrompt, 80))}${header}
148708
148823
  `);
148709
148824
  for (const e3 of group) {
148710
148825
  process.stdout.write(
@@ -148784,20 +148899,22 @@ async function readAuditLog() {
148784
148899
  }
148785
148900
  }
148786
148901
  async function removeAuditEntry(slug) {
148787
- try {
148788
- const text = await promises.readFile(AUDIT_PATH(), "utf8");
148789
- const kept = text.split("\n").filter((line) => {
148790
- if (!line.trim()) return false;
148791
- try {
148792
- const e3 = JSON.parse(line);
148793
- return e3.slug !== slug;
148794
- } catch {
148795
- return true;
148796
- }
148797
- }).join("\n");
148798
- await promises.writeFile(AUDIT_PATH(), kept + (kept ? "\n" : ""));
148799
- } catch {
148800
- }
148902
+ await auditMutex.run(async () => {
148903
+ try {
148904
+ const text = await promises.readFile(AUDIT_PATH(), "utf8");
148905
+ const kept = text.split("\n").filter((line) => {
148906
+ if (!line.trim()) return false;
148907
+ try {
148908
+ const e3 = JSON.parse(line);
148909
+ return e3.slug !== slug;
148910
+ } catch {
148911
+ return true;
148912
+ }
148913
+ }).join("\n");
148914
+ await writeFileAtomic(AUDIT_PATH(), kept + (kept ? "\n" : ""));
148915
+ } catch {
148916
+ }
148917
+ });
148801
148918
  }
148802
148919
  function groupSimilarPrompts(entries) {
148803
148920
  const groups = [];
@@ -148820,7 +148937,7 @@ function groupSimilarPrompts(entries) {
148820
148937
  function tokenize8(s2) {
148821
148938
  return s2.toLowerCase().split(/[^a-z0-9_-]+/).filter((t2) => t2.length >= 3);
148822
148939
  }
148823
- function truncate11(s2, n2) {
148940
+ function truncate8(s2, n2) {
148824
148941
  return s2.length <= n2 ? s2 : s2.slice(0, n2 - 1) + "\u2026";
148825
148942
  }
148826
148943
  var HELP3 = `moxxy plugins new \u2014 scaffold a new user-scope plugin
@@ -152132,14 +152249,14 @@ var HELP14 = formatHelp({
152132
152249
  async function runCommand2(cmd) {
152133
152250
  const [bin, ...args] = cmd;
152134
152251
  if (!bin) return 1;
152135
- return new Promise((resolve12) => {
152252
+ return new Promise((resolve13) => {
152136
152253
  const proc = spawn(bin, args, {
152137
152254
  stdio: "inherit",
152138
152255
  // npm/pnpm/yarn/bun are `.cmd` shims on Windows — needs a shell to launch.
152139
152256
  shell: process.platform === "win32"
152140
152257
  });
152141
- proc.on("error", () => resolve12(127));
152142
- proc.on("exit", (code) => resolve12(code ?? 1));
152258
+ proc.on("error", () => resolve13(127));
152259
+ proc.on("exit", (code) => resolve13(code ?? 1));
152143
152260
  });
152144
152261
  }
152145
152262
  async function runUpdateCommand(argv, deps = {}) {