@aifabrix/builder 2.52.0 → 2.53.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 (310) hide show
  1. package/lib/api/datasources-extended.api.js +8 -8
  2. package/lib/api/keycloak.api.js +92 -0
  3. package/lib/api/token-providers.api.js +77 -0
  4. package/lib/api/types/keycloak.types.js +23 -0
  5. package/lib/api/types/token-providers.types.js +65 -0
  6. package/lib/app/deploy-config.js +3 -2
  7. package/lib/app/down.js +16 -1
  8. package/lib/channels/add-channel.js +134 -57
  9. package/lib/channels/approval-guides/chatgpt.js +1 -1
  10. package/lib/channels/approval-guides/index.js +3 -0
  11. package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
  12. package/lib/channels/channel-add-ensure.js +128 -0
  13. package/lib/channels/channel-add-existing.js +72 -0
  14. package/lib/channels/channel-artifact-generator.js +11 -1
  15. package/lib/channels/channel-branding.js +94 -0
  16. package/lib/channels/channel-credential.js +8 -0
  17. package/lib/channels/channel-discovery.js +330 -0
  18. package/lib/channels/channel-external-system.js +1 -1
  19. package/lib/channels/channel-runtime-resolver.js +107 -14
  20. package/lib/channels/channel-status-display.js +36 -3
  21. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  22. package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
  23. package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
  24. package/lib/channels/microsoft-copilot-icons.js +74 -0
  25. package/lib/channels/microsoft-copilot-limits.js +103 -0
  26. package/lib/channels/microsoft-copilot-package.js +178 -52
  27. package/lib/channels/microsoft-copilot-validate.js +227 -0
  28. package/lib/cli/attach-default-help-examples.js +102 -0
  29. package/lib/cli/index.js +4 -0
  30. package/lib/cli/infra-guided.js +13 -6
  31. package/lib/cli/setup-credential-deployment.js +7 -5
  32. package/lib/cli/setup-infra.js +31 -4
  33. package/lib/cli/setup-utility-validate.js +1 -0
  34. package/lib/commands/channel-add-setup.js +28 -9
  35. package/lib/commands/channel.js +14 -10
  36. package/lib/commands/credential-push.js +37 -5
  37. package/lib/commands/integration-definition.js +158 -0
  38. package/lib/commands/package-score.js +72 -0
  39. package/lib/commands/repair-auth-apply.js +19 -5
  40. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  41. package/lib/commands/role-assistant-test-output.js +200 -0
  42. package/lib/commands/role-assistant.js +163 -166
  43. package/lib/datasource/capability/capability-resolve.js +15 -5
  44. package/lib/datasource/capability/copy-operations.js +14 -4
  45. package/lib/deployment/deployer-poll-run.js +2 -2
  46. package/lib/deployment/deployer.js +1 -1
  47. package/lib/deployment/environment.js +2 -2
  48. package/lib/external-system/deploy.js +11 -21
  49. package/lib/infrastructure/index.js +19 -4
  50. package/lib/integration-definition/apply.js +476 -0
  51. package/lib/integration-definition/canonical-json.js +51 -0
  52. package/lib/integration-definition/emit-suite-bid.js +94 -0
  53. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  54. package/lib/integration-definition/enrich-openapi-operations.js +433 -0
  55. package/lib/integration-definition/from-discovery.js +339 -0
  56. package/lib/integration-definition/hash.js +37 -0
  57. package/lib/integration-definition/index.js +37 -0
  58. package/lib/integration-definition/resource-type-catalog.js +59 -0
  59. package/lib/integration-definition/system-kind-enum.js +40 -0
  60. package/lib/integration-definition/validate.js +148 -0
  61. package/lib/lab/package-parity-score.js +417 -0
  62. package/lib/programmatic/builder-api-request.js +5 -1
  63. package/lib/programmatic/builder-help-governance.js +3 -2
  64. package/lib/programmatic/capability-registry.js +20 -0
  65. package/lib/programmatic/help-content/channel-onboarding.md +35 -0
  66. package/lib/programmatic/help-content/cip-overview.md +27 -0
  67. package/lib/programmatic/help-content/connected-system-ui.md +70 -0
  68. package/lib/programmatic/help-content/dimensions-guide.md +23 -0
  69. package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
  70. package/lib/programmatic/help-content/overview.md +25 -0
  71. package/lib/programmatic/help-content/subscription-guide.md +27 -0
  72. package/lib/programmatic/help-content/workflow.md +50 -0
  73. package/lib/programmatic/openapi-component-schemas.js +7 -1
  74. package/lib/programmatic/openapi-descriptions.js +46 -0
  75. package/lib/programmatic/openapi-envelope-examples.js +280 -0
  76. package/lib/programmatic/openapi-operation-bindings.js +50 -0
  77. package/lib/programmatic/openapi-request-schemas.js +40 -0
  78. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  79. package/lib/programmatic/openapi-result-schemas.js +76 -99
  80. package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
  81. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  82. package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
  83. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  84. package/lib/programmatic/openapi-spec.js +11 -1
  85. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  86. package/lib/programmatic/persist-supplied-openapi.js +180 -0
  87. package/lib/programmatic/route-handler-map.js +35 -1
  88. package/lib/programmatic/run-channel-package.js +236 -0
  89. package/lib/programmatic/run-integration-definition.js +77 -0
  90. package/lib/role-assistant/evidence-sync.js +55 -7
  91. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  92. package/lib/role-assistant/knowledge-sync.js +88 -93
  93. package/lib/role-assistant/test-cases-bid.js +155 -0
  94. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  95. package/lib/role-assistant/test-cases-honesty.js +24 -10
  96. package/lib/role-assistant/test-cases.js +28 -0
  97. package/lib/role-assistant/test-runner-attachments.js +118 -0
  98. package/lib/role-assistant/test-runner-bid-apply.js +201 -0
  99. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  100. package/lib/role-assistant/test-runner-start-payload.js +96 -0
  101. package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
  102. package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
  103. package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
  104. package/lib/role-assistant/test-runner-workhub.js +152 -107
  105. package/lib/role-assistant/test-runner.js +5 -63
  106. package/lib/role-assistant/test-suite.js +112 -0
  107. package/lib/schema/application-schema.json +56 -6
  108. package/lib/schema/external-datasource.schema.json +103 -17
  109. package/lib/schema/external-system.schema.json +54 -3
  110. package/lib/schema/integration-definition.schema.json +195 -0
  111. package/lib/utils/authentication-shape.js +6 -0
  112. package/lib/utils/compose-generator.js +10 -1
  113. package/lib/utils/compose-traefik-extra-routes.js +107 -0
  114. package/lib/utils/docker-build.js +2 -2
  115. package/lib/utils/help-builder.js +3 -1
  116. package/lib/utils/promote-dev-docker-image.js +102 -18
  117. package/lib/utils/transient-developer-id.js +28 -0
  118. package/package.json +14 -16
  119. package/templates/README.md +12 -1
  120. package/templates/applications/dataplane/application.yaml +10 -2
  121. package/templates/applications/dataplane/env.template +7 -6
  122. package/templates/applications/miso-controller/application.yaml +23 -8
  123. package/templates/applications/miso-controller/env.template +8 -2
  124. package/templates/applications/miso-controller/rbac.yaml +1 -0
  125. package/templates/channels/README.md +11 -1
  126. package/templates/channels/brand/color-192.png +0 -0
  127. package/templates/channels/brand/dark/128.png +0 -0
  128. package/templates/channels/brand/dark/192.png +0 -0
  129. package/templates/channels/brand/dark/256.png +0 -0
  130. package/templates/channels/brand/dark/32.png +0 -0
  131. package/templates/channels/brand/dark/512.png +0 -0
  132. package/templates/channels/brand/dark/64.png +0 -0
  133. package/templates/channels/brand/light/128.png +0 -0
  134. package/templates/channels/brand/light/192.png +0 -0
  135. package/templates/channels/brand/light/256.png +0 -0
  136. package/templates/channels/brand/light/32.png +0 -0
  137. package/templates/channels/brand/light/512.png +0 -0
  138. package/templates/channels/brand/light/64.png +0 -0
  139. package/templates/channels/brand/mono-white/128.png +0 -0
  140. package/templates/channels/brand/mono-white/192.png +0 -0
  141. package/templates/channels/brand/mono-white/256.png +0 -0
  142. package/templates/channels/brand/mono-white/32.png +0 -0
  143. package/templates/channels/brand/mono-white/512.png +0 -0
  144. package/templates/channels/brand/mono-white/64.png +0 -0
  145. package/templates/channels/brand/outline-32.png +0 -0
  146. package/templates/channels/chatgpt/install.template.md.hbs +6 -4
  147. package/templates/channels/chatgpt/integration/README.md +4 -5
  148. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  149. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
  150. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  151. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
  152. package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
  153. package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
  154. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  155. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  156. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
  157. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
  158. package/templates/channels/slack/integration/README.md +2 -4
  159. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  160. package/templates/channels/teams-bot/integration/README.md +3 -5
  161. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  162. package/templates/python/docker-compose.hbs +36 -0
  163. package/templates/typescript/docker-compose.hbs +36 -0
  164. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
  165. package/.cursor/process/README.md +0 -9
  166. package/.cursor/rules/anchor-docs.mdc +0 -15
  167. package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
  168. package/.cursor/rules/cli-layout.mdc +0 -81
  169. package/.cursor/rules/cli-product-neutral.mdc +0 -43
  170. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
  171. package/.cursor/rules/docs-rules.mdc +0 -32
  172. package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
  173. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
  174. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
  175. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
  176. package/.cursor/rules/project-rules.mdc +0 -913
  177. package/.cursor/skills/README.md +0 -15
  178. package/.dockerignore +0 -52
  179. package/.eslintignore +0 -22
  180. package/.markdownlint.json +0 -14
  181. package/anchor-docs/README.md +0 -10
  182. package/anchor-docs/_TEMPLATE +0 -24
  183. package/babel.config.js +0 -6
  184. package/bin/builder-api-cleanup.js +0 -26
  185. package/bin/builder-api-nest.js +0 -10
  186. package/bin/builder-api-spike.js +0 -19
  187. package/enterprise-knowledge/README.md +0 -50
  188. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
  189. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
  190. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
  191. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
  192. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
  193. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
  194. package/integration/README.md +0 -81
  195. package/integration/github/README.md +0 -53
  196. package/integration/github/application.json +0 -21
  197. package/integration/github/deploy.js +0 -72
  198. package/integration/github/env.template +0 -11
  199. package/integration/github/github-datasource-issue-comments.json +0 -239
  200. package/integration/github/github-datasource-issues.json +0 -399
  201. package/integration/github/github-datasource-repository.json +0 -354
  202. package/integration/github/github-deploy.json +0 -1202
  203. package/integration/github/github-system.json +0 -82
  204. package/integration/hubspot-test/README.md +0 -159
  205. package/integration/hubspot-test/application.json +0 -54
  206. package/integration/hubspot-test/companies.json +0 -2048
  207. package/integration/hubspot-test/create-hubspot.js +0 -523
  208. package/integration/hubspot-test/env.template +0 -4
  209. package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
  210. package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
  211. package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
  212. package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
  213. package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
  214. package/integration/hubspot-test/hubspot-test-system.json +0 -74
  215. package/integration/hubspot-test/rbac.json +0 -166
  216. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
  217. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
  218. package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
  219. package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
  220. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
  221. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
  222. package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
  223. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
  224. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  225. package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
  226. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
  227. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
  228. package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
  229. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
  230. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  231. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  232. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
  233. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
  234. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
  235. package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
  236. package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
  237. package/integration/hubspot-test/test-dataplane-down.js +0 -209
  238. package/integration/hubspot-test/test.js +0 -1588
  239. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
  240. package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
  241. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
  242. package/integration/roundtrip-test-local/README.md +0 -143
  243. package/integration/roundtrip-test-local/application.yaml +0 -13
  244. package/integration/roundtrip-test-local/env.template +0 -15
  245. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
  246. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
  247. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
  248. package/integration/roundtrip-test-local2/README.md +0 -143
  249. package/integration/roundtrip-test-local2/application.yaml +0 -13
  250. package/integration/roundtrip-test-local2/env.template +0 -15
  251. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
  252. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
  253. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
  254. package/integration/test/wizard.yaml +0 -8
  255. package/jest.config.coverage.js +0 -37
  256. package/jest.config.default.js +0 -11
  257. package/jest.config.integration.fixtures.js +0 -22
  258. package/jest.config.integration.js +0 -33
  259. package/jest.config.isolated.js +0 -11
  260. package/jest.config.manual.js +0 -30
  261. package/jest.global-live-fabrix-hooks.js +0 -36
  262. package/jest.isolated-projects.js +0 -260
  263. package/jest.projects.js +0 -76
  264. package/packages/builder-api/README.md +0 -120
  265. package/packages/builder-api/package.json +0 -30
  266. package/packages/builder-api/src/app.module.ts +0 -7
  267. package/packages/builder-api/src/auth/auth.module.ts +0 -5
  268. package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
  269. package/packages/builder-api/src/main.ts +0 -16
  270. package/packages/builder-api/tsconfig.json +0 -15
  271. package/scripts/check-builder-api-architecture-grep.js +0 -79
  272. package/scripts/check-datasource-test-run-schema-sync.js +0 -34
  273. package/scripts/ci-fix.sh +0 -19
  274. package/scripts/ci-simulate.sh +0 -19
  275. package/scripts/diagnose-cli.js +0 -150
  276. package/scripts/docker_image_content_gate.js +0 -47
  277. package/scripts/docker_image_content_gate.sh +0 -5
  278. package/scripts/export-builder-api-evidence.js +0 -262
  279. package/scripts/install-local.js +0 -490
  280. package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
  281. package/scripts/lib/builder-api-docker-staging-core.js +0 -183
  282. package/scripts/lib/docker-image-content-gate-core.js +0 -166
  283. package/scripts/lib/plan-actor.js +0 -109
  284. package/scripts/lib/plan-config.js +0 -20
  285. package/scripts/lib/plan-gates.js +0 -154
  286. package/scripts/lib/plan-meta.js +0 -104
  287. package/scripts/lib/plan-parse.js +0 -162
  288. package/scripts/lib/plan-prevalidate-gates.js +0 -337
  289. package/scripts/lib/plan-run-core.js +0 -125
  290. package/scripts/lib/plan-run-report.js +0 -119
  291. package/scripts/plan-approve.js +0 -24
  292. package/scripts/plan-archive.js +0 -49
  293. package/scripts/plan-run.js +0 -13
  294. package/scripts/plan-set-actor.js +0 -21
  295. package/scripts/plan-validate.js +0 -80
  296. package/scripts/pnpm/af.mjs +0 -110
  297. package/scripts/pnpm/check-quiet.mjs +0 -32
  298. package/scripts/pnpm/dev-install.mjs +0 -29
  299. package/scripts/pnpm/dev-reload.mjs +0 -18
  300. package/scripts/pnpm/help.mjs +0 -55
  301. package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
  302. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
  303. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
  304. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
  305. package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
  306. package/scripts/pnpm/lib/spinner.mjs +0 -42
  307. package/scripts/pnpm-global-remove.js +0 -48
  308. package/scripts/stage_builder_api_for_docker.js +0 -65
  309. package/scripts/sync-builder-api-template.js +0 -44
  310. package/scripts/test-dataplane-bootstrap.js +0 -331
@@ -331,23 +331,30 @@ async function runGuidedDownInfra(appName, options, infraMod, appLib) {
331
331
  logger.log(SEPARATOR);
332
332
  logger.log('');
333
333
 
334
+ const targetDeveloperId = options && options.developerId;
334
335
  const spin = startSpinner('Stopping infrastructure...');
335
336
  await withMutedLogger(async() => {
336
337
  if (typeof appName === 'string' && appName.trim().length > 0) {
337
- await appLib.downApp(appName, { volumes: !!options.volumes });
338
+ await appLib.downApp(appName, {
339
+ volumes: !!options.volumes,
340
+ developerId: targetDeveloperId
341
+ });
338
342
  return;
339
343
  }
340
- if (options.volumes) await infraMod.stopInfraWithVolumes();
341
- else await infraMod.stopInfra();
344
+ if (options.volumes) await infraMod.stopInfraWithVolumes(targetDeveloperId);
345
+ else await infraMod.stopInfra(targetDeveloperId);
342
346
  });
343
347
  stopSpinnerSuccess(spin, 'Infrastructure stopped');
344
348
 
345
- const developerId = await config.getDeveloperId();
346
- const idNum = typeof developerId === 'string' ? parseInt(developerId, 10) : developerId;
349
+ const developerId = String(
350
+ targetDeveloperId !== undefined && targetDeveloperId !== null && targetDeveloperId !== ''
351
+ ? targetDeveloperId
352
+ : await config.getDeveloperId()
353
+ );
347
354
  const cfg = await config.getConfig();
348
355
 
349
356
  logFooterStart('Stopped');
350
- logSection('Developer', `dev${String(idNum).padStart(2, '0')} (id: ${idNum})`);
357
+ logSection('Developer', `dev${developerId.padStart(2, '0')} (id: ${developerId})`);
351
358
  logStoppedServices(cfg);
352
359
  if (options.volumes) {
353
360
  logger.log(chalk.yellow('⚠ Volumes removed: all local data deleted'));
@@ -18,8 +18,10 @@ const { runDeploymentList } = require('../commands/deployment-list');
18
18
  const CREDENTIAL_HELP_AFTER = `
19
19
  Subcommands:
20
20
  env <systemKey> Prompt for KV_* values → integration/<key>/.env
21
- push <systemKey> Upload secrets from .env to Dataplane
21
+ push <systemKey> Upload secrets from an env file to Dataplane (--file recommended)
22
22
  list List credentials (pagination: --page-size)
23
+
24
+ Secrets: pass paths only (e.g. --file ./path/to/.env). Never put secret values on the command line.
23
25
  `;
24
26
 
25
27
  const DEPLOYMENT_HELP_AFTER = `
@@ -42,10 +44,11 @@ function setupCredentialEnvAndPush(credential) {
42
44
  });
43
45
  credential
44
46
  .command('push <systemKey>')
45
- .description('Push KV_* secrets from .env to Dataplane')
46
- .action(async(systemKey, _options) => {
47
+ .description('Push KV_* secrets from an env file to Dataplane (file path only — no secret values on argv)')
48
+ .option('--file <path>', 'Env file with KV_* values (must exist; never put secret values on argv)')
49
+ .action(async(systemKey, options) => {
47
50
  try {
48
- await runCredentialPush(systemKey);
51
+ await runCredentialPush(systemKey, { file: options.file });
49
52
  } catch (error) {
50
53
  logger.error(chalk.red(`Error: ${error.message}`));
51
54
  handleCommandError(error, 'credential push');
@@ -53,7 +56,6 @@ function setupCredentialEnvAndPush(credential) {
53
56
  }
54
57
  });
55
58
  }
56
-
57
59
  /**
58
60
  * Sets up credential and deployment list commands
59
61
  * @param {Command} program - Commander program instance
@@ -31,6 +31,9 @@ const {
31
31
  getRestartableInfraServiceNames,
32
32
  buildRestartInfraHelpLines
33
33
  } = require('../constants/infra-compose-service-names');
34
+ const {
35
+ resolveTransientDeveloperIdFromOptions
36
+ } = require('../utils/transient-developer-id');
34
37
 
35
38
  const {
36
39
  computeEffectiveInfraOptionalFlags,
@@ -97,6 +100,18 @@ async function applyDeveloperIdFromUpInfra(options) {
97
100
  return id;
98
101
  }
99
102
 
103
+ const DOWN_INFRA_HELP_AFTER = `
104
+ Examples:
105
+ $ aifabrix down-infra
106
+ $ aifabrix down-infra --volumes
107
+ $ aifabrix down-infra --developer-id 02
108
+ $ aifabrix down-infra -d 02 --volumes
109
+ $ aifabrix down-infra myapp --developer-id 02
110
+
111
+ --developer-id / -d target another developer's stack for this command only.
112
+ They do not change developer-id in config.
113
+ `;
114
+
100
115
  /**
101
116
  * @param {Object} options
102
117
  * @param {Object} cfg - Mutable config from getConfig()
@@ -302,20 +317,32 @@ function setupUpBuilderApiCommand(program) {
302
317
  function setupDownInfraCommand(program) {
303
318
  program.command('down-infra [service|app]')
304
319
  .description('Stop all infra, or stop one app; use -v to remove volumes')
320
+ .addHelpText('after', DOWN_INFRA_HELP_AFTER)
305
321
  .option('-v, --volumes', 'Remove volumes (deletes all data)')
306
322
  .option('--verbose', 'Show full orchestration output (default is guided summary)')
323
+ .option(
324
+ '-d, --developer <id>',
325
+ 'Target developer ID for this stop only (does not change config)'
326
+ )
327
+ .option(
328
+ '--developer-id <id>',
329
+ 'Same as --developer; target another developer without changing config'
330
+ )
307
331
  .action(async(appName, options) => {
308
332
  try {
333
+ const developerId = resolveTransientDeveloperIdFromOptions(options);
334
+ const opts = { ...options, developerId };
309
335
  if (!options.verbose) {
310
- await runGuidedDownInfra(appName, options, infra, appLib);
336
+ await runGuidedDownInfra(appName, opts, infra, appLib);
311
337
  return;
312
338
  }
313
339
 
314
340
  if (typeof appName === 'string' && appName.trim().length > 0) {
315
- await appLib.downApp(appName, { volumes: !!options.volumes });
341
+ await appLib.downApp(appName, { volumes: !!options.volumes, developerId });
342
+ } else if (options.volumes) {
343
+ await infra.stopInfraWithVolumes(developerId);
316
344
  } else {
317
- if (options.volumes) await infra.stopInfraWithVolumes();
318
- else await infra.stopInfra();
345
+ await infra.stopInfra(developerId);
319
346
  }
320
347
  } catch (error) {
321
348
  handleCommandError(error, 'down-infra');
@@ -228,6 +228,7 @@ function setupValidateDiffCommands(program) {
228
228
  setupValidateCommand(program);
229
229
  setupValidateJsonCommand(program);
230
230
  setupDiffCommand(program);
231
+ require('../commands/package-score').setupPackageScoreCommand(program);
231
232
  }
232
233
 
233
234
  module.exports = {
@@ -18,26 +18,36 @@ const { addChannelCommand } = require('../channels/add-channel');
18
18
  const CHANNEL_ADD_HELP_AFTER = `
19
19
  ${formatSupportedChannelTargetsHelp()}
20
20
 
21
+ One command covers scaffold → upload → install:
22
+ $ aifabrix channel add slack --name "Elsa" --probe
23
+
21
24
  Examples:
22
- # After upload/deploy of the communication external system
23
25
  $ aifabrix channel add slack --name "Elsa"
24
26
  $ aifabrix channel add teams-bot --name "Elsa" --description "Enterprise AI assistant for employees"
25
27
  $ aifabrix channel add chatgpt --name "Your Assistant"
26
- $ aifabrix channel add microsoft-copilot --name "Your Assistant"
28
+ $ aifabrix channel add microsoft-copilot --name "Your Assistant" \\
29
+ --oauth-plugin-vault-reference-id "<Teams-Entra-SSO-auth-config-id>"
27
30
 
28
31
  # Slack slash-command prefix (registers /{prefix}-help in manifest)
29
32
  $ aifabrix channel add slack --name "Elsa" --command-prefix af
30
33
 
31
- # Generate artifacts only; no dataplane patch
34
+ # Generate artifacts only; no dataplane patch / upload
32
35
  $ aifabrix channel add slack --name "Elsa" --dry-run
33
36
 
34
- # Regenerate artifacts and patch config (does not rotate secrets)
37
+ # Re-upload communication system + regenerate channel config (does not rotate secrets)
35
38
  $ aifabrix channel add slack --name "Elsa" --force
36
39
 
37
40
  # Validate callbacks and assistant catalog after install
38
41
  $ aifabrix channel add slack --name "Elsa" --probe
39
42
 
40
- Prerequisites: aifabrix upload <target> (or deploy) and aifabrix login
43
+ Behavior:
44
+ - Scaffolds integration/<target>/ when missing (does not overwrite existing files)
45
+ - Uploads when the system is not on the dataplane; with --force uploads every time
46
+ - Then configures the channel install (artifacts, credentials, admin guide)
47
+ - microsoft-copilot uses Entra SSO (trustedIssuer); pass --oauth-plugin-vault-reference-id
48
+ from Teams Developer Portal. Does not create Fabrix oauth2 channel credentials.
49
+
50
+ Requires: aifabrix login
41
51
  `;
42
52
 
43
53
  /**
@@ -64,6 +74,7 @@ async function runChannelAddAction(channelTarget, options, meta = {}) {
64
74
  icon: options.icon,
65
75
  template: options.template,
66
76
  commandPrefix: options.commandPrefix,
77
+ oauthPluginVaultReferenceId: options.oauthPluginVaultReferenceId,
67
78
  dryRun: options.dryRun === true,
68
79
  force: options.force === true,
69
80
  probe: options.probe === true
@@ -77,7 +88,7 @@ async function runChannelAddAction(channelTarget, options, meta = {}) {
77
88
  */
78
89
  function registerChannelAddCommand(parent, meta = {}) {
79
90
  const description =
80
- 'Configure channel install (manifest, credentials, admin guide) after upload/deploy';
91
+ 'Scaffold (if needed), upload (if needed/--force), then configure channel install';
81
92
  const commandName = meta.commandName || 'add <channelTarget>';
82
93
  const cmd = meta.hidden
83
94
  ? parent.command(commandName, { hidden: true })
@@ -88,12 +99,19 @@ function registerChannelAddCommand(parent, meta = {}) {
88
99
  .option('-d, --description <text>', 'Channel description (default generated)')
89
100
  .option('--icon <path>', 'Path to channel icon asset')
90
101
  .option('--template <name>', 'Template override (default from channel target)')
91
- .option('--dry-run', 'Generate artifacts only; do not patch external system or credentials')
92
- .option('--force', 'Regenerate artifacts and patch config (does not rotate secrets)')
102
+ .option('--dry-run', 'Generate artifacts only; do not upload, patch, or set credentials')
103
+ .option(
104
+ '--force',
105
+ 'Re-upload communication system and regenerate channel config (does not rotate secrets)'
106
+ )
93
107
  .option(
94
108
  '--command-prefix <key>',
95
109
  'Slack slash alias prefix (default af) — registers /{prefix}-help etc. in manifest'
96
110
  )
111
+ .option(
112
+ '--oauth-plugin-vault-reference-id <id>',
113
+ 'Teams Developer Portal Entra SSO OAuth auth-config id (microsoft-copilot)'
114
+ )
97
115
  .option('--probe', 'After install, validate callbacks and assistant catalog')
98
116
  .addHelpText('after', CHANNEL_ADD_HELP_AFTER)
99
117
  .action(async(channelTarget, options) => {
@@ -101,7 +119,8 @@ function registerChannelAddCommand(parent, meta = {}) {
101
119
  await runChannelAddAction(channelTarget, options, meta);
102
120
  } catch (error) {
103
121
  if (!error.message?.includes('Authentication required')) {
104
- logger.error(formatBlockingError('Channel install failed:'), error.message);
122
+ const detail = error.message || String(error);
123
+ logger.error(formatBlockingError(`Channel install failed:\n${detail}`));
105
124
  }
106
125
  process.exit(1);
107
126
  }
@@ -25,15 +25,20 @@ const { registerChannelAddCommand } = require('./channel-add-setup');
25
25
 
26
26
  const CHANNEL_HELP_AFTER = `
27
27
  Subcommands:
28
- scaffold <target> Create integration/<target>/ files locally (step 1)
29
- add <target> Channel install guide + manifest/credential patch (step 3)
28
+ add <target> One command: scaffold (if needed) → upload (if needed/--force) → install
29
+ scaffold <target> Optional: create integration/<target>/ files only (local)
30
30
 
31
31
  ${formatSupportedChannelTargetsHelp()}
32
32
 
33
- Typical flow (channels are connected systems, not controller apps):
33
+ Typical flow:
34
+ aifabrix channel add slack --name "Elsa" --probe
35
+
36
+ # Force re-upload of the communication system, then reinstall channel
37
+ aifabrix channel add slack --name "Elsa" --force --probe
38
+
39
+ Optional low-level steps (usually unnecessary):
34
40
  aifabrix channel scaffold slack
35
41
  aifabrix upload slack --force
36
- aifabrix channel add slack --name "Elsa" --probe
37
42
 
38
43
  Controller pipeline apps only: aifabrix app register · aifabrix app list
39
44
 
@@ -43,10 +48,10 @@ Requires: aifabrix login (for add)
43
48
  const CHANNEL_SCAFFOLD_HELP_AFTER = `
44
49
  ${formatSupportedChannelTargetsHelp()}
45
50
 
46
- Typical flow:
47
- aifabrix channel scaffold slack
48
- aifabrix upload slack --force
51
+ Prefer one command (scaffold + upload + install):
49
52
  aifabrix channel add slack --name "Your Assistant" --probe
53
+
54
+ scaffold alone only writes local files under integration/<target>/.
50
55
  `;
51
56
 
52
57
  /**
@@ -56,7 +61,7 @@ function setupChannelCommands(program) {
56
61
  const channel = program
57
62
  .command('channel')
58
63
  .description(
59
- 'Assistant channels (Slack, Teams, Copilot, ChatGPT) — scaffold integration and install'
64
+ 'Assistant channels — one-command add (scaffold → upload → install), plus optional scaffold'
60
65
  )
61
66
  .addHelpText('after', CHANNEL_HELP_AFTER);
62
67
 
@@ -86,8 +91,7 @@ function setupChannelCommands(program) {
86
91
  logger.log(metadata(file));
87
92
  }
88
93
  logger.log('');
89
- logger.log(chalk.white('Next steps:'));
90
- logger.log(chalk.gray(` aifabrix upload ${channelTarget} --force`));
94
+ logger.log(chalk.white('Next step (recommended):'));
91
95
  logger.log(
92
96
  chalk.gray(` aifabrix channel add ${channelTarget} --name "Your Assistant" --probe`)
93
97
  );
@@ -51,8 +51,10 @@ async function buildPayload(systemKey) {
51
51
  * Runs credential push: push KV_* from .env to dataplane.
52
52
  * @async
53
53
  * @param {string} systemKey - External system key
54
+ * @param {Object} [options]
55
+ * @param {string} [options.file] - Explicit env file path (required to exist when set)
54
56
  * @returns {Promise<{ pushed: number }>} Count of secrets pushed
55
- * @throws {Error} If auth or push fails
57
+ * @throws {Error} If auth or push fails, or --file path is missing
56
58
  */
57
59
  function logPushResult(pushResult) {
58
60
  if (pushResult.pushed > 0) {
@@ -66,10 +68,35 @@ function logPushResult(pushResult) {
66
68
  if (pushResult.warning) logger.log(chalk.yellow(`Warning: ${pushResult.warning}`));
67
69
  }
68
70
 
69
- async function runCredentialPush(systemKey) {
71
+ /**
72
+ * Resolve env file path for credential push.
73
+ * @param {string} systemKey
74
+ * @param {Object} [options]
75
+ * @returns {string}
76
+ */
77
+ function resolveCredentialEnvFilePath(systemKey, options = {}) {
78
+ const fileOpt =
79
+ options.file !== undefined && options.file !== null ? String(options.file).trim() : '';
80
+ if (fileOpt) {
81
+ const resolved = path.resolve(fileOpt);
82
+ const fsReal = require('../internal/fs-real-sync');
83
+ let isFile = false;
84
+ try {
85
+ isFile = fsReal.existsSync(resolved) && fsReal.statSync(resolved).isFile();
86
+ } catch (_err) {
87
+ isFile = false;
88
+ }
89
+ if (!isFile) {
90
+ throw new Error(`Credential env file not found: ${resolved}`);
91
+ }
92
+ return resolved;
93
+ }
94
+ return path.join(getIntegrationPath(systemKey), '.env');
95
+ }
96
+
97
+ async function runCredentialPush(systemKey, options = {}) {
70
98
  validateSystemKeyFormat(systemKey);
71
- const appPath = getIntegrationPath(systemKey);
72
- const envFilePath = path.join(appPath, '.env');
99
+ const envFilePath = resolveCredentialEnvFilePath(systemKey, options);
73
100
 
74
101
  const { resolveEnvironment } = require('../core/config');
75
102
  const environment = await resolveEnvironment();
@@ -99,4 +126,9 @@ async function runCredentialPush(systemKey) {
99
126
  return { pushed: pushResult.pushed || 0 };
100
127
  }
101
128
 
102
- module.exports = { runCredentialPush, validateSystemKeyFormat, buildPayload };
129
+ module.exports = {
130
+ runCredentialPush,
131
+ validateSystemKeyFormat,
132
+ buildPayload,
133
+ resolveCredentialEnvFilePath
134
+ };
@@ -0,0 +1,158 @@
1
+ /**
2
+ * CLI: integration-definition validate | apply
3
+ * @fileoverview BT → Builder BID commands (no section PATCH orchestration)
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ /* eslint-disable no-console */
9
+
10
+ const chalk = require('chalk');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const {
14
+ applyIntegrationDefinition,
15
+ validateIntegrationDefinition,
16
+ withDefinitionHash
17
+ } = require('../integration-definition');
18
+ const { handleCommandError } = require('../utils/cli-utils');
19
+ const {
20
+ formatSuccessLine,
21
+ formatBlockingError,
22
+ failureGlyph
23
+ } = require('../utils/cli-layout-chalk');
24
+
25
+ const PARENT_HELP_AFTER = `
26
+
27
+ Examples:
28
+ $ aifabrix integration-definition validate ./bid.json
29
+ $ aifabrix integration-definition apply ./bid.json --dry-run
30
+
31
+ BID is the minimal business create language (systemKind, resourceType, propertyKeys).
32
+ Apply materializes integration/<systemKey>/ package files (EDS/system).
33
+ AI catalog: GET /help?topic=resourceTypeCatalog on builder-api.
34
+ `;
35
+
36
+ const VALIDATE_HELP_AFTER = `
37
+
38
+ Examples:
39
+ $ aifabrix integration-definition validate ./bid.json
40
+ $ aifabrix integration-definition validate ./bid.json --fix-hash
41
+
42
+ Checks JSON Schema, definitionHash, product rules, and active resourceType catalog keys.
43
+ `;
44
+
45
+ const APPLY_HELP_AFTER = `
46
+
47
+ Examples:
48
+ $ aifabrix integration-definition apply ./bid.json
49
+ $ aifabrix integration-definition apply ./bid.json --dry-run
50
+ $ aifabrix integration-definition apply ./bid.json --force
51
+ $ aifabrix integration-definition apply ./bid.json --output-dir /tmp/out
52
+ `;
53
+
54
+ /**
55
+ * @param {string} filePath
56
+ * @returns {Record<string, unknown>}
57
+ */
58
+ function loadBidFile(filePath) {
59
+ const abs = path.resolve(filePath);
60
+ if (!fs.existsSync(abs)) {
61
+ throw new Error(`BID file not found: ${abs}`);
62
+ }
63
+ return JSON.parse(fs.readFileSync(abs, 'utf8'));
64
+ }
65
+
66
+ /**
67
+ * @param {string} file
68
+ * @param {{ fixHash?: boolean }} options
69
+ * @returns {Promise<void>}
70
+ */
71
+ async function runValidateCommand(file, options) {
72
+ let bid = loadBidFile(file);
73
+ if (options.fixHash) {
74
+ bid = withDefinitionHash(bid);
75
+ fs.writeFileSync(path.resolve(file), `${JSON.stringify(bid, null, 2)}\n`, 'utf8');
76
+ console.log(formatSuccessLine(`Wrote definitionHash to ${file}`));
77
+ }
78
+ const result = validateIntegrationDefinition(bid);
79
+ if (!result.valid) {
80
+ console.error(formatBlockingError('BID invalid'));
81
+ for (const err of result.errors) {
82
+ console.error(chalk.red(` ${failureGlyph()} ${err}`));
83
+ }
84
+ process.exit(1);
85
+ }
86
+ console.log(formatSuccessLine('BID valid'));
87
+ console.log(` definitionId: ${result.bid.definitionId}`);
88
+ console.log(` definitionHash: ${result.bid.definitionHash}`);
89
+ }
90
+
91
+ /**
92
+ * @param {string} file
93
+ * @param {{ outputDir?: string, dryRun?: boolean, force?: boolean }} options
94
+ * @returns {Promise<void>}
95
+ */
96
+ async function runApplyCommand(file, options) {
97
+ const bid = loadBidFile(file);
98
+ const out = await applyIntegrationDefinition(bid, {
99
+ outputDir: options.outputDir,
100
+ dryRun: Boolean(options.dryRun),
101
+ force: Boolean(options.force)
102
+ });
103
+ console.log(formatSuccessLine(`BID apply ${out.status}`));
104
+ console.log(` systemKey: ${out.systemKey}`);
105
+ console.log(` outputDir: ${out.outputDir}`);
106
+ console.log(` definitionHash: ${out.definitionHash}`);
107
+ if (out.files) {
108
+ console.log(` files: ${out.files.join(', ')}`);
109
+ }
110
+ }
111
+
112
+ /**
113
+ * @param {import('commander').Command} program
114
+ */
115
+ function setupIntegrationDefinitionCommands(program) {
116
+ const cmd = program
117
+ .command('integration-definition')
118
+ .description(
119
+ 'Validate or apply a Builder Integration Definition (BID) — minimal business create language for integration packages'
120
+ )
121
+ .addHelpText('after', PARENT_HELP_AFTER);
122
+
123
+ cmd
124
+ .command('validate <file>')
125
+ .description(
126
+ 'Validate BID JSON (schema, definitionHash, product rules, resourceType catalog)'
127
+ )
128
+ .option('--fix-hash', 'Rewrite file with computed definitionHash')
129
+ .addHelpText('after', VALIDATE_HELP_AFTER)
130
+ .action(async(file, options) => {
131
+ try {
132
+ await runValidateCommand(file, options);
133
+ } catch (error) {
134
+ handleCommandError(error, 'integration-definition validate');
135
+ }
136
+ });
137
+
138
+ cmd
139
+ .command('apply <file>')
140
+ .description(
141
+ 'Idempotently apply BID to integration/<systemKey>/ (Builder-owned EDS/system writes)'
142
+ )
143
+ .option('--output-dir <dir>', 'Override output directory')
144
+ .option('--force', 'Rewrite package even when definitionHash matches stamp')
145
+ .option('--dry-run', 'Show planned files without writing')
146
+ .addHelpText('after', APPLY_HELP_AFTER)
147
+ .action(async(file, options) => {
148
+ try {
149
+ await runApplyCommand(file, options);
150
+ } catch (error) {
151
+ handleCommandError(error, 'integration-definition apply');
152
+ }
153
+ });
154
+ }
155
+
156
+ module.exports = {
157
+ setupIntegrationDefinitionCommands
158
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * CLI: score candidate integration package vs a reference package directory.
3
+ *
4
+ * @fileoverview package-score command — score-only parity; reference is never generation input
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const chalk = require('chalk');
11
+ const logger = require('../utils/logger');
12
+ const { scorePackageParity } = require('../lab/package-parity-score');
13
+
14
+ /**
15
+ * @param {Object} options
16
+ * @param {string} options.reference
17
+ * @param {string} options.candidate
18
+ * @param {boolean} [options.json]
19
+ * @returns {Promise<number>} process exit code
20
+ */
21
+ async function runPackageScoreCommand(options = {}) {
22
+ const reference = String(options.reference || '').trim();
23
+ const candidate = String(options.candidate || '').trim();
24
+ if (!reference || !candidate) {
25
+ throw new Error('Both --reference <dir> and --candidate <dir> are required.');
26
+ }
27
+ const report = scorePackageParity(path.resolve(reference), path.resolve(candidate));
28
+ if (options.json === true) {
29
+ logger.log(JSON.stringify(report, null, 2));
30
+ } else {
31
+ logger.log(chalk.bold(`Package parity score: ${report.score}/${report.maxScore}`));
32
+ logger.log(chalk.gray(report.summary));
33
+ logger.log(chalk.gray(`Reference (score-only): ${report.referenceDir}`));
34
+ logger.log(chalk.gray(`Candidate: ${report.candidateDir}`));
35
+ for (const row of report.facets) {
36
+ const mark = row.ok ? chalk.green('✔') : chalk.red('✖');
37
+ logger.log(` ${mark} ${row.id}: ${row.detail}`);
38
+ }
39
+ if (report.goldIsScoreOnly) {
40
+ logger.log(chalk.yellow('Note: reference package is for scoring only — never use it as generation input.'));
41
+ }
42
+ }
43
+ return report.identical ? 0 : 1;
44
+ }
45
+
46
+ /**
47
+ * @param {import('commander').Command} program
48
+ */
49
+ function setupPackageScoreCommand(program) {
50
+ program
51
+ .command('package-score')
52
+ .description(
53
+ 'Score a candidate integration package directory against a reference package (score-only; not generation)'
54
+ )
55
+ .option('--reference <dir>', 'Reference integration package directory (score baseline only)')
56
+ .option('--candidate <dir>', 'Candidate integration package directory')
57
+ .option('--json', 'Emit structured JSON report', false)
58
+ .action(async(options) => {
59
+ try {
60
+ const code = await runPackageScoreCommand(options);
61
+ process.exitCode = code;
62
+ } catch (error) {
63
+ logger.error(chalk.red(`Error: ${error.message}`));
64
+ process.exitCode = 1;
65
+ }
66
+ });
67
+ }
68
+
69
+ module.exports = {
70
+ setupPackageScoreCommand,
71
+ runPackageScoreCommand
72
+ };
@@ -28,6 +28,7 @@ const ALLOWED_REPAIR_AUTH = [
28
28
  'oidc',
29
29
  'hmac',
30
30
  'none',
31
+ 'system',
31
32
  'bearerforward'
32
33
  ];
33
34
 
@@ -57,8 +58,12 @@ function isAllowedRepairAuth(authOption) {
57
58
  */
58
59
  function buildAuthenticationForRepair(systemKey, authOption) {
59
60
  const normalized = normalizeRepairAuthOption(authOption);
61
+ if (normalized === 'system') {
62
+ return buildSystemAuthentication();
63
+ }
60
64
  if (normalized === 'bearerforward') {
61
- return buildBearerForwardAuthentication();
65
+ // Legacy alias: prefer authType system for platform facades.
66
+ return buildSystemAuthentication();
62
67
  }
63
68
  const schemaMethod =
64
69
  normalized === 'queryparam'
@@ -70,11 +75,19 @@ function buildAuthenticationForRepair(systemKey, authOption) {
70
75
  }
71
76
 
72
77
  /**
73
- * Facade APIs that forward the caller Bearer token — no workspace kv secret.
74
- * @returns {{ authType: 'none' }}
78
+ * Platform-managed downstream authentication (no workspace kv secret).
79
+ * @returns {{ authType: 'system' }}
80
+ */
81
+ function buildSystemAuthentication() {
82
+ return { authType: 'system' };
83
+ }
84
+
85
+ /**
86
+ * @deprecated Use buildSystemAuthentication — bearerForward is not a public authType.
87
+ * @returns {{ authType: 'system' }}
75
88
  */
76
89
  function buildBearerForwardAuthentication() {
77
- return { authType: 'none' };
90
+ return buildSystemAuthentication();
78
91
  }
79
92
 
80
93
  /**
@@ -99,7 +112,7 @@ function mergePreservedAuthVariables(mergedVariables, existingVars) {
99
112
  function repairAuthChangeLabel(authOption) {
100
113
  const normalized = normalizeRepairAuthOption(authOption);
101
114
  if (normalized === 'bearertoken' || normalized === 'bearerkey') return 'bearerToken';
102
- if (normalized === 'bearerforward') return 'bearerForward';
115
+ if (normalized === 'bearerforward') return 'system';
103
116
  return normalized;
104
117
  }
105
118
 
@@ -157,6 +170,7 @@ module.exports = {
157
170
  normalizeRepairAuthOption,
158
171
  isAllowedRepairAuth,
159
172
  buildAuthenticationForRepair,
173
+ buildSystemAuthentication,
160
174
  buildBearerForwardAuthentication,
161
175
  mergePreservedAuthVariables,
162
176
  repairAuthChangeLabel,
@@ -108,7 +108,10 @@ function ensureSyncOperationScaffold(parsed) {
108
108
  parsed.execution = { engine: 'cip' };
109
109
  }
110
110
  if (!parsed.execution.cip || typeof parsed.execution.cip !== 'object') {
111
- parsed.execution.cip = { operations: {} };
111
+ parsed.execution.cip = { version: '1.0', operations: {} };
112
+ }
113
+ if (!parsed.execution.cip.version) {
114
+ parsed.execution.cip.version = '1.0';
112
115
  }
113
116
  if (!parsed.execution.cip.operations || typeof parsed.execution.cip.operations !== 'object') {
114
117
  parsed.execution.cip.operations = {};