@wrongstack/core 0.5.7 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/{agent-bridge-BKNiE1VH.d.ts → agent-bridge-DaCvA_uK.d.ts} +1 -1
  2. package/dist/coordination/index.d.ts +5 -5
  3. package/dist/coordination/index.js +218 -78
  4. package/dist/coordination/index.js.map +1 -1
  5. package/dist/defaults/index.d.ts +10 -9
  6. package/dist/defaults/index.js +1127 -180
  7. package/dist/defaults/index.js.map +1 -1
  8. package/dist/{events-DPQKFX7W.d.ts → events-CzkeaVVl.d.ts} +8 -2
  9. package/dist/execution/index.d.ts +281 -5
  10. package/dist/execution/index.js +785 -3
  11. package/dist/execution/index.js.map +1 -1
  12. package/dist/extension/index.d.ts +2 -2
  13. package/dist/extension/index.js +2 -1
  14. package/dist/extension/index.js.map +1 -1
  15. package/dist/goal-store-DVCfj7Ff.d.ts +95 -0
  16. package/dist/{index-j2WyAyML.d.ts → index-BkKLQjea.d.ts} +34 -2
  17. package/dist/{index-Bf9Bpkdc.d.ts → index-i9rPR53g.d.ts} +11 -4
  18. package/dist/index.d.ts +51 -16
  19. package/dist/index.js +1506 -247
  20. package/dist/index.js.map +1 -1
  21. package/dist/infrastructure/index.d.ts +2 -2
  22. package/dist/kernel/index.d.ts +2 -2
  23. package/dist/kernel/index.js.map +1 -1
  24. package/dist/models/index.js +2 -3
  25. package/dist/models/index.js.map +1 -1
  26. package/dist/{multi-agent-Cpp7FXUl.d.ts → multi-agent-MfI6dmv-.d.ts} +30 -5
  27. package/dist/observability/index.d.ts +1 -1
  28. package/dist/{path-resolver--g_hKJ7V.d.ts → path-resolver-CWINz5XR.d.ts} +1 -1
  29. package/dist/{plan-templates-Bveo2W8n.d.ts → plan-templates-Bne1pB4d.d.ts} +6 -5
  30. package/dist/{provider-runner-hl4Il3xS.d.ts → provider-runner-CZYIzeBp.d.ts} +1 -1
  31. package/dist/sdd/index.d.ts +5 -3
  32. package/dist/sdd/index.js +102 -68
  33. package/dist/sdd/index.js.map +1 -1
  34. package/dist/security/index.js +82 -82
  35. package/dist/security/index.js.map +1 -1
  36. package/dist/skills/index.js +102 -38
  37. package/dist/skills/index.js.map +1 -1
  38. package/dist/storage/index.d.ts +3 -2
  39. package/dist/storage/index.js +134 -22
  40. package/dist/storage/index.js.map +1 -1
  41. package/dist/{tool-executor-DbAFkHdP.d.ts → tool-executor-40Q6shR-.d.ts} +1 -1
  42. package/dist/types/index.d.ts +7 -7
  43. package/dist/types/index.js +116 -103
  44. package/dist/types/index.js.map +1 -1
  45. package/dist/utils/index.js +5 -0
  46. package/dist/utils/index.js.map +1 -1
  47. package/package.json +5 -1
@@ -2,7 +2,7 @@ import { a2 as Context, h as ProviderError, v as Tool, G as ToolUseBlock, B as T
2
2
  import { a as Compactor, C as CompactReport } from './compactor-RIPuTtWK.js';
3
3
  import { a as RecoveryDecision, E as ErrorHandler, R as RetryPolicy } from './retry-policy-LKS8MHsB.js';
4
4
  import { M as ModelsRegistry } from './models-registry-Y2xbog0E.js';
5
- import { k as ToolExecutorOptions, l as ToolExecutorStrategy, m as ToolBatchResult } from './index-j2WyAyML.js';
5
+ import { k as ToolExecutorOptions, l as ToolExecutorStrategy, m as ToolBatchResult } from './index-BkKLQjea.js';
6
6
 
7
7
  interface CompactorOptions {
8
8
  preserveK?: number;
@@ -1,5 +1,5 @@
1
1
  export { A as AgentError, C as Capabilities, a as ConfigError, b as ContentBlock, E as ErrorCode, c as ErrorSeverity, d as ErrorSubsystem, F as FileSnapshot, I as ImageBlock, J as JSONSchema, M as Message, e as MessageRole, P as Permission, f as PluginError, g as Provider, h as ProviderError, i as ProviderErrorBody, R as Request, j as Response, k as ResumedSession, l as RiskTier, S as SessionData, m as SessionError, n as SessionEvent, o as SessionMetadata, p as SessionStore, q as SessionSummary, r as SessionWriter, s as StopReason, t as StreamEvent, T as TextBlock, u as ThinkingBlock, v as Tool, w as ToolCallContext, x as ToolError, y as ToolFinalEvent, z as ToolProgressEvent, B as ToolResultBlock, D as ToolStreamEvent, G as ToolUseBlock, U as Usage, W as WrongStackError, H as asBlocks, K as asText, L as isAgentError, N as isConfigError, O as isImageBlock, Q as isPluginError, V as isSessionError, X as isTextBlock, Y as isThinkingBlock, Z as isToolError, _ as isToolResultBlock, $ as isToolUseBlock, a0 as isWrongStackError, a1 as toWrongStackError } from '../context-CDRyrkKQ.js';
2
- export { P as ProviderRunner, R as RunProviderOptions } from '../provider-runner-hl4Il3xS.js';
2
+ export { P as ProviderRunner, R as RunProviderOptions } from '../provider-runner-CZYIzeBp.js';
3
3
  export { C as CONTEXT_WINDOW_MODES, a as Config, b as ConfigLoader, c as ConfigStore, d as ContextConfig, e as ContextWindowAggressiveOn, f as ContextWindowConfigLike, g as ContextWindowMode, h as ContextWindowModeId, i as ContextWindowPolicy, j as ContextWindowThresholds, D as DEFAULT_CONTEXT_WINDOW_MODE_ID, F as FeaturesConfig, L as LogConfig, M as MCPServerConfig, P as PluginConfig, k as ProviderApiKey, l as ProviderConfig, T as ToolsConfig, m as formatContextWindowModeList, n as getContextWindowMode, o as isContextWindowModeId, p as listContextWindowModes, r as resolveContextWindowPolicy } from '../config-BGGuP_Ar.js';
4
4
  export { C as CompactReport, a as Compactor } from '../compactor-RIPuTtWK.js';
5
5
  export { P as PermissionDecision, a as PermissionPolicy, T as TrustPolicy } from '../secret-scrubber-CfMdAJ_l.js';
@@ -7,20 +7,20 @@ export { C as CheckpointInfo, R as RewindResult, a as RewindResultExtended, S as
7
7
  export { A as AddAttachmentInput, a as Attachment, b as AttachmentKind, c as AttachmentMeta, d as AttachmentRef, e as AttachmentStore, D as DefaultSessionReader } from '../session-reader-CzfRA6Vk.js';
8
8
  export { D as DefaultSecretScrubber, a as DefaultSecretVault, S as SecretVaultOptions, d as decryptConfigSecrets, e as encryptConfigSecrets, m as migratePlaintextSecrets, r as rewriteConfigEncrypted } from '../secret-scrubber-BzQR5BiL.js';
9
9
  export { D as DefaultLogger, a as DefaultLoggerOptions } from '../logger-BH6AE0W9.js';
10
- export { D as DefaultPathResolver, a as DefaultTokenCounter } from '../path-resolver--g_hKJ7V.js';
10
+ export { D as DefaultPathResolver, a as DefaultTokenCounter } from '../path-resolver-CWINz5XR.js';
11
11
  export { M as MemoryEntry, a as MemoryScope, b as MemoryStore } from '../memory-CEXuo7sz.js';
12
- export { C as CompactorOptions, D as DEFAULT_RECOVERY_STRATEGIES, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, R as RecoveryStrategy, T as ToolExecutor, c as buildRecoveryStrategies } from '../tool-executor-DbAFkHdP.js';
12
+ export { C as CompactorOptions, D as DEFAULT_RECOVERY_STRATEGIES, a as DefaultErrorHandler, b as DefaultRetryPolicy, H as HybridCompactor, R as RecoveryStrategy, T as ToolExecutor, c as buildRecoveryStrategies } from '../tool-executor-40Q6shR-.js';
13
13
  export { S as SkillEntry, a as SkillLoader, b as SkillManifest } from '../skill-CxuWrsKK.js';
14
14
  export { B as BuildContext, M as ModelCapabilities, R as Renderer, S as SystemPromptBuilder } from '../system-prompt-Dl2QY1_B.js';
15
15
  export { I as InputReader, P as PromptOption } from '../input-reader-E-ffP2ee.js';
16
- export { M as MCPRegistryView, a as MetricsSinkView, P as Plugin, b as PluginAPI, c as PluginCapabilities, d as PluginDependency, e as PluginPipelines, f as ProviderFactory, g as ProviderRegistryView, S as SessionWriterView, h as SlashCommand, i as SlashCommandRegistryView, j as SystemPromptContributor, T as ToolRegistryView } from '../index-j2WyAyML.js';
16
+ export { M as MCPRegistryView, a as MetricsSinkView, P as Plugin, b as PluginAPI, c as PluginCapabilities, d as PluginDependency, e as PluginPipelines, f as ProviderFactory, g as ProviderRegistryView, S as SessionWriterView, h as SlashCommand, i as SlashCommandRegistryView, j as SystemPromptContributor, T as ToolRegistryView } from '../index-BkKLQjea.js';
17
17
  export { D as DefaultModelsRegistry, a as DefaultModelsRegistryOptions, c as classifyFamily } from '../models-registry-DqzwpBQy.js';
18
18
  export { D as DEFAULT_MODES, M as Mode, a as ModeConfig, b as ModeManifest, c as ModeStore } from '../mode-CV077NjV.js';
19
- export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-BKNiE1VH.js';
20
- export { C as CoordinatorEvents, a as CoordinatorStatus, D as DoneCondition, M as MultiAgentConfig, b as MultiAgentCoordinator, S as SpawnResult, c as SubagentConfig, d as SubagentContext, e as SubagentError, f as SubagentErrorKind, g as SubagentRunContext, h as SubagentRunOutcome, i as SubagentRunner, T as TaskDelegation, j as TaskResult, k as TaskSpec } from '../multi-agent-Cpp7FXUl.js';
19
+ export { I as InMemoryAgentBridge, a as InMemoryBridgeTransport, c as createMessage } from '../agent-bridge-DaCvA_uK.js';
20
+ export { C as CoordinatorEvents, a as CoordinatorStatus, D as DoneCondition, M as MultiAgentConfig, b as MultiAgentCoordinator, S as SpawnResult, c as SubagentConfig, d as SubagentContext, e as SubagentError, f as SubagentErrorKind, g as SubagentRunContext, h as SubagentRunOutcome, i as SubagentRunner, T as TaskDelegation, j as TaskResult, k as TaskSpec } from '../multi-agent-MfI6dmv-.js';
21
21
  export { C as CriticalPathResult, D as DEFAULT_SPEC_TEMPLATE, S as SpecAnalysis, a as SpecApiEndpoint, b as SpecRequirement, c as SpecSection, d as SpecSectionType, e as SpecStatus, f as SpecTemplate, g as SpecValidationResult, h as Specification, T as TaskAssignment, i as TaskDependency, j as TaskEdge, k as TaskFilter, l as TaskGraph, m as TaskNode, n as TaskPriority, o as TaskProgress, p as TaskSort, q as TaskStatus, r as TaskType, s as computeTaskProgress, t as findCriticalPath, u as topologicalSort } from '../task-graph-BITvWt4t.js';
22
22
  export { A as AggregateHealth, H as HealthCheck, a as HealthCheckResult, b as HealthRegistry, c as HealthStatus, M as MetricLabels, d as MetricSeries, e as MetricsSink, f as MetricsSnapshot, S as Span, T as Tracer } from '../observability-BhnVLBLS.js';
23
- import '../events-DPQKFX7W.js';
23
+ import '../events-CzkeaVVl.js';
24
24
  import '../logger-BMQgxvdy.js';
25
25
  import '../retry-policy-LKS8MHsB.js';
26
26
  import '../models-registry-Y2xbog0E.js';
@@ -1,7 +1,7 @@
1
1
  import { randomBytes, createCipheriv, createDecipheriv, randomUUID } from 'crypto';
2
- import * as fs from 'fs';
3
- import * as fs4 from 'fs/promises';
4
- import * as path3 from 'path';
2
+ import * as fs2 from 'fs';
3
+ import * as fs from 'fs/promises';
4
+ import * as path4 from 'path';
5
5
 
6
6
  // src/types/blocks.ts
7
7
  function isTextBlock(b) {
@@ -235,6 +235,67 @@ function providerStatusToCode(status, type) {
235
235
 
236
236
  // src/types/secret-vault.ts
237
237
  var ENCRYPTED_PREFIX = "enc:v1:";
238
+ async function atomicWrite(targetPath, content, opts = {}) {
239
+ const dir = path4.dirname(targetPath);
240
+ await fs.mkdir(dir, { recursive: true });
241
+ const tmp = path4.join(dir, `.${path4.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
242
+ try {
243
+ if (typeof content === "string") {
244
+ await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
245
+ } else {
246
+ await fs.writeFile(tmp, content, { flag: "wx" });
247
+ }
248
+ try {
249
+ const fh = await fs.open(tmp, "r+");
250
+ try {
251
+ await fh.sync();
252
+ } finally {
253
+ await fh.close();
254
+ }
255
+ } catch {
256
+ }
257
+ let mode;
258
+ try {
259
+ const stat2 = await fs.stat(targetPath);
260
+ mode = stat2.mode & 511;
261
+ } catch {
262
+ mode = opts.mode;
263
+ }
264
+ if (mode !== void 0) {
265
+ await fs.chmod(tmp, mode);
266
+ }
267
+ await renameWithRetry(tmp, targetPath);
268
+ } catch (err) {
269
+ try {
270
+ await fs.unlink(tmp);
271
+ } catch {
272
+ }
273
+ throw err;
274
+ }
275
+ }
276
+ var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
277
+ async function renameWithRetry(from, to) {
278
+ if (process.platform !== "win32") {
279
+ await fs.rename(from, to);
280
+ return;
281
+ }
282
+ const delays = [10, 25, 60, 120, 250];
283
+ let lastErr;
284
+ for (let i = 0; i <= delays.length; i++) {
285
+ try {
286
+ await fs.rename(from, to);
287
+ return;
288
+ } catch (err) {
289
+ lastErr = err;
290
+ const code = err?.code;
291
+ if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
292
+ throw err;
293
+ }
294
+ await new Promise((resolve3) => setTimeout(resolve3, delays[i]));
295
+ }
296
+ }
297
+ throw lastErr;
298
+ }
238
299
 
239
300
  // src/security/secret-vault.ts
240
301
  var KEY_BYTES = 32;
@@ -281,7 +342,7 @@ var DefaultSecretVault = class {
281
342
  loadOrCreateKey() {
282
343
  if (this.key) return this.key;
283
344
  try {
284
- const buf = fs.readFileSync(this.keyFile);
345
+ const buf = fs2.readFileSync(this.keyFile);
285
346
  if (buf.length !== KEY_BYTES) {
286
347
  throw new Error(`SecretVault: key file ${this.keyFile} has wrong size`);
287
348
  }
@@ -290,13 +351,13 @@ var DefaultSecretVault = class {
290
351
  } catch (err) {
291
352
  if (err.code !== "ENOENT") throw err;
292
353
  }
293
- fs.mkdirSync(path3.dirname(this.keyFile), { recursive: true });
354
+ fs2.mkdirSync(path4.dirname(this.keyFile), { recursive: true });
294
355
  const key = randomBytes(KEY_BYTES);
295
356
  try {
296
- fs.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
357
+ fs2.writeFileSync(this.keyFile, key, { mode: 384, flag: "wx" });
297
358
  } catch (err) {
298
359
  if (err.code !== "EEXIST") throw err;
299
- const buf = fs.readFileSync(this.keyFile);
360
+ const buf = fs2.readFileSync(this.keyFile);
300
361
  if (buf.length !== KEY_BYTES) {
301
362
  throw new Error(`SecretVault: key file ${this.keyFile} has wrong size`);
302
363
  }
@@ -351,23 +412,23 @@ function isSecretField(name) {
351
412
  async function rewriteConfigEncrypted(configPath, vault, patch) {
352
413
  let current = {};
353
414
  try {
354
- const raw = await fs4.readFile(configPath, "utf8");
415
+ const raw = await fs.readFile(configPath, "utf8");
355
416
  current = JSON.parse(raw);
356
417
  } catch {
357
418
  }
358
419
  const merged = deepMerge(current, patch ?? {});
359
420
  const encrypted = encryptConfigSecrets(merged, vault);
360
- await fs4.mkdir(path3.dirname(configPath), { recursive: true });
361
- await fs4.writeFile(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
421
+ await fs.mkdir(path4.dirname(configPath), { recursive: true });
422
+ await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
362
423
  try {
363
- await fs4.chmod(configPath, 384);
424
+ await fs.chmod(configPath, 384);
364
425
  } catch {
365
426
  }
366
427
  }
367
428
  async function migratePlaintextSecrets(configPath, vault) {
368
429
  let raw;
369
430
  try {
370
- raw = await fs4.readFile(configPath, "utf8");
431
+ raw = await fs.readFile(configPath, "utf8");
371
432
  } catch {
372
433
  return { migrated: 0, file: configPath };
373
434
  }
@@ -380,9 +441,9 @@ async function migratePlaintextSecrets(configPath, vault) {
380
441
  const counter = { n: 0 };
381
442
  const migrated = walkCount(parsed, vault, counter);
382
443
  if (counter.n === 0) return { migrated: 0, file: configPath };
383
- await fs4.writeFile(configPath, JSON.stringify(migrated, null, 2), { mode: 384 });
444
+ await atomicWrite(configPath, JSON.stringify(migrated, null, 2), { mode: 384 });
384
445
  try {
385
- await fs4.chmod(configPath, 384);
446
+ await fs.chmod(configPath, 384);
386
447
  } catch {
387
448
  }
388
449
  return { migrated: counter.n, file: configPath };
@@ -483,7 +544,7 @@ var DefaultLogger = class _DefaultLogger {
483
544
  this.pretty = opts.pretty ?? true;
484
545
  if (this.file) {
485
546
  try {
486
- fs.mkdirSync(path3.dirname(this.file), { recursive: true });
547
+ fs2.mkdirSync(path4.dirname(this.file), { recursive: true });
487
548
  } catch {
488
549
  }
489
550
  }
@@ -522,7 +583,7 @@ var DefaultLogger = class _DefaultLogger {
522
583
  }
523
584
  if (this.file) {
524
585
  try {
525
- fs.appendFileSync(this.file, `${JSON.stringify(entry)}
586
+ fs2.appendFileSync(this.file, `${JSON.stringify(entry)}
526
587
  `);
527
588
  } catch {
528
589
  }
@@ -947,47 +1008,47 @@ var DefaultPathResolver = class {
947
1008
  projectRoot;
948
1009
  cwd;
949
1010
  constructor(cwd = process.cwd()) {
950
- this.cwd = path3.resolve(cwd);
1011
+ this.cwd = path4.resolve(cwd);
951
1012
  this.projectRoot = this.detectProjectRoot(this.cwd);
952
1013
  }
953
1014
  detectProjectRoot(start) {
954
- let dir = path3.resolve(start);
955
- const root = path3.parse(dir).root;
1015
+ let dir = path4.resolve(start);
1016
+ const root = path4.parse(dir).root;
956
1017
  while (dir !== root) {
957
1018
  for (const marker of PROJECT_MARKERS) {
958
1019
  try {
959
- fs.accessSync(path3.join(dir, marker));
1020
+ fs2.accessSync(path4.join(dir, marker));
960
1021
  return dir;
961
1022
  } catch {
962
1023
  }
963
1024
  }
964
- const parent = path3.dirname(dir);
1025
+ const parent = path4.dirname(dir);
965
1026
  if (parent === dir) break;
966
1027
  dir = parent;
967
1028
  }
968
- return path3.resolve(start);
1029
+ return path4.resolve(start);
969
1030
  }
970
1031
  resolve(input) {
971
- const abs = path3.isAbsolute(input) ? input : path3.resolve(this.cwd, input);
1032
+ const abs = path4.isAbsolute(input) ? input : path4.resolve(this.cwd, input);
972
1033
  let real;
973
1034
  try {
974
- real = fs.realpathSync(abs);
1035
+ real = fs2.realpathSync(abs);
975
1036
  } catch {
976
- real = path3.normalize(abs);
1037
+ real = path4.normalize(abs);
977
1038
  }
978
1039
  return real;
979
1040
  }
980
1041
  isInsideRoot(absPath) {
981
- const normalized = path3.normalize(absPath);
982
- const root = path3.normalize(this.projectRoot);
1042
+ const normalized = path4.normalize(absPath);
1043
+ const root = path4.normalize(this.projectRoot);
983
1044
  if (normalized === root) return true;
984
- const rel = path3.relative(root, normalized);
985
- return !rel.startsWith("..") && !path3.isAbsolute(rel);
1045
+ const rel = path4.relative(root, normalized);
1046
+ return !rel.startsWith("..") && !path4.isAbsolute(rel);
986
1047
  }
987
1048
  ensureInsideRoot(absPath) {
988
1049
  const resolved = this.resolve(absPath);
989
1050
  if (!this.isInsideRoot(resolved)) {
990
- const display = path3.isAbsolute(absPath) ? path3.basename(absPath) : absPath;
1051
+ const display = path4.isAbsolute(absPath) ? path4.basename(absPath) : absPath;
991
1052
  const err = new Error(`Path "${display}" resolves outside the project root`);
992
1053
  err.fullPath = absPath;
993
1054
  err.projectRoot = this.projectRoot;
@@ -1025,7 +1086,7 @@ function buildRecoveryStrategies(opts) {
1025
1086
  async attempt(err) {
1026
1087
  if (!(err instanceof ProviderError) || err.status !== 429) return null;
1027
1088
  const delayMs = err.body?.retryAfterMs ?? 5e3;
1028
- const delay = Math.max(1e3, Math.min(delayMs, 6e4));
1089
+ const delay = Math.min(6e4, Math.max(1e3, delayMs));
1029
1090
  await new Promise((r) => setTimeout(r, delay));
1030
1091
  return { action: "retry", reason: "rate_limit_backoff" };
1031
1092
  }
@@ -1178,15 +1239,15 @@ var PATTERNS = [
1178
1239
  { type: "redis_uri", regex: /redis:\/\/[^\s"'`]+/g },
1179
1240
  {
1180
1241
  type: "bearer_token",
1181
- // Bounded at 512 chars to prevent catastrophic backtracking on adversarial input.
1182
- // Negative lookahead is a simple single-char check no backtracking risk.
1183
- regex: /(?<![A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{20,512}=*(?![A-Za-z0-9_.~+/-])/g
1242
+ // Anchored with alternation instead of negative lookahead avoids V8
1243
+ // backtracking risk on adversarial input. Bounded at 512 chars.
1244
+ regex: /(?:^|[^A-Za-z0-9_.~+/-])Bearer\s+[A-Za-z0-9._~+/-]{20,512}=*(?:$|[^A-Za-z0-9_.~+/-])/g
1184
1245
  },
1185
1246
  {
1186
1247
  type: "high_entropy_env",
1187
- // Value bounded at 512 chars; negative lookahead simplified to avoid
1188
- // nested quantifier backtracking on adversarial input.
1189
- regex: /\b([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?/g
1248
+ // Anchored with alternation instead of lookbehind to avoid backtracking.
1249
+ // Value bounded at 512 chars.
1250
+ regex: /(?:^|\s)([A-Z_]{4,}(?:KEY|TOKEN|SECRET|PASSWORD|PWD))\s*[:=]\s*['"]?([A-Za-z0-9_/+=-]{20,512})['"]?(?:\s|$)/g
1190
1251
  }
1191
1252
  ];
1192
1253
  var SCRUB_CHUNK_BYTES = 64 * 1024;
@@ -1238,69 +1299,6 @@ var DefaultSecretScrubber = class {
1238
1299
  return visit(obj);
1239
1300
  }
1240
1301
  };
1241
- async function atomicWrite(targetPath, content, opts = {}) {
1242
- const dir = path3.dirname(targetPath);
1243
- await fs4.mkdir(dir, { recursive: true });
1244
- const tmp = path3.join(dir, `.${path3.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
1245
- try {
1246
- if (typeof content === "string") {
1247
- await fs4.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
1248
- } else {
1249
- await fs4.writeFile(tmp, content, { flag: "wx" });
1250
- }
1251
- try {
1252
- const fh = await fs4.open(tmp, "r+");
1253
- try {
1254
- await fh.sync();
1255
- } finally {
1256
- await fh.close();
1257
- }
1258
- } catch {
1259
- }
1260
- let mode;
1261
- try {
1262
- const stat2 = await fs4.stat(targetPath);
1263
- mode = stat2.mode & 511;
1264
- } catch {
1265
- mode = opts.mode;
1266
- }
1267
- if (mode !== void 0) {
1268
- await fs4.chmod(tmp, mode);
1269
- }
1270
- await renameWithRetry(tmp, targetPath);
1271
- } catch (err) {
1272
- try {
1273
- await fs4.unlink(tmp);
1274
- } catch {
1275
- }
1276
- throw err;
1277
- }
1278
- }
1279
- var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
1280
- async function renameWithRetry(from, to) {
1281
- if (process.platform !== "win32") {
1282
- await fs4.rename(from, to);
1283
- return;
1284
- }
1285
- const delays = [10, 25, 60, 120, 250];
1286
- let lastErr;
1287
- for (let i = 0; i <= delays.length; i++) {
1288
- try {
1289
- await fs4.rename(from, to);
1290
- return;
1291
- } catch (err) {
1292
- lastErr = err;
1293
- const code = err?.code;
1294
- if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
1295
- throw err;
1296
- }
1297
- await new Promise((resolve3) => setTimeout(resolve3, delays[i]));
1298
- }
1299
- }
1300
- throw lastErr;
1301
- }
1302
-
1303
- // src/models/models-registry.ts
1304
1302
  var DEFAULT_URL = "https://models.dev/api.json";
1305
1303
  var DEFAULT_TTL_SECONDS = 24 * 3600;
1306
1304
  var FAMILY_BY_NPM = {
@@ -1457,7 +1455,7 @@ var DefaultModelsRegistry = class {
1457
1455
  }
1458
1456
  async readCache() {
1459
1457
  try {
1460
- const raw = await fs4.readFile(this.cacheFile, "utf8");
1458
+ const raw = await fs.readFile(this.cacheFile, "utf8");
1461
1459
  return JSON.parse(raw);
1462
1460
  } catch {
1463
1461
  return void 0;
@@ -1465,7 +1463,7 @@ var DefaultModelsRegistry = class {
1465
1463
  }
1466
1464
  /** Used by `wstack models refresh` to expose where the cache lives. */
1467
1465
  cacheLocation() {
1468
- return path3.resolve(this.cacheFile);
1466
+ return path4.resolve(this.cacheFile);
1469
1467
  }
1470
1468
  };
1471
1469
 
@@ -2266,13 +2264,17 @@ var ToolExecutor = class {
2266
2264
  const ctrl = new AbortController();
2267
2265
  const timer = setTimeout(() => ctrl.abort(new Error("tool timeout")), timeoutMs);
2268
2266
  const combined = AbortSignal.any([parentSignal, ctrl.signal]);
2267
+ let cleanupCalled = false;
2268
+ let caught = false;
2269
2269
  try {
2270
2270
  if (typeof tool.executeStream === "function") {
2271
2271
  return await this.runStreamedTool(tool, input, ctx, combined, toolUseId);
2272
2272
  }
2273
2273
  return await tool.execute(input, ctx, { signal: combined });
2274
2274
  } catch (err) {
2275
+ caught = true;
2275
2276
  if (combined.aborted && typeof tool.cleanup === "function") {
2277
+ cleanupCalled = true;
2276
2278
  try {
2277
2279
  await tool.cleanup(input, ctx);
2278
2280
  } catch {
@@ -2281,6 +2283,16 @@ var ToolExecutor = class {
2281
2283
  throw err;
2282
2284
  } finally {
2283
2285
  clearTimeout(timer);
2286
+ if (combined.aborted && !caught) {
2287
+ if (!cleanupCalled && typeof tool.cleanup === "function") {
2288
+ try {
2289
+ await tool.cleanup(input, ctx);
2290
+ } catch {
2291
+ }
2292
+ }
2293
+ const reason = combined.reason instanceof Error ? combined.reason : new Error(typeof combined.reason === "string" ? combined.reason : "aborted");
2294
+ throw reason;
2295
+ }
2284
2296
  }
2285
2297
  }
2286
2298
  async runStreamedTool(tool, input, ctx, signal, toolUseId) {
@@ -2338,7 +2350,8 @@ var ToolExecutor = class {
2338
2350
  if (subjectKey) {
2339
2351
  const v = obj[subjectKey];
2340
2352
  if (typeof v === "string") {
2341
- return subjectKey === "path" || subjectKey === "file" || subjectKey === "files" ? normalizePath(v) : escapeGlob(v);
2353
+ const isPathKey = subjectKey === "path" || subjectKey === "file" || subjectKey === "files";
2354
+ return isPathKey ? normalizePath(v) : escapeGlob(v);
2342
2355
  }
2343
2356
  }
2344
2357
  if (toolName === "bash" && typeof obj.command === "string") {