@jigyasudham/veto 3.3.0 → 3.5.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 +89 -7
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/agents/llm-runner.d.ts.map +1 -1
- package/dist/agents/llm-runner.js +78 -8
- package/dist/agents/llm-runner.js.map +1 -1
- package/dist/cli/context-guidance.d.ts +16 -0
- package/dist/cli/context-guidance.d.ts.map +1 -0
- package/dist/cli/context-guidance.js +20 -0
- package/dist/cli/context-guidance.js.map +1 -0
- package/dist/cli/leftover-guides.d.ts +38 -0
- package/dist/cli/leftover-guides.d.ts.map +1 -0
- package/dist/cli/leftover-guides.js +135 -0
- package/dist/cli/leftover-guides.js.map +1 -0
- package/dist/cli/lessons.d.ts +17 -0
- package/dist/cli/lessons.d.ts.map +1 -0
- package/dist/cli/lessons.js +448 -0
- package/dist/cli/lessons.js.map +1 -0
- package/dist/cli/statusline-hosts.d.ts +36 -0
- package/dist/cli/statusline-hosts.d.ts.map +1 -0
- package/dist/cli/statusline-hosts.js +212 -0
- package/dist/cli/statusline-hosts.js.map +1 -0
- package/dist/cli/statusline.d.ts +7 -0
- package/dist/cli/statusline.d.ts.map +1 -1
- package/dist/cli/statusline.js +69 -11
- package/dist/cli/statusline.js.map +1 -1
- package/dist/cli.js +114 -47
- package/dist/cli.js.map +1 -1
- package/dist/council/llm-council.d.ts.map +1 -1
- package/dist/council/llm-council.js +13 -8
- package/dist/council/llm-council.js.map +1 -1
- package/dist/lessons/adapters/claude.d.ts +10 -0
- package/dist/lessons/adapters/claude.d.ts.map +1 -0
- package/dist/lessons/adapters/claude.js +18 -0
- package/dist/lessons/adapters/claude.js.map +1 -0
- package/dist/lessons/adapters/codex.d.ts +7 -0
- package/dist/lessons/adapters/codex.d.ts.map +1 -0
- package/dist/lessons/adapters/codex.js +9 -0
- package/dist/lessons/adapters/codex.js.map +1 -0
- package/dist/lessons/adapters/gemini.d.ts +4 -0
- package/dist/lessons/adapters/gemini.d.ts.map +1 -0
- package/dist/lessons/adapters/gemini.js +44 -0
- package/dist/lessons/adapters/gemini.js.map +1 -0
- package/dist/lessons/adapters/index.d.ts +6 -0
- package/dist/lessons/adapters/index.d.ts.map +1 -0
- package/dist/lessons/adapters/index.js +14 -0
- package/dist/lessons/adapters/index.js.map +1 -0
- package/dist/lessons/adapters/markdown.d.ts +16 -0
- package/dist/lessons/adapters/markdown.d.ts.map +1 -0
- package/dist/lessons/adapters/markdown.js +130 -0
- package/dist/lessons/adapters/markdown.js.map +1 -0
- package/dist/lessons/adapters/types.d.ts +27 -0
- package/dist/lessons/adapters/types.d.ts.map +1 -0
- package/dist/lessons/adapters/types.js +2 -0
- package/dist/lessons/adapters/types.js.map +1 -0
- package/dist/lessons/classify.d.ts +33 -0
- package/dist/lessons/classify.d.ts.map +1 -0
- package/dist/lessons/classify.js +108 -0
- package/dist/lessons/classify.js.map +1 -0
- package/dist/lessons/consent.d.ts +30 -0
- package/dist/lessons/consent.d.ts.map +1 -0
- package/dist/lessons/consent.js +86 -0
- package/dist/lessons/consent.js.map +1 -0
- package/dist/lessons/discover.d.ts +26 -0
- package/dist/lessons/discover.d.ts.map +1 -0
- package/dist/lessons/discover.js +65 -0
- package/dist/lessons/discover.js.map +1 -0
- package/dist/lessons/harvest.d.ts +84 -0
- package/dist/lessons/harvest.d.ts.map +1 -0
- package/dist/lessons/harvest.js +271 -0
- package/dist/lessons/harvest.js.map +1 -0
- package/dist/lessons/identity.d.ts +23 -0
- package/dist/lessons/identity.d.ts.map +1 -0
- package/dist/lessons/identity.js +81 -0
- package/dist/lessons/identity.js.map +1 -0
- package/dist/lessons/manage.d.ts +163 -0
- package/dist/lessons/manage.d.ts.map +1 -0
- package/dist/lessons/manage.js +337 -0
- package/dist/lessons/manage.js.map +1 -0
- package/dist/lessons/mask.d.ts +6 -0
- package/dist/lessons/mask.d.ts.map +1 -0
- package/dist/lessons/mask.js +22 -0
- package/dist/lessons/mask.js.map +1 -0
- package/dist/lessons/on-save.d.ts +18 -0
- package/dist/lessons/on-save.d.ts.map +1 -0
- package/dist/lessons/on-save.js +53 -0
- package/dist/lessons/on-save.js.map +1 -0
- package/dist/lessons/select.d.ts +23 -0
- package/dist/lessons/select.d.ts.map +1 -0
- package/dist/lessons/select.js +136 -0
- package/dist/lessons/select.js.map +1 -0
- package/dist/lessons/source-project.d.ts +9 -0
- package/dist/lessons/source-project.d.ts.map +1 -0
- package/dist/lessons/source-project.js +149 -0
- package/dist/lessons/source-project.js.map +1 -0
- package/dist/lessons/store.d.ts +135 -0
- package/dist/lessons/store.d.ts.map +1 -0
- package/dist/lessons/store.js +222 -0
- package/dist/lessons/store.js.map +1 -0
- package/dist/memory/config.d.ts +27 -0
- package/dist/memory/config.d.ts.map +1 -1
- package/dist/memory/config.js +67 -0
- package/dist/memory/config.js.map +1 -1
- package/dist/memory/local.d.ts.map +1 -1
- package/dist/memory/local.js +19 -1
- package/dist/memory/local.js.map +1 -1
- package/dist/memory/schema.d.ts +1 -1
- package/dist/memory/schema.d.ts.map +1 -1
- package/dist/memory/schema.js +104 -0
- package/dist/memory/schema.js.map +1 -1
- package/dist/server/handlers/council.d.ts.map +1 -1
- package/dist/server/handlers/council.js +40 -4
- package/dist/server/handlers/council.js.map +1 -1
- package/dist/server/handlers/memory.d.ts.map +1 -1
- package/dist/server/handlers/memory.js +13 -3
- package/dist/server/handlers/memory.js.map +1 -1
- package/dist/server/handlers/session.d.ts.map +1 -1
- package/dist/server/handlers/session.js +61 -21
- package/dist/server/handlers/session.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -3
- package/dist/server.js.map +1 -1
- package/dist/transcripts/cache.d.ts +1 -0
- package/dist/transcripts/cache.d.ts.map +1 -1
- package/dist/transcripts/cache.js +0 -0
- package/dist/transcripts/cache.js.map +1 -1
- package/dist/transcripts/claude-paths.d.ts +5 -0
- package/dist/transcripts/claude-paths.d.ts.map +1 -0
- package/dist/transcripts/claude-paths.js +21 -0
- package/dist/transcripts/claude-paths.js.map +1 -0
- package/dist/transcripts/context.d.ts +41 -0
- package/dist/transcripts/context.d.ts.map +1 -0
- package/dist/transcripts/context.js +144 -0
- package/dist/transcripts/context.js.map +1 -0
- package/dist/transcripts/discover.d.ts +12 -2
- package/dist/transcripts/discover.d.ts.map +1 -1
- package/dist/transcripts/discover.js +55 -7
- package/dist/transcripts/discover.js.map +1 -1
- package/dist/transcripts/manage.d.ts +8 -0
- package/dist/transcripts/manage.d.ts.map +1 -1
- package/dist/transcripts/manage.js +28 -13
- package/dist/transcripts/manage.js.map +1 -1
- package/dist/transcripts/mapping.d.ts.map +1 -1
- package/dist/transcripts/mapping.js +4 -2
- package/dist/transcripts/mapping.js.map +1 -1
- package/dist/transcripts/on-save.d.ts +9 -0
- package/dist/transcripts/on-save.d.ts.map +1 -1
- package/dist/transcripts/on-save.js +36 -9
- package/dist/transcripts/on-save.js.map +1 -1
- package/dist/transcripts/project-key.d.ts +4 -0
- package/dist/transcripts/project-key.d.ts.map +1 -0
- package/dist/transcripts/project-key.js +30 -0
- package/dist/transcripts/project-key.js.map +1 -0
- package/dist/transcripts/recall.d.ts +4 -0
- package/dist/transcripts/recall.d.ts.map +1 -1
- package/dist/transcripts/recall.js +6 -5
- package/dist/transcripts/recall.js.map +1 -1
- package/dist/transcripts/stopwords.d.ts +2 -0
- package/dist/transcripts/stopwords.d.ts.map +1 -0
- package/dist/transcripts/stopwords.js +8 -0
- package/dist/transcripts/stopwords.js.map +1 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { parseMarkdownMemory } from './markdown.js';
|
|
3
|
+
// Gemini CLI's save_memory tool appends `- <fact>` lines under this heading in
|
|
4
|
+
// ~/.gemini/GEMINI.md; the rest of the file is the user's own instructions.
|
|
5
|
+
export const GEMINI_MEMORY_HEADING = 'Gemini Added Memories';
|
|
6
|
+
/**
|
|
7
|
+
* One saved fact per section. Anchors hash the fact rather than count bullets,
|
|
8
|
+
* so inserting a memory does not re-key every memory after it.
|
|
9
|
+
*/
|
|
10
|
+
function splitSavedMemories(section) {
|
|
11
|
+
const facts = [];
|
|
12
|
+
const rest = [];
|
|
13
|
+
for (const line of section.text.split('\n').slice(1)) {
|
|
14
|
+
const bullet = /^\s*[-*]\s+(.+)$/.exec(line);
|
|
15
|
+
if (bullet)
|
|
16
|
+
facts.push(bullet[1].trim());
|
|
17
|
+
else if (/^\s+\S/.test(line) && facts.length)
|
|
18
|
+
facts[facts.length - 1] += ` ${line.trim()}`;
|
|
19
|
+
else if (line.trim())
|
|
20
|
+
rest.push(line);
|
|
21
|
+
}
|
|
22
|
+
const seen = new Set();
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const fact of facts) {
|
|
25
|
+
const anchor = `${section.anchor}-${createHash('sha256').update(fact).digest('hex').slice(0, 8)}`;
|
|
26
|
+
if (seen.has(anchor))
|
|
27
|
+
continue;
|
|
28
|
+
seen.add(anchor);
|
|
29
|
+
out.push({ anchor, title: section.title, text: fact });
|
|
30
|
+
}
|
|
31
|
+
if (rest.length)
|
|
32
|
+
out.push({ ...section, text: `${section.title}\n${rest.join('\n')}` });
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
export function parseGeminiMemory(raw, fileName = '') {
|
|
36
|
+
const parsed = parseMarkdownMemory(raw, fileName || 'GEMINI.md');
|
|
37
|
+
if (!parsed.ok || 'skip' in parsed)
|
|
38
|
+
return parsed;
|
|
39
|
+
return {
|
|
40
|
+
...parsed,
|
|
41
|
+
sections: parsed.sections.flatMap(section => section.title === GEMINI_MEMORY_HEADING ? splitSavedMemories(section) : [section]),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/lessons/adapters/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpD,+EAA+E;AAC/E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAE7D;;;GAGG;AACH,SAAS,kBAAkB,CAAC,OAAsB;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;aACpC,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM;YAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;aACtF,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAClG,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QAC/B,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,IAAI,CAAC,MAAM;QAAE,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACxF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,QAAQ,GAAG,EAAE;IAC1D,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,EAAE,QAAQ,IAAI,WAAW,CAAC,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,MAAM,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAClD,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAC1C,OAAO,CAAC,KAAK,KAAK,qBAAqB,CAAC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;KACrF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LessonSource, MemoryParseResult } from './types.js';
|
|
2
|
+
export type { LessonSource, MemoryFrontmatter, MemoryParseResult, MemorySection } from './types.js';
|
|
3
|
+
export { LESSON_SOURCES } from './types.js';
|
|
4
|
+
/** Parse one native-memory document using its host-specific adapter. */
|
|
5
|
+
export declare function parseNativeMemory(source: LessonSource, raw: string, fileName?: string): MemoryParseResult;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lessons/adapters/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAElE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACpG,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQ5C,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,iBAAiB,CAErG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { parseClaudeMemory } from './claude.js';
|
|
2
|
+
import { parseCodexMemory } from './codex.js';
|
|
3
|
+
import { parseGeminiMemory } from './gemini.js';
|
|
4
|
+
export { LESSON_SOURCES } from './types.js';
|
|
5
|
+
const PARSERS = {
|
|
6
|
+
claude: parseClaudeMemory,
|
|
7
|
+
codex: parseCodexMemory,
|
|
8
|
+
gemini: parseGeminiMemory,
|
|
9
|
+
};
|
|
10
|
+
/** Parse one native-memory document using its host-specific adapter. */
|
|
11
|
+
export function parseNativeMemory(source, raw, fileName = '') {
|
|
12
|
+
return PARSERS[source](raw, fileName);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lessons/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,OAAO,GAA+E;IAC1F,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,gBAAgB;IACvB,MAAM,EAAE,iBAAiB;CAC1B,CAAC;AAEF,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,MAAoB,EAAE,GAAW,EAAE,QAAQ,GAAG,EAAE;IAChF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MemoryParseResult, MemorySection } from './types.js';
|
|
2
|
+
export declare function normalizeMarkdown(raw: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Split a Markdown body into section-level notes. Text before the first heading
|
|
5
|
+
* is a note of its own (most Claude entries have no heading at all). Headings
|
|
6
|
+
* inside fenced code are not structure, and a heading with no body is only a
|
|
7
|
+
* document title. Anchors are unique within the document.
|
|
8
|
+
*/
|
|
9
|
+
export declare function splitSections(body: string, fallbackTitle: string): MemorySection[];
|
|
10
|
+
/**
|
|
11
|
+
* Native memory documents are Markdown, optionally with YAML frontmatter.
|
|
12
|
+
* Only shapes that cannot be Markdown count as drift and fail closed; a
|
|
13
|
+
* headingless entry is the normal Claude shape, not drift.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseMarkdownMemory(raw: string, fallbackTitle?: string): MemoryParseResult;
|
|
16
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../../src/lessons/adapters/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMtF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAiDD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,aAAa,EAAE,CAyBlF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,SAAK,GAAG,iBAAiB,CAwBtF"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---[ \t]*(?:\n|$)/;
|
|
2
|
+
const HEADING_RE = /^(#{1,6})\s+(.+?)(?:\s+#+)?\s*$/;
|
|
3
|
+
const FENCE_RE = /^\s*(```|~~~)/;
|
|
4
|
+
export function normalizeMarkdown(raw) {
|
|
5
|
+
return raw.replace(/^\uFEFF/, '').replace(/\r\n?/g, '\n');
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The guide `veto init` used to write over ~/.gemini/GEMINI.md and
|
|
9
|
+
* ~/.codex/AGENTS.override.md. It is Veto's own text, not a host's memory.
|
|
10
|
+
* Every version of it has exactly one heading, so it is always exactly one
|
|
11
|
+
* section, and a host that later appended its own memories below it keeps them.
|
|
12
|
+
*/
|
|
13
|
+
function isVetoGuideSection(section) {
|
|
14
|
+
return section.title === 'Veto MCP Server' && /\bVeto is active\b/.test(section.text);
|
|
15
|
+
}
|
|
16
|
+
function unquote(value) {
|
|
17
|
+
const v = value.trim();
|
|
18
|
+
if (v.length >= 2 && v.startsWith('"') && v.endsWith('"'))
|
|
19
|
+
return v.slice(1, -1).replace(/\\(["\\])/g, '$1');
|
|
20
|
+
if (v.length >= 2 && v.startsWith("'") && v.endsWith("'"))
|
|
21
|
+
return v.slice(1, -1).replace(/''/g, "'");
|
|
22
|
+
return v;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Just enough YAML for memory frontmatter: top-level `name`/`description`, and
|
|
26
|
+
* `type` either top-level (older entries) or nested under `metadata:` (current
|
|
27
|
+
* Claude entries). Block scalars are ignored rather than guessed at.
|
|
28
|
+
*/
|
|
29
|
+
function readFrontmatter(yaml) {
|
|
30
|
+
const out = {};
|
|
31
|
+
let parent = null;
|
|
32
|
+
for (const line of yaml.split('\n')) {
|
|
33
|
+
const m = /^(\s*)([A-Za-z_][\w-]*):[ \t]*(.*)$/.exec(line);
|
|
34
|
+
if (!m)
|
|
35
|
+
continue;
|
|
36
|
+
const [, indent, key, rawValue] = m;
|
|
37
|
+
const value = rawValue.trim();
|
|
38
|
+
if (indent.length === 0) {
|
|
39
|
+
parent = value === '' ? key : null;
|
|
40
|
+
if (value === '' || value === '|' || value === '>')
|
|
41
|
+
continue;
|
|
42
|
+
if (key === 'name')
|
|
43
|
+
out.name = unquote(value);
|
|
44
|
+
else if (key === 'description')
|
|
45
|
+
out.description = unquote(value);
|
|
46
|
+
else if (key === 'type')
|
|
47
|
+
out.type = unquote(value).toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
else if (parent === 'metadata' && key === 'type' && value) {
|
|
50
|
+
out.type = unquote(value).toLowerCase();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
function slug(title) {
|
|
56
|
+
return title.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Split a Markdown body into section-level notes. Text before the first heading
|
|
60
|
+
* is a note of its own (most Claude entries have no heading at all). Headings
|
|
61
|
+
* inside fenced code are not structure, and a heading with no body is only a
|
|
62
|
+
* document title. Anchors are unique within the document.
|
|
63
|
+
*/
|
|
64
|
+
export function splitSections(body, fallbackTitle) {
|
|
65
|
+
const lines = body.split('\n');
|
|
66
|
+
const headings = [];
|
|
67
|
+
let inFence = false;
|
|
68
|
+
lines.forEach((line, index) => {
|
|
69
|
+
if (FENCE_RE.test(line)) {
|
|
70
|
+
inFence = !inFence;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (inFence)
|
|
74
|
+
return;
|
|
75
|
+
const m = HEADING_RE.exec(line);
|
|
76
|
+
if (m)
|
|
77
|
+
headings.push({ index, title: m[2].trim() });
|
|
78
|
+
});
|
|
79
|
+
const raw = [];
|
|
80
|
+
const preamble = lines.slice(0, headings[0]?.index ?? lines.length).join('\n').trim();
|
|
81
|
+
if (preamble)
|
|
82
|
+
raw.push({ base: 'body', title: fallbackTitle, body: preamble });
|
|
83
|
+
headings.forEach((heading, i) => {
|
|
84
|
+
const text = lines.slice(heading.index + 1, headings[i + 1]?.index ?? lines.length).join('\n').trim();
|
|
85
|
+
if (text)
|
|
86
|
+
raw.push({ base: slug(heading.title) || `section-${i + 1}`, title: heading.title, body: text });
|
|
87
|
+
});
|
|
88
|
+
const seen = new Map();
|
|
89
|
+
return raw.map(({ base, title, body: text }) => {
|
|
90
|
+
const n = (seen.get(base) ?? 0) + 1;
|
|
91
|
+
seen.set(base, n);
|
|
92
|
+
return { anchor: n === 1 ? base : `${base}-${n}`, title, text: title ? `${title}\n${text}` : text };
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Native memory documents are Markdown, optionally with YAML frontmatter.
|
|
97
|
+
* Only shapes that cannot be Markdown count as drift and fail closed; a
|
|
98
|
+
* headingless entry is the normal Claude shape, not drift.
|
|
99
|
+
*/
|
|
100
|
+
export function parseMarkdownMemory(raw, fallbackTitle = '') {
|
|
101
|
+
const text = normalizeMarkdown(raw);
|
|
102
|
+
if (text.includes('\u0000'))
|
|
103
|
+
return { ok: false, reason: 'binary content where Markdown was expected' };
|
|
104
|
+
const trimmed = text.trim();
|
|
105
|
+
if (!trimmed)
|
|
106
|
+
return { ok: true, skip: 'empty' };
|
|
107
|
+
if (/^[[{]/.test(trimmed)) {
|
|
108
|
+
try {
|
|
109
|
+
JSON.parse(trimmed);
|
|
110
|
+
return { ok: false, reason: 'JSON document where Markdown was expected' };
|
|
111
|
+
}
|
|
112
|
+
catch { /* Markdown that happens to start with a bracket */ }
|
|
113
|
+
}
|
|
114
|
+
let frontmatter = {};
|
|
115
|
+
let body = text;
|
|
116
|
+
if (text.startsWith('---\n')) {
|
|
117
|
+
const fm = FRONTMATTER_RE.exec(text);
|
|
118
|
+
if (!fm)
|
|
119
|
+
return { ok: false, reason: 'frontmatter is not terminated' };
|
|
120
|
+
frontmatter = readFrontmatter(fm[1]);
|
|
121
|
+
body = text.slice(fm[0].length);
|
|
122
|
+
}
|
|
123
|
+
const title = frontmatter.description || frontmatter.name || fallbackTitle;
|
|
124
|
+
const all = splitSections(body, title);
|
|
125
|
+
const sections = all.filter(section => !isVetoGuideSection(section));
|
|
126
|
+
if (sections.length)
|
|
127
|
+
return { ok: true, frontmatter, sections };
|
|
128
|
+
return { ok: true, skip: all.length ? 'veto-authored' : 'empty' };
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../../src/lessons/adapters/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const LESSON_SOURCES: readonly ["claude", "codex", "gemini"];
|
|
2
|
+
export type LessonSource = (typeof LESSON_SOURCES)[number];
|
|
3
|
+
export type MemorySection = {
|
|
4
|
+
anchor: string;
|
|
5
|
+
/** Heading, or the entry's frontmatter description/name for body text. */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Title and body as one note; this is what gets masked and stored. */
|
|
8
|
+
text: string;
|
|
9
|
+
};
|
|
10
|
+
export type MemoryFrontmatter = {
|
|
11
|
+
name?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Claude memory type: user | feedback | project | reference. */
|
|
14
|
+
type?: string;
|
|
15
|
+
};
|
|
16
|
+
export type MemoryParseResult = {
|
|
17
|
+
ok: true;
|
|
18
|
+
frontmatter: MemoryFrontmatter;
|
|
19
|
+
sections: MemorySection[];
|
|
20
|
+
} | {
|
|
21
|
+
ok: true;
|
|
22
|
+
skip: 'empty' | 'index' | 'veto-authored';
|
|
23
|
+
} | {
|
|
24
|
+
ok: false;
|
|
25
|
+
reason: string;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lessons/adapters/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,wCAAyC,CAAC;AACrE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,GAGvE;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,eAAe,CAAA;CAAE,GAEvD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lessons/adapters/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { LessonSource, MemoryFrontmatter, MemorySection } from './adapters/index.js';
|
|
2
|
+
export type LessonScope = 'project' | 'user' | 'machine';
|
|
3
|
+
/** Which rule set the scope; `veto lessons why` explains it from this. */
|
|
4
|
+
export type ScopeReason = 'global-file' | 'names-project' | 'user-entry' | 'feedback-entry' | 'environment-heading' | 'project-default';
|
|
5
|
+
export type LessonClassification = {
|
|
6
|
+
scope: LessonScope;
|
|
7
|
+
scopeReason: ScopeReason;
|
|
8
|
+
kind: string;
|
|
9
|
+
/** Non-null keeps the note inside its own project, whatever its scope. */
|
|
10
|
+
quarantineReason: string | null;
|
|
11
|
+
};
|
|
12
|
+
export declare function isSensitiveNote(fileName: string, frontmatter: MemoryFrontmatter, sectionTitle: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Scope rules. User and machine scope can come ONLY from the sources below,
|
|
15
|
+
* and even then a note that names its own project is about that project:
|
|
16
|
+
* - a host's GLOBAL file (~/.codex/AGENTS.md, ~/.gemini/GEMINI.md) is the
|
|
17
|
+
* user's own standing instructions → user;
|
|
18
|
+
* - a Claude entry typed `user` or `feedback` → user;
|
|
19
|
+
* - a section whose heading names the environment → machine;
|
|
20
|
+
* - everything else, including anything untyped → project.
|
|
21
|
+
*/
|
|
22
|
+
export declare function classifyLesson(input: {
|
|
23
|
+
source: LessonSource;
|
|
24
|
+
fileName: string;
|
|
25
|
+
global: boolean;
|
|
26
|
+
frontmatter: MemoryFrontmatter;
|
|
27
|
+
section: MemorySection;
|
|
28
|
+
maskedText: string;
|
|
29
|
+
secrets: number;
|
|
30
|
+
/** The note's own project's names (folder, repository); empty for global files. */
|
|
31
|
+
projectNames?: string[];
|
|
32
|
+
}): LessonClassification;
|
|
33
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/lessons/classify.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE1F,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzD,0EAA0E;AAC1E,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,eAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,qBAAqB,GAAG,iBAAiB,CAAC;AAExI,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC,CAAC;AA6DF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAE/G;AASD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,GAAG,oBAAoB,CAWvB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Deterministic classification of a harvested section (council 320c40dc).
|
|
2
|
+
//
|
|
3
|
+
// Scope decides WHERE a note may go; quarantine decides whether it may leave
|
|
4
|
+
// its own project at all. Both are rules, not judgement: "ambiguous" always
|
|
5
|
+
// resolves to the narrower answer, because a wrong narrow call costs a missed
|
|
6
|
+
// note while a wrong wide call spreads text into other projects and vendors.
|
|
7
|
+
// Notes ABOUT secrets, identity, sanitization or credentials never cross scope.
|
|
8
|
+
// Matched on what names the note (file name, entry name and description,
|
|
9
|
+
// section heading), not on every passing mention in its body.
|
|
10
|
+
const SENSITIVE_NAME_RE = /(secret|credential|passw(or)?d|api[-_ ]?key|private[-_ ]?key|ssh[-_ ]?key|access[-_ ]?token|auth[-_ ]?token|api[-_ ]?token|identit(y|ies)|saniti[sz]|\bpii\b|personal|profile|employer)/i;
|
|
11
|
+
// A section whose heading names the shell, console or network environment is a
|
|
12
|
+
// machine lesson (cp1252, Git Bash quoting, dead IPv6). Heading only: a body
|
|
13
|
+
// that merely mentions PowerShell is still a project note.
|
|
14
|
+
const ENVIRONMENT_TITLE_RE = /\b(git[ -]bash|powershell|pwsh|cmd\.exe|wsl|cp\d{3,4}|code ?page|encoding|utf-?8|crlf|line endings?|ipv[46]|dns|proxy|locale|terminal|console|shell)\b/i;
|
|
15
|
+
const URL_RE = /\b(?:https?|ftp|file|ssh|git|wss?):\/\/|\bwww\.[a-z0-9-]+\.[a-z]{2,}/i;
|
|
16
|
+
const EXECUTABLES = [
|
|
17
|
+
'npm', 'npx', 'pnpm', 'yarn', 'bun', 'node', 'deno', 'python3?', 'py', 'pip3?', 'uv', 'uvx', 'git', 'gh',
|
|
18
|
+
'curl', 'wget', 'ssh', 'scp', 'rsync', 'nc', 'ncat', 'telnet', 'ftp', 'docker', 'kubectl', 'helm',
|
|
19
|
+
'terraform', 'aws', 'gcloud', 'az', 'powershell(?:\\.exe)?', 'pwsh', 'cmd(?:\\.exe)?', 'bash', 'sh', 'zsh',
|
|
20
|
+
'sudo', 'chmod', 'chown', 'rm', 'del', 'rmdir', 'mv', 'cp', 'iwr', 'irm', 'iex', 'invoke-webrequest',
|
|
21
|
+
'invoke-restmethod', 'invoke-expression', 'start-process', 'remove-item', 'set-executionpolicy', 'reg',
|
|
22
|
+
'schtasks', 'certutil', 'bitsadmin', 'mshta', 'rundll32', 'regsvr32', 'msiexec', 'winget', 'choco', 'scoop',
|
|
23
|
+
'brew', 'apt(?:-get)?', 'yum', 'dnf', 'cargo', 'make', 'mcp-publisher', 'smithery', 'veto',
|
|
24
|
+
].join('|');
|
|
25
|
+
const EXEC = `(?:${EXECUTABLES})(?:\\.(?:cmd|exe|bat|ps1))?`;
|
|
26
|
+
// Prose lines are NOT scanned for a leading executable ("Make sure…", "Node
|
|
27
|
+
// 22.13 is the floor"); commands are recognised where commands are written:
|
|
28
|
+
// behind a prompt, inside a code span, inside a fence, or after "run".
|
|
29
|
+
const PROMPT_LINE_RE = /(?:^|\n)[ \t]*(?:\$|PS>|PS [^>\n]*>)[ \t]*\S/;
|
|
30
|
+
const COMMAND_SPAN_RE = new RegExp('`[ \\t]*(?:\\$[ \\t]*)?' + EXEC + '(?:[ \\t][^`]*)?`', 'i');
|
|
31
|
+
const FENCED_LINE_RE = new RegExp(`^[ \\t]*(?:\\$[ \\t]*)?${EXEC}(?:[ \\t]|$)`, 'i');
|
|
32
|
+
const SHELL_FENCE_RE = /(?:^|\n)[ \t]*(?:```|~~~)[ \t]*(?:bash|sh|zsh|shell|console|terminal|powershell|pwsh|ps1?|cmd|bat|batch)\b/i;
|
|
33
|
+
const PIPE_TO_SHELL_RE = /\|\s*(?:sh|bash|zsh|iex|invoke-expression|powershell|pwsh)\b/i;
|
|
34
|
+
const RUN_DIRECTIVE_RE = new RegExp(`\\b(?:run|execute|exec|type|paste|invoke)\\s+[\`'"]?${EXEC}\\b`, 'i');
|
|
35
|
+
const DIRECTIVE_RES = [
|
|
36
|
+
/\b(?:ignore|disregard|override|forget)\b[^.\n]{0,30}\b(?:previous|prior|above|system|all|earlier)\b[^.\n]{0,20}\b(?:instructions?|rules?|prompts?|guidelines?)\b/i,
|
|
37
|
+
/\b(?:always|must|should)\s+(?:run|execute)\s+(?:this|these|it|them|the following)\b/i,
|
|
38
|
+
/\b(?:always|must|should)\s+(?:download|fetch|install|open|visit|send|upload)\b/i,
|
|
39
|
+
/\b(?:download|fetch)\b[^.\n]{0,60}\b(?:from|url|link|script)\b/i,
|
|
40
|
+
/\b(?:send|post|upload|exfiltrate|forward)\b[^.\n]{0,60}\bto\b[^.\n]{0,40}(?:\[email redacted\]|server|endpoint|webhook|url|address)/i,
|
|
41
|
+
];
|
|
42
|
+
function fencedCommand(text) {
|
|
43
|
+
let inFence = false;
|
|
44
|
+
for (const line of text.split('\n')) {
|
|
45
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
46
|
+
inFence = !inFence;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (inFence && FENCED_LINE_RE.test(line))
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
function quarantineReason(text, secrets, sensitive) {
|
|
55
|
+
if (sensitive)
|
|
56
|
+
return 'sensitive';
|
|
57
|
+
if (secrets > 0 || /REDACTED\[sha256:/.test(text))
|
|
58
|
+
return 'credential';
|
|
59
|
+
if (URL_RE.test(text))
|
|
60
|
+
return 'url';
|
|
61
|
+
if (SHELL_FENCE_RE.test(text) || PROMPT_LINE_RE.test(text) || COMMAND_SPAN_RE.test(text) || fencedCommand(text)
|
|
62
|
+
|| PIPE_TO_SHELL_RE.test(text) || RUN_DIRECTIVE_RE.test(text))
|
|
63
|
+
return 'command';
|
|
64
|
+
if (DIRECTIVE_RES.some(re => re.test(text)))
|
|
65
|
+
return 'directive';
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
export function isSensitiveNote(fileName, frontmatter, sectionTitle) {
|
|
69
|
+
return [fileName, frontmatter.name, frontmatter.description, sectionTitle].some(label => SENSITIVE_NAME_RE.test(label ?? ''));
|
|
70
|
+
}
|
|
71
|
+
function namesProject(text, names) {
|
|
72
|
+
return names.some(name => {
|
|
73
|
+
const pattern = name.trim().split(/[\s_-]+/).map(part => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('[\\s_-]+');
|
|
74
|
+
return pattern && new RegExp(`(?<![\\p{L}\\p{N}])${pattern}(?![\\p{L}\\p{N}])`, 'iu').test(text);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Scope rules. User and machine scope can come ONLY from the sources below,
|
|
79
|
+
* and even then a note that names its own project is about that project:
|
|
80
|
+
* - a host's GLOBAL file (~/.codex/AGENTS.md, ~/.gemini/GEMINI.md) is the
|
|
81
|
+
* user's own standing instructions → user;
|
|
82
|
+
* - a Claude entry typed `user` or `feedback` → user;
|
|
83
|
+
* - a section whose heading names the environment → machine;
|
|
84
|
+
* - everything else, including anything untyped → project.
|
|
85
|
+
*/
|
|
86
|
+
export function classifyLesson(input) {
|
|
87
|
+
const type = input.frontmatter.type;
|
|
88
|
+
const kind = type ?? (input.global ? 'instructions' : 'note');
|
|
89
|
+
let scope = 'project';
|
|
90
|
+
let scopeReason = 'project-default';
|
|
91
|
+
if (input.global) {
|
|
92
|
+
scope = 'user';
|
|
93
|
+
scopeReason = 'global-file';
|
|
94
|
+
}
|
|
95
|
+
else if (namesProject(input.maskedText, input.projectNames ?? []))
|
|
96
|
+
scopeReason = 'names-project';
|
|
97
|
+
else if (type === 'user' || type === 'feedback') {
|
|
98
|
+
scope = 'user';
|
|
99
|
+
scopeReason = `${type}-entry`;
|
|
100
|
+
}
|
|
101
|
+
else if (ENVIRONMENT_TITLE_RE.test(input.section.title)) {
|
|
102
|
+
scope = 'machine';
|
|
103
|
+
scopeReason = 'environment-heading';
|
|
104
|
+
}
|
|
105
|
+
const sensitive = isSensitiveNote(input.fileName, input.frontmatter, input.section.title);
|
|
106
|
+
return { scope, scopeReason, kind, quarantineReason: quarantineReason(input.maskedText, input.secrets, sensitive) };
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=classify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/lessons/classify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type LessonSyncReport } from './harvest.js';
|
|
2
|
+
/**
|
|
3
|
+
* What each AI CLI sets in the environment of the commands it runs.
|
|
4
|
+
* CLAUDECODE and AI_AGENT are set by Claude Code (checked on this machine);
|
|
5
|
+
* GEMINI_CLI by Gemini CLI's shell tool; the CODEX_ ones by Codex's sandboxed
|
|
6
|
+
* and npm-launched runs. A real terminal is required as well, so a marker a
|
|
7
|
+
* host does not set is not the only line of defence.
|
|
8
|
+
*/
|
|
9
|
+
export declare const AI_SESSION_MARKERS: readonly ["CLAUDECODE", "AI_AGENT", "GEMINI_CLI", "CODEX_SANDBOX", "CODEX_SANDBOX_NETWORK_DISABLED", "CODEX_MANAGED_BY_NPM"];
|
|
10
|
+
/** The marker showing an AI is running this command, or null in the user's own terminal. */
|
|
11
|
+
export declare function detectAiSession(env?: NodeJS.ProcessEnv): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* The disclosure shown before the user accepts. Changing what it promises
|
|
14
|
+
* means bumping LESSONS_CONSENT_VERSION, and so does starting delivery: this
|
|
15
|
+
* text promises to ask again first.
|
|
16
|
+
*/
|
|
17
|
+
export declare function lessonsDisclosure(): string;
|
|
18
|
+
export type ConsentSummary = {
|
|
19
|
+
report: LessonSyncReport;
|
|
20
|
+
notes: number;
|
|
21
|
+
projects: number;
|
|
22
|
+
anyProject: number;
|
|
23
|
+
ownProject: number;
|
|
24
|
+
unlinked: number;
|
|
25
|
+
byHost: Record<'claude' | 'codex' | 'gemini', number>;
|
|
26
|
+
disabledHosts: string[];
|
|
27
|
+
};
|
|
28
|
+
/** Record consent, read every AI's memory once, and summarise what was found. */
|
|
29
|
+
export declare function acceptLessonsConsent(home?: string): ConsentSummary;
|
|
30
|
+
//# sourceMappingURL=consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/lessons/consent.ts"],"names":[],"mappings":"AAOA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGxE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,8HAA+H,CAAC;AAE/J,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,IAAI,CAEnF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CA0C1C;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,QAAQ,GAAG,OAAO,GAAG,QAAQ,EAAE,MAAM,CAAC,CAAC;IACtD,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB,CAAC;AAEF,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAelE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Consent v2 for Harvest-and-Share (council 320c40dc, legal conditions): it
|
|
2
|
+
// names both flows, across projects and between AI vendors, is OFF by default,
|
|
3
|
+
// and no upgrade can switch it on. Only the user can accept it, typing "yes"
|
|
4
|
+
// in a terminal of their own: a command an AI runs is refused, so no AI can
|
|
5
|
+
// turn sharing on for them (owner decision, 2026-09-19).
|
|
6
|
+
import { enableLessonsSharing } from '../memory/config.js';
|
|
7
|
+
import { syncLessonSources } from './harvest.js';
|
|
8
|
+
import { lessonFlows, lessonsStatus, unresolvedFolders } from './manage.js';
|
|
9
|
+
/**
|
|
10
|
+
* What each AI CLI sets in the environment of the commands it runs.
|
|
11
|
+
* CLAUDECODE and AI_AGENT are set by Claude Code (checked on this machine);
|
|
12
|
+
* GEMINI_CLI by Gemini CLI's shell tool; the CODEX_ ones by Codex's sandboxed
|
|
13
|
+
* and npm-launched runs. A real terminal is required as well, so a marker a
|
|
14
|
+
* host does not set is not the only line of defence.
|
|
15
|
+
*/
|
|
16
|
+
export const AI_SESSION_MARKERS = ['CLAUDECODE', 'AI_AGENT', 'GEMINI_CLI', 'CODEX_SANDBOX', 'CODEX_SANDBOX_NETWORK_DISABLED', 'CODEX_MANAGED_BY_NPM'];
|
|
17
|
+
/** The marker showing an AI is running this command, or null in the user's own terminal. */
|
|
18
|
+
export function detectAiSession(env = process.env) {
|
|
19
|
+
return AI_SESSION_MARKERS.find(name => (env[name] ?? '') !== '') ?? null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The disclosure shown before the user accepts. Changing what it promises
|
|
23
|
+
* means bumping LESSONS_CONSENT_VERSION, and so does starting delivery: this
|
|
24
|
+
* text promises to ask again first.
|
|
25
|
+
*/
|
|
26
|
+
export function lessonsDisclosure() {
|
|
27
|
+
return [
|
|
28
|
+
'What you are turning on: sharing between your AIs\' notes',
|
|
29
|
+
'',
|
|
30
|
+
'Claude, Codex and Gemini each keep notes in their own memory (Claude\'s',
|
|
31
|
+
'memory folders, ~/.codex/AGENTS.md, ~/.gemini/GEMINI.md). With sharing on,',
|
|
32
|
+
'Veto passes those notes on where they help:',
|
|
33
|
+
'',
|
|
34
|
+
' • ACROSS YOUR PROJECTS: a note about you or this computer, written while',
|
|
35
|
+
' you worked on one project, can be shared into your other projects.',
|
|
36
|
+
' • BETWEEN AIs: a note one AI wrote can be shared with the others, so a',
|
|
37
|
+
' note Claude wrote can reach Codex and Gemini, and the other way round.',
|
|
38
|
+
' A note given to an AI goes to that AI\'s company as part of your',
|
|
39
|
+
' conversation, like anything else you send it.',
|
|
40
|
+
'',
|
|
41
|
+
'What Veto does, and does not do:',
|
|
42
|
+
' • It only reads those memory files. It never changes or deletes them.',
|
|
43
|
+
' • It reads them again each time you save a session, so notes you make',
|
|
44
|
+
' today are picked up without you running anything. `veto lessons off`',
|
|
45
|
+
' stops it, and so does turning harvest_on_save off in Veto\'s config.',
|
|
46
|
+
' • It keeps a copy of each note in its own database on this computer,',
|
|
47
|
+
' with email addresses, your home folder and anything that looks like a',
|
|
48
|
+
' password or key removed first. Veto itself uploads nothing.',
|
|
49
|
+
' • A note stays in its own project if it is about that project, or if it',
|
|
50
|
+
' contains a command, a web address, a credential or an instruction to',
|
|
51
|
+
' fetch, send or run something. Notes about secrets or personal details',
|
|
52
|
+
' never leave their project.',
|
|
53
|
+
' • A shared note is marked as information from another AI session, never',
|
|
54
|
+
' as an instruction to follow.',
|
|
55
|
+
'',
|
|
56
|
+
'For now this is a trial: Veto reads the notes and keeps its own masked',
|
|
57
|
+
'copy of them on this computer, but gives none of them to any AI yet, and',
|
|
58
|
+
'works out nothing about which ones it would give. Before it starts giving',
|
|
59
|
+
'notes to your AIs, Veto will ask you again.',
|
|
60
|
+
'',
|
|
61
|
+
'You stay in control:',
|
|
62
|
+
' veto lessons list every note Veto has read',
|
|
63
|
+
' veto lessons why <id> one note, where it came from, where it may go',
|
|
64
|
+
' veto lessons forget <id> stop one note for good',
|
|
65
|
+
' veto lessons exclude keep the current project out entirely',
|
|
66
|
+
' veto lessons off turn sharing off and delete everything Veto copied',
|
|
67
|
+
].join('\n');
|
|
68
|
+
}
|
|
69
|
+
/** Record consent, read every AI's memory once, and summarise what was found. */
|
|
70
|
+
export function acceptLessonsConsent(home) {
|
|
71
|
+
enableLessonsSharing();
|
|
72
|
+
const report = syncLessonSources(home);
|
|
73
|
+
const status = lessonsStatus();
|
|
74
|
+
const flows = lessonFlows();
|
|
75
|
+
return {
|
|
76
|
+
report,
|
|
77
|
+
notes: status.notes,
|
|
78
|
+
projects: new Set(flows.filter(f => !f.projectIdentity.startsWith('global:')).map(f => f.projectIdentity)).size,
|
|
79
|
+
anyProject: status.anyProject,
|
|
80
|
+
ownProject: flows.reduce((sum, f) => sum + f.ownProject + f.nowhere, 0),
|
|
81
|
+
unlinked: unresolvedFolders().length,
|
|
82
|
+
byHost: status.byHost,
|
|
83
|
+
disabledHosts: [...status.disabledHosts.keys()],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=consent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.js","sourceRoot":"","sources":["../../src/lessons/consent.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,4EAA4E;AAC5E,yDAAyD;AAEzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAyB,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE5E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,gCAAgC,EAAE,sBAAsB,CAAU,CAAC;AAE/J,4FAA4F;AAC5F,MAAM,UAAU,eAAe,CAAC,MAAyB,OAAO,CAAC,GAAG;IAClE,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;AAC3E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,2DAA2D;QAC3D,EAAE;QACF,yEAAyE;QACzE,4EAA4E;QAC5E,6CAA6C;QAC7C,EAAE;QACF,4EAA4E;QAC5E,wEAAwE;QACxE,0EAA0E;QAC1E,4EAA4E;QAC5E,sEAAsE;QACtE,mDAAmD;QACnD,EAAE;QACF,kCAAkC;QAClC,yEAAyE;QACzE,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,2EAA2E;QAC3E,iEAAiE;QACjE,2EAA2E;QAC3E,0EAA0E;QAC1E,2EAA2E;QAC3E,gCAAgC;QAChC,2EAA2E;QAC3E,kCAAkC;QAClC,EAAE;QACF,wEAAwE;QACxE,0EAA0E;QAC1E,2EAA2E;QAC3E,6CAA6C;QAC7C,EAAE;QACF,sBAAsB;QACtB,uDAAuD;QACvD,4EAA4E;QAC5E,qDAAqD;QACrD,oEAAoE;QACpE,iFAAiF;KAClF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAaD,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,IAAa;IAChD,oBAAoB,EAAE,CAAC;IACvB,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,OAAO;QACL,MAAM;QACN,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI;QAC/G,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACvE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,MAAM;QACpC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,aAAa,EAAE,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LessonSource } from './adapters/index.js';
|
|
2
|
+
export type NativeMemorySource = {
|
|
3
|
+
source: LessonSource;
|
|
4
|
+
sourcePath: string;
|
|
5
|
+
fileName: string;
|
|
6
|
+
mtimeMs: number;
|
|
7
|
+
/** A host-wide file every session of that host loads, not tied to a project. */
|
|
8
|
+
global: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The host's own directory this file was found under. A memory file is only
|
|
11
|
+
* followed while it resolves inside it, so a link dropped into a memory
|
|
12
|
+
* folder cannot make the harvester read somewhere else. Not the user's home:
|
|
13
|
+
* CODEX_HOME and a relocated Claude directory both live wherever they like.
|
|
14
|
+
*/
|
|
15
|
+
root: string;
|
|
16
|
+
/** Claude only: the ~/.claude/projects/<slug> folder the entry lives in. */
|
|
17
|
+
claudeFolder?: string;
|
|
18
|
+
claudeSlug?: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Known native-memory locations only; discovery reads directory listings and
|
|
22
|
+
* file metadata and performs no writes. CODEX_HOME relocates ~/.codex, as it
|
|
23
|
+
* does for Codex itself.
|
|
24
|
+
*/
|
|
25
|
+
export declare function discoverNativeMemorySources(home?: string): NativeMemorySource[];
|
|
26
|
+
//# sourceMappingURL=discover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/lessons/discover.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA8BF;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,SAAY,GAAG,kBAAkB,EAAE,CAUlF"}
|