pumuki-ast-hooks 6.1.3 → 6.1.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 CHANGED
@@ -21,6 +21,14 @@ npm run install-hooks
21
21
  npx ast-hooks
22
22
  ```
23
23
 
24
+ Default installation mode is `npm-runtime`.
25
+
26
+ To opt into an embedded runtime copy (`vendored` mode):
27
+
28
+ ```bash
29
+ HOOK_INSTALL_MODE=vendored npm run install-hooks
30
+ ```
31
+
24
32
  ---
25
33
 
26
34
  ## Operational visuals (examples)
@@ -53,14 +61,7 @@ Documentation:
53
61
 
54
62
  - `docs/USAGE.md` (Interactive Menu, non‑interactive `AUDIT_OPTION`, and typical flows)
55
63
  - `CHANGELOG.md` (Release notes and changes)
56
- - Keychain/Security casts are exempted from `ios.types.forbidden_type_cast` to avoid false positives in secure storage implementations.
57
-
58
- Release 6.0.6:
59
- - Keychain/Security casts are exempted from `ios.types.forbidden_type_cast` to avoid false positives in secure storage implementations.
60
- - Staging-only detection now ignores deleted files when building the file list.
61
-
62
- Release 6.0.7:
63
- - God Class detection (backend): baseline-first by default; optional hard cap via env; detector always runs (with or without baseline).
64
+ - `docs/RELEASE_NOTES.md` (Historical release notes)
64
65
 
65
66
  ---
66
67
 
@@ -0,0 +1,50 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+
5
+ function makeTempProject() {
6
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'pumuki-uninstall-'));
7
+ fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify({ name: 'tmp', version: '0.0.0' }));
8
+ fs.mkdirSync(path.join(root, '.ast-intelligence'), { recursive: true });
9
+ fs.writeFileSync(path.join(root, '.AI_EVIDENCE.json'), JSON.stringify({ ok: true }));
10
+ fs.writeFileSync(path.join(root, '.evidence-guard.pid'), '99999');
11
+ fs.writeFileSync(path.join(root, '.evidence-guard.log'), 'log');
12
+
13
+ const gitHooksDir = path.join(root, '.git', 'hooks');
14
+ fs.mkdirSync(gitHooksDir, { recursive: true });
15
+ fs.writeFileSync(path.join(gitHooksDir, 'pre-commit'), 'node_modules/pumuki-ast-hooks/scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh');
16
+ fs.writeFileSync(path.join(gitHooksDir, 'pre-push'), 'node_modules/pumuki-ast-hooks/scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh');
17
+
18
+ return root;
19
+ }
20
+
21
+ describe('ast-uninstall', () => {
22
+ it('should default to dry-run (no deletions)', () => {
23
+ const projectRoot = makeTempProject();
24
+ const { planUninstall, applyUninstall } = require('../uninstall');
25
+
26
+ const plan = planUninstall({ projectRoot });
27
+ expect(Array.isArray(plan.paths)).toBe(true);
28
+ expect(plan.paths.length).toBeGreaterThan(0);
29
+
30
+ const result = applyUninstall({ projectRoot, apply: false, yes: true });
31
+ expect(result.applied).toBe(false);
32
+ expect(fs.existsSync(path.join(projectRoot, '.ast-intelligence'))).toBe(true);
33
+ });
34
+
35
+ it('should delete pumuki artifacts when apply=true', () => {
36
+ const projectRoot = makeTempProject();
37
+ const { applyUninstall } = require('../uninstall');
38
+
39
+ const result = applyUninstall({ projectRoot, apply: true, yes: true });
40
+ expect(result.applied).toBe(true);
41
+
42
+ expect(fs.existsSync(path.join(projectRoot, '.ast-intelligence'))).toBe(false);
43
+ expect(fs.existsSync(path.join(projectRoot, '.AI_EVIDENCE.json'))).toBe(false);
44
+ expect(fs.existsSync(path.join(projectRoot, '.evidence-guard.pid'))).toBe(false);
45
+ expect(fs.existsSync(path.join(projectRoot, '.evidence-guard.log'))).toBe(false);
46
+
47
+ expect(fs.existsSync(path.join(projectRoot, '.git', 'hooks', 'pre-commit'))).toBe(false);
48
+ expect(fs.existsSync(path.join(projectRoot, '.git', 'hooks', 'pre-push'))).toBe(false);
49
+ });
50
+ });
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ function findProjectRoot(startDir) {
7
+ let current = startDir;
8
+ while (current !== '/') {
9
+ if (fs.existsSync(path.join(current, 'package.json'))) {
10
+ return current;
11
+ }
12
+ current = path.dirname(current);
13
+ }
14
+ return startDir;
15
+ }
16
+
17
+ function isPumukiHookContent(content) {
18
+ if (!content) return false;
19
+ const text = String(content);
20
+ return text.includes('pumuki-ast-hooks') ||
21
+ text.includes('AST Intelligence') ||
22
+ text.includes('gitflow-enforcer.sh') ||
23
+ text.includes('Hook-System Git Flow Enforcer');
24
+ }
25
+
26
+ function safeReadFile(filePath) {
27
+ try {
28
+ return fs.readFileSync(filePath, 'utf8');
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+
34
+ function shouldRemoveGitHook(hookPath) {
35
+ if (!fs.existsSync(hookPath)) return false;
36
+ const content = safeReadFile(hookPath);
37
+ return isPumukiHookContent(content);
38
+ }
39
+
40
+ function buildUninstallPlan(projectRoot) {
41
+ const paths = [];
42
+
43
+ const artifactPaths = [
44
+ '.ast-intelligence',
45
+ '.AI_EVIDENCE.json',
46
+ '.evidence-guard.pid',
47
+ '.evidence-guard.log',
48
+ '.audit_tmp',
49
+ '.audit-reports'
50
+ ];
51
+
52
+ for (const rel of artifactPaths) {
53
+ const p = path.join(projectRoot, rel);
54
+ if (fs.existsSync(p)) {
55
+ paths.push(p);
56
+ }
57
+ }
58
+
59
+ const gitHooksDir = path.join(projectRoot, '.git', 'hooks');
60
+ const preCommit = path.join(gitHooksDir, 'pre-commit');
61
+ const prePush = path.join(gitHooksDir, 'pre-push');
62
+
63
+ if (shouldRemoveGitHook(preCommit)) {
64
+ paths.push(preCommit);
65
+ }
66
+ if (shouldRemoveGitHook(prePush)) {
67
+ paths.push(prePush);
68
+ }
69
+
70
+ const vendoredRoot = path.join(projectRoot, 'scripts', 'hooks-system');
71
+ if (fs.existsSync(vendoredRoot)) {
72
+ paths.push(vendoredRoot);
73
+ }
74
+
75
+ const cursorDir = path.join(projectRoot, '.cursor');
76
+ const windsurfDir = path.join(projectRoot, '.windsurf');
77
+ const vscodeDir = path.join(projectRoot, '.vscode');
78
+
79
+ const cursorMcp = path.join(cursorDir, 'mcp.json');
80
+ const windsurfMcp = path.join(windsurfDir, 'mcp.json');
81
+
82
+ if (fs.existsSync(cursorMcp) || fs.existsSync(windsurfMcp)) {
83
+ if (fs.existsSync(cursorDir)) paths.push(cursorDir);
84
+ if (fs.existsSync(windsurfDir)) paths.push(windsurfDir);
85
+ }
86
+
87
+ if (fs.existsSync(vscodeDir)) {
88
+ paths.push(vscodeDir);
89
+ }
90
+
91
+ const unique = Array.from(new Set(paths));
92
+ return {
93
+ projectRoot,
94
+ paths: unique.sort()
95
+ };
96
+ }
97
+
98
+ function removePath(targetPath) {
99
+ if (!fs.existsSync(targetPath)) return;
100
+ const stat = fs.lstatSync(targetPath);
101
+ if (stat.isDirectory()) {
102
+ fs.rmSync(targetPath, { recursive: true, force: true });
103
+ return;
104
+ }
105
+ fs.rmSync(targetPath, { force: true });
106
+ }
107
+
108
+ function stopEvidenceGuard(projectRoot) {
109
+ const pidPath = path.join(projectRoot, '.evidence-guard.pid');
110
+ if (!fs.existsSync(pidPath)) return;
111
+
112
+ const raw = safeReadFile(pidPath);
113
+ const pid = raw ? parseInt(raw.trim(), 10) : NaN;
114
+ if (Number.isNaN(pid)) return;
115
+
116
+ try {
117
+ process.kill(pid, 0);
118
+ } catch {
119
+ return;
120
+ }
121
+
122
+ try {
123
+ process.kill(pid, 'SIGTERM');
124
+ } catch {
125
+ return;
126
+ }
127
+ }
128
+
129
+ function parseArgs(argv) {
130
+ const args = argv.slice(2);
131
+ return {
132
+ apply: args.includes('--apply'),
133
+ dryRun: args.includes('--dry-run') || !args.includes('--apply'),
134
+ yes: args.includes('--yes'),
135
+ help: args.includes('--help') || args.includes('-h'),
136
+ projectRootArg: (() => {
137
+ const p = args.find(a => a.startsWith('--project-root='));
138
+ if (!p) return null;
139
+ return p.split('=').slice(1).join('=');
140
+ })()
141
+ };
142
+ }
143
+
144
+ function printUsage() {
145
+ process.stdout.write(`\nUsage:\n npx ast-uninstall [--dry-run] [--apply] [--yes] [--project-root=/path]\n\nDefaults:\n --dry-run is default (no changes)\n\nExamples:\n npx ast-uninstall\n npx ast-uninstall --apply\n npx ast-uninstall --apply --yes\n npx ast-uninstall --project-root=/path/to/repo\n\n`);
146
+ }
147
+
148
+ function planUninstall({ projectRoot }) {
149
+ return buildUninstallPlan(projectRoot);
150
+ }
151
+
152
+ function applyUninstall({ projectRoot, apply, yes }) {
153
+ const plan = buildUninstallPlan(projectRoot);
154
+
155
+ if (!apply) {
156
+ return { applied: false, plan };
157
+ }
158
+
159
+ if (!yes && process.stdout.isTTY) {
160
+ process.stdout.write('This will delete files from your repository. Re-run with --yes to confirm.\n');
161
+ return { applied: false, plan, needsConfirmation: true };
162
+ }
163
+
164
+ stopEvidenceGuard(projectRoot);
165
+
166
+ for (const p of plan.paths) {
167
+ removePath(p);
168
+ }
169
+
170
+ return { applied: true, plan };
171
+ }
172
+
173
+ function main() {
174
+ const options = parseArgs(process.argv);
175
+
176
+ if (options.help) {
177
+ printUsage();
178
+ process.exit(0);
179
+ }
180
+
181
+ const cwd = process.cwd();
182
+ const rootFromCwd = findProjectRoot(cwd);
183
+ const projectRoot = options.projectRootArg ? path.resolve(options.projectRootArg) : rootFromCwd;
184
+
185
+ const plan = buildUninstallPlan(projectRoot);
186
+
187
+ if (options.dryRun) {
188
+ process.stdout.write(`Project root: ${projectRoot}\n`);
189
+ process.stdout.write('Planned removals:\n');
190
+ for (const p of plan.paths) {
191
+ process.stdout.write(`- ${p}\n`);
192
+ }
193
+ process.exit(0);
194
+ }
195
+
196
+ const result = applyUninstall({ projectRoot, apply: true, yes: options.yes });
197
+
198
+ if (result.needsConfirmation) {
199
+ process.exit(2);
200
+ }
201
+
202
+ process.stdout.write('Uninstall completed.\n');
203
+ process.exit(0);
204
+ }
205
+
206
+ if (require.main === module) {
207
+ main();
208
+ }
209
+
210
+ module.exports = { planUninstall, applyUninstall, findProjectRoot };
@@ -91,6 +91,8 @@ npm install --save-dev pumuki-ast-hooks
91
91
  npm run install-hooks
92
92
  ```
93
93
 
94
+ By default, the installer uses npm-runtime mode (no embedded copy of `scripts/hooks-system` into your project). To use the vendored mode (embedded runtime), run the installer with `HOOK_INSTALL_MODE=vendored`.
95
+
94
96
  ### Option 2: Global Installation
95
97
 
96
98
  ```bash
@@ -231,7 +233,7 @@ cat > .cursor/mcp.json << 'EOF'
231
233
  "ai-evidence-watcher": {
232
234
  "command": "node",
233
235
  "args": [
234
- "${workspaceFolder}/node_modules/pumuki-ast-hooks/infrastructure/mcp/evidence-watcher.js"
236
+ "${workspaceFolder}/node_modules/pumuki-ast-hooks/scripts/hooks-system/infrastructure/mcp/evidence-watcher.js"
235
237
  ],
236
238
  "env": {
237
239
  "REPO_ROOT": "${workspaceFolder}"
@@ -240,7 +242,7 @@ cat > .cursor/mcp.json << 'EOF'
240
242
  "ast-intelligence-automation": {
241
243
  "command": "node",
242
244
  "args": [
243
- "${workspaceFolder}/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js"
245
+ "${workspaceFolder}/node_modules/pumuki-ast-hooks/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js"
244
246
  ],
245
247
  "env": {
246
248
  "REPO_ROOT": "${workspaceFolder}",
@@ -358,6 +360,8 @@ cp node_modules/pumuki-ast-hooks/templates/config/rules.json.template \
358
360
  # Then customize as needed
359
361
  ```
360
362
 
363
+ If you are using npm-runtime mode (default), use `HOOK_INSTALL_MODE=vendored` before re-running the installer to ensure `scripts/hooks-system/config/` exists in your project.
364
+
361
365
  **Note:** Templates are optional. The library works without them using default configurations. Only copy and customize if you need project-specific overrides.
362
366
 
363
367
  ### 7. Configure Exclusions
@@ -653,7 +657,7 @@ npm run install-hooks
653
657
  This ensures:
654
658
  - ✅ Latest Git hooks are installed (with new features)
655
659
  - ✅ Latest MCP server configurations are updated
656
- - ✅ Latest system files are copied to `scripts/hooks-system/`
660
+ - ✅ Latest system files are copied to `scripts/hooks-system/` when using vendored mode
657
661
  - ✅ Any new configuration options are applied
658
662
 
659
663
  **What gets updated:**
package/docs/USAGE.md CHANGED
@@ -12,13 +12,6 @@
12
12
 
13
13
  ---
14
14
 
15
- ## Recent Changes (v6.0.6)
16
-
17
- - Keychain/Security casts are exempted from `ios.types.forbidden_type_cast` to avoid false positives.
18
- - Staging gate evaluation ignores deleted files when assembling the staged file list.
19
-
20
- ---
21
-
22
15
  ## Minimal Example (5 minutes)
23
16
 
24
17
  ### Step 1: Install
@@ -88,10 +81,15 @@ npm run ast:guard:logs
88
81
  Gate scope:
89
82
  ```bash
90
83
  # Default is staging (only staged files)
91
- AI_GATE_SCOPE=staging bash ./scripts/hooks-system/bin/update-evidence.sh --auto
84
+ AI_GATE_SCOPE=staging bash ./node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/update-evidence.sh --auto
92
85
 
93
86
  # Repository-wide gate evaluation
94
- AI_GATE_SCOPE=repo bash ./scripts/hooks-system/bin/update-evidence.sh --auto
87
+ AI_GATE_SCOPE=repo bash ./node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/update-evidence.sh --auto
88
+ ```
89
+
90
+ If you are using vendored mode, you can use:
91
+ ```bash
92
+ AI_GATE_SCOPE=staging bash ./scripts/hooks-system/bin/update-evidence.sh --auto
95
93
  ```
96
94
 
97
95
  ### Interactive Menu (Recommended)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki-ast-hooks",
3
- "version": "6.1.3",
3
+ "version": "6.1.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": {
@@ -8,6 +8,7 @@
8
8
  "audit": "./bin/audit",
9
9
  "ast-hooks": "./bin/cli.js",
10
10
  "ast-install": "./bin/install.js",
11
+ "ast-uninstall": "./bin/uninstall.js",
11
12
  "ast-violations": "./bin/violations-api.js",
12
13
  "ast-check-version": "./bin/check-version.js",
13
14
  "ast-gitflow": "./scripts/hooks-system/bin/gitflow-cycle.js",
@@ -35,3 +35,7 @@
35
35
  {"timestamp":"2026-01-14T10:52:05.241Z","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":{}}
36
36
  {"timestamp":"2026-01-14T10:53:08.625Z","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":{}}
37
37
  {"timestamp":"2026-01-14T10:53:45.774Z","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":{}}
38
+ {"timestamp":"2026-01-14T19:41:34.447Z","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":{}}
39
+ {"timestamp":"2026-01-14T22:23:58.130Z","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":{}}
40
+ {"timestamp":"2026-01-15T07:43:05.309Z","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":{}}
41
+ {"timestamp":"2026-01-15T07:49:00.777Z","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":{}}
@@ -150,3 +150,19 @@
150
150
  {"timestamp":"2026-01-14T10:53:45.937Z","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":{}}
151
151
  {"timestamp":"2026-01-14T10:53:45.939Z","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":{}}
152
152
  {"timestamp":"2026-01-14T10:53:45.939Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
153
+ {"timestamp":"2026-01-14T19:41:34.372Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
154
+ {"timestamp":"2026-01-14T19:41:34.380Z","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":{}}
155
+ {"timestamp":"2026-01-14T19:41:34.380Z","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":{}}
156
+ {"timestamp":"2026-01-14T19:41:34.380Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
157
+ {"timestamp":"2026-01-14T22:23:58.044Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
158
+ {"timestamp":"2026-01-14T22:23:58.052Z","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":{}}
159
+ {"timestamp":"2026-01-14T22:23:58.052Z","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":{}}
160
+ {"timestamp":"2026-01-14T22:23:58.053Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
161
+ {"timestamp":"2026-01-15T07:43:05.408Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
162
+ {"timestamp":"2026-01-15T07:43:05.416Z","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":{}}
163
+ {"timestamp":"2026-01-15T07:43:05.417Z","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":{}}
164
+ {"timestamp":"2026-01-15T07:43:05.417Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
165
+ {"timestamp":"2026-01-15T07:49:00.924Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
166
+ {"timestamp":"2026-01-15T07:49:00.931Z","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":{}}
167
+ {"timestamp":"2026-01-15T07:49:00.931Z","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":{}}
168
+ {"timestamp":"2026-01-15T07:49:00.931Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
@@ -1154,3 +1154,99 @@
1154
1154
  {"timestamp":1768388025774,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1155
1155
  {"timestamp":1768388025774,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1156
1156
  {"timestamp":1768388025774,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1157
+ {"timestamp":1768419694445,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1158
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1159
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1160
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1161
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1162
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1163
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1164
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1165
+ {"timestamp":1768419694446,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1166
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1167
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1168
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1169
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1170
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1171
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1172
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1173
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1174
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1175
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1176
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1177
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1178
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1179
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1180
+ {"timestamp":1768419694447,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1181
+ {"timestamp":1768429438128,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1182
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1183
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1184
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1185
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1186
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1187
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1188
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1189
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1190
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1191
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1192
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1193
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1194
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1195
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1196
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1197
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1198
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1199
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1200
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1201
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1202
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1203
+ {"timestamp":1768429438129,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1204
+ {"timestamp":1768429438130,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1205
+ {"timestamp":1768462985307,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1206
+ {"timestamp":1768462985308,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1207
+ {"timestamp":1768462985308,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1208
+ {"timestamp":1768462985308,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1209
+ {"timestamp":1768462985308,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1210
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1211
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1212
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1213
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1214
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1215
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1216
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1217
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1218
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1219
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1220
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1221
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1222
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1223
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1224
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1225
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1226
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1227
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1228
+ {"timestamp":1768462985309,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1229
+ {"timestamp":1768463340775,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1230
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1231
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1232
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1233
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1234
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1235
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1236
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1237
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1238
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1239
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1240
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1241
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1242
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1243
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1244
+ {"timestamp":1768463340776,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1245
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1246
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1247
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1248
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1249
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
1250
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
1251
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
1252
+ {"timestamp":1768463340777,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
@@ -68,8 +68,12 @@ class ConfigurationGeneratorService {
68
68
  }
69
69
  });
70
70
 
71
- const configPath = path.join(this.targetRoot, 'scripts/hooks-system/config/project.config.json');
72
- // Ensure dir exists just in case
71
+ const installMode = String(env.get('HOOK_INSTALL_MODE', 'npm')).trim().toLowerCase();
72
+ const useVendored = installMode === 'vendored' || installMode === 'embedded';
73
+ const configPath = useVendored
74
+ ? path.join(this.targetRoot, 'scripts/hooks-system/config/project.config.json')
75
+ : path.join(this.targetRoot, '.ast-intelligence/project.config.json');
76
+
73
77
  const configDir = path.dirname(configPath);
74
78
  if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
75
79
 
@@ -107,16 +111,22 @@ class ConfigurationGeneratorService {
107
111
  packageJson.scripts = {};
108
112
  }
109
113
 
110
- // Add helper scripts
111
- packageJson.scripts['ast:refresh'] = 'node scripts/hooks-system/bin/update-evidence.sh';
112
- packageJson.scripts['ast:audit'] = 'node scripts/hooks-system/infrastructure/ast/ast-intelligence.js';
113
- packageJson.scripts['ast:guard:start'] = 'bash scripts/hooks-system/bin/evidence-guard start';
114
- packageJson.scripts['ast:guard:stop'] = 'bash scripts/hooks-system/bin/evidence-guard stop';
115
- packageJson.scripts['ast:guard:restart'] = 'bash scripts/hooks-system/bin/evidence-guard restart';
116
- packageJson.scripts['ast:guard:status'] = 'bash scripts/hooks-system/bin/evidence-guard status';
117
- packageJson.scripts['ast:guard:logs'] = 'bash scripts/hooks-system/bin/evidence-guard logs';
118
- packageJson.scripts['ast:check-version'] = 'node scripts/hooks-system/bin/check-version.js';
119
- packageJson.scripts['ast:gitflow'] = 'node scripts/hooks-system/bin/gitflow-cycle.js';
114
+ const installMode = String(env.get('HOOK_INSTALL_MODE', 'npm')).trim().toLowerCase();
115
+ const useVendored = installMode === 'vendored' || installMode === 'embedded';
116
+
117
+ const base = useVendored
118
+ ? 'scripts/hooks-system'
119
+ : 'node_modules/pumuki-ast-hooks/scripts/hooks-system';
120
+
121
+ packageJson.scripts['ast:refresh'] = `node ${base}/bin/update-evidence.sh`;
122
+ packageJson.scripts['ast:audit'] = `node ${base}/infrastructure/ast/ast-intelligence.js`;
123
+ packageJson.scripts['ast:guard:start'] = `bash ${base}/bin/evidence-guard start`;
124
+ packageJson.scripts['ast:guard:stop'] = `bash ${base}/bin/evidence-guard stop`;
125
+ packageJson.scripts['ast:guard:restart'] = `bash ${base}/bin/evidence-guard restart`;
126
+ packageJson.scripts['ast:guard:status'] = `bash ${base}/bin/evidence-guard status`;
127
+ packageJson.scripts['ast:guard:logs'] = `bash ${base}/bin/evidence-guard logs`;
128
+ packageJson.scripts['ast:check-version'] = `node ${base}/bin/check-version.js`;
129
+ packageJson.scripts['ast:gitflow'] = `node ${base}/bin/gitflow-cycle.js`;
120
130
 
121
131
  fs.writeFileSync(projectPackageJsonPath, JSON.stringify(packageJson, null, 2));
122
132
  this.logSuccess('npm scripts added');
@@ -130,6 +130,10 @@ fi
130
130
 
131
131
  # Enforce Git Flow checks (strict) before allowing commit
132
132
  ENFORCER_SCRIPT="scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh"
133
+ if [[ ! -f "$ENFORCER_SCRIPT" ]]; then
134
+ ENFORCER_SCRIPT="node_modules/pumuki-ast-hooks/scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh"
135
+ fi
136
+
133
137
  if [[ -f "$ENFORCER_SCRIPT" ]]; then
134
138
  echo ""
135
139
  echo "🔍 Running Git Flow checks (strict)..."
@@ -276,6 +280,10 @@ fi
276
280
 
277
281
  # Run gitflow-enforcer if available (optional validation)
278
282
  ENFORCER_SCRIPT="scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh"
283
+ if [[ ! -f "$ENFORCER_SCRIPT" ]]; then
284
+ ENFORCER_SCRIPT="node_modules/pumuki-ast-hooks/scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh"
285
+ fi
286
+
279
287
  if [[ -f "$ENFORCER_SCRIPT" ]]; then
280
288
  echo ""
281
289
  echo "🔍 Running Git Flow checks (strict)..."
@@ -77,6 +77,14 @@ class InstallService {
77
77
  this.ideIntegration = new IdeIntegrationService(this.targetRoot, this.hookSystemRoot, this.logger);
78
78
  }
79
79
 
80
+ getInstallMode() {
81
+ const mode = String(env.get('HOOK_INSTALL_MODE', 'npm')).trim().toLowerCase();
82
+ if (mode === 'vendored' || mode === 'embedded') {
83
+ return 'vendored';
84
+ }
85
+ return 'npm';
86
+ }
87
+
80
88
  checkCriticalDependencies() {
81
89
  CriticalDependenciesService.check({
82
90
  targetRoot: this.targetRoot,
@@ -113,12 +121,18 @@ class InstallService {
113
121
  this.logStep('2/8', 'Installing ESLint configurations...');
114
122
  this.configGenerator.installESLintConfigs();
115
123
 
116
- this.logStep('3/8', 'Creating hooks-system directory structure...');
117
- this.fsInstaller.createDirectoryStructure();
124
+ const installMode = this.getInstallMode();
125
+ if (installMode === 'vendored') {
126
+ this.logStep('3/8', 'Creating hooks-system directory structure...');
127
+ this.fsInstaller.createDirectoryStructure();
118
128
 
119
- this.logStep('4/8', 'Copying AST Intelligence system files...');
120
- this.fsInstaller.copySystemFiles();
121
- this.fsInstaller.copyManageLibraryScript();
129
+ this.logStep('4/8', 'Copying AST Intelligence system files...');
130
+ this.fsInstaller.copySystemFiles();
131
+ this.fsInstaller.copyManageLibraryScript();
132
+ } else {
133
+ this.logStep('3/8', 'Skipping embedded runtime copy (npm-runtime mode)...');
134
+ this.logStep('4/8', 'Skipping embedded system files (npm-runtime mode)...');
135
+ }
122
136
 
123
137
  this.logStep('5/8', 'Creating project configuration...');
124
138
  this.configGenerator.createProjectConfig(platforms);
@@ -148,9 +162,14 @@ class InstallService {
148
162
 
149
163
  startEvidenceGuard() {
150
164
  const { spawn } = require('child_process');
151
- const guardScript = path.join(this.targetRoot, 'scripts/hooks-system/bin/evidence-guard');
165
+ const candidates = [
166
+ path.join(this.targetRoot, 'scripts/hooks-system/bin/evidence-guard'),
167
+ path.join(this.targetRoot, 'node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/evidence-guard')
168
+ ];
169
+
170
+ const guardScript = candidates.find(p => fs.existsSync(p)) || null;
152
171
 
153
- if (!fs.existsSync(guardScript)) {
172
+ if (!guardScript) {
154
173
  this.logWarning('Evidence guard script not found, skipping daemon start');
155
174
  return;
156
175
  }
@@ -241,6 +260,11 @@ ${COLORS.reset}\n`);
241
260
  }
242
261
 
243
262
  printFooter() {
263
+ const installMode = this.getInstallMode();
264
+ const configHint = installMode === 'vendored'
265
+ ? 'scripts/hooks-system/config/project.config.json'
266
+ : '.ast-intelligence/project.config.json';
267
+
244
268
  process.stdout.write(`
245
269
  ${COLORS.green}✨ Installation Complete! ✨${COLORS.reset}
246
270
 
@@ -249,13 +273,8 @@ ${COLORS.cyan}Evidence Guard Daemon:${COLORS.reset}
249
273
  - Manage with: ${COLORS.yellow}npm run ast:guard:{start|stop|status|logs}${COLORS.reset}
250
274
 
251
275
  ${COLORS.cyan}Next Steps:${COLORS.reset}
252
- 1. Review generated configuration in ${COLORS.yellow}scripts/hooks-system/config/project.config.json${COLORS.reset}
253
- 2. Run ${COLORS.yellow}./manage-library.sh verify${COLORS.reset} to check installation
254
- 3. Commit the changes: ${COLORS.yellow}git add . && git commit -m "chore: install ast-intelligence-hooks"${COLORS.reset}
255
-
256
- ${COLORS.blue}Documentation:${COLORS.reset}
257
- - scripts/hooks-system/docs/guides/getting-started.md
258
- - scripts/hooks-system/docs/architecture.md
276
+ 1. Review generated configuration in ${COLORS.yellow}${configHint}${COLORS.reset}
277
+ 2. Commit the changes: ${COLORS.yellow}git add . && git commit -m "chore: install ast-intelligence-hooks"${COLORS.reset}
259
278
  `);
260
279
  }
261
280
 
@@ -0,0 +1,98 @@
1
+ describe('Installation mode (npm-runtime vs vendored)', () => {
2
+ const fs = require('fs');
3
+ const os = require('os');
4
+ const path = require('path');
5
+
6
+ const ConfigurationGeneratorService = require('../../application/services/installation/ConfigurationGeneratorService');
7
+ const InstallService = require('../../application/services/installation/InstallService');
8
+
9
+ const originalEnv = { ...process.env };
10
+
11
+ afterEach(() => {
12
+ process.env = { ...originalEnv };
13
+ });
14
+
15
+ it('ConfigurationGeneratorService.addNpmScripts writes node_modules scripts by default', () => {
16
+ const testRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-hooks-install-mode-'));
17
+ const pkgPath = path.join(testRoot, 'package.json');
18
+ fs.writeFileSync(pkgPath, JSON.stringify({ name: 'test', version: '1.0.0', scripts: {} }, null, 2));
19
+
20
+ const service = new ConfigurationGeneratorService(testRoot, __dirname);
21
+ delete process.env.HOOK_INSTALL_MODE;
22
+
23
+ service.addNpmScripts();
24
+
25
+ const written = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
26
+ expect(written.scripts['ast:audit']).toContain('node_modules/pumuki-ast-hooks');
27
+ expect(written.scripts['ast:guard:start']).toContain('node_modules/pumuki-ast-hooks');
28
+
29
+ fs.rmSync(testRoot, { recursive: true, force: true });
30
+ });
31
+
32
+ it('ConfigurationGeneratorService.addNpmScripts writes vendored scripts when HOOK_INSTALL_MODE=vendored', () => {
33
+ const testRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-hooks-install-mode-'));
34
+ const pkgPath = path.join(testRoot, 'package.json');
35
+ fs.writeFileSync(pkgPath, JSON.stringify({ name: 'test', version: '1.0.0', scripts: {} }, null, 2));
36
+
37
+ const service = new ConfigurationGeneratorService(testRoot, __dirname);
38
+ process.env.HOOK_INSTALL_MODE = 'vendored';
39
+
40
+ service.addNpmScripts();
41
+
42
+ const written = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
43
+ expect(written.scripts['ast:audit']).toContain('scripts/hooks-system');
44
+ expect(written.scripts['ast:guard:start']).toContain('scripts/hooks-system');
45
+
46
+ fs.rmSync(testRoot, { recursive: true, force: true });
47
+ });
48
+
49
+ it('InstallService does not copy system files in npm runtime mode by default', async () => {
50
+ const service = new InstallService();
51
+
52
+ service.gitService = { checkGitRepository: () => true, ensureGitInfoExclude: () => { }, installGitHooks: () => { } };
53
+ service.platformService = { detect: () => ['backend'] };
54
+
55
+ const fsInstaller = {
56
+ createDirectoryStructure: jest.fn(),
57
+ copySystemFiles: jest.fn(),
58
+ copyManageLibraryScript: jest.fn()
59
+ };
60
+
61
+ service.fsInstaller = fsInstaller;
62
+ service.configGenerator = { installESLintConfigs: () => { }, createProjectConfig: () => { }, addNpmScripts: () => { } };
63
+ service.ideIntegration = { installCursorHooks: () => { }, configureVSCodeTasks: () => { } };
64
+ service.checkCriticalDependencies = () => { };
65
+ service.startEvidenceGuard = () => { };
66
+
67
+ delete process.env.HOOK_INSTALL_MODE;
68
+
69
+ await service.run();
70
+
71
+ expect(fsInstaller.copySystemFiles).not.toHaveBeenCalled();
72
+ });
73
+
74
+ it('InstallService copies system files when HOOK_INSTALL_MODE=vendored', async () => {
75
+ const service = new InstallService();
76
+
77
+ service.gitService = { checkGitRepository: () => true, ensureGitInfoExclude: () => { }, installGitHooks: () => { } };
78
+ service.platformService = { detect: () => ['backend'] };
79
+
80
+ const fsInstaller = {
81
+ createDirectoryStructure: jest.fn(),
82
+ copySystemFiles: jest.fn(),
83
+ copyManageLibraryScript: jest.fn()
84
+ };
85
+
86
+ service.fsInstaller = fsInstaller;
87
+ service.configGenerator = { installESLintConfigs: () => { }, createProjectConfig: () => { }, addNpmScripts: () => { } };
88
+ service.ideIntegration = { installCursorHooks: () => { }, configureVSCodeTasks: () => { } };
89
+ service.checkCriticalDependencies = () => { };
90
+ service.startEvidenceGuard = () => { };
91
+
92
+ process.env.HOOK_INSTALL_MODE = 'vendored';
93
+
94
+ await service.run();
95
+
96
+ expect(fsInstaller.copySystemFiles).toHaveBeenCalled();
97
+ });
98
+ });
@@ -432,7 +432,11 @@ const commands = {
432
432
 
433
433
  'gitflow': () => {
434
434
  const subcommand = args[0] || 'check';
435
- execFileSync('bash', [path.join(HOOKS_ROOT, 'infrastructure/shell/gitflow-enforcer.sh'), subcommand], { stdio: 'inherit' });
435
+ let enforcerPath = path.join(HOOKS_ROOT, 'infrastructure/shell/gitflow/gitflow-enforcer.sh');
436
+ if (!fs.existsSync(enforcerPath)) {
437
+ enforcerPath = path.join(HOOKS_ROOT, 'infrastructure/shell/gitflow-enforcer.sh');
438
+ }
439
+ execFileSync('bash', [enforcerPath, subcommand], { stdio: 'inherit' });
436
440
  },
437
441
 
438
442
  'intent': () => {
@@ -6,7 +6,11 @@
6
6
  # =============================================================================
7
7
 
8
8
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
- ENFORCER="${SCRIPT_DIR}/../infrastructure/shell/gitflow-enforcer.sh"
9
+ ENFORCER="${SCRIPT_DIR}/../infrastructure/shell/gitflow/gitflow-enforcer.sh"
10
+
11
+ if [[ ! -f "$ENFORCER" ]]; then
12
+ ENFORCER="${SCRIPT_DIR}/../infrastructure/shell/gitflow-enforcer.sh"
13
+ fi
10
14
 
11
15
  if [[ ! -f "$ENFORCER" ]]; then
12
16
  echo "❌ Error: gitflow-enforcer.sh not found"
@@ -14,4 +18,17 @@ if [[ ! -f "$ENFORCER" ]]; then
14
18
  exit 1
15
19
  fi
16
20
 
17
- bash "$ENFORCER" "${1:-check}"
21
+ SUBCOMMAND="${1:-check}"
22
+ case "$SUBCOMMAND" in
23
+ status)
24
+ SUBCOMMAND="check"
25
+ ;;
26
+ workflow)
27
+ SUBCOMMAND="cycle"
28
+ ;;
29
+ reset)
30
+ SUBCOMMAND="cleanup"
31
+ ;;
32
+ esac
33
+
34
+ bash "$ENFORCER" "$SUBCOMMAND"
@@ -1,8 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const env = require('../config/env');
4
3
  const InstallService = require('../application/services/installation/InstallService');
5
4
 
5
+ const args = process.argv.slice(2);
6
+ if (args.includes('--vendored') || args.includes('--embedded')) {
7
+ process.env.HOOK_INSTALL_MODE = 'vendored';
8
+ }
9
+ if (args.includes('--npm-runtime') || args.includes('--npm')) {
10
+ process.env.HOOK_INSTALL_MODE = 'npm';
11
+ }
12
+
6
13
  // Run installation
7
14
  const installer = new InstallService();
8
15
  installer.run().catch(error => {
@@ -12,6 +12,22 @@ describe('ios.encapsulation.public_mutable', () => {
12
12
  };
13
13
  }
14
14
 
15
+ it('does not flag public private(set) stored property', () => {
16
+ const analyzer = makeAnalyzer();
17
+ const node = {
18
+ 'key.name': 'state',
19
+ 'key.line': 10,
20
+ 'key.kind': 'source.lang.swift.decl.var.instance',
21
+ 'key.accessibility': 'source.lang.swift.accessibility.public'
22
+ };
23
+
24
+ analyzer.getAttributes = () => ['setter_access.private'];
25
+
26
+ analyzePropertyAST(analyzer, node, '/tmp/Foo.swift');
27
+
28
+ expect(analyzer.findings.find(f => f.ruleId === 'ios.encapsulation.public_mutable')).toBeUndefined();
29
+ });
30
+
15
31
  it('does not flag public computed get-only property', () => {
16
32
  const analyzer = makeAnalyzer();
17
33
  const node = {
@@ -457,7 +457,8 @@ function analyzePropertyAST(analyzer, node, filePath) {
457
457
  const isComputed = hasAccessorGet || hasAccessorSet;
458
458
  const isMutable = isComputed ? hasAccessorSet : true;
459
459
 
460
- if (isPublic && isInstance && isMutable && !attributes.includes('setter_access')) {
460
+ const hasSetterAccessRestriction = attributes.some(a => String(a).startsWith('setter_access'));
461
+ if (isPublic && isInstance && isMutable && !hasSetterAccessRestriction) {
461
462
  analyzer.pushFinding('ios.encapsulation.public_mutable', 'medium', filePath, line, `Public mutable property '${name}' - consider private(set)`);
462
463
  }
463
464
  }
@@ -19,7 +19,12 @@ echo ""
19
19
  echo "🔍 Validating Git Flow compliance before push..."
20
20
  echo ""
21
21
 
22
- if ! bash "${HOOKS_SYSTEM_ROOT}/infrastructure/shell/gitflow-enforcer.sh" check; then
22
+ ENFORCER_SCRIPT="${HOOKS_SYSTEM_ROOT}/infrastructure/shell/gitflow/gitflow-enforcer.sh"
23
+ if [[ ! -f "$ENFORCER_SCRIPT" ]]; then
24
+ ENFORCER_SCRIPT="${HOOKS_SYSTEM_ROOT}/infrastructure/shell/gitflow-enforcer.sh"
25
+ fi
26
+
27
+ if ! bash "$ENFORCER_SCRIPT" check; then
23
28
  echo ""
24
29
  echo "🚨 PUSH BLOCKED: Complete Git Flow cycle first"
25
30
  echo ""
@@ -2432,7 +2432,7 @@ async function handleMcpMessage(message) {
2432
2432
  result = suggestHumanIntent();
2433
2433
  break;
2434
2434
  case 'pre_flight_check':
2435
- result = preFlightCheck(toolParams);
2435
+ result = await preFlightCheck(toolParams);
2436
2436
  break;
2437
2437
  case 'record_test_created':
2438
2438
  result = recordTestCreated(toolParams);
@@ -109,3 +109,15 @@
109
109
  {"timestamp":"2026-01-14T10:53:47.998Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
110
110
  {"timestamp":"2026-01-14T10:53:47.999Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
111
111
  {"timestamp":"2026-01-14T10:53:47.999Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
112
+ {"timestamp":"2026-01-14T19:41:36.274Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
113
+ {"timestamp":"2026-01-14T19:41:36.275Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
114
+ {"timestamp":"2026-01-14T19:41:36.275Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
115
+ {"timestamp":"2026-01-14T22:24:01.361Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
116
+ {"timestamp":"2026-01-14T22:24:01.362Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
117
+ {"timestamp":"2026-01-14T22:24:01.362Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
118
+ {"timestamp":"2026-01-15T07:43:06.798Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
119
+ {"timestamp":"2026-01-15T07:43:06.800Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
120
+ {"timestamp":"2026-01-15T07:43:06.800Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
121
+ {"timestamp":"2026-01-15T07:49:02.751Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
122
+ {"timestamp":"2026-01-15T07:49:02.752Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
123
+ {"timestamp":"2026-01-15T07:49:02.753Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}