akm-cli 0.9.12 → 0.9.14-beta.1

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 (48) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/assets/workflows/workflow-template.md +4 -0
  3. package/dist/commands/improve/eligibility.js +27 -15
  4. package/dist/commands/improve/improve.js +1 -0
  5. package/dist/commands/lint/base-linter.js +10 -0
  6. package/dist/commands/proposal/drain.js +48 -6
  7. package/dist/commands/proposal/proposal-cli.js +1 -0
  8. package/dist/commands/read/curate.js +3 -2
  9. package/dist/commands/read/show.js +26 -9
  10. package/dist/core/adapter/adapters/akm-adapter.js +5 -1
  11. package/dist/core/asset/markdown-fragments.js +146 -0
  12. package/dist/core/config/config-walker.js +7 -3
  13. package/dist/core/config/config.js +21 -12
  14. package/dist/core/config/schema/primitives.js +8 -2
  15. package/dist/core/errors.js +2 -0
  16. package/dist/core/lexical-score.js +25 -0
  17. package/dist/core/type-presentation.js +36 -4
  18. package/dist/indexer/index-written-assets.js +4 -0
  19. package/dist/indexer/indexer.js +5 -2
  20. package/dist/indexer/passes/metadata.js +64 -1
  21. package/dist/indexer/scan/doc-to-entry.js +3 -0
  22. package/dist/indexer/scan/drain-dir.js +33 -22
  23. package/dist/indexer/search/db-search.js +72 -14
  24. package/dist/indexer/search/name-match.js +35 -0
  25. package/dist/indexer/search/ranking-contributors.js +15 -12
  26. package/dist/indexer/search/ranking.js +42 -18
  27. package/dist/indexer/usage/show-usage.js +14 -2
  28. package/dist/llm/client.js +12 -8
  29. package/dist/llm/embedders/remote.js +3 -2
  30. package/dist/llm/graph-extract.js +18 -67
  31. package/dist/output/shapes.js +46 -1
  32. package/dist/output/text/proposal-format.js +5 -0
  33. package/dist/scripts/akm-migrate-node.js +648 -253
  34. package/dist/scripts/akm-migrate.js +648 -253
  35. package/dist/storage/repositories/index-connection.js +23 -8
  36. package/dist/storage/repositories/index-entries-repository.js +3 -2
  37. package/dist/storage/repositories/index-entry-schema.js +43 -3
  38. package/dist/storage/repositories/index-fts-repository.js +160 -14
  39. package/dist/storage/repositories/index-schema.js +8 -18
  40. package/dist/storage/repositories/workflow-runs-repository.js +118 -10
  41. package/dist/workflows/exec/run-workflow.js +1 -1
  42. package/dist/workflows/exec/step-work.js +41 -0
  43. package/dist/workflows/parser.js +1 -1
  44. package/dist/workflows/runtime/runs.js +29 -5
  45. package/docs/migration/release-notes/0.9.14.md +26 -0
  46. package/docs/migration/release-notes/README.md +2 -0
  47. package/docs/reference/cli.md +18 -0
  48. package/package.json +1 -1
@@ -7042,7 +7042,8 @@ var init_errors = __esm(() => {
7042
7042
  TEST_ISOLATION_MISSING: "Under bun test, when AKM_BUNDLE_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
7043
7043
  UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The bundle directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
7044
7044
  UNKNOWN_IMPROVE_STRATEGY: "Pass one of the listed strategy names to `--strategy`, or define it under `improve.strategies`. Names are case-sensitive.",
7045
- EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry."
7045
+ EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry.",
7046
+ SECRET_REFERENCE_UNRESOLVED: "Check the secret exists (`akm secret list`) and the name after `secret://` matches, or run `akm secret set <name> <value>` to store it."
7046
7047
  };
7047
7048
  COMPOSITION_INVALID_MULTI_JOB_HINT = "AKM workflows support exactly one job per source, with no needs: between jobs. Split the extra job(s) into " + "their own workflow file, and compose them with uses: workflows/<ref> instead.";
7048
7049
  USAGE_HINTS = {
@@ -7064,7 +7065,8 @@ var init_errors = __esm(() => {
7064
7065
  INPUT_BINDING_INVALID: "Check the step's with: keys against the target's declared inputs.",
7065
7066
  TASK_TARGET_UNSUPPORTED: "Task definitions support command, script, workflow, and shell (run:) targets; akm/command is layered by callers.",
7066
7067
  WORKFLOW_IR_VERSION_UNSUPPORTED: "Abandon the run with `akm workflow abandon <id>`, then start it again from the workflow source \u2014 a frozen plan this akm cannot execute is not re-executable in place.",
7067
- WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes."
7068
+ WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes.",
7069
+ RUN_LEASE_HELD: "Wait for the named engine invocation to finish or for the lease to expire, then retry. `akm workflow status <id>` shows the current lease."
7068
7070
  };
7069
7071
  NOT_FOUND_HINTS = {
7070
7072
  ASSET_NOT_FOUND: "Run `akm search <query>` or `akm index` to refresh the index.",
@@ -8388,6 +8390,17 @@ function parseRefInput(raw) {
8388
8390
  }
8389
8391
  return { type: parts.type, name: parts.name, origin: ref.bundle };
8390
8392
  }
8393
+ function isFullRefInput(raw) {
8394
+ const trimmed = raw.trim();
8395
+ if (!trimmed)
8396
+ return false;
8397
+ try {
8398
+ const parsed = parseBundleRef(trimmed);
8399
+ return parsed.bundle !== undefined || typeNameFromConceptId(parsed.conceptId) !== undefined;
8400
+ } catch {
8401
+ return false;
8402
+ }
8403
+ }
8391
8404
  var init_resolve_ref = __esm(() => {
8392
8405
  init_errors();
8393
8406
  init_asset_placement();
@@ -9453,6 +9466,53 @@ function projectMarkdownContent(body, truncationInfo) {
9453
9466
  truncationInfo.truncated = text.length > MARKDOWN_CONTENT_MAX_CHARS;
9454
9467
  return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
9455
9468
  }
9469
+ function setMarkdownFragmentContent(entry, content) {
9470
+ markdownFragmentProjectionEntries.add(entry);
9471
+ if (content)
9472
+ markdownFragmentContentByEntry.set(entry, content);
9473
+ }
9474
+ function getMarkdownFragmentContent(entry) {
9475
+ return markdownFragmentContentByEntry.get(entry);
9476
+ }
9477
+ function hasMarkdownFragmentContent(entry) {
9478
+ return markdownFragmentProjectionEntries.has(entry);
9479
+ }
9480
+ function projectMarkdownFragmentContent(raw) {
9481
+ const lines = raw.split(/\r?\n/);
9482
+ const parsed = parseFrontmatter(raw);
9483
+ const start = parsed.frontmatter ? parsed.bodyStartLine - 1 : 0;
9484
+ const projected = lines.map(() => "");
9485
+ let fence;
9486
+ const htmlComment = { inComment: false };
9487
+ for (let index = start;index < lines.length; index++) {
9488
+ const rawLine = lines[index];
9489
+ if (fence) {
9490
+ if (isMarkdownFenceClosing(rawLine, fence))
9491
+ fence = undefined;
9492
+ continue;
9493
+ }
9494
+ if (!htmlComment.inComment) {
9495
+ const opening2 = parseMarkdownFenceOpening(rawLine);
9496
+ if (opening2) {
9497
+ fence = opening2;
9498
+ continue;
9499
+ }
9500
+ }
9501
+ let safe = stripMarkdownHtmlComments(rawLine, htmlComment);
9502
+ const opening = parseMarkdownFenceOpening(safe.trim());
9503
+ if (opening) {
9504
+ fence = opening;
9505
+ continue;
9506
+ }
9507
+ if (/^\s*\[[^\]]+\]:\s*\S+/.test(safe) || /^\s*<[^>]+>\s*$/.test(safe))
9508
+ continue;
9509
+ safe = stripMarkdownLinkDestinations(safe).replace(/<[^>]+>/g, " ");
9510
+ projected[index] = safe.replace(/[ \t]+$/g, "");
9511
+ }
9512
+ const text = projected.join(`
9513
+ `);
9514
+ return text.trim() ? text : undefined;
9515
+ }
9456
9516
  function applyPreContributorFields(entry, file, ctx, pkgMeta) {
9457
9517
  const ext = path19.extname(file).toLowerCase();
9458
9518
  if (pkgMeta) {
@@ -9473,7 +9533,9 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
9473
9533
  entry.parameters = fmParams;
9474
9534
  applyWikiFrontmatter(entry, parsed.data);
9475
9535
  applyProvenanceFrontmatter(entry, parsed.data);
9476
- if (entry.type !== "env" && entry.type !== "session" && !hasSessionMemoryMarker(parsed.data, parsed.content)) {
9536
+ const safeForFragments = entry.type !== "env" && entry.type !== "session" && !hasSessionMemoryMarker(parsed.data, parsed.content);
9537
+ setMarkdownFragmentContent(entry, safeForFragments ? projectMarkdownFragmentContent(content) : undefined);
9538
+ if (safeForFragments) {
9477
9539
  const truncationInfo = { truncated: false };
9478
9540
  const contentProjection = projectMarkdownContent(parsed.content, truncationInfo);
9479
9541
  if (contentProjection) {
@@ -9591,7 +9653,7 @@ function extractDirTagsFromName(name) {
9591
9653
  }
9592
9654
  return Array.from(tags);
9593
9655
  }
9594
- var SCOPE_KEYS, KNOWN_QUALITY_VALUES, warnedUnknownQualityValues, MARKDOWN_CONTENT_MAX_CHARS = 1e6, MAX_MARKDOWN_LINK_NESTING = 32;
9656
+ var SCOPE_KEYS, KNOWN_QUALITY_VALUES, warnedUnknownQualityValues, MARKDOWN_CONTENT_MAX_CHARS = 1e6, MAX_MARKDOWN_LINK_NESTING = 32, markdownFragmentContentByEntry, markdownFragmentProjectionEntries;
9595
9657
  var init_metadata = __esm(() => {
9596
9658
  init_asset_ref();
9597
9659
  init_frontmatter();
@@ -9600,6 +9662,8 @@ var init_metadata = __esm(() => {
9600
9662
  SCOPE_KEYS = ["user", "agent", "run", "channel"];
9601
9663
  KNOWN_QUALITY_VALUES = new Set(["generated", "curated", "enriched", "proposed"]);
9602
9664
  warnedUnknownQualityValues = new Set;
9665
+ markdownFragmentContentByEntry = new WeakMap;
9666
+ markdownFragmentProjectionEntries = new WeakSet;
9603
9667
  });
9604
9668
 
9605
9669
  // src/execution/record.ts
@@ -12173,6 +12237,9 @@ var init_schema2 = __esm(() => {
12173
12237
  });
12174
12238
 
12175
12239
  // src/core/asset/markdown.ts
12240
+ function markdownHeadingSlug(heading) {
12241
+ return heading.trim().toLowerCase().replace(/<[^>]*>/g, "").replace(/[^\p{L}\p{N}\s_-]+/gu, "-").replace(/[\s_]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
12242
+ }
12176
12243
  function parseMarkdownToc(content) {
12177
12244
  const lines = content.split(/\r?\n/);
12178
12245
  const headings = [];
@@ -12414,7 +12481,7 @@ function bindStepSections(headings, lines, bodyStartLine, totalLines, path24, de
12414
12481
  if (!declaredIds.has(h.text)) {
12415
12482
  errors3.push({
12416
12483
  line: h.line,
12417
- message: `Unexpected level-2 heading "## ${h.text}" on line ${h.line} \u2014 no step "${h.text}" is declared in frontmatter "steps:". Level-2 headings must exactly match a declared step id.`
12484
+ message: `Unexpected level-2 heading "## ${h.text}" on line ${h.line} \u2014 no step "${h.text}" is declared in frontmatter "steps:". Level-2 headings must exactly match a declared step id. To document something that is not a step, use a level-3 heading.`
12418
12485
  });
12419
12486
  continue;
12420
12487
  }
@@ -35607,7 +35674,7 @@ var require_libvips = __commonJS((exports, module) => {
35607
35674
  SPDX-License-Identifier: Apache-2.0
35608
35675
  */
35609
35676
  var { spawnSync: spawnSync6 } = __require("child_process");
35610
- var { createHash: createHash9 } = __require("crypto");
35677
+ var { createHash: createHash10 } = __require("crypto");
35611
35678
  var semverCoerce = require_coerce2();
35612
35679
  var semverGreaterThanOrEqualTo = require_gte2();
35613
35680
  var semverSatisfies = require_satisfies2();
@@ -35695,7 +35762,7 @@ var require_libvips = __commonJS((exports, module) => {
35695
35762
  }
35696
35763
  return false;
35697
35764
  };
35698
- var sha512 = (s) => createHash9("sha512").update(s).digest("hex");
35765
+ var sha512 = (s) => createHash10("sha512").update(s).digest("hex");
35699
35766
  var yarnLocator = () => {
35700
35767
  try {
35701
35768
  const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
@@ -49987,10 +50054,10 @@ var import_sharp, __dirname = "/home/runner/work/akm/akm/node_modules/@huggingfa
49987
50054
  if (cached) {
49988
50055
  return cached.text();
49989
50056
  }
49990
- const hash3 = await this._getLfsFileHash(url2);
49991
- if (hash3) {
49992
- await hashCache.put(url2, new Response(hash3));
49993
- return hash3;
50057
+ const hash4 = await this._getLfsFileHash(url2);
50058
+ if (hash4) {
50059
+ await hashCache.put(url2, new Response(hash4));
50060
+ return hash4;
49994
50061
  }
49995
50062
  return null;
49996
50063
  } catch {
@@ -68087,15 +68154,15 @@ ${this.boa_token}${this.audio_token.repeat(this._compute_audio_num_tokens(audio_
68087
68154
  });
68088
68155
 
68089
68156
  // src/indexer/walk/file-context.ts
68090
- import fs45 from "fs";
68091
- import path55 from "path";
68157
+ import fs47 from "fs";
68158
+ import path56 from "path";
68092
68159
  function buildFileContext(stashRoot, absPath) {
68093
- const relPath = toPosix(path55.relative(stashRoot, absPath));
68094
- const ext = path55.extname(absPath).toLowerCase();
68095
- const fileName = path55.basename(absPath);
68096
- const parentDirAbs = path55.dirname(absPath);
68097
- const parentDir = path55.basename(parentDirAbs);
68098
- const relDir = toPosix(path55.dirname(relPath));
68160
+ const relPath = toPosix(path56.relative(stashRoot, absPath));
68161
+ const ext = path56.extname(absPath).toLowerCase();
68162
+ const fileName = path56.basename(absPath);
68163
+ const parentDirAbs = path56.dirname(absPath);
68164
+ const parentDir = path56.basename(parentDirAbs);
68165
+ const relDir = toPosix(path56.dirname(relPath));
68099
68166
  const ancestorDirs = relDir === "." ? [] : relDir.split("/").filter((seg) => seg.length > 0);
68100
68167
  let cachedContent;
68101
68168
  let cachedFrontmatter;
@@ -68112,7 +68179,7 @@ function buildFileContext(stashRoot, absPath) {
68112
68179
  stashRoot,
68113
68180
  content() {
68114
68181
  if (cachedContent === undefined) {
68115
- cachedContent = fs45.readFileSync(absPath, "utf8");
68182
+ cachedContent = fs47.readFileSync(absPath, "utf8");
68116
68183
  }
68117
68184
  return cachedContent;
68118
68185
  },
@@ -68127,7 +68194,7 @@ function buildFileContext(stashRoot, absPath) {
68127
68194
  },
68128
68195
  stat() {
68129
68196
  if (cachedStat === undefined) {
68130
- cachedStat = fs45.statSync(absPath);
68197
+ cachedStat = fs47.statSync(absPath);
68131
68198
  }
68132
68199
  return cachedStat;
68133
68200
  }
@@ -70250,6 +70317,7 @@ function formatProposalDrainPlain(r) {
70250
70317
  const deferred = Array.isArray(r.deferred) ? r.deferred : [];
70251
70318
  const skippedByCap = Array.isArray(r.skippedByCap) ? r.skippedByCap : [];
70252
70319
  const staged = Array.isArray(r.staged) ? r.staged : [];
70320
+ const failed = Array.isArray(r.failed) ? r.failed : [];
70253
70321
  const prefix = r.dryRun === true ? "[dry-run] " : "";
70254
70322
  const lines = [
70255
70323
  `${prefix}Drained proposal queue (strategy=${String(r.strategy ?? "?")}, policy=${policy}, applyMode=${applyMode})`,
@@ -70257,11 +70325,15 @@ function formatProposalDrainPlain(r) {
70257
70325
  ` rejected: ${rejected.length}`,
70258
70326
  ` deferred: ${deferred.length}`,
70259
70327
  ` skippedByCap: ${skippedByCap.length}`,
70260
- ` staged: ${staged.length}`
70328
+ ` staged: ${staged.length}`,
70329
+ ` failed: ${failed.length}`
70261
70330
  ];
70262
70331
  for (const d of deferred) {
70263
70332
  lines.push(` - ${String(d.id ?? "?")} (${String(d.reason ?? "?")})`);
70264
70333
  }
70334
+ for (const f of failed) {
70335
+ lines.push(` ! ${String(f.id ?? "?")} (${String(f.reason ?? "?")}): ${String(f.detail ?? "?")}`);
70336
+ }
70265
70337
  appendLoweringNotices(lines, r);
70266
70338
  return lines.join(`
70267
70339
  `).trimEnd();
@@ -75483,12 +75555,16 @@ var httpUrl = exports_external.string().refine((v) => v.startsWith("http://") ||
75483
75555
  });
75484
75556
  var ENGINE_NAME_PATTERN = new RegExp(ENGINE_NAME_PATTERN_SOURCE);
75485
75557
  var ENV_REFERENCE_PATTERN = /^\$[A-Za-z_][A-Za-z0-9_]*$|^\$\{[A-Za-z_][A-Za-z0-9_]*\}$/;
75558
+ var SECRET_STORE_REFERENCE_PATTERN = /^secret:\/\/(.+)$/;
75486
75559
  var engineName = exports_external.string().max(63).regex(ENGINE_NAME_PATTERN, "names must be lowercase kebab-case and must not begin with reserved akm-");
75560
+ function isApiKeyReference(value) {
75561
+ return ENV_REFERENCE_PATTERN.test(value) || SECRET_STORE_REFERENCE_PATTERN.test(value);
75562
+ }
75487
75563
  function symbolicOrWarnApiKey(label) {
75488
75564
  return exports_external.string().superRefine((value) => {
75489
- if (ENV_REFERENCE_PATTERN.test(value))
75565
+ if (isApiKeyReference(value))
75490
75566
  return;
75491
- warnOnce(`config:literal-api-key:${label}`, `A ${label} in config.json is a literal API key, not a $VAR/\${VAR} reference; using it as configured. Prefer \`akm config set ...apiKey '$VAR'\` (with the corresponding env var set) \u2014 see docs/reference/data-and-telemetry.md.`);
75567
+ warnOnce(`config:literal-api-key:${label}`, `A ${label} in config.json is a literal API key, not a $VAR/\${VAR}/secret:// reference; using it as configured. Prefer \`akm config set ...apiKey '$VAR'\` (with the corresponding env var set) or \`secret://<name>\` (with \`akm secret set <name> ...\`) \u2014 see docs/reference/data-and-telemetry.md.`);
75492
75568
  });
75493
75569
  }
75494
75570
  var chatCompletionsEndpoint = exports_external.string().superRefine((value, ctx) => {
@@ -76656,11 +76732,19 @@ function getSources(config) {
76656
76732
  function loadConfig() {
76657
76733
  return loadUserConfig();
76658
76734
  }
76659
- function resolveSecret(value) {
76735
+ function resolveSecret(value, resolveFromStore) {
76660
76736
  if (value === undefined)
76661
76737
  return;
76662
76738
  if (typeof value !== "string")
76663
76739
  return value;
76740
+ const storeRef = SECRET_STORE_REFERENCE_PATTERN.exec(value)?.[1];
76741
+ if (storeRef !== undefined) {
76742
+ const resolved = resolveFromStore?.(storeRef) ?? null;
76743
+ if (resolved === null) {
76744
+ throw new ConfigError(`Secret store reference "${value}" did not resolve to a stored value.`, "SECRET_REFERENCE_UNRESOLVED");
76745
+ }
76746
+ return resolved;
76747
+ }
76664
76748
  if (!value.includes("$"))
76665
76749
  return value;
76666
76750
  return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, braced, bare) => {
@@ -78544,10 +78628,10 @@ function listTxnJournalsTolerant(predicate) {
78544
78628
  }
78545
78629
 
78546
78630
  // src/commands/proposal/repository.ts
78547
- import { createHash as createHash9, randomUUID as randomUUID6 } from "crypto";
78548
- import fs47 from "fs";
78631
+ import { createHash as createHash10, randomUUID as randomUUID6 } from "crypto";
78632
+ import fs49 from "fs";
78549
78633
  init_dist();
78550
- import path60 from "path";
78634
+ import path61 from "path";
78551
78635
 
78552
78636
  // src/core/adapter/adapters/agent-skills-adapter.ts
78553
78637
  init_frontmatter();
@@ -79452,20 +79536,41 @@ function buildWorkflowAction(ref) {
79452
79536
  return `Start or resume execution with \`akm workflow run ${shellQuote(ref)}\`.`;
79453
79537
  }
79454
79538
  var TYPE_PRESENTATION = {
79455
- skill: { label: "Skill", renderer: "skill-md", action: (ref) => `akm show ${ref} -> follow the instructions` },
79539
+ skill: {
79540
+ label: "Skill",
79541
+ renderer: "skill-md",
79542
+ action: (ref) => `akm show ${ref} -> follow the instructions`,
79543
+ fragmentRef: false
79544
+ },
79456
79545
  command: {
79457
79546
  label: "Command",
79458
79547
  renderer: "command-md",
79459
- action: (ref) => `akm show ${ref} -> fill placeholders and dispatch`
79548
+ action: (ref) => `akm show ${ref} -> fill placeholders and dispatch`,
79549
+ fragmentRef: false
79550
+ },
79551
+ agent: {
79552
+ label: "Agent",
79553
+ renderer: "agent-md",
79554
+ action: (ref) => `akm show ${ref} -> dispatch with full prompt`,
79555
+ fragmentRef: false
79460
79556
  },
79461
- agent: { label: "Agent", renderer: "agent-md", action: (ref) => `akm show ${ref} -> dispatch with full prompt` },
79462
79557
  knowledge: {
79463
79558
  label: "Knowledge",
79464
79559
  renderer: "knowledge-md",
79465
79560
  action: (ref) => `akm show ${ref} -> read reference material`
79466
79561
  },
79467
- workflow: { label: "Workflow", renderer: "workflow-md", action: (ref) => buildWorkflowAction(ref) },
79468
- script: { label: "Script", renderer: "script-source", action: (ref) => `akm show ${ref} -> execute the run command` },
79562
+ workflow: {
79563
+ label: "Workflow",
79564
+ renderer: "workflow-md",
79565
+ action: (ref) => buildWorkflowAction(ref),
79566
+ fragmentRef: false
79567
+ },
79568
+ script: {
79569
+ label: "Script",
79570
+ renderer: "script-source",
79571
+ action: (ref) => `akm show ${ref} -> execute the run command`,
79572
+ fragmentRef: false
79573
+ },
79469
79574
  memory: { label: "Memory", renderer: "memory-md", action: (ref) => `akm show ${ref} -> recall context` },
79470
79575
  env: {
79471
79576
  label: "Env",
@@ -79485,7 +79590,8 @@ var TYPE_PRESENTATION = {
79485
79590
  task: {
79486
79591
  label: "Task",
79487
79592
  renderer: "task-yaml",
79488
- action: (ref) => `akm show ${ref} -> inspect; akm task run <id> -> run now; edit the file + akm task sync -> unschedule`
79593
+ action: (ref) => `akm show ${ref} -> inspect; akm task run <id> -> run now; edit the file + akm task sync -> unschedule`,
79594
+ fragmentRef: false
79489
79595
  },
79490
79596
  session: {
79491
79597
  label: "Session",
@@ -79500,7 +79606,8 @@ var TYPE_PRESENTATION = {
79500
79606
  instruction: {
79501
79607
  label: "Instruction",
79502
79608
  renderer: "knowledge-md",
79503
- action: (ref) => `akm show ${ref} -> read the project instructions`
79609
+ action: (ref) => `akm show ${ref} -> read the project instructions`,
79610
+ fragmentRef: false
79504
79611
  }
79505
79612
  };
79506
79613
  var DEFAULT_PRESENTATION = { label: "Asset" };
@@ -82426,6 +82533,8 @@ function indexDocumentFromEntry(entry, base3, rendererName) {
82426
82533
  doc.lessonStrength = entry.lessonStrength;
82427
82534
  if (entry.derivedFrom !== undefined)
82428
82535
  doc.derivedFrom = entry.derivedFrom;
82536
+ if (hasMarkdownFragmentContent(entry))
82537
+ setMarkdownFragmentContent(doc, getMarkdownFragmentContent(entry));
82429
82538
  return doc;
82430
82539
  }
82431
82540
  function conceptIdForRecognizedType(root, filePath, type) {
@@ -92631,8 +92740,8 @@ init_warn();
92631
92740
  init_write_provenance();
92632
92741
 
92633
92742
  // src/indexer/index-written-assets.ts
92634
- import fs46 from "fs";
92635
- import path58 from "path";
92743
+ import fs48 from "fs";
92744
+ import path59 from "path";
92636
92745
  init_errors();
92637
92746
  init_paths();
92638
92747
  init_warn();
@@ -92643,7 +92752,7 @@ init_paths();
92643
92752
  init_warn();
92644
92753
 
92645
92754
  // src/storage/repositories/index-entry-schema.ts
92646
- var CANONICAL_INDEX_DB_VERSION = 22;
92755
+ var CANONICAL_INDEX_DB_VERSION = 23;
92647
92756
  var CANONICAL_ENTRY_SCHEMA_FINGERPRINT = {
92648
92757
  tableSql: "CREATE TABLE entries ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_ref TEXT NOT NULL UNIQUE, bundle_id TEXT NOT NULL, component_id TEXT NOT NULL, concept_id TEXT NOT NULL, adapter_id TEXT NOT NULL, type TEXT NOT NULL, file_path TEXT NOT NULL, content_hash TEXT, document_json TEXT NOT NULL, search_text TEXT NOT NULL, derived_from TEXT )",
92649
92758
  sqliteSequenceTable: true,
@@ -92793,7 +92902,12 @@ var CANONICAL_ENTRY_SCHEMA_FINGERPRINT = {
92793
92902
  { sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 }
92794
92903
  ]
92795
92904
  }
92796
- ]
92905
+ ],
92906
+ searchSurfaces: {
92907
+ entriesFtsSql: "CREATE VIRTUAL TABLE entries_fts USING fts5( entry_id UNINDEXED, name, description, tags, hints, content, tokenize='porter unicode61' )",
92908
+ fragmentSourceSql: "CREATE TABLE entry_fragments ( entry_id INTEGER PRIMARY KEY REFERENCES entries(id) ON DELETE CASCADE, safe_markdown TEXT NOT NULL )",
92909
+ fragmentsFtsSql: "CREATE VIRTUAL TABLE entry_fragments_fts USING fts5( entry_id UNINDEXED, fragment_id UNINDEXED, fragment_ordinal UNINDEXED, content, tokenize='porter unicode61' )"
92910
+ }
92797
92911
  };
92798
92912
  function sqlString(value) {
92799
92913
  return `'${value.replaceAll("'", "''")}'`;
@@ -92803,8 +92917,11 @@ function normalizeSchemaSql(value) {
92803
92917
  return null;
92804
92918
  return value.replace(/\s+/g, " ").trim();
92805
92919
  }
92920
+ function readNamedTableSql(db, name) {
92921
+ const row = db.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ${sqlString(name)}`).get();
92922
+ return normalizeSchemaSql(row?.sql);
92923
+ }
92806
92924
  function readEntrySchemaFingerprint(db) {
92807
- const tableRow = db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'entries'").get();
92808
92925
  const sqliteSequenceTable = db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = 'sqlite_sequence'").get() != null;
92809
92926
  const maxId = Number(db.prepare("SELECT COALESCE(MAX(id), 0) AS maxId FROM entries").get().maxId);
92810
92927
  const sequenceRow = sqliteSequenceTable ? db.prepare("SELECT seq FROM sqlite_sequence WHERE name = 'entries'").get() : undefined;
@@ -92833,11 +92950,16 @@ function readEntrySchemaFingerprint(db) {
92833
92950
  }))
92834
92951
  })).sort((left, right) => left.name.localeCompare(right.name));
92835
92952
  return {
92836
- tableSql: normalizeSchemaSql(tableRow?.sql),
92953
+ tableSql: readNamedTableSql(db, "entries"),
92837
92954
  sqliteSequenceTable,
92838
92955
  sqliteSequenceValid,
92839
92956
  columns,
92840
- indexes
92957
+ indexes,
92958
+ searchSurfaces: {
92959
+ entriesFtsSql: readNamedTableSql(db, "entries_fts"),
92960
+ fragmentSourceSql: readNamedTableSql(db, "entry_fragments"),
92961
+ fragmentsFtsSql: readNamedTableSql(db, "entry_fragments_fts")
92962
+ }
92841
92963
  };
92842
92964
  }
92843
92965
  function hasCanonicalEntrySchema(db) {
@@ -93040,20 +93162,30 @@ function openExistingDatabase(dbPath) {
93040
93162
  if (classifyPathAccess(resolvedPath).access === "absent") {
93041
93163
  throw new Error(`Index database not found at ${resolvedPath}. Run 'akm index' to build it.`);
93042
93164
  }
93043
- return openManagedDatabase({
93165
+ const db = openManagedDatabase({
93044
93166
  path: resolvedPath,
93045
- init: (db) => {
93046
- loadVecExtension(db);
93047
- warnIfNonCanonicalIndexGeneration(db, resolvedPath);
93167
+ init: (db2) => {
93168
+ loadVecExtension(db2);
93048
93169
  },
93049
93170
  create: false
93050
93171
  });
93172
+ try {
93173
+ assertCanonicalIndexGeneration(db, resolvedPath);
93174
+ return db;
93175
+ } catch (error2) {
93176
+ db.close();
93177
+ throw error2;
93178
+ }
93051
93179
  }
93052
- function warnIfNonCanonicalIndexGeneration(db, resolvedPath) {
93180
+ function assertCanonicalIndexGeneration(db, resolvedPath) {
93053
93181
  if (isCanonicalIndexGeneration(db))
93054
93182
  return;
93055
93183
  const classification = classifyIndexGeneration(db);
93056
- warnOnce(`index-read-noncanonical:${resolvedPath}`, `Index database at ${resolvedPath} does not match this akm's derived schema (stored generation ` + `${classification.storedVersion ?? "unknown"}; this binary understands ${CANONICAL_INDEX_DB_VERSION}). ` + "Reading it as-is; a query that needs a table or column this generation lacks will fail on its own. " + "Run 'akm index' to rebuild it for this binary.");
93184
+ const stored = classification.storedVersion ?? "unknown";
93185
+ if (classification.status === "newer") {
93186
+ throw new ConfigError(`Index database at ${resolvedPath} was built by a newer akm (stored generation ${stored}; ` + `this binary understands ${CANONICAL_INDEX_DB_VERSION}). Upgrade akm to use this index.`, "INDEX_SCHEMA_INCOMPATIBLE", "Upgrade akm to a version that understands this index generation.");
93187
+ }
93188
+ throw new ConfigError(`Index database at ${resolvedPath} is not usable with this akm's derived schema (stored generation ${stored}; ` + `this binary understands ${CANONICAL_INDEX_DB_VERSION}). Run 'akm index' to rebuild it.`, "INDEX_SCHEMA_INCOMPATIBLE", "Run `akm index` to rebuild the derived index from the currently materialized sources.");
93057
93189
  }
93058
93190
  function assertIndexPathReadable(resolvedPath) {
93059
93191
  const { access, code } = classifyPathAccess(resolvedPath);
@@ -93070,6 +93202,7 @@ import fs40 from "fs";
93070
93202
  init_asset_ref();
93071
93203
  init_resolve_ref();
93072
93204
  init_warn();
93205
+ init_metadata();
93073
93206
 
93074
93207
  // src/indexer/search/search-fields.ts
93075
93208
  function buildSearchFields(entry) {
@@ -93133,9 +93266,129 @@ function buildSearchText(entry) {
93133
93266
  // src/storage/repositories/index-entry-mapper.ts
93134
93267
  init_warn();
93135
93268
 
93269
+ // src/core/asset/markdown-fragments.ts
93270
+ init_markdown();
93271
+ import { createHash as createHash9 } from "crypto";
93272
+ var MARKDOWN_FRAGMENT_MAX_CHARS = 1600;
93273
+ var MARKDOWN_FRAGMENT_PREFIX = "akm-fragment-";
93274
+ function hash3(text) {
93275
+ return createHash9("sha256").update(text).digest("hex");
93276
+ }
93277
+ function uniqueSlugs(body) {
93278
+ const out = new Map;
93279
+ const seen = new Set;
93280
+ for (const heading of parseMarkdownToc(body).headings) {
93281
+ const base3 = markdownHeadingSlug(heading.text);
93282
+ if (!base3)
93283
+ continue;
93284
+ let slug = base3;
93285
+ for (let suffix = 1;seen.has(slug); suffix++)
93286
+ slug = `${base3}-${suffix}`;
93287
+ seen.add(slug);
93288
+ out.set(heading.line, slug);
93289
+ }
93290
+ return out;
93291
+ }
93292
+ function textOf(lines) {
93293
+ return lines.join(`
93294
+ `).trim();
93295
+ }
93296
+ function splitPiece(piece, maxChars) {
93297
+ if (textOf(piece.lines).length <= maxChars)
93298
+ return [piece];
93299
+ const pieces = [];
93300
+ let start = 0;
93301
+ while (start < piece.lines.length) {
93302
+ let end = start;
93303
+ let chars = 0;
93304
+ while (end < piece.lines.length) {
93305
+ const next2 = piece.lines[end];
93306
+ if (end === start && next2.length > maxChars)
93307
+ break;
93308
+ if (end > start && chars + next2.length + 1 > maxChars)
93309
+ break;
93310
+ chars += next2.length + (end > start ? 1 : 0);
93311
+ end++;
93312
+ }
93313
+ if (end === start) {
93314
+ const line = piece.lines[start];
93315
+ let offset = 0;
93316
+ while (offset < line.length) {
93317
+ let cut = Math.min(offset + maxChars, line.length);
93318
+ if (cut < line.length) {
93319
+ const space = line.lastIndexOf(" ", cut);
93320
+ if (space > offset + Math.floor(maxChars * 0.55))
93321
+ cut = space;
93322
+ }
93323
+ pieces.push({ lines: [line.slice(offset, cut).trim()], startLine: piece.startLine + start });
93324
+ offset = cut;
93325
+ while (line[offset] === " ")
93326
+ offset++;
93327
+ }
93328
+ start++;
93329
+ continue;
93330
+ }
93331
+ let preferred = -1;
93332
+ for (let i = start + 1;i < end; i++)
93333
+ if (!piece.lines[i].trim())
93334
+ preferred = i;
93335
+ if (preferred > start)
93336
+ end = preferred;
93337
+ pieces.push({ lines: piece.lines.slice(start, end), startLine: piece.startLine + start });
93338
+ start = end;
93339
+ while (start < piece.lines.length && !piece.lines[start].trim())
93340
+ start++;
93341
+ }
93342
+ return pieces.filter((candidate) => textOf(candidate.lines));
93343
+ }
93344
+ function splitMarkdownFragmentStats(body, maxChars = MARKDOWN_FRAGMENT_MAX_CHARS) {
93345
+ const lines = body.split(/\r?\n/);
93346
+ const headings = parseMarkdownToc(body).headings;
93347
+ const boundaries = [1, ...headings.map((heading) => heading.line), lines.length + 1].filter((line, index, all) => index === 0 || line !== all[index - 1]).sort((left, right) => left - right);
93348
+ const slugs = uniqueSlugs(body);
93349
+ const pieces = [];
93350
+ let sectionCount = 0;
93351
+ for (let i = 0;i < boundaries.length - 1; i++) {
93352
+ const startLine = boundaries[i];
93353
+ const end = boundaries[i + 1] - 1;
93354
+ const section = { lines: lines.slice(startLine - 1, end), startLine, headingSlug: slugs.get(startLine) };
93355
+ if (textOf(section.lines)) {
93356
+ sectionCount++;
93357
+ pieces.push(...splitPiece(section, maxChars));
93358
+ }
93359
+ }
93360
+ const piecesPerHeading = new Map;
93361
+ for (const piece of pieces) {
93362
+ if (piece.headingSlug)
93363
+ piecesPerHeading.set(piece.headingSlug, (piecesPerHeading.get(piece.headingSlug) ?? 0) + 1);
93364
+ }
93365
+ const fragments = pieces.map((piece, ordinal) => {
93366
+ const text = textOf(piece.lines);
93367
+ const contentLines = piece.lines.map((line, index) => ({ line, index })).filter(({ line }) => line.trim());
93368
+ const first = contentLines[0]?.index ?? 0;
93369
+ const last = contentLines.at(-1)?.index ?? 0;
93370
+ const digest = hash3(text);
93371
+ const unsplitHeading = piece.headingSlug && piecesPerHeading.get(piece.headingSlug) === 1;
93372
+ return {
93373
+ fragmentId: `${MARKDOWN_FRAGMENT_PREFIX}${ordinal + 1}-${digest.slice(0, 12)}`,
93374
+ ordinal,
93375
+ startLine: piece.startLine + first,
93376
+ endLine: piece.startLine + last,
93377
+ ...unsplitHeading ? { headingSlug: piece.headingSlug } : {},
93378
+ text,
93379
+ hash: digest
93380
+ };
93381
+ });
93382
+ return { fragments, hardSplitCount: Math.max(0, pieces.length - sectionCount) };
93383
+ }
93384
+ function splitMarkdownFragments(body, maxChars = MARKDOWN_FRAGMENT_MAX_CHARS) {
93385
+ return splitMarkdownFragmentStats(body, maxChars).fragments;
93386
+ }
93387
+
93136
93388
  // src/storage/repositories/index-fts-repository.ts
93137
93389
  init_warn();
93138
93390
  var INSERT_FTS_SQL = "INSERT INTO entries_fts (entry_id, name, description, tags, hints, content) VALUES (?, ?, ?, ?, ?, ?)";
93391
+ var INSERT_FRAGMENT_SQL = "INSERT INTO entry_fragments_fts (entry_id, fragment_id, fragment_ordinal, content) VALUES (?, ?, ?, ?)";
93139
93392
  var ftsMutationStatementsByDb = new WeakMap;
93140
93393
  function getFtsMutationStatements(db) {
93141
93394
  const existing = ftsMutationStatementsByDb.get(db);
@@ -93143,22 +93396,39 @@ function getFtsMutationStatements(db) {
93143
93396
  return existing;
93144
93397
  const statements = {
93145
93398
  deleteOne: db.prepare("DELETE FROM entries_fts WHERE entry_id = ?"),
93146
- insert: db.prepare(INSERT_FTS_SQL)
93399
+ insert: db.prepare(INSERT_FTS_SQL),
93400
+ deleteFragments: db.prepare("DELETE FROM entry_fragments_fts WHERE entry_id = ?"),
93401
+ upsertFragmentSource: db.prepare("INSERT INTO entry_fragments (entry_id, safe_markdown) VALUES (?, ?) ON CONFLICT(entry_id) DO UPDATE SET safe_markdown = excluded.safe_markdown"),
93402
+ deleteFragmentSource: db.prepare("DELETE FROM entry_fragments WHERE entry_id = ?"),
93403
+ insertFragment: db.prepare(INSERT_FRAGMENT_SQL)
93147
93404
  };
93148
93405
  ftsMutationStatementsByDb.set(db, statements);
93149
93406
  return statements;
93150
93407
  }
93151
- function replaceFtsEntry(db, entryId, entry) {
93408
+ function replaceFtsEntry(db, entryId, entry, fragmentContent) {
93152
93409
  const fields = buildSearchFields(entry);
93153
93410
  const statements = getFtsMutationStatements(db);
93154
93411
  statements.deleteOne.run(entryId);
93155
93412
  statements.insert.run(entryId, fields.name, fields.description, fields.tags, fields.hints, fields.content);
93413
+ if (fragmentContent === undefined) {
93414
+ return;
93415
+ }
93416
+ statements.deleteFragments.run(entryId);
93417
+ statements.deleteFragmentSource.run(entryId);
93418
+ if (!fragmentContent)
93419
+ return;
93420
+ statements.upsertFragmentSource.run(entryId, fragmentContent);
93421
+ for (const fragment of splitMarkdownFragments(fragmentContent)) {
93422
+ statements.insertFragment.run(entryId, fragment.fragmentId, fragment.ordinal, fragment.text.toLowerCase());
93423
+ }
93156
93424
  }
93157
93425
  function deleteFtsEntries(db, entryIds) {
93158
93426
  for (let i = 0;i < entryIds.length; i += SQLITE_CHUNK_SIZE) {
93159
93427
  const chunk = entryIds.slice(i, i + SQLITE_CHUNK_SIZE);
93160
93428
  const placeholders = chunk.map(() => "?").join(",");
93161
93429
  db.prepare(`DELETE FROM entries_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
93430
+ db.prepare(`DELETE FROM entry_fragments_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
93431
+ db.prepare(`DELETE FROM entry_fragments WHERE entry_id IN (${placeholders})`).run(...chunk);
93162
93432
  }
93163
93433
  }
93164
93434
 
@@ -93173,7 +93443,7 @@ function upsertEntry(db, filePath, entry, searchText, provenance, contentHash) {
93173
93443
  throw new Error("upsertEntry: item_ref not found after upsert");
93174
93444
  if (previous?.id === result.id && previous.search_text !== searchText)
93175
93445
  deleteEntryVectors(db, result.id);
93176
- replaceFtsEntry(db, result.id, entry);
93446
+ replaceFtsEntry(db, result.id, entry, hasMarkdownFragmentContent(entry) ? getMarkdownFragmentContent(entry) ?? null : undefined);
93177
93447
  return result.id;
93178
93448
  };
93179
93449
  return db.transaction(apply)();
@@ -93669,6 +93939,127 @@ function redactSensitiveText(text, sensitiveValues) {
93669
93939
 
93670
93940
  // src/llm/embedders/remote.ts
93671
93941
  init_warn();
93942
+
93943
+ // src/sources/snapshot-fetchers/secret-seam.ts
93944
+ import fs45 from "fs";
93945
+
93946
+ // src/core/env-secret-ref.ts
93947
+ import fs43 from "fs";
93948
+ import path54 from "path";
93949
+
93950
+ // src/registry/origin-resolve.ts
93951
+ init_asset_ref();
93952
+ function resolveSourcesForOrigin(origin, allSources) {
93953
+ if (!origin)
93954
+ return allSources;
93955
+ const installations = deriveInstallations(allSources);
93956
+ return allSources.filter((_, index) => installations[index]?.id === origin);
93957
+ }
93958
+
93959
+ // src/core/asset/asset-create.ts
93960
+ init_errors();
93961
+ function normalizeCreateSubPath(subPath) {
93962
+ if (subPath === undefined)
93963
+ return "";
93964
+ const trimmed = subPath.trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
93965
+ if (!trimmed)
93966
+ return "";
93967
+ if (trimmed.split("/").some((segment) => !segment || segment === "." || segment === "..")) {
93968
+ throw new UsageError("--path must be a relative directory without '.' or '..' segments.");
93969
+ }
93970
+ return trimmed;
93971
+ }
93972
+ function assertFlatAssetName(name) {
93973
+ if (name?.replace(/\\/g, "/").replace(/\.md$/i, "").includes("/")) {
93974
+ throw new UsageError("Asset --name must be a flat name without '/'. Use --path to choose a subdirectory " + "(e.g. --path personal --name grocery-list).");
93975
+ }
93976
+ }
93977
+ function combineCreatePath(subPath, baseName) {
93978
+ return subPath ? `${subPath}/${baseName}` : baseName;
93979
+ }
93980
+
93981
+ // src/core/env-secret-ref.ts
93982
+ init_asset_placement();
93983
+ init_resolve_ref();
93984
+ init_common();
93985
+ init_errors();
93986
+ function assertNotRemovedVaultRef(ref) {
93987
+ const boundary = ref.indexOf("//");
93988
+ const bare = boundary >= 0 ? ref.slice(boundary + 2) : ref;
93989
+ if (/^vault[:/]/.test(bare.trim())) {
93990
+ throw new UsageError("The `vault` asset type was removed in 0.9.0 \u2014 use `env/` (whole .env config) or `secrets/` (a single value).", "INVALID_FLAG_VALUE");
93991
+ }
93992
+ }
93993
+ function assertNotColonRef(ref, aliases, replacement) {
93994
+ const boundary = ref.indexOf("//");
93995
+ const bare = (boundary >= 0 ? ref.slice(boundary + 2) : ref).trim();
93996
+ const colon = bare.indexOf(":");
93997
+ if (colon <= 0)
93998
+ return;
93999
+ const head = bare.slice(0, colon).toLowerCase();
94000
+ if (!aliases.includes(head))
94001
+ return;
94002
+ const name = bare.slice(colon + 1);
94003
+ throw new UsageError(`The \`${head}:\` ref spelling was removed in 0.9.0 \u2014 use the slash form instead: \`${replacement}${name}\`.`, "INVALID_FLAG_VALUE");
94004
+ }
94005
+ function findEnvSource(origin, type, name) {
94006
+ const sources = resolveSourceEntries(undefined, loadConfig());
94007
+ if (sources.length === 0) {
94008
+ throw new UsageError("No bundles configured. Run `akm bundle create` to create your working bundle.");
94009
+ }
94010
+ const candidates = origin ? resolveSourcesForOrigin(origin, sources) : sources;
94011
+ const typeDir = type === "env" ? "env" : "secrets";
94012
+ const member = candidates.find((source) => fs43.existsSync(assetPathForName(type, path54.join(source.path, typeDir), name)));
94013
+ if (member)
94014
+ return member;
94015
+ if (!origin) {
94016
+ const fallback = candidates[0];
94017
+ if (fallback)
94018
+ return fallback;
94019
+ throw new UsageError("No bundles configured. Run `akm bundle create` to create your working bundle.");
94020
+ }
94021
+ const named = candidates[0];
94022
+ if (!named) {
94023
+ throw new NotFoundError(`Source not found for origin: ${origin}`);
94024
+ }
94025
+ return named;
94026
+ }
94027
+ function parseSecretRef(ref) {
94028
+ assertNotRemovedVaultRef(ref);
94029
+ assertNotColonRef(ref, ["secret", "secrets"], "secrets/");
94030
+ return parseRefInput(isFullRefInput(ref) ? ref : `secrets/${ref}`);
94031
+ }
94032
+ function resolveSecretPath(ref, create) {
94033
+ const parsed = parseSecretRef(ref);
94034
+ if (parsed.type !== "secret") {
94035
+ throw new UsageError(`Expected a secret ref (secrets/<name>); got "${ref}".`);
94036
+ }
94037
+ if (create) {
94038
+ assertFlatAssetName(parsed.name);
94039
+ parsed.name = combineCreatePath(normalizeCreateSubPath(create.subPath), parsed.name);
94040
+ }
94041
+ const source = findEnvSource(parsed.origin, "secret", parsed.name);
94042
+ const typeRoot = path54.join(source.path, "secrets");
94043
+ const absPath = assetPathForName("secret", typeRoot, parsed.name);
94044
+ if (!isWithin(absPath, typeRoot)) {
94045
+ throw new UsageError(`Secret name "${parsed.name}" escapes the secrets directory.`);
94046
+ }
94047
+ return { name: parsed.name, absPath, source };
94048
+ }
94049
+
94050
+ // src/sources/snapshot-fetchers/secret-seam.ts
94051
+ function resolveSecretFromStore(ref) {
94052
+ try {
94053
+ const { absPath } = resolveSecretPath(ref);
94054
+ if (!fs45.existsSync(absPath))
94055
+ return null;
94056
+ return fs45.readFileSync(absPath, "utf8").trim() || null;
94057
+ } catch {
94058
+ return null;
94059
+ }
94060
+ }
94061
+
94062
+ // src/llm/embedders/remote.ts
93672
94063
  var DEFAULT_REMOTE_BATCH_SIZE = 100;
93673
94064
  var DEFAULT_TOKEN_BUDGET = 8000;
93674
94065
  function estimateTokenCount(text) {
@@ -93824,14 +94215,14 @@ class RemoteEmbedder {
93824
94215
  }
93825
94216
  buildHeaders() {
93826
94217
  const headers = { "Content-Type": "application/json" };
93827
- const resolvedKey = resolveSecret(this.config.apiKey);
94218
+ const resolvedKey = resolveSecret(this.config.apiKey, resolveSecretFromStore);
93828
94219
  if (resolvedKey) {
93829
94220
  headers.Authorization = `Bearer ${resolvedKey}`;
93830
94221
  }
93831
94222
  return headers;
93832
94223
  }
93833
94224
  safeErrorBody(body) {
93834
- const resolvedKey = resolveSecret(this.config.apiKey);
94225
+ const resolvedKey = resolveSecret(this.config.apiKey, resolveSecretFromStore);
93835
94226
  return redactSensitiveText(redactErrorBody(body), resolvedKey ? [resolvedKey] : []);
93836
94227
  }
93837
94228
  }
@@ -94066,8 +94457,11 @@ function publishTargetedEmbeddingMeta(db, config) {
94066
94457
  setMeta(db, "hasEmbeddings", ready ? "1" : "0");
94067
94458
  }
94068
94459
 
94460
+ // src/indexer/index-written-assets.ts
94461
+ init_metadata();
94462
+
94069
94463
  // src/indexer/scan/drain-dir.ts
94070
- import path57 from "path";
94464
+ import path58 from "path";
94071
94465
  init_common();
94072
94466
  init_recognition_util();
94073
94467
 
@@ -94076,8 +94470,8 @@ init_common();
94076
94470
  init_errors();
94077
94471
  init_recognition_util();
94078
94472
  init_warn();
94079
- import fs43 from "fs";
94080
- import path54 from "path";
94473
+ import fs46 from "fs";
94474
+ import path55 from "path";
94081
94475
 
94082
94476
  class WorkflowSourceRejectionError extends UsageError {
94083
94477
  sourcePaths;
@@ -94117,63 +94511,67 @@ class WorkflowSourcePathIdentityError extends WorkflowSourceRejectionError {
94117
94511
  function workflowNameForSourcePath(sourceRoot, adapterId, sourcePath) {
94118
94512
  if (adapterId !== "akm" && adapterId !== "akm-workflow")
94119
94513
  return;
94120
- const relativePath = toPosix(path54.relative(path54.resolve(sourceRoot), path54.resolve(sourcePath)));
94514
+ const relativePath = toPosix(path55.relative(path55.resolve(sourceRoot), path55.resolve(sourcePath)));
94121
94515
  if (!isSafeRelativeName(relativePath))
94122
94516
  return;
94123
94517
  const ownedPath = adapterId === "akm" ? relativePath.replace(/^workflows\//, "") : relativePath;
94124
94518
  if (adapterId === "akm" && ownedPath === relativePath)
94125
94519
  return;
94126
- const extension = path54.posix.extname(ownedPath);
94520
+ const extension = path55.posix.extname(ownedPath);
94127
94521
  if (!WORKFLOW_EXTENSIONS.includes(extension.toLowerCase()))
94128
94522
  return;
94129
94523
  return ownedPath;
94130
94524
  }
94131
- function listWorkflowSourceFiles(sourceRoot, adapterId, name) {
94525
+ function resolveWorkflowSourceDomains(sourceRoot, adapterId, sourcePaths) {
94132
94526
  if (adapterId !== "akm" && adapterId !== "akm-workflow")
94133
94527
  return [];
94134
- const canonicalName = canonicalizeWorkflowName(normalizeName2(name));
94135
- if (!isSafeRelativeName(canonicalName)) {
94136
- throw new UsageError("Workflow ref resolves outside the bundle root.", "PATH_ESCAPE_VIOLATION");
94137
- }
94528
+ const authoredRoot = path55.resolve(sourceRoot);
94138
94529
  let realRoot;
94139
- const authoredRoot = path54.resolve(sourceRoot);
94140
94530
  try {
94141
- realRoot = fs43.realpathSync(authoredRoot);
94531
+ realRoot = fs46.realpathSync(authoredRoot);
94142
94532
  } catch {
94143
94533
  return [];
94144
94534
  }
94145
- const ownershipRoot = adapterId === "akm" ? path54.join(authoredRoot, "workflows") : authoredRoot;
94146
- const parent = path54.join(ownershipRoot, path54.dirname(canonicalName));
94147
- if (!isWithinResolved(parent, authoredRoot)) {
94148
- throw new UsageError("Workflow ref resolves outside the bundle root.", "PATH_ESCAPE_VIOLATION");
94149
- }
94150
- let entries;
94151
- try {
94152
- entries = fs43.readdirSync(parent, { withFileTypes: true });
94153
- } catch {
94154
- return [];
94155
- }
94156
- const basename = path54.basename(canonicalName);
94157
- const candidates = [];
94158
- for (const entry of entries) {
94159
- if (!entry.isFile() && !entry.isSymbolicLink())
94535
+ const candidatesByName = new Map;
94536
+ const seenAuthoredPaths = new Set;
94537
+ for (const sourcePath of sourcePaths) {
94538
+ const normalizedSourcePath = path55.resolve(sourcePath);
94539
+ if (seenAuthoredPaths.has(normalizedSourcePath))
94160
94540
  continue;
94161
- const extension = path54.extname(entry.name);
94541
+ seenAuthoredPaths.add(normalizedSourcePath);
94542
+ const authoredName = workflowNameForSourcePath(authoredRoot, adapterId, normalizedSourcePath);
94543
+ if (authoredName === undefined)
94544
+ continue;
94545
+ const canonicalName = canonicalizeWorkflowName(authoredName);
94546
+ if (!isSafeRelativeName(canonicalName))
94547
+ continue;
94548
+ const extension = path55.extname(normalizedSourcePath);
94162
94549
  const lowerExtension = extension.toLowerCase();
94163
94550
  if (!WORKFLOW_EXTENSIONS.includes(lowerExtension))
94164
94551
  continue;
94165
- if (entry.name.slice(0, -extension.length) !== basename)
94166
- continue;
94167
- const candidatePath = path54.join(parent, entry.name);
94168
- candidates.push({
94169
- path: candidatePath,
94170
- relativePath: toPosix(path54.relative(authoredRoot, candidatePath)),
94552
+ const candidate = {
94553
+ path: normalizedSourcePath,
94554
+ relativePath: toPosix(path55.relative(authoredRoot, normalizedSourcePath)),
94171
94555
  lowerExtension,
94172
- extensionlessStem: entry.name.slice(0, -extension.length)
94556
+ extensionlessStem: path55.basename(normalizedSourcePath).slice(0, -extension.length)
94557
+ };
94558
+ const domain = candidatesByName.get(canonicalName) ?? [];
94559
+ domain.push(candidate);
94560
+ candidatesByName.set(canonicalName, domain);
94561
+ }
94562
+ const resolutions = [];
94563
+ for (const canonicalName of [...candidatesByName.keys()].sort(compareCodePoints)) {
94564
+ const candidates = candidatesByName.get(canonicalName) ?? [];
94565
+ candidates.sort((left, right) => compareCodePoints(left.relativePath, right.relativePath));
94566
+ const sources = inspectWorkflowSourceDomain(candidates, canonicalName, realRoot);
94567
+ const sourcePaths2 = candidates.map((candidate) => candidate.relativePath);
94568
+ resolutions.push({
94569
+ canonicalName,
94570
+ sourcePaths: sourcePaths2,
94571
+ source: pickWorkflowSource(adapterId, canonicalName, sources)
94173
94572
  });
94174
94573
  }
94175
- candidates.sort((left, right) => compareCodePoints(left.relativePath, right.relativePath));
94176
- return inspectWorkflowSourceDomain(candidates, canonicalName, realRoot);
94574
+ return resolutions;
94177
94575
  }
94178
94576
  function inspectWorkflowSourceDomain(candidates, canonicalName, realRoot) {
94179
94577
  const sources = [];
@@ -94202,7 +94600,7 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
94202
94600
  const issues = [];
94203
94601
  let authoredStat;
94204
94602
  try {
94205
- authoredStat = fs43.lstatSync(candidate.path);
94603
+ authoredStat = fs46.lstatSync(candidate.path);
94206
94604
  } catch {
94207
94605
  issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
94208
94606
  return { issues };
@@ -94214,21 +94612,21 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
94214
94612
  }
94215
94613
  let realPath;
94216
94614
  try {
94217
- realPath = fs43.realpathSync(candidate.path);
94615
+ realPath = fs46.realpathSync(candidate.path);
94218
94616
  } catch {
94219
94617
  issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
94220
94618
  return { issues };
94221
94619
  }
94222
- const targetPath = toPosix(path54.relative(realRoot, realPath));
94620
+ const targetPath = toPosix(path55.relative(realRoot, realPath));
94223
94621
  const contained2 = isWithinResolved(realPath, realRoot);
94224
94622
  if (!contained2)
94225
94623
  issues.push(new WorkflowSourcePathIdentityError(candidate.relativePath, targetPath));
94226
- if (isLink && path54.extname(realPath).toLowerCase() !== candidate.lowerExtension) {
94624
+ if (isLink && path55.extname(realPath).toLowerCase() !== candidate.lowerExtension) {
94227
94625
  issues.push(new WorkflowSourceLinkIdentityError(candidate.relativePath, targetPath));
94228
94626
  }
94229
94627
  if (contained2) {
94230
94628
  try {
94231
- if (!fs43.statSync(realPath).isFile())
94629
+ if (!fs46.statSync(realPath).isFile())
94232
94630
  issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
94233
94631
  } catch {
94234
94632
  issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
@@ -94247,20 +94645,12 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
94247
94645
  }
94248
94646
  };
94249
94647
  }
94250
- function resolveUniqueWorkflowSource(sourceRoot, adapterId, name) {
94251
- const sources = listWorkflowSourceFiles(sourceRoot, adapterId, name);
94252
- const canonicalName = sources[0]?.canonicalName ?? canonicalizeWorkflowName(normalizeName2(name));
94253
- return pickWorkflowSource(adapterId, canonicalName, sources);
94254
- }
94255
- function normalizeName2(name) {
94256
- return name.replaceAll("\\", "/");
94257
- }
94258
94648
  function isSafeRelativeName(name) {
94259
- return name.length > 0 && !path54.posix.isAbsolute(name) && name !== ".." && !name.startsWith("../") && path54.posix.normalize(name) === name;
94649
+ return name.length > 0 && !path55.posix.isAbsolute(name) && name !== ".." && !name.startsWith("../") && path55.posix.normalize(name) === name;
94260
94650
  }
94261
94651
  function isWithinResolved(candidate, root2) {
94262
- const relative = path54.relative(root2, path54.resolve(candidate));
94263
- return relative === "" || !relative.startsWith("..") && !path54.isAbsolute(relative);
94652
+ const relative = path55.relative(root2, path55.resolve(candidate));
94653
+ return relative === "" || !relative.startsWith("..") && !path55.isAbsolute(relative);
94264
94654
  }
94265
94655
 
94266
94656
  // src/indexer/scan/drain-dir.ts
@@ -94269,13 +94659,14 @@ init_metadata();
94269
94659
  init_file_context();
94270
94660
 
94271
94661
  // src/indexer/scan/doc-to-entry.ts
94272
- import path56 from "path";
94662
+ init_metadata();
94663
+ import path57 from "path";
94273
94664
  function indexDocumentToStashEntry(doc) {
94274
94665
  const dj = doc.documentJson ?? {};
94275
94666
  const entry = {
94276
94667
  name: doc.name,
94277
94668
  type: doc.type,
94278
- filename: path56.basename(doc.path ?? "")
94669
+ filename: path57.basename(doc.path ?? "")
94279
94670
  };
94280
94671
  if (doc.description !== undefined)
94281
94672
  entry.description = doc.description;
@@ -94285,6 +94676,8 @@ function indexDocumentToStashEntry(doc) {
94285
94676
  entry.content = doc.content;
94286
94677
  if (doc.contentTruncated !== undefined)
94287
94678
  entry.contentTruncated = doc.contentTruncated;
94679
+ if (hasMarkdownFragmentContent(doc))
94680
+ setMarkdownFragmentContent(entry, getMarkdownFragmentContent(doc));
94288
94681
  if (doc.ownsPresentation !== undefined)
94289
94682
  entry.ownsPresentation = doc.ownsPresentation;
94290
94683
  if (doc.updated !== undefined)
@@ -94378,31 +94771,28 @@ function drainDirDocuments(adapter, component, fileContexts) {
94378
94771
  const conceptIdByFile = new Map;
94379
94772
  const rejectedPaths = new Set;
94380
94773
  const rejectedConceptIds = new Set;
94381
- const workflowLookups = new Map;
94382
- for (const file of fileContexts) {
94774
+ const workflowOwnerPathByCanonicalName = new Map(resolveWorkflowSourceDomains(component.root, adapter.id, fileContexts.map((file) => file.absPath)).filter((resolution) => resolution.source !== undefined).map((resolution) => [resolution.canonicalName, path58.resolve(resolution.source.path)]));
94775
+ const invalidWorkflowOwnerNames = new Set;
94776
+ const orderedFileContexts = [...fileContexts].sort((left, right) => {
94777
+ const leftName = workflowNameForSourcePath(component.root, adapter.id, left.absPath);
94778
+ const rightName = workflowNameForSourcePath(component.root, adapter.id, right.absPath);
94779
+ const leftOwner = leftName !== undefined && workflowOwnerPathByCanonicalName.get(canonicalizeWorkflowName(leftName)) === path58.resolve(left.absPath);
94780
+ const rightOwner = rightName !== undefined && workflowOwnerPathByCanonicalName.get(canonicalizeWorkflowName(rightName)) === path58.resolve(right.absPath);
94781
+ if (leftOwner !== rightOwner)
94782
+ return leftOwner ? -1 : 1;
94783
+ return compareCodePoints(left.absPath, right.absPath);
94784
+ });
94785
+ for (const file of orderedFileContexts) {
94786
+ if (rejectedPaths.has(file.absPath))
94787
+ continue;
94383
94788
  const workflowName = workflowNameForSourcePath(component.root, adapter.id, file.absPath);
94384
94789
  if (workflowName !== undefined) {
94385
94790
  const canonicalName = canonicalizeWorkflowName(workflowName);
94386
- if (!workflowLookups.has(canonicalName))
94387
- workflowLookups.set(canonicalName, workflowName);
94388
- }
94389
- }
94390
- for (const [canonicalName, workflowName] of [...workflowLookups].sort(([left], [right]) => compareCodePoints(left, right))) {
94391
- try {
94392
- resolveUniqueWorkflowSource(component.root, adapter.id, workflowName);
94393
- } catch (error2) {
94394
- if (!(error2 instanceof WorkflowSourceRejectionError))
94395
- throw error2;
94396
- rejectedConceptIds.add(adapter.id === "akm" ? `workflows/${canonicalName}` : canonicalName);
94397
- for (const relativePath of error2.sourcePaths) {
94398
- rejectedPaths.add(path57.join(component.root, relativePath));
94791
+ const ownerPath = workflowOwnerPathByCanonicalName.get(canonicalName);
94792
+ if (ownerPath !== undefined && ownerPath !== path58.resolve(file.absPath) && !invalidWorkflowOwnerNames.has(canonicalName)) {
94793
+ continue;
94399
94794
  }
94400
- warnings.push(error2.message);
94401
94795
  }
94402
- }
94403
- for (const file of fileContexts) {
94404
- if (rejectedPaths.has(file.absPath))
94405
- continue;
94406
94796
  const doc = adapter.recognize(component, file);
94407
94797
  if (doc === null)
94408
94798
  continue;
@@ -94414,6 +94804,8 @@ function drainDirDocuments(adapter, component, fileContexts) {
94414
94804
  const dropWarning = handleWorkflowDoc(doc, file, component.root);
94415
94805
  if (dropWarning !== null) {
94416
94806
  warnings.push(dropWarning);
94807
+ if (workflowName !== undefined)
94808
+ invalidWorkflowOwnerNames.add(canonicalizeWorkflowName(workflowName));
94417
94809
  continue;
94418
94810
  }
94419
94811
  if (doc.hash !== undefined)
@@ -94457,7 +94849,7 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
94457
94849
  if (isPathAbsent(dbPath))
94458
94850
  return true;
94459
94851
  const files = filePaths.filter((f) => {
94460
- const rel = path58.relative(stashDir, f);
94852
+ const rel = path59.relative(stashDir, f);
94461
94853
  return !rel.split(/[\\/]+/).some((segment) => segment.startsWith("."));
94462
94854
  });
94463
94855
  if (files.length === 0)
@@ -94471,10 +94863,10 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
94471
94863
  const unindexable = new Set;
94472
94864
  const rejectedConceptIds = new Set;
94473
94865
  for (const file of files) {
94474
- if (!fs46.existsSync(file)) {
94866
+ if (!fs48.existsSync(file)) {
94475
94867
  let authoredDanglingSymlink = false;
94476
94868
  try {
94477
- authoredDanglingSymlink = fs46.lstatSync(file).isSymbolicLink();
94869
+ authoredDanglingSymlink = fs48.lstatSync(file).isSymbolicLink();
94478
94870
  } catch {}
94479
94871
  if (!authoredDanglingSymlink) {
94480
94872
  unindexable.add(file);
@@ -94525,7 +94917,10 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
94525
94917
  for (const { file, entry, conceptId, contentHash } of pairs) {
94526
94918
  let entryWithSize = entry;
94527
94919
  try {
94528
- entryWithSize = { ...entry, fileSize: fs46.statSync(file).size };
94920
+ entryWithSize = { ...entry, fileSize: fs48.statSync(file).size };
94921
+ if (hasMarkdownFragmentContent(entry)) {
94922
+ setMarkdownFragmentContent(entryWithSize, getMarkdownFragmentContent(entry));
94923
+ }
94529
94924
  } catch {}
94530
94925
  const provenance = deriveEntryProvenance({ bundleId: component.id, componentId: component.id, adapterId: component.adapter }, entry.type, entry.name, conceptId);
94531
94926
  const supersededIds = db.prepare("SELECT id FROM entries WHERE file_path = ? AND item_ref <> ?").all(file, provenance.itemRef);
@@ -94558,7 +94953,7 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
94558
94953
  init_asset_placement();
94559
94954
  init_asset_ref();
94560
94955
  init_warn();
94561
- import path59 from "path";
94956
+ import path60 from "path";
94562
94957
  function changesToStored(changes) {
94563
94958
  return changes.map((c, i) => ({
94564
94959
  path: c.path,
@@ -94611,10 +95006,10 @@ function currentProposalTarget(value) {
94611
95006
  if (typeof value !== "object" || value === null)
94612
95007
  throw new Error("Proposal metadata has an invalid proposedTarget.");
94613
95008
  const target = value;
94614
- if (typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !path59.isAbsolute(target.root)) {
95009
+ if (typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !path60.isAbsolute(target.root)) {
94615
95010
  throw new Error("Proposal metadata has an invalid proposedTarget.");
94616
95011
  }
94617
- return { source: target.source, root: path59.resolve(target.root) };
95012
+ return { source: target.source, root: path60.resolve(target.root) };
94618
95013
  }
94619
95014
  function invalidPresentField(name) {
94620
95015
  throw new Error(`Proposal metadata has an invalid ${name}.`);
@@ -94654,7 +95049,7 @@ function validatePresentMetadata(meta) {
94654
95049
  }
94655
95050
  if (Object.hasOwn(meta, "acceptedTarget")) {
94656
95051
  const target = meta.acceptedTarget;
94657
- if (typeof target !== "object" || target === null || typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !path59.isAbsolute(target.root) || typeof target.path !== "string" || !path59.isAbsolute(target.path) || typeof target.contentHash !== "string") {
95052
+ if (typeof target !== "object" || target === null || typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !path60.isAbsolute(target.root) || typeof target.path !== "string" || !path60.isAbsolute(target.path) || typeof target.contentHash !== "string") {
94658
95053
  invalidPresentField("acceptedTarget");
94659
95054
  }
94660
95055
  }
@@ -95385,15 +95780,15 @@ var PROPOSAL_TXN_PHASES = [
95385
95780
  "committed"
95386
95781
  ];
95387
95782
  function proposalHash(content) {
95388
- return createHash9("sha256").update(content).digest("hex");
95783
+ return createHash10("sha256").update(content).digest("hex");
95389
95784
  }
95390
95785
  function proposalFileHash(filePath) {
95391
- return proposalHash(fs47.readFileSync(filePath));
95786
+ return proposalHash(fs49.readFileSync(filePath));
95392
95787
  }
95393
95788
  function sameProposalFile(left, right) {
95394
95789
  try {
95395
- const leftStat = fs47.statSync(left);
95396
- const rightStat = fs47.statSync(right);
95790
+ const leftStat = fs49.statSync(left);
95791
+ const rightStat = fs49.statSync(right);
95397
95792
  return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
95398
95793
  } catch {
95399
95794
  return false;
@@ -95402,20 +95797,20 @@ function sameProposalFile(left, right) {
95402
95797
  function cleanupProposalPublication(p) {
95403
95798
  for (const filePath of [p.publishPath, p.displacedPath]) {
95404
95799
  try {
95405
- fs47.rmSync(filePath, { force: true });
95800
+ fs49.rmSync(filePath, { force: true });
95406
95801
  } catch (error2) {
95407
95802
  warn(`[proposals] transaction publication cleanup failed at ${filePath}: ${error2 instanceof Error ? error2.message : String(error2)}`);
95408
95803
  }
95409
95804
  }
95410
- fsyncTxnDir(path60.dirname(p.assetPath));
95805
+ fsyncTxnDir(path61.dirname(p.assetPath));
95411
95806
  }
95412
95807
  function rollbackPreparedProposalTransaction(txn) {
95413
95808
  const p = txn.journal.payload;
95414
- const currentHash = fs47.existsSync(p.assetPath) ? proposalFileHash(p.assetPath) : null;
95415
- if (!fs47.existsSync(p.displacedPath)) {
95809
+ const currentHash = fs49.existsSync(p.assetPath) ? proposalFileHash(p.assetPath) : null;
95810
+ if (!fs49.existsSync(p.displacedPath)) {
95416
95811
  if (p.originalHash === null) {
95417
95812
  if (currentHash === p.publishedHash && sameProposalFile(p.assetPath, p.publishPath)) {
95418
- fs47.unlinkSync(p.assetPath);
95813
+ fs49.unlinkSync(p.assetPath);
95419
95814
  recordWrittenPath(p.assetPath);
95420
95815
  } else if (currentHash !== null) {
95421
95816
  throw new Error(`Cannot roll back proposal transaction: target was created externally.`);
@@ -95427,30 +95822,30 @@ function rollbackPreparedProposalTransaction(txn) {
95427
95822
  return;
95428
95823
  }
95429
95824
  if (currentHash === p.publishedHash) {
95430
- fs47.unlinkSync(p.assetPath);
95825
+ fs49.unlinkSync(p.assetPath);
95431
95826
  recordWrittenPath(p.assetPath);
95432
95827
  } else if (currentHash !== null && currentHash !== p.originalHash) {
95433
95828
  throw new Error(`Cannot roll back proposal transaction: ${p.assetPath} diverged.`);
95434
95829
  }
95435
- if (fs47.existsSync(p.displacedPath)) {
95436
- if (fs47.existsSync(p.assetPath)) {
95830
+ if (fs49.existsSync(p.displacedPath)) {
95831
+ if (fs49.existsSync(p.assetPath)) {
95437
95832
  throw new Error(`Cannot restore proposal backup: ${p.assetPath} is occupied.`);
95438
95833
  }
95439
- fs47.linkSync(p.displacedPath, p.assetPath);
95834
+ fs49.linkSync(p.displacedPath, p.assetPath);
95440
95835
  recordWrittenPath(p.assetPath);
95441
95836
  }
95442
95837
  cleanupProposalPublication(p);
95443
95838
  }
95444
95839
  function validatePublishedProposal(p) {
95445
- if (!fs47.existsSync(p.assetPath) || proposalFileHash(p.assetPath) !== p.publishedHash) {
95840
+ if (!fs49.existsSync(p.assetPath) || proposalFileHash(p.assetPath) !== p.publishedHash) {
95446
95841
  throw new Error(`Cannot recover proposal ${p.proposalId}: published asset diverged.`);
95447
95842
  }
95448
95843
  }
95449
95844
  function persistProposalTransactionState(txn, proposal, ctx) {
95450
95845
  const p = txn.journal.payload;
95451
95846
  const decidedAt = txn.journal.decidedAt;
95452
- const backupContent = p.backupPath ? fs47.readFileSync(p.backupPath, "utf8") : undefined;
95453
- const publishedContent = fs47.readFileSync(p.contentPath, "utf8");
95847
+ const backupContent = p.backupPath ? fs49.readFileSync(p.backupPath, "utf8") : undefined;
95848
+ const publishedContent = fs49.readFileSync(p.contentPath, "utf8");
95454
95849
  return withProposalsDb(p.stashDir, ctx, (db) => withImmediateTransaction(db, () => {
95455
95850
  const current = requireProposal(db, p.stashDir, p.proposalId);
95456
95851
  if (p.operation === "accept") {
@@ -95468,7 +95863,7 @@ function persistProposalTransactionState(txn, proposal, ctx) {
95468
95863
  payload: { ...proposal.payload, content: publishedContent },
95469
95864
  changes: [
95470
95865
  {
95471
- path: path60.relative(txn.journal.root, p.assetPath),
95866
+ path: path61.relative(txn.journal.root, p.assetPath),
95472
95867
  op: p.originalHash === null ? "create" : "update",
95473
95868
  after: publishedContent
95474
95869
  }
@@ -95539,7 +95934,7 @@ async function finalizeProposalTransaction(txn, target, proposal, ctx) {
95539
95934
  cleanupProposalPublication(p);
95540
95935
  if (txn.journal.phase === "asset-published") {
95541
95936
  const commitRoot = target.source.repoPath ?? target.source.path;
95542
- const commitPath = path60.relative(commitRoot, p.assetPath).replaceAll(path60.sep, "/");
95937
+ const commitPath = path61.relative(commitRoot, p.assetPath).replaceAll(path61.sep, "/");
95543
95938
  publishWriteTargetTransaction(target, p.gitPublication, {
95544
95939
  transactionId: txn.journal.transactionId,
95545
95940
  message: `${p.operation === "accept" ? "Update" : "Revert"} ${p.ref}`,
@@ -95576,8 +95971,8 @@ async function finalizeProposalTransaction(txn, target, proposal, ctx) {
95576
95971
  function fenceProposalTxnJournal(journal, txnDir, root2) {
95577
95972
  const p = journal.payload;
95578
95973
  const refIdentity = proposalRefIdentity(p.ref);
95579
- if (!["accept", "revert"].includes(p.operation) || !p.targetSource || !p.targetKind || refIdentity?.bundle === undefined || !isWithin(p.assetPath, root2) || ![p.contentPath, p.backupPath].filter((candidate) => candidate !== null).every((candidate) => isWithin(candidate, txnDir)) || ![p.publishPath, p.displacedPath].every((candidate) => isWithin(candidate, root2) && path60.dirname(candidate) === path60.dirname(p.assetPath))) {
95580
- throw new Error(`Refusing unsafe proposal transaction journal at ${path60.join(txnDir, "journal.json")}.`);
95974
+ if (!["accept", "revert"].includes(p.operation) || !p.targetSource || !p.targetKind || refIdentity?.bundle === undefined || !isWithin(p.assetPath, root2) || ![p.contentPath, p.backupPath].filter((candidate) => candidate !== null).every((candidate) => isWithin(candidate, txnDir)) || ![p.publishPath, p.displacedPath].every((candidate) => isWithin(candidate, root2) && path61.dirname(candidate) === path61.dirname(p.assetPath))) {
95975
+ throw new Error(`Refusing unsafe proposal transaction journal at ${path61.join(txnDir, "journal.json")}.`);
95581
95976
  }
95582
95977
  }
95583
95978
  function resolveProposalRecoveryTarget(config, journal) {
@@ -95677,8 +96072,8 @@ async function recoverStaleTxns(stashDir) {
95677
96072
  }
95678
96073
 
95679
96074
  // scripts/akm-migrate/migrate/writer-relocation.ts
95680
- import fs48 from "fs";
95681
- import path61 from "path";
96075
+ import fs50 from "fs";
96076
+ import path62 from "path";
95682
96077
  init_paths();
95683
96078
  function relocationSpecs(stashDir) {
95684
96079
  return [
@@ -95698,7 +96093,7 @@ function mutexSiblingName(lockName) {
95698
96093
  function fileCountIfExists(dir) {
95699
96094
  let entries;
95700
96095
  try {
95701
- entries = fs48.readdirSync(dir, { withFileTypes: true });
96096
+ entries = fs50.readdirSync(dir, { withFileTypes: true });
95702
96097
  } catch {
95703
96098
  return;
95704
96099
  }
@@ -95706,7 +96101,7 @@ function fileCountIfExists(dir) {
95706
96101
  }
95707
96102
  function statFileIfExists(filePath) {
95708
96103
  try {
95709
- const stat = fs48.statSync(filePath);
96104
+ const stat = fs50.statSync(filePath);
95710
96105
  return stat.isFile() ? stat : undefined;
95711
96106
  } catch {
95712
96107
  return;
@@ -95716,8 +96111,8 @@ function classifyLockArtifacts(akmDir) {
95716
96111
  const removable = [];
95717
96112
  const skipped = [];
95718
96113
  for (const lockName of LOCK_NAMES) {
95719
- const lockPath = path61.join(akmDir, lockName);
95720
- const mutexPath = path61.join(akmDir, mutexSiblingName(lockName));
96114
+ const lockPath = path62.join(akmDir, lockName);
96115
+ const mutexPath = path62.join(akmDir, mutexSiblingName(lockName));
95721
96116
  const lockStat = statFileIfExists(lockPath);
95722
96117
  const mutexStat = statFileIfExists(mutexPath);
95723
96118
  if (!lockStat) {
@@ -95743,11 +96138,11 @@ function classifyLockArtifacts(akmDir) {
95743
96138
  return { removable, skipped };
95744
96139
  }
95745
96140
  function findWriterRelocationEntries(stashDir) {
95746
- const akmDir = path61.join(stashDir, ".akm");
96141
+ const akmDir = path62.join(stashDir, ".akm");
95747
96142
  const directories = [];
95748
96143
  for (const spec of relocationSpecs(stashDir)) {
95749
96144
  const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
95750
- const oldPath = path61.join(akmDir, ...relativeParts);
96145
+ const oldPath = path62.join(akmDir, ...relativeParts);
95751
96146
  const fileCount = fileCountIfExists(oldPath);
95752
96147
  if (fileCount === undefined || fileCount === 0)
95753
96148
  continue;
@@ -95758,36 +96153,36 @@ function findWriterRelocationEntries(stashDir) {
95758
96153
  }
95759
96154
  function moveFile(oldFilePath, newFilePath) {
95760
96155
  try {
95761
- fs48.renameSync(oldFilePath, newFilePath);
96156
+ fs50.renameSync(oldFilePath, newFilePath);
95762
96157
  } catch (error2) {
95763
96158
  if (error2.code !== "EXDEV")
95764
96159
  throw error2;
95765
- fs48.copyFileSync(oldFilePath, newFilePath);
95766
- fs48.rmSync(oldFilePath, { force: true });
96160
+ fs50.copyFileSync(oldFilePath, newFilePath);
96161
+ fs50.rmSync(oldFilePath, { force: true });
95767
96162
  }
95768
96163
  }
95769
96164
  function moveDirectoryContents(entry) {
95770
96165
  const errors3 = [];
95771
96166
  let moved = 0;
95772
- fs48.mkdirSync(entry.newPath, { recursive: true });
96167
+ fs50.mkdirSync(entry.newPath, { recursive: true });
95773
96168
  let names;
95774
96169
  try {
95775
- names = fs48.readdirSync(entry.oldPath).sort();
96170
+ names = fs50.readdirSync(entry.oldPath).sort();
95776
96171
  } catch {
95777
96172
  return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved: 0, errors: [] };
95778
96173
  }
95779
96174
  for (const name of names) {
95780
- const oldFilePath = path61.join(entry.oldPath, name);
95781
- const newFilePath = path61.join(entry.newPath, name);
96175
+ const oldFilePath = path62.join(entry.oldPath, name);
96176
+ const newFilePath = path62.join(entry.newPath, name);
95782
96177
  let oldStat;
95783
96178
  try {
95784
- oldStat = fs48.lstatSync(oldFilePath);
96179
+ oldStat = fs50.lstatSync(oldFilePath);
95785
96180
  } catch {
95786
96181
  continue;
95787
96182
  }
95788
96183
  if (!oldStat.isFile())
95789
96184
  continue;
95790
- if (fs48.existsSync(newFilePath))
96185
+ if (fs50.existsSync(newFilePath))
95791
96186
  continue;
95792
96187
  try {
95793
96188
  moveFile(oldFilePath, newFilePath);
@@ -95800,13 +96195,13 @@ function moveDirectoryContents(entry) {
95800
96195
  }
95801
96196
  function removeIfEmptyDir(dir) {
95802
96197
  try {
95803
- if (fs48.readdirSync(dir).length === 0)
95804
- fs48.rmdirSync(dir);
96198
+ if (fs50.readdirSync(dir).length === 0)
96199
+ fs50.rmdirSync(dir);
95805
96200
  } catch {}
95806
96201
  }
95807
96202
  function removeLockArtifact(entry) {
95808
96203
  try {
95809
- fs48.rmSync(entry.path, { force: true });
96204
+ fs50.rmSync(entry.path, { force: true });
95810
96205
  return { path: entry.path, removed: true };
95811
96206
  } catch (error2) {
95812
96207
  return { path: entry.path, removed: false, error: error2 instanceof Error ? error2.message : String(error2) };
@@ -95818,36 +96213,36 @@ function applyWriterRelocation(stashDir) {
95818
96213
  const lockResults = lockArtifacts.map(removeLockArtifact);
95819
96214
  for (const spec of relocationSpecs(stashDir)) {
95820
96215
  const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
95821
- removeIfEmptyDir(path61.join(stashDir, ".akm", ...relativeParts));
96216
+ removeIfEmptyDir(path62.join(stashDir, ".akm", ...relativeParts));
95822
96217
  }
95823
96218
  return { directories: directoryResults, lockArtifacts: lockResults, skippedLocks };
95824
96219
  }
95825
96220
 
95826
96221
  // scripts/akm-migrate/task-migrate.ts
95827
96222
  import { randomUUID as randomUUID7 } from "crypto";
95828
- import fs53 from "fs";
96223
+ import fs56 from "fs";
95829
96224
  import os5 from "os";
95830
- import path64 from "path";
96225
+ import path65 from "path";
95831
96226
  init_errors();
95832
96227
  init_paths();
95833
96228
 
95834
96229
  // scripts/akm-migrate/migrate/task-files-to-v3.ts
95835
96230
  init_errors();
95836
96231
  import crypto6 from "crypto";
95837
- import fs50 from "fs";
95838
- import path62 from "path";
96232
+ import fs53 from "fs";
96233
+ import path63 from "path";
95839
96234
 
95840
96235
  // scripts/akm-migrate/migrate/durable-fs.ts
95841
- import fs49 from "fs";
96236
+ import fs51 from "fs";
95842
96237
  function fsyncDirectoryPortable(directory) {
95843
96238
  if (process.platform === "win32")
95844
96239
  return;
95845
96240
  try {
95846
- const fd = fs49.openSync(directory, "r");
96241
+ const fd = fs51.openSync(directory, "r");
95847
96242
  try {
95848
- fs49.fsyncSync(fd);
96243
+ fs51.fsyncSync(fd);
95849
96244
  } finally {
95850
- fs49.closeSync(fd);
96245
+ fs51.closeSync(fd);
95851
96246
  }
95852
96247
  } catch (cause) {
95853
96248
  const code = cause.code;
@@ -95861,25 +96256,25 @@ function migrationError(detail) {
95861
96256
  return new ConfigError(`Task migration to v3 failed: ${detail}`, "INVALID_CONFIG_FILE");
95862
96257
  }
95863
96258
  function contained2(root2, candidate) {
95864
- const relative = path62.relative(root2, candidate);
95865
- return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
96259
+ const relative = path63.relative(root2, candidate);
96260
+ return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
95866
96261
  }
95867
96262
  function realDirectory(filePath) {
95868
- const stat = fs50.lstatSync(filePath);
96263
+ const stat = fs53.lstatSync(filePath);
95869
96264
  if (stat.isSymbolicLink() || !stat.isDirectory())
95870
96265
  throw migrationError(`${filePath} must be a real directory.`);
95871
- return fs50.realpathSync(filePath);
96266
+ return fs53.realpathSync(filePath);
95872
96267
  }
95873
96268
  function snapshot(filePath) {
95874
- const stat = fs50.lstatSync(filePath);
96269
+ const stat = fs53.lstatSync(filePath);
95875
96270
  if (stat.isSymbolicLink() || !stat.isFile())
95876
96271
  throw migrationError(`${filePath} must be a real file.`);
95877
- const bytes = fs50.readFileSync(filePath);
96272
+ const bytes = fs53.readFileSync(filePath);
95878
96273
  return Object.freeze({ bytes, mode: stat.mode & 511 });
95879
96274
  }
95880
96275
  function writable(filePath) {
95881
96276
  try {
95882
- fs50.accessSync(filePath, fs50.constants.W_OK);
96277
+ fs53.accessSync(filePath, fs53.constants.W_OK);
95883
96278
  return true;
95884
96279
  } catch {
95885
96280
  return false;
@@ -95892,12 +96287,12 @@ function walkTasks(root2, tasksDir, out) {
95892
96287
  throw migrationError(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
95893
96288
  }
95894
96289
  const visit2 = (directory) => {
95895
- const physicalDirectory = fs50.realpathSync(directory);
96290
+ const physicalDirectory = fs53.realpathSync(directory);
95896
96291
  if (!contained2(physicalRoot, physicalDirectory)) {
95897
96292
  throw migrationError(`${directory} resolves outside bundle ${root2.bundleId}.`);
95898
96293
  }
95899
- for (const entry of fs50.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
95900
- const candidate = path62.join(directory, entry.name);
96294
+ for (const entry of fs53.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
96295
+ const candidate = path63.join(directory, entry.name);
95901
96296
  if (entry.isSymbolicLink())
95902
96297
  throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
95903
96298
  if (entry.isDirectory()) {
@@ -95907,7 +96302,7 @@ function walkTasks(root2, tasksDir, out) {
95907
96302
  if (!entry.isFile() || !entry.name.endsWith(".yml"))
95908
96303
  continue;
95909
96304
  const current = snapshot(candidate);
95910
- const parent = path62.dirname(candidate);
96305
+ const parent = path63.dirname(candidate);
95911
96306
  out.push({
95912
96307
  filePath: candidate,
95913
96308
  bytes: current.bytes,
@@ -95923,9 +96318,9 @@ function walkTasks(root2, tasksDir, out) {
95923
96318
  function inspectTaskToV3Files(roots) {
95924
96319
  const files = [];
95925
96320
  for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
95926
- const tasksDir = root2.layout === "akm-task" ? root2.root : path62.join(root2.root, "tasks");
96321
+ const tasksDir = root2.layout === "akm-task" ? root2.root : path63.join(root2.root, "tasks");
95927
96322
  try {
95928
- const stat = fs50.lstatSync(tasksDir);
96323
+ const stat = fs53.lstatSync(tasksDir);
95929
96324
  if (stat.isSymbolicLink())
95930
96325
  throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
95931
96326
  if (!stat.isDirectory())
@@ -95940,33 +96335,33 @@ function inspectTaskToV3Files(roots) {
95940
96335
  return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
95941
96336
  }
95942
96337
  function hashPath(filePath) {
95943
- return crypto6.createHash("sha256").update(path62.resolve(filePath)).digest("hex").slice(0, 16);
96338
+ return crypto6.createHash("sha256").update(path63.resolve(filePath)).digest("hex").slice(0, 16);
95944
96339
  }
95945
96340
  function taskMigrationBackupPath(backupRoot, filePath) {
95946
- return path62.join(backupRoot, "files", `${hashPath(filePath)}-${path62.basename(filePath)}`);
96341
+ return path63.join(backupRoot, "files", `${hashPath(filePath)}-${path63.basename(filePath)}`);
95947
96342
  }
95948
96343
  function writeDurable(filePath, bytes, mode, exclusive = false) {
95949
- fs50.mkdirSync(path62.dirname(filePath), { recursive: true });
96344
+ fs53.mkdirSync(path63.dirname(filePath), { recursive: true });
95950
96345
  const flags = exclusive ? "wx" : "w";
95951
- const fd = fs50.openSync(filePath, flags, mode);
96346
+ const fd = fs53.openSync(filePath, flags, mode);
95952
96347
  try {
95953
- fs50.writeFileSync(fd, bytes);
95954
- fs50.fsyncSync(fd);
96348
+ fs53.writeFileSync(fd, bytes);
96349
+ fs53.fsyncSync(fd);
95955
96350
  } finally {
95956
- fs50.closeSync(fd);
96351
+ fs53.closeSync(fd);
95957
96352
  }
95958
- fs50.chmodSync(filePath, mode);
95959
- fsyncDirectoryPortable(path62.dirname(filePath));
96353
+ fs53.chmodSync(filePath, mode);
96354
+ fsyncDirectoryPortable(path63.dirname(filePath));
95960
96355
  }
95961
96356
  function replaceAtomically(filePath, bytes, mode) {
95962
- const temporary = path62.join(path62.dirname(filePath), `.${path62.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
96357
+ const temporary = path63.join(path63.dirname(filePath), `.${path63.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
95963
96358
  try {
95964
96359
  writeDurable(temporary, bytes, mode, true);
95965
- fs50.renameSync(temporary, filePath);
95966
- fsyncDirectoryPortable(path62.dirname(filePath));
96360
+ fs53.renameSync(temporary, filePath);
96361
+ fsyncDirectoryPortable(path63.dirname(filePath));
95967
96362
  } finally {
95968
96363
  try {
95969
- fs50.unlinkSync(temporary);
96364
+ fs53.unlinkSync(temporary);
95970
96365
  } catch (cause) {
95971
96366
  if (cause.code !== "ENOENT")
95972
96367
  throw cause;
@@ -96005,7 +96400,7 @@ function applyTaskToV3MigrationPlan(plan, options) {
96005
96400
  const current = snapshot(change.filePath);
96006
96401
  if (!current.bytes.equals(change.after))
96007
96402
  continue;
96008
- replaceAtomically(change.filePath, fs50.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
96403
+ replaceAtomically(change.filePath, fs53.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
96009
96404
  }
96010
96405
  throw cause;
96011
96406
  }
@@ -96015,31 +96410,31 @@ function applyTaskToV3MigrationPlan(plan, options) {
96015
96410
  // scripts/akm-migrate/migrate/task-files-to-v4.ts
96016
96411
  init_errors();
96017
96412
  import crypto7 from "crypto";
96018
- import fs51 from "fs";
96019
- import path63 from "path";
96413
+ import fs55 from "fs";
96414
+ import path64 from "path";
96020
96415
  function migrationError2(detail) {
96021
96416
  return new ConfigError(`Task migration to v4 failed: ${detail}`, "INVALID_CONFIG_FILE");
96022
96417
  }
96023
96418
  function contained3(root2, candidate) {
96024
- const relative = path63.relative(root2, candidate);
96025
- return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
96419
+ const relative = path64.relative(root2, candidate);
96420
+ return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
96026
96421
  }
96027
96422
  function realDirectory2(filePath) {
96028
- const stat = fs51.lstatSync(filePath);
96423
+ const stat = fs55.lstatSync(filePath);
96029
96424
  if (stat.isSymbolicLink() || !stat.isDirectory())
96030
96425
  throw migrationError2(`${filePath} must be a real directory.`);
96031
- return fs51.realpathSync(filePath);
96426
+ return fs55.realpathSync(filePath);
96032
96427
  }
96033
96428
  function snapshot2(filePath) {
96034
- const stat = fs51.lstatSync(filePath);
96429
+ const stat = fs55.lstatSync(filePath);
96035
96430
  if (stat.isSymbolicLink() || !stat.isFile())
96036
96431
  throw migrationError2(`${filePath} must be a real file.`);
96037
- const bytes = fs51.readFileSync(filePath);
96432
+ const bytes = fs55.readFileSync(filePath);
96038
96433
  return Object.freeze({ bytes, mode: stat.mode & 511 });
96039
96434
  }
96040
96435
  function writable2(filePath) {
96041
96436
  try {
96042
- fs51.accessSync(filePath, fs51.constants.W_OK);
96437
+ fs55.accessSync(filePath, fs55.constants.W_OK);
96043
96438
  return true;
96044
96439
  } catch {
96045
96440
  return false;
@@ -96052,12 +96447,12 @@ function walkTasks2(root2, tasksDir, out) {
96052
96447
  throw migrationError2(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
96053
96448
  }
96054
96449
  const visit2 = (directory) => {
96055
- const physicalDirectory = fs51.realpathSync(directory);
96450
+ const physicalDirectory = fs55.realpathSync(directory);
96056
96451
  if (!contained3(physicalRoot, physicalDirectory)) {
96057
96452
  throw migrationError2(`${directory} resolves outside bundle ${root2.bundleId}.`);
96058
96453
  }
96059
- for (const entry of fs51.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
96060
- const candidate = path63.join(directory, entry.name);
96454
+ for (const entry of fs55.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
96455
+ const candidate = path64.join(directory, entry.name);
96061
96456
  if (entry.isSymbolicLink())
96062
96457
  throw migrationError2(`task migration does not follow symbolic link ${candidate}.`);
96063
96458
  if (entry.isDirectory()) {
@@ -96067,7 +96462,7 @@ function walkTasks2(root2, tasksDir, out) {
96067
96462
  if (!entry.isFile() || !entry.name.endsWith(".yml"))
96068
96463
  continue;
96069
96464
  const current = snapshot2(candidate);
96070
- const parent = path63.dirname(candidate);
96465
+ const parent = path64.dirname(candidate);
96071
96466
  out.push({
96072
96467
  filePath: candidate,
96073
96468
  bytes: current.bytes,
@@ -96083,9 +96478,9 @@ function walkTasks2(root2, tasksDir, out) {
96083
96478
  function inspectTaskToV4Files(roots) {
96084
96479
  const files = [];
96085
96480
  for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
96086
- const tasksDir = root2.layout === "akm-task" ? root2.root : path63.join(root2.root, "tasks");
96481
+ const tasksDir = root2.layout === "akm-task" ? root2.root : path64.join(root2.root, "tasks");
96087
96482
  try {
96088
- const stat = fs51.lstatSync(tasksDir);
96483
+ const stat = fs55.lstatSync(tasksDir);
96089
96484
  if (stat.isSymbolicLink())
96090
96485
  throw migrationError2(`task migration does not follow symbolic link ${tasksDir}.`);
96091
96486
  if (!stat.isDirectory())
@@ -96100,33 +96495,33 @@ function inspectTaskToV4Files(roots) {
96100
96495
  return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
96101
96496
  }
96102
96497
  function hashPath2(filePath) {
96103
- return crypto7.createHash("sha256").update(path63.resolve(filePath)).digest("hex").slice(0, 16);
96498
+ return crypto7.createHash("sha256").update(path64.resolve(filePath)).digest("hex").slice(0, 16);
96104
96499
  }
96105
96500
  function taskMigrationBackupPathV4(backupRoot, filePath) {
96106
- return path63.join(backupRoot, "files", `${hashPath2(filePath)}-${path63.basename(filePath)}`);
96501
+ return path64.join(backupRoot, "files", `${hashPath2(filePath)}-${path64.basename(filePath)}`);
96107
96502
  }
96108
96503
  function writeDurable2(filePath, bytes, mode, exclusive = false) {
96109
- fs51.mkdirSync(path63.dirname(filePath), { recursive: true });
96504
+ fs55.mkdirSync(path64.dirname(filePath), { recursive: true });
96110
96505
  const flags = exclusive ? "wx" : "w";
96111
- const fd = fs51.openSync(filePath, flags, mode);
96506
+ const fd = fs55.openSync(filePath, flags, mode);
96112
96507
  try {
96113
- fs51.writeFileSync(fd, bytes);
96114
- fs51.fsyncSync(fd);
96508
+ fs55.writeFileSync(fd, bytes);
96509
+ fs55.fsyncSync(fd);
96115
96510
  } finally {
96116
- fs51.closeSync(fd);
96511
+ fs55.closeSync(fd);
96117
96512
  }
96118
- fs51.chmodSync(filePath, mode);
96119
- fsyncDirectoryPortable(path63.dirname(filePath));
96513
+ fs55.chmodSync(filePath, mode);
96514
+ fsyncDirectoryPortable(path64.dirname(filePath));
96120
96515
  }
96121
96516
  function replaceAtomically2(filePath, bytes, mode) {
96122
- const temporary = path63.join(path63.dirname(filePath), `.${path63.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
96517
+ const temporary = path64.join(path64.dirname(filePath), `.${path64.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
96123
96518
  try {
96124
96519
  writeDurable2(temporary, bytes, mode, true);
96125
- fs51.renameSync(temporary, filePath);
96126
- fsyncDirectoryPortable(path63.dirname(filePath));
96520
+ fs55.renameSync(temporary, filePath);
96521
+ fsyncDirectoryPortable(path64.dirname(filePath));
96127
96522
  } finally {
96128
96523
  try {
96129
- fs51.unlinkSync(temporary);
96524
+ fs55.unlinkSync(temporary);
96130
96525
  } catch (cause) {
96131
96526
  if (cause.code !== "ENOENT")
96132
96527
  throw cause;
@@ -96165,7 +96560,7 @@ function applyTaskToV4MigrationPlan(plan, options) {
96165
96560
  const current = snapshot2(change.filePath);
96166
96561
  if (!current.bytes.equals(change.after))
96167
96562
  continue;
96168
- replaceAtomically2(change.filePath, fs51.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
96563
+ replaceAtomically2(change.filePath, fs55.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
96169
96564
  }
96170
96565
  throw cause;
96171
96566
  }
@@ -96177,12 +96572,12 @@ function expandTilde(value) {
96177
96572
  if (value === "~")
96178
96573
  return os5.homedir();
96179
96574
  if (value.startsWith("~/") || value.startsWith("~\\"))
96180
- return path64.join(os5.homedir(), value.slice(2));
96575
+ return path65.join(os5.homedir(), value.slice(2));
96181
96576
  return value;
96182
96577
  }
96183
96578
  function existingDirectory(target) {
96184
96579
  try {
96185
- return fs53.statSync(target).isDirectory();
96580
+ return fs56.statSync(target).isDirectory();
96186
96581
  } catch (cause) {
96187
96582
  if (cause.code === "ENOENT")
96188
96583
  return false;
@@ -96203,21 +96598,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
96203
96598
  const source = sources.get(bundleId);
96204
96599
  if (!source)
96205
96600
  continue;
96206
- const configuredRoot = source.type === "filesystem" && source.path ? path64.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
96601
+ const configuredRoot = source.type === "filesystem" && source.path ? path65.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
96207
96602
  if (!configuredRoot || !existingDirectory(configuredRoot))
96208
96603
  continue;
96209
- const bundleRoot = path64.resolve(configuredRoot);
96604
+ const bundleRoot = path65.resolve(configuredRoot);
96210
96605
  const component = bundleComponentConfig(bundle);
96211
- const componentRoot = path64.resolve(bundleRoot, component?.root ?? ".");
96212
- const relative = path64.relative(bundleRoot, componentRoot);
96213
- if (relative === ".." || relative.startsWith(`..${path64.sep}`) || path64.isAbsolute(relative)) {
96606
+ const componentRoot = path65.resolve(bundleRoot, component?.root ?? ".");
96607
+ const relative = path65.relative(bundleRoot, componentRoot);
96608
+ if (relative === ".." || relative.startsWith(`..${path65.sep}`) || path65.isAbsolute(relative)) {
96214
96609
  throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
96215
96610
  }
96216
96611
  if (!existingDirectory(componentRoot))
96217
96612
  continue;
96218
96613
  const adapter = component?.adapter ?? detectAdapterId(componentRoot, "");
96219
96614
  if (!component?.adapter && adapter === "") {
96220
- const flatTasks = fs53.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
96615
+ const flatTasks = fs56.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
96221
96616
  if (flatTasks.length > 0) {
96222
96617
  throw new ConfigError(`Task migration cannot classify top-level task file(s) ${flatTasks.join(", ")} in bundle ${bundleId}; configure adapter "akm-task" or move them under tasks/.`, "INVALID_CONFIG_FILE");
96223
96618
  }
@@ -96289,8 +96684,8 @@ function applyTaskV3Migration() {
96289
96684
  const before = inspectCurrentTaskPlan();
96290
96685
  if (before.result.taskV3Migration.changed === 0)
96291
96686
  return before.result;
96292
- const backupRoot = path64.join(getDataDir(), "backups", "task-v3");
96293
- const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96687
+ const backupRoot = path65.join(getDataDir(), "backups", "task-v3");
96688
+ const backupPath = path65.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96294
96689
  const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
96295
96690
  const after = inspectCurrentTaskPlan().result;
96296
96691
  if (after.taskV3Migration.changed > 0) {
@@ -96346,8 +96741,8 @@ function applyTaskV4Migration() {
96346
96741
  const before = inspectCurrentTaskV4Plan();
96347
96742
  if (before.result.taskV4Migration.changed === 0)
96348
96743
  return before.result;
96349
- const backupRoot = path64.join(getDataDir(), "backups", "task-v4");
96350
- const backupPath = path64.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96744
+ const backupRoot = path65.join(getDataDir(), "backups", "task-v4");
96745
+ const backupPath = path65.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
96351
96746
  const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
96352
96747
  const after = inspectCurrentTaskV4Plan().result;
96353
96748
  if (after.taskV4Migration.changed > 0) {