@goondocks/myco 0.18.0 → 0.18.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 (128) hide show
  1. package/dist/{agent-run-2NFYMQXW.js → agent-run-I4O2K2CK.js} +4 -4
  2. package/dist/{agent-tasks-MEIYLXGN.js → agent-tasks-UOW5BQIB.js} +4 -4
  3. package/dist/{chunk-JMOUFG6Y.js → chunk-44PZCAYS.js} +47 -5
  4. package/dist/chunk-44PZCAYS.js.map +1 -0
  5. package/dist/{chunk-JDI4DPWD.js → chunk-C3EGL5JX.js} +632 -145
  6. package/dist/chunk-C3EGL5JX.js.map +1 -0
  7. package/dist/{chunk-OW433Q4C.js → chunk-CURS2TNP.js} +44 -3
  8. package/dist/chunk-CURS2TNP.js.map +1 -0
  9. package/dist/{chunk-FABWUX5G.js → chunk-DPSLJ242.js} +16 -2
  10. package/dist/chunk-DPSLJ242.js.map +1 -0
  11. package/dist/{chunk-DLFDBKEV.js → chunk-LSP5HYOO.js} +17 -14
  12. package/dist/chunk-LSP5HYOO.js.map +1 -0
  13. package/dist/{chunk-VOCGURV7.js → chunk-N75GMQGA.js} +3 -3
  14. package/dist/{chunk-U7GJTVSX.js → chunk-RIDSOQDR.js} +20 -6
  15. package/dist/chunk-RIDSOQDR.js.map +1 -0
  16. package/dist/{chunk-KWTOCJLB.js → chunk-TCSVDQF5.js} +1128 -193
  17. package/dist/chunk-TCSVDQF5.js.map +1 -0
  18. package/dist/{chunk-55QEICRO.js → chunk-TLK46KKD.js} +2 -2
  19. package/dist/{chunk-NZI7WBZI.js → chunk-TOER6RNC.js} +21 -1
  20. package/dist/chunk-TOER6RNC.js.map +1 -0
  21. package/dist/{chunk-7OYXB2NM.js → chunk-TZAXQKO6.js} +5 -1
  22. package/dist/chunk-TZAXQKO6.js.map +1 -0
  23. package/dist/{chunk-EO2RQW4S.js → chunk-W7WENJ6F.js} +2 -2
  24. package/dist/{chunk-BUIR3JWM.js → chunk-XWOQL4XN.js} +2 -2
  25. package/dist/{chunk-PFWIPRF6.js → chunk-YZPI2Y3E.js} +2 -2
  26. package/dist/{cli-IIMBALPV.js → cli-D3TJYJ2U.js} +35 -35
  27. package/dist/{client-VZCUISHZ.js → client-4LLEXLVK.js} +3 -3
  28. package/dist/{detect-GEM3NVK6.js → detect-SZ2KDUF4.js} +2 -2
  29. package/dist/{doctor-QYD34X7Q.js → doctor-KCTXPX5D.js} +6 -6
  30. package/dist/{executor-NSPRTH4M.js → executor-UYIZC3L5.js} +83 -275
  31. package/dist/executor-UYIZC3L5.js.map +1 -0
  32. package/dist/{init-WYYL44KZ.js → init-QFNBKKDC.js} +7 -7
  33. package/dist/{llm-KEDHK3TQ.js → llm-SMA5ZEAW.js} +2 -2
  34. package/dist/{main-6PY3ITQ5.js → main-5THODR77.js} +427 -196
  35. package/dist/main-5THODR77.js.map +1 -0
  36. package/dist/{open-HRFMJDQX.js → open-7737CSPN.js} +4 -4
  37. package/dist/{post-compact-HT24YMAN.js → post-compact-2TJ5FPZH.js} +6 -6
  38. package/dist/{post-tool-use-DENRI5WB.js → post-tool-use-FRTSICC3.js} +5 -5
  39. package/dist/{post-tool-use-failure-A6SNJX42.js → post-tool-use-failure-KYO2NCNB.js} +6 -6
  40. package/dist/{pre-compact-3Q4BALCL.js → pre-compact-J6GCJEJR.js} +6 -6
  41. package/dist/{remove-YB5A6HY2.js → remove-3WZZC7AX.js} +5 -5
  42. package/dist/{restart-RGDVHELZ.js → restart-HUHEFOXU.js} +5 -5
  43. package/dist/{search-WOHT3G55.js → search-ZGN3LDXG.js} +5 -5
  44. package/dist/{server-6SUNYDV7.js → server-PTXLVVEE.js} +3 -3
  45. package/dist/{session-W3SKRFRV.js → session-7VV3IQMO.js} +5 -5
  46. package/dist/{session-end-OUTY7AFF.js → session-end-SMU55UCM.js} +5 -5
  47. package/dist/{session-start-5MB3LFOA.js → session-start-NIMWEOIZ.js} +16 -11
  48. package/dist/{session-start-5MB3LFOA.js.map → session-start-NIMWEOIZ.js.map} +1 -1
  49. package/dist/{setup-llm-ZMYGIQX5.js → setup-llm-7S3VPAPN.js} +4 -4
  50. package/dist/src/agent/definitions/tasks/extract-only.yaml +1 -1
  51. package/dist/src/agent/definitions/tasks/full-intelligence.yaml +10 -0
  52. package/dist/src/agent/definitions/tasks/skill-evolve.yaml +163 -49
  53. package/dist/src/agent/definitions/tasks/skill-generate.yaml +44 -27
  54. package/dist/src/agent/definitions/tasks/skill-survey.yaml +132 -138
  55. package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +1 -1
  56. package/dist/src/cli.js +1 -1
  57. package/dist/src/daemon/main.js +1 -1
  58. package/dist/src/hooks/post-tool-use.js +1 -1
  59. package/dist/src/hooks/session-end.js +1 -1
  60. package/dist/src/hooks/session-start.js +1 -1
  61. package/dist/src/hooks/stop.js +1 -1
  62. package/dist/src/hooks/user-prompt-submit.js +1 -1
  63. package/dist/src/mcp/server.js +1 -1
  64. package/dist/src/symbionts/manifests/codex.yaml +45 -7
  65. package/dist/src/worker/src/index.ts +8 -2
  66. package/dist/src/worker/src/schema.ts +2 -0
  67. package/dist/{stats-DGI6B3HX.js → stats-GEOQ2DFF.js} +5 -5
  68. package/dist/{stop-YGHODSP7.js → stop-7AKYBJJ2.js} +5 -5
  69. package/dist/{stop-failure-7IJTPJ6W.js → stop-failure-NLE2EURG.js} +6 -6
  70. package/dist/{subagent-start-ZBQ5PJB5.js → subagent-start-LBNZF2TG.js} +6 -6
  71. package/dist/{subagent-stop-N2TDQU2D.js → subagent-stop-B2Z5GYAB.js} +6 -6
  72. package/dist/{task-completed-BDLMRSBB.js → task-completed-PO5TETJ7.js} +6 -6
  73. package/dist/{team-2ZFGTSIN.js → team-DPNP2RN7.js} +3 -3
  74. package/dist/ui/assets/{index-DtT9_nlT.js → index-CiI1fwas.js} +2 -2
  75. package/dist/ui/index.html +1 -1
  76. package/dist/{update-STLAN7LR.js → update-WBWB5URU.js} +5 -5
  77. package/dist/{user-prompt-submit-4IBFUYQ3.js → user-prompt-submit-IZJC3NV7.js} +11 -8
  78. package/dist/user-prompt-submit-IZJC3NV7.js.map +1 -0
  79. package/dist/{verify-EJYPO7QA.js → verify-FNSP62I3.js} +2 -2
  80. package/dist/{version-YPBIKH77.js → version-QEVU66NT.js} +2 -2
  81. package/package.json +7 -7
  82. package/dist/chunk-7OYXB2NM.js.map +0 -1
  83. package/dist/chunk-DLFDBKEV.js.map +0 -1
  84. package/dist/chunk-FABWUX5G.js.map +0 -1
  85. package/dist/chunk-JDI4DPWD.js.map +0 -1
  86. package/dist/chunk-JMOUFG6Y.js.map +0 -1
  87. package/dist/chunk-KWTOCJLB.js.map +0 -1
  88. package/dist/chunk-NZI7WBZI.js.map +0 -1
  89. package/dist/chunk-OW433Q4C.js.map +0 -1
  90. package/dist/chunk-U7GJTVSX.js.map +0 -1
  91. package/dist/executor-NSPRTH4M.js.map +0 -1
  92. package/dist/main-6PY3ITQ5.js.map +0 -1
  93. package/dist/user-prompt-submit-4IBFUYQ3.js.map +0 -1
  94. /package/dist/{agent-run-2NFYMQXW.js.map → agent-run-I4O2K2CK.js.map} +0 -0
  95. /package/dist/{agent-tasks-MEIYLXGN.js.map → agent-tasks-UOW5BQIB.js.map} +0 -0
  96. /package/dist/{chunk-VOCGURV7.js.map → chunk-N75GMQGA.js.map} +0 -0
  97. /package/dist/{chunk-55QEICRO.js.map → chunk-TLK46KKD.js.map} +0 -0
  98. /package/dist/{chunk-EO2RQW4S.js.map → chunk-W7WENJ6F.js.map} +0 -0
  99. /package/dist/{chunk-BUIR3JWM.js.map → chunk-XWOQL4XN.js.map} +0 -0
  100. /package/dist/{chunk-PFWIPRF6.js.map → chunk-YZPI2Y3E.js.map} +0 -0
  101. /package/dist/{cli-IIMBALPV.js.map → cli-D3TJYJ2U.js.map} +0 -0
  102. /package/dist/{client-VZCUISHZ.js.map → client-4LLEXLVK.js.map} +0 -0
  103. /package/dist/{detect-GEM3NVK6.js.map → detect-SZ2KDUF4.js.map} +0 -0
  104. /package/dist/{doctor-QYD34X7Q.js.map → doctor-KCTXPX5D.js.map} +0 -0
  105. /package/dist/{init-WYYL44KZ.js.map → init-QFNBKKDC.js.map} +0 -0
  106. /package/dist/{llm-KEDHK3TQ.js.map → llm-SMA5ZEAW.js.map} +0 -0
  107. /package/dist/{open-HRFMJDQX.js.map → open-7737CSPN.js.map} +0 -0
  108. /package/dist/{post-compact-HT24YMAN.js.map → post-compact-2TJ5FPZH.js.map} +0 -0
  109. /package/dist/{post-tool-use-DENRI5WB.js.map → post-tool-use-FRTSICC3.js.map} +0 -0
  110. /package/dist/{post-tool-use-failure-A6SNJX42.js.map → post-tool-use-failure-KYO2NCNB.js.map} +0 -0
  111. /package/dist/{pre-compact-3Q4BALCL.js.map → pre-compact-J6GCJEJR.js.map} +0 -0
  112. /package/dist/{remove-YB5A6HY2.js.map → remove-3WZZC7AX.js.map} +0 -0
  113. /package/dist/{restart-RGDVHELZ.js.map → restart-HUHEFOXU.js.map} +0 -0
  114. /package/dist/{search-WOHT3G55.js.map → search-ZGN3LDXG.js.map} +0 -0
  115. /package/dist/{server-6SUNYDV7.js.map → server-PTXLVVEE.js.map} +0 -0
  116. /package/dist/{session-W3SKRFRV.js.map → session-7VV3IQMO.js.map} +0 -0
  117. /package/dist/{session-end-OUTY7AFF.js.map → session-end-SMU55UCM.js.map} +0 -0
  118. /package/dist/{setup-llm-ZMYGIQX5.js.map → setup-llm-7S3VPAPN.js.map} +0 -0
  119. /package/dist/{stats-DGI6B3HX.js.map → stats-GEOQ2DFF.js.map} +0 -0
  120. /package/dist/{stop-YGHODSP7.js.map → stop-7AKYBJJ2.js.map} +0 -0
  121. /package/dist/{stop-failure-7IJTPJ6W.js.map → stop-failure-NLE2EURG.js.map} +0 -0
  122. /package/dist/{subagent-start-ZBQ5PJB5.js.map → subagent-start-LBNZF2TG.js.map} +0 -0
  123. /package/dist/{subagent-stop-N2TDQU2D.js.map → subagent-stop-B2Z5GYAB.js.map} +0 -0
  124. /package/dist/{task-completed-BDLMRSBB.js.map → task-completed-PO5TETJ7.js.map} +0 -0
  125. /package/dist/{team-2ZFGTSIN.js.map → team-DPNP2RN7.js.map} +0 -0
  126. /package/dist/{update-STLAN7LR.js.map → update-WBWB5URU.js.map} +0 -0
  127. /package/dist/{verify-EJYPO7QA.js.map → verify-FNSP62I3.js.map} +0 -0
  128. /package/dist/{version-YPBIKH77.js.map → version-QEVU66NT.js.map} +0 -0
@@ -12,11 +12,13 @@ import {
12
12
  } from "./chunk-NI23QCHB.js";
13
13
  import {
14
14
  getSpore,
15
- listSporeIdsSince
16
- } from "./chunk-7OYXB2NM.js";
15
+ listSporeIdsSince,
16
+ listSpores
17
+ } from "./chunk-TZAXQKO6.js";
17
18
  import {
18
- getSession
19
- } from "./chunk-U7GJTVSX.js";
19
+ getSession,
20
+ listSessions
21
+ } from "./chunk-RIDSOQDR.js";
20
22
  import {
21
23
  getTeamMachineId,
22
24
  syncRow
@@ -169,6 +171,10 @@ function errorMessage(err) {
169
171
  }
170
172
  }
171
173
 
174
+ // src/agent/instruction-builders.ts
175
+ import { readFileSync } from "fs";
176
+ import { resolve } from "path";
177
+
172
178
  // src/db/queries/skill-candidates.ts
173
179
  var DEFAULT_CONFIDENCE = 0;
174
180
  var DEFAULT_STATUS = "identified";
@@ -182,6 +188,7 @@ var CANDIDATE_COLUMNS = [
182
188
  "status",
183
189
  "source_ids",
184
190
  "skill_id",
191
+ "supersedes",
185
192
  "approved_at",
186
193
  "created_at",
187
194
  "updated_at",
@@ -199,6 +206,7 @@ function toCandidateRow(row) {
199
206
  status: row.status,
200
207
  source_ids: row.source_ids ?? "[]",
201
208
  skill_id: row.skill_id ?? null,
209
+ supersedes: row.supersedes ?? null,
202
210
  approved_at: row.approved_at ?? null,
203
211
  created_at: row.created_at,
204
212
  updated_at: row.updated_at,
@@ -230,11 +238,11 @@ function insertCandidate(data) {
230
238
  db.prepare(
231
239
  `INSERT INTO skill_candidates (
232
240
  id, agent_id, machine_id, topic, rationale,
233
- confidence, status, source_ids, skill_id, approved_at,
241
+ confidence, status, source_ids, skill_id, supersedes, approved_at,
234
242
  created_at, updated_at
235
243
  ) VALUES (
236
244
  ?, ?, ?, ?, ?,
237
- ?, ?, ?, ?, ?,
245
+ ?, ?, ?, ?, ?, ?,
238
246
  ?, ?
239
247
  )`
240
248
  ).run(
@@ -247,6 +255,7 @@ function insertCandidate(data) {
247
255
  data.status ?? DEFAULT_STATUS,
248
256
  data.source_ids ?? "[]",
249
257
  data.skill_id ?? null,
258
+ data.supersedes ?? null,
250
259
  data.approved_at ?? null,
251
260
  data.created_at,
252
261
  data.updated_at
@@ -296,6 +305,7 @@ function updateCandidate(id, updates) {
296
305
  status: "status",
297
306
  source_ids: "source_ids",
298
307
  skill_id: "skill_id",
308
+ supersedes: "supersedes",
299
309
  approved_at: "approved_at",
300
310
  updated_at: "updated_at"
301
311
  };
@@ -556,69 +566,357 @@ function deleteSkillRecordCascade(idOrName) {
556
566
  return { id: record.id, name: record.name };
557
567
  }
558
568
 
559
- // src/db/queries/skill-lineage.ts
560
- var LINEAGE_COLUMNS = [
569
+ // src/db/queries/digest-extracts.ts
570
+ var EXTRACT_COLUMNS = [
561
571
  "id",
562
- "skill_id",
563
- "generation",
564
- "action",
565
- "rationale",
566
- "source_ids_added",
567
- "content_snapshot",
568
- "created_at"
572
+ "agent_id",
573
+ "tier",
574
+ "content",
575
+ "substrate_hash",
576
+ "generated_at",
577
+ "machine_id",
578
+ "synced_at"
569
579
  ];
570
- var SELECT_COLUMNS3 = LINEAGE_COLUMNS.join(", ");
571
- function toLineageRow(row) {
580
+ var SELECT_COLUMNS3 = EXTRACT_COLUMNS.join(", ");
581
+ function toDigestExtractRow(row) {
572
582
  return {
573
583
  id: row.id,
574
- skill_id: row.skill_id,
575
- generation: row.generation,
576
- action: row.action,
577
- rationale: row.rationale,
578
- source_ids_added: row.source_ids_added ?? "[]",
579
- content_snapshot: row.content_snapshot,
580
- created_at: row.created_at
584
+ agent_id: row.agent_id,
585
+ tier: row.tier,
586
+ content: row.content,
587
+ substrate_hash: row.substrate_hash ?? null,
588
+ generated_at: row.generated_at,
589
+ machine_id: row.machine_id ?? "local",
590
+ synced_at: row.synced_at ?? null
581
591
  };
582
592
  }
583
- function insertLineage(data) {
593
+ function upsertDigestExtract(data) {
584
594
  const db = getDatabase();
585
595
  db.prepare(
586
- `INSERT INTO skill_lineage (
587
- id, skill_id, generation, action, rationale,
588
- source_ids_added, content_snapshot, created_at
589
- ) VALUES (
590
- ?, ?, ?, ?, ?,
591
- ?, ?, ?
592
- )`
593
- ).run(
594
- data.id,
595
- data.skill_id,
596
- data.generation,
597
- data.action,
598
- data.rationale,
599
- data.source_ids_added ?? "[]",
600
- data.content_snapshot,
601
- data.created_at
602
- );
603
- return toLineageRow(
604
- db.prepare(`SELECT ${SELECT_COLUMNS3} FROM skill_lineage WHERE id = ?`).get(data.id)
605
- );
596
+ `INSERT INTO digest_extracts (agent_id, tier, content, generated_at)
597
+ VALUES (?, ?, ?, ?)
598
+ ON CONFLICT (agent_id, tier) DO UPDATE SET
599
+ content = EXCLUDED.content,
600
+ generated_at = EXCLUDED.generated_at`
601
+ ).run(data.agent_id, data.tier, data.content, data.generated_at);
602
+ const row = db.prepare(
603
+ `SELECT ${SELECT_COLUMNS3} FROM digest_extracts WHERE agent_id = ? AND tier = ?`
604
+ ).get(data.agent_id, data.tier);
605
+ return toDigestExtractRow(row);
606
606
  }
607
- function listLineageForSkill(skillId, limit = 50) {
607
+ function getDigestExtract(agentId, tier) {
608
608
  const db = getDatabase();
609
+ const row = db.prepare(
610
+ `SELECT ${SELECT_COLUMNS3} FROM digest_extracts
611
+ WHERE agent_id = ? AND tier = ?`
612
+ ).get(agentId, tier);
613
+ if (!row) return null;
614
+ return toDigestExtractRow(row);
615
+ }
616
+ function listDigestExtracts(agentId) {
617
+ const db = getDatabase();
618
+ const tierPlaceholders = DIGEST_TIERS.map(() => "?").join(", ");
609
619
  const rows = db.prepare(
610
620
  `SELECT ${SELECT_COLUMNS3}
611
- FROM skill_lineage
612
- WHERE skill_id = ?
613
- ORDER BY generation DESC
614
- LIMIT ?`
615
- ).all(skillId, limit);
616
- return rows.map(toLineageRow);
621
+ FROM digest_extracts
622
+ WHERE agent_id = ? AND tier IN (${tierPlaceholders})
623
+ ORDER BY tier ASC`
624
+ ).all(agentId, ...DIGEST_TIERS);
625
+ return rows.map(toDigestExtractRow);
626
+ }
627
+
628
+ // src/db/queries/agent-state.ts
629
+ var STATE_COLUMNS = [
630
+ "agent_id",
631
+ "key",
632
+ "value",
633
+ "updated_at"
634
+ ];
635
+ var SELECT_COLUMNS4 = STATE_COLUMNS.join(", ");
636
+ function toAgentStateRow(row) {
637
+ return {
638
+ agent_id: row.agent_id,
639
+ key: row.key,
640
+ value: row.value,
641
+ updated_at: row.updated_at
642
+ };
643
+ }
644
+ function getState(agentId, key) {
645
+ const db = getDatabase();
646
+ const row = db.prepare(
647
+ `SELECT ${SELECT_COLUMNS4} FROM agent_state WHERE agent_id = ? AND key = ?`
648
+ ).get(agentId, key);
649
+ if (!row) return null;
650
+ return toAgentStateRow(row);
651
+ }
652
+ function setState(agentId, key, value, updatedAt) {
653
+ const db = getDatabase();
654
+ db.prepare(
655
+ `INSERT INTO agent_state (agent_id, key, value, updated_at)
656
+ VALUES (?, ?, ?, ?)
657
+ ON CONFLICT (agent_id, key) DO UPDATE SET
658
+ value = EXCLUDED.value,
659
+ updated_at = EXCLUDED.updated_at`
660
+ ).run(agentId, key, value, updatedAt);
661
+ return toAgentStateRow(
662
+ db.prepare(`SELECT ${SELECT_COLUMNS4} FROM agent_state WHERE agent_id = ? AND key = ?`).get(agentId, key)
663
+ );
664
+ }
665
+ function getStatesForAgent(agentId) {
666
+ const db = getDatabase();
667
+ const rows = db.prepare(
668
+ `SELECT ${SELECT_COLUMNS4}
669
+ FROM agent_state
670
+ WHERE agent_id = ?
671
+ ORDER BY key ASC`
672
+ ).all(agentId);
673
+ return rows.map(toAgentStateRow);
674
+ }
675
+
676
+ // src/agent/tools/skill-validator.ts
677
+ var MAX_SKILL_LINES = 800;
678
+ var REQUIRED_FRONTMATTER_FIELDS = ["name", "description", "managed_by", "user-invocable", "allowed-tools"];
679
+ var PROTECTED_FRONTMATTER_FIELDS = ["user-invocable", "allowed-tools"];
680
+ var ALLOWED_CLAUDE_CODE_TOOLS = /* @__PURE__ */ new Set([
681
+ "Read",
682
+ "Edit",
683
+ "Write",
684
+ "MultiEdit",
685
+ "Bash",
686
+ "Grep",
687
+ "Glob",
688
+ "NotebookRead",
689
+ "NotebookEdit",
690
+ "WebFetch",
691
+ "WebSearch",
692
+ "Task",
693
+ "TodoWrite"
694
+ ]);
695
+ function extractFrontmatterField(content, field) {
696
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
697
+ if (!fmMatch) return void 0;
698
+ const fm = fmMatch[1];
699
+ const match = fm.match(new RegExp(`^${field}:\\s*(.+)$`, "m"));
700
+ if (match) return match[1].trim();
701
+ const blockMatch = fm.match(new RegExp(`^${field}:\\s*$`, "m"));
702
+ if (blockMatch) {
703
+ const startIdx = fm.indexOf(blockMatch[0]) + blockMatch[0].length;
704
+ const remaining = fm.slice(startIdx);
705
+ const items = [];
706
+ for (const line of remaining.split("\n")) {
707
+ const itemMatch = line.match(/^\s+-\s+(.+)$/);
708
+ if (!itemMatch) break;
709
+ items.push(itemMatch[1].trim());
710
+ }
711
+ if (items.length > 0) return items.join(", ");
712
+ }
713
+ return void 0;
714
+ }
715
+ function parseAllowedTools(rawValue) {
716
+ if (!rawValue) return null;
717
+ let stripped = rawValue.trim();
718
+ if (stripped.length === 0) return null;
719
+ if (stripped.startsWith("[") && stripped.endsWith("]")) {
720
+ stripped = stripped.slice(1, -1).trim();
721
+ }
722
+ if (stripped.length === 0) return null;
723
+ const parts = stripped.split(",").map((s) => s.trim().replace(/^['"]|['"]$/g, "")).filter((s) => s.length > 0);
724
+ if (parts.length === 0) return null;
725
+ const sentinels = /* @__PURE__ */ new Set(["None", "none", "null", "Null", "~"]);
726
+ if (parts.some((p) => sentinels.has(p))) return null;
727
+ return parts;
728
+ }
729
+ function stemToken(word) {
730
+ let w = word;
731
+ if (w.length > 5 && w.endsWith("ing")) w = w.slice(0, -3);
732
+ else if (w.length > 5 && w.endsWith("ed")) w = w.slice(0, -2);
733
+ if (w.length > 4 && w.endsWith("s")) w = w.slice(0, -1);
734
+ if (w.length > 4 && w.endsWith("e")) w = w.slice(0, -1);
735
+ return w;
736
+ }
737
+ var STOPWORDS = /* @__PURE__ */ new Set([
738
+ "the",
739
+ "a",
740
+ "an",
741
+ "and",
742
+ "or",
743
+ "but",
744
+ "is",
745
+ "are",
746
+ "was",
747
+ "were",
748
+ "be",
749
+ "been",
750
+ "being",
751
+ "have",
752
+ "has",
753
+ "had",
754
+ "do",
755
+ "does",
756
+ "did",
757
+ "will",
758
+ "would",
759
+ "should",
760
+ "could",
761
+ "may",
762
+ "might",
763
+ "must",
764
+ "can",
765
+ "this",
766
+ "that",
767
+ "these",
768
+ "those",
769
+ "with",
770
+ "from",
771
+ "into",
772
+ "onto",
773
+ "for",
774
+ "when",
775
+ "where",
776
+ "which",
777
+ "what",
778
+ "who",
779
+ "how",
780
+ "why",
781
+ "use",
782
+ "uses",
783
+ "used",
784
+ "using",
785
+ "not",
786
+ "also",
787
+ "than",
788
+ "then",
789
+ "ensure",
790
+ "ensures",
791
+ "make",
792
+ "makes"
793
+ ]);
794
+ function tokenSet(text) {
795
+ return new Set(
796
+ text.toLowerCase().replace(/[^a-z0-9_\s]/g, " ").split(/\s+/).filter((w) => w.length >= 4 && !STOPWORDS.has(w)).map(stemToken)
797
+ );
798
+ }
799
+ function intersectionSize(a, b) {
800
+ let count = 0;
801
+ for (const token of a) {
802
+ if (b.has(token)) count++;
803
+ }
804
+ return count;
805
+ }
806
+ function descriptionSimilarity(a, b) {
807
+ const aTokens = tokenSet(a);
808
+ const bTokens = tokenSet(b);
809
+ if (aTokens.size === 0 || bTokens.size === 0) return 0;
810
+ const intersection = intersectionSize(aTokens, bTokens);
811
+ const union = aTokens.size + bTokens.size - intersection;
812
+ return union === 0 ? 0 : intersection / union;
813
+ }
814
+ function topicOverlapSimilarity(a, b, minTokens = 3) {
815
+ const aTokens = tokenSet(a);
816
+ const bTokens = tokenSet(b);
817
+ if (aTokens.size < minTokens || bTokens.size < minTokens) return 0;
818
+ const intersection = intersectionSize(aTokens, bTokens);
819
+ const smaller = Math.min(aTokens.size, bTokens.size);
820
+ return smaller === 0 ? 0 : intersection / smaller;
821
+ }
822
+ var DESCRIPTION_DUPLICATE_THRESHOLD = 0.4;
823
+ var TOPIC_OVERLAP_THRESHOLD = 0.6;
824
+ function checkFrontmatterPreservation(existing, incoming) {
825
+ const violations = [];
826
+ for (const field of PROTECTED_FRONTMATTER_FIELDS) {
827
+ const oldValue = extractFrontmatterField(existing, field);
828
+ const newValue = extractFrontmatterField(incoming, field);
829
+ if (oldValue === void 0 || newValue === void 0) continue;
830
+ if (field === "allowed-tools") {
831
+ const oldParsed = parseAllowedTools(oldValue);
832
+ const newParsed = parseAllowedTools(newValue);
833
+ if (oldParsed && newParsed) {
834
+ const oldSet = new Set(oldParsed);
835
+ const newSet = new Set(newParsed);
836
+ const changed = oldSet.size !== newSet.size || [...oldSet].some((t) => !newSet.has(t));
837
+ if (changed) {
838
+ violations.push(`${field}: was [${oldParsed.join(", ")}], changed to [${newParsed.join(", ")}]`);
839
+ }
840
+ continue;
841
+ }
842
+ }
843
+ if (oldValue !== newValue) {
844
+ violations.push(`${field}: was "${oldValue}", changed to "${newValue}"`);
845
+ }
846
+ }
847
+ const oldDesc = extractFrontmatterField(existing, "description");
848
+ const newDesc = extractFrontmatterField(incoming, "description");
849
+ if (oldDesc && newDesc && newDesc.length < oldDesc.length * 0.9) {
850
+ violations.push(
851
+ `description shortened from ${oldDesc.length} to ${newDesc.length} chars (${Math.round((1 - newDesc.length / oldDesc.length) * 100)}% reduction). Descriptions are the primary triggering mechanism \u2014 do not shorten them.`
852
+ );
853
+ }
854
+ return violations;
855
+ }
856
+ function validateSkillContent(content, dirName) {
857
+ const issues = [];
858
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
859
+ if (!fmMatch) {
860
+ issues.push("Missing YAML frontmatter (must start with --- and end with ---)");
861
+ return issues;
862
+ }
863
+ const frontmatter = fmMatch[1];
864
+ for (const field of REQUIRED_FRONTMATTER_FIELDS) {
865
+ if (!frontmatter.includes(`${field}:`)) {
866
+ issues.push(`Missing required frontmatter field: ${field}`);
867
+ }
868
+ }
869
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
870
+ if (nameMatch && !nameMatch[1].trim().startsWith("myco:")) {
871
+ issues.push(`Skill name must start with "myco:" prefix. Got: "${nameMatch[1].trim()}"`);
872
+ }
873
+ const managedMatch = frontmatter.match(/^managed_by:\s*(.+)$/m);
874
+ if (managedMatch && managedMatch[1].trim() !== "myco") {
875
+ issues.push(`managed_by must be "myco". Got: "${managedMatch[1].trim()}"`);
876
+ }
877
+ const rawAllowedTools = extractFrontmatterField(content, "allowed-tools");
878
+ if (rawAllowedTools) {
879
+ const rawValue = rawAllowedTools;
880
+ if (rawValue.includes("vault_")) {
881
+ issues.push(
882
+ "allowed-tools contains vault agent tool names (vault_*). Skills run in Claude Code sessions -- use Claude Code tool names instead: Read, Edit, Write, Bash, Grep, Glob"
883
+ );
884
+ } else {
885
+ const parsed = parseAllowedTools(rawValue);
886
+ if (parsed === null) {
887
+ issues.push(
888
+ `allowed-tools value is malformed or empty: "${rawValue}". Provide a comma-separated list of Claude Code tools, e.g. "Read, Edit, Write, Bash, Grep, Glob". Use the narrowest set the skill actually needs.`
889
+ );
890
+ } else {
891
+ const unknown = parsed.filter((t) => !ALLOWED_CLAUDE_CODE_TOOLS.has(t));
892
+ if (unknown.length > 0) {
893
+ issues.push(
894
+ `allowed-tools contains unknown tool name(s): ${unknown.join(", ")}. Valid Claude Code tools: ${[...ALLOWED_CLAUDE_CODE_TOOLS].join(", ")}.`
895
+ );
896
+ }
897
+ }
898
+ }
899
+ }
900
+ const listToolLines = frontmatter.match(/^\s+-\s+vault_\w+/gm);
901
+ if (listToolLines) {
902
+ issues.push(
903
+ "allowed-tools contains vault agent tool names (vault_*). Skills run in Claude Code sessions -- use Claude Code tool names instead: Read, Edit, Write, Bash, Grep, Glob"
904
+ );
905
+ }
906
+ const lineCount = content.split("\n").length;
907
+ if (lineCount > MAX_SKILL_LINES) {
908
+ issues.push(`Skill is ${lineCount} lines (max ${MAX_SKILL_LINES})`);
909
+ }
910
+ return issues;
617
911
  }
618
912
 
619
913
  // src/agent/instruction-builders.ts
620
914
  var SKILL_GENERATE_TASK = "skill-generate";
621
915
  var SKILL_EVOLVE_TASK = "skill-evolve";
916
+ var SKILL_SURVEY_TASK = "skill-survey";
917
+ var SURVEY_MAX_WISDOM_SPORES = 30;
918
+ var SURVEY_MAX_SESSIONS = 15;
919
+ var SURVEY_WATERMARK_KEY = "skill-survey-watermark";
622
920
  function buildSkillGenerateInstruction() {
623
921
  const candidates = listCandidates({ status: "approved", limit: 1 });
624
922
  if (candidates.length === 0) return void 0;
@@ -661,9 +959,103 @@ function buildSkillGenerateInstruction() {
661
959
  context: { candidate_id: c.id }
662
960
  };
663
961
  }
962
+ function buildSkillSurveyInstruction(agentId) {
963
+ const now = epochSeconds();
964
+ const watermarkState = getState(agentId, SURVEY_WATERMARK_KEY);
965
+ const watermarkEpoch = watermarkState ? Number(watermarkState.value) : 0;
966
+ const sinceFilter = watermarkEpoch > 0 ? { since: watermarkEpoch } : {};
967
+ const parts = [
968
+ "## Pre-assembled Vault Context",
969
+ "",
970
+ `Survey watermark: ${watermarkEpoch === 0 ? "first run (full scan)" : new Date(watermarkEpoch * 1e3).toISOString()}`,
971
+ ""
972
+ ];
973
+ const digests = listDigestExtracts(agentId);
974
+ if (digests.length > 0) {
975
+ const smallest = digests.reduce((a, b) => a.tier < b.tier ? a : b);
976
+ parts.push("### Digest");
977
+ parts.push(`**Tier ${smallest.tier}** (${smallest.content.length} chars):`);
978
+ parts.push(smallest.content);
979
+ parts.push("");
980
+ }
981
+ const wisdomSpores = listSpores({
982
+ observation_type: "wisdom",
983
+ limit: SURVEY_MAX_WISDOM_SPORES,
984
+ ...sinceFilter
985
+ });
986
+ if (wisdomSpores.length > 0) {
987
+ parts.push(`### Wisdom Spores (${wisdomSpores.length})`);
988
+ for (const s of wisdomSpores) {
989
+ parts.push(`- **${s.id}** (importance ${s.importance}): ${s.content.slice(0, 300)}`);
990
+ }
991
+ parts.push("");
992
+ }
993
+ const decisions = listSpores({
994
+ observation_type: "decision",
995
+ limit: 20,
996
+ ...sinceFilter
997
+ });
998
+ const gotchas = listSpores({
999
+ observation_type: "gotcha",
1000
+ limit: 10,
1001
+ ...sinceFilter
1002
+ });
1003
+ if (decisions.length > 0 || gotchas.length > 0) {
1004
+ parts.push(`### Decisions (${decisions.length}) & Gotchas (${gotchas.length})`);
1005
+ for (const s of [...decisions, ...gotchas]) {
1006
+ parts.push(`- **${s.observation_type}** ${s.id}: ${s.content.slice(0, 200)}`);
1007
+ }
1008
+ parts.push("");
1009
+ }
1010
+ const sessions = listSessions({
1011
+ limit: SURVEY_MAX_SESSIONS,
1012
+ ...sinceFilter
1013
+ });
1014
+ if (sessions.length > 0) {
1015
+ parts.push(`### Recent Sessions (${sessions.length})`);
1016
+ for (const s of sessions) {
1017
+ parts.push(`- **${s.id}**: ${s.title ?? "(untitled)"} \u2014 ${(s.summary ?? "").slice(0, 200)}`);
1018
+ }
1019
+ parts.push("");
1020
+ }
1021
+ const activeSkills = listSkillRecords({ status: "active", limit: 100 });
1022
+ parts.push(`### Active Skills (${activeSkills.length})`);
1023
+ for (const s of activeSkills) {
1024
+ parts.push(`- **${s.name}**: ${s.description.slice(0, 150)}`);
1025
+ }
1026
+ parts.push("");
1027
+ setState(agentId, SURVEY_WATERMARK_KEY, String(now), now);
1028
+ return { instruction: parts.join("\n") };
1029
+ }
664
1030
  var SKILL_EVOLVE_DEFAULT_ASSESS_INTERVAL_HOURS = 24;
665
- var SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN = 5;
666
- function buildSkillEvolveInstruction(params) {
1031
+ var SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN = 8;
1032
+ var MIN_SECTIONS_FOR_STANDALONE = 2;
1033
+ function extractHeadings(content) {
1034
+ const bodyMatch = content.match(/^---[\s\S]*?---\n([\s\S]*)$/);
1035
+ const body = bodyMatch ? bodyMatch[1] : content;
1036
+ return body.split("\n").filter((line) => line.startsWith("## ")).map((line) => line.slice(3).trim());
1037
+ }
1038
+ function headingOverlap(headingsA, headingsB) {
1039
+ if (headingsA.length === 0 || headingsB.length === 0) return { score: 0, shared: [] };
1040
+ const tokenize = (h) => new Set(
1041
+ h.toLowerCase().replace(/[^a-z0-9\s]/g, " ").split(/\s+/).filter((w) => w.length >= 4)
1042
+ );
1043
+ const shared = [];
1044
+ for (const a of headingsA) {
1045
+ const aTokens = tokenize(a);
1046
+ for (const b of headingsB) {
1047
+ const bTokens = tokenize(b);
1048
+ const intersection = [...aTokens].filter((t) => bTokens.has(t)).length;
1049
+ const union = (/* @__PURE__ */ new Set([...aTokens, ...bTokens])).size;
1050
+ if (union > 0 && intersection / union >= 0.5) {
1051
+ shared.push(`"${a}" ~ "${b}"`);
1052
+ }
1053
+ }
1054
+ }
1055
+ const smaller = Math.min(headingsA.length, headingsB.length);
1056
+ return { score: smaller > 0 ? shared.length / smaller : 0, shared };
1057
+ }
1058
+ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
667
1059
  const assessIntervalHours = Number(params?.assess_interval_hours ?? SKILL_EVOLVE_DEFAULT_ASSESS_INTERVAL_HOURS);
668
1060
  const maxSkillsPerRun = Number(params?.max_skills_per_run ?? SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN);
669
1061
  const now = epochSeconds();
@@ -682,14 +1074,11 @@ function buildSkillEvolveInstruction(params) {
682
1074
  if (lastAssessedAt > 0 && now - lastAssessedAt < intervalSeconds) continue;
683
1075
  const newSporeIds = listSporeIdsSince(knowledgeWatermark, 10);
684
1076
  if (newSporeIds.length === 0) continue;
685
- const lineage = listLineageForSkill(skill.id, 1);
686
- if (lineage.length === 0) continue;
687
1077
  needsAssessment.push({
688
1078
  id: skill.id,
689
1079
  name: skill.name,
690
1080
  generation: skill.generation,
691
1081
  description: skill.description,
692
- contentSnapshot: lineage[0].content_snapshot,
693
1082
  newSporeIds
694
1083
  });
695
1084
  if (needsAssessment.length >= maxSkillsPerRun) {
@@ -699,6 +1088,48 @@ function buildSkillEvolveInstruction(params) {
699
1088
  if (needsAssessment.length === 0) {
700
1089
  return "No skills need assessment. All active skills are current or were recently assessed. Report skip via vault_report and finish.";
701
1090
  }
1091
+ const structures = [];
1092
+ const skillHeadings = /* @__PURE__ */ new Map();
1093
+ for (const skill of allSkills) {
1094
+ let content = "";
1095
+ if (projectRoot && skill.path) {
1096
+ try {
1097
+ content = readFileSync(resolve(projectRoot, skill.path), "utf-8");
1098
+ } catch {
1099
+ }
1100
+ }
1101
+ const headings = extractHeadings(content);
1102
+ skillHeadings.set(skill.name, headings);
1103
+ structures.push({
1104
+ name: skill.name,
1105
+ sectionCount: headings.length,
1106
+ headings,
1107
+ narrow: headings.length < MIN_SECTIONS_FOR_STANDALONE
1108
+ });
1109
+ }
1110
+ const overlaps = [];
1111
+ for (let i = 0; i < allSkills.length; i++) {
1112
+ for (let j = i + 1; j < allSkills.length; j++) {
1113
+ const a = allSkills[i];
1114
+ const b = allSkills[j];
1115
+ const descJaccard = descriptionSimilarity(a.description, b.description);
1116
+ const aHeadings = skillHeadings.get(a.name) ?? [];
1117
+ const bHeadings = skillHeadings.get(b.name) ?? [];
1118
+ const ho = headingOverlap(aHeadings, bHeadings);
1119
+ const descFlag = descJaccard >= DESCRIPTION_DUPLICATE_THRESHOLD * 0.75;
1120
+ const headingFlag = ho.score >= 0.4;
1121
+ if (!descFlag && !headingFlag) continue;
1122
+ const verdict = descJaccard >= DESCRIPTION_DUPLICATE_THRESHOLD || ho.score >= 0.5 ? "potential-merge" : "potential-narrow";
1123
+ overlaps.push({
1124
+ skillA: a.name,
1125
+ skillB: b.name,
1126
+ descriptionJaccard: Math.round(descJaccard * 100) / 100,
1127
+ headingOverlap: Math.round(ho.score * 100) / 100,
1128
+ sharedHeadings: ho.shared,
1129
+ verdict
1130
+ });
1131
+ }
1132
+ }
702
1133
  const parts = [
703
1134
  `${needsAssessment.length} skill(s) need assessment.`,
704
1135
  `assess_interval_hours: ${assessIntervalHours}`,
@@ -711,19 +1142,66 @@ function buildSkillEvolveInstruction(params) {
711
1142
  parts.push(`id: ${skill.id}`);
712
1143
  parts.push(`description: ${skill.description}`);
713
1144
  parts.push(`new_spore_ids: ${JSON.stringify(skill.newSporeIds)}`);
1145
+ }
1146
+ parts.push("");
1147
+ parts.push("## All Active Skills (for inventory analysis)");
1148
+ for (const s of structures) {
1149
+ const skill = allSkills.find((sk) => sk.name === s.name);
1150
+ const narrowTag = s.narrow ? " **[NARROW \u2014 <2 sections]**" : "";
1151
+ parts.push(`- **${skill.name}** (gen ${skill.generation}, ${s.sectionCount} sections${narrowTag}): ${skill.description.slice(0, 200)}`);
1152
+ if (s.headings.length > 0) {
1153
+ parts.push(` Headings: ${s.headings.join(" | ")}`);
1154
+ }
1155
+ }
1156
+ const narrowSkills = structures.filter((s) => s.narrow);
1157
+ if (narrowSkills.length > 0) {
714
1158
  parts.push("");
715
- parts.push("### Current Content");
1159
+ parts.push("## Mechanically Narrow Skills (<2 H2 sections)");
1160
+ parts.push("These skills have insufficient section breadth for domain-level standalone status.");
1161
+ parts.push("Determine which broader skill each should be absorbed into.");
1162
+ for (const s of narrowSkills) {
1163
+ parts.push(`- **${s.name}**: ${s.sectionCount} section(s). Headings: ${s.headings.length > 0 ? s.headings.join(" | ") : "(none)"}`);
1164
+ }
1165
+ }
1166
+ if (overlaps.length > 0) {
716
1167
  parts.push("");
717
- parts.push(skill.contentSnapshot);
1168
+ parts.push("## Pre-computed Token Overlap");
1169
+ parts.push("Pairs flagged by description token similarity AND/OR heading overlap:");
1170
+ for (const o of overlaps) {
1171
+ parts.push(`- **${o.skillA}** <-> **${o.skillB}**: desc=${o.descriptionJaccard}, headings=${o.headingOverlap} (${o.verdict})`);
1172
+ if (o.sharedHeadings.length > 0) {
1173
+ parts.push(` Shared headings: ${o.sharedHeadings.join("; ")}`);
1174
+ }
1175
+ }
1176
+ }
1177
+ if (similarityProvider) {
1178
+ const idToName = new Map(allSkills.map((s) => [s.id, s.name]));
1179
+ try {
1180
+ const semanticPairs = similarityProvider.pairwiseSimilarity("skill_records", 0.65);
1181
+ if (semanticPairs.length > 0) {
1182
+ parts.push("");
1183
+ parts.push("## Semantic Similarity (embedding cosine distance)");
1184
+ parts.push("Pairs with cosine similarity >= 0.65. This is the STRONGEST overlap signal.");
1185
+ parts.push("High similarity (>0.8) means the skills describe nearly identical procedures.");
1186
+ for (const p of semanticPairs) {
1187
+ const nameA = idToName.get(p.idA) ?? p.idA;
1188
+ const nameB = idToName.get(p.idB) ?? p.idB;
1189
+ parts.push(`- **${nameA}** <-> **${nameB}**: cosine=${p.similarity}`);
1190
+ }
1191
+ }
1192
+ } catch {
1193
+ }
718
1194
  }
719
1195
  return parts.join("\n");
720
1196
  }
721
- function buildTaskInstruction(taskName, taskParams) {
1197
+ function buildTaskInstruction(taskName, taskParams, agentId, projectRoot, similarityProvider) {
722
1198
  switch (taskName) {
723
1199
  case SKILL_GENERATE_TASK:
724
1200
  return buildSkillGenerateInstruction();
1201
+ case SKILL_SURVEY_TASK:
1202
+ return agentId ? buildSkillSurveyInstruction(agentId) : void 0;
725
1203
  case SKILL_EVOLVE_TASK: {
726
- const instruction = buildSkillEvolveInstruction(taskParams);
1204
+ const instruction = buildSkillEvolveInstruction(taskParams, projectRoot, similarityProvider);
727
1205
  return instruction ? { instruction } : void 0;
728
1206
  }
729
1207
  default:
@@ -731,7 +1209,7 @@ function buildTaskInstruction(taskName, taskParams) {
731
1209
  }
732
1210
  }
733
1211
  function isInstructionRequiredTask(taskName) {
734
- return taskName === SKILL_GENERATE_TASK || taskName === SKILL_EVOLVE_TASK;
1212
+ return taskName === SKILL_GENERATE_TASK || taskName === SKILL_EVOLVE_TASK || taskName === SKILL_SURVEY_TASK;
735
1213
  }
736
1214
 
737
1215
  // src/db/queries/runs.ts
@@ -753,7 +1231,7 @@ var RUN_COLUMNS = [
753
1231
  "actions_taken",
754
1232
  "error"
755
1233
  ];
756
- var SELECT_COLUMNS4 = RUN_COLUMNS.join(", ");
1234
+ var SELECT_COLUMNS5 = RUN_COLUMNS.join(", ");
757
1235
  function toRunRow(row) {
758
1236
  return {
759
1237
  id: row.id,
@@ -795,13 +1273,13 @@ function insertRun(data) {
795
1273
  data.error ?? null
796
1274
  );
797
1275
  return toRunRow(
798
- db.prepare(`SELECT ${SELECT_COLUMNS4} FROM agent_runs WHERE id = ?`).get(data.id)
1276
+ db.prepare(`SELECT ${SELECT_COLUMNS5} FROM agent_runs WHERE id = ?`).get(data.id)
799
1277
  );
800
1278
  }
801
1279
  function getRun(id) {
802
1280
  const db = getDatabase();
803
1281
  const row = db.prepare(
804
- `SELECT ${SELECT_COLUMNS4} FROM agent_runs WHERE id = ?`
1282
+ `SELECT ${SELECT_COLUMNS5} FROM agent_runs WHERE id = ?`
805
1283
  ).get(id);
806
1284
  if (!row) return null;
807
1285
  return toRunRow(row);
@@ -836,7 +1314,7 @@ function listRuns(options = {}) {
836
1314
  const limit = options.limit ?? DEFAULT_LIST_LIMIT2;
837
1315
  const offset = options.offset ?? 0;
838
1316
  const rows = db.prepare(
839
- `SELECT ${SELECT_COLUMNS4}
1317
+ `SELECT ${SELECT_COLUMNS5}
840
1318
  FROM agent_runs
841
1319
  ${where}
842
1320
  ORDER BY started_at DESC NULLS LAST
@@ -885,7 +1363,7 @@ function updateRunStatus(id, status, completion) {
885
1363
  ).run(...params);
886
1364
  if (info.changes === 0) return null;
887
1365
  return toRunRow(
888
- db.prepare(`SELECT ${SELECT_COLUMNS4} FROM agent_runs WHERE id = ?`).get(id)
1366
+ db.prepare(`SELECT ${SELECT_COLUMNS5} FROM agent_runs WHERE id = ?`).get(id)
889
1367
  );
890
1368
  }
891
1369
  function getRunningRunForTask(agentId, taskName) {
@@ -994,6 +1472,66 @@ function resolveRunConfig(agentId, requestedTask, vaultDir) {
994
1472
  };
995
1473
  }
996
1474
 
1475
+ // src/db/queries/skill-lineage.ts
1476
+ var LINEAGE_COLUMNS = [
1477
+ "id",
1478
+ "skill_id",
1479
+ "generation",
1480
+ "action",
1481
+ "rationale",
1482
+ "source_ids_added",
1483
+ "content_snapshot",
1484
+ "created_at"
1485
+ ];
1486
+ var SELECT_COLUMNS6 = LINEAGE_COLUMNS.join(", ");
1487
+ function toLineageRow(row) {
1488
+ return {
1489
+ id: row.id,
1490
+ skill_id: row.skill_id,
1491
+ generation: row.generation,
1492
+ action: row.action,
1493
+ rationale: row.rationale,
1494
+ source_ids_added: row.source_ids_added ?? "[]",
1495
+ content_snapshot: row.content_snapshot,
1496
+ created_at: row.created_at
1497
+ };
1498
+ }
1499
+ function insertLineage(data) {
1500
+ const db = getDatabase();
1501
+ db.prepare(
1502
+ `INSERT INTO skill_lineage (
1503
+ id, skill_id, generation, action, rationale,
1504
+ source_ids_added, content_snapshot, created_at
1505
+ ) VALUES (
1506
+ ?, ?, ?, ?, ?,
1507
+ ?, ?, ?
1508
+ )`
1509
+ ).run(
1510
+ data.id,
1511
+ data.skill_id,
1512
+ data.generation,
1513
+ data.action,
1514
+ data.rationale,
1515
+ data.source_ids_added ?? "[]",
1516
+ data.content_snapshot,
1517
+ data.created_at
1518
+ );
1519
+ return toLineageRow(
1520
+ db.prepare(`SELECT ${SELECT_COLUMNS6} FROM skill_lineage WHERE id = ?`).get(data.id)
1521
+ );
1522
+ }
1523
+ function listLineageForSkill(skillId, limit = 50) {
1524
+ const db = getDatabase();
1525
+ const rows = db.prepare(
1526
+ `SELECT ${SELECT_COLUMNS6}
1527
+ FROM skill_lineage
1528
+ WHERE skill_id = ?
1529
+ ORDER BY generation DESC
1530
+ LIMIT ?`
1531
+ ).all(skillId, limit);
1532
+ return rows.map(toLineageRow);
1533
+ }
1534
+
997
1535
  // src/db/queries/batches.ts
998
1536
  var DEFAULT_UNPROCESSED_LIMIT = 100;
999
1537
  var BATCHES_DEFAULT_LIMIT = 200;
@@ -1020,7 +1558,7 @@ var BATCH_COLUMNS = [
1020
1558
  "machine_id",
1021
1559
  "synced_at"
1022
1560
  ];
1023
- var SELECT_COLUMNS5 = BATCH_COLUMNS.join(", ");
1561
+ var SELECT_COLUMNS7 = BATCH_COLUMNS.join(", ");
1024
1562
  function toBatchRow(row) {
1025
1563
  return {
1026
1564
  id: row.id,
@@ -1067,7 +1605,7 @@ function getUnprocessedBatches(options = {}) {
1067
1605
  params.push(limit);
1068
1606
  const where = conditions.join(" AND ");
1069
1607
  const rows = db.prepare(
1070
- `SELECT ${SELECT_COLUMNS5}
1608
+ `SELECT ${SELECT_COLUMNS7}
1071
1609
  FROM prompt_batches
1072
1610
  WHERE ${where}
1073
1611
  ORDER BY id ASC
@@ -1084,7 +1622,7 @@ function incrementActivityCount(id) {
1084
1622
  ).run(id);
1085
1623
  if (info.changes === 0) return null;
1086
1624
  return toBatchRow(
1087
- db.prepare(`SELECT ${SELECT_COLUMNS5} FROM prompt_batches WHERE id = ?`).get(id)
1625
+ db.prepare(`SELECT ${SELECT_COLUMNS7} FROM prompt_batches WHERE id = ?`).get(id)
1088
1626
  );
1089
1627
  }
1090
1628
  function markBatchProcessed(id) {
@@ -1096,7 +1634,7 @@ function markBatchProcessed(id) {
1096
1634
  ).run(PROCESSED_FLAG, id);
1097
1635
  if (info.changes === 0) return null;
1098
1636
  return toBatchRow(
1099
- db.prepare(`SELECT ${SELECT_COLUMNS5} FROM prompt_batches WHERE id = ?`).get(id)
1637
+ db.prepare(`SELECT ${SELECT_COLUMNS7} FROM prompt_batches WHERE id = ?`).get(id)
1100
1638
  );
1101
1639
  }
1102
1640
  function findBatchByPromptPrefix(sessionId, promptPrefix) {
@@ -1136,7 +1674,7 @@ function insertBatchStateless(data) {
1136
1674
  );
1137
1675
  const batchId = Number(info.lastInsertRowid);
1138
1676
  return toBatchRow(
1139
- db.prepare(`SELECT ${SELECT_COLUMNS5} FROM prompt_batches WHERE id = ?`).get(batchId)
1677
+ db.prepare(`SELECT ${SELECT_COLUMNS7} FROM prompt_batches WHERE id = ?`).get(batchId)
1140
1678
  );
1141
1679
  }
1142
1680
  function closeOpenBatches(sessionId, endedAt) {
@@ -1157,7 +1695,7 @@ function setResponseSummary(batchId, summary) {
1157
1695
  function getLatestBatch(sessionId) {
1158
1696
  const db = getDatabase();
1159
1697
  const row = db.prepare(
1160
- `SELECT ${SELECT_COLUMNS5} FROM prompt_batches
1698
+ `SELECT ${SELECT_COLUMNS7} FROM prompt_batches
1161
1699
  WHERE session_id = ?
1162
1700
  ORDER BY id DESC LIMIT 1`
1163
1701
  ).get(sessionId);
@@ -1169,7 +1707,7 @@ function listBatchesBySession(sessionId, options = {}) {
1169
1707
  const limit = options.limit ?? BATCHES_DEFAULT_LIMIT;
1170
1708
  const offset = options.offset ?? 0;
1171
1709
  const rows = db.prepare(
1172
- `SELECT ${SELECT_COLUMNS5}
1710
+ `SELECT ${SELECT_COLUMNS7}
1173
1711
  FROM prompt_batches
1174
1712
  WHERE session_id = ?
1175
1713
  ORDER BY prompt_number ASC
@@ -1205,7 +1743,7 @@ var GRAPH_EDGE_COLUMNS = [
1205
1743
  "machine_id",
1206
1744
  "synced_at"
1207
1745
  ];
1208
- var SELECT_COLUMNS6 = GRAPH_EDGE_COLUMNS.join(", ");
1746
+ var SELECT_COLUMNS8 = GRAPH_EDGE_COLUMNS.join(", ");
1209
1747
  function toGraphEdgeRow(row) {
1210
1748
  return {
1211
1749
  id: row.id,
@@ -1246,7 +1784,7 @@ function insertGraphEdge(data) {
1246
1784
  data.machine_id ?? getTeamMachineId()
1247
1785
  );
1248
1786
  const row = toGraphEdgeRow(
1249
- db.prepare(`SELECT ${SELECT_COLUMNS6} FROM graph_edges WHERE id = ?`).get(id)
1787
+ db.prepare(`SELECT ${SELECT_COLUMNS8} FROM graph_edges WHERE id = ?`).get(id)
1250
1788
  );
1251
1789
  syncRow("graph_edges", row);
1252
1790
  return row;
@@ -1275,7 +1813,7 @@ function listGraphEdges(options = {}) {
1275
1813
  const limit = options.limit ?? QUERY_DEFAULT_LIST_LIMIT;
1276
1814
  params.push(limit);
1277
1815
  const rows = db.prepare(
1278
- `SELECT ${SELECT_COLUMNS6}
1816
+ `SELECT ${SELECT_COLUMNS8}
1279
1817
  FROM graph_edges
1280
1818
  ${where}
1281
1819
  ORDER BY created_at DESC
@@ -1295,7 +1833,7 @@ function getGraphForNode(nodeId, nodeType, options) {
1295
1833
  const frontierArray = Array.from(frontier);
1296
1834
  const placeholders = frontierArray.map(() => `?`).join(", ");
1297
1835
  const rows = db.prepare(
1298
- `SELECT ${SELECT_COLUMNS6}
1836
+ `SELECT ${SELECT_COLUMNS8}
1299
1837
  FROM graph_edges
1300
1838
  WHERE source_id IN (${placeholders}) OR target_id IN (${placeholders})`
1301
1839
  ).all(...frontierArray, ...frontierArray);
@@ -1336,7 +1874,7 @@ var ENTITY_COLUMNS = [
1336
1874
  "machine_id",
1337
1875
  "synced_at"
1338
1876
  ];
1339
- var SELECT_COLUMNS7 = ENTITY_COLUMNS.join(", ");
1877
+ var SELECT_COLUMNS9 = ENTITY_COLUMNS.join(", ");
1340
1878
  function toEntityRow(row) {
1341
1879
  return {
1342
1880
  id: row.id,
@@ -1370,7 +1908,7 @@ function insertEntity(data) {
1370
1908
  data.machine_id ?? getTeamMachineId()
1371
1909
  );
1372
1910
  const row = toEntityRow(
1373
- db.prepare(`SELECT ${SELECT_COLUMNS7} FROM entities WHERE agent_id = ? AND type = ? AND name = ?`).get(
1911
+ db.prepare(`SELECT ${SELECT_COLUMNS9} FROM entities WHERE agent_id = ? AND type = ? AND name = ?`).get(
1374
1912
  data.agent_id,
1375
1913
  data.type,
1376
1914
  data.name
@@ -1382,7 +1920,7 @@ function insertEntity(data) {
1382
1920
  function getEntity(id) {
1383
1921
  const db = getDatabase();
1384
1922
  const row = db.prepare(
1385
- `SELECT ${SELECT_COLUMNS7} FROM entities WHERE id = ?`
1923
+ `SELECT ${SELECT_COLUMNS9} FROM entities WHERE id = ?`
1386
1924
  ).get(id);
1387
1925
  if (!row) return null;
1388
1926
  return toEntityRow(row);
@@ -1423,7 +1961,7 @@ function listEntities(options = {}) {
1423
1961
  params.push(limit);
1424
1962
  params.push(offset);
1425
1963
  const rows = db.prepare(
1426
- `SELECT ${SELECT_COLUMNS7}
1964
+ `SELECT ${SELECT_COLUMNS9}
1427
1965
  FROM entities
1428
1966
  ${where}
1429
1967
  ORDER BY last_seen DESC
@@ -1433,65 +1971,6 @@ function listEntities(options = {}) {
1433
1971
  return rows.map(toEntityRow);
1434
1972
  }
1435
1973
 
1436
- // src/db/queries/digest-extracts.ts
1437
- var EXTRACT_COLUMNS = [
1438
- "id",
1439
- "agent_id",
1440
- "tier",
1441
- "content",
1442
- "substrate_hash",
1443
- "generated_at",
1444
- "machine_id",
1445
- "synced_at"
1446
- ];
1447
- var SELECT_COLUMNS8 = EXTRACT_COLUMNS.join(", ");
1448
- function toDigestExtractRow(row) {
1449
- return {
1450
- id: row.id,
1451
- agent_id: row.agent_id,
1452
- tier: row.tier,
1453
- content: row.content,
1454
- substrate_hash: row.substrate_hash ?? null,
1455
- generated_at: row.generated_at,
1456
- machine_id: row.machine_id ?? "local",
1457
- synced_at: row.synced_at ?? null
1458
- };
1459
- }
1460
- function upsertDigestExtract(data) {
1461
- const db = getDatabase();
1462
- db.prepare(
1463
- `INSERT INTO digest_extracts (agent_id, tier, content, generated_at)
1464
- VALUES (?, ?, ?, ?)
1465
- ON CONFLICT (agent_id, tier) DO UPDATE SET
1466
- content = EXCLUDED.content,
1467
- generated_at = EXCLUDED.generated_at`
1468
- ).run(data.agent_id, data.tier, data.content, data.generated_at);
1469
- const row = db.prepare(
1470
- `SELECT ${SELECT_COLUMNS8} FROM digest_extracts WHERE agent_id = ? AND tier = ?`
1471
- ).get(data.agent_id, data.tier);
1472
- return toDigestExtractRow(row);
1473
- }
1474
- function getDigestExtract(agentId, tier) {
1475
- const db = getDatabase();
1476
- const row = db.prepare(
1477
- `SELECT ${SELECT_COLUMNS8} FROM digest_extracts
1478
- WHERE agent_id = ? AND tier = ?`
1479
- ).get(agentId, tier);
1480
- if (!row) return null;
1481
- return toDigestExtractRow(row);
1482
- }
1483
- function listDigestExtracts(agentId) {
1484
- const db = getDatabase();
1485
- const tierPlaceholders = DIGEST_TIERS.map(() => "?").join(", ");
1486
- const rows = db.prepare(
1487
- `SELECT ${SELECT_COLUMNS8}
1488
- FROM digest_extracts
1489
- WHERE agent_id = ? AND tier IN (${tierPlaceholders})
1490
- ORDER BY tier ASC`
1491
- ).all(agentId, ...DIGEST_TIERS);
1492
- return rows.map(toDigestExtractRow);
1493
- }
1494
-
1495
1974
  // src/db/queries/lineage.ts
1496
1975
  function createSporeLineage(spore) {
1497
1976
  if (spore.session_id) {
@@ -1558,7 +2037,7 @@ var REPORT_COLUMNS = [
1558
2037
  "details",
1559
2038
  "created_at"
1560
2039
  ];
1561
- var SELECT_COLUMNS9 = REPORT_COLUMNS.join(", ");
2040
+ var SELECT_COLUMNS10 = REPORT_COLUMNS.join(", ");
1562
2041
  function toReportRow(row) {
1563
2042
  return {
1564
2043
  id: row.id,
@@ -1588,13 +2067,13 @@ function insertReport(data) {
1588
2067
  );
1589
2068
  const reportId = Number(info.lastInsertRowid);
1590
2069
  return toReportRow(
1591
- db.prepare(`SELECT ${SELECT_COLUMNS9} FROM agent_reports WHERE id = ?`).get(reportId)
2070
+ db.prepare(`SELECT ${SELECT_COLUMNS10} FROM agent_reports WHERE id = ?`).get(reportId)
1592
2071
  );
1593
2072
  }
1594
2073
  function listReports(runId) {
1595
2074
  const db = getDatabase();
1596
2075
  const rows = db.prepare(
1597
- `SELECT ${SELECT_COLUMNS9}
2076
+ `SELECT ${SELECT_COLUMNS10}
1598
2077
  FROM agent_reports
1599
2078
  WHERE run_id = ?
1600
2079
  ORDER BY created_at ASC`
@@ -1651,6 +2130,14 @@ export {
1651
2130
  getDigestExtract,
1652
2131
  listDigestExtracts,
1653
2132
  errorMessage,
2133
+ setState,
2134
+ getStatesForAgent,
2135
+ descriptionSimilarity,
2136
+ topicOverlapSimilarity,
2137
+ DESCRIPTION_DUPLICATE_THRESHOLD,
2138
+ TOPIC_OVERLAP_THRESHOLD,
2139
+ checkFrontmatterPreservation,
2140
+ validateSkillContent,
1654
2141
  SKILL_GENERATE_TASK,
1655
2142
  buildTaskInstruction,
1656
2143
  isInstructionRequiredTask,
@@ -1671,4 +2158,4 @@ export {
1671
2158
  hasConfiguredProvider,
1672
2159
  resolveRunConfig
1673
2160
  };
1674
- //# sourceMappingURL=chunk-JDI4DPWD.js.map
2161
+ //# sourceMappingURL=chunk-C3EGL5JX.js.map