@soleri/cli 9.13.1 → 9.14.1
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/create.js +3 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/install.d.ts +28 -0
- package/dist/commands/install.js +174 -7
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/pack.js +6 -2
- package/dist/commands/pack.js.map +1 -1
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +71 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/hook-packs/clean-commits/hookify.no-ai-attribution.local.md +6 -3
- package/dist/main.js +2 -0
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/install-verify.test.ts +109 -0
- package/src/__tests__/install.test.ts +75 -1
- package/src/__tests__/update.test.ts +102 -0
- package/src/commands/create.ts +4 -0
- package/src/commands/install.ts +209 -8
- package/src/commands/pack.ts +13 -2
- package/src/commands/update.ts +82 -0
- package/src/hook-packs/clean-commits/hookify.no-ai-attribution.local.md +6 -3
- package/src/main.ts +2 -0
package/src/commands/install.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
12
12
|
import { homedir } from 'node:os';
|
|
13
13
|
import * as p from '@clack/prompts';
|
|
14
14
|
import { detectAgent } from '../utils/agent-context.js';
|
|
15
|
+
import { detectArtifacts } from '../utils/agent-artifacts.js';
|
|
15
16
|
|
|
16
17
|
/** Default parent directory for agents: ~/.soleri/ */
|
|
17
18
|
const SOLERI_HOME = process.env.SOLERI_HOME ?? join(homedir(), '.soleri');
|
|
@@ -25,7 +26,7 @@ export const toPosix = (p: string): string => p.replace(/\\/g, '/');
|
|
|
25
26
|
* Resolve the absolute path to the soleri-engine binary.
|
|
26
27
|
* Falls back to `npx @soleri/engine` if resolution fails (e.g. not installed globally).
|
|
27
28
|
*/
|
|
28
|
-
function resolveEngineBin(): { command: string; bin: string } {
|
|
29
|
+
export function resolveEngineBin(): { command: string; bin: string } {
|
|
29
30
|
try {
|
|
30
31
|
const require = createRequire(import.meta.url);
|
|
31
32
|
const bin = require.resolve('@soleri/core/dist/engine/bin/soleri-engine.js');
|
|
@@ -80,6 +81,87 @@ function checkWritable(filePath: string): boolean {
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Facade suffixes pre-approved for every Soleri agent.
|
|
86
|
+
* Each suffix becomes `mcp__<agentId>__<agentId>_<suffix>` in settings.local.json.
|
|
87
|
+
*/
|
|
88
|
+
const PRE_APPROVED_FACADE_SUFFIXES = [
|
|
89
|
+
'core',
|
|
90
|
+
'vault',
|
|
91
|
+
'plan',
|
|
92
|
+
'brain',
|
|
93
|
+
'memory',
|
|
94
|
+
'admin',
|
|
95
|
+
'curator',
|
|
96
|
+
'orchestrate',
|
|
97
|
+
'control',
|
|
98
|
+
'context',
|
|
99
|
+
'agency',
|
|
100
|
+
'operator',
|
|
101
|
+
'chat',
|
|
102
|
+
'archive',
|
|
103
|
+
'sync',
|
|
104
|
+
'review',
|
|
105
|
+
'intake',
|
|
106
|
+
'links',
|
|
107
|
+
'branching',
|
|
108
|
+
'tier',
|
|
109
|
+
'loop',
|
|
110
|
+
'embedding',
|
|
111
|
+
'dream',
|
|
112
|
+
'testing',
|
|
113
|
+
'typescript',
|
|
114
|
+
] as const;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Write pre-approved facade permissions to ~/.claude/settings.local.json.
|
|
118
|
+
* Merges with existing permissions — never removes entries added by the user or other agents.
|
|
119
|
+
*/
|
|
120
|
+
export function installClaudePermissions(agentId: string): void {
|
|
121
|
+
const claudeDir = join(homedir(), '.claude');
|
|
122
|
+
const settingsPath = join(claudeDir, 'settings.local.json');
|
|
123
|
+
|
|
124
|
+
// Build permission entries: mcp__<agentId>__<agentId>_<suffix>
|
|
125
|
+
const newEntries = PRE_APPROVED_FACADE_SUFFIXES.map(
|
|
126
|
+
(suffix) => `mcp__${agentId}__${agentId}_${suffix}`,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
let config: Record<string, unknown> = {};
|
|
130
|
+
if (existsSync(settingsPath)) {
|
|
131
|
+
try {
|
|
132
|
+
config = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
133
|
+
} catch {
|
|
134
|
+
// Corrupted file — start fresh but warn
|
|
135
|
+
p.log.warn(`Could not parse ${settingsPath} — creating fresh permissions`);
|
|
136
|
+
config = {};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!config.permissions || typeof config.permissions !== 'object') {
|
|
141
|
+
config.permissions = {};
|
|
142
|
+
}
|
|
143
|
+
const permissions = config.permissions as Record<string, unknown>;
|
|
144
|
+
|
|
145
|
+
const existing = Array.isArray(permissions.allow) ? (permissions.allow as string[]) : [];
|
|
146
|
+
const merged = [...new Set([...existing, ...newEntries])];
|
|
147
|
+
permissions.allow = merged;
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
151
|
+
writeFileSync(settingsPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
152
|
+
} catch {
|
|
153
|
+
p.log.warn(`Could not write ${settingsPath} — MCP tools may require manual approval`);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const added = merged.length - existing.length;
|
|
158
|
+
if (added > 0) {
|
|
159
|
+
p.log.success(`Pre-approved ${merged.length} facade permissions in settings.local.json`);
|
|
160
|
+
} else {
|
|
161
|
+
p.log.info('Facade permissions already configured in settings.local.json');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
83
165
|
export function installClaude(agentId: string, agentDir: string, isFileTree: boolean): void {
|
|
84
166
|
const configPath = join(homedir(), '.claude.json');
|
|
85
167
|
|
|
@@ -113,7 +195,10 @@ export function installClaude(agentId: string, agentDir: string, isFileTree: boo
|
|
|
113
195
|
p.log.error(`Cannot write to ${configPath}. Check file permissions.`);
|
|
114
196
|
process.exit(1);
|
|
115
197
|
}
|
|
116
|
-
p.log.success(`Registered ${agentId} in ~/.claude.json`);
|
|
198
|
+
p.log.success(`Registered ${agentId} in ~/.claude.json (restart your session to load)`);
|
|
199
|
+
|
|
200
|
+
// Pre-approve facade permissions so users don't hit approval prompts
|
|
201
|
+
installClaudePermissions(agentId);
|
|
117
202
|
}
|
|
118
203
|
|
|
119
204
|
function installCodex(agentId: string, agentDir: string, isFileTree: boolean): void {
|
|
@@ -162,7 +247,7 @@ function installCodex(agentId: string, agentDir: string, isFileTree: boolean): v
|
|
|
162
247
|
p.log.error(`Cannot write to ${configPath}. Check file permissions.`);
|
|
163
248
|
process.exit(1);
|
|
164
249
|
}
|
|
165
|
-
p.log.success(`Registered ${agentId} in ~/.codex/config.toml`);
|
|
250
|
+
p.log.success(`Registered ${agentId} in ~/.codex/config.toml (restart your session to load)`);
|
|
166
251
|
}
|
|
167
252
|
|
|
168
253
|
function installOpencode(agentId: string, agentDir: string, isFileTree: boolean): void {
|
|
@@ -222,7 +307,29 @@ function installOpencode(agentId: string, agentDir: string, isFileTree: boolean)
|
|
|
222
307
|
p.log.error(`Cannot write to ${configPath}. Check file permissions.`);
|
|
223
308
|
process.exit(1);
|
|
224
309
|
}
|
|
225
|
-
p.log.success(
|
|
310
|
+
p.log.success(
|
|
311
|
+
`Registered ${agentId} in ~/.config/opencode/opencode.json (restart your session to load)`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Return target-specific post-install restart instructions.
|
|
317
|
+
*/
|
|
318
|
+
export function getNextStepMessage(target: string): string {
|
|
319
|
+
const instructions: Record<string, string> = {
|
|
320
|
+
claude: 'Next step: Restart your Claude Code session (or run `/mcp` to reload MCP servers).',
|
|
321
|
+
codex: 'Next step: Start a new Codex conversation to load the MCP server.',
|
|
322
|
+
opencode: 'Next step: Restart OpenCode to load the MCP server.',
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
if (target === 'both' || target === 'all') {
|
|
326
|
+
return [instructions.claude, instructions.codex, instructions.opencode].join('\n');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (!(target in instructions)) {
|
|
330
|
+
p.log.warn(`Unknown target "${target}" — defaulting to Claude instructions.`);
|
|
331
|
+
}
|
|
332
|
+
return instructions[target] ?? instructions.claude;
|
|
226
333
|
}
|
|
227
334
|
|
|
228
335
|
function escapeRegExp(s: string): string {
|
|
@@ -233,7 +340,20 @@ function escapeRegExp(s: string): string {
|
|
|
233
340
|
* Create a global launcher script so the agent can be invoked by name from any directory.
|
|
234
341
|
* e.g., typing `ernesto` opens Claude Code with that agent's MCP config.
|
|
235
342
|
*/
|
|
236
|
-
function installLauncher(agentId: string, agentDir: string): void {
|
|
343
|
+
function installLauncher(agentId: string, agentDir: string, target: Target): void {
|
|
344
|
+
// Only create a launcher for Claude — other targets don't have a CLI equivalent
|
|
345
|
+
if (target === 'codex') {
|
|
346
|
+
p.log.info('Launcher skipped: Codex does not have a CLI equivalent.');
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (target === 'opencode') {
|
|
350
|
+
p.log.info('Launcher skipped: OpenCode does not have a CLI equivalent.');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (target === 'all' || target === 'both') {
|
|
354
|
+
p.log.info('Note: Launcher is Claude-specific — other targets do not have a CLI equivalent.');
|
|
355
|
+
}
|
|
356
|
+
|
|
237
357
|
// Launcher scripts to /usr/local/bin are Unix-only
|
|
238
358
|
if (process.platform === 'win32') {
|
|
239
359
|
p.log.info('Launcher scripts are not supported on Windows.');
|
|
@@ -264,13 +384,67 @@ function installLauncher(agentId: string, agentDir: string): void {
|
|
|
264
384
|
}
|
|
265
385
|
}
|
|
266
386
|
|
|
387
|
+
// ---------------------------------------------------------------------------
|
|
388
|
+
// Verify
|
|
389
|
+
// ---------------------------------------------------------------------------
|
|
390
|
+
|
|
391
|
+
export interface VerifyCheck {
|
|
392
|
+
label: string;
|
|
393
|
+
passed: boolean;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Verify the full install chain for an agent against a given target.
|
|
398
|
+
* Returns an array of pass/fail checks.
|
|
399
|
+
*/
|
|
400
|
+
export function verifyInstall(agentId: string, agentDir: string, target: Target): VerifyCheck[] {
|
|
401
|
+
const checks: VerifyCheck[] = [];
|
|
402
|
+
|
|
403
|
+
// 1. Agent entry exists in config for each relevant target
|
|
404
|
+
const artifacts = detectArtifacts(agentId, agentDir);
|
|
405
|
+
const targetEntries = artifacts.mcpServerEntries;
|
|
406
|
+
|
|
407
|
+
const targets: ('claude' | 'codex' | 'opencode')[] =
|
|
408
|
+
target === 'all' || target === 'both'
|
|
409
|
+
? ['claude', 'codex', 'opencode']
|
|
410
|
+
: [target as 'claude' | 'codex' | 'opencode'];
|
|
411
|
+
|
|
412
|
+
for (const t of targets) {
|
|
413
|
+
const hasEntry = targetEntries.some((e) => e.target === t);
|
|
414
|
+
checks.push({
|
|
415
|
+
label: `Agent entry in ${t} config`,
|
|
416
|
+
passed: hasEntry,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 2. Engine binary resolves (local or npx fallback)
|
|
421
|
+
const engine = resolveEngineBin();
|
|
422
|
+
const isLocal = engine.command === 'node';
|
|
423
|
+
checks.push({
|
|
424
|
+
label: isLocal
|
|
425
|
+
? `Engine binary resolves (${engine.bin})`
|
|
426
|
+
: 'Engine resolves via npx (fallback)',
|
|
427
|
+
passed: true,
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// 3. agent.yaml exists at configured path
|
|
431
|
+
const agentYamlPath = join(agentDir, 'agent.yaml');
|
|
432
|
+
checks.push({
|
|
433
|
+
label: `agent.yaml exists (${agentYamlPath})`,
|
|
434
|
+
passed: existsSync(agentYamlPath),
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
return checks;
|
|
438
|
+
}
|
|
439
|
+
|
|
267
440
|
export function registerInstall(program: Command): void {
|
|
268
441
|
program
|
|
269
442
|
.command('install')
|
|
270
443
|
.argument('[dir]', 'Agent directory or agent name (checks ~/.soleri/<name> first, then cwd)')
|
|
271
444
|
.option('--target <target>', 'Registration target: claude, opencode, codex, or all', 'claude')
|
|
445
|
+
.option('--verify', 'Verify the install chain (config, engine, agent.yaml)')
|
|
272
446
|
.description('Register agent as MCP server in editor config')
|
|
273
|
-
.action(async (dir?: string, opts?: { target?: string }) => {
|
|
447
|
+
.action(async (dir?: string, opts?: { target?: string; verify?: boolean }) => {
|
|
274
448
|
let resolvedDir: string | undefined;
|
|
275
449
|
|
|
276
450
|
if (dir) {
|
|
@@ -328,8 +502,35 @@ export function registerInstall(program: Command): void {
|
|
|
328
502
|
}
|
|
329
503
|
|
|
330
504
|
// Create global launcher script
|
|
331
|
-
installLauncher(ctx.agentId, ctx.agentPath);
|
|
505
|
+
installLauncher(ctx.agentId, ctx.agentPath, target);
|
|
506
|
+
|
|
507
|
+
p.log.success(`Install complete for ${ctx.agentId}.`);
|
|
508
|
+
p.log.info(getNextStepMessage(target));
|
|
509
|
+
|
|
510
|
+
// Warn users running via npx — their cache may go stale on next release
|
|
511
|
+
if (resolveEngineBin().command === 'npx') {
|
|
512
|
+
p.log.warn(
|
|
513
|
+
`Running via npx — updates may be cached. For reliable updates: npm install -g soleri`,
|
|
514
|
+
);
|
|
515
|
+
}
|
|
332
516
|
|
|
333
|
-
|
|
517
|
+
// Run verification if --verify was passed
|
|
518
|
+
if (opts?.verify) {
|
|
519
|
+
const checks = verifyInstall(ctx.agentId, ctx.agentPath, target);
|
|
520
|
+
p.log.info('');
|
|
521
|
+
p.log.info('Install verification:');
|
|
522
|
+
let allPassed = true;
|
|
523
|
+
for (const check of checks) {
|
|
524
|
+
const icon = check.passed ? '\u2705' : '\u274C';
|
|
525
|
+
const logFn = check.passed ? p.log.success : p.log.error;
|
|
526
|
+
logFn(`${icon} ${check.label}`);
|
|
527
|
+
if (!check.passed) allPassed = false;
|
|
528
|
+
}
|
|
529
|
+
if (!allPassed) {
|
|
530
|
+
p.log.error('Verification failed — one or more checks did not pass.');
|
|
531
|
+
process.exit(1);
|
|
532
|
+
}
|
|
533
|
+
p.log.success('All checks passed.');
|
|
534
|
+
}
|
|
334
535
|
});
|
|
335
536
|
}
|
package/src/commands/pack.ts
CHANGED
|
@@ -11,7 +11,13 @@ import { join, resolve as pathResolve } from 'node:path';
|
|
|
11
11
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
12
12
|
import type { Command } from 'commander';
|
|
13
13
|
import * as p from '@clack/prompts';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
PackLockfile,
|
|
16
|
+
inferPackType,
|
|
17
|
+
resolvePack,
|
|
18
|
+
checkNpmVersion,
|
|
19
|
+
getBuiltinKnowledgePacksDirs,
|
|
20
|
+
} from '@soleri/core';
|
|
15
21
|
import type { LockEntry, PackSource } from '@soleri/core';
|
|
16
22
|
|
|
17
23
|
// ─── Tier display helpers ────────────────────────────────────────────
|
|
@@ -457,9 +463,14 @@ export function registerPack(program: Command): void {
|
|
|
457
463
|
const candidates = [
|
|
458
464
|
join(process.cwd(), 'knowledge-packs'),
|
|
459
465
|
pathResolve(import.meta.dirname ?? '.', '..', '..', '..', '..', '..', 'knowledge-packs'),
|
|
466
|
+
...getBuiltinKnowledgePacksDirs(),
|
|
460
467
|
];
|
|
468
|
+
const seen = new Set<string>();
|
|
461
469
|
for (const c of candidates) {
|
|
462
|
-
if (existsSync(c)
|
|
470
|
+
if (existsSync(c) && !seen.has(c)) {
|
|
471
|
+
searchDirs.push(c);
|
|
472
|
+
seen.add(c);
|
|
473
|
+
}
|
|
463
474
|
}
|
|
464
475
|
}
|
|
465
476
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import * as p from '@clack/prompts';
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
|
|
8
|
+
function getCurrentVersion(): string {
|
|
9
|
+
try {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
11
|
+
return (require('../package.json') as { version: string }).version;
|
|
12
|
+
} catch {
|
|
13
|
+
return 'unknown';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getLatestVersion(): string {
|
|
18
|
+
try {
|
|
19
|
+
return execSync('npm view @soleri/cli version', { stdio: ['pipe', 'pipe', 'pipe'] })
|
|
20
|
+
.toString()
|
|
21
|
+
.trim();
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error('Could not reach npm registry. Check your network connection and try again.');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function installLatest(): void {
|
|
28
|
+
execSync('npm install -g soleri@latest', { stdio: 'inherit' });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function registerUpdate(program: Command): void {
|
|
32
|
+
program
|
|
33
|
+
.command('update')
|
|
34
|
+
.description('Update Soleri CLI to the latest version')
|
|
35
|
+
.action(async () => {
|
|
36
|
+
p.intro('Soleri Update');
|
|
37
|
+
|
|
38
|
+
const current = getCurrentVersion();
|
|
39
|
+
p.log.info(`Current version: ${current}`);
|
|
40
|
+
|
|
41
|
+
const spinner = p.spinner();
|
|
42
|
+
spinner.start('Checking latest version…');
|
|
43
|
+
|
|
44
|
+
let latest: string;
|
|
45
|
+
try {
|
|
46
|
+
latest = getLatestVersion();
|
|
47
|
+
} catch (err) {
|
|
48
|
+
spinner.stop('Failed');
|
|
49
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
spinner.stop(`Latest version: ${latest}`);
|
|
55
|
+
|
|
56
|
+
if (current === latest) {
|
|
57
|
+
p.log.success(`Already on latest (${current})`);
|
|
58
|
+
p.outro('Nothing to do.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
p.log.info(`Updating ${current} → ${latest}…`);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
installLatest();
|
|
66
|
+
} catch {
|
|
67
|
+
p.log.error('Update failed. Try manually: npm install -g soleri@latest');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const installed = getLatestVersion();
|
|
72
|
+
if (installed !== latest) {
|
|
73
|
+
p.log.warn(
|
|
74
|
+
`Installed version (${installed}) does not match expected (${latest}). Verify manually.`,
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
p.log.success(`Updated ${current} → ${installed}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
p.outro('Restart your session to use the new version.');
|
|
81
|
+
});
|
|
82
|
+
}
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
# Soleri Hook Pack: clean-commits
|
|
3
3
|
# Version: 1.0.0
|
|
4
4
|
# Rule: no-ai-attribution
|
|
5
|
+
# NOTE: This hook is intentionally disabled. The host agent (e.g. Claude Code)
|
|
6
|
+
# controls commit attribution via its own system prompt. Blocking attribution
|
|
7
|
+
# patterns here causes a deadlock when the host mandates them.
|
|
5
8
|
name: no-ai-attribution
|
|
6
|
-
enabled:
|
|
9
|
+
enabled: false
|
|
7
10
|
event: bash
|
|
8
11
|
action: block
|
|
9
12
|
conditions:
|
|
@@ -12,7 +15,7 @@ conditions:
|
|
|
12
15
|
pattern: git\s+commit.*(-m|--message)
|
|
13
16
|
- field: command
|
|
14
17
|
operator: regex_match
|
|
15
|
-
pattern: (
|
|
18
|
+
pattern: (placeholder-disabled-pattern)
|
|
16
19
|
---
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
This hook is intentionally disabled. Commit style is enforced by the engine rules, not by blocking patterns.
|
package/src/main.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { registerStaging } from './commands/staging.js';
|
|
|
32
32
|
import { registerVault } from './commands/vault.js';
|
|
33
33
|
import { registerYolo } from './commands/yolo.js';
|
|
34
34
|
import { registerDream } from './commands/dream.js';
|
|
35
|
+
import { registerUpdate } from './commands/update.js';
|
|
35
36
|
|
|
36
37
|
const require = createRequire(import.meta.url);
|
|
37
38
|
const { version } = require('../package.json');
|
|
@@ -96,4 +97,5 @@ registerStaging(program);
|
|
|
96
97
|
registerVault(program);
|
|
97
98
|
registerYolo(program);
|
|
98
99
|
registerDream(program);
|
|
100
|
+
registerUpdate(program);
|
|
99
101
|
program.parse();
|