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,361 @@
1
+ 'use strict';
2
+
3
+ const { CodeIntelSource } = require('./data-sources/code-intel-source');
4
+ const { RegistrySource } = require('./data-sources/registry-source');
5
+ const { MetricsSource } = require('./data-sources/metrics-source');
6
+ const { renderTree } = require('./renderers/tree-renderer');
7
+ const { renderStats } = require('./renderers/stats-renderer');
8
+ const { renderStatus } = require('./renderers/status-renderer');
9
+ const { formatAsJson } = require('./formatters/json-formatter');
10
+ const { formatAsDot } = require('./formatters/dot-formatter');
11
+ const { formatAsMermaid } = require('./formatters/mermaid-formatter');
12
+ const { formatAsHtml } = require('./formatters/html-formatter');
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const { exec } = require('child_process');
17
+
18
+ const MAX_SUMMARY_PER_CATEGORY = 5;
19
+ const DEFAULT_WATCH_INTERVAL_MS = 5000;
20
+ const DEBOUNCE_MS = 300;
21
+
22
+ const FORMAT_MAP = {
23
+ json: formatAsJson,
24
+ dot: formatAsDot,
25
+ mermaid: formatAsMermaid,
26
+ html: formatAsHtml,
27
+ };
28
+
29
+ const VALID_FORMATS = ['ascii', ...Object.keys(FORMAT_MAP)];
30
+
31
+ const WATCH_FORMAT_MAP = {
32
+ dot: { formatter: formatAsDot, filename: 'graph.dot' },
33
+ mermaid: { formatter: formatAsMermaid, filename: 'graph.mmd' },
34
+ html: {
35
+ formatter: (graphData) => formatAsHtml(graphData, { autoRefresh: true, refreshInterval: 5 }),
36
+ filename: 'graph.html',
37
+ },
38
+ };
39
+
40
+ const COMMANDS = {
41
+ '--deps': handleDeps,
42
+ '--stats': handleStats,
43
+ '--help': handleHelp,
44
+ '-h': handleHelp,
45
+ };
46
+
47
+ /**
48
+ * Parse CLI arguments into structured args object.
49
+ * @param {string[]} argv - Raw CLI arguments
50
+ * @returns {Object} Parsed args
51
+ */
52
+ function parseArgs(argv) {
53
+ const args = {
54
+ command: null,
55
+ format: 'ascii',
56
+ file: null,
57
+ interval: 5,
58
+ watch: false,
59
+ help: false,
60
+ };
61
+
62
+ for (let i = 0; i < argv.length; i++) {
63
+ const arg = argv[i];
64
+
65
+ if (arg === '--help' || arg === '-h') {
66
+ args.help = true;
67
+ args.command = '--help';
68
+ } else if (arg === '--deps') {
69
+ args.command = '--deps';
70
+ } else if (arg === '--stats') {
71
+ args.command = '--stats';
72
+ } else if (arg === '--watch') {
73
+ args.watch = true;
74
+ } else if (arg === '--format' && i + 1 < argv.length) {
75
+ args.format = argv[++i];
76
+ } else if (arg.startsWith('--format=')) {
77
+ args.format = arg.split('=')[1];
78
+ } else if (arg === '--interval' && i + 1 < argv.length) {
79
+ args.interval = parseInt(argv[++i], 10);
80
+ } else if (arg.startsWith('--interval=')) {
81
+ args.interval = parseInt(arg.split('=')[1], 10);
82
+ } else if (arg.startsWith('--') && !args.command) {
83
+ args.command = arg;
84
+ }
85
+ }
86
+
87
+ return args;
88
+ }
89
+
90
+ /**
91
+ * Handle --deps command: render dependency tree or formatted output.
92
+ * If --watch is set, delegates to handleWatch.
93
+ * @param {Object} args - Parsed CLI args
94
+ */
95
+ async function handleDeps(args) {
96
+ const format = args.format || 'ascii';
97
+
98
+ if (format !== 'ascii' && !FORMAT_MAP[format]) {
99
+ console.error(`Unknown format: ${format}. Valid formats: ${VALID_FORMATS.join(', ')}`);
100
+ process.exit(1);
101
+ }
102
+
103
+ if (args.watch) {
104
+ return handleWatch(args);
105
+ }
106
+
107
+ const source = new CodeIntelSource();
108
+ const graphData = await source.getData();
109
+
110
+ if (format === 'html') {
111
+ return handleHtmlOutput(graphData);
112
+ }
113
+
114
+ if (format !== 'ascii') {
115
+ const formatter = FORMAT_MAP[format];
116
+ process.stdout.write(formatter(graphData) + '\n');
117
+ return;
118
+ }
119
+
120
+ const isTTY = process.stdout.isTTY;
121
+ const output = renderTree(graphData, { color: isTTY, unicode: isTTY });
122
+ console.log(output);
123
+ }
124
+
125
+ /**
126
+ * Write HTML graph to .aios/graph.html and open in default browser.
127
+ * @param {Object} graphData - Normalized graph data
128
+ * @param {Object} [options] - Options passed to formatAsHtml
129
+ * @returns {string} Output file path
130
+ */
131
+ function handleHtmlOutput(graphData, options = {}) {
132
+ const outputDir = path.resolve(process.cwd(), '.aios');
133
+ const outputPath = path.join(outputDir, 'graph.html');
134
+
135
+ fs.mkdirSync(outputDir, { recursive: true });
136
+
137
+ const html = formatAsHtml(graphData, options);
138
+ fs.writeFileSync(outputPath, html, 'utf8');
139
+
140
+ const nodeCount = (graphData.nodes || []).length;
141
+ console.log(`HTML graph written to ${outputPath} (${nodeCount} entities)`);
142
+
143
+ openInBrowser(outputPath);
144
+ return outputPath;
145
+ }
146
+
147
+ /**
148
+ * Open a file in the default browser (cross-platform).
149
+ * @param {string} filePath - Absolute path to file
150
+ */
151
+ function openInBrowser(filePath) {
152
+ const platform = process.platform;
153
+ const cmd = platform === 'win32' ? 'start ""' : platform === 'darwin' ? 'open' : 'xdg-open';
154
+
155
+ exec(`${cmd} "${filePath}"`, (err) => {
156
+ if (err) {
157
+ console.log(`Could not open browser automatically. Open manually: ${filePath}`);
158
+ }
159
+ });
160
+ }
161
+
162
+ /**
163
+ * Handle --watch mode: regenerate graph file on interval and on file changes.
164
+ * Writes to .aios/graph.dot, .aios/graph.mmd, or .aios/graph.html.
165
+ * @param {Object} args - Parsed CLI args
166
+ * @returns {Object} Watch state for cleanup (used by tests)
167
+ */
168
+ async function handleWatch(args) {
169
+ const watchFormat = WATCH_FORMAT_MAP[args.format] ? args.format : 'dot';
170
+ const { formatter, filename } = WATCH_FORMAT_MAP[watchFormat];
171
+ const intervalMs = (args.interval || 5) * 1000;
172
+ const outputDir = path.resolve(process.cwd(), '.aios');
173
+ const outputPath = path.join(outputDir, filename);
174
+
175
+ fs.mkdirSync(outputDir, { recursive: true });
176
+
177
+ const source = new CodeIntelSource();
178
+
179
+ async function regenerate() {
180
+ try {
181
+ const graphData = await source.getData();
182
+ const content = formatter(graphData);
183
+ fs.writeFileSync(outputPath, content, 'utf8');
184
+ const nodeCount = (graphData.nodes || []).length;
185
+ console.log(`[watch] ${filename} updated (${nodeCount} entities)`);
186
+ } catch (err) {
187
+ console.error(`[watch] regeneration failed: ${err.message}`);
188
+ }
189
+ }
190
+
191
+ await regenerate();
192
+
193
+ const intervalId = setInterval(regenerate, intervalMs);
194
+
195
+ let fileWatcher = null;
196
+ let debounceTimer = null;
197
+ const registryPath = path.resolve(process.cwd(), '.aios-core/data/entity-registry.yaml');
198
+
199
+ try {
200
+ if (fs.existsSync(registryPath)) {
201
+ fileWatcher = fs.watch(registryPath, () => {
202
+ if (debounceTimer) {
203
+ clearTimeout(debounceTimer);
204
+ }
205
+ debounceTimer = setTimeout(regenerate, DEBOUNCE_MS);
206
+ });
207
+ }
208
+ } catch (_err) {
209
+ // fs.watch not available or path inaccessible; interval-only mode
210
+ }
211
+
212
+ function cleanup() {
213
+ clearInterval(intervalId);
214
+ if (debounceTimer) {
215
+ clearTimeout(debounceTimer);
216
+ }
217
+ if (fileWatcher) {
218
+ fileWatcher.close();
219
+ }
220
+ console.log('[watch] stopped');
221
+ }
222
+
223
+ process.once('SIGINT', () => {
224
+ cleanup();
225
+ process.exit(0);
226
+ });
227
+
228
+ return { intervalId, fileWatcher, cleanup, outputPath };
229
+ }
230
+
231
+ /**
232
+ * Handle --stats command: render entity statistics and cache metrics.
233
+ * @param {Object} args - Parsed CLI args
234
+ */
235
+ async function handleStats(_args) {
236
+ const registrySource = new RegistrySource();
237
+ const metricsSource = new MetricsSource();
238
+ const [registryData, metricsData] = await Promise.all([
239
+ registrySource.getData(),
240
+ metricsSource.getData(),
241
+ ]);
242
+ const isTTY = process.stdout.isTTY;
243
+ const output = renderStats(registryData, metricsData, { isTTY: !!isTTY });
244
+
245
+ process.stdout.write(output + '\n');
246
+ }
247
+
248
+ /**
249
+ * Handle --help command: show usage text.
250
+ */
251
+ function handleHelp() {
252
+ const usage = `
253
+ Usage: aios graph [command] [options]
254
+
255
+ Commands:
256
+ --deps Show dependency tree as ASCII text
257
+ --stats Show entity statistics and cache metrics
258
+ --help, -h Show this help message
259
+
260
+ Options:
261
+ --format=FORMAT Output format: ascii (default), json, dot, mermaid, html
262
+ --watch Live mode: regenerate graph file on interval
263
+ --interval=N Seconds between regeneration in watch mode (default: 5)
264
+
265
+ Examples:
266
+ aios graph --deps Show dependency tree
267
+ aios graph --deps --format=json Output as JSON
268
+ aios graph --deps --format=html Interactive HTML graph (opens browser)
269
+ aios graph --deps --watch Live DOT file for VS Code preview
270
+ aios graph --deps --watch --format=html Live HTML with auto-refresh
271
+ aios graph --deps --watch --format=mermaid Live Mermaid file
272
+ aios graph --deps --watch --interval=10 Refresh every 10 seconds
273
+ aios graph --stats Show entity stats and cache metrics
274
+ `.trim();
275
+
276
+ console.log(usage);
277
+ }
278
+
279
+ /**
280
+ * Handle default summary view: dependency tree (compact) + stats + provider status.
281
+ * @param {Object} args - Parsed CLI args
282
+ */
283
+ async function handleSummary(args) {
284
+ const codeIntelSource = new CodeIntelSource();
285
+ const registrySource = new RegistrySource();
286
+ const metricsSource = new MetricsSource();
287
+
288
+ const [graphData, registryData, metricsData] = await Promise.all([
289
+ codeIntelSource.getData(),
290
+ registrySource.getData(),
291
+ metricsSource.getData(),
292
+ ]);
293
+
294
+ const isTTY = !!process.stdout.isTTY;
295
+ const sections = [];
296
+
297
+ sections.push('AIOS Graph Dashboard');
298
+ sections.push(isTTY ? '\u2550'.repeat(35) : '='.repeat(35));
299
+ sections.push('');
300
+
301
+ const treeOutput = renderTree(graphData, {
302
+ color: isTTY,
303
+ unicode: isTTY,
304
+ maxPerCategory: MAX_SUMMARY_PER_CATEGORY,
305
+ });
306
+ sections.push(treeOutput);
307
+ sections.push('');
308
+
309
+ const statsOutput = renderStats(registryData, metricsData, { isTTY });
310
+ sections.push(statsOutput);
311
+ sections.push('');
312
+
313
+ const statusOutput = renderStatus(metricsData, { isTTY });
314
+ sections.push(statusOutput);
315
+
316
+ process.stdout.write(sections.join('\n') + '\n');
317
+ }
318
+
319
+ /**
320
+ * Main CLI entry point.
321
+ * @param {string[]} argv - Raw CLI arguments
322
+ */
323
+ async function run(argv) {
324
+ const args = parseArgs(argv);
325
+
326
+ if (args.help) {
327
+ handleHelp();
328
+ return;
329
+ }
330
+
331
+ if (args.command === null) {
332
+ return handleSummary(args);
333
+ }
334
+
335
+ const handler = COMMANDS[args.command];
336
+ if (!handler) {
337
+ console.error(`Unknown command: ${args.command}`);
338
+ handleHelp();
339
+ process.exit(1);
340
+ }
341
+
342
+ return handler(args);
343
+ }
344
+
345
+ module.exports = {
346
+ run,
347
+ parseArgs,
348
+ handleDeps,
349
+ handleStats,
350
+ handleHelp,
351
+ handleWatch,
352
+ handleSummary,
353
+ handleHtmlOutput,
354
+ openInBrowser,
355
+ MAX_SUMMARY_PER_CATEGORY,
356
+ DEFAULT_WATCH_INTERVAL_MS,
357
+ DEBOUNCE_MS,
358
+ FORMAT_MAP,
359
+ VALID_FORMATS,
360
+ WATCH_FORMAT_MAP,
361
+ };
@@ -0,0 +1,234 @@
1
+ 'use strict';
2
+
3
+ const { getClient, isCodeIntelAvailable } = require('../../code-intel');
4
+ const { RegistryLoader } = require('../../ids/registry-loader');
5
+
6
+ /**
7
+ * Data source that provides normalized graph data from code-intel
8
+ * or falls back to entity-registry.yaml when provider is offline.
9
+ */
10
+ /**
11
+ * Classify a script entity into subcategory based on its path.
12
+ * @param {string} filePath - Entity path
13
+ * @returns {string} 'scripts/task' | 'scripts/engine' | 'scripts/infra'
14
+ */
15
+ function _classifyScript(filePath) {
16
+ if (filePath.includes('/development/scripts/')) return 'scripts/task';
17
+ if (filePath.includes('/core/')) return 'scripts/engine';
18
+ if (filePath.includes('/infrastructure/')) return 'scripts/infra';
19
+ return 'scripts/task';
20
+ }
21
+
22
+ /**
23
+ * Detect fine-grained category from entity path and base category.
24
+ * @param {string} baseCategory - Original category from registry/provider
25
+ * @param {string} filePath - Entity path
26
+ * @returns {string} Refined category
27
+ */
28
+ function _detectCategory(baseCategory, filePath) {
29
+ const path = (filePath || '').toLowerCase();
30
+
31
+ if (path.includes('/checklists/')) return 'checklists';
32
+ if (path.includes('/workflows/')) return 'workflows';
33
+ if (path.includes('/utils/')) return 'utils';
34
+ if (path.includes('/data/')) return 'data';
35
+ if (path.includes('/tools/')) return 'tools';
36
+
37
+ if (baseCategory === 'scripts' || path.includes('/scripts/')) {
38
+ return _classifyScript(path);
39
+ }
40
+
41
+ return baseCategory;
42
+ }
43
+
44
+ class CodeIntelSource {
45
+ /**
46
+ * @param {Object} [options]
47
+ * @param {number} [options.cacheTTL=5000] - Cache TTL in milliseconds
48
+ */
49
+ constructor(options = {}) {
50
+ this._cache = null;
51
+ this._cacheTimestamp = 0;
52
+ this._cacheTTL = options.cacheTTL || 5000;
53
+ }
54
+
55
+ /**
56
+ * Get normalized graph data.
57
+ * Primary: code-intel provider (live data).
58
+ * Fallback: entity-registry.yaml (static data).
59
+ * @returns {Promise<Object>} { nodes, edges, source, isFallback, timestamp }
60
+ */
61
+ async getData() {
62
+ if (this._cache && !this.isStale()) {
63
+ return this._cache;
64
+ }
65
+
66
+ let result;
67
+
68
+ try {
69
+ if (isCodeIntelAvailable()) {
70
+ const client = getClient();
71
+ const deps = await client.analyzeDependencies('.');
72
+ result = this._wrap(this._normalizeDeps(deps), 'code-intel', false);
73
+ } else {
74
+ result = this._getRegistryFallback();
75
+ }
76
+ } catch (_err) {
77
+ result = this._getRegistryFallback();
78
+ }
79
+
80
+ this._cache = result;
81
+ this._cacheTimestamp = Date.now();
82
+ return result;
83
+ }
84
+
85
+ /**
86
+ * Get timestamp of last successful data fetch.
87
+ * @returns {number}
88
+ */
89
+ getLastUpdate() {
90
+ return this._cacheTimestamp;
91
+ }
92
+
93
+ /**
94
+ * Check if cached data is expired.
95
+ * @returns {boolean}
96
+ */
97
+ isStale() {
98
+ return Date.now() - this._cacheTimestamp > this._cacheTTL;
99
+ }
100
+
101
+ /**
102
+ * Load graph data from entity-registry.yaml as fallback.
103
+ * @returns {Object} Wrapped graph data
104
+ */
105
+ _getRegistryFallback() {
106
+ try {
107
+ const loader = new RegistryLoader();
108
+ const registry = loader.load();
109
+ return this._wrap(this._registryToTree(registry), 'registry', true);
110
+ } catch (_err) {
111
+ return this._wrap({ nodes: [], edges: [] }, 'registry', true);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Normalize analyzeDependencies output to { nodes, edges }.
117
+ * Handles various shapes from different providers.
118
+ * @param {*} deps - Raw output from analyzeDependencies
119
+ * @returns {Object} { nodes: Array, edges: Array }
120
+ */
121
+ _normalizeDeps(deps) {
122
+ if (!deps) {
123
+ return { nodes: [], edges: [] };
124
+ }
125
+
126
+ // Already normalized format
127
+ if (Array.isArray(deps.nodes) && Array.isArray(deps.edges)) {
128
+ return { nodes: deps.nodes, edges: deps.edges };
129
+ }
130
+
131
+ // Array of dependency objects
132
+ if (Array.isArray(deps)) {
133
+ const nodes = [];
134
+ const edges = [];
135
+ const seen = new Set();
136
+
137
+ for (const dep of deps) {
138
+ const id = dep.id || dep.name || dep.path;
139
+ if (!id || seen.has(id)) continue;
140
+ seen.add(id);
141
+
142
+ nodes.push({
143
+ id,
144
+ label: dep.label || dep.name || id,
145
+ type: dep.type || 'unknown',
146
+ path: dep.path || '',
147
+ category: _detectCategory(dep.category || dep.type || 'other', dep.path || ''),
148
+ });
149
+
150
+ for (const target of dep.dependencies || dep.deps || []) {
151
+ edges.push({ from: id, to: target, type: 'depends' });
152
+ }
153
+ }
154
+
155
+ return { nodes, edges };
156
+ }
157
+
158
+ // Flat object with dependencies property
159
+ if (deps.dependencies && typeof deps.dependencies === 'object') {
160
+ return this._normalizeDeps(
161
+ Object.entries(deps.dependencies).map(([key, val]) => ({
162
+ id: key,
163
+ ...((typeof val === 'object' && val) || {}),
164
+ }))
165
+ );
166
+ }
167
+
168
+ return { nodes: [], edges: [] };
169
+ }
170
+
171
+ /**
172
+ * Convert entity-registry to normalized graph format.
173
+ * Groups entities by category and maps dependencies/usedBy to edges.
174
+ * @param {Object} registry - Loaded registry data
175
+ * @returns {Object} { nodes: Array, edges: Array }
176
+ */
177
+ _registryToTree(registry) {
178
+ const nodes = [];
179
+ const edges = [];
180
+ const edgeSet = new Set();
181
+
182
+ for (const [category, entities] of Object.entries(registry.entities || {})) {
183
+ if (!entities || typeof entities !== 'object') continue;
184
+
185
+ for (const [entityId, entity] of Object.entries(entities)) {
186
+ nodes.push({
187
+ id: entityId,
188
+ label: entityId,
189
+ type: entity.type || category,
190
+ path: entity.path || '',
191
+ category: _detectCategory(category, entity.path || ''),
192
+ lifecycle: entity.lifecycle || 'production', // NOG-16C: pass lifecycle for graph filtering
193
+ });
194
+
195
+ for (const dep of entity.dependencies || []) {
196
+ const edgeKey = `${entityId}->depends->${dep}`;
197
+ if (!edgeSet.has(edgeKey)) {
198
+ edgeSet.add(edgeKey);
199
+ edges.push({ from: entityId, to: dep, type: 'depends' });
200
+ }
201
+ }
202
+
203
+ for (const consumer of entity.usedBy || []) {
204
+ const edgeKey = `${consumer}->uses->${entityId}`;
205
+ if (!edgeSet.has(edgeKey)) {
206
+ edgeSet.add(edgeKey);
207
+ edges.push({ from: consumer, to: entityId, type: 'uses' });
208
+ }
209
+ }
210
+ }
211
+ }
212
+
213
+ return { nodes, edges };
214
+ }
215
+
216
+ /**
217
+ * Wrap data in standard result envelope.
218
+ * @param {Object} data - { nodes, edges }
219
+ * @param {string} source - 'code-intel' | 'registry'
220
+ * @param {boolean} isFallback
221
+ * @returns {Object}
222
+ */
223
+ _wrap(data, source, isFallback) {
224
+ return {
225
+ nodes: data.nodes || [],
226
+ edges: data.edges || [],
227
+ source,
228
+ isFallback,
229
+ timestamp: Date.now(),
230
+ };
231
+ }
232
+ }
233
+
234
+ module.exports = { CodeIntelSource, _classifyScript, _detectCategory };
@@ -0,0 +1,95 @@
1
+ 'use strict';
2
+
3
+ const { getClient, isCodeIntelAvailable } = require('../../code-intel');
4
+
5
+ /**
6
+ * Data source that provides cache and latency metrics from the code-intel client.
7
+ * Falls back to offline data when Code Graph MCP is unavailable.
8
+ * Implements the same interface as CodeIntelSource: getData(), getLastUpdate(), isStale().
9
+ */
10
+ class MetricsSource {
11
+ /**
12
+ * @param {Object} [options]
13
+ * @param {number} [options.cacheTTL=5000] - Cache TTL in milliseconds
14
+ */
15
+ constructor(options = {}) {
16
+ this._cache = null;
17
+ this._cacheTimestamp = 0;
18
+ this._cacheTTL = options.cacheTTL || 5000;
19
+ }
20
+
21
+ /**
22
+ * Get metrics from code-intel client.
23
+ * Primary: live metrics from active provider.
24
+ * Fallback: offline placeholder with providerAvailable=false.
25
+ * @returns {Promise<Object>} Metrics object
26
+ */
27
+ async getData() {
28
+ if (this._cache && !this.isStale()) {
29
+ return this._cache;
30
+ }
31
+
32
+ let result;
33
+
34
+ try {
35
+ if (isCodeIntelAvailable()) {
36
+ const client = getClient();
37
+ const metrics = client.getMetrics();
38
+ result = {
39
+ cacheHits: metrics.cacheHits || 0,
40
+ cacheMisses: metrics.cacheMisses || 0,
41
+ cacheHitRate: metrics.cacheHitRate || 0,
42
+ circuitBreakerState: metrics.circuitBreakerState || 'CLOSED',
43
+ latencyLog: metrics.latencyLog || [],
44
+ providerAvailable: true,
45
+ activeProvider: metrics.activeProvider || null,
46
+ timestamp: Date.now(),
47
+ };
48
+ } else {
49
+ result = this._offlineMetrics();
50
+ }
51
+ } catch (_err) {
52
+ result = this._offlineMetrics();
53
+ }
54
+
55
+ this._cache = result;
56
+ this._cacheTimestamp = Date.now();
57
+ return result;
58
+ }
59
+
60
+ /**
61
+ * Get timestamp of last successful data fetch.
62
+ * @returns {number}
63
+ */
64
+ getLastUpdate() {
65
+ return this._cacheTimestamp;
66
+ }
67
+
68
+ /**
69
+ * Check if cached data is expired.
70
+ * @returns {boolean}
71
+ */
72
+ isStale() {
73
+ return Date.now() - this._cacheTimestamp > this._cacheTTL;
74
+ }
75
+
76
+ /**
77
+ * Return offline placeholder metrics.
78
+ * @returns {Object}
79
+ * @private
80
+ */
81
+ _offlineMetrics() {
82
+ return {
83
+ cacheHits: 0,
84
+ cacheMisses: 0,
85
+ cacheHitRate: 0,
86
+ circuitBreakerState: 'CLOSED',
87
+ latencyLog: [],
88
+ providerAvailable: false,
89
+ activeProvider: null,
90
+ timestamp: Date.now(),
91
+ };
92
+ }
93
+ }
94
+
95
+ module.exports = { MetricsSource };