@soleri/cli 9.11.0 → 9.13.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/README.md +44 -15
- package/dist/commands/create.js +11 -2
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/dev.js +11 -9
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/dream.d.ts +10 -0
- package/dist/commands/dream.js +151 -0
- package/dist/commands/dream.js.map +1 -0
- package/dist/commands/uninstall.js +161 -3
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -1
- package/dist/prompts/create-wizard.js +6 -40
- package/dist/prompts/create-wizard.js.map +1 -1
- package/dist/utils/agent-artifacts.d.ts +63 -0
- package/dist/utils/agent-artifacts.js +276 -0
- package/dist/utils/agent-artifacts.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/dream.test.ts +119 -0
- package/src/__tests__/uninstall-full.test.ts +566 -0
- package/src/commands/create.ts +10 -2
- package/src/commands/dev.ts +19 -9
- package/src/commands/dream.ts +174 -0
- package/src/commands/uninstall.ts +214 -31
- package/src/main.ts +2 -0
- package/src/prompts/create-wizard.ts +7 -40
- package/src/utils/agent-artifacts.ts +366 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dream CLI — vault memory consolidation.
|
|
3
|
+
*
|
|
4
|
+
* `soleri dream` — run a dream pass immediately
|
|
5
|
+
* `soleri dream schedule [--time HH:MM]` — schedule daily cron
|
|
6
|
+
* `soleri dream unschedule` — remove cron entry
|
|
7
|
+
* `soleri dream status` — show dream status + cron info
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import type { Command } from 'commander';
|
|
13
|
+
import { detectAgent } from '../utils/agent-context.js';
|
|
14
|
+
import { pass, fail, info, heading, dim } from '../utils/logger.js';
|
|
15
|
+
import { SOLERI_HOME } from '@soleri/core';
|
|
16
|
+
|
|
17
|
+
function resolveVaultDbPath(agentId: string): string | null {
|
|
18
|
+
const newDbPath = join(SOLERI_HOME, agentId, 'vault.db');
|
|
19
|
+
const legacyDbPath = join(SOLERI_HOME, '..', `.${agentId}`, 'vault.db');
|
|
20
|
+
if (existsSync(newDbPath)) return newDbPath;
|
|
21
|
+
if (existsSync(legacyDbPath)) return legacyDbPath;
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function registerDream(program: Command): void {
|
|
26
|
+
const dream = program.command('dream').description('Vault memory consolidation');
|
|
27
|
+
|
|
28
|
+
// ─── soleri dream (no subcommand) — run immediately ─────────
|
|
29
|
+
dream
|
|
30
|
+
.command('run', { isDefault: true })
|
|
31
|
+
.description('Run a dream pass immediately')
|
|
32
|
+
.action(async () => {
|
|
33
|
+
const agent = detectAgent();
|
|
34
|
+
if (!agent) {
|
|
35
|
+
fail('Not in a Soleri agent project', 'Run from an agent directory');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const dbPath = resolveVaultDbPath(agent.agentId);
|
|
40
|
+
if (!dbPath) {
|
|
41
|
+
fail('Vault DB not found', 'Run the agent once to initialize its vault database.');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { Vault, Curator, DreamEngine, ensureDreamSchema } = await import('@soleri/core');
|
|
46
|
+
const vault = new Vault(dbPath);
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
ensureDreamSchema(vault.getProvider());
|
|
50
|
+
const curator = new Curator(vault);
|
|
51
|
+
const engine = new DreamEngine(vault, curator);
|
|
52
|
+
|
|
53
|
+
heading('Dream — Memory Consolidation');
|
|
54
|
+
info('Running dream pass...');
|
|
55
|
+
console.log();
|
|
56
|
+
|
|
57
|
+
const report = engine.run();
|
|
58
|
+
|
|
59
|
+
pass('Dream pass complete');
|
|
60
|
+
console.log();
|
|
61
|
+
console.log(' Field Value');
|
|
62
|
+
console.log(' ───────────────────── ──────────────');
|
|
63
|
+
dim(` Duration ${report.durationMs}ms`);
|
|
64
|
+
dim(` Duplicates found ${report.duplicatesFound}`);
|
|
65
|
+
dim(` Stale archived ${report.staleArchived}`);
|
|
66
|
+
dim(` Contradictions found ${report.contradictionsFound}`);
|
|
67
|
+
dim(` Total dreams ${report.totalDreams}`);
|
|
68
|
+
dim(` Timestamp ${report.timestamp}`);
|
|
69
|
+
console.log();
|
|
70
|
+
} finally {
|
|
71
|
+
vault.close();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ─── soleri dream schedule ──────────────────────────────────
|
|
76
|
+
dream
|
|
77
|
+
.command('schedule')
|
|
78
|
+
.description('Schedule daily dream cron job')
|
|
79
|
+
.option('--time <HH:MM>', 'Time to run (24h format)', '22:00')
|
|
80
|
+
.action(async (opts: { time: string }) => {
|
|
81
|
+
const agent = detectAgent();
|
|
82
|
+
if (!agent) {
|
|
83
|
+
fail('Not in a Soleri agent project', 'Run from an agent directory');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const { scheduleDream } = await import('@soleri/core');
|
|
88
|
+
|
|
89
|
+
const result = scheduleDream(opts.time, agent.agentPath);
|
|
90
|
+
|
|
91
|
+
if (!result.isScheduled) {
|
|
92
|
+
fail('Failed to schedule dream cron', 'Check time format (HH:MM) and crontab access.');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
heading('Dream — Scheduled');
|
|
97
|
+
pass(`Daily dream scheduled at ${result.time}`);
|
|
98
|
+
dim(` Log path: ${result.logPath}`);
|
|
99
|
+
dim(` Project: ${result.projectDir}`);
|
|
100
|
+
console.log();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// ─── soleri dream unschedule ────────────────────────────────
|
|
104
|
+
dream
|
|
105
|
+
.command('unschedule')
|
|
106
|
+
.description('Remove dream cron entry')
|
|
107
|
+
.action(async () => {
|
|
108
|
+
const { unscheduleDream } = await import('@soleri/core');
|
|
109
|
+
|
|
110
|
+
unscheduleDream();
|
|
111
|
+
|
|
112
|
+
heading('Dream — Unscheduled');
|
|
113
|
+
pass('Dream cron entry removed');
|
|
114
|
+
console.log();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ─── soleri dream status ────────────────────────────────────
|
|
118
|
+
dream
|
|
119
|
+
.command('status')
|
|
120
|
+
.description('Show dream status and cron info')
|
|
121
|
+
.action(async () => {
|
|
122
|
+
const agent = detectAgent();
|
|
123
|
+
if (!agent) {
|
|
124
|
+
fail('Not in a Soleri agent project', 'Run from an agent directory');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const dbPath = resolveVaultDbPath(agent.agentId);
|
|
129
|
+
|
|
130
|
+
heading('Dream — Status');
|
|
131
|
+
|
|
132
|
+
// Dream engine status (only if vault exists)
|
|
133
|
+
if (dbPath) {
|
|
134
|
+
const { Vault, Curator, DreamEngine, ensureDreamSchema } = await import('@soleri/core');
|
|
135
|
+
const vault = new Vault(dbPath);
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
ensureDreamSchema(vault.getProvider());
|
|
139
|
+
const curator = new Curator(vault);
|
|
140
|
+
const engine = new DreamEngine(vault, curator);
|
|
141
|
+
const status = engine.getStatus();
|
|
142
|
+
|
|
143
|
+
console.log(' Field Value');
|
|
144
|
+
console.log(' ──────────────────────── ──────────────');
|
|
145
|
+
dim(` Sessions since last ${status.sessionsSinceLastDream}`);
|
|
146
|
+
dim(` Last dream at ${status.lastDreamAt ?? 'never'}`);
|
|
147
|
+
dim(
|
|
148
|
+
` Last duration ${status.lastDreamDurationMs !== null ? `${status.lastDreamDurationMs}ms` : 'n/a'}`,
|
|
149
|
+
);
|
|
150
|
+
dim(` Total dreams ${status.totalDreams}`);
|
|
151
|
+
dim(` Gate eligible ${status.gateEligible ? 'yes' : 'no'}`);
|
|
152
|
+
} finally {
|
|
153
|
+
vault.close();
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
info('Vault DB not found — dream engine status unavailable.');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log();
|
|
160
|
+
|
|
161
|
+
// Cron schedule status
|
|
162
|
+
const { getDreamSchedule } = await import('@soleri/core');
|
|
163
|
+
const cron = getDreamSchedule();
|
|
164
|
+
|
|
165
|
+
if (cron.isScheduled) {
|
|
166
|
+
pass(`Cron scheduled at ${cron.time}`);
|
|
167
|
+
dim(` Log path: ${cron.logPath}`);
|
|
168
|
+
dim(` Project: ${cron.projectDir}`);
|
|
169
|
+
} else {
|
|
170
|
+
info('No cron schedule configured. Run `soleri dream schedule` to set one.');
|
|
171
|
+
}
|
|
172
|
+
console.log();
|
|
173
|
+
});
|
|
174
|
+
}
|
|
@@ -4,6 +4,16 @@ import { join, resolve } from 'node:path';
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import * as p from '@clack/prompts';
|
|
6
6
|
import { detectAgent } from '../utils/agent-context.js';
|
|
7
|
+
import {
|
|
8
|
+
detectArtifacts,
|
|
9
|
+
removeDirectory,
|
|
10
|
+
removeClaudeMdBlock,
|
|
11
|
+
removePermissionEntries,
|
|
12
|
+
removeLauncherScript,
|
|
13
|
+
type ArtifactManifest,
|
|
14
|
+
type RemovalResult,
|
|
15
|
+
} from '../utils/agent-artifacts.js';
|
|
16
|
+
import { pass, fail, warn, skip, heading, dim } from '../utils/logger.js';
|
|
7
17
|
|
|
8
18
|
type Target = 'claude' | 'codex' | 'opencode' | 'both' | 'all';
|
|
9
19
|
|
|
@@ -89,39 +99,212 @@ function escapeRegExp(s: string): string {
|
|
|
89
99
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
90
100
|
}
|
|
91
101
|
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Full uninstall helpers
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
function countArtifacts(manifest: ArtifactManifest): number {
|
|
107
|
+
let count = 0;
|
|
108
|
+
if (manifest.projectDir?.exists) count++;
|
|
109
|
+
if (manifest.dataDir?.exists) count++;
|
|
110
|
+
if (manifest.dataDirLegacy?.exists) count++;
|
|
111
|
+
count += manifest.claudeMdBlocks.length;
|
|
112
|
+
count += manifest.mcpServerEntries.length;
|
|
113
|
+
if (manifest.permissionEntries.length > 0) count++;
|
|
114
|
+
if (manifest.launcherScript?.exists) count++;
|
|
115
|
+
return count;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function displayManifest(manifest: ArtifactManifest): void {
|
|
119
|
+
heading(`Artifacts for "${manifest.agentId}"`);
|
|
120
|
+
|
|
121
|
+
const show = (label: string, loc: { path: string; exists: boolean } | null) => {
|
|
122
|
+
if (loc?.exists) warn(label, loc.path);
|
|
123
|
+
else dim(`${label} — not found`);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
show('Project directory', manifest.projectDir);
|
|
127
|
+
show('Data directory', manifest.dataDir);
|
|
128
|
+
show('Data directory (legacy)', manifest.dataDirLegacy);
|
|
129
|
+
show('Launcher script', manifest.launcherScript);
|
|
130
|
+
|
|
131
|
+
if (manifest.claudeMdBlocks.length > 0) {
|
|
132
|
+
for (const block of manifest.claudeMdBlocks) {
|
|
133
|
+
warn('CLAUDE.md block', `${block.path} (lines ${block.startLine}-${block.endLine})`);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
dim('CLAUDE.md blocks — none found');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (manifest.mcpServerEntries.length > 0) {
|
|
140
|
+
for (const entry of manifest.mcpServerEntries) {
|
|
141
|
+
warn(`MCP server (${entry.target})`, `${entry.file} → ${entry.key}`);
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
dim('MCP server entries — none found');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (manifest.permissionEntries.length > 0) {
|
|
148
|
+
for (const pe of manifest.permissionEntries) {
|
|
149
|
+
warn(`Permissions (${pe.matches.length} entries)`, pe.file);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
dim('Permission entries — none found');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function reportResult(label: string, result: RemovalResult): void {
|
|
157
|
+
if (result.removed) pass(label, result.path);
|
|
158
|
+
else if (result.error) fail(label, result.error);
|
|
159
|
+
else skip(label, result.path);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function fullUninstall(
|
|
163
|
+
agentId: string,
|
|
164
|
+
agentDir: string | undefined,
|
|
165
|
+
target: Target,
|
|
166
|
+
dryRun: boolean,
|
|
167
|
+
force: boolean,
|
|
168
|
+
): Promise<void> {
|
|
169
|
+
const manifest = detectArtifacts(agentId, agentDir);
|
|
170
|
+
const total = countArtifacts(manifest);
|
|
171
|
+
|
|
172
|
+
displayManifest(manifest);
|
|
173
|
+
|
|
174
|
+
if (total === 0) {
|
|
175
|
+
p.log.info('Nothing to remove.');
|
|
176
|
+
process.exit(2);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log(`\n Found ${total} artifact(s) to remove.\n`);
|
|
180
|
+
|
|
181
|
+
if (dryRun) {
|
|
182
|
+
p.log.info('Dry run — no changes made.');
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!force) {
|
|
187
|
+
const confirmed = await p.confirm({
|
|
188
|
+
message: `Remove all artifacts for "${agentId}"? This cannot be undone.`,
|
|
189
|
+
});
|
|
190
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
191
|
+
p.log.info('Cancelled.');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let removed = 0;
|
|
197
|
+
heading('Removing artifacts');
|
|
198
|
+
|
|
199
|
+
// 1. MCP server entries (existing logic)
|
|
200
|
+
if (target === 'claude' || target === 'both' || target === 'all') {
|
|
201
|
+
uninstallClaude(agentId);
|
|
202
|
+
}
|
|
203
|
+
if (target === 'codex' || target === 'both' || target === 'all') {
|
|
204
|
+
uninstallCodex(agentId);
|
|
205
|
+
}
|
|
206
|
+
if (target === 'opencode' || target === 'all') {
|
|
207
|
+
uninstallOpencode(agentId);
|
|
208
|
+
}
|
|
209
|
+
removed += manifest.mcpServerEntries.length;
|
|
210
|
+
|
|
211
|
+
// 2. Permission entries
|
|
212
|
+
for (const pe of manifest.permissionEntries) {
|
|
213
|
+
const result = await removePermissionEntries(pe.file, agentId);
|
|
214
|
+
reportResult(`Permissions (${pe.matches.length} entries)`, result);
|
|
215
|
+
if (result.removed) removed++;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 3. CLAUDE.md blocks (reverse order to preserve line numbers)
|
|
219
|
+
const sortedBlocks = [...manifest.claudeMdBlocks].sort((a, b) => b.startLine - a.startLine);
|
|
220
|
+
for (const block of sortedBlocks) {
|
|
221
|
+
const result = await removeClaudeMdBlock(block.path, block.startLine, block.endLine);
|
|
222
|
+
reportResult('CLAUDE.md block', result);
|
|
223
|
+
if (result.removed) removed++;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 4. Launcher script
|
|
227
|
+
if (manifest.launcherScript?.exists) {
|
|
228
|
+
const result = await removeLauncherScript(manifest.launcherScript.path);
|
|
229
|
+
reportResult('Launcher script', result);
|
|
230
|
+
if (result.removed) removed++;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// 5. Data directories
|
|
234
|
+
if (manifest.dataDir?.exists) {
|
|
235
|
+
const result = await removeDirectory(manifest.dataDir.path);
|
|
236
|
+
reportResult('Data directory', result);
|
|
237
|
+
if (result.removed) removed++;
|
|
238
|
+
}
|
|
239
|
+
if (manifest.dataDirLegacy?.exists) {
|
|
240
|
+
const result = await removeDirectory(manifest.dataDirLegacy.path);
|
|
241
|
+
reportResult('Data directory (legacy)', result);
|
|
242
|
+
if (result.removed) removed++;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// 6. Project directory (last — most destructive)
|
|
246
|
+
if (manifest.projectDir?.exists) {
|
|
247
|
+
const result = await removeDirectory(manifest.projectDir.path);
|
|
248
|
+
reportResult('Project directory', result);
|
|
249
|
+
if (result.removed) removed++;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
console.log(`\n Removed ${removed}/${total} artifacts for "${agentId}".\n`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// Command registration
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
|
|
92
259
|
export function registerUninstall(program: Command): void {
|
|
93
260
|
program
|
|
94
261
|
.command('uninstall')
|
|
95
262
|
.argument('[dir]', 'Agent directory (defaults to cwd)')
|
|
96
|
-
.option('--target <target>', 'Registration target: opencode, claude, codex, or all'
|
|
97
|
-
.
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
263
|
+
.option('--target <target>', 'Registration target: opencode, claude, codex, or all')
|
|
264
|
+
.option('--full', 'Remove all agent artifacts (project, data, configs, permissions, launcher)')
|
|
265
|
+
.option('--dry-run', 'Show what would be removed without making changes')
|
|
266
|
+
.option('--force', 'Skip confirmation prompt')
|
|
267
|
+
.description('Remove agent MCP server entries (or all artifacts with --full)')
|
|
268
|
+
.action(
|
|
269
|
+
async (
|
|
270
|
+
dir?: string,
|
|
271
|
+
opts?: { target?: string; full?: boolean; dryRun?: boolean; force?: boolean },
|
|
272
|
+
) => {
|
|
273
|
+
const resolvedDir = dir ? resolve(dir) : undefined;
|
|
274
|
+
const ctx = detectAgent(resolvedDir);
|
|
275
|
+
|
|
276
|
+
if (!ctx) {
|
|
277
|
+
p.log.error('Not in an agent project. Run from an agent directory or pass its path.');
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Default: 'all' when --full, 'opencode' otherwise
|
|
282
|
+
const defaultTarget = opts?.full ? 'all' : 'opencode';
|
|
283
|
+
const target = (opts?.target ?? defaultTarget) as Target;
|
|
284
|
+
const validTargets: Target[] = ['claude', 'codex', 'opencode', 'both', 'all'];
|
|
285
|
+
|
|
286
|
+
if (!validTargets.includes(target)) {
|
|
287
|
+
p.log.error(`Invalid target "${target}". Use: ${validTargets.join(', ')}`);
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (opts?.full) {
|
|
292
|
+
await fullUninstall(ctx.agentId, resolvedDir, target, !!opts.dryRun, !!opts.force);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Default: MCP-only removal (backward compatible)
|
|
297
|
+
if (target === 'claude' || target === 'both' || target === 'all') {
|
|
298
|
+
uninstallClaude(ctx.agentId);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (target === 'codex' || target === 'both' || target === 'all') {
|
|
302
|
+
uninstallCodex(ctx.agentId);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (target === 'opencode' || target === 'all') {
|
|
306
|
+
uninstallOpencode(ctx.agentId);
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
);
|
|
127
310
|
}
|
package/src/main.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { registerTelegram } from './commands/telegram.js';
|
|
|
31
31
|
import { registerStaging } from './commands/staging.js';
|
|
32
32
|
import { registerVault } from './commands/vault.js';
|
|
33
33
|
import { registerYolo } from './commands/yolo.js';
|
|
34
|
+
import { registerDream } from './commands/dream.js';
|
|
34
35
|
|
|
35
36
|
const require = createRequire(import.meta.url);
|
|
36
37
|
const { version } = require('../package.json');
|
|
@@ -94,4 +95,5 @@ registerTelegram(program);
|
|
|
94
95
|
registerStaging(program);
|
|
95
96
|
registerVault(program);
|
|
96
97
|
registerYolo(program);
|
|
98
|
+
registerDream(program);
|
|
97
99
|
program.parse();
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import * as p from '@clack/prompts';
|
|
9
9
|
import type { AgentConfigInput } from '@soleri/forge/lib';
|
|
10
|
-
import { ITALIAN_CRAFTSPERSON } from '@soleri/core/personas';
|
|
10
|
+
import { ITALIAN_CRAFTSPERSON, NEUTRAL_PERSONA } from '@soleri/core/personas';
|
|
11
11
|
import { isGhInstalled } from '../utils/git.js';
|
|
12
12
|
|
|
13
13
|
/** Git configuration collected from the wizard. */
|
|
@@ -67,52 +67,19 @@ export async function runCreateWizard(initialName?: string): Promise<CreateWizar
|
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
value: 'custom',
|
|
70
|
-
label: '
|
|
71
|
-
hint: '
|
|
70
|
+
label: 'Custom (editable neutral persona)',
|
|
71
|
+
hint: 'Full persona file — customize later via agent.yaml',
|
|
72
72
|
},
|
|
73
73
|
],
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
if (p.isCancel(personaChoice)) return null;
|
|
77
77
|
|
|
78
|
-
let personaDescription: string | undefined;
|
|
79
|
-
|
|
80
|
-
if (personaChoice === 'custom') {
|
|
81
|
-
const desc = (await p.text({
|
|
82
|
-
message: "Describe your agent's personality (we'll generate the persona from this)",
|
|
83
|
-
placeholder: 'A calm Japanese sensei who speaks in zen metaphors and values harmony in code',
|
|
84
|
-
validate: (v) => {
|
|
85
|
-
if (!v || v.trim().length < 10) return 'Give at least a brief description (10+ chars)';
|
|
86
|
-
if (v.length > 500) return 'Max 500 characters';
|
|
87
|
-
},
|
|
88
|
-
})) as string;
|
|
89
|
-
|
|
90
|
-
if (p.isCancel(desc)) return null;
|
|
91
|
-
personaDescription = desc;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
78
|
// ─── Build config ───────────────────────────────────────────
|
|
95
|
-
const persona =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
voice: personaDescription,
|
|
100
|
-
// Custom personas start with minimal config — the LLM enriches from the voice description
|
|
101
|
-
inspiration: '',
|
|
102
|
-
culture: '',
|
|
103
|
-
metaphors: [] as string[],
|
|
104
|
-
traits: [] as string[],
|
|
105
|
-
quirks: [] as string[],
|
|
106
|
-
opinions: [] as string[],
|
|
107
|
-
greetings: [`Hello! I'm ${name.trim()}. What are we working on?`],
|
|
108
|
-
signoffs: ['Until next time!'],
|
|
109
|
-
languageRule: "Speak the user's language naturally.",
|
|
110
|
-
nameRule: 'Adapt to name changes but keep character intact.',
|
|
111
|
-
}
|
|
112
|
-
: {
|
|
113
|
-
...ITALIAN_CRAFTSPERSON,
|
|
114
|
-
name: name.trim(),
|
|
115
|
-
};
|
|
79
|
+
const persona =
|
|
80
|
+
personaChoice === 'custom'
|
|
81
|
+
? { ...NEUTRAL_PERSONA, name: name.trim() }
|
|
82
|
+
: { ...ITALIAN_CRAFTSPERSON, name: name.trim() };
|
|
116
83
|
|
|
117
84
|
const greeting = persona.greetings[0] ?? `Ciao! I'm ${name.trim()}. What are we working on?`;
|
|
118
85
|
|