@goondocks/myco 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/dist/chunk-2UEJVXXE.js +33 -0
  4. package/dist/chunk-2UEJVXXE.js.map +1 -0
  5. package/dist/chunk-3JCXYLHD.js +33 -0
  6. package/dist/chunk-3JCXYLHD.js.map +1 -0
  7. package/dist/{chunk-NTYYYC32.js → chunk-5BGQJOJN.js} +47 -4
  8. package/dist/chunk-5BGQJOJN.js.map +1 -0
  9. package/dist/{chunk-QQWUV3TC.js → chunk-72OAG4SF.js} +2 -1
  10. package/dist/chunk-JIQISBPI.js +362 -0
  11. package/dist/chunk-JIQISBPI.js.map +1 -0
  12. package/dist/{cli-ZHUR53CS.js → cli-4RR3QBYK.js} +15 -6
  13. package/dist/cli-4RR3QBYK.js.map +1 -0
  14. package/dist/{client-HORA3CC4.js → client-43ML4EHJ.js} +3 -2
  15. package/dist/{init-LLLHUNSY.js → init-HTKEL3YT.js} +4 -4
  16. package/dist/{main-JY6O6ZVH.js → main-DTWU4OAH.js} +227 -537
  17. package/dist/main-DTWU4OAH.js.map +1 -0
  18. package/dist/{rebuild-YAN3TPFB.js → rebuild-TXMFYBOU.js} +27 -20
  19. package/dist/rebuild-TXMFYBOU.js.map +1 -0
  20. package/dist/reprocess-ARKHGDWF.js +199 -0
  21. package/dist/reprocess-ARKHGDWF.js.map +1 -0
  22. package/dist/{restart-NH5MX45I.js → restart-C5BCVG3A.js} +2 -2
  23. package/dist/{search-W3ECVSTH.js → search-YCKNX2WS.js} +7 -7
  24. package/dist/{server-DLBATUNG.js → server-EBKMQISL.js} +18 -23
  25. package/dist/{server-DLBATUNG.js.map → server-EBKMQISL.js.map} +1 -1
  26. package/dist/{session-start-DECLNJDI.js → session-start-ADZLL2YI.js} +3 -2
  27. package/dist/{session-start-DECLNJDI.js.map → session-start-ADZLL2YI.js.map} +1 -1
  28. package/dist/src/cli.js +1 -1
  29. package/dist/src/daemon/main.js +1 -1
  30. package/dist/src/hooks/post-tool-use.js +2 -1
  31. package/dist/src/hooks/post-tool-use.js.map +1 -1
  32. package/dist/src/hooks/session-end.js +2 -1
  33. package/dist/src/hooks/session-end.js.map +1 -1
  34. package/dist/src/hooks/session-start.js +1 -1
  35. package/dist/src/hooks/stop.js +2 -1
  36. package/dist/src/hooks/stop.js.map +1 -1
  37. package/dist/src/hooks/user-prompt-submit.js +2 -1
  38. package/dist/src/hooks/user-prompt-submit.js.map +1 -1
  39. package/dist/src/mcp/server.js +1 -1
  40. package/dist/version-N55WTRG5.js +11 -0
  41. package/dist/version-N55WTRG5.js.map +1 -0
  42. package/package.json +1 -1
  43. package/skills/myco/SKILL.md +34 -0
  44. package/dist/chunk-NTYYYC32.js.map +0 -1
  45. package/dist/cli-ZHUR53CS.js.map +0 -1
  46. package/dist/main-JY6O6ZVH.js.map +0 -1
  47. package/dist/rebuild-YAN3TPFB.js.map +0 -1
  48. /package/dist/{chunk-QQWUV3TC.js.map → chunk-72OAG4SF.js.map} +0 -0
  49. /package/dist/{client-HORA3CC4.js.map → client-43ML4EHJ.js.map} +0 -0
  50. /package/dist/{init-LLLHUNSY.js.map → init-HTKEL3YT.js.map} +0 -0
  51. /package/dist/{restart-NH5MX45I.js.map → restart-C5BCVG3A.js.map} +0 -0
  52. /package/dist/{search-W3ECVSTH.js.map → search-YCKNX2WS.js.map} +0 -0
@@ -12,7 +12,7 @@
12
12
  "source": {
13
13
  "source": "npm",
14
14
  "package": "@goondocks/myco",
15
- "version": "0.2.14"
15
+ "version": "0.3.1"
16
16
  },
17
17
  "description": "Collective agent intelligence — captures session knowledge and serves it back via MCP",
18
18
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myco",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Collective agent intelligence — captures session knowledge and serves it back to your team via MCP",
5
5
  "author": {
6
6
  "name": "goondocks-co",
@@ -0,0 +1,33 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ AgentRegistry
4
+ } from "./chunk-2QEJKG7R.js";
5
+
6
+ // src/version.ts
7
+ import fs from "fs";
8
+ import path from "path";
9
+ var cached;
10
+ function getPluginVersion() {
11
+ if (cached) return cached;
12
+ const pluginRoot = new AgentRegistry().resolvePluginRoot();
13
+ if (pluginRoot) {
14
+ cached = readVersionFrom(pluginRoot);
15
+ if (cached) return cached;
16
+ }
17
+ cached = readVersionFrom(process.cwd()) ?? "0.0.0";
18
+ return cached;
19
+ }
20
+ function readVersionFrom(dir) {
21
+ const pkgPath = path.join(dir, "package.json");
22
+ try {
23
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
24
+ return pkg.version;
25
+ } catch {
26
+ return void 0;
27
+ }
28
+ }
29
+
30
+ export {
31
+ getPluginVersion
32
+ };
33
+ //# sourceMappingURL=chunk-2UEJVXXE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * Resolve the plugin's package version from package.json.\n * Uses the agent registry to find the plugin root, then reads package.json.\n */\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { AgentRegistry } from './agents/registry.js';\n\nlet cached: string | undefined;\n\nexport function getPluginVersion(): string {\n if (cached) return cached;\n\n // Primary: resolve via agent env var (CLAUDE_PLUGIN_ROOT, etc.)\n const pluginRoot = new AgentRegistry().resolvePluginRoot();\n if (pluginRoot) {\n cached = readVersionFrom(pluginRoot);\n if (cached) return cached;\n }\n\n // Fallback: walk up from cwd\n cached = readVersionFrom(process.cwd()) ?? '0.0.0';\n return cached;\n}\n\nfunction readVersionFrom(dir: string): string | undefined {\n const pkgPath = path.join(dir, 'package.json');\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n return pkg.version;\n } catch {\n return undefined;\n }\n}\n"],"mappings":";;;;;;AAIA,OAAO,QAAQ;AACf,OAAO,UAAU;AAGjB,IAAI;AAEG,SAAS,mBAA2B;AACzC,MAAI,OAAQ,QAAO;AAGnB,QAAM,aAAa,IAAI,cAAc,EAAE,kBAAkB;AACzD,MAAI,YAAY;AACd,aAAS,gBAAgB,UAAU;AACnC,QAAI,OAAQ,QAAO;AAAA,EACrB;AAGA,WAAS,gBAAgB,QAAQ,IAAI,CAAC,KAAK;AAC3C,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAiC;AACxD,QAAM,UAAU,KAAK,KAAK,KAAK,cAAc;AAC7C,MAAI;AACF,UAAM,MAAM,KAAK,MAAM,GAAG,aAAa,SAAS,OAAO,CAAC;AACxD,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -0,0 +1,33 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+
3
+ // src/intelligence/batch.ts
4
+ var LLM_BATCH_CONCURRENCY = 3;
5
+ var EMBEDDING_BATCH_CONCURRENCY = 4;
6
+ async function batchExecute(items, fn, options) {
7
+ const { concurrency, onProgress } = options;
8
+ let succeeded = 0;
9
+ let failed = 0;
10
+ const results = [];
11
+ for (let i = 0; i < items.length; i += concurrency) {
12
+ const batch = items.slice(i, i + concurrency);
13
+ const settled = await Promise.allSettled(batch.map(fn));
14
+ for (const result of settled) {
15
+ if (result.status === "fulfilled") {
16
+ succeeded++;
17
+ results.push({ status: "fulfilled", value: result.value });
18
+ } else {
19
+ failed++;
20
+ results.push({ status: "rejected", reason: result.reason?.message ?? String(result.reason) });
21
+ }
22
+ }
23
+ onProgress?.(succeeded + failed, items.length);
24
+ }
25
+ return { succeeded, failed, results };
26
+ }
27
+
28
+ export {
29
+ LLM_BATCH_CONCURRENCY,
30
+ EMBEDDING_BATCH_CONCURRENCY,
31
+ batchExecute
32
+ };
33
+ //# sourceMappingURL=chunk-3JCXYLHD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/intelligence/batch.ts"],"sourcesContent":["/**\n * Batch execution utilities for LLM and embedding operations.\n *\n * Provides concurrency-limited parallel execution for bulk operations\n * like reprocessing, rebuilding, and any future batch pipeline.\n */\n\n/** Default concurrency for LLM calls (heavier, single-threaded backends). */\nexport const LLM_BATCH_CONCURRENCY = 3;\n/** Default concurrency for embedding calls (lighter, can run more in parallel). */\nexport const EMBEDDING_BATCH_CONCURRENCY = 4;\n\nexport interface BatchResult<T> {\n succeeded: number;\n failed: number;\n results: Array<{ status: 'fulfilled'; value: T } | { status: 'rejected'; reason: string }>;\n}\n\n/**\n * Execute async tasks with a concurrency limit.\n * Reports progress via an optional callback.\n */\nexport async function batchExecute<I, O>(\n items: I[],\n fn: (item: I) => Promise<O>,\n options: {\n concurrency: number;\n onProgress?: (completed: number, total: number) => void;\n },\n): Promise<BatchResult<O>> {\n const { concurrency, onProgress } = options;\n let succeeded = 0;\n let failed = 0;\n const results: BatchResult<O>['results'] = [];\n\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n const settled = await Promise.allSettled(batch.map(fn));\n\n for (const result of settled) {\n if (result.status === 'fulfilled') {\n succeeded++;\n results.push({ status: 'fulfilled', value: result.value });\n } else {\n failed++;\n results.push({ status: 'rejected', reason: (result.reason as Error)?.message ?? String(result.reason) });\n }\n }\n\n onProgress?.(succeeded + failed, items.length);\n }\n\n return { succeeded, failed, results };\n}\n"],"mappings":";;;AAQO,IAAM,wBAAwB;AAE9B,IAAM,8BAA8B;AAY3C,eAAsB,aACpB,OACA,IACA,SAIyB;AACzB,QAAM,EAAE,aAAa,WAAW,IAAI;AACpC,MAAI,YAAY;AAChB,MAAI,SAAS;AACb,QAAM,UAAqC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,aAAa;AAClD,UAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,WAAW;AAC5C,UAAM,UAAU,MAAM,QAAQ,WAAW,MAAM,IAAI,EAAE,CAAC;AAEtD,eAAW,UAAU,SAAS;AAC5B,UAAI,OAAO,WAAW,aAAa;AACjC;AACA,gBAAQ,KAAK,EAAE,QAAQ,aAAa,OAAO,OAAO,MAAM,CAAC;AAAA,MAC3D,OAAO;AACL;AACA,gBAAQ,KAAK,EAAE,QAAQ,YAAY,QAAS,OAAO,QAAkB,WAAW,OAAO,OAAO,MAAM,EAAE,CAAC;AAAA,MACzG;AAAA,IACF;AAEA,iBAAa,YAAY,QAAQ,MAAM,MAAM;AAAA,EAC/C;AAEA,SAAO,EAAE,WAAW,QAAQ,QAAQ;AACtC;","names":[]}
@@ -1,4 +1,7 @@
1
1
  import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ getPluginVersion
4
+ } from "./chunk-2UEJVXXE.js";
2
5
  import {
3
6
  AgentRegistry
4
7
  } from "./chunk-2QEJKG7R.js";
@@ -63,11 +66,51 @@ var DaemonClient = class {
63
66
  }
64
67
  }
65
68
  /**
66
- * Ensure the daemon is running. Spawns it if unhealthy and waits for it
67
- * to become ready. Returns true if the daemon is healthy after this call.
69
+ * Check if the daemon is running a stale version.
70
+ * Returns true if the daemon's version doesn't match the current plugin version.
71
+ */
72
+ async isStale() {
73
+ try {
74
+ const info = this.readDaemonJson();
75
+ if (!info) return false;
76
+ const res = await fetch(`http://127.0.0.1:${info.port}/health`, {
77
+ signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS)
78
+ });
79
+ if (!res.ok) return false;
80
+ const data = await res.json();
81
+ if (!data.myco) return false;
82
+ if (!data.version) return true;
83
+ return data.version !== getPluginVersion();
84
+ } catch {
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * Kill the running daemon process.
90
+ */
91
+ killDaemon() {
92
+ try {
93
+ const info = this.readDaemonJson();
94
+ if (!info) return;
95
+ process.kill(info.pid, "SIGTERM");
96
+ } catch {
97
+ }
98
+ try {
99
+ fs.unlinkSync(path.join(this.vaultDir, "daemon.json"));
100
+ } catch {
101
+ }
102
+ }
103
+ /**
104
+ * Ensure the daemon is running the current version. Spawns it if unhealthy
105
+ * or restarts it if the version is stale. Returns true if healthy after this call.
68
106
  */
69
107
  async ensureRunning() {
70
- if (await this.isHealthy()) return true;
108
+ if (await this.isStale()) {
109
+ this.killDaemon();
110
+ await new Promise((r) => setTimeout(r, 200));
111
+ } else if (await this.isHealthy()) {
112
+ return true;
113
+ }
71
114
  this.spawnDaemon();
72
115
  for (const delay of DAEMON_HEALTH_RETRY_DELAYS) {
73
116
  await new Promise((r) => setTimeout(r, delay));
@@ -101,4 +144,4 @@ var DaemonClient = class {
101
144
  export {
102
145
  DaemonClient
103
146
  };
104
- //# sourceMappingURL=chunk-NTYYYC32.js.map
147
+ //# sourceMappingURL=chunk-5BGQJOJN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/client.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport { DAEMON_CLIENT_TIMEOUT_MS, DAEMON_HEALTH_CHECK_TIMEOUT_MS, DAEMON_HEALTH_RETRY_DELAYS } from '../constants.js';\nimport { AgentRegistry } from '../agents/registry.js';\nimport { getPluginVersion } from '../version.js';\n\ninterface DaemonInfo {\n pid: number;\n port: number;\n}\n\ninterface HealthResponse {\n myco: boolean;\n version?: string;\n}\n\ninterface ClientResult {\n ok: boolean;\n data?: any;\n}\n\nexport class DaemonClient {\n private vaultDir: string;\n\n constructor(vaultDir: string) {\n this.vaultDir = vaultDir;\n }\n\n async post(endpoint: string, body: unknown): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async get(endpoint: string): Promise<ClientResult> {\n try {\n const info = this.readDaemonJson();\n if (!info) return { ok: false };\n\n const res = await fetch(`http://127.0.0.1:${info.port}${endpoint}`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n\n if (!res.ok) return { ok: false };\n const data = await res.json();\n return { ok: true, data };\n } catch {\n return { ok: false };\n }\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n const info = this.readDaemonJson();\n if (!info) return false;\n\n const res = await fetch(`http://127.0.0.1:${info.port}/health`, {\n signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS),\n });\n if (!res.ok) return false;\n const data = await res.json() as HealthResponse;\n return data.myco === true;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if the daemon is running a stale version.\n * Returns true if the daemon's version doesn't match the current plugin version.\n */\n private async isStale(): Promise<boolean> {\n try {\n const info = this.readDaemonJson();\n if (!info) return false;\n\n const res = await fetch(`http://127.0.0.1:${info.port}/health`, {\n signal: AbortSignal.timeout(DAEMON_HEALTH_CHECK_TIMEOUT_MS),\n });\n if (!res.ok) return false;\n const data = await res.json() as HealthResponse;\n if (!data.myco) return false;\n\n // No version in response = old daemon that predates this check\n if (!data.version) return true;\n\n return data.version !== getPluginVersion();\n } catch {\n return false;\n }\n }\n\n /**\n * Kill the running daemon process.\n */\n private killDaemon(): void {\n try {\n const info = this.readDaemonJson();\n if (!info) return;\n process.kill(info.pid, 'SIGTERM');\n } catch { /* already dead */ }\n try {\n fs.unlinkSync(path.join(this.vaultDir, 'daemon.json'));\n } catch { /* already gone */ }\n }\n\n /**\n * Ensure the daemon is running the current version. Spawns it if unhealthy\n * or restarts it if the version is stale. Returns true if healthy after this call.\n */\n async ensureRunning(): Promise<boolean> {\n // Check if daemon is running but stale (version mismatch)\n if (await this.isStale()) {\n this.killDaemon();\n // Brief pause for port release\n await new Promise((r) => setTimeout(r, 200));\n } else if (await this.isHealthy()) {\n return true;\n }\n\n this.spawnDaemon();\n\n for (const delay of DAEMON_HEALTH_RETRY_DELAYS) {\n await new Promise((r) => setTimeout(r, delay));\n if (await this.isHealthy()) return true;\n }\n return false;\n }\n\n spawnDaemon(): void {\n const pluginRoot = new AgentRegistry().resolvePluginRoot();\n const daemonScript = pluginRoot\n ? path.join(pluginRoot, 'dist', 'src', 'daemon', 'main.js')\n : path.resolve(import.meta.dirname, '..', 'daemon', 'main.js');\n if (!fs.existsSync(daemonScript)) return;\n\n const child = spawn('node', [daemonScript, '--vault', this.vaultDir], {\n detached: true,\n stdio: 'ignore',\n });\n child.unref();\n }\n\n private readDaemonJson(): DaemonInfo | null {\n try {\n const jsonPath = path.join(this.vaultDir, 'daemon.json');\n const content = fs.readFileSync(jsonPath, 'utf-8');\n const info = JSON.parse(content);\n if (typeof info.port !== 'number') return null;\n return info as DaemonInfo;\n } catch {\n return null;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -3665,6 +3665,7 @@ function extractTitle(content) {
3665
3665
  }
3666
3666
 
3667
3667
  export {
3668
+ require_gray_matter,
3668
3669
  PlanFrontmatterSchema,
3669
3670
  ARTIFACT_TYPES,
3670
3671
  indexNote,
@@ -3688,4 +3689,4 @@ strip-bom-string/index.js:
3688
3689
  * Released under the MIT License.
3689
3690
  *)
3690
3691
  */
3691
- //# sourceMappingURL=chunk-QQWUV3TC.js.map
3692
+ //# sourceMappingURL=chunk-72OAG4SF.js.map
@@ -0,0 +1,362 @@
1
+ import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
2
+ import {
3
+ formatMemoryBody,
4
+ sessionNoteId
5
+ } from "./chunk-P2Q77C5F.js";
6
+ import {
7
+ ARTIFACT_TYPES,
8
+ indexNote
9
+ } from "./chunk-72OAG4SF.js";
10
+ import {
11
+ external_exports
12
+ } from "./chunk-ISCT2SI6.js";
13
+ import {
14
+ AgentRegistry
15
+ } from "./chunk-2QEJKG7R.js";
16
+ import {
17
+ AI_RESPONSE_PREVIEW_CHARS,
18
+ CANDIDATE_CONTENT_PREVIEW,
19
+ CHARS_PER_TOKEN,
20
+ CLASSIFICATION_MAX_TOKENS,
21
+ COMMAND_PREVIEW_CHARS,
22
+ EXTRACTION_MAX_TOKENS,
23
+ PROMPT_PREVIEW_CHARS,
24
+ SUMMARY_MAX_TOKENS,
25
+ TITLE_MAX_TOKENS
26
+ } from "./chunk-Q7BEFSOV.js";
27
+
28
+ // src/prompts/index.ts
29
+ import fs from "fs";
30
+ import path from "path";
31
+ import { fileURLToPath } from "url";
32
+ function resolvePromptsDir() {
33
+ let dir = path.dirname(fileURLToPath(import.meta.url));
34
+ for (let i = 0; i < 5; i++) {
35
+ if (fs.existsSync(path.join(dir, "package.json"))) {
36
+ return path.join(dir, "dist", "src", "prompts");
37
+ }
38
+ if (fs.existsSync(path.join(dir, "extraction.md"))) {
39
+ return dir;
40
+ }
41
+ dir = path.dirname(dir);
42
+ }
43
+ return path.dirname(fileURLToPath(import.meta.url));
44
+ }
45
+ var PROMPTS_DIR = resolvePromptsDir();
46
+ var promptCache = /* @__PURE__ */ new Map();
47
+ function loadPrompt(name) {
48
+ let cached = promptCache.get(name);
49
+ if (!cached) {
50
+ cached = fs.readFileSync(path.join(PROMPTS_DIR, `${name}.md`), "utf-8").trim();
51
+ promptCache.set(name, cached);
52
+ }
53
+ return cached;
54
+ }
55
+ function interpolate(template, vars) {
56
+ let result = template;
57
+ for (const [key, value] of Object.entries(vars)) {
58
+ result = result.replaceAll(`{{${key}}}`, value);
59
+ }
60
+ return result;
61
+ }
62
+ function buildExtractionPrompt(sessionId, eventCount, toolSummary) {
63
+ return interpolate(loadPrompt("extraction"), {
64
+ sessionId,
65
+ eventCount: String(eventCount),
66
+ toolSummary
67
+ });
68
+ }
69
+ function buildSummaryPrompt(sessionId, user, content) {
70
+ return interpolate(loadPrompt("summary"), {
71
+ sessionId,
72
+ user,
73
+ content
74
+ });
75
+ }
76
+ function buildTitlePrompt(summary, sessionId) {
77
+ return interpolate(loadPrompt("title"), {
78
+ summary,
79
+ sessionId
80
+ });
81
+ }
82
+ var ARTIFACT_TYPE_DESCRIPTIONS = [
83
+ '"spec" \u2014 Design specifications, architecture documents',
84
+ '"plan" \u2014 Implementation plans, roadmaps',
85
+ '"rfc" \u2014 Requests for comment, proposals',
86
+ '"doc" \u2014 Documentation, guides, READMEs',
87
+ '"other" \u2014 Other substantive documents'
88
+ ];
89
+ function buildSimilarityPrompt(currentSummary, candidateSummary) {
90
+ return interpolate(loadPrompt("session-similarity"), {
91
+ currentSummary,
92
+ candidateSummary
93
+ });
94
+ }
95
+ function buildClassificationPrompt(sessionId, candidates) {
96
+ const fileList = candidates.map((c) => {
97
+ const truncated = c.content.slice(0, CANDIDATE_CONTENT_PREVIEW);
98
+ return `### ${c.path}
99
+ \`\`\`
100
+ ${truncated}
101
+ \`\`\``;
102
+ }).join("\n\n");
103
+ return interpolate(loadPrompt("classification"), {
104
+ sessionId,
105
+ fileList,
106
+ artifactTypes: ARTIFACT_TYPE_DESCRIPTIONS.map((d) => `- ${d}`).join("\n"),
107
+ validTypes: ARTIFACT_TYPES.join("|")
108
+ });
109
+ }
110
+
111
+ // src/intelligence/response.ts
112
+ var REASONING_PATTERNS = [
113
+ // <think>...</think>answer (DeepSeek, Qwen, GLM, many others)
114
+ /<think>[\s\S]*?<\/think>\s*/gi,
115
+ // Implicit opening: reasoning...</think>answer (GLM-4.7 observed)
116
+ /^[\s\S]*?<\/think>\s*/i,
117
+ // <reasoning>...</reasoning>answer
118
+ /<reasoning>[\s\S]*?<\/reasoning>\s*/gi,
119
+ // <|thinking|>...<|/thinking|>answer
120
+ /<\|thinking\|>[\s\S]*?<\|\/thinking\|>\s*/gi
121
+ ];
122
+ function stripReasoningTokens(text) {
123
+ if (!text) return text;
124
+ for (const pattern of REASONING_PATTERNS) {
125
+ const stripped = text.replace(pattern, "").trim();
126
+ if (stripped && stripped !== text.trim()) {
127
+ return stripped;
128
+ }
129
+ }
130
+ return text;
131
+ }
132
+ function extractJson(text) {
133
+ const cleaned = stripReasoningTokens(text);
134
+ const fenceMatch = cleaned.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
135
+ if (fenceMatch) {
136
+ return JSON.parse(fenceMatch[1].trim());
137
+ }
138
+ const objectMatch = cleaned.match(/\{[\s\S]*\}/);
139
+ if (objectMatch) {
140
+ return JSON.parse(objectMatch[0]);
141
+ }
142
+ return JSON.parse(cleaned);
143
+ }
144
+ function extractNumber(text) {
145
+ const cleaned = stripReasoningTokens(text).trim();
146
+ const match = cleaned.match(/(\d+\.?\d*)/);
147
+ if (match) return parseFloat(match[1]);
148
+ return parseFloat(cleaned);
149
+ }
150
+
151
+ // src/daemon/processor.ts
152
+ var ClassificationResponseSchema = external_exports.object({
153
+ artifacts: external_exports.array(external_exports.object({
154
+ source_path: external_exports.string(),
155
+ artifact_type: external_exports.enum(ARTIFACT_TYPES),
156
+ title: external_exports.string(),
157
+ tags: external_exports.array(external_exports.string()).default([])
158
+ })).default([])
159
+ });
160
+ var BufferProcessor = class {
161
+ constructor(backend, contextWindow = 8192) {
162
+ this.backend = backend;
163
+ this.contextWindow = contextWindow;
164
+ }
165
+ truncateForContext(data, maxTokens) {
166
+ const available = this.contextWindow - maxTokens;
167
+ const dataTokens = Math.ceil(data.length / CHARS_PER_TOKEN);
168
+ if (dataTokens <= available) return data;
169
+ const charBudget = available * CHARS_PER_TOKEN;
170
+ return data.slice(0, charBudget);
171
+ }
172
+ async process(events, sessionId) {
173
+ const rawPrompt = this.buildPromptForExtraction(events, sessionId);
174
+ const prompt = this.truncateForContext(rawPrompt, EXTRACTION_MAX_TOKENS);
175
+ try {
176
+ const response = await this.backend.summarize(prompt, { maxTokens: EXTRACTION_MAX_TOKENS });
177
+ const parsed = extractJson(response.text);
178
+ return {
179
+ summary: parsed.summary,
180
+ observations: parsed.observations ?? [],
181
+ degraded: false
182
+ };
183
+ } catch (error) {
184
+ return {
185
+ summary: `LLM processing failed for session ${sessionId}. ${events.length} events captured. Error: ${error.message}`,
186
+ observations: [],
187
+ degraded: true
188
+ };
189
+ }
190
+ }
191
+ buildPromptForExtraction(events, sessionId) {
192
+ const toolSummary = this.summarizeEvents(events);
193
+ return buildExtractionPrompt(sessionId, events.length, toolSummary);
194
+ }
195
+ async summarizeSession(conversationMarkdown, sessionId, user) {
196
+ const truncatedContent = this.truncateForContext(conversationMarkdown, SUMMARY_MAX_TOKENS);
197
+ const summaryPrompt = buildSummaryPrompt(sessionId, user ?? "unknown", truncatedContent);
198
+ let summaryText;
199
+ try {
200
+ const response = await this.backend.summarize(summaryPrompt, { maxTokens: SUMMARY_MAX_TOKENS });
201
+ summaryText = stripReasoningTokens(response.text);
202
+ } catch (error) {
203
+ summaryText = `Session ${sessionId} \u2014 summarization failed: ${error.message}`;
204
+ }
205
+ const titlePrompt = buildTitlePrompt(summaryText, sessionId);
206
+ let title;
207
+ try {
208
+ const response = await this.backend.summarize(titlePrompt, { maxTokens: TITLE_MAX_TOKENS });
209
+ title = stripReasoningTokens(response.text).trim();
210
+ } catch {
211
+ title = `Session ${sessionId}`;
212
+ }
213
+ return { summary: summaryText, title };
214
+ }
215
+ async classifyArtifacts(candidates, sessionId) {
216
+ if (candidates.length === 0) return [];
217
+ const prompt = this.buildPromptForClassification(candidates, sessionId);
218
+ const response = await this.backend.summarize(prompt, { maxTokens: CLASSIFICATION_MAX_TOKENS });
219
+ const raw = extractJson(response.text);
220
+ const parsed = ClassificationResponseSchema.parse(raw);
221
+ return parsed.artifacts;
222
+ }
223
+ buildPromptForClassification(candidates, sessionId) {
224
+ return buildClassificationPrompt(sessionId, candidates);
225
+ }
226
+ summarizeEvents(events) {
227
+ const toolCounts = /* @__PURE__ */ new Map();
228
+ const filesAccessed = /* @__PURE__ */ new Set();
229
+ const prompts = [];
230
+ const aiResponses = [];
231
+ for (const event of events) {
232
+ if (event.type === "user_prompt") {
233
+ const prompt = String(event.prompt ?? "");
234
+ if (prompt) prompts.push(prompt.slice(0, PROMPT_PREVIEW_CHARS));
235
+ continue;
236
+ }
237
+ if (event.type === "ai_response") {
238
+ const content = String(event.content ?? "");
239
+ if (content) aiResponses.push(content.slice(0, AI_RESPONSE_PREVIEW_CHARS));
240
+ continue;
241
+ }
242
+ const tool = String(event.tool_name ?? event.tool ?? "unknown");
243
+ toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);
244
+ const input = event.tool_input ?? event.input;
245
+ if (input?.path) filesAccessed.add(String(input.path));
246
+ if (input?.file_path) filesAccessed.add(String(input.file_path));
247
+ if (input?.command) filesAccessed.add(`[cmd] ${String(input.command).slice(0, COMMAND_PREVIEW_CHARS)}`);
248
+ }
249
+ const lines = [];
250
+ if (prompts.length > 0) {
251
+ lines.push("### User Prompts");
252
+ for (const p of prompts) {
253
+ lines.push(`- "${p}"`);
254
+ }
255
+ }
256
+ lines.push("\n### Tool Usage");
257
+ for (const [tool, count] of toolCounts) {
258
+ lines.push(`- ${tool}: ${count} calls`);
259
+ }
260
+ if (filesAccessed.size > 0) {
261
+ lines.push("\n### Files Accessed");
262
+ for (const file of filesAccessed) {
263
+ lines.push(`- ${file}`);
264
+ }
265
+ }
266
+ if (aiResponses.length > 0) {
267
+ lines.push("\n### AI Responses");
268
+ for (const r of aiResponses) {
269
+ lines.push(`- "${r}"`);
270
+ }
271
+ }
272
+ return lines.join("\n");
273
+ }
274
+ };
275
+
276
+ // src/capture/transcript-miner.ts
277
+ var TranscriptMiner = class {
278
+ registry;
279
+ constructor(config) {
280
+ this.registry = new AgentRegistry(config?.additionalAdapters);
281
+ }
282
+ /**
283
+ * Extract all conversation turns for a session.
284
+ * Convenience wrapper — delegates to getAllTurnsWithSource.
285
+ */
286
+ getAllTurns(sessionId) {
287
+ return this.getAllTurnsWithSource(sessionId).turns;
288
+ }
289
+ /**
290
+ * Extract turns using the hook-provided transcript path first (fast, no scanning),
291
+ * then fall back to adapter registry scanning if the path isn't provided.
292
+ */
293
+ getAllTurnsWithSource(sessionId, transcriptPath) {
294
+ if (transcriptPath) {
295
+ const result2 = this.registry.parseTurnsFromPath(transcriptPath);
296
+ if (result2) return result2;
297
+ }
298
+ const result = this.registry.getTranscriptTurns(sessionId);
299
+ if (result) return result;
300
+ return { turns: [], source: "none" };
301
+ }
302
+ };
303
+ function extractTurnsFromBuffer(events) {
304
+ const turns = [];
305
+ let current = null;
306
+ for (const event of events) {
307
+ const type = event.type;
308
+ if (type === "user_prompt") {
309
+ if (current) turns.push(current);
310
+ current = {
311
+ prompt: String(event.prompt ?? "").slice(0, PROMPT_PREVIEW_CHARS),
312
+ toolCount: 0,
313
+ timestamp: String(event.timestamp ?? (/* @__PURE__ */ new Date()).toISOString())
314
+ };
315
+ } else if (type === "tool_use") {
316
+ if (current) current.toolCount++;
317
+ }
318
+ }
319
+ if (current) turns.push(current);
320
+ return turns;
321
+ }
322
+
323
+ // src/vault/observations.ts
324
+ function writeObservationNotes(observations, sessionId, writer, index, vaultDir) {
325
+ const results = [];
326
+ for (const obs of observations) {
327
+ const obsId = `${obs.type}-${sessionId.slice(-6)}-${Date.now()}`;
328
+ const body = formatMemoryBody({
329
+ title: obs.title,
330
+ observationType: obs.type,
331
+ content: obs.content,
332
+ sessionId,
333
+ root_cause: obs.root_cause,
334
+ fix: obs.fix,
335
+ rationale: obs.rationale,
336
+ alternatives_rejected: obs.alternatives_rejected,
337
+ gained: obs.gained,
338
+ sacrificed: obs.sacrificed,
339
+ tags: obs.tags
340
+ });
341
+ const relativePath = writer.writeMemory({
342
+ id: obsId,
343
+ observation_type: obs.type,
344
+ session: sessionNoteId(sessionId),
345
+ tags: obs.tags,
346
+ content: body
347
+ });
348
+ indexNote(index, vaultDir, relativePath);
349
+ results.push({ id: obsId, path: relativePath, observation: obs });
350
+ }
351
+ return results;
352
+ }
353
+
354
+ export {
355
+ buildSimilarityPrompt,
356
+ extractNumber,
357
+ BufferProcessor,
358
+ TranscriptMiner,
359
+ extractTurnsFromBuffer,
360
+ writeObservationNotes
361
+ };
362
+ //# sourceMappingURL=chunk-JIQISBPI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prompts/index.ts","../src/intelligence/response.ts","../src/daemon/processor.ts","../src/capture/transcript-miner.ts","../src/vault/observations.ts"],"sourcesContent":["/**\n * Prompt loader — reads .md templates from disk and interpolates variables.\n * Prompts are markdown files in this directory, not TypeScript strings.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { ARTIFACT_TYPES } from '../vault/types.js';\nimport { CANDIDATE_CONTENT_PREVIEW } from '../constants.js';\n\n/**\n * Resolve the prompts directory. With tsup code-splitting, import.meta.url\n * points to a chunk file (dist/chunk-XXXX.js), not dist/src/prompts/.\n * Walk up from the current file to find package.json, then use dist/src/prompts/.\n */\nfunction resolvePromptsDir(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 5; i++) {\n if (fs.existsSync(path.join(dir, 'package.json'))) {\n return path.join(dir, 'dist', 'src', 'prompts');\n }\n // Also check if we're already in the right place (tsc output or dev mode)\n if (fs.existsSync(path.join(dir, 'extraction.md'))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n // Final fallback: adjacent to current file (works with tsc)\n return path.dirname(fileURLToPath(import.meta.url));\n}\n\nconst PROMPTS_DIR = resolvePromptsDir();\n\nconst promptCache = new Map<string, string>();\n\nfunction loadPrompt(name: string): string {\n let cached = promptCache.get(name);\n if (!cached) {\n cached = fs.readFileSync(path.join(PROMPTS_DIR, `${name}.md`), 'utf-8').trim();\n promptCache.set(name, cached);\n }\n return cached;\n}\n\nfunction interpolate(template: string, vars: Record<string, string>): string {\n let result = template;\n for (const [key, value] of Object.entries(vars)) {\n result = result.replaceAll(`{{${key}}}`, value);\n }\n return result;\n}\n\n// --- Prompt builders ---\n\nexport function buildExtractionPrompt(\n sessionId: string,\n eventCount: number,\n toolSummary: string,\n): string {\n return interpolate(loadPrompt('extraction'), {\n sessionId,\n eventCount: String(eventCount),\n toolSummary,\n });\n}\n\nexport function buildSummaryPrompt(\n sessionId: string,\n user: string,\n content: string,\n): string {\n return interpolate(loadPrompt('summary'), {\n sessionId,\n user,\n content,\n });\n}\n\nexport function buildTitlePrompt(\n summary: string,\n sessionId: string,\n): string {\n return interpolate(loadPrompt('title'), {\n summary,\n sessionId,\n });\n}\n\nconst ARTIFACT_TYPE_DESCRIPTIONS = [\n '\"spec\" — Design specifications, architecture documents',\n '\"plan\" — Implementation plans, roadmaps',\n '\"rfc\" — Requests for comment, proposals',\n '\"doc\" — Documentation, guides, READMEs',\n '\"other\" — Other substantive documents',\n];\n\nexport function buildSimilarityPrompt(\n currentSummary: string,\n candidateSummary: string,\n): string {\n return interpolate(loadPrompt('session-similarity'), {\n currentSummary,\n candidateSummary,\n });\n}\n\nexport function buildClassificationPrompt(\n sessionId: string,\n candidates: Array<{ path: string; content: string }>,\n): string {\n const fileList = candidates\n .map((c) => {\n const truncated = c.content.slice(0, CANDIDATE_CONTENT_PREVIEW);\n return `### ${c.path}\\n\\`\\`\\`\\n${truncated}\\n\\`\\`\\``;\n })\n .join('\\n\\n');\n\n return interpolate(loadPrompt('classification'), {\n sessionId,\n fileList,\n artifactTypes: ARTIFACT_TYPE_DESCRIPTIONS.map((d) => `- ${d}`).join('\\n'),\n validTypes: ARTIFACT_TYPES.join('|'),\n });\n}\n","/**\n * Clean LLM response text before parsing.\n *\n * Reasoning models (DeepSeek, Qwen, GLM, etc.) embed chain-of-thought\n * in the response using special tags. These must be stripped before\n * JSON parsing or value extraction.\n */\n\n// Patterns for reasoning model chain-of-thought tokens.\n// Order matters: most specific patterns first.\nconst REASONING_PATTERNS = [\n // <think>...</think>answer (DeepSeek, Qwen, GLM, many others)\n /<think>[\\s\\S]*?<\\/think>\\s*/gi,\n // Implicit opening: reasoning...</think>answer (GLM-4.7 observed)\n /^[\\s\\S]*?<\\/think>\\s*/i,\n // <reasoning>...</reasoning>answer\n /<reasoning>[\\s\\S]*?<\\/reasoning>\\s*/gi,\n // <|thinking|>...<|/thinking|>answer\n /<\\|thinking\\|>[\\s\\S]*?<\\|\\/thinking\\|>\\s*/gi,\n];\n\n/**\n * Strip reasoning/chain-of-thought tokens from LLM response text.\n * Returns the final answer without the thinking process.\n */\nexport function stripReasoningTokens(text: string): string {\n if (!text) return text;\n\n for (const pattern of REASONING_PATTERNS) {\n const stripped = text.replace(pattern, '').trim();\n if (stripped && stripped !== text.trim()) {\n return stripped;\n }\n }\n\n return text;\n}\n\n/**\n * Extract JSON from an LLM response that may contain markdown fences,\n * reasoning tokens, or other wrapper text.\n *\n * Tries in order:\n * 1. Strip reasoning tokens\n * 2. Extract from ```json ... ``` code fences\n * 3. Find bare {...} JSON object\n * 4. Parse the cleaned text directly\n */\nexport function extractJson(text: string): unknown {\n const cleaned = stripReasoningTokens(text);\n\n // Try code fence extraction\n const fenceMatch = cleaned.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?```/);\n if (fenceMatch) {\n return JSON.parse(fenceMatch[1].trim());\n }\n\n // Try bare JSON object\n const objectMatch = cleaned.match(/\\{[\\s\\S]*\\}/);\n if (objectMatch) {\n return JSON.parse(objectMatch[0]);\n }\n\n // Try direct parse\n return JSON.parse(cleaned);\n}\n\n/**\n * Extract a numeric value from an LLM response that may contain\n * reasoning tokens or extra text around the number.\n */\nexport function extractNumber(text: string): number {\n const cleaned = stripReasoningTokens(text).trim();\n const match = cleaned.match(/(\\d+\\.?\\d*)/);\n if (match) return parseFloat(match[1]);\n return parseFloat(cleaned);\n}\n","import { z } from 'zod';\nimport type { LlmProvider } from '../intelligence/llm.js';\nimport { ARTIFACT_TYPES } from '../vault/types.js';\nimport { CHARS_PER_TOKEN, EXTRACTION_MAX_TOKENS, SUMMARY_MAX_TOKENS, TITLE_MAX_TOKENS, CLASSIFICATION_MAX_TOKENS, PROMPT_PREVIEW_CHARS, AI_RESPONSE_PREVIEW_CHARS, COMMAND_PREVIEW_CHARS } from '../constants.js';\nimport type { ObservationType, ArtifactType } from '../vault/types.js';\nimport { buildExtractionPrompt, buildSummaryPrompt, buildTitlePrompt, buildClassificationPrompt } from '../prompts/index.js';\nimport { extractJson, stripReasoningTokens } from '../intelligence/response.js';\n\nexport interface Observation {\n type: ObservationType;\n title: string;\n content: string;\n tags: string[];\n root_cause?: string;\n fix?: string;\n rationale?: string;\n alternatives_rejected?: string;\n gained?: string;\n sacrificed?: string;\n}\n\nexport interface ProcessorResult {\n summary: string;\n observations: Observation[];\n degraded: boolean;\n}\n\nexport interface ClassifiedArtifact {\n source_path: string;\n artifact_type: ArtifactType;\n title: string;\n tags: string[];\n}\n\nconst ClassificationResponseSchema = z.object({\n artifacts: z.array(z.object({\n source_path: z.string(),\n artifact_type: z.enum(ARTIFACT_TYPES),\n title: z.string(),\n tags: z.array(z.string()).default([]),\n })).default([]),\n});\n\nexport class BufferProcessor {\n constructor(private backend: LlmProvider, private contextWindow: number = 8192) {}\n\n private truncateForContext(data: string, maxTokens: number): string {\n const available = this.contextWindow - maxTokens;\n const dataTokens = Math.ceil(data.length / CHARS_PER_TOKEN);\n if (dataTokens <= available) return data;\n const charBudget = available * CHARS_PER_TOKEN;\n return data.slice(0, charBudget);\n }\n\n async process(\n events: Array<Record<string, unknown>>,\n sessionId: string,\n ): Promise<ProcessorResult> {\n const rawPrompt = this.buildPromptForExtraction(events, sessionId);\n const prompt = this.truncateForContext(rawPrompt, EXTRACTION_MAX_TOKENS);\n\n try {\n const response = await this.backend.summarize(prompt, { maxTokens: EXTRACTION_MAX_TOKENS });\n const parsed = extractJson(response.text) as {\n summary: string;\n observations: Observation[];\n };\n\n return {\n summary: parsed.summary,\n observations: parsed.observations ?? [],\n degraded: false,\n };\n } catch (error) {\n return {\n summary: `LLM processing failed for session ${sessionId}. ${events.length} events captured. Error: ${(error as Error).message}`,\n observations: [],\n degraded: true,\n };\n }\n }\n\n private buildPromptForExtraction(\n events: Array<Record<string, unknown>>,\n sessionId: string,\n ): string {\n const toolSummary = this.summarizeEvents(events);\n return buildExtractionPrompt(sessionId, events.length, toolSummary);\n }\n\n async summarizeSession(\n conversationMarkdown: string,\n sessionId: string,\n user?: string,\n ): Promise<{ summary: string; title: string }> {\n const truncatedContent = this.truncateForContext(conversationMarkdown, SUMMARY_MAX_TOKENS);\n const summaryPrompt = buildSummaryPrompt(sessionId, user ?? 'unknown', truncatedContent);\n\n let summaryText: string;\n try {\n const response = await this.backend.summarize(summaryPrompt, { maxTokens: SUMMARY_MAX_TOKENS });\n summaryText = stripReasoningTokens(response.text);\n } catch (error) {\n summaryText = `Session ${sessionId} — summarization failed: ${(error as Error).message}`;\n }\n\n const titlePrompt = buildTitlePrompt(summaryText, sessionId);\n let title: string;\n try {\n const response = await this.backend.summarize(titlePrompt, { maxTokens: TITLE_MAX_TOKENS });\n title = stripReasoningTokens(response.text).trim();\n } catch {\n title = `Session ${sessionId}`;\n }\n\n return { summary: summaryText, title };\n }\n\n async classifyArtifacts(\n candidates: Array<{ path: string; content: string }>,\n sessionId: string,\n ): Promise<ClassifiedArtifact[]> {\n if (candidates.length === 0) return [];\n\n const prompt = this.buildPromptForClassification(candidates, sessionId);\n const response = await this.backend.summarize(prompt, { maxTokens: CLASSIFICATION_MAX_TOKENS });\n const raw = extractJson(response.text);\n const parsed = ClassificationResponseSchema.parse(raw);\n return parsed.artifacts;\n }\n\n private buildPromptForClassification(\n candidates: Array<{ path: string; content: string }>,\n sessionId: string,\n ): string {\n return buildClassificationPrompt(sessionId, candidates);\n }\n\n private summarizeEvents(events: Array<Record<string, unknown>>): string {\n const toolCounts = new Map<string, number>();\n const filesAccessed = new Set<string>();\n const prompts: string[] = [];\n const aiResponses: string[] = [];\n\n for (const event of events) {\n if (event.type === 'user_prompt') {\n const prompt = String(event.prompt ?? '');\n if (prompt) prompts.push(prompt.slice(0, PROMPT_PREVIEW_CHARS));\n continue;\n }\n\n if (event.type === 'ai_response') {\n const content = String(event.content ?? '');\n if (content) aiResponses.push(content.slice(0, AI_RESPONSE_PREVIEW_CHARS));\n continue;\n }\n\n // Hooks send tool_name/tool_input; also support legacy tool/input\n const tool = String(event.tool_name ?? event.tool ?? 'unknown');\n toolCounts.set(tool, (toolCounts.get(tool) ?? 0) + 1);\n\n const input = (event.tool_input ?? event.input) as Record<string, unknown> | undefined;\n if (input?.path) filesAccessed.add(String(input.path));\n if (input?.file_path) filesAccessed.add(String(input.file_path));\n if (input?.command) filesAccessed.add(`[cmd] ${String(input.command).slice(0, COMMAND_PREVIEW_CHARS)}`);\n }\n\n const lines: string[] = [];\n\n if (prompts.length > 0) {\n lines.push('### User Prompts');\n for (const p of prompts) {\n lines.push(`- \"${p}\"`);\n }\n }\n\n lines.push('\\n### Tool Usage');\n for (const [tool, count] of toolCounts) {\n lines.push(`- ${tool}: ${count} calls`);\n }\n\n if (filesAccessed.size > 0) {\n lines.push('\\n### Files Accessed');\n for (const file of filesAccessed) {\n lines.push(`- ${file}`);\n }\n }\n\n if (aiResponses.length > 0) {\n lines.push('\\n### AI Responses');\n for (const r of aiResponses) {\n lines.push(`- \"${r}\"`);\n }\n }\n\n return lines.join('\\n');\n }\n}\n","import { AgentRegistry } from '../agents/registry.js';\nimport type { AgentAdapter } from '../agents/adapter.js';\nimport { PROMPT_PREVIEW_CHARS } from '../constants.js';\nimport fs from 'node:fs';\n\n// Re-export TranscriptTurn from its canonical home in agents/adapter.ts\nexport type { TranscriptTurn } from '../agents/adapter.js';\nimport type { TranscriptTurn } from '../agents/adapter.js';\n\ninterface TranscriptConfig {\n /** Additional agent adapters to register (useful for testing or custom agents) */\n additionalAdapters?: AgentAdapter[];\n}\n\nexport class TranscriptMiner {\n private registry: AgentRegistry;\n\n constructor(config?: TranscriptConfig) {\n this.registry = new AgentRegistry(config?.additionalAdapters);\n }\n\n /**\n * Extract all conversation turns for a session.\n * Convenience wrapper — delegates to getAllTurnsWithSource.\n */\n getAllTurns(sessionId: string): TranscriptTurn[] {\n return this.getAllTurnsWithSource(sessionId).turns;\n }\n\n /**\n * Extract turns using the hook-provided transcript path first (fast, no scanning),\n * then fall back to adapter registry scanning if the path isn't provided.\n */\n getAllTurnsWithSource(sessionId: string, transcriptPath?: string): { turns: TranscriptTurn[]; source: string } {\n // Primary: use the path provided by the hook (no directory scanning needed)\n if (transcriptPath) {\n const result = this.registry.parseTurnsFromPath(transcriptPath);\n if (result) return result;\n }\n\n // Fallback: scan known agent directories\n const result = this.registry.getTranscriptTurns(sessionId);\n if (result) return result;\n return { turns: [], source: 'none' };\n }\n}\n\n/**\n * Build turns from buffer events — the fallback when no agent transcript is available.\n * Buffer events come from hooks (user_prompt, tool_use) and lack AI responses.\n * Turns will have prompts and tool counts but no aiResponse.\n */\nexport function extractTurnsFromBuffer(events: Array<Record<string, unknown>>): TranscriptTurn[] {\n const turns: TranscriptTurn[] = [];\n let current: TranscriptTurn | null = null;\n\n for (const event of events) {\n const type = event.type as string;\n if (type === 'user_prompt') {\n if (current) turns.push(current);\n current = {\n prompt: String(event.prompt ?? '').slice(0, PROMPT_PREVIEW_CHARS),\n toolCount: 0,\n timestamp: String(event.timestamp ?? new Date().toISOString()),\n };\n } else if (type === 'tool_use') {\n if (current) current.toolCount++;\n }\n }\n if (current) turns.push(current);\n return turns;\n}\n","import { formatMemoryBody } from '../obsidian/formatter.js';\nimport { sessionNoteId } from './session-id.js';\nimport { indexNote } from '../index/rebuild.js';\nimport type { Observation } from '../daemon/processor.js';\nimport type { VaultWriter } from './writer.js';\nimport type { MycoIndex } from '../index/sqlite.js';\n\nexport interface WrittenNote {\n id: string;\n path: string;\n observation: Observation;\n}\n\nexport function writeObservationNotes(\n observations: Observation[],\n sessionId: string,\n writer: VaultWriter,\n index: MycoIndex,\n vaultDir: string,\n): WrittenNote[] {\n const results: WrittenNote[] = [];\n\n for (const obs of observations) {\n const obsId = `${obs.type}-${sessionId.slice(-6)}-${Date.now()}`;\n const body = formatMemoryBody({\n title: obs.title,\n observationType: obs.type,\n content: obs.content,\n sessionId,\n root_cause: obs.root_cause,\n fix: obs.fix,\n rationale: obs.rationale,\n alternatives_rejected: obs.alternatives_rejected,\n gained: obs.gained,\n sacrificed: obs.sacrificed,\n tags: obs.tags,\n });\n const relativePath = writer.writeMemory({\n id: obsId,\n observation_type: obs.type,\n session: sessionNoteId(sessionId),\n tags: obs.tags,\n content: body,\n });\n indexNote(index, vaultDir, relativePath);\n results.push({ id: obsId, path: relativePath, observation: obs });\n }\n\n return results;\n}\n"],"mappings":"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","names":["result"]}