@soleri/cli 1.9.0 → 1.10.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.
Files changed (94) hide show
  1. package/README.md +4 -0
  2. package/dist/commands/agent.d.ts +8 -0
  3. package/dist/commands/agent.js +150 -0
  4. package/dist/commands/agent.js.map +1 -0
  5. package/dist/commands/create.js +38 -6
  6. package/dist/commands/create.js.map +1 -1
  7. package/dist/commands/install-knowledge.js +65 -3
  8. package/dist/commands/install-knowledge.js.map +1 -1
  9. package/dist/commands/install.d.ts +2 -0
  10. package/dist/commands/install.js +80 -0
  11. package/dist/commands/install.js.map +1 -0
  12. package/dist/commands/pack.d.ts +10 -0
  13. package/dist/commands/pack.js +512 -0
  14. package/dist/commands/pack.js.map +1 -0
  15. package/dist/commands/skills.d.ts +8 -0
  16. package/dist/commands/skills.js +167 -0
  17. package/dist/commands/skills.js.map +1 -0
  18. package/dist/commands/uninstall.d.ts +2 -0
  19. package/dist/commands/uninstall.js +74 -0
  20. package/dist/commands/uninstall.js.map +1 -0
  21. package/dist/hook-packs/installer.d.ts +0 -7
  22. package/dist/hook-packs/installer.js +1 -14
  23. package/dist/hook-packs/installer.js.map +1 -1
  24. package/dist/hook-packs/installer.ts +1 -18
  25. package/dist/hook-packs/registry.d.ts +2 -1
  26. package/dist/hook-packs/registry.ts +1 -1
  27. package/dist/main.js +40 -1
  28. package/dist/main.js.map +1 -1
  29. package/dist/prompts/archetypes.d.ts +1 -0
  30. package/dist/prompts/archetypes.js +177 -62
  31. package/dist/prompts/archetypes.js.map +1 -1
  32. package/dist/prompts/create-wizard.d.ts +3 -3
  33. package/dist/prompts/create-wizard.js +99 -50
  34. package/dist/prompts/create-wizard.js.map +1 -1
  35. package/dist/prompts/playbook.d.ts +8 -7
  36. package/dist/prompts/playbook.js +201 -15
  37. package/dist/prompts/playbook.js.map +1 -1
  38. package/dist/utils/checks.d.ts +0 -1
  39. package/dist/utils/checks.js +1 -1
  40. package/dist/utils/checks.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/__tests__/archetypes.test.ts +84 -0
  43. package/src/__tests__/doctor.test.ts +2 -2
  44. package/src/__tests__/wizard-e2e.mjs +508 -0
  45. package/src/commands/agent.ts +181 -0
  46. package/src/commands/create.ts +152 -104
  47. package/src/commands/install-knowledge.ts +75 -4
  48. package/src/commands/install.ts +101 -0
  49. package/src/commands/pack.ts +585 -0
  50. package/src/commands/skills.ts +191 -0
  51. package/src/commands/uninstall.ts +93 -0
  52. package/src/hook-packs/installer.ts +1 -18
  53. package/src/hook-packs/registry.ts +1 -1
  54. package/src/main.ts +42 -1
  55. package/src/prompts/archetypes.ts +193 -62
  56. package/src/prompts/create-wizard.ts +117 -61
  57. package/src/prompts/playbook.ts +207 -21
  58. package/src/utils/checks.ts +1 -1
  59. package/code-reviewer/.claude/hookify.focus-ring-required.local.md +0 -21
  60. package/code-reviewer/.claude/hookify.no-ai-attribution.local.md +0 -18
  61. package/code-reviewer/.claude/hookify.no-any-types.local.md +0 -18
  62. package/code-reviewer/.claude/hookify.no-console-log.local.md +0 -21
  63. package/code-reviewer/.claude/hookify.no-important.local.md +0 -18
  64. package/code-reviewer/.claude/hookify.no-inline-styles.local.md +0 -21
  65. package/code-reviewer/.claude/hookify.semantic-html.local.md +0 -18
  66. package/code-reviewer/.claude/hookify.ux-touch-targets.local.md +0 -18
  67. package/code-reviewer/.mcp.json +0 -11
  68. package/code-reviewer/README.md +0 -346
  69. package/code-reviewer/package-lock.json +0 -4484
  70. package/code-reviewer/package.json +0 -45
  71. package/code-reviewer/scripts/copy-assets.js +0 -15
  72. package/code-reviewer/scripts/setup.sh +0 -130
  73. package/code-reviewer/skills/brainstorming/SKILL.md +0 -170
  74. package/code-reviewer/skills/code-patrol/SKILL.md +0 -176
  75. package/code-reviewer/skills/context-resume/SKILL.md +0 -143
  76. package/code-reviewer/skills/executing-plans/SKILL.md +0 -201
  77. package/code-reviewer/skills/fix-and-learn/SKILL.md +0 -164
  78. package/code-reviewer/skills/health-check/SKILL.md +0 -225
  79. package/code-reviewer/skills/second-opinion/SKILL.md +0 -142
  80. package/code-reviewer/skills/systematic-debugging/SKILL.md +0 -230
  81. package/code-reviewer/skills/verification-before-completion/SKILL.md +0 -170
  82. package/code-reviewer/skills/writing-plans/SKILL.md +0 -207
  83. package/code-reviewer/src/__tests__/facades.test.ts +0 -598
  84. package/code-reviewer/src/activation/activate.ts +0 -125
  85. package/code-reviewer/src/activation/claude-md-content.ts +0 -217
  86. package/code-reviewer/src/activation/inject-claude-md.ts +0 -113
  87. package/code-reviewer/src/extensions/index.ts +0 -47
  88. package/code-reviewer/src/extensions/ops/example.ts +0 -28
  89. package/code-reviewer/src/identity/persona.ts +0 -62
  90. package/code-reviewer/src/index.ts +0 -278
  91. package/code-reviewer/src/intelligence/data/architecture.json +0 -5
  92. package/code-reviewer/src/intelligence/data/code-review.json +0 -5
  93. package/code-reviewer/tsconfig.json +0 -30
  94. package/code-reviewer/vitest.config.ts +0 -23
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Skills CLI — convenience aliases for `soleri pack --type skills`.
3
+ *
4
+ * Provides `soleri skills list|install|remove|info` as thin wrappers
5
+ * around the unified pack system.
6
+ */
7
+
8
+ import { join } from 'node:path';
9
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
10
+ import type { Command } from 'commander';
11
+ import * as p from '@clack/prompts';
12
+ import { PackLockfile, inferPackType, resolvePack } from '@soleri/core';
13
+ import type { LockEntry, PackSource } from '@soleri/core';
14
+ import { detectAgent } from '../utils/agent-context.js';
15
+
16
+ const LOCKFILE_NAME = 'soleri.lock';
17
+
18
+ function getLockfilePath(): string {
19
+ const ctx = detectAgent();
20
+ if (!ctx) {
21
+ p.log.error('No agent project detected in current directory.');
22
+ process.exit(1);
23
+ }
24
+ return join(ctx.agentPath, LOCKFILE_NAME);
25
+ }
26
+
27
+ export function registerSkills(program: Command): void {
28
+ const skills = program
29
+ .command('skills')
30
+ .description('Manage skill packs (alias for pack --type skills)');
31
+
32
+ // ─── list ──────────────────────────────────────────────────
33
+ skills
34
+ .command('list')
35
+ .description('List installed skill packs')
36
+ .action(() => {
37
+ const lockfile = new PackLockfile(getLockfilePath());
38
+ const entries = lockfile.list().filter((e) => e.type === 'skills' || e.type === 'bundle');
39
+
40
+ if (entries.length === 0) {
41
+ p.log.info('No skill packs installed.');
42
+ return;
43
+ }
44
+
45
+ p.log.info(`${entries.length} skill pack(s) installed:\n`);
46
+ for (const entry of entries) {
47
+ const badge =
48
+ entry.source === 'built-in' ? ' [built-in]' : entry.source === 'npm' ? ' [npm]' : '';
49
+ console.log(` ${entry.id}@${entry.version}${badge}`);
50
+ if (entry.skills.length > 0) console.log(` skills: ${entry.skills.join(', ')}`);
51
+ }
52
+ });
53
+
54
+ // ─── install ───────────────────────────────────────────────
55
+ skills
56
+ .command('install')
57
+ .argument('<pack>', 'Skill pack name, path, or npm package')
58
+ .option('--version <ver>', 'Specific version to install')
59
+ .description('Install a skill pack')
60
+ .action(async (packName: string, opts: { version?: string }) => {
61
+ const lockfilePath = getLockfilePath();
62
+ const lockfile = new PackLockfile(lockfilePath);
63
+ const ctx = detectAgent();
64
+ if (!ctx) return;
65
+
66
+ if (lockfile.has(packName)) {
67
+ p.log.warn(`Pack "${packName}" is already installed.`);
68
+ return;
69
+ }
70
+
71
+ const s = p.spinner();
72
+ s.start(`Resolving skill pack: ${packName}...`);
73
+
74
+ try {
75
+ const resolved = resolvePack(packName, {
76
+ builtinDirs: getBuiltinDirs(ctx.agentPath),
77
+ version: opts.version,
78
+ });
79
+
80
+ const manifestPath = join(resolved.directory, 'soleri-pack.json');
81
+ if (!existsSync(manifestPath)) {
82
+ s.stop('Install failed');
83
+ p.log.error(`No soleri-pack.json found in ${resolved.directory}`);
84
+ process.exit(1);
85
+ return;
86
+ }
87
+
88
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
89
+ const packType = inferPackType(manifest);
90
+
91
+ if (packType !== 'skills' && packType !== 'bundle') {
92
+ s.stop('Install failed');
93
+ p.log.error(`Pack "${packName}" is type "${packType}", not a skill pack.`);
94
+ process.exit(1);
95
+ return;
96
+ }
97
+
98
+ const skillsDir = join(resolved.directory, manifest.skills?.dir ?? 'skills');
99
+ const skillsList = existsSync(skillsDir) ? listMdFiles(skillsDir) : [];
100
+
101
+ const entry: LockEntry = {
102
+ id: manifest.id,
103
+ version: manifest.version,
104
+ type: packType,
105
+ source: resolved.source as PackSource,
106
+ directory: resolved.directory,
107
+ integrity: PackLockfile.computeIntegrity(manifestPath),
108
+ installedAt: new Date().toISOString(),
109
+ vaultEntries: 0,
110
+ skills: skillsList,
111
+ hooks: [],
112
+ facadesRegistered: false,
113
+ };
114
+
115
+ lockfile.set(entry);
116
+ lockfile.save();
117
+
118
+ s.stop(`Installed ${manifest.id}@${manifest.version}`);
119
+ if (skillsList.length > 0) {
120
+ p.log.info(` Skills: ${skillsList.join(', ')}`);
121
+ }
122
+ } catch (err) {
123
+ s.stop('Install failed');
124
+ p.log.error(err instanceof Error ? err.message : String(err));
125
+ process.exit(1);
126
+ }
127
+ });
128
+
129
+ // ─── remove ────────────────────────────────────────────────
130
+ skills
131
+ .command('remove')
132
+ .argument('<packId>', 'Skill pack ID to remove')
133
+ .description('Remove a skill pack')
134
+ .action((packId: string) => {
135
+ const lockfile = new PackLockfile(getLockfilePath());
136
+
137
+ if (!lockfile.has(packId)) {
138
+ p.log.error(`Skill pack "${packId}" is not installed.`);
139
+ process.exit(1);
140
+ }
141
+
142
+ lockfile.remove(packId);
143
+ lockfile.save();
144
+ p.log.success(`Removed ${packId}`);
145
+ });
146
+
147
+ // ─── info ──────────────────────────────────────────────────
148
+ skills
149
+ .command('info')
150
+ .argument('<packId>', 'Skill pack ID')
151
+ .description('Show info about a skill pack')
152
+ .action((packId: string) => {
153
+ const lockfile = new PackLockfile(getLockfilePath());
154
+ const entry = lockfile.get(packId);
155
+
156
+ if (!entry) {
157
+ p.log.error(`Skill pack "${packId}" is not installed.`);
158
+ process.exit(1);
159
+ return;
160
+ }
161
+
162
+ console.log(`\n Pack: ${entry.id}`);
163
+ console.log(` Version: ${entry.version}`);
164
+ console.log(` Source: ${entry.source}`);
165
+ console.log(` Installed: ${entry.installedAt}`);
166
+ if (entry.skills.length > 0) console.log(` Skills: ${entry.skills.join(', ')}`);
167
+ console.log('');
168
+ });
169
+ }
170
+
171
+ // ─── Helpers ──────────────────────────────────────────────────────────
172
+
173
+ function getBuiltinDirs(agentPath: string): string[] {
174
+ const dirs: string[] = [];
175
+ const nmPacks = join(agentPath, 'node_modules', '@soleri');
176
+ if (existsSync(nmPacks)) {
177
+ dirs.push(nmPacks);
178
+ }
179
+ return dirs;
180
+ }
181
+
182
+ function listMdFiles(dir: string): string[] {
183
+ try {
184
+ const { basename } = require('node:path');
185
+ return readdirSync(dir)
186
+ .filter((f: string) => f.endsWith('.md'))
187
+ .map((f: string) => basename(f, '.md'));
188
+ } catch {
189
+ return [];
190
+ }
191
+ }
@@ -0,0 +1,93 @@
1
+ import type { Command } from 'commander';
2
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join, resolve } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import * as p from '@clack/prompts';
6
+ import { detectAgent } from '../utils/agent-context.js';
7
+
8
+ type Target = 'claude' | 'codex' | 'both';
9
+
10
+ function uninstallClaude(agentId: string): void {
11
+ const configPath = join(homedir(), '.claude.json');
12
+
13
+ if (!existsSync(configPath)) {
14
+ p.log.warn(`~/.claude.json not found — nothing to remove.`);
15
+ return;
16
+ }
17
+
18
+ let config: Record<string, unknown>;
19
+ try {
20
+ config = JSON.parse(readFileSync(configPath, 'utf-8'));
21
+ } catch {
22
+ p.log.error(`Failed to parse ${configPath}.`);
23
+ process.exit(1);
24
+ }
25
+
26
+ const servers = config.mcpServers as Record<string, unknown> | undefined;
27
+ if (!servers || !(agentId in servers)) {
28
+ p.log.warn(`${agentId} not found in ~/.claude.json — nothing to remove.`);
29
+ return;
30
+ }
31
+
32
+ delete servers[agentId];
33
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
34
+ p.log.success(`Removed ${agentId} from ~/.claude.json`);
35
+ }
36
+
37
+ function uninstallCodex(agentId: string): void {
38
+ const configPath = join(homedir(), '.codex', 'config.toml');
39
+
40
+ if (!existsSync(configPath)) {
41
+ p.log.warn(`~/.codex/config.toml not found — nothing to remove.`);
42
+ return;
43
+ }
44
+
45
+ let content = readFileSync(configPath, 'utf-8');
46
+
47
+ const sectionRegex = new RegExp(`\\[mcp_servers\\.${escapeRegExp(agentId)}\\][^\\[]*`, 's');
48
+
49
+ if (!sectionRegex.test(content)) {
50
+ p.log.warn(`${agentId} not found in ~/.codex/config.toml — nothing to remove.`);
51
+ return;
52
+ }
53
+
54
+ content = content.replace(sectionRegex, '').trim();
55
+ writeFileSync(configPath, content + '\n', 'utf-8');
56
+ p.log.success(`Removed ${agentId} from ~/.codex/config.toml`);
57
+ }
58
+
59
+ function escapeRegExp(s: string): string {
60
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
61
+ }
62
+
63
+ export function registerUninstall(program: Command): void {
64
+ program
65
+ .command('uninstall')
66
+ .argument('[dir]', 'Agent directory (defaults to cwd)')
67
+ .option('--target <target>', 'Registration target: claude, codex, or both', 'claude')
68
+ .description('Remove agent MCP server entry from editor config')
69
+ .action(async (dir?: string, opts?: { target?: string }) => {
70
+ const resolvedDir = dir ? resolve(dir) : undefined;
71
+ const ctx = detectAgent(resolvedDir);
72
+
73
+ if (!ctx) {
74
+ p.log.error('Not in an agent project. Run from an agent directory or pass its path.');
75
+ process.exit(1);
76
+ }
77
+
78
+ const target = (opts?.target ?? 'claude') as Target;
79
+
80
+ if (target !== 'claude' && target !== 'codex' && target !== 'both') {
81
+ p.log.error(`Invalid target "${target}". Use: claude, codex, or both`);
82
+ process.exit(1);
83
+ }
84
+
85
+ if (target === 'claude' || target === 'both') {
86
+ uninstallClaude(ctx.agentId);
87
+ }
88
+
89
+ if (target === 'codex' || target === 'both') {
90
+ uninstallCodex(ctx.agentId);
91
+ }
92
+ });
93
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Hook pack installer — copies hookify files to ~/.claude/ (global) or project .claude/ (local).
3
3
  */
4
- import { existsSync, copyFileSync, unlinkSync, mkdirSync, readFileSync } from 'node:fs';
4
+ import { existsSync, copyFileSync, unlinkSync, mkdirSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
6
  import { homedir } from 'node:os';
7
7
  import { getPack } from './registry.js';
@@ -126,20 +126,3 @@ export function isPackInstalled(
126
126
  if (present === pack.manifest.hooks.length) return true;
127
127
  return 'partial';
128
128
  }
129
-
130
- /**
131
- * Get the installed version of a hook from its file header.
132
- * Returns null if no version found or file doesn't exist.
133
- */
134
- export function getInstalledHookVersion(
135
- hook: string,
136
- options?: { projectDir?: string },
137
- ): string | null {
138
- const claudeDir = resolveClaudeDir(options?.projectDir);
139
- const filePath = join(claudeDir, `hookify.${hook}.local.md`);
140
- if (!existsSync(filePath)) return null;
141
-
142
- const content = readFileSync(filePath, 'utf-8');
143
- const match = content.match(/^# Version: (.+)$/m);
144
- return match ? match[1] : null;
145
- }
@@ -6,7 +6,7 @@ import { join, dirname } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { homedir } from 'node:os';
8
8
 
9
- export interface HookPackManifest {
9
+ interface HookPackManifest {
10
10
  name: string;
11
11
  description: string;
12
12
  hooks: string[];
package/src/main.ts CHANGED
@@ -13,16 +13,52 @@ import { registerGovernance } from './commands/governance.js';
13
13
  import { registerTest } from './commands/test.js';
14
14
  import { registerUpgrade } from './commands/upgrade.js';
15
15
  import { registerExtend } from './commands/extend.js';
16
+ import { registerInstall } from './commands/install.js';
17
+ import { registerUninstall } from './commands/uninstall.js';
18
+ import { registerPack } from './commands/pack.js';
19
+ import { registerSkills } from './commands/skills.js';
20
+ import { registerAgent } from './commands/agent.js';
16
21
 
17
22
  const require = createRequire(import.meta.url);
18
23
  const { version } = require('../package.json');
19
24
 
25
+ const RESET = '\x1b[0m';
26
+ const BOLD = '\x1b[1m';
27
+ const DIM = '\x1b[2m';
28
+ const CYAN = '\x1b[36m';
29
+ const GREEN = '\x1b[32m';
30
+ const YELLOW = '\x1b[33m';
31
+
32
+ function showWelcome(): void {
33
+ console.log();
34
+ console.log(` ${BOLD}${CYAN}soleri${RESET} ${DIM}v${version}${RESET}`);
35
+ console.log(` ${DIM}The agent forge${RESET}`);
36
+ console.log();
37
+ console.log(` ${GREEN}Get started${RESET}`);
38
+ console.log(` ${BOLD}soleri create${RESET} Scaffold a new agent`);
39
+ console.log(` ${BOLD}soleri doctor${RESET} Check system health`);
40
+ console.log();
41
+ console.log(` ${YELLOW}Working on an agent${RESET}`);
42
+ console.log(` ${BOLD}soleri dev${RESET} Run in development mode`);
43
+ console.log(` ${BOLD}soleri test${RESET} Run agent tests`);
44
+ console.log(` ${BOLD}soleri add-domain${RESET} Add a knowledge domain`);
45
+ console.log(` ${BOLD}soleri hooks${RESET} Manage editor hooks`);
46
+ console.log(` ${BOLD}soleri install${RESET} Register agent as MCP server`);
47
+ console.log(` ${BOLD}soleri uninstall${RESET} Remove agent MCP server entry`);
48
+ console.log();
49
+ console.log(` ${DIM}Run ${BOLD}soleri --help${RESET}${DIM} for all commands${RESET}`);
50
+ console.log();
51
+ }
52
+
20
53
  const program = new Command();
21
54
 
22
55
  program
23
56
  .name('soleri')
24
57
  .description('Developer CLI for creating and managing Soleri AI agents')
25
- .version(version);
58
+ .version(version)
59
+ .action(() => {
60
+ showWelcome();
61
+ });
26
62
 
27
63
  registerCreate(program);
28
64
  registerList(program);
@@ -35,5 +71,10 @@ registerGovernance(program);
35
71
  registerTest(program);
36
72
  registerUpgrade(program);
37
73
  registerExtend(program);
74
+ registerInstall(program);
75
+ registerUninstall(program);
76
+ registerPack(program);
77
+ registerSkills(program);
78
+ registerAgent(program);
38
79
 
39
80
  program.parse();