@remcostoeten/use-shortcut 1.3.0 → 2.0.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.
@@ -1,35 +1,22 @@
1
1
  #!/usr/bin/env node
2
-
3
- // cli/index.ts
4
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5
- import { join, dirname } from "path";
6
- import { fileURLToPath } from "url";
7
-
8
- // cli/templates.ts
9
- function getArchitectureTemplates(framework) {
10
- const integrationSection = framework === "next" ? `## Next.js Integration
11
-
12
- 1. Create a client provider wrapper at \`app/shortcut-provider.tsx\` and render \`<ShortcutProvider />\` there.
13
- 2. Render that provider inside \`app/layout.tsx\` around your app shell.
14
- 3. Keep page/server components pure; shortcut handlers stay in client components.
15
- ` : `## React Integration
16
-
17
- 1. Wrap your app root (for example in \`main.tsx\`) with \`<ShortcutProvider />\`.
18
- 2. Keep handlers in a top-level client component and pass them to the provider via \`handlers\`.
19
- 3. Use \`useShortcutManager()\` inside feature components to toggle scopes and bindings.
20
- `;
21
- return {
22
- "scopes.ts": `export const shortcutScopes = ["global", "navigation", "editor", "modal"] as const
2
+ import{existsSync as h,mkdirSync as f,readFileSync as w,writeFileSync as x}from"fs";import{join as l,dirname as B}from"path";import{fileURLToPath as I}from"url";function m(t){return{"scopes.ts":`/** App-defined scope catalog used by the scaffolded provider. */
3
+ export const shortcutScopes = ["global", "navigation", "editor", "modal"] as const
23
4
 
24
5
  export type ShortcutScope = (typeof shortcutScopes)[number]
25
6
 
7
+ /** Default active scopes at provider boot. */
26
8
  export const defaultActiveScopes: ShortcutScope[] = ["global", "navigation"]
27
9
 
10
+ /**
11
+ * Normalizes a scope input into an array form.
12
+ *
13
+ * @param scopes - One or many scope names
14
+ * @returns Array of scope names
15
+ */
28
16
  export function normalizeScopes(scopes: ShortcutScope | ShortcutScope[]): ShortcutScope[] {
29
17
  return Array.isArray(scopes) ? scopes : [scopes]
30
18
  }
31
- `,
32
- "registry.ts": `import type { HandlerOptions } from "@remcostoeten/use-shortcut"
19
+ `,"registry.ts":`import type { HandlerOptions } from "@remcostoeten/use-shortcut"
33
20
  import type { ShortcutScope } from "./scopes"
34
21
 
35
22
  export type ShortcutDefinition = {
@@ -64,8 +51,7 @@ export const shortcutRegistry = {
64
51
 
65
52
  export type ShortcutActionId = keyof typeof shortcutRegistry
66
53
  export type ShortcutBindings = Record<ShortcutActionId, string | string[]>
67
- `,
68
- "types.ts": `import type { ShortcutActionId, ShortcutBindings } from "./registry"
54
+ `,"types.ts":`import type { ShortcutActionId, ShortcutBindings } from "./registry"
69
55
  import type { ShortcutScope } from "./scopes"
70
56
 
71
57
  export type ShortcutHandlers = Record<ShortcutActionId, (event: KeyboardEvent) => void>
@@ -96,12 +82,16 @@ export type ShortcutContextValue = {
96
82
  actions: ShortcutActions
97
83
  meta: ShortcutMeta
98
84
  }
99
- `,
100
- "runtime.ts": `import type { ShortcutMap } from "@remcostoeten/use-shortcut"
85
+ `,"runtime.ts":`import type { ShortcutMap } from "@remcostoeten/use-shortcut"
101
86
  import { shortcutRegistry, type ShortcutActionId, type ShortcutBindings } from "./registry"
102
87
  import type { ShortcutHandlers } from "./types"
103
88
 
104
- export function createDefaultBindings(): ShortcutBindings {
89
+ /**
90
+ * Returns a fresh binding object seeded from \`shortcutRegistry\` defaults.
91
+ *
92
+ * @returns Default shortcut bindings for every registered action
93
+ */
94
+ export function createDefaultShortcutBindings(): ShortcutBindings {
105
95
  const bindings = {} as ShortcutBindings
106
96
 
107
97
  for (const actionId of Object.keys(shortcutRegistry) as ShortcutActionId[]) {
@@ -111,7 +101,15 @@ export function createDefaultBindings(): ShortcutBindings {
111
101
  return bindings
112
102
  }
113
103
 
114
- export function createShortcutMap(bindings: ShortcutBindings, handlers: ShortcutHandlers): ShortcutMap {
104
+ /**
105
+ * Builds a \`ShortcutMap\` by combining current bindings with action handlers.
106
+ * Actions without handlers are skipped.
107
+ *
108
+ * @param bindings - Current binding state (defaults + user overrides)
109
+ * @param handlers - Runtime action handlers from the consuming app
110
+ * @returns Runtime shortcut map consumable by \`registerShortcutMap\`
111
+ */
112
+ export function buildShortcutMap(bindings: ShortcutBindings, handlers: ShortcutHandlers): ShortcutMap {
115
113
  const map: ShortcutMap = {}
116
114
 
117
115
  for (const actionId of Object.keys(shortcutRegistry) as ShortcutActionId[]) {
@@ -135,16 +133,22 @@ export function createShortcutMap(bindings: ShortcutBindings, handlers: Shortcut
135
133
 
136
134
  return map
137
135
  }
138
- `,
139
- "storage.ts": `import type { ShortcutActionId, ShortcutBindings } from "./registry"
136
+ `,"storage.ts":`import type { ShortcutActionId, ShortcutBindings } from "./registry"
140
137
 
138
+ /** Default localStorage key used by the scaffolded shortcut provider. */
141
139
  export const DEFAULT_SHORTCUT_STORAGE_KEY = "app-shortcut-bindings"
142
140
 
143
- function isBindingValue(value: unknown): value is string | string[] {
141
+ function _isBindingValue(value: unknown): value is string | string[] {
144
142
  if (typeof value === "string") return true
145
143
  return Array.isArray(value) && value.every((entry) => typeof entry === "string")
146
144
  }
147
145
 
146
+ /**
147
+ * Loads persisted shortcut binding overrides from localStorage.
148
+ *
149
+ * @param storageKey - Storage key namespace
150
+ * @returns Partial binding overrides keyed by action id
151
+ */
148
152
  export function loadShortcutBindings(storageKey: string): Partial<ShortcutBindings> {
149
153
  if (typeof window === "undefined") return {}
150
154
 
@@ -158,7 +162,7 @@ export function loadShortcutBindings(storageKey: string): Partial<ShortcutBindin
158
162
  const result: Partial<ShortcutBindings> = {}
159
163
 
160
164
  for (const [actionId, value] of Object.entries(parsed as Record<string, unknown>)) {
161
- if (!isBindingValue(value)) continue
165
+ if (!_isBindingValue(value)) continue
162
166
  result[actionId as ShortcutActionId] = value
163
167
  }
164
168
 
@@ -168,6 +172,12 @@ export function loadShortcutBindings(storageKey: string): Partial<ShortcutBindin
168
172
  }
169
173
  }
170
174
 
175
+ /**
176
+ * Persists all shortcut bindings to localStorage.
177
+ *
178
+ * @param storageKey - Storage key namespace
179
+ * @param bindings - Full current binding set
180
+ */
171
181
  export function saveShortcutBindings(storageKey: string, bindings: ShortcutBindings): void {
172
182
  if (typeof window === "undefined") return
173
183
 
@@ -178,6 +188,11 @@ export function saveShortcutBindings(storageKey: string, bindings: ShortcutBindi
178
188
  }
179
189
  }
180
190
 
191
+ /**
192
+ * Removes persisted shortcut bindings from localStorage.
193
+ *
194
+ * @param storageKey - Storage key namespace
195
+ */
181
196
  export function clearShortcutBindings(storageKey: string): void {
182
197
  if (typeof window === "undefined") return
183
198
 
@@ -187,8 +202,7 @@ export function clearShortcutBindings(storageKey: string): void {
187
202
  // Ignore quota/security errors.
188
203
  }
189
204
  }
190
- `,
191
- "provider.tsx": `"use client"
205
+ `,"provider.tsx":`"use client"
192
206
 
193
207
  import {
194
208
  createContext,
@@ -201,7 +215,7 @@ import {
201
215
  } from "react"
202
216
  import { registerShortcutMap, useShortcut, type UseShortcutOptions } from "@remcostoeten/use-shortcut"
203
217
  import { shortcutRegistry, type ShortcutActionId, type ShortcutBindings } from "./registry"
204
- import { createDefaultBindings, createShortcutMap } from "./runtime"
218
+ import { buildShortcutMap, createDefaultShortcutBindings } from "./runtime"
205
219
  import { defaultActiveScopes, normalizeScopes, type ShortcutScope } from "./scopes"
206
220
  import {
207
221
  DEFAULT_SHORTCUT_STORAGE_KEY,
@@ -211,9 +225,9 @@ import {
211
225
  } from "./storage"
212
226
  import type { ShortcutContextValue, ShortcutHandlers } from "./types"
213
227
 
214
- const ShortcutContext = createContext<ShortcutContextValue | null>(null)
228
+ const _ShortcutContext = createContext<ShortcutContextValue | null>(null)
215
229
 
216
- function mergeBindings(defaultBindings: ShortcutBindings, persisted: Partial<ShortcutBindings>): ShortcutBindings {
230
+ function _mergeBindings(defaultBindings: ShortcutBindings, persisted: Partial<ShortcutBindings>): ShortcutBindings {
217
231
  const merged = { ...defaultBindings }
218
232
 
219
233
  for (const actionId of Object.keys(defaultBindings) as ShortcutActionId[]) {
@@ -226,17 +240,17 @@ function mergeBindings(defaultBindings: ShortcutBindings, persisted: Partial<Sho
226
240
  return merged
227
241
  }
228
242
 
229
- function sameBinding(a: string | string[], b: string | string[]): boolean {
243
+ function _isSameBinding(a: string | string[], b: string | string[]): boolean {
230
244
  const left = Array.isArray(a) ? a.join("|") : a
231
245
  const right = Array.isArray(b) ? b.join("|") : b
232
246
  return left === right
233
247
  }
234
248
 
235
- function hasBindingOverrides(bindings: ShortcutBindings): boolean {
236
- const defaults = createDefaultBindings()
249
+ function _hasBindingOverrides(bindings: ShortcutBindings): boolean {
250
+ const defaults = createDefaultShortcutBindings()
237
251
 
238
252
  for (const actionId of Object.keys(defaults) as ShortcutActionId[]) {
239
- if (!sameBinding(bindings[actionId], defaults[actionId])) {
253
+ if (!_isSameBinding(bindings[actionId], defaults[actionId])) {
240
254
  return true
241
255
  }
242
256
  }
@@ -244,6 +258,7 @@ function hasBindingOverrides(bindings: ShortcutBindings): boolean {
244
258
  return false
245
259
  }
246
260
 
261
+ /** Props for the scaffolded \`ShortcutProvider\`. */
247
262
  export type ShortcutProviderProps = {
248
263
  children: ReactNode
249
264
  handlers: ShortcutHandlers
@@ -254,6 +269,9 @@ export type ShortcutProviderProps = {
254
269
  shortcutOptions?: Omit<UseShortcutOptions, "activeScopes" | "disabled">
255
270
  }
256
271
 
272
+ /**
273
+ * App-level provider that binds action handlers, scope state, and optional binding persistence.
274
+ */
257
275
  export function ShortcutProvider({
258
276
  children,
259
277
  handlers,
@@ -265,7 +283,7 @@ export function ShortcutProvider({
265
283
  }: ShortcutProviderProps) {
266
284
  const [activeScopes, setActiveScopes] = useState<ShortcutScope[]>(initialScopes)
267
285
  const [enabled, setEnabled] = useState(initialEnabled)
268
- const [bindings, setBindings] = useState<ShortcutBindings>(() => createDefaultBindings())
286
+ const [bindings, setBindings] = useState<ShortcutBindings>(() => createDefaultShortcutBindings())
269
287
 
270
288
  useEffect(() => {
271
289
  setEnabled(initialEnabled)
@@ -275,7 +293,7 @@ export function ShortcutProvider({
275
293
  if (!persistBindings) return
276
294
 
277
295
  const persisted = loadShortcutBindings(storageKey)
278
- setBindings((current) => mergeBindings(current, persisted))
296
+ setBindings((current) => _mergeBindings(current, persisted))
279
297
  }, [persistBindings, storageKey])
280
298
 
281
299
  useEffect(() => {
@@ -283,7 +301,7 @@ export function ShortcutProvider({
283
301
  saveShortcutBindings(storageKey, bindings)
284
302
  }, [bindings, persistBindings, storageKey])
285
303
 
286
- const shortcutMap = useMemo(() => createShortcutMap(bindings, handlers), [bindings, handlers])
304
+ const shortcutMap = useMemo(() => buildShortcutMap(bindings, handlers), [bindings, handlers])
287
305
 
288
306
  const $ = useShortcut({
289
307
  ...shortcutOptions,
@@ -331,7 +349,7 @@ export function ShortcutProvider({
331
349
  }, [])
332
350
 
333
351
  const resetBindings = useCallback(() => {
334
- setBindings(createDefaultBindings())
352
+ setBindings(createDefaultShortcutBindings())
335
353
  if (persistBindings) clearShortcutBindings(storageKey)
336
354
  }, [persistBindings, storageKey])
337
355
 
@@ -352,7 +370,7 @@ export function ShortcutProvider({
352
370
  setEnabled,
353
371
  },
354
372
  meta: {
355
- hasBindingOverrides: hasBindingOverrides(bindings),
373
+ hasBindingOverrides: _hasBindingOverrides(bindings),
356
374
  availableActions: Object.keys(shortcutRegistry) as ShortcutActionId[],
357
375
  },
358
376
  }),
@@ -369,11 +387,14 @@ export function ShortcutProvider({
369
387
  ],
370
388
  )
371
389
 
372
- return <ShortcutContext.Provider value={contextValue}>{children}</ShortcutContext.Provider>
390
+ return <_ShortcutContext.Provider value={contextValue}>{children}</_ShortcutContext.Provider>
373
391
  }
374
392
 
393
+ /**
394
+ * Reads the shortcut manager context exposed by \`ShortcutProvider\`.
395
+ */
375
396
  export function useShortcutManager(): ShortcutContextValue {
376
- const context = useContext(ShortcutContext)
397
+ const context = useContext(_ShortcutContext)
377
398
 
378
399
  if (!context) {
379
400
  throw new Error("useShortcutManager must be used within <ShortcutProvider>")
@@ -381,8 +402,7 @@ export function useShortcutManager(): ShortcutContextValue {
381
402
 
382
403
  return context
383
404
  }
384
- `,
385
- "index.ts": `export { ShortcutProvider, useShortcutManager, type ShortcutProviderProps } from "./provider"
405
+ `,"index.ts":`export { ShortcutProvider, useShortcutManager, type ShortcutProviderProps } from "./provider"
386
406
  export { shortcutRegistry, type ShortcutActionId, type ShortcutBindings } from "./registry"
387
407
  export { defaultActiveScopes, shortcutScopes, type ShortcutScope } from "./scopes"
388
408
  export type {
@@ -392,8 +412,7 @@ export type {
392
412
  ShortcutMeta,
393
413
  ShortcutState,
394
414
  } from "./types"
395
- `,
396
- "README.md": `# Shortcut Architecture Scaffold
415
+ `,"README.md":`# Shortcut Architecture Scaffold
397
416
 
398
417
  This folder was generated by \`use-shortcut scaffold\`.
399
418
 
@@ -412,172 +431,25 @@ It follows a scalable architecture with a strict split between:
412
431
  3. Optionally expose a user-configurable key in your settings UI through \`useShortcutManager().actions.setBinding\`.
413
432
  4. Activate scopes from feature boundaries (for example editor route enters \`editor\` scope).
414
433
 
415
- ${integrationSection}
434
+ ${t==="next"?"## Next.js Integration\n\n1. Create a client provider wrapper at `app/shortcut-provider.tsx` and render `<ShortcutProvider />` there.\n2. Render that provider inside `app/layout.tsx` around your app shell.\n3. Keep page/server components pure; shortcut handlers stay in client components.\n":"## React Integration\n\n1. Wrap your app root (for example in `main.tsx`) with `<ShortcutProvider />`.\n2. Keep handlers in a top-level client component and pass them to the provider via `handlers`.\n3. Use `useShortcutManager()` inside feature components to toggle scopes and bindings.\n"}
416
435
  ## Rules For Scale
417
436
 
418
437
  - Keep handlers side-effect focused and feature-owned; keep the registry declarative.
419
438
  - Use scopes instead of conditionals in handlers.
420
439
  - Persist only key bindings, not executable handlers.
421
440
  - Treat \`registry.ts\` as your architectural contract.
422
- `
423
- };
424
- }
425
-
426
- // cli/index.ts
427
- var __filename = fileURLToPath(import.meta.url);
428
- var __dirname = dirname(__filename);
429
- var COLORS = {
430
- reset: "\x1B[0m",
431
- green: "\x1B[32m",
432
- cyan: "\x1B[36m",
433
- yellow: "\x1B[33m",
434
- dim: "\x1B[2m",
435
- red: "\x1B[31m"
436
- };
437
- function log(message, color = COLORS.reset) {
438
- console.log(`${color}${message}${COLORS.reset}`);
439
- }
440
- function getSrcPath() {
441
- return join(__dirname, "..", "src");
442
- }
443
- function getCopyDestPath(targetDir) {
444
- return join(process.cwd(), targetDir, "use-shortcut");
445
- }
446
- function getScaffoldDestPath(targetDir, dir) {
447
- return join(process.cwd(), targetDir, dir);
448
- }
449
- function getFlagValue(args, flag, fallback) {
450
- const flagIndex = args.indexOf(flag);
451
- if (flagIndex === -1) return fallback;
452
- const value = args[flagIndex + 1];
453
- if (!value || value.startsWith("--")) return fallback;
454
- return value;
455
- }
456
- function hasFlag(args, flag) {
457
- return args.includes(flag);
458
- }
459
- var CORE_FILES = [
460
- "index.ts",
461
- "hook.ts",
462
- "builder.ts",
463
- "types.ts",
464
- "parser.ts",
465
- "constants.ts",
466
- "formatter.ts"
467
- ];
468
- function init(targetDir = "hooks", force = false) {
469
- const srcPath = getSrcPath();
470
- const destPath = getCopyDestPath(targetDir);
471
- log("\nuse-shortcut CLI\n", COLORS.cyan);
472
- if (existsSync(destPath) && !force) {
473
- log(`Directory already exists: ${destPath}`, COLORS.yellow);
474
- log("Use --force to overwrite existing files\n", COLORS.dim);
475
- return;
476
- }
477
- mkdirSync(destPath, { recursive: true });
478
- let written = 0;
479
- for (const file of CORE_FILES) {
480
- const srcFile = join(srcPath, file);
481
- const destFile = join(destPath, file);
482
- if (!existsSync(srcFile)) {
483
- log(`Source file not found: ${file}`, COLORS.yellow);
484
- continue;
485
- }
486
- const content = readFileSync(srcFile, "utf-8");
487
- writeFileSync(destFile, content);
488
- written += 1;
489
- log(` wrote ${file}`, COLORS.green);
490
- }
491
- log(`
492
- Copied ${written} files to:`, COLORS.green);
493
- log(` ${destPath}
494
- `, COLORS.dim);
495
- log("Usage:", COLORS.cyan);
496
- log(` import { useShortcut } from "@/${targetDir}/use-shortcut"`, COLORS.dim);
497
- log(" const $ = useShortcut()", COLORS.dim);
498
- log(' $.mod.key("k").on(() => console.log("Search"))\n', COLORS.dim);
499
- }
500
- function scaffoldArchitecture(framework, targetDir = "src", dir = "shortcuts", force = false) {
501
- const destPath = getScaffoldDestPath(targetDir, dir);
502
- const templates = getArchitectureTemplates(framework);
503
- log("\nuse-shortcut CLI\n", COLORS.cyan);
504
- log(`Scaffolding ${framework} architecture in ${destPath}
505
- `, COLORS.dim);
506
- mkdirSync(destPath, { recursive: true });
507
- let written = 0;
508
- let skipped = 0;
509
- for (const [file, content] of Object.entries(templates)) {
510
- const outputPath = join(destPath, file);
511
- if (existsSync(outputPath) && !force) {
512
- skipped += 1;
513
- log(` skipped ${file} (already exists)`, COLORS.yellow);
514
- continue;
515
- }
516
- writeFileSync(outputPath, content);
517
- written += 1;
518
- log(` wrote ${file}`, COLORS.green);
519
- }
520
- log("", COLORS.reset);
521
- log(`Architecture scaffold complete: ${written} written, ${skipped} skipped.`, COLORS.green);
522
- log(`Location: ${destPath}
523
- `, COLORS.dim);
524
- log("Next steps:", COLORS.cyan);
525
- log(` 1. Open ${join(targetDir, dir, "registry.ts")} and define your action catalog`, COLORS.dim);
526
- log(` 2. Wire app handlers into <ShortcutProvider handlers={...} />`, COLORS.dim);
527
- log(` 3. Toggle scopes from feature boundaries via useShortcutManager()`, COLORS.dim);
528
- log(` 4. Optionally expose setBinding/resetBinding in your settings UI
529
- `, COLORS.dim);
530
- }
531
- function printHelp() {
532
- log("\nuse-shortcut CLI\n", COLORS.cyan);
533
- log("Commands:", COLORS.yellow);
534
- log(" init [--target hooks] [--force]", COLORS.dim);
535
- log(" Copy source files into your project (shadcn-style).", COLORS.dim);
536
- log("", COLORS.dim);
537
- log(" scaffold [--framework next|react] [--target src] [--dir shortcuts] [--force]", COLORS.dim);
538
- log(" Generate a scalable app shortcut architecture.", COLORS.dim);
539
- log("", COLORS.dim);
540
- log(" init --architecture", COLORS.dim);
541
- log(" Alias for scaffold with defaults.\n", COLORS.dim);
542
- }
543
- function parseFramework(value) {
544
- if (value === "next" || value === "react") {
545
- return value;
546
- }
547
- log(`Invalid framework: ${value}. Expected "next" or "react".`, COLORS.red);
548
- process.exit(1);
549
- }
550
- function main() {
551
- const args = process.argv.slice(2);
552
- const command = args[0];
553
- const isHelp = !command || command === "--help" || command === "-h" || command === "help";
554
- if (isHelp) {
555
- printHelp();
556
- return;
557
- }
558
- if (command === "init") {
559
- if (hasFlag(args, "--architecture") || hasFlag(args, "--app") || hasFlag(args, "--scaffold")) {
560
- const framework = parseFramework(getFlagValue(args, "--framework", "next"));
561
- const targetDir2 = getFlagValue(args, "--target", "src");
562
- const dir = getFlagValue(args, "--dir", "shortcuts");
563
- const force2 = hasFlag(args, "--force");
564
- scaffoldArchitecture(framework, targetDir2, dir, force2);
565
- return;
566
- }
567
- const targetDir = getFlagValue(args, "--target", "hooks");
568
- const force = hasFlag(args, "--force");
569
- init(targetDir, force);
570
- return;
571
- }
572
- if (command === "scaffold" || command === "architecture") {
573
- const framework = parseFramework(getFlagValue(args, "--framework", "next"));
574
- const targetDir = getFlagValue(args, "--target", "src");
575
- const dir = getFlagValue(args, "--dir", "shortcuts");
576
- const force = hasFlag(args, "--force");
577
- scaffoldArchitecture(framework, targetDir, dir, force);
578
- return;
579
- }
580
- printHelp();
581
- process.exit(1);
582
- }
583
- main();
441
+ `}}var k=I(import.meta.url),_=B(k),e={reset:"\x1B[0m",green:"\x1B[32m",cyan:"\x1B[36m",yellow:"\x1B[33m",dim:"\x1B[2m",red:"\x1B[31m"};function r(t,o=e.reset){console.log(`${o}${t}${e.reset}`)}function O(){return l(_,"..","src")}function R(t){return l(process.cwd(),t,"use-shortcut")}function C(t,o){return l(process.cwd(),t,o)}function p(t,o,a){let s=t.indexOf(o);if(s===-1)return a;let n=t[s+1];return!n||n.startsWith("--")?a:n}function g(t,o){return t.includes(o)}var P=["index.ts","hook.ts","builder.ts","types.ts","parser.ts","constants.ts","formatter.ts","runtime/types.ts","runtime/binding.ts","runtime/conflicts.ts","runtime/debug.ts","runtime/guards.ts","runtime/keys.ts","runtime/listener.ts","runtime/recording.ts"];function E(t="hooks",o=!1){let a=O(),s=R(t);if(r(`
442
+ use-shortcut CLI
443
+ `,e.cyan),h(s)&&!o){r(`Directory already exists: ${s}`,e.yellow),r(`Use --force to overwrite existing files
444
+ `,e.dim);return}f(s,{recursive:!0});let n=0;for(let i of P){let c=l(a,i),d=l(s,i);if(f(B(d),{recursive:!0}),!h(c)){r(`Source file not found: ${i}`,e.yellow);continue}let u=w(c,"utf-8");x(d,u),n+=1,r(` wrote ${i}`,e.green)}r(`
445
+ Copied ${n} files to:`,e.green),r(` ${s}
446
+ `,e.dim),r("Usage:",e.cyan),r(` import { useShortcut } from "@/${t}/use-shortcut"`,e.dim),r(" const $ = useShortcut()",e.dim),r(` $.mod.key("k").on(() => console.log("Search"))
447
+ `,e.dim)}function y(t,o="src",a="shortcuts",s=!1){let n=C(o,a),i=m(t);r(`
448
+ use-shortcut CLI
449
+ `,e.cyan),r(`Scaffolding ${t} architecture in ${n}
450
+ `,e.dim),f(n,{recursive:!0});let c=0,d=0;for(let[u,A]of Object.entries(i)){let S=l(n,u);if(h(S)&&!s){d+=1,r(` skipped ${u} (already exists)`,e.yellow);continue}x(S,A),c+=1,r(` wrote ${u}`,e.green)}r("",e.reset),r(`Architecture scaffold complete: ${c} written, ${d} skipped.`,e.green),r(`Location: ${n}
451
+ `,e.dim),r("Next steps:",e.cyan),r(` 1. Open ${l(o,a,"registry.ts")} and define your action catalog`,e.dim),r(" 2. Wire app handlers into <ShortcutProvider handlers={...} />",e.dim),r(" 3. Toggle scopes from feature boundaries via useShortcutManager()",e.dim),r(` 4. Optionally expose setBinding/resetBinding in your settings UI
452
+ `,e.dim)}function b(){r(`
453
+ use-shortcut CLI
454
+ `,e.cyan),r("Commands:",e.yellow),r(" init [--target hooks] [--force]",e.dim),r(" Copy source files into your project (shadcn-style).",e.dim),r("",e.dim),r(" scaffold [--framework next|react] [--target src] [--dir shortcuts] [--force]",e.dim),r(" Generate a scalable app shortcut architecture.",e.dim),r("",e.dim),r(" init --architecture",e.dim),r(` Alias for scaffold with defaults.
455
+ `,e.dim)}function v(t){if(t==="next"||t==="react")return t;r(`Invalid framework: ${t}. Expected "next" or "react".`,e.red),process.exit(1)}function K(){let t=process.argv.slice(2),o=t[0];if(!o||o==="--help"||o==="-h"||o==="help"){b();return}if(o==="init"){if(g(t,"--architecture")||g(t,"--app")||g(t,"--scaffold")){let i=v(p(t,"--framework","next")),c=p(t,"--target","src"),d=p(t,"--dir","shortcuts"),u=g(t,"--force");y(i,c,d,u);return}let s=p(t,"--target","hooks"),n=g(t,"--force");E(s,n);return}if(o==="scaffold"||o==="architecture"){let s=v(p(t,"--framework","next")),n=p(t,"--target","src"),i=p(t,"--dir","shortcuts"),c=g(t,"--force");y(s,n,i,c);return}b(),process.exit(1)}K();