@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.
- package/dist/commands/briefing.d.ts +7 -0
- package/dist/commands/briefing.d.ts.map +1 -0
- package/dist/commands/briefing.js +134 -0
- package/dist/commands/briefing.js.map +1 -0
- package/dist/commands/handoff.d.ts +7 -0
- package/dist/commands/handoff.d.ts.map +1 -0
- package/dist/commands/handoff.js +119 -0
- package/dist/commands/handoff.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +227 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install-hooks.d.ts +4 -0
- package/dist/commands/install-hooks.d.ts.map +1 -0
- package/dist/commands/install-hooks.js +125 -0
- package/dist/commands/install-hooks.js.map +1 -0
- package/dist/commands/learn.d.ts +14 -0
- package/dist/commands/learn.d.ts.map +1 -0
- package/dist/commands/learn.js +323 -0
- package/dist/commands/learn.js.map +1 -0
- package/dist/commands/search.d.ts +5 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +31 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/shield.d.ts +8 -0
- package/dist/commands/shield.d.ts.map +1 -0
- package/dist/commands/shield.js +130 -0
- package/dist/commands/shield.js.map +1 -0
- package/dist/commands/spec.d.ts +7 -0
- package/dist/commands/spec.d.ts.map +1 -0
- package/dist/commands/spec.js +159 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/stats.d.ts +2 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +22 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/sync.d.ts +4 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +16 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/triage.d.ts +7 -0
- package/dist/commands/triage.d.ts.map +1 -0
- package/dist/commands/triage.js +149 -0
- package/dist/commands/triage.js.map +1 -0
- package/dist/git.d.ts +12 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +127 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.d.ts +48 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +224 -0
- package/dist/utils.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"briefing.d.ts","sourceRoot":"","sources":["../../src/commands/briefing.ts"],"names":[],"mappings":"AAqJA,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC7E"}
|
|
@@ -0,0 +1,134 @@
|
|
|
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 { getGitBranch, getGitStatus } from '../git.js';
|
|
6
|
+
import { formatResults, GH_TIMEOUT_MS, IS_WIN, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, writeOutput, } from '../utils.js';
|
|
7
|
+
// ─── Constants ──────────────────────────────────────────
|
|
8
|
+
const TAG = 'Briefing';
|
|
9
|
+
const MAX_SPEC_RESULTS = 5;
|
|
10
|
+
const MAX_SESSION_RESULTS = 5;
|
|
11
|
+
// ─── System prompt ──────────────────────────────────────
|
|
12
|
+
const SYSTEM_PROMPT = `# Briefing System Prompt — Session Startup Briefing
|
|
13
|
+
|
|
14
|
+
## Purpose
|
|
15
|
+
Produce a session startup briefing that orients the developer at the start of an AI-assisted work session.
|
|
16
|
+
|
|
17
|
+
## Role
|
|
18
|
+
You are a technical project assistant producing a quick-start briefing. You have access to the current git state, open pull requests, and project knowledge from Totem. Your job is to synthesize this into an actionable summary so the developer knows exactly where they left off and what to do next.
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
- Reference PRs by number (#NNN) and branch name
|
|
22
|
+
- Reference issues by number (#NNN) when they appear in Totem knowledge
|
|
23
|
+
- Be opinionated about what the recommended first action should be
|
|
24
|
+
- Be concise — this is a startup briefing, not a project plan
|
|
25
|
+
- If there are uncommitted changes, flag them prominently
|
|
26
|
+
- If there are no open PRs, say so
|
|
27
|
+
|
|
28
|
+
## Output Format
|
|
29
|
+
Respond with ONLY the sections below. No preamble, no closing remarks.
|
|
30
|
+
|
|
31
|
+
### Session Context
|
|
32
|
+
[Current branch, uncommitted changes summary. If working tree is clean, say so. If on a feature branch, note what it likely relates to.]
|
|
33
|
+
|
|
34
|
+
### Open PRs
|
|
35
|
+
[List of open PRs with number, title, and branch. If none, say "No open PRs." Highlight any that are the developer's current branch.]
|
|
36
|
+
|
|
37
|
+
### Active Priorities
|
|
38
|
+
[Key priorities and recent work context from Totem knowledge — what was recently worked on, what specs are active, what sessions covered. If no relevant knowledge, say "No recent context found in Totem index."]
|
|
39
|
+
|
|
40
|
+
### Recommended First Action
|
|
41
|
+
[Single clear recommendation for what the developer should do first in this session. Consider: uncommitted work to commit/continue, PRs to review/merge, next issue to pick up.]
|
|
42
|
+
`;
|
|
43
|
+
// ─── GitHub helpers ─────────────────────────────────────
|
|
44
|
+
const GhPrListItemSchema = z.object({
|
|
45
|
+
number: z.number(),
|
|
46
|
+
title: z.string(),
|
|
47
|
+
headRefName: z.string(),
|
|
48
|
+
});
|
|
49
|
+
function fetchOpenPRs(cwd) {
|
|
50
|
+
try {
|
|
51
|
+
const result = execFileSync('gh', ['pr', 'list', '--state', 'open', '--json', 'number,title,headRefName'], { cwd, encoding: 'utf-8', timeout: GH_TIMEOUT_MS, shell: IS_WIN });
|
|
52
|
+
return z.array(GhPrListItemSchema).parse(JSON.parse(result));
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
if (err instanceof z.ZodError) {
|
|
56
|
+
throw new Error(`[Totem Error] Failed to parse GitHub PR list response: ${err.message}`);
|
|
57
|
+
}
|
|
58
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
59
|
+
if (msg.includes('ENOENT') || msg.includes('not found')) {
|
|
60
|
+
throw new Error(`[Totem Error] GitHub CLI (gh) is required for PR fetching. Install: https://cli.github.com`);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`[Totem Error] Failed to fetch open PRs: ${msg}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function retrieveContext(query, store) {
|
|
66
|
+
const search = (typeFilter, maxResults) => store.search({ query, typeFilter, maxResults });
|
|
67
|
+
const [specs, sessions] = await Promise.all([
|
|
68
|
+
search('spec', MAX_SPEC_RESULTS),
|
|
69
|
+
search('session_log', MAX_SESSION_RESULTS),
|
|
70
|
+
]);
|
|
71
|
+
return { specs, sessions };
|
|
72
|
+
}
|
|
73
|
+
// ─── Prompt assembly ────────────────────────────────────
|
|
74
|
+
function formatPRList(prs) {
|
|
75
|
+
if (prs.length === 0)
|
|
76
|
+
return '(none)';
|
|
77
|
+
return prs.map((pr) => `- #${pr.number} — ${pr.title} (branch: ${pr.headRefName})`).join('\n');
|
|
78
|
+
}
|
|
79
|
+
function assemblePrompt(branch, status, prs, context) {
|
|
80
|
+
const sections = [SYSTEM_PROMPT];
|
|
81
|
+
// Git state
|
|
82
|
+
sections.push('=== GIT STATE ===');
|
|
83
|
+
sections.push(`Branch: ${branch}`);
|
|
84
|
+
sections.push(`Uncommitted changes:\n${status || '(clean working tree)'}`);
|
|
85
|
+
// Open PRs
|
|
86
|
+
sections.push('\n=== OPEN PULL REQUESTS ===');
|
|
87
|
+
sections.push(formatPRList(prs));
|
|
88
|
+
// Totem knowledge
|
|
89
|
+
const specSection = formatResults(context.specs, 'RECENT SPECS & ADRs');
|
|
90
|
+
const sessionSection = formatResults(context.sessions, 'RECENT SESSION HISTORY');
|
|
91
|
+
if (specSection || sessionSection) {
|
|
92
|
+
sections.push('\n=== TOTEM KNOWLEDGE ===');
|
|
93
|
+
if (specSection)
|
|
94
|
+
sections.push(specSection);
|
|
95
|
+
if (sessionSection)
|
|
96
|
+
sections.push(sessionSection);
|
|
97
|
+
}
|
|
98
|
+
return sections.join('\n');
|
|
99
|
+
}
|
|
100
|
+
export async function briefingCommand(options) {
|
|
101
|
+
const cwd = process.cwd();
|
|
102
|
+
const configPath = resolveConfigPath(cwd);
|
|
103
|
+
loadEnv(cwd);
|
|
104
|
+
const config = await loadConfig(configPath);
|
|
105
|
+
// Gather git state
|
|
106
|
+
console.error(`[${TAG}] Gathering git state...`);
|
|
107
|
+
const branch = getGitBranch(cwd);
|
|
108
|
+
const status = getGitStatus(cwd);
|
|
109
|
+
console.error(`[${TAG}] Branch: ${branch}`);
|
|
110
|
+
// Fetch open PRs
|
|
111
|
+
console.error(`[${TAG}] Fetching open PRs...`);
|
|
112
|
+
const prs = fetchOpenPRs(cwd);
|
|
113
|
+
console.error(`[${TAG}] Found ${prs.length} open PRs.`);
|
|
114
|
+
// Connect to LanceDB
|
|
115
|
+
const embedder = createEmbedder(config.embedding);
|
|
116
|
+
const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
|
|
117
|
+
await store.connect();
|
|
118
|
+
// Retrieve context from LanceDB
|
|
119
|
+
const query = `${branch} active work session priorities`;
|
|
120
|
+
console.error(`[${TAG}] Querying Totem index...`);
|
|
121
|
+
const context = await retrieveContext(query, store);
|
|
122
|
+
const totalResults = context.specs.length + context.sessions.length;
|
|
123
|
+
console.error(`[${TAG}] Found: ${context.specs.length} specs, ${context.sessions.length} sessions`);
|
|
124
|
+
// Assemble prompt
|
|
125
|
+
const prompt = assemblePrompt(branch, status, prs, context);
|
|
126
|
+
console.error(`[${TAG}] Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
|
|
127
|
+
const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd, totalResults });
|
|
128
|
+
if (content != null) {
|
|
129
|
+
writeOutput(content, options.out);
|
|
130
|
+
if (options.out)
|
|
131
|
+
console.error(`[${TAG}] Written to ${options.out}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=briefing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"briefing.js","sourceRoot":"","sources":["../../src/commands/briefing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"AAyGA,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC3E"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { getGitBranch, getGitDiff, getGitDiffStat, getGitStatus } from '../git.js';
|
|
4
|
+
import { loadConfig, loadEnv, resolveConfigPath, runOrchestrator, writeOutput } from '../utils.js';
|
|
5
|
+
// ─── Constants ──────────────────────────────────────────
|
|
6
|
+
const TAG = 'Handoff';
|
|
7
|
+
const MAX_DIFF_CHARS = 50_000;
|
|
8
|
+
const LESSONS_TAIL_LINES = 100;
|
|
9
|
+
// ─── System prompt ──────────────────────────────────────
|
|
10
|
+
const SYSTEM_PROMPT = `# Handoff System Prompt — End-of-Session State Transfer
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
Produce an end-of-session handoff snapshot that captures everything the next session (or the next developer) needs to resume work immediately.
|
|
14
|
+
|
|
15
|
+
## Role
|
|
16
|
+
You are writing a concise, tactical "End of Shift" handoff. You have access to the current git state, uncommitted changes, and lessons learned during this session. Your job is to synthesize this into a snapshot that lets the next session bootstrap instantly — no detective work required.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
- Be concrete and specific — file paths, branch names, issue numbers
|
|
20
|
+
- Distinguish between what IS done vs what NEEDS to be done next
|
|
21
|
+
- If there are uncommitted changes, describe what they represent and whether they look ready to commit
|
|
22
|
+
- If the working tree is clean, say so and focus on what was accomplished and what's next
|
|
23
|
+
- Capture any lessons or traps discovered during this session
|
|
24
|
+
- Be concise — this is a tactical handoff, not a retrospective
|
|
25
|
+
|
|
26
|
+
## Output Format
|
|
27
|
+
Respond with ONLY the sections below. No preamble, no closing remarks.
|
|
28
|
+
|
|
29
|
+
### Branch & State
|
|
30
|
+
[Current branch, clean/dirty status, what the branch represents]
|
|
31
|
+
|
|
32
|
+
### What Was Done
|
|
33
|
+
[Summary of work completed this session based on the diff and git state. If no changes, say "No uncommitted changes — session may have been exploratory or changes were already committed."]
|
|
34
|
+
|
|
35
|
+
### Uncommitted Changes
|
|
36
|
+
[Description of what the uncommitted changes contain and their state (staged vs unstaged). If clean, say "Working tree is clean."]
|
|
37
|
+
|
|
38
|
+
### Lessons & Traps
|
|
39
|
+
[Lessons learned during this session from the memory file. If none, say "No new lessons recorded this session."]
|
|
40
|
+
|
|
41
|
+
### Next Steps
|
|
42
|
+
[Clear, ordered list of what the next session should do first. Be specific — not "continue working" but "finish implementing X in file Y, then run tests."]
|
|
43
|
+
`;
|
|
44
|
+
// ─── Lessons file reader ────────────────────────────────
|
|
45
|
+
function readRecentLessons(cwd, totemDir) {
|
|
46
|
+
const lessonsPath = path.join(cwd, totemDir, 'lessons.md');
|
|
47
|
+
if (!fs.existsSync(lessonsPath))
|
|
48
|
+
return '';
|
|
49
|
+
const content = fs.readFileSync(lessonsPath, 'utf-8');
|
|
50
|
+
const lines = content.split('\n');
|
|
51
|
+
if (lines.length <= LESSONS_TAIL_LINES)
|
|
52
|
+
return content.trim();
|
|
53
|
+
return lines.slice(-LESSONS_TAIL_LINES).join('\n').trim();
|
|
54
|
+
}
|
|
55
|
+
// ─── Prompt assembly ────────────────────────────────────
|
|
56
|
+
function assemblePrompt(branch, status, diff, diffStat, lessons) {
|
|
57
|
+
const sections = [SYSTEM_PROMPT];
|
|
58
|
+
// Git state
|
|
59
|
+
sections.push('=== GIT STATE ===');
|
|
60
|
+
sections.push(`Branch: ${branch}`);
|
|
61
|
+
sections.push(`Status:\n${status || '(clean working tree)'}`);
|
|
62
|
+
// Diff
|
|
63
|
+
sections.push('\n=== DIFF ===');
|
|
64
|
+
if (!diff.trim()) {
|
|
65
|
+
sections.push('(no uncommitted changes)');
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (diffStat) {
|
|
69
|
+
sections.push(`Diff stat:\n${diffStat}`);
|
|
70
|
+
sections.push('');
|
|
71
|
+
}
|
|
72
|
+
if (diff.length > MAX_DIFF_CHARS) {
|
|
73
|
+
sections.push(diff.slice(0, MAX_DIFF_CHARS));
|
|
74
|
+
sections.push(`\n... [diff truncated at ${MAX_DIFF_CHARS} chars] ...`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
sections.push(diff);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Lessons
|
|
81
|
+
sections.push('\n=== SESSION LESSONS ===');
|
|
82
|
+
sections.push(lessons || '(no lessons recorded)');
|
|
83
|
+
return sections.join('\n');
|
|
84
|
+
}
|
|
85
|
+
export async function handoffCommand(options) {
|
|
86
|
+
const cwd = process.cwd();
|
|
87
|
+
const configPath = resolveConfigPath(cwd);
|
|
88
|
+
loadEnv(cwd);
|
|
89
|
+
const config = await loadConfig(configPath);
|
|
90
|
+
// Gather git state
|
|
91
|
+
console.error(`[${TAG}] Gathering git state...`);
|
|
92
|
+
const branch = getGitBranch(cwd);
|
|
93
|
+
const status = getGitStatus(cwd);
|
|
94
|
+
console.error(`[${TAG}] Branch: ${branch}`);
|
|
95
|
+
// Get diff
|
|
96
|
+
console.error(`[${TAG}] Getting uncommitted diff...`);
|
|
97
|
+
const diff = getGitDiff('all', cwd);
|
|
98
|
+
const diffStat = diff.trim() ? getGitDiffStat(cwd) : '';
|
|
99
|
+
if (diff.trim()) {
|
|
100
|
+
console.error(`[${TAG}] Diff: ${(diff.length / 1024).toFixed(0)}KB`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.error(`[${TAG}] Working tree is clean.`);
|
|
104
|
+
}
|
|
105
|
+
// Read recent lessons
|
|
106
|
+
console.error(`[${TAG}] Reading recent lessons...`);
|
|
107
|
+
const lessons = readRecentLessons(cwd, config.totemDir);
|
|
108
|
+
console.error(`[${TAG}] Lessons: ${lessons ? `${lessons.split('\n').length} lines` : 'none found'}`);
|
|
109
|
+
// Assemble prompt
|
|
110
|
+
const prompt = assemblePrompt(branch, status, diff, diffStat, lessons);
|
|
111
|
+
console.error(`[${TAG}] Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
|
|
112
|
+
const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd });
|
|
113
|
+
if (content != null) {
|
|
114
|
+
writeOutput(content, options.out);
|
|
115
|
+
if (options.out)
|
|
116
|
+
console.error(`[${TAG}] Written to ${options.out}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAoJA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA+HjD"}
|
|
@@ -0,0 +1,227 @@
|
|
|
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 { installPostMergeHook } from './install-hooks.js';
|
|
6
|
+
const AI_PROMPT_BLOCK = `
|
|
7
|
+
|
|
8
|
+
## Totem AI Integration (Auto-Generated)
|
|
9
|
+
You have access to the Totem MCP for long-term project memory. You MUST operate with the following reflexes:
|
|
10
|
+
|
|
11
|
+
### Memory Reflexes
|
|
12
|
+
1. **Pull Before Planning:** Before writing specs, architecture, or fixing complex bugs, use \`search_knowledge\` to retrieve domain constraints and past traps.
|
|
13
|
+
2. **Proactive Anchoring (The 3 Triggers):** You must autonomously call \`add_lesson\` when any of the following occur — do NOT wait for the user to ask:
|
|
14
|
+
- **The Trap Trigger:** If you spend >2 turns fixing a bug caused by a framework quirk, unexpected API response, or edge case. (Anchor the symptom + fix).
|
|
15
|
+
- **The Pivot Trigger:** If the user introduces a new architectural pattern or deprecates an old one. (Anchor the rule).
|
|
16
|
+
- **The Handoff Trigger:** At the end of a session or when wrapping up a complex feature, extract the non-obvious lessons learned and anchor them.
|
|
17
|
+
3. **Tool Preference (MCP over CLI):** Always prioritize using dedicated MCP tools (e.g., GitHub, Supabase, Vercel) over executing generic shell commands (like \`gh issue view\` or \`curl\`). MCP tools provide structured, un-truncated data optimized for your context window. Only fall back to bash execution if an MCP tool is unavailable or fails.
|
|
18
|
+
|
|
19
|
+
Lessons are automatically re-indexed in the background after each \`add_lesson\` call — no manual sync needed.
|
|
20
|
+
|
|
21
|
+
### Workflow Orchestrator Rituals
|
|
22
|
+
Totem provides CLI commands that map to your development lifecycle. Use them at these moments:
|
|
23
|
+
1. **Start of Session:** Run \`totem briefing\` to get oriented with current branch state, open PRs, and recent context. Run \`totem triage\` if you need to pick a new task.
|
|
24
|
+
2. **Before Implementation:** Run \`totem spec <issue-url-or-topic>\` to generate an architectural plan and review related context before writing code.
|
|
25
|
+
3. **Before PR/Push:** Run \`totem shield\` to analyze uncommitted changes against project knowledge — catches architectural drift and pattern violations.
|
|
26
|
+
4. **End of Session:** Run \`totem handoff\` to generate a snapshot for the next agent session with current progress and open threads.
|
|
27
|
+
`;
|
|
28
|
+
function detectProject(cwd) {
|
|
29
|
+
const exists = (p) => fs.existsSync(path.join(cwd, p));
|
|
30
|
+
return {
|
|
31
|
+
hasTypeScript: exists('tsconfig.json'),
|
|
32
|
+
hasSrc: exists('src'),
|
|
33
|
+
hasDocs: exists('docs'),
|
|
34
|
+
hasSpecs: exists('specs'),
|
|
35
|
+
hasContext: exists('context'),
|
|
36
|
+
hasSessions: exists('context/sessions'),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function buildTargets(detected) {
|
|
40
|
+
const targets = [];
|
|
41
|
+
if (detected.hasTypeScript) {
|
|
42
|
+
targets.push({ glob: 'src/**/*.ts', type: 'code', strategy: 'typescript-ast' }, { glob: 'src/**/*.tsx', type: 'code', strategy: 'typescript-ast' });
|
|
43
|
+
if (!detected.hasSrc) {
|
|
44
|
+
// Monorepo layout — scan packages/
|
|
45
|
+
targets.push({ glob: 'packages/**/*.ts', type: 'code', strategy: 'typescript-ast' }, { glob: 'packages/**/*.tsx', type: 'code', strategy: 'typescript-ast' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (detected.hasSessions) {
|
|
49
|
+
targets.push({
|
|
50
|
+
glob: 'context/sessions/**/*.md',
|
|
51
|
+
type: 'session_log',
|
|
52
|
+
strategy: 'session-log',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (detected.hasSpecs) {
|
|
56
|
+
targets.push({
|
|
57
|
+
glob: 'specs/**/*.md',
|
|
58
|
+
type: 'spec',
|
|
59
|
+
strategy: 'markdown-heading',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (detected.hasDocs) {
|
|
63
|
+
targets.push({
|
|
64
|
+
glob: 'docs/**/*.md',
|
|
65
|
+
type: 'spec',
|
|
66
|
+
strategy: 'markdown-heading',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
if (detected.hasContext) {
|
|
70
|
+
targets.push({
|
|
71
|
+
glob: 'context/**/*.md',
|
|
72
|
+
type: 'spec',
|
|
73
|
+
strategy: 'markdown-heading',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Fallback: if nothing detected, add a sensible default
|
|
77
|
+
if (targets.length === 0) {
|
|
78
|
+
targets.push({
|
|
79
|
+
glob: '**/*.md',
|
|
80
|
+
type: 'spec',
|
|
81
|
+
strategy: 'markdown-heading',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return targets;
|
|
85
|
+
}
|
|
86
|
+
function formatTargets(targets) {
|
|
87
|
+
const lines = targets.map((t) => {
|
|
88
|
+
return ` { glob: '${t.glob}', type: '${t.type}', strategy: '${t.strategy}' },`;
|
|
89
|
+
});
|
|
90
|
+
return lines.join('\n');
|
|
91
|
+
}
|
|
92
|
+
function generateConfig(targets, provider) {
|
|
93
|
+
const embeddingBlock = provider === 'openai'
|
|
94
|
+
? ` embedding: { provider: 'openai', model: 'text-embedding-3-small' },`
|
|
95
|
+
: ` embedding: { provider: 'ollama', model: 'nomic-embed-text', baseUrl: 'http://localhost:11434' },`;
|
|
96
|
+
return `import type { TotemConfig } from '@mmnto/totem';
|
|
97
|
+
|
|
98
|
+
const config: TotemConfig = {
|
|
99
|
+
targets: [
|
|
100
|
+
${formatTargets(targets)}
|
|
101
|
+
],
|
|
102
|
+
|
|
103
|
+
${embeddingBlock}
|
|
104
|
+
|
|
105
|
+
orchestrator: {
|
|
106
|
+
provider: 'shell',
|
|
107
|
+
command: 'gemini --model {model} -o json -e none < {file}',
|
|
108
|
+
defaultModel: 'gemini-3-flash-preview',
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export default config;
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
export async function initCommand() {
|
|
116
|
+
const cwd = process.cwd();
|
|
117
|
+
const configPath = path.join(cwd, 'totem.config.ts');
|
|
118
|
+
const totemDir = path.join(cwd, '.totem');
|
|
119
|
+
const configExists = fs.existsSync(configPath);
|
|
120
|
+
const rl = readline.createInterface({ input, output });
|
|
121
|
+
try {
|
|
122
|
+
if (!configExists) {
|
|
123
|
+
// --- Fresh install: generate config ---
|
|
124
|
+
console.log('[Totem] Scanning project...');
|
|
125
|
+
const detected = detectProject(cwd);
|
|
126
|
+
const detections = [];
|
|
127
|
+
if (detected.hasTypeScript)
|
|
128
|
+
detections.push('TypeScript');
|
|
129
|
+
if (detected.hasSrc)
|
|
130
|
+
detections.push('src/');
|
|
131
|
+
if (detected.hasDocs)
|
|
132
|
+
detections.push('docs/');
|
|
133
|
+
if (detected.hasSpecs)
|
|
134
|
+
detections.push('specs/');
|
|
135
|
+
if (detected.hasContext)
|
|
136
|
+
detections.push('context/');
|
|
137
|
+
if (detected.hasSessions)
|
|
138
|
+
detections.push('session logs');
|
|
139
|
+
if (detections.length > 0) {
|
|
140
|
+
console.log(`[Totem] Detected: ${detections.join(', ')}`);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log('[Totem] No specific project structure detected. Using markdown defaults.');
|
|
144
|
+
}
|
|
145
|
+
const targets = buildTargets(detected);
|
|
146
|
+
let provider = 'openai';
|
|
147
|
+
const answer = await rl.question('Enter your OpenAI API key (or press Enter to configure local Ollama later): ');
|
|
148
|
+
if (answer.trim()) {
|
|
149
|
+
const envPath = path.join(cwd, '.env');
|
|
150
|
+
const envLine = `OPENAI_API_KEY=${answer.trim()}\n`;
|
|
151
|
+
if (fs.existsSync(envPath)) {
|
|
152
|
+
const existing = fs.readFileSync(envPath, 'utf-8');
|
|
153
|
+
if (!existing.includes('OPENAI_API_KEY')) {
|
|
154
|
+
fs.appendFileSync(envPath, envLine);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
fs.writeFileSync(envPath, envLine);
|
|
159
|
+
}
|
|
160
|
+
console.log('[Totem] OpenAI API key saved to .env');
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
provider = 'ollama';
|
|
164
|
+
console.log('[Totem] Configured for Ollama. Make sure it is running locally.');
|
|
165
|
+
}
|
|
166
|
+
const configContent = generateConfig(targets, provider);
|
|
167
|
+
fs.writeFileSync(configPath, configContent, 'utf-8');
|
|
168
|
+
console.log('[Totem] Created totem.config.ts');
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log('[Totem] totem.config.ts already exists. Checking reflexes and hooks...');
|
|
172
|
+
}
|
|
173
|
+
// --- Always run: .totem/ directory ---
|
|
174
|
+
if (!fs.existsSync(totemDir)) {
|
|
175
|
+
fs.mkdirSync(totemDir, { recursive: true });
|
|
176
|
+
}
|
|
177
|
+
const lessonsPath = path.join(totemDir, 'lessons.md');
|
|
178
|
+
if (!fs.existsSync(lessonsPath)) {
|
|
179
|
+
fs.writeFileSync(lessonsPath, `# Totem Lessons\n\nLessons learned from PR reviews and Shield checks.\nThis file is version-controlled and reviewed in PR diffs.\n\n---\n`, 'utf-8');
|
|
180
|
+
console.log('[Totem] Created .totem/lessons.md');
|
|
181
|
+
}
|
|
182
|
+
// --- Always run: AI prompt injection ---
|
|
183
|
+
const aiFiles = ['CLAUDE.md', '.cursorrules', '.gemini/gemini.md'];
|
|
184
|
+
const foundAiFiles = aiFiles.filter((f) => fs.existsSync(path.join(cwd, f)));
|
|
185
|
+
if (foundAiFiles.length > 0) {
|
|
186
|
+
console.log(`\n[Totem] Detected AI context files: ${foundAiFiles.join(', ')}`);
|
|
187
|
+
const injectAnswer = await rl.question('Would you like to inject Totem automated memory reflexes into these files? (y/N): ');
|
|
188
|
+
if (injectAnswer.trim().toLowerCase() === 'y' ||
|
|
189
|
+
injectAnswer.trim().toLowerCase() === 'yes') {
|
|
190
|
+
for (const file of foundAiFiles) {
|
|
191
|
+
try {
|
|
192
|
+
const filePath = path.join(cwd, file);
|
|
193
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
194
|
+
if (!content.includes('Totem AI Integration') &&
|
|
195
|
+
!content.includes('Totem Memory Reflexes')) {
|
|
196
|
+
fs.appendFileSync(filePath, AI_PROMPT_BLOCK);
|
|
197
|
+
console.log(`[Totem] Injected reflexes into ${file}`);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.log(`[Totem] ${file} already contains Totem reflexes.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
205
|
+
console.error(`\n[Totem Error] Failed to inject reflexes into ${file}: ${message}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// --- Always run: post-merge git hook ---
|
|
211
|
+
await installPostMergeHook(cwd, rl);
|
|
212
|
+
// --- Always run: .gitignore ---
|
|
213
|
+
const gitignorePath = path.join(cwd, '.gitignore');
|
|
214
|
+
if (fs.existsSync(gitignorePath)) {
|
|
215
|
+
const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
|
|
216
|
+
if (!gitignore.includes('.lancedb')) {
|
|
217
|
+
fs.appendFileSync(gitignorePath, '\n# Totem\n.lancedb/\n');
|
|
218
|
+
console.log('[Totem] Added .lancedb/ to .gitignore');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
console.log('[Totem] Init complete. Run `totem sync` to index your project.');
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
rl.close();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AA0EnD,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,CAAC,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D7F;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CASzD"}
|