@pella-labs/pinakes 0.1.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 +208 -0
- package/dist/cli/audit.d.ts +30 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +49 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/export.d.ts +32 -0
- package/dist/cli/export.d.ts.map +1 -0
- package/dist/cli/export.js +73 -0
- package/dist/cli/export.js.map +1 -0
- package/dist/cli/import.d.ts +24 -0
- package/dist/cli/import.d.ts.map +1 -0
- package/dist/cli/import.js +96 -0
- package/dist/cli/import.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +172 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/purge.d.ts +23 -0
- package/dist/cli/purge.d.ts.map +1 -0
- package/dist/cli/purge.js +57 -0
- package/dist/cli/purge.js.map +1 -0
- package/dist/cli/rebuild.d.ts +54 -0
- package/dist/cli/rebuild.d.ts.map +1 -0
- package/dist/cli/rebuild.js +113 -0
- package/dist/cli/rebuild.js.map +1 -0
- package/dist/cli/serve.d.ts +49 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +296 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/status.d.ts +39 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +108 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/db/client.d.ts +109 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +175 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/repository.d.ts +82 -0
- package/dist/db/repository.d.ts.map +1 -0
- package/dist/db/repository.js +173 -0
- package/dist/db/repository.js.map +1 -0
- package/dist/db/schema.d.ts +990 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +259 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/types.d.ts +28 -0
- package/dist/db/types.d.ts.map +1 -0
- package/dist/db/types.js +11 -0
- package/dist/db/types.js.map +1 -0
- package/dist/gaps/detector.d.ts +67 -0
- package/dist/gaps/detector.d.ts.map +1 -0
- package/dist/gaps/detector.js +160 -0
- package/dist/gaps/detector.js.map +1 -0
- package/dist/gate/budget.d.ts +90 -0
- package/dist/gate/budget.d.ts.map +1 -0
- package/dist/gate/budget.js +145 -0
- package/dist/gate/budget.js.map +1 -0
- package/dist/ingest/chokidar.d.ts +33 -0
- package/dist/ingest/chokidar.d.ts.map +1 -0
- package/dist/ingest/chokidar.js +152 -0
- package/dist/ingest/chokidar.js.map +1 -0
- package/dist/ingest/ingester.d.ts +117 -0
- package/dist/ingest/ingester.d.ts.map +1 -0
- package/dist/ingest/ingester.js +312 -0
- package/dist/ingest/ingester.js.map +1 -0
- package/dist/ingest/manifest.d.ts +87 -0
- package/dist/ingest/manifest.d.ts.map +1 -0
- package/dist/ingest/manifest.js +223 -0
- package/dist/ingest/manifest.js.map +1 -0
- package/dist/ingest/memory-store.d.ts +55 -0
- package/dist/ingest/memory-store.d.ts.map +1 -0
- package/dist/ingest/memory-store.js +94 -0
- package/dist/ingest/memory-store.js.map +1 -0
- package/dist/ingest/parse/chunk.d.ts +15 -0
- package/dist/ingest/parse/chunk.d.ts.map +1 -0
- package/dist/ingest/parse/chunk.js +88 -0
- package/dist/ingest/parse/chunk.js.map +1 -0
- package/dist/ingest/parse/markdown.d.ts +64 -0
- package/dist/ingest/parse/markdown.d.ts.map +1 -0
- package/dist/ingest/parse/markdown.js +152 -0
- package/dist/ingest/parse/markdown.js.map +1 -0
- package/dist/ingest/queue.d.ts +21 -0
- package/dist/ingest/queue.d.ts.map +1 -0
- package/dist/ingest/queue.js +24 -0
- package/dist/ingest/queue.js.map +1 -0
- package/dist/ingest/source.d.ts +42 -0
- package/dist/ingest/source.d.ts.map +1 -0
- package/dist/ingest/source.js +19 -0
- package/dist/ingest/source.js.map +1 -0
- package/dist/mcp/envelope.d.ts +73 -0
- package/dist/mcp/envelope.d.ts.map +1 -0
- package/dist/mcp/envelope.js +46 -0
- package/dist/mcp/envelope.js.map +1 -0
- package/dist/mcp/tools/execute.d.ts +55 -0
- package/dist/mcp/tools/execute.d.ts.map +1 -0
- package/dist/mcp/tools/execute.js +232 -0
- package/dist/mcp/tools/execute.js.map +1 -0
- package/dist/mcp/tools/search.d.ts +53 -0
- package/dist/mcp/tools/search.d.ts.map +1 -0
- package/dist/mcp/tools/search.js +114 -0
- package/dist/mcp/tools/search.js.map +1 -0
- package/dist/observability/audit.d.ts +25 -0
- package/dist/observability/audit.d.ts.map +1 -0
- package/dist/observability/audit.js +38 -0
- package/dist/observability/audit.js.map +1 -0
- package/dist/observability/logger.d.ts +4 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +56 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +38 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +64 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/retrieval/embedder.d.ts +130 -0
- package/dist/retrieval/embedder.d.ts.map +1 -0
- package/dist/retrieval/embedder.js +278 -0
- package/dist/retrieval/embedder.js.map +1 -0
- package/dist/retrieval/fts.d.ts +42 -0
- package/dist/retrieval/fts.d.ts.map +1 -0
- package/dist/retrieval/fts.js +46 -0
- package/dist/retrieval/fts.js.map +1 -0
- package/dist/retrieval/hybrid.d.ts +43 -0
- package/dist/retrieval/hybrid.d.ts.map +1 -0
- package/dist/retrieval/hybrid.js +120 -0
- package/dist/retrieval/hybrid.js.map +1 -0
- package/dist/retrieval/vec.d.ts +39 -0
- package/dist/retrieval/vec.d.ts.map +1 -0
- package/dist/retrieval/vec.js +50 -0
- package/dist/retrieval/vec.js.map +1 -0
- package/dist/sandbox/bindings/budget.d.ts +10 -0
- package/dist/sandbox/bindings/budget.d.ts.map +1 -0
- package/dist/sandbox/bindings/budget.js +44 -0
- package/dist/sandbox/bindings/budget.js.map +1 -0
- package/dist/sandbox/bindings/install.d.ts +23 -0
- package/dist/sandbox/bindings/install.d.ts.map +1 -0
- package/dist/sandbox/bindings/install.js +15 -0
- package/dist/sandbox/bindings/install.js.map +1 -0
- package/dist/sandbox/bindings/kg.d.ts +29 -0
- package/dist/sandbox/bindings/kg.d.ts.map +1 -0
- package/dist/sandbox/bindings/kg.js +323 -0
- package/dist/sandbox/bindings/kg.js.map +1 -0
- package/dist/sandbox/bindings/logger.d.ts +11 -0
- package/dist/sandbox/bindings/logger.d.ts.map +1 -0
- package/dist/sandbox/bindings/logger.js +33 -0
- package/dist/sandbox/bindings/logger.js.map +1 -0
- package/dist/sandbox/bindings/write.d.ts +34 -0
- package/dist/sandbox/bindings/write.d.ts.map +1 -0
- package/dist/sandbox/bindings/write.js +195 -0
- package/dist/sandbox/bindings/write.js.map +1 -0
- package/dist/sandbox/executor.d.ts +68 -0
- package/dist/sandbox/executor.d.ts.map +1 -0
- package/dist/sandbox/executor.js +280 -0
- package/dist/sandbox/executor.js.map +1 -0
- package/dist/sandbox/helpers.d.ts +26 -0
- package/dist/sandbox/helpers.d.ts.map +1 -0
- package/dist/sandbox/helpers.js +131 -0
- package/dist/sandbox/helpers.js.map +1 -0
- package/dist/sandbox/pool.d.ts +63 -0
- package/dist/sandbox/pool.d.ts.map +1 -0
- package/dist/sandbox/pool.js +98 -0
- package/dist/sandbox/pool.js.map +1 -0
- package/dist/sandbox/vendored-codemode.d.ts +99 -0
- package/dist/sandbox/vendored-codemode.d.ts.map +1 -0
- package/dist/sandbox/vendored-codemode.js +471 -0
- package/dist/sandbox/vendored-codemode.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +74 -0
- package/dist/server.js.map +1 -0
- package/dist/spike.d.ts +15 -0
- package/dist/spike.d.ts.map +1 -0
- package/dist/spike.js +90 -0
- package/dist/spike.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { Scope } from 'quickjs-emscripten';
|
|
2
|
+
import { nextReader } from '../../db/client.js';
|
|
3
|
+
import { ftsQuery as ftsQueryImpl } from '../../retrieval/fts.js';
|
|
4
|
+
import { vecQuery as vecQueryImpl } from '../../retrieval/vec.js';
|
|
5
|
+
import { rrfFuse } from '../../retrieval/hybrid.js';
|
|
6
|
+
import { writeWikiFile, appendWikiLog, removeWikiFile } from './write.js';
|
|
7
|
+
import { queryGaps } from '../../gaps/detector.js';
|
|
8
|
+
import { errorMessage, marshalJsValue } from '../helpers.js';
|
|
9
|
+
/**
|
|
10
|
+
* Install the `kg` global with `kg.project.*` and/or `kg.personal.*`
|
|
11
|
+
* bindings plus backward-compat `kg.search()` / `kg.get()` aliases
|
|
12
|
+
* and `kg.describe()`.
|
|
13
|
+
*
|
|
14
|
+
* **Privacy invariant**: if `personalDeps` is undefined, `kg.personal`
|
|
15
|
+
* does NOT exist in the sandbox — not undefined, not null, simply absent.
|
|
16
|
+
* This is enforced at the dispatcher level (tool handler decides which
|
|
17
|
+
* deps to pass). The 15-test adversarial suite verifies this.
|
|
18
|
+
*/
|
|
19
|
+
export function installKgBindings(context, projectDeps, personalDeps) {
|
|
20
|
+
Scope.withScope((s) => {
|
|
21
|
+
const kgObj = s.manage(context.newObject());
|
|
22
|
+
// Install project namespace if deps provided
|
|
23
|
+
if (projectDeps) {
|
|
24
|
+
const projectObj = s.manage(context.newObject());
|
|
25
|
+
installScopeBindings(context, s, projectObj, projectDeps);
|
|
26
|
+
context.setProp(kgObj, 'project', projectObj);
|
|
27
|
+
// Backward-compat aliases route to project scope
|
|
28
|
+
installBackwardCompat(context, kgObj, projectDeps);
|
|
29
|
+
}
|
|
30
|
+
// Install personal namespace if deps provided (privacy invariant)
|
|
31
|
+
if (personalDeps) {
|
|
32
|
+
const personalObj = s.manage(context.newObject());
|
|
33
|
+
installScopeBindings(context, s, personalObj, personalDeps);
|
|
34
|
+
context.setProp(kgObj, 'personal', personalObj);
|
|
35
|
+
}
|
|
36
|
+
// kg.describe() — returns metadata for available scopes only
|
|
37
|
+
attachFn(context, kgObj, 'describe', () => {
|
|
38
|
+
const result = {};
|
|
39
|
+
if (projectDeps) {
|
|
40
|
+
result.project = describeScope(projectDeps);
|
|
41
|
+
}
|
|
42
|
+
if (personalDeps) {
|
|
43
|
+
result.personal = describeScope(personalDeps);
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
});
|
|
47
|
+
context.setProp(context.global, 'kg', kgObj);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Install all bindings for one scope onto a QuickJS object.
|
|
52
|
+
* Called once for project, once for personal (if both are requested).
|
|
53
|
+
*/
|
|
54
|
+
function installScopeBindings(context, s, scopeObj, deps) {
|
|
55
|
+
const { bundle, scope } = deps;
|
|
56
|
+
const reader = nextReader(bundle);
|
|
57
|
+
const logObj = s.manage(context.newObject());
|
|
58
|
+
// -- fts(query, opts?) -------------------------------------------------
|
|
59
|
+
attachFn(context, scopeObj, 'fts', (args) => {
|
|
60
|
+
const query = args[0];
|
|
61
|
+
if (typeof query !== 'string' || !query.trim())
|
|
62
|
+
return [];
|
|
63
|
+
const opts = (args[1] ?? {});
|
|
64
|
+
const limit = Math.min(Math.max(opts.limit ?? 20, 1), 100);
|
|
65
|
+
return ftsQueryImpl(reader, scope, query, limit);
|
|
66
|
+
});
|
|
67
|
+
// -- vec(query, opts?) -------------------------------------------------
|
|
68
|
+
attachFn(context, scopeObj, 'vec', (args) => {
|
|
69
|
+
const query = args[0];
|
|
70
|
+
if (typeof query !== 'string' || !query.trim())
|
|
71
|
+
return [];
|
|
72
|
+
const opts = (args[1] ?? {});
|
|
73
|
+
const limit = Math.min(Math.max(opts.limit ?? 20, 1), 100);
|
|
74
|
+
const cached = deps.queryEmbeddings?.get(query);
|
|
75
|
+
if (!cached)
|
|
76
|
+
return [];
|
|
77
|
+
return vecQueryImpl(reader, scope, cached, limit);
|
|
78
|
+
});
|
|
79
|
+
// -- hybrid(query, opts?) ----------------------------------------------
|
|
80
|
+
attachFn(context, scopeObj, 'hybrid', (args) => {
|
|
81
|
+
const query = args[0];
|
|
82
|
+
if (typeof query !== 'string' || !query.trim())
|
|
83
|
+
return [];
|
|
84
|
+
const opts = (args[1] ?? {});
|
|
85
|
+
const limit = Math.min(Math.max(opts.limit ?? 20, 1), 100);
|
|
86
|
+
const rrfK = opts.rrf_k ?? 60;
|
|
87
|
+
const fetchLimit = Math.min(limit * 2, 100);
|
|
88
|
+
const ftsResults = ftsQueryImpl(reader, scope, query, fetchLimit);
|
|
89
|
+
const cached = deps.queryEmbeddings?.get(query);
|
|
90
|
+
const vecResults = cached
|
|
91
|
+
? vecQueryImpl(reader, scope, cached, fetchLimit)
|
|
92
|
+
: [];
|
|
93
|
+
return rrfFuse(ftsResults, vecResults, rrfK, limit);
|
|
94
|
+
});
|
|
95
|
+
// -- get(id) -----------------------------------------------------------
|
|
96
|
+
attachFn(context, scopeObj, 'get', (args) => {
|
|
97
|
+
const id = args[0];
|
|
98
|
+
if (typeof id !== 'string')
|
|
99
|
+
return null;
|
|
100
|
+
return nodeGet(reader, scope, id);
|
|
101
|
+
});
|
|
102
|
+
// -- index(opts?) — Phase 7.5: browsable table of contents ---------------
|
|
103
|
+
attachFn(context, scopeObj, 'index', (args) => {
|
|
104
|
+
const opts = (args[0] ?? {});
|
|
105
|
+
const limit = Math.min(Math.max(opts.limit ?? 500, 1), 2000);
|
|
106
|
+
return indexQuery(reader, scope, limit, opts.kind, opts.source_uri);
|
|
107
|
+
});
|
|
108
|
+
// -- neighbors(id, opts?) ----------------------------------------------
|
|
109
|
+
attachFn(context, scopeObj, 'neighbors', (args) => {
|
|
110
|
+
const id = args[0];
|
|
111
|
+
if (typeof id !== 'string')
|
|
112
|
+
return [];
|
|
113
|
+
const opts = (args[1] ?? {});
|
|
114
|
+
const depth = Math.min(Math.max(opts.depth ?? 1, 1), 3);
|
|
115
|
+
return neighborsQuery(reader, scope, id, depth, opts.edge_kinds);
|
|
116
|
+
});
|
|
117
|
+
// -- log.recent(n?, opts?) ---------------------------------------------
|
|
118
|
+
attachFn(context, logObj, 'recent', (args) => {
|
|
119
|
+
const n = typeof args[0] === 'number' ? Math.min(Math.max(args[0], 1), 100) : 20;
|
|
120
|
+
const opts = (args[1] ?? {});
|
|
121
|
+
return logRecent(reader, scope, n, opts.kind);
|
|
122
|
+
});
|
|
123
|
+
// -- gaps(opts?) — Phase 6: query kg_gaps for concept gaps ---------------
|
|
124
|
+
attachFn(context, scopeObj, 'gaps', (args) => {
|
|
125
|
+
const opts = (args[0] ?? {});
|
|
126
|
+
return queryGaps(reader, scope, opts);
|
|
127
|
+
});
|
|
128
|
+
// -- write(path, content) ----------------------------------------------
|
|
129
|
+
attachThrowingFn(context, scopeObj, 'write', (args) => {
|
|
130
|
+
if (!deps.wikiRoot || !deps.writeCounter) {
|
|
131
|
+
throw new Error('write bindings not available (no wikiRoot configured)');
|
|
132
|
+
}
|
|
133
|
+
const path = args[0];
|
|
134
|
+
const content = args[1];
|
|
135
|
+
if (typeof path !== 'string')
|
|
136
|
+
throw new Error('write: path must be a string');
|
|
137
|
+
if (typeof content !== 'string')
|
|
138
|
+
throw new Error('write: content must be a string');
|
|
139
|
+
return writeWikiFile(deps.wikiRoot, path, content, deps.writeCounter, scope, bundle.writer);
|
|
140
|
+
});
|
|
141
|
+
// -- append(entry) -----------------------------------------------------
|
|
142
|
+
attachThrowingFn(context, scopeObj, 'append', (args) => {
|
|
143
|
+
if (!deps.wikiRoot || !deps.writeCounter) {
|
|
144
|
+
throw new Error('append bindings not available (no wikiRoot configured)');
|
|
145
|
+
}
|
|
146
|
+
const entry = args[0];
|
|
147
|
+
if (typeof entry !== 'string')
|
|
148
|
+
throw new Error('append: entry must be a string');
|
|
149
|
+
return appendWikiLog(deps.wikiRoot, entry, deps.writeCounter, scope, bundle.writer);
|
|
150
|
+
});
|
|
151
|
+
// -- remove(path) ------------------------------------------------------
|
|
152
|
+
attachThrowingFn(context, scopeObj, 'remove', (args) => {
|
|
153
|
+
if (!deps.wikiRoot || !deps.writeCounter) {
|
|
154
|
+
throw new Error('remove bindings not available (no wikiRoot configured)');
|
|
155
|
+
}
|
|
156
|
+
const path = args[0];
|
|
157
|
+
if (typeof path !== 'string')
|
|
158
|
+
throw new Error('remove: path must be a string');
|
|
159
|
+
return removeWikiFile(deps.wikiRoot, path, deps.writeCounter, scope, bundle.writer);
|
|
160
|
+
});
|
|
161
|
+
// Wire nesting: scope.log
|
|
162
|
+
context.setProp(scopeObj, 'log', logObj);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Install backward-compat `kg.search()` and `kg.get()` aliases.
|
|
166
|
+
* Always routes to the project scope.
|
|
167
|
+
*/
|
|
168
|
+
function installBackwardCompat(context, kgObj, deps) {
|
|
169
|
+
const { repository, scope } = deps;
|
|
170
|
+
attachFn(context, kgObj, 'search', (args) => {
|
|
171
|
+
const query = args[0];
|
|
172
|
+
if (typeof query !== 'string')
|
|
173
|
+
return [];
|
|
174
|
+
return repository.search(query, scope).map((c) => ({
|
|
175
|
+
id: c.id,
|
|
176
|
+
text: c.text,
|
|
177
|
+
source_uri: c.source_uri,
|
|
178
|
+
}));
|
|
179
|
+
});
|
|
180
|
+
attachFn(context, kgObj, 'get', (args) => {
|
|
181
|
+
const id = args[0];
|
|
182
|
+
if (typeof id !== 'string')
|
|
183
|
+
return null;
|
|
184
|
+
const c = repository.get(id, scope);
|
|
185
|
+
if (!c)
|
|
186
|
+
return null;
|
|
187
|
+
return { id: c.id, text: c.text, source_uri: c.source_uri };
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Return summary metadata for a scope (no content, just counts).
|
|
192
|
+
*/
|
|
193
|
+
function describeScope(deps) {
|
|
194
|
+
const reader = nextReader(deps.bundle);
|
|
195
|
+
const chunks = reader
|
|
196
|
+
.prepare(`SELECT count(*) AS c FROM kg_chunks ch JOIN kg_nodes n ON ch.node_id = n.id WHERE n.scope = ?`)
|
|
197
|
+
.get(deps.scope)?.c ?? 0;
|
|
198
|
+
const nodes = reader
|
|
199
|
+
.prepare(`SELECT count(*) AS c FROM kg_nodes WHERE scope = ?`)
|
|
200
|
+
.get(deps.scope)?.c ?? 0;
|
|
201
|
+
return { chunks, nodes };
|
|
202
|
+
}
|
|
203
|
+
// ============================================================================
|
|
204
|
+
// SQL query implementations
|
|
205
|
+
// ============================================================================
|
|
206
|
+
function nodeGet(reader, scope, id) {
|
|
207
|
+
const row = reader
|
|
208
|
+
.prepare(`SELECT id, source_uri, section_path, kind, title, content, token_count, confidence
|
|
209
|
+
FROM kg_nodes
|
|
210
|
+
WHERE id = ? AND scope = ?
|
|
211
|
+
LIMIT 1`)
|
|
212
|
+
.get(id, scope);
|
|
213
|
+
return row ?? null;
|
|
214
|
+
}
|
|
215
|
+
function indexQuery(reader, scope, limit, kind, sourceUri) {
|
|
216
|
+
let sql = `SELECT id, title, source_uri, section_path, kind, token_count
|
|
217
|
+
FROM kg_nodes
|
|
218
|
+
WHERE scope = ?`;
|
|
219
|
+
const params = [scope];
|
|
220
|
+
if (kind) {
|
|
221
|
+
sql += ` AND kind = ?`;
|
|
222
|
+
params.push(kind);
|
|
223
|
+
}
|
|
224
|
+
if (sourceUri) {
|
|
225
|
+
sql += ` AND source_uri = ?`;
|
|
226
|
+
params.push(sourceUri);
|
|
227
|
+
}
|
|
228
|
+
sql += ` ORDER BY source_uri, section_path LIMIT ?`;
|
|
229
|
+
params.push(limit);
|
|
230
|
+
return reader.prepare(sql).all(...params);
|
|
231
|
+
}
|
|
232
|
+
function neighborsQuery(reader, scope, id, maxDepth, edgeKinds) {
|
|
233
|
+
let edgeFilter = '';
|
|
234
|
+
const params = [id, maxDepth];
|
|
235
|
+
if (edgeKinds && edgeKinds.length > 0) {
|
|
236
|
+
const placeholders = edgeKinds.map(() => '?').join(',');
|
|
237
|
+
edgeFilter = `AND e.edge_kind IN (${placeholders})`;
|
|
238
|
+
params.push(...edgeKinds);
|
|
239
|
+
}
|
|
240
|
+
params.push(id, scope);
|
|
241
|
+
const sql = `
|
|
242
|
+
WITH RECURSIVE hops(node_id, depth) AS (
|
|
243
|
+
VALUES(?, 0)
|
|
244
|
+
UNION ALL
|
|
245
|
+
SELECT e.dst_id, h.depth + 1
|
|
246
|
+
FROM hops h
|
|
247
|
+
JOIN kg_edges e ON e.src_id = h.node_id
|
|
248
|
+
WHERE h.depth < ? ${edgeFilter}
|
|
249
|
+
)
|
|
250
|
+
SELECT DISTINCT n.id, n.source_uri, n.section_path, n.kind, n.title, h.depth
|
|
251
|
+
FROM hops h
|
|
252
|
+
JOIN kg_nodes n ON n.id = h.node_id
|
|
253
|
+
WHERE n.id != ? AND n.scope = ?`;
|
|
254
|
+
return reader.prepare(sql).all(...params);
|
|
255
|
+
}
|
|
256
|
+
function logRecent(reader, scope, n, kind) {
|
|
257
|
+
let sql;
|
|
258
|
+
let params;
|
|
259
|
+
if (kind) {
|
|
260
|
+
sql = `SELECT id, ts, kind, source_uri, payload
|
|
261
|
+
FROM kg_log
|
|
262
|
+
WHERE scope = ? AND kind = ?
|
|
263
|
+
ORDER BY ts DESC
|
|
264
|
+
LIMIT ?`;
|
|
265
|
+
params = [scope, kind, n];
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
sql = `SELECT id, ts, kind, source_uri, payload
|
|
269
|
+
FROM kg_log
|
|
270
|
+
WHERE scope = ?
|
|
271
|
+
ORDER BY ts DESC
|
|
272
|
+
LIMIT ?`;
|
|
273
|
+
params = [scope, n];
|
|
274
|
+
}
|
|
275
|
+
const rows = reader.prepare(sql).all(...params);
|
|
276
|
+
return rows.map((r) => ({
|
|
277
|
+
id: r.id,
|
|
278
|
+
ts: r.ts,
|
|
279
|
+
kind: r.kind,
|
|
280
|
+
source_uri: r.source_uri,
|
|
281
|
+
payload: r.payload ? tryParseJson(r.payload) : null,
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
// ============================================================================
|
|
285
|
+
// Helpers
|
|
286
|
+
// ============================================================================
|
|
287
|
+
function tryParseJson(s) {
|
|
288
|
+
try {
|
|
289
|
+
return JSON.parse(s);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return s;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function attachFn(context, obj, name, impl) {
|
|
296
|
+
const fn = context.newFunction(name, (...handles) => {
|
|
297
|
+
try {
|
|
298
|
+
const nativeArgs = handles.map((h) => context.dump(h));
|
|
299
|
+
const result = impl(nativeArgs);
|
|
300
|
+
return marshalJsValue(context, result);
|
|
301
|
+
}
|
|
302
|
+
catch (e) {
|
|
303
|
+
return context.newError(errorMessage(e));
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
context.setProp(obj, name, fn);
|
|
307
|
+
fn.dispose();
|
|
308
|
+
}
|
|
309
|
+
function attachThrowingFn(context, obj, name, impl) {
|
|
310
|
+
const fn = context.newFunction(name, (...handles) => {
|
|
311
|
+
try {
|
|
312
|
+
const nativeArgs = handles.map((h) => context.dump(h));
|
|
313
|
+
const result = impl(nativeArgs);
|
|
314
|
+
return marshalJsValue(context, result);
|
|
315
|
+
}
|
|
316
|
+
catch (e) {
|
|
317
|
+
return { error: context.newError(errorMessage(e)) };
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
context.setProp(obj, name, fn);
|
|
321
|
+
fn.dispose();
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=kg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kg.js","sourceRoot":"","sources":["../../../src/sandbox/bindings/kg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type QuickJSContext } from 'quickjs-emscripten';
|
|
2
|
+
/**
|
|
3
|
+
* Install `logger.log(...)` capture on a QuickJS context.
|
|
4
|
+
*
|
|
5
|
+
* Every call to `logger.log(arg1, arg2, ...)` inside the guest appends a
|
|
6
|
+
* single string to `logs`. Arguments are dumped from QuickJS handles and
|
|
7
|
+
* joined with spaces — strings pass through as-is, everything else is
|
|
8
|
+
* JSON-stringified.
|
|
9
|
+
*/
|
|
10
|
+
export declare function installLogger(context: QuickJSContext, logs: string[]): void;
|
|
11
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/sandbox/bindings/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AAGpF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAsB3E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Scope } from 'quickjs-emscripten';
|
|
2
|
+
import { errorMessage } from '../helpers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Install `logger.log(...)` capture on a QuickJS context.
|
|
5
|
+
*
|
|
6
|
+
* Every call to `logger.log(arg1, arg2, ...)` inside the guest appends a
|
|
7
|
+
* single string to `logs`. Arguments are dumped from QuickJS handles and
|
|
8
|
+
* joined with spaces — strings pass through as-is, everything else is
|
|
9
|
+
* JSON-stringified.
|
|
10
|
+
*/
|
|
11
|
+
export function installLogger(context, logs) {
|
|
12
|
+
Scope.withScope((scope) => {
|
|
13
|
+
const loggerObj = scope.manage(context.newObject());
|
|
14
|
+
const logFn = context.newFunction('log', (...argsHandles) => {
|
|
15
|
+
try {
|
|
16
|
+
const parts = [];
|
|
17
|
+
for (const h of argsHandles) {
|
|
18
|
+
const dumped = context.dump(h);
|
|
19
|
+
parts.push(typeof dumped === 'string' ? dumped : JSON.stringify(dumped));
|
|
20
|
+
}
|
|
21
|
+
logs.push(parts.join(' '));
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
logs.push(`<logger.log serialization error: ${errorMessage(e)}>`);
|
|
25
|
+
}
|
|
26
|
+
return context.undefined;
|
|
27
|
+
});
|
|
28
|
+
context.setProp(loggerObj, 'log', logFn);
|
|
29
|
+
logFn.dispose();
|
|
30
|
+
context.setProp(context.global, 'logger', loggerObj);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/sandbox/bindings/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA2C,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,OAAuB,EAAE,IAAc;IACnE,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;QACxB,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAEpD,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,GAAG,WAA4B,EAAE,EAAE;YAC3E,IAAI,CAAC;gBACH,MAAM,KAAK,GAAa,EAAE,CAAC;gBAC3B,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;oBAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAC/B,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC3E,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CAAC,oCAAoC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACpE,CAAC;YACD,OAAO,OAAO,CAAC,SAAS,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACzC,KAAK,CAAC,OAAO,EAAE,CAAC;QAEhB,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Database as BetterSqliteDatabase } from 'better-sqlite3';
|
|
2
|
+
/** Mutable counter shared across all write operations in a single kg_execute call. */
|
|
3
|
+
export interface WriteCounter {
|
|
4
|
+
value: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Create or overwrite a wiki page. Atomic write via tmp + rename.
|
|
8
|
+
*
|
|
9
|
+
* @returns `{ path: string, bytes: number }` — the relative path and byte count.
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeWikiFile(wikiRoot: string, rawPath: string, content: string, counter: WriteCounter, scope: string, writer: BetterSqliteDatabase): {
|
|
12
|
+
path: string;
|
|
13
|
+
bytes: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Append a timestamped entry to `<wikiRoot>/log.md`.
|
|
17
|
+
*
|
|
18
|
+
* @returns `{ path: string, bytes: number }` — always `log.md`.
|
|
19
|
+
*/
|
|
20
|
+
export declare function appendWikiLog(wikiRoot: string, entry: string, counter: WriteCounter, scope: string, writer: BetterSqliteDatabase): {
|
|
21
|
+
path: string;
|
|
22
|
+
bytes: number;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Remove a wiki page from disk. Chokidar `unlink` event triggers
|
|
26
|
+
* ingester removal of the corresponding nodes/chunks.
|
|
27
|
+
*
|
|
28
|
+
* @returns `{ path: string, removed: true }`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function removeWikiFile(wikiRoot: string, rawPath: string, counter: WriteCounter, scope: string, writer: BetterSqliteDatabase): {
|
|
31
|
+
path: string;
|
|
32
|
+
removed: true;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/sandbox/bindings/write.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAsBvE,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf;AAmGD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,oBAAoB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAqCjC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,oBAAoB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA2CjC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,oBAAoB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAgBjC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, normalize, resolve, sep } from 'node:path';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { logger } from '../../observability/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Write-path bindings for `kg.project.write()`, `kg.project.append()`,
|
|
8
|
+
* and `kg.project.remove()` (CLAUDE.md §Architecture #6, presearch D35).
|
|
9
|
+
*
|
|
10
|
+
* **Write contract**:
|
|
11
|
+
* 1. Path containment: resolved path must start with `wikiRoot`
|
|
12
|
+
* 2. Extension: only `.md` files
|
|
13
|
+
* 3. Size: max `KG_MAX_WRITE_SIZE` bytes (default 100KB)
|
|
14
|
+
* 4. Rate: max 20 writes per `kg_execute` call
|
|
15
|
+
* 5. Atomic: tmp file + rename (never half-written files)
|
|
16
|
+
* 6. Audit: every write appends to `kg_log`
|
|
17
|
+
*
|
|
18
|
+
* Chokidar picks up the written file and triggers re-indexing automatically.
|
|
19
|
+
*/
|
|
20
|
+
const MAX_WRITE_SIZE = parseInt(process.env['KG_MAX_WRITE_SIZE'] ?? '102400', 10);
|
|
21
|
+
const MAX_WRITES_PER_CALL = 20;
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Path sanitization
|
|
24
|
+
// ============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Sanitize and resolve a user-provided path against the wiki root.
|
|
27
|
+
* Throws if the path escapes the wiki root or violates constraints.
|
|
28
|
+
*/
|
|
29
|
+
function sanitizePath(wikiRoot, rawPath) {
|
|
30
|
+
if (!rawPath || typeof rawPath !== 'string') {
|
|
31
|
+
throw new Error('path is required and must be a non-empty string');
|
|
32
|
+
}
|
|
33
|
+
// Reject absolute paths
|
|
34
|
+
if (isAbsolute(rawPath)) {
|
|
35
|
+
throw new Error(`absolute paths are not allowed: ${rawPath}`);
|
|
36
|
+
}
|
|
37
|
+
// Normalize and check for .. traversal
|
|
38
|
+
const normalized = normalize(rawPath);
|
|
39
|
+
const parts = normalized.split(sep);
|
|
40
|
+
if (parts.some((p) => p === '..')) {
|
|
41
|
+
throw new Error(`path traversal (..) is not allowed: ${rawPath}`);
|
|
42
|
+
}
|
|
43
|
+
// Ensure .md extension
|
|
44
|
+
if (!normalized.endsWith('.md')) {
|
|
45
|
+
throw new Error(`only .md files can be written (got: ${rawPath})`);
|
|
46
|
+
}
|
|
47
|
+
// Resolve against wiki root
|
|
48
|
+
const resolved = resolve(wikiRoot, normalized);
|
|
49
|
+
// Containment check: resolved path must start with wikiRoot
|
|
50
|
+
if (!resolved.startsWith(wikiRoot + sep) && resolved !== wikiRoot) {
|
|
51
|
+
throw new Error(`path escapes wiki root: ${rawPath}`);
|
|
52
|
+
}
|
|
53
|
+
// Symlink check: if the target already exists, verify its real path
|
|
54
|
+
if (existsSync(resolved)) {
|
|
55
|
+
try {
|
|
56
|
+
const stat = lstatSync(resolved);
|
|
57
|
+
if (stat.isSymbolicLink()) {
|
|
58
|
+
const real = realpathSync(resolved);
|
|
59
|
+
if (!real.startsWith(wikiRoot + sep) && real !== wikiRoot) {
|
|
60
|
+
throw new Error(`symlink escapes wiki root: ${rawPath} → ${real}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
if (e.message.includes('escapes wiki root'))
|
|
66
|
+
throw e;
|
|
67
|
+
// lstat errors on non-existent files are fine
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return resolved;
|
|
71
|
+
}
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Rate limiting
|
|
74
|
+
// ============================================================================
|
|
75
|
+
function checkRateLimit(counter) {
|
|
76
|
+
counter.value++;
|
|
77
|
+
if (counter.value > MAX_WRITES_PER_CALL) {
|
|
78
|
+
throw new Error(`write rate limit exceeded: max ${MAX_WRITES_PER_CALL} writes per kg_execute call (attempted #${counter.value})`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Audit logging
|
|
83
|
+
// ============================================================================
|
|
84
|
+
function auditLog(writer, scope, kind, filePath, payload) {
|
|
85
|
+
try {
|
|
86
|
+
writer
|
|
87
|
+
.prepare(`INSERT INTO kg_log (ts, scope, kind, source_uri, payload)
|
|
88
|
+
VALUES (?, ?, ?, ?, ?)`)
|
|
89
|
+
.run(Date.now(), scope, kind, pathToFileURL(filePath).href, JSON.stringify(payload));
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
logger.warn({ err, kind, filePath }, 'failed to append write audit to kg_log');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// ============================================================================
|
|
96
|
+
// Write operations
|
|
97
|
+
// ============================================================================
|
|
98
|
+
/**
|
|
99
|
+
* Create or overwrite a wiki page. Atomic write via tmp + rename.
|
|
100
|
+
*
|
|
101
|
+
* @returns `{ path: string, bytes: number }` — the relative path and byte count.
|
|
102
|
+
*/
|
|
103
|
+
export function writeWikiFile(wikiRoot, rawPath, content, counter, scope, writer) {
|
|
104
|
+
checkRateLimit(counter);
|
|
105
|
+
const resolved = sanitizePath(wikiRoot, rawPath);
|
|
106
|
+
const bytes = Buffer.byteLength(content, 'utf-8');
|
|
107
|
+
if (bytes > MAX_WRITE_SIZE) {
|
|
108
|
+
throw new Error(`content exceeds max write size: ${bytes} bytes > ${MAX_WRITE_SIZE} bytes`);
|
|
109
|
+
}
|
|
110
|
+
// Ensure parent directory exists
|
|
111
|
+
const dir = dirname(resolved);
|
|
112
|
+
if (!existsSync(dir)) {
|
|
113
|
+
mkdirSync(dir, { recursive: true });
|
|
114
|
+
}
|
|
115
|
+
// Atomic write: write to tmp file, then rename
|
|
116
|
+
const tmpPath = `${resolved}.tmp.${randomBytes(4).toString('hex')}`;
|
|
117
|
+
try {
|
|
118
|
+
writeFileSync(tmpPath, content, 'utf-8');
|
|
119
|
+
renameSync(tmpPath, resolved);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
// Clean up tmp file if rename failed
|
|
123
|
+
try {
|
|
124
|
+
if (existsSync(tmpPath))
|
|
125
|
+
unlinkSync(tmpPath);
|
|
126
|
+
}
|
|
127
|
+
catch { /* best effort */ }
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
// Relative path for the response
|
|
131
|
+
const relativePath = resolved.slice(wikiRoot.length + 1);
|
|
132
|
+
auditLog(writer, scope, 'write', resolved, { bytes, relativePath });
|
|
133
|
+
return { path: relativePath, bytes };
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Append a timestamped entry to `<wikiRoot>/log.md`.
|
|
137
|
+
*
|
|
138
|
+
* @returns `{ path: string, bytes: number }` — always `log.md`.
|
|
139
|
+
*/
|
|
140
|
+
export function appendWikiLog(wikiRoot, entry, counter, scope, writer) {
|
|
141
|
+
checkRateLimit(counter);
|
|
142
|
+
if (!entry || typeof entry !== 'string') {
|
|
143
|
+
throw new Error('entry is required and must be a non-empty string');
|
|
144
|
+
}
|
|
145
|
+
const logPath = resolve(wikiRoot, 'log.md');
|
|
146
|
+
const timestamp = new Date().toISOString();
|
|
147
|
+
const line = `- ${timestamp}: ${entry}\n`;
|
|
148
|
+
const lineBytes = Buffer.byteLength(line, 'utf-8');
|
|
149
|
+
if (lineBytes > MAX_WRITE_SIZE) {
|
|
150
|
+
throw new Error(`entry exceeds max write size: ${lineBytes} bytes > ${MAX_WRITE_SIZE} bytes`);
|
|
151
|
+
}
|
|
152
|
+
// Read existing content (may not exist yet)
|
|
153
|
+
let existing = '';
|
|
154
|
+
if (existsSync(logPath)) {
|
|
155
|
+
existing = readFileSync(logPath, 'utf-8');
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
existing = '# Turn log\n\n';
|
|
159
|
+
}
|
|
160
|
+
const newContent = existing + line;
|
|
161
|
+
// Atomic write
|
|
162
|
+
const tmpPath = `${logPath}.tmp.${randomBytes(4).toString('hex')}`;
|
|
163
|
+
try {
|
|
164
|
+
writeFileSync(tmpPath, newContent, 'utf-8');
|
|
165
|
+
renameSync(tmpPath, logPath);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
try {
|
|
169
|
+
if (existsSync(tmpPath))
|
|
170
|
+
unlinkSync(tmpPath);
|
|
171
|
+
}
|
|
172
|
+
catch { /* best effort */ }
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
auditLog(writer, scope, 'append', logPath, { entry, bytes: lineBytes });
|
|
176
|
+
return { path: 'log.md', bytes: lineBytes };
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Remove a wiki page from disk. Chokidar `unlink` event triggers
|
|
180
|
+
* ingester removal of the corresponding nodes/chunks.
|
|
181
|
+
*
|
|
182
|
+
* @returns `{ path: string, removed: true }`.
|
|
183
|
+
*/
|
|
184
|
+
export function removeWikiFile(wikiRoot, rawPath, counter, scope, writer) {
|
|
185
|
+
checkRateLimit(counter);
|
|
186
|
+
const resolved = sanitizePath(wikiRoot, rawPath);
|
|
187
|
+
if (!existsSync(resolved)) {
|
|
188
|
+
throw new Error(`file does not exist: ${rawPath}`);
|
|
189
|
+
}
|
|
190
|
+
const relativePath = resolved.slice(wikiRoot.length + 1);
|
|
191
|
+
unlinkSync(resolved);
|
|
192
|
+
auditLog(writer, scope, 'remove', resolved, { relativePath });
|
|
193
|
+
return { path: relativePath, removed: true };
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/sandbox/bindings/write.ts"],"names":[],"mappings":"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"}
|