akm-cli 0.9.10 → 0.9.11

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 (33) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/STABILITY.md +22 -14
  3. package/dist/commands/health/checks.js +23 -7
  4. package/dist/commands/health/improve-metrics.js +12 -0
  5. package/dist/commands/improve/distill/quality-gate.js +13 -5
  6. package/dist/commands/improve/eval-cases.js +9 -2
  7. package/dist/commands/improve/improve.js +19 -4
  8. package/dist/commands/improve/loop-stages.js +13 -3
  9. package/dist/commands/tasks/tasks-cli.js +32 -0
  10. package/dist/commands/tasks/validate.js +186 -0
  11. package/dist/commands/url-checker.js +75 -16
  12. package/dist/core/bundle-id.js +7 -1
  13. package/dist/core/config/schema/engines.js +17 -0
  14. package/dist/core/improve-result.js +8 -0
  15. package/dist/core/paths.js +112 -0
  16. package/dist/indexer/search/search-source.js +3 -2
  17. package/dist/integrations/agent/engine-resolution.js +92 -3
  18. package/dist/integrations/agent/execution-lowering.js +15 -2
  19. package/dist/integrations/agent/runner-dispatch.js +16 -3
  20. package/dist/integrations/agent/runner.js +2 -0
  21. package/dist/output/shapes/passthrough.js +1 -0
  22. package/dist/scripts/akm-migrate-node.js +1043 -822
  23. package/dist/scripts/akm-migrate.js +1043 -822
  24. package/dist/tasks/scheduler-sync.js +51 -25
  25. package/dist/workflows/exec/dispatch-redaction.js +21 -7
  26. package/docs/integration/bundling-akm.md +1 -1
  27. package/docs/migration/v0.8-to-v0.9.md +32 -0
  28. package/docs/reference/cli.md +31 -5
  29. package/docs/reference/configuration.md +12 -2
  30. package/docs/reference/data-and-telemetry.md +1 -1
  31. package/docs/reference/tasks.md +8 -0
  32. package/package.json +1 -1
  33. package/schemas/akm-config.json +8 -0
@@ -7124,6 +7124,136 @@ var init_errors = __esm(() => {
7124
7124
  };
7125
7125
  });
7126
7126
 
7127
+ // src/core/asset/asset-ref.ts
7128
+ import path from "node:path";
7129
+ function validateName(name) {
7130
+ if (!name)
7131
+ throw new UsageError("Empty asset name.", "MISSING_REQUIRED_ARGUMENT");
7132
+ if (name.includes("\x00"))
7133
+ throw new UsageError("Null byte in asset name.", "MISSING_REQUIRED_ARGUMENT");
7134
+ if (/^[A-Za-z]:/.test(name))
7135
+ throw new UsageError("Windows drive path in asset name.", "MISSING_REQUIRED_ARGUMENT");
7136
+ const slashName = name.replace(/\\/g, "/");
7137
+ if (slashName === ".." || slashName.startsWith("../")) {
7138
+ throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
7139
+ }
7140
+ if (slashName.split("/").some((seg) => seg === "." || seg === "..")) {
7141
+ throw new UsageError("Asset name cannot contain relative path segments.", "MISSING_REQUIRED_ARGUMENT");
7142
+ }
7143
+ const normalized = path.posix.normalize(slashName);
7144
+ if (path.posix.isAbsolute(normalized))
7145
+ throw new UsageError("Absolute path in asset name.", "MISSING_REQUIRED_ARGUMENT");
7146
+ if (normalized === ".." || normalized.startsWith("../")) {
7147
+ throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
7148
+ }
7149
+ }
7150
+ function normalizeName(name) {
7151
+ return path.posix.normalize(name.replace(/\\/g, "/"));
7152
+ }
7153
+ function isBundleSlug(s) {
7154
+ return BUNDLE_SLUG_RE.test(s);
7155
+ }
7156
+ function normalizeConceptId(raw) {
7157
+ const nfc = raw.normalize("NFC");
7158
+ if (nfc.includes("#")) {
7159
+ throw new UsageError("`#` is reserved for the export fragment in a concept id.", "MISSING_REQUIRED_ARGUMENT");
7160
+ }
7161
+ validateName(nfc);
7162
+ return normalizeName(nfc);
7163
+ }
7164
+ function makeBundleRef(bundle, conceptId, fragment) {
7165
+ const normalized = normalizeConceptId(conceptId);
7166
+ let out = normalized;
7167
+ if (bundle) {
7168
+ if (!BUNDLE_SLUG_RE.test(bundle)) {
7169
+ throw new UsageError(`Invalid bundle slug "${bundle}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
7170
+ }
7171
+ out = `${bundle}//${normalized}`;
7172
+ }
7173
+ if (fragment)
7174
+ out = `${out}#${fragment}`;
7175
+ return out;
7176
+ }
7177
+ function bundleRefToString(ref) {
7178
+ return makeBundleRef(ref.bundle, ref.conceptId, ref.fragment);
7179
+ }
7180
+ function parseBundleRef(ref) {
7181
+ const trimmed = ref.trim();
7182
+ if (!trimmed)
7183
+ throw new UsageError("Empty ref.", "MISSING_REQUIRED_ARGUMENT");
7184
+ let bundle;
7185
+ let body = trimmed;
7186
+ const boundary = trimmed.indexOf("//");
7187
+ if (boundary >= 0) {
7188
+ bundle = trimmed.slice(0, boundary);
7189
+ body = trimmed.slice(boundary + 2);
7190
+ if (!bundle)
7191
+ throw new UsageError("Empty bundle in ref.", "MISSING_REQUIRED_ARGUMENT");
7192
+ if (!BUNDLE_SLUG_RE.test(bundle)) {
7193
+ throw new UsageError(`Invalid bundle slug "${bundle}" in ref "${trimmed}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
7194
+ }
7195
+ }
7196
+ let fragment;
7197
+ const hash = body.indexOf("#");
7198
+ if (hash >= 0) {
7199
+ fragment = body.slice(hash + 1) || undefined;
7200
+ body = body.slice(0, hash);
7201
+ }
7202
+ if (!body) {
7203
+ throw new UsageError(`Invalid ref "${trimmed}". Expected [bundle//]conceptId, e.g. knowledge/guide or core//skills/review`, "MISSING_REQUIRED_ARGUMENT");
7204
+ }
7205
+ const conceptId = normalizeConceptId(body);
7206
+ return { bundle: bundle || undefined, conceptId, fragment };
7207
+ }
7208
+ var BUNDLE_SLUG_RE;
7209
+ var init_asset_ref = __esm(() => {
7210
+ init_errors();
7211
+ BUNDLE_SLUG_RE = /^[^\s:.#/]+$/;
7212
+ });
7213
+
7214
+ // src/core/bundle-id.ts
7215
+ import crypto2 from "node:crypto";
7216
+ import path2 from "node:path";
7217
+ function slugForPath(sourcePath) {
7218
+ const resolved = path2.resolve(sourcePath);
7219
+ const base = path2.basename(resolved).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
7220
+ if (base.length > 0)
7221
+ return base;
7222
+ return `bundle-${shortHash(resolved)}`;
7223
+ }
7224
+ function deriveBundleId(registryId, sourcePath, usedIds) {
7225
+ const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
7226
+ const id = ensureUniqueId(preferred, sourcePath, usedIds);
7227
+ usedIds.add(id);
7228
+ return id;
7229
+ }
7230
+ function deriveBundleIds(sources) {
7231
+ const usedIds = new Set;
7232
+ const reservedIds = new Set(sources.flatMap((source) => source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : []));
7233
+ return sources.map((source) => {
7234
+ const id = source.registryId && isBundleSlug(source.registryId) ? deriveBundleId(source.registryId, source.path, usedIds) : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
7235
+ usedIds.add(id);
7236
+ return id;
7237
+ });
7238
+ }
7239
+ function ensureUniqueId(preferred, sourcePath, used) {
7240
+ if (!used.has(preferred))
7241
+ return preferred;
7242
+ const suffixed = `${preferred}-${shortHash(path2.resolve(sourcePath))}`;
7243
+ if (!used.has(suffixed))
7244
+ return suffixed;
7245
+ let n = 2;
7246
+ while (used.has(`${suffixed}-${n}`))
7247
+ n++;
7248
+ return `${suffixed}-${n}`;
7249
+ }
7250
+ function shortHash(input) {
7251
+ return crypto2.createHash("sha256").update(input).digest("hex").slice(0, 8);
7252
+ }
7253
+ var init_bundle_id = __esm(() => {
7254
+ init_asset_ref();
7255
+ });
7256
+
7127
7257
  // src/core/platform.ts
7128
7258
  var IS_WINDOWS;
7129
7259
  var init_platform = __esm(() => {
@@ -7132,7 +7262,7 @@ var init_platform = __esm(() => {
7132
7262
 
7133
7263
  // src/core/paths.ts
7134
7264
  import os from "node:os";
7135
- import path from "node:path";
7265
+ import path3 from "node:path";
7136
7266
  function isUnderBunTest(env) {
7137
7267
  return env.BUN_TEST === "1" || env.NODE_ENV === "test";
7138
7268
  }
@@ -7149,37 +7279,37 @@ function getConfigDir(env = process.env, platform = process.platform) {
7149
7279
  if (platform === "win32") {
7150
7280
  const appData = env.APPDATA?.trim();
7151
7281
  if (appData)
7152
- return path.join(appData, "akm");
7282
+ return path3.join(appData, "akm");
7153
7283
  } else {
7154
7284
  const xdgConfigHome2 = env.XDG_CONFIG_HOME?.trim();
7155
7285
  if (xdgConfigHome2)
7156
- return path.join(xdgConfigHome2, "akm");
7286
+ return path3.join(xdgConfigHome2, "akm");
7157
7287
  }
7158
7288
  const stashOverride = env.AKM_BUNDLE_DIR?.trim();
7159
7289
  if (stashOverride && isTransientStashPath(stashOverride)) {
7160
- return path.join(stashOverride, ".akm");
7290
+ return path3.join(stashOverride, ".akm");
7161
7291
  }
7162
7292
  if (platform === "win32") {
7163
7293
  const appData = env.APPDATA?.trim();
7164
7294
  if (appData)
7165
- return path.join(appData, "akm");
7295
+ return path3.join(appData, "akm");
7166
7296
  const userProfile = env.USERPROFILE?.trim();
7167
7297
  if (!userProfile) {
7168
7298
  throw new ConfigError("Unable to determine config directory. Set APPDATA or USERPROFILE.", "CONFIG_DIR_UNRESOLVABLE");
7169
7299
  }
7170
- return path.join(userProfile, "AppData", "Roaming", "akm");
7300
+ return path3.join(userProfile, "AppData", "Roaming", "akm");
7171
7301
  }
7172
7302
  const xdgConfigHome = env.XDG_CONFIG_HOME?.trim();
7173
7303
  if (xdgConfigHome)
7174
- return path.join(xdgConfigHome, "akm");
7304
+ return path3.join(xdgConfigHome, "akm");
7175
7305
  const home = env.HOME?.trim();
7176
7306
  if (!home) {
7177
7307
  throw new ConfigError("Unable to determine config directory. Set XDG_CONFIG_HOME or HOME.", "CONFIG_DIR_UNRESOLVABLE");
7178
7308
  }
7179
- return path.join(home, ".config", "akm");
7309
+ return path3.join(home, ".config", "akm");
7180
7310
  }
7181
7311
  function getConfigPath(env = process.env) {
7182
- return path.join(getConfigDir(env), "config.json");
7312
+ return path3.join(getConfigDir(env), "config.json");
7183
7313
  }
7184
7314
  function getCacheDir(env = process.env) {
7185
7315
  const override = env.AKM_CACHE_DIR?.trim();
@@ -7188,22 +7318,22 @@ function getCacheDir(env = process.env) {
7188
7318
  if (IS_WINDOWS) {
7189
7319
  const localAppData = env.LOCALAPPDATA?.trim();
7190
7320
  if (localAppData)
7191
- return path.join(localAppData, "akm");
7321
+ return path3.join(localAppData, "akm");
7192
7322
  const userProfile = env.USERPROFILE?.trim();
7193
7323
  if (userProfile)
7194
- return path.join(userProfile, "AppData", "Local", "akm");
7324
+ return path3.join(userProfile, "AppData", "Local", "akm");
7195
7325
  const appData = env.APPDATA?.trim();
7196
7326
  if (appData) {
7197
- return path.join(appData, "..", "Local", "akm");
7327
+ return path3.join(appData, "..", "Local", "akm");
7198
7328
  }
7199
7329
  } else {
7200
7330
  const xdgCacheHome = env.XDG_CACHE_HOME?.trim();
7201
7331
  if (xdgCacheHome)
7202
- return path.join(xdgCacheHome, "akm");
7332
+ return path3.join(xdgCacheHome, "akm");
7203
7333
  }
7204
7334
  const stashOverride = env.AKM_BUNDLE_DIR?.trim();
7205
7335
  if (stashOverride && isTransientStashPath(stashOverride)) {
7206
- return path.join(stashOverride, ".akm", "cache");
7336
+ return path3.join(stashOverride, ".akm", "cache");
7207
7337
  }
7208
7338
  if (IS_WINDOWS) {
7209
7339
  throw new ConfigError("Unable to determine cache directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
@@ -7211,11 +7341,11 @@ function getCacheDir(env = process.env) {
7211
7341
  const home = env.HOME?.trim();
7212
7342
  if (!home)
7213
7343
  return homelessFallbackDir("akm-cache");
7214
- return path.join(home, ".cache", "akm");
7344
+ return path3.join(home, ".cache", "akm");
7215
7345
  }
7216
7346
  function homelessFallbackDir(kind) {
7217
7347
  const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
7218
- return path.join(os.tmpdir(), uid === undefined ? kind : `${kind}-${uid}`);
7348
+ return path3.join(os.tmpdir(), uid === undefined ? kind : `${kind}-${uid}`);
7219
7349
  }
7220
7350
  function getDataDir(env = process.env, platform = process.platform) {
7221
7351
  const override = env.AKM_DATA_DIR?.trim();
@@ -7227,38 +7357,83 @@ function getDataDir(env = process.env, platform = process.platform) {
7227
7357
  if (platform === "win32") {
7228
7358
  const localAppData = env.LOCALAPPDATA?.trim();
7229
7359
  if (localAppData)
7230
- return path.join(localAppData, "akm", "data");
7360
+ return path3.join(localAppData, "akm", "data");
7231
7361
  const userProfile = env.USERPROFILE?.trim();
7232
7362
  if (userProfile)
7233
- return path.join(userProfile, "AppData", "Local", "akm", "data");
7363
+ return path3.join(userProfile, "AppData", "Local", "akm", "data");
7234
7364
  const appData = env.APPDATA?.trim();
7235
7365
  if (!appData) {
7236
7366
  throw new ConfigError("Unable to determine data directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
7237
7367
  }
7238
- return path.join(appData, "..", "Local", "akm", "data");
7368
+ return path3.join(appData, "..", "Local", "akm", "data");
7239
7369
  }
7240
7370
  const xdgDataHome = env.XDG_DATA_HOME?.trim();
7241
7371
  if (xdgDataHome)
7242
- return path.join(xdgDataHome, "akm");
7372
+ return path3.join(xdgDataHome, "akm");
7243
7373
  const home = env.HOME?.trim();
7244
7374
  if (!home)
7245
7375
  return homelessFallbackDir("akm-data");
7246
- return path.join(home, ".local", "share", "akm");
7376
+ return path3.join(home, ".local", "share", "akm");
7247
7377
  }
7248
7378
  function getDbPath(env = process.env) {
7249
- return path.join(getDataDir(env), "index.db");
7379
+ return path3.join(getDataDir(env), "index.db");
7250
7380
  }
7251
7381
  function getMaintenanceBarrierPath() {
7252
- return path.join(getDataDir(), "maintenance.barrier.lock");
7382
+ return path3.join(getDataDir(), "maintenance.barrier.lock");
7253
7383
  }
7254
7384
  function getLockfilePath() {
7255
- return path.join(getDataDir(), "akm.lock");
7385
+ return path3.join(getDataDir(), "akm.lock");
7256
7386
  }
7257
7387
  function getRegistryCacheDir() {
7258
- return path.join(getCacheDir(), "registry");
7388
+ return path3.join(getCacheDir(), "registry");
7259
7389
  }
7260
7390
  function getRegistryIndexCacheDir() {
7261
- return path.join(getCacheDir(), "registry-index");
7391
+ return path3.join(getCacheDir(), "registry-index");
7392
+ }
7393
+ function getStateDir(env = process.env, platform = process.platform) {
7394
+ const override = env.AKM_STATE_DIR?.trim();
7395
+ if (override)
7396
+ return override;
7397
+ if (platform === "win32") {
7398
+ const localAppData = env.LOCALAPPDATA?.trim();
7399
+ if (localAppData)
7400
+ return path3.join(localAppData, "akm", "state");
7401
+ const userProfile = env.USERPROFILE?.trim();
7402
+ if (userProfile)
7403
+ return path3.join(userProfile, "AppData", "Local", "akm", "state");
7404
+ const appData = env.APPDATA?.trim();
7405
+ if (!appData) {
7406
+ throw new ConfigError("Unable to determine state directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
7407
+ }
7408
+ return path3.join(appData, "..", "Local", "akm", "state");
7409
+ }
7410
+ const xdgStateHome = env.XDG_STATE_HOME?.trim();
7411
+ if (xdgStateHome)
7412
+ return path3.join(xdgStateHome, "akm");
7413
+ const home = env.HOME?.trim();
7414
+ if (!home)
7415
+ return homelessFallbackDir("akm-state");
7416
+ return path3.join(home, ".local", "state", "akm");
7417
+ }
7418
+ function getStashStateKey(stashDir) {
7419
+ const resolved = path3.resolve(stashDir).replace(/\\/g, "/");
7420
+ const normalized = IS_WINDOWS ? resolved.toLowerCase() : resolved;
7421
+ return shortHash(normalized);
7422
+ }
7423
+ function stashScopedDir(base, stashDir) {
7424
+ return path3.join(base, getStashStateKey(stashDir));
7425
+ }
7426
+ function getDistillRejectedDir(stashDir) {
7427
+ return stashScopedDir(path3.join(getStateDir(), "improve", "distill-rejected"), stashDir);
7428
+ }
7429
+ function getEvalCasesDir(stashDir) {
7430
+ return stashScopedDir(path3.join(getStateDir(), "improve", "eval-cases"), stashDir);
7431
+ }
7432
+ function getMeasurementVerdictsDir(stashDir) {
7433
+ return stashScopedDir(path3.join(getStateDir(), "improve", "measurement", "verdicts"), stashDir);
7434
+ }
7435
+ function getUnresolvedSourcesDir(stashDir) {
7436
+ return stashScopedDir(path3.join(getCacheDir(), "index", "unresolved-sources"), stashDir);
7262
7437
  }
7263
7438
  function getDefaultStashDir(env = process.env) {
7264
7439
  const override = env.AKM_BUNDLE_DIR?.trim();
@@ -7267,24 +7442,25 @@ function getDefaultStashDir(env = process.env) {
7267
7442
  if (IS_WINDOWS) {
7268
7443
  const userProfile = env.USERPROFILE?.trim();
7269
7444
  if (userProfile)
7270
- return path.join(userProfile, "Documents", "akm");
7271
- return path.join("C:\\", "akm");
7445
+ return path3.join(userProfile, "Documents", "akm");
7446
+ return path3.join("C:\\", "akm");
7272
7447
  }
7273
7448
  const home = env.HOME?.trim();
7274
7449
  if (!home) {
7275
7450
  throw new ConfigError("Unable to determine default bundle directory. Set HOME.", "STASH_DIR_NOT_FOUND");
7276
7451
  }
7277
- return path.join(home, "akm");
7452
+ return path3.join(home, "akm");
7278
7453
  }
7279
7454
  var init_paths = __esm(() => {
7455
+ init_bundle_id();
7280
7456
  init_errors();
7281
7457
  init_platform();
7282
7458
  });
7283
7459
 
7284
7460
  // src/core/common.ts
7285
- import crypto2 from "node:crypto";
7461
+ import crypto3 from "node:crypto";
7286
7462
  import fs from "node:fs";
7287
- import path2 from "node:path";
7463
+ import path4 from "node:path";
7288
7464
  function isHttpUrl(value) {
7289
7465
  return !!value && /^https?:\/\//.test(value);
7290
7466
  }
@@ -7362,7 +7538,7 @@ function stripJsonComments(text) {
7362
7538
  return result;
7363
7539
  }
7364
7540
  function writeFileAtomic(target, content, mode) {
7365
- const tmp = `${target}.tmp.${process.pid}.${crypto2.randomBytes(8).toString("hex")}`;
7541
+ const tmp = `${target}.tmp.${process.pid}.${crypto3.randomBytes(8).toString("hex")}`;
7366
7542
  const data = typeof content === "string" ? Buffer.from(content) : content;
7367
7543
  const fileMode = mode ?? 384;
7368
7544
  let fd;
@@ -7417,7 +7593,7 @@ function writeFileAtomic(target, content, mode) {
7417
7593
  if (process.platform !== "win32") {
7418
7594
  let dirFd;
7419
7595
  try {
7420
- dirFd = fs.openSync(path2.dirname(target), "r");
7596
+ dirFd = fs.openSync(path4.dirname(target), "r");
7421
7597
  } catch (error) {
7422
7598
  if (hasErrnoCode(error, "EINVAL") || hasErrnoCode(error, "ENOTSUP"))
7423
7599
  return;
@@ -7450,7 +7626,7 @@ function resolveStashDir(env = process.env) {
7450
7626
  throw new ConfigError(`No bundle directory found. Run "akm bundle create" to create one at ${defaultDir}.`, "STASH_DIR_NOT_FOUND");
7451
7627
  }
7452
7628
  function validateStashDir(raw) {
7453
- const stashDir = path2.resolve(raw);
7629
+ const stashDir = path4.resolve(raw);
7454
7630
  let stat;
7455
7631
  try {
7456
7632
  stat = fs.statSync(stashDir);
@@ -7496,8 +7672,8 @@ function readStashDirFromConfig() {
7496
7672
  const componentConfig = component;
7497
7673
  if (typeof componentConfig.root !== "string")
7498
7674
  return bundlePath;
7499
- const bundleRoot = path2.resolve(bundlePath);
7500
- const componentRoot = path2.resolve(bundleRoot, componentConfig.root);
7675
+ const bundleRoot = path4.resolve(bundlePath);
7676
+ const componentRoot = path4.resolve(bundleRoot, componentConfig.root);
7501
7677
  if (!isWithin(componentRoot, bundleRoot)) {
7502
7678
  throw new ConfigError(`Component root "${componentConfig.root}" escapes bundle "${defaultBundle}".`, "INVALID_CONFIG_FILE");
7503
7679
  }
@@ -7542,30 +7718,30 @@ function isAkmRegistryCachePath(filePath) {
7542
7718
  return isWithin(filePath, getRegistryCacheDir()) || isWithin(filePath, getRegistryIndexCacheDir());
7543
7719
  }
7544
7720
  function isContainedResolvedPath(resolvedCandidate, resolvedRoot) {
7545
- const rel = path2.relative(normalizeFsPathForComparison(resolvedRoot), normalizeFsPathForComparison(resolvedCandidate));
7721
+ const rel = path4.relative(normalizeFsPathForComparison(resolvedRoot), normalizeFsPathForComparison(resolvedCandidate));
7546
7722
  if (rel === "")
7547
7723
  return true;
7548
- if (path2.isAbsolute(rel))
7724
+ if (path4.isAbsolute(rel))
7549
7725
  return false;
7550
7726
  return rel.split(/[/\\]+/)[0] !== "..";
7551
7727
  }
7552
7728
  function safeRealpath(p) {
7553
- const resolved = path2.resolve(p);
7729
+ const resolved = path4.resolve(p);
7554
7730
  try {
7555
7731
  return fs.realpathSync(resolved);
7556
7732
  } catch {
7557
7733
  const suffix = [];
7558
7734
  let current = resolved;
7559
7735
  for (;; ) {
7560
- const parent = path2.dirname(current);
7736
+ const parent = path4.dirname(current);
7561
7737
  if (parent === current) {
7562
7738
  return resolved;
7563
7739
  }
7564
- suffix.unshift(path2.basename(current));
7740
+ suffix.unshift(path4.basename(current));
7565
7741
  current = parent;
7566
7742
  try {
7567
7743
  const realParent = fs.realpathSync(current);
7568
- return path2.join(realParent, ...suffix);
7744
+ return path4.join(realParent, ...suffix);
7569
7745
  } catch {}
7570
7746
  }
7571
7747
  }
@@ -7879,7 +8055,7 @@ var init_recognition_util = __esm(() => {
7879
8055
 
7880
8056
  // src/core/asset/asset-placement.ts
7881
8057
  import fs2 from "node:fs";
7882
- import path5 from "node:path";
8058
+ import path7 from "node:path";
7883
8059
  function placementSpecFor(type) {
7884
8060
  return PLACEMENT_SPECS[type];
7885
8061
  }
@@ -7903,10 +8079,10 @@ function deriveCanonicalAssetName(assetType, typeRoot, filePath) {
7903
8079
  return PLACEMENT_SPECS[assetType]?.toCanonicalName(typeRoot, filePath);
7904
8080
  }
7905
8081
  function deriveCanonicalAssetNameFromStashRoot(assetType, stashRoot, filePath) {
7906
- const relPath = toPosix(path5.relative(stashRoot, filePath));
8082
+ const relPath = toPosix(path7.relative(stashRoot, filePath));
7907
8083
  const segments = relPath.split("/").filter(Boolean);
7908
8084
  const firstSegment = segments[0];
7909
- const typeRoot = firstSegment !== undefined && firstSegment === stashDirFor(assetType) ? path5.join(stashRoot, firstSegment) : stashRoot;
8085
+ const typeRoot = firstSegment !== undefined && firstSegment === stashDirFor(assetType) ? path7.join(stashRoot, firstSegment) : stashRoot;
7910
8086
  return deriveCanonicalAssetName(assetType, typeRoot, filePath);
7911
8087
  }
7912
8088
  function assetPathForName(assetType, typeRoot, name) {
@@ -7925,8 +8101,8 @@ function assetPathCandidatesForName(assetType, typeRoot, name) {
7925
8101
  const base = name === "default" ? "" : name.endsWith("/default") ? name.slice(0, -"default".length) : undefined;
7926
8102
  if (base === undefined)
7927
8103
  return [primary];
7928
- const dotForm = path5.join(typeRoot, base, ".env");
7929
- const namedForm = path5.join(typeRoot, base, "default.env");
8104
+ const dotForm = path7.join(typeRoot, base, ".env");
8105
+ const namedForm = path7.join(typeRoot, base, "default.env");
7930
8106
  return [...new Set([primary, dotForm, namedForm])];
7931
8107
  }
7932
8108
  var workflowSpec, markdownSpec, scriptSpec, BUILTIN_PLACEMENT_SPECS, PLACEMENT_SPECS;
@@ -7934,9 +8110,9 @@ var init_asset_placement = __esm(() => {
7934
8110
  init_common();
7935
8111
  init_recognition_util();
7936
8112
  workflowSpec = {
7937
- isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path5.extname(fileName).toLowerCase()),
8113
+ isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path7.extname(fileName).toLowerCase()),
7938
8114
  toCanonicalName: (typeRoot, filePath) => {
7939
- const rel = toPosix(path5.relative(typeRoot, filePath));
8115
+ const rel = toPosix(path7.relative(typeRoot, filePath));
7940
8116
  for (const ext of WORKFLOW_EXTENSIONS) {
7941
8117
  if (rel.toLowerCase().endsWith(ext))
7942
8118
  return rel.slice(0, -ext.length);
@@ -7947,43 +8123,43 @@ var init_asset_placement = __esm(() => {
7947
8123
  const lower = name.toLowerCase();
7948
8124
  for (const ext of WORKFLOW_EXTENSIONS) {
7949
8125
  if (lower.endsWith(ext))
7950
- return path5.join(typeRoot, name);
8126
+ return path7.join(typeRoot, name);
7951
8127
  }
7952
8128
  for (const ext of WORKFLOW_EXTENSIONS) {
7953
- const candidate = path5.join(typeRoot, `${name}${ext}`);
8129
+ const candidate = path7.join(typeRoot, `${name}${ext}`);
7954
8130
  if (fs2.existsSync(candidate))
7955
8131
  return candidate;
7956
8132
  }
7957
- return path5.join(typeRoot, `${name}.md`);
8133
+ return path7.join(typeRoot, `${name}.md`);
7958
8134
  }
7959
8135
  };
7960
8136
  markdownSpec = {
7961
- isRelevantFile: (fileName) => path5.extname(fileName).toLowerCase() === ".md",
8137
+ isRelevantFile: (fileName) => path7.extname(fileName).toLowerCase() === ".md",
7962
8138
  toCanonicalName: (typeRoot, filePath) => {
7963
- const rel = toPosix(path5.relative(typeRoot, filePath));
8139
+ const rel = toPosix(path7.relative(typeRoot, filePath));
7964
8140
  return rel.endsWith(".md") ? rel.slice(0, -3) : rel;
7965
8141
  },
7966
8142
  toAssetPath: (typeRoot, name) => {
7967
8143
  const withExt = name.endsWith(".md") ? name : `${name}.md`;
7968
- return path5.join(typeRoot, withExt);
8144
+ return path7.join(typeRoot, withExt);
7969
8145
  }
7970
8146
  };
7971
8147
  scriptSpec = {
7972
- isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path5.extname(fileName).toLowerCase()),
7973
- toCanonicalName: (typeRoot, filePath) => toPosix(path5.relative(typeRoot, filePath)),
7974
- toAssetPath: (typeRoot, name) => path5.join(typeRoot, name)
8148
+ isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path7.extname(fileName).toLowerCase()),
8149
+ toCanonicalName: (typeRoot, filePath) => toPosix(path7.relative(typeRoot, filePath)),
8150
+ toAssetPath: (typeRoot, name) => path7.join(typeRoot, name)
7975
8151
  };
7976
8152
  BUILTIN_PLACEMENT_SPECS = {
7977
8153
  skill: {
7978
8154
  stashDir: "skills",
7979
8155
  isRelevantFile: (fileName) => fileName === "SKILL.md",
7980
8156
  toCanonicalName: (typeRoot, filePath) => {
7981
- const relDir = toPosix(path5.dirname(path5.relative(typeRoot, filePath)));
8157
+ const relDir = toPosix(path7.dirname(path7.relative(typeRoot, filePath)));
7982
8158
  if (!relDir || relDir === ".")
7983
8159
  return;
7984
8160
  return relDir;
7985
8161
  },
7986
- toAssetPath: (typeRoot, name) => path5.join(typeRoot, name, "SKILL.md")
8162
+ toAssetPath: (typeRoot, name) => path7.join(typeRoot, name, "SKILL.md")
7987
8163
  },
7988
8164
  command: { stashDir: "commands", ...markdownSpec },
7989
8165
  agent: { stashDir: "agents", ...markdownSpec },
@@ -7996,10 +8172,10 @@ var init_asset_placement = __esm(() => {
7996
8172
  stashDir: "env",
7997
8173
  isRelevantFile: (fileName) => fileName === ".env" || fileName.endsWith(".env"),
7998
8174
  toCanonicalName: (typeRoot, filePath) => {
7999
- const rel = toPosix(path5.relative(typeRoot, filePath));
8000
- const fileName = path5.basename(rel);
8175
+ const rel = toPosix(path7.relative(typeRoot, filePath));
8176
+ const fileName = path7.basename(rel);
8001
8177
  if (fileName === ".env") {
8002
- const dir = path5.dirname(rel);
8178
+ const dir = path7.dirname(rel);
8003
8179
  return dir === "." || dir === "" ? "default" : `${dir}/default`;
8004
8180
  }
8005
8181
  const stripped = rel.endsWith(".env") ? rel.slice(0, -4) : rel;
@@ -8007,27 +8183,27 @@ var init_asset_placement = __esm(() => {
8007
8183
  },
8008
8184
  toAssetPath: (typeRoot, name) => {
8009
8185
  if (name === "default")
8010
- return path5.join(typeRoot, ".env");
8011
- return path5.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8186
+ return path7.join(typeRoot, ".env");
8187
+ return path7.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8012
8188
  }
8013
8189
  },
8014
8190
  secret: {
8015
8191
  stashDir: "secrets",
8016
8192
  isRelevantFile: (fileName) => !fileName.endsWith(".lock") && !fileName.endsWith(".sensitive"),
8017
- toCanonicalName: (typeRoot, filePath) => toPosix(path5.relative(typeRoot, filePath)),
8018
- toAssetPath: (typeRoot, name) => path5.join(typeRoot, name)
8193
+ toCanonicalName: (typeRoot, filePath) => toPosix(path7.relative(typeRoot, filePath)),
8194
+ toAssetPath: (typeRoot, name) => path7.join(typeRoot, name)
8019
8195
  },
8020
8196
  lesson: { stashDir: "lessons", ...markdownSpec },
8021
8197
  task: {
8022
8198
  stashDir: "tasks",
8023
- isRelevantFile: (fileName) => path5.extname(fileName).toLowerCase() === ".yml",
8199
+ isRelevantFile: (fileName) => path7.extname(fileName).toLowerCase() === ".yml",
8024
8200
  toCanonicalName: (typeRoot, filePath) => {
8025
- const rel = toPosix(path5.relative(typeRoot, filePath));
8201
+ const rel = toPosix(path7.relative(typeRoot, filePath));
8026
8202
  return rel.toLowerCase().endsWith(".yml") ? rel.slice(0, -4) : rel;
8027
8203
  },
8028
8204
  toAssetPath: (typeRoot, name) => {
8029
8205
  const withExt = name.toLowerCase().endsWith(".yml") ? name : `${name}.yml`;
8030
- return path5.join(typeRoot, withExt);
8206
+ return path7.join(typeRoot, withExt);
8031
8207
  }
8032
8208
  },
8033
8209
  session: { stashDir: "sessions", ...markdownSpec },
@@ -8036,93 +8212,6 @@ var init_asset_placement = __esm(() => {
8036
8212
  PLACEMENT_SPECS = { ...BUILTIN_PLACEMENT_SPECS };
8037
8213
  });
8038
8214
 
8039
- // src/core/asset/asset-ref.ts
8040
- import path6 from "node:path";
8041
- function validateName(name) {
8042
- if (!name)
8043
- throw new UsageError("Empty asset name.", "MISSING_REQUIRED_ARGUMENT");
8044
- if (name.includes("\x00"))
8045
- throw new UsageError("Null byte in asset name.", "MISSING_REQUIRED_ARGUMENT");
8046
- if (/^[A-Za-z]:/.test(name))
8047
- throw new UsageError("Windows drive path in asset name.", "MISSING_REQUIRED_ARGUMENT");
8048
- const slashName = name.replace(/\\/g, "/");
8049
- if (slashName === ".." || slashName.startsWith("../")) {
8050
- throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
8051
- }
8052
- if (slashName.split("/").some((seg) => seg === "." || seg === "..")) {
8053
- throw new UsageError("Asset name cannot contain relative path segments.", "MISSING_REQUIRED_ARGUMENT");
8054
- }
8055
- const normalized = path6.posix.normalize(slashName);
8056
- if (path6.posix.isAbsolute(normalized))
8057
- throw new UsageError("Absolute path in asset name.", "MISSING_REQUIRED_ARGUMENT");
8058
- if (normalized === ".." || normalized.startsWith("../")) {
8059
- throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
8060
- }
8061
- }
8062
- function normalizeName(name) {
8063
- return path6.posix.normalize(name.replace(/\\/g, "/"));
8064
- }
8065
- function isBundleSlug(s) {
8066
- return BUNDLE_SLUG_RE.test(s);
8067
- }
8068
- function normalizeConceptId(raw) {
8069
- const nfc = raw.normalize("NFC");
8070
- if (nfc.includes("#")) {
8071
- throw new UsageError("`#` is reserved for the export fragment in a concept id.", "MISSING_REQUIRED_ARGUMENT");
8072
- }
8073
- validateName(nfc);
8074
- return normalizeName(nfc);
8075
- }
8076
- function makeBundleRef(bundle, conceptId, fragment) {
8077
- const normalized = normalizeConceptId(conceptId);
8078
- let out = normalized;
8079
- if (bundle) {
8080
- if (!BUNDLE_SLUG_RE.test(bundle)) {
8081
- throw new UsageError(`Invalid bundle slug "${bundle}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
8082
- }
8083
- out = `${bundle}//${normalized}`;
8084
- }
8085
- if (fragment)
8086
- out = `${out}#${fragment}`;
8087
- return out;
8088
- }
8089
- function bundleRefToString(ref) {
8090
- return makeBundleRef(ref.bundle, ref.conceptId, ref.fragment);
8091
- }
8092
- function parseBundleRef(ref) {
8093
- const trimmed = ref.trim();
8094
- if (!trimmed)
8095
- throw new UsageError("Empty ref.", "MISSING_REQUIRED_ARGUMENT");
8096
- let bundle;
8097
- let body = trimmed;
8098
- const boundary = trimmed.indexOf("//");
8099
- if (boundary >= 0) {
8100
- bundle = trimmed.slice(0, boundary);
8101
- body = trimmed.slice(boundary + 2);
8102
- if (!bundle)
8103
- throw new UsageError("Empty bundle in ref.", "MISSING_REQUIRED_ARGUMENT");
8104
- if (!BUNDLE_SLUG_RE.test(bundle)) {
8105
- throw new UsageError(`Invalid bundle slug "${bundle}" in ref "${trimmed}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
8106
- }
8107
- }
8108
- let fragment;
8109
- const hash = body.indexOf("#");
8110
- if (hash >= 0) {
8111
- fragment = body.slice(hash + 1) || undefined;
8112
- body = body.slice(0, hash);
8113
- }
8114
- if (!body) {
8115
- throw new UsageError(`Invalid ref "${trimmed}". Expected [bundle//]conceptId, e.g. knowledge/guide or core//skills/review`, "MISSING_REQUIRED_ARGUMENT");
8116
- }
8117
- const conceptId = normalizeConceptId(body);
8118
- return { bundle: bundle || undefined, conceptId, fragment };
8119
- }
8120
- var BUNDLE_SLUG_RE;
8121
- var init_asset_ref = __esm(() => {
8122
- init_errors();
8123
- BUNDLE_SLUG_RE = /^[^\s:.#/]+$/;
8124
- });
8125
-
8126
8215
  // src/core/asset/resolve-ref.ts
8127
8216
  function conceptIdFromTypeName(type, name) {
8128
8217
  const stashDir = stashDirFor(type);
@@ -8186,13 +8275,13 @@ function validateExtraParams(value) {
8186
8275
  }
8187
8276
  const issues = [];
8188
8277
  const seen = new WeakSet;
8189
- const visit2 = (entry, path7) => {
8278
+ const visit2 = (entry, path8) => {
8190
8279
  if (Array.isArray(entry)) {
8191
8280
  if (seen.has(entry))
8192
8281
  return;
8193
8282
  seen.add(entry);
8194
8283
  entry.forEach((child, index) => {
8195
- visit2(child, [...path7, index]);
8284
+ visit2(child, [...path8, index]);
8196
8285
  });
8197
8286
  return;
8198
8287
  }
@@ -8203,7 +8292,7 @@ function validateExtraParams(value) {
8203
8292
  seen.add(entry);
8204
8293
  for (const [key, child] of Object.entries(entry)) {
8205
8294
  const normalized = normalizeExtraParamKey(key);
8206
- if (path7.length === 0 && PROTECTED_TOP_LEVEL_KEYS.has(normalized)) {
8295
+ if (path8.length === 0 && PROTECTED_TOP_LEVEL_KEYS.has(normalized)) {
8207
8296
  const remedy = protectedKeyRemedy(normalized);
8208
8297
  issues.push({
8209
8298
  path: [key],
@@ -8211,9 +8300,9 @@ function validateExtraParams(value) {
8211
8300
  });
8212
8301
  }
8213
8302
  if (CREDENTIAL_KEYS.has(normalized)) {
8214
- issues.push({ path: [...path7, key], message: `${key} cannot carry credentials` });
8303
+ issues.push({ path: [...path8, key], message: `${key} cannot carry credentials` });
8215
8304
  }
8216
- visit2(child, [...path7, key]);
8305
+ visit2(child, [...path8, key]);
8217
8306
  }
8218
8307
  };
8219
8308
  visit2(value, []);
@@ -8406,13 +8495,13 @@ var init_warn = __esm(() => {
8406
8495
  });
8407
8496
 
8408
8497
  // src/core/write-provenance.ts
8409
- import path15 from "node:path";
8498
+ import path16 from "node:path";
8410
8499
  function recordWrittenPath(filePath) {
8411
8500
  if (activeJournals.size === 0 || !filePath)
8412
8501
  return;
8413
8502
  let absolute;
8414
8503
  try {
8415
- absolute = path15.resolve(filePath);
8504
+ absolute = path16.resolve(filePath);
8416
8505
  } catch {
8417
8506
  return;
8418
8507
  }
@@ -8520,7 +8609,7 @@ var init_frontmatter = __esm(() => {
8520
8609
 
8521
8610
  // src/indexer/passes/metadata.ts
8522
8611
  import fs13 from "node:fs";
8523
- import path17 from "node:path";
8612
+ import path18 from "node:path";
8524
8613
  function normalizeQuality(raw) {
8525
8614
  if (KNOWN_QUALITY_VALUES.has(raw))
8526
8615
  return raw;
@@ -9280,7 +9369,7 @@ function projectMarkdownContent(body, truncationInfo) {
9280
9369
  return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
9281
9370
  }
9282
9371
  function applyPreContributorFields(entry, file, ctx, pkgMeta) {
9283
- const ext = path17.extname(file).toLowerCase();
9372
+ const ext = path18.extname(file).toLowerCase();
9284
9373
  if (pkgMeta) {
9285
9374
  if (pkgMeta.description && !entry.description) {
9286
9375
  entry.description = pkgMeta.description;
@@ -9326,8 +9415,8 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
9326
9415
  }
9327
9416
  }
9328
9417
  function applyPostContributorFields(entry, file, canonicalName, dirPath) {
9329
- const ext = path17.extname(file).toLowerCase();
9330
- const baseName = path17.basename(file, ext);
9418
+ const ext = path18.extname(file).toLowerCase();
9419
+ const baseName = path18.basename(file, ext);
9331
9420
  if (!entry.description) {
9332
9421
  entry.description = fileNameToDescription(baseName);
9333
9422
  entry.source = "filename";
@@ -9339,7 +9428,7 @@ function applyPostContributorFields(entry, file, canonicalName, dirPath) {
9339
9428
  entry.tags = [...entry.tags ?? [], ...extractDirTagsFromName(canonicalName)];
9340
9429
  entry.tags = normalizeTerms(entry.tags ?? []);
9341
9430
  entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, entry.tags));
9342
- entry.filename = path17.basename(file);
9431
+ entry.filename = path18.basename(file);
9343
9432
  }
9344
9433
  function buildMetadataSkipWarning(filePath, assetType, error) {
9345
9434
  const detail = error instanceof Error ? error.message : String(error);
@@ -9371,7 +9460,7 @@ function buildAliases(name, tags) {
9371
9460
  return Array.from(aliases);
9372
9461
  }
9373
9462
  function extractPackageMetadata(dirPath) {
9374
- const pkgPath = path17.join(dirPath, "package.json");
9463
+ const pkgPath = path18.join(dirPath, "package.json");
9375
9464
  if (!fs13.existsSync(pkgPath))
9376
9465
  return null;
9377
9466
  try {
@@ -9393,11 +9482,11 @@ function fileNameToDescription(fileName) {
9393
9482
  return fileName.replace(/[-_]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().trim();
9394
9483
  }
9395
9484
  function extractTagsFromPath(filePath, rootDir) {
9396
- const rel = path17.relative(rootDir, filePath);
9397
- const parts = rel.split(path17.sep);
9485
+ const rel = path18.relative(rootDir, filePath);
9486
+ const parts = rel.split(path18.sep);
9398
9487
  const tags = new Set;
9399
9488
  for (const part of parts) {
9400
- const name = part.replace(path17.extname(part), "");
9489
+ const name = part.replace(path18.extname(part), "");
9401
9490
  for (const token of name.split(/[-_./\\]+/)) {
9402
9491
  const clean = token.toLowerCase().trim();
9403
9492
  if (clean && clean.length > 1)
@@ -9429,27 +9518,27 @@ var init_metadata = __esm(() => {
9429
9518
  });
9430
9519
 
9431
9520
  // src/execution/record.ts
9432
- function snapshotStrictRecord(value, path18, options = {}) {
9521
+ function snapshotStrictRecord(value, path19, options = {}) {
9433
9522
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
9434
- throw new TypeError(`${path18} must be an object`);
9523
+ throw new TypeError(`${path19} must be an object`);
9435
9524
  }
9436
9525
  const prototype = Object.getPrototypeOf(value);
9437
9526
  if (prototype !== Object.prototype && prototype !== null) {
9438
- throw new TypeError(`${path18} must use a plain or null prototype`);
9527
+ throw new TypeError(`${path19} must use a plain or null prototype`);
9439
9528
  }
9440
9529
  const out = Object.create(null);
9441
9530
  for (const key of Reflect.ownKeys(value)) {
9442
9531
  const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
9443
9532
  if (!descriptor)
9444
- throw new TypeError(`${path18}.${String(key)} must have a stable own descriptor`);
9533
+ throw new TypeError(`${path19}.${String(key)} must have a stable own descriptor`);
9445
9534
  if (typeof key === "symbol" && !options.allowedSymbols?.has(key)) {
9446
- throw new TypeError(`${path18} contains unsupported symbol field: ${String(key)}`);
9535
+ throw new TypeError(`${path19} contains unsupported symbol field: ${String(key)}`);
9447
9536
  }
9448
9537
  if (!("value" in descriptor)) {
9449
- throw new TypeError(`${path18}.${String(key)} must be an enumerable data property, not an accessor`);
9538
+ throw new TypeError(`${path19}.${String(key)} must be an enumerable data property, not an accessor`);
9450
9539
  }
9451
9540
  if (typeof key === "string" && !descriptor.enumerable) {
9452
- throw new TypeError(`${path18}.${key} must be an enumerable data property, not a non-enumerable field`);
9541
+ throw new TypeError(`${path19}.${key} must be an enumerable data property, not a non-enumerable field`);
9453
9542
  }
9454
9543
  Object.defineProperty(out, key, {
9455
9544
  value: descriptor.value,
@@ -9460,14 +9549,14 @@ function snapshotStrictRecord(value, path18, options = {}) {
9460
9549
  }
9461
9550
  return Object.freeze(out);
9462
9551
  }
9463
- function assertSnapshotKeys(value, allowed, path18, allowedSymbols = new Set) {
9552
+ function assertSnapshotKeys(value, allowed, path19, allowedSymbols = new Set) {
9464
9553
  const allowedKeys = new Set(allowed);
9465
9554
  for (const key of Reflect.ownKeys(value)) {
9466
9555
  if (typeof key === "symbol") {
9467
9556
  if (!allowedSymbols.has(key))
9468
- throw new TypeError(`${path18} contains unsupported field: ${String(key)}`);
9557
+ throw new TypeError(`${path19} contains unsupported field: ${String(key)}`);
9469
9558
  } else if (!allowedKeys.has(key)) {
9470
- throw new TypeError(`${path18} contains unsupported field: ${key}`);
9559
+ throw new TypeError(`${path19} contains unsupported field: ${key}`);
9471
9560
  }
9472
9561
  }
9473
9562
  }
@@ -9475,9 +9564,9 @@ function assertSnapshotKeys(value, allowed, path18, allowedSymbols = new Set) {
9475
9564
  // node_modules/dotenv/lib/main.js
9476
9565
  var require_main = __commonJS((exports, module) => {
9477
9566
  var fs14 = __require("fs");
9478
- var path18 = __require("path");
9567
+ var path19 = __require("path");
9479
9568
  var os2 = __require("os");
9480
- var crypto3 = __require("crypto");
9569
+ var crypto4 = __require("crypto");
9481
9570
  var TIPS = [
9482
9571
  "◈ encrypted .env [www.dotenvx.com]",
9483
9572
  "◈ secrets for agents [www.dotenvx.com]",
@@ -9616,7 +9705,7 @@ var require_main = __commonJS((exports, module) => {
9616
9705
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
9617
9706
  }
9618
9707
  } else {
9619
- possibleVaultPath = path18.resolve(process.cwd(), ".env.vault");
9708
+ possibleVaultPath = path19.resolve(process.cwd(), ".env.vault");
9620
9709
  }
9621
9710
  if (fs14.existsSync(possibleVaultPath)) {
9622
9711
  return possibleVaultPath;
@@ -9624,7 +9713,7 @@ var require_main = __commonJS((exports, module) => {
9624
9713
  return null;
9625
9714
  }
9626
9715
  function _resolveHome(envPath) {
9627
- return envPath[0] === "~" ? path18.join(os2.homedir(), envPath.slice(1)) : envPath;
9716
+ return envPath[0] === "~" ? path19.join(os2.homedir(), envPath.slice(1)) : envPath;
9628
9717
  }
9629
9718
  function _configVault(options) {
9630
9719
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
@@ -9641,7 +9730,7 @@ var require_main = __commonJS((exports, module) => {
9641
9730
  return { parsed };
9642
9731
  }
9643
9732
  function configDotenv(options) {
9644
- const dotenvPath = path18.resolve(process.cwd(), ".env");
9733
+ const dotenvPath = path19.resolve(process.cwd(), ".env");
9645
9734
  let encoding = "utf8";
9646
9735
  let processEnv = process.env;
9647
9736
  if (options && options.processEnv != null) {
@@ -9669,13 +9758,13 @@ var require_main = __commonJS((exports, module) => {
9669
9758
  }
9670
9759
  let lastError;
9671
9760
  const parsedAll = {};
9672
- for (const path19 of optionPaths) {
9761
+ for (const path20 of optionPaths) {
9673
9762
  try {
9674
- const parsed = DotenvModule.parse(fs14.readFileSync(path19, { encoding }));
9763
+ const parsed = DotenvModule.parse(fs14.readFileSync(path20, { encoding }));
9675
9764
  DotenvModule.populate(parsedAll, parsed, options);
9676
9765
  } catch (e) {
9677
9766
  if (debug) {
9678
- _debug(`failed to load ${path19} ${e.message}`);
9767
+ _debug(`failed to load ${path20} ${e.message}`);
9679
9768
  }
9680
9769
  lastError = e;
9681
9770
  }
@@ -9688,7 +9777,7 @@ var require_main = __commonJS((exports, module) => {
9688
9777
  const shortPaths = [];
9689
9778
  for (const filePath of optionPaths) {
9690
9779
  try {
9691
- const relative = path18.relative(process.cwd(), filePath);
9780
+ const relative = path19.relative(process.cwd(), filePath);
9692
9781
  shortPaths.push(relative);
9693
9782
  } catch (e) {
9694
9783
  if (debug) {
@@ -9723,7 +9812,7 @@ var require_main = __commonJS((exports, module) => {
9723
9812
  const authTag = ciphertext.subarray(-16);
9724
9813
  ciphertext = ciphertext.subarray(12, -16);
9725
9814
  try {
9726
- const aesgcm = crypto3.createDecipheriv("aes-256-gcm", key, nonce);
9815
+ const aesgcm = crypto4.createDecipheriv("aes-256-gcm", key, nonce);
9727
9816
  aesgcm.setAuthTag(authTag);
9728
9817
  return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
9729
9818
  } catch (error) {
@@ -9827,7 +9916,7 @@ var init_time = __esm(() => {
9827
9916
 
9828
9917
  // src/tasks/source/bounded-document.ts
9829
9918
  import fs14 from "node:fs";
9830
- import path18 from "node:path";
9919
+ import path19 from "node:path";
9831
9920
  import { types as utilTypes } from "node:util";
9832
9921
  function own2(value, key) {
9833
9922
  return Object.hasOwn(value, key);
@@ -9998,7 +10087,7 @@ function parseTools(value, ctx) {
9998
10087
  sourceError(ctx, ["akm", "tools"], "must be a string, string array, mapping, or null.");
9999
10088
  }
10000
10089
  function validateWorkingDirectory(value, ctx) {
10001
- if (value.trim().length === 0 || value.includes("\x00") || path18.posix.isAbsolute(value.replaceAll("\\", "/")) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) {
10090
+ if (value.trim().length === 0 || value.includes("\x00") || path19.posix.isAbsolute(value.replaceAll("\\", "/")) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) {
10002
10091
  sourceError(ctx, ["working-directory"], "must be a non-empty relative path contained by the workspace root.");
10003
10092
  }
10004
10093
  const segments = value.replaceAll("\\", "/").split("/");
@@ -10012,7 +10101,7 @@ function validateWorkingDirectory(value, ctx) {
10012
10101
  let realCandidate;
10013
10102
  try {
10014
10103
  realRoot = fs14.realpathSync(ctx.workspaceRoot);
10015
- const candidate = path18.resolve(realRoot, value);
10104
+ const candidate = path19.resolve(realRoot, value);
10016
10105
  const stat = fs14.statSync(candidate);
10017
10106
  if (!stat.isDirectory())
10018
10107
  sourceError(ctx, ["working-directory"], "must resolve to a directory.");
@@ -10022,8 +10111,8 @@ function validateWorkingDirectory(value, ctx) {
10022
10111
  throw cause;
10023
10112
  sourceError(ctx, ["working-directory"], `cannot be physically verified: ${cause instanceof Error ? cause.message : String(cause)}.`);
10024
10113
  }
10025
- const relative = path18.relative(realRoot, realCandidate);
10026
- if (relative.startsWith("..") || path18.isAbsolute(relative)) {
10114
+ const relative = path19.relative(realRoot, realCandidate);
10115
+ if (relative.startsWith("..") || path19.isAbsolute(relative)) {
10027
10116
  sourceError(ctx, ["working-directory"], "resolves outside the workspace root and is not physically contained.");
10028
10117
  }
10029
10118
  }
@@ -10192,34 +10281,34 @@ function checkJsonSchemaDefinition(schema) {
10192
10281
  checkDefinitionNode(schema, [], issues, 0);
10193
10282
  return issues;
10194
10283
  }
10195
- function pointerFor(path19) {
10196
- return path19.length === 0 ? "$" : `$.${path19.map(String).join(".")}`;
10284
+ function pointerFor(path20) {
10285
+ return path20.length === 0 ? "$" : `$.${path20.map(String).join(".")}`;
10197
10286
  }
10198
- function pushIssue(issues, path19, keyword, kind, message) {
10199
- issues.push({ path: [...path19], pointer: pointerFor(path19), keyword, kind, message });
10287
+ function pushIssue(issues, path20, keyword, kind, message) {
10288
+ issues.push({ path: [...path20], pointer: pointerFor(path20), keyword, kind, message });
10200
10289
  }
10201
10290
  function isSupportedEnumValue(value) {
10202
10291
  return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
10203
10292
  }
10204
- function checkDefinitionNode(schema, path19, issues, depth) {
10293
+ function checkDefinitionNode(schema, path20, issues, depth) {
10205
10294
  if (depth > MAX_DEFINITION_DEPTH) {
10206
- pushIssue(issues, path19, "(depth)", "malformed", `schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10295
+ pushIssue(issues, path20, "(depth)", "malformed", `schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10207
10296
  return;
10208
10297
  }
10209
10298
  for (const keyword of Object.keys(schema)) {
10210
10299
  if (UNSUPPORTED_KEYWORDS.has(keyword)) {
10211
10300
  const hint = UNSUPPORTED_KEYWORD_HINTS.get(keyword);
10212
- pushIssue(issues, [...path19, keyword], keyword, "unsupported", `keyword "${keyword}" is not enforced by the workflow schema subset — the schema would silently not ` + `constrain what it looks like it constrains${hint ? `; ${hint}` : ""}`);
10301
+ pushIssue(issues, [...path20, keyword], keyword, "unsupported", `keyword "${keyword}" is not enforced by the workflow schema subset — the schema would silently not ` + `constrain what it looks like it constrains${hint ? `; ${hint}` : ""}`);
10213
10302
  }
10214
10303
  }
10215
10304
  const declared = schema.type;
10216
10305
  if (declared !== undefined) {
10217
10306
  const names = Array.isArray(declared) ? declared : [declared];
10218
10307
  if (names.length === 0) {
10219
- pushIssue(issues, [...path19, "type"], "type", "malformed", `"type" must name at least one type`);
10308
+ pushIssue(issues, [...path20, "type"], "type", "malformed", `"type" must name at least one type`);
10220
10309
  }
10221
10310
  for (const [index, name] of names.entries()) {
10222
- const namePath = Array.isArray(declared) ? [...path19, "type", index] : [...path19, "type"];
10311
+ const namePath = Array.isArray(declared) ? [...path20, "type", index] : [...path20, "type"];
10223
10312
  if (typeof name !== "string") {
10224
10313
  pushIssue(issues, namePath, "type", "malformed", `"type" must be a string or an array of strings`);
10225
10314
  } else if (!KNOWN_TYPE_NAMES.has(name)) {
@@ -10229,12 +10318,12 @@ function checkDefinitionNode(schema, path19, issues, depth) {
10229
10318
  }
10230
10319
  if (schema.enum !== undefined) {
10231
10320
  if (!Array.isArray(schema.enum) || schema.enum.length === 0) {
10232
- pushIssue(issues, [...path19, "enum"], "enum", "malformed", `"enum" must be a non-empty array of allowed values`);
10321
+ pushIssue(issues, [...path20, "enum"], "enum", "malformed", `"enum" must be a non-empty array of allowed values`);
10233
10322
  } else {
10234
10323
  schema.enum.forEach((value, index) => {
10235
10324
  if (isSupportedEnumValue(value))
10236
10325
  return;
10237
- pushIssue(issues, [...path19, "enum", index], "enum", "unsupported", `"enum" values must be JSON primitives (string, finite number, boolean, or null) in the workflow ` + `schema subset — object and array enum members cannot be matched by the runtime subset`);
10326
+ pushIssue(issues, [...path20, "enum", index], "enum", "unsupported", `"enum" values must be JSON primitives (string, finite number, boolean, or null) in the workflow ` + `schema subset — object and array enum members cannot be matched by the runtime subset`);
10238
10327
  });
10239
10328
  }
10240
10329
  }
@@ -10243,68 +10332,68 @@ function checkDefinitionNode(schema, path19, issues, depth) {
10243
10332
  if (branches === undefined)
10244
10333
  continue;
10245
10334
  if (!Array.isArray(branches) || branches.length === 0) {
10246
- pushIssue(issues, [...path19, keyword], keyword, "malformed", `"${keyword}" must be a non-empty array of schema objects`);
10335
+ pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a non-empty array of schema objects`);
10247
10336
  continue;
10248
10337
  }
10249
10338
  branches.forEach((branch, index) => {
10250
10339
  if (isRecord(branch)) {
10251
- checkDefinitionNode(branch, [...path19, keyword, index], issues, depth + 1);
10340
+ checkDefinitionNode(branch, [...path20, keyword, index], issues, depth + 1);
10252
10341
  } else {
10253
- pushIssue(issues, [...path19, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
10342
+ pushIssue(issues, [...path20, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
10254
10343
  }
10255
10344
  });
10256
10345
  }
10257
10346
  if (schema.not !== undefined) {
10258
10347
  if (isRecord(schema.not)) {
10259
- checkDefinitionNode(schema.not, [...path19, "not"], issues, depth + 1);
10348
+ checkDefinitionNode(schema.not, [...path20, "not"], issues, depth + 1);
10260
10349
  } else {
10261
- pushIssue(issues, [...path19, "not"], "not", "malformed", `"not" must be a schema object`);
10350
+ pushIssue(issues, [...path20, "not"], "not", "malformed", `"not" must be a schema object`);
10262
10351
  }
10263
10352
  }
10264
10353
  if (schema.required !== undefined) {
10265
10354
  if (!Array.isArray(schema.required) || !schema.required.every((key) => typeof key === "string")) {
10266
- pushIssue(issues, [...path19, "required"], "required", "malformed", `"required" must be an array of property-name strings`);
10355
+ pushIssue(issues, [...path20, "required"], "required", "malformed", `"required" must be an array of property-name strings`);
10267
10356
  }
10268
10357
  }
10269
10358
  if (schema.properties !== undefined) {
10270
10359
  if (!isRecord(schema.properties)) {
10271
- pushIssue(issues, [...path19, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
10360
+ pushIssue(issues, [...path20, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
10272
10361
  } else {
10273
10362
  for (const [key, propSchema] of Object.entries(schema.properties)) {
10274
10363
  if (isRecord(propSchema)) {
10275
- checkDefinitionNode(propSchema, [...path19, "properties", key], issues, depth + 1);
10364
+ checkDefinitionNode(propSchema, [...path20, "properties", key], issues, depth + 1);
10276
10365
  } else {
10277
- pushIssue(issues, [...path19, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
10366
+ pushIssue(issues, [...path20, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
10278
10367
  }
10279
10368
  }
10280
10369
  }
10281
10370
  }
10282
10371
  if (schema.items !== undefined) {
10283
10372
  if (isRecord(schema.items)) {
10284
- checkDefinitionNode(schema.items, [...path19, "items"], issues, depth + 1);
10373
+ checkDefinitionNode(schema.items, [...path20, "items"], issues, depth + 1);
10285
10374
  } else if (Array.isArray(schema.items)) {
10286
- pushIssue(issues, [...path19, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset — use a single schema object`);
10375
+ pushIssue(issues, [...path20, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset — use a single schema object`);
10287
10376
  } else {
10288
- pushIssue(issues, [...path19, "items"], "items", "malformed", `"items" must be a schema object`);
10377
+ pushIssue(issues, [...path20, "items"], "items", "malformed", `"items" must be a schema object`);
10289
10378
  }
10290
10379
  }
10291
10380
  if (schema.additionalProperties !== undefined && typeof schema.additionalProperties !== "boolean") {
10292
10381
  if (isRecord(schema.additionalProperties)) {
10293
- pushIssue(issues, [...path19, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset — only "additionalProperties: false" is`);
10382
+ pushIssue(issues, [...path20, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset — only "additionalProperties: false" is`);
10294
10383
  } else {
10295
- pushIssue(issues, [...path19, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
10384
+ pushIssue(issues, [...path20, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
10296
10385
  }
10297
10386
  }
10298
10387
  for (const keyword of ["minItems", "maxItems", "minLength", "maxLength"]) {
10299
10388
  const value = schema[keyword];
10300
10389
  if (value !== undefined && (typeof value !== "number" || !Number.isInteger(value) || value < 0)) {
10301
- pushIssue(issues, [...path19, keyword], keyword, "malformed", `"${keyword}" must be a non-negative integer`);
10390
+ pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a non-negative integer`);
10302
10391
  }
10303
10392
  }
10304
10393
  for (const keyword of ["minimum", "maximum"]) {
10305
10394
  const value = schema[keyword];
10306
10395
  if (value !== undefined && (typeof value !== "number" || !Number.isFinite(value))) {
10307
- pushIssue(issues, [...path19, keyword], keyword, "malformed", `"${keyword}" must be a finite number`);
10396
+ pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a finite number`);
10308
10397
  }
10309
10398
  }
10310
10399
  }
@@ -10329,9 +10418,9 @@ function matchesType(actual, expected) {
10329
10418
  return true;
10330
10419
  return expected === "number" && actual === "integer";
10331
10420
  }
10332
- function branchErrors(value, schema, path19, ctx) {
10421
+ function branchErrors(value, schema, path20, ctx) {
10333
10422
  const errors3 = [];
10334
- validateNode(value, schema, path19, { ...ctx, errors: errors3, depth: ctx.depth + 1 });
10423
+ validateNode(value, schema, path20, { ...ctx, errors: errors3, depth: ctx.depth + 1 });
10335
10424
  return errors3;
10336
10425
  }
10337
10426
  function combinatorBranches(schema, keyword) {
@@ -10346,9 +10435,9 @@ function summarizeBranchFailures(failures) {
10346
10435
  shown.push(`…${failures.length - shown.length} more`);
10347
10436
  return shown.join("; ");
10348
10437
  }
10349
- function validateCombinators(value, schema, path19, ctx) {
10438
+ function validateCombinators(value, schema, path20, ctx) {
10350
10439
  for (const branch of combinatorBranches(schema, "allOf")) {
10351
- ctx.errors.push(...branchErrors(value, branch, path19, ctx));
10440
+ ctx.errors.push(...branchErrors(value, branch, path20, ctx));
10352
10441
  }
10353
10442
  for (const keyword of ["anyOf", "oneOf"]) {
10354
10443
  const branches = combinatorBranches(schema, keyword);
@@ -10357,27 +10446,27 @@ function validateCombinators(value, schema, path19, ctx) {
10357
10446
  const failures = [];
10358
10447
  const matched = [];
10359
10448
  branches.forEach((branch, index) => {
10360
- const errors3 = branchErrors(value, branch, path19, ctx);
10449
+ const errors3 = branchErrors(value, branch, path20, ctx);
10361
10450
  if (errors3.length === 0)
10362
10451
  matched.push(index + 1);
10363
10452
  else
10364
10453
  failures.push({ index, errors: errors3 });
10365
10454
  });
10366
10455
  if (matched.length === 0) {
10367
- ctx.errors.push(`${path19}: value matches none of the ${branches.length} "${keyword}" schemas (${summarizeBranchFailures(failures)})`);
10456
+ ctx.errors.push(`${path20}: value matches none of the ${branches.length} "${keyword}" schemas (${summarizeBranchFailures(failures)})`);
10368
10457
  } else if (keyword === "oneOf" && matched.length > 1) {
10369
- ctx.errors.push(`${path19}: value matches ${matched.length} "oneOf" schemas (branches ${matched.join(", ")}); exactly one must match`);
10458
+ ctx.errors.push(`${path20}: value matches ${matched.length} "oneOf" schemas (branches ${matched.join(", ")}); exactly one must match`);
10370
10459
  }
10371
10460
  }
10372
10461
  const not = schema.not;
10373
- if (isRecord(not) && branchErrors(value, not, path19, ctx).length === 0) {
10374
- ctx.errors.push(`${path19}: value must not match the "not" schema`);
10462
+ if (isRecord(not) && branchErrors(value, not, path20, ctx).length === 0) {
10463
+ ctx.errors.push(`${path20}: value must not match the "not" schema`);
10375
10464
  }
10376
10465
  }
10377
- function validateNode(value, schema, path19, ctx) {
10466
+ function validateNode(value, schema, path20, ctx) {
10378
10467
  const errors3 = ctx.errors;
10379
10468
  if (ctx.depth > MAX_DEFINITION_DEPTH) {
10380
- errors3.push(`${path19}: schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10469
+ errors3.push(`${path20}: schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10381
10470
  return;
10382
10471
  }
10383
10472
  if (--ctx.budget.nodes < 0)
@@ -10387,47 +10476,47 @@ function validateNode(value, schema, path19, ctx) {
10387
10476
  if (typeof declared === "string" || Array.isArray(declared)) {
10388
10477
  const expected = (Array.isArray(declared) ? declared : [declared]).filter((t) => typeof t === "string");
10389
10478
  if (expected.length > 0 && !expected.some((t) => matchesType(actual, t))) {
10390
- errors3.push(`${path19}: expected type ${expected.join(" | ")}, got ${actual}`);
10479
+ errors3.push(`${path20}: expected type ${expected.join(" | ")}, got ${actual}`);
10391
10480
  return;
10392
10481
  }
10393
10482
  }
10394
10483
  if (Array.isArray(schema.enum) && schema.enum.length > 0) {
10395
10484
  const allowed = schema.enum;
10396
10485
  if (!allowed.some((candidate) => candidate === value)) {
10397
- errors3.push(ctx.redactValues ? `${path19}: value is not one of ${JSON.stringify(allowed)}` : `${path19}: value ${JSON.stringify(value)} is not one of ${JSON.stringify(allowed)}`);
10486
+ errors3.push(ctx.redactValues ? `${path20}: value is not one of ${JSON.stringify(allowed)}` : `${path20}: value ${JSON.stringify(value)} is not one of ${JSON.stringify(allowed)}`);
10398
10487
  return;
10399
10488
  }
10400
10489
  }
10401
- validateCombinators(value, schema, path19, ctx);
10490
+ validateCombinators(value, schema, path20, ctx);
10402
10491
  if (actual === "string" && typeof value === "string") {
10403
10492
  if (typeof schema.minLength === "number" && value.length < schema.minLength) {
10404
- errors3.push(`${path19}: string shorter than minLength ${schema.minLength}`);
10493
+ errors3.push(`${path20}: string shorter than minLength ${schema.minLength}`);
10405
10494
  }
10406
10495
  if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
10407
- errors3.push(`${path19}: string longer than maxLength ${schema.maxLength}`);
10496
+ errors3.push(`${path20}: string longer than maxLength ${schema.maxLength}`);
10408
10497
  }
10409
10498
  return;
10410
10499
  }
10411
10500
  if ((actual === "number" || actual === "integer") && typeof value === "number") {
10412
10501
  if (typeof schema.minimum === "number" && value < schema.minimum) {
10413
- errors3.push(ctx.redactValues ? `${path19}: value is below minimum ${schema.minimum}` : `${path19}: ${value} is below minimum ${schema.minimum}`);
10502
+ errors3.push(ctx.redactValues ? `${path20}: value is below minimum ${schema.minimum}` : `${path20}: ${value} is below minimum ${schema.minimum}`);
10414
10503
  }
10415
10504
  if (typeof schema.maximum === "number" && value > schema.maximum) {
10416
- errors3.push(ctx.redactValues ? `${path19}: value is above maximum ${schema.maximum}` : `${path19}: ${value} is above maximum ${schema.maximum}`);
10505
+ errors3.push(ctx.redactValues ? `${path20}: value is above maximum ${schema.maximum}` : `${path20}: ${value} is above maximum ${schema.maximum}`);
10417
10506
  }
10418
10507
  return;
10419
10508
  }
10420
10509
  if (actual === "array" && Array.isArray(value)) {
10421
10510
  if (typeof schema.minItems === "number" && value.length < schema.minItems) {
10422
- errors3.push(`${path19}: array has fewer than minItems ${schema.minItems}`);
10511
+ errors3.push(`${path20}: array has fewer than minItems ${schema.minItems}`);
10423
10512
  }
10424
10513
  if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
10425
- errors3.push(`${path19}: array has more than maxItems ${schema.maxItems}`);
10514
+ errors3.push(`${path20}: array has more than maxItems ${schema.maxItems}`);
10426
10515
  }
10427
10516
  const items = schema.items;
10428
10517
  if (items && typeof items === "object" && !Array.isArray(items)) {
10429
10518
  value.forEach((element, index) => {
10430
- validateNode(element, items, `${path19}[${index}]`, {
10519
+ validateNode(element, items, `${path20}[${index}]`, {
10431
10520
  ...ctx,
10432
10521
  depth: ctx.depth + 1
10433
10522
  });
@@ -10441,7 +10530,7 @@ function validateNode(value, schema, path19, ctx) {
10441
10530
  if (Array.isArray(schema.required)) {
10442
10531
  for (const key of schema.required) {
10443
10532
  if (typeof key === "string" && !Object.hasOwn(record, key)) {
10444
- errors3.push(`${path19}: missing required property "${key}"`);
10533
+ errors3.push(`${path20}: missing required property "${key}"`);
10445
10534
  }
10446
10535
  }
10447
10536
  }
@@ -10450,7 +10539,7 @@ function validateNode(value, schema, path19, ctx) {
10450
10539
  if (!Object.hasOwn(record, key))
10451
10540
  continue;
10452
10541
  if (propSchema && typeof propSchema === "object" && !Array.isArray(propSchema)) {
10453
- validateNode(record[key], propSchema, `${path19}.${key}`, {
10542
+ validateNode(record[key], propSchema, `${path20}.${key}`, {
10454
10543
  ...ctx,
10455
10544
  depth: ctx.depth + 1
10456
10545
  });
@@ -10460,7 +10549,7 @@ function validateNode(value, schema, path19, ctx) {
10460
10549
  if (schema.additionalProperties === false) {
10461
10550
  for (const key of Object.keys(record)) {
10462
10551
  if (!properties || !Object.hasOwn(properties, key)) {
10463
- errors3.push(`${path19}: unexpected property "${key}" (additionalProperties: false)`);
10552
+ errors3.push(`${path20}: unexpected property "${key}" (additionalProperties: false)`);
10464
10553
  }
10465
10554
  }
10466
10555
  }
@@ -10641,10 +10730,10 @@ function parseReference(source) {
10641
10730
  if (!output || output.name !== "output") {
10642
10731
  return { ok: false, message: `Expected ".output" after "steps.${stepId.name}" in "${text}".` };
10643
10732
  }
10644
- const path21 = parsePath(text, output.end);
10645
- if (!path21.ok)
10646
- return { ok: false, message: path21.message };
10647
- return { ok: true, expr: { kind: "stepOutput", stepId: stepId.name, path: path21.path } };
10733
+ const path22 = parsePath(text, output.end);
10734
+ if (!path22.ok)
10735
+ return { ok: false, message: path22.message };
10736
+ return { ok: true, expr: { kind: "stepOutput", stepId: stepId.name, path: path22.path } };
10648
10737
  }
10649
10738
  default:
10650
10739
  return { ok: false, message: `Unknown root "${root.name}" in "${text}"; ${GRAMMAR_HINT}.` };
@@ -10659,7 +10748,7 @@ function readIdent(text, start) {
10659
10748
  return { name: text.slice(start, end), end };
10660
10749
  }
10661
10750
  function parsePath(text, start) {
10662
- const path21 = [];
10751
+ const path22 = [];
10663
10752
  let i = start;
10664
10753
  while (i < text.length) {
10665
10754
  const char = text[i];
@@ -10668,7 +10757,7 @@ function parsePath(text, start) {
10668
10757
  if (!ident) {
10669
10758
  return { ok: false, message: `Invalid path segment after "." at position ${i} in "${text}".` };
10670
10759
  }
10671
- path21.push(ident.name);
10760
+ path22.push(ident.name);
10672
10761
  i = ident.end;
10673
10762
  } else if (char === "[") {
10674
10763
  let j = i + 1;
@@ -10680,13 +10769,13 @@ function parsePath(text, start) {
10680
10769
  message: `Invalid indexer at position ${i} in "${text}" — expected [<non-negative integer>].`
10681
10770
  };
10682
10771
  }
10683
- path21.push(Number.parseInt(text.slice(i + 1, j), 10));
10772
+ path22.push(Number.parseInt(text.slice(i + 1, j), 10));
10684
10773
  i = j + 1;
10685
10774
  } else {
10686
10775
  return { ok: false, message: `Unexpected character "${char}" at position ${i} in "${text}".` };
10687
10776
  }
10688
10777
  }
10689
- return { ok: true, path: path21 };
10778
+ return { ok: true, path: path22 };
10690
10779
  }
10691
10780
  function formatReference(expr) {
10692
10781
  switch (expr.kind) {
@@ -11059,7 +11148,7 @@ var init_uses = __esm(() => {
11059
11148
 
11060
11149
  // src/workflows/source-ir/semantics.ts
11061
11150
  import fs15 from "node:fs";
11062
- import path21 from "node:path";
11151
+ import path22 from "node:path";
11063
11152
  function canonicalizeWorkflowCron(value) {
11064
11153
  const canonical = value.trim().split(/\s+/).join(" ");
11065
11154
  if (canonical.startsWith("@") || canonical.split(" ").length !== 5) {
@@ -11095,7 +11184,7 @@ function canonicalizeWorkflowWorkingDirectory(value, workspaceRoot) {
11095
11184
  }
11096
11185
  const portable = value.replaceAll("\\", "/");
11097
11186
  const segments = portable.split("/");
11098
- if (path21.posix.isAbsolute(portable) || path21.win32.isAbsolute(value) || portable.startsWith("~") || segments.some((segment) => segment === "" || segment === "..")) {
11187
+ if (path22.posix.isAbsolute(portable) || path22.win32.isAbsolute(value) || portable.startsWith("~") || segments.some((segment) => segment === "" || segment === "..")) {
11099
11188
  throw new WorkflowSourceSemanticError("working-directory-escape", "working-directory must be relative and contained.");
11100
11189
  }
11101
11190
  const withoutDots = segments.filter((segment) => segment !== ".");
@@ -11175,13 +11264,13 @@ function verifyPhysicalContainment(workspaceRoot, relative) {
11175
11264
  } catch {
11176
11265
  throw new WorkflowSourceSemanticError("working-directory-unverifiable", "Workspace root cannot be physically verified.");
11177
11266
  }
11178
- const candidate = path21.resolve(root, ...relative.split("/"));
11267
+ const candidate = path22.resolve(root, ...relative.split("/"));
11179
11268
  if (!contained(root, candidate)) {
11180
11269
  throw new WorkflowSourceSemanticError("working-directory-escape", "working-directory escapes the workspace.");
11181
11270
  }
11182
11271
  let current = root;
11183
11272
  for (const segment of relative === "." ? [] : relative.split("/")) {
11184
- current = path21.join(current, segment);
11273
+ current = path22.join(current, segment);
11185
11274
  try {
11186
11275
  const entry = fs15.lstatSync(current);
11187
11276
  if (entry.isSymbolicLink()) {
@@ -11224,8 +11313,8 @@ function verifyPhysicalContainment(workspaceRoot, relative) {
11224
11313
  }
11225
11314
  }
11226
11315
  function contained(root, candidate) {
11227
- const relative = path21.relative(root, candidate);
11228
- return relative === "" || !relative.startsWith(`..${path21.sep}`) && relative !== ".." && !path21.isAbsolute(relative);
11316
+ const relative = path22.relative(root, candidate);
11317
+ return relative === "" || !relative.startsWith(`..${path22.sep}`) && relative !== ".." && !path22.isAbsolute(relative);
11229
11318
  }
11230
11319
  var TOKEN_SAFE_RUN, WorkflowSourceSemanticError;
11231
11320
  var init_semantics = __esm(() => {
@@ -12059,7 +12148,7 @@ function parseWorkflow(markdown, source) {
12059
12148
  };
12060
12149
  }
12061
12150
  const errors3 = [];
12062
- const path22 = source.path;
12151
+ const path23 = source.path;
12063
12152
  const lines = markdown.split(/\r?\n/);
12064
12153
  const totalLines = lines.length;
12065
12154
  const fmBlock = parseFrontmatterBlock(markdown);
@@ -12111,7 +12200,7 @@ function parseWorkflow(markdown, source) {
12111
12200
  return 2;
12112
12201
  };
12113
12202
  const ctx = {
12114
- filePath: path22,
12203
+ filePath: path23,
12115
12204
  errors: errors3,
12116
12205
  ...source.validateExecCwd ? { validateExecCwd: source.validateExecCwd } : {},
12117
12206
  lineAt,
@@ -12124,10 +12213,10 @@ function parseWorkflow(markdown, source) {
12124
12213
  if (range) {
12125
12214
  const start = Math.max(1, lineCounter2.linePos(range[0]).line + lineOffset);
12126
12215
  const end = Math.max(start, lineCounter2.linePos(Math.max(range[0], range[1] - 1)).line + lineOffset);
12127
- return { path: path22, start, end };
12216
+ return { path: path23, start, end };
12128
12217
  }
12129
12218
  }
12130
- return { path: path22, start: frontmatterEndLine, end: frontmatterEndLine };
12219
+ return { path: path23, start: frontmatterEndLine, end: frontmatterEndLine };
12131
12220
  },
12132
12221
  err: (p, message) => errors3.push({ line: lineAt(p), message }),
12133
12222
  errAtLine: (line, message) => errors3.push({ line, message })
@@ -12151,7 +12240,7 @@ function parseWorkflow(markdown, source) {
12151
12240
  const parsedSteps = parseSteps(ctx, root.steps);
12152
12241
  const toc = parseMarkdownToc(markdown);
12153
12242
  const declaredIds = new Set(parsedSteps.map((s) => s.id));
12154
- const { sections, preamble } = bindStepSections(toc.headings, lines, fmBlock.bodyStartLine, totalLines, path22, declaredIds, errors3);
12243
+ const { sections, preamble } = bindStepSections(toc.headings, lines, fmBlock.bodyStartLine, totalLines, path23, declaredIds, errors3);
12155
12244
  const steps = parsedSteps.map((step, index) => {
12156
12245
  const section = sections.get(step.id);
12157
12246
  if (!section) {
@@ -12195,14 +12284,14 @@ function parseWorkflow(markdown, source) {
12195
12284
  ...budget ? { budget } : {},
12196
12285
  steps,
12197
12286
  ...preamble ? { preamble } : {},
12198
- source: { path: path22, lineCount: totalLines }
12287
+ source: { path: path23, lineCount: totalLines }
12199
12288
  };
12200
12289
  runSemanticChecks(draft, root, frontmatterEndLine, errors3);
12201
12290
  if (errors3.length > 0)
12202
12291
  return { ok: false, errors: sortErrors(errors3) };
12203
12292
  return { ok: true, document: draft };
12204
12293
  }
12205
- function bindStepSections(headings, lines, bodyStartLine, totalLines, path22, declaredIds, errors3) {
12294
+ function bindStepSections(headings, lines, bodyStartLine, totalLines, path23, declaredIds, errors3) {
12206
12295
  const sections = new Map;
12207
12296
  const h2s = headings.filter((h) => h.level === 2);
12208
12297
  const firstH2Line = h2s[0]?.line;
@@ -12226,24 +12315,24 @@ function bindStepSections(headings, lines, bodyStartLine, totalLines, path22, de
12226
12315
  continue;
12227
12316
  }
12228
12317
  const sectionEnd = findNextHeadingAtOrAboveLevel(headings, i, 2, totalLines);
12229
- const gate = findGateSubsection(headings, i, sectionEnd, path22, h.text, errors3);
12318
+ const gate = findGateSubsection(headings, i, sectionEnd, path23, h.text, errors3);
12230
12319
  const instructionsEnd = gate ? gate.headingLine - 1 : sectionEnd;
12231
12320
  const instructionsText = sliceProseLines(lines, h.line + 1, instructionsEnd);
12232
12321
  const section = { headingLine: h.line };
12233
12322
  if (instructionsText) {
12234
- section.instructions = { text: instructionsText, source: { path: path22, start: h.line + 1, end: instructionsEnd } };
12323
+ section.instructions = { text: instructionsText, source: { path: path23, start: h.line + 1, end: instructionsEnd } };
12235
12324
  }
12236
12325
  if (gate) {
12237
12326
  const gateText = sliceProseLines(lines, gate.bodyStart, gate.bodyEnd);
12238
12327
  if (gateText) {
12239
- section.gateRubric = { text: gateText, source: { path: path22, start: gate.bodyStart, end: gate.bodyEnd } };
12328
+ section.gateRubric = { text: gateText, source: { path: path23, start: gate.bodyStart, end: gate.bodyEnd } };
12240
12329
  }
12241
12330
  }
12242
12331
  sections.set(h.text, section);
12243
12332
  }
12244
12333
  return { sections, preamble: preambleRaw || undefined };
12245
12334
  }
12246
- function findGateSubsection(headings, stepHeadingIndex, sectionEnd, path22, stepId, errors3) {
12335
+ function findGateSubsection(headings, stepHeadingIndex, sectionEnd, path23, stepId, errors3) {
12247
12336
  let found;
12248
12337
  for (let j = stepHeadingIndex + 1;j < headings.length; j++) {
12249
12338
  const h = headings[j];
@@ -12325,19 +12414,19 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
12325
12414
  ctx.err(["stale_after"], `Workflow frontmatter "stale_after" must be a string.`);
12326
12415
  }
12327
12416
  }
12328
- function checkActorStamp(ctx, value, path22, label) {
12417
+ function checkActorStamp(ctx, value, path23, label) {
12329
12418
  if (value === undefined)
12330
12419
  return;
12331
12420
  if (!isRecord(value)) {
12332
- ctx.err(path22, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12421
+ ctx.err(path23, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12333
12422
  return;
12334
12423
  }
12335
- checkUnknownKeys(ctx, value, path22, ACTOR_STAMP_KEYS, `${label} actor stamp`);
12424
+ checkUnknownKeys(ctx, value, path23, ACTOR_STAMP_KEYS, `${label} actor stamp`);
12336
12425
  if (typeof value.by !== "string" || value.by.length === 0) {
12337
- ctx.err([...path22, "by"], `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12426
+ ctx.err([...path23, "by"], `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12338
12427
  }
12339
12428
  if (value.at !== undefined && typeof value.at !== "string") {
12340
- ctx.err([...path22, "at"], `Workflow frontmatter ${label} actor stamp "at" must be a string.`);
12429
+ ctx.err([...path23, "at"], `Workflow frontmatter ${label} actor stamp "at" must be a string.`);
12341
12430
  }
12342
12431
  }
12343
12432
  function readTags2(ctx, value, fmEndLine) {
@@ -12390,38 +12479,38 @@ function parseOutputs(ctx, raw) {
12390
12479
  }
12391
12480
  const outputs = {};
12392
12481
  for (const [outputName, value] of Object.entries(raw)) {
12393
- const path22 = ["outputs", outputName];
12482
+ const path23 = ["outputs", outputName];
12394
12483
  if (!INPUT_NAME_PATTERN.test(outputName)) {
12395
- ctx.err(path22, `Output name "${outputName}" is invalid. Use letters, digits, and underscores, starting with a letter or ` + `underscore, so "steps.<child>.output.${outputName}" can address it.`);
12484
+ ctx.err(path23, `Output name "${outputName}" is invalid. Use letters, digits, and underscores, starting with a letter or ` + `underscore, so "steps.<child>.output.${outputName}" can address it.`);
12396
12485
  continue;
12397
12486
  }
12398
12487
  if (!isRecord(value)) {
12399
- ctx.err(path22, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
12488
+ ctx.err(path23, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
12400
12489
  continue;
12401
12490
  }
12402
- checkUnknownKeys(ctx, value, path22, OUTPUT_ENTRY_KEYS, `output "${outputName}"`);
12491
+ checkUnknownKeys(ctx, value, path23, OUTPUT_ENTRY_KEYS, `output "${outputName}"`);
12403
12492
  if (typeof value.from !== "string" || value.from.trim() === "") {
12404
- ctx.err([...path22, "from"], `Output "${outputName}" must declare "from": a steps.<id>.output(.<seg>)* reference.`);
12493
+ ctx.err([...path23, "from"], `Output "${outputName}" must declare "from": a steps.<id>.output(.<seg>)* reference.`);
12405
12494
  continue;
12406
12495
  }
12407
12496
  const parsedFrom = parseReference(value.from);
12408
12497
  if (!parsedFrom.ok) {
12409
- ctx.err([...path22, "from"], `Output "${outputName}" "from": ${parsedFrom.message}`);
12498
+ ctx.err([...path23, "from"], `Output "${outputName}" "from": ${parsedFrom.message}`);
12410
12499
  continue;
12411
12500
  }
12412
12501
  if (parsedFrom.expr.kind !== "stepOutput") {
12413
- ctx.err([...path22, "from"], `Output "${outputName}" "from" must reference a step output (steps.<id>.output...), not a param — an ` + `output projects a step artifact, never a param (got "${value.from}").`);
12502
+ ctx.err([...path23, "from"], `Output "${outputName}" "from" must reference a step output (steps.<id>.output...), not a param — an ` + `output projects a step artifact, never a param (got "${value.from}").`);
12414
12503
  continue;
12415
12504
  }
12416
12505
  const entry = { from: value.from };
12417
12506
  if (value.schema !== undefined) {
12418
12507
  if (!isRecord(value.schema)) {
12419
- ctx.err([...path22, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
12508
+ ctx.err([...path23, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
12420
12509
  } else {
12421
12510
  if (jsonBytes(value.schema) > WORKFLOW_MAX_SCHEMA_BYTES) {
12422
- ctx.err([...path22, "schema"], `Output "${outputName}" schema exceeds the 256 KiB resource limit.`);
12511
+ ctx.err([...path23, "schema"], `Output "${outputName}" schema exceeds the 256 KiB resource limit.`);
12423
12512
  }
12424
- checkSchemaDefinition(ctx, value.schema, [...path22, "schema"], `Output "${outputName}" schema`);
12513
+ checkSchemaDefinition(ctx, value.schema, [...path23, "schema"], `Output "${outputName}" schema`);
12425
12514
  entry.schema = value.schema;
12426
12515
  }
12427
12516
  }
@@ -12432,15 +12521,15 @@ function parseOutputs(ctx, raw) {
12432
12521
  function parseDefaults(ctx, raw) {
12433
12522
  if (raw === undefined)
12434
12523
  return;
12435
- const path22 = ["defaults"];
12524
+ const path23 = ["defaults"];
12436
12525
  if (!isRecord(raw)) {
12437
- ctx.err(path22, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
12526
+ ctx.err(path23, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
12438
12527
  return;
12439
12528
  }
12440
- checkUnknownKeys(ctx, raw, path22, DEFAULTS_KEYS, `"defaults"`);
12529
+ checkUnknownKeys(ctx, raw, path23, DEFAULTS_KEYS, `"defaults"`);
12441
12530
  const defaults = {};
12442
12531
  if (raw.engine !== undefined) {
12443
- const engine = parseEngineName(ctx, raw.engine, [...path22, "engine"], `"defaults.engine"`);
12532
+ const engine = parseEngineName(ctx, raw.engine, [...path23, "engine"], `"defaults.engine"`);
12444
12533
  if (engine !== undefined)
12445
12534
  defaults.engine = engine;
12446
12535
  }
@@ -12448,15 +12537,15 @@ function parseDefaults(ctx, raw) {
12448
12537
  if (typeof raw.model === "string" && raw.model.trim() !== "")
12449
12538
  defaults.model = raw.model.trim();
12450
12539
  else
12451
- ctx.err([...path22, "model"], `"defaults.model" must be a non-empty string (a model alias or exact id).`);
12540
+ ctx.err([...path23, "model"], `"defaults.model" must be a non-empty string (a model alias or exact id).`);
12452
12541
  }
12453
- const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path22, "timeout"], `"defaults.timeout"`);
12542
+ const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path23, "timeout"], `"defaults.timeout"`);
12454
12543
  if (timeoutMs !== undefined)
12455
12544
  defaults.timeoutMs = timeoutMs;
12456
- const onError = parseEnumField(ctx, raw.on_error, [...path22, "on_error"], `"defaults.on_error"`, PROGRAM_ON_ERROR);
12545
+ const onError = parseEnumField(ctx, raw.on_error, [...path23, "on_error"], `"defaults.on_error"`, PROGRAM_ON_ERROR);
12457
12546
  if (onError !== undefined)
12458
12547
  defaults.onError = onError;
12459
- const llm = parseLlmOverrides(ctx, raw.llm, [...path22, "llm"], `"defaults.llm"`);
12548
+ const llm = parseLlmOverrides(ctx, raw.llm, [...path23, "llm"], `"defaults.llm"`);
12460
12549
  if (llm !== undefined)
12461
12550
  defaults.llm = llm;
12462
12551
  return Object.keys(defaults).length > 0 ? defaults : undefined;
@@ -12464,25 +12553,25 @@ function parseDefaults(ctx, raw) {
12464
12553
  function parseBudget(ctx, raw) {
12465
12554
  if (raw === undefined)
12466
12555
  return;
12467
- const path22 = ["budget"];
12556
+ const path23 = ["budget"];
12468
12557
  if (!isRecord(raw)) {
12469
- ctx.err(path22, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
12558
+ ctx.err(path23, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
12470
12559
  return;
12471
12560
  }
12472
- checkUnknownKeys(ctx, raw, path22, BUDGET_KEYS, `"budget"`);
12561
+ checkUnknownKeys(ctx, raw, path23, BUDGET_KEYS, `"budget"`);
12473
12562
  const budget = {};
12474
12563
  if (raw.max_tokens !== undefined) {
12475
12564
  if (typeof raw.max_tokens === "number" && Number.isInteger(raw.max_tokens) && raw.max_tokens >= 1) {
12476
12565
  budget.maxTokens = raw.max_tokens;
12477
12566
  } else {
12478
- ctx.err([...path22, "max_tokens"], `"budget.max_tokens" must be an integer >= 1.`);
12567
+ ctx.err([...path23, "max_tokens"], `"budget.max_tokens" must be an integer >= 1.`);
12479
12568
  }
12480
12569
  }
12481
12570
  if (raw.max_units !== undefined) {
12482
12571
  if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1) {
12483
12572
  budget.maxUnits = raw.max_units;
12484
12573
  } else {
12485
- ctx.err([...path22, "max_units"], `"budget.max_units" must be an integer >= 1.`);
12574
+ ctx.err([...path23, "max_units"], `"budget.max_units" must be an integer >= 1.`);
12486
12575
  }
12487
12576
  }
12488
12577
  return Object.keys(budget).length > 0 ? budget : undefined;
@@ -12502,49 +12591,49 @@ function parseSteps(ctx, raw) {
12502
12591
  const seenIds = new Map;
12503
12592
  const routeChecks = [];
12504
12593
  raw.forEach((rawStep, index) => {
12505
- const path22 = ["steps", index];
12594
+ const path23 = ["steps", index];
12506
12595
  if (!isRecord(rawStep)) {
12507
- ctx.err(path22, `Step ${index + 1} must be a mapping with an "id".`);
12596
+ ctx.err(path23, `Step ${index + 1} must be a mapping with an "id".`);
12508
12597
  return;
12509
12598
  }
12510
12599
  const label = typeof rawStep.id === "string" && rawStep.id !== "" ? `Step "${rawStep.id}"` : `Step ${index + 1}`;
12511
- checkUnknownKeys(ctx, rawStep, path22, STEP_KEYS, label);
12600
+ checkUnknownKeys(ctx, rawStep, path23, STEP_KEYS, label);
12512
12601
  let id = "";
12513
12602
  if (typeof rawStep.id !== "string" || rawStep.id === "") {
12514
- ctx.err([...path22, "id"], `${label} requires a non-empty string "id".`);
12603
+ ctx.err([...path23, "id"], `${label} requires a non-empty string "id".`);
12515
12604
  } else if (!PROGRAM_STEP_ID_PATTERN.test(rawStep.id)) {
12516
- ctx.err([...path22, "id"], `${label} has an invalid id "${rawStep.id}". A step id cannot be referenced from steps.${rawStep.id}.output ` + `unless it matches [A-Za-z_][A-Za-z0-9_-]* (a letter or underscore first, then letters, digits, ` + `underscores, or dashes; no dots, no leading digit).`);
12605
+ ctx.err([...path23, "id"], `${label} has an invalid id "${rawStep.id}". A step id cannot be referenced from steps.${rawStep.id}.output ` + `unless it matches [A-Za-z_][A-Za-z0-9_-]* (a letter or underscore first, then letters, digits, ` + `underscores, or dashes; no dots, no leading digit).`);
12517
12606
  } else {
12518
12607
  id = rawStep.id;
12519
12608
  const firstIndex = seenIds.get(id);
12520
12609
  if (firstIndex !== undefined) {
12521
- ctx.err([...path22, "id"], `Duplicate step id "${id}" (first used by step ${firstIndex + 1}). Step ids must be unique.`);
12610
+ ctx.err([...path23, "id"], `Duplicate step id "${id}" (first used by step ${firstIndex + 1}). Step ids must be unique.`);
12522
12611
  } else {
12523
12612
  seenIds.set(id, index);
12524
12613
  }
12525
12614
  }
12526
12615
  const declaredKinds = ["map", "route"].filter((kind) => rawStep[kind] !== undefined);
12527
12616
  if (declaredKinds.length > 1) {
12528
- ctx.err(path22, `${label} must declare at most one of "map" or "route" (found ${declaredKinds.join(" + ")}).`);
12617
+ ctx.err(path23, `${label} must declare at most one of "map" or "route" (found ${declaredKinds.join(" + ")}).`);
12529
12618
  }
12530
12619
  const isRoute = rawStep.route !== undefined;
12531
12620
  const isMapStep = rawStep.map !== undefined;
12532
12621
  if (isRoute && rawStep.unit !== undefined) {
12533
- ctx.err(path22, `${label} is a route step and cannot also declare "unit" (route steps dispatch no unit).`);
12622
+ ctx.err(path23, `${label} is a route step and cannot also declare "unit" (route steps dispatch no unit).`);
12534
12623
  }
12535
12624
  if (isMapStep && rawStep.unit !== undefined) {
12536
- ctx.err(path22, `${label} is a map step; the per-item dispatch-override bag belongs at "map.unit", not top-level "unit".`);
12625
+ ctx.err(path23, `${label} is a map step; the per-item dispatch-override bag belongs at "map.unit", not top-level "unit".`);
12537
12626
  }
12538
12627
  if (isRoute && rawStep.inputs !== undefined) {
12539
- ctx.err(path22, `${label} is a route step and cannot declare "inputs" (route steps dispatch no unit).`);
12540
- }
12541
- const unit = rawStep.unit !== undefined && !isRoute && !isMapStep ? parseUnit(ctx, rawStep.unit, [...path22, "unit"], label) : undefined;
12542
- const map = isMapStep ? parseMap(ctx, rawStep.map, [...path22, "map"], label) : undefined;
12543
- const route = isRoute ? parseRoute(ctx, rawStep.route, [...path22, "route"], label, index, routeChecks) : undefined;
12544
- const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...path22, "inputs"], label) : undefined;
12545
- const output = parseSchemaObject(ctx, rawStep.output, [...path22, "output"], `${label} "output"`);
12546
- const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...path22, "gate"], label) : undefined;
12547
- const step = { id, source: ctx.refAt(path22) };
12628
+ ctx.err(path23, `${label} is a route step and cannot declare "inputs" (route steps dispatch no unit).`);
12629
+ }
12630
+ const unit = rawStep.unit !== undefined && !isRoute && !isMapStep ? parseUnit(ctx, rawStep.unit, [...path23, "unit"], label) : undefined;
12631
+ const map = isMapStep ? parseMap(ctx, rawStep.map, [...path23, "map"], label) : undefined;
12632
+ const route = isRoute ? parseRoute(ctx, rawStep.route, [...path23, "route"], label, index, routeChecks) : undefined;
12633
+ const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...path23, "inputs"], label) : undefined;
12634
+ const output = parseSchemaObject(ctx, rawStep.output, [...path23, "output"], `${label} "output"`);
12635
+ const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...path23, "gate"], label) : undefined;
12636
+ const step = { id, source: ctx.refAt(path23) };
12548
12637
  if (unit)
12549
12638
  step.unit = unit;
12550
12639
  if (map)
@@ -12576,25 +12665,25 @@ function parseSteps(ctx, raw) {
12576
12665
  }
12577
12666
  return steps;
12578
12667
  }
12579
- function parseUnit(ctx, raw, path22, stepLabel) {
12668
+ function parseUnit(ctx, raw, path23, stepLabel) {
12580
12669
  if (!isRecord(raw)) {
12581
- ctx.err(path22, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
12670
+ ctx.err(path23, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
12582
12671
  return;
12583
12672
  }
12584
- checkUnknownKeys(ctx, raw, path22, UNIT_KEYS, `${stepLabel} "unit"`);
12585
- const unit = { source: ctx.refAt(path22) };
12673
+ checkUnknownKeys(ctx, raw, path23, UNIT_KEYS, `${stepLabel} "unit"`);
12674
+ const unit = { source: ctx.refAt(path23) };
12586
12675
  if (raw.exec !== undefined) {
12587
- const exec = parseExec(ctx, raw.exec, [...path22, "exec"], stepLabel);
12676
+ const exec = parseExec(ctx, raw.exec, [...path23, "exec"], stepLabel);
12588
12677
  if (exec !== undefined)
12589
12678
  unit.exec = exec;
12590
12679
  for (const key of UNIT_ENGINE_KEYS) {
12591
12680
  if (raw[key] === undefined)
12592
12681
  continue;
12593
- ctx.err([...path22, key], `${stepLabel} "unit" declares both "exec" and "${key}". An exec unit runs a shell command and never ` + `reaches an engine, so "${key}" would have no effect — remove one of the two.`);
12682
+ ctx.err([...path23, key], `${stepLabel} "unit" declares both "exec" and "${key}". An exec unit runs a shell command and never ` + `reaches an engine, so "${key}" would have no effect — remove one of the two.`);
12594
12683
  }
12595
12684
  }
12596
12685
  if (raw.engine !== undefined) {
12597
- const engine = parseEngineName(ctx, raw.engine, [...path22, "engine"], `${stepLabel} "engine"`);
12686
+ const engine = parseEngineName(ctx, raw.engine, [...path23, "engine"], `${stepLabel} "engine"`);
12598
12687
  if (engine !== undefined)
12599
12688
  unit.engine = engine;
12600
12689
  }
@@ -12602,21 +12691,21 @@ function parseUnit(ctx, raw, path22, stepLabel) {
12602
12691
  if (typeof raw.model === "string" && raw.model.trim() !== "")
12603
12692
  unit.model = raw.model.trim();
12604
12693
  else
12605
- ctx.err([...path22, "model"], `${stepLabel} "model" must be a non-empty string (a model alias or exact id).`);
12694
+ ctx.err([...path23, "model"], `${stepLabel} "model" must be a non-empty string (a model alias or exact id).`);
12606
12695
  }
12607
- const llm = parseLlmOverrides(ctx, raw.llm, [...path22, "llm"], `${stepLabel} "llm"`);
12696
+ const llm = parseLlmOverrides(ctx, raw.llm, [...path23, "llm"], `${stepLabel} "llm"`);
12608
12697
  if (llm !== undefined)
12609
12698
  unit.llm = llm;
12610
- const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path22, "timeout"], `${stepLabel} "timeout"`);
12699
+ const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path23, "timeout"], `${stepLabel} "timeout"`);
12611
12700
  if (timeoutMs !== undefined)
12612
12701
  unit.timeoutMs = timeoutMs;
12613
- const retry = parseRetry(ctx, raw.retry, [...path22, "retry"], stepLabel);
12702
+ const retry = parseRetry(ctx, raw.retry, [...path23, "retry"], stepLabel);
12614
12703
  if (retry !== undefined)
12615
12704
  unit.retry = retry;
12616
- const onError = parseEnumField(ctx, raw.on_error, [...path22, "on_error"], `${stepLabel} "on_error"`, PROGRAM_ON_ERROR);
12705
+ const onError = parseEnumField(ctx, raw.on_error, [...path23, "on_error"], `${stepLabel} "on_error"`, PROGRAM_ON_ERROR);
12617
12706
  if (onError !== undefined)
12618
12707
  unit.onError = onError;
12619
- const output = parseSchemaObject(ctx, raw.output, [...path22, "output"], `${stepLabel} unit "output"`);
12708
+ const output = parseSchemaObject(ctx, raw.output, [...path23, "output"], `${stepLabel} unit "output"`);
12620
12709
  if (output !== undefined)
12621
12710
  unit.output = output;
12622
12711
  if (raw.env !== undefined) {
@@ -12624,87 +12713,87 @@ function parseUnit(ctx, raw, path22, stepLabel) {
12624
12713
  const envRefs = raw.env.map((entry) => entry.trim());
12625
12714
  const duplicate = envRefs.find((ref, i) => envRefs.indexOf(ref) !== i);
12626
12715
  if (duplicate !== undefined) {
12627
- ctx.err([...path22, "env"], `${stepLabel} "env" contains a duplicate entry: "${duplicate}".`);
12716
+ ctx.err([...path23, "env"], `${stepLabel} "env" contains a duplicate entry: "${duplicate}".`);
12628
12717
  } else {
12629
12718
  unit.env = envRefs;
12630
12719
  }
12631
12720
  } else {
12632
- ctx.err([...path22, "env"], `${stepLabel} "env" must be a list of non-empty env asset refs.`);
12721
+ ctx.err([...path23, "env"], `${stepLabel} "env" must be a list of non-empty env asset refs.`);
12633
12722
  }
12634
12723
  }
12635
- const isolation = parseEnumField(ctx, raw.isolation, [...path22, "isolation"], `${stepLabel} "isolation"`, PROGRAM_ISOLATION_KINDS);
12724
+ const isolation = parseEnumField(ctx, raw.isolation, [...path23, "isolation"], `${stepLabel} "isolation"`, PROGRAM_ISOLATION_KINDS);
12636
12725
  if (isolation !== undefined)
12637
12726
  unit.isolation = isolation;
12638
12727
  return unit;
12639
12728
  }
12640
- function parseExec(ctx, raw, path22, stepLabel) {
12729
+ function parseExec(ctx, raw, path23, stepLabel) {
12641
12730
  if (!isRecord(raw)) {
12642
- ctx.err(path22, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
12731
+ ctx.err(path23, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
12643
12732
  return;
12644
12733
  }
12645
- checkUnknownKeys(ctx, raw, path22, EXEC_KEYS, `${stepLabel} "exec"`);
12646
- const command = parseExecCommand(ctx, raw.command, [...path22, "command"], stepLabel);
12734
+ checkUnknownKeys(ctx, raw, path23, EXEC_KEYS, `${stepLabel} "exec"`);
12735
+ const command = parseExecCommand(ctx, raw.command, [...path23, "command"], stepLabel);
12647
12736
  if (command === undefined)
12648
12737
  return;
12649
12738
  const exec = { command };
12650
- const cwd = parseExecCwd(ctx, raw.cwd, [...path22, "cwd"], stepLabel);
12739
+ const cwd = parseExecCwd(ctx, raw.cwd, [...path23, "cwd"], stepLabel);
12651
12740
  if (cwd !== undefined)
12652
12741
  exec.cwd = cwd;
12653
- const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...path22, "pass_env"], stepLabel);
12742
+ const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...path23, "pass_env"], stepLabel);
12654
12743
  if (passEnv !== undefined)
12655
12744
  exec.passEnv = passEnv;
12656
12745
  return exec;
12657
12746
  }
12658
- function parseExecPassEnv(ctx, raw, path22, stepLabel) {
12747
+ function parseExecPassEnv(ctx, raw, path23, stepLabel) {
12659
12748
  if (raw === undefined)
12660
12749
  return;
12661
12750
  if (!Array.isArray(raw) || raw.length === 0) {
12662
- ctx.err(path22, `${stepLabel} "exec.pass_env" must be a non-empty list of environment variable NAMES to copy through from ` + `akm's own environment, e.g. pass_env: [CARGO_HOME]. Values never appear here — use "env:" bindings for those.`);
12751
+ ctx.err(path23, `${stepLabel} "exec.pass_env" must be a non-empty list of environment variable NAMES to copy through from ` + `akm's own environment, e.g. pass_env: [CARGO_HOME]. Values never appear here — use "env:" bindings for those.`);
12663
12752
  return;
12664
12753
  }
12665
12754
  const names = [];
12666
12755
  for (const [index, entry] of raw.entries()) {
12667
12756
  if (typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry)) {
12668
- ctx.err(path22, `${stepLabel} "exec.pass_env[${index}]" must be an environment variable name matching ` + `${WORKFLOW_ENV_VAR_NAME_PATTERN.source}.`);
12757
+ ctx.err(path23, `${stepLabel} "exec.pass_env[${index}]" must be an environment variable name matching ` + `${WORKFLOW_ENV_VAR_NAME_PATTERN.source}.`);
12669
12758
  return;
12670
12759
  }
12671
12760
  if (names.includes(entry)) {
12672
- ctx.err(path22, `${stepLabel} "exec.pass_env" lists "${entry}" more than once.`);
12761
+ ctx.err(path23, `${stepLabel} "exec.pass_env" lists "${entry}" more than once.`);
12673
12762
  return;
12674
12763
  }
12675
12764
  names.push(entry);
12676
12765
  }
12677
12766
  return names;
12678
12767
  }
12679
- function parseExecCommand(ctx, raw, path22, stepLabel) {
12768
+ function parseExecCommand(ctx, raw, path23, stepLabel) {
12680
12769
  if (!Array.isArray(raw) || raw.length === 0) {
12681
- ctx.err(path22, `${stepLabel} "exec" requires "command": a non-empty argv list, e.g. command: ["bun", "run", "test:unit"]. ` + `A single shell string is not accepted — the command is spawned directly, never through a shell.`);
12770
+ ctx.err(path23, `${stepLabel} "exec" requires "command": a non-empty argv list, e.g. command: ["bun", "run", "test:unit"]. ` + `A single shell string is not accepted — the command is spawned directly, never through a shell.`);
12682
12771
  return;
12683
12772
  }
12684
12773
  const argv = [];
12685
12774
  for (const [index, entry] of raw.entries()) {
12686
12775
  if (typeof entry !== "string" || entry === "") {
12687
- ctx.err(path22, `${stepLabel} "exec.command[${index}]" must be a non-empty string.`);
12776
+ ctx.err(path23, `${stepLabel} "exec.command[${index}]" must be a non-empty string.`);
12688
12777
  return;
12689
12778
  }
12690
12779
  if (entry.includes("\x00")) {
12691
- ctx.err([...path22, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
12780
+ ctx.err([...path23, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
12692
12781
  return;
12693
12782
  }
12694
12783
  argv.push(entry);
12695
12784
  }
12696
12785
  return argv;
12697
12786
  }
12698
- function parseExecCwd(ctx, raw, path22, stepLabel) {
12787
+ function parseExecCwd(ctx, raw, path23, stepLabel) {
12699
12788
  if (raw === undefined)
12700
12789
  return;
12701
12790
  if (typeof raw !== "string" || raw.trim() === "") {
12702
- ctx.err(path22, `${stepLabel} "exec.cwd" must be a non-empty relative path inside the unit's working directory.`);
12791
+ ctx.err(path23, `${stepLabel} "exec.cwd" must be a non-empty relative path inside the unit's working directory.`);
12703
12792
  return;
12704
12793
  }
12705
12794
  const value = raw.trim();
12706
12795
  if (!isContainedRelativePath(value)) {
12707
- ctx.err(path22, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` + `directory — absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
12796
+ ctx.err(path23, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` + `directory — absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
12708
12797
  return;
12709
12798
  }
12710
12799
  if (ctx.validateExecCwd) {
@@ -12712,7 +12801,7 @@ function parseExecCwd(ctx, raw, path22, stepLabel) {
12712
12801
  if (!semantic.ok) {
12713
12802
  ctx.errors.push({
12714
12803
  code: semantic.code,
12715
- line: ctx.lineAt(path22),
12804
+ line: ctx.lineAt(path23),
12716
12805
  message: semantic.message
12717
12806
  });
12718
12807
  return;
@@ -12721,29 +12810,29 @@ function parseExecCwd(ctx, raw, path22, stepLabel) {
12721
12810
  }
12722
12811
  return value;
12723
12812
  }
12724
- function parseMap(ctx, raw, path22, stepLabel) {
12813
+ function parseMap(ctx, raw, path23, stepLabel) {
12725
12814
  if (!isRecord(raw)) {
12726
- ctx.err(path22, `${stepLabel} "map" must be a mapping with an "over" key.`);
12815
+ ctx.err(path23, `${stepLabel} "map" must be a mapping with an "over" key.`);
12727
12816
  return;
12728
12817
  }
12729
- checkUnknownKeys(ctx, raw, path22, MAP_KEYS, `${stepLabel} "map"`);
12818
+ checkUnknownKeys(ctx, raw, path23, MAP_KEYS, `${stepLabel} "map"`);
12730
12819
  let over = "";
12731
12820
  if (typeof raw.over === "string" && raw.over.trim() !== "") {
12732
12821
  over = raw.over.trim();
12733
- checkReferenceSyntax(ctx, over, [...path22, "over"], `${stepLabel} "over"`);
12822
+ checkReferenceSyntax(ctx, over, [...path23, "over"], `${stepLabel} "over"`);
12734
12823
  } else {
12735
- ctx.err([...path22, "over"], `${stepLabel} "map" requires "over": a reference naming the item list (e.g. steps.discover.output.files).`);
12824
+ ctx.err([...path23, "over"], `${stepLabel} "map" requires "over": a reference naming the item list (e.g. steps.discover.output.files).`);
12736
12825
  }
12737
12826
  let concurrency;
12738
12827
  if (raw.concurrency !== undefined) {
12739
12828
  if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0) {
12740
12829
  concurrency = Math.min(raw.concurrency, WORKFLOW_MAX_CONCURRENCY);
12741
12830
  } else {
12742
- ctx.err([...path22, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
12831
+ ctx.err([...path23, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
12743
12832
  }
12744
12833
  }
12745
- const reducer = parseEnumField(ctx, raw.reducer, [...path22, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
12746
- const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path22, "unit"], stepLabel) : undefined;
12834
+ const reducer = parseEnumField(ctx, raw.reducer, [...path23, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
12835
+ const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path23, "unit"], stepLabel) : undefined;
12747
12836
  const map = { over };
12748
12837
  if (concurrency !== undefined)
12749
12838
  map.concurrency = concurrency;
@@ -12753,21 +12842,21 @@ function parseMap(ctx, raw, path22, stepLabel) {
12753
12842
  map.unit = unit;
12754
12843
  return map;
12755
12844
  }
12756
- function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
12845
+ function parseRoute(ctx, raw, path23, stepLabel, stepIndex, routeChecks) {
12757
12846
  if (!isRecord(raw)) {
12758
- ctx.err(path22, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
12847
+ ctx.err(path23, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
12759
12848
  return;
12760
12849
  }
12761
- checkUnknownKeys(ctx, raw, path22, ROUTE_KEYS, `${stepLabel} "route"`);
12850
+ checkUnknownKeys(ctx, raw, path23, ROUTE_KEYS, `${stepLabel} "route"`);
12762
12851
  let input = "";
12763
12852
  if (typeof raw.input === "string" && raw.input.trim() !== "") {
12764
12853
  input = raw.input.trim();
12765
- checkReferenceSyntax(ctx, input, [...path22, "input"], `${stepLabel} "route.input"`);
12854
+ checkReferenceSyntax(ctx, input, [...path23, "input"], `${stepLabel} "route.input"`);
12766
12855
  } else {
12767
- ctx.err([...path22, "input"], `${stepLabel} "route" requires "input": a reference naming the value to route on.`);
12856
+ ctx.err([...path23, "input"], `${stepLabel} "route" requires "input": a reference naming the value to route on.`);
12768
12857
  }
12769
12858
  const check = { stepIndex, stepLabel, branches: [] };
12770
- const whenPath = [...path22, "when"];
12859
+ const whenPath = [...path23, "when"];
12771
12860
  if (!Array.isArray(raw.when) || raw.when.length === 0) {
12772
12861
  ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
12773
12862
  } else {
@@ -12808,9 +12897,9 @@ function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
12808
12897
  if (raw.default !== undefined) {
12809
12898
  if (typeof raw.default === "string" && raw.default.trim() !== "") {
12810
12899
  defaultStepId = raw.default.trim();
12811
- check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...path22, "default"]) };
12900
+ check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...path23, "default"]) };
12812
12901
  } else {
12813
- ctx.err([...path22, "default"], `${stepLabel} "route.default" must be a step id string.`);
12902
+ ctx.err([...path23, "default"], `${stepLabel} "route.default" must be a step id string.`);
12814
12903
  }
12815
12904
  }
12816
12905
  routeChecks.push(check);
@@ -12819,70 +12908,70 @@ function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
12819
12908
  route.defaultStepId = defaultStepId;
12820
12909
  return route;
12821
12910
  }
12822
- function parseInputs(ctx, raw, path22, stepLabel) {
12911
+ function parseInputs(ctx, raw, path23, stepLabel) {
12823
12912
  if (raw === undefined)
12824
12913
  return;
12825
12914
  if (!Array.isArray(raw) || raw.length === 0) {
12826
- ctx.err(path22, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
12915
+ ctx.err(path23, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
12827
12916
  return;
12828
12917
  }
12829
12918
  const out = [];
12830
12919
  const seen = new Set;
12831
12920
  raw.forEach((entry, i) => {
12832
12921
  if (typeof entry !== "string" || entry.trim() === "") {
12833
- ctx.err([...path22, i], `${stepLabel} "inputs[${i}]" must be a non-empty reference string.`);
12922
+ ctx.err([...path23, i], `${stepLabel} "inputs[${i}]" must be a non-empty reference string.`);
12834
12923
  return;
12835
12924
  }
12836
12925
  const value = entry.trim();
12837
12926
  if (seen.has(value)) {
12838
- ctx.err([...path22, i], `${stepLabel} "inputs[${i}]" duplicates an earlier entry: "${value}".`);
12927
+ ctx.err([...path23, i], `${stepLabel} "inputs[${i}]" duplicates an earlier entry: "${value}".`);
12839
12928
  return;
12840
12929
  }
12841
12930
  seen.add(value);
12842
- checkReferenceSyntax(ctx, value, [...path22, i], `${stepLabel} "inputs[${i}]"`);
12931
+ checkReferenceSyntax(ctx, value, [...path23, i], `${stepLabel} "inputs[${i}]"`);
12843
12932
  out.push(value);
12844
12933
  });
12845
12934
  return out.length > 0 ? out : undefined;
12846
12935
  }
12847
- function parseGate(ctx, raw, path22, stepLabel) {
12936
+ function parseGate(ctx, raw, path23, stepLabel) {
12848
12937
  if (!isRecord(raw)) {
12849
- ctx.err(path22, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
12938
+ ctx.err(path23, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
12850
12939
  return;
12851
12940
  }
12852
- checkUnknownKeys(ctx, raw, path22, GATE_KEYS, `${stepLabel} "gate"`);
12941
+ checkUnknownKeys(ctx, raw, path23, GATE_KEYS, `${stepLabel} "gate"`);
12853
12942
  const gate = {};
12854
12943
  if (raw.max_loops !== undefined) {
12855
12944
  if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1) {
12856
12945
  gate.maxLoops = raw.max_loops;
12857
12946
  } else {
12858
- ctx.err([...path22, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
12947
+ ctx.err([...path23, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
12859
12948
  }
12860
12949
  }
12861
12950
  return gate;
12862
12951
  }
12863
- function parseEngineName(ctx, raw, path22, label) {
12952
+ function parseEngineName(ctx, raw, path23, label) {
12864
12953
  if (typeof raw !== "string" || raw.trim() === "") {
12865
- ctx.err(path22, `${label} must be a non-empty engine name.`);
12954
+ ctx.err(path23, `${label} must be a non-empty engine name.`);
12866
12955
  return;
12867
12956
  }
12868
12957
  const name = raw.trim();
12869
12958
  if (!WORKFLOW_ENGINE_NAME_PATTERN.test(name) || name.length > WORKFLOW_MAX_ENGINE_NAME_LENGTH) {
12870
- ctx.err(path22, `${label} has an invalid engine name ${JSON.stringify(name)}. Engine names are lowercase words of letters ` + `and digits separated by single dashes, starting with a letter (e.g. "code-review-llm"), at most ` + `${WORKFLOW_MAX_ENGINE_NAME_LENGTH} characters.`);
12959
+ ctx.err(path23, `${label} has an invalid engine name ${JSON.stringify(name)}. Engine names are lowercase words of letters ` + `and digits separated by single dashes, starting with a letter (e.g. "code-review-llm"), at most ` + `${WORKFLOW_MAX_ENGINE_NAME_LENGTH} characters.`);
12871
12960
  return;
12872
12961
  }
12873
12962
  return name;
12874
12963
  }
12875
- function parseRetry(ctx, raw, path22, stepLabel) {
12964
+ function parseRetry(ctx, raw, path23, stepLabel) {
12876
12965
  if (raw === undefined)
12877
12966
  return;
12878
12967
  if (!isRecord(raw)) {
12879
- ctx.err(path22, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, …] }.`);
12968
+ ctx.err(path23, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, …] }.`);
12880
12969
  return;
12881
12970
  }
12882
- checkUnknownKeys(ctx, raw, path22, RETRY_KEYS, `${stepLabel} "retry"`);
12971
+ checkUnknownKeys(ctx, raw, path23, RETRY_KEYS, `${stepLabel} "retry"`);
12883
12972
  let ok = true;
12884
12973
  if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0)) {
12885
- ctx.err([...path22, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
12974
+ ctx.err([...path23, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
12886
12975
  ok = false;
12887
12976
  }
12888
12977
  const on = [];
@@ -12891,27 +12980,27 @@ function parseRetry(ctx, raw, path22, stepLabel) {
12891
12980
  if (typeof reason === "string" && PROGRAM_RETRY_REASONS.includes(reason)) {
12892
12981
  on.push(reason);
12893
12982
  } else {
12894
- ctx.err([...path22, "on", i], `${stepLabel} "retry.on" has unknown failure reason ${JSON.stringify(reason)}. Valid reasons: ${PROGRAM_RETRY_REASONS.join(", ")}.`);
12983
+ ctx.err([...path23, "on", i], `${stepLabel} "retry.on" has unknown failure reason ${JSON.stringify(reason)}. Valid reasons: ${PROGRAM_RETRY_REASONS.join(", ")}.`);
12895
12984
  ok = false;
12896
12985
  }
12897
12986
  });
12898
12987
  } else {
12899
- ctx.err([...path22, "on"], `${stepLabel} "retry.on" is required and must be a non-empty list of failure reasons (${PROGRAM_RETRY_REASONS.join(", ")}).`);
12988
+ ctx.err([...path23, "on"], `${stepLabel} "retry.on" is required and must be a non-empty list of failure reasons (${PROGRAM_RETRY_REASONS.join(", ")}).`);
12900
12989
  ok = false;
12901
12990
  }
12902
12991
  return ok ? { max: raw.max, on } : undefined;
12903
12992
  }
12904
- function parseTimeoutField(ctx, raw, path22, label) {
12993
+ function parseTimeoutField(ctx, raw, path23, label) {
12905
12994
  if (raw === undefined)
12906
12995
  return;
12907
12996
  if (typeof raw === "number") {
12908
12997
  if (Number.isInteger(raw) && raw > 0)
12909
- return checkTimeoutCeiling(ctx, raw, path22, label, String(raw));
12910
- ctx.err(path22, `${label} has a non-positive timeout ${JSON.stringify(raw)}. ${TIMEOUT_HINT}.`);
12998
+ return checkTimeoutCeiling(ctx, raw, path23, label, String(raw));
12999
+ ctx.err(path23, `${label} has a non-positive timeout ${JSON.stringify(raw)}. ${TIMEOUT_HINT}.`);
12911
13000
  return;
12912
13001
  }
12913
13002
  if (typeof raw !== "string") {
12914
- ctx.err(path22, `${label} must be a duration string. ${TIMEOUT_HINT}.`);
13003
+ ctx.err(path23, `${label} must be a duration string. ${TIMEOUT_HINT}.`);
12915
13004
  return;
12916
13005
  }
12917
13006
  const value = raw.trim().toLowerCase();
@@ -12919,37 +13008,37 @@ function parseTimeoutField(ctx, raw, path22, label) {
12919
13008
  return null;
12920
13009
  const match = value.match(TIMEOUT_VALUE);
12921
13010
  if (!match) {
12922
- ctx.err(path22, `${label} has an invalid timeout "${raw}". ${TIMEOUT_HINT}.`);
13011
+ ctx.err(path23, `${label} has an invalid timeout "${raw}". ${TIMEOUT_HINT}.`);
12923
13012
  return;
12924
13013
  }
12925
13014
  const n = Number.parseInt(match[1], 10);
12926
13015
  const unit = match[2] ?? "ms";
12927
13016
  const timeoutMs = unit === "m" ? n * 60000 : unit === "s" ? n * 1000 : n;
12928
13017
  if (timeoutMs <= 0) {
12929
- ctx.err(path22, `${label} has a non-positive timeout "${raw}". Use a positive duration or "none".`);
13018
+ ctx.err(path23, `${label} has a non-positive timeout "${raw}". Use a positive duration or "none".`);
12930
13019
  return;
12931
13020
  }
12932
- return checkTimeoutCeiling(ctx, timeoutMs, path22, label, raw);
13021
+ return checkTimeoutCeiling(ctx, timeoutMs, path23, label, raw);
12933
13022
  }
12934
- function checkTimeoutCeiling(ctx, timeoutMs, path22, label, raw) {
13023
+ function checkTimeoutCeiling(ctx, timeoutMs, path23, label, raw) {
12935
13024
  if (timeoutMs <= WORKFLOW_MAX_TIMEOUT_MS)
12936
13025
  return timeoutMs;
12937
- ctx.err(path22, `${label} has a timeout "${raw}" above the maximum of ${WORKFLOW_MAX_TIMEOUT_MS} ms (about 24.8 days). ` + `Use a shorter duration or "none" for no timeout.`);
13026
+ ctx.err(path23, `${label} has a timeout "${raw}" above the maximum of ${WORKFLOW_MAX_TIMEOUT_MS} ms (about 24.8 days). ` + `Use a shorter duration or "none" for no timeout.`);
12938
13027
  return;
12939
13028
  }
12940
- function parseEnumField(ctx, raw, path22, label, allowed) {
13029
+ function parseEnumField(ctx, raw, path23, label, allowed) {
12941
13030
  if (raw === undefined)
12942
13031
  return;
12943
13032
  if (typeof raw === "string" && allowed.includes(raw))
12944
13033
  return raw;
12945
- ctx.err(path22, `${label} must be one of: ${allowed.join(" | ")} (got ${JSON.stringify(raw)}).`);
13034
+ ctx.err(path23, `${label} must be one of: ${allowed.join(" | ")} (got ${JSON.stringify(raw)}).`);
12946
13035
  return;
12947
13036
  }
12948
- function parseLlmOverrides(ctx, raw, path22, label) {
13037
+ function parseLlmOverrides(ctx, raw, path23, label) {
12949
13038
  if (raw === undefined)
12950
13039
  return;
12951
13040
  if (!isRecord(raw)) {
12952
- ctx.err(path22, `${label} must be a mapping of LLM invocation overrides.`);
13041
+ ctx.err(path23, `${label} must be a mapping of LLM invocation overrides.`);
12953
13042
  return;
12954
13043
  }
12955
13044
  const keys2 = [
@@ -12961,36 +13050,36 @@ function parseLlmOverrides(ctx, raw, path22, label) {
12961
13050
  "enable_thinking",
12962
13051
  "reasoning_effort"
12963
13052
  ];
12964
- checkUnknownKeys(ctx, raw, path22, keys2, label);
13053
+ checkUnknownKeys(ctx, raw, path23, keys2, label);
12965
13054
  const result = {};
12966
13055
  if (raw.temperature !== undefined) {
12967
13056
  if (typeof raw.temperature === "number" && Number.isFinite(raw.temperature))
12968
13057
  result.temperature = raw.temperature;
12969
13058
  else
12970
- ctx.err([...path22, "temperature"], `${label}.temperature must be a finite number.`);
13059
+ ctx.err([...path23, "temperature"], `${label}.temperature must be a finite number.`);
12971
13060
  }
12972
13061
  if (raw.max_tokens !== undefined) {
12973
13062
  if (typeof raw.max_tokens === "number" && Number.isInteger(raw.max_tokens) && raw.max_tokens > 0) {
12974
13063
  result.maxTokens = raw.max_tokens;
12975
13064
  } else
12976
- ctx.err([...path22, "max_tokens"], `${label}.max_tokens must be a positive integer.`);
13065
+ ctx.err([...path23, "max_tokens"], `${label}.max_tokens must be a positive integer.`);
12977
13066
  }
12978
13067
  if (raw.supports_json_schema !== undefined) {
12979
13068
  if (typeof raw.supports_json_schema === "boolean")
12980
13069
  result.supportsJsonSchema = raw.supports_json_schema;
12981
13070
  else
12982
- ctx.err([...path22, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
13071
+ ctx.err([...path23, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
12983
13072
  }
12984
13073
  if (raw.extra_params !== undefined) {
12985
13074
  if (!isRecord(raw.extra_params)) {
12986
- ctx.err([...path22, "extra_params"], `${label}.extra_params must be a JSON object.`);
13075
+ ctx.err([...path23, "extra_params"], `${label}.extra_params must be a JSON object.`);
12987
13076
  } else {
12988
13077
  const issues = validateExtraParams(raw.extra_params);
12989
13078
  for (const issue of issues) {
12990
- ctx.err([...path22, "extra_params", ...issue.path], `${formatExtraParamsIssue(`${label}.extra_params`, issue)}.`);
13079
+ ctx.err([...path23, "extra_params", ...issue.path], `${formatExtraParamsIssue(`${label}.extra_params`, issue)}.`);
12991
13080
  }
12992
13081
  if (jsonBytes(raw.extra_params) > WORKFLOW_MAX_EXTRA_PARAMS_BYTES) {
12993
- ctx.err([...path22, "extra_params"], `${label}.extra_params exceeds the 64 KiB resource limit.`);
13082
+ ctx.err([...path23, "extra_params"], `${label}.extra_params exceeds the 64 KiB resource limit.`);
12994
13083
  }
12995
13084
  if (issues.length === 0 && jsonBytes(raw.extra_params) <= WORKFLOW_MAX_EXTRA_PARAMS_BYTES) {
12996
13085
  result.extraParams = raw.extra_params;
@@ -13001,38 +13090,38 @@ function parseLlmOverrides(ctx, raw, path22, label) {
13001
13090
  if (typeof raw.context_length === "number" && Number.isInteger(raw.context_length) && raw.context_length > 0) {
13002
13091
  result.contextLength = raw.context_length;
13003
13092
  } else
13004
- ctx.err([...path22, "context_length"], `${label}.context_length must be a positive integer.`);
13093
+ ctx.err([...path23, "context_length"], `${label}.context_length must be a positive integer.`);
13005
13094
  }
13006
13095
  if (raw.enable_thinking !== undefined) {
13007
13096
  if (typeof raw.enable_thinking === "boolean")
13008
13097
  result.enableThinking = raw.enable_thinking;
13009
13098
  else
13010
- ctx.err([...path22, "enable_thinking"], `${label}.enable_thinking must be a boolean.`);
13099
+ ctx.err([...path23, "enable_thinking"], `${label}.enable_thinking must be a boolean.`);
13011
13100
  }
13012
13101
  if (raw.reasoning_effort !== undefined) {
13013
13102
  if (typeof raw.reasoning_effort === "string" && raw.reasoning_effort.trim().length > 0) {
13014
13103
  result.reasoningEffort = raw.reasoning_effort;
13015
13104
  } else
13016
- ctx.err([...path22, "reasoning_effort"], `${label}.reasoning_effort must be a non-empty string.`);
13105
+ ctx.err([...path23, "reasoning_effort"], `${label}.reasoning_effort must be a non-empty string.`);
13017
13106
  }
13018
13107
  return Object.keys(result).length > 0 ? result : undefined;
13019
13108
  }
13020
- function parseSchemaObject(ctx, raw, path22, label) {
13109
+ function parseSchemaObject(ctx, raw, path23, label) {
13021
13110
  if (raw === undefined)
13022
13111
  return;
13023
13112
  if (!isRecord(raw)) {
13024
- ctx.err(path22, `${label} must be a JSON Schema object (e.g. { type: object, properties: { … } }).`);
13113
+ ctx.err(path23, `${label} must be a JSON Schema object (e.g. { type: object, properties: { … } }).`);
13025
13114
  return;
13026
13115
  }
13027
13116
  if (jsonBytes(raw) > WORKFLOW_MAX_SCHEMA_BYTES) {
13028
- ctx.err(path22, `${label} exceeds the 256 KiB resource limit.`);
13117
+ ctx.err(path23, `${label} exceeds the 256 KiB resource limit.`);
13029
13118
  }
13030
- checkSchemaDefinition(ctx, raw, path22, label);
13119
+ checkSchemaDefinition(ctx, raw, path23, label);
13031
13120
  return raw;
13032
13121
  }
13033
- function checkSchemaDefinition(ctx, schema, path22, label) {
13122
+ function checkSchemaDefinition(ctx, schema, path23, label) {
13034
13123
  for (const issue of checkJsonSchemaDefinition(schema)) {
13035
- const issuePath = [...path22, ...issue.path];
13124
+ const issuePath = [...path23, ...issue.path];
13036
13125
  if (issue.kind === "unsupported") {
13037
13126
  ctx.err(issuePath, `${label} (at ${issue.pointer}): ${issue.message}. Supported JSON Schema keywords: ` + `${JSON_SCHEMA_SUBSET_SUPPORTED_KEYWORDS}.`);
13038
13127
  } else {
@@ -13040,15 +13129,15 @@ function checkSchemaDefinition(ctx, schema, path22, label) {
13040
13129
  }
13041
13130
  }
13042
13131
  }
13043
- function checkReferenceSyntax(ctx, text, path22, label) {
13132
+ function checkReferenceSyntax(ctx, text, path23, label) {
13044
13133
  const result = parseReference(text);
13045
13134
  if (!result.ok)
13046
- ctx.err(path22, `${label}: ${result.message}`);
13135
+ ctx.err(path23, `${label}: ${result.message}`);
13047
13136
  }
13048
- function checkUnknownKeys(ctx, obj, path22, allowed, label) {
13137
+ function checkUnknownKeys(ctx, obj, path23, allowed, label) {
13049
13138
  for (const key of Object.keys(obj)) {
13050
13139
  if (!allowed.includes(key)) {
13051
- ctx.err([...path22, key], `Unknown ${label} key "${key}". Allowed keys: ${allowed.join(", ")}.`);
13140
+ ctx.err([...path23, key], `Unknown ${label} key "${key}". Allowed keys: ${allowed.join(", ")}.`);
13052
13141
  }
13053
13142
  }
13054
13143
  }
@@ -13108,7 +13197,7 @@ var init_parser = __esm(() => {
13108
13197
  });
13109
13198
 
13110
13199
  // src/workflows/source-ir/result.ts
13111
- function sourceFailureResult(cause, path22) {
13200
+ function sourceFailureResult(cause, path23) {
13112
13201
  if (cause instanceof WorkflowSourceFailure)
13113
13202
  return { ok: false, errors: [cause.error] };
13114
13203
  return {
@@ -13117,7 +13206,7 @@ function sourceFailureResult(cause, path22) {
13117
13206
  {
13118
13207
  code: "invalid-workflow-source",
13119
13208
  message: cause instanceof Error ? cause.message : String(cause),
13120
- path: path22,
13209
+ path: path23,
13121
13210
  line: 1
13122
13211
  }
13123
13212
  ]
@@ -13768,7 +13857,7 @@ var init_triggers = __esm(() => {
13768
13857
  });
13769
13858
 
13770
13859
  // src/workflows/source-ir/compile.ts
13771
- import path22 from "node:path";
13860
+ import path23 from "node:path";
13772
13861
  function compileGithubWorkflowSource(source, options) {
13773
13862
  try {
13774
13863
  return {
@@ -13852,7 +13941,7 @@ function compileMarkdownWorkflowSource(source, options) {
13852
13941
  }
13853
13942
  }
13854
13943
  function compileWorkflowSource(source, options) {
13855
- const extension = path22.extname(options.path).toLowerCase();
13944
+ const extension = path23.extname(options.path).toLowerCase();
13856
13945
  if (extension === ".md")
13857
13946
  return compileMarkdownWorkflowSource(source, options);
13858
13947
  if (extension === ".yml")
@@ -13930,7 +14019,7 @@ function markdownName(source, filePath) {
13930
14019
  const title = body.match(/^#\s+(.+?)\s*$/m)?.[1]?.trim();
13931
14020
  if (title)
13932
14021
  return title;
13933
- return path22.basename(filePath, path22.extname(filePath));
14022
+ return path23.basename(filePath, path23.extname(filePath));
13934
14023
  }
13935
14024
  function wholeSourceSpan2(source, filePath) {
13936
14025
  return { path: filePath, start: 1, end: Math.max(1, source.split(/\r?\n/).length) };
@@ -68660,13 +68749,13 @@ function flattenForText(value, path, lines) {
68660
68749
  }
68661
68750
 
68662
68751
  // src/output/html-render.ts
68663
- import path4 from "node:path";
68752
+ import path6 from "node:path";
68664
68753
  // src/runtime.ts
68665
68754
  import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "node:child_process";
68666
68755
  init_common();
68667
68756
  import { createWriteStream, statfsSync } from "node:fs";
68668
68757
  import { createRequire as createRequire2 } from "node:module";
68669
- import path3 from "node:path";
68758
+ import path5 from "node:path";
68670
68759
  import { Readable } from "node:stream";
68671
68760
  import { pipeline } from "node:stream/promises";
68672
68761
  import { fileURLToPath } from "node:url";
@@ -68752,11 +68841,11 @@ async function writeResponseToFileCapped(filePath, res, options) {
68752
68841
  }
68753
68842
  }
68754
68843
  function getDirname(importMetaUrl) {
68755
- return path3.dirname(fileURLToPath(importMetaUrl));
68844
+ return path5.dirname(fileURLToPath(importMetaUrl));
68756
68845
  }
68757
- function statfsType(path4) {
68846
+ function statfsType(path6) {
68758
68847
  try {
68759
- return statfsSync(path4).type;
68848
+ return statfsSync(path6).type;
68760
68849
  } catch {
68761
68850
  return;
68762
68851
  }
@@ -68783,7 +68872,7 @@ function toBuffer(data) {
68783
68872
  }
68784
68873
 
68785
68874
  // src/output/html-render.ts
68786
- var TEMPLATES_DIR = path4.join(getDirname(import.meta.url), "../assets/templates/html");
68875
+ var TEMPLATES_DIR = path6.join(getDirname(import.meta.url), "../assets/templates/html");
68787
68876
 
68788
68877
  // src/output/command-registry.ts
68789
68878
  function createCommandRegistry() {
@@ -69368,6 +69457,7 @@ var PASSTHROUGH_COMMANDS = [
69368
69457
  "task-run",
69369
69458
  "task-sync",
69370
69459
  "task-sync-dry-run",
69460
+ "task-validate",
69371
69461
  "update",
69372
69462
  "upgrade",
69373
69463
  "workflow-abandon",
@@ -69953,16 +70043,16 @@ function formatConfigPlain(r) {
69953
70043
  const lines = [];
69954
70044
  const walk = (obj, prefix) => {
69955
70045
  for (const [k, v] of Object.entries(obj)) {
69956
- const path5 = prefix ? `${prefix}.${k}` : k;
70046
+ const path7 = prefix ? `${prefix}.${k}` : k;
69957
70047
  if (v === null || v === undefined) {
69958
- lines.push(`${path5}=`);
70048
+ lines.push(`${path7}=`);
69959
70049
  } else if (Array.isArray(v)) {
69960
- lines.push(`${path5}=${JSON.stringify(v)}`);
70050
+ lines.push(`${path7}=${JSON.stringify(v)}`);
69961
70051
  } else if (typeof v === "object") {
69962
- walk(v, path5);
70052
+ walk(v, path7);
69963
70053
  } else {
69964
- const rendered = typeof v === "string" && /^registries\.\d+\.url$/u.test(path5) ? formatRegistryUrl(v) : String(v);
69965
- lines.push(`${path5}=${rendered}`);
70054
+ const rendered = typeof v === "string" && /^registries\.\d+\.url$/u.test(path7) ? formatRegistryUrl(v) : String(v);
70055
+ lines.push(`${path7}=${rendered}`);
69966
70056
  }
69967
70057
  }
69968
70058
  };
@@ -71508,27 +71598,7 @@ var GLOBAL_OUTPUT_ARGS2 = {
71508
71598
  init_errors();
71509
71599
 
71510
71600
  // scripts/akm-migrate/help.txt
71511
- var help_default = `Usage: akm-migrate <command> [options]
71512
-
71513
- The one migration tool for an akm installation. Every historical shape akm
71514
- has ever written lives here; the CLI proper reads only current schemas.
71515
- \`status\` and \`apply\` run every step, in order, and print one combined JSON
71516
- plan (exit 1 when any step is blocked):
71517
-
71518
- 1. legacy config \`extraParams\` keys lifted onto first-class engine fields
71519
- 2. pending state.db migrations, historical-destructive ones included,
71520
- with a verified sibling safety copy (the only path that admits them)
71521
- 3. task-v2 files to task v3, then task-v3 files to task source v4
71522
- 4. superseded pre-0.9.0 \`.akm\` residue and stale filesystem transactions
71523
-
71524
- \`akm migrate status|apply\` wraps this executable; \`akm upgrade\` runs
71525
- \`apply\` after its install step, so an image that ships akm can put either
71526
- in its entrypoint (a current installation is a no-op).
71527
-
71528
- Commands:
71529
- status Inspect every pending migration without changing anything.
71530
- apply [--dry-run] Back up and apply every pending migration.
71531
- `;
71601
+ var help_default = "Usage: akm-migrate <command> [options]\n\nThe one migration tool for an akm installation. Every historical shape akm\nhas ever written lives here; the CLI proper reads only current schemas.\n`status` and `apply` run every step, in order, and print one combined JSON\nplan (exit 1 when any step is blocked):\n\n 1. legacy config `extraParams` keys lifted onto first-class engine fields\n 2. pending state.db migrations, historical-destructive ones included,\n with a verified sibling safety copy (the only path that admits them)\n 3. task-v2 files to task v3, then task-v3 files to task source v4\n 4. superseded pre-0.9.0 `.akm` residue and stale filesystem transactions\n 5. live `.akm` writers relocated to `$STATE`/`$CACHE`, for every local\n bundle (distill-rejected, eval-cases, measurement verdicts, and stale\n improve-pipeline locks — a lock a live run still holds is left alone)\n\n`akm migrate status|apply` wraps this executable; `akm upgrade` runs\n`apply` after its install step, so an image that ships akm can put either\nin its entrypoint (a current installation is a no-op).\n\nCommands:\n status Inspect every pending migration without changing anything.\n apply [--dry-run] Back up and apply every pending migration.\n";
71532
71602
 
71533
71603
  // scripts/akm-migrate/run-migrate.ts
71534
71604
  init_common();
@@ -71540,14 +71610,14 @@ init_extra_params();
71540
71610
 
71541
71611
  // src/core/config/config-io.ts
71542
71612
  import fs4 from "node:fs";
71543
- import path8 from "node:path";
71613
+ import path9 from "node:path";
71544
71614
  init_common();
71545
71615
  init_errors();
71546
71616
 
71547
71617
  // src/core/file-lock.ts
71548
71618
  import { randomUUID } from "node:crypto";
71549
71619
  import fs3 from "node:fs";
71550
- import path7 from "node:path";
71620
+ import path8 from "node:path";
71551
71621
 
71552
71622
  // src/storage/database.ts
71553
71623
  import { createRequire as createRequire3 } from "node:module";
@@ -71571,12 +71641,12 @@ function selectProvider() {
71571
71641
  }
71572
71642
  return provider;
71573
71643
  }
71574
- function openDatabase(path7, opts) {
71575
- return selectProvider().open(path7, opts);
71644
+ function openDatabase(path8, opts) {
71645
+ return selectProvider().open(path8, opts);
71576
71646
  }
71577
- function openBunDatabase(path7, opts) {
71647
+ function openBunDatabase(path8, opts) {
71578
71648
  const { Database: BunDatabase } = loadBunSqlite();
71579
- const db = opts ? new BunDatabase(path7, bunOptions(opts)) : new BunDatabase(path7);
71649
+ const db = opts ? new BunDatabase(path8, bunOptions(opts)) : new BunDatabase(path8);
71580
71650
  return db;
71581
71651
  }
71582
71652
  function bunOptions(opts) {
@@ -71632,7 +71702,7 @@ function loadBetterSqlite3() {
71632
71702
  }
71633
71703
  return betterSqlite3Ctor;
71634
71704
  }
71635
- function openNodeDatabase(path7, opts) {
71705
+ function openNodeDatabase(path8, opts) {
71636
71706
  const BetterSqlite3 = loadBetterSqlite3();
71637
71707
  const options = {};
71638
71708
  if (opts?.readonly !== undefined)
@@ -71641,7 +71711,7 @@ function openNodeDatabase(path7, opts) {
71641
71711
  options.fileMustExist = true;
71642
71712
  let db;
71643
71713
  try {
71644
- db = opts ? new BetterSqlite3(path7, options) : new BetterSqlite3(path7);
71714
+ db = opts ? new BetterSqlite3(path8, options) : new BetterSqlite3(path8);
71645
71715
  } catch (err) {
71646
71716
  const raw = err instanceof Error ? err.message : String(err);
71647
71717
  const remedy = abiMismatchRemedy(raw);
@@ -71689,7 +71759,7 @@ function sameIdentity(left, right) {
71689
71759
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
71690
71760
  }
71691
71761
  function operationMutexPath(lockPath) {
71692
- return path7.join(path7.dirname(lockPath), `.${path7.basename(lockPath)}.operations.sensitive`);
71762
+ return path8.join(path8.dirname(lockPath), `.${path8.basename(lockPath)}.operations.sensitive`);
71693
71763
  }
71694
71764
  function withLockOperationMutex(lockPath, run) {
71695
71765
  const db = openDatabase(operationMutexPath(lockPath));
@@ -71908,14 +71978,14 @@ var MAX_CONFIG_BACKUPS = 5;
71908
71978
  function backupExistingConfig(configPath, now = new Date) {
71909
71979
  if (!fs4.existsSync(configPath))
71910
71980
  return;
71911
- const backupDir = path8.join(getCacheDir(), "config-backups");
71981
+ const backupDir = path9.join(getCacheDir(), "config-backups");
71912
71982
  fs4.mkdirSync(backupDir, { recursive: true, mode: 448 });
71913
71983
  fs4.chmodSync(backupDir, 448);
71914
71984
  const timestamp = now.toISOString().replace(/[.:]/g, "-");
71915
71985
  let sequence = 0;
71916
71986
  let timestamped;
71917
71987
  while (true) {
71918
- timestamped = path8.join(backupDir, `config-${timestamp}${sequence === 0 ? "" : `-${sequence}`}.json`);
71988
+ timestamped = path9.join(backupDir, `config-${timestamp}${sequence === 0 ? "" : `-${sequence}`}.json`);
71919
71989
  try {
71920
71990
  fs4.copyFileSync(configPath, timestamped, fs4.constants.COPYFILE_EXCL);
71921
71991
  break;
@@ -71925,7 +71995,7 @@ function backupExistingConfig(configPath, now = new Date) {
71925
71995
  sequence++;
71926
71996
  }
71927
71997
  }
71928
- const latest = path8.join(backupDir, "config.latest.json");
71998
+ const latest = path9.join(backupDir, "config.latest.json");
71929
71999
  fs4.copyFileSync(configPath, latest);
71930
72000
  fs4.chmodSync(timestamped, 384);
71931
72001
  fs4.chmodSync(latest, 384);
@@ -71946,7 +72016,7 @@ function pruneToNewest(dir, keep, select) {
71946
72016
  return;
71947
72017
  }
71948
72018
  const candidates = entries.filter(select).map((entry) => {
71949
- const full = path8.join(dir, entry.name);
72019
+ const full = path9.join(dir, entry.name);
71950
72020
  let mtime = 0;
71951
72021
  try {
71952
72022
  mtime = fs4.statSync(full).mtimeMs;
@@ -71960,7 +72030,7 @@ function pruneToNewest(dir, keep, select) {
71960
72030
  }
71961
72031
  }
71962
72032
  function getConfigLockPath() {
71963
- return path8.join(getConfigDir(), "config.json.lck");
72033
+ return path9.join(getConfigDir(), "config.json.lck");
71964
72034
  }
71965
72035
  var CONFIG_LOCK_MAX_RETRIES = 40;
71966
72036
  var CONFIG_LOCK_RETRY_DELAY_MS = 50;
@@ -71970,7 +72040,7 @@ function sleepSyncMs(ms) {
71970
72040
  function acquireConfigLock() {
71971
72041
  const lockPath = getConfigLockPath();
71972
72042
  try {
71973
- fs4.mkdirSync(path8.dirname(lockPath), { recursive: true });
72043
+ fs4.mkdirSync(path9.dirname(lockPath), { recursive: true });
71974
72044
  } catch {}
71975
72045
  for (let attempt = 0;attempt < CONFIG_LOCK_MAX_RETRIES; attempt++) {
71976
72046
  try {
@@ -72475,8 +72545,8 @@ function getErrorMap() {
72475
72545
  }
72476
72546
  // node_modules/zod/v3/helpers/parseUtil.js
72477
72547
  var makeIssue = (params) => {
72478
- const { data, path: path9, errorMaps, issueData } = params;
72479
- const fullPath = [...path9, ...issueData.path || []];
72548
+ const { data, path: path10, errorMaps, issueData } = params;
72549
+ const fullPath = [...path10, ...issueData.path || []];
72480
72550
  const fullIssue = {
72481
72551
  ...issueData,
72482
72552
  path: fullPath
@@ -72588,11 +72658,11 @@ var errorUtil;
72588
72658
 
72589
72659
  // node_modules/zod/v3/types.js
72590
72660
  class ParseInputLazyPath {
72591
- constructor(parent, value, path9, key) {
72661
+ constructor(parent, value, path10, key) {
72592
72662
  this._cachedPath = [];
72593
72663
  this.parent = parent;
72594
72664
  this.data = value;
72595
- this._path = path9;
72665
+ this._path = path10;
72596
72666
  this._key = key;
72597
72667
  }
72598
72668
  get path() {
@@ -76100,6 +76170,7 @@ var LlmEngineSchema = exports_external.object({
76100
76170
  endpoint: chatCompletionsEndpoint,
76101
76171
  model: nonEmptyString,
76102
76172
  apiKey: exports_external.string().regex(ENV_REFERENCE_PATTERN, `apiKey must be $VAR or \${VAR}`).optional(),
76173
+ apiKeyFile: nonEmptyString.optional(),
76103
76174
  temperature: exports_external.number().finite().optional(),
76104
76175
  maxTokens: positiveInt.optional(),
76105
76176
  timeoutMs: timeoutMsField,
@@ -76113,6 +76184,13 @@ var LlmEngineSchema = exports_external.object({
76113
76184
  if (key in value)
76114
76185
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
76115
76186
  }
76187
+ if (value.apiKey !== undefined && value.apiKeyFile !== undefined) {
76188
+ ctx.addIssue({
76189
+ code: exports_external.ZodIssueCode.custom,
76190
+ path: ["apiKeyFile"],
76191
+ message: "apiKey and apiKeyFile cannot both be set"
76192
+ });
76193
+ }
76116
76194
  });
76117
76195
  var AgentEngineSchema = exports_external.object({
76118
76196
  kind: exports_external.literal("agent"),
@@ -76130,6 +76208,7 @@ var AgentEngineSchema = exports_external.object({
76130
76208
  "provider",
76131
76209
  "endpoint",
76132
76210
  "apiKey",
76211
+ "apiKeyFile",
76133
76212
  "temperature",
76134
76213
  "maxTokens",
76135
76214
  "concurrency",
@@ -76867,7 +76946,7 @@ var AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
76867
76946
  // src/core/config/config-sources.ts
76868
76947
  init_errors();
76869
76948
  import { createHash } from "node:crypto";
76870
- import path9 from "node:path";
76949
+ import path10 from "node:path";
76871
76950
  function bundleComponentConfig(bundle) {
76872
76951
  if (!bundle?.components)
76873
76952
  return;
@@ -76878,7 +76957,20 @@ function bundleComponentConfig(bundle) {
76878
76957
  return components[0];
76879
76958
  }
76880
76959
  function bundleContentRoot(entryPath, componentRoot) {
76881
- return path9.resolve(entryPath, componentRoot ?? ".");
76960
+ return path10.resolve(entryPath, componentRoot ?? ".");
76961
+ }
76962
+ function bundleContentRoots(config) {
76963
+ const bundles = config.bundles ?? {};
76964
+ const out = [];
76965
+ for (const [id, entry] of Object.entries(bundles)) {
76966
+ if (typeof entry.path !== "string" || entry.path.length === 0)
76967
+ continue;
76968
+ out.push({ id, contentRoot: bundleContentRoot(entry.path, bundleComponentConfig(entry)?.root) });
76969
+ }
76970
+ return out;
76971
+ }
76972
+ function bundleKeyForContentRoot(config, resolvedContentRoot) {
76973
+ return bundleContentRoots(config).find((entry) => entry.contentRoot === resolvedContentRoot)?.id;
76882
76974
  }
76883
76975
  function bundlesToSourceEntries(config) {
76884
76976
  const bundles = config.bundles;
@@ -77191,7 +77283,7 @@ init_paths();
77191
77283
  // src/core/state-db.ts
77192
77284
  import { randomUUID as randomUUID3 } from "node:crypto";
77193
77285
  import fs9 from "node:fs";
77194
- import path12 from "node:path";
77286
+ import path13 from "node:path";
77195
77287
 
77196
77288
  // src/storage/engines/sqlite-migrations.ts
77197
77289
  function assertMigrationRegistry(migrations) {
@@ -77360,7 +77452,7 @@ function withImmediateWriteLock(db, fn) {
77360
77452
 
77361
77453
  // src/storage/managed-db.ts
77362
77454
  import fs7 from "node:fs";
77363
- import path10 from "node:path";
77455
+ import path11 from "node:path";
77364
77456
 
77365
77457
  // src/storage/sqlite-pragmas.ts
77366
77458
  init_warn();
@@ -77434,7 +77526,7 @@ function warnNetworkFallbackOnce(dataDir) {
77434
77526
 
77435
77527
  // src/storage/managed-db.ts
77436
77528
  function openManagedDatabase(spec) {
77437
- const dir = path10.dirname(spec.path);
77529
+ const dir = path11.dirname(spec.path);
77438
77530
  if (spec.create !== false && !fs7.existsSync(dir)) {
77439
77531
  fs7.mkdirSync(dir, { recursive: true });
77440
77532
  }
@@ -77472,13 +77564,13 @@ function withManagedDb(open, fn, opts) {
77472
77564
  import { AsyncLocalStorage } from "node:async_hooks";
77473
77565
  import { randomUUID as randomUUID2 } from "node:crypto";
77474
77566
  import fs8 from "node:fs";
77475
- import path11 from "node:path";
77567
+ import path12 from "node:path";
77476
77568
  init_errors();
77477
77569
  init_paths();
77478
77570
  var heldBarrierContext = new AsyncLocalStorage;
77479
77571
  function tryAcquireMaintenanceBarrier() {
77480
77572
  const lockPath = getMaintenanceBarrierPath();
77481
- fs8.mkdirSync(path11.dirname(lockPath), { recursive: true });
77573
+ fs8.mkdirSync(path12.dirname(lockPath), { recursive: true });
77482
77574
  for (let attempt = 0;attempt < 2; attempt += 1) {
77483
77575
  const ownership = tryAcquireLockSync(lockPath, createLockPayload({ purpose: "maintenance-start" }));
77484
77576
  if (ownership) {
@@ -77529,9 +77621,9 @@ function withMaintenanceStartBarrierSyncWait(run) {
77529
77621
  }
77530
77622
  function acquireMaintenanceActivitySync(name) {
77531
77623
  return withMaintenanceStartBarrierSyncWait(() => {
77532
- const directory = path11.join(path11.dirname(getMaintenanceBarrierPath()), "maintenance-activities");
77624
+ const directory = path12.join(path12.dirname(getMaintenanceBarrierPath()), "maintenance-activities");
77533
77625
  fs8.mkdirSync(directory, { recursive: true, mode: 448 });
77534
- const lockPath = path11.join(directory, `${name}-${process.pid}-${randomUUID2()}.lock`);
77626
+ const lockPath = path12.join(directory, `${name}-${process.pid}-${randomUUID2()}.lock`);
77535
77627
  const ownership = tryAcquireLockSync(lockPath, createLockPayload({ purpose: name }));
77536
77628
  if (!ownership) {
77537
77629
  throw new ConfigError(`Could not register AKM maintenance activity at ${lockPath}.`, "INVALID_CONFIG_FILE");
@@ -78297,7 +78389,7 @@ function runMigrations2(db, options) {
78297
78389
 
78298
78390
  // src/core/state-db.ts
78299
78391
  function getStateDbPath() {
78300
- return path12.join(getDataDir(), "state.db");
78392
+ return path13.join(getDataDir(), "state.db");
78301
78393
  }
78302
78394
  function safetyCopyTimestamp() {
78303
78395
  return new Date().toISOString().replaceAll(/[^0-9]/g, "");
@@ -78482,7 +78574,7 @@ function createHistoricalStateSafetyCopy(source, migrationId) {
78482
78574
  fs9.fchmodSync(reservation.fd, finalMode);
78483
78575
  fs9.fsyncSync(reservation.fd);
78484
78576
  assertOwnedFileReservation(reservation, "Reserved state.db safety copy");
78485
- fsyncDirectory(path12.dirname(reservation.path));
78577
+ fsyncDirectory(path13.dirname(reservation.path));
78486
78578
  closeFileIdentity(reservation);
78487
78579
  return reservation.path;
78488
78580
  } catch (error) {
@@ -78500,11 +78592,11 @@ function openStateDatabase(dbPath, options) {
78500
78592
  if (resolvedPath === ":memory:") {
78501
78593
  return openManagedDatabase({
78502
78594
  path: resolvedPath,
78503
- pragmas: { dataDir: path12.dirname(resolvedPath) },
78595
+ pragmas: { dataDir: path13.dirname(resolvedPath) },
78504
78596
  init: (db) => runMigrations2(db, { freshDatabase: true })
78505
78597
  });
78506
78598
  }
78507
- const isCanonical = path12.resolve(resolvedPath) === path12.resolve(canonicalPath);
78599
+ const isCanonical = path13.resolve(resolvedPath) === path13.resolve(canonicalPath);
78508
78600
  const releaseActivity = isCanonical ? acquireMaintenanceActivitySync("state-db") : undefined;
78509
78601
  let freshReservation;
78510
78602
  let existingSource;
@@ -78512,7 +78604,7 @@ function openStateDatabase(dbPath, options) {
78512
78604
  let existingUnversionedDatabase = false;
78513
78605
  let stateSafetyCopyCreated = false;
78514
78606
  try {
78515
- fs9.mkdirSync(path12.dirname(resolvedPath), { recursive: true });
78607
+ fs9.mkdirSync(path13.dirname(resolvedPath), { recursive: true });
78516
78608
  freshReservation = reserveFreshStateDatabase(resolvedPath);
78517
78609
  if (!freshReservation) {
78518
78610
  existingSource = openExistingStateDatabaseSource(resolvedPath);
@@ -78533,7 +78625,7 @@ function openStateDatabase(dbPath, options) {
78533
78625
  const boundSource = existingSource;
78534
78626
  openedDb = openManagedDatabase({
78535
78627
  path: boundSource ? sqliteBoundFilePath(boundSource) : resolvedPath,
78536
- pragmas: { dataDir: path12.dirname(resolvedPath) },
78628
+ pragmas: { dataDir: path13.dirname(resolvedPath) },
78537
78629
  init: (db2) => {
78538
78630
  runMigrations2(db2, {
78539
78631
  freshDatabase: !!freshReservation,
@@ -78734,7 +78826,7 @@ function applyConfigExtraParamsLift(configPath) {
78734
78826
 
78735
78827
  // scripts/akm-migrate/migrate/dead-residue.ts
78736
78828
  import fs10 from "node:fs";
78737
- import path13 from "node:path";
78829
+ import path14 from "node:path";
78738
78830
  var DEAD_RESIDUE_PATHS = [
78739
78831
  { name: "proposals", reason: "superseded by the `proposals` table in $DATA/state.db (0.9.0)" },
78740
78832
  { prefix: "runs.archived-", reason: "orphaned archive of a directory that no longer exists" },
@@ -78756,7 +78848,7 @@ function dirSizeBytes(target) {
78756
78848
  return 0;
78757
78849
  }
78758
78850
  for (const entry of entries) {
78759
- const entryPath = path13.join(target, entry.name);
78851
+ const entryPath = path14.join(target, entry.name);
78760
78852
  if (entry.isDirectory()) {
78761
78853
  total += dirSizeBytes(entryPath);
78762
78854
  } else if (entry.isFile()) {
@@ -78772,7 +78864,7 @@ function sizeOf(target) {
78772
78864
  return st.isDirectory() ? dirSizeBytes(target) : st.size;
78773
78865
  }
78774
78866
  function findDeadResidueEntries(stashDir) {
78775
- const akmDir = path13.join(stashDir, ".akm");
78867
+ const akmDir = path14.join(stashDir, ".akm");
78776
78868
  let names;
78777
78869
  try {
78778
78870
  names = fs10.readdirSync(akmDir);
@@ -78785,14 +78877,14 @@ function findDeadResidueEntries(stashDir) {
78785
78877
  for (const name of matches) {
78786
78878
  if (!names.includes(name))
78787
78879
  continue;
78788
- const absolutePath = path13.join(akmDir, name);
78880
+ const absolutePath = path14.join(akmDir, name);
78789
78881
  let sizeBytes;
78790
78882
  try {
78791
78883
  sizeBytes = sizeOf(absolutePath);
78792
78884
  } catch {
78793
78885
  continue;
78794
78886
  }
78795
- found.push({ relativePath: path13.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
78887
+ found.push({ relativePath: path14.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
78796
78888
  }
78797
78889
  }
78798
78890
  return found;
@@ -78819,7 +78911,7 @@ init_paths();
78819
78911
  init_warn();
78820
78912
  import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
78821
78913
  import fs11 from "node:fs";
78822
- import path14 from "node:path";
78914
+ import path15 from "node:path";
78823
78915
  var kinds = new Map;
78824
78916
  function registerTxnKind(kind, handler3) {
78825
78917
  kinds.set(kind, handler3);
@@ -78863,18 +78955,18 @@ function writeTxnFileDurably(filePath, content, mode = 384) {
78863
78955
  fs11.writeFileSync(tempPath, content, { mode });
78864
78956
  fsyncTxnFile(tempPath);
78865
78957
  fs11.renameSync(tempPath, filePath);
78866
- fsyncTxnDir(path14.dirname(filePath));
78958
+ fsyncTxnDir(path15.dirname(filePath));
78867
78959
  }
78868
78960
  function canonicalTxnRoot(root) {
78869
78961
  try {
78870
- return fs11.realpathSync(path14.resolve(root));
78962
+ return fs11.realpathSync(path15.resolve(root));
78871
78963
  } catch {
78872
- return path14.resolve(root);
78964
+ return path15.resolve(root);
78873
78965
  }
78874
78966
  }
78875
78967
  function txnNamespaceDir(root) {
78876
78968
  const ns = txnHash(canonicalTxnRoot(root)).slice(0, 24);
78877
- return path14.join(getDataDir(), "txn", ns);
78969
+ return path15.join(getDataDir(), "txn", ns);
78878
78970
  }
78879
78971
  function advanceTxn(txn, phase) {
78880
78972
  const handler3 = requireKind(txn.journal.kind);
@@ -78890,7 +78982,7 @@ function cleanupTxn(dir) {
78890
78982
  try {
78891
78983
  fs11.rmSync(dir, { recursive: true, force: true });
78892
78984
  try {
78893
- fs11.rmdirSync(path14.dirname(dir));
78985
+ fs11.rmdirSync(path15.dirname(dir));
78894
78986
  } catch {}
78895
78987
  return null;
78896
78988
  } catch (error) {
@@ -78912,8 +79004,8 @@ function sweepJournallessTxnDir(dir, graceMs = TXN_SWEEP_GRACE_MS) {
78912
79004
  }
78913
79005
  }
78914
79006
  function isWithinTxnRoot(candidate, root) {
78915
- const rel = path14.relative(path14.resolve(root), path14.resolve(candidate));
78916
- return rel !== "" && !rel.startsWith("..") && !path14.isAbsolute(rel);
79007
+ const rel = path15.relative(path15.resolve(root), path15.resolve(candidate));
79008
+ return rel !== "" && !rel.startsWith("..") && !path15.isAbsolute(rel);
78917
79009
  }
78918
79010
  function readJournal(journalPath) {
78919
79011
  let journal;
@@ -78954,8 +79046,8 @@ async function recoverTxnsForRoot(root, filter) {
78954
79046
  for (const entry of fs11.readdirSync(nsDir, { withFileTypes: true })) {
78955
79047
  if (!entry.isDirectory())
78956
79048
  continue;
78957
- const dir = path14.join(nsDir, entry.name);
78958
- const journalPath = path14.join(dir, "journal.json");
79049
+ const dir = path15.join(nsDir, entry.name);
79050
+ const journalPath = path15.join(dir, "journal.json");
78959
79051
  if (!fs11.existsSync(journalPath)) {
78960
79052
  sweepJournallessTxnDir(dir);
78961
79053
  continue;
@@ -78984,7 +79076,7 @@ async function recoverTxnsForRoot(root, filter) {
78984
79076
  return recovered;
78985
79077
  }
78986
79078
  function listTxnJournalsTolerant(predicate) {
78987
- const home = path14.join(getDataDir(), "txn");
79079
+ const home = path15.join(getDataDir(), "txn");
78988
79080
  const matches = [];
78989
79081
  const unreadableMtimes = [];
78990
79082
  if (!fs11.existsSync(home))
@@ -78992,11 +79084,11 @@ function listTxnJournalsTolerant(predicate) {
78992
79084
  for (const ns of fs11.readdirSync(home, { withFileTypes: true })) {
78993
79085
  if (!ns.isDirectory())
78994
79086
  continue;
78995
- const nsDir = path14.join(home, ns.name);
79087
+ const nsDir = path15.join(home, ns.name);
78996
79088
  for (const entry of fs11.readdirSync(nsDir, { withFileTypes: true })) {
78997
79089
  if (!entry.isDirectory())
78998
79090
  continue;
78999
- const journalPath = path14.join(nsDir, entry.name, "journal.json");
79091
+ const journalPath = path15.join(nsDir, entry.name, "journal.json");
79000
79092
  let mtimeMs;
79001
79093
  try {
79002
79094
  mtimeMs = fs11.statSync(journalPath).mtimeMs;
@@ -79025,7 +79117,7 @@ import path60 from "node:path";
79025
79117
  init_frontmatter();
79026
79118
  init_common();
79027
79119
  import fs12 from "node:fs";
79028
- import path16 from "node:path";
79120
+ import path17 from "node:path";
79029
79121
 
79030
79122
  // src/core/adapter/adapters/shared.ts
79031
79123
  init_frontmatter();
@@ -79334,10 +79426,10 @@ var agentSkillsAdapter = {
79334
79426
  recognize,
79335
79427
  validate,
79336
79428
  readCandidates(c, conceptId) {
79337
- return [{ path: path16.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
79429
+ return [{ path: path17.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
79338
79430
  },
79339
79431
  placeNew(c, conceptId) {
79340
- return path16.join(c.root, conceptId, SKILL_MANIFEST);
79432
+ return path17.join(c.root, conceptId, SKILL_MANIFEST);
79341
79433
  },
79342
79434
  looksLikeRoot(root) {
79343
79435
  let entries;
@@ -79350,7 +79442,7 @@ var agentSkillsAdapter = {
79350
79442
  if (!entry.isDirectory())
79351
79443
  return false;
79352
79444
  try {
79353
- return fs12.existsSync(path16.join(root, entry.name, SKILL_MANIFEST));
79445
+ return fs12.existsSync(path17.join(root, entry.name, SKILL_MANIFEST));
79354
79446
  } catch {
79355
79447
  return false;
79356
79448
  }
@@ -79363,66 +79455,66 @@ init_metadata();
79363
79455
  init_asset_placement();
79364
79456
  init_frontmatter();
79365
79457
  import fs16 from "node:fs";
79366
- import path24 from "node:path";
79458
+ import path25 from "node:path";
79367
79459
 
79368
79460
  // src/core/adapter/execution-source.ts
79369
79461
  init_dist();
79370
79462
  import { createHash as createHash4 } from "node:crypto";
79371
79463
 
79372
79464
  // src/execution/json.ts
79373
- function fail(path18, detail) {
79374
- throw new TypeError(`${path18} ${detail}`);
79465
+ function fail(path19, detail) {
79466
+ throw new TypeError(`${path19} ${detail}`);
79375
79467
  }
79376
- function cloneExecutionJson(value, path18 = "execution value", ancestors = new Set) {
79468
+ function cloneExecutionJson(value, path19 = "execution value", ancestors = new Set) {
79377
79469
  if (value === null || typeof value === "string" || typeof value === "boolean")
79378
79470
  return value;
79379
79471
  if (typeof value === "number") {
79380
79472
  if (!Number.isFinite(value))
79381
- fail(path18, "must contain only finite numbers");
79473
+ fail(path19, "must contain only finite numbers");
79382
79474
  return value;
79383
79475
  }
79384
79476
  if (value === undefined)
79385
- fail(path18, "must be omitted rather than set to undefined");
79477
+ fail(path19, "must be omitted rather than set to undefined");
79386
79478
  if (typeof value !== "object")
79387
- fail(path18, "must be JSON-safe");
79479
+ fail(path19, "must be JSON-safe");
79388
79480
  if (ancestors.has(value))
79389
- fail(path18, "must not contain a cycle");
79481
+ fail(path19, "must not contain a cycle");
79390
79482
  const nextAncestors = new Set(ancestors);
79391
79483
  nextAncestors.add(value);
79392
79484
  if (Array.isArray(value)) {
79393
79485
  if (Object.getPrototypeOf(value) !== Array.prototype)
79394
- fail(path18, "array must use the standard Array prototype");
79486
+ fail(path19, "array must use the standard Array prototype");
79395
79487
  const ownKeys = Reflect.ownKeys(value);
79396
79488
  const lengthDescriptor = Reflect.getOwnPropertyDescriptor(value, "length");
79397
79489
  if (!lengthDescriptor || !("value" in lengthDescriptor) || typeof lengthDescriptor.value !== "number" || !Number.isInteger(lengthDescriptor.value) || lengthDescriptor.value < 0) {
79398
- fail(path18, "array length must be a stable nonnegative integer data property");
79490
+ fail(path19, "array length must be a stable nonnegative integer data property");
79399
79491
  }
79400
79492
  const length = lengthDescriptor.value;
79401
79493
  if (ownKeys.length !== length + 1) {
79402
- fail(path18, "array must be dense and contain no non-index properties");
79494
+ fail(path19, "array must be dense and contain no non-index properties");
79403
79495
  }
79404
79496
  for (const key of ownKeys) {
79405
79497
  if (key === "length")
79406
79498
  continue;
79407
79499
  if (typeof key !== "string" || !/^(?:0|[1-9]\d*)$/.test(key) || Number(key) >= length) {
79408
- fail(path18, "array must contain only canonical index properties");
79500
+ fail(path19, "array must contain only canonical index properties");
79409
79501
  }
79410
79502
  }
79411
79503
  const cloned2 = [];
79412
79504
  for (let index = 0;index < length; index++) {
79413
79505
  const descriptor = Reflect.getOwnPropertyDescriptor(value, String(index));
79414
79506
  if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
79415
- fail(path18, "array must be dense enumerable data properties");
79507
+ fail(path19, "array must be dense enumerable data properties");
79416
79508
  }
79417
- cloned2.push(cloneExecutionJson(descriptor.value, `${path18}[${index}]`, nextAncestors));
79509
+ cloned2.push(cloneExecutionJson(descriptor.value, `${path19}[${index}]`, nextAncestors));
79418
79510
  }
79419
79511
  return Object.freeze(cloned2);
79420
79512
  }
79421
- const snapshot = snapshotStrictRecord(value, path18);
79513
+ const snapshot = snapshotStrictRecord(value, path19);
79422
79514
  const cloned = Object.create(null);
79423
79515
  for (const [key, child] of Object.entries(snapshot)) {
79424
79516
  Object.defineProperty(cloned, key, {
79425
- value: cloneExecutionJson(child, `${path18}.${key}`, nextAncestors),
79517
+ value: cloneExecutionJson(child, `${path19}.${key}`, nextAncestors),
79426
79518
  enumerable: true,
79427
79519
  configurable: false,
79428
79520
  writable: false
@@ -79430,10 +79522,10 @@ function cloneExecutionJson(value, path18 = "execution value", ancestors = new S
79430
79522
  }
79431
79523
  return Object.freeze(cloned);
79432
79524
  }
79433
- function cloneExecutionJsonObject(value, path18) {
79434
- const cloned = cloneExecutionJson(value, path18);
79525
+ function cloneExecutionJsonObject(value, path19) {
79526
+ const cloned = cloneExecutionJson(value, path19);
79435
79527
  if (cloned === null || Array.isArray(cloned) || typeof cloned !== "object") {
79436
- fail(path18, "must be a JSON object");
79528
+ fail(path19, "must be a JSON object");
79437
79529
  }
79438
79530
  return cloned;
79439
79531
  }
@@ -79447,11 +79539,11 @@ var WINDOWS_DRIVE_PREFIX_PATTERN = /^[A-Za-z]:/;
79447
79539
  var RESERVED_EXTENSION_OWNERS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
79448
79540
  var renderedSourceBrand = Symbol("akm.adapter-rendered-execution-source");
79449
79541
  var renderedSourceInstances = new WeakSet;
79450
- function requireRecord(value, path18) {
79451
- return snapshotStrictRecord(value, path18);
79542
+ function requireRecord(value, path19) {
79543
+ return snapshotStrictRecord(value, path19);
79452
79544
  }
79453
- function assertOnlyKeys(value, allowed, path18) {
79454
- assertSnapshotKeys(value, allowed, path18);
79545
+ function assertOnlyKeys(value, allowed, path19) {
79546
+ assertSnapshotKeys(value, allowed, path19);
79455
79547
  }
79456
79548
  function validateExtensionOwner(owner) {
79457
79549
  const normalized = owner.toLowerCase();
@@ -79467,16 +79559,16 @@ function frozenNullPrototypeMap(entries) {
79467
79559
  return Object.freeze(out);
79468
79560
  }
79469
79561
  function cloneExtensionEntry(value, index) {
79470
- const path18 = `extension entry ${index}`;
79471
- const cloned = cloneExecutionJson(value, path18);
79562
+ const path19 = `extension entry ${index}`;
79563
+ const cloned = cloneExecutionJson(value, path19);
79472
79564
  if (!Array.isArray(cloned) || cloned.length !== 2) {
79473
- throw new TypeError(`${path18} must be a two-element [owner, values] array`);
79565
+ throw new TypeError(`${path19} must be a two-element [owner, values] array`);
79474
79566
  }
79475
79567
  const [owner, values] = cloned;
79476
79568
  if (typeof owner !== "string")
79477
- throw new TypeError(`${path18} owner must be a string`);
79569
+ throw new TypeError(`${path19} owner must be a string`);
79478
79570
  if (values === null || Array.isArray(values) || typeof values !== "object") {
79479
- throw new TypeError(`${path18} values must be a JSON object`);
79571
+ throw new TypeError(`${path19} values must be a JSON object`);
79480
79572
  }
79481
79573
  return [owner, values];
79482
79574
  }
@@ -79494,18 +79586,18 @@ function createAdapterExtensions(first, second, ...rest) {
79494
79586
  }
79495
79587
  return frozenNullPrototypeMap(cloned);
79496
79588
  }
79497
- function cloneAdapterExtensions(value, path18) {
79498
- const record = requireRecord(value, path18);
79499
- const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path18}.${owner}`)]);
79589
+ function cloneAdapterExtensions(value, path19) {
79590
+ const record = requireRecord(value, path19);
79591
+ const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path19}.${owner}`)]);
79500
79592
  const [first, ...rest] = entries;
79501
79593
  return first ? createAdapterExtensions(first, ...rest) : frozenNullPrototypeMap([]);
79502
79594
  }
79503
- function requireCanonicalString(value, path18) {
79595
+ function requireCanonicalString(value, path19) {
79504
79596
  if (typeof value !== "string" || value.length === 0 || !isWellFormedUnicode(value) || value.normalize("NFC") !== value) {
79505
- throw new TypeError(`${path18} must be a non-empty NFC string`);
79597
+ throw new TypeError(`${path19} must be a non-empty NFC string`);
79506
79598
  }
79507
79599
  if (hasUnsafeIdentityCharacter(value)) {
79508
- throw new TypeError(`${path18} must not contain Unicode control or dangerous format characters`);
79600
+ throw new TypeError(`${path19} must not contain Unicode control or dangerous format characters`);
79509
79601
  }
79510
79602
  return value;
79511
79603
  }
@@ -79532,38 +79624,38 @@ function isWellFormedUnicode(value) {
79532
79624
  }
79533
79625
  return true;
79534
79626
  }
79535
- function validateCanonicalIdentity(input, path18) {
79536
- assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path18);
79537
- const ref = requireCanonicalString(input.ref, `${path18}.ref`);
79538
- const bundle = requireCanonicalString(input.bundle, `${path18}.bundle`);
79539
- const adapter = requireCanonicalString(input.adapter, `${path18}.adapter`);
79540
- const file = requireCanonicalString(input.file, `${path18}.file`);
79541
- const hash = requireCanonicalString(input.hash, `${path18}.hash`);
79627
+ function validateCanonicalIdentity(input, path19) {
79628
+ assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path19);
79629
+ const ref = requireCanonicalString(input.ref, `${path19}.ref`);
79630
+ const bundle = requireCanonicalString(input.bundle, `${path19}.bundle`);
79631
+ const adapter = requireCanonicalString(input.adapter, `${path19}.adapter`);
79632
+ const file = requireCanonicalString(input.file, `${path19}.file`);
79633
+ const hash = requireCanonicalString(input.hash, `${path19}.hash`);
79542
79634
  let parsed;
79543
79635
  try {
79544
79636
  parsed = parseBundleRef(ref);
79545
79637
  } catch (cause) {
79546
- throw new TypeError(`${path18}.ref is not a canonical bundle ref`, { cause });
79638
+ throw new TypeError(`${path19}.ref is not a canonical bundle ref`, { cause });
79547
79639
  }
79548
79640
  if (parsed.bundle === undefined || parsed.bundle !== bundle || parsed.fragment !== undefined || !isBundleSlug(bundle) || bundleRefToString(parsed) !== ref) {
79549
- throw new TypeError(`${path18}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
79641
+ throw new TypeError(`${path19}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
79550
79642
  }
79551
79643
  if (!EXECUTION_ADAPTER_ID_PATTERN.test(adapter)) {
79552
- throw new TypeError(`${path18}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
79644
+ throw new TypeError(`${path19}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
79553
79645
  }
79554
79646
  const segments = file.split("/");
79555
79647
  if (file.startsWith("/") || WINDOWS_DRIVE_PREFIX_PATTERN.test(file) || file.includes("\\") || segments.some((segment) => !segment || segment === "." || segment === "..")) {
79556
- throw new TypeError(`${path18}.file must be a normalized relative POSIX path`);
79648
+ throw new TypeError(`${path19}.file must be a normalized relative POSIX path`);
79557
79649
  }
79558
79650
  if (!/^[a-f0-9]{64}$/.test(hash))
79559
- throw new TypeError(`${path18}.hash must be a SHA-256 hex digest`);
79651
+ throw new TypeError(`${path19}.hash must be a SHA-256 hex digest`);
79560
79652
  return { ref, bundle, adapter, file, hash };
79561
79653
  }
79562
79654
  function createExecutionSourceIdentity(input) {
79563
79655
  return Object.freeze(validateCanonicalIdentity(requireRecord(input, "execution source identity"), "execution source identity"));
79564
79656
  }
79565
- function cloneUnresolvedExecutionDefaults(input, path18 = "execution source defaults") {
79566
- const record = requireRecord(input, path18);
79657
+ function cloneUnresolvedExecutionDefaults(input, path19 = "execution source defaults") {
79658
+ const record = requireRecord(input, path19);
79567
79659
  assertOnlyKeys(record, [
79568
79660
  "agent",
79569
79661
  "engine",
@@ -79575,47 +79667,47 @@ function cloneUnresolvedExecutionDefaults(input, path18 = "execution source defa
79575
79667
  "workspace",
79576
79668
  "environment",
79577
79669
  "runtime"
79578
- ], path18);
79579
- const json = { ...cloneExecutionJsonObject(record, path18) };
79670
+ ], path19);
79671
+ const json = { ...cloneExecutionJsonObject(record, path19) };
79580
79672
  for (const key of ["agent", "engine", "model", "workspace"]) {
79581
79673
  const value = json[key];
79582
79674
  if (value !== undefined && value !== null && typeof value !== "string") {
79583
- throw new TypeError(`${path18}.${key} must be a string or null`);
79675
+ throw new TypeError(`${path19}.${key} must be a string or null`);
79584
79676
  }
79585
79677
  }
79586
79678
  const timeout = json.timeout;
79587
79679
  if (timeout !== undefined && timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
79588
- throw new TypeError(`${path18}.timeout must be a string, number, or null`);
79680
+ throw new TypeError(`${path19}.timeout must be a string, number, or null`);
79589
79681
  }
79590
79682
  for (const key of ["inference", "outputSchema", "runtime"]) {
79591
79683
  const value = json[key];
79592
79684
  if (value !== undefined && value !== null && (Array.isArray(value) || typeof value !== "object")) {
79593
- throw new TypeError(`${path18}.${key} must be an object or null`);
79685
+ throw new TypeError(`${path19}.${key} must be an object or null`);
79594
79686
  }
79595
79687
  }
79596
79688
  const environment = json.environment;
79597
79689
  if (environment !== undefined && environment !== null) {
79598
79690
  if (Array.isArray(environment) || typeof environment !== "object") {
79599
- throw new TypeError(`${path18}.environment must be an object or null`);
79691
+ throw new TypeError(`${path19}.environment must be an object or null`);
79600
79692
  }
79601
79693
  if (Object.values(environment).some((value) => typeof value !== "string")) {
79602
- throw new TypeError(`${path18}.environment values must be strings`);
79694
+ throw new TypeError(`${path19}.environment values must be strings`);
79603
79695
  }
79604
79696
  }
79605
79697
  if (Object.hasOwn(json, "tools"))
79606
- json.tools = cloneToolSelection(json.tools, `${path18}.tools`);
79698
+ json.tools = cloneToolSelection(json.tools, `${path19}.tools`);
79607
79699
  return Object.freeze(json);
79608
79700
  }
79609
- function cloneToolSelection(value, path18 = "tools") {
79701
+ function cloneToolSelection(value, path19 = "tools") {
79610
79702
  if (value === null || typeof value === "string")
79611
79703
  return value;
79612
- const cloned = cloneExecutionJson(value, path18);
79704
+ const cloned = cloneExecutionJson(value, path19);
79613
79705
  if (Array.isArray(cloned)) {
79614
79706
  if (cloned.some((tool) => typeof tool !== "string"))
79615
- throw new TypeError(`${path18} array values must be strings`);
79707
+ throw new TypeError(`${path19} array values must be strings`);
79616
79708
  return cloned;
79617
79709
  }
79618
- return cloneExecutionJsonObject(cloned, path18);
79710
+ return cloneExecutionJsonObject(cloned, path19);
79619
79711
  }
79620
79712
  function createAdapterRenderedExecutionSource(input) {
79621
79713
  const record = requireRecord(input, "adapter-rendered execution source");
@@ -79724,34 +79816,34 @@ function parseExecutionMarkdown(raw) {
79724
79816
  function own(data, key) {
79725
79817
  return Object.hasOwn(data, key);
79726
79818
  }
79727
- function requireMetadataMapping(value, path18) {
79819
+ function requireMetadataMapping(value, path19) {
79728
79820
  try {
79729
- return snapshotStrictRecord(value, path18);
79821
+ return snapshotStrictRecord(value, path19);
79730
79822
  } catch (cause) {
79731
- throw new TypeError(`${path18} must be a mapping with enumerable data fields`, { cause });
79823
+ throw new TypeError(`${path19} must be a mapping with enumerable data fields`, { cause });
79732
79824
  }
79733
79825
  }
79734
- function nullableString(value, path18) {
79826
+ function nullableString(value, path19) {
79735
79827
  if (value !== null && typeof value !== "string")
79736
- throw new TypeError(`${path18} must be a string or null`);
79828
+ throw new TypeError(`${path19} must be a string or null`);
79737
79829
  return value;
79738
79830
  }
79739
- function nullableObject(value, path18) {
79740
- return value === null ? null : cloneExecutionJsonObject(value, path18);
79831
+ function nullableObject(value, path19) {
79832
+ return value === null ? null : cloneExecutionJsonObject(value, path19);
79741
79833
  }
79742
- function nullableEnvironment(value, path18) {
79834
+ function nullableEnvironment(value, path19) {
79743
79835
  if (value === null)
79744
79836
  return null;
79745
- const environment = cloneExecutionJsonObject(value, path18);
79837
+ const environment = cloneExecutionJsonObject(value, path19);
79746
79838
  if (Object.values(environment).some((entry) => typeof entry !== "string")) {
79747
- throw new TypeError(`${path18} values must be strings`);
79839
+ throw new TypeError(`${path19} values must be strings`);
79748
79840
  }
79749
79841
  return environment;
79750
79842
  }
79751
- function nullableTimeout(value, path18) {
79752
- const timeout = cloneExecutionJson(value, path18);
79843
+ function nullableTimeout(value, path19) {
79844
+ const timeout = cloneExecutionJson(value, path19);
79753
79845
  if (timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
79754
- throw new TypeError(`${path18} must be a string, number, or null`);
79846
+ throw new TypeError(`${path19} must be a string, number, or null`);
79755
79847
  }
79756
79848
  return timeout;
79757
79849
  }
@@ -80195,7 +80287,7 @@ function recognizeMatch(file) {
80195
80287
  }
80196
80288
 
80197
80289
  // src/core/adapter/adapters/akm-lint.ts
80198
- import path23 from "node:path";
80290
+ import path24 from "node:path";
80199
80291
 
80200
80292
  // src/commands/lint/env-key-rules.ts
80201
80293
  init_env();
@@ -80318,28 +80410,28 @@ var MOVE_TO_ENV = "Workflow params are copied verbatim into every native unit ex
80318
80410
  function detectSecretShapedParams(params) {
80319
80411
  const warnings = [];
80320
80412
  const seen = new Set;
80321
- const push = (path19, why) => {
80322
- if (seen.has(path19))
80413
+ const push = (path20, why) => {
80414
+ if (seen.has(path20))
80323
80415
  return;
80324
- seen.add(path19);
80325
- warnings.push(`Run param "${path19}" ${why}. ${MOVE_TO_ENV} (Heuristic warning; params are declared non-secret.)`);
80416
+ seen.add(path20);
80417
+ warnings.push(`Run param "${path20}" ${why}. ${MOVE_TO_ENV} (Heuristic warning; params are declared non-secret.)`);
80326
80418
  };
80327
- const walk = (value, path19, key) => {
80419
+ const walk = (value, path20, key) => {
80328
80420
  if (key !== null && keyLooksSecret(key))
80329
- push(path19, "has a secret-suggesting name");
80421
+ push(path20, "has a secret-suggesting name");
80330
80422
  if (typeof value === "string") {
80331
80423
  if (valueLooksSecret(value))
80332
- push(path19, "has a secret-shaped value (long, high-entropy string)");
80424
+ push(path20, "has a secret-shaped value (long, high-entropy string)");
80333
80425
  return;
80334
80426
  }
80335
80427
  if (Array.isArray(value)) {
80336
80428
  for (let i = 0;i < value.length; i++)
80337
- walk(value[i], `${path19}[${i}]`, null);
80429
+ walk(value[i], `${path20}[${i}]`, null);
80338
80430
  return;
80339
80431
  }
80340
80432
  if (value && typeof value === "object") {
80341
80433
  for (const [k, v] of Object.entries(value)) {
80342
- walk(v, path19 ? `${path19}.${k}` : k, k);
80434
+ walk(v, path20 ? `${path20}.${k}` : k, k);
80343
80435
  }
80344
80436
  }
80345
80437
  };
@@ -80787,8 +80879,8 @@ init_dist();
80787
80879
  init_asset_ref();
80788
80880
  init_extra_params();
80789
80881
  init_resource_limits();
80790
- import crypto3 from "node:crypto";
80791
- import path19 from "node:path";
80882
+ import crypto4 from "node:crypto";
80883
+ import path20 from "node:path";
80792
80884
 
80793
80885
  // src/tasks/task-id.ts
80794
80886
  init_errors();
@@ -81230,7 +81322,7 @@ var KNOWN_PROMPT_REF_FAMILIES = new Set([
81230
81322
  "workflows"
81231
81323
  ]);
81232
81324
  function hash(bytes) {
81233
- return crypto3.createHash("sha256").update(bytes).digest("hex");
81325
+ return crypto4.createHash("sha256").update(bytes).digest("hex");
81234
81326
  }
81235
81327
  function base(input) {
81236
81328
  return {
@@ -81389,7 +81481,7 @@ function addSharedNonPromptOverrides(data, akm) {
81389
81481
  }
81390
81482
  function promptSourceKind(raw) {
81391
81483
  const trimmed = raw.trim();
81392
- if (trimmed.startsWith("./") || trimmed.startsWith("../") || path19.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
81484
+ if (trimmed.startsWith("./") || trimmed.startsWith("../") || path20.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
81393
81485
  return "file";
81394
81486
  }
81395
81487
  try {
@@ -81496,7 +81588,7 @@ function planLegacyTaskDataToV3(input, data) {
81496
81588
  return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
81497
81589
  }
81498
81590
  try {
81499
- validateTaskId(path19.basename(input.filePath, ".yml"));
81591
+ validateTaskId(path20.basename(input.filePath, ".yml"));
81500
81592
  } catch (cause) {
81501
81593
  return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
81502
81594
  }
@@ -81566,7 +81658,7 @@ function planTaskToV3File(input) {
81566
81658
  return planLegacyTaskDataToV3(input, data);
81567
81659
  }
81568
81660
  function generationFor(files) {
81569
- const digest = crypto3.createHash("sha256");
81661
+ const digest = crypto4.createHash("sha256");
81570
81662
  digest.update("akm-task-to-v3-plan-v1\x00");
81571
81663
  for (const file of files) {
81572
81664
  digest.update(file.filePath);
@@ -81600,7 +81692,7 @@ function taskToV3PlanFromOutcomes(outcomes) {
81600
81692
  for (let index = 1;index < files.length; index += 1) {
81601
81693
  const previous = files[index - 1];
81602
81694
  const current = files[index];
81603
- if (previous && current && path19.resolve(previous.filePath) === path19.resolve(current.filePath)) {
81695
+ if (previous && current && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
81604
81696
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
81605
81697
  }
81606
81698
  }
@@ -81610,7 +81702,7 @@ function planTaskToV3Migration(inputs) {
81610
81702
  const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
81611
81703
  let previous;
81612
81704
  for (const current of sorted) {
81613
- if (previous && path19.resolve(previous.filePath) === path19.resolve(current.filePath)) {
81705
+ if (previous && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
81614
81706
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
81615
81707
  }
81616
81708
  previous = current;
@@ -81621,8 +81713,8 @@ function planTaskToV3Migration(inputs) {
81621
81713
  // src/tasks/source/task-to-v4.ts
81622
81714
  init_dist();
81623
81715
  init_bounded_document();
81624
- import crypto4 from "node:crypto";
81625
- import path20 from "node:path";
81716
+ import crypto5 from "node:crypto";
81717
+ import path21 from "node:path";
81626
81718
  var V3_TOP_LEVEL_KEYS = new Set([
81627
81719
  "version",
81628
81720
  "name",
@@ -81668,7 +81760,7 @@ var AKM_HOIST_KEYS = [
81668
81760
  "maxRetries"
81669
81761
  ];
81670
81762
  function hash2(bytes) {
81671
- return crypto4.createHash("sha256").update(bytes).digest("hex");
81763
+ return crypto5.createHash("sha256").update(bytes).digest("hex");
81672
81764
  }
81673
81765
  function causeMessage(cause) {
81674
81766
  return cause instanceof Error ? cause.message : String(cause);
@@ -81937,7 +82029,7 @@ function planTaskToV4File(input) {
81937
82029
  return planV3DataToV4(input, data);
81938
82030
  }
81939
82031
  function generationFor2(files) {
81940
- const digest = crypto4.createHash("sha256");
82032
+ const digest = crypto5.createHash("sha256");
81941
82033
  digest.update("akm-task-to-v4-plan-v1\x00");
81942
82034
  for (const file of files) {
81943
82035
  digest.update(file.filePath);
@@ -81974,7 +82066,7 @@ function taskToV4PlanFromOutcomes(outcomes) {
81974
82066
  for (let index = 1;index < files.length; index += 1) {
81975
82067
  const previous = files[index - 1];
81976
82068
  const current = files[index];
81977
- if (previous && current && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
82069
+ if (previous && current && path21.resolve(previous.filePath) === path21.resolve(current.filePath)) {
81978
82070
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
81979
82071
  }
81980
82072
  }
@@ -81984,7 +82076,7 @@ function planTaskToV4Migration(inputs) {
81984
82076
  const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
81985
82077
  let previous;
81986
82078
  for (const current of sorted) {
81987
- if (previous && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
82079
+ if (previous && path21.resolve(previous.filePath) === path21.resolve(current.filePath)) {
81988
82080
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
81989
82081
  }
81990
82082
  previous = current;
@@ -82299,7 +82391,7 @@ function checkInvalidTypeValue(data, allowedTypes) {
82299
82391
  return `type field has invalid value '${value}'; expected one of: ${allowedTypes.join(", ")}`;
82300
82392
  }
82301
82393
  function suggestSlug(filePath) {
82302
- return path23.basename(filePath, ".md").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
82394
+ return path24.basename(filePath, ".md").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
82303
82395
  }
82304
82396
  function nameOrTypeDiagnostics(relPath, data, frontmatter, allowedTypes) {
82305
82397
  const missingFieldDetail = checkMissingNameOrType(data, frontmatter);
@@ -82339,7 +82431,7 @@ function collectSuppressedKeys(raw) {
82339
82431
  function dangerousEnvKeyDiagnostics(type, relPath, raw) {
82340
82432
  if (type !== "env" && type !== "secret")
82341
82433
  return [];
82342
- const baseNameWithExt = path23.basename(relPath);
82434
+ const baseNameWithExt = path24.basename(relPath);
82343
82435
  if (!baseNameWithExt.endsWith(".env"))
82344
82436
  return [];
82345
82437
  const ref = conceptIdForStashFile(type, ".", relPath);
@@ -82485,7 +82577,7 @@ function workflowFrontendDiagnostics(relPath, raw, parsePath2) {
82485
82577
  }
82486
82578
  return { errors: errors3, warnings };
82487
82579
  }
82488
- const compiled = compileWorkflowPlan(result.ir, path23.basename(parsePath2, path23.extname(parsePath2)));
82580
+ const compiled = compileWorkflowPlan(result.ir, path24.basename(parsePath2, path24.extname(parsePath2)));
82489
82581
  if (!compiled.ok) {
82490
82582
  for (const err of compiled.errors) {
82491
82583
  errors3.push({
@@ -82803,13 +82895,13 @@ function isReservedFileName(name) {
82803
82895
  }
82804
82896
  var WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
82805
82897
  function akmStashAbstains(root, absPath) {
82806
- const relPath = path24.relative(root, absPath);
82807
- if (!relPath || relPath.startsWith("..") || path24.isAbsolute(relPath))
82898
+ const relPath = path25.relative(root, absPath);
82899
+ if (!relPath || relPath.startsWith("..") || path25.isAbsolute(relPath))
82808
82900
  return false;
82809
82901
  const segments = relPath.split(/[\\/]+/).filter(Boolean);
82810
82902
  if (segments.length === 0)
82811
82903
  return false;
82812
- if (segments[0] === "env" && (absPath.endsWith(".env") || path24.basename(absPath) === ".env")) {
82904
+ if (segments[0] === "env" && (absPath.endsWith(".env") || path25.basename(absPath) === ".env")) {
82813
82905
  if (fs16.existsSync(absPath.replace(/\.env$/, ".sensitive")))
82814
82906
  return true;
82815
82907
  }
@@ -82916,7 +83008,7 @@ function recognize2(c, file) {
82916
83008
  return null;
82917
83009
  const stashDir = stashDirFor(match.type);
82918
83010
  const canonicalName = stashDir !== undefined ? conceptId.slice(stashDir.length + 1) : conceptId;
82919
- const dirPath = path24.dirname(file.absPath);
83011
+ const dirPath = path25.dirname(file.absPath);
82920
83012
  const entry = {
82921
83013
  name: canonicalName,
82922
83014
  type: match.type,
@@ -82962,13 +83054,13 @@ function renderExecutionSource(c, file) {
82962
83054
  });
82963
83055
  }
82964
83056
  function buildOverlayContext(root, relPathInput, raw) {
82965
- const absPath = path24.join(root, relPathInput);
82966
- const relPath = path24.relative(root, absPath).replace(/\\/g, "/");
82967
- const ext = path24.extname(absPath).toLowerCase();
82968
- const fileName = path24.basename(absPath);
82969
- const parentDirAbs = path24.dirname(absPath);
82970
- const parentDir = path24.basename(parentDirAbs);
82971
- const relDir = path24.dirname(relPath).replace(/\\/g, "/");
83057
+ const absPath = path25.join(root, relPathInput);
83058
+ const relPath = path25.relative(root, absPath).replace(/\\/g, "/");
83059
+ const ext = path25.extname(absPath).toLowerCase();
83060
+ const fileName = path25.basename(absPath);
83061
+ const parentDirAbs = path25.dirname(absPath);
83062
+ const parentDir = path25.basename(parentDirAbs);
83063
+ const relDir = path25.dirname(relPath).replace(/\\/g, "/");
82972
83064
  const ancestorDirs = relDir === "." ? [] : relDir.split("/").filter((seg) => seg.length > 0);
82973
83065
  let cachedFrontmatter;
82974
83066
  let frontmatterComputed = false;
@@ -83066,13 +83158,13 @@ var akmAdapter = {
83066
83158
  const posix = conceptId.replace(/\\/g, "/");
83067
83159
  const slash = posix.indexOf("/");
83068
83160
  if (slash <= 0)
83069
- return [{ path: path24.join(c.root, `${posix}.md`), conceptId: posix }];
83161
+ return [{ path: path25.join(c.root, `${posix}.md`), conceptId: posix }];
83070
83162
  const head = posix.slice(0, slash);
83071
83163
  const rest = posix.slice(slash + 1);
83072
83164
  const type = stashDirToType(head);
83073
83165
  if (type === undefined || rest.length === 0)
83074
83166
  return [];
83075
- const canonical = assetPathCandidatesForName(type, path24.join(c.root, head), rest);
83167
+ const canonical = assetPathCandidatesForName(type, path25.join(c.root, head), rest);
83076
83168
  const loose = assetPathCandidatesForName(type, c.root, rest);
83077
83169
  return [...new Set([...canonical, ...loose])].map((candidatePath) => ({
83078
83170
  path: candidatePath,
@@ -83087,18 +83179,18 @@ var akmAdapter = {
83087
83179
  const rest = posix.slice(slash + 1);
83088
83180
  const type = stashDirToType(head);
83089
83181
  if (type !== undefined && rest.length > 0) {
83090
- const typeDir = path24.join(c.root, head);
83182
+ const typeDir = path25.join(c.root, head);
83091
83183
  return assetPathForName(type, typeDir, rest);
83092
83184
  }
83093
83185
  }
83094
- return path24.join(c.root, `${posix}.md`);
83186
+ return path25.join(c.root, `${posix}.md`);
83095
83187
  },
83096
83188
  directoryList(_c) {
83097
83189
  return [...new Set(stashDirNames())];
83098
83190
  },
83099
83191
  looksLikeRoot(root) {
83100
83192
  try {
83101
- if (fs16.statSync(path24.join(root, ".stash")).isDirectory())
83193
+ if (fs16.statSync(path25.join(root, ".stash")).isDirectory())
83102
83194
  return true;
83103
83195
  } catch {}
83104
83196
  const ownedDirNames = new Set(stashDirNames());
@@ -83116,10 +83208,10 @@ var akmAdapter = {
83116
83208
  return false;
83117
83209
  const expectedType = stashDirToType(only.name);
83118
83210
  try {
83119
- const markdown = fs16.readdirSync(path24.join(root, only.name), { withFileTypes: true }).find((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md"));
83211
+ const markdown = fs16.readdirSync(path25.join(root, only.name), { withFileTypes: true }).find((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md"));
83120
83212
  if (!markdown)
83121
83213
  return true;
83122
- const data = parseFrontmatter(fs16.readFileSync(path24.join(root, only.name, markdown.name), "utf8")).data;
83214
+ const data = parseFrontmatter(fs16.readFileSync(path25.join(root, only.name, markdown.name), "utf8")).data;
83123
83215
  const declaredType = typeof data.type === "string" ? data.type.trim() : "";
83124
83216
  return !declaredType || declaredType === expectedType;
83125
83217
  } catch {
@@ -83130,7 +83222,7 @@ var akmAdapter = {
83130
83222
 
83131
83223
  // src/core/adapter/adapters/akm-task-adapter.ts
83132
83224
  import fs17 from "node:fs";
83133
- import path25 from "node:path";
83225
+ import path26 from "node:path";
83134
83226
  init_common();
83135
83227
  var COMPONENT_ID2 = "main";
83136
83228
  var TASK_EXT = TASK_EXTENSION;
@@ -83161,7 +83253,7 @@ async function validate3(c, changes, ctx) {
83161
83253
  const raw = change.after ?? await ctx.readFile(change.path);
83162
83254
  if (typeof raw !== "string")
83163
83255
  continue;
83164
- const ext = path25.extname(change.path).toLowerCase();
83256
+ const ext = path26.extname(change.path).toLowerCase();
83165
83257
  if (ext !== TASK_EXT && ext !== TASK_NEAR_MISS_EXTENSION)
83166
83258
  continue;
83167
83259
  const relPath = toPosix(change.path);
@@ -83196,13 +83288,13 @@ var akmTaskAdapter = {
83196
83288
  readCandidates(c, conceptId) {
83197
83289
  const posix = toPosix(conceptId).replace(/\.ya?ml$/i, "");
83198
83290
  return [
83199
- { path: path25.join(c.root, `${posix}.yml`), conceptId: posix },
83200
- { path: path25.join(c.root, `${posix}.yaml`), conceptId: posix }
83291
+ { path: path26.join(c.root, `${posix}.yml`), conceptId: posix },
83292
+ { path: path26.join(c.root, `${posix}.yaml`), conceptId: posix }
83201
83293
  ];
83202
83294
  },
83203
83295
  placeNew(c, conceptId) {
83204
83296
  const posix = toPosix(conceptId);
83205
- return path25.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
83297
+ return path26.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
83206
83298
  },
83207
83299
  directoryList() {
83208
83300
  return ["."];
@@ -83215,11 +83307,11 @@ var akmTaskAdapter = {
83215
83307
  return false;
83216
83308
  }
83217
83309
  for (const entry of entries) {
83218
- if (!entry.isFile() || path25.extname(entry.name).toLowerCase() !== TASK_EXT)
83310
+ if (!entry.isFile() || path26.extname(entry.name).toLowerCase() !== TASK_EXT)
83219
83311
  continue;
83220
83312
  let raw;
83221
83313
  try {
83222
- raw = fs17.readFileSync(path25.join(root, entry.name), "utf8");
83314
+ raw = fs17.readFileSync(path26.join(root, entry.name), "utf8");
83223
83315
  } catch {
83224
83316
  continue;
83225
83317
  }
@@ -83237,7 +83329,7 @@ init_compile();
83237
83329
  init_frontmatter();
83238
83330
  init_common();
83239
83331
  import fs18 from "node:fs";
83240
- import path26 from "node:path";
83332
+ import path27 from "node:path";
83241
83333
  var COMPONENT_ID3 = "main";
83242
83334
  var WORKFLOW_EXTS = new Set([".md", ".yml"]);
83243
83335
  function conceptIdOf(relPath) {
@@ -83291,8 +83383,8 @@ async function validate4(c, changes, ctx) {
83291
83383
  const raw = change.after ?? await ctx.readFile(change.path);
83292
83384
  if (typeof raw !== "string")
83293
83385
  continue;
83294
- const ext = path26.extname(change.path).toLowerCase();
83295
- if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path26.basename(change.path)))
83386
+ const ext = path27.extname(change.path).toLowerCase();
83387
+ if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path27.basename(change.path)))
83296
83388
  continue;
83297
83389
  const relPath = toPosix(change.path);
83298
83390
  if (ext === ".yml") {
@@ -83321,12 +83413,12 @@ function hasTopLevelWorkflowFile(root, entries) {
83321
83413
  for (const entry of entries) {
83322
83414
  if (!entry.isFile())
83323
83415
  continue;
83324
- const ext = path26.extname(entry.name).toLowerCase();
83416
+ const ext = path27.extname(entry.name).toLowerCase();
83325
83417
  if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(entry.name))
83326
83418
  continue;
83327
83419
  let raw;
83328
83420
  try {
83329
- raw = fs18.readFileSync(path26.join(root, entry.name), "utf8");
83421
+ raw = fs18.readFileSync(path27.join(root, entry.name), "utf8");
83330
83422
  } catch {
83331
83423
  continue;
83332
83424
  }
@@ -83346,16 +83438,16 @@ var akmWorkflowAdapter = {
83346
83438
  readCandidates(c, conceptId) {
83347
83439
  const posix = toPosix(conceptId);
83348
83440
  const canonical = posix.replace(/\.(?:md|yml)$/i, "");
83349
- return /\.(?:md|yml)$/i.test(posix) ? [{ path: path26.join(c.root, posix), conceptId: canonical }] : [
83350
- { path: path26.join(c.root, `${posix}.md`), conceptId: canonical },
83351
- { path: path26.join(c.root, `${posix}.yml`), conceptId: canonical }
83441
+ return /\.(?:md|yml)$/i.test(posix) ? [{ path: path27.join(c.root, posix), conceptId: canonical }] : [
83442
+ { path: path27.join(c.root, `${posix}.md`), conceptId: canonical },
83443
+ { path: path27.join(c.root, `${posix}.yml`), conceptId: canonical }
83352
83444
  ];
83353
83445
  },
83354
83446
  placeNew(c, conceptId) {
83355
83447
  const posix = toPosix(conceptId);
83356
83448
  if (/\.(?:md|yml)$/i.test(posix))
83357
- return path26.join(c.root, posix);
83358
- return path26.join(c.root, `${posix}.md`);
83449
+ return path27.join(c.root, posix);
83450
+ return path27.join(c.root, `${posix}.md`);
83359
83451
  },
83360
83452
  directoryList() {
83361
83453
  return ["."];
@@ -83373,10 +83465,10 @@ var akmWorkflowAdapter = {
83373
83465
 
83374
83466
  // src/core/adapter/adapters/claude-adapter.ts
83375
83467
  import fs19 from "node:fs";
83376
- import path28 from "node:path";
83468
+ import path29 from "node:path";
83377
83469
 
83378
83470
  // src/core/adapter/adapters/tool-dir-shared.ts
83379
- import path27 from "node:path";
83471
+ import path28 from "node:path";
83380
83472
  init_frontmatter();
83381
83473
  init_common();
83382
83474
  var CANONICAL_COMMAND_DIR = "commands";
@@ -83398,7 +83490,7 @@ function classify(relPath, layout) {
83398
83490
  return { type: "instruction", conceptId: layout.instructionConceptId, name: layout.instructionConceptId };
83399
83491
  }
83400
83492
  const head = segs[0];
83401
- const ext = path27.extname(base3).toLowerCase();
83493
+ const ext = path28.extname(base3).toLowerCase();
83402
83494
  if (layout.skillDirs.has(head)) {
83403
83495
  if (segs.length === 3 && base3 === SKILL_MANIFEST2) {
83404
83496
  return { type: "skill", conceptId: `${segs[0]}/${segs[1]}`, name: segs[1] };
@@ -83447,24 +83539,24 @@ function recognizeToolDir(layout, c, file) {
83447
83539
  function placeNewToolDir(layout, c, conceptId) {
83448
83540
  const posix = toPosix(conceptId);
83449
83541
  if (posix === layout.instructionConceptId)
83450
- return path27.join(c.root, layout.instructionFile);
83542
+ return path28.join(c.root, layout.instructionFile);
83451
83543
  const segs = posix.split("/").filter((s) => s.length > 0);
83452
83544
  const head = segs[0];
83453
83545
  const rest = segs.slice(1).join("/");
83454
83546
  if (rest.length > 0) {
83455
83547
  if (layout.skillDirs.has(head))
83456
- return path27.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST2);
83548
+ return path28.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST2);
83457
83549
  if (layout.commandDirs.has(head))
83458
- return path27.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
83550
+ return path28.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
83459
83551
  if (layout.agentDirs.has(head))
83460
- return path27.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
83552
+ return path28.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
83461
83553
  }
83462
- return path27.join(c.root, `${posix}.md`);
83554
+ return path28.join(c.root, `${posix}.md`);
83463
83555
  }
83464
83556
  function readCandidatesToolDir(layout, c, conceptId) {
83465
83557
  const posix = toPosix(conceptId);
83466
83558
  if (posix === layout.instructionConceptId) {
83467
- return [{ path: path27.join(c.root, layout.instructionFile), conceptId: posix }];
83559
+ return [{ path: path28.join(c.root, layout.instructionFile), conceptId: posix }];
83468
83560
  }
83469
83561
  const segs = posix.split("/").filter((segment) => segment.length > 0);
83470
83562
  const head = segs[0];
@@ -83472,10 +83564,10 @@ function readCandidatesToolDir(layout, c, conceptId) {
83472
83564
  if (!head || !rest)
83473
83565
  return [];
83474
83566
  if (layout.skillDirs.has(head)) {
83475
- return segs.length === 2 ? [{ path: path27.join(c.root, head, rest, SKILL_MANIFEST2), conceptId: posix }] : [];
83567
+ return segs.length === 2 ? [{ path: path28.join(c.root, head, rest, SKILL_MANIFEST2), conceptId: posix }] : [];
83476
83568
  }
83477
83569
  if (layout.commandDirs.has(head) || layout.agentDirs.has(head)) {
83478
- return [{ path: path27.join(c.root, head, `${rest}.md`), conceptId: posix }];
83570
+ return [{ path: path28.join(c.root, head, `${rest}.md`), conceptId: posix }];
83479
83571
  }
83480
83572
  return [];
83481
83573
  }
@@ -83587,12 +83679,12 @@ function dirExists(p) {
83587
83679
  }
83588
83680
  function claudeLooksLikeRoot(root) {
83589
83681
  try {
83590
- if (!fs19.existsSync(path28.join(root, "CLAUDE.md")))
83682
+ if (!fs19.existsSync(path29.join(root, "CLAUDE.md")))
83591
83683
  return false;
83592
83684
  } catch {
83593
83685
  return false;
83594
83686
  }
83595
- return ["commands", "agents", "skills"].some((d) => dirExists(path28.join(root, d)));
83687
+ return ["commands", "agents", "skills"].some((d) => dirExists(path29.join(root, d)));
83596
83688
  }
83597
83689
  var claudeAdapter = makeToolDirAdapter(LAYOUT, claudeLooksLikeRoot);
83598
83690
 
@@ -83600,7 +83692,7 @@ var claudeAdapter = makeToolDirAdapter(LAYOUT, claudeLooksLikeRoot);
83600
83692
  init_asset_placement();
83601
83693
  init_common();
83602
83694
  import fs20 from "node:fs";
83603
- import path29 from "node:path";
83695
+ import path30 from "node:path";
83604
83696
  var COMPONENT_ID4 = "main";
83605
83697
  var ENV_DIR = "env";
83606
83698
  var SECRETS_DIR = "secrets";
@@ -83702,7 +83794,7 @@ var dotenvAdapter = {
83702
83794
  const type = typeForStashDir(head);
83703
83795
  if (type !== "env" && type !== "secret" || rest.length === 0)
83704
83796
  return [];
83705
- const primaries = assetPathCandidatesForName(type, path29.join(c.root, head), rest);
83797
+ const primaries = assetPathCandidatesForName(type, path30.join(c.root, head), rest);
83706
83798
  const expanded = primaries.flatMap((primary) => type === "env" ? [primary, primary.replace(/\.env$/i, ".sensitive")] : [primary, `${primary}.sensitive`, `${primary}.lock`]);
83707
83799
  return expanded.map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
83708
83800
  },
@@ -83714,10 +83806,10 @@ var dotenvAdapter = {
83714
83806
  const rest = posix.slice(slash + 1);
83715
83807
  const type = typeForStashDir(head);
83716
83808
  if ((type === "env" || type === "secret") && rest.length > 0) {
83717
- return assetPathForName(type, path29.join(c.root, head), rest);
83809
+ return assetPathForName(type, path30.join(c.root, head), rest);
83718
83810
  }
83719
83811
  }
83720
- return path29.join(c.root, posix);
83812
+ return path30.join(c.root, posix);
83721
83813
  },
83722
83814
  directoryList() {
83723
83815
  return [ENV_DIR, SECRETS_DIR];
@@ -83742,7 +83834,7 @@ var dotenvAdapter = {
83742
83834
  init_frontmatter();
83743
83835
  init_common();
83744
83836
  init_recognition_util();
83745
- import path30 from "node:path";
83837
+ import path31 from "node:path";
83746
83838
  var COMPONENT_ID5 = "main";
83747
83839
  var DOCUMENT_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".text"]);
83748
83840
  function isReserved2(base3) {
@@ -83808,17 +83900,17 @@ var genericFilesAdapter = {
83808
83900
  validate: validate6,
83809
83901
  readCandidates(c, conceptId) {
83810
83902
  const posix = toPosix(conceptId);
83811
- const extension = path30.extname(posix).toLowerCase();
83903
+ const extension = path31.extname(posix).toLowerCase();
83812
83904
  const documentCandidates = [...DOCUMENT_EXTENSIONS].map((candidateExtension) => ({
83813
- path: path30.join(c.root, `${posix}${candidateExtension}`),
83905
+ path: path31.join(c.root, `${posix}${candidateExtension}`),
83814
83906
  conceptId: posix
83815
83907
  }));
83816
- return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path30.join(c.root, posix), conceptId: posix }, ...documentCandidates];
83908
+ return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path31.join(c.root, posix), conceptId: posix }, ...documentCandidates];
83817
83909
  },
83818
83910
  placeNew(c, conceptId) {
83819
83911
  const posix = toPosix(conceptId);
83820
- const hasExt = path30.extname(posix) !== "";
83821
- return path30.join(c.root, hasExt ? posix : `${posix}.md`);
83912
+ const hasExt = path31.extname(posix) !== "";
83913
+ return path31.join(c.root, hasExt ? posix : `${posix}.md`);
83822
83914
  },
83823
83915
  looksLikeRoot() {
83824
83916
  return false;
@@ -83830,7 +83922,7 @@ init_dist();
83830
83922
  init_frontmatter();
83831
83923
  init_common();
83832
83924
  import fs21 from "node:fs";
83833
- import path31 from "node:path";
83925
+ import path32 from "node:path";
83834
83926
  var WIKI_COMPONENT_ID = "main";
83835
83927
  var WIKI_SOURCE_TYPE = "wiki-source";
83836
83928
  var DEFAULT_PAGE_KIND = "note";
@@ -83888,7 +83980,7 @@ function resolveXref(xref, bundleId) {
83888
83980
  return target.length > 0 ? target : null;
83889
83981
  }
83890
83982
  function resolveBodyLinks(body, fileRelPath) {
83891
- const dir = path31.posix.dirname(toPosix(fileRelPath));
83983
+ const dir = path32.posix.dirname(toPosix(fileRelPath));
83892
83984
  const linkRe = /\[[^\]]*\]\(([^)]+)\)/g;
83893
83985
  const out = [];
83894
83986
  const seen = new Set;
@@ -83914,10 +84006,10 @@ function resolveBodyLinks(body, fileRelPath) {
83914
84006
  continue;
83915
84007
  let resolved;
83916
84008
  if (target.startsWith("/")) {
83917
- resolved = path31.posix.normalize(target.slice(1));
84009
+ resolved = path32.posix.normalize(target.slice(1));
83918
84010
  } else {
83919
84011
  const base3 = dir === "." ? "" : dir;
83920
- resolved = path31.posix.normalize(path31.posix.join(base3, target));
84012
+ resolved = path32.posix.normalize(path32.posix.join(base3, target));
83921
84013
  }
83922
84014
  if (resolved.startsWith("../") || resolved === ".." || resolved.startsWith("/"))
83923
84015
  continue;
@@ -84099,19 +84191,19 @@ var llmWikiAdapter = {
84099
84191
  validate: validate7,
84100
84192
  readCandidates(c, conceptId) {
84101
84193
  const canonical = toPosix(conceptId).replace(/\.md$/i, "");
84102
- return [{ path: path31.join(c.root, `${canonical}.md`), conceptId: canonical }];
84194
+ return [{ path: path32.join(c.root, `${canonical}.md`), conceptId: canonical }];
84103
84195
  },
84104
84196
  placeNew(c, conceptId) {
84105
- return path31.join(c.root, `${conceptId}.md`);
84197
+ return path32.join(c.root, `${conceptId}.md`);
84106
84198
  },
84107
84199
  directoryList(_c) {
84108
84200
  return ["."];
84109
84201
  },
84110
84202
  looksLikeRoot(root) {
84111
84203
  try {
84112
- if (!fs21.existsSync(path31.join(root, "schema.md")))
84204
+ if (!fs21.existsSync(path32.join(root, "schema.md")))
84113
84205
  return false;
84114
- return fs21.statSync(path31.join(root, PAGES_SUBDIR)).isDirectory();
84206
+ return fs21.statSync(path32.join(root, PAGES_SUBDIR)).isDirectory();
84115
84207
  } catch {
84116
84208
  return false;
84117
84209
  }
@@ -84122,7 +84214,7 @@ var llmWikiAdapter = {
84122
84214
  init_frontmatter();
84123
84215
  init_common();
84124
84216
  import fs22 from "node:fs";
84125
- import path32 from "node:path";
84217
+ import path33 from "node:path";
84126
84218
  var CONSUMED_FRONTMATTER_KEYS = [
84127
84219
  "type",
84128
84220
  "title",
@@ -84194,7 +84286,7 @@ function isReservedFileName2(name) {
84194
84286
  return RESERVED_FILES.has(name.toLowerCase());
84195
84287
  }
84196
84288
  function resolveOkfLinks(body, fileRelPath) {
84197
- const dir = path32.posix.dirname(toPosix(fileRelPath));
84289
+ const dir = path33.posix.dirname(toPosix(fileRelPath));
84198
84290
  const definitions = new Map;
84199
84291
  for (const match of body.matchAll(/^\s*\[([^\]]+)\]:\s*(\S+)/gm)) {
84200
84292
  definitions.set(match[1].trim().toLowerCase(), match[2]);
@@ -84232,10 +84324,10 @@ function resolveOkfLinks(body, fileRelPath) {
84232
84324
  continue;
84233
84325
  let resolved;
84234
84326
  if (target.startsWith("/")) {
84235
- resolved = path32.posix.normalize(target.slice(1));
84327
+ resolved = path33.posix.normalize(target.slice(1));
84236
84328
  } else {
84237
84329
  const base3 = dir === "." ? "" : dir;
84238
- resolved = path32.posix.normalize(path32.posix.join(base3, target));
84330
+ resolved = path33.posix.normalize(path33.posix.join(base3, target));
84239
84331
  }
84240
84332
  if (resolved.startsWith("../") || resolved === ".." || resolved.startsWith("/"))
84241
84333
  continue;
@@ -84363,13 +84455,13 @@ var okfAdapter = {
84363
84455
  validate: validate8,
84364
84456
  readCandidates(c, conceptId) {
84365
84457
  const canonical = conceptId.replace(/\\/g, "/").replace(/\.md$/i, "");
84366
- return [{ path: path32.join(c.root, `${canonical}.md`), conceptId: canonical }];
84458
+ return [{ path: path33.join(c.root, `${canonical}.md`), conceptId: canonical }];
84367
84459
  },
84368
84460
  directoryList(_c) {
84369
84461
  return ["."];
84370
84462
  },
84371
84463
  looksLikeRoot(root) {
84372
- if (fs22.existsSync(path32.join(root, "index.md")))
84464
+ if (fs22.existsSync(path33.join(root, "index.md")))
84373
84465
  return true;
84374
84466
  const stack = [root];
84375
84467
  while (stack.length > 0) {
@@ -84385,7 +84477,7 @@ var okfAdapter = {
84385
84477
  for (const entry of entries) {
84386
84478
  if (entry.isSymbolicLink() || entry.name === ".git")
84387
84479
  continue;
84388
- const absolute = path32.join(current, entry.name);
84480
+ const absolute = path33.join(current, entry.name);
84389
84481
  if (entry.isDirectory()) {
84390
84482
  stack.push(absolute);
84391
84483
  continue;
@@ -84403,7 +84495,7 @@ var okfAdapter = {
84403
84495
 
84404
84496
  // src/core/adapter/adapters/opencode-adapter.ts
84405
84497
  import fs23 from "node:fs";
84406
- import path33 from "node:path";
84498
+ import path34 from "node:path";
84407
84499
  var LAYOUT2 = {
84408
84500
  adapterId: "opencode",
84409
84501
  componentId: ".opencode",
@@ -84430,11 +84522,11 @@ function dirExists2(p) {
84430
84522
  }
84431
84523
  }
84432
84524
  function opencodeLooksLikeRoot(root) {
84433
- if (CONFIG_FILES.some((f) => fileExists(path33.join(root, f))))
84525
+ if (CONFIG_FILES.some((f) => fileExists(path34.join(root, f))))
84434
84526
  return true;
84435
- if (!fileExists(path33.join(root, "AGENTS.md")))
84527
+ if (!fileExists(path34.join(root, "AGENTS.md")))
84436
84528
  return false;
84437
- return TOOL_DIRS.some((d) => dirExists2(path33.join(root, d)));
84529
+ return TOOL_DIRS.some((d) => dirExists2(path34.join(root, d)));
84438
84530
  }
84439
84531
  var opencodeAdapter = makeToolDirAdapter(LAYOUT2, opencodeLooksLikeRoot);
84440
84532
 
@@ -84443,7 +84535,7 @@ init_dist();
84443
84535
  init_frontmatter();
84444
84536
  init_common();
84445
84537
  import fs24 from "node:fs";
84446
- import path34 from "node:path";
84538
+ import path35 from "node:path";
84447
84539
  var COMPONENT_ID6 = "main";
84448
84540
  var PAGES_PREFIX = "stash/knowledge/";
84449
84541
  var MANIFEST_FILE = "manifest.json";
@@ -84531,12 +84623,12 @@ var websiteSnapshotAdapter = {
84531
84623
  validate: validate9,
84532
84624
  readCandidates(c, conceptId) {
84533
84625
  const canonical = toPosix(conceptId).replace(/\.md$/i, "");
84534
- return [{ path: path34.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
84626
+ return [{ path: path35.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
84535
84627
  },
84536
84628
  looksLikeRoot(root) {
84537
84629
  let raw;
84538
84630
  try {
84539
- raw = fs24.readFileSync(path34.join(root, MANIFEST_FILE), "utf8");
84631
+ raw = fs24.readFileSync(path35.join(root, MANIFEST_FILE), "utf8");
84540
84632
  } catch {
84541
84633
  return false;
84542
84634
  }
@@ -84649,7 +84741,7 @@ function isSourceWriteActivated(source) {
84649
84741
 
84650
84742
  // src/core/adapter/detect-adapter.ts
84651
84743
  import fs25 from "node:fs";
84652
- import path35 from "node:path";
84744
+ import path36 from "node:path";
84653
84745
  var SHADOWABLE_ADAPTER_IDS = new Set(["agent-skills", "claude", "opencode"]);
84654
84746
  function hasExtraAkmContent(root, winnerId) {
84655
84747
  const akm = adapterForId("akm");
@@ -84671,13 +84763,13 @@ function hasExtraAkmContent(root, winnerId) {
84671
84763
  continue;
84672
84764
  if (winnerId === "agent-skills") {
84673
84765
  try {
84674
- if (fs25.statSync(path35.join(root, entry.name, "SKILL.md")).isFile())
84766
+ if (fs25.statSync(path36.join(root, entry.name, "SKILL.md")).isFile())
84675
84767
  continue;
84676
84768
  } catch {}
84677
84769
  }
84678
84770
  let children;
84679
84771
  try {
84680
- children = fs25.readdirSync(path35.join(root, entry.name), { withFileTypes: true });
84772
+ children = fs25.readdirSync(path36.join(root, entry.name), { withFileTypes: true });
84681
84773
  } catch {
84682
84774
  continue;
84683
84775
  }
@@ -84702,48 +84794,7 @@ function detectAdapterId(root, fallback = "akm") {
84702
84794
 
84703
84795
  // src/indexer/installations.ts
84704
84796
  init_asset_placement();
84705
-
84706
- // src/core/bundle-id.ts
84707
- init_asset_ref();
84708
- import crypto5 from "node:crypto";
84709
- import path36 from "node:path";
84710
- function slugForPath(sourcePath) {
84711
- const resolved = path36.resolve(sourcePath);
84712
- const base3 = path36.basename(resolved).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
84713
- if (base3.length > 0)
84714
- return base3;
84715
- return `bundle-${shortHash(resolved)}`;
84716
- }
84717
- function deriveBundleId(registryId, sourcePath, usedIds) {
84718
- const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
84719
- const id = ensureUniqueId(preferred, sourcePath, usedIds);
84720
- usedIds.add(id);
84721
- return id;
84722
- }
84723
- function deriveBundleIds(sources) {
84724
- const usedIds = new Set;
84725
- const reservedIds = new Set(sources.flatMap((source) => source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : []));
84726
- return sources.map((source) => {
84727
- const id = source.registryId && isBundleSlug(source.registryId) ? deriveBundleId(source.registryId, source.path, usedIds) : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
84728
- usedIds.add(id);
84729
- return id;
84730
- });
84731
- }
84732
- function ensureUniqueId(preferred, sourcePath, used) {
84733
- if (!used.has(preferred))
84734
- return preferred;
84735
- const suffixed = `${preferred}-${shortHash(path36.resolve(sourcePath))}`;
84736
- if (!used.has(suffixed))
84737
- return suffixed;
84738
- let n = 2;
84739
- while (used.has(`${suffixed}-${n}`))
84740
- n++;
84741
- return `${suffixed}-${n}`;
84742
- }
84743
- function shortHash(input) {
84744
- return crypto5.createHash("sha256").update(input).digest("hex").slice(0, 8);
84745
- }
84746
- // src/indexer/installations.ts
84797
+ init_bundle_id();
84747
84798
  var FALLBACK_ADAPTER_ID = "akm";
84748
84799
  function deriveInstallations(sources) {
84749
84800
  const ids = deriveBundleIds(sources);
@@ -84782,6 +84833,7 @@ function deriveEntryProvenance(bundle, type, name, adapterConceptId) {
84782
84833
  // src/indexer/search/search-source.ts
84783
84834
  init_common();
84784
84835
  import path49 from "node:path";
84836
+ init_paths();
84785
84837
 
84786
84838
  // src/core/write-source.ts
84787
84839
  import fs36 from "node:fs";
@@ -87752,6 +87804,7 @@ function buildGithubTargetAliases(canonicalUrl) {
87752
87804
  // src/core/write-source.ts
87753
87805
  init_asset_placement();
87754
87806
  init_resolve_ref();
87807
+ init_bundle_id();
87755
87808
  init_common();
87756
87809
  init_errors();
87757
87810
  init_warn();
@@ -92295,14 +92348,14 @@ function resolveSourceEntries(overrideStashDir, existingConfig) {
92295
92348
  const component = bundleComponentConfig(config.bundles?.[entry.name ?? ""]);
92296
92349
  const contentRoot = resolveEntryContentDir(entry);
92297
92350
  if (contentRoot == null) {
92298
- const unresolvedPath = path49.join(implicitStashDir ?? process.cwd(), ".akm", "unresolved-sources", entry.name ?? entry.type);
92351
+ const unresolvedPath = path49.join(getUnresolvedSourcesDir(implicitStashDir ?? process.cwd()), entry.name ?? entry.type);
92299
92352
  addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
92300
92353
  continue;
92301
92354
  }
92302
92355
  const dir = path49.resolve(contentRoot, component?.root ?? ".");
92303
92356
  if (!isWithin(dir, contentRoot)) {
92304
92357
  warn(`Warning: component root "${component?.root}" escapes bundle "${entry.name}"; skipping source.`);
92305
- const unresolvedPath = path49.join(contentRoot, ".akm", "unresolved-sources", entry.name ?? entry.type);
92358
+ const unresolvedPath = path49.join(getUnresolvedSourcesDir(contentRoot), entry.name ?? entry.type);
92306
92359
  addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
92307
92360
  continue;
92308
92361
  }
@@ -95472,31 +95525,178 @@ async function recoverStaleTxns(stashDir) {
95472
95525
  return recovered.map(journalToEntry);
95473
95526
  }
95474
95527
 
95528
+ // scripts/akm-migrate/migrate/writer-relocation.ts
95529
+ import fs48 from "node:fs";
95530
+ import path61 from "node:path";
95531
+ init_paths();
95532
+ function relocationSpecs(stashDir) {
95533
+ return [
95534
+ { key: "distillRejected", oldRelative: "distill-rejected", newDir: getDistillRejectedDir(stashDir) },
95535
+ { key: "evalCases", oldRelative: "eval-cases", newDir: getEvalCasesDir(stashDir) },
95536
+ {
95537
+ key: "measurementVerdicts",
95538
+ oldRelative: ["measurement", "verdicts"],
95539
+ newDir: getMeasurementVerdictsDir(stashDir)
95540
+ }
95541
+ ];
95542
+ }
95543
+ var LOCK_NAMES = ["improve.lock", "consolidate.lock", "reflect-distill.lock", "triage.lock"];
95544
+ function mutexSiblingName(lockName) {
95545
+ return `.${lockName}.operations.sensitive`;
95546
+ }
95547
+ function fileCountIfExists(dir) {
95548
+ let entries;
95549
+ try {
95550
+ entries = fs48.readdirSync(dir, { withFileTypes: true });
95551
+ } catch {
95552
+ return;
95553
+ }
95554
+ return entries.filter((entry) => entry.isFile()).length;
95555
+ }
95556
+ function statFileIfExists(filePath) {
95557
+ try {
95558
+ const stat = fs48.statSync(filePath);
95559
+ return stat.isFile() ? stat : undefined;
95560
+ } catch {
95561
+ return;
95562
+ }
95563
+ }
95564
+ function classifyLockArtifacts(akmDir) {
95565
+ const removable = [];
95566
+ const skipped = [];
95567
+ for (const lockName of LOCK_NAMES) {
95568
+ const lockPath = path61.join(akmDir, lockName);
95569
+ const mutexPath = path61.join(akmDir, mutexSiblingName(lockName));
95570
+ const lockStat = statFileIfExists(lockPath);
95571
+ const mutexStat = statFileIfExists(mutexPath);
95572
+ if (!lockStat) {
95573
+ if (mutexStat)
95574
+ removable.push({ path: mutexPath, sizeBytes: mutexStat.size });
95575
+ continue;
95576
+ }
95577
+ const probe = probeLock(lockPath);
95578
+ if (probe.state === "held") {
95579
+ skipped.push({ path: lockPath, reason: "held", holderPid: probe.holderPid });
95580
+ continue;
95581
+ }
95582
+ if (probe.state === "inaccessible") {
95583
+ skipped.push({ path: lockPath, reason: "inaccessible" });
95584
+ continue;
95585
+ }
95586
+ if (probe.state === "absent")
95587
+ continue;
95588
+ removable.push({ path: lockPath, sizeBytes: lockStat.size });
95589
+ if (mutexStat)
95590
+ removable.push({ path: mutexPath, sizeBytes: mutexStat.size });
95591
+ }
95592
+ return { removable, skipped };
95593
+ }
95594
+ function findWriterRelocationEntries(stashDir) {
95595
+ const akmDir = path61.join(stashDir, ".akm");
95596
+ const directories = [];
95597
+ for (const spec of relocationSpecs(stashDir)) {
95598
+ const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
95599
+ const oldPath = path61.join(akmDir, ...relativeParts);
95600
+ const fileCount = fileCountIfExists(oldPath);
95601
+ if (fileCount === undefined || fileCount === 0)
95602
+ continue;
95603
+ directories.push({ key: spec.key, oldPath, newPath: spec.newDir, fileCount });
95604
+ }
95605
+ const { removable, skipped } = classifyLockArtifacts(akmDir);
95606
+ return { directories, lockArtifacts: removable, skippedLocks: skipped };
95607
+ }
95608
+ function moveFile(oldFilePath, newFilePath) {
95609
+ try {
95610
+ fs48.renameSync(oldFilePath, newFilePath);
95611
+ } catch (error2) {
95612
+ if (error2.code !== "EXDEV")
95613
+ throw error2;
95614
+ fs48.copyFileSync(oldFilePath, newFilePath);
95615
+ fs48.rmSync(oldFilePath, { force: true });
95616
+ }
95617
+ }
95618
+ function moveDirectoryContents(entry) {
95619
+ const errors3 = [];
95620
+ let moved = 0;
95621
+ fs48.mkdirSync(entry.newPath, { recursive: true });
95622
+ let names;
95623
+ try {
95624
+ names = fs48.readdirSync(entry.oldPath).sort();
95625
+ } catch {
95626
+ return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved: 0, errors: [] };
95627
+ }
95628
+ for (const name of names) {
95629
+ const oldFilePath = path61.join(entry.oldPath, name);
95630
+ const newFilePath = path61.join(entry.newPath, name);
95631
+ let oldStat;
95632
+ try {
95633
+ oldStat = fs48.lstatSync(oldFilePath);
95634
+ } catch {
95635
+ continue;
95636
+ }
95637
+ if (!oldStat.isFile())
95638
+ continue;
95639
+ if (fs48.existsSync(newFilePath))
95640
+ continue;
95641
+ try {
95642
+ moveFile(oldFilePath, newFilePath);
95643
+ moved += 1;
95644
+ } catch (error2) {
95645
+ errors3.push(`${name}: ${error2 instanceof Error ? error2.message : String(error2)}`);
95646
+ }
95647
+ }
95648
+ return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved, errors: errors3 };
95649
+ }
95650
+ function removeIfEmptyDir(dir) {
95651
+ try {
95652
+ if (fs48.readdirSync(dir).length === 0)
95653
+ fs48.rmdirSync(dir);
95654
+ } catch {}
95655
+ }
95656
+ function removeLockArtifact(entry) {
95657
+ try {
95658
+ fs48.rmSync(entry.path, { force: true });
95659
+ return { path: entry.path, removed: true };
95660
+ } catch (error2) {
95661
+ return { path: entry.path, removed: false, error: error2 instanceof Error ? error2.message : String(error2) };
95662
+ }
95663
+ }
95664
+ function applyWriterRelocation(stashDir) {
95665
+ const { directories, lockArtifacts, skippedLocks } = findWriterRelocationEntries(stashDir);
95666
+ const directoryResults = directories.map(moveDirectoryContents);
95667
+ const lockResults = lockArtifacts.map(removeLockArtifact);
95668
+ for (const spec of relocationSpecs(stashDir)) {
95669
+ const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
95670
+ removeIfEmptyDir(path61.join(stashDir, ".akm", ...relativeParts));
95671
+ }
95672
+ return { directories: directoryResults, lockArtifacts: lockResults, skippedLocks };
95673
+ }
95674
+
95475
95675
  // scripts/akm-migrate/task-migrate.ts
95476
95676
  import { randomUUID as randomUUID7 } from "node:crypto";
95477
- import fs51 from "node:fs";
95677
+ import fs53 from "node:fs";
95478
95678
  import os5 from "node:os";
95479
- import path63 from "node:path";
95679
+ import path64 from "node:path";
95480
95680
  init_errors();
95481
95681
  init_paths();
95482
95682
 
95483
95683
  // scripts/akm-migrate/migrate/task-files-to-v3.ts
95484
95684
  init_errors();
95485
95685
  import crypto6 from "node:crypto";
95486
- import fs49 from "node:fs";
95487
- import path61 from "node:path";
95686
+ import fs50 from "node:fs";
95687
+ import path62 from "node:path";
95488
95688
 
95489
95689
  // scripts/akm-migrate/migrate/durable-fs.ts
95490
- import fs48 from "node:fs";
95690
+ import fs49 from "node:fs";
95491
95691
  function fsyncDirectoryPortable(directory) {
95492
95692
  if (process.platform === "win32")
95493
95693
  return;
95494
95694
  try {
95495
- const fd = fs48.openSync(directory, "r");
95695
+ const fd = fs49.openSync(directory, "r");
95496
95696
  try {
95497
- fs48.fsyncSync(fd);
95697
+ fs49.fsyncSync(fd);
95498
95698
  } finally {
95499
- fs48.closeSync(fd);
95699
+ fs49.closeSync(fd);
95500
95700
  }
95501
95701
  } catch (cause) {
95502
95702
  const code = cause.code;
@@ -95510,25 +95710,25 @@ function migrationError(detail) {
95510
95710
  return new ConfigError(`Task migration to v3 failed: ${detail}`, "INVALID_CONFIG_FILE");
95511
95711
  }
95512
95712
  function contained2(root, candidate) {
95513
- const relative = path61.relative(root, candidate);
95514
- return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
95713
+ const relative = path62.relative(root, candidate);
95714
+ return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
95515
95715
  }
95516
95716
  function realDirectory(filePath) {
95517
- const stat = fs49.lstatSync(filePath);
95717
+ const stat = fs50.lstatSync(filePath);
95518
95718
  if (stat.isSymbolicLink() || !stat.isDirectory())
95519
95719
  throw migrationError(`${filePath} must be a real directory.`);
95520
- return fs49.realpathSync(filePath);
95720
+ return fs50.realpathSync(filePath);
95521
95721
  }
95522
95722
  function snapshot(filePath) {
95523
- const stat = fs49.lstatSync(filePath);
95723
+ const stat = fs50.lstatSync(filePath);
95524
95724
  if (stat.isSymbolicLink() || !stat.isFile())
95525
95725
  throw migrationError(`${filePath} must be a real file.`);
95526
- const bytes = fs49.readFileSync(filePath);
95726
+ const bytes = fs50.readFileSync(filePath);
95527
95727
  return Object.freeze({ bytes, mode: stat.mode & 511 });
95528
95728
  }
95529
95729
  function writable(filePath) {
95530
95730
  try {
95531
- fs49.accessSync(filePath, fs49.constants.W_OK);
95731
+ fs50.accessSync(filePath, fs50.constants.W_OK);
95532
95732
  return true;
95533
95733
  } catch {
95534
95734
  return false;
@@ -95541,12 +95741,12 @@ function walkTasks(root, tasksDir, out) {
95541
95741
  throw migrationError(`${root.root} resolves outside bundle ${root.bundleId}.`);
95542
95742
  }
95543
95743
  const visit2 = (directory) => {
95544
- const physicalDirectory = fs49.realpathSync(directory);
95744
+ const physicalDirectory = fs50.realpathSync(directory);
95545
95745
  if (!contained2(physicalRoot, physicalDirectory)) {
95546
95746
  throw migrationError(`${directory} resolves outside bundle ${root.bundleId}.`);
95547
95747
  }
95548
- for (const entry of fs49.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95549
- const candidate = path61.join(directory, entry.name);
95748
+ for (const entry of fs50.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95749
+ const candidate = path62.join(directory, entry.name);
95550
95750
  if (entry.isSymbolicLink())
95551
95751
  throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
95552
95752
  if (entry.isDirectory()) {
@@ -95556,7 +95756,7 @@ function walkTasks(root, tasksDir, out) {
95556
95756
  if (!entry.isFile() || !entry.name.endsWith(".yml"))
95557
95757
  continue;
95558
95758
  const current = snapshot(candidate);
95559
- const parent = path61.dirname(candidate);
95759
+ const parent = path62.dirname(candidate);
95560
95760
  out.push({
95561
95761
  filePath: candidate,
95562
95762
  bytes: current.bytes,
@@ -95572,9 +95772,9 @@ function walkTasks(root, tasksDir, out) {
95572
95772
  function inspectTaskToV3Files(roots) {
95573
95773
  const files = [];
95574
95774
  for (const root of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
95575
- const tasksDir = root.layout === "akm-task" ? root.root : path61.join(root.root, "tasks");
95775
+ const tasksDir = root.layout === "akm-task" ? root.root : path62.join(root.root, "tasks");
95576
95776
  try {
95577
- const stat = fs49.lstatSync(tasksDir);
95777
+ const stat = fs50.lstatSync(tasksDir);
95578
95778
  if (stat.isSymbolicLink())
95579
95779
  throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
95580
95780
  if (!stat.isDirectory())
@@ -95589,33 +95789,33 @@ function inspectTaskToV3Files(roots) {
95589
95789
  return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
95590
95790
  }
95591
95791
  function hashPath(filePath) {
95592
- return crypto6.createHash("sha256").update(path61.resolve(filePath)).digest("hex").slice(0, 16);
95792
+ return crypto6.createHash("sha256").update(path62.resolve(filePath)).digest("hex").slice(0, 16);
95593
95793
  }
95594
95794
  function taskMigrationBackupPath(backupRoot, filePath) {
95595
- return path61.join(backupRoot, "files", `${hashPath(filePath)}-${path61.basename(filePath)}`);
95795
+ return path62.join(backupRoot, "files", `${hashPath(filePath)}-${path62.basename(filePath)}`);
95596
95796
  }
95597
95797
  function writeDurable(filePath, bytes, mode, exclusive = false) {
95598
- fs49.mkdirSync(path61.dirname(filePath), { recursive: true });
95798
+ fs50.mkdirSync(path62.dirname(filePath), { recursive: true });
95599
95799
  const flags = exclusive ? "wx" : "w";
95600
- const fd = fs49.openSync(filePath, flags, mode);
95800
+ const fd = fs50.openSync(filePath, flags, mode);
95601
95801
  try {
95602
- fs49.writeFileSync(fd, bytes);
95603
- fs49.fsyncSync(fd);
95802
+ fs50.writeFileSync(fd, bytes);
95803
+ fs50.fsyncSync(fd);
95604
95804
  } finally {
95605
- fs49.closeSync(fd);
95805
+ fs50.closeSync(fd);
95606
95806
  }
95607
- fs49.chmodSync(filePath, mode);
95608
- fsyncDirectoryPortable(path61.dirname(filePath));
95807
+ fs50.chmodSync(filePath, mode);
95808
+ fsyncDirectoryPortable(path62.dirname(filePath));
95609
95809
  }
95610
95810
  function replaceAtomically(filePath, bytes, mode) {
95611
- const temporary = path61.join(path61.dirname(filePath), `.${path61.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
95811
+ const temporary = path62.join(path62.dirname(filePath), `.${path62.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
95612
95812
  try {
95613
95813
  writeDurable(temporary, bytes, mode, true);
95614
- fs49.renameSync(temporary, filePath);
95615
- fsyncDirectoryPortable(path61.dirname(filePath));
95814
+ fs50.renameSync(temporary, filePath);
95815
+ fsyncDirectoryPortable(path62.dirname(filePath));
95616
95816
  } finally {
95617
95817
  try {
95618
- fs49.unlinkSync(temporary);
95818
+ fs50.unlinkSync(temporary);
95619
95819
  } catch (cause) {
95620
95820
  if (cause.code !== "ENOENT")
95621
95821
  throw cause;
@@ -95654,7 +95854,7 @@ function applyTaskToV3MigrationPlan(plan, options) {
95654
95854
  const current = snapshot(change.filePath);
95655
95855
  if (!current.bytes.equals(change.after))
95656
95856
  continue;
95657
- replaceAtomically(change.filePath, fs49.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
95857
+ replaceAtomically(change.filePath, fs50.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
95658
95858
  }
95659
95859
  throw cause;
95660
95860
  }
@@ -95664,31 +95864,31 @@ function applyTaskToV3MigrationPlan(plan, options) {
95664
95864
  // scripts/akm-migrate/migrate/task-files-to-v4.ts
95665
95865
  init_errors();
95666
95866
  import crypto7 from "node:crypto";
95667
- import fs50 from "node:fs";
95668
- import path62 from "node:path";
95867
+ import fs51 from "node:fs";
95868
+ import path63 from "node:path";
95669
95869
  function migrationError2(detail) {
95670
95870
  return new ConfigError(`Task migration to v4 failed: ${detail}`, "INVALID_CONFIG_FILE");
95671
95871
  }
95672
95872
  function contained3(root, candidate) {
95673
- const relative = path62.relative(root, candidate);
95674
- return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
95873
+ const relative = path63.relative(root, candidate);
95874
+ return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
95675
95875
  }
95676
95876
  function realDirectory2(filePath) {
95677
- const stat = fs50.lstatSync(filePath);
95877
+ const stat = fs51.lstatSync(filePath);
95678
95878
  if (stat.isSymbolicLink() || !stat.isDirectory())
95679
95879
  throw migrationError2(`${filePath} must be a real directory.`);
95680
- return fs50.realpathSync(filePath);
95880
+ return fs51.realpathSync(filePath);
95681
95881
  }
95682
95882
  function snapshot2(filePath) {
95683
- const stat = fs50.lstatSync(filePath);
95883
+ const stat = fs51.lstatSync(filePath);
95684
95884
  if (stat.isSymbolicLink() || !stat.isFile())
95685
95885
  throw migrationError2(`${filePath} must be a real file.`);
95686
- const bytes = fs50.readFileSync(filePath);
95886
+ const bytes = fs51.readFileSync(filePath);
95687
95887
  return Object.freeze({ bytes, mode: stat.mode & 511 });
95688
95888
  }
95689
95889
  function writable2(filePath) {
95690
95890
  try {
95691
- fs50.accessSync(filePath, fs50.constants.W_OK);
95891
+ fs51.accessSync(filePath, fs51.constants.W_OK);
95692
95892
  return true;
95693
95893
  } catch {
95694
95894
  return false;
@@ -95701,12 +95901,12 @@ function walkTasks2(root, tasksDir, out) {
95701
95901
  throw migrationError2(`${root.root} resolves outside bundle ${root.bundleId}.`);
95702
95902
  }
95703
95903
  const visit2 = (directory) => {
95704
- const physicalDirectory = fs50.realpathSync(directory);
95904
+ const physicalDirectory = fs51.realpathSync(directory);
95705
95905
  if (!contained3(physicalRoot, physicalDirectory)) {
95706
95906
  throw migrationError2(`${directory} resolves outside bundle ${root.bundleId}.`);
95707
95907
  }
95708
- for (const entry of fs50.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95709
- const candidate = path62.join(directory, entry.name);
95908
+ for (const entry of fs51.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95909
+ const candidate = path63.join(directory, entry.name);
95710
95910
  if (entry.isSymbolicLink())
95711
95911
  throw migrationError2(`task migration does not follow symbolic link ${candidate}.`);
95712
95912
  if (entry.isDirectory()) {
@@ -95716,7 +95916,7 @@ function walkTasks2(root, tasksDir, out) {
95716
95916
  if (!entry.isFile() || !entry.name.endsWith(".yml"))
95717
95917
  continue;
95718
95918
  const current = snapshot2(candidate);
95719
- const parent = path62.dirname(candidate);
95919
+ const parent = path63.dirname(candidate);
95720
95920
  out.push({
95721
95921
  filePath: candidate,
95722
95922
  bytes: current.bytes,
@@ -95732,9 +95932,9 @@ function walkTasks2(root, tasksDir, out) {
95732
95932
  function inspectTaskToV4Files(roots) {
95733
95933
  const files = [];
95734
95934
  for (const root of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
95735
- const tasksDir = root.layout === "akm-task" ? root.root : path62.join(root.root, "tasks");
95935
+ const tasksDir = root.layout === "akm-task" ? root.root : path63.join(root.root, "tasks");
95736
95936
  try {
95737
- const stat = fs50.lstatSync(tasksDir);
95937
+ const stat = fs51.lstatSync(tasksDir);
95738
95938
  if (stat.isSymbolicLink())
95739
95939
  throw migrationError2(`task migration does not follow symbolic link ${tasksDir}.`);
95740
95940
  if (!stat.isDirectory())
@@ -95749,33 +95949,33 @@ function inspectTaskToV4Files(roots) {
95749
95949
  return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
95750
95950
  }
95751
95951
  function hashPath2(filePath) {
95752
- return crypto7.createHash("sha256").update(path62.resolve(filePath)).digest("hex").slice(0, 16);
95952
+ return crypto7.createHash("sha256").update(path63.resolve(filePath)).digest("hex").slice(0, 16);
95753
95953
  }
95754
95954
  function taskMigrationBackupPathV4(backupRoot, filePath) {
95755
- return path62.join(backupRoot, "files", `${hashPath2(filePath)}-${path62.basename(filePath)}`);
95955
+ return path63.join(backupRoot, "files", `${hashPath2(filePath)}-${path63.basename(filePath)}`);
95756
95956
  }
95757
95957
  function writeDurable2(filePath, bytes, mode, exclusive = false) {
95758
- fs50.mkdirSync(path62.dirname(filePath), { recursive: true });
95958
+ fs51.mkdirSync(path63.dirname(filePath), { recursive: true });
95759
95959
  const flags = exclusive ? "wx" : "w";
95760
- const fd = fs50.openSync(filePath, flags, mode);
95960
+ const fd = fs51.openSync(filePath, flags, mode);
95761
95961
  try {
95762
- fs50.writeFileSync(fd, bytes);
95763
- fs50.fsyncSync(fd);
95962
+ fs51.writeFileSync(fd, bytes);
95963
+ fs51.fsyncSync(fd);
95764
95964
  } finally {
95765
- fs50.closeSync(fd);
95965
+ fs51.closeSync(fd);
95766
95966
  }
95767
- fs50.chmodSync(filePath, mode);
95768
- fsyncDirectoryPortable(path62.dirname(filePath));
95967
+ fs51.chmodSync(filePath, mode);
95968
+ fsyncDirectoryPortable(path63.dirname(filePath));
95769
95969
  }
95770
95970
  function replaceAtomically2(filePath, bytes, mode) {
95771
- const temporary = path62.join(path62.dirname(filePath), `.${path62.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
95971
+ const temporary = path63.join(path63.dirname(filePath), `.${path63.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
95772
95972
  try {
95773
95973
  writeDurable2(temporary, bytes, mode, true);
95774
- fs50.renameSync(temporary, filePath);
95775
- fsyncDirectoryPortable(path62.dirname(filePath));
95974
+ fs51.renameSync(temporary, filePath);
95975
+ fsyncDirectoryPortable(path63.dirname(filePath));
95776
95976
  } finally {
95777
95977
  try {
95778
- fs50.unlinkSync(temporary);
95978
+ fs51.unlinkSync(temporary);
95779
95979
  } catch (cause) {
95780
95980
  if (cause.code !== "ENOENT")
95781
95981
  throw cause;
@@ -95814,7 +96014,7 @@ function applyTaskToV4MigrationPlan(plan, options) {
95814
96014
  const current = snapshot2(change.filePath);
95815
96015
  if (!current.bytes.equals(change.after))
95816
96016
  continue;
95817
- replaceAtomically2(change.filePath, fs50.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
96017
+ replaceAtomically2(change.filePath, fs51.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
95818
96018
  }
95819
96019
  throw cause;
95820
96020
  }
@@ -95826,12 +96026,12 @@ function expandTilde(value) {
95826
96026
  if (value === "~")
95827
96027
  return os5.homedir();
95828
96028
  if (value.startsWith("~/") || value.startsWith("~\\"))
95829
- return path63.join(os5.homedir(), value.slice(2));
96029
+ return path64.join(os5.homedir(), value.slice(2));
95830
96030
  return value;
95831
96031
  }
95832
96032
  function existingDirectory(target) {
95833
96033
  try {
95834
- return fs51.statSync(target).isDirectory();
96034
+ return fs53.statSync(target).isDirectory();
95835
96035
  } catch (cause) {
95836
96036
  if (cause.code === "ENOENT")
95837
96037
  return false;
@@ -95852,21 +96052,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
95852
96052
  const source = sources.get(bundleId);
95853
96053
  if (!source)
95854
96054
  continue;
95855
- const configuredRoot = source.type === "filesystem" && source.path ? path63.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
96055
+ const configuredRoot = source.type === "filesystem" && source.path ? path64.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
95856
96056
  if (!configuredRoot || !existingDirectory(configuredRoot))
95857
96057
  continue;
95858
- const bundleRoot = path63.resolve(configuredRoot);
96058
+ const bundleRoot = path64.resolve(configuredRoot);
95859
96059
  const component = bundleComponentConfig(bundle);
95860
- const componentRoot = path63.resolve(bundleRoot, component?.root ?? ".");
95861
- const relative = path63.relative(bundleRoot, componentRoot);
95862
- if (relative === ".." || relative.startsWith(`..${path63.sep}`) || path63.isAbsolute(relative)) {
96060
+ const componentRoot = path64.resolve(bundleRoot, component?.root ?? ".");
96061
+ const relative = path64.relative(bundleRoot, componentRoot);
96062
+ if (relative === ".." || relative.startsWith(`..${path64.sep}`) || path64.isAbsolute(relative)) {
95863
96063
  throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
95864
96064
  }
95865
96065
  if (!existingDirectory(componentRoot))
95866
96066
  continue;
95867
96067
  const adapter = component?.adapter ?? detectAdapterId(componentRoot, "");
95868
96068
  if (!component?.adapter && adapter === "") {
95869
- const flatTasks = fs51.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
96069
+ const flatTasks = fs53.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
95870
96070
  if (flatTasks.length > 0) {
95871
96071
  throw new ConfigError(`Task migration cannot classify top-level task file(s) ${flatTasks.join(", ")} in bundle ${bundleId}; configure adapter "akm-task" or move them under tasks/.`, "INVALID_CONFIG_FILE");
95872
96072
  }
@@ -95938,8 +96138,8 @@ function applyTaskV3Migration() {
95938
96138
  const before = inspectCurrentTaskPlan();
95939
96139
  if (before.result.taskV3Migration.changed === 0)
95940
96140
  return before.result;
95941
- const backupRoot = path63.join(getDataDir(), "backups", "task-v3");
95942
- const backupPath = path63.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96141
+ const backupRoot = path64.join(getDataDir(), "backups", "task-v3");
96142
+ const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
95943
96143
  const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
95944
96144
  const after = inspectCurrentTaskPlan().result;
95945
96145
  if (after.taskV3Migration.changed > 0) {
@@ -95995,8 +96195,8 @@ function applyTaskV4Migration() {
95995
96195
  const before = inspectCurrentTaskV4Plan();
95996
96196
  if (before.result.taskV4Migration.changed === 0)
95997
96197
  return before.result;
95998
- const backupRoot = path63.join(getDataDir(), "backups", "task-v4");
95999
- const backupPath = path63.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96198
+ const backupRoot = path64.join(getDataDir(), "backups", "task-v4");
96199
+ const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96000
96200
  const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
96001
96201
  const after = inspectCurrentTaskV4Plan().result;
96002
96202
  if (after.taskV4Migration.changed > 0) {
@@ -96024,6 +96224,22 @@ function stashDirIfConfigured() {
96024
96224
  throw error2;
96025
96225
  }
96026
96226
  }
96227
+ function writerRelocationTargets(defaultStashDir) {
96228
+ const config = loadConfig();
96229
+ const seen = new Set;
96230
+ const targets = [];
96231
+ if (defaultStashDir !== undefined) {
96232
+ targets.push({ id: bundleKeyForContentRoot(config, defaultStashDir) ?? "default", dir: defaultStashDir });
96233
+ seen.add(defaultStashDir);
96234
+ }
96235
+ for (const { id, contentRoot } of bundleContentRoots(config)) {
96236
+ if (seen.has(contentRoot))
96237
+ continue;
96238
+ seen.add(contentRoot);
96239
+ targets.push({ id, dir: contentRoot });
96240
+ }
96241
+ return targets;
96242
+ }
96027
96243
  async function runMigration(options) {
96028
96244
  const { apply } = options;
96029
96245
  const configPath = getConfigPath();
@@ -96044,10 +96260,15 @@ async function runMigration(options) {
96044
96260
  const stashDir = stashDirIfConfigured();
96045
96261
  const taskV3 = apply ? applyTaskV3Migration() : inspectMigrationPlan();
96046
96262
  const taskV4 = apply ? applyTaskV4Migration() : inspectTaskV4MigrationStatus();
96047
- const stashSections = stashDir === undefined ? {} : {
96048
- deadResidue: apply ? { removed: removeDeadResidue(stashDir) } : { pending: findDeadResidueEntries(stashDir) },
96049
- staleTxns: apply ? { recovered: await recoverStaleTxns(stashDir) } : { pending: findStaleTxnEntries(stashDir) }
96050
- };
96263
+ const stashSections = {};
96264
+ if (stashDir !== undefined) {
96265
+ stashSections.deadResidue = apply ? { removed: removeDeadResidue(stashDir) } : { pending: findDeadResidueEntries(stashDir) };
96266
+ stashSections.staleTxns = apply ? { recovered: await recoverStaleTxns(stashDir) } : { pending: findStaleTxnEntries(stashDir) };
96267
+ }
96268
+ const relocationTargets = writerRelocationTargets(stashDir);
96269
+ if (relocationTargets.length > 0) {
96270
+ stashSections.writerRelocation = apply ? { relocated: Object.fromEntries(relocationTargets.map(({ id, dir }) => [id, applyWriterRelocation(dir)])) } : { pending: Object.fromEntries(relocationTargets.map(({ id, dir }) => [id, findWriterRelocationEntries(dir)])) };
96271
+ }
96051
96272
  const stateStatus = "pending" in stateMigrations && stateMigrations.pending.length > 0 ? "ready" : "current";
96052
96273
  return {
96053
96274
  schemaVersion: 1,