@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,130 @@
1
+ import * as path from 'node:path';
2
+ import { createEmbedder, LanceStore } from '@mmnto/totem';
3
+ import { extractChangedFiles, getDefaultBranch, getGitBranchDiff, getGitDiff } from '../git.js';
4
+ import { formatResults, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, writeOutput, } from '../utils.js';
5
+ // ─── Constants ──────────────────────────────────────────
6
+ const TAG = 'Shield';
7
+ const MAX_DIFF_CHARS = 50_000;
8
+ const QUERY_DIFF_TRUNCATE = 2_000;
9
+ const MAX_SPEC_RESULTS = 3;
10
+ const MAX_SESSION_RESULTS = 5;
11
+ const MAX_CODE_RESULTS = 5;
12
+ // ─── System prompt ──────────────────────────────────────
13
+ const SYSTEM_PROMPT = `# Shield System Prompt — Pre-Flight Code Review
14
+
15
+ ## Purpose
16
+ Perform a pre-flight code review on a git diff, using project-specific knowledge to catch traps and anti-patterns before a PR is opened.
17
+
18
+ ## Role
19
+ You are a senior code reviewer analyzing a diff against the project's accumulated knowledge: past session lessons, architectural specs, and codebase conventions. Flag issues the developer might miss, especially ones that have caused problems before.
20
+
21
+ ## Rules
22
+ - Focus on the DIFF — only comment on code that is actually changing
23
+ - Reference specific lines/hunks from the diff when flagging issues
24
+ - Cite Totem knowledge when it directly applies (e.g., "Session #142 found that...")
25
+ - Distinguish severity: CRITICAL (must fix), WARNING (should fix), INFO (consider)
26
+ - Be concise — this is a pre-flight check, not a full RFC
27
+ - If the diff looks clean and follows all known patterns, say so
28
+
29
+ ## Output Format
30
+ Respond with ONLY the sections below. No preamble, no closing remarks.
31
+
32
+ ### Summary
33
+ [1-2 sentences describing what this diff does at a high level]
34
+
35
+ ### Critical Issues
36
+ [Issues that MUST be fixed before merging. If none, say "None found."]
37
+
38
+ ### Warnings
39
+ [Issues that SHOULD be addressed. Include pattern violations, potential regressions, and lessons from past sessions. If none, say "None found."]
40
+
41
+ ### Suggestions
42
+ [Optional improvements and style notes. If none, say "None."]
43
+
44
+ ### Relevant History
45
+ [Specific past traps, lessons, or decisions from Totem knowledge that apply to this diff. If none, say "No relevant history found."]
46
+ `;
47
+ async function retrieveContext(query, store) {
48
+ const search = (typeFilter, maxResults) => store.search({ query, typeFilter, maxResults });
49
+ const [specs, sessions, code] = await Promise.all([
50
+ search('spec', MAX_SPEC_RESULTS),
51
+ search('session_log', MAX_SESSION_RESULTS),
52
+ search('code', MAX_CODE_RESULTS),
53
+ ]);
54
+ return { specs, sessions, code };
55
+ }
56
+ function buildSearchQuery(changedFiles, diff) {
57
+ const fileNames = changedFiles.map((f) => path.basename(f)).join(' ');
58
+ const diffSnippet = diff.slice(0, QUERY_DIFF_TRUNCATE);
59
+ return `${fileNames} ${diffSnippet}`.trim();
60
+ }
61
+ // ─── Prompt assembly ────────────────────────────────────
62
+ function assemblePrompt(diff, changedFiles, context) {
63
+ const sections = [SYSTEM_PROMPT];
64
+ // Diff section
65
+ sections.push('=== DIFF ===');
66
+ sections.push(`Changed files: ${changedFiles.join(', ')}`);
67
+ sections.push('');
68
+ if (diff.length > MAX_DIFF_CHARS) {
69
+ sections.push(diff.slice(0, MAX_DIFF_CHARS));
70
+ sections.push(`\n... [diff truncated at ${MAX_DIFF_CHARS} chars] ...`);
71
+ }
72
+ else {
73
+ sections.push(diff);
74
+ }
75
+ // Totem knowledge
76
+ const specSection = formatResults(context.specs, 'RELATED SPECS & ADRs');
77
+ const sessionSection = formatResults(context.sessions, 'RELATED SESSION HISTORY & LESSONS');
78
+ const codeSection = formatResults(context.code, 'RELATED CODE PATTERNS');
79
+ if (specSection || sessionSection || codeSection) {
80
+ sections.push('\n=== TOTEM KNOWLEDGE ===');
81
+ if (specSection)
82
+ sections.push(specSection);
83
+ if (sessionSection)
84
+ sections.push(sessionSection);
85
+ if (codeSection)
86
+ sections.push(codeSection);
87
+ }
88
+ return sections.join('\n');
89
+ }
90
+ export async function shieldCommand(options) {
91
+ const cwd = process.cwd();
92
+ const configPath = resolveConfigPath(cwd);
93
+ loadEnv(cwd);
94
+ const config = await loadConfig(configPath);
95
+ // Get git diff — try uncommitted/staged first, fall back to branch diff vs main
96
+ const mode = options.staged ? 'staged' : 'all';
97
+ console.error(`[${TAG}] Getting ${mode === 'staged' ? 'staged' : 'uncommitted'} diff...`);
98
+ let diff = getGitDiff(mode, cwd);
99
+ if (!diff.trim()) {
100
+ const base = getDefaultBranch(cwd);
101
+ console.error(`[${TAG}] No uncommitted changes. Falling back to branch diff (${base}...HEAD)...`);
102
+ diff = getGitBranchDiff(cwd, base);
103
+ }
104
+ if (!diff.trim()) {
105
+ console.error(`[${TAG}] No changes detected. Nothing to review.`);
106
+ return;
107
+ }
108
+ const changedFiles = extractChangedFiles(diff);
109
+ console.error(`[${TAG}] Changed files (${changedFiles.length}): ${changedFiles.join(', ')}`);
110
+ // Connect to LanceDB
111
+ const embedder = createEmbedder(config.embedding);
112
+ const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
113
+ await store.connect();
114
+ // Retrieve context from LanceDB
115
+ const query = buildSearchQuery(changedFiles, diff);
116
+ console.error(`[${TAG}] Querying Totem index...`);
117
+ const context = await retrieveContext(query, store);
118
+ const totalResults = context.specs.length + context.sessions.length + context.code.length;
119
+ console.error(`[${TAG}] Found: ${context.specs.length} specs, ${context.sessions.length} sessions, ${context.code.length} code chunks`);
120
+ // Assemble prompt
121
+ const prompt = assemblePrompt(diff, changedFiles, context);
122
+ console.error(`[${TAG}] Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
123
+ const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd, totalResults });
124
+ if (content != null) {
125
+ writeOutput(content, options.out);
126
+ if (options.out)
127
+ console.error(`[${TAG}] Written to ${options.out}`);
128
+ }
129
+ }
130
+ //# sourceMappingURL=shield.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield.js","sourceRoot":"","sources":["../../src/commands/shield.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface SpecOptions {
2
+ raw?: boolean;
3
+ out?: string;
4
+ model?: string;
5
+ }
6
+ export declare function specCommand(input: string, options: SpecOptions): Promise<void>;
7
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../src/commands/spec.ts"],"names":[],"mappings":"AAwKA,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CpF"}
@@ -0,0 +1,159 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import * as path from 'node:path';
3
+ import { z } from 'zod';
4
+ import { createEmbedder, LanceStore } from '@mmnto/totem';
5
+ import { formatResults, GH_TIMEOUT_MS, IS_WIN, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, writeOutput, } from '../utils.js';
6
+ // ─── Constants ──────────────────────────────────────────
7
+ const TAG = 'Spec';
8
+ const QUERY_BODY_TRUNCATE = 500;
9
+ // ─── System prompt ──────────────────────────────────────
10
+ const SYSTEM_PROMPT = `# Spec System Prompt — Pre-Work Briefing
11
+
12
+ ## Purpose
13
+ Produce a structured pre-work briefing for a GitHub issue before implementation begins.
14
+
15
+ ## Role
16
+ You are a technical spec writer analyzing a GitHub issue and its related project context. Your job is to produce a focused briefing that identifies: relevant history, files to examine, implementation approach, traps, and test plan.
17
+
18
+ ## Rules
19
+ - File paths must reference actual files from the context provided
20
+ - Cite related issues by number (#NNN) when relevant
21
+ - Identify edge cases the issue description doesn't mention
22
+ - Be concise — this is a briefing, not a full proposal
23
+ - When multiple approaches exist, list trade-offs with a clear recommendation
24
+
25
+ ## Output Format
26
+ Respond with ONLY the sections below. No preamble, no closing remarks.
27
+
28
+ ### Problem
29
+ [1-2 sentences restating the issue in concrete implementation terms. What exactly needs to change?]
30
+
31
+ ### Historical Context
32
+ [Relevant sessions, PRs, decisions, related issues from the provided Totem knowledge. If nothing relevant, say "None found in provided context."]
33
+
34
+ ### Files to Examine
35
+ [Ordered list of files the developer should read before starting. Most critical first. Format: \`path/to/file.ts\` — reason to examine]
36
+
37
+ ### Approach
38
+ [Recommended implementation approach. Concrete steps, not abstract descriptions. If multiple valid approaches exist, list them as Option A / Option B with trade-offs and a clear recommendation.]
39
+
40
+ ### Edge Cases & Traps
41
+ [Things the issue description doesn't mention but the developer should watch for. Include existing patterns that MUST be followed for consistency and potential regressions in related features.]
42
+
43
+ ### Test Plan
44
+ [Specific test scenarios. Reference existing test file patterns when applicable.]
45
+
46
+ ### Related Issues
47
+ [Issues that might be affected by or related to this work. Format: #NNN — title — relationship (blocks, unblocks, overlaps, conflicts). If none found, say "None identified."]
48
+ `;
49
+ // ─── GitHub helpers ─────────────────────────────────────
50
+ const GhIssueSchema = z.object({
51
+ number: z.number(),
52
+ title: z.string(),
53
+ body: z.string().nullable(),
54
+ labels: z.array(z.object({ name: z.string() })),
55
+ state: z.string(),
56
+ });
57
+ function fetchIssue(issueNumber, cwd) {
58
+ try {
59
+ const result = execFileSync('gh', ['issue', 'view', String(issueNumber), '--json', 'number,title,body,labels,state'], { cwd, encoding: 'utf-8', timeout: GH_TIMEOUT_MS, shell: IS_WIN });
60
+ return GhIssueSchema.parse(JSON.parse(result));
61
+ }
62
+ catch (err) {
63
+ if (err instanceof z.ZodError) {
64
+ throw new Error(`[Totem Error] Failed to parse GitHub issue response: ${err.message}`);
65
+ }
66
+ const msg = err instanceof Error ? err.message : String(err);
67
+ if (msg.includes('ENOENT') || msg.includes('not found')) {
68
+ throw new Error(`[Totem Error] GitHub CLI (gh) is required for issue fetching. Install: https://cli.github.com`);
69
+ }
70
+ throw new Error(`[Totem Error] Failed to fetch issue #${issueNumber}: ${msg}`);
71
+ }
72
+ }
73
+ async function retrieveContext(query, store) {
74
+ const search = (typeFilter, maxResults) => store.search({ query, typeFilter, maxResults });
75
+ const [specs, sessions, code] = await Promise.all([
76
+ search('spec', 5),
77
+ search('session_log', 5),
78
+ search('code', 3),
79
+ ]);
80
+ return { specs, sessions, code };
81
+ }
82
+ function buildSearchQuery(issue) {
83
+ const labels = issue.labels.map((l) => l.name).join(' ');
84
+ const bodySnippet = (issue.body ?? '').slice(0, QUERY_BODY_TRUNCATE);
85
+ return `${issue.title} ${labels} ${bodySnippet}`.trim();
86
+ }
87
+ // ─── Prompt assembly ────────────────────────────────────
88
+ function assemblePrompt(issue, freeText, context) {
89
+ const sections = [SYSTEM_PROMPT];
90
+ // Target issue or free-text topic
91
+ if (issue) {
92
+ const issueLabels = issue.labels.map((l) => l.name).join(', ');
93
+ sections.push('=== TARGET ISSUE ===');
94
+ sections.push(`Issue #${issue.number}: ${issue.title}`);
95
+ sections.push(`Labels: ${issueLabels || '(none)'}`);
96
+ sections.push(`State: ${issue.state}`);
97
+ if (issue.body) {
98
+ sections.push('');
99
+ sections.push(issue.body);
100
+ }
101
+ }
102
+ else if (freeText) {
103
+ sections.push('=== TOPIC ===');
104
+ sections.push(freeText);
105
+ }
106
+ // Totem knowledge
107
+ const specSection = formatResults(context.specs, 'RELATED SPECS & ADRs');
108
+ const sessionSection = formatResults(context.sessions, 'RELATED SESSION HISTORY');
109
+ const codeSection = formatResults(context.code, 'RELATED CODE');
110
+ if (specSection || sessionSection || codeSection) {
111
+ sections.push('\n=== TOTEM KNOWLEDGE ===');
112
+ if (specSection)
113
+ sections.push(specSection);
114
+ if (sessionSection)
115
+ sections.push(sessionSection);
116
+ if (codeSection)
117
+ sections.push(codeSection);
118
+ }
119
+ return sections.join('\n');
120
+ }
121
+ export async function specCommand(input, options) {
122
+ const cwd = process.cwd();
123
+ const configPath = resolveConfigPath(cwd);
124
+ loadEnv(cwd);
125
+ const config = await loadConfig(configPath);
126
+ // Connect to LanceDB
127
+ const embedder = createEmbedder(config.embedding);
128
+ const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
129
+ await store.connect();
130
+ // Parse input: issue number or free-text
131
+ const issueNumber = /^\d+$/.test(input) ? parseInt(input, 10) : null;
132
+ let issue = null;
133
+ let query;
134
+ if (issueNumber) {
135
+ console.error(`[${TAG}] Fetching issue #${issueNumber}...`);
136
+ issue = fetchIssue(issueNumber, cwd);
137
+ console.error(`[${TAG}] Title: ${issue.title}`);
138
+ query = buildSearchQuery(issue);
139
+ }
140
+ else {
141
+ console.error(`[${TAG}] Topic: ${input}`);
142
+ query = input;
143
+ }
144
+ // Retrieve context from LanceDB
145
+ console.error(`[${TAG}] Querying Totem index...`);
146
+ const context = await retrieveContext(query, store);
147
+ const totalResults = context.specs.length + context.sessions.length + context.code.length;
148
+ console.error(`[${TAG}] Found: ${context.specs.length} specs, ${context.sessions.length} sessions, ${context.code.length} code chunks`);
149
+ // Assemble prompt
150
+ const prompt = assemblePrompt(issue, issueNumber ? null : input, context);
151
+ console.error(`[${TAG}] Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
152
+ const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd, totalResults });
153
+ if (content != null) {
154
+ writeOutput(content, options.out);
155
+ if (options.out)
156
+ console.error(`[${TAG}] Written to ${options.out}`);
157
+ }
158
+ }
159
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../../src/commands/spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function statsCommand(): Promise<void>;
2
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AAMA,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAsBlD"}
@@ -0,0 +1,22 @@
1
+ import * as path from 'node:path';
2
+ import { createEmbedder, LanceStore } from '@mmnto/totem';
3
+ import { loadConfig, loadEnv, resolveConfigPath } from '../utils.js';
4
+ export async function statsCommand() {
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 { totalChunks, byType } = await store.stats();
13
+ console.log(`[Totem] Index statistics:`);
14
+ console.log(` Total chunks: ${totalChunks}`);
15
+ for (const [type, count] of Object.entries(byType)) {
16
+ console.log(` ${type}: ${count}`);
17
+ }
18
+ if (totalChunks === 0) {
19
+ console.log('\n No data indexed yet. Run `totem sync` first.');
20
+ }
21
+ }
22
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErE,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,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,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IAEpD,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,mBAAmB,WAAW,EAAE,CAAC,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function syncCommand(options: {
2
+ full?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAIA,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5E"}
@@ -0,0 +1,16 @@
1
+ import { runSync } from '@mmnto/totem';
2
+ import { loadConfig, loadEnv, resolveConfigPath } from '../utils.js';
3
+ export async function syncCommand(options) {
4
+ const cwd = process.cwd();
5
+ const configPath = resolveConfigPath(cwd);
6
+ loadEnv(cwd);
7
+ const config = await loadConfig(configPath);
8
+ const incremental = !options.full;
9
+ const result = await runSync(config, {
10
+ projectRoot: cwd,
11
+ incremental,
12
+ onProgress: (msg) => console.log(`[Totem] ${msg}`),
13
+ });
14
+ console.log(`[Totem] Done: ${result.chunksProcessed} chunks from ${result.filesProcessed} files`);
15
+ }
16
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,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,WAAW,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;IAElC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE;QACnC,WAAW,EAAE,GAAG;QAChB,WAAW;QACX,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC;KACnD,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,eAAe,gBAAgB,MAAM,CAAC,cAAc,QAAQ,CAAC,CAAC;AACpG,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface TriageOptions {
2
+ raw?: boolean;
3
+ out?: string;
4
+ model?: string;
5
+ }
6
+ export declare function triageCommand(options: TriageOptions): Promise<void>;
7
+ //# sourceMappingURL=triage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/commands/triage.ts"],"names":[],"mappings":"AAkKA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwCzE"}
@@ -0,0 +1,149 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import * as path from 'node:path';
3
+ import { z } from 'zod';
4
+ import { createEmbedder, LanceStore } from '@mmnto/totem';
5
+ import { formatResults, GH_TIMEOUT_MS, IS_WIN, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, writeOutput, } from '../utils.js';
6
+ // ─── Constants ──────────────────────────────────────────
7
+ const TAG = 'Triage';
8
+ const MAX_SPEC_RESULTS = 5;
9
+ const MAX_SESSION_RESULTS = 5;
10
+ const QUERY_TITLES_TRUNCATE = 2_000;
11
+ const GH_ISSUE_LIMIT = 100;
12
+ // ─── System prompt ──────────────────────────────────────
13
+ const SYSTEM_PROMPT = `# Triage System Prompt — Active Work Roadmap
14
+
15
+ ## Purpose
16
+ Produce a prioritized roadmap from the project's open GitHub issues, informed by recent work history from Totem knowledge.
17
+
18
+ ## Role
19
+ You are a technical project manager analyzing a project's open issue backlog alongside its recent development history. Your job is to produce a clear, actionable prioritization that helps the developer decide what to work on next.
20
+
21
+ ## Rules
22
+ - Reference issues by number (#NNN) and title
23
+ - Consider labels (bug, enhancement, priority, etc.) as strong signals
24
+ - Use recent session history and specs to understand project momentum — what was just finished, what's in progress
25
+ - Factor in issue age (updatedAt) — stale issues may need re-evaluation
26
+ - Be opinionated — give a clear recommendation, not a wishy-washy list
27
+ - Be concise — this is a decision-making tool, not a project plan
28
+
29
+ ## Output Format
30
+ Respond with ONLY the sections below. No preamble, no closing remarks.
31
+
32
+ ### Active Work Summary
33
+ [1-3 sentences about what was recently completed or is in progress, based on the Totem knowledge provided. If no relevant history, say "No recent session history available."]
34
+
35
+ ### Prioritized Roadmap
36
+ [Ordered list of open issues, most important first. For each: #NNN — title — 1-sentence rationale for its priority position. Group by priority tier if helpful (e.g., "Do Next", "Up Next", "Backlog").]
37
+
38
+ ### Next Issue
39
+ [Single recommended issue to work on next. Include: issue number, title, and 2-3 sentences explaining WHY this should be next — considering dependencies, momentum, and impact.]
40
+
41
+ ### Blocked / Needs Input
42
+ [Issues that cannot progress without external input, decisions, or prerequisite work. If none, say "None identified."]
43
+ `;
44
+ // ─── GitHub helpers ─────────────────────────────────────
45
+ const GhIssueListItemSchema = z.object({
46
+ number: z.number(),
47
+ title: z.string(),
48
+ labels: z.array(z.object({ name: z.string() })),
49
+ updatedAt: z.string().datetime(),
50
+ });
51
+ function fetchOpenIssues(cwd) {
52
+ try {
53
+ const result = execFileSync('gh', [
54
+ 'issue',
55
+ 'list',
56
+ '--state',
57
+ 'open',
58
+ '--json',
59
+ 'number,title,labels,updatedAt',
60
+ '--limit',
61
+ String(GH_ISSUE_LIMIT),
62
+ ], { cwd, encoding: 'utf-8', timeout: GH_TIMEOUT_MS, shell: IS_WIN });
63
+ return z.array(GhIssueListItemSchema).parse(JSON.parse(result));
64
+ }
65
+ catch (err) {
66
+ if (err instanceof z.ZodError) {
67
+ throw new Error(`[Totem Error] Failed to parse GitHub issue list response: ${err.message}`);
68
+ }
69
+ const msg = err instanceof Error ? err.message : String(err);
70
+ if (msg.includes('ENOENT') || msg.includes('not found')) {
71
+ throw new Error(`[Totem Error] GitHub CLI (gh) is required for issue fetching. Install: https://cli.github.com`);
72
+ }
73
+ throw new Error(`[Totem Error] Failed to fetch open issues: ${msg}`);
74
+ }
75
+ }
76
+ async function retrieveContext(query, store) {
77
+ const search = (typeFilter, maxResults) => store.search({ query, typeFilter, maxResults });
78
+ const [specs, sessions] = await Promise.all([
79
+ search('spec', MAX_SPEC_RESULTS),
80
+ search('session_log', MAX_SESSION_RESULTS),
81
+ ]);
82
+ return { specs, sessions };
83
+ }
84
+ function buildSearchQuery(issues) {
85
+ const titles = issues.map((i) => i.title).join(' ');
86
+ const labels = [...new Set(issues.flatMap((i) => i.labels.map((l) => l.name)))].join(' ');
87
+ return `${titles} ${labels}`.slice(0, QUERY_TITLES_TRUNCATE).trim();
88
+ }
89
+ // ─── Prompt assembly ────────────────────────────────────
90
+ function formatIssueInventory(issues) {
91
+ const rows = issues.map((i) => {
92
+ const labels = i.labels.map((l) => l.name).join(', ') || '(none)';
93
+ const updated = i.updatedAt.slice(0, 10); // YYYY-MM-DD
94
+ return `| #${i.number} | ${i.title} | ${labels} | ${updated} |`;
95
+ });
96
+ return ['| Issue | Title | Labels | Updated |', '|---|---|---|---|', ...rows].join('\n');
97
+ }
98
+ function assemblePrompt(issues, context) {
99
+ const sections = [SYSTEM_PROMPT];
100
+ // Issue inventory
101
+ sections.push('=== OPEN ISSUES ===');
102
+ sections.push(`Total: ${issues.length} open issues\n`);
103
+ sections.push(formatIssueInventory(issues));
104
+ // Totem knowledge
105
+ const specSection = formatResults(context.specs, 'RECENT SPECS & ADRs');
106
+ const sessionSection = formatResults(context.sessions, 'RECENT SESSION HISTORY');
107
+ if (specSection || sessionSection) {
108
+ sections.push('\n=== TOTEM KNOWLEDGE ===');
109
+ if (specSection)
110
+ sections.push(specSection);
111
+ if (sessionSection)
112
+ sections.push(sessionSection);
113
+ }
114
+ return sections.join('\n');
115
+ }
116
+ export async function triageCommand(options) {
117
+ const cwd = process.cwd();
118
+ const configPath = resolveConfigPath(cwd);
119
+ loadEnv(cwd);
120
+ const config = await loadConfig(configPath);
121
+ // Fetch open issues
122
+ console.error(`[${TAG}] Fetching open issues...`);
123
+ const issues = fetchOpenIssues(cwd);
124
+ if (issues.length === 0) {
125
+ console.error(`[${TAG}] No open issues found. Nothing to triage.`);
126
+ return;
127
+ }
128
+ console.error(`[${TAG}] Found ${issues.length} open issues.`);
129
+ // Connect to LanceDB
130
+ const embedder = createEmbedder(config.embedding);
131
+ const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
132
+ await store.connect();
133
+ // Retrieve context from LanceDB
134
+ const query = buildSearchQuery(issues);
135
+ console.error(`[${TAG}] Querying Totem index...`);
136
+ const context = await retrieveContext(query, store);
137
+ const totalResults = context.specs.length + context.sessions.length;
138
+ console.error(`[${TAG}] Found: ${context.specs.length} specs, ${context.sessions.length} sessions`);
139
+ // Assemble prompt
140
+ const prompt = assemblePrompt(issues, context);
141
+ console.error(`[${TAG}] Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
142
+ const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd, totalResults });
143
+ if (content != null) {
144
+ writeOutput(content, options.out);
145
+ if (options.out)
146
+ console.error(`[${TAG}] Written to ${options.out}`);
147
+ }
148
+ }
149
+ //# sourceMappingURL=triage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage.js","sourceRoot":"","sources":["../../src/commands/triage.ts"],"names":[],"mappings":"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"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export declare function getGitBranch(cwd: string): string;
2
+ export declare function getGitStatus(cwd: string): string;
3
+ export declare function getGitDiff(mode: 'staged' | 'all', cwd: string): string;
4
+ export declare function getGitDiffStat(cwd: string): string;
5
+ /**
6
+ * Detect the default branch of the remote (e.g. main, master).
7
+ * Falls back to 'main' if detection fails.
8
+ */
9
+ export declare function getDefaultBranch(cwd: string): string;
10
+ export declare function getGitBranchDiff(cwd: string, base?: string): string;
11
+ export declare function extractChangedFiles(diff: string): string[];
12
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAmBA,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUhD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUhD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CActE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWlD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA+BpD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAcnE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAS1D"}