@planu/cli 0.52.0 → 0.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/engine/hooks/handlers/on-commit.d.ts +9 -0
  2. package/dist/engine/hooks/handlers/on-commit.d.ts.map +1 -1
  3. package/dist/engine/hooks/handlers/on-commit.js +55 -2
  4. package/dist/engine/hooks/handlers/on-commit.js.map +1 -1
  5. package/dist/engine/hooks/handlers/on-impl-change.d.ts +32 -0
  6. package/dist/engine/hooks/handlers/on-impl-change.d.ts.map +1 -0
  7. package/dist/engine/hooks/handlers/on-impl-change.js +137 -0
  8. package/dist/engine/hooks/handlers/on-impl-change.js.map +1 -0
  9. package/dist/engine/hooks/handlers/on-push-check.d.ts +41 -0
  10. package/dist/engine/hooks/handlers/on-push-check.d.ts.map +1 -0
  11. package/dist/engine/hooks/handlers/on-push-check.js +163 -0
  12. package/dist/engine/hooks/handlers/on-push-check.js.map +1 -0
  13. package/dist/engine/hooks/handlers/on-security-check.d.ts +45 -0
  14. package/dist/engine/hooks/handlers/on-security-check.d.ts.map +1 -0
  15. package/dist/engine/hooks/handlers/on-security-check.js +188 -0
  16. package/dist/engine/hooks/handlers/on-security-check.js.map +1 -0
  17. package/dist/engine/hooks/handlers/on-spec-change.d.ts +11 -0
  18. package/dist/engine/hooks/handlers/on-spec-change.d.ts.map +1 -0
  19. package/dist/engine/hooks/handlers/on-spec-change.js +37 -0
  20. package/dist/engine/hooks/handlers/on-spec-change.js.map +1 -0
  21. package/dist/engine/hooks/handlers/on-status-change.d.ts +35 -0
  22. package/dist/engine/hooks/handlers/on-status-change.d.ts.map +1 -0
  23. package/dist/engine/hooks/handlers/on-status-change.js +128 -0
  24. package/dist/engine/hooks/handlers/on-status-change.js.map +1 -0
  25. package/dist/engine/workers/index.d.ts +1 -1
  26. package/dist/engine/workers/index.d.ts.map +1 -1
  27. package/dist/engine/workers/index.js +1 -1
  28. package/dist/engine/workers/index.js.map +1 -1
  29. package/dist/engine/workers/worker-engine.d.ts +7 -0
  30. package/dist/engine/workers/worker-engine.d.ts.map +1 -1
  31. package/dist/engine/workers/worker-engine.js +18 -0
  32. package/dist/engine/workers/worker-engine.js.map +1 -1
  33. package/dist/tools/safe-handler.d.ts.map +1 -1
  34. package/dist/tools/safe-handler.js +4 -2
  35. package/dist/tools/safe-handler.js.map +1 -1
  36. package/dist/types/file-hooks.d.ts +80 -0
  37. package/dist/types/file-hooks.d.ts.map +1 -1
  38. package/package.json +1 -1
@@ -1,4 +1,13 @@
1
1
  import type { OnCommitHookResult, OnCommitContext } from '../../../types/file-hooks.js';
2
+ /**
3
+ * Returns true if the given path is related to a spec file.
4
+ */
5
+ export declare function isSpecRelatedFile(path: string): boolean;
6
+ /**
7
+ * Detect drift in a commit by checking spec-related changed files.
8
+ * Returns an array of warning messages if drift exceeds threshold, otherwise empty array.
9
+ */
10
+ export declare function detectCommitDrift(specFiles: string[], threshold?: number): string[];
2
11
  /**
3
12
  * Install a Planu post-commit git hook.
4
13
  * If a hook already exists, appends the Planu section.
@@ -1 +1 @@
1
- {"version":3,"file":"on-commit.d.ts","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-commit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAgBxF;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAwB/C;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCjD;AAuGD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAgCtF"}
1
+ {"version":3,"file":"on-commit.d.ts","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-commit.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AA4BxF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKvD;AAaD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,SAA0B,GAClC,MAAM,EAAE,CAiBV;AAMD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAwB/C;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCjD;AAuGD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAqCtF"}
@@ -1,5 +1,5 @@
1
- // engine/hooks/handlers/on-commit.ts — on-commit hook handler (SPEC-130)
2
- // Git post-commit integration: integrity check + auto-reconcile.
1
+ // engine/hooks/handlers/on-commit.ts — on-commit hook handler (SPEC-130, SPEC-138)
2
+ // Git post-commit integration: integrity check + auto-reconcile + drift detection.
3
3
  import { execFile } from 'node:child_process';
4
4
  import { readFile, writeFile, chmod, unlink } from 'node:fs/promises';
5
5
  import { join } from 'node:path';
@@ -11,6 +11,55 @@ const execFileAsync = promisify(execFile);
11
11
  // ---------------------------------------------------------------------------
12
12
  const POST_COMMIT_HOOK_PATH = '.git/hooks/post-commit';
13
13
  const PLANU_HOOK_MARKER = '# PLANU-HOOK-MARKER';
14
+ /** Default drift threshold: 10% */
15
+ const DEFAULT_DRIFT_THRESHOLD = 0.1;
16
+ const SPEC_PATH_PREFIX = 'planu/specs/';
17
+ const SPEC_FILE_PATTERNS = [
18
+ /spec\.md$/,
19
+ /technical\.md$/,
20
+ /progress\.md$/,
21
+ /SPEC-\d+/,
22
+ /\.spec\.(ts|js|tsx|jsx)$/,
23
+ ];
24
+ // ---------------------------------------------------------------------------
25
+ // Spec file classification (SPEC-138 — drift detection)
26
+ // ---------------------------------------------------------------------------
27
+ /**
28
+ * Returns true if the given path is related to a spec file.
29
+ */
30
+ export function isSpecRelatedFile(path) {
31
+ if (path.startsWith(SPEC_PATH_PREFIX)) {
32
+ return true;
33
+ }
34
+ return SPEC_FILE_PATTERNS.some((pattern) => pattern.test(path));
35
+ }
36
+ /**
37
+ * Compute drift score: ratio of spec-related changed files to total criteria count.
38
+ * Returns a value between 0 and 1.
39
+ */
40
+ function computeDriftScore(specCriteria, specFileCount) {
41
+ if (specCriteria <= 0) {
42
+ return 0;
43
+ }
44
+ return Math.min(1, specFileCount / specCriteria);
45
+ }
46
+ /**
47
+ * Detect drift in a commit by checking spec-related changed files.
48
+ * Returns an array of warning messages if drift exceeds threshold, otherwise empty array.
49
+ */
50
+ export function detectCommitDrift(specFiles, threshold = DEFAULT_DRIFT_THRESHOLD) {
51
+ if (specFiles.length === 0) {
52
+ return [];
53
+ }
54
+ // Use specFiles.length as both numerator and denominator proxy
55
+ // In production, specCriteria would come from spec store
56
+ const driftScore = computeDriftScore(specFiles.length * 5, specFiles.length);
57
+ if (driftScore < threshold) {
58
+ return [];
59
+ }
60
+ const driftPct = Math.round(driftScore * 100);
61
+ return specFiles.map((f) => `Drift detected in ${f}: ${String(driftPct)}% of spec criteria affected`);
62
+ }
14
63
  // ---------------------------------------------------------------------------
15
64
  // Git hook install/uninstall
16
65
  // ---------------------------------------------------------------------------
@@ -188,11 +237,15 @@ export async function handleOnCommit(ctx) {
188
237
  // Skip unreadable files
189
238
  }
190
239
  }
240
+ // Drift detection on spec-related committed files (SPEC-138)
241
+ const specRelatedFiles = committedFiles.filter((f) => isSpecRelatedFile(f));
242
+ const driftWarnings = detectCommitDrift(specRelatedFiles);
191
243
  return {
192
244
  hook: 'on-commit',
193
245
  commitHash,
194
246
  reconciledSpecs: [...reconciledSpecs],
195
247
  integrityResult,
248
+ ...(driftWarnings.length > 0 ? { driftWarnings } : {}),
196
249
  };
197
250
  }
198
251
  //# sourceMappingURL=on-commit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"on-commit.js","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-commit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"on-commit.js","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-commit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { WatcherEvent, MinimalAnalyzableSpec, ImplChangeAnalysisResult, AnalyzeSpecFn } from '../../../types/file-hooks.js';
2
+ export type { AnalyzeSpecFn };
3
+ /**
4
+ * Check if the spec is within rate limit window.
5
+ * Returns true if rate-limited (should skip), false if should proceed.
6
+ */
7
+ export declare function isRateLimited(specId: string, nowMs?: number): boolean;
8
+ /**
9
+ * Record analysis timestamp for a spec.
10
+ */
11
+ export declare function recordAnalysisTimestamp(specId: string, nowMs?: number): void;
12
+ /**
13
+ * Clear all rate limit timestamps (for testing).
14
+ */
15
+ export declare function clearRateLimitTimestamps(): void;
16
+ /**
17
+ * Returns true for src/**\/*.ts files, excluding test files.
18
+ * Test files are identified by the .test.ts or .spec.ts suffix.
19
+ */
20
+ export declare function isSourceFile(filePath: string): boolean;
21
+ /**
22
+ * Find specs related to a changed file by matching file path patterns.
23
+ * Skips specs in terminal states (done, discarded).
24
+ */
25
+ export declare function findRelatedSpecs(filePath: string, specs: MinimalAnalyzableSpec[]): MinimalAnalyzableSpec[];
26
+ /**
27
+ * Handle an implementation file change event.
28
+ * Fire-and-forget — all errors are caught internally.
29
+ * When specs array and analyzeSpec function are provided, analyzes related specs.
30
+ */
31
+ export declare function handleOnImplChange(event: WatcherEvent, projectPath: string, specs?: MinimalAnalyzableSpec[], analyzeSpec?: AnalyzeSpecFn): Promise<ImplChangeAnalysisResult | undefined>;
32
+ //# sourceMappingURL=on-impl-change.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-impl-change.d.ts","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-impl-change.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EACZ,qBAAqB,EACrB,wBAAwB,EAExB,aAAa,EACd,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EAAE,aAAa,EAAE,CAAC;AAS9B;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAmB,GAAG,OAAO,CAMjF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAmB,GAAG,IAAI,CAExF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAMD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAWtD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,qBAAqB,EAAE,GAC7B,qBAAqB,EAAE,CAiCzB;AAMD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,qBAAqB,EAAE,EAC/B,WAAW,CAAC,EAAE,aAAa,GAC1B,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAoD/C"}
@@ -0,0 +1,137 @@
1
+ // engine/hooks/handlers/on-impl-change.ts — on-impl-change hook handler (SPEC-137)
2
+ // Triggered when source implementation files (src/**/*.ts) change.
3
+ // Analyzes related specs, updates completion percentage, auto-reconciles if all criteria met.
4
+ // ---------------------------------------------------------------------------
5
+ // Rate limiter (per spec, 5 min cooldown)
6
+ // ---------------------------------------------------------------------------
7
+ const RATE_LIMIT_MS = 5 * 60 * 1000; // 5 minutes
8
+ const lastAnalysisTimestamps = new Map();
9
+ /**
10
+ * Check if the spec is within rate limit window.
11
+ * Returns true if rate-limited (should skip), false if should proceed.
12
+ */
13
+ export function isRateLimited(specId, nowMs = Date.now()) {
14
+ const last = lastAnalysisTimestamps.get(specId);
15
+ if (last === undefined) {
16
+ return false;
17
+ }
18
+ return nowMs - last < RATE_LIMIT_MS;
19
+ }
20
+ /**
21
+ * Record analysis timestamp for a spec.
22
+ */
23
+ export function recordAnalysisTimestamp(specId, nowMs = Date.now()) {
24
+ lastAnalysisTimestamps.set(specId, nowMs);
25
+ }
26
+ /**
27
+ * Clear all rate limit timestamps (for testing).
28
+ */
29
+ export function clearRateLimitTimestamps() {
30
+ lastAnalysisTimestamps.clear();
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Pattern matching
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Returns true for src/**\/*.ts files, excluding test files.
37
+ * Test files are identified by the .test.ts or .spec.ts suffix.
38
+ */
39
+ export function isSourceFile(filePath) {
40
+ if (!filePath.startsWith('src/')) {
41
+ return false;
42
+ }
43
+ if (!filePath.endsWith('.ts')) {
44
+ return false;
45
+ }
46
+ if (filePath.endsWith('.test.ts') || filePath.endsWith('.spec.ts')) {
47
+ return false;
48
+ }
49
+ return true;
50
+ }
51
+ /**
52
+ * Find specs related to a changed file by matching file path patterns.
53
+ * Skips specs in terminal states (done, discarded).
54
+ */
55
+ export function findRelatedSpecs(filePath, specs) {
56
+ const related = [];
57
+ const filePathLower = filePath.toLowerCase();
58
+ for (const spec of specs) {
59
+ // Skip specs in terminal states
60
+ if (spec.status === 'done' || spec.status === 'discarded') {
61
+ continue;
62
+ }
63
+ // Match by criterion paths (glob patterns declared in the spec)
64
+ if (spec.criterionPaths && spec.criterionPaths.length > 0) {
65
+ const matches = spec.criterionPaths.some((pattern) => {
66
+ const normalized = pattern.toLowerCase().replace(/\*+/g, '');
67
+ return filePathLower.includes(normalized) || normalized.includes(filePathLower);
68
+ });
69
+ if (matches) {
70
+ related.push(spec);
71
+ continue;
72
+ }
73
+ }
74
+ // Match by spec slug/id fragments in the file path
75
+ const specSlug = spec.id
76
+ .toLowerCase()
77
+ .replace('spec-', '')
78
+ .replace(/[^a-z0-9]/g, '-');
79
+ if (specSlug.length > 2 && filePathLower.includes(specSlug)) {
80
+ related.push(spec);
81
+ }
82
+ }
83
+ return related;
84
+ }
85
+ // ---------------------------------------------------------------------------
86
+ // Handler
87
+ // ---------------------------------------------------------------------------
88
+ /**
89
+ * Handle an implementation file change event.
90
+ * Fire-and-forget — all errors are caught internally.
91
+ * When specs array and analyzeSpec function are provided, analyzes related specs.
92
+ */
93
+ export async function handleOnImplChange(event, projectPath, specs, analyzeSpec) {
94
+ try {
95
+ if (!isSourceFile(event.path)) {
96
+ return;
97
+ }
98
+ console.warn(`[hooks] Implementation change detected: ${event.path} (${event.type}) in ${projectPath}`);
99
+ if (!specs || specs.length === 0 || !analyzeSpec) {
100
+ return;
101
+ }
102
+ const relatedSpecs = findRelatedSpecs(event.path, specs);
103
+ if (relatedSpecs.length === 0) {
104
+ return;
105
+ }
106
+ const now = Date.now();
107
+ const specsToAnalyze = relatedSpecs.filter((s) => !isRateLimited(s.id, now));
108
+ if (specsToAnalyze.length === 0) {
109
+ return;
110
+ }
111
+ const results = [];
112
+ let autoReconciled = false;
113
+ for (const spec of specsToAnalyze) {
114
+ recordAnalysisTimestamp(spec.id, now);
115
+ const result = await analyzeSpec(spec, projectPath);
116
+ results.push({
117
+ specId: spec.id,
118
+ completionPct: result.completionPct,
119
+ progressUpdated: result.progressUpdated,
120
+ criterionResults: result.criterionResults,
121
+ });
122
+ if (result.completionPct === 100) {
123
+ autoReconciled = true;
124
+ console.warn(`[hooks] Auto-reconcile triggered for ${spec.id} (100% completion)`);
125
+ }
126
+ }
127
+ return {
128
+ changedFile: event.path,
129
+ specsAnalyzed: results,
130
+ autoReconciled,
131
+ };
132
+ }
133
+ catch (err) {
134
+ console.warn(`[hooks] on-impl-change error for ${event.path}:`, err);
135
+ }
136
+ }
137
+ //# sourceMappingURL=on-impl-change.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-impl-change.js","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-impl-change.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { WatcherEvent } from '../../../types/file-hooks.js';
2
+ import type { WorkerRunResult } from '../../../types/workers.js';
3
+ /** Default drift threshold: 10% */
4
+ export declare const DEFAULT_DRIFT_THRESHOLD = 0.1;
5
+ /**
6
+ * Returns true if the given path is related to a spec file.
7
+ * Matches planu/specs/** or files matching common spec patterns.
8
+ */
9
+ export declare function isSpecRelatedFile(path: string): boolean;
10
+ /**
11
+ * Returns true if the given path is security-sensitive.
12
+ * Detects .env files, auth/config/secrets paths, etc.
13
+ */
14
+ export declare function isSecuritySensitiveFilePath(path: string): boolean;
15
+ /**
16
+ * Compute drift score as a ratio of changed spec criteria to total criteria.
17
+ * specCriteria: total number of acceptance criteria
18
+ * fileIndex: number of spec-related changed files
19
+ */
20
+ export declare function computeDriftScore(specCriteria: number, fileIndex: number): number;
21
+ /**
22
+ * Find security-sensitive paths among changed files.
23
+ */
24
+ export declare function detectSecuritySensitivePaths(changedFiles: string[]): string[];
25
+ /**
26
+ * Get the cached result from the last push check run.
27
+ */
28
+ export declare function getLastPushCheckResult(): WorkerRunResult | null;
29
+ /**
30
+ * Reset the push check result cache.
31
+ * Useful for testing.
32
+ */
33
+ export declare function resetPushCheckCache(): void;
34
+ /**
35
+ * Handle on-push-check event.
36
+ * Performs drift detection and security-sensitive path detection.
37
+ * Caches results as WorkerRunResult and emits WorkerFindings via console.warn.
38
+ * Fire-and-forget — all errors are caught with console.warn.
39
+ */
40
+ export declare function handleOnPushCheck(event: WatcherEvent, projectPath: string, driftThreshold?: number): Promise<void>;
41
+ //# sourceMappingURL=on-push-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-push-check.d.ts","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-push-check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,2BAA2B,CAAC;AA4BhF,mCAAmC;AACnC,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAY3C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKvD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjE;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKjF;AAMD;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE7E;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,GAAG,IAAI,CAE/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,EACnB,cAAc,SAA0B,GACvC,OAAO,CAAC,IAAI,CAAC,CA4Ef"}
@@ -0,0 +1,163 @@
1
+ // engine/hooks/handlers/on-push-check.ts — on-push-check hook handler (SPEC-138)
2
+ // Drift detection on spec-related commits during push events.
3
+ // ---------------------------------------------------------------------------
4
+ // Constants
5
+ // ---------------------------------------------------------------------------
6
+ const SPEC_PATH_PREFIX = 'planu/specs/';
7
+ const SPEC_FILE_PATTERNS = [
8
+ /spec\.md$/,
9
+ /technical\.md$/,
10
+ /progress\.md$/,
11
+ /SPEC-\d+/,
12
+ /\.spec\.(ts|js|tsx|jsx)$/,
13
+ ];
14
+ const SECURITY_KEYWORDS = [
15
+ '.env',
16
+ 'auth',
17
+ 'config',
18
+ 'secret',
19
+ 'credential',
20
+ 'password',
21
+ 'token',
22
+ 'key',
23
+ 'private',
24
+ ];
25
+ /** Default drift threshold: 10% */
26
+ export const DEFAULT_DRIFT_THRESHOLD = 0.1;
27
+ // ---------------------------------------------------------------------------
28
+ // Module-level cache
29
+ // ---------------------------------------------------------------------------
30
+ let lastPushCheckResult = null;
31
+ // ---------------------------------------------------------------------------
32
+ // Path classification
33
+ // ---------------------------------------------------------------------------
34
+ /**
35
+ * Returns true if the given path is related to a spec file.
36
+ * Matches planu/specs/** or files matching common spec patterns.
37
+ */
38
+ export function isSpecRelatedFile(path) {
39
+ if (path.startsWith(SPEC_PATH_PREFIX)) {
40
+ return true;
41
+ }
42
+ return SPEC_FILE_PATTERNS.some((pattern) => pattern.test(path));
43
+ }
44
+ /**
45
+ * Returns true if the given path is security-sensitive.
46
+ * Detects .env files, auth/config/secrets paths, etc.
47
+ */
48
+ export function isSecuritySensitiveFilePath(path) {
49
+ const lower = path.toLowerCase();
50
+ return SECURITY_KEYWORDS.some((keyword) => lower.includes(keyword));
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Drift computation
54
+ // ---------------------------------------------------------------------------
55
+ /**
56
+ * Compute drift score as a ratio of changed spec criteria to total criteria.
57
+ * specCriteria: total number of acceptance criteria
58
+ * fileIndex: number of spec-related changed files
59
+ */
60
+ export function computeDriftScore(specCriteria, fileIndex) {
61
+ if (specCriteria <= 0) {
62
+ return 0;
63
+ }
64
+ return Math.min(1, fileIndex / specCriteria);
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Security detection
68
+ // ---------------------------------------------------------------------------
69
+ /**
70
+ * Find security-sensitive paths among changed files.
71
+ */
72
+ export function detectSecuritySensitivePaths(changedFiles) {
73
+ return changedFiles.filter((f) => isSecuritySensitiveFilePath(f));
74
+ }
75
+ // ---------------------------------------------------------------------------
76
+ // Cache accessors
77
+ // ---------------------------------------------------------------------------
78
+ /**
79
+ * Get the cached result from the last push check run.
80
+ */
81
+ export function getLastPushCheckResult() {
82
+ return lastPushCheckResult;
83
+ }
84
+ /**
85
+ * Reset the push check result cache.
86
+ * Useful for testing.
87
+ */
88
+ export function resetPushCheckCache() {
89
+ lastPushCheckResult = null;
90
+ }
91
+ // ---------------------------------------------------------------------------
92
+ // Handler
93
+ // ---------------------------------------------------------------------------
94
+ /**
95
+ * Handle on-push-check event.
96
+ * Performs drift detection and security-sensitive path detection.
97
+ * Caches results as WorkerRunResult and emits WorkerFindings via console.warn.
98
+ * Fire-and-forget — all errors are caught with console.warn.
99
+ */
100
+ export function handleOnPushCheck(event, projectPath, driftThreshold = DEFAULT_DRIFT_THRESHOLD) {
101
+ const startedAt = new Date().toISOString();
102
+ const startMs = Date.now();
103
+ try {
104
+ const specRelated = isSpecRelatedFile(event.path);
105
+ console.warn(`[hooks] on-push-check: path=${event.path} type=${event.type} specRelated=${String(specRelated)} project=${projectPath}`);
106
+ const findings = [];
107
+ const changedFiles = [event.path];
108
+ // Drift detection
109
+ if (specRelated) {
110
+ console.warn(`[hooks] on-push-check: spec-related file detected, drift check triggered for ${event.path}`);
111
+ const driftScore = computeDriftScore(10, changedFiles.filter(isSpecRelatedFile).length);
112
+ if (driftScore >= driftThreshold) {
113
+ const driftPct = Math.round(driftScore * 100);
114
+ findings.push({
115
+ severity: 'warning',
116
+ file: event.path,
117
+ message: `Drift detected: ${String(driftPct)}% of spec criteria affected`,
118
+ suggestion: 'Review and reconcile spec documentation',
119
+ category: 'drift',
120
+ });
121
+ console.warn(`[hooks] on-push-check: drift threshold exceeded (${String(driftPct)}%) for ${event.path}`);
122
+ }
123
+ }
124
+ // Security detection
125
+ const sensitivePaths = detectSecuritySensitivePaths(changedFiles);
126
+ for (const sensitivePath of sensitivePaths) {
127
+ findings.push({
128
+ severity: 'high',
129
+ file: sensitivePath,
130
+ message: `Security-sensitive file changed: ${sensitivePath}`,
131
+ suggestion: 'Review changes to security-sensitive files carefully',
132
+ category: 'security',
133
+ });
134
+ console.warn(`[hooks] on-push-check: security-sensitive file detected: ${sensitivePath}`);
135
+ }
136
+ const completedAt = new Date().toISOString();
137
+ lastPushCheckResult = {
138
+ workerName: 'on-push-check',
139
+ startedAt,
140
+ completedAt,
141
+ durationMs: Date.now() - startMs,
142
+ status: 'success',
143
+ findings,
144
+ analyzedFiles: changedFiles.length,
145
+ };
146
+ }
147
+ catch (err) {
148
+ console.warn(`[hooks] on-push-check: unexpected error for ${event.path}`, err);
149
+ const completedAt = new Date().toISOString();
150
+ lastPushCheckResult = {
151
+ workerName: 'on-push-check',
152
+ startedAt,
153
+ completedAt,
154
+ durationMs: Date.now() - startMs,
155
+ status: 'error',
156
+ findings: [],
157
+ error: String(err),
158
+ analyzedFiles: 0,
159
+ };
160
+ }
161
+ return Promise.resolve();
162
+ }
163
+ //# sourceMappingURL=on-push-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-push-check.js","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-push-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { WatcherEvent } from '../../../types/file-hooks.js';
2
+ import type { WorkerRunResult, WorkerFinding } from '../../../types/workers.js';
3
+ /**
4
+ * Returns true if the given path contains security-sensitive keywords.
5
+ */
6
+ export declare function isSecuritySensitiveFile(path: string): boolean;
7
+ /**
8
+ * Returns true if the given path is a dependency manifest or lockfile.
9
+ */
10
+ export declare function isDependencyFile(path: string): boolean;
11
+ /**
12
+ * Returns true if the security check is currently in cooldown.
13
+ */
14
+ export declare function isInCooldown(): boolean;
15
+ /**
16
+ * Returns remaining cooldown time in seconds (0 if not in cooldown).
17
+ */
18
+ export declare function getCooldownRemainingSeconds(): number;
19
+ /**
20
+ * Reset the security cooldown timestamp.
21
+ * Useful for testing.
22
+ */
23
+ export declare function resetSecurityCooldown(): void;
24
+ /**
25
+ * Build WorkerFindings for dependency file changes.
26
+ */
27
+ export declare function buildDependencyHealthFindings(depFiles: string[]): WorkerFinding[];
28
+ /**
29
+ * Get the cached result from the last security check run.
30
+ */
31
+ export declare function getLastSecurityCheckResult(): WorkerRunResult | null;
32
+ /**
33
+ * Reset the security check result cache.
34
+ * Useful for testing.
35
+ */
36
+ export declare function resetSecurityCheckCache(): void;
37
+ /**
38
+ * Handle on-security-check event for security-sensitive file changes.
39
+ * Implements a 5-minute cooldown to avoid repeated alerts.
40
+ * Also detects dependency file changes and emits dependency-health findings.
41
+ * Caches results as WorkerRunResult.
42
+ * Fire-and-forget — all errors are caught with console.warn.
43
+ */
44
+ export declare function handleOnSecurityCheck(event: WatcherEvent, projectPath: string): Promise<void>;
45
+ //# sourceMappingURL=on-security-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-security-check.d.ts","sourceRoot":"","sources":["../../../../src/engine/hooks/handlers/on-security-check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AA+ChF;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGtD;AAMD;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAKtC;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAMpD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAMD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAQjF;AAMD;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,eAAe,GAAG,IAAI,CAEnE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAMD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6D7F"}