pumuki-ast-hooks 5.6.4 → 5.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -5
- package/docs/images/ai-start.png +0 -0
- package/docs/images/ai_gate.png +0 -0
- package/docs/images/pre-flight-check.png +0 -0
- package/hooks/pre-tool-use-guard.ts +105 -1
- package/package.json +2 -2
- package/scripts/hooks-system/.audit-reports/auto-recovery.log +3 -0
- package/scripts/hooks-system/.audit-reports/install-wizard.log +12 -0
- package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +72 -0
- package/scripts/hooks-system/bin/__tests__/cli-audit-no-stack.spec.js +22 -0
- package/scripts/hooks-system/bin/cli.js +176 -7
- package/scripts/hooks-system/bin/update-evidence.sh +8 -0
- package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidSOLIDAnalyzer.js +33 -5
- package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +7 -1
- package/scripts/hooks-system/infrastructure/ast/common/__tests__/ast-common.spec.js +19 -0
- package/scripts/hooks-system/infrastructure/ast/common/ast-common.js +24 -19
- package/scripts/hooks-system/infrastructure/ast/ios/__tests__/forbidden-testable-import.spec.js +21 -0
- package/scripts/hooks-system/infrastructure/ast/ios/__tests__/missing-makesut-leaks.spec.js +64 -0
- package/scripts/hooks-system/infrastructure/ast/ios/ast-ios.js +74 -33
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/__tests__/ios-encapsulation-public-mutable.spec.js +63 -0
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/__tests__/ios-unused-imports.spec.js +34 -0
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js +15 -2
- package/scripts/hooks-system/infrastructure/mcp/__tests__/preflight-check-blocks-tests.spec.js +14 -0
- package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +154 -50
- package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js +39 -1
- package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +67 -0
- package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +9 -0
package/README.md
CHANGED
|
@@ -100,6 +100,9 @@ Pumuki addresses these issues by **removing trust from the AI** and replacing it
|
|
|
100
100
|
* **In-Memory AST Analysis**: `analyzeCodeInMemory()` for proposed code validation
|
|
101
101
|
* **IDE Hooks**: Real-time blocking in Windsurf, Claude Code, OpenCode
|
|
102
102
|
|
|
103
|
+
<img src="./assets/Hook_02.png" alt="Windsurf pre-write hook output" width="100%" />
|
|
104
|
+
|
|
105
|
+
<img src="./assets/Hook_01.png" alt="Windsurf post-write hook output" width="100%" />
|
|
103
106
|
### NEW: MCP Integration
|
|
104
107
|
|
|
105
108
|
* **MCP Server**: Full Model Context Protocol integration
|
|
@@ -107,6 +110,8 @@ Pumuki addresses these issues by **removing trust from the AI** and replacing it
|
|
|
107
110
|
* **pre_flight_check**: Validate proposed code before writing
|
|
108
111
|
* **set_human_intent**: Track user goals across sessions
|
|
109
112
|
|
|
113
|
+

|
|
114
|
+
|
|
110
115
|
### NEW: Cognitive Layers
|
|
111
116
|
|
|
112
117
|
* **Human Intent**: Persistent user goal tracking with confidence levels
|
|
@@ -122,15 +127,15 @@ Pumuki addresses these issues by **removing trust from the AI** and replacing it
|
|
|
122
127
|
|
|
123
128
|
## Visual Overview
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+

|
|
126
131
|
|
|
127
|
-
|
|
132
|
+

|
|
128
133
|
|
|
129
|
-
|
|
134
|
+

|
|
130
135
|
|
|
131
|
-
|
|
136
|
+

|
|
132
137
|
|
|
133
|
-
|
|
138
|
+

|
|
134
139
|
|
|
135
140
|
---
|
|
136
141
|
|
|
@@ -251,6 +256,7 @@ if (result.hasCritical) {
|
|
|
251
256
|
* Detect critical violations before code is written
|
|
252
257
|
* Platform-aware analysis (iOS, Android, Backend, Frontend)
|
|
253
258
|
* Integration with IDE hooks for real-time blocking
|
|
259
|
+

|
|
254
260
|
|
|
255
261
|
---
|
|
256
262
|
|
|
@@ -345,6 +351,26 @@ AI generates code → IDE Hook intercepts → AST Intelligence analyzes →
|
|
|
345
351
|
|
|
346
352
|
> **Note**: For IDEs without pre-write hooks, the Git pre-commit hook provides 100% enforcement at commit time.
|
|
347
353
|
|
|
354
|
+
### PreToolUse Guard (`hooks/pre-tool-use-guard.ts`)
|
|
355
|
+
|
|
356
|
+
This repository includes a **PreToolUse guard hook** that runs *before* `Edit` / `Write` / `MultiEdit` operations (where supported by the IDE integration).
|
|
357
|
+
|
|
358
|
+
When it runs:
|
|
359
|
+
|
|
360
|
+
* In IDEs that support **PreToolUse** interception (e.g. Claude Code integrations)
|
|
361
|
+
* Before code is written to disk
|
|
362
|
+
|
|
363
|
+
What it does:
|
|
364
|
+
|
|
365
|
+
* Analyzes the **proposed code** using `analyzeCodeInMemory()`.
|
|
366
|
+
* If the IDE only provides **partial diffs** (`tool_input.edits`), the hook reconstructs the final candidate file content by applying `old_string → new_string` edits over the current file content, then analyzes the result.
|
|
367
|
+
* **Blocks** the operation when **CRITICAL/HIGH** violations are detected (exit code `2`).
|
|
368
|
+
|
|
369
|
+
Why it exists:
|
|
370
|
+
|
|
371
|
+
* To ensure **enforcement happens before write**, not only at commit time.
|
|
372
|
+
* To prevent silent injection of high-impact patterns (e.g. empty `catch {}`) during AI-assisted edits.
|
|
373
|
+
|
|
348
374
|
See [`scripts/hooks-system/infrastructure/cascade-hooks/README.md`](./scripts/hooks-system/infrastructure/cascade-hooks/README.md) for installation instructions.
|
|
349
375
|
|
|
350
376
|
---
|
|
@@ -384,6 +410,23 @@ Initialize AI evidence:
|
|
|
384
410
|
npx ai-start
|
|
385
411
|
```
|
|
386
412
|
|
|
413
|
+
### What is `ai-start` and when should you run it?
|
|
414
|
+
|
|
415
|
+
`ai-start` refreshes the project AI context and updates `.AI_EVIDENCE.json` so the system has a **fresh, auditable source of truth** before any AI-assisted work.
|
|
416
|
+
|
|
417
|
+
Run it when:
|
|
418
|
+
|
|
419
|
+
* **Starting a new day/session** (fresh context)
|
|
420
|
+
* **After pulling a lot of changes** (context drift prevention)
|
|
421
|
+
* **After fixing blocking violations** (to refresh gate + evidence)
|
|
422
|
+
|
|
423
|
+
What it does:
|
|
424
|
+
|
|
425
|
+
* Detects active platforms (iOS/Android/Backend/Frontend)
|
|
426
|
+
* Refreshes the evidence file (`.AI_EVIDENCE.json`)
|
|
427
|
+
* Helps the AI gate operate deterministically (block/allow)
|
|
428
|
+
|
|
429
|
+

|
|
387
430
|
---
|
|
388
431
|
|
|
389
432
|
## Installation & Lifecycle Commands
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync, existsSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
4
7
|
|
|
5
8
|
interface ToolInput {
|
|
6
9
|
tool_name: string;
|
|
@@ -9,6 +12,10 @@ interface ToolInput {
|
|
|
9
12
|
target_file?: string;
|
|
10
13
|
contents?: string;
|
|
11
14
|
new_string?: string;
|
|
15
|
+
edits?: Array<{
|
|
16
|
+
old_string?: string;
|
|
17
|
+
new_string?: string;
|
|
18
|
+
}>;
|
|
12
19
|
};
|
|
13
20
|
}
|
|
14
21
|
|
|
@@ -58,6 +65,39 @@ function matchesPathPattern(filePath: string, patterns: string[]): boolean {
|
|
|
58
65
|
return false;
|
|
59
66
|
}
|
|
60
67
|
|
|
68
|
+
function resolveFilePath(projectDir: string, filePath: string): string {
|
|
69
|
+
if (!filePath) return filePath;
|
|
70
|
+
if (filePath.startsWith('/')) return filePath;
|
|
71
|
+
return join(projectDir, filePath);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function applyStringEdits(baseContent: string, edits: Array<{ old_string?: string; new_string?: string }>): {
|
|
75
|
+
content: string;
|
|
76
|
+
appliedCount: number;
|
|
77
|
+
} {
|
|
78
|
+
let content = baseContent;
|
|
79
|
+
let appliedCount = 0;
|
|
80
|
+
|
|
81
|
+
for (const edit of edits) {
|
|
82
|
+
const oldStr = edit?.old_string;
|
|
83
|
+
const newStr = edit?.new_string;
|
|
84
|
+
if (!newStr) continue;
|
|
85
|
+
|
|
86
|
+
if (oldStr && content.includes(oldStr)) {
|
|
87
|
+
content = content.replace(oldStr, newStr);
|
|
88
|
+
appliedCount += 1;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// If we can't locate old_string (or it's missing), we cannot safely place the change.
|
|
93
|
+
// Best-effort fallback: append to end so AST still sees the new code.
|
|
94
|
+
content = `${content}\n${newStr}`;
|
|
95
|
+
appliedCount += 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { content, appliedCount };
|
|
99
|
+
}
|
|
100
|
+
|
|
61
101
|
function shouldSkip(skipConditions?: SkipConditions, filePath?: string): boolean {
|
|
62
102
|
if (!skipConditions) {
|
|
63
103
|
return false;
|
|
@@ -94,7 +134,71 @@ async function main() {
|
|
|
94
134
|
}
|
|
95
135
|
|
|
96
136
|
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
97
|
-
const
|
|
137
|
+
const resolvedFilePath = resolveFilePath(projectDir, filePath);
|
|
138
|
+
|
|
139
|
+
const proposedCodeDirect = (input.tool_input?.contents || input.tool_input?.new_string || '').trim();
|
|
140
|
+
const isTestFile = /\.(spec|test)\.(js|ts|swift|kt)$/i.test(resolvedFilePath);
|
|
141
|
+
|
|
142
|
+
let candidateCode = proposedCodeDirect;
|
|
143
|
+
if (!candidateCode) {
|
|
144
|
+
const edits = Array.isArray(input.tool_input?.edits) ? input.tool_input.edits : [];
|
|
145
|
+
if (edits.length > 0) {
|
|
146
|
+
let baseContent = '';
|
|
147
|
+
try {
|
|
148
|
+
if (existsSync(resolvedFilePath)) {
|
|
149
|
+
baseContent = readFileSync(resolvedFilePath, 'utf8');
|
|
150
|
+
}
|
|
151
|
+
} catch {
|
|
152
|
+
baseContent = '';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const applied = applyStringEdits(baseContent, edits);
|
|
156
|
+
candidateCode = (applied.content || '').trim();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!isTestFile && candidateCode.length > 0) {
|
|
161
|
+
try {
|
|
162
|
+
const { analyzeCodeInMemory } = require(join(projectDir, 'scripts', 'hooks-system', 'infrastructure', 'ast', 'ast-core'));
|
|
163
|
+
const analysis = analyzeCodeInMemory(candidateCode, resolvedFilePath);
|
|
164
|
+
if (analysis && (analysis.hasCritical || analysis.hasHigh)) {
|
|
165
|
+
const violations = Array.isArray(analysis.violations)
|
|
166
|
+
? analysis.violations.filter((v: unknown) => {
|
|
167
|
+
if (!v || typeof v !== 'object') return false;
|
|
168
|
+
const severity = (v as { severity?: unknown }).severity;
|
|
169
|
+
return severity === 'CRITICAL' || severity === 'HIGH';
|
|
170
|
+
})
|
|
171
|
+
: [];
|
|
172
|
+
|
|
173
|
+
const message = [
|
|
174
|
+
'',
|
|
175
|
+
'🚫 AST INTELLIGENCE BLOCKED THIS WRITE',
|
|
176
|
+
`File: ${resolvedFilePath}`,
|
|
177
|
+
...violations.map((v: unknown) => {
|
|
178
|
+
const obj = (v && typeof v === 'object')
|
|
179
|
+
? (v as { ruleId?: unknown; rule?: unknown; message?: unknown })
|
|
180
|
+
: {};
|
|
181
|
+
const ruleId = (typeof obj.ruleId === 'string' && obj.ruleId.length > 0)
|
|
182
|
+
? obj.ruleId
|
|
183
|
+
: (typeof obj.rule === 'string' && obj.rule.length > 0)
|
|
184
|
+
? obj.rule
|
|
185
|
+
: 'unknown';
|
|
186
|
+
const message = typeof obj.message === 'string' ? obj.message : '';
|
|
187
|
+
return ` ❌ [${ruleId}] ${message}`;
|
|
188
|
+
}),
|
|
189
|
+
''
|
|
190
|
+
].join('\n');
|
|
191
|
+
process.stderr.write(message);
|
|
192
|
+
process.exit(2);
|
|
193
|
+
}
|
|
194
|
+
} catch (error) {
|
|
195
|
+
if (process.env.DEBUG) {
|
|
196
|
+
process.stderr.write(`PreToolUse AST check failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const { getSkillRulesPath } = await import('./getSkillRulesPath.ts');
|
|
98
202
|
const rulesPath = getSkillRulesPath(projectDir);
|
|
99
203
|
|
|
100
204
|
if (!rulesPath || !existsSync(rulesPath)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "5.6.
|
|
3
|
+
"version": "5.6.6",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -134,4 +134,4 @@
|
|
|
134
134
|
"./skills": "./skills/skill-rules.json",
|
|
135
135
|
"./hooks": "./hooks/index.js"
|
|
136
136
|
}
|
|
137
|
-
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
{"timestamp":"2026-01-11T00:41:26.979Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
2
|
+
{"timestamp":"2026-01-11T00:47:24.400Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
3
|
+
{"timestamp":"2026-01-11T00:48:07.599Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{"timestamp":"2026-01-11T00:41:26.266Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
|
|
2
|
+
{"timestamp":"2026-01-11T00:41:26.274Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
|
|
3
|
+
{"timestamp":"2026-01-11T00:41:26.275Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
|
|
4
|
+
{"timestamp":"2026-01-11T00:41:26.275Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
5
|
+
{"timestamp":"2026-01-11T00:47:24.957Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
|
|
6
|
+
{"timestamp":"2026-01-11T00:47:24.965Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
|
|
7
|
+
{"timestamp":"2026-01-11T00:47:24.965Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
|
|
8
|
+
{"timestamp":"2026-01-11T00:47:24.965Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
9
|
+
{"timestamp":"2026-01-11T00:48:08.380Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
|
|
10
|
+
{"timestamp":"2026-01-11T00:48:08.399Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
|
|
11
|
+
{"timestamp":"2026-01-11T00:48:08.400Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
|
|
12
|
+
{"timestamp":"2026-01-11T00:48:08.400Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
@@ -230,3 +230,75 @@
|
|
|
230
230
|
{"timestamp":1768038658259,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
231
231
|
{"timestamp":1768038658259,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
232
232
|
{"timestamp":1768038658259,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
233
|
+
{"timestamp":1768092086977,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
234
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
235
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
236
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
237
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
238
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
239
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
240
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
241
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
242
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
243
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
244
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
245
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
246
|
+
{"timestamp":1768092086978,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
247
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
248
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
249
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
250
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
251
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
252
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
253
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
254
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
255
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
256
|
+
{"timestamp":1768092086979,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
257
|
+
{"timestamp":1768092444397,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
258
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
259
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
260
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
261
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
262
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
263
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
264
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
265
|
+
{"timestamp":1768092444398,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
266
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
267
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
268
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
269
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
270
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
271
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
272
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
273
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
274
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
275
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
276
|
+
{"timestamp":1768092444399,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
277
|
+
{"timestamp":1768092444400,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
278
|
+
{"timestamp":1768092444400,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
279
|
+
{"timestamp":1768092444400,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
280
|
+
{"timestamp":1768092444400,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
281
|
+
{"timestamp":1768092487594,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
282
|
+
{"timestamp":1768092487595,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
283
|
+
{"timestamp":1768092487595,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
284
|
+
{"timestamp":1768092487595,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
285
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
286
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
287
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
288
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
289
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
290
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
291
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
292
|
+
{"timestamp":1768092487596,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
293
|
+
{"timestamp":1768092487597,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
294
|
+
{"timestamp":1768092487597,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
295
|
+
{"timestamp":1768092487597,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
296
|
+
{"timestamp":1768092487597,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
297
|
+
{"timestamp":1768092487597,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
298
|
+
{"timestamp":1768092487598,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
299
|
+
{"timestamp":1768092487598,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
300
|
+
{"timestamp":1768092487598,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
301
|
+
{"timestamp":1768092487598,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
302
|
+
{"timestamp":1768092487598,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
303
|
+
{"timestamp":1768092487599,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
304
|
+
{"timestamp":1768092487599,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
jest.mock('child_process', () => ({
|
|
2
|
+
execSync: jest.fn(() => {
|
|
3
|
+
const err = new Error('audit failed');
|
|
4
|
+
err.status = 1;
|
|
5
|
+
throw err;
|
|
6
|
+
})
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
describe('cli audit', () => {
|
|
10
|
+
it('exits with the same status instead of throwing a stacktrace', () => {
|
|
11
|
+
const cli = require('../cli.js');
|
|
12
|
+
|
|
13
|
+
const exitSpy = jest.spyOn(process, 'exit').mockImplementation((code) => {
|
|
14
|
+
throw new Error(`process.exit:${code}`);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
expect(() => cli.commands.audit()).toThrow('process.exit:1');
|
|
18
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
19
|
+
|
|
20
|
+
exitSpy.mockRestore();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -47,6 +47,89 @@ function resolveRepoRoot() {
|
|
|
47
47
|
return process.cwd();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function getCurrentBranchSafe() {
|
|
51
|
+
try {
|
|
52
|
+
const output = execSync('git branch --show-current', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
53
|
+
return output.trim() || null;
|
|
54
|
+
} catch (e) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getStagedFilesSafe() {
|
|
60
|
+
try {
|
|
61
|
+
const output = execSync('git diff --cached --name-only', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
62
|
+
return output.trim().split('\n').filter(Boolean);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function proposeHumanIntent({ evidence, branch, stagedFiles }) {
|
|
69
|
+
const safeEvidence = (evidence && typeof evidence === 'object') ? evidence : {};
|
|
70
|
+
const safeBranch = branch || safeEvidence.current_context?.current_branch || 'unknown';
|
|
71
|
+
const staged = Array.isArray(stagedFiles) ? stagedFiles : [];
|
|
72
|
+
|
|
73
|
+
const detectedPlatforms = ['ios', 'android', 'backend', 'frontend']
|
|
74
|
+
.filter(p => safeEvidence.platforms && safeEvidence.platforms[p] && safeEvidence.platforms[p].detected);
|
|
75
|
+
|
|
76
|
+
const gateStatus = safeEvidence.ai_gate?.status || safeEvidence.severity_metrics?.gate_status || 'unknown';
|
|
77
|
+
|
|
78
|
+
const branchLower = String(safeBranch).toLowerCase();
|
|
79
|
+
const hasIosTouch = staged.some(f => String(f).toLowerCase().endsWith('.swift')) || detectedPlatforms.includes('ios');
|
|
80
|
+
const hasAndroidTouch = staged.some(f => /\.(kt|kts|java)$/i.test(String(f))) || detectedPlatforms.includes('android');
|
|
81
|
+
const hasBackendTouch = staged.some(f => String(f).toLowerCase().includes('backend') || String(f).toLowerCase().includes('services/')) || detectedPlatforms.includes('backend');
|
|
82
|
+
const hasFrontendTouch = staged.some(f => String(f).toLowerCase().includes('frontend') || /\.(tsx?|jsx?)$/i.test(String(f))) || detectedPlatforms.includes('frontend');
|
|
83
|
+
|
|
84
|
+
const platforms = [
|
|
85
|
+
hasIosTouch ? 'ios' : null,
|
|
86
|
+
hasAndroidTouch ? 'android' : null,
|
|
87
|
+
hasBackendTouch ? 'backend' : null,
|
|
88
|
+
hasFrontendTouch ? 'frontend' : null
|
|
89
|
+
].filter(Boolean);
|
|
90
|
+
|
|
91
|
+
const platformLabel = platforms.length > 0 ? platforms.join('+') : (detectedPlatforms.length > 0 ? detectedPlatforms.join('+') : 'repo');
|
|
92
|
+
|
|
93
|
+
let primaryGoal = `Continue work on ${platformLabel} changes`;
|
|
94
|
+
if (gateStatus === 'BLOCKED') {
|
|
95
|
+
primaryGoal = `Unblock AI gate by fixing ${platformLabel} violations`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (branchLower.startsWith('fix/') || branchLower.startsWith('bugfix/') || branchLower.startsWith('hotfix/')) {
|
|
99
|
+
primaryGoal = gateStatus === 'BLOCKED'
|
|
100
|
+
? `Unblock AI gate by fixing ${platformLabel} violations (bugfix)`
|
|
101
|
+
: `Fix ${platformLabel} issues on ${safeBranch}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const secondary = [];
|
|
105
|
+
if (gateStatus === 'BLOCKED') {
|
|
106
|
+
secondary.push('Fix HIGH/CRITICAL violations first');
|
|
107
|
+
}
|
|
108
|
+
if (platforms.includes('ios')) {
|
|
109
|
+
secondary.push('Keep tests compliant (makeSUT + trackForMemoryLeaks)');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const constraints = [];
|
|
113
|
+
constraints.push('Do not bypass hooks (--no-verify)');
|
|
114
|
+
constraints.push('Follow platform rules (rules*.mdc)');
|
|
115
|
+
|
|
116
|
+
const confidence = platforms.length > 0 || detectedPlatforms.length > 0 ? 'medium' : 'low';
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
primary_goal: primaryGoal,
|
|
120
|
+
secondary_goals: secondary,
|
|
121
|
+
non_goals: [],
|
|
122
|
+
constraints,
|
|
123
|
+
confidence_level: confidence,
|
|
124
|
+
derived_from: {
|
|
125
|
+
branch: safeBranch,
|
|
126
|
+
staged_files_count: staged.length,
|
|
127
|
+
platforms: platforms.length > 0 ? platforms : detectedPlatforms,
|
|
128
|
+
gate_status: gateStatus
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
50
133
|
function buildHealthSnapshot() {
|
|
51
134
|
const repoRoot = resolveRepoRoot();
|
|
52
135
|
const result = {
|
|
@@ -136,7 +219,55 @@ function buildHealthSnapshot() {
|
|
|
136
219
|
|
|
137
220
|
const commands = {
|
|
138
221
|
audit: () => {
|
|
139
|
-
|
|
222
|
+
try {
|
|
223
|
+
execSync(`bash ${path.join(HOOKS_ROOT, 'presentation/cli/audit.sh')}`, { stdio: 'inherit' });
|
|
224
|
+
} catch (err) {
|
|
225
|
+
const status = (err && typeof err.status === 'number') ? err.status : 1;
|
|
226
|
+
process.exit(status);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
'wrap-up': () => {
|
|
231
|
+
commands['evidence:full-update']();
|
|
232
|
+
try {
|
|
233
|
+
const repoRoot = resolveRepoRoot();
|
|
234
|
+
const evidencePath = path.join(repoRoot, '.AI_EVIDENCE.json');
|
|
235
|
+
if (!fs.existsSync(evidencePath)) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let evidence = {};
|
|
240
|
+
try {
|
|
241
|
+
evidence = JSON.parse(fs.readFileSync(evidencePath, 'utf8'));
|
|
242
|
+
} catch {
|
|
243
|
+
if (process.env.DEBUG) {
|
|
244
|
+
process.stderr.write('[wrap-up] Failed to parse .AI_EVIDENCE.json\n');
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const branch = getCurrentBranchSafe();
|
|
250
|
+
const stagedFiles = getStagedFilesSafe();
|
|
251
|
+
const proposed = proposeHumanIntent({ evidence, branch, stagedFiles });
|
|
252
|
+
|
|
253
|
+
console.log('\n💡 Suggested Human Intent (proposal only):');
|
|
254
|
+
console.log(` Primary Goal: ${proposed.primary_goal}`);
|
|
255
|
+
console.log(` Secondary: ${(proposed.secondary_goals || []).join(', ') || '(none)'}`);
|
|
256
|
+
console.log(` Constraints: ${(proposed.constraints || []).join(', ') || '(none)'}`);
|
|
257
|
+
console.log(` Confidence: ${proposed.confidence_level || 'unset'}`);
|
|
258
|
+
console.log(` Branch: ${(proposed.derived_from && proposed.derived_from.branch) || '(unknown)'}`);
|
|
259
|
+
console.log(` Gate: ${(proposed.derived_from && proposed.derived_from.gate_status) || '(unknown)'}`);
|
|
260
|
+
|
|
261
|
+
const suggestedCmd = `ast-hooks intent set --goal="${proposed.primary_goal}" --confidence=${proposed.confidence_level || 'medium'} --expires=24h`;
|
|
262
|
+
console.log('\n✅ To apply it, run:');
|
|
263
|
+
console.log(` ${suggestedCmd}`);
|
|
264
|
+
console.log('');
|
|
265
|
+
} catch (error) {
|
|
266
|
+
if (process.env.DEBUG) {
|
|
267
|
+
process.stderr.write(`[wrap-up] Intent suggestion failed: ${error && error.message ? error.message : String(error)}\n`);
|
|
268
|
+
}
|
|
269
|
+
// Best-effort: wrap-up should succeed even if suggestion fails
|
|
270
|
+
}
|
|
140
271
|
},
|
|
141
272
|
|
|
142
273
|
'evidence:update': () => {
|
|
@@ -326,6 +457,38 @@ const commands = {
|
|
|
326
457
|
return;
|
|
327
458
|
}
|
|
328
459
|
|
|
460
|
+
if (subcommand === 'suggest') {
|
|
461
|
+
if (!fs.existsSync(evidencePath)) {
|
|
462
|
+
console.log('❌ No .AI_EVIDENCE.json found');
|
|
463
|
+
process.exit(1);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
let evidence = {};
|
|
467
|
+
try {
|
|
468
|
+
evidence = JSON.parse(fs.readFileSync(evidencePath, 'utf8'));
|
|
469
|
+
} catch (e) {
|
|
470
|
+
console.log(`❌ Failed to read .AI_EVIDENCE.json: ${e.message}`);
|
|
471
|
+
process.exit(1);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const branch = getCurrentBranchSafe();
|
|
475
|
+
const stagedFiles = getStagedFilesSafe();
|
|
476
|
+
const proposed = proposeHumanIntent({ evidence, branch, stagedFiles });
|
|
477
|
+
|
|
478
|
+
console.log('\n💡 Suggested Human Intent (proposal only):');
|
|
479
|
+
console.log(` Primary Goal: ${proposed.primary_goal}`);
|
|
480
|
+
console.log(` Secondary: ${(proposed.secondary_goals || []).join(', ') || '(none)'}`);
|
|
481
|
+
console.log(` Constraints: ${(proposed.constraints || []).join(', ') || '(none)'}`);
|
|
482
|
+
console.log(` Confidence: ${proposed.confidence_level || 'unset'}`);
|
|
483
|
+
console.log(` Branch: ${(proposed.derived_from && proposed.derived_from.branch) || '(unknown)'}`);
|
|
484
|
+
console.log(` Gate: ${(proposed.derived_from && proposed.derived_from.gate_status) || '(unknown)'}`);
|
|
485
|
+
|
|
486
|
+
const suggestedCmd = `ast-hooks intent set --goal="${proposed.primary_goal}" --confidence=${proposed.confidence_level || 'medium'} --expires=24h`;
|
|
487
|
+
console.log('\n✅ To apply it, run:');
|
|
488
|
+
console.log(` ${suggestedCmd}`);
|
|
489
|
+
console.log('');
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
329
492
|
if (subcommand === 'clear') {
|
|
330
493
|
if (!fs.existsSync(evidencePath)) {
|
|
331
494
|
console.log('❌ No .AI_EVIDENCE.json found');
|
|
@@ -350,7 +513,7 @@ const commands = {
|
|
|
350
513
|
return;
|
|
351
514
|
}
|
|
352
515
|
|
|
353
|
-
console.log('❌ Unknown subcommand. Use: show, set, clear');
|
|
516
|
+
console.log('❌ Unknown subcommand. Use: show, suggest, set, clear');
|
|
354
517
|
process.exit(1);
|
|
355
518
|
},
|
|
356
519
|
|
|
@@ -363,24 +526,27 @@ Usage:
|
|
|
363
526
|
|
|
364
527
|
Commands:
|
|
365
528
|
audit Run interactive audit menu
|
|
529
|
+
wrap-up End of day: refresh evidence + propose human intent (no writes)
|
|
366
530
|
ast Run AST Intelligence analysis only
|
|
367
531
|
install Install hooks in new project
|
|
368
532
|
verify-policy Verify --no-verify policy compliance
|
|
369
533
|
progress Show violation progress report
|
|
370
534
|
health Show hook-system health snapshot (JSON)
|
|
371
535
|
gitflow Check Git Flow compliance (check|reset)
|
|
372
|
-
intent Manage human intent (show|set|clear)
|
|
536
|
+
intent Manage human intent (show|suggest|set|clear)
|
|
373
537
|
help Show this help message
|
|
374
538
|
version Show version
|
|
375
539
|
|
|
376
540
|
Examples:
|
|
377
541
|
ast-hooks audit
|
|
542
|
+
ast-hooks wrap-up
|
|
378
543
|
ast-hooks ast
|
|
379
544
|
ast-hooks install
|
|
380
545
|
ast-hooks verify-policy
|
|
381
546
|
ast-hooks progress
|
|
382
547
|
ast-hooks health
|
|
383
548
|
ast-hooks intent show
|
|
549
|
+
ast-hooks intent suggest
|
|
384
550
|
ast-hooks intent set --goal="Implement feature X" --expires=24h
|
|
385
551
|
ast-hooks intent clear
|
|
386
552
|
|
|
@@ -408,9 +574,12 @@ Documentation:
|
|
|
408
574
|
}
|
|
409
575
|
};
|
|
410
576
|
|
|
411
|
-
if (
|
|
412
|
-
commands
|
|
413
|
-
|
|
577
|
+
if (require.main === module) {
|
|
578
|
+
if (!command || !commands[command]) {
|
|
579
|
+
commands.help();
|
|
580
|
+
process.exit(command ? 1 : 0);
|
|
581
|
+
}
|
|
582
|
+
commands[command]();
|
|
414
583
|
}
|
|
415
584
|
|
|
416
|
-
commands
|
|
585
|
+
module.exports = { commands };
|
|
@@ -26,3 +26,11 @@ fi
|
|
|
26
26
|
|
|
27
27
|
AUTO_EVIDENCE_TRIGGER="$AUTO_TRIGGER" AUTO_EVIDENCE_REASON="$AUTO_REASON" AUTO_EVIDENCE_SUMMARY="$AUTO_SUMMARY" \
|
|
28
28
|
node "$CLI" evidence:full-update
|
|
29
|
+
|
|
30
|
+
EXIT_CODE=$?
|
|
31
|
+
if [[ "$EXIT_CODE" -ne 0 ]]; then
|
|
32
|
+
echo " Evidence updated but gate reported violations (exit code: $EXIT_CODE)." >&2
|
|
33
|
+
exit 0
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
exit 0
|