@enterpriseai/cli 3.19.0 → 3.19.2

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 (364) hide show
  1. package/package.json +3 -3
  2. package/resources/deploy/eai-app-template/producer-pin.json +5 -5
  3. package/resources/deploy/eai-app-template/tests/source-unknown-deployment-evidence.test.mjs +2141 -1
  4. package/resources/gofer/.gofer-version +4 -357
  5. package/resources/gofer/agents-skills/eai/SKILL.md +365 -0
  6. package/resources/gofer/agents-skills/eai-update/SKILL.md +56 -0
  7. package/resources/gofer/agents-skills/gofer-documentation/SKILL.md +93 -0
  8. package/resources/gofer/bash-scripts/create-new-feature.sh +3 -1
  9. package/resources/gofer/bash-scripts/sync-implementation-status.sh +4 -3
  10. package/resources/gofer/bash-scripts/update-agent-context.sh +7 -8
  11. package/resources/gofer/bash-scripts/validate-artifact.sh +10 -6
  12. package/resources/gofer/bash-scripts/verify-object-type-routing-workspace.sh +184 -0
  13. package/resources/gofer/claude-commands/eai-update.md +46 -0
  14. package/resources/gofer/claude-commands/eai.md +355 -0
  15. package/resources/gofer/claude-skills/eai/SKILL.md +365 -0
  16. package/resources/gofer/claude-skills/eai-update/SKILL.md +56 -0
  17. package/resources/gofer/claude-skills/gofer-documentation/SKILL.md +93 -0
  18. package/resources/gofer/commands/0_gofer_start.md +440 -99
  19. package/resources/gofer/commands/0a_problem_validation.md +187 -27
  20. package/resources/gofer/commands/10_gofer_cloud.md +183 -23
  21. package/resources/gofer/commands/1_gofer_research.md +239 -30
  22. package/resources/gofer/commands/2_gofer_specify.md +239 -35
  23. package/resources/gofer/commands/3_gofer_plan.md +259 -43
  24. package/resources/gofer/commands/4_gofer_tasks.md +401 -81
  25. package/resources/gofer/commands/5_gofer_implement.md +375 -84
  26. package/resources/gofer/commands/6_gofer_validate.md +284 -53
  27. package/resources/gofer/commands/7_gofer_save.md +187 -26
  28. package/resources/gofer/commands/7a_stakeholder_comms.md +183 -23
  29. package/resources/gofer/commands/8_gofer_branding.md +183 -23
  30. package/resources/gofer/commands/9_gofer_tests.md +212 -23
  31. package/resources/gofer/commands/gofer_bootstrap_workspace.md +121 -8
  32. package/resources/gofer/commands/gofer_check_workspace.md +123 -8
  33. package/resources/gofer/commands/gofer_constitution.md +183 -23
  34. package/resources/gofer/commands/gofer_diagnose.md +183 -23
  35. package/resources/gofer/commands/gofer_eai_first_run.md +254 -25
  36. package/resources/gofer/commands/gofer_hydrate.md +183 -23
  37. package/resources/gofer/commands/gofer_personality.md +117 -6
  38. package/resources/gofer/commands/gofer_plan.md +117 -6
  39. package/resources/gofer/commands/gofer_side.md +117 -6
  40. package/resources/gofer/commands/gofer_spec_summary.md +183 -23
  41. package/resources/gofer/commands/gofer_tdd.md +183 -23
  42. package/resources/gofer/commands/gofer_vocabulary.md +185 -25
  43. package/resources/gofer/commands/gofer_zoom_out.md +183 -23
  44. package/resources/gofer/config/typesafe-learning-review.json +16 -0
  45. package/resources/gofer/config/typesafe-semantic-review.json +9 -0
  46. package/resources/gofer/copilot-instructions/gofer-cost.instructions.md +15 -6
  47. package/resources/gofer/copilot-instructions/typescript.instructions.md +1 -1
  48. package/resources/gofer/copilot-prompts/eai-update.prompt.md +58 -0
  49. package/resources/gofer/copilot-prompts/eai.prompt.md +367 -0
  50. package/resources/gofer/gemini/commands/gofer/eai-update.md +22 -0
  51. package/resources/gofer/gemini/commands/gofer/eai-update.toml +2 -0
  52. package/resources/gofer/gemini/commands/gofer/eai.md +357 -0
  53. package/resources/gofer/gemini/commands/gofer/eai.toml +2 -0
  54. package/resources/gofer/gemini/commands/gofer/manifest.json +3 -27
  55. package/resources/gofer/gemini/extension.json +4 -4
  56. package/resources/gofer/github-agents/eai.agent.md +83 -0
  57. package/resources/gofer/github-agents/gofer-business.agent.md +73 -4
  58. package/resources/gofer/github-agents/gofer-implement.agent.md +71 -2
  59. package/resources/gofer/github-agents/gofer-plan.agent.md +72 -2
  60. package/resources/gofer/github-agents/gofer-research.agent.md +72 -2
  61. package/resources/gofer/github-agents/gofer-validate.agent.md +72 -2
  62. package/resources/gofer/github-skills/eai/SKILL.md +365 -0
  63. package/resources/gofer/github-skills/eai-update/SKILL.md +56 -0
  64. package/resources/gofer/github-skills/gofer-documentation/SKILL.md +93 -0
  65. package/resources/gofer/grok-skills/eai/SKILL.md +267 -14
  66. package/resources/gofer/grok-skills/eai-update/SKILL.md +56 -0
  67. package/resources/gofer/hook-scripts/user-prompt-submit.mjs +58 -13
  68. package/resources/gofer/instruction-templates/base/agents-base.md +8 -4
  69. package/resources/gofer/instruction-templates/gofer/gofer-claude.md +7 -5
  70. package/resources/gofer/instruction-templates/gofer/gofer-copilot.md +10 -8
  71. package/resources/gofer/memory/constitution.md +9 -7
  72. package/resources/gofer/memory/gofer-model-policy.yaml +23 -1
  73. package/resources/gofer/memory/lessons.md +0 -31
  74. package/resources/gofer/node-scripts/canonical-descriptions.mjs +1 -1
  75. package/resources/gofer/node-scripts/check-version-alignment.mjs +4 -7
  76. package/resources/gofer/node-scripts/delivery-lineage-corpus.mjs +156 -0
  77. package/resources/gofer/node-scripts/generate-commands.mjs +1073 -265
  78. package/resources/gofer/node-scripts/gofer-acceptance-check.mjs +143 -0
  79. package/resources/gofer/node-scripts/gofer-agent-catalog.mjs +271 -0
  80. package/resources/gofer/node-scripts/gofer-benchmark-executor.mjs +123 -0
  81. package/resources/gofer/node-scripts/gofer-benchmark-sign.mjs +62 -0
  82. package/resources/gofer/node-scripts/gofer-benchmark-signer.mjs +89 -0
  83. package/resources/gofer/node-scripts/gofer-benchmark.mjs +76 -0
  84. package/resources/gofer/node-scripts/gofer-blocker-control.mjs +274 -0
  85. package/resources/gofer/node-scripts/gofer-claude-adapter.mjs +154 -0
  86. package/resources/gofer/node-scripts/gofer-closed-loop-audit.mjs +19 -2
  87. package/resources/gofer/node-scripts/gofer-delivery-check.mjs +121 -0
  88. package/resources/gofer/node-scripts/gofer-encrypted-key.mjs +58 -0
  89. package/resources/gofer/node-scripts/gofer-execution-metrics.mjs +477 -0
  90. package/resources/gofer/node-scripts/gofer-execution-recovery.mjs +334 -0
  91. package/resources/gofer/node-scripts/gofer-grok-adapter.mjs +184 -0
  92. package/resources/gofer/node-scripts/gofer-heldout-corpus.mjs +73 -0
  93. package/resources/gofer/node-scripts/gofer-heldout-snapshot.mjs +286 -0
  94. package/resources/gofer/node-scripts/gofer-heldout-verifier.mjs +211 -0
  95. package/resources/gofer/node-scripts/gofer-host-capability.mjs +335 -0
  96. package/resources/gofer/node-scripts/gofer-independent-reviewer.mjs +130 -0
  97. package/resources/gofer/node-scripts/gofer-live-routing.mjs +109 -0
  98. package/resources/gofer/node-scripts/gofer-local-capability-issuer.mjs +71 -0
  99. package/resources/gofer/node-scripts/gofer-local-isolation.mjs +175 -0
  100. package/resources/gofer/node-scripts/gofer-local-settings-cleanup.mjs +388 -0
  101. package/resources/gofer/node-scripts/gofer-loop-audit.mjs +54 -3
  102. package/resources/gofer/node-scripts/gofer-native-adapter.mjs +567 -0
  103. package/resources/gofer/node-scripts/gofer-native-benchmark-dispatch.mjs +145 -0
  104. package/resources/gofer/node-scripts/gofer-native-runtime.mjs +169 -0
  105. package/resources/gofer/node-scripts/gofer-pre-edit-check.mjs +204 -0
  106. package/resources/gofer/node-scripts/gofer-priority-check.mjs +214 -0
  107. package/resources/gofer/node-scripts/gofer-response-check.mjs +56 -0
  108. package/resources/gofer/node-scripts/gofer-reviewed-learning.mjs +1232 -0
  109. package/resources/gofer/node-scripts/gofer-run-verified-task.mjs +330 -0
  110. package/resources/gofer/node-scripts/gofer-runtime-ledger.mjs +289 -0
  111. package/resources/gofer/node-scripts/gofer-semantic-drift.mjs +584 -0
  112. package/resources/gofer/node-scripts/gofer-surface-update.mjs +1178 -0
  113. package/resources/gofer/node-scripts/gofer-trust-bootstrap.mjs +77 -0
  114. package/resources/gofer/node-scripts/gofer-trusted-benchmark.mjs +102 -0
  115. package/resources/gofer/node-scripts/gofer-trusted-evaluator.mjs +274 -0
  116. package/resources/gofer/node-scripts/gofer-tty-prompt.mjs +34 -0
  117. package/resources/gofer/node-scripts/gofer-typesafe-credentials.mjs +435 -0
  118. package/resources/gofer/node-scripts/gofer-ui-preview.mjs +1212 -0
  119. package/resources/gofer/node-scripts/gofer-verified-execution.mjs +484 -0
  120. package/resources/gofer/node-scripts/gofer-verifier-key-ceremony.mjs +101 -0
  121. package/resources/gofer/node-scripts/gofer-worktree-layout.mjs +32 -0
  122. package/resources/gofer/node-scripts/object-type-routing-phase-bundle.mjs +360 -0
  123. package/resources/gofer/node-scripts/package-agent-plugin.mjs +574 -82
  124. package/resources/gofer/node-scripts/parse-stage-command.mjs +1 -1
  125. package/resources/gofer/node-scripts/render-delivery-lineage.mjs +178 -0
  126. package/resources/gofer/node-scripts/sync-extension-resources.mjs +78 -2
  127. package/resources/gofer/node-scripts/validate-object-type-identifiers.mjs +767 -0
  128. package/resources/gofer/node-scripts/validate-object-type-routing-workspace.mjs +1325 -0
  129. package/resources/gofer/node-scripts/validate-v4-resource-contract.d.mts +44 -0
  130. package/resources/gofer/node-scripts/validate-v4-resource-contract.mjs +957 -0
  131. package/resources/gofer/node-scripts/workspace-bootstrap-lib.mjs +685 -116
  132. package/resources/gofer/references/agent-catalog.json +126 -0
  133. package/resources/gofer/references/blocker-mediation.md +156 -0
  134. package/resources/gofer/references/business-updates-and-goal-checks.md +109 -0
  135. package/resources/gofer/references/delivery-lineage.md +48 -0
  136. package/resources/gofer/references/mvp-capability-validation.md +102 -0
  137. package/resources/gofer/references/platform/README.md +1 -1
  138. package/resources/gofer/references/platform/eai-app-template.md +15 -13
  139. package/resources/gofer/references/platform/eai-auth-access.md +104 -0
  140. package/resources/gofer/references/platform/eai-config-driven-ui.md +5 -5
  141. package/resources/gofer/references/platform/eai-error-catalog.yaml +77 -19
  142. package/resources/gofer/references/platform/eai-repo-contract.md +61 -23
  143. package/resources/gofer/references/platform/eai-service-patterns.md +102 -105
  144. package/resources/gofer/references/platform/eai.md +44 -8
  145. package/resources/gofer/references/platform/vertical-template.md +10 -9
  146. package/resources/gofer/references/priority-outcome-protection.md +152 -0
  147. package/resources/gofer/references/verified-agent-execution.md +179 -0
  148. package/resources/gofer/schemas/gofer-learning-trace-v1.json +70 -0
  149. package/resources/gofer/specify-commands/0_gofer_start.md +440 -99
  150. package/resources/gofer/specify-commands/0a_problem_validation.md +187 -27
  151. package/resources/gofer/specify-commands/10_gofer_cloud.md +183 -23
  152. package/resources/gofer/specify-commands/1_gofer_research.md +239 -30
  153. package/resources/gofer/specify-commands/2_gofer_specify.md +239 -35
  154. package/resources/gofer/specify-commands/3_gofer_plan.md +259 -43
  155. package/resources/gofer/specify-commands/4_gofer_tasks.md +401 -81
  156. package/resources/gofer/specify-commands/5_gofer_implement.md +375 -84
  157. package/resources/gofer/specify-commands/6_gofer_validate.md +284 -53
  158. package/resources/gofer/specify-commands/7_gofer_save.md +187 -26
  159. package/resources/gofer/specify-commands/7a_stakeholder_comms.md +183 -23
  160. package/resources/gofer/specify-commands/8_gofer_branding.md +183 -23
  161. package/resources/gofer/specify-commands/9_gofer_tests.md +212 -23
  162. package/resources/gofer/specify-commands/gofer_bootstrap_workspace.md +121 -8
  163. package/resources/gofer/specify-commands/gofer_check_workspace.md +123 -8
  164. package/resources/gofer/specify-commands/gofer_constitution.md +183 -23
  165. package/resources/gofer/specify-commands/gofer_diagnose.md +183 -23
  166. package/resources/gofer/specify-commands/gofer_eai_first_run.md +254 -25
  167. package/resources/gofer/specify-commands/gofer_hydrate.md +183 -23
  168. package/resources/gofer/specify-commands/gofer_personality.md +117 -6
  169. package/resources/gofer/specify-commands/gofer_plan.md +117 -6
  170. package/resources/gofer/specify-commands/gofer_side.md +117 -6
  171. package/resources/gofer/specify-commands/gofer_spec_summary.md +183 -23
  172. package/resources/gofer/specify-commands/gofer_tdd.md +183 -23
  173. package/resources/gofer/specify-commands/gofer_vocabulary.md +185 -25
  174. package/resources/gofer/specify-commands/gofer_zoom_out.md +183 -23
  175. package/resources/gofer/specify-config/object-type-routing.json +24 -0
  176. package/resources/gofer/specify-config/typesafe-learning-review.json +16 -0
  177. package/resources/gofer/specify-config/typesafe-semantic-review.json +9 -0
  178. package/resources/gofer/system-skills/eai/SKILL.md +365 -0
  179. package/resources/gofer/system-skills/eai-update/SKILL.md +56 -0
  180. package/resources/gofer/system-skills/gofer-documentation/SKILL.md +93 -0
  181. package/resources/gofer/templates/build-map-template.md +64 -0
  182. package/resources/gofer/templates/business-scenarios-template.json +14 -0
  183. package/resources/gofer/templates/ciso-security-summary-template.md +3 -3
  184. package/resources/gofer/templates/context-bundle-template.md +4 -3
  185. package/resources/gofer/templates/contract-pack-template.md +8 -8
  186. package/resources/gofer/templates/cto-architecture-summary-template.md +3 -3
  187. package/resources/gofer/templates/delivery-lineage-template.json +8 -0
  188. package/resources/gofer/templates/eai-preflight-template.md +109 -68
  189. package/resources/gofer/templates/goal-ledger-template.json +1 -1
  190. package/resources/gofer/templates/gofer-model-policy.yaml +28 -6
  191. package/resources/gofer/templates/loop-contract-template.json +3 -1
  192. package/resources/gofer/templates/plan-template.md +8 -7
  193. package/resources/gofer/templates/priority-plan-template.json +29 -0
  194. package/resources/gofer/templates/proposal-review-template.md +6 -3
  195. package/resources/gofer/templates/release-capability-ledger-template.md +24 -0
  196. package/resources/gofer/templates/research-template.md +7 -6
  197. package/resources/gofer/templates/spec-summary-template.md +1 -1
  198. package/resources/gofer/templates/spec-template.md +45 -6
  199. package/resources/gofer/templates/tasks-template.md +12 -3
  200. package/resources/gofer/templates/ui-preview-brief-template.md +55 -5
  201. package/resources/gofer/templates/ui-review-log-template.md +21 -3
  202. package/resources/gofer/templates/ui-show-and-tell-template.md +46 -0
  203. package/resources/gofer/templates/visuals/capability-heatmap-template.md +2 -2
  204. package/resources/gofer/templates/working-backwards-prfaq-template.md +9 -8
  205. package/resources/linked-sources.json +4 -4
  206. package/resources/gofer/agents-skills/0_gofer_start/SKILL.md +0 -1287
  207. package/resources/gofer/agents-skills/0a_problem_validation/SKILL.md +0 -429
  208. package/resources/gofer/agents-skills/10_gofer_cloud/SKILL.md +0 -635
  209. package/resources/gofer/agents-skills/1_gofer_research/SKILL.md +0 -1159
  210. package/resources/gofer/agents-skills/2_gofer_specify/SKILL.md +0 -860
  211. package/resources/gofer/agents-skills/3_gofer_plan/SKILL.md +0 -899
  212. package/resources/gofer/agents-skills/4_gofer_tasks/SKILL.md +0 -760
  213. package/resources/gofer/agents-skills/5_gofer_implement/SKILL.md +0 -944
  214. package/resources/gofer/agents-skills/6_gofer_validate/SKILL.md +0 -2302
  215. package/resources/gofer/agents-skills/7_gofer_save/SKILL.md +0 -423
  216. package/resources/gofer/agents-skills/7a_stakeholder_comms/SKILL.md +0 -508
  217. package/resources/gofer/agents-skills/8_gofer_branding/SKILL.md +0 -315
  218. package/resources/gofer/agents-skills/9_gofer_tests/SKILL.md +0 -558
  219. package/resources/gofer/agents-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  220. package/resources/gofer/agents-skills/gofer_check_workspace/SKILL.md +0 -119
  221. package/resources/gofer/agents-skills/gofer_constitution/SKILL.md +0 -612
  222. package/resources/gofer/agents-skills/gofer_diagnose/SKILL.md +0 -114
  223. package/resources/gofer/agents-skills/gofer_eai_first_run/SKILL.md +0 -397
  224. package/resources/gofer/agents-skills/gofer_hydrate/SKILL.md +0 -561
  225. package/resources/gofer/agents-skills/gofer_personality/SKILL.md +0 -44
  226. package/resources/gofer/agents-skills/gofer_plan/SKILL.md +0 -40
  227. package/resources/gofer/agents-skills/gofer_side/SKILL.md +0 -45
  228. package/resources/gofer/agents-skills/gofer_spec_summary/SKILL.md +0 -112
  229. package/resources/gofer/agents-skills/gofer_tdd/SKILL.md +0 -112
  230. package/resources/gofer/agents-skills/gofer_vocabulary/SKILL.md +0 -112
  231. package/resources/gofer/agents-skills/gofer_zoom_out/SKILL.md +0 -112
  232. package/resources/gofer/claude-commands/0_gofer_start.md +0 -1282
  233. package/resources/gofer/claude-commands/0a_problem_validation.md +0 -424
  234. package/resources/gofer/claude-commands/10_gofer_cloud.md +0 -630
  235. package/resources/gofer/claude-commands/1_gofer_research.md +0 -1154
  236. package/resources/gofer/claude-commands/2_gofer_specify.md +0 -855
  237. package/resources/gofer/claude-commands/3_gofer_plan.md +0 -894
  238. package/resources/gofer/claude-commands/4_gofer_tasks.md +0 -755
  239. package/resources/gofer/claude-commands/5_gofer_implement.md +0 -939
  240. package/resources/gofer/claude-commands/6_gofer_validate.md +0 -2297
  241. package/resources/gofer/claude-commands/7_gofer_save.md +0 -418
  242. package/resources/gofer/claude-commands/7a_stakeholder_comms.md +0 -503
  243. package/resources/gofer/claude-commands/8_gofer_branding.md +0 -310
  244. package/resources/gofer/claude-commands/9_gofer_tests.md +0 -553
  245. package/resources/gofer/claude-commands/gofer_bootstrap_workspace.md +0 -143
  246. package/resources/gofer/claude-commands/gofer_check_workspace.md +0 -114
  247. package/resources/gofer/claude-commands/gofer_constitution.md +0 -607
  248. package/resources/gofer/claude-commands/gofer_diagnose.md +0 -109
  249. package/resources/gofer/claude-commands/gofer_eai_first_run.md +0 -392
  250. package/resources/gofer/claude-commands/gofer_hydrate.md +0 -556
  251. package/resources/gofer/claude-commands/gofer_personality.md +0 -39
  252. package/resources/gofer/claude-commands/gofer_plan.md +0 -35
  253. package/resources/gofer/claude-commands/gofer_side.md +0 -40
  254. package/resources/gofer/claude-commands/gofer_spec_summary.md +0 -107
  255. package/resources/gofer/claude-commands/gofer_tdd.md +0 -107
  256. package/resources/gofer/claude-commands/gofer_vocabulary.md +0 -107
  257. package/resources/gofer/claude-commands/gofer_zoom_out.md +0 -107
  258. package/resources/gofer/claude-skills/eai-gofer/SKILL.md +0 -56
  259. package/resources/gofer/copilot-prompts/0_gofer_start.prompt.md +0 -1308
  260. package/resources/gofer/copilot-prompts/0a_problem_validation.prompt.md +0 -429
  261. package/resources/gofer/copilot-prompts/10_gofer_cloud.prompt.md +0 -644
  262. package/resources/gofer/copilot-prompts/1_gofer_research.prompt.md +0 -1177
  263. package/resources/gofer/copilot-prompts/2_gofer_specify.prompt.md +0 -878
  264. package/resources/gofer/copilot-prompts/3_gofer_plan.prompt.md +0 -917
  265. package/resources/gofer/copilot-prompts/4_gofer_tasks.prompt.md +0 -778
  266. package/resources/gofer/copilot-prompts/5_gofer_implement.prompt.md +0 -962
  267. package/resources/gofer/copilot-prompts/6_gofer_validate.prompt.md +0 -2310
  268. package/resources/gofer/copilot-prompts/7_gofer_save.prompt.md +0 -433
  269. package/resources/gofer/copilot-prompts/7a_stakeholder_comms.prompt.md +0 -516
  270. package/resources/gofer/copilot-prompts/8_gofer_branding.prompt.md +0 -323
  271. package/resources/gofer/copilot-prompts/9_gofer_tests.prompt.md +0 -566
  272. package/resources/gofer/copilot-prompts/gofer_bootstrap_workspace.prompt.md +0 -161
  273. package/resources/gofer/copilot-prompts/gofer_check_workspace.prompt.md +0 -132
  274. package/resources/gofer/copilot-prompts/gofer_constitution.prompt.md +0 -621
  275. package/resources/gofer/copilot-prompts/gofer_diagnose.prompt.md +0 -127
  276. package/resources/gofer/copilot-prompts/gofer_eai_first_run.prompt.md +0 -410
  277. package/resources/gofer/copilot-prompts/gofer_hydrate.prompt.md +0 -571
  278. package/resources/gofer/copilot-prompts/gofer_personality.prompt.md +0 -57
  279. package/resources/gofer/copilot-prompts/gofer_plan.prompt.md +0 -53
  280. package/resources/gofer/copilot-prompts/gofer_side.prompt.md +0 -58
  281. package/resources/gofer/copilot-prompts/gofer_spec_summary.prompt.md +0 -125
  282. package/resources/gofer/copilot-prompts/gofer_tdd.prompt.md +0 -125
  283. package/resources/gofer/copilot-prompts/gofer_vocabulary.prompt.md +0 -125
  284. package/resources/gofer/copilot-prompts/gofer_zoom_out.prompt.md +0 -125
  285. package/resources/gofer/gemini/commands/gofer/0_gofer_start.md +0 -1282
  286. package/resources/gofer/gemini/commands/gofer/0_gofer_start.toml +0 -2
  287. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.md +0 -424
  288. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.toml +0 -2
  289. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.md +0 -630
  290. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.toml +0 -2
  291. package/resources/gofer/gemini/commands/gofer/1_gofer_research.md +0 -1154
  292. package/resources/gofer/gemini/commands/gofer/1_gofer_research.toml +0 -2
  293. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.md +0 -855
  294. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.toml +0 -2
  295. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.md +0 -894
  296. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.toml +0 -2
  297. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.md +0 -755
  298. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.toml +0 -2
  299. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.md +0 -939
  300. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.toml +0 -2
  301. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.md +0 -2297
  302. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.toml +0 -2
  303. package/resources/gofer/gemini/commands/gofer/7_gofer_save.md +0 -418
  304. package/resources/gofer/gemini/commands/gofer/7_gofer_save.toml +0 -2
  305. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.md +0 -503
  306. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.toml +0 -2
  307. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.md +0 -310
  308. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.toml +0 -2
  309. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.md +0 -553
  310. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.toml +0 -2
  311. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.md +0 -143
  312. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.toml +0 -2
  313. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.md +0 -114
  314. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.toml +0 -2
  315. package/resources/gofer/gemini/commands/gofer/gofer_constitution.md +0 -607
  316. package/resources/gofer/gemini/commands/gofer/gofer_constitution.toml +0 -2
  317. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.md +0 -109
  318. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.toml +0 -2
  319. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.md +0 -392
  320. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.toml +0 -2
  321. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.md +0 -556
  322. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.toml +0 -2
  323. package/resources/gofer/gemini/commands/gofer/gofer_personality.md +0 -39
  324. package/resources/gofer/gemini/commands/gofer/gofer_personality.toml +0 -2
  325. package/resources/gofer/gemini/commands/gofer/gofer_plan.md +0 -35
  326. package/resources/gofer/gemini/commands/gofer/gofer_plan.toml +0 -2
  327. package/resources/gofer/gemini/commands/gofer/gofer_side.md +0 -40
  328. package/resources/gofer/gemini/commands/gofer/gofer_side.toml +0 -2
  329. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.md +0 -107
  330. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.toml +0 -2
  331. package/resources/gofer/gemini/commands/gofer/gofer_tdd.md +0 -107
  332. package/resources/gofer/gemini/commands/gofer/gofer_tdd.toml +0 -2
  333. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.md +0 -107
  334. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.toml +0 -2
  335. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.md +0 -107
  336. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.toml +0 -2
  337. package/resources/gofer/github-skills/eai-gofer/SKILL.md +0 -56
  338. package/resources/gofer/system-skills/0_gofer_start/SKILL.md +0 -1287
  339. package/resources/gofer/system-skills/0a_problem_validation/SKILL.md +0 -429
  340. package/resources/gofer/system-skills/10_gofer_cloud/SKILL.md +0 -635
  341. package/resources/gofer/system-skills/1_gofer_research/SKILL.md +0 -1159
  342. package/resources/gofer/system-skills/2_gofer_specify/SKILL.md +0 -860
  343. package/resources/gofer/system-skills/3_gofer_plan/SKILL.md +0 -899
  344. package/resources/gofer/system-skills/4_gofer_tasks/SKILL.md +0 -760
  345. package/resources/gofer/system-skills/5_gofer_implement/SKILL.md +0 -944
  346. package/resources/gofer/system-skills/6_gofer_validate/SKILL.md +0 -2302
  347. package/resources/gofer/system-skills/7_gofer_save/SKILL.md +0 -423
  348. package/resources/gofer/system-skills/7a_stakeholder_comms/SKILL.md +0 -508
  349. package/resources/gofer/system-skills/8_gofer_branding/SKILL.md +0 -315
  350. package/resources/gofer/system-skills/9_gofer_tests/SKILL.md +0 -558
  351. package/resources/gofer/system-skills/gofer_bootstrap_workspace/SKILL.md +0 -148
  352. package/resources/gofer/system-skills/gofer_check_workspace/SKILL.md +0 -119
  353. package/resources/gofer/system-skills/gofer_constitution/SKILL.md +0 -612
  354. package/resources/gofer/system-skills/gofer_diagnose/SKILL.md +0 -114
  355. package/resources/gofer/system-skills/gofer_eai_first_run/SKILL.md +0 -397
  356. package/resources/gofer/system-skills/gofer_hydrate/SKILL.md +0 -561
  357. package/resources/gofer/system-skills/gofer_personality/SKILL.md +0 -44
  358. package/resources/gofer/system-skills/gofer_plan/SKILL.md +0 -40
  359. package/resources/gofer/system-skills/gofer_side/SKILL.md +0 -45
  360. package/resources/gofer/system-skills/gofer_spec_summary/SKILL.md +0 -112
  361. package/resources/gofer/system-skills/gofer_tdd/SKILL.md +0 -112
  362. package/resources/gofer/system-skills/gofer_vocabulary/SKILL.md +0 -112
  363. package/resources/gofer/system-skills/gofer_zoom_out/SKILL.md +0 -112
  364. 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
+ }