@goondocks/myco 0.2.14 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-3JCXYLHD.js +33 -0
- package/dist/chunk-3JCXYLHD.js.map +1 -0
- 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-72OAG4SF.js +3692 -0
- package/dist/chunk-72OAG4SF.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-JIQISBPI.js +362 -0
- package/dist/chunk-JIQISBPI.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-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-UUFDD2FB.js → chunk-TJJRIVZ7.js} +2 -2
- 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-ERAS5H43.js +79 -0
- package/dist/cli-ERAS5H43.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-UJAXPP6S.js → main-D4X6XWRT.js} +241 -542
- package/dist/main-D4X6XWRT.js.map +1 -0
- package/dist/rebuild-3367GP5R.js +85 -0
- package/dist/rebuild-3367GP5R.js.map +1 -0
- package/dist/reprocess-EM5RIRH4.js +199 -0
- package/dist/reprocess-EM5RIRH4.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-I7MRMIOP.js} +41 -21
- package/dist/{server-J3AQ3YFA.js.map → server-I7MRMIOP.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 +5 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/daemon/main.js +5 -4
- 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 +5 -4
- 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 +5 -4
- 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/skills/myco/SKILL.md +33 -0
- 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/main-UJAXPP6S.js.map +0 -1
- /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
- /package/dist/{chunk-UUFDD2FB.js.map → chunk-TJJRIVZ7.js.map} +0 -0
package/commands/init.md
CHANGED
|
@@ -5,11 +5,21 @@ description: Initialize Myco in the current project — sets up vault, config, a
|
|
|
5
5
|
|
|
6
6
|
# Initialize Myco
|
|
7
7
|
|
|
8
|
-
Guide the user through setup
|
|
8
|
+
Guide the user through setup using the composable CLI commands. **Do NOT create files manually — the CLI handles all vault creation, config writing, and env configuration.**
|
|
9
9
|
|
|
10
10
|
**Ask each question one at a time using AskUserQuestion with selectable options.** Wait for the user's answer before proceeding to the next question. Do NOT combine multiple questions into one message.
|
|
11
11
|
|
|
12
|
-
## Step 1:
|
|
12
|
+
## Step 1: Detect available providers
|
|
13
|
+
|
|
14
|
+
Run the provider detection command to see what's available:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js detect-providers
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Parse the JSON output. This tells you which providers are running and what models are available.
|
|
21
|
+
|
|
22
|
+
## Step 2: Choose vault location
|
|
13
23
|
|
|
14
24
|
Ask the user:
|
|
15
25
|
|
|
@@ -22,32 +32,26 @@ Ask the user:
|
|
|
22
32
|
|
|
23
33
|
If the user picks "Custom path", ask them to type the path.
|
|
24
34
|
|
|
25
|
-
## Step
|
|
26
|
-
|
|
27
|
-
First, detect available providers by checking local endpoints:
|
|
35
|
+
## Step 3: Choose LLM provider
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
- **LM Studio** — `curl -s http://localhost:1234/v1/models` — list model IDs
|
|
31
|
-
- **Anthropic** — check if `ANTHROPIC_API_KEY` is set
|
|
32
|
-
|
|
33
|
-
Then ask the user:
|
|
37
|
+
Using the detected providers from Step 1, ask the user:
|
|
34
38
|
|
|
35
39
|
**Question:** "Which LLM provider for summarization?"
|
|
36
40
|
|
|
37
|
-
**Options:** List only providers
|
|
41
|
+
**Options:** List only providers where `available` is `true`, with recommended models. Example:
|
|
38
42
|
- "Ollama — gpt-oss (recommended)"
|
|
39
43
|
- "LM Studio — openai/gpt-oss-20b"
|
|
40
44
|
- "Anthropic"
|
|
41
45
|
|
|
42
|
-
After the user picks a provider, ask them to choose a specific model from
|
|
46
|
+
After the user picks a provider, ask them to choose a specific model from that provider's model list (from the detect-providers output).
|
|
43
47
|
|
|
44
|
-
## Step
|
|
48
|
+
## Step 4: Choose embedding provider
|
|
45
49
|
|
|
46
50
|
Ask the user:
|
|
47
51
|
|
|
48
52
|
**Question:** "Which embedding provider?"
|
|
49
53
|
|
|
50
|
-
**Options:** List only providers
|
|
54
|
+
**Options:** List only providers where `available` is `true` and that support embeddings (Anthropic does not). Example:
|
|
51
55
|
- "Ollama — bge-m3 (recommended)"
|
|
52
56
|
- "LM Studio — text-embedding-bge-m3"
|
|
53
57
|
|
|
@@ -56,9 +60,9 @@ After the user picks a provider, ask them to choose a specific embedding model.
|
|
|
56
60
|
If the recommended embedding model isn't available, offer to pull it:
|
|
57
61
|
- **Ollama**: `ollama pull bge-m3`
|
|
58
62
|
|
|
59
|
-
## Step
|
|
63
|
+
## Step 5: Run init with all gathered inputs
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
Pass everything to the init command in a single call:
|
|
62
66
|
|
|
63
67
|
```bash
|
|
64
68
|
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js init \
|
|
@@ -71,17 +75,24 @@ node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js init \
|
|
|
71
75
|
--embedding-url <base-url>
|
|
72
76
|
```
|
|
73
77
|
|
|
74
|
-
|
|
78
|
+
The CLI creates the vault structure, writes myco.yaml, .gitignore, _dashboard.md, initializes the FTS index, and configures MYCO_VAULT_DIR if the vault is external.
|
|
79
|
+
|
|
80
|
+
## Step 6: Verify connectivity
|
|
81
|
+
|
|
82
|
+
Run the verify command to confirm providers are reachable:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node ${CLAUDE_PLUGIN_ROOT}/dist/src/cli.js verify
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If verification fails, help the user troubleshoot (check if the provider is running, model is loaded, etc.).
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
## Step 7: Display summary
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
2. Test embeddings — generate a test embedding and report dimensions
|
|
80
|
-
3. Display a setup summary table
|
|
92
|
+
Show the user a setup summary table:
|
|
81
93
|
|
|
82
94
|
| Setting | Value |
|
|
83
95
|
|---------|-------|
|
|
84
96
|
| Vault path | `<resolved path>` |
|
|
85
97
|
| LLM provider | `<provider>` / `<model>` |
|
|
86
98
|
| Embedding provider | `<provider>` / `<model>` |
|
|
87
|
-
| Context window | `<context_window>` |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
PROMPT_PREVIEW_CHARS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-Q7BEFSOV.js";
|
|
5
5
|
|
|
6
6
|
// src/agents/adapter.ts
|
|
7
7
|
import fs from "fs";
|
|
@@ -351,4 +351,4 @@ export {
|
|
|
351
351
|
claudeCodeAdapter,
|
|
352
352
|
AgentRegistry
|
|
353
353
|
};
|
|
354
|
-
//# sourceMappingURL=chunk-
|
|
354
|
+
//# sourceMappingURL=chunk-2QEJKG7R.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
STDIN_TIMEOUT_MS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-Q7BEFSOV.js";
|
|
5
5
|
|
|
6
6
|
// src/hooks/read-stdin.ts
|
|
7
7
|
function readStdin() {
|
|
@@ -18,4 +18,4 @@ function readStdin() {
|
|
|
18
18
|
export {
|
|
19
19
|
readStdin
|
|
20
20
|
};
|
|
21
|
-
//# sourceMappingURL=chunk-
|
|
21
|
+
//# sourceMappingURL=chunk-2TKJPRZL.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/intelligence/batch.ts
|
|
4
|
+
var LLM_BATCH_CONCURRENCY = 3;
|
|
5
|
+
var EMBEDDING_BATCH_CONCURRENCY = 4;
|
|
6
|
+
async function batchExecute(items, fn, options) {
|
|
7
|
+
const { concurrency, onProgress } = options;
|
|
8
|
+
let succeeded = 0;
|
|
9
|
+
let failed = 0;
|
|
10
|
+
const results = [];
|
|
11
|
+
for (let i = 0; i < items.length; i += concurrency) {
|
|
12
|
+
const batch = items.slice(i, i + concurrency);
|
|
13
|
+
const settled = await Promise.allSettled(batch.map(fn));
|
|
14
|
+
for (const result of settled) {
|
|
15
|
+
if (result.status === "fulfilled") {
|
|
16
|
+
succeeded++;
|
|
17
|
+
results.push({ status: "fulfilled", value: result.value });
|
|
18
|
+
} else {
|
|
19
|
+
failed++;
|
|
20
|
+
results.push({ status: "rejected", reason: result.reason?.message ?? String(result.reason) });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
onProgress?.(succeeded + failed, items.length);
|
|
24
|
+
}
|
|
25
|
+
return { succeeded, failed, results };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
LLM_BATCH_CONCURRENCY,
|
|
30
|
+
EMBEDDING_BATCH_CONCURRENCY,
|
|
31
|
+
batchExecute
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=chunk-3JCXYLHD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/intelligence/batch.ts"],"sourcesContent":["/**\n * Batch execution utilities for LLM and embedding operations.\n *\n * Provides concurrency-limited parallel execution for bulk operations\n * like reprocessing, rebuilding, and any future batch pipeline.\n */\n\n/** Default concurrency for LLM calls (heavier, single-threaded backends). */\nexport const LLM_BATCH_CONCURRENCY = 3;\n/** Default concurrency for embedding calls (lighter, can run more in parallel). */\nexport const EMBEDDING_BATCH_CONCURRENCY = 4;\n\nexport interface BatchResult<T> {\n succeeded: number;\n failed: number;\n results: Array<{ status: 'fulfilled'; value: T } | { status: 'rejected'; reason: string }>;\n}\n\n/**\n * Execute async tasks with a concurrency limit.\n * Reports progress via an optional callback.\n */\nexport async function batchExecute<I, O>(\n items: I[],\n fn: (item: I) => Promise<O>,\n options: {\n concurrency: number;\n onProgress?: (completed: number, total: number) => void;\n },\n): Promise<BatchResult<O>> {\n const { concurrency, onProgress } = options;\n let succeeded = 0;\n let failed = 0;\n const results: BatchResult<O>['results'] = [];\n\n for (let i = 0; i < items.length; i += concurrency) {\n const batch = items.slice(i, i + concurrency);\n const settled = await Promise.allSettled(batch.map(fn));\n\n for (const result of settled) {\n if (result.status === 'fulfilled') {\n succeeded++;\n results.push({ status: 'fulfilled', value: result.value });\n } else {\n failed++;\n results.push({ status: 'rejected', reason: (result.reason as Error)?.message ?? String(result.reason) });\n }\n }\n\n onProgress?.(succeeded + failed, items.length);\n }\n\n return { succeeded, failed, results };\n}\n"],"mappings":";;;AAQO,IAAM,wBAAwB;AAE9B,IAAM,8BAA8B;AAY3C,eAAsB,aACpB,OACA,IACA,SAIyB;AACzB,QAAM,EAAE,aAAa,WAAW,IAAI;AACpC,MAAI,YAAY;AAChB,MAAI,SAAS;AACb,QAAM,UAAqC,CAAC;AAE5C,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,aAAa;AAClD,UAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,WAAW;AAC5C,UAAM,UAAU,MAAM,QAAQ,WAAW,MAAM,IAAI,EAAE,CAAC;AAEtD,eAAW,UAAU,SAAS;AAC5B,UAAI,OAAO,WAAW,aAAa;AACjC;AACA,gBAAQ,KAAK,EAAE,QAAQ,aAAa,OAAO,OAAO,MAAM,CAAC;AAAA,MAC3D,OAAO;AACL;AACA,gBAAQ,KAAK,EAAE,QAAQ,YAAY,QAAS,OAAO,QAAkB,WAAW,OAAO,OAAO,MAAM,EAAE,CAAC;AAAA,MACzG;AAAA,IACF;AAEA,iBAAa,YAAY,QAAQ,MAAM,MAAM;AAAA,EAC/C;AAEA,SAAO,EAAE,WAAW,QAAQ,QAAQ;AACtC;","names":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/daemon/logger.ts
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
var LEVEL_ORDER = {
|
|
7
|
+
debug: 0,
|
|
8
|
+
info: 1,
|
|
9
|
+
warn: 2,
|
|
10
|
+
error: 3
|
|
11
|
+
};
|
|
12
|
+
var DaemonLogger = class {
|
|
13
|
+
logPath;
|
|
14
|
+
fd = null;
|
|
15
|
+
currentSize = 0;
|
|
16
|
+
level;
|
|
17
|
+
maxSize;
|
|
18
|
+
maxFiles;
|
|
19
|
+
logDir;
|
|
20
|
+
constructor(logDir, options = {}) {
|
|
21
|
+
this.logDir = logDir;
|
|
22
|
+
this.logPath = path.join(logDir, "daemon.log");
|
|
23
|
+
this.level = options.level ?? "info";
|
|
24
|
+
this.maxSize = options.maxSize ?? 5242880;
|
|
25
|
+
this.maxFiles = options.maxFiles ?? 3;
|
|
26
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
27
|
+
this.fd = fs.openSync(this.logPath, "a");
|
|
28
|
+
try {
|
|
29
|
+
this.currentSize = fs.fstatSync(this.fd).size;
|
|
30
|
+
} catch {
|
|
31
|
+
this.currentSize = 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
debug(component, message, data) {
|
|
35
|
+
this.write("debug", component, message, data);
|
|
36
|
+
}
|
|
37
|
+
info(component, message, data) {
|
|
38
|
+
this.write("info", component, message, data);
|
|
39
|
+
}
|
|
40
|
+
warn(component, message, data) {
|
|
41
|
+
this.write("warn", component, message, data);
|
|
42
|
+
}
|
|
43
|
+
error(component, message, data) {
|
|
44
|
+
this.write("error", component, message, data);
|
|
45
|
+
}
|
|
46
|
+
close() {
|
|
47
|
+
if (this.fd !== null) {
|
|
48
|
+
fs.closeSync(this.fd);
|
|
49
|
+
this.fd = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
write(level, component, message, data) {
|
|
53
|
+
if (LEVEL_ORDER[level] < LEVEL_ORDER[this.level]) return;
|
|
54
|
+
const entry = {
|
|
55
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
56
|
+
level,
|
|
57
|
+
component,
|
|
58
|
+
message,
|
|
59
|
+
...data
|
|
60
|
+
};
|
|
61
|
+
const line = JSON.stringify(entry) + "\n";
|
|
62
|
+
const bytes = Buffer.byteLength(line);
|
|
63
|
+
if (this.currentSize + bytes > this.maxSize) {
|
|
64
|
+
this.rotate();
|
|
65
|
+
}
|
|
66
|
+
if (this.fd !== null) {
|
|
67
|
+
fs.writeSync(this.fd, line);
|
|
68
|
+
this.currentSize += bytes;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
rotate() {
|
|
72
|
+
this.close();
|
|
73
|
+
for (let i = this.maxFiles - 1; i >= 1; i--) {
|
|
74
|
+
const from = path.join(this.logDir, `daemon.${i}.log`);
|
|
75
|
+
const to = path.join(this.logDir, `daemon.${i + 1}.log`);
|
|
76
|
+
if (fs.existsSync(from)) {
|
|
77
|
+
if (i + 1 > this.maxFiles) {
|
|
78
|
+
fs.unlinkSync(from);
|
|
79
|
+
} else {
|
|
80
|
+
fs.renameSync(from, to);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (fs.existsSync(this.logPath)) {
|
|
85
|
+
fs.renameSync(this.logPath, path.join(this.logDir, "daemon.1.log"));
|
|
86
|
+
}
|
|
87
|
+
this.fd = fs.openSync(this.logPath, "a");
|
|
88
|
+
this.currentSize = 0;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
LEVEL_ORDER,
|
|
94
|
+
DaemonLogger
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=chunk-5EZ7QF6J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon/logger.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface LogEntry {\n timestamp: string;\n level: string;\n component: string;\n message: string;\n [key: string]: unknown;\n}\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport const LEVEL_ORDER: Record<LogLevel, number> = {\n debug: 0, info: 1, warn: 2, error: 3,\n};\n\ninterface LoggerOptions {\n level?: LogLevel;\n maxSize?: number;\n maxFiles?: number;\n}\n\nexport class DaemonLogger {\n private logPath: string;\n private fd: number | null = null;\n private currentSize = 0;\n private level: LogLevel;\n private maxSize: number;\n private maxFiles: number;\n private logDir: string;\n\n constructor(logDir: string, options: LoggerOptions = {}) {\n this.logDir = logDir;\n this.logPath = path.join(logDir, 'daemon.log');\n this.level = options.level ?? 'info';\n this.maxSize = options.maxSize ?? 5_242_880;\n this.maxFiles = options.maxFiles ?? 3;\n\n fs.mkdirSync(logDir, { recursive: true });\n this.fd = fs.openSync(this.logPath, 'a');\n try {\n this.currentSize = fs.fstatSync(this.fd).size;\n } catch {\n this.currentSize = 0;\n }\n }\n\n debug(component: string, message: string, data?: Record<string, unknown>): void {\n this.write('debug', component, message, data);\n }\n\n info(component: string, message: string, data?: Record<string, unknown>): void {\n this.write('info', component, message, data);\n }\n\n warn(component: string, message: string, data?: Record<string, unknown>): void {\n this.write('warn', component, message, data);\n }\n\n error(component: string, message: string, data?: Record<string, unknown>): void {\n this.write('error', component, message, data);\n }\n\n close(): void {\n if (this.fd !== null) {\n fs.closeSync(this.fd);\n this.fd = null;\n }\n }\n\n private write(level: LogLevel, component: string, message: string, data?: Record<string, unknown>): void {\n if (LEVEL_ORDER[level] < LEVEL_ORDER[this.level]) return;\n\n const entry: LogEntry = {\n timestamp: new Date().toISOString(),\n level,\n component,\n message,\n ...data,\n };\n\n const line = JSON.stringify(entry) + '\\n';\n const bytes = Buffer.byteLength(line);\n\n if (this.currentSize + bytes > this.maxSize) {\n this.rotate();\n }\n\n if (this.fd !== null) {\n fs.writeSync(this.fd, line);\n this.currentSize += bytes;\n }\n }\n\n private rotate(): void {\n this.close();\n\n for (let i = this.maxFiles - 1; i >= 1; i--) {\n const from = path.join(this.logDir, `daemon.${i}.log`);\n const to = path.join(this.logDir, `daemon.${i + 1}.log`);\n if (fs.existsSync(from)) {\n if (i + 1 > this.maxFiles) {\n fs.unlinkSync(from);\n } else {\n fs.renameSync(from, to);\n }\n }\n }\n\n if (fs.existsSync(this.logPath)) {\n fs.renameSync(this.logPath, path.join(this.logDir, 'daemon.1.log'));\n }\n\n this.fd = fs.openSync(this.logPath, 'a');\n this.currentSize = 0;\n }\n}\n"],"mappings":";;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAYV,IAAM,cAAwC;AAAA,EACnD,OAAO;AAAA,EAAG,MAAM;AAAA,EAAG,MAAM;AAAA,EAAG,OAAO;AACrC;AAQO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA,KAAoB;AAAA,EACpB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAAgB,UAAyB,CAAC,GAAG;AACvD,SAAK,SAAS;AACd,SAAK,UAAU,KAAK,KAAK,QAAQ,YAAY;AAC7C,SAAK,QAAQ,QAAQ,SAAS;AAC9B,SAAK,UAAU,QAAQ,WAAW;AAClC,SAAK,WAAW,QAAQ,YAAY;AAEpC,OAAG,UAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACxC,SAAK,KAAK,GAAG,SAAS,KAAK,SAAS,GAAG;AACvC,QAAI;AACF,WAAK,cAAc,GAAG,UAAU,KAAK,EAAE,EAAE;AAAA,IAC3C,QAAQ;AACN,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,WAAmB,SAAiB,MAAsC;AAC9E,SAAK,MAAM,SAAS,WAAW,SAAS,IAAI;AAAA,EAC9C;AAAA,EAEA,KAAK,WAAmB,SAAiB,MAAsC;AAC7E,SAAK,MAAM,QAAQ,WAAW,SAAS,IAAI;AAAA,EAC7C;AAAA,EAEA,KAAK,WAAmB,SAAiB,MAAsC;AAC7E,SAAK,MAAM,QAAQ,WAAW,SAAS,IAAI;AAAA,EAC7C;AAAA,EAEA,MAAM,WAAmB,SAAiB,MAAsC;AAC9E,SAAK,MAAM,SAAS,WAAW,SAAS,IAAI;AAAA,EAC9C;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,OAAO,MAAM;AACpB,SAAG,UAAU,KAAK,EAAE;AACpB,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEQ,MAAM,OAAiB,WAAmB,SAAiB,MAAsC;AACvG,QAAI,YAAY,KAAK,IAAI,YAAY,KAAK,KAAK,EAAG;AAElD,UAAM,QAAkB;AAAA,MACtB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAEA,UAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,UAAM,QAAQ,OAAO,WAAW,IAAI;AAEpC,QAAI,KAAK,cAAc,QAAQ,KAAK,SAAS;AAC3C,WAAK,OAAO;AAAA,IACd;AAEA,QAAI,KAAK,OAAO,MAAM;AACpB,SAAG,UAAU,KAAK,IAAI,IAAI;AAC1B,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEQ,SAAe;AACrB,SAAK,MAAM;AAEX,aAAS,IAAI,KAAK,WAAW,GAAG,KAAK,GAAG,KAAK;AAC3C,YAAM,OAAO,KAAK,KAAK,KAAK,QAAQ,UAAU,CAAC,MAAM;AACrD,YAAM,KAAK,KAAK,KAAK,KAAK,QAAQ,UAAU,IAAI,CAAC,MAAM;AACvD,UAAI,GAAG,WAAW,IAAI,GAAG;AACvB,YAAI,IAAI,IAAI,KAAK,UAAU;AACzB,aAAG,WAAW,IAAI;AAAA,QACpB,OAAO;AACL,aAAG,WAAW,MAAM,EAAE;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,GAAG,WAAW,KAAK,OAAO,GAAG;AAC/B,SAAG,WAAW,KAAK,SAAS,KAAK,KAAK,KAAK,QAAQ,cAAc,CAAC;AAAA,IACpE;AAEA,SAAK,KAAK,GAAG,SAAS,KAAK,SAAS,GAAG;AACvC,SAAK,cAAc;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/index/fts.ts
|
|
4
|
+
function initFts(index) {
|
|
5
|
+
const db = index.getDb();
|
|
6
|
+
db.exec(`
|
|
7
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
|
|
8
|
+
path UNINDEXED,
|
|
9
|
+
type UNINDEXED,
|
|
10
|
+
id UNINDEXED,
|
|
11
|
+
title,
|
|
12
|
+
content,
|
|
13
|
+
content='notes',
|
|
14
|
+
content_rowid='rowid'
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TRIGGER IF NOT EXISTS notes_ai AFTER INSERT ON notes BEGIN
|
|
18
|
+
INSERT INTO notes_fts(rowid, path, type, id, title, content)
|
|
19
|
+
VALUES (new.rowid, new.path, new.type, new.id, new.title, new.content);
|
|
20
|
+
END;
|
|
21
|
+
|
|
22
|
+
CREATE TRIGGER IF NOT EXISTS notes_ad AFTER DELETE ON notes BEGIN
|
|
23
|
+
INSERT INTO notes_fts(notes_fts, rowid, path, type, id, title, content)
|
|
24
|
+
VALUES ('delete', old.rowid, old.path, old.type, old.id, old.title, old.content);
|
|
25
|
+
END;
|
|
26
|
+
|
|
27
|
+
CREATE TRIGGER IF NOT EXISTS notes_au AFTER UPDATE ON notes BEGIN
|
|
28
|
+
INSERT INTO notes_fts(notes_fts, rowid, path, type, id, title, content)
|
|
29
|
+
VALUES ('delete', old.rowid, old.path, old.type, old.id, old.title, old.content);
|
|
30
|
+
INSERT INTO notes_fts(rowid, path, type, id, title, content)
|
|
31
|
+
VALUES (new.rowid, new.path, new.type, new.id, new.title, new.content);
|
|
32
|
+
END;
|
|
33
|
+
`);
|
|
34
|
+
}
|
|
35
|
+
function searchFts(index, query, options = {}) {
|
|
36
|
+
const db = index.getDb();
|
|
37
|
+
const limit = options.limit ?? 20;
|
|
38
|
+
const params = [query];
|
|
39
|
+
let typeFilter = "";
|
|
40
|
+
if (options.type) {
|
|
41
|
+
typeFilter = " AND type = ?";
|
|
42
|
+
params.push(options.type);
|
|
43
|
+
}
|
|
44
|
+
params.push(limit);
|
|
45
|
+
const sql = `
|
|
46
|
+
SELECT path, type, id, title,
|
|
47
|
+
snippet(notes_fts, 4, '<mark>', '</mark>', '...', 40) AS snippet,
|
|
48
|
+
rank
|
|
49
|
+
FROM notes_fts
|
|
50
|
+
WHERE notes_fts MATCH ?${typeFilter}
|
|
51
|
+
ORDER BY rank
|
|
52
|
+
LIMIT ?
|
|
53
|
+
`;
|
|
54
|
+
return db.prepare(sql).all(...params);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
initFts,
|
|
59
|
+
searchFts
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=chunk-6FQISQNA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index/fts.ts"],"sourcesContent":["import type { MycoIndex } from './sqlite.js';\n\nexport interface FtsResult {\n path: string;\n type: string;\n id: string;\n title: string;\n snippet: string;\n rank: number;\n}\n\nexport interface FtsSearchOptions {\n type?: string;\n limit?: number;\n}\n\nexport function initFts(index: MycoIndex): void {\n const db = index.getDb();\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(\n path UNINDEXED,\n type UNINDEXED,\n id UNINDEXED,\n title,\n content,\n content='notes',\n content_rowid='rowid'\n );\n\n CREATE TRIGGER IF NOT EXISTS notes_ai AFTER INSERT ON notes BEGIN\n INSERT INTO notes_fts(rowid, path, type, id, title, content)\n VALUES (new.rowid, new.path, new.type, new.id, new.title, new.content);\n END;\n\n CREATE TRIGGER IF NOT EXISTS notes_ad AFTER DELETE ON notes BEGIN\n INSERT INTO notes_fts(notes_fts, rowid, path, type, id, title, content)\n VALUES ('delete', old.rowid, old.path, old.type, old.id, old.title, old.content);\n END;\n\n CREATE TRIGGER IF NOT EXISTS notes_au AFTER UPDATE ON notes BEGIN\n INSERT INTO notes_fts(notes_fts, rowid, path, type, id, title, content)\n VALUES ('delete', old.rowid, old.path, old.type, old.id, old.title, old.content);\n INSERT INTO notes_fts(rowid, path, type, id, title, content)\n VALUES (new.rowid, new.path, new.type, new.id, new.title, new.content);\n END;\n `);\n}\n\nexport function searchFts(index: MycoIndex, query: string, options: FtsSearchOptions = {}): FtsResult[] {\n const db = index.getDb();\n const limit = options.limit ?? 20;\n const params: unknown[] = [query];\n\n let typeFilter = '';\n if (options.type) {\n typeFilter = ' AND type = ?';\n params.push(options.type);\n }\n params.push(limit);\n\n const sql = `\n SELECT path, type, id, title,\n snippet(notes_fts, 4, '<mark>', '</mark>', '...', 40) AS snippet,\n rank\n FROM notes_fts\n WHERE notes_fts MATCH ?${typeFilter}\n ORDER BY rank\n LIMIT ?\n `;\n\n return db.prepare(sql).all(...params) as FtsResult[];\n}\n"],"mappings":";;;AAgBO,SAAS,QAAQ,OAAwB;AAC9C,QAAM,KAAK,MAAM,MAAM;AACvB,KAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GA2BP;AACH;AAEO,SAAS,UAAU,OAAkB,OAAe,UAA4B,CAAC,GAAgB;AACtG,QAAM,KAAK,MAAM,MAAM;AACvB,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,SAAoB,CAAC,KAAK;AAEhC,MAAI,aAAa;AACjB,MAAI,QAAQ,MAAM;AAChB,iBAAa;AACb,WAAO,KAAK,QAAQ,IAAI;AAAA,EAC1B;AACA,SAAO,KAAK,KAAK;AAEjB,QAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,6BAKe,UAAU;AAAA;AAAA;AAAA;AAKrC,SAAO,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,MAAM;AACtC;","names":[]}
|