primitive-admin 1.1.0-alpha.7 → 1.1.0-alpha.71

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 (438) hide show
  1. package/README.md +404 -80
  2. package/assets/skill/skills/primitive-platform/SKILL.md +808 -0
  3. package/dist/bin/primitive.d.ts +2 -0
  4. package/dist/bin/primitive.js +294 -21
  5. package/dist/bin/primitive.js.map +1 -1
  6. package/dist/src/commands/admins.d.ts +2 -0
  7. package/dist/src/commands/admins.js +138 -19
  8. package/dist/src/commands/admins.js.map +1 -1
  9. package/dist/src/commands/analytics.d.ts +2 -0
  10. package/dist/src/commands/analytics.js +544 -55
  11. package/dist/src/commands/analytics.js.map +1 -1
  12. package/dist/src/commands/apps.d.ts +2 -0
  13. package/dist/src/commands/apps.js +51 -96
  14. package/dist/src/commands/apps.js.map +1 -1
  15. package/dist/src/commands/auth.d.ts +2 -0
  16. package/dist/src/commands/auth.js +177 -7
  17. package/dist/src/commands/auth.js.map +1 -1
  18. package/dist/src/commands/blob-buckets.d.ts +2 -0
  19. package/dist/src/commands/blob-buckets.js +330 -0
  20. package/dist/src/commands/blob-buckets.js.map +1 -0
  21. package/dist/src/commands/catalog.d.ts +2 -0
  22. package/dist/src/commands/catalog.js +37 -38
  23. package/dist/src/commands/catalog.js.map +1 -1
  24. package/dist/src/commands/collection-type-configs.d.ts +2 -0
  25. package/dist/src/commands/collection-type-configs.js +92 -0
  26. package/dist/src/commands/collection-type-configs.js.map +1 -0
  27. package/dist/src/commands/collections.d.ts +2 -0
  28. package/dist/src/commands/collections.js +565 -0
  29. package/dist/src/commands/collections.js.map +1 -0
  30. package/dist/src/commands/comparisons.d.ts +2 -0
  31. package/dist/src/commands/comparisons.js +6 -6
  32. package/dist/src/commands/comparisons.js.map +1 -1
  33. package/dist/src/commands/config.d.ts +46 -0
  34. package/dist/src/commands/config.js +479 -0
  35. package/dist/src/commands/config.js.map +1 -0
  36. package/dist/src/commands/connections.d.ts +2 -0
  37. package/dist/src/commands/connections.js +100 -0
  38. package/dist/src/commands/connections.js.map +1 -0
  39. package/dist/src/commands/cron-triggers.d.ts +2 -0
  40. package/dist/src/commands/cron-triggers.js +265 -0
  41. package/dist/src/commands/cron-triggers.js.map +1 -0
  42. package/dist/src/commands/database-type-configs.d.ts +2 -0
  43. package/dist/src/commands/database-type-configs.js +171 -0
  44. package/dist/src/commands/database-type-configs.js.map +1 -0
  45. package/dist/src/commands/database-types.d.ts +2 -0
  46. package/dist/src/commands/database-types.js +471 -0
  47. package/dist/src/commands/database-types.js.map +1 -0
  48. package/dist/src/commands/databases.d.ts +65 -0
  49. package/dist/src/commands/databases.js +2140 -112
  50. package/dist/src/commands/databases.js.map +1 -1
  51. package/dist/src/commands/documents.d.ts +2 -0
  52. package/dist/src/commands/documents.js +1357 -19
  53. package/dist/src/commands/documents.js.map +1 -1
  54. package/dist/src/commands/email-templates.d.ts +2 -0
  55. package/dist/src/commands/email-templates.js +174 -0
  56. package/dist/src/commands/email-templates.js.map +1 -0
  57. package/dist/src/commands/env.d.ts +23 -0
  58. package/dist/src/commands/env.js +333 -0
  59. package/dist/src/commands/env.js.map +1 -0
  60. package/dist/src/commands/feature-flags.d.ts +14 -0
  61. package/dist/src/commands/feature-flags.js +116 -0
  62. package/dist/src/commands/feature-flags.js.map +1 -0
  63. package/dist/src/commands/group-type-configs.d.ts +2 -0
  64. package/dist/src/commands/group-type-configs.js +86 -0
  65. package/dist/src/commands/group-type-configs.js.map +1 -0
  66. package/dist/src/commands/groups.d.ts +2 -0
  67. package/dist/src/commands/groups.js +38 -99
  68. package/dist/src/commands/groups.js.map +1 -1
  69. package/dist/src/commands/guides.d.ts +223 -0
  70. package/dist/src/commands/guides.js +617 -65
  71. package/dist/src/commands/guides.js.map +1 -1
  72. package/dist/src/commands/init.d.ts +25 -0
  73. package/dist/src/commands/init.js +1605 -208
  74. package/dist/src/commands/init.js.map +1 -1
  75. package/dist/src/commands/integrations.d.ts +2 -0
  76. package/dist/src/commands/integrations.js +380 -178
  77. package/dist/src/commands/integrations.js.map +1 -1
  78. package/dist/src/commands/llm.d.ts +2 -0
  79. package/dist/src/commands/llm.js +4 -2
  80. package/dist/src/commands/llm.js.map +1 -1
  81. package/dist/src/commands/locks.d.ts +8 -0
  82. package/dist/src/commands/locks.js +160 -0
  83. package/dist/src/commands/locks.js.map +1 -0
  84. package/dist/src/commands/metadata-category-configs.d.ts +12 -0
  85. package/dist/src/commands/metadata-category-configs.js +112 -0
  86. package/dist/src/commands/metadata-category-configs.js.map +1 -0
  87. package/dist/src/commands/metadata.d.ts +2 -0
  88. package/dist/src/commands/metadata.js +281 -0
  89. package/dist/src/commands/metadata.js.map +1 -0
  90. package/dist/src/commands/prompts.d.ts +2 -0
  91. package/dist/src/commands/prompts.js +225 -584
  92. package/dist/src/commands/prompts.js.map +1 -1
  93. package/dist/src/commands/rule-sets.d.ts +3 -0
  94. package/dist/src/commands/rule-sets.js +272 -0
  95. package/dist/src/commands/rule-sets.js.map +1 -0
  96. package/dist/src/commands/scripts.d.ts +20 -0
  97. package/dist/src/commands/scripts.js +554 -0
  98. package/dist/src/commands/scripts.js.map +1 -0
  99. package/dist/src/commands/secrets.d.ts +2 -0
  100. package/dist/src/commands/secrets.js +108 -0
  101. package/dist/src/commands/secrets.js.map +1 -0
  102. package/dist/src/commands/sessions.d.ts +2 -0
  103. package/dist/src/commands/sessions.js +75 -0
  104. package/dist/src/commands/sessions.js.map +1 -0
  105. package/dist/src/commands/skill.d.ts +2 -0
  106. package/dist/src/commands/skill.js +29 -0
  107. package/dist/src/commands/skill.js.map +1 -0
  108. package/dist/src/commands/sync-app-settings.d.ts +158 -0
  109. package/dist/src/commands/sync-app-settings.js +330 -0
  110. package/dist/src/commands/sync-app-settings.js.map +1 -0
  111. package/dist/src/commands/sync.d.ts +2323 -0
  112. package/dist/src/commands/sync.js +15065 -843
  113. package/dist/src/commands/sync.js.map +1 -1
  114. package/dist/src/commands/tokens.d.ts +2 -0
  115. package/dist/src/commands/tokens.js +130 -21
  116. package/dist/src/commands/tokens.js.map +1 -1
  117. package/dist/src/commands/users.d.ts +2 -0
  118. package/dist/src/commands/users.js +532 -23
  119. package/dist/src/commands/users.js.map +1 -1
  120. package/dist/src/commands/vars.d.ts +8 -0
  121. package/dist/src/commands/vars.js +96 -0
  122. package/dist/src/commands/vars.js.map +1 -0
  123. package/dist/src/commands/waitlist.d.ts +2 -0
  124. package/dist/src/commands/waitlist.js +10 -10
  125. package/dist/src/commands/waitlist.js.map +1 -1
  126. package/dist/src/commands/webhooks.d.ts +2 -0
  127. package/dist/src/commands/webhooks.js +562 -0
  128. package/dist/src/commands/webhooks.js.map +1 -0
  129. package/dist/src/commands/workflows.d.ts +116 -0
  130. package/dist/src/commands/workflows.js +1583 -681
  131. package/dist/src/commands/workflows.js.map +1 -1
  132. package/dist/src/lib/access-rule-display.d.ts +21 -0
  133. package/dist/src/lib/access-rule-display.js +34 -0
  134. package/dist/src/lib/access-rule-display.js.map +1 -0
  135. package/dist/src/lib/api-client.d.ts +1936 -0
  136. package/dist/src/lib/api-client.js +1826 -138
  137. package/dist/src/lib/api-client.js.map +1 -1
  138. package/dist/src/lib/app-settings-descriptor.d.ts +263 -0
  139. package/dist/src/lib/app-settings-descriptor.js +575 -0
  140. package/dist/src/lib/app-settings-descriptor.js.map +1 -0
  141. package/dist/src/lib/auth-flow.d.ts +8 -0
  142. package/dist/src/lib/batch.d.ts +26 -0
  143. package/dist/src/lib/batch.js +32 -0
  144. package/dist/src/lib/batch.js.map +1 -0
  145. package/dist/src/lib/block-layout.d.ts +160 -0
  146. package/dist/src/lib/block-layout.js +451 -0
  147. package/dist/src/lib/block-layout.js.map +1 -0
  148. package/dist/src/lib/canonical-json.d.ts +12 -0
  149. package/dist/src/lib/canonical-json.js +35 -0
  150. package/dist/src/lib/canonical-json.js.map +1 -0
  151. package/dist/src/lib/channel.d.ts +30 -0
  152. package/dist/src/lib/channel.js +68 -0
  153. package/dist/src/lib/channel.js.map +1 -0
  154. package/dist/src/lib/cli-manifest.d.ts +68 -0
  155. package/dist/src/lib/cli-manifest.js +71 -0
  156. package/dist/src/lib/cli-manifest.js.map +1 -0
  157. package/dist/src/lib/codegen-shared/generatedFiles.d.ts +101 -0
  158. package/dist/src/lib/codegen-shared/generatedFiles.js +191 -0
  159. package/dist/src/lib/codegen-shared/generatedFiles.js.map +1 -0
  160. package/dist/src/lib/codegen-shared/prettierStable.d.ts +262 -0
  161. package/dist/src/lib/codegen-shared/prettierStable.js +610 -0
  162. package/dist/src/lib/codegen-shared/prettierStable.js.map +1 -0
  163. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.d.ts +68 -0
  164. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js +168 -0
  165. package/dist/src/lib/codegen-shared/resolveCodegenSourceDir.js.map +1 -0
  166. package/dist/src/lib/config-object-descriptor.d.ts +127 -0
  167. package/dist/src/lib/config-object-descriptor.js +658 -0
  168. package/dist/src/lib/config-object-descriptor.js.map +1 -0
  169. package/dist/src/lib/config-payload.d.ts +85 -0
  170. package/dist/src/lib/config-payload.js +116 -0
  171. package/dist/src/lib/config-payload.js.map +1 -0
  172. package/dist/src/lib/config-surface.d.ts +130 -0
  173. package/dist/src/lib/config-surface.js +300 -0
  174. package/dist/src/lib/config-surface.js.map +1 -0
  175. package/dist/src/lib/config-toml.d.ts +10 -0
  176. package/dist/src/lib/config-toml.js +42 -0
  177. package/dist/src/lib/config-toml.js.map +1 -0
  178. package/dist/src/lib/config.d.ts +53 -0
  179. package/dist/src/lib/config.js +92 -53
  180. package/dist/src/lib/config.js.map +1 -1
  181. package/dist/src/lib/confirm-prompt.d.ts +83 -0
  182. package/dist/src/lib/confirm-prompt.js +110 -0
  183. package/dist/src/lib/confirm-prompt.js.map +1 -0
  184. package/dist/src/lib/constants.d.ts +11 -0
  185. package/dist/src/lib/constants.js +12 -0
  186. package/dist/src/lib/constants.js.map +1 -0
  187. package/dist/src/lib/crash-handlers.d.ts +20 -0
  188. package/dist/src/lib/crash-handlers.js +49 -0
  189. package/dist/src/lib/crash-handlers.js.map +1 -0
  190. package/dist/src/lib/credentials-store.d.ts +89 -0
  191. package/dist/src/lib/credentials-store.js +330 -0
  192. package/dist/src/lib/credentials-store.js.map +1 -0
  193. package/dist/src/lib/csv.d.ts +47 -0
  194. package/dist/src/lib/csv.js +172 -0
  195. package/dist/src/lib/csv.js.map +1 -0
  196. package/dist/src/lib/data-input.d.ts +23 -0
  197. package/dist/src/lib/data-input.js +50 -0
  198. package/dist/src/lib/data-input.js.map +1 -0
  199. package/dist/src/lib/db-codegen/dbFingerprint.d.ts +10 -0
  200. package/dist/src/lib/db-codegen/dbFingerprint.js +17 -0
  201. package/dist/src/lib/db-codegen/dbFingerprint.js.map +1 -0
  202. package/dist/src/lib/db-codegen/dbGenerator.d.ts +67 -0
  203. package/dist/src/lib/db-codegen/dbGenerator.js +170 -0
  204. package/dist/src/lib/db-codegen/dbGenerator.js.map +1 -0
  205. package/dist/src/lib/db-codegen/dbNaming.d.ts +87 -0
  206. package/dist/src/lib/db-codegen/dbNaming.js +180 -0
  207. package/dist/src/lib/db-codegen/dbNaming.js.map +1 -0
  208. package/dist/src/lib/db-codegen/dbTemplates.d.ts +272 -0
  209. package/dist/src/lib/db-codegen/dbTemplates.js +480 -0
  210. package/dist/src/lib/db-codegen/dbTemplates.js.map +1 -0
  211. package/dist/src/lib/db-codegen/dbTsTypes.d.ts +73 -0
  212. package/dist/src/lib/db-codegen/dbTsTypes.js +139 -0
  213. package/dist/src/lib/db-codegen/dbTsTypes.js.map +1 -0
  214. package/dist/src/lib/db-codegen/dbTypeIR.d.ts +146 -0
  215. package/dist/src/lib/db-codegen/dbTypeIR.js +517 -0
  216. package/dist/src/lib/db-codegen/dbTypeIR.js.map +1 -0
  217. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.d.ts +112 -0
  218. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js +211 -0
  219. package/dist/src/lib/db-codegen/generated-operation-def-descriptor.js.map +1 -0
  220. package/dist/src/lib/env-resolver-core.d.ts +147 -0
  221. package/dist/src/lib/env-resolver-core.js +265 -0
  222. package/dist/src/lib/env-resolver-core.js.map +1 -0
  223. package/dist/src/lib/env-resolver.d.ts +84 -0
  224. package/dist/src/lib/env-resolver.js +133 -0
  225. package/dist/src/lib/env-resolver.js.map +1 -0
  226. package/dist/src/lib/fetch.d.ts +5 -0
  227. package/dist/src/lib/generated-allowlist.d.ts +28 -0
  228. package/dist/src/lib/generated-allowlist.js +277 -0
  229. package/dist/src/lib/generated-allowlist.js.map +1 -0
  230. package/dist/src/lib/generated-config-surfaces.d.ts +682 -0
  231. package/dist/src/lib/generated-config-surfaces.js +4058 -0
  232. package/dist/src/lib/generated-config-surfaces.js.map +1 -0
  233. package/dist/src/lib/generated-template-lint.d.ts +212 -0
  234. package/dist/src/lib/generated-template-lint.js +624 -0
  235. package/dist/src/lib/generated-template-lint.js.map +1 -0
  236. package/dist/src/lib/init-adopt.d.ts +16 -0
  237. package/dist/src/lib/init-adopt.js +34 -0
  238. package/dist/src/lib/init-adopt.js.map +1 -0
  239. package/dist/src/lib/init-assets.d.ts +39 -0
  240. package/dist/src/lib/init-assets.js +97 -0
  241. package/dist/src/lib/init-assets.js.map +1 -0
  242. package/dist/src/lib/init-config.d.ts +98 -0
  243. package/dist/src/lib/init-config.js +186 -0
  244. package/dist/src/lib/init-config.js.map +1 -0
  245. package/dist/src/lib/init-ios-links.d.ts +50 -0
  246. package/dist/src/lib/init-ios-links.js +153 -0
  247. package/dist/src/lib/init-ios-links.js.map +1 -0
  248. package/dist/src/lib/init-plan.d.ts +80 -0
  249. package/dist/src/lib/init-plan.js +95 -0
  250. package/dist/src/lib/init-plan.js.map +1 -0
  251. package/dist/src/lib/init-production-env.d.ts +48 -0
  252. package/dist/src/lib/init-production-env.js +59 -0
  253. package/dist/src/lib/init-production-env.js.map +1 -0
  254. package/dist/src/lib/init-schema.d.ts +74 -0
  255. package/dist/src/lib/init-schema.js +358 -0
  256. package/dist/src/lib/init-schema.js.map +1 -0
  257. package/dist/src/lib/init-xcode.d.ts +33 -0
  258. package/dist/src/lib/init-xcode.js +114 -0
  259. package/dist/src/lib/init-xcode.js.map +1 -0
  260. package/dist/src/lib/integration-request-config.d.ts +30 -0
  261. package/dist/src/lib/integration-request-config.js +145 -0
  262. package/dist/src/lib/integration-request-config.js.map +1 -0
  263. package/dist/src/lib/local-state.d.ts +55 -0
  264. package/dist/src/lib/local-state.js +167 -0
  265. package/dist/src/lib/local-state.js.map +1 -0
  266. package/dist/src/lib/log-inspection.d.ts +568 -0
  267. package/dist/src/lib/log-inspection.js +639 -0
  268. package/dist/src/lib/log-inspection.js.map +1 -0
  269. package/dist/src/lib/migration-nag.d.ts +49 -0
  270. package/dist/src/lib/migration-nag.js +163 -0
  271. package/dist/src/lib/migration-nag.js.map +1 -0
  272. package/dist/src/lib/object-status-filter.d.ts +22 -0
  273. package/dist/src/lib/object-status-filter.js +45 -0
  274. package/dist/src/lib/object-status-filter.js.map +1 -0
  275. package/dist/src/lib/output.d.ts +109 -0
  276. package/dist/src/lib/output.js +191 -8
  277. package/dist/src/lib/output.js.map +1 -1
  278. package/dist/src/lib/package-manager.d.ts +140 -0
  279. package/dist/src/lib/package-manager.js +305 -0
  280. package/dist/src/lib/package-manager.js.map +1 -0
  281. package/dist/src/lib/paginate.d.ts +83 -0
  282. package/dist/src/lib/paginate.js +95 -0
  283. package/dist/src/lib/paginate.js.map +1 -0
  284. package/dist/src/lib/platform-owned.d.ts +63 -0
  285. package/dist/src/lib/platform-owned.js +85 -0
  286. package/dist/src/lib/platform-owned.js.map +1 -0
  287. package/dist/src/lib/project-config.d.ts +97 -0
  288. package/dist/src/lib/project-config.js +217 -0
  289. package/dist/src/lib/project-config.js.map +1 -0
  290. package/dist/src/lib/query-operators.d.ts +43 -0
  291. package/dist/src/lib/query-operators.js +80 -0
  292. package/dist/src/lib/query-operators.js.map +1 -0
  293. package/dist/src/lib/record-filter.d.ts +18 -0
  294. package/dist/src/lib/record-filter.js +55 -0
  295. package/dist/src/lib/record-filter.js.map +1 -0
  296. package/dist/src/lib/refresh-admin-credentials.d.ts +65 -0
  297. package/dist/src/lib/refresh-admin-credentials.js +103 -0
  298. package/dist/src/lib/refresh-admin-credentials.js.map +1 -0
  299. package/dist/src/lib/resolve-init-dev-port.d.ts +56 -0
  300. package/dist/src/lib/resolve-init-dev-port.js +55 -0
  301. package/dist/src/lib/resolve-init-dev-port.js.map +1 -0
  302. package/dist/src/lib/resolve-init-server.d.ts +64 -0
  303. package/dist/src/lib/resolve-init-server.js +77 -0
  304. package/dist/src/lib/resolve-init-server.js.map +1 -0
  305. package/dist/src/lib/resolve-platform.d.ts +74 -0
  306. package/dist/src/lib/resolve-platform.js +105 -0
  307. package/dist/src/lib/resolve-platform.js.map +1 -0
  308. package/dist/src/lib/run-status.d.ts +19 -0
  309. package/dist/src/lib/run-status.generated.d.ts +39 -0
  310. package/dist/src/lib/run-status.generated.js +66 -0
  311. package/dist/src/lib/run-status.generated.js.map +1 -0
  312. package/dist/src/lib/run-status.js +19 -0
  313. package/dist/src/lib/run-status.js.map +1 -0
  314. package/dist/src/lib/server-text-normalization.d.ts +51 -0
  315. package/dist/src/lib/server-text-normalization.js +90 -0
  316. package/dist/src/lib/server-text-normalization.js.map +1 -0
  317. package/dist/src/lib/server-url.d.ts +22 -0
  318. package/dist/src/lib/server-url.js +33 -0
  319. package/dist/src/lib/server-url.js.map +1 -0
  320. package/dist/src/lib/signing-secret-status.d.ts +81 -0
  321. package/dist/src/lib/signing-secret-status.js +116 -0
  322. package/dist/src/lib/signing-secret-status.js.map +1 -0
  323. package/dist/src/lib/skill-installer.d.ts +25 -0
  324. package/dist/src/lib/skill-installer.js +266 -0
  325. package/dist/src/lib/skill-installer.js.map +1 -0
  326. package/dist/src/lib/snapshots.d.ts +99 -0
  327. package/dist/src/lib/snapshots.js +357 -0
  328. package/dist/src/lib/snapshots.js.map +1 -0
  329. package/dist/src/lib/swift-codegen/dbGenerator.d.ts +113 -0
  330. package/dist/src/lib/swift-codegen/dbGenerator.js +914 -0
  331. package/dist/src/lib/swift-codegen/dbGenerator.js.map +1 -0
  332. package/dist/src/lib/swift-codegen/dbSwiftTypes.d.ts +42 -0
  333. package/dist/src/lib/swift-codegen/dbSwiftTypes.js +100 -0
  334. package/dist/src/lib/swift-codegen/dbSwiftTypes.js.map +1 -0
  335. package/dist/src/lib/swift-codegen/generator.d.ts +94 -0
  336. package/dist/src/lib/swift-codegen/generator.js +440 -0
  337. package/dist/src/lib/swift-codegen/generator.js.map +1 -0
  338. package/dist/src/lib/swift-codegen/schemaToSwift.d.ts +72 -0
  339. package/dist/src/lib/swift-codegen/schemaToSwift.js +644 -0
  340. package/dist/src/lib/swift-codegen/schemaToSwift.js.map +1 -0
  341. package/dist/src/lib/swift-codegen/siblingSymbols.d.ts +94 -0
  342. package/dist/src/lib/swift-codegen/siblingSymbols.js +155 -0
  343. package/dist/src/lib/swift-codegen/siblingSymbols.js.map +1 -0
  344. package/dist/src/lib/swift-codegen/swiftNaming.d.ts +85 -0
  345. package/dist/src/lib/swift-codegen/swiftNaming.js +198 -0
  346. package/dist/src/lib/swift-codegen/swiftNaming.js.map +1 -0
  347. package/dist/src/lib/sync-dir-selector.d.ts +21 -0
  348. package/dist/src/lib/sync-dir-selector.js +30 -0
  349. package/dist/src/lib/sync-dir-selector.js.map +1 -0
  350. package/dist/src/lib/sync-paths.d.ts +111 -0
  351. package/dist/src/lib/sync-paths.js +198 -0
  352. package/dist/src/lib/sync-paths.js.map +1 -0
  353. package/dist/src/lib/sync-resource-types.d.ts +544 -0
  354. package/dist/src/lib/sync-resource-types.js +975 -0
  355. package/dist/src/lib/sync-resource-types.js.map +1 -0
  356. package/dist/src/lib/sync-selectors.d.ts +95 -0
  357. package/dist/src/lib/sync-selectors.js +228 -0
  358. package/dist/src/lib/sync-selectors.js.map +1 -0
  359. package/dist/src/lib/template.d.ts +170 -0
  360. package/dist/src/lib/template.js +484 -68
  361. package/dist/src/lib/template.js.map +1 -1
  362. package/dist/src/lib/test-case-keys.d.ts +29 -0
  363. package/dist/src/lib/test-case-keys.js +55 -0
  364. package/dist/src/lib/test-case-keys.js.map +1 -0
  365. package/dist/src/lib/test-case-variables.d.ts +15 -0
  366. package/dist/src/lib/test-case-variables.js +29 -0
  367. package/dist/src/lib/test-case-variables.js.map +1 -0
  368. package/dist/src/lib/token-inject.d.ts +56 -0
  369. package/dist/src/lib/token-inject.js +204 -0
  370. package/dist/src/lib/token-inject.js.map +1 -0
  371. package/dist/src/lib/toml-database-config.d.ts +123 -0
  372. package/dist/src/lib/toml-database-config.js +527 -0
  373. package/dist/src/lib/toml-database-config.js.map +1 -0
  374. package/dist/src/lib/toml-metadata-config.d.ts +151 -0
  375. package/dist/src/lib/toml-metadata-config.js +476 -0
  376. package/dist/src/lib/toml-metadata-config.js.map +1 -0
  377. package/dist/src/lib/toml-native-form.d.ts +46 -0
  378. package/dist/src/lib/toml-native-form.js +78 -0
  379. package/dist/src/lib/toml-native-form.js.map +1 -0
  380. package/dist/src/lib/toml-params-validator.d.ts +129 -0
  381. package/dist/src/lib/toml-params-validator.js +298 -0
  382. package/dist/src/lib/toml-params-validator.js.map +1 -0
  383. package/dist/src/lib/toml-scalar-edit.d.ts +43 -0
  384. package/dist/src/lib/toml-scalar-edit.js +283 -0
  385. package/dist/src/lib/toml-scalar-edit.js.map +1 -0
  386. package/dist/src/lib/user-selector.d.ts +24 -0
  387. package/dist/src/lib/user-selector.js +33 -0
  388. package/dist/src/lib/user-selector.js.map +1 -0
  389. package/dist/src/lib/version-check.d.ts +35 -0
  390. package/dist/src/lib/version-check.js +241 -0
  391. package/dist/src/lib/version-check.js.map +1 -0
  392. package/dist/src/lib/watch.d.ts +121 -0
  393. package/dist/src/lib/watch.js +169 -0
  394. package/dist/src/lib/watch.js.map +1 -0
  395. package/dist/src/lib/workflow-apply.d.ts +110 -0
  396. package/dist/src/lib/workflow-apply.js +164 -0
  397. package/dist/src/lib/workflow-apply.js.map +1 -0
  398. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.d.ts +129 -0
  399. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js +269 -0
  400. package/dist/src/lib/workflow-codegen/generated-schema-descriptor.js.map +1 -0
  401. package/dist/src/lib/workflow-codegen/generator.d.ts +96 -0
  402. package/dist/src/lib/workflow-codegen/generator.js +361 -0
  403. package/dist/src/lib/workflow-codegen/generator.js.map +1 -0
  404. package/dist/src/lib/workflow-codegen/invokerIR.d.ts +94 -0
  405. package/dist/src/lib/workflow-codegen/invokerIR.js +76 -0
  406. package/dist/src/lib/workflow-codegen/invokerIR.js.map +1 -0
  407. package/dist/src/lib/workflow-codegen/naming.d.ts +33 -0
  408. package/dist/src/lib/workflow-codegen/naming.js +81 -0
  409. package/dist/src/lib/workflow-codegen/naming.js.map +1 -0
  410. package/dist/src/lib/workflow-codegen/schemaToTs.d.ts +80 -0
  411. package/dist/src/lib/workflow-codegen/schemaToTs.js +303 -0
  412. package/dist/src/lib/workflow-codegen/schemaToTs.js.map +1 -0
  413. package/dist/src/lib/workflow-config-apply.d.ts +70 -0
  414. package/dist/src/lib/workflow-config-apply.js +137 -0
  415. package/dist/src/lib/workflow-config-apply.js.map +1 -0
  416. package/dist/src/lib/workflow-config-sidecar.d.ts +63 -0
  417. package/dist/src/lib/workflow-config-sidecar.js +96 -0
  418. package/dist/src/lib/workflow-config-sidecar.js.map +1 -0
  419. package/dist/src/lib/workflow-defaults.d.ts +29 -0
  420. package/dist/src/lib/workflow-defaults.js +41 -0
  421. package/dist/src/lib/workflow-defaults.js.map +1 -0
  422. package/dist/src/lib/workflow-fragments.d.ts +64 -0
  423. package/dist/src/lib/workflow-fragments.js +342 -0
  424. package/dist/src/lib/workflow-fragments.js.map +1 -0
  425. package/dist/src/lib/workflow-include-preserve.d.ts +76 -0
  426. package/dist/src/lib/workflow-include-preserve.js +286 -0
  427. package/dist/src/lib/workflow-include-preserve.js.map +1 -0
  428. package/dist/src/lib/workflow-payload.d.ts +98 -0
  429. package/dist/src/lib/workflow-payload.js +178 -0
  430. package/dist/src/lib/workflow-payload.js.map +1 -0
  431. package/dist/src/lib/workflow-toml-validator.d.ts +202 -0
  432. package/dist/src/lib/workflow-toml-validator.js +757 -0
  433. package/dist/src/lib/workflow-toml-validator.js.map +1 -0
  434. package/dist/src/types/index.d.ts +581 -0
  435. package/dist/src/validators.d.ts +65 -0
  436. package/dist/src/validators.js +64 -0
  437. package/dist/src/validators.js.map +1 -0
  438. package/package.json +32 -8
@@ -1,18 +1,35 @@
1
- import { readFileSync } from "fs";
2
- import * as TOML from "@iarna/toml";
1
+ import chalk from "chalk";
3
2
  import { ApiClient } from "../lib/api-client.js";
4
3
  import { resolveAppId } from "../lib/config.js";
5
- import { success, error, info, keyValue, formatTable, formatId, formatDate, formatStatus, formatDuration, json, divider, } from "../lib/output.js";
4
+ import { success, error, info, keyValue, result as printResult, formatTable, formatId, formatDate, formatStatus, formatDuration, json, divider, } from "../lib/output.js";
5
+ import { buildIntegrationEnvelope } from "../lib/log-inspection.js";
6
+ import { confirmPrompt } from "../lib/confirm-prompt.js";
7
+ import { parseStatusFilter } from "../lib/object-status-filter.js";
8
+ import { testCaseInputVariables } from "../lib/test-case-variables.js";
6
9
  export function registerIntegrationsCommands(program) {
7
10
  const integrations = program
8
11
  .command("integrations")
9
- .description("Configure external HTTP API connections and manage secrets")
12
+ .description("Configure external HTTP API connections")
10
13
  .addHelpText("after", `
11
14
  Examples:
12
15
  $ primitive integrations list
13
- $ primitive integrations create --from-file weather-api.toml
16
+ $ primitive config create integration weather-api # scaffold integrations/weather-api.toml
17
+ $ primitive config push --only integration/weather-api # apply it
14
18
  $ primitive integrations test 01HXY...
15
- $ primitive integrations secrets add 01HXY... --data '{"apiKey":"..."}'
19
+ $ primitive integrations archive 01HXY... # retire it (soft delete)
20
+
21
+ Storing credentials for an integration:
22
+ $ primitive secrets set MY_API_KEY --value <value>
23
+ # then reference it in integration config via {{secrets.MY_API_KEY}}
24
+ `);
25
+ // Server-side configuration is authored in TOML and applied with `config push`
26
+ // (issue #2645) — this group no longer carries config-setting flags.
27
+ integrations.addHelpText("after", `
28
+ Configuration lives in integrations/<key>.toml:
29
+ $ primitive config fields integration # the file's keys, types and defaults
30
+ $ primitive config create integration <key> # scaffold one locally
31
+ $ primitive config set integration/<key> <path>=<value>
32
+ $ primitive config push --only integration/<key>
16
33
  `);
17
34
  // List integrations
18
35
  integrations
@@ -20,14 +37,20 @@ Examples:
20
37
  .description("List integrations")
21
38
  .argument("[app-id]", "App ID (uses current app if not specified)")
22
39
  .option("--app <app-id>", "App ID")
23
- .option("--status <status>", "Filter by status: draft, active, archived")
40
+ .option("--status <status>", "Filter by status: active, inactive, archived")
24
41
  .option("--json", "Output as JSON")
25
42
  .action(async (appId, options) => {
26
43
  const resolvedAppId = resolveAppId(appId, options);
27
44
  const client = new ApiClient();
28
45
  try {
46
+ // #2803 — `draft` is gone; refuse it by name rather than returning the
47
+ // empty list a canonical filter would produce.
29
48
  const { items } = await client.listIntegrations(resolvedAppId, {
30
- status: options.status,
49
+ status: parseStatusFilter("integrations", options.status, [
50
+ "active",
51
+ "inactive",
52
+ "archived",
53
+ ]),
31
54
  });
32
55
  if (options.json) {
33
56
  json(items);
@@ -50,195 +73,161 @@ Examples:
50
73
  process.exit(1);
51
74
  }
52
75
  });
53
- // Create integration
76
+ // #2645 criterion 9 / #2803 — the operational verbs. They are the only
77
+ // writers of `status`, which is server-owned and no longer a TOML key.
54
78
  integrations
55
- .command("create")
56
- .description("Create a new integration")
57
- .argument("[app-id]", "App ID (uses current app if not specified)")
58
- .option("--app <app-id>", "App ID")
59
- .option("--key <key>", "Integration key (unique identifier)")
60
- .option("--name <name>", "Display name")
61
- .option("--description <desc>", "Description")
62
- .option("--base-url <url>", "Base URL for API requests")
63
- .option("--allowed-methods <methods>", "Comma-separated list of allowed HTTP methods")
64
- .option("--allowed-paths <paths>", "Comma-separated list of allowed paths")
65
- .option("--timeout-ms <ms>", "Request timeout in milliseconds")
66
- .option("--from-file <path>", "Load integration from TOML file")
79
+ .command("disable")
80
+ .description("Take integration out of service now. Operational, not configuration: `status` is server-owned and 'config push' can neither set nor clear it.")
81
+ .argument("<integration-id>", "Integration ID")
82
+ .option("--app <app-id>", "App ID (uses current app if not specified)")
67
83
  .option("--json", "Output as JSON")
68
- .action(async (appId, options) => {
69
- const resolvedAppId = resolveAppId(appId, options);
84
+ .action(async (id, options) => {
85
+ const resolvedAppId = resolveAppId(undefined, options);
70
86
  const client = new ApiClient();
71
- let payload;
72
- if (options.fromFile) {
73
- try {
74
- const content = readFileSync(options.fromFile, "utf-8");
75
- const tomlData = TOML.parse(content);
76
- payload = {
77
- integrationKey: tomlData.integration?.key || tomlData.key,
78
- displayName: tomlData.integration?.displayName || tomlData.displayName,
79
- description: tomlData.integration?.description || tomlData.description,
80
- requestConfig: tomlData.requestConfig || {},
81
- timeoutMs: tomlData.integration?.timeoutMs || tomlData.timeoutMs,
82
- };
83
- }
84
- catch (err) {
85
- error(`Failed to read TOML file: ${err.message}`);
86
- process.exit(1);
87
- }
88
- }
89
- else {
90
- if (!options.key || !options.name || !options.baseUrl) {
91
- error("Required: --key, --name, --base-url (or use --from-file)");
92
- process.exit(1);
93
- }
94
- payload = {
95
- integrationKey: options.key,
96
- displayName: options.name,
97
- description: options.description,
98
- requestConfig: {
99
- baseUrl: options.baseUrl,
100
- allowedMethods: options.allowedMethods?.split(",").map((s) => s.trim()),
101
- allowedPaths: options.allowedPaths?.split(",").map((s) => s.trim()),
102
- },
103
- timeoutMs: options.timeoutMs ? parseInt(options.timeoutMs) : undefined,
104
- };
105
- }
106
87
  try {
107
- const result = await client.createIntegration(resolvedAppId, payload);
88
+ const result = await client.setIntegrationAvailability(resolvedAppId, id, "disable");
108
89
  if (options.json) {
109
90
  json(result);
110
91
  return;
111
92
  }
112
- success(`Integration created: ${result.displayName}`);
113
- keyValue("Integration ID", result.integrationId);
114
- keyValue("Key", result.integrationKey);
93
+ success(`Integration disabled: ${result.integrationKey || id}`);
115
94
  }
116
95
  catch (err) {
117
96
  error(err.message);
118
97
  process.exit(1);
119
98
  }
120
99
  });
121
- // Get integration
122
100
  integrations
123
- .command("get")
124
- .description("Get integration details")
101
+ .command("enable")
102
+ .description("Put integration back in service.")
125
103
  .argument("<integration-id>", "Integration ID")
126
104
  .option("--app <app-id>", "App ID (uses current app if not specified)")
127
105
  .option("--json", "Output as JSON")
128
- .action(async (integrationId, options) => {
106
+ .action(async (id, options) => {
129
107
  const resolvedAppId = resolveAppId(undefined, options);
130
108
  const client = new ApiClient();
131
109
  try {
132
- const result = await client.getIntegration(resolvedAppId, integrationId);
110
+ const result = await client.setIntegrationAvailability(resolvedAppId, id, "enable");
133
111
  if (options.json) {
134
112
  json(result);
135
113
  return;
136
114
  }
137
- keyValue("Integration ID", result.integrationId);
138
- keyValue("Key", result.integrationKey);
139
- keyValue("Name", result.displayName);
140
- keyValue("Description", result.description);
141
- keyValue("Status", formatStatus(result.status));
142
- keyValue("Timeout", result.timeoutMs ? `${result.timeoutMs}ms` : "-");
143
- if (result.requestConfig) {
144
- divider();
145
- info("Request Config:");
146
- keyValue(" Base URL", result.requestConfig.baseUrl);
147
- keyValue(" Allowed Methods", result.requestConfig.allowedMethods?.join(", ") || "all");
148
- keyValue(" Allowed Paths", result.requestConfig.allowedPaths?.join(", ") || "all");
149
- keyValue(" Response Passthrough", result.requestConfig.responsePassthrough);
150
- if (result.requestConfig.bodyMode) {
151
- keyValue(" Body Mode", result.requestConfig.bodyMode);
152
- }
153
- if (result.requestConfig.multipartFieldMapping?.length) {
154
- keyValue(" Multipart Fields", result.requestConfig.multipartFieldMapping
155
- .map((f) => `${f.fieldName} (${f.type}${f.attachmentIndex != null ? `, attachment[${f.attachmentIndex}]` : ""})`)
156
- .join(", "));
157
- }
158
- }
115
+ success(`Integration enabled: ${result.integrationKey || id}`);
159
116
  }
160
117
  catch (err) {
161
118
  error(err.message);
162
119
  process.exit(1);
163
120
  }
164
121
  });
165
- // Update integration
122
+ // #2907 — the delete flow's CLI spelling. Not a second writer of `status`:
123
+ // this is the plain `DELETE` the server has always answered by writing the
124
+ // tombstone, which until now only the admin API and the console could reach.
125
+ // Named `archive`, not `delete`, because a configuration noun gets no
126
+ // `delete` verb (docs/cli-design.md) and prune-by-push stays the only CLI
127
+ // hard-delete path.
166
128
  integrations
167
- .command("update")
168
- .description("Update an integration")
129
+ .command("archive")
130
+ .description("Retire an integration (soft delete). Delete-lifecycle, not `disable`: the row is kept, goes on holding its key, and there is no un-archive.")
169
131
  .argument("<integration-id>", "Integration ID")
170
132
  .option("--app <app-id>", "App ID (uses current app if not specified)")
171
- .option("--name <name>", "Display name")
172
- .option("--description <desc>", "Description")
173
- .option("--status <status>", "Status: draft, active, archived")
174
- .option("--timeout-ms <ms>", "Request timeout in milliseconds")
133
+ .option("-y, --yes", "Skip confirmation prompt")
175
134
  .option("--json", "Output as JSON")
176
- .action(async (integrationId, options) => {
135
+ .addHelpText("after", `
136
+ What archiving an integration costs:
137
+ The proxy refuses it, and so does every workflow step that calls it.
138
+ The archived row still holds its integrationKey, so a push cannot re-create
139
+ one under the same key.
140
+ \`primitive integrations enable\` refuses an archived integration; there is no
141
+ un-archive.
142
+
143
+ Reclaiming the key means hard-deleting the row:
144
+ $ rm integrations/<key>.toml
145
+ $ primitive config push --prune # confirmed; hard-deletes the row
146
+ # or hard-delete it in the console, then re-add the file and push.
147
+ `)
148
+ .action(async (id, options) => {
177
149
  const resolvedAppId = resolveAppId(undefined, options);
178
- const payload = {};
179
- if (options.name)
180
- payload.displayName = options.name;
181
- if (options.description)
182
- payload.description = options.description;
183
- if (options.status)
184
- payload.status = options.status;
185
- if (options.timeoutMs)
186
- payload.timeoutMs = parseInt(options.timeoutMs);
187
- if (Object.keys(payload).length === 0) {
188
- error("No update options specified.");
189
- process.exit(1);
150
+ if (!options.yes) {
151
+ let confirmed;
152
+ try {
153
+ confirmed = await confirmPrompt(`Archive integration ${id}? It is retired, goes on holding its key, ` +
154
+ `and there is no un-archive.`);
155
+ }
156
+ catch (err) {
157
+ error(err.message);
158
+ process.exit(1);
159
+ }
160
+ if (!confirmed) {
161
+ info("Cancelled.");
162
+ return;
163
+ }
190
164
  }
191
165
  const client = new ApiClient();
192
166
  try {
193
- const result = await client.updateIntegration(resolvedAppId, integrationId, payload);
167
+ // The soft delete: no `hard`, so the server writes the tombstone and
168
+ // keeps the row (and its canonical block mirror) in step.
169
+ const result = await client.deleteIntegration(resolvedAppId, id);
194
170
  if (options.json) {
195
171
  json(result);
196
172
  return;
197
173
  }
198
- success("Integration updated.");
174
+ success(`Integration archived: ${id}`);
175
+ info("It is retired and still holds its key — reclaim the key by removing its file and running a confirmed `primitive config push --prune`.");
199
176
  }
200
177
  catch (err) {
201
178
  error(err.message);
202
179
  process.exit(1);
203
180
  }
204
181
  });
205
- // Delete integration
206
182
  integrations
207
- .command("delete")
208
- .description("Delete or archive an integration")
183
+ .command("get")
184
+ .description("Get integration details")
209
185
  .argument("<integration-id>", "Integration ID")
210
186
  .option("--app <app-id>", "App ID (uses current app if not specified)")
211
- .option("--hard", "Permanently delete instead of archive")
212
- .option("-y, --yes", "Skip confirmation prompt")
187
+ .option("--json", "Output as JSON")
213
188
  .action(async (integrationId, options) => {
214
189
  const resolvedAppId = resolveAppId(undefined, options);
215
- if (!options.yes) {
216
- const action = options.hard ? "permanently delete" : "archive";
217
- const inquirer = await import("inquirer");
218
- const { confirm } = await inquirer.default.prompt([
219
- {
220
- type: "confirm",
221
- name: "confirm",
222
- message: `Are you sure you want to ${action} integration ${integrationId}?`,
223
- default: false,
224
- },
225
- ]);
226
- if (!confirm) {
227
- info("Cancelled.");
228
- return;
229
- }
230
- }
231
190
  const client = new ApiClient();
232
191
  try {
233
- await client.deleteIntegration(resolvedAppId, integrationId, options.hard);
234
- success(`Integration ${options.hard ? "deleted" : "archived"}.`);
192
+ const result = await client.getIntegration(resolvedAppId, integrationId);
193
+ if (options.json) {
194
+ json(result);
195
+ return;
196
+ }
197
+ printResult("Integration ID", result.integrationId);
198
+ printResult("Key", result.integrationKey);
199
+ printResult("Name", result.displayName);
200
+ printResult("Description", result.description);
201
+ printResult("Status", formatStatus(result.status));
202
+ printResult("Timeout", result.timeoutMs ? `${result.timeoutMs}ms` : "-");
203
+ // #2631: no rule means every non-admin call is denied. Print that in
204
+ // words — a blank or "-" would read as "unrestricted" and hide an
205
+ // integration that was never given a rule.
206
+ printResult("Access Rule", typeof result.accessRule === "string" && result.accessRule !== ""
207
+ ? result.accessRule
208
+ : "(none — all non-admin calls are denied; set one to allow callers)");
209
+ if (result.requestConfig) {
210
+ divider();
211
+ info("Request Config:");
212
+ printResult(" Base URL", result.requestConfig.baseUrl);
213
+ printResult(" Allowed Methods", result.requestConfig.allowedMethods?.join(", ") || "all");
214
+ printResult(" Allowed Paths", result.requestConfig.allowedPaths?.join(", ") || "all");
215
+ printResult(" Response Passthrough", result.requestConfig.responsePassthrough);
216
+ if (result.requestConfig.bodyMode) {
217
+ printResult(" Body Mode", result.requestConfig.bodyMode);
218
+ }
219
+ if (result.requestConfig.multipartFieldMapping?.length) {
220
+ printResult(" Multipart Fields", result.requestConfig.multipartFieldMapping
221
+ .map((f) => `${f.fieldName} (${f.type}${f.attachmentIndex != null ? `, attachment[${f.attachmentIndex}]` : ""})`)
222
+ .join(", "));
223
+ }
224
+ }
235
225
  }
236
226
  catch (err) {
237
227
  error(err.message);
238
228
  process.exit(1);
239
229
  }
240
230
  });
241
- // Test integration
242
231
  integrations
243
232
  .command("test")
244
233
  .description("Test an integration by making a request")
@@ -304,20 +293,33 @@ Examples:
304
293
  // List integration logs
305
294
  integrations
306
295
  .command("logs")
307
- .description("View integration request logs")
296
+ .description("View integration request logs (includes workflow-initiated calls; filter with --source workflow|user|admin|test)")
308
297
  .argument("<integration-id>", "Integration ID")
309
298
  .option("--app <app-id>", "App ID (uses current app if not specified)")
310
299
  .option("--limit <n>", "Number of logs to show", "20")
300
+ .option("--source <source>", "Filter by call source: user, admin, test, or workflow")
301
+ .option("--status <status>", "Filter by upstream HTTP status (e.g. 200, 500)")
302
+ .option("--from <iso>", "Only logs at or after this ISO timestamp")
303
+ .option("--to <iso>", "Only logs at or before this ISO timestamp")
311
304
  .option("--json", "Output as JSON")
312
305
  .action(async (integrationId, options) => {
313
306
  const resolvedAppId = resolveAppId(undefined, options);
314
307
  const client = new ApiClient();
315
308
  try {
309
+ const validSources = new Set(["user", "admin", "test", "workflow"]);
310
+ if (options.source && !validSources.has(options.source)) {
311
+ error(`Invalid --source value '${options.source}'. Must be one of: user, admin, test, workflow.`);
312
+ process.exit(1);
313
+ }
316
314
  const logs = await client.listIntegrationLogs(resolvedAppId, integrationId, {
317
315
  limit: parseInt(options.limit),
316
+ ...(options.source && { source: options.source }),
317
+ ...(options.status && { status: options.status }),
318
+ ...(options.from && { from: options.from }),
319
+ ...(options.to && { to: options.to }),
318
320
  });
319
321
  if (options.json) {
320
- json(logs);
322
+ json(buildIntegrationEnvelope(logs));
321
323
  return;
322
324
  }
323
325
  if (!logs || logs.length === 0) {
@@ -326,10 +328,13 @@ Examples:
326
328
  }
327
329
  console.log(formatTable(logs, [
328
330
  { header: "TIME", key: "timestamp", format: formatDate },
331
+ { header: "SOURCE", key: "source", format: (v) => v || "user" },
329
332
  { header: "METHOD", key: "method" },
330
333
  { header: "PATH", key: "path" },
331
334
  { header: "STATUS", key: "status" },
332
335
  { header: "DURATION", key: "durationMs", format: formatDuration },
336
+ { header: "WORKFLOW", key: "workflowKey", format: (v) => v || "" },
337
+ { header: "RUN", key: "runId", format: (v) => (v ? formatId(v) : "") },
333
338
  { header: "TRACE", key: "traceId", format: formatId },
334
339
  ]));
335
340
  }
@@ -338,12 +343,28 @@ Examples:
338
343
  process.exit(1);
339
344
  }
340
345
  });
341
- // Secrets subcommand
342
- const secrets = integrations.command("secrets").description("Manage integration secrets");
343
- // List secrets
344
- secrets
346
+ // ============================================
347
+ // TESTS SUBCOMMAND
348
+ // ============================================
349
+ const tests = integrations
350
+ .command("tests")
351
+ .description("Run and inspect integration test cases")
352
+ .addHelpText("after", `
353
+ Test cases are authored in TOML at integrations/<key>.tests/<name>.toml and
354
+ applied with \`primitive config push\` (issue #2769); \`config fields integration\`
355
+ lists the fields. Deleting a case is removing its file and running
356
+ \`config push --prune\`.
357
+
358
+ Examples:
359
+ $ primitive integrations tests list <integration-id>
360
+ $ primitive integrations tests run <integration-id> <test-case-id>
361
+ $ primitive integrations tests run-all <integration-id>
362
+ $ primitive integrations tests run-all <integration-id> --test-cases 01ABC,01DEF,01GHI
363
+ `);
364
+ // List test cases
365
+ tests
345
366
  .command("list")
346
- .description("List secrets for an integration")
367
+ .description("List test cases for an integration")
347
368
  .argument("<integration-id>", "Integration ID")
348
369
  .option("--app <app-id>", "App ID (uses current app if not specified)")
349
370
  .option("--json", "Output as JSON")
@@ -351,20 +372,19 @@ Examples:
351
372
  const resolvedAppId = resolveAppId(undefined, options);
352
373
  const client = new ApiClient();
353
374
  try {
354
- const secretsList = await client.listIntegrationSecrets(resolvedAppId, integrationId);
375
+ const { items } = await client.listTestCases(resolvedAppId, "integration", integrationId);
355
376
  if (options.json) {
356
- json(secretsList);
377
+ json(items);
357
378
  return;
358
379
  }
359
- if (!secretsList || secretsList.length === 0) {
360
- info("No secrets found.");
380
+ if (!items || items.length === 0) {
381
+ info("No test cases found.");
361
382
  return;
362
383
  }
363
- console.log(formatTable(secretsList, [
364
- { header: "ID", key: "secretId", format: formatId },
365
- { header: "VERSION", key: "version" },
366
- { header: "SUMMARY", key: "secretSummary" },
367
- { header: "STATUS", key: "status", format: formatStatus },
384
+ console.log(formatTable(items, [
385
+ { header: "ID", key: "testCaseId", format: formatId },
386
+ { header: "NAME", key: "name" },
387
+ { header: "CONFIG", key: "configId", format: (v) => v ? formatId(v) : "-" },
368
388
  { header: "CREATED", key: "createdAt", format: formatDate },
369
389
  ]));
370
390
  }
@@ -373,61 +393,243 @@ Examples:
373
393
  process.exit(1);
374
394
  }
375
395
  });
376
- // Add secret
377
- secrets
378
- .command("add")
379
- .description("Add a secret to an integration")
396
+ // Get test case
397
+ tests
398
+ .command("get")
399
+ .description("Get test case details")
380
400
  .argument("<integration-id>", "Integration ID")
401
+ .argument("<test-case-id>", "Test Case ID")
381
402
  .option("--app <app-id>", "App ID (uses current app if not specified)")
382
- .option("--data <json>", "Secret data as JSON (e.g., '{\"apiKey\":\"...\"}' )")
383
- .option("--summary <text>", "Description of the secret")
384
403
  .option("--json", "Output as JSON")
385
- .action(async (integrationId, options) => {
404
+ .action(async (integrationId, testCaseId, options) => {
386
405
  const resolvedAppId = resolveAppId(undefined, options);
387
- if (!options.data) {
388
- error("--data is required (JSON object with secret values)");
406
+ const client = new ApiClient();
407
+ try {
408
+ const result = await client.getTestCase(resolvedAppId, "integration", integrationId, testCaseId);
409
+ if (options.json) {
410
+ json(result);
411
+ return;
412
+ }
413
+ printResult("Test Case ID", result.testCaseId);
414
+ printResult("Name", result.name);
415
+ printResult("Config ID", result.configId || "-");
416
+ printResult("Created", formatDate(result.createdAt));
417
+ divider();
418
+ info("Input Variables:");
419
+ console.log(JSON.stringify(testCaseInputVariables(result.inputVariables), null, 2));
420
+ if (result.expectedOutputPattern) {
421
+ divider();
422
+ printResult("Expected Pattern", result.expectedOutputPattern);
423
+ }
424
+ if (result.expectedOutputContains) {
425
+ divider();
426
+ info("Expected Contains:");
427
+ try {
428
+ console.log(JSON.stringify(JSON.parse(result.expectedOutputContains), null, 2));
429
+ }
430
+ catch {
431
+ console.log(result.expectedOutputContains);
432
+ }
433
+ }
434
+ if (result.expectedJsonSubset) {
435
+ divider();
436
+ info("Expected JSON Subset:");
437
+ try {
438
+ console.log(JSON.stringify(JSON.parse(result.expectedJsonSubset), null, 2));
439
+ }
440
+ catch {
441
+ console.log(result.expectedJsonSubset);
442
+ }
443
+ }
444
+ if (result.evaluatorPromptId) {
445
+ divider();
446
+ printResult("Evaluator Prompt", result.evaluatorPromptId);
447
+ printResult("Evaluator Config", result.evaluatorConfigId || "-");
448
+ }
449
+ }
450
+ catch (err) {
451
+ error(err.message);
389
452
  process.exit(1);
390
453
  }
391
- let secretData;
454
+ });
455
+ // Run a single test case
456
+ tests
457
+ .command("run")
458
+ .description("Run a single test case")
459
+ .argument("<integration-id>", "Integration ID")
460
+ .argument("<test-case-id>", "Test Case ID")
461
+ .option("--app <app-id>", "App ID (uses current app if not specified)")
462
+ .option("--config <config-id>", "Override config ID")
463
+ .option("--json", "Output as JSON")
464
+ .action(async (integrationId, testCaseId, options) => {
465
+ const resolvedAppId = resolveAppId(undefined, options);
466
+ const client = new ApiClient();
392
467
  try {
393
- secretData = JSON.parse(options.data);
468
+ // Get test case to retrieve its variables
469
+ const testCase = await client.getTestCase(resolvedAppId, "integration", integrationId, testCaseId);
470
+ // #2968 — the case's variables ARE the request the run issues, so a
471
+ // dropped `inputVariables` here is the config's bare defaults instead
472
+ // of the case's method, path and body. The server hands them back
473
+ // parsed; older servers hand back JSON text.
474
+ const variables = testCaseInputVariables(testCase.inputVariables);
475
+ const result = await client.executeBlockTest(resolvedAppId, "integration", integrationId, {
476
+ variables,
477
+ testCaseId,
478
+ configId: options.config || testCase.configId,
479
+ });
480
+ if (options.json) {
481
+ json(result);
482
+ return;
483
+ }
484
+ const passed = result.verification?.passed;
485
+ if (passed) {
486
+ success("Test PASSED");
487
+ }
488
+ else {
489
+ error("Test FAILED");
490
+ }
491
+ keyValue("Duration", formatDuration(result.metrics?.durationMs));
492
+ if (result.verification) {
493
+ divider();
494
+ info("Verification:");
495
+ const v = result.verification;
496
+ keyValue(" Passed", v.passed ? chalk.green("Yes") : chalk.red("No"));
497
+ keyValue(" Checks", `${v.summary?.passed || 0}/${v.summary?.total || 0} passed`);
498
+ if (v.checks && v.checks.length > 0) {
499
+ console.log();
500
+ for (const check of v.checks) {
501
+ const icon = check.passed ? chalk.green("\u2713") : chalk.red("\u2717");
502
+ console.log(` ${icon} ${check.name}`);
503
+ if (!check.passed && check.message) {
504
+ console.log(` ${chalk.dim(check.message)}`);
505
+ }
506
+ }
507
+ }
508
+ }
509
+ if (result.output) {
510
+ divider();
511
+ info("Output:");
512
+ console.log(typeof result.output === "string" ? result.output : JSON.stringify(result.output, null, 2));
513
+ }
514
+ if (result.error) {
515
+ divider();
516
+ error(`Error: ${result.error}`);
517
+ }
518
+ if (!passed) {
519
+ process.exit(1);
520
+ }
394
521
  }
395
- catch {
396
- error("Invalid JSON in --data");
522
+ catch (err) {
523
+ error(err.message);
397
524
  process.exit(1);
398
525
  }
526
+ });
527
+ // Run all test cases (or a specific group)
528
+ tests
529
+ .command("run-all")
530
+ .description("Run all test cases for an integration, or a specific subset")
531
+ .argument("<integration-id>", "Integration ID")
532
+ .option("--app <app-id>", "App ID (uses current app if not specified)")
533
+ .option("--config <config-id>", "Override config ID for all tests")
534
+ .option("--test-cases <ids>", "Comma-separated list of test case IDs to run (runs only these)")
535
+ .option("--json", "Output as JSON")
536
+ .action(async (integrationId, options) => {
537
+ const resolvedAppId = resolveAppId(undefined, options);
399
538
  const client = new ApiClient();
400
539
  try {
401
- const result = await client.addIntegrationSecret(resolvedAppId, integrationId, {
402
- secretData,
403
- secretSummary: options.summary,
540
+ // Parse test case IDs if provided
541
+ let testCaseIds;
542
+ if (options.testCases) {
543
+ testCaseIds = options.testCases.split(",").map((id) => id.trim()).filter(Boolean);
544
+ if (testCaseIds.length === 0) {
545
+ error("No valid test case IDs provided in --test-cases");
546
+ process.exit(1);
547
+ }
548
+ }
549
+ if (!options.json) {
550
+ if (testCaseIds) {
551
+ info(`Running ${testCaseIds.length} selected test case(s)...`);
552
+ }
553
+ else {
554
+ info("Running all test cases...");
555
+ }
556
+ }
557
+ const result = await client.runAllTestCases(resolvedAppId, "integration", integrationId, {
558
+ overrideConfigId: options.config,
559
+ testCaseIds,
404
560
  });
405
561
  if (options.json) {
406
562
  json(result);
407
563
  return;
408
564
  }
409
- success("Secret added.");
410
- keyValue("Secret ID", result?.secretId);
411
- keyValue("Version", result?.version);
565
+ const { summary, runs, comparisonGroup } = result;
566
+ divider();
567
+ keyValue("Comparison Group", comparisonGroup);
568
+ keyValue("Total Tests", summary.total);
569
+ keyValue("Passed", chalk.green(summary.passed));
570
+ keyValue("Failed", summary.failed > 0 ? chalk.red(summary.failed) : "0");
571
+ divider();
572
+ if (runs && runs.length > 0) {
573
+ for (const r of runs) {
574
+ const passed = r.verification?.passed;
575
+ const icon = passed ? chalk.green("\u2713") : chalk.red("\u2717");
576
+ const status = passed ? "PASSED" : "FAILED";
577
+ console.log(`${icon} ${r.testCaseName} - ${status}`);
578
+ if (!passed && r.verification?.details?.reason) {
579
+ console.log(` ${chalk.dim(r.verification.details.reason)}`);
580
+ }
581
+ }
582
+ }
583
+ // Exit with error code if any tests failed
584
+ if (summary.failed > 0) {
585
+ process.exit(1);
586
+ }
412
587
  }
413
588
  catch (err) {
414
589
  error(err.message);
415
590
  process.exit(1);
416
591
  }
417
592
  });
418
- // Archive secret
419
- secrets
420
- .command("archive")
421
- .description("Archive a secret")
593
+ // List test runs
594
+ tests
595
+ .command("runs")
596
+ .description("List recent test runs for an integration")
422
597
  .argument("<integration-id>", "Integration ID")
423
- .argument("<secret-id>", "Secret ID")
424
598
  .option("--app <app-id>", "App ID (uses current app if not specified)")
425
- .action(async (integrationId, secretId, options) => {
599
+ .option("--limit <n>", "Maximum number of runs to show", "20")
600
+ .option("--group <group>", "Filter by comparison group")
601
+ .option("--json", "Output as JSON")
602
+ .action(async (integrationId, options) => {
426
603
  const resolvedAppId = resolveAppId(undefined, options);
427
604
  const client = new ApiClient();
428
605
  try {
429
- await client.archiveIntegrationSecret(resolvedAppId, integrationId, secretId);
430
- success("Secret archived.");
606
+ const { items } = await client.listTestRuns(resolvedAppId, "integration", integrationId, {
607
+ limit: parseInt(options.limit),
608
+ comparisonGroup: options.group,
609
+ });
610
+ if (options.json) {
611
+ json(items);
612
+ return;
613
+ }
614
+ if (!items || items.length === 0) {
615
+ info("No test runs found.");
616
+ return;
617
+ }
618
+ console.log(formatTable(items, [
619
+ { header: "RUN ID", key: "runId", format: formatId },
620
+ { header: "TEST CASE ID", key: "testCaseId", format: (v) => v ? formatId(v) : "-" },
621
+ {
622
+ header: "PASSED",
623
+ key: "verificationPassed",
624
+ format: (v) => v === true
625
+ ? chalk.green("Yes")
626
+ : v === false
627
+ ? chalk.red("No")
628
+ : "-",
629
+ },
630
+ { header: "DURATION", key: "durationMs", format: formatDuration },
631
+ { header: "STARTED", key: "startedAt", format: formatDate },
632
+ ]));
431
633
  }
432
634
  catch (err) {
433
635
  error(err.message);