@mmnto/cli 0.7.0 → 0.9.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/anchor.d.ts.map +1 -1
- package/dist/commands/anchor.js +6 -4
- package/dist/commands/anchor.js.map +1 -1
- package/dist/commands/briefing.d.ts.map +1 -1
- package/dist/commands/briefing.js +15 -12
- package/dist/commands/briefing.js.map +1 -1
- package/dist/commands/handoff.d.ts.map +1 -1
- package/dist/commands/handoff.js +16 -13
- package/dist/commands/handoff.js.map +1 -1
- package/dist/commands/init.d.ts +21 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +210 -15
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/init.test.js +160 -1
- package/dist/commands/init.test.js.map +1 -1
- package/dist/commands/learn.d.ts +12 -1
- package/dist/commands/learn.d.ts.map +1 -1
- package/dist/commands/learn.js +137 -59
- package/dist/commands/learn.js.map +1 -1
- package/dist/commands/learn.test.js +59 -1
- package/dist/commands/learn.test.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +5 -4
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/shield.d.ts.map +1 -1
- package/dist/commands/shield.js +19 -14
- package/dist/commands/shield.js.map +1 -1
- package/dist/commands/spec.d.ts +1 -1
- package/dist/commands/spec.d.ts.map +1 -1
- package/dist/commands/spec.js +56 -43
- package/dist/commands/spec.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +15 -6
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/triage.d.ts.map +1 -1
- package/dist/commands/triage.js +14 -11
- package/dist/commands/triage.js.map +1 -1
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/ui.d.ts +26 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +85 -0
- package/dist/ui.js.map +1 -0
- package/dist/ui.test.d.ts +2 -0
- package/dist/ui.test.d.ts.map +1 -0
- package/dist/ui.test.js +76 -0
- package/dist/ui.test.js.map +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +37 -8
- package/dist/utils.js.map +1 -1
- package/dist/utils.test.js +70 -1
- package/dist/utils.test.js.map +1 -1
- package/package.json +4 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../src/commands/anchor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"anchor.d.ts","sourceRoot":"","sources":["../../src/commands/anchor.ts"],"names":[],"mappings":"AAmBA,wBAAsB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ErE"}
|
package/dist/commands/anchor.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { stdin as input, stdout as output } from 'node:process';
|
|
5
5
|
import * as readline from 'node:readline/promises';
|
|
6
|
+
import { log } from '../ui.js';
|
|
6
7
|
import { IS_WIN, loadConfig, loadEnv, resolveConfigPath } from '../utils.js';
|
|
7
8
|
function detectSyncCommand(cwd) {
|
|
8
9
|
if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {
|
|
@@ -53,16 +54,16 @@ export async function anchorCommand(lessonArg) {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
if (!lessonText || !lessonText.trim()) {
|
|
56
|
-
|
|
57
|
+
log.error('Totem', 'Lesson text cannot be empty.');
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
const timestamp = new Date().toISOString();
|
|
60
61
|
const tagString = tags.length > 0 ? tags.join(', ') : 'manual';
|
|
61
62
|
const entry = `\n## Lesson — ${timestamp}\n\n**Tags:** ${tagString}\n\n${lessonText.trim()}\n`;
|
|
62
63
|
fs.appendFileSync(lessonsPath, entry, 'utf-8');
|
|
63
|
-
|
|
64
|
+
log.success('Totem', `Lesson saved to ${config.totemDir}/lessons.md`);
|
|
64
65
|
const logPath = path.join(totemDir, 'mcp-sync.log');
|
|
65
|
-
|
|
66
|
+
log.dim('Totem', 'Triggering background re-index...');
|
|
66
67
|
try {
|
|
67
68
|
const { cmd, args } = detectSyncCommand(cwd);
|
|
68
69
|
const logFd = fs.openSync(logPath, 'a');
|
|
@@ -76,7 +77,8 @@ export async function anchorCommand(lessonArg) {
|
|
|
76
77
|
child.unref();
|
|
77
78
|
}
|
|
78
79
|
catch (err) {
|
|
79
|
-
|
|
80
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
81
|
+
log.warn('Totem', `Failed to trigger background sync: ${message}`);
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
//# sourceMappingURL=anchor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anchor.js","sourceRoot":"","sources":["../../src/commands/anchor.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"anchor.js","sourceRoot":"","sources":["../../src/commands/anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE7E,SAAS,iBAAiB,CAAC,GAAW;IACpC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC;IACjG,CAAC;IACD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC;IACzF,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAkB;IACpD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAE5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEtD,IAAI,UAAU,GAAG,SAAS,CAAC;IAC3B,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC,CAAC;YACxF,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAC;YAClF,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC,CAAC;YAC1F,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;YAE/D,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBAClB,IAAI,CAAC,IAAI,CACP,GAAG,MAAM;qBACN,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;qBACpB,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;YACJ,CAAC;YAED,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,OAAO,CAAC,IAAI,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACjE,IAAI,OAAO,CAAC,IAAI,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACjE,IAAI,GAAG,CAAC,IAAI,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAE1D,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;IACH,CAAC;IAED,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;QACtC,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,8BAA8B,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAE/D,MAAM,KAAK,GAAG,iBAAiB,SAAS,iBAAiB,SAAS,OAAO,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC;IAE/F,EAAE,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/C,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,mBAAmB,MAAM,CAAC,QAAQ,aAAa,CAAC,CAAC;IAEtE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACpD,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,mCAAmC,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YAC7B,GAAG;YACH,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC;YAC/B,KAAK,EAAE,MAAM;YACb,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,sCAAsC,OAAO,EAAE,CAAC,CAAC;IACrE,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"briefing.d.ts","sourceRoot":"","sources":["../../src/commands/briefing.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"briefing.d.ts","sourceRoot":"","sources":["../../src/commands/briefing.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AA2EpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAG9D;AAqCD,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C7E"}
|
|
@@ -2,7 +2,8 @@ import * as path from 'node:path';
|
|
|
2
2
|
import { createEmbedder, LanceStore } from '@mmnto/totem';
|
|
3
3
|
import { GitHubCliPrAdapter } from '../adapters/github-cli-pr.js';
|
|
4
4
|
import { getGitBranch, getGitStatus } from '../git.js';
|
|
5
|
-
import {
|
|
5
|
+
import { log } from '../ui.js';
|
|
6
|
+
import { formatResults, getSystemPrompt, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, wrapXml, writeOutput, } from '../utils.js';
|
|
6
7
|
// ─── Constants ──────────────────────────────────────────
|
|
7
8
|
const TAG = 'Briefing';
|
|
8
9
|
const MAX_SPEC_RESULTS = 5;
|
|
@@ -53,8 +54,8 @@ export function formatPRList(prs) {
|
|
|
53
54
|
return '(none)';
|
|
54
55
|
return prs.map((pr) => `- #${pr.number} — ${pr.title} (branch: ${pr.headRefName})`).join('\n');
|
|
55
56
|
}
|
|
56
|
-
function assemblePrompt(branch, status, prs, context) {
|
|
57
|
-
const sections = [
|
|
57
|
+
function assemblePrompt(branch, status, prs, context, systemPrompt) {
|
|
58
|
+
const sections = [systemPrompt];
|
|
58
59
|
// Git state
|
|
59
60
|
sections.push('=== GIT STATE ===');
|
|
60
61
|
sections.push(`Branch: ${branch}`);
|
|
@@ -80,33 +81,35 @@ export async function briefingCommand(options) {
|
|
|
80
81
|
loadEnv(cwd);
|
|
81
82
|
const config = await loadConfig(configPath);
|
|
82
83
|
// Gather git state
|
|
83
|
-
|
|
84
|
+
log.info(TAG, 'Gathering git state...');
|
|
84
85
|
const branch = getGitBranch(cwd);
|
|
85
86
|
const status = getGitStatus(cwd);
|
|
86
|
-
|
|
87
|
+
log.info(TAG, `Branch: ${branch}`);
|
|
87
88
|
// Fetch open PRs
|
|
88
|
-
|
|
89
|
+
log.info(TAG, 'Fetching open PRs...');
|
|
89
90
|
const adapter = new GitHubCliPrAdapter(cwd);
|
|
90
91
|
const prs = adapter.fetchOpenPRs();
|
|
91
|
-
|
|
92
|
+
log.info(TAG, `Found ${prs.length} open PRs.`);
|
|
92
93
|
// Connect to LanceDB
|
|
93
94
|
const embedder = createEmbedder(config.embedding);
|
|
94
95
|
const store = new LanceStore(path.join(cwd, config.lanceDir), embedder);
|
|
95
96
|
await store.connect();
|
|
96
97
|
// Retrieve context from LanceDB
|
|
97
98
|
const query = `${branch} active work session priorities`;
|
|
98
|
-
|
|
99
|
+
log.info(TAG, 'Querying Totem index...');
|
|
99
100
|
const context = await retrieveContext(query, store);
|
|
100
101
|
const totalResults = context.specs.length + context.sessions.length;
|
|
101
|
-
|
|
102
|
+
log.info(TAG, `Found: ${context.specs.length} specs, ${context.sessions.length} sessions`);
|
|
103
|
+
// Resolve system prompt (allow .totem/prompts/briefing.md override)
|
|
104
|
+
const systemPrompt = getSystemPrompt('briefing', SYSTEM_PROMPT, cwd, config.totemDir);
|
|
102
105
|
// Assemble prompt
|
|
103
|
-
const prompt = assemblePrompt(branch, status, prs, context);
|
|
104
|
-
|
|
106
|
+
const prompt = assemblePrompt(branch, status, prs, context, systemPrompt);
|
|
107
|
+
log.dim(TAG, `Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
|
|
105
108
|
const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd, totalResults });
|
|
106
109
|
if (content != null) {
|
|
107
110
|
writeOutput(content, options.out);
|
|
108
111
|
if (options.out)
|
|
109
|
-
|
|
112
|
+
log.success(TAG, `Written to ${options.out}`);
|
|
110
113
|
}
|
|
111
114
|
}
|
|
112
115
|
//# sourceMappingURL=briefing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"briefing.js","sourceRoot":"","sources":["../../src/commands/briefing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EACL,aAAa,EACb,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,OAAO,EACP,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,2DAA2D;AAE3D,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,2DAA2D;AAE3D,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BrB,CAAC;AASF,KAAK,UAAU,eAAe,CAAC,KAAa,EAAE,KAAiB;IAC7D,MAAM,MAAM,GAAG,CAAC,UAAuB,EAAE,UAAkB,EAAE,EAAE,CAC7D,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;IAElD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1C,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC;QAChC,MAAM,CAAC,aAAa,EAAE,mBAAmB,CAAC;KAC3C,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,2DAA2D;AAE3D,MAAM,UAAU,YAAY,CAAC,GAAyB;IACpD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACtC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,MAAM,MAAM,EAAE,CAAC,KAAK,aAAa,EAAE,CAAC,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,cAAc,CACrB,MAAc,EACd,MAAc,EACd,GAAyB,EACzB,OAAyB;
|
|
1
|
+
{"version":3,"file":"briefing.js","sourceRoot":"","sources":["../../src/commands/briefing.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"AA4DA,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUvE;AAiDD,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;CACjB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC3E"}
|
package/dist/commands/handoff.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { getGitBranch, getGitDiff, getGitDiffStat, getGitStatus } from '../git.js';
|
|
4
|
-
import {
|
|
4
|
+
import { log } from '../ui.js';
|
|
5
|
+
import { getSystemPrompt, loadConfig, loadEnv, resolveConfigPath, runOrchestrator, wrapXml, writeOutput, } from '../utils.js';
|
|
5
6
|
// ─── Constants ──────────────────────────────────────────
|
|
6
7
|
const TAG = 'Handoff';
|
|
7
8
|
const MAX_DIFF_CHARS = 50_000;
|
|
@@ -53,8 +54,8 @@ export function readRecentLessons(cwd, totemDir) {
|
|
|
53
54
|
return lines.slice(-LESSONS_TAIL_LINES).join('\n').trim();
|
|
54
55
|
}
|
|
55
56
|
// ─── Prompt assembly ────────────────────────────────────
|
|
56
|
-
function assemblePrompt(branch, status, diff, diffStat, lessons) {
|
|
57
|
-
const sections = [
|
|
57
|
+
function assemblePrompt(branch, status, diff, diffStat, lessons, systemPrompt) {
|
|
58
|
+
const sections = [systemPrompt];
|
|
58
59
|
// Git state
|
|
59
60
|
sections.push('=== GIT STATE ===');
|
|
60
61
|
sections.push(`Branch: ${branch}`);
|
|
@@ -87,32 +88,34 @@ export async function handoffCommand(options) {
|
|
|
87
88
|
loadEnv(cwd);
|
|
88
89
|
const config = await loadConfig(configPath);
|
|
89
90
|
// Gather git state
|
|
90
|
-
|
|
91
|
+
log.info(TAG, 'Gathering git state...');
|
|
91
92
|
const branch = getGitBranch(cwd);
|
|
92
93
|
const status = getGitStatus(cwd);
|
|
93
|
-
|
|
94
|
+
log.info(TAG, `Branch: ${branch}`);
|
|
94
95
|
// Get diff
|
|
95
|
-
|
|
96
|
+
log.info(TAG, 'Getting uncommitted diff...');
|
|
96
97
|
const diff = getGitDiff('all', cwd);
|
|
97
98
|
const diffStat = diff.trim() ? getGitDiffStat(cwd) : '';
|
|
98
99
|
if (diff.trim()) {
|
|
99
|
-
|
|
100
|
+
log.info(TAG, `Diff: ${(diff.length / 1024).toFixed(0)}KB`);
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
|
-
|
|
103
|
+
log.dim(TAG, 'Working tree is clean.');
|
|
103
104
|
}
|
|
104
105
|
// Read recent lessons
|
|
105
|
-
|
|
106
|
+
log.info(TAG, 'Reading recent lessons...');
|
|
106
107
|
const lessons = readRecentLessons(cwd, config.totemDir);
|
|
107
|
-
|
|
108
|
+
log.info(TAG, `Lessons: ${lessons ? `${lessons.split('\n').length} lines` : 'none found'}`);
|
|
109
|
+
// Resolve system prompt (allow .totem/prompts/handoff.md override)
|
|
110
|
+
const systemPrompt = getSystemPrompt('handoff', SYSTEM_PROMPT, cwd, config.totemDir);
|
|
108
111
|
// Assemble prompt
|
|
109
|
-
const prompt = assemblePrompt(branch, status, diff, diffStat, lessons);
|
|
110
|
-
|
|
112
|
+
const prompt = assemblePrompt(branch, status, diff, diffStat, lessons, systemPrompt);
|
|
113
|
+
log.dim(TAG, `Prompt: ${(prompt.length / 1024).toFixed(0)}KB`);
|
|
111
114
|
const content = runOrchestrator({ prompt, tag: TAG, options, config, cwd });
|
|
112
115
|
if (content != null) {
|
|
113
116
|
writeOutput(content, options.out);
|
|
114
117
|
if (options.out)
|
|
115
|
-
|
|
118
|
+
log.success(TAG, `Written to ${options.out}`);
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
121
|
//# sourceMappingURL=handoff.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EACL,UAAU,EACV,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,OAAO,EACP,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,2DAA2D;AAE3D,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,2DAA2D;AAE3D,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCrB,CAAC;AAEF,2DAA2D;AAE3D,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,QAAgB;IAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAC;IAE3C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,KAAK,CAAC,MAAM,IAAI,kBAAkB;QAAE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;IAE9D,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC;AAED,2DAA2D;AAE3D,SAAS,cAAc,CACrB,MAAc,EACd,MAAc,EACd,IAAY,EACZ,QAAgB,EAChB,OAAe;
|
|
1
|
+
{"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
+
export interface HookInstallerResult {
|
|
2
|
+
file: string;
|
|
3
|
+
action: 'created' | 'exists' | 'skipped' | 'merged';
|
|
4
|
+
err?: string;
|
|
5
|
+
}
|
|
1
6
|
export declare function buildNpxCommand(isWin: boolean): {
|
|
2
7
|
command: string;
|
|
3
8
|
args: string[];
|
|
4
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* Scaffold a file with idempotency — skips if the marker is already present.
|
|
12
|
+
* Creates parent directories as needed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function scaffoldFile(filePath: string, content: string, marker?: string): {
|
|
15
|
+
action: 'created' | 'exists' | 'skipped';
|
|
16
|
+
err?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Merge Totem hooks into .claude/settings.local.json without overwriting
|
|
20
|
+
* existing user-defined hooks.
|
|
21
|
+
*/
|
|
22
|
+
export declare function scaffoldClaudeHooks(filePath: string): {
|
|
23
|
+
action: 'created' | 'merged' | 'skipped';
|
|
24
|
+
err?: string;
|
|
25
|
+
};
|
|
5
26
|
export declare function scaffoldMcpConfig(filePath: string, serverEntry: Record<string, unknown>): {
|
|
6
27
|
action: 'created' | 'merged' | 'skipped';
|
|
7
28
|
err?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAqDA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAUD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAInF;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,GAAE,MAA0B,GACjC;IAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAqB5D;AAqFD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACrD,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAkEA;AAiDD,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC;IAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAoD5D;AAmID,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAmMjD"}
|
package/dist/commands/init.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { stdin as input, stdout as output } from 'node:process';
|
|
4
4
|
import * as readline from 'node:readline/promises';
|
|
5
|
+
import { bold, brand, dim, log, printBanner, success } from '../ui.js';
|
|
5
6
|
import { IS_WIN } from '../utils.js';
|
|
6
7
|
import { installPostMergeHook } from './install-hooks.js';
|
|
7
8
|
const AI_PROMPT_BLOCK = `
|
|
@@ -26,25 +27,198 @@ Totem provides CLI commands that map to your development lifecycle. Use them at
|
|
|
26
27
|
2. **Before Implementation:** Run \`totem spec <issue-url-or-topic>\` to generate an architectural plan and review related context before writing code.
|
|
27
28
|
3. **Before PR/Push:** Run \`totem shield\` to analyze uncommitted changes against project knowledge — catches architectural drift and pattern violations.
|
|
28
29
|
4. **End of Session:** Run \`totem handoff\` to generate a snapshot for the next agent session with current progress and open threads.
|
|
30
|
+
|
|
31
|
+
### Cloud / PR Review Bots
|
|
32
|
+
[FOR CLOUD BOTS ONLY — e.g., Gemini Code Assist, GitHub Copilot PR Review]
|
|
33
|
+
You do NOT have access to the local CLI. Instead, use the Totem MCP tools directly:
|
|
34
|
+
1. **Before reviewing a PR:** Call \`search_knowledge\` with queries about the files and patterns being changed to check for known traps and architectural constraints.
|
|
35
|
+
2. **Before suggesting changes:** Call \`search_knowledge\` to verify your suggestion aligns with established project patterns and past lessons.
|
|
36
|
+
3. **When you spot a recurring issue:** Call \`add_lesson\` to persist the trap so future reviews catch it automatically.
|
|
29
37
|
`;
|
|
30
38
|
export function buildNpxCommand(isWin) {
|
|
31
39
|
return isWin
|
|
32
40
|
? { command: 'cmd', args: ['/c', 'npx', '-y', '@mmnto/mcp'] }
|
|
33
41
|
: { command: 'npx', args: ['-y', '@mmnto/mcp'] };
|
|
34
42
|
}
|
|
43
|
+
const TOTEM_FILE_MARKER = '// [totem] auto-generated';
|
|
44
|
+
/**
|
|
45
|
+
* Scaffold a file with idempotency — skips if the marker is already present.
|
|
46
|
+
* Creates parent directories as needed.
|
|
47
|
+
*/
|
|
48
|
+
export function scaffoldFile(filePath, content, marker = TOTEM_FILE_MARKER) {
|
|
49
|
+
try {
|
|
50
|
+
if (fs.existsSync(filePath)) {
|
|
51
|
+
const existing = fs.readFileSync(filePath, 'utf-8');
|
|
52
|
+
if (existing.includes(marker)) {
|
|
53
|
+
return { action: 'exists' };
|
|
54
|
+
}
|
|
55
|
+
return { action: 'skipped' };
|
|
56
|
+
}
|
|
57
|
+
const dir = path.dirname(filePath);
|
|
58
|
+
if (!fs.existsSync(dir)) {
|
|
59
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
62
|
+
return { action: 'created' };
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
66
|
+
return { action: 'skipped', err: `[Totem Error] ${message}` };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
35
69
|
const { command: npxCmd, args: npxArgs } = buildNpxCommand(IS_WIN);
|
|
70
|
+
// --- Gemini CLI hook templates ---
|
|
71
|
+
const GEMINI_SESSION_START = `// [totem] auto-generated — Gemini CLI SessionStart hook
|
|
72
|
+
// Runs \`totem briefing\` at the start of every Gemini CLI session.
|
|
73
|
+
const { execSync } = require('child_process');
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const output = execSync('totem briefing', {
|
|
77
|
+
encoding: 'utf-8',
|
|
78
|
+
timeout: 30000,
|
|
79
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
80
|
+
});
|
|
81
|
+
process.stderr.write(output);
|
|
82
|
+
} catch (err) {
|
|
83
|
+
process.stderr.write('[Totem Error] Briefing unavailable: ' + (err instanceof Error ? err.message : String(err)) + '\\n');
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
const GEMINI_BEFORE_TOOL = `// [totem] auto-generated — Gemini CLI BeforeTool hook
|
|
87
|
+
// Intercepts git push/commit to run \`totem shield\` before proceeding.
|
|
88
|
+
const { execSync } = require('child_process');
|
|
89
|
+
|
|
90
|
+
module.exports = function beforeTool(toolName, toolInput) {
|
|
91
|
+
if (toolName !== 'run_shell_command') return;
|
|
92
|
+
const cmd = typeof toolInput === 'string' ? toolInput : JSON.stringify(toolInput);
|
|
93
|
+
if (!/git\\s+(push|commit)/.test(cmd) && !/["']git["'].*["'](push|commit)["']/.test(cmd)) return;
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
execSync('totem shield', { encoding: 'utf-8', timeout: 60000, stdio: 'inherit' });
|
|
97
|
+
} catch (err) {
|
|
98
|
+
throw new Error('[Totem Error] Shield check failed. Fix violations before pushing.\\n' + err.message);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
`;
|
|
102
|
+
const GEMINI_SKILL = `<!-- [totem] auto-generated — Totem Architect skill -->
|
|
103
|
+
# Totem Architect
|
|
104
|
+
|
|
105
|
+
Before designing, planning, or implementing features, query the project's memory index for relevant context:
|
|
106
|
+
|
|
107
|
+
1. Use the \`search_knowledge\` MCP tool with a query describing what you're about to build.
|
|
108
|
+
2. Review returned lessons, specs, and code patterns before writing any code.
|
|
109
|
+
3. If you discover a trap or architectural constraint, factor it into your design.
|
|
110
|
+
|
|
111
|
+
This ensures you build on existing knowledge rather than repeating past mistakes.
|
|
112
|
+
`;
|
|
113
|
+
async function installGeminiHooks(cwd) {
|
|
114
|
+
const results = [];
|
|
115
|
+
const files = [
|
|
116
|
+
{
|
|
117
|
+
rel: '.gemini/hooks/SessionStart.js',
|
|
118
|
+
content: GEMINI_SESSION_START,
|
|
119
|
+
marker: TOTEM_FILE_MARKER,
|
|
120
|
+
},
|
|
121
|
+
{ rel: '.gemini/hooks/BeforeTool.js', content: GEMINI_BEFORE_TOOL, marker: TOTEM_FILE_MARKER },
|
|
122
|
+
{
|
|
123
|
+
rel: '.gemini/skills/totem.md',
|
|
124
|
+
content: GEMINI_SKILL,
|
|
125
|
+
marker: '<!-- [totem] auto-generated — Totem Architect skill -->',
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
for (const { rel, content, marker } of files) {
|
|
129
|
+
const filePath = path.join(cwd, rel);
|
|
130
|
+
const result = scaffoldFile(filePath, content, marker);
|
|
131
|
+
results.push({ file: rel, ...result });
|
|
132
|
+
}
|
|
133
|
+
return results;
|
|
134
|
+
}
|
|
135
|
+
// --- Claude Code hook installer ---
|
|
136
|
+
const CLAUDE_PRETOOLUSE_ENTRY = {
|
|
137
|
+
matcher: 'Bash',
|
|
138
|
+
hooks: [
|
|
139
|
+
'if printf "%s" "$TOOL_INPUT" | grep -q "git" && printf "%s" "$TOOL_INPUT" | grep -qE "(push|commit)"; then totem shield; fi',
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Merge Totem hooks into .claude/settings.local.json without overwriting
|
|
144
|
+
* existing user-defined hooks.
|
|
145
|
+
*/
|
|
146
|
+
export function scaffoldClaudeHooks(filePath) {
|
|
147
|
+
try {
|
|
148
|
+
const dir = path.dirname(filePath);
|
|
149
|
+
if (!fs.existsSync(dir)) {
|
|
150
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
151
|
+
}
|
|
152
|
+
const fullConfig = { hooks: { PreToolUse: [CLAUDE_PRETOOLUSE_ENTRY] } };
|
|
153
|
+
if (!fs.existsSync(filePath)) {
|
|
154
|
+
fs.writeFileSync(filePath, JSON.stringify(fullConfig, null, 2) + '\n', 'utf-8');
|
|
155
|
+
return { action: 'created' };
|
|
156
|
+
}
|
|
157
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
158
|
+
let parsed;
|
|
159
|
+
try {
|
|
160
|
+
parsed = JSON.parse(raw);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
164
|
+
return {
|
|
165
|
+
action: 'skipped',
|
|
166
|
+
err: `[Totem Error] Could not parse settings.local.json (invalid JSON): ${message}`,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
// Deep merge: check if PreToolUse already has a totem entry
|
|
170
|
+
const hooksUntyped = parsed.hooks;
|
|
171
|
+
if (hooksUntyped !== undefined &&
|
|
172
|
+
(typeof hooksUntyped !== 'object' || hooksUntyped === null || Array.isArray(hooksUntyped))) {
|
|
173
|
+
return {
|
|
174
|
+
action: 'skipped',
|
|
175
|
+
err: '[Totem Error] Could not merge config: "hooks" in settings.local.json must be an object.',
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const hooks = (hooksUntyped ?? {});
|
|
179
|
+
if (hooks.PreToolUse !== undefined && !Array.isArray(hooks.PreToolUse)) {
|
|
180
|
+
return {
|
|
181
|
+
action: 'skipped',
|
|
182
|
+
err: '[Totem Error] Could not merge config: "hooks.PreToolUse" in settings.local.json must be an array.',
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const preToolUse = (hooks.PreToolUse ?? []);
|
|
186
|
+
if (preToolUse.some((h) => h &&
|
|
187
|
+
h.matcher === 'Bash' &&
|
|
188
|
+
Array.isArray(h.hooks) &&
|
|
189
|
+
h.hooks.some((cmd) => typeof cmd === 'string' && cmd.includes('totem shield')))) {
|
|
190
|
+
return { action: 'skipped' };
|
|
191
|
+
}
|
|
192
|
+
hooks.PreToolUse = [...preToolUse, CLAUDE_PRETOOLUSE_ENTRY];
|
|
193
|
+
parsed.hooks = hooks;
|
|
194
|
+
fs.writeFileSync(filePath, JSON.stringify(parsed, null, 2) + '\n', 'utf-8');
|
|
195
|
+
return { action: 'merged' };
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
199
|
+
return { action: 'skipped', err: `[Totem Error] ${message}` };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function installClaudeHooks(cwd) {
|
|
203
|
+
const rel = '.claude/settings.local.json';
|
|
204
|
+
const filePath = path.join(cwd, rel);
|
|
205
|
+
const result = scaffoldClaudeHooks(filePath);
|
|
206
|
+
return [{ file: rel, ...result }];
|
|
207
|
+
}
|
|
36
208
|
const AI_TOOLS = [
|
|
37
209
|
{
|
|
38
210
|
name: 'Claude Code',
|
|
39
211
|
mcpPath: '.mcp.json',
|
|
40
212
|
reflexFile: 'CLAUDE.md',
|
|
41
213
|
serverEntry: { type: 'stdio', command: npxCmd, args: npxArgs },
|
|
214
|
+
hookInstaller: installClaudeHooks,
|
|
42
215
|
},
|
|
43
216
|
{
|
|
44
217
|
name: 'Gemini CLI',
|
|
45
218
|
mcpPath: '.gemini/settings.json',
|
|
46
219
|
reflexFile: '.gemini/gemini.md',
|
|
47
220
|
serverEntry: { command: npxCmd, args: npxArgs },
|
|
221
|
+
hookInstaller: installGeminiHooks,
|
|
48
222
|
},
|
|
49
223
|
{
|
|
50
224
|
name: 'Cursor',
|
|
@@ -223,9 +397,10 @@ export async function initCommand() {
|
|
|
223
397
|
const rl = readline.createInterface({ input, output });
|
|
224
398
|
const summary = [];
|
|
225
399
|
try {
|
|
400
|
+
printBanner();
|
|
226
401
|
if (!configExists) {
|
|
227
402
|
// --- Fresh install: generate config ---
|
|
228
|
-
|
|
403
|
+
log.info('Totem', 'Scanning project...');
|
|
229
404
|
const detected = detectProject(cwd);
|
|
230
405
|
const detections = [];
|
|
231
406
|
if (detected.hasTypeScript)
|
|
@@ -241,10 +416,10 @@ export async function initCommand() {
|
|
|
241
416
|
if (detected.hasSessions)
|
|
242
417
|
detections.push('session logs');
|
|
243
418
|
if (detections.length > 0) {
|
|
244
|
-
|
|
419
|
+
log.info('Totem', `Detected: ${bold(detections.join(', '))}`);
|
|
245
420
|
}
|
|
246
421
|
else {
|
|
247
|
-
|
|
422
|
+
log.dim('Totem', 'No specific project structure detected. Using markdown defaults.');
|
|
248
423
|
}
|
|
249
424
|
const targets = buildTargets(detected);
|
|
250
425
|
let provider = 'openai';
|
|
@@ -252,7 +427,7 @@ export async function initCommand() {
|
|
|
252
427
|
const apiKey = answer.trim().replace(/[\r\n]/g, '');
|
|
253
428
|
if (apiKey) {
|
|
254
429
|
if (!/^sk-[a-zA-Z0-9_-]+$/.test(apiKey)) {
|
|
255
|
-
|
|
430
|
+
log.warn('Totem', 'API key does not look like a valid OpenAI key (expected sk-...). Skipping.');
|
|
256
431
|
provider = 'ollama';
|
|
257
432
|
}
|
|
258
433
|
else {
|
|
@@ -273,14 +448,14 @@ export async function initCommand() {
|
|
|
273
448
|
}
|
|
274
449
|
else {
|
|
275
450
|
provider = 'ollama';
|
|
276
|
-
|
|
451
|
+
log.info('Totem', 'Configured for Ollama. Make sure it is running locally.');
|
|
277
452
|
}
|
|
278
453
|
const configContent = generateConfig(targets, provider);
|
|
279
454
|
fs.writeFileSync(configPath, configContent, 'utf-8');
|
|
280
455
|
summary.push({ file: 'totem.config.ts', action: 'Created with auto-detected targets' });
|
|
281
456
|
}
|
|
282
457
|
else {
|
|
283
|
-
|
|
458
|
+
log.dim('Totem', 'totem.config.ts already exists. Checking reflexes and hooks...');
|
|
284
459
|
}
|
|
285
460
|
// --- Always run: .totem/ directory ---
|
|
286
461
|
if (!fs.existsSync(totemDir)) {
|
|
@@ -295,7 +470,7 @@ export async function initCommand() {
|
|
|
295
470
|
const detectedTools = detectAiTools(cwd);
|
|
296
471
|
if (detectedTools.length > 0) {
|
|
297
472
|
const toolNames = detectedTools.map((t) => t.name).join(', ');
|
|
298
|
-
|
|
473
|
+
log.info('Totem', `Detected AI tools: ${bold(toolNames)}`);
|
|
299
474
|
const toolAnswer = await rl.question('Which tools should Totem configure? [all/none/select] (default: all): ');
|
|
300
475
|
let selectedTools;
|
|
301
476
|
const trimmed = toolAnswer.trim().toLowerCase();
|
|
@@ -320,9 +495,9 @@ export async function initCommand() {
|
|
|
320
495
|
const filePath = path.join(cwd, tool.mcpPath);
|
|
321
496
|
const result = scaffoldMcpConfig(filePath, tool.serverEntry);
|
|
322
497
|
if (result.err) {
|
|
323
|
-
|
|
324
|
-
console.
|
|
325
|
-
console.
|
|
498
|
+
log.error('Totem', result.err);
|
|
499
|
+
console.error(`To fix this, add the following manually to your ${tool.mcpPath} under "mcpServers":\n`);
|
|
500
|
+
console.error(` "totem": ${JSON.stringify(tool.serverEntry, null, 2)}\n`);
|
|
326
501
|
}
|
|
327
502
|
else if (result.action === 'created') {
|
|
328
503
|
summary.push({ file: tool.mcpPath, action: `Created with Totem MCP server` });
|
|
@@ -344,7 +519,27 @@ export async function initCommand() {
|
|
|
344
519
|
}
|
|
345
520
|
catch (err) {
|
|
346
521
|
const message = err instanceof Error ? err.message : String(err);
|
|
347
|
-
|
|
522
|
+
log.error('Totem', `Failed to inject reflexes into ${tool.reflexFile}: ${message}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// --- Hook installation for selected tools ---
|
|
526
|
+
for (const tool of selectedTools) {
|
|
527
|
+
if (!tool.hookInstaller)
|
|
528
|
+
continue;
|
|
529
|
+
const results = await tool.hookInstaller(cwd);
|
|
530
|
+
for (const result of results) {
|
|
531
|
+
if (result.err) {
|
|
532
|
+
log.error('Totem', `Hook scaffolding failed for ${result.file}: ${result.err}`);
|
|
533
|
+
}
|
|
534
|
+
else if (result.action === 'created') {
|
|
535
|
+
summary.push({ file: result.file, action: `Scaffolded ${tool.name} hook` });
|
|
536
|
+
}
|
|
537
|
+
else if (result.action === 'merged') {
|
|
538
|
+
summary.push({
|
|
539
|
+
file: result.file,
|
|
540
|
+
action: `Merged ${tool.name} hook into existing config`,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
348
543
|
}
|
|
349
544
|
}
|
|
350
545
|
}
|
|
@@ -361,13 +556,13 @@ export async function initCommand() {
|
|
|
361
556
|
}
|
|
362
557
|
// --- Print summary ---
|
|
363
558
|
if (summary.length > 0) {
|
|
364
|
-
console.
|
|
559
|
+
console.error(`\n${brand('--- Totem Init Summary ---')}`);
|
|
365
560
|
for (const entry of summary) {
|
|
366
|
-
console.
|
|
561
|
+
console.error(` ${success('OK')} ${dim(entry.file)} — ${entry.action}`);
|
|
367
562
|
}
|
|
368
|
-
console.
|
|
563
|
+
console.error(brand('--------------------------'));
|
|
369
564
|
}
|
|
370
|
-
|
|
565
|
+
log.success('Totem', 'Init complete. Run `totem sync` to index your project.');
|
|
371
566
|
}
|
|
372
567
|
finally {
|
|
373
568
|
rl.close();
|