@aifabrix/builder 2.54.1 → 2.55.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/README.md +8 -0
  2. package/lib/agent-kit/apply-ops.js +82 -0
  3. package/lib/agent-kit/checksums.js +28 -0
  4. package/lib/agent-kit/classify.js +113 -0
  5. package/lib/agent-kit/claude-shim.js +61 -0
  6. package/lib/agent-kit/constants.js +55 -0
  7. package/lib/agent-kit/file-list.js +103 -0
  8. package/lib/agent-kit/host-approve.js +172 -0
  9. package/lib/agent-kit/hosting/github.js +63 -0
  10. package/lib/agent-kit/hosts.js +71 -0
  11. package/lib/agent-kit/init.js +319 -0
  12. package/lib/agent-kit/kit-root.js +17 -0
  13. package/lib/agent-kit/managed-section.js +79 -0
  14. package/lib/agent-kit/package-load.js +45 -0
  15. package/lib/agent-kit/plan-ops.js +69 -0
  16. package/lib/agent-kit/remote-prompts.js +272 -0
  17. package/lib/agent-kit/render-host-markdown.js +40 -0
  18. package/lib/agent-kit/repo-guard.js +47 -0
  19. package/lib/agent-kit/report.js +107 -0
  20. package/lib/agent-kit/run.js +82 -0
  21. package/lib/agent-kit/scm/git.js +122 -0
  22. package/lib/agent-kit/start.js +310 -0
  23. package/lib/agent-kit/state-file.js +83 -0
  24. package/lib/agent-kit/status.js +50 -0
  25. package/lib/agent-kit/v1-detect.js +81 -0
  26. package/lib/agent-kit/validate-kit.js +87 -0
  27. package/lib/agent-kit/workspace-name.js +40 -0
  28. package/lib/agent-kit/workspace-skeleton.js +103 -0
  29. package/lib/api/role-assistant-test-pack.api.js +86 -0
  30. package/lib/api/work-search.api.js +31 -4
  31. package/lib/api/work.api.js +19 -12
  32. package/lib/app/deploy.js +7 -4
  33. package/lib/app/list-external-systems.js +2 -1
  34. package/lib/app/offer-create-from-template.js +184 -0
  35. package/lib/app/show-display.js +33 -6
  36. package/lib/app/show.js +25 -2
  37. package/lib/channels/add-channel.js +1 -0
  38. package/lib/channels/approval-guides/claude.js +2 -2
  39. package/lib/channels/channel-add-failure.js +1 -0
  40. package/lib/channels/channel-add-remaining.js +15 -9
  41. package/lib/channels/channel-definition-status.js +115 -0
  42. package/lib/channels/channel-description.js +2 -1
  43. package/lib/channels/channel-install-envelope.js +4 -2
  44. package/lib/channels/channel-integration-generator.js +2 -0
  45. package/lib/channels/channel-runtime-resolver.js +14 -0
  46. package/lib/channels/channel-targets.js +31 -5
  47. package/lib/channels/claude-setup-values.js +4 -1
  48. package/lib/channels/slack-channel-add.js +59 -6
  49. package/lib/channels/slack-mcp-callback.js +51 -0
  50. package/lib/channels/slack-mcp-runtime.js +156 -0
  51. package/lib/channels/slack-provisioning/install-cli.js +14 -2
  52. package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
  53. package/lib/cli/index.js +4 -0
  54. package/lib/cli/setup-app.js +8 -1
  55. package/lib/cli/setup-auth.js +11 -2
  56. package/lib/cli/setup-certification-commands.js +2 -2
  57. package/lib/cli/setup-certification.help.js +3 -1
  58. package/lib/commands/agent-kit-help.js +149 -0
  59. package/lib/commands/agent-kit.js +417 -0
  60. package/lib/commands/auth-status-user.js +99 -0
  61. package/lib/commands/auth-status.js +14 -4
  62. package/lib/commands/channel-add-help.js +5 -5
  63. package/lib/commands/datasource-capability-relate-cli.js +5 -4
  64. package/lib/commands/datasource-load-export-cli.js +7 -2
  65. package/lib/commands/datasource-test-trust-cli.js +5 -1
  66. package/lib/commands/governance-command-action.js +5 -4
  67. package/lib/commands/identity-membership-role-cache.js +6 -1
  68. package/lib/commands/lifecycle-command-action.js +16 -15
  69. package/lib/commands/login-credentials.js +8 -3
  70. package/lib/commands/login-device.js +14 -5
  71. package/lib/commands/login.js +14 -1
  72. package/lib/commands/logout.js +50 -15
  73. package/lib/commands/repair-auth-apply.js +1 -1
  74. package/lib/commands/repair-datasource-key-skip.js +39 -0
  75. package/lib/commands/repair-datasource-keys.js +24 -12
  76. package/lib/commands/repair-rbac.js +16 -10
  77. package/lib/commands/role-assistant-copy-output.js +61 -0
  78. package/lib/commands/role-assistant-copy.js +155 -0
  79. package/lib/commands/role-assistant-test-output.js +8 -9
  80. package/lib/commands/role-assistant-test-result-rows.js +42 -0
  81. package/lib/commands/role-assistant.js +140 -59
  82. package/lib/commands/search.js +143 -0
  83. package/lib/commands/test-trust-external.js +7 -5
  84. package/lib/commands/upload-sidecar-followups.js +4 -1
  85. package/lib/commands/verify-governance-command-action.js +9 -7
  86. package/lib/commands/verify-operations-command-action.js +9 -8
  87. package/lib/commands/verify-operations-skip-e2e.js +131 -0
  88. package/lib/commands/verify-operations-step-plan.js +6 -33
  89. package/lib/commands/verify-operations-steps.js +3 -1
  90. package/lib/commands/verify-trust-command-action.js +6 -5
  91. package/lib/datasource/capability/relate-operations.js +28 -10
  92. package/lib/datasource/capability/run-capability-relate.js +48 -25
  93. package/lib/datasource/datasource-identifier.js +13 -5
  94. package/lib/deployment/deployer-poll-run.js +117 -35
  95. package/lib/external-system/deploy-dataplane-published.js +70 -0
  96. package/lib/external-system/deploy.js +12 -2
  97. package/lib/external-system/download-role-assistant.js +41 -15
  98. package/lib/external-system/download.js +8 -3
  99. package/lib/generator/helpers.js +12 -1
  100. package/lib/generator/wizard-datasource-key.js +54 -0
  101. package/lib/generator/wizard.js +55 -54
  102. package/lib/integration-definition/apply-datasource-keys.js +75 -0
  103. package/lib/integration-definition/apply-relationships.js +195 -0
  104. package/lib/integration-definition/apply-static-enterprise.js +232 -0
  105. package/lib/integration-definition/apply-system-file.js +71 -0
  106. package/lib/integration-definition/apply-test-endpoint.js +89 -0
  107. package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
  108. package/lib/integration-definition/apply.js +78 -59
  109. package/lib/integration-definition/enrich-openapi-operations.js +36 -10
  110. package/lib/integration-definition/enrich-openapi-pick.js +87 -0
  111. package/lib/lifecycle/role-assistant-governance.js +56 -21
  112. package/lib/programmatic/capability-registry.js +1 -0
  113. package/lib/programmatic/index.js +2 -0
  114. package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
  115. package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
  116. package/lib/programmatic/openapi-component-schemas.js +1 -0
  117. package/lib/programmatic/openapi-descriptions.js +9 -3
  118. package/lib/programmatic/openapi-envelope-examples.js +7 -0
  119. package/lib/programmatic/openapi-operation-bindings.js +5 -0
  120. package/lib/programmatic/openapi-request-schemas.js +5 -0
  121. package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
  122. package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
  123. package/lib/programmatic/openapi-spec.js +1 -0
  124. package/lib/programmatic/request-timeout.js +3 -0
  125. package/lib/programmatic/route-handler-map.js +7 -0
  126. package/lib/programmatic/run-channel-catalog.js +50 -8
  127. package/lib/programmatic/run-channel-install-options.js +5 -1
  128. package/lib/programmatic/run-download.js +41 -0
  129. package/lib/protection/auth-context.js +3 -1
  130. package/lib/protection/protection-display.js +3 -2
  131. package/lib/protection/report-exit.js +50 -0
  132. package/lib/protection/run-commands.js +2 -0
  133. package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
  134. package/lib/role-assistant/knowledge-sync.js +9 -126
  135. package/lib/role-assistant/package-validate.js +175 -0
  136. package/lib/role-assistant/test-case-assertion-row.js +36 -0
  137. package/lib/role-assistant/test-case-copy-bind.js +77 -0
  138. package/lib/role-assistant/test-case-copy-expected.js +127 -0
  139. package/lib/role-assistant/test-case-copy-from-work.js +90 -0
  140. package/lib/role-assistant/test-case-copy-interactions.js +67 -0
  141. package/lib/role-assistant/test-case-copy.js +119 -0
  142. package/lib/role-assistant/test-case-expected-catalog.js +135 -0
  143. package/lib/role-assistant/test-case-validate.js +88 -0
  144. package/lib/role-assistant/test-cases-bid.js +117 -4
  145. package/lib/role-assistant/test-cases-evaluate.js +149 -31
  146. package/lib/role-assistant/test-cases-evidence.js +44 -5
  147. package/lib/role-assistant/test-cases-honesty.js +155 -6
  148. package/lib/role-assistant/test-cases-lifecycle.js +297 -0
  149. package/lib/role-assistant/test-cases-search-graph.js +122 -0
  150. package/lib/role-assistant/test-cases-search.js +20 -2
  151. package/lib/role-assistant/test-cases.js +34 -168
  152. package/lib/role-assistant/test-pack-map.js +180 -0
  153. package/lib/role-assistant/test-pack-sync.js +187 -0
  154. package/lib/role-assistant/test-runner-debug.js +54 -0
  155. package/lib/role-assistant/test-runner-respond-body.js +36 -0
  156. package/lib/role-assistant/test-runner-search.js +20 -5
  157. package/lib/role-assistant/test-runner-start-payload.js +63 -10
  158. package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
  159. package/lib/role-assistant/test-runner-workhub.js +45 -21
  160. package/lib/role-assistant/test-runner.js +53 -10
  161. package/lib/schema/external-datasource.schema.json +36 -5
  162. package/lib/schema/external-system.schema.json +20 -2
  163. package/lib/schema/infra-parameter.schema.json +51 -3
  164. package/lib/schema/infra.parameter.yaml +476 -40
  165. package/lib/schema/role-assistant-test-case.schema.json +408 -0
  166. package/lib/schema/type/document-storage.json +1 -1
  167. package/lib/search/dataplane-context.js +23 -0
  168. package/lib/search/search-args.js +211 -0
  169. package/lib/search/search-display.js +238 -0
  170. package/lib/search/search-errors.js +50 -0
  171. package/lib/search/search-prompts.js +119 -0
  172. package/lib/search/search-roles.js +85 -0
  173. package/lib/search/search-run.js +241 -0
  174. package/lib/search/search-skills.js +198 -0
  175. package/lib/utils/api-required-permissions.js +271 -0
  176. package/lib/utils/api.js +16 -13
  177. package/lib/utils/authentication-slot-show.js +153 -0
  178. package/lib/utils/cli-json-exit.js +41 -0
  179. package/lib/utils/cli-utils.js +23 -5
  180. package/lib/utils/controller-url.js +78 -4
  181. package/lib/utils/credential-display.js +43 -1
  182. package/lib/utils/deployment-errors.js +15 -0
  183. package/lib/utils/deployment-validation-helpers.js +4 -1
  184. package/lib/utils/device-code.js +31 -10
  185. package/lib/utils/error-formatters/error-parser.js +16 -1
  186. package/lib/utils/error-formatters/permission-errors.js +19 -5
  187. package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
  188. package/lib/utils/external-system-readiness-compact-display.js +30 -1
  189. package/lib/utils/external-system-validators.js +2 -1
  190. package/lib/utils/help-builder.js +3 -1
  191. package/lib/utils/keycloak-realm-ready.js +5 -2
  192. package/lib/utils/logger.js +1 -0
  193. package/lib/utils/paths.js +26 -5
  194. package/lib/utils/schema-loader.js +37 -0
  195. package/lib/utils/secrets-helpers.js +2 -2
  196. package/lib/utils/write-stream-and-wait.js +63 -0
  197. package/lib/validation/validate-external-file.js +5 -1
  198. package/lib/validation/validate.js +3 -2
  199. package/package.json +20 -6
  200. package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
  201. package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
  202. package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
  203. package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
  204. package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
  205. package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
  206. package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
  207. package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
  208. package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
  209. package/templates/agent-kit/agent-kit.yaml +45 -0
  210. package/templates/agent-kit/instructions/AGENTKIT.md +104 -0
  211. package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
  212. package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
  213. package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
  214. package/templates/agent-kit/parity-inventory.yaml +188 -0
  215. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +59 -0
  216. package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
  217. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
  218. package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
  219. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
  220. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +52 -0
  221. package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
  222. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
  223. package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
  224. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +51 -0
  225. package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
  226. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
  227. package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
  228. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +43 -0
  229. package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
  230. package/templates/agent-kit/skills/shared/hosts.md +65 -0
  231. package/templates/agent-kit/skills/shared/login.md +16 -0
  232. package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
  233. package/templates/agent-kit/workspace/LICENSE.mit +21 -0
  234. package/templates/agent-kit/workspace/README.md +89 -0
  235. package/templates/applications/builder-api/Dockerfile +3 -1
  236. package/templates/applications/dataplane/application.yaml +2 -3
  237. package/templates/applications/dataplane/env.template +5 -5
  238. package/templates/applications/dataplane/rbac.yaml +28 -0
  239. package/templates/applications/keycloak/env.template +3 -3
  240. package/templates/applications/miso-controller/application.yaml +21 -2
  241. package/templates/applications/miso-controller/env.template +96 -25
  242. package/templates/applications/miso-controller/rbac.yaml +5 -0
  243. package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
  244. package/templates/channels/claude/channel.json +1 -1
  245. package/templates/channels/claude/install.template.md.hbs +1 -0
  246. package/templates/channels/claude/integration/claude-system.json +1 -1
  247. package/templates/channels/slack/channel.json +11 -0
  248. package/templates/channels/slack/install.template.md.hbs +9 -0
  249. package/templates/channels/slack/integration/slack-system.json +11 -0
  250. package/templates/channels/slack/manifest.template.json.hbs +6 -3
  251. package/templates/channels/teams-bot/channel.json +1 -0
  252. package/templates/python/docker-compose.hbs +14 -0
  253. package/templates/typescript/docker-compose.hbs +14 -0
@@ -21,6 +21,14 @@ const OPENAPI_APPLY_RESULT_SCHEMAS = {
21
21
  },
22
22
  ['deployed']
23
23
  ),
24
+ DownloadResultData: frozenObject(
25
+ {
26
+ downloaded: { type: 'boolean' },
27
+ dryRun: { type: 'boolean' },
28
+ systemKey: schemaRef('SystemKey')
29
+ },
30
+ ['downloaded', 'dryRun', 'systemKey']
31
+ ),
24
32
  ProtectionUploadData: frozenObject(
25
33
  {
26
34
  datasourceKey: schemaRef('DatasourceKey'),
@@ -90,6 +90,7 @@ const OPENAPI_CHANNEL_INSTALL_RESULT_SCHEMAS = {
90
90
  provisioning: schemaRef('ChannelProvisioning'),
91
91
  runtimeTarget: schemaRef('ChannelRuntimeTarget'),
92
92
  experimental: { type: 'boolean' },
93
+ status: { type: 'string', enum: ['visible', 'hide', 'coming-soon'] },
93
94
  maxInstances: { type: 'integer', minimum: 1 },
94
95
  profiles: { type: 'array', items: schemaRef('ChannelTargetProfile') }
95
96
  }),
@@ -108,7 +109,8 @@ const OPENAPI_CHANNEL_INSTALL_RESULT_SCHEMAS = {
108
109
  maxInstances: { type: 'integer', minimum: 1 },
109
110
  installationCount: { type: 'integer', minimum: 0 },
110
111
  canInstall: { type: 'boolean' },
111
- blockedReason: { type: 'string' }
112
+ blockedReason: { type: 'string' },
113
+ status: { type: 'string', enum: ['visible', 'hide', 'coming-soon'] }
112
114
  },
113
115
  ['key', 'displayName', 'channel', 'installations']
114
116
  ),
@@ -140,6 +142,7 @@ const OPENAPI_CHANNEL_INSTALL_RESULT_SCHEMAS = {
140
142
  displayLabel: { type: 'string' },
141
143
  description: { type: 'string' },
142
144
  experimental: { type: 'boolean' },
145
+ status: { type: 'string', enum: ['visible', 'hide', 'coming-soon'] },
143
146
  provisioning: schemaRef('ChannelProvisioning'),
144
147
  runtimeTarget: schemaRef('ChannelRuntimeTarget'),
145
148
  installationSummary: schemaRef('ChannelInstallationSummary'),
@@ -40,6 +40,7 @@ const RESPONSE_ENVELOPES = [
40
40
  ['PreviewUploadResponse', 'PreviewUploadData'],
41
41
  ['UploadResultResponse', 'UploadResultData'],
42
42
  ['DeployResultResponse', 'DeployResultData'],
43
+ ['DownloadResultResponse', 'DownloadResultData'],
43
44
  ['ProtectionUploadResponse', 'ProtectionUploadData'],
44
45
  ['ProtectionCreateResponse', 'ProtectionCreateData'],
45
46
  ['TestResultResponse', 'TestResultData'],
@@ -140,6 +140,12 @@ const OPERATION_DESCRIPTIONS = Object.freeze({
140
140
  'Controller deploy for external systems (CLI aifabrix deploy parity). Optional body.gate matches CLI --gate (operations,trust,governance,full). Certificate seal is a platform side-effect of published Deploy — not a separate certificates issue call. Mutating; use Idempotency-Key.',
141
141
  tags: ['apply']
142
142
  },
143
+ runDownload: {
144
+ summary: 'Download system package into the workspace',
145
+ description:
146
+ 'Fetch the published system from Dataplane into the workspace (CLI aifabrix download parity). Role Assistant packages also pull Evidence, Knowledge, and tests. Mutating; use Idempotency-Key.',
147
+ tags: ['workspace']
148
+ },
143
149
  runProtectionUpload: {
144
150
  summary: 'Upload protection manifest for a datasource',
145
151
  description:
@@ -269,13 +275,13 @@ const OPERATION_DESCRIPTIONS = Object.freeze({
269
275
  listChannelTargets: {
270
276
  summary: 'List live channel definitions',
271
277
  description:
272
- 'List live Channel Definitions. Each row has key, displayLabel, description, experimental, provisioning, runtimeTarget, installationSummary, installationCount, and canInstall. Optional maxInstances and blockedReason when capped. Catalog is information-only; publishing uses POST install. Read-only.',
278
+ 'List live Channel Definitions. Each row has key, displayLabel, description, experimental, status, provisioning, runtimeTarget, installationSummary, installationCount, and canInstall. Optional maxInstances and blockedReason when capped or coming-soon. hide definitions are omitted. Catalog is information-only; publishing uses POST install. Read-only.',
273
279
  tags: ['infra']
274
280
  },
275
281
  getChannelDefinitionDetail: {
276
282
  summary: 'Get a Channel Definition',
277
283
  description:
278
- 'Return a safe Channel Definition (identity, configuration, provisioning, runtimeTarget, profiles, optional maxInstances) plus installations projected from Dataplane Connected Systems. Includes canInstall. Unknown definition keys return 404. Known definitions with no instances return installations []. Read-only.',
284
+ 'Return a safe Channel Definition (identity, configuration, provisioning, runtimeTarget, profiles, optional maxInstances, status) plus installations projected from Dataplane Connected Systems. Includes canInstall. Unknown or hide definition keys return 404. Known definitions with no instances return installations []. Read-only.',
279
285
  tags: ['infra']
280
286
  },
281
287
  getChannelInstallation: {
@@ -287,7 +293,7 @@ const OPERATION_DESCRIPTIONS = Object.freeze({
287
293
  runChannelInstall: {
288
294
  summary: 'Install a channel',
289
295
  description:
290
- 'Scaffold, upload, and configure a channel from a Channel Definition. Path systemKey is the definition key. Body name is required; optional systemKey is the Connected System instance key; configuration is a generic propertyKey map. Returns help markdown plus phase, safe userActions, definitionKey, installationKey, and systemKey (the instance). Mutating.',
296
+ 'Scaffold, upload, and configure a channel from a Channel Definition. Path systemKey is the definition key. Body name is required; optional systemKey is the Connected System instance key; configuration is a generic propertyKey map. hide and coming-soon definitions return 403; --force does not override. Returns help markdown plus phase, safe userActions, definitionKey, installationKey, and systemKey (the instance). Mutating.',
291
297
  tags: ['infra']
292
298
  },
293
299
  getChannelInstall: {
@@ -141,6 +141,11 @@ const OPENAPI_ENVELOPE_DATA_EXAMPLES = {
141
141
  environment: 'dev',
142
142
  systemKey: SAMPLE_SYSTEM_KEY
143
143
  },
144
+ DownloadResultData: {
145
+ downloaded: true,
146
+ dryRun: false,
147
+ systemKey: SAMPLE_SYSTEM_KEY
148
+ },
144
149
  ProtectionUploadData: {
145
150
  datasourceKey: SAMPLE_DATASOURCE_KEY,
146
151
  uploaded: true,
@@ -282,6 +287,7 @@ const OPENAPI_ENVELOPE_DATA_EXAMPLES = {
282
287
  displayLabel: 'ChatGPT',
283
288
  description: 'ChatGPT channel',
284
289
  experimental: false,
290
+ status: 'visible',
285
291
  provisioning: { mode: 'guided' },
286
292
  runtimeTarget: { defaultSystemKey: 'runtime-orchestration', configurable: true },
287
293
  installationSummary: { count: 0, statusRollup: 'none' },
@@ -310,6 +316,7 @@ const OPENAPI_ENVELOPE_DATA_EXAMPLES = {
310
316
  provisioning: { mode: 'guided' },
311
317
  runtimeTarget: { defaultSystemKey: 'runtime-orchestration', configurable: true },
312
318
  experimental: false,
319
+ status: 'visible',
313
320
  profiles: []
314
321
  },
315
322
  installations: []
@@ -233,6 +233,11 @@ const OPERATION_BINDINGS = Object.freeze({
233
233
  requestBody: jsonRequestBody('DeployRequest'),
234
234
  successResponse: 'DeployResultResponse'
235
235
  },
236
+ runDownload: {
237
+ parameters: [SYSTEM_KEY_PARAM],
238
+ requestBody: jsonRequestBody('DownloadRequest'),
239
+ successResponse: 'DownloadResultResponse'
240
+ },
236
241
  runProtectionUpload: {
237
242
  parameters: [SYSTEM_KEY_PARAM, DATASOURCE_KEY_PARAM],
238
243
  requestBody: jsonRequestBody('ProtectionUploadRequest'),
@@ -147,6 +147,11 @@ const OPENAPI_REQUEST_SCHEMAS = {
147
147
  sync: { type: 'boolean' },
148
148
  verbose: { type: 'boolean' }
149
149
  }),
150
+ DownloadRequest: frozenObject({
151
+ force: { type: 'boolean' },
152
+ dryRun: { type: 'boolean' },
153
+ format: { type: 'string', enum: ['json', 'yaml'] }
154
+ }),
150
155
  ProtectionUploadRequest: frozenObject({
151
156
  dryRun: { type: 'boolean' },
152
157
  sync: { type: 'boolean' },
@@ -64,6 +64,7 @@ const CHANNEL_INSTALL_SCHEMA_DESCRIPTIONS = {
64
64
  provisioning: 'Provisioning mode for this definition.',
65
65
  runtimeTarget: 'Default runtime or MCP Connected System.',
66
66
  experimental: 'True when install requires allowExperimental.',
67
+ status: 'Catalog availability. Omit or visible: listed and installable. hide is omitted from this catalog. coming-soon: listed read-only; new install is refused.',
67
68
  maxInstances: 'Optional cap on Connected System instances for this definition. Omit for unbounded.',
68
69
  profiles: 'Optional generic install profiles (for example MCP client targets).'
69
70
  },
@@ -78,6 +79,7 @@ const CHANNEL_INSTALL_SCHEMA_DESCRIPTIONS = {
78
79
  displayLabel: 'Human-readable interface name.',
79
80
  description: 'Short catalog blurb for the portal table. Not remaining-step copy.',
80
81
  experimental: 'True when the target requires allowExperimental.',
82
+ status: 'visible: listed and installable. coming-soon: listed read-only. hide is omitted from the catalog.',
81
83
  provisioning: 'How Builder provisions this channel (automatic, guided, or cli).',
82
84
  runtimeTarget: 'Runtime or MCP Connected System. Not the channel instance key.',
83
85
  installationSummary: 'Count and status rollup of Connected System instances for this definition.',
@@ -88,12 +90,12 @@ const CHANNEL_INSTALL_SCHEMA_DESCRIPTIONS = {
88
90
  iconHref: 'Data URL for the definition icon.svg from the Builder channel template. Omitted when the template has no icon.',
89
91
  maxInstances: 'Optional instance cap from the Channel Definition. Omitted when unbounded.',
90
92
  installationCount: 'Number of Connected System instances currently projected for this definition.',
91
- canInstall: 'False when installationCount is already at maxInstances. Omitted meaning is canInstall true when unbounded.',
92
- blockedReason: 'Present when canInstall is false. Explains why a new install is refused.'
93
+ canInstall: 'False when coming-soon or when installationCount is already at maxInstances. Omitted meaning is canInstall true when unbounded.',
94
+ blockedReason: 'Present when canInstall is false. Explains why a new install is refused (coming soon or at cap).'
93
95
  },
94
96
  ListChannelTargetsData: {
95
97
  _schema: 'Catalog of live channel / interface targets.',
96
- channels: 'Live targets the caller may install. Unimplemented keys are omitted.'
98
+ channels: 'Live targets. hide is omitted. coming-soon is included read-only (canInstall false). Unimplemented keys are omitted.'
97
99
  },
98
100
  ListChannelTargetsResponse: {
99
101
  _schema: '200 response envelope for listChannelTargets.',
@@ -116,8 +118,9 @@ const CHANNEL_INSTALL_SCHEMA_DESCRIPTIONS = {
116
118
  installations: 'Connected System instances for this definition. Empty array when none exist.',
117
119
  maxInstances: 'Optional instance cap from the Channel Definition. Omitted when unbounded.',
118
120
  installationCount: 'Number of Connected System instances currently projected for this definition.',
119
- canInstall: 'False when installationCount is already at maxInstances.',
120
- blockedReason: 'Present when canInstall is false.'
121
+ canInstall: 'False when coming-soon or when installationCount is already at maxInstances.',
122
+ blockedReason: 'Present when canInstall is false.',
123
+ status: 'visible or coming-soon. hide definitions return 404 instead of this payload.'
121
124
  },
122
125
  ChannelDefinitionDetailResponse: {
123
126
  _schema: '200 response envelope for getChannelDefinitionDetail.',
@@ -124,6 +124,12 @@ const OPERATIONS_SCHEMA_DESCRIPTIONS = {
124
124
  sync: 'When true, force full datasource data sync after deploy.',
125
125
  verbose: 'When true, expand deploy summary output.'
126
126
  },
127
+ DownloadRequest: {
128
+ _schema: 'Optional flags for workspace download (CLI aifabrix download parity).',
129
+ force: 'When true, overwrite existing local package files.',
130
+ dryRun: 'When true, preview files that would be written without mutating the workspace.',
131
+ format: 'Package file format when downloading a Connected System (json or yaml).'
132
+ },
127
133
  ProtectionUploadRequest: {
128
134
  _schema: 'Optional flags for protection upload (CLI protection upload parity).',
129
135
  dryRun: 'When true, validate only; do not upload or sync.',
@@ -354,6 +360,19 @@ const OPERATIONS_SCHEMA_DESCRIPTIONS = {
354
360
  correlationId: 'UUID correlating logs for this request.',
355
361
  requestId: 'Optional per-request UUID when emitted by the server.'
356
362
  },
363
+ DownloadResultData: {
364
+ _schema: 'Workspace download outcome summary.',
365
+ downloaded: 'True when package files were written (false on dryRun).',
366
+ dryRun: 'True when validate-only dry run was requested.',
367
+ systemKey: 'Downloaded integration or Role Assistant system key.'
368
+ },
369
+ DownloadResultResponse: {
370
+ _schema: '200 response envelope for runDownload.',
371
+ success: 'Always true for successful builder-api JSON responses.',
372
+ data: 'Typed payload; see DownloadResultData.',
373
+ correlationId: 'UUID correlating logs for this request.',
374
+ requestId: 'Optional per-request UUID when emitted by the server.'
375
+ },
357
376
  ProtectionUploadData: {
358
377
  _schema: 'Protection upload outcome.',
359
378
  datasourceKey: 'Datasource key whose protection manifest was uploaded.',
@@ -88,6 +88,7 @@ function applyOperationDurationHints(capability, operation) {
88
88
  const durationByHandler = {
89
89
  runUpload: Number(process.env.MAX_UPLOAD_TIMEOUT_MS || 300000),
90
90
  runDeploySystem: Number(process.env.MAX_DEPLOY_TIMEOUT_MS || 300000),
91
+ runDownload: Number(process.env.MAX_DOWNLOAD_TIMEOUT_MS || 300000),
91
92
  runTest: Number(process.env.MAX_TEST_E2E_TIMEOUT_MS || 120000),
92
93
  runCertifyPillar: Number(process.env.MAX_CERTIFY_TIMEOUT_MS || 120000)
93
94
  };
@@ -19,6 +19,9 @@ function getTimeoutMsForHandler(handlerId) {
19
19
  if (handlerId === 'runDeploySystem') {
20
20
  return Number(process.env.MAX_DEPLOY_TIMEOUT_MS || 300000);
21
21
  }
22
+ if (handlerId === 'runDownload') {
23
+ return Number(process.env.MAX_DOWNLOAD_TIMEOUT_MS || 300000);
24
+ }
22
25
  if (handlerId === 'runTest') {
23
26
  return Number(process.env.MAX_TEST_E2E_TIMEOUT_MS || 120000);
24
27
  }
@@ -19,6 +19,7 @@ const { runRepair } = require('./run-repair');
19
19
  const { runValidate } = require('./run-validate');
20
20
  const { runPreviewUpload, runUpload } = require('./run-upload');
21
21
  const { runDeploySystem } = require('./run-deploy');
22
+ const { runDownload } = require('./run-download');
22
23
  const { runProtectionUpload, runProtectionCreate } = require('./run-protection');
23
24
  const { runTest } = require('./run-test');
24
25
  const { runCertifyPillar } = require('./run-certify');
@@ -164,6 +165,12 @@ const HANDLER_MAP = {
164
165
  sync: body.sync === true,
165
166
  verbose: body.verbose === true
166
167
  }),
168
+ runDownload: (params, auth, body = {}) =>
169
+ runDownload(buildContext(auth, params.systemKey), {
170
+ force: body.force === true,
171
+ dryRun: body.dryRun === true,
172
+ format: body.format
173
+ }),
167
174
  runProtectionUpload: (params, auth, body) =>
168
175
  runProtectionUpload(buildContext(auth, params.systemKey), params.datasourceKey, {
169
176
  dryRun: body.dryRun === true,
@@ -8,7 +8,7 @@
8
8
 
9
9
  'use strict';
10
10
 
11
- const { getChannelDefinition } = require('../channels/channel-definition-registry');
11
+ const registry = require('../channels/channel-definition-registry');
12
12
  const { listLiveChannelTargetKeys, getChannelTarget } = require('../channels/channel-targets');
13
13
  const { profilesForCatalogRow } = require('../channels/channel-install-profiles');
14
14
  const { toSafeConfiguration, toPortalFields } = require('../channels/channel-configuration-map');
@@ -23,7 +23,14 @@ const {
23
23
  } = require('../channels/channel-install-inventory');
24
24
  const { listConnectedSystemsForInventory } = require('../channels/channel-inventory-fetch');
25
25
  const { cardinalityProjection } = require('../channels/channel-cardinality');
26
+ const {
27
+ applyChannelStatusProjection,
28
+ normalizeChannelStatus
29
+ } = require('../channels/channel-definition-status');
26
30
  const { httpError } = require('./channel-install-session');
31
+ const { getExternalSystem } = require('../api/external-systems.api');
32
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
33
+ const { isNotFoundError } = require('../channels/channel-instance-collision');
27
34
 
28
35
  /**
29
36
  * @param {Object} target
@@ -32,6 +39,7 @@ const { httpError } = require('./channel-install-session');
32
39
  */
33
40
  function toChannelCatalogRow(target, installations = []) {
34
41
  const summary = summarizeInstallations(installations);
42
+ const definition = registry.getChannelDefinition(target.key);
35
43
  const row = {
36
44
  key: target.key,
37
45
  displayLabel: target.displayLabel,
@@ -49,7 +57,10 @@ function toChannelCatalogRow(target, installations = []) {
49
57
  }
50
58
  return {
51
59
  ...row,
52
- ...cardinalityProjection(getChannelDefinition(target.key), installations)
60
+ ...applyChannelStatusProjection(
61
+ normalizeChannelStatus(definition),
62
+ cardinalityProjection(definition, installations)
63
+ )
53
64
  };
54
65
  }
55
66
 
@@ -59,7 +70,7 @@ function toChannelCatalogRow(target, installations = []) {
59
70
  * @returns {Object}
60
71
  */
61
72
  function definitionListFields(definitionKey) {
62
- const definition = getChannelDefinition(definitionKey);
73
+ const definition = registry.getChannelDefinition(definitionKey);
63
74
  if (!definition) {
64
75
  return {};
65
76
  }
@@ -99,8 +110,8 @@ async function listChannelTargets(query = {}, ctx = null, deps = {}) {
99
110
  * @returns {Object}
100
111
  */
101
112
  function requireChannelDefinition(definitionKey) {
102
- const definition = getChannelDefinition(definitionKey);
103
- if (!definition) {
113
+ const definition = registry.getChannelDefinition(definitionKey);
114
+ if (!definition || normalizeChannelStatus(definition) === 'hide') {
104
115
  throw httpError(`Unknown channel definition "${definitionKey}".`, 404);
105
116
  }
106
117
  return definition;
@@ -125,6 +136,7 @@ function toSafeDefinition(definition) {
125
136
  provisioning: channel.provisioning,
126
137
  runtimeTarget: channel.runtimeTarget,
127
138
  experimental: channel.experimental === true,
139
+ status: normalizeChannelStatus(definition),
128
140
  profiles: Array.isArray(channel.profiles) ? channel.profiles : []
129
141
  }
130
142
  };
@@ -153,11 +165,39 @@ async function getChannelDefinitionDetail(ctx, definitionKey, deps = {}) {
153
165
  const installations = installationsForDefinition(systems, definition.key);
154
166
  return {
155
167
  ...toSafeDefinition(definition),
156
- ...cardinalityProjection(definition, installations),
168
+ ...applyChannelStatusProjection(
169
+ normalizeChannelStatus(definition),
170
+ cardinalityProjection(definition, installations)
171
+ ),
157
172
  installations
158
173
  };
159
174
  }
160
175
 
176
+ /**
177
+ * @param {Object} ctx
178
+ * @param {string} definitionKey
179
+ * @param {string} systemKey
180
+ * @param {Object} [deps]
181
+ * @returns {Promise<Object>}
182
+ */
183
+ async function installationFromDirectLookup(ctx, definitionKey, systemKey, deps) {
184
+ const getSystem = deps.getExternalSystem || getExternalSystem;
185
+ try {
186
+ const res = await getSystem(ctx.dataplaneUrl, systemKey, {
187
+ type: 'bearer',
188
+ token: ctx.bearerToken,
189
+ preserveBearer: true
190
+ });
191
+ const system = unwrapApiData(res);
192
+ return installationsForDefinition(system ? [system] : [], definitionKey)[0] || null;
193
+ } catch (err) {
194
+ if (isNotFoundError(err)) {
195
+ return null;
196
+ }
197
+ throw err;
198
+ }
199
+ }
200
+
161
201
  /**
162
202
  * @param {Object} ctx
163
203
  * @param {string} definitionKey
@@ -168,8 +208,10 @@ async function getChannelDefinitionDetail(ctx, definitionKey, deps = {}) {
168
208
  async function getChannelInstallation(ctx, definitionKey, systemKey, deps = {}) {
169
209
  requireChannelDefinition(definitionKey);
170
210
  const systems = await listConnectedSystemsForInventory(ctx, deps);
171
- const installations = installationsForDefinition(systems, definitionKey);
172
- const found = installations.find((row) => row.key === systemKey);
211
+ const fromList = installationsForDefinition(systems, definitionKey).find(
212
+ (row) => row.key === systemKey
213
+ );
214
+ const found = fromList || (await installationFromDirectLookup(ctx, definitionKey, systemKey, deps));
173
215
  if (!found) {
174
216
  throw httpError(
175
217
  `Channel installation "${systemKey}" was not found for "${definitionKey}".`,
@@ -56,9 +56,13 @@ function assertChannelInstallTarget(systemKey, body) {
56
56
  assertInstallProfile(systemKey, body || {});
57
57
  try {
58
58
  assertChannelTargetInstallable(systemKey, {
59
- allowExperimental: body && body.allowExperimental === true
59
+ allowExperimental: body && body.allowExperimental === true,
60
+ continueInstall: body && body.continueInstall === true
60
61
  });
61
62
  } catch (err) {
63
+ if (err && err.statusCode === 403) {
64
+ throw httpError(err.message, 403);
65
+ }
62
66
  const live = listLiveChannelTargetKeys({
63
67
  allowExperimental: body && body.allowExperimental === true
64
68
  }).join(', ');
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Programmatic download wrapper — CLI download parity for builder-api.
3
+ *
4
+ * @fileoverview runDownload for POST /systems/:systemKey/download
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { downloadExternalSystem } = require('../external-system/download');
12
+ const { runWithWorkspaceContext } = require('./workspace-context');
13
+ const { mergeProgrammaticOptions } = require('./command-options');
14
+ const { touchWorkspaceMeta } = require('./workspace-meta');
15
+
16
+ /**
17
+ * @param {import('./workspace-context').WorkspaceContext} ctx
18
+ * @param {Object} [options]
19
+ * @param {boolean} [options.force]
20
+ * @param {boolean} [options.dryRun]
21
+ * @param {string} [options.format]
22
+ * @returns {Promise<Object>}
23
+ */
24
+ async function runDownload(ctx, options = {}) {
25
+ const merged = mergeProgrammaticOptions(ctx, options);
26
+ return runWithWorkspaceContext(ctx, async() => {
27
+ await downloadExternalSystem(ctx.systemKey, merged);
28
+ if (!options.dryRun) {
29
+ touchWorkspaceMeta(ctx, { lastOperation: 'download' });
30
+ }
31
+ return {
32
+ downloaded: options.dryRun !== true,
33
+ dryRun: options.dryRun === true,
34
+ systemKey: ctx.systemKey
35
+ };
36
+ });
37
+ }
38
+
39
+ module.exports = {
40
+ runDownload
41
+ };
@@ -67,7 +67,9 @@ async function resolveCliProtectionDataplaneContext(options) {
67
67
  throw new Error('Authentication required. Run "aifabrix login" and try again.');
68
68
  }
69
69
 
70
- const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
70
+ const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig, {
71
+ silent: options.json === true || options.silent === true
72
+ });
71
73
  return { environment, controllerUrl, dataplaneUrl, authConfig };
72
74
  }
73
75
 
@@ -18,7 +18,7 @@ const {
18
18
  formatProgress,
19
19
  formatNextActions
20
20
  } = require('../utils/cli-test-layout-chalk');
21
- const { reportTaskRows } = require('./report-exit');
21
+ const { reportTaskRows, isProtectionProblemResponse } = require('./report-exit');
22
22
  const { describeProtectionRoot } = require('./paths');
23
23
  const {
24
24
  appendTaskRows,
@@ -46,7 +46,8 @@ function formatProtectionValidateTTY(report, opts = {}) {
46
46
  const meta = report?.metadata || {};
47
47
  appendProtectionReportHeader(lines, meta);
48
48
  const summary = report?.summary || {};
49
- const failCount = Number(summary.fail || 0);
49
+ const problem = isProtectionProblemResponse(report);
50
+ const failCount = problem ? Math.max(1, Number(summary.fail || 0)) : Number(summary.fail || 0);
50
51
  const warnCount = Number(summary.warn || 0);
51
52
  const aggregate = failCount > 0 ? 'fail' : warnCount > 0 ? 'warn' : 'ok';
52
53
  const glyph = aggregate === 'fail' ? '✖' : aggregate === 'warn' ? '⚠' : '✔';
@@ -23,6 +23,51 @@ function reportTaskRows(report) {
23
23
  return [];
24
24
  }
25
25
 
26
+ /**
27
+ * True when the payload is an RFC 7807 / API-client error, not a validate report.
28
+ * @param {*} report
29
+ * @returns {boolean}
30
+ */
31
+ function isProtectionProblemResponse(report) {
32
+ if (!report || typeof report !== 'object') {
33
+ return false;
34
+ }
35
+ if (report.success === false) {
36
+ return true;
37
+ }
38
+ const status = Number(report.statusCode || report.status);
39
+ if (Number.isFinite(status) && status >= 400) {
40
+ return true;
41
+ }
42
+ const type = typeof report.type === 'string' ? report.type : '';
43
+ return type.includes('/Errors/') || type.includes('application/problem');
44
+ }
45
+
46
+ /**
47
+ * @param {*} uploaded
48
+ * @returns {string}
49
+ */
50
+ function protectionUploadFailureMessage(uploaded) {
51
+ if (!uploaded || typeof uploaded !== 'object') {
52
+ return 'Protection upload returned empty response';
53
+ }
54
+ return (
55
+ uploaded.formattedError ||
56
+ uploaded.error ||
57
+ uploaded.detail ||
58
+ `Protection upload failed (HTTP ${uploaded.statusCode || uploaded.status || 0})`
59
+ );
60
+ }
61
+
62
+ /**
63
+ * @param {*} uploaded
64
+ */
65
+ function assertProtectionUploadSucceeded(uploaded) {
66
+ if (!uploaded || typeof uploaded !== 'object' || isProtectionProblemResponse(uploaded)) {
67
+ throw new Error(protectionUploadFailureMessage(uploaded));
68
+ }
69
+ }
70
+
26
71
  /**
27
72
  * @param {Object} report
28
73
  * @param {Object} [opts]
@@ -33,6 +78,9 @@ function exitCodeFromProtectionReport(report, opts = {}) {
33
78
  if (!report || typeof report !== 'object') {
34
79
  return 3;
35
80
  }
81
+ if (isProtectionProblemResponse(report)) {
82
+ return 1;
83
+ }
36
84
  const summary = report.summary || {};
37
85
  const failCount = Number(summary.fail || 0);
38
86
  const warnCount = Number(summary.warn || 0);
@@ -58,5 +106,7 @@ function exitCodeFromProtectionReport(report, opts = {}) {
58
106
 
59
107
  module.exports = {
60
108
  reportTaskRows,
109
+ isProtectionProblemResponse,
110
+ assertProtectionUploadSucceeded,
61
111
  exitCodeFromProtectionReport
62
112
  };
@@ -18,6 +18,7 @@ const {
18
18
  deleteProtection,
19
19
  findProtectionKeyByDatasource
20
20
  } = require('../api/protection.api');
21
+ const { assertProtectionUploadSucceeded } = require('./report-exit');
21
22
  const { preflightDatasourceReady } = require('./preflight-datasource-ready');
22
23
  const { runProtectionUploadDataSync } = require('./run-commands-upload-sync');
23
24
  const {
@@ -63,6 +64,7 @@ async function runProtectionUpload(datasourceKey, manifest, opts, logger) {
63
64
 
64
65
  logger.log(formatProgress('Uploading protection manifest...'));
65
66
  const uploaded = await uploadProtection(ctx.dataplaneUrl, ctx.authConfig, manifest);
67
+ assertProtectionUploadSucceeded(uploaded);
66
68
  logger.log(
67
69
  formatSuccessLine(
68
70
  `Protection for '${datasourceKey}' uploaded (deploymentId ${uploaded?.deploymentId || '—'}, revision ${uploaded?.revision ?? '—'})`