specweave 1.0.551 → 1.0.552

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 (132) hide show
  1. package/bin/specweave.js +23 -1
  2. package/dist/src/cli/commands/hook.d.ts +15 -0
  3. package/dist/src/cli/commands/hook.d.ts.map +1 -0
  4. package/dist/src/cli/commands/hook.js +61 -0
  5. package/dist/src/cli/commands/hook.js.map +1 -0
  6. package/dist/src/config/types.d.ts +2 -2
  7. package/dist/src/core/hooks/handlers/hook-router.d.ts +19 -0
  8. package/dist/src/core/hooks/handlers/hook-router.d.ts.map +1 -0
  9. package/dist/src/core/hooks/handlers/hook-router.js +75 -0
  10. package/dist/src/core/hooks/handlers/hook-router.js.map +1 -0
  11. package/dist/src/core/hooks/handlers/index.d.ts +10 -0
  12. package/dist/src/core/hooks/handlers/index.d.ts.map +1 -0
  13. package/dist/src/core/hooks/handlers/index.js +9 -0
  14. package/dist/src/core/hooks/handlers/index.js.map +1 -0
  15. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts +11 -0
  16. package/dist/src/core/hooks/handlers/post-tool-use-analytics.d.ts.map +1 -0
  17. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js +73 -0
  18. package/dist/src/core/hooks/handlers/post-tool-use-analytics.js.map +1 -0
  19. package/dist/src/core/hooks/handlers/post-tool-use.d.ts +11 -0
  20. package/dist/src/core/hooks/handlers/post-tool-use.d.ts.map +1 -0
  21. package/dist/src/core/hooks/handlers/post-tool-use.js +76 -0
  22. package/dist/src/core/hooks/handlers/post-tool-use.js.map +1 -0
  23. package/dist/src/core/hooks/handlers/pre-compact.d.ts +11 -0
  24. package/dist/src/core/hooks/handlers/pre-compact.d.ts.map +1 -0
  25. package/dist/src/core/hooks/handlers/pre-compact.js +77 -0
  26. package/dist/src/core/hooks/handlers/pre-compact.js.map +1 -0
  27. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts +11 -0
  28. package/dist/src/core/hooks/handlers/pre-tool-use.d.ts.map +1 -0
  29. package/dist/src/core/hooks/handlers/pre-tool-use.js +318 -0
  30. package/dist/src/core/hooks/handlers/pre-tool-use.js.map +1 -0
  31. package/dist/src/core/hooks/handlers/session-start.d.ts +9 -0
  32. package/dist/src/core/hooks/handlers/session-start.d.ts.map +1 -0
  33. package/dist/src/core/hooks/handlers/session-start.js +111 -0
  34. package/dist/src/core/hooks/handlers/session-start.js.map +1 -0
  35. package/dist/src/core/hooks/handlers/stop-auto.d.ts +16 -0
  36. package/dist/src/core/hooks/handlers/stop-auto.d.ts.map +1 -0
  37. package/dist/src/core/hooks/handlers/stop-auto.js +122 -0
  38. package/dist/src/core/hooks/handlers/stop-auto.js.map +1 -0
  39. package/dist/src/core/hooks/handlers/stop-reflect.d.ts +14 -0
  40. package/dist/src/core/hooks/handlers/stop-reflect.d.ts.map +1 -0
  41. package/dist/src/core/hooks/handlers/stop-reflect.js +43 -0
  42. package/dist/src/core/hooks/handlers/stop-reflect.js.map +1 -0
  43. package/dist/src/core/hooks/handlers/stop-sync.d.ts +15 -0
  44. package/dist/src/core/hooks/handlers/stop-sync.d.ts.map +1 -0
  45. package/dist/src/core/hooks/handlers/stop-sync.js +68 -0
  46. package/dist/src/core/hooks/handlers/stop-sync.js.map +1 -0
  47. package/dist/src/core/hooks/handlers/types.d.ts +63 -0
  48. package/dist/src/core/hooks/handlers/types.d.ts.map +1 -0
  49. package/dist/src/core/hooks/handlers/types.js +27 -0
  50. package/dist/src/core/hooks/handlers/types.js.map +1 -0
  51. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts +14 -0
  52. package/dist/src/core/hooks/handlers/user-prompt-submit.d.ts.map +1 -0
  53. package/dist/src/core/hooks/handlers/user-prompt-submit.js +173 -0
  54. package/dist/src/core/hooks/handlers/user-prompt-submit.js.map +1 -0
  55. package/dist/src/core/hooks/handlers/utils.d.ts +25 -0
  56. package/dist/src/core/hooks/handlers/utils.d.ts.map +1 -0
  57. package/dist/src/core/hooks/handlers/utils.js +64 -0
  58. package/dist/src/core/hooks/handlers/utils.js.map +1 -0
  59. package/dist/src/init/research/types.d.ts +1 -1
  60. package/dist/src/sync/sync-target-resolver.js.map +1 -1
  61. package/dist/src/utils/lock-manager.d.ts.map +1 -1
  62. package/dist/src/utils/lock-manager.js +5 -0
  63. package/dist/src/utils/lock-manager.js.map +1 -1
  64. package/dist/src/utils/plugin-copier.d.ts.map +1 -1
  65. package/dist/src/utils/plugin-copier.js +3 -30
  66. package/dist/src/utils/plugin-copier.js.map +1 -1
  67. package/package.json +1 -1
  68. package/plugins/specweave/hooks/hooks.json +10 -10
  69. package/plugins/specweave/hooks/README.md +0 -493
  70. package/plugins/specweave/hooks/_archive/stop-auto-v4-legacy.sh +0 -1319
  71. package/plugins/specweave/hooks/lib/common-setup.sh +0 -144
  72. package/plugins/specweave/hooks/lib/hook-errors.sh +0 -414
  73. package/plugins/specweave/hooks/lib/migrate-increment-work.sh +0 -245
  74. package/plugins/specweave/hooks/lib/resolve-package.sh +0 -146
  75. package/plugins/specweave/hooks/lib/scheduler-startup.sh +0 -135
  76. package/plugins/specweave/hooks/lib/score-increment.sh +0 -87
  77. package/plugins/specweave/hooks/lib/sync-spec-content.sh +0 -193
  78. package/plugins/specweave/hooks/lib/update-active-increment.sh +0 -95
  79. package/plugins/specweave/hooks/lib/update-status-line.sh +0 -233
  80. package/plugins/specweave/hooks/lib/validate-spec-status.sh +0 -171
  81. package/plugins/specweave/hooks/llm-judge-validator.sh +0 -219
  82. package/plugins/specweave/hooks/log-decision.sh +0 -168
  83. package/plugins/specweave/hooks/pre-compact.sh +0 -64
  84. package/plugins/specweave/hooks/startup-health-check.sh +0 -64
  85. package/plugins/specweave/hooks/stop-auto-v5.sh +0 -276
  86. package/plugins/specweave/hooks/stop-reflect.sh +0 -336
  87. package/plugins/specweave/hooks/stop-sync.sh +0 -283
  88. package/plugins/specweave/hooks/tests/test-auto-context-integration.sh +0 -126
  89. package/plugins/specweave/hooks/tests/test-stop-auto-enriched.sh +0 -128
  90. package/plugins/specweave/hooks/universal/dispatcher.mjs +0 -336
  91. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +0 -325
  92. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +0 -26
  93. package/plugins/specweave/hooks/universal/hook-wrapper.sh +0 -69
  94. package/plugins/specweave/hooks/universal/run-hook.sh +0 -20
  95. package/plugins/specweave/hooks/universal/session-start.cmd +0 -16
  96. package/plugins/specweave/hooks/universal/session-start.ps1 +0 -16
  97. package/plugins/specweave/hooks/user-prompt-submit.sh +0 -2550
  98. package/plugins/specweave/hooks/v2/detectors/lifecycle-detector.sh +0 -87
  99. package/plugins/specweave/hooks/v2/detectors/us-completion-detector.sh +0 -186
  100. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use-analytics.sh +0 -83
  101. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +0 -447
  102. package/plugins/specweave/hooks/v2/dispatchers/pre-tool-use.sh +0 -104
  103. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +0 -270
  104. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +0 -14
  105. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +0 -14
  106. package/plugins/specweave/hooks/v2/guards/increment-existence-guard.sh +0 -240
  107. package/plugins/specweave/hooks/v2/guards/interview-enforcement-guard.sh +0 -171
  108. package/plugins/specweave/hooks/v2/guards/metadata-json-guard.sh +0 -14
  109. package/plugins/specweave/hooks/v2/guards/skill-chain-enforcement-guard.sh +0 -222
  110. package/plugins/specweave/hooks/v2/guards/spec-template-enforcement-guard.sh +0 -21
  111. package/plugins/specweave/hooks/v2/guards/spec-validation-guard.sh +0 -14
  112. package/plugins/specweave/hooks/v2/guards/status-completion-guard.sh +0 -84
  113. package/plugins/specweave/hooks/v2/guards/task-ac-sync-guard.sh +0 -475
  114. package/plugins/specweave/hooks/v2/guards/tdd-enforcement-guard.sh +0 -268
  115. package/plugins/specweave/hooks/v2/handlers/ac-sync-dispatcher.sh +0 -332
  116. package/plugins/specweave/hooks/v2/handlers/ac-validation-handler.sh +0 -50
  117. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +0 -347
  118. package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +0 -83
  119. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +0 -268
  120. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +0 -104
  121. package/plugins/specweave/hooks/v2/handlers/status-line-handler.sh +0 -165
  122. package/plugins/specweave/hooks/v2/handlers/status-update.sh +0 -61
  123. package/plugins/specweave/hooks/v2/handlers/universal-auto-create-dispatcher.sh +0 -270
  124. package/plugins/specweave/hooks/v2/integrations/ado-post-living-docs-update.sh +0 -367
  125. package/plugins/specweave/hooks/v2/integrations/ado-post-task.sh +0 -179
  126. package/plugins/specweave/hooks/v2/integrations/github-auto-create-handler.sh +0 -553
  127. package/plugins/specweave/hooks/v2/integrations/github-post-task.sh +0 -345
  128. package/plugins/specweave/hooks/v2/integrations/jira-post-task.sh +0 -180
  129. package/plugins/specweave/hooks/v2/lib/check-provider-enabled.sh +0 -52
  130. package/plugins/specweave/hooks/v2/queue/enqueue.sh +0 -81
  131. package/plugins/specweave/hooks/v2/session-end.sh +0 -139
  132. package/plugins/specweave/hooks/validate-skill-activations.sh +0 -227
package/bin/specweave.js CHANGED
@@ -1244,6 +1244,28 @@ program
1244
1244
  }
1245
1245
  });
1246
1246
 
1247
+ // Hook command - CLI delegation entry point for Claude Code hooks (internal)
1248
+ program
1249
+ .command('hook <event-type>')
1250
+ .description('Handle Claude Code hook events (internal)')
1251
+ .action(async (eventType) => {
1252
+ try {
1253
+ const { handleHook } = await import('../dist/src/cli/commands/hook.js');
1254
+ await handleHook(eventType);
1255
+ } catch {
1256
+ // Never crash — output safe default
1257
+ const defaults = {
1258
+ 'user-prompt-submit': '{"decision":"approve"}',
1259
+ 'pre-tool-use': '{"decision":"allow"}',
1260
+ 'stop-reflect': '{"decision":"approve"}',
1261
+ 'stop-auto': '{"decision":"approve"}',
1262
+ 'stop-sync': '{"decision":"approve"}',
1263
+ };
1264
+ process.stdout.write(defaults[eventType] || '{"continue":true}');
1265
+ }
1266
+ process.exit(0);
1267
+ });
1268
+
1247
1269
  // Detect intent command - Hook helper for automatic plugin loading (internal)
1248
1270
  program
1249
1271
  .command('detect-intent [prompt]')
@@ -1556,7 +1578,7 @@ program
1556
1578
  await checkForDuplicates();
1557
1579
 
1558
1580
  // Hide internal-only commands from --help (still callable by hooks)
1559
- for (const name of ['detect-intent', 'evaluate-completion', 'reflect-stop', 'detect-project']) {
1581
+ for (const name of ['hook', 'detect-intent', 'evaluate-completion', 'reflect-stop', 'detect-project']) {
1560
1582
  const cmd = program.commands.find(c => c.name() === name);
1561
1583
  if (cmd) cmd._hidden = true;
1562
1584
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Hook CLI Command — entry point for Claude Code hook delegation.
3
+ *
4
+ * Usage: specweave hook <event-type>
5
+ *
6
+ * Reads JSON from stdin, dispatches to the correct handler via hook-router,
7
+ * writes JSON to stdout. Always exits 0 — never crashes Claude Code.
8
+ *
9
+ * @module cli/commands/hook
10
+ */
11
+ /**
12
+ * Main hook handler entry point.
13
+ */
14
+ export declare function handleHook(eventType: string): Promise<void>;
15
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsCH;;GAEG;AACH,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjE"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Hook CLI Command — entry point for Claude Code hook delegation.
3
+ *
4
+ * Usage: specweave hook <event-type>
5
+ *
6
+ * Reads JSON from stdin, dispatches to the correct handler via hook-router,
7
+ * writes JSON to stdout. Always exits 0 — never crashes Claude Code.
8
+ *
9
+ * @module cli/commands/hook
10
+ */
11
+ import { hookRouter } from '../../core/hooks/handlers/hook-router.js';
12
+ import { getSafeDefault } from '../../core/hooks/handlers/types.js';
13
+ /**
14
+ * Read all of stdin as a string.
15
+ */
16
+ async function readStdin() {
17
+ return new Promise((resolve) => {
18
+ const chunks = [];
19
+ const timeout = setTimeout(() => {
20
+ process.stdin.removeAllListeners();
21
+ resolve(Buffer.concat(chunks).toString('utf-8'));
22
+ }, 5000);
23
+ process.stdin.on('data', (chunk) => {
24
+ chunks.push(chunk);
25
+ });
26
+ process.stdin.on('end', () => {
27
+ clearTimeout(timeout);
28
+ resolve(Buffer.concat(chunks).toString('utf-8'));
29
+ });
30
+ process.stdin.on('error', () => {
31
+ clearTimeout(timeout);
32
+ resolve('');
33
+ });
34
+ // If stdin is already ended (no pipe), resolve immediately
35
+ if (process.stdin.readableEnded) {
36
+ clearTimeout(timeout);
37
+ resolve(Buffer.concat(chunks).toString('utf-8'));
38
+ }
39
+ });
40
+ }
41
+ /**
42
+ * Main hook handler entry point.
43
+ */
44
+ export async function handleHook(eventType) {
45
+ // Crash prevention
46
+ process.on('unhandledRejection', () => {
47
+ const fallback = getSafeDefault(eventType);
48
+ process.stdout.write(JSON.stringify(fallback));
49
+ process.exit(0);
50
+ });
51
+ try {
52
+ const rawStdin = await readStdin();
53
+ const result = await hookRouter(eventType, rawStdin);
54
+ process.stdout.write(JSON.stringify(result));
55
+ }
56
+ catch {
57
+ const fallback = getSafeDefault(eventType);
58
+ process.stdout.write(JSON.stringify(fallback));
59
+ }
60
+ }
61
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../../../../src/cli/commands/hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEpE;;GAEG;AACH,KAAK,UAAU,SAAS;IACtB,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC;YACnC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YAC3B,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC7B,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,CAAC,EAAE,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,2DAA2D;QAC3D,IAAI,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YAChC,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB;IAChD,mBAAmB;IACnB,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,QAAQ,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC;AACH,CAAC"}
@@ -19,12 +19,12 @@ export declare const ResearchConfigSchema: z.ZodObject<{
19
19
  iot: "iot";
20
20
  gaming: "gaming";
21
21
  marketplace: "marketplace";
22
+ blockchain: "blockchain";
22
23
  "productivity-saas": "productivity-saas";
23
24
  "e-commerce": "e-commerce";
24
25
  "social-network": "social-network";
25
26
  "enterprise-b2b": "enterprise-b2b";
26
27
  "consumer-b2c": "consumer-b2c";
27
- blockchain: "blockchain";
28
28
  "ai-ml": "ai-ml";
29
29
  }>;
30
30
  competitors: z.ZodArray<z.ZodObject<{
@@ -190,12 +190,12 @@ export declare const SpecWeaveConfigSchema: z.ZodObject<{
190
190
  iot: "iot";
191
191
  gaming: "gaming";
192
192
  marketplace: "marketplace";
193
+ blockchain: "blockchain";
193
194
  "productivity-saas": "productivity-saas";
194
195
  "e-commerce": "e-commerce";
195
196
  "social-network": "social-network";
196
197
  "enterprise-b2b": "enterprise-b2b";
197
198
  "consumer-b2c": "consumer-b2c";
198
- blockchain: "blockchain";
199
199
  "ai-ml": "ai-ml";
200
200
  }>;
201
201
  competitors: z.ZodArray<z.ZodObject<{
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Hook router — the central dispatcher for all hook events.
3
+ *
4
+ * Reads stdin JSON, resolves the project root, dynamically imports the
5
+ * correct handler, and returns JSON. Wraps everything in try/catch so
6
+ * no hook can ever crash.
7
+ *
8
+ * @module core/hooks/handlers/hook-router
9
+ */
10
+ import type { HookResult } from './types.js';
11
+ /**
12
+ * Route a hook event to the correct handler.
13
+ *
14
+ * @param eventType - The hook event type (e.g. 'pre-compact', 'user-prompt-submit')
15
+ * @param rawStdin - Raw stdin string (JSON from Claude Code)
16
+ * @returns HookResult — always valid JSON, never throws
17
+ */
18
+ export declare function hookRouter(eventType: string, rawStdin: string): Promise<HookResult>;
19
+ //# sourceMappingURL=hook-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-router.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/hook-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAa,UAAU,EAAE,MAAM,YAAY,CAAC;AAiBxD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,CA+CrB"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Hook router — the central dispatcher for all hook events.
3
+ *
4
+ * Reads stdin JSON, resolves the project root, dynamically imports the
5
+ * correct handler, and returns JSON. Wraps everything in try/catch so
6
+ * no hook can ever crash.
7
+ *
8
+ * @module core/hooks/handlers/hook-router
9
+ */
10
+ import { getSafeDefault } from './types.js';
11
+ import { findProjectRoot, createContext, parseStdinJson, logHook } from './utils.js';
12
+ /** Dynamic import map — only the requested handler is loaded per invocation */
13
+ const HANDLERS = {
14
+ 'user-prompt-submit': () => import('./user-prompt-submit.js'),
15
+ 'pre-tool-use': () => import('./pre-tool-use.js'),
16
+ 'post-tool-use': () => import('./post-tool-use.js'),
17
+ 'post-tool-use-analytics': () => import('./post-tool-use-analytics.js'),
18
+ 'session-start': () => import('./session-start.js'),
19
+ 'pre-compact': () => import('./pre-compact.js'),
20
+ 'stop-reflect': () => import('./stop-reflect.js'),
21
+ 'stop-auto': () => import('./stop-auto.js'),
22
+ 'stop-sync': () => import('./stop-sync.js'),
23
+ };
24
+ /**
25
+ * Route a hook event to the correct handler.
26
+ *
27
+ * @param eventType - The hook event type (e.g. 'pre-compact', 'user-prompt-submit')
28
+ * @param rawStdin - Raw stdin string (JSON from Claude Code)
29
+ * @returns HookResult — always valid JSON, never throws
30
+ */
31
+ export async function hookRouter(eventType, rawStdin) {
32
+ const safeDefault = getSafeDefault(eventType);
33
+ try {
34
+ // Global kill switch
35
+ if (process.env.SPECWEAVE_DISABLE_HOOKS === '1') {
36
+ return safeDefault;
37
+ }
38
+ // Parse stdin
39
+ const input = parseStdinJson(rawStdin);
40
+ // Resolve project root
41
+ const projectRoot = findProjectRoot();
42
+ if (!projectRoot) {
43
+ // Not a SpecWeave project — pass through
44
+ return safeDefault;
45
+ }
46
+ // Build context
47
+ const context = createContext(projectRoot);
48
+ // Find handler
49
+ const loader = HANDLERS[eventType];
50
+ if (!loader) {
51
+ logHook(context, 'router', `Unknown event type: ${eventType}`);
52
+ return safeDefault;
53
+ }
54
+ // Dynamic import + execute
55
+ const handlerModule = await loader();
56
+ const result = await handlerModule.handle(input, context);
57
+ return result;
58
+ }
59
+ catch (error) {
60
+ // Never crash — log and return safe default
61
+ try {
62
+ const projectRoot = findProjectRoot();
63
+ if (projectRoot) {
64
+ const context = createContext(projectRoot);
65
+ const msg = error instanceof Error ? error.message : String(error);
66
+ logHook(context, 'router', `Error in ${eventType}: ${msg}`);
67
+ }
68
+ }
69
+ catch {
70
+ // Even logging can fail — swallow everything
71
+ }
72
+ return safeDefault;
73
+ }
74
+ }
75
+ //# sourceMappingURL=hook-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-router.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/hook-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErF,+EAA+E;AAC/E,MAAM,QAAQ,GAAyD;IACrE,oBAAoB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,yBAAyB,CAAC;IAC7D,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC;IACjD,eAAe,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC;IACnD,yBAAyB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,8BAA8B,CAAC;IACvE,eAAe,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC;IACnD,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC;IAC/C,cAAc,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC;IACjD,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC;IAC3C,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC;CAC5C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,SAAiB,EACjB,QAAgB;IAEhB,MAAM,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAE9C,IAAI,CAAC;QACH,qBAAqB;QACrB,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,GAAG,EAAE,CAAC;YAChD,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,cAAc;QACd,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAEvC,uBAAuB;QACvB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;QACtC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,yCAAyC;YACzC,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,gBAAgB;QAChB,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QAE3C,eAAe;QACf,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,uBAAuB,SAAS,EAAE,CAAC,CAAC;YAC/D,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,2BAA2B;QAC3B,MAAM,aAAa,GAAG,MAAM,MAAM,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4CAA4C;QAC5C,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;YACtC,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;gBAC3C,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACnE,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,SAAS,KAAK,GAAG,EAAE,CAAC,CAAC;YAC9D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Hook handlers barrel export.
3
+ *
4
+ * @module core/hooks/handlers
5
+ */
6
+ export type { HandlerFn, HookContext, HookInput, HookResult, HookEventType } from './types.js';
7
+ export { getSafeDefault, SAFE_DEFAULTS } from './types.js';
8
+ export { hookRouter } from './hook-router.js';
9
+ export { findProjectRoot, createContext, parseStdinJson, logHook } from './utils.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Hook handlers barrel export.
3
+ *
4
+ * @module core/hooks/handlers
5
+ */
6
+ export { getSafeDefault, SAFE_DEFAULTS } from './types.js';
7
+ export { hookRouter } from './hook-router.js';
8
+ export { findProjectRoot, createContext, parseStdinJson, logHook } from './utils.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * PostToolUse analytics handler — tracks Skill and Task (subagent) usage.
3
+ *
4
+ * Appends events to `.specweave/state/analytics/events.jsonl`.
5
+ * Non-blocking, never throws.
6
+ *
7
+ * @module core/hooks/handlers/post-tool-use-analytics
8
+ */
9
+ import type { HandlerFn } from './types.js';
10
+ export declare const handle: HandlerFn;
11
+ //# sourceMappingURL=post-tool-use-analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-tool-use-analytics.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/post-tool-use-analytics.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AAyBvD,eAAO,MAAM,MAAM,EAAE,SAkCpB,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * PostToolUse analytics handler — tracks Skill and Task (subagent) usage.
3
+ *
4
+ * Appends events to `.specweave/state/analytics/events.jsonl`.
5
+ * Non-blocking, never throws.
6
+ *
7
+ * @module core/hooks/handlers/post-tool-use-analytics
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ const CONTINUE = { continue: true };
12
+ function getToolInput(input) {
13
+ return (input.tool_input ?? input.toolInput ?? {});
14
+ }
15
+ function resolveToolName(input) {
16
+ const explicit = (input.tool_name ?? input.toolName ?? '');
17
+ if (explicit)
18
+ return explicit;
19
+ // Fallback: detect from input fields
20
+ const ti = getToolInput(input);
21
+ if (ti.skill)
22
+ return 'Skill';
23
+ if (ti.subagent_type)
24
+ return 'Task';
25
+ return '';
26
+ }
27
+ function extractPlugin(skillName) {
28
+ if (!skillName.includes(':'))
29
+ return 'specweave';
30
+ const prefix = skillName.split(':')[0];
31
+ return prefix === 'sw' ? 'specweave' : prefix;
32
+ }
33
+ export const handle = async (input, context) => {
34
+ const toolName = resolveToolName(input);
35
+ const ti = getToolInput(input);
36
+ if (toolName === 'Skill') {
37
+ const skillName = (ti.skill ?? '');
38
+ if (!skillName)
39
+ return CONTINUE;
40
+ const plugin = extractPlugin(skillName);
41
+ const event = {
42
+ type: 'skill',
43
+ name: skillName,
44
+ plugin,
45
+ timestamp: context.timestamp,
46
+ };
47
+ appendEvent(context.stateDir, event);
48
+ return CONTINUE;
49
+ }
50
+ if (toolName === 'Task') {
51
+ const agentType = (ti.subagent_type ?? 'general');
52
+ const event = {
53
+ type: 'agent',
54
+ name: agentType,
55
+ plugin: 'specweave',
56
+ timestamp: context.timestamp,
57
+ };
58
+ appendEvent(context.stateDir, event);
59
+ return CONTINUE;
60
+ }
61
+ return CONTINUE;
62
+ };
63
+ function appendEvent(stateDir, event) {
64
+ try {
65
+ const analyticsDir = path.join(stateDir, 'analytics');
66
+ fs.mkdirSync(analyticsDir, { recursive: true });
67
+ fs.appendFileSync(path.join(analyticsDir, 'events.jsonl'), JSON.stringify(event) + '\n');
68
+ }
69
+ catch {
70
+ // Never throw from analytics
71
+ }
72
+ }
73
+ //# sourceMappingURL=post-tool-use-analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-tool-use-analytics.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/post-tool-use-analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * PostToolUse hook handler — non-blocking event detector and queue writer.
3
+ *
4
+ * Detects changes to increment files and queues events to pending.jsonl
5
+ * for later processing by stop-sync.
6
+ *
7
+ * @module core/hooks/handlers/post-tool-use
8
+ */
9
+ import type { HandlerFn } from './types.js';
10
+ export declare const handle: HandlerFn;
11
+ //# sourceMappingURL=post-tool-use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-tool-use.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/post-tool-use.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,YAAY,CAAC;AA2CvD,eAAO,MAAM,MAAM,EAAE,SA+CpB,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * PostToolUse hook handler — non-blocking event detector and queue writer.
3
+ *
4
+ * Detects changes to increment files and queues events to pending.jsonl
5
+ * for later processing by stop-sync.
6
+ *
7
+ * @module core/hooks/handlers/post-tool-use
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ const CONTINUE = { continue: true };
12
+ function getToolInput(input) {
13
+ return (input.tool_input ?? input.toolInput ?? {});
14
+ }
15
+ function getFilePath(input) {
16
+ const ti = getToolInput(input);
17
+ return (ti.file_path ?? '');
18
+ }
19
+ function extractIncrementId(filePath) {
20
+ const match = filePath.match(/(\d{4}-[^/]+)/);
21
+ return match ? match[1] : null;
22
+ }
23
+ function queueEvent(stateDir, event, incrementId, timestamp, data) {
24
+ try {
25
+ const queueDir = path.join(stateDir, 'event-queue');
26
+ fs.mkdirSync(queueDir, { recursive: true });
27
+ const entry = {
28
+ event,
29
+ incrementId,
30
+ timestamp,
31
+ ...(data ? { data } : {}),
32
+ };
33
+ fs.appendFileSync(path.join(queueDir, 'pending.jsonl'), JSON.stringify(entry) + '\n');
34
+ }
35
+ catch {
36
+ // Never throw from event queuing
37
+ }
38
+ }
39
+ export const handle = async (input, context) => {
40
+ const filePath = getFilePath(input);
41
+ // Ignore non-increment files
42
+ if (!filePath.includes('.specweave/increments/')) {
43
+ return CONTINUE;
44
+ }
45
+ const incrementId = extractIncrementId(filePath);
46
+ if (!incrementId)
47
+ return CONTINUE;
48
+ const basename = path.basename(filePath);
49
+ // metadata.json → detect status changes
50
+ if (basename === 'metadata.json') {
51
+ try {
52
+ if (fs.existsSync(filePath)) {
53
+ const raw = fs.readFileSync(filePath, 'utf-8');
54
+ const meta = JSON.parse(raw);
55
+ const status = meta.status ?? 'unknown';
56
+ queueEvent(context.stateDir, 'increment.status_changed', incrementId, context.timestamp, { field: 'status', value: status });
57
+ }
58
+ }
59
+ catch {
60
+ // Read failure — skip silently
61
+ }
62
+ return CONTINUE;
63
+ }
64
+ // tasks.md → queue task.updated
65
+ if (basename === 'tasks.md') {
66
+ queueEvent(context.stateDir, 'task.updated', incrementId, context.timestamp);
67
+ return CONTINUE;
68
+ }
69
+ // spec.md → queue spec.updated
70
+ if (basename === 'spec.md') {
71
+ queueEvent(context.stateDir, 'spec.updated', incrementId, context.timestamp);
72
+ return CONTINUE;
73
+ }
74
+ return CONTINUE;
75
+ };
76
+ //# sourceMappingURL=post-tool-use.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"post-tool-use.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/post-tool-use.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Pre-compact hook handler — context pressure signal.
3
+ *
4
+ * Fires when Claude Code approaches context limits (before compaction).
5
+ * Tracks compaction count, escalates pressure level, writes health alerts.
6
+ *
7
+ * Escalation: 1st=elevated, 2nd=critical, 3+=emergency
8
+ */
9
+ import type { HandlerFn } from './types.js';
10
+ export declare const handle: HandlerFn;
11
+ //# sourceMappingURL=pre-compact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-compact.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/pre-compact.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAqC5C,eAAO,MAAM,MAAM,EAAE,SA0CpB,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Pre-compact hook handler — context pressure signal.
3
+ *
4
+ * Fires when Claude Code approaches context limits (before compaction).
5
+ * Tracks compaction count, escalates pressure level, writes health alerts.
6
+ *
7
+ * Escalation: 1st=elevated, 2nd=critical, 3+=emergency
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ function readPressure(filePath) {
12
+ try {
13
+ const raw = fs.readFileSync(filePath, 'utf-8');
14
+ const data = JSON.parse(raw);
15
+ return typeof data.compactionCount === 'number' ? data.compactionCount : 0;
16
+ }
17
+ catch {
18
+ return 0;
19
+ }
20
+ }
21
+ function getLevel(count) {
22
+ if (count >= 3)
23
+ return 'emergency';
24
+ if (count >= 2)
25
+ return 'critical';
26
+ return 'elevated';
27
+ }
28
+ function getAdvice(level) {
29
+ switch (level) {
30
+ case 'elevated':
31
+ return 'Context budget reduced to compact. Session is running long.';
32
+ case 'critical':
33
+ return 'Context budget at minimal. Consider starting a new session or setting contextBudget.level to off.';
34
+ case 'emergency':
35
+ return 'Context budget stripped to off (3+ compactions). Strongly recommend starting a new session.';
36
+ default:
37
+ return '';
38
+ }
39
+ }
40
+ export const handle = async (_input, context) => {
41
+ if (process.env.SPECWEAVE_DISABLE_HOOKS === '1') {
42
+ return { continue: true };
43
+ }
44
+ const { stateDir, logsDir, timestamp } = context;
45
+ fs.mkdirSync(stateDir, { recursive: true });
46
+ const pressurePath = path.join(stateDir, 'context-pressure.json');
47
+ const prevCount = readPressure(pressurePath);
48
+ const newCount = prevCount + 1;
49
+ const level = getLevel(newCount);
50
+ const advice = getAdvice(level);
51
+ // Write context-pressure.json
52
+ const pressure = {
53
+ level,
54
+ compactionCount: newCount,
55
+ lastCompaction: timestamp,
56
+ };
57
+ fs.writeFileSync(pressurePath, JSON.stringify(pressure));
58
+ // Write prompt-health-alert.json
59
+ const alertPath = path.join(stateDir, 'prompt-health-alert.json');
60
+ fs.writeFileSync(alertPath, JSON.stringify({
61
+ level,
62
+ compactionCount: newCount,
63
+ advice,
64
+ timestamp,
65
+ }));
66
+ // Log compaction event
67
+ try {
68
+ fs.mkdirSync(logsDir, { recursive: true });
69
+ const logEntry = `[${timestamp}] COMPACTION #${newCount} | level=${level} | ${advice}\n`;
70
+ fs.appendFileSync(path.join(logsDir, 'prompt-health.log'), logEntry);
71
+ }
72
+ catch {
73
+ // Never throw from logging
74
+ }
75
+ return { continue: true };
76
+ };
77
+ //# sourceMappingURL=pre-compact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-compact.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/pre-compact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * PreToolUse hook handler — inlines all guard logic:
3
+ * 1. Status Completion Guard (Edit metadata.json → "completed")
4
+ * 2. Interview Enforcement Guard (Write spec.md with strict interview)
5
+ * 3. Increment Existence Guard (TeamCreate without valid spec)
6
+ *
7
+ * @module core/hooks/handlers/pre-tool-use
8
+ */
9
+ import type { HandlerFn } from './types.js';
10
+ export declare const handle: HandlerFn;
11
+ //# sourceMappingURL=pre-tool-use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-tool-use.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/pre-tool-use.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,SAAS,EAA0B,MAAM,YAAY,CAAC;AA0UpE,eAAO,MAAM,MAAM,EAAE,SA0BpB,CAAC"}