@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,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool response envelope.
|
|
3
|
+
*
|
|
4
|
+
* CLAUDE.md §API Rules #5 — the envelope is immutable. Adding a field
|
|
5
|
+
* requires updating this file and regenerating the tool schemas. The LLM
|
|
6
|
+
* consumer parses this shape, so drift here breaks prompts in the wild.
|
|
7
|
+
*/
|
|
8
|
+
export type Scope = 'project' | 'personal' | 'both';
|
|
9
|
+
export interface EnvelopeMeta {
|
|
10
|
+
/** User-requested `max_tokens` (default 5000, max 20000). */
|
|
11
|
+
tokens_budgeted: number;
|
|
12
|
+
/** Actual token count of the final serialized response body. */
|
|
13
|
+
tokens_used: number;
|
|
14
|
+
/** True if the budget gate truncated results or emitted a sentinel. */
|
|
15
|
+
results_truncated: boolean;
|
|
16
|
+
/** Scope this call ran against. */
|
|
17
|
+
scope: Scope;
|
|
18
|
+
/** Wall-clock time from tool entry to envelope build. */
|
|
19
|
+
query_time_ms: number;
|
|
20
|
+
/**
|
|
21
|
+
* Files whose on-disk `source_sha` no longer matches the indexed copy.
|
|
22
|
+
* Always empty in Phase 1 (in-memory store, no staleness concept).
|
|
23
|
+
* Phase 2+ populates this after the staleness check.
|
|
24
|
+
*/
|
|
25
|
+
stale_files: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The canonical response wrapper for both `kg_search` and `kg_execute`.
|
|
29
|
+
*
|
|
30
|
+
* `result` is the tool-specific payload. `meta` is always present and
|
|
31
|
+
* always has every field populated. `logs` is optional — present when the
|
|
32
|
+
* tool invoked `logger.log()` inside the sandbox, or when ingestion emitted
|
|
33
|
+
* warnings worth surfacing.
|
|
34
|
+
*
|
|
35
|
+
* Errors go inside `result` (e.g. `{ result: { error: "..." } }`) rather
|
|
36
|
+
* than being thrown or marked with `isError: true`, per CLAUDE.md
|
|
37
|
+
* §API Rules #8 — Claude Code has a bug where protocol-level errors display
|
|
38
|
+
* as "Error: undefined", and stuffing the error into the payload is the
|
|
39
|
+
* only way to keep it visible.
|
|
40
|
+
*/
|
|
41
|
+
export interface Envelope<T> {
|
|
42
|
+
result: T;
|
|
43
|
+
meta: EnvelopeMeta;
|
|
44
|
+
logs?: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Build an envelope from its parts. Kept as a helper so the field order is
|
|
48
|
+
* stable (JSON stringification cares) and so the caller cannot forget a
|
|
49
|
+
* required meta field.
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildEnvelope<T>(params: {
|
|
52
|
+
result: T;
|
|
53
|
+
tokensBudgeted: number;
|
|
54
|
+
tokensUsed: number;
|
|
55
|
+
resultsTruncated: boolean;
|
|
56
|
+
scope: Scope;
|
|
57
|
+
queryTimeMs: number;
|
|
58
|
+
staleFiles?: string[];
|
|
59
|
+
logs?: string[];
|
|
60
|
+
}): Envelope<T>;
|
|
61
|
+
/**
|
|
62
|
+
* Helper for measuring query wall-clock time. Captures a start timestamp
|
|
63
|
+
* on construction and returns the elapsed ms when `end()` is called. Using
|
|
64
|
+
* `performance.now()` instead of `Date.now()` for sub-ms resolution — the
|
|
65
|
+
* cold-start benchmark gate in Phase 1 tests #6 is measuring p50 at the
|
|
66
|
+
* 100ms scale, so millisecond precision matters.
|
|
67
|
+
*/
|
|
68
|
+
export declare class QueryTimer {
|
|
69
|
+
private readonly startMs;
|
|
70
|
+
constructor();
|
|
71
|
+
end(): number;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/mcp/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,eAAe,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,iBAAiB,EAAE,OAAO,CAAC;IAC3B,mCAAmC;IACnC,KAAK,EAAE,KAAK,CAAC;IACb,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,MAAM,EAAE,CAAC,CAAC;IACV,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE;IACvC,MAAM,EAAE,CAAC,CAAC;IACV,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAgBd;AAED;;;;;;GAMG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;;IAMjC,GAAG,IAAI,MAAM;CAGd"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool response envelope.
|
|
3
|
+
*
|
|
4
|
+
* CLAUDE.md §API Rules #5 — the envelope is immutable. Adding a field
|
|
5
|
+
* requires updating this file and regenerating the tool schemas. The LLM
|
|
6
|
+
* consumer parses this shape, so drift here breaks prompts in the wild.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Build an envelope from its parts. Kept as a helper so the field order is
|
|
10
|
+
* stable (JSON stringification cares) and so the caller cannot forget a
|
|
11
|
+
* required meta field.
|
|
12
|
+
*/
|
|
13
|
+
export function buildEnvelope(params) {
|
|
14
|
+
const envelope = {
|
|
15
|
+
result: params.result,
|
|
16
|
+
meta: {
|
|
17
|
+
tokens_budgeted: params.tokensBudgeted,
|
|
18
|
+
tokens_used: params.tokensUsed,
|
|
19
|
+
results_truncated: params.resultsTruncated,
|
|
20
|
+
scope: params.scope,
|
|
21
|
+
query_time_ms: params.queryTimeMs,
|
|
22
|
+
stale_files: params.staleFiles ?? [],
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
if (params.logs && params.logs.length > 0) {
|
|
26
|
+
envelope.logs = params.logs;
|
|
27
|
+
}
|
|
28
|
+
return envelope;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Helper for measuring query wall-clock time. Captures a start timestamp
|
|
32
|
+
* on construction and returns the elapsed ms when `end()` is called. Using
|
|
33
|
+
* `performance.now()` instead of `Date.now()` for sub-ms resolution — the
|
|
34
|
+
* cold-start benchmark gate in Phase 1 tests #6 is measuring p50 at the
|
|
35
|
+
* 100ms scale, so millisecond precision matters.
|
|
36
|
+
*/
|
|
37
|
+
export class QueryTimer {
|
|
38
|
+
startMs;
|
|
39
|
+
constructor() {
|
|
40
|
+
this.startMs = performance.now();
|
|
41
|
+
}
|
|
42
|
+
end() {
|
|
43
|
+
return Math.round(performance.now() - this.startMs);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/mcp/envelope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2CH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAI,MAShC;IACC,MAAM,QAAQ,GAAgB;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE;YACJ,eAAe,EAAE,MAAM,CAAC,cAAc;YACtC,WAAW,EAAE,MAAM,CAAC,UAAU;YAC9B,iBAAiB,EAAE,MAAM,CAAC,gBAAgB;YAC1C,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,aAAa,EAAE,MAAM,CAAC,WAAW;YACjC,WAAW,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;SACrC;KACF,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,QAAQ,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IAC9B,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,UAAU;IACJ,OAAO,CAAS;IAEjC;QACE,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACnC,CAAC;IAED,GAAG;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;CACF"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Repository } from '../../db/repository.js';
|
|
3
|
+
import type { DbBundle } from '../../db/client.js';
|
|
4
|
+
import type { QuickJSExecutor } from '../../sandbox/executor.js';
|
|
5
|
+
import type { Embedder } from '../../retrieval/embedder.js';
|
|
6
|
+
export declare const kgExecuteInputShape: {
|
|
7
|
+
code: z.ZodString;
|
|
8
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
9
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
scope: z.ZodOptional<z.ZodEnum<{
|
|
11
|
+
project: "project";
|
|
12
|
+
personal: "personal";
|
|
13
|
+
both: "both";
|
|
14
|
+
}>>;
|
|
15
|
+
};
|
|
16
|
+
export declare const kgExecuteToolConfig: {
|
|
17
|
+
readonly title: "Run JS in the knowledge-graph sandbox";
|
|
18
|
+
readonly description: string;
|
|
19
|
+
readonly inputSchema: {
|
|
20
|
+
code: z.ZodString;
|
|
21
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
scope: z.ZodOptional<z.ZodEnum<{
|
|
24
|
+
project: "project";
|
|
25
|
+
personal: "personal";
|
|
26
|
+
both: "both";
|
|
27
|
+
}>>;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export interface KgExecuteDeps {
|
|
31
|
+
repository: Repository;
|
|
32
|
+
executor: QuickJSExecutor;
|
|
33
|
+
bundle: DbBundle;
|
|
34
|
+
embedder: Embedder;
|
|
35
|
+
wikiRoot?: string;
|
|
36
|
+
personalBundle?: DbBundle;
|
|
37
|
+
personalWikiRoot?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the `kg_execute` handler. Phase 3 path: uses `executeWithBindings`
|
|
41
|
+
* with the full `kg.project.*` surface via the warm pool.
|
|
42
|
+
*/
|
|
43
|
+
export declare function makeKgExecuteHandler(deps: KgExecuteDeps): (args: {
|
|
44
|
+
code: string;
|
|
45
|
+
max_tokens?: number;
|
|
46
|
+
timeout_ms?: number;
|
|
47
|
+
scope?: "project" | "personal" | "both";
|
|
48
|
+
}) => Promise<{
|
|
49
|
+
content: [{
|
|
50
|
+
type: "text";
|
|
51
|
+
text: string;
|
|
52
|
+
}];
|
|
53
|
+
isError?: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/execute.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAmD5D,eAAO,MAAM,mBAAmB;;;;;;;;;CAuC/B,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;CAWtB,CAAC;AAEX,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,IACxC,MAAM;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC,KAAG,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA8F9E"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { countEnvelopeTokens, countTokens, computeInternalBudget, fitResults } from '../../gate/budget.js';
|
|
3
|
+
import { buildEnvelope, QueryTimer } from '../envelope.js';
|
|
4
|
+
/**
|
|
5
|
+
* `kg_execute` — code-mode tool. The LLM writes a short JS snippet, we run
|
|
6
|
+
* it inside the QuickJS sandbox against the `kg` bindings, and return the
|
|
7
|
+
* (budget-shaped) result.
|
|
8
|
+
*
|
|
9
|
+
* Phase 3: full `kg.project.*` binding surface via warm pool. Backward-compat
|
|
10
|
+
* `kg.search()`/`kg.get()` aliases remain.
|
|
11
|
+
*/
|
|
12
|
+
const KG_EXECUTE_TYPES = `
|
|
13
|
+
declare const kg: {
|
|
14
|
+
/** Substring search (backward compat). */
|
|
15
|
+
search(query: string): Array<{ id: string; text: string; source_uri: string }>;
|
|
16
|
+
/** Chunk lookup by id (backward compat). */
|
|
17
|
+
get(id: string): { id: string; text: string; source_uri: string } | null;
|
|
18
|
+
project: {
|
|
19
|
+
/** FTS5 full-text search with bm25 ranking. */
|
|
20
|
+
fts(query: string, opts?: { limit?: number }): Array<{ id: string; text: string; source_uri: string; node_id: string; rank: number; title: string | null; section_path: string }>;
|
|
21
|
+
/** Vector similarity search. Returns [] if no pre-computed embedding available. */
|
|
22
|
+
vec(query: string, opts?: { limit?: number }): Array<{ id: string; text: string; source_uri: string; node_id: string; distance: number; title: string | null; section_path: string }>;
|
|
23
|
+
/** Hybrid FTS + vector search with RRF fusion. Falls back to FTS-only if no embedding cached. */
|
|
24
|
+
hybrid(query: string, opts?: { limit?: number; rrf_k?: number }): Array<{ id: string; text: string; source_uri: string; node_id: string; score: number; snippet?: string; title: string | null; section_path: string }>;
|
|
25
|
+
/** Table of contents — list all nodes for LLM-driven browsing. Use this to scan titles, then get(id) to read specific sections. */
|
|
26
|
+
index(opts?: { kind?: string; source_uri?: string; limit?: number }): Array<{ id: string; title: string | null; source_uri: string; section_path: string; kind: string; token_count: number }>;
|
|
27
|
+
/** Node lookup by id — full section content. */
|
|
28
|
+
get(id: string): { id: string; source_uri: string; section_path: string; kind: string; title: string | null; content: string; token_count: number } | null;
|
|
29
|
+
/** K-hop graph traversal. */
|
|
30
|
+
neighbors(id: string, opts?: { depth?: number; edge_kinds?: string[] }): Array<{ id: string; source_uri: string; kind: string; title: string | null; depth: number }>;
|
|
31
|
+
log: {
|
|
32
|
+
/** Recent log entries. */
|
|
33
|
+
recent(n?: number, opts?: { kind?: string }): Array<{ id: number; ts: number; kind: string; source_uri: string | null; payload: unknown }>;
|
|
34
|
+
};
|
|
35
|
+
/** Concept gaps (stub, Phase 6). */
|
|
36
|
+
gaps(opts?: { resolved?: boolean; limit?: number }): never[];
|
|
37
|
+
/** Create or overwrite a wiki page. Path is relative to wiki root, .md extension enforced. */
|
|
38
|
+
write(path: string, content: string): { path: string; bytes: number };
|
|
39
|
+
/** Append a timestamped entry to log.md. */
|
|
40
|
+
append(entry: string): { path: string; bytes: number };
|
|
41
|
+
/** Delete a wiki page. Path is relative to wiki root. */
|
|
42
|
+
remove(path: string): { path: string; removed: true };
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
declare const budget: { fit(items: unknown[], maxTokens?: number): unknown[] };
|
|
46
|
+
declare const logger: { log(...args: unknown[]): void };
|
|
47
|
+
`.trim();
|
|
48
|
+
export const kgExecuteInputShape = {
|
|
49
|
+
code: z
|
|
50
|
+
.string()
|
|
51
|
+
.min(1)
|
|
52
|
+
.describe('JavaScript to run inside the sandbox. The sandbox is QuickJS with ' +
|
|
53
|
+
'`eval`, `Function`, `fetch`, `require`, `process`, and `constructor` ' +
|
|
54
|
+
'removed. You have `kg.project.*` for FTS, graph traversal, log ' +
|
|
55
|
+
'queries, and wiki writes (write/append/remove), plus `budget.fit()` ' +
|
|
56
|
+
'for token-aware truncation and `logger.log()` captured into ' +
|
|
57
|
+
'`response.logs`. Return a value.\n' +
|
|
58
|
+
KG_EXECUTE_TYPES),
|
|
59
|
+
max_tokens: z
|
|
60
|
+
.number()
|
|
61
|
+
.int()
|
|
62
|
+
.positive()
|
|
63
|
+
.max(20_000)
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('Maximum total tokens the response can contain. Default 5000, max 20000.'),
|
|
66
|
+
timeout_ms: z
|
|
67
|
+
.number()
|
|
68
|
+
.int()
|
|
69
|
+
.positive()
|
|
70
|
+
.max(10_000)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('Hard wall-clock execution timeout for the sandbox. Default 2000ms, ' +
|
|
73
|
+
'max 10000ms. If exceeded, the response contains an `error` string.'),
|
|
74
|
+
scope: z
|
|
75
|
+
.enum(['project', 'personal', 'both'])
|
|
76
|
+
.optional()
|
|
77
|
+
.describe('Which KG bindings to inject. "project" (default) installs kg.project, ' +
|
|
78
|
+
'"personal" installs kg.personal, "both" installs both namespaces.'),
|
|
79
|
+
};
|
|
80
|
+
export const kgExecuteToolConfig = {
|
|
81
|
+
title: 'Run JS in the knowledge-graph sandbox',
|
|
82
|
+
description: 'Run a short JavaScript snippet inside the KG sandbox. Use `kg.project.index()` ' +
|
|
83
|
+
'to browse the wiki table of contents, then `kg.project.get(id)` to read ' +
|
|
84
|
+
'specific sections. `kg.project.hybrid()` for search, ' +
|
|
85
|
+
'`kg.project.neighbors()` for graph traversal, `kg.project.log.recent()` for ' +
|
|
86
|
+
'event log. Legacy `kg.search()`/`kg.get()` also available. ' +
|
|
87
|
+
'64MB memory cap, 2s default timeout. No network, no eval.\n\n' +
|
|
88
|
+
KG_EXECUTE_TYPES,
|
|
89
|
+
inputSchema: kgExecuteInputShape,
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Build the `kg_execute` handler. Phase 3 path: uses `executeWithBindings`
|
|
93
|
+
* with the full `kg.project.*` surface via the warm pool.
|
|
94
|
+
*/
|
|
95
|
+
export function makeKgExecuteHandler(deps) {
|
|
96
|
+
return async (args) => {
|
|
97
|
+
const timer = new QueryTimer();
|
|
98
|
+
const maxTokens = args.max_tokens ?? 5000;
|
|
99
|
+
const scope = args.scope ?? 'project';
|
|
100
|
+
// Check that personal scope is available if requested
|
|
101
|
+
if ((scope === 'personal' || scope === 'both') && !deps.personalBundle) {
|
|
102
|
+
const envelope = buildEnvelope({
|
|
103
|
+
result: {
|
|
104
|
+
error: 'personal scope requested but no personal KG is configured — ' +
|
|
105
|
+
'set KG_PROFILE_PATH or pass --profile-path',
|
|
106
|
+
},
|
|
107
|
+
tokensBudgeted: maxTokens,
|
|
108
|
+
tokensUsed: 0,
|
|
109
|
+
resultsTruncated: false,
|
|
110
|
+
scope,
|
|
111
|
+
queryTimeMs: timer.end(),
|
|
112
|
+
});
|
|
113
|
+
return wrapText(envelope);
|
|
114
|
+
}
|
|
115
|
+
const logs = [];
|
|
116
|
+
const writeCounter = { value: 0 };
|
|
117
|
+
// Build per-scope binding deps. Privacy invariant: only include
|
|
118
|
+
// the scope(s) the caller requested.
|
|
119
|
+
const bindingDeps = { maxTokens, logs };
|
|
120
|
+
if (scope === 'project' || scope === 'both') {
|
|
121
|
+
bindingDeps.project = {
|
|
122
|
+
repository: deps.repository,
|
|
123
|
+
bundle: deps.bundle,
|
|
124
|
+
scope: 'project',
|
|
125
|
+
embedder: deps.embedder,
|
|
126
|
+
wikiRoot: deps.wikiRoot,
|
|
127
|
+
writeCounter,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if ((scope === 'personal' || scope === 'both') && deps.personalBundle) {
|
|
131
|
+
bindingDeps.personal = {
|
|
132
|
+
repository: deps.repository,
|
|
133
|
+
bundle: deps.personalBundle,
|
|
134
|
+
scope: 'personal',
|
|
135
|
+
embedder: deps.embedder,
|
|
136
|
+
wikiRoot: deps.personalWikiRoot,
|
|
137
|
+
writeCounter,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const result = await deps.executor.executeWithBindings(args.code, bindingDeps, args.timeout_ms);
|
|
141
|
+
// Executor errors are in-payload per CLAUDE.md §API Rules #8.
|
|
142
|
+
if (result.error) {
|
|
143
|
+
const envelope = buildEnvelope({
|
|
144
|
+
result: { error: result.error },
|
|
145
|
+
tokensBudgeted: maxTokens,
|
|
146
|
+
tokensUsed: 0,
|
|
147
|
+
resultsTruncated: false,
|
|
148
|
+
scope,
|
|
149
|
+
queryTimeMs: timer.end(),
|
|
150
|
+
logs: result.logs,
|
|
151
|
+
});
|
|
152
|
+
const json = JSON.stringify(envelope);
|
|
153
|
+
envelope.meta.tokens_used = countEnvelopeTokens(json);
|
|
154
|
+
return wrapText(envelope);
|
|
155
|
+
}
|
|
156
|
+
// Apply the budget gate. If the result is an array, fitResults does
|
|
157
|
+
// the greedy truncation we want. If the result is a scalar or object,
|
|
158
|
+
// we check its total size and replace it with a truncation notice
|
|
159
|
+
// rather than emitting a too-large sentinel (which only makes sense
|
|
160
|
+
// for rank-ordered results).
|
|
161
|
+
const raw = result.result;
|
|
162
|
+
const { shapedResult, truncated, tokensUsed, tokensBudgeted } = shapeForBudget(raw, maxTokens);
|
|
163
|
+
const envelope = buildEnvelope({
|
|
164
|
+
result: shapedResult,
|
|
165
|
+
tokensBudgeted,
|
|
166
|
+
tokensUsed,
|
|
167
|
+
resultsTruncated: truncated,
|
|
168
|
+
scope,
|
|
169
|
+
queryTimeMs: timer.end(),
|
|
170
|
+
logs: result.logs,
|
|
171
|
+
});
|
|
172
|
+
const json = JSON.stringify(envelope);
|
|
173
|
+
envelope.meta.tokens_used = countEnvelopeTokens(json);
|
|
174
|
+
return wrapText(envelope);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Budget-shape the raw result of a sandbox execution. For array results
|
|
179
|
+
* we reuse `fitResults` with a synthetic id/uri extractor. For non-array
|
|
180
|
+
* results we measure the whole thing and replace it with a truncation
|
|
181
|
+
* notice if it overflows.
|
|
182
|
+
*/
|
|
183
|
+
function shapeForBudget(raw, maxTokens) {
|
|
184
|
+
const budget = computeInternalBudget(maxTokens);
|
|
185
|
+
if (Array.isArray(raw)) {
|
|
186
|
+
let arrayIdx = 0;
|
|
187
|
+
const fit = fitResults(raw, maxTokens, (item) => JSON.stringify(item), (item) => {
|
|
188
|
+
// Try to pull a stable id out of the item if it has one,
|
|
189
|
+
// otherwise fall back to an array-index pseudo-id.
|
|
190
|
+
const obj = item;
|
|
191
|
+
if (obj && typeof obj.id === 'string')
|
|
192
|
+
return obj.id;
|
|
193
|
+
return `[${arrayIdx++}]`;
|
|
194
|
+
}, (item) => {
|
|
195
|
+
const obj = item;
|
|
196
|
+
return obj && typeof obj.source_uri === 'string' ? obj.source_uri : '';
|
|
197
|
+
});
|
|
198
|
+
return {
|
|
199
|
+
shapedResult: fit.kept,
|
|
200
|
+
truncated: fit.truncated,
|
|
201
|
+
tokensUsed: fit.tokensUsed,
|
|
202
|
+
tokensBudgeted: fit.tokensBudgeted,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
// Scalar, object, null, etc. — measure the whole thing.
|
|
206
|
+
const json = JSON.stringify(raw);
|
|
207
|
+
const cost = countTokens(json ?? 'null');
|
|
208
|
+
if (cost <= budget) {
|
|
209
|
+
return {
|
|
210
|
+
shapedResult: raw,
|
|
211
|
+
truncated: false,
|
|
212
|
+
tokensUsed: cost,
|
|
213
|
+
tokensBudgeted: budget,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
// Too large for a scalar result. Replace with an error string so the
|
|
217
|
+
// LLM can retry with a higher max_tokens or re-query more narrowly.
|
|
218
|
+
return {
|
|
219
|
+
shapedResult: {
|
|
220
|
+
error: `result body is ${cost} tokens, which exceeds the internal budget ` +
|
|
221
|
+
`of ${budget} (max_tokens=${maxTokens}). Re-query with a higher ` +
|
|
222
|
+
`max_tokens or narrow your code to return fewer fields.`,
|
|
223
|
+
},
|
|
224
|
+
truncated: true,
|
|
225
|
+
tokensUsed: countTokens(JSON.stringify({ error: 'placeholder' })),
|
|
226
|
+
tokensBudgeted: budget,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
function wrapText(envelope) {
|
|
230
|
+
return { content: [{ type: 'text', text: JSON.stringify(envelope) }] };
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/mcp/tools/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { Repository } from '../../db/repository.js';
|
|
3
|
+
import type { DbBundle } from '../../db/client.js';
|
|
4
|
+
import type { Embedder } from '../../retrieval/embedder.js';
|
|
5
|
+
/**
|
|
6
|
+
* `kg_search` — fast-path hybrid search against the knowledge graph.
|
|
7
|
+
*
|
|
8
|
+
* Phase 5: supports all three scopes. For `scope='both'`, results from
|
|
9
|
+
* both KGs are merged and tagged with `source_scope`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const kgSearchInputShape: {
|
|
12
|
+
query: z.ZodString;
|
|
13
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
14
|
+
scope: z.ZodOptional<z.ZodEnum<{
|
|
15
|
+
project: "project";
|
|
16
|
+
personal: "personal";
|
|
17
|
+
both: "both";
|
|
18
|
+
}>>;
|
|
19
|
+
};
|
|
20
|
+
export declare const kgSearchToolConfig: {
|
|
21
|
+
readonly title: "Search the knowledge graph";
|
|
22
|
+
readonly description: string;
|
|
23
|
+
readonly inputSchema: {
|
|
24
|
+
query: z.ZodString;
|
|
25
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
scope: z.ZodOptional<z.ZodEnum<{
|
|
27
|
+
project: "project";
|
|
28
|
+
personal: "personal";
|
|
29
|
+
both: "both";
|
|
30
|
+
}>>;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export interface KgSearchDeps {
|
|
34
|
+
repository: Repository;
|
|
35
|
+
embedder: Embedder;
|
|
36
|
+
bundle: DbBundle;
|
|
37
|
+
personalBundle?: DbBundle;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the `kg_search` handler. Supports project, personal, and both scopes.
|
|
41
|
+
*/
|
|
42
|
+
export declare function makeKgSearchHandler(deps: KgSearchDeps): (args: {
|
|
43
|
+
query: string;
|
|
44
|
+
max_tokens?: number;
|
|
45
|
+
scope?: "project" | "personal" | "both";
|
|
46
|
+
}) => Promise<{
|
|
47
|
+
content: [{
|
|
48
|
+
type: "text";
|
|
49
|
+
text: string;
|
|
50
|
+
}];
|
|
51
|
+
isError?: boolean;
|
|
52
|
+
}>;
|
|
53
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAM5D;;;;;GAKG;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;CA6B9B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;CASrB,CAAC;AAEX,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,QAAQ,CAAC;IACjB,cAAc,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAaD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,IACtC,MAAM;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;CACzC,KAAG,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CA4E9E"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { hybridSearch } from '../../retrieval/hybrid.js';
|
|
3
|
+
import { fitResults, countEnvelopeTokens } from '../../gate/budget.js';
|
|
4
|
+
import { buildEnvelope, QueryTimer } from '../envelope.js';
|
|
5
|
+
import { nextReader } from '../../db/client.js';
|
|
6
|
+
/**
|
|
7
|
+
* `kg_search` — fast-path hybrid search against the knowledge graph.
|
|
8
|
+
*
|
|
9
|
+
* Phase 5: supports all three scopes. For `scope='both'`, results from
|
|
10
|
+
* both KGs are merged and tagged with `source_scope`.
|
|
11
|
+
*/
|
|
12
|
+
export const kgSearchInputShape = {
|
|
13
|
+
query: z
|
|
14
|
+
.string()
|
|
15
|
+
.min(1)
|
|
16
|
+
.describe('The search term. Hybrid FTS5 + vector search against every indexed ' +
|
|
17
|
+
'chunk of the wiki, ranked by Reciprocal Rank Fusion. ' +
|
|
18
|
+
'Examples: "hashPassword", "bcrypt", "auth flow".'),
|
|
19
|
+
max_tokens: z
|
|
20
|
+
.number()
|
|
21
|
+
.int()
|
|
22
|
+
.positive()
|
|
23
|
+
.max(20_000)
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Maximum total tokens the response can contain. Defaults to 5000, max 20000. ' +
|
|
26
|
+
'The server applies a ~10% safety margin internally. If results would ' +
|
|
27
|
+
'exceed the budget, they are greedy-truncated in rank order and ' +
|
|
28
|
+
'`meta.results_truncated` is set to true.'),
|
|
29
|
+
scope: z
|
|
30
|
+
.enum(['project', 'personal', 'both'])
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Which KG to query. "project" (default) searches the project wiki, ' +
|
|
33
|
+
'"personal" searches the personal wiki, "both" merges results from ' +
|
|
34
|
+
'both with `source_scope` tagging on each result.'),
|
|
35
|
+
};
|
|
36
|
+
export const kgSearchToolConfig = {
|
|
37
|
+
title: 'Search the knowledge graph',
|
|
38
|
+
description: 'Hybrid FTS + vector search the knowledge graph and return matching ' +
|
|
39
|
+
'chunks ranked by Reciprocal Rank Fusion. Each result includes `title` ' +
|
|
40
|
+
'and `section_path` for quick triage without reading full content. ' +
|
|
41
|
+
'Prefer this for short lookups; use `kg_execute` when you need to chain ' +
|
|
42
|
+
'filters, browse the wiki index, or combine multiple queries in one call.',
|
|
43
|
+
inputSchema: kgSearchInputShape,
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Build the `kg_search` handler. Supports project, personal, and both scopes.
|
|
47
|
+
*/
|
|
48
|
+
export function makeKgSearchHandler(deps) {
|
|
49
|
+
return async (args) => {
|
|
50
|
+
const timer = new QueryTimer();
|
|
51
|
+
const maxTokens = args.max_tokens ?? 5000;
|
|
52
|
+
const scope = args.scope ?? 'project';
|
|
53
|
+
// Check personal scope availability
|
|
54
|
+
if ((scope === 'personal' || scope === 'both') && !deps.personalBundle) {
|
|
55
|
+
const envelope = buildEnvelope({
|
|
56
|
+
result: {
|
|
57
|
+
error: 'personal scope requested but no personal KG is configured — ' +
|
|
58
|
+
'set KG_PROFILE_PATH or pass --profile-path',
|
|
59
|
+
},
|
|
60
|
+
tokensBudgeted: maxTokens,
|
|
61
|
+
tokensUsed: 0,
|
|
62
|
+
resultsTruncated: false,
|
|
63
|
+
scope,
|
|
64
|
+
queryTimeMs: timer.end(),
|
|
65
|
+
});
|
|
66
|
+
return wrapText(envelope);
|
|
67
|
+
}
|
|
68
|
+
let allHits = [];
|
|
69
|
+
if (scope === 'project' || scope === 'both') {
|
|
70
|
+
const reader = nextReader(deps.bundle);
|
|
71
|
+
const hits = await hybridSearch(reader, 'project', args.query, deps.embedder);
|
|
72
|
+
const tagged = hits.map((h) => ({
|
|
73
|
+
id: h.id, text: h.text, source_uri: h.source_uri, score: h.score,
|
|
74
|
+
confidence: h.confidence, title: h.title, section_path: h.section_path,
|
|
75
|
+
...(scope === 'both' ? { source_scope: 'project' } : {}),
|
|
76
|
+
}));
|
|
77
|
+
allHits.push(...tagged);
|
|
78
|
+
}
|
|
79
|
+
if ((scope === 'personal' || scope === 'both') && deps.personalBundle) {
|
|
80
|
+
const reader = nextReader(deps.personalBundle);
|
|
81
|
+
const hits = await hybridSearch(reader, 'personal', args.query, deps.embedder);
|
|
82
|
+
const tagged = hits.map((h) => ({
|
|
83
|
+
id: h.id, text: h.text, source_uri: h.source_uri, score: h.score,
|
|
84
|
+
confidence: h.confidence, title: h.title, section_path: h.section_path,
|
|
85
|
+
...(scope === 'both' ? { source_scope: 'personal' } : {}),
|
|
86
|
+
}));
|
|
87
|
+
allHits.push(...tagged);
|
|
88
|
+
}
|
|
89
|
+
// For scope='both', re-sort merged results by score descending
|
|
90
|
+
if (scope === 'both') {
|
|
91
|
+
allHits.sort((a, b) => b.score - a.score);
|
|
92
|
+
}
|
|
93
|
+
const fit = fitResults(allHits, maxTokens, (h) => JSON.stringify(h), (h) => h.id, (h) => h.source_uri);
|
|
94
|
+
const envelope = buildEnvelope({
|
|
95
|
+
result: fit.kept.map((item) => {
|
|
96
|
+
if ('too_large' in item)
|
|
97
|
+
return item;
|
|
98
|
+
return item;
|
|
99
|
+
}),
|
|
100
|
+
tokensBudgeted: fit.tokensBudgeted,
|
|
101
|
+
tokensUsed: 0,
|
|
102
|
+
resultsTruncated: fit.truncated,
|
|
103
|
+
scope,
|
|
104
|
+
queryTimeMs: timer.end(),
|
|
105
|
+
});
|
|
106
|
+
const json = JSON.stringify(envelope);
|
|
107
|
+
envelope.meta.tokens_used = countEnvelopeTokens(json);
|
|
108
|
+
return wrapText(envelope);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function wrapText(envelope) {
|
|
112
|
+
return { content: [{ type: 'text', text: JSON.stringify(envelope) }] };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/mcp/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Database as BetterSqliteDatabase } from 'better-sqlite3';
|
|
2
|
+
/**
|
|
3
|
+
* Audit log writer with scope-split JSONL mirror.
|
|
4
|
+
*
|
|
5
|
+
* Per CLAUDE.md §Security #7:
|
|
6
|
+
* - scope='project' → kg_audit table in project .kg/kg.db + .kg/audit.jsonl
|
|
7
|
+
* - scope='personal' or 'both' → kg_audit table in ~/.kg/kg.db + ~/.kg/audit.jsonl
|
|
8
|
+
* - NEVER write personal query text to a path inside the project repo
|
|
9
|
+
*/
|
|
10
|
+
export interface AuditEntry {
|
|
11
|
+
toolName: string;
|
|
12
|
+
scopeRequested: string;
|
|
13
|
+
callerCtx?: string;
|
|
14
|
+
responseTokens?: number;
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Write an audit row to the appropriate DB and mirror to JSONL.
|
|
19
|
+
*
|
|
20
|
+
* @param writer The DB writer for the scope-appropriate bundle.
|
|
21
|
+
* @param jsonlPath The path for the JSONL mirror file.
|
|
22
|
+
* @param entry Audit entry data.
|
|
23
|
+
*/
|
|
24
|
+
export declare function writeAuditRow(writer: BetterSqliteDatabase, jsonlPath: string | undefined, entry: AuditEntry): void;
|
|
25
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/observability/audit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAIvE;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,oBAAoB,EAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,KAAK,EAAE,UAAU,GAChB,IAAI,CAmCN"}
|