@enterpriseai/cli 3.19.0 → 3.19.1

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 (362) hide show
  1. package/package.json +1 -1
  2. package/resources/gofer/.gofer-version +4 -357
  3. package/resources/gofer/agents-skills/eai/SKILL.md +365 -0
  4. package/resources/gofer/agents-skills/eai-update/SKILL.md +56 -0
  5. package/resources/gofer/agents-skills/gofer-documentation/SKILL.md +93 -0
  6. package/resources/gofer/bash-scripts/create-new-feature.sh +3 -1
  7. package/resources/gofer/bash-scripts/sync-implementation-status.sh +4 -3
  8. package/resources/gofer/bash-scripts/update-agent-context.sh +7 -8
  9. package/resources/gofer/bash-scripts/validate-artifact.sh +10 -6
  10. package/resources/gofer/bash-scripts/verify-object-type-routing-workspace.sh +184 -0
  11. package/resources/gofer/claude-commands/eai-update.md +46 -0
  12. package/resources/gofer/claude-commands/eai.md +355 -0
  13. package/resources/gofer/claude-skills/eai/SKILL.md +365 -0
  14. package/resources/gofer/claude-skills/eai-update/SKILL.md +56 -0
  15. package/resources/gofer/claude-skills/gofer-documentation/SKILL.md +93 -0
  16. package/resources/gofer/commands/0_gofer_start.md +440 -99
  17. package/resources/gofer/commands/0a_problem_validation.md +187 -27
  18. package/resources/gofer/commands/10_gofer_cloud.md +183 -23
  19. package/resources/gofer/commands/1_gofer_research.md +239 -30
  20. package/resources/gofer/commands/2_gofer_specify.md +239 -35
  21. package/resources/gofer/commands/3_gofer_plan.md +259 -43
  22. package/resources/gofer/commands/4_gofer_tasks.md +401 -81
  23. package/resources/gofer/commands/5_gofer_implement.md +375 -84
  24. package/resources/gofer/commands/6_gofer_validate.md +284 -53
  25. package/resources/gofer/commands/7_gofer_save.md +187 -26
  26. package/resources/gofer/commands/7a_stakeholder_comms.md +183 -23
  27. package/resources/gofer/commands/8_gofer_branding.md +183 -23
  28. package/resources/gofer/commands/9_gofer_tests.md +212 -23
  29. package/resources/gofer/commands/gofer_bootstrap_workspace.md +121 -8
  30. package/resources/gofer/commands/gofer_check_workspace.md +123 -8
  31. package/resources/gofer/commands/gofer_constitution.md +183 -23
  32. package/resources/gofer/commands/gofer_diagnose.md +183 -23
  33. package/resources/gofer/commands/gofer_eai_first_run.md +254 -25
  34. package/resources/gofer/commands/gofer_hydrate.md +183 -23
  35. package/resources/gofer/commands/gofer_personality.md +117 -6
  36. package/resources/gofer/commands/gofer_plan.md +117 -6
  37. package/resources/gofer/commands/gofer_side.md +117 -6
  38. package/resources/gofer/commands/gofer_spec_summary.md +183 -23
  39. package/resources/gofer/commands/gofer_tdd.md +183 -23
  40. package/resources/gofer/commands/gofer_vocabulary.md +185 -25
  41. package/resources/gofer/commands/gofer_zoom_out.md +183 -23
  42. package/resources/gofer/config/typesafe-learning-review.json +16 -0
  43. package/resources/gofer/config/typesafe-semantic-review.json +9 -0
  44. package/resources/gofer/copilot-instructions/gofer-cost.instructions.md +15 -6
  45. package/resources/gofer/copilot-instructions/typescript.instructions.md +1 -1
  46. package/resources/gofer/copilot-prompts/eai-update.prompt.md +58 -0
  47. package/resources/gofer/copilot-prompts/eai.prompt.md +367 -0
  48. package/resources/gofer/gemini/commands/gofer/eai-update.md +22 -0
  49. package/resources/gofer/gemini/commands/gofer/eai-update.toml +2 -0
  50. package/resources/gofer/gemini/commands/gofer/eai.md +357 -0
  51. package/resources/gofer/gemini/commands/gofer/eai.toml +2 -0
  52. package/resources/gofer/gemini/commands/gofer/manifest.json +3 -27
  53. package/resources/gofer/gemini/extension.json +4 -4
  54. package/resources/gofer/github-agents/eai.agent.md +83 -0
  55. package/resources/gofer/github-agents/gofer-business.agent.md +73 -4
  56. package/resources/gofer/github-agents/gofer-implement.agent.md +71 -2
  57. package/resources/gofer/github-agents/gofer-plan.agent.md +72 -2
  58. package/resources/gofer/github-agents/gofer-research.agent.md +72 -2
  59. package/resources/gofer/github-agents/gofer-validate.agent.md +72 -2
  60. package/resources/gofer/github-skills/eai/SKILL.md +365 -0
  61. package/resources/gofer/github-skills/eai-update/SKILL.md +56 -0
  62. package/resources/gofer/github-skills/gofer-documentation/SKILL.md +93 -0
  63. package/resources/gofer/grok-skills/eai/SKILL.md +267 -14
  64. package/resources/gofer/grok-skills/eai-update/SKILL.md +56 -0
  65. package/resources/gofer/hook-scripts/user-prompt-submit.mjs +58 -13
  66. package/resources/gofer/instruction-templates/base/agents-base.md +8 -4
  67. package/resources/gofer/instruction-templates/gofer/gofer-claude.md +7 -5
  68. package/resources/gofer/instruction-templates/gofer/gofer-copilot.md +10 -8
  69. package/resources/gofer/memory/constitution.md +9 -7
  70. package/resources/gofer/memory/gofer-model-policy.yaml +23 -1
  71. package/resources/gofer/memory/lessons.md +0 -31
  72. package/resources/gofer/node-scripts/canonical-descriptions.mjs +1 -1
  73. package/resources/gofer/node-scripts/check-version-alignment.mjs +4 -7
  74. package/resources/gofer/node-scripts/delivery-lineage-corpus.mjs +156 -0
  75. package/resources/gofer/node-scripts/generate-commands.mjs +1073 -265
  76. package/resources/gofer/node-scripts/gofer-acceptance-check.mjs +143 -0
  77. package/resources/gofer/node-scripts/gofer-agent-catalog.mjs +271 -0
  78. package/resources/gofer/node-scripts/gofer-benchmark-executor.mjs +123 -0
  79. package/resources/gofer/node-scripts/gofer-benchmark-sign.mjs +62 -0
  80. package/resources/gofer/node-scripts/gofer-benchmark-signer.mjs +89 -0
  81. package/resources/gofer/node-scripts/gofer-benchmark.mjs +76 -0
  82. package/resources/gofer/node-scripts/gofer-blocker-control.mjs +274 -0
  83. package/resources/gofer/node-scripts/gofer-claude-adapter.mjs +154 -0
  84. package/resources/gofer/node-scripts/gofer-closed-loop-audit.mjs +19 -2
  85. package/resources/gofer/node-scripts/gofer-delivery-check.mjs +121 -0
  86. package/resources/gofer/node-scripts/gofer-encrypted-key.mjs +58 -0
  87. package/resources/gofer/node-scripts/gofer-execution-metrics.mjs +477 -0
  88. package/resources/gofer/node-scripts/gofer-execution-recovery.mjs +334 -0
  89. package/resources/gofer/node-scripts/gofer-grok-adapter.mjs +184 -0
  90. package/resources/gofer/node-scripts/gofer-heldout-corpus.mjs +73 -0
  91. package/resources/gofer/node-scripts/gofer-heldout-snapshot.mjs +286 -0
  92. package/resources/gofer/node-scripts/gofer-heldout-verifier.mjs +211 -0
  93. package/resources/gofer/node-scripts/gofer-host-capability.mjs +335 -0
  94. package/resources/gofer/node-scripts/gofer-independent-reviewer.mjs +130 -0
  95. package/resources/gofer/node-scripts/gofer-live-routing.mjs +109 -0
  96. package/resources/gofer/node-scripts/gofer-local-capability-issuer.mjs +71 -0
  97. package/resources/gofer/node-scripts/gofer-local-isolation.mjs +175 -0
  98. package/resources/gofer/node-scripts/gofer-local-settings-cleanup.mjs +388 -0
  99. package/resources/gofer/node-scripts/gofer-loop-audit.mjs +54 -3
  100. package/resources/gofer/node-scripts/gofer-native-adapter.mjs +567 -0
  101. package/resources/gofer/node-scripts/gofer-native-benchmark-dispatch.mjs +145 -0
  102. package/resources/gofer/node-scripts/gofer-native-runtime.mjs +169 -0
  103. package/resources/gofer/node-scripts/gofer-pre-edit-check.mjs +204 -0
  104. package/resources/gofer/node-scripts/gofer-priority-check.mjs +214 -0
  105. package/resources/gofer/node-scripts/gofer-response-check.mjs +56 -0
  106. package/resources/gofer/node-scripts/gofer-reviewed-learning.mjs +1232 -0
  107. package/resources/gofer/node-scripts/gofer-run-verified-task.mjs +330 -0
  108. package/resources/gofer/node-scripts/gofer-runtime-ledger.mjs +289 -0
  109. package/resources/gofer/node-scripts/gofer-semantic-drift.mjs +584 -0
  110. package/resources/gofer/node-scripts/gofer-surface-update.mjs +1178 -0
  111. package/resources/gofer/node-scripts/gofer-trust-bootstrap.mjs +77 -0
  112. package/resources/gofer/node-scripts/gofer-trusted-benchmark.mjs +102 -0
  113. package/resources/gofer/node-scripts/gofer-trusted-evaluator.mjs +274 -0
  114. package/resources/gofer/node-scripts/gofer-tty-prompt.mjs +34 -0
  115. package/resources/gofer/node-scripts/gofer-typesafe-credentials.mjs +435 -0
  116. package/resources/gofer/node-scripts/gofer-ui-preview.mjs +1212 -0
  117. package/resources/gofer/node-scripts/gofer-verified-execution.mjs +484 -0
  118. package/resources/gofer/node-scripts/gofer-verifier-key-ceremony.mjs +101 -0
  119. package/resources/gofer/node-scripts/gofer-worktree-layout.mjs +32 -0
  120. package/resources/gofer/node-scripts/object-type-routing-phase-bundle.mjs +360 -0
  121. package/resources/gofer/node-scripts/package-agent-plugin.mjs +574 -82
  122. package/resources/gofer/node-scripts/parse-stage-command.mjs +1 -1
  123. package/resources/gofer/node-scripts/render-delivery-lineage.mjs +178 -0
  124. package/resources/gofer/node-scripts/sync-extension-resources.mjs +78 -2
  125. package/resources/gofer/node-scripts/validate-object-type-identifiers.mjs +767 -0
  126. package/resources/gofer/node-scripts/validate-object-type-routing-workspace.mjs +1325 -0
  127. package/resources/gofer/node-scripts/validate-v4-resource-contract.d.mts +44 -0
  128. package/resources/gofer/node-scripts/validate-v4-resource-contract.mjs +957 -0
  129. package/resources/gofer/node-scripts/workspace-bootstrap-lib.mjs +685 -116
  130. package/resources/gofer/references/agent-catalog.json +126 -0
  131. package/resources/gofer/references/blocker-mediation.md +156 -0
  132. package/resources/gofer/references/business-updates-and-goal-checks.md +109 -0
  133. package/resources/gofer/references/delivery-lineage.md +48 -0
  134. package/resources/gofer/references/mvp-capability-validation.md +102 -0
  135. package/resources/gofer/references/platform/README.md +1 -1
  136. package/resources/gofer/references/platform/eai-app-template.md +15 -13
  137. package/resources/gofer/references/platform/eai-auth-access.md +104 -0
  138. package/resources/gofer/references/platform/eai-config-driven-ui.md +5 -5
  139. package/resources/gofer/references/platform/eai-error-catalog.yaml +77 -19
  140. package/resources/gofer/references/platform/eai-repo-contract.md +61 -23
  141. package/resources/gofer/references/platform/eai-service-patterns.md +102 -105
  142. package/resources/gofer/references/platform/eai.md +44 -8
  143. package/resources/gofer/references/platform/vertical-template.md +10 -9
  144. package/resources/gofer/references/priority-outcome-protection.md +152 -0
  145. package/resources/gofer/references/verified-agent-execution.md +179 -0
  146. package/resources/gofer/schemas/gofer-learning-trace-v1.json +70 -0
  147. package/resources/gofer/specify-commands/0_gofer_start.md +440 -99
  148. package/resources/gofer/specify-commands/0a_problem_validation.md +187 -27
  149. package/resources/gofer/specify-commands/10_gofer_cloud.md +183 -23
  150. package/resources/gofer/specify-commands/1_gofer_research.md +239 -30
  151. package/resources/gofer/specify-commands/2_gofer_specify.md +239 -35
  152. package/resources/gofer/specify-commands/3_gofer_plan.md +259 -43
  153. package/resources/gofer/specify-commands/4_gofer_tasks.md +401 -81
  154. package/resources/gofer/specify-commands/5_gofer_implement.md +375 -84
  155. package/resources/gofer/specify-commands/6_gofer_validate.md +284 -53
  156. package/resources/gofer/specify-commands/7_gofer_save.md +187 -26
  157. package/resources/gofer/specify-commands/7a_stakeholder_comms.md +183 -23
  158. package/resources/gofer/specify-commands/8_gofer_branding.md +183 -23
  159. package/resources/gofer/specify-commands/9_gofer_tests.md +212 -23
  160. package/resources/gofer/specify-commands/gofer_bootstrap_workspace.md +121 -8
  161. package/resources/gofer/specify-commands/gofer_check_workspace.md +123 -8
  162. package/resources/gofer/specify-commands/gofer_constitution.md +183 -23
  163. package/resources/gofer/specify-commands/gofer_diagnose.md +183 -23
  164. package/resources/gofer/specify-commands/gofer_eai_first_run.md +254 -25
  165. package/resources/gofer/specify-commands/gofer_hydrate.md +183 -23
  166. package/resources/gofer/specify-commands/gofer_personality.md +117 -6
  167. package/resources/gofer/specify-commands/gofer_plan.md +117 -6
  168. package/resources/gofer/specify-commands/gofer_side.md +117 -6
  169. package/resources/gofer/specify-commands/gofer_spec_summary.md +183 -23
  170. package/resources/gofer/specify-commands/gofer_tdd.md +183 -23
  171. package/resources/gofer/specify-commands/gofer_vocabulary.md +185 -25
  172. package/resources/gofer/specify-commands/gofer_zoom_out.md +183 -23
  173. package/resources/gofer/specify-config/object-type-routing.json +24 -0
  174. package/resources/gofer/specify-config/typesafe-learning-review.json +16 -0
  175. package/resources/gofer/specify-config/typesafe-semantic-review.json +9 -0
  176. package/resources/gofer/system-skills/eai/SKILL.md +365 -0
  177. package/resources/gofer/system-skills/eai-update/SKILL.md +56 -0
  178. package/resources/gofer/system-skills/gofer-documentation/SKILL.md +93 -0
  179. package/resources/gofer/templates/build-map-template.md +64 -0
  180. package/resources/gofer/templates/business-scenarios-template.json +14 -0
  181. package/resources/gofer/templates/ciso-security-summary-template.md +3 -3
  182. package/resources/gofer/templates/context-bundle-template.md +4 -3
  183. package/resources/gofer/templates/contract-pack-template.md +8 -8
  184. package/resources/gofer/templates/cto-architecture-summary-template.md +3 -3
  185. package/resources/gofer/templates/delivery-lineage-template.json +8 -0
  186. package/resources/gofer/templates/eai-preflight-template.md +109 -68
  187. package/resources/gofer/templates/goal-ledger-template.json +1 -1
  188. package/resources/gofer/templates/gofer-model-policy.yaml +28 -6
  189. package/resources/gofer/templates/loop-contract-template.json +3 -1
  190. package/resources/gofer/templates/plan-template.md +8 -7
  191. package/resources/gofer/templates/priority-plan-template.json +29 -0
  192. package/resources/gofer/templates/proposal-review-template.md +6 -3
  193. package/resources/gofer/templates/release-capability-ledger-template.md +24 -0
  194. package/resources/gofer/templates/research-template.md +7 -6
  195. package/resources/gofer/templates/spec-summary-template.md +1 -1
  196. package/resources/gofer/templates/spec-template.md +45 -6
  197. package/resources/gofer/templates/tasks-template.md +12 -3
  198. package/resources/gofer/templates/ui-preview-brief-template.md +55 -5
  199. package/resources/gofer/templates/ui-review-log-template.md +21 -3
  200. package/resources/gofer/templates/ui-show-and-tell-template.md +46 -0
  201. package/resources/gofer/templates/visuals/capability-heatmap-template.md +2 -2
  202. package/resources/gofer/templates/working-backwards-prfaq-template.md +9 -8
  203. package/resources/linked-sources.json +2 -2
  204. package/resources/gofer/agents-skills/0_gofer_start/SKILL.md +0 -1287
  205. package/resources/gofer/agents-skills/0a_problem_validation/SKILL.md +0 -429
  206. package/resources/gofer/agents-skills/10_gofer_cloud/SKILL.md +0 -635
  207. package/resources/gofer/agents-skills/1_gofer_research/SKILL.md +0 -1159
  208. package/resources/gofer/agents-skills/2_gofer_specify/SKILL.md +0 -860
  209. package/resources/gofer/agents-skills/3_gofer_plan/SKILL.md +0 -899
  210. package/resources/gofer/agents-skills/4_gofer_tasks/SKILL.md +0 -760
  211. package/resources/gofer/agents-skills/5_gofer_implement/SKILL.md +0 -944
  212. package/resources/gofer/agents-skills/6_gofer_validate/SKILL.md +0 -2302
  213. package/resources/gofer/agents-skills/7_gofer_save/SKILL.md +0 -423
  214. package/resources/gofer/agents-skills/7a_stakeholder_comms/SKILL.md +0 -508
  215. package/resources/gofer/agents-skills/8_gofer_branding/SKILL.md +0 -315
  216. package/resources/gofer/agents-skills/9_gofer_tests/SKILL.md +0 -558
  217. package/resources/gofer/agents-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  218. package/resources/gofer/agents-skills/gofer_check_workspace/SKILL.md +0 -119
  219. package/resources/gofer/agents-skills/gofer_constitution/SKILL.md +0 -612
  220. package/resources/gofer/agents-skills/gofer_diagnose/SKILL.md +0 -114
  221. package/resources/gofer/agents-skills/gofer_eai_first_run/SKILL.md +0 -397
  222. package/resources/gofer/agents-skills/gofer_hydrate/SKILL.md +0 -561
  223. package/resources/gofer/agents-skills/gofer_personality/SKILL.md +0 -44
  224. package/resources/gofer/agents-skills/gofer_plan/SKILL.md +0 -40
  225. package/resources/gofer/agents-skills/gofer_side/SKILL.md +0 -45
  226. package/resources/gofer/agents-skills/gofer_spec_summary/SKILL.md +0 -112
  227. package/resources/gofer/agents-skills/gofer_tdd/SKILL.md +0 -112
  228. package/resources/gofer/agents-skills/gofer_vocabulary/SKILL.md +0 -112
  229. package/resources/gofer/agents-skills/gofer_zoom_out/SKILL.md +0 -112
  230. package/resources/gofer/claude-commands/0_gofer_start.md +0 -1282
  231. package/resources/gofer/claude-commands/0a_problem_validation.md +0 -424
  232. package/resources/gofer/claude-commands/10_gofer_cloud.md +0 -630
  233. package/resources/gofer/claude-commands/1_gofer_research.md +0 -1154
  234. package/resources/gofer/claude-commands/2_gofer_specify.md +0 -855
  235. package/resources/gofer/claude-commands/3_gofer_plan.md +0 -894
  236. package/resources/gofer/claude-commands/4_gofer_tasks.md +0 -755
  237. package/resources/gofer/claude-commands/5_gofer_implement.md +0 -939
  238. package/resources/gofer/claude-commands/6_gofer_validate.md +0 -2297
  239. package/resources/gofer/claude-commands/7_gofer_save.md +0 -418
  240. package/resources/gofer/claude-commands/7a_stakeholder_comms.md +0 -503
  241. package/resources/gofer/claude-commands/8_gofer_branding.md +0 -310
  242. package/resources/gofer/claude-commands/9_gofer_tests.md +0 -553
  243. package/resources/gofer/claude-commands/gofer_bootstrap_workspace.md +0 -143
  244. package/resources/gofer/claude-commands/gofer_check_workspace.md +0 -114
  245. package/resources/gofer/claude-commands/gofer_constitution.md +0 -607
  246. package/resources/gofer/claude-commands/gofer_diagnose.md +0 -109
  247. package/resources/gofer/claude-commands/gofer_eai_first_run.md +0 -392
  248. package/resources/gofer/claude-commands/gofer_hydrate.md +0 -556
  249. package/resources/gofer/claude-commands/gofer_personality.md +0 -39
  250. package/resources/gofer/claude-commands/gofer_plan.md +0 -35
  251. package/resources/gofer/claude-commands/gofer_side.md +0 -40
  252. package/resources/gofer/claude-commands/gofer_spec_summary.md +0 -107
  253. package/resources/gofer/claude-commands/gofer_tdd.md +0 -107
  254. package/resources/gofer/claude-commands/gofer_vocabulary.md +0 -107
  255. package/resources/gofer/claude-commands/gofer_zoom_out.md +0 -107
  256. package/resources/gofer/claude-skills/eai-gofer/SKILL.md +0 -56
  257. package/resources/gofer/copilot-prompts/0_gofer_start.prompt.md +0 -1308
  258. package/resources/gofer/copilot-prompts/0a_problem_validation.prompt.md +0 -429
  259. package/resources/gofer/copilot-prompts/10_gofer_cloud.prompt.md +0 -644
  260. package/resources/gofer/copilot-prompts/1_gofer_research.prompt.md +0 -1177
  261. package/resources/gofer/copilot-prompts/2_gofer_specify.prompt.md +0 -878
  262. package/resources/gofer/copilot-prompts/3_gofer_plan.prompt.md +0 -917
  263. package/resources/gofer/copilot-prompts/4_gofer_tasks.prompt.md +0 -778
  264. package/resources/gofer/copilot-prompts/5_gofer_implement.prompt.md +0 -962
  265. package/resources/gofer/copilot-prompts/6_gofer_validate.prompt.md +0 -2310
  266. package/resources/gofer/copilot-prompts/7_gofer_save.prompt.md +0 -433
  267. package/resources/gofer/copilot-prompts/7a_stakeholder_comms.prompt.md +0 -516
  268. package/resources/gofer/copilot-prompts/8_gofer_branding.prompt.md +0 -323
  269. package/resources/gofer/copilot-prompts/9_gofer_tests.prompt.md +0 -566
  270. package/resources/gofer/copilot-prompts/gofer_bootstrap_workspace.prompt.md +0 -161
  271. package/resources/gofer/copilot-prompts/gofer_check_workspace.prompt.md +0 -132
  272. package/resources/gofer/copilot-prompts/gofer_constitution.prompt.md +0 -621
  273. package/resources/gofer/copilot-prompts/gofer_diagnose.prompt.md +0 -127
  274. package/resources/gofer/copilot-prompts/gofer_eai_first_run.prompt.md +0 -410
  275. package/resources/gofer/copilot-prompts/gofer_hydrate.prompt.md +0 -571
  276. package/resources/gofer/copilot-prompts/gofer_personality.prompt.md +0 -57
  277. package/resources/gofer/copilot-prompts/gofer_plan.prompt.md +0 -53
  278. package/resources/gofer/copilot-prompts/gofer_side.prompt.md +0 -58
  279. package/resources/gofer/copilot-prompts/gofer_spec_summary.prompt.md +0 -125
  280. package/resources/gofer/copilot-prompts/gofer_tdd.prompt.md +0 -125
  281. package/resources/gofer/copilot-prompts/gofer_vocabulary.prompt.md +0 -125
  282. package/resources/gofer/copilot-prompts/gofer_zoom_out.prompt.md +0 -125
  283. package/resources/gofer/gemini/commands/gofer/0_gofer_start.md +0 -1282
  284. package/resources/gofer/gemini/commands/gofer/0_gofer_start.toml +0 -2
  285. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.md +0 -424
  286. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.toml +0 -2
  287. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.md +0 -630
  288. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.toml +0 -2
  289. package/resources/gofer/gemini/commands/gofer/1_gofer_research.md +0 -1154
  290. package/resources/gofer/gemini/commands/gofer/1_gofer_research.toml +0 -2
  291. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.md +0 -855
  292. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.toml +0 -2
  293. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.md +0 -894
  294. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.toml +0 -2
  295. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.md +0 -755
  296. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.toml +0 -2
  297. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.md +0 -939
  298. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.toml +0 -2
  299. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.md +0 -2297
  300. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.toml +0 -2
  301. package/resources/gofer/gemini/commands/gofer/7_gofer_save.md +0 -418
  302. package/resources/gofer/gemini/commands/gofer/7_gofer_save.toml +0 -2
  303. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.md +0 -503
  304. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.toml +0 -2
  305. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.md +0 -310
  306. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.toml +0 -2
  307. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.md +0 -553
  308. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.toml +0 -2
  309. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.md +0 -143
  310. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.toml +0 -2
  311. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.md +0 -114
  312. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.toml +0 -2
  313. package/resources/gofer/gemini/commands/gofer/gofer_constitution.md +0 -607
  314. package/resources/gofer/gemini/commands/gofer/gofer_constitution.toml +0 -2
  315. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.md +0 -109
  316. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.toml +0 -2
  317. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.md +0 -392
  318. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.toml +0 -2
  319. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.md +0 -556
  320. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.toml +0 -2
  321. package/resources/gofer/gemini/commands/gofer/gofer_personality.md +0 -39
  322. package/resources/gofer/gemini/commands/gofer/gofer_personality.toml +0 -2
  323. package/resources/gofer/gemini/commands/gofer/gofer_plan.md +0 -35
  324. package/resources/gofer/gemini/commands/gofer/gofer_plan.toml +0 -2
  325. package/resources/gofer/gemini/commands/gofer/gofer_side.md +0 -40
  326. package/resources/gofer/gemini/commands/gofer/gofer_side.toml +0 -2
  327. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.md +0 -107
  328. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.toml +0 -2
  329. package/resources/gofer/gemini/commands/gofer/gofer_tdd.md +0 -107
  330. package/resources/gofer/gemini/commands/gofer/gofer_tdd.toml +0 -2
  331. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.md +0 -107
  332. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.toml +0 -2
  333. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.md +0 -107
  334. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.toml +0 -2
  335. package/resources/gofer/github-skills/eai-gofer/SKILL.md +0 -56
  336. package/resources/gofer/system-skills/0_gofer_start/SKILL.md +0 -1287
  337. package/resources/gofer/system-skills/0a_problem_validation/SKILL.md +0 -429
  338. package/resources/gofer/system-skills/10_gofer_cloud/SKILL.md +0 -635
  339. package/resources/gofer/system-skills/1_gofer_research/SKILL.md +0 -1159
  340. package/resources/gofer/system-skills/2_gofer_specify/SKILL.md +0 -860
  341. package/resources/gofer/system-skills/3_gofer_plan/SKILL.md +0 -899
  342. package/resources/gofer/system-skills/4_gofer_tasks/SKILL.md +0 -760
  343. package/resources/gofer/system-skills/5_gofer_implement/SKILL.md +0 -944
  344. package/resources/gofer/system-skills/6_gofer_validate/SKILL.md +0 -2302
  345. package/resources/gofer/system-skills/7_gofer_save/SKILL.md +0 -423
  346. package/resources/gofer/system-skills/7a_stakeholder_comms/SKILL.md +0 -508
  347. package/resources/gofer/system-skills/8_gofer_branding/SKILL.md +0 -315
  348. package/resources/gofer/system-skills/9_gofer_tests/SKILL.md +0 -558
  349. package/resources/gofer/system-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  350. package/resources/gofer/system-skills/gofer_check_workspace/SKILL.md +0 -119
  351. package/resources/gofer/system-skills/gofer_constitution/SKILL.md +0 -612
  352. package/resources/gofer/system-skills/gofer_diagnose/SKILL.md +0 -114
  353. package/resources/gofer/system-skills/gofer_eai_first_run/SKILL.md +0 -397
  354. package/resources/gofer/system-skills/gofer_hydrate/SKILL.md +0 -561
  355. package/resources/gofer/system-skills/gofer_personality/SKILL.md +0 -44
  356. package/resources/gofer/system-skills/gofer_plan/SKILL.md +0 -40
  357. package/resources/gofer/system-skills/gofer_side/SKILL.md +0 -45
  358. package/resources/gofer/system-skills/gofer_spec_summary/SKILL.md +0 -112
  359. package/resources/gofer/system-skills/gofer_tdd/SKILL.md +0 -112
  360. package/resources/gofer/system-skills/gofer_vocabulary/SKILL.md +0 -112
  361. package/resources/gofer/system-skills/gofer_zoom_out/SKILL.md +0 -112
  362. package/resources/gofer/templates/ui-approval-template.md +0 -32
@@ -0,0 +1,957 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { promises as fs } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const DOCS_URL = 'https://docs.eai.software/services/publicapi/v4/resource-mutation-contract';
8
+ const OBJECT_TYPE_ROUTING_CONFIG_PATH = path.resolve(
9
+ path.dirname(fileURLToPath(import.meta.url)),
10
+ '..',
11
+ '..',
12
+ 'config',
13
+ 'object-type-routing.json'
14
+ );
15
+ const SOURCE_EXTENSIONS = new Set(['.cjs', '.js', '.jsx', '.mjs', '.mts', '.ts', '.tsx', '.vue']);
16
+ const RESOURCE_URL_PATTERN =
17
+ /(?:\/api\/eai)?\/v4\/data\/resources|(?<![\w$])(?:this\s*\.\s*)?(?:resources?BaseUrl|resourceUrl)\s*\(/;
18
+ const NON_RECORD_MUTATION_PATTERN =
19
+ /\/(?:object-types|query|search|aggregate|batch|files|links|shares|parents|storage)(?:\/|['"`}]|$)/;
20
+ const RESOURCE_ROUTING_METHODS = Object.freeze([
21
+ 'collection',
22
+ 'member',
23
+ 'subresource',
24
+ 'collectionOperation',
25
+ 'query',
26
+ 'search',
27
+ 'schema',
28
+ 'objectTypes',
29
+ 'objectType',
30
+ 'parent',
31
+ ]);
32
+ const RESOURCE_ROUTING_CALLEE_PATTERN =
33
+ `this\\s*\\.\\s*routing\\s*\\.\\s*(?:${RESOURCE_ROUTING_METHODS.join('|')})`;
34
+ const RESOURCE_ROUTING_ROUTE_PREFIX = 'eai-resource-routing:';
35
+ const RESOURCE_ROUTING_NON_RECORD_FAMILIES = new Set([
36
+ 'subresource',
37
+ 'collectionOperation',
38
+ 'query',
39
+ 'search',
40
+ 'schema',
41
+ 'parent',
42
+ ]);
43
+ const NON_NETWORK_ROUTE_CONSUMERS = new Set(['URL']);
44
+ const IS_DIRECT_RUN =
45
+ process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
46
+ const FIXED_AUDIT_ROOTS = ['src', 'app', 'pages', 'lib', 'packages'];
47
+ const GOVERNED_REPOSITORY_ROOTS = ['front/eai-app-template'];
48
+ const SOLE_ROUTE_OWNER = 'front/eai-app-template/packages/platform-sdk/src/resource-routing.ts';
49
+
50
+ function assertObjectTypeRoutingConfig(config) {
51
+ if (
52
+ config?.schemaVersion !== 'eai.object-type-routing.source-audit-config/v1' ||
53
+ config?.contractVersion !== 'eai.object-type-routing/v1' ||
54
+ !Array.isArray(config.fixedRoots) ||
55
+ !Array.isArray(config.governedRepositoryRoots) ||
56
+ !Array.isArray(config.excludedDirectories) ||
57
+ typeof config.soleOwner !== 'string' ||
58
+ typeof config.canonicalGuidance !== 'string' ||
59
+ JSON.stringify(config.fixedRoots) !== JSON.stringify(FIXED_AUDIT_ROOTS) ||
60
+ JSON.stringify(config.governedRepositoryRoots) !==
61
+ JSON.stringify(GOVERNED_REPOSITORY_ROOTS) ||
62
+ config.soleOwner !== SOLE_ROUTE_OWNER
63
+ ) {
64
+ throw new Error(`Invalid immutable Object Type routing config: ${OBJECT_TYPE_ROUTING_CONFIG_PATH}`);
65
+ }
66
+ return Object.freeze({
67
+ fixedRoots: Object.freeze([...config.fixedRoots]),
68
+ governedRepositoryRoots: Object.freeze([...config.governedRepositoryRoots]),
69
+ excludedDirectories: new Set(config.excludedDirectories),
70
+ soleOwner: config.soleOwner.replace(/\\/g, '/'),
71
+ canonicalGuidance: config.canonicalGuidance,
72
+ });
73
+ }
74
+
75
+ const OBJECT_TYPE_ROUTING_CONFIG = assertObjectTypeRoutingConfig(
76
+ JSON.parse(await fs.readFile(OBJECT_TYPE_ROUTING_CONFIG_PATH, 'utf8'))
77
+ );
78
+
79
+ export const OBJECT_TYPE_ROUTING_AUDIT_CONFIG = Object.freeze({
80
+ fixedRoots: [...OBJECT_TYPE_ROUTING_CONFIG.fixedRoots],
81
+ governedRepositoryRoots: [...OBJECT_TYPE_ROUTING_CONFIG.governedRepositoryRoots],
82
+ excludedDirectories: [...OBJECT_TYPE_ROUTING_CONFIG.excludedDirectories].sort(),
83
+ soleOwner: OBJECT_TYPE_ROUTING_CONFIG.soleOwner,
84
+ canonicalGuidance: OBJECT_TYPE_ROUTING_CONFIG.canonicalGuidance,
85
+ });
86
+
87
+ function lineNumber(content, index) {
88
+ return content.slice(0, index).split(/\r?\n/).length;
89
+ }
90
+
91
+ function maskNonCode(content) {
92
+ const masked = [...content];
93
+ let quote = '';
94
+ let escaped = false;
95
+ let lineComment = false;
96
+ let blockComment = false;
97
+
98
+ for (let index = 0; index < content.length; index += 1) {
99
+ const character = content[index];
100
+ const next = content[index + 1];
101
+
102
+ if (lineComment) {
103
+ if (character === '\n') {
104
+ lineComment = false;
105
+ } else {
106
+ masked[index] = ' ';
107
+ }
108
+ continue;
109
+ }
110
+ if (blockComment) {
111
+ if (character === '*' && next === '/') {
112
+ masked[index] = ' ';
113
+ masked[index + 1] = ' ';
114
+ index += 1;
115
+ blockComment = false;
116
+ } else if (character !== '\n') {
117
+ masked[index] = ' ';
118
+ }
119
+ continue;
120
+ }
121
+ if (quote) {
122
+ if (character !== '\n') masked[index] = ' ';
123
+ if (escaped) {
124
+ escaped = false;
125
+ } else if (character === '\\') {
126
+ escaped = true;
127
+ } else if (character === quote) {
128
+ quote = '';
129
+ }
130
+ continue;
131
+ }
132
+ if (character === '/' && next === '/') {
133
+ masked[index] = ' ';
134
+ masked[index + 1] = ' ';
135
+ index += 1;
136
+ lineComment = true;
137
+ continue;
138
+ }
139
+ if (character === '/' && next === '*') {
140
+ masked[index] = ' ';
141
+ masked[index + 1] = ' ';
142
+ index += 1;
143
+ blockComment = true;
144
+ continue;
145
+ }
146
+ if (character === "'" || character === '"' || character === '`') {
147
+ masked[index] = ' ';
148
+ quote = character;
149
+ }
150
+ }
151
+
152
+ return masked.join('');
153
+ }
154
+
155
+ function callSnippets(content, calleePattern) {
156
+ const snippets = [];
157
+ const masked = maskNonCode(content);
158
+ const regex = new RegExp(`(?<![\\w$])(?:${calleePattern})(?![\\w$])`, 'g');
159
+ let match;
160
+
161
+ while ((match = regex.exec(masked)) !== null) {
162
+ let openIndex = match.index + match[0].length;
163
+ while (/\s/.test(masked[openIndex] || '')) openIndex += 1;
164
+
165
+ if (masked.slice(openIndex, openIndex + 2) === '?.') {
166
+ openIndex += 2;
167
+ while (/\s/.test(masked[openIndex] || '')) openIndex += 1;
168
+ }
169
+
170
+ if (masked[openIndex] === '<') {
171
+ let genericDepth = 0;
172
+ for (let index = openIndex; index < masked.length; index += 1) {
173
+ if (masked[index] === '<') genericDepth += 1;
174
+ if (masked[index] === '>' && masked[index - 1] !== '=') {
175
+ genericDepth -= 1;
176
+ if (genericDepth === 0) {
177
+ openIndex = index + 1;
178
+ break;
179
+ }
180
+ }
181
+ }
182
+ while (/\s/.test(masked[openIndex] || '')) openIndex += 1;
183
+ }
184
+
185
+ if (masked.slice(openIndex, openIndex + 2) === '?.') {
186
+ openIndex += 2;
187
+ while (/\s/.test(masked[openIndex] || '')) openIndex += 1;
188
+ }
189
+
190
+ if (masked[openIndex] !== '(') continue;
191
+ let depth = 0;
192
+ for (let index = openIndex; index < content.length; index += 1) {
193
+ const character = masked[index];
194
+ if (character === '(') depth += 1;
195
+ if (character === ')') {
196
+ depth -= 1;
197
+ if (depth === 0) {
198
+ snippets.push({
199
+ start: match.index,
200
+ end: index + 1,
201
+ text: content.slice(match.index, index + 1),
202
+ callee: content.slice(match.index, match.index + match[0].length).replace(/\s+/g, ''),
203
+ openOffset: openIndex - match.index,
204
+ });
205
+ regex.lastIndex = index + 1;
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ return snippets;
213
+ }
214
+
215
+ function splitTopLevel(content) {
216
+ const masked = maskNonCode(content);
217
+ const segments = [];
218
+ let segmentStart = 0;
219
+ let depth = 0;
220
+
221
+ for (let index = 0; index < masked.length; index += 1) {
222
+ const character = masked[index];
223
+ if (character === '{' || character === '[' || character === '(') depth += 1;
224
+ if (character === '}' || character === ']' || character === ')') depth -= 1;
225
+ if (character === ',' && depth === 0) {
226
+ segments.push(content.slice(segmentStart, index).trim());
227
+ segmentStart = index + 1;
228
+ }
229
+ }
230
+ segments.push(content.slice(segmentStart).trim());
231
+ return segments;
232
+ }
233
+
234
+ function callArguments(snippet, openOffset) {
235
+ const openIndex = openOffset ?? maskNonCode(snippet).indexOf('(');
236
+ if (openIndex === -1 || !snippet.endsWith(')')) return [];
237
+ return splitTopLevel(snippet.slice(openIndex + 1, -1));
238
+ }
239
+
240
+ function literalRouteSegment(expression) {
241
+ const match = expression.trim().match(/^(['"`])([^'"`]*)\1$/);
242
+ if (!match || match[2].includes('${')) return undefined;
243
+ return match[2].replace(/^\/+|\/+$/g, '') || undefined;
244
+ }
245
+
246
+ function canonicalResourceRoutingRoute(expression) {
247
+ const call = callSnippets(expression, RESOURCE_ROUTING_CALLEE_PATTERN)[0];
248
+ if (!call) return undefined;
249
+
250
+ const prefix = expression.slice(0, call.start);
251
+ const suffix = expression.slice(call.end);
252
+ if (!/^\s*\(*\s*$/.test(prefix) || !/^\s*\)*\s*$/.test(suffix)) return undefined;
253
+
254
+ const method = call.callee.split('.').at(-1);
255
+ const args = callArguments(call.text, call.openOffset);
256
+ const family =
257
+ method === 'subresource' && literalRouteSegment(args[2] || '') === 'actions'
258
+ ? 'action'
259
+ : method;
260
+ return `${RESOURCE_ROUTING_ROUTE_PREFIX}${family}`;
261
+ }
262
+
263
+ function canonicalResourceRoutingFamily(route) {
264
+ return route.startsWith(RESOURCE_ROUTING_ROUTE_PREFIX)
265
+ ? route.slice(RESOURCE_ROUTING_ROUTE_PREFIX.length)
266
+ : undefined;
267
+ }
268
+
269
+ function objectLiteralBody(expression) {
270
+ let candidate = expression.trim();
271
+ const stringifyMatch = /^JSON\s*\.\s*stringify\s*\(/.exec(maskNonCode(candidate));
272
+ if (stringifyMatch) {
273
+ const args = callArguments(candidate);
274
+ candidate = args[0]?.trim() || '';
275
+ }
276
+ if (!candidate.startsWith('{')) return null;
277
+
278
+ const masked = maskNonCode(candidate);
279
+ let depth = 0;
280
+ for (let index = 0; index < masked.length; index += 1) {
281
+ if (masked[index] === '{') depth += 1;
282
+ if (masked[index] === '}') {
283
+ depth -= 1;
284
+ if (depth === 0) {
285
+ return candidate.slice(1, index);
286
+ }
287
+ }
288
+ }
289
+ return null;
290
+ }
291
+
292
+ function topLevelPropertyExpression(objectExpression, propertyName) {
293
+ const objectBody = objectLiteralBody(objectExpression);
294
+ if (objectBody === null) return undefined;
295
+ for (const segment of splitTopLevel(objectBody)) {
296
+ if (segment.trim() === propertyName) return propertyName;
297
+ const match = segment.match(
298
+ /^(?:['"`]([A-Za-z_$][\w$]*)['"`]|([A-Za-z_$][\w$]*))\s*:\s*([\s\S]+)$/
299
+ );
300
+ if ((match?.[1] || match?.[2]) === propertyName) return match[3].trim();
301
+ }
302
+ return undefined;
303
+ }
304
+
305
+ function methodOf(optionsExpression) {
306
+ const normalizedOptions = optionsExpression.trim();
307
+ if (!normalizedOptions || normalizedOptions === 'undefined') {
308
+ return { method: 'GET', resolved: true };
309
+ }
310
+
311
+ const objectBody = objectLiteralBody(normalizedOptions);
312
+ if (objectBody === null) return { method: undefined, resolved: false };
313
+
314
+ let methodExpression;
315
+ let unresolvedAssignment = false;
316
+ for (const segment of splitTopLevel(objectBody)) {
317
+ const candidate = segment.trim();
318
+ if (candidate.startsWith('...') || candidate.startsWith('[')) {
319
+ methodExpression = undefined;
320
+ unresolvedAssignment = true;
321
+ continue;
322
+ }
323
+
324
+ if (candidate === 'method') {
325
+ methodExpression = candidate;
326
+ unresolvedAssignment = false;
327
+ continue;
328
+ }
329
+
330
+ const match = candidate.match(/^(?:['"`]method['"`]|method)\s*:\s*([\s\S]+)$/);
331
+ if (match) {
332
+ methodExpression = match[1].trim();
333
+ unresolvedAssignment = false;
334
+ }
335
+ }
336
+
337
+ if (unresolvedAssignment) return { method: undefined, resolved: false };
338
+ if (methodExpression === undefined) return { method: 'GET', resolved: true };
339
+ const method = methodExpression.match(/^['"`](GET|POST|PUT|PATCH|DELETE)['"`]$/i)?.[1];
340
+ return method
341
+ ? { method: method.toUpperCase(), resolved: true }
342
+ : { method: undefined, resolved: false };
343
+ }
344
+
345
+ function objectLiteralArgument(expression) {
346
+ const stringifyIndex = expression.search(/JSON\s*\.\s*stringify\s*\(/);
347
+ if (stringifyIndex === -1) return null;
348
+ const openParenthesis = expression.indexOf('(', stringifyIndex);
349
+ let index = openParenthesis + 1;
350
+ while (/\s/.test(expression[index] || '')) index += 1;
351
+ return objectLiteralBody(expression.slice(index));
352
+ }
353
+
354
+ function topLevelObjectProperties(objectBody) {
355
+ const properties = new Set();
356
+ let segmentStart = 0;
357
+ let depth = 0;
358
+ let quote = '';
359
+ let escaped = false;
360
+
361
+ function recordSegment(end) {
362
+ const segment = objectBody.slice(segmentStart, end).trim();
363
+ const property = segment.match(
364
+ /^(?:['"`]([A-Za-z_$][\w$]*)['"`]|([A-Za-z_$][\w$]*))\s*(?::|$)/
365
+ );
366
+ const name = property?.[1] || property?.[2];
367
+ if (name) properties.add(name);
368
+ }
369
+
370
+ for (let index = 0; index < objectBody.length; index += 1) {
371
+ const character = objectBody[index];
372
+ if (quote) {
373
+ if (escaped) {
374
+ escaped = false;
375
+ } else if (character === '\\') {
376
+ escaped = true;
377
+ } else if (character === quote) {
378
+ quote = '';
379
+ }
380
+ continue;
381
+ }
382
+ if (character === "'" || character === '"' || character === '`') {
383
+ quote = character;
384
+ continue;
385
+ }
386
+ if (character === '{' || character === '[' || character === '(') depth += 1;
387
+ if (character === '}' || character === ']' || character === ')') depth -= 1;
388
+ if (character === ',' && depth === 0) {
389
+ recordSegment(index);
390
+ segmentStart = index + 1;
391
+ }
392
+ }
393
+ recordSegment(objectBody.length);
394
+ return properties;
395
+ }
396
+
397
+ function hasObjectEnvelope(bodyExpression, requiredProperties) {
398
+ const objectBody = objectLiteralArgument(bodyExpression);
399
+ if (objectBody === null) return false;
400
+ const properties = topLevelObjectProperties(objectBody);
401
+ return requiredProperties.every((property) => properties.has(property));
402
+ }
403
+
404
+ function simpleResourceBindings(content) {
405
+ const bindings = new Map();
406
+ const masked = maskNonCode(content);
407
+ const bindingPattern = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/g;
408
+ let match;
409
+
410
+ while ((match = bindingPattern.exec(masked)) !== null) {
411
+ const expressionStart = match.index + match[0].length;
412
+ let expressionEnd = masked.indexOf(';', expressionStart);
413
+ if (expressionEnd === -1) expressionEnd = content.length;
414
+ const expression = content.slice(expressionStart, expressionEnd).trim();
415
+ const canonicalRoute = canonicalResourceRoutingRoute(expression);
416
+ if (canonicalRoute || RESOURCE_URL_PATTERN.test(expression)) {
417
+ bindings.set(match[1], canonicalRoute || expression);
418
+ }
419
+ }
420
+ return bindings;
421
+ }
422
+
423
+ function resolvedResourceRoute(expression, bindings) {
424
+ const canonicalRoute = canonicalResourceRoutingRoute(expression);
425
+ if (canonicalRoute) return canonicalRoute;
426
+ if (RESOURCE_URL_PATTERN.test(expression)) return expression;
427
+ const identifier = expression.trim().match(/^([A-Za-z_$][\w$]*)$/)?.[1];
428
+ return identifier ? bindings.get(identifier) : undefined;
429
+ }
430
+
431
+ function isResourceMemberRoute(route) {
432
+ const routingFamily = canonicalResourceRoutingFamily(route);
433
+ if (routingFamily) return routingFamily === 'member';
434
+
435
+ const resourceUrlCall = route.match(/(?:this\s*\.\s*)?resourceUrl\s*\(([\s\S]*?)\)/);
436
+ if (resourceUrlCall) {
437
+ return splitTopLevel(resourceUrlCall[1]).length >= 2;
438
+ }
439
+
440
+ const marker = '/v4/data/resources';
441
+ const markerIndex = route.indexOf(marker);
442
+ if (markerIndex === -1) return false;
443
+ const suffix = route
444
+ .slice(markerIndex + marker.length)
445
+ .split(/[?#]/, 1)[0]
446
+ .replace(/['"`)}\];,\s]+$/g, '');
447
+ const segments = suffix.split('/').filter(Boolean);
448
+ if (segments.length >= 3) return true;
449
+ if (segments.length < 2) return false;
450
+
451
+ const firstSegment = segments[0];
452
+ const isExplicitTenantSegment =
453
+ /tenant/i.test(firstSegment) ||
454
+ /^\$\{[^}]*tenant[^}]*\}$/i.test(firstSegment) ||
455
+ /^[0-9a-f]{8}-[0-9a-f-]{27,}$/i.test(firstSegment);
456
+ return !isExplicitTenantSegment;
457
+ }
458
+
459
+ function enclosingBlockEnd(content, start) {
460
+ const masked = maskNonCode(content);
461
+ let depth = 0;
462
+ for (let index = 0; index < start; index += 1) {
463
+ if (masked[index] === '{') depth += 1;
464
+ if (masked[index] === '}') depth -= 1;
465
+ }
466
+ if (depth === 0) return content.length;
467
+
468
+ const targetDepth = depth - 1;
469
+ for (let index = start; index < masked.length; index += 1) {
470
+ if (masked[index] === '{') depth += 1;
471
+ if (masked[index] === '}') {
472
+ depth -= 1;
473
+ if (depth === targetDepth) return index;
474
+ }
475
+ }
476
+ return content.length;
477
+ }
478
+
479
+ function normalizedExpression(expression) {
480
+ let normalized = expression.replace(/\s+/g, '');
481
+ while (normalized.startsWith('(') && normalized.endsWith(')')) {
482
+ normalized = normalized.slice(1, -1);
483
+ }
484
+ return normalized;
485
+ }
486
+
487
+ function actionResultBinding(content, actionStart) {
488
+ const prefix = maskNonCode(content.slice(0, actionStart));
489
+ const destructured = prefix.match(
490
+ /(?:const|let|var)\s*\{([^{}]+)\}(?:\s*:\s*[^=]+)?\s*=\s*await\s*\(?\s*$/
491
+ );
492
+ if (destructured) {
493
+ for (const property of splitTopLevel(destructured[1])) {
494
+ const versionBinding = property
495
+ .trim()
496
+ .match(/^version(?:\s*:\s*([A-Za-z_$][\w$]*))?$/);
497
+ if (versionBinding) {
498
+ return {
499
+ resultName: undefined,
500
+ versionNames: new Set([versionBinding[1] || 'version']),
501
+ };
502
+ }
503
+ }
504
+ }
505
+
506
+ const declarations = [
507
+ ...prefix.matchAll(/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)/g),
508
+ ].reverse();
509
+
510
+ for (const declaration of declarations) {
511
+ const candidate = prefix.slice(declaration.index);
512
+ const binding = candidate.match(
513
+ /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)(?:\s*:\s*[^=]*?)?\s*=\s*await\s*\(?\s*$/
514
+ );
515
+ if (binding) {
516
+ return { resultName: binding[1], versionNames: new Set() };
517
+ }
518
+ }
519
+
520
+ const assignment = prefix.match(
521
+ /(?:^|[;{}])\s*([A-Za-z_$][\w$]*)\s*=\s*await\s*\(?\s*$/
522
+ );
523
+ return {
524
+ resultName: assignment?.[1],
525
+ versionNames: new Set(),
526
+ };
527
+ }
528
+
529
+ function versionExpressionsBeforeUpdate(binding, flowPrefix) {
530
+ const accepted = new Set(binding.versionNames);
531
+ if (binding.resultName) accepted.add(`${binding.resultName}.version`);
532
+
533
+ const masked = maskNonCode(flowPrefix);
534
+ if (binding.resultName) {
535
+ const escapedResult = binding.resultName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
536
+ const propertyAlias = new RegExp(
537
+ `\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)(?:\\s*:\\s*[^=]+)?\\s*=\\s*${escapedResult}\\s*\\.\\s*version\\b`,
538
+ 'g'
539
+ );
540
+ for (const match of masked.matchAll(propertyAlias)) accepted.add(match[1]);
541
+
542
+ const destructuredAlias = new RegExp(
543
+ `\\b(?:const|let|var)\\s*\\{\\s*version(?:\\s*:\\s*([A-Za-z_$][\\w$]*))?\\s*\\}\\s*=\\s*${escapedResult}\\b`,
544
+ 'g'
545
+ );
546
+ for (const match of masked.matchAll(destructuredAlias)) {
547
+ accepted.add(match[1] || 'version');
548
+ }
549
+ }
550
+
551
+ for (const sourceName of [...accepted]) {
552
+ if (sourceName.includes('.')) continue;
553
+ const escapedSource = sourceName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
554
+ const localAlias = new RegExp(
555
+ `\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)(?:\\s*:\\s*[^=]+)?\\s*=\\s*${escapedSource}\\b`,
556
+ 'g'
557
+ );
558
+ for (const match of masked.matchAll(localAlias)) accepted.add(match[1]);
559
+ }
560
+
561
+ return accepted;
562
+ }
563
+
564
+ function violation(ruleId, file, content, index, message, remediation) {
565
+ return {
566
+ ruleId,
567
+ file,
568
+ line: lineNumber(content, index),
569
+ message,
570
+ remediation,
571
+ documentation: DOCS_URL,
572
+ };
573
+ }
574
+
575
+ export function validateSourceContent(content, file = '<memory>') {
576
+ const violations = [];
577
+ const bindings = simpleResourceBindings(content);
578
+ const requests = callSnippets(
579
+ content,
580
+ '[A-Za-z_$][\\w$]*(?:\\s*\\.\\s*[A-Za-z_$][\\w$]*)*'
581
+ );
582
+
583
+ for (const request of requests) {
584
+ const callee = request.callee;
585
+ const terminalCallee = callee.split('.').at(-1);
586
+ const args = callArguments(request.text, request.openOffset);
587
+ const isNetworkLike =
588
+ terminalCallee === 'fetch' ||
589
+ terminalCallee === 'platformFetch' ||
590
+ /(?:fetch|request|send|call)$/i.test(terminalCallee || '');
591
+ if (!isNetworkLike) continue;
592
+
593
+ const route = resolvedResourceRoute(args[0] || '', bindings);
594
+ if (!route) {
595
+ const routeExpression = (args[0] || '').trim();
596
+ const optionsExpression = args[1] || '{}';
597
+ const methodResult = methodOf(optionsExpression);
598
+ const isLiteralNonV4Route =
599
+ /^['"`]/.test(routeExpression) && !/\/v4\/data\/resources/.test(routeExpression);
600
+ const isUnresolvedResourceCandidate =
601
+ !isLiteralNonV4Route && /resource/i.test(routeExpression);
602
+ const isMutationCandidate =
603
+ !methodResult.resolved || ['POST', 'PUT', 'PATCH'].includes(methodResult.method);
604
+
605
+ if (isUnresolvedResourceCandidate && isMutationCandidate) {
606
+ violations.push(
607
+ violation(
608
+ 'EAI_V4_RESOURCE_PATTERN_UNRESOLVED',
609
+ file,
610
+ content,
611
+ request.start,
612
+ 'A mutation-capable PublicAPI resource request uses a route that cannot be proven.',
613
+ 'Use the canonical resource SDK or keep the literal /v4/data/resources route in the network call.'
614
+ )
615
+ );
616
+ }
617
+ continue;
618
+ }
619
+
620
+ if (NON_NETWORK_ROUTE_CONSUMERS.has(terminalCallee)) continue;
621
+
622
+ if (terminalCallee !== 'fetch' && terminalCallee !== 'platformFetch') {
623
+ violations.push(
624
+ violation(
625
+ 'EAI_V4_RESOURCE_PATTERN_UNRESOLVED',
626
+ file,
627
+ content,
628
+ request.start,
629
+ `A PublicAPI v4 resource request is hidden behind unsupported helper ${callee}().`,
630
+ 'Use the canonical resource SDK or a direct fetch/platformFetch call with a literal method and body envelope.'
631
+ )
632
+ );
633
+ continue;
634
+ }
635
+
636
+ const optionsExpression = args[1] || '{}';
637
+ const methodResult = methodOf(optionsExpression);
638
+ if (!methodResult.resolved) {
639
+ violations.push(
640
+ violation(
641
+ 'EAI_V4_RESOURCE_PATTERN_UNRESOLVED',
642
+ file,
643
+ content,
644
+ request.start,
645
+ 'A PublicAPI v4 resource request uses a dynamic or unresolved HTTP method.',
646
+ 'Use a literal GET, POST, PUT, PATCH, or DELETE method so Gofer can prove the mutation contract.'
647
+ )
648
+ );
649
+ continue;
650
+ }
651
+
652
+ const method = methodResult.method;
653
+ const bodyExpression = topLevelPropertyExpression(optionsExpression, 'body') || '';
654
+ const routingFamily = canonicalResourceRoutingFamily(route);
655
+ const isObjectTypeManagement =
656
+ /\/object-types(?:\/|['"`}]|$)/.test(route) ||
657
+ routingFamily === 'objectTypes' ||
658
+ routingFamily === 'objectType';
659
+ const isAction = /\/actions\//.test(route) || routingFamily === 'action';
660
+ const isOperation = /\/operations\//.test(route);
661
+ const routeShapeResolved =
662
+ /\/v4\/data\/resources/.test(route) ||
663
+ /\b(?:this\.)?resources?BaseUrl\s*\(/.test(route) ||
664
+ /\b(?:this\.)?resourceUrl\s*\(/.test(route) ||
665
+ routingFamily !== undefined;
666
+
667
+ if (method === 'PATCH' && !isObjectTypeManagement) {
668
+ violations.push(
669
+ violation(
670
+ 'EAI_V4_RESOURCE_PATCH_FORBIDDEN',
671
+ file,
672
+ content,
673
+ request.start,
674
+ 'PATCH is not a valid PublicAPI v4 resource record update.',
675
+ 'Use PUT with {"data": {...}, "version": n}.'
676
+ )
677
+ );
678
+ continue;
679
+ }
680
+
681
+ if (!routeShapeResolved && ['POST', 'PUT'].includes(method)) {
682
+ violations.push(
683
+ violation(
684
+ 'EAI_V4_RESOURCE_PATTERN_UNRESOLVED',
685
+ file,
686
+ content,
687
+ request.start,
688
+ 'A PublicAPI v4 resource mutation route is constructed dynamically and its route family cannot be proven.',
689
+ 'Use the canonical resource SDK or keep the literal /v4/data/resources route in the fetch call.'
690
+ )
691
+ );
692
+ continue;
693
+ }
694
+
695
+ if (method === 'PUT' && !isObjectTypeManagement) {
696
+ if (!hasObjectEnvelope(bodyExpression, ['data', 'version'])) {
697
+ violations.push(
698
+ violation(
699
+ 'EAI_V4_RESOURCE_ENVELOPE_REQUIRED',
700
+ file,
701
+ content,
702
+ request.start,
703
+ 'A PublicAPI v4 resource update is not provably wrapped in data and version.',
704
+ 'Send PUT with JSON.stringify({ data, version }).'
705
+ )
706
+ );
707
+ }
708
+ continue;
709
+ }
710
+
711
+ if (method !== 'POST') continue;
712
+ if (isAction || isOperation) {
713
+ if (!hasObjectEnvelope(bodyExpression, ['params'])) {
714
+ violations.push(
715
+ violation(
716
+ 'EAI_V4_RESOURCE_ENVELOPE_REQUIRED',
717
+ file,
718
+ content,
719
+ request.start,
720
+ `A PublicAPI v4 resource ${isOperation ? 'operation' : 'action'} is missing the params envelope.`,
721
+ 'Send POST with JSON.stringify({ params }).'
722
+ )
723
+ );
724
+ }
725
+ continue;
726
+ }
727
+ if (
728
+ isObjectTypeManagement ||
729
+ NON_RECORD_MUTATION_PATTERN.test(route) ||
730
+ RESOURCE_ROUTING_NON_RECORD_FAMILIES.has(routingFamily)
731
+ ) {
732
+ continue;
733
+ }
734
+ if (isResourceMemberRoute(route)) {
735
+ violations.push(
736
+ violation(
737
+ 'EAI_V4_RESOURCE_METHOD_REQUIRED',
738
+ file,
739
+ content,
740
+ request.start,
741
+ 'POST is not a valid PublicAPI v4 resource record update.',
742
+ 'Use PUT with JSON.stringify({ data, version }) for a member resource route.'
743
+ )
744
+ );
745
+ continue;
746
+ }
747
+ if (!hasObjectEnvelope(bodyExpression, ['data'])) {
748
+ violations.push(
749
+ violation(
750
+ 'EAI_V4_RESOURCE_ENVELOPE_REQUIRED',
751
+ file,
752
+ content,
753
+ request.start,
754
+ 'A PublicAPI v4 resource create is not provably wrapped in data.',
755
+ 'Send POST with JSON.stringify({ data }).'
756
+ )
757
+ );
758
+ }
759
+ }
760
+
761
+ const actionCalls = callSnippets(
762
+ content,
763
+ '[A-Za-z_$][\\w$]*(?:\\s*\\))?\\s*\\.\\s*executeAction'
764
+ );
765
+ for (const [actionIndex, actionCall] of actionCalls.entries()) {
766
+ const receiver = actionCall.text.match(
767
+ /^([A-Za-z_$][\w$]*)\s*(?:\)\s*)?\.\s*executeAction/
768
+ )?.[1];
769
+ if (!receiver) continue;
770
+ let flowEnd = enclosingBlockEnd(content, actionCall.end);
771
+ for (const nextAction of actionCalls.slice(actionIndex + 1)) {
772
+ if (nextAction.start >= flowEnd) break;
773
+ const nextReceiver = nextAction.text.match(
774
+ /^([A-Za-z_$][\w$]*)\s*(?:\)\s*)?\.\s*executeAction/
775
+ )?.[1];
776
+ if (nextReceiver === receiver) {
777
+ flowEnd = nextAction.start;
778
+ break;
779
+ }
780
+ }
781
+ const afterAction = content.slice(actionCall.end, flowEnd);
782
+ const escapedReceiver = receiver.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
783
+ const actionBinding = actionResultBinding(content, actionCall.start);
784
+ const updateCalls = callSnippets(afterAction, `${escapedReceiver}\\s*\\.\\s*update`);
785
+
786
+ for (const updateCall of updateCalls) {
787
+ const versionExpression = callArguments(updateCall.text, updateCall.openOffset)[3];
788
+ const acceptedVersions = versionExpressionsBeforeUpdate(
789
+ actionBinding,
790
+ afterAction.slice(0, updateCall.start)
791
+ );
792
+ const usesActionVersion =
793
+ versionExpression &&
794
+ acceptedVersions.has(normalizedExpression(versionExpression));
795
+
796
+ if (!usesActionVersion) {
797
+ violations.push(
798
+ violation(
799
+ 'EAI_V4_RESOURCE_STALE_VERSION_FLOW',
800
+ file,
801
+ content,
802
+ actionCall.end + updateCall.start,
803
+ 'An action is followed by update without passing the action result version as the update version argument.',
804
+ 'Capture executeAction(), then call updateFrom(objectType, actionResult, data) or pass actionResult.version as update() argument four.'
805
+ )
806
+ );
807
+ }
808
+ }
809
+ }
810
+
811
+ return violations;
812
+ }
813
+
814
+ function rawObjectTypeRouteFindings(content, file) {
815
+ if (file.replace(/\\/g, '/') === OBJECT_TYPE_ROUTING_CONFIG.soleOwner) return [];
816
+
817
+ const findings = [];
818
+ const pattern = /(?:\/api\/eai)?\/v4\/data\/resources\b/g;
819
+ let match;
820
+ while ((match = pattern.exec(content)) !== null) {
821
+ const prefix = content.slice(0, match.index);
822
+ const lineStart = Math.max(prefix.lastIndexOf('\n'), prefix.lastIndexOf('\r')) + 1;
823
+ findings.push({
824
+ contractVersion: 'eai.object-type-routing/v1',
825
+ rule: 'OBJECT_TYPE_DIRECT_ROUTE_CONSTRUCTION',
826
+ classification: 'blocking_source_drift',
827
+ severity: 'error',
828
+ location: {
829
+ kind: 'source',
830
+ file,
831
+ line: lineNumber(content, match.index),
832
+ column: match.index - lineStart + 1,
833
+ },
834
+ field: null,
835
+ offendingValue: match[0],
836
+ expectedValue: 'shared platform SDK or approved BFF route owner',
837
+ remediation: OBJECT_TYPE_ROUTING_CONFIG.canonicalGuidance,
838
+ });
839
+ }
840
+ return findings;
841
+ }
842
+
843
+ async function sourceFiles(root) {
844
+ const files = [];
845
+
846
+ async function visit(directory) {
847
+ let entries;
848
+ try {
849
+ entries = await fs.readdir(directory, { withFileTypes: true });
850
+ } catch (error) {
851
+ if (error?.code === 'ENOENT') return;
852
+ throw error;
853
+ }
854
+ for (const entry of entries) {
855
+ if (entry.isDirectory() && OBJECT_TYPE_ROUTING_CONFIG.excludedDirectories.has(entry.name)) continue;
856
+ const absolute = path.join(directory, entry.name);
857
+ if (entry.isDirectory()) {
858
+ await visit(absolute);
859
+ } else if (SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
860
+ files.push(absolute);
861
+ }
862
+ }
863
+ }
864
+
865
+ for (const repositoryRoot of ['', ...OBJECT_TYPE_ROUTING_CONFIG.governedRepositoryRoots]) {
866
+ for (const fixedRoot of OBJECT_TYPE_ROUTING_CONFIG.fixedRoots) {
867
+ await visit(path.join(root, repositoryRoot, fixedRoot));
868
+ }
869
+ }
870
+ const soleOwner = path.join(root, ...OBJECT_TYPE_ROUTING_CONFIG.soleOwner.split('/'));
871
+ try {
872
+ if ((await fs.stat(soleOwner)).isFile()) files.push(soleOwner);
873
+ } catch (error) {
874
+ if (error?.code !== 'ENOENT') throw error;
875
+ }
876
+ return [...new Set(files)].sort((left, right) => left.localeCompare(right));
877
+ }
878
+
879
+ export async function validateWorkspace(workspace) {
880
+ const root = path.resolve(workspace);
881
+ const files = await sourceFiles(root);
882
+ const violations = [];
883
+ for (const file of files) {
884
+ const content = await fs.readFile(file, 'utf8');
885
+ const relativeFile = path.relative(root, file).split(path.sep).join('/');
886
+ violations.push(...validateSourceContent(content, relativeFile));
887
+ violations.push(...rawObjectTypeRouteFindings(content, relativeFile));
888
+ }
889
+ violations.sort((left, right) => {
890
+ const leftFile = left.location?.file ?? left.file ?? '';
891
+ const rightFile = right.location?.file ?? right.file ?? '';
892
+ return (
893
+ leftFile.localeCompare(rightFile) ||
894
+ (left.location?.line ?? left.line ?? 0) - (right.location?.line ?? right.line ?? 0) ||
895
+ String(left.rule ?? left.ruleId).localeCompare(String(right.rule ?? right.ruleId))
896
+ );
897
+ });
898
+ return {
899
+ valid: violations.length === 0,
900
+ filesScanned: files.length,
901
+ violations,
902
+ };
903
+ }
904
+
905
+ function parseArgs(argv) {
906
+ const args = { workspace: process.cwd(), json: false };
907
+ for (let index = 0; index < argv.length; index += 1) {
908
+ if (argv[index] === '--workspace') {
909
+ const workspace = argv[index + 1];
910
+ if (!workspace || workspace.startsWith('-')) {
911
+ throw new Error('--workspace requires a path.');
912
+ }
913
+ args.workspace = workspace;
914
+ index += 1;
915
+ } else if (argv[index] === '--json') {
916
+ args.json = true;
917
+ } else if (argv[index] === '--help' || argv[index] === '-h') {
918
+ process.stdout.write(
919
+ 'Usage: validate-v4-resource-contract.mjs [--workspace <path>] [--json]\n'
920
+ );
921
+ process.exit(0);
922
+ } else {
923
+ throw new Error(`Unknown argument: ${argv[index]}`);
924
+ }
925
+ }
926
+ return args;
927
+ }
928
+
929
+ async function main() {
930
+ const args = parseArgs(process.argv.slice(2));
931
+ const result = await validateWorkspace(args.workspace);
932
+ if (args.json) {
933
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
934
+ } else if (result.valid) {
935
+ process.stdout.write(
936
+ `PASS PublicAPI v4 resource mutation contract (${result.filesScanned} files scanned)\n`
937
+ );
938
+ } else {
939
+ for (const item of result.violations) {
940
+ const rule = item.rule ?? item.ruleId;
941
+ const location = item.location ?? { file: item.file, line: item.line };
942
+ process.stderr.write(
943
+ `${location.file}:${location.line} ${rule}: ${item.message ?? item.remediation}\n` +
944
+ ` Fix: ${item.remediation}\n` +
945
+ (item.documentation ? ` Docs: ${item.documentation}\n` : '')
946
+ );
947
+ }
948
+ }
949
+ process.exitCode = result.valid ? 0 : 1;
950
+ }
951
+
952
+ if (IS_DIRECT_RUN) {
953
+ main().catch((error) => {
954
+ console.error(error instanceof Error ? error.message : String(error));
955
+ process.exit(1);
956
+ });
957
+ }