aios-core 4.2.14 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/.aios-core/cli/commands/validate/index.js +1 -1
  2. package/.aios-core/core/code-intel/helpers/creation-helper.js +183 -0
  3. package/.aios-core/core/code-intel/helpers/devops-helper.js +166 -0
  4. package/.aios-core/core/code-intel/helpers/planning-helper.js +248 -0
  5. package/.aios-core/core/code-intel/helpers/qa-helper.js +187 -0
  6. package/.aios-core/core/code-intel/helpers/story-helper.js +146 -0
  7. package/.aios-core/core/config/schemas/framework-config.schema.json +155 -7
  8. package/.aios-core/core/config/schemas/project-config.schema.json +329 -15
  9. package/.aios-core/core/config/template-overrides.js +84 -0
  10. package/.aios-core/core/docs/troubleshooting-guide.md +1 -1
  11. package/.aios-core/core/doctor/checks/agent-memory.js +63 -0
  12. package/.aios-core/core/doctor/checks/claude-md.js +56 -0
  13. package/.aios-core/core/doctor/checks/code-intel.js +57 -0
  14. package/.aios-core/core/doctor/checks/commands-count.js +81 -0
  15. package/.aios-core/core/doctor/checks/core-config.js +53 -0
  16. package/.aios-core/core/doctor/checks/entity-registry.js +53 -0
  17. package/.aios-core/core/doctor/checks/git-hooks.js +50 -0
  18. package/.aios-core/core/doctor/checks/graph-dashboard.js +48 -0
  19. package/.aios-core/core/doctor/checks/hooks-claude-count.js +107 -0
  20. package/.aios-core/core/doctor/checks/ide-sync.js +68 -0
  21. package/.aios-core/core/doctor/checks/index.js +46 -0
  22. package/.aios-core/core/doctor/checks/node-version.js +33 -0
  23. package/.aios-core/core/doctor/checks/npm-packages.js +35 -0
  24. package/.aios-core/core/doctor/checks/rules-files.js +61 -0
  25. package/.aios-core/core/doctor/checks/settings-json.js +121 -0
  26. package/.aios-core/core/doctor/checks/skills-count.js +72 -0
  27. package/.aios-core/core/doctor/fix-handler.js +165 -0
  28. package/.aios-core/core/doctor/formatters/json.js +14 -0
  29. package/.aios-core/core/doctor/formatters/text.js +59 -0
  30. package/.aios-core/core/doctor/index.js +94 -0
  31. package/.aios-core/core/graph-dashboard/cli.js +361 -0
  32. package/.aios-core/core/graph-dashboard/data-sources/code-intel-source.js +234 -0
  33. package/.aios-core/core/graph-dashboard/data-sources/metrics-source.js +95 -0
  34. package/.aios-core/core/graph-dashboard/data-sources/registry-source.js +106 -0
  35. package/.aios-core/core/graph-dashboard/formatters/dot-formatter.js +45 -0
  36. package/.aios-core/core/graph-dashboard/formatters/html-formatter.js +1437 -0
  37. package/.aios-core/core/graph-dashboard/formatters/json-formatter.js +13 -0
  38. package/.aios-core/core/graph-dashboard/formatters/mermaid-formatter.js +59 -0
  39. package/.aios-core/core/graph-dashboard/index.js +21 -0
  40. package/.aios-core/core/graph-dashboard/renderers/stats-renderer.js +217 -0
  41. package/.aios-core/core/graph-dashboard/renderers/status-renderer.js +125 -0
  42. package/.aios-core/core/graph-dashboard/renderers/tree-renderer.js +119 -0
  43. package/.aios-core/core/health-check/base-check.js +1 -1
  44. package/.aios-core/core/health-check/check-registry.js +1 -1
  45. package/.aios-core/core/health-check/checks/deployment/build-config.js +1 -1
  46. package/.aios-core/core/health-check/checks/deployment/ci-config.js +1 -1
  47. package/.aios-core/core/health-check/checks/deployment/deployment-readiness.js +1 -1
  48. package/.aios-core/core/health-check/checks/deployment/docker-config.js +1 -1
  49. package/.aios-core/core/health-check/checks/deployment/env-file.js +1 -1
  50. package/.aios-core/core/health-check/checks/deployment/index.js +1 -1
  51. package/.aios-core/core/health-check/checks/index.js +1 -1
  52. package/.aios-core/core/health-check/checks/local/disk-space.js +1 -1
  53. package/.aios-core/core/health-check/checks/local/environment-vars.js +1 -1
  54. package/.aios-core/core/health-check/checks/local/git-install.js +1 -1
  55. package/.aios-core/core/health-check/checks/local/ide-detection.js +1 -1
  56. package/.aios-core/core/health-check/checks/local/index.js +1 -1
  57. package/.aios-core/core/health-check/checks/local/memory.js +1 -1
  58. package/.aios-core/core/health-check/checks/local/network.js +1 -1
  59. package/.aios-core/core/health-check/checks/local/npm-install.js +1 -1
  60. package/.aios-core/core/health-check/checks/local/shell-environment.js +1 -1
  61. package/.aios-core/core/health-check/checks/project/agent-config.js +1 -1
  62. package/.aios-core/core/health-check/checks/project/aios-directory.js +1 -1
  63. package/.aios-core/core/health-check/checks/project/dependencies.js +1 -1
  64. package/.aios-core/core/health-check/checks/project/framework-config.js +1 -1
  65. package/.aios-core/core/health-check/checks/project/index.js +1 -1
  66. package/.aios-core/core/health-check/checks/project/node-version.js +1 -1
  67. package/.aios-core/core/health-check/checks/project/package-json.js +1 -1
  68. package/.aios-core/core/health-check/checks/project/task-definitions.js +1 -1
  69. package/.aios-core/core/health-check/checks/project/workflow-dependencies.js +1 -1
  70. package/.aios-core/core/health-check/checks/repository/branch-protection.js +1 -1
  71. package/.aios-core/core/health-check/checks/repository/commit-history.js +1 -1
  72. package/.aios-core/core/health-check/checks/repository/conflicts.js +1 -1
  73. package/.aios-core/core/health-check/checks/repository/git-repo.js +1 -1
  74. package/.aios-core/core/health-check/checks/repository/git-status.js +1 -1
  75. package/.aios-core/core/health-check/checks/repository/gitignore.js +1 -1
  76. package/.aios-core/core/health-check/checks/repository/index.js +1 -1
  77. package/.aios-core/core/health-check/checks/repository/large-files.js +1 -1
  78. package/.aios-core/core/health-check/checks/repository/lockfile-integrity.js +1 -1
  79. package/.aios-core/core/health-check/checks/services/api-endpoints.js +1 -1
  80. package/.aios-core/core/health-check/checks/services/claude-code.js +1 -1
  81. package/.aios-core/core/health-check/checks/services/gemini-cli.js +1 -1
  82. package/.aios-core/core/health-check/checks/services/github-cli.js +1 -1
  83. package/.aios-core/core/health-check/checks/services/index.js +1 -1
  84. package/.aios-core/core/health-check/checks/services/mcp-integration.js +1 -1
  85. package/.aios-core/core/health-check/engine.js +1 -1
  86. package/.aios-core/core/health-check/healers/backup-manager.js +1 -1
  87. package/.aios-core/core/health-check/healers/index.js +1 -1
  88. package/.aios-core/core/health-check/index.js +9 -2
  89. package/.aios-core/core/health-check/reporters/console.js +1 -1
  90. package/.aios-core/core/health-check/reporters/index.js +1 -1
  91. package/.aios-core/core/health-check/reporters/json.js +1 -1
  92. package/.aios-core/core/health-check/reporters/markdown.js +1 -1
  93. package/.aios-core/core/ids/layer-classifier.js +65 -0
  94. package/.aios-core/core/ids/registry-updater.js +49 -0
  95. package/.aios-core/core/index.esm.js +1 -1
  96. package/.aios-core/core/index.js +1 -1
  97. package/.aios-core/core/session/context-detector.js +2 -7
  98. package/.aios-core/core/synapse/context/context-tracker.js +9 -1
  99. package/.aios-core/core/synapse/engine.js +33 -13
  100. package/.aios-core/core/synapse/runtime/hook-runtime.js +40 -2
  101. package/.aios-core/core/synapse/session/session-manager.js +3 -2
  102. package/.aios-core/core/synapse/utils/atomic-write.js +79 -0
  103. package/.aios-core/core-config.yaml +34 -1
  104. package/.aios-core/data/aios-kb.md +2 -2
  105. package/.aios-core/data/capability-detection.js +290 -0
  106. package/.aios-core/data/entity-registry.yaml +10424 -2127
  107. package/.aios-core/data/mcp-discipline.js +166 -0
  108. package/.aios-core/data/mcp-tool-examples.yaml +215 -0
  109. package/.aios-core/data/tok2-validation.js +168 -0
  110. package/.aios-core/data/tok3-token-comparison.js +123 -0
  111. package/.aios-core/data/tool-registry.yaml +648 -0
  112. package/.aios-core/data/tool-search-validation.js +174 -0
  113. package/.aios-core/development/agents/analyst/MEMORY.md +33 -0
  114. package/.aios-core/development/agents/architect/MEMORY.md +39 -0
  115. package/.aios-core/development/agents/data-engineer/MEMORY.md +32 -0
  116. package/.aios-core/development/agents/dev/MEMORY.md +46 -0
  117. package/.aios-core/development/agents/dev.md +1 -1
  118. package/.aios-core/development/agents/devops/MEMORY.md +39 -0
  119. package/.aios-core/development/agents/devops.md +22 -0
  120. package/.aios-core/development/agents/pm/MEMORY.md +38 -0
  121. package/.aios-core/development/agents/po/MEMORY.md +45 -0
  122. package/.aios-core/development/agents/qa/MEMORY.md +42 -0
  123. package/.aios-core/development/agents/qa.md +1 -1
  124. package/.aios-core/development/agents/sm/MEMORY.md +31 -0
  125. package/.aios-core/development/agents/ux/MEMORY.md +31 -0
  126. package/.aios-core/development/checklists/issue-triage-checklist.md +35 -0
  127. package/.aios-core/development/checklists/memory-audit-checklist.md +53 -0
  128. package/.aios-core/development/scripts/issue-triage.js +171 -0
  129. package/.aios-core/development/scripts/populate-entity-registry.js +412 -19
  130. package/.aios-core/development/scripts/unified-activation-pipeline.js +31 -10
  131. package/.aios-core/development/tasks/analyze-project-structure.md +48 -0
  132. package/.aios-core/development/tasks/brownfield-create-epic.md +41 -0
  133. package/.aios-core/development/tasks/create-doc.md +44 -0
  134. package/.aios-core/development/tasks/create-next-story.md +10 -0
  135. package/.aios-core/development/tasks/dev-develop-story.md +1 -1
  136. package/.aios-core/development/tasks/github-devops-github-pr-automation.md +49 -0
  137. package/.aios-core/development/tasks/github-devops-pre-push-quality-gate.md +63 -0
  138. package/.aios-core/development/tasks/github-issue-triage.md +118 -0
  139. package/.aios-core/development/tasks/health-check.yaml +206 -171
  140. package/.aios-core/development/tasks/kb-mode-interaction.md +3 -3
  141. package/.aios-core/development/tasks/plan-create-context.md +47 -1
  142. package/.aios-core/development/tasks/plan-create-implementation.md +55 -0
  143. package/.aios-core/development/tasks/pr-automation.md +5 -5
  144. package/.aios-core/development/tasks/qa-gate.md +48 -0
  145. package/.aios-core/development/tasks/qa-review-story.md +24 -1
  146. package/.aios-core/development/tasks/resolve-github-issue.md +608 -0
  147. package/.aios-core/development/tasks/review-contributor-pr.md +152 -0
  148. package/.aios-core/development/tasks/setup-llm-routing.md +1 -1
  149. package/.aios-core/development/tasks/spec-research-dependencies.md +4 -0
  150. package/.aios-core/development/tasks/triage-github-issues.md +356 -0
  151. package/.aios-core/development/tasks/validate-agents.md +4 -0
  152. package/.aios-core/development/tasks/validate-next-story.md +10 -0
  153. package/.aios-core/development/templates/agent-handoff-tmpl.yaml +48 -0
  154. package/.aios-core/development/templates/code-intel-integration-pattern.md +199 -0
  155. package/.aios-core/development/templates/ptc-entity-validation.md +113 -0
  156. package/.aios-core/development/templates/ptc-qa-gate.md +100 -0
  157. package/.aios-core/development/templates/ptc-research-aggregation.md +94 -0
  158. package/.aios-core/development/templates/service-template/README.md.hbs +158 -158
  159. package/.aios-core/development/templates/service-template/__tests__/index.test.ts.hbs +237 -237
  160. package/.aios-core/development/templates/service-template/client.ts.hbs +403 -403
  161. package/.aios-core/development/templates/service-template/errors.ts.hbs +182 -182
  162. package/.aios-core/development/templates/service-template/index.ts.hbs +120 -120
  163. package/.aios-core/development/templates/service-template/package.json.hbs +87 -87
  164. package/.aios-core/development/templates/service-template/types.ts.hbs +145 -145
  165. package/.aios-core/development/templates/squad/agent-template.md +11 -0
  166. package/.aios-core/development/templates/squad/task-template.md +21 -0
  167. package/.aios-core/development/templates/squad-template/LICENSE +21 -21
  168. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +1 -1
  169. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +1 -1
  170. package/.aios-core/framework-config.yaml +8 -0
  171. package/.aios-core/index.esm.js +1 -1
  172. package/.aios-core/index.js +1 -1
  173. package/.aios-core/infrastructure/integrations/ai-providers/index.js +1 -1
  174. package/.aios-core/infrastructure/schemas/task-v3-schema.json +6 -0
  175. package/.aios-core/infrastructure/scripts/collect-tool-usage.js +311 -0
  176. package/.aios-core/infrastructure/scripts/generate-optimization-report.js +497 -0
  177. package/.aios-core/infrastructure/scripts/generate-settings-json.js +300 -0
  178. package/.aios-core/infrastructure/scripts/git-config-detector.js +65 -9
  179. package/.aios-core/infrastructure/scripts/ide-sync/index.js +3 -1
  180. package/.aios-core/infrastructure/scripts/ide-sync/transformers/github-copilot.js +184 -0
  181. package/.aios-core/infrastructure/scripts/repository-detector.js +3 -3
  182. package/.aios-core/infrastructure/templates/aios-sync.yaml.template +182 -182
  183. package/.aios-core/infrastructure/templates/coderabbit.yaml.template +279 -279
  184. package/.aios-core/infrastructure/templates/github-workflows/ci.yml.template +169 -169
  185. package/.aios-core/infrastructure/templates/github-workflows/pr-automation.yml.template +330 -330
  186. package/.aios-core/infrastructure/templates/github-workflows/release.yml.template +196 -196
  187. package/.aios-core/infrastructure/templates/gitignore/gitignore-aios-base.tmpl +63 -63
  188. package/.aios-core/infrastructure/templates/gitignore/gitignore-brownfield-merge.tmpl +18 -18
  189. package/.aios-core/infrastructure/templates/gitignore/gitignore-node.tmpl +85 -85
  190. package/.aios-core/infrastructure/templates/gitignore/gitignore-python.tmpl +145 -145
  191. package/.aios-core/install-manifest.yaml +541 -249
  192. package/.aios-core/lib/build.json +1 -0
  193. package/.aios-core/local-config.yaml.template +71 -71
  194. package/.aios-core/monitor/hooks/lib/__init__.py +1 -1
  195. package/.aios-core/monitor/hooks/lib/enrich.py +58 -58
  196. package/.aios-core/monitor/hooks/lib/send_event.py +47 -47
  197. package/.aios-core/monitor/hooks/notification.py +29 -29
  198. package/.aios-core/monitor/hooks/post_tool_use.py +45 -45
  199. package/.aios-core/monitor/hooks/pre_compact.py +29 -29
  200. package/.aios-core/monitor/hooks/pre_tool_use.py +40 -40
  201. package/.aios-core/monitor/hooks/stop.py +29 -29
  202. package/.aios-core/monitor/hooks/subagent_stop.py +29 -29
  203. package/.aios-core/monitor/hooks/user_prompt_submit.py +38 -38
  204. package/.aios-core/product/templates/adr.hbs +125 -125
  205. package/.aios-core/product/templates/dbdr.hbs +241 -241
  206. package/.aios-core/product/templates/epic.hbs +212 -212
  207. package/.aios-core/product/templates/ide-rules/claude-rules.md +77 -0
  208. package/.aios-core/product/templates/pmdr.hbs +186 -186
  209. package/.aios-core/product/templates/prd-v2.0.hbs +216 -216
  210. package/.aios-core/product/templates/prd.hbs +201 -201
  211. package/.aios-core/product/templates/story.hbs +263 -263
  212. package/.aios-core/product/templates/task.hbs +170 -170
  213. package/.aios-core/product/templates/tmpl-comment-on-examples.sql +158 -158
  214. package/.aios-core/product/templates/tmpl-migration-script.sql +91 -91
  215. package/.aios-core/product/templates/tmpl-rls-granular-policies.sql +104 -104
  216. package/.aios-core/product/templates/tmpl-rls-kiss-policy.sql +10 -10
  217. package/.aios-core/product/templates/tmpl-rls-roles.sql +135 -135
  218. package/.aios-core/product/templates/tmpl-rls-simple.sql +77 -77
  219. package/.aios-core/product/templates/tmpl-rls-tenant.sql +152 -152
  220. package/.aios-core/product/templates/tmpl-rollback-script.sql +77 -77
  221. package/.aios-core/product/templates/tmpl-seed-data.sql +140 -140
  222. package/.aios-core/product/templates/tmpl-smoke-test.sql +16 -16
  223. package/.aios-core/product/templates/tmpl-staging-copy-merge.sql +139 -139
  224. package/.aios-core/product/templates/tmpl-stored-proc.sql +140 -140
  225. package/.aios-core/product/templates/tmpl-trigger.sql +152 -152
  226. package/.aios-core/product/templates/tmpl-view-materialized.sql +133 -133
  227. package/.aios-core/product/templates/tmpl-view.sql +177 -177
  228. package/.aios-core/scripts/pm.sh +0 -0
  229. package/.aios-core/user-guide.md +15 -15
  230. package/.aios-core/utils/filters/constants.js +10 -0
  231. package/.aios-core/utils/filters/content-filter.js +223 -0
  232. package/.aios-core/utils/filters/field-filter.js +126 -0
  233. package/.aios-core/utils/filters/index.js +180 -0
  234. package/.aios-core/utils/filters/schema-filter.js +157 -0
  235. package/.claude/CLAUDE.md +62 -0
  236. package/.claude/hooks/enforce-architecture-first.py +196 -196
  237. package/.claude/hooks/enforce-git-push-authority.sh +33 -0
  238. package/.claude/hooks/mind-clone-governance.py +192 -192
  239. package/.claude/hooks/read-protection.py +151 -151
  240. package/.claude/hooks/slug-validation.py +176 -176
  241. package/.claude/hooks/sql-governance.py +182 -182
  242. package/.claude/hooks/synapse-engine.cjs +28 -5
  243. package/.claude/hooks/write-path-validation.py +194 -194
  244. package/.claude/rules/agent-authority.md +105 -0
  245. package/.claude/rules/agent-handoff.md +97 -0
  246. package/.claude/rules/agent-memory-imports.md +15 -0
  247. package/.claude/rules/coderabbit-integration.md +101 -0
  248. package/.claude/rules/ids-principles.md +119 -0
  249. package/.claude/rules/story-lifecycle.md +145 -0
  250. package/.claude/rules/tool-examples.md +64 -0
  251. package/.claude/rules/tool-response-filtering.md +57 -0
  252. package/.claude/rules/workflow-execution.md +150 -0
  253. package/LICENSE +33 -33
  254. package/bin/aios-graph.js +9 -0
  255. package/bin/aios-init.js +2 -2
  256. package/bin/aios-minimal.js +0 -0
  257. package/bin/aios.js +17 -221
  258. package/bin/utils/detect-fsmonitor.js +70 -0
  259. package/bin/utils/framework-guard.js +238 -0
  260. package/bin/utils/validate-publish.js +108 -0
  261. package/package.json +6 -3
  262. package/packages/aios-install/bin/aios-install.js +0 -0
  263. package/packages/aios-install/bin/edmcp.js +0 -0
  264. package/packages/aios-pro-cli/bin/aios-pro.js +2 -0
  265. package/packages/installer/src/installer/brownfield-upgrader.js +68 -5
  266. package/packages/installer/src/merger/index.js +3 -0
  267. package/packages/installer/src/merger/strategies/index.js +6 -0
  268. package/packages/installer/src/merger/strategies/yaml-merger.js +181 -0
  269. package/packages/installer/src/updater/index.js +4 -4
  270. package/packages/installer/src/wizard/i18n.js +321 -3
  271. package/packages/installer/src/wizard/ide-config-generator.js +152 -25
  272. package/packages/installer/src/wizard/index.js +119 -1
  273. package/packages/installer/src/wizard/pro-setup.js +137 -121
  274. package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +261 -0
  275. package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +192 -0
  276. package/packages/installer/tests/unit/doctor/doctor-checks.test.js +551 -0
  277. package/packages/installer/tests/unit/doctor/doctor-orchestrator.test.js +134 -0
  278. package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +186 -0
  279. package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +309 -0
  280. package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +230 -0
  281. package/packages/installer/tests/unit/merger/strategies.test.js +2 -2
  282. package/packages/installer/tests/unit/merger/yaml-merger.test.js +327 -0
  283. package/scripts/check-markdown-links.py +352 -352
  284. package/scripts/dashboard-parallel-dev.sh +0 -0
  285. package/scripts/dashboard-parallel-phase3.sh +0 -0
  286. package/scripts/dashboard-parallel-phase4.sh +0 -0
  287. package/scripts/install-monitor-hooks.sh +0 -0
  288. package/scripts/package-synapse.js +2 -1
@@ -0,0 +1,497 @@
1
+ #!/usr/bin/env node
2
+ // =============================================================================
3
+ // generate-optimization-report.js — Optimization Report & Recommendations
4
+ // =============================================================================
5
+ // Story: TOK-5 (Tool Usage Analytics Pipeline)
6
+ // Layer: L2 (.aios-core/infrastructure/scripts/)
7
+ // Purpose:
8
+ // - Compare post-optimization metrics against TOK-1.5 baseline (ACs 4-6)
9
+ // - Generate promote/demote recommendations (ACs 7-9, 13-15)
10
+ // - Produce summary optimization report (ACs 16-17)
11
+ //
12
+ // Usage:
13
+ // node .aios-core/infrastructure/scripts/generate-optimization-report.js [options]
14
+ //
15
+ // Options:
16
+ // --dry-run Show results without writing files
17
+ // --json Output results as JSON to stdout
18
+ // --verbose Show detailed per-tool breakdown
19
+ // =============================================================================
20
+
21
+ 'use strict';
22
+
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+ const yaml = require('js-yaml');
26
+
27
+ // --- Paths ---
28
+ const ROOT = process.cwd();
29
+ const ANALYTICS_DIR = path.resolve(ROOT, '.aios', 'analytics');
30
+ const BASELINE_FILE = path.join(ANALYTICS_DIR, 'token-baseline.json');
31
+ const USAGE_FILE = path.join(ANALYTICS_DIR, 'tool-usage.json');
32
+ const REPORT_FILE = path.join(ANALYTICS_DIR, 'optimization-report.json');
33
+ const RECOMMENDATIONS_FILE = path.join(ANALYTICS_DIR, 'recommendations.yaml');
34
+ const TOOL_REGISTRY_FILE = path.resolve(ROOT, '.aios-core', 'data', 'tool-registry.yaml');
35
+
36
+ // --- Default Thresholds (overridden by tool-registry.yaml) ---
37
+ const DEFAULT_THRESHOLDS = {
38
+ promote: { minUsesPerSession: 10, minSessions: 5 },
39
+ demote: { maxUsesPerNSessions: 1, sessionWindow: 5 }
40
+ };
41
+
42
+ // --- Load Thresholds from tool-registry.yaml (AC 15) ---
43
+ function loadThresholds() {
44
+ try {
45
+ const raw = fs.readFileSync(TOOL_REGISTRY_FILE, 'utf8');
46
+ const registry = yaml.load(raw);
47
+ if (registry && registry.analytics && registry.analytics.thresholds) {
48
+ const t = registry.analytics.thresholds;
49
+ return {
50
+ promote: {
51
+ minUsesPerSession: t.promote?.minUsesPerSession ?? DEFAULT_THRESHOLDS.promote.minUsesPerSession,
52
+ minSessions: t.promote?.minSessions ?? DEFAULT_THRESHOLDS.promote.minSessions
53
+ },
54
+ demote: {
55
+ maxUsesPerNSessions: t.demote?.maxUsesPerNSessions ?? DEFAULT_THRESHOLDS.demote.maxUsesPerNSessions,
56
+ sessionWindow: t.demote?.sessionWindow ?? DEFAULT_THRESHOLDS.demote.sessionWindow
57
+ }
58
+ };
59
+ }
60
+ } catch {
61
+ // Fall back to defaults
62
+ }
63
+ return DEFAULT_THRESHOLDS;
64
+ }
65
+
66
+ // --- Load Baseline (TOK-1.5) ---
67
+ function loadBaseline() {
68
+ try {
69
+ const raw = fs.readFileSync(BASELINE_FILE, 'utf8');
70
+ return JSON.parse(raw);
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+
76
+ // --- Load Usage Data ---
77
+ function loadUsageData() {
78
+ try {
79
+ const raw = fs.readFileSync(USAGE_FILE, 'utf8');
80
+ const data = JSON.parse(raw);
81
+ return data && Array.isArray(data.sessions) ? data : null;
82
+ } catch {
83
+ return null;
84
+ }
85
+ }
86
+
87
+ // --- Load Tool Registry ---
88
+ function loadToolRegistry() {
89
+ try {
90
+ const raw = fs.readFileSync(TOOL_REGISTRY_FILE, 'utf8');
91
+ return yaml.load(raw);
92
+ } catch {
93
+ return null;
94
+ }
95
+ }
96
+
97
+ // --- Get tool tier from registry ---
98
+ function getToolTier(registry, toolName) {
99
+ if (!registry || !registry.tools) return 'unknown';
100
+ const tool = registry.tools[toolName];
101
+ return tool ? `tier_${tool.tier}` : 'unknown';
102
+ }
103
+
104
+ // --- Aggregate tool usage across sessions ---
105
+ function aggregateUsage(sessions) {
106
+ const toolStats = {};
107
+ const sessionCount = sessions.length;
108
+
109
+ for (const session of sessions) {
110
+ if (!session.events) continue;
111
+ for (const event of session.events) {
112
+ if (!toolStats[event.tool_name]) {
113
+ toolStats[event.tool_name] = {
114
+ tool_name: event.tool_name,
115
+ total_invocations: 0,
116
+ total_token_cost_input: 0,
117
+ total_token_cost_output: 0,
118
+ sessions_used: 0,
119
+ invocations_per_session: []
120
+ };
121
+ }
122
+ const stat = toolStats[event.tool_name];
123
+ stat.total_invocations += event.invocation_count;
124
+ stat.total_token_cost_input += event.token_cost_input;
125
+ stat.total_token_cost_output += event.token_cost_output;
126
+ stat.sessions_used += 1;
127
+ stat.invocations_per_session.push(event.invocation_count);
128
+ }
129
+ }
130
+
131
+ // Calculate averages
132
+ for (const stat of Object.values(toolStats)) {
133
+ stat.avg_invocations_per_session = stat.invocations_per_session.length > 0
134
+ ? stat.invocations_per_session.reduce((a, b) => a + b, 0) / stat.invocations_per_session.length
135
+ : 0;
136
+ stat.avg_tokens_per_session = sessionCount > 0
137
+ ? (stat.total_token_cost_input + stat.total_token_cost_output) / sessionCount
138
+ : 0;
139
+ }
140
+
141
+ return { toolStats, sessionCount };
142
+ }
143
+
144
+ // --- Baseline Comparison (ACs 4-6) ---
145
+ // Compares two dimensions:
146
+ // 1. Static overhead: framework tokens loaded at session start (schemas, rules, agents)
147
+ // Baseline source: frameworkOverhead.totalEstimatedTokens
148
+ // Post-opt source: sum of tool schema tokenCost for tools actually used (from registry)
149
+ // 2. Dynamic usage: total invocation token costs per session
150
+ // Baseline source: workflow median totalTokens
151
+ // Post-opt source: actual usage data from collect-tool-usage.js
152
+ function compareBaseline(baseline, usageData, registry) {
153
+ if (!baseline || !usageData) {
154
+ return { available: false, reason: 'Baseline or usage data not found' };
155
+ }
156
+
157
+ const sessions = usageData.sessions;
158
+ if (sessions.length === 0) {
159
+ return { available: false, reason: 'No sessions to compare' };
160
+ }
161
+
162
+ const { toolStats, sessionCount } = aggregateUsage(sessions);
163
+
164
+ // --- Static overhead comparison (C1 fix: apples-to-apples) ---
165
+ // Baseline: total framework overhead loaded at session start
166
+ const baselineOverhead = baseline.frameworkOverhead?.totalEstimatedTokens || 0;
167
+
168
+ // Post-opt: estimate schema overhead for tools actually used in sessions
169
+ // Uses tokenCost from tool-registry.yaml for tools that appeared in usage data
170
+ let postOptSchemaOverhead = 0;
171
+ if (registry && registry.tools) {
172
+ for (const toolName of Object.keys(toolStats)) {
173
+ const toolDef = registry.tools[toolName];
174
+ if (toolDef && toolDef.tokenCost) {
175
+ postOptSchemaOverhead += toolDef.tokenCost;
176
+ }
177
+ }
178
+ } else {
179
+ // Fallback: estimate from usage data (avg tokens / avg invocations = per-invocation cost)
180
+ postOptSchemaOverhead = Object.values(toolStats).reduce((sum, t) => {
181
+ return sum + (t.avg_invocations_per_session > 0
182
+ ? Math.round((t.total_token_cost_input + t.total_token_cost_output) / t.total_invocations)
183
+ : 0);
184
+ }, 0);
185
+ }
186
+
187
+ // --- Dynamic usage comparison ---
188
+ const postOptTokensInput = Object.values(toolStats).reduce((s, t) => s + t.total_token_cost_input, 0);
189
+ const postOptTokensOutput = Object.values(toolStats).reduce((s, t) => s + t.total_token_cost_output, 0);
190
+ const postOptTotal = postOptTokensInput + postOptTokensOutput;
191
+ const avgPostOptPerSession = sessionCount > 0 ? postOptTotal / sessionCount : 0;
192
+
193
+ const baselineWorkflows = baseline.workflows || {};
194
+
195
+ // Per-workflow comparison (AC 5)
196
+ const workflowComparison = {};
197
+ for (const [wfName, wfData] of Object.entries(baselineWorkflows)) {
198
+ const baselineMedian = wfData.median?.totalTokens || 0;
199
+ const baselineOverheadPct = baseline.comparison?.aiosActual?.overheadPercentOfTypicalSession?.[wfName] || 0;
200
+ const baselineOverheadTokens = Math.round(baselineMedian * baselineOverheadPct / 100);
201
+
202
+ workflowComparison[wfName] = {
203
+ baseline_median_total: baselineMedian,
204
+ baseline_overhead_tokens: baselineOverheadTokens,
205
+ baseline_overhead_pct: baselineOverheadPct,
206
+ post_optimization_schema_overhead: postOptSchemaOverhead,
207
+ post_optimization_avg_usage_per_session: Math.round(avgPostOptPerSession),
208
+ sessions_analyzed: sessionCount
209
+ };
210
+ }
211
+
212
+ // Total reduction: compares static overhead (schema tokens loaded)
213
+ const absoluteReduction = baselineOverhead - postOptSchemaOverhead;
214
+ const percentageReduction = baselineOverhead > 0
215
+ ? Math.round((absoluteReduction / baselineOverhead) * 1000) / 10
216
+ : 0;
217
+
218
+ // Target assessment (AC 6)
219
+ let targetStatus;
220
+ if (percentageReduction >= 25) {
221
+ targetStatus = 'ACHIEVED';
222
+ } else if (percentageReduction >= 15) {
223
+ targetStatus = 'PARTIALLY_ACHIEVED';
224
+ } else {
225
+ targetStatus = 'NOT_ACHIEVED';
226
+ }
227
+
228
+ return {
229
+ available: true,
230
+ comparison_methodology: 'Static schema overhead: baseline frameworkOverhead vs post-opt tool schema costs from registry. Dynamic usage tracked separately.',
231
+ baseline_overhead_tokens: baselineOverhead,
232
+ post_optimization_overhead_tokens: postOptSchemaOverhead,
233
+ absolute_reduction_tokens: absoluteReduction,
234
+ percentage_reduction: percentageReduction,
235
+ target_25_45_pct: targetStatus,
236
+ target_description: `25-45% reduction target is ${targetStatus}. Measured: ${percentageReduction}%`,
237
+ dynamic_usage: {
238
+ avg_invocation_tokens_per_session: Math.round(avgPostOptPerSession),
239
+ total_invocation_tokens: postOptTotal,
240
+ sessions_analyzed: sessionCount
241
+ },
242
+ workflow_comparison: workflowComparison,
243
+ per_tool_breakdown: Object.values(toolStats).map(t => ({
244
+ tool_name: t.tool_name,
245
+ total_invocations: t.total_invocations,
246
+ avg_invocations_per_session: Math.round(t.avg_invocations_per_session * 10) / 10,
247
+ total_tokens: t.total_token_cost_input + t.total_token_cost_output,
248
+ avg_tokens_per_session: Math.round(t.avg_tokens_per_session)
249
+ })).sort((a, b) => b.total_tokens - a.total_tokens)
250
+ };
251
+ }
252
+
253
+ // --- Promote/Demote Recommendations (ACs 7-9, 13-14) ---
254
+ function generateRecommendations(usageData, registry, thresholds) {
255
+ if (!usageData || usageData.sessions.length === 0) {
256
+ return [];
257
+ }
258
+
259
+ const { toolStats, sessionCount } = aggregateUsage(usageData.sessions);
260
+ const recommendations = [];
261
+
262
+ for (const [toolName, stat] of Object.entries(toolStats)) {
263
+ const currentTier = getToolTier(registry, toolName);
264
+
265
+ // Promote: tool used >10 times per session average across 5+ sessions (AC 7, 13)
266
+ if (
267
+ stat.avg_invocations_per_session > thresholds.promote.minUsesPerSession &&
268
+ stat.sessions_used >= thresholds.promote.minSessions &&
269
+ currentTier !== 'tier_1' // Don't promote if already Tier 1
270
+ ) {
271
+ recommendations.push({
272
+ tool_name: toolName,
273
+ action: 'promote',
274
+ current_tier: currentTier,
275
+ recommended_tier: currentTier === 'tier_3' ? 'tier_2' : 'tier_1',
276
+ evidence: {
277
+ avg_invocations_per_session: Math.round(stat.avg_invocations_per_session * 10) / 10,
278
+ sessions_used: stat.sessions_used,
279
+ total_sessions: sessionCount,
280
+ threshold_invocations: thresholds.promote.minUsesPerSession,
281
+ threshold_sessions: thresholds.promote.minSessions
282
+ },
283
+ rationale: `Tool used ${Math.round(stat.avg_invocations_per_session * 10) / 10} times/session across ${stat.sessions_used} sessions (threshold: >${thresholds.promote.minUsesPerSession}/session, ${thresholds.promote.minSessions}+ sessions)`
284
+ });
285
+ }
286
+
287
+ // Demote: tool used <1 time per N sessions (AC 8, 14)
288
+ // C2 fix: precise calculation — sessions_used/sessionCount gives the fraction
289
+ // of sessions where tool appeared. Compare against maxUsesPerNSessions/sessionWindow
290
+ // meaning "less than 1 use per 5 sessions" = usage rate < 1/5 = 0.2
291
+ const usageRate = sessionCount > 0 ? stat.sessions_used / sessionCount : 0;
292
+ const demoteThresholdRate = thresholds.demote.maxUsesPerNSessions / thresholds.demote.sessionWindow;
293
+
294
+ if (
295
+ usageRate < demoteThresholdRate &&
296
+ sessionCount >= thresholds.demote.sessionWindow &&
297
+ currentTier !== 'tier_3' // Don't demote if already Tier 3
298
+ ) {
299
+ recommendations.push({
300
+ tool_name: toolName,
301
+ action: 'demote',
302
+ current_tier: currentTier,
303
+ recommended_tier: currentTier === 'tier_1' ? 'tier_2' : 'tier_3',
304
+ evidence: {
305
+ usage_rate: Math.round(usageRate * 1000) / 1000,
306
+ demote_threshold_rate: demoteThresholdRate,
307
+ sessions_used: stat.sessions_used,
308
+ total_sessions: sessionCount,
309
+ threshold_max_uses: thresholds.demote.maxUsesPerNSessions,
310
+ threshold_session_window: thresholds.demote.sessionWindow
311
+ },
312
+ rationale: `Tool used in ${stat.sessions_used}/${sessionCount} sessions (rate: ${Math.round(usageRate * 100)}%). Threshold: <${thresholds.demote.maxUsesPerNSessions} per ${thresholds.demote.sessionWindow} sessions (${Math.round(demoteThresholdRate * 100)}%)`
313
+ });
314
+ }
315
+ }
316
+
317
+ // Check for tools in registry that are never used
318
+ if (registry && registry.tools && sessionCount >= thresholds.demote.sessionWindow) {
319
+ for (const [toolName, toolDef] of Object.entries(registry.tools)) {
320
+ if (!toolStats[toolName] && toolDef.tier < 3) {
321
+ recommendations.push({
322
+ tool_name: toolName,
323
+ action: 'demote',
324
+ current_tier: `tier_${toolDef.tier}`,
325
+ recommended_tier: 'tier_3',
326
+ evidence: {
327
+ usage_rate: 0,
328
+ sessions_used: 0,
329
+ total_sessions: sessionCount
330
+ },
331
+ rationale: `Tool never used in ${sessionCount} analyzed sessions. Consider demotion to Tier 3 (deferred).`
332
+ });
333
+ }
334
+ }
335
+ }
336
+
337
+ return recommendations;
338
+ }
339
+
340
+ // --- Generate Summary Report (ACs 16-17) ---
341
+ function generateReport(comparison, recommendations, usageData, thresholds) {
342
+ const sessions = usageData ? usageData.sessions : [];
343
+ const sessionCount = sessions.length;
344
+
345
+ // Measurement period
346
+ let periodStart = null;
347
+ let periodEnd = null;
348
+ if (sessionCount > 0) {
349
+ const timestamps = sessions.map(s => s.timestamp).filter(Boolean).sort();
350
+ periodStart = timestamps[0];
351
+ periodEnd = timestamps[timestamps.length - 1];
352
+ }
353
+
354
+ return {
355
+ version: '1.0.0',
356
+ generated_at: new Date().toISOString(),
357
+ story: 'TOK-5',
358
+ epic: 'Token Optimization — Intelligent Tool Loading',
359
+ measurement_period: {
360
+ start: periodStart,
361
+ end: periodEnd,
362
+ sessions_analyzed: sessionCount
363
+ },
364
+ baseline_comparison: comparison,
365
+ total_tokens_saved: comparison.available ? comparison.absolute_reduction_tokens : 0,
366
+ percentage_reduction: comparison.available ? comparison.percentage_reduction : 0,
367
+ target_status: comparison.available ? comparison.target_25_45_pct : 'NO_DATA',
368
+ recommendations_count: recommendations.length,
369
+ promote_count: recommendations.filter(r => r.action === 'promote').length,
370
+ demote_count: recommendations.filter(r => r.action === 'demote').length,
371
+ thresholds_used: thresholds
372
+ };
373
+ }
374
+
375
+ // --- Save Recommendations as YAML (AC 9) ---
376
+ function saveRecommendations(recommendations, dryRun) {
377
+ const yamlContent = yaml.dump({
378
+ version: '1.0.0',
379
+ generated_at: new Date().toISOString(),
380
+ story: 'TOK-5',
381
+ recommendations_count: recommendations.length,
382
+ recommendations: recommendations
383
+ }, { lineWidth: 120, noRefs: true });
384
+
385
+ if (!dryRun) {
386
+ if (!fs.existsSync(ANALYTICS_DIR)) {
387
+ fs.mkdirSync(ANALYTICS_DIR, { recursive: true });
388
+ }
389
+ fs.writeFileSync(RECOMMENDATIONS_FILE, yamlContent, 'utf8');
390
+ }
391
+ return yamlContent;
392
+ }
393
+
394
+ // --- Save Report as JSON (AC 16) ---
395
+ function saveReport(report, dryRun) {
396
+ const content = JSON.stringify(report, null, 2);
397
+ if (!dryRun) {
398
+ if (!fs.existsSync(ANALYTICS_DIR)) {
399
+ fs.mkdirSync(ANALYTICS_DIR, { recursive: true });
400
+ }
401
+ fs.writeFileSync(REPORT_FILE, content, 'utf8');
402
+ }
403
+ return content;
404
+ }
405
+
406
+ // --- Main ---
407
+ function main() {
408
+ const args = process.argv.slice(2);
409
+ const dryRun = args.includes('--dry-run');
410
+ const jsonOutput = args.includes('--json');
411
+ const verbose = args.includes('--verbose');
412
+
413
+ // Load data
414
+ const baseline = loadBaseline();
415
+ const usageData = loadUsageData();
416
+ const registry = loadToolRegistry();
417
+ const thresholds = loadThresholds();
418
+
419
+ if (!baseline) {
420
+ console.error('[TOK-5] Error: Baseline not found at', BASELINE_FILE);
421
+ console.error('[TOK-5] Run TOK-1.5 baseline collection first.');
422
+ process.exit(1);
423
+ }
424
+
425
+ if (!usageData || usageData.sessions.length === 0) {
426
+ console.error('[TOK-5] Error: No usage data found at', USAGE_FILE);
427
+ console.error('[TOK-5] Run collect-tool-usage.js to collect session data first.');
428
+ process.exit(1);
429
+ }
430
+
431
+ // Baseline comparison (ACs 4-6)
432
+ const comparison = compareBaseline(baseline, usageData, registry);
433
+
434
+ // Promote/demote recommendations (ACs 7-9, 13-14)
435
+ const recommendations = generateRecommendations(usageData, registry, thresholds);
436
+
437
+ // Summary report (ACs 16-17)
438
+ const report = generateReport(comparison, recommendations, usageData, thresholds);
439
+
440
+ // Save outputs
441
+ saveReport(report, dryRun);
442
+ saveRecommendations(recommendations, dryRun);
443
+
444
+ // Console output
445
+ if (jsonOutput) {
446
+ console.log(JSON.stringify({ report, recommendations }, null, 2));
447
+ } else {
448
+ console.log('=== TOK-5 Optimization Report ===');
449
+ console.log(`Sessions analyzed: ${report.measurement_period.sessions_analyzed}`);
450
+ console.log(`Period: ${report.measurement_period.start || 'N/A'} → ${report.measurement_period.end || 'N/A'}`);
451
+ console.log('');
452
+
453
+ if (comparison.available) {
454
+ console.log('--- Baseline Comparison ---');
455
+ console.log(`Baseline overhead: ${comparison.baseline_overhead_tokens} tokens`);
456
+ console.log(`Post-optimization: ${comparison.post_optimization_overhead_tokens} tokens`);
457
+ console.log(`Reduction: ${comparison.absolute_reduction_tokens} tokens (${comparison.percentage_reduction}%)`);
458
+ console.log(`Target (25-45%): ${comparison.target_25_45_pct}`);
459
+ } else {
460
+ console.log(`Baseline comparison: ${comparison.reason}`);
461
+ }
462
+
463
+ console.log('');
464
+ console.log('--- Recommendations ---');
465
+ console.log(`Total: ${recommendations.length} (${report.promote_count} promote, ${report.demote_count} demote)`);
466
+
467
+ if (verbose && recommendations.length > 0) {
468
+ for (const rec of recommendations) {
469
+ console.log(` ${rec.action.toUpperCase()}: ${rec.tool_name} (${rec.current_tier} → ${rec.recommended_tier})`);
470
+ console.log(` Rationale: ${rec.rationale}`);
471
+ }
472
+ }
473
+
474
+ console.log('');
475
+ if (dryRun) {
476
+ console.log('[TOK-5] Dry run — no files written.');
477
+ } else {
478
+ console.log(`[TOK-5] Report: ${REPORT_FILE}`);
479
+ console.log(`[TOK-5] Recommendations: ${RECOMMENDATIONS_FILE}`);
480
+ }
481
+ }
482
+ }
483
+
484
+ // Run main only when executed directly (not when required as module)
485
+ if (require.main === module) {
486
+ main();
487
+ }
488
+
489
+ // --- Exports for testing ---
490
+ module.exports = {
491
+ loadThresholds,
492
+ compareBaseline,
493
+ generateRecommendations,
494
+ generateReport,
495
+ aggregateUsage,
496
+ DEFAULT_THRESHOLDS
497
+ };