@wrongstack/core 0.148.0 → 0.236.0

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 (82) hide show
  1. package/dist/{agent-bridge-r9y6gdn4.d.ts → agent-bridge-Cimv7bK7.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-1GeQE_L0.d.ts → agent-subagent-runner-C658wj_c.d.ts} +9 -8
  3. package/dist/{brain-Cp_3GIS2.d.ts → brain-sCZ3lCjq.d.ts} +28 -2
  4. package/dist/{compactor-BueGt7LG.d.ts → compactor-BRfg3QPd.d.ts} +1 -1
  5. package/dist/{config-BaVThgnT.d.ts → config-Koq6f3fs.d.ts} +2 -2
  6. package/dist/{context-C7G_MtLV.d.ts → context-CLz3z_E8.d.ts} +126 -2
  7. package/dist/coordination/index.d.ts +70 -13
  8. package/dist/coordination/index.js +2126 -151
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +27 -27
  11. package/dist/defaults/index.js +1328 -354
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +45 -16
  14. package/dist/execution/index.js +367 -59
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/execution/prompt-enhancer.d.ts +86 -0
  17. package/dist/execution/prompt-enhancer.js +125 -0
  18. package/dist/execution/prompt-enhancer.js.map +1 -0
  19. package/dist/extension/index.d.ts +6 -6
  20. package/dist/extension/index.js +3 -1
  21. package/dist/extension/index.js.map +1 -1
  22. package/dist/{goal-preamble-CYJLg0wk.d.ts → goal-preamble-CnbzyVvl.d.ts} +19 -10
  23. package/dist/{index-BZdezm3g.d.ts → index-BlMqh5GO.d.ts} +8 -8
  24. package/dist/{index-CPweVoFM.d.ts → index-C2eSNPsB.d.ts} +7 -5
  25. package/dist/index.d.ts +439 -129
  26. package/dist/index.js +5206 -905
  27. package/dist/index.js.map +1 -1
  28. package/dist/infrastructure/index.d.ts +7 -7
  29. package/dist/infrastructure/index.js +72 -15
  30. package/dist/infrastructure/index.js.map +1 -1
  31. package/dist/kernel/index.d.ts +9 -9
  32. package/dist/kernel/index.js +7 -1
  33. package/dist/kernel/index.js.map +1 -1
  34. package/dist/{llm-selector-CP72f1lC.d.ts → llm-selector-D22R4AFz.d.ts} +2 -2
  35. package/dist/logger-DmmQhf4P.d.ts +65 -0
  36. package/dist/{mcp-servers-Bl5LTvQg.d.ts → mcp-servers-DFbirBv6.d.ts} +11 -4
  37. package/dist/models/index.d.ts +5 -5
  38. package/dist/models/index.js +89 -9
  39. package/dist/models/index.js.map +1 -1
  40. package/dist/{models-registry-D90K9UnM.d.ts → models-registry-CnJRjTXc.d.ts} +1 -1
  41. package/dist/{multi-agent-coordinator-QWEzJDlm.d.ts → multi-agent-coordinator-60weDZoA.d.ts} +8 -8
  42. package/dist/{null-fleet-bus-BUyfqh23.d.ts → null-fleet-bus-1068dEnr.d.ts} +7 -7
  43. package/dist/observability/index.d.ts +2 -2
  44. package/dist/package-outdated-watcher-pzJ5w7y8.d.ts +560 -0
  45. package/dist/{parallel-eternal-engine-C75QuhAI.d.ts → parallel-eternal-engine-DtG1fjc9.d.ts} +13 -9
  46. package/dist/{path-resolver-DRjQBkoO.d.ts → path-resolver-CA1ULU0J.d.ts} +3 -3
  47. package/dist/{permission-B7nKnEvQ.d.ts → permission-DbWPbuoA.d.ts} +1 -1
  48. package/dist/{permission-policy-8-6zBmfA.d.ts → permission-policy-AOk0LVsV.d.ts} +2 -2
  49. package/dist/pipeline-DsmlwTXu.d.ts +493 -0
  50. package/dist/{plan-templates-CkKNPU3I.d.ts → plan-templates-DPABrDvy.d.ts} +19 -8
  51. package/dist/{provider-runner-BNpuIyOL.d.ts → provider-runner-D0HgUqwV.d.ts} +3 -3
  52. package/dist/{retry-policy-rutAfVeR.d.ts → retry-policy-BVnkbMET.d.ts} +1 -1
  53. package/dist/sdd/index.d.ts +8 -8
  54. package/dist/sdd/index.js +358 -85
  55. package/dist/sdd/index.js.map +1 -1
  56. package/dist/{secret-vault-DoISxaKO.d.ts → secret-vault-BJDY28ev.d.ts} +7 -1
  57. package/dist/{secret-vault-BTcC_T5v.d.ts → secret-vault-CeVNiy_f.d.ts} +4 -3
  58. package/dist/security/index.d.ts +6 -5
  59. package/dist/security/index.js +214 -35
  60. package/dist/security/index.js.map +1 -1
  61. package/dist/{selector-4vDFZKt3.d.ts → selector-Cb4_9-hf.d.ts} +1 -1
  62. package/dist/{session-event-bridge-DWlvglC2.d.ts → session-event-bridge-BhtkkFFy.d.ts} +4 -2
  63. package/dist/{session-reader-BAtCxdaw.d.ts → session-reader-CCOssnBS.d.ts} +1 -1
  64. package/dist/skills/index.js +171 -21
  65. package/dist/skills/index.js.map +1 -1
  66. package/dist/storage/index.d.ts +151 -13
  67. package/dist/storage/index.js +1117 -256
  68. package/dist/storage/index.js.map +1 -1
  69. package/dist/types/index.d.ts +68 -21
  70. package/dist/types/index.js +616 -74
  71. package/dist/types/index.js.map +1 -1
  72. package/dist/utils/expect-defined.js +3 -1
  73. package/dist/utils/expect-defined.js.map +1 -1
  74. package/dist/utils/index.d.ts +80 -4
  75. package/dist/utils/index.js +100 -15
  76. package/dist/utils/index.js.map +1 -1
  77. package/dist/{wstack-paths-DD50Omgn.d.ts → wstack-paths-CJjEwPXn.d.ts} +14 -1
  78. package/package.json +7 -3
  79. package/skills/chimera/SKILL.md +105 -0
  80. package/skills/research-web/SKILL.md +342 -0
  81. package/dist/logger-B9J5puGM.d.ts +0 -32
  82. package/dist/pipeline-BG7UgbDc.d.ts +0 -239
@@ -15,5 +15,11 @@ interface SecretVault {
15
15
  decrypt(value: string): string;
16
16
  isEncrypted(value: string): boolean;
17
17
  }
18
+ /**
19
+ * No-op SecretVault that passes values through unchanged.
20
+ * Used in contexts where encryption is not needed — e.g. reading/writing
21
+ * config sections that contain no secret fields (models, settings, etc.).
22
+ */
23
+ declare const noOpVault: SecretVault;
18
24
 
19
- export type { SecretVault as S };
25
+ export { type SecretVault as S, noOpVault as n };
@@ -1,5 +1,6 @@
1
- import { S as SecretScrubber } from './permission-B7nKnEvQ.js';
2
- import { S as SecretVault } from './secret-vault-DoISxaKO.js';
1
+ import { S as SecretScrubber } from './permission-DbWPbuoA.js';
2
+ import { L as Logger } from './logger-B63L5bTg.js';
3
+ import { S as SecretVault } from './secret-vault-BJDY28ev.js';
3
4
 
4
5
  declare class DefaultSecretScrubber implements SecretScrubber {
5
6
  scrub(text: string): string;
@@ -55,7 +56,7 @@ declare function rewriteConfigEncrypted(configPath: string, vault: SecretVault,
55
56
  * users who had plaintext keys before the vault landed are upgraded
56
57
  * transparently.
57
58
  */
58
- declare function migratePlaintextSecrets(configPath: string, vault: SecretVault): Promise<{
59
+ declare function migratePlaintextSecrets(configPath: string, vault: SecretVault, logger?: Pick<Logger, 'warn'>): Promise<{
59
60
  migrated: number;
60
61
  file: string;
61
62
  }>;
@@ -1,8 +1,9 @@
1
- export { D as DefaultSecretScrubber, a as DefaultSecretVault, S as SecretVaultOptions, d as decryptConfigSecrets, e as encryptConfigSecrets, i as isSecretField, m as migratePlaintextSecrets, r as rewriteConfigEncrypted } from '../secret-vault-BTcC_T5v.js';
2
- export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from '../permission-policy-8-6zBmfA.js';
3
- import '../permission-B7nKnEvQ.js';
4
- import '../context-C7G_MtLV.js';
5
- import '../secret-vault-DoISxaKO.js';
1
+ export { D as DefaultSecretScrubber, a as DefaultSecretVault, S as SecretVaultOptions, d as decryptConfigSecrets, e as encryptConfigSecrets, i as isSecretField, m as migratePlaintextSecrets, r as rewriteConfigEncrypted } from '../secret-vault-CeVNiy_f.js';
2
+ export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from '../permission-policy-AOk0LVsV.js';
3
+ import '../permission-DbWPbuoA.js';
4
+ import '../context-CLz3z_E8.js';
5
+ import '../logger-B63L5bTg.js';
6
+ import '../secret-vault-BJDY28ev.js';
6
7
  import '../input-reader-E-ffP2ee.js';
7
8
 
8
9
  /**
@@ -110,6 +110,105 @@ var DefaultSecretScrubber = class {
110
110
  }
111
111
  };
112
112
 
113
+ // src/types/errors.ts
114
+ var ERROR_CODES = {
115
+ // Provider
116
+ PROVIDER_RATE_LIMITED: "PROVIDER_RATE_LIMITED",
117
+ PROVIDER_AUTH_FAILED: "PROVIDER_AUTH_FAILED",
118
+ PROVIDER_OVERLOADED: "PROVIDER_OVERLOADED",
119
+ PROVIDER_INVALID_REQUEST: "PROVIDER_INVALID_REQUEST",
120
+ PROVIDER_SERVER_ERROR: "PROVIDER_SERVER_ERROR",
121
+ PROVIDER_NETWORK_ERROR: "PROVIDER_NETWORK_ERROR",
122
+ PROVIDER_CONTEXT_OVERFLOW: "PROVIDER_CONTEXT_OVERFLOW",
123
+ // Tool
124
+ TOOL_NOT_FOUND: "TOOL_NOT_FOUND",
125
+ TOOL_PERMISSION_DENIED: "TOOL_PERMISSION_DENIED",
126
+ TOOL_EXECUTION_FAILED: "TOOL_EXECUTION_FAILED",
127
+ TOOL_TIMEOUT: "TOOL_TIMEOUT",
128
+ TOOL_INPUT_INVALID: "TOOL_INPUT_INVALID",
129
+ // Config
130
+ CONFIG_INVALID: "CONFIG_INVALID",
131
+ CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND",
132
+ CONFIG_PARSE_FAILED: "CONFIG_PARSE_FAILED",
133
+ CONFIG_MIGRATION_NEEDED: "CONFIG_MIGRATION_NEEDED",
134
+ // Plugin
135
+ PLUGIN_LOAD_FAILED: "PLUGIN_LOAD_FAILED",
136
+ PLUGIN_API_MISMATCH: "PLUGIN_API_MISMATCH",
137
+ PLUGIN_MISSING_DEPENDENCY: "PLUGIN_MISSING_DEPENDENCY",
138
+ // Agent
139
+ AGENT_ITERATION_LIMIT: "AGENT_ITERATION_LIMIT",
140
+ AGENT_CONTEXT_OVERFLOW: "AGENT_CONTEXT_OVERFLOW",
141
+ AGENT_ABORTED: "AGENT_ABORTED",
142
+ AGENT_RUN_FAILED: "AGENT_RUN_FAILED",
143
+ // Session
144
+ SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
145
+ SESSION_CORRUPTED: "SESSION_CORRUPTED",
146
+ SESSION_WRITE_FAILED: "SESSION_WRITE_FAILED",
147
+ // Container / Registry
148
+ CONTAINER_TOKEN_ALREADY_BOUND: "CONTAINER_TOKEN_ALREADY_BOUND",
149
+ CONTAINER_TOKEN_NOT_BOUND: "CONTAINER_TOKEN_NOT_BOUND",
150
+ CONTAINER_CIRCULAR_DEPENDENCY: "CONTAINER_CIRCULAR_DEPENDENCY",
151
+ REGISTRY_DUPLICATE: "REGISTRY_DUPLICATE",
152
+ REGISTRY_NOT_FOUND: "REGISTRY_NOT_FOUND",
153
+ REGISTRY_INVALID: "REGISTRY_INVALID",
154
+ // File system
155
+ FS_READ_FAILED: "FS_READ_FAILED",
156
+ FS_WRITE_FAILED: "FS_WRITE_FAILED",
157
+ FS_MKDIR_FAILED: "FS_MKDIR_FAILED",
158
+ FS_DELETE_FAILED: "FS_DELETE_FAILED",
159
+ FS_ATOMIC_WRITE_FAILED: "FS_ATOMIC_WRITE_FAILED",
160
+ // SDD (Spec-Driven Development)
161
+ SDD_VALIDATION_FAILED: "SDD_VALIDATION_FAILED",
162
+ SDD_PARSE_FAILED: "SDD_PARSE_FAILED",
163
+ SDD_INVALID_STATE: "SDD_INVALID_STATE",
164
+ SDD_NOT_READY: "SDD_NOT_READY",
165
+ // General
166
+ VALIDATION_ERROR: "VALIDATION_ERROR",
167
+ UNKNOWN: "UNKNOWN"
168
+ };
169
+ var WrongStackError = class extends Error {
170
+ code;
171
+ subsystem;
172
+ severity;
173
+ recoverable;
174
+ context;
175
+ constructor(opts) {
176
+ super(opts.message, { cause: opts.cause });
177
+ this.name = "WrongStackError";
178
+ this.code = opts.code;
179
+ this.subsystem = opts.subsystem;
180
+ this.severity = opts.severity ?? "error";
181
+ this.recoverable = opts.recoverable ?? false;
182
+ this.context = opts.context;
183
+ }
184
+ /**
185
+ * Render a one-line user-facing description.
186
+ * Subclasses should override for domain-specific formatting.
187
+ */
188
+ describe() {
189
+ const ctx = this.context ? ` ${formatContext(this.context)}` : "";
190
+ return `${this.code}: ${this.message}${ctx}`;
191
+ }
192
+ };
193
+ function formatContext(ctx) {
194
+ const parts = Object.entries(ctx).filter(([, v]) => v !== void 0).slice(0, 3).map(([k, v]) => `${k}=${String(v)}`);
195
+ return parts.length > 0 ? `[${parts.join(" ")}]` : "";
196
+ }
197
+ var ConfigError = class extends WrongStackError {
198
+ constructor(opts) {
199
+ super({
200
+ message: opts.message,
201
+ code: opts.code,
202
+ subsystem: "config",
203
+ severity: "fatal",
204
+ recoverable: false,
205
+ context: opts.context,
206
+ cause: opts.cause
207
+ });
208
+ this.name = "ConfigError";
209
+ }
210
+ };
211
+
113
212
  // src/types/secret-vault.ts
114
213
  var ENCRYPTED_PREFIX = "enc:v1:";
115
214
  async function atomicWrite(targetPath, content, opts = {}) {
@@ -174,11 +273,90 @@ async function renameWithRetry(from, to) {
174
273
  throw lastErr;
175
274
  }
176
275
 
276
+ // src/utils/deep-merge.ts
277
+ var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
278
+ "__proto__",
279
+ "constructor",
280
+ "prototype",
281
+ "__defineGetter__",
282
+ "__defineSetter__",
283
+ "__lookupGetter__",
284
+ "__lookupSetter__"
285
+ ]);
286
+ function isPrimitiveArray(a) {
287
+ return a.every((v) => v === null || typeof v !== "object" && typeof v !== "function");
288
+ }
289
+ function deepMerge(base, patch, options = {}) {
290
+ const {
291
+ conflictResolution = "prefer-patch",
292
+ arrayMode = "replace",
293
+ protectProto = true,
294
+ onNonPrimitiveArrayReplace
295
+ } = options;
296
+ if (typeof base !== "object" || base === null) {
297
+ return conflictResolution === "prefer-patch" ? patch : base;
298
+ }
299
+ if (typeof patch !== "object" || patch === null) {
300
+ return conflictResolution === "prefer-patch" ? patch : base;
301
+ }
302
+ if (Array.isArray(base) && Array.isArray(patch)) {
303
+ if (arrayMode === "concat-primitives" && isPrimitiveArray(base) && isPrimitiveArray(patch)) {
304
+ return [.../* @__PURE__ */ new Set([...base, ...patch])];
305
+ }
306
+ return conflictResolution === "prefer-patch" ? patch : base;
307
+ }
308
+ if (Array.isArray(base) || Array.isArray(patch)) {
309
+ return conflictResolution === "prefer-patch" ? patch : base;
310
+ }
311
+ const baseObj = base;
312
+ const patchObj = patch;
313
+ const out = { ...baseObj };
314
+ for (const [k, v] of Object.entries(patchObj)) {
315
+ if (protectProto && FORBIDDEN_PROTO_KEYS.has(k)) continue;
316
+ const existing = out[k];
317
+ if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
318
+ out[k] = deepMerge(existing, v, options);
319
+ } else if (Array.isArray(v) && Array.isArray(existing)) {
320
+ if (onNonPrimitiveArrayReplace && !isPrimitiveArray(v)) {
321
+ onNonPrimitiveArrayReplace(k, existing.length, v.length);
322
+ }
323
+ out[k] = deepMerge(existing, v, options);
324
+ } else if (v !== void 0) {
325
+ if (onNonPrimitiveArrayReplace && Array.isArray(v) && !isPrimitiveArray(v)) {
326
+ const existingLen = Array.isArray(existing) ? existing.length : 0;
327
+ onNonPrimitiveArrayReplace(k, existingLen, v.length);
328
+ }
329
+ out[k] = v;
330
+ }
331
+ }
332
+ return out;
333
+ }
334
+
177
335
  // src/security/secret-vault.ts
178
336
  var KEY_BYTES = 32;
179
337
  var IV_BYTES = 12;
180
338
  var TAG_BYTES = 16;
181
339
  var ALGO = "aes-256-gcm";
340
+ var KEY_FILE_MODE = 384;
341
+ function checkKeyFilePermissions(keyFile) {
342
+ if (process.platform === "win32") return;
343
+ try {
344
+ const stat2 = fs2.statSync(keyFile);
345
+ const actualMode = stat2.mode & 511;
346
+ if (actualMode !== KEY_FILE_MODE) {
347
+ console.warn(JSON.stringify({
348
+ level: "warn",
349
+ event: "vault.key_file_wrong_permissions",
350
+ message: `Key file ${keyFile} has mode ${actualMode.toString(8)} \u2014 expected ${KEY_FILE_MODE.toString(8)}. Run: chmod ${KEY_FILE_MODE.toString(8)} ${keyFile}`,
351
+ keyFile,
352
+ expectedMode: KEY_FILE_MODE,
353
+ actualMode,
354
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
355
+ }));
356
+ }
357
+ } catch {
358
+ }
359
+ }
182
360
  var DefaultSecretVault = class {
183
361
  keyFile;
184
362
  key;
@@ -202,14 +380,26 @@ var DefaultSecretVault = class {
202
380
  const rest = value.slice(ENCRYPTED_PREFIX.length);
203
381
  const parts = rest.split(":");
204
382
  if (parts.length !== 3) {
205
- throw new Error("SecretVault: malformed encrypted value");
383
+ throw new ConfigError({
384
+ message: "SecretVault: malformed encrypted value",
385
+ code: ERROR_CODES.CONFIG_PARSE_FAILED,
386
+ context: { field: "encrypted_value" }
387
+ });
206
388
  }
207
389
  const [ivB64, tagB64, ctB64] = parts;
208
390
  const iv = Buffer.from(ivB64, "base64");
209
391
  const tag = Buffer.from(tagB64, "base64");
210
392
  const ct = Buffer.from(ctB64, "base64");
211
- if (iv.length !== IV_BYTES) throw new Error("SecretVault: bad IV length");
212
- if (tag.length !== TAG_BYTES) throw new Error("SecretVault: bad tag length");
393
+ if (iv.length !== IV_BYTES) throw new ConfigError({
394
+ message: "SecretVault: bad IV length",
395
+ code: ERROR_CODES.CONFIG_PARSE_FAILED,
396
+ context: { expected: IV_BYTES, actual: iv.length }
397
+ });
398
+ if (tag.length !== TAG_BYTES) throw new ConfigError({
399
+ message: "SecretVault: bad tag length",
400
+ code: ERROR_CODES.CONFIG_PARSE_FAILED,
401
+ context: { expected: TAG_BYTES, actual: tag.length }
402
+ });
213
403
  const key = this.loadOrCreateKey();
214
404
  const decipher = createDecipheriv(ALGO, key, iv);
215
405
  decipher.setAuthTag(tag);
@@ -221,11 +411,14 @@ var DefaultSecretVault = class {
221
411
  try {
222
412
  const buf = fs2.readFileSync(this.keyFile);
223
413
  if (buf.length !== KEY_BYTES) {
224
- throw new Error(
225
- `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`
226
- );
414
+ throw new ConfigError({
415
+ message: `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`,
416
+ code: ERROR_CODES.CONFIG_INVALID,
417
+ context: { keyFile: this.keyFile, expectedBytes: KEY_BYTES, actualBytes: buf.length }
418
+ });
227
419
  }
228
420
  this.key = buf;
421
+ checkKeyFilePermissions(this.keyFile);
229
422
  return this.key;
230
423
  } catch (err) {
231
424
  if (err.code !== "ENOENT") throw err;
@@ -238,11 +431,14 @@ var DefaultSecretVault = class {
238
431
  if (err.code !== "EEXIST") throw err;
239
432
  const buf = fs2.readFileSync(this.keyFile);
240
433
  if (buf.length !== KEY_BYTES) {
241
- throw new Error(
242
- `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`
243
- );
434
+ throw new ConfigError({
435
+ message: `SecretVault: key file ${this.keyFile} is ${buf.length} bytes (expected ${KEY_BYTES}). Remove it manually to generate a new key.`,
436
+ code: ERROR_CODES.CONFIG_INVALID,
437
+ context: { keyFile: this.keyFile, expectedBytes: KEY_BYTES, actualBytes: buf.length }
438
+ });
244
439
  }
245
440
  this.key = buf;
441
+ checkKeyFilePermissions(this.keyFile);
246
442
  return this.key;
247
443
  }
248
444
  this.key = key;
@@ -303,7 +499,7 @@ async function rewriteConfigEncrypted(configPath, vault, patch) {
303
499
  await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
304
500
  await restrictFilePermissions(configPath);
305
501
  }
306
- async function migratePlaintextSecrets(configPath, vault) {
502
+ async function migratePlaintextSecrets(configPath, vault, logger) {
307
503
  let raw;
308
504
  try {
309
505
  raw = await fs.readFile(configPath, "utf8");
@@ -320,11 +516,14 @@ async function migratePlaintextSecrets(configPath, vault) {
320
516
  const migrated = walkCount(parsed, vault, counter);
321
517
  if (counter.n === 0) return { migrated: 0, file: configPath };
322
518
  await atomicWrite(configPath, JSON.stringify(migrated, null, 2), { mode: 384 });
323
- await restrictFilePermissions(configPath);
519
+ await restrictFilePermissions(
520
+ configPath,
521
+ logger ? { warn: (msg) => logger.warn(msg) } : void 0
522
+ );
324
523
  return { migrated: counter.n, file: configPath };
325
524
  }
326
525
  async function restrictFilePermissions(filePath, opts) {
327
- const warn = ((msg) => console.warn(msg));
526
+ const warn = opts?.warn ?? ((msg) => console.warn(msg));
328
527
  if (process.platform === "win32") {
329
528
  try {
330
529
  const { execFile } = await import('child_process');
@@ -376,28 +575,6 @@ function walkCount(node, vault, counter) {
376
575
  }
377
576
  return out;
378
577
  }
379
- var FORBIDDEN_PROTO_KEYS = /* @__PURE__ */ new Set([
380
- "__proto__",
381
- "constructor",
382
- "prototype",
383
- "__defineGetter__",
384
- "__defineSetter__",
385
- "__lookupGetter__",
386
- "__lookupSetter__"
387
- ]);
388
- function deepMerge(a, b) {
389
- const out = { ...a };
390
- for (const [k, v] of Object.entries(b)) {
391
- if (FORBIDDEN_PROTO_KEYS.has(k)) continue;
392
- const existing = out[k];
393
- if (v !== null && typeof v === "object" && !Array.isArray(v) && existing !== null && typeof existing === "object" && !Array.isArray(existing)) {
394
- out[k] = deepMerge(existing, v);
395
- } else {
396
- out[k] = v;
397
- }
398
- }
399
- return out;
400
- }
401
578
 
402
579
  // src/security/capabilities.ts
403
580
  var ToolCapabilities = {
@@ -457,7 +634,9 @@ function getDangerousCapabilities(toolOrCaps) {
457
634
  // src/utils/expect-defined.ts
458
635
  function expectDefined(value, label) {
459
636
  if (value === null || value === void 0) {
460
- throw new Error("Expected value to be defined");
637
+ const err = new Error("Expected value to be defined");
638
+ err.name = "ExpectDefinedError";
639
+ throw err;
461
640
  }
462
641
  return value;
463
642
  }