hookstack-cli 0.1.15 → 0.1.17
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.
- package/bin/cli.mjs +10 -5
- package/bin/core.mjs +11 -7
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -151,10 +151,13 @@ async function interactiveInstall(slugs, args) {
|
|
|
151
151
|
// Scope selection
|
|
152
152
|
let scope = args.scope
|
|
153
153
|
console.log('\n Where to install?')
|
|
154
|
-
console.log(` ${pc.cyan('1')} This project
|
|
155
|
-
console.log(` ${pc.cyan('2')} All my projects
|
|
156
|
-
|
|
154
|
+
console.log(` ${pc.cyan('1')} This project ${pc.dim('./.claude — committed with your repo')}`)
|
|
155
|
+
console.log(` ${pc.cyan('2')} All my projects ${pc.dim('~/.claude — every project on this machine')}`)
|
|
156
|
+
console.log(` ${pc.cyan('3')} This GitHub Copilot project ${pc.dim('./.claude — settings.json adapted, committed with your repo')}`)
|
|
157
|
+
const defaultChoice = scope === 'global' ? '2' : scope === 'copilot' ? '3' : '1'
|
|
158
|
+
const scopeAnswer = await ask(` → [${defaultChoice}]: `)
|
|
157
159
|
if (scopeAnswer === '2' || scopeAnswer === 'global') scope = 'global'
|
|
160
|
+
else if (scopeAnswer === '3' || scopeAnswer === 'copilot') scope = 'copilot'
|
|
158
161
|
else if (scopeAnswer === 'q') { console.log('Cancelled.'); process.exit(0) }
|
|
159
162
|
else scope = 'project'
|
|
160
163
|
|
|
@@ -165,7 +168,8 @@ async function interactiveInstall(slugs, args) {
|
|
|
165
168
|
console.log(`\n ${pc.bold('Security')}`)
|
|
166
169
|
console.log(securityPanel(buildSecurityRows(hooks)))
|
|
167
170
|
|
|
168
|
-
const
|
|
171
|
+
const scopeLabel = scope === 'global' ? '~/.claude' : scope === 'copilot' ? './.claude (GitHub Copilot mode)' : './.claude'
|
|
172
|
+
const confirmAnswer = await ask(`\n Install ${plural(hooks.length, 'hook')} into ${scopeLabel}? [Y/n]: `)
|
|
169
173
|
if (confirmAnswer.toLowerCase() === 'n' || confirmAnswer.toLowerCase() === 'no') {
|
|
170
174
|
console.log('Cancelled.')
|
|
171
175
|
process.exit(0)
|
|
@@ -221,7 +225,8 @@ const HELP = `
|
|
|
221
225
|
Options:
|
|
222
226
|
--hooks <slugs> Comma-separated list of hook slugs (omit for default set)
|
|
223
227
|
--global, -g Install into ~/.claude instead of ./.claude
|
|
224
|
-
--
|
|
228
|
+
--copilot Install into ./.claude with paths adapted for GitHub Copilot
|
|
229
|
+
--scope <s> "project" (default), "global", or "copilot"
|
|
225
230
|
--yes, -y Skip prompts (non-interactive install)
|
|
226
231
|
--version, -v Show version
|
|
227
232
|
--help, -h Show this help
|
package/bin/core.mjs
CHANGED
|
@@ -36,6 +36,7 @@ export function parseArgs(argv) {
|
|
|
36
36
|
if (arg === '--yes' || arg === '-y') { result.yes = true; continue }
|
|
37
37
|
if (arg === '--global' || arg === '-g') { result.scope = 'global'; continue }
|
|
38
38
|
if (arg === '--project') { result.scope = 'project'; continue }
|
|
39
|
+
if (arg === '--copilot') { result.scope = 'copilot'; continue }
|
|
39
40
|
if (arg.startsWith('--scope=')) {
|
|
40
41
|
const v = arg.slice('--scope='.length)
|
|
41
42
|
if (v === 'global' || v === 'project') result.scope = v
|
|
@@ -98,7 +99,8 @@ export function mergeHooks(existing, incoming) {
|
|
|
98
99
|
|
|
99
100
|
// Gathers the hook fragments from an API hook list into a single event→entries
|
|
100
101
|
// map. For global scope, rewrites $CLAUDE_PROJECT_DIR to the absolute global
|
|
101
|
-
// root so commands resolve outside any project.
|
|
102
|
+
// root so commands resolve outside any project. For copilot scope, strips
|
|
103
|
+
// $CLAUDE_PROJECT_DIR/ so paths become relative (GitHub Copilot compatible).
|
|
102
104
|
export function collectIncomingHooks(hooks, { scope = 'project', globalRoot } = {}) {
|
|
103
105
|
const incoming = {}
|
|
104
106
|
for (const hook of hooks) {
|
|
@@ -107,14 +109,16 @@ export function collectIncomingHooks(hooks, { scope = 'project', globalRoot } =
|
|
|
107
109
|
for (const [event, entries] of Object.entries(fragment)) {
|
|
108
110
|
incoming[event] ??= []
|
|
109
111
|
for (const entry of entries) {
|
|
110
|
-
const rewrite = scope === 'global' && globalRoot
|
|
111
112
|
incoming[event].push({
|
|
112
113
|
...entry,
|
|
113
|
-
hooks: entry.hooks.map(h =>
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
: h,
|
|
117
|
-
|
|
114
|
+
hooks: entry.hooks.map(h => {
|
|
115
|
+
if (!h.command || typeof h.command !== 'string') return h
|
|
116
|
+
if (scope === 'global' && globalRoot)
|
|
117
|
+
return { ...h, command: h.command.replace(PROJECT_DIR_RE, globalRoot) }
|
|
118
|
+
if (scope === 'copilot')
|
|
119
|
+
return { ...h, command: h.command.replace(/\$\{?CLAUDE_PROJECT_DIR\}?\//g, '') }
|
|
120
|
+
return h
|
|
121
|
+
}),
|
|
118
122
|
})
|
|
119
123
|
}
|
|
120
124
|
}
|