eai-cli 0.0.0-bootstrap.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (690) hide show
  1. package/LICENSE +183 -0
  2. package/NOTICE +4 -0
  3. package/README.md +14 -0
  4. package/dist/commands/agent.d.ts +3 -0
  5. package/dist/commands/agent.d.ts.map +1 -0
  6. package/dist/commands/agent.js +69 -0
  7. package/dist/commands/agent.js.map +1 -0
  8. package/dist/commands/blocks.d.ts +3 -0
  9. package/dist/commands/blocks.d.ts.map +1 -0
  10. package/dist/commands/blocks.js +249 -0
  11. package/dist/commands/blocks.js.map +1 -0
  12. package/dist/commands/chat.d.ts +6 -0
  13. package/dist/commands/chat.d.ts.map +1 -0
  14. package/dist/commands/chat.js +105 -0
  15. package/dist/commands/chat.js.map +1 -0
  16. package/dist/commands/deploy.d.ts +36 -0
  17. package/dist/commands/deploy.d.ts.map +1 -0
  18. package/dist/commands/deploy.js +712 -0
  19. package/dist/commands/deploy.js.map +1 -0
  20. package/dist/commands/dev.d.ts +15 -0
  21. package/dist/commands/dev.d.ts.map +1 -0
  22. package/dist/commands/dev.js +133 -0
  23. package/dist/commands/dev.js.map +1 -0
  24. package/dist/commands/docs.d.ts +6 -0
  25. package/dist/commands/docs.d.ts.map +1 -0
  26. package/dist/commands/docs.js +118 -0
  27. package/dist/commands/docs.js.map +1 -0
  28. package/dist/commands/env.d.ts +10 -0
  29. package/dist/commands/env.d.ts.map +1 -0
  30. package/dist/commands/env.js +200 -0
  31. package/dist/commands/env.js.map +1 -0
  32. package/dist/commands/errors.d.ts +3 -0
  33. package/dist/commands/errors.d.ts.map +1 -0
  34. package/dist/commands/errors.js +72 -0
  35. package/dist/commands/errors.js.map +1 -0
  36. package/dist/commands/gofer.d.ts +3 -0
  37. package/dist/commands/gofer.d.ts.map +1 -0
  38. package/dist/commands/gofer.js +134 -0
  39. package/dist/commands/gofer.js.map +1 -0
  40. package/dist/commands/init.d.ts +14 -0
  41. package/dist/commands/init.d.ts.map +1 -0
  42. package/dist/commands/init.js +1437 -0
  43. package/dist/commands/init.js.map +1 -0
  44. package/dist/commands/login.d.ts +7 -0
  45. package/dist/commands/login.d.ts.map +1 -0
  46. package/dist/commands/login.js +117 -0
  47. package/dist/commands/login.js.map +1 -0
  48. package/dist/commands/provision.d.ts +6 -0
  49. package/dist/commands/provision.d.ts.map +1 -0
  50. package/dist/commands/provision.js +855 -0
  51. package/dist/commands/provision.js.map +1 -0
  52. package/dist/commands/publicapi.d.ts +6 -0
  53. package/dist/commands/publicapi.d.ts.map +1 -0
  54. package/dist/commands/publicapi.js +184 -0
  55. package/dist/commands/publicapi.js.map +1 -0
  56. package/dist/commands/resources.d.ts +38 -0
  57. package/dist/commands/resources.d.ts.map +1 -0
  58. package/dist/commands/resources.js +1010 -0
  59. package/dist/commands/resources.js.map +1 -0
  60. package/dist/commands/runtime.d.ts +3 -0
  61. package/dist/commands/runtime.d.ts.map +1 -0
  62. package/dist/commands/runtime.js +78 -0
  63. package/dist/commands/runtime.js.map +1 -0
  64. package/dist/commands/template.d.ts +3 -0
  65. package/dist/commands/template.d.ts.map +1 -0
  66. package/dist/commands/template.js +365 -0
  67. package/dist/commands/template.js.map +1 -0
  68. package/dist/commands/tenant.d.ts +45 -0
  69. package/dist/commands/tenant.d.ts.map +1 -0
  70. package/dist/commands/tenant.js +1036 -0
  71. package/dist/commands/tenant.js.map +1 -0
  72. package/dist/commands/types.d.ts +130 -0
  73. package/dist/commands/types.d.ts.map +1 -0
  74. package/dist/commands/types.js +1636 -0
  75. package/dist/commands/types.js.map +1 -0
  76. package/dist/commands/update.d.ts +13 -0
  77. package/dist/commands/update.d.ts.map +1 -0
  78. package/dist/commands/update.js +163 -0
  79. package/dist/commands/update.js.map +1 -0
  80. package/dist/commands/user.d.ts +6 -0
  81. package/dist/commands/user.d.ts.map +1 -0
  82. package/dist/commands/user.js +359 -0
  83. package/dist/commands/user.js.map +1 -0
  84. package/dist/commands/verify.d.ts +40 -0
  85. package/dist/commands/verify.d.ts.map +1 -0
  86. package/dist/commands/verify.js +1442 -0
  87. package/dist/commands/verify.js.map +1 -0
  88. package/dist/commands/vertical.d.ts +24 -0
  89. package/dist/commands/vertical.d.ts.map +1 -0
  90. package/dist/commands/vertical.js +301 -0
  91. package/dist/commands/vertical.js.map +1 -0
  92. package/dist/commands/whoami.d.ts +6 -0
  93. package/dist/commands/whoami.d.ts.map +1 -0
  94. package/dist/commands/whoami.js +73 -0
  95. package/dist/commands/whoami.js.map +1 -0
  96. package/dist/commands/workflow.d.ts +6 -0
  97. package/dist/commands/workflow.d.ts.map +1 -0
  98. package/dist/commands/workflow.js +400 -0
  99. package/dist/commands/workflow.js.map +1 -0
  100. package/dist/index.d.ts +10 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +272 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/lib/agent-guide.d.ts +24 -0
  105. package/dist/lib/agent-guide.d.ts.map +1 -0
  106. package/dist/lib/agent-guide.js +155 -0
  107. package/dist/lib/agent-guide.js.map +1 -0
  108. package/dist/lib/api.d.ts +338 -0
  109. package/dist/lib/api.d.ts.map +1 -0
  110. package/dist/lib/api.js +991 -0
  111. package/dist/lib/api.js.map +1 -0
  112. package/dist/lib/auth.d.ts +65 -0
  113. package/dist/lib/auth.d.ts.map +1 -0
  114. package/dist/lib/auth.js +592 -0
  115. package/dist/lib/auth.js.map +1 -0
  116. package/dist/lib/azure-cli.d.ts +6 -0
  117. package/dist/lib/azure-cli.d.ts.map +1 -0
  118. package/dist/lib/azure-cli.js +13 -0
  119. package/dist/lib/azure-cli.js.map +1 -0
  120. package/dist/lib/block-catalog-normalize.d.ts +47 -0
  121. package/dist/lib/block-catalog-normalize.d.ts.map +1 -0
  122. package/dist/lib/block-catalog-normalize.js +355 -0
  123. package/dist/lib/block-catalog-normalize.js.map +1 -0
  124. package/dist/lib/block-catalog-types.d.ts +111 -0
  125. package/dist/lib/block-catalog-types.d.ts.map +1 -0
  126. package/dist/lib/block-catalog-types.js +41 -0
  127. package/dist/lib/block-catalog-types.js.map +1 -0
  128. package/dist/lib/block-catalog-utils.d.ts +7 -0
  129. package/dist/lib/block-catalog-utils.d.ts.map +1 -0
  130. package/dist/lib/block-catalog-utils.js +47 -0
  131. package/dist/lib/block-catalog-utils.js.map +1 -0
  132. package/dist/lib/block-catalog-validation.d.ts +5 -0
  133. package/dist/lib/block-catalog-validation.d.ts.map +1 -0
  134. package/dist/lib/block-catalog-validation.js +112 -0
  135. package/dist/lib/block-catalog-validation.js.map +1 -0
  136. package/dist/lib/block-catalog.d.ts +3 -0
  137. package/dist/lib/block-catalog.d.ts.map +1 -0
  138. package/dist/lib/block-catalog.js +284 -0
  139. package/dist/lib/block-catalog.js.map +1 -0
  140. package/dist/lib/cloud-env.d.ts +25 -0
  141. package/dist/lib/cloud-env.d.ts.map +1 -0
  142. package/dist/lib/cloud-env.js +79 -0
  143. package/dist/lib/cloud-env.js.map +1 -0
  144. package/dist/lib/config.d.ts +116 -0
  145. package/dist/lib/config.d.ts.map +1 -0
  146. package/dist/lib/config.js +195 -0
  147. package/dist/lib/config.js.map +1 -0
  148. package/dist/lib/context.d.ts +43 -0
  149. package/dist/lib/context.d.ts.map +1 -0
  150. package/dist/lib/context.js +68 -0
  151. package/dist/lib/context.js.map +1 -0
  152. package/dist/lib/error-codes.d.ts +56 -0
  153. package/dist/lib/error-codes.d.ts.map +1 -0
  154. package/dist/lib/error-codes.js +211 -0
  155. package/dist/lib/error-codes.js.map +1 -0
  156. package/dist/lib/error-guidance/catalog.d.ts +648 -0
  157. package/dist/lib/error-guidance/catalog.d.ts.map +1 -0
  158. package/dist/lib/error-guidance/catalog.js +940 -0
  159. package/dist/lib/error-guidance/catalog.js.map +1 -0
  160. package/dist/lib/error-guidance/match.d.ts +3 -0
  161. package/dist/lib/error-guidance/match.d.ts.map +1 -0
  162. package/dist/lib/error-guidance/match.js +46 -0
  163. package/dist/lib/error-guidance/match.js.map +1 -0
  164. package/dist/lib/error-guidance/render.d.ts +5 -0
  165. package/dist/lib/error-guidance/render.d.ts.map +1 -0
  166. package/dist/lib/error-guidance/render.js +92 -0
  167. package/dist/lib/error-guidance/render.js.map +1 -0
  168. package/dist/lib/error-guidance/types.d.ts +76 -0
  169. package/dist/lib/error-guidance/types.d.ts.map +1 -0
  170. package/dist/lib/error-guidance/types.js +2 -0
  171. package/dist/lib/error-guidance/types.js.map +1 -0
  172. package/dist/lib/error-guidance/validate.d.ts +3 -0
  173. package/dist/lib/error-guidance/validate.d.ts.map +1 -0
  174. package/dist/lib/error-guidance/validate.js +59 -0
  175. package/dist/lib/error-guidance/validate.js.map +1 -0
  176. package/dist/lib/gofer-installer.d.ts +32 -0
  177. package/dist/lib/gofer-installer.d.ts.map +1 -0
  178. package/dist/lib/gofer-installer.js +589 -0
  179. package/dist/lib/gofer-installer.js.map +1 -0
  180. package/dist/lib/gofer-refresh.d.ts +46 -0
  181. package/dist/lib/gofer-refresh.d.ts.map +1 -0
  182. package/dist/lib/gofer-refresh.js +536 -0
  183. package/dist/lib/gofer-refresh.js.map +1 -0
  184. package/dist/lib/next-route-exports.d.ts +6 -0
  185. package/dist/lib/next-route-exports.d.ts.map +1 -0
  186. package/dist/lib/next-route-exports.js +127 -0
  187. package/dist/lib/next-route-exports.js.map +1 -0
  188. package/dist/lib/npm.d.ts +2 -0
  189. package/dist/lib/npm.d.ts.map +1 -0
  190. package/dist/lib/npm.js +4 -0
  191. package/dist/lib/npm.js.map +1 -0
  192. package/dist/lib/object-type-defaults.d.ts +4 -0
  193. package/dist/lib/object-type-defaults.d.ts.map +1 -0
  194. package/dist/lib/object-type-defaults.js +72 -0
  195. package/dist/lib/object-type-defaults.js.map +1 -0
  196. package/dist/lib/output.d.ts +35 -0
  197. package/dist/lib/output.d.ts.map +1 -0
  198. package/dist/lib/output.js +166 -0
  199. package/dist/lib/output.js.map +1 -0
  200. package/dist/lib/profile.d.ts +52 -0
  201. package/dist/lib/profile.d.ts.map +1 -0
  202. package/dist/lib/profile.js +116 -0
  203. package/dist/lib/profile.js.map +1 -0
  204. package/dist/lib/project-manifest.d.ts +42 -0
  205. package/dist/lib/project-manifest.d.ts.map +1 -0
  206. package/dist/lib/project-manifest.js +191 -0
  207. package/dist/lib/project-manifest.js.map +1 -0
  208. package/dist/lib/resourceapi-bundle.d.ts +33 -0
  209. package/dist/lib/resourceapi-bundle.d.ts.map +1 -0
  210. package/dist/lib/resourceapi-bundle.js +79 -0
  211. package/dist/lib/resourceapi-bundle.js.map +1 -0
  212. package/dist/lib/runtime-contract.d.ts +84 -0
  213. package/dist/lib/runtime-contract.d.ts.map +1 -0
  214. package/dist/lib/runtime-contract.js +318 -0
  215. package/dist/lib/runtime-contract.js.map +1 -0
  216. package/dist/lib/schema-builder.d.ts +28 -0
  217. package/dist/lib/schema-builder.d.ts.map +1 -0
  218. package/dist/lib/schema-builder.js +69 -0
  219. package/dist/lib/schema-builder.js.map +1 -0
  220. package/dist/lib/tenant-context.d.ts +127 -0
  221. package/dist/lib/tenant-context.d.ts.map +1 -0
  222. package/dist/lib/tenant-context.js +573 -0
  223. package/dist/lib/tenant-context.js.map +1 -0
  224. package/dist/lib/update-check.d.ts +52 -0
  225. package/dist/lib/update-check.d.ts.map +1 -0
  226. package/dist/lib/update-check.js +271 -0
  227. package/dist/lib/update-check.js.map +1 -0
  228. package/dist/lib/update-maintenance.d.ts +15 -0
  229. package/dist/lib/update-maintenance.d.ts.map +1 -0
  230. package/dist/lib/update-maintenance.js +187 -0
  231. package/dist/lib/update-maintenance.js.map +1 -0
  232. package/dist/lib/utils.d.ts +23 -0
  233. package/dist/lib/utils.d.ts.map +1 -0
  234. package/dist/lib/utils.js +48 -0
  235. package/dist/lib/utils.js.map +1 -0
  236. package/dist/lib/workflow-provisioning.d.ts +54 -0
  237. package/dist/lib/workflow-provisioning.d.ts.map +1 -0
  238. package/dist/lib/workflow-provisioning.js +281 -0
  239. package/dist/lib/workflow-provisioning.js.map +1 -0
  240. package/package.json +51 -0
  241. package/resources/gofer/.gofer-version +7 -0
  242. package/resources/gofer/agents-skills/0_gofer_start/SKILL.md +1287 -0
  243. package/resources/gofer/agents-skills/0a_problem_validation/SKILL.md +429 -0
  244. package/resources/gofer/agents-skills/10_gofer_cloud/SKILL.md +635 -0
  245. package/resources/gofer/agents-skills/1_gofer_research/SKILL.md +1159 -0
  246. package/resources/gofer/agents-skills/2_gofer_specify/SKILL.md +860 -0
  247. package/resources/gofer/agents-skills/3_gofer_plan/SKILL.md +886 -0
  248. package/resources/gofer/agents-skills/4_gofer_tasks/SKILL.md +748 -0
  249. package/resources/gofer/agents-skills/5_gofer_implement/SKILL.md +924 -0
  250. package/resources/gofer/agents-skills/6_gofer_validate/SKILL.md +2269 -0
  251. package/resources/gofer/agents-skills/7_gofer_save/SKILL.md +423 -0
  252. package/resources/gofer/agents-skills/7a_stakeholder_comms/SKILL.md +508 -0
  253. package/resources/gofer/agents-skills/8_gofer_branding/SKILL.md +315 -0
  254. package/resources/gofer/agents-skills/9_gofer_tests/SKILL.md +558 -0
  255. package/resources/gofer/agents-skills/gofer_bootstrap_workspace/SKILL.md +148 -0
  256. package/resources/gofer/agents-skills/gofer_check_workspace/SKILL.md +119 -0
  257. package/resources/gofer/agents-skills/gofer_constitution/SKILL.md +612 -0
  258. package/resources/gofer/agents-skills/gofer_diagnose/SKILL.md +114 -0
  259. package/resources/gofer/agents-skills/gofer_eai_first_run/SKILL.md +397 -0
  260. package/resources/gofer/agents-skills/gofer_hydrate/SKILL.md +561 -0
  261. package/resources/gofer/agents-skills/gofer_personality/SKILL.md +44 -0
  262. package/resources/gofer/agents-skills/gofer_plan/SKILL.md +40 -0
  263. package/resources/gofer/agents-skills/gofer_side/SKILL.md +45 -0
  264. package/resources/gofer/agents-skills/gofer_spec_summary/SKILL.md +112 -0
  265. package/resources/gofer/agents-skills/gofer_tdd/SKILL.md +112 -0
  266. package/resources/gofer/agents-skills/gofer_vocabulary/SKILL.md +112 -0
  267. package/resources/gofer/agents-skills/gofer_zoom_out/SKILL.md +112 -0
  268. package/resources/gofer/bash-scripts/check-context-health.sh +365 -0
  269. package/resources/gofer/bash-scripts/check-persona-pack.sh +81 -0
  270. package/resources/gofer/bash-scripts/check-prerequisites.sh +168 -0
  271. package/resources/gofer/bash-scripts/common.sh +192 -0
  272. package/resources/gofer/bash-scripts/create-new-feature.sh +260 -0
  273. package/resources/gofer/bash-scripts/install-optional-tools.sh +270 -0
  274. package/resources/gofer/bash-scripts/log-stage.sh +224 -0
  275. package/resources/gofer/bash-scripts/mark-task-complete.sh +74 -0
  276. package/resources/gofer/bash-scripts/pipeline-state.sh +306 -0
  277. package/resources/gofer/bash-scripts/read-failed-approaches.sh +114 -0
  278. package/resources/gofer/bash-scripts/read-session-memories.sh +96 -0
  279. package/resources/gofer/bash-scripts/save-checkpoint.sh +407 -0
  280. package/resources/gofer/bash-scripts/setup-plan.sh +62 -0
  281. package/resources/gofer/bash-scripts/sync-implementation-status.sh +47 -0
  282. package/resources/gofer/bash-scripts/update-agent-context.sh +772 -0
  283. package/resources/gofer/bash-scripts/validate-artifact.sh +335 -0
  284. package/resources/gofer/bash-scripts/verify-task.sh +384 -0
  285. package/resources/gofer/bash-scripts/write-failed-approach.sh +110 -0
  286. package/resources/gofer/bash-scripts/write-periodic-checkpoint.sh +128 -0
  287. package/resources/gofer/bash-scripts/write-session-memory.sh +118 -0
  288. package/resources/gofer/claude-agents/assumption-tracker.md +168 -0
  289. package/resources/gofer/claude-agents/business-metrics-analyzer.md +169 -0
  290. package/resources/gofer/claude-agents/business-problem-validator.md +168 -0
  291. package/resources/gofer/claude-agents/codebase-analyzer.md +124 -0
  292. package/resources/gofer/claude-agents/codebase-locator.md +95 -0
  293. package/resources/gofer/claude-agents/codebase-pattern-finder.md +180 -0
  294. package/resources/gofer/claude-agents/comms-writer.md +158 -0
  295. package/resources/gofer/claude-agents/engineer-review.md +169 -0
  296. package/resources/gofer/claude-agents/implement-bug-triangulator.md +94 -0
  297. package/resources/gofer/claude-agents/implement-code-review-council.md +89 -0
  298. package/resources/gofer/claude-agents/implement-doc-writer.md +89 -0
  299. package/resources/gofer/claude-agents/implement-error-hardener.md +84 -0
  300. package/resources/gofer/claude-agents/implement-performance-explorer.md +95 -0
  301. package/resources/gofer/claude-agents/implement-test-diversifier.md +82 -0
  302. package/resources/gofer/claude-agents/implement-variant-generator.md +80 -0
  303. package/resources/gofer/claude-agents/multi-perspective-judge.md +114 -0
  304. package/resources/gofer/claude-agents/plan-api-comparator.md +90 -0
  305. package/resources/gofer/claude-agents/plan-architecture-diverger.md +100 -0
  306. package/resources/gofer/claude-agents/plan-data-model-stress-tester.md +95 -0
  307. package/resources/gofer/claude-agents/plan-migration-path-finder.md +95 -0
  308. package/resources/gofer/claude-agents/plan-refactor-rewrite-advisor.md +97 -0
  309. package/resources/gofer/claude-agents/research-dependency-evaluator.md +106 -0
  310. package/resources/gofer/claude-agents/research-horizon-scanner.md +100 -0
  311. package/resources/gofer/claude-agents/research-market-scanner.md +137 -0
  312. package/resources/gofer/claude-agents/research-perspective-multiplier.md +102 -0
  313. package/resources/gofer/claude-agents/scope-creep-detector.md +152 -0
  314. package/resources/gofer/claude-agents/specify-ambiguity-detector.md +95 -0
  315. package/resources/gofer/claude-agents/specify-journey-stress-tester.md +92 -0
  316. package/resources/gofer/claude-agents/tasks-cross-cutting-scanner.md +91 -0
  317. package/resources/gofer/claude-agents/tasks-rollback-planner.md +89 -0
  318. package/resources/gofer/claude-agents/validate-security-red-team.md +102 -0
  319. package/resources/gofer/claude-agents/validation-correctness.md +103 -0
  320. package/resources/gofer/claude-agents/validation-integration.md +129 -0
  321. package/resources/gofer/claude-agents/validation-performance.md +120 -0
  322. package/resources/gofer/claude-agents/validation-security.md +115 -0
  323. package/resources/gofer/claude-agents/validation-standards.md +151 -0
  324. package/resources/gofer/claude-agents/validation-test-quality.md +146 -0
  325. package/resources/gofer/claude-agents/visual-bounded-context-writer.md +40 -0
  326. package/resources/gofer/claude-agents/visual-c4-writer.md +45 -0
  327. package/resources/gofer/claude-agents/visual-erd-writer.md +34 -0
  328. package/resources/gofer/claude-agents/visual-heatmap-writer.md +63 -0
  329. package/resources/gofer/claude-agents/visual-risk-writer.md +64 -0
  330. package/resources/gofer/claude-commands/0_gofer_start.md +1282 -0
  331. package/resources/gofer/claude-commands/0a_problem_validation.md +424 -0
  332. package/resources/gofer/claude-commands/10_gofer_cloud.md +630 -0
  333. package/resources/gofer/claude-commands/1_gofer_research.md +1154 -0
  334. package/resources/gofer/claude-commands/2_gofer_specify.md +855 -0
  335. package/resources/gofer/claude-commands/3_gofer_plan.md +881 -0
  336. package/resources/gofer/claude-commands/4_gofer_tasks.md +743 -0
  337. package/resources/gofer/claude-commands/5_gofer_implement.md +919 -0
  338. package/resources/gofer/claude-commands/6_gofer_validate.md +2264 -0
  339. package/resources/gofer/claude-commands/7_gofer_save.md +418 -0
  340. package/resources/gofer/claude-commands/7a_stakeholder_comms.md +503 -0
  341. package/resources/gofer/claude-commands/8_gofer_branding.md +310 -0
  342. package/resources/gofer/claude-commands/9_gofer_tests.md +553 -0
  343. package/resources/gofer/claude-commands/gofer_bootstrap_workspace.md +143 -0
  344. package/resources/gofer/claude-commands/gofer_check_workspace.md +114 -0
  345. package/resources/gofer/claude-commands/gofer_constitution.md +607 -0
  346. package/resources/gofer/claude-commands/gofer_diagnose.md +109 -0
  347. package/resources/gofer/claude-commands/gofer_eai_first_run.md +392 -0
  348. package/resources/gofer/claude-commands/gofer_hydrate.md +556 -0
  349. package/resources/gofer/claude-commands/gofer_personality.md +39 -0
  350. package/resources/gofer/claude-commands/gofer_plan.md +35 -0
  351. package/resources/gofer/claude-commands/gofer_side.md +40 -0
  352. package/resources/gofer/claude-commands/gofer_spec_summary.md +107 -0
  353. package/resources/gofer/claude-commands/gofer_tdd.md +107 -0
  354. package/resources/gofer/claude-commands/gofer_vocabulary.md +107 -0
  355. package/resources/gofer/claude-commands/gofer_zoom_out.md +107 -0
  356. package/resources/gofer/claude-skills/eai-gofer/SKILL.md +56 -0
  357. package/resources/gofer/commands/.gitkeep +0 -0
  358. package/resources/gofer/commands/0_gofer_start.md +1299 -0
  359. package/resources/gofer/commands/0a_problem_validation.md +405 -0
  360. package/resources/gofer/commands/10_gofer_cloud.md +611 -0
  361. package/resources/gofer/commands/1_gofer_research.md +1135 -0
  362. package/resources/gofer/commands/2_gofer_specify.md +836 -0
  363. package/resources/gofer/commands/3_gofer_plan.md +862 -0
  364. package/resources/gofer/commands/4_gofer_tasks.md +724 -0
  365. package/resources/gofer/commands/5_gofer_implement.md +900 -0
  366. package/resources/gofer/commands/6_gofer_validate.md +2245 -0
  367. package/resources/gofer/commands/7_gofer_save.md +399 -0
  368. package/resources/gofer/commands/7a_stakeholder_comms.md +484 -0
  369. package/resources/gofer/commands/8_gofer_branding.md +291 -0
  370. package/resources/gofer/commands/9_gofer_tests.md +534 -0
  371. package/resources/gofer/commands/gofer_bootstrap_workspace.md +159 -0
  372. package/resources/gofer/commands/gofer_check_workspace.md +130 -0
  373. package/resources/gofer/commands/gofer_constitution.md +588 -0
  374. package/resources/gofer/commands/gofer_diagnose.md +89 -0
  375. package/resources/gofer/commands/gofer_eai_first_run.md +392 -0
  376. package/resources/gofer/commands/gofer_hydrate.md +537 -0
  377. package/resources/gofer/commands/gofer_personality.md +61 -0
  378. package/resources/gofer/commands/gofer_plan.md +51 -0
  379. package/resources/gofer/commands/gofer_side.md +56 -0
  380. package/resources/gofer/commands/gofer_spec_summary.md +87 -0
  381. package/resources/gofer/commands/gofer_tdd.md +87 -0
  382. package/resources/gofer/commands/gofer_vocabulary.md +87 -0
  383. package/resources/gofer/commands/gofer_zoom_out.md +87 -0
  384. package/resources/gofer/copilot-instructions/gofer-cost.instructions.md +13 -0
  385. package/resources/gofer/copilot-instructions/language-server.instructions.md +49 -0
  386. package/resources/gofer/copilot-instructions/typescript.instructions.md +47 -0
  387. package/resources/gofer/copilot-instructions/vscode-extension.instructions.md +46 -0
  388. package/resources/gofer/copilot-prompts/0_gofer_start.prompt.md +1308 -0
  389. package/resources/gofer/copilot-prompts/0a_problem_validation.prompt.md +429 -0
  390. package/resources/gofer/copilot-prompts/10_gofer_cloud.prompt.md +644 -0
  391. package/resources/gofer/copilot-prompts/1_gofer_research.prompt.md +1177 -0
  392. package/resources/gofer/copilot-prompts/2_gofer_specify.prompt.md +878 -0
  393. package/resources/gofer/copilot-prompts/3_gofer_plan.prompt.md +904 -0
  394. package/resources/gofer/copilot-prompts/4_gofer_tasks.prompt.md +766 -0
  395. package/resources/gofer/copilot-prompts/5_gofer_implement.prompt.md +942 -0
  396. package/resources/gofer/copilot-prompts/6_gofer_validate.prompt.md +2277 -0
  397. package/resources/gofer/copilot-prompts/7_gofer_save.prompt.md +433 -0
  398. package/resources/gofer/copilot-prompts/7a_stakeholder_comms.prompt.md +516 -0
  399. package/resources/gofer/copilot-prompts/8_gofer_branding.prompt.md +323 -0
  400. package/resources/gofer/copilot-prompts/9_gofer_tests.prompt.md +566 -0
  401. package/resources/gofer/copilot-prompts/gofer_bootstrap_workspace.prompt.md +161 -0
  402. package/resources/gofer/copilot-prompts/gofer_check_workspace.prompt.md +132 -0
  403. package/resources/gofer/copilot-prompts/gofer_constitution.prompt.md +621 -0
  404. package/resources/gofer/copilot-prompts/gofer_diagnose.prompt.md +127 -0
  405. package/resources/gofer/copilot-prompts/gofer_eai_first_run.prompt.md +410 -0
  406. package/resources/gofer/copilot-prompts/gofer_hydrate.prompt.md +571 -0
  407. package/resources/gofer/copilot-prompts/gofer_personality.prompt.md +57 -0
  408. package/resources/gofer/copilot-prompts/gofer_plan.prompt.md +53 -0
  409. package/resources/gofer/copilot-prompts/gofer_side.prompt.md +58 -0
  410. package/resources/gofer/copilot-prompts/gofer_spec_summary.prompt.md +125 -0
  411. package/resources/gofer/copilot-prompts/gofer_tdd.prompt.md +125 -0
  412. package/resources/gofer/copilot-prompts/gofer_vocabulary.prompt.md +125 -0
  413. package/resources/gofer/copilot-prompts/gofer_zoom_out.prompt.md +125 -0
  414. package/resources/gofer/gemini/agents/assumption-tracker.md +171 -0
  415. package/resources/gofer/gemini/agents/business-metrics-analyzer.md +172 -0
  416. package/resources/gofer/gemini/agents/business-problem-validator.md +171 -0
  417. package/resources/gofer/gemini/agents/codebase-analyzer.md +127 -0
  418. package/resources/gofer/gemini/agents/codebase-locator.md +98 -0
  419. package/resources/gofer/gemini/agents/codebase-pattern-finder.md +183 -0
  420. package/resources/gofer/gemini/agents/comms-writer.md +161 -0
  421. package/resources/gofer/gemini/agents/engineer-review.md +172 -0
  422. package/resources/gofer/gemini/agents/implement-bug-triangulator.md +97 -0
  423. package/resources/gofer/gemini/agents/implement-code-review-council.md +92 -0
  424. package/resources/gofer/gemini/agents/implement-doc-writer.md +92 -0
  425. package/resources/gofer/gemini/agents/implement-error-hardener.md +87 -0
  426. package/resources/gofer/gemini/agents/implement-performance-explorer.md +98 -0
  427. package/resources/gofer/gemini/agents/implement-test-diversifier.md +85 -0
  428. package/resources/gofer/gemini/agents/implement-variant-generator.md +83 -0
  429. package/resources/gofer/gemini/agents/multi-perspective-judge.md +117 -0
  430. package/resources/gofer/gemini/agents/plan-api-comparator.md +93 -0
  431. package/resources/gofer/gemini/agents/plan-architecture-diverger.md +103 -0
  432. package/resources/gofer/gemini/agents/plan-data-model-stress-tester.md +98 -0
  433. package/resources/gofer/gemini/agents/plan-migration-path-finder.md +98 -0
  434. package/resources/gofer/gemini/agents/plan-refactor-rewrite-advisor.md +100 -0
  435. package/resources/gofer/gemini/agents/research-dependency-evaluator.md +109 -0
  436. package/resources/gofer/gemini/agents/research-horizon-scanner.md +103 -0
  437. package/resources/gofer/gemini/agents/research-market-scanner.md +140 -0
  438. package/resources/gofer/gemini/agents/research-perspective-multiplier.md +105 -0
  439. package/resources/gofer/gemini/agents/scope-creep-detector.md +155 -0
  440. package/resources/gofer/gemini/agents/specify-ambiguity-detector.md +98 -0
  441. package/resources/gofer/gemini/agents/specify-journey-stress-tester.md +95 -0
  442. package/resources/gofer/gemini/agents/tasks-cross-cutting-scanner.md +94 -0
  443. package/resources/gofer/gemini/agents/tasks-rollback-planner.md +92 -0
  444. package/resources/gofer/gemini/agents/validate-security-red-team.md +105 -0
  445. package/resources/gofer/gemini/agents/validation-correctness.md +106 -0
  446. package/resources/gofer/gemini/agents/validation-integration.md +132 -0
  447. package/resources/gofer/gemini/agents/validation-performance.md +123 -0
  448. package/resources/gofer/gemini/agents/validation-security.md +118 -0
  449. package/resources/gofer/gemini/agents/validation-standards.md +154 -0
  450. package/resources/gofer/gemini/agents/validation-test-quality.md +149 -0
  451. package/resources/gofer/gemini/agents/visual-bounded-context-writer.md +40 -0
  452. package/resources/gofer/gemini/agents/visual-c4-writer.md +44 -0
  453. package/resources/gofer/gemini/agents/visual-erd-writer.md +36 -0
  454. package/resources/gofer/gemini/agents/visual-heatmap-writer.md +63 -0
  455. package/resources/gofer/gemini/agents/visual-risk-writer.md +64 -0
  456. package/resources/gofer/gemini/commands/gofer/.gitkeep +0 -0
  457. package/resources/gofer/gemini/commands/gofer/0_gofer_start.md +1282 -0
  458. package/resources/gofer/gemini/commands/gofer/0_gofer_start.toml +2 -0
  459. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.md +424 -0
  460. package/resources/gofer/gemini/commands/gofer/0a_problem_validation.toml +2 -0
  461. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.md +630 -0
  462. package/resources/gofer/gemini/commands/gofer/10_gofer_cloud.toml +2 -0
  463. package/resources/gofer/gemini/commands/gofer/1_gofer_research.md +1154 -0
  464. package/resources/gofer/gemini/commands/gofer/1_gofer_research.toml +2 -0
  465. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.md +855 -0
  466. package/resources/gofer/gemini/commands/gofer/2_gofer_specify.toml +2 -0
  467. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.md +881 -0
  468. package/resources/gofer/gemini/commands/gofer/3_gofer_plan.toml +2 -0
  469. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.md +743 -0
  470. package/resources/gofer/gemini/commands/gofer/4_gofer_tasks.toml +2 -0
  471. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.md +919 -0
  472. package/resources/gofer/gemini/commands/gofer/5_gofer_implement.toml +2 -0
  473. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.md +2264 -0
  474. package/resources/gofer/gemini/commands/gofer/6_gofer_validate.toml +2 -0
  475. package/resources/gofer/gemini/commands/gofer/7_gofer_save.md +418 -0
  476. package/resources/gofer/gemini/commands/gofer/7_gofer_save.toml +2 -0
  477. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.md +503 -0
  478. package/resources/gofer/gemini/commands/gofer/7a_stakeholder_comms.toml +2 -0
  479. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.md +310 -0
  480. package/resources/gofer/gemini/commands/gofer/8_gofer_branding.toml +2 -0
  481. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.md +553 -0
  482. package/resources/gofer/gemini/commands/gofer/9_gofer_tests.toml +2 -0
  483. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.md +143 -0
  484. package/resources/gofer/gemini/commands/gofer/gofer_bootstrap_workspace.toml +2 -0
  485. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.md +114 -0
  486. package/resources/gofer/gemini/commands/gofer/gofer_check_workspace.toml +2 -0
  487. package/resources/gofer/gemini/commands/gofer/gofer_constitution.md +607 -0
  488. package/resources/gofer/gemini/commands/gofer/gofer_constitution.toml +2 -0
  489. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.md +109 -0
  490. package/resources/gofer/gemini/commands/gofer/gofer_diagnose.toml +2 -0
  491. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.md +392 -0
  492. package/resources/gofer/gemini/commands/gofer/gofer_eai_first_run.toml +2 -0
  493. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.md +556 -0
  494. package/resources/gofer/gemini/commands/gofer/gofer_hydrate.toml +2 -0
  495. package/resources/gofer/gemini/commands/gofer/gofer_personality.md +39 -0
  496. package/resources/gofer/gemini/commands/gofer/gofer_personality.toml +2 -0
  497. package/resources/gofer/gemini/commands/gofer/gofer_plan.md +35 -0
  498. package/resources/gofer/gemini/commands/gofer/gofer_plan.toml +2 -0
  499. package/resources/gofer/gemini/commands/gofer/gofer_side.md +40 -0
  500. package/resources/gofer/gemini/commands/gofer/gofer_side.toml +2 -0
  501. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.md +107 -0
  502. package/resources/gofer/gemini/commands/gofer/gofer_spec_summary.toml +2 -0
  503. package/resources/gofer/gemini/commands/gofer/gofer_tdd.md +107 -0
  504. package/resources/gofer/gemini/commands/gofer/gofer_tdd.toml +2 -0
  505. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.md +107 -0
  506. package/resources/gofer/gemini/commands/gofer/gofer_vocabulary.toml +2 -0
  507. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.md +107 -0
  508. package/resources/gofer/gemini/commands/gofer/gofer_zoom_out.toml +2 -0
  509. package/resources/gofer/gemini/commands/gofer/manifest.json +32 -0
  510. package/resources/gofer/gemini/extension.json +16 -0
  511. package/resources/gofer/github-agents/gofer-business.agent.md +20 -0
  512. package/resources/gofer/github-agents/gofer-implement.agent.md +15 -0
  513. package/resources/gofer/github-agents/gofer-plan.agent.md +15 -0
  514. package/resources/gofer/github-agents/gofer-research.agent.md +15 -0
  515. package/resources/gofer/github-agents/gofer-validate.agent.md +10 -0
  516. package/resources/gofer/github-skills/eai-gofer/SKILL.md +56 -0
  517. package/resources/gofer/hook-scripts/agent-stop.mjs +655 -0
  518. package/resources/gofer/hook-scripts/log-stage-launch-time.mjs +77 -0
  519. package/resources/gofer/hook-scripts/post-tool-use.mjs +333 -0
  520. package/resources/gofer/hook-scripts/queued-input.mjs +188 -0
  521. package/resources/gofer/hook-scripts/session-lifecycle.mjs +93 -0
  522. package/resources/gofer/hook-scripts/user-prompt-submit.mjs +228 -0
  523. package/resources/gofer/instruction-templates/base/agents-base.md +37 -0
  524. package/resources/gofer/instruction-templates/base/claude-base.md +7 -0
  525. package/resources/gofer/instruction-templates/base/copilot-base.md +26 -0
  526. package/resources/gofer/instruction-templates/gofer/gofer-claude.md +5 -0
  527. package/resources/gofer/instruction-templates/gofer/gofer-copilot.md +9 -0
  528. package/resources/gofer/instruction-templates/languages/generic.md +7 -0
  529. package/resources/gofer/instruction-templates/languages/go.md +8 -0
  530. package/resources/gofer/instruction-templates/languages/java.md +8 -0
  531. package/resources/gofer/instruction-templates/languages/python.md +9 -0
  532. package/resources/gofer/instruction-templates/languages/rust.md +9 -0
  533. package/resources/gofer/instruction-templates/languages/typescript.md +19 -0
  534. package/resources/gofer/instruction-templates/workflow/principles.md +52 -0
  535. package/resources/gofer/memory/constitution.md +391 -0
  536. package/resources/gofer/memory/context-profiles.yaml +74 -0
  537. package/resources/gofer/memory/decisions/000-use-adr-for-decisions.md +67 -0
  538. package/resources/gofer/memory/decisions/001-di-framework.md +190 -0
  539. package/resources/gofer/memory/decisions/002-module-extraction.md +305 -0
  540. package/resources/gofer/memory/decisions/003-error-handling.md +368 -0
  541. package/resources/gofer/memory/decisions/004-cache-eviction.md +436 -0
  542. package/resources/gofer/memory/decisions/005-constants-management.md +520 -0
  543. package/resources/gofer/memory/decisions/README.md +129 -0
  544. package/resources/gofer/memory/diagrams/di-container.mmd +321 -0
  545. package/resources/gofer/memory/diagrams/extension-activation.mmd +184 -0
  546. package/resources/gofer/memory/diagrams/module-dependencies.mmd +264 -0
  547. package/resources/gofer/memory/gofer-model-policy.yaml +97 -0
  548. package/resources/gofer/memory/lessons.md +46 -0
  549. package/resources/gofer/node-scripts/canonical-descriptions.mjs +86 -0
  550. package/resources/gofer/node-scripts/check-version-alignment.mjs +131 -0
  551. package/resources/gofer/node-scripts/codex-doctor.mjs +425 -0
  552. package/resources/gofer/node-scripts/generate-commands.mjs +1366 -0
  553. package/resources/gofer/node-scripts/generate-issues.js +563 -0
  554. package/resources/gofer/node-scripts/gofer-closed-loop-audit.mjs +893 -0
  555. package/resources/gofer/node-scripts/gofer-loop-audit.mjs +541 -0
  556. package/resources/gofer/node-scripts/gofer-performance-report.mjs +306 -0
  557. package/resources/gofer/node-scripts/gofer-workspace-bootstrap.mjs +56 -0
  558. package/resources/gofer/node-scripts/gofer-workspace-check.mjs +56 -0
  559. package/resources/gofer/node-scripts/lib/ai-leverage-tagger.mjs +103 -0
  560. package/resources/gofer/node-scripts/lib/assemble-stakeholder-pack.mjs +114 -0
  561. package/resources/gofer/node-scripts/lib/marp-deck.mjs +87 -0
  562. package/resources/gofer/node-scripts/lib/mermaid-tabular-fallback.mjs +264 -0
  563. package/resources/gofer/node-scripts/lib/render-visual.mjs +54 -0
  564. package/resources/gofer/node-scripts/lib/validate-aliases.mjs +85 -0
  565. package/resources/gofer/node-scripts/lib/visual-counts.mjs +44 -0
  566. package/resources/gofer/node-scripts/lib/visual-pass-pipeline.mjs +134 -0
  567. package/resources/gofer/node-scripts/mermaid-export.mjs +72 -0
  568. package/resources/gofer/node-scripts/package-agent-plugin.mjs +940 -0
  569. package/resources/gofer/node-scripts/parse-stage-command.mjs +211 -0
  570. package/resources/gofer/node-scripts/schemas/.gitkeep +0 -0
  571. package/resources/gofer/node-scripts/schemas/stage-command.schema.json +72 -0
  572. package/resources/gofer/node-scripts/sync-extension-resources.mjs +110 -0
  573. package/resources/gofer/node-scripts/workspace-bootstrap-lib.mjs +1166 -0
  574. package/resources/gofer/powershell-scripts/install-optional-tools.ps1 +214 -0
  575. package/resources/gofer/references/platform/README.md +17 -0
  576. package/resources/gofer/references/platform/deployment-repo.md +9 -0
  577. package/resources/gofer/references/platform/eai-app-template.md +45 -0
  578. package/resources/gofer/references/platform/eai-config-driven-ui.md +156 -0
  579. package/resources/gofer/references/platform/eai-error-catalog.yaml +197 -0
  580. package/resources/gofer/references/platform/eai-repo-contract.md +134 -0
  581. package/resources/gofer/references/platform/eai-service-patterns.md +56 -0
  582. package/resources/gofer/references/platform/eai.md +85 -0
  583. package/resources/gofer/references/platform/vertical-template.md +49 -0
  584. package/resources/gofer/specify-commands/.gitkeep +0 -0
  585. package/resources/gofer/specify-commands/0_gofer_start.md +1299 -0
  586. package/resources/gofer/specify-commands/0a_problem_validation.md +405 -0
  587. package/resources/gofer/specify-commands/10_gofer_cloud.md +611 -0
  588. package/resources/gofer/specify-commands/1_gofer_research.md +1135 -0
  589. package/resources/gofer/specify-commands/2_gofer_specify.md +836 -0
  590. package/resources/gofer/specify-commands/3_gofer_plan.md +862 -0
  591. package/resources/gofer/specify-commands/4_gofer_tasks.md +724 -0
  592. package/resources/gofer/specify-commands/5_gofer_implement.md +900 -0
  593. package/resources/gofer/specify-commands/6_gofer_validate.md +2245 -0
  594. package/resources/gofer/specify-commands/7_gofer_save.md +399 -0
  595. package/resources/gofer/specify-commands/7a_stakeholder_comms.md +484 -0
  596. package/resources/gofer/specify-commands/8_gofer_branding.md +291 -0
  597. package/resources/gofer/specify-commands/9_gofer_tests.md +534 -0
  598. package/resources/gofer/specify-commands/gofer_bootstrap_workspace.md +159 -0
  599. package/resources/gofer/specify-commands/gofer_check_workspace.md +130 -0
  600. package/resources/gofer/specify-commands/gofer_constitution.md +588 -0
  601. package/resources/gofer/specify-commands/gofer_diagnose.md +89 -0
  602. package/resources/gofer/specify-commands/gofer_eai_first_run.md +392 -0
  603. package/resources/gofer/specify-commands/gofer_hydrate.md +537 -0
  604. package/resources/gofer/specify-commands/gofer_personality.md +61 -0
  605. package/resources/gofer/specify-commands/gofer_plan.md +51 -0
  606. package/resources/gofer/specify-commands/gofer_side.md +56 -0
  607. package/resources/gofer/specify-commands/gofer_spec_summary.md +87 -0
  608. package/resources/gofer/specify-commands/gofer_tdd.md +87 -0
  609. package/resources/gofer/specify-commands/gofer_vocabulary.md +87 -0
  610. package/resources/gofer/specify-commands/gofer_zoom_out.md +87 -0
  611. package/resources/gofer/system-skills/0_gofer_start/SKILL.md +1287 -0
  612. package/resources/gofer/system-skills/0a_problem_validation/SKILL.md +429 -0
  613. package/resources/gofer/system-skills/10_gofer_cloud/SKILL.md +635 -0
  614. package/resources/gofer/system-skills/1_gofer_research/SKILL.md +1159 -0
  615. package/resources/gofer/system-skills/2_gofer_specify/SKILL.md +860 -0
  616. package/resources/gofer/system-skills/3_gofer_plan/SKILL.md +886 -0
  617. package/resources/gofer/system-skills/4_gofer_tasks/SKILL.md +748 -0
  618. package/resources/gofer/system-skills/5_gofer_implement/SKILL.md +924 -0
  619. package/resources/gofer/system-skills/6_gofer_validate/SKILL.md +2269 -0
  620. package/resources/gofer/system-skills/7_gofer_save/SKILL.md +423 -0
  621. package/resources/gofer/system-skills/7a_stakeholder_comms/SKILL.md +508 -0
  622. package/resources/gofer/system-skills/8_gofer_branding/SKILL.md +315 -0
  623. package/resources/gofer/system-skills/9_gofer_tests/SKILL.md +558 -0
  624. package/resources/gofer/system-skills/gofer_bootstrap_workspace/SKILL.md +148 -0
  625. package/resources/gofer/system-skills/gofer_check_workspace/SKILL.md +119 -0
  626. package/resources/gofer/system-skills/gofer_constitution/SKILL.md +612 -0
  627. package/resources/gofer/system-skills/gofer_diagnose/SKILL.md +114 -0
  628. package/resources/gofer/system-skills/gofer_eai_first_run/SKILL.md +397 -0
  629. package/resources/gofer/system-skills/gofer_hydrate/SKILL.md +561 -0
  630. package/resources/gofer/system-skills/gofer_personality/SKILL.md +44 -0
  631. package/resources/gofer/system-skills/gofer_plan/SKILL.md +40 -0
  632. package/resources/gofer/system-skills/gofer_side/SKILL.md +45 -0
  633. package/resources/gofer/system-skills/gofer_spec_summary/SKILL.md +112 -0
  634. package/resources/gofer/system-skills/gofer_tdd/SKILL.md +112 -0
  635. package/resources/gofer/system-skills/gofer_vocabulary/SKILL.md +112 -0
  636. package/resources/gofer/system-skills/gofer_zoom_out/SKILL.md +112 -0
  637. package/resources/gofer/templates/agent-file-template.md +28 -0
  638. package/resources/gofer/templates/assumptions-template.md +94 -0
  639. package/resources/gofer/templates/audit-history-template.md +35 -0
  640. package/resources/gofer/templates/brand/brand-profile-template.json +45 -0
  641. package/resources/gofer/templates/brand/document-style-template.md +50 -0
  642. package/resources/gofer/templates/brand/marp-theme-template.css +58 -0
  643. package/resources/gofer/templates/brownfield-analysis.md +44 -0
  644. package/resources/gofer/templates/business-metrics-template.md +120 -0
  645. package/resources/gofer/templates/business-owner-summary-template.md +83 -0
  646. package/resources/gofer/templates/checklist-template.md +40 -0
  647. package/resources/gofer/templates/ciso-security-summary-template.md +70 -0
  648. package/resources/gofer/templates/context-bundle-template.md +76 -0
  649. package/resources/gofer/templates/contract-pack-template.md +109 -0
  650. package/resources/gofer/templates/cto-architecture-summary-template.md +83 -0
  651. package/resources/gofer/templates/discovery-template.md +92 -0
  652. package/resources/gofer/templates/eai-preflight-template.md +144 -0
  653. package/resources/gofer/templates/goal-ledger-template.json +69 -0
  654. package/resources/gofer/templates/gofer-model-policy.yaml +97 -0
  655. package/resources/gofer/templates/issues-template.md +106 -0
  656. package/resources/gofer/templates/journey/base-journey.md +95 -0
  657. package/resources/gofer/templates/journey/industry-variants.yaml +277 -0
  658. package/resources/gofer/templates/loop-contract-template.json +68 -0
  659. package/resources/gofer/templates/plan-template.md +215 -0
  660. package/resources/gofer/templates/problem-brief-template.md +85 -0
  661. package/resources/gofer/templates/proposal-review-template.md +79 -0
  662. package/resources/gofer/templates/research-template.md +222 -0
  663. package/resources/gofer/templates/reuse-scan-template.md +43 -0
  664. package/resources/gofer/templates/sequence-diagrams/option-spectrum.yaml +178 -0
  665. package/resources/gofer/templates/service-fit-matrix-template.md +29 -0
  666. package/resources/gofer/templates/session-handoff-template.md +172 -0
  667. package/resources/gofer/templates/spec-summary-template.md +118 -0
  668. package/resources/gofer/templates/spec-template.md +196 -0
  669. package/resources/gofer/templates/stakeholder-comms-template.md +330 -0
  670. package/resources/gofer/templates/stakeholder-review-index-template.md +54 -0
  671. package/resources/gofer/templates/tasks-template.md +323 -0
  672. package/resources/gofer/templates/ui-approval-template.md +32 -0
  673. package/resources/gofer/templates/ui-preview-brief-template.md +65 -0
  674. package/resources/gofer/templates/ui-review-log-template.md +11 -0
  675. package/resources/gofer/templates/visuals/.gitkeep +0 -0
  676. package/resources/gofer/templates/visuals/bounded-context-map.md +19 -0
  677. package/resources/gofer/templates/visuals/bounded-context-template.md +47 -0
  678. package/resources/gofer/templates/visuals/c4-container-template.md +38 -0
  679. package/resources/gofer/templates/visuals/c4-container.md +20 -0
  680. package/resources/gofer/templates/visuals/c4-context-template.md +46 -0
  681. package/resources/gofer/templates/visuals/capability-heatmap-template.md +54 -0
  682. package/resources/gofer/templates/visuals/data-model-erd-template.md +41 -0
  683. package/resources/gofer/templates/visuals/erd.md +19 -0
  684. package/resources/gofer/templates/visuals/impact-canvas.md +40 -0
  685. package/resources/gofer/templates/visuals/risk-heatmap-template.md +51 -0
  686. package/resources/gofer/templates/visuals/roi-projection.md +17 -0
  687. package/resources/gofer/templates/visuals/value-stream-asis.md +16 -0
  688. package/resources/gofer/templates/visuals/value-stream-tobe.md +18 -0
  689. package/resources/gofer/templates/working-backwards-prfaq-template.md +165 -0
  690. package/resources/linked-sources.json +25 -0
@@ -0,0 +1,1636 @@
1
+ /**
2
+ * eai types — manage Object Type definitions.
3
+ *
4
+ * seed: Push local Object Types to platform via PublicAPI
5
+ * validate: Check types against platform schema rules
6
+ * diff: Compare local definitions with remote platform state
7
+ * pull: Download remote Object Types to local TypeScript
8
+ * define: Interactive Object Type builder (future)
9
+ */
10
+ import { Command } from "commander";
11
+ import ora from "ora";
12
+ import chalk from "chalk";
13
+ import inquirer from "inquirer";
14
+ import { findProjectRoot, loadObjectTypes, } from "../lib/config.js";
15
+ import { extractServerErrorContext, PlatformAPIClient } from "../lib/api.js";
16
+ import { resolveCommandContext } from "../lib/context.js";
17
+ import { validateObjectTypeDefaultValues } from "../lib/object-type-defaults.js";
18
+ import { isRecord, toObjectTypeSlug } from "../lib/utils.js";
19
+ import * as out from "../lib/output.js";
20
+ import { ErrorCode, exitWithError } from "../lib/error-codes.js";
21
+ export function shouldFailTypeSeedRun(results) {
22
+ return results.some((result) => {
23
+ const syncStatus = isRecord(result.resourceApiSchemaSync)
24
+ ? String(result.resourceApiSchemaSync.status ?? "").toLowerCase()
25
+ : undefined;
26
+ return (!result.verification?.converged ||
27
+ isBlockingResourceApiSchemaSyncStatus(syncStatus));
28
+ });
29
+ }
30
+ const RESOURCEAPI_SCHEMA_SYNC_NON_FAILURE_STATUSES = new Set([
31
+ "pending",
32
+ "queued",
33
+ "synced",
34
+ ]);
35
+ const RESOURCEAPI_SCHEMA_SYNC_ASYNC_STATUSES = new Set(["pending", "queued"]);
36
+ const RESOURCEAPI_SCHEMA_BACKGROUND_APPLY_UNTRUSTED_INSTALL = "RESOURCEAPI_SCHEMA_BACKGROUND_APPLY_UNTRUSTED_INSTALL";
37
+ const RESOURCEAPI_SCHEMA_VISIBILITY_TIMEOUT = "RESOURCEAPI_SCHEMA_VISIBILITY_TIMEOUT";
38
+ function isBlockingResourceApiSchemaSyncStatus(status) {
39
+ if (status === undefined || status === "") {
40
+ return false;
41
+ }
42
+ return !RESOURCEAPI_SCHEMA_SYNC_NON_FAILURE_STATUSES.has(status);
43
+ }
44
+ function optionalString(value) {
45
+ if (typeof value !== "string") {
46
+ return undefined;
47
+ }
48
+ const trimmed = value.trim();
49
+ return trimmed ? trimmed : undefined;
50
+ }
51
+ function firstString(...values) {
52
+ for (const value of values) {
53
+ const result = optionalString(value);
54
+ if (result) {
55
+ return result;
56
+ }
57
+ }
58
+ return undefined;
59
+ }
60
+ function resourceApiSchemaSyncInstallContext(sync) {
61
+ const result = isRecord(sync.result) ? sync.result : {};
62
+ const details = isRecord(sync.details) ? sync.details : {};
63
+ const trustFingerprint = isRecord(sync.installTrustFingerprint)
64
+ ? sync.installTrustFingerprint
65
+ : isRecord(result.installTrustFingerprint)
66
+ ? result.installTrustFingerprint
67
+ : isRecord(details.installTrustFingerprint)
68
+ ? details.installTrustFingerprint
69
+ : {};
70
+ return {
71
+ installId: firstString(trustFingerprint.installId, result.installId, details.installId, sync.installId),
72
+ mode: firstString(trustFingerprint.mode, result.mode, details.mode, sync.mode),
73
+ endpoint: firstString(trustFingerprint.endpoint, result.endpoint, details.endpoint, sync.endpoint),
74
+ tenantId: firstString(sync.tenantId, result.tenantId, details.tenantId),
75
+ };
76
+ }
77
+ export function resourceApiSchemaSyncGuidance(sync) {
78
+ const errorCode = firstString(sync.errorCode, sync.error_code);
79
+ if (errorCode === RESOURCEAPI_SCHEMA_BACKGROUND_APPLY_UNTRUSTED_INSTALL) {
80
+ const { installId, mode, tenantId } = resourceApiSchemaSyncInstallContext(sync);
81
+ const install = installId
82
+ ? `EAI resource runtime install ${installId}`
83
+ : "the selected EAI resource runtime install";
84
+ const modeSentence = mode
85
+ ? ` The tenant metadata currently says mode=${mode}.`
86
+ : "";
87
+ const tenantFlag = tenantId
88
+ ? ` --tenant-id ${tenantId}`
89
+ : " --tenant-id <tenant-id>";
90
+ const installFlag = installId
91
+ ? ` --install-id ${installId}`
92
+ : " --install-id <install-id>";
93
+ return {
94
+ title: "EAI resource schema apply was skipped because the install is not trusted for automatic apply.",
95
+ currentState: "The Object Types were published to platform metadata, but the live EAI resource runtime schema was not refreshed. The runtime can still serve an older schema snapshot, so reads or writes for the new Object Types may fail.",
96
+ reason: `${install} was not accepted as an EAI-hosted install for the background schema apply.${modeSentence} EAI-managed eai-* installs should normally be mode=eai-hosted; customer-hosted-passive is only for an explicit customer-hosted passive install.`,
97
+ fix: "A platform admin needs to repair the tenant resource runtime install metadata so the EAI-managed install is mode=eai-hosted, then re-run the resource schema apply or publish flow.",
98
+ nextSteps: [
99
+ `Check the current schema: eai resources schema${tenantFlag} --format json`,
100
+ `Repair canonical EAI install metadata using platform administration tooling: npx tsx scripts-new/backfill-resourceapi-installs.ts --env <test|prod>${tenantFlag} --execute [--confirm-prod]`,
101
+ `Refresh the EAI resource runtime after the metadata repair: eai provision resourceapi-refresh${tenantFlag}${installFlag} --apply --force-overwrite --reason "Repair EAI resource schema after install mode fix"`,
102
+ "Retry the Object Type publish or seed command and confirm the EAI resource schema includes the new Object Types.",
103
+ ],
104
+ platformActionRequired: true,
105
+ };
106
+ }
107
+ if (errorCode === RESOURCEAPI_SCHEMA_VISIBILITY_TIMEOUT) {
108
+ return {
109
+ title: "EAI resource schema visibility timed out.",
110
+ currentState: "The schema apply was queued or started, but the CLI could not see the requested Object Types through the schema read path before its timeout.",
111
+ reason: "This usually means the background apply is still running, the EAI resource runtime is serving a stale snapshot, or one of the requested Object Types failed to apply.",
112
+ fix: "Check the EAI resource schema/status output and rerun the apply if the Object Types do not appear after the background work settles.",
113
+ nextSteps: [
114
+ "Check schema status: eai resources schema --format json",
115
+ "If the types are still missing, rerun the EAI resource schema apply for the tenant.",
116
+ "If it repeats, inspect platform administration and resource runtime logs for the schema apply request.",
117
+ ],
118
+ platformActionRequired: true,
119
+ };
120
+ }
121
+ return undefined;
122
+ }
123
+ export function enrichResourceApiSchemaSync(sync) {
124
+ if (!sync) {
125
+ return undefined;
126
+ }
127
+ const guidance = resourceApiSchemaSyncGuidance(sync);
128
+ return guidance ? { ...sync, guidance } : sync;
129
+ }
130
+ function readEmbeddedResourceApiSchemaSyncGuidance(value) {
131
+ if (!isRecord(value)) {
132
+ return undefined;
133
+ }
134
+ const nextSteps = readStringArray(value.nextSteps);
135
+ if (typeof value.title !== "string" ||
136
+ typeof value.currentState !== "string" ||
137
+ typeof value.reason !== "string" ||
138
+ typeof value.fix !== "string" ||
139
+ nextSteps.length === 0) {
140
+ return undefined;
141
+ }
142
+ return {
143
+ title: value.title,
144
+ currentState: value.currentState,
145
+ reason: value.reason,
146
+ fix: value.fix,
147
+ nextSteps,
148
+ platformActionRequired: value.platformActionRequired === true,
149
+ };
150
+ }
151
+ function printResourceApiSchemaSyncSummary(resourceApiSchemaSync) {
152
+ if (!resourceApiSchemaSync) {
153
+ return;
154
+ }
155
+ const syncStatus = optionalString(resourceApiSchemaSync.status);
156
+ if (!syncStatus) {
157
+ return;
158
+ }
159
+ const line = `Resource schema sync: ${chalk.cyan(syncStatus)}`;
160
+ if (isBlockingResourceApiSchemaSyncStatus(syncStatus.toLowerCase())) {
161
+ out.warn(line);
162
+ }
163
+ else {
164
+ out.info(line);
165
+ }
166
+ const guidance = readEmbeddedResourceApiSchemaSyncGuidance(resourceApiSchemaSync.guidance) ??
167
+ resourceApiSchemaSyncGuidance(resourceApiSchemaSync);
168
+ if (!guidance) {
169
+ return;
170
+ }
171
+ out.warn(guidance.title);
172
+ out.info(`Current state: ${guidance.currentState}`);
173
+ out.info(`Reason: ${guidance.reason}`);
174
+ out.info(`Fix: ${guidance.fix}`);
175
+ out.info("Next steps:");
176
+ guidance.nextSteps.forEach((step, index) => {
177
+ out.info(`${index + 1}. ${step}`);
178
+ });
179
+ }
180
+ const VALID_STORAGE_BACKENDS = [
181
+ "postgresql",
182
+ "documentdb",
183
+ "blob",
184
+ "search",
185
+ ];
186
+ const VALID_STORAGE_METADATA_STATUSES = ["draft", "ready"];
187
+ export function collectTypeDefaultValueValidationIssues(objectTypes) {
188
+ return Object.entries(objectTypes).flatMap(([tenantKey, types]) => types.flatMap((type) => validateObjectTypeDefaultValues(type).map((issue) => ({
189
+ tenantKey,
190
+ typeName: type.name,
191
+ issue,
192
+ }))));
193
+ }
194
+ function hasStorageValue(value) {
195
+ return value !== null && value !== undefined && value !== "";
196
+ }
197
+ function getStorageBindingScope(binding, key) {
198
+ if (!isRecord(binding)) {
199
+ return null;
200
+ }
201
+ const scope = binding[key];
202
+ return isRecord(scope) ? scope : null;
203
+ }
204
+ function collectMissingStorageFields(scope, fields) {
205
+ return fields.filter((field) => !hasStorageValue(scope?.[field]));
206
+ }
207
+ function formatStorageFieldIssue(label, missing) {
208
+ return `${label} is incomplete. Missing: ${missing.join(", ")}`;
209
+ }
210
+ export function validateObjectTypeStorageMetadata(type) {
211
+ const issues = [];
212
+ const backend = type.storageBackend || "postgresql";
213
+ const storageMetadataStatus = type.storageMetadataStatus || "draft";
214
+ if (!VALID_STORAGE_BACKENDS.includes(backend)) {
215
+ issues.push(`storageBackend "${backend}" must be one of: ${VALID_STORAGE_BACKENDS.join(", ")}`);
216
+ }
217
+ if (!VALID_STORAGE_METADATA_STATUSES.includes(storageMetadataStatus)) {
218
+ issues.push(`storageMetadataStatus "${storageMetadataStatus}" must be one of: ${VALID_STORAGE_METADATA_STATUSES.join(", ")}`);
219
+ }
220
+ if (type.status === "published" && storageMetadataStatus !== "ready") {
221
+ issues.push('published Object Types require storageMetadataStatus "ready"');
222
+ }
223
+ if (storageMetadataStatus !== "ready" ||
224
+ !VALID_STORAGE_BACKENDS.includes(backend)) {
225
+ return issues;
226
+ }
227
+ if (!isRecord(type.storageBinding)) {
228
+ issues.push('storageMetadataStatus "ready" requires storageBinding');
229
+ return issues;
230
+ }
231
+ if (backend === "postgresql") {
232
+ const missing = collectMissingStorageFields(getStorageBindingScope(type.storageBinding, "sql"), ["databaseAlias", "tenantSchemaStrategy", "tableName"]);
233
+ if (missing.length > 0) {
234
+ issues.push(formatStorageFieldIssue("PostgreSQL storageBinding", missing));
235
+ }
236
+ }
237
+ else if (backend === "documentdb") {
238
+ const missing = collectMissingStorageFields(getStorageBindingScope(type.storageBinding, "documentdb"), ["databaseAlias", "databaseName", "collectionName", "partitionKey"]);
239
+ if (missing.length > 0) {
240
+ issues.push(formatStorageFieldIssue("DocumentDB storageBinding", missing));
241
+ }
242
+ }
243
+ else if (backend === "blob") {
244
+ const missing = collectMissingStorageFields(getStorageBindingScope(type.storageBinding, "blob"), ["storageAccountAlias", "containerName"]);
245
+ if (missing.length > 0) {
246
+ issues.push(formatStorageFieldIssue("Blob storageBinding", missing));
247
+ }
248
+ }
249
+ else if (backend === "search") {
250
+ const missing = collectMissingStorageFields(getStorageBindingScope(type.storageBinding, "search"), ["searchServiceAlias"]);
251
+ if (missing.length > 0) {
252
+ issues.push(formatStorageFieldIssue("Search storageBinding", missing));
253
+ }
254
+ }
255
+ return issues;
256
+ }
257
+ export function collectTypeStorageValidationIssues(objectTypes) {
258
+ return Object.entries(objectTypes).flatMap(([tenantKey, types]) => types.flatMap((type) => validateObjectTypeStorageMetadata(type).map((issue) => ({
259
+ tenantKey,
260
+ typeName: type.name,
261
+ issue,
262
+ }))));
263
+ }
264
+ export function resolveTenantIdForKey(tenantKey, explicitTenantId, activeTenantId) {
265
+ if (explicitTenantId) {
266
+ return { tenantId: explicitTenantId, source: "option" };
267
+ }
268
+ if (activeTenantId) {
269
+ return { tenantId: activeTenantId, source: "active:tenant" };
270
+ }
271
+ return { source: "unresolved" };
272
+ }
273
+ function describeTenantResolutionSource(source) {
274
+ switch (source) {
275
+ case "option":
276
+ return "CLI override";
277
+ case "active:tenant":
278
+ return "active tenant";
279
+ default:
280
+ return "unresolved";
281
+ }
282
+ }
283
+ function explainMissingTenantId(tenantKey) {
284
+ out.warn(`No active tenant is available for "${tenantKey}"`);
285
+ out.info(`Run ${chalk.cyan("eai login")} and ${chalk.cyan("eai tenant select")} to choose the tenant to work with, or use ${chalk.cyan(`--tenant-key ${tenantKey} --tenant-id <uuid>`)}`);
286
+ }
287
+ export function resolveDefaultTenantKey(objectTypes, activeTenantSlug) {
288
+ const keys = Object.keys(objectTypes);
289
+ if (keys.length === 1) {
290
+ return keys[0];
291
+ }
292
+ if (activeTenantSlug && objectTypes[activeTenantSlug]) {
293
+ return activeTenantSlug;
294
+ }
295
+ if (objectTypes.template) {
296
+ return "template";
297
+ }
298
+ if (objectTypes.default) {
299
+ return "default";
300
+ }
301
+ return null;
302
+ }
303
+ function toTimestamp(value) {
304
+ if (!value) {
305
+ return 0;
306
+ }
307
+ const parsed = Date.parse(value);
308
+ return Number.isNaN(parsed) ? 0 : parsed;
309
+ }
310
+ function compareRemoteDocs(a, b) {
311
+ const publishedDelta = toTimestamp(b.publishedAt) - toTimestamp(a.publishedAt);
312
+ if (publishedDelta !== 0) {
313
+ return publishedDelta;
314
+ }
315
+ const aSlug = typeof a.slug === "string" ? a.slug : toObjectTypeSlug(a.name);
316
+ const bSlug = typeof b.slug === "string" ? b.slug : toObjectTypeSlug(b.name);
317
+ return aSlug.localeCompare(bSlug) || a.name.localeCompare(b.name);
318
+ }
319
+ function matchesRequestedType(doc, requestedType) {
320
+ const requestedSlug = toObjectTypeSlug(requestedType);
321
+ return (doc.name === requestedType ||
322
+ doc.slug === requestedSlug ||
323
+ toObjectTypeSlug(doc.name) === requestedSlug);
324
+ }
325
+ export function findMatchingRemoteTypes(remoteDocs, requestedType) {
326
+ return remoteDocs
327
+ .filter((doc) => matchesRequestedType(doc, requestedType))
328
+ .sort(compareRemoteDocs);
329
+ }
330
+ function dedupeRemoteObjectTypeDocs(remoteDocs) {
331
+ const bySlug = new Map();
332
+ for (const doc of remoteDocs) {
333
+ const slug = typeof doc.slug === "string" ? doc.slug : toObjectTypeSlug(doc.name);
334
+ const existing = bySlug.get(slug);
335
+ if (!existing || compareRemoteDocs(doc, existing) < 0) {
336
+ bySlug.set(slug, doc);
337
+ }
338
+ }
339
+ return Array.from(bySlug.values()).sort(compareRemoteDocs);
340
+ }
341
+ function extractRemoteTypeState(payload) {
342
+ const published = new Set();
343
+ const available = new Set();
344
+ const mark = (value, isPublished) => {
345
+ if (!isRecord(value) || typeof value.name !== "string") {
346
+ return;
347
+ }
348
+ const slug = typeof value.slug === "string"
349
+ ? value.slug
350
+ : toObjectTypeSlug(value.name);
351
+ available.add(slug);
352
+ if (isPublished) {
353
+ published.add(slug);
354
+ }
355
+ };
356
+ if (isRecord(payload) && Array.isArray(payload.objectTypes)) {
357
+ payload.objectTypes.forEach((value) => mark(value, true));
358
+ return { published, available };
359
+ }
360
+ if (isRecord(payload) && Array.isArray(payload.object_types)) {
361
+ payload.object_types.forEach((value) => mark(value, true));
362
+ return { published, available };
363
+ }
364
+ if (isRecord(payload) && Array.isArray(payload.objectTypeSlugs)) {
365
+ payload.objectTypeSlugs.forEach((value) => {
366
+ if (typeof value !== "string" || !value.trim()) {
367
+ return;
368
+ }
369
+ available.add(toObjectTypeSlug(value));
370
+ published.add(toObjectTypeSlug(value));
371
+ });
372
+ return { published, available };
373
+ }
374
+ if (isRecord(payload) && Array.isArray(payload.docs)) {
375
+ dedupeRemoteObjectTypeDocs(extractRemoteObjectTypeDocs(payload)).forEach((value) => {
376
+ const publishedState = value.status === "published" ||
377
+ (value.publishedAt !== null && value.publishedAt !== undefined);
378
+ mark(value, publishedState);
379
+ });
380
+ }
381
+ return { published, available };
382
+ }
383
+ function extractRemoteObjectTypeDocs(payload) {
384
+ if (!isRecord(payload) || !Array.isArray(payload.docs)) {
385
+ return [];
386
+ }
387
+ return payload.docs
388
+ .filter((value) => isRecord(value) && typeof value.name === "string")
389
+ .map((value) => ({
390
+ id: typeof value.id === "string" ? value.id : undefined,
391
+ name: value.name,
392
+ slug: typeof value.slug === "string" ? value.slug : undefined,
393
+ properties: Array.isArray(value.properties) ? value.properties : [],
394
+ linkTypes: Array.isArray(value.linkTypes) ? value.linkTypes : [],
395
+ actions: Array.isArray(value.actions) ? value.actions : [],
396
+ storageBackend: typeof value.storageBackend === "string"
397
+ ? value.storageBackend
398
+ : undefined,
399
+ schemaVersion: typeof value.schemaVersion === "number"
400
+ ? value.schemaVersion
401
+ : undefined,
402
+ storageMetadataStatus: typeof value.storageMetadataStatus === "string"
403
+ ? value.storageMetadataStatus
404
+ : undefined,
405
+ storageBinding: isRecord(value.storageBinding)
406
+ ? value.storageBinding
407
+ : undefined,
408
+ provisioningHints: isRecord(value.provisioningHints)
409
+ ? value.provisioningHints
410
+ : undefined,
411
+ status: typeof value.status === "string" ? value.status : undefined,
412
+ publishedAt: typeof value.publishedAt === "string" ? value.publishedAt : null,
413
+ }))
414
+ .sort(compareRemoteDocs);
415
+ }
416
+ function findMatchingRemoteType(remoteDocs, requestedType) {
417
+ return findMatchingRemoteTypes(remoteDocs, requestedType)[0];
418
+ }
419
+ function propertyNames(properties) {
420
+ return properties
421
+ .map((property) => isRecord(property) && typeof property.name === "string"
422
+ ? property.name
423
+ : null)
424
+ .filter((name) => Boolean(name));
425
+ }
426
+ function diffEntry(name, slug, addedProperties = [], removedProperties = [], unchangedProperties = []) {
427
+ return {
428
+ name,
429
+ ...(slug ? { slug } : {}),
430
+ addedProperties,
431
+ removedProperties,
432
+ unchangedProperties,
433
+ };
434
+ }
435
+ export function diffObjectTypesForTenant(tenantKey, tenantId, resolutionSource, localTypes, remoteDocs) {
436
+ const matchedRemoteNames = new Set();
437
+ const result = {
438
+ tenantKey,
439
+ tenantId,
440
+ resolutionSource,
441
+ localCount: localTypes.length,
442
+ remoteCount: remoteDocs.length,
443
+ localOnly: [],
444
+ remoteOnly: [],
445
+ changed: [],
446
+ unchanged: [],
447
+ };
448
+ for (const localType of localTypes) {
449
+ const remote = findMatchingRemoteType(remoteDocs, localType.name);
450
+ if (!remote) {
451
+ result.localOnly.push(diffEntry(localType.name, toObjectTypeSlug(localType.name)));
452
+ continue;
453
+ }
454
+ matchedRemoteNames.add(remote.name);
455
+ const localPropNames = new Set(localType.properties.map((p) => p.name));
456
+ const remotePropNames = new Set(propertyNames(remote.properties));
457
+ const addedProperties = [...localPropNames].filter((property) => !remotePropNames.has(property));
458
+ const removedProperties = [...remotePropNames].filter((property) => !localPropNames.has(property));
459
+ const unchangedProperties = [...localPropNames].filter((property) => remotePropNames.has(property));
460
+ const entry = diffEntry(localType.name, remote.slug ?? toObjectTypeSlug(localType.name), addedProperties, removedProperties, unchangedProperties);
461
+ if (addedProperties.length === 0 && removedProperties.length === 0) {
462
+ result.unchanged.push(entry);
463
+ }
464
+ else {
465
+ result.changed.push(entry);
466
+ }
467
+ }
468
+ for (const remote of remoteDocs) {
469
+ if (!matchedRemoteNames.has(remote.name)) {
470
+ result.remoteOnly.push(diffEntry(remote.name, remote.slug ?? toObjectTypeSlug(remote.name)));
471
+ }
472
+ }
473
+ return result;
474
+ }
475
+ export async function resolveTypesPullOutputPath(root, output) {
476
+ const { isAbsolute, join: pathJoin } = await import("node:path");
477
+ return isAbsolute(output) ? output : pathJoin(root, output);
478
+ }
479
+ export async function describeFailedPlatformResponse(response) {
480
+ const context = await extractServerErrorContext(response);
481
+ const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
482
+ // String() guards against a non-string slipping through (defense in depth;
483
+ // extractServerErrorContext already coerces, but this line must never throw).
484
+ const detail = String(context.serverMessage ?? context.rawBody ?? "").trim();
485
+ if (!detail) {
486
+ return status;
487
+ }
488
+ const truncatedDetail = detail.length > 500 ? `${detail.slice(0, 497)}...` : detail;
489
+ const code = context.serverCode ? `[${context.serverCode}] ` : "";
490
+ const requestId = context.requestId ? ` (request ${context.requestId})` : "";
491
+ return `${status} - ${code}${truncatedDetail}${requestId}`;
492
+ }
493
+ async function archiveDuplicateRemoteTypes(client, duplicates) {
494
+ let archived = 0;
495
+ for (const duplicate of duplicates) {
496
+ if (!duplicate.id) {
497
+ continue;
498
+ }
499
+ const response = await client.updateObjectType(duplicate.id, {
500
+ status: "draft",
501
+ });
502
+ if (!response.ok) {
503
+ throw new Error(`archive failed: ${await describeFailedPlatformResponse(response)}`);
504
+ }
505
+ archived++;
506
+ }
507
+ return archived;
508
+ }
509
+ export async function appObjectTypePublishFallbackReason(response, phase) {
510
+ if (response.status === 405) {
511
+ return `app object-type manifest ${phase} route unavailable`;
512
+ }
513
+ // Newer platforms expose the manifest route but return 404 "App was not found
514
+ // for this company" when the tenant has no app enrollment for this vertical
515
+ // (e.g. a freshly created tenant seeded straight from the repo). That is not a
516
+ // hard failure — fall back to direct (tenant-scoped) Object Type writes, the
517
+ // same behaviour older platforms gave via 405. Body-gated so genuine
518
+ // route/resource 404s still surface.
519
+ if (response.status === 404) {
520
+ let body;
521
+ try {
522
+ body = await response.clone().text();
523
+ }
524
+ catch {
525
+ body = "";
526
+ }
527
+ if (/app was not found|not found for this company/i.test(body)) {
528
+ return `app object-type manifest ${phase} route unavailable (tenant has no app enrollment)`;
529
+ }
530
+ }
531
+ return null;
532
+ }
533
+ export function toAppManifestObjectTypes(types) {
534
+ return types.map((type) => ({
535
+ ...type,
536
+ status: type.status ?? "published",
537
+ }));
538
+ }
539
+ function readStringArray(value) {
540
+ return Array.isArray(value)
541
+ ? value.filter((item) => typeof item === "string")
542
+ : [];
543
+ }
544
+ function readTypeSeedVerification(tenantId, requestedTypes, value, counts) {
545
+ if (!isRecord(value)) {
546
+ return {
547
+ tenantId,
548
+ requestedTypes,
549
+ matchedTypes: [],
550
+ missingTypes: requestedTypes,
551
+ driftedTypes: [],
552
+ ...counts,
553
+ converged: false,
554
+ };
555
+ }
556
+ return {
557
+ tenantId: typeof value.tenantId === "string" ? value.tenantId : tenantId,
558
+ requestedTypes: readStringArray(value.requestedTypes),
559
+ matchedTypes: readStringArray(value.matchedTypes),
560
+ missingTypes: readStringArray(value.missingTypes),
561
+ driftedTypes: readStringArray(value.driftedTypes),
562
+ createdCount: typeof value.createdCount === "number"
563
+ ? value.createdCount
564
+ : counts.createdCount,
565
+ updatedCount: typeof value.updatedCount === "number"
566
+ ? value.updatedCount
567
+ : counts.updatedCount,
568
+ failedCount: typeof value.failedCount === "number"
569
+ ? value.failedCount
570
+ : counts.failedCount,
571
+ converged: value.converged === true,
572
+ };
573
+ }
574
+ export function summarizeAppObjectTypePublish(tenantKey, tenantId, types, payload) {
575
+ const body = isRecord(payload) ? payload : {};
576
+ const results = Array.isArray(body.results)
577
+ ? body.results.filter(isRecord)
578
+ : [];
579
+ const created = results.filter((result) => result.status === "created").length;
580
+ const updated = results.filter((result) => result.status === "updated").length;
581
+ const failed = results.filter((result) => result.status === "failed").length;
582
+ const counts = {
583
+ createdCount: created,
584
+ updatedCount: updated,
585
+ failedCount: failed,
586
+ };
587
+ return {
588
+ tenantKey,
589
+ tenantId,
590
+ created,
591
+ updated,
592
+ failed,
593
+ verification: readTypeSeedVerification(tenantId, types.map((type) => type.name), body.verification, counts),
594
+ publishingMode: "app-manifest",
595
+ resourceApiSchemaSync: isRecord(body.resourceApiSchemaSync)
596
+ ? enrichResourceApiSchemaSync(body.resourceApiSchemaSync)
597
+ : undefined,
598
+ };
599
+ }
600
+ export async function trySeedViaAppManifestPublish(client, tenantKey, tenantId, types) {
601
+ const manifestResponse = await client.saveAppObjectTypeManifest(tenantKey, toAppManifestObjectTypes(types));
602
+ const manifestFallbackReason = await appObjectTypePublishFallbackReason(manifestResponse, "save");
603
+ if (manifestFallbackReason) {
604
+ return { fallbackReason: manifestFallbackReason };
605
+ }
606
+ if (!manifestResponse.ok) {
607
+ throw new Error(`app manifest save failed: ${await describeFailedPlatformResponse(manifestResponse)}`);
608
+ }
609
+ const publishResponse = await client.publishAppObjectTypes(tenantKey);
610
+ const publishFallbackReason = await appObjectTypePublishFallbackReason(publishResponse, "publish");
611
+ if (publishFallbackReason) {
612
+ return { fallbackReason: publishFallbackReason };
613
+ }
614
+ if (!publishResponse.ok) {
615
+ throw new Error(`app manifest publish failed: ${await describeFailedPlatformResponse(publishResponse)}`);
616
+ }
617
+ const result = summarizeAppObjectTypePublish(tenantKey, tenantId, types, await publishResponse.json());
618
+ return { result };
619
+ }
620
+ const RESOURCEAPI_SYNC_SUCCESS_STATUSES = new Set([
621
+ "applied",
622
+ "already_applied",
623
+ "planned",
624
+ "provisioned",
625
+ "synced",
626
+ ]);
627
+ function syncResultObjectTypeSlug(result) {
628
+ return typeof result.objectType === "string" && result.objectType
629
+ ? toObjectTypeSlug(result.objectType)
630
+ : null;
631
+ }
632
+ export async function summarizeResourceApiSchemaSync(response, requestedObjectTypes = []) {
633
+ if (!response.ok) {
634
+ return {
635
+ status: "failed",
636
+ error: await describeFailedPlatformResponse(response),
637
+ };
638
+ }
639
+ const payload = (await response.json());
640
+ const results = isRecord(payload) && Array.isArray(payload.results)
641
+ ? payload.results.filter(isRecord)
642
+ : [];
643
+ const requestedSlugs = new Set(requestedObjectTypes.map((objectType) => toObjectTypeSlug(objectType)));
644
+ const successfulResultSlugs = new Set(results
645
+ .filter((result) => typeof result.status === "string" &&
646
+ RESOURCEAPI_SYNC_SUCCESS_STATUSES.has(result.status))
647
+ .map(syncResultObjectTypeSlug)
648
+ .filter((slug) => typeof slug === "string"));
649
+ const missingObjectTypes = [...requestedSlugs].filter((slug) => !successfulResultSlugs.has(slug));
650
+ const failedResults = results.filter((result) => result.status === "failed");
651
+ const skippedRequestedResults = results.filter((result) => {
652
+ const slug = syncResultObjectTypeSlug(result);
653
+ return (slug !== null &&
654
+ requestedSlugs.has(slug) &&
655
+ !RESOURCEAPI_SYNC_SUCCESS_STATUSES.has(String(result.status ?? "")));
656
+ });
657
+ const failed = results.length === 0 ||
658
+ failedResults.length > 0 ||
659
+ missingObjectTypes.length > 0 ||
660
+ skippedRequestedResults.length > 0;
661
+ // Redact secrets (connection strings, credential-bearing details.issues/
662
+ // reason/error) that resource-store failed results can surface before they land
663
+ // in CLI JSON output, logs, or release evidence. The AdminAPI manifest path
664
+ // already sanitizes this shape; this hardens the direct fallback path too.
665
+ return enrichResourceApiSchemaSync({
666
+ ...(isRecord(payload) ? out.redactSensitiveDeep(payload) : {}),
667
+ ...(missingObjectTypes.length > 0 ? { missingObjectTypes } : {}),
668
+ status: failed ? "failed" : "synced",
669
+ });
670
+ }
671
+ export function verifyTypeSeedConvergence(tenantId, requestedTypes, payload, counts) {
672
+ const remote = extractRemoteTypeState(payload);
673
+ const matchedTypes = [];
674
+ const missingTypes = [];
675
+ const driftedTypes = [];
676
+ for (const requestedType of requestedTypes) {
677
+ const slug = toObjectTypeSlug(requestedType);
678
+ if (remote.published.has(slug)) {
679
+ matchedTypes.push(requestedType);
680
+ }
681
+ else if (remote.available.has(slug)) {
682
+ driftedTypes.push(requestedType);
683
+ }
684
+ else {
685
+ missingTypes.push(requestedType);
686
+ }
687
+ }
688
+ return {
689
+ tenantId,
690
+ requestedTypes,
691
+ matchedTypes,
692
+ missingTypes,
693
+ driftedTypes,
694
+ createdCount: counts.createdCount,
695
+ updatedCount: counts.updatedCount,
696
+ failedCount: counts.failedCount,
697
+ converged: counts.failedCount === 0 &&
698
+ missingTypes.length === 0 &&
699
+ driftedTypes.length === 0,
700
+ };
701
+ }
702
+ export async function verifyTypeSeedConvergenceWithRetry(client, tenantId, requestedTypes, counts, options) {
703
+ const attempts = Math.max(options?.attempts ?? 60, 1);
704
+ const delayMs = Math.max(options?.delayMs ?? 1000, 0);
705
+ let lastVerification = null;
706
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
707
+ if (typeof client.getPublishedObjectTypes === "function") {
708
+ const publishedResponse = await client.getPublishedObjectTypes({
709
+ limit: Math.max(requestedTypes.length, 20),
710
+ });
711
+ if (!publishedResponse.ok) {
712
+ throw new Error(`published type re-fetch failed: ${publishedResponse.status} ${publishedResponse.statusText}`);
713
+ }
714
+ const publishedPayload = (await publishedResponse.json());
715
+ let publishedVerification = verifyTypeSeedConvergence(tenantId, requestedTypes, publishedPayload, counts);
716
+ if (!publishedVerification.converged &&
717
+ publishedVerification.failedCount === 0) {
718
+ const preciseDocs = [];
719
+ for (const requestedType of requestedTypes) {
720
+ const preciseResponse = await client.getPublishedObjectTypes({
721
+ name: requestedType,
722
+ limit: 10,
723
+ });
724
+ if (!preciseResponse.ok) {
725
+ throw new Error(`published type re-fetch failed for ${requestedType}: ${preciseResponse.status} ${preciseResponse.statusText}`);
726
+ }
727
+ preciseDocs.push(...extractRemoteObjectTypeDocs((await preciseResponse.json())));
728
+ }
729
+ const preciseVerification = verifyTypeSeedConvergence(tenantId, requestedTypes, { docs: preciseDocs }, counts);
730
+ if (preciseVerification.converged ||
731
+ preciseVerification.matchedTypes.length >
732
+ publishedVerification.matchedTypes.length) {
733
+ publishedVerification = preciseVerification;
734
+ }
735
+ }
736
+ lastVerification = publishedVerification;
737
+ if (publishedVerification.converged ||
738
+ publishedVerification.failedCount > 0) {
739
+ return publishedVerification;
740
+ }
741
+ if (attempt < attempts) {
742
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
743
+ continue;
744
+ }
745
+ }
746
+ const schemaResponse = await client.getSchema();
747
+ if (!schemaResponse.ok) {
748
+ throw new Error(`schema re-fetch failed: ${schemaResponse.status} ${schemaResponse.statusText}`);
749
+ }
750
+ const schemaPayload = (await schemaResponse.json());
751
+ const verification = verifyTypeSeedConvergence(tenantId, requestedTypes, schemaPayload, counts);
752
+ lastVerification = verification;
753
+ if (verification.converged ||
754
+ verification.failedCount > 0 ||
755
+ attempt === attempts) {
756
+ return verification;
757
+ }
758
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
759
+ }
760
+ if (lastVerification) {
761
+ return lastVerification;
762
+ }
763
+ throw new Error("schema verification did not produce a result");
764
+ }
765
+ export async function waitForResourceApiSchemaVisibility(client, tenantId, requestedTypes, resourceApiSchemaSync, options) {
766
+ const status = isRecord(resourceApiSchemaSync)
767
+ ? String(resourceApiSchemaSync.status ?? "").toLowerCase()
768
+ : "";
769
+ if (!RESOURCEAPI_SCHEMA_SYNC_ASYNC_STATUSES.has(status)) {
770
+ return resourceApiSchemaSync;
771
+ }
772
+ const attempts = Math.max(options?.attempts ?? 45, 1);
773
+ const delayMs = Math.max(options?.delayMs ?? 1000, 0);
774
+ let lastVerification;
775
+ let lastError;
776
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
777
+ try {
778
+ const schemaStatusResponse = await client.getResourceStorageSchemaStatus();
779
+ if (schemaStatusResponse.ok) {
780
+ const verification = verifyTypeSeedConvergence(tenantId, requestedTypes, (await schemaStatusResponse.json()), {
781
+ createdCount: 0,
782
+ updatedCount: 0,
783
+ failedCount: 0,
784
+ });
785
+ lastVerification = verification;
786
+ if (verification.converged) {
787
+ return {
788
+ ...resourceApiSchemaSync,
789
+ status: "synced",
790
+ schemaVisibility: "visible",
791
+ schemaVisibilitySource: "storage.schema-status",
792
+ };
793
+ }
794
+ }
795
+ else {
796
+ lastError = `schema-status re-fetch failed: ${schemaStatusResponse.status} ${schemaStatusResponse.statusText}`;
797
+ }
798
+ const schemaResponse = await client.getSchema();
799
+ if (!schemaResponse.ok) {
800
+ lastError = `schema re-fetch failed: ${schemaResponse.status} ${schemaResponse.statusText}`;
801
+ }
802
+ else {
803
+ const verification = verifyTypeSeedConvergence(tenantId, requestedTypes, (await schemaResponse.json()), {
804
+ createdCount: 0,
805
+ updatedCount: 0,
806
+ failedCount: 0,
807
+ });
808
+ lastVerification = verification;
809
+ if (verification.converged) {
810
+ return {
811
+ ...resourceApiSchemaSync,
812
+ status: "synced",
813
+ schemaVisibility: "visible",
814
+ };
815
+ }
816
+ }
817
+ }
818
+ catch (err) {
819
+ lastError = err instanceof Error ? err.message : String(err);
820
+ }
821
+ if (attempt < attempts) {
822
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
823
+ }
824
+ }
825
+ return enrichResourceApiSchemaSync({
826
+ ...resourceApiSchemaSync,
827
+ status: "failed",
828
+ errorCode: RESOURCEAPI_SCHEMA_VISIBILITY_TIMEOUT,
829
+ message: "Platform schema sync was queued, but requested Object Types were not visible from the platform schema read path before the CLI timeout.",
830
+ details: {
831
+ requestedTypes,
832
+ ...(lastVerification
833
+ ? {
834
+ matchedTypes: lastVerification.matchedTypes,
835
+ missingTypes: lastVerification.missingTypes,
836
+ driftedTypes: lastVerification.driftedTypes,
837
+ }
838
+ : {}),
839
+ ...(lastError ? { lastError } : {}),
840
+ },
841
+ });
842
+ }
843
+ async function selectTenantKey(objectTypes, explicitTenantKey, activeTenantSlug) {
844
+ if (explicitTenantKey) {
845
+ return [explicitTenantKey];
846
+ }
847
+ const defaultKey = resolveDefaultTenantKey(objectTypes, activeTenantSlug);
848
+ if (defaultKey) {
849
+ return [defaultKey];
850
+ }
851
+ const keys = Object.keys(objectTypes);
852
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
853
+ exitWithError(ErrorCode.E303, { field: "--tenant-key" });
854
+ }
855
+ const { tenantKey } = await inquirer.prompt([
856
+ {
857
+ type: "select",
858
+ name: "tenantKey",
859
+ message: "Select the local object-type scope to publish or diff",
860
+ choices: keys.map((key) => ({
861
+ name: key,
862
+ value: key,
863
+ })),
864
+ },
865
+ ]);
866
+ return [tenantKey];
867
+ }
868
+ export const typesCommand = new Command("types")
869
+ .description("Manage Object Type definitions")
870
+ .addHelpText("after", `
871
+ Workflow:
872
+ 1. Validate local definitions:
873
+ eai types validate
874
+ 2. Login and select the active tenant:
875
+ eai login
876
+ eai tenant select
877
+ 3. Preview remote differences:
878
+ eai types diff --tenant-key <key>
879
+ 4. Publish:
880
+ eai types seed --tenant-key <key>
881
+ 5. Verify published schema:
882
+ eai resources schema
883
+ `);
884
+ // ─── eai types seed ────────────────────────────────────────────────────────
885
+ typesCommand
886
+ .command("seed")
887
+ .description("Push Object Types to platform")
888
+ .option("--env <label>", "Optional deployment label for compatibility")
889
+ .option("--tenant-key <key>", "Specific tenant key from object-types.ts")
890
+ .option("--tenant-id <id>", "Override the resolved tenant ID (use with --tenant-key)")
891
+ .option("--dry-run", "Show what would be seeded without making changes", false)
892
+ .option("--format <format>", "Output format (text|json)", "text")
893
+ .option("--json", "Output raw JSON (deprecated, use --format json)", false)
894
+ .addHelpText("after", `
895
+ Examples:
896
+ $ eai types seed
897
+ $ eai types seed --dry-run
898
+ $ eai types seed --tenant-key trial-portal
899
+ $ eai types seed --tenant-key template --tenant-id 00000000-0000-4000-8000-000000000000
900
+ $ eai types seed --format json | jq
901
+ `)
902
+ .action(async (options) => {
903
+ // Backward compatibility: --json maps to --format json
904
+ if (options.json) {
905
+ options.format = "json";
906
+ }
907
+ const ctx = await resolveCommandContext({ tenantId: options.tenantId });
908
+ const { root, publicApiUrl, activeTenant: activeContextTenant } = ctx;
909
+ // Wrap in shape expected by downstream helpers
910
+ const activeContext = { activeTenant: activeContextTenant };
911
+ const spinner = options.format === "json" ? null : ora("Loading Object Types...").start();
912
+ let objectTypes;
913
+ try {
914
+ objectTypes = await loadObjectTypes(root);
915
+ const totalTypes = Object.values(objectTypes).reduce((sum, types) => sum + types.length, 0);
916
+ const tenantKeys = Object.keys(objectTypes);
917
+ if (spinner) {
918
+ spinner.succeed(`Found ${totalTypes} types across ${tenantKeys.length} tenant scope(s): ${tenantKeys.join(", ")}`);
919
+ }
920
+ }
921
+ catch (err) {
922
+ if (spinner)
923
+ spinner.fail("Failed to load Object Types");
924
+ out.error(err instanceof Error ? err.message : String(err));
925
+ process.exit(1);
926
+ }
927
+ if (options.tenantId &&
928
+ !options.tenantKey &&
929
+ Object.keys(objectTypes).length > 1) {
930
+ exitWithError(ErrorCode.E303, {
931
+ field: "--tenant-key when using --tenant-id with multiple tenant scopes",
932
+ }, options.format);
933
+ }
934
+ const defaultValueIssues = collectTypeDefaultValueValidationIssues(objectTypes);
935
+ if (defaultValueIssues.length > 0) {
936
+ if (options.format === "json") {
937
+ out.json({
938
+ error: "Object Type defaultValue validation failed",
939
+ issues: defaultValueIssues,
940
+ });
941
+ }
942
+ else {
943
+ out.error("Object Type defaultValue validation failed");
944
+ for (const issue of defaultValueIssues) {
945
+ out.error(` [${issue.tenantKey}/${issue.typeName}] ${issue.issue}`);
946
+ }
947
+ }
948
+ process.exit(1);
949
+ }
950
+ const storageIssues = collectTypeStorageValidationIssues(objectTypes);
951
+ if (storageIssues.length > 0) {
952
+ if (options.format === "json") {
953
+ out.json({
954
+ error: "Object Type storage metadata validation failed",
955
+ issues: storageIssues,
956
+ });
957
+ }
958
+ else {
959
+ out.error("Object Type storage metadata validation failed");
960
+ for (const issue of storageIssues) {
961
+ out.error(` [${issue.tenantKey}/${issue.typeName}] ${issue.issue}`);
962
+ }
963
+ }
964
+ process.exit(1);
965
+ }
966
+ // Filter to specific tenant key if requested
967
+ const keysToSeed = await selectTenantKey(objectTypes, options.tenantKey, activeContext.activeTenant.slug);
968
+ if (options.format !== "json") {
969
+ out.blank();
970
+ }
971
+ const jsonResults = [];
972
+ for (const tenantKey of keysToSeed) {
973
+ const types = objectTypes[tenantKey];
974
+ if (!types || types.length === 0) {
975
+ if (options.format !== "json") {
976
+ out.warn(`No types for tenant key "${tenantKey}"`);
977
+ }
978
+ continue;
979
+ }
980
+ // Resolve tenant ID
981
+ const resolution = resolveTenantIdForKey(tenantKey, options.tenantId, activeContext.activeTenant.id);
982
+ const tenantId = resolution.tenantId;
983
+ if (!tenantId) {
984
+ explainMissingTenantId(tenantKey);
985
+ continue;
986
+ }
987
+ if (options.format !== "json") {
988
+ out.heading(`Tenant: ${tenantKey} → ${chalk.dim(tenantId)} ${chalk.dim(`(${describeTenantResolutionSource(resolution.source)})`)}`);
989
+ }
990
+ if (options.dryRun) {
991
+ if (options.format !== "json") {
992
+ for (const type of types) {
993
+ out.info(`Would publish: ${chalk.cyan(type.name)}`);
994
+ }
995
+ out.info("Dry run — no changes made");
996
+ }
997
+ continue;
998
+ }
999
+ const client = new PlatformAPIClient(publicApiUrl, tenantId);
1000
+ let created = 0, updated = 0, failed = 0;
1001
+ let remoteDocs = [];
1002
+ let appManifestFallbackReason;
1003
+ try {
1004
+ const appPublishOutcome = await trySeedViaAppManifestPublish(client, tenantKey, tenantId, types);
1005
+ if (appPublishOutcome.result) {
1006
+ appPublishOutcome.result.resourceApiSchemaSync =
1007
+ await waitForResourceApiSchemaVisibility(client, tenantId, types.map((type) => type.name), appPublishOutcome.result.resourceApiSchemaSync);
1008
+ if (options.format !== "json") {
1009
+ out.success("Published via app object-type manifest");
1010
+ out.info(`Result: ${chalk.green(`${appPublishOutcome.result.created} created`)}, ${chalk.cyan(`${appPublishOutcome.result.updated} updated`)}, ${chalk.red(`${appPublishOutcome.result.failed} failed`)}`);
1011
+ const verification = appPublishOutcome.result.verification;
1012
+ if (verification?.converged) {
1013
+ out.success(`Verification: converged (${verification.matchedTypes.length}/${verification.requestedTypes.length} published remotely)`);
1014
+ }
1015
+ else if (verification) {
1016
+ const issues = [
1017
+ verification.missingTypes.length > 0
1018
+ ? `${verification.missingTypes.length} missing`
1019
+ : null,
1020
+ verification.driftedTypes.length > 0
1021
+ ? `${verification.driftedTypes.length} drifted`
1022
+ : null,
1023
+ verification.failedCount > 0
1024
+ ? `${verification.failedCount} failed writes`
1025
+ : null,
1026
+ ]
1027
+ .filter(Boolean)
1028
+ .join(", ");
1029
+ out.warn(`Verification: partial (${issues || "remote schema did not converge"})`);
1030
+ }
1031
+ printResourceApiSchemaSyncSummary(appPublishOutcome.result.resourceApiSchemaSync);
1032
+ out.blank();
1033
+ }
1034
+ jsonResults.push(appPublishOutcome.result);
1035
+ continue;
1036
+ }
1037
+ appManifestFallbackReason = appPublishOutcome.fallbackReason;
1038
+ if (options.format !== "json") {
1039
+ out.warn(`${appManifestFallbackReason ?? "App manifest publish unavailable"}; falling back to direct Object Type writes.`);
1040
+ }
1041
+ }
1042
+ catch (err) {
1043
+ const message = err instanceof Error ? err.message : String(err);
1044
+ if (options.format !== "json") {
1045
+ out.error(message);
1046
+ }
1047
+ jsonResults.push({
1048
+ tenantKey,
1049
+ tenantId,
1050
+ created: 0,
1051
+ updated: 0,
1052
+ failed: types.length,
1053
+ publishingMode: "app-manifest",
1054
+ error: message,
1055
+ verification: {
1056
+ tenantId,
1057
+ requestedTypes: types.map((type) => type.name),
1058
+ matchedTypes: [],
1059
+ missingTypes: types.map((type) => type.name),
1060
+ driftedTypes: [],
1061
+ createdCount: 0,
1062
+ updatedCount: 0,
1063
+ failedCount: types.length,
1064
+ converged: false,
1065
+ },
1066
+ });
1067
+ continue;
1068
+ }
1069
+ try {
1070
+ const remoteRes = await client.getPublishedObjectTypes({ limit: 200 });
1071
+ if (!remoteRes.ok) {
1072
+ throw new Error(`remote lookup failed: ${await describeFailedPlatformResponse(remoteRes)}`);
1073
+ }
1074
+ remoteDocs = extractRemoteObjectTypeDocs(await remoteRes.json());
1075
+ }
1076
+ catch (err) {
1077
+ const message = err instanceof Error ? err.message : String(err);
1078
+ if (options.format !== "json") {
1079
+ out.warn(`Pre-flight lookup failed: ${message}`);
1080
+ }
1081
+ }
1082
+ for (const type of types) {
1083
+ const typeSpinner = options.format === "json" ? null : ora(` ${type.name}`).start();
1084
+ try {
1085
+ const matches = findMatchingRemoteTypes(remoteDocs, type.name);
1086
+ const existing = matches[0];
1087
+ const duplicates = matches.slice(1).filter((doc) => doc.id);
1088
+ if (duplicates.length > 0) {
1089
+ const archivedCount = await archiveDuplicateRemoteTypes(client, duplicates);
1090
+ if (archivedCount > 0) {
1091
+ remoteDocs = remoteDocs.filter((doc) => !duplicates.some((duplicate) => duplicate.id === doc.id));
1092
+ }
1093
+ }
1094
+ if (existing?.id) {
1095
+ // Update
1096
+ const updateRes = await client.updateObjectType(existing.id, {
1097
+ name: type.name,
1098
+ slug: toObjectTypeSlug(type.name),
1099
+ tenant: tenantId,
1100
+ displayName: type.displayName,
1101
+ description: type.description,
1102
+ properties: type.properties,
1103
+ linkTypes: type.linkTypes,
1104
+ actions: type.actions,
1105
+ storageBackend: type.storageBackend,
1106
+ schemaVersion: type.schemaVersion,
1107
+ storageMetadataStatus: type.storageMetadataStatus,
1108
+ storageBinding: type.storageBinding,
1109
+ provisioningHints: type.provisioningHints,
1110
+ status: type.status,
1111
+ });
1112
+ if (updateRes.ok) {
1113
+ const archivedSuffix = duplicates.length > 0
1114
+ ? chalk.dim(` + archived ${duplicates.length} duplicate${duplicates.length === 1 ? "" : "s"}`)
1115
+ : "";
1116
+ if (typeSpinner) {
1117
+ typeSpinner.succeed(` ${type.name} ${chalk.cyan("(updated)")}${archivedSuffix}`);
1118
+ }
1119
+ updated++;
1120
+ remoteDocs = remoteDocs.map((doc) => doc.id === existing.id
1121
+ ? {
1122
+ ...doc,
1123
+ name: type.name,
1124
+ slug: toObjectTypeSlug(type.name),
1125
+ properties: type.properties,
1126
+ linkTypes: type.linkTypes,
1127
+ actions: type.actions,
1128
+ storageBackend: type.storageBackend,
1129
+ schemaVersion: type.schemaVersion,
1130
+ storageMetadataStatus: type.storageMetadataStatus,
1131
+ storageBinding: type.storageBinding,
1132
+ provisioningHints: type.provisioningHints,
1133
+ status: type.status,
1134
+ }
1135
+ : doc);
1136
+ }
1137
+ else {
1138
+ if (typeSpinner) {
1139
+ typeSpinner.fail(` ${type.name} — update failed: ${await describeFailedPlatformResponse(updateRes)}`);
1140
+ }
1141
+ failed++;
1142
+ }
1143
+ }
1144
+ else {
1145
+ // Create
1146
+ const createRes = await client.createObjectType({
1147
+ name: type.name,
1148
+ slug: toObjectTypeSlug(type.name),
1149
+ displayName: type.displayName,
1150
+ description: type.description,
1151
+ properties: type.properties,
1152
+ linkTypes: type.linkTypes,
1153
+ actions: type.actions,
1154
+ storageBackend: type.storageBackend,
1155
+ schemaVersion: type.schemaVersion,
1156
+ storageMetadataStatus: type.storageMetadataStatus,
1157
+ storageBinding: type.storageBinding,
1158
+ provisioningHints: type.provisioningHints,
1159
+ status: type.status,
1160
+ tenant: tenantId,
1161
+ });
1162
+ if (createRes.ok) {
1163
+ const archivedSuffix = duplicates.length > 0
1164
+ ? chalk.dim(` + archived ${duplicates.length} duplicate${duplicates.length === 1 ? "" : "s"}`)
1165
+ : "";
1166
+ if (typeSpinner) {
1167
+ typeSpinner.succeed(` ${type.name} ${chalk.green("(created)")}${archivedSuffix}`);
1168
+ }
1169
+ created++;
1170
+ remoteDocs.push({
1171
+ name: type.name,
1172
+ slug: toObjectTypeSlug(type.name),
1173
+ properties: type.properties,
1174
+ linkTypes: type.linkTypes,
1175
+ actions: type.actions,
1176
+ storageBackend: type.storageBackend,
1177
+ schemaVersion: type.schemaVersion,
1178
+ storageMetadataStatus: type.storageMetadataStatus,
1179
+ storageBinding: type.storageBinding,
1180
+ provisioningHints: type.provisioningHints,
1181
+ status: type.status,
1182
+ });
1183
+ }
1184
+ else {
1185
+ if (typeSpinner) {
1186
+ typeSpinner.fail(` ${type.name} — create failed: ${await describeFailedPlatformResponse(createRes)}`);
1187
+ }
1188
+ failed++;
1189
+ }
1190
+ }
1191
+ }
1192
+ catch (err) {
1193
+ if (typeSpinner) {
1194
+ typeSpinner.fail(` ${type.name} — ${err instanceof Error ? err.message : String(err)}`);
1195
+ }
1196
+ failed++;
1197
+ }
1198
+ }
1199
+ if (options.format !== "json") {
1200
+ out.blank();
1201
+ }
1202
+ let verification;
1203
+ let resourceApiSchemaSync;
1204
+ try {
1205
+ verification = await verifyTypeSeedConvergenceWithRetry(client, tenantId, types.map((type) => type.name), {
1206
+ createdCount: created,
1207
+ updatedCount: updated,
1208
+ failedCount: failed,
1209
+ }, {
1210
+ attempts: failed > 0 ? 1 : 6,
1211
+ delayMs: 1000,
1212
+ });
1213
+ }
1214
+ catch (err) {
1215
+ const message = err instanceof Error ? err.message : String(err);
1216
+ verification = {
1217
+ tenantId,
1218
+ requestedTypes: types.map((type) => type.name),
1219
+ matchedTypes: [],
1220
+ missingTypes: types.map((type) => type.name),
1221
+ driftedTypes: [],
1222
+ createdCount: created,
1223
+ updatedCount: updated,
1224
+ failedCount: failed,
1225
+ converged: false,
1226
+ };
1227
+ if (options.format !== "json") {
1228
+ out.warn(`Verification: ${message}`);
1229
+ }
1230
+ }
1231
+ if (verification.converged) {
1232
+ resourceApiSchemaSync = await summarizeResourceApiSchemaSync(await client.syncStorageSchema({
1233
+ dryRun: false,
1234
+ objectTypes: types.map((type) => toObjectTypeSlug(type.name)),
1235
+ }), types.map((type) => toObjectTypeSlug(type.name)));
1236
+ }
1237
+ if (options.format !== "json") {
1238
+ out.info(`Result: ${chalk.green(`${created} created`)}, ${chalk.cyan(`${updated} updated`)}, ${chalk.red(`${failed} failed`)}`);
1239
+ if (verification.converged) {
1240
+ out.success(`Verification: converged (${verification.matchedTypes.length}/${verification.requestedTypes.length} published remotely)`);
1241
+ }
1242
+ else {
1243
+ const issues = [
1244
+ verification.missingTypes.length > 0
1245
+ ? `${verification.missingTypes.length} missing`
1246
+ : null,
1247
+ verification.driftedTypes.length > 0
1248
+ ? `${verification.driftedTypes.length} drifted`
1249
+ : null,
1250
+ verification.failedCount > 0
1251
+ ? `${verification.failedCount} failed writes`
1252
+ : null,
1253
+ ]
1254
+ .filter(Boolean)
1255
+ .join(", ");
1256
+ out.warn(`Verification: partial (${issues || "remote schema did not converge"})`);
1257
+ }
1258
+ printResourceApiSchemaSyncSummary(resourceApiSchemaSync);
1259
+ }
1260
+ jsonResults.push({
1261
+ tenantKey,
1262
+ tenantId: tenantId,
1263
+ created,
1264
+ updated,
1265
+ failed,
1266
+ verification,
1267
+ publishingMode: "direct-object-types",
1268
+ resourceApiSchemaSync,
1269
+ appManifestFallbackReason,
1270
+ });
1271
+ }
1272
+ if (options.format === "json") {
1273
+ out.json({ tenants: jsonResults });
1274
+ }
1275
+ if (shouldFailTypeSeedRun(jsonResults)) {
1276
+ process.exitCode = 1;
1277
+ }
1278
+ });
1279
+ // ─── eai types validate ────────────────────────────────────────────────────
1280
+ typesCommand
1281
+ .command("validate")
1282
+ .description("Validate Object Types against platform schema rules")
1283
+ .addHelpText("after", `
1284
+ Examples:
1285
+ $ eai types validate
1286
+ `)
1287
+ .action(async () => {
1288
+ const root = await findProjectRoot();
1289
+ if (!root) {
1290
+ exitWithError(ErrorCode.E001);
1291
+ }
1292
+ const spinner = ora("Loading Object Types...").start();
1293
+ let objectTypes;
1294
+ try {
1295
+ objectTypes = await loadObjectTypes(root);
1296
+ spinner.succeed("Loaded Object Types");
1297
+ }
1298
+ catch (err) {
1299
+ spinner.fail("Failed to load Object Types");
1300
+ out.error(err instanceof Error ? err.message : String(err));
1301
+ process.exit(1);
1302
+ }
1303
+ let errors = 0;
1304
+ let warnings = 0;
1305
+ for (const [tenantKey, types] of Object.entries(objectTypes)) {
1306
+ out.heading(`Tenant: ${tenantKey}`);
1307
+ for (const type of types) {
1308
+ const issues = [];
1309
+ const warns = [];
1310
+ // Name must be PascalCase
1311
+ if (!/^[A-Z][a-zA-Z0-9]*$/.test(type.name)) {
1312
+ issues.push(`name "${type.name}" must be PascalCase`);
1313
+ }
1314
+ // Must have displayName
1315
+ if (!type.displayName) {
1316
+ issues.push("missing displayName");
1317
+ }
1318
+ // Status must be valid
1319
+ if (!["draft", "published", "deprecated"].includes(type.status)) {
1320
+ issues.push(`invalid status "${type.status}"`);
1321
+ }
1322
+ // Validate properties
1323
+ const propNames = new Set();
1324
+ const validTypes = [
1325
+ "text",
1326
+ "number",
1327
+ "boolean",
1328
+ "date",
1329
+ "select",
1330
+ "json",
1331
+ "file",
1332
+ "relationship",
1333
+ ];
1334
+ for (const prop of type.properties) {
1335
+ if (propNames.has(prop.name)) {
1336
+ issues.push(`duplicate property name "${prop.name}"`);
1337
+ }
1338
+ propNames.add(prop.name);
1339
+ if (!validTypes.includes(prop.type)) {
1340
+ issues.push(`property "${prop.name}" has invalid type "${prop.type}"`);
1341
+ }
1342
+ if (prop.type === "select" &&
1343
+ (!prop.options || prop.options.length === 0)) {
1344
+ issues.push(`select property "${prop.name}" must have options`);
1345
+ }
1346
+ if (prop.type !== "select" &&
1347
+ prop.options &&
1348
+ prop.options.length > 0) {
1349
+ warns.push(`property "${prop.name}" has options but type is "${prop.type}" (not select)`);
1350
+ }
1351
+ }
1352
+ issues.push(...validateObjectTypeDefaultValues(type));
1353
+ issues.push(...validateObjectTypeStorageMetadata(type));
1354
+ // Validate link types
1355
+ for (const link of type.linkTypes) {
1356
+ if (!link.targetObjectType) {
1357
+ issues.push(`link "${link.name}" missing targetObjectType`);
1358
+ }
1359
+ if (![
1360
+ "one-to-one",
1361
+ "one-to-many",
1362
+ "many-to-one",
1363
+ "many-to-many",
1364
+ ].includes(link.cardinality)) {
1365
+ issues.push(`link "${link.name}" has invalid cardinality "${link.cardinality}"`);
1366
+ }
1367
+ }
1368
+ // Validate actions
1369
+ for (const action of type.actions) {
1370
+ if (!action.name) {
1371
+ issues.push("action missing name");
1372
+ }
1373
+ if (!["tenant-viewer", "tenant-builder", "tenant-admin"].includes(action.requiredRole)) {
1374
+ issues.push(`action "${action.name}" has invalid requiredRole "${action.requiredRole}"`);
1375
+ }
1376
+ for (const effect of action.sideEffects) {
1377
+ if (!["set_field", "set_timestamp", "set_user"].includes(effect.type)) {
1378
+ issues.push(`action "${action.name}" side effect has invalid type "${effect.type}"`);
1379
+ }
1380
+ if (effect.type === "set_field" && !propNames.has(effect.field)) {
1381
+ warns.push(`action "${action.name}" side effect references unknown field "${effect.field}"`);
1382
+ }
1383
+ }
1384
+ }
1385
+ // Print results
1386
+ if (issues.length === 0 && warns.length === 0) {
1387
+ out.success(`${type.name} — ${type.properties.length} props, ${type.linkTypes.length} links, ${type.actions.length} actions`);
1388
+ }
1389
+ else {
1390
+ if (issues.length > 0) {
1391
+ out.error(`${type.name}`);
1392
+ for (const issue of issues) {
1393
+ out.error(` ${issue}`);
1394
+ }
1395
+ errors += issues.length;
1396
+ }
1397
+ if (warns.length > 0) {
1398
+ if (issues.length === 0)
1399
+ out.warn(`${type.name}`);
1400
+ for (const w of warns) {
1401
+ out.warn(` ${w}`);
1402
+ }
1403
+ warnings += warns.length;
1404
+ }
1405
+ }
1406
+ }
1407
+ }
1408
+ out.blank();
1409
+ if (errors > 0) {
1410
+ exitWithError(ErrorCode.E302, {
1411
+ details: `${errors} validation error(s), ${warnings} warning(s)`,
1412
+ });
1413
+ }
1414
+ else if (warnings > 0) {
1415
+ out.warn(`${warnings} warning(s), 0 errors`);
1416
+ }
1417
+ else {
1418
+ out.success("All Object Types are valid");
1419
+ }
1420
+ });
1421
+ // ─── eai types diff ────────────────────────────────────────────────────────
1422
+ typesCommand
1423
+ .command("diff")
1424
+ .description("Compare local Object Types with remote platform")
1425
+ .option("--tenant-key <key>", "Specific tenant key from object-types.ts")
1426
+ .option("--tenant-id <id>", "Override the resolved tenant ID (use with --tenant-key)")
1427
+ .option("--format <format>", "Output format (text|json)", "text")
1428
+ .option("--json", "Output raw JSON (deprecated, use --format json)", false)
1429
+ .addHelpText("after", `
1430
+ Examples:
1431
+ $ eai types diff
1432
+ $ eai types diff --tenant-key council --tenant-id 423b7e9c-9a69-4763-5b9a-69570218f65d
1433
+ $ eai types diff --format json
1434
+ `)
1435
+ .action(async (options) => {
1436
+ if (options.json) {
1437
+ options.format = "json";
1438
+ }
1439
+ if (!["text", "json"].includes(options.format)) {
1440
+ exitWithError(ErrorCode.E303, {
1441
+ field: "--format",
1442
+ value: options.format,
1443
+ expected: "text or json",
1444
+ });
1445
+ }
1446
+ const jsonOutput = options.format === "json";
1447
+ const ctx = await resolveCommandContext({ tenantId: options.tenantId });
1448
+ const { root, publicApiUrl } = ctx;
1449
+ const activeContext = options.tenantId ? null : ctx;
1450
+ const spinner = jsonOutput ? null : ora("Loading local Object Types...").start();
1451
+ let objectTypes;
1452
+ try {
1453
+ objectTypes = await loadObjectTypes(root);
1454
+ spinner?.succeed("Loaded local types");
1455
+ }
1456
+ catch (err) {
1457
+ spinner?.fail("Failed to load local types");
1458
+ out.error(err instanceof Error ? err.message : String(err));
1459
+ process.exit(1);
1460
+ }
1461
+ const keysToDiff = await selectTenantKey(objectTypes, options.tenantKey, activeContext?.activeTenant.slug);
1462
+ const entries = keysToDiff.map((key) => [key, objectTypes[key]]);
1463
+ if (options.tenantId &&
1464
+ !options.tenantKey &&
1465
+ Object.keys(objectTypes).length > 1) {
1466
+ exitWithError(ErrorCode.E303, {
1467
+ field: "--tenant-key when using --tenant-id with multiple tenant scopes",
1468
+ });
1469
+ }
1470
+ const results = [];
1471
+ for (const [tenantKey, localTypes] of entries) {
1472
+ if (!localTypes || localTypes.length === 0) {
1473
+ if (!jsonOutput) {
1474
+ out.warn(`No local Object Types found for "${tenantKey}"`);
1475
+ }
1476
+ results.push({
1477
+ tenantKey,
1478
+ tenantId: options.tenantId,
1479
+ resolutionSource: options.tenantId ? "option" : undefined,
1480
+ localCount: 0,
1481
+ remoteCount: 0,
1482
+ localOnly: [],
1483
+ remoteOnly: [],
1484
+ changed: [],
1485
+ unchanged: [],
1486
+ });
1487
+ continue;
1488
+ }
1489
+ const resolution = resolveTenantIdForKey(tenantKey, options.tenantId, activeContext?.activeTenant.id);
1490
+ const tenantId = resolution.tenantId;
1491
+ if (!tenantId) {
1492
+ if (!jsonOutput) {
1493
+ explainMissingTenantId(tenantKey);
1494
+ }
1495
+ results.push({
1496
+ tenantKey,
1497
+ resolutionSource: resolution.source,
1498
+ localCount: localTypes.length,
1499
+ remoteCount: 0,
1500
+ localOnly: [],
1501
+ remoteOnly: [],
1502
+ changed: [],
1503
+ unchanged: [],
1504
+ error: "Tenant ID could not be resolved",
1505
+ });
1506
+ continue;
1507
+ }
1508
+ if (!jsonOutput) {
1509
+ out.heading(`Tenant: ${tenantKey} → ${chalk.dim(tenantId)} ${chalk.dim(`(${describeTenantResolutionSource(resolution.source)})`)}`);
1510
+ }
1511
+ const client = new PlatformAPIClient(publicApiUrl, tenantId);
1512
+ const remoteSpinner = jsonOutput ? null : ora(" Fetching remote types...").start();
1513
+ try {
1514
+ const res = await client.getPublishedObjectTypes({ limit: 100 });
1515
+ const remoteDocs = extractRemoteObjectTypeDocs(await res.json());
1516
+ remoteSpinner?.succeed(` ${remoteDocs.length} remote types`);
1517
+ const result = diffObjectTypesForTenant(tenantKey, tenantId, resolution.source, localTypes, remoteDocs);
1518
+ results.push(result);
1519
+ if (jsonOutput) {
1520
+ continue;
1521
+ }
1522
+ for (const entry of result.localOnly) {
1523
+ out.info(` ${out.symbols.added} ${entry.name} — local only`);
1524
+ }
1525
+ for (const entry of result.unchanged) {
1526
+ out.info(` ${out.symbols.unchanged} ${entry.name} — no changes`);
1527
+ }
1528
+ for (const entry of result.changed) {
1529
+ out.info(` ${out.symbols.changed} ${entry.name}`);
1530
+ for (const property of entry.addedProperties) {
1531
+ out.info(` ${out.symbols.added} ${property}`);
1532
+ }
1533
+ for (const property of entry.removedProperties) {
1534
+ out.info(` ${out.symbols.removed} ${property}`);
1535
+ }
1536
+ if (entry.unchangedProperties.length > 0) {
1537
+ out.dim(` ${entry.unchangedProperties.length} unchanged`);
1538
+ }
1539
+ }
1540
+ for (const entry of result.remoteOnly) {
1541
+ out.warn(` ${out.symbols.warning} ${entry.name} — exists remotely but not locally`);
1542
+ }
1543
+ }
1544
+ catch (err) {
1545
+ const message = err instanceof Error ? err.message : String(err);
1546
+ remoteSpinner?.fail(" Failed to fetch remote types");
1547
+ if (!jsonOutput) {
1548
+ out.error(message);
1549
+ }
1550
+ results.push({
1551
+ tenantKey,
1552
+ tenantId,
1553
+ resolutionSource: resolution.source,
1554
+ localCount: localTypes.length,
1555
+ remoteCount: 0,
1556
+ localOnly: [],
1557
+ remoteOnly: [],
1558
+ changed: [],
1559
+ unchanged: [],
1560
+ error: message,
1561
+ });
1562
+ }
1563
+ }
1564
+ if (jsonOutput) {
1565
+ out.json({ tenants: results });
1566
+ }
1567
+ if (results.some((result) => result.error)) {
1568
+ process.exitCode = 1;
1569
+ }
1570
+ });
1571
+ // ─── eai types pull ────────────────────────────────────────────────────────
1572
+ typesCommand
1573
+ .command("pull")
1574
+ .description("Download remote Object Types to local TypeScript")
1575
+ .option("--tenant-id <id>", "platform tenant ID")
1576
+ .option("--output <path>", "Output file path", "src/eai.config/object-types.generated.ts")
1577
+ .addHelpText("after", `
1578
+ Examples:
1579
+ $ eai types pull
1580
+ $ eai types pull --output src/types/generated.ts
1581
+ `)
1582
+ .action(async (options) => {
1583
+ const ctx = await resolveCommandContext({ tenantId: options.tenantId });
1584
+ const spinner = ora("Fetching remote Object Types...").start();
1585
+ try {
1586
+ const { client, tenantId, root } = ctx;
1587
+ const res = await client.getPublishedObjectTypes({ limit: 100 });
1588
+ const data = (await res.json());
1589
+ const types = data?.docs || [];
1590
+ spinner.succeed(`Found ${types.length} remote types`);
1591
+ // Generate TypeScript
1592
+ const ts = generateTypeScript(types, tenantId);
1593
+ const { writeFile: write } = await import("node:fs/promises");
1594
+ const outputPath = await resolveTypesPullOutputPath(root, options.output);
1595
+ await write(outputPath, ts, "utf-8");
1596
+ out.success(`Written to ${chalk.bold(options.output)}`);
1597
+ out.info("Review the generated file and merge into object-types.ts");
1598
+ }
1599
+ catch (err) {
1600
+ spinner.fail("Failed to pull types");
1601
+ out.error(err instanceof Error ? err.message : String(err));
1602
+ process.exit(1);
1603
+ }
1604
+ });
1605
+ // ─── eai types define ──────────────────────────────────────────────────────
1606
+ typesCommand
1607
+ .command("define")
1608
+ .description("Interactive Object Type builder (coming soon)")
1609
+ .action(async () => {
1610
+ out.info("Interactive Object Type builder is planned for Phase 3.");
1611
+ out.info("For now, edit src/eai.config/object-types.ts directly.");
1612
+ out.info("See the Object Types Guide in CLAUDE.md for the schema format.");
1613
+ });
1614
+ // ─── Helpers ───────────────────────────────────────────────────────────────
1615
+ function generateTypeScript(types, tenantKey) {
1616
+ const lines = [
1617
+ "/**",
1618
+ " * Object Types — auto-generated by `eai types pull`",
1619
+ ` * Generated: ${new Date().toISOString()}`,
1620
+ " *",
1621
+ " * Review and merge into object-types.ts.",
1622
+ " */",
1623
+ "",
1624
+ "import type { ObjectTypeDefinition } from './object-types';",
1625
+ "",
1626
+ `export const pulledTypes: Record<string, ObjectTypeDefinition[]> = {`,
1627
+ ` '${tenantKey}': ${JSON.stringify(types, null, 4)
1628
+ .split("\n")
1629
+ .map((l, i) => (i === 0 ? l : " " + l))
1630
+ .join("\n")},`,
1631
+ "};",
1632
+ "",
1633
+ ];
1634
+ return lines.join("\n");
1635
+ }
1636
+ //# sourceMappingURL=types.js.map