@pella-labs/pinakes 0.1.10 → 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/README.md +20 -20
- package/dist/cli/audit.d.ts +5 -3
- package/dist/cli/audit.d.ts.map +1 -1
- package/dist/cli/audit.js +3 -24
- package/dist/cli/audit.js.map +1 -1
- package/dist/cli/contradiction-cli.d.ts +12 -0
- package/dist/cli/contradiction-cli.d.ts.map +1 -0
- package/dist/cli/contradiction-cli.js +35 -0
- package/dist/cli/contradiction-cli.js.map +1 -0
- package/dist/cli/contradiction.d.ts +59 -0
- package/dist/cli/contradiction.d.ts.map +1 -0
- package/dist/cli/contradiction.js +172 -0
- package/dist/cli/contradiction.js.map +1 -0
- package/dist/cli/export.d.ts +1 -1
- package/dist/cli/export.d.ts.map +1 -1
- package/dist/cli/export.js +7 -28
- package/dist/cli/export.js.map +1 -1
- package/dist/cli/import.d.ts +2 -2
- package/dist/cli/import.d.ts.map +1 -1
- package/dist/cli/import.js +5 -26
- package/dist/cli/import.js.map +1 -1
- package/dist/cli/index.js +39 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/purge.d.ts +2 -2
- package/dist/cli/purge.d.ts.map +1 -1
- package/dist/cli/purge.js +2 -23
- package/dist/cli/purge.js.map +1 -1
- package/dist/cli/rebuild.d.ts +8 -6
- package/dist/cli/rebuild.d.ts.map +1 -1
- package/dist/cli/rebuild.js +9 -31
- package/dist/cli/rebuild.js.map +1 -1
- package/dist/cli/serve.d.ts +9 -7
- package/dist/cli/serve.d.ts.map +1 -1
- package/dist/cli/serve.js +71 -41
- package/dist/cli/serve.js.map +1 -1
- package/dist/cli/status.d.ts +7 -5
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +10 -29
- package/dist/cli/status.js.map +1 -1
- package/dist/db/client.d.ts +4 -4
- package/dist/db/client.js +3 -3
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrations/migrations/0002_rename_kg_to_pinakes.sql +49 -0
- package/dist/db/migrations/migrations/meta/0002_snapshot.json +504 -0
- package/dist/db/migrations/migrations/meta/_journal.json +7 -0
- package/dist/db/repository.js +5 -5
- package/dist/db/repository.js.map +1 -1
- package/dist/db/schema.d.ts +84 -84
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +49 -49
- package/dist/db/schema.js.map +1 -1
- package/dist/db/types.d.ts +2 -2
- package/dist/db/types.js +1 -1
- package/dist/gaps/detector.d.ts +5 -5
- package/dist/gaps/detector.js +15 -15
- package/dist/gaps/detector.js.map +1 -1
- package/dist/ingest/chokidar.js +1 -1
- package/dist/ingest/ingester.d.ts +9 -4
- package/dist/ingest/ingester.d.ts.map +1 -1
- package/dist/ingest/ingester.js +82 -17
- package/dist/ingest/ingester.js.map +1 -1
- package/dist/ingest/manifest.d.ts +5 -3
- package/dist/ingest/manifest.d.ts.map +1 -1
- package/dist/ingest/manifest.js +23 -14
- package/dist/ingest/manifest.js.map +1 -1
- package/dist/ingest/parse/chunk.js +1 -1
- package/dist/ingest/parse/markdown.d.ts +2 -2
- package/dist/ingest/queue.d.ts +1 -1
- package/dist/ingest/queue.js +1 -1
- package/dist/ingest/source.d.ts +2 -2
- package/dist/ingest/source.d.ts.map +1 -1
- package/dist/ingest/source.js +1 -1
- package/dist/llm/provider.d.ts +70 -0
- package/dist/llm/provider.d.ts.map +1 -0
- package/dist/llm/provider.js +235 -0
- package/dist/llm/provider.js.map +1 -0
- package/dist/mcp/envelope.d.ts +1 -1
- package/dist/mcp/tools/execute.d.ts +7 -7
- package/dist/mcp/tools/execute.d.ts.map +1 -1
- package/dist/mcp/tools/execute.js +41 -59
- package/dist/mcp/tools/execute.js.map +1 -1
- package/dist/mcp/tools/search.d.ts +13 -8
- package/dist/mcp/tools/search.d.ts.map +1 -1
- package/dist/mcp/tools/search.js +53 -28
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/observability/audit.d.ts +2 -2
- package/dist/observability/audit.js +3 -3
- package/dist/observability/audit.js.map +1 -1
- package/dist/observability/logger.js +4 -4
- package/dist/observability/logger.js.map +1 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/metrics.js.map +1 -1
- package/dist/paths.d.ts +61 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +106 -0
- package/dist/paths.js.map +1 -0
- package/dist/retrieval/dedup.d.ts +25 -0
- package/dist/retrieval/dedup.d.ts.map +1 -0
- package/dist/retrieval/dedup.js +97 -0
- package/dist/retrieval/dedup.js.map +1 -0
- package/dist/retrieval/embedder.d.ts +9 -9
- package/dist/retrieval/embedder.d.ts.map +1 -1
- package/dist/retrieval/embedder.js +17 -17
- package/dist/retrieval/embedder.js.map +1 -1
- package/dist/retrieval/expand.d.ts +18 -0
- package/dist/retrieval/expand.d.ts.map +1 -0
- package/dist/retrieval/expand.js +89 -0
- package/dist/retrieval/expand.js.map +1 -0
- package/dist/retrieval/fts.d.ts +3 -3
- package/dist/retrieval/fts.js +8 -8
- package/dist/retrieval/graph.d.ts +47 -0
- package/dist/retrieval/graph.d.ts.map +1 -0
- package/dist/retrieval/graph.js +144 -0
- package/dist/retrieval/graph.js.map +1 -0
- package/dist/retrieval/hybrid.d.ts +10 -0
- package/dist/retrieval/hybrid.d.ts.map +1 -1
- package/dist/retrieval/hybrid.js +57 -2
- package/dist/retrieval/hybrid.js.map +1 -1
- package/dist/retrieval/vec.d.ts +2 -2
- package/dist/retrieval/vec.js +3 -3
- package/dist/sandbox/bindings/install.d.ts +5 -5
- package/dist/sandbox/bindings/install.d.ts.map +1 -1
- package/dist/sandbox/bindings/install.js +3 -3
- package/dist/sandbox/bindings/install.js.map +1 -1
- package/dist/sandbox/bindings/kg.d.ts.map +1 -1
- package/dist/sandbox/bindings/kg.js +10 -0
- package/dist/sandbox/bindings/kg.js.map +1 -1
- package/dist/sandbox/bindings/pinakes.d.ts +29 -0
- package/dist/sandbox/bindings/pinakes.d.ts.map +1 -0
- package/dist/sandbox/bindings/pinakes.js +333 -0
- package/dist/sandbox/bindings/pinakes.js.map +1 -0
- package/dist/sandbox/bindings/write.d.ts +1 -1
- package/dist/sandbox/bindings/write.d.ts.map +1 -1
- package/dist/sandbox/bindings/write.js +9 -9
- package/dist/sandbox/bindings/write.js.map +1 -1
- package/dist/sandbox/executor.d.ts +3 -3
- package/dist/sandbox/executor.js +6 -6
- package/dist/sandbox/executor.js.map +1 -1
- package/dist/sandbox/helpers.d.ts +1 -1
- package/dist/sandbox/helpers.d.ts.map +1 -1
- package/dist/sandbox/helpers.js +2 -2
- package/dist/sandbox/vendored-codemode.d.ts +1 -1
- package/dist/sandbox/vendored-codemode.js +1 -1
- package/dist/server.js +15 -6
- package/dist/server.js.map +1 -1
- package/package.json +22 -27
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@ Local stdio MCP server that indexes a [Karpathy-style](https://gist.github.com/k
|
|
|
4
4
|
|
|
5
5
|
**Two tools. One process. Works with any MCP client.**
|
|
6
6
|
|
|
7
|
-
- `
|
|
8
|
-
- `
|
|
7
|
+
- `search` — hybrid FTS5 + vector search ranked by Reciprocal Rank Fusion
|
|
8
|
+
- `execute` — run JS in a QuickJS sandbox with `pinakes.project.*` bindings for search, graph traversal, wiki writes, and more
|
|
9
9
|
|
|
10
10
|
Markdown is canonical. SQLite is the index. If the index is corrupted or lost, rebuild it from markdown.
|
|
11
11
|
|
|
@@ -103,33 +103,33 @@ The server indexes all `.md` files in the wiki directory, watches for changes, a
|
|
|
103
103
|
### Search
|
|
104
104
|
|
|
105
105
|
```
|
|
106
|
-
|
|
106
|
+
search({ query: "authentication flow", scope: "project" })
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
### Execute (code-mode)
|
|
110
110
|
|
|
111
111
|
```javascript
|
|
112
112
|
// Browse the wiki index
|
|
113
|
-
|
|
113
|
+
execute({ code: `return pinakes.project.index()` })
|
|
114
114
|
|
|
115
115
|
// Full-text search
|
|
116
|
-
|
|
116
|
+
execute({ code: `return pinakes.project.fts("bcrypt")` })
|
|
117
117
|
|
|
118
118
|
// Node lookup + neighbors
|
|
119
|
-
|
|
120
|
-
const node =
|
|
121
|
-
const neighbors =
|
|
119
|
+
execute({ code: `
|
|
120
|
+
const node = pinakes.project.get("sha1-id-here");
|
|
121
|
+
const neighbors = pinakes.project.neighbors(node.id, { depth: 2 });
|
|
122
122
|
return { node, neighbors };
|
|
123
123
|
` })
|
|
124
124
|
|
|
125
125
|
// Write a wiki page
|
|
126
|
-
|
|
127
|
-
return
|
|
126
|
+
execute({ code: `
|
|
127
|
+
return pinakes.project.write("decisions/use-postgres.md", "# Use PostgreSQL\\nWe chose Postgres because...");
|
|
128
128
|
` })
|
|
129
129
|
|
|
130
130
|
// Query across both scopes
|
|
131
|
-
|
|
132
|
-
code: `return
|
|
131
|
+
execute({
|
|
132
|
+
code: `return pinakes.project.hybrid("deploy process")`,
|
|
133
133
|
scope: "both"
|
|
134
134
|
})
|
|
135
135
|
```
|
|
@@ -153,23 +153,23 @@ The default embedder is bundled (`Xenova/all-MiniLM-L6-v2`, 384 dimensions, runs
|
|
|
153
153
|
### Ollama (local, free)
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
|
-
export
|
|
157
|
-
export
|
|
158
|
-
export
|
|
156
|
+
export PINAKES_EMBED_PROVIDER=ollama
|
|
157
|
+
export PINAKES_OLLAMA_URL=http://localhost:11434
|
|
158
|
+
export PINAKES_OLLAMA_MODEL=nomic-embed-text
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
### Voyage AI (cloud, paid)
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
|
-
export
|
|
165
|
-
export
|
|
164
|
+
export PINAKES_EMBED_PROVIDER=voyage
|
|
165
|
+
export PINAKES_VOYAGE_API_KEY=your-key-here
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
### OpenAI (cloud, paid)
|
|
169
169
|
|
|
170
170
|
```bash
|
|
171
|
-
export
|
|
172
|
-
export
|
|
171
|
+
export PINAKES_EMBED_PROVIDER=openai
|
|
172
|
+
export PINAKES_OPENAI_API_KEY=your-key-here
|
|
173
173
|
```
|
|
174
174
|
|
|
175
175
|
Changing the embedder requires a full rebuild (`pinakes rebuild`) since the vector dimensions change.
|
|
@@ -178,7 +178,7 @@ Changing the embedder requires a full rebuild (`pinakes rebuild`) since the vect
|
|
|
178
178
|
|
|
179
179
|
- **Single process**: MCP server, file watcher, SQLite writer, read pool, embedder, and QuickJS sandbox all in one Node process
|
|
180
180
|
- **Single writer, multi reader**: one writer connection + 2 reader connections per DB, WAL mode
|
|
181
|
-
- **Two-level KG**: project wiki (`./wiki/`) + personal wiki (`~/.
|
|
181
|
+
- **Two-level KG**: project wiki (`./wiki/`) + personal wiki (`~/.pinakes/wiki/`), fully isolated by default
|
|
182
182
|
- **Privacy invariant**: personal KG bindings are only injected when `scope` includes `'personal'`
|
|
183
183
|
- **Budget gate**: every response stays under `max_tokens` (default 5000, hard cap 25000)
|
|
184
184
|
- **Deterministic IDs**: `sha1(scope + ':' + source_uri + ':' + section_path)` means re-indexing is idempotent
|
package/dist/cli/audit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
2
|
+
* `pinakes audit --tail` — tail the pinakes_audit table for a scope's DB.
|
|
3
3
|
*
|
|
4
4
|
* Reads the most recent N audit rows (default 20) and prints them as
|
|
5
5
|
* newline-delimited JSON. Strictly read-only.
|
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
export interface AuditOptions {
|
|
8
8
|
/** Number of rows to show (default 20) */
|
|
9
9
|
n?: number;
|
|
10
|
-
/** Project
|
|
10
|
+
/** Project root directory (default: cwd) */
|
|
11
|
+
projectRoot?: string;
|
|
12
|
+
/** Project DB path override */
|
|
11
13
|
dbPath?: string;
|
|
12
|
-
/** Wiki path (
|
|
14
|
+
/** Wiki path (unused in new layout, kept for backwards compat) */
|
|
13
15
|
wikiPath?: string;
|
|
14
16
|
/** Personal DB path */
|
|
15
17
|
profileDbPath?: string;
|
package/dist/cli/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/cli/audit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/cli/audit.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uBAAuB;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,KAAK,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;CAChC;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,QAAQ,EAAE,CAqB9D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAGpD"}
|
package/dist/cli/audit.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
4
2
|
import { closeDb, openDb } from '../db/client.js';
|
|
3
|
+
import { resolveCliDbPath } from '../paths.js';
|
|
5
4
|
export function auditCommand(options) {
|
|
6
5
|
const scope = options.scope ?? 'project';
|
|
7
6
|
const n = options.n ?? 20;
|
|
8
|
-
const dbPath =
|
|
7
|
+
const dbPath = resolveCliDbPath(options, scope);
|
|
9
8
|
if (!existsSync(dbPath)) {
|
|
10
9
|
return [];
|
|
11
10
|
}
|
|
@@ -13,7 +12,7 @@ export function auditCommand(options) {
|
|
|
13
12
|
try {
|
|
14
13
|
const rows = bundle.writer
|
|
15
14
|
.prepare(`SELECT id, ts, tool_name, scope_requested, caller_ctx, response_tokens, error
|
|
16
|
-
FROM
|
|
15
|
+
FROM pinakes_audit ORDER BY id DESC LIMIT ?`)
|
|
17
16
|
.all(n);
|
|
18
17
|
return rows.reverse(); // chronological order
|
|
19
18
|
}
|
|
@@ -26,24 +25,4 @@ export function renderAudit(rows) {
|
|
|
26
25
|
return '(no audit rows)';
|
|
27
26
|
return rows.map((r) => JSON.stringify(r)).join('\n');
|
|
28
27
|
}
|
|
29
|
-
// ----------------------------------------------------------------------------
|
|
30
|
-
// Path helpers (shared pattern with status.ts)
|
|
31
|
-
// ----------------------------------------------------------------------------
|
|
32
|
-
function resolveDbPath(options, scope) {
|
|
33
|
-
if (scope === 'personal') {
|
|
34
|
-
if (options.profileDbPath)
|
|
35
|
-
return resolveAbs(options.profileDbPath);
|
|
36
|
-
const env = process.env.KG_PROFILE_PATH;
|
|
37
|
-
const profileDir = env ? resolveAbs(env) : resolve(homedir(), '.pharos/profile');
|
|
38
|
-
return resolve(profileDir, 'kg.db');
|
|
39
|
-
}
|
|
40
|
-
if (options.dbPath)
|
|
41
|
-
return resolveAbs(options.dbPath);
|
|
42
|
-
if (options.wikiPath)
|
|
43
|
-
return resolve(dirname(resolveAbs(options.wikiPath)), '.pinakes', 'pinakes.db');
|
|
44
|
-
return resolve(process.cwd(), '.pinakes', 'pinakes.db');
|
|
45
|
-
}
|
|
46
|
-
function resolveAbs(p) {
|
|
47
|
-
return isAbsolute(p) ? p : resolve(process.cwd(), p);
|
|
48
|
-
}
|
|
49
28
|
//# sourceMappingURL=audit.js.map
|
package/dist/cli/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/cli/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/cli/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAkC/C,MAAM,UAAU,YAAY,CAAC,OAAqB;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC;IACzC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAEhD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM;aACvB,OAAO,CACN;qDAC6C,CAC9C;aACA,GAAG,CAAC,CAAC,CAAe,CAAC;QACxB,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,sBAAsB;IAC/C,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAChD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ContradictionResult } from './contradiction.js';
|
|
2
|
+
/**
|
|
3
|
+
* CLI wrapper for the contradiction scan command.
|
|
4
|
+
* Sets up DB connection and LLM provider, runs the scan, cleans up.
|
|
5
|
+
*/
|
|
6
|
+
export declare function contradictionScanCommand(opts: {
|
|
7
|
+
scope: 'project' | 'personal';
|
|
8
|
+
projectRoot?: string;
|
|
9
|
+
wikiPath?: string;
|
|
10
|
+
dbPath?: string;
|
|
11
|
+
}): Promise<ContradictionResult>;
|
|
12
|
+
//# sourceMappingURL=contradiction-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contradiction-cli.d.ts","sourceRoot":"","sources":["../../src/cli/contradiction-cli.ts"],"names":[],"mappings":"AASA,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEjF;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyB/B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { closeDb, openDb } from '../db/client.js';
|
|
2
|
+
import { createLlmProvider } from '../llm/provider.js';
|
|
3
|
+
import { resolveAbs, projectWikiPath as defaultProjectWikiPath, projectDbPath as defaultProjectDbPath, personalWikiPath as defaultPersonalWikiPath, personalDbPath as defaultPersonalDbPath, } from '../paths.js';
|
|
4
|
+
import { contradictionScan } from './contradiction.js';
|
|
5
|
+
/**
|
|
6
|
+
* CLI wrapper for the contradiction scan command.
|
|
7
|
+
* Sets up DB connection and LLM provider, runs the scan, cleans up.
|
|
8
|
+
*/
|
|
9
|
+
export async function contradictionScanCommand(opts) {
|
|
10
|
+
const projectRoot = resolveAbs(opts.projectRoot ?? process.cwd());
|
|
11
|
+
const wikiPath = opts.wikiPath
|
|
12
|
+
? resolveAbs(opts.wikiPath)
|
|
13
|
+
: opts.scope === 'personal'
|
|
14
|
+
? defaultPersonalWikiPath()
|
|
15
|
+
: defaultProjectWikiPath(projectRoot);
|
|
16
|
+
const dbPath = opts.dbPath
|
|
17
|
+
? resolveAbs(opts.dbPath)
|
|
18
|
+
: opts.scope === 'personal'
|
|
19
|
+
? defaultPersonalDbPath()
|
|
20
|
+
: defaultProjectDbPath(projectRoot);
|
|
21
|
+
const bundle = openDb(dbPath);
|
|
22
|
+
try {
|
|
23
|
+
const llmProvider = createLlmProvider();
|
|
24
|
+
return await contradictionScan({
|
|
25
|
+
bundle,
|
|
26
|
+
scope: opts.scope,
|
|
27
|
+
llmProvider,
|
|
28
|
+
wikiRoot: wikiPath,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
closeDb(bundle);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=contradiction-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contradiction-cli.js","sourceRoot":"","sources":["../../src/cli/contradiction-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EACL,UAAU,EACV,eAAe,IAAI,sBAAsB,EACzC,aAAa,IAAI,oBAAoB,EACrC,gBAAgB,IAAI,uBAAuB,EAC3C,cAAc,IAAI,qBAAqB,GACxC,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAA4B,MAAM,oBAAoB,CAAC;AAEjF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,IAK9C;IACC,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;QAC5B,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC3B,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,UAAU;YACzB,CAAC,CAAC,uBAAuB,EAAE;YAC3B,CAAC,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM;QACxB,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;QACzB,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,UAAU;YACzB,CAAC,CAAC,qBAAqB,EAAE;YACzB,CAAC,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAExC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,iBAAiB,EAAE,CAAC;QACxC,OAAO,MAAM,iBAAiB,CAAC;YAC7B,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW;YACX,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DbBundle } from '../db/client.js';
|
|
2
|
+
import type { LlmProvider } from '../llm/provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* Contradiction detector CLI command (PRD Phase 8, stretch goal H).
|
|
5
|
+
*
|
|
6
|
+
* Scans wiki chunks for contradictory claims using pairwise LLM judge.
|
|
7
|
+
* Rate-limited to 1 scan per hour. Outputs contradictions.md to wiki root.
|
|
8
|
+
*/
|
|
9
|
+
export interface ContradictionScanOpts {
|
|
10
|
+
bundle: DbBundle;
|
|
11
|
+
scope: 'project' | 'personal';
|
|
12
|
+
llmProvider: LlmProvider;
|
|
13
|
+
wikiRoot: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Contradiction {
|
|
16
|
+
chunkA: {
|
|
17
|
+
id: string;
|
|
18
|
+
source_uri: string;
|
|
19
|
+
text: string;
|
|
20
|
+
};
|
|
21
|
+
chunkB: {
|
|
22
|
+
id: string;
|
|
23
|
+
source_uri: string;
|
|
24
|
+
text: string;
|
|
25
|
+
};
|
|
26
|
+
explanation: string;
|
|
27
|
+
confidence: 'high' | 'medium';
|
|
28
|
+
}
|
|
29
|
+
export interface ContradictionResult {
|
|
30
|
+
scanned_pairs: number;
|
|
31
|
+
contradictions: Contradiction[];
|
|
32
|
+
rate_limited: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Run a contradiction scan. Returns immediately if rate-limited.
|
|
36
|
+
*/
|
|
37
|
+
export declare function contradictionScan(opts: ContradictionScanOpts): Promise<ContradictionResult>;
|
|
38
|
+
interface ChunkInfo {
|
|
39
|
+
id: string;
|
|
40
|
+
source_uri: string;
|
|
41
|
+
text: string;
|
|
42
|
+
}
|
|
43
|
+
interface CandidatePair {
|
|
44
|
+
a: ChunkInfo;
|
|
45
|
+
b: ChunkInfo;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Find candidate pairs for contradiction checking.
|
|
49
|
+
* Uses vector similarity to find chunks that are semantically similar
|
|
50
|
+
* (which is a prerequisite for them to potentially contradict).
|
|
51
|
+
*/
|
|
52
|
+
declare function findCandidatePairs(bundle: DbBundle, scope: string): CandidatePair[];
|
|
53
|
+
declare function parseJudgment(response: string): {
|
|
54
|
+
contradicts: boolean;
|
|
55
|
+
explanation: string;
|
|
56
|
+
confidence: string;
|
|
57
|
+
} | null;
|
|
58
|
+
export { findCandidatePairs as _findCandidatePairs, parseJudgment as _parseJudgment };
|
|
59
|
+
//# sourceMappingURL=contradiction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contradiction.d.ts","sourceRoot":"","sources":["../../src/cli/contradiction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD;;;;;GAKG;AAEH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,EAAE,OAAO,CAAC;CACvB;AAQD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAmE9B;AAMD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,aAAa;IACrB,CAAC,EAAE,SAAS,CAAC;IACb,CAAC,EAAE,SAAS,CAAC;CACd;AAED;;;;GAIG;AACH,iBAAS,kBAAkB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,CAwD5E;AAED,iBAAS,aAAa,CACpB,QAAQ,EAAE,MAAM,GACf;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkB1E;AAyDD,OAAO,EAAE,kBAAkB,IAAI,mBAAmB,EAAE,aAAa,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { logger } from '../observability/logger.js';
|
|
2
|
+
const RATE_LIMIT_MS = 60 * 60 * 1000; // 1 hour
|
|
3
|
+
const MAX_PAIRS = 50;
|
|
4
|
+
const SIMILARITY_THRESHOLD = 0.3;
|
|
5
|
+
const JUDGE_SYSTEM = `You are a contradiction detector. Given two text chunks from a knowledge wiki, determine if they contain contradictory claims. Respond with ONLY valid JSON: {"contradicts": true/false, "explanation": "why", "confidence": "high"|"medium"|"low"}. Only report contradictions you are confident about.`;
|
|
6
|
+
/**
|
|
7
|
+
* Run a contradiction scan. Returns immediately if rate-limited.
|
|
8
|
+
*/
|
|
9
|
+
export async function contradictionScan(opts) {
|
|
10
|
+
const { bundle, scope, llmProvider, wikiRoot } = opts;
|
|
11
|
+
// Rate limit check
|
|
12
|
+
const lastScan = bundle.writer
|
|
13
|
+
.prepare(`SELECT value FROM pinakes_meta WHERE key = ?`)
|
|
14
|
+
.get('last_contradiction_scan');
|
|
15
|
+
if (lastScan) {
|
|
16
|
+
const lastTs = parseInt(lastScan.value, 10);
|
|
17
|
+
if (Date.now() - lastTs < RATE_LIMIT_MS) {
|
|
18
|
+
return { scanned_pairs: 0, contradictions: [], rate_limited: true };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (!llmProvider.available()) {
|
|
22
|
+
throw new Error('No LLM provider available for contradiction detection. ' +
|
|
23
|
+
'Set PINAKES_OLLAMA_URL, ANTHROPIC_API_KEY, or OPENAI_API_KEY, ' +
|
|
24
|
+
'or install the claude/codex CLI.');
|
|
25
|
+
}
|
|
26
|
+
// Find candidate pairs via vector similarity
|
|
27
|
+
const pairs = findCandidatePairs(bundle, scope);
|
|
28
|
+
const contradictions = [];
|
|
29
|
+
let scanned = 0;
|
|
30
|
+
for (const pair of pairs) {
|
|
31
|
+
try {
|
|
32
|
+
const response = await llmProvider.complete({
|
|
33
|
+
system: JUDGE_SYSTEM,
|
|
34
|
+
prompt: `Chunk A (from ${pair.a.source_uri}):\n${pair.a.text}\n\nChunk B (from ${pair.b.source_uri}):\n${pair.b.text}`,
|
|
35
|
+
maxTokens: 200,
|
|
36
|
+
});
|
|
37
|
+
const judgment = parseJudgment(response);
|
|
38
|
+
if (judgment && judgment.contradicts && (judgment.confidence === 'high' || judgment.confidence === 'medium')) {
|
|
39
|
+
contradictions.push({
|
|
40
|
+
chunkA: pair.a,
|
|
41
|
+
chunkB: pair.b,
|
|
42
|
+
explanation: judgment.explanation,
|
|
43
|
+
confidence: judgment.confidence,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
scanned++;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
logger.warn({ err, pairA: pair.a.id, pairB: pair.b.id }, 'contradiction check failed for pair');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Update rate limit timestamp
|
|
53
|
+
bundle.writer
|
|
54
|
+
.prepare(`INSERT OR REPLACE INTO pinakes_meta (key, value) VALUES ('last_contradiction_scan', ?)`)
|
|
55
|
+
.run(String(Date.now()));
|
|
56
|
+
// Write contradictions.md if any found
|
|
57
|
+
if (contradictions.length > 0) {
|
|
58
|
+
writeContradictionReport(wikiRoot, contradictions, bundle, scope);
|
|
59
|
+
}
|
|
60
|
+
return { scanned_pairs: scanned, contradictions, rate_limited: false };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Find candidate pairs for contradiction checking.
|
|
64
|
+
* Uses vector similarity to find chunks that are semantically similar
|
|
65
|
+
* (which is a prerequisite for them to potentially contradict).
|
|
66
|
+
*/
|
|
67
|
+
function findCandidatePairs(bundle, scope) {
|
|
68
|
+
// Get all chunks with their vec embeddings
|
|
69
|
+
const chunks = bundle.writer
|
|
70
|
+
.prepare(`SELECT c.id, n.source_uri, c.text, c.rowid
|
|
71
|
+
FROM pinakes_chunks c
|
|
72
|
+
JOIN pinakes_nodes n ON c.node_id = n.id
|
|
73
|
+
WHERE n.scope = ?
|
|
74
|
+
ORDER BY c.rowid`)
|
|
75
|
+
.all(scope);
|
|
76
|
+
if (chunks.length < 2)
|
|
77
|
+
return [];
|
|
78
|
+
// For each chunk, find the top 5 most similar via vec
|
|
79
|
+
const pairs = new Set();
|
|
80
|
+
const result = [];
|
|
81
|
+
for (const chunk of chunks) {
|
|
82
|
+
if (result.length >= MAX_PAIRS)
|
|
83
|
+
break;
|
|
84
|
+
const similar = bundle.writer
|
|
85
|
+
.prepare(`SELECT rowid, distance
|
|
86
|
+
FROM pinakes_chunks_vec
|
|
87
|
+
WHERE embedding MATCH (SELECT embedding FROM pinakes_chunks_vec WHERE rowid = ?)
|
|
88
|
+
AND k = ?
|
|
89
|
+
ORDER BY distance`)
|
|
90
|
+
.all(chunk.rowid, 6); // 6 because first result is self
|
|
91
|
+
for (const sim of similar) {
|
|
92
|
+
if (sim.rowid === chunk.rowid)
|
|
93
|
+
continue;
|
|
94
|
+
if (sim.distance > SIMILARITY_THRESHOLD)
|
|
95
|
+
continue;
|
|
96
|
+
// Deduplicate symmetric pairs
|
|
97
|
+
const pairKey = [chunk.rowid, sim.rowid].sort().join(':');
|
|
98
|
+
if (pairs.has(pairKey))
|
|
99
|
+
continue;
|
|
100
|
+
pairs.add(pairKey);
|
|
101
|
+
const other = chunks.find((c) => c.rowid === sim.rowid);
|
|
102
|
+
if (!other)
|
|
103
|
+
continue;
|
|
104
|
+
// Skip same-source pairs (they're likely just adjacent sections)
|
|
105
|
+
if (chunk.source_uri === other.source_uri)
|
|
106
|
+
continue;
|
|
107
|
+
result.push({
|
|
108
|
+
a: { id: chunk.id, source_uri: chunk.source_uri, text: chunk.text },
|
|
109
|
+
b: { id: other.id, source_uri: other.source_uri, text: other.text },
|
|
110
|
+
});
|
|
111
|
+
if (result.length >= MAX_PAIRS)
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
function parseJudgment(response) {
|
|
118
|
+
try {
|
|
119
|
+
const match = response.match(/\{[\s\S]*\}/);
|
|
120
|
+
if (!match)
|
|
121
|
+
return null;
|
|
122
|
+
const parsed = JSON.parse(match[0]);
|
|
123
|
+
if (typeof parsed.contradicts !== 'boolean')
|
|
124
|
+
return null;
|
|
125
|
+
return {
|
|
126
|
+
contradicts: parsed.contradicts,
|
|
127
|
+
explanation: parsed.explanation ?? '',
|
|
128
|
+
confidence: parsed.confidence ?? 'low',
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function writeContradictionReport(wikiRoot, contradictions, bundle, scope) {
|
|
136
|
+
const { writeFileSync } = require('node:fs');
|
|
137
|
+
const { join } = require('node:path');
|
|
138
|
+
const lines = [
|
|
139
|
+
'# Detected Contradictions',
|
|
140
|
+
'',
|
|
141
|
+
`*Last scanned: ${new Date().toISOString()}*`,
|
|
142
|
+
'',
|
|
143
|
+
];
|
|
144
|
+
for (const c of contradictions) {
|
|
145
|
+
lines.push(`## ${c.chunkA.source_uri} vs ${c.chunkB.source_uri}`);
|
|
146
|
+
lines.push('');
|
|
147
|
+
lines.push(`- **Chunk A** (${c.chunkA.source_uri}): "${truncate(c.chunkA.text, 200)}"`);
|
|
148
|
+
lines.push(`- **Chunk B** (${c.chunkB.source_uri}): "${truncate(c.chunkB.text, 200)}"`);
|
|
149
|
+
lines.push(`- **Explanation**: ${c.explanation}`);
|
|
150
|
+
lines.push(`- **Confidence**: ${c.confidence}`);
|
|
151
|
+
lines.push('');
|
|
152
|
+
}
|
|
153
|
+
writeFileSync(join(wikiRoot, 'contradictions.md'), lines.join('\n'), 'utf8');
|
|
154
|
+
// Log the scan
|
|
155
|
+
try {
|
|
156
|
+
bundle.writer
|
|
157
|
+
.prepare(`INSERT INTO pinakes_log (ts, scope, kind, source_uri, payload)
|
|
158
|
+
VALUES (?, ?, 'contradiction:scan', NULL, ?)`)
|
|
159
|
+
.run(Date.now(), scope, JSON.stringify({ contradictions_found: contradictions.length }));
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Non-fatal
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function truncate(s, maxLen) {
|
|
166
|
+
if (s.length <= maxLen)
|
|
167
|
+
return s;
|
|
168
|
+
return s.slice(0, maxLen) + '...';
|
|
169
|
+
}
|
|
170
|
+
// Export for testing
|
|
171
|
+
export { findCandidatePairs as _findCandidatePairs, parseJudgment as _parseJudgment };
|
|
172
|
+
//# sourceMappingURL=contradiction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contradiction.js","sourceRoot":"","sources":["../../src/cli/contradiction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AA6BpD,MAAM,aAAa,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAC/C,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,MAAM,YAAY,GAAG,0SAA0S,CAAC;AAEhU;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA2B;IAE3B,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC;IAEtD,mBAAmB;IACnB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM;SAC3B,OAAO,CACN,8CAA8C,CAC/C;SACA,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAElC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,GAAG,aAAa,EAAE,CAAC;YACxC,OAAO,EAAE,aAAa,EAAE,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QACtE,CAAC;IACH,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,yDAAyD;YACvD,gEAAgE;YAChE,kCAAkC,CACrC,CAAC;IACJ,CAAC;IAED,6CAA6C;IAC7C,MAAM,KAAK,GAAG,kBAAkB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEhD,MAAM,cAAc,GAAoB,EAAE,CAAC;IAC3C,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC;gBAC1C,MAAM,EAAE,YAAY;gBACpB,MAAM,EAAE,iBAAiB,IAAI,CAAC,CAAC,CAAC,UAAU,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,qBAAqB,IAAI,CAAC,CAAC,CAAC,UAAU,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;gBACtH,SAAS,EAAE,GAAG;aACf,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,QAAQ,IAAI,QAAQ,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,UAAU,KAAK,MAAM,IAAI,QAAQ,CAAC,UAAU,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC7G,cAAc,CAAC,IAAI,CAAC;oBAClB,MAAM,EAAE,IAAI,CAAC,CAAC;oBACd,MAAM,EAAE,IAAI,CAAC,CAAC;oBACd,WAAW,EAAE,QAAQ,CAAC,WAAW;oBACjC,UAAU,EAAE,QAAQ,CAAC,UAAU;iBAChC,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,qCAAqC,CAAC,CAAC;QAClG,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,CAAC,MAAM;SACV,OAAO,CACN,wFAAwF,CACzF;SACA,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAE3B,uCAAuC;IACvC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACzE,CAAC;AAiBD;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,MAAgB,EAAE,KAAa;IACzD,2CAA2C;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM;SACzB,OAAO,CACN;;;;wBAIkB,CACnB;SACA,GAAG,CAAC,KAAK,CAAC,CAAC;IAEd,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,sDAAsD;IACtD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,MAAM,CAAC,MAAM,IAAI,SAAS;YAAE,MAAM;QAEtC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM;aAC1B,OAAO,CACN;;;;2BAImB,CACpB;aACA,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,iCAAiC;QAEzD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;gBAAE,SAAS;YACxC,IAAI,GAAG,CAAC,QAAQ,GAAG,oBAAoB;gBAAE,SAAS;YAElD,8BAA8B;YAC9B,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1D,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YACjC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAEnB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,iEAAiE;YACjE,IAAI,KAAK,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU;gBAAE,SAAS;YAEpD,MAAM,CAAC,IAAI,CAAC;gBACV,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;gBACnE,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;aACpE,CAAC,CAAC;YAEH,IAAI,MAAM,CAAC,MAAM,IAAI,SAAS;gBAAE,MAAM;QACxC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CACpB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC5C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAIjC,CAAC;QACF,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACzD,OAAO;YACL,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;YACrC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,KAAK;SACvC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAC/B,QAAgB,EAChB,cAA+B,EAC/B,MAAgB,EAChB,KAAa;IAEb,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,SAAS,CAA6B,CAAC;IACzE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,WAAW,CAA+B,CAAC;IAEpE,MAAM,KAAK,GAAG;QACZ,2BAA2B;QAC3B,EAAE;QACF,kBAAkB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG;QAC7C,EAAE;KACH,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,UAAU,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CACR,kBAAkB,CAAC,CAAC,MAAM,CAAC,UAAU,OAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAC5E,CAAC;QACF,KAAK,CAAC,IAAI,CACR,kBAAkB,CAAC,CAAC,MAAM,CAAC,UAAU,OAAO,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAC5E,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,mBAAmB,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IAE7E,eAAe;IACf,IAAI,CAAC;QACH,MAAM,CAAC,MAAM;aACV,OAAO,CACN;sDAC8C,CAC/C;aACA,GAAG,CACF,IAAI,CAAC,GAAG,EAAE,EACV,KAAK,EACL,IAAI,CAAC,SAAS,CAAC,EAAE,oBAAoB,EAAE,cAAc,CAAC,MAAM,EAAE,CAAC,CAChE,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACP,YAAY;IACd,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,MAAc;IACzC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;AACpC,CAAC;AAED,qBAAqB;AACrB,OAAO,EAAE,kBAAkB,IAAI,mBAAmB,EAAE,aAAa,IAAI,cAAc,EAAE,CAAC"}
|
package/dist/cli/export.d.ts
CHANGED
package/dist/cli/export.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,UAAU,CAiDhE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAIvE"}
|
package/dist/cli/export.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { existsSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
4
2
|
import { closeDb, openDb } from '../db/client.js';
|
|
3
|
+
import { resolveCliDbPath } from '../paths.js';
|
|
5
4
|
export function exportCommand(options) {
|
|
6
|
-
const dbPath =
|
|
5
|
+
const dbPath = resolveCliDbPath(options, options.scope);
|
|
7
6
|
if (!existsSync(dbPath)) {
|
|
8
7
|
return {
|
|
9
8
|
scope: options.scope,
|
|
@@ -16,16 +15,16 @@ export function exportCommand(options) {
|
|
|
16
15
|
const bundle = openDb(dbPath, { runMigrations: false });
|
|
17
16
|
try {
|
|
18
17
|
const nodes = bundle.writer
|
|
19
|
-
.prepare(`SELECT * FROM
|
|
18
|
+
.prepare(`SELECT * FROM pinakes_nodes WHERE scope = ?`)
|
|
20
19
|
.all(options.scope);
|
|
21
20
|
const edges = bundle.writer
|
|
22
|
-
.prepare(`SELECT e.* FROM
|
|
23
|
-
JOIN
|
|
21
|
+
.prepare(`SELECT e.* FROM pinakes_edges e
|
|
22
|
+
JOIN pinakes_nodes n ON e.src_id = n.id
|
|
24
23
|
WHERE n.scope = ?`)
|
|
25
24
|
.all(options.scope);
|
|
26
25
|
const chunks = bundle.writer
|
|
27
|
-
.prepare(`SELECT c.* FROM
|
|
28
|
-
JOIN
|
|
26
|
+
.prepare(`SELECT c.* FROM pinakes_chunks c
|
|
27
|
+
JOIN pinakes_nodes n ON c.node_id = n.id
|
|
29
28
|
WHERE n.scope = ?`)
|
|
30
29
|
.all(options.scope);
|
|
31
30
|
const data = {
|
|
@@ -50,24 +49,4 @@ export function renderExport(data, outPath) {
|
|
|
50
49
|
return `${line} → ${outPath}`;
|
|
51
50
|
return line;
|
|
52
51
|
}
|
|
53
|
-
// ----------------------------------------------------------------------------
|
|
54
|
-
// Path helpers
|
|
55
|
-
// ----------------------------------------------------------------------------
|
|
56
|
-
function resolveDbPath(options, scope) {
|
|
57
|
-
if (scope === 'personal') {
|
|
58
|
-
if (options.profileDbPath)
|
|
59
|
-
return resolveAbs(options.profileDbPath);
|
|
60
|
-
const env = process.env.KG_PROFILE_PATH;
|
|
61
|
-
const profileDir = env ? resolveAbs(env) : resolve(homedir(), '.pharos/profile');
|
|
62
|
-
return resolve(profileDir, 'kg.db');
|
|
63
|
-
}
|
|
64
|
-
if (options.dbPath)
|
|
65
|
-
return resolveAbs(options.dbPath);
|
|
66
|
-
if (options.wikiPath)
|
|
67
|
-
return resolve(dirname(resolveAbs(options.wikiPath)), '.pinakes', 'pinakes.db');
|
|
68
|
-
return resolve(process.cwd(), '.pinakes', 'pinakes.db');
|
|
69
|
-
}
|
|
70
|
-
function resolveAbs(p) {
|
|
71
|
-
return isAbsolute(p) ? p : resolve(process.cwd(), p);
|
|
72
|
-
}
|
|
73
52
|
//# sourceMappingURL=export.js.map
|
package/dist/cli/export.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAkC/C,MAAM,UAAU,aAAa,CAAC,OAAsB;IAClD,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAExD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,KAAK,EAAE,EAAE;YACT,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM;aACxB,OAAO,CAAC,6CAA6C,CAAC;aACtD,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtB,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM;aACxB,OAAO,CACN;;2BAEmB,CACpB;aACA,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM;aACzB,OAAO,CACN;;2BAEmB,CACpB;aACA,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAEtB,MAAM,IAAI,GAAe;YACvB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,KAAK;YACL,KAAK;YACL,MAAM;SACP,CAAC;QAEF,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAgB,EAAE,OAAgB;IAC7D,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,KAAM,IAAI,CAAC,KAAmB,CAAC,MAAM,WAAY,IAAI,CAAC,KAAmB,CAAC,MAAM,WAAY,IAAI,CAAC,MAAoB,CAAC,MAAM,SAAS,CAAC;IAChK,IAAI,OAAO;QAAE,OAAO,GAAG,IAAI,MAAM,OAAO,EAAE,CAAC;IAC3C,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/cli/import.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `
|
|
3
|
-
* from a JSON dump produced by `
|
|
2
|
+
* `pinakes import --scope <s> --in file.json` — restore nodes, edges, and chunks
|
|
3
|
+
* from a JSON dump produced by `pinakes export`.
|
|
4
4
|
*
|
|
5
5
|
* Imports are additive: existing rows with the same PK are replaced via
|
|
6
6
|
* INSERT OR REPLACE. This makes import idempotent — running it twice
|
package/dist/cli/import.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/cli/import.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/cli/import.ts"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAaD,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAuFlE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEzD"}
|