@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/dist/chunk-2UEJVXXE.js +33 -0
- package/dist/chunk-2UEJVXXE.js.map +1 -0
- package/dist/chunk-3JCXYLHD.js +33 -0
- package/dist/chunk-3JCXYLHD.js.map +1 -0
- package/dist/{chunk-NTYYYC32.js → chunk-5BGQJOJN.js} +47 -4
- package/dist/chunk-5BGQJOJN.js.map +1 -0
- package/dist/{chunk-QQWUV3TC.js → chunk-72OAG4SF.js} +2 -1
- package/dist/chunk-JIQISBPI.js +362 -0
- package/dist/chunk-JIQISBPI.js.map +1 -0
- package/dist/{cli-ZHUR53CS.js → cli-4RR3QBYK.js} +15 -6
- package/dist/cli-4RR3QBYK.js.map +1 -0
- package/dist/{client-HORA3CC4.js → client-43ML4EHJ.js} +3 -2
- package/dist/{init-LLLHUNSY.js → init-HTKEL3YT.js} +4 -4
- package/dist/{main-JY6O6ZVH.js → main-DTWU4OAH.js} +227 -537
- package/dist/main-DTWU4OAH.js.map +1 -0
- package/dist/{rebuild-YAN3TPFB.js → rebuild-TXMFYBOU.js} +27 -20
- package/dist/rebuild-TXMFYBOU.js.map +1 -0
- package/dist/reprocess-ARKHGDWF.js +199 -0
- package/dist/reprocess-ARKHGDWF.js.map +1 -0
- package/dist/{restart-NH5MX45I.js → restart-C5BCVG3A.js} +2 -2
- package/dist/{search-W3ECVSTH.js → search-YCKNX2WS.js} +7 -7
- package/dist/{server-DLBATUNG.js → server-EBKMQISL.js} +18 -23
- package/dist/{server-DLBATUNG.js.map → server-EBKMQISL.js.map} +1 -1
- package/dist/{session-start-DECLNJDI.js → session-start-ADZLL2YI.js} +3 -2
- package/dist/{session-start-DECLNJDI.js.map → session-start-ADZLL2YI.js.map} +1 -1
- package/dist/src/cli.js +1 -1
- package/dist/src/daemon/main.js +1 -1
- package/dist/src/hooks/post-tool-use.js +2 -1
- package/dist/src/hooks/post-tool-use.js.map +1 -1
- package/dist/src/hooks/session-end.js +2 -1
- package/dist/src/hooks/session-end.js.map +1 -1
- package/dist/src/hooks/session-start.js +1 -1
- package/dist/src/hooks/stop.js +2 -1
- package/dist/src/hooks/stop.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.js +2 -1
- package/dist/src/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/version-N55WTRG5.js +11 -0
- package/dist/version-N55WTRG5.js.map +1 -0
- package/package.json +1 -1
- package/skills/myco/SKILL.md +34 -0
- package/dist/chunk-NTYYYC32.js.map +0 -1
- package/dist/cli-ZHUR53CS.js.map +0 -1
- package/dist/main-JY6O6ZVH.js.map +0 -1
- package/dist/rebuild-YAN3TPFB.js.map +0 -1
- /package/dist/{chunk-QQWUV3TC.js.map → chunk-72OAG4SF.js.map} +0 -0
- /package/dist/{client-HORA3CC4.js.map → client-43ML4EHJ.js.map} +0 -0
- /package/dist/{init-LLLHUNSY.js.map → init-HTKEL3YT.js.map} +0 -0
- /package/dist/{restart-NH5MX45I.js.map → restart-C5BCVG3A.js.map} +0 -0
- /package/dist/{search-W3ECVSTH.js.map → search-YCKNX2WS.js.map} +0 -0
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
} from "./chunk-2TKJPRZL.js";
|
|
16
16
|
import {
|
|
17
17
|
DaemonClient
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-5BGQJOJN.js";
|
|
19
|
+
import "./chunk-2UEJVXXE.js";
|
|
19
20
|
import {
|
|
20
21
|
resolveVaultDir
|
|
21
22
|
} from "./chunk-N33KUCFP.js";
|
|
@@ -187,4 +188,4 @@ async function main() {
|
|
|
187
188
|
}
|
|
188
189
|
}
|
|
189
190
|
main();
|
|
190
|
-
//# sourceMappingURL=session-start-
|
|
191
|
+
//# sourceMappingURL=session-start-ADZLL2YI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context/relevance.ts","../src/context/injector.ts","../src/hooks/session-start.ts"],"sourcesContent":["import type { IndexedNote } from '../index/sqlite.js';\n\nexport interface ScoredNote {\n note: IndexedNote;\n score: number;\n reason: string;\n}\n\ninterface RelevanceInput {\n branch?: string;\n activePlanIds?: string[];\n}\n\n// --- Recency thresholds (hours) and score weights ---\nconst RECENCY_TIERS = [\n { maxHours: 24, score: 3, label: 'recent (<24h)' },\n { maxHours: 72, score: 2, label: 'recent (<72h)' },\n { maxHours: 168, score: 1, label: 'recent (<1w)' },\n] as const;\n\nconst BRANCH_MATCH_SCORE = 3;\nconst PLAN_MATCH_SCORE = 2;\n\nconst MS_PER_HOUR = 3_600_000;\n\nexport function scoreRelevance(\n notes: IndexedNote[],\n input: RelevanceInput,\n): ScoredNote[] {\n return notes\n .map((note) => {\n let score = 0;\n const reasons: string[] = [];\n\n const fm = note.frontmatter as Record<string, unknown>;\n\n // Recency boost\n const age = Date.now() - new Date(note.created).getTime();\n const hoursOld = age / MS_PER_HOUR;\n for (const tier of RECENCY_TIERS) {\n if (hoursOld < tier.maxHours) {\n score += tier.score;\n reasons.push(tier.label);\n break;\n }\n }\n\n // Branch match\n if (input.branch && fm.branch === input.branch) {\n score += BRANCH_MATCH_SCORE;\n reasons.push('same branch');\n }\n\n // Plan match\n if (input.activePlanIds?.length) {\n const planRef = fm.plan as string | undefined;\n if (planRef && input.activePlanIds.some((id) =>\n planRef === `[[${id}]]` || planRef === id,\n )) {\n score += PLAN_MATCH_SCORE;\n reasons.push('active plan');\n }\n }\n\n return { note, score, reason: reasons.join(', ') };\n })\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score);\n}\n","import type { MycoIndex } from '../index/sqlite.js';\nimport type { MycoConfig } from '../config/schema.js';\nimport { planFm, memoryFm } from '../vault/frontmatter.js';\nimport { scoreRelevance } from './relevance.js';\nimport { CHARS_PER_TOKEN, CONTEXT_PLAN_PREVIEW_CHARS, CONTEXT_SESSION_PREVIEW_CHARS, CONTEXT_MEMORY_PREVIEW_CHARS } from '../constants.js';\n\ninterface InjectionContext {\n branch?: string;\n}\n\ninterface InjectedContext {\n text: string;\n tokenEstimate: number;\n layers: {\n plans: string;\n sessions: string;\n memories: string;\n team: string;\n };\n}\n\nexport function buildInjectedContext(\n index: MycoIndex,\n config: MycoConfig,\n context: InjectionContext,\n): InjectedContext {\n const budgets = config.context.layers;\n\n // Layer 1: Active plans\n const plans = index.query({ type: 'plan' });\n const activePlans = plans.filter((p) =>\n ['active', 'in_progress'].includes(planFm(p).status ?? ''),\n );\n const plansText = formatLayer(\n 'Active Plans',\n activePlans.map((p) => `- **${p.title}** (${planFm(p).status}): ${p.content.slice(0, CONTEXT_PLAN_PREVIEW_CHARS)}`),\n budgets.plans,\n );\n\n // Layer 2: Recent sessions\n const sessions = index.query({ type: 'session', limit: 10 });\n const activePlanIds = activePlans.map((p) => p.id);\n const scoredSessions = scoreRelevance(sessions, {\n branch: context.branch,\n activePlanIds,\n });\n const sessionsText = formatLayer(\n 'Recent Sessions',\n scoredSessions.slice(0, 5).map((s) =>\n `- **${s.note.title}**: ${s.note.content.slice(0, CONTEXT_SESSION_PREVIEW_CHARS)} (${s.reason})`,\n ),\n budgets.sessions,\n );\n\n // Layer 3: Relevant memories (exclude superseded/archived)\n const memories = index.query({ type: 'memory', limit: 20 })\n .filter((m) => {\n const status = memoryFm(m).status;\n return status !== 'superseded' && status !== 'archived';\n });\n const scoredMemories = scoreRelevance(memories, {\n branch: context.branch,\n activePlanIds,\n });\n const memoriesText = formatLayer(\n 'Relevant Memories',\n scoredMemories.slice(0, 5).map((m) =>\n `- **${m.note.title}** (${memoryFm(m.note).observation_type}): ${m.note.content.slice(0, CONTEXT_MEMORY_PREVIEW_CHARS)}`,\n ),\n budgets.memories,\n );\n\n // Layer 4: Team activity\n const teamText = formatLayer('Team Activity', [], budgets.team);\n\n // Enforce total max_tokens budget\n const allLayers = [plansText, sessionsText, memoriesText, teamText].filter(Boolean);\n const parts: string[] = [];\n let totalTokens = 0;\n\n for (const layer of allLayers) {\n const layerTokens = estimateTokens(layer);\n if (totalTokens + layerTokens > config.context.max_tokens) break;\n parts.push(layer);\n totalTokens += layerTokens;\n }\n\n const fullText = parts.join('\\n\\n');\n\n return {\n text: fullText,\n tokenEstimate: totalTokens,\n layers: {\n plans: plansText,\n sessions: sessionsText,\n memories: memoriesText,\n team: teamText,\n },\n };\n}\n\nfunction formatLayer(heading: string, items: string[], budget: number): string {\n if (items.length === 0) return '';\n\n let text = `### ${heading}\\n`;\n let currentTokens = estimateTokens(text);\n\n for (const item of items) {\n const itemTokens = estimateTokens(item);\n if (currentTokens + itemTokens > budget) break;\n text += item + '\\n';\n currentTokens += itemTokens;\n }\n\n return text.trim();\n}\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n","import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { loadConfig } from '../config/loader.js';\nimport { MycoIndex } from '../index/sqlite.js';\nimport { buildInjectedContext } from '../context/injector.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const config = loadConfig(VAULT_DIR);\n const client = new DaemonClient(VAULT_DIR);\n const healthy = await client.ensureRunning();\n\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? `s-${Date.now()}`;\n\n let branch: string | undefined;\n try {\n branch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf-8' }).trim();\n } catch { /* not a git repo */ }\n\n if (healthy) {\n await client.post('/sessions/register', {\n session_id: sessionId,\n branch,\n started_at: new Date().toISOString(),\n });\n\n const contextResult = await client.post('/context', { session_id: sessionId, branch });\n\n if (contextResult.ok && contextResult.data?.text) {\n process.stdout.write(contextResult.data.text);\n return;\n }\n }\n\n // Degraded: local FTS context only\n const index = new MycoIndex(path.join(VAULT_DIR, 'index.db'));\n const injected = buildInjectedContext(index, config, { branch });\n if (injected.text) process.stdout.write(injected.text);\n index.close();\n } catch (error) {\n process.stderr.write(`[myco] session-start error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/context/relevance.ts","../src/context/injector.ts","../src/hooks/session-start.ts"],"sourcesContent":["import type { IndexedNote } from '../index/sqlite.js';\n\nexport interface ScoredNote {\n note: IndexedNote;\n score: number;\n reason: string;\n}\n\ninterface RelevanceInput {\n branch?: string;\n activePlanIds?: string[];\n}\n\n// --- Recency thresholds (hours) and score weights ---\nconst RECENCY_TIERS = [\n { maxHours: 24, score: 3, label: 'recent (<24h)' },\n { maxHours: 72, score: 2, label: 'recent (<72h)' },\n { maxHours: 168, score: 1, label: 'recent (<1w)' },\n] as const;\n\nconst BRANCH_MATCH_SCORE = 3;\nconst PLAN_MATCH_SCORE = 2;\n\nconst MS_PER_HOUR = 3_600_000;\n\nexport function scoreRelevance(\n notes: IndexedNote[],\n input: RelevanceInput,\n): ScoredNote[] {\n return notes\n .map((note) => {\n let score = 0;\n const reasons: string[] = [];\n\n const fm = note.frontmatter as Record<string, unknown>;\n\n // Recency boost\n const age = Date.now() - new Date(note.created).getTime();\n const hoursOld = age / MS_PER_HOUR;\n for (const tier of RECENCY_TIERS) {\n if (hoursOld < tier.maxHours) {\n score += tier.score;\n reasons.push(tier.label);\n break;\n }\n }\n\n // Branch match\n if (input.branch && fm.branch === input.branch) {\n score += BRANCH_MATCH_SCORE;\n reasons.push('same branch');\n }\n\n // Plan match\n if (input.activePlanIds?.length) {\n const planRef = fm.plan as string | undefined;\n if (planRef && input.activePlanIds.some((id) =>\n planRef === `[[${id}]]` || planRef === id,\n )) {\n score += PLAN_MATCH_SCORE;\n reasons.push('active plan');\n }\n }\n\n return { note, score, reason: reasons.join(', ') };\n })\n .filter((s) => s.score > 0)\n .sort((a, b) => b.score - a.score);\n}\n","import type { MycoIndex } from '../index/sqlite.js';\nimport type { MycoConfig } from '../config/schema.js';\nimport { planFm, memoryFm } from '../vault/frontmatter.js';\nimport { scoreRelevance } from './relevance.js';\nimport { CHARS_PER_TOKEN, CONTEXT_PLAN_PREVIEW_CHARS, CONTEXT_SESSION_PREVIEW_CHARS, CONTEXT_MEMORY_PREVIEW_CHARS } from '../constants.js';\n\ninterface InjectionContext {\n branch?: string;\n}\n\ninterface InjectedContext {\n text: string;\n tokenEstimate: number;\n layers: {\n plans: string;\n sessions: string;\n memories: string;\n team: string;\n };\n}\n\nexport function buildInjectedContext(\n index: MycoIndex,\n config: MycoConfig,\n context: InjectionContext,\n): InjectedContext {\n const budgets = config.context.layers;\n\n // Layer 1: Active plans\n const plans = index.query({ type: 'plan' });\n const activePlans = plans.filter((p) =>\n ['active', 'in_progress'].includes(planFm(p).status ?? ''),\n );\n const plansText = formatLayer(\n 'Active Plans',\n activePlans.map((p) => `- **${p.title}** (${planFm(p).status}): ${p.content.slice(0, CONTEXT_PLAN_PREVIEW_CHARS)}`),\n budgets.plans,\n );\n\n // Layer 2: Recent sessions\n const sessions = index.query({ type: 'session', limit: 10 });\n const activePlanIds = activePlans.map((p) => p.id);\n const scoredSessions = scoreRelevance(sessions, {\n branch: context.branch,\n activePlanIds,\n });\n const sessionsText = formatLayer(\n 'Recent Sessions',\n scoredSessions.slice(0, 5).map((s) =>\n `- **${s.note.title}**: ${s.note.content.slice(0, CONTEXT_SESSION_PREVIEW_CHARS)} (${s.reason})`,\n ),\n budgets.sessions,\n );\n\n // Layer 3: Relevant memories (exclude superseded/archived)\n const memories = index.query({ type: 'memory', limit: 20 })\n .filter((m) => {\n const status = memoryFm(m).status;\n return status !== 'superseded' && status !== 'archived';\n });\n const scoredMemories = scoreRelevance(memories, {\n branch: context.branch,\n activePlanIds,\n });\n const memoriesText = formatLayer(\n 'Relevant Memories',\n scoredMemories.slice(0, 5).map((m) =>\n `- **${m.note.title}** (${memoryFm(m.note).observation_type}): ${m.note.content.slice(0, CONTEXT_MEMORY_PREVIEW_CHARS)}`,\n ),\n budgets.memories,\n );\n\n // Layer 4: Team activity\n const teamText = formatLayer('Team Activity', [], budgets.team);\n\n // Enforce total max_tokens budget\n const allLayers = [plansText, sessionsText, memoriesText, teamText].filter(Boolean);\n const parts: string[] = [];\n let totalTokens = 0;\n\n for (const layer of allLayers) {\n const layerTokens = estimateTokens(layer);\n if (totalTokens + layerTokens > config.context.max_tokens) break;\n parts.push(layer);\n totalTokens += layerTokens;\n }\n\n const fullText = parts.join('\\n\\n');\n\n return {\n text: fullText,\n tokenEstimate: totalTokens,\n layers: {\n plans: plansText,\n sessions: sessionsText,\n memories: memoriesText,\n team: teamText,\n },\n };\n}\n\nfunction formatLayer(heading: string, items: string[], budget: number): string {\n if (items.length === 0) return '';\n\n let text = `### ${heading}\\n`;\n let currentTokens = estimateTokens(text);\n\n for (const item of items) {\n const itemTokens = estimateTokens(item);\n if (currentTokens + itemTokens > budget) break;\n text += item + '\\n';\n currentTokens += itemTokens;\n }\n\n return text.trim();\n}\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN);\n}\n","import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { loadConfig } from '../config/loader.js';\nimport { MycoIndex } from '../index/sqlite.js';\nimport { buildInjectedContext } from '../context/injector.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport { execFileSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const config = loadConfig(VAULT_DIR);\n const client = new DaemonClient(VAULT_DIR);\n const healthy = await client.ensureRunning();\n\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? `s-${Date.now()}`;\n\n let branch: string | undefined;\n try {\n branch = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { encoding: 'utf-8' }).trim();\n } catch { /* not a git repo */ }\n\n if (healthy) {\n await client.post('/sessions/register', {\n session_id: sessionId,\n branch,\n started_at: new Date().toISOString(),\n });\n\n const contextResult = await client.post('/context', { session_id: sessionId, branch });\n\n if (contextResult.ok && contextResult.data?.text) {\n process.stdout.write(contextResult.data.text);\n return;\n }\n }\n\n // Degraded: local FTS context only\n const index = new MycoIndex(path.join(VAULT_DIR, 'index.db'));\n const injected = buildInjectedContext(index, config, { branch });\n if (injected.text) process.stdout.write(injected.text);\n index.close();\n } catch (error) {\n process.stderr.write(`[myco] session-start error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|
package/dist/src/cli.js
CHANGED
package/dist/src/daemon/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/post-tool-use.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { EventBuffer } from '../capture/buffer.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport { TOOL_OUTPUT_PREVIEW_CHARS } from '../constants.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID ?? `s-${Date.now()}`;\n\n const client = new DaemonClient(VAULT_DIR);\n\n // PostToolUse fires frequently — don't spawn the daemon here.\n // If it's down, buffer to disk. The stop or prompt hook will respawn it.\n const result = await client.post('/events', {\n type: 'tool_use',\n tool_name: input.tool_name,\n tool_input: input.tool_input,\n output_preview: typeof input.tool_output === 'string' ? input.tool_output.slice(0, TOOL_OUTPUT_PREVIEW_CHARS) : undefined,\n session_id: sessionId,\n });\n\n if (!result.ok) {\n const buffer = new EventBuffer(path.join(VAULT_DIR, 'buffer'), sessionId);\n buffer.append({\n type: 'tool_use',\n tool: input.tool_name,\n input: input.tool_input,\n output_preview: typeof input.tool_output === 'string' ? input.tool_output.slice(0, TOOL_OUTPUT_PREVIEW_CHARS) : undefined,\n });\n }\n } catch (error) {\n process.stderr.write(`[myco] post-tool-use error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/post-tool-use.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { EventBuffer } from '../capture/buffer.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport { TOOL_OUTPUT_PREVIEW_CHARS } from '../constants.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID ?? `s-${Date.now()}`;\n\n const client = new DaemonClient(VAULT_DIR);\n\n // PostToolUse fires frequently — don't spawn the daemon here.\n // If it's down, buffer to disk. The stop or prompt hook will respawn it.\n const result = await client.post('/events', {\n type: 'tool_use',\n tool_name: input.tool_name,\n tool_input: input.tool_input,\n output_preview: typeof input.tool_output === 'string' ? input.tool_output.slice(0, TOOL_OUTPUT_PREVIEW_CHARS) : undefined,\n session_id: sessionId,\n });\n\n if (!result.ok) {\n const buffer = new EventBuffer(path.join(VAULT_DIR, 'buffer'), sessionId);\n buffer.append({\n type: 'tool_use',\n tool: input.tool_name,\n input: input.tool_input,\n output_preview: typeof input.tool_output === 'string' ? input.tool_output.slice(0, TOOL_OUTPUT_PREVIEW_CHARS) : undefined,\n });\n }\n } catch (error) {\n process.stderr.write(`[myco] post-tool-use error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAKA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAe,OAAO;AACpB,QAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,WAAW,WAAW,CAAC,EAAG;AAEvD,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,CAAC;AAC1C,UAAM,YAAY,MAAM,cAAc,QAAQ,IAAI,mBAAmB,KAAK,KAAK,IAAI,CAAC;AAEpF,UAAM,SAAS,IAAI,aAAa,SAAS;AAIzC,UAAM,SAAS,MAAM,OAAO,KAAK,WAAW;AAAA,MAC1C,MAAM;AAAA,MACN,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,gBAAgB,OAAO,MAAM,gBAAgB,WAAW,MAAM,YAAY,MAAM,GAAG,yBAAyB,IAAI;AAAA,MAChH,YAAY;AAAA,IACd,CAAC;AAED,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,SAAS,IAAI,YAAY,KAAK,KAAK,WAAW,QAAQ,GAAG,SAAS;AACxE,aAAO,OAAO;AAAA,QACZ,MAAM;AAAA,QACN,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,QACb,gBAAgB,OAAO,MAAM,gBAAgB,WAAW,MAAM,YAAY,MAAM,GAAG,yBAAyB,IAAI;AAAA,MAClH,CAAC;AAAA,IACH;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,+BAAgC,MAAgB,OAAO;AAAA,CAAI;AAAA,EAClF;AACF;AAEA,KAAK;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/session-end.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID;\n\n const client = new DaemonClient(VAULT_DIR);\n if (sessionId) {\n await client.post('/sessions/unregister', { session_id: sessionId });\n }\n } catch (error) {\n process.stderr.write(`[myco] session-end error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/session-end.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID;\n\n const client = new DaemonClient(VAULT_DIR);\n if (sessionId) {\n await client.post('/sessions/unregister', { session_id: sessionId });\n }\n } catch (error) {\n process.stderr.write(`[myco] session-end error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":";;;;;;;;;;;;;;;;AAGA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAe,OAAO;AACpB,QAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,WAAW,WAAW,CAAC,EAAG;AAEvD,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,CAAC;AAC1C,UAAM,YAAY,MAAM,cAAc,QAAQ,IAAI;AAElD,UAAM,SAAS,IAAI,aAAa,SAAS;AACzC,QAAI,WAAW;AACb,YAAM,OAAO,KAAK,wBAAwB,EAAE,YAAY,UAAU,CAAC;AAAA,IACrE;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,6BAA8B,MAAgB,OAAO;AAAA,CAAI;AAAA,EAChF;AACF;AAEA,KAAK;","names":[]}
|
package/dist/src/hooks/stop.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/stop.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { loadConfig } from '../config/loader.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID;\n if (!sessionId) return;\n\n const config = loadConfig(VAULT_DIR);\n const client = new DaemonClient(VAULT_DIR);\n\n await client.ensureRunning();\n\n // Pass transcript_path and last_assistant_message from Claude Code.\n // These are provided by the hook system and eliminate the need to\n // scan directories or mine the transcript for the AI response.\n await client.post('/events/stop', {\n session_id: sessionId,\n user: config.team.user || undefined,\n transcript_path: input.transcript_path,\n last_assistant_message: input.last_assistant_message,\n });\n } catch (error) {\n process.stderr.write(`[myco] stop error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/stop.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { loadConfig } from '../config/loader.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const sessionId = input.session_id ?? process.env.MYCO_SESSION_ID;\n if (!sessionId) return;\n\n const config = loadConfig(VAULT_DIR);\n const client = new DaemonClient(VAULT_DIR);\n\n await client.ensureRunning();\n\n // Pass transcript_path and last_assistant_message from Claude Code.\n // These are provided by the hook system and eliminate the need to\n // scan directories or mine the transcript for the AI response.\n await client.post('/events/stop', {\n session_id: sessionId,\n user: config.team.user || undefined,\n transcript_path: input.transcript_path,\n last_assistant_message: input.last_assistant_message,\n });\n } catch (error) {\n process.stderr.write(`[myco] stop error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAIA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAe,OAAO;AACpB,QAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,WAAW,WAAW,CAAC,EAAG;AAEvD,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,CAAC;AAC1C,UAAM,YAAY,MAAM,cAAc,QAAQ,IAAI;AAClD,QAAI,CAAC,UAAW;AAEhB,UAAM,SAAS,WAAW,SAAS;AACnC,UAAM,SAAS,IAAI,aAAa,SAAS;AAEzC,UAAM,OAAO,cAAc;AAK3B,UAAM,OAAO,KAAK,gBAAgB;AAAA,MAChC,YAAY;AAAA,MACZ,MAAM,OAAO,KAAK,QAAQ;AAAA,MAC1B,iBAAiB,MAAM;AAAA,MACvB,wBAAwB,MAAM;AAAA,IAChC,CAAC;AAAA,EACH,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,sBAAuB,MAAgB,OAAO;AAAA,CAAI;AAAA,EACzE;AACF;AAEA,KAAK;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/hooks/user-prompt-submit.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { EventBuffer } from '../capture/buffer.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const prompt = input.prompt ?? '';\n const sessionId = input.session_id ?? `s-${Date.now()}`;\n\n const client = new DaemonClient(VAULT_DIR);\n // Spawn daemon if needed but don't block on full health check backoff.\n // The event POST will fail fast if daemon isn't ready — buffer absorbs it.\n if (!(await client.isHealthy())) {\n client.spawnDaemon();\n }\n\n // Forward prompt as event for capture\n const eventResult = await client.post('/events', {\n type: 'user_prompt', prompt, session_id: sessionId,\n });\n\n if (!eventResult.ok) {\n // Daemon still unreachable — write directly to buffer for later processing\n const buffer = new EventBuffer(path.join(VAULT_DIR, 'buffer'), sessionId);\n buffer.append({ type: 'user_prompt', prompt });\n }\n\n // Search for relevant memories to inject as context for this prompt.\n // The daemon does a vector search against the prompt text and returns\n // any high-relevance memories. This is fast (~20ms) — no LLM call.\n const contextResult = await client.post('/context/prompt', {\n prompt,\n session_id: sessionId,\n });\n\n if (contextResult.ok && contextResult.data?.text) {\n process.stdout.write(contextResult.data.text);\n }\n } catch (error) {\n process.stderr.write(`[myco] user-prompt-submit error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/hooks/user-prompt-submit.ts"],"sourcesContent":["import { DaemonClient } from './client.js';\nimport { readStdin } from './read-stdin.js';\nimport { EventBuffer } from '../capture/buffer.js';\nimport { resolveVaultDir } from '../vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nasync function main() {\n const VAULT_DIR = resolveVaultDir();\n if (!fs.existsSync(path.join(VAULT_DIR, 'myco.yaml'))) return;\n\n try {\n const input = JSON.parse(await readStdin());\n const prompt = input.prompt ?? '';\n const sessionId = input.session_id ?? `s-${Date.now()}`;\n\n const client = new DaemonClient(VAULT_DIR);\n // Spawn daemon if needed but don't block on full health check backoff.\n // The event POST will fail fast if daemon isn't ready — buffer absorbs it.\n if (!(await client.isHealthy())) {\n client.spawnDaemon();\n }\n\n // Forward prompt as event for capture\n const eventResult = await client.post('/events', {\n type: 'user_prompt', prompt, session_id: sessionId,\n });\n\n if (!eventResult.ok) {\n // Daemon still unreachable — write directly to buffer for later processing\n const buffer = new EventBuffer(path.join(VAULT_DIR, 'buffer'), sessionId);\n buffer.append({ type: 'user_prompt', prompt });\n }\n\n // Search for relevant memories to inject as context for this prompt.\n // The daemon does a vector search against the prompt text and returns\n // any high-relevance memories. This is fast (~20ms) — no LLM call.\n const contextResult = await client.post('/context/prompt', {\n prompt,\n session_id: sessionId,\n });\n\n if (contextResult.ok && contextResult.data?.text) {\n process.stdout.write(contextResult.data.text);\n }\n } catch (error) {\n process.stderr.write(`[myco] user-prompt-submit error: ${(error as Error).message}\\n`);\n }\n}\n\nmain();\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAIA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAe,OAAO;AACpB,QAAM,YAAY,gBAAgB;AAClC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,WAAW,WAAW,CAAC,EAAG;AAEvD,MAAI;AACF,UAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,CAAC;AAC1C,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,YAAY,MAAM,cAAc,KAAK,KAAK,IAAI,CAAC;AAErD,UAAM,SAAS,IAAI,aAAa,SAAS;AAGzC,QAAI,CAAE,MAAM,OAAO,UAAU,GAAI;AAC/B,aAAO,YAAY;AAAA,IACrB;AAGA,UAAM,cAAc,MAAM,OAAO,KAAK,WAAW;AAAA,MAC/C,MAAM;AAAA,MAAe;AAAA,MAAQ,YAAY;AAAA,IAC3C,CAAC;AAED,QAAI,CAAC,YAAY,IAAI;AAEnB,YAAM,SAAS,IAAI,YAAY,KAAK,KAAK,WAAW,QAAQ,GAAG,SAAS;AACxE,aAAO,OAAO,EAAE,MAAM,eAAe,OAAO,CAAC;AAAA,IAC/C;AAKA,UAAM,gBAAgB,MAAM,OAAO,KAAK,mBAAmB;AAAA,MACzD;AAAA,MACA,YAAY;AAAA,IACd,CAAC;AAED,QAAI,cAAc,MAAM,cAAc,MAAM,MAAM;AAChD,cAAQ,OAAO,MAAM,cAAc,KAAK,IAAI;AAAA,IAC9C;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,OAAO,MAAM,oCAAqC,MAAgB,OAAO;AAAA,CAAI;AAAA,EACvF;AACF;AAEA,KAAK;","names":[]}
|
package/dist/src/mcp/server.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
getPluginVersion
|
|
4
|
+
} from "./chunk-2UEJVXXE.js";
|
|
5
|
+
import "./chunk-2QEJKG7R.js";
|
|
6
|
+
import "./chunk-Q7BEFSOV.js";
|
|
7
|
+
import "./chunk-PZUWP5VK.js";
|
|
8
|
+
export {
|
|
9
|
+
getPluginVersion
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=version-N55WTRG5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
package/skills/myco/SKILL.md
CHANGED
|
@@ -204,3 +204,37 @@ The vault should get sharper over time, not just bigger. Every session should le
|
|
|
204
204
|
1. `myco_search` for prior decisions on the same component
|
|
205
205
|
2. If you find relevant context, factor it into your recommendation
|
|
206
206
|
3. After the decision is made, `myco_remember` the rationale
|
|
207
|
+
|
|
208
|
+
## Maintenance
|
|
209
|
+
|
|
210
|
+
The CLI is at `dist/src/cli.js` inside the plugin root. The plugin root env var depends on the agent: `CLAUDE_PLUGIN_ROOT` (Claude Code), `CURSOR_PLUGIN_ROOT` (Cursor), etc. Use whichever is set in your environment. Examples below use `MYCO_CLI` as shorthand:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# Resolve the CLI path (use the appropriate env var for your agent)
|
|
214
|
+
MYCO_CLI="node ${CLAUDE_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT}}/dist/src/cli.js"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Reprocessing sessions
|
|
218
|
+
|
|
219
|
+
If observations were lost due to a bug, or if you want to re-extract observations with a different LLM:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
$MYCO_CLI reprocess
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
This re-reads all session transcripts, re-extracts observations, and re-indexes everything. Existing memories are preserved — new observations are additive.
|
|
226
|
+
|
|
227
|
+
Options:
|
|
228
|
+
- `--session <id>` — reprocess a single session (partial ID match)
|
|
229
|
+
- `--index-only` — skip LLM extraction, just re-index and re-embed existing notes
|
|
230
|
+
|
|
231
|
+
### Other maintenance commands
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
$MYCO_CLI version # Check plugin version
|
|
235
|
+
$MYCO_CLI rebuild # Re-index all vault notes (FTS + vectors)
|
|
236
|
+
$MYCO_CLI stats # Check vault health
|
|
237
|
+
$MYCO_CLI verify # Test provider connectivity
|
|
238
|
+
$MYCO_CLI config get intelligence.llm.model # View config
|
|
239
|
+
$MYCO_CLI config set intelligence.llm.model gpt-oss # Change config
|
|
240
|
+
```
|
|
@@ -1 +0,0 @@
|
|
|
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';\n\ninterface DaemonInfo {\n pid: number;\n port: number;\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 // Health checks use a shorter timeout than regular requests —\n // if the daemon doesn't respond in 500ms it's effectively down.\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 Record<string, unknown>;\n return data.myco === true;\n } catch {\n return false;\n }\n }\n\n /**\n * Ensure the daemon is running. Spawns it if unhealthy and waits for it\n * to become ready. Returns true if the daemon is healthy after this call.\n */\n async ensureRunning(): Promise<boolean> {\n if (await this.isHealthy()) return true;\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 // Resolve daemon script via agent registry (checks all known agent env vars)\n // or fall back to relative path from this module.\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":[]}
|
package/dist/cli-ZHUR53CS.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { loadEnv } from './cli/shared.js';\nimport { resolveVaultDir } from './vault/resolve.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nloadEnv();\n\nconst USAGE = `Usage: myco <command> [args]\n\nCommands:\n init [options] Initialize a new vault\n config <get|set> [args] Get or set vault config values\n detect-providers Detect available LLM/embedding providers (JSON)\n verify Test LLM and embedding connectivity\n stats Vault health, index counts, vector count\n search <query> Combined FTS + vector search with scores\n vectors <query> Raw vector search with similarity scores\n session [id|latest] Show a session note\n logs [options] View daemon logs\n restart Restart the daemon\n rebuild Reindex the entire vault\n`;\n\nasync function main(): Promise<void> {\n const [cmd, ...args] = process.argv.slice(2);\n if (!cmd || cmd === '--help' || cmd === '-h') {\n process.stdout.write(USAGE);\n return;\n }\n\n if (cmd === 'init') return (await import('./cli/init.js')).run(args);\n if (cmd === 'detect-providers') return (await import('./cli/detect-providers.js')).run(args);\n\n const vaultDir = resolveVaultDir();\n if (!fs.existsSync(path.join(vaultDir, 'myco.yaml'))) {\n console.error(`No myco.yaml found in ${vaultDir}. Run 'myco init' first.`);\n process.exit(1);\n }\n\n switch (cmd) {\n case 'config': return (await import('./cli/config.js')).run(args, vaultDir);\n case 'verify': return (await import('./cli/verify.js')).run(args, vaultDir);\n case 'stats': return (await import('./cli/stats.js')).run(args, vaultDir);\n case 'search': return (await import('./cli/search.js')).run(args, vaultDir);\n case 'vectors': return (await import('./cli/search.js')).runVectors(args, vaultDir);\n case 'session': return (await import('./cli/session.js')).run(args, vaultDir);\n case 'restart': return (await import('./cli/restart.js')).run(args, vaultDir);\n case 'rebuild': return (await import('./cli/rebuild.js')).run(args, vaultDir);\n case 'logs': return (await import('./cli/logs.js')).run(args, vaultDir);\n default:\n console.error(`Unknown command: ${cmd}`);\n process.stdout.write(USAGE);\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error(`myco: ${(err as Error).message}`);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;AAGA,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,QAAQ;AAER,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBd,eAAe,OAAsB;AACnC,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC;AAC3C,MAAI,CAAC,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC5C,YAAQ,OAAO,MAAM,KAAK;AAC1B;AAAA,EACF;AAEA,MAAI,QAAQ,OAAQ,SAAQ,MAAM,OAAO,oBAAe,GAAG,IAAI,IAAI;AACnE,MAAI,QAAQ,mBAAoB,SAAQ,MAAM,OAAO,gCAA2B,GAAG,IAAI,IAAI;AAE3F,QAAM,WAAW,gBAAgB;AACjC,MAAI,CAAC,GAAG,WAAW,KAAK,KAAK,UAAU,WAAW,CAAC,GAAG;AACpD,YAAQ,MAAM,yBAAyB,QAAQ,0BAA0B;AACzE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,KAAK;AAAA,IACX,KAAK;AAAU,cAAQ,MAAM,OAAO,sBAAiB,GAAG,IAAI,MAAM,QAAQ;AAAA,IAC1E,KAAK;AAAU,cAAQ,MAAM,OAAO,sBAAiB,GAAG,IAAI,MAAM,QAAQ;AAAA,IAC1E,KAAK;AAAS,cAAQ,MAAM,OAAO,qBAAgB,GAAG,IAAI,MAAM,QAAQ;AAAA,IACxE,KAAK;AAAU,cAAQ,MAAM,OAAO,sBAAiB,GAAG,IAAI,MAAM,QAAQ;AAAA,IAC1E,KAAK;AAAW,cAAQ,MAAM,OAAO,sBAAiB,GAAG,WAAW,MAAM,QAAQ;AAAA,IAClF,KAAK;AAAW,cAAQ,MAAM,OAAO,uBAAkB,GAAG,IAAI,MAAM,QAAQ;AAAA,IAC5E,KAAK;AAAW,cAAQ,MAAM,OAAO,uBAAkB,GAAG,IAAI,MAAM,QAAQ;AAAA,IAC5E,KAAK;AAAW,cAAQ,MAAM,OAAO,uBAAkB,GAAG,IAAI,MAAM,QAAQ;AAAA,IAC5E,KAAK;AAAQ,cAAQ,MAAM,OAAO,oBAAe,GAAG,IAAI,MAAM,QAAQ;AAAA,IACtE;AACE,cAAQ,MAAM,oBAAoB,GAAG,EAAE;AACvC,cAAQ,OAAO,MAAM,KAAK;AAC1B,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,SAAU,IAAc,OAAO,EAAE;AAC/C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|