@soleri/cli 1.0.4 → 1.2.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 (44) hide show
  1. package/dist/commands/create.js +39 -4
  2. package/dist/commands/create.js.map +1 -1
  3. package/dist/commands/hooks.js +70 -1
  4. package/dist/commands/hooks.js.map +1 -1
  5. package/dist/hook-packs/a11y/hookify.focus-ring-required.local.md +20 -0
  6. package/dist/hook-packs/a11y/hookify.semantic-html.local.md +17 -0
  7. package/dist/hook-packs/a11y/hookify.ux-touch-targets.local.md +17 -0
  8. package/dist/hook-packs/a11y/manifest.json +5 -0
  9. package/dist/hook-packs/clean-commits/hookify.no-ai-attribution.local.md +17 -0
  10. package/dist/hook-packs/clean-commits/manifest.json +5 -0
  11. package/dist/hook-packs/css-discipline/hookify.no-important.local.md +17 -0
  12. package/dist/hook-packs/css-discipline/hookify.no-inline-styles.local.md +20 -0
  13. package/dist/hook-packs/css-discipline/manifest.json +5 -0
  14. package/dist/hook-packs/full/manifest.json +6 -0
  15. package/dist/hook-packs/installer.d.ts +19 -0
  16. package/dist/hook-packs/installer.js +103 -0
  17. package/dist/hook-packs/installer.js.map +1 -0
  18. package/dist/hook-packs/installer.ts +113 -0
  19. package/dist/hook-packs/registry.d.ts +21 -0
  20. package/dist/hook-packs/registry.js +69 -0
  21. package/dist/hook-packs/registry.js.map +1 -0
  22. package/dist/hook-packs/registry.ts +84 -0
  23. package/dist/hook-packs/typescript-safety/hookify.no-any-types.local.md +17 -0
  24. package/dist/hook-packs/typescript-safety/hookify.no-console-log.local.md +20 -0
  25. package/dist/hook-packs/typescript-safety/manifest.json +5 -0
  26. package/package.json +2 -2
  27. package/src/__tests__/hook-packs.test.ts +195 -0
  28. package/src/commands/create.ts +43 -3
  29. package/src/commands/hooks.ts +75 -1
  30. package/src/hook-packs/a11y/hookify.focus-ring-required.local.md +20 -0
  31. package/src/hook-packs/a11y/hookify.semantic-html.local.md +17 -0
  32. package/src/hook-packs/a11y/hookify.ux-touch-targets.local.md +17 -0
  33. package/src/hook-packs/a11y/manifest.json +5 -0
  34. package/src/hook-packs/clean-commits/hookify.no-ai-attribution.local.md +17 -0
  35. package/src/hook-packs/clean-commits/manifest.json +5 -0
  36. package/src/hook-packs/css-discipline/hookify.no-important.local.md +17 -0
  37. package/src/hook-packs/css-discipline/hookify.no-inline-styles.local.md +20 -0
  38. package/src/hook-packs/css-discipline/manifest.json +5 -0
  39. package/src/hook-packs/full/manifest.json +6 -0
  40. package/src/hook-packs/installer.ts +113 -0
  41. package/src/hook-packs/registry.ts +84 -0
  42. package/src/hook-packs/typescript-safety/hookify.no-any-types.local.md +17 -0
  43. package/src/hook-packs/typescript-safety/hookify.no-console-log.local.md +20 -0
  44. package/src/hook-packs/typescript-safety/manifest.json +5 -0
@@ -3,6 +3,8 @@ import { resolve } from 'node:path';
3
3
  import * as p from '@clack/prompts';
4
4
  import { previewScaffold, scaffold, AgentConfigSchema } from '@soleri/forge/lib';
5
5
  import { runCreateWizard } from '../prompts/create-wizard.js';
6
+ import { listPacks } from '../hook-packs/registry.js';
7
+ import { installPack } from '../hook-packs/installer.js';
6
8
  export function registerCreate(program) {
7
9
  program
8
10
  .command('create')
@@ -35,11 +37,32 @@ export function registerCreate(program) {
35
37
  return;
36
38
  }
37
39
  }
40
+ // Hook packs (interactive only)
41
+ let selectedPacks = [];
42
+ if (!opts?.config) {
43
+ const packs = listPacks();
44
+ const packChoices = packs.map((pk) => ({
45
+ value: pk.name,
46
+ label: pk.name,
47
+ hint: `${pk.description} (${pk.hooks.length} hooks)`,
48
+ }));
49
+ const chosen = await p.multiselect({
50
+ message: 'Install hook packs? (quality gates for ~/.claude/)',
51
+ options: packChoices,
52
+ required: false,
53
+ });
54
+ if (!p.isCancel(chosen)) {
55
+ selectedPacks = chosen;
56
+ }
57
+ }
38
58
  // Preview
39
59
  const preview = previewScaffold(config);
40
60
  p.log.info(`Will create ${preview.files.length} files in ${preview.agentDir}`);
41
61
  p.log.info(`Facades: ${preview.facades.map((f) => f.name).join(', ')}`);
42
62
  p.log.info(`Domains: ${preview.domains.join(', ')}`);
63
+ if (selectedPacks.length > 0) {
64
+ p.log.info(`Hook packs: ${selectedPacks.join(', ')}`);
65
+ }
43
66
  const confirmed = await p.confirm({ message: 'Create agent?' });
44
67
  if (p.isCancel(confirmed) || !confirmed) {
45
68
  p.outro('Cancelled.');
@@ -50,13 +73,25 @@ export function registerCreate(program) {
50
73
  s.start('Scaffolding agent...');
51
74
  const result = scaffold(config);
52
75
  s.stop(result.success ? 'Agent created!' : 'Scaffolding failed');
53
- if (result.success) {
54
- p.note(result.summary, 'Next steps');
55
- }
56
- else {
76
+ if (!result.success) {
57
77
  p.log.error(result.summary);
58
78
  process.exit(1);
59
79
  }
80
+ // Install selected hook packs
81
+ if (selectedPacks.length > 0) {
82
+ for (const packName of selectedPacks) {
83
+ const { installed } = installPack(packName);
84
+ if (installed.length > 0) {
85
+ p.log.success(`Hook pack "${packName}" installed (${installed.length} hooks)`);
86
+ }
87
+ else {
88
+ p.log.info(`Hook pack "${packName}" — all hooks already present`);
89
+ }
90
+ }
91
+ }
92
+ if (result.success) {
93
+ p.note(result.summary, 'Next steps');
94
+ }
60
95
  p.outro('Done!');
61
96
  }
62
97
  catch (err) {
@@ -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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"}
@@ -1,9 +1,11 @@
1
1
  import { SUPPORTED_EDITORS } from '../hooks/templates.js';
2
2
  import { installHooks, removeHooks, detectInstalledHooks } from '../hooks/generator.js';
3
3
  import { detectAgent } from '../utils/agent-context.js';
4
+ import { listPacks, getPack } from '../hook-packs/registry.js';
5
+ import { installPack, removePack, isPackInstalled } from '../hook-packs/installer.js';
4
6
  import * as log from '../utils/logger.js';
5
7
  export function registerHooks(program) {
6
- const hooks = program.command('hooks').description('Manage editor hooks for this agent');
8
+ const hooks = program.command('hooks').description('Manage editor hooks and hook packs');
7
9
  hooks
8
10
  .command('add')
9
11
  .argument('<editor>', `Editor: ${SUPPORTED_EDITORS.join(', ')}`)
@@ -69,6 +71,73 @@ export function registerHooks(program) {
69
71
  }
70
72
  }
71
73
  });
74
+ // ── Hook Pack subcommands ──
75
+ hooks
76
+ .command('add-pack')
77
+ .argument('<pack>', 'Hook pack name')
78
+ .description('Install a hook pack globally (~/.claude/)')
79
+ .action((packName) => {
80
+ const pack = getPack(packName);
81
+ if (!pack) {
82
+ const available = listPacks().map((p) => p.name);
83
+ log.fail(`Unknown pack "${packName}". Available: ${available.join(', ')}`);
84
+ process.exit(1);
85
+ }
86
+ const { installed, skipped } = installPack(packName);
87
+ for (const hook of installed) {
88
+ log.pass(`Installed hookify.${hook}.local.md`);
89
+ }
90
+ for (const hook of skipped) {
91
+ log.dim(` hookify.${hook}.local.md — already exists, skipped`);
92
+ }
93
+ if (installed.length > 0) {
94
+ log.info(`Pack "${packName}" installed (${installed.length} hooks)`);
95
+ }
96
+ else {
97
+ log.info(`Pack "${packName}" — all hooks already installed`);
98
+ }
99
+ });
100
+ hooks
101
+ .command('remove-pack')
102
+ .argument('<pack>', 'Hook pack name')
103
+ .description('Remove a hook pack from ~/.claude/')
104
+ .action((packName) => {
105
+ const pack = getPack(packName);
106
+ if (!pack) {
107
+ const available = listPacks().map((p) => p.name);
108
+ log.fail(`Unknown pack "${packName}". Available: ${available.join(', ')}`);
109
+ process.exit(1);
110
+ }
111
+ const { removed } = removePack(packName);
112
+ if (removed.length === 0) {
113
+ log.info(`No hooks from pack "${packName}" found to remove.`);
114
+ }
115
+ else {
116
+ for (const hook of removed) {
117
+ log.warn(`Removed hookify.${hook}.local.md`);
118
+ }
119
+ log.info(`Pack "${packName}" removed (${removed.length} hooks)`);
120
+ }
121
+ });
122
+ hooks
123
+ .command('list-packs')
124
+ .description('Show available hook packs and their status')
125
+ .action(() => {
126
+ const packs = listPacks();
127
+ log.heading('Hook Packs');
128
+ for (const pack of packs) {
129
+ const status = isPackInstalled(pack.name);
130
+ if (status === true) {
131
+ log.pass(`${pack.name}`, `${pack.description} (${pack.hooks.length} hooks)`);
132
+ }
133
+ else if (status === 'partial') {
134
+ log.warn(`${pack.name}`, `${pack.description} (${pack.hooks.length} hooks) — partial`);
135
+ }
136
+ else {
137
+ log.dim(` ${pack.name} — ${pack.description} (${pack.hooks.length} hooks)`);
138
+ }
139
+ }
140
+ });
72
141
  }
73
142
  function isValidEditor(editor) {
74
143
  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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"}
@@ -0,0 +1,20 @@
1
+ ---
2
+ # Soleri Hook Pack: a11y
3
+ # Rule: focus-ring-required
4
+ name: focus-ring-required
5
+ enabled: true
6
+ event: file
7
+ action: warn
8
+ conditions:
9
+ - field: file_path
10
+ operator: regex_match
11
+ pattern: src/components/ui/.*\.tsx$
12
+ - field: content
13
+ operator: regex_match
14
+ pattern: (<button|<Button|<a\s+href)
15
+ - field: content
16
+ operator: not_regex_match
17
+ pattern: (focus:ring|focus-visible:ring|focus:outline)
18
+ ---
19
+
20
+ ⚠️ **A11y:** Add focus ring for keyboard navigation: `focus:ring-2 focus:ring-accent focus:ring-offset-2`
@@ -0,0 +1,17 @@
1
+ ---
2
+ # Soleri Hook Pack: a11y
3
+ # Rule: semantic-html
4
+ name: semantic-html
5
+ enabled: true
6
+ event: file
7
+ action: warn
8
+ conditions:
9
+ - field: file_path
10
+ operator: regex_match
11
+ pattern: src/components/.*\.tsx$
12
+ - field: content
13
+ operator: regex_match
14
+ pattern: (<div\s+onClick(?!=)|<span\s+onClick(?!=))
15
+ ---
16
+
17
+ ⚠️ **A11y:** Use `<button>` instead of `<div onClick>`. Semantic HTML provides keyboard support.
@@ -0,0 +1,17 @@
1
+ ---
2
+ # Soleri Hook Pack: a11y
3
+ # Rule: ux-touch-targets
4
+ name: ux-touch-targets
5
+ enabled: true
6
+ event: file
7
+ action: warn
8
+ conditions:
9
+ - field: file_path
10
+ operator: regex_match
11
+ pattern: src/components/.*\.tsx$
12
+ - field: content
13
+ operator: regex_match
14
+ pattern: (<button[^>]*className="[^"]*(?:p-1|p-2|h-6|h-7|h-8|w-6|w-7|w-8)[^"]*"[^>]*>|className="[^"]*(?:p-1|p-2)[^"]*"[^>]*onClick)
15
+ ---
16
+
17
+ ⚠️ **Touch target too small.** Min 44x44px required. Add `min-h-11 min-w-11` to small interactive elements.
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "a11y",
3
+ "description": "Accessibility enforcement",
4
+ "hooks": ["semantic-html", "focus-ring-required", "ux-touch-targets"]
5
+ }
@@ -0,0 +1,17 @@
1
+ ---
2
+ # Soleri Hook Pack: clean-commits
3
+ # Rule: no-ai-attribution
4
+ name: no-ai-attribution
5
+ enabled: true
6
+ event: bash
7
+ action: block
8
+ conditions:
9
+ - field: command
10
+ operator: regex_match
11
+ pattern: git\s+commit.*(-m|--message)
12
+ - field: command
13
+ operator: regex_match
14
+ pattern: (🤖|Co-Authored-By|Generated with|AI-generated|by Claude|Claude Code|with Claude|noreply@anthropic\.com|Anthropic|Claude\s+(Opus|Sonnet|Haiku))
15
+ ---
16
+
17
+ 🚫 **AI attribution blocked.** Use clean conventional commits: `feat:`, `fix:`, `refactor:`. No 🤖, Claude, Co-Authored-By, or Anthropic references.
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "clean-commits",
3
+ "description": "No AI attribution in git commits",
4
+ "hooks": ["no-ai-attribution"]
5
+ }
@@ -0,0 +1,17 @@
1
+ ---
2
+ # Soleri Hook Pack: css-discipline
3
+ # Rule: no-important
4
+ name: no-important
5
+ enabled: true
6
+ event: file
7
+ action: block
8
+ conditions:
9
+ - field: file_path
10
+ operator: regex_match
11
+ pattern: \.(tsx?|jsx?|css)$
12
+ - field: content
13
+ operator: regex_match
14
+ pattern: "!important"
15
+ ---
16
+
17
+ 🚫 **!important blocked.** Fix specificity instead. Use Tailwind `!` prefix (`!text-error`) only if needed.
@@ -0,0 +1,20 @@
1
+ ---
2
+ # Soleri Hook Pack: css-discipline
3
+ # Rule: no-inline-styles
4
+ name: no-inline-styles
5
+ enabled: true
6
+ event: file
7
+ action: warn
8
+ conditions:
9
+ - field: file_path
10
+ operator: regex_match
11
+ pattern: src/components/.*\.tsx$
12
+ - field: file_path
13
+ operator: not_contains
14
+ pattern: .stories.tsx
15
+ - field: content
16
+ operator: regex_match
17
+ pattern: style=\{\{[^}]*(padding|margin|width|height|fontSize|color|background)[^}]*\}\}
18
+ ---
19
+
20
+ ⚠️ **Inline style detected.** Use Tailwind: `p-4` not `style={{ padding: '16px' }}`. Exception: CSS variables.
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "css-discipline",
3
+ "description": "CSS best practices",
4
+ "hooks": ["no-important", "no-inline-styles"]
5
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "full",
3
+ "description": "Complete quality suite — all 8 hooks",
4
+ "hooks": ["no-any-types", "no-console-log", "no-important", "no-inline-styles", "semantic-html", "focus-ring-required", "ux-touch-targets", "no-ai-attribution"],
5
+ "composedFrom": ["typescript-safety", "a11y", "css-discipline", "clean-commits"]
6
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Install a hook pack globally to ~/.claude/.
3
+ * Skips files that already exist (idempotent).
4
+ */
5
+ export declare function installPack(packName: string): {
6
+ installed: string[];
7
+ skipped: string[];
8
+ };
9
+ /**
10
+ * Remove a hook pack's files from ~/.claude/.
11
+ */
12
+ export declare function removePack(packName: string): {
13
+ removed: string[];
14
+ };
15
+ /**
16
+ * Check if a pack is installed.
17
+ * Returns true (all hooks present), false (none present), or 'partial'.
18
+ */
19
+ export declare function isPackInstalled(packName: string): boolean | 'partial';
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Hook pack installer — copies hookify files to ~/.claude/ for global enforcement.
3
+ */
4
+ import { existsSync, copyFileSync, unlinkSync, mkdirSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { homedir } from 'node:os';
7
+ import { getPack } from './registry.js';
8
+ /**
9
+ * Resolve all hookify file paths for a pack, handling composed packs.
10
+ * Returns a map of hook name → source file path.
11
+ */
12
+ function resolveHookFiles(packName) {
13
+ const pack = getPack(packName);
14
+ if (!pack)
15
+ return new Map();
16
+ const files = new Map();
17
+ if (pack.manifest.composedFrom) {
18
+ // Composed pack: gather files from constituent packs
19
+ for (const subPackName of pack.manifest.composedFrom) {
20
+ const subFiles = resolveHookFiles(subPackName);
21
+ for (const [hook, path] of subFiles) {
22
+ files.set(hook, path);
23
+ }
24
+ }
25
+ }
26
+ else {
27
+ // Direct pack: look for hookify files in the pack directory
28
+ for (const hook of pack.manifest.hooks) {
29
+ const filePath = join(pack.dir, `hookify.${hook}.local.md`);
30
+ if (existsSync(filePath)) {
31
+ files.set(hook, filePath);
32
+ }
33
+ }
34
+ }
35
+ return files;
36
+ }
37
+ /**
38
+ * Install a hook pack globally to ~/.claude/.
39
+ * Skips files that already exist (idempotent).
40
+ */
41
+ export function installPack(packName) {
42
+ const pack = getPack(packName);
43
+ if (!pack) {
44
+ throw new Error(`Unknown hook pack: "${packName}"`);
45
+ }
46
+ const claudeDir = join(homedir(), '.claude');
47
+ mkdirSync(claudeDir, { recursive: true });
48
+ const hookFiles = resolveHookFiles(packName);
49
+ const installed = [];
50
+ const skipped = [];
51
+ for (const [hook, sourcePath] of hookFiles) {
52
+ const destPath = join(claudeDir, `hookify.${hook}.local.md`);
53
+ if (existsSync(destPath)) {
54
+ skipped.push(hook);
55
+ }
56
+ else {
57
+ copyFileSync(sourcePath, destPath);
58
+ installed.push(hook);
59
+ }
60
+ }
61
+ return { installed, skipped };
62
+ }
63
+ /**
64
+ * Remove a hook pack's files from ~/.claude/.
65
+ */
66
+ export function removePack(packName) {
67
+ const pack = getPack(packName);
68
+ if (!pack) {
69
+ throw new Error(`Unknown hook pack: "${packName}"`);
70
+ }
71
+ const claudeDir = join(homedir(), '.claude');
72
+ const removed = [];
73
+ for (const hook of pack.manifest.hooks) {
74
+ const filePath = join(claudeDir, `hookify.${hook}.local.md`);
75
+ if (existsSync(filePath)) {
76
+ unlinkSync(filePath);
77
+ removed.push(hook);
78
+ }
79
+ }
80
+ return { removed };
81
+ }
82
+ /**
83
+ * Check if a pack is installed.
84
+ * Returns true (all hooks present), false (none present), or 'partial'.
85
+ */
86
+ export function isPackInstalled(packName) {
87
+ const pack = getPack(packName);
88
+ if (!pack)
89
+ return false;
90
+ const claudeDir = join(homedir(), '.claude');
91
+ let present = 0;
92
+ for (const hook of pack.manifest.hooks) {
93
+ if (existsSync(join(claudeDir, `hookify.${hook}.local.md`))) {
94
+ present++;
95
+ }
96
+ }
97
+ if (present === 0)
98
+ return false;
99
+ if (present === pack.manifest.hooks.length)
100
+ return true;
101
+ return 'partial';
102
+ }
103
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/hook-packs/installer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;;GAGG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAE5B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAExC,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QAC/B,qDAAqD;QACrD,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;YAC/C,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACpC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,4DAA4D;QAC5D,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,IAAI,WAAW,CAAC,CAAC;YAC5D,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7C,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,SAAS,EAAE,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,IAAI,WAAW,CAAC,CAAC;QAC7D,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACnC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,IAAI,WAAW,CAAC,CAAC;QAC7D,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,UAAU,CAAC,QAAQ,CAAC,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IAExB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACvC,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,IAAI,WAAW,CAAC,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,IAAI,OAAO,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAChC,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACxD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Hook pack installer — copies hookify files to ~/.claude/ for global enforcement.
3
+ */
4
+ import { existsSync, copyFileSync, unlinkSync, mkdirSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { homedir } from 'node:os';
7
+ import { getPack } from './registry.js';
8
+
9
+ /**
10
+ * Resolve all hookify file paths for a pack, handling composed packs.
11
+ * Returns a map of hook name → source file path.
12
+ */
13
+ function resolveHookFiles(packName: string): Map<string, string> {
14
+ const pack = getPack(packName);
15
+ if (!pack) return new Map();
16
+
17
+ const files = new Map<string, string>();
18
+
19
+ if (pack.manifest.composedFrom) {
20
+ // Composed pack: gather files from constituent packs
21
+ for (const subPackName of pack.manifest.composedFrom) {
22
+ const subFiles = resolveHookFiles(subPackName);
23
+ for (const [hook, path] of subFiles) {
24
+ files.set(hook, path);
25
+ }
26
+ }
27
+ } else {
28
+ // Direct pack: look for hookify files in the pack directory
29
+ for (const hook of pack.manifest.hooks) {
30
+ const filePath = join(pack.dir, `hookify.${hook}.local.md`);
31
+ if (existsSync(filePath)) {
32
+ files.set(hook, filePath);
33
+ }
34
+ }
35
+ }
36
+
37
+ return files;
38
+ }
39
+
40
+ /**
41
+ * Install a hook pack globally to ~/.claude/.
42
+ * Skips files that already exist (idempotent).
43
+ */
44
+ export function installPack(packName: string): { installed: string[]; skipped: string[] } {
45
+ const pack = getPack(packName);
46
+ if (!pack) {
47
+ throw new Error(`Unknown hook pack: "${packName}"`);
48
+ }
49
+
50
+ const claudeDir = join(homedir(), '.claude');
51
+ mkdirSync(claudeDir, { recursive: true });
52
+
53
+ const hookFiles = resolveHookFiles(packName);
54
+ const installed: string[] = [];
55
+ const skipped: string[] = [];
56
+
57
+ for (const [hook, sourcePath] of hookFiles) {
58
+ const destPath = join(claudeDir, `hookify.${hook}.local.md`);
59
+ if (existsSync(destPath)) {
60
+ skipped.push(hook);
61
+ } else {
62
+ copyFileSync(sourcePath, destPath);
63
+ installed.push(hook);
64
+ }
65
+ }
66
+
67
+ return { installed, skipped };
68
+ }
69
+
70
+ /**
71
+ * Remove a hook pack's files from ~/.claude/.
72
+ */
73
+ export function removePack(packName: string): { removed: string[] } {
74
+ const pack = getPack(packName);
75
+ if (!pack) {
76
+ throw new Error(`Unknown hook pack: "${packName}"`);
77
+ }
78
+
79
+ const claudeDir = join(homedir(), '.claude');
80
+ const removed: string[] = [];
81
+
82
+ for (const hook of pack.manifest.hooks) {
83
+ const filePath = join(claudeDir, `hookify.${hook}.local.md`);
84
+ if (existsSync(filePath)) {
85
+ unlinkSync(filePath);
86
+ removed.push(hook);
87
+ }
88
+ }
89
+
90
+ return { removed };
91
+ }
92
+
93
+ /**
94
+ * Check if a pack is installed.
95
+ * Returns true (all hooks present), false (none present), or 'partial'.
96
+ */
97
+ export function isPackInstalled(packName: string): boolean | 'partial' {
98
+ const pack = getPack(packName);
99
+ if (!pack) return false;
100
+
101
+ const claudeDir = join(homedir(), '.claude');
102
+ let present = 0;
103
+
104
+ for (const hook of pack.manifest.hooks) {
105
+ if (existsSync(join(claudeDir, `hookify.${hook}.local.md`))) {
106
+ present++;
107
+ }
108
+ }
109
+
110
+ if (present === 0) return false;
111
+ if (present === pack.manifest.hooks.length) return true;
112
+ return 'partial';
113
+ }
@@ -0,0 +1,21 @@
1
+ export interface HookPackManifest {
2
+ name: string;
3
+ description: string;
4
+ hooks: string[];
5
+ composedFrom?: string[];
6
+ }
7
+ /**
8
+ * List all available built-in hook packs.
9
+ */
10
+ export declare function listPacks(): HookPackManifest[];
11
+ /**
12
+ * Get a specific pack by name.
13
+ */
14
+ export declare function getPack(name: string): {
15
+ manifest: HookPackManifest;
16
+ dir: string;
17
+ } | null;
18
+ /**
19
+ * Get names of packs that are fully installed in ~/.claude/.
20
+ */
21
+ export declare function getInstalledPacks(): string[];