@goondocks/myco 0.6.1 → 0.6.3

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 (111) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/dist/{chunk-QGJ2ZIUZ.js → chunk-25FY74AP.js} +56 -22
  4. package/dist/chunk-25FY74AP.js.map +1 -0
  5. package/dist/{chunk-2YBUL3IL.js → chunk-4WL5X7VS.js} +3 -3
  6. package/dist/{chunk-24DOZEUJ.js → chunk-ALBVNGCF.js} +591 -27
  7. package/dist/chunk-ALBVNGCF.js.map +1 -0
  8. package/dist/{chunk-E7OBRBCQ.js → chunk-CK24O5YQ.js} +12 -2
  9. package/dist/chunk-CK24O5YQ.js.map +1 -0
  10. package/dist/{chunk-2GSX3BK2.js → chunk-CPVXNRGW.js} +4 -4
  11. package/dist/{chunk-L25U7PIG.js → chunk-CQ4RKK67.js} +2 -2
  12. package/dist/{chunk-GDYYJTTT.js → chunk-DBMHUMG3.js} +3 -3
  13. package/dist/{chunk-5FNZ7AMX.js → chunk-IWBWZQK6.js} +2 -2
  14. package/dist/{chunk-MQSYSQ6T.js → chunk-JSK7L46L.js} +11 -6
  15. package/dist/{chunk-MQSYSQ6T.js.map → chunk-JSK7L46L.js.map} +1 -1
  16. package/dist/{chunk-KUMVJIJW.js → chunk-LDKXXKF6.js} +6 -10
  17. package/dist/{chunk-KUMVJIJW.js.map → chunk-LDKXXKF6.js.map} +1 -1
  18. package/dist/{chunk-2ZBB3MQT.js → chunk-PQWQC3RF.js} +444 -21
  19. package/dist/chunk-PQWQC3RF.js.map +1 -0
  20. package/dist/{chunk-5QWZT4AB.js → chunk-RNWALAFP.js} +2 -2
  21. package/dist/{chunk-3EM23DMD.js → chunk-RXJHB7W4.js} +2 -2
  22. package/dist/{chunk-GNR3QAER.js → chunk-RY76WEN3.js} +2 -2
  23. package/dist/{chunk-6BSDCZ5Q.js → chunk-WBLTISAK.js} +8 -3
  24. package/dist/chunk-WBLTISAK.js.map +1 -0
  25. package/dist/{chunk-ZMYNRTTD.js → chunk-WU4PCNIK.js} +4 -3
  26. package/dist/chunk-WU4PCNIK.js.map +1 -0
  27. package/dist/{chunk-YTANWAGE.js → chunk-XNAM6Z4O.js} +2 -2
  28. package/dist/{chunk-P3WO3N3I.js → chunk-YG6MLLGL.js} +19 -3
  29. package/dist/{chunk-P3WO3N3I.js.map → chunk-YG6MLLGL.js.map} +1 -1
  30. package/dist/{cli-K7SUTP7A.js → cli-EGWAINIE.js} +20 -20
  31. package/dist/{client-YJMNTITQ.js → client-FDKJ4BY7.js} +5 -5
  32. package/dist/{config-G5GGT5A6.js → config-HDUFDOQN.js} +3 -3
  33. package/dist/{curate-6T5NKVXK.js → curate-OHIJFBYF.js} +10 -11
  34. package/dist/{curate-6T5NKVXK.js.map → curate-OHIJFBYF.js.map} +1 -1
  35. package/dist/{detect-providers-S3M5TAMW.js → detect-providers-4U3ZPW5G.js} +3 -3
  36. package/dist/{digest-O35VHYFP.js → digest-I2XYCK2M.js} +11 -13
  37. package/dist/{digest-O35VHYFP.js.map → digest-I2XYCK2M.js.map} +1 -1
  38. package/dist/{init-TFLSATB3.js → init-ZO2XQT6U.js} +8 -8
  39. package/dist/{main-JEUQS3BY.js → main-XZ6X4BUX.js} +177 -40
  40. package/dist/main-XZ6X4BUX.js.map +1 -0
  41. package/dist/{rebuild-7SH5GSNX.js → rebuild-NAH4EW5B.js} +10 -11
  42. package/dist/{rebuild-7SH5GSNX.js.map → rebuild-NAH4EW5B.js.map} +1 -1
  43. package/dist/reprocess-6FOP37XS.js +79 -0
  44. package/dist/reprocess-6FOP37XS.js.map +1 -0
  45. package/dist/{restart-NLJLB52D.js → restart-WSA4JSE3.js} +6 -6
  46. package/dist/{search-2BVRF54H.js → search-QXJQUB35.js} +6 -6
  47. package/dist/{server-4AMZNP4F.js → server-VXN3CJ4Y.js} +14 -18
  48. package/dist/{server-4AMZNP4F.js.map → server-VXN3CJ4Y.js.map} +1 -1
  49. package/dist/{session-start-AZAF3DTE.js → session-start-KQ4KCQMZ.js} +9 -9
  50. package/dist/setup-digest-QNCM3PNQ.js +15 -0
  51. package/dist/setup-llm-EAOIUSPJ.js +15 -0
  52. package/dist/src/cli.js +4 -4
  53. package/dist/src/daemon/main.js +4 -4
  54. package/dist/src/hooks/post-tool-use.js +5 -5
  55. package/dist/src/hooks/session-end.js +5 -5
  56. package/dist/src/hooks/session-start.js +4 -4
  57. package/dist/src/hooks/stop.js +7 -7
  58. package/dist/src/hooks/user-prompt-submit.js +5 -5
  59. package/dist/src/mcp/server.js +4 -4
  60. package/dist/src/prompts/consolidation.md +2 -0
  61. package/dist/src/prompts/digest-7500.md +68 -0
  62. package/dist/{stats-MKDIZFIQ.js → stats-43OESUEB.js} +6 -6
  63. package/dist/ui/assets/index-Bk4X_8-Z.css +1 -0
  64. package/dist/ui/assets/index-D3SY7ZHY.js +299 -0
  65. package/dist/ui/index.html +2 -2
  66. package/dist/{verify-7DW7LAND.js → verify-IIAHBAAU.js} +6 -6
  67. package/dist/{version-RQLD7VBP.js → version-NKOECSVH.js} +4 -4
  68. package/package.json +1 -1
  69. package/dist/chunk-24DOZEUJ.js.map +0 -1
  70. package/dist/chunk-2ZBB3MQT.js.map +0 -1
  71. package/dist/chunk-3JCXYLHD.js +0 -33
  72. package/dist/chunk-3JCXYLHD.js.map +0 -1
  73. package/dist/chunk-6BSDCZ5Q.js.map +0 -1
  74. package/dist/chunk-B5UZSHQV.js +0 -250
  75. package/dist/chunk-B5UZSHQV.js.map +0 -1
  76. package/dist/chunk-E7OBRBCQ.js.map +0 -1
  77. package/dist/chunk-KC7ENQTN.js +0 -436
  78. package/dist/chunk-KC7ENQTN.js.map +0 -1
  79. package/dist/chunk-QGJ2ZIUZ.js.map +0 -1
  80. package/dist/chunk-UVGAVYWZ.js +0 -157
  81. package/dist/chunk-UVGAVYWZ.js.map +0 -1
  82. package/dist/chunk-ZMYNRTTD.js.map +0 -1
  83. package/dist/main-JEUQS3BY.js.map +0 -1
  84. package/dist/reprocess-Q4YH2ZBK.js +0 -268
  85. package/dist/reprocess-Q4YH2ZBK.js.map +0 -1
  86. package/dist/setup-digest-YLZZGSSR.js +0 -15
  87. package/dist/setup-llm-JOXBSLXC.js +0 -15
  88. package/dist/ui/assets/index-D37IoDXS.css +0 -1
  89. package/dist/ui/assets/index-DA61Ial2.js +0 -289
  90. /package/dist/{chunk-2YBUL3IL.js.map → chunk-4WL5X7VS.js.map} +0 -0
  91. /package/dist/{chunk-2GSX3BK2.js.map → chunk-CPVXNRGW.js.map} +0 -0
  92. /package/dist/{chunk-L25U7PIG.js.map → chunk-CQ4RKK67.js.map} +0 -0
  93. /package/dist/{chunk-GDYYJTTT.js.map → chunk-DBMHUMG3.js.map} +0 -0
  94. /package/dist/{chunk-5FNZ7AMX.js.map → chunk-IWBWZQK6.js.map} +0 -0
  95. /package/dist/{chunk-5QWZT4AB.js.map → chunk-RNWALAFP.js.map} +0 -0
  96. /package/dist/{chunk-3EM23DMD.js.map → chunk-RXJHB7W4.js.map} +0 -0
  97. /package/dist/{chunk-GNR3QAER.js.map → chunk-RY76WEN3.js.map} +0 -0
  98. /package/dist/{chunk-YTANWAGE.js.map → chunk-XNAM6Z4O.js.map} +0 -0
  99. /package/dist/{cli-K7SUTP7A.js.map → cli-EGWAINIE.js.map} +0 -0
  100. /package/dist/{client-YJMNTITQ.js.map → client-FDKJ4BY7.js.map} +0 -0
  101. /package/dist/{config-G5GGT5A6.js.map → config-HDUFDOQN.js.map} +0 -0
  102. /package/dist/{detect-providers-S3M5TAMW.js.map → detect-providers-4U3ZPW5G.js.map} +0 -0
  103. /package/dist/{init-TFLSATB3.js.map → init-ZO2XQT6U.js.map} +0 -0
  104. /package/dist/{restart-NLJLB52D.js.map → restart-WSA4JSE3.js.map} +0 -0
  105. /package/dist/{search-2BVRF54H.js.map → search-QXJQUB35.js.map} +0 -0
  106. /package/dist/{session-start-AZAF3DTE.js.map → session-start-KQ4KCQMZ.js.map} +0 -0
  107. /package/dist/{setup-digest-YLZZGSSR.js.map → setup-digest-QNCM3PNQ.js.map} +0 -0
  108. /package/dist/{setup-llm-JOXBSLXC.js.map → setup-llm-EAOIUSPJ.js.map} +0 -0
  109. /package/dist/{stats-MKDIZFIQ.js.map → stats-43OESUEB.js.map} +0 -0
  110. /package/dist/{verify-7DW7LAND.js.map → verify-IIAHBAAU.js.map} +0 -0
  111. /package/dist/{version-RQLD7VBP.js.map → version-NKOECSVH.js.map} +0 -0
@@ -1,10 +1,19 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
2
  import {
3
- external_exports
4
- } from "./chunk-MQSYSQ6T.js";
3
+ generateEmbedding
4
+ } from "./chunk-RGVBGTD6.js";
5
5
  import {
6
- CANDIDATE_CONTENT_PREVIEW
7
- } from "./chunk-6BSDCZ5Q.js";
6
+ external_exports,
7
+ require_dist
8
+ } from "./chunk-JSK7L46L.js";
9
+ import {
10
+ CANDIDATE_CONTENT_PREVIEW,
11
+ EMBEDDING_INPUT_LIMIT,
12
+ LLM_REASONING_MODE,
13
+ SUPERSESSION_CANDIDATE_LIMIT,
14
+ SUPERSESSION_MAX_TOKENS,
15
+ SUPERSESSION_VECTOR_FETCH_LIMIT
16
+ } from "./chunk-WBLTISAK.js";
8
17
  import {
9
18
  __commonJS,
10
19
  __require,
@@ -3383,7 +3392,7 @@ var require_parse = __commonJS({
3383
3392
  var require_gray_matter = __commonJS({
3384
3393
  "node_modules/gray-matter/index.js"(exports2, module2) {
3385
3394
  "use strict";
3386
- var fs3 = __require("fs");
3395
+ var fs5 = __require("fs");
3387
3396
  var sections = require_section_matter();
3388
3397
  var defaults = require_defaults();
3389
3398
  var stringify = require_stringify();
@@ -3467,7 +3476,7 @@ var require_gray_matter = __commonJS({
3467
3476
  return stringify(file, data, options2);
3468
3477
  };
3469
3478
  matter2.read = function(filepath, options2) {
3470
- const str2 = fs3.readFileSync(filepath, "utf8");
3479
+ const str2 = fs5.readFileSync(filepath, "utf8");
3471
3480
  const file = matter2(str2, options2);
3472
3481
  file.path = filepath;
3473
3482
  return file;
@@ -3495,10 +3504,427 @@ var require_gray_matter = __commonJS({
3495
3504
  }
3496
3505
  });
3497
3506
 
3498
- // src/vault/reader.ts
3499
- var import_gray_matter = __toESM(require_gray_matter(), 1);
3507
+ // src/vault/session-id.ts
3508
+ var SESSION_PREFIX = "session-";
3509
+ function sessionNoteId(bareId) {
3510
+ if (bareId.startsWith(SESSION_PREFIX)) return bareId;
3511
+ return `${SESSION_PREFIX}${bareId}`;
3512
+ }
3513
+ function bareSessionId(noteId) {
3514
+ if (noteId.startsWith(SESSION_PREFIX)) return noteId.slice(SESSION_PREFIX.length);
3515
+ return noteId;
3516
+ }
3517
+ function sessionWikilink(bareId) {
3518
+ return `[[${sessionNoteId(bareId)}]]`;
3519
+ }
3520
+ function sessionRelativePath(bareId, date) {
3521
+ return `sessions/${date}/${sessionNoteId(bareId)}.md`;
3522
+ }
3523
+
3524
+ // src/obsidian/formatter.ts
3525
+ var CONVERSATION_HEADING = "## Conversation";
3526
+ var CALLOUT_MAP = {
3527
+ gotcha: "warning",
3528
+ bug_fix: "bug",
3529
+ decision: "info",
3530
+ discovery: "tip",
3531
+ trade_off: "question"
3532
+ };
3533
+ function observationCalloutType(observationType) {
3534
+ return CALLOUT_MAP[observationType] ?? "note";
3535
+ }
3536
+ function escapeHtmlTags(text) {
3537
+ return text.replace(/<(?=[a-zA-Z/!])/g, "\\<");
3538
+ }
3539
+ function callout(type, title, content) {
3540
+ const safe = escapeHtmlTags(content);
3541
+ const indented = safe.split("\n").map((line) => `> ${line}`).join("\n");
3542
+ return `> [!${type}] ${title}
3543
+ ${indented}`;
3544
+ }
3545
+ function inlineField(key, value) {
3546
+ return `${key}:: ${value}`;
3547
+ }
3548
+ function wikilink(target, display) {
3549
+ return display ? `[[${target}|${display}]]` : `[[${target}]]`;
3550
+ }
3551
+ function tagNormalize(s) {
3552
+ return s.replace(/_/g, "-");
3553
+ }
3554
+ function sanitizeTag(raw) {
3555
+ const stripped = raw.startsWith("#") ? raw.slice(1) : raw;
3556
+ return stripped.replace(/\s+/g, "/");
3557
+ }
3558
+ function buildTags(type, subtype, extraTags = []) {
3559
+ const tags = [`type/${type}`];
3560
+ if (subtype) {
3561
+ tags.push(`${type}/${tagNormalize(subtype)}`);
3562
+ }
3563
+ for (const tag of extraTags) {
3564
+ const normalized = sanitizeTag(tag);
3565
+ if (normalized && !tags.includes(normalized)) {
3566
+ tags.push(normalized);
3567
+ }
3568
+ }
3569
+ return tags;
3570
+ }
3571
+ function footerTags(tags) {
3572
+ return tags.map((t) => t.startsWith("#") ? t : `#${t}`).join(" ");
3573
+ }
3574
+ function formatSessionBody(input) {
3575
+ const sections = [];
3576
+ sections.push(`# ${input.title}`);
3577
+ if (input.narrative) {
3578
+ sections.push(callout("abstract", "Summary", input.narrative));
3579
+ }
3580
+ const fields = [];
3581
+ fields.push(inlineField("Session", wikilink(sessionNoteId(input.sessionId))));
3582
+ if (input.user) fields.push(inlineField("User", input.user));
3583
+ if (input.started && input.ended) {
3584
+ const duration = formatDuration(input.started, input.ended);
3585
+ if (duration) fields.push(inlineField("Duration", duration));
3586
+ }
3587
+ if (input.branch) fields.push(inlineField("Branch", `\`${input.branch}\``));
3588
+ sections.push(fields.join("\n"));
3589
+ if (input.relatedMemories?.length) {
3590
+ const links = input.relatedMemories.map((m) => `- ${wikilink(m.id, m.title)}`);
3591
+ sections.push(`## Related Spores
3592
+ ${links.join("\n")}`);
3593
+ }
3594
+ if (input.turns.length > 0) {
3595
+ const turnLines = [];
3596
+ for (let i = 0; i < input.turns.length; i++) {
3597
+ const turn = input.turns[i];
3598
+ const turnNum = i + 1;
3599
+ turnLines.push(`### Turn ${turnNum}`);
3600
+ if (turn.prompt || turn.images?.length) {
3601
+ const parts = [];
3602
+ if (turn.prompt) parts.push(turn.prompt);
3603
+ if (turn.images?.length) {
3604
+ parts.push(turn.images.map((f) => `![[${f}]]`).join("\n"));
3605
+ }
3606
+ if (turn.toolCount > 0) parts.push(`*${turn.toolCount} tool calls*`);
3607
+ turnLines.push(callout("user", "Prompt", parts.join("\n\n")));
3608
+ } else if (turn.toolCount > 0) {
3609
+ turnLines.push(callout("user", "Prompt", `*${turn.toolCount} tool calls*`));
3610
+ }
3611
+ if (turn.aiResponse) {
3612
+ turnLines.push(callout("assistant", "Response", turn.aiResponse));
3613
+ }
3614
+ }
3615
+ sections.push(`${CONVERSATION_HEADING}
3616
+
3617
+ ${turnLines.join("\n\n")}`);
3618
+ }
3619
+ const allTags = buildTags("session", "ended", [
3620
+ ...input.user ? [`user/${input.user}`] : [],
3621
+ ...input.tags ?? []
3622
+ ]);
3623
+ sections.push(footerTags(allTags));
3624
+ return sections.join("\n\n");
3625
+ }
3626
+ function formatSporeBody(input) {
3627
+ const sections = [];
3628
+ const calloutType = observationCalloutType(input.observationType);
3629
+ const calloutTitle = capitalize(tagNormalize(input.observationType));
3630
+ sections.push(`# ${input.title}`);
3631
+ sections.push(callout(calloutType, calloutTitle, input.content));
3632
+ const fields = [];
3633
+ if (input.sessionId) {
3634
+ fields.push(inlineField("Session", wikilink(sessionNoteId(input.sessionId))));
3635
+ }
3636
+ fields.push(inlineField("Observation", input.observationType));
3637
+ if (fields.length > 0) sections.push(fields.join("\n"));
3638
+ if (input.root_cause) sections.push(`## Root Cause
3639
+ ${input.root_cause}`);
3640
+ if (input.fix) sections.push(`## Fix
3641
+ ${input.fix}`);
3642
+ if (input.rationale) sections.push(`## Rationale
3643
+ ${input.rationale}`);
3644
+ if (input.alternatives_rejected) sections.push(`## Alternatives Rejected
3645
+ ${input.alternatives_rejected}`);
3646
+ if (input.gained) sections.push(`## Gained
3647
+ ${input.gained}`);
3648
+ if (input.sacrificed) sections.push(`## Sacrificed
3649
+ ${input.sacrificed}`);
3650
+ const allTags = buildTags("spore", input.observationType, input.tags ?? []);
3651
+ sections.push(footerTags(allTags));
3652
+ return sections.join("\n\n");
3653
+ }
3654
+ function formatPlanBody(input) {
3655
+ const sections = [];
3656
+ const fields = [];
3657
+ fields.push(inlineField("Plan", wikilink(input.id)));
3658
+ fields.push(inlineField("Status", input.status));
3659
+ if (input.author) fields.push(inlineField("Author", input.author));
3660
+ if (input.created) fields.push(inlineField("Created", input.created));
3661
+ sections.push(fields.join("\n"));
3662
+ sections.push(input.content);
3663
+ if (input.sessions?.length) {
3664
+ const links = input.sessions.map((s) => `- ${wikilink(sessionNoteId(s.id), s.title)}`);
3665
+ sections.push(`## Sessions
3666
+ ${links.join("\n")}`);
3667
+ }
3668
+ const statusTag = tagNormalize(input.status);
3669
+ const allTags = buildTags("plan", statusTag, input.tags ?? []);
3670
+ sections.push(footerTags(allTags));
3671
+ return sections.join("\n\n");
3672
+ }
3673
+ function formatArtifactBody(input) {
3674
+ const sections = [];
3675
+ const fields = [];
3676
+ fields.push(inlineField("Artifact", wikilink(input.id)));
3677
+ fields.push(inlineField("Source", `\`${input.source_path}\``));
3678
+ fields.push(inlineField("Type", input.artifact_type));
3679
+ fields.push(inlineField("Session", wikilink(sessionNoteId(input.sessionId))));
3680
+ sections.push(fields.join("\n"));
3681
+ sections.push(input.content);
3682
+ const allTags = buildTags("artifact", input.artifact_type, input.tags ?? []);
3683
+ sections.push(footerTags(allTags));
3684
+ return sections.join("\n\n");
3685
+ }
3686
+ function formatTeamBody(input) {
3687
+ const sections = [];
3688
+ sections.push(`# ${input.user}`);
3689
+ sections.push(callout("info", "Team Member", input.role ?? "Contributor"));
3690
+ const fields = [];
3691
+ fields.push(inlineField("User", input.user));
3692
+ if (input.role) fields.push(inlineField("Role", input.role));
3693
+ sections.push(fields.join("\n"));
3694
+ if (input.recentSessions?.length) {
3695
+ const links = input.recentSessions.map((s) => `- ${wikilink(sessionNoteId(s.id), s.title)}`);
3696
+ sections.push(`## Recent Sessions
3697
+ ${links.join("\n")}`);
3698
+ }
3699
+ const allTags = buildTags("team", "", [`user/${input.user}`]);
3700
+ sections.push(footerTags(allTags));
3701
+ return sections.join("\n\n");
3702
+ }
3703
+ var FOOTER_TAG_PREFIX = "\n#type/";
3704
+ function extractSection(body, heading) {
3705
+ const start = body.indexOf(heading);
3706
+ if (start === -1) return "";
3707
+ const section = body.slice(start + heading.length);
3708
+ const footerIdx = section.lastIndexOf(FOOTER_TAG_PREFIX);
3709
+ if (footerIdx !== -1) return section.slice(0, footerIdx).trim();
3710
+ return section.trim();
3711
+ }
3712
+ function capitalize(s) {
3713
+ return s.charAt(0).toUpperCase() + s.slice(1);
3714
+ }
3715
+ function formatDuration(started, ended) {
3716
+ const ms = new Date(ended).getTime() - new Date(started).getTime();
3717
+ if (isNaN(ms) || ms < 0) return "";
3718
+ const totalMinutes = Math.floor(ms / 6e4);
3719
+ if (totalMinutes < 1) return "<1m";
3720
+ const hours = Math.floor(totalMinutes / 60);
3721
+ const minutes = totalMinutes % 60;
3722
+ if (hours === 0) return `${minutes}m`;
3723
+ if (minutes === 0) return `${hours}h`;
3724
+ return `${hours}h ${minutes}m`;
3725
+ }
3726
+
3727
+ // src/vault/writer.ts
3728
+ var import_yaml = __toESM(require_dist(), 1);
3500
3729
  import fs from "fs";
3501
3730
  import path from "path";
3731
+ var VaultWriter = class {
3732
+ constructor(vaultDir) {
3733
+ this.vaultDir = vaultDir;
3734
+ }
3735
+ writeSession(input) {
3736
+ const date = input.started.slice(0, 10);
3737
+ const relativePath = sessionRelativePath(input.id, date);
3738
+ const frontmatter = {
3739
+ type: "session",
3740
+ id: input.id,
3741
+ agent: input.agent ?? "claude-code",
3742
+ user: input.user ?? "",
3743
+ started: input.started
3744
+ };
3745
+ if (input.ended) frontmatter.ended = input.ended;
3746
+ if (input.parent) frontmatter.parent = input.parent;
3747
+ if (input.parent_reason) frontmatter.parent_reason = input.parent_reason;
3748
+ if (input.plans?.length) frontmatter.plans = input.plans;
3749
+ if (input.branch) frontmatter.branch = input.branch;
3750
+ frontmatter.tags = buildTags("session", "ended", [
3751
+ ...input.user ? [`user/${input.user}`] : [],
3752
+ ...input.tags ?? []
3753
+ ]);
3754
+ if (input.tools_used != null) frontmatter.tools_used = input.tools_used;
3755
+ if (input.files_changed != null) frontmatter.files_changed = input.files_changed;
3756
+ this.writeMarkdown(relativePath, frontmatter, input.summary);
3757
+ return relativePath;
3758
+ }
3759
+ writePlan(input) {
3760
+ const relativePath = `plans/${input.id}.md`;
3761
+ const fullPath = path.join(this.vaultDir, relativePath);
3762
+ const status = input.status ?? "active";
3763
+ let created = (/* @__PURE__ */ new Date()).toISOString();
3764
+ try {
3765
+ const existing = fs.readFileSync(fullPath, "utf-8");
3766
+ const fmMatch = existing.match(/^---\n([\s\S]*?)\n---/);
3767
+ if (fmMatch) {
3768
+ const parsed = import_yaml.default.parse(fmMatch[1]);
3769
+ if (typeof parsed.created === "string") created = parsed.created;
3770
+ }
3771
+ } catch {
3772
+ }
3773
+ const frontmatter = {
3774
+ type: "plan",
3775
+ id: input.id,
3776
+ status,
3777
+ created
3778
+ };
3779
+ if (input.author) frontmatter.author = input.author;
3780
+ frontmatter.tags = buildTags("plan", status, input.tags ?? []);
3781
+ const body = formatPlanBody({
3782
+ id: input.id,
3783
+ status,
3784
+ author: input.author,
3785
+ created,
3786
+ content: input.content,
3787
+ tags: input.tags
3788
+ });
3789
+ this.writeMarkdown(relativePath, frontmatter, body);
3790
+ return relativePath;
3791
+ }
3792
+ writeSpore(input) {
3793
+ const normalizedType = input.observation_type.replace(/_/g, "-");
3794
+ const relativePath = `spores/${normalizedType}/${input.id}.md`;
3795
+ const fullPath = path.join(this.vaultDir, relativePath);
3796
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3797
+ let created = now;
3798
+ try {
3799
+ const existing = fs.readFileSync(fullPath, "utf-8");
3800
+ const fmMatch = existing.match(/^---\n([\s\S]*?)\n---/);
3801
+ if (fmMatch) {
3802
+ const parsed = import_yaml.default.parse(fmMatch[1]);
3803
+ if (typeof parsed.created === "string") created = parsed.created;
3804
+ }
3805
+ } catch {
3806
+ }
3807
+ const frontmatter = {
3808
+ type: "spore",
3809
+ id: input.id,
3810
+ observation_type: input.observation_type,
3811
+ created
3812
+ };
3813
+ if (input.session) frontmatter.session = input.session;
3814
+ if (input.plan) frontmatter.plan = input.plan;
3815
+ frontmatter.tags = buildTags("spore", input.observation_type, input.tags ?? []);
3816
+ this.writeMarkdown(relativePath, frontmatter, input.content);
3817
+ return relativePath;
3818
+ }
3819
+ writeArtifact(input) {
3820
+ const relativePath = `artifacts/${input.id}.md`;
3821
+ const fullPath = path.join(this.vaultDir, relativePath);
3822
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3823
+ let created = now;
3824
+ try {
3825
+ const existing = fs.readFileSync(fullPath, "utf-8");
3826
+ const fmMatch = existing.match(/^---\n([\s\S]*?)\n---/);
3827
+ if (fmMatch) {
3828
+ const parsed = import_yaml.default.parse(fmMatch[1]);
3829
+ if (typeof parsed.created === "string") created = parsed.created;
3830
+ }
3831
+ } catch {
3832
+ }
3833
+ const frontmatter = {
3834
+ type: "artifact",
3835
+ id: input.id,
3836
+ artifact_type: input.artifact_type,
3837
+ source_path: input.source_path,
3838
+ title: input.title,
3839
+ last_captured_by: sessionNoteId(input.session),
3840
+ created,
3841
+ updated: now,
3842
+ tags: buildTags("artifact", input.artifact_type, input.tags ?? [])
3843
+ };
3844
+ const body = formatArtifactBody({
3845
+ id: input.id,
3846
+ title: input.title,
3847
+ artifact_type: input.artifact_type,
3848
+ source_path: input.source_path,
3849
+ sessionId: input.session,
3850
+ content: input.content,
3851
+ tags: input.tags
3852
+ });
3853
+ this.writeMarkdown(relativePath, frontmatter, body);
3854
+ return relativePath;
3855
+ }
3856
+ writeTeamMember(input) {
3857
+ const relativePath = `team/${input.user}.md`;
3858
+ const frontmatter = {
3859
+ type: "team-member",
3860
+ user: input.user,
3861
+ joined: (/* @__PURE__ */ new Date()).toISOString(),
3862
+ tags: buildTags("team", "", [`user/${input.user}`])
3863
+ };
3864
+ if (input.role) frontmatter.role = input.role;
3865
+ const body = formatTeamBody({
3866
+ user: input.user,
3867
+ role: input.role
3868
+ });
3869
+ this.writeMarkdown(relativePath, frontmatter, body);
3870
+ return relativePath;
3871
+ }
3872
+ /**
3873
+ * Update frontmatter fields on an existing note without touching the body.
3874
+ * By default only adds fields that don't exist. Set overwrite=true to replace existing values.
3875
+ * Returns true if the update was applied, false if the file doesn't exist.
3876
+ */
3877
+ updateNoteFrontmatter(relativePath, fields, overwrite = false) {
3878
+ const fullPath = path.join(this.vaultDir, relativePath);
3879
+ let fileContent;
3880
+ try {
3881
+ fileContent = fs.readFileSync(fullPath, "utf-8");
3882
+ } catch {
3883
+ return false;
3884
+ }
3885
+ const fmMatch = fileContent.match(/^---\n([\s\S]*?)\n---/);
3886
+ if (!fmMatch) return false;
3887
+ const parsed = import_yaml.default.parse(fmMatch[1]);
3888
+ for (const [key, value] of Object.entries(fields)) {
3889
+ if (overwrite || parsed[key] === void 0) {
3890
+ parsed[key] = value;
3891
+ }
3892
+ }
3893
+ const body = fileContent.slice(fmMatch[0].length);
3894
+ const fmYaml = import_yaml.default.stringify(parsed, { defaultStringType: "QUOTE_DOUBLE", defaultKeyType: "PLAIN" }).trim();
3895
+ this.atomicWrite(fullPath, `---
3896
+ ${fmYaml}
3897
+ ---${body}`);
3898
+ return true;
3899
+ }
3900
+ /** @deprecated Use updateNoteFrontmatter instead */
3901
+ updateSessionFrontmatter(relativePath, fields) {
3902
+ return this.updateNoteFrontmatter(relativePath, fields);
3903
+ }
3904
+ writeMarkdown(relativePath, frontmatter, content) {
3905
+ const fullPath = path.join(this.vaultDir, relativePath);
3906
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
3907
+ const fmYaml = import_yaml.default.stringify(frontmatter, { defaultStringType: "QUOTE_DOUBLE", defaultKeyType: "PLAIN" }).trim();
3908
+ const file = `---
3909
+ ${fmYaml}
3910
+ ---
3911
+
3912
+ ${content}
3913
+ `;
3914
+ this.atomicWrite(fullPath, file);
3915
+ }
3916
+ /** Write to a temp file then rename — prevents Obsidian from seeing a truncated file mid-write. */
3917
+ atomicWrite(fullPath, content) {
3918
+ const tmp = `${fullPath}.tmp`;
3919
+ fs.writeFileSync(tmp, content, "utf-8");
3920
+ fs.renameSync(tmp, fullPath);
3921
+ }
3922
+ };
3923
+
3924
+ // src/vault/reader.ts
3925
+ var import_gray_matter = __toESM(require_gray_matter(), 1);
3926
+ import fs2 from "fs";
3927
+ import path2 from "path";
3502
3928
 
3503
3929
  // src/vault/types.ts
3504
3930
  var SessionFrontmatterSchema = external_exports.object({
@@ -3600,18 +4026,18 @@ var VaultReader = class {
3600
4026
  this.vaultDir = vaultDir;
3601
4027
  }
3602
4028
  readNote(relativePath) {
3603
- const fullPath = path.join(this.vaultDir, relativePath);
3604
- const raw = fs.readFileSync(fullPath, "utf-8");
4029
+ const fullPath = path2.join(this.vaultDir, relativePath);
4030
+ const raw = fs2.readFileSync(fullPath, "utf-8");
3605
4031
  const { data, content } = (0, import_gray_matter.default)(raw);
3606
4032
  const frontmatter = parseNoteFrontmatter(data);
3607
4033
  return { path: relativePath, frontmatter, content: content.trim() };
3608
4034
  }
3609
4035
  listNotes(subdir) {
3610
- const dirPath = path.join(this.vaultDir, subdir);
3611
- if (!fs.existsSync(dirPath)) return [];
4036
+ const dirPath = path2.join(this.vaultDir, subdir);
4037
+ if (!fs2.existsSync(dirPath)) return [];
3612
4038
  const files = this.walkMarkdownFiles(dirPath);
3613
4039
  return files.map((filePath) => {
3614
- const relativePath = path.relative(this.vaultDir, filePath);
4040
+ const relativePath = path2.relative(this.vaultDir, filePath);
3615
4041
  return this.readNote(relativePath);
3616
4042
  });
3617
4043
  }
@@ -3619,11 +4045,11 @@ var VaultReader = class {
3619
4045
  return VAULT_SUBDIRS.flatMap((subdir) => this.listNotes(subdir));
3620
4046
  }
3621
4047
  walkMarkdownFiles(dir) {
3622
- if (!fs.existsSync(dir)) return [];
4048
+ if (!fs2.existsSync(dir)) return [];
3623
4049
  const results = [];
3624
- const entries = fs.readdirSync(dir, { withFileTypes: true });
4050
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
3625
4051
  for (const entry of entries) {
3626
- const fullPath = path.join(dir, entry.name);
4052
+ const fullPath = path2.join(dir, entry.name);
3627
4053
  if (entry.isDirectory()) {
3628
4054
  results.push(...this.walkMarkdownFiles(fullPath));
3629
4055
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -3716,28 +4142,28 @@ function extractNumber(text) {
3716
4142
  }
3717
4143
 
3718
4144
  // src/prompts/index.ts
3719
- import fs2 from "fs";
3720
- import path2 from "path";
4145
+ import fs3 from "fs";
4146
+ import path3 from "path";
3721
4147
  import { fileURLToPath } from "url";
3722
4148
  function resolvePromptsDir() {
3723
- let dir = path2.dirname(fileURLToPath(import.meta.url));
4149
+ let dir = path3.dirname(fileURLToPath(import.meta.url));
3724
4150
  for (let i = 0; i < 5; i++) {
3725
- if (fs2.existsSync(path2.join(dir, "package.json"))) {
3726
- return path2.join(dir, "dist", "src", "prompts");
4151
+ if (fs3.existsSync(path3.join(dir, "package.json"))) {
4152
+ return path3.join(dir, "dist", "src", "prompts");
3727
4153
  }
3728
- if (fs2.existsSync(path2.join(dir, "extraction.md"))) {
4154
+ if (fs3.existsSync(path3.join(dir, "extraction.md"))) {
3729
4155
  return dir;
3730
4156
  }
3731
- dir = path2.dirname(dir);
4157
+ dir = path3.dirname(dir);
3732
4158
  }
3733
- return path2.dirname(fileURLToPath(import.meta.url));
4159
+ return path3.dirname(fileURLToPath(import.meta.url));
3734
4160
  }
3735
4161
  var PROMPTS_DIR = resolvePromptsDir();
3736
4162
  var promptCache = /* @__PURE__ */ new Map();
3737
4163
  function loadPrompt(name) {
3738
4164
  let cached = promptCache.get(name);
3739
4165
  if (!cached) {
3740
- cached = fs2.readFileSync(path2.join(PROMPTS_DIR, `${name}.md`), "utf-8").trim();
4166
+ cached = fs3.readFileSync(path3.join(PROMPTS_DIR, `${name}.md`), "utf-8").trim();
3741
4167
  promptCache.set(name, cached);
3742
4168
  }
3743
4169
  return cached;
@@ -3808,7 +4234,141 @@ ${truncated}
3808
4234
  });
3809
4235
  }
3810
4236
 
4237
+ // src/vault/curation.ts
4238
+ var import_yaml2 = __toESM(require_dist(), 1);
4239
+ import fs4 from "fs";
4240
+ import path4 from "path";
4241
+ var supersededIdsSchema = external_exports.array(external_exports.string());
4242
+ var SUPERSESSION_NOTICE_MARKER = "Superseded by::";
4243
+ function isActiveSpore(frontmatter) {
4244
+ const status = frontmatter.status;
4245
+ return !status || status === "active";
4246
+ }
4247
+ function supersedeSpore(targetId, newSporeId, targetPath, deps) {
4248
+ const fullPath = path4.join(deps.vaultDir, targetPath);
4249
+ let fileContent;
4250
+ try {
4251
+ fileContent = fs4.readFileSync(fullPath, "utf-8");
4252
+ } catch {
4253
+ return false;
4254
+ }
4255
+ const fmMatch = fileContent.match(/^---\n([\s\S]*?)\n---/);
4256
+ if (!fmMatch) return false;
4257
+ const parsed = import_yaml2.default.parse(fmMatch[1]);
4258
+ parsed.status = "superseded";
4259
+ parsed.superseded_by = newSporeId;
4260
+ const fmYaml = import_yaml2.default.stringify(parsed, { defaultStringType: "QUOTE_DOUBLE", defaultKeyType: "PLAIN" }).trim();
4261
+ let body = fileContent.slice(fmMatch[0].length);
4262
+ if (!body.includes(SUPERSESSION_NOTICE_MARKER)) {
4263
+ const notice = `
4264
+
4265
+ > [!warning] Superseded
4266
+ > This observation has been superseded.
4267
+
4268
+ ${SUPERSESSION_NOTICE_MARKER} [[${newSporeId}]]`;
4269
+ body = body.trimEnd() + notice + "\n";
4270
+ }
4271
+ const tmp = `${fullPath}.tmp`;
4272
+ fs4.writeFileSync(tmp, `---
4273
+ ${fmYaml}
4274
+ ---${body}`, "utf-8");
4275
+ fs4.renameSync(tmp, fullPath);
4276
+ indexNote(deps.index, deps.vaultDir, targetPath);
4277
+ deps.vectorIndex?.delete(targetId);
4278
+ return true;
4279
+ }
4280
+ async function checkSupersession(newSporeId, deps) {
4281
+ const { index, vectorIndex, embeddingProvider, llmProvider, vaultDir, log } = deps;
4282
+ if (!vectorIndex || !llmProvider) {
4283
+ log?.("debug", "checkSupersession: skipped \u2014 vectorIndex or llmProvider unavailable", { newSporeId });
4284
+ return [];
4285
+ }
4286
+ const newSporeResults = index.queryByIds([newSporeId]);
4287
+ if (newSporeResults.length === 0) {
4288
+ log?.("warn", "checkSupersession: new spore not found in index", { newSporeId });
4289
+ return [];
4290
+ }
4291
+ const newSpore = newSporeResults[0];
4292
+ const observationType = newSpore.frontmatter["observation_type"];
4293
+ const embeddingText = newSpore.content.slice(0, EMBEDDING_INPUT_LIMIT);
4294
+ const embeddingResult = await generateEmbedding(embeddingProvider, embeddingText);
4295
+ const vectorResults = vectorIndex.search(embeddingResult.embedding, {
4296
+ type: "spore",
4297
+ limit: SUPERSESSION_VECTOR_FETCH_LIMIT
4298
+ });
4299
+ if (vectorResults.length === 0) {
4300
+ log?.("debug", "checkSupersession: no vector results", { newSporeId });
4301
+ return [];
4302
+ }
4303
+ const candidateIds = vectorResults.map((r) => r.id);
4304
+ const candidateNotes = index.queryByIds(candidateIds);
4305
+ const filtered = candidateNotes.filter((note) => {
4306
+ if (note.id === newSporeId) return false;
4307
+ if (!isActiveSpore(note.frontmatter)) return false;
4308
+ if (observationType && note.frontmatter["observation_type"] !== observationType) return false;
4309
+ return true;
4310
+ }).slice(0, SUPERSESSION_CANDIDATE_LIMIT);
4311
+ if (filtered.length === 0) {
4312
+ log?.("debug", "checkSupersession: no candidates after filtering", { newSporeId, observationType });
4313
+ return [];
4314
+ }
4315
+ const template = loadPrompt("supersession");
4316
+ const newSporeText = formatNoteForPrompt(newSpore);
4317
+ const candidatesText = formatNotesForPrompt(filtered);
4318
+ const prompt = template.replace("{{new_spore}}", newSporeText).replace("{{candidates}}", candidatesText);
4319
+ let responseText;
4320
+ try {
4321
+ const response = await llmProvider.summarize(prompt, {
4322
+ maxTokens: SUPERSESSION_MAX_TOKENS,
4323
+ reasoning: LLM_REASONING_MODE
4324
+ });
4325
+ responseText = stripReasoningTokens(response.text);
4326
+ } catch (err) {
4327
+ log?.("warn", "checkSupersession: LLM call failed", { newSporeId, error: String(err) });
4328
+ return [];
4329
+ }
4330
+ let rawIds;
4331
+ try {
4332
+ rawIds = extractJson(responseText);
4333
+ } catch {
4334
+ log?.("warn", "checkSupersession: failed to parse LLM response", { newSporeId, responseText });
4335
+ return [];
4336
+ }
4337
+ const parsed = supersededIdsSchema.safeParse(rawIds);
4338
+ if (!parsed.success) {
4339
+ log?.("warn", "checkSupersession: LLM response failed schema validation", { newSporeId });
4340
+ return [];
4341
+ }
4342
+ const candidateMap = new Map(filtered.map((c) => [c.id, c]));
4343
+ const validIds = parsed.data.filter((id) => candidateMap.has(id));
4344
+ if (validIds.length === 0) {
4345
+ return [];
4346
+ }
4347
+ const supersededIds = [];
4348
+ for (const id of validIds) {
4349
+ const candidate = candidateMap.get(id);
4350
+ const wrote = supersedeSpore(id, newSporeId, candidate.path, { index, vectorIndex, vaultDir });
4351
+ if (!wrote) {
4352
+ log?.("warn", "checkSupersession: file not found for candidate, skipping", { id, path: candidate.path });
4353
+ continue;
4354
+ }
4355
+ supersededIds.push(id);
4356
+ log?.("info", "checkSupersession: marked superseded", { supersededId: id, newSporeId });
4357
+ }
4358
+ return supersededIds;
4359
+ }
4360
+
3811
4361
  export {
4362
+ sessionNoteId,
4363
+ bareSessionId,
4364
+ sessionWikilink,
4365
+ sessionRelativePath,
4366
+ CONVERSATION_HEADING,
4367
+ callout,
4368
+ formatSessionBody,
4369
+ formatSporeBody,
4370
+ extractSection,
4371
+ VaultWriter,
3812
4372
  require_gray_matter,
3813
4373
  PLAN_STATUSES,
3814
4374
  OBSERVATION_TYPES,
@@ -3825,7 +4385,11 @@ export {
3825
4385
  buildSummaryPrompt,
3826
4386
  buildTitlePrompt,
3827
4387
  buildSimilarityPrompt,
3828
- buildClassificationPrompt
4388
+ buildClassificationPrompt,
4389
+ supersededIdsSchema,
4390
+ isActiveSpore,
4391
+ supersedeSpore,
4392
+ checkSupersession
3829
4393
  };
3830
4394
  /*! Bundled license information:
3831
4395
 
@@ -3845,4 +4409,4 @@ strip-bom-string/index.js:
3845
4409
  * Released under the MIT License.
3846
4410
  *)
3847
4411
  */
3848
- //# sourceMappingURL=chunk-24DOZEUJ.js.map
4412
+ //# sourceMappingURL=chunk-ALBVNGCF.js.map