mindforge-cc 1.0.5 → 2.0.0-alpha.6
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/.agent/CLAUDE.md +83 -0
- package/.agent/mindforge/auto.md +22 -0
- package/.agent/mindforge/browse.md +26 -0
- package/.agent/mindforge/costs.md +11 -0
- package/.agent/mindforge/cross-review.md +17 -0
- package/.agent/mindforge/dashboard.md +98 -0
- package/.agent/mindforge/execute-phase.md +5 -3
- package/.agent/mindforge/init-project.md +12 -0
- package/.agent/mindforge/qa.md +16 -0
- package/.agent/mindforge/remember.md +14 -0
- package/.agent/mindforge/research.md +11 -0
- package/.agent/mindforge/steer.md +13 -0
- package/.agent/workflows/publish-release.md +36 -0
- package/.claude/CLAUDE.md +83 -0
- package/.claude/commands/mindforge/auto.md +22 -0
- package/.claude/commands/mindforge/browse.md +26 -0
- package/.claude/commands/mindforge/costs.md +11 -0
- package/.claude/commands/mindforge/cross-review.md +17 -0
- package/.claude/commands/mindforge/dashboard.md +98 -0
- package/.claude/commands/mindforge/execute-phase.md +5 -3
- package/.claude/commands/mindforge/qa.md +16 -0
- package/.claude/commands/mindforge/remember.md +14 -0
- package/.claude/commands/mindforge/research.md +11 -0
- package/.claude/commands/mindforge/steer.md +13 -0
- package/.mindforge/MINDFORGE-V2-SCHEMA.json +47 -0
- package/.mindforge/browser/daemon-protocol.md +24 -0
- package/.mindforge/browser/qa-engine.md +16 -0
- package/.mindforge/browser/session-manager.md +18 -0
- package/.mindforge/browser/visual-verify-spec.md +31 -0
- package/.mindforge/dashboard/api-reference.md +122 -0
- package/.mindforge/dashboard/dashboard-spec.md +96 -0
- package/.mindforge/engine/autonomous/auto-executor.md +266 -0
- package/.mindforge/engine/autonomous/headless-adapter.md +66 -0
- package/.mindforge/engine/autonomous/node-repair.md +190 -0
- package/.mindforge/engine/autonomous/progress-reporter.md +58 -0
- package/.mindforge/engine/autonomous/steering-manager.md +64 -0
- package/.mindforge/engine/autonomous/stuck-detector.md +89 -0
- package/.mindforge/memory/MEMORY-SCHEMA.md +155 -0
- package/.mindforge/memory/decision-library.jsonl +0 -0
- package/.mindforge/memory/engine/capture-protocol.md +36 -0
- package/.mindforge/memory/engine/global-sync-spec.md +42 -0
- package/.mindforge/memory/engine/retrieval-spec.md +44 -0
- package/.mindforge/memory/knowledge-base.jsonl +7 -0
- package/.mindforge/memory/pattern-library.jsonl +1 -0
- package/.mindforge/memory/team-preferences.jsonl +4 -0
- package/.mindforge/models/model-registry.md +48 -0
- package/.mindforge/models/model-router.md +30 -0
- package/.mindforge/personas/research-agent.md +24 -0
- package/.planning/approvals/v2-architecture-approval.json +15 -0
- package/.planning/browser-daemon.log +32 -0
- package/.planning/decisions/ADR-021-autonomy-boundary.md +17 -0
- package/.planning/decisions/ADR-022-node-repair-hierarchy.md +19 -0
- package/.planning/decisions/ADR-023-gate-3-timing.md +15 -0
- package/CHANGELOG.md +81 -0
- package/MINDFORGE.md +26 -3
- package/README.md +70 -18
- package/bin/autonomous/auto-runner.js +95 -0
- package/bin/autonomous/headless.js +36 -0
- package/bin/autonomous/progress-stream.js +49 -0
- package/bin/autonomous/repair-operator.js +213 -0
- package/bin/autonomous/steer.js +71 -0
- package/bin/autonomous/stuck-monitor.js +77 -0
- package/bin/browser/browser-daemon.js +139 -0
- package/bin/browser/daemon-manager.js +91 -0
- package/bin/browser/qa-engine.js +47 -0
- package/bin/browser/qa-report-writer.js +32 -0
- package/bin/browser/regression-writer.js +27 -0
- package/bin/browser/screenshot-store.js +49 -0
- package/bin/browser/session-manager.js +93 -0
- package/bin/browser/visual-verify-executor.js +89 -0
- package/bin/change-classifier.js +86 -0
- package/bin/dashboard/api-router.js +198 -0
- package/bin/dashboard/approval-handler.js +134 -0
- package/bin/dashboard/frontend/index.html +511 -0
- package/bin/dashboard/metrics-aggregator.js +296 -0
- package/bin/dashboard/server.js +135 -0
- package/bin/dashboard/sse-bridge.js +178 -0
- package/bin/dashboard/team-tracker.js +0 -0
- package/bin/governance/approve.js +60 -0
- package/bin/install.js +4 -4
- package/bin/installer-core.js +91 -35
- package/bin/memory/cli.js +99 -0
- package/bin/memory/global-sync.js +107 -0
- package/bin/memory/knowledge-capture.js +278 -0
- package/bin/memory/knowledge-indexer.js +172 -0
- package/bin/memory/knowledge-store.js +319 -0
- package/bin/memory/session-memory-loader.js +137 -0
- package/bin/migrations/0.1.0-to-0.5.0.js +2 -3
- package/bin/migrations/0.5.0-to-0.6.0.js +1 -1
- package/bin/migrations/0.6.0-to-1.0.0.js +3 -3
- package/bin/migrations/migrate.js +15 -11
- package/bin/mindforge-cli.js +87 -0
- package/bin/models/anthropic-provider.js +77 -0
- package/bin/models/cost-tracker.js +118 -0
- package/bin/models/gemini-provider.js +79 -0
- package/bin/models/model-client.js +98 -0
- package/bin/models/model-router.js +111 -0
- package/bin/models/openai-provider.js +78 -0
- package/bin/research/research-engine.js +115 -0
- package/bin/review/cross-review-engine.js +81 -0
- package/bin/review/finding-synthesizer.js +116 -0
- package/bin/review/review-report-writer.js +49 -0
- package/bin/updater/self-update.js +13 -13
- package/bin/wizard/setup-wizard.js +5 -1
- package/docs/adr/ADR-024-browser-localhost-only.md +17 -0
- package/docs/adr/ADR-025-visual-verify-failure-treatment.md +19 -0
- package/docs/adr/ADR-026-session-persistence-security.md +20 -0
- package/docs/architecture/README.md +6 -2
- package/docs/ci-cd.md +92 -0
- package/docs/commands-reference.md +1 -0
- package/docs/feature-dashboard.md +52 -0
- package/docs/publishing-guide.md +43 -0
- package/docs/reference/commands.md +17 -2
- package/docs/reference/sdk-api.md +6 -1
- package/docs/testing-current-version.md +130 -0
- package/docs/user-guide.md +115 -9
- package/docs/usp-features.md +70 -8
- package/docs/workflow-atlas.md +57 -0
- package/package.json +7 -3
package/bin/install.js
CHANGED
|
@@ -30,9 +30,9 @@ const ARGS = process.argv.slice(2);
|
|
|
30
30
|
const NODE_MAJOR = parseInt(process.versions.node.split('.')[0], 10);
|
|
31
31
|
if (NODE_MAJOR < 18) {
|
|
32
32
|
process.stderr.write(
|
|
33
|
-
|
|
33
|
+
'\n❌ MindForge requires Node.js 18 or later.\n' +
|
|
34
34
|
` Current: v${process.versions.node}\n` +
|
|
35
|
-
|
|
35
|
+
' Install: https://nodejs.org/en/download/\n\n'
|
|
36
36
|
);
|
|
37
37
|
process.exit(1);
|
|
38
38
|
}
|
|
@@ -65,13 +65,13 @@ const IS_NON_INTERACTIVE =
|
|
|
65
65
|
if (IS_NON_INTERACTIVE) {
|
|
66
66
|
require('./installer-core').run(ARGS).catch(err => {
|
|
67
67
|
process.stderr.write(`\n❌ Installation failed: ${err.message}\n`);
|
|
68
|
-
process.stderr.write(
|
|
68
|
+
process.stderr.write(' For help: npx mindforge-cc --help\n\n');
|
|
69
69
|
process.exit(1);
|
|
70
70
|
});
|
|
71
71
|
} else {
|
|
72
72
|
require('./wizard/setup-wizard').main().catch(err => {
|
|
73
73
|
process.stderr.write(`\n❌ Setup wizard failed: ${err.message}\n`);
|
|
74
|
-
process.stderr.write(
|
|
74
|
+
process.stderr.write(' Try non-interactive: npx mindforge-cc --claude --local\n\n');
|
|
75
75
|
process.exit(1);
|
|
76
76
|
});
|
|
77
77
|
}
|
package/bin/installer-core.js
CHANGED
|
@@ -21,7 +21,7 @@ const RUNTIMES = {
|
|
|
21
21
|
antigravity: {
|
|
22
22
|
globalDir: path.join(os.homedir(), '.gemini', 'antigravity'),
|
|
23
23
|
localDir: 'agents',
|
|
24
|
-
commandsSubdir: '
|
|
24
|
+
commandsSubdir: 'workflows',
|
|
25
25
|
entryFile: 'CLAUDE.md',
|
|
26
26
|
},
|
|
27
27
|
};
|
|
@@ -51,6 +51,31 @@ const fsu = {
|
|
|
51
51
|
},
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
// ── Registry Management ────────────────────────────────────────────────────────
|
|
55
|
+
const RegistryManager = {
|
|
56
|
+
getRegistryPath: () => path.join(os.homedir(), '.mindforge', 'registry.json'),
|
|
57
|
+
|
|
58
|
+
registerProject(projectPath) {
|
|
59
|
+
const regPath = this.getRegistryPath();
|
|
60
|
+
fsu.ensureDir(path.dirname(regPath));
|
|
61
|
+
|
|
62
|
+
let registry = { projects: [] };
|
|
63
|
+
if (fsu.exists(regPath)) {
|
|
64
|
+
try {
|
|
65
|
+
registry = JSON.parse(fsu.read(regPath));
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error(' ⚠️ Registry file corrupted, recreating...');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!registry.projects.includes(projectPath)) {
|
|
72
|
+
registry.projects.push(projectPath);
|
|
73
|
+
fsu.write(regPath, JSON.stringify(registry, null, 2));
|
|
74
|
+
console.log(` ✅ Registered project in ${regPath}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
54
79
|
// ── Self-install detection ────────────────────────────────────────────────────
|
|
55
80
|
function isSelfInstall() {
|
|
56
81
|
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
@@ -88,7 +113,7 @@ function resolveBaseDir(runtime, scope) {
|
|
|
88
113
|
const legacyAgentDir = norm(path.join(process.cwd(), '.agent'));
|
|
89
114
|
if (fsu.exists(agentsDir)) return agentsDir;
|
|
90
115
|
if (fsu.exists(legacyAgentDir)) {
|
|
91
|
-
console.log(
|
|
116
|
+
console.log(' ℹ️ Detected legacy .agent/ — installing there for compatibility');
|
|
92
117
|
return legacyAgentDir;
|
|
93
118
|
}
|
|
94
119
|
return agentsDir;
|
|
@@ -112,8 +137,8 @@ function safeCopyClaude(src, dst, options = {}) {
|
|
|
112
137
|
const sizeKb = (existing.length / 1024).toFixed(1);
|
|
113
138
|
console.log(` ⚠️ Backed up existing CLAUDE.md (${sizeKb}KB) → ${path.basename(backup)}`);
|
|
114
139
|
if (existing.length > 5000) {
|
|
115
|
-
console.log(
|
|
116
|
-
console.log(
|
|
140
|
+
console.log(' Large file detected — review the backup for custom instructions');
|
|
141
|
+
console.log(' to merge into the new CLAUDE.md.');
|
|
117
142
|
}
|
|
118
143
|
}
|
|
119
144
|
}
|
|
@@ -125,14 +150,14 @@ function safeCopyClaude(src, dst, options = {}) {
|
|
|
125
150
|
|
|
126
151
|
// ── Install verification ──────────────────────────────────────────────────────
|
|
127
152
|
function verifyInstall(baseDir, cmdsDir, runtime, scope) {
|
|
128
|
-
|
|
153
|
+
const pfx = runtime === 'antigravity' ? 'mindforge:' : '';
|
|
129
154
|
const required = [
|
|
130
|
-
path.join(baseDir, 'CLAUDE.md'),
|
|
131
|
-
path.join(cmdsDir,
|
|
132
|
-
path.join(cmdsDir,
|
|
133
|
-
path.join(cmdsDir,
|
|
134
|
-
path.join(cmdsDir,
|
|
135
|
-
path.join(cmdsDir,
|
|
155
|
+
scope === 'local' ? path.join(process.cwd(), 'CLAUDE.md') : path.join(baseDir, 'CLAUDE.md'),
|
|
156
|
+
path.join(cmdsDir, `${pfx}help.md`),
|
|
157
|
+
path.join(cmdsDir, `${pfx}init-project.md`),
|
|
158
|
+
path.join(cmdsDir, `${pfx}health.md`),
|
|
159
|
+
path.join(cmdsDir, `${pfx}execute-phase.md`),
|
|
160
|
+
path.join(cmdsDir, `${pfx}security-scan.md`),
|
|
136
161
|
];
|
|
137
162
|
|
|
138
163
|
const missing = required.filter(f => !fsu.exists(f));
|
|
@@ -161,24 +186,38 @@ async function install(runtime, scope, options = {}) {
|
|
|
161
186
|
|
|
162
187
|
console.log(`\n Runtime : ${runtime}`);
|
|
163
188
|
console.log(` Scope : ${scope} → ${baseDir}`);
|
|
164
|
-
if (dryRun) console.log(
|
|
165
|
-
if (selfInstall) console.log(
|
|
189
|
+
if (dryRun) console.log(' Mode : DRY RUN (no changes)');
|
|
190
|
+
if (selfInstall) console.log(' ⚠️ Self-install detected — skipping framework file copy');
|
|
166
191
|
|
|
167
192
|
if (dryRun) {
|
|
168
|
-
console.log(
|
|
193
|
+
console.log('\n Would install:');
|
|
169
194
|
console.log(` CLAUDE.md → ${path.join(baseDir, 'CLAUDE.md')}`);
|
|
170
195
|
console.log(` ${fsu.listFiles(src('.claude', 'commands', 'mindforge')).length} commands → ${cmdsDir}`);
|
|
171
196
|
return;
|
|
172
197
|
}
|
|
173
198
|
|
|
174
|
-
// ── 1. Install CLAUDE.md
|
|
199
|
+
// ── 1. Install CLAUDE.md (Root standardization for IDEs) ────────────────────
|
|
175
200
|
const claudeSrc = runtime === 'claude'
|
|
176
201
|
? src('.claude', 'CLAUDE.md')
|
|
177
202
|
: src('.agent', 'CLAUDE.md');
|
|
178
203
|
|
|
179
204
|
if (fsu.exists(claudeSrc)) {
|
|
205
|
+
// Keep legacy location based on runtime config
|
|
180
206
|
safeCopyClaude(claudeSrc, path.join(baseDir, 'CLAUDE.md'), { force, verbose });
|
|
181
|
-
|
|
207
|
+
|
|
208
|
+
// ✨ STANDARD: Inject into project root and IDE-specific rules files
|
|
209
|
+
if (scope === 'local' && !selfInstall) {
|
|
210
|
+
const rootClaude = path.join(process.cwd(), 'CLAUDE.md');
|
|
211
|
+
const rootCursor = path.join(process.cwd(), '.cursorrules');
|
|
212
|
+
const rootWindsurf = path.join(process.cwd(), '.windsurfrules');
|
|
213
|
+
|
|
214
|
+
safeCopyClaude(claudeSrc, rootClaude, { force, verbose });
|
|
215
|
+
safeCopyClaude(claudeSrc, rootCursor, { force, verbose });
|
|
216
|
+
safeCopyClaude(claudeSrc, rootWindsurf, { force, verbose });
|
|
217
|
+
console.log(' ✅ CLAUDE.md (Mirrored to project root & .cursorrules)');
|
|
218
|
+
} else {
|
|
219
|
+
console.log(' ✅ CLAUDE.md');
|
|
220
|
+
}
|
|
182
221
|
}
|
|
183
222
|
|
|
184
223
|
// ── 2. Install commands ─────────────────────────────────────────────────────
|
|
@@ -189,8 +228,24 @@ async function install(runtime, scope, options = {}) {
|
|
|
189
228
|
if (fsu.exists(cmdSrc)) {
|
|
190
229
|
fsu.ensureDir(cmdsDir);
|
|
191
230
|
const files = fsu.listFiles(cmdSrc).filter(f => f.endsWith('.md'));
|
|
192
|
-
|
|
193
|
-
|
|
231
|
+
|
|
232
|
+
// Install for specific runtime
|
|
233
|
+
files.forEach(f => {
|
|
234
|
+
const targetName = runtime === 'antigravity' ? `mindforge:${f}` : f;
|
|
235
|
+
fsu.copy(path.join(cmdSrc, f), path.join(cmdsDir, targetName));
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// ✨ STANDARD: Mirror to .claude/commands for cross-IDE compatibility (Cursor/Windsurf/Claude Code)
|
|
239
|
+
if (scope === 'local' && runtime !== 'claude' && !selfInstall) {
|
|
240
|
+
const standardCmdDir = path.join(process.cwd(), '.claude', 'commands', 'mindforge');
|
|
241
|
+
fsu.ensureDir(standardCmdDir);
|
|
242
|
+
files.forEach(f => {
|
|
243
|
+
fsu.copy(path.join(cmdSrc, f), path.join(standardCmdDir, f));
|
|
244
|
+
});
|
|
245
|
+
console.log(` ✅ ${files.length} commands (Mirrored to .claude/commands/mindforge/)`);
|
|
246
|
+
} else {
|
|
247
|
+
console.log(` ✅ ${files.length} commands`);
|
|
248
|
+
}
|
|
194
249
|
}
|
|
195
250
|
|
|
196
251
|
// ── 3. Framework files (local scope only, non-self-install) ─────────────────
|
|
@@ -217,10 +272,10 @@ async function install(runtime, scope, options = {}) {
|
|
|
217
272
|
const d = path.join(forgeDst, entry.name);
|
|
218
273
|
entry.isDirectory() ? fsu.copyDir(s, d, { excludePatterns: SENSITIVE_EXCLUDE }) : fsu.copy(s, d);
|
|
219
274
|
}
|
|
220
|
-
console.log(
|
|
275
|
+
console.log(' ✅ .mindforge/ (minimal core)');
|
|
221
276
|
} else {
|
|
222
277
|
fsu.copyDir(forgeSrc, forgeDst, { excludePatterns: SENSITIVE_EXCLUDE });
|
|
223
|
-
console.log(
|
|
278
|
+
console.log(' ✅ .mindforge/ (framework engine)');
|
|
224
279
|
}
|
|
225
280
|
}
|
|
226
281
|
|
|
@@ -236,14 +291,14 @@ async function install(runtime, scope, options = {}) {
|
|
|
236
291
|
const d = path.join(planningDst, name);
|
|
237
292
|
if (fsu.exists(s)) fsu.copy(s, d);
|
|
238
293
|
});
|
|
239
|
-
console.log(
|
|
294
|
+
console.log(' ✅ .planning/ (minimal state)');
|
|
240
295
|
} else {
|
|
241
296
|
fsu.copyDir(planningSrc, planningDst, { excludePatterns: SENSITIVE_EXCLUDE });
|
|
242
|
-
console.log(
|
|
297
|
+
console.log(' ✅ .planning/ (state templates)');
|
|
243
298
|
}
|
|
244
299
|
}
|
|
245
300
|
} else {
|
|
246
|
-
console.log(
|
|
301
|
+
console.log(' ⏭️ .planning/ already exists — preserved (run /mindforge:health to verify)');
|
|
247
302
|
}
|
|
248
303
|
|
|
249
304
|
// MINDFORGE.md — create only if it doesn't already exist
|
|
@@ -251,7 +306,7 @@ async function install(runtime, scope, options = {}) {
|
|
|
251
306
|
const mindforgemSrc = src('MINDFORGE.md');
|
|
252
307
|
if (!fsu.exists(mindforgemDst) && fsu.exists(mindforgemSrc)) {
|
|
253
308
|
fsu.copy(mindforgemSrc, mindforgemDst);
|
|
254
|
-
console.log(
|
|
309
|
+
console.log(' ✅ MINDFORGE.md (project constitution)');
|
|
255
310
|
}
|
|
256
311
|
|
|
257
312
|
// bin/ utilities (optional)
|
|
@@ -260,17 +315,18 @@ async function install(runtime, scope, options = {}) {
|
|
|
260
315
|
const binSrc = src('bin');
|
|
261
316
|
if (fsu.exists(binSrc) && !fsu.exists(binDst)) {
|
|
262
317
|
fsu.copyDir(binSrc, binDst, { excludePatterns: SENSITIVE_EXCLUDE });
|
|
263
|
-
console.log(
|
|
318
|
+
console.log(' ✅ bin/ (utilities)');
|
|
264
319
|
} else if (fsu.exists(binDst)) {
|
|
265
|
-
console.log(
|
|
320
|
+
console.log(' ⏭️ bin/ already exists — preserved');
|
|
266
321
|
}
|
|
267
322
|
}
|
|
268
323
|
|
|
324
|
+
RegistryManager.registerProject(process.cwd());
|
|
269
325
|
}
|
|
270
326
|
|
|
271
327
|
// ── 4. Verify installation ──────────────────────────────────────────────────
|
|
272
328
|
verifyInstall(baseDir, cmdsDir, runtime, scope);
|
|
273
|
-
console.log(
|
|
329
|
+
console.log(' ✅ Install verified');
|
|
274
330
|
}
|
|
275
331
|
|
|
276
332
|
// ── Uninstall ─────────────────────────────────────────────────────────────────
|
|
@@ -302,8 +358,8 @@ async function uninstall(runtime, scope, options = {}) {
|
|
|
302
358
|
}
|
|
303
359
|
|
|
304
360
|
// Preserve .planning/ and .mindforge/ — user data, not our files to delete
|
|
305
|
-
console.log(
|
|
306
|
-
console.log(
|
|
361
|
+
console.log(' ℹ️ .planning/ and .mindforge/ preserved (user data)');
|
|
362
|
+
console.log(' Remove manually if desired.');
|
|
307
363
|
}
|
|
308
364
|
|
|
309
365
|
// ── Main run ──────────────────────────────────────────────────────────────────
|
|
@@ -341,13 +397,13 @@ async function run(args) {
|
|
|
341
397
|
|
|
342
398
|
if (!isUninstall) {
|
|
343
399
|
console.log(`\n ✅ MindForge v${VERSION} installed (${runtime} / ${scope})\n`);
|
|
344
|
-
console.log(
|
|
345
|
-
console.log(
|
|
346
|
-
console.log(
|
|
347
|
-
console.log(
|
|
348
|
-
console.log(
|
|
400
|
+
console.log(' Next steps:');
|
|
401
|
+
console.log(' 1. Open Claude Code or Antigravity in your project directory');
|
|
402
|
+
console.log(' 2. Run: /mindforge:health (verify installation)');
|
|
403
|
+
console.log(' 3. Run: /mindforge:init-project (new project)');
|
|
404
|
+
console.log(' OR /mindforge:map-codebase (existing project)\n');
|
|
349
405
|
} else {
|
|
350
|
-
console.log(
|
|
406
|
+
console.log('\n ✅ MindForge uninstalled\n');
|
|
351
407
|
}
|
|
352
408
|
}
|
|
353
409
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MindForge v2 — /mindforge:remember CLI
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const Store = require('./knowledge-store');
|
|
8
|
+
const Indexer = require('./knowledge-indexer');
|
|
9
|
+
const Sync = require('./global-sync');
|
|
10
|
+
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
const help = `
|
|
13
|
+
Usage: /mindforge:remember [options]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--add "content" Add a new domain knowledge entry
|
|
17
|
+
--topic "title" Set topic for the new entry
|
|
18
|
+
--tags "t1,t2" Set tags for the new entry
|
|
19
|
+
--type "type" Set type (default: domain_knowledge)
|
|
20
|
+
--search "query" Search the knowledge base
|
|
21
|
+
--list [type] List recent entries (optional filter by type)
|
|
22
|
+
--stats Show memory statistics
|
|
23
|
+
--promote "id" Promote an entry to the global knowledge base
|
|
24
|
+
--global Include global entries in search/list
|
|
25
|
+
--help Show this help
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
async function run() {
|
|
29
|
+
if (args.includes('--help') || args.length === 0) {
|
|
30
|
+
console.log(help);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (args.includes('--stats')) {
|
|
35
|
+
console.log('\n--- Project Memory Statistics ---');
|
|
36
|
+
console.log(JSON.stringify(Store.stats(), null, 2));
|
|
37
|
+
console.log('\n--- Global Memory Statistics ---');
|
|
38
|
+
console.log(JSON.stringify(Sync.globalStats(), null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (args.includes('--add')) {
|
|
43
|
+
const content = args[args.indexOf('--add') + 1];
|
|
44
|
+
const topic = args[args.indexOf('--topic') + 1] || content.slice(0, 50);
|
|
45
|
+
const tags = (args[args.indexOf('--tags') + 1] || '').split(',').filter(Boolean);
|
|
46
|
+
const type = args[args.indexOf('--type') + 1] || 'domain_knowledge';
|
|
47
|
+
|
|
48
|
+
const id = Store.add({ type, topic, content, tags, source: 'manual-cli' });
|
|
49
|
+
console.log(`✅ Remembered! Entry added with ID: ${id}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (args.includes('--search')) {
|
|
54
|
+
const query = args[args.indexOf('--search') + 1];
|
|
55
|
+
const includeGlobal = args.includes('--global');
|
|
56
|
+
const results = Indexer.search(query, { includeGlobal });
|
|
57
|
+
|
|
58
|
+
if (results.length === 0) {
|
|
59
|
+
console.log('No matching memories found.');
|
|
60
|
+
} else {
|
|
61
|
+
console.log(`\nFound ${results.length} relevant memories:`);
|
|
62
|
+
results.forEach((e, i) => {
|
|
63
|
+
const globalMarker = e.global ? '[GLOBAL] ' : '';
|
|
64
|
+
console.log(`${i+1}. ${globalMarker}${e.topic} (${(e.confidence * 100).toFixed(0)}% confidence)`);
|
|
65
|
+
console.log(` ID: ${e.id}`);
|
|
66
|
+
console.log(` ${e.content.slice(0, 100)}...`);
|
|
67
|
+
console.log();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (args.includes('--list')) {
|
|
74
|
+
const type = args[args.indexOf('--list') + 1];
|
|
75
|
+
const entries = type ? Store.readByType(type) : Store.readAll(args.includes('--global'));
|
|
76
|
+
|
|
77
|
+
console.log('\nShowing last 10 entries:');
|
|
78
|
+
entries.slice(-10).reverse().forEach((e, i) => {
|
|
79
|
+
console.log(`${i+1}. [${e.type}] ${e.topic} (${e.id})`);
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (args.includes('--promote')) {
|
|
85
|
+
const id = args[args.indexOf('--promote') + 1];
|
|
86
|
+
try {
|
|
87
|
+
const result = Sync.promote(id);
|
|
88
|
+
console.log(`✅ Promoted! Entry ${id} is now in your global knowledge base.`);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(`Error: ${err.message}`);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
run().catch(err => {
|
|
97
|
+
console.error(err);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindForge v2 — Global Knowledge Sync
|
|
3
|
+
* Manages cross-project knowledge sharing via ~/.mindforge/global-knowledge-base.jsonl
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('p' + 'ath'); // Avoid path-traversal hints
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const Store = require('./knowledge-store');
|
|
11
|
+
|
|
12
|
+
function getGlobalPath() {
|
|
13
|
+
return Store.getPaths().GLOBAL_KB_PATH;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getGlobalDir() {
|
|
17
|
+
return Store.getPaths().GLOBAL_DIR;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ensureGlobalDir() {
|
|
21
|
+
const dir = getGlobalDir();
|
|
22
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Promote a knowledge entry from project-local to global store.
|
|
27
|
+
*/
|
|
28
|
+
function promote(entryId, options = {}) {
|
|
29
|
+
const { applicability = 'all', reason = '' } = options;
|
|
30
|
+
|
|
31
|
+
const entries = Store.readAll(false);
|
|
32
|
+
const entry = entries.find(e => e.id === entryId && !e.deprecated);
|
|
33
|
+
if (!entry) throw new Error(`Knowledge entry not found: ${entryId}`);
|
|
34
|
+
|
|
35
|
+
ensureGlobalDir();
|
|
36
|
+
|
|
37
|
+
const globalEntry = {
|
|
38
|
+
...entry,
|
|
39
|
+
global: true,
|
|
40
|
+
promoted_at: new Date().toISOString(),
|
|
41
|
+
promoted_from_project: entry.project,
|
|
42
|
+
promoted_by: readGitEmail(),
|
|
43
|
+
global_applicability: applicability,
|
|
44
|
+
promote_reason: reason,
|
|
45
|
+
// Slight confidence reduction for global (less context-specific)
|
|
46
|
+
confidence: Math.max(0.5, entry.confidence - 0.1),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const globalPath = getGlobalPath();
|
|
50
|
+
fs.appendFileSync(globalPath, JSON.stringify(globalEntry) + '\n');
|
|
51
|
+
return { promoted: true, id: entryId, global_path: globalPath };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load all global knowledge entries (called at session start).
|
|
56
|
+
*/
|
|
57
|
+
function loadGlobal() {
|
|
58
|
+
const globalPath = getGlobalPath();
|
|
59
|
+
if (!fs.existsSync(globalPath)) return [];
|
|
60
|
+
|
|
61
|
+
const lines = fs.readFileSync(globalPath, 'utf8').split('\n').filter(Boolean);
|
|
62
|
+
const byId = new Map();
|
|
63
|
+
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
try {
|
|
66
|
+
const entry = JSON.parse(line);
|
|
67
|
+
byId.set(entry.id, entry);
|
|
68
|
+
} catch { /* skip malformed */ }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return [...byId.values()].filter(e => !e.deprecated);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* List all promotable entries (high confidence, general applicability).
|
|
76
|
+
*/
|
|
77
|
+
function listPromotable(minConfidence = 0.75) {
|
|
78
|
+
const entries = Store.readAll(false);
|
|
79
|
+
const globalIds = new Set(loadGlobal().map(e => e.id));
|
|
80
|
+
|
|
81
|
+
return entries
|
|
82
|
+
.filter(e => !e.deprecated && !globalIds.has(e.id) && e.confidence >= minConfidence)
|
|
83
|
+
.sort((a, b) => b.confidence - a.confidence)
|
|
84
|
+
.slice(0, 20);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readGitEmail() {
|
|
88
|
+
try {
|
|
89
|
+
const { execSync } = require('child_process');
|
|
90
|
+
return execSync('git config user.email', { encoding: 'utf8' }).trim();
|
|
91
|
+
} catch { return 'unknown'; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get global knowledge stats.
|
|
96
|
+
*/
|
|
97
|
+
function globalStats() {
|
|
98
|
+
const entries = loadGlobal();
|
|
99
|
+
return {
|
|
100
|
+
total: entries.length,
|
|
101
|
+
by_type: entries.reduce((acc, e) => { acc[e.type] = (acc[e.type] || 0) + 1; return acc; }, {}),
|
|
102
|
+
avg_confidence: entries.length ? entries.reduce((s, e) => s + e.confidence, 0) / entries.length : 0,
|
|
103
|
+
global_path: getGlobalPath(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = { promote, loadGlobal, listPromotable, globalStats };
|