@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
package/README.md CHANGED
@@ -25,6 +25,10 @@ The interactive wizard walks you through agent configuration: name, role, domain
25
25
  | `soleri hooks add <editor>` | Generate editor hooks/config files |
26
26
  | `soleri hooks remove <editor>` | Remove editor hooks/config files |
27
27
  | `soleri hooks list` | Show installed editor hooks |
28
+ | `soleri hooks add-pack <pack>` | Install a hook pack globally (~/.claude/) |
29
+ | `soleri hooks remove-pack <pack>` | Remove a hook pack |
30
+ | `soleri hooks list-packs` | Show available hook packs and their status |
31
+ | `soleri hooks upgrade-pack <pack>`| Upgrade a hook pack to the latest version |
28
32
 
29
33
  ### Create
30
34
 
@@ -47,10 +51,35 @@ The config file follows the same schema as the wizard output:
47
51
  "domains": ["security", "code-quality"],
48
52
  "principles": ["Security is not optional"],
49
53
  "greeting": "Ready to review.",
50
- "outputDir": "."
54
+ "outputDir": ".",
55
+ "hookPacks": ["typescript-safety", "clean-commits"]
51
56
  }
52
57
  ```
53
58
 
59
+ ### Hook Packs
60
+
61
+ Hook packs are curated sets of quality gate rules that install as hookify files to `~/.claude/`. They enforce code standards during AI-assisted development.
62
+
63
+ **Built-in packs:**
64
+
65
+ | Pack | Hooks | Description |
66
+ |------|-------|-------------|
67
+ | `typescript-safety` | no-any-types, no-console-log | Block unsafe TS patterns |
68
+ | `a11y` | semantic-html, focus-ring-required, ux-touch-targets | Accessibility enforcement |
69
+ | `css-discipline` | no-important, no-inline-styles | CSS best practices |
70
+ | `clean-commits` | no-ai-attribution | No AI attribution in git |
71
+ | `full` | All 8 hooks | Complete quality suite |
72
+
73
+ ```bash
74
+ soleri hooks list-packs # See available packs
75
+ soleri hooks add-pack typescript-safety # Install globally
76
+ soleri hooks add-pack full --project # Install to project .claude/
77
+ soleri hooks upgrade-pack full # Upgrade to latest version
78
+ soleri hooks remove-pack typescript-safety # Remove
79
+ ```
80
+
81
+ **Custom packs:** Create a `.soleri/hook-packs/<pack-name>/` directory with a `manifest.json` and hookify `.md` files. Local packs override built-in packs with the same name.
82
+
54
83
  ### Editor Hooks
55
84
 
56
85
  Generate editor-specific configuration files for your agent:
@@ -37,9 +37,12 @@ export function registerCreate(program) {
37
37
  return;
38
38
  }
39
39
  }
40
- // Hook packs (interactive only)
40
+ // Hook packs — from config file or interactive prompt
41
41
  let selectedPacks = [];
42
- if (!opts?.config) {
42
+ if (config.hookPacks && config.hookPacks.length > 0) {
43
+ selectedPacks = config.hookPacks;
44
+ }
45
+ else if (!opts?.config) {
43
46
  const packs = listPacks();
44
47
  const packChoices = packs.map((pk) => ({
45
48
  value: pk.name,
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -75,23 +75,26 @@ export function registerHooks(program) {
75
75
  hooks
76
76
  .command('add-pack')
77
77
  .argument('<pack>', 'Hook pack name')
78
- .description('Install a hook pack globally (~/.claude/)')
79
- .action((packName) => {
78
+ .option('--project', 'Install to project .claude/ instead of global ~/.claude/')
79
+ .description('Install a hook pack globally (~/.claude/) or per-project (--project)')
80
+ .action((packName, opts) => {
80
81
  const pack = getPack(packName);
81
82
  if (!pack) {
82
83
  const available = listPacks().map((p) => p.name);
83
84
  log.fail(`Unknown pack "${packName}". Available: ${available.join(', ')}`);
84
85
  process.exit(1);
85
86
  }
86
- const { installed, skipped } = installPack(packName);
87
+ const projectDir = opts.project ? process.cwd() : undefined;
88
+ const target = opts.project ? '.claude/' : '~/.claude/';
89
+ const { installed, skipped } = installPack(packName, { projectDir });
87
90
  for (const hook of installed) {
88
- log.pass(`Installed hookify.${hook}.local.md`);
91
+ log.pass(`Installed hookify.${hook}.local.md → ${target}`);
89
92
  }
90
93
  for (const hook of skipped) {
91
94
  log.dim(` hookify.${hook}.local.md — already exists, skipped`);
92
95
  }
93
96
  if (installed.length > 0) {
94
- log.info(`Pack "${packName}" installed (${installed.length} hooks)`);
97
+ log.info(`Pack "${packName}" installed (${installed.length} hooks) → ${target}`);
95
98
  }
96
99
  else {
97
100
  log.info(`Pack "${packName}" — all hooks already installed`);
@@ -100,15 +103,17 @@ export function registerHooks(program) {
100
103
  hooks
101
104
  .command('remove-pack')
102
105
  .argument('<pack>', 'Hook pack name')
103
- .description('Remove a hook pack from ~/.claude/')
104
- .action((packName) => {
106
+ .option('--project', 'Remove from project .claude/ instead of global ~/.claude/')
107
+ .description('Remove a hook pack')
108
+ .action((packName, opts) => {
105
109
  const pack = getPack(packName);
106
110
  if (!pack) {
107
111
  const available = listPacks().map((p) => p.name);
108
112
  log.fail(`Unknown pack "${packName}". Available: ${available.join(', ')}`);
109
113
  process.exit(1);
110
114
  }
111
- const { removed } = removePack(packName);
115
+ const projectDir = opts.project ? process.cwd() : undefined;
116
+ const { removed } = removePack(packName, { projectDir });
112
117
  if (removed.length === 0) {
113
118
  log.info(`No hooks from pack "${packName}" found to remove.`);
114
119
  }
@@ -127,17 +132,41 @@ export function registerHooks(program) {
127
132
  log.heading('Hook Packs');
128
133
  for (const pack of packs) {
129
134
  const status = isPackInstalled(pack.name);
135
+ const versionLabel = pack.version ? ` v${pack.version}` : '';
136
+ const sourceLabel = pack.source === 'local' ? ' [local]' : '';
130
137
  if (status === true) {
131
- log.pass(`${pack.name}`, `${pack.description} (${pack.hooks.length} hooks)`);
138
+ log.pass(`${pack.name}${versionLabel}${sourceLabel}`, `${pack.description} (${pack.hooks.length} hooks)`);
132
139
  }
133
140
  else if (status === 'partial') {
134
- log.warn(`${pack.name}`, `${pack.description} (${pack.hooks.length} hooks) — partial`);
141
+ log.warn(`${pack.name}${versionLabel}${sourceLabel}`, `${pack.description} (${pack.hooks.length} hooks) — partial`);
135
142
  }
136
143
  else {
137
- log.dim(` ${pack.name} — ${pack.description} (${pack.hooks.length} hooks)`);
144
+ log.dim(` ${pack.name}${versionLabel}${sourceLabel} — ${pack.description} (${pack.hooks.length} hooks)`);
138
145
  }
139
146
  }
140
147
  });
148
+ hooks
149
+ .command('upgrade-pack')
150
+ .argument('<pack>', 'Hook pack name')
151
+ .option('--project', 'Upgrade in project .claude/ instead of global ~/.claude/')
152
+ .description('Upgrade a hook pack to the latest version (overwrites existing files)')
153
+ .action((packName, opts) => {
154
+ const pack = getPack(packName);
155
+ if (!pack) {
156
+ const available = listPacks().map((p) => p.name);
157
+ log.fail(`Unknown pack "${packName}". Available: ${available.join(', ')}`);
158
+ process.exit(1);
159
+ }
160
+ const projectDir = opts.project ? process.cwd() : undefined;
161
+ const packVersion = pack.manifest.version ?? 'unknown';
162
+ // Remove then reinstall to force overwrite
163
+ removePack(packName, { projectDir });
164
+ const { installed } = installPack(packName, { projectDir });
165
+ for (const hook of installed) {
166
+ log.pass(`hookify.${hook}.local.md → v${packVersion}`);
167
+ }
168
+ log.info(`Pack "${packName}" upgraded to v${packVersion} (${installed.length} hooks)`);
169
+ });
141
170
  }
142
171
  function isValidEditor(editor) {
143
172
  return SUPPORTED_EDITORS.includes(editor);
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: a11y
3
+ # Version: 1.0.0
3
4
  # Rule: focus-ring-required
4
5
  name: focus-ring-required
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: a11y
3
+ # Version: 1.0.0
3
4
  # Rule: semantic-html
4
5
  name: semantic-html
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: a11y
3
+ # Version: 1.0.0
3
4
  # Rule: ux-touch-targets
4
5
  name: ux-touch-targets
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "a11y",
3
+ "version": "1.0.0",
3
4
  "description": "Accessibility enforcement",
4
5
  "hooks": ["semantic-html", "focus-ring-required", "ux-touch-targets"]
5
6
  }
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: clean-commits
3
+ # Version: 1.0.0
3
4
  # Rule: no-ai-attribution
4
5
  name: no-ai-attribution
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "clean-commits",
3
+ "version": "1.0.0",
3
4
  "description": "No AI attribution in git commits",
4
5
  "hooks": ["no-ai-attribution"]
5
6
  }
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: css-discipline
3
+ # Version: 1.0.0
3
4
  # Rule: no-important
4
5
  name: no-important
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Soleri Hook Pack: css-discipline
3
+ # Version: 1.0.0
3
4
  # Rule: no-inline-styles
4
5
  name: no-inline-styles
5
6
  enabled: true
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "css-discipline",
3
+ "version": "1.0.0",
3
4
  "description": "CSS best practices",
4
5
  "hooks": ["no-important", "no-inline-styles"]
5
6
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "full",
3
+ "version": "1.0.0",
3
4
  "description": "Complete quality suite — all 8 hooks",
4
5
  "hooks": ["no-any-types", "no-console-log", "no-important", "no-inline-styles", "semantic-html", "focus-ring-required", "ux-touch-targets", "no-ai-attribution"],
5
6
  "composedFrom": ["typescript-safety", "a11y", "css-discipline", "clean-commits"]
@@ -1,19 +1,32 @@
1
1
  /**
2
- * Install a hook pack globally to ~/.claude/.
2
+ * Install a hook pack to ~/.claude/ (default) or project .claude/ (--project).
3
3
  * Skips files that already exist (idempotent).
4
4
  */
5
- export declare function installPack(packName: string): {
5
+ export declare function installPack(packName: string, options?: {
6
+ projectDir?: string;
7
+ }): {
6
8
  installed: string[];
7
9
  skipped: string[];
8
10
  };
9
11
  /**
10
- * Remove a hook pack's files from ~/.claude/.
12
+ * Remove a hook pack's files from target directory.
11
13
  */
12
- export declare function removePack(packName: string): {
14
+ export declare function removePack(packName: string, options?: {
15
+ projectDir?: string;
16
+ }): {
13
17
  removed: string[];
14
18
  };
15
19
  /**
16
20
  * Check if a pack is installed.
17
21
  * Returns true (all hooks present), false (none present), or 'partial'.
18
22
  */
19
- export declare function isPackInstalled(packName: string): boolean | 'partial';
23
+ export declare function isPackInstalled(packName: string, options?: {
24
+ projectDir?: string;
25
+ }): boolean | 'partial';
26
+ /**
27
+ * Get the installed version of a hook from its file header.
28
+ * Returns null if no version found or file doesn't exist.
29
+ */
30
+ export declare function getInstalledHookVersion(hook: string, options?: {
31
+ projectDir?: string;
32
+ }): string | null;
@@ -1,10 +1,16 @@
1
1
  /**
2
- * Hook pack installer — copies hookify files to ~/.claude/ for global enforcement.
2
+ * Hook pack installer — copies hookify files to ~/.claude/ (global) or project .claude/ (local).
3
3
  */
4
- import { existsSync, copyFileSync, unlinkSync, mkdirSync } from 'node:fs';
4
+ import { existsSync, copyFileSync, unlinkSync, mkdirSync, readFileSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
6
  import { homedir } from 'node:os';
7
7
  import { getPack } from './registry.js';
8
+ /** Resolve the target .claude/ directory. */
9
+ function resolveClaudeDir(projectDir) {
10
+ if (projectDir)
11
+ return join(projectDir, '.claude');
12
+ return join(homedir(), '.claude');
13
+ }
8
14
  /**
9
15
  * Resolve all hookify file paths for a pack, handling composed packs.
10
16
  * Returns a map of hook name → source file path.
@@ -35,15 +41,15 @@ function resolveHookFiles(packName) {
35
41
  return files;
36
42
  }
37
43
  /**
38
- * Install a hook pack globally to ~/.claude/.
44
+ * Install a hook pack to ~/.claude/ (default) or project .claude/ (--project).
39
45
  * Skips files that already exist (idempotent).
40
46
  */
41
- export function installPack(packName) {
47
+ export function installPack(packName, options) {
42
48
  const pack = getPack(packName);
43
49
  if (!pack) {
44
50
  throw new Error(`Unknown hook pack: "${packName}"`);
45
51
  }
46
- const claudeDir = join(homedir(), '.claude');
52
+ const claudeDir = resolveClaudeDir(options?.projectDir);
47
53
  mkdirSync(claudeDir, { recursive: true });
48
54
  const hookFiles = resolveHookFiles(packName);
49
55
  const installed = [];
@@ -61,14 +67,14 @@ export function installPack(packName) {
61
67
  return { installed, skipped };
62
68
  }
63
69
  /**
64
- * Remove a hook pack's files from ~/.claude/.
70
+ * Remove a hook pack's files from target directory.
65
71
  */
66
- export function removePack(packName) {
72
+ export function removePack(packName, options) {
67
73
  const pack = getPack(packName);
68
74
  if (!pack) {
69
75
  throw new Error(`Unknown hook pack: "${packName}"`);
70
76
  }
71
- const claudeDir = join(homedir(), '.claude');
77
+ const claudeDir = resolveClaudeDir(options?.projectDir);
72
78
  const removed = [];
73
79
  for (const hook of pack.manifest.hooks) {
74
80
  const filePath = join(claudeDir, `hookify.${hook}.local.md`);
@@ -83,11 +89,11 @@ export function removePack(packName) {
83
89
  * Check if a pack is installed.
84
90
  * Returns true (all hooks present), false (none present), or 'partial'.
85
91
  */
86
- export function isPackInstalled(packName) {
92
+ export function isPackInstalled(packName, options) {
87
93
  const pack = getPack(packName);
88
94
  if (!pack)
89
95
  return false;
90
- const claudeDir = join(homedir(), '.claude');
96
+ const claudeDir = resolveClaudeDir(options?.projectDir);
91
97
  let present = 0;
92
98
  for (const hook of pack.manifest.hooks) {
93
99
  if (existsSync(join(claudeDir, `hookify.${hook}.local.md`))) {
@@ -100,4 +106,17 @@ export function isPackInstalled(packName) {
100
106
  return true;
101
107
  return 'partial';
102
108
  }
109
+ /**
110
+ * Get the installed version of a hook from its file header.
111
+ * Returns null if no version found or file doesn't exist.
112
+ */
113
+ export function getInstalledHookVersion(hook, options) {
114
+ const claudeDir = resolveClaudeDir(options?.projectDir);
115
+ const filePath = join(claudeDir, `hookify.${hook}.local.md`);
116
+ if (!existsSync(filePath))
117
+ return null;
118
+ const content = readFileSync(filePath, 'utf-8');
119
+ const match = content.match(/^# Version: (.+)$/m);
120
+ return match ? match[1] : null;
121
+ }
103
122
  //# sourceMappingURL=installer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/hook-packs/installer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/hook-packs/installer.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,17 @@
1
1
  /**
2
- * Hook pack installer — copies hookify files to ~/.claude/ for global enforcement.
2
+ * Hook pack installer — copies hookify files to ~/.claude/ (global) or project .claude/ (local).
3
3
  */
4
- import { existsSync, copyFileSync, unlinkSync, mkdirSync } from 'node:fs';
4
+ import { existsSync, copyFileSync, unlinkSync, mkdirSync, readFileSync } from 'node:fs';
5
5
  import { join } from 'node:path';
6
6
  import { homedir } from 'node:os';
7
7
  import { getPack } from './registry.js';
8
8
 
9
+ /** Resolve the target .claude/ directory. */
10
+ function resolveClaudeDir(projectDir?: string): string {
11
+ if (projectDir) return join(projectDir, '.claude');
12
+ return join(homedir(), '.claude');
13
+ }
14
+
9
15
  /**
10
16
  * Resolve all hookify file paths for a pack, handling composed packs.
11
17
  * Returns a map of hook name → source file path.
@@ -38,16 +44,19 @@ function resolveHookFiles(packName: string): Map<string, string> {
38
44
  }
39
45
 
40
46
  /**
41
- * Install a hook pack globally to ~/.claude/.
47
+ * Install a hook pack to ~/.claude/ (default) or project .claude/ (--project).
42
48
  * Skips files that already exist (idempotent).
43
49
  */
44
- export function installPack(packName: string): { installed: string[]; skipped: string[] } {
50
+ export function installPack(
51
+ packName: string,
52
+ options?: { projectDir?: string },
53
+ ): { installed: string[]; skipped: string[] } {
45
54
  const pack = getPack(packName);
46
55
  if (!pack) {
47
56
  throw new Error(`Unknown hook pack: "${packName}"`);
48
57
  }
49
58
 
50
- const claudeDir = join(homedir(), '.claude');
59
+ const claudeDir = resolveClaudeDir(options?.projectDir);
51
60
  mkdirSync(claudeDir, { recursive: true });
52
61
 
53
62
  const hookFiles = resolveHookFiles(packName);
@@ -68,15 +77,18 @@ export function installPack(packName: string): { installed: string[]; skipped: s
68
77
  }
69
78
 
70
79
  /**
71
- * Remove a hook pack's files from ~/.claude/.
80
+ * Remove a hook pack's files from target directory.
72
81
  */
73
- export function removePack(packName: string): { removed: string[] } {
82
+ export function removePack(
83
+ packName: string,
84
+ options?: { projectDir?: string },
85
+ ): { removed: string[] } {
74
86
  const pack = getPack(packName);
75
87
  if (!pack) {
76
88
  throw new Error(`Unknown hook pack: "${packName}"`);
77
89
  }
78
90
 
79
- const claudeDir = join(homedir(), '.claude');
91
+ const claudeDir = resolveClaudeDir(options?.projectDir);
80
92
  const removed: string[] = [];
81
93
 
82
94
  for (const hook of pack.manifest.hooks) {
@@ -94,11 +106,14 @@ export function removePack(packName: string): { removed: string[] } {
94
106
  * Check if a pack is installed.
95
107
  * Returns true (all hooks present), false (none present), or 'partial'.
96
108
  */
97
- export function isPackInstalled(packName: string): boolean | 'partial' {
109
+ export function isPackInstalled(
110
+ packName: string,
111
+ options?: { projectDir?: string },
112
+ ): boolean | 'partial' {
98
113
  const pack = getPack(packName);
99
114
  if (!pack) return false;
100
115
 
101
- const claudeDir = join(homedir(), '.claude');
116
+ const claudeDir = resolveClaudeDir(options?.projectDir);
102
117
  let present = 0;
103
118
 
104
119
  for (const hook of pack.manifest.hooks) {
@@ -111,3 +126,20 @@ export function isPackInstalled(packName: string): boolean | 'partial' {
111
126
  if (present === pack.manifest.hooks.length) return true;
112
127
  return 'partial';
113
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
+ }
@@ -3,13 +3,17 @@ export interface HookPackManifest {
3
3
  description: string;
4
4
  hooks: string[];
5
5
  composedFrom?: string[];
6
+ version?: string;
7
+ /** Whether this pack is built-in or user-defined */
8
+ source?: 'built-in' | 'local';
6
9
  }
7
10
  /**
8
- * List all available built-in hook packs.
11
+ * List all available hook packs (built-in + local custom).
12
+ * Local packs in .soleri/hook-packs/ override built-in packs with the same name.
9
13
  */
10
14
  export declare function listPacks(): HookPackManifest[];
11
15
  /**
12
- * Get a specific pack by name.
16
+ * Get a specific pack by name. Local packs take precedence.
13
17
  */
14
18
  export declare function getPack(name: string): {
15
19
  manifest: HookPackManifest;