@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
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Resolve Runtime Layer B tool names from Dataplane.
3
+ *
4
+ * @fileoverview Runtime-orchestration MCP tool discovery for channel artifacts and probes
5
+ * @author AI Fabrix Team
6
+ * @version 1.1.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { createDataplaneApiClient } = require('../api/index');
12
+ const { getChannelTarget } = require('./channel-targets');
13
+
14
+ /**
15
+ * Prefer the first-party MCP gateway catalog, then MCP OpenAPI, then legacy paths.
16
+ */
17
+ const TOOL_CATALOG_BUILDERS = Object.freeze([
18
+ (systemKey) =>
19
+ `/api/v1/mcp/servers/tools?filter=${encodeURIComponent(`systemKey:eq:${systemKey}`)}&pageSize=100`,
20
+ (systemKey) => `/api/v1/mcp/${systemKey}/docs/mcp-openapi.json`,
21
+ (systemKey) => `/api/v1/external/systems/${systemKey}/mcp/tools`,
22
+ (systemKey) => `/api/v1/external/systems/${systemKey}/mcp/tools/list`,
23
+ (systemKey) => `/api/v1/external/systems/${systemKey}/mcp/catalog`,
24
+ (systemKey) => `/api/v1/external/systems/${systemKey}/tools`
25
+ ]);
26
+
27
+ /**
28
+ * @param {unknown} value
29
+ * @returns {string[]}
30
+ */
31
+ function extractToolNames(value) {
32
+ if (Array.isArray(value)) {
33
+ return value
34
+ .map((item) => {
35
+ if (typeof item === 'string') return item.trim();
36
+ if (!item || typeof item !== 'object') return '';
37
+ return String(item.name || item.toolName || item.key || '').trim();
38
+ })
39
+ .filter(Boolean);
40
+ }
41
+ if (!value || typeof value !== 'object') {
42
+ return [];
43
+ }
44
+ const body = /** @type {Record<string, unknown>} */ (value);
45
+ if (body.paths && typeof body.paths === 'object') {
46
+ return extractToolNamesFromOpenApiPaths(body.paths);
47
+ }
48
+ const candidates = [body.tools, body.items, body.data, body.result];
49
+ for (const candidate of candidates) {
50
+ const names = extractToolNames(candidate);
51
+ if (names.length > 0) {
52
+ return names;
53
+ }
54
+ }
55
+ return [];
56
+ }
57
+
58
+ /**
59
+ * @param {Record<string, unknown>} paths
60
+ * @returns {string[]}
61
+ */
62
+ function extractToolNamesFromOpenApiPaths(paths) {
63
+ const names = [];
64
+ for (const pathKey of Object.keys(paths || {})) {
65
+ const match = String(pathKey).match(/\/tools\/([^/]+)\/execute$/);
66
+ if (match && match[1] && match[1] !== 'execute') {
67
+ names.push(match[1]);
68
+ }
69
+ }
70
+ return [...new Set(names)];
71
+ }
72
+
73
+ /**
74
+ * @param {string} routeSystemKey
75
+ * @returns {string[]}
76
+ */
77
+ function buildToolCatalogEndpoints(routeSystemKey) {
78
+ return TOOL_CATALOG_BUILDERS.map((build) => build(routeSystemKey));
79
+ }
80
+
81
+ /**
82
+ * @param {Object} response
83
+ * @returns {string[]}
84
+ */
85
+ function extractToolNamesFromClientResponse(response) {
86
+ const direct = extractToolNames(response);
87
+ if (direct.length > 0) return preferLayerBToolNames(direct);
88
+ return preferLayerBToolNames(extractToolNames(response?.data ?? response));
89
+ }
90
+
91
+ /**
92
+ * Prefer MCP Layer B names (`work.start`) over REST-ish operation ids.
93
+ *
94
+ * @param {string[]} names
95
+ * @returns {string[]}
96
+ */
97
+ function preferLayerBToolNames(names) {
98
+ const list = Array.isArray(names) ? names : [];
99
+ const dotted = list.filter((name) => /^[a-z][a-z0-9]*\.[a-z][a-z0-9.]*$/i.test(name));
100
+ return dotted.length > 0 ? dotted : list;
101
+ }
102
+
103
+ /**
104
+ * @param {string} dataplaneUrl
105
+ * @param {Object} authConfig
106
+ * @param {string} channelTarget
107
+ * @returns {Promise<string[]>}
108
+ */
109
+ async function fetchRuntimeLayerBToolNames(dataplaneUrl, authConfig, channelTarget) {
110
+ const target = getChannelTarget(channelTarget);
111
+ const routeSystemKey = target.routeSystemKey || target.key;
112
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
113
+ const endpoints = buildToolCatalogEndpoints(routeSystemKey);
114
+ for (const endpoint of endpoints) {
115
+ try {
116
+ const response = await client.get(endpoint, { timeoutMs: 10000 });
117
+ const names = extractToolNamesFromClientResponse(response);
118
+ if (Array.isArray(names) && names.length > 0) {
119
+ return [...new Set(names)].sort();
120
+ }
121
+ } catch {
122
+ // Try the next endpoint candidate.
123
+ }
124
+ }
125
+ return [];
126
+ }
127
+
128
+ /**
129
+ * True when Runtime MCP gateway docs or tool catalog is reachable.
130
+ *
131
+ * @async
132
+ * @param {string} dataplaneUrl
133
+ * @param {Object} authConfig
134
+ * @param {string} routeSystemKey
135
+ * @returns {Promise<boolean>}
136
+ */
137
+ async function isRuntimeMcpGatewayReachable(dataplaneUrl, authConfig, routeSystemKey) {
138
+ if (!dataplaneUrl || !routeSystemKey) return false;
139
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
140
+ const candidates = [
141
+ `/api/v1/mcp/${routeSystemKey}/docs/mcp-openapi.json`,
142
+ `/api/v1/mcp/servers/tools?filter=${encodeURIComponent(`systemKey:eq:${routeSystemKey}`)}&pageSize=1`
143
+ ];
144
+ for (const endpoint of candidates) {
145
+ try {
146
+ const response = await client.get(endpoint, { timeoutMs: 8000 });
147
+ if (response && response.success !== false) {
148
+ return true;
149
+ }
150
+ } catch {
151
+ // try next
152
+ }
153
+ }
154
+ return false;
155
+ }
156
+
157
+ module.exports = {
158
+ TOOL_CATALOG_BUILDERS,
159
+ extractToolNames,
160
+ extractToolNamesFromOpenApiPaths,
161
+ preferLayerBToolNames,
162
+ buildToolCatalogEndpoints,
163
+ fetchRuntimeLayerBToolNames,
164
+ isRuntimeMcpGatewayReachable
165
+ };
package/lib/cli/index.js CHANGED
@@ -23,6 +23,9 @@ const { setupAppCommands: setupAppManagementCommands } = require('../commands/ap
23
23
  const { setupDatasourceCommands } = require('../commands/datasource');
24
24
  const { setupDimensionCommands } = require('../commands/dimension');
25
25
  const { setupResourceTypeCommands } = require('../commands/resource-type');
26
+ const { setupRoleCommands } = require('../commands/role');
27
+ const { setupRoleAssistantCommands } = require('../commands/role-assistant');
28
+ const { setupEvidenceKindCommands } = require('../commands/evidence-kind');
26
29
  const { setupEnterpriseKnowledgeCommands } = require('../commands/enterprise-knowledge');
27
30
  const { setupIdentityCommands } = require('../commands/identity');
28
31
  const { setupProtectionCommands } = require('../commands/protection');
@@ -73,6 +76,9 @@ function setupCoreCliCommands(program) {
73
76
  function setupExtendedCliCommands(program) {
74
77
  setupDimensionCommands(program);
75
78
  setupResourceTypeCommands(program);
79
+ setupRoleCommands(program);
80
+ setupRoleAssistantCommands(program);
81
+ setupEvidenceKindCommands(program);
76
82
  setupEnterpriseKnowledgeCommands(program);
77
83
  setupIdentityCommands(program);
78
84
  setupProtectionCommands(program);
@@ -56,12 +56,18 @@ Examples:
56
56
  $ aifabrix validate hubspot-demo
57
57
  $ aifabrix upload hubspot-demo --probe
58
58
  $ aifabrix deploy hubspot-demo --probe -v
59
+ # Prove pillars in tst/CI, then promote (plain deploy seals cert on published Deploy)
59
60
  $ aifabrix deploy ek-sales --gate full --subject-email ops@example.com
61
+ $ aifabrix deploy ek-sales
60
62
 
61
63
  Notes:
62
64
  - Login or set MISO_CONTROLLER_URL + environment (aifabrix login / aifabrix auth).
63
65
  - CI: register once (aifabrix app register <appKey>), store DEV_MISO_CLIENTID and DEV_MISO_CLIENTSECRET in pipeline secrets.
64
66
  - upload = dataplane publish for dev iteration; deploy = controller validate + deploy (Azure or local Docker).
67
+ - Prove (tst/CI): use --gate full (optional --subject-email) before promote; plain deploy promotes without live E2E gates.
68
+ - After a successful published Deploy, the platform seals the integration certificate (no separate certificates issue step).
69
+ - Default output is a compact status card; use -v for expanded preflight and readiness detail.
70
+ - Controller deploy always polls to a terminal status (no --poll / --no-poll on this command).
65
71
  - --repository-url overrides repo URL for pipeline validate (default: application.yaml repository.repositoryUrl).
66
72
  `;
67
73
 
@@ -219,7 +225,7 @@ Examples:
219
225
  });
220
226
  }
221
227
 
222
- function setupBuildRunLogsDownCommands(program) {
228
+ function registerBuildCommand(program) {
223
229
  program.command('build <appKey>')
224
230
  .description('Build Docker image for builder appKey (auto-detect runtime)')
225
231
  .option('-l, --language <lang>', 'Override language detection')
@@ -243,9 +249,9 @@ function setupBuildRunLogsDownCommands(program) {
243
249
  process.exit(1);
244
250
  }
245
251
  });
252
+ }
246
253
 
247
- registerRunCommand(program);
248
-
254
+ function registerLogsCommand(program) {
249
255
  program.command('logs <appKey>')
250
256
  .description('Tail container logs for appKey (optional env summary; secrets masked)')
251
257
  .option('-f', 'Follow log stream')
@@ -256,14 +262,22 @@ function setupBuildRunLogsDownCommands(program) {
256
262
  try {
257
263
  const { runAppLogs } = require('../commands/app-logs');
258
264
  const tailNum = parseInt(options.tail, 10);
259
- const level = options.level !== undefined && options.level !== null && options.level !== '' ? String(options.level).trim() : undefined;
260
- await runAppLogs(appName, { follow: options.f, tail: Number.isNaN(tailNum) ? 100 : tailNum, level });
265
+ const level = options.level !== undefined && options.level !== null && options.level !== ''
266
+ ? String(options.level).trim()
267
+ : undefined;
268
+ await runAppLogs(appName, {
269
+ follow: options.f,
270
+ tail: Number.isNaN(tailNum) ? 100 : tailNum,
271
+ level
272
+ });
261
273
  } catch (error) {
262
274
  handleCommandError(error, 'logs');
263
275
  process.exit(1);
264
276
  }
265
277
  });
278
+ }
266
279
 
280
+ function registerDownAppCommand(program) {
267
281
  program.command('down-app <appKey>')
268
282
  .description('Stop and remove container for appKey (--volumes removes data volume)')
269
283
  .option('--volumes', 'Remove application Docker volume')
@@ -278,6 +292,13 @@ function setupBuildRunLogsDownCommands(program) {
278
292
  });
279
293
  }
280
294
 
295
+ function setupBuildRunLogsDownCommands(program) {
296
+ registerBuildCommand(program);
297
+ registerRunCommand(program);
298
+ registerLogsCommand(program);
299
+ registerDownAppCommand(program);
300
+ }
301
+
281
302
  function setupShellTestStopCommands(program) {
282
303
  program.command('stop <appKey>')
283
304
  .description('Alias for down-app: stop and remove container for appKey')
@@ -12,7 +12,8 @@ const config = require('../core/config');
12
12
  const logger = require('../utils/logger');
13
13
  const { handleCommandError } = require('../utils/cli-utils');
14
14
  const { setupDevPathAndFormatCommands } = require('./setup-dev-path-commands');
15
- const { runDevInit, runDevRefresh } = require('../commands/dev-init');
15
+ const { runDevInit } = require('../commands/dev-init');
16
+ const { runDevRefresh, ensureDevCertFreshIfDue } = require('../commands/dev-refresh');
16
17
  const { displayDevConfig } = require('../commands/dev-show-display');
17
18
  const {
18
19
  handleDevList,
@@ -49,11 +50,21 @@ Examples:
49
50
  Requires a configured remote Builder Server and an admin client certificate (same machine setup as dev list / dev pin). After add, run dev pin <id> once to create a PIN for aifabrix dev init.
50
51
  `;
51
52
 
53
+ /** Appended to `dev list --help` (sort examples). */
54
+ const DEV_LIST_HELP_AFTER = `
55
+ Examples:
56
+ $ aifabrix dev list
57
+ $ aifabrix dev list --sort id
58
+ $ aifabrix dev list --sort -until
59
+
60
+ Sort fields: id, name, email, until. Prefix - for descending (default: name ascending).
61
+ `;
62
+
52
63
  /** Appended to `aifabrix dev --help` (overview; keep subcommand .description lines short). */
53
64
  const DEV_GROUP_HELP_AFTER = `
54
65
  Categories:
55
66
  Local config show, set-id, set-scoped-resources, set-env-config, set-home, set-work, set-format, print-home, print-work
56
- Onboarding init (PIN onboarding), refresh (sync settings / renew cert)
67
+ Onboarding init (PIN onboarding), refresh (sync settings / renew cert); show auto-renews when due
57
68
  Remote admin list, add, update, pin, delete, platform-install, platform-update, platform-install-cli (need remote-server + client cert in ~/.aifabrix)
58
69
  Sync / stop down (Mutagen; optional --apps for containers)
59
70
 
@@ -168,9 +179,10 @@ async function handleSetScopedResources(value) {
168
179
  function setupDevShowAndSetId(dev) {
169
180
  dev
170
181
  .command('show')
171
- .description('Show dev ports and ~/.aifabrix config')
182
+ .description('Show dev ports and ~/.aifabrix config (auto-renews cert when due)')
172
183
  .action(async() => {
173
184
  try {
185
+ await ensureDevCertFreshIfDue();
174
186
  const devId = await config.getDeveloperId();
175
187
  await displayDevConfig(devId);
176
188
  } catch (error) {
@@ -286,9 +298,14 @@ function setupDevListAddCommands(dev) {
286
298
  dev
287
299
  .command('list')
288
300
  .description('List developers (remote Builder Server)')
289
- .action(async() => {
301
+ .option(
302
+ '--sort <field>',
303
+ 'Sort field/direction (id|name|email|until; prefix - for descending; default name)'
304
+ )
305
+ .addHelpText('after', DEV_LIST_HELP_AFTER)
306
+ .action(async(options) => {
290
307
  try {
291
- await handleDevList();
308
+ await handleDevList(options);
292
309
  } catch (error) {
293
310
  handleCommandError(error, 'dev list');
294
311
  process.exit(1);
@@ -398,8 +415,6 @@ function setupDevUpdatePinDeleteCommands(dev) {
398
415
  process.exit(1);
399
416
  }
400
417
  });
401
-
402
- setupDevDownCommand(dev);
403
418
  }
404
419
 
405
420
  /**
@@ -457,6 +472,7 @@ function setupDevPlatformCommands(dev) {
457
472
  function setupDevUserCommands(dev) {
458
473
  setupDevListAddCommands(dev);
459
474
  setupDevUpdatePinDeleteCommands(dev);
475
+ setupDevDownCommand(dev);
460
476
  setupDevPlatformCommands(dev);
461
477
  }
462
478
 
@@ -10,6 +10,7 @@ Examples:
10
10
  $ aifabrix upload hubspot-demo
11
11
  $ aifabrix upload hubspot-demo -v
12
12
  $ aifabrix upload hubspot-demo --probe
13
+ $ aifabrix upload hubspot-demo --timeout 600000
13
14
 
14
15
  # Build and validate payload only (no API calls)
15
16
  $ aifabrix upload hubspot-demo --dry-run
@@ -18,11 +19,16 @@ Examples:
18
19
  $ aifabrix upload .protection
19
20
  $ aifabrix upload .protection --warnings-as-errors
20
21
 
22
+ # Role Assistant package (settings section + Evidence sidecars)
23
+ $ aifabrix upload sales-representative --env dev
24
+
21
25
  Notes:
22
26
  - Requires login (aifabrix auth status).
23
- - Reads files under integration/<systemKey>/ (system JSON, datasources, credentials).
27
+ - Reads files under integration/<systemKey>/ or role-assistant/<roleKey>/ for digital workers.
24
28
  - Default output is a compact readiness summary; use -v for expanded detail and server-side validate warnings.
25
- - --probe runs dataplane runtime checks after publish (slower; common in Session 1).
29
+ - --probe runs dataplane runtime checks after publish (slower).
30
+ - --timeout sets publish budget in ms (HTTP client and dataplane); default 300000.
31
+ - --env selects role-assistant.yaml section (dev|tst|pro) for digital workers; default dev.
26
32
  - test-e2e and test-integration publish local files first by default; use --no-publish on those commands to skip.
27
33
  - After dimension/FK edits on active datasources, use --force (or test-e2e / test-integration / datasource test-* with --sync --force).
28
34
  - For one datasource only: aifabrix datasource upload <datasourceKey>
@@ -45,13 +45,16 @@ async function handleUploadCommandAction(systemKey, options) {
45
45
  return;
46
46
  }
47
47
  const upload = require('../commands/upload');
48
+ const { resolvePipelineUploadTimeoutMs } = require('../api/pipeline.api');
48
49
  const probeTimeout =
49
50
  options.probeTimeout === undefined || options.probeTimeout === null
50
51
  ? 120000
51
52
  : Number(options.probeTimeout);
53
+ const timeoutMs = resolvePipelineUploadTimeoutMs(options.timeout);
52
54
  await upload.uploadExternalSystem(systemKey, {
53
55
  ...options,
54
56
  probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000,
57
+ timeoutMs,
55
58
  pathOptions: {}
56
59
  });
57
60
  }
@@ -98,10 +101,19 @@ function setupUploadCommand(program) {
98
101
  .option('-v, --verbose', 'Expanded upload summary and server-side pipeline validate warnings before publish')
99
102
  .option('--probe', 'After publish, run dataplane runtime checks (validation/run); slower')
100
103
  .option('--probe-timeout <ms>', 'Timeout for --probe (default: 120000)', '120000')
104
+ .option(
105
+ '--timeout <ms>',
106
+ 'Publish timeout in ms for HTTP and dataplane budget (default: 300000; min 5000, max 2700000)'
107
+ )
101
108
  .option(
102
109
  '--force',
103
110
  'Bypass schema guards on active datasources during publish (dangerous; shows a warning)'
104
111
  )
112
+ .option(
113
+ '-e, --env <env>',
114
+ 'Role Assistant settings environment section: dev, tst, or pro (default: dev)',
115
+ 'dev'
116
+ )
105
117
  .action(async(systemKey, options) => {
106
118
  try {
107
119
  await handleUploadCommandAction(systemKey, options);
@@ -18,6 +18,17 @@ Examples:
18
18
  $ aifabrix validate --builder
19
19
  `;
20
20
 
21
+ const VALIDATE_JSON_HELP_AFTER = `
22
+ Examples:
23
+ $ aifabrix validate-json myapp
24
+ $ aifabrix validate-json my-system
25
+ $ aifabrix validate-json --integration
26
+ $ aifabrix validate-json --builder
27
+ $ aifabrix validate-json --integration --builder --format json
28
+
29
+ Runs full local validation first; writes *-deploy.json only when validation succeeds (offline).
30
+ `;
31
+
21
32
  const REPAIR_HELP_AFTER = `
22
33
  Examples:
23
34
  $ aifabrix repair hubspot-demo
@@ -63,6 +74,7 @@ Examples:
63
74
  module.exports = {
64
75
  JSON_HELP_AFTER,
65
76
  VALIDATE_HELP_AFTER,
77
+ VALIDATE_JSON_HELP_AFTER,
66
78
  REPAIR_HELP_AFTER,
67
79
  RESOLVE_HELP_AFTER
68
80
  };
@@ -12,7 +12,7 @@ const fs = require('fs');
12
12
  const chalk = require('chalk');
13
13
  const logger = require('../utils/logger');
14
14
  const { handleCommandError } = require('../utils/cli-utils');
15
- const { VALIDATE_HELP_AFTER } = require('./setup-utility-help-after');
15
+ const { VALIDATE_HELP_AFTER, VALIDATE_JSON_HELP_AFTER } = require('./setup-utility-help-after');
16
16
 
17
17
  /**
18
18
  * @param {string} appOrFile
@@ -154,7 +154,7 @@ async function runValidateCommand(appOrFile, options) {
154
154
  /**
155
155
  * @param {import('commander').Command} program
156
156
  */
157
- function setupValidateDiffCommands(program) {
157
+ function setupValidateCommand(program) {
158
158
  program.command('validate [appKey|systemKey|file]')
159
159
  .description('Validate appKey, systemKey, file path, .protection batch, or all under integration/ and builder/')
160
160
  .addHelpText('after', VALIDATE_HELP_AFTER)
@@ -173,7 +173,37 @@ function setupValidateDiffCommands(program) {
173
173
  process.exit(1);
174
174
  });
175
175
  });
176
+ }
177
+
178
+ /**
179
+ * @param {import('commander').Command} program
180
+ */
181
+ function setupValidateJsonCommand(program) {
182
+ program.command('validate-json [appKey|systemKey]')
183
+ .description(
184
+ 'Validate locally then write *-deploy.json only when validation succeeds (offline; no file-path mode)'
185
+ )
186
+ .addHelpText('after', VALIDATE_JSON_HELP_AFTER)
187
+ .option('--format <format>', 'Output format: json | default (human-readable)')
188
+ .option('--integration', 'Validate and write deploy JSON for all apps under integration/')
189
+ .option('--builder', 'Validate and write deploy JSON for all apps under builder/')
190
+ .action((appKey, options) => {
191
+ const { runValidateJsonCommand } = require('../commands/validate-json');
192
+ runValidateJsonCommand(appKey, options)
193
+ .then(({ exitCode }) => {
194
+ if (exitCode !== 0) process.exit(exitCode);
195
+ })
196
+ .catch((error) => {
197
+ handleCommandError(error, 'validate-json');
198
+ process.exit(1);
199
+ });
200
+ });
201
+ }
176
202
 
203
+ /**
204
+ * @param {import('commander').Command} program
205
+ */
206
+ function setupDiffCommand(program) {
177
207
  program.command('diff <file1> <file2>')
178
208
  .description('Diff two config files (optional schema validate)')
179
209
  .option('--no-validate', 'Skip schema validation (type check still applied)')
@@ -191,6 +221,15 @@ function setupValidateDiffCommands(program) {
191
221
  });
192
222
  }
193
223
 
224
+ /**
225
+ * @param {import('commander').Command} program
226
+ */
227
+ function setupValidateDiffCommands(program) {
228
+ setupValidateCommand(program);
229
+ setupValidateJsonCommand(program);
230
+ setupDiffCommand(program);
231
+ }
232
+
194
233
  module.exports = {
195
234
  setupValidateDiffCommands,
196
235
  runValidateCommand
@@ -166,20 +166,8 @@ async function runDockerExec(containerName, testCmd, envFilePath = null) {
166
166
  * @returns {Promise<number>} Exit code
167
167
  */
168
168
  async function runDockerRunEphemeral(fullImage, testCmd, envFilePath = null) {
169
- const { getDockerExecEnv } = require('../utils/remote-docker-env');
170
- const dockerEnv = await getDockerExecEnv();
171
- return new Promise((resolve) => {
172
- const args = ['run', '--rm'];
173
- if (envFilePath) args.push('--env-file', envFilePath);
174
- args.push(fullImage, 'sh', '-c', testCmd);
175
- const proc = spawn('docker', args, {
176
- stdio: 'inherit',
177
- shell: false,
178
- env: dockerEnv
179
- });
180
- proc.on('close', code => resolve(code !== null ? code : 1));
181
- proc.on('error', () => resolve(1));
182
- });
169
+ const { runDockerRunEphemeral: runEphemeral } = require('../utils/docker-run-ephemeral');
170
+ return runEphemeral(fullImage, testCmd, envFilePath);
183
171
  }
184
172
 
185
173
  /**
@@ -76,7 +76,8 @@ async function datasourceLoadAction(datasourceKey, options) {
76
76
  dryRun: options.dryRun,
77
77
  batchSize: options.batchSize,
78
78
  syncType: options.syncType,
79
- format: options.format
79
+ format: options.format,
80
+ timeoutMs: options.timeout
80
81
  });
81
82
 
82
83
  if (options.json) {
@@ -141,6 +142,10 @@ function setupDatasourceLoadExportCommands(datasource) {
141
142
  'Dataplane syncType',
142
143
  'incremental'
143
144
  )
145
+ .option(
146
+ '--timeout <ms>',
147
+ 'Per-batch HTTP timeout for records/bulk (default 120000)'
148
+ )
144
149
  .option('--dry-run', 'Parse and validate only; no upload')
145
150
  .option('-v, --verbose', 'Per-batch progress')
146
151
  .option('--json', 'Machine-readable result JSON')
@@ -113,6 +113,24 @@ function formatOperationsGateFailure(result) {
113
113
  return 'E2E validation did not succeed for one or more datasources';
114
114
  }
115
115
 
116
+ /**
117
+ * @param {Object} row
118
+ * @returns {string|null}
119
+ */
120
+ function formatFailedDatasourceRowHint(row) {
121
+ if (!row || row.success !== false) {
122
+ return null;
123
+ }
124
+ const key = row.key || row.datasourceKey || 'datasource';
125
+ const issues = row.datasourceTestRun?.validation?.issues;
126
+ if (Array.isArray(issues) && issues.length > 0) {
127
+ const first = issues[0];
128
+ const code = first.code ? `${first.code}: ` : '';
129
+ return `${key}: ${code}${first.message || 'validation failed'}`;
130
+ }
131
+ return row.error ? `${key}: ${row.error}` : null;
132
+ }
133
+
116
134
  /**
117
135
  * @param {Object} result
118
136
  * @returns {string}
@@ -124,6 +142,11 @@ function formatIntegrationGateFailure(result) {
124
142
  if (result?.message) {
125
143
  return String(result.message);
126
144
  }
145
+ const rows = Array.isArray(result?.datasourceResults) ? result.datasourceResults : [];
146
+ const hints = rows.map(formatFailedDatasourceRowHint).filter(Boolean);
147
+ if (hints.length > 0) {
148
+ return hints.slice(0, 3).join('; ');
149
+ }
127
150
  return 'integration test did not succeed';
128
151
  }
129
152