@mmnto/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/commands/briefing.d.ts +7 -0
  2. package/dist/commands/briefing.d.ts.map +1 -0
  3. package/dist/commands/briefing.js +134 -0
  4. package/dist/commands/briefing.js.map +1 -0
  5. package/dist/commands/handoff.d.ts +7 -0
  6. package/dist/commands/handoff.d.ts.map +1 -0
  7. package/dist/commands/handoff.js +119 -0
  8. package/dist/commands/handoff.js.map +1 -0
  9. package/dist/commands/init.d.ts +2 -0
  10. package/dist/commands/init.d.ts.map +1 -0
  11. package/dist/commands/init.js +227 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/commands/install-hooks.d.ts +4 -0
  14. package/dist/commands/install-hooks.d.ts.map +1 -0
  15. package/dist/commands/install-hooks.js +125 -0
  16. package/dist/commands/install-hooks.js.map +1 -0
  17. package/dist/commands/learn.d.ts +14 -0
  18. package/dist/commands/learn.d.ts.map +1 -0
  19. package/dist/commands/learn.js +323 -0
  20. package/dist/commands/learn.js.map +1 -0
  21. package/dist/commands/search.d.ts +5 -0
  22. package/dist/commands/search.d.ts.map +1 -0
  23. package/dist/commands/search.js +31 -0
  24. package/dist/commands/search.js.map +1 -0
  25. package/dist/commands/shield.d.ts +8 -0
  26. package/dist/commands/shield.d.ts.map +1 -0
  27. package/dist/commands/shield.js +130 -0
  28. package/dist/commands/shield.js.map +1 -0
  29. package/dist/commands/spec.d.ts +7 -0
  30. package/dist/commands/spec.d.ts.map +1 -0
  31. package/dist/commands/spec.js +159 -0
  32. package/dist/commands/spec.js.map +1 -0
  33. package/dist/commands/stats.d.ts +2 -0
  34. package/dist/commands/stats.d.ts.map +1 -0
  35. package/dist/commands/stats.js +22 -0
  36. package/dist/commands/stats.js.map +1 -0
  37. package/dist/commands/sync.d.ts +4 -0
  38. package/dist/commands/sync.d.ts.map +1 -0
  39. package/dist/commands/sync.js +16 -0
  40. package/dist/commands/sync.js.map +1 -0
  41. package/dist/commands/triage.d.ts +7 -0
  42. package/dist/commands/triage.d.ts.map +1 -0
  43. package/dist/commands/triage.js +149 -0
  44. package/dist/commands/triage.js.map +1 -0
  45. package/dist/git.d.ts +12 -0
  46. package/dist/git.d.ts.map +1 -0
  47. package/dist/git.js +127 -0
  48. package/dist/git.js.map +1 -0
  49. package/dist/index.d.ts +3 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +178 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/utils.d.ts +48 -0
  54. package/dist/utils.d.ts.map +1 -0
  55. package/dist/utils.js +224 -0
  56. package/dist/utils.js.map +1 -0
  57. package/package.json +51 -0
@@ -0,0 +1,125 @@
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
+ const TOTEM_HOOK_MARKER = '[totem] post-merge hook';
6
+ function detectSyncCommand(cwd) {
7
+ if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {
8
+ return 'pnpm exec totem sync --incremental';
9
+ }
10
+ if (fs.existsSync(path.join(cwd, 'yarn.lock'))) {
11
+ return 'yarn totem sync --incremental';
12
+ }
13
+ return 'npx totem sync --incremental';
14
+ }
15
+ function buildHookContent(syncCmd) {
16
+ return `#!/bin/sh
17
+ # ${TOTEM_HOOK_MARKER} — background re-index after pull/merge.
18
+
19
+ echo "[totem] Triggering background re-index..."
20
+ (${syncCmd} > .git/totem-sync.log 2>&1) &
21
+ `;
22
+ }
23
+ function detectHookManager(cwd) {
24
+ if (fs.existsSync(path.join(cwd, '.husky'))) {
25
+ return 'husky';
26
+ }
27
+ if (fs.existsSync(path.join(cwd, 'lefthook.yml')) ||
28
+ fs.existsSync(path.join(cwd, '.lefthook.yml'))) {
29
+ return 'lefthook';
30
+ }
31
+ const pkgPath = path.join(cwd, 'package.json');
32
+ if (fs.existsSync(pkgPath)) {
33
+ try {
34
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
35
+ if (pkg['simple-git-hooks']) {
36
+ return 'simple-git-hooks';
37
+ }
38
+ }
39
+ catch {
40
+ console.log('[Totem] Warning: could not parse package.json while detecting hook manager.');
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ function printHookManagerGuidance(manager, syncCmd) {
46
+ switch (manager) {
47
+ case 'husky':
48
+ console.log('[Totem] Detected husky. Add Totem to your post-merge hook:');
49
+ console.log(` echo '${syncCmd}' >> .husky/post-merge`);
50
+ console.log(' chmod +x .husky/post-merge');
51
+ break;
52
+ case 'lefthook':
53
+ console.log('[Totem] Detected lefthook. Add to your lefthook.yml:');
54
+ console.log(' post-merge:');
55
+ console.log(' commands:');
56
+ console.log(' totem-sync:');
57
+ console.log(` run: ${syncCmd}`);
58
+ break;
59
+ case 'simple-git-hooks':
60
+ console.log('[Totem] Detected simple-git-hooks. Add to your package.json:');
61
+ console.log(' "simple-git-hooks": {');
62
+ console.log(` "post-merge": "${syncCmd}"`);
63
+ console.log(' }');
64
+ break;
65
+ }
66
+ }
67
+ export async function installPostMergeHook(cwd, rl) {
68
+ // Guard: must be a git repo
69
+ if (!fs.existsSync(path.join(cwd, '.git'))) {
70
+ console.log('[Totem] Not a git repository — skipping hook installation.');
71
+ return;
72
+ }
73
+ const syncCmd = detectSyncCommand(cwd);
74
+ const manager = detectHookManager(cwd);
75
+ if (manager) {
76
+ printHookManagerGuidance(manager, syncCmd);
77
+ return;
78
+ }
79
+ const answer = await rl.question('\nInstall a post-merge git hook to auto-sync Totem after merges? (y/N): ');
80
+ if (answer.trim().toLowerCase() !== 'y' && answer.trim().toLowerCase() !== 'yes') {
81
+ return;
82
+ }
83
+ const hooksDir = path.join(cwd, '.git', 'hooks');
84
+ const hookPath = path.join(hooksDir, 'post-merge');
85
+ // Idempotency: check if already installed
86
+ if (fs.existsSync(hookPath)) {
87
+ const existing = fs.readFileSync(hookPath, 'utf-8');
88
+ if (existing.includes(TOTEM_HOOK_MARKER)) {
89
+ console.log('[Totem] Post-merge hook already installed.');
90
+ return;
91
+ }
92
+ // Append to existing hook
93
+ const separator = existing.endsWith('\n') ? '' : '\n';
94
+ const appendBlock = `${separator}
95
+ # ${TOTEM_HOOK_MARKER} — background re-index after pull/merge.
96
+ echo "[totem] Triggering background re-index..."
97
+ (${syncCmd} > .git/totem-sync.log 2>&1) &
98
+ `;
99
+ fs.appendFileSync(hookPath, appendBlock);
100
+ console.log('[Totem] Appended post-merge hook to existing hook file.');
101
+ return;
102
+ }
103
+ // Create new hook
104
+ fs.mkdirSync(hooksDir, { recursive: true });
105
+ fs.writeFileSync(hookPath, buildHookContent(syncCmd));
106
+ // Make executable (no-op on Windows, git bash handles it)
107
+ try {
108
+ fs.chmodSync(hookPath, 0o755);
109
+ }
110
+ catch {
111
+ // chmod may fail on Windows — hooks still work via git bash
112
+ }
113
+ console.log('[Totem] Installed post-merge hook.');
114
+ }
115
+ export async function installHooksCommand() {
116
+ const cwd = process.cwd();
117
+ const rl = readline.createInterface({ input, output });
118
+ try {
119
+ await installPostMergeHook(cwd, rl);
120
+ }
121
+ finally {
122
+ rl.close();
123
+ }
124
+ }
125
+ //# sourceMappingURL=install-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface ExtractedLesson {
2
+ tags: string[];
3
+ text: string;
4
+ }
5
+ export declare function parseLessons(llmOutput: string): ExtractedLesson[];
6
+ export declare function appendLessons(lessons: ExtractedLesson[], lessonsPath: string): void;
7
+ export interface LearnOptions {
8
+ raw?: boolean;
9
+ out?: string;
10
+ model?: string;
11
+ dryRun?: boolean;
12
+ }
13
+ export declare function learnCommand(prNumber: string, options: LearnOptions): Promise<void>;
14
+ //# sourceMappingURL=learn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learn.d.ts","sourceRoot":"","sources":["../../src/commands/learn.ts"],"names":[],"mappings":"AAuRA,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;AAID,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmGzF"}
@@ -0,0 +1,323 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { z } from 'zod';
5
+ import { createEmbedder, LanceStore, runSync } from '@mmnto/totem';
6
+ import { formatResults, GH_TIMEOUT_MS, IS_WIN, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, } from '../utils.js';
7
+ // ─── Constants ──────────────────────────────────────────
8
+ const TAG = 'Learn';
9
+ const MAX_EXISTING_LESSONS = 10;
10
+ const MAX_REVIEW_BODY_CHARS = 50_000;
11
+ // ─── System prompt ──────────────────────────────────────
12
+ const SYSTEM_PROMPT = `# Learn System Prompt — PR Lesson Extraction
13
+
14
+ ## Purpose
15
+ Extract tactical lessons from a pull request's review comments and discussion.
16
+
17
+ ## Role
18
+ You are a knowledge curator analyzing a PR's review threads. Your job is to distill non-obvious lessons — traps, patterns, decisions with rationale — that will prevent future mistakes.
19
+
20
+ ## Rules
21
+ - Extract ONLY non-obvious lessons (traps, surprising behaviors, pattern decisions with rationale)
22
+ - Ignore GCA boilerplate, simple acknowledgments, nits, and formatting suggestions
23
+ - When a suggestion was DECLINED, the author's rationale is often the most valuable lesson
24
+ - Each lesson should be 1-2 sentences capturing WHAT happened and WHY it matters
25
+ - Tags should be lowercase, comma-separated, reflecting the technical domain
26
+ - If existing lessons are provided, do NOT extract duplicates or near-duplicates
27
+ - If no lessons are worth extracting, output exactly: NONE
28
+
29
+ ## Output Format
30
+ For each lesson, use this exact delimiter format:
31
+
32
+ ---LESSON---
33
+ Tags: tag1, tag2, tag3
34
+ The lesson text. One or two sentences capturing the trap/pattern and WHY it matters.
35
+ ---END---
36
+
37
+ If no lessons found, output exactly: NONE
38
+ `;
39
+ // ─── GitHub helpers ─────────────────────────────────────
40
+ const GhPrSchema = z.object({
41
+ number: z.number(),
42
+ title: z.string(),
43
+ body: z.string().nullable(),
44
+ state: z.string(),
45
+ comments: z.array(z.object({
46
+ author: z.object({ login: z.string() }),
47
+ body: z.string(),
48
+ })),
49
+ reviews: z.array(z.object({
50
+ author: z.object({ login: z.string() }),
51
+ state: z.string(),
52
+ body: z.string(),
53
+ })),
54
+ });
55
+ const GhReviewCommentSchema = z.object({
56
+ id: z.number(),
57
+ user: z.object({ login: z.string() }),
58
+ body: z.string(),
59
+ path: z.string(),
60
+ diff_hunk: z.string(),
61
+ in_reply_to_id: z.number().optional(),
62
+ created_at: z.string().optional(),
63
+ });
64
+ function fetchPr(prNumber, cwd) {
65
+ try {
66
+ const result = execFileSync('gh', ['pr', 'view', String(prNumber), '--json', 'number,title,body,state,comments,reviews'], { cwd, encoding: 'utf-8', timeout: GH_TIMEOUT_MS, shell: IS_WIN });
67
+ return GhPrSchema.parse(JSON.parse(result));
68
+ }
69
+ catch (err) {
70
+ if (err instanceof z.ZodError) {
71
+ throw new Error(`[Totem Error] Failed to parse GitHub PR response: ${err.message}`);
72
+ }
73
+ const msg = err instanceof Error ? err.message : String(err);
74
+ if (msg.includes('ENOENT') || msg.includes('not found')) {
75
+ throw new Error(`[Totem Error] GitHub CLI (gh) is required for PR fetching. Install: https://cli.github.com`);
76
+ }
77
+ throw new Error(`[Totem Error] Failed to fetch PR #${prNumber}: ${msg}`);
78
+ }
79
+ }
80
+ function getRepoNwo(cwd) {
81
+ try {
82
+ const result = execFileSync('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner'], {
83
+ cwd,
84
+ encoding: 'utf-8',
85
+ timeout: GH_TIMEOUT_MS,
86
+ shell: IS_WIN,
87
+ });
88
+ return result.trim();
89
+ }
90
+ catch (err) {
91
+ const msg = err instanceof Error ? err.message : String(err);
92
+ throw new Error(`[Totem Error] Failed to detect repository: ${msg}`);
93
+ }
94
+ }
95
+ function fetchReviewComments(prNumber, cwd) {
96
+ const nwo = getRepoNwo(cwd);
97
+ try {
98
+ const result = execFileSync('gh', ['api', `repos/${nwo}/pulls/${prNumber}/comments`, '--paginate'], { cwd, encoding: 'utf-8', timeout: GH_TIMEOUT_MS, shell: IS_WIN });
99
+ const parsed = JSON.parse(result);
100
+ return z.array(GhReviewCommentSchema).parse(parsed);
101
+ }
102
+ catch (err) {
103
+ if (err instanceof z.ZodError) {
104
+ throw new Error(`[Totem Error] Failed to parse review comments: ${err.message}`);
105
+ }
106
+ const msg = err instanceof Error ? err.message : String(err);
107
+ throw new Error(`[Totem Error] Failed to fetch review comments for PR #${prNumber}: ${msg}`);
108
+ }
109
+ }
110
+ function groupIntoThreads(comments) {
111
+ // Build a map of id -> comment for threading
112
+ const byId = new Map();
113
+ for (const c of comments)
114
+ byId.set(c.id, c);
115
+ // Group by root comment (the one without in_reply_to_id)
116
+ const threadMap = new Map();
117
+ for (const c of comments) {
118
+ const rootId = c.in_reply_to_id ?? c.id;
119
+ const thread = threadMap.get(rootId) ?? [];
120
+ thread.push(c);
121
+ threadMap.set(rootId, thread);
122
+ }
123
+ const threads = [];
124
+ for (const [rootId, threadComments] of threadMap) {
125
+ // Sort by created_at to ensure chronological order within thread
126
+ threadComments.sort((a, b) => {
127
+ if (!a.created_at || !b.created_at)
128
+ return 0;
129
+ return a.created_at.localeCompare(b.created_at);
130
+ });
131
+ const root = byId.get(rootId) ?? threadComments[0];
132
+ threads.push({
133
+ path: root.path,
134
+ diffHunk: root.diff_hunk,
135
+ comments: threadComments.map((c) => ({ author: c.user.login, body: c.body })),
136
+ });
137
+ }
138
+ return threads;
139
+ }
140
+ // ─── LanceDB retrieval ─────────────────────────────────
141
+ async function retrieveExistingLessons(store) {
142
+ return store.search({
143
+ query: 'lesson trap pattern decision',
144
+ typeFilter: 'spec',
145
+ maxResults: MAX_EXISTING_LESSONS,
146
+ });
147
+ }
148
+ // ─── Prompt assembly ────────────────────────────────────
149
+ const GCA_MARKERS = ['Using Gemini Code Assist', 'Gemini Code Assist'];
150
+ function isGcaBoilerplate(body) {
151
+ return GCA_MARKERS.some((marker) => body.includes(marker));
152
+ }
153
+ function assemblePrompt(pr, threads, existingLessons) {
154
+ const sections = [SYSTEM_PROMPT];
155
+ // PR metadata
156
+ sections.push('=== PR METADATA ===');
157
+ sections.push(`PR #${pr.number}: ${pr.title}`);
158
+ sections.push(`State: ${pr.state}`);
159
+ if (pr.body) {
160
+ sections.push('');
161
+ sections.push(pr.body);
162
+ }
163
+ // Review summaries (non-empty review bodies)
164
+ const reviewBodies = pr.reviews.filter((r) => r.body.trim());
165
+ if (reviewBodies.length > 0) {
166
+ sections.push('\n=== REVIEW SUMMARIES ===');
167
+ for (const r of reviewBodies) {
168
+ sections.push(`[${r.author.login} — ${r.state}]`);
169
+ sections.push(r.body);
170
+ sections.push('');
171
+ }
172
+ }
173
+ // Regular PR comments (filter GCA boilerplate)
174
+ const prComments = pr.comments.filter((c) => !isGcaBoilerplate(c.body));
175
+ if (prComments.length > 0) {
176
+ sections.push('\n=== PR COMMENTS ===');
177
+ for (const c of prComments) {
178
+ sections.push(`[${c.author.login}]`);
179
+ sections.push(c.body);
180
+ sections.push('');
181
+ }
182
+ }
183
+ // Inline review comment threads
184
+ if (threads.length > 0) {
185
+ sections.push('\n=== INLINE REVIEW THREADS ===');
186
+ for (const thread of threads) {
187
+ sections.push(`--- ${thread.path} ---`);
188
+ sections.push('```diff');
189
+ sections.push(thread.diffHunk);
190
+ sections.push('```');
191
+ for (const c of thread.comments) {
192
+ sections.push(`[${c.author}]: ${c.body}`);
193
+ }
194
+ sections.push('');
195
+ }
196
+ }
197
+ // Existing lessons for dedup context
198
+ const lessonSection = formatResults(existingLessons, 'EXISTING LESSONS (do NOT duplicate)');
199
+ if (lessonSection) {
200
+ sections.push('\n=== DEDUP CONTEXT ===');
201
+ sections.push(lessonSection);
202
+ }
203
+ // Truncate if needed
204
+ let prompt = sections.join('\n');
205
+ if (prompt.length > MAX_REVIEW_BODY_CHARS) {
206
+ prompt = prompt.slice(0, MAX_REVIEW_BODY_CHARS) + '\n\n... [content truncated] ...';
207
+ }
208
+ return prompt;
209
+ }
210
+ const LESSON_RE = /---LESSON---\s*\nTags:\s*(.+)\n([\s\S]+?)---END---/g;
211
+ export function parseLessons(llmOutput) {
212
+ if (llmOutput.trim() === 'NONE')
213
+ return [];
214
+ const lessons = [];
215
+ let match;
216
+ while ((match = LESSON_RE.exec(llmOutput)) !== null) {
217
+ const tags = match[1]
218
+ .split(',')
219
+ .map((t) => t.trim())
220
+ .filter(Boolean);
221
+ const text = match[2].trim();
222
+ if (text) {
223
+ lessons.push({ tags, text });
224
+ }
225
+ }
226
+ return lessons;
227
+ }
228
+ // ─── Lesson writer ──────────────────────────────────────
229
+ export function appendLessons(lessons, lessonsPath) {
230
+ const dir = path.dirname(lessonsPath);
231
+ if (!fs.existsSync(dir)) {
232
+ fs.mkdirSync(dir, { recursive: true });
233
+ }
234
+ const entries = lessons
235
+ .map((l) => {
236
+ const timestamp = new Date().toISOString();
237
+ const tags = l.tags.join(', ');
238
+ return `\n## Lesson — ${timestamp}\n\n**Tags:** ${tags}\n\n${l.text}\n`;
239
+ })
240
+ .join('');
241
+ fs.appendFileSync(lessonsPath, entries, 'utf-8');
242
+ }
243
+ export async function learnCommand(prNumber, options) {
244
+ const cwd = process.cwd();
245
+ const configPath = resolveConfigPath(cwd);
246
+ loadEnv(cwd);
247
+ const config = await loadConfig(configPath);
248
+ // Validate PR number
249
+ const num = parseInt(prNumber, 10);
250
+ if (isNaN(num) || num <= 0) {
251
+ throw new Error(`[Totem Error] Invalid PR number: '${prNumber}'. Must be a positive integer.`);
252
+ }
253
+ // Fetch PR data
254
+ console.error(`[${TAG}] Fetching PR #${num}...`);
255
+ const pr = fetchPr(num, cwd);
256
+ console.error(`[${TAG}] Title: ${pr.title}`);
257
+ // Fetch inline review comments
258
+ console.error(`[${TAG}] Fetching review comments...`);
259
+ const reviewComments = fetchReviewComments(num, cwd);
260
+ console.error(`[${TAG}] Found ${reviewComments.length} inline review comments`);
261
+ // Filter GCA boilerplate from inline comments
262
+ const filteredComments = reviewComments.filter((c) => !isGcaBoilerplate(c.body));
263
+ // Early exit if no review content
264
+ const hasReviewContent = pr.reviews.some((r) => r.body.trim()) ||
265
+ pr.comments.some((c) => !isGcaBoilerplate(c.body)) ||
266
+ filteredComments.length > 0;
267
+ if (!hasReviewContent) {
268
+ console.error(`[${TAG}] No review content found in PR #${num}. Nothing to extract.`);
269
+ return;
270
+ }
271
+ // Group inline comments into threads
272
+ const threads = groupIntoThreads(filteredComments);
273
+ console.error(`[${TAG}] Grouped into ${threads.length} review threads`);
274
+ // Connect to LanceDB for dedup context
275
+ const embedder = createEmbedder(config.embedding);
276
+ const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
277
+ await store.connect();
278
+ console.error(`[${TAG}] Querying existing lessons for dedup...`);
279
+ const existingLessons = await retrieveExistingLessons(store);
280
+ console.error(`[${TAG}] Found ${existingLessons.length} existing lessons for context`);
281
+ // Assemble prompt
282
+ const prompt = assemblePrompt(pr, threads, existingLessons);
283
+ console.error(`[${TAG}] Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
284
+ // Run orchestrator (handles --raw mode, validation, invocation, telemetry)
285
+ const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd });
286
+ if (content == null)
287
+ return; // --raw mode handled
288
+ // Parse lessons from LLM output
289
+ const lessons = parseLessons(content);
290
+ if (lessons.length === 0) {
291
+ console.error(`[${TAG}] No lessons extracted from PR #${num}.`);
292
+ return;
293
+ }
294
+ console.error(`[${TAG}] Extracted ${lessons.length} lesson(s)`);
295
+ // --dry-run mode: preview lessons without writing
296
+ if (options.dryRun) {
297
+ console.error(`[${TAG}] Dry run — lessons not written.`);
298
+ for (const lesson of lessons) {
299
+ console.log(`\n Tags: ${lesson.tags.join(', ')}`);
300
+ console.log(` ${lesson.text}`);
301
+ }
302
+ return;
303
+ }
304
+ // Append lessons to .totem/lessons.md
305
+ const lessonsPath = path.join(cwd, config.totemDir, 'lessons.md');
306
+ appendLessons(lessons, lessonsPath);
307
+ console.error(`[${TAG}] Appended ${lessons.length} lesson(s) to ${config.totemDir}/lessons.md`);
308
+ // Run incremental sync so lessons are immediately searchable
309
+ console.error(`[${TAG}] Running incremental sync...`);
310
+ const syncResult = await runSync(config, {
311
+ projectRoot: cwd,
312
+ incremental: true,
313
+ onProgress: (msg) => console.error(`[${TAG}] ${msg}`),
314
+ });
315
+ console.error(`[${TAG}] Sync complete: ${syncResult.chunksProcessed} chunks from ${syncResult.filesProcessed} files`);
316
+ // Print summary
317
+ console.log(`\nExtracted ${lessons.length} lesson(s) from PR #${num}:`);
318
+ for (const lesson of lessons) {
319
+ console.log(`\n Tags: ${lesson.tags.join(', ')}`);
320
+ console.log(` ${lesson.text}`);
321
+ }
322
+ }
323
+ //# sourceMappingURL=learn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learn.js","sourceRoot":"","sources":["../../src/commands/learn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function searchCommand(query: string, options: {
2
+ type?: string;
3
+ maxResults?: string;
4
+ }): Promise<void>;
5
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAOA,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,IAAI,CAAC,CAkCf"}
@@ -0,0 +1,31 @@
1
+ import * as path from 'node:path';
2
+ import { ContentTypeSchema, createEmbedder, LanceStore } from '@mmnto/totem';
3
+ import { loadConfig, loadEnv, resolveConfigPath } from '../utils.js';
4
+ export async function searchCommand(query, options) {
5
+ const cwd = process.cwd();
6
+ const configPath = resolveConfigPath(cwd);
7
+ loadEnv(cwd);
8
+ const config = await loadConfig(configPath);
9
+ const embedder = createEmbedder(config.embedding);
10
+ const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
11
+ await store.connect();
12
+ const VALID_TYPES = ContentTypeSchema.options;
13
+ if (options.type && !VALID_TYPES.includes(options.type)) {
14
+ throw new Error(`[Totem Error] Invalid type filter: '${options.type}'. Valid types are: ${VALID_TYPES.join(', ')}`);
15
+ }
16
+ const results = await store.search({
17
+ query,
18
+ typeFilter: options.type,
19
+ maxResults: options.maxResults ? parseInt(options.maxResults, 10) : 5,
20
+ });
21
+ if (results.length === 0) {
22
+ console.log('[Totem] No results found.');
23
+ return;
24
+ }
25
+ for (const result of results) {
26
+ console.log(`\n--- ${result.label} (${result.type}) ---`);
27
+ console.log(`File: ${result.filePath} | Score: ${result.score.toFixed(3)}`);
28
+ console.log(result.content.slice(0, 200) + (result.content.length > 200 ? '...' : ''));
29
+ }
30
+ }
31
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE7E,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,KAAa,EACb,OAA+C;IAE/C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAE1C,OAAO,CAAC,GAAG,CAAC,CAAC;IAEb,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IACxE,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IAEtB,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC;IAC9C,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAmB,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CACb,uCAAuC,OAAO,CAAC,IAAI,uBAAuB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACnG,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC;QACjC,KAAK;QACL,UAAU,EAAE,OAAO,CAAC,IAA+B;QACnD,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KACtE,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,QAAQ,aAAa,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5E,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzF,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface ShieldOptions {
2
+ raw?: boolean;
3
+ out?: string;
4
+ model?: string;
5
+ staged?: boolean;
6
+ }
7
+ export declare function shieldCommand(options: ShieldOptions): Promise<void>;
8
+ //# sourceMappingURL=shield.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield.d.ts","sourceRoot":"","sources":["../../src/commands/shield.ts"],"names":[],"mappings":"AAyHA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDzE"}