@mnemosyne_os/forge 1.0.0 → 1.2.2
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/CHANGELOG.md +34 -34
- package/LICENSE +21 -21
- package/README.md +230 -230
- package/dist/cli.js +667 -76
- package/dist/lib/chronicle.js +105 -0
- package/dist/lib/init-flow.js +139 -0
- package/dist/lib/providers.js +46 -0
- package/dist/lib/sources/antigravity.js +142 -0
- package/dist/lib/sources/index.js +172 -0
- package/dist/lib/vault.js +118 -0
- package/package.json +14 -2
- package/dist/templates/index.template.js +0 -36
- package/src/cli.ts +0 -121
- package/src/templates/.cursorrules +0 -55
- package/src/templates/AGENT_INSTRUCTIONS.md +0 -60
- package/src/templates/index.template.tsx +0 -34
- package/tsconfig.json +0 -15
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
38
|
};
|
|
@@ -9,100 +42,658 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
9
42
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
43
|
const fs_1 = __importDefault(require("fs"));
|
|
11
44
|
const path_1 = __importDefault(require("path"));
|
|
45
|
+
const os_1 = __importDefault(require("os"));
|
|
46
|
+
const vault_js_1 = require("./lib/vault.js");
|
|
47
|
+
const chronicle_js_1 = require("./lib/chronicle.js");
|
|
48
|
+
const init_flow_js_1 = require("./lib/init-flow.js");
|
|
49
|
+
const index_js_1 = require("./lib/sources/index.js");
|
|
12
50
|
// ─────────────────────────────────────────────
|
|
13
51
|
// MnemoForge CLI — Mnemosyne Neural OS
|
|
14
52
|
// AI Inception Engine · XPACEGEMS LLC
|
|
15
53
|
// ─────────────────────────────────────────────
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
54
|
+
// ─────────────────────────────────────────────
|
|
55
|
+
// Welcome Dashboard — shown when no command given
|
|
56
|
+
// ─────────────────────────────────────────────
|
|
57
|
+
const V = chalk_1.default.hex('#8B5CF6');
|
|
58
|
+
const V2 = chalk_1.default.hex('#A78BFA');
|
|
59
|
+
const V3 = chalk_1.default.hex('#C4B5FD');
|
|
60
|
+
const V4 = chalk_1.default.hex('#DDD6FE');
|
|
61
|
+
const DIM = chalk_1.default.gray;
|
|
62
|
+
const HL = chalk_1.default.hex('#A78BFA').bold;
|
|
63
|
+
const ASCII = [
|
|
64
|
+
V('███╗ ███╗███╗ ██╗███████╗███╗ ███╗ ██████╗ '),
|
|
65
|
+
V('████╗ ████║████╗ ██║██╔════╝████╗ ████║██╔═══██╗'),
|
|
66
|
+
V2('██╔████╔██║██╔██╗ ██║█████╗ ██╔████╔██║██║ ██║'),
|
|
67
|
+
V3('██║╚██╔╝██║██║╚██╗██║██╔══╝ ██║╚██╔╝██║██║ ██║'),
|
|
68
|
+
V4('██║ ╚═╝ ██║██║ ╚████║███████╗██║ ╚═╝ ██║╚██████╔╝'),
|
|
69
|
+
chalk_1.default.hex('#EDE9FE')('╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ '),
|
|
70
|
+
].join('\n');
|
|
71
|
+
function showWelcome() {
|
|
72
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
73
|
+
const w = '═'.repeat(52);
|
|
74
|
+
const pad = (s, n) => s + ' '.repeat(Math.max(0, n - s.length));
|
|
75
|
+
console.log();
|
|
76
|
+
console.log(ASCII);
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(V(' ╔' + w + '╗'));
|
|
79
|
+
console.log(V(' ║') + chalk_1.default.hex('#F5F3FF').bold(' M N E M O S Y N E O S — N E U R A L O S ') + V(' ║'));
|
|
80
|
+
console.log(V(' ║') + DIM(' MnemoForge CLI v1.2.0 · XPACEGEMS LLC ') + V(' ║'));
|
|
81
|
+
console.log(V(' ╠' + w + '╣'));
|
|
82
|
+
if (config) {
|
|
83
|
+
const profiles = config.registeredModels ?? [];
|
|
84
|
+
const activeChron = (0, vault_js_1.listChronicles)(config).length;
|
|
85
|
+
const activeStyle = config.defaultChronicleStyle ?? 'session';
|
|
86
|
+
const activeName = config.ide + ' / ' + config.provider;
|
|
87
|
+
console.log(V(' ║') + DIM(' ⚡ RESONANCE PROFILES ') + V(' ║'));
|
|
88
|
+
console.log(V(' ║') + ' ' + chalk_1.default.green('★') + ' ' + chalk_1.default.white(pad(activeName, 32)) + DIM(pad(activeStyle, 12)) + DIM(activeChron + ' chron.') + ' ' + chalk_1.default.green('[✓]') + ' ' + V(' ║'));
|
|
89
|
+
if (profiles.length > 0) {
|
|
90
|
+
console.log(V(' ║') + ' ' + DIM('─'.repeat(48)) + V(' ║'));
|
|
91
|
+
profiles.forEach((p, i) => {
|
|
92
|
+
const pName = p.ide + ' / ' + p.provider;
|
|
93
|
+
const pStyle = p.defaultChronicleStyle ?? 'session';
|
|
94
|
+
console.log(V(' ║') + ' ' + DIM('○') + ' ' + DIM(pad(pName, 32)) + DIM(pad(pStyle, 12)) + DIM('[' + (i + 1) + '] switch') + ' ' + V(' ║'));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(V(' ║') + chalk_1.default.yellow(' ⚠ No vault configured.') + ' Run: ' + chalk_1.default.white('mnemoforge chronicle init') + ' ' + V(' ║'));
|
|
100
|
+
}
|
|
101
|
+
console.log(V(' ╠' + w + '╣'));
|
|
102
|
+
console.log(V(' ║') + DIM(' COMMANDS ') + V(' ║'));
|
|
103
|
+
console.log(V(' ║') + ' ' + V2('chronicle init ') + DIM('─ add / reconfigure a profile ') + V(' ║'));
|
|
104
|
+
console.log(V(' ║') + ' ' + V2('chronicle switch ') + DIM('─ change active profile ') + V(' ║'));
|
|
105
|
+
console.log(V(' ║') + ' ' + V2('chronicle config ') + DIM('─ edit a profile settings ') + V(' ║'));
|
|
106
|
+
console.log(V(' ║') + ' ' + V2('chronicle commit ') + DIM('─ write a new chronicle ') + V(' ║'));
|
|
107
|
+
console.log(V(' ║') + ' ' + V2('chronicle list ') + DIM('─ explore vault ') + V(' ║'));
|
|
108
|
+
console.log(V(' ║') + ' ' + V2('models import ') + DIM('─ add from UniversalModelCard ') + V(' ║'));
|
|
109
|
+
console.log(V(' ╠' + w + '╣'));
|
|
110
|
+
console.log(V(' ║') + DIM(' "Memory is the architecture of intelligence." ') + V(' ║'));
|
|
111
|
+
console.log(V(' ╚' + w + '╝'));
|
|
112
|
+
console.log();
|
|
113
|
+
}
|
|
114
|
+
const BANNER = ASCII;
|
|
27
115
|
const program = new commander_1.Command();
|
|
28
116
|
program
|
|
29
117
|
.name('mnemoforge')
|
|
30
118
|
.description('MnemoForge — AI Inception Engine for the Mnemosyne Neural OS ecosystem')
|
|
31
|
-
.version('1.
|
|
32
|
-
.addHelpText('beforeAll', BANNER)
|
|
119
|
+
.version('1.2.0', '-v, --version', 'Display current version')
|
|
120
|
+
.addHelpText('beforeAll', BANNER + '\n')
|
|
121
|
+
.action(() => { showWelcome(); });
|
|
33
122
|
program
|
|
34
123
|
.command('init')
|
|
35
124
|
.description('Scaffold a new Mnemosyne-grade module with AI governance DNA')
|
|
36
125
|
.argument('[module-name]', 'Name of the module to create (PascalCase recommended)')
|
|
37
126
|
.option('--no-git', 'Skip git initialization')
|
|
38
|
-
.action(async (
|
|
39
|
-
console.log(
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
127
|
+
.action(async () => {
|
|
128
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n\u29e1 MnemoChronicle \u2014 Vault Init\n'));
|
|
129
|
+
const existing = (0, vault_js_1.loadVaultConfig)();
|
|
130
|
+
if (existing) {
|
|
131
|
+
console.log(chalk_1.default.yellow(' \u26a0 Already configured:'));
|
|
132
|
+
console.log(chalk_1.default.gray(' IDE: ' + existing.ide));
|
|
133
|
+
console.log(chalk_1.default.gray(' Provider: ' + existing.provider + '\n'));
|
|
134
|
+
}
|
|
135
|
+
const profile = await (0, init_flow_js_1.askPrimaryProfile)(existing);
|
|
136
|
+
// \u2500\u2500 Extra profiles (loop)
|
|
137
|
+
const registeredModels = existing?.registeredModels ?? [];
|
|
138
|
+
// Auto-demote old primary when switching
|
|
139
|
+
if (existing && (existing.ide !== profile.ide || existing.provider !== profile.provider)) {
|
|
140
|
+
const old = { ide: existing.ide, provider: existing.provider, defaultChronicleStyle: existing.defaultChronicleStyle };
|
|
141
|
+
if (!registeredModels.some(m => m.ide === old.ide && m.provider === old.provider))
|
|
142
|
+
registeredModels.unshift(old);
|
|
143
|
+
}
|
|
144
|
+
let extra = await (0, init_flow_js_1.askExtraProfile)(registeredModels.length);
|
|
145
|
+
while (extra) {
|
|
146
|
+
console.log(chalk_1.default.green(' \u2714 Added: ' + extra.provider + ' (' + extra.ide + ') \u00b7 style: ' + extra.defaultChronicleStyle));
|
|
147
|
+
registeredModels.push(extra);
|
|
148
|
+
extra = await (0, init_flow_js_1.askExtraProfile)(registeredModels.length);
|
|
149
|
+
}
|
|
150
|
+
const config = { ...profile, registeredModels };
|
|
151
|
+
(0, vault_js_1.saveVaultConfig)(config);
|
|
152
|
+
const res = config.vaultPath + '/.cli_resonance/' + config.ide + '/' + config.provider + '/';
|
|
153
|
+
console.log(chalk_1.default.green('\n \u2714 Vault configured!'));
|
|
154
|
+
console.log(chalk_1.default.gray(' IDE: ') + chalk_1.default.white(config.ide));
|
|
155
|
+
console.log(chalk_1.default.gray(' Provider: ') + chalk_1.default.white(config.provider));
|
|
156
|
+
console.log(chalk_1.default.gray(' Style: ') + chalk_1.default.hex('#A78BFA')(config.defaultChronicleStyle ?? 'session'));
|
|
157
|
+
if (registeredModels.length > 0)
|
|
158
|
+
console.log(chalk_1.default.gray(' + ' + registeredModels.length + ' extra profile(s)'));
|
|
159
|
+
console.log(chalk_1.default.gray('\n Chronicles \u2192 ') + chalk_1.default.hex('#A78BFA')(res) + '\n');
|
|
160
|
+
console.log(chalk_1.default.gray(' Run ') + chalk_1.default.white('mnemoforge') + chalk_1.default.gray(' to see your dashboard.\n'));
|
|
161
|
+
});
|
|
162
|
+
// ─────────────────────────────────────────────
|
|
163
|
+
// ─────────────────────────────────────────────
|
|
164
|
+
// CATALOG — IDE / Provider / Model
|
|
165
|
+
// ─────────────────────────────────────────────
|
|
166
|
+
// Model names are free text — stored in chronicle frontmatter, not in folder structure
|
|
167
|
+
// ─────────────────────────────────────────────
|
|
168
|
+
// WORKSPACE COMMANDS
|
|
169
|
+
// mnemoforge workspace init | show | add-rule
|
|
170
|
+
// mnemoforge project init
|
|
171
|
+
// External safety memory — readable by any agent at session start
|
|
172
|
+
// ─────────────────────────────────────────────
|
|
173
|
+
const workspace = new commander_1.Command('workspace')
|
|
174
|
+
.description('Workspace & Resonance Project memory — rules that survive IDE sessions');
|
|
175
|
+
workspace
|
|
176
|
+
.command('init')
|
|
177
|
+
.description('Initialize a Workspace (ecosystem / org container) in the current directory')
|
|
178
|
+
.option('--name <name>', 'Workspace name (e.g. Mnemosyne-OS)')
|
|
179
|
+
.action(async (opts) => {
|
|
180
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ MnemoWorkspace — Init\n'));
|
|
181
|
+
const answers = await inquirer_1.default.prompt([
|
|
182
|
+
{
|
|
183
|
+
type: 'input', name: 'name', message: 'Workspace name (e.g. Mnemosyne-OS):',
|
|
184
|
+
default: opts.name ?? path_1.default.basename(process.cwd()),
|
|
185
|
+
when: !opts.name,
|
|
186
|
+
},
|
|
187
|
+
]);
|
|
188
|
+
const name = opts.name ?? answers.name;
|
|
189
|
+
const wsPath = path_1.default.join(process.cwd(), '.cli_resonance', 'WORKSPACE.json');
|
|
190
|
+
const existing = fs_1.default.existsSync(wsPath) ? JSON.parse(fs_1.default.readFileSync(wsPath, 'utf8')) : {};
|
|
191
|
+
const ws = {
|
|
192
|
+
...existing,
|
|
193
|
+
workspace: name,
|
|
194
|
+
workspace_version: '0.1',
|
|
195
|
+
last_updated: new Date().toISOString().slice(0, 10),
|
|
196
|
+
updated_by: 'mnemoforge workspace init',
|
|
197
|
+
};
|
|
198
|
+
fs_1.default.mkdirSync(path_1.default.join(process.cwd(), '.cli_resonance'), { recursive: true });
|
|
199
|
+
fs_1.default.writeFileSync(wsPath, JSON.stringify(ws, null, 2), 'utf8');
|
|
200
|
+
console.log(chalk_1.default.green(` ✔ Workspace "${name}" initialized\n`));
|
|
201
|
+
console.log(chalk_1.default.gray(` → .cli_resonance/WORKSPACE.json\n`));
|
|
202
|
+
console.log(chalk_1.default.cyan(' Next: ') + chalk_1.default.white('mnemoforge project init') + chalk_1.default.gray(' ← create a Resonance Project\n'));
|
|
203
|
+
});
|
|
204
|
+
// ─────────────────────────────────────────────
|
|
205
|
+
// PROJECT COMMANDS
|
|
206
|
+
// mnemoforge project init
|
|
207
|
+
// ─────────────────────────────────────────────
|
|
208
|
+
const project = new commander_1.Command('project')
|
|
209
|
+
.description('Resonance Project — a component or feature within a Workspace');
|
|
210
|
+
project
|
|
211
|
+
.command('init')
|
|
212
|
+
.description('Initialize a Resonance Project — links a workspace + project to the vault')
|
|
213
|
+
.action(async () => {
|
|
214
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ Resonance Project — Init\n'));
|
|
215
|
+
// Load existing workspace name from WORKSPACE.json if present
|
|
216
|
+
const wsPath = path_1.default.join(process.cwd(), '.cli_resonance', 'WORKSPACE.json');
|
|
217
|
+
const wsData = fs_1.default.existsSync(wsPath) ? JSON.parse(fs_1.default.readFileSync(wsPath, 'utf8')) : {};
|
|
218
|
+
const existingConfig = (0, vault_js_1.loadVaultConfig)();
|
|
219
|
+
const answers = await inquirer_1.default.prompt([
|
|
220
|
+
{
|
|
221
|
+
type: 'input', name: 'workspace',
|
|
222
|
+
message: 'Workspace name (ecosystem / org):',
|
|
223
|
+
default: wsData.workspace ?? 'Mnemosyne-OS',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
type: 'input', name: 'resonanceProject',
|
|
227
|
+
message: 'Resonance Project name (feature / component):',
|
|
228
|
+
default: path_1.default.basename(process.cwd()),
|
|
229
|
+
},
|
|
230
|
+
]);
|
|
231
|
+
// Merge into vault config
|
|
232
|
+
const config = {
|
|
233
|
+
...(existingConfig ?? {
|
|
234
|
+
vaultPath: vault_js_1.DEFAULT_VAULT,
|
|
235
|
+
ide: 'Antigravity',
|
|
236
|
+
provider: 'Anthropic',
|
|
237
|
+
}),
|
|
238
|
+
workspace: answers.workspace,
|
|
239
|
+
resonanceProject: answers.resonanceProject,
|
|
240
|
+
};
|
|
241
|
+
(0, vault_js_1.saveVaultConfig)(config);
|
|
242
|
+
// Update WORKSPACE.json too
|
|
243
|
+
const ws = { ...wsData, workspace: answers.workspace, resonanceProject: answers.resonanceProject, last_updated: new Date().toISOString().slice(0, 10) };
|
|
244
|
+
fs_1.default.mkdirSync(path_1.default.join(process.cwd(), '.cli_resonance'), { recursive: true });
|
|
245
|
+
fs_1.default.writeFileSync(wsPath, JSON.stringify(ws, null, 2), 'utf8');
|
|
246
|
+
// Create handbook/chronicles/ scaffold
|
|
247
|
+
const chroniclesDir = path_1.default.join(process.cwd(), 'handbook', 'chronicles');
|
|
248
|
+
fs_1.default.mkdirSync(chroniclesDir, { recursive: true });
|
|
249
|
+
console.log(chalk_1.default.green(`\n ✔ Resonance Project "${answers.resonanceProject}" initialized\n`));
|
|
250
|
+
console.log(chalk_1.default.cyan(' Workspace : ') + chalk_1.default.white(answers.workspace));
|
|
251
|
+
console.log(chalk_1.default.cyan(' Project : ') + chalk_1.default.white(answers.resonanceProject));
|
|
252
|
+
console.log(chalk_1.default.cyan(' Vault path : ') + chalk_1.default.gray(`${config.vaultPath}/${answers.workspace}/${answers.resonanceProject}/`));
|
|
253
|
+
console.log(chalk_1.default.cyan(' Chronicles : ') + chalk_1.default.gray('./handbook/chronicles/\n'));
|
|
254
|
+
console.log(chalk_1.default.hex('#8B5CF6')(' Chronicles go in vault:'));
|
|
255
|
+
console.log(chalk_1.default.gray(` ${config.vaultPath}/${answers.workspace}/${answers.resonanceProject}/${config.ide}/${config.provider}/\n`));
|
|
256
|
+
});
|
|
257
|
+
program.addCommand(project);
|
|
258
|
+
workspace
|
|
259
|
+
.command('show')
|
|
260
|
+
.description('Show workspace rules (agent briefing before starting work)')
|
|
261
|
+
.action(async () => {
|
|
262
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
263
|
+
const wsPath = path_1.default.join(process.cwd(), '.cli_resonance', 'WORKSPACE.json');
|
|
264
|
+
const globalWsPath = path_1.default.join(config?.vaultPath ?? path_1.default.join(os_1.default.homedir(), 'Documents', 'MnemoVault'), '.cli_resonance', 'WORKSPACE.json');
|
|
265
|
+
const target = fs_1.default.existsSync(wsPath) ? wsPath : fs_1.default.existsSync(globalWsPath) ? globalWsPath : null;
|
|
266
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ MnemoWorkspace — Agent Briefing\n'));
|
|
267
|
+
if (!target) {
|
|
268
|
+
console.log(chalk_1.default.yellow(' ⚠ No WORKSPACE.json found.'));
|
|
269
|
+
console.log(chalk_1.default.gray(' Run from a project root or use: mnemoforge workspace init\n'));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const ws = JSON.parse(fs_1.default.readFileSync(target, 'utf8'));
|
|
273
|
+
console.log(chalk_1.default.cyan(` Project : `) + chalk_1.default.white(ws.project ?? '—'));
|
|
274
|
+
console.log(chalk_1.default.cyan(` Version : `) + chalk_1.default.gray(ws.version ?? '—'));
|
|
275
|
+
console.log(chalk_1.default.cyan(` Source : `) + chalk_1.default.gray(target));
|
|
276
|
+
if (config?.workspace)
|
|
277
|
+
console.log(chalk_1.default.cyan(` Vault ws : `) + chalk_1.default.gray(config.workspace));
|
|
278
|
+
// Print all rule arrays found in the workspace
|
|
279
|
+
const printRules = (label, rules) => {
|
|
280
|
+
if (!rules?.length)
|
|
281
|
+
return;
|
|
282
|
+
console.log(chalk_1.default.hex('#8B5CF6')(`\n ▸ ${label}`));
|
|
283
|
+
rules.forEach(r => console.log(chalk_1.default.gray(' • ') + r));
|
|
284
|
+
};
|
|
285
|
+
Object.entries(ws).forEach(([key, val]) => {
|
|
286
|
+
if (val?.rules?.length)
|
|
287
|
+
printRules(key, val.rules);
|
|
288
|
+
});
|
|
289
|
+
if (ws.neural_coding?.principles?.length) {
|
|
290
|
+
printRules('neural_coding.principles', ws.neural_coding.principles);
|
|
291
|
+
}
|
|
292
|
+
console.log(chalk_1.default.gray(`\n Last updated: ${ws.last_updated ?? '—'} by ${ws.updated_by ?? '—'}\n`));
|
|
293
|
+
});
|
|
294
|
+
workspace
|
|
295
|
+
.command('add-rule')
|
|
296
|
+
.description('Append a rule to the workspace safety memory')
|
|
297
|
+
.argument('<rule>', 'The rule text to add')
|
|
298
|
+
.option('--section <section>', 'Section to add to (npm | architecture | dev)', 'dev')
|
|
299
|
+
.action(async (rule, opts) => {
|
|
300
|
+
const wsPath = path_1.default.join(process.cwd(), '.cli_resonance', 'WORKSPACE.json');
|
|
301
|
+
if (!fs_1.default.existsSync(wsPath)) {
|
|
302
|
+
console.log(chalk_1.default.red('\n ✖ No WORKSPACE.json in current directory.\n'));
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
const ws = JSON.parse(fs_1.default.readFileSync(wsPath, 'utf8'));
|
|
306
|
+
const section = opts.section ?? 'dev';
|
|
307
|
+
if (!ws[section])
|
|
308
|
+
ws[section] = {};
|
|
309
|
+
if (!ws[section].rules)
|
|
310
|
+
ws[section].rules = [];
|
|
311
|
+
ws[section].rules.push(rule);
|
|
312
|
+
ws.last_updated = new Date().toISOString().slice(0, 10);
|
|
313
|
+
ws.updated_by = 'agent (auto)';
|
|
314
|
+
fs_1.default.writeFileSync(wsPath, JSON.stringify(ws, null, 2), 'utf8');
|
|
315
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ MnemoWorkspace — Rule Added\n'));
|
|
316
|
+
console.log(chalk_1.default.green(` ✔ [${section}] ${rule}\n`));
|
|
317
|
+
});
|
|
318
|
+
program.addCommand(workspace);
|
|
319
|
+
// ─────────────────────────────────────────────
|
|
320
|
+
// CHRONICLE COMMANDS
|
|
321
|
+
// mnemoforge chronicle init | commit | sweep | list
|
|
322
|
+
// ─────────────────────────────────────────────
|
|
323
|
+
const chronicle = new commander_1.Command('chronicle')
|
|
324
|
+
.description('MnemoChronicle — multi-agent memory archiving system');
|
|
325
|
+
chronicle
|
|
326
|
+
.command('init')
|
|
327
|
+
.description('Initialize .cli_resonance vault — choose IDE / Provider / Model')
|
|
328
|
+
.action(async () => {
|
|
329
|
+
const existing = (0, vault_js_1.loadVaultConfig)();
|
|
330
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n\u29e1 MnemoChronicle \u2014 Vault Init\n'));
|
|
331
|
+
if (existing) {
|
|
332
|
+
console.log(chalk_1.default.yellow(' \u26a0 Re-configuring vault:'));
|
|
333
|
+
console.log(chalk_1.default.gray(' IDE: ' + existing.ide));
|
|
334
|
+
console.log(chalk_1.default.gray(' Provider: ' + existing.provider + '\n'));
|
|
335
|
+
}
|
|
336
|
+
const profile = await (0, init_flow_js_1.askPrimaryProfile)(existing);
|
|
337
|
+
// \u2500\u2500 Extra profiles (loop)
|
|
338
|
+
const reg = existing?.registeredModels ?? [];
|
|
339
|
+
if (existing && (existing.ide !== profile.ide || existing.provider !== profile.provider)) {
|
|
340
|
+
const old = { ide: existing.ide, provider: existing.provider, defaultChronicleStyle: existing.defaultChronicleStyle };
|
|
341
|
+
if (!reg.some(m => m.ide === old.ide && m.provider === old.provider))
|
|
342
|
+
reg.unshift(old);
|
|
343
|
+
}
|
|
344
|
+
let extra = await (0, init_flow_js_1.askExtraProfile)(reg.length);
|
|
345
|
+
while (extra) {
|
|
346
|
+
console.log(chalk_1.default.green(' \u2714 Added: ' + extra.ide + ' / ' + extra.provider + ' \u00b7 ' + extra.defaultChronicleStyle));
|
|
347
|
+
reg.push(extra);
|
|
348
|
+
extra = await (0, init_flow_js_1.askExtraProfile)(reg.length);
|
|
349
|
+
}
|
|
350
|
+
const config = { ...profile, registeredModels: reg };
|
|
351
|
+
(0, vault_js_1.saveVaultConfig)(config);
|
|
352
|
+
const dir = config.vaultPath + '/.cli_resonance/' + config.ide + '/' + config.provider + '/';
|
|
353
|
+
console.log(chalk_1.default.green('\n \u2714 Vault configured!'));
|
|
354
|
+
console.log(chalk_1.default.gray(' IDE: ') + chalk_1.default.white(config.ide));
|
|
355
|
+
console.log(chalk_1.default.gray(' Provider: ') + chalk_1.default.white(config.provider));
|
|
356
|
+
console.log(chalk_1.default.gray(' Style: ') + chalk_1.default.hex('#A78BFA')(config.defaultChronicleStyle ?? 'session'));
|
|
357
|
+
if (reg.length > 0)
|
|
358
|
+
console.log(chalk_1.default.gray(' + ' + reg.length + ' extra profile(s)'));
|
|
359
|
+
console.log(chalk_1.default.gray('\n Chronicles \u2192 ') + chalk_1.default.hex('#A78BFA')(dir) + '\n');
|
|
360
|
+
console.log(chalk_1.default.gray(' Run ') + chalk_1.default.white('mnemoforge') + chalk_1.default.gray(' to see your dashboard.\n'));
|
|
361
|
+
});
|
|
362
|
+
chronicle
|
|
363
|
+
.command('commit')
|
|
364
|
+
.description('Write a new Chronicle to the vault')
|
|
365
|
+
.option('-t, --title <title>', 'Chronicle title')
|
|
366
|
+
.option('--type <type>', 'Chronicle style: session | reflection | decision | sweep | narcissus')
|
|
367
|
+
.option('--tags <tags>', 'Comma-separated tags')
|
|
368
|
+
.option('--auto', 'Auto-generate draft and open in VS Code (no editor prompt)')
|
|
369
|
+
.action(async (opts) => {
|
|
370
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
371
|
+
if (!config) {
|
|
372
|
+
console.log(chalk_1.default.red('\n ✖ Not initialized. Run: mnemoforge chronicle init\n'));
|
|
64
373
|
process.exit(1);
|
|
65
374
|
}
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
375
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ MnemoChronicle — New Chronicle\n'));
|
|
376
|
+
// ── AUTO mode: generate draft → write directly → open in editor ──────────
|
|
377
|
+
if (opts.auto) {
|
|
378
|
+
console.log(chalk_1.default.cyan(' ⟳ Reading conversation source…'));
|
|
379
|
+
const ctx = (0, index_js_1.readSourceForConfig)(config);
|
|
380
|
+
let draftContent = '';
|
|
381
|
+
let draftTitle = opts.title ?? 'Session chronicle';
|
|
382
|
+
if (ctx) {
|
|
383
|
+
draftContent = (0, index_js_1.generateChronicleDraft)(ctx, config);
|
|
384
|
+
draftTitle = opts.title || ctx.sessionTitle.slice(0, 60) || draftTitle;
|
|
385
|
+
console.log(chalk_1.default.green(` ✔ Draft from: ${ctx.conversationId.slice(0, 8)}…`));
|
|
386
|
+
console.log(chalk_1.default.gray(` Files: ${ctx.filesTouched.length} · Decisions: ${ctx.keyDecisions.length}`));
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// No source — create a blank template from the style
|
|
390
|
+
console.log(chalk_1.default.yellow(' ⚠ No source — creating blank template.\n'));
|
|
391
|
+
draftContent = (0, index_js_1.generateChronicleDraft)({ conversationId: 'manual', startedAt: null, sessionTitle: draftTitle,
|
|
392
|
+
filesTouched: [], commandsRun: [], keyDecisions: [], rawTurns: [], sourcePath: '' }, config);
|
|
393
|
+
}
|
|
394
|
+
const tags = opts.tags ? opts.tags.split(',').map((t) => t.trim()) : [];
|
|
395
|
+
const { filePath, filename } = (0, chronicle_js_1.writeChronicle)({
|
|
396
|
+
title: draftTitle,
|
|
397
|
+
type: (opts.type ?? config.defaultChronicleStyle ?? 'session'),
|
|
398
|
+
content: draftContent,
|
|
399
|
+
tags,
|
|
400
|
+
config,
|
|
401
|
+
});
|
|
402
|
+
console.log(chalk_1.default.green(`\n ✔ Chronicle created: ${filename}`));
|
|
403
|
+
console.log(chalk_1.default.gray(` ${filePath}`));
|
|
404
|
+
console.log(chalk_1.default.cyan('\n Opening in VS Code…\n'));
|
|
405
|
+
// Open in VS Code — shell:true required on Windows for PATH resolution
|
|
73
406
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
console.log(chalk_1.default.yellow(` ⚠ Template "${file}" not found — skipping.`));
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
let content = fs_1.default.readFileSync(srcPath, 'utf8');
|
|
80
|
-
content = content.replace(/\{\{MODULE_NAME\}\}/g, name);
|
|
81
|
-
fs_1.default.writeFileSync(path_1.default.join(targetDir, destName), content, 'utf8');
|
|
82
|
-
console.log(chalk_1.default.green(` ✔ ${destName}`));
|
|
83
|
-
return true;
|
|
407
|
+
const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
408
|
+
spawn('code', [filePath], { detached: true, stdio: 'ignore', shell: true }).unref();
|
|
84
409
|
}
|
|
85
|
-
catch
|
|
86
|
-
|
|
87
|
-
console.log(chalk_1.default.red(` ✖ Failed to create "${file}": ${message}`));
|
|
88
|
-
return false;
|
|
410
|
+
catch {
|
|
411
|
+
console.log(chalk_1.default.gray(` (Could not open VS Code automatically — open the file manually)\n`));
|
|
89
412
|
}
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
// ── MANUAL mode: ask title + content via simple prompts ─────────────────
|
|
416
|
+
const answers = await inquirer_1.default.prompt([
|
|
417
|
+
{
|
|
418
|
+
type: 'input',
|
|
419
|
+
name: 'title',
|
|
420
|
+
message: chalk_1.default.cyan('Chronicle title?'),
|
|
421
|
+
default: opts.title,
|
|
422
|
+
when: !opts.title,
|
|
423
|
+
validate: (v) => v.trim() !== '' || 'Required',
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
type: 'input',
|
|
427
|
+
name: 'content',
|
|
428
|
+
message: chalk_1.default.cyan('Short summary') + chalk_1.default.gray(' (you can edit the file after)'),
|
|
429
|
+
default: '',
|
|
430
|
+
},
|
|
431
|
+
]);
|
|
432
|
+
const title = opts.title || answers.title;
|
|
433
|
+
const tags = opts.tags ? opts.tags.split(',').map((t) => t.trim()) : [];
|
|
434
|
+
const { filePath, filename } = (0, chronicle_js_1.writeChronicle)({
|
|
435
|
+
title,
|
|
436
|
+
type: (opts.type ?? config.defaultChronicleStyle ?? 'session'),
|
|
437
|
+
content: answers.content,
|
|
438
|
+
tags,
|
|
439
|
+
config,
|
|
440
|
+
});
|
|
441
|
+
console.log(chalk_1.default.green(`\n ✔ Chronicle written: ${filename}`));
|
|
442
|
+
console.log(chalk_1.default.gray(` ${filePath}\n`));
|
|
443
|
+
console.log(chalk_1.default.gray(` Tip: run with `) + chalk_1.default.white('--auto') + chalk_1.default.gray(' to generate a full draft automatically.\n'));
|
|
444
|
+
});
|
|
445
|
+
// ── chronicle archive ──────────────────────────────────────────────────────
|
|
446
|
+
// Primary workflow: agent writes a .md file → CLI archives it to the vault.
|
|
447
|
+
// The human never writes chronicles. The agent does.
|
|
448
|
+
chronicle
|
|
449
|
+
.command('archive')
|
|
450
|
+
.description('Archive an agent-written chronicle into the vault (primary workflow)')
|
|
451
|
+
.option('-f, --file <path>', 'Path to the .md chronicle file to archive')
|
|
452
|
+
.action(async (opts) => {
|
|
453
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
454
|
+
if (!config) {
|
|
455
|
+
console.log(chalk_1.default.red('\n ✖ Not initialized. Run: mnemoforge chronicle init\n'));
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
if (!opts.file) {
|
|
459
|
+
console.log(chalk_1.default.red('\n ✖ Specify a file: mnemoforge chronicle archive --file <path>\n'));
|
|
460
|
+
process.exit(1);
|
|
461
|
+
}
|
|
462
|
+
const srcPath = path_1.default.resolve(opts.file);
|
|
463
|
+
if (!fs_1.default.existsSync(srcPath)) {
|
|
464
|
+
console.log(chalk_1.default.red(`\n ✖ File not found: ${srcPath}\n`));
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
// Resolve destination dir from config
|
|
468
|
+
const { resolveChronicleDir } = await Promise.resolve().then(() => __importStar(require('./lib/vault.js')));
|
|
469
|
+
const destDir = resolveChronicleDir(config);
|
|
470
|
+
fs_1.default.mkdirSync(destDir, { recursive: true });
|
|
471
|
+
const filename = path_1.default.basename(srcPath);
|
|
472
|
+
const destPath = path_1.default.join(destDir, filename);
|
|
473
|
+
fs_1.default.copyFileSync(srcPath, destPath);
|
|
474
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ MnemoChronicle — Archived\n'));
|
|
475
|
+
console.log(chalk_1.default.green(` ✔ ${filename}`));
|
|
476
|
+
console.log(chalk_1.default.gray(` → ${destPath}\n`));
|
|
477
|
+
});
|
|
478
|
+
chronicle
|
|
479
|
+
.command('sweep')
|
|
480
|
+
.description('Create a daily sweep Chronicle from recent entries')
|
|
481
|
+
.action(async () => {
|
|
482
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
483
|
+
if (!config) {
|
|
484
|
+
console.log(chalk_1.default.red('\n ✖ Not initialized. Run: mnemoforge chronicle init\n'));
|
|
485
|
+
process.exit(1);
|
|
486
|
+
}
|
|
487
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
488
|
+
const recent = (0, vault_js_1.listChronicles)(config).filter(f => f.includes(today));
|
|
489
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ MnemoChronicle — Daily Sweep\n'));
|
|
490
|
+
console.log(chalk_1.default.gray(` Found ${recent.length} chronicle(s) from today (${today})\n`));
|
|
491
|
+
if (recent.length === 0) {
|
|
492
|
+
console.log(chalk_1.default.yellow(' No chronicles today to sweep.\n'));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
const { doSweep } = await inquirer_1.default.prompt([{
|
|
496
|
+
type: 'confirm',
|
|
497
|
+
name: 'doSweep',
|
|
498
|
+
message: `Create sweep from ${recent.length} chronicle(s)?`,
|
|
499
|
+
default: true,
|
|
500
|
+
}]);
|
|
501
|
+
if (!doSweep)
|
|
502
|
+
return;
|
|
503
|
+
const sweepContent = (0, chronicle_js_1.buildSweepContent)(recent, config);
|
|
504
|
+
const { filePath, filename } = (0, chronicle_js_1.writeChronicle)({
|
|
505
|
+
title: `Daily Sweep — ${today}`,
|
|
506
|
+
type: 'sweep',
|
|
507
|
+
content: sweepContent,
|
|
508
|
+
tags: ['sweep', today],
|
|
509
|
+
config,
|
|
510
|
+
});
|
|
511
|
+
console.log(chalk_1.default.green(`\n ✔ Sweep written: ${filename}`));
|
|
512
|
+
console.log(chalk_1.default.gray(` ${filePath}\n`));
|
|
513
|
+
});
|
|
514
|
+
chronicle
|
|
515
|
+
.command('list')
|
|
516
|
+
.description('List recent Chronicles in the vault')
|
|
517
|
+
.option('-n, --count <n>', 'Number of chronicles to show', '10')
|
|
518
|
+
.action((opts) => {
|
|
519
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
520
|
+
if (!config) {
|
|
521
|
+
console.log(chalk_1.default.red('\n ✖ Not initialized. Run: mnemoforge chronicle init\n'));
|
|
522
|
+
process.exit(1);
|
|
523
|
+
}
|
|
524
|
+
const chronicles = (0, vault_js_1.listChronicles)(config).slice(0, parseInt(opts.count || '10'));
|
|
525
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold(`\n⬡ Chronicles — ${config.ide} / ${config.provider}\n`));
|
|
526
|
+
if (chronicles.length === 0) {
|
|
527
|
+
console.log(chalk_1.default.gray(' No chronicles yet.\n'));
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
chronicles.forEach((f, i) => {
|
|
531
|
+
console.log(chalk_1.default.gray(` ${String(i + 1).padStart(2, ' ')}. `) + chalk_1.default.white(f));
|
|
532
|
+
});
|
|
533
|
+
console.log();
|
|
534
|
+
});
|
|
535
|
+
// ── chronicle switch ───────────────────────────────────────────
|
|
536
|
+
chronicle
|
|
537
|
+
.command('switch')
|
|
538
|
+
.description('Switch the active profile to another registered one')
|
|
539
|
+
.action(async () => {
|
|
540
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
541
|
+
if (!config) {
|
|
542
|
+
console.log(chalk_1.default.red('\n ✖ Not initialized. Run: mnemoforge chronicle init\n'));
|
|
543
|
+
process.exit(1);
|
|
544
|
+
}
|
|
545
|
+
const profiles = config.registeredModels ?? [];
|
|
546
|
+
if (profiles.length === 0) {
|
|
547
|
+
console.log(chalk_1.default.yellow('\n ⚠ No other profiles registered.'));
|
|
548
|
+
console.log(chalk_1.default.gray(' Use: mnemoforge chronicle init → "Add a new profile"\n'));
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const choices = profiles.map((p, i) => ({
|
|
552
|
+
name: p.ide + ' / ' + p.provider + ' · ' + p.displayName,
|
|
553
|
+
value: i,
|
|
554
|
+
}));
|
|
555
|
+
const { idx } = await inquirer_1.default.prompt([{
|
|
556
|
+
type: 'list',
|
|
557
|
+
name: 'idx',
|
|
558
|
+
message: chalk_1.default.cyan('Which profile to make active?'),
|
|
559
|
+
choices,
|
|
560
|
+
}]);
|
|
561
|
+
const selected = profiles[idx];
|
|
562
|
+
const displaced = {
|
|
563
|
+
ide: config.ide,
|
|
564
|
+
provider: config.provider,
|
|
565
|
+
modelId: config.modelId,
|
|
566
|
+
displayName: config.displayName,
|
|
567
|
+
defaultChronicleStyle: config.defaultChronicleStyle,
|
|
90
568
|
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
console.log(chalk_1.default.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
569
|
+
const newRegistered = profiles.filter((_p, i) => i !== idx);
|
|
570
|
+
newRegistered.push(displaced);
|
|
571
|
+
(0, vault_js_1.saveVaultConfig)({
|
|
572
|
+
...config,
|
|
573
|
+
ide: selected.ide,
|
|
574
|
+
provider: selected.provider,
|
|
575
|
+
modelId: selected.modelId,
|
|
576
|
+
displayName: selected.displayName,
|
|
577
|
+
defaultChronicleStyle: selected.defaultChronicleStyle ?? 'session',
|
|
578
|
+
registeredModels: newRegistered,
|
|
579
|
+
});
|
|
580
|
+
console.log(chalk_1.default.green('\n ✔ Switched to: ' + selected.displayName + ' (' + selected.provider + ')\n'));
|
|
581
|
+
showWelcome();
|
|
582
|
+
});
|
|
583
|
+
// ── chronicle config ───────────────────────────────────────────
|
|
584
|
+
chronicle
|
|
585
|
+
.command('config')
|
|
586
|
+
.description('Edit settings (style, display name) of any registered profile')
|
|
587
|
+
.action(async () => {
|
|
588
|
+
const config = (0, vault_js_1.loadVaultConfig)();
|
|
589
|
+
if (!config) {
|
|
590
|
+
console.log(chalk_1.default.red('\n ✖ Not initialized. Run: mnemoforge chronicle init\n'));
|
|
591
|
+
process.exit(1);
|
|
592
|
+
}
|
|
593
|
+
const profiles = config.registeredModels ?? [];
|
|
594
|
+
// Choose profile to edit
|
|
595
|
+
let targetIdx = -1;
|
|
596
|
+
if (profiles.length > 0) {
|
|
597
|
+
const allChoices = [
|
|
598
|
+
{ name: '★ ' + config.ide + ' / ' + config.provider + ' · ' + config.displayName + ' [ACTIVE]', value: -1 },
|
|
599
|
+
...profiles.map((p, i) => ({
|
|
600
|
+
name: '○ ' + p.ide + ' / ' + p.provider + ' · ' + p.displayName,
|
|
601
|
+
value: i,
|
|
602
|
+
})),
|
|
603
|
+
];
|
|
604
|
+
const { which } = await inquirer_1.default.prompt([{
|
|
605
|
+
type: 'list',
|
|
606
|
+
name: 'which',
|
|
607
|
+
message: chalk_1.default.cyan('Which profile to edit?'),
|
|
608
|
+
choices: allChoices,
|
|
609
|
+
}]);
|
|
610
|
+
targetIdx = which;
|
|
611
|
+
}
|
|
612
|
+
const isActive = targetIdx === -1;
|
|
613
|
+
const curStyle = isActive ? (config.defaultChronicleStyle ?? 'session') : (profiles[targetIdx].defaultChronicleStyle ?? 'session');
|
|
614
|
+
const curName = isActive ? config.displayName : profiles[targetIdx].displayName;
|
|
615
|
+
const edit = await inquirer_1.default.prompt([
|
|
616
|
+
{
|
|
617
|
+
type: 'list',
|
|
618
|
+
name: 'style',
|
|
619
|
+
message: chalk_1.default.cyan('Chronicle style?'),
|
|
620
|
+
choices: [
|
|
621
|
+
{ name: 'Session — coding/work session', value: 'session' },
|
|
622
|
+
{ name: 'Reflection — deep thoughts', value: 'reflection' },
|
|
623
|
+
{ name: 'Decision — ADR-style record', value: 'decision' },
|
|
624
|
+
{ name: 'Sweep — daily digest', value: 'sweep' },
|
|
625
|
+
{ name: 'Narcissus — soul narrative', value: 'narcissus' },
|
|
626
|
+
],
|
|
627
|
+
default: curStyle,
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
type: 'input',
|
|
631
|
+
name: 'displayName',
|
|
632
|
+
message: chalk_1.default.cyan('Display name?'),
|
|
633
|
+
default: curName,
|
|
634
|
+
},
|
|
635
|
+
]);
|
|
636
|
+
if (isActive) {
|
|
637
|
+
(0, vault_js_1.saveVaultConfig)({ ...config, defaultChronicleStyle: edit.style, displayName: edit.displayName });
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
const updated = [...profiles];
|
|
641
|
+
updated[targetIdx] = { ...updated[targetIdx], defaultChronicleStyle: edit.style, displayName: edit.displayName };
|
|
642
|
+
(0, vault_js_1.saveVaultConfig)({ ...config, registeredModels: updated });
|
|
643
|
+
}
|
|
644
|
+
console.log(chalk_1.default.green('\n ✔ Profile updated!\n'));
|
|
645
|
+
showWelcome();
|
|
646
|
+
});
|
|
647
|
+
program.addCommand(chronicle);
|
|
648
|
+
// ─────────────────────────────────────────────
|
|
649
|
+
// MODELS COMMAND
|
|
650
|
+
// mnemoforge models import | list
|
|
651
|
+
// ─────────────────────────────────────────────
|
|
652
|
+
const vault_js_2 = require("./lib/vault.js");
|
|
653
|
+
const models = new commander_1.Command('models')
|
|
654
|
+
.description('Manage the local model registry (UniversalModelCard compatible)');
|
|
655
|
+
models
|
|
656
|
+
.command('import <file>')
|
|
657
|
+
.description('Import a model from a UniversalModelCard JSON file')
|
|
658
|
+
.action((file) => {
|
|
659
|
+
const resolved = path_1.default.resolve(file);
|
|
660
|
+
if (!fs_1.default.existsSync(resolved)) {
|
|
661
|
+
console.log(chalk_1.default.red(`\n ✖ File not found: ${resolved}\n`));
|
|
662
|
+
process.exit(1);
|
|
663
|
+
}
|
|
664
|
+
const entry = (0, vault_js_2.importFromModelCard)(resolved);
|
|
665
|
+
if (!entry) {
|
|
666
|
+
console.log(chalk_1.default.red('\n ✖ Could not extract model info. Expected fields: model_id, provider\n'));
|
|
667
|
+
process.exit(1);
|
|
668
|
+
}
|
|
669
|
+
const existing = (0, vault_js_2.loadCustomModels)();
|
|
670
|
+
const alreadyExists = existing.some(m => m.modelId === entry.modelId);
|
|
671
|
+
if (alreadyExists) {
|
|
672
|
+
console.log(chalk_1.default.yellow(`\n ⚠ Model already registered: ${entry.modelId}\n`));
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
(0, vault_js_2.saveCustomModels)([...existing, entry]);
|
|
676
|
+
console.log(chalk_1.default.green(`\n ✔ Model imported!`));
|
|
677
|
+
console.log(chalk_1.default.gray(` ID: ${entry.modelId}`));
|
|
678
|
+
console.log(chalk_1.default.gray(` Provider: ${entry.provider}`));
|
|
679
|
+
console.log(chalk_1.default.gray(` Name: ${entry.displayName}\n`));
|
|
680
|
+
});
|
|
681
|
+
models
|
|
682
|
+
.command('list')
|
|
683
|
+
.description('List all registered custom models')
|
|
684
|
+
.action(() => {
|
|
685
|
+
const custom = (0, vault_js_2.loadCustomModels)();
|
|
686
|
+
console.log(chalk_1.default.hex('#8B5CF6').bold('\n⬡ Custom Models Registry\n'));
|
|
687
|
+
if (custom.length === 0) {
|
|
688
|
+
console.log(chalk_1.default.gray(' No custom models. Use: mnemoforge models import <file.json>\n'));
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
custom.forEach((m, i) => {
|
|
692
|
+
console.log(chalk_1.default.gray(` ${String(i + 1).padStart(2, ' ')}. `) +
|
|
693
|
+
chalk_1.default.white(`${m.displayName}`) +
|
|
694
|
+
chalk_1.default.gray(` · ${m.provider} · ${m.modelId}`));
|
|
695
|
+
});
|
|
696
|
+
console.log();
|
|
107
697
|
});
|
|
698
|
+
program.addCommand(models);
|
|
108
699
|
program.parse(process.argv);
|