pumuki-ast-hooks 6.1.11 → 6.1.13
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 +13 -13
- package/package.json +18 -18
- package/scripts/hooks-system/.audit-reports/auto-recovery.log +2 -0
- package/scripts/hooks-system/.audit-reports/install-wizard.log +8 -0
- package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +56 -0
- package/scripts/hooks-system/infrastructure/ast/ios/__tests__/ios-srp-helpers.spec.js +62 -0
- package/scripts/hooks-system/infrastructure/ast/ios/ast-ios.js +25 -11
- package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js +21 -9
- package/scripts/hooks-system/infrastructure/ast/ios/utils/ios-srp-helpers.js +162 -0
- package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +6 -0
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Portable, project‑agnostic, multi‑platform enterprise framework to govern AI
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Quick start (30–60s)
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
git init
|
|
@@ -22,9 +22,9 @@ npx ast-install
|
|
|
22
22
|
npx ast-hooks audit
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Default installation mode: `npm-runtime`.
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
To use the embedded runtime (`vendored` mode):
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
HOOK_INSTALL_MODE=vendored npx ast-install
|
|
@@ -360,55 +360,55 @@ The Git Flow cycle includes branch validation, commits, push, PR, merge (by poli
|
|
|
360
360
|
|
|
361
361
|
---
|
|
362
362
|
|
|
363
|
-
## 9.
|
|
363
|
+
## 9. Commands (required)
|
|
364
364
|
|
|
365
|
-
###
|
|
365
|
+
### Installation (dev)
|
|
366
366
|
|
|
367
367
|
```bash
|
|
368
368
|
npm install --save-dev pumuki-ast-hooks
|
|
369
369
|
npx ast-install
|
|
370
370
|
```
|
|
371
371
|
|
|
372
|
-
###
|
|
372
|
+
### Installation (legacy)
|
|
373
373
|
|
|
374
374
|
```bash
|
|
375
375
|
npm install --save-dev pumuki-ast-hooks
|
|
376
376
|
npx ast-install
|
|
377
377
|
```
|
|
378
378
|
|
|
379
|
-
###
|
|
379
|
+
### Update
|
|
380
380
|
|
|
381
381
|
```bash
|
|
382
382
|
npm install --save-dev pumuki-ast-hooks@latest
|
|
383
383
|
npx ast-install
|
|
384
384
|
```
|
|
385
385
|
|
|
386
|
-
###
|
|
386
|
+
### Uninstall
|
|
387
387
|
|
|
388
388
|
```bash
|
|
389
389
|
npx ast-uninstall
|
|
390
390
|
npm uninstall pumuki-ast-hooks
|
|
391
391
|
```
|
|
392
392
|
|
|
393
|
-
###
|
|
393
|
+
### Install hooks
|
|
394
394
|
|
|
395
395
|
```bash
|
|
396
396
|
npm run install-hooks
|
|
397
397
|
```
|
|
398
398
|
|
|
399
|
-
###
|
|
399
|
+
### Interactive menu
|
|
400
400
|
|
|
401
401
|
```bash
|
|
402
402
|
npx ast-hooks
|
|
403
403
|
```
|
|
404
404
|
|
|
405
|
-
###
|
|
405
|
+
### Version check
|
|
406
406
|
|
|
407
407
|
```bash
|
|
408
408
|
npm run ast:check-version
|
|
409
409
|
```
|
|
410
410
|
|
|
411
|
-
###
|
|
411
|
+
### Audit
|
|
412
412
|
|
|
413
413
|
```bash
|
|
414
414
|
npm run audit
|
|
@@ -435,7 +435,7 @@ npm run ast:guard:status
|
|
|
435
435
|
npm run ast:guard:logs
|
|
436
436
|
```
|
|
437
437
|
|
|
438
|
-
###
|
|
438
|
+
### Evidence refresh
|
|
439
439
|
|
|
440
440
|
```bash
|
|
441
441
|
npm run ast:refresh
|
package/package.json
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki-ast-hooks",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.13",
|
|
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": {
|
|
7
|
-
"pumuki-ast-hooks": "
|
|
8
|
-
"audit": "
|
|
9
|
-
"ast-hooks": "
|
|
10
|
-
"ast-install": "
|
|
11
|
-
"ast-uninstall": "
|
|
12
|
-
"ast-violations": "
|
|
13
|
-
"ast-check-version": "
|
|
14
|
-
"ast-gitflow": "
|
|
15
|
-
"ai-commit": "
|
|
16
|
-
"hook-run-orchestrator": "
|
|
17
|
-
"hook-watch": "
|
|
18
|
-
"hook-status": "
|
|
19
|
-
"hook-predict": "
|
|
20
|
-
"hook-playbook": "
|
|
21
|
-
"hook-doc-drift": "
|
|
22
|
-
"hook-plan-review": "
|
|
7
|
+
"pumuki-ast-hooks": "bin/pumuki-mcp-server.js",
|
|
8
|
+
"audit": "bin/audit",
|
|
9
|
+
"ast-hooks": "bin/cli.js",
|
|
10
|
+
"ast-install": "bin/install.js",
|
|
11
|
+
"ast-uninstall": "bin/uninstall.js",
|
|
12
|
+
"ast-violations": "bin/violations-api.js",
|
|
13
|
+
"ast-check-version": "bin/check-version.js",
|
|
14
|
+
"ast-gitflow": "scripts/hooks-system/bin/gitflow-cycle.js",
|
|
15
|
+
"ai-commit": "bin/ai-commit.sh",
|
|
16
|
+
"hook-run-orchestrator": "bin/run-orchestrator.js",
|
|
17
|
+
"hook-watch": "bin/watch-hooks.js",
|
|
18
|
+
"hook-status": "bin/hook-status.js",
|
|
19
|
+
"hook-predict": "bin/predictive-hooks.js",
|
|
20
|
+
"hook-playbook": "bin/run-playbook.js",
|
|
21
|
+
"hook-doc-drift": "bin/check-doc-drift.js",
|
|
22
|
+
"hook-plan-review": "bin/plan-review.js"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"install-hooks": "node bin/install.js",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"license": "MIT",
|
|
82
82
|
"repository": {
|
|
83
83
|
"type": "git",
|
|
84
|
-
"url": "https://github.com/SwiftEnProfundidad/ast-intelligence-hooks.git"
|
|
84
|
+
"url": "git+https://github.com/SwiftEnProfundidad/ast-intelligence-hooks.git"
|
|
85
85
|
},
|
|
86
86
|
"bugs": {
|
|
87
87
|
"url": "https://github.com/SwiftEnProfundidad/ast-intelligence-hooks/issues"
|
|
@@ -46,3 +46,5 @@
|
|
|
46
46
|
{"timestamp":"2026-01-21T13:16:57.700Z","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":{}}
|
|
47
47
|
{"timestamp":"2026-01-21T14:08:08.597Z","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":{}}
|
|
48
48
|
{"timestamp":"2026-01-21T14:14:43.580Z","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":{}}
|
|
49
|
+
{"timestamp":"2026-01-21T14:19:14.000Z","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":{}}
|
|
50
|
+
{"timestamp":"2026-01-21T14:43:15.797Z","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":{}}
|
|
@@ -194,3 +194,11 @@
|
|
|
194
194
|
{"timestamp":"2026-01-21T14:14:44.277Z","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":{}}
|
|
195
195
|
{"timestamp":"2026-01-21T14:14:44.277Z","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":{}}
|
|
196
196
|
{"timestamp":"2026-01-21T14:14:44.277Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
197
|
+
{"timestamp":"2026-01-21T14:19:14.062Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
|
|
198
|
+
{"timestamp":"2026-01-21T14:19:14.069Z","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":{}}
|
|
199
|
+
{"timestamp":"2026-01-21T14:19:14.070Z","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":{}}
|
|
200
|
+
{"timestamp":"2026-01-21T14:19:14.070Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
201
|
+
{"timestamp":"2026-01-21T14:43:15.954Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
|
|
202
|
+
{"timestamp":"2026-01-21T14:43:15.961Z","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":{}}
|
|
203
|
+
{"timestamp":"2026-01-21T14:43:15.961Z","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":{}}
|
|
204
|
+
{"timestamp":"2026-01-21T14:43:15.961Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
|
|
@@ -1450,3 +1450,59 @@
|
|
|
1450
1450
|
{"timestamp":1769004905775,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1451
1451
|
{"timestamp":1769004905775,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1452
1452
|
{"timestamp":1769004905775,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1453
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1454
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1455
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1456
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1457
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1458
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1459
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1460
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1461
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1462
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1463
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1464
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1465
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1466
|
+
{"timestamp":1769005153999,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1467
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1468
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1469
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1470
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1471
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1472
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1473
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1474
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1475
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1476
|
+
{"timestamp":1769005154000,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1477
|
+
{"timestamp":1769005445389,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1478
|
+
{"timestamp":1769005445389,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1479
|
+
{"timestamp":1769005445390,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1480
|
+
{"timestamp":1769005445390,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1481
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1482
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1483
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1484
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1485
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1486
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1487
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1488
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1489
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1490
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1491
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1492
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1493
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1494
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1495
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1496
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1497
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1498
|
+
{"timestamp":1769006595796,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1499
|
+
{"timestamp":1769006595797,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1500
|
+
{"timestamp":1769006595797,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1501
|
+
{"timestamp":1769006595797,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1502
|
+
{"timestamp":1769006595797,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1503
|
+
{"timestamp":1769006595797,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1504
|
+
{"timestamp":1769006595797,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1505
|
+
{"timestamp":1769006619003,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
1506
|
+
{"timestamp":1769006619004,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
|
|
1507
|
+
{"timestamp":1769006619004,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
|
|
1508
|
+
{"timestamp":1769006619004,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const { summarizeSwiftTypes, evaluateMultipleTypeGroups, resolveSrpSeverity, isThinWrapperSummary } = require('../utils/ios-srp-helpers');
|
|
2
|
+
|
|
3
|
+
describe('ios srp heuristics', () => {
|
|
4
|
+
it('flags multiple unrelated types by group', () => {
|
|
5
|
+
const content = `
|
|
6
|
+
struct User { let id: String }
|
|
7
|
+
struct Order { let id: String }
|
|
8
|
+
struct Product { let id: String }
|
|
9
|
+
`;
|
|
10
|
+
const summaries = summarizeSwiftTypes(content);
|
|
11
|
+
const result = evaluateMultipleTypeGroups(summaries);
|
|
12
|
+
expect(result.shouldFlag).toBe(true);
|
|
13
|
+
expect(result.distinctGroups).toBeGreaterThan(1);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('does not flag multiple types with shared prefix', () => {
|
|
17
|
+
const content = `
|
|
18
|
+
struct UserView { var body: some View { Text("x") } }
|
|
19
|
+
final class UserViewModel { func load() {} }
|
|
20
|
+
final class UserRouter { func route() {} }
|
|
21
|
+
`;
|
|
22
|
+
const summaries = summarizeSwiftTypes(content);
|
|
23
|
+
const result = evaluateMultipleTypeGroups(summaries);
|
|
24
|
+
expect(result.shouldFlag).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('counts methods without nested type members', () => {
|
|
28
|
+
const content = `
|
|
29
|
+
struct Wrapper {
|
|
30
|
+
struct Nested { func inner() {} }
|
|
31
|
+
func outer() {}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
const summaries = summarizeSwiftTypes(content);
|
|
35
|
+
const wrapper = summaries.find((item) => item.name === 'Wrapper');
|
|
36
|
+
expect(wrapper.methodsCount).toBe(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('detects thin wrappers', () => {
|
|
40
|
+
const content = `
|
|
41
|
+
struct TokenSpyStorageState {
|
|
42
|
+
var savedTokens: [String]
|
|
43
|
+
var deletedTokensCount: Int
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
final class AccessTokenSpyStorage {
|
|
47
|
+
var state: TokenSpyStorageState
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
const summaries = summarizeSwiftTypes(content);
|
|
51
|
+
const wrapper = summaries.find((item) => item.name === 'AccessTokenSpyStorage');
|
|
52
|
+
expect(isThinWrapperSummary(wrapper)).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('resolves severity by layer', () => {
|
|
56
|
+
const config = { coreSeverity: 'critical', defaultSeverity: 'high', testSeverity: 'low' };
|
|
57
|
+
expect(resolveSrpSeverity('Apps/Domain/User.swift', config)).toBe('critical');
|
|
58
|
+
expect(resolveSrpSeverity('Apps/Application/UserUseCase.swift', config)).toBe('critical');
|
|
59
|
+
expect(resolveSrpSeverity('Apps/Tests/UserTests.swift', config)).toBe('low');
|
|
60
|
+
expect(resolveSrpSeverity('Apps/Presentation/UserView.swift', config)).toBe('high');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -17,6 +17,7 @@ const { iOSCICDRules } = require(path.join(__dirname, 'analyzers/iOSCICDRules'))
|
|
|
17
17
|
const { iOSForbiddenLiteralsAnalyzer } = require(path.join(__dirname, 'analyzers/iOSForbiddenLiteralsAnalyzer'));
|
|
18
18
|
const { iOSASTIntelligentAnalyzer } = require(path.join(__dirname, 'analyzers/iOSASTIntelligentAnalyzer'));
|
|
19
19
|
const { iOSModernPracticesRules } = require(path.join(__dirname, 'analyzers/iOSModernPracticesRules'));
|
|
20
|
+
const { summarizeSwiftTypes, evaluateMultipleTypeGroups, resolveSrpSeverity, isThinWrapperSummary } = require(path.join(__dirname, 'utils/ios-srp-helpers'));
|
|
20
21
|
|
|
21
22
|
function detectForbiddenTestableImport({ filePath, content }) {
|
|
22
23
|
if (!filePath || !content) return null;
|
|
@@ -1134,29 +1135,42 @@ async function runIOSIntelligence(project, findings, platform) {
|
|
|
1134
1135
|
// ==========================================
|
|
1135
1136
|
|
|
1136
1137
|
|
|
1137
|
-
const
|
|
1138
|
-
const
|
|
1139
|
-
if (
|
|
1138
|
+
const typeSummaries = summarizeSwiftTypes(content);
|
|
1139
|
+
const typeGroups = evaluateMultipleTypeGroups(typeSummaries);
|
|
1140
|
+
if (typeGroups.shouldFlag && !filePath.includes('Generated')) {
|
|
1141
|
+
const severity = resolveSrpSeverity(filePath, {
|
|
1142
|
+
coreSeverity: 'high',
|
|
1143
|
+
defaultSeverity: 'medium',
|
|
1144
|
+
testSeverity: 'low'
|
|
1145
|
+
});
|
|
1140
1146
|
pushFinding(
|
|
1141
1147
|
"ios.solid.srp_multiple_types",
|
|
1142
|
-
|
|
1148
|
+
severity,
|
|
1143
1149
|
sf,
|
|
1144
1150
|
sf,
|
|
1145
|
-
`File defines ${
|
|
1151
|
+
`File defines ${typeGroups.totalTypes} types across ${typeGroups.distinctGroups} domains - split by responsibility (SRP)`,
|
|
1146
1152
|
findings
|
|
1147
1153
|
);
|
|
1148
1154
|
}
|
|
1149
1155
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1156
|
+
const godClassSeverityConfig = {
|
|
1157
|
+
coreSeverity: 'critical',
|
|
1158
|
+
defaultSeverity: 'high',
|
|
1159
|
+
testSeverity: 'low'
|
|
1160
|
+
};
|
|
1161
|
+
const godClassThreshold = 20;
|
|
1162
|
+
for (const summary of typeSummaries) {
|
|
1163
|
+
if (isThinWrapperSummary(summary)) {
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
if (summary.methodsCount > godClassThreshold) {
|
|
1167
|
+
const severity = resolveSrpSeverity(filePath, godClassSeverityConfig);
|
|
1154
1168
|
pushFinding(
|
|
1155
1169
|
"ios.solid.srp_god_class",
|
|
1156
|
-
|
|
1170
|
+
severity,
|
|
1157
1171
|
sf,
|
|
1158
1172
|
sf,
|
|
1159
|
-
`Type has ${
|
|
1173
|
+
`Type '${summary.name}' has ${summary.methodsCount} methods - split responsibilities (SRP: one reason to change)`,
|
|
1160
1174
|
findings
|
|
1161
1175
|
);
|
|
1162
1176
|
}
|
package/scripts/hooks-system/infrastructure/ast/ios/detectors/ios-ast-intelligent-strategies.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const DIValidationService = require('../../../../application/DIValidationService');
|
|
3
|
+
const { resolveSrpSeverity, isThinWrapperSummary } = require('../utils/ios-srp-helpers');
|
|
3
4
|
|
|
4
5
|
const diValidationService = new DIValidationService();
|
|
5
6
|
|
|
@@ -168,16 +169,22 @@ async function analyzeClassAST(analyzer, node, filePath) {
|
|
|
168
169
|
|
|
169
170
|
if (name && !/Spec$|Test$|Mock/.test(name) && !name.includes('Coordinator')) {
|
|
170
171
|
const complexity = calculateComplexityAST(substructure);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
filePath,
|
|
174
|
-
line,
|
|
175
|
-
methodsCount: methods.length,
|
|
176
|
-
significantMethodsCount: significantMethods.length,
|
|
172
|
+
const isThinWrapper = isThinWrapperSummary({
|
|
173
|
+
methodsCount: significantMethods.length,
|
|
177
174
|
propertiesCount: properties.length,
|
|
178
|
-
bodyLength,
|
|
179
|
-
complexity,
|
|
180
175
|
});
|
|
176
|
+
if (!isThinWrapper) {
|
|
177
|
+
analyzer.godClassCandidates.push({
|
|
178
|
+
name,
|
|
179
|
+
filePath,
|
|
180
|
+
line,
|
|
181
|
+
methodsCount: methods.length,
|
|
182
|
+
significantMethodsCount: significantMethods.length,
|
|
183
|
+
propertiesCount: properties.length,
|
|
184
|
+
bodyLength,
|
|
185
|
+
complexity,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
181
188
|
}
|
|
182
189
|
|
|
183
190
|
if (name.includes('ViewController')) {
|
|
@@ -803,9 +810,14 @@ function finalizeGodClassDetection(analyzer) {
|
|
|
803
810
|
const signalCount = [sizeOutlier, complexityOutlier].filter(Boolean).length;
|
|
804
811
|
|
|
805
812
|
if (extremeOutlier || signalCount >= 2) {
|
|
813
|
+
const severity = resolveSrpSeverity(c.filePath, {
|
|
814
|
+
coreSeverity: 'critical',
|
|
815
|
+
defaultSeverity: 'high',
|
|
816
|
+
testSeverity: 'low',
|
|
817
|
+
});
|
|
806
818
|
analyzer.pushFinding(
|
|
807
819
|
'ios.solid.srp.god_class',
|
|
808
|
-
|
|
820
|
+
severity,
|
|
809
821
|
c.filePath,
|
|
810
822
|
c.line,
|
|
811
823
|
`God class '${c.name}': ${c.methodsCount} methods (z=${methodsZ.toFixed(2)}), ${c.propertiesCount} properties (z=${propsZ.toFixed(2)}), body ${c.bodyLength} (z=${bodyZ.toFixed(2)}), complexity ${c.complexity} (z=${complexityZ.toFixed(2)}) - VIOLATES SRP`
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
function resolveSrpSeverity(filePath, { coreSeverity, defaultSeverity, testSeverity }) {
|
|
2
|
+
const normalized = String(filePath || '').replace(/\\/g, '/');
|
|
3
|
+
const isTest = /Tests|Test|Spec/.test(normalized);
|
|
4
|
+
if (isTest) return testSeverity || defaultSeverity;
|
|
5
|
+
const isCore = normalized.includes('/Domain/') || normalized.includes('/Application/');
|
|
6
|
+
if (isCore) return coreSeverity || defaultSeverity;
|
|
7
|
+
return defaultSeverity;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function findMatchingBraceIndex(content, startIndex) {
|
|
11
|
+
let depth = 0;
|
|
12
|
+
let inString = false;
|
|
13
|
+
let stringChar = '';
|
|
14
|
+
let inLineComment = false;
|
|
15
|
+
let inBlockComment = false;
|
|
16
|
+
|
|
17
|
+
for (let i = startIndex; i < content.length; i += 1) {
|
|
18
|
+
const current = content[i];
|
|
19
|
+
const next = content[i + 1];
|
|
20
|
+
|
|
21
|
+
if (inLineComment) {
|
|
22
|
+
if (current === '\n') inLineComment = false;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (inBlockComment) {
|
|
27
|
+
if (current === '*' && next === '/') {
|
|
28
|
+
inBlockComment = false;
|
|
29
|
+
i += 1;
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (inString) {
|
|
35
|
+
if (current === '\\') {
|
|
36
|
+
i += 1;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (current === stringChar) {
|
|
40
|
+
inString = false;
|
|
41
|
+
}
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (current === '/' && next === '/') {
|
|
46
|
+
inLineComment = true;
|
|
47
|
+
i += 1;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (current === '/' && next === '*') {
|
|
52
|
+
inBlockComment = true;
|
|
53
|
+
i += 1;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (current === '"' || current === "'") {
|
|
58
|
+
inString = true;
|
|
59
|
+
stringChar = current;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (current === '{') depth += 1;
|
|
64
|
+
if (current === '}') {
|
|
65
|
+
depth -= 1;
|
|
66
|
+
if (depth === 0) return i;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function extractSwiftTypeBlocks(content) {
|
|
74
|
+
const blocks = [];
|
|
75
|
+
const pattern = /(^|\n)\s*(?:public|internal|fileprivate|private|open)?\s*(?:final\s+)?(class|struct|enum|protocol)\s+([A-Za-z_][A-Za-z0-9_]*)[^\n{]*\{/g;
|
|
76
|
+
let match = pattern.exec(content);
|
|
77
|
+
while (match) {
|
|
78
|
+
const name = match[3];
|
|
79
|
+
const braceIndex = match.index + match[0].lastIndexOf('{');
|
|
80
|
+
const endIndex = findMatchingBraceIndex(content, braceIndex);
|
|
81
|
+
if (endIndex !== -1) {
|
|
82
|
+
blocks.push({
|
|
83
|
+
name,
|
|
84
|
+
openIndex: braceIndex,
|
|
85
|
+
closeIndex: endIndex,
|
|
86
|
+
body: content.slice(braceIndex + 1, endIndex)
|
|
87
|
+
});
|
|
88
|
+
pattern.lastIndex = endIndex + 1;
|
|
89
|
+
}
|
|
90
|
+
match = pattern.exec(content);
|
|
91
|
+
}
|
|
92
|
+
return blocks;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function stripNestedTypeBlocks(content) {
|
|
96
|
+
const nestedBlocks = extractSwiftTypeBlocks(content);
|
|
97
|
+
if (nestedBlocks.length === 0) return content;
|
|
98
|
+
const sorted = nestedBlocks.slice().sort((a, b) => b.openIndex - a.openIndex);
|
|
99
|
+
let output = content;
|
|
100
|
+
for (const block of sorted) {
|
|
101
|
+
const length = block.closeIndex - block.openIndex + 1;
|
|
102
|
+
output = `${output.slice(0, block.openIndex)}${' '.repeat(length)}${output.slice(block.closeIndex + 1)}`;
|
|
103
|
+
}
|
|
104
|
+
return output;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function countFunctions(content) {
|
|
108
|
+
const matches = content.match(/\bfunc\s+[A-Za-z_][A-Za-z0-9_]*/g) || [];
|
|
109
|
+
return matches.length;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function countProperties(content) {
|
|
113
|
+
const matches = content.match(/(^|\n)\s*(?:@[A-Za-z0-9_.]+\s*)*(var|let)\s+[A-Za-z_][A-Za-z0-9_]*/g) || [];
|
|
114
|
+
return matches.length;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function splitTypeName(name) {
|
|
118
|
+
return String(name).match(/[A-Z]+(?![a-z])|[A-Z]?[a-z]+|[0-9]+/g) || [name];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getTypeGroupKey(name) {
|
|
122
|
+
const parts = splitTypeName(name);
|
|
123
|
+
return parts[0] || name;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function summarizeSwiftTypes(content) {
|
|
127
|
+
const blocks = extractSwiftTypeBlocks(String(content || ''));
|
|
128
|
+
return blocks.map((block) => {
|
|
129
|
+
const sanitizedBody = stripNestedTypeBlocks(block.body);
|
|
130
|
+
return {
|
|
131
|
+
name: block.name,
|
|
132
|
+
methodsCount: countFunctions(sanitizedBody),
|
|
133
|
+
propertiesCount: countProperties(sanitizedBody),
|
|
134
|
+
groupKey: getTypeGroupKey(block.name)
|
|
135
|
+
};
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function evaluateMultipleTypeGroups(summaries) {
|
|
140
|
+
const groups = new Set((summaries || []).map((item) => item.groupKey).filter(Boolean));
|
|
141
|
+
const totalTypes = (summaries || []).length;
|
|
142
|
+
const distinctGroups = groups.size;
|
|
143
|
+
const shouldFlag = totalTypes >= 3 && distinctGroups >= 2;
|
|
144
|
+
return {
|
|
145
|
+
totalTypes,
|
|
146
|
+
distinctGroups,
|
|
147
|
+
shouldFlag,
|
|
148
|
+
groups: Array.from(groups)
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isThinWrapperSummary(summary) {
|
|
153
|
+
if (!summary) return false;
|
|
154
|
+
return summary.methodsCount === 0 && summary.propertiesCount <= 1;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
module.exports = {
|
|
158
|
+
summarizeSwiftTypes,
|
|
159
|
+
evaluateMultipleTypeGroups,
|
|
160
|
+
resolveSrpSeverity,
|
|
161
|
+
isThinWrapperSummary
|
|
162
|
+
};
|
package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log
CHANGED
|
@@ -142,3 +142,9 @@
|
|
|
142
142
|
{"timestamp":"2026-01-21T14:14:45.047Z","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"}}
|
|
143
143
|
{"timestamp":"2026-01-21T14:14:45.048Z","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"}}
|
|
144
144
|
{"timestamp":"2026-01-21T14:14:45.048Z","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)"}}
|
|
145
|
+
{"timestamp":"2026-01-21T14:19:16.416Z","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"}}
|
|
146
|
+
{"timestamp":"2026-01-21T14:19:16.417Z","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"}}
|
|
147
|
+
{"timestamp":"2026-01-21T14:19:16.418Z","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)"}}
|
|
148
|
+
{"timestamp":"2026-01-21T14:43:17.747Z","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"}}
|
|
149
|
+
{"timestamp":"2026-01-21T14:43:17.748Z","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"}}
|
|
150
|
+
{"timestamp":"2026-01-21T14:43:17.749Z","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)"}}
|