@mmnto/cli 0.11.0 → 0.13.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.
Files changed (49) hide show
  1. package/dist/commands/add-lesson.d.ts +2 -0
  2. package/dist/commands/add-lesson.d.ts.map +1 -0
  3. package/dist/commands/{anchor.js → add-lesson.js} +2 -2
  4. package/dist/commands/add-lesson.js.map +1 -0
  5. package/dist/commands/bridge.d.ts +7 -0
  6. package/dist/commands/bridge.d.ts.map +1 -0
  7. package/dist/commands/bridge.js +49 -0
  8. package/dist/commands/bridge.js.map +1 -0
  9. package/dist/commands/bridge.test.d.ts +2 -0
  10. package/dist/commands/bridge.test.d.ts.map +1 -0
  11. package/dist/commands/bridge.test.js +50 -0
  12. package/dist/commands/bridge.test.js.map +1 -0
  13. package/dist/commands/eject.d.ts +5 -0
  14. package/dist/commands/eject.d.ts.map +1 -0
  15. package/dist/commands/eject.js +252 -0
  16. package/dist/commands/eject.js.map +1 -0
  17. package/dist/commands/eject.test.d.ts +2 -0
  18. package/dist/commands/eject.test.d.ts.map +1 -0
  19. package/dist/commands/eject.test.js +99 -0
  20. package/dist/commands/eject.test.js.map +1 -0
  21. package/dist/commands/{learn.d.ts → extract.d.ts} +7 -8
  22. package/dist/commands/extract.d.ts.map +1 -0
  23. package/dist/commands/{learn.js → extract.js} +48 -38
  24. package/dist/commands/extract.js.map +1 -0
  25. package/dist/commands/extract.test.d.ts +2 -0
  26. package/dist/commands/extract.test.d.ts.map +1 -0
  27. package/dist/commands/{learn.test.js → extract.test.js} +14 -56
  28. package/dist/commands/extract.test.js.map +1 -0
  29. package/dist/commands/wrap.d.ts +7 -0
  30. package/dist/commands/wrap.d.ts.map +1 -0
  31. package/dist/commands/wrap.js +26 -0
  32. package/dist/commands/wrap.js.map +1 -0
  33. package/dist/commands/wrap.test.d.ts +2 -0
  34. package/dist/commands/wrap.test.d.ts.map +1 -0
  35. package/dist/commands/wrap.test.js +62 -0
  36. package/dist/commands/wrap.test.js.map +1 -0
  37. package/dist/index.js +47 -6
  38. package/dist/index.js.map +1 -1
  39. package/dist/utils.test.js +2 -2
  40. package/dist/utils.test.js.map +1 -1
  41. package/package.json +3 -2
  42. package/dist/commands/anchor.d.ts +0 -2
  43. package/dist/commands/anchor.d.ts.map +0 -1
  44. package/dist/commands/anchor.js.map +0 -1
  45. package/dist/commands/learn.d.ts.map +0 -1
  46. package/dist/commands/learn.js.map +0 -1
  47. package/dist/commands/learn.test.d.ts +0 -2
  48. package/dist/commands/learn.test.d.ts.map +0 -1
  49. package/dist/commands/learn.test.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ export declare function addLessonCommand(lessonArg?: string): Promise<void>;
2
+ //# sourceMappingURL=add-lesson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-lesson.d.ts","sourceRoot":"","sources":["../../src/commands/add-lesson.ts"],"names":[],"mappings":"AAmBA,wBAAsB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ExE"}
@@ -14,7 +14,7 @@ function detectSyncCommand(cwd) {
14
14
  }
15
15
  return { cmd: IS_WIN ? 'npx.cmd' : 'npx', args: ['totem', 'sync', '--incremental'] };
16
16
  }
17
- export async function anchorCommand(lessonArg) {
17
+ export async function addLessonCommand(lessonArg) {
18
18
  const cwd = process.cwd();
19
19
  const configPath = resolveConfigPath(cwd);
20
20
  loadEnv(cwd);
@@ -81,4 +81,4 @@ export async function anchorCommand(lessonArg) {
81
81
  log.warn('Totem', `Failed to trigger background sync: ${message}`);
82
82
  }
83
83
  }
84
- //# sourceMappingURL=anchor.js.map
84
+ //# sourceMappingURL=add-lesson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-lesson.js","sourceRoot":"","sources":["../../src/commands/add-lesson.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function assembleBridge(branch: string, status: string, message?: string): string;
2
+ export interface BridgeOptions {
3
+ message?: string;
4
+ out?: string;
5
+ }
6
+ export declare function bridgeCommand(options: BridgeOptions): void;
7
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/commands/bridge.ts"],"names":[],"mappings":"AAcA,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA6BvF;AAID,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAqB1D"}
@@ -0,0 +1,49 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { getGitBranch, getGitStatus } from '../git.js';
4
+ import { log } from '../ui.js';
5
+ import { writeOutput } from '../utils.js';
6
+ // ─── Constants ──────────────────────────────────────────
7
+ const TAG = 'Bridge';
8
+ const MAX_STATUS_FILES = 20;
9
+ // ─── Prompt assembly ────────────────────────────────────
10
+ export function assembleBridge(branch, status, message) {
11
+ const sections = ['# Context Bridge'];
12
+ sections.push(`**Branch:** ${branch}`);
13
+ // Summarize modified files
14
+ if (status.trim()) {
15
+ const lines = status.trim().split('\n');
16
+ const fileList = lines.slice(0, MAX_STATUS_FILES).join('\n');
17
+ const summary = lines.length > MAX_STATUS_FILES
18
+ ? `${fileList}\n... and ${lines.length - MAX_STATUS_FILES} more file${lines.length - MAX_STATUS_FILES === 1 ? '' : 's'}`
19
+ : fileList;
20
+ sections.push(`**Modified Files:**\n${summary}`);
21
+ }
22
+ else {
23
+ sections.push('**Modified Files:** (clean working tree)');
24
+ }
25
+ // Breadcrumb message
26
+ if (message) {
27
+ const sanitized = message.replace(/<\/\s*([a-zA-Z0-9_]+)\s*>/gi, '<\\/$1>');
28
+ sections.push(`**Current Task / Breadcrumb:** "${sanitized}"`);
29
+ }
30
+ sections.push('**Instruction:** Resume work based on the current uncommitted changes and the breadcrumb above. Do not restart the task from scratch.');
31
+ return sections.join('\n\n');
32
+ }
33
+ export function bridgeCommand(options) {
34
+ const cwd = process.cwd();
35
+ if (!fs.existsSync(path.join(cwd, '.git'))) {
36
+ throw new Error('[Totem Error] Not a git repository. Run `totem bridge` from a project with git initialized.');
37
+ }
38
+ log.info(TAG, 'Capturing workspace state...');
39
+ const branch = getGitBranch(cwd);
40
+ const status = getGitStatus(cwd);
41
+ log.info(TAG, `Branch: ${branch}`);
42
+ const output = assembleBridge(branch, status, options.message);
43
+ writeOutput(output, options.out);
44
+ if (options.out) {
45
+ log.success(TAG, `Written to ${options.out}`);
46
+ }
47
+ log.success(TAG, 'Context bridge generated. Paste this into your new session.');
48
+ }
49
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/commands/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bridge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.test.d.ts","sourceRoot":"","sources":["../../src/commands/bridge.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { assembleBridge } from './bridge.js';
3
+ describe('assembleBridge', () => {
4
+ it('generates a bridge with branch and clean status', () => {
5
+ const output = assembleBridge('main', '');
6
+ expect(output).toContain('# Context Bridge');
7
+ expect(output).toContain('**Branch:** main');
8
+ expect(output).toContain('(clean working tree)');
9
+ expect(output).toContain('Resume work');
10
+ });
11
+ it('includes modified files from git status', () => {
12
+ const status = ' M src/foo.ts\n M src/bar.ts';
13
+ const output = assembleBridge('feat/test', status);
14
+ expect(output).toContain('src/foo.ts');
15
+ expect(output).toContain('src/bar.ts');
16
+ expect(output).not.toContain('clean working tree');
17
+ });
18
+ it('includes breadcrumb message when provided', () => {
19
+ const output = assembleBridge('main', '', 'Stuck on auth bug in middleware.ts');
20
+ expect(output).toContain('Stuck on auth bug in middleware.ts');
21
+ expect(output).toContain('**Current Task / Breadcrumb:**');
22
+ });
23
+ it('omits breadcrumb section when no message provided', () => {
24
+ const output = assembleBridge('main', '');
25
+ expect(output).not.toContain('Breadcrumb');
26
+ });
27
+ it('truncates file list when more than 20 files', () => {
28
+ const lines = Array.from({ length: 25 }, (_, i) => ` M src/file${i}.ts`);
29
+ const status = lines.join('\n');
30
+ const output = assembleBridge('main', status);
31
+ expect(output).toContain('src/file0.ts');
32
+ expect(output).toContain('src/file19.ts');
33
+ expect(output).not.toContain('src/file20.ts');
34
+ expect(output).toContain('and 5 more files');
35
+ });
36
+ it('escapes closing XML tags in breadcrumb message', () => {
37
+ const output = assembleBridge('main', '', 'Fix </system> injection </TAG >');
38
+ expect(output).toContain('<\\/system>');
39
+ expect(output).toContain('<\\/TAG>');
40
+ expect(output).not.toContain('</system>');
41
+ });
42
+ it('uses singular "file" when exactly 1 file over limit', () => {
43
+ const lines = Array.from({ length: 21 }, (_, i) => ` M src/file${i}.ts`);
44
+ const status = lines.join('\n');
45
+ const output = assembleBridge('main', status);
46
+ expect(output).toContain('and 1 more file');
47
+ expect(output).not.toContain('and 1 more files');
48
+ });
49
+ });
50
+ //# sourceMappingURL=bridge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.test.js","sourceRoot":"","sources":["../../src/commands/bridge.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface EjectOptions {
2
+ force?: boolean;
3
+ }
4
+ export declare function ejectCommand(options: EjectOptions): Promise<void>;
5
+ //# sourceMappingURL=eject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eject.d.ts","sourceRoot":"","sources":["../../src/commands/eject.ts"],"names":[],"mappings":"AAwOA,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DvE"}
@@ -0,0 +1,252 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { stdin as input, stdout as output } from 'node:process';
4
+ import * as readline from 'node:readline/promises';
5
+ import { log } from '../ui.js';
6
+ // ─── Constants ──────────────────────────────────────────
7
+ const TAG = 'Eject';
8
+ const TOTEM_HOOK_MARKER = '[totem] post-merge hook';
9
+ const TOTEM_FILE_MARKER = '// [totem] auto-generated';
10
+ /** Files that may have AI reflex blocks appended by `totem init`. */
11
+ const REFLEX_FILES = ['CLAUDE.md', '.cursorrules'];
12
+ /** Files scaffolded by `totem init` that are fully owned by Totem. */
13
+ const TOTEM_SCAFFOLDED_FILES = [
14
+ '.gemini/hooks/SessionStart.js',
15
+ '.gemini/hooks/BeforeTool.js',
16
+ '.gemini/skills/totem.md',
17
+ '.totem/hooks/shield-gate.cjs',
18
+ ];
19
+ /**
20
+ * Remove the Totem section from the post-merge git hook.
21
+ * Deletes the file entirely if it only contains the Totem hook.
22
+ */
23
+ function scrubPostMergeHook(cwd, summary) {
24
+ const hookPath = path.join(cwd, '.git', 'hooks', 'post-merge');
25
+ if (!fs.existsSync(hookPath)) {
26
+ summary.skipped.push('.git/hooks/post-merge (not found)');
27
+ return;
28
+ }
29
+ const content = fs.readFileSync(hookPath, 'utf-8');
30
+ if (!content.includes(TOTEM_HOOK_MARKER)) {
31
+ summary.skipped.push('.git/hooks/post-merge (no Totem section)');
32
+ return;
33
+ }
34
+ // Remove the Totem block: from the marker comment to the background command
35
+ const lines = content.split('\n');
36
+ const filtered = [];
37
+ let inTotemBlock = false;
38
+ for (const line of lines) {
39
+ if (line.includes(TOTEM_HOOK_MARKER)) {
40
+ inTotemBlock = true;
41
+ continue;
42
+ }
43
+ if (inTotemBlock) {
44
+ // Skip lines until we hit a blank line or non-Totem content
45
+ if (line === '' ||
46
+ line.startsWith('echo "[totem]') ||
47
+ line.startsWith('(') ||
48
+ line.trim() === '') {
49
+ continue;
50
+ }
51
+ inTotemBlock = false;
52
+ }
53
+ filtered.push(line);
54
+ }
55
+ const remaining = filtered.join('\n').trim();
56
+ if (!remaining || remaining === '#!/bin/sh') {
57
+ fs.unlinkSync(hookPath);
58
+ summary.removed.push('.git/hooks/post-merge');
59
+ }
60
+ else {
61
+ fs.writeFileSync(hookPath, remaining + '\n', 'utf-8');
62
+ summary.scrubbed.push('.git/hooks/post-merge');
63
+ }
64
+ }
65
+ /**
66
+ * Remove scaffolded files that are fully owned by Totem.
67
+ * Only removes files that contain the Totem marker to avoid deleting user files.
68
+ */
69
+ function removeScaffoldedFiles(cwd, summary) {
70
+ for (const rel of TOTEM_SCAFFOLDED_FILES) {
71
+ const filePath = path.join(cwd, rel);
72
+ if (!fs.existsSync(filePath))
73
+ continue;
74
+ const content = fs.readFileSync(filePath, 'utf-8');
75
+ if (content.includes(TOTEM_FILE_MARKER) || content.includes('[totem] auto-generated')) {
76
+ fs.unlinkSync(filePath);
77
+ summary.removed.push(rel);
78
+ }
79
+ else {
80
+ summary.skipped.push(`${rel} (no Totem marker)`);
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Remove the Totem PreToolUse hook entry from Claude's settings.local.json.
86
+ */
87
+ function scrubClaudeSettings(cwd, summary) {
88
+ const filePath = path.join(cwd, '.claude', 'settings.local.json');
89
+ if (!fs.existsSync(filePath)) {
90
+ summary.skipped.push('.claude/settings.local.json (not found)');
91
+ return;
92
+ }
93
+ let parsed;
94
+ try {
95
+ parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
96
+ }
97
+ catch {
98
+ summary.skipped.push('.claude/settings.local.json (invalid JSON)');
99
+ return;
100
+ }
101
+ const hooks = parsed.hooks;
102
+ const preToolUse = hooks?.PreToolUse;
103
+ if (!preToolUse) {
104
+ summary.skipped.push('.claude/settings.local.json (no PreToolUse hooks)');
105
+ return;
106
+ }
107
+ const filtered = preToolUse.filter((entry) => {
108
+ if (entry.matcher !== 'Bash')
109
+ return true;
110
+ const entryHooks = entry.hooks ?? [];
111
+ return !entryHooks.some((h) => {
112
+ const cmd = typeof h === 'string'
113
+ ? h
114
+ : h && typeof h === 'object'
115
+ ? (h.command ?? '')
116
+ : '';
117
+ return cmd.includes('shield-gate') || cmd.includes('totem shield');
118
+ });
119
+ });
120
+ if (filtered.length === preToolUse.length) {
121
+ summary.skipped.push('.claude/settings.local.json (no Totem hooks)');
122
+ return;
123
+ }
124
+ hooks.PreToolUse = filtered;
125
+ if (filtered.length === 0) {
126
+ delete hooks.PreToolUse;
127
+ }
128
+ // Clean up empty hooks object
129
+ if (Object.keys(hooks).length === 0) {
130
+ delete parsed.hooks;
131
+ }
132
+ if (Object.keys(parsed).length === 0) {
133
+ fs.unlinkSync(filePath);
134
+ summary.removed.push('.claude/settings.local.json');
135
+ }
136
+ else {
137
+ fs.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + '\n', 'utf-8');
138
+ summary.scrubbed.push('.claude/settings.local.json');
139
+ }
140
+ }
141
+ /**
142
+ * Remove the AI Integration block appended by `totem init` to reflex files.
143
+ */
144
+ function scrubReflexFiles(cwd, summary) {
145
+ for (const rel of REFLEX_FILES) {
146
+ const filePath = path.join(cwd, rel);
147
+ if (!fs.existsSync(filePath))
148
+ continue;
149
+ const content = fs.readFileSync(filePath, 'utf-8');
150
+ // Match the block from the heading to end of file (init always appends at the end)
151
+ const primaryMarker = /\n*## Totem AI Integration \(Auto-Generated\)[\s\S]*$/;
152
+ const altMarker = /\n*## Totem Memory Reflexes[\s\S]*$/;
153
+ const activeMarker = primaryMarker.test(content)
154
+ ? primaryMarker
155
+ : altMarker.test(content)
156
+ ? altMarker
157
+ : null;
158
+ if (!activeMarker) {
159
+ summary.skipped.push(`${rel} (no Totem block)`);
160
+ continue;
161
+ }
162
+ fs.writeFileSync(filePath, content.replace(activeMarker, '\n'), 'utf-8');
163
+ summary.scrubbed.push(rel);
164
+ }
165
+ }
166
+ /**
167
+ * Delete Totem directories and config file.
168
+ */
169
+ function deleteArtifacts(cwd, summary) {
170
+ const artifacts = ['.lancedb', '.totem'];
171
+ for (const dir of artifacts) {
172
+ const dirPath = path.join(cwd, dir);
173
+ if (fs.existsSync(dirPath)) {
174
+ try {
175
+ fs.rmSync(dirPath, { recursive: true, force: true });
176
+ summary.removed.push(`${dir}/`);
177
+ }
178
+ catch (err) {
179
+ const msg = err instanceof Error ? err.message : String(err);
180
+ summary.skipped.push(`${dir}/ (could not delete: ${msg})`);
181
+ }
182
+ }
183
+ else {
184
+ summary.skipped.push(`${dir}/ (not found)`);
185
+ }
186
+ }
187
+ const configPath = path.join(cwd, 'totem.config.ts');
188
+ if (fs.existsSync(configPath)) {
189
+ try {
190
+ fs.unlinkSync(configPath);
191
+ summary.removed.push('totem.config.ts');
192
+ }
193
+ catch (err) {
194
+ const msg = err instanceof Error ? err.message : String(err);
195
+ summary.skipped.push(`totem.config.ts (could not delete: ${msg})`);
196
+ }
197
+ }
198
+ else {
199
+ summary.skipped.push('totem.config.ts (not found)');
200
+ }
201
+ }
202
+ export async function ejectCommand(options) {
203
+ const cwd = process.cwd();
204
+ if (!options.force) {
205
+ const rl = readline.createInterface({ input, output });
206
+ try {
207
+ const answer = await rl.question('This will remove all Totem hooks, config, and data from this project. Continue? (y/N): ');
208
+ if (answer.trim().toLowerCase() !== 'y' && answer.trim().toLowerCase() !== 'yes') {
209
+ log.info(TAG, 'Aborted.');
210
+ return;
211
+ }
212
+ }
213
+ finally {
214
+ rl.close();
215
+ }
216
+ }
217
+ const summary = { removed: [], scrubbed: [], skipped: [] };
218
+ // 1. Scrub git hooks
219
+ scrubPostMergeHook(cwd, summary);
220
+ // 2. Remove scaffolded Gemini/Claude hook files
221
+ removeScaffoldedFiles(cwd, summary);
222
+ // 3. Scrub Claude settings.local.json
223
+ scrubClaudeSettings(cwd, summary);
224
+ // 4. Scrub AI reflex blocks from markdown files
225
+ scrubReflexFiles(cwd, summary);
226
+ // 5. Delete artifacts
227
+ deleteArtifacts(cwd, summary);
228
+ // Print summary
229
+ if (summary.removed.length > 0) {
230
+ log.info(TAG, 'Removed:');
231
+ for (const item of summary.removed) {
232
+ log.success(TAG, ` ${item}`);
233
+ }
234
+ }
235
+ if (summary.scrubbed.length > 0) {
236
+ log.info(TAG, 'Scrubbed (Totem content removed, file preserved):');
237
+ for (const item of summary.scrubbed) {
238
+ log.success(TAG, ` ${item}`);
239
+ }
240
+ }
241
+ if (summary.skipped.length > 0) {
242
+ log.dim(TAG, 'Skipped:');
243
+ for (const item of summary.skipped) {
244
+ log.dim(TAG, ` ${item}`);
245
+ }
246
+ }
247
+ if (summary.removed.length === 0 && summary.scrubbed.length === 0) {
248
+ log.info(TAG, 'Nothing to remove — project appears clean.');
249
+ }
250
+ log.success(TAG, 'Totem has been ejected from this project.');
251
+ }
252
+ //# sourceMappingURL=eject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eject.js","sourceRoot":"","sources":["../../src/commands/eject.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=eject.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eject.test.d.ts","sourceRoot":"","sources":["../../src/commands/eject.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,99 @@
1
+ import * as fs from 'node:fs';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { ejectCommand } from './eject.js';
6
+ function makeTmpDir() {
7
+ return fs.mkdtempSync(path.join(os.tmpdir(), 'totem-eject-'));
8
+ }
9
+ describe('ejectCommand', () => {
10
+ let cwd;
11
+ let originalCwd;
12
+ beforeEach(() => {
13
+ cwd = makeTmpDir();
14
+ originalCwd = process.cwd();
15
+ process.chdir(cwd);
16
+ // Create .git so it looks like a repo
17
+ fs.mkdirSync(path.join(cwd, '.git', 'hooks'), { recursive: true });
18
+ });
19
+ afterEach(() => {
20
+ process.chdir(originalCwd);
21
+ fs.rmSync(cwd, { recursive: true, force: true });
22
+ });
23
+ it('removes post-merge hook when it only contains Totem content', async () => {
24
+ const hookPath = path.join(cwd, '.git', 'hooks', 'post-merge');
25
+ fs.writeFileSync(hookPath, '#!/bin/sh\n# [totem] post-merge hook — background re-index after pull/merge.\n\necho "[totem] Triggering background re-index..."\n(pnpm exec totem sync --incremental > .git/totem-sync.log 2>&1) &\n');
26
+ await ejectCommand({ force: true });
27
+ expect(fs.existsSync(hookPath)).toBe(false);
28
+ });
29
+ it('preserves non-Totem content in post-merge hook', async () => {
30
+ const hookPath = path.join(cwd, '.git', 'hooks', 'post-merge');
31
+ fs.writeFileSync(hookPath, '#!/bin/sh\necho "my custom hook"\n# [totem] post-merge hook — background re-index after pull/merge.\n\necho "[totem] Triggering background re-index..."\n(pnpm exec totem sync --incremental > .git/totem-sync.log 2>&1) &\n');
32
+ await ejectCommand({ force: true });
33
+ expect(fs.existsSync(hookPath)).toBe(true);
34
+ const content = fs.readFileSync(hookPath, 'utf-8');
35
+ expect(content).toContain('my custom hook');
36
+ expect(content).not.toContain('[totem]');
37
+ });
38
+ it('removes scaffolded files with Totem marker', async () => {
39
+ const hookDir = path.join(cwd, '.gemini', 'hooks');
40
+ fs.mkdirSync(hookDir, { recursive: true });
41
+ fs.writeFileSync(path.join(hookDir, 'SessionStart.js'), '// [totem] auto-generated — Gemini CLI SessionStart hook\nconsole.log("hi");');
42
+ await ejectCommand({ force: true });
43
+ expect(fs.existsSync(path.join(hookDir, 'SessionStart.js'))).toBe(false);
44
+ });
45
+ it('does not remove files without Totem marker', async () => {
46
+ const hookDir = path.join(cwd, '.gemini', 'hooks');
47
+ fs.mkdirSync(hookDir, { recursive: true });
48
+ fs.writeFileSync(path.join(hookDir, 'SessionStart.js'), 'console.log("user hook");');
49
+ await ejectCommand({ force: true });
50
+ expect(fs.existsSync(path.join(hookDir, 'SessionStart.js'))).toBe(true);
51
+ });
52
+ it('scrubs AI reflex block from CLAUDE.md', async () => {
53
+ const claudePath = path.join(cwd, 'CLAUDE.md');
54
+ fs.writeFileSync(claudePath, '# My Project\n\nSome instructions.\n\n## Totem AI Integration (Auto-Generated)\nYou have access to the Totem MCP.\n\n### Memory Reflexes\n1. Pull before planning.\n');
55
+ await ejectCommand({ force: true });
56
+ const content = fs.readFileSync(claudePath, 'utf-8');
57
+ expect(content).toContain('# My Project');
58
+ expect(content).toContain('Some instructions.');
59
+ expect(content).not.toContain('Totem AI Integration');
60
+ expect(content).not.toContain('Memory Reflexes');
61
+ });
62
+ it('deletes .lancedb, .totem, and totem.config.ts', async () => {
63
+ fs.mkdirSync(path.join(cwd, '.lancedb'), { recursive: true });
64
+ fs.mkdirSync(path.join(cwd, '.totem'), { recursive: true });
65
+ fs.writeFileSync(path.join(cwd, 'totem.config.ts'), 'export default {};');
66
+ await ejectCommand({ force: true });
67
+ expect(fs.existsSync(path.join(cwd, '.lancedb'))).toBe(false);
68
+ expect(fs.existsSync(path.join(cwd, '.totem'))).toBe(false);
69
+ expect(fs.existsSync(path.join(cwd, 'totem.config.ts'))).toBe(false);
70
+ });
71
+ it('scrubs Claude settings.local.json PreToolUse entry', async () => {
72
+ const settingsDir = path.join(cwd, '.claude');
73
+ fs.mkdirSync(settingsDir, { recursive: true });
74
+ const settings = {
75
+ permissions: { allow: ['Bash'] },
76
+ hooks: {
77
+ PreToolUse: [
78
+ {
79
+ matcher: 'Bash',
80
+ hooks: [{ type: 'command', command: 'node .totem/hooks/shield-gate.cjs' }],
81
+ },
82
+ { matcher: 'Write', hooks: [{ type: 'command', command: 'echo custom' }] },
83
+ ],
84
+ },
85
+ };
86
+ fs.writeFileSync(path.join(settingsDir, 'settings.local.json'), JSON.stringify(settings));
87
+ await ejectCommand({ force: true });
88
+ const updated = JSON.parse(fs.readFileSync(path.join(settingsDir, 'settings.local.json'), 'utf-8'));
89
+ expect(updated.hooks.PreToolUse).toHaveLength(1);
90
+ expect(updated.hooks.PreToolUse[0].matcher).toBe('Write');
91
+ expect(updated.permissions).toBeDefined();
92
+ });
93
+ it('handles clean project with nothing to remove', async () => {
94
+ // No Totem artifacts exist
95
+ await ejectCommand({ force: true });
96
+ // Should not throw
97
+ });
98
+ });
99
+ //# sourceMappingURL=eject.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eject.test.js","sourceRoot":"","sources":["../../src/commands/eject.test.ts"],"names":[],"mappings":"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"}
@@ -5,16 +5,15 @@ export interface ExtractedLesson {
5
5
  export declare function parseLessons(llmOutput: string): ExtractedLesson[];
6
6
  export declare function appendLessons(lessons: ExtractedLesson[], lessonsPath: string): void;
7
7
  /**
8
- * Returns true if lessons should be written, false to abort.
8
+ * Prompts the user to select which lessons to keep via multi-select.
9
+ * Returns the selected lessons, or all lessons if --yes is set.
9
10
  * Throws in non-interactive environments without --yes.
10
11
  */
11
- export declare function confirmLessons(count: number, opts: {
12
+ export declare function selectLessons(lessons: ExtractedLesson[], opts: {
12
13
  yes?: boolean;
13
14
  isTTY?: boolean;
14
- input?: NodeJS.ReadableStream;
15
- output?: NodeJS.WritableStream;
16
- }): Promise<boolean>;
17
- export interface LearnOptions {
15
+ }): Promise<ExtractedLesson[]>;
16
+ export interface ExtractOptions {
18
17
  raw?: boolean;
19
18
  out?: string;
20
19
  model?: string;
@@ -22,5 +21,5 @@ export interface LearnOptions {
22
21
  dryRun?: boolean;
23
22
  yes?: boolean;
24
23
  }
25
- export declare function learnCommand(prNumbers: string[], options: LearnOptions): Promise<void>;
26
- //# sourceMappingURL=learn.d.ts.map
24
+ export declare function extractCommand(prNumbers: string[], options: ExtractOptions): Promise<void>;
25
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/commands/extract.ts"],"names":[],"mappings":"AAyLA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe,EAAE,CAkBjE;AAID,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAenF;AAYD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,eAAe,EAAE,EAC1B,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACvC,OAAO,CAAC,eAAe,EAAE,CAAC,CAyB5B;AAID,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA0KhG"}