@soleri/cli 1.2.0 → 1.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.
Files changed (48) hide show
  1. package/README.md +30 -1
  2. package/dist/commands/create.js +5 -2
  3. package/dist/commands/create.js.map +1 -1
  4. package/dist/commands/hooks.js +40 -11
  5. package/dist/commands/hooks.js.map +1 -1
  6. package/dist/hook-packs/a11y/hookify.focus-ring-required.local.md +1 -0
  7. package/dist/hook-packs/a11y/hookify.semantic-html.local.md +1 -0
  8. package/dist/hook-packs/a11y/hookify.ux-touch-targets.local.md +1 -0
  9. package/dist/hook-packs/a11y/manifest.json +1 -0
  10. package/dist/hook-packs/clean-commits/hookify.no-ai-attribution.local.md +1 -0
  11. package/dist/hook-packs/clean-commits/manifest.json +1 -0
  12. package/dist/hook-packs/css-discipline/hookify.no-important.local.md +1 -0
  13. package/dist/hook-packs/css-discipline/hookify.no-inline-styles.local.md +1 -0
  14. package/dist/hook-packs/css-discipline/manifest.json +1 -0
  15. package/dist/hook-packs/full/manifest.json +1 -0
  16. package/dist/hook-packs/installer.d.ts +18 -5
  17. package/dist/hook-packs/installer.js +29 -10
  18. package/dist/hook-packs/installer.js.map +1 -1
  19. package/dist/hook-packs/installer.ts +42 -10
  20. package/dist/hook-packs/registry.d.ts +6 -2
  21. package/dist/hook-packs/registry.js +46 -13
  22. package/dist/hook-packs/registry.js.map +1 -1
  23. package/dist/hook-packs/registry.ts +49 -13
  24. package/dist/hook-packs/typescript-safety/hookify.no-any-types.local.md +1 -0
  25. package/dist/hook-packs/typescript-safety/hookify.no-console-log.local.md +1 -0
  26. package/dist/hook-packs/typescript-safety/manifest.json +1 -0
  27. package/dist/utils/checks.d.ts +1 -0
  28. package/dist/utils/checks.js +17 -0
  29. package/dist/utils/checks.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/commands/create.ts +4 -2
  32. package/src/commands/hooks.ts +54 -11
  33. package/src/hook-packs/a11y/hookify.focus-ring-required.local.md +1 -0
  34. package/src/hook-packs/a11y/hookify.semantic-html.local.md +1 -0
  35. package/src/hook-packs/a11y/hookify.ux-touch-targets.local.md +1 -0
  36. package/src/hook-packs/a11y/manifest.json +1 -0
  37. package/src/hook-packs/clean-commits/hookify.no-ai-attribution.local.md +1 -0
  38. package/src/hook-packs/clean-commits/manifest.json +1 -0
  39. package/src/hook-packs/css-discipline/hookify.no-important.local.md +1 -0
  40. package/src/hook-packs/css-discipline/hookify.no-inline-styles.local.md +1 -0
  41. package/src/hook-packs/css-discipline/manifest.json +1 -0
  42. package/src/hook-packs/full/manifest.json +1 -0
  43. package/src/hook-packs/installer.ts +42 -10
  44. package/src/hook-packs/registry.ts +49 -13
  45. package/src/hook-packs/typescript-safety/hookify.no-any-types.local.md +1 -0
  46. package/src/hook-packs/typescript-safety/hookify.no-console-log.local.md +1 -0
  47. package/src/hook-packs/typescript-safety/manifest.json +1 -0
  48. package/src/utils/checks.ts +18 -0
@@ -11,21 +11,27 @@ export interface HookPackManifest {
11
11
  description: string;
12
12
  hooks: string[];
13
13
  composedFrom?: string[];
14
+ version?: string;
15
+ /** Whether this pack is built-in or user-defined */
16
+ source?: 'built-in' | 'local';
14
17
  }
15
18
 
16
19
  const __filename = fileURLToPath(import.meta.url);
17
20
  const __dirname = dirname(__filename);
18
21
 
19
22
  /** Root directory containing all built-in hook packs. */
20
- function getPacksRoot(): string {
23
+ function getBuiltinRoot(): string {
21
24
  return __dirname;
22
25
  }
23
26
 
24
- /**
25
- * List all available built-in hook packs.
26
- */
27
- export function listPacks(): HookPackManifest[] {
28
- const root = getPacksRoot();
27
+ /** Local custom packs directory. */
28
+ function getLocalRoot(): string {
29
+ return join(process.cwd(), '.soleri', 'hook-packs');
30
+ }
31
+
32
+ /** Scan a directory for pack manifests. */
33
+ function scanPacksDir(root: string, source: 'built-in' | 'local'): HookPackManifest[] {
34
+ if (!existsSync(root)) return [];
29
35
  const entries = readdirSync(root, { withFileTypes: true });
30
36
  const packs: HookPackManifest[] = [];
31
37
 
@@ -36,6 +42,7 @@ export function listPacks(): HookPackManifest[] {
36
42
 
37
43
  try {
38
44
  const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as HookPackManifest;
45
+ manifest.source = source;
39
46
  packs.push(manifest);
40
47
  } catch {
41
48
  // Skip malformed manifests
@@ -46,18 +53,47 @@ export function listPacks(): HookPackManifest[] {
46
53
  }
47
54
 
48
55
  /**
49
- * Get a specific pack by name.
56
+ * List all available hook packs (built-in + local custom).
57
+ * Local packs in .soleri/hook-packs/ override built-in packs with the same name.
58
+ */
59
+ export function listPacks(): HookPackManifest[] {
60
+ const builtIn = scanPacksDir(getBuiltinRoot(), 'built-in');
61
+ const local = scanPacksDir(getLocalRoot(), 'local');
62
+
63
+ // Local packs override built-in packs with same name
64
+ const byName = new Map<string, HookPackManifest>();
65
+ for (const pack of builtIn) byName.set(pack.name, pack);
66
+ for (const pack of local) byName.set(pack.name, pack);
67
+
68
+ return Array.from(byName.values());
69
+ }
70
+
71
+ /**
72
+ * Get a specific pack by name. Local packs take precedence.
50
73
  */
51
74
  export function getPack(name: string): { manifest: HookPackManifest; dir: string } | null {
52
- const root = getPacksRoot();
53
- const dir = join(root, name);
54
- const manifestPath = join(dir, 'manifest.json');
75
+ // Check local first
76
+ const localDir = join(getLocalRoot(), name);
77
+ const localManifest = join(localDir, 'manifest.json');
78
+ if (existsSync(localManifest)) {
79
+ try {
80
+ const manifest = JSON.parse(readFileSync(localManifest, 'utf-8')) as HookPackManifest;
81
+ manifest.source = 'local';
82
+ return { manifest, dir: localDir };
83
+ } catch {
84
+ // Fall through to built-in
85
+ }
86
+ }
55
87
 
56
- if (!existsSync(manifestPath)) return null;
88
+ // Then built-in
89
+ const builtinDir = join(getBuiltinRoot(), name);
90
+ const builtinManifest = join(builtinDir, 'manifest.json');
91
+ if (!existsSync(builtinManifest)) return null;
57
92
 
58
93
  try {
59
- const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as HookPackManifest;
60
- return { manifest, dir };
94
+ const manifest = JSON.parse(readFileSync(builtinManifest, 'utf-8')) as HookPackManifest;
95
+ manifest.source = 'built-in';
96
+ return { manifest, dir: builtinDir };
61
97
  } catch {
62
98
  return null;
63
99
  }
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: typescript-safety
3
+ # Version: 1.0.0
3
4
  # Rule: no-any-types
4
5
  name: no-any-types
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: typescript-safety
3
+ # Version: 1.0.0
3
4
  # Rule: no-console-log
4
5
  name: no-console-log
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "typescript-safety",
3
+ "version": "1.0.0",
3
4
  "description": "Block unsafe TypeScript patterns",
4
5
  "hooks": ["no-any-types", "no-console-log"]
5
6
  }
@@ -6,6 +6,7 @@ import { join } from 'node:path';
6
6
  import { execFileSync } from 'node:child_process';
7
7
  import { homedir } from 'node:os';
8
8
  import { detectAgent } from './agent-context.js';
9
+ import { getInstalledPacks } from '../hook-packs/registry.js';
9
10
 
10
11
  interface CheckResult {
11
12
  status: 'pass' | 'fail' | 'warn';
@@ -134,6 +135,22 @@ function checkCognee(): CheckResult {
134
135
  }
135
136
  }
136
137
 
138
+ export function checkHookPacks(): CheckResult {
139
+ const installed = getInstalledPacks();
140
+ if (installed.length === 0) {
141
+ return {
142
+ status: 'warn',
143
+ label: 'Hook packs',
144
+ detail: 'none installed — run soleri hooks list-packs',
145
+ };
146
+ }
147
+ return {
148
+ status: 'pass',
149
+ label: 'Hook packs',
150
+ detail: installed.join(', '),
151
+ };
152
+ }
153
+
137
154
  export function runAllChecks(dir?: string): CheckResult[] {
138
155
  return [
139
156
  checkNodeVersion(),
@@ -143,6 +160,7 @@ export function runAllChecks(dir?: string): CheckResult[] {
143
160
  checkNodeModules(dir),
144
161
  checkAgentBuild(dir),
145
162
  checkMcpRegistration(dir),
163
+ checkHookPacks(),
146
164
  checkCognee(),
147
165
  ];
148
166
  }