akm-cli 0.9.7 → 0.9.8-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +310 -0
  2. package/dist/commands/env/env.js +2 -21
  3. package/dist/commands/health/checks.js +0 -25
  4. package/dist/commands/health/data-dir-usage.js +165 -0
  5. package/dist/commands/health/improve-metrics.js +8 -34
  6. package/dist/commands/health/windows.js +0 -4
  7. package/dist/commands/health.js +18 -37
  8. package/dist/commands/improve/consolidate/eligibility.js +11 -5
  9. package/dist/commands/improve/extract.js +36 -32
  10. package/dist/commands/improve/memory/memory-belief.js +15 -5
  11. package/dist/commands/improve/memory/memory-contradiction-detect.js +16 -25
  12. package/dist/commands/improve/memory/memory-improve.js +7 -19
  13. package/dist/commands/improve/preparation.js +52 -36
  14. package/dist/commands/improve/reflect.js +13 -17
  15. package/dist/commands/lint/base-linter.js +42 -2
  16. package/dist/commands/lint/index.js +4 -5
  17. package/dist/commands/migrate/config-extra-params.js +61 -0
  18. package/dist/commands/migrate/dead-residue.js +113 -0
  19. package/dist/commands/migrate/stale-txn.js +49 -0
  20. package/dist/commands/migrate-cli.js +42 -1
  21. package/dist/commands/proposal/proposal.js +1 -21
  22. package/dist/commands/proposal/repository.js +0 -4
  23. package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -6
  24. package/dist/commands/read/curate.js +4 -18
  25. package/dist/commands/read/show.js +2 -1
  26. package/dist/commands/sources/installed-stashes.js +5 -1
  27. package/dist/commands/sources/self-update.js +38 -1
  28. package/dist/commands/sources/sources-cli.js +17 -1
  29. package/dist/commands/tasks/tasks.js +0 -8
  30. package/dist/commands/url-checker.js +20 -28
  31. package/dist/commands/workflow-cli.js +11 -61
  32. package/dist/core/adapter/adapters/agent-skills-adapter.js +2 -6
  33. package/dist/core/adapter/adapters/akm-adapter.js +2 -3
  34. package/dist/core/adapter/adapters/akm-lint.js +2 -20
  35. package/dist/core/adapter/adapters/akm-task-adapter.js +2 -6
  36. package/dist/core/adapter/adapters/akm-workflow-adapter.js +2 -6
  37. package/dist/core/adapter/adapters/dotenv-adapter.js +2 -22
  38. package/dist/core/adapter/adapters/generic-files-adapter.js +3 -9
  39. package/dist/core/adapter/adapters/llm-wiki-adapter.js +2 -6
  40. package/dist/core/adapter/adapters/okf-adapter.js +7 -18
  41. package/dist/core/adapter/adapters/shared.js +2 -0
  42. package/dist/core/adapter/adapters/tool-dir-shared.js +3 -9
  43. package/dist/core/adapter/adapters/website-snapshot-adapter.js +2 -6
  44. package/dist/core/adapter/validate-context.js +1 -3
  45. package/dist/core/asset/asset-placement.js +1 -3
  46. package/dist/core/asset/frontmatter.js +96 -0
  47. package/dist/core/common.js +66 -2
  48. package/dist/core/config/config-io.js +21 -8
  49. package/dist/core/config/config-walker.js +6 -10
  50. package/dist/core/config/config.js +11 -8
  51. package/dist/core/extra-params.js +17 -13
  52. package/dist/core/improve-result.js +1 -3
  53. package/dist/core/json-schema.js +9 -11
  54. package/dist/core/state/migrations.js +74 -2
  55. package/dist/core/state-db.js +2 -1
  56. package/dist/core/warn.js +15 -0
  57. package/dist/execution/executable-identity.js +1 -3
  58. package/dist/execution/guarded-source.js +1 -6
  59. package/dist/indexer/bundle-identity-guard.js +6 -1
  60. package/dist/indexer/db/graph-db.js +139 -154
  61. package/dist/indexer/ensure-index.js +11 -19
  62. package/dist/indexer/graph/graph-boost.js +23 -34
  63. package/dist/indexer/graph/graph-extraction.js +12 -2
  64. package/dist/indexer/indexer.js +43 -22
  65. package/dist/indexer/lookup/adapter-concept-owner.js +12 -9
  66. package/dist/indexer/passes/dir-staleness.js +30 -9
  67. package/dist/indexer/passes/memory-inference.js +7 -2
  68. package/dist/indexer/scan/drain-dir.js +2 -4
  69. package/dist/indexer/search/db-search.js +3 -3
  70. package/dist/indexer/search/fts-query.js +10 -15
  71. package/dist/indexer/search/search-source.js +0 -13
  72. package/dist/indexer/usage/usage-events.js +9 -1
  73. package/dist/indexer/walk/walker.js +11 -6
  74. package/dist/integrations/harnesses/claude/result-extractor.js +30 -15
  75. package/dist/integrations/harnesses/codex/result-extractor.js +43 -6
  76. package/dist/integrations/harnesses/copilot/result-extractor.js +39 -12
  77. package/dist/integrations/harnesses/gemini/result-extractor.js +40 -12
  78. package/dist/integrations/harnesses/index.js +0 -4
  79. package/dist/integrations/harnesses/openhands/result-extractor.js +51 -19
  80. package/dist/integrations/harnesses/pi/result-extractor.js +45 -12
  81. package/dist/integrations/lockfile.js +0 -14
  82. package/dist/integrations/session-logs/index.js +0 -81
  83. package/dist/llm/client.js +0 -12
  84. package/dist/llm/memory-infer.js +1 -3
  85. package/dist/llm/usage-telemetry.js +1 -3
  86. package/dist/registry/create-provider-registry.js +4 -0
  87. package/dist/registry/factory.js +4 -0
  88. package/dist/registry/resolve.js +23 -8
  89. package/dist/runtime.js +0 -12
  90. package/dist/scripts/akm-migrate-node.js +179 -248
  91. package/dist/scripts/akm-migrate.js +179 -248
  92. package/dist/setup/setup.js +6 -12
  93. package/dist/sources/providers/git-install.js +7 -2
  94. package/dist/sources/providers/tar-utils.js +1 -7
  95. package/dist/sources/snapshot-fetchers/content-extract.js +0 -17
  96. package/dist/storage/managed-db.js +20 -7
  97. package/dist/storage/repositories/events-repository.js +0 -81
  98. package/dist/storage/repositories/index-entries-repository.js +24 -28
  99. package/dist/storage/repositories/index-fts-repository.js +24 -30
  100. package/dist/storage/repositories/index-meta-repository.js +6 -4
  101. package/dist/storage/repositories/index-schema.js +16 -1
  102. package/dist/storage/repositories/index-utility-repository.js +0 -57
  103. package/dist/storage/repositories/index-vec-repository.js +25 -27
  104. package/dist/storage/repositories/proposals-repository.js +4 -1
  105. package/dist/storage/repositories/task-history-repository.js +9 -3
  106. package/dist/tasks/backends/launchd.js +8 -18
  107. package/dist/tasks/resolve-akm-bin.js +15 -0
  108. package/dist/tasks/run/task-history.js +21 -31
  109. package/dist/tasks/scheduler-sync.js +1 -6
  110. package/dist/tasks/source/bounded-document.js +1 -14
  111. package/dist/tasks/source/task-to-v3.js +10 -2
  112. package/dist/workflows/exec/child-workflow.js +1 -1
  113. package/dist/workflows/exec/native-executor.js +2 -2
  114. package/dist/workflows/exec/step-work.js +5 -17
  115. package/dist/workflows/exec/worktree.js +40 -6
  116. package/dist/workflows/freeze/task-bindings.js +2 -4
  117. package/dist/workflows/ir/compile.js +3 -14
  118. package/dist/workflows/ir/schema-v4.js +4 -6
  119. package/dist/workflows/ir/schema.js +2 -5
  120. package/dist/workflows/parser.js +23 -26
  121. package/dist/workflows/source-files.js +8 -13
  122. package/dist/workflows/source-ir/schema.js +1 -19
  123. package/docs/migration/v0.9.0-troubleshooting.md +12 -2
  124. package/docs/migration/v0.9.1-to-v0.9.2.md +18 -4
  125. package/docs/reference/cli.md +3 -1
  126. package/docs/reference/data-and-telemetry.md +1 -0
  127. package/docs/reference/tasks.md +11 -0
  128. package/docs/reference/workflow-schema.md +24 -0
  129. package/package.json +2 -9
  130. package/dist/workflows/source-ir/compare.js +0 -17
@@ -9453,6 +9453,12 @@ function stripJsonComments(text) {
9453
9453
  }
9454
9454
  return result;
9455
9455
  }
9456
+ function toPosix(input) {
9457
+ return input.replace(/\\/g, "/");
9458
+ }
9459
+ function compareCodePoints(left, right) {
9460
+ return left < right ? -1 : left > right ? 1 : 0;
9461
+ }
9456
9462
  function isContainedRelativePath(value) {
9457
9463
  if (value === "" || value.startsWith("/") || value.startsWith("\\") || value.startsWith("~"))
9458
9464
  return false;
@@ -9505,6 +9511,40 @@ function asNonEmptyString(value) {
9505
9511
  const trimmed = value.trim();
9506
9512
  return trimmed.length > 0 ? trimmed : undefined;
9507
9513
  }
9514
+ var ENV_ASSIGN_LINE_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
9515
+ function scanEnvKeyNames(text) {
9516
+ const keys = [];
9517
+ const seen = new Set;
9518
+ for (const line of text.split(/\r?\n/)) {
9519
+ const m = line.match(ENV_ASSIGN_LINE_RE);
9520
+ if (!m)
9521
+ continue;
9522
+ const key = m[1];
9523
+ if (!key)
9524
+ continue;
9525
+ if (seen.has(key))
9526
+ continue;
9527
+ seen.add(key);
9528
+ keys.push(key);
9529
+ }
9530
+ return keys;
9531
+ }
9532
+ function wellFormedUnicode(value) {
9533
+ for (let index = 0;index < value.length; index += 1) {
9534
+ const code = value.charCodeAt(index);
9535
+ if (code >= 55296 && code <= 56319) {
9536
+ const next = value.charCodeAt(index + 1);
9537
+ if (!(next >= 56320 && next <= 57343))
9538
+ return false;
9539
+ index += 1;
9540
+ } else if (code >= 56320 && code <= 57343)
9541
+ return false;
9542
+ }
9543
+ return true;
9544
+ }
9545
+ function isRecord(value) {
9546
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9547
+ }
9508
9548
  function isProcessAlive(pid) {
9509
9549
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
9510
9550
  return false;
@@ -11547,9 +11587,6 @@ function isKnownType(type) {
11547
11587
  var DEPRECATED_REJECTED_TYPES = new Set(["tool", "vault"]);
11548
11588
 
11549
11589
  // src/core/asset/asset-placement.ts
11550
- function toPosix(input) {
11551
- return input.replace(/\\/g, "/");
11552
- }
11553
11590
  var workflowSpec = {
11554
11591
  isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path5.extname(fileName).toLowerCase()),
11555
11592
  toCanonicalName: (typeRoot, filePath) => {
@@ -12650,6 +12687,7 @@ function readTags(value) {
12650
12687
  const tags = value.filter((tag) => typeof tag === "string" && tag.trim().length > 0);
12651
12688
  return tags.length > 0 ? tags : undefined;
12652
12689
  }
12690
+ var RESERVED_FILES = new Set(["index.md", "log.md"]);
12653
12691
  function checkMissingUpdated(data, frontmatterText) {
12654
12692
  return frontmatterText !== null && !("updated" in data);
12655
12693
  }
@@ -12787,12 +12825,8 @@ var NAME_MAX = 64;
12787
12825
  var DESCRIPTION_MAX = 1024;
12788
12826
  var RESERVED_NAME_WORDS = ["anthropic", "claude"];
12789
12827
  var NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
12790
- var MAX_CONTENT_CHARS = 1e5;
12791
- function toPosix2(p) {
12792
- return p.replace(/\\/g, "/");
12793
- }
12794
12828
  function skillPackage(relPath) {
12795
- const posix = toPosix2(relPath);
12829
+ const posix = toPosix(relPath);
12796
12830
  const segs = posix.split("/").filter((s) => s.length > 0);
12797
12831
  if (segs.length < 2 || segs[segs.length - 1] !== SKILL_MANIFEST)
12798
12832
  return null;
@@ -12821,7 +12855,7 @@ function recognize(c, file) {
12821
12855
  adapterId: "agent-skills",
12822
12856
  type: "skill",
12823
12857
  name,
12824
- content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body
12858
+ content: body
12825
12859
  };
12826
12860
  if (description !== undefined)
12827
12861
  doc.description = description;
@@ -12909,7 +12943,7 @@ async function validate(_c, changes, ctx) {
12909
12943
  if (seenDirs.has(pkg.conceptId))
12910
12944
  continue;
12911
12945
  seenDirs.add(pkg.conceptId);
12912
- diagnostics.push(...skillFieldDiagnostics(toPosix2(change.path), pkg.dirName, parseFrontmatter(raw).data));
12946
+ diagnostics.push(...skillFieldDiagnostics(toPosix(change.path), pkg.dirName, parseFrontmatter(raw).data));
12913
12947
  }
12914
12948
  diagnostics.push(...await missingManifestDiagnostics(ctx));
12915
12949
  return diagnostics;
@@ -12992,6 +13026,7 @@ function warn(...args) {
12992
13026
  console.warn(...args);
12993
13027
  }
12994
13028
  }
13029
+ var warnedOnceKeys = new Set;
12995
13030
  function warnVerbose(...args) {
12996
13031
  if (sinkOverride) {
12997
13032
  sinkOverride("warnVerbose", args);
@@ -14768,24 +14803,6 @@ import path14 from "path";
14768
14803
 
14769
14804
  // src/commands/env/env.ts
14770
14805
  var import_dotenv = __toESM(require_main(), 1);
14771
- var ASSIGN_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
14772
- function scanEnvKeyNames(text) {
14773
- const keys = [];
14774
- const seen = new Set;
14775
- for (const line of text.split(/\r?\n/)) {
14776
- const m = line.match(ASSIGN_RE);
14777
- if (!m)
14778
- continue;
14779
- const key = m[1];
14780
- if (!key)
14781
- continue;
14782
- if (seen.has(key))
14783
- continue;
14784
- seen.add(key);
14785
- keys.push(key);
14786
- }
14787
- return keys;
14788
- }
14789
14806
 
14790
14807
  // src/commands/lint/env-key-rules.ts
14791
14808
  var DANGEROUS_ENV_KEYS = new Set([
@@ -14923,19 +14940,6 @@ function own2(value, key) {
14923
14940
  function utf8Bytes2(value) {
14924
14941
  return new TextEncoder().encode(value).byteLength;
14925
14942
  }
14926
- function wellFormedUnicode(value) {
14927
- for (let index = 0;index < value.length; index += 1) {
14928
- const code = value.charCodeAt(index);
14929
- if (code >= 55296 && code <= 56319) {
14930
- const next = value.charCodeAt(index + 1);
14931
- if (!(next >= 56320 && next <= 57343))
14932
- return false;
14933
- index += 1;
14934
- } else if (code >= 56320 && code <= 57343)
14935
- return false;
14936
- }
14937
- return true;
14938
- }
14939
14943
  function sourceError(ctx, fieldPath, detail) {
14940
14944
  const dotted = fieldPath.length === 0 ? "$" : fieldPath.reduce((display, segment) => typeof segment === "number" ? `${display}[${segment}]` : display.length > 0 ? `${display}.${segment}` : segment, "");
14941
14945
  const line = ctx.lineAt?.(fieldPath);
@@ -15347,9 +15351,6 @@ function pointerFor(path10) {
15347
15351
  function pushIssue(issues, path10, keyword, kind, message) {
15348
15352
  issues.push({ path: [...path10], pointer: pointerFor(path10), keyword, kind, message });
15349
15353
  }
15350
- function isPlainObject(value) {
15351
- return typeof value === "object" && value !== null && !Array.isArray(value);
15352
- }
15353
15354
  function isSupportedEnumValue(value) {
15354
15355
  return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
15355
15356
  }
@@ -15399,7 +15400,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15399
15400
  continue;
15400
15401
  }
15401
15402
  branches.forEach((branch, index) => {
15402
- if (isPlainObject(branch)) {
15403
+ if (isRecord(branch)) {
15403
15404
  checkDefinitionNode(branch, [...path10, keyword, index], issues, depth + 1);
15404
15405
  } else {
15405
15406
  pushIssue(issues, [...path10, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
@@ -15407,7 +15408,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15407
15408
  });
15408
15409
  }
15409
15410
  if (schema.not !== undefined) {
15410
- if (isPlainObject(schema.not)) {
15411
+ if (isRecord(schema.not)) {
15411
15412
  checkDefinitionNode(schema.not, [...path10, "not"], issues, depth + 1);
15412
15413
  } else {
15413
15414
  pushIssue(issues, [...path10, "not"], "not", "malformed", `"not" must be a schema object`);
@@ -15419,11 +15420,11 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15419
15420
  }
15420
15421
  }
15421
15422
  if (schema.properties !== undefined) {
15422
- if (!isPlainObject(schema.properties)) {
15423
+ if (!isRecord(schema.properties)) {
15423
15424
  pushIssue(issues, [...path10, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
15424
15425
  } else {
15425
15426
  for (const [key, propSchema] of Object.entries(schema.properties)) {
15426
- if (isPlainObject(propSchema)) {
15427
+ if (isRecord(propSchema)) {
15427
15428
  checkDefinitionNode(propSchema, [...path10, "properties", key], issues, depth + 1);
15428
15429
  } else {
15429
15430
  pushIssue(issues, [...path10, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
@@ -15432,7 +15433,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15432
15433
  }
15433
15434
  }
15434
15435
  if (schema.items !== undefined) {
15435
- if (isPlainObject(schema.items)) {
15436
+ if (isRecord(schema.items)) {
15436
15437
  checkDefinitionNode(schema.items, [...path10, "items"], issues, depth + 1);
15437
15438
  } else if (Array.isArray(schema.items)) {
15438
15439
  pushIssue(issues, [...path10, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset \u2014 use a single schema object`);
@@ -15441,7 +15442,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15441
15442
  }
15442
15443
  }
15443
15444
  if (schema.additionalProperties !== undefined && typeof schema.additionalProperties !== "boolean") {
15444
- if (isPlainObject(schema.additionalProperties)) {
15445
+ if (isRecord(schema.additionalProperties)) {
15445
15446
  pushIssue(issues, [...path10, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset \u2014 only "additionalProperties: false" is`);
15446
15447
  } else {
15447
15448
  pushIssue(issues, [...path10, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
@@ -15490,7 +15491,7 @@ function combinatorBranches(schema, keyword) {
15490
15491
  const raw = schema[keyword];
15491
15492
  if (!Array.isArray(raw))
15492
15493
  return [];
15493
- return raw.filter(isPlainObject);
15494
+ return raw.filter(isRecord);
15494
15495
  }
15495
15496
  function summarizeBranchFailures(failures) {
15496
15497
  const shown = failures.slice(0, 3).map((f) => `${f.index + 1}: ${f.errors[0] ?? "no match"}`);
@@ -15522,7 +15523,7 @@ function validateCombinators(value, schema, path10, ctx) {
15522
15523
  }
15523
15524
  }
15524
15525
  const not = schema.not;
15525
- if (isPlainObject(not) && branchErrors(value, not, path10, ctx).length === 0) {
15526
+ if (isRecord(not) && branchErrors(value, not, path10, ctx).length === 0) {
15526
15527
  ctx.errors.push(`${path10}: value must not match the "not" schema`);
15527
15528
  }
15528
15529
  }
@@ -16278,20 +16279,17 @@ function formatExtraParamsIssue(label, issue) {
16278
16279
  const suffix = issue.path.map((part) => typeof part === "number" ? `[${part}]` : `.${part}`).join("");
16279
16280
  return `${label}${suffix} ${issue.message}`;
16280
16281
  }
16281
- function isPlainObject2(value) {
16282
- return typeof value === "object" && value !== null && !Array.isArray(value);
16283
- }
16284
16282
  function liftLegacyEngineExtraParams(raw) {
16285
16283
  const lifted = [];
16286
16284
  const conflicts = [];
16287
16285
  const rawEngines = raw.engines;
16288
- if (!isPlainObject2(rawEngines)) {
16286
+ if (!isRecord(rawEngines)) {
16289
16287
  return { config: raw, lifted, conflicts };
16290
16288
  }
16291
16289
  const engines = {};
16292
16290
  let anyEngineChanged = false;
16293
16291
  for (const [name, engineValue] of Object.entries(rawEngines)) {
16294
- if (!isPlainObject2(engineValue) || !isPlainObject2(engineValue.extraParams)) {
16292
+ if (!isRecord(engineValue) || !isRecord(engineValue.extraParams)) {
16295
16293
  engines[name] = engineValue;
16296
16294
  continue;
16297
16295
  }
@@ -16780,6 +16778,7 @@ function base(input) {
16780
16778
  ...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
16781
16779
  };
16782
16780
  }
16781
+ var ARGV_ARRAY_BLOCK_DETAIL = "Manual conversion required: an array `command:` has no safe v3 `run:` string. Rewrite it by hand as " + "`run:` (string) plus `shell:` \u2014 see docs/migration/v0.9.1-to-v0.9.2.md for the full v2 to v4 field mapping.";
16783
16782
  function blocked(input, reason, detail) {
16784
16783
  return Object.freeze({ status: "blocked", ...base(input), reason, ...detail ? { detail } : {} });
16785
16784
  }
@@ -17042,8 +17041,10 @@ function planLegacyTaskDataToV3(input, data) {
17042
17041
  } catch (cause) {
17043
17042
  return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
17044
17043
  }
17045
- if (isReason(migrated))
17046
- return blocked(input, migrated);
17044
+ if (isReason(migrated)) {
17045
+ const detail = migrated === "argv-array-has-no-portable-shell-string" ? ARGV_ARRAY_BLOCK_DETAIL : undefined;
17046
+ return blocked(input, migrated, detail);
17047
+ }
17047
17048
  const after = Buffer.from($stringify(migrated), "utf8");
17048
17049
  try {
17049
17050
  parseTaskV3Yaml({
@@ -17811,11 +17812,6 @@ function sourceStepRef(source) {
17811
17812
  // src/workflows/source-ir/schema.ts
17812
17813
  import { types as utilTypes2 } from "util";
17813
17814
 
17814
- // src/workflows/source-ir/compare.ts
17815
- function compareWorkflowSourceCodePoints(left, right) {
17816
- return left < right ? -1 : left > right ? 1 : 0;
17817
- }
17818
-
17819
17815
  // src/workflows/source-ir/semantics.ts
17820
17816
  import fs7 from "fs";
17821
17817
  import path12 from "path";
@@ -18454,9 +18450,6 @@ function validateStep(value, jobId, index, stepIds, options) {
18454
18450
  extensions(step.extensions, `step ${id} extensions`);
18455
18451
  span(step.source, `step ${id} source`);
18456
18452
  }
18457
- function compareCodePoints(left, right) {
18458
- return compareWorkflowSourceCodePoints(left, right);
18459
- }
18460
18453
  function validateExec(value, location, options) {
18461
18454
  if (value === undefined)
18462
18455
  return;
@@ -18762,7 +18755,7 @@ function snapshotValue(value, depth, location, state) {
18762
18755
  return value;
18763
18756
  }
18764
18757
  if (typeof value === "string") {
18765
- if (!wellFormedUnicode2(value))
18758
+ if (!wellFormedUnicode(value))
18766
18759
  fail2(`${location} must contain well-formed Unicode`);
18767
18760
  countJsonBytes(state, JSON.stringify(value));
18768
18761
  return value;
@@ -18826,7 +18819,7 @@ function snapshotObject(value, depth, location, state) {
18826
18819
  for (const [index, key] of ownKeys.entries()) {
18827
18820
  if (typeof key === "symbol")
18828
18821
  fail2(`${location} contains symbol keys`);
18829
- if (!wellFormedUnicode2(key))
18822
+ if (!wellFormedUnicode(key))
18830
18823
  fail2(`${location} contains an ill-formed key`);
18831
18824
  if (UNSAFE_KEYS.has(key))
18832
18825
  fail2(`${location} contains unsafe key ${key}`);
@@ -18855,20 +18848,6 @@ function countJsonBytes(state, token) {
18855
18848
  if (state.bytes > WORKFLOW_SOURCE_IR_MAX_BYTES)
18856
18849
  fail2("source IR exceeds the byte limit");
18857
18850
  }
18858
- function wellFormedUnicode2(value) {
18859
- for (let index = 0;index < value.length; index++) {
18860
- const code = value.charCodeAt(index);
18861
- if (code >= 55296 && code <= 56319) {
18862
- const next = value.charCodeAt(index + 1);
18863
- if (!(next >= 56320 && next <= 57343))
18864
- return false;
18865
- index++;
18866
- } else if (code >= 56320 && code <= 57343) {
18867
- return false;
18868
- }
18869
- }
18870
- return true;
18871
- }
18872
18851
  function record(value, location) {
18873
18852
  if (value === null || typeof value !== "object" || Array.isArray(value))
18874
18853
  fail2(`${location} must be an object`);
@@ -19013,14 +18992,11 @@ function compileWorkflowPlan(input, title, resolvedUnits = new Map) {
19013
18992
  }
19014
18993
  function sortedOutputs(outputs) {
19015
18994
  const sorted = {};
19016
- for (const name of Object.keys(outputs).sort(compareCodePoints2)) {
18995
+ for (const name of Object.keys(outputs).sort(compareCodePoints)) {
19017
18996
  sorted[name] = outputs[name];
19018
18997
  }
19019
18998
  return sorted;
19020
18999
  }
19021
- function compareCodePoints2(left, right) {
19022
- return left < right ? -1 : left > right ? 1 : 0;
19023
- }
19024
19000
  function compileStep(step, sequenceIndex, defaults, resolved) {
19025
19001
  const gate = {
19026
19002
  kind: "gate",
@@ -19147,12 +19123,6 @@ function collectWorkflowWarnings(input) {
19147
19123
  message: `Step "${step.id}" declares \`gate.max_loops: ${maxLoops}\` on an \`exec\` step \u2014 it runs its command ` + `ONCE. A gate loop re-executes the step so it can address the judge's feedback, and a frozen argv cannot ` + `read that feedback; looping would only repeat the command's side effects. The gate still evaluates and ` + `can still fail the step.`
19148
19124
  });
19149
19125
  }
19150
- if ((step.map || step.route === undefined) && step.output === undefined) {
19151
- warnings.push({
19152
- line: step.source.start,
19153
- message: `Step "${step.id}" declares no \`output:\` schema \u2014 its unit results are carried as an untyped ` + `artifact (permitted). Add an \`output:\` JSON Schema to type and validate the step artifact.`
19154
- });
19155
- }
19156
19126
  if (declaredParams) {
19157
19127
  const declaredList = [...declaredParams].join(", ");
19158
19128
  const scan = (text, label) => {
@@ -19366,7 +19336,7 @@ function parseWorkflow(markdown, source) {
19366
19336
  };
19367
19337
  if (root === null || root === undefined)
19368
19338
  root = {};
19369
- if (!isPlainRecord(root)) {
19339
+ if (!isRecord(root)) {
19370
19340
  return {
19371
19341
  ok: false,
19372
19342
  errors: [{ line: 2, message: `Workflow frontmatter must be a YAML mapping (key: value pairs).` }]
@@ -19547,7 +19517,7 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
19547
19517
  checkActorStamp(ctx, root.verified, ["verified"], `"verified"`);
19548
19518
  }
19549
19519
  }
19550
- if (root.provenance !== undefined && !isPlainRecord(root.provenance)) {
19520
+ if (root.provenance !== undefined && !isRecord(root.provenance)) {
19551
19521
  ctx.err(["provenance"], `Workflow frontmatter "provenance" must be a mapping.`);
19552
19522
  }
19553
19523
  if (root.status !== undefined && (typeof root.status !== "string" || !LIFECYCLE_STATUSES.has(root.status))) {
@@ -19560,7 +19530,7 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
19560
19530
  function checkActorStamp(ctx, value, path13, label) {
19561
19531
  if (value === undefined)
19562
19532
  return;
19563
- if (!isPlainRecord(value)) {
19533
+ if (!isRecord(value)) {
19564
19534
  ctx.err(path13, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
19565
19535
  return;
19566
19536
  }
@@ -19591,7 +19561,7 @@ function checkXrefs2(ctx, value, fmEndLine) {
19591
19561
  function parseParams(ctx, raw) {
19592
19562
  if (raw === undefined)
19593
19563
  return;
19594
- if (!isPlainRecord(raw)) {
19564
+ if (!isRecord(raw)) {
19595
19565
  ctx.err(["params"], `"params" must be a mapping of param name to a JSON Schema object (e.g. changed_files: { type: array }).`);
19596
19566
  return;
19597
19567
  }
@@ -19601,7 +19571,7 @@ function parseParams(ctx, raw) {
19601
19571
  ctx.err(["params", paramName], `Param name "${paramName}" is invalid. Use letters, digits, and underscores, starting with a letter or underscore, so "params.${paramName}" can address it.`);
19602
19572
  continue;
19603
19573
  }
19604
- if (!isPlainRecord(value)) {
19574
+ if (!isRecord(value)) {
19605
19575
  ctx.err(["params", paramName], `Param "${paramName}" must be a JSON Schema object (e.g. { type: string }).`);
19606
19576
  continue;
19607
19577
  }
@@ -19616,7 +19586,7 @@ function parseParams(ctx, raw) {
19616
19586
  function parseOutputs(ctx, raw) {
19617
19587
  if (raw === undefined)
19618
19588
  return;
19619
- if (!isPlainRecord(raw)) {
19589
+ if (!isRecord(raw)) {
19620
19590
  ctx.err(["outputs"], `"outputs" must be a mapping of output name to { from, schema? } (e.g. report: { from: steps.summarize.output }).`);
19621
19591
  return;
19622
19592
  }
@@ -19627,7 +19597,7 @@ function parseOutputs(ctx, raw) {
19627
19597
  ctx.err(path13, `Output name "${outputName}" is invalid. Use letters, digits, and underscores, starting with a letter or ` + `underscore, so "steps.<child>.output.${outputName}" can address it.`);
19628
19598
  continue;
19629
19599
  }
19630
- if (!isPlainRecord(value)) {
19600
+ if (!isRecord(value)) {
19631
19601
  ctx.err(path13, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
19632
19602
  continue;
19633
19603
  }
@@ -19647,7 +19617,7 @@ function parseOutputs(ctx, raw) {
19647
19617
  }
19648
19618
  const entry = { from: value.from };
19649
19619
  if (value.schema !== undefined) {
19650
- if (!isPlainRecord(value.schema)) {
19620
+ if (!isRecord(value.schema)) {
19651
19621
  ctx.err([...path13, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
19652
19622
  } else {
19653
19623
  if (jsonBytes(value.schema) > WORKFLOW_MAX_SCHEMA_BYTES) {
@@ -19665,7 +19635,7 @@ function parseDefaults(ctx, raw) {
19665
19635
  if (raw === undefined)
19666
19636
  return;
19667
19637
  const path13 = ["defaults"];
19668
- if (!isPlainRecord(raw)) {
19638
+ if (!isRecord(raw)) {
19669
19639
  ctx.err(path13, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
19670
19640
  return;
19671
19641
  }
@@ -19697,7 +19667,7 @@ function parseBudget(ctx, raw) {
19697
19667
  if (raw === undefined)
19698
19668
  return;
19699
19669
  const path13 = ["budget"];
19700
- if (!isPlainRecord(raw)) {
19670
+ if (!isRecord(raw)) {
19701
19671
  ctx.err(path13, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
19702
19672
  return;
19703
19673
  }
@@ -19726,7 +19696,7 @@ function parseSteps(ctx, raw) {
19726
19696
  }
19727
19697
  const idIndex = new Map;
19728
19698
  raw.forEach((rawStep, index) => {
19729
- if (isPlainRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
19699
+ if (isRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
19730
19700
  idIndex.set(rawStep.id, index);
19731
19701
  }
19732
19702
  });
@@ -19735,7 +19705,7 @@ function parseSteps(ctx, raw) {
19735
19705
  const routeChecks = [];
19736
19706
  raw.forEach((rawStep, index) => {
19737
19707
  const path13 = ["steps", index];
19738
- if (!isPlainRecord(rawStep)) {
19708
+ if (!isRecord(rawStep)) {
19739
19709
  ctx.err(path13, `Step ${index + 1} must be a mapping with an "id".`);
19740
19710
  return;
19741
19711
  }
@@ -19809,7 +19779,7 @@ function parseSteps(ctx, raw) {
19809
19779
  return steps;
19810
19780
  }
19811
19781
  function parseUnit(ctx, raw, path13, stepLabel) {
19812
- if (!isPlainRecord(raw)) {
19782
+ if (!isRecord(raw)) {
19813
19783
  ctx.err(path13, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
19814
19784
  return;
19815
19785
  }
@@ -19870,7 +19840,7 @@ function parseUnit(ctx, raw, path13, stepLabel) {
19870
19840
  return unit;
19871
19841
  }
19872
19842
  function parseExec(ctx, raw, path13, stepLabel) {
19873
- if (!isPlainRecord(raw)) {
19843
+ if (!isRecord(raw)) {
19874
19844
  ctx.err(path13, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
19875
19845
  return;
19876
19846
  }
@@ -19954,7 +19924,7 @@ function parseExecCwd(ctx, raw, path13, stepLabel) {
19954
19924
  return value;
19955
19925
  }
19956
19926
  function parseMap(ctx, raw, path13, stepLabel) {
19957
- if (!isPlainRecord(raw)) {
19927
+ if (!isRecord(raw)) {
19958
19928
  ctx.err(path13, `${stepLabel} "map" must be a mapping with an "over" key.`);
19959
19929
  return;
19960
19930
  }
@@ -19986,7 +19956,7 @@ function parseMap(ctx, raw, path13, stepLabel) {
19986
19956
  return map;
19987
19957
  }
19988
19958
  function parseRoute(ctx, raw, path13, stepLabel, stepIndex, routeChecks) {
19989
- if (!isPlainRecord(raw)) {
19959
+ if (!isRecord(raw)) {
19990
19960
  ctx.err(path13, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
19991
19961
  return;
19992
19962
  }
@@ -20006,7 +19976,7 @@ function parseRoute(ctx, raw, path13, stepLabel, stepIndex, routeChecks) {
20006
19976
  const seenMatches = new Map;
20007
19977
  raw.when.forEach((branch, i) => {
20008
19978
  const branchPath = [...whenPath, i];
20009
- if (!isPlainRecord(branch)) {
19979
+ if (!isRecord(branch)) {
20010
19980
  ctx.err(branchPath, `${stepLabel} "when[${i}]" must be a mapping: { match, step }.`);
20011
19981
  return;
20012
19982
  }
@@ -20077,7 +20047,7 @@ function parseInputs(ctx, raw, path13, stepLabel) {
20077
20047
  return out.length > 0 ? out : undefined;
20078
20048
  }
20079
20049
  function parseGate(ctx, raw, path13, stepLabel) {
20080
- if (!isPlainRecord(raw)) {
20050
+ if (!isRecord(raw)) {
20081
20051
  ctx.err(path13, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
20082
20052
  return;
20083
20053
  }
@@ -20107,7 +20077,7 @@ function parseEngineName(ctx, raw, path13, label) {
20107
20077
  function parseRetry(ctx, raw, path13, stepLabel) {
20108
20078
  if (raw === undefined)
20109
20079
  return;
20110
- if (!isPlainRecord(raw)) {
20080
+ if (!isRecord(raw)) {
20111
20081
  ctx.err(path13, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, \u2026] }.`);
20112
20082
  return;
20113
20083
  }
@@ -20180,7 +20150,7 @@ function parseEnumField(ctx, raw, path13, label, allowed) {
20180
20150
  function parseLlmOverrides(ctx, raw, path13, label) {
20181
20151
  if (raw === undefined)
20182
20152
  return;
20183
- if (!isPlainRecord(raw)) {
20153
+ if (!isRecord(raw)) {
20184
20154
  ctx.err(path13, `${label} must be a mapping of LLM invocation overrides.`);
20185
20155
  return;
20186
20156
  }
@@ -20214,7 +20184,7 @@ function parseLlmOverrides(ctx, raw, path13, label) {
20214
20184
  ctx.err([...path13, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
20215
20185
  }
20216
20186
  if (raw.extra_params !== undefined) {
20217
- if (!isPlainRecord(raw.extra_params)) {
20187
+ if (!isRecord(raw.extra_params)) {
20218
20188
  ctx.err([...path13, "extra_params"], `${label}.extra_params must be a JSON object.`);
20219
20189
  } else {
20220
20190
  const issues = validateExtraParams(raw.extra_params);
@@ -20252,7 +20222,7 @@ function parseLlmOverrides(ctx, raw, path13, label) {
20252
20222
  function parseSchemaObject(ctx, raw, path13, label) {
20253
20223
  if (raw === undefined)
20254
20224
  return;
20255
- if (!isPlainRecord(raw)) {
20225
+ if (!isRecord(raw)) {
20256
20226
  ctx.err(path13, `${label} must be a JSON Schema object (e.g. { type: object, properties: { \u2026 } }).`);
20257
20227
  return;
20258
20228
  }
@@ -20284,9 +20254,6 @@ function checkUnknownKeys(ctx, obj, path13, allowed, label) {
20284
20254
  }
20285
20255
  }
20286
20256
  }
20287
- function isPlainRecord(value) {
20288
- return typeof value === "object" && value !== null && !Array.isArray(value);
20289
- }
20290
20257
  function describeError(cause) {
20291
20258
  return cause instanceof Error ? cause.message : String(cause);
20292
20259
  }
@@ -21167,22 +21134,6 @@ function nameOrTypeDiagnostics(relPath, data, frontmatter, allowedTypes) {
21167
21134
  }
21168
21135
  return [];
21169
21136
  }
21170
- var ASSIGN_RE2 = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
21171
- function scanKeys(text) {
21172
- const keys2 = [];
21173
- const seen = new Set;
21174
- for (const line of text.split(/\r?\n/)) {
21175
- const m = line.match(ASSIGN_RE2);
21176
- if (!m)
21177
- continue;
21178
- const key = m[1];
21179
- if (seen.has(key))
21180
- continue;
21181
- seen.add(key);
21182
- keys2.push(key);
21183
- }
21184
- return keys2;
21185
- }
21186
21137
  function collectSuppressedKeys(raw) {
21187
21138
  const suppressed = new Set;
21188
21139
  const lines = raw.split(/\r?\n/);
@@ -21206,7 +21157,7 @@ function dangerousEnvKeyDiagnostics(type, relPath, raw) {
21206
21157
  if (!baseNameWithExt.endsWith(".env"))
21207
21158
  return [];
21208
21159
  const ref = conceptIdForStashFile(type, ".", relPath);
21209
- const keys2 = scanKeys(raw);
21160
+ const keys2 = scanEnvKeyNames(raw);
21210
21161
  const suppressed = collectSuppressedKeys(raw);
21211
21162
  const diagnostics = [];
21212
21163
  for (const key of keys2) {
@@ -21656,7 +21607,6 @@ function applyFoldedMetadata(entry, folded) {
21656
21607
  }
21657
21608
 
21658
21609
  // src/core/adapter/adapters/akm-adapter.ts
21659
- var RESERVED_FILES = new Set(["index.md", "log.md"]);
21660
21610
  function isReservedFileName(name) {
21661
21611
  return RESERVED_FILES.has(name.toLowerCase());
21662
21612
  }
@@ -21992,14 +21942,10 @@ import fs9 from "fs";
21992
21942
  import path16 from "path";
21993
21943
  var COMPONENT_ID2 = "main";
21994
21944
  var TASK_EXT = TASK_EXTENSION;
21995
- var MAX_CONTENT_CHARS2 = 1e5;
21996
- function toPosix3(p) {
21997
- return p.replace(/\\/g, "/");
21998
- }
21999
21945
  function recognize3(c, file) {
22000
21946
  if (file.ext !== TASK_EXT)
22001
21947
  return null;
22002
- const conceptId = toPosix3(file.relPath).replace(/\.yml$/i, "");
21948
+ const conceptId = toPosix(file.relPath).replace(/\.yml$/i, "");
22003
21949
  const name = conceptId.split("/").pop() ?? conceptId;
22004
21950
  const raw = file.content();
22005
21951
  return {
@@ -22012,7 +21958,7 @@ function recognize3(c, file) {
22012
21958
  adapterId: "akm-task",
22013
21959
  type: "task",
22014
21960
  name,
22015
- content: raw.length > MAX_CONTENT_CHARS2 ? raw.slice(0, MAX_CONTENT_CHARS2) : raw
21961
+ content: raw
22016
21962
  };
22017
21963
  }
22018
21964
  async function validate3(c, changes, ctx) {
@@ -22026,7 +21972,7 @@ async function validate3(c, changes, ctx) {
22026
21972
  const ext = path16.extname(change.path).toLowerCase();
22027
21973
  if (ext !== TASK_EXT && ext !== TASK_NEAR_MISS_EXTENSION)
22028
21974
  continue;
22029
- const relPath = toPosix3(change.path);
21975
+ const relPath = toPosix(change.path);
22030
21976
  if (ext === TASK_NEAR_MISS_EXTENSION) {
22031
21977
  diagnostics.push({
22032
21978
  file: relPath,
@@ -22056,14 +22002,14 @@ var akmTaskAdapter = {
22056
22002
  recognize: recognize3,
22057
22003
  validate: validate3,
22058
22004
  readCandidates(c, conceptId) {
22059
- const posix = toPosix3(conceptId).replace(/\.ya?ml$/i, "");
22005
+ const posix = toPosix(conceptId).replace(/\.ya?ml$/i, "");
22060
22006
  return [
22061
22007
  { path: path16.join(c.root, `${posix}.yml`), conceptId: posix },
22062
22008
  { path: path16.join(c.root, `${posix}.yaml`), conceptId: posix }
22063
22009
  ];
22064
22010
  },
22065
22011
  placeNew(c, conceptId) {
22066
- const posix = toPosix3(conceptId);
22012
+ const posix = toPosix(conceptId);
22067
22013
  return path16.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
22068
22014
  },
22069
22015
  directoryList() {
@@ -22099,12 +22045,8 @@ import fs10 from "fs";
22099
22045
  import path17 from "path";
22100
22046
  var COMPONENT_ID3 = "main";
22101
22047
  var WORKFLOW_EXTS = new Set([".md", ".yml"]);
22102
- var MAX_CONTENT_CHARS3 = 1e5;
22103
- function toPosix4(p) {
22104
- return p.replace(/\\/g, "/");
22105
- }
22106
22048
  function conceptIdOf(relPath) {
22107
- return toPosix4(relPath).replace(/\.(?:md|yml)$/i, "");
22049
+ return toPosix(relPath).replace(/\.(?:md|yml)$/i, "");
22108
22050
  }
22109
22051
  function isReservedDocFile(fileName) {
22110
22052
  return fileName.toLowerCase() === "readme.md";
@@ -22138,7 +22080,7 @@ function recognize4(c, file) {
22138
22080
  adapterId: "akm-workflow",
22139
22081
  type: "workflow",
22140
22082
  name,
22141
- content: body.length > MAX_CONTENT_CHARS3 ? body.slice(0, MAX_CONTENT_CHARS3) : body
22083
+ content: body
22142
22084
  };
22143
22085
  if (description !== undefined)
22144
22086
  doc.description = description;
@@ -22157,7 +22099,7 @@ async function validate4(c, changes, ctx) {
22157
22099
  const ext = path17.extname(change.path).toLowerCase();
22158
22100
  if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path17.basename(change.path)))
22159
22101
  continue;
22160
- const relPath = toPosix4(change.path);
22102
+ const relPath = toPosix(change.path);
22161
22103
  if (ext === ".yml") {
22162
22104
  diagnostics.push(...workflowYamlSourceDiagnostics(relPath, raw, relPath, c.root).errors);
22163
22105
  continue;
@@ -22207,7 +22149,7 @@ var akmWorkflowAdapter = {
22207
22149
  recognize: recognize4,
22208
22150
  validate: validate4,
22209
22151
  readCandidates(c, conceptId) {
22210
- const posix = toPosix4(conceptId);
22152
+ const posix = toPosix(conceptId);
22211
22153
  const canonical = posix.replace(/\.(?:md|yml)$/i, "");
22212
22154
  return /\.(?:md|yml)$/i.test(posix) ? [{ path: path17.join(c.root, posix), conceptId: canonical }] : [
22213
22155
  { path: path17.join(c.root, `${posix}.md`), conceptId: canonical },
@@ -22215,7 +22157,7 @@ var akmWorkflowAdapter = {
22215
22157
  ];
22216
22158
  },
22217
22159
  placeNew(c, conceptId) {
22218
- const posix = toPosix4(conceptId);
22160
+ const posix = toPosix(conceptId);
22219
22161
  if (/\.(?:md|yml)$/i.test(posix))
22220
22162
  return path17.join(c.root, posix);
22221
22163
  return path17.join(c.root, `${posix}.md`);
@@ -22240,20 +22182,15 @@ import path19 from "path";
22240
22182
 
22241
22183
  // src/core/adapter/adapters/tool-dir-shared.ts
22242
22184
  import path18 from "path";
22243
- var RESERVED_FILES2 = new Set(["index.md", "log.md"]);
22244
- var MAX_CONTENT_CHARS4 = 1e5;
22245
22185
  var CANONICAL_COMMAND_DIR = "commands";
22246
22186
  var CANONICAL_AGENT_DIR = "agents";
22247
22187
  var CANONICAL_SKILL_DIR = "skills";
22248
22188
  var SKILL_MANIFEST2 = "SKILL.md";
22249
- function toPosix5(p) {
22250
- return p.replace(/\\/g, "/");
22251
- }
22252
22189
  function isReserved(base3) {
22253
- return RESERVED_FILES2.has(base3.toLowerCase());
22190
+ return RESERVED_FILES.has(base3.toLowerCase());
22254
22191
  }
22255
22192
  function classify(relPath, layout) {
22256
- const posix = toPosix5(relPath);
22193
+ const posix = toPosix(relPath);
22257
22194
  const segs = posix.split("/").filter((s) => s.length > 0);
22258
22195
  if (segs.length === 0)
22259
22196
  return null;
@@ -22300,7 +22237,7 @@ function recognizeToolDir(layout, c, file) {
22300
22237
  adapterId: layout.adapterId,
22301
22238
  type: cls.type,
22302
22239
  name,
22303
- content: body.length > MAX_CONTENT_CHARS4 ? body.slice(0, MAX_CONTENT_CHARS4) : body
22240
+ content: body
22304
22241
  };
22305
22242
  if (cls.type === "instruction")
22306
22243
  doc.ownsPresentation = true;
@@ -22311,7 +22248,7 @@ function recognizeToolDir(layout, c, file) {
22311
22248
  return doc;
22312
22249
  }
22313
22250
  function placeNewToolDir(layout, c, conceptId) {
22314
- const posix = toPosix5(conceptId);
22251
+ const posix = toPosix(conceptId);
22315
22252
  if (posix === layout.instructionConceptId)
22316
22253
  return path18.join(c.root, layout.instructionFile);
22317
22254
  const segs = posix.split("/").filter((s) => s.length > 0);
@@ -22328,7 +22265,7 @@ function placeNewToolDir(layout, c, conceptId) {
22328
22265
  return path18.join(c.root, `${posix}.md`);
22329
22266
  }
22330
22267
  function readCandidatesToolDir(layout, c, conceptId) {
22331
- const posix = toPosix5(conceptId);
22268
+ const posix = toPosix(conceptId);
22332
22269
  if (posix === layout.instructionConceptId) {
22333
22270
  return [{ path: path18.join(c.root, layout.instructionFile), conceptId: posix }];
22334
22271
  }
@@ -22369,7 +22306,7 @@ async function validateToolDir(layout, c, changes, ctx) {
22369
22306
  const raw = change.after ?? await ctx.readFile(change.path);
22370
22307
  if (typeof raw !== "string")
22371
22308
  continue;
22372
- const relPath = toPosix5(change.path);
22309
+ const relPath = toPosix(change.path);
22373
22310
  diagnostics.push(...await skillDirectoryDiagnostics(relPath, seenSkillDirs, ctx, layout.skillDirs));
22374
22311
  const cls = classify(change.path, layout);
22375
22312
  if (cls === null)
@@ -22469,12 +22406,8 @@ var COMPONENT_ID4 = "main";
22469
22406
  var ENV_DIR = "env";
22470
22407
  var SECRETS_DIR = "secrets";
22471
22408
  var SECRET_SKIP_SUFFIXES = [".lock", ".sensitive"];
22472
- var ASSIGN_RE3 = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
22473
- function toPosix6(p) {
22474
- return p.replace(/\\/g, "/");
22475
- }
22476
22409
  function classify2(relPath) {
22477
- const posix = toPosix6(relPath);
22410
+ const posix = toPosix(relPath);
22478
22411
  const segs = posix.split("/").filter((s) => s.length > 0);
22479
22412
  if (segs.length < 2)
22480
22413
  return null;
@@ -22492,23 +22425,8 @@ function hasSensitiveMarker(absPath, type) {
22492
22425
  const marker = type === "env" ? absPath.replace(/\.env$/i, ".sensitive") : `${absPath}.sensitive`;
22493
22426
  return marker !== absPath && fs12.existsSync(marker);
22494
22427
  }
22495
- function scanKeyNames(raw) {
22496
- const keys2 = [];
22497
- const seen = new Set;
22498
- for (const line of raw.split(/\r?\n/)) {
22499
- const m = line.match(ASSIGN_RE3);
22500
- if (!m)
22501
- continue;
22502
- const key = m[1];
22503
- if (seen.has(key))
22504
- continue;
22505
- seen.add(key);
22506
- keys2.push(key);
22507
- }
22508
- return keys2;
22509
- }
22510
22428
  function conceptIdForPath(type, relativePath) {
22511
- const posix = toPosix6(relativePath);
22429
+ const posix = toPosix(relativePath);
22512
22430
  if (type === "secret")
22513
22431
  return posix;
22514
22432
  const stripped = posix.replace(/\.env$/i, "");
@@ -22520,12 +22438,12 @@ function recognize5(c, file) {
22520
22438
  return null;
22521
22439
  if (hasSensitiveMarker(file.absPath, type))
22522
22440
  return null;
22523
- const posix = toPosix6(file.relPath);
22441
+ const posix = toPosix(file.relPath);
22524
22442
  const raw = file.content();
22525
22443
  if (type === "env") {
22526
22444
  const conceptId = conceptIdForPath(type, posix);
22527
22445
  const name2 = (conceptId.split("/").pop() ?? conceptId) || "default";
22528
- const keys2 = scanKeyNames(raw);
22446
+ const keys2 = scanEnvKeyNames(raw);
22529
22447
  const doc = {
22530
22448
  ref: `${c.id}//${conceptId}`,
22531
22449
  bundle: c.id,
@@ -22565,7 +22483,7 @@ async function validate5(_c, changes, ctx) {
22565
22483
  const type = classify2(change.path);
22566
22484
  if (type === null)
22567
22485
  continue;
22568
- diagnostics.push(...dangerousEnvKeyDiagnostics(type, toPosix6(change.path), raw));
22486
+ diagnostics.push(...dangerousEnvKeyDiagnostics(type, toPosix(change.path), raw));
22569
22487
  }
22570
22488
  return diagnostics;
22571
22489
  }
@@ -22576,7 +22494,7 @@ var dotenvAdapter = {
22576
22494
  recognize: recognize5,
22577
22495
  validate: validate5,
22578
22496
  readCandidates(c, conceptId) {
22579
- const posix = toPosix6(conceptId);
22497
+ const posix = toPosix(conceptId);
22580
22498
  const slash = posix.indexOf("/");
22581
22499
  if (slash <= 0)
22582
22500
  return [];
@@ -22590,7 +22508,7 @@ var dotenvAdapter = {
22590
22508
  return expanded.map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
22591
22509
  },
22592
22510
  placeNew(c, conceptId) {
22593
- const posix = toPosix6(conceptId);
22511
+ const posix = toPosix(conceptId);
22594
22512
  const slash = posix.indexOf("/");
22595
22513
  if (slash > 0) {
22596
22514
  const head = posix.slice(0, slash);
@@ -22625,13 +22543,8 @@ var dotenvAdapter = {
22625
22543
  import path21 from "path";
22626
22544
  var COMPONENT_ID5 = "main";
22627
22545
  var DOCUMENT_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".text"]);
22628
- var RESERVED_FILES3 = new Set(["index.md", "log.md"]);
22629
- var MAX_CONTENT_CHARS5 = 1e5;
22630
- function toPosix7(p) {
22631
- return p.replace(/\\/g, "/");
22632
- }
22633
22546
  function isReserved2(base3) {
22634
- return RESERVED_FILES3.has(base3.toLowerCase());
22547
+ return RESERVED_FILES.has(base3.toLowerCase());
22635
22548
  }
22636
22549
  function classify3(ext) {
22637
22550
  if (SCRIPT_EXTENSIONS.has(ext))
@@ -22641,7 +22554,7 @@ function classify3(ext) {
22641
22554
  return "file";
22642
22555
  }
22643
22556
  function recognize6(c, file) {
22644
- const posix = toPosix7(file.relPath);
22557
+ const posix = toPosix(file.relPath);
22645
22558
  const base3 = posix.split("/").pop() ?? posix;
22646
22559
  if (isReserved2(base3))
22647
22560
  return null;
@@ -22661,7 +22574,7 @@ function recognize6(c, file) {
22661
22574
  adapterId: "generic-files",
22662
22575
  type,
22663
22576
  name,
22664
- content: body.length > MAX_CONTENT_CHARS5 ? body.slice(0, MAX_CONTENT_CHARS5) : body
22577
+ content: body
22665
22578
  };
22666
22579
  if (type !== "script")
22667
22580
  doc.ownsPresentation = true;
@@ -22681,7 +22594,7 @@ async function validate6(c, changes, ctx) {
22681
22594
  const raw = change.after ?? await ctx.readFile(change.path);
22682
22595
  if (typeof raw !== "string")
22683
22596
  continue;
22684
- diagnostics.push(...await runBaseValidateChecks(toPosix7(change.path), parseFrontmatter(raw), c.root, ctx));
22597
+ diagnostics.push(...await runBaseValidateChecks(toPosix(change.path), parseFrontmatter(raw), c.root, ctx));
22685
22598
  }
22686
22599
  return diagnostics;
22687
22600
  }
@@ -22692,7 +22605,7 @@ var genericFilesAdapter = {
22692
22605
  recognize: recognize6,
22693
22606
  validate: validate6,
22694
22607
  readCandidates(c, conceptId) {
22695
- const posix = toPosix7(conceptId);
22608
+ const posix = toPosix(conceptId);
22696
22609
  const extension = path21.extname(posix).toLowerCase();
22697
22610
  const documentCandidates = [...DOCUMENT_EXTENSIONS].map((candidateExtension) => ({
22698
22611
  path: path21.join(c.root, `${posix}${candidateExtension}`),
@@ -22701,7 +22614,7 @@ var genericFilesAdapter = {
22701
22614
  return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path21.join(c.root, posix), conceptId: posix }, ...documentCandidates];
22702
22615
  },
22703
22616
  placeNew(c, conceptId) {
22704
- const posix = toPosix7(conceptId);
22617
+ const posix = toPosix(conceptId);
22705
22618
  const hasExt = path21.extname(posix) !== "";
22706
22619
  return path21.join(c.root, hasExt ? posix : `${posix}.md`);
22707
22620
  },
@@ -22719,12 +22632,8 @@ var DEFAULT_PAGE_KIND = "note";
22719
22632
  var RESERVED_ROOT_FILES = new Set(["schema.md", "index.md", "log.md"]);
22720
22633
  var RAW_SUBDIR = "raw";
22721
22634
  var PAGES_SUBDIR = "pages";
22722
- var MAX_CONTENT_CHARS6 = 1e5;
22723
- function toPosix8(p) {
22724
- return p.replace(/\\/g, "/");
22725
- }
22726
22635
  function conceptIdOf2(relPath) {
22727
- return toPosix8(relPath).replace(/\.md$/i, "");
22636
+ return toPosix(relPath).replace(/\.md$/i, "");
22728
22637
  }
22729
22638
  function parseWikiFrontmatter(raw) {
22730
22639
  const out = { xrefs: [], sources: [] };
@@ -22756,13 +22665,13 @@ function parseWikiFrontmatter(raw) {
22756
22665
  return out;
22757
22666
  }
22758
22667
  function isReservedRootFile(relPath) {
22759
- const posix = toPosix8(relPath);
22668
+ const posix = toPosix(relPath);
22760
22669
  if (posix.includes("/"))
22761
22670
  return false;
22762
22671
  return RESERVED_ROOT_FILES.has(posix.toLowerCase());
22763
22672
  }
22764
22673
  function firstSegment(relPath) {
22765
- const posix = toPosix8(relPath);
22674
+ const posix = toPosix(relPath);
22766
22675
  const slash = posix.indexOf("/");
22767
22676
  return slash < 0 ? posix : posix.slice(0, slash);
22768
22677
  }
@@ -22774,7 +22683,7 @@ function resolveXref(xref, bundleId) {
22774
22683
  return target.length > 0 ? target : null;
22775
22684
  }
22776
22685
  function resolveBodyLinks(body, fileRelPath) {
22777
- const dir = path22.posix.dirname(toPosix8(fileRelPath));
22686
+ const dir = path22.posix.dirname(toPosix(fileRelPath));
22778
22687
  const linkRe = /\[[^\]]*\]\(([^)]+)\)/g;
22779
22688
  const out = [];
22780
22689
  const seen = new Set;
@@ -22851,7 +22760,7 @@ function resolveSources(fm) {
22851
22760
  function recognize7(c, file) {
22852
22761
  if (file.ext !== ".md")
22853
22762
  return null;
22854
- const relPath = toPosix8(file.relPath);
22763
+ const relPath = toPosix(file.relPath);
22855
22764
  if (isReservedRootFile(relPath))
22856
22765
  return null;
22857
22766
  const head = firstSegment(relPath);
@@ -22875,7 +22784,7 @@ function recognize7(c, file) {
22875
22784
  ownsPresentation: true,
22876
22785
  type: isRaw ? WIKI_SOURCE_TYPE : fm.pageKind ?? DEFAULT_PAGE_KIND,
22877
22786
  name: lastSegment,
22878
- content: body.length > MAX_CONTENT_CHARS6 ? body.slice(0, MAX_CONTENT_CHARS6) : body
22787
+ content: body
22879
22788
  };
22880
22789
  if (fm.description !== undefined)
22881
22790
  doc.description = fm.description;
@@ -22901,7 +22810,7 @@ async function validate7(c, changes, ctx) {
22901
22810
  const raw = change.after ?? await ctx.readFile(change.path);
22902
22811
  if (typeof raw !== "string")
22903
22812
  continue;
22904
- const relPath = toPosix8(change.path);
22813
+ const relPath = toPosix(change.path);
22905
22814
  if (isReservedRootFile(relPath))
22906
22815
  continue;
22907
22816
  const head = firstSegment(relPath);
@@ -22984,7 +22893,7 @@ var llmWikiAdapter = {
22984
22893
  recognize: recognize7,
22985
22894
  validate: validate7,
22986
22895
  readCandidates(c, conceptId) {
22987
- const canonical = toPosix8(conceptId).replace(/\.md$/i, "");
22896
+ const canonical = toPosix(conceptId).replace(/\.md$/i, "");
22988
22897
  return [{ path: path22.join(c.root, `${canonical}.md`), conceptId: canonical }];
22989
22898
  },
22990
22899
  placeNew(c, conceptId) {
@@ -23020,11 +22929,8 @@ var CONSUMED_FRONTMATTER_KEYS = [
23020
22929
  "stale_after",
23021
22930
  "okf_version"
23022
22931
  ];
23023
- function isPlainObject3(value) {
23024
- return value !== null && typeof value === "object" && !Array.isArray(value);
23025
- }
23026
22932
  function parseActorMapping(value) {
23027
- if (!isPlainObject3(value))
22933
+ if (!isRecord(value))
23028
22934
  return;
23029
22935
  const by = nonEmptyString(value.by);
23030
22936
  if (by === undefined)
@@ -23049,7 +22955,7 @@ function parseOkfSources(value) {
23049
22955
  return;
23050
22956
  const out = [];
23051
22957
  for (const item of value) {
23052
- if (!isPlainObject3(item))
22958
+ if (!isRecord(item))
23053
22959
  continue;
23054
22960
  const resource = nonEmptyString(item.resource);
23055
22961
  if (resource === undefined)
@@ -23077,16 +22983,11 @@ function parseOkfSources(value) {
23077
22983
  function parseLifecycleStatus(value) {
23078
22984
  return value === "draft" || value === "stable" || value === "deprecated" ? value : undefined;
23079
22985
  }
23080
- var RESERVED_FILES4 = new Set(["index.md", "log.md"]);
23081
- var MAX_CONTENT_CHARS7 = 1e5;
23082
- function toPosix9(p) {
23083
- return p.replace(/\\/g, "/");
23084
- }
23085
22986
  function isReservedFileName2(name) {
23086
- return RESERVED_FILES4.has(name.toLowerCase());
22987
+ return RESERVED_FILES.has(name.toLowerCase());
23087
22988
  }
23088
22989
  function resolveOkfLinks(body, fileRelPath) {
23089
- const dir = path23.posix.dirname(toPosix9(fileRelPath));
22990
+ const dir = path23.posix.dirname(toPosix(fileRelPath));
23090
22991
  const definitions = new Map;
23091
22992
  for (const match of body.matchAll(/^\s*\[([^\]]+)\]:\s*(\S+)/gm)) {
23092
22993
  definitions.set(match[1].trim().toLowerCase(), match[2]);
@@ -23144,7 +23045,7 @@ function recognize8(c, file) {
23144
23045
  return null;
23145
23046
  if (isReservedFileName2(file.fileName))
23146
23047
  return null;
23147
- const conceptId = toPosix9(file.relPath).replace(/\.md$/i, "");
23048
+ const conceptId = toPosix(file.relPath).replace(/\.md$/i, "");
23148
23049
  const raw = file.content();
23149
23050
  const parsed = parseFrontmatter(raw);
23150
23051
  const data = parsed.data;
@@ -23155,7 +23056,7 @@ function recognize8(c, file) {
23155
23056
  const description = nonEmptyString(data.description);
23156
23057
  const tags = readTags(data.tags);
23157
23058
  const links = resolveOkfLinks(body, file.relPath);
23158
- const generatedMapping = isPlainObject3(data.generated) ? data.generated : undefined;
23059
+ const generatedMapping = isRecord(data.generated) ? data.generated : undefined;
23159
23060
  const generatedAt = generatedMapping ? nonEmptyString(generatedMapping.at) : undefined;
23160
23061
  const generatedBy = generatedMapping ? nonEmptyString(generatedMapping.by) : undefined;
23161
23062
  const legacyTimestamp = nonEmptyString(data.timestamp);
@@ -23182,7 +23083,7 @@ function recognize8(c, file) {
23182
23083
  ownsPresentation: true,
23183
23084
  type,
23184
23085
  name,
23185
- content: body.length > MAX_CONTENT_CHARS7 ? body.slice(0, MAX_CONTENT_CHARS7) : body
23086
+ content: body
23186
23087
  };
23187
23088
  if (description !== undefined)
23188
23089
  doc.description = description;
@@ -23213,7 +23114,7 @@ async function validate8(c, changes, ctx) {
23213
23114
  const raw = change.after ?? await ctx.readFile(change.path);
23214
23115
  if (typeof raw !== "string")
23215
23116
  continue;
23216
- const relPath = toPosix9(change.path);
23117
+ const relPath = toPosix(change.path);
23217
23118
  const fileName = relPath.split("/").pop() ?? relPath;
23218
23119
  const reserved = isReservedFileName2(fileName);
23219
23120
  const parsed = parseFrontmatter(raw);
@@ -23337,10 +23238,6 @@ var COMPONENT_ID6 = "main";
23337
23238
  var PAGES_PREFIX = "stash/knowledge/";
23338
23239
  var MANIFEST_FILE = "manifest.json";
23339
23240
  var WEBSITE_TAG = "website";
23340
- var MAX_CONTENT_CHARS8 = 1e5;
23341
- function toPosix10(p) {
23342
- return p.replace(/\\/g, "/");
23343
- }
23344
23241
  function parseSnapshotFrontmatter(raw) {
23345
23242
  const out = { tags: [] };
23346
23243
  const block = parseFrontmatterBlock(raw);
@@ -23363,14 +23260,14 @@ function parseSnapshotFrontmatter(raw) {
23363
23260
  return out;
23364
23261
  }
23365
23262
  function isSnapshotPage(relPath) {
23366
- const posix = toPosix10(relPath);
23263
+ const posix = toPosix(relPath);
23367
23264
  return posix.startsWith(PAGES_PREFIX) && posix.toLowerCase().endsWith(".md");
23368
23265
  }
23369
23266
  function isReTypeGated(fm) {
23370
23267
  return fm.sourceUrl !== undefined || fm.tags.includes(WEBSITE_TAG);
23371
23268
  }
23372
23269
  function conceptIdOf3(relPath) {
23373
- return toPosix10(relPath).slice(PAGES_PREFIX.length).replace(/\.md$/i, "");
23270
+ return toPosix(relPath).slice(PAGES_PREFIX.length).replace(/\.md$/i, "");
23374
23271
  }
23375
23272
  function recognize9(c, file) {
23376
23273
  if (file.ext !== ".md" || !isSnapshotPage(file.relPath))
@@ -23393,7 +23290,7 @@ function recognize9(c, file) {
23393
23290
  ownsPresentation: true,
23394
23291
  type: "website",
23395
23292
  name,
23396
- content: body.length > MAX_CONTENT_CHARS8 ? body.slice(0, MAX_CONTENT_CHARS8) : body
23293
+ content: body
23397
23294
  };
23398
23295
  if (fm.description !== undefined)
23399
23296
  doc.description = fm.description;
@@ -23411,7 +23308,7 @@ async function validate9(c, changes, ctx) {
23411
23308
  continue;
23412
23309
  if (!isSnapshotPage(change.path))
23413
23310
  continue;
23414
- const base3 = await runBaseValidateChecks(toPosix10(change.path), parseFrontmatter(raw), c.root, ctx);
23311
+ const base3 = await runBaseValidateChecks(toPosix(change.path), parseFrontmatter(raw), c.root, ctx);
23415
23312
  diagnostics.push(...base3.filter((d) => d.issue !== "missing-updated"));
23416
23313
  }
23417
23314
  return diagnostics;
@@ -23423,7 +23320,7 @@ var websiteSnapshotAdapter = {
23423
23320
  recognize: recognize9,
23424
23321
  validate: validate9,
23425
23322
  readCandidates(c, conceptId) {
23426
- const canonical = toPosix10(conceptId).replace(/\.md$/i, "");
23323
+ const canonical = toPosix(conceptId).replace(/\.md$/i, "");
23427
23324
  return [{ path: path25.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
23428
23325
  },
23429
23326
  looksLikeRoot(root) {
@@ -23900,6 +23797,27 @@ function describeJsonRoot(value) {
23900
23797
  return "a boolean";
23901
23798
  return typeof value;
23902
23799
  }
23800
+ function pruneToNewest(dir, keep, select) {
23801
+ let entries;
23802
+ try {
23803
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
23804
+ } catch {
23805
+ return;
23806
+ }
23807
+ const candidates = entries.filter(select).map((entry) => {
23808
+ const full = path27.join(dir, entry.name);
23809
+ let mtime = 0;
23810
+ try {
23811
+ mtime = fs18.statSync(full).mtimeMs;
23812
+ } catch {}
23813
+ return { path: full, mtime };
23814
+ }).sort((a, b) => b.mtime - a.mtime);
23815
+ for (const stale of candidates.slice(keep)) {
23816
+ try {
23817
+ fs18.rmSync(stale.path, { recursive: true, force: true });
23818
+ } catch {}
23819
+ }
23820
+ }
23903
23821
  function getConfigLockPath() {
23904
23822
  return path27.join(getConfigDir(), "config.json.lck");
23905
23823
  }
@@ -28813,7 +28731,7 @@ function upgradeConfigVersion(raw, sourcePath) {
28813
28731
 
28814
28732
  // src/core/config/deep-merge.ts
28815
28733
  var UNSAFE_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
28816
- function isPlainObject4(value) {
28734
+ function isPlainObject(value) {
28817
28735
  if (value === null || typeof value !== "object" || Array.isArray(value))
28818
28736
  return false;
28819
28737
  const prototype = Object.getPrototypeOf(value);
@@ -28822,7 +28740,7 @@ function isPlainObject4(value) {
28822
28740
  function copyConfigValue(value) {
28823
28741
  if (Array.isArray(value))
28824
28742
  return value.map(copyConfigValue);
28825
- if (!isPlainObject4(value))
28743
+ if (!isPlainObject(value))
28826
28744
  return value;
28827
28745
  const copy = {};
28828
28746
  for (const key of Object.keys(value)) {
@@ -28841,7 +28759,7 @@ function deepMergeConfig(base3, override) {
28841
28759
  if (next === undefined)
28842
28760
  continue;
28843
28761
  const current = result[key];
28844
- result[key] = isPlainObject4(current) && isPlainObject4(next) ? deepMergeConfig(current, next) : copyConfigValue(next);
28762
+ result[key] = isPlainObject(current) && isPlainObject(next) ? deepMergeConfig(current, next) : copyConfigValue(next);
28845
28763
  }
28846
28764
  return result;
28847
28765
  }
@@ -28902,8 +28820,8 @@ function loadUserConfig() {
28902
28820
  }
28903
28821
  function parseAndValidateConfigText(text, sourcePath) {
28904
28822
  const parsedRaw = upgradeConfigVersion(parseConfigText(text, sourcePath), sourcePath);
28905
- const { config: raw, lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
28906
28823
  const where = sourcePath ? ` at ${sourcePath}` : "";
28824
+ const { lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
28907
28825
  if (conflicts.length > 0) {
28908
28826
  const lines = conflicts.map((c) => ` - engines.${c.engine}.extraParams.${c.key} (${JSON.stringify(c.extraParamsValue)}) conflicts with engines.${c.engine}.${c.field} (${JSON.stringify(c.fieldValue)})`).join(`
28909
28827
  `);
@@ -28913,11 +28831,13 @@ ${lines}
28913
28831
  Each extraParams key above has a first-class equivalent and akm will not guess which value you meant \u2014 remove the extraParams entry once the field carries the value you want.`, "INVALID_CONFIG_FILE");
28914
28832
  }
28915
28833
  if (lifted.length > 0) {
28916
- warn(`Config${where} uses deprecated extraParams keys with first-class equivalents; treating them as the first-class fields for this run (not written back to the file):
28834
+ throw new ConfigError(`Config${where} uses deprecated extraParams keys with first-class equivalents:
28917
28835
  - ${lifted.join(`
28918
- - `)}`);
28836
+ - `)}
28837
+
28838
+ Run \`akm migrate apply\` to rewrite the config file, or move the values onto the first-class fields yourself.`, "INVALID_CONFIG_FILE");
28919
28839
  }
28920
- const parsed = AkmConfigSchema.safeParse(raw);
28840
+ const parsed = AkmConfigSchema.safeParse(parsedRaw);
28921
28841
  if (!parsed.success) {
28922
28842
  const lines = parsed.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join(`
28923
28843
  `);
@@ -29212,6 +29132,9 @@ function createProviderRegistry() {
29212
29132
  resolve(type) {
29213
29133
  return map.get(type) ?? null;
29214
29134
  },
29135
+ unregister(type) {
29136
+ map.delete(type);
29137
+ },
29215
29138
  list() {
29216
29139
  return [...map.keys()];
29217
29140
  }
@@ -29868,6 +29791,10 @@ function inspectCurrentTaskPlan() {
29868
29791
  function inspectMigrationPlan() {
29869
29792
  return inspectCurrentTaskPlan().result;
29870
29793
  }
29794
+ var MAX_TASK_MIGRATION_BACKUPS = 5;
29795
+ function pruneTaskMigrationBackups(generationBackupDir) {
29796
+ pruneToNewest(generationBackupDir, MAX_TASK_MIGRATION_BACKUPS, (entry) => entry.isDirectory());
29797
+ }
29871
29798
  function printPlan(plan) {
29872
29799
  console.log(JSON.stringify(plan));
29873
29800
  if (plan.status === "blocked")
@@ -29885,12 +29812,14 @@ async function runMigrationApply(options = {}) {
29885
29812
  const before = inspectCurrentTaskPlan();
29886
29813
  if (before.result.taskV3Migration.changed === 0)
29887
29814
  return before.result;
29888
- const backupPath = path33.join(getDataDir(), "backups", "task-v3", `${Date.now()}-${randomUUID2()}`);
29815
+ const backupRoot = path33.join(getDataDir(), "backups", "task-v3");
29816
+ const backupPath = path33.join(backupRoot, `${Date.now()}-${randomUUID2()}`);
29889
29817
  const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
29890
29818
  const after = inspectCurrentTaskPlan().result;
29891
29819
  if (after.taskV3Migration.changed > 0) {
29892
29820
  throw new ConfigError("Task migration did not converge to task v3.", "INVALID_CONFIG_FILE");
29893
29821
  }
29822
+ pruneTaskMigrationBackups(backupRoot);
29894
29823
  return { ...after, backupPath, applied: applied.changed.length };
29895
29824
  }));
29896
29825
  printPlan(result);
@@ -29948,12 +29877,14 @@ async function runTaskV4MigrationApply(options = {}) {
29948
29877
  const before = inspectCurrentTaskV4Plan();
29949
29878
  if (before.result.taskV4Migration.changed === 0)
29950
29879
  return before.result;
29951
- const backupPath = path33.join(getDataDir(), "backups", "task-v4", `${Date.now()}-${randomUUID2()}`);
29880
+ const backupRoot = path33.join(getDataDir(), "backups", "task-v4");
29881
+ const backupPath = path33.join(backupRoot, `${Date.now()}-${randomUUID2()}`);
29952
29882
  const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
29953
29883
  const after = inspectCurrentTaskV4Plan().result;
29954
29884
  if (after.taskV4Migration.changed > 0) {
29955
29885
  throw new ConfigError("Task migration did not converge to task source v4.", "INVALID_CONFIG_FILE");
29956
29886
  }
29887
+ pruneTaskMigrationBackups(backupRoot);
29957
29888
  return { ...after, backupPath, applied: applied.changed.length };
29958
29889
  }));
29959
29890
  printPlan(result);