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
@@ -0,0 +1,318 @@
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 * as fs from 'fs';
10
+ import * as path from 'path';
11
+ const ALLOW = { decision: 'allow' };
12
+ const TEMPLATE_MARKERS = [
13
+ '[Story Title]',
14
+ '[user type]',
15
+ '[goal]',
16
+ '[benefit]',
17
+ '[Specific, testable criterion]',
18
+ '[Component 1]',
19
+ '[High-level description',
20
+ '{{RESOLVED_PROJECT}}',
21
+ 'TEMPLATE FILE',
22
+ ];
23
+ const DEFAULT_INTERVIEW_CATEGORIES = [
24
+ 'architecture',
25
+ 'integrations',
26
+ 'ui-ux',
27
+ 'performance',
28
+ 'security',
29
+ 'edge-cases',
30
+ ];
31
+ const NON_IMPL_PREFIXES = [
32
+ 'review-',
33
+ 'brainstorm-',
34
+ 'analysis-',
35
+ 'audit-',
36
+ 'explore-',
37
+ 'ideate-',
38
+ 'research-',
39
+ 'plan-',
40
+ ];
41
+ const NON_IMPL_KEYWORDS = [
42
+ 'review',
43
+ 'brainstorm',
44
+ 'analyze',
45
+ 'audit',
46
+ 'explore',
47
+ 'ideate',
48
+ 'pull request',
49
+ 'pr #',
50
+ 'pr review',
51
+ 'code review',
52
+ 'architecture review',
53
+ 'security audit',
54
+ 'performance audit',
55
+ 'code audit',
56
+ 'ideation',
57
+ 'exploration',
58
+ 'research',
59
+ 'planning',
60
+ 'perspectives',
61
+ "devil's advocate",
62
+ 'pros and cons',
63
+ ];
64
+ function getToolName(input) {
65
+ return (input.tool_name ?? input.toolName ?? '');
66
+ }
67
+ function getToolInput(input) {
68
+ return (input.tool_input ?? input.toolInput ?? {});
69
+ }
70
+ function getFilePath(input) {
71
+ const ti = getToolInput(input);
72
+ return (ti.file_path ?? '');
73
+ }
74
+ function isIncrementFile(filePath) {
75
+ return filePath.includes('.specweave/increments/');
76
+ }
77
+ function extractIncrementId(filePath) {
78
+ const match = filePath.match(/(\d{4}[E]?-[^/]+)/);
79
+ return match ? match[1] : 'unknown';
80
+ }
81
+ function readJsonSafe(filePath) {
82
+ try {
83
+ if (!fs.existsSync(filePath))
84
+ return {};
85
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
86
+ }
87
+ catch {
88
+ return {};
89
+ }
90
+ }
91
+ // ---------------------------------------------------------------------------
92
+ // Guard: Status Completion (Edit metadata.json → "completed")
93
+ // ---------------------------------------------------------------------------
94
+ function checkStatusCompletionGuard(input, context) {
95
+ const ti = getToolInput(input);
96
+ const filePath = getFilePath(input);
97
+ const newString = (ti.new_string ?? '');
98
+ // Only care about metadata.json in increments
99
+ if (!filePath.match(/\.specweave\/increments\/.*\/metadata\.json$/)) {
100
+ return ALLOW;
101
+ }
102
+ // Check if setting status to "completed"
103
+ if (!/"status"\s*:\s*"completed"/.test(newString)) {
104
+ return ALLOW;
105
+ }
106
+ // Allow if sw-done marker exists
107
+ const doneMarker = path.join(context.stateDir, '.sw-done-in-progress');
108
+ if (fs.existsSync(doneMarker)) {
109
+ return ALLOW;
110
+ }
111
+ // Allow if auto-mode active with testsVerified
112
+ const autoSession = path.join(context.stateDir, 'auto', 'session.json');
113
+ if (fs.existsSync(autoSession)) {
114
+ const session = readJsonSafe(autoSession);
115
+ if (session.status === 'active' && session.testsVerified === true) {
116
+ return ALLOW;
117
+ }
118
+ }
119
+ const incrementId = extractIncrementId(filePath);
120
+ return {
121
+ decision: 'block',
122
+ reason: `Direct status change to 'completed' is blocked for ${incrementId}. Use /sw:done or /sw:auto instead.`,
123
+ };
124
+ }
125
+ // ---------------------------------------------------------------------------
126
+ // Guard: Interview Enforcement (Write spec.md with strict interview)
127
+ // ---------------------------------------------------------------------------
128
+ function checkInterviewGuard(input, context) {
129
+ const filePath = getFilePath(input);
130
+ const ti = getToolInput(input);
131
+ const content = (ti.content ?? '');
132
+ // Only care about spec.md in increments
133
+ if (!filePath.match(/\.specweave\/increments\/\d{4}-[^/]+\/spec\.md$/)) {
134
+ return ALLOW;
135
+ }
136
+ // Allow template writes through
137
+ for (const marker of TEMPLATE_MARKERS) {
138
+ if (content.includes(marker)) {
139
+ return ALLOW;
140
+ }
141
+ }
142
+ // Read config to check if strict interview enabled
143
+ const config = readJsonSafe(context.configPath);
144
+ const planning = (config.planning ?? {});
145
+ const di = (planning.deepInterview ?? {});
146
+ if (di.enabled !== true || di.enforcement !== 'strict') {
147
+ return ALLOW;
148
+ }
149
+ const incrementId = extractIncrementId(filePath);
150
+ const categories = di.categories ?? DEFAULT_INTERVIEW_CATEGORIES;
151
+ // Check interview state file
152
+ const interviewState = path.join(context.stateDir, `interview-${incrementId}.json`);
153
+ if (!fs.existsSync(interviewState)) {
154
+ return {
155
+ decision: 'block',
156
+ reason: `Strict Interview Enforcement: Interview Required. Deep Interview has not been started for ${incrementId}. Start and cover all categories before writing spec.md.`,
157
+ };
158
+ }
159
+ // Check covered categories
160
+ const state = readJsonSafe(interviewState);
161
+ const covered = state.coveredCategories;
162
+ const coveredKeys = covered ? Object.keys(covered) : [];
163
+ const missing = categories.filter((c) => !coveredKeys.includes(c));
164
+ if (missing.length > 0) {
165
+ return {
166
+ decision: 'block',
167
+ reason: `Strict Interview Enforcement: Incomplete Interview for ${incrementId}. Missing categories: ${missing.join(', ')}`,
168
+ };
169
+ }
170
+ return ALLOW;
171
+ }
172
+ // ---------------------------------------------------------------------------
173
+ // Guard: Increment Existence (TeamCreate without valid spec)
174
+ // ---------------------------------------------------------------------------
175
+ function isNonImplTeam(input) {
176
+ const ti = getToolInput(input);
177
+ const teamName = (ti.team_name ?? '').toLowerCase();
178
+ const description = (ti.description ?? '').toLowerCase();
179
+ // Check team name prefix
180
+ for (const prefix of NON_IMPL_PREFIXES) {
181
+ if (teamName.startsWith(prefix))
182
+ return true;
183
+ }
184
+ // Check description keywords
185
+ for (const keyword of NON_IMPL_KEYWORDS) {
186
+ if (description.includes(keyword))
187
+ return true;
188
+ }
189
+ return false;
190
+ }
191
+ function hasValidSpec(specPath) {
192
+ try {
193
+ if (!fs.existsSync(specPath))
194
+ return false;
195
+ const content = fs.readFileSync(specPath, 'utf-8');
196
+ // Min 500 bytes
197
+ if (Buffer.byteLength(content) <= 500)
198
+ return false;
199
+ // No template markers
200
+ for (const marker of TEMPLATE_MARKERS) {
201
+ if (content.includes(marker))
202
+ return false;
203
+ }
204
+ // No {{UPPERCASE}} mustache placeholders
205
+ if (/\{\{[A-Z_]+\}\}/.test(content))
206
+ return false;
207
+ // Must have at least one acceptance criterion
208
+ if (!/AC-US\d+-\d+|AC-\d+/.test(content))
209
+ return false;
210
+ return true;
211
+ }
212
+ catch {
213
+ return false;
214
+ }
215
+ }
216
+ function checkIncrementExistenceGuard(_input, context) {
217
+ // Env var bypass
218
+ if (process.env.SPECWEAVE_NO_INCREMENT === '1') {
219
+ return ALLOW;
220
+ }
221
+ // Scan increments for valid specs with active/in-progress status
222
+ const incDir = path.join(context.projectRoot, '.specweave', 'increments');
223
+ if (fs.existsSync(incDir)) {
224
+ try {
225
+ const entries = fs.readdirSync(incDir, { withFileTypes: true });
226
+ for (const entry of entries) {
227
+ if (entry.isDirectory()) {
228
+ const specPath = path.join(incDir, entry.name, 'spec.md');
229
+ if (!hasValidSpec(specPath))
230
+ continue;
231
+ // Check metadata.json for qualifying status
232
+ const metaPath = path.join(incDir, entry.name, 'metadata.json');
233
+ if (fs.existsSync(metaPath)) {
234
+ try {
235
+ const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
236
+ const status = meta?.status ?? '';
237
+ const qualifying = ['active', 'in-progress', 'ready_for_review', 'planned'];
238
+ if (qualifying.includes(status))
239
+ return ALLOW;
240
+ }
241
+ catch {
242
+ // Unreadable metadata — skip this increment
243
+ }
244
+ }
245
+ else {
246
+ // No metadata.json but valid spec — allow (legacy increments)
247
+ return ALLOW;
248
+ }
249
+ }
250
+ }
251
+ }
252
+ catch {
253
+ // scan failure — don't block
254
+ }
255
+ }
256
+ // Scan multi-repo increments
257
+ const reposDir = path.join(context.projectRoot, 'repositories');
258
+ if (fs.existsSync(reposDir)) {
259
+ try {
260
+ const orgs = fs.readdirSync(reposDir, { withFileTypes: true });
261
+ for (const org of orgs) {
262
+ if (!org.isDirectory())
263
+ continue;
264
+ const orgPath = path.join(reposDir, org.name);
265
+ const repos = fs.readdirSync(orgPath, { withFileTypes: true });
266
+ for (const repo of repos) {
267
+ if (!repo.isDirectory())
268
+ continue;
269
+ const repoIncDir = path.join(orgPath, repo.name, '.specweave', 'increments');
270
+ if (!fs.existsSync(repoIncDir))
271
+ continue;
272
+ const incs = fs.readdirSync(repoIncDir, { withFileTypes: true });
273
+ for (const inc of incs) {
274
+ if (inc.isDirectory()) {
275
+ const specPath = path.join(repoIncDir, inc.name, 'spec.md');
276
+ if (hasValidSpec(specPath))
277
+ return ALLOW;
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ catch {
284
+ // scan failure — don't block
285
+ }
286
+ }
287
+ return {
288
+ decision: 'block',
289
+ reason: 'Increment Required Before Team Creation. No qualifying increment with a valid spec.md found. Run /sw:increment first, or use a mode-prefixed team name (review-*, brainstorm-*, analysis-*, research-*) for non-implementation work.',
290
+ };
291
+ }
292
+ // ---------------------------------------------------------------------------
293
+ // Main handler
294
+ // ---------------------------------------------------------------------------
295
+ export const handle = async (input, context) => {
296
+ const toolName = getToolName(input);
297
+ const filePath = getFilePath(input);
298
+ // Fast path: not targeting increment files AND not TeamCreate
299
+ if (!isIncrementFile(filePath) && toolName !== 'TeamCreate') {
300
+ return ALLOW;
301
+ }
302
+ // Edit guard: status completion
303
+ if (toolName === 'Edit') {
304
+ return checkStatusCompletionGuard(input, context);
305
+ }
306
+ // Write guard: interview enforcement
307
+ if (toolName === 'Write') {
308
+ return checkInterviewGuard(input, context);
309
+ }
310
+ // TeamCreate guard: increment existence
311
+ if (toolName === 'TeamCreate') {
312
+ if (isNonImplTeam(input))
313
+ return ALLOW;
314
+ return checkIncrementExistenceGuard(input, context);
315
+ }
316
+ return ALLOW;
317
+ };
318
+ //# sourceMappingURL=pre-tool-use.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-tool-use.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/pre-tool-use.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Session-start hook handler — session initialization.
3
+ *
4
+ * Clears stale auto-mode files, resets context pressure,
5
+ * and performs baseline prompt health check.
6
+ */
7
+ import type { HandlerFn } from './types.js';
8
+ export declare const handle: HandlerFn;
9
+ //# sourceMappingURL=session-start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/session-start.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAkC5C,eAAO,MAAM,MAAM,EAAE,SA6EpB,CAAC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Session-start hook handler — session initialization.
3
+ *
4
+ * Clears stale auto-mode files, resets context pressure,
5
+ * and performs baseline prompt health check.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ const STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000; // 24 hours
10
+ const WARNING_THRESHOLD = 80000;
11
+ const CRITICAL_THRESHOLD = 120000;
12
+ const SYSTEM_ESTIMATE = 12000;
13
+ const SKILL_BUDGET = 15000;
14
+ const HOOK_PER_TURN = 3000;
15
+ function isStale(filePath) {
16
+ try {
17
+ const stat = fs.statSync(filePath);
18
+ return Date.now() - stat.mtimeMs > STALE_THRESHOLD_MS;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ function safeRemove(filePath) {
25
+ try {
26
+ fs.unlinkSync(filePath);
27
+ }
28
+ catch {
29
+ // Ignore
30
+ }
31
+ }
32
+ function fileSize(filePath) {
33
+ try {
34
+ return fs.statSync(filePath).size;
35
+ }
36
+ catch {
37
+ return 0;
38
+ }
39
+ }
40
+ export const handle = async (_input, context) => {
41
+ const { projectRoot, stateDir, logsDir, timestamp } = context;
42
+ try {
43
+ fs.mkdirSync(stateDir, { recursive: true });
44
+ }
45
+ catch {
46
+ return { continue: true };
47
+ }
48
+ // --- Auto-mode cleanup: remove stale session files (>24h) ---
49
+ const autoFile = path.join(stateDir, 'auto-mode.json');
50
+ if (fs.existsSync(autoFile) && isStale(autoFile)) {
51
+ safeRemove(autoFile);
52
+ safeRemove(path.join(stateDir, '.stop-auto-dedup'));
53
+ safeRemove(path.join(stateDir, '.stop-auto-dedup-prev'));
54
+ safeRemove(path.join(stateDir, '.stop-auto-turns'));
55
+ try {
56
+ fs.mkdirSync(logsDir, { recursive: true });
57
+ fs.appendFileSync(path.join(logsDir, 'session.log'), `[${timestamp}] SessionStart: Cleared stale auto-mode session files (>24h)\n`);
58
+ }
59
+ catch {
60
+ // Never throw from logging
61
+ }
62
+ }
63
+ // --- Context pressure reset ---
64
+ safeRemove(path.join(stateDir, 'context-pressure.json'));
65
+ safeRemove(path.join(stateDir, 'prompt-health-alert.json'));
66
+ // --- Baseline health check ---
67
+ try {
68
+ const claudeMdSize = fileSize(path.join(projectRoot, 'CLAUDE.md'));
69
+ const memoryDir = path.join(projectRoot, '.claude', 'projects');
70
+ let memoryMdSize = 0;
71
+ try {
72
+ // Find MEMORY.md in any project subdirectory
73
+ if (fs.existsSync(memoryDir)) {
74
+ const entries = fs.readdirSync(memoryDir, { withFileTypes: true });
75
+ for (const entry of entries) {
76
+ if (entry.isDirectory()) {
77
+ const memPath = path.join(memoryDir, entry.name, 'memory', 'MEMORY.md');
78
+ memoryMdSize += fileSize(memPath);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ catch {
84
+ // Best-effort
85
+ }
86
+ const baseline = claudeMdSize + memoryMdSize + SYSTEM_ESTIMATE + SKILL_BUDGET + HOOK_PER_TURN;
87
+ let warningLevel = 'normal';
88
+ if (baseline > CRITICAL_THRESHOLD) {
89
+ warningLevel = 'critical';
90
+ }
91
+ else if (baseline > WARNING_THRESHOLD) {
92
+ warningLevel = 'warning';
93
+ }
94
+ const health = {
95
+ baseline,
96
+ claudeMdSize,
97
+ memoryMdSize,
98
+ skillBudget: SKILL_BUDGET,
99
+ systemEstimate: SYSTEM_ESTIMATE,
100
+ hookPerTurn: HOOK_PER_TURN,
101
+ warningLevel,
102
+ checkedAt: timestamp,
103
+ };
104
+ fs.writeFileSync(path.join(stateDir, 'prompt-health.json'), JSON.stringify(health));
105
+ }
106
+ catch {
107
+ // Health check is best-effort
108
+ }
109
+ return { continue: true };
110
+ };
111
+ //# sourceMappingURL=session-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-start.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/session-start.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,MAAM,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;AAC3D,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAChC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,eAAe,GAAG,KAAK,CAAC;AAC9B,MAAM,YAAY,GAAG,KAAK,CAAC;AAC3B,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B,SAAS,OAAO,CAAC,QAAgB;IAC/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,kBAAkB,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,QAAgB;IAChC,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAc,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;IACzD,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE9D,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAED,+DAA+D;IAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IACvD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,UAAU,CAAC,QAAQ,CAAC,CAAC;QACrB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACpD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC;QACzD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAC;QAEpD,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,EAAE,CAAC,cAAc,CACf,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACjC,IAAI,SAAS,gEAAgE,CAC9E,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAED,iCAAiC;IACjC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC;IACzD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,0BAA0B,CAAC,CAAC,CAAC;IAE5D,gCAAgC;IAChC,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;QACnE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QAChE,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,CAAC;YACH,6CAA6C;YAC7C,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;wBACxB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;wBACxE,YAAY,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QACD,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,GAAG,eAAe,GAAG,YAAY,GAAG,aAAa,CAAC;QAE9F,IAAI,YAAY,GAAG,QAAQ,CAAC;QAC5B,IAAI,QAAQ,GAAG,kBAAkB,EAAE,CAAC;YAClC,YAAY,GAAG,UAAU,CAAC;QAC5B,CAAC;aAAM,IAAI,QAAQ,GAAG,iBAAiB,EAAE,CAAC;YACxC,YAAY,GAAG,SAAS,CAAC;QAC3B,CAAC;QAED,MAAM,MAAM,GAAG;YACb,QAAQ;YACR,YAAY;YACZ,YAAY;YACZ,WAAW,EAAE,YAAY;YACzB,cAAc,EAAE,eAAe;YAC/B,WAAW,EAAE,aAAa;YAC1B,YAAY;YACZ,SAAS,EAAE,SAAS;SACrB,CAAC;QAEF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACtF,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Stop-auto hook handler.
3
+ *
4
+ * Fires when a session ends. Checks if an auto-mode session is active:
5
+ * 1. Look for auto-mode.json (per-session or global)
6
+ * 2. Check session staleness
7
+ * 3. Scan active increments for pending tasks
8
+ * 4. Include progress context but always approve
9
+ *
10
+ * Stop hooks should NEVER block session exit.
11
+ *
12
+ * @module core/hooks/handlers/stop-auto
13
+ */
14
+ import type { HandlerFn } from './types.js';
15
+ export declare const handle: HandlerFn;
16
+ //# sourceMappingURL=stop-auto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-auto.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/stop-auto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAwE5C,eAAO,MAAM,MAAM,EAAE,SAyCpB,CAAC"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Stop-auto hook handler.
3
+ *
4
+ * Fires when a session ends. Checks if an auto-mode session is active:
5
+ * 1. Look for auto-mode.json (per-session or global)
6
+ * 2. Check session staleness
7
+ * 3. Scan active increments for pending tasks
8
+ * 4. Include progress context but always approve
9
+ *
10
+ * Stop hooks should NEVER block session exit.
11
+ *
12
+ * @module core/hooks/handlers/stop-auto
13
+ */
14
+ import * as fs from 'fs';
15
+ import * as path from 'path';
16
+ import { logHook } from './utils.js';
17
+ /** Read JSON safely, return null on error */
18
+ function readJsonSafe(filePath) {
19
+ try {
20
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ /** Get auto-mode session file path (per-session or global fallback) */
27
+ function getSessionPath(stateDir) {
28
+ const sessionId = process.env.CLAUDE_SESSION_ID;
29
+ if (sessionId) {
30
+ const perSession = path.join(stateDir, 'sessions', sessionId, 'auto-mode.json');
31
+ if (fs.existsSync(perSession))
32
+ return perSession;
33
+ }
34
+ return path.join(stateDir, 'auto-mode.json');
35
+ }
36
+ /** Check if session file is stale (older than maxSessionAge seconds) */
37
+ function isSessionStale(sessionPath, maxSessionAge) {
38
+ try {
39
+ const stat = fs.statSync(sessionPath);
40
+ const ageMs = Date.now() - stat.mtimeMs;
41
+ return ageMs > maxSessionAge * 1000;
42
+ }
43
+ catch {
44
+ return true;
45
+ }
46
+ }
47
+ /** Count pending tasks across active increments */
48
+ function scanPendingTasks(projectRoot) {
49
+ const incDir = path.join(projectRoot, '.specweave', 'increments');
50
+ let pending = 0;
51
+ let completed = 0;
52
+ const incrementIds = [];
53
+ try {
54
+ if (!fs.existsSync(incDir))
55
+ return { pending, completed, incrementIds };
56
+ const dirs = fs.readdirSync(incDir);
57
+ for (const dir of dirs) {
58
+ const metaPath = path.join(incDir, dir, 'metadata.json');
59
+ if (!fs.existsSync(metaPath))
60
+ continue;
61
+ const meta = readJsonSafe(metaPath);
62
+ if (!meta || (meta.status !== 'active' && meta.status !== 'in-progress'))
63
+ continue;
64
+ const tasksPath = path.join(incDir, dir, 'tasks.md');
65
+ try {
66
+ const tasks = fs.readFileSync(tasksPath, 'utf8');
67
+ const p = (tasks.match(/\[ \]/g) || []).length;
68
+ const c = (tasks.match(/\[x\]/g) || []).length;
69
+ if (p > 0) {
70
+ pending += p;
71
+ completed += c;
72
+ incrementIds.push(dir);
73
+ }
74
+ }
75
+ catch {
76
+ // No tasks file
77
+ }
78
+ }
79
+ }
80
+ catch {
81
+ // fs errors
82
+ }
83
+ return { pending, completed, incrementIds };
84
+ }
85
+ export const handle = async (input, context) => {
86
+ try {
87
+ // 1. Find auto-mode session file
88
+ const sessionPath = getSessionPath(context.stateDir);
89
+ if (!fs.existsSync(sessionPath)) {
90
+ logHook(context, 'stop-auto', 'No auto session');
91
+ return { decision: 'approve' };
92
+ }
93
+ // 2. Read session data
94
+ const session = readJsonSafe(sessionPath);
95
+ if (!session || session.active !== true) {
96
+ logHook(context, 'stop-auto', 'Session not active');
97
+ return { decision: 'approve' };
98
+ }
99
+ // 3. Read config for maxSessionAge
100
+ const config = readJsonSafe(context.configPath);
101
+ const maxSessionAge = config?.auto?.maxSessionAge ?? 7200;
102
+ // 4. Check staleness
103
+ if (isSessionStale(sessionPath, maxSessionAge)) {
104
+ logHook(context, 'stop-auto', 'Stale session — expired');
105
+ return { decision: 'approve' };
106
+ }
107
+ // 5. Scan active increments for pending tasks
108
+ const { pending, completed, incrementIds } = scanPendingTasks(context.projectRoot);
109
+ if (pending === 0) {
110
+ logHook(context, 'stop-auto', 'All tasks complete');
111
+ return { decision: 'approve' };
112
+ }
113
+ // 6. Pending tasks exist — include progress context but still approve
114
+ logHook(context, 'stop-auto', `Pending tasks: ${pending} across ${incrementIds.length} increment(s)`);
115
+ return { decision: 'approve' };
116
+ }
117
+ catch {
118
+ // Never throw — always approve
119
+ return { decision: 'approve' };
120
+ }
121
+ };
122
+ //# sourceMappingURL=stop-auto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-auto.js","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/stop-auto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Stop-reflect hook handler.
3
+ *
4
+ * Fires when a session ends. Checks if reflection is enabled in config.
5
+ * If enabled, logs that reflection was requested (actual reflection logic
6
+ * will call `specweave reflect-stop` CLI in a follow-up).
7
+ *
8
+ * NEVER blocks — always returns approve.
9
+ *
10
+ * @module core/hooks/handlers/stop-reflect
11
+ */
12
+ import type { HandlerFn } from './types.js';
13
+ export declare const handle: HandlerFn;
14
+ //# sourceMappingURL=stop-reflect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-reflect.d.ts","sourceRoot":"","sources":["../../../../../src/core/hooks/handlers/stop-reflect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAe5C,eAAO,MAAM,MAAM,EAAE,SAgBpB,CAAC"}