@goondocks/myco 0.2.13 → 0.3.0
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/commands/init.md +33 -22
- package/dist/{chunk-BXFS4PCJ.js → chunk-2QEJKG7R.js} +2 -2
- package/dist/{chunk-MAFUTKOZ.js → chunk-2TKJPRZL.js} +2 -2
- package/dist/chunk-5EZ7QF6J.js +96 -0
- package/dist/chunk-5EZ7QF6J.js.map +1 -0
- package/dist/chunk-6FQISQNA.js +61 -0
- package/dist/chunk-6FQISQNA.js.map +1 -0
- package/dist/{chunk-S4WBXXO6.js → chunk-BMJX2IDQ.js} +2 -2
- package/dist/chunk-EF4JVH24.js +7299 -0
- package/dist/chunk-EF4JVH24.js.map +1 -0
- package/dist/{chunk-YXZEP5U6.js → chunk-ISCT2SI6.js} +11 -7301
- package/dist/chunk-ISCT2SI6.js.map +1 -0
- package/dist/{chunk-6C26YFOA.js → chunk-N6IAW33G.js} +248 -4306
- package/dist/chunk-N6IAW33G.js.map +1 -0
- package/dist/{chunk-C2YPBQQM.js → chunk-NTYYYC32.js} +3 -3
- package/dist/{chunk-NKJIZSPD.js → chunk-P2Q77C5F.js} +3 -3
- package/dist/chunk-PAUPHPOC.js +111 -0
- package/dist/chunk-PAUPHPOC.js.map +1 -0
- package/dist/chunk-PZUWP5VK.js +44 -0
- package/dist/{chunk-O5VSPHDL.js → chunk-Q7BEFSOV.js} +3 -40
- package/dist/{chunk-O5VSPHDL.js.map → chunk-Q7BEFSOV.js.map} +1 -1
- package/dist/chunk-QQWUV3TC.js +3691 -0
- package/dist/chunk-QQWUV3TC.js.map +1 -0
- package/dist/chunk-RGVBGTD6.js +21 -0
- package/dist/chunk-RGVBGTD6.js.map +1 -0
- package/dist/chunk-SAKJMNSR.js +50 -0
- package/dist/chunk-SAKJMNSR.js.map +1 -0
- package/dist/chunk-TJJRIVZ7.js +56 -0
- package/dist/chunk-TJJRIVZ7.js.map +1 -0
- package/dist/chunk-XQXXF6MU.js +96 -0
- package/dist/chunk-XQXXF6MU.js.map +1 -0
- package/dist/chunk-XW3OL55U.js +160 -0
- package/dist/chunk-XW3OL55U.js.map +1 -0
- package/dist/cli-ZHUR53CS.js +76 -0
- package/dist/cli-ZHUR53CS.js.map +1 -0
- package/dist/client-HORA3CC4.js +11 -0
- package/dist/client-HORA3CC4.js.map +1 -0
- package/dist/config-MD4XMLUS.js +101 -0
- package/dist/config-MD4XMLUS.js.map +1 -0
- package/dist/detect-providers-6RQCQZOI.js +35 -0
- package/dist/detect-providers-6RQCQZOI.js.map +1 -0
- package/dist/init-LLLHUNSY.js +120 -0
- package/dist/init-LLLHUNSY.js.map +1 -0
- package/dist/logs-BSTBZHDR.js +84 -0
- package/dist/logs-BSTBZHDR.js.map +1 -0
- package/dist/{main-ORWCEWNJ.js → main-JY6O6ZVH.js} +60 -15
- package/dist/{main-ORWCEWNJ.js.map → main-JY6O6ZVH.js.map} +1 -1
- package/dist/rebuild-YAN3TPFB.js +78 -0
- package/dist/rebuild-YAN3TPFB.js.map +1 -0
- package/dist/restart-NH5MX45I.js +50 -0
- package/dist/restart-NH5MX45I.js.map +1 -0
- package/dist/search-W3ECVSTH.js +120 -0
- package/dist/search-W3ECVSTH.js.map +1 -0
- package/dist/{server-J3AQ3YFA.js → server-DLBATUNG.js} +29 -16
- package/dist/{server-J3AQ3YFA.js.map → server-DLBATUNG.js.map} +1 -1
- package/dist/session-5GI2YU6R.js +44 -0
- package/dist/session-5GI2YU6R.js.map +1 -0
- package/dist/{session-start-BEC4JMNZ.js → session-start-DECLNJDI.js} +8 -6
- package/dist/{session-start-BEC4JMNZ.js.map → session-start-DECLNJDI.js.map} +1 -1
- package/dist/src/cli.js +8 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/daemon/main.js +8 -1
- package/dist/src/daemon/main.js.map +1 -1
- package/dist/src/hooks/post-tool-use.js +5 -4
- package/dist/src/hooks/post-tool-use.js.map +1 -1
- package/dist/src/hooks/session-end.js +5 -4
- package/dist/src/hooks/session-end.js.map +1 -1
- package/dist/src/hooks/session-start.js +8 -1
- package/dist/src/hooks/session-start.js.map +1 -1
- package/dist/src/hooks/stop.js +7 -5
- package/dist/src/hooks/stop.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.js +5 -4
- package/dist/src/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/mcp/server.js +8 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/stats-7VEZN2WF.js +77 -0
- package/dist/stats-7VEZN2WF.js.map +1 -0
- package/dist/verify-HN5DWV2H.js +50 -0
- package/dist/verify-HN5DWV2H.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6C26YFOA.js.map +0 -1
- package/dist/chunk-YXZEP5U6.js.map +0 -1
- package/dist/cli-KMWJFK5Y.js +0 -623
- package/dist/cli-KMWJFK5Y.js.map +0 -1
- package/dist/client-TEUHXGOY.js +0 -10
- /package/dist/{chunk-BXFS4PCJ.js.map → chunk-2QEJKG7R.js.map} +0 -0
- /package/dist/{chunk-MAFUTKOZ.js.map → chunk-2TKJPRZL.js.map} +0 -0
- /package/dist/{chunk-S4WBXXO6.js.map → chunk-BMJX2IDQ.js.map} +0 -0
- /package/dist/{chunk-C2YPBQQM.js.map → chunk-NTYYYC32.js.map} +0 -0
- /package/dist/{chunk-NKJIZSPD.js.map → chunk-P2Q77C5F.js.map} +0 -0
- /package/dist/{client-TEUHXGOY.js.map → chunk-PZUWP5VK.js.map} +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/logs/format.ts
|
|
4
|
+
var LOG_VALUE_MAX_DISPLAY = 80;
|
|
5
|
+
var CORE_FIELDS = ["timestamp", "level", "component", "message"];
|
|
6
|
+
function formatLogLine(entry) {
|
|
7
|
+
const time = formatLocalTime(entry.timestamp);
|
|
8
|
+
const lvl = entry.level.toUpperCase().padEnd(5);
|
|
9
|
+
const comp = `[${entry.component}]`.padEnd(14);
|
|
10
|
+
const extras = [];
|
|
11
|
+
for (const [key, value] of Object.entries(entry)) {
|
|
12
|
+
if (CORE_FIELDS.includes(key)) continue;
|
|
13
|
+
const str = String(value);
|
|
14
|
+
const display = str.length > LOG_VALUE_MAX_DISPLAY ? str.slice(0, LOG_VALUE_MAX_DISPLAY) + "..." : str;
|
|
15
|
+
extras.push(`${key}=${display}`);
|
|
16
|
+
}
|
|
17
|
+
const extraStr = extras.length > 0 ? " " + extras.join(" ") : "";
|
|
18
|
+
return `${time} ${lvl} ${comp} ${entry.message}${extraStr}`;
|
|
19
|
+
}
|
|
20
|
+
function formatLocalTime(iso) {
|
|
21
|
+
const d = new Date(iso);
|
|
22
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
23
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
24
|
+
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
25
|
+
return `${hh}:${mm}:${ss}`;
|
|
26
|
+
}
|
|
27
|
+
function parseIntFlag(args, long, short) {
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
if (args[i] === long || short && args[i] === short) {
|
|
30
|
+
const val = parseInt(args[i + 1], 10);
|
|
31
|
+
return isNaN(val) ? void 0 : val;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
function parseStringFlag(args, long, short) {
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
if (args[i] === long || short && args[i] === short) {
|
|
39
|
+
return args[i + 1];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
formatLogLine,
|
|
47
|
+
parseIntFlag,
|
|
48
|
+
parseStringFlag
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=chunk-SAKJMNSR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logs/format.ts"],"sourcesContent":["import type { LogEntry } from '../daemon/logger.js';\n\n/** Max display length for extra field values in pretty-printed output. */\nconst LOG_VALUE_MAX_DISPLAY = 80;\n\n/** Core fields that are handled positionally, not as extras. */\nconst CORE_FIELDS: ReadonlyArray<keyof LogEntry> = ['timestamp', 'level', 'component', 'message'];\n\nexport function formatLogLine(entry: LogEntry): string {\n const time = formatLocalTime(entry.timestamp);\n const lvl = entry.level.toUpperCase().padEnd(5);\n const comp = `[${entry.component}]`.padEnd(14);\n\n const extras: string[] = [];\n for (const [key, value] of Object.entries(entry)) {\n if (CORE_FIELDS.includes(key)) continue;\n const str = String(value);\n const display = str.length > LOG_VALUE_MAX_DISPLAY\n ? str.slice(0, LOG_VALUE_MAX_DISPLAY) + '...'\n : str;\n extras.push(`${key}=${display}`);\n }\n\n const extraStr = extras.length > 0 ? ' ' + extras.join(' ') : '';\n return `${time} ${lvl} ${comp} ${entry.message}${extraStr}`;\n}\n\nexport function formatLocalTime(iso: string): string {\n const d = new Date(iso);\n const hh = String(d.getHours()).padStart(2, '0');\n const mm = String(d.getMinutes()).padStart(2, '0');\n const ss = String(d.getSeconds()).padStart(2, '0');\n return `${hh}:${mm}:${ss}`;\n}\n\nexport function parseIntFlag(args: string[], long: string, short?: string): number | undefined {\n for (let i = 0; i < args.length; i++) {\n if (args[i] === long || (short && args[i] === short)) {\n const val = parseInt(args[i + 1], 10);\n return isNaN(val) ? undefined : val;\n }\n }\n return undefined;\n}\n\nexport function parseStringFlag(args: string[], long: string, short?: string): string | undefined {\n for (let i = 0; i < args.length; i++) {\n if (args[i] === long || (short && args[i] === short)) {\n return args[i + 1];\n }\n }\n return undefined;\n}\n"],"mappings":";;;AAGA,IAAM,wBAAwB;AAG9B,IAAM,cAA6C,CAAC,aAAa,SAAS,aAAa,SAAS;AAEzF,SAAS,cAAc,OAAyB;AACrD,QAAM,OAAO,gBAAgB,MAAM,SAAS;AAC5C,QAAM,MAAM,MAAM,MAAM,YAAY,EAAE,OAAO,CAAC;AAC9C,QAAM,OAAO,IAAI,MAAM,SAAS,IAAI,OAAO,EAAE;AAE7C,QAAM,SAAmB,CAAC;AAC1B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,YAAY,SAAS,GAAG,EAAG;AAC/B,UAAM,MAAM,OAAO,KAAK;AACxB,UAAM,UAAU,IAAI,SAAS,wBACzB,IAAI,MAAM,GAAG,qBAAqB,IAAI,QACtC;AACJ,WAAO,KAAK,GAAG,GAAG,IAAI,OAAO,EAAE;AAAA,EACjC;AAEA,QAAM,WAAW,OAAO,SAAS,IAAI,OAAO,OAAO,KAAK,GAAG,IAAI;AAC/D,SAAO,GAAG,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM,OAAO,GAAG,QAAQ;AAC3D;AAEO,SAAS,gBAAgB,KAAqB;AACnD,QAAM,IAAI,IAAI,KAAK,GAAG;AACtB,QAAM,KAAK,OAAO,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,QAAM,KAAK,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AACjD,QAAM,KAAK,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AACjD,SAAO,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE;AAC1B;AAEO,SAAS,aAAa,MAAgB,MAAc,OAAoC;AAC7F,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,MAAM,QAAS,SAAS,KAAK,CAAC,MAAM,OAAQ;AACpD,YAAM,MAAM,SAAS,KAAK,IAAI,CAAC,GAAG,EAAE;AACpC,aAAO,MAAM,GAAG,IAAI,SAAY;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,MAAgB,MAAc,OAAoC;AAChG,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,MAAM,QAAS,SAAS,KAAK,CAAC,MAAM,OAAQ;AACpD,aAAO,KAAK,IAAI,CAAC;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,56 @@
|
|
|
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/native-deps.ts
|
|
7
|
+
import { execFileSync } from "child_process";
|
|
8
|
+
import { createRequire } from "module";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
var NATIVE_PACKAGES = ["better-sqlite3", "sqlite-vec"];
|
|
12
|
+
function findPluginRoot() {
|
|
13
|
+
const fromRegistry = new AgentRegistry().resolvePluginRoot();
|
|
14
|
+
if (fromRegistry) return fromRegistry;
|
|
15
|
+
let dir = path.dirname(new URL(import.meta.url).pathname);
|
|
16
|
+
for (let i = 0; i < 5; i++) {
|
|
17
|
+
if (fs.existsSync(path.join(dir, "package.json"))) return dir;
|
|
18
|
+
dir = path.dirname(dir);
|
|
19
|
+
}
|
|
20
|
+
return process.cwd();
|
|
21
|
+
}
|
|
22
|
+
function ensureNativeDeps() {
|
|
23
|
+
const pluginRoot = findPluginRoot();
|
|
24
|
+
const require2 = createRequire(path.join(pluginRoot, "node_modules", ".package.json"));
|
|
25
|
+
const missing = [];
|
|
26
|
+
for (const pkg of NATIVE_PACKAGES) {
|
|
27
|
+
try {
|
|
28
|
+
require2.resolve(pkg);
|
|
29
|
+
} catch {
|
|
30
|
+
missing.push(pkg);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (missing.length === 0) return;
|
|
34
|
+
const nodeModulesDir = path.join(pluginRoot, "node_modules");
|
|
35
|
+
if (!fs.existsSync(nodeModulesDir)) {
|
|
36
|
+
fs.mkdirSync(nodeModulesDir, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
execFileSync("npm", ["install", "--no-save", "--no-package-lock", ...missing], {
|
|
40
|
+
cwd: pluginRoot,
|
|
41
|
+
stdio: "pipe",
|
|
42
|
+
timeout: 12e4
|
|
43
|
+
});
|
|
44
|
+
} catch (error) {
|
|
45
|
+
const msg = error.message;
|
|
46
|
+
process.stderr.write(`[myco] Failed to install native dependencies: ${msg}
|
|
47
|
+
`);
|
|
48
|
+
process.stderr.write(`[myco] You can install them manually: cd ${pluginRoot} && npm install ${missing.join(" ")}
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export {
|
|
54
|
+
ensureNativeDeps
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=chunk-TJJRIVZ7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/native-deps.ts"],"sourcesContent":["/**\n * Ensures native npm dependencies (better-sqlite3, sqlite-vec) are available.\n *\n * When the plugin is installed from a marketplace, only the bundled\n * JS files are present in the cache directory — node_modules is stripped.\n * Native modules cannot be bundled by tsup/esbuild, so we install them on\n * first use into the plugin's cache directory.\n */\nimport { execFileSync } from 'node:child_process';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { AgentRegistry } from './agents/registry.js';\n\nconst NATIVE_PACKAGES = ['better-sqlite3', 'sqlite-vec'] as const;\n\n/**\n * Detect the plugin root via the active agent's env var (CLAUDE_PLUGIN_ROOT,\n * CURSOR_PLUGIN_ROOT, etc.), falling back to walking up from this file.\n */\nfunction findPluginRoot(): string {\n const fromRegistry = new AgentRegistry().resolvePluginRoot();\n if (fromRegistry) return fromRegistry;\n\n // Fallback: walk up from dist/src/ to find package.json\n let dir = path.dirname(new URL(import.meta.url).pathname);\n for (let i = 0; i < 5; i++) {\n if (fs.existsSync(path.join(dir, 'package.json'))) return dir;\n dir = path.dirname(dir);\n }\n return process.cwd();\n}\n\nexport function ensureNativeDeps(): void {\n const pluginRoot = findPluginRoot();\n const require = createRequire(path.join(pluginRoot, 'node_modules', '.package.json'));\n\n const missing: string[] = [];\n for (const pkg of NATIVE_PACKAGES) {\n try {\n require.resolve(pkg);\n } catch {\n missing.push(pkg);\n }\n }\n\n if (missing.length === 0) return;\n\n const nodeModulesDir = path.join(pluginRoot, 'node_modules');\n if (!fs.existsSync(nodeModulesDir)) {\n fs.mkdirSync(nodeModulesDir, { recursive: true });\n }\n\n try {\n execFileSync('npm', ['install', '--no-save', '--no-package-lock', ...missing], {\n cwd: pluginRoot,\n stdio: 'pipe',\n timeout: 120_000,\n });\n } catch (error) {\n const msg = (error as Error).message;\n process.stderr.write(`[myco] Failed to install native dependencies: ${msg}\\n`);\n process.stderr.write(`[myco] You can install them manually: cd ${pluginRoot} && npm install ${missing.join(' ')}\\n`);\n }\n}\n"],"mappings":";;;;;;AAQA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AACjB,OAAO,QAAQ;AAGf,IAAM,kBAAkB,CAAC,kBAAkB,YAAY;AAMvD,SAAS,iBAAyB;AAChC,QAAM,eAAe,IAAI,cAAc,EAAE,kBAAkB;AAC3D,MAAI,aAAc,QAAO;AAGzB,MAAI,MAAM,KAAK,QAAQ,IAAI,IAAI,YAAY,GAAG,EAAE,QAAQ;AACxD,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,GAAG,WAAW,KAAK,KAAK,KAAK,cAAc,CAAC,EAAG,QAAO;AAC1D,UAAM,KAAK,QAAQ,GAAG;AAAA,EACxB;AACA,SAAO,QAAQ,IAAI;AACrB;AAEO,SAAS,mBAAyB;AACvC,QAAM,aAAa,eAAe;AAClC,QAAMA,WAAU,cAAc,KAAK,KAAK,YAAY,gBAAgB,eAAe,CAAC;AAEpF,QAAM,UAAoB,CAAC;AAC3B,aAAW,OAAO,iBAAiB;AACjC,QAAI;AACF,MAAAA,SAAQ,QAAQ,GAAG;AAAA,IACrB,QAAQ;AACN,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,iBAAiB,KAAK,KAAK,YAAY,cAAc;AAC3D,MAAI,CAAC,GAAG,WAAW,cAAc,GAAG;AAClC,OAAG,UAAU,gBAAgB,EAAE,WAAW,KAAK,CAAC;AAAA,EAClD;AAEA,MAAI;AACF,iBAAa,OAAO,CAAC,WAAW,aAAa,qBAAqB,GAAG,OAAO,GAAG;AAAA,MAC7E,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,MAAO,MAAgB;AAC7B,YAAQ,OAAO,MAAM,iDAAiD,GAAG;AAAA,CAAI;AAC7E,YAAQ,OAAO,MAAM,4CAA4C,UAAU,mBAAmB,QAAQ,KAAK,GAAG,CAAC;AAAA,CAAI;AAAA,EACrH;AACF;","names":["require"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/index/vectors.ts
|
|
4
|
+
import Database from "better-sqlite3";
|
|
5
|
+
import * as sqliteVec from "sqlite-vec";
|
|
6
|
+
var VectorIndex = class {
|
|
7
|
+
db;
|
|
8
|
+
dimensions;
|
|
9
|
+
constructor(dbPath, dimensions) {
|
|
10
|
+
this.dimensions = dimensions;
|
|
11
|
+
this.db = new Database(dbPath);
|
|
12
|
+
sqliteVec.load(this.db);
|
|
13
|
+
this.init();
|
|
14
|
+
}
|
|
15
|
+
init() {
|
|
16
|
+
this.db.exec(`
|
|
17
|
+
CREATE TABLE IF NOT EXISTS vec_metadata (
|
|
18
|
+
id TEXT PRIMARY KEY,
|
|
19
|
+
type TEXT NOT NULL DEFAULT '',
|
|
20
|
+
importance TEXT NOT NULL DEFAULT '',
|
|
21
|
+
session_id TEXT NOT NULL DEFAULT '',
|
|
22
|
+
file_path TEXT NOT NULL DEFAULT '',
|
|
23
|
+
branch TEXT NOT NULL DEFAULT '',
|
|
24
|
+
created TEXT NOT NULL DEFAULT (datetime('now'))
|
|
25
|
+
);
|
|
26
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS vec_embeddings USING vec0(
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
embedding float[${this.dimensions}]
|
|
29
|
+
);
|
|
30
|
+
`);
|
|
31
|
+
}
|
|
32
|
+
upsert(id, embedding, metadata = {}) {
|
|
33
|
+
this.db.prepare("DELETE FROM vec_metadata WHERE id = ?").run(id);
|
|
34
|
+
this.db.prepare("DELETE FROM vec_embeddings WHERE id = ?").run(id);
|
|
35
|
+
this.db.prepare(
|
|
36
|
+
"INSERT INTO vec_metadata (id, type, importance, session_id, file_path, branch) VALUES (?, ?, ?, ?, ?, ?)"
|
|
37
|
+
).run(id, metadata.type ?? "", metadata.importance ?? "", metadata.session_id ?? "", metadata.file_path ?? "", metadata.branch ?? "");
|
|
38
|
+
this.db.prepare("INSERT INTO vec_embeddings (id, embedding) VALUES (?, ?)").run(id, new Float32Array(embedding));
|
|
39
|
+
}
|
|
40
|
+
search(query, options = {}) {
|
|
41
|
+
const limit = options.limit ?? 10;
|
|
42
|
+
const knnParams = [new Float32Array(query), limit * 4];
|
|
43
|
+
const knnRows = this.db.prepare(`
|
|
44
|
+
SELECT id, distance
|
|
45
|
+
FROM vec_embeddings
|
|
46
|
+
WHERE embedding MATCH ?
|
|
47
|
+
ORDER BY distance
|
|
48
|
+
LIMIT ?
|
|
49
|
+
`).all(...knnParams);
|
|
50
|
+
if (knnRows.length === 0) return [];
|
|
51
|
+
const metaConditions = ["id IN (" + knnRows.map(() => "?").join(",") + ")"];
|
|
52
|
+
const metaParams = knnRows.map((r) => r.id);
|
|
53
|
+
if (options.type) {
|
|
54
|
+
metaConditions.push("type = ?");
|
|
55
|
+
metaParams.push(options.type);
|
|
56
|
+
}
|
|
57
|
+
if (options.importance) {
|
|
58
|
+
metaConditions.push("importance = ?");
|
|
59
|
+
metaParams.push(options.importance);
|
|
60
|
+
}
|
|
61
|
+
const metaRows = this.db.prepare(`
|
|
62
|
+
SELECT id, type, importance, session_id, file_path, branch
|
|
63
|
+
FROM vec_metadata
|
|
64
|
+
WHERE ${metaConditions.join(" AND ")}
|
|
65
|
+
`).all(...metaParams);
|
|
66
|
+
const metaMap = new Map(metaRows.map((m) => [m.id, m]));
|
|
67
|
+
const scored = knnRows.filter((r) => metaMap.has(r.id)).map((r) => {
|
|
68
|
+
const m = metaMap.get(r.id);
|
|
69
|
+
return {
|
|
70
|
+
id: r.id,
|
|
71
|
+
similarity: 1 - r.distance,
|
|
72
|
+
metadata: { type: m.type, importance: m.importance, session_id: m.session_id, file_path: m.file_path, branch: m.branch }
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
if (scored.length === 0) return [];
|
|
76
|
+
const topScore = scored[0].similarity;
|
|
77
|
+
const threshold = options.relativeThreshold ?? 0.5;
|
|
78
|
+
const floor = topScore * threshold;
|
|
79
|
+
return scored.filter((r) => r.similarity >= floor).slice(0, limit);
|
|
80
|
+
}
|
|
81
|
+
delete(id) {
|
|
82
|
+
this.db.prepare("DELETE FROM vec_metadata WHERE id = ?").run(id);
|
|
83
|
+
this.db.prepare("DELETE FROM vec_embeddings WHERE id = ?").run(id);
|
|
84
|
+
}
|
|
85
|
+
count() {
|
|
86
|
+
return this.db.prepare("SELECT COUNT(*) as c FROM vec_metadata").get().c;
|
|
87
|
+
}
|
|
88
|
+
close() {
|
|
89
|
+
this.db.close();
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export {
|
|
94
|
+
VectorIndex
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=chunk-XQXXF6MU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index/vectors.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport * as sqliteVec from 'sqlite-vec';\n\nexport interface VectorSearchResult {\n id: string;\n similarity: number;\n metadata: Record<string, string>;\n}\n\nexport interface VectorSearchOptions {\n limit?: number;\n /** Drop results below this fraction of the top result's score (0-1). Default 0.5. */\n relativeThreshold?: number;\n type?: string;\n importance?: string;\n}\n\nexport class VectorIndex {\n private db: Database.Database;\n private dimensions: number;\n\n constructor(dbPath: string, dimensions: number) {\n this.dimensions = dimensions;\n this.db = new Database(dbPath);\n sqliteVec.load(this.db);\n this.init();\n }\n\n private init(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS vec_metadata (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL DEFAULT '',\n importance TEXT NOT NULL DEFAULT '',\n session_id TEXT NOT NULL DEFAULT '',\n file_path TEXT NOT NULL DEFAULT '',\n branch TEXT NOT NULL DEFAULT '',\n created TEXT NOT NULL DEFAULT (datetime('now'))\n );\n CREATE VIRTUAL TABLE IF NOT EXISTS vec_embeddings USING vec0(\n id TEXT PRIMARY KEY,\n embedding float[${this.dimensions}]\n );\n `);\n }\n\n upsert(id: string, embedding: number[], metadata: Record<string, string> = {}): void {\n this.db.prepare('DELETE FROM vec_metadata WHERE id = ?').run(id);\n this.db.prepare('DELETE FROM vec_embeddings WHERE id = ?').run(id);\n\n this.db.prepare(\n 'INSERT INTO vec_metadata (id, type, importance, session_id, file_path, branch) VALUES (?, ?, ?, ?, ?, ?)',\n ).run(id, metadata.type ?? '', metadata.importance ?? '', metadata.session_id ?? '', metadata.file_path ?? '', metadata.branch ?? '');\n\n this.db.prepare('INSERT INTO vec_embeddings (id, embedding) VALUES (?, ?)').run(id, new Float32Array(embedding));\n }\n\n search(query: number[], options: VectorSearchOptions = {}): VectorSearchResult[] {\n const limit = options.limit ?? 10;\n\n // vec0 KNN queries require LIMIT to be a direct constraint on the virtual table.\n // JOINs with additional WHERE filters confuse the query planner, so we use a\n // subquery to get KNN candidates first, then filter by metadata in the outer query.\n const knnParams: unknown[] = [new Float32Array(query), limit * 4];\n const knnRows = this.db.prepare(`\n SELECT id, distance\n FROM vec_embeddings\n WHERE embedding MATCH ?\n ORDER BY distance\n LIMIT ?\n `).all(...knnParams) as Array<{ id: string; distance: number }>;\n\n if (knnRows.length === 0) return [];\n\n // Now fetch metadata for the candidates and apply optional filters\n const metaConditions: string[] = ['id IN (' + knnRows.map(() => '?').join(',') + ')'];\n const metaParams: unknown[] = knnRows.map((r) => r.id);\n\n if (options.type) { metaConditions.push('type = ?'); metaParams.push(options.type); }\n if (options.importance) { metaConditions.push('importance = ?'); metaParams.push(options.importance); }\n\n const metaRows = this.db.prepare(`\n SELECT id, type, importance, session_id, file_path, branch\n FROM vec_metadata\n WHERE ${metaConditions.join(' AND ')}\n `).all(...metaParams) as Array<{ id: string; type: string; importance: string; session_id: string; file_path: string; branch: string }>;\n\n const metaMap = new Map(metaRows.map((m) => [m.id, m]));\n\n const scored = knnRows\n .filter((r) => metaMap.has(r.id))\n .map((r) => {\n const m = metaMap.get(r.id)!;\n return {\n id: r.id,\n similarity: 1 - r.distance,\n metadata: { type: m.type, importance: m.importance, session_id: m.session_id, file_path: m.file_path, branch: m.branch },\n };\n });\n\n if (scored.length === 0) return [];\n\n // Relative threshold: drop results below a fraction of the best score.\n // Adapts automatically to any embedding model's score distribution.\n const topScore = scored[0].similarity;\n const threshold = options.relativeThreshold ?? 0.5;\n const floor = topScore * threshold;\n\n return scored\n .filter((r) => r.similarity >= floor)\n .slice(0, limit);\n }\n\n delete(id: string): void {\n this.db.prepare('DELETE FROM vec_metadata WHERE id = ?').run(id);\n this.db.prepare('DELETE FROM vec_embeddings WHERE id = ?').run(id);\n }\n\n count(): number {\n return (this.db.prepare('SELECT COUNT(*) as c FROM vec_metadata').get() as { c: number }).c;\n }\n\n close(): void { this.db.close(); }\n}\n"],"mappings":";;;AAAA,OAAO,cAAc;AACrB,YAAY,eAAe;AAgBpB,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA;AAAA,EAER,YAAY,QAAgB,YAAoB;AAC9C,SAAK,aAAa;AAClB,SAAK,KAAK,IAAI,SAAS,MAAM;AAC7B,IAAU,eAAK,KAAK,EAAE;AACtB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,OAAa;AACnB,SAAK,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAYS,KAAK,UAAU;AAAA;AAAA,KAEpC;AAAA,EACH;AAAA,EAEA,OAAO,IAAY,WAAqB,WAAmC,CAAC,GAAS;AACnF,SAAK,GAAG,QAAQ,uCAAuC,EAAE,IAAI,EAAE;AAC/D,SAAK,GAAG,QAAQ,yCAAyC,EAAE,IAAI,EAAE;AAEjE,SAAK,GAAG;AAAA,MACN;AAAA,IACF,EAAE,IAAI,IAAI,SAAS,QAAQ,IAAI,SAAS,cAAc,IAAI,SAAS,cAAc,IAAI,SAAS,aAAa,IAAI,SAAS,UAAU,EAAE;AAEpI,SAAK,GAAG,QAAQ,0DAA0D,EAAE,IAAI,IAAI,IAAI,aAAa,SAAS,CAAC;AAAA,EACjH;AAAA,EAEA,OAAO,OAAiB,UAA+B,CAAC,GAAyB;AAC/E,UAAM,QAAQ,QAAQ,SAAS;AAK/B,UAAM,YAAuB,CAAC,IAAI,aAAa,KAAK,GAAG,QAAQ,CAAC;AAChE,UAAM,UAAU,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAM/B,EAAE,IAAI,GAAG,SAAS;AAEnB,QAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAGlC,UAAM,iBAA2B,CAAC,YAAY,QAAQ,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG;AACpF,UAAM,aAAwB,QAAQ,IAAI,CAAC,MAAM,EAAE,EAAE;AAErD,QAAI,QAAQ,MAAM;AAAE,qBAAe,KAAK,UAAU;AAAG,iBAAW,KAAK,QAAQ,IAAI;AAAA,IAAG;AACpF,QAAI,QAAQ,YAAY;AAAE,qBAAe,KAAK,gBAAgB;AAAG,iBAAW,KAAK,QAAQ,UAAU;AAAA,IAAG;AAEtG,UAAM,WAAW,KAAK,GAAG,QAAQ;AAAA;AAAA;AAAA,cAGvB,eAAe,KAAK,OAAO,CAAC;AAAA,KACrC,EAAE,IAAI,GAAG,UAAU;AAEpB,UAAM,UAAU,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAEtD,UAAM,SAAS,QACZ,OAAO,CAAC,MAAM,QAAQ,IAAI,EAAE,EAAE,CAAC,EAC/B,IAAI,CAAC,MAAM;AACV,YAAM,IAAI,QAAQ,IAAI,EAAE,EAAE;AAC1B,aAAO;AAAA,QACL,IAAI,EAAE;AAAA,QACN,YAAY,IAAI,EAAE;AAAA,QAClB,UAAU,EAAE,MAAM,EAAE,MAAM,YAAY,EAAE,YAAY,YAAY,EAAE,YAAY,WAAW,EAAE,WAAW,QAAQ,EAAE,OAAO;AAAA,MACzH;AAAA,IACF,CAAC;AAEH,QAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AAIjC,UAAM,WAAW,OAAO,CAAC,EAAE;AAC3B,UAAM,YAAY,QAAQ,qBAAqB;AAC/C,UAAM,QAAQ,WAAW;AAEzB,WAAO,OACJ,OAAO,CAAC,MAAM,EAAE,cAAc,KAAK,EACnC,MAAM,GAAG,KAAK;AAAA,EACnB;AAAA,EAEA,OAAO,IAAkB;AACvB,SAAK,GAAG,QAAQ,uCAAuC,EAAE,IAAI,EAAE;AAC/D,SAAK,GAAG,QAAQ,yCAAyC,EAAE,IAAI,EAAE;AAAA,EACnE;AAAA,EAEA,QAAgB;AACd,WAAQ,KAAK,GAAG,QAAQ,wCAAwC,EAAE,IAAI,EAAoB;AAAA,EAC5F;AAAA,EAEA,QAAc;AAAE,SAAK,GAAG,MAAM;AAAA,EAAG;AACnC;","names":[]}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
CHARS_PER_TOKEN,
|
|
4
|
+
DAEMON_CLIENT_TIMEOUT_MS,
|
|
5
|
+
EMBEDDING_REQUEST_TIMEOUT_MS,
|
|
6
|
+
LLM_REQUEST_TIMEOUT_MS
|
|
7
|
+
} from "./chunk-Q7BEFSOV.js";
|
|
8
|
+
|
|
9
|
+
// src/intelligence/ollama.ts
|
|
10
|
+
var OllamaBackend = class _OllamaBackend {
|
|
11
|
+
static DEFAULT_BASE_URL = "http://localhost:11434";
|
|
12
|
+
name = "ollama";
|
|
13
|
+
baseUrl;
|
|
14
|
+
model;
|
|
15
|
+
contextWindow;
|
|
16
|
+
defaultMaxTokens;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.baseUrl = config?.base_url ?? _OllamaBackend.DEFAULT_BASE_URL;
|
|
19
|
+
this.model = config?.model ?? config?.summary_model ?? "llama3.2";
|
|
20
|
+
this.contextWindow = config?.context_window ?? 8192;
|
|
21
|
+
this.defaultMaxTokens = config?.max_tokens ?? 1024;
|
|
22
|
+
}
|
|
23
|
+
async summarize(prompt, opts) {
|
|
24
|
+
const maxTokens = opts?.maxTokens ?? this.defaultMaxTokens;
|
|
25
|
+
const promptTokens = Math.ceil(prompt.length / CHARS_PER_TOKEN);
|
|
26
|
+
const numCtx = Math.max(promptTokens + maxTokens, this.contextWindow);
|
|
27
|
+
const response = await fetch(`${this.baseUrl}/api/generate`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "Content-Type": "application/json" },
|
|
30
|
+
body: JSON.stringify({
|
|
31
|
+
model: this.model,
|
|
32
|
+
prompt,
|
|
33
|
+
stream: false,
|
|
34
|
+
options: { num_ctx: numCtx }
|
|
35
|
+
}),
|
|
36
|
+
signal: AbortSignal.timeout(LLM_REQUEST_TIMEOUT_MS)
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(`Ollama summarize failed: ${response.status} ${response.statusText}`);
|
|
40
|
+
}
|
|
41
|
+
const data = await response.json();
|
|
42
|
+
return { text: data.response, model: data.model };
|
|
43
|
+
}
|
|
44
|
+
async embed(text) {
|
|
45
|
+
const response = await fetch(`${this.baseUrl}/api/embed`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "Content-Type": "application/json" },
|
|
48
|
+
body: JSON.stringify({
|
|
49
|
+
model: this.model,
|
|
50
|
+
input: text
|
|
51
|
+
}),
|
|
52
|
+
signal: AbortSignal.timeout(EMBEDDING_REQUEST_TIMEOUT_MS)
|
|
53
|
+
});
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error(`Ollama embed failed: ${response.status} ${response.statusText}`);
|
|
56
|
+
}
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
const embedding = data.embeddings[0];
|
|
59
|
+
return { embedding, model: data.model, dimensions: embedding.length };
|
|
60
|
+
}
|
|
61
|
+
async isAvailable() {
|
|
62
|
+
try {
|
|
63
|
+
const response = await fetch(`${this.baseUrl}/api/tags`, {
|
|
64
|
+
signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS)
|
|
65
|
+
});
|
|
66
|
+
return response.ok;
|
|
67
|
+
} catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** List available models on this Ollama instance. */
|
|
72
|
+
async listModels(timeoutMs) {
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(`${this.baseUrl}/api/tags`, {
|
|
75
|
+
signal: AbortSignal.timeout(timeoutMs ?? DAEMON_CLIENT_TIMEOUT_MS)
|
|
76
|
+
});
|
|
77
|
+
const data = await response.json();
|
|
78
|
+
return data.models.map((m) => m.name);
|
|
79
|
+
} catch {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/intelligence/lm-studio.ts
|
|
86
|
+
var LmStudioBackend = class _LmStudioBackend {
|
|
87
|
+
static DEFAULT_BASE_URL = "http://localhost:1234";
|
|
88
|
+
name = "lm-studio";
|
|
89
|
+
baseUrl;
|
|
90
|
+
model;
|
|
91
|
+
defaultMaxTokens;
|
|
92
|
+
constructor(config) {
|
|
93
|
+
this.baseUrl = config?.base_url ?? _LmStudioBackend.DEFAULT_BASE_URL;
|
|
94
|
+
this.model = config?.model ?? config?.summary_model ?? "llama3.2";
|
|
95
|
+
this.defaultMaxTokens = config?.max_tokens ?? 1024;
|
|
96
|
+
}
|
|
97
|
+
async summarize(prompt, opts) {
|
|
98
|
+
const maxTokens = opts?.maxTokens ?? this.defaultMaxTokens;
|
|
99
|
+
const response = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
|
100
|
+
method: "POST",
|
|
101
|
+
headers: { "Content-Type": "application/json" },
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
model: this.model,
|
|
104
|
+
messages: [{ role: "user", content: prompt }],
|
|
105
|
+
max_tokens: maxTokens
|
|
106
|
+
}),
|
|
107
|
+
signal: AbortSignal.timeout(LLM_REQUEST_TIMEOUT_MS)
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
throw new Error(`LM Studio summarize failed: ${response.status}`);
|
|
111
|
+
}
|
|
112
|
+
const data = await response.json();
|
|
113
|
+
return { text: data.choices[0].message.content, model: data.model };
|
|
114
|
+
}
|
|
115
|
+
async embed(text) {
|
|
116
|
+
const response = await fetch(`${this.baseUrl}/v1/embeddings`, {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "Content-Type": "application/json" },
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
model: this.model,
|
|
121
|
+
input: text
|
|
122
|
+
}),
|
|
123
|
+
signal: AbortSignal.timeout(EMBEDDING_REQUEST_TIMEOUT_MS)
|
|
124
|
+
});
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`LM Studio embed failed: ${response.status}`);
|
|
127
|
+
}
|
|
128
|
+
const data = await response.json();
|
|
129
|
+
const embedding = data.data[0].embedding;
|
|
130
|
+
return { embedding, model: data.model, dimensions: embedding.length };
|
|
131
|
+
}
|
|
132
|
+
async isAvailable() {
|
|
133
|
+
try {
|
|
134
|
+
const response = await fetch(`${this.baseUrl}/v1/models`, {
|
|
135
|
+
signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS)
|
|
136
|
+
});
|
|
137
|
+
return response.ok;
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** List available models on this LM Studio instance. */
|
|
143
|
+
async listModels(timeoutMs) {
|
|
144
|
+
try {
|
|
145
|
+
const response = await fetch(`${this.baseUrl}/v1/models`, {
|
|
146
|
+
signal: AbortSignal.timeout(timeoutMs ?? DAEMON_CLIENT_TIMEOUT_MS)
|
|
147
|
+
});
|
|
148
|
+
const data = await response.json();
|
|
149
|
+
return data.data.map((m) => m.id);
|
|
150
|
+
} catch {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
OllamaBackend,
|
|
158
|
+
LmStudioBackend
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=chunk-XW3OL55U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/intelligence/ollama.ts","../src/intelligence/lm-studio.ts"],"sourcesContent":["import type { LlmProvider, EmbeddingProvider, LlmResponse, EmbeddingResponse, LlmRequestOptions } from './llm.js';\nimport { CHARS_PER_TOKEN, LLM_REQUEST_TIMEOUT_MS, EMBEDDING_REQUEST_TIMEOUT_MS, DAEMON_CLIENT_TIMEOUT_MS } from '../constants.js';\n\ninterface OllamaConfig {\n model?: string;\n base_url?: string;\n context_window?: number;\n max_tokens?: number;\n // Legacy fields (ignored, kept for backward compat during migration)\n embedding_model?: string;\n summary_model?: string;\n}\n\nexport class OllamaBackend implements LlmProvider, EmbeddingProvider {\n static readonly DEFAULT_BASE_URL = 'http://localhost:11434';\n readonly name = 'ollama';\n private baseUrl: string;\n private model: string;\n private contextWindow: number;\n private defaultMaxTokens: number;\n\n constructor(config?: OllamaConfig) {\n this.baseUrl = config?.base_url ?? OllamaBackend.DEFAULT_BASE_URL;\n this.model = config?.model ?? config?.summary_model ?? 'llama3.2';\n this.contextWindow = config?.context_window ?? 8192;\n this.defaultMaxTokens = config?.max_tokens ?? 1024;\n }\n\n async summarize(prompt: string, opts?: LlmRequestOptions): Promise<LlmResponse> {\n const maxTokens = opts?.maxTokens ?? this.defaultMaxTokens;\n const promptTokens = Math.ceil(prompt.length / CHARS_PER_TOKEN);\n const numCtx = Math.max(promptTokens + maxTokens, this.contextWindow);\n\n const response = await fetch(`${this.baseUrl}/api/generate`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n prompt,\n stream: false,\n options: { num_ctx: numCtx },\n }),\n signal: AbortSignal.timeout(LLM_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(`Ollama summarize failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json() as { response: string; model: string };\n return { text: data.response, model: data.model };\n }\n\n async embed(text: string): Promise<EmbeddingResponse> {\n const response = await fetch(`${this.baseUrl}/api/embed`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n input: text,\n }),\n signal: AbortSignal.timeout(EMBEDDING_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(`Ollama embed failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json() as { embeddings: number[][]; model: string };\n const embedding = data.embeddings[0];\n return { embedding, model: data.model, dimensions: embedding.length };\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /** List available models on this Ollama instance. */\n async listModels(timeoutMs?: number): Promise<string[]> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n signal: AbortSignal.timeout(timeoutMs ?? DAEMON_CLIENT_TIMEOUT_MS),\n });\n const data = await response.json() as { models: Array<{ name: string }> };\n return data.models.map((m) => m.name);\n } catch {\n return [];\n }\n }\n}\n","import type { LlmProvider, EmbeddingProvider, LlmResponse, EmbeddingResponse, LlmRequestOptions } from './llm.js';\nimport { LLM_REQUEST_TIMEOUT_MS, EMBEDDING_REQUEST_TIMEOUT_MS, DAEMON_CLIENT_TIMEOUT_MS } from '../constants.js';\n\ninterface LmStudioConfig {\n model?: string;\n base_url?: string;\n max_tokens?: number;\n // Legacy fields\n embedding_model?: string;\n summary_model?: string;\n}\n\nexport class LmStudioBackend implements LlmProvider, EmbeddingProvider {\n static readonly DEFAULT_BASE_URL = 'http://localhost:1234';\n readonly name = 'lm-studio';\n private baseUrl: string;\n private model: string;\n private defaultMaxTokens: number;\n\n constructor(config?: LmStudioConfig) {\n this.baseUrl = config?.base_url ?? LmStudioBackend.DEFAULT_BASE_URL;\n this.model = config?.model ?? config?.summary_model ?? 'llama3.2';\n this.defaultMaxTokens = config?.max_tokens ?? 1024;\n }\n\n async summarize(prompt: string, opts?: LlmRequestOptions): Promise<LlmResponse> {\n const maxTokens = opts?.maxTokens ?? this.defaultMaxTokens;\n\n const response = await fetch(`${this.baseUrl}/v1/chat/completions`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n messages: [{ role: 'user', content: prompt }],\n max_tokens: maxTokens,\n }),\n signal: AbortSignal.timeout(LLM_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(`LM Studio summarize failed: ${response.status}`);\n }\n\n const data = await response.json() as {\n choices: Array<{ message: { content: string } }>;\n model: string;\n };\n return { text: data.choices[0].message.content, model: data.model };\n }\n\n async embed(text: string): Promise<EmbeddingResponse> {\n const response = await fetch(`${this.baseUrl}/v1/embeddings`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n input: text,\n }),\n signal: AbortSignal.timeout(EMBEDDING_REQUEST_TIMEOUT_MS),\n });\n\n if (!response.ok) {\n throw new Error(`LM Studio embed failed: ${response.status}`);\n }\n\n const data = await response.json() as {\n data: Array<{ embedding: number[] }>;\n model: string;\n };\n const embedding = data.data[0].embedding;\n return { embedding, model: data.model, dimensions: embedding.length };\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/v1/models`, {\n signal: AbortSignal.timeout(DAEMON_CLIENT_TIMEOUT_MS),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /** List available models on this LM Studio instance. */\n async listModels(timeoutMs?: number): Promise<string[]> {\n try {\n const response = await fetch(`${this.baseUrl}/v1/models`, {\n signal: AbortSignal.timeout(timeoutMs ?? DAEMON_CLIENT_TIMEOUT_MS),\n });\n const data = await response.json() as { data: Array<{ id: string }> };\n return data.data.map((m) => m.id);\n } catch {\n return [];\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
loadEnv
|
|
5
|
+
} from "./chunk-PAUPHPOC.js";
|
|
6
|
+
import "./chunk-SAKJMNSR.js";
|
|
7
|
+
import "./chunk-XW3OL55U.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveVaultDir
|
|
10
|
+
} from "./chunk-N33KUCFP.js";
|
|
11
|
+
import "./chunk-2QEJKG7R.js";
|
|
12
|
+
import "./chunk-Q7BEFSOV.js";
|
|
13
|
+
import "./chunk-PZUWP5VK.js";
|
|
14
|
+
|
|
15
|
+
// src/cli.ts
|
|
16
|
+
import fs from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
loadEnv();
|
|
19
|
+
var USAGE = `Usage: myco <command> [args]
|
|
20
|
+
|
|
21
|
+
Commands:
|
|
22
|
+
init [options] Initialize a new vault
|
|
23
|
+
config <get|set> [args] Get or set vault config values
|
|
24
|
+
detect-providers Detect available LLM/embedding providers (JSON)
|
|
25
|
+
verify Test LLM and embedding connectivity
|
|
26
|
+
stats Vault health, index counts, vector count
|
|
27
|
+
search <query> Combined FTS + vector search with scores
|
|
28
|
+
vectors <query> Raw vector search with similarity scores
|
|
29
|
+
session [id|latest] Show a session note
|
|
30
|
+
logs [options] View daemon logs
|
|
31
|
+
restart Restart the daemon
|
|
32
|
+
rebuild Reindex the entire vault
|
|
33
|
+
`;
|
|
34
|
+
async function main() {
|
|
35
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
36
|
+
if (!cmd || cmd === "--help" || cmd === "-h") {
|
|
37
|
+
process.stdout.write(USAGE);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (cmd === "init") return (await import("./init-LLLHUNSY.js")).run(args);
|
|
41
|
+
if (cmd === "detect-providers") return (await import("./detect-providers-6RQCQZOI.js")).run(args);
|
|
42
|
+
const vaultDir = resolveVaultDir();
|
|
43
|
+
if (!fs.existsSync(path.join(vaultDir, "myco.yaml"))) {
|
|
44
|
+
console.error(`No myco.yaml found in ${vaultDir}. Run 'myco init' first.`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
switch (cmd) {
|
|
48
|
+
case "config":
|
|
49
|
+
return (await import("./config-MD4XMLUS.js")).run(args, vaultDir);
|
|
50
|
+
case "verify":
|
|
51
|
+
return (await import("./verify-HN5DWV2H.js")).run(args, vaultDir);
|
|
52
|
+
case "stats":
|
|
53
|
+
return (await import("./stats-7VEZN2WF.js")).run(args, vaultDir);
|
|
54
|
+
case "search":
|
|
55
|
+
return (await import("./search-W3ECVSTH.js")).run(args, vaultDir);
|
|
56
|
+
case "vectors":
|
|
57
|
+
return (await import("./search-W3ECVSTH.js")).runVectors(args, vaultDir);
|
|
58
|
+
case "session":
|
|
59
|
+
return (await import("./session-5GI2YU6R.js")).run(args, vaultDir);
|
|
60
|
+
case "restart":
|
|
61
|
+
return (await import("./restart-NH5MX45I.js")).run(args, vaultDir);
|
|
62
|
+
case "rebuild":
|
|
63
|
+
return (await import("./rebuild-YAN3TPFB.js")).run(args, vaultDir);
|
|
64
|
+
case "logs":
|
|
65
|
+
return (await import("./logs-BSTBZHDR.js")).run(args, vaultDir);
|
|
66
|
+
default:
|
|
67
|
+
console.error(`Unknown command: ${cmd}`);
|
|
68
|
+
process.stdout.write(USAGE);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
main().catch((err) => {
|
|
73
|
+
console.error(`myco: ${err.message}`);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=cli-ZHUR53CS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
DaemonClient
|
|
4
|
+
} from "./chunk-NTYYYC32.js";
|
|
5
|
+
import "./chunk-2QEJKG7R.js";
|
|
6
|
+
import "./chunk-Q7BEFSOV.js";
|
|
7
|
+
import "./chunk-PZUWP5VK.js";
|
|
8
|
+
export {
|
|
9
|
+
DaemonClient
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=client-HORA3CC4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
MycoConfigSchema,
|
|
4
|
+
loadConfig
|
|
5
|
+
} from "./chunk-ISCT2SI6.js";
|
|
6
|
+
import {
|
|
7
|
+
require_dist
|
|
8
|
+
} from "./chunk-EF4JVH24.js";
|
|
9
|
+
import {
|
|
10
|
+
__toESM
|
|
11
|
+
} from "./chunk-PZUWP5VK.js";
|
|
12
|
+
|
|
13
|
+
// src/cli/config.ts
|
|
14
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
import path from "path";
|
|
17
|
+
var CONFIG_FILENAME = "myco.yaml";
|
|
18
|
+
var DAEMON_STATE_FILENAME = "daemon.json";
|
|
19
|
+
async function run(args, vaultDir) {
|
|
20
|
+
const [subcommand, key, ...rest] = args;
|
|
21
|
+
if (subcommand === "get") {
|
|
22
|
+
if (!key) {
|
|
23
|
+
console.error("Usage: myco config get <dot.path.key>");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
return configGet(key, vaultDir);
|
|
27
|
+
}
|
|
28
|
+
if (subcommand === "set") {
|
|
29
|
+
const value = rest[0];
|
|
30
|
+
if (!key || value === void 0) {
|
|
31
|
+
console.error("Usage: myco config set <dot.path.key> <value>");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
return configSet(key, value, vaultDir);
|
|
35
|
+
}
|
|
36
|
+
console.error("Usage: myco config <get|set> <dot.path.key> [value]");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
function configGet(dotPath, vaultDir) {
|
|
40
|
+
const config = loadConfig(vaultDir);
|
|
41
|
+
const value = walkPath(config, dotPath);
|
|
42
|
+
if (value === void 0) {
|
|
43
|
+
console.error(`Key not found: ${dotPath}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
console.log(typeof value === "object" ? JSON.stringify(value, null, 2) : String(value));
|
|
47
|
+
}
|
|
48
|
+
function configSet(dotPath, rawValue, vaultDir) {
|
|
49
|
+
const configPath = path.join(vaultDir, CONFIG_FILENAME);
|
|
50
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
51
|
+
const doc = import_yaml.default.parse(raw);
|
|
52
|
+
const value = parseValue(rawValue);
|
|
53
|
+
setPath(doc, dotPath, value);
|
|
54
|
+
const result = MycoConfigSchema.safeParse(doc);
|
|
55
|
+
if (!result.success) {
|
|
56
|
+
console.error("Validation error:");
|
|
57
|
+
for (const issue of result.error.issues) {
|
|
58
|
+
console.error(` ${issue.path.join(".")}: ${issue.message}`);
|
|
59
|
+
}
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
fs.writeFileSync(configPath, import_yaml.default.stringify(doc), "utf-8");
|
|
63
|
+
console.log(`Set ${dotPath} = ${JSON.stringify(value)}`);
|
|
64
|
+
if (fs.existsSync(path.join(vaultDir, DAEMON_STATE_FILENAME))) {
|
|
65
|
+
console.log("Note: restart the daemon for changes to take effect (myco restart)");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function walkPath(obj, dotPath) {
|
|
69
|
+
const segments = dotPath.split(".");
|
|
70
|
+
let current = obj;
|
|
71
|
+
for (const segment of segments) {
|
|
72
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
current = current[segment];
|
|
76
|
+
}
|
|
77
|
+
return current;
|
|
78
|
+
}
|
|
79
|
+
function setPath(obj, dotPath, value) {
|
|
80
|
+
const segments = dotPath.split(".");
|
|
81
|
+
let current = obj;
|
|
82
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
83
|
+
const segment = segments[i];
|
|
84
|
+
if (current[segment] === void 0 || current[segment] === null || typeof current[segment] !== "object") {
|
|
85
|
+
current[segment] = {};
|
|
86
|
+
}
|
|
87
|
+
current = current[segment];
|
|
88
|
+
}
|
|
89
|
+
current[segments[segments.length - 1]] = value;
|
|
90
|
+
}
|
|
91
|
+
function parseValue(raw) {
|
|
92
|
+
try {
|
|
93
|
+
return JSON.parse(raw);
|
|
94
|
+
} catch {
|
|
95
|
+
return raw;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export {
|
|
99
|
+
run
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=config-MD4XMLUS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/config.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport YAML from 'yaml';\nimport { loadConfig } from '../config/loader.js';\nimport { MycoConfigSchema } from '../config/schema.js';\n\nconst CONFIG_FILENAME = 'myco.yaml';\nconst DAEMON_STATE_FILENAME = 'daemon.json';\n\nexport async function run(args: string[], vaultDir: string): Promise<void> {\n const [subcommand, key, ...rest] = args;\n\n if (subcommand === 'get') {\n if (!key) {\n console.error('Usage: myco config get <dot.path.key>');\n process.exit(1);\n }\n return configGet(key, vaultDir);\n }\n\n if (subcommand === 'set') {\n const value = rest[0];\n if (!key || value === undefined) {\n console.error('Usage: myco config set <dot.path.key> <value>');\n process.exit(1);\n }\n return configSet(key, value, vaultDir);\n }\n\n console.error('Usage: myco config <get|set> <dot.path.key> [value]');\n process.exit(1);\n}\n\nfunction configGet(dotPath: string, vaultDir: string): void {\n const config = loadConfig(vaultDir);\n const value = walkPath(config as Record<string, unknown>, dotPath);\n if (value === undefined) {\n console.error(`Key not found: ${dotPath}`);\n process.exit(1);\n }\n console.log(typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value));\n}\n\nfunction configSet(dotPath: string, rawValue: string, vaultDir: string): void {\n const configPath = path.join(vaultDir, CONFIG_FILENAME);\n const raw = fs.readFileSync(configPath, 'utf-8');\n const doc = YAML.parse(raw) as Record<string, unknown>;\n\n const value = parseValue(rawValue);\n setPath(doc, dotPath, value);\n\n const result = MycoConfigSchema.safeParse(doc);\n if (!result.success) {\n console.error('Validation error:');\n for (const issue of result.error.issues) {\n console.error(` ${issue.path.join('.')}: ${issue.message}`);\n }\n process.exit(1);\n }\n\n fs.writeFileSync(configPath, YAML.stringify(doc), 'utf-8');\n console.log(`Set ${dotPath} = ${JSON.stringify(value)}`);\n\n if (fs.existsSync(path.join(vaultDir, DAEMON_STATE_FILENAME))) {\n console.log('Note: restart the daemon for changes to take effect (myco restart)');\n }\n}\n\n/** Walk a dot-separated path to retrieve a nested value. */\nfunction walkPath(obj: Record<string, unknown>, dotPath: string): unknown {\n const segments = dotPath.split('.');\n let current: unknown = obj;\n for (const segment of segments) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[segment];\n }\n return current;\n}\n\n/** Set a value at a dot-separated path, creating intermediate objects as needed. */\nfunction setPath(obj: Record<string, unknown>, dotPath: string, value: unknown): void {\n const segments = dotPath.split('.');\n let current: Record<string, unknown> = obj;\n for (let i = 0; i < segments.length - 1; i++) {\n const segment = segments[i];\n if (current[segment] === undefined || current[segment] === null || typeof current[segment] !== 'object') {\n current[segment] = {};\n }\n current = current[segment] as Record<string, unknown>;\n }\n current[segments[segments.length - 1]] = value;\n}\n\n/** Parse a string value as JSON (number, boolean, array, object), falling back to raw string. */\nfunction parseValue(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n"],"mappings":"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","names":["YAML"]}
|