@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,313 @@
1
+ /**
2
+ * Role Assistant CLI command group.
3
+ *
4
+ * @fileoverview role-assistant test command with portal deep-link output
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const logger = require('../utils/logger');
12
+ const { handleCommandError } = require('../utils/cli-utils');
13
+ const {
14
+ runLifecycleForExternalSystem,
15
+ resolveLifecycleAuth
16
+ } = require('./lifecycle-external');
17
+ const { lifecycleVerdictFromReport } = require('./lifecycle-command-action');
18
+ const { buildExternalSystemUiUrl } = require('../lifecycle/dataplane-ui-url');
19
+ const { VERDICT } = require('../lifecycle/product-model');
20
+ const { exitCodeFromVerdict } = require('../lifecycle/exit-codes');
21
+ const {
22
+ loadRoleAssistantTestCase,
23
+ evaluateRoleAssistantTestCase
24
+ } = require('../role-assistant/test-cases');
25
+ const {
26
+ isExecutableRoleAssistantCase,
27
+ runRoleAssistantCaseLifecycle,
28
+ mergeCaseExecutionIntoLifecycleResult,
29
+ lifecycleVerdictFromCaseExecution
30
+ } = require('../role-assistant/test-runner');
31
+ const { collectString } = require('./governance');
32
+ const {
33
+ sectionTitle,
34
+ headerKeyValue,
35
+ formatSuccessLine,
36
+ formatSuccessParagraph,
37
+ formatWarningLine,
38
+ formatBlockingError,
39
+ metadata
40
+ } = require('../utils/cli-test-layout-chalk');
41
+
42
+ function roleAssistantHelpAfter() {
43
+ return `
44
+ Examples:
45
+ $ aifabrix role-assistant test customer-support-bot
46
+ $ aifabrix role-assistant test customer-support-bot --case smoke
47
+ $ aifabrix role-assistant test customer-support-bot --case tests/customer-address-change.yaml
48
+ $ aifabrix role-assistant test customer-support-bot --subject-email ops@example.com
49
+ $ aifabrix role-assistant test customer-support-bot --json
50
+ $ aifabrix role-assistant test customer-support-bot --publish --force
51
+
52
+ Notes:
53
+ - Uses the public/running Role Assistant on the dataplane by default (does not publish local datasources).
54
+ - Use \`aifabrix upload <roleKey> --env …\` (or \`--publish\`) when you intentionally refresh the package.
55
+ - Runs lifecycle checks, then prints a portal deep link for full step-by-step status.
56
+ - Case files with input.message/input.content execute Work Hub plan→accept (or work.start when executionPath: intent).
57
+ - answers[] and approvals[] are matched to runtime wait payloads (questionKey/requestKey/waitReason).
58
+ - Use the portal URL for detailed human review while automation reads CLI/JSON output.
59
+ `;
60
+ }
61
+
62
+ function rawArgsInclude(cmd, flag) {
63
+ const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
64
+ return raw.includes(flag);
65
+ }
66
+
67
+ function optionOrFlag(options, key, cmd, ...flags) {
68
+ if (options[key] === true) {
69
+ return true;
70
+ }
71
+ return flags.some((flag) => rawArgsInclude(cmd, flag));
72
+ }
73
+
74
+ function trimOptionalString(value) {
75
+ return value ? String(value).trim() : '';
76
+ }
77
+
78
+ function normalizeRoleAssistantTestOptions(options, cmd) {
79
+ // Role Assistant test uses the public/running digital worker by default.
80
+ // Opt in to publish with --publish (optional --force).
81
+ const wantsPublish = optionOrFlag(options, 'publish', cmd, '--publish');
82
+ return {
83
+ env: options.env || 'dev',
84
+ verbose: optionOrFlag(options, 'verbose', cmd, '-v', '--verbose'),
85
+ debug: optionOrFlag(options, 'debug', cmd, '-d', '--debug'),
86
+ json: optionOrFlag(options, 'json', cmd, '--json'),
87
+ noPublish: !wantsPublish,
88
+ force: optionOrFlag(options, 'force', cmd, '--force'),
89
+ subjectUserId: options.subjectUserId || [],
90
+ subjectEmail: options.subjectEmail || [],
91
+ certificationProfile: options.certificationProfile || 'bronze',
92
+ case: trimOptionalString(options.case),
93
+ testsDir: trimOptionalString(options.testsDir),
94
+ run: true
95
+ };
96
+ }
97
+
98
+ function buildRoleAssistantTestEnvelope(roleKey, verdict, portalUrl, result, opts, caseResult = null) {
99
+ const report = result.report || {};
100
+ const envelope = {
101
+ roleKey,
102
+ command: 'role-assistant test',
103
+ verdict,
104
+ portalUrl,
105
+ openApiPublished: result.openApiPublished === true,
106
+ certification: report.certification || null,
107
+ recommendations: Array.isArray(report.recommendations) ? report.recommendations : [],
108
+ warnings: Array.isArray(report.warnings) ? report.warnings : [],
109
+ stepsRun: result.stepsRun || [],
110
+ case: caseResult
111
+ ? {
112
+ caseId: caseResult.caseId,
113
+ sourceFile: caseResult.sourceFile,
114
+ passed: caseResult.passed,
115
+ lifecycleState: caseResult.lifecycleState,
116
+ assertions: caseResult.assertions,
117
+ failedAssertions: caseResult.failedAssertions,
118
+ warnings: Array.isArray(caseResult.warnings) ? caseResult.warnings : [],
119
+ execution: caseResult.execution || null
120
+ }
121
+ : null
122
+ };
123
+ if (opts.verbose || opts.debug) {
124
+ envelope.report = report;
125
+ }
126
+ if (opts.debug) {
127
+ envelope.debug = {
128
+ observation: caseResult ? caseResult.observation : null,
129
+ lifecycleResult: result
130
+ };
131
+ }
132
+ return envelope;
133
+ }
134
+
135
+ function displayCaseResultSummary(caseResult) {
136
+ if (!caseResult) {
137
+ return;
138
+ }
139
+ logger.log(headerKeyValue('Case:', caseResult.caseId));
140
+ logger.log(headerKeyValue('Case file:', caseResult.sourceFile));
141
+ logger.log(headerKeyValue('Observed state:', caseResult.lifecycleState));
142
+ if (caseResult.execution) {
143
+ logger.log(headerKeyValue('Execution id:', caseResult.execution.processExecutionId || 'n/a'));
144
+ logger.log(headerKeyValue('Final runtime status:', caseResult.execution.finalStatus || 'n/a'));
145
+ }
146
+ if (caseResult.passed) {
147
+ logger.log(formatSuccessLine('Case assertions passed.'));
148
+ const warnings = Array.isArray(caseResult.warnings) ? caseResult.warnings : [];
149
+ for (const row of warnings) {
150
+ logger.log(formatWarningLine(row.message || String(row)));
151
+ }
152
+ return;
153
+ }
154
+ logger.log(formatBlockingError('Case assertions failed.'));
155
+ for (const row of caseResult.failedAssertions) {
156
+ logger.log(formatWarningLine(row.message));
157
+ }
158
+ }
159
+
160
+ function displayRoleAssistantTestSummary(roleKey, verdict, portalUrl, result, caseResult = null) {
161
+ logger.log('');
162
+ logger.log(sectionTitle(`${String(roleKey).toUpperCase()} ROLE ASSISTANT TEST`));
163
+ logger.log('');
164
+ logger.log(headerKeyValue('Role key:', roleKey));
165
+ if (portalUrl) {
166
+ logger.log(headerKeyValue('Portal:', portalUrl));
167
+ } else {
168
+ logger.log(formatWarningLine('Portal link unavailable. Configure dataplane public URL and retry.'));
169
+ }
170
+ const verdictMessage =
171
+ verdict === VERDICT.VERIFIED
172
+ ? 'Lifecycle checks passed. Open portal for full execution steps and logs.'
173
+ : 'Lifecycle checks are not fully verified. Open portal to inspect blocking steps.';
174
+ if (verdict === VERDICT.VERIFIED) {
175
+ logger.log(formatSuccessParagraph(verdictMessage));
176
+ } else {
177
+ logger.log(formatWarningLine(verdictMessage));
178
+ }
179
+ const steps = Array.isArray(result.stepsRun) ? result.stepsRun : [];
180
+ if (steps.length > 0) {
181
+ const labels = steps.map((row) => (row && row.pillar ? row.pillar : String(row)));
182
+ logger.log(metadata(`Steps run: ${labels.join(', ')}`));
183
+ }
184
+ displayCaseResultSummary(caseResult);
185
+ }
186
+
187
+ async function resolveRoleAssistantCaseResult(roleKey, opts, result, verdict, portalUrl) {
188
+ if (!opts.case) {
189
+ return null;
190
+ }
191
+ const roleCase = loadRoleAssistantTestCase(roleKey, opts.case, {
192
+ testsDir: opts.testsDir || null
193
+ });
194
+ if (!isExecutableRoleAssistantCase(roleCase)) {
195
+ return evaluateRoleAssistantTestCase(roleCase, result, verdict, portalUrl);
196
+ }
197
+ const authContext = await resolveLifecycleAuth(roleKey, {
198
+ ...opts,
199
+ run: false,
200
+ noPublish: true
201
+ });
202
+ const executionResult = await runRoleAssistantCaseLifecycle(roleKey, roleCase, authContext, opts);
203
+ const executionVerdict = lifecycleVerdictFromCaseExecution(executionResult, verdict);
204
+ const evaluationInput = mergeCaseExecutionIntoLifecycleResult(result, executionResult);
205
+ const evaluation = evaluateRoleAssistantTestCase(
206
+ roleCase,
207
+ evaluationInput,
208
+ executionVerdict,
209
+ portalUrl
210
+ );
211
+ evaluation.execution = {
212
+ processExecutionId: executionResult.processExecutionId || null,
213
+ finalStatus: executionResult.finalStatus?.status || null,
214
+ waitReason: executionResult.finalStatus?.wait?.waitReason || null,
215
+ interactions: executionResult.interactions || [],
216
+ workResultError: executionResult.workResultError || null
217
+ };
218
+ return evaluation;
219
+ }
220
+
221
+ function computeRoleAssistantExitCode(verdict, caseResult) {
222
+ if (caseResult) {
223
+ return caseResult.passed ? 0 : 2;
224
+ }
225
+ if (verdict === VERDICT.VERIFIED) {
226
+ return 0;
227
+ }
228
+ return exitCodeFromVerdict(verdict, { partial: verdict === VERDICT.NOT_VERIFIED });
229
+ }
230
+
231
+ async function runRoleAssistantTestAction(roleKey, options, cmd) {
232
+ const opts = normalizeRoleAssistantTestOptions(options, cmd);
233
+ const result = await runLifecycleForExternalSystem(roleKey, opts);
234
+ const verdict = lifecycleVerdictFromReport(result.report || {});
235
+ const portalUrl = buildExternalSystemUiUrl(result.dataplaneUiBaseUrl, roleKey);
236
+ const caseResult = await resolveRoleAssistantCaseResult(roleKey, opts, result, verdict, portalUrl);
237
+
238
+ if (opts.json) {
239
+ logger.log(
240
+ JSON.stringify(
241
+ buildRoleAssistantTestEnvelope(roleKey, verdict, portalUrl, result, opts, caseResult),
242
+ null,
243
+ 2
244
+ )
245
+ );
246
+ } else {
247
+ displayRoleAssistantTestSummary(roleKey, verdict, portalUrl, result, caseResult);
248
+ }
249
+
250
+ const exitCode = computeRoleAssistantExitCode(verdict, caseResult);
251
+ if (exitCode !== 0) {
252
+ process.exit(exitCode);
253
+ }
254
+ }
255
+
256
+ async function roleAssistantTestHandler(roleKey, options, cmd) {
257
+ try {
258
+ await runRoleAssistantTestAction(roleKey, options, cmd);
259
+ } catch (error) {
260
+ handleCommandError(error, 'role-assistant test');
261
+ process.exit(3);
262
+ }
263
+ }
264
+
265
+ function setupRoleAssistantCommands(program) {
266
+ const roleAssistant = program
267
+ .command('role-assistant')
268
+ .description('Role Assistant lifecycle and portal workflows');
269
+
270
+ roleAssistant
271
+ .command('test <roleKey>')
272
+ .description('Run role-assistant lifecycle checks and print portal deep link')
273
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro', 'dev')
274
+ .option('--case <caseIdOrPath>', 'Run and evaluate one role-assistant test case')
275
+ .option('--tests-dir <dir>', 'Override role-assistant test case directory')
276
+ .option('-v, --verbose', 'Include full lifecycle report payload in --json output')
277
+ .option('-d, --debug', 'Write debug logs under role-assistant/<roleKey>/logs/')
278
+ .option(
279
+ '--publish',
280
+ 'Publish local Role Assistant package before checks (default: use public/running worker)'
281
+ )
282
+ .option('--force', 'Force upload when --publish is set')
283
+ .option(
284
+ '--subject-user-id <id>',
285
+ 'Subject user id for governance generate (repeatable)',
286
+ collectString,
287
+ []
288
+ )
289
+ .option(
290
+ '--subject-email <email>',
291
+ 'Subject email for governance generate (repeatable)',
292
+ collectString,
293
+ []
294
+ )
295
+ .option(
296
+ '--certification-profile <profile>',
297
+ 'Certification profile for governance generate (bronze, silver, gold, ...)',
298
+ 'bronze'
299
+ )
300
+ .option('--json', 'Machine-readable output envelope')
301
+ .addHelpText('after', roleAssistantHelpAfter())
302
+ .action((roleKey, options, cmd) => roleAssistantTestHandler(roleKey, options, cmd));
303
+ }
304
+
305
+ module.exports = {
306
+ setupRoleAssistantCommands,
307
+ roleAssistantTestHandler,
308
+ runRoleAssistantTestAction,
309
+ normalizeRoleAssistantTestOptions,
310
+ buildRoleAssistantTestEnvelope,
311
+ computeRoleAssistantExitCode,
312
+ resolveRoleAssistantCaseResult
313
+ };