ctxr-cli 0.30.0 → 0.31.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 +28 -0
- package/dist/commands/land.d.ts.map +1 -1
- package/dist/commands/land.js +3 -18
- package/dist/commands/land.js.map +1 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +10 -2
- package/dist/commands/serve.js.map +1 -1
- package/dist/config/schema.d.ts +17 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +40 -8
- package/dist/config/schema.js.map +1 -1
- package/dist/core/browse/approve.d.ts +3 -0
- package/dist/core/browse/approve.d.ts.map +1 -1
- package/dist/core/browse/approve.js.map +1 -1
- package/dist/core/browse/page-url.d.ts +15 -0
- package/dist/core/browse/page-url.d.ts.map +1 -1
- package/dist/core/browse/page-url.js +8 -1
- package/dist/core/browse/page-url.js.map +1 -1
- package/dist/core/forge/credentials.d.ts +12 -1
- package/dist/core/forge/credentials.d.ts.map +1 -1
- package/dist/core/forge/credentials.js +25 -1
- package/dist/core/forge/credentials.js.map +1 -1
- package/dist/core/forge/github.d.ts +9 -0
- package/dist/core/forge/github.d.ts.map +1 -1
- package/dist/core/forge/github.js +6 -0
- package/dist/core/forge/github.js.map +1 -1
- package/dist/core/mcp/drafts.d.ts +30 -0
- package/dist/core/mcp/drafts.d.ts.map +1 -0
- package/dist/core/mcp/drafts.js +52 -0
- package/dist/core/mcp/drafts.js.map +1 -0
- package/dist/core/mcp/http.d.ts +40 -0
- package/dist/core/mcp/http.d.ts.map +1 -0
- package/dist/core/mcp/http.js +90 -0
- package/dist/core/mcp/http.js.map +1 -0
- package/dist/core/mcp/jsonrpc.d.ts +73 -0
- package/dist/core/mcp/jsonrpc.d.ts.map +1 -0
- package/dist/core/mcp/jsonrpc.js +149 -0
- package/dist/core/mcp/jsonrpc.js.map +1 -0
- package/dist/core/mcp/members.d.ts +11 -0
- package/dist/core/mcp/members.d.ts.map +1 -0
- package/dist/core/mcp/members.js +21 -0
- package/dist/core/mcp/members.js.map +1 -0
- package/dist/core/mcp/oauth.d.ts +99 -0
- package/dist/core/mcp/oauth.d.ts.map +1 -0
- package/dist/core/mcp/oauth.js +454 -0
- package/dist/core/mcp/oauth.js.map +1 -0
- package/dist/core/mcp/pages.d.ts +3 -0
- package/dist/core/mcp/pages.d.ts.map +1 -0
- package/dist/core/mcp/pages.js +41 -0
- package/dist/core/mcp/pages.js.map +1 -0
- package/dist/core/mcp/ripgrep.d.ts +48 -0
- package/dist/core/mcp/ripgrep.d.ts.map +1 -0
- package/dist/core/mcp/ripgrep.js +98 -0
- package/dist/core/mcp/ripgrep.js.map +1 -0
- package/dist/core/mcp/rwlock.d.ts +16 -0
- package/dist/core/mcp/rwlock.d.ts.map +1 -0
- package/dist/core/mcp/rwlock.js +59 -0
- package/dist/core/mcp/rwlock.js.map +1 -0
- package/dist/core/mcp/sessions.d.ts +84 -0
- package/dist/core/mcp/sessions.d.ts.map +1 -0
- package/dist/core/mcp/sessions.js +154 -0
- package/dist/core/mcp/sessions.js.map +1 -0
- package/dist/core/mcp/surface.d.ts +42 -0
- package/dist/core/mcp/surface.d.ts.map +1 -0
- package/dist/core/mcp/surface.js +141 -0
- package/dist/core/mcp/surface.js.map +1 -0
- package/dist/core/mcp/sync.d.ts +91 -0
- package/dist/core/mcp/sync.d.ts.map +1 -0
- package/dist/core/mcp/sync.js +218 -0
- package/dist/core/mcp/sync.js.map +1 -0
- package/dist/core/mcp/tools/capture.d.ts +64 -0
- package/dist/core/mcp/tools/capture.d.ts.map +1 -0
- package/dist/core/mcp/tools/capture.js +182 -0
- package/dist/core/mcp/tools/capture.js.map +1 -0
- package/dist/core/mcp/tools/edit.d.ts +79 -0
- package/dist/core/mcp/tools/edit.d.ts.map +1 -0
- package/dist/core/mcp/tools/edit.js +212 -0
- package/dist/core/mcp/tools/edit.js.map +1 -0
- package/dist/core/mcp/tools/files.d.ts +163 -0
- package/dist/core/mcp/tools/files.d.ts.map +1 -0
- package/dist/core/mcp/tools/files.js +265 -0
- package/dist/core/mcp/tools/files.js.map +1 -0
- package/dist/core/mcp/tools/find.d.ts +82 -0
- package/dist/core/mcp/tools/find.d.ts.map +1 -0
- package/dist/core/mcp/tools/find.js +136 -0
- package/dist/core/mcp/tools/find.js.map +1 -0
- package/dist/core/mcp/tools/gather.d.ts +88 -0
- package/dist/core/mcp/tools/gather.d.ts.map +1 -0
- package/dist/core/mcp/tools/gather.js +123 -0
- package/dist/core/mcp/tools/gather.js.map +1 -0
- package/dist/core/mcp/tools/index.d.ts +21 -0
- package/dist/core/mcp/tools/index.d.ts.map +1 -0
- package/dist/core/mcp/tools/index.js +129 -0
- package/dist/core/mcp/tools/index.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/templates/mcp/Edit.md +7 -0
- package/templates/mcp/Glob.md +5 -0
- package/templates/mcp/Grep.md +10 -0
- package/templates/mcp/Read.md +7 -0
- package/templates/mcp/Write.md +7 -0
- package/templates/mcp/capture.md +9 -0
- package/templates/mcp/consent.html +40 -0
- package/templates/mcp/find.md +9 -0
- package/templates/mcp/gather.md +5 -0
- package/templates/mcp/server-instructions.md +17 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { joinBaseUrl, noteRoute } from '../../browse/page-url.js';
|
|
4
|
+
import { catalogSectionsFor, sectionForNote } from '../../catalog/model.js';
|
|
5
|
+
import { isUnderAnyPrefix } from '../../fs/prefix.js';
|
|
6
|
+
import { listCaptures, listNotes } from '../../notes/list.js';
|
|
7
|
+
import { readCatalogGlosses } from '../../records.js';
|
|
8
|
+
import { ToolRefusal } from '../jsonrpc.js';
|
|
9
|
+
/**
|
|
10
|
+
* remote-access spec, *`find` stands in for a client's own content
|
|
11
|
+
* matching*; context-retrieval's bounded exception. Literal,
|
|
12
|
+
* case-insensitive substring matching over the notes the store's
|
|
13
|
+
* enumeration admits, in path order, with no score. Captures — inbox files
|
|
14
|
+
* on the default branch and on pending `capture/` branches — come back in
|
|
15
|
+
* `unfiled`, never among the notes (context-ingest's exception, design.md
|
|
16
|
+
* D6). With no text, the catalog as a map to pick selectors from.
|
|
17
|
+
*/
|
|
18
|
+
export const MAX_LINES_PER_HIT = 3;
|
|
19
|
+
export const MAX_LINE_CHARS = 240;
|
|
20
|
+
export const DEFAULT_MAX_MATCHES = 25;
|
|
21
|
+
export const DEFAULT_MAX_MAP_NOTES = 500;
|
|
22
|
+
export const MAX_RESULTS = 1000;
|
|
23
|
+
const MAX_TEXT_CHARS = 200;
|
|
24
|
+
/**
|
|
25
|
+
* Plain on purpose: type, description and required only. Some clients (Gemini) accept a narrow subset of JSON
|
|
26
|
+
* Schema and drop a tool whose schema uses more; every limit is enforced by `parseFindArgs` instead.
|
|
27
|
+
*/
|
|
28
|
+
export const FIND_INPUT_SCHEMA = {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
text: { type: 'string', description: 'Literal text to look for, case-insensitive. Omit it to get the map of the store instead.' },
|
|
32
|
+
under: { type: 'string', description: 'Only look under this folder of the store, e.g. "projects/".' },
|
|
33
|
+
max: { type: 'integer', description: `How many notes to return (default ${DEFAULT_MAX_MATCHES} when matching, ${DEFAULT_MAX_MAP_NOTES} for the map).` },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
export function parseFindArgs(args) {
|
|
37
|
+
const out = {};
|
|
38
|
+
if (args.text !== undefined && args.text !== null) {
|
|
39
|
+
if (typeof args.text !== 'string')
|
|
40
|
+
throw new ToolRefusal('mcp.invalid_arguments', '"text" must be a string.');
|
|
41
|
+
if (args.text.length > MAX_TEXT_CHARS)
|
|
42
|
+
throw new ToolRefusal('mcp.invalid_arguments', `"text" is at most ${MAX_TEXT_CHARS} characters.`);
|
|
43
|
+
if (args.text.trim().length > 0)
|
|
44
|
+
out.text = args.text.trim();
|
|
45
|
+
}
|
|
46
|
+
if (args.under !== undefined && args.under !== null) {
|
|
47
|
+
if (typeof args.under !== 'string')
|
|
48
|
+
throw new ToolRefusal('mcp.invalid_arguments', '"under" must be a string.');
|
|
49
|
+
const under = args.under.trim().replace(/^\.?\/+/, '');
|
|
50
|
+
if (under.length > 0)
|
|
51
|
+
out.under = under;
|
|
52
|
+
}
|
|
53
|
+
if (args.max !== undefined && args.max !== null) {
|
|
54
|
+
if (typeof args.max !== 'number' || !Number.isInteger(args.max) || args.max < 1 || args.max > MAX_RESULTS) {
|
|
55
|
+
throw new ToolRefusal('mcp.invalid_arguments', `"max" must be a whole number from 1 to ${MAX_RESULTS}.`);
|
|
56
|
+
}
|
|
57
|
+
out.max = args.max;
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
function matchLines(text, needle) {
|
|
62
|
+
const lines = [];
|
|
63
|
+
let count = 0;
|
|
64
|
+
const all = text.split(/\r?\n/);
|
|
65
|
+
for (let i = 0; i < all.length; i += 1) {
|
|
66
|
+
const line = all[i];
|
|
67
|
+
if (!line.toLowerCase().includes(needle))
|
|
68
|
+
continue;
|
|
69
|
+
count += 1;
|
|
70
|
+
if (lines.length < MAX_LINES_PER_HIT) {
|
|
71
|
+
lines.push({ line: i + 1, text: line.length > MAX_LINE_CHARS ? `${line.slice(0, MAX_LINE_CHARS - 1)}…` : line });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { lines, count };
|
|
75
|
+
}
|
|
76
|
+
const byPath = (a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
77
|
+
/** `baseUrl` is `serve.base_url` from the configuration `serve` loaded: links point at the browsing surface it answers. */
|
|
78
|
+
export async function find(snapshot, args, baseUrl) {
|
|
79
|
+
const store = snapshot.store;
|
|
80
|
+
const linkFor = (notePath) => joinBaseUrl(baseUrl, noteRoute(notePath));
|
|
81
|
+
const glosses = await readCatalogGlosses(store);
|
|
82
|
+
const scope = (p) => args.under === undefined || isUnderAnyPrefix(p, [args.under]);
|
|
83
|
+
const notes = (await listNotes(store.root, store.config)).filter((n) => scope(n.path)).sort(byPath);
|
|
84
|
+
if (args.text === undefined) {
|
|
85
|
+
const max = args.max ?? DEFAULT_MAX_MAP_NOTES;
|
|
86
|
+
const sections = catalogSectionsFor(store.config);
|
|
87
|
+
const grouped = new Map(sections.map((s) => [s.id, []]));
|
|
88
|
+
let listed = 0;
|
|
89
|
+
for (const note of notes) {
|
|
90
|
+
if (listed >= max)
|
|
91
|
+
break;
|
|
92
|
+
grouped.get(sectionForNote(sections, note.path).id).push({ path: note.path, gloss: glosses.get(note.path) ?? '', url: linkFor(note.path) });
|
|
93
|
+
listed += 1;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
mode: 'map',
|
|
97
|
+
sections: [...grouped.entries()].filter(([, entries]) => entries.length > 0).map(([id, entries]) => ({ id, notes: entries })),
|
|
98
|
+
notes_omitted: notes.length - listed,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const needle = args.text.toLowerCase();
|
|
102
|
+
const max = args.max ?? DEFAULT_MAX_MATCHES;
|
|
103
|
+
// Raw file text, frontmatter included, so line numbers are the file's own — what grep would report.
|
|
104
|
+
const noteHits = [];
|
|
105
|
+
for (const note of notes) {
|
|
106
|
+
const { lines, count } = matchLines(await readFile(path.join(store.root, note.path), 'utf8'), needle);
|
|
107
|
+
if (count > 0)
|
|
108
|
+
noteHits.push({ path: note.path, gloss: glosses.get(note.path) ?? '', lines, matching_lines: count, url: linkFor(note.path) });
|
|
109
|
+
}
|
|
110
|
+
const inbox = store.config.ingest.inbox_path;
|
|
111
|
+
const unfiled = [];
|
|
112
|
+
for (const capture of (await listCaptures(store.root, store.config)).sort(byPath)) {
|
|
113
|
+
if (!isUnderAnyPrefix(capture.path, [inbox]) || !scope(capture.path))
|
|
114
|
+
continue;
|
|
115
|
+
const { lines, count } = matchLines(await readFile(path.join(store.root, capture.path), 'utf8'), needle);
|
|
116
|
+
if (count > 0)
|
|
117
|
+
unfiled.push({ path: capture.path, lines, matching_lines: count, pending_merge: false, branch: null });
|
|
118
|
+
}
|
|
119
|
+
const pending = [...snapshot.pending].sort((a, b) => byPath(a, b) || (a.branch < b.branch ? -1 : 1));
|
|
120
|
+
for (const capture of pending) {
|
|
121
|
+
if (!scope(capture.path))
|
|
122
|
+
continue;
|
|
123
|
+
const { lines, count } = matchLines(capture.text, needle);
|
|
124
|
+
if (count > 0)
|
|
125
|
+
unfiled.push({ path: capture.path, lines, matching_lines: count, pending_merge: true, branch: capture.branch });
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
mode: 'match',
|
|
129
|
+
text: args.text,
|
|
130
|
+
notes: noteHits.slice(0, max),
|
|
131
|
+
notes_omitted: Math.max(0, noteHits.length - max),
|
|
132
|
+
unfiled: unfiled.slice(0, max),
|
|
133
|
+
unfiled_omitted: Math.max(0, unfiled.length - max),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=find.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find.js","sourceRoot":"","sources":["../../../../src/core/mcp/tools/find.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { type GatherOutcome, type GatherResult } from '../../retrieval/pass.js';
|
|
2
|
+
import type { Snapshot } from '../sync.js';
|
|
3
|
+
/**
|
|
4
|
+
* remote-access spec, *`gather` returns the retrieval pass with the bodies a
|
|
5
|
+
* client cannot read itself* (design.md D8). The pass runs unchanged against
|
|
6
|
+
* the view's notes and the view's own graph, and still returns no body; this
|
|
7
|
+
* attaches them afterwards, to a prefix of the pass's order, within a byte
|
|
8
|
+
* budget — so the cap never reorders anything, exactly as the pass's own cap.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_GATHER_MAX_BYTES = 60000;
|
|
11
|
+
export interface GatherArgs {
|
|
12
|
+
seeds?: string[];
|
|
13
|
+
sections?: string[];
|
|
14
|
+
under?: string[];
|
|
15
|
+
entities?: string[];
|
|
16
|
+
hops?: number;
|
|
17
|
+
direction?: 'in' | 'out' | 'both';
|
|
18
|
+
type?: string;
|
|
19
|
+
max_notes?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface GatheredNote extends GatherResult {
|
|
22
|
+
/** The note's text, frontmatter included; null once the byte budget is spent. */
|
|
23
|
+
body: string | null;
|
|
24
|
+
/** Set on the first note only, when it alone exceeded the budget and was cut to it. */
|
|
25
|
+
body_clipped?: true;
|
|
26
|
+
}
|
|
27
|
+
export interface GatherToolResult extends Omit<GatherOutcome, 'notes'> {
|
|
28
|
+
notes: GatheredNote[];
|
|
29
|
+
bodies: {
|
|
30
|
+
max_bytes: number;
|
|
31
|
+
returned: number;
|
|
32
|
+
omitted: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Plain on purpose (see FIND_INPUT_SCHEMA): `parseGatherArgs` enforces every limit. */
|
|
36
|
+
export declare const GATHER_INPUT_SCHEMA: {
|
|
37
|
+
readonly type: 'object';
|
|
38
|
+
readonly properties: {
|
|
39
|
+
readonly seeds: {
|
|
40
|
+
readonly type: 'array';
|
|
41
|
+
readonly items: {
|
|
42
|
+
readonly type: 'string';
|
|
43
|
+
};
|
|
44
|
+
readonly description: 'Note paths to start from, usually from find.';
|
|
45
|
+
};
|
|
46
|
+
readonly sections: {
|
|
47
|
+
readonly type: 'array';
|
|
48
|
+
readonly items: {
|
|
49
|
+
readonly type: 'string';
|
|
50
|
+
};
|
|
51
|
+
readonly description: 'Catalog section ids whose notes to start from (find with no text lists them).';
|
|
52
|
+
};
|
|
53
|
+
readonly under: {
|
|
54
|
+
readonly type: 'array';
|
|
55
|
+
readonly items: {
|
|
56
|
+
readonly type: 'string';
|
|
57
|
+
};
|
|
58
|
+
readonly description: 'Folders whose notes to start from, e.g. "projects/".';
|
|
59
|
+
};
|
|
60
|
+
readonly entities: {
|
|
61
|
+
readonly type: 'array';
|
|
62
|
+
readonly items: {
|
|
63
|
+
readonly type: 'string';
|
|
64
|
+
};
|
|
65
|
+
readonly description: 'Note paths whose backlinks to start from: every note linking to them.';
|
|
66
|
+
};
|
|
67
|
+
readonly hops: {
|
|
68
|
+
readonly type: 'integer';
|
|
69
|
+
readonly description: 'How many links to follow out from the starting notes (default 1; 0 returns only them).';
|
|
70
|
+
};
|
|
71
|
+
readonly direction: {
|
|
72
|
+
readonly type: 'string';
|
|
73
|
+
readonly enum: readonly ['in', 'out', 'both'];
|
|
74
|
+
readonly description: 'Follow links pointing out, in, or both (default both).';
|
|
75
|
+
};
|
|
76
|
+
readonly type: {
|
|
77
|
+
readonly type: 'string';
|
|
78
|
+
readonly description: 'Follow only links of this relation type.';
|
|
79
|
+
};
|
|
80
|
+
readonly max_notes: {
|
|
81
|
+
readonly type: 'integer';
|
|
82
|
+
readonly description: 'Cap on how many notes to return; the omitted count is reported.';
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
export declare function parseGatherArgs(args: Record<string, unknown>): GatherArgs;
|
|
87
|
+
export declare function gatherWithBodies(snapshot: Snapshot, args: GatherArgs, maxBytes?: number): Promise<GatherToolResult>;
|
|
88
|
+
//# sourceMappingURL=gather.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gather.d.ts","sourceRoot":"","sources":["../../../../src/core/mcp/tools/gather.ts"],"names":[],"mappings":"AAKA,OAAO,EAAqB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEnG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;GAMG;AAEH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,iFAAiF;IACjF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uFAAuF;IACvF,YAAY,CAAC,EAAE,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC;IACpE,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAClE;AAED,wFAAwF;AACxF,eAAO,MAAM,mBAAmB;aAC9B,IAAI,EAAE,QAAQ;aACd,UAAU;iBACR,KAAK;qBAAI,IAAI,EAAE,OAAO;qBAAE,KAAK;yBAAI,IAAI,EAAE,QAAQ;;qBAAI,WAAW,EAAE,8CAA8C;;iBAC9G,QAAQ;qBAAI,IAAI,EAAE,OAAO;qBAAE,KAAK;yBAAI,IAAI,EAAE,QAAQ;;qBAAI,WAAW,EAAE,+EAA+E;;iBAClJ,KAAK;qBAAI,IAAI,EAAE,OAAO;qBAAE,KAAK;yBAAI,IAAI,EAAE,QAAQ;;qBAAI,WAAW,EAAE,sDAAsD;;iBACtH,QAAQ;qBAAI,IAAI,EAAE,OAAO;qBAAE,KAAK;yBAAI,IAAI,EAAE,QAAQ;;qBAAI,WAAW,EAAE,uEAAuE;;iBAC1I,IAAI;qBAAI,IAAI,EAAE,SAAS;qBAAE,WAAW,EAAE,wFAAwF;;iBAC9H,SAAS;qBAAI,IAAI,EAAE,QAAQ;qBAAE,IAAI,YAAG,IAAI,EAAE,KAAK,EAAE,MAAM;qBAAG,WAAW,EAAE,wDAAwD;;iBAC/H,IAAI;qBAAI,IAAI,EAAE,QAAQ;qBAAE,WAAW,EAAE,0CAA0C;;iBAC/E,SAAS;qBAAI,IAAI,EAAE,SAAS;qBAAE,WAAW,EAAE,iEAAiE;;;CAEtG,CAAC;AAqBX,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAuBzE;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,SAA2B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiD3I"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isUnderAnyPrefix } from '../../fs/prefix.js';
|
|
4
|
+
import { readAdmittedGraph } from '../../graph/persist.js';
|
|
5
|
+
import { listNotes } from '../../notes/list.js';
|
|
6
|
+
import { gather as runPass } from '../../retrieval/pass.js';
|
|
7
|
+
import { ToolRefusal } from '../jsonrpc.js';
|
|
8
|
+
/**
|
|
9
|
+
* remote-access spec, *`gather` returns the retrieval pass with the bodies a
|
|
10
|
+
* client cannot read itself* (design.md D8). The pass runs unchanged against
|
|
11
|
+
* the view's notes and the view's own graph, and still returns no body; this
|
|
12
|
+
* attaches them afterwards, to a prefix of the pass's order, within a byte
|
|
13
|
+
* budget — so the cap never reorders anything, exactly as the pass's own cap.
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_GATHER_MAX_BYTES = 60_000;
|
|
16
|
+
/** Plain on purpose (see FIND_INPUT_SCHEMA): `parseGatherArgs` enforces every limit. */
|
|
17
|
+
export const GATHER_INPUT_SCHEMA = {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
seeds: { type: 'array', items: { type: 'string' }, description: 'Note paths to start from, usually from find.' },
|
|
21
|
+
sections: { type: 'array', items: { type: 'string' }, description: 'Catalog section ids whose notes to start from (find with no text lists them).' },
|
|
22
|
+
under: { type: 'array', items: { type: 'string' }, description: 'Folders whose notes to start from, e.g. "projects/".' },
|
|
23
|
+
entities: { type: 'array', items: { type: 'string' }, description: 'Note paths whose backlinks to start from: every note linking to them.' },
|
|
24
|
+
hops: { type: 'integer', description: 'How many links to follow out from the starting notes (default 1; 0 returns only them).' },
|
|
25
|
+
direction: { type: 'string', enum: ['in', 'out', 'both'], description: 'Follow links pointing out, in, or both (default both).' },
|
|
26
|
+
type: { type: 'string', description: 'Follow only links of this relation type.' },
|
|
27
|
+
max_notes: { type: 'integer', description: 'Cap on how many notes to return; the omitted count is reported.' },
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
function stringList(args, key) {
|
|
31
|
+
const value = args[key];
|
|
32
|
+
if (value === undefined || value === null)
|
|
33
|
+
return undefined;
|
|
34
|
+
const list = typeof value === 'string' ? [value] : value;
|
|
35
|
+
if (!Array.isArray(list) || !list.every((v) => typeof v === 'string' && v.trim().length > 0)) {
|
|
36
|
+
throw new ToolRefusal('mcp.invalid_arguments', `"${key}" must be a list of non-empty strings.`);
|
|
37
|
+
}
|
|
38
|
+
return list.map((v) => v.trim().replace(/^\.?\/+/, ''));
|
|
39
|
+
}
|
|
40
|
+
function wholeNumber(args, key, min, max) {
|
|
41
|
+
const value = args[key];
|
|
42
|
+
if (value === undefined || value === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
if (typeof value !== 'number' || !Number.isInteger(value) || value < min || value > max) {
|
|
45
|
+
throw new ToolRefusal('mcp.invalid_arguments', `"${key}" must be a whole number from ${min} to ${max}.`);
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
export function parseGatherArgs(args) {
|
|
50
|
+
const out = {
|
|
51
|
+
seeds: stringList(args, 'seeds'),
|
|
52
|
+
sections: stringList(args, 'sections'),
|
|
53
|
+
under: stringList(args, 'under'),
|
|
54
|
+
entities: stringList(args, 'entities'),
|
|
55
|
+
hops: wholeNumber(args, 'hops', 0, 5),
|
|
56
|
+
max_notes: wholeNumber(args, 'max_notes', 1, 500),
|
|
57
|
+
};
|
|
58
|
+
if (args.direction !== undefined && args.direction !== null) {
|
|
59
|
+
if (args.direction !== 'in' && args.direction !== 'out' && args.direction !== 'both') {
|
|
60
|
+
throw new ToolRefusal('mcp.invalid_arguments', '"direction" is one of in, out, both.');
|
|
61
|
+
}
|
|
62
|
+
out.direction = args.direction;
|
|
63
|
+
}
|
|
64
|
+
if (args.type !== undefined && args.type !== null) {
|
|
65
|
+
if (typeof args.type !== 'string')
|
|
66
|
+
throw new ToolRefusal('mcp.invalid_arguments', '"type" must be a string.');
|
|
67
|
+
out.type = args.type;
|
|
68
|
+
}
|
|
69
|
+
if ([out.seeds, out.sections, out.under, out.entities].every((l) => l === undefined || l.length === 0)) {
|
|
70
|
+
throw new ToolRefusal('mcp.invalid_arguments', 'Name at least one starting point: seeds, sections, under or entities. Use find first to get note paths.');
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
export async function gatherWithBodies(snapshot, args, maxBytes = DEFAULT_GATHER_MAX_BYTES) {
|
|
75
|
+
const store = snapshot.store;
|
|
76
|
+
const captureRoot = store.config.ingest.capture_root;
|
|
77
|
+
for (const seed of args.seeds ?? []) {
|
|
78
|
+
if (isUnderAnyPrefix(seed, [captureRoot])) {
|
|
79
|
+
throw new ToolRefusal('mcp.capture_not_filed', `"${seed}" is a capture that has not been filed into a note yet, so it cannot start a gather; read it with Read instead.`, { path: seed });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const notes = await listNotes(store.root, store.config);
|
|
83
|
+
const graph = await readAdmittedGraph(store);
|
|
84
|
+
const pass = await runPass(store, notes, graph, {
|
|
85
|
+
seeds: args.seeds,
|
|
86
|
+
sections: args.sections,
|
|
87
|
+
under: args.under,
|
|
88
|
+
entities: args.entities,
|
|
89
|
+
hops: args.hops,
|
|
90
|
+
direction: args.direction,
|
|
91
|
+
type: args.type,
|
|
92
|
+
maxNotes: args.max_notes,
|
|
93
|
+
});
|
|
94
|
+
let spent = 0;
|
|
95
|
+
let open = true;
|
|
96
|
+
let returned = 0;
|
|
97
|
+
const withBodies = [];
|
|
98
|
+
for (const [index, note] of pass.notes.entries()) {
|
|
99
|
+
if (!open) {
|
|
100
|
+
withBodies.push({ ...note, body: null });
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const text = await readFile(path.join(store.root, note.path), 'utf8');
|
|
104
|
+
const bytes = Buffer.byteLength(text, 'utf8');
|
|
105
|
+
if (spent + bytes <= maxBytes) {
|
|
106
|
+
spent += bytes;
|
|
107
|
+
returned += 1;
|
|
108
|
+
withBodies.push({ ...note, body: text });
|
|
109
|
+
}
|
|
110
|
+
else if (index === 0) {
|
|
111
|
+
// A call never comes back with no text at all: the first note is cut to the budget and says so.
|
|
112
|
+
withBodies.push({ ...note, body: Buffer.from(text, 'utf8').subarray(0, maxBytes).toString('utf8'), body_clipped: true });
|
|
113
|
+
returned += 1;
|
|
114
|
+
open = false;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
withBodies.push({ ...note, body: null });
|
|
118
|
+
open = false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { ...pass, notes: withBodies, bodies: { max_bytes: maxBytes, returned, omitted: pass.notes.length - returned } };
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=gather.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gather.js","sourceRoot":"","sources":["../../../../src/core/mcp/tools/gather.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ToolDefinition } from '../jsonrpc.js';
|
|
2
|
+
import type { Principal } from '../oauth.js';
|
|
3
|
+
import type { Mutex, WriteDeps } from '../sessions.js';
|
|
4
|
+
import type { McpView, SyncDeps } from '../sync.js';
|
|
5
|
+
/**
|
|
6
|
+
* The remote surface's tool set and the prose that describes it
|
|
7
|
+
* (templates/mcp/, shipped-prose-lives-in-templates). Built per request from
|
|
8
|
+
* the server's current state. Reads go through `view.read`, so each sees one
|
|
9
|
+
* commit and names it; writes go through the one mutex (design.md D9, D13).
|
|
10
|
+
*/
|
|
11
|
+
export declare function serverInstructions(storeName: string): string;
|
|
12
|
+
export interface ToolContext {
|
|
13
|
+
view: McpView;
|
|
14
|
+
syncDeps: SyncDeps;
|
|
15
|
+
write: WriteDeps;
|
|
16
|
+
mutex: Mutex;
|
|
17
|
+
/** `serve.base_url` from the loaded configuration. */
|
|
18
|
+
baseUrl: string | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare function buildTools(ctx: ToolContext): ToolDefinition<Principal>[];
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/mcp/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAoBpD;;;;;GAKG;AAEH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,sDAAsD;IACtD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAWD,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,EAAE,CAuGxE"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { packagedTemplate } from '../../templates.js';
|
|
2
|
+
import { asToolRefusal, capture, CAPTURE_INPUT_SCHEMA, parseCaptureArgs } from './capture.js';
|
|
3
|
+
import { EDIT_INPUT_SCHEMA, editTool, parseEditArgs, parseWriteArgs, WRITE_INPUT_SCHEMA, writeTool } from './edit.js';
|
|
4
|
+
import { GLOB_INPUT_SCHEMA, globTool, GREP_INPUT_SCHEMA, grepTool, parseGlobArgs, parseGrepArgs, parseReadArgs, READ_INPUT_SCHEMA, readTool, renderGlob, renderGrep, renderRead, } from './files.js';
|
|
5
|
+
import { find, FIND_INPUT_SCHEMA, parseFindArgs } from './find.js';
|
|
6
|
+
import { GATHER_INPUT_SCHEMA, gatherWithBodies, parseGatherArgs } from './gather.js';
|
|
7
|
+
/**
|
|
8
|
+
* The remote surface's tool set and the prose that describes it
|
|
9
|
+
* (templates/mcp/, shipped-prose-lives-in-templates). Built per request from
|
|
10
|
+
* the server's current state. Reads go through `view.read`, so each sees one
|
|
11
|
+
* commit and names it; writes go through the one mutex (design.md D9, D13).
|
|
12
|
+
*/
|
|
13
|
+
export function serverInstructions(storeName) {
|
|
14
|
+
return packagedTemplate('mcp', 'server-instructions').replaceAll('__STORE_NAME__', storeName);
|
|
15
|
+
}
|
|
16
|
+
/** Writes surface a WriteRefusal as a refusal the client model can read. */
|
|
17
|
+
async function writing(ctx, fn) {
|
|
18
|
+
try {
|
|
19
|
+
return await ctx.mutex.run(fn);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw asToolRefusal(err);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function buildTools(ctx) {
|
|
26
|
+
const read = (fn) => ctx.view.read(ctx.syncDeps, fn);
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
name: 'find',
|
|
30
|
+
title: 'Find in the store',
|
|
31
|
+
description: packagedTemplate('mcp', 'find'),
|
|
32
|
+
inputSchema: FIND_INPUT_SCHEMA,
|
|
33
|
+
scope: 'read',
|
|
34
|
+
readOnly: true,
|
|
35
|
+
run: (args) => {
|
|
36
|
+
const parsed = parseFindArgs(args);
|
|
37
|
+
return read((snapshot) => find(snapshot, parsed, ctx.baseUrl));
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'gather',
|
|
42
|
+
title: 'Gather related notes',
|
|
43
|
+
description: packagedTemplate('mcp', 'gather'),
|
|
44
|
+
inputSchema: GATHER_INPUT_SCHEMA,
|
|
45
|
+
scope: 'read',
|
|
46
|
+
readOnly: true,
|
|
47
|
+
run: (args) => {
|
|
48
|
+
const parsed = parseGatherArgs(args);
|
|
49
|
+
return read((snapshot) => gatherWithBodies(snapshot, parsed));
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'Read',
|
|
54
|
+
title: 'Read a file',
|
|
55
|
+
description: packagedTemplate('mcp', 'Read'),
|
|
56
|
+
inputSchema: READ_INPUT_SCHEMA,
|
|
57
|
+
scope: 'read',
|
|
58
|
+
readOnly: true,
|
|
59
|
+
render: renderRead,
|
|
60
|
+
run: (args, principal) => {
|
|
61
|
+
const parsed = parseReadArgs(args);
|
|
62
|
+
return read((snapshot) => readTool(snapshot, ctx.write, principal.email, parsed));
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'Grep',
|
|
67
|
+
title: 'Search file contents',
|
|
68
|
+
description: packagedTemplate('mcp', 'Grep'),
|
|
69
|
+
inputSchema: GREP_INPUT_SCHEMA,
|
|
70
|
+
scope: 'read',
|
|
71
|
+
readOnly: true,
|
|
72
|
+
render: renderGrep,
|
|
73
|
+
run: (args) => {
|
|
74
|
+
const parsed = parseGrepArgs(args);
|
|
75
|
+
return read((snapshot) => grepTool(snapshot, parsed));
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'Glob',
|
|
80
|
+
title: 'Find files by name',
|
|
81
|
+
description: packagedTemplate('mcp', 'Glob'),
|
|
82
|
+
inputSchema: GLOB_INPUT_SCHEMA,
|
|
83
|
+
scope: 'read',
|
|
84
|
+
readOnly: true,
|
|
85
|
+
render: renderGlob,
|
|
86
|
+
run: (args) => {
|
|
87
|
+
const parsed = parseGlobArgs(args);
|
|
88
|
+
return read((snapshot) => globTool(snapshot, parsed));
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: 'capture',
|
|
93
|
+
title: 'Capture into the store',
|
|
94
|
+
description: packagedTemplate('mcp', 'capture'),
|
|
95
|
+
inputSchema: CAPTURE_INPUT_SCHEMA,
|
|
96
|
+
scope: 'capture',
|
|
97
|
+
readOnly: false,
|
|
98
|
+
run: (args, principal) => {
|
|
99
|
+
const parsed = parseCaptureArgs(args);
|
|
100
|
+
return writing(ctx, () => capture({ view: ctx.view, syncDeps: ctx.syncDeps, write: ctx.write }, principal.email, parsed));
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'Edit',
|
|
105
|
+
title: 'Edit a note',
|
|
106
|
+
description: packagedTemplate('mcp', 'Edit'),
|
|
107
|
+
inputSchema: EDIT_INPUT_SCHEMA,
|
|
108
|
+
scope: 'edit',
|
|
109
|
+
readOnly: false,
|
|
110
|
+
run: (args, principal) => {
|
|
111
|
+
const parsed = parseEditArgs(args);
|
|
112
|
+
return writing(ctx, () => editTool({ view: ctx.view, syncDeps: ctx.syncDeps, write: ctx.write }, principal.email, parsed));
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'Write',
|
|
117
|
+
title: 'Create a note',
|
|
118
|
+
description: packagedTemplate('mcp', 'Write'),
|
|
119
|
+
inputSchema: WRITE_INPUT_SCHEMA,
|
|
120
|
+
scope: 'edit',
|
|
121
|
+
readOnly: false,
|
|
122
|
+
run: (args, principal) => {
|
|
123
|
+
const parsed = parseWriteArgs(args);
|
|
124
|
+
return writing(ctx, () => writeTool({ view: ctx.view, syncDeps: ctx.syncDeps, write: ctx.write }, principal.email, parsed));
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/core/mcp/tools/index.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Kept in sync with package.json's "version" field. */
|
|
2
|
-
export declare const CLI_VERSION = "0.
|
|
2
|
+
export declare const CLI_VERSION = "0.31.0";
|
|
3
3
|
/**
|
|
4
4
|
* The npm package this executable is published as. Bound here, beside the
|
|
5
5
|
* version, because the release check resolves the latest published release by
|
package/dist/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Kept in sync with package.json's "version" field. */
|
|
2
|
-
export const CLI_VERSION = '0.
|
|
2
|
+
export const CLI_VERSION = '0.31.0';
|
|
3
3
|
/**
|
|
4
4
|
* The npm package this executable is published as. Bound here, beside the
|
|
5
5
|
* version, because the release check resolves the latest published release by
|
package/package.json
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Makes an exact string replacement in a note, like a local Edit tool.
|
|
2
|
+
|
|
3
|
+
- Read the note first, and copy `old_string` exactly as it appears, including indentation and line breaks. Do not include the line-number prefix that `Read` shows.
|
|
4
|
+
- The edit fails if `old_string` is not unique in the note. Give more surrounding text to make it unique, or set `replace_all` to change every occurrence.
|
|
5
|
+
- Only notes can be edited: never configuration, the entry document, captures or tool-owned files.
|
|
6
|
+
|
|
7
|
+
Edits do not change the store directly. Each one is saved to your draft, a pull request that collects all of your edits and lands only once someone approves it on the store's approval page. Tell the person that, and give them the approval link the result returns. If someone asked for changes on your draft, more edits go into the same draft.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
A search tool over the store's files, built on ripgrep, with the same parameters as a local Grep tool.
|
|
2
|
+
|
|
3
|
+
- Supports full regular-expression syntax (e.g. `kestrel.*launch`, `^## Decisions`).
|
|
4
|
+
- Filter files with `glob` (e.g. `projects/**/*.md`) or `type` (e.g. `md`).
|
|
5
|
+
- `output_mode`: `content` shows matching lines (with `-n` line numbers, `-A`/`-B`/`-C` context); `files_with_matches` shows only file paths (the default); `count` shows match counts.
|
|
6
|
+
- `multiline: true` lets a pattern span lines.
|
|
7
|
+
- Results are in path order. Use `head_limit` and `offset` to page through many results.
|
|
8
|
+
- Matching captures still awaiting approval are listed after the results. They are not in the store yet.
|
|
9
|
+
|
|
10
|
+
For a plain question about what the store knows, `find` (with glosses and links) is usually the better start. Use Grep for an exact pattern.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Reads a file from the store. Works like a local Read tool: `file_path` is relative to the store root (a leading `/` means the store root), and the result is numbered like `cat -n`, starting at 1.
|
|
2
|
+
|
|
3
|
+
- By default it reads up to 2000 lines from the start; use `offset` and `limit` for longer files.
|
|
4
|
+
- It reads notes, the entry document (`AGENTS.md`), and captures under the inbox. A capture is raw material not yet filed into a note: never present it as what the store says.
|
|
5
|
+
- If you have a pending draft that changed this note (from `Edit` or `Write`), you get your draft's version, marked as such. Other people still see the version in the store until your draft is approved.
|
|
6
|
+
- Configuration, derived files and tool-owned folders cannot be read.
|
|
7
|
+
- A note's result names its page on the store's site. When you cite the note to the person, include that link.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Creates a new note, like a local Write tool, except that it never overwrites. Use `Edit` to change a note that already exists.
|
|
2
|
+
|
|
3
|
+
- `file_path` is relative to the store root and must end in `.md`, e.g. `projects/kestrel-launch.md`. Put it where similar notes live: use `Glob` or `find` to see the store's folders first.
|
|
4
|
+
- Follow the store's conventions for notes (frontmatter, headings, links). `Read` `AGENTS.md` if you have not.
|
|
5
|
+
- Captures of outside material go through `capture`, not `Write`.
|
|
6
|
+
|
|
7
|
+
Like edits, a new note goes into your draft and lands only once someone approves it. Tell the person, and give them the approval link the result returns.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Save one item of outside material — a meeting transcript or notes, an email, a document, a web page — into the store's inbox, where it waits to be reviewed and filed into notes. It never changes an existing note.
|
|
2
|
+
|
|
3
|
+
Rules:
|
|
4
|
+
- Pass the material in its own words. Copy it through; do not condense, reorder, correct or summarise it. If the source supplies its own summary, keep it in a separate section marked as the source's summary, beside the record rather than instead of it.
|
|
5
|
+
- One item per call. Two meetings are two captures.
|
|
6
|
+
- `source_type` names where the material came from, lowercased (for example `email`, `meeting`, `web`, `document`). Use the same word the store already uses for that source.
|
|
7
|
+
- `source_id` is the source system's own identifier for the item when you have one (a message id, a meeting id, a URL). Leave it out when there is none.
|
|
8
|
+
|
|
9
|
+
The store refuses material it already holds, and tells you where; tell the person rather than retrying.
|