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
@@ -9454,6 +9454,12 @@ function stripJsonComments(text) {
9454
9454
  }
9455
9455
  return result;
9456
9456
  }
9457
+ function toPosix(input) {
9458
+ return input.replace(/\\/g, "/");
9459
+ }
9460
+ function compareCodePoints(left, right) {
9461
+ return left < right ? -1 : left > right ? 1 : 0;
9462
+ }
9457
9463
  function isContainedRelativePath(value) {
9458
9464
  if (value === "" || value.startsWith("/") || value.startsWith("\\") || value.startsWith("~"))
9459
9465
  return false;
@@ -9506,6 +9512,40 @@ function asNonEmptyString(value) {
9506
9512
  const trimmed = value.trim();
9507
9513
  return trimmed.length > 0 ? trimmed : undefined;
9508
9514
  }
9515
+ var ENV_ASSIGN_LINE_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
9516
+ function scanEnvKeyNames(text) {
9517
+ const keys = [];
9518
+ const seen = new Set;
9519
+ for (const line of text.split(/\r?\n/)) {
9520
+ const m = line.match(ENV_ASSIGN_LINE_RE);
9521
+ if (!m)
9522
+ continue;
9523
+ const key = m[1];
9524
+ if (!key)
9525
+ continue;
9526
+ if (seen.has(key))
9527
+ continue;
9528
+ seen.add(key);
9529
+ keys.push(key);
9530
+ }
9531
+ return keys;
9532
+ }
9533
+ function wellFormedUnicode(value) {
9534
+ for (let index = 0;index < value.length; index += 1) {
9535
+ const code = value.charCodeAt(index);
9536
+ if (code >= 55296 && code <= 56319) {
9537
+ const next = value.charCodeAt(index + 1);
9538
+ if (!(next >= 56320 && next <= 57343))
9539
+ return false;
9540
+ index += 1;
9541
+ } else if (code >= 56320 && code <= 57343)
9542
+ return false;
9543
+ }
9544
+ return true;
9545
+ }
9546
+ function isRecord(value) {
9547
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9548
+ }
9509
9549
  function isProcessAlive(pid) {
9510
9550
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0)
9511
9551
  return false;
@@ -11548,9 +11588,6 @@ function isKnownType(type) {
11548
11588
  var DEPRECATED_REJECTED_TYPES = new Set(["tool", "vault"]);
11549
11589
 
11550
11590
  // src/core/asset/asset-placement.ts
11551
- function toPosix(input) {
11552
- return input.replace(/\\/g, "/");
11553
- }
11554
11591
  var workflowSpec = {
11555
11592
  isRelevantFile: (fileName) => WORKFLOW_EXTENSIONS.includes(path5.extname(fileName).toLowerCase()),
11556
11593
  toCanonicalName: (typeRoot, filePath) => {
@@ -12728,6 +12765,7 @@ function readTags(value) {
12728
12765
  const tags = value.filter((tag) => typeof tag === "string" && tag.trim().length > 0);
12729
12766
  return tags.length > 0 ? tags : undefined;
12730
12767
  }
12768
+ var RESERVED_FILES = new Set(["index.md", "log.md"]);
12731
12769
  function checkMissingUpdated(data, frontmatterText) {
12732
12770
  return frontmatterText !== null && !("updated" in data);
12733
12771
  }
@@ -12865,12 +12903,8 @@ var NAME_MAX = 64;
12865
12903
  var DESCRIPTION_MAX = 1024;
12866
12904
  var RESERVED_NAME_WORDS = ["anthropic", "claude"];
12867
12905
  var NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
12868
- var MAX_CONTENT_CHARS = 1e5;
12869
- function toPosix2(p) {
12870
- return p.replace(/\\/g, "/");
12871
- }
12872
12906
  function skillPackage(relPath) {
12873
- const posix = toPosix2(relPath);
12907
+ const posix = toPosix(relPath);
12874
12908
  const segs = posix.split("/").filter((s) => s.length > 0);
12875
12909
  if (segs.length < 2 || segs[segs.length - 1] !== SKILL_MANIFEST)
12876
12910
  return null;
@@ -12899,7 +12933,7 @@ function recognize(c, file) {
12899
12933
  adapterId: "agent-skills",
12900
12934
  type: "skill",
12901
12935
  name,
12902
- content: body.length > MAX_CONTENT_CHARS ? body.slice(0, MAX_CONTENT_CHARS) : body
12936
+ content: body
12903
12937
  };
12904
12938
  if (description !== undefined)
12905
12939
  doc.description = description;
@@ -12987,7 +13021,7 @@ async function validate(_c, changes, ctx) {
12987
13021
  if (seenDirs.has(pkg.conceptId))
12988
13022
  continue;
12989
13023
  seenDirs.add(pkg.conceptId);
12990
- diagnostics.push(...skillFieldDiagnostics(toPosix2(change.path), pkg.dirName, parseFrontmatter(raw).data));
13024
+ diagnostics.push(...skillFieldDiagnostics(toPosix(change.path), pkg.dirName, parseFrontmatter(raw).data));
12991
13025
  }
12992
13026
  diagnostics.push(...await missingManifestDiagnostics(ctx));
12993
13027
  return diagnostics;
@@ -13070,6 +13104,7 @@ function warn(...args) {
13070
13104
  console.warn(...args);
13071
13105
  }
13072
13106
  }
13107
+ var warnedOnceKeys = new Set;
13073
13108
  function warnVerbose(...args) {
13074
13109
  if (sinkOverride) {
13075
13110
  sinkOverride("warnVerbose", args);
@@ -14846,24 +14881,6 @@ import path14 from "node:path";
14846
14881
 
14847
14882
  // src/commands/env/env.ts
14848
14883
  var import_dotenv = __toESM(require_main(), 1);
14849
- var ASSIGN_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
14850
- function scanEnvKeyNames(text) {
14851
- const keys = [];
14852
- const seen = new Set;
14853
- for (const line of text.split(/\r?\n/)) {
14854
- const m = line.match(ASSIGN_RE);
14855
- if (!m)
14856
- continue;
14857
- const key = m[1];
14858
- if (!key)
14859
- continue;
14860
- if (seen.has(key))
14861
- continue;
14862
- seen.add(key);
14863
- keys.push(key);
14864
- }
14865
- return keys;
14866
- }
14867
14884
 
14868
14885
  // src/commands/lint/env-key-rules.ts
14869
14886
  var DANGEROUS_ENV_KEYS = new Set([
@@ -15001,19 +15018,6 @@ function own2(value, key) {
15001
15018
  function utf8Bytes2(value) {
15002
15019
  return new TextEncoder().encode(value).byteLength;
15003
15020
  }
15004
- function wellFormedUnicode(value) {
15005
- for (let index = 0;index < value.length; index += 1) {
15006
- const code = value.charCodeAt(index);
15007
- if (code >= 55296 && code <= 56319) {
15008
- const next = value.charCodeAt(index + 1);
15009
- if (!(next >= 56320 && next <= 57343))
15010
- return false;
15011
- index += 1;
15012
- } else if (code >= 56320 && code <= 57343)
15013
- return false;
15014
- }
15015
- return true;
15016
- }
15017
15021
  function sourceError(ctx, fieldPath, detail) {
15018
15022
  const dotted = fieldPath.length === 0 ? "$" : fieldPath.reduce((display, segment) => typeof segment === "number" ? `${display}[${segment}]` : display.length > 0 ? `${display}.${segment}` : segment, "");
15019
15023
  const line = ctx.lineAt?.(fieldPath);
@@ -15425,9 +15429,6 @@ function pointerFor(path10) {
15425
15429
  function pushIssue(issues, path10, keyword, kind, message) {
15426
15430
  issues.push({ path: [...path10], pointer: pointerFor(path10), keyword, kind, message });
15427
15431
  }
15428
- function isPlainObject(value) {
15429
- return typeof value === "object" && value !== null && !Array.isArray(value);
15430
- }
15431
15432
  function isSupportedEnumValue(value) {
15432
15433
  return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
15433
15434
  }
@@ -15477,7 +15478,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15477
15478
  continue;
15478
15479
  }
15479
15480
  branches.forEach((branch, index) => {
15480
- if (isPlainObject(branch)) {
15481
+ if (isRecord(branch)) {
15481
15482
  checkDefinitionNode(branch, [...path10, keyword, index], issues, depth + 1);
15482
15483
  } else {
15483
15484
  pushIssue(issues, [...path10, keyword, index], keyword, "malformed", `"${keyword}[${index}]" must be a schema object`);
@@ -15485,7 +15486,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15485
15486
  });
15486
15487
  }
15487
15488
  if (schema.not !== undefined) {
15488
- if (isPlainObject(schema.not)) {
15489
+ if (isRecord(schema.not)) {
15489
15490
  checkDefinitionNode(schema.not, [...path10, "not"], issues, depth + 1);
15490
15491
  } else {
15491
15492
  pushIssue(issues, [...path10, "not"], "not", "malformed", `"not" must be a schema object`);
@@ -15497,11 +15498,11 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15497
15498
  }
15498
15499
  }
15499
15500
  if (schema.properties !== undefined) {
15500
- if (!isPlainObject(schema.properties)) {
15501
+ if (!isRecord(schema.properties)) {
15501
15502
  pushIssue(issues, [...path10, "properties"], "properties", "malformed", `"properties" must be an object mapping property names to schemas`);
15502
15503
  } else {
15503
15504
  for (const [key, propSchema] of Object.entries(schema.properties)) {
15504
- if (isPlainObject(propSchema)) {
15505
+ if (isRecord(propSchema)) {
15505
15506
  checkDefinitionNode(propSchema, [...path10, "properties", key], issues, depth + 1);
15506
15507
  } else {
15507
15508
  pushIssue(issues, [...path10, "properties", key], "properties", "malformed", `property ${JSON.stringify(key)} must be a schema object`);
@@ -15510,7 +15511,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15510
15511
  }
15511
15512
  }
15512
15513
  if (schema.items !== undefined) {
15513
- if (isPlainObject(schema.items)) {
15514
+ if (isRecord(schema.items)) {
15514
15515
  checkDefinitionNode(schema.items, [...path10, "items"], issues, depth + 1);
15515
15516
  } else if (Array.isArray(schema.items)) {
15516
15517
  pushIssue(issues, [...path10, "items"], "items", "unsupported", `tuple-form "items" (an array of schemas) is not enforced by the workflow schema subset — use a single schema object`);
@@ -15519,7 +15520,7 @@ function checkDefinitionNode(schema, path10, issues, depth) {
15519
15520
  }
15520
15521
  }
15521
15522
  if (schema.additionalProperties !== undefined && typeof schema.additionalProperties !== "boolean") {
15522
- if (isPlainObject(schema.additionalProperties)) {
15523
+ if (isRecord(schema.additionalProperties)) {
15523
15524
  pushIssue(issues, [...path10, "additionalProperties"], "additionalProperties", "unsupported", `schema-form "additionalProperties" is not enforced by the workflow schema subset — only "additionalProperties: false" is`);
15524
15525
  } else {
15525
15526
  pushIssue(issues, [...path10, "additionalProperties"], "additionalProperties", "malformed", `"additionalProperties" must be a boolean (only "false" is enforced)`);
@@ -15568,7 +15569,7 @@ function combinatorBranches(schema, keyword) {
15568
15569
  const raw = schema[keyword];
15569
15570
  if (!Array.isArray(raw))
15570
15571
  return [];
15571
- return raw.filter(isPlainObject);
15572
+ return raw.filter(isRecord);
15572
15573
  }
15573
15574
  function summarizeBranchFailures(failures) {
15574
15575
  const shown = failures.slice(0, 3).map((f) => `${f.index + 1}: ${f.errors[0] ?? "no match"}`);
@@ -15600,7 +15601,7 @@ function validateCombinators(value, schema, path10, ctx) {
15600
15601
  }
15601
15602
  }
15602
15603
  const not = schema.not;
15603
- if (isPlainObject(not) && branchErrors(value, not, path10, ctx).length === 0) {
15604
+ if (isRecord(not) && branchErrors(value, not, path10, ctx).length === 0) {
15604
15605
  ctx.errors.push(`${path10}: value must not match the "not" schema`);
15605
15606
  }
15606
15607
  }
@@ -16356,20 +16357,17 @@ function formatExtraParamsIssue(label, issue) {
16356
16357
  const suffix = issue.path.map((part) => typeof part === "number" ? `[${part}]` : `.${part}`).join("");
16357
16358
  return `${label}${suffix} ${issue.message}`;
16358
16359
  }
16359
- function isPlainObject2(value) {
16360
- return typeof value === "object" && value !== null && !Array.isArray(value);
16361
- }
16362
16360
  function liftLegacyEngineExtraParams(raw) {
16363
16361
  const lifted = [];
16364
16362
  const conflicts = [];
16365
16363
  const rawEngines = raw.engines;
16366
- if (!isPlainObject2(rawEngines)) {
16364
+ if (!isRecord(rawEngines)) {
16367
16365
  return { config: raw, lifted, conflicts };
16368
16366
  }
16369
16367
  const engines = {};
16370
16368
  let anyEngineChanged = false;
16371
16369
  for (const [name, engineValue] of Object.entries(rawEngines)) {
16372
- if (!isPlainObject2(engineValue) || !isPlainObject2(engineValue.extraParams)) {
16370
+ if (!isRecord(engineValue) || !isRecord(engineValue.extraParams)) {
16373
16371
  engines[name] = engineValue;
16374
16372
  continue;
16375
16373
  }
@@ -16858,6 +16856,7 @@ function base(input) {
16858
16856
  ...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
16859
16857
  };
16860
16858
  }
16859
+ 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:` — see docs/migration/v0.9.1-to-v0.9.2.md for the full v2 to v4 field mapping.";
16861
16860
  function blocked(input, reason, detail) {
16862
16861
  return Object.freeze({ status: "blocked", ...base(input), reason, ...detail ? { detail } : {} });
16863
16862
  }
@@ -17120,8 +17119,10 @@ function planLegacyTaskDataToV3(input, data) {
17120
17119
  } catch (cause) {
17121
17120
  return blocked(input, "invalid-v2-task", cause instanceof Error ? cause.message : String(cause));
17122
17121
  }
17123
- if (isReason(migrated))
17124
- return blocked(input, migrated);
17122
+ if (isReason(migrated)) {
17123
+ const detail = migrated === "argv-array-has-no-portable-shell-string" ? ARGV_ARRAY_BLOCK_DETAIL : undefined;
17124
+ return blocked(input, migrated, detail);
17125
+ }
17125
17126
  const after = Buffer.from($stringify(migrated), "utf8");
17126
17127
  try {
17127
17128
  parseTaskV3Yaml({
@@ -17889,11 +17890,6 @@ function sourceStepRef(source) {
17889
17890
  // src/workflows/source-ir/schema.ts
17890
17891
  import { types as utilTypes2 } from "node:util";
17891
17892
 
17892
- // src/workflows/source-ir/compare.ts
17893
- function compareWorkflowSourceCodePoints(left, right) {
17894
- return left < right ? -1 : left > right ? 1 : 0;
17895
- }
17896
-
17897
17893
  // src/workflows/source-ir/semantics.ts
17898
17894
  import fs7 from "node:fs";
17899
17895
  import path12 from "node:path";
@@ -18532,9 +18528,6 @@ function validateStep(value, jobId, index, stepIds, options) {
18532
18528
  extensions(step.extensions, `step ${id} extensions`);
18533
18529
  span(step.source, `step ${id} source`);
18534
18530
  }
18535
- function compareCodePoints(left, right) {
18536
- return compareWorkflowSourceCodePoints(left, right);
18537
- }
18538
18531
  function validateExec(value, location, options) {
18539
18532
  if (value === undefined)
18540
18533
  return;
@@ -18840,7 +18833,7 @@ function snapshotValue(value, depth, location, state) {
18840
18833
  return value;
18841
18834
  }
18842
18835
  if (typeof value === "string") {
18843
- if (!wellFormedUnicode2(value))
18836
+ if (!wellFormedUnicode(value))
18844
18837
  fail2(`${location} must contain well-formed Unicode`);
18845
18838
  countJsonBytes(state, JSON.stringify(value));
18846
18839
  return value;
@@ -18904,7 +18897,7 @@ function snapshotObject(value, depth, location, state) {
18904
18897
  for (const [index, key] of ownKeys.entries()) {
18905
18898
  if (typeof key === "symbol")
18906
18899
  fail2(`${location} contains symbol keys`);
18907
- if (!wellFormedUnicode2(key))
18900
+ if (!wellFormedUnicode(key))
18908
18901
  fail2(`${location} contains an ill-formed key`);
18909
18902
  if (UNSAFE_KEYS.has(key))
18910
18903
  fail2(`${location} contains unsafe key ${key}`);
@@ -18933,20 +18926,6 @@ function countJsonBytes(state, token) {
18933
18926
  if (state.bytes > WORKFLOW_SOURCE_IR_MAX_BYTES)
18934
18927
  fail2("source IR exceeds the byte limit");
18935
18928
  }
18936
- function wellFormedUnicode2(value) {
18937
- for (let index = 0;index < value.length; index++) {
18938
- const code = value.charCodeAt(index);
18939
- if (code >= 55296 && code <= 56319) {
18940
- const next = value.charCodeAt(index + 1);
18941
- if (!(next >= 56320 && next <= 57343))
18942
- return false;
18943
- index++;
18944
- } else if (code >= 56320 && code <= 57343) {
18945
- return false;
18946
- }
18947
- }
18948
- return true;
18949
- }
18950
18929
  function record(value, location) {
18951
18930
  if (value === null || typeof value !== "object" || Array.isArray(value))
18952
18931
  fail2(`${location} must be an object`);
@@ -19091,14 +19070,11 @@ function compileWorkflowPlan(input, title, resolvedUnits = new Map) {
19091
19070
  }
19092
19071
  function sortedOutputs(outputs) {
19093
19072
  const sorted = {};
19094
- for (const name of Object.keys(outputs).sort(compareCodePoints2)) {
19073
+ for (const name of Object.keys(outputs).sort(compareCodePoints)) {
19095
19074
  sorted[name] = outputs[name];
19096
19075
  }
19097
19076
  return sorted;
19098
19077
  }
19099
- function compareCodePoints2(left, right) {
19100
- return left < right ? -1 : left > right ? 1 : 0;
19101
- }
19102
19078
  function compileStep(step, sequenceIndex, defaults, resolved) {
19103
19079
  const gate = {
19104
19080
  kind: "gate",
@@ -19225,12 +19201,6 @@ function collectWorkflowWarnings(input) {
19225
19201
  message: `Step "${step.id}" declares \`gate.max_loops: ${maxLoops}\` on an \`exec\` step — 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.`
19226
19202
  });
19227
19203
  }
19228
- if ((step.map || step.route === undefined) && step.output === undefined) {
19229
- warnings.push({
19230
- line: step.source.start,
19231
- message: `Step "${step.id}" declares no \`output:\` schema — its unit results are carried as an untyped ` + `artifact (permitted). Add an \`output:\` JSON Schema to type and validate the step artifact.`
19232
- });
19233
- }
19234
19204
  if (declaredParams) {
19235
19205
  const declaredList = [...declaredParams].join(", ");
19236
19206
  const scan = (text, label) => {
@@ -19444,7 +19414,7 @@ function parseWorkflow(markdown, source) {
19444
19414
  };
19445
19415
  if (root === null || root === undefined)
19446
19416
  root = {};
19447
- if (!isPlainRecord(root)) {
19417
+ if (!isRecord(root)) {
19448
19418
  return {
19449
19419
  ok: false,
19450
19420
  errors: [{ line: 2, message: `Workflow frontmatter must be a YAML mapping (key: value pairs).` }]
@@ -19625,7 +19595,7 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
19625
19595
  checkActorStamp(ctx, root.verified, ["verified"], `"verified"`);
19626
19596
  }
19627
19597
  }
19628
- if (root.provenance !== undefined && !isPlainRecord(root.provenance)) {
19598
+ if (root.provenance !== undefined && !isRecord(root.provenance)) {
19629
19599
  ctx.err(["provenance"], `Workflow frontmatter "provenance" must be a mapping.`);
19630
19600
  }
19631
19601
  if (root.status !== undefined && (typeof root.status !== "string" || !LIFECYCLE_STATUSES.has(root.status))) {
@@ -19638,7 +19608,7 @@ function checkEnvelopeFields(ctx, root, fmEndLine) {
19638
19608
  function checkActorStamp(ctx, value, path13, label) {
19639
19609
  if (value === undefined)
19640
19610
  return;
19641
- if (!isPlainRecord(value)) {
19611
+ if (!isRecord(value)) {
19642
19612
  ctx.err(path13, `Workflow frontmatter ${label} must be a mapping with a non-empty "by".`);
19643
19613
  return;
19644
19614
  }
@@ -19669,7 +19639,7 @@ function checkXrefs2(ctx, value, fmEndLine) {
19669
19639
  function parseParams(ctx, raw) {
19670
19640
  if (raw === undefined)
19671
19641
  return;
19672
- if (!isPlainRecord(raw)) {
19642
+ if (!isRecord(raw)) {
19673
19643
  ctx.err(["params"], `"params" must be a mapping of param name to a JSON Schema object (e.g. changed_files: { type: array }).`);
19674
19644
  return;
19675
19645
  }
@@ -19679,7 +19649,7 @@ function parseParams(ctx, raw) {
19679
19649
  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.`);
19680
19650
  continue;
19681
19651
  }
19682
- if (!isPlainRecord(value)) {
19652
+ if (!isRecord(value)) {
19683
19653
  ctx.err(["params", paramName], `Param "${paramName}" must be a JSON Schema object (e.g. { type: string }).`);
19684
19654
  continue;
19685
19655
  }
@@ -19694,7 +19664,7 @@ function parseParams(ctx, raw) {
19694
19664
  function parseOutputs(ctx, raw) {
19695
19665
  if (raw === undefined)
19696
19666
  return;
19697
- if (!isPlainRecord(raw)) {
19667
+ if (!isRecord(raw)) {
19698
19668
  ctx.err(["outputs"], `"outputs" must be a mapping of output name to { from, schema? } (e.g. report: { from: steps.summarize.output }).`);
19699
19669
  return;
19700
19670
  }
@@ -19705,7 +19675,7 @@ function parseOutputs(ctx, raw) {
19705
19675
  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.`);
19706
19676
  continue;
19707
19677
  }
19708
- if (!isPlainRecord(value)) {
19678
+ if (!isRecord(value)) {
19709
19679
  ctx.err(path13, `Output "${outputName}" must be a mapping with "from" (and optional "schema").`);
19710
19680
  continue;
19711
19681
  }
@@ -19725,7 +19695,7 @@ function parseOutputs(ctx, raw) {
19725
19695
  }
19726
19696
  const entry = { from: value.from };
19727
19697
  if (value.schema !== undefined) {
19728
- if (!isPlainRecord(value.schema)) {
19698
+ if (!isRecord(value.schema)) {
19729
19699
  ctx.err([...path13, "schema"], `Output "${outputName}" "schema" must be a JSON Schema object.`);
19730
19700
  } else {
19731
19701
  if (jsonBytes(value.schema) > WORKFLOW_MAX_SCHEMA_BYTES) {
@@ -19743,7 +19713,7 @@ function parseDefaults(ctx, raw) {
19743
19713
  if (raw === undefined)
19744
19714
  return;
19745
19715
  const path13 = ["defaults"];
19746
- if (!isPlainRecord(raw)) {
19716
+ if (!isRecord(raw)) {
19747
19717
  ctx.err(path13, `"defaults" must be a mapping with any of: ${DEFAULTS_KEYS.join(", ")}.`);
19748
19718
  return;
19749
19719
  }
@@ -19775,7 +19745,7 @@ function parseBudget(ctx, raw) {
19775
19745
  if (raw === undefined)
19776
19746
  return;
19777
19747
  const path13 = ["budget"];
19778
- if (!isPlainRecord(raw)) {
19748
+ if (!isRecord(raw)) {
19779
19749
  ctx.err(path13, `"budget" must be a mapping with any of: ${BUDGET_KEYS.join(", ")}.`);
19780
19750
  return;
19781
19751
  }
@@ -19804,7 +19774,7 @@ function parseSteps(ctx, raw) {
19804
19774
  }
19805
19775
  const idIndex = new Map;
19806
19776
  raw.forEach((rawStep, index) => {
19807
- if (isPlainRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
19777
+ if (isRecord(rawStep) && typeof rawStep.id === "string" && !idIndex.has(rawStep.id)) {
19808
19778
  idIndex.set(rawStep.id, index);
19809
19779
  }
19810
19780
  });
@@ -19813,7 +19783,7 @@ function parseSteps(ctx, raw) {
19813
19783
  const routeChecks = [];
19814
19784
  raw.forEach((rawStep, index) => {
19815
19785
  const path13 = ["steps", index];
19816
- if (!isPlainRecord(rawStep)) {
19786
+ if (!isRecord(rawStep)) {
19817
19787
  ctx.err(path13, `Step ${index + 1} must be a mapping with an "id".`);
19818
19788
  return;
19819
19789
  }
@@ -19887,7 +19857,7 @@ function parseSteps(ctx, raw) {
19887
19857
  return steps;
19888
19858
  }
19889
19859
  function parseUnit(ctx, raw, path13, stepLabel) {
19890
- if (!isPlainRecord(raw)) {
19860
+ if (!isRecord(raw)) {
19891
19861
  ctx.err(path13, `${stepLabel} "unit" must be a mapping (a dispatch-override bag).`);
19892
19862
  return;
19893
19863
  }
@@ -19948,7 +19918,7 @@ function parseUnit(ctx, raw, path13, stepLabel) {
19948
19918
  return unit;
19949
19919
  }
19950
19920
  function parseExec(ctx, raw, path13, stepLabel) {
19951
- if (!isPlainRecord(raw)) {
19921
+ if (!isRecord(raw)) {
19952
19922
  ctx.err(path13, `${stepLabel} "exec" must be a mapping with a "command" argv list.`);
19953
19923
  return;
19954
19924
  }
@@ -20032,7 +20002,7 @@ function parseExecCwd(ctx, raw, path13, stepLabel) {
20032
20002
  return value;
20033
20003
  }
20034
20004
  function parseMap(ctx, raw, path13, stepLabel) {
20035
- if (!isPlainRecord(raw)) {
20005
+ if (!isRecord(raw)) {
20036
20006
  ctx.err(path13, `${stepLabel} "map" must be a mapping with an "over" key.`);
20037
20007
  return;
20038
20008
  }
@@ -20064,7 +20034,7 @@ function parseMap(ctx, raw, path13, stepLabel) {
20064
20034
  return map;
20065
20035
  }
20066
20036
  function parseRoute(ctx, raw, path13, stepLabel, stepIndex, routeChecks) {
20067
- if (!isPlainRecord(raw)) {
20037
+ if (!isRecord(raw)) {
20068
20038
  ctx.err(path13, `${stepLabel} "route" must be a mapping with "input" and "when" keys.`);
20069
20039
  return;
20070
20040
  }
@@ -20084,7 +20054,7 @@ function parseRoute(ctx, raw, path13, stepLabel, stepIndex, routeChecks) {
20084
20054
  const seenMatches = new Map;
20085
20055
  raw.when.forEach((branch, i) => {
20086
20056
  const branchPath = [...whenPath, i];
20087
- if (!isPlainRecord(branch)) {
20057
+ if (!isRecord(branch)) {
20088
20058
  ctx.err(branchPath, `${stepLabel} "when[${i}]" must be a mapping: { match, step }.`);
20089
20059
  return;
20090
20060
  }
@@ -20155,7 +20125,7 @@ function parseInputs(ctx, raw, path13, stepLabel) {
20155
20125
  return out.length > 0 ? out : undefined;
20156
20126
  }
20157
20127
  function parseGate(ctx, raw, path13, stepLabel) {
20158
- if (!isPlainRecord(raw)) {
20128
+ if (!isRecord(raw)) {
20159
20129
  ctx.err(path13, `${stepLabel} "gate" must be a mapping with any of: ${GATE_KEYS.join(", ")}.`);
20160
20130
  return;
20161
20131
  }
@@ -20185,7 +20155,7 @@ function parseEngineName(ctx, raw, path13, label) {
20185
20155
  function parseRetry(ctx, raw, path13, stepLabel) {
20186
20156
  if (raw === undefined)
20187
20157
  return;
20188
- if (!isPlainRecord(raw)) {
20158
+ if (!isRecord(raw)) {
20189
20159
  ctx.err(path13, `${stepLabel} "retry" must be a mapping: { max: <n>, on: [<failure_reason>, …] }.`);
20190
20160
  return;
20191
20161
  }
@@ -20258,7 +20228,7 @@ function parseEnumField(ctx, raw, path13, label, allowed) {
20258
20228
  function parseLlmOverrides(ctx, raw, path13, label) {
20259
20229
  if (raw === undefined)
20260
20230
  return;
20261
- if (!isPlainRecord(raw)) {
20231
+ if (!isRecord(raw)) {
20262
20232
  ctx.err(path13, `${label} must be a mapping of LLM invocation overrides.`);
20263
20233
  return;
20264
20234
  }
@@ -20292,7 +20262,7 @@ function parseLlmOverrides(ctx, raw, path13, label) {
20292
20262
  ctx.err([...path13, "supports_json_schema"], `${label}.supports_json_schema must be a boolean.`);
20293
20263
  }
20294
20264
  if (raw.extra_params !== undefined) {
20295
- if (!isPlainRecord(raw.extra_params)) {
20265
+ if (!isRecord(raw.extra_params)) {
20296
20266
  ctx.err([...path13, "extra_params"], `${label}.extra_params must be a JSON object.`);
20297
20267
  } else {
20298
20268
  const issues = validateExtraParams(raw.extra_params);
@@ -20330,7 +20300,7 @@ function parseLlmOverrides(ctx, raw, path13, label) {
20330
20300
  function parseSchemaObject(ctx, raw, path13, label) {
20331
20301
  if (raw === undefined)
20332
20302
  return;
20333
- if (!isPlainRecord(raw)) {
20303
+ if (!isRecord(raw)) {
20334
20304
  ctx.err(path13, `${label} must be a JSON Schema object (e.g. { type: object, properties: { … } }).`);
20335
20305
  return;
20336
20306
  }
@@ -20362,9 +20332,6 @@ function checkUnknownKeys(ctx, obj, path13, allowed, label) {
20362
20332
  }
20363
20333
  }
20364
20334
  }
20365
- function isPlainRecord(value) {
20366
- return typeof value === "object" && value !== null && !Array.isArray(value);
20367
- }
20368
20335
  function describeError(cause) {
20369
20336
  return cause instanceof Error ? cause.message : String(cause);
20370
20337
  }
@@ -21245,22 +21212,6 @@ function nameOrTypeDiagnostics(relPath, data, frontmatter, allowedTypes) {
21245
21212
  }
21246
21213
  return [];
21247
21214
  }
21248
- var ASSIGN_RE2 = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
21249
- function scanKeys(text) {
21250
- const keys2 = [];
21251
- const seen = new Set;
21252
- for (const line of text.split(/\r?\n/)) {
21253
- const m = line.match(ASSIGN_RE2);
21254
- if (!m)
21255
- continue;
21256
- const key = m[1];
21257
- if (seen.has(key))
21258
- continue;
21259
- seen.add(key);
21260
- keys2.push(key);
21261
- }
21262
- return keys2;
21263
- }
21264
21215
  function collectSuppressedKeys(raw) {
21265
21216
  const suppressed = new Set;
21266
21217
  const lines = raw.split(/\r?\n/);
@@ -21284,7 +21235,7 @@ function dangerousEnvKeyDiagnostics(type, relPath, raw) {
21284
21235
  if (!baseNameWithExt.endsWith(".env"))
21285
21236
  return [];
21286
21237
  const ref = conceptIdForStashFile(type, ".", relPath);
21287
- const keys2 = scanKeys(raw);
21238
+ const keys2 = scanEnvKeyNames(raw);
21288
21239
  const suppressed = collectSuppressedKeys(raw);
21289
21240
  const diagnostics = [];
21290
21241
  for (const key of keys2) {
@@ -21734,7 +21685,6 @@ function applyFoldedMetadata(entry, folded) {
21734
21685
  }
21735
21686
 
21736
21687
  // src/core/adapter/adapters/akm-adapter.ts
21737
- var RESERVED_FILES = new Set(["index.md", "log.md"]);
21738
21688
  function isReservedFileName(name) {
21739
21689
  return RESERVED_FILES.has(name.toLowerCase());
21740
21690
  }
@@ -22070,14 +22020,10 @@ import fs9 from "node:fs";
22070
22020
  import path16 from "node:path";
22071
22021
  var COMPONENT_ID2 = "main";
22072
22022
  var TASK_EXT = TASK_EXTENSION;
22073
- var MAX_CONTENT_CHARS2 = 1e5;
22074
- function toPosix3(p) {
22075
- return p.replace(/\\/g, "/");
22076
- }
22077
22023
  function recognize3(c, file) {
22078
22024
  if (file.ext !== TASK_EXT)
22079
22025
  return null;
22080
- const conceptId = toPosix3(file.relPath).replace(/\.yml$/i, "");
22026
+ const conceptId = toPosix(file.relPath).replace(/\.yml$/i, "");
22081
22027
  const name = conceptId.split("/").pop() ?? conceptId;
22082
22028
  const raw = file.content();
22083
22029
  return {
@@ -22090,7 +22036,7 @@ function recognize3(c, file) {
22090
22036
  adapterId: "akm-task",
22091
22037
  type: "task",
22092
22038
  name,
22093
- content: raw.length > MAX_CONTENT_CHARS2 ? raw.slice(0, MAX_CONTENT_CHARS2) : raw
22039
+ content: raw
22094
22040
  };
22095
22041
  }
22096
22042
  async function validate3(c, changes, ctx) {
@@ -22104,7 +22050,7 @@ async function validate3(c, changes, ctx) {
22104
22050
  const ext = path16.extname(change.path).toLowerCase();
22105
22051
  if (ext !== TASK_EXT && ext !== TASK_NEAR_MISS_EXTENSION)
22106
22052
  continue;
22107
- const relPath = toPosix3(change.path);
22053
+ const relPath = toPosix(change.path);
22108
22054
  if (ext === TASK_NEAR_MISS_EXTENSION) {
22109
22055
  diagnostics.push({
22110
22056
  file: relPath,
@@ -22134,14 +22080,14 @@ var akmTaskAdapter = {
22134
22080
  recognize: recognize3,
22135
22081
  validate: validate3,
22136
22082
  readCandidates(c, conceptId) {
22137
- const posix = toPosix3(conceptId).replace(/\.ya?ml$/i, "");
22083
+ const posix = toPosix(conceptId).replace(/\.ya?ml$/i, "");
22138
22084
  return [
22139
22085
  { path: path16.join(c.root, `${posix}.yml`), conceptId: posix },
22140
22086
  { path: path16.join(c.root, `${posix}.yaml`), conceptId: posix }
22141
22087
  ];
22142
22088
  },
22143
22089
  placeNew(c, conceptId) {
22144
- const posix = toPosix3(conceptId);
22090
+ const posix = toPosix(conceptId);
22145
22091
  return path16.join(c.root, /\.yml$/i.test(posix) ? posix : `${posix}.yml`);
22146
22092
  },
22147
22093
  directoryList() {
@@ -22177,12 +22123,8 @@ import fs10 from "node:fs";
22177
22123
  import path17 from "node:path";
22178
22124
  var COMPONENT_ID3 = "main";
22179
22125
  var WORKFLOW_EXTS = new Set([".md", ".yml"]);
22180
- var MAX_CONTENT_CHARS3 = 1e5;
22181
- function toPosix4(p) {
22182
- return p.replace(/\\/g, "/");
22183
- }
22184
22126
  function conceptIdOf(relPath) {
22185
- return toPosix4(relPath).replace(/\.(?:md|yml)$/i, "");
22127
+ return toPosix(relPath).replace(/\.(?:md|yml)$/i, "");
22186
22128
  }
22187
22129
  function isReservedDocFile(fileName) {
22188
22130
  return fileName.toLowerCase() === "readme.md";
@@ -22216,7 +22158,7 @@ function recognize4(c, file) {
22216
22158
  adapterId: "akm-workflow",
22217
22159
  type: "workflow",
22218
22160
  name,
22219
- content: body.length > MAX_CONTENT_CHARS3 ? body.slice(0, MAX_CONTENT_CHARS3) : body
22161
+ content: body
22220
22162
  };
22221
22163
  if (description !== undefined)
22222
22164
  doc.description = description;
@@ -22235,7 +22177,7 @@ async function validate4(c, changes, ctx) {
22235
22177
  const ext = path17.extname(change.path).toLowerCase();
22236
22178
  if (!WORKFLOW_EXTS.has(ext) || isReservedDocFile(path17.basename(change.path)))
22237
22179
  continue;
22238
- const relPath = toPosix4(change.path);
22180
+ const relPath = toPosix(change.path);
22239
22181
  if (ext === ".yml") {
22240
22182
  diagnostics.push(...workflowYamlSourceDiagnostics(relPath, raw, relPath, c.root).errors);
22241
22183
  continue;
@@ -22285,7 +22227,7 @@ var akmWorkflowAdapter = {
22285
22227
  recognize: recognize4,
22286
22228
  validate: validate4,
22287
22229
  readCandidates(c, conceptId) {
22288
- const posix = toPosix4(conceptId);
22230
+ const posix = toPosix(conceptId);
22289
22231
  const canonical = posix.replace(/\.(?:md|yml)$/i, "");
22290
22232
  return /\.(?:md|yml)$/i.test(posix) ? [{ path: path17.join(c.root, posix), conceptId: canonical }] : [
22291
22233
  { path: path17.join(c.root, `${posix}.md`), conceptId: canonical },
@@ -22293,7 +22235,7 @@ var akmWorkflowAdapter = {
22293
22235
  ];
22294
22236
  },
22295
22237
  placeNew(c, conceptId) {
22296
- const posix = toPosix4(conceptId);
22238
+ const posix = toPosix(conceptId);
22297
22239
  if (/\.(?:md|yml)$/i.test(posix))
22298
22240
  return path17.join(c.root, posix);
22299
22241
  return path17.join(c.root, `${posix}.md`);
@@ -22318,20 +22260,15 @@ import path19 from "node:path";
22318
22260
 
22319
22261
  // src/core/adapter/adapters/tool-dir-shared.ts
22320
22262
  import path18 from "node:path";
22321
- var RESERVED_FILES2 = new Set(["index.md", "log.md"]);
22322
- var MAX_CONTENT_CHARS4 = 1e5;
22323
22263
  var CANONICAL_COMMAND_DIR = "commands";
22324
22264
  var CANONICAL_AGENT_DIR = "agents";
22325
22265
  var CANONICAL_SKILL_DIR = "skills";
22326
22266
  var SKILL_MANIFEST2 = "SKILL.md";
22327
- function toPosix5(p) {
22328
- return p.replace(/\\/g, "/");
22329
- }
22330
22267
  function isReserved(base3) {
22331
- return RESERVED_FILES2.has(base3.toLowerCase());
22268
+ return RESERVED_FILES.has(base3.toLowerCase());
22332
22269
  }
22333
22270
  function classify(relPath, layout) {
22334
- const posix = toPosix5(relPath);
22271
+ const posix = toPosix(relPath);
22335
22272
  const segs = posix.split("/").filter((s) => s.length > 0);
22336
22273
  if (segs.length === 0)
22337
22274
  return null;
@@ -22378,7 +22315,7 @@ function recognizeToolDir(layout, c, file) {
22378
22315
  adapterId: layout.adapterId,
22379
22316
  type: cls.type,
22380
22317
  name,
22381
- content: body.length > MAX_CONTENT_CHARS4 ? body.slice(0, MAX_CONTENT_CHARS4) : body
22318
+ content: body
22382
22319
  };
22383
22320
  if (cls.type === "instruction")
22384
22321
  doc.ownsPresentation = true;
@@ -22389,7 +22326,7 @@ function recognizeToolDir(layout, c, file) {
22389
22326
  return doc;
22390
22327
  }
22391
22328
  function placeNewToolDir(layout, c, conceptId) {
22392
- const posix = toPosix5(conceptId);
22329
+ const posix = toPosix(conceptId);
22393
22330
  if (posix === layout.instructionConceptId)
22394
22331
  return path18.join(c.root, layout.instructionFile);
22395
22332
  const segs = posix.split("/").filter((s) => s.length > 0);
@@ -22406,7 +22343,7 @@ function placeNewToolDir(layout, c, conceptId) {
22406
22343
  return path18.join(c.root, `${posix}.md`);
22407
22344
  }
22408
22345
  function readCandidatesToolDir(layout, c, conceptId) {
22409
- const posix = toPosix5(conceptId);
22346
+ const posix = toPosix(conceptId);
22410
22347
  if (posix === layout.instructionConceptId) {
22411
22348
  return [{ path: path18.join(c.root, layout.instructionFile), conceptId: posix }];
22412
22349
  }
@@ -22447,7 +22384,7 @@ async function validateToolDir(layout, c, changes, ctx) {
22447
22384
  const raw = change.after ?? await ctx.readFile(change.path);
22448
22385
  if (typeof raw !== "string")
22449
22386
  continue;
22450
- const relPath = toPosix5(change.path);
22387
+ const relPath = toPosix(change.path);
22451
22388
  diagnostics.push(...await skillDirectoryDiagnostics(relPath, seenSkillDirs, ctx, layout.skillDirs));
22452
22389
  const cls = classify(change.path, layout);
22453
22390
  if (cls === null)
@@ -22547,12 +22484,8 @@ var COMPONENT_ID4 = "main";
22547
22484
  var ENV_DIR = "env";
22548
22485
  var SECRETS_DIR = "secrets";
22549
22486
  var SECRET_SKIP_SUFFIXES = [".lock", ".sensitive"];
22550
- var ASSIGN_RE3 = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
22551
- function toPosix6(p) {
22552
- return p.replace(/\\/g, "/");
22553
- }
22554
22487
  function classify2(relPath) {
22555
- const posix = toPosix6(relPath);
22488
+ const posix = toPosix(relPath);
22556
22489
  const segs = posix.split("/").filter((s) => s.length > 0);
22557
22490
  if (segs.length < 2)
22558
22491
  return null;
@@ -22570,23 +22503,8 @@ function hasSensitiveMarker(absPath, type) {
22570
22503
  const marker = type === "env" ? absPath.replace(/\.env$/i, ".sensitive") : `${absPath}.sensitive`;
22571
22504
  return marker !== absPath && fs12.existsSync(marker);
22572
22505
  }
22573
- function scanKeyNames(raw) {
22574
- const keys2 = [];
22575
- const seen = new Set;
22576
- for (const line of raw.split(/\r?\n/)) {
22577
- const m = line.match(ASSIGN_RE3);
22578
- if (!m)
22579
- continue;
22580
- const key = m[1];
22581
- if (seen.has(key))
22582
- continue;
22583
- seen.add(key);
22584
- keys2.push(key);
22585
- }
22586
- return keys2;
22587
- }
22588
22506
  function conceptIdForPath(type, relativePath) {
22589
- const posix = toPosix6(relativePath);
22507
+ const posix = toPosix(relativePath);
22590
22508
  if (type === "secret")
22591
22509
  return posix;
22592
22510
  const stripped = posix.replace(/\.env$/i, "");
@@ -22598,12 +22516,12 @@ function recognize5(c, file) {
22598
22516
  return null;
22599
22517
  if (hasSensitiveMarker(file.absPath, type))
22600
22518
  return null;
22601
- const posix = toPosix6(file.relPath);
22519
+ const posix = toPosix(file.relPath);
22602
22520
  const raw = file.content();
22603
22521
  if (type === "env") {
22604
22522
  const conceptId = conceptIdForPath(type, posix);
22605
22523
  const name2 = (conceptId.split("/").pop() ?? conceptId) || "default";
22606
- const keys2 = scanKeyNames(raw);
22524
+ const keys2 = scanEnvKeyNames(raw);
22607
22525
  const doc = {
22608
22526
  ref: `${c.id}//${conceptId}`,
22609
22527
  bundle: c.id,
@@ -22643,7 +22561,7 @@ async function validate5(_c, changes, ctx) {
22643
22561
  const type = classify2(change.path);
22644
22562
  if (type === null)
22645
22563
  continue;
22646
- diagnostics.push(...dangerousEnvKeyDiagnostics(type, toPosix6(change.path), raw));
22564
+ diagnostics.push(...dangerousEnvKeyDiagnostics(type, toPosix(change.path), raw));
22647
22565
  }
22648
22566
  return diagnostics;
22649
22567
  }
@@ -22654,7 +22572,7 @@ var dotenvAdapter = {
22654
22572
  recognize: recognize5,
22655
22573
  validate: validate5,
22656
22574
  readCandidates(c, conceptId) {
22657
- const posix = toPosix6(conceptId);
22575
+ const posix = toPosix(conceptId);
22658
22576
  const slash = posix.indexOf("/");
22659
22577
  if (slash <= 0)
22660
22578
  return [];
@@ -22668,7 +22586,7 @@ var dotenvAdapter = {
22668
22586
  return expanded.map((candidatePath) => ({ path: candidatePath, conceptId: posix }));
22669
22587
  },
22670
22588
  placeNew(c, conceptId) {
22671
- const posix = toPosix6(conceptId);
22589
+ const posix = toPosix(conceptId);
22672
22590
  const slash = posix.indexOf("/");
22673
22591
  if (slash > 0) {
22674
22592
  const head = posix.slice(0, slash);
@@ -22703,13 +22621,8 @@ var dotenvAdapter = {
22703
22621
  import path21 from "node:path";
22704
22622
  var COMPONENT_ID5 = "main";
22705
22623
  var DOCUMENT_EXTENSIONS = new Set([".md", ".markdown", ".txt", ".text"]);
22706
- var RESERVED_FILES3 = new Set(["index.md", "log.md"]);
22707
- var MAX_CONTENT_CHARS5 = 1e5;
22708
- function toPosix7(p) {
22709
- return p.replace(/\\/g, "/");
22710
- }
22711
22624
  function isReserved2(base3) {
22712
- return RESERVED_FILES3.has(base3.toLowerCase());
22625
+ return RESERVED_FILES.has(base3.toLowerCase());
22713
22626
  }
22714
22627
  function classify3(ext) {
22715
22628
  if (SCRIPT_EXTENSIONS.has(ext))
@@ -22719,7 +22632,7 @@ function classify3(ext) {
22719
22632
  return "file";
22720
22633
  }
22721
22634
  function recognize6(c, file) {
22722
- const posix = toPosix7(file.relPath);
22635
+ const posix = toPosix(file.relPath);
22723
22636
  const base3 = posix.split("/").pop() ?? posix;
22724
22637
  if (isReserved2(base3))
22725
22638
  return null;
@@ -22739,7 +22652,7 @@ function recognize6(c, file) {
22739
22652
  adapterId: "generic-files",
22740
22653
  type,
22741
22654
  name,
22742
- content: body.length > MAX_CONTENT_CHARS5 ? body.slice(0, MAX_CONTENT_CHARS5) : body
22655
+ content: body
22743
22656
  };
22744
22657
  if (type !== "script")
22745
22658
  doc.ownsPresentation = true;
@@ -22759,7 +22672,7 @@ async function validate6(c, changes, ctx) {
22759
22672
  const raw = change.after ?? await ctx.readFile(change.path);
22760
22673
  if (typeof raw !== "string")
22761
22674
  continue;
22762
- diagnostics.push(...await runBaseValidateChecks(toPosix7(change.path), parseFrontmatter(raw), c.root, ctx));
22675
+ diagnostics.push(...await runBaseValidateChecks(toPosix(change.path), parseFrontmatter(raw), c.root, ctx));
22763
22676
  }
22764
22677
  return diagnostics;
22765
22678
  }
@@ -22770,7 +22683,7 @@ var genericFilesAdapter = {
22770
22683
  recognize: recognize6,
22771
22684
  validate: validate6,
22772
22685
  readCandidates(c, conceptId) {
22773
- const posix = toPosix7(conceptId);
22686
+ const posix = toPosix(conceptId);
22774
22687
  const extension = path21.extname(posix).toLowerCase();
22775
22688
  const documentCandidates = [...DOCUMENT_EXTENSIONS].map((candidateExtension) => ({
22776
22689
  path: path21.join(c.root, `${posix}${candidateExtension}`),
@@ -22779,7 +22692,7 @@ var genericFilesAdapter = {
22779
22692
  return DOCUMENT_EXTENSIONS.has(extension) ? documentCandidates : [{ path: path21.join(c.root, posix), conceptId: posix }, ...documentCandidates];
22780
22693
  },
22781
22694
  placeNew(c, conceptId) {
22782
- const posix = toPosix7(conceptId);
22695
+ const posix = toPosix(conceptId);
22783
22696
  const hasExt = path21.extname(posix) !== "";
22784
22697
  return path21.join(c.root, hasExt ? posix : `${posix}.md`);
22785
22698
  },
@@ -22797,12 +22710,8 @@ var DEFAULT_PAGE_KIND = "note";
22797
22710
  var RESERVED_ROOT_FILES = new Set(["schema.md", "index.md", "log.md"]);
22798
22711
  var RAW_SUBDIR = "raw";
22799
22712
  var PAGES_SUBDIR = "pages";
22800
- var MAX_CONTENT_CHARS6 = 1e5;
22801
- function toPosix8(p) {
22802
- return p.replace(/\\/g, "/");
22803
- }
22804
22713
  function conceptIdOf2(relPath) {
22805
- return toPosix8(relPath).replace(/\.md$/i, "");
22714
+ return toPosix(relPath).replace(/\.md$/i, "");
22806
22715
  }
22807
22716
  function parseWikiFrontmatter(raw) {
22808
22717
  const out = { xrefs: [], sources: [] };
@@ -22834,13 +22743,13 @@ function parseWikiFrontmatter(raw) {
22834
22743
  return out;
22835
22744
  }
22836
22745
  function isReservedRootFile(relPath) {
22837
- const posix = toPosix8(relPath);
22746
+ const posix = toPosix(relPath);
22838
22747
  if (posix.includes("/"))
22839
22748
  return false;
22840
22749
  return RESERVED_ROOT_FILES.has(posix.toLowerCase());
22841
22750
  }
22842
22751
  function firstSegment(relPath) {
22843
- const posix = toPosix8(relPath);
22752
+ const posix = toPosix(relPath);
22844
22753
  const slash = posix.indexOf("/");
22845
22754
  return slash < 0 ? posix : posix.slice(0, slash);
22846
22755
  }
@@ -22852,7 +22761,7 @@ function resolveXref(xref, bundleId) {
22852
22761
  return target.length > 0 ? target : null;
22853
22762
  }
22854
22763
  function resolveBodyLinks(body, fileRelPath) {
22855
- const dir = path22.posix.dirname(toPosix8(fileRelPath));
22764
+ const dir = path22.posix.dirname(toPosix(fileRelPath));
22856
22765
  const linkRe = /\[[^\]]*\]\(([^)]+)\)/g;
22857
22766
  const out = [];
22858
22767
  const seen = new Set;
@@ -22929,7 +22838,7 @@ function resolveSources(fm) {
22929
22838
  function recognize7(c, file) {
22930
22839
  if (file.ext !== ".md")
22931
22840
  return null;
22932
- const relPath = toPosix8(file.relPath);
22841
+ const relPath = toPosix(file.relPath);
22933
22842
  if (isReservedRootFile(relPath))
22934
22843
  return null;
22935
22844
  const head = firstSegment(relPath);
@@ -22953,7 +22862,7 @@ function recognize7(c, file) {
22953
22862
  ownsPresentation: true,
22954
22863
  type: isRaw ? WIKI_SOURCE_TYPE : fm.pageKind ?? DEFAULT_PAGE_KIND,
22955
22864
  name: lastSegment,
22956
- content: body.length > MAX_CONTENT_CHARS6 ? body.slice(0, MAX_CONTENT_CHARS6) : body
22865
+ content: body
22957
22866
  };
22958
22867
  if (fm.description !== undefined)
22959
22868
  doc.description = fm.description;
@@ -22979,7 +22888,7 @@ async function validate7(c, changes, ctx) {
22979
22888
  const raw = change.after ?? await ctx.readFile(change.path);
22980
22889
  if (typeof raw !== "string")
22981
22890
  continue;
22982
- const relPath = toPosix8(change.path);
22891
+ const relPath = toPosix(change.path);
22983
22892
  if (isReservedRootFile(relPath))
22984
22893
  continue;
22985
22894
  const head = firstSegment(relPath);
@@ -23062,7 +22971,7 @@ var llmWikiAdapter = {
23062
22971
  recognize: recognize7,
23063
22972
  validate: validate7,
23064
22973
  readCandidates(c, conceptId) {
23065
- const canonical = toPosix8(conceptId).replace(/\.md$/i, "");
22974
+ const canonical = toPosix(conceptId).replace(/\.md$/i, "");
23066
22975
  return [{ path: path22.join(c.root, `${canonical}.md`), conceptId: canonical }];
23067
22976
  },
23068
22977
  placeNew(c, conceptId) {
@@ -23098,11 +23007,8 @@ var CONSUMED_FRONTMATTER_KEYS = [
23098
23007
  "stale_after",
23099
23008
  "okf_version"
23100
23009
  ];
23101
- function isPlainObject3(value) {
23102
- return value !== null && typeof value === "object" && !Array.isArray(value);
23103
- }
23104
23010
  function parseActorMapping(value) {
23105
- if (!isPlainObject3(value))
23011
+ if (!isRecord(value))
23106
23012
  return;
23107
23013
  const by = nonEmptyString(value.by);
23108
23014
  if (by === undefined)
@@ -23127,7 +23033,7 @@ function parseOkfSources(value) {
23127
23033
  return;
23128
23034
  const out = [];
23129
23035
  for (const item of value) {
23130
- if (!isPlainObject3(item))
23036
+ if (!isRecord(item))
23131
23037
  continue;
23132
23038
  const resource = nonEmptyString(item.resource);
23133
23039
  if (resource === undefined)
@@ -23155,16 +23061,11 @@ function parseOkfSources(value) {
23155
23061
  function parseLifecycleStatus(value) {
23156
23062
  return value === "draft" || value === "stable" || value === "deprecated" ? value : undefined;
23157
23063
  }
23158
- var RESERVED_FILES4 = new Set(["index.md", "log.md"]);
23159
- var MAX_CONTENT_CHARS7 = 1e5;
23160
- function toPosix9(p) {
23161
- return p.replace(/\\/g, "/");
23162
- }
23163
23064
  function isReservedFileName2(name) {
23164
- return RESERVED_FILES4.has(name.toLowerCase());
23065
+ return RESERVED_FILES.has(name.toLowerCase());
23165
23066
  }
23166
23067
  function resolveOkfLinks(body, fileRelPath) {
23167
- const dir = path23.posix.dirname(toPosix9(fileRelPath));
23068
+ const dir = path23.posix.dirname(toPosix(fileRelPath));
23168
23069
  const definitions = new Map;
23169
23070
  for (const match of body.matchAll(/^\s*\[([^\]]+)\]:\s*(\S+)/gm)) {
23170
23071
  definitions.set(match[1].trim().toLowerCase(), match[2]);
@@ -23222,7 +23123,7 @@ function recognize8(c, file) {
23222
23123
  return null;
23223
23124
  if (isReservedFileName2(file.fileName))
23224
23125
  return null;
23225
- const conceptId = toPosix9(file.relPath).replace(/\.md$/i, "");
23126
+ const conceptId = toPosix(file.relPath).replace(/\.md$/i, "");
23226
23127
  const raw = file.content();
23227
23128
  const parsed = parseFrontmatter(raw);
23228
23129
  const data = parsed.data;
@@ -23233,7 +23134,7 @@ function recognize8(c, file) {
23233
23134
  const description = nonEmptyString(data.description);
23234
23135
  const tags = readTags(data.tags);
23235
23136
  const links = resolveOkfLinks(body, file.relPath);
23236
- const generatedMapping = isPlainObject3(data.generated) ? data.generated : undefined;
23137
+ const generatedMapping = isRecord(data.generated) ? data.generated : undefined;
23237
23138
  const generatedAt = generatedMapping ? nonEmptyString(generatedMapping.at) : undefined;
23238
23139
  const generatedBy = generatedMapping ? nonEmptyString(generatedMapping.by) : undefined;
23239
23140
  const legacyTimestamp = nonEmptyString(data.timestamp);
@@ -23260,7 +23161,7 @@ function recognize8(c, file) {
23260
23161
  ownsPresentation: true,
23261
23162
  type,
23262
23163
  name,
23263
- content: body.length > MAX_CONTENT_CHARS7 ? body.slice(0, MAX_CONTENT_CHARS7) : body
23164
+ content: body
23264
23165
  };
23265
23166
  if (description !== undefined)
23266
23167
  doc.description = description;
@@ -23291,7 +23192,7 @@ async function validate8(c, changes, ctx) {
23291
23192
  const raw = change.after ?? await ctx.readFile(change.path);
23292
23193
  if (typeof raw !== "string")
23293
23194
  continue;
23294
- const relPath = toPosix9(change.path);
23195
+ const relPath = toPosix(change.path);
23295
23196
  const fileName = relPath.split("/").pop() ?? relPath;
23296
23197
  const reserved = isReservedFileName2(fileName);
23297
23198
  const parsed = parseFrontmatter(raw);
@@ -23415,10 +23316,6 @@ var COMPONENT_ID6 = "main";
23415
23316
  var PAGES_PREFIX = "stash/knowledge/";
23416
23317
  var MANIFEST_FILE = "manifest.json";
23417
23318
  var WEBSITE_TAG = "website";
23418
- var MAX_CONTENT_CHARS8 = 1e5;
23419
- function toPosix10(p) {
23420
- return p.replace(/\\/g, "/");
23421
- }
23422
23319
  function parseSnapshotFrontmatter(raw) {
23423
23320
  const out = { tags: [] };
23424
23321
  const block = parseFrontmatterBlock(raw);
@@ -23441,14 +23338,14 @@ function parseSnapshotFrontmatter(raw) {
23441
23338
  return out;
23442
23339
  }
23443
23340
  function isSnapshotPage(relPath) {
23444
- const posix = toPosix10(relPath);
23341
+ const posix = toPosix(relPath);
23445
23342
  return posix.startsWith(PAGES_PREFIX) && posix.toLowerCase().endsWith(".md");
23446
23343
  }
23447
23344
  function isReTypeGated(fm) {
23448
23345
  return fm.sourceUrl !== undefined || fm.tags.includes(WEBSITE_TAG);
23449
23346
  }
23450
23347
  function conceptIdOf3(relPath) {
23451
- return toPosix10(relPath).slice(PAGES_PREFIX.length).replace(/\.md$/i, "");
23348
+ return toPosix(relPath).slice(PAGES_PREFIX.length).replace(/\.md$/i, "");
23452
23349
  }
23453
23350
  function recognize9(c, file) {
23454
23351
  if (file.ext !== ".md" || !isSnapshotPage(file.relPath))
@@ -23471,7 +23368,7 @@ function recognize9(c, file) {
23471
23368
  ownsPresentation: true,
23472
23369
  type: "website",
23473
23370
  name,
23474
- content: body.length > MAX_CONTENT_CHARS8 ? body.slice(0, MAX_CONTENT_CHARS8) : body
23371
+ content: body
23475
23372
  };
23476
23373
  if (fm.description !== undefined)
23477
23374
  doc.description = fm.description;
@@ -23489,7 +23386,7 @@ async function validate9(c, changes, ctx) {
23489
23386
  continue;
23490
23387
  if (!isSnapshotPage(change.path))
23491
23388
  continue;
23492
- const base3 = await runBaseValidateChecks(toPosix10(change.path), parseFrontmatter(raw), c.root, ctx);
23389
+ const base3 = await runBaseValidateChecks(toPosix(change.path), parseFrontmatter(raw), c.root, ctx);
23493
23390
  diagnostics.push(...base3.filter((d) => d.issue !== "missing-updated"));
23494
23391
  }
23495
23392
  return diagnostics;
@@ -23501,7 +23398,7 @@ var websiteSnapshotAdapter = {
23501
23398
  recognize: recognize9,
23502
23399
  validate: validate9,
23503
23400
  readCandidates(c, conceptId) {
23504
- const canonical = toPosix10(conceptId).replace(/\.md$/i, "");
23401
+ const canonical = toPosix(conceptId).replace(/\.md$/i, "");
23505
23402
  return [{ path: path25.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
23506
23403
  },
23507
23404
  looksLikeRoot(root) {
@@ -23978,6 +23875,27 @@ function describeJsonRoot(value) {
23978
23875
  return "a boolean";
23979
23876
  return typeof value;
23980
23877
  }
23878
+ function pruneToNewest(dir, keep, select) {
23879
+ let entries;
23880
+ try {
23881
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
23882
+ } catch {
23883
+ return;
23884
+ }
23885
+ const candidates = entries.filter(select).map((entry) => {
23886
+ const full = path27.join(dir, entry.name);
23887
+ let mtime = 0;
23888
+ try {
23889
+ mtime = fs18.statSync(full).mtimeMs;
23890
+ } catch {}
23891
+ return { path: full, mtime };
23892
+ }).sort((a, b) => b.mtime - a.mtime);
23893
+ for (const stale of candidates.slice(keep)) {
23894
+ try {
23895
+ fs18.rmSync(stale.path, { recursive: true, force: true });
23896
+ } catch {}
23897
+ }
23898
+ }
23981
23899
  function getConfigLockPath() {
23982
23900
  return path27.join(getConfigDir(), "config.json.lck");
23983
23901
  }
@@ -28891,7 +28809,7 @@ function upgradeConfigVersion(raw, sourcePath) {
28891
28809
 
28892
28810
  // src/core/config/deep-merge.ts
28893
28811
  var UNSAFE_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
28894
- function isPlainObject4(value) {
28812
+ function isPlainObject(value) {
28895
28813
  if (value === null || typeof value !== "object" || Array.isArray(value))
28896
28814
  return false;
28897
28815
  const prototype = Object.getPrototypeOf(value);
@@ -28900,7 +28818,7 @@ function isPlainObject4(value) {
28900
28818
  function copyConfigValue(value) {
28901
28819
  if (Array.isArray(value))
28902
28820
  return value.map(copyConfigValue);
28903
- if (!isPlainObject4(value))
28821
+ if (!isPlainObject(value))
28904
28822
  return value;
28905
28823
  const copy = {};
28906
28824
  for (const key of Object.keys(value)) {
@@ -28919,7 +28837,7 @@ function deepMergeConfig(base3, override) {
28919
28837
  if (next === undefined)
28920
28838
  continue;
28921
28839
  const current = result[key];
28922
- result[key] = isPlainObject4(current) && isPlainObject4(next) ? deepMergeConfig(current, next) : copyConfigValue(next);
28840
+ result[key] = isPlainObject(current) && isPlainObject(next) ? deepMergeConfig(current, next) : copyConfigValue(next);
28923
28841
  }
28924
28842
  return result;
28925
28843
  }
@@ -28980,8 +28898,8 @@ function loadUserConfig() {
28980
28898
  }
28981
28899
  function parseAndValidateConfigText(text, sourcePath) {
28982
28900
  const parsedRaw = upgradeConfigVersion(parseConfigText(text, sourcePath), sourcePath);
28983
- const { config: raw, lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
28984
28901
  const where = sourcePath ? ` at ${sourcePath}` : "";
28902
+ const { lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
28985
28903
  if (conflicts.length > 0) {
28986
28904
  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(`
28987
28905
  `);
@@ -28991,11 +28909,13 @@ ${lines}
28991
28909
  Each extraParams key above has a first-class equivalent and akm will not guess which value you meant — remove the extraParams entry once the field carries the value you want.`, "INVALID_CONFIG_FILE");
28992
28910
  }
28993
28911
  if (lifted.length > 0) {
28994
- 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):
28912
+ throw new ConfigError(`Config${where} uses deprecated extraParams keys with first-class equivalents:
28995
28913
  - ${lifted.join(`
28996
- - `)}`);
28914
+ - `)}
28915
+
28916
+ Run \`akm migrate apply\` to rewrite the config file, or move the values onto the first-class fields yourself.`, "INVALID_CONFIG_FILE");
28997
28917
  }
28998
- const parsed = AkmConfigSchema.safeParse(raw);
28918
+ const parsed = AkmConfigSchema.safeParse(parsedRaw);
28999
28919
  if (!parsed.success) {
29000
28920
  const lines = parsed.error.issues.map((i) => ` - ${i.path.join(".") || "(root)"}: ${i.message}`).join(`
29001
28921
  `);
@@ -29290,6 +29210,9 @@ function createProviderRegistry() {
29290
29210
  resolve(type) {
29291
29211
  return map.get(type) ?? null;
29292
29212
  },
29213
+ unregister(type) {
29214
+ map.delete(type);
29215
+ },
29293
29216
  list() {
29294
29217
  return [...map.keys()];
29295
29218
  }
@@ -29946,6 +29869,10 @@ function inspectCurrentTaskPlan() {
29946
29869
  function inspectMigrationPlan() {
29947
29870
  return inspectCurrentTaskPlan().result;
29948
29871
  }
29872
+ var MAX_TASK_MIGRATION_BACKUPS = 5;
29873
+ function pruneTaskMigrationBackups(generationBackupDir) {
29874
+ pruneToNewest(generationBackupDir, MAX_TASK_MIGRATION_BACKUPS, (entry) => entry.isDirectory());
29875
+ }
29949
29876
  function printPlan(plan) {
29950
29877
  console.log(JSON.stringify(plan));
29951
29878
  if (plan.status === "blocked")
@@ -29963,12 +29890,14 @@ async function runMigrationApply(options = {}) {
29963
29890
  const before = inspectCurrentTaskPlan();
29964
29891
  if (before.result.taskV3Migration.changed === 0)
29965
29892
  return before.result;
29966
- const backupPath = path33.join(getDataDir(), "backups", "task-v3", `${Date.now()}-${randomUUID2()}`);
29893
+ const backupRoot = path33.join(getDataDir(), "backups", "task-v3");
29894
+ const backupPath = path33.join(backupRoot, `${Date.now()}-${randomUUID2()}`);
29967
29895
  const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
29968
29896
  const after = inspectCurrentTaskPlan().result;
29969
29897
  if (after.taskV3Migration.changed > 0) {
29970
29898
  throw new ConfigError("Task migration did not converge to task v3.", "INVALID_CONFIG_FILE");
29971
29899
  }
29900
+ pruneTaskMigrationBackups(backupRoot);
29972
29901
  return { ...after, backupPath, applied: applied.changed.length };
29973
29902
  }));
29974
29903
  printPlan(result);
@@ -30026,12 +29955,14 @@ async function runTaskV4MigrationApply(options = {}) {
30026
29955
  const before = inspectCurrentTaskV4Plan();
30027
29956
  if (before.result.taskV4Migration.changed === 0)
30028
29957
  return before.result;
30029
- const backupPath = path33.join(getDataDir(), "backups", "task-v4", `${Date.now()}-${randomUUID2()}`);
29958
+ const backupRoot = path33.join(getDataDir(), "backups", "task-v4");
29959
+ const backupPath = path33.join(backupRoot, `${Date.now()}-${randomUUID2()}`);
30030
29960
  const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
30031
29961
  const after = inspectCurrentTaskV4Plan().result;
30032
29962
  if (after.taskV4Migration.changed > 0) {
30033
29963
  throw new ConfigError("Task migration did not converge to task source v4.", "INVALID_CONFIG_FILE");
30034
29964
  }
29965
+ pruneTaskMigrationBackups(backupRoot);
30035
29966
  return { ...after, backupPath, applied: applied.changed.length };
30036
29967
  }));
30037
29968
  printPlan(result);