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,300 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const yaml = require('js-yaml');
8
+
9
+ const CORE_CONFIG_FILE = '.aios-core/core-config.yaml';
10
+ const SETTINGS_FILE = '.claude/settings.json';
11
+ const TOOLS = ['Edit', 'Write'];
12
+
13
+ /**
14
+ * Validate that a boundary path does not escape the project root via traversal.
15
+ * Rejects paths containing '..' segments or absolute paths.
16
+ */
17
+ function validateBoundaryPath(p) {
18
+ const segments = p.replace(/\\/g, '/').split('/');
19
+ if (segments.some(function(s) { return s === '..'; })) {
20
+ throw new Error('Path traversal detected in boundary config: ' + p);
21
+ }
22
+ if (path.isAbsolute(p)) {
23
+ throw new Error('Absolute path not allowed in boundary config: ' + p);
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Read boundary configuration from core-config.yaml.
29
+ */
30
+ function readBoundaryConfig(projectRoot) {
31
+ const configPath = path.join(projectRoot, CORE_CONFIG_FILE);
32
+
33
+ if (!fs.existsSync(configPath)) {
34
+ throw new Error(`core-config.yaml not found at ${configPath}`);
35
+ }
36
+
37
+ const content = fs.readFileSync(configPath, 'utf8');
38
+ const config = yaml.load(content);
39
+
40
+ if (!config || !config.boundary) {
41
+ throw new Error('core-config.yaml missing "boundary" section');
42
+ }
43
+
44
+ const { boundary } = config;
45
+
46
+ const result = {
47
+ frameworkProtection: boundary.frameworkProtection !== false,
48
+ protected: Array.isArray(boundary.protected) ? boundary.protected : [],
49
+ exceptions: Array.isArray(boundary.exceptions) ? boundary.exceptions : [],
50
+ };
51
+
52
+ for (const p of result.protected) { validateBoundaryPath(p); }
53
+ for (const p of result.exceptions) { validateBoundaryPath(p); }
54
+
55
+ return result;
56
+ }
57
+
58
+ /**
59
+ * Check if an exception path falls within a given directory.
60
+ */
61
+ function isChildOf(exceptionPath, parentDir) {
62
+ const clean = exceptionPath.replace(/\/\*\*$/, '');
63
+ const parts = clean.split('/');
64
+ const parentParts = parentDir.split('/');
65
+
66
+ if (parts.length <= parentParts.length) {
67
+ return false;
68
+ }
69
+
70
+ for (let i = 0; i < parentParts.length; i++) {
71
+ if (parts[i] !== parentParts[i]) {
72
+ return false;
73
+ }
74
+ }
75
+
76
+ return true;
77
+ }
78
+
79
+ /**
80
+ * Expand a directory one level deep into subdirectory/** and file entries.
81
+ * Returns { dirs: [...], files: [...] } sorted separately.
82
+ */
83
+ function expandOneLevel(dirRelative, projectRoot) {
84
+ const dirAbsolute = path.join(projectRoot, dirRelative);
85
+
86
+ if (!fs.existsSync(dirAbsolute)) {
87
+ return { dirs: [dirRelative + '/**'], files: [] };
88
+ }
89
+
90
+ const entries = fs.readdirSync(dirAbsolute, { withFileTypes: true });
91
+ const dirs = [];
92
+ const files = [];
93
+
94
+ for (const entry of entries) {
95
+ const entryRelative = dirRelative + '/' + entry.name;
96
+ if (entry.isDirectory()) {
97
+ dirs.push(entryRelative);
98
+ } else {
99
+ files.push(entryRelative);
100
+ }
101
+ }
102
+
103
+ dirs.sort();
104
+ files.sort();
105
+
106
+ return { dirs, files };
107
+ }
108
+
109
+ /**
110
+ * For a subdirectory that has exceptions inside it, expand to individual
111
+ * file-level deny rules excluding files/dirs covered by exceptions.
112
+ */
113
+ function expandSubdirWithExceptions(subdirPath, exceptions, projectRoot) {
114
+ const dirAbsolute = path.join(projectRoot, subdirPath);
115
+
116
+ if (!fs.existsSync(dirAbsolute)) {
117
+ return [subdirPath + '/**'];
118
+ }
119
+
120
+ const entries = fs.readdirSync(dirAbsolute, { withFileTypes: true });
121
+ const result = [];
122
+
123
+ for (const entry of entries) {
124
+ const entryRelative = subdirPath + '/' + entry.name;
125
+ const entryGlob = entry.isDirectory() ? entryRelative + '/**' : entryRelative;
126
+
127
+ const isCoveredByException = exceptions.some(function(exc) {
128
+ return exc === entryGlob || exc === entryRelative;
129
+ });
130
+
131
+ if (!isCoveredByException) {
132
+ result.push(entryGlob);
133
+ }
134
+ }
135
+
136
+ result.sort();
137
+ return result;
138
+ }
139
+
140
+ /**
141
+ * Expand protected paths according to the specific rules:
142
+ * - .aios-core/core/** gets expanded one level deep
143
+ * - Subdirs with exceptions inside get expanded further (file-level)
144
+ * - Order: regular subdirs first (sorted), then root files (sorted),
145
+ * then exception-expanded subdirs (sorted) at the end
146
+ * - All other paths stay as-is (no expansion)
147
+ */
148
+ function expandProtectedPaths(protectedPaths, exceptions, projectRoot) {
149
+ const allPaths = [];
150
+
151
+ for (const globPath of protectedPaths) {
152
+ if (globPath === '.aios-core/core/**') {
153
+ const { dirs, files } = expandOneLevel('.aios-core/core', projectRoot);
154
+
155
+ // Separate dirs into regular (no exceptions inside) and special (has exceptions)
156
+ const regularDirs = [];
157
+ const specialDirEntries = [];
158
+
159
+ for (const dir of dirs) {
160
+ const relevantExceptions = exceptions.filter(function(exc) {
161
+ return isChildOf(exc, dir);
162
+ });
163
+
164
+ if (relevantExceptions.length > 0) {
165
+ // Expand this dir further, excluding exceptions
166
+ const expanded = expandSubdirWithExceptions(dir, relevantExceptions, projectRoot);
167
+ specialDirEntries.push(...expanded);
168
+ } else {
169
+ regularDirs.push(dir + '/**');
170
+ }
171
+ }
172
+
173
+ // Order: regular subdirs, then root files, then special-expanded entries
174
+ allPaths.push(...regularDirs);
175
+ allPaths.push(...files);
176
+ allPaths.push(...specialDirEntries);
177
+ } else {
178
+ allPaths.push(globPath);
179
+ }
180
+ }
181
+
182
+ return allPaths;
183
+ }
184
+
185
+ /**
186
+ * Keep exception paths as-is (no expansion needed).
187
+ */
188
+ function expandExceptionPaths(exceptionPaths) {
189
+ return [...exceptionPaths].sort();
190
+ }
191
+
192
+ /**
193
+ * Generate permissions object from boundary config.
194
+ */
195
+ function generatePermissions(boundary, projectRoot) {
196
+ if (!boundary.frameworkProtection) {
197
+ return { deny: [], allow: [] };
198
+ }
199
+
200
+ const denyPaths = expandProtectedPaths(boundary.protected, boundary.exceptions, projectRoot);
201
+
202
+ const deny = [];
203
+ for (const denyPath of denyPaths) {
204
+ for (const tool of TOOLS) {
205
+ deny.push(tool + '(' + denyPath + ')');
206
+ }
207
+ }
208
+
209
+ const allowPaths = expandExceptionPaths(boundary.exceptions);
210
+
211
+ const allow = [];
212
+ for (const allowPath of allowPaths) {
213
+ for (const tool of TOOLS) {
214
+ allow.push(tool + '(' + allowPath + ')');
215
+ }
216
+ }
217
+
218
+ allow.push('Read(.aios-core/**)');
219
+
220
+ return { deny, allow };
221
+ }
222
+
223
+ /**
224
+ * Write settings.json preserving user sections outside permissions.
225
+ */
226
+ function writeSettingsJson(projectRoot, permissions) {
227
+ const claudeDir = path.join(projectRoot, '.claude');
228
+ const fullSettingsPath = path.join(projectRoot, SETTINGS_FILE);
229
+
230
+ if (!fs.existsSync(claudeDir)) {
231
+ fs.mkdirSync(claudeDir, { recursive: true });
232
+ }
233
+
234
+ let existing = {};
235
+ if (fs.existsSync(fullSettingsPath)) {
236
+ try {
237
+ const content = fs.readFileSync(fullSettingsPath, 'utf8');
238
+ existing = JSON.parse(content);
239
+ } catch {
240
+ console.warn('WARNING: Existing settings.json is invalid JSON, starting fresh.');
241
+ existing = {};
242
+ }
243
+ }
244
+
245
+ const updated = { ...existing };
246
+
247
+ if (permissions.deny.length > 0 || permissions.allow.length > 0) {
248
+ updated.permissions = permissions;
249
+ } else {
250
+ delete updated.permissions;
251
+ }
252
+
253
+ const newContent = JSON.stringify(updated, null, 2) + '\n';
254
+
255
+ if (fs.existsSync(fullSettingsPath)) {
256
+ const currentContent = fs.readFileSync(fullSettingsPath, 'utf8');
257
+ if (currentContent === newContent) {
258
+ console.log('PASS: settings.json already up to date, no changes needed.');
259
+ return;
260
+ }
261
+ }
262
+
263
+ fs.writeFileSync(fullSettingsPath, newContent, 'utf8');
264
+ console.log('PASS: settings.json updated with ' + permissions.deny.length + ' deny rules and ' + permissions.allow.length + ' allow rules.');
265
+ }
266
+
267
+ /**
268
+ * Main generator entry point.
269
+ */
270
+ function generate(projectRoot, configOverride) {
271
+ const root = projectRoot || process.cwd();
272
+ const resolvedRoot = path.resolve(root);
273
+
274
+ const boundary = configOverride || readBoundaryConfig(resolvedRoot);
275
+ const permissions = generatePermissions(boundary, resolvedRoot);
276
+
277
+ writeSettingsJson(resolvedRoot, permissions);
278
+ }
279
+
280
+ if (require.main === module) {
281
+ const projectRoot = process.argv[2] || process.cwd();
282
+ try {
283
+ generate(projectRoot);
284
+ } catch (error) {
285
+ console.error('ERROR: ' + error.message);
286
+ process.exit(1);
287
+ }
288
+ }
289
+
290
+ module.exports = {
291
+ generate,
292
+ validateBoundaryPath,
293
+ readBoundaryConfig,
294
+ expandProtectedPaths,
295
+ expandExceptionPaths,
296
+ expandOneLevel,
297
+ expandSubdirWithExceptions,
298
+ generatePermissions,
299
+ writeSettingsJson,
300
+ };
@@ -12,6 +12,8 @@
12
12
  */
13
13
 
14
14
  const { execSync } = require('child_process');
15
+ const fs = require('fs');
16
+ const path = require('path');
15
17
 
16
18
  const DEFAULT_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
17
19
  const GIT_TIMEOUT = 1000; // 1 second
@@ -113,25 +115,79 @@ class GitConfigDetector {
113
115
  * @returns {boolean} True if git repository
114
116
  */
115
117
  _isGitRepository() {
118
+ // NOG-18: Replace execSync (~34ms) with synchronous fs check (~0.05ms).
119
+ // .git/HEAD exists in normal repos AND worktrees (as file or via gitdir link).
116
120
  try {
117
- const output = execSync('git rev-parse --is-inside-work-tree', {
118
- encoding: 'utf8',
119
- timeout: GIT_TIMEOUT,
120
- stdio: ['pipe', 'pipe', 'ignore'], // Suppress stderr
121
- }).trim();
122
-
123
- return output === 'true';
124
- } catch (error) {
121
+ const gitPath = path.join(process.cwd(), '.git');
122
+ // .git can be a directory (normal repo) or a file (worktree with "gitdir:" pointer)
123
+ return fs.existsSync(gitPath);
124
+ } catch {
125
125
  return false;
126
126
  }
127
127
  }
128
128
 
129
129
  /**
130
- * Get current git branch name
130
+ * Get current git branch name via direct .git/HEAD file read.
131
+ * Fallback chain: .git/HEAD read → worktree/gitfile resolution → execSync.
131
132
  * @private
132
133
  * @returns {string|null} Branch name or null
133
134
  */
134
135
  _getCurrentBranch() {
136
+ const direct = this._detectBranchDirect();
137
+ if (direct !== undefined) return direct;
138
+
139
+ // Fallback: execSync (slow but reliable)
140
+ return this._getCurrentBranchExec();
141
+ }
142
+
143
+ /**
144
+ * Read branch directly from .git/HEAD file (~0.06ms vs ~52ms for execSync).
145
+ * Handles: normal branch, detached HEAD, worktree/gitfile.
146
+ * @private
147
+ * @returns {string|null|undefined} Branch name, null (detached/no-git), or undefined (needs fallback)
148
+ */
149
+ _detectBranchDirect() {
150
+ try {
151
+ const gitPath = path.join(process.cwd(), '.git');
152
+ const stat = fs.statSync(gitPath);
153
+
154
+ let headPath;
155
+ if (stat.isFile()) {
156
+ // Worktree/gitfile: .git is a file with "gitdir: <path>"
157
+ const gitContent = fs.readFileSync(gitPath, 'utf8').trim();
158
+ const match = gitContent.match(/^gitdir:\s*(.+)$/);
159
+ if (!match) return undefined;
160
+ const gitDir = path.resolve(process.cwd(), match[1]);
161
+ headPath = path.join(gitDir, 'HEAD');
162
+ } else {
163
+ headPath = path.join(gitPath, 'HEAD');
164
+ }
165
+
166
+ const headContent = fs.readFileSync(headPath, 'utf8').trim();
167
+
168
+ // Normal branch: "ref: refs/heads/feat/my-branch"
169
+ const refMatch = headContent.match(/^ref:\s*refs\/heads\/(.+)$/);
170
+ if (refMatch) return refMatch[1];
171
+
172
+ // Detached HEAD: raw commit hash
173
+ if (/^[0-9a-f]{40}$/.test(headContent)) {
174
+ return headContent.substring(0, 7) + ' (detached)';
175
+ }
176
+
177
+ return undefined; // Unexpected format — fallback
178
+ } catch (_err) {
179
+ // File not found or permission error — could be no .git dir
180
+ if (_err.code === 'ENOENT') return null;
181
+ return undefined; // Other error — fallback
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Fallback: get branch via execSync (original method).
187
+ * @private
188
+ * @returns {string|null} Branch name or null
189
+ */
190
+ _getCurrentBranchExec() {
135
191
  try {
136
192
  const branch = execSync('git branch --show-current', {
137
193
  encoding: 'utf8',
@@ -30,6 +30,7 @@ const { syncGeminiCommands, buildGeminiCommandFiles } = require('./gemini-comman
30
30
  const claudeCodeTransformer = require('./transformers/claude-code');
31
31
  const cursorTransformer = require('./transformers/cursor');
32
32
  const antigravityTransformer = require('./transformers/antigravity');
33
+ const githubCopilotTransformer = require('./transformers/github-copilot');
33
34
 
34
35
  // ANSI colors for output
35
36
  const colors = {
@@ -74,7 +75,7 @@ function loadConfig(projectRoot) {
74
75
  'github-copilot': {
75
76
  enabled: true,
76
77
  path: '.github/agents',
77
- format: 'full-markdown-yaml',
78
+ format: 'github-copilot',
78
79
  },
79
80
  cursor: {
80
81
  enabled: true,
@@ -126,6 +127,7 @@ function getTransformer(format) {
126
127
  'full-markdown-yaml': claudeCodeTransformer,
127
128
  'condensed-rules': cursorTransformer,
128
129
  'cursor-style': antigravityTransformer,
130
+ 'github-copilot': githubCopilotTransformer,
129
131
  };
130
132
 
131
133
  return transformers[format] || claudeCodeTransformer;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * GitHub Copilot Transformer - YAML frontmatter + condensed markdown
3
+ * @story 6.19 - IDE Command Auto-Sync System
4
+ * @issue #138 - Agent files not compatible with GitHub Copilot
5
+ *
6
+ * Format: .agent.md files with YAML frontmatter (--- delimiters)
7
+ * Target: .github/agents/*.agent.md
8
+ *
9
+ * GitHub Copilot custom agents require:
10
+ * - YAML frontmatter with `description` (required), `name`, `tools`
11
+ * - Markdown body under 30,000 characters
12
+ * - File extension: .agent.md
13
+ *
14
+ * @see https://docs.github.com/en/copilot/reference/custom-agents-configuration
15
+ */
16
+
17
+ const { normalizeCommands, getVisibleCommands } = require('../agent-parser');
18
+
19
+ /**
20
+ * Transform agent data to GitHub Copilot custom agent format
21
+ * @param {object} agentData - Parsed agent data from agent-parser
22
+ * @returns {string} - Transformed content with YAML frontmatter
23
+ */
24
+ function transform(agentData) {
25
+ const agent = agentData.agent || {};
26
+ const persona = agentData.persona_profile || {};
27
+ const yamlData = agentData.yaml || {};
28
+ const personaBlock = yamlData.persona || {};
29
+
30
+ const id = agent.id || agentData.id;
31
+ const name = agent.name || id;
32
+ const title = agent.title || 'AIOS Agent';
33
+ const icon = agent.icon || '';
34
+ const description = escapeYamlString(agent.whenToUse || `${title} agent for development tasks`);
35
+
36
+ // Build YAML frontmatter
37
+ const frontmatter = [
38
+ '---',
39
+ `name: ${id}`,
40
+ `description: '${description}'`,
41
+ `tools: ['read', 'edit', 'search', 'execute']`,
42
+ '---',
43
+ ].join('\n');
44
+
45
+ // Build markdown body
46
+ const body = buildMarkdownBody({
47
+ id,
48
+ name,
49
+ title,
50
+ icon,
51
+ personaBlock,
52
+ persona,
53
+ commands: agentData.commands || [],
54
+ sections: agentData.sections || {},
55
+ corePrinciples: yamlData.core_principles,
56
+ filename: agentData.filename,
57
+ });
58
+
59
+ const content = `${frontmatter}\n\n${body}`;
60
+
61
+ // Enforce 30K character limit
62
+ if (content.length > 30000) {
63
+ return truncateContent(content, 30000);
64
+ }
65
+
66
+ return content;
67
+ }
68
+
69
+ /**
70
+ * Build the markdown body for the Copilot agent prompt
71
+ * @param {object} params - Agent parameters
72
+ * @returns {string} - Markdown body
73
+ */
74
+ function buildMarkdownBody(params) {
75
+ const { id, name, title, icon, personaBlock, persona, commands, sections, filename } = params;
76
+
77
+ const parts = [];
78
+
79
+ // Header
80
+ const headerIcon = icon ? `${icon} ` : '';
81
+ parts.push(`# ${headerIcon}${name} Agent (@${id})\n`);
82
+
83
+ // Role description
84
+ if (personaBlock.role) {
85
+ parts.push(`You are an expert ${personaBlock.role}.\n`);
86
+ } else {
87
+ parts.push(`You are an expert ${title}.\n`);
88
+ }
89
+
90
+ // Style
91
+ if (personaBlock.style) {
92
+ parts.push(`## Style\n\n${personaBlock.style}\n`);
93
+ }
94
+
95
+ // Core principles (may be in persona block or at root level of YAML)
96
+ const corePrinciples = personaBlock.core_principles || params.corePrinciples;
97
+ if (corePrinciples && Array.isArray(corePrinciples)) {
98
+ parts.push('## Core Principles\n');
99
+ for (const principle of corePrinciples) {
100
+ // Handle both string and object formats (YAML may parse "KEY: value" as {KEY: value})
101
+ if (typeof principle === 'string') {
102
+ parts.push(`- ${principle}`);
103
+ } else if (typeof principle === 'object' && principle !== null) {
104
+ const entries = Object.entries(principle);
105
+ for (const [key, value] of entries) {
106
+ parts.push(`- ${key}: ${value}`);
107
+ }
108
+ }
109
+ }
110
+ parts.push('');
111
+ }
112
+
113
+ // Commands reference
114
+ const allCommands = normalizeCommands(commands);
115
+ const keyCommands = getVisibleCommands(allCommands, 'key');
116
+ const quickCommands = getVisibleCommands(allCommands, 'quick');
117
+ const displayCommands = keyCommands.length > 0 ? keyCommands : quickCommands.slice(0, 10);
118
+
119
+ if (displayCommands.length > 0) {
120
+ parts.push('## Commands\n');
121
+ parts.push('Use `*` prefix for commands:\n');
122
+ for (const cmd of displayCommands) {
123
+ parts.push(`- \`*${cmd.name}\` - ${cmd.description || 'No description'}`);
124
+ }
125
+ parts.push('');
126
+ }
127
+
128
+ // Collaboration section (condensed)
129
+ if (sections.collaboration) {
130
+ parts.push(`## Collaboration\n\n${sections.collaboration}\n`);
131
+ }
132
+
133
+ // Sync footer
134
+ parts.push('---');
135
+ parts.push(`*AIOS Agent - Synced from .aios-core/development/agents/${filename}*`);
136
+ parts.push('');
137
+
138
+ return parts.join('\n');
139
+ }
140
+
141
+ /**
142
+ * Escape a string for use as a YAML single-quoted value
143
+ * Single quotes inside the string must be doubled
144
+ * @param {string} str - Input string
145
+ * @returns {string} - Escaped string
146
+ */
147
+ function escapeYamlString(str) {
148
+ if (!str) return '';
149
+ // In YAML single-quoted strings, single quotes are escaped by doubling them
150
+ return str.replace(/'/g, "''");
151
+ }
152
+
153
+ /**
154
+ * Truncate content to fit within character limit while keeping structure valid
155
+ * @param {string} content - Full content
156
+ * @param {number} maxChars - Maximum characters
157
+ * @returns {string} - Truncated content
158
+ */
159
+ function truncateContent(content, maxChars) {
160
+ // Find the last complete section before the limit
161
+ const truncated = content.substring(0, maxChars - 100);
162
+ const lastNewline = truncated.lastIndexOf('\n\n');
163
+
164
+ if (lastNewline > 0) {
165
+ return truncated.substring(0, lastNewline) + '\n\n---\n*Content truncated to fit 30K limit*\n';
166
+ }
167
+ return truncated + '\n\n---\n*Content truncated to fit 30K limit*\n';
168
+ }
169
+
170
+ /**
171
+ * Get the target filename for this agent (with .agent.md extension)
172
+ * @param {object} agentData - Parsed agent data
173
+ * @returns {string} - Target filename (e.g., "dev.agent.md")
174
+ */
175
+ function getFilename(agentData) {
176
+ const id = (agentData.agent && agentData.agent.id) || agentData.id;
177
+ return `${id}.agent.md`;
178
+ }
179
+
180
+ module.exports = {
181
+ transform,
182
+ getFilename,
183
+ format: 'github-copilot',
184
+ };
@@ -36,11 +36,11 @@ function detectRepositoryContext() {
36
36
 
37
37
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
38
38
 
39
- // Detect if we're in @synkra/aios-core repo itself
39
+ // Detect if we're in aios-core repo itself
40
40
  const isFrameworkRepo =
41
41
  packageJson.name === '@aios/fullstack' ||
42
- packageJson.name === '@synkra/aios-core' ||
43
- remoteUrl.includes('@synkra/aios-core');
42
+ packageJson.name === 'aios-core' ||
43
+ remoteUrl.includes('aios-core');
44
44
 
45
45
  // Load installation config if exists
46
46
  let installConfig = null;