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
@@ -7123,6 +7123,136 @@ var init_errors = __esm(() => {
7123
7123
  };
7124
7124
  });
7125
7125
 
7126
+ // src/core/asset/asset-ref.ts
7127
+ import path from "path";
7128
+ function validateName(name) {
7129
+ if (!name)
7130
+ throw new UsageError("Empty asset name.", "MISSING_REQUIRED_ARGUMENT");
7131
+ if (name.includes("\x00"))
7132
+ throw new UsageError("Null byte in asset name.", "MISSING_REQUIRED_ARGUMENT");
7133
+ if (/^[A-Za-z]:/.test(name))
7134
+ throw new UsageError("Windows drive path in asset name.", "MISSING_REQUIRED_ARGUMENT");
7135
+ const slashName = name.replace(/\\/g, "/");
7136
+ if (slashName === ".." || slashName.startsWith("../")) {
7137
+ throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
7138
+ }
7139
+ if (slashName.split("/").some((seg) => seg === "." || seg === "..")) {
7140
+ throw new UsageError("Asset name cannot contain relative path segments.", "MISSING_REQUIRED_ARGUMENT");
7141
+ }
7142
+ const normalized = path.posix.normalize(slashName);
7143
+ if (path.posix.isAbsolute(normalized))
7144
+ throw new UsageError("Absolute path in asset name.", "MISSING_REQUIRED_ARGUMENT");
7145
+ if (normalized === ".." || normalized.startsWith("../")) {
7146
+ throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
7147
+ }
7148
+ }
7149
+ function normalizeName(name) {
7150
+ return path.posix.normalize(name.replace(/\\/g, "/"));
7151
+ }
7152
+ function isBundleSlug(s) {
7153
+ return BUNDLE_SLUG_RE.test(s);
7154
+ }
7155
+ function normalizeConceptId(raw) {
7156
+ const nfc = raw.normalize("NFC");
7157
+ if (nfc.includes("#")) {
7158
+ throw new UsageError("`#` is reserved for the export fragment in a concept id.", "MISSING_REQUIRED_ARGUMENT");
7159
+ }
7160
+ validateName(nfc);
7161
+ return normalizeName(nfc);
7162
+ }
7163
+ function makeBundleRef(bundle, conceptId, fragment) {
7164
+ const normalized = normalizeConceptId(conceptId);
7165
+ let out = normalized;
7166
+ if (bundle) {
7167
+ if (!BUNDLE_SLUG_RE.test(bundle)) {
7168
+ throw new UsageError(`Invalid bundle slug "${bundle}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
7169
+ }
7170
+ out = `${bundle}//${normalized}`;
7171
+ }
7172
+ if (fragment)
7173
+ out = `${out}#${fragment}`;
7174
+ return out;
7175
+ }
7176
+ function bundleRefToString(ref) {
7177
+ return makeBundleRef(ref.bundle, ref.conceptId, ref.fragment);
7178
+ }
7179
+ function parseBundleRef(ref) {
7180
+ const trimmed = ref.trim();
7181
+ if (!trimmed)
7182
+ throw new UsageError("Empty ref.", "MISSING_REQUIRED_ARGUMENT");
7183
+ let bundle;
7184
+ let body = trimmed;
7185
+ const boundary = trimmed.indexOf("//");
7186
+ if (boundary >= 0) {
7187
+ bundle = trimmed.slice(0, boundary);
7188
+ body = trimmed.slice(boundary + 2);
7189
+ if (!bundle)
7190
+ throw new UsageError("Empty bundle in ref.", "MISSING_REQUIRED_ARGUMENT");
7191
+ if (!BUNDLE_SLUG_RE.test(bundle)) {
7192
+ throw new UsageError(`Invalid bundle slug "${bundle}" in ref "${trimmed}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
7193
+ }
7194
+ }
7195
+ let fragment;
7196
+ const hash = body.indexOf("#");
7197
+ if (hash >= 0) {
7198
+ fragment = body.slice(hash + 1) || undefined;
7199
+ body = body.slice(0, hash);
7200
+ }
7201
+ if (!body) {
7202
+ throw new UsageError(`Invalid ref "${trimmed}". Expected [bundle//]conceptId, e.g. knowledge/guide or core//skills/review`, "MISSING_REQUIRED_ARGUMENT");
7203
+ }
7204
+ const conceptId = normalizeConceptId(body);
7205
+ return { bundle: bundle || undefined, conceptId, fragment };
7206
+ }
7207
+ var BUNDLE_SLUG_RE;
7208
+ var init_asset_ref = __esm(() => {
7209
+ init_errors();
7210
+ BUNDLE_SLUG_RE = /^[^\s:.#/]+$/;
7211
+ });
7212
+
7213
+ // src/core/bundle-id.ts
7214
+ import crypto2 from "crypto";
7215
+ import path2 from "path";
7216
+ function slugForPath(sourcePath) {
7217
+ const resolved = path2.resolve(sourcePath);
7218
+ const base = path2.basename(resolved).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
7219
+ if (base.length > 0)
7220
+ return base;
7221
+ return `bundle-${shortHash(resolved)}`;
7222
+ }
7223
+ function deriveBundleId(registryId, sourcePath, usedIds) {
7224
+ const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
7225
+ const id = ensureUniqueId(preferred, sourcePath, usedIds);
7226
+ usedIds.add(id);
7227
+ return id;
7228
+ }
7229
+ function deriveBundleIds(sources) {
7230
+ const usedIds = new Set;
7231
+ const reservedIds = new Set(sources.flatMap((source) => source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : []));
7232
+ return sources.map((source) => {
7233
+ const id = source.registryId && isBundleSlug(source.registryId) ? deriveBundleId(source.registryId, source.path, usedIds) : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
7234
+ usedIds.add(id);
7235
+ return id;
7236
+ });
7237
+ }
7238
+ function ensureUniqueId(preferred, sourcePath, used) {
7239
+ if (!used.has(preferred))
7240
+ return preferred;
7241
+ const suffixed = `${preferred}-${shortHash(path2.resolve(sourcePath))}`;
7242
+ if (!used.has(suffixed))
7243
+ return suffixed;
7244
+ let n = 2;
7245
+ while (used.has(`${suffixed}-${n}`))
7246
+ n++;
7247
+ return `${suffixed}-${n}`;
7248
+ }
7249
+ function shortHash(input) {
7250
+ return crypto2.createHash("sha256").update(input).digest("hex").slice(0, 8);
7251
+ }
7252
+ var init_bundle_id = __esm(() => {
7253
+ init_asset_ref();
7254
+ });
7255
+
7126
7256
  // src/core/platform.ts
7127
7257
  var IS_WINDOWS;
7128
7258
  var init_platform = __esm(() => {
@@ -7131,7 +7261,7 @@ var init_platform = __esm(() => {
7131
7261
 
7132
7262
  // src/core/paths.ts
7133
7263
  import os from "os";
7134
- import path from "path";
7264
+ import path3 from "path";
7135
7265
  function isUnderBunTest(env) {
7136
7266
  return env.BUN_TEST === "1" || env.NODE_ENV === "test";
7137
7267
  }
@@ -7148,37 +7278,37 @@ function getConfigDir(env = process.env, platform = process.platform) {
7148
7278
  if (platform === "win32") {
7149
7279
  const appData = env.APPDATA?.trim();
7150
7280
  if (appData)
7151
- return path.join(appData, "akm");
7281
+ return path3.join(appData, "akm");
7152
7282
  } else {
7153
7283
  const xdgConfigHome2 = env.XDG_CONFIG_HOME?.trim();
7154
7284
  if (xdgConfigHome2)
7155
- return path.join(xdgConfigHome2, "akm");
7285
+ return path3.join(xdgConfigHome2, "akm");
7156
7286
  }
7157
7287
  const stashOverride = env.AKM_BUNDLE_DIR?.trim();
7158
7288
  if (stashOverride && isTransientStashPath(stashOverride)) {
7159
- return path.join(stashOverride, ".akm");
7289
+ return path3.join(stashOverride, ".akm");
7160
7290
  }
7161
7291
  if (platform === "win32") {
7162
7292
  const appData = env.APPDATA?.trim();
7163
7293
  if (appData)
7164
- return path.join(appData, "akm");
7294
+ return path3.join(appData, "akm");
7165
7295
  const userProfile = env.USERPROFILE?.trim();
7166
7296
  if (!userProfile) {
7167
7297
  throw new ConfigError("Unable to determine config directory. Set APPDATA or USERPROFILE.", "CONFIG_DIR_UNRESOLVABLE");
7168
7298
  }
7169
- return path.join(userProfile, "AppData", "Roaming", "akm");
7299
+ return path3.join(userProfile, "AppData", "Roaming", "akm");
7170
7300
  }
7171
7301
  const xdgConfigHome = env.XDG_CONFIG_HOME?.trim();
7172
7302
  if (xdgConfigHome)
7173
- return path.join(xdgConfigHome, "akm");
7303
+ return path3.join(xdgConfigHome, "akm");
7174
7304
  const home = env.HOME?.trim();
7175
7305
  if (!home) {
7176
7306
  throw new ConfigError("Unable to determine config directory. Set XDG_CONFIG_HOME or HOME.", "CONFIG_DIR_UNRESOLVABLE");
7177
7307
  }
7178
- return path.join(home, ".config", "akm");
7308
+ return path3.join(home, ".config", "akm");
7179
7309
  }
7180
7310
  function getConfigPath(env = process.env) {
7181
- return path.join(getConfigDir(env), "config.json");
7311
+ return path3.join(getConfigDir(env), "config.json");
7182
7312
  }
7183
7313
  function getCacheDir(env = process.env) {
7184
7314
  const override = env.AKM_CACHE_DIR?.trim();
@@ -7187,22 +7317,22 @@ function getCacheDir(env = process.env) {
7187
7317
  if (IS_WINDOWS) {
7188
7318
  const localAppData = env.LOCALAPPDATA?.trim();
7189
7319
  if (localAppData)
7190
- return path.join(localAppData, "akm");
7320
+ return path3.join(localAppData, "akm");
7191
7321
  const userProfile = env.USERPROFILE?.trim();
7192
7322
  if (userProfile)
7193
- return path.join(userProfile, "AppData", "Local", "akm");
7323
+ return path3.join(userProfile, "AppData", "Local", "akm");
7194
7324
  const appData = env.APPDATA?.trim();
7195
7325
  if (appData) {
7196
- return path.join(appData, "..", "Local", "akm");
7326
+ return path3.join(appData, "..", "Local", "akm");
7197
7327
  }
7198
7328
  } else {
7199
7329
  const xdgCacheHome = env.XDG_CACHE_HOME?.trim();
7200
7330
  if (xdgCacheHome)
7201
- return path.join(xdgCacheHome, "akm");
7331
+ return path3.join(xdgCacheHome, "akm");
7202
7332
  }
7203
7333
  const stashOverride = env.AKM_BUNDLE_DIR?.trim();
7204
7334
  if (stashOverride && isTransientStashPath(stashOverride)) {
7205
- return path.join(stashOverride, ".akm", "cache");
7335
+ return path3.join(stashOverride, ".akm", "cache");
7206
7336
  }
7207
7337
  if (IS_WINDOWS) {
7208
7338
  throw new ConfigError("Unable to determine cache directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
@@ -7210,11 +7340,11 @@ function getCacheDir(env = process.env) {
7210
7340
  const home = env.HOME?.trim();
7211
7341
  if (!home)
7212
7342
  return homelessFallbackDir("akm-cache");
7213
- return path.join(home, ".cache", "akm");
7343
+ return path3.join(home, ".cache", "akm");
7214
7344
  }
7215
7345
  function homelessFallbackDir(kind) {
7216
7346
  const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
7217
- return path.join(os.tmpdir(), uid === undefined ? kind : `${kind}-${uid}`);
7347
+ return path3.join(os.tmpdir(), uid === undefined ? kind : `${kind}-${uid}`);
7218
7348
  }
7219
7349
  function getDataDir(env = process.env, platform = process.platform) {
7220
7350
  const override = env.AKM_DATA_DIR?.trim();
@@ -7226,38 +7356,83 @@ function getDataDir(env = process.env, platform = process.platform) {
7226
7356
  if (platform === "win32") {
7227
7357
  const localAppData = env.LOCALAPPDATA?.trim();
7228
7358
  if (localAppData)
7229
- return path.join(localAppData, "akm", "data");
7359
+ return path3.join(localAppData, "akm", "data");
7230
7360
  const userProfile = env.USERPROFILE?.trim();
7231
7361
  if (userProfile)
7232
- return path.join(userProfile, "AppData", "Local", "akm", "data");
7362
+ return path3.join(userProfile, "AppData", "Local", "akm", "data");
7233
7363
  const appData = env.APPDATA?.trim();
7234
7364
  if (!appData) {
7235
7365
  throw new ConfigError("Unable to determine data directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
7236
7366
  }
7237
- return path.join(appData, "..", "Local", "akm", "data");
7367
+ return path3.join(appData, "..", "Local", "akm", "data");
7238
7368
  }
7239
7369
  const xdgDataHome = env.XDG_DATA_HOME?.trim();
7240
7370
  if (xdgDataHome)
7241
- return path.join(xdgDataHome, "akm");
7371
+ return path3.join(xdgDataHome, "akm");
7242
7372
  const home = env.HOME?.trim();
7243
7373
  if (!home)
7244
7374
  return homelessFallbackDir("akm-data");
7245
- return path.join(home, ".local", "share", "akm");
7375
+ return path3.join(home, ".local", "share", "akm");
7246
7376
  }
7247
7377
  function getDbPath(env = process.env) {
7248
- return path.join(getDataDir(env), "index.db");
7378
+ return path3.join(getDataDir(env), "index.db");
7249
7379
  }
7250
7380
  function getMaintenanceBarrierPath() {
7251
- return path.join(getDataDir(), "maintenance.barrier.lock");
7381
+ return path3.join(getDataDir(), "maintenance.barrier.lock");
7252
7382
  }
7253
7383
  function getLockfilePath() {
7254
- return path.join(getDataDir(), "akm.lock");
7384
+ return path3.join(getDataDir(), "akm.lock");
7255
7385
  }
7256
7386
  function getRegistryCacheDir() {
7257
- return path.join(getCacheDir(), "registry");
7387
+ return path3.join(getCacheDir(), "registry");
7258
7388
  }
7259
7389
  function getRegistryIndexCacheDir() {
7260
- return path.join(getCacheDir(), "registry-index");
7390
+ return path3.join(getCacheDir(), "registry-index");
7391
+ }
7392
+ function getStateDir(env = process.env, platform = process.platform) {
7393
+ const override = env.AKM_STATE_DIR?.trim();
7394
+ if (override)
7395
+ return override;
7396
+ if (platform === "win32") {
7397
+ const localAppData = env.LOCALAPPDATA?.trim();
7398
+ if (localAppData)
7399
+ return path3.join(localAppData, "akm", "state");
7400
+ const userProfile = env.USERPROFILE?.trim();
7401
+ if (userProfile)
7402
+ return path3.join(userProfile, "AppData", "Local", "akm", "state");
7403
+ const appData = env.APPDATA?.trim();
7404
+ if (!appData) {
7405
+ throw new ConfigError("Unable to determine state directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
7406
+ }
7407
+ return path3.join(appData, "..", "Local", "akm", "state");
7408
+ }
7409
+ const xdgStateHome = env.XDG_STATE_HOME?.trim();
7410
+ if (xdgStateHome)
7411
+ return path3.join(xdgStateHome, "akm");
7412
+ const home = env.HOME?.trim();
7413
+ if (!home)
7414
+ return homelessFallbackDir("akm-state");
7415
+ return path3.join(home, ".local", "state", "akm");
7416
+ }
7417
+ function getStashStateKey(stashDir) {
7418
+ const resolved = path3.resolve(stashDir).replace(/\\/g, "/");
7419
+ const normalized = IS_WINDOWS ? resolved.toLowerCase() : resolved;
7420
+ return shortHash(normalized);
7421
+ }
7422
+ function stashScopedDir(base, stashDir) {
7423
+ return path3.join(base, getStashStateKey(stashDir));
7424
+ }
7425
+ function getDistillRejectedDir(stashDir) {
7426
+ return stashScopedDir(path3.join(getStateDir(), "improve", "distill-rejected"), stashDir);
7427
+ }
7428
+ function getEvalCasesDir(stashDir) {
7429
+ return stashScopedDir(path3.join(getStateDir(), "improve", "eval-cases"), stashDir);
7430
+ }
7431
+ function getMeasurementVerdictsDir(stashDir) {
7432
+ return stashScopedDir(path3.join(getStateDir(), "improve", "measurement", "verdicts"), stashDir);
7433
+ }
7434
+ function getUnresolvedSourcesDir(stashDir) {
7435
+ return stashScopedDir(path3.join(getCacheDir(), "index", "unresolved-sources"), stashDir);
7261
7436
  }
7262
7437
  function getDefaultStashDir(env = process.env) {
7263
7438
  const override = env.AKM_BUNDLE_DIR?.trim();
@@ -7266,24 +7441,25 @@ function getDefaultStashDir(env = process.env) {
7266
7441
  if (IS_WINDOWS) {
7267
7442
  const userProfile = env.USERPROFILE?.trim();
7268
7443
  if (userProfile)
7269
- return path.join(userProfile, "Documents", "akm");
7270
- return path.join("C:\\", "akm");
7444
+ return path3.join(userProfile, "Documents", "akm");
7445
+ return path3.join("C:\\", "akm");
7271
7446
  }
7272
7447
  const home = env.HOME?.trim();
7273
7448
  if (!home) {
7274
7449
  throw new ConfigError("Unable to determine default bundle directory. Set HOME.", "STASH_DIR_NOT_FOUND");
7275
7450
  }
7276
- return path.join(home, "akm");
7451
+ return path3.join(home, "akm");
7277
7452
  }
7278
7453
  var init_paths = __esm(() => {
7454
+ init_bundle_id();
7279
7455
  init_errors();
7280
7456
  init_platform();
7281
7457
  });
7282
7458
 
7283
7459
  // src/core/common.ts
7284
- import crypto2 from "crypto";
7460
+ import crypto3 from "crypto";
7285
7461
  import fs from "fs";
7286
- import path2 from "path";
7462
+ import path4 from "path";
7287
7463
  function isHttpUrl(value) {
7288
7464
  return !!value && /^https?:\/\//.test(value);
7289
7465
  }
@@ -7361,7 +7537,7 @@ function stripJsonComments(text) {
7361
7537
  return result;
7362
7538
  }
7363
7539
  function writeFileAtomic(target, content, mode) {
7364
- const tmp = `${target}.tmp.${process.pid}.${crypto2.randomBytes(8).toString("hex")}`;
7540
+ const tmp = `${target}.tmp.${process.pid}.${crypto3.randomBytes(8).toString("hex")}`;
7365
7541
  const data = typeof content === "string" ? Buffer.from(content) : content;
7366
7542
  const fileMode = mode ?? 384;
7367
7543
  let fd;
@@ -7416,7 +7592,7 @@ function writeFileAtomic(target, content, mode) {
7416
7592
  if (process.platform !== "win32") {
7417
7593
  let dirFd;
7418
7594
  try {
7419
- dirFd = fs.openSync(path2.dirname(target), "r");
7595
+ dirFd = fs.openSync(path4.dirname(target), "r");
7420
7596
  } catch (error) {
7421
7597
  if (hasErrnoCode(error, "EINVAL") || hasErrnoCode(error, "ENOTSUP"))
7422
7598
  return;
@@ -7449,7 +7625,7 @@ function resolveStashDir(env = process.env) {
7449
7625
  throw new ConfigError(`No bundle directory found. Run "akm bundle create" to create one at ${defaultDir}.`, "STASH_DIR_NOT_FOUND");
7450
7626
  }
7451
7627
  function validateStashDir(raw) {
7452
- const stashDir = path2.resolve(raw);
7628
+ const stashDir = path4.resolve(raw);
7453
7629
  let stat;
7454
7630
  try {
7455
7631
  stat = fs.statSync(stashDir);
@@ -7495,8 +7671,8 @@ function readStashDirFromConfig() {
7495
7671
  const componentConfig = component;
7496
7672
  if (typeof componentConfig.root !== "string")
7497
7673
  return bundlePath;
7498
- const bundleRoot = path2.resolve(bundlePath);
7499
- const componentRoot = path2.resolve(bundleRoot, componentConfig.root);
7674
+ const bundleRoot = path4.resolve(bundlePath);
7675
+ const componentRoot = path4.resolve(bundleRoot, componentConfig.root);
7500
7676
  if (!isWithin(componentRoot, bundleRoot)) {
7501
7677
  throw new ConfigError(`Component root "${componentConfig.root}" escapes bundle "${defaultBundle}".`, "INVALID_CONFIG_FILE");
7502
7678
  }
@@ -7541,30 +7717,30 @@ function isAkmRegistryCachePath(filePath) {
7541
7717
  return isWithin(filePath, getRegistryCacheDir()) || isWithin(filePath, getRegistryIndexCacheDir());
7542
7718
  }
7543
7719
  function isContainedResolvedPath(resolvedCandidate, resolvedRoot) {
7544
- const rel = path2.relative(normalizeFsPathForComparison(resolvedRoot), normalizeFsPathForComparison(resolvedCandidate));
7720
+ const rel = path4.relative(normalizeFsPathForComparison(resolvedRoot), normalizeFsPathForComparison(resolvedCandidate));
7545
7721
  if (rel === "")
7546
7722
  return true;
7547
- if (path2.isAbsolute(rel))
7723
+ if (path4.isAbsolute(rel))
7548
7724
  return false;
7549
7725
  return rel.split(/[/\\]+/)[0] !== "..";
7550
7726
  }
7551
7727
  function safeRealpath(p) {
7552
- const resolved = path2.resolve(p);
7728
+ const resolved = path4.resolve(p);
7553
7729
  try {
7554
7730
  return fs.realpathSync(resolved);
7555
7731
  } catch {
7556
7732
  const suffix = [];
7557
7733
  let current = resolved;
7558
7734
  for (;; ) {
7559
- const parent = path2.dirname(current);
7735
+ const parent = path4.dirname(current);
7560
7736
  if (parent === current) {
7561
7737
  return resolved;
7562
7738
  }
7563
- suffix.unshift(path2.basename(current));
7739
+ suffix.unshift(path4.basename(current));
7564
7740
  current = parent;
7565
7741
  try {
7566
7742
  const realParent = fs.realpathSync(current);
7567
- return path2.join(realParent, ...suffix);
7743
+ return path4.join(realParent, ...suffix);
7568
7744
  } catch {}
7569
7745
  }
7570
7746
  }
@@ -7878,7 +8054,7 @@ var init_recognition_util = __esm(() => {
7878
8054
 
7879
8055
  // src/core/asset/asset-placement.ts
7880
8056
  import fs2 from "fs";
7881
- import path5 from "path";
8057
+ import path7 from "path";
7882
8058
  function placementSpecFor(type) {
7883
8059
  return PLACEMENT_SPECS[type];
7884
8060
  }
@@ -7902,10 +8078,10 @@ function deriveCanonicalAssetName(assetType, typeRoot, filePath) {
7902
8078
  return PLACEMENT_SPECS[assetType]?.toCanonicalName(typeRoot, filePath);
7903
8079
  }
7904
8080
  function deriveCanonicalAssetNameFromStashRoot(assetType, stashRoot, filePath) {
7905
- const relPath = toPosix(path5.relative(stashRoot, filePath));
8081
+ const relPath = toPosix(path7.relative(stashRoot, filePath));
7906
8082
  const segments = relPath.split("/").filter(Boolean);
7907
8083
  const firstSegment = segments[0];
7908
- const typeRoot = firstSegment !== undefined && firstSegment === stashDirFor(assetType) ? path5.join(stashRoot, firstSegment) : stashRoot;
8084
+ const typeRoot = firstSegment !== undefined && firstSegment === stashDirFor(assetType) ? path7.join(stashRoot, firstSegment) : stashRoot;
7909
8085
  return deriveCanonicalAssetName(assetType, typeRoot, filePath);
7910
8086
  }
7911
8087
  function assetPathForName(assetType, typeRoot, name) {
@@ -7924,8 +8100,8 @@ function assetPathCandidatesForName(assetType, typeRoot, name) {
7924
8100
  const base = name === "default" ? "" : name.endsWith("/default") ? name.slice(0, -"default".length) : undefined;
7925
8101
  if (base === undefined)
7926
8102
  return [primary];
7927
- const dotForm = path5.join(typeRoot, base, ".env");
7928
- const namedForm = path5.join(typeRoot, base, "default.env");
8103
+ const dotForm = path7.join(typeRoot, base, ".env");
8104
+ const namedForm = path7.join(typeRoot, base, "default.env");
7929
8105
  return [...new Set([primary, dotForm, namedForm])];
7930
8106
  }
7931
8107
  var workflowSpec, markdownSpec, scriptSpec, BUILTIN_PLACEMENT_SPECS, PLACEMENT_SPECS;
@@ -7933,9 +8109,9 @@ var init_asset_placement = __esm(() => {
7933
8109
  init_common();
7934
8110
  init_recognition_util();
7935
8111
  workflowSpec = {
7936
- isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path5.extname(fileName).toLowerCase()),
8112
+ isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path7.extname(fileName).toLowerCase()),
7937
8113
  toCanonicalName: (typeRoot, filePath) => {
7938
- const rel = toPosix(path5.relative(typeRoot, filePath));
8114
+ const rel = toPosix(path7.relative(typeRoot, filePath));
7939
8115
  for (const ext of WORKFLOW_EXTENSIONS) {
7940
8116
  if (rel.toLowerCase().endsWith(ext))
7941
8117
  return rel.slice(0, -ext.length);
@@ -7946,43 +8122,43 @@ var init_asset_placement = __esm(() => {
7946
8122
  const lower = name.toLowerCase();
7947
8123
  for (const ext of WORKFLOW_EXTENSIONS) {
7948
8124
  if (lower.endsWith(ext))
7949
- return path5.join(typeRoot, name);
8125
+ return path7.join(typeRoot, name);
7950
8126
  }
7951
8127
  for (const ext of WORKFLOW_EXTENSIONS) {
7952
- const candidate = path5.join(typeRoot, `${name}${ext}`);
8128
+ const candidate = path7.join(typeRoot, `${name}${ext}`);
7953
8129
  if (fs2.existsSync(candidate))
7954
8130
  return candidate;
7955
8131
  }
7956
- return path5.join(typeRoot, `${name}.md`);
8132
+ return path7.join(typeRoot, `${name}.md`);
7957
8133
  }
7958
8134
  };
7959
8135
  markdownSpec = {
7960
- isRelevantFile: (fileName) => path5.extname(fileName).toLowerCase() === ".md",
8136
+ isRelevantFile: (fileName) => path7.extname(fileName).toLowerCase() === ".md",
7961
8137
  toCanonicalName: (typeRoot, filePath) => {
7962
- const rel = toPosix(path5.relative(typeRoot, filePath));
8138
+ const rel = toPosix(path7.relative(typeRoot, filePath));
7963
8139
  return rel.endsWith(".md") ? rel.slice(0, -3) : rel;
7964
8140
  },
7965
8141
  toAssetPath: (typeRoot, name) => {
7966
8142
  const withExt = name.endsWith(".md") ? name : `${name}.md`;
7967
- return path5.join(typeRoot, withExt);
8143
+ return path7.join(typeRoot, withExt);
7968
8144
  }
7969
8145
  };
7970
8146
  scriptSpec = {
7971
- isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path5.extname(fileName).toLowerCase()),
7972
- toCanonicalName: (typeRoot, filePath) => toPosix(path5.relative(typeRoot, filePath)),
7973
- toAssetPath: (typeRoot, name) => path5.join(typeRoot, name)
8147
+ isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path7.extname(fileName).toLowerCase()),
8148
+ toCanonicalName: (typeRoot, filePath) => toPosix(path7.relative(typeRoot, filePath)),
8149
+ toAssetPath: (typeRoot, name) => path7.join(typeRoot, name)
7974
8150
  };
7975
8151
  BUILTIN_PLACEMENT_SPECS = {
7976
8152
  skill: {
7977
8153
  stashDir: "skills",
7978
8154
  isRelevantFile: (fileName) => fileName === "SKILL.md",
7979
8155
  toCanonicalName: (typeRoot, filePath) => {
7980
- const relDir = toPosix(path5.dirname(path5.relative(typeRoot, filePath)));
8156
+ const relDir = toPosix(path7.dirname(path7.relative(typeRoot, filePath)));
7981
8157
  if (!relDir || relDir === ".")
7982
8158
  return;
7983
8159
  return relDir;
7984
8160
  },
7985
- toAssetPath: (typeRoot, name) => path5.join(typeRoot, name, "SKILL.md")
8161
+ toAssetPath: (typeRoot, name) => path7.join(typeRoot, name, "SKILL.md")
7986
8162
  },
7987
8163
  command: { stashDir: "commands", ...markdownSpec },
7988
8164
  agent: { stashDir: "agents", ...markdownSpec },
@@ -7995,10 +8171,10 @@ var init_asset_placement = __esm(() => {
7995
8171
  stashDir: "env",
7996
8172
  isRelevantFile: (fileName) => fileName === ".env" || fileName.endsWith(".env"),
7997
8173
  toCanonicalName: (typeRoot, filePath) => {
7998
- const rel = toPosix(path5.relative(typeRoot, filePath));
7999
- const fileName = path5.basename(rel);
8174
+ const rel = toPosix(path7.relative(typeRoot, filePath));
8175
+ const fileName = path7.basename(rel);
8000
8176
  if (fileName === ".env") {
8001
- const dir = path5.dirname(rel);
8177
+ const dir = path7.dirname(rel);
8002
8178
  return dir === "." || dir === "" ? "default" : `${dir}/default`;
8003
8179
  }
8004
8180
  const stripped = rel.endsWith(".env") ? rel.slice(0, -4) : rel;
@@ -8006,27 +8182,27 @@ var init_asset_placement = __esm(() => {
8006
8182
  },
8007
8183
  toAssetPath: (typeRoot, name) => {
8008
8184
  if (name === "default")
8009
- return path5.join(typeRoot, ".env");
8010
- return path5.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8185
+ return path7.join(typeRoot, ".env");
8186
+ return path7.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8011
8187
  }
8012
8188
  },
8013
8189
  secret: {
8014
8190
  stashDir: "secrets",
8015
8191
  isRelevantFile: (fileName) => !fileName.endsWith(".lock") && !fileName.endsWith(".sensitive"),
8016
- toCanonicalName: (typeRoot, filePath) => toPosix(path5.relative(typeRoot, filePath)),
8017
- toAssetPath: (typeRoot, name) => path5.join(typeRoot, name)
8192
+ toCanonicalName: (typeRoot, filePath) => toPosix(path7.relative(typeRoot, filePath)),
8193
+ toAssetPath: (typeRoot, name) => path7.join(typeRoot, name)
8018
8194
  },
8019
8195
  lesson: { stashDir: "lessons", ...markdownSpec },
8020
8196
  task: {
8021
8197
  stashDir: "tasks",
8022
- isRelevantFile: (fileName) => path5.extname(fileName).toLowerCase() === ".yml",
8198
+ isRelevantFile: (fileName) => path7.extname(fileName).toLowerCase() === ".yml",
8023
8199
  toCanonicalName: (typeRoot, filePath) => {
8024
- const rel = toPosix(path5.relative(typeRoot, filePath));
8200
+ const rel = toPosix(path7.relative(typeRoot, filePath));
8025
8201
  return rel.toLowerCase().endsWith(".yml") ? rel.slice(0, -4) : rel;
8026
8202
  },
8027
8203
  toAssetPath: (typeRoot, name) => {
8028
8204
  const withExt = name.toLowerCase().endsWith(".yml") ? name : `${name}.yml`;
8029
- return path5.join(typeRoot, withExt);
8205
+ return path7.join(typeRoot, withExt);
8030
8206
  }
8031
8207
  },
8032
8208
  session: { stashDir: "sessions", ...markdownSpec },
@@ -8035,93 +8211,6 @@ var init_asset_placement = __esm(() => {
8035
8211
  PLACEMENT_SPECS = { ...BUILTIN_PLACEMENT_SPECS };
8036
8212
  });
8037
8213
 
8038
- // src/core/asset/asset-ref.ts
8039
- import path6 from "path";
8040
- function validateName(name) {
8041
- if (!name)
8042
- throw new UsageError("Empty asset name.", "MISSING_REQUIRED_ARGUMENT");
8043
- if (name.includes("\x00"))
8044
- throw new UsageError("Null byte in asset name.", "MISSING_REQUIRED_ARGUMENT");
8045
- if (/^[A-Za-z]:/.test(name))
8046
- throw new UsageError("Windows drive path in asset name.", "MISSING_REQUIRED_ARGUMENT");
8047
- const slashName = name.replace(/\\/g, "/");
8048
- if (slashName === ".." || slashName.startsWith("../")) {
8049
- throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
8050
- }
8051
- if (slashName.split("/").some((seg) => seg === "." || seg === "..")) {
8052
- throw new UsageError("Asset name cannot contain relative path segments.", "MISSING_REQUIRED_ARGUMENT");
8053
- }
8054
- const normalized = path6.posix.normalize(slashName);
8055
- if (path6.posix.isAbsolute(normalized))
8056
- throw new UsageError("Absolute path in asset name.", "MISSING_REQUIRED_ARGUMENT");
8057
- if (normalized === ".." || normalized.startsWith("../")) {
8058
- throw new UsageError("Path traversal in asset name.", "MISSING_REQUIRED_ARGUMENT");
8059
- }
8060
- }
8061
- function normalizeName(name) {
8062
- return path6.posix.normalize(name.replace(/\\/g, "/"));
8063
- }
8064
- function isBundleSlug(s) {
8065
- return BUNDLE_SLUG_RE.test(s);
8066
- }
8067
- function normalizeConceptId(raw) {
8068
- const nfc = raw.normalize("NFC");
8069
- if (nfc.includes("#")) {
8070
- throw new UsageError("`#` is reserved for the export fragment in a concept id.", "MISSING_REQUIRED_ARGUMENT");
8071
- }
8072
- validateName(nfc);
8073
- return normalizeName(nfc);
8074
- }
8075
- function makeBundleRef(bundle, conceptId, fragment) {
8076
- const normalized = normalizeConceptId(conceptId);
8077
- let out = normalized;
8078
- if (bundle) {
8079
- if (!BUNDLE_SLUG_RE.test(bundle)) {
8080
- throw new UsageError(`Invalid bundle slug "${bundle}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
8081
- }
8082
- out = `${bundle}//${normalized}`;
8083
- }
8084
- if (fragment)
8085
- out = `${out}#${fragment}`;
8086
- return out;
8087
- }
8088
- function bundleRefToString(ref) {
8089
- return makeBundleRef(ref.bundle, ref.conceptId, ref.fragment);
8090
- }
8091
- function parseBundleRef(ref) {
8092
- const trimmed = ref.trim();
8093
- if (!trimmed)
8094
- throw new UsageError("Empty ref.", "MISSING_REQUIRED_ARGUMENT");
8095
- let bundle;
8096
- let body = trimmed;
8097
- const boundary = trimmed.indexOf("//");
8098
- if (boundary >= 0) {
8099
- bundle = trimmed.slice(0, boundary);
8100
- body = trimmed.slice(boundary + 2);
8101
- if (!bundle)
8102
- throw new UsageError("Empty bundle in ref.", "MISSING_REQUIRED_ARGUMENT");
8103
- if (!BUNDLE_SLUG_RE.test(bundle)) {
8104
- throw new UsageError(`Invalid bundle slug "${bundle}" in ref "${trimmed}". A bundle slug may not contain ':', '.', '#', '/', or whitespace.`, "MISSING_REQUIRED_ARGUMENT");
8105
- }
8106
- }
8107
- let fragment;
8108
- const hash = body.indexOf("#");
8109
- if (hash >= 0) {
8110
- fragment = body.slice(hash + 1) || undefined;
8111
- body = body.slice(0, hash);
8112
- }
8113
- if (!body) {
8114
- throw new UsageError(`Invalid ref "${trimmed}". Expected [bundle//]conceptId, e.g. knowledge/guide or core//skills/review`, "MISSING_REQUIRED_ARGUMENT");
8115
- }
8116
- const conceptId = normalizeConceptId(body);
8117
- return { bundle: bundle || undefined, conceptId, fragment };
8118
- }
8119
- var BUNDLE_SLUG_RE;
8120
- var init_asset_ref = __esm(() => {
8121
- init_errors();
8122
- BUNDLE_SLUG_RE = /^[^\s:.#/]+$/;
8123
- });
8124
-
8125
8214
  // src/core/asset/resolve-ref.ts
8126
8215
  function conceptIdFromTypeName(type, name) {
8127
8216
  const stashDir = stashDirFor(type);
@@ -8185,13 +8274,13 @@ function validateExtraParams(value) {
8185
8274
  }
8186
8275
  const issues = [];
8187
8276
  const seen = new WeakSet;
8188
- const visit2 = (entry, path7) => {
8277
+ const visit2 = (entry, path8) => {
8189
8278
  if (Array.isArray(entry)) {
8190
8279
  if (seen.has(entry))
8191
8280
  return;
8192
8281
  seen.add(entry);
8193
8282
  entry.forEach((child, index) => {
8194
- visit2(child, [...path7, index]);
8283
+ visit2(child, [...path8, index]);
8195
8284
  });
8196
8285
  return;
8197
8286
  }
@@ -8202,7 +8291,7 @@ function validateExtraParams(value) {
8202
8291
  seen.add(entry);
8203
8292
  for (const [key, child] of Object.entries(entry)) {
8204
8293
  const normalized = normalizeExtraParamKey(key);
8205
- if (path7.length === 0 && PROTECTED_TOP_LEVEL_KEYS.has(normalized)) {
8294
+ if (path8.length === 0 && PROTECTED_TOP_LEVEL_KEYS.has(normalized)) {
8206
8295
  const remedy = protectedKeyRemedy(normalized);
8207
8296
  issues.push({
8208
8297
  path: [key],
@@ -8210,9 +8299,9 @@ function validateExtraParams(value) {
8210
8299
  });
8211
8300
  }
8212
8301
  if (CREDENTIAL_KEYS.has(normalized)) {
8213
- issues.push({ path: [...path7, key], message: `${key} cannot carry credentials` });
8302
+ issues.push({ path: [...path8, key], message: `${key} cannot carry credentials` });
8214
8303
  }
8215
- visit2(child, [...path7, key]);
8304
+ visit2(child, [...path8, key]);
8216
8305
  }
8217
8306
  };
8218
8307
  visit2(value, []);
@@ -8405,13 +8494,13 @@ var init_warn = __esm(() => {
8405
8494
  });
8406
8495
 
8407
8496
  // src/core/write-provenance.ts
8408
- import path15 from "path";
8497
+ import path16 from "path";
8409
8498
  function recordWrittenPath(filePath) {
8410
8499
  if (activeJournals.size === 0 || !filePath)
8411
8500
  return;
8412
8501
  let absolute;
8413
8502
  try {
8414
- absolute = path15.resolve(filePath);
8503
+ absolute = path16.resolve(filePath);
8415
8504
  } catch {
8416
8505
  return;
8417
8506
  }
@@ -8519,7 +8608,7 @@ var init_frontmatter = __esm(() => {
8519
8608
 
8520
8609
  // src/indexer/passes/metadata.ts
8521
8610
  import fs13 from "fs";
8522
- import path17 from "path";
8611
+ import path18 from "path";
8523
8612
  function normalizeQuality(raw) {
8524
8613
  if (KNOWN_QUALITY_VALUES.has(raw))
8525
8614
  return raw;
@@ -9279,7 +9368,7 @@ function projectMarkdownContent(body, truncationInfo) {
9279
9368
  return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
9280
9369
  }
9281
9370
  function applyPreContributorFields(entry, file, ctx, pkgMeta) {
9282
- const ext = path17.extname(file).toLowerCase();
9371
+ const ext = path18.extname(file).toLowerCase();
9283
9372
  if (pkgMeta) {
9284
9373
  if (pkgMeta.description && !entry.description) {
9285
9374
  entry.description = pkgMeta.description;
@@ -9325,8 +9414,8 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
9325
9414
  }
9326
9415
  }
9327
9416
  function applyPostContributorFields(entry, file, canonicalName, dirPath) {
9328
- const ext = path17.extname(file).toLowerCase();
9329
- const baseName = path17.basename(file, ext);
9417
+ const ext = path18.extname(file).toLowerCase();
9418
+ const baseName = path18.basename(file, ext);
9330
9419
  if (!entry.description) {
9331
9420
  entry.description = fileNameToDescription(baseName);
9332
9421
  entry.source = "filename";
@@ -9338,7 +9427,7 @@ function applyPostContributorFields(entry, file, canonicalName, dirPath) {
9338
9427
  entry.tags = [...entry.tags ?? [], ...extractDirTagsFromName(canonicalName)];
9339
9428
  entry.tags = normalizeTerms(entry.tags ?? []);
9340
9429
  entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, entry.tags));
9341
- entry.filename = path17.basename(file);
9430
+ entry.filename = path18.basename(file);
9342
9431
  }
9343
9432
  function buildMetadataSkipWarning(filePath, assetType, error) {
9344
9433
  const detail = error instanceof Error ? error.message : String(error);
@@ -9370,7 +9459,7 @@ function buildAliases(name, tags) {
9370
9459
  return Array.from(aliases);
9371
9460
  }
9372
9461
  function extractPackageMetadata(dirPath) {
9373
- const pkgPath = path17.join(dirPath, "package.json");
9462
+ const pkgPath = path18.join(dirPath, "package.json");
9374
9463
  if (!fs13.existsSync(pkgPath))
9375
9464
  return null;
9376
9465
  try {
@@ -9392,11 +9481,11 @@ function fileNameToDescription(fileName) {
9392
9481
  return fileName.replace(/[-_]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().trim();
9393
9482
  }
9394
9483
  function extractTagsFromPath(filePath, rootDir) {
9395
- const rel = path17.relative(rootDir, filePath);
9396
- const parts = rel.split(path17.sep);
9484
+ const rel = path18.relative(rootDir, filePath);
9485
+ const parts = rel.split(path18.sep);
9397
9486
  const tags = new Set;
9398
9487
  for (const part of parts) {
9399
- const name = part.replace(path17.extname(part), "");
9488
+ const name = part.replace(path18.extname(part), "");
9400
9489
  for (const token of name.split(/[-_./\\]+/)) {
9401
9490
  const clean = token.toLowerCase().trim();
9402
9491
  if (clean && clean.length > 1)
@@ -9428,27 +9517,27 @@ var init_metadata = __esm(() => {
9428
9517
  });
9429
9518
 
9430
9519
  // src/execution/record.ts
9431
- function snapshotStrictRecord(value, path18, options = {}) {
9520
+ function snapshotStrictRecord(value, path19, options = {}) {
9432
9521
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
9433
- throw new TypeError(`${path18} must be an object`);
9522
+ throw new TypeError(`${path19} must be an object`);
9434
9523
  }
9435
9524
  const prototype = Object.getPrototypeOf(value);
9436
9525
  if (prototype !== Object.prototype && prototype !== null) {
9437
- throw new TypeError(`${path18} must use a plain or null prototype`);
9526
+ throw new TypeError(`${path19} must use a plain or null prototype`);
9438
9527
  }
9439
9528
  const out = Object.create(null);
9440
9529
  for (const key of Reflect.ownKeys(value)) {
9441
9530
  const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
9442
9531
  if (!descriptor)
9443
- throw new TypeError(`${path18}.${String(key)} must have a stable own descriptor`);
9532
+ throw new TypeError(`${path19}.${String(key)} must have a stable own descriptor`);
9444
9533
  if (typeof key === "symbol" && !options.allowedSymbols?.has(key)) {
9445
- throw new TypeError(`${path18} contains unsupported symbol field: ${String(key)}`);
9534
+ throw new TypeError(`${path19} contains unsupported symbol field: ${String(key)}`);
9446
9535
  }
9447
9536
  if (!("value" in descriptor)) {
9448
- throw new TypeError(`${path18}.${String(key)} must be an enumerable data property, not an accessor`);
9537
+ throw new TypeError(`${path19}.${String(key)} must be an enumerable data property, not an accessor`);
9449
9538
  }
9450
9539
  if (typeof key === "string" && !descriptor.enumerable) {
9451
- throw new TypeError(`${path18}.${key} must be an enumerable data property, not a non-enumerable field`);
9540
+ throw new TypeError(`${path19}.${key} must be an enumerable data property, not a non-enumerable field`);
9452
9541
  }
9453
9542
  Object.defineProperty(out, key, {
9454
9543
  value: descriptor.value,
@@ -9459,14 +9548,14 @@ function snapshotStrictRecord(value, path18, options = {}) {
9459
9548
  }
9460
9549
  return Object.freeze(out);
9461
9550
  }
9462
- function assertSnapshotKeys(value, allowed, path18, allowedSymbols = new Set) {
9551
+ function assertSnapshotKeys(value, allowed, path19, allowedSymbols = new Set) {
9463
9552
  const allowedKeys = new Set(allowed);
9464
9553
  for (const key of Reflect.ownKeys(value)) {
9465
9554
  if (typeof key === "symbol") {
9466
9555
  if (!allowedSymbols.has(key))
9467
- throw new TypeError(`${path18} contains unsupported field: ${String(key)}`);
9556
+ throw new TypeError(`${path19} contains unsupported field: ${String(key)}`);
9468
9557
  } else if (!allowedKeys.has(key)) {
9469
- throw new TypeError(`${path18} contains unsupported field: ${key}`);
9558
+ throw new TypeError(`${path19} contains unsupported field: ${key}`);
9470
9559
  }
9471
9560
  }
9472
9561
  }
@@ -9474,9 +9563,9 @@ function assertSnapshotKeys(value, allowed, path18, allowedSymbols = new Set) {
9474
9563
  // node_modules/dotenv/lib/main.js
9475
9564
  var require_main = __commonJS((exports, module) => {
9476
9565
  var fs14 = __require("fs");
9477
- var path18 = __require("path");
9566
+ var path19 = __require("path");
9478
9567
  var os2 = __require("os");
9479
- var crypto3 = __require("crypto");
9568
+ var crypto4 = __require("crypto");
9480
9569
  var TIPS = [
9481
9570
  "\u25C8 encrypted .env [www.dotenvx.com]",
9482
9571
  "\u25C8 secrets for agents [www.dotenvx.com]",
@@ -9615,7 +9704,7 @@ var require_main = __commonJS((exports, module) => {
9615
9704
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
9616
9705
  }
9617
9706
  } else {
9618
- possibleVaultPath = path18.resolve(process.cwd(), ".env.vault");
9707
+ possibleVaultPath = path19.resolve(process.cwd(), ".env.vault");
9619
9708
  }
9620
9709
  if (fs14.existsSync(possibleVaultPath)) {
9621
9710
  return possibleVaultPath;
@@ -9623,7 +9712,7 @@ var require_main = __commonJS((exports, module) => {
9623
9712
  return null;
9624
9713
  }
9625
9714
  function _resolveHome(envPath) {
9626
- return envPath[0] === "~" ? path18.join(os2.homedir(), envPath.slice(1)) : envPath;
9715
+ return envPath[0] === "~" ? path19.join(os2.homedir(), envPath.slice(1)) : envPath;
9627
9716
  }
9628
9717
  function _configVault(options) {
9629
9718
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
@@ -9640,7 +9729,7 @@ var require_main = __commonJS((exports, module) => {
9640
9729
  return { parsed };
9641
9730
  }
9642
9731
  function configDotenv(options) {
9643
- const dotenvPath = path18.resolve(process.cwd(), ".env");
9732
+ const dotenvPath = path19.resolve(process.cwd(), ".env");
9644
9733
  let encoding = "utf8";
9645
9734
  let processEnv = process.env;
9646
9735
  if (options && options.processEnv != null) {
@@ -9668,13 +9757,13 @@ var require_main = __commonJS((exports, module) => {
9668
9757
  }
9669
9758
  let lastError;
9670
9759
  const parsedAll = {};
9671
- for (const path19 of optionPaths) {
9760
+ for (const path20 of optionPaths) {
9672
9761
  try {
9673
- const parsed = DotenvModule.parse(fs14.readFileSync(path19, { encoding }));
9762
+ const parsed = DotenvModule.parse(fs14.readFileSync(path20, { encoding }));
9674
9763
  DotenvModule.populate(parsedAll, parsed, options);
9675
9764
  } catch (e) {
9676
9765
  if (debug) {
9677
- _debug(`failed to load ${path19} ${e.message}`);
9766
+ _debug(`failed to load ${path20} ${e.message}`);
9678
9767
  }
9679
9768
  lastError = e;
9680
9769
  }
@@ -9687,7 +9776,7 @@ var require_main = __commonJS((exports, module) => {
9687
9776
  const shortPaths = [];
9688
9777
  for (const filePath of optionPaths) {
9689
9778
  try {
9690
- const relative = path18.relative(process.cwd(), filePath);
9779
+ const relative = path19.relative(process.cwd(), filePath);
9691
9780
  shortPaths.push(relative);
9692
9781
  } catch (e) {
9693
9782
  if (debug) {
@@ -9722,7 +9811,7 @@ var require_main = __commonJS((exports, module) => {
9722
9811
  const authTag = ciphertext.subarray(-16);
9723
9812
  ciphertext = ciphertext.subarray(12, -16);
9724
9813
  try {
9725
- const aesgcm = crypto3.createDecipheriv("aes-256-gcm", key, nonce);
9814
+ const aesgcm = crypto4.createDecipheriv("aes-256-gcm", key, nonce);
9726
9815
  aesgcm.setAuthTag(authTag);
9727
9816
  return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
9728
9817
  } catch (error) {
@@ -9826,7 +9915,7 @@ var init_time = __esm(() => {
9826
9915
 
9827
9916
  // src/tasks/source/bounded-document.ts
9828
9917
  import fs14 from "fs";
9829
- import path18 from "path";
9918
+ import path19 from "path";
9830
9919
  import { types as utilTypes } from "util";
9831
9920
  function own2(value, key) {
9832
9921
  return Object.hasOwn(value, key);
@@ -9997,7 +10086,7 @@ function parseTools(value, ctx) {
9997
10086
  sourceError(ctx, ["akm", "tools"], "must be a string, string array, mapping, or null.");
9998
10087
  }
9999
10088
  function validateWorkingDirectory(value, ctx) {
10000
- if (value.trim().length === 0 || value.includes("\x00") || path18.posix.isAbsolute(value.replaceAll("\\", "/")) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) {
10089
+ if (value.trim().length === 0 || value.includes("\x00") || path19.posix.isAbsolute(value.replaceAll("\\", "/")) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) {
10001
10090
  sourceError(ctx, ["working-directory"], "must be a non-empty relative path contained by the workspace root.");
10002
10091
  }
10003
10092
  const segments = value.replaceAll("\\", "/").split("/");
@@ -10011,7 +10100,7 @@ function validateWorkingDirectory(value, ctx) {
10011
10100
  let realCandidate;
10012
10101
  try {
10013
10102
  realRoot = fs14.realpathSync(ctx.workspaceRoot);
10014
- const candidate = path18.resolve(realRoot, value);
10103
+ const candidate = path19.resolve(realRoot, value);
10015
10104
  const stat = fs14.statSync(candidate);
10016
10105
  if (!stat.isDirectory())
10017
10106
  sourceError(ctx, ["working-directory"], "must resolve to a directory.");
@@ -10021,8 +10110,8 @@ function validateWorkingDirectory(value, ctx) {
10021
10110
  throw cause;
10022
10111
  sourceError(ctx, ["working-directory"], `cannot be physically verified: ${cause instanceof Error ? cause.message : String(cause)}.`);
10023
10112
  }
10024
- const relative = path18.relative(realRoot, realCandidate);
10025
- if (relative.startsWith("..") || path18.isAbsolute(relative)) {
10113
+ const relative = path19.relative(realRoot, realCandidate);
10114
+ if (relative.startsWith("..") || path19.isAbsolute(relative)) {
10026
10115
  sourceError(ctx, ["working-directory"], "resolves outside the workspace root and is not physically contained.");
10027
10116
  }
10028
10117
  }
@@ -10191,34 +10280,34 @@ function checkJsonSchemaDefinition(schema) {
10191
10280
  checkDefinitionNode(schema, [], issues, 0);
10192
10281
  return issues;
10193
10282
  }
10194
- function pointerFor(path19) {
10195
- return path19.length === 0 ? "$" : `$.${path19.map(String).join(".")}`;
10283
+ function pointerFor(path20) {
10284
+ return path20.length === 0 ? "$" : `$.${path20.map(String).join(".")}`;
10196
10285
  }
10197
- function pushIssue(issues, path19, keyword, kind, message) {
10198
- issues.push({ path: [...path19], pointer: pointerFor(path19), keyword, kind, message });
10286
+ function pushIssue(issues, path20, keyword, kind, message) {
10287
+ issues.push({ path: [...path20], pointer: pointerFor(path20), keyword, kind, message });
10199
10288
  }
10200
10289
  function isSupportedEnumValue(value) {
10201
10290
  return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
10202
10291
  }
10203
- function checkDefinitionNode(schema, path19, issues, depth) {
10292
+ function checkDefinitionNode(schema, path20, issues, depth) {
10204
10293
  if (depth > MAX_DEFINITION_DEPTH) {
10205
- pushIssue(issues, path19, "(depth)", "malformed", `schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10294
+ pushIssue(issues, path20, "(depth)", "malformed", `schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10206
10295
  return;
10207
10296
  }
10208
10297
  for (const keyword of Object.keys(schema)) {
10209
10298
  if (UNSUPPORTED_KEYWORDS.has(keyword)) {
10210
10299
  const hint = UNSUPPORTED_KEYWORD_HINTS.get(keyword);
10211
- pushIssue(issues, [...path19, keyword], keyword, "unsupported", `keyword "${keyword}" is not enforced by the workflow schema subset \u2014 the schema would silently not ` + `constrain what it looks like it constrains${hint ? `; ${hint}` : ""}`);
10300
+ pushIssue(issues, [...path20, keyword], keyword, "unsupported", `keyword "${keyword}" is not enforced by the workflow schema subset \u2014 the schema would silently not ` + `constrain what it looks like it constrains${hint ? `; ${hint}` : ""}`);
10212
10301
  }
10213
10302
  }
10214
10303
  const declared = schema.type;
10215
10304
  if (declared !== undefined) {
10216
10305
  const names = Array.isArray(declared) ? declared : [declared];
10217
10306
  if (names.length === 0) {
10218
- pushIssue(issues, [...path19, "type"], "type", "malformed", `"type" must name at least one type`);
10307
+ pushIssue(issues, [...path20, "type"], "type", "malformed", `"type" must name at least one type`);
10219
10308
  }
10220
10309
  for (const [index, name] of names.entries()) {
10221
- const namePath = Array.isArray(declared) ? [...path19, "type", index] : [...path19, "type"];
10310
+ const namePath = Array.isArray(declared) ? [...path20, "type", index] : [...path20, "type"];
10222
10311
  if (typeof name !== "string") {
10223
10312
  pushIssue(issues, namePath, "type", "malformed", `"type" must be a string or an array of strings`);
10224
10313
  } else if (!KNOWN_TYPE_NAMES.has(name)) {
@@ -10228,12 +10317,12 @@ function checkDefinitionNode(schema, path19, issues, depth) {
10228
10317
  }
10229
10318
  if (schema.enum !== undefined) {
10230
10319
  if (!Array.isArray(schema.enum) || schema.enum.length === 0) {
10231
- pushIssue(issues, [...path19, "enum"], "enum", "malformed", `"enum" must be a non-empty array of allowed values`);
10320
+ pushIssue(issues, [...path20, "enum"], "enum", "malformed", `"enum" must be a non-empty array of allowed values`);
10232
10321
  } else {
10233
10322
  schema.enum.forEach((value, index) => {
10234
10323
  if (isSupportedEnumValue(value))
10235
10324
  return;
10236
- pushIssue(issues, [...path19, "enum", index], "enum", "unsupported", `"enum" values must be JSON primitives (string, finite number, boolean, or null) in the workflow ` + `schema subset \u2014 object and array enum members cannot be matched by the runtime subset`);
10325
+ pushIssue(issues, [...path20, "enum", index], "enum", "unsupported", `"enum" values must be JSON primitives (string, finite number, boolean, or null) in the workflow ` + `schema subset \u2014 object and array enum members cannot be matched by the runtime subset`);
10237
10326
  });
10238
10327
  }
10239
10328
  }
@@ -10242,68 +10331,68 @@ function checkDefinitionNode(schema, path19, issues, depth) {
10242
10331
  if (branches === undefined)
10243
10332
  continue;
10244
10333
  if (!Array.isArray(branches) || branches.length === 0) {
10245
- pushIssue(issues, [...path19, keyword], keyword, "malformed", `"${keyword}" must be a non-empty array of schema objects`);
10334
+ pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a non-empty array of schema objects`);
10246
10335
  continue;
10247
10336
  }
10248
10337
  branches.forEach((branch, index) => {
10249
10338
  if (isRecord(branch)) {
10250
- checkDefinitionNode(branch, [...path19, keyword, index], issues, depth + 1);
10339
+ checkDefinitionNode(branch, [...path20, keyword, index], issues, depth + 1);
10251
10340
  } else {
10252
- pushIssue(issues, [...path19, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
10341
+ pushIssue(issues, [...path20, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
10253
10342
  }
10254
10343
  });
10255
10344
  }
10256
10345
  if (schema.not !== undefined) {
10257
10346
  if (isRecord(schema.not)) {
10258
- checkDefinitionNode(schema.not, [...path19, "not"], issues, depth + 1);
10347
+ checkDefinitionNode(schema.not, [...path20, "not"], issues, depth + 1);
10259
10348
  } else {
10260
- pushIssue(issues, [...path19, "not"], "not", "malformed", `"not" must be a schema object`);
10349
+ pushIssue(issues, [...path20, "not"], "not", "malformed", `"not" must be a schema object`);
10261
10350
  }
10262
10351
  }
10263
10352
  if (schema.required !== undefined) {
10264
10353
  if (!Array.isArray(schema.required) || !schema.required.every((key) => typeof key === "string")) {
10265
- pushIssue(issues, [...path19, "required"], "required", "malformed", `"required" must be an array of property-name strings`);
10354
+ pushIssue(issues, [...path20, "required"], "required", "malformed", `"required" must be an array of property-name strings`);
10266
10355
  }
10267
10356
  }
10268
10357
  if (schema.properties !== undefined) {
10269
10358
  if (!isRecord(schema.properties)) {
10270
- pushIssue(issues, [...path19, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
10359
+ pushIssue(issues, [...path20, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
10271
10360
  } else {
10272
10361
  for (const [key, propSchema] of Object.entries(schema.properties)) {
10273
10362
  if (isRecord(propSchema)) {
10274
- checkDefinitionNode(propSchema, [...path19, "properties", key], issues, depth + 1);
10363
+ checkDefinitionNode(propSchema, [...path20, "properties", key], issues, depth + 1);
10275
10364
  } else {
10276
- pushIssue(issues, [...path19, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
10365
+ pushIssue(issues, [...path20, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
10277
10366
  }
10278
10367
  }
10279
10368
  }
10280
10369
  }
10281
10370
  if (schema.items !== undefined) {
10282
10371
  if (isRecord(schema.items)) {
10283
- checkDefinitionNode(schema.items, [...path19, "items"], issues, depth + 1);
10372
+ checkDefinitionNode(schema.items, [...path20, "items"], issues, depth + 1);
10284
10373
  } else if (Array.isArray(schema.items)) {
10285
- pushIssue(issues, [...path19, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset \u2014 use a single schema object`);
10374
+ pushIssue(issues, [...path20, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset \u2014 use a single schema object`);
10286
10375
  } else {
10287
- pushIssue(issues, [...path19, "items"], "items", "malformed", `"items" must be a schema object`);
10376
+ pushIssue(issues, [...path20, "items"], "items", "malformed", `"items" must be a schema object`);
10288
10377
  }
10289
10378
  }
10290
10379
  if (schema.additionalProperties !== undefined && typeof schema.additionalProperties !== "boolean") {
10291
10380
  if (isRecord(schema.additionalProperties)) {
10292
- pushIssue(issues, [...path19, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset \u2014 only "additionalProperties: false" is`);
10381
+ pushIssue(issues, [...path20, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset \u2014 only "additionalProperties: false" is`);
10293
10382
  } else {
10294
- pushIssue(issues, [...path19, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
10383
+ pushIssue(issues, [...path20, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
10295
10384
  }
10296
10385
  }
10297
10386
  for (const keyword of ["minItems", "maxItems", "minLength", "maxLength"]) {
10298
10387
  const value = schema[keyword];
10299
10388
  if (value !== undefined && (typeof value !== "number" || !Number.isInteger(value) || value < 0)) {
10300
- pushIssue(issues, [...path19, keyword], keyword, "malformed", `"${keyword}" must be a non-negative integer`);
10389
+ pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a non-negative integer`);
10301
10390
  }
10302
10391
  }
10303
10392
  for (const keyword of ["minimum", "maximum"]) {
10304
10393
  const value = schema[keyword];
10305
10394
  if (value !== undefined && (typeof value !== "number" || !Number.isFinite(value))) {
10306
- pushIssue(issues, [...path19, keyword], keyword, "malformed", `"${keyword}" must be a finite number`);
10395
+ pushIssue(issues, [...path20, keyword], keyword, "malformed", `"${keyword}" must be a finite number`);
10307
10396
  }
10308
10397
  }
10309
10398
  }
@@ -10328,9 +10417,9 @@ function matchesType(actual, expected) {
10328
10417
  return true;
10329
10418
  return expected === "number" && actual === "integer";
10330
10419
  }
10331
- function branchErrors(value, schema, path19, ctx) {
10420
+ function branchErrors(value, schema, path20, ctx) {
10332
10421
  const errors3 = [];
10333
- validateNode(value, schema, path19, { ...ctx, errors: errors3, depth: ctx.depth + 1 });
10422
+ validateNode(value, schema, path20, { ...ctx, errors: errors3, depth: ctx.depth + 1 });
10334
10423
  return errors3;
10335
10424
  }
10336
10425
  function combinatorBranches(schema, keyword) {
@@ -10345,9 +10434,9 @@ function summarizeBranchFailures(failures) {
10345
10434
  shown.push(`\u2026${failures.length - shown.length} more`);
10346
10435
  return shown.join("; ");
10347
10436
  }
10348
- function validateCombinators(value, schema, path19, ctx) {
10437
+ function validateCombinators(value, schema, path20, ctx) {
10349
10438
  for (const branch of combinatorBranches(schema, "allOf")) {
10350
- ctx.errors.push(...branchErrors(value, branch, path19, ctx));
10439
+ ctx.errors.push(...branchErrors(value, branch, path20, ctx));
10351
10440
  }
10352
10441
  for (const keyword of ["anyOf", "oneOf"]) {
10353
10442
  const branches = combinatorBranches(schema, keyword);
@@ -10356,27 +10445,27 @@ function validateCombinators(value, schema, path19, ctx) {
10356
10445
  const failures = [];
10357
10446
  const matched = [];
10358
10447
  branches.forEach((branch, index) => {
10359
- const errors3 = branchErrors(value, branch, path19, ctx);
10448
+ const errors3 = branchErrors(value, branch, path20, ctx);
10360
10449
  if (errors3.length === 0)
10361
10450
  matched.push(index + 1);
10362
10451
  else
10363
10452
  failures.push({ index, errors: errors3 });
10364
10453
  });
10365
10454
  if (matched.length === 0) {
10366
- ctx.errors.push(`${path19}: value matches none of the ${branches.length} "${keyword}" schemas (${summarizeBranchFailures(failures)})`);
10455
+ ctx.errors.push(`${path20}: value matches none of the ${branches.length} "${keyword}" schemas (${summarizeBranchFailures(failures)})`);
10367
10456
  } else if (keyword === "oneOf" && matched.length > 1) {
10368
- ctx.errors.push(`${path19}: value matches ${matched.length} "oneOf" schemas (branches ${matched.join(", ")}); exactly one must match`);
10457
+ ctx.errors.push(`${path20}: value matches ${matched.length} "oneOf" schemas (branches ${matched.join(", ")}); exactly one must match`);
10369
10458
  }
10370
10459
  }
10371
10460
  const not = schema.not;
10372
- if (isRecord(not) && branchErrors(value, not, path19, ctx).length === 0) {
10373
- ctx.errors.push(`${path19}: value must not match the "not" schema`);
10461
+ if (isRecord(not) && branchErrors(value, not, path20, ctx).length === 0) {
10462
+ ctx.errors.push(`${path20}: value must not match the "not" schema`);
10374
10463
  }
10375
10464
  }
10376
- function validateNode(value, schema, path19, ctx) {
10465
+ function validateNode(value, schema, path20, ctx) {
10377
10466
  const errors3 = ctx.errors;
10378
10467
  if (ctx.depth > MAX_DEFINITION_DEPTH) {
10379
- errors3.push(`${path19}: schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10468
+ errors3.push(`${path20}: schema nesting exceeds the depth limit of ${MAX_DEFINITION_DEPTH}`);
10380
10469
  return;
10381
10470
  }
10382
10471
  if (--ctx.budget.nodes < 0)
@@ -10386,47 +10475,47 @@ function validateNode(value, schema, path19, ctx) {
10386
10475
  if (typeof declared === "string" || Array.isArray(declared)) {
10387
10476
  const expected = (Array.isArray(declared) ? declared : [declared]).filter((t) => typeof t === "string");
10388
10477
  if (expected.length > 0 && !expected.some((t) => matchesType(actual, t))) {
10389
- errors3.push(`${path19}: expected type ${expected.join(" | ")}, got ${actual}`);
10478
+ errors3.push(`${path20}: expected type ${expected.join(" | ")}, got ${actual}`);
10390
10479
  return;
10391
10480
  }
10392
10481
  }
10393
10482
  if (Array.isArray(schema.enum) && schema.enum.length > 0) {
10394
10483
  const allowed = schema.enum;
10395
10484
  if (!allowed.some((candidate) => candidate === value)) {
10396
- 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)}`);
10485
+ 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)}`);
10397
10486
  return;
10398
10487
  }
10399
10488
  }
10400
- validateCombinators(value, schema, path19, ctx);
10489
+ validateCombinators(value, schema, path20, ctx);
10401
10490
  if (actual === "string" && typeof value === "string") {
10402
10491
  if (typeof schema.minLength === "number" && value.length < schema.minLength) {
10403
- errors3.push(`${path19}: string shorter than minLength ${schema.minLength}`);
10492
+ errors3.push(`${path20}: string shorter than minLength ${schema.minLength}`);
10404
10493
  }
10405
10494
  if (typeof schema.maxLength === "number" && value.length > schema.maxLength) {
10406
- errors3.push(`${path19}: string longer than maxLength ${schema.maxLength}`);
10495
+ errors3.push(`${path20}: string longer than maxLength ${schema.maxLength}`);
10407
10496
  }
10408
10497
  return;
10409
10498
  }
10410
10499
  if ((actual === "number" || actual === "integer") && typeof value === "number") {
10411
10500
  if (typeof schema.minimum === "number" && value < schema.minimum) {
10412
- errors3.push(ctx.redactValues ? `${path19}: value is below minimum ${schema.minimum}` : `${path19}: ${value} is below minimum ${schema.minimum}`);
10501
+ errors3.push(ctx.redactValues ? `${path20}: value is below minimum ${schema.minimum}` : `${path20}: ${value} is below minimum ${schema.minimum}`);
10413
10502
  }
10414
10503
  if (typeof schema.maximum === "number" && value > schema.maximum) {
10415
- errors3.push(ctx.redactValues ? `${path19}: value is above maximum ${schema.maximum}` : `${path19}: ${value} is above maximum ${schema.maximum}`);
10504
+ errors3.push(ctx.redactValues ? `${path20}: value is above maximum ${schema.maximum}` : `${path20}: ${value} is above maximum ${schema.maximum}`);
10416
10505
  }
10417
10506
  return;
10418
10507
  }
10419
10508
  if (actual === "array" && Array.isArray(value)) {
10420
10509
  if (typeof schema.minItems === "number" && value.length < schema.minItems) {
10421
- errors3.push(`${path19}: array has fewer than minItems ${schema.minItems}`);
10510
+ errors3.push(`${path20}: array has fewer than minItems ${schema.minItems}`);
10422
10511
  }
10423
10512
  if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
10424
- errors3.push(`${path19}: array has more than maxItems ${schema.maxItems}`);
10513
+ errors3.push(`${path20}: array has more than maxItems ${schema.maxItems}`);
10425
10514
  }
10426
10515
  const items = schema.items;
10427
10516
  if (items && typeof items === "object" && !Array.isArray(items)) {
10428
10517
  value.forEach((element, index) => {
10429
- validateNode(element, items, `${path19}[${index}]`, {
10518
+ validateNode(element, items, `${path20}[${index}]`, {
10430
10519
  ...ctx,
10431
10520
  depth: ctx.depth + 1
10432
10521
  });
@@ -10440,7 +10529,7 @@ function validateNode(value, schema, path19, ctx) {
10440
10529
  if (Array.isArray(schema.required)) {
10441
10530
  for (const key of schema.required) {
10442
10531
  if (typeof key === "string" && !Object.hasOwn(record, key)) {
10443
- errors3.push(`${path19}: missing required property "${key}"`);
10532
+ errors3.push(`${path20}: missing required property "${key}"`);
10444
10533
  }
10445
10534
  }
10446
10535
  }
@@ -10449,7 +10538,7 @@ function validateNode(value, schema, path19, ctx) {
10449
10538
  if (!Object.hasOwn(record, key))
10450
10539
  continue;
10451
10540
  if (propSchema && typeof propSchema === "object" && !Array.isArray(propSchema)) {
10452
- validateNode(record[key], propSchema, `${path19}.${key}`, {
10541
+ validateNode(record[key], propSchema, `${path20}.${key}`, {
10453
10542
  ...ctx,
10454
10543
  depth: ctx.depth + 1
10455
10544
  });
@@ -10459,7 +10548,7 @@ function validateNode(value, schema, path19, ctx) {
10459
10548
  if (schema.additionalProperties === false) {
10460
10549
  for (const key of Object.keys(record)) {
10461
10550
  if (!properties || !Object.hasOwn(properties, key)) {
10462
- errors3.push(`${path19}: unexpected property "${key}" (additionalProperties: false)`);
10551
+ errors3.push(`${path20}: unexpected property "${key}" (additionalProperties: false)`);
10463
10552
  }
10464
10553
  }
10465
10554
  }
@@ -10640,10 +10729,10 @@ function parseReference(source) {
10640
10729
  if (!output || output.name !== "output") {
10641
10730
  return { ok: false, message: `Expected ".output" after "steps.${stepId.name}" in "${text}".` };
10642
10731
  }
10643
- const path21 = parsePath(text, output.end);
10644
- if (!path21.ok)
10645
- return { ok: false, message: path21.message };
10646
- return { ok: true, expr: { kind: "stepOutput", stepId: stepId.name, path: path21.path } };
10732
+ const path22 = parsePath(text, output.end);
10733
+ if (!path22.ok)
10734
+ return { ok: false, message: path22.message };
10735
+ return { ok: true, expr: { kind: "stepOutput", stepId: stepId.name, path: path22.path } };
10647
10736
  }
10648
10737
  default:
10649
10738
  return { ok: false, message: `Unknown root "${root.name}" in "${text}"; ${GRAMMAR_HINT}.` };
@@ -10658,7 +10747,7 @@ function readIdent(text, start) {
10658
10747
  return { name: text.slice(start, end), end };
10659
10748
  }
10660
10749
  function parsePath(text, start) {
10661
- const path21 = [];
10750
+ const path22 = [];
10662
10751
  let i = start;
10663
10752
  while (i < text.length) {
10664
10753
  const char = text[i];
@@ -10667,7 +10756,7 @@ function parsePath(text, start) {
10667
10756
  if (!ident) {
10668
10757
  return { ok: false, message: `Invalid path segment after "." at position ${i} in "${text}".` };
10669
10758
  }
10670
- path21.push(ident.name);
10759
+ path22.push(ident.name);
10671
10760
  i = ident.end;
10672
10761
  } else if (char === "[") {
10673
10762
  let j = i + 1;
@@ -10679,13 +10768,13 @@ function parsePath(text, start) {
10679
10768
  message: `Invalid indexer at position ${i} in "${text}" \u2014 expected [<non-negative integer>].`
10680
10769
  };
10681
10770
  }
10682
- path21.push(Number.parseInt(text.slice(i + 1, j), 10));
10771
+ path22.push(Number.parseInt(text.slice(i + 1, j), 10));
10683
10772
  i = j + 1;
10684
10773
  } else {
10685
10774
  return { ok: false, message: `Unexpected character "${char}" at position ${i} in "${text}".` };
10686
10775
  }
10687
10776
  }
10688
- return { ok: true, path: path21 };
10777
+ return { ok: true, path: path22 };
10689
10778
  }
10690
10779
  function formatReference(expr) {
10691
10780
  switch (expr.kind) {
@@ -11058,7 +11147,7 @@ var init_uses = __esm(() => {
11058
11147
 
11059
11148
  // src/workflows/source-ir/semantics.ts
11060
11149
  import fs15 from "fs";
11061
- import path21 from "path";
11150
+ import path22 from "path";
11062
11151
  function canonicalizeWorkflowCron(value) {
11063
11152
  const canonical = value.trim().split(/\s+/).join(" ");
11064
11153
  if (canonical.startsWith("@") || canonical.split(" ").length !== 5) {
@@ -11094,7 +11183,7 @@ function canonicalizeWorkflowWorkingDirectory(value, workspaceRoot) {
11094
11183
  }
11095
11184
  const portable = value.replaceAll("\\", "/");
11096
11185
  const segments = portable.split("/");
11097
- if (path21.posix.isAbsolute(portable) || path21.win32.isAbsolute(value) || portable.startsWith("~") || segments.some((segment) => segment === "" || segment === "..")) {
11186
+ if (path22.posix.isAbsolute(portable) || path22.win32.isAbsolute(value) || portable.startsWith("~") || segments.some((segment) => segment === "" || segment === "..")) {
11098
11187
  throw new WorkflowSourceSemanticError("working-directory-escape", "working-directory must be relative and contained.");
11099
11188
  }
11100
11189
  const withoutDots = segments.filter((segment) => segment !== ".");
@@ -11174,13 +11263,13 @@ function verifyPhysicalContainment(workspaceRoot, relative) {
11174
11263
  } catch {
11175
11264
  throw new WorkflowSourceSemanticError("working-directory-unverifiable", "Workspace root cannot be physically verified.");
11176
11265
  }
11177
- const candidate = path21.resolve(root, ...relative.split("/"));
11266
+ const candidate = path22.resolve(root, ...relative.split("/"));
11178
11267
  if (!contained(root, candidate)) {
11179
11268
  throw new WorkflowSourceSemanticError("working-directory-escape", "working-directory escapes the workspace.");
11180
11269
  }
11181
11270
  let current = root;
11182
11271
  for (const segment of relative === "." ? [] : relative.split("/")) {
11183
- current = path21.join(current, segment);
11272
+ current = path22.join(current, segment);
11184
11273
  try {
11185
11274
  const entry = fs15.lstatSync(current);
11186
11275
  if (entry.isSymbolicLink()) {
@@ -11223,8 +11312,8 @@ function verifyPhysicalContainment(workspaceRoot, relative) {
11223
11312
  }
11224
11313
  }
11225
11314
  function contained(root, candidate) {
11226
- const relative = path21.relative(root, candidate);
11227
- return relative === "" || !relative.startsWith(`..${path21.sep}`) && relative !== ".." && !path21.isAbsolute(relative);
11315
+ const relative = path22.relative(root, candidate);
11316
+ return relative === "" || !relative.startsWith(`..${path22.sep}`) && relative !== ".." && !path22.isAbsolute(relative);
11228
11317
  }
11229
11318
  var TOKEN_SAFE_RUN, WorkflowSourceSemanticError;
11230
11319
  var init_semantics = __esm(() => {
@@ -12058,7 +12147,7 @@ function parseWorkflow(markdown, source) {
12058
12147
  };
12059
12148
  }
12060
12149
  const errors3 = [];
12061
- const path22 = source.path;
12150
+ const path23 = source.path;
12062
12151
  const lines = markdown.split(/\r?\n/);
12063
12152
  const totalLines = lines.length;
12064
12153
  const fmBlock = parseFrontmatterBlock(markdown);
@@ -12110,7 +12199,7 @@ function parseWorkflow(markdown, source) {
12110
12199
  return 2;
12111
12200
  };
12112
12201
  const ctx = {
12113
- filePath: path22,
12202
+ filePath: path23,
12114
12203
  errors: errors3,
12115
12204
  ...source.validateExecCwd ? { validateExecCwd: source.validateExecCwd } : {},
12116
12205
  lineAt,
@@ -12123,10 +12212,10 @@ function parseWorkflow(markdown, source) {
12123
12212
  if (range) {
12124
12213
  const start = Math.max(1, lineCounter2.linePos(range[0]).line + lineOffset);
12125
12214
  const end = Math.max(start, lineCounter2.linePos(Math.max(range[0], range[1] - 1)).line + lineOffset);
12126
- return { path: path22, start, end };
12215
+ return { path: path23, start, end };
12127
12216
  }
12128
12217
  }
12129
- return { path: path22, start: frontmatterEndLine, end: frontmatterEndLine };
12218
+ return { path: path23, start: frontmatterEndLine, end: frontmatterEndLine };
12130
12219
  },
12131
12220
  err: (p, message) => errors3.push({ line: lineAt(p), message }),
12132
12221
  errAtLine: (line, message) => errors3.push({ line, message })
@@ -12150,7 +12239,7 @@ function parseWorkflow(markdown, source) {
12150
12239
  const parsedSteps = parseSteps(ctx, root.steps);
12151
12240
  const toc = parseMarkdownToc(markdown);
12152
12241
  const declaredIds = new Set(parsedSteps.map((s) => s.id));
12153
- const { sections, preamble } = bindStepSections(toc.headings, lines, fmBlock.bodyStartLine, totalLines, path22, declaredIds, errors3);
12242
+ const { sections, preamble } = bindStepSections(toc.headings, lines, fmBlock.bodyStartLine, totalLines, path23, declaredIds, errors3);
12154
12243
  const steps = parsedSteps.map((step, index) => {
12155
12244
  const section = sections.get(step.id);
12156
12245
  if (!section) {
@@ -12194,14 +12283,14 @@ function parseWorkflow(markdown, source) {
12194
12283
  ...budget ? { budget } : {},
12195
12284
  steps,
12196
12285
  ...preamble ? { preamble } : {},
12197
- source: { path: path22, lineCount: totalLines }
12286
+ source: { path: path23, lineCount: totalLines }
12198
12287
  };
12199
12288
  runSemanticChecks(draft, root, frontmatterEndLine, errors3);
12200
12289
  if (errors3.length > 0)
12201
12290
  return { ok: false, errors: sortErrors(errors3) };
12202
12291
  return { ok: true, document: draft };
12203
12292
  }
12204
- function bindStepSections(headings, lines, bodyStartLine, totalLines, path22, declaredIds, errors3) {
12293
+ function bindStepSections(headings, lines, bodyStartLine, totalLines, path23, declaredIds, errors3) {
12205
12294
  const sections = new Map;
12206
12295
  const h2s = headings.filter((h) => h.level === 2);
12207
12296
  const firstH2Line = h2s[0]?.line;
@@ -12225,24 +12314,24 @@ function bindStepSections(headings, lines, bodyStartLine, totalLines, path22, de
12225
12314
  continue;
12226
12315
  }
12227
12316
  const sectionEnd = findNextHeadingAtOrAboveLevel(headings, i, 2, totalLines);
12228
- const gate = findGateSubsection(headings, i, sectionEnd, path22, h.text, errors3);
12317
+ const gate = findGateSubsection(headings, i, sectionEnd, path23, h.text, errors3);
12229
12318
  const instructionsEnd = gate ? gate.headingLine - 1 : sectionEnd;
12230
12319
  const instructionsText = sliceProseLines(lines, h.line + 1, instructionsEnd);
12231
12320
  const section = { headingLine: h.line };
12232
12321
  if (instructionsText) {
12233
- section.instructions = { text: instructionsText, source: { path: path22, start: h.line + 1, end: instructionsEnd } };
12322
+ section.instructions = { text: instructionsText, source: { path: path23, start: h.line + 1, end: instructionsEnd } };
12234
12323
  }
12235
12324
  if (gate) {
12236
12325
  const gateText = sliceProseLines(lines, gate.bodyStart, gate.bodyEnd);
12237
12326
  if (gateText) {
12238
- section.gateRubric = { text: gateText, source: { path: path22, start: gate.bodyStart, end: gate.bodyEnd } };
12327
+ section.gateRubric = { text: gateText, source: { path: path23, start: gate.bodyStart, end: gate.bodyEnd } };
12239
12328
  }
12240
12329
  }
12241
12330
  sections.set(h.text, section);
12242
12331
  }
12243
12332
  return { sections, preamble: preambleRaw || undefined };
12244
12333
  }
12245
- function findGateSubsection(headings, stepHeadingIndex, sectionEnd, path22, stepId, errors3) {
12334
+ function findGateSubsection(headings, stepHeadingIndex, sectionEnd, path23, stepId, errors3) {
12246
12335
  let found;
12247
12336
  for (let j = stepHeadingIndex + 1;j < headings.length; j++) {
12248
12337
  const h = headings[j];
@@ -12324,19 +12413,19 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
12324
12413
  ctx.err(["stale_after"], `Workflow frontmatter "stale_after" must be a string.`);
12325
12414
  }
12326
12415
  }
12327
- function checkActorStamp(ctx, value, path22, label) {
12416
+ function checkActorStamp(ctx, value, path23, label) {
12328
12417
  if (value === undefined)
12329
12418
  return;
12330
12419
  if (!isRecord(value)) {
12331
- ctx.err(path22, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12420
+ ctx.err(path23, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12332
12421
  return;
12333
12422
  }
12334
- checkUnknownKeys(ctx, value, path22, ACTOR_STAMP_KEYS, `${label} actor stamp`);
12423
+ checkUnknownKeys(ctx, value, path23, ACTOR_STAMP_KEYS, `${label} actor stamp`);
12335
12424
  if (typeof value.by !== "string" || value.by.length === 0) {
12336
- ctx.err([...path22, "by"], `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12425
+ ctx.err([...path23, "by"], `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
12337
12426
  }
12338
12427
  if (value.at !== undefined && typeof value.at !== "string") {
12339
- ctx.err([...path22, "at"], `Workflow frontmatter ${label} actor stamp "at" must be a string.`);
12428
+ ctx.err([...path23, "at"], `Workflow frontmatter ${label} actor stamp "at" must be a string.`);
12340
12429
  }
12341
12430
  }
12342
12431
  function readTags2(ctx, value, fmEndLine) {
@@ -12389,38 +12478,38 @@ function parseOutputs(ctx, raw) {
12389
12478
  }
12390
12479
  const outputs = {};
12391
12480
  for (const [outputName, value] of Object.entries(raw)) {
12392
- const path22 = ["outputs", outputName];
12481
+ const path23 = ["outputs", outputName];
12393
12482
  if (!INPUT_NAME_PATTERN.test(outputName)) {
12394
- 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.`);
12483
+ 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.`);
12395
12484
  continue;
12396
12485
  }
12397
12486
  if (!isRecord(value)) {
12398
- ctx.err(path22, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
12487
+ ctx.err(path23, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
12399
12488
  continue;
12400
12489
  }
12401
- checkUnknownKeys(ctx, value, path22, OUTPUT_ENTRY_KEYS, `output "${outputName}"`);
12490
+ checkUnknownKeys(ctx, value, path23, OUTPUT_ENTRY_KEYS, `output "${outputName}"`);
12402
12491
  if (typeof value.from !== "string" || value.from.trim() === "") {
12403
- ctx.err([...path22, "from"], `Output "${outputName}" must declare "from": a steps.<id>.output(.<seg>)* reference.`);
12492
+ ctx.err([...path23, "from"], `Output "${outputName}" must declare "from": a steps.<id>.output(.<seg>)* reference.`);
12404
12493
  continue;
12405
12494
  }
12406
12495
  const parsedFrom = parseReference(value.from);
12407
12496
  if (!parsedFrom.ok) {
12408
- ctx.err([...path22, "from"], `Output "${outputName}" "from": ${parsedFrom.message}`);
12497
+ ctx.err([...path23, "from"], `Output "${outputName}" "from": ${parsedFrom.message}`);
12409
12498
  continue;
12410
12499
  }
12411
12500
  if (parsedFrom.expr.kind !== "stepOutput") {
12412
- ctx.err([...path22, "from"], `Output "${outputName}" "from" must reference a step output (steps.<id>.output...), not a param \u2014 an ` + `output projects a step artifact, never a param (got "${value.from}").`);
12501
+ ctx.err([...path23, "from"], `Output "${outputName}" "from" must reference a step output (steps.<id>.output...), not a param \u2014 an ` + `output projects a step artifact, never a param (got "${value.from}").`);
12413
12502
  continue;
12414
12503
  }
12415
12504
  const entry = { from: value.from };
12416
12505
  if (value.schema !== undefined) {
12417
12506
  if (!isRecord(value.schema)) {
12418
- ctx.err([...path22, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
12507
+ ctx.err([...path23, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
12419
12508
  } else {
12420
12509
  if (jsonBytes(value.schema) > WORKFLOW_MAX_SCHEMA_BYTES) {
12421
- ctx.err([...path22, "schema"], `Output "${outputName}" schema exceeds the 256 KiB resource limit.`);
12510
+ ctx.err([...path23, "schema"], `Output "${outputName}" schema exceeds the 256 KiB resource limit.`);
12422
12511
  }
12423
- checkSchemaDefinition(ctx, value.schema, [...path22, "schema"], `Output "${outputName}" schema`);
12512
+ checkSchemaDefinition(ctx, value.schema, [...path23, "schema"], `Output "${outputName}" schema`);
12424
12513
  entry.schema = value.schema;
12425
12514
  }
12426
12515
  }
@@ -12431,15 +12520,15 @@ function parseOutputs(ctx, raw) {
12431
12520
  function parseDefaults(ctx, raw) {
12432
12521
  if (raw === undefined)
12433
12522
  return;
12434
- const path22 = ["defaults"];
12523
+ const path23 = ["defaults"];
12435
12524
  if (!isRecord(raw)) {
12436
- ctx.err(path22, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
12525
+ ctx.err(path23, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
12437
12526
  return;
12438
12527
  }
12439
- checkUnknownKeys(ctx, raw, path22, DEFAULTS_KEYS, `"defaults"`);
12528
+ checkUnknownKeys(ctx, raw, path23, DEFAULTS_KEYS, `"defaults"`);
12440
12529
  const defaults = {};
12441
12530
  if (raw.engine !== undefined) {
12442
- const engine = parseEngineName(ctx, raw.engine, [...path22, "engine"], `"defaults.engine"`);
12531
+ const engine = parseEngineName(ctx, raw.engine, [...path23, "engine"], `"defaults.engine"`);
12443
12532
  if (engine !== undefined)
12444
12533
  defaults.engine = engine;
12445
12534
  }
@@ -12447,15 +12536,15 @@ function parseDefaults(ctx, raw) {
12447
12536
  if (typeof raw.model === "string" && raw.model.trim() !== "")
12448
12537
  defaults.model = raw.model.trim();
12449
12538
  else
12450
- ctx.err([...path22, "model"], `"defaults.model" must be a non-empty string (a model alias or exact id).`);
12539
+ ctx.err([...path23, "model"], `"defaults.model" must be a non-empty string (a model alias or exact id).`);
12451
12540
  }
12452
- const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path22, "timeout"], `"defaults.timeout"`);
12541
+ const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path23, "timeout"], `"defaults.timeout"`);
12453
12542
  if (timeoutMs !== undefined)
12454
12543
  defaults.timeoutMs = timeoutMs;
12455
- const onError = parseEnumField(ctx, raw.on_error, [...path22, "on_error"], `"defaults.on_error"`, PROGRAM_ON_ERROR);
12544
+ const onError = parseEnumField(ctx, raw.on_error, [...path23, "on_error"], `"defaults.on_error"`, PROGRAM_ON_ERROR);
12456
12545
  if (onError !== undefined)
12457
12546
  defaults.onError = onError;
12458
- const llm = parseLlmOverrides(ctx, raw.llm, [...path22, "llm"], `"defaults.llm"`);
12547
+ const llm = parseLlmOverrides(ctx, raw.llm, [...path23, "llm"], `"defaults.llm"`);
12459
12548
  if (llm !== undefined)
12460
12549
  defaults.llm = llm;
12461
12550
  return Object.keys(defaults).length > 0 ? defaults : undefined;
@@ -12463,25 +12552,25 @@ function parseDefaults(ctx, raw) {
12463
12552
  function parseBudget(ctx, raw) {
12464
12553
  if (raw === undefined)
12465
12554
  return;
12466
- const path22 = ["budget"];
12555
+ const path23 = ["budget"];
12467
12556
  if (!isRecord(raw)) {
12468
- ctx.err(path22, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
12557
+ ctx.err(path23, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
12469
12558
  return;
12470
12559
  }
12471
- checkUnknownKeys(ctx, raw, path22, BUDGET_KEYS, `"budget"`);
12560
+ checkUnknownKeys(ctx, raw, path23, BUDGET_KEYS, `"budget"`);
12472
12561
  const budget = {};
12473
12562
  if (raw.max_tokens !== undefined) {
12474
12563
  if (typeof raw.max_tokens === "number" && Number.isInteger(raw.max_tokens) && raw.max_tokens >= 1) {
12475
12564
  budget.maxTokens = raw.max_tokens;
12476
12565
  } else {
12477
- ctx.err([...path22, "max_tokens"], `"budget.max_tokens" must be an integer >= 1.`);
12566
+ ctx.err([...path23, "max_tokens"], `"budget.max_tokens" must be an integer >= 1.`);
12478
12567
  }
12479
12568
  }
12480
12569
  if (raw.max_units !== undefined) {
12481
12570
  if (typeof raw.max_units === "number" && Number.isInteger(raw.max_units) && raw.max_units >= 1) {
12482
12571
  budget.maxUnits = raw.max_units;
12483
12572
  } else {
12484
- ctx.err([...path22, "max_units"], `"budget.max_units" must be an integer >= 1.`);
12573
+ ctx.err([...path23, "max_units"], `"budget.max_units" must be an integer >= 1.`);
12485
12574
  }
12486
12575
  }
12487
12576
  return Object.keys(budget).length > 0 ? budget : undefined;
@@ -12501,49 +12590,49 @@ function parseSteps(ctx, raw) {
12501
12590
  const seenIds = new Map;
12502
12591
  const routeChecks = [];
12503
12592
  raw.forEach((rawStep, index) => {
12504
- const path22 = ["steps", index];
12593
+ const path23 = ["steps", index];
12505
12594
  if (!isRecord(rawStep)) {
12506
- ctx.err(path22, `Step ${index + 1} must be a mapping with an "id".`);
12595
+ ctx.err(path23, `Step ${index + 1} must be a mapping with an "id".`);
12507
12596
  return;
12508
12597
  }
12509
12598
  const label = typeof rawStep.id === "string" && rawStep.id !== "" ? `Step "${rawStep.id}"` : `Step ${index + 1}`;
12510
- checkUnknownKeys(ctx, rawStep, path22, STEP_KEYS, label);
12599
+ checkUnknownKeys(ctx, rawStep, path23, STEP_KEYS, label);
12511
12600
  let id = "";
12512
12601
  if (typeof rawStep.id !== "string" || rawStep.id === "") {
12513
- ctx.err([...path22, "id"], `${label} requires a non-empty string "id".`);
12602
+ ctx.err([...path23, "id"], `${label} requires a non-empty string "id".`);
12514
12603
  } else if (!PROGRAM_STEP_ID_PATTERN.test(rawStep.id)) {
12515
- 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).`);
12604
+ 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).`);
12516
12605
  } else {
12517
12606
  id = rawStep.id;
12518
12607
  const firstIndex = seenIds.get(id);
12519
12608
  if (firstIndex !== undefined) {
12520
- ctx.err([...path22, "id"], `Duplicate step id "${id}" (first used by step ${firstIndex + 1}). Step ids must be unique.`);
12609
+ ctx.err([...path23, "id"], `Duplicate step id "${id}" (first used by step ${firstIndex + 1}). Step ids must be unique.`);
12521
12610
  } else {
12522
12611
  seenIds.set(id, index);
12523
12612
  }
12524
12613
  }
12525
12614
  const declaredKinds = ["map", "route"].filter((kind) => rawStep[kind] !== undefined);
12526
12615
  if (declaredKinds.length > 1) {
12527
- ctx.err(path22, `${label} must declare at most one of "map" or "route" (found ${declaredKinds.join(" + ")}).`);
12616
+ ctx.err(path23, `${label} must declare at most one of "map" or "route" (found ${declaredKinds.join(" + ")}).`);
12528
12617
  }
12529
12618
  const isRoute = rawStep.route !== undefined;
12530
12619
  const isMapStep = rawStep.map !== undefined;
12531
12620
  if (isRoute && rawStep.unit !== undefined) {
12532
- ctx.err(path22, `${label} is a route step and cannot also declare "unit" (route steps dispatch no unit).`);
12621
+ ctx.err(path23, `${label} is a route step and cannot also declare "unit" (route steps dispatch no unit).`);
12533
12622
  }
12534
12623
  if (isMapStep && rawStep.unit !== undefined) {
12535
- ctx.err(path22, `${label} is a map step; the per-item dispatch-override bag belongs at "map.unit", not top-level "unit".`);
12624
+ ctx.err(path23, `${label} is a map step; the per-item dispatch-override bag belongs at "map.unit", not top-level "unit".`);
12536
12625
  }
12537
12626
  if (isRoute && rawStep.inputs !== undefined) {
12538
- ctx.err(path22, `${label} is a route step and cannot declare "inputs" (route steps dispatch no unit).`);
12539
- }
12540
- const unit = rawStep.unit !== undefined && !isRoute && !isMapStep ? parseUnit(ctx, rawStep.unit, [...path22, "unit"], label) : undefined;
12541
- const map = isMapStep ? parseMap(ctx, rawStep.map, [...path22, "map"], label) : undefined;
12542
- const route = isRoute ? parseRoute(ctx, rawStep.route, [...path22, "route"], label, index, routeChecks) : undefined;
12543
- const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...path22, "inputs"], label) : undefined;
12544
- const output = parseSchemaObject(ctx, rawStep.output, [...path22, "output"], `${label} "output"`);
12545
- const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...path22, "gate"], label) : undefined;
12546
- const step = { id, source: ctx.refAt(path22) };
12627
+ ctx.err(path23, `${label} is a route step and cannot declare "inputs" (route steps dispatch no unit).`);
12628
+ }
12629
+ const unit = rawStep.unit !== undefined && !isRoute && !isMapStep ? parseUnit(ctx, rawStep.unit, [...path23, "unit"], label) : undefined;
12630
+ const map = isMapStep ? parseMap(ctx, rawStep.map, [...path23, "map"], label) : undefined;
12631
+ const route = isRoute ? parseRoute(ctx, rawStep.route, [...path23, "route"], label, index, routeChecks) : undefined;
12632
+ const inputs = !isRoute ? parseInputs(ctx, rawStep.inputs, [...path23, "inputs"], label) : undefined;
12633
+ const output = parseSchemaObject(ctx, rawStep.output, [...path23, "output"], `${label} "output"`);
12634
+ const gate = rawStep.gate !== undefined ? parseGate(ctx, rawStep.gate, [...path23, "gate"], label) : undefined;
12635
+ const step = { id, source: ctx.refAt(path23) };
12547
12636
  if (unit)
12548
12637
  step.unit = unit;
12549
12638
  if (map)
@@ -12575,25 +12664,25 @@ function parseSteps(ctx, raw) {
12575
12664
  }
12576
12665
  return steps;
12577
12666
  }
12578
- function parseUnit(ctx, raw, path22, stepLabel) {
12667
+ function parseUnit(ctx, raw, path23, stepLabel) {
12579
12668
  if (!isRecord(raw)) {
12580
- ctx.err(path22, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
12669
+ ctx.err(path23, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
12581
12670
  return;
12582
12671
  }
12583
- checkUnknownKeys(ctx, raw, path22, UNIT_KEYS, `${stepLabel} "unit"`);
12584
- const unit = { source: ctx.refAt(path22) };
12672
+ checkUnknownKeys(ctx, raw, path23, UNIT_KEYS, `${stepLabel} "unit"`);
12673
+ const unit = { source: ctx.refAt(path23) };
12585
12674
  if (raw.exec !== undefined) {
12586
- const exec = parseExec(ctx, raw.exec, [...path22, "exec"], stepLabel);
12675
+ const exec = parseExec(ctx, raw.exec, [...path23, "exec"], stepLabel);
12587
12676
  if (exec !== undefined)
12588
12677
  unit.exec = exec;
12589
12678
  for (const key of UNIT_ENGINE_KEYS) {
12590
12679
  if (raw[key] === undefined)
12591
12680
  continue;
12592
- 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 \u2014 remove one of the two.`);
12681
+ 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 \u2014 remove one of the two.`);
12593
12682
  }
12594
12683
  }
12595
12684
  if (raw.engine !== undefined) {
12596
- const engine = parseEngineName(ctx, raw.engine, [...path22, "engine"], `${stepLabel} "engine"`);
12685
+ const engine = parseEngineName(ctx, raw.engine, [...path23, "engine"], `${stepLabel} "engine"`);
12597
12686
  if (engine !== undefined)
12598
12687
  unit.engine = engine;
12599
12688
  }
@@ -12601,21 +12690,21 @@ function parseUnit(ctx, raw, path22, stepLabel) {
12601
12690
  if (typeof raw.model === "string" && raw.model.trim() !== "")
12602
12691
  unit.model = raw.model.trim();
12603
12692
  else
12604
- ctx.err([...path22, "model"], `${stepLabel} "model" must be a non-empty string (a model alias or exact id).`);
12693
+ ctx.err([...path23, "model"], `${stepLabel} "model" must be a non-empty string (a model alias or exact id).`);
12605
12694
  }
12606
- const llm = parseLlmOverrides(ctx, raw.llm, [...path22, "llm"], `${stepLabel} "llm"`);
12695
+ const llm = parseLlmOverrides(ctx, raw.llm, [...path23, "llm"], `${stepLabel} "llm"`);
12607
12696
  if (llm !== undefined)
12608
12697
  unit.llm = llm;
12609
- const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path22, "timeout"], `${stepLabel} "timeout"`);
12698
+ const timeoutMs = parseTimeoutField(ctx, raw.timeout, [...path23, "timeout"], `${stepLabel} "timeout"`);
12610
12699
  if (timeoutMs !== undefined)
12611
12700
  unit.timeoutMs = timeoutMs;
12612
- const retry = parseRetry(ctx, raw.retry, [...path22, "retry"], stepLabel);
12701
+ const retry = parseRetry(ctx, raw.retry, [...path23, "retry"], stepLabel);
12613
12702
  if (retry !== undefined)
12614
12703
  unit.retry = retry;
12615
- const onError = parseEnumField(ctx, raw.on_error, [...path22, "on_error"], `${stepLabel} "on_error"`, PROGRAM_ON_ERROR);
12704
+ const onError = parseEnumField(ctx, raw.on_error, [...path23, "on_error"], `${stepLabel} "on_error"`, PROGRAM_ON_ERROR);
12616
12705
  if (onError !== undefined)
12617
12706
  unit.onError = onError;
12618
- const output = parseSchemaObject(ctx, raw.output, [...path22, "output"], `${stepLabel} unit "output"`);
12707
+ const output = parseSchemaObject(ctx, raw.output, [...path23, "output"], `${stepLabel} unit "output"`);
12619
12708
  if (output !== undefined)
12620
12709
  unit.output = output;
12621
12710
  if (raw.env !== undefined) {
@@ -12623,87 +12712,87 @@ function parseUnit(ctx, raw, path22, stepLabel) {
12623
12712
  const envRefs = raw.env.map((entry) => entry.trim());
12624
12713
  const duplicate = envRefs.find((ref, i) => envRefs.indexOf(ref) !== i);
12625
12714
  if (duplicate !== undefined) {
12626
- ctx.err([...path22, "env"], `${stepLabel} "env" contains a duplicate entry: "${duplicate}".`);
12715
+ ctx.err([...path23, "env"], `${stepLabel} "env" contains a duplicate entry: "${duplicate}".`);
12627
12716
  } else {
12628
12717
  unit.env = envRefs;
12629
12718
  }
12630
12719
  } else {
12631
- ctx.err([...path22, "env"], `${stepLabel} "env" must be a list of non-empty env asset refs.`);
12720
+ ctx.err([...path23, "env"], `${stepLabel} "env" must be a list of non-empty env asset refs.`);
12632
12721
  }
12633
12722
  }
12634
- const isolation = parseEnumField(ctx, raw.isolation, [...path22, "isolation"], `${stepLabel} "isolation"`, PROGRAM_ISOLATION_KINDS);
12723
+ const isolation = parseEnumField(ctx, raw.isolation, [...path23, "isolation"], `${stepLabel} "isolation"`, PROGRAM_ISOLATION_KINDS);
12635
12724
  if (isolation !== undefined)
12636
12725
  unit.isolation = isolation;
12637
12726
  return unit;
12638
12727
  }
12639
- function parseExec(ctx, raw, path22, stepLabel) {
12728
+ function parseExec(ctx, raw, path23, stepLabel) {
12640
12729
  if (!isRecord(raw)) {
12641
- ctx.err(path22, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
12730
+ ctx.err(path23, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
12642
12731
  return;
12643
12732
  }
12644
- checkUnknownKeys(ctx, raw, path22, EXEC_KEYS, `${stepLabel} "exec"`);
12645
- const command = parseExecCommand(ctx, raw.command, [...path22, "command"], stepLabel);
12733
+ checkUnknownKeys(ctx, raw, path23, EXEC_KEYS, `${stepLabel} "exec"`);
12734
+ const command = parseExecCommand(ctx, raw.command, [...path23, "command"], stepLabel);
12646
12735
  if (command === undefined)
12647
12736
  return;
12648
12737
  const exec = { command };
12649
- const cwd = parseExecCwd(ctx, raw.cwd, [...path22, "cwd"], stepLabel);
12738
+ const cwd = parseExecCwd(ctx, raw.cwd, [...path23, "cwd"], stepLabel);
12650
12739
  if (cwd !== undefined)
12651
12740
  exec.cwd = cwd;
12652
- const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...path22, "pass_env"], stepLabel);
12741
+ const passEnv = parseExecPassEnv(ctx, raw.pass_env, [...path23, "pass_env"], stepLabel);
12653
12742
  if (passEnv !== undefined)
12654
12743
  exec.passEnv = passEnv;
12655
12744
  return exec;
12656
12745
  }
12657
- function parseExecPassEnv(ctx, raw, path22, stepLabel) {
12746
+ function parseExecPassEnv(ctx, raw, path23, stepLabel) {
12658
12747
  if (raw === undefined)
12659
12748
  return;
12660
12749
  if (!Array.isArray(raw) || raw.length === 0) {
12661
- 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 \u2014 use "env:" bindings for those.`);
12750
+ 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 \u2014 use "env:" bindings for those.`);
12662
12751
  return;
12663
12752
  }
12664
12753
  const names = [];
12665
12754
  for (const [index, entry] of raw.entries()) {
12666
12755
  if (typeof entry !== "string" || !WORKFLOW_ENV_VAR_NAME_PATTERN.test(entry)) {
12667
- ctx.err(path22, `${stepLabel} "exec.pass_env[${index}]" must be an environment variable name matching ` + `${WORKFLOW_ENV_VAR_NAME_PATTERN.source}.`);
12756
+ ctx.err(path23, `${stepLabel} "exec.pass_env[${index}]" must be an environment variable name matching ` + `${WORKFLOW_ENV_VAR_NAME_PATTERN.source}.`);
12668
12757
  return;
12669
12758
  }
12670
12759
  if (names.includes(entry)) {
12671
- ctx.err(path22, `${stepLabel} "exec.pass_env" lists "${entry}" more than once.`);
12760
+ ctx.err(path23, `${stepLabel} "exec.pass_env" lists "${entry}" more than once.`);
12672
12761
  return;
12673
12762
  }
12674
12763
  names.push(entry);
12675
12764
  }
12676
12765
  return names;
12677
12766
  }
12678
- function parseExecCommand(ctx, raw, path22, stepLabel) {
12767
+ function parseExecCommand(ctx, raw, path23, stepLabel) {
12679
12768
  if (!Array.isArray(raw) || raw.length === 0) {
12680
- 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 \u2014 the command is spawned directly, never through a shell.`);
12769
+ 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 \u2014 the command is spawned directly, never through a shell.`);
12681
12770
  return;
12682
12771
  }
12683
12772
  const argv = [];
12684
12773
  for (const [index, entry] of raw.entries()) {
12685
12774
  if (typeof entry !== "string" || entry === "") {
12686
- ctx.err(path22, `${stepLabel} "exec.command[${index}]" must be a non-empty string.`);
12775
+ ctx.err(path23, `${stepLabel} "exec.command[${index}]" must be a non-empty string.`);
12687
12776
  return;
12688
12777
  }
12689
12778
  if (entry.includes("\x00")) {
12690
- ctx.err([...path22, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
12779
+ ctx.err([...path23, index], `${stepLabel} "exec.command[${index}]" may not contain NUL bytes.`);
12691
12780
  return;
12692
12781
  }
12693
12782
  argv.push(entry);
12694
12783
  }
12695
12784
  return argv;
12696
12785
  }
12697
- function parseExecCwd(ctx, raw, path22, stepLabel) {
12786
+ function parseExecCwd(ctx, raw, path23, stepLabel) {
12698
12787
  if (raw === undefined)
12699
12788
  return;
12700
12789
  if (typeof raw !== "string" || raw.trim() === "") {
12701
- ctx.err(path22, `${stepLabel} "exec.cwd" must be a non-empty relative path inside the unit's working directory.`);
12790
+ ctx.err(path23, `${stepLabel} "exec.cwd" must be a non-empty relative path inside the unit's working directory.`);
12702
12791
  return;
12703
12792
  }
12704
12793
  const value = raw.trim();
12705
12794
  if (!isContainedRelativePath(value)) {
12706
- ctx.err(path22, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` + `directory \u2014 absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
12795
+ ctx.err(path23, `${stepLabel} "exec.cwd" (${JSON.stringify(value)}) must be a RELATIVE path inside the unit's working ` + `directory \u2014 absolute paths, Windows drive letters, "~", and ".." segments are rejected.`);
12707
12796
  return;
12708
12797
  }
12709
12798
  if (ctx.validateExecCwd) {
@@ -12711,7 +12800,7 @@ function parseExecCwd(ctx, raw, path22, stepLabel) {
12711
12800
  if (!semantic.ok) {
12712
12801
  ctx.errors.push({
12713
12802
  code: semantic.code,
12714
- line: ctx.lineAt(path22),
12803
+ line: ctx.lineAt(path23),
12715
12804
  message: semantic.message
12716
12805
  });
12717
12806
  return;
@@ -12720,29 +12809,29 @@ function parseExecCwd(ctx, raw, path22, stepLabel) {
12720
12809
  }
12721
12810
  return value;
12722
12811
  }
12723
- function parseMap(ctx, raw, path22, stepLabel) {
12812
+ function parseMap(ctx, raw, path23, stepLabel) {
12724
12813
  if (!isRecord(raw)) {
12725
- ctx.err(path22, `${stepLabel} "map" must be a mapping with an "over" key.`);
12814
+ ctx.err(path23, `${stepLabel} "map" must be a mapping with an "over" key.`);
12726
12815
  return;
12727
12816
  }
12728
- checkUnknownKeys(ctx, raw, path22, MAP_KEYS, `${stepLabel} "map"`);
12817
+ checkUnknownKeys(ctx, raw, path23, MAP_KEYS, `${stepLabel} "map"`);
12729
12818
  let over = "";
12730
12819
  if (typeof raw.over === "string" && raw.over.trim() !== "") {
12731
12820
  over = raw.over.trim();
12732
- checkReferenceSyntax(ctx, over, [...path22, "over"], `${stepLabel} "over"`);
12821
+ checkReferenceSyntax(ctx, over, [...path23, "over"], `${stepLabel} "over"`);
12733
12822
  } else {
12734
- ctx.err([...path22, "over"], `${stepLabel} "map" requires "over": a reference naming the item list (e.g. steps.discover.output.files).`);
12823
+ ctx.err([...path23, "over"], `${stepLabel} "map" requires "over": a reference naming the item list (e.g. steps.discover.output.files).`);
12735
12824
  }
12736
12825
  let concurrency;
12737
12826
  if (raw.concurrency !== undefined) {
12738
12827
  if (typeof raw.concurrency === "number" && Number.isInteger(raw.concurrency) && raw.concurrency > 0) {
12739
12828
  concurrency = Math.min(raw.concurrency, WORKFLOW_MAX_CONCURRENCY);
12740
12829
  } else {
12741
- ctx.err([...path22, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
12830
+ ctx.err([...path23, "concurrency"], `${stepLabel} "concurrency" must be a positive integer.`);
12742
12831
  }
12743
12832
  }
12744
- const reducer = parseEnumField(ctx, raw.reducer, [...path22, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
12745
- const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path22, "unit"], stepLabel) : undefined;
12833
+ const reducer = parseEnumField(ctx, raw.reducer, [...path23, "reducer"], `${stepLabel} "reducer"`, PROGRAM_REDUCERS);
12834
+ const unit = raw.unit !== undefined ? parseUnit(ctx, raw.unit, [...path23, "unit"], stepLabel) : undefined;
12746
12835
  const map = { over };
12747
12836
  if (concurrency !== undefined)
12748
12837
  map.concurrency = concurrency;
@@ -12752,21 +12841,21 @@ function parseMap(ctx, raw, path22, stepLabel) {
12752
12841
  map.unit = unit;
12753
12842
  return map;
12754
12843
  }
12755
- function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
12844
+ function parseRoute(ctx, raw, path23, stepLabel, stepIndex, routeChecks) {
12756
12845
  if (!isRecord(raw)) {
12757
- ctx.err(path22, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
12846
+ ctx.err(path23, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
12758
12847
  return;
12759
12848
  }
12760
- checkUnknownKeys(ctx, raw, path22, ROUTE_KEYS, `${stepLabel} "route"`);
12849
+ checkUnknownKeys(ctx, raw, path23, ROUTE_KEYS, `${stepLabel} "route"`);
12761
12850
  let input = "";
12762
12851
  if (typeof raw.input === "string" && raw.input.trim() !== "") {
12763
12852
  input = raw.input.trim();
12764
- checkReferenceSyntax(ctx, input, [...path22, "input"], `${stepLabel} "route.input"`);
12853
+ checkReferenceSyntax(ctx, input, [...path23, "input"], `${stepLabel} "route.input"`);
12765
12854
  } else {
12766
- ctx.err([...path22, "input"], `${stepLabel} "route" requires "input": a reference naming the value to route on.`);
12855
+ ctx.err([...path23, "input"], `${stepLabel} "route" requires "input": a reference naming the value to route on.`);
12767
12856
  }
12768
12857
  const check = { stepIndex, stepLabel, branches: [] };
12769
- const whenPath = [...path22, "when"];
12858
+ const whenPath = [...path23, "when"];
12770
12859
  if (!Array.isArray(raw.when) || raw.when.length === 0) {
12771
12860
  ctx.err(whenPath, `${stepLabel} "route" requires "when": a non-empty list of { match, step } branches (e.g. when: [{ match: pass, step: ship }]).`);
12772
12861
  } else {
@@ -12807,9 +12896,9 @@ function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
12807
12896
  if (raw.default !== undefined) {
12808
12897
  if (typeof raw.default === "string" && raw.default.trim() !== "") {
12809
12898
  defaultStepId = raw.default.trim();
12810
- check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...path22, "default"]) };
12899
+ check.defaultTarget = { stepId: defaultStepId, line: ctx.lineAt([...path23, "default"]) };
12811
12900
  } else {
12812
- ctx.err([...path22, "default"], `${stepLabel} "route.default" must be a step id string.`);
12901
+ ctx.err([...path23, "default"], `${stepLabel} "route.default" must be a step id string.`);
12813
12902
  }
12814
12903
  }
12815
12904
  routeChecks.push(check);
@@ -12818,70 +12907,70 @@ function parseRoute(ctx, raw, path22, stepLabel, stepIndex, routeChecks) {
12818
12907
  route.defaultStepId = defaultStepId;
12819
12908
  return route;
12820
12909
  }
12821
- function parseInputs(ctx, raw, path22, stepLabel) {
12910
+ function parseInputs(ctx, raw, path23, stepLabel) {
12822
12911
  if (raw === undefined)
12823
12912
  return;
12824
12913
  if (!Array.isArray(raw) || raw.length === 0) {
12825
- ctx.err(path22, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
12914
+ ctx.err(path23, `${stepLabel} "inputs" must be a non-empty list of reference strings.`);
12826
12915
  return;
12827
12916
  }
12828
12917
  const out = [];
12829
12918
  const seen = new Set;
12830
12919
  raw.forEach((entry, i) => {
12831
12920
  if (typeof entry !== "string" || entry.trim() === "") {
12832
- ctx.err([...path22, i], `${stepLabel} "inputs[${i}]" must be a non-empty reference string.`);
12921
+ ctx.err([...path23, i], `${stepLabel} "inputs[${i}]" must be a non-empty reference string.`);
12833
12922
  return;
12834
12923
  }
12835
12924
  const value = entry.trim();
12836
12925
  if (seen.has(value)) {
12837
- ctx.err([...path22, i], `${stepLabel} "inputs[${i}]" duplicates an earlier entry: "${value}".`);
12926
+ ctx.err([...path23, i], `${stepLabel} "inputs[${i}]" duplicates an earlier entry: "${value}".`);
12838
12927
  return;
12839
12928
  }
12840
12929
  seen.add(value);
12841
- checkReferenceSyntax(ctx, value, [...path22, i], `${stepLabel} "inputs[${i}]"`);
12930
+ checkReferenceSyntax(ctx, value, [...path23, i], `${stepLabel} "inputs[${i}]"`);
12842
12931
  out.push(value);
12843
12932
  });
12844
12933
  return out.length > 0 ? out : undefined;
12845
12934
  }
12846
- function parseGate(ctx, raw, path22, stepLabel) {
12935
+ function parseGate(ctx, raw, path23, stepLabel) {
12847
12936
  if (!isRecord(raw)) {
12848
- ctx.err(path22, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
12937
+ ctx.err(path23, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
12849
12938
  return;
12850
12939
  }
12851
- checkUnknownKeys(ctx, raw, path22, GATE_KEYS, `${stepLabel} "gate"`);
12940
+ checkUnknownKeys(ctx, raw, path23, GATE_KEYS, `${stepLabel} "gate"`);
12852
12941
  const gate = {};
12853
12942
  if (raw.max_loops !== undefined) {
12854
12943
  if (typeof raw.max_loops === "number" && Number.isInteger(raw.max_loops) && raw.max_loops >= 1) {
12855
12944
  gate.maxLoops = raw.max_loops;
12856
12945
  } else {
12857
- ctx.err([...path22, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
12946
+ ctx.err([...path23, "max_loops"], `${stepLabel} "gate.max_loops" must be an integer of at least 1.`);
12858
12947
  }
12859
12948
  }
12860
12949
  return gate;
12861
12950
  }
12862
- function parseEngineName(ctx, raw, path22, label) {
12951
+ function parseEngineName(ctx, raw, path23, label) {
12863
12952
  if (typeof raw !== "string" || raw.trim() === "") {
12864
- ctx.err(path22, `${label} must be a non-empty engine name.`);
12953
+ ctx.err(path23, `${label} must be a non-empty engine name.`);
12865
12954
  return;
12866
12955
  }
12867
12956
  const name = raw.trim();
12868
12957
  if (!WORKFLOW_ENGINE_NAME_PATTERN.test(name) || name.length > WORKFLOW_MAX_ENGINE_NAME_LENGTH) {
12869
- 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.`);
12958
+ 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.`);
12870
12959
  return;
12871
12960
  }
12872
12961
  return name;
12873
12962
  }
12874
- function parseRetry(ctx, raw, path22, stepLabel) {
12963
+ function parseRetry(ctx, raw, path23, stepLabel) {
12875
12964
  if (raw === undefined)
12876
12965
  return;
12877
12966
  if (!isRecord(raw)) {
12878
- ctx.err(path22, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, \u2026] }.`);
12967
+ ctx.err(path23, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, \u2026] }.`);
12879
12968
  return;
12880
12969
  }
12881
- checkUnknownKeys(ctx, raw, path22, RETRY_KEYS, `${stepLabel} "retry"`);
12970
+ checkUnknownKeys(ctx, raw, path23, RETRY_KEYS, `${stepLabel} "retry"`);
12882
12971
  let ok = true;
12883
12972
  if (!(typeof raw.max === "number" && Number.isInteger(raw.max) && raw.max >= 0)) {
12884
- ctx.err([...path22, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
12973
+ ctx.err([...path23, "max"], `${stepLabel} "retry.max" is required and must be a non-negative integer.`);
12885
12974
  ok = false;
12886
12975
  }
12887
12976
  const on = [];
@@ -12890,27 +12979,27 @@ function parseRetry(ctx, raw, path22, stepLabel) {
12890
12979
  if (typeof reason === "string" && PROGRAM_RETRY_REASONS.includes(reason)) {
12891
12980
  on.push(reason);
12892
12981
  } else {
12893
- ctx.err([...path22, "on", i], `${stepLabel} "retry.on" has unknown failure reason ${JSON.stringify(reason)}. Valid reasons: ${PROGRAM_RETRY_REASONS.join(", ")}.`);
12982
+ ctx.err([...path23, "on", i], `${stepLabel} "retry.on" has unknown failure reason ${JSON.stringify(reason)}. Valid reasons: ${PROGRAM_RETRY_REASONS.join(", ")}.`);
12894
12983
  ok = false;
12895
12984
  }
12896
12985
  });
12897
12986
  } else {
12898
- ctx.err([...path22, "on"], `${stepLabel} "retry.on" is required and must be a non-empty list of failure reasons (${PROGRAM_RETRY_REASONS.join(", ")}).`);
12987
+ ctx.err([...path23, "on"], `${stepLabel} "retry.on" is required and must be a non-empty list of failure reasons (${PROGRAM_RETRY_REASONS.join(", ")}).`);
12899
12988
  ok = false;
12900
12989
  }
12901
12990
  return ok ? { max: raw.max, on } : undefined;
12902
12991
  }
12903
- function parseTimeoutField(ctx, raw, path22, label) {
12992
+ function parseTimeoutField(ctx, raw, path23, label) {
12904
12993
  if (raw === undefined)
12905
12994
  return;
12906
12995
  if (typeof raw === "number") {
12907
12996
  if (Number.isInteger(raw) && raw > 0)
12908
- return checkTimeoutCeiling(ctx, raw, path22, label, String(raw));
12909
- ctx.err(path22, `${label} has a non-positive timeout ${JSON.stringify(raw)}. ${TIMEOUT_HINT}.`);
12997
+ return checkTimeoutCeiling(ctx, raw, path23, label, String(raw));
12998
+ ctx.err(path23, `${label} has a non-positive timeout ${JSON.stringify(raw)}. ${TIMEOUT_HINT}.`);
12910
12999
  return;
12911
13000
  }
12912
13001
  if (typeof raw !== "string") {
12913
- ctx.err(path22, `${label} must be a duration string. ${TIMEOUT_HINT}.`);
13002
+ ctx.err(path23, `${label} must be a duration string. ${TIMEOUT_HINT}.`);
12914
13003
  return;
12915
13004
  }
12916
13005
  const value = raw.trim().toLowerCase();
@@ -12918,37 +13007,37 @@ function parseTimeoutField(ctx, raw, path22, label) {
12918
13007
  return null;
12919
13008
  const match = value.match(TIMEOUT_VALUE);
12920
13009
  if (!match) {
12921
- ctx.err(path22, `${label} has an invalid timeout "${raw}". ${TIMEOUT_HINT}.`);
13010
+ ctx.err(path23, `${label} has an invalid timeout "${raw}". ${TIMEOUT_HINT}.`);
12922
13011
  return;
12923
13012
  }
12924
13013
  const n = Number.parseInt(match[1], 10);
12925
13014
  const unit = match[2] ?? "ms";
12926
13015
  const timeoutMs = unit === "m" ? n * 60000 : unit === "s" ? n * 1000 : n;
12927
13016
  if (timeoutMs <= 0) {
12928
- ctx.err(path22, `${label} has a non-positive timeout "${raw}". Use a positive duration or "none".`);
13017
+ ctx.err(path23, `${label} has a non-positive timeout "${raw}". Use a positive duration or "none".`);
12929
13018
  return;
12930
13019
  }
12931
- return checkTimeoutCeiling(ctx, timeoutMs, path22, label, raw);
13020
+ return checkTimeoutCeiling(ctx, timeoutMs, path23, label, raw);
12932
13021
  }
12933
- function checkTimeoutCeiling(ctx, timeoutMs, path22, label, raw) {
13022
+ function checkTimeoutCeiling(ctx, timeoutMs, path23, label, raw) {
12934
13023
  if (timeoutMs <= WORKFLOW_MAX_TIMEOUT_MS)
12935
13024
  return timeoutMs;
12936
- 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.`);
13025
+ 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.`);
12937
13026
  return;
12938
13027
  }
12939
- function parseEnumField(ctx, raw, path22, label, allowed) {
13028
+ function parseEnumField(ctx, raw, path23, label, allowed) {
12940
13029
  if (raw === undefined)
12941
13030
  return;
12942
13031
  if (typeof raw === "string" && allowed.includes(raw))
12943
13032
  return raw;
12944
- ctx.err(path22, `${label} must be one of: ${allowed.join(" | ")} (got ${JSON.stringify(raw)}).`);
13033
+ ctx.err(path23, `${label} must be one of: ${allowed.join(" | ")} (got ${JSON.stringify(raw)}).`);
12945
13034
  return;
12946
13035
  }
12947
- function parseLlmOverrides(ctx, raw, path22, label) {
13036
+ function parseLlmOverrides(ctx, raw, path23, label) {
12948
13037
  if (raw === undefined)
12949
13038
  return;
12950
13039
  if (!isRecord(raw)) {
12951
- ctx.err(path22, `${label} must be a mapping of LLM invocation overrides.`);
13040
+ ctx.err(path23, `${label} must be a mapping of LLM invocation overrides.`);
12952
13041
  return;
12953
13042
  }
12954
13043
  const keys2 = [
@@ -12960,36 +13049,36 @@ function parseLlmOverrides(ctx, raw, path22, label) {
12960
13049
  "enable_thinking",
12961
13050
  "reasoning_effort"
12962
13051
  ];
12963
- checkUnknownKeys(ctx, raw, path22, keys2, label);
13052
+ checkUnknownKeys(ctx, raw, path23, keys2, label);
12964
13053
  const result = {};
12965
13054
  if (raw.temperature !== undefined) {
12966
13055
  if (typeof raw.temperature === "number" && Number.isFinite(raw.temperature))
12967
13056
  result.temperature = raw.temperature;
12968
13057
  else
12969
- ctx.err([...path22, "temperature"], `${label}.temperature must be a finite number.`);
13058
+ ctx.err([...path23, "temperature"], `${label}.temperature must be a finite number.`);
12970
13059
  }
12971
13060
  if (raw.max_tokens !== undefined) {
12972
13061
  if (typeof raw.max_tokens === "number" && Number.isInteger(raw.max_tokens) && raw.max_tokens > 0) {
12973
13062
  result.maxTokens = raw.max_tokens;
12974
13063
  } else
12975
- ctx.err([...path22, "max_tokens"], `${label}.max_tokens must be a positive integer.`);
13064
+ ctx.err([...path23, "max_tokens"], `${label}.max_tokens must be a positive integer.`);
12976
13065
  }
12977
13066
  if (raw.supports_json_schema !== undefined) {
12978
13067
  if (typeof raw.supports_json_schema === "boolean")
12979
13068
  result.supportsJsonSchema = raw.supports_json_schema;
12980
13069
  else
12981
- ctx.err([...path22, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
13070
+ ctx.err([...path23, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
12982
13071
  }
12983
13072
  if (raw.extra_params !== undefined) {
12984
13073
  if (!isRecord(raw.extra_params)) {
12985
- ctx.err([...path22, "extra_params"], `${label}.extra_params must be a JSON object.`);
13074
+ ctx.err([...path23, "extra_params"], `${label}.extra_params must be a JSON object.`);
12986
13075
  } else {
12987
13076
  const issues = validateExtraParams(raw.extra_params);
12988
13077
  for (const issue of issues) {
12989
- ctx.err([...path22, "extra_params", ...issue.path], `${formatExtraParamsIssue(`${label}.extra_params`, issue)}.`);
13078
+ ctx.err([...path23, "extra_params", ...issue.path], `${formatExtraParamsIssue(`${label}.extra_params`, issue)}.`);
12990
13079
  }
12991
13080
  if (jsonBytes(raw.extra_params) > WORKFLOW_MAX_EXTRA_PARAMS_BYTES) {
12992
- ctx.err([...path22, "extra_params"], `${label}.extra_params exceeds the 64 KiB resource limit.`);
13081
+ ctx.err([...path23, "extra_params"], `${label}.extra_params exceeds the 64 KiB resource limit.`);
12993
13082
  }
12994
13083
  if (issues.length === 0 && jsonBytes(raw.extra_params) <= WORKFLOW_MAX_EXTRA_PARAMS_BYTES) {
12995
13084
  result.extraParams = raw.extra_params;
@@ -13000,38 +13089,38 @@ function parseLlmOverrides(ctx, raw, path22, label) {
13000
13089
  if (typeof raw.context_length === "number" && Number.isInteger(raw.context_length) && raw.context_length > 0) {
13001
13090
  result.contextLength = raw.context_length;
13002
13091
  } else
13003
- ctx.err([...path22, "context_length"], `${label}.context_length must be a positive integer.`);
13092
+ ctx.err([...path23, "context_length"], `${label}.context_length must be a positive integer.`);
13004
13093
  }
13005
13094
  if (raw.enable_thinking !== undefined) {
13006
13095
  if (typeof raw.enable_thinking === "boolean")
13007
13096
  result.enableThinking = raw.enable_thinking;
13008
13097
  else
13009
- ctx.err([...path22, "enable_thinking"], `${label}.enable_thinking must be a boolean.`);
13098
+ ctx.err([...path23, "enable_thinking"], `${label}.enable_thinking must be a boolean.`);
13010
13099
  }
13011
13100
  if (raw.reasoning_effort !== undefined) {
13012
13101
  if (typeof raw.reasoning_effort === "string" && raw.reasoning_effort.trim().length > 0) {
13013
13102
  result.reasoningEffort = raw.reasoning_effort;
13014
13103
  } else
13015
- ctx.err([...path22, "reasoning_effort"], `${label}.reasoning_effort must be a non-empty string.`);
13104
+ ctx.err([...path23, "reasoning_effort"], `${label}.reasoning_effort must be a non-empty string.`);
13016
13105
  }
13017
13106
  return Object.keys(result).length > 0 ? result : undefined;
13018
13107
  }
13019
- function parseSchemaObject(ctx, raw, path22, label) {
13108
+ function parseSchemaObject(ctx, raw, path23, label) {
13020
13109
  if (raw === undefined)
13021
13110
  return;
13022
13111
  if (!isRecord(raw)) {
13023
- ctx.err(path22, `${label} must be a JSON Schema object (e.g. { type: object, properties: { \u2026 } }).`);
13112
+ ctx.err(path23, `${label} must be a JSON Schema object (e.g. { type: object, properties: { \u2026 } }).`);
13024
13113
  return;
13025
13114
  }
13026
13115
  if (jsonBytes(raw) > WORKFLOW_MAX_SCHEMA_BYTES) {
13027
- ctx.err(path22, `${label} exceeds the 256 KiB resource limit.`);
13116
+ ctx.err(path23, `${label} exceeds the 256 KiB resource limit.`);
13028
13117
  }
13029
- checkSchemaDefinition(ctx, raw, path22, label);
13118
+ checkSchemaDefinition(ctx, raw, path23, label);
13030
13119
  return raw;
13031
13120
  }
13032
- function checkSchemaDefinition(ctx, schema, path22, label) {
13121
+ function checkSchemaDefinition(ctx, schema, path23, label) {
13033
13122
  for (const issue of checkJsonSchemaDefinition(schema)) {
13034
- const issuePath = [...path22, ...issue.path];
13123
+ const issuePath = [...path23, ...issue.path];
13035
13124
  if (issue.kind === "unsupported") {
13036
13125
  ctx.err(issuePath, `${label} (at ${issue.pointer}): ${issue.message}. Supported JSON Schema keywords: ` + `${JSON_SCHEMA_SUBSET_SUPPORTED_KEYWORDS}.`);
13037
13126
  } else {
@@ -13039,15 +13128,15 @@ function checkSchemaDefinition(ctx, schema, path22, label) {
13039
13128
  }
13040
13129
  }
13041
13130
  }
13042
- function checkReferenceSyntax(ctx, text, path22, label) {
13131
+ function checkReferenceSyntax(ctx, text, path23, label) {
13043
13132
  const result = parseReference(text);
13044
13133
  if (!result.ok)
13045
- ctx.err(path22, `${label}: ${result.message}`);
13134
+ ctx.err(path23, `${label}: ${result.message}`);
13046
13135
  }
13047
- function checkUnknownKeys(ctx, obj, path22, allowed, label) {
13136
+ function checkUnknownKeys(ctx, obj, path23, allowed, label) {
13048
13137
  for (const key of Object.keys(obj)) {
13049
13138
  if (!allowed.includes(key)) {
13050
- ctx.err([...path22, key], `Unknown ${label} key "${key}". Allowed keys: ${allowed.join(", ")}.`);
13139
+ ctx.err([...path23, key], `Unknown ${label} key "${key}". Allowed keys: ${allowed.join(", ")}.`);
13051
13140
  }
13052
13141
  }
13053
13142
  }
@@ -13107,7 +13196,7 @@ var init_parser = __esm(() => {
13107
13196
  });
13108
13197
 
13109
13198
  // src/workflows/source-ir/result.ts
13110
- function sourceFailureResult(cause, path22) {
13199
+ function sourceFailureResult(cause, path23) {
13111
13200
  if (cause instanceof WorkflowSourceFailure)
13112
13201
  return { ok: false, errors: [cause.error] };
13113
13202
  return {
@@ -13116,7 +13205,7 @@ function sourceFailureResult(cause, path22) {
13116
13205
  {
13117
13206
  code: "invalid-workflow-source",
13118
13207
  message: cause instanceof Error ? cause.message : String(cause),
13119
- path: path22,
13208
+ path: path23,
13120
13209
  line: 1
13121
13210
  }
13122
13211
  ]
@@ -13767,7 +13856,7 @@ var init_triggers = __esm(() => {
13767
13856
  });
13768
13857
 
13769
13858
  // src/workflows/source-ir/compile.ts
13770
- import path22 from "path";
13859
+ import path23 from "path";
13771
13860
  function compileGithubWorkflowSource(source, options) {
13772
13861
  try {
13773
13862
  return {
@@ -13851,7 +13940,7 @@ function compileMarkdownWorkflowSource(source, options) {
13851
13940
  }
13852
13941
  }
13853
13942
  function compileWorkflowSource(source, options) {
13854
- const extension = path22.extname(options.path).toLowerCase();
13943
+ const extension = path23.extname(options.path).toLowerCase();
13855
13944
  if (extension === ".md")
13856
13945
  return compileMarkdownWorkflowSource(source, options);
13857
13946
  if (extension === ".yml")
@@ -13929,7 +14018,7 @@ function markdownName(source, filePath) {
13929
14018
  const title = body.match(/^#\s+(.+?)\s*$/m)?.[1]?.trim();
13930
14019
  if (title)
13931
14020
  return title;
13932
- return path22.basename(filePath, path22.extname(filePath));
14021
+ return path23.basename(filePath, path23.extname(filePath));
13933
14022
  }
13934
14023
  function wholeSourceSpan2(source, filePath) {
13935
14024
  return { path: filePath, start: 1, end: Math.max(1, source.split(/\r?\n/).length) };
@@ -67988,13 +68077,13 @@ function flattenForText(value, path, lines) {
67988
68077
  }
67989
68078
 
67990
68079
  // src/output/html-render.ts
67991
- import path4 from "path";
68080
+ import path6 from "path";
67992
68081
  // src/runtime.ts
67993
68082
  import { spawn as nodeSpawn, spawnSync as nodeSpawnSync } from "child_process";
67994
68083
  init_common();
67995
68084
  import { createWriteStream, statfsSync } from "fs";
67996
68085
  import { createRequire } from "module";
67997
- import path3 from "path";
68086
+ import path5 from "path";
67998
68087
  import { Readable } from "stream";
67999
68088
  import { pipeline } from "stream/promises";
68000
68089
  import { fileURLToPath } from "url";
@@ -68080,11 +68169,11 @@ async function writeResponseToFileCapped(filePath, res, options) {
68080
68169
  }
68081
68170
  }
68082
68171
  function getDirname(importMetaUrl) {
68083
- return path3.dirname(fileURLToPath(importMetaUrl));
68172
+ return path5.dirname(fileURLToPath(importMetaUrl));
68084
68173
  }
68085
- function statfsType(path4) {
68174
+ function statfsType(path6) {
68086
68175
  try {
68087
- return statfsSync(path4).type;
68176
+ return statfsSync(path6).type;
68088
68177
  } catch {
68089
68178
  return;
68090
68179
  }
@@ -68111,7 +68200,7 @@ function toBuffer(data) {
68111
68200
  }
68112
68201
 
68113
68202
  // src/output/html-render.ts
68114
- var TEMPLATES_DIR = path4.join(getDirname(import.meta.url), "../assets/templates/html");
68203
+ var TEMPLATES_DIR = path6.join(getDirname(import.meta.url), "../assets/templates/html");
68115
68204
 
68116
68205
  // src/output/command-registry.ts
68117
68206
  function createCommandRegistry() {
@@ -68696,6 +68785,7 @@ var PASSTHROUGH_COMMANDS = [
68696
68785
  "task-run",
68697
68786
  "task-sync",
68698
68787
  "task-sync-dry-run",
68788
+ "task-validate",
68699
68789
  "update",
68700
68790
  "upgrade",
68701
68791
  "workflow-abandon",
@@ -69281,16 +69371,16 @@ function formatConfigPlain(r) {
69281
69371
  const lines = [];
69282
69372
  const walk = (obj, prefix) => {
69283
69373
  for (const [k, v] of Object.entries(obj)) {
69284
- const path5 = prefix ? `${prefix}.${k}` : k;
69374
+ const path7 = prefix ? `${prefix}.${k}` : k;
69285
69375
  if (v === null || v === undefined) {
69286
- lines.push(`${path5}=`);
69376
+ lines.push(`${path7}=`);
69287
69377
  } else if (Array.isArray(v)) {
69288
- lines.push(`${path5}=${JSON.stringify(v)}`);
69378
+ lines.push(`${path7}=${JSON.stringify(v)}`);
69289
69379
  } else if (typeof v === "object") {
69290
- walk(v, path5);
69380
+ walk(v, path7);
69291
69381
  } else {
69292
- const rendered = typeof v === "string" && /^registries\.\d+\.url$/u.test(path5) ? formatRegistryUrl(v) : String(v);
69293
- lines.push(`${path5}=${rendered}`);
69382
+ const rendered = typeof v === "string" && /^registries\.\d+\.url$/u.test(path7) ? formatRegistryUrl(v) : String(v);
69383
+ lines.push(`${path7}=${rendered}`);
69294
69384
  }
69295
69385
  }
69296
69386
  };
@@ -70798,27 +70888,7 @@ var GLOBAL_OUTPUT_ARGS = {
70798
70888
  init_errors();
70799
70889
 
70800
70890
  // scripts/akm-migrate/help.txt
70801
- var help_default = `Usage: akm-migrate <command> [options]
70802
-
70803
- The one migration tool for an akm installation. Every historical shape akm
70804
- has ever written lives here; the CLI proper reads only current schemas.
70805
- \`status\` and \`apply\` run every step, in order, and print one combined JSON
70806
- plan (exit 1 when any step is blocked):
70807
-
70808
- 1. legacy config \`extraParams\` keys lifted onto first-class engine fields
70809
- 2. pending state.db migrations, historical-destructive ones included,
70810
- with a verified sibling safety copy (the only path that admits them)
70811
- 3. task-v2 files to task v3, then task-v3 files to task source v4
70812
- 4. superseded pre-0.9.0 \`.akm\` residue and stale filesystem transactions
70813
-
70814
- \`akm migrate status|apply\` wraps this executable; \`akm upgrade\` runs
70815
- \`apply\` after its install step, so an image that ships akm can put either
70816
- in its entrypoint (a current installation is a no-op).
70817
-
70818
- Commands:
70819
- status Inspect every pending migration without changing anything.
70820
- apply [--dry-run] Back up and apply every pending migration.
70821
- `;
70891
+ 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 \u2014 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";
70822
70892
 
70823
70893
  // scripts/akm-migrate/run-migrate.ts
70824
70894
  init_common();
@@ -70830,14 +70900,14 @@ init_extra_params();
70830
70900
 
70831
70901
  // src/core/config/config-io.ts
70832
70902
  import fs4 from "fs";
70833
- import path8 from "path";
70903
+ import path9 from "path";
70834
70904
  init_common();
70835
70905
  init_errors();
70836
70906
 
70837
70907
  // src/core/file-lock.ts
70838
70908
  import { randomUUID } from "crypto";
70839
70909
  import fs3 from "fs";
70840
- import path7 from "path";
70910
+ import path8 from "path";
70841
70911
 
70842
70912
  // src/storage/database.ts
70843
70913
  import { createRequire as createRequire2 } from "module";
@@ -70861,12 +70931,12 @@ function selectProvider() {
70861
70931
  }
70862
70932
  return provider;
70863
70933
  }
70864
- function openDatabase(path7, opts) {
70865
- return selectProvider().open(path7, opts);
70934
+ function openDatabase(path8, opts) {
70935
+ return selectProvider().open(path8, opts);
70866
70936
  }
70867
- function openBunDatabase(path7, opts) {
70937
+ function openBunDatabase(path8, opts) {
70868
70938
  const { Database: BunDatabase } = loadBunSqlite();
70869
- const db = opts ? new BunDatabase(path7, bunOptions(opts)) : new BunDatabase(path7);
70939
+ const db = opts ? new BunDatabase(path8, bunOptions(opts)) : new BunDatabase(path8);
70870
70940
  return db;
70871
70941
  }
70872
70942
  function bunOptions(opts) {
@@ -70922,7 +70992,7 @@ function loadBetterSqlite3() {
70922
70992
  }
70923
70993
  return betterSqlite3Ctor;
70924
70994
  }
70925
- function openNodeDatabase(path7, opts) {
70995
+ function openNodeDatabase(path8, opts) {
70926
70996
  const BetterSqlite3 = loadBetterSqlite3();
70927
70997
  const options = {};
70928
70998
  if (opts?.readonly !== undefined)
@@ -70931,7 +71001,7 @@ function openNodeDatabase(path7, opts) {
70931
71001
  options.fileMustExist = true;
70932
71002
  let db;
70933
71003
  try {
70934
- db = opts ? new BetterSqlite3(path7, options) : new BetterSqlite3(path7);
71004
+ db = opts ? new BetterSqlite3(path8, options) : new BetterSqlite3(path8);
70935
71005
  } catch (err) {
70936
71006
  const raw = err instanceof Error ? err.message : String(err);
70937
71007
  const remedy = abiMismatchRemedy(raw);
@@ -70979,7 +71049,7 @@ function sameIdentity(left, right) {
70979
71049
  return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs;
70980
71050
  }
70981
71051
  function operationMutexPath(lockPath) {
70982
- return path7.join(path7.dirname(lockPath), `.${path7.basename(lockPath)}.operations.sensitive`);
71052
+ return path8.join(path8.dirname(lockPath), `.${path8.basename(lockPath)}.operations.sensitive`);
70983
71053
  }
70984
71054
  function withLockOperationMutex(lockPath, run) {
70985
71055
  const db = openDatabase(operationMutexPath(lockPath));
@@ -71198,14 +71268,14 @@ var MAX_CONFIG_BACKUPS = 5;
71198
71268
  function backupExistingConfig(configPath, now = new Date) {
71199
71269
  if (!fs4.existsSync(configPath))
71200
71270
  return;
71201
- const backupDir = path8.join(getCacheDir(), "config-backups");
71271
+ const backupDir = path9.join(getCacheDir(), "config-backups");
71202
71272
  fs4.mkdirSync(backupDir, { recursive: true, mode: 448 });
71203
71273
  fs4.chmodSync(backupDir, 448);
71204
71274
  const timestamp = now.toISOString().replace(/[.:]/g, "-");
71205
71275
  let sequence = 0;
71206
71276
  let timestamped;
71207
71277
  while (true) {
71208
- timestamped = path8.join(backupDir, `config-${timestamp}${sequence === 0 ? "" : `-${sequence}`}.json`);
71278
+ timestamped = path9.join(backupDir, `config-${timestamp}${sequence === 0 ? "" : `-${sequence}`}.json`);
71209
71279
  try {
71210
71280
  fs4.copyFileSync(configPath, timestamped, fs4.constants.COPYFILE_EXCL);
71211
71281
  break;
@@ -71215,7 +71285,7 @@ function backupExistingConfig(configPath, now = new Date) {
71215
71285
  sequence++;
71216
71286
  }
71217
71287
  }
71218
- const latest = path8.join(backupDir, "config.latest.json");
71288
+ const latest = path9.join(backupDir, "config.latest.json");
71219
71289
  fs4.copyFileSync(configPath, latest);
71220
71290
  fs4.chmodSync(timestamped, 384);
71221
71291
  fs4.chmodSync(latest, 384);
@@ -71236,7 +71306,7 @@ function pruneToNewest(dir, keep, select) {
71236
71306
  return;
71237
71307
  }
71238
71308
  const candidates = entries.filter(select).map((entry) => {
71239
- const full = path8.join(dir, entry.name);
71309
+ const full = path9.join(dir, entry.name);
71240
71310
  let mtime = 0;
71241
71311
  try {
71242
71312
  mtime = fs4.statSync(full).mtimeMs;
@@ -71250,7 +71320,7 @@ function pruneToNewest(dir, keep, select) {
71250
71320
  }
71251
71321
  }
71252
71322
  function getConfigLockPath() {
71253
- return path8.join(getConfigDir(), "config.json.lck");
71323
+ return path9.join(getConfigDir(), "config.json.lck");
71254
71324
  }
71255
71325
  var CONFIG_LOCK_MAX_RETRIES = 40;
71256
71326
  var CONFIG_LOCK_RETRY_DELAY_MS = 50;
@@ -71260,7 +71330,7 @@ function sleepSyncMs(ms) {
71260
71330
  function acquireConfigLock() {
71261
71331
  const lockPath = getConfigLockPath();
71262
71332
  try {
71263
- fs4.mkdirSync(path8.dirname(lockPath), { recursive: true });
71333
+ fs4.mkdirSync(path9.dirname(lockPath), { recursive: true });
71264
71334
  } catch {}
71265
71335
  for (let attempt = 0;attempt < CONFIG_LOCK_MAX_RETRIES; attempt++) {
71266
71336
  try {
@@ -71765,8 +71835,8 @@ function getErrorMap() {
71765
71835
  }
71766
71836
  // node_modules/zod/v3/helpers/parseUtil.js
71767
71837
  var makeIssue = (params) => {
71768
- const { data, path: path9, errorMaps, issueData } = params;
71769
- const fullPath = [...path9, ...issueData.path || []];
71838
+ const { data, path: path10, errorMaps, issueData } = params;
71839
+ const fullPath = [...path10, ...issueData.path || []];
71770
71840
  const fullIssue = {
71771
71841
  ...issueData,
71772
71842
  path: fullPath
@@ -71878,11 +71948,11 @@ var errorUtil;
71878
71948
 
71879
71949
  // node_modules/zod/v3/types.js
71880
71950
  class ParseInputLazyPath {
71881
- constructor(parent, value, path9, key) {
71951
+ constructor(parent, value, path10, key) {
71882
71952
  this._cachedPath = [];
71883
71953
  this.parent = parent;
71884
71954
  this.data = value;
71885
- this._path = path9;
71955
+ this._path = path10;
71886
71956
  this._key = key;
71887
71957
  }
71888
71958
  get path() {
@@ -75390,6 +75460,7 @@ var LlmEngineSchema = exports_external.object({
75390
75460
  endpoint: chatCompletionsEndpoint,
75391
75461
  model: nonEmptyString,
75392
75462
  apiKey: exports_external.string().regex(ENV_REFERENCE_PATTERN, `apiKey must be $VAR or \${VAR}`).optional(),
75463
+ apiKeyFile: nonEmptyString.optional(),
75393
75464
  temperature: exports_external.number().finite().optional(),
75394
75465
  maxTokens: positiveInt.optional(),
75395
75466
  timeoutMs: timeoutMsField,
@@ -75403,6 +75474,13 @@ var LlmEngineSchema = exports_external.object({
75403
75474
  if (key in value)
75404
75475
  ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
75405
75476
  }
75477
+ if (value.apiKey !== undefined && value.apiKeyFile !== undefined) {
75478
+ ctx.addIssue({
75479
+ code: exports_external.ZodIssueCode.custom,
75480
+ path: ["apiKeyFile"],
75481
+ message: "apiKey and apiKeyFile cannot both be set"
75482
+ });
75483
+ }
75406
75484
  });
75407
75485
  var AgentEngineSchema = exports_external.object({
75408
75486
  kind: exports_external.literal("agent"),
@@ -75420,6 +75498,7 @@ var AgentEngineSchema = exports_external.object({
75420
75498
  "provider",
75421
75499
  "endpoint",
75422
75500
  "apiKey",
75501
+ "apiKeyFile",
75423
75502
  "temperature",
75424
75503
  "maxTokens",
75425
75504
  "concurrency",
@@ -76157,7 +76236,7 @@ var AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
76157
76236
  // src/core/config/config-sources.ts
76158
76237
  init_errors();
76159
76238
  import { createHash } from "crypto";
76160
- import path9 from "path";
76239
+ import path10 from "path";
76161
76240
  function bundleComponentConfig(bundle) {
76162
76241
  if (!bundle?.components)
76163
76242
  return;
@@ -76168,7 +76247,20 @@ function bundleComponentConfig(bundle) {
76168
76247
  return components[0];
76169
76248
  }
76170
76249
  function bundleContentRoot(entryPath, componentRoot) {
76171
- return path9.resolve(entryPath, componentRoot ?? ".");
76250
+ return path10.resolve(entryPath, componentRoot ?? ".");
76251
+ }
76252
+ function bundleContentRoots(config) {
76253
+ const bundles = config.bundles ?? {};
76254
+ const out = [];
76255
+ for (const [id, entry] of Object.entries(bundles)) {
76256
+ if (typeof entry.path !== "string" || entry.path.length === 0)
76257
+ continue;
76258
+ out.push({ id, contentRoot: bundleContentRoot(entry.path, bundleComponentConfig(entry)?.root) });
76259
+ }
76260
+ return out;
76261
+ }
76262
+ function bundleKeyForContentRoot(config, resolvedContentRoot) {
76263
+ return bundleContentRoots(config).find((entry) => entry.contentRoot === resolvedContentRoot)?.id;
76172
76264
  }
76173
76265
  function bundlesToSourceEntries(config) {
76174
76266
  const bundles = config.bundles;
@@ -76481,7 +76573,7 @@ init_paths();
76481
76573
  // src/core/state-db.ts
76482
76574
  import { randomUUID as randomUUID3 } from "crypto";
76483
76575
  import fs9 from "fs";
76484
- import path12 from "path";
76576
+ import path13 from "path";
76485
76577
 
76486
76578
  // src/storage/engines/sqlite-migrations.ts
76487
76579
  function assertMigrationRegistry(migrations) {
@@ -76650,7 +76742,7 @@ function withImmediateWriteLock(db, fn) {
76650
76742
 
76651
76743
  // src/storage/managed-db.ts
76652
76744
  import fs7 from "fs";
76653
- import path10 from "path";
76745
+ import path11 from "path";
76654
76746
 
76655
76747
  // src/storage/sqlite-pragmas.ts
76656
76748
  init_warn();
@@ -76724,7 +76816,7 @@ function warnNetworkFallbackOnce(dataDir) {
76724
76816
 
76725
76817
  // src/storage/managed-db.ts
76726
76818
  function openManagedDatabase(spec) {
76727
- const dir = path10.dirname(spec.path);
76819
+ const dir = path11.dirname(spec.path);
76728
76820
  if (spec.create !== false && !fs7.existsSync(dir)) {
76729
76821
  fs7.mkdirSync(dir, { recursive: true });
76730
76822
  }
@@ -76762,13 +76854,13 @@ function withManagedDb(open, fn, opts) {
76762
76854
  import { AsyncLocalStorage } from "async_hooks";
76763
76855
  import { randomUUID as randomUUID2 } from "crypto";
76764
76856
  import fs8 from "fs";
76765
- import path11 from "path";
76857
+ import path12 from "path";
76766
76858
  init_errors();
76767
76859
  init_paths();
76768
76860
  var heldBarrierContext = new AsyncLocalStorage;
76769
76861
  function tryAcquireMaintenanceBarrier() {
76770
76862
  const lockPath = getMaintenanceBarrierPath();
76771
- fs8.mkdirSync(path11.dirname(lockPath), { recursive: true });
76863
+ fs8.mkdirSync(path12.dirname(lockPath), { recursive: true });
76772
76864
  for (let attempt = 0;attempt < 2; attempt += 1) {
76773
76865
  const ownership = tryAcquireLockSync(lockPath, createLockPayload({ purpose: "maintenance-start" }));
76774
76866
  if (ownership) {
@@ -76819,9 +76911,9 @@ function withMaintenanceStartBarrierSyncWait(run) {
76819
76911
  }
76820
76912
  function acquireMaintenanceActivitySync(name) {
76821
76913
  return withMaintenanceStartBarrierSyncWait(() => {
76822
- const directory = path11.join(path11.dirname(getMaintenanceBarrierPath()), "maintenance-activities");
76914
+ const directory = path12.join(path12.dirname(getMaintenanceBarrierPath()), "maintenance-activities");
76823
76915
  fs8.mkdirSync(directory, { recursive: true, mode: 448 });
76824
- const lockPath = path11.join(directory, `${name}-${process.pid}-${randomUUID2()}.lock`);
76916
+ const lockPath = path12.join(directory, `${name}-${process.pid}-${randomUUID2()}.lock`);
76825
76917
  const ownership = tryAcquireLockSync(lockPath, createLockPayload({ purpose: name }));
76826
76918
  if (!ownership) {
76827
76919
  throw new ConfigError(`Could not register AKM maintenance activity at ${lockPath}.`, "INVALID_CONFIG_FILE");
@@ -77587,7 +77679,7 @@ function runMigrations2(db, options) {
77587
77679
 
77588
77680
  // src/core/state-db.ts
77589
77681
  function getStateDbPath() {
77590
- return path12.join(getDataDir(), "state.db");
77682
+ return path13.join(getDataDir(), "state.db");
77591
77683
  }
77592
77684
  function safetyCopyTimestamp() {
77593
77685
  return new Date().toISOString().replaceAll(/[^0-9]/g, "");
@@ -77772,7 +77864,7 @@ function createHistoricalStateSafetyCopy(source, migrationId) {
77772
77864
  fs9.fchmodSync(reservation.fd, finalMode);
77773
77865
  fs9.fsyncSync(reservation.fd);
77774
77866
  assertOwnedFileReservation(reservation, "Reserved state.db safety copy");
77775
- fsyncDirectory(path12.dirname(reservation.path));
77867
+ fsyncDirectory(path13.dirname(reservation.path));
77776
77868
  closeFileIdentity(reservation);
77777
77869
  return reservation.path;
77778
77870
  } catch (error) {
@@ -77790,11 +77882,11 @@ function openStateDatabase(dbPath, options) {
77790
77882
  if (resolvedPath === ":memory:") {
77791
77883
  return openManagedDatabase({
77792
77884
  path: resolvedPath,
77793
- pragmas: { dataDir: path12.dirname(resolvedPath) },
77885
+ pragmas: { dataDir: path13.dirname(resolvedPath) },
77794
77886
  init: (db) => runMigrations2(db, { freshDatabase: true })
77795
77887
  });
77796
77888
  }
77797
- const isCanonical = path12.resolve(resolvedPath) === path12.resolve(canonicalPath);
77889
+ const isCanonical = path13.resolve(resolvedPath) === path13.resolve(canonicalPath);
77798
77890
  const releaseActivity = isCanonical ? acquireMaintenanceActivitySync("state-db") : undefined;
77799
77891
  let freshReservation;
77800
77892
  let existingSource;
@@ -77802,7 +77894,7 @@ function openStateDatabase(dbPath, options) {
77802
77894
  let existingUnversionedDatabase = false;
77803
77895
  let stateSafetyCopyCreated = false;
77804
77896
  try {
77805
- fs9.mkdirSync(path12.dirname(resolvedPath), { recursive: true });
77897
+ fs9.mkdirSync(path13.dirname(resolvedPath), { recursive: true });
77806
77898
  freshReservation = reserveFreshStateDatabase(resolvedPath);
77807
77899
  if (!freshReservation) {
77808
77900
  existingSource = openExistingStateDatabaseSource(resolvedPath);
@@ -77823,7 +77915,7 @@ function openStateDatabase(dbPath, options) {
77823
77915
  const boundSource = existingSource;
77824
77916
  openedDb = openManagedDatabase({
77825
77917
  path: boundSource ? sqliteBoundFilePath(boundSource) : resolvedPath,
77826
- pragmas: { dataDir: path12.dirname(resolvedPath) },
77918
+ pragmas: { dataDir: path13.dirname(resolvedPath) },
77827
77919
  init: (db2) => {
77828
77920
  runMigrations2(db2, {
77829
77921
  freshDatabase: !!freshReservation,
@@ -78024,7 +78116,7 @@ function applyConfigExtraParamsLift(configPath) {
78024
78116
 
78025
78117
  // scripts/akm-migrate/migrate/dead-residue.ts
78026
78118
  import fs10 from "fs";
78027
- import path13 from "path";
78119
+ import path14 from "path";
78028
78120
  var DEAD_RESIDUE_PATHS = [
78029
78121
  { name: "proposals", reason: "superseded by the `proposals` table in $DATA/state.db (0.9.0)" },
78030
78122
  { prefix: "runs.archived-", reason: "orphaned archive of a directory that no longer exists" },
@@ -78046,7 +78138,7 @@ function dirSizeBytes(target) {
78046
78138
  return 0;
78047
78139
  }
78048
78140
  for (const entry of entries) {
78049
- const entryPath = path13.join(target, entry.name);
78141
+ const entryPath = path14.join(target, entry.name);
78050
78142
  if (entry.isDirectory()) {
78051
78143
  total += dirSizeBytes(entryPath);
78052
78144
  } else if (entry.isFile()) {
@@ -78062,7 +78154,7 @@ function sizeOf(target) {
78062
78154
  return st.isDirectory() ? dirSizeBytes(target) : st.size;
78063
78155
  }
78064
78156
  function findDeadResidueEntries(stashDir) {
78065
- const akmDir = path13.join(stashDir, ".akm");
78157
+ const akmDir = path14.join(stashDir, ".akm");
78066
78158
  let names;
78067
78159
  try {
78068
78160
  names = fs10.readdirSync(akmDir);
@@ -78075,14 +78167,14 @@ function findDeadResidueEntries(stashDir) {
78075
78167
  for (const name of matches) {
78076
78168
  if (!names.includes(name))
78077
78169
  continue;
78078
- const absolutePath = path13.join(akmDir, name);
78170
+ const absolutePath = path14.join(akmDir, name);
78079
78171
  let sizeBytes;
78080
78172
  try {
78081
78173
  sizeBytes = sizeOf(absolutePath);
78082
78174
  } catch {
78083
78175
  continue;
78084
78176
  }
78085
- found.push({ relativePath: path13.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
78177
+ found.push({ relativePath: path14.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
78086
78178
  }
78087
78179
  }
78088
78180
  return found;
@@ -78109,7 +78201,7 @@ init_paths();
78109
78201
  init_warn();
78110
78202
  import { createHash as createHash2, randomUUID as randomUUID4 } from "crypto";
78111
78203
  import fs11 from "fs";
78112
- import path14 from "path";
78204
+ import path15 from "path";
78113
78205
  var kinds = new Map;
78114
78206
  function registerTxnKind(kind, handler3) {
78115
78207
  kinds.set(kind, handler3);
@@ -78153,18 +78245,18 @@ function writeTxnFileDurably(filePath, content, mode = 384) {
78153
78245
  fs11.writeFileSync(tempPath, content, { mode });
78154
78246
  fsyncTxnFile(tempPath);
78155
78247
  fs11.renameSync(tempPath, filePath);
78156
- fsyncTxnDir(path14.dirname(filePath));
78248
+ fsyncTxnDir(path15.dirname(filePath));
78157
78249
  }
78158
78250
  function canonicalTxnRoot(root) {
78159
78251
  try {
78160
- return fs11.realpathSync(path14.resolve(root));
78252
+ return fs11.realpathSync(path15.resolve(root));
78161
78253
  } catch {
78162
- return path14.resolve(root);
78254
+ return path15.resolve(root);
78163
78255
  }
78164
78256
  }
78165
78257
  function txnNamespaceDir(root) {
78166
78258
  const ns = txnHash(canonicalTxnRoot(root)).slice(0, 24);
78167
- return path14.join(getDataDir(), "txn", ns);
78259
+ return path15.join(getDataDir(), "txn", ns);
78168
78260
  }
78169
78261
  function advanceTxn(txn, phase) {
78170
78262
  const handler3 = requireKind(txn.journal.kind);
@@ -78180,7 +78272,7 @@ function cleanupTxn(dir) {
78180
78272
  try {
78181
78273
  fs11.rmSync(dir, { recursive: true, force: true });
78182
78274
  try {
78183
- fs11.rmdirSync(path14.dirname(dir));
78275
+ fs11.rmdirSync(path15.dirname(dir));
78184
78276
  } catch {}
78185
78277
  return null;
78186
78278
  } catch (error) {
@@ -78202,8 +78294,8 @@ function sweepJournallessTxnDir(dir, graceMs = TXN_SWEEP_GRACE_MS) {
78202
78294
  }
78203
78295
  }
78204
78296
  function isWithinTxnRoot(candidate, root) {
78205
- const rel = path14.relative(path14.resolve(root), path14.resolve(candidate));
78206
- return rel !== "" && !rel.startsWith("..") && !path14.isAbsolute(rel);
78297
+ const rel = path15.relative(path15.resolve(root), path15.resolve(candidate));
78298
+ return rel !== "" && !rel.startsWith("..") && !path15.isAbsolute(rel);
78207
78299
  }
78208
78300
  function readJournal(journalPath) {
78209
78301
  let journal;
@@ -78244,8 +78336,8 @@ async function recoverTxnsForRoot(root, filter) {
78244
78336
  for (const entry of fs11.readdirSync(nsDir, { withFileTypes: true })) {
78245
78337
  if (!entry.isDirectory())
78246
78338
  continue;
78247
- const dir = path14.join(nsDir, entry.name);
78248
- const journalPath = path14.join(dir, "journal.json");
78339
+ const dir = path15.join(nsDir, entry.name);
78340
+ const journalPath = path15.join(dir, "journal.json");
78249
78341
  if (!fs11.existsSync(journalPath)) {
78250
78342
  sweepJournallessTxnDir(dir);
78251
78343
  continue;
@@ -78274,7 +78366,7 @@ async function recoverTxnsForRoot(root, filter) {
78274
78366
  return recovered;
78275
78367
  }
78276
78368
  function listTxnJournalsTolerant(predicate) {
78277
- const home = path14.join(getDataDir(), "txn");
78369
+ const home = path15.join(getDataDir(), "txn");
78278
78370
  const matches = [];
78279
78371
  const unreadableMtimes = [];
78280
78372
  if (!fs11.existsSync(home))
@@ -78282,11 +78374,11 @@ function listTxnJournalsTolerant(predicate) {
78282
78374
  for (const ns of fs11.readdirSync(home, { withFileTypes: true })) {
78283
78375
  if (!ns.isDirectory())
78284
78376
  continue;
78285
- const nsDir = path14.join(home, ns.name);
78377
+ const nsDir = path15.join(home, ns.name);
78286
78378
  for (const entry of fs11.readdirSync(nsDir, { withFileTypes: true })) {
78287
78379
  if (!entry.isDirectory())
78288
78380
  continue;
78289
- const journalPath = path14.join(nsDir, entry.name, "journal.json");
78381
+ const journalPath = path15.join(nsDir, entry.name, "journal.json");
78290
78382
  let mtimeMs;
78291
78383
  try {
78292
78384
  mtimeMs = fs11.statSync(journalPath).mtimeMs;
@@ -78315,7 +78407,7 @@ import path60 from "path";
78315
78407
  init_frontmatter();
78316
78408
  init_common();
78317
78409
  import fs12 from "fs";
78318
- import path16 from "path";
78410
+ import path17 from "path";
78319
78411
 
78320
78412
  // src/core/adapter/adapters/shared.ts
78321
78413
  init_frontmatter();
@@ -78624,10 +78716,10 @@ var agentSkillsAdapter = {
78624
78716
  recognize,
78625
78717
  validate,
78626
78718
  readCandidates(c, conceptId) {
78627
- return [{ path: path16.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
78719
+ return [{ path: path17.join(c.root, conceptId, SKILL_MANIFEST), conceptId }];
78628
78720
  },
78629
78721
  placeNew(c, conceptId) {
78630
- return path16.join(c.root, conceptId, SKILL_MANIFEST);
78722
+ return path17.join(c.root, conceptId, SKILL_MANIFEST);
78631
78723
  },
78632
78724
  looksLikeRoot(root) {
78633
78725
  let entries;
@@ -78640,7 +78732,7 @@ var agentSkillsAdapter = {
78640
78732
  if (!entry.isDirectory())
78641
78733
  return false;
78642
78734
  try {
78643
- return fs12.existsSync(path16.join(root, entry.name, SKILL_MANIFEST));
78735
+ return fs12.existsSync(path17.join(root, entry.name, SKILL_MANIFEST));
78644
78736
  } catch {
78645
78737
  return false;
78646
78738
  }
@@ -78653,66 +78745,66 @@ init_metadata();
78653
78745
  init_asset_placement();
78654
78746
  init_frontmatter();
78655
78747
  import fs16 from "fs";
78656
- import path24 from "path";
78748
+ import path25 from "path";
78657
78749
 
78658
78750
  // src/core/adapter/execution-source.ts
78659
78751
  init_dist();
78660
78752
  import { createHash as createHash4 } from "crypto";
78661
78753
 
78662
78754
  // src/execution/json.ts
78663
- function fail(path18, detail) {
78664
- throw new TypeError(`${path18} ${detail}`);
78755
+ function fail(path19, detail) {
78756
+ throw new TypeError(`${path19} ${detail}`);
78665
78757
  }
78666
- function cloneExecutionJson(value, path18 = "execution value", ancestors = new Set) {
78758
+ function cloneExecutionJson(value, path19 = "execution value", ancestors = new Set) {
78667
78759
  if (value === null || typeof value === "string" || typeof value === "boolean")
78668
78760
  return value;
78669
78761
  if (typeof value === "number") {
78670
78762
  if (!Number.isFinite(value))
78671
- fail(path18, "must contain only finite numbers");
78763
+ fail(path19, "must contain only finite numbers");
78672
78764
  return value;
78673
78765
  }
78674
78766
  if (value === undefined)
78675
- fail(path18, "must be omitted rather than set to undefined");
78767
+ fail(path19, "must be omitted rather than set to undefined");
78676
78768
  if (typeof value !== "object")
78677
- fail(path18, "must be JSON-safe");
78769
+ fail(path19, "must be JSON-safe");
78678
78770
  if (ancestors.has(value))
78679
- fail(path18, "must not contain a cycle");
78771
+ fail(path19, "must not contain a cycle");
78680
78772
  const nextAncestors = new Set(ancestors);
78681
78773
  nextAncestors.add(value);
78682
78774
  if (Array.isArray(value)) {
78683
78775
  if (Object.getPrototypeOf(value) !== Array.prototype)
78684
- fail(path18, "array must use the standard Array prototype");
78776
+ fail(path19, "array must use the standard Array prototype");
78685
78777
  const ownKeys = Reflect.ownKeys(value);
78686
78778
  const lengthDescriptor = Reflect.getOwnPropertyDescriptor(value, "length");
78687
78779
  if (!lengthDescriptor || !("value" in lengthDescriptor) || typeof lengthDescriptor.value !== "number" || !Number.isInteger(lengthDescriptor.value) || lengthDescriptor.value < 0) {
78688
- fail(path18, "array length must be a stable nonnegative integer data property");
78780
+ fail(path19, "array length must be a stable nonnegative integer data property");
78689
78781
  }
78690
78782
  const length = lengthDescriptor.value;
78691
78783
  if (ownKeys.length !== length + 1) {
78692
- fail(path18, "array must be dense and contain no non-index properties");
78784
+ fail(path19, "array must be dense and contain no non-index properties");
78693
78785
  }
78694
78786
  for (const key of ownKeys) {
78695
78787
  if (key === "length")
78696
78788
  continue;
78697
78789
  if (typeof key !== "string" || !/^(?:0|[1-9]\d*)$/.test(key) || Number(key) >= length) {
78698
- fail(path18, "array must contain only canonical index properties");
78790
+ fail(path19, "array must contain only canonical index properties");
78699
78791
  }
78700
78792
  }
78701
78793
  const cloned2 = [];
78702
78794
  for (let index = 0;index < length; index++) {
78703
78795
  const descriptor = Reflect.getOwnPropertyDescriptor(value, String(index));
78704
78796
  if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
78705
- fail(path18, "array must be dense enumerable data properties");
78797
+ fail(path19, "array must be dense enumerable data properties");
78706
78798
  }
78707
- cloned2.push(cloneExecutionJson(descriptor.value, `${path18}[${index}]`, nextAncestors));
78799
+ cloned2.push(cloneExecutionJson(descriptor.value, `${path19}[${index}]`, nextAncestors));
78708
78800
  }
78709
78801
  return Object.freeze(cloned2);
78710
78802
  }
78711
- const snapshot = snapshotStrictRecord(value, path18);
78803
+ const snapshot = snapshotStrictRecord(value, path19);
78712
78804
  const cloned = Object.create(null);
78713
78805
  for (const [key, child] of Object.entries(snapshot)) {
78714
78806
  Object.defineProperty(cloned, key, {
78715
- value: cloneExecutionJson(child, `${path18}.${key}`, nextAncestors),
78807
+ value: cloneExecutionJson(child, `${path19}.${key}`, nextAncestors),
78716
78808
  enumerable: true,
78717
78809
  configurable: false,
78718
78810
  writable: false
@@ -78720,10 +78812,10 @@ function cloneExecutionJson(value, path18 = "execution value", ancestors = new S
78720
78812
  }
78721
78813
  return Object.freeze(cloned);
78722
78814
  }
78723
- function cloneExecutionJsonObject(value, path18) {
78724
- const cloned = cloneExecutionJson(value, path18);
78815
+ function cloneExecutionJsonObject(value, path19) {
78816
+ const cloned = cloneExecutionJson(value, path19);
78725
78817
  if (cloned === null || Array.isArray(cloned) || typeof cloned !== "object") {
78726
- fail(path18, "must be a JSON object");
78818
+ fail(path19, "must be a JSON object");
78727
78819
  }
78728
78820
  return cloned;
78729
78821
  }
@@ -78737,11 +78829,11 @@ var WINDOWS_DRIVE_PREFIX_PATTERN = /^[A-Za-z]:/;
78737
78829
  var RESERVED_EXTENSION_OWNERS = new Set(["__proto__", "constructor", "prototype", "tostring"]);
78738
78830
  var renderedSourceBrand = Symbol("akm.adapter-rendered-execution-source");
78739
78831
  var renderedSourceInstances = new WeakSet;
78740
- function requireRecord(value, path18) {
78741
- return snapshotStrictRecord(value, path18);
78832
+ function requireRecord(value, path19) {
78833
+ return snapshotStrictRecord(value, path19);
78742
78834
  }
78743
- function assertOnlyKeys(value, allowed, path18) {
78744
- assertSnapshotKeys(value, allowed, path18);
78835
+ function assertOnlyKeys(value, allowed, path19) {
78836
+ assertSnapshotKeys(value, allowed, path19);
78745
78837
  }
78746
78838
  function validateExtensionOwner(owner) {
78747
78839
  const normalized = owner.toLowerCase();
@@ -78757,16 +78849,16 @@ function frozenNullPrototypeMap(entries) {
78757
78849
  return Object.freeze(out);
78758
78850
  }
78759
78851
  function cloneExtensionEntry(value, index) {
78760
- const path18 = `extension entry ${index}`;
78761
- const cloned = cloneExecutionJson(value, path18);
78852
+ const path19 = `extension entry ${index}`;
78853
+ const cloned = cloneExecutionJson(value, path19);
78762
78854
  if (!Array.isArray(cloned) || cloned.length !== 2) {
78763
- throw new TypeError(`${path18} must be a two-element [owner, values] array`);
78855
+ throw new TypeError(`${path19} must be a two-element [owner, values] array`);
78764
78856
  }
78765
78857
  const [owner, values] = cloned;
78766
78858
  if (typeof owner !== "string")
78767
- throw new TypeError(`${path18} owner must be a string`);
78859
+ throw new TypeError(`${path19} owner must be a string`);
78768
78860
  if (values === null || Array.isArray(values) || typeof values !== "object") {
78769
- throw new TypeError(`${path18} values must be a JSON object`);
78861
+ throw new TypeError(`${path19} values must be a JSON object`);
78770
78862
  }
78771
78863
  return [owner, values];
78772
78864
  }
@@ -78784,18 +78876,18 @@ function createAdapterExtensions(first, second, ...rest) {
78784
78876
  }
78785
78877
  return frozenNullPrototypeMap(cloned);
78786
78878
  }
78787
- function cloneAdapterExtensions(value, path18) {
78788
- const record = requireRecord(value, path18);
78789
- const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path18}.${owner}`)]);
78879
+ function cloneAdapterExtensions(value, path19) {
78880
+ const record = requireRecord(value, path19);
78881
+ const entries = Object.entries(record).map(([owner, fields]) => [owner, cloneExecutionJsonObject(fields, `${path19}.${owner}`)]);
78790
78882
  const [first, ...rest] = entries;
78791
78883
  return first ? createAdapterExtensions(first, ...rest) : frozenNullPrototypeMap([]);
78792
78884
  }
78793
- function requireCanonicalString(value, path18) {
78885
+ function requireCanonicalString(value, path19) {
78794
78886
  if (typeof value !== "string" || value.length === 0 || !isWellFormedUnicode(value) || value.normalize("NFC") !== value) {
78795
- throw new TypeError(`${path18} must be a non-empty NFC string`);
78887
+ throw new TypeError(`${path19} must be a non-empty NFC string`);
78796
78888
  }
78797
78889
  if (hasUnsafeIdentityCharacter(value)) {
78798
- throw new TypeError(`${path18} must not contain Unicode control or dangerous format characters`);
78890
+ throw new TypeError(`${path19} must not contain Unicode control or dangerous format characters`);
78799
78891
  }
78800
78892
  return value;
78801
78893
  }
@@ -78822,38 +78914,38 @@ function isWellFormedUnicode(value) {
78822
78914
  }
78823
78915
  return true;
78824
78916
  }
78825
- function validateCanonicalIdentity(input, path18) {
78826
- assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path18);
78827
- const ref = requireCanonicalString(input.ref, `${path18}.ref`);
78828
- const bundle = requireCanonicalString(input.bundle, `${path18}.bundle`);
78829
- const adapter = requireCanonicalString(input.adapter, `${path18}.adapter`);
78830
- const file = requireCanonicalString(input.file, `${path18}.file`);
78831
- const hash = requireCanonicalString(input.hash, `${path18}.hash`);
78917
+ function validateCanonicalIdentity(input, path19) {
78918
+ assertOnlyKeys(input, ["ref", "bundle", "adapter", "file", "hash"], path19);
78919
+ const ref = requireCanonicalString(input.ref, `${path19}.ref`);
78920
+ const bundle = requireCanonicalString(input.bundle, `${path19}.bundle`);
78921
+ const adapter = requireCanonicalString(input.adapter, `${path19}.adapter`);
78922
+ const file = requireCanonicalString(input.file, `${path19}.file`);
78923
+ const hash = requireCanonicalString(input.hash, `${path19}.hash`);
78832
78924
  let parsed;
78833
78925
  try {
78834
78926
  parsed = parseBundleRef(ref);
78835
78927
  } catch (cause) {
78836
- throw new TypeError(`${path18}.ref is not a canonical bundle ref`, { cause });
78928
+ throw new TypeError(`${path19}.ref is not a canonical bundle ref`, { cause });
78837
78929
  }
78838
78930
  if (parsed.bundle === undefined || parsed.bundle !== bundle || parsed.fragment !== undefined || !isBundleSlug(bundle) || bundleRefToString(parsed) !== ref) {
78839
- throw new TypeError(`${path18}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
78931
+ throw new TypeError(`${path19}.ref must round-trip as the same fully-qualified bundle ref without a fragment`);
78840
78932
  }
78841
78933
  if (!EXECUTION_ADAPTER_ID_PATTERN.test(adapter)) {
78842
- throw new TypeError(`${path18}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
78934
+ throw new TypeError(`${path19}.adapter must use the current lowercase kebab-case adapter identifier grammar`);
78843
78935
  }
78844
78936
  const segments = file.split("/");
78845
78937
  if (file.startsWith("/") || WINDOWS_DRIVE_PREFIX_PATTERN.test(file) || file.includes("\\") || segments.some((segment) => !segment || segment === "." || segment === "..")) {
78846
- throw new TypeError(`${path18}.file must be a normalized relative POSIX path`);
78938
+ throw new TypeError(`${path19}.file must be a normalized relative POSIX path`);
78847
78939
  }
78848
78940
  if (!/^[a-f0-9]{64}$/.test(hash))
78849
- throw new TypeError(`${path18}.hash must be a SHA-256 hex digest`);
78941
+ throw new TypeError(`${path19}.hash must be a SHA-256 hex digest`);
78850
78942
  return { ref, bundle, adapter, file, hash };
78851
78943
  }
78852
78944
  function createExecutionSourceIdentity(input) {
78853
78945
  return Object.freeze(validateCanonicalIdentity(requireRecord(input, "execution source identity"), "execution source identity"));
78854
78946
  }
78855
- function cloneUnresolvedExecutionDefaults(input, path18 = "execution source defaults") {
78856
- const record = requireRecord(input, path18);
78947
+ function cloneUnresolvedExecutionDefaults(input, path19 = "execution source defaults") {
78948
+ const record = requireRecord(input, path19);
78857
78949
  assertOnlyKeys(record, [
78858
78950
  "agent",
78859
78951
  "engine",
@@ -78865,47 +78957,47 @@ function cloneUnresolvedExecutionDefaults(input, path18 = "execution source defa
78865
78957
  "workspace",
78866
78958
  "environment",
78867
78959
  "runtime"
78868
- ], path18);
78869
- const json = { ...cloneExecutionJsonObject(record, path18) };
78960
+ ], path19);
78961
+ const json = { ...cloneExecutionJsonObject(record, path19) };
78870
78962
  for (const key of ["agent", "engine", "model", "workspace"]) {
78871
78963
  const value = json[key];
78872
78964
  if (value !== undefined && value !== null && typeof value !== "string") {
78873
- throw new TypeError(`${path18}.${key} must be a string or null`);
78965
+ throw new TypeError(`${path19}.${key} must be a string or null`);
78874
78966
  }
78875
78967
  }
78876
78968
  const timeout = json.timeout;
78877
78969
  if (timeout !== undefined && timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
78878
- throw new TypeError(`${path18}.timeout must be a string, number, or null`);
78970
+ throw new TypeError(`${path19}.timeout must be a string, number, or null`);
78879
78971
  }
78880
78972
  for (const key of ["inference", "outputSchema", "runtime"]) {
78881
78973
  const value = json[key];
78882
78974
  if (value !== undefined && value !== null && (Array.isArray(value) || typeof value !== "object")) {
78883
- throw new TypeError(`${path18}.${key} must be an object or null`);
78975
+ throw new TypeError(`${path19}.${key} must be an object or null`);
78884
78976
  }
78885
78977
  }
78886
78978
  const environment = json.environment;
78887
78979
  if (environment !== undefined && environment !== null) {
78888
78980
  if (Array.isArray(environment) || typeof environment !== "object") {
78889
- throw new TypeError(`${path18}.environment must be an object or null`);
78981
+ throw new TypeError(`${path19}.environment must be an object or null`);
78890
78982
  }
78891
78983
  if (Object.values(environment).some((value) => typeof value !== "string")) {
78892
- throw new TypeError(`${path18}.environment values must be strings`);
78984
+ throw new TypeError(`${path19}.environment values must be strings`);
78893
78985
  }
78894
78986
  }
78895
78987
  if (Object.hasOwn(json, "tools"))
78896
- json.tools = cloneToolSelection(json.tools, `${path18}.tools`);
78988
+ json.tools = cloneToolSelection(json.tools, `${path19}.tools`);
78897
78989
  return Object.freeze(json);
78898
78990
  }
78899
- function cloneToolSelection(value, path18 = "tools") {
78991
+ function cloneToolSelection(value, path19 = "tools") {
78900
78992
  if (value === null || typeof value === "string")
78901
78993
  return value;
78902
- const cloned = cloneExecutionJson(value, path18);
78994
+ const cloned = cloneExecutionJson(value, path19);
78903
78995
  if (Array.isArray(cloned)) {
78904
78996
  if (cloned.some((tool) => typeof tool !== "string"))
78905
- throw new TypeError(`${path18} array values must be strings`);
78997
+ throw new TypeError(`${path19} array values must be strings`);
78906
78998
  return cloned;
78907
78999
  }
78908
- return cloneExecutionJsonObject(cloned, path18);
79000
+ return cloneExecutionJsonObject(cloned, path19);
78909
79001
  }
78910
79002
  function createAdapterRenderedExecutionSource(input) {
78911
79003
  const record = requireRecord(input, "adapter-rendered execution source");
@@ -79014,34 +79106,34 @@ function parseExecutionMarkdown(raw) {
79014
79106
  function own(data, key) {
79015
79107
  return Object.hasOwn(data, key);
79016
79108
  }
79017
- function requireMetadataMapping(value, path18) {
79109
+ function requireMetadataMapping(value, path19) {
79018
79110
  try {
79019
- return snapshotStrictRecord(value, path18);
79111
+ return snapshotStrictRecord(value, path19);
79020
79112
  } catch (cause) {
79021
- throw new TypeError(`${path18} must be a mapping with enumerable data fields`, { cause });
79113
+ throw new TypeError(`${path19} must be a mapping with enumerable data fields`, { cause });
79022
79114
  }
79023
79115
  }
79024
- function nullableString(value, path18) {
79116
+ function nullableString(value, path19) {
79025
79117
  if (value !== null && typeof value !== "string")
79026
- throw new TypeError(`${path18} must be a string or null`);
79118
+ throw new TypeError(`${path19} must be a string or null`);
79027
79119
  return value;
79028
79120
  }
79029
- function nullableObject(value, path18) {
79030
- return value === null ? null : cloneExecutionJsonObject(value, path18);
79121
+ function nullableObject(value, path19) {
79122
+ return value === null ? null : cloneExecutionJsonObject(value, path19);
79031
79123
  }
79032
- function nullableEnvironment(value, path18) {
79124
+ function nullableEnvironment(value, path19) {
79033
79125
  if (value === null)
79034
79126
  return null;
79035
- const environment = cloneExecutionJsonObject(value, path18);
79127
+ const environment = cloneExecutionJsonObject(value, path19);
79036
79128
  if (Object.values(environment).some((entry) => typeof entry !== "string")) {
79037
- throw new TypeError(`${path18} values must be strings`);
79129
+ throw new TypeError(`${path19} values must be strings`);
79038
79130
  }
79039
79131
  return environment;
79040
79132
  }
79041
- function nullableTimeout(value, path18) {
79042
- const timeout = cloneExecutionJson(value, path18);
79133
+ function nullableTimeout(value, path19) {
79134
+ const timeout = cloneExecutionJson(value, path19);
79043
79135
  if (timeout !== null && typeof timeout !== "string" && typeof timeout !== "number") {
79044
- throw new TypeError(`${path18} must be a string, number, or null`);
79136
+ throw new TypeError(`${path19} must be a string, number, or null`);
79045
79137
  }
79046
79138
  return timeout;
79047
79139
  }
@@ -79485,7 +79577,7 @@ function recognizeMatch(file) {
79485
79577
  }
79486
79578
 
79487
79579
  // src/core/adapter/adapters/akm-lint.ts
79488
- import path23 from "path";
79580
+ import path24 from "path";
79489
79581
 
79490
79582
  // src/commands/lint/env-key-rules.ts
79491
79583
  init_env();
@@ -79608,28 +79700,28 @@ var MOVE_TO_ENV = "Workflow params are copied verbatim into every native unit ex
79608
79700
  function detectSecretShapedParams(params) {
79609
79701
  const warnings = [];
79610
79702
  const seen = new Set;
79611
- const push = (path19, why) => {
79612
- if (seen.has(path19))
79703
+ const push = (path20, why) => {
79704
+ if (seen.has(path20))
79613
79705
  return;
79614
- seen.add(path19);
79615
- warnings.push(`Run param "${path19}" ${why}. ${MOVE_TO_ENV} (Heuristic warning; params are declared non-secret.)`);
79706
+ seen.add(path20);
79707
+ warnings.push(`Run param "${path20}" ${why}. ${MOVE_TO_ENV} (Heuristic warning; params are declared non-secret.)`);
79616
79708
  };
79617
- const walk = (value, path19, key) => {
79709
+ const walk = (value, path20, key) => {
79618
79710
  if (key !== null && keyLooksSecret(key))
79619
- push(path19, "has a secret-suggesting name");
79711
+ push(path20, "has a secret-suggesting name");
79620
79712
  if (typeof value === "string") {
79621
79713
  if (valueLooksSecret(value))
79622
- push(path19, "has a secret-shaped value (long, high-entropy string)");
79714
+ push(path20, "has a secret-shaped value (long, high-entropy string)");
79623
79715
  return;
79624
79716
  }
79625
79717
  if (Array.isArray(value)) {
79626
79718
  for (let i = 0;i < value.length; i++)
79627
- walk(value[i], `${path19}[${i}]`, null);
79719
+ walk(value[i], `${path20}[${i}]`, null);
79628
79720
  return;
79629
79721
  }
79630
79722
  if (value && typeof value === "object") {
79631
79723
  for (const [k, v] of Object.entries(value)) {
79632
- walk(v, path19 ? `${path19}.${k}` : k, k);
79724
+ walk(v, path20 ? `${path20}.${k}` : k, k);
79633
79725
  }
79634
79726
  }
79635
79727
  };
@@ -80077,8 +80169,8 @@ init_dist();
80077
80169
  init_asset_ref();
80078
80170
  init_extra_params();
80079
80171
  init_resource_limits();
80080
- import crypto3 from "crypto";
80081
- import path19 from "path";
80172
+ import crypto4 from "crypto";
80173
+ import path20 from "path";
80082
80174
 
80083
80175
  // src/tasks/task-id.ts
80084
80176
  init_errors();
@@ -80520,7 +80612,7 @@ var KNOWN_PROMPT_REF_FAMILIES = new Set([
80520
80612
  "workflows"
80521
80613
  ]);
80522
80614
  function hash(bytes) {
80523
- return crypto3.createHash("sha256").update(bytes).digest("hex");
80615
+ return crypto4.createHash("sha256").update(bytes).digest("hex");
80524
80616
  }
80525
80617
  function base(input) {
80526
80618
  return {
@@ -80679,7 +80771,7 @@ function addSharedNonPromptOverrides(data, akm) {
80679
80771
  }
80680
80772
  function promptSourceKind(raw) {
80681
80773
  const trimmed = raw.trim();
80682
- if (trimmed.startsWith("./") || trimmed.startsWith("../") || path19.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
80774
+ if (trimmed.startsWith("./") || trimmed.startsWith("../") || path20.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
80683
80775
  return "file";
80684
80776
  }
80685
80777
  try {
@@ -80786,7 +80878,7 @@ function planLegacyTaskDataToV3(input, data) {
80786
80878
  return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
80787
80879
  }
80788
80880
  try {
80789
- validateTaskId(path19.basename(input.filePath, ".yml"));
80881
+ validateTaskId(path20.basename(input.filePath, ".yml"));
80790
80882
  } catch (cause) {
80791
80883
  return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
80792
80884
  }
@@ -80856,7 +80948,7 @@ function planTaskToV3File(input) {
80856
80948
  return planLegacyTaskDataToV3(input, data);
80857
80949
  }
80858
80950
  function generationFor(files) {
80859
- const digest = crypto3.createHash("sha256");
80951
+ const digest = crypto4.createHash("sha256");
80860
80952
  digest.update("akm-task-to-v3-plan-v1\x00");
80861
80953
  for (const file of files) {
80862
80954
  digest.update(file.filePath);
@@ -80890,7 +80982,7 @@ function taskToV3PlanFromOutcomes(outcomes) {
80890
80982
  for (let index = 1;index < files.length; index += 1) {
80891
80983
  const previous = files[index - 1];
80892
80984
  const current = files[index];
80893
- if (previous && current && path19.resolve(previous.filePath) === path19.resolve(current.filePath)) {
80985
+ if (previous && current && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
80894
80986
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
80895
80987
  }
80896
80988
  }
@@ -80900,7 +80992,7 @@ function planTaskToV3Migration(inputs) {
80900
80992
  const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
80901
80993
  let previous;
80902
80994
  for (const current of sorted) {
80903
- if (previous && path19.resolve(previous.filePath) === path19.resolve(current.filePath)) {
80995
+ if (previous && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
80904
80996
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
80905
80997
  }
80906
80998
  previous = current;
@@ -80911,8 +81003,8 @@ function planTaskToV3Migration(inputs) {
80911
81003
  // src/tasks/source/task-to-v4.ts
80912
81004
  init_dist();
80913
81005
  init_bounded_document();
80914
- import crypto4 from "crypto";
80915
- import path20 from "path";
81006
+ import crypto5 from "crypto";
81007
+ import path21 from "path";
80916
81008
  var V3_TOP_LEVEL_KEYS = new Set([
80917
81009
  "version",
80918
81010
  "name",
@@ -80958,7 +81050,7 @@ var AKM_HOIST_KEYS = [
80958
81050
  "maxRetries"
80959
81051
  ];
80960
81052
  function hash2(bytes) {
80961
- return crypto4.createHash("sha256").update(bytes).digest("hex");
81053
+ return crypto5.createHash("sha256").update(bytes).digest("hex");
80962
81054
  }
80963
81055
  function causeMessage(cause) {
80964
81056
  return cause instanceof Error ? cause.message : String(cause);
@@ -81227,7 +81319,7 @@ function planTaskToV4File(input) {
81227
81319
  return planV3DataToV4(input, data);
81228
81320
  }
81229
81321
  function generationFor2(files) {
81230
- const digest = crypto4.createHash("sha256");
81322
+ const digest = crypto5.createHash("sha256");
81231
81323
  digest.update("akm-task-to-v4-plan-v1\x00");
81232
81324
  for (const file of files) {
81233
81325
  digest.update(file.filePath);
@@ -81264,7 +81356,7 @@ function taskToV4PlanFromOutcomes(outcomes) {
81264
81356
  for (let index = 1;index < files.length; index += 1) {
81265
81357
  const previous = files[index - 1];
81266
81358
  const current = files[index];
81267
- if (previous && current && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
81359
+ if (previous && current && path21.resolve(previous.filePath) === path21.resolve(current.filePath)) {
81268
81360
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
81269
81361
  }
81270
81362
  }
@@ -81274,7 +81366,7 @@ function planTaskToV4Migration(inputs) {
81274
81366
  const sorted = [...inputs].sort((left, right) => left.filePath < right.filePath ? -1 : left.filePath > right.filePath ? 1 : 0);
81275
81367
  let previous;
81276
81368
  for (const current of sorted) {
81277
- if (previous && path20.resolve(previous.filePath) === path20.resolve(current.filePath)) {
81369
+ if (previous && path21.resolve(previous.filePath) === path21.resolve(current.filePath)) {
81278
81370
  throw new Error(`duplicate task migration file path: ${current.filePath}`);
81279
81371
  }
81280
81372
  previous = current;
@@ -81589,7 +81681,7 @@ function checkInvalidTypeValue(data, allowedTypes) {
81589
81681
  return `type field has invalid value '${value}'; expected one of: ${allowedTypes.join(", ")}`;
81590
81682
  }
81591
81683
  function suggestSlug(filePath) {
81592
- return path23.basename(filePath, ".md").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
81684
+ return path24.basename(filePath, ".md").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
81593
81685
  }
81594
81686
  function nameOrTypeDiagnostics(relPath, data, frontmatter, allowedTypes) {
81595
81687
  const missingFieldDetail = checkMissingNameOrType(data, frontmatter);
@@ -81629,7 +81721,7 @@ function collectSuppressedKeys(raw) {
81629
81721
  function dangerousEnvKeyDiagnostics(type, relPath, raw) {
81630
81722
  if (type !== "env" && type !== "secret")
81631
81723
  return [];
81632
- const baseNameWithExt = path23.basename(relPath);
81724
+ const baseNameWithExt = path24.basename(relPath);
81633
81725
  if (!baseNameWithExt.endsWith(".env"))
81634
81726
  return [];
81635
81727
  const ref = conceptIdForStashFile(type, ".", relPath);
@@ -81775,7 +81867,7 @@ function workflowFrontendDiagnostics(relPath, raw, parsePath2) {
81775
81867
  }
81776
81868
  return { errors: errors3, warnings };
81777
81869
  }
81778
- const compiled = compileWorkflowPlan(result.ir, path23.basename(parsePath2, path23.extname(parsePath2)));
81870
+ const compiled = compileWorkflowPlan(result.ir, path24.basename(parsePath2, path24.extname(parsePath2)));
81779
81871
  if (!compiled.ok) {
81780
81872
  for (const err of compiled.errors) {
81781
81873
  errors3.push({
@@ -82093,13 +82185,13 @@ function isReservedFileName(name) {
82093
82185
  }
82094
82186
  var WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
82095
82187
  function akmStashAbstains(root, absPath) {
82096
- const relPath = path24.relative(root, absPath);
82097
- if (!relPath || relPath.startsWith("..") || path24.isAbsolute(relPath))
82188
+ const relPath = path25.relative(root, absPath);
82189
+ if (!relPath || relPath.startsWith("..") || path25.isAbsolute(relPath))
82098
82190
  return false;
82099
82191
  const segments = relPath.split(/[\\/]+/).filter(Boolean);
82100
82192
  if (segments.length === 0)
82101
82193
  return false;
82102
- if (segments[0] === "env" && (absPath.endsWith(".env") || path24.basename(absPath) === ".env")) {
82194
+ if (segments[0] === "env" && (absPath.endsWith(".env") || path25.basename(absPath) === ".env")) {
82103
82195
  if (fs16.existsSync(absPath.replace(/\.env$/, ".sensitive")))
82104
82196
  return true;
82105
82197
  }
@@ -82206,7 +82298,7 @@ function recognize2(c, file) {
82206
82298
  return null;
82207
82299
  const stashDir = stashDirFor(match.type);
82208
82300
  const canonicalName = stashDir !== undefined ? conceptId.slice(stashDir.length + 1) : conceptId;
82209
- const dirPath = path24.dirname(file.absPath);
82301
+ const dirPath = path25.dirname(file.absPath);
82210
82302
  const entry = {
82211
82303
  name: canonicalName,
82212
82304
  type: match.type,
@@ -82252,13 +82344,13 @@ function renderExecutionSource(c, file) {
82252
82344
  });
82253
82345
  }
82254
82346
  function buildOverlayContext(root, relPathInput, raw) {
82255
- const absPath = path24.join(root, relPathInput);
82256
- const relPath = path24.relative(root, absPath).replace(/\\/g, "/");
82257
- const ext = path24.extname(absPath).toLowerCase();
82258
- const fileName = path24.basename(absPath);
82259
- const parentDirAbs = path24.dirname(absPath);
82260
- const parentDir = path24.basename(parentDirAbs);
82261
- const relDir = path24.dirname(relPath).replace(/\\/g, "/");
82347
+ const absPath = path25.join(root, relPathInput);
82348
+ const relPath = path25.relative(root, absPath).replace(/\\/g, "/");
82349
+ const ext = path25.extname(absPath).toLowerCase();
82350
+ const fileName = path25.basename(absPath);
82351
+ const parentDirAbs = path25.dirname(absPath);
82352
+ const parentDir = path25.basename(parentDirAbs);
82353
+ const relDir = path25.dirname(relPath).replace(/\\/g, "/");
82262
82354
  const ancestorDirs = relDir === "." ? [] : relDir.split("/").filter((seg) => seg.length > 0);
82263
82355
  let cachedFrontmatter;
82264
82356
  let frontmatterComputed = false;
@@ -82356,13 +82448,13 @@ var akmAdapter = {
82356
82448
  const posix = conceptId.replace(/\\/g, "/");
82357
82449
  const slash = posix.indexOf("/");
82358
82450
  if (slash <= 0)
82359
- return [{ path: path24.join(c.root, `${posix}.md`), conceptId: posix }];
82451
+ return [{ path: path25.join(c.root, `${posix}.md`), conceptId: posix }];
82360
82452
  const head = posix.slice(0, slash);
82361
82453
  const rest = posix.slice(slash + 1);
82362
82454
  const type = stashDirToType(head);
82363
82455
  if (type === undefined || rest.length === 0)
82364
82456
  return [];
82365
- const canonical = assetPathCandidatesForName(type, path24.join(c.root, head), rest);
82457
+ const canonical = assetPathCandidatesForName(type, path25.join(c.root, head), rest);
82366
82458
  const loose = assetPathCandidatesForName(type, c.root, rest);
82367
82459
  return [...new Set([...canonical, ...loose])].map((candidatePath) => ({
82368
82460
  path: candidatePath,
@@ -82377,18 +82469,18 @@ var akmAdapter = {
82377
82469
  const rest = posix.slice(slash + 1);
82378
82470
  const type = stashDirToType(head);
82379
82471
  if (type !== undefined && rest.length > 0) {
82380
- const typeDir = path24.join(c.root, head);
82472
+ const typeDir = path25.join(c.root, head);
82381
82473
  return assetPathForName(type, typeDir, rest);
82382
82474
  }
82383
82475
  }
82384
- return path24.join(c.root, `${posix}.md`);
82476
+ return path25.join(c.root, `${posix}.md`);
82385
82477
  },
82386
82478
  directoryList(_c) {
82387
82479
  return [...new Set(stashDirNames())];
82388
82480
  },
82389
82481
  looksLikeRoot(root) {
82390
82482
  try {
82391
- if (fs16.statSync(path24.join(root, ".stash")).isDirectory())
82483
+ if (fs16.statSync(path25.join(root, ".stash")).isDirectory())
82392
82484
  return true;
82393
82485
  } catch {}
82394
82486
  const ownedDirNames = new Set(stashDirNames());
@@ -82406,10 +82498,10 @@ var akmAdapter = {
82406
82498
  return false;
82407
82499
  const expectedType = stashDirToType(only.name);
82408
82500
  try {
82409
- const markdown = fs16.readdirSync(path24.join(root, only.name), { withFileTypes: true }).find((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md"));
82501
+ const markdown = fs16.readdirSync(path25.join(root, only.name), { withFileTypes: true }).find((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".md"));
82410
82502
  if (!markdown)
82411
82503
  return true;
82412
- const data = parseFrontmatter(fs16.readFileSync(path24.join(root, only.name, markdown.name), "utf8")).data;
82504
+ const data = parseFrontmatter(fs16.readFileSync(path25.join(root, only.name, markdown.name), "utf8")).data;
82413
82505
  const declaredType = typeof data.type === "string" ? data.type.trim() : "";
82414
82506
  return !declaredType || declaredType === expectedType;
82415
82507
  } catch {
@@ -82420,7 +82512,7 @@ var akmAdapter = {
82420
82512
 
82421
82513
  // src/core/adapter/adapters/akm-task-adapter.ts
82422
82514
  import fs17 from "fs";
82423
- import path25 from "path";
82515
+ import path26 from "path";
82424
82516
  init_common();
82425
82517
  var COMPONENT_ID2 = "main";
82426
82518
  var TASK_EXT = TASK_EXTENSION;
@@ -82451,7 +82543,7 @@ async function validate3(c, changes, ctx) {
82451
82543
  const raw = change.after ?? await ctx.readFile(change.path);
82452
82544
  if (typeof raw !== "string")
82453
82545
  continue;
82454
- const ext = path25.extname(change.path).toLowerCase();
82546
+ const ext = path26.extname(change.path).toLowerCase();
82455
82547
  if (ext !== TASK_EXT && ext !== TASK_NEAR_MISS_EXTENSION)
82456
82548
  continue;
82457
82549
  const relPath = toPosix(change.path);
@@ -82486,13 +82578,13 @@ var akmTaskAdapter = {
82486
82578
  readCandidates(c, conceptId) {
82487
82579
  const posix = toPosix(conceptId).replace(/\.ya?ml$/i, "");
82488
82580
  return [
82489
- { path: path25.join(c.root, `${posix}.yml`), conceptId: posix },
82490
- { path: path25.join(c.root, `${posix}.yaml`), conceptId: posix }
82581
+ { path: path26.join(c.root, `${posix}.yml`), conceptId: posix },
82582
+ { path: path26.join(c.root, `${posix}.yaml`), conceptId: posix }
82491
82583
  ];
82492
82584
  },
82493
82585
  placeNew(c, conceptId) {
82494
82586
  const posix = toPosix(conceptId);
82495
- return path25.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
82587
+ return path26.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
82496
82588
  },
82497
82589
  directoryList() {
82498
82590
  return ["."];
@@ -82505,11 +82597,11 @@ var akmTaskAdapter = {
82505
82597
  return false;
82506
82598
  }
82507
82599
  for (const entry of entries) {
82508
- if (!entry.isFile() || path25.extname(entry.name).toLowerCase() !== TASK_EXT)
82600
+ if (!entry.isFile() || path26.extname(entry.name).toLowerCase() !== TASK_EXT)
82509
82601
  continue;
82510
82602
  let raw;
82511
82603
  try {
82512
- raw = fs17.readFileSync(path25.join(root, entry.name), "utf8");
82604
+ raw = fs17.readFileSync(path26.join(root, entry.name), "utf8");
82513
82605
  } catch {
82514
82606
  continue;
82515
82607
  }
@@ -82527,7 +82619,7 @@ init_compile();
82527
82619
  init_frontmatter();
82528
82620
  init_common();
82529
82621
  import fs18 from "fs";
82530
- import path26 from "path";
82622
+ import path27 from "path";
82531
82623
  var COMPONENT_ID3 = "main";
82532
82624
  var WORKFLOW_EXTS = new Set([".md", ".yml"]);
82533
82625
  function conceptIdOf(relPath) {
@@ -82581,8 +82673,8 @@ async function validate4(c, changes, ctx) {
82581
82673
  const raw = change.after ?? await ctx.readFile(change.path);
82582
82674
  if (typeof raw !== "string")
82583
82675
  continue;
82584
- const ext = path26.extname(change.path).toLowerCase();
82585
- if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path26.basename(change.path)))
82676
+ const ext = path27.extname(change.path).toLowerCase();
82677
+ if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path27.basename(change.path)))
82586
82678
  continue;
82587
82679
  const relPath = toPosix(change.path);
82588
82680
  if (ext === ".yml") {
@@ -82611,12 +82703,12 @@ function hasTopLevelWorkflowFile(root, entries) {
82611
82703
  for (const entry of entries) {
82612
82704
  if (!entry.isFile())
82613
82705
  continue;
82614
- const ext = path26.extname(entry.name).toLowerCase();
82706
+ const ext = path27.extname(entry.name).toLowerCase();
82615
82707
  if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(entry.name))
82616
82708
  continue;
82617
82709
  let raw;
82618
82710
  try {
82619
- raw = fs18.readFileSync(path26.join(root, entry.name), "utf8");
82711
+ raw = fs18.readFileSync(path27.join(root, entry.name), "utf8");
82620
82712
  } catch {
82621
82713
  continue;
82622
82714
  }
@@ -82636,16 +82728,16 @@ var akmWorkflowAdapter = {
82636
82728
  readCandidates(c, conceptId) {
82637
82729
  const posix = toPosix(conceptId);
82638
82730
  const canonical = posix.replace(/\.(?:md|yml)$/i, "");
82639
- return /\.(?:md|yml)$/i.test(posix) ? [{ path: path26.join(c.root, posix), conceptId: canonical }] : [
82640
- { path: path26.join(c.root, `${posix}.md`), conceptId: canonical },
82641
- { path: path26.join(c.root, `${posix}.yml`), conceptId: canonical }
82731
+ return /\.(?:md|yml)$/i.test(posix) ? [{ path: path27.join(c.root, posix), conceptId: canonical }] : [
82732
+ { path: path27.join(c.root, `${posix}.md`), conceptId: canonical },
82733
+ { path: path27.join(c.root, `${posix}.yml`), conceptId: canonical }
82642
82734
  ];
82643
82735
  },
82644
82736
  placeNew(c, conceptId) {
82645
82737
  const posix = toPosix(conceptId);
82646
82738
  if (/\.(?:md|yml)$/i.test(posix))
82647
- return path26.join(c.root, posix);
82648
- return path26.join(c.root, `${posix}.md`);
82739
+ return path27.join(c.root, posix);
82740
+ return path27.join(c.root, `${posix}.md`);
82649
82741
  },
82650
82742
  directoryList() {
82651
82743
  return ["."];
@@ -82663,10 +82755,10 @@ var akmWorkflowAdapter = {
82663
82755
 
82664
82756
  // src/core/adapter/adapters/claude-adapter.ts
82665
82757
  import fs19 from "fs";
82666
- import path28 from "path";
82758
+ import path29 from "path";
82667
82759
 
82668
82760
  // src/core/adapter/adapters/tool-dir-shared.ts
82669
- import path27 from "path";
82761
+ import path28 from "path";
82670
82762
  init_frontmatter();
82671
82763
  init_common();
82672
82764
  var CANONICAL_COMMAND_DIR = "commands";
@@ -82688,7 +82780,7 @@ function classify(relPath, layout) {
82688
82780
  return { type: "instruction", conceptId: layout.instructionConceptId, name: layout.instructionConceptId };
82689
82781
  }
82690
82782
  const head = segs[0];
82691
- const ext = path27.extname(base3).toLowerCase();
82783
+ const ext = path28.extname(base3).toLowerCase();
82692
82784
  if (layout.skillDirs.has(head)) {
82693
82785
  if (segs.length === 3 && base3 === SKILL_MANIFEST2) {
82694
82786
  return { type: "skill", conceptId: `${segs[0]}/${segs[1]}`, name: segs[1] };
@@ -82737,24 +82829,24 @@ function recognizeToolDir(layout, c, file) {
82737
82829
  function placeNewToolDir(layout, c, conceptId) {
82738
82830
  const posix = toPosix(conceptId);
82739
82831
  if (posix === layout.instructionConceptId)
82740
- return path27.join(c.root, layout.instructionFile);
82832
+ return path28.join(c.root, layout.instructionFile);
82741
82833
  const segs = posix.split("/").filter((s) => s.length > 0);
82742
82834
  const head = segs[0];
82743
82835
  const rest = segs.slice(1).join("/");
82744
82836
  if (rest.length > 0) {
82745
82837
  if (layout.skillDirs.has(head))
82746
- return path27.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST2);
82838
+ return path28.join(c.root, CANONICAL_SKILL_DIR, rest, SKILL_MANIFEST2);
82747
82839
  if (layout.commandDirs.has(head))
82748
- return path27.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
82840
+ return path28.join(c.root, CANONICAL_COMMAND_DIR, `${rest}.md`);
82749
82841
  if (layout.agentDirs.has(head))
82750
- return path27.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
82842
+ return path28.join(c.root, CANONICAL_AGENT_DIR, `${rest}.md`);
82751
82843
  }
82752
- return path27.join(c.root, `${posix}.md`);
82844
+ return path28.join(c.root, `${posix}.md`);
82753
82845
  }
82754
82846
  function readCandidatesToolDir(layout, c, conceptId) {
82755
82847
  const posix = toPosix(conceptId);
82756
82848
  if (posix === layout.instructionConceptId) {
82757
- return [{ path: path27.join(c.root, layout.instructionFile), conceptId: posix }];
82849
+ return [{ path: path28.join(c.root, layout.instructionFile), conceptId: posix }];
82758
82850
  }
82759
82851
  const segs = posix.split("/").filter((segment) => segment.length > 0);
82760
82852
  const head = segs[0];
@@ -82762,10 +82854,10 @@ function readCandidatesToolDir(layout, c, conceptId) {
82762
82854
  if (!head || !rest)
82763
82855
  return [];
82764
82856
  if (layout.skillDirs.has(head)) {
82765
- return segs.length === 2 ? [{ path: path27.join(c.root, head, rest, SKILL_MANIFEST2), conceptId: posix }] : [];
82857
+ return segs.length === 2 ? [{ path: path28.join(c.root, head, rest, SKILL_MANIFEST2), conceptId: posix }] : [];
82766
82858
  }
82767
82859
  if (layout.commandDirs.has(head) || layout.agentDirs.has(head)) {
82768
- return [{ path: path27.join(c.root, head, `${rest}.md`), conceptId: posix }];
82860
+ return [{ path: path28.join(c.root, head, `${rest}.md`), conceptId: posix }];
82769
82861
  }
82770
82862
  return [];
82771
82863
  }
@@ -82877,12 +82969,12 @@ function dirExists(p) {
82877
82969
  }
82878
82970
  function claudeLooksLikeRoot(root) {
82879
82971
  try {
82880
- if (!fs19.existsSync(path28.join(root, "CLAUDE.md")))
82972
+ if (!fs19.existsSync(path29.join(root, "CLAUDE.md")))
82881
82973
  return false;
82882
82974
  } catch {
82883
82975
  return false;
82884
82976
  }
82885
- return ["commands", "agents", "skills"].some((d) => dirExists(path28.join(root, d)));
82977
+ return ["commands", "agents", "skills"].some((d) => dirExists(path29.join(root, d)));
82886
82978
  }
82887
82979
  var claudeAdapter = makeToolDirAdapter(LAYOUT, claudeLooksLikeRoot);
82888
82980
 
@@ -82890,7 +82982,7 @@ var claudeAdapter = makeToolDirAdapter(LAYOUT, claudeLooksLikeRoot);
82890
82982
  init_asset_placement();
82891
82983
  init_common();
82892
82984
  import fs20 from "fs";
82893
- import path29 from "path";
82985
+ import path30 from "path";
82894
82986
  var COMPONENT_ID4 = "main";
82895
82987
  var ENV_DIR = "env";
82896
82988
  var SECRETS_DIR = "secrets";
@@ -82992,7 +83084,7 @@ var dotenvAdapter = {
82992
83084
  const type = typeForStashDir(head);
82993
83085
  if (type !== "env" && type !== "secret" || rest.length === 0)
82994
83086
  return [];
82995
- const primaries = assetPathCandidatesForName(type, path29.join(c.root, head), rest);
83087
+ const primaries = assetPathCandidatesForName(type, path30.join(c.root, head), rest);
82996
83088
  const expanded = primaries.flatMap((primary) => type === "env" ? [primary, primary.replace(/\.env$/i, ".sensitive")] : [primary, `${primary}.sensitive`, `${primary}.lock`]);
82997
83089
  return expanded.map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
82998
83090
  },
@@ -83004,10 +83096,10 @@ var dotenvAdapter = {
83004
83096
  const rest = posix.slice(slash + 1);
83005
83097
  const type = typeForStashDir(head);
83006
83098
  if ((type === "env" || type === "secret") && rest.length > 0) {
83007
- return assetPathForName(type, path29.join(c.root, head), rest);
83099
+ return assetPathForName(type, path30.join(c.root, head), rest);
83008
83100
  }
83009
83101
  }
83010
- return path29.join(c.root, posix);
83102
+ return path30.join(c.root, posix);
83011
83103
  },
83012
83104
  directoryList() {
83013
83105
  return [ENV_DIR, SECRETS_DIR];
@@ -83032,7 +83124,7 @@ var dotenvAdapter = {
83032
83124
  init_frontmatter();
83033
83125
  init_common();
83034
83126
  init_recognition_util();
83035
- import path30 from "path";
83127
+ import path31 from "path";
83036
83128
  var COMPONENT_ID5 = "main";
83037
83129
  var DOCUMENT_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".text"]);
83038
83130
  function isReserved2(base3) {
@@ -83098,17 +83190,17 @@ var genericFilesAdapter = {
83098
83190
  validate: validate6,
83099
83191
  readCandidates(c, conceptId) {
83100
83192
  const posix = toPosix(conceptId);
83101
- const extension = path30.extname(posix).toLowerCase();
83193
+ const extension = path31.extname(posix).toLowerCase();
83102
83194
  const documentCandidates = [...DOCUMENT_EXTENSIONS].map((candidateExtension) => ({
83103
- path: path30.join(c.root, `${posix}${candidateExtension}`),
83195
+ path: path31.join(c.root, `${posix}${candidateExtension}`),
83104
83196
  conceptId: posix
83105
83197
  }));
83106
- return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path30.join(c.root, posix), conceptId: posix }, ...documentCandidates];
83198
+ return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path31.join(c.root, posix), conceptId: posix }, ...documentCandidates];
83107
83199
  },
83108
83200
  placeNew(c, conceptId) {
83109
83201
  const posix = toPosix(conceptId);
83110
- const hasExt = path30.extname(posix) !== "";
83111
- return path30.join(c.root, hasExt ? posix : `${posix}.md`);
83202
+ const hasExt = path31.extname(posix) !== "";
83203
+ return path31.join(c.root, hasExt ? posix : `${posix}.md`);
83112
83204
  },
83113
83205
  looksLikeRoot() {
83114
83206
  return false;
@@ -83120,7 +83212,7 @@ init_dist();
83120
83212
  init_frontmatter();
83121
83213
  init_common();
83122
83214
  import fs21 from "fs";
83123
- import path31 from "path";
83215
+ import path32 from "path";
83124
83216
  var WIKI_COMPONENT_ID = "main";
83125
83217
  var WIKI_SOURCE_TYPE = "wiki-source";
83126
83218
  var DEFAULT_PAGE_KIND = "note";
@@ -83178,7 +83270,7 @@ function resolveXref(xref, bundleId) {
83178
83270
  return target.length > 0 ? target : null;
83179
83271
  }
83180
83272
  function resolveBodyLinks(body, fileRelPath) {
83181
- const dir = path31.posix.dirname(toPosix(fileRelPath));
83273
+ const dir = path32.posix.dirname(toPosix(fileRelPath));
83182
83274
  const linkRe = /\[[^\]]*\]\(([^)]+)\)/g;
83183
83275
  const out = [];
83184
83276
  const seen = new Set;
@@ -83204,10 +83296,10 @@ function resolveBodyLinks(body, fileRelPath) {
83204
83296
  continue;
83205
83297
  let resolved;
83206
83298
  if (target.startsWith("/")) {
83207
- resolved = path31.posix.normalize(target.slice(1));
83299
+ resolved = path32.posix.normalize(target.slice(1));
83208
83300
  } else {
83209
83301
  const base3 = dir === "." ? "" : dir;
83210
- resolved = path31.posix.normalize(path31.posix.join(base3, target));
83302
+ resolved = path32.posix.normalize(path32.posix.join(base3, target));
83211
83303
  }
83212
83304
  if (resolved.startsWith("../") || resolved === ".." || resolved.startsWith("/"))
83213
83305
  continue;
@@ -83389,19 +83481,19 @@ var llmWikiAdapter = {
83389
83481
  validate: validate7,
83390
83482
  readCandidates(c, conceptId) {
83391
83483
  const canonical = toPosix(conceptId).replace(/\.md$/i, "");
83392
- return [{ path: path31.join(c.root, `${canonical}.md`), conceptId: canonical }];
83484
+ return [{ path: path32.join(c.root, `${canonical}.md`), conceptId: canonical }];
83393
83485
  },
83394
83486
  placeNew(c, conceptId) {
83395
- return path31.join(c.root, `${conceptId}.md`);
83487
+ return path32.join(c.root, `${conceptId}.md`);
83396
83488
  },
83397
83489
  directoryList(_c) {
83398
83490
  return ["."];
83399
83491
  },
83400
83492
  looksLikeRoot(root) {
83401
83493
  try {
83402
- if (!fs21.existsSync(path31.join(root, "schema.md")))
83494
+ if (!fs21.existsSync(path32.join(root, "schema.md")))
83403
83495
  return false;
83404
- return fs21.statSync(path31.join(root, PAGES_SUBDIR)).isDirectory();
83496
+ return fs21.statSync(path32.join(root, PAGES_SUBDIR)).isDirectory();
83405
83497
  } catch {
83406
83498
  return false;
83407
83499
  }
@@ -83412,7 +83504,7 @@ var llmWikiAdapter = {
83412
83504
  init_frontmatter();
83413
83505
  init_common();
83414
83506
  import fs22 from "fs";
83415
- import path32 from "path";
83507
+ import path33 from "path";
83416
83508
  var CONSUMED_FRONTMATTER_KEYS = [
83417
83509
  "type",
83418
83510
  "title",
@@ -83484,7 +83576,7 @@ function isReservedFileName2(name) {
83484
83576
  return RESERVED_FILES.has(name.toLowerCase());
83485
83577
  }
83486
83578
  function resolveOkfLinks(body, fileRelPath) {
83487
- const dir = path32.posix.dirname(toPosix(fileRelPath));
83579
+ const dir = path33.posix.dirname(toPosix(fileRelPath));
83488
83580
  const definitions = new Map;
83489
83581
  for (const match of body.matchAll(/^\s*\[([^\]]+)\]:\s*(\S+)/gm)) {
83490
83582
  definitions.set(match[1].trim().toLowerCase(), match[2]);
@@ -83522,10 +83614,10 @@ function resolveOkfLinks(body, fileRelPath) {
83522
83614
  continue;
83523
83615
  let resolved;
83524
83616
  if (target.startsWith("/")) {
83525
- resolved = path32.posix.normalize(target.slice(1));
83617
+ resolved = path33.posix.normalize(target.slice(1));
83526
83618
  } else {
83527
83619
  const base3 = dir === "." ? "" : dir;
83528
- resolved = path32.posix.normalize(path32.posix.join(base3, target));
83620
+ resolved = path33.posix.normalize(path33.posix.join(base3, target));
83529
83621
  }
83530
83622
  if (resolved.startsWith("../") || resolved === ".." || resolved.startsWith("/"))
83531
83623
  continue;
@@ -83653,13 +83745,13 @@ var okfAdapter = {
83653
83745
  validate: validate8,
83654
83746
  readCandidates(c, conceptId) {
83655
83747
  const canonical = conceptId.replace(/\\/g, "/").replace(/\.md$/i, "");
83656
- return [{ path: path32.join(c.root, `${canonical}.md`), conceptId: canonical }];
83748
+ return [{ path: path33.join(c.root, `${canonical}.md`), conceptId: canonical }];
83657
83749
  },
83658
83750
  directoryList(_c) {
83659
83751
  return ["."];
83660
83752
  },
83661
83753
  looksLikeRoot(root) {
83662
- if (fs22.existsSync(path32.join(root, "index.md")))
83754
+ if (fs22.existsSync(path33.join(root, "index.md")))
83663
83755
  return true;
83664
83756
  const stack = [root];
83665
83757
  while (stack.length > 0) {
@@ -83675,7 +83767,7 @@ var okfAdapter = {
83675
83767
  for (const entry of entries) {
83676
83768
  if (entry.isSymbolicLink() || entry.name === ".git")
83677
83769
  continue;
83678
- const absolute = path32.join(current, entry.name);
83770
+ const absolute = path33.join(current, entry.name);
83679
83771
  if (entry.isDirectory()) {
83680
83772
  stack.push(absolute);
83681
83773
  continue;
@@ -83693,7 +83785,7 @@ var okfAdapter = {
83693
83785
 
83694
83786
  // src/core/adapter/adapters/opencode-adapter.ts
83695
83787
  import fs23 from "fs";
83696
- import path33 from "path";
83788
+ import path34 from "path";
83697
83789
  var LAYOUT2 = {
83698
83790
  adapterId: "opencode",
83699
83791
  componentId: ".opencode",
@@ -83720,11 +83812,11 @@ function dirExists2(p) {
83720
83812
  }
83721
83813
  }
83722
83814
  function opencodeLooksLikeRoot(root) {
83723
- if (CONFIG_FILES.some((f) => fileExists(path33.join(root, f))))
83815
+ if (CONFIG_FILES.some((f) => fileExists(path34.join(root, f))))
83724
83816
  return true;
83725
- if (!fileExists(path33.join(root, "AGENTS.md")))
83817
+ if (!fileExists(path34.join(root, "AGENTS.md")))
83726
83818
  return false;
83727
- return TOOL_DIRS.some((d) => dirExists2(path33.join(root, d)));
83819
+ return TOOL_DIRS.some((d) => dirExists2(path34.join(root, d)));
83728
83820
  }
83729
83821
  var opencodeAdapter = makeToolDirAdapter(LAYOUT2, opencodeLooksLikeRoot);
83730
83822
 
@@ -83733,7 +83825,7 @@ init_dist();
83733
83825
  init_frontmatter();
83734
83826
  init_common();
83735
83827
  import fs24 from "fs";
83736
- import path34 from "path";
83828
+ import path35 from "path";
83737
83829
  var COMPONENT_ID6 = "main";
83738
83830
  var PAGES_PREFIX = "stash/knowledge/";
83739
83831
  var MANIFEST_FILE = "manifest.json";
@@ -83821,12 +83913,12 @@ var websiteSnapshotAdapter = {
83821
83913
  validate: validate9,
83822
83914
  readCandidates(c, conceptId) {
83823
83915
  const canonical = toPosix(conceptId).replace(/\.md$/i, "");
83824
- return [{ path: path34.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
83916
+ return [{ path: path35.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
83825
83917
  },
83826
83918
  looksLikeRoot(root) {
83827
83919
  let raw;
83828
83920
  try {
83829
- raw = fs24.readFileSync(path34.join(root, MANIFEST_FILE), "utf8");
83921
+ raw = fs24.readFileSync(path35.join(root, MANIFEST_FILE), "utf8");
83830
83922
  } catch {
83831
83923
  return false;
83832
83924
  }
@@ -83939,7 +84031,7 @@ function isSourceWriteActivated(source) {
83939
84031
 
83940
84032
  // src/core/adapter/detect-adapter.ts
83941
84033
  import fs25 from "fs";
83942
- import path35 from "path";
84034
+ import path36 from "path";
83943
84035
  var SHADOWABLE_ADAPTER_IDS = new Set(["agent-skills", "claude", "opencode"]);
83944
84036
  function hasExtraAkmContent(root, winnerId) {
83945
84037
  const akm = adapterForId("akm");
@@ -83961,13 +84053,13 @@ function hasExtraAkmContent(root, winnerId) {
83961
84053
  continue;
83962
84054
  if (winnerId === "agent-skills") {
83963
84055
  try {
83964
- if (fs25.statSync(path35.join(root, entry.name, "SKILL.md")).isFile())
84056
+ if (fs25.statSync(path36.join(root, entry.name, "SKILL.md")).isFile())
83965
84057
  continue;
83966
84058
  } catch {}
83967
84059
  }
83968
84060
  let children;
83969
84061
  try {
83970
- children = fs25.readdirSync(path35.join(root, entry.name), { withFileTypes: true });
84062
+ children = fs25.readdirSync(path36.join(root, entry.name), { withFileTypes: true });
83971
84063
  } catch {
83972
84064
  continue;
83973
84065
  }
@@ -83992,48 +84084,7 @@ function detectAdapterId(root, fallback = "akm") {
83992
84084
 
83993
84085
  // src/indexer/installations.ts
83994
84086
  init_asset_placement();
83995
-
83996
- // src/core/bundle-id.ts
83997
- init_asset_ref();
83998
- import crypto5 from "crypto";
83999
- import path36 from "path";
84000
- function slugForPath(sourcePath) {
84001
- const resolved = path36.resolve(sourcePath);
84002
- const base3 = path36.basename(resolved).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
84003
- if (base3.length > 0)
84004
- return base3;
84005
- return `bundle-${shortHash(resolved)}`;
84006
- }
84007
- function deriveBundleId(registryId, sourcePath, usedIds) {
84008
- const preferred = registryId && registryId.length > 0 && isBundleSlug(registryId) ? registryId : slugForPath(sourcePath);
84009
- const id = ensureUniqueId(preferred, sourcePath, usedIds);
84010
- usedIds.add(id);
84011
- return id;
84012
- }
84013
- function deriveBundleIds(sources) {
84014
- const usedIds = new Set;
84015
- const reservedIds = new Set(sources.flatMap((source) => source.registryId && isBundleSlug(source.registryId) ? [source.registryId] : []));
84016
- return sources.map((source) => {
84017
- const id = source.registryId && isBundleSlug(source.registryId) ? deriveBundleId(source.registryId, source.path, usedIds) : deriveBundleId(undefined, source.path, new Set([...usedIds, ...reservedIds]));
84018
- usedIds.add(id);
84019
- return id;
84020
- });
84021
- }
84022
- function ensureUniqueId(preferred, sourcePath, used) {
84023
- if (!used.has(preferred))
84024
- return preferred;
84025
- const suffixed = `${preferred}-${shortHash(path36.resolve(sourcePath))}`;
84026
- if (!used.has(suffixed))
84027
- return suffixed;
84028
- let n = 2;
84029
- while (used.has(`${suffixed}-${n}`))
84030
- n++;
84031
- return `${suffixed}-${n}`;
84032
- }
84033
- function shortHash(input) {
84034
- return crypto5.createHash("sha256").update(input).digest("hex").slice(0, 8);
84035
- }
84036
- // src/indexer/installations.ts
84087
+ init_bundle_id();
84037
84088
  var FALLBACK_ADAPTER_ID = "akm";
84038
84089
  function deriveInstallations(sources) {
84039
84090
  const ids = deriveBundleIds(sources);
@@ -84072,6 +84123,7 @@ function deriveEntryProvenance(bundle, type, name, adapterConceptId) {
84072
84123
  // src/indexer/search/search-source.ts
84073
84124
  init_common();
84074
84125
  import path49 from "path";
84126
+ init_paths();
84075
84127
 
84076
84128
  // src/core/write-source.ts
84077
84129
  import fs36 from "fs";
@@ -87042,6 +87094,7 @@ function buildGithubTargetAliases(canonicalUrl) {
87042
87094
  // src/core/write-source.ts
87043
87095
  init_asset_placement();
87044
87096
  init_resolve_ref();
87097
+ init_bundle_id();
87045
87098
  init_common();
87046
87099
  init_errors();
87047
87100
  init_warn();
@@ -92252,14 +92305,14 @@ function resolveSourceEntries(overrideStashDir, existingConfig) {
92252
92305
  const component = bundleComponentConfig(config.bundles?.[entry.name ?? ""]);
92253
92306
  const contentRoot = resolveEntryContentDir(entry);
92254
92307
  if (contentRoot == null) {
92255
- const unresolvedPath = path49.join(implicitStashDir ?? process.cwd(), ".akm", "unresolved-sources", entry.name ?? entry.type);
92308
+ const unresolvedPath = path49.join(getUnresolvedSourcesDir(implicitStashDir ?? process.cwd()), entry.name ?? entry.type);
92256
92309
  addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
92257
92310
  continue;
92258
92311
  }
92259
92312
  const dir = path49.resolve(contentRoot, component?.root ?? ".");
92260
92313
  if (!isWithin(dir, contentRoot)) {
92261
92314
  warn(`Warning: component root "${component?.root}" escapes bundle "${entry.name}"; skipping source.`);
92262
- const unresolvedPath = path49.join(contentRoot, ".akm", "unresolved-sources", entry.name ?? entry.type);
92315
+ const unresolvedPath = path49.join(getUnresolvedSourcesDir(contentRoot), entry.name ?? entry.type);
92263
92316
  addSource(unresolvedPath, entry.name, component?.writable ?? resolveWritable(entry), entry.type, component?.adapter, true);
92264
92317
  continue;
92265
92318
  }
@@ -95429,31 +95482,178 @@ async function recoverStaleTxns(stashDir) {
95429
95482
  return recovered.map(journalToEntry);
95430
95483
  }
95431
95484
 
95485
+ // scripts/akm-migrate/migrate/writer-relocation.ts
95486
+ import fs48 from "fs";
95487
+ import path61 from "path";
95488
+ init_paths();
95489
+ function relocationSpecs(stashDir) {
95490
+ return [
95491
+ { key: "distillRejected", oldRelative: "distill-rejected", newDir: getDistillRejectedDir(stashDir) },
95492
+ { key: "evalCases", oldRelative: "eval-cases", newDir: getEvalCasesDir(stashDir) },
95493
+ {
95494
+ key: "measurementVerdicts",
95495
+ oldRelative: ["measurement", "verdicts"],
95496
+ newDir: getMeasurementVerdictsDir(stashDir)
95497
+ }
95498
+ ];
95499
+ }
95500
+ var LOCK_NAMES = ["improve.lock", "consolidate.lock", "reflect-distill.lock", "triage.lock"];
95501
+ function mutexSiblingName(lockName) {
95502
+ return `.${lockName}.operations.sensitive`;
95503
+ }
95504
+ function fileCountIfExists(dir) {
95505
+ let entries;
95506
+ try {
95507
+ entries = fs48.readdirSync(dir, { withFileTypes: true });
95508
+ } catch {
95509
+ return;
95510
+ }
95511
+ return entries.filter((entry) => entry.isFile()).length;
95512
+ }
95513
+ function statFileIfExists(filePath) {
95514
+ try {
95515
+ const stat = fs48.statSync(filePath);
95516
+ return stat.isFile() ? stat : undefined;
95517
+ } catch {
95518
+ return;
95519
+ }
95520
+ }
95521
+ function classifyLockArtifacts(akmDir) {
95522
+ const removable = [];
95523
+ const skipped = [];
95524
+ for (const lockName of LOCK_NAMES) {
95525
+ const lockPath = path61.join(akmDir, lockName);
95526
+ const mutexPath = path61.join(akmDir, mutexSiblingName(lockName));
95527
+ const lockStat = statFileIfExists(lockPath);
95528
+ const mutexStat = statFileIfExists(mutexPath);
95529
+ if (!lockStat) {
95530
+ if (mutexStat)
95531
+ removable.push({ path: mutexPath, sizeBytes: mutexStat.size });
95532
+ continue;
95533
+ }
95534
+ const probe = probeLock(lockPath);
95535
+ if (probe.state === "held") {
95536
+ skipped.push({ path: lockPath, reason: "held", holderPid: probe.holderPid });
95537
+ continue;
95538
+ }
95539
+ if (probe.state === "inaccessible") {
95540
+ skipped.push({ path: lockPath, reason: "inaccessible" });
95541
+ continue;
95542
+ }
95543
+ if (probe.state === "absent")
95544
+ continue;
95545
+ removable.push({ path: lockPath, sizeBytes: lockStat.size });
95546
+ if (mutexStat)
95547
+ removable.push({ path: mutexPath, sizeBytes: mutexStat.size });
95548
+ }
95549
+ return { removable, skipped };
95550
+ }
95551
+ function findWriterRelocationEntries(stashDir) {
95552
+ const akmDir = path61.join(stashDir, ".akm");
95553
+ const directories = [];
95554
+ for (const spec of relocationSpecs(stashDir)) {
95555
+ const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
95556
+ const oldPath = path61.join(akmDir, ...relativeParts);
95557
+ const fileCount = fileCountIfExists(oldPath);
95558
+ if (fileCount === undefined || fileCount === 0)
95559
+ continue;
95560
+ directories.push({ key: spec.key, oldPath, newPath: spec.newDir, fileCount });
95561
+ }
95562
+ const { removable, skipped } = classifyLockArtifacts(akmDir);
95563
+ return { directories, lockArtifacts: removable, skippedLocks: skipped };
95564
+ }
95565
+ function moveFile(oldFilePath, newFilePath) {
95566
+ try {
95567
+ fs48.renameSync(oldFilePath, newFilePath);
95568
+ } catch (error2) {
95569
+ if (error2.code !== "EXDEV")
95570
+ throw error2;
95571
+ fs48.copyFileSync(oldFilePath, newFilePath);
95572
+ fs48.rmSync(oldFilePath, { force: true });
95573
+ }
95574
+ }
95575
+ function moveDirectoryContents(entry) {
95576
+ const errors3 = [];
95577
+ let moved = 0;
95578
+ fs48.mkdirSync(entry.newPath, { recursive: true });
95579
+ let names;
95580
+ try {
95581
+ names = fs48.readdirSync(entry.oldPath).sort();
95582
+ } catch {
95583
+ return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved: 0, errors: [] };
95584
+ }
95585
+ for (const name of names) {
95586
+ const oldFilePath = path61.join(entry.oldPath, name);
95587
+ const newFilePath = path61.join(entry.newPath, name);
95588
+ let oldStat;
95589
+ try {
95590
+ oldStat = fs48.lstatSync(oldFilePath);
95591
+ } catch {
95592
+ continue;
95593
+ }
95594
+ if (!oldStat.isFile())
95595
+ continue;
95596
+ if (fs48.existsSync(newFilePath))
95597
+ continue;
95598
+ try {
95599
+ moveFile(oldFilePath, newFilePath);
95600
+ moved += 1;
95601
+ } catch (error2) {
95602
+ errors3.push(`${name}: ${error2 instanceof Error ? error2.message : String(error2)}`);
95603
+ }
95604
+ }
95605
+ return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved, errors: errors3 };
95606
+ }
95607
+ function removeIfEmptyDir(dir) {
95608
+ try {
95609
+ if (fs48.readdirSync(dir).length === 0)
95610
+ fs48.rmdirSync(dir);
95611
+ } catch {}
95612
+ }
95613
+ function removeLockArtifact(entry) {
95614
+ try {
95615
+ fs48.rmSync(entry.path, { force: true });
95616
+ return { path: entry.path, removed: true };
95617
+ } catch (error2) {
95618
+ return { path: entry.path, removed: false, error: error2 instanceof Error ? error2.message : String(error2) };
95619
+ }
95620
+ }
95621
+ function applyWriterRelocation(stashDir) {
95622
+ const { directories, lockArtifacts, skippedLocks } = findWriterRelocationEntries(stashDir);
95623
+ const directoryResults = directories.map(moveDirectoryContents);
95624
+ const lockResults = lockArtifacts.map(removeLockArtifact);
95625
+ for (const spec of relocationSpecs(stashDir)) {
95626
+ const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
95627
+ removeIfEmptyDir(path61.join(stashDir, ".akm", ...relativeParts));
95628
+ }
95629
+ return { directories: directoryResults, lockArtifacts: lockResults, skippedLocks };
95630
+ }
95631
+
95432
95632
  // scripts/akm-migrate/task-migrate.ts
95433
95633
  import { randomUUID as randomUUID7 } from "crypto";
95434
- import fs51 from "fs";
95634
+ import fs53 from "fs";
95435
95635
  import os5 from "os";
95436
- import path63 from "path";
95636
+ import path64 from "path";
95437
95637
  init_errors();
95438
95638
  init_paths();
95439
95639
 
95440
95640
  // scripts/akm-migrate/migrate/task-files-to-v3.ts
95441
95641
  init_errors();
95442
95642
  import crypto6 from "crypto";
95443
- import fs49 from "fs";
95444
- import path61 from "path";
95643
+ import fs50 from "fs";
95644
+ import path62 from "path";
95445
95645
 
95446
95646
  // scripts/akm-migrate/migrate/durable-fs.ts
95447
- import fs48 from "fs";
95647
+ import fs49 from "fs";
95448
95648
  function fsyncDirectoryPortable(directory) {
95449
95649
  if (process.platform === "win32")
95450
95650
  return;
95451
95651
  try {
95452
- const fd = fs48.openSync(directory, "r");
95652
+ const fd = fs49.openSync(directory, "r");
95453
95653
  try {
95454
- fs48.fsyncSync(fd);
95654
+ fs49.fsyncSync(fd);
95455
95655
  } finally {
95456
- fs48.closeSync(fd);
95656
+ fs49.closeSync(fd);
95457
95657
  }
95458
95658
  } catch (cause) {
95459
95659
  const code = cause.code;
@@ -95467,25 +95667,25 @@ function migrationError(detail) {
95467
95667
  return new ConfigError(`Task migration to v3 failed: ${detail}`, "INVALID_CONFIG_FILE");
95468
95668
  }
95469
95669
  function contained2(root2, candidate) {
95470
- const relative = path61.relative(root2, candidate);
95471
- return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
95670
+ const relative = path62.relative(root2, candidate);
95671
+ return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
95472
95672
  }
95473
95673
  function realDirectory(filePath) {
95474
- const stat = fs49.lstatSync(filePath);
95674
+ const stat = fs50.lstatSync(filePath);
95475
95675
  if (stat.isSymbolicLink() || !stat.isDirectory())
95476
95676
  throw migrationError(`${filePath} must be a real directory.`);
95477
- return fs49.realpathSync(filePath);
95677
+ return fs50.realpathSync(filePath);
95478
95678
  }
95479
95679
  function snapshot(filePath) {
95480
- const stat = fs49.lstatSync(filePath);
95680
+ const stat = fs50.lstatSync(filePath);
95481
95681
  if (stat.isSymbolicLink() || !stat.isFile())
95482
95682
  throw migrationError(`${filePath} must be a real file.`);
95483
- const bytes = fs49.readFileSync(filePath);
95683
+ const bytes = fs50.readFileSync(filePath);
95484
95684
  return Object.freeze({ bytes, mode: stat.mode & 511 });
95485
95685
  }
95486
95686
  function writable(filePath) {
95487
95687
  try {
95488
- fs49.accessSync(filePath, fs49.constants.W_OK);
95688
+ fs50.accessSync(filePath, fs50.constants.W_OK);
95489
95689
  return true;
95490
95690
  } catch {
95491
95691
  return false;
@@ -95498,12 +95698,12 @@ function walkTasks(root2, tasksDir, out) {
95498
95698
  throw migrationError(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
95499
95699
  }
95500
95700
  const visit2 = (directory) => {
95501
- const physicalDirectory = fs49.realpathSync(directory);
95701
+ const physicalDirectory = fs50.realpathSync(directory);
95502
95702
  if (!contained2(physicalRoot, physicalDirectory)) {
95503
95703
  throw migrationError(`${directory} resolves outside bundle ${root2.bundleId}.`);
95504
95704
  }
95505
- for (const entry of fs49.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95506
- const candidate = path61.join(directory, entry.name);
95705
+ for (const entry of fs50.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95706
+ const candidate = path62.join(directory, entry.name);
95507
95707
  if (entry.isSymbolicLink())
95508
95708
  throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
95509
95709
  if (entry.isDirectory()) {
@@ -95513,7 +95713,7 @@ function walkTasks(root2, tasksDir, out) {
95513
95713
  if (!entry.isFile() || !entry.name.endsWith(".yml"))
95514
95714
  continue;
95515
95715
  const current = snapshot(candidate);
95516
- const parent = path61.dirname(candidate);
95716
+ const parent = path62.dirname(candidate);
95517
95717
  out.push({
95518
95718
  filePath: candidate,
95519
95719
  bytes: current.bytes,
@@ -95529,9 +95729,9 @@ function walkTasks(root2, tasksDir, out) {
95529
95729
  function inspectTaskToV3Files(roots) {
95530
95730
  const files = [];
95531
95731
  for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
95532
- const tasksDir = root2.layout === "akm-task" ? root2.root : path61.join(root2.root, "tasks");
95732
+ const tasksDir = root2.layout === "akm-task" ? root2.root : path62.join(root2.root, "tasks");
95533
95733
  try {
95534
- const stat = fs49.lstatSync(tasksDir);
95734
+ const stat = fs50.lstatSync(tasksDir);
95535
95735
  if (stat.isSymbolicLink())
95536
95736
  throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
95537
95737
  if (!stat.isDirectory())
@@ -95546,33 +95746,33 @@ function inspectTaskToV3Files(roots) {
95546
95746
  return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
95547
95747
  }
95548
95748
  function hashPath(filePath) {
95549
- return crypto6.createHash("sha256").update(path61.resolve(filePath)).digest("hex").slice(0, 16);
95749
+ return crypto6.createHash("sha256").update(path62.resolve(filePath)).digest("hex").slice(0, 16);
95550
95750
  }
95551
95751
  function taskMigrationBackupPath(backupRoot, filePath) {
95552
- return path61.join(backupRoot, "files", `${hashPath(filePath)}-${path61.basename(filePath)}`);
95752
+ return path62.join(backupRoot, "files", `${hashPath(filePath)}-${path62.basename(filePath)}`);
95553
95753
  }
95554
95754
  function writeDurable(filePath, bytes, mode, exclusive = false) {
95555
- fs49.mkdirSync(path61.dirname(filePath), { recursive: true });
95755
+ fs50.mkdirSync(path62.dirname(filePath), { recursive: true });
95556
95756
  const flags = exclusive ? "wx" : "w";
95557
- const fd = fs49.openSync(filePath, flags, mode);
95757
+ const fd = fs50.openSync(filePath, flags, mode);
95558
95758
  try {
95559
- fs49.writeFileSync(fd, bytes);
95560
- fs49.fsyncSync(fd);
95759
+ fs50.writeFileSync(fd, bytes);
95760
+ fs50.fsyncSync(fd);
95561
95761
  } finally {
95562
- fs49.closeSync(fd);
95762
+ fs50.closeSync(fd);
95563
95763
  }
95564
- fs49.chmodSync(filePath, mode);
95565
- fsyncDirectoryPortable(path61.dirname(filePath));
95764
+ fs50.chmodSync(filePath, mode);
95765
+ fsyncDirectoryPortable(path62.dirname(filePath));
95566
95766
  }
95567
95767
  function replaceAtomically(filePath, bytes, mode) {
95568
- const temporary = path61.join(path61.dirname(filePath), `.${path61.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
95768
+ const temporary = path62.join(path62.dirname(filePath), `.${path62.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
95569
95769
  try {
95570
95770
  writeDurable(temporary, bytes, mode, true);
95571
- fs49.renameSync(temporary, filePath);
95572
- fsyncDirectoryPortable(path61.dirname(filePath));
95771
+ fs50.renameSync(temporary, filePath);
95772
+ fsyncDirectoryPortable(path62.dirname(filePath));
95573
95773
  } finally {
95574
95774
  try {
95575
- fs49.unlinkSync(temporary);
95775
+ fs50.unlinkSync(temporary);
95576
95776
  } catch (cause) {
95577
95777
  if (cause.code !== "ENOENT")
95578
95778
  throw cause;
@@ -95611,7 +95811,7 @@ function applyTaskToV3MigrationPlan(plan, options) {
95611
95811
  const current = snapshot(change.filePath);
95612
95812
  if (!current.bytes.equals(change.after))
95613
95813
  continue;
95614
- replaceAtomically(change.filePath, fs49.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
95814
+ replaceAtomically(change.filePath, fs50.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
95615
95815
  }
95616
95816
  throw cause;
95617
95817
  }
@@ -95621,31 +95821,31 @@ function applyTaskToV3MigrationPlan(plan, options) {
95621
95821
  // scripts/akm-migrate/migrate/task-files-to-v4.ts
95622
95822
  init_errors();
95623
95823
  import crypto7 from "crypto";
95624
- import fs50 from "fs";
95625
- import path62 from "path";
95824
+ import fs51 from "fs";
95825
+ import path63 from "path";
95626
95826
  function migrationError2(detail) {
95627
95827
  return new ConfigError(`Task migration to v4 failed: ${detail}`, "INVALID_CONFIG_FILE");
95628
95828
  }
95629
95829
  function contained3(root2, candidate) {
95630
- const relative = path62.relative(root2, candidate);
95631
- return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
95830
+ const relative = path63.relative(root2, candidate);
95831
+ return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
95632
95832
  }
95633
95833
  function realDirectory2(filePath) {
95634
- const stat = fs50.lstatSync(filePath);
95834
+ const stat = fs51.lstatSync(filePath);
95635
95835
  if (stat.isSymbolicLink() || !stat.isDirectory())
95636
95836
  throw migrationError2(`${filePath} must be a real directory.`);
95637
- return fs50.realpathSync(filePath);
95837
+ return fs51.realpathSync(filePath);
95638
95838
  }
95639
95839
  function snapshot2(filePath) {
95640
- const stat = fs50.lstatSync(filePath);
95840
+ const stat = fs51.lstatSync(filePath);
95641
95841
  if (stat.isSymbolicLink() || !stat.isFile())
95642
95842
  throw migrationError2(`${filePath} must be a real file.`);
95643
- const bytes = fs50.readFileSync(filePath);
95843
+ const bytes = fs51.readFileSync(filePath);
95644
95844
  return Object.freeze({ bytes, mode: stat.mode & 511 });
95645
95845
  }
95646
95846
  function writable2(filePath) {
95647
95847
  try {
95648
- fs50.accessSync(filePath, fs50.constants.W_OK);
95848
+ fs51.accessSync(filePath, fs51.constants.W_OK);
95649
95849
  return true;
95650
95850
  } catch {
95651
95851
  return false;
@@ -95658,12 +95858,12 @@ function walkTasks2(root2, tasksDir, out) {
95658
95858
  throw migrationError2(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
95659
95859
  }
95660
95860
  const visit2 = (directory) => {
95661
- const physicalDirectory = fs50.realpathSync(directory);
95861
+ const physicalDirectory = fs51.realpathSync(directory);
95662
95862
  if (!contained3(physicalRoot, physicalDirectory)) {
95663
95863
  throw migrationError2(`${directory} resolves outside bundle ${root2.bundleId}.`);
95664
95864
  }
95665
- for (const entry of fs50.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95666
- const candidate = path62.join(directory, entry.name);
95865
+ for (const entry of fs51.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95866
+ const candidate = path63.join(directory, entry.name);
95667
95867
  if (entry.isSymbolicLink())
95668
95868
  throw migrationError2(`task migration does not follow symbolic link ${candidate}.`);
95669
95869
  if (entry.isDirectory()) {
@@ -95673,7 +95873,7 @@ function walkTasks2(root2, tasksDir, out) {
95673
95873
  if (!entry.isFile() || !entry.name.endsWith(".yml"))
95674
95874
  continue;
95675
95875
  const current = snapshot2(candidate);
95676
- const parent = path62.dirname(candidate);
95876
+ const parent = path63.dirname(candidate);
95677
95877
  out.push({
95678
95878
  filePath: candidate,
95679
95879
  bytes: current.bytes,
@@ -95689,9 +95889,9 @@ function walkTasks2(root2, tasksDir, out) {
95689
95889
  function inspectTaskToV4Files(roots) {
95690
95890
  const files = [];
95691
95891
  for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
95692
- const tasksDir = root2.layout === "akm-task" ? root2.root : path62.join(root2.root, "tasks");
95892
+ const tasksDir = root2.layout === "akm-task" ? root2.root : path63.join(root2.root, "tasks");
95693
95893
  try {
95694
- const stat = fs50.lstatSync(tasksDir);
95894
+ const stat = fs51.lstatSync(tasksDir);
95695
95895
  if (stat.isSymbolicLink())
95696
95896
  throw migrationError2(`task migration does not follow symbolic link ${tasksDir}.`);
95697
95897
  if (!stat.isDirectory())
@@ -95706,33 +95906,33 @@ function inspectTaskToV4Files(roots) {
95706
95906
  return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
95707
95907
  }
95708
95908
  function hashPath2(filePath) {
95709
- return crypto7.createHash("sha256").update(path62.resolve(filePath)).digest("hex").slice(0, 16);
95909
+ return crypto7.createHash("sha256").update(path63.resolve(filePath)).digest("hex").slice(0, 16);
95710
95910
  }
95711
95911
  function taskMigrationBackupPathV4(backupRoot, filePath) {
95712
- return path62.join(backupRoot, "files", `${hashPath2(filePath)}-${path62.basename(filePath)}`);
95912
+ return path63.join(backupRoot, "files", `${hashPath2(filePath)}-${path63.basename(filePath)}`);
95713
95913
  }
95714
95914
  function writeDurable2(filePath, bytes, mode, exclusive = false) {
95715
- fs50.mkdirSync(path62.dirname(filePath), { recursive: true });
95915
+ fs51.mkdirSync(path63.dirname(filePath), { recursive: true });
95716
95916
  const flags = exclusive ? "wx" : "w";
95717
- const fd = fs50.openSync(filePath, flags, mode);
95917
+ const fd = fs51.openSync(filePath, flags, mode);
95718
95918
  try {
95719
- fs50.writeFileSync(fd, bytes);
95720
- fs50.fsyncSync(fd);
95919
+ fs51.writeFileSync(fd, bytes);
95920
+ fs51.fsyncSync(fd);
95721
95921
  } finally {
95722
- fs50.closeSync(fd);
95922
+ fs51.closeSync(fd);
95723
95923
  }
95724
- fs50.chmodSync(filePath, mode);
95725
- fsyncDirectoryPortable(path62.dirname(filePath));
95924
+ fs51.chmodSync(filePath, mode);
95925
+ fsyncDirectoryPortable(path63.dirname(filePath));
95726
95926
  }
95727
95927
  function replaceAtomically2(filePath, bytes, mode) {
95728
- const temporary = path62.join(path62.dirname(filePath), `.${path62.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
95928
+ const temporary = path63.join(path63.dirname(filePath), `.${path63.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
95729
95929
  try {
95730
95930
  writeDurable2(temporary, bytes, mode, true);
95731
- fs50.renameSync(temporary, filePath);
95732
- fsyncDirectoryPortable(path62.dirname(filePath));
95931
+ fs51.renameSync(temporary, filePath);
95932
+ fsyncDirectoryPortable(path63.dirname(filePath));
95733
95933
  } finally {
95734
95934
  try {
95735
- fs50.unlinkSync(temporary);
95935
+ fs51.unlinkSync(temporary);
95736
95936
  } catch (cause) {
95737
95937
  if (cause.code !== "ENOENT")
95738
95938
  throw cause;
@@ -95771,7 +95971,7 @@ function applyTaskToV4MigrationPlan(plan, options) {
95771
95971
  const current = snapshot2(change.filePath);
95772
95972
  if (!current.bytes.equals(change.after))
95773
95973
  continue;
95774
- replaceAtomically2(change.filePath, fs50.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
95974
+ replaceAtomically2(change.filePath, fs51.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
95775
95975
  }
95776
95976
  throw cause;
95777
95977
  }
@@ -95783,12 +95983,12 @@ function expandTilde(value) {
95783
95983
  if (value === "~")
95784
95984
  return os5.homedir();
95785
95985
  if (value.startsWith("~/") || value.startsWith("~\\"))
95786
- return path63.join(os5.homedir(), value.slice(2));
95986
+ return path64.join(os5.homedir(), value.slice(2));
95787
95987
  return value;
95788
95988
  }
95789
95989
  function existingDirectory(target) {
95790
95990
  try {
95791
- return fs51.statSync(target).isDirectory();
95991
+ return fs53.statSync(target).isDirectory();
95792
95992
  } catch (cause) {
95793
95993
  if (cause.code === "ENOENT")
95794
95994
  return false;
@@ -95809,21 +96009,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
95809
96009
  const source = sources.get(bundleId);
95810
96010
  if (!source)
95811
96011
  continue;
95812
- const configuredRoot = source.type === "filesystem" && source.path ? path63.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
96012
+ const configuredRoot = source.type === "filesystem" && source.path ? path64.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
95813
96013
  if (!configuredRoot || !existingDirectory(configuredRoot))
95814
96014
  continue;
95815
- const bundleRoot = path63.resolve(configuredRoot);
96015
+ const bundleRoot = path64.resolve(configuredRoot);
95816
96016
  const component = bundleComponentConfig(bundle);
95817
- const componentRoot = path63.resolve(bundleRoot, component?.root ?? ".");
95818
- const relative = path63.relative(bundleRoot, componentRoot);
95819
- if (relative === ".." || relative.startsWith(`..${path63.sep}`) || path63.isAbsolute(relative)) {
96017
+ const componentRoot = path64.resolve(bundleRoot, component?.root ?? ".");
96018
+ const relative = path64.relative(bundleRoot, componentRoot);
96019
+ if (relative === ".." || relative.startsWith(`..${path64.sep}`) || path64.isAbsolute(relative)) {
95820
96020
  throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
95821
96021
  }
95822
96022
  if (!existingDirectory(componentRoot))
95823
96023
  continue;
95824
96024
  const adapter = component?.adapter ?? detectAdapterId(componentRoot, "");
95825
96025
  if (!component?.adapter && adapter === "") {
95826
- const flatTasks = fs51.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
96026
+ const flatTasks = fs53.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
95827
96027
  if (flatTasks.length > 0) {
95828
96028
  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");
95829
96029
  }
@@ -95895,8 +96095,8 @@ function applyTaskV3Migration() {
95895
96095
  const before = inspectCurrentTaskPlan();
95896
96096
  if (before.result.taskV3Migration.changed === 0)
95897
96097
  return before.result;
95898
- const backupRoot = path63.join(getDataDir(), "backups", "task-v3");
95899
- const backupPath = path63.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96098
+ const backupRoot = path64.join(getDataDir(), "backups", "task-v3");
96099
+ const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
95900
96100
  const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
95901
96101
  const after = inspectCurrentTaskPlan().result;
95902
96102
  if (after.taskV3Migration.changed > 0) {
@@ -95952,8 +96152,8 @@ function applyTaskV4Migration() {
95952
96152
  const before = inspectCurrentTaskV4Plan();
95953
96153
  if (before.result.taskV4Migration.changed === 0)
95954
96154
  return before.result;
95955
- const backupRoot = path63.join(getDataDir(), "backups", "task-v4");
95956
- const backupPath = path63.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96155
+ const backupRoot = path64.join(getDataDir(), "backups", "task-v4");
96156
+ const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
95957
96157
  const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
95958
96158
  const after = inspectCurrentTaskV4Plan().result;
95959
96159
  if (after.taskV4Migration.changed > 0) {
@@ -95981,6 +96181,22 @@ function stashDirIfConfigured() {
95981
96181
  throw error2;
95982
96182
  }
95983
96183
  }
96184
+ function writerRelocationTargets(defaultStashDir) {
96185
+ const config = loadConfig();
96186
+ const seen = new Set;
96187
+ const targets = [];
96188
+ if (defaultStashDir !== undefined) {
96189
+ targets.push({ id: bundleKeyForContentRoot(config, defaultStashDir) ?? "default", dir: defaultStashDir });
96190
+ seen.add(defaultStashDir);
96191
+ }
96192
+ for (const { id, contentRoot } of bundleContentRoots(config)) {
96193
+ if (seen.has(contentRoot))
96194
+ continue;
96195
+ seen.add(contentRoot);
96196
+ targets.push({ id, dir: contentRoot });
96197
+ }
96198
+ return targets;
96199
+ }
95984
96200
  async function runMigration(options) {
95985
96201
  const { apply } = options;
95986
96202
  const configPath = getConfigPath();
@@ -96001,10 +96217,15 @@ async function runMigration(options) {
96001
96217
  const stashDir = stashDirIfConfigured();
96002
96218
  const taskV3 = apply ? applyTaskV3Migration() : inspectMigrationPlan();
96003
96219
  const taskV4 = apply ? applyTaskV4Migration() : inspectTaskV4MigrationStatus();
96004
- const stashSections = stashDir === undefined ? {} : {
96005
- deadResidue: apply ? { removed: removeDeadResidue(stashDir) } : { pending: findDeadResidueEntries(stashDir) },
96006
- staleTxns: apply ? { recovered: await recoverStaleTxns(stashDir) } : { pending: findStaleTxnEntries(stashDir) }
96007
- };
96220
+ const stashSections = {};
96221
+ if (stashDir !== undefined) {
96222
+ stashSections.deadResidue = apply ? { removed: removeDeadResidue(stashDir) } : { pending: findDeadResidueEntries(stashDir) };
96223
+ stashSections.staleTxns = apply ? { recovered: await recoverStaleTxns(stashDir) } : { pending: findStaleTxnEntries(stashDir) };
96224
+ }
96225
+ const relocationTargets = writerRelocationTargets(stashDir);
96226
+ if (relocationTargets.length > 0) {
96227
+ stashSections.writerRelocation = apply ? { relocated: Object.fromEntries(relocationTargets.map(({ id, dir }) => [id, applyWriterRelocation(dir)])) } : { pending: Object.fromEntries(relocationTargets.map(({ id, dir }) => [id, findWriterRelocationEntries(dir)])) };
96228
+ }
96008
96229
  const stateStatus = "pending" in stateMigrations && stateMigrations.pending.length > 0 ? "ready" : "current";
96009
96230
  return {
96010
96231
  schemaVersion: 1,