akm-cli 0.9.0-beta.5 → 0.9.0-beta.50

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 (207) hide show
  1. package/CHANGELOG.md +709 -0
  2. package/dist/assets/profiles/default.json +9 -4
  3. package/dist/assets/profiles/frequent.json +1 -1
  4. package/dist/assets/profiles/memory-focus.json +1 -1
  5. package/dist/assets/profiles/quick.json +1 -1
  6. package/dist/assets/profiles/synthesize.json +15 -0
  7. package/dist/assets/profiles/thorough.json +1 -1
  8. package/dist/assets/prompts/consolidate-system.md +23 -0
  9. package/dist/assets/prompts/contradiction-judge.md +33 -0
  10. package/dist/assets/prompts/distill-knowledge-system.md +22 -0
  11. package/dist/assets/prompts/distill-lesson-system.md +36 -0
  12. package/dist/assets/prompts/extract-session.md +6 -2
  13. package/dist/assets/prompts/graph-extract-system.md +1 -0
  14. package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
  15. package/dist/assets/prompts/memory-infer-system.md +1 -0
  16. package/dist/assets/prompts/memory-infer-user.md +5 -0
  17. package/dist/assets/prompts/metadata-enhance-system.md +1 -0
  18. package/dist/assets/prompts/procedural-system.md +44 -0
  19. package/dist/assets/prompts/recombine-system.md +40 -0
  20. package/dist/assets/prompts/staleness-detect-system.md +6 -0
  21. package/dist/assets/prompts/validate-summary-judge.md +1 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
  23. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
  24. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
  25. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
  26. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
  27. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
  28. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
  29. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
  30. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
  31. package/dist/assets/templates/html/health.html +281 -111
  32. package/dist/assets/wiki/ingest-workflow-template.md +17 -10
  33. package/dist/cli/shared.js +28 -0
  34. package/dist/cli.js +15 -5
  35. package/dist/commands/agent/agent-dispatch.js +2 -2
  36. package/dist/commands/agent/agent-support.js +0 -7
  37. package/dist/commands/agent/contribute-cli.js +17 -4
  38. package/dist/commands/env/env-cli.js +16 -24
  39. package/dist/commands/env/secret-cli.js +12 -20
  40. package/dist/commands/feedback-cli.js +15 -6
  41. package/dist/commands/graph/graph-cli.js +5 -13
  42. package/dist/commands/graph/graph.js +76 -72
  43. package/dist/commands/health/checks.js +48 -0
  44. package/dist/commands/health/html-report.js +422 -80
  45. package/dist/commands/health.js +386 -9
  46. package/dist/commands/improve/calibration.js +161 -0
  47. package/dist/commands/improve/consolidate/chunking.js +141 -0
  48. package/dist/commands/improve/consolidate/eligibility.js +81 -0
  49. package/dist/commands/improve/consolidate/merge.js +145 -0
  50. package/dist/commands/improve/consolidate/sanitize.js +231 -0
  51. package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
  52. package/dist/commands/improve/consolidate.js +635 -660
  53. package/dist/commands/improve/dedup.js +482 -0
  54. package/dist/commands/improve/distill.js +159 -69
  55. package/dist/commands/improve/eligibility.js +434 -0
  56. package/dist/commands/improve/encoding-salience.js +205 -0
  57. package/dist/commands/improve/extract-cli.js +124 -2
  58. package/dist/commands/improve/extract-prompt.js +39 -2
  59. package/dist/commands/improve/extract-watch.js +140 -0
  60. package/dist/commands/improve/extract.js +389 -40
  61. package/dist/commands/improve/feedback-valence.js +54 -0
  62. package/dist/commands/improve/homeostatic.js +467 -0
  63. package/dist/commands/improve/improve-auto-accept.js +109 -6
  64. package/dist/commands/improve/improve-cli.js +35 -60
  65. package/dist/commands/improve/improve-profiles.js +14 -0
  66. package/dist/commands/improve/improve-result-file.js +5 -23
  67. package/dist/commands/improve/improve-session.js +58 -0
  68. package/dist/commands/improve/improve.js +485 -2498
  69. package/dist/commands/improve/locks.js +154 -0
  70. package/dist/commands/improve/loop-stages.js +1083 -0
  71. package/dist/commands/improve/memory/memory-contradiction-detect.js +23 -28
  72. package/dist/commands/improve/outcome-loop.js +256 -0
  73. package/dist/commands/improve/preparation.js +1966 -0
  74. package/dist/commands/improve/proactive-maintenance.js +115 -0
  75. package/dist/commands/improve/procedural.js +418 -0
  76. package/dist/commands/improve/recombine.js +813 -0
  77. package/dist/commands/improve/reflect-noise.js +0 -0
  78. package/dist/commands/improve/reflect.js +183 -40
  79. package/dist/commands/improve/salience.js +438 -0
  80. package/dist/commands/improve/triage.js +93 -0
  81. package/dist/commands/lint/agent-linter.js +19 -24
  82. package/dist/commands/lint/base-linter.js +173 -60
  83. package/dist/commands/lint/command-linter.js +19 -24
  84. package/dist/commands/lint/env-key-rules.js +34 -1
  85. package/dist/commands/lint/fact-linter.js +39 -0
  86. package/dist/commands/lint/index.js +31 -13
  87. package/dist/commands/lint/memory-linter.js +1 -1
  88. package/dist/commands/lint/registry.js +7 -2
  89. package/dist/commands/lint/task-linter.js +3 -3
  90. package/dist/commands/lint/workflow-linter.js +26 -1
  91. package/dist/commands/proposal/drain-policies.js +5 -0
  92. package/dist/commands/proposal/drain.js +43 -50
  93. package/dist/commands/proposal/proposal-cli.js +21 -31
  94. package/dist/commands/proposal/proposal.js +5 -0
  95. package/dist/commands/proposal/propose.js +7 -2
  96. package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
  97. package/dist/commands/proposal/validators/proposals.js +189 -63
  98. package/dist/commands/read/curate.js +414 -94
  99. package/dist/commands/read/knowledge.js +2 -2
  100. package/dist/commands/read/search-cli.js +7 -0
  101. package/dist/commands/read/search.js +1 -0
  102. package/dist/commands/read/show.js +67 -2
  103. package/dist/commands/sources/init.js +36 -9
  104. package/dist/commands/sources/installed-stashes.js +5 -1
  105. package/dist/commands/sources/schema-repair.js +13 -1
  106. package/dist/commands/sources/self-update.js +2 -2
  107. package/dist/commands/sources/stash-cli.js +28 -40
  108. package/dist/commands/sources/stash-skeleton.js +23 -8
  109. package/dist/commands/tasks/tasks-cli.js +19 -27
  110. package/dist/commands/tasks/tasks.js +1 -1
  111. package/dist/commands/wiki-cli.js +21 -35
  112. package/dist/core/asset/asset-registry.js +2 -0
  113. package/dist/core/asset/asset-spec.js +14 -0
  114. package/dist/core/asset/frontmatter.js +166 -167
  115. package/dist/core/asset/markdown.js +8 -0
  116. package/dist/core/authoring-rules.js +92 -0
  117. package/dist/core/common.js +0 -5
  118. package/dist/core/config/config-schema.js +340 -56
  119. package/dist/core/config/config-types.js +3 -3
  120. package/dist/core/config/config.js +28 -7
  121. package/dist/core/events.js +3 -7
  122. package/dist/core/improve-types.js +11 -8
  123. package/dist/core/logs-db.js +10 -66
  124. package/dist/core/parse.js +36 -16
  125. package/dist/core/paths.js +3 -0
  126. package/dist/core/standards/resolve-standards-context.js +87 -0
  127. package/dist/core/standards/resolve-stash-standards.js +99 -0
  128. package/dist/core/standards/resolve-type-conventions.js +66 -0
  129. package/dist/core/state/migrations.js +714 -0
  130. package/dist/core/state-db.js +525 -474
  131. package/dist/indexer/db/db.js +439 -247
  132. package/dist/indexer/db/graph-db.js +129 -86
  133. package/dist/indexer/ensure-index.js +152 -17
  134. package/dist/indexer/graph/graph-boost.js +51 -41
  135. package/dist/indexer/graph/graph-extraction.js +218 -4
  136. package/dist/indexer/index-writer-lock.js +99 -0
  137. package/dist/indexer/indexer.js +123 -221
  138. package/dist/indexer/passes/dir-staleness.js +114 -0
  139. package/dist/indexer/passes/memory-inference.js +10 -3
  140. package/dist/indexer/passes/staleness-detect.js +2 -5
  141. package/dist/indexer/search/db-search.js +15 -4
  142. package/dist/indexer/search/ranking-contributors.js +22 -0
  143. package/dist/indexer/search/ranking.js +4 -0
  144. package/dist/indexer/search/search-source.js +10 -24
  145. package/dist/indexer/search/semantic-status.js +4 -0
  146. package/dist/indexer/walk/matchers.js +9 -0
  147. package/dist/integrations/agent/config.js +6 -53
  148. package/dist/integrations/agent/index.js +2 -18
  149. package/dist/integrations/agent/prompts.js +74 -8
  150. package/dist/integrations/agent/runner-dispatch.js +59 -0
  151. package/dist/integrations/harnesses/claude/session-log.js +11 -1
  152. package/dist/integrations/harnesses/index.js +2 -3
  153. package/dist/integrations/harnesses/opencode/session-log.js +173 -3
  154. package/dist/integrations/harnesses/opencode-sdk/index.js +2 -2
  155. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -2
  156. package/dist/integrations/session-logs/index.js +16 -0
  157. package/dist/llm/client.js +45 -15
  158. package/dist/llm/embedder.js +42 -3
  159. package/dist/llm/embedders/deterministic.js +66 -0
  160. package/dist/llm/embedders/local.js +66 -2
  161. package/dist/llm/feature-gate.js +8 -4
  162. package/dist/llm/graph-extract.js +67 -44
  163. package/dist/llm/memory-infer.js +38 -30
  164. package/dist/llm/metadata-enhance.js +44 -31
  165. package/dist/llm/structured-call.js +49 -0
  166. package/dist/output/context.js +5 -5
  167. package/dist/output/renderers.js +73 -1
  168. package/dist/output/shapes/curate.js +14 -2
  169. package/dist/output/shapes/passthrough.js +0 -1
  170. package/dist/output/text/helpers.js +16 -1
  171. package/dist/registry/providers/skills-sh.js +21 -147
  172. package/dist/registry/providers/static-index.js +15 -157
  173. package/dist/registry/resolve.js +22 -9
  174. package/dist/runtime.js +25 -1
  175. package/dist/scripts/migrate-storage.js +2136 -1596
  176. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +682 -433
  177. package/dist/setup/setup.js +29 -8
  178. package/dist/sources/providers/filesystem.js +0 -1
  179. package/dist/sources/providers/git-install.js +206 -0
  180. package/dist/sources/providers/git-provider.js +234 -0
  181. package/dist/sources/providers/git-stash.js +248 -0
  182. package/dist/sources/providers/git.js +10 -661
  183. package/dist/sources/providers/npm.js +2 -6
  184. package/dist/sources/providers/sync-from-ref.js +9 -1
  185. package/dist/sources/providers/tar-utils.js +16 -8
  186. package/dist/sources/providers/website.js +2 -3
  187. package/dist/sources/website-ingest.js +51 -9
  188. package/dist/sources/wiki-fetchers/registry.js +53 -0
  189. package/dist/sources/wiki-fetchers/youtube.js +239 -0
  190. package/dist/storage/database.js +45 -10
  191. package/dist/storage/managed-db.js +82 -0
  192. package/dist/storage/repositories/registry-cache.js +92 -0
  193. package/dist/storage/sqlite-pragmas.js +146 -0
  194. package/dist/tasks/backends/cron.js +1 -1
  195. package/dist/tasks/backends/launchd.js +1 -1
  196. package/dist/tasks/backends/schtasks.js +1 -1
  197. package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
  198. package/dist/tasks/runner.js +5 -13
  199. package/dist/wiki/wiki.js +37 -0
  200. package/dist/workflows/db.js +3 -4
  201. package/dist/workflows/runtime/runs.js +1 -117
  202. package/dist/workflows/runtime/workflow-asset-loader.js +125 -0
  203. package/dist/workflows/validate-summary.js +2 -7
  204. package/docs/data-and-telemetry.md +1 -0
  205. package/package.json +9 -7
  206. package/dist/commands/db-cli.js +0 -23
  207. package/dist/indexer/db/db-backup.js +0 -376
@@ -34,10 +34,36 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
34
34
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
35
35
  var __require = import.meta.require;
36
36
 
37
+ // src/core/warn.ts
38
+ import fs from "fs";
39
+ function appendToLogFile(level, args) {
40
+ if (!logFilePath)
41
+ return;
42
+ const ts = new Date().toISOString();
43
+ const msg = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
44
+ try {
45
+ fs.appendFileSync(logFilePath, `[${ts}] [${level}] ${msg}
46
+ `);
47
+ } catch (e) {
48
+ process.stderr.write(`[akm:warn] log-file write failed (${logFilePath}): ${e}
49
+ `);
50
+ process.stderr.write(`[${ts}] [${level}] ${msg}
51
+ `);
52
+ }
53
+ }
54
+ function warn(...args) {
55
+ appendToLogFile("WARN", args);
56
+ if (!quiet) {
57
+ console.warn(...args);
58
+ }
59
+ }
60
+ var quiet = false, logFilePath;
61
+ var init_warn = () => {};
62
+
37
63
  // node_modules/dotenv/lib/main.js
38
64
  var require_main = __commonJS((exports, module) => {
39
- var fs = __require("fs");
40
- var path = __require("path");
65
+ var fs3 = __require("fs");
66
+ var path2 = __require("path");
41
67
  var os = __require("os");
42
68
  var crypto = __require("crypto");
43
69
  var TIPS = [
@@ -170,7 +196,7 @@ var require_main = __commonJS((exports, module) => {
170
196
  if (options && options.path && options.path.length > 0) {
171
197
  if (Array.isArray(options.path)) {
172
198
  for (const filepath of options.path) {
173
- if (fs.existsSync(filepath)) {
199
+ if (fs3.existsSync(filepath)) {
174
200
  possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
175
201
  }
176
202
  }
@@ -178,20 +204,20 @@ var require_main = __commonJS((exports, module) => {
178
204
  possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
179
205
  }
180
206
  } else {
181
- possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
207
+ possibleVaultPath = path2.resolve(process.cwd(), ".env.vault");
182
208
  }
183
- if (fs.existsSync(possibleVaultPath)) {
209
+ if (fs3.existsSync(possibleVaultPath)) {
184
210
  return possibleVaultPath;
185
211
  }
186
212
  return null;
187
213
  }
188
214
  function _resolveHome(envPath) {
189
- return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
215
+ return envPath[0] === "~" ? path2.join(os.homedir(), envPath.slice(1)) : envPath;
190
216
  }
191
217
  function _configVault(options) {
192
218
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options && options.debug);
193
- const quiet = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
194
- if (debug || !quiet) {
219
+ const quiet2 = parseBoolean(process.env.DOTENV_CONFIG_QUIET || options && options.quiet);
220
+ if (debug || !quiet2) {
195
221
  _log("loading env from encrypted .env.vault");
196
222
  }
197
223
  const parsed = DotenvModule._parseVault(options);
@@ -203,14 +229,14 @@ var require_main = __commonJS((exports, module) => {
203
229
  return { parsed };
204
230
  }
205
231
  function configDotenv(options) {
206
- const dotenvPath = path.resolve(process.cwd(), ".env");
232
+ const dotenvPath = path2.resolve(process.cwd(), ".env");
207
233
  let encoding = "utf8";
208
234
  let processEnv = process.env;
209
235
  if (options && options.processEnv != null) {
210
236
  processEnv = options.processEnv;
211
237
  }
212
238
  let debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || options && options.debug);
213
- let quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
239
+ let quiet2 = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || options && options.quiet);
214
240
  if (options && options.encoding) {
215
241
  encoding = options.encoding;
216
242
  } else {
@@ -231,26 +257,26 @@ var require_main = __commonJS((exports, module) => {
231
257
  }
232
258
  let lastError;
233
259
  const parsedAll = {};
234
- for (const path2 of optionPaths) {
260
+ for (const path3 of optionPaths) {
235
261
  try {
236
- const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
262
+ const parsed = DotenvModule.parse(fs3.readFileSync(path3, { encoding }));
237
263
  DotenvModule.populate(parsedAll, parsed, options);
238
264
  } catch (e) {
239
265
  if (debug) {
240
- _debug(`failed to load ${path2} ${e.message}`);
266
+ _debug(`failed to load ${path3} ${e.message}`);
241
267
  }
242
268
  lastError = e;
243
269
  }
244
270
  }
245
271
  const populated = DotenvModule.populate(processEnv, parsedAll, options);
246
272
  debug = parseBoolean(processEnv.DOTENV_CONFIG_DEBUG || debug);
247
- quiet = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet);
248
- if (debug || !quiet) {
273
+ quiet2 = parseBoolean(processEnv.DOTENV_CONFIG_QUIET || quiet2);
274
+ if (debug || !quiet2) {
249
275
  const keysCount = Object.keys(populated).length;
250
276
  const shortPaths = [];
251
277
  for (const filePath of optionPaths) {
252
278
  try {
253
- const relative = path.relative(process.cwd(), filePath);
279
+ const relative = path2.relative(process.cwd(), filePath);
254
280
  shortPaths.push(relative);
255
281
  } catch (e) {
256
282
  if (debug) {
@@ -412,7 +438,7 @@ var init_errors = __esm(() => {
412
438
  });
413
439
 
414
440
  // src/commands/env/env.ts
415
- import fs from "fs";
441
+ import fs3 from "fs";
416
442
  function scanKeys(text) {
417
443
  const keys = [];
418
444
  const seen = new Set;
@@ -439,9 +465,9 @@ function scanComments(text) {
439
465
  return comments;
440
466
  }
441
467
  function listKeys(envPath) {
442
- if (!fs.existsSync(envPath))
468
+ if (!fs3.existsSync(envPath))
443
469
  return { keys: [], comments: [] };
444
- const text = fs.readFileSync(envPath, "utf8");
470
+ const text = fs3.readFileSync(envPath, "utf8");
445
471
  return { keys: scanKeys(text), comments: scanComments(text) };
446
472
  }
447
473
  var import_dotenv, ASSIGN_RE;
@@ -452,251 +478,6 @@ var init_env = __esm(() => {
452
478
  ASSIGN_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
453
479
  });
454
480
 
455
- // src/core/asset/frontmatter.ts
456
- function parseFrontmatter(raw) {
457
- const parsedBlock = parseFrontmatterBlock(raw);
458
- if (!parsedBlock) {
459
- return { data: {}, content: raw, frontmatter: null, bodyStartLine: 1 };
460
- }
461
- const data = {};
462
- let currentKey = null;
463
- let mode = "scalar";
464
- let nested = null;
465
- let currentList = null;
466
- let blockLines = null;
467
- let blockChomping = "clip";
468
- const flushPending = () => {
469
- if (mode === "pending" && currentKey !== null) {
470
- data[currentKey] = "";
471
- }
472
- };
473
- const flushBlock = () => {
474
- if (mode !== "block" || currentKey === null || blockLines === null)
475
- return;
476
- const deindented = blockLines.map((l) => l.startsWith(" ") ? l.slice(2) : l);
477
- if (blockChomping === "keep") {
478
- data[currentKey] = deindented.join(`
479
- `);
480
- } else if (blockChomping === "strip") {
481
- data[currentKey] = deindented.join(`
482
- `).replace(/\n+$/, "");
483
- } else {
484
- data[currentKey] = `${deindented.join(`
485
- `).replace(/\n+$/, "")}
486
- `;
487
- }
488
- };
489
- for (const line of parsedBlock.frontmatter.split(/\r?\n/)) {
490
- if (mode === "block") {
491
- if (line.startsWith(" ") || line === "") {
492
- blockLines.push(line);
493
- continue;
494
- }
495
- flushBlock();
496
- mode = "scalar";
497
- blockLines = null;
498
- }
499
- const seqItem = line.match(/^(?: {2})?- (.*)$/);
500
- if (seqItem && currentKey !== null && (mode === "list" || mode === "pending")) {
501
- if (mode === "pending") {
502
- currentList = [];
503
- data[currentKey] = currentList;
504
- mode = "list";
505
- }
506
- currentList.push(parseYamlScalar(seqItem[1].trim()));
507
- continue;
508
- }
509
- if (mode === "scalar" && currentKey !== null && /^ {2}\S/.test(line)) {
510
- data[currentKey] = `${String(data[currentKey])} ${line.trim()}`;
511
- continue;
512
- }
513
- const indented = line.match(/^ {2}(\w[\w-]*):\s*(.+)$/);
514
- if (indented && currentKey !== null && (mode === "object" || mode === "pending")) {
515
- if (mode === "pending") {
516
- nested = {};
517
- data[currentKey] = nested;
518
- mode = "object";
519
- }
520
- nested[indented[1]] = parseYamlScalar(indented[2].trim());
521
- continue;
522
- }
523
- const top = line.match(/^(\w[\w-]*):\s*(.*)$/);
524
- if (!top) {
525
- continue;
526
- }
527
- flushPending();
528
- currentKey = top[1];
529
- const value = top[2].trim();
530
- if (value === "|" || value === "|-" || value === "|+") {
531
- mode = "block";
532
- blockLines = [];
533
- blockChomping = value === "|-" ? "strip" : value === "|+" ? "keep" : "clip";
534
- nested = null;
535
- currentList = null;
536
- } else if (value === "") {
537
- mode = "pending";
538
- nested = null;
539
- currentList = null;
540
- } else if (value.startsWith("[") && value.endsWith("]")) {
541
- mode = "list";
542
- nested = null;
543
- currentList = null;
544
- currentList = parseFlowArray(value);
545
- data[currentKey] = currentList;
546
- } else {
547
- mode = "scalar";
548
- nested = null;
549
- currentList = null;
550
- data[currentKey] = parseYamlScalar(value);
551
- }
552
- }
553
- if (mode === "block") {
554
- flushBlock();
555
- }
556
- flushPending();
557
- return {
558
- data,
559
- content: parsedBlock.content,
560
- frontmatter: parsedBlock.frontmatter,
561
- bodyStartLine: parsedBlock.bodyStartLine
562
- };
563
- }
564
- function parseFlowArray(value) {
565
- const inner = value.slice(1, -1).trim();
566
- if (!inner)
567
- return [];
568
- return inner.split(",").map((item) => parseYamlScalar(item.trim()));
569
- }
570
- function parseFrontmatterBlock(raw) {
571
- const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r\n|\r|\n|$)([\s\S]*)$/);
572
- if (!match)
573
- return null;
574
- const frontmatter = match[1].replace(/\r/g, "");
575
- const content = match[2];
576
- return {
577
- frontmatter,
578
- content,
579
- bodyStartLine: countLines(raw.slice(0, match[0].length - match[2].length)) + 1
580
- };
581
- }
582
- function countLines(text) {
583
- if (text.length === 0)
584
- return 0;
585
- return text.split(/\r?\n/).length - 1;
586
- }
587
- function parseYamlScalar(value) {
588
- if (value === "")
589
- return "";
590
- if (value === "true")
591
- return true;
592
- if (value === "false")
593
- return false;
594
- const asNumber = Number(value);
595
- if (!Number.isNaN(asNumber))
596
- return asNumber;
597
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
598
- return value.slice(1, -1);
599
- }
600
- return value;
601
- }
602
-
603
- // src/core/asset/markdown.ts
604
- function parseMarkdownToc(content) {
605
- const lines = content.split(/\r?\n/);
606
- const headings = [];
607
- const parsed = parseFrontmatter(content);
608
- const start = parsed.frontmatter ? parsed.bodyStartLine - 1 : 0;
609
- for (let i = start;i < lines.length; i++) {
610
- const match = lines[i].match(/^(#{1,6})\s+(.+)$/);
611
- if (match) {
612
- headings.push({
613
- level: match[1].length,
614
- text: match[2].replace(/\s+#+\s*$/, "").trim(),
615
- line: i + 1
616
- });
617
- }
618
- }
619
- return { headings, totalLines: lines.length };
620
- }
621
- var init_markdown = () => {};
622
-
623
- // src/core/warn.ts
624
- var init_warn = () => {};
625
-
626
- // src/indexer/walk/file-context.ts
627
- var renderers;
628
- var init_file_context = __esm(() => {
629
- init_common();
630
- renderers = new Map;
631
- });
632
-
633
- // src/indexer/passes/metadata-contributors.ts
634
- function registerMetadataContributor(contributor) {
635
- contributors.push(contributor);
636
- }
637
- var contributors;
638
- var init_metadata_contributors = __esm(() => {
639
- contributors = [];
640
- });
641
-
642
- // src/indexer/passes/metadata.ts
643
- import fs2 from "fs";
644
- function extractDescriptionFromComments(filePath) {
645
- let content;
646
- try {
647
- content = fs2.readFileSync(filePath, "utf8");
648
- } catch {
649
- return null;
650
- }
651
- const lines = content.split(/\r?\n/).slice(0, 50);
652
- const blockStart = lines.findIndex((l) => /^\s*\/\*\*/.test(l));
653
- if (blockStart >= 0) {
654
- const desc = [];
655
- for (let i = blockStart;i < lines.length; i++) {
656
- const line = lines[i];
657
- if (i > blockStart && /\*\//.test(line))
658
- break;
659
- const cleaned = line.replace(/^\s*\/?\*\*?\s?/, "").replace(/\*\/\s*$/, "").trim();
660
- if (cleaned)
661
- desc.push(cleaned);
662
- }
663
- if (desc.length > 0)
664
- return desc.join(" ");
665
- }
666
- let start = 0;
667
- if (lines[0]?.startsWith("#!"))
668
- start = 1;
669
- const hashLines = [];
670
- for (let i = start;i < lines.length; i++) {
671
- const line = lines[i].trim();
672
- if (line.startsWith("#") && !line.startsWith("#!")) {
673
- hashLines.push(line.replace(/^#+\s*/, "").trim());
674
- } else if (line === "") {} else {
675
- break;
676
- }
677
- }
678
- if (hashLines.length > 0)
679
- return hashLines.join(" ");
680
- return null;
681
- }
682
- var KNOWN_QUALITY_VALUES, warnedUnknownQualityValues, WIKI_INFRA_FILES;
683
- var init_metadata = __esm(() => {
684
- init_asset_spec();
685
- init_common();
686
- init_warn();
687
- init_file_context();
688
- init_metadata_contributors();
689
- KNOWN_QUALITY_VALUES = new Set(["generated", "curated", "enriched", "proposed"]);
690
- warnedUnknownQualityValues = new Set;
691
- WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
692
- });
693
-
694
- // src/core/asset/asset-ref.ts
695
- var init_asset_ref = __esm(() => {
696
- init_common();
697
- init_errors();
698
- });
699
-
700
481
  // node_modules/yaml/dist/nodes/identity.js
701
482
  var require_identity = __commonJS((exports) => {
702
483
  var ALIAS = Symbol.for("yaml.alias");
@@ -769,17 +550,17 @@ var require_visit = __commonJS((exports) => {
769
550
  visit.BREAK = BREAK;
770
551
  visit.SKIP = SKIP;
771
552
  visit.REMOVE = REMOVE;
772
- function visit_(key, node, visitor, path) {
773
- const ctrl = callVisitor(key, node, visitor, path);
553
+ function visit_(key, node, visitor, path2) {
554
+ const ctrl = callVisitor(key, node, visitor, path2);
774
555
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
775
- replaceNode(key, path, ctrl);
776
- return visit_(key, ctrl, visitor, path);
556
+ replaceNode(key, path2, ctrl);
557
+ return visit_(key, ctrl, visitor, path2);
777
558
  }
778
559
  if (typeof ctrl !== "symbol") {
779
560
  if (identity.isCollection(node)) {
780
- path = Object.freeze(path.concat(node));
561
+ path2 = Object.freeze(path2.concat(node));
781
562
  for (let i = 0;i < node.items.length; ++i) {
782
- const ci = visit_(i, node.items[i], visitor, path);
563
+ const ci = visit_(i, node.items[i], visitor, path2);
783
564
  if (typeof ci === "number")
784
565
  i = ci - 1;
785
566
  else if (ci === BREAK)
@@ -790,13 +571,13 @@ var require_visit = __commonJS((exports) => {
790
571
  }
791
572
  }
792
573
  } else if (identity.isPair(node)) {
793
- path = Object.freeze(path.concat(node));
794
- const ck = visit_("key", node.key, visitor, path);
574
+ path2 = Object.freeze(path2.concat(node));
575
+ const ck = visit_("key", node.key, visitor, path2);
795
576
  if (ck === BREAK)
796
577
  return BREAK;
797
578
  else if (ck === REMOVE)
798
579
  node.key = null;
799
- const cv = visit_("value", node.value, visitor, path);
580
+ const cv = visit_("value", node.value, visitor, path2);
800
581
  if (cv === BREAK)
801
582
  return BREAK;
802
583
  else if (cv === REMOVE)
@@ -817,17 +598,17 @@ var require_visit = __commonJS((exports) => {
817
598
  visitAsync.BREAK = BREAK;
818
599
  visitAsync.SKIP = SKIP;
819
600
  visitAsync.REMOVE = REMOVE;
820
- async function visitAsync_(key, node, visitor, path) {
821
- const ctrl = await callVisitor(key, node, visitor, path);
601
+ async function visitAsync_(key, node, visitor, path2) {
602
+ const ctrl = await callVisitor(key, node, visitor, path2);
822
603
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
823
- replaceNode(key, path, ctrl);
824
- return visitAsync_(key, ctrl, visitor, path);
604
+ replaceNode(key, path2, ctrl);
605
+ return visitAsync_(key, ctrl, visitor, path2);
825
606
  }
826
607
  if (typeof ctrl !== "symbol") {
827
608
  if (identity.isCollection(node)) {
828
- path = Object.freeze(path.concat(node));
609
+ path2 = Object.freeze(path2.concat(node));
829
610
  for (let i = 0;i < node.items.length; ++i) {
830
- const ci = await visitAsync_(i, node.items[i], visitor, path);
611
+ const ci = await visitAsync_(i, node.items[i], visitor, path2);
831
612
  if (typeof ci === "number")
832
613
  i = ci - 1;
833
614
  else if (ci === BREAK)
@@ -838,13 +619,13 @@ var require_visit = __commonJS((exports) => {
838
619
  }
839
620
  }
840
621
  } else if (identity.isPair(node)) {
841
- path = Object.freeze(path.concat(node));
842
- const ck = await visitAsync_("key", node.key, visitor, path);
622
+ path2 = Object.freeze(path2.concat(node));
623
+ const ck = await visitAsync_("key", node.key, visitor, path2);
843
624
  if (ck === BREAK)
844
625
  return BREAK;
845
626
  else if (ck === REMOVE)
846
627
  node.key = null;
847
- const cv = await visitAsync_("value", node.value, visitor, path);
628
+ const cv = await visitAsync_("value", node.value, visitor, path2);
848
629
  if (cv === BREAK)
849
630
  return BREAK;
850
631
  else if (cv === REMOVE)
@@ -871,23 +652,23 @@ var require_visit = __commonJS((exports) => {
871
652
  }
872
653
  return visitor;
873
654
  }
874
- function callVisitor(key, node, visitor, path) {
655
+ function callVisitor(key, node, visitor, path2) {
875
656
  if (typeof visitor === "function")
876
- return visitor(key, node, path);
657
+ return visitor(key, node, path2);
877
658
  if (identity.isMap(node))
878
- return visitor.Map?.(key, node, path);
659
+ return visitor.Map?.(key, node, path2);
879
660
  if (identity.isSeq(node))
880
- return visitor.Seq?.(key, node, path);
661
+ return visitor.Seq?.(key, node, path2);
881
662
  if (identity.isPair(node))
882
- return visitor.Pair?.(key, node, path);
663
+ return visitor.Pair?.(key, node, path2);
883
664
  if (identity.isScalar(node))
884
- return visitor.Scalar?.(key, node, path);
665
+ return visitor.Scalar?.(key, node, path2);
885
666
  if (identity.isAlias(node))
886
- return visitor.Alias?.(key, node, path);
667
+ return visitor.Alias?.(key, node, path2);
887
668
  return;
888
669
  }
889
- function replaceNode(key, path, node) {
890
- const parent = path[path.length - 1];
670
+ function replaceNode(key, path2, node) {
671
+ const parent = path2[path2.length - 1];
891
672
  if (identity.isCollection(parent)) {
892
673
  parent.items[key] = node;
893
674
  } else if (identity.isPair(parent)) {
@@ -1446,10 +1227,10 @@ var require_Collection = __commonJS((exports) => {
1446
1227
  var createNode = require_createNode();
1447
1228
  var identity = require_identity();
1448
1229
  var Node = require_Node();
1449
- function collectionFromPath(schema, path, value) {
1230
+ function collectionFromPath(schema, path2, value) {
1450
1231
  let v = value;
1451
- for (let i = path.length - 1;i >= 0; --i) {
1452
- const k = path[i];
1232
+ for (let i = path2.length - 1;i >= 0; --i) {
1233
+ const k = path2[i];
1453
1234
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
1454
1235
  const a = [];
1455
1236
  a[k] = v;
@@ -1468,7 +1249,7 @@ var require_Collection = __commonJS((exports) => {
1468
1249
  sourceObjects: new Map
1469
1250
  });
1470
1251
  }
1471
- var isEmptyPath = (path) => path == null || typeof path === "object" && !!path[Symbol.iterator]().next().done;
1252
+ var isEmptyPath = (path2) => path2 == null || typeof path2 === "object" && !!path2[Symbol.iterator]().next().done;
1472
1253
 
1473
1254
  class Collection extends Node.NodeBase {
1474
1255
  constructor(type, schema) {
@@ -1489,11 +1270,11 @@ var require_Collection = __commonJS((exports) => {
1489
1270
  copy.range = this.range.slice();
1490
1271
  return copy;
1491
1272
  }
1492
- addIn(path, value) {
1493
- if (isEmptyPath(path))
1273
+ addIn(path2, value) {
1274
+ if (isEmptyPath(path2))
1494
1275
  this.add(value);
1495
1276
  else {
1496
- const [key, ...rest] = path;
1277
+ const [key, ...rest] = path2;
1497
1278
  const node = this.get(key, true);
1498
1279
  if (identity.isCollection(node))
1499
1280
  node.addIn(rest, value);
@@ -1503,8 +1284,8 @@ var require_Collection = __commonJS((exports) => {
1503
1284
  throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
1504
1285
  }
1505
1286
  }
1506
- deleteIn(path) {
1507
- const [key, ...rest] = path;
1287
+ deleteIn(path2) {
1288
+ const [key, ...rest] = path2;
1508
1289
  if (rest.length === 0)
1509
1290
  return this.delete(key);
1510
1291
  const node = this.get(key, true);
@@ -1513,8 +1294,8 @@ var require_Collection = __commonJS((exports) => {
1513
1294
  else
1514
1295
  throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
1515
1296
  }
1516
- getIn(path, keepScalar) {
1517
- const [key, ...rest] = path;
1297
+ getIn(path2, keepScalar) {
1298
+ const [key, ...rest] = path2;
1518
1299
  const node = this.get(key, true);
1519
1300
  if (rest.length === 0)
1520
1301
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -1529,15 +1310,15 @@ var require_Collection = __commonJS((exports) => {
1529
1310
  return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
1530
1311
  });
1531
1312
  }
1532
- hasIn(path) {
1533
- const [key, ...rest] = path;
1313
+ hasIn(path2) {
1314
+ const [key, ...rest] = path2;
1534
1315
  if (rest.length === 0)
1535
1316
  return this.has(key);
1536
1317
  const node = this.get(key, true);
1537
1318
  return identity.isCollection(node) ? node.hasIn(rest) : false;
1538
1319
  }
1539
- setIn(path, value) {
1540
- const [key, ...rest] = path;
1320
+ setIn(path2, value) {
1321
+ const [key, ...rest] = path2;
1541
1322
  if (rest.length === 0) {
1542
1323
  this.set(key, value);
1543
1324
  } else {
@@ -3930,9 +3711,9 @@ var require_Document = __commonJS((exports) => {
3930
3711
  if (assertCollection(this.contents))
3931
3712
  this.contents.add(value);
3932
3713
  }
3933
- addIn(path, value) {
3714
+ addIn(path2, value) {
3934
3715
  if (assertCollection(this.contents))
3935
- this.contents.addIn(path, value);
3716
+ this.contents.addIn(path2, value);
3936
3717
  }
3937
3718
  createAlias(node, name) {
3938
3719
  if (!node.anchor) {
@@ -3981,30 +3762,30 @@ var require_Document = __commonJS((exports) => {
3981
3762
  delete(key) {
3982
3763
  return assertCollection(this.contents) ? this.contents.delete(key) : false;
3983
3764
  }
3984
- deleteIn(path) {
3985
- if (Collection.isEmptyPath(path)) {
3765
+ deleteIn(path2) {
3766
+ if (Collection.isEmptyPath(path2)) {
3986
3767
  if (this.contents == null)
3987
3768
  return false;
3988
3769
  this.contents = null;
3989
3770
  return true;
3990
3771
  }
3991
- return assertCollection(this.contents) ? this.contents.deleteIn(path) : false;
3772
+ return assertCollection(this.contents) ? this.contents.deleteIn(path2) : false;
3992
3773
  }
3993
3774
  get(key, keepScalar) {
3994
3775
  return identity.isCollection(this.contents) ? this.contents.get(key, keepScalar) : undefined;
3995
3776
  }
3996
- getIn(path, keepScalar) {
3997
- if (Collection.isEmptyPath(path))
3777
+ getIn(path2, keepScalar) {
3778
+ if (Collection.isEmptyPath(path2))
3998
3779
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3999
- return identity.isCollection(this.contents) ? this.contents.getIn(path, keepScalar) : undefined;
3780
+ return identity.isCollection(this.contents) ? this.contents.getIn(path2, keepScalar) : undefined;
4000
3781
  }
4001
3782
  has(key) {
4002
3783
  return identity.isCollection(this.contents) ? this.contents.has(key) : false;
4003
3784
  }
4004
- hasIn(path) {
4005
- if (Collection.isEmptyPath(path))
3785
+ hasIn(path2) {
3786
+ if (Collection.isEmptyPath(path2))
4006
3787
  return this.contents !== undefined;
4007
- return identity.isCollection(this.contents) ? this.contents.hasIn(path) : false;
3788
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path2) : false;
4008
3789
  }
4009
3790
  set(key, value) {
4010
3791
  if (this.contents == null) {
@@ -4013,13 +3794,13 @@ var require_Document = __commonJS((exports) => {
4013
3794
  this.contents.set(key, value);
4014
3795
  }
4015
3796
  }
4016
- setIn(path, value) {
4017
- if (Collection.isEmptyPath(path)) {
3797
+ setIn(path2, value) {
3798
+ if (Collection.isEmptyPath(path2)) {
4018
3799
  this.contents = value;
4019
3800
  } else if (this.contents == null) {
4020
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path), value);
3801
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path2), value);
4021
3802
  } else if (assertCollection(this.contents)) {
4022
- this.contents.setIn(path, value);
3803
+ this.contents.setIn(path2, value);
4023
3804
  }
4024
3805
  }
4025
3806
  setSchema(version, options = {}) {
@@ -5914,9 +5695,9 @@ var require_cst_visit = __commonJS((exports) => {
5914
5695
  visit.BREAK = BREAK;
5915
5696
  visit.SKIP = SKIP;
5916
5697
  visit.REMOVE = REMOVE;
5917
- visit.itemAtPath = (cst, path) => {
5698
+ visit.itemAtPath = (cst, path2) => {
5918
5699
  let item = cst;
5919
- for (const [field, index] of path) {
5700
+ for (const [field, index] of path2) {
5920
5701
  const tok = item?.[field];
5921
5702
  if (tok && "items" in tok) {
5922
5703
  item = tok.items[index];
@@ -5925,23 +5706,23 @@ var require_cst_visit = __commonJS((exports) => {
5925
5706
  }
5926
5707
  return item;
5927
5708
  };
5928
- visit.parentCollection = (cst, path) => {
5929
- const parent = visit.itemAtPath(cst, path.slice(0, -1));
5930
- const field = path[path.length - 1][0];
5709
+ visit.parentCollection = (cst, path2) => {
5710
+ const parent = visit.itemAtPath(cst, path2.slice(0, -1));
5711
+ const field = path2[path2.length - 1][0];
5931
5712
  const coll = parent?.[field];
5932
5713
  if (coll && "items" in coll)
5933
5714
  return coll;
5934
5715
  throw new Error("Parent collection not found");
5935
5716
  };
5936
- function _visit(path, item, visitor) {
5937
- let ctrl = visitor(item, path);
5717
+ function _visit(path2, item, visitor) {
5718
+ let ctrl = visitor(item, path2);
5938
5719
  if (typeof ctrl === "symbol")
5939
5720
  return ctrl;
5940
5721
  for (const field of ["key", "value"]) {
5941
5722
  const token = item[field];
5942
5723
  if (token && "items" in token) {
5943
5724
  for (let i = 0;i < token.items.length; ++i) {
5944
- const ci = _visit(Object.freeze(path.concat([[field, i]])), token.items[i], visitor);
5725
+ const ci = _visit(Object.freeze(path2.concat([[field, i]])), token.items[i], visitor);
5945
5726
  if (typeof ci === "number")
5946
5727
  i = ci - 1;
5947
5728
  else if (ci === BREAK)
@@ -5952,10 +5733,10 @@ var require_cst_visit = __commonJS((exports) => {
5952
5733
  }
5953
5734
  }
5954
5735
  if (typeof ctrl === "function" && field === "key")
5955
- ctrl = ctrl(item, path);
5736
+ ctrl = ctrl(item, path2);
5956
5737
  }
5957
5738
  }
5958
- return typeof ctrl === "function" ? ctrl(item, path) : ctrl;
5739
+ return typeof ctrl === "function" ? ctrl(item, path2) : ctrl;
5959
5740
  }
5960
5741
  exports.visit = visit;
5961
5742
  });
@@ -7224,14 +7005,14 @@ var require_parser = __commonJS((exports) => {
7224
7005
  case "scalar":
7225
7006
  case "single-quoted-scalar":
7226
7007
  case "double-quoted-scalar": {
7227
- const fs3 = this.flowScalar(this.type);
7008
+ const fs4 = this.flowScalar(this.type);
7228
7009
  if (atNextItem || it.value) {
7229
- map.items.push({ start, key: fs3, sep: [] });
7010
+ map.items.push({ start, key: fs4, sep: [] });
7230
7011
  this.onKeyLine = true;
7231
7012
  } else if (it.sep) {
7232
- this.stack.push(fs3);
7013
+ this.stack.push(fs4);
7233
7014
  } else {
7234
- Object.assign(it, { key: fs3, sep: [] });
7015
+ Object.assign(it, { key: fs4, sep: [] });
7235
7016
  this.onKeyLine = true;
7236
7017
  }
7237
7018
  return;
@@ -7359,13 +7140,13 @@ var require_parser = __commonJS((exports) => {
7359
7140
  case "scalar":
7360
7141
  case "single-quoted-scalar":
7361
7142
  case "double-quoted-scalar": {
7362
- const fs3 = this.flowScalar(this.type);
7143
+ const fs4 = this.flowScalar(this.type);
7363
7144
  if (!it || it.value)
7364
- fc.items.push({ start: [], key: fs3, sep: [] });
7145
+ fc.items.push({ start: [], key: fs4, sep: [] });
7365
7146
  else if (it.sep)
7366
- this.stack.push(fs3);
7147
+ this.stack.push(fs4);
7367
7148
  else
7368
- Object.assign(it, { key: fs3, sep: [] });
7149
+ Object.assign(it, { key: fs4, sep: [] });
7369
7150
  return;
7370
7151
  }
7371
7152
  case "flow-map-end":
@@ -7667,6 +7448,199 @@ var init_dist = __esm(() => {
7667
7448
  $visitAsync = visit.visitAsync;
7668
7449
  });
7669
7450
 
7451
+ // src/core/asset/frontmatter.ts
7452
+ function parseFrontmatter(raw) {
7453
+ const parsedBlock = parseFrontmatterBlock(raw);
7454
+ if (!parsedBlock) {
7455
+ return { data: {}, content: raw, frontmatter: null, bodyStartLine: 1 };
7456
+ }
7457
+ let data = {};
7458
+ if (parsedBlock.frontmatter.trim()) {
7459
+ try {
7460
+ const parsed = $parse(parsedBlock.frontmatter);
7461
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
7462
+ data = normalizeYamlValues(parsed);
7463
+ }
7464
+ } catch {
7465
+ data = parseFrontmatterLenient(parsedBlock.frontmatter);
7466
+ }
7467
+ }
7468
+ return {
7469
+ data,
7470
+ content: parsedBlock.content,
7471
+ frontmatter: parsedBlock.frontmatter,
7472
+ bodyStartLine: parsedBlock.bodyStartLine
7473
+ };
7474
+ }
7475
+ function normalizeYamlValues(value) {
7476
+ if (value instanceof Date) {
7477
+ const y = value.getUTCFullYear();
7478
+ const m = String(value.getUTCMonth() + 1).padStart(2, "0");
7479
+ const d = String(value.getUTCDate()).padStart(2, "0");
7480
+ return `${y}-${m}-${d}`;
7481
+ }
7482
+ if (value === null)
7483
+ return "";
7484
+ if (Array.isArray(value))
7485
+ return value.map(normalizeYamlValues);
7486
+ if (typeof value === "object") {
7487
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, normalizeYamlValues(v)]));
7488
+ }
7489
+ return value;
7490
+ }
7491
+ function parseFrontmatterLenient(frontmatter) {
7492
+ const data = {};
7493
+ for (const line of frontmatter.split(/\r?\n/)) {
7494
+ const m = line.match(/^([\w][\w-]*):\s*(.*)$/);
7495
+ if (!m)
7496
+ continue;
7497
+ const key = m[1];
7498
+ const rawValue = (m[2] ?? "").trim();
7499
+ try {
7500
+ const singleEntry = $parse(`k: ${rawValue}`);
7501
+ if (singleEntry !== null && typeof singleEntry === "object" && !Array.isArray(singleEntry)) {
7502
+ const v = singleEntry.k;
7503
+ data[key] = v === null || v === undefined ? "" : v;
7504
+ } else {
7505
+ data[key] = rawValue;
7506
+ }
7507
+ } catch {
7508
+ data[key] = rawValue;
7509
+ }
7510
+ }
7511
+ return data;
7512
+ }
7513
+ function parseFrontmatterBlock(raw) {
7514
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r\n|\r|\n|$)([\s\S]*)$/);
7515
+ if (match) {
7516
+ const frontmatter = match[1].replace(/\r/g, "");
7517
+ const content = match[2];
7518
+ return {
7519
+ frontmatter,
7520
+ content,
7521
+ bodyStartLine: countLines(raw.slice(0, match[0].length - match[2].length)) + 1
7522
+ };
7523
+ }
7524
+ const emptyMatch = raw.match(/^---\r?\n---(?:\r\n|\r|\n)([\s\S]*)$/);
7525
+ if (emptyMatch) {
7526
+ return { frontmatter: "", content: emptyMatch[1], bodyStartLine: 3 };
7527
+ }
7528
+ return null;
7529
+ }
7530
+ function countLines(text) {
7531
+ if (text.length === 0)
7532
+ return 0;
7533
+ return text.split(/\r?\n/).length - 1;
7534
+ }
7535
+ var init_frontmatter = __esm(() => {
7536
+ init_dist();
7537
+ });
7538
+
7539
+ // src/core/asset/markdown.ts
7540
+ function parseMarkdownToc(content) {
7541
+ const lines = content.split(/\r?\n/);
7542
+ const headings = [];
7543
+ const parsed = parseFrontmatter(content);
7544
+ const start = parsed.frontmatter ? parsed.bodyStartLine - 1 : 0;
7545
+ let inFence = false;
7546
+ for (let i = start;i < lines.length; i++) {
7547
+ if (/^\s*(`{3,}|~{3,})/.test(lines[i])) {
7548
+ inFence = !inFence;
7549
+ continue;
7550
+ }
7551
+ if (inFence)
7552
+ continue;
7553
+ const match = lines[i].match(/^(#{1,6})\s+(.+)$/);
7554
+ if (match) {
7555
+ headings.push({
7556
+ level: match[1].length,
7557
+ text: match[2].replace(/\s+#+\s*$/, "").trim(),
7558
+ line: i + 1
7559
+ });
7560
+ }
7561
+ }
7562
+ return { headings, totalLines: lines.length };
7563
+ }
7564
+ var init_markdown = __esm(() => {
7565
+ init_frontmatter();
7566
+ });
7567
+
7568
+ // src/indexer/walk/file-context.ts
7569
+ var renderers;
7570
+ var init_file_context = __esm(() => {
7571
+ init_frontmatter();
7572
+ init_common();
7573
+ renderers = new Map;
7574
+ });
7575
+
7576
+ // src/indexer/passes/metadata-contributors.ts
7577
+ function registerMetadataContributor(contributor) {
7578
+ contributors.push(contributor);
7579
+ }
7580
+ var contributors;
7581
+ var init_metadata_contributors = __esm(() => {
7582
+ contributors = [];
7583
+ });
7584
+
7585
+ // src/indexer/passes/metadata.ts
7586
+ import fs4 from "fs";
7587
+ function extractDescriptionFromComments(filePath) {
7588
+ let content;
7589
+ try {
7590
+ content = fs4.readFileSync(filePath, "utf8");
7591
+ } catch {
7592
+ return null;
7593
+ }
7594
+ const lines = content.split(/\r?\n/).slice(0, 50);
7595
+ const blockStart = lines.findIndex((l) => /^\s*\/\*\*/.test(l));
7596
+ if (blockStart >= 0) {
7597
+ const desc = [];
7598
+ for (let i = blockStart;i < lines.length; i++) {
7599
+ const line = lines[i];
7600
+ if (i > blockStart && /\*\//.test(line))
7601
+ break;
7602
+ const cleaned = line.replace(/^\s*\/?\*\*?\s?/, "").replace(/\*\/\s*$/, "").trim();
7603
+ if (cleaned)
7604
+ desc.push(cleaned);
7605
+ }
7606
+ if (desc.length > 0)
7607
+ return desc.join(" ");
7608
+ }
7609
+ let start = 0;
7610
+ if (lines[0]?.startsWith("#!"))
7611
+ start = 1;
7612
+ const hashLines = [];
7613
+ for (let i = start;i < lines.length; i++) {
7614
+ const line = lines[i].trim();
7615
+ if (line.startsWith("#") && !line.startsWith("#!")) {
7616
+ hashLines.push(line.replace(/^#+\s*/, "").trim());
7617
+ } else if (line === "") {} else {
7618
+ break;
7619
+ }
7620
+ }
7621
+ if (hashLines.length > 0)
7622
+ return hashLines.join(" ");
7623
+ return null;
7624
+ }
7625
+ var KNOWN_QUALITY_VALUES, warnedUnknownQualityValues, WIKI_INFRA_FILES;
7626
+ var init_metadata = __esm(() => {
7627
+ init_asset_spec();
7628
+ init_frontmatter();
7629
+ init_common();
7630
+ init_warn();
7631
+ init_file_context();
7632
+ init_metadata_contributors();
7633
+ KNOWN_QUALITY_VALUES = new Set(["generated", "curated", "enriched", "proposed"]);
7634
+ warnedUnknownQualityValues = new Set;
7635
+ WIKI_INFRA_FILES = new Set(["schema.md", "index.md", "log.md"]);
7636
+ });
7637
+
7638
+ // src/core/asset/asset-ref.ts
7639
+ var init_asset_ref = __esm(() => {
7640
+ init_common();
7641
+ init_errors();
7642
+ });
7643
+
7670
7644
  // src/workflows/schema.ts
7671
7645
  var WORKFLOW_SCHEMA_VERSION = 1;
7672
7646
 
@@ -7719,7 +7693,7 @@ var init_validator = __esm(() => {
7719
7693
  // src/workflows/parser.ts
7720
7694
  function parseWorkflow(markdown, source) {
7721
7695
  const errors2 = [];
7722
- const path = source.path;
7696
+ const path2 = source.path;
7723
7697
  const lines = markdown.split(/\r?\n/);
7724
7698
  const totalLines = lines.length;
7725
7699
  const fmBlock = parseFrontmatterBlock(markdown);
@@ -7727,7 +7701,7 @@ function parseWorkflow(markdown, source) {
7727
7701
  const fmData = readFrontmatter(fmBlock?.frontmatter, errors2);
7728
7702
  const description = readDescription(fmData);
7729
7703
  const tags = readTags(fmData, errors2, frontmatterEndLine);
7730
- const parameters = readParameters(fmData, errors2, frontmatterEndLine, path);
7704
+ const parameters = readParameters(fmData, errors2, frontmatterEndLine, path2);
7731
7705
  const toc = parseMarkdownToc(markdown);
7732
7706
  const { title, titleLine } = extractTitle(toc.headings, errors2);
7733
7707
  for (const h of toc.headings) {
@@ -7744,7 +7718,7 @@ function parseWorkflow(markdown, source) {
7744
7718
  });
7745
7719
  }
7746
7720
  }
7747
- const steps = extractSteps(toc.headings, lines, totalLines, path, errors2);
7721
+ const steps = extractSteps(toc.headings, lines, totalLines, path2, errors2);
7748
7722
  if (steps.length === 0 && titleLine > 0) {
7749
7723
  errors2.push({
7750
7724
  line: titleLine,
@@ -7758,7 +7732,7 @@ function parseWorkflow(markdown, source) {
7758
7732
  ...tags ? { tags } : {},
7759
7733
  ...parameters ? { parameters } : {},
7760
7734
  steps,
7761
- source: { path, lineCount: totalLines }
7735
+ source: { path: path2, lineCount: totalLines }
7762
7736
  };
7763
7737
  runSemanticChecks(draft, fmData, frontmatterEndLine, errors2);
7764
7738
  if (errors2.length > 0) {
@@ -7793,7 +7767,7 @@ function extractTitle(headings, errors2) {
7793
7767
  }
7794
7768
  return { title, titleLine: first.line };
7795
7769
  }
7796
- function extractSteps(headings, lines, totalLines, path, errors2) {
7770
+ function extractSteps(headings, lines, totalLines, path2, errors2) {
7797
7771
  const steps = [];
7798
7772
  let sequenceIndex = 0;
7799
7773
  for (let i = 0;i < headings.length; i++) {
@@ -7809,11 +7783,11 @@ function extractSteps(headings, lines, totalLines, path, errors2) {
7809
7783
  continue;
7810
7784
  }
7811
7785
  const stepEnd = Math.min(findNextSiblingOrParentLine(headings, i, 2) - 1, totalLines);
7812
- const stepSource = { path, start: h.line, end: stepEnd };
7786
+ const stepSource = { path: path2, start: h.line, end: stepEnd };
7813
7787
  const subsections = collectSubsections(headings, i, stepEnd);
7814
7788
  const stepIdSearchEnd = subsections.length > 0 ? subsections[0].headingLine - 1 : stepEnd;
7815
7789
  const stepId = scanStepId(lines, h.line + 1, stepIdSearchEnd, stepTitle, errors2);
7816
- const { instructions, completionCriteria } = collectStepBody(subsections, lines, path, stepTitle, errors2);
7790
+ const { instructions, completionCriteria } = collectStepBody(subsections, lines, path2, stepTitle, errors2);
7817
7791
  if (!stepId)
7818
7792
  continue;
7819
7793
  if (!instructions) {
@@ -7853,7 +7827,7 @@ function collectSubsections(headings, stepIndex, stepEnd) {
7853
7827
  }
7854
7828
  return subs;
7855
7829
  }
7856
- function collectStepBody(subsections, lines, path, stepTitle, errors2) {
7830
+ function collectStepBody(subsections, lines, path2, stepTitle, errors2) {
7857
7831
  let instructions;
7858
7832
  let completionCriteria;
7859
7833
  for (const sub of subsections) {
@@ -7875,7 +7849,7 @@ function collectStepBody(subsections, lines, path, stepTitle, errors2) {
7875
7849
  }
7876
7850
  instructions = {
7877
7851
  text,
7878
- source: { path, start: sub.bodyStart, end: sub.bodyEnd }
7852
+ source: { path: path2, start: sub.bodyStart, end: sub.bodyEnd }
7879
7853
  };
7880
7854
  continue;
7881
7855
  }
@@ -7887,7 +7861,7 @@ function collectStepBody(subsections, lines, path, stepTitle, errors2) {
7887
7861
  });
7888
7862
  continue;
7889
7863
  }
7890
- const items = collectBullets(lines, sub.bodyStart, sub.bodyEnd, path);
7864
+ const items = collectBullets(lines, sub.bodyStart, sub.bodyEnd, path2);
7891
7865
  if (items.length === 0) {
7892
7866
  errors2.push({
7893
7867
  line: sub.headingLine,
@@ -7936,7 +7910,7 @@ function scanStepId(lines, startLineInclusive, endLineInclusive, stepTitle, erro
7936
7910
  }
7937
7911
  return foundId;
7938
7912
  }
7939
- function collectBullets(lines, startLineInclusive, endLineInclusive, path) {
7913
+ function collectBullets(lines, startLineInclusive, endLineInclusive, path2) {
7940
7914
  const items = [];
7941
7915
  for (let lineNum = startLineInclusive;lineNum <= endLineInclusive; lineNum++) {
7942
7916
  const trimmed = (lines[lineNum - 1] ?? "").trim();
@@ -7947,7 +7921,7 @@ function collectBullets(lines, startLineInclusive, endLineInclusive, path) {
7947
7921
  continue;
7948
7922
  items.push({
7949
7923
  text: match[1].trim(),
7950
- source: { path, start: lineNum, end: lineNum }
7924
+ source: { path: path2, start: lineNum, end: lineNum }
7951
7925
  });
7952
7926
  }
7953
7927
  return items;
@@ -8016,7 +7990,7 @@ function readTags(data, errors2, fmEndLine) {
8016
7990
  }
8017
7991
  return v.map((tag) => tag.trim());
8018
7992
  }
8019
- function readParameters(data, errors2, fmEndLine, path) {
7993
+ function readParameters(data, errors2, fmEndLine, path2) {
8020
7994
  const v = data.params;
8021
7995
  if (v === undefined || v === null)
8022
7996
  return;
@@ -8050,7 +8024,7 @@ function readParameters(data, errors2, fmEndLine, path) {
8050
8024
  out.push({
8051
8025
  name: trimmedName,
8052
8026
  description: desc.trim(),
8053
- source: { path, start: 1, end: fmEndLine }
8027
+ source: { path: path2, start: 1, end: fmEndLine }
8054
8028
  });
8055
8029
  }
8056
8030
  return out.length > 0 ? out : undefined;
@@ -8061,6 +8035,7 @@ function sortErrors(errors2) {
8061
8035
  var WORKFLOW_TITLE_PREFIX = "Workflow:", STEP_PREFIX = "Step:", STEP_ID_LINE, BULLET_LINE, SUBSECTION_INSTRUCTIONS = "Instructions", SUBSECTION_COMPLETION_CRITERIA = "Completion Criteria";
8062
8036
  var init_parser = __esm(() => {
8063
8037
  init_dist();
8038
+ init_frontmatter();
8064
8039
  init_markdown();
8065
8040
  init_validator();
8066
8041
  STEP_ID_LINE = /^Step ID:\s+(.+?)\s*$/;
@@ -8151,6 +8126,25 @@ function applyTocMetadata(entry, ctx) {
8151
8126
  entry.toc = toc.headings;
8152
8127
  } catch {}
8153
8128
  }
8129
+ function applyFactMetadata(entry, ctx) {
8130
+ try {
8131
+ const fm = applyFrontmatterDescriptionAndTags(entry, ctx);
8132
+ const tags = new Set([...entry.tags ?? [], "fact"]);
8133
+ const hints = new Set(entry.searchHints ?? []);
8134
+ const category = asNonEmptyString(fm.category);
8135
+ if (category) {
8136
+ tags.add(category);
8137
+ hints.add(`category:${category}`);
8138
+ }
8139
+ if (fm.pinned === true) {
8140
+ tags.add("pinned");
8141
+ hints.add("pinned");
8142
+ }
8143
+ entry.tags = Array.from(tags).filter(Boolean);
8144
+ if (hints.size > 0)
8145
+ entry.searchHints = Array.from(hints).filter(Boolean);
8146
+ } catch {}
8147
+ }
8154
8148
  function applyFrontmatterDescriptionAndTags(entry, ctx) {
8155
8149
  const parsed = parseFrontmatter(ctx.content());
8156
8150
  const fm = parsed.data;
@@ -8250,6 +8244,7 @@ function applyTaskMetadata(entry, ctx) {
8250
8244
  }
8251
8245
  var init_renderers = __esm(() => {
8252
8246
  init_env();
8247
+ init_frontmatter();
8253
8248
  init_markdown();
8254
8249
  init_common();
8255
8250
  init_metadata();
@@ -8296,6 +8291,11 @@ var init_renderers = __esm(() => {
8296
8291
  appliesTo: ({ rendererName }) => rendererName === "session-md",
8297
8292
  contribute: (entry, ctx) => applySessionMetadata(entry, ctx.renderContext)
8298
8293
  });
8294
+ registerMetadataContributor({
8295
+ name: "fact-md-metadata",
8296
+ appliesTo: ({ rendererName }) => rendererName === "fact-md",
8297
+ contribute: (entry, ctx) => applyFactMetadata(entry, ctx.renderContext)
8298
+ });
8299
8299
  });
8300
8300
 
8301
8301
  // src/core/asset/asset-registry.ts
@@ -8304,7 +8304,7 @@ var init_asset_registry = __esm(() => {
8304
8304
  });
8305
8305
 
8306
8306
  // src/core/asset/asset-spec.ts
8307
- import path from "path";
8307
+ import path2 from "path";
8308
8308
  function getAssetTypes() {
8309
8309
  return Object.keys(ASSET_SPECS_INTERNAL);
8310
8310
  }
@@ -8314,14 +8314,14 @@ var init_asset_spec = __esm(() => {
8314
8314
  init_common();
8315
8315
  init_asset_registry();
8316
8316
  markdownSpec = {
8317
- isRelevantFile: (fileName) => path.extname(fileName).toLowerCase() === ".md",
8317
+ isRelevantFile: (fileName) => path2.extname(fileName).toLowerCase() === ".md",
8318
8318
  toCanonicalName: (typeRoot, filePath) => {
8319
- const rel = toPosix(path.relative(typeRoot, filePath));
8319
+ const rel = toPosix(path2.relative(typeRoot, filePath));
8320
8320
  return rel.endsWith(".md") ? rel.slice(0, -3) : rel;
8321
8321
  },
8322
8322
  toAssetPath: (typeRoot, name) => {
8323
8323
  const withExt = name.endsWith(".md") ? name : `${name}.md`;
8324
- return path.join(typeRoot, withExt);
8324
+ return path2.join(typeRoot, withExt);
8325
8325
  }
8326
8326
  };
8327
8327
  SCRIPT_EXTENSIONS = new Set([
@@ -8343,21 +8343,21 @@ var init_asset_spec = __esm(() => {
8343
8343
  ".kts"
8344
8344
  ]);
8345
8345
  scriptSpec = {
8346
- isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path.extname(fileName).toLowerCase()),
8347
- toCanonicalName: (typeRoot, filePath) => toPosix(path.relative(typeRoot, filePath)),
8348
- toAssetPath: (typeRoot, name) => path.join(typeRoot, name)
8346
+ isRelevantFile: (fileName) => SCRIPT_EXTENSIONS.has(path2.extname(fileName).toLowerCase()),
8347
+ toCanonicalName: (typeRoot, filePath) => toPosix(path2.relative(typeRoot, filePath)),
8348
+ toAssetPath: (typeRoot, name) => path2.join(typeRoot, name)
8349
8349
  };
8350
8350
  ASSET_SPECS_INTERNAL = {
8351
8351
  skill: {
8352
8352
  stashDir: "skills",
8353
8353
  isRelevantFile: (fileName) => fileName === "SKILL.md",
8354
8354
  toCanonicalName: (typeRoot, filePath) => {
8355
- const relDir = toPosix(path.dirname(path.relative(typeRoot, filePath)));
8355
+ const relDir = toPosix(path2.dirname(path2.relative(typeRoot, filePath)));
8356
8356
  if (!relDir || relDir === ".")
8357
8357
  return;
8358
8358
  return relDir;
8359
8359
  },
8360
- toAssetPath: (typeRoot, name) => path.join(typeRoot, name, "SKILL.md")
8360
+ toAssetPath: (typeRoot, name) => path2.join(typeRoot, name, "SKILL.md")
8361
8361
  },
8362
8362
  command: { stashDir: "commands", ...markdownSpec },
8363
8363
  agent: { stashDir: "agents", ...markdownSpec },
@@ -8374,10 +8374,10 @@ var init_asset_spec = __esm(() => {
8374
8374
  stashDir: "env",
8375
8375
  isRelevantFile: (fileName) => fileName === ".env" || fileName.endsWith(".env"),
8376
8376
  toCanonicalName: (typeRoot, filePath) => {
8377
- const rel = toPosix(path.relative(typeRoot, filePath));
8378
- const fileName = path.basename(rel);
8377
+ const rel = toPosix(path2.relative(typeRoot, filePath));
8378
+ const fileName = path2.basename(rel);
8379
8379
  if (fileName === ".env") {
8380
- const dir = path.dirname(rel);
8380
+ const dir = path2.dirname(rel);
8381
8381
  return dir === "." || dir === "" ? "default" : `${dir}/default`;
8382
8382
  }
8383
8383
  const stripped = rel.endsWith(".env") ? rel.slice(0, -4) : rel;
@@ -8385,8 +8385,8 @@ var init_asset_spec = __esm(() => {
8385
8385
  },
8386
8386
  toAssetPath: (typeRoot, name) => {
8387
8387
  if (name === "default")
8388
- return path.join(typeRoot, ".env");
8389
- return path.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8388
+ return path2.join(typeRoot, ".env");
8389
+ return path2.join(typeRoot, name.endsWith(".env") ? name : `${name}.env`);
8390
8390
  },
8391
8391
  rendererName: "env-file",
8392
8392
  actionBuilder: (ref) => `akm show ${ref} -> inspect key names; akm env run ${ref} -- <command> -> run with the whole .env injected (values never reach stdout); akm env export ${ref} --out <file> -> write a sourceable script to a file`
@@ -8394,8 +8394,8 @@ var init_asset_spec = __esm(() => {
8394
8394
  secret: {
8395
8395
  stashDir: "secrets",
8396
8396
  isRelevantFile: (fileName) => !fileName.endsWith(".lock") && !fileName.endsWith(".sensitive"),
8397
- toCanonicalName: (typeRoot, filePath) => toPosix(path.relative(typeRoot, filePath)),
8398
- toAssetPath: (typeRoot, name) => path.join(typeRoot, name),
8397
+ toCanonicalName: (typeRoot, filePath) => toPosix(path2.relative(typeRoot, filePath)),
8398
+ toAssetPath: (typeRoot, name) => path2.join(typeRoot, name),
8399
8399
  rendererName: "secret-file",
8400
8400
  actionBuilder: (ref) => `akm show ${ref} -> name only (value never shown); akm secret path ${ref} -> file path; akm secret run ${ref} <VAR> -- <command> -> run with value injected into $VAR`
8401
8401
  },
@@ -8413,14 +8413,14 @@ var init_asset_spec = __esm(() => {
8413
8413
  },
8414
8414
  task: {
8415
8415
  stashDir: "tasks",
8416
- isRelevantFile: (fileName) => path.extname(fileName).toLowerCase() === ".yml",
8416
+ isRelevantFile: (fileName) => path2.extname(fileName).toLowerCase() === ".yml",
8417
8417
  toCanonicalName: (typeRoot, filePath) => {
8418
- const rel = toPosix(path.relative(typeRoot, filePath));
8418
+ const rel = toPosix(path2.relative(typeRoot, filePath));
8419
8419
  return rel.endsWith(".yml") ? rel.slice(0, -4) : rel;
8420
8420
  },
8421
8421
  toAssetPath: (typeRoot, name) => {
8422
8422
  const withExt = name.endsWith(".yml") ? name : `${name}.yml`;
8423
- return path.join(typeRoot, withExt);
8423
+ return path2.join(typeRoot, withExt);
8424
8424
  },
8425
8425
  rendererName: "task-yaml",
8426
8426
  actionBuilder: buildTaskAction
@@ -8430,6 +8430,12 @@ var init_asset_spec = __esm(() => {
8430
8430
  ...markdownSpec,
8431
8431
  rendererName: "session-md",
8432
8432
  actionBuilder: (ref) => `akm show ${ref} -> read the session summary; follow the \`access\` frontmatter to open the raw log at \`log_path\``
8433
+ },
8434
+ fact: {
8435
+ stashDir: "facts",
8436
+ ...markdownSpec,
8437
+ rendererName: "fact-md",
8438
+ actionBuilder: (ref) => `akm show ${ref} -> read the stash fact and apply it as durable context`
8433
8439
  }
8434
8440
  };
8435
8441
  TYPE_DIRS = Object.fromEntries(Object.entries(ASSET_SPECS_INTERNAL).map(([type, spec]) => [type, spec.stashDir]));
@@ -8457,7 +8463,7 @@ var init_common = __esm(() => {
8457
8463
  });
8458
8464
 
8459
8465
  // src/core/paths.ts
8460
- import path2 from "path";
8466
+ import path3 from "path";
8461
8467
  function isUnderBunTest(env) {
8462
8468
  return env.BUN_TEST === "1" || env.NODE_ENV === "test";
8463
8469
  }
@@ -8474,23 +8480,23 @@ function getDataDir(env = process.env, platform = process.platform) {
8474
8480
  if (platform === "win32") {
8475
8481
  const localAppData = env.LOCALAPPDATA?.trim();
8476
8482
  if (localAppData)
8477
- return path2.join(localAppData, "akm", "data");
8483
+ return path3.join(localAppData, "akm", "data");
8478
8484
  const userProfile = env.USERPROFILE?.trim();
8479
8485
  if (userProfile)
8480
- return path2.join(userProfile, "AppData", "Local", "akm", "data");
8486
+ return path3.join(userProfile, "AppData", "Local", "akm", "data");
8481
8487
  const appData = env.APPDATA?.trim();
8482
8488
  if (!appData) {
8483
8489
  throw new ConfigError("Unable to determine data directory. Set LOCALAPPDATA, USERPROFILE, or APPDATA.", "CONFIG_DIR_UNRESOLVABLE");
8484
8490
  }
8485
- return path2.join(appData, "..", "Local", "akm", "data");
8491
+ return path3.join(appData, "..", "Local", "akm", "data");
8486
8492
  }
8487
8493
  const xdgDataHome = env.XDG_DATA_HOME?.trim();
8488
8494
  if (xdgDataHome)
8489
- return path2.join(xdgDataHome, "akm");
8495
+ return path3.join(xdgDataHome, "akm");
8490
8496
  const home = env.HOME?.trim();
8491
8497
  if (!home)
8492
- return path2.join("/tmp", "akm-data");
8493
- return path2.join(home, ".local", "share", "akm");
8498
+ return path3.join("/tmp", "akm-data");
8499
+ return path3.join(home, ".local", "share", "akm");
8494
8500
  }
8495
8501
  var init_paths = __esm(() => {
8496
8502
  init_common();
@@ -8498,22 +8504,40 @@ var init_paths = __esm(() => {
8498
8504
  });
8499
8505
 
8500
8506
  // scripts/migrations/import-fs-improve-runs-to-db.ts
8501
- import fs4 from "fs";
8502
- import path4 from "path";
8507
+ import fs5 from "fs";
8508
+ import path5 from "path";
8503
8509
 
8504
8510
  // src/core/state-db.ts
8505
- import fs3 from "fs";
8506
- import path3 from "path";
8511
+ import path4 from "path";
8512
+
8513
+ // src/storage/managed-db.ts
8514
+ import fs2 from "fs";
8515
+ import path from "path";
8507
8516
 
8508
8517
  // src/storage/database.ts
8509
8518
  import { createRequire } from "module";
8510
8519
  var isBun = !!process.versions?.bun;
8511
8520
  var nodeRequire = createRequire(import.meta.url);
8512
- function openDatabase(path, opts) {
8513
- if (isBun) {
8514
- return openBunDatabase(path, opts);
8521
+ var bunSqliteProvider = {
8522
+ name: "bun:sqlite",
8523
+ supported: () => isBun,
8524
+ open: openBunDatabase
8525
+ };
8526
+ var nodeSqliteProvider = {
8527
+ name: "better-sqlite3",
8528
+ supported: () => !isBun,
8529
+ open: openNodeDatabase
8530
+ };
8531
+ var PROVIDERS = [bunSqliteProvider, nodeSqliteProvider];
8532
+ function selectProvider() {
8533
+ const provider = PROVIDERS.find((p) => p.supported());
8534
+ if (!provider) {
8535
+ throw new Error(`No storage provider supports the current runtime (${isBun ? "Bun" : "Node"}).`);
8515
8536
  }
8516
- return openNodeDatabase(path, opts);
8537
+ return provider;
8538
+ }
8539
+ function openDatabase(path, opts) {
8540
+ return selectProvider().open(path, opts);
8517
8541
  }
8518
8542
  function openBunDatabase(path, opts) {
8519
8543
  const { Database: BunDatabase } = loadBunSqlite();
@@ -8538,7 +8562,16 @@ function loadBunSqlite() {
8538
8562
  var betterSqlite3Ctor;
8539
8563
  function loadBetterSqlite3() {
8540
8564
  if (!betterSqlite3Ctor) {
8541
- const mod = nodeRequire("better-sqlite3");
8565
+ let mod;
8566
+ try {
8567
+ mod = nodeRequire("better-sqlite3");
8568
+ } catch (err) {
8569
+ throw new Error(`akm could not load 'better-sqlite3', the SQLite driver it needs on Node.js.
8570
+ ` + ` \u2022 Reinstall akm with a working C/C++ build toolchain so its optional
8571
+ ` + " 'better-sqlite3' native binding rebuilds (a global `npm i -g better-sqlite3`\n" + ` will NOT be resolved \u2014 Node loads it from akm's own node_modules).
8572
+ ` + ` \u2022 Or run akm under Bun, which has a built-in SQLite driver and needs no native build.
8573
+ ` + ` Underlying load error: ${err instanceof Error ? err.message : String(err)}`);
8574
+ }
8542
8575
  betterSqlite3Ctor = mod.default ?? mod;
8543
8576
  }
8544
8577
  return betterSqlite3Ctor;
@@ -8554,28 +8587,104 @@ function openNodeDatabase(path, opts) {
8554
8587
  return db;
8555
8588
  }
8556
8589
 
8557
- // src/storage/engines/sqlite-migrations.ts
8558
- function ensureMigrationsTable(db) {
8559
- db.exec(`
8560
- CREATE TABLE IF NOT EXISTS schema_migrations (
8561
- id TEXT PRIMARY KEY,
8562
- applied_at TEXT NOT NULL DEFAULT (datetime('now'))
8563
- );
8564
- `);
8590
+ // src/storage/sqlite-pragmas.ts
8591
+ init_warn();
8592
+
8593
+ // src/runtime.ts
8594
+ import { createWriteStream, statfsSync } from "fs";
8595
+ import { createRequire as createRequire2 } from "module";
8596
+ var isBun2 = !!process.versions?.bun;
8597
+ var nodeRequire2 = createRequire2(import.meta.url);
8598
+ function statfsType(path) {
8599
+ try {
8600
+ return statfsSync(path).type;
8601
+ } catch {
8602
+ return;
8603
+ }
8565
8604
  }
8566
- function runMigrations(db, migrations, opts) {
8567
- ensureMigrationsTable(db);
8568
- opts?.bootstrap?.(db);
8569
- const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
8570
- const applied = new Set(appliedRows.map((r) => r.id));
8571
- for (const migration of migrations) {
8572
- if (applied.has(migration.id))
8573
- continue;
8574
- db.transaction(() => {
8575
- db.exec(migration.up);
8576
- db.prepare("INSERT INTO schema_migrations (id) VALUES (?)").run(migration.id);
8577
- })();
8605
+ var mainPath = isBun2 ? bunGlobal().main : process.argv[1];
8606
+ function bunGlobal() {
8607
+ return globalThis.Bun;
8608
+ }
8609
+
8610
+ // src/storage/sqlite-pragmas.ts
8611
+ var VALID_MODES = new Set(["WAL", "DELETE", "TRUNCATE"]);
8612
+ var warnedInvalid = false;
8613
+ var warnedNetworkFallback = false;
8614
+ function resolveJournalMode(raw) {
8615
+ if (raw === undefined)
8616
+ return "WAL";
8617
+ const normalized = raw.trim().toUpperCase();
8618
+ if (normalized === "")
8619
+ return "WAL";
8620
+ if (VALID_MODES.has(normalized)) {
8621
+ return normalized;
8622
+ }
8623
+ warnInvalidJournalModeOnce(raw);
8624
+ return "WAL";
8625
+ }
8626
+ function resolveConfiguredJournalMode() {
8627
+ return resolveJournalMode(process.env.AKM_SQLITE_JOURNAL_MODE);
8628
+ }
8629
+ function warnInvalidJournalModeOnce(raw) {
8630
+ if (warnedInvalid)
8631
+ return;
8632
+ warnedInvalid = true;
8633
+ warn(`[akm] invalid AKM_SQLITE_JOURNAL_MODE=${JSON.stringify(raw)} \u2014 using WAL (valid: WAL, DELETE, TRUNCATE)`);
8634
+ }
8635
+ var FS_MAGIC_NFS = 26985;
8636
+ var FS_MAGIC_SMB = 20859;
8637
+ var FS_MAGIC_CIFS = 4283649346;
8638
+ var FS_MAGIC_SMB2 = 4266872130;
8639
+ var FS_MAGIC_FUSE = 1702057286;
8640
+ var NETWORK_FS_MAGICS = new Set([
8641
+ FS_MAGIC_NFS,
8642
+ FS_MAGIC_SMB,
8643
+ FS_MAGIC_CIFS,
8644
+ FS_MAGIC_SMB2,
8645
+ FS_MAGIC_FUSE
8646
+ ]);
8647
+ function isNetworkFilesystem(fsType) {
8648
+ if (fsType === undefined)
8649
+ return false;
8650
+ return NETWORK_FS_MAGICS.has(fsType);
8651
+ }
8652
+ function applyStandardPragmas(db, opts = {}) {
8653
+ let mode = resolveConfiguredJournalMode();
8654
+ if (mode === "WAL" && opts.dataDir) {
8655
+ const probe = opts.fsTypeProbe ?? statfsType;
8656
+ if (isNetworkFilesystem(probe(opts.dataDir))) {
8657
+ mode = "DELETE";
8658
+ warnNetworkFallbackOnce(opts.dataDir);
8659
+ }
8578
8660
  }
8661
+ db.exec("PRAGMA busy_timeout = 30000");
8662
+ db.exec(`PRAGMA journal_mode = ${mode}`);
8663
+ if (opts.foreignKeys !== false) {
8664
+ db.exec("PRAGMA foreign_keys = ON");
8665
+ }
8666
+ if (mode !== "WAL") {
8667
+ db.exec("PRAGMA synchronous = FULL");
8668
+ }
8669
+ return mode;
8670
+ }
8671
+ function warnNetworkFallbackOnce(dataDir) {
8672
+ if (warnedNetworkFallback)
8673
+ return;
8674
+ warnedNetworkFallback = true;
8675
+ warn(`[akm] network filesystem detected at ${dataDir} \u2014 WAL unsupported, using DELETE journal mode`);
8676
+ }
8677
+
8678
+ // src/storage/managed-db.ts
8679
+ function openManagedDatabase(spec) {
8680
+ const dir = path.dirname(spec.path);
8681
+ if (!fs2.existsSync(dir)) {
8682
+ fs2.mkdirSync(dir, { recursive: true });
8683
+ }
8684
+ const db = openDatabase(spec.path);
8685
+ applyStandardPragmas(db, spec.pragmas ?? { dataDir: dir });
8686
+ spec.init?.(db);
8687
+ return db;
8579
8688
  }
8580
8689
 
8581
8690
  // src/core/assert.ts
@@ -8604,6 +8713,7 @@ function classifyImproveAction(mode) {
8604
8713
  case "reflect-cooldown":
8605
8714
  case "reflect-skipped":
8606
8715
  case "distill-skipped":
8716
+ return "skipped";
8607
8717
  case "reflect-guard-rejected":
8608
8718
  return "rejected";
8609
8719
  case "reflect-failed":
@@ -8619,22 +8729,32 @@ function classifyImproveAction(mode) {
8619
8729
  // src/core/state-db.ts
8620
8730
  init_paths();
8621
8731
  init_warn();
8622
- function getStateDbPath() {
8623
- return path3.join(getDataDir(), "state.db");
8732
+
8733
+ // src/storage/engines/sqlite-migrations.ts
8734
+ function ensureMigrationsTable(db) {
8735
+ db.exec(`
8736
+ CREATE TABLE IF NOT EXISTS schema_migrations (
8737
+ id TEXT PRIMARY KEY,
8738
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
8739
+ );
8740
+ `);
8624
8741
  }
8625
- function openStateDatabase(dbPath) {
8626
- const resolvedPath = dbPath ?? getStateDbPath();
8627
- const dir = path3.dirname(resolvedPath);
8628
- if (!fs3.existsSync(dir)) {
8629
- fs3.mkdirSync(dir, { recursive: true });
8630
- }
8631
- const db = openDatabase(resolvedPath);
8632
- db.exec("PRAGMA journal_mode = WAL");
8633
- db.exec("PRAGMA foreign_keys = ON");
8634
- db.exec("PRAGMA busy_timeout = 30000");
8635
- runMigrations2(db);
8636
- return db;
8742
+ function runMigrations(db, migrations, opts) {
8743
+ ensureMigrationsTable(db);
8744
+ opts?.bootstrap?.(db);
8745
+ const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
8746
+ const applied = new Set(appliedRows.map((r) => r.id));
8747
+ for (const migration of migrations) {
8748
+ if (applied.has(migration.id))
8749
+ continue;
8750
+ db.transaction(() => {
8751
+ db.exec(migration.up);
8752
+ db.prepare("INSERT INTO schema_migrations (id) VALUES (?)").run(migration.id);
8753
+ })();
8754
+ }
8637
8755
  }
8756
+
8757
+ // src/core/state/migrations.ts
8638
8758
  var MIGRATIONS = [
8639
8759
  {
8640
8760
  id: "001-initial-schema",
@@ -8708,7 +8828,7 @@ var MIGRATIONS = [
8708
8828
  -- metadata_json TEXT \u2014 JSON object for future proposal fields.
8709
8829
  -- Current fields stored here: sourceRun,
8710
8830
  -- review, confidence, gateDecision (#577),
8711
- -- backupContent.
8831
+ -- backupContent, eligibilitySource.
8712
8832
  --
8713
8833
  -- ADD COLUMN extension points (future migrations):
8714
8834
  -- ALTER TABLE proposals ADD COLUMN source_run TEXT DEFAULT NULL;
@@ -8905,17 +9025,143 @@ var MIGRATIONS = [
8905
9025
  imported_count INTEGER NOT NULL DEFAULT 0
8906
9026
  );
8907
9027
  `
9028
+ },
9029
+ {
9030
+ id: "006-proposals-pending-ref-source",
9031
+ up: `
9032
+ CREATE INDEX IF NOT EXISTS idx_proposals_stash_status_ref_source
9033
+ ON proposals(stash_dir, status, ref, source);
9034
+ `
9035
+ },
9036
+ {
9037
+ id: "007-consolidation-judged",
9038
+ up: `
9039
+ CREATE TABLE IF NOT EXISTS consolidation_judged (
9040
+ entry_key TEXT PRIMARY KEY,
9041
+ content_hash TEXT NOT NULL,
9042
+ judged_at TEXT NOT NULL,
9043
+ outcome TEXT NOT NULL
9044
+ );
9045
+ `
9046
+ },
9047
+ {
9048
+ id: "008-body-embeddings",
9049
+ up: `
9050
+ CREATE TABLE IF NOT EXISTS body_embeddings (
9051
+ content_hash TEXT PRIMARY KEY,
9052
+ embedding BLOB NOT NULL,
9053
+ model_id TEXT NOT NULL,
9054
+ created_at INTEGER NOT NULL
9055
+ );
9056
+ `
9057
+ },
9058
+ {
9059
+ id: "009-asset-salience",
9060
+ up: `
9061
+ CREATE TABLE IF NOT EXISTS asset_salience (
9062
+ asset_ref TEXT PRIMARY KEY,
9063
+ encoding_salience REAL NOT NULL DEFAULT 0.5,
9064
+ outcome_salience REAL NOT NULL DEFAULT 0.0,
9065
+ retrieval_salience REAL NOT NULL DEFAULT 0.0,
9066
+ rank_score REAL NOT NULL DEFAULT 0.0,
9067
+ consecutive_no_ops INTEGER NOT NULL DEFAULT 0,
9068
+ updated_at INTEGER NOT NULL DEFAULT 0
9069
+ );
9070
+
9071
+ -- Hot path: sort / filter by rank_score for selector queries.
9072
+ CREATE INDEX IF NOT EXISTS idx_asset_salience_rank
9073
+ ON asset_salience(rank_score DESC);
9074
+ `
9075
+ },
9076
+ {
9077
+ id: "010-asset-outcome",
9078
+ up: `
9079
+ CREATE TABLE IF NOT EXISTS asset_outcome (
9080
+ asset_ref TEXT PRIMARY KEY,
9081
+ last_retrieved_at INTEGER NOT NULL DEFAULT 0,
9082
+ retrieval_count INTEGER NOT NULL DEFAULT 0,
9083
+ expected_retrieval_rate REAL NOT NULL DEFAULT 0.0,
9084
+ negative_feedback_count INTEGER NOT NULL DEFAULT 0,
9085
+ accepted_change_count INTEGER NOT NULL DEFAULT 0,
9086
+ review_pressure INTEGER NOT NULL DEFAULT 0,
9087
+ outcome_score REAL NOT NULL DEFAULT 0.0,
9088
+ updated_at INTEGER NOT NULL DEFAULT 0
9089
+ );
9090
+
9091
+ -- Hot path: sort assets by review_pressure DESC for #613 admission.
9092
+ CREATE INDEX IF NOT EXISTS idx_asset_outcome_review_pressure
9093
+ ON asset_outcome(review_pressure DESC);
9094
+
9095
+ -- Secondary: sort by outcome_score DESC for outcomeSalience reads.
9096
+ CREATE INDEX IF NOT EXISTS idx_asset_outcome_score
9097
+ ON asset_outcome(outcome_score DESC);
9098
+ `
9099
+ },
9100
+ {
9101
+ id: "011-asset-salience-homeostatic-demoted-at",
9102
+ up: `
9103
+ ALTER TABLE asset_salience ADD COLUMN homeostatic_demoted_at INTEGER DEFAULT NULL;
9104
+ `
9105
+ },
9106
+ {
9107
+ id: "012-improve-gate-thresholds",
9108
+ up: `
9109
+ CREATE TABLE IF NOT EXISTS improve_gate_thresholds (
9110
+ phase TEXT NOT NULL PRIMARY KEY,
9111
+ threshold INTEGER NOT NULL,
9112
+ updated_at INTEGER NOT NULL
9113
+ );
9114
+ `
9115
+ },
9116
+ {
9117
+ id: "013-extract-sessions-content-hash",
9118
+ up: `
9119
+ ALTER TABLE extract_sessions_seen ADD COLUMN content_hash TEXT DEFAULT NULL;
9120
+ `
9121
+ },
9122
+ {
9123
+ id: "014-recombine-hypotheses",
9124
+ up: `
9125
+ CREATE TABLE IF NOT EXISTS recombine_hypotheses (
9126
+ hypothesis_ref TEXT PRIMARY KEY,
9127
+ signature TEXT NOT NULL,
9128
+ member_key TEXT NOT NULL,
9129
+ consecutive_count INTEGER NOT NULL DEFAULT 0,
9130
+ first_seen_at TEXT NOT NULL,
9131
+ last_seen_at TEXT NOT NULL,
9132
+ last_run TEXT,
9133
+ promoted_at TEXT,
9134
+ metadata_json TEXT NOT NULL DEFAULT '{}'
9135
+ );
9136
+ CREATE INDEX IF NOT EXISTS idx_recombine_hypotheses_last_seen
9137
+ ON recombine_hypotheses(last_seen_at);
9138
+ `
9139
+ },
9140
+ {
9141
+ id: "015-asset-salience-encoding-source",
9142
+ up: `
9143
+ ALTER TABLE asset_salience ADD COLUMN encoding_source TEXT DEFAULT NULL;
9144
+ `
8908
9145
  }
8909
9146
  ];
8910
9147
  function runMigrations2(db) {
8911
9148
  runMigrations(db, MIGRATIONS);
8912
9149
  }
9150
+
9151
+ // src/core/state-db.ts
9152
+ function getStateDbPath() {
9153
+ return path4.join(getDataDir(), "state.db");
9154
+ }
9155
+ function openStateDatabase(dbPath) {
9156
+ return openManagedDatabase({ path: dbPath ?? getStateDbPath(), init: runMigrations2 });
9157
+ }
8913
9158
  function computeImproveRunMetrics(result) {
8914
9159
  const plannedCount = Array.isArray(result.plannedRefs) ? result.plannedRefs.length : 0;
8915
9160
  const actions = Array.isArray(result.actions) ? result.actions : [];
8916
9161
  const actionsCount = actions.length;
8917
9162
  let acceptedCount = 0;
8918
9163
  let rejectedCount = 0;
9164
+ let skippedCount = 0;
8919
9165
  let autoAcceptedCount = 0;
8920
9166
  let errorCount = 0;
8921
9167
  for (const action of actions) {
@@ -8926,6 +9172,9 @@ function computeImproveRunMetrics(result) {
8926
9172
  case "rejected":
8927
9173
  rejectedCount++;
8928
9174
  break;
9175
+ case "skipped":
9176
+ skippedCount++;
9177
+ break;
8929
9178
  case "error":
8930
9179
  errorCount++;
8931
9180
  break;
@@ -8937,7 +9186,7 @@ function computeImproveRunMetrics(result) {
8937
9186
  autoAcceptedCount++;
8938
9187
  }
8939
9188
  autoAcceptedCount += result.gateAutoAcceptedCount ?? 0;
8940
- return { plannedCount, actionsCount, acceptedCount, rejectedCount, autoAcceptedCount, errorCount };
9189
+ return { plannedCount, actionsCount, acceptedCount, rejectedCount, skippedCount, autoAcceptedCount, errorCount };
8941
9190
  }
8942
9191
  function recordImproveRun(db, input) {
8943
9192
  const metricsObj = input.metrics ?? computeImproveRunMetrics(input.result);
@@ -8953,7 +9202,7 @@ function recordImproveRun(db, input) {
8953
9202
  function parseArgs(argv) {
8954
9203
  const stashFromEnv = process.env.AKM_STASH_DIR;
8955
9204
  const out = {
8956
- stashDir: stashFromEnv ?? path4.join(process.env.HOME ?? "", "akm"),
9205
+ stashDir: stashFromEnv ?? path5.join(process.env.HOME ?? "", "akm"),
8957
9206
  dryRun: false,
8958
9207
  archive: true
8959
9208
  };
@@ -9012,12 +9261,12 @@ function inferScope(envelope) {
9012
9261
  }
9013
9262
  async function main() {
9014
9263
  const args = parseArgs(process.argv.slice(2));
9015
- const runsRoot = path4.join(args.stashDir, ".akm", "runs");
9016
- if (!fs4.existsSync(runsRoot)) {
9264
+ const runsRoot = path5.join(args.stashDir, ".akm", "runs");
9265
+ if (!fs5.existsSync(runsRoot)) {
9017
9266
  console.log(`[import] no legacy runs directory at ${runsRoot}; nothing to do`);
9018
9267
  return;
9019
9268
  }
9020
- const entries = fs4.readdirSync(runsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
9269
+ const entries = fs5.readdirSync(runsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
9021
9270
  if (entries.length === 0) {
9022
9271
  console.log(`[import] ${runsRoot} is empty; nothing to do`);
9023
9272
  return;
@@ -9031,8 +9280,8 @@ async function main() {
9031
9280
  let skippedParseFailed = 0;
9032
9281
  let skippedNoTimestamp = 0;
9033
9282
  for (const id of entries) {
9034
- const resultPath = path4.join(runsRoot, id, "improve-result.json");
9035
- if (!fs4.existsSync(resultPath)) {
9283
+ const resultPath = path5.join(runsRoot, id, "improve-result.json");
9284
+ if (!fs5.existsSync(resultPath)) {
9036
9285
  skippedNoResult++;
9037
9286
  continue;
9038
9287
  }
@@ -9042,7 +9291,7 @@ async function main() {
9042
9291
  }
9043
9292
  let envelope;
9044
9293
  try {
9045
- envelope = JSON.parse(fs4.readFileSync(resultPath, "utf8"));
9294
+ envelope = JSON.parse(fs5.readFileSync(resultPath, "utf8"));
9046
9295
  } catch (err) {
9047
9296
  console.warn(`[import] skipping ${id}: parse failed (${err instanceof Error ? err.message : String(err)})`);
9048
9297
  skippedParseFailed++;
@@ -9107,8 +9356,8 @@ async function main() {
9107
9356
  return;
9108
9357
  }
9109
9358
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
9110
- const archiveTarget = path4.join(args.stashDir, ".akm", `runs.archived-${ts}`);
9111
- fs4.renameSync(runsRoot, archiveTarget);
9359
+ const archiveTarget = path5.join(args.stashDir, ".akm", `runs.archived-${ts}`);
9360
+ fs5.renameSync(runsRoot, archiveTarget);
9112
9361
  console.log(`[import] archived ${runsRoot} \u2192 ${archiveTarget}`);
9113
9362
  }
9114
9363
  main().catch((err) => {