@soleri/cli 9.2.0 → 9.3.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.
@@ -145,9 +145,10 @@ function installOpencode(agentId: string, agentDir: string, isFileTree: boolean)
145
145
  const engine = resolveEngineBin();
146
146
  servers[agentId] = {
147
147
  type: 'local',
148
- command: engine.command === 'node'
149
- ? ['node', engine.bin, '--agent', join(agentDir, 'agent.yaml')]
150
- : ['npx', '-y', '@soleri/engine', '--agent', join(agentDir, 'agent.yaml')],
148
+ command:
149
+ engine.command === 'node'
150
+ ? ['node', engine.bin, '--agent', join(agentDir, 'agent.yaml')]
151
+ : ['npx', '-y', '@soleri/engine', '--agent', join(agentDir, 'agent.yaml')],
151
152
  };
152
153
  } else {
153
154
  servers[agentId] = {
@@ -234,7 +235,9 @@ export function registerInstall(program: Command): void {
234
235
  if (engine.command === 'node') {
235
236
  p.log.info(`Detected file-tree agent (v7) — using resolved engine at ${engine.bin}`);
236
237
  } else {
237
- p.log.warn(`Could not resolve @soleri/core locally — falling back to npx (slower startup)`);
238
+ p.log.warn(
239
+ `Could not resolve @soleri/core locally — falling back to npx (slower startup)`,
240
+ );
238
241
  p.log.info(`For instant startup: npm install -g @soleri/cli`);
239
242
  }
240
243
  }
@@ -30,25 +30,33 @@ function resolveHookFiles(packName: string): Map<string, string> {
30
30
  if (pack.manifest.composedFrom) {
31
31
  for (const subPackName of pack.manifest.composedFrom) {
32
32
  const subFiles = resolveHookFiles(subPackName);
33
- for (const [hook, path] of subFiles) { files.set(hook, path); }
33
+ for (const [hook, path] of subFiles) {
34
+ files.set(hook, path);
35
+ }
34
36
  }
35
37
  } else {
36
38
  for (const hook of pack.manifest.hooks) {
37
39
  const filePath = join(pack.dir, `hookify.${hook}.local.md`);
38
- if (existsSync(filePath)) { files.set(hook, filePath); }
40
+ if (existsSync(filePath)) {
41
+ files.set(hook, filePath);
42
+ }
39
43
  }
40
44
  }
41
45
  return files;
42
46
  }
43
47
 
44
- function resolveScripts(packName: string): Map<string, { sourcePath: string; targetDir: string; file: string }> {
48
+ function resolveScripts(
49
+ packName: string,
50
+ ): Map<string, { sourcePath: string; targetDir: string; file: string }> {
45
51
  const pack = getPack(packName);
46
52
  if (!pack) return new Map();
47
53
  const scripts = new Map<string, { sourcePath: string; targetDir: string; file: string }>();
48
54
  if (pack.manifest.composedFrom) {
49
55
  for (const subPackName of pack.manifest.composedFrom) {
50
56
  const subScripts = resolveScripts(subPackName);
51
- for (const [name, info] of subScripts) { scripts.set(name, info); }
57
+ for (const [name, info] of subScripts) {
58
+ scripts.set(name, info);
59
+ }
52
60
  }
53
61
  } else if (pack.manifest.scripts) {
54
62
  for (const script of pack.manifest.scripts) {
@@ -61,24 +69,39 @@ function resolveScripts(packName: string): Map<string, { sourcePath: string; tar
61
69
  return scripts;
62
70
  }
63
71
 
64
- function resolveLifecycleHooks(packName: string): { packName: string; hook: HookPackLifecycleHook }[] {
72
+ function resolveLifecycleHooks(
73
+ packName: string,
74
+ ): { packName: string; hook: HookPackLifecycleHook }[] {
65
75
  const pack = getPack(packName);
66
76
  if (!pack) return [];
67
77
  const hooks: { packName: string; hook: HookPackLifecycleHook }[] = [];
68
78
  if (pack.manifest.composedFrom) {
69
- for (const subPackName of pack.manifest.composedFrom) { hooks.push(...resolveLifecycleHooks(subPackName)); }
79
+ for (const subPackName of pack.manifest.composedFrom) {
80
+ hooks.push(...resolveLifecycleHooks(subPackName));
81
+ }
70
82
  } else if (pack.manifest.lifecycleHooks) {
71
- for (const hook of pack.manifest.lifecycleHooks) { hooks.push({ packName: pack.manifest.name, hook }); }
83
+ for (const hook of pack.manifest.lifecycleHooks) {
84
+ hooks.push({ packName: pack.manifest.name, hook });
85
+ }
72
86
  }
73
87
  return hooks;
74
88
  }
75
89
 
76
- interface SettingsHookEntry { type: 'command'; command: string; timeout?: number; [key: string]: unknown; }
90
+ interface SettingsHookEntry {
91
+ type: 'command';
92
+ command: string;
93
+ timeout?: number;
94
+ [key: string]: unknown;
95
+ }
77
96
 
78
97
  function readClaudeSettings(claudeDir: string): Record<string, unknown> {
79
98
  const settingsPath = join(claudeDir, 'settings.json');
80
99
  if (!existsSync(settingsPath)) return {};
81
- try { return JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch { return {}; }
100
+ try {
101
+ return JSON.parse(readFileSync(settingsPath, 'utf-8'));
102
+ } catch {
103
+ return {};
104
+ }
82
105
  }
83
106
 
84
107
  function writeClaudeSettings(claudeDir: string, settings: Record<string, unknown>): void {
@@ -86,7 +109,10 @@ function writeClaudeSettings(claudeDir: string, settings: Record<string, unknown
86
109
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
87
110
  }
88
111
 
89
- function addLifecycleHooks(claudeDir: string, lifecycleHooks: { packName: string; hook: HookPackLifecycleHook }[]): string[] {
112
+ function addLifecycleHooks(
113
+ claudeDir: string,
114
+ lifecycleHooks: { packName: string; hook: HookPackLifecycleHook }[],
115
+ ): string[] {
90
116
  if (lifecycleHooks.length === 0) return [];
91
117
  const settings = readClaudeSettings(claudeDir);
92
118
  const hooks = (settings['hooks'] ?? {}) as Record<string, unknown>;
@@ -94,10 +120,18 @@ function addLifecycleHooks(claudeDir: string, lifecycleHooks: { packName: string
94
120
  for (const { packName: sourcePack, hook } of lifecycleHooks) {
95
121
  const eventKey = hook.event;
96
122
  const eventHooks = (hooks[eventKey] ?? []) as SettingsHookEntry[];
97
- const alreadyExists = eventHooks.some((h) => h.command === hook.command && h[PACK_MARKER] === sourcePack);
123
+ const alreadyExists = eventHooks.some(
124
+ (h) => h.command === hook.command && h[PACK_MARKER] === sourcePack,
125
+ );
98
126
  if (!alreadyExists) {
99
- const entry: SettingsHookEntry = { type: hook.type, command: hook.command, [PACK_MARKER]: sourcePack };
100
- if (hook.timeout) { entry.timeout = hook.timeout; }
127
+ const entry: SettingsHookEntry = {
128
+ type: hook.type,
129
+ command: hook.command,
130
+ [PACK_MARKER]: sourcePack,
131
+ };
132
+ if (hook.timeout) {
133
+ entry.timeout = hook.timeout;
134
+ }
101
135
  eventHooks.push(entry);
102
136
  hooks[eventKey] = eventHooks;
103
137
  added.push(`${eventKey}:${hook.matcher}`);
@@ -118,10 +152,17 @@ function removeLifecycleHooks(claudeDir: string, packName: string): string[] {
118
152
  const filtered = eventHooks.filter((h) => h[PACK_MARKER] !== packName);
119
153
  if (filtered.length < before) {
120
154
  removed.push(eventKey);
121
- if (filtered.length === 0) { delete hooks[eventKey]; } else { hooks[eventKey] = filtered; }
155
+ if (filtered.length === 0) {
156
+ delete hooks[eventKey];
157
+ } else {
158
+ hooks[eventKey] = filtered;
159
+ }
122
160
  }
123
161
  }
124
- if (removed.length > 0) { settings['hooks'] = hooks; writeClaudeSettings(claudeDir, settings); }
162
+ if (removed.length > 0) {
163
+ settings['hooks'] = hooks;
164
+ writeClaudeSettings(claudeDir, settings);
165
+ }
125
166
  return removed;
126
167
  }
127
168
 
@@ -130,7 +171,9 @@ export function installPack(
130
171
  options?: { projectDir?: string },
131
172
  ): { installed: string[]; skipped: string[]; scripts: string[]; lifecycleHooks: string[] } {
132
173
  const pack = getPack(packName);
133
- if (!pack) { throw new Error(`Unknown hook pack: "${packName}"`); }
174
+ if (!pack) {
175
+ throw new Error(`Unknown hook pack: "${packName}"`);
176
+ }
134
177
  const claudeDir = resolveClaudeDir(options?.projectDir);
135
178
  mkdirSync(claudeDir, { recursive: true });
136
179
  const hookFiles = resolveHookFiles(packName);
@@ -138,7 +181,12 @@ export function installPack(
138
181
  const skipped: string[] = [];
139
182
  for (const [hook, sourcePath] of hookFiles) {
140
183
  const destPath = join(claudeDir, `hookify.${hook}.local.md`);
141
- if (existsSync(destPath)) { skipped.push(hook); } else { copyFileSync(sourcePath, destPath); installed.push(hook); }
184
+ if (existsSync(destPath)) {
185
+ skipped.push(hook);
186
+ } else {
187
+ copyFileSync(sourcePath, destPath);
188
+ installed.push(hook);
189
+ }
142
190
  }
143
191
  const scriptFiles = resolveScripts(packName);
144
192
  const installedScripts: string[] = [];
@@ -160,18 +208,26 @@ export function removePack(
160
208
  options?: { projectDir?: string },
161
209
  ): { removed: string[]; scripts: string[]; lifecycleHooks: string[] } {
162
210
  const pack = getPack(packName);
163
- if (!pack) { throw new Error(`Unknown hook pack: "${packName}"`); }
211
+ if (!pack) {
212
+ throw new Error(`Unknown hook pack: "${packName}"`);
213
+ }
164
214
  const claudeDir = resolveClaudeDir(options?.projectDir);
165
215
  const removed: string[] = [];
166
216
  for (const hook of pack.manifest.hooks) {
167
217
  const filePath = join(claudeDir, `hookify.${hook}.local.md`);
168
- if (existsSync(filePath)) { unlinkSync(filePath); removed.push(hook); }
218
+ if (existsSync(filePath)) {
219
+ unlinkSync(filePath);
220
+ removed.push(hook);
221
+ }
169
222
  }
170
223
  const removedScripts: string[] = [];
171
224
  if (pack.manifest.scripts) {
172
225
  for (const script of pack.manifest.scripts) {
173
226
  const filePath = join(claudeDir, script.targetDir, script.file);
174
- if (existsSync(filePath)) { unlinkSync(filePath); removedScripts.push(`${script.targetDir}/${script.file}`); }
227
+ if (existsSync(filePath)) {
228
+ unlinkSync(filePath);
229
+ removedScripts.push(`${script.targetDir}/${script.file}`);
230
+ }
175
231
  }
176
232
  }
177
233
  if (pack.manifest.composedFrom) {
@@ -180,14 +236,19 @@ export function removePack(
180
236
  if (subPack?.manifest.scripts) {
181
237
  for (const script of subPack.manifest.scripts) {
182
238
  const filePath = join(claudeDir, script.targetDir, script.file);
183
- if (existsSync(filePath)) { unlinkSync(filePath); removedScripts.push(`${script.targetDir}/${script.file}`); }
239
+ if (existsSync(filePath)) {
240
+ unlinkSync(filePath);
241
+ removedScripts.push(`${script.targetDir}/${script.file}`);
242
+ }
184
243
  }
185
244
  }
186
245
  }
187
246
  }
188
247
  const removedHooks = removeLifecycleHooks(claudeDir, packName);
189
248
  if (pack.manifest.composedFrom) {
190
- for (const subPackName of pack.manifest.composedFrom) { removedHooks.push(...removeLifecycleHooks(claudeDir, subPackName)); }
249
+ for (const subPackName of pack.manifest.composedFrom) {
250
+ removedHooks.push(...removeLifecycleHooks(claudeDir, subPackName));
251
+ }
191
252
  }
192
253
  return { removed, scripts: removedScripts, lifecycleHooks: removedHooks };
193
254
  }
@@ -203,12 +264,16 @@ export function isPackInstalled(
203
264
  let present = 0;
204
265
  for (const hook of pack.manifest.hooks) {
205
266
  total++;
206
- if (existsSync(join(claudeDir, `hookify.${hook}.local.md`))) { present++; }
267
+ if (existsSync(join(claudeDir, `hookify.${hook}.local.md`))) {
268
+ present++;
269
+ }
207
270
  }
208
271
  if (pack.manifest.scripts) {
209
272
  for (const script of pack.manifest.scripts) {
210
273
  total++;
211
- if (existsSync(join(claudeDir, script.targetDir, script.file))) { present++; }
274
+ if (existsSync(join(claudeDir, script.targetDir, script.file))) {
275
+ present++;
276
+ }
212
277
  }
213
278
  }
214
279
  if (pack.manifest.composedFrom) {
@@ -217,7 +282,9 @@ export function isPackInstalled(
217
282
  if (subPack?.manifest.scripts) {
218
283
  for (const script of subPack.manifest.scripts) {
219
284
  total++;
220
- if (existsSync(join(claudeDir, script.targetDir, script.file))) { present++; }
285
+ if (existsSync(join(claudeDir, script.targetDir, script.file))) {
286
+ present++;
287
+ }
221
288
  }
222
289
  }
223
290
  }
@@ -230,7 +297,12 @@ export function isPackInstalled(
230
297
  for (const { packName: sourcePack, hook } of lcHooks) {
231
298
  total++;
232
299
  const eventHooks = hooksObj[hook.event];
233
- if (Array.isArray(eventHooks) && eventHooks.some((h) => h.command === hook.command && h[PACK_MARKER] === sourcePack)) { present++; }
300
+ if (
301
+ Array.isArray(eventHooks) &&
302
+ eventHooks.some((h) => h.command === hook.command && h[PACK_MARKER] === sourcePack)
303
+ ) {
304
+ present++;
305
+ }
234
306
  }
235
307
  }
236
308
  }
@@ -35,8 +35,12 @@ export interface HookPackManifest {
35
35
  const __filename = fileURLToPath(import.meta.url);
36
36
  const __dirname = dirname(__filename);
37
37
 
38
- function getBuiltinRoot(): string { return __dirname; }
39
- function getLocalRoot(): string { return join(process.cwd(), '.soleri', 'hook-packs'); }
38
+ function getBuiltinRoot(): string {
39
+ return __dirname;
40
+ }
41
+ function getLocalRoot(): string {
42
+ return join(process.cwd(), '.soleri', 'hook-packs');
43
+ }
40
44
 
41
45
  function scanPacksDir(root: string, source: 'built-in' | 'local'): HookPackManifest[] {
42
46
  if (!existsSync(root)) return [];
@@ -50,7 +54,9 @@ function scanPacksDir(root: string, source: 'built-in' | 'local'): HookPackManif
50
54
  const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as HookPackManifest;
51
55
  manifest.source = source;
52
56
  packs.push(manifest);
53
- } catch { /* Skip malformed manifests */ }
57
+ } catch {
58
+ /* Skip malformed manifests */
59
+ }
54
60
  }
55
61
  return packs;
56
62
  }
@@ -72,7 +78,9 @@ export function getPack(name: string): { manifest: HookPackManifest; dir: string
72
78
  const manifest = JSON.parse(readFileSync(localManifest, 'utf-8')) as HookPackManifest;
73
79
  manifest.source = 'local';
74
80
  return { manifest, dir: localDir };
75
- } catch { /* Fall through */ }
81
+ } catch {
82
+ /* Fall through */
83
+ }
76
84
  }
77
85
  const builtinDir = join(getBuiltinRoot(), name);
78
86
  const builtinManifest = join(builtinDir, 'manifest.json');
@@ -81,7 +89,9 @@ export function getPack(name: string): { manifest: HookPackManifest; dir: string
81
89
  const manifest = JSON.parse(readFileSync(builtinManifest, 'utf-8')) as HookPackManifest;
82
90
  manifest.source = 'built-in';
83
91
  return { manifest, dir: builtinDir };
84
- } catch { return null; }
92
+ } catch {
93
+ return null;
94
+ }
85
95
  }
86
96
 
87
97
  export function getInstalledPacks(): string[] {
@@ -94,14 +104,18 @@ export function getInstalledPacks(): string[] {
94
104
  const allScripts = pack.scripts.every((script) =>
95
105
  existsSync(join(claudeDir, script.targetDir, script.file)),
96
106
  );
97
- if (allScripts) { installed.push(pack.name); }
107
+ if (allScripts) {
108
+ installed.push(pack.name);
109
+ }
98
110
  }
99
111
  continue;
100
112
  }
101
113
  const allPresent = pack.hooks.every((hook) =>
102
114
  existsSync(join(claudeDir, `hookify.${hook}.local.md`)),
103
115
  );
104
- if (allPresent) { installed.push(pack.name); }
116
+ if (allPresent) {
117
+ installed.push(pack.name);
118
+ }
105
119
  }
106
120
  return installed;
107
121
  }