@aifabrix/builder 2.50.0 → 2.51.1

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 (236) hide show
  1. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +374 -0
  2. package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
  3. package/integration/hubspot-test/create-hubspot.js +1 -16
  4. package/jest.isolated-projects.js +77 -1
  5. package/jest.projects.js +5 -426
  6. package/lib/api/assistants.api.js +67 -0
  7. package/lib/api/datasources-extended.api.js +6 -6
  8. package/lib/api/evidence-authoring-helpers.js +267 -0
  9. package/lib/api/evidence-authoring.api.js +337 -0
  10. package/lib/api/evidence-kinds.api.js +128 -0
  11. package/lib/api/evidence.api.js +57 -1
  12. package/lib/api/index.js +24 -7
  13. package/lib/api/pipeline.api.js +47 -3
  14. package/lib/api/records-bulk.api.js +28 -3
  15. package/lib/api/resource-types.api.js +4 -4
  16. package/lib/api/roles.api.js +121 -0
  17. package/lib/api/types/evidence-kinds.types.js +42 -0
  18. package/lib/api/types/evidence.types.js +156 -8
  19. package/lib/api/types/roles.types.js +36 -0
  20. package/lib/api/work.api.js +283 -0
  21. package/lib/app/certification-verify-rows.js +1 -1
  22. package/lib/app/run-deploy-job.js +108 -0
  23. package/lib/app/run-helpers.js +10 -3
  24. package/lib/app/run.js +8 -0
  25. package/lib/app/show.js +2 -2
  26. package/lib/certification/merge-certification-from-artifact.js +1 -1
  27. package/lib/channels/add-channel.js +54 -23
  28. package/lib/channels/approval-guides/chatgpt.js +8 -7
  29. package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
  30. package/lib/channels/channel-artifact-generator.js +16 -3
  31. package/lib/channels/channel-credential.js +3 -1
  32. package/lib/channels/channel-probe-evidence.js +79 -0
  33. package/lib/channels/channel-probe.js +265 -13
  34. package/lib/channels/channel-runtime-resolver.js +120 -29
  35. package/lib/channels/channel-status-display.js +44 -0
  36. package/lib/channels/channel-targets.js +7 -0
  37. package/lib/channels/chatgpt-runtime-contract.js +29 -0
  38. package/lib/channels/microsoft-copilot-package.js +280 -0
  39. package/lib/channels/runtime-tool-catalog.js +165 -0
  40. package/lib/cli/index.js +6 -0
  41. package/lib/cli/setup-app.js +26 -5
  42. package/lib/cli/setup-dev.js +23 -7
  43. package/lib/cli/setup-external-system-help.js +8 -2
  44. package/lib/cli/setup-external-system.js +12 -0
  45. package/lib/cli/setup-utility-help-after.js +12 -0
  46. package/lib/cli/setup-utility-validate.js +41 -2
  47. package/lib/commands/app-test.js +2 -14
  48. package/lib/commands/datasource-load-export-cli.js +6 -1
  49. package/lib/commands/deploy-gate-failure-details.js +23 -0
  50. package/lib/commands/deploy-gate-orchestrator.js +64 -18
  51. package/lib/commands/dev-cli-handlers.js +6 -3
  52. package/lib/commands/dev-down.js +2 -6
  53. package/lib/commands/dev-init.js +7 -109
  54. package/lib/commands/dev-refresh.js +197 -0
  55. package/lib/commands/evidence-kind.js +478 -0
  56. package/lib/commands/governance-command-action.js +4 -2
  57. package/lib/commands/governance-generate-external.js +56 -21
  58. package/lib/commands/lifecycle-external.js +10 -4
  59. package/lib/commands/repair-datasource-apply.js +10 -1
  60. package/lib/commands/repair-datasource-run.js +4 -2
  61. package/lib/commands/repair-datasource-test-payload.js +80 -19
  62. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
  63. package/lib/commands/repair-internal.js +9 -1
  64. package/lib/commands/repair-openapi-export.js +1 -1
  65. package/lib/commands/repair-openapi-sync.js +43 -18
  66. package/lib/commands/resource-type.js +101 -18
  67. package/lib/commands/role-assistant.js +313 -0
  68. package/lib/commands/role.js +452 -0
  69. package/lib/commands/setup.js +1 -1
  70. package/lib/commands/upload-data-sync-finalize.js +5 -4
  71. package/lib/commands/upload-sidecar-followups.js +144 -47
  72. package/lib/commands/upload.js +43 -6
  73. package/lib/commands/validate-json.js +230 -0
  74. package/lib/commands/verify-governance-combined-external.js +73 -9
  75. package/lib/commands/verify-governance-db.js +80 -25
  76. package/lib/commands/verify-governance-external.js +29 -5
  77. package/lib/commands/verify-operations-step-plan.js +78 -40
  78. package/lib/commands/wizard-core-helpers.js +7 -3
  79. package/lib/commands/wizard-core.js +78 -9
  80. package/lib/core/audit-logger.js +1 -1
  81. package/lib/core/secrets-load.js +1 -3
  82. package/lib/datasource/bulk-loader-run-batches.js +4 -2
  83. package/lib/datasource/bulk-loader-service.js +5 -1
  84. package/lib/datasource/capability/relate-operations.js +1 -1
  85. package/lib/datasource/datasource-validate-summary.js +2 -2
  86. package/lib/datasource/validate.js +13 -6
  87. package/lib/external-system/deploy-helpers.js +35 -1
  88. package/lib/external-system/deploy.js +23 -10
  89. package/lib/external-system/download-helpers.js +111 -2
  90. package/lib/external-system/download-role-assistant.js +55 -0
  91. package/lib/external-system/download.js +45 -26
  92. package/lib/external-system/test-helpers.js +1 -1
  93. package/lib/external-system/test.js +39 -3
  94. package/lib/generator/builders.js +3 -0
  95. package/lib/generator/helpers.js +13 -5
  96. package/lib/generator/split-variables.js +9 -3
  97. package/lib/generator/wizard.js +51 -4
  98. package/lib/infrastructure/helpers-docker-check.js +6 -0
  99. package/lib/infrastructure/helpers.js +1 -1
  100. package/lib/lifecycle/access-control-abac.js +121 -0
  101. package/lib/lifecycle/lifecycle-governance-options.js +4 -1
  102. package/lib/lifecycle/product-model.js +3 -2
  103. package/lib/lifecycle/report-display.js +14 -2
  104. package/lib/programmatic/auth-config.js +3 -2
  105. package/lib/programmatic/bearer-auth.js +1 -1
  106. package/lib/programmatic/capability-registry.js +20 -1
  107. package/lib/programmatic/command-options.js +1 -0
  108. package/lib/programmatic/enterprise-mcp-client.js +18 -2
  109. package/lib/programmatic/index.js +4 -0
  110. package/lib/programmatic/manifest-patch-section.js +48 -9
  111. package/lib/programmatic/manifest-section-registry-data.js +3 -2
  112. package/lib/programmatic/manifest-section-registry.js +18 -1
  113. package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
  114. package/lib/programmatic/openapi-component-schemas.js +16 -1
  115. package/lib/programmatic/openapi-description-enricher.js +3 -1
  116. package/lib/programmatic/openapi-descriptions.js +55 -5
  117. package/lib/programmatic/openapi-evidence-schemas.js +161 -0
  118. package/lib/programmatic/openapi-manifest-schemas.js +6 -2
  119. package/lib/programmatic/openapi-operation-bindings.js +99 -0
  120. package/lib/programmatic/openapi-request-schemas.js +36 -1
  121. package/lib/programmatic/openapi-result-schemas.js +29 -12
  122. package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
  123. package/lib/programmatic/openapi-schema-descriptions-core.js +6 -3
  124. package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
  125. package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
  126. package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
  127. package/lib/programmatic/openapi-schema-helpers.js +16 -1
  128. package/lib/programmatic/openapi-spec.js +48 -29
  129. package/lib/programmatic/orchestration-openapi-meta.js +5 -0
  130. package/lib/programmatic/request-timeout.js +3 -0
  131. package/lib/programmatic/route-handler-map.js +89 -2
  132. package/lib/programmatic/run-certify.js +15 -2
  133. package/lib/programmatic/run-deploy.js +74 -0
  134. package/lib/programmatic/run-evidence-authoring.js +80 -0
  135. package/lib/programmatic/run-protection.js +124 -0
  136. package/lib/programmatic/run-repository-emcp.js +11 -3
  137. package/lib/programmatic/run-template-workspace.js +42 -2
  138. package/lib/programmatic/workspace-context.js +6 -0
  139. package/lib/protection/auth-context.js +48 -6
  140. package/lib/protection/paths.js +22 -0
  141. package/lib/protection/run-protection-create-helpers.js +22 -1
  142. package/lib/protection/run-protection-create.js +1 -1
  143. package/lib/protection/sync-after-upload.js +1 -1
  144. package/lib/resolvers/evidence-kind-file.js +230 -0
  145. package/lib/resolvers/resource-type-file.js +36 -1
  146. package/lib/resolvers/role-file.js +227 -0
  147. package/lib/role-assistant/evidence-sync.js +450 -0
  148. package/lib/role-assistant/github-workflow.js +96 -0
  149. package/lib/role-assistant/knowledge-sync.js +465 -0
  150. package/lib/role-assistant/settings.js +126 -0
  151. package/lib/role-assistant/test-cases-evaluate.js +170 -0
  152. package/lib/role-assistant/test-cases-honesty.js +184 -0
  153. package/lib/role-assistant/test-cases.js +364 -0
  154. package/lib/role-assistant/test-runner-workhub-answers.js +203 -0
  155. package/lib/role-assistant/test-runner-workhub.js +385 -0
  156. package/lib/role-assistant/test-runner.js +500 -0
  157. package/lib/schema/application-schema.json +36 -2
  158. package/lib/schema/deployment-rules.yaml +1 -0
  159. package/lib/schema/external-datasource.schema.json +121 -4
  160. package/lib/schema/external-system.schema.json +20 -6
  161. package/lib/schema/infra.parameter.yaml +45 -1
  162. package/lib/schema/role-assistant-settings.schema.json +108 -0
  163. package/lib/schema/type/credential-field-registry.json +19 -3
  164. package/lib/utils/api.js +52 -21
  165. package/lib/utils/app-path-resolve.js +72 -24
  166. package/lib/utils/app-register-config.js +4 -3
  167. package/lib/utils/authentication-shape.js +3 -1
  168. package/lib/utils/cli-sync-options.js +59 -3
  169. package/lib/utils/cli-utils.js +11 -3
  170. package/lib/utils/deployment-validation.js +28 -3
  171. package/lib/utils/dev-ca-install.js +5 -6
  172. package/lib/utils/dev-config.js +2 -2
  173. package/lib/utils/dev-list-sort.js +145 -0
  174. package/lib/utils/dev-platform-tls.js +0 -63
  175. package/lib/utils/docker-build.js +46 -27
  176. package/lib/utils/docker-daemon-tls-ca.js +1 -1
  177. package/lib/utils/docker-exec.js +91 -6
  178. package/lib/utils/docker-run-ephemeral.js +55 -0
  179. package/lib/utils/enterprise-knowledge-paths.js +29 -12
  180. package/lib/utils/env-copy-keycloak.js +196 -0
  181. package/lib/utils/env-copy.js +35 -4
  182. package/lib/utils/error-formatters/error-parser.js +0 -3
  183. package/lib/utils/external-env-template.js +1 -1
  184. package/lib/utils/external-system-readiness-compact-blocks.js +28 -1
  185. package/lib/utils/external-system-readiness-compact-display.js +3 -0
  186. package/lib/utils/health-check-request.js +2 -3
  187. package/lib/utils/help-builder.js +4 -0
  188. package/lib/utils/image-name.js +22 -4
  189. package/lib/utils/logger.js +37 -4
  190. package/lib/utils/manifest-source-emit.js +1 -1
  191. package/lib/utils/paths.js +98 -26
  192. package/lib/utils/pipeline-upload-auth-retry.js +19 -3
  193. package/lib/utils/postgres-platform-bootstrap.js +24 -17
  194. package/lib/utils/postgres-wipe.js +5 -2
  195. package/lib/utils/remote-dev-auth.js +39 -4
  196. package/lib/utils/resolve-docker-image-ref.js +36 -6
  197. package/lib/utils/role-assistant-paths.js +98 -0
  198. package/lib/utils/schema-loader.js +41 -0
  199. package/lib/utils/schema-resolver.js +36 -4
  200. package/lib/utils/token-manager.js +47 -22
  201. package/lib/utils/upload-sync-options.js +17 -3
  202. package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
  203. package/lib/validation/external-manifest-validator.js +31 -8
  204. package/lib/validation/openapi-contract-surface-validator.js +4 -0
  205. package/lib/validation/validate-external-file.js +8 -1
  206. package/lib/validation/validator.js +6 -5
  207. package/package.json +35 -12
  208. package/scripts/export-builder-api-evidence.js +3 -3
  209. package/scripts/lib/plan-actor.js +2 -2
  210. package/scripts/lib/plan-meta.js +1 -1
  211. package/scripts/lib/plan-parse.js +1 -1
  212. package/scripts/lib/plan-prevalidate-gates.js +12 -1
  213. package/scripts/lib/plan-run-report.js +13 -2
  214. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +10 -10
  215. package/templates/applications/dataplane/application.yaml +47 -17
  216. package/templates/applications/dataplane/env.template +28 -9
  217. package/templates/applications/dataplane/rbac.yaml +78 -2
  218. package/templates/applications/miso-controller/application.yaml +10 -1
  219. package/templates/applications/miso-controller/env.template +13 -8
  220. package/templates/applications/miso-controller/rbac.yaml +72 -0
  221. package/templates/channels/chatgpt/install.template.md.hbs +42 -24
  222. package/templates/channels/chatgpt/integration/README.md +10 -7
  223. package/templates/channels/chatgpt/integration/application.json +2 -2
  224. package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
  225. package/templates/channels/chatgpt/integration/env.template +1 -1
  226. package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
  227. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
  228. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
  229. package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
  230. package/templates/channels/microsoft-copilot/integration/README.md +9 -7
  231. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  232. package/templates/channels/microsoft-copilot/integration/env.template +1 -1
  233. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
  234. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
  235. package/templates/channels/slack/integration/slack-system.json +60 -2
  236. package/templates/python/requirements.txt +1 -1
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * @fileoverview JSDoc types for Evidence Fabrix dataplane API.
3
3
  * @author AI Fabrix Team
4
- * @version 1.0.0
4
+ * @version 1.1.0
5
5
  */
6
6
 
7
7
  /**
8
- * @typedef {'active' | 'disabled'} EvidenceStatus
8
+ * @typedef {'candidate' | 'active' | 'disabled' | 'archived'} EvidenceStatus
9
9
  */
10
10
 
11
11
  /**
@@ -19,11 +19,44 @@
19
19
  * @property {string|null} [roleKey]
20
20
  */
21
21
 
22
+ /**
23
+ * @typedef {Object} EvidenceContributionOverride
24
+ * @property {string} contributionKey
25
+ * @property {number} referenceValue
26
+ */
27
+
28
+ /**
29
+ * @typedef {Object} EvidenceValueProposal
30
+ * @property {number|null} [primaryReferenceValue]
31
+ * @property {string|null} [primaryContributionKey]
32
+ * @property {string|null} [unit]
33
+ * @property {string|null} [rationale]
34
+ * @property {EvidenceContributionOverride[]} [overrides]
35
+ */
36
+
37
+ /**
38
+ * @typedef {Object} EvidenceContributionProjectionItem
39
+ * @property {string} contributionKey
40
+ * @property {string|null} [typeRef]
41
+ * @property {string|null} [unit]
42
+ * @property {boolean} [primary]
43
+ * @property {number|null} [inheritedReferenceValue]
44
+ * @property {number|null} [effectiveReferenceValue]
45
+ * @property {boolean} [overridden]
46
+ * @property {string|null} [attributionKey]
47
+ * @property {string|null} [attributionBoundary]
48
+ * @property {string|null} [kindKey]
49
+ * @property {string|null} [kindVersion]
50
+ */
51
+
22
52
  /**
23
53
  * @typedef {Object} EvidenceRow
24
54
  * @property {string} id
25
- * @property {string} resourceType
55
+ * @property {string|null} [key]
56
+ * @property {string|null} [resourceType]
26
57
  * @property {string|null} [roleKey]
58
+ * @property {string|null} [kindKey]
59
+ * @property {string|null} [kindVersion]
27
60
  * @property {string} title
28
61
  * @property {string|null} [description]
29
62
  * @property {string} when
@@ -32,23 +65,34 @@
32
65
  * @property {EvidenceStatus} status
33
66
  * @property {number|null} [generationConfidence]
34
67
  * @property {string|null} [suggestionExplanation]
68
+ * @property {EvidenceContributionOverride[]|null} [contributionOverrides]
69
+ * @property {EvidenceValueProposal|null} [valueProposal]
70
+ * @property {EvidenceContributionProjectionItem[]|null} [contributionProjection]
71
+ * @property {string|null} [fingerprint]
72
+ * @property {Object|null} [provenanceSummary]
73
+ * @property {Object|null} [trustProjections]
35
74
  * @property {EvidenceApprovalPolicy} approval
36
- * @property {'human' | 'assistant'} createdByType
37
- * @property {string} createdById
38
- * @property {string} createdAt
39
- * @property {string} updatedAt
75
+ * @property {'human' | 'assistant'} [createdByType]
76
+ * @property {string|Object} [createdById]
77
+ * @property {string} [createdAt]
78
+ * @property {string} [updatedAt]
40
79
  */
41
80
 
42
81
  /**
43
82
  * @typedef {Object} EvidenceCreatePayload
44
- * @property {string} resourceType
83
+ * @property {string|null} [key]
84
+ * @property {string|null} [resourceType]
45
85
  * @property {string|null} [roleKey]
86
+ * @property {string|null} [kindKey]
87
+ * @property {string|null} [kindVersion]
46
88
  * @property {string} title
47
89
  * @property {string|null} [description]
48
90
  * @property {string} when
49
91
  * @property {string} expectedBehavior
50
92
  * @property {number|null} [order]
51
93
  * @property {EvidenceStatus} [status]
94
+ * @property {EvidenceContributionOverride[]} [contributionOverrides]
95
+ * @property {string|null} [suggestionExplanation]
52
96
  * @property {EvidenceApprovalPolicy} [approval]
53
97
  */
54
98
 
@@ -62,6 +106,110 @@
62
106
  * @property {string} [roleKey]
63
107
  * @property {boolean} [genericOnly]
64
108
  * @property {EvidenceStatus} [status]
109
+ * @property {string} [kindKey]
110
+ * @property {string} [aspect]
111
+ * @property {string} [search]
112
+ * @property {number} [limit]
113
+ * @property {number} [offset]
114
+ */
115
+
116
+ /**
117
+ * @typedef {Object} EvidenceMetadataKind
118
+ * @property {string|null} key
119
+ * @property {string|null} version
120
+ * @property {string|null} [displayName]
121
+ * @property {string|null} [purpose]
122
+ */
123
+
124
+ /**
125
+ * @typedef {Object} EvidenceMetadataResourceType
126
+ * @property {string|null} key
127
+ * @property {string|null} [displayName]
128
+ * @property {string|null} [category]
129
+ */
130
+
131
+ /**
132
+ * @typedef {Object} EvidenceAuthoringMetadata
133
+ * @property {string} roleKey
134
+ * @property {EvidenceMetadataKind[]} evidenceKinds
135
+ * @property {string[]} aspects
136
+ * @property {EvidenceMetadataResourceType[]} resourceTypes
137
+ * @property {string[]} assistantCapabilities
138
+ * @property {string[]} writableFields
139
+ * @property {string[]} requiredFields
140
+ * @property {Object} constraints
141
+ * @property {Object} constraints.certification
142
+ * @property {string} constraints.certification.validationStatus
143
+ * @property {string} constraints.certification.candidateStatus
144
+ * @property {Object} constraints.activation
145
+ * @property {boolean} constraints.activation.requiresCertified
146
+ * @property {boolean} constraints.activation.requiresAuthority
147
+ */
148
+
149
+ /**
150
+ * @typedef {EvidenceListParams & { roleKey: string }} EvidenceDownloadParams
151
+ */
152
+
153
+ /**
154
+ * @typedef {Object} EvidenceDownloadResponse
155
+ * @property {string} roleKey
156
+ * @property {number} count
157
+ * @property {EvidenceRow[]} data
158
+ */
159
+
160
+ /**
161
+ * @typedef {Object} EvidenceUploadRequest
162
+ * @property {string} roleKey
163
+ * @property {EvidenceCreatePayload[]} rows
164
+ * @property {string} [comment]
165
+ */
166
+
167
+ /**
168
+ * @typedef {Object} EvidenceUploadAcceptedItem
169
+ * @property {number} index
170
+ * @property {string} evidenceRef
171
+ * @property {string} status
172
+ */
173
+
174
+ /**
175
+ * @typedef {Object} EvidenceUploadRejectedItem
176
+ * @property {number} index
177
+ * @property {string} error
178
+ * @property {string} [evidenceRef]
179
+ * @property {Object[]} [issues]
180
+ */
181
+
182
+ /**
183
+ * @typedef {Object} EvidenceUploadCertifiedItem
184
+ * @property {number} index
185
+ * @property {string} evidenceRef
186
+ * @property {string} status
187
+ * @property {Object} data
188
+ */
189
+
190
+ /**
191
+ * @typedef {Object} EvidenceUploadResponse
192
+ * @property {string} roleKey
193
+ * @property {number} inserted
194
+ * @property {number} updated
195
+ * @property {EvidenceUploadAcceptedItem[]} accepted
196
+ * @property {EvidenceUploadRejectedItem[]} rejected
197
+ * @property {Object[]} warnings
198
+ * @property {EvidenceUploadCertifiedItem[]} certified
199
+ * @property {boolean} readyToActivate
200
+ */
201
+
202
+ /**
203
+ * @typedef {Object} EvidenceActivateRequest
204
+ * @property {string[]} evidenceIds
205
+ */
206
+
207
+ /**
208
+ * @typedef {Object} EvidenceActivateResponse
209
+ * @property {number} requested
210
+ * @property {Array<{ evidenceId: string, result: Object }>} activated
211
+ * @property {Array<{ evidenceId: string, error: string, status: number|null }>} failed
212
+ * @property {boolean} success
65
213
  */
66
214
 
67
215
  module.exports = {};
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileoverview Business role API type definitions (Controller /api/v1/roles)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ /**
8
+ * Create business role request body (API shape uses domainKey)
9
+ * @typedef {Object} CreateBusinessRoleRequest
10
+ * @property {string} key - Catalog key (lowercase, hyphens)
11
+ * @property {string} domainKey - Enterprise domain key
12
+ * @property {string} displayName - Human-readable name
13
+ * @property {string} [description] - Optional description
14
+ * @property {string} [purpose] - Role purpose
15
+ * @property {string} [businessOutcome] - Business outcome
16
+ * @property {boolean} [isActive] - Active flag
17
+ * @property {string} [source] - Provenance source
18
+ * @property {Object} [metadata] - Compiler fields and extensions
19
+ */
20
+
21
+ /**
22
+ * Business role record
23
+ * @typedef {Object} BusinessRoleRecord
24
+ * @property {string} id - Controller id
25
+ * @property {string} key - Catalog key
26
+ * @property {string} domainKey - Enterprise domain key
27
+ * @property {string} displayName - Display name
28
+ * @property {string} [description] - Description
29
+ * @property {string} [purpose] - Purpose
30
+ * @property {string} [businessOutcome] - Business outcome
31
+ * @property {boolean} isActive - Active flag
32
+ * @property {string} [source] - Source
33
+ * @property {Object} [metadata] - Metadata
34
+ */
35
+
36
+ module.exports = {};
@@ -0,0 +1,283 @@
1
+ /**
2
+ * @fileoverview Dataplane work runtime API client for role-assistant test flows.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { createDataplaneApiClient } = require('./index');
10
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
11
+
12
+ /** Work Hub plan create runs LLM planning; 30s default is too short under load/reload. */
13
+ const WORK_PLAN_TIMEOUT_MS = 120000;
14
+ /** Task poll / result fetch can wait on Celery + CIP. */
15
+ const WORK_TASK_TIMEOUT_MS = 60000;
16
+
17
+ /**
18
+ * Some dataplane work routes return `{ data: { … } }` while ApiClient already
19
+ * wraps once — peel a nested `data` envelope when top-level identity is missing.
20
+ */
21
+ function unwrapWorkPayload(res) {
22
+ const cur = unwrapApiData(res);
23
+ if (!cur || typeof cur !== 'object' || Array.isArray(cur)) {
24
+ return cur;
25
+ }
26
+ if (cur.planId || cur.taskId || cur.processExecutionId || cur.status || cur.schemaVersion) {
27
+ return cur;
28
+ }
29
+ if (cur.data && typeof cur.data === 'object' && !Array.isArray(cur.data)) {
30
+ return cur.data;
31
+ }
32
+ return cur;
33
+ }
34
+
35
+ function extractApiErrorMessage(res, fallbackMessage) {
36
+ return (
37
+ (res &&
38
+ res.error &&
39
+ (res.error.formattedError || res.error.error || res.error.message || res.error.detail)) ||
40
+ (res && (res.formattedError || res.error || res.message)) ||
41
+ fallbackMessage
42
+ );
43
+ }
44
+
45
+ function assertObjectShape(value, fallbackMessage) {
46
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
47
+ throw new Error(fallbackMessage);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * POST /api/v1/work/start
53
+ * @requiresPermission {Dataplane} worker-task:create
54
+ * @async
55
+ * @param {string} dataplaneUrl
56
+ * @param {Object} authConfig
57
+ * @param {Object} body
58
+ * @returns {Promise<Object>}
59
+ */
60
+ async function startWorkIntent(dataplaneUrl, authConfig, body) {
61
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
62
+ const res = await client.post('/api/v1/work/start', { body });
63
+ if (res && res.success === false) {
64
+ throw new Error(extractApiErrorMessage(res, 'work.start request failed'));
65
+ }
66
+ const unwrapped = unwrapWorkPayload(res);
67
+ assertObjectShape(unwrapped, 'work.start returned an unexpected response shape');
68
+ return unwrapped;
69
+ }
70
+
71
+ /**
72
+ * GET /api/v1/work/executions/{processExecutionId}
73
+ * @requiresPermission {Dataplane} worker-task:read
74
+ * @async
75
+ * @param {string} dataplaneUrl
76
+ * @param {Object} authConfig
77
+ * @param {string} processExecutionId
78
+ * @returns {Promise<Object>}
79
+ */
80
+ async function getWorkExecutionStatus(dataplaneUrl, authConfig, processExecutionId) {
81
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
82
+ const encodedId = encodeURIComponent(String(processExecutionId));
83
+ const res = await client.get(`/api/v1/work/executions/${encodedId}`, {
84
+ timeoutMs: WORK_TASK_TIMEOUT_MS
85
+ });
86
+ if (res && res.success === false) {
87
+ throw new Error(extractApiErrorMessage(res, 'work.status request failed'));
88
+ }
89
+ const unwrapped = unwrapWorkPayload(res);
90
+ assertObjectShape(unwrapped, 'work.status returned an unexpected response shape');
91
+ return unwrapped;
92
+ }
93
+
94
+ /**
95
+ * POST /api/v1/work/executions/{processExecutionId}/respond
96
+ * @requiresPermission {Dataplane} worker-task:update
97
+ * @async
98
+ * @param {string} dataplaneUrl
99
+ * @param {Object} authConfig
100
+ * @param {string} processExecutionId
101
+ * @param {Object} body
102
+ * @returns {Promise<Object>}
103
+ */
104
+ async function respondWorkExecution(dataplaneUrl, authConfig, processExecutionId, body) {
105
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
106
+ const encodedId = encodeURIComponent(String(processExecutionId));
107
+ const res = await client.post(`/api/v1/work/executions/${encodedId}/respond`, {
108
+ body,
109
+ timeoutMs: WORK_TASK_TIMEOUT_MS
110
+ });
111
+ if (res && res.success === false) {
112
+ throw new Error(extractApiErrorMessage(res, 'work.respond request failed'));
113
+ }
114
+ const unwrapped = unwrapWorkPayload(res);
115
+ assertObjectShape(unwrapped, 'work.respond returned an unexpected response shape');
116
+ return unwrapped;
117
+ }
118
+
119
+ /**
120
+ * POST /api/v1/work/executions/{processExecutionId}/continue
121
+ * @requiresPermission {Dataplane} worker-task:update
122
+ * @async
123
+ * @param {string} dataplaneUrl
124
+ * @param {Object} authConfig
125
+ * @param {string} processExecutionId
126
+ * @param {Object} [body]
127
+ * @returns {Promise<Object>}
128
+ */
129
+ async function continueWorkExecution(dataplaneUrl, authConfig, processExecutionId, body = {}) {
130
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
131
+ const encodedId = encodeURIComponent(String(processExecutionId));
132
+ const res = await client.post(`/api/v1/work/executions/${encodedId}/continue`, {
133
+ body,
134
+ timeoutMs: WORK_TASK_TIMEOUT_MS
135
+ });
136
+ if (res && res.success === false) {
137
+ throw new Error(extractApiErrorMessage(res, 'work.continue request failed'));
138
+ }
139
+ const unwrapped = unwrapWorkPayload(res);
140
+ assertObjectShape(unwrapped, 'work.continue returned an unexpected response shape');
141
+ return unwrapped;
142
+ }
143
+
144
+ /**
145
+ * GET /api/v1/work/executions/{processExecutionId}/result
146
+ * @requiresPermission {Dataplane} worker-task:read
147
+ * @async
148
+ * @param {string} dataplaneUrl
149
+ * @param {Object} authConfig
150
+ * @param {string} processExecutionId
151
+ * @param {Object} [query]
152
+ * @returns {Promise<Object>}
153
+ */
154
+ async function getWorkExecutionResult(dataplaneUrl, authConfig, processExecutionId, query = {}) {
155
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
156
+ const encodedId = encodeURIComponent(String(processExecutionId));
157
+ const params = {};
158
+ if (query && typeof query === 'object') {
159
+ if (query.requestedDepth) {
160
+ params.requestedDepth = String(query.requestedDepth);
161
+ }
162
+ if (query.format) {
163
+ params.format = String(query.format);
164
+ }
165
+ if (query.projection) {
166
+ params.projection = String(query.projection);
167
+ }
168
+ }
169
+ const res = await client.get(`/api/v1/work/executions/${encodedId}/result`, {
170
+ params,
171
+ timeoutMs: WORK_TASK_TIMEOUT_MS
172
+ });
173
+ if (res && res.success === false) {
174
+ throw new Error(extractApiErrorMessage(res, 'work.result request failed'));
175
+ }
176
+ const unwrapped = unwrapWorkPayload(res);
177
+ assertObjectShape(unwrapped, 'work.result returned an unexpected response shape');
178
+ return unwrapped;
179
+ }
180
+
181
+ /**
182
+ * POST /api/v1/work/tasks/plan — Work Hub plan (objective → Role Assistant).
183
+ * @requiresPermission {Dataplane} worker-task:create
184
+ */
185
+ async function createWorkTaskPlan(dataplaneUrl, authConfig, body) {
186
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
187
+ const res = await client.post('/api/v1/work/tasks/plan', {
188
+ body,
189
+ timeoutMs: WORK_PLAN_TIMEOUT_MS
190
+ });
191
+ if (res && res.success === false) {
192
+ throw new Error(extractApiErrorMessage(res, 'work.tasks.plan request failed'));
193
+ }
194
+ const unwrapped = unwrapWorkPayload(res);
195
+ assertObjectShape(unwrapped, 'work.tasks.plan returned an unexpected response shape');
196
+ return unwrapped;
197
+ }
198
+
199
+ /**
200
+ * POST /api/v1/work/tasks/plan/{planId}/activate-assistant
201
+ * @requiresPermission {Dataplane} worker-task:update
202
+ */
203
+ async function activateWorkPlanAssistant(dataplaneUrl, authConfig, planId, body) {
204
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
205
+ const encodedId = encodeURIComponent(String(planId));
206
+ const res = await client.post(`/api/v1/work/tasks/plan/${encodedId}/activate-assistant`, {
207
+ body,
208
+ timeoutMs: WORK_TASK_TIMEOUT_MS
209
+ });
210
+ if (res && res.success === false) {
211
+ throw new Error(extractApiErrorMessage(res, 'work.tasks.plan.activate-assistant failed'));
212
+ }
213
+ const unwrapped = unwrapWorkPayload(res);
214
+ assertObjectShape(unwrapped, 'activate-assistant returned an unexpected response shape');
215
+ return unwrapped;
216
+ }
217
+
218
+ /**
219
+ * POST /api/v1/work/tasks/plan/{planId}/accept
220
+ * @requiresPermission {Dataplane} worker-task:update
221
+ */
222
+ async function acceptWorkTaskPlan(dataplaneUrl, authConfig, planId, body = {}) {
223
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
224
+ const encodedId = encodeURIComponent(String(planId));
225
+ const res = await client.post(`/api/v1/work/tasks/plan/${encodedId}/accept`, {
226
+ body: { planId, ...body },
227
+ timeoutMs: WORK_PLAN_TIMEOUT_MS
228
+ });
229
+ if (res && res.success === false) {
230
+ throw new Error(extractApiErrorMessage(res, 'work.tasks.plan.accept failed'));
231
+ }
232
+ const unwrapped = unwrapWorkPayload(res);
233
+ assertObjectShape(unwrapped, 'work.tasks.plan.accept returned an unexpected response shape');
234
+ return unwrapped;
235
+ }
236
+
237
+ /**
238
+ * GET /api/v1/work/tasks/{taskId}
239
+ * @requiresPermission {Dataplane} worker-task:read
240
+ */
241
+ async function getWorkTask(dataplaneUrl, authConfig, taskId) {
242
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
243
+ const encodedId = encodeURIComponent(String(taskId));
244
+ const res = await client.get(`/api/v1/work/tasks/${encodedId}`, {
245
+ timeoutMs: WORK_TASK_TIMEOUT_MS
246
+ });
247
+ if (res && res.success === false) {
248
+ throw new Error(extractApiErrorMessage(res, 'work.tasks.get failed'));
249
+ }
250
+ const unwrapped = unwrapWorkPayload(res);
251
+ assertObjectShape(unwrapped, 'work.tasks.get returned an unexpected response shape');
252
+ return unwrapped;
253
+ }
254
+
255
+ /**
256
+ * POST /api/v1/work/tasks/{taskId}/approve
257
+ * @requiresPermission {Dataplane} worker-task:update
258
+ */
259
+ async function approveWorkTask(dataplaneUrl, authConfig, taskId, body = {}) {
260
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
261
+ const encodedId = encodeURIComponent(String(taskId));
262
+ const res = await client.post(`/api/v1/work/tasks/${encodedId}/approve`, {
263
+ body: { taskId, ...body },
264
+ timeoutMs: WORK_TASK_TIMEOUT_MS
265
+ });
266
+ if (res && res.success === false) {
267
+ throw new Error(extractApiErrorMessage(res, 'work.tasks.approve failed'));
268
+ }
269
+ return unwrapWorkPayload(res);
270
+ }
271
+
272
+ module.exports = {
273
+ startWorkIntent,
274
+ getWorkExecutionStatus,
275
+ respondWorkExecution,
276
+ continueWorkExecution,
277
+ getWorkExecutionResult,
278
+ createWorkTaskPlan,
279
+ activateWorkPlanAssistant,
280
+ acceptWorkTaskPlan,
281
+ getWorkTask,
282
+ approveWorkTask
283
+ };
@@ -16,7 +16,7 @@ const { getActiveIntegrationCertificate, verifyIntegrationCertificate } = requir
16
16
  function certificateIdString(id) {
17
17
  if (id === undefined || id === null) return null;
18
18
  if (typeof id === 'string') return id.trim() || null;
19
- if (typeof id === 'object' && id !== null && typeof id.id === 'string') return id.id.trim() || null;
19
+ if (typeof id === 'object' && typeof id.id === 'string') return id.id.trim() || null;
20
20
  return null;
21
21
  }
22
22
 
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Optional build.deployJob — one-shot before long-running aifabrix run start.
3
+ *
4
+ * @fileoverview Run deployJob once per aifabrix run
5
+ * @author AI Fabrix Team
6
+ * @version 2.0.0
7
+ */
8
+
9
+ const config = require('../core/config');
10
+ const logger = require('../utils/logger');
11
+ const {
12
+ infoLine,
13
+ formatSuccessLine,
14
+ formatBlockingError
15
+ } = require('../utils/cli-test-layout-chalk');
16
+ const { runDockerRunEphemeral } = require('../utils/docker-run-ephemeral');
17
+ const { getInfraBridgeNetworkName } = require('../infrastructure/orphan-infra-docker-teardown');
18
+
19
+ /**
20
+ * Resolve trimmed deployJob from app config, or null if unset.
21
+ * @param {Object} appConfig - Application configuration
22
+ * @returns {string|null}
23
+ */
24
+ function resolveDeployJobCommand(appConfig) {
25
+ const raw = appConfig?.build?.deployJob;
26
+ if (typeof raw !== 'string') {
27
+ return null;
28
+ }
29
+ const trimmed = raw.trim();
30
+ return trimmed ? trimmed : null;
31
+ }
32
+
33
+ /**
34
+ * Developer infra bridge so ephemeral jobs resolve compose DNS (e.g. postgres).
35
+ * @returns {Promise<string>}
36
+ */
37
+ async function resolveDeployJobNetwork() {
38
+ const developerId = await config.getDeveloperId();
39
+ return getInfraBridgeNetworkName(developerId);
40
+ }
41
+
42
+ /**
43
+ * If build.deployJob is set, run it once in an ephemeral container (same image + env).
44
+ * Fail-closed on non-zero exit. No-op when unset.
45
+ *
46
+ * When `devMountPath` is set (aifabrix run --reload), bind-mount that path at `/app`
47
+ * so migrate/deploy sees the same tree as the long-running reload container.
48
+ *
49
+ * @async
50
+ * @param {Object} params
51
+ * @param {Object} params.appConfig - Application configuration
52
+ * @param {string} params.fullImage - Image:tag used for the run
53
+ * @param {string|null} [params.runEnvPath] - Ephemeral .env.run path for --env-file
54
+ * @param {string|null} [params.devMountPath] - Host path mounted at /app for --reload
55
+ * @param {boolean} [params.debug]
56
+ * @returns {Promise<void>}
57
+ * @throws {Error} If deployJob exits non-zero
58
+ */
59
+ async function runDeployJobIfConfigured({
60
+ appConfig,
61
+ fullImage,
62
+ runEnvPath = null,
63
+ devMountPath = null,
64
+ debug = false
65
+ }) {
66
+ const cmd = resolveDeployJobCommand(appConfig);
67
+ if (!cmd) {
68
+ return;
69
+ }
70
+ if (!fullImage || typeof fullImage !== 'string') {
71
+ throw new Error('build.deployJob requires a resolved container image');
72
+ }
73
+ const network = await resolveDeployJobNetwork();
74
+ const volumeMounts = _deployJobVolumeMounts(devMountPath);
75
+ logger.log(infoLine(`Running build.deployJob once before start (${fullImage})…`));
76
+ if (debug) {
77
+ logger.log(infoLine(`deployJob: ${cmd}`));
78
+ logger.log(infoLine(`deployJob network: ${network}`));
79
+ if (volumeMounts.length) {
80
+ logger.log(infoLine(`deployJob mount: ${volumeMounts[0].host} -> /app`));
81
+ }
82
+ }
83
+ const code = await runDockerRunEphemeral(fullImage, cmd, runEnvPath, {
84
+ network,
85
+ volumeMounts
86
+ });
87
+ if (code !== 0) {
88
+ logger.log(formatBlockingError(`build.deployJob failed with exit code ${code}`));
89
+ throw new Error(`build.deployJob failed with exit code ${code}`);
90
+ }
91
+ logger.log(formatSuccessLine('build.deployJob completed'));
92
+ }
93
+
94
+ /**
95
+ * @param {string|null|undefined} devMountPath
96
+ * @returns {Array<{ host: string, container: string }>}
97
+ */
98
+ function _deployJobVolumeMounts(devMountPath) {
99
+ if (typeof devMountPath !== 'string' || !devMountPath.trim()) {
100
+ return [];
101
+ }
102
+ return [{ host: devMountPath.trim(), container: '/app' }];
103
+ }
104
+
105
+ module.exports = {
106
+ resolveDeployJobCommand,
107
+ runDeployJobIfConfigured
108
+ };
@@ -34,7 +34,12 @@ const runEnvCompose = require('./run-env-compose');
34
34
  const { getAppInfraRequirements } = require('./run-infra-requirements');
35
35
  const { resolveRunImage } = require('./run-resolve-image');
36
36
  const { startContainer } = require('./run-container-start');
37
- const { resolveEnvOutputPath, writeEnvOutputForReload, writeEnvOutputForLocal } = require('../utils/env-copy');
37
+ const {
38
+ resolveEnvOutputPath,
39
+ resolveEnvLocalOutputPath,
40
+ writeEnvOutputForReload,
41
+ writeEnvOutputForLocal
42
+ } = require('../utils/env-copy');
38
43
  const { resolveVersionForApp } = require('../utils/image-version');
39
44
  const healthCheckUtil = require('../utils/health-check');
40
45
  const { computeTraefikPublicAppUrl } = require('../utils/health-check-url');
@@ -303,8 +308,8 @@ async function generateComposeFile(appName, appConfig, composeOptions, devDir, l
303
308
 
304
309
  /**
305
310
  * Writes `build.envOutputPath` after each `aifabrix run`: **local**-flavored env for the host/IDE
306
- * when not using `--reload`; with **`--reload`**, merges container `.env.run` into the existing file
307
- * (preserves resolve comments) without appending run-only keys missing from the template.
311
+ * when not using `--reload`; with **`--reload`**, merges container `.env.run` into `.env` and also
312
+ * writes a sibling **`.env.local`** with localhost / published-port URLs for host CLI and manual tests.
308
313
  *
309
314
  * @async
310
315
  * @param {string} appName - Application name
@@ -326,6 +331,8 @@ async function writeEnvOutputIfConfigured(appName, appConfig, runEnvPath, option
326
331
  }
327
332
  if (options && options.reload === true) {
328
333
  await writeEnvOutputForReload(outputPath, runEnvPath, appName);
334
+ const localOutputPath = resolveEnvLocalOutputPath(outputPath);
335
+ await writeEnvOutputForLocal(appName, localOutputPath);
329
336
  } else {
330
337
  await writeEnvOutputForLocal(appName, outputPath);
331
338
  }
package/lib/app/run.js CHANGED
@@ -404,6 +404,14 @@ async function runApp(appName, options = {}) {
404
404
  logger.log(chalk.gray(`[DEBUG] Compose file generated: ${prepared.tempComposePath}`));
405
405
  }
406
406
  logReloadDevSummary(Boolean(prepared.mergedRunOptions.reload), prepared.mergedRunOptions.reloadSyncSummary);
407
+ const { runDeployJobIfConfigured } = require('./run-deploy-job');
408
+ await runDeployJobIfConfigured({
409
+ appConfig: prepared.appConfig,
410
+ fullImage: prepared.mergedRunOptions.image,
411
+ runEnvPath: prepared.runEnvPath,
412
+ devMountPath: prepared.devMountPath || null,
413
+ debug
414
+ });
407
415
  await startAppContainer(appName, prepared.tempComposePath, prepared.hostPort, prepared.appConfig, {
408
416
  debug,
409
417
  runEnvPath: prepared.runEnvPath,