@aifabrix/builder 2.51.0 → 2.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/jest.isolated-projects.js +77 -1
  2. package/jest.projects.js +5 -426
  3. package/lib/api/assistants.api.js +67 -0
  4. package/lib/api/datasources-extended.api.js +6 -6
  5. package/lib/api/evidence-authoring-helpers.js +267 -0
  6. package/lib/api/evidence-authoring.api.js +337 -0
  7. package/lib/api/evidence.api.js +57 -1
  8. package/lib/api/index.js +24 -7
  9. package/lib/api/pipeline.api.js +43 -3
  10. package/lib/api/records-bulk.api.js +28 -3
  11. package/lib/api/types/evidence.types.js +156 -8
  12. package/lib/api/work.api.js +283 -0
  13. package/lib/app/run-container-start.js +4 -0
  14. package/lib/app/run-deploy-job.js +216 -0
  15. package/lib/app/run-env-compose.js +32 -0
  16. package/lib/app/run-env-recovery.js +35 -0
  17. package/lib/app/run-helpers.js +15 -9
  18. package/lib/app/run.js +18 -2
  19. package/lib/channels/add-channel.js +54 -23
  20. package/lib/channels/approval-guides/chatgpt.js +13 -9
  21. package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
  22. package/lib/channels/channel-artifact-generator.js +14 -2
  23. package/lib/channels/channel-credential.js +3 -1
  24. package/lib/channels/channel-probe-evidence.js +79 -0
  25. package/lib/channels/channel-probe.js +265 -13
  26. package/lib/channels/channel-runtime-resolver.js +120 -29
  27. package/lib/channels/channel-status-display.js +44 -0
  28. package/lib/channels/channel-targets.js +25 -1
  29. package/lib/channels/chatgpt-runtime-contract.js +29 -0
  30. package/lib/channels/microsoft-copilot-package.js +280 -0
  31. package/lib/channels/runtime-tool-catalog.js +165 -0
  32. package/lib/cli/index.js +2 -0
  33. package/lib/cli/infra-guided-footers.js +1 -1
  34. package/lib/cli/infra-guided-public-url-warn.js +55 -0
  35. package/lib/cli/infra-guided.js +65 -56
  36. package/lib/cli/setup-app.help.js +4 -0
  37. package/lib/cli/setup-app.js +4 -0
  38. package/lib/cli/setup-app.test-commands.js +59 -28
  39. package/lib/cli/setup-external-system-help.js +8 -2
  40. package/lib/cli/setup-external-system.js +62 -12
  41. package/lib/commands/app-test.js +2 -14
  42. package/lib/commands/channel-add-setup.js +8 -2
  43. package/lib/commands/channel.js +16 -5
  44. package/lib/commands/datasource-load-export-cli.js +6 -1
  45. package/lib/commands/deploy-gate-failure-details.js +19 -17
  46. package/lib/commands/deploy-gate-orchestrator.js +3 -2
  47. package/lib/commands/dev-down.js +2 -6
  48. package/lib/commands/evidence-kind.js +65 -15
  49. package/lib/commands/governance-generate-external.js +56 -21
  50. package/lib/commands/governance-verify-external.js +2 -5
  51. package/lib/commands/lifecycle-external.js +21 -8
  52. package/lib/commands/repair-datasource-apply.js +10 -1
  53. package/lib/commands/repair-datasource-run.js +4 -2
  54. package/lib/commands/repair-datasource-test-payload.js +80 -19
  55. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
  56. package/lib/commands/repair-internal.js +9 -1
  57. package/lib/commands/repair-openapi-sync.js +34 -17
  58. package/lib/commands/role-assistant.js +371 -0
  59. package/lib/commands/test-governance-external.js +2 -5
  60. package/lib/commands/up-miso.js +61 -24
  61. package/lib/commands/upload-data-sync-finalize.js +25 -7
  62. package/lib/commands/upload-sidecar-followups.js +144 -47
  63. package/lib/commands/upload.js +43 -6
  64. package/lib/commands/verify-governance-combined-external.js +73 -9
  65. package/lib/commands/verify-governance-db.js +80 -25
  66. package/lib/commands/verify-governance-external.js +31 -10
  67. package/lib/commands/verify-operations-external.js +2 -5
  68. package/lib/commands/verify-operations-step-plan.js +31 -0
  69. package/lib/commands/verify-trust-command-action.js +2 -5
  70. package/lib/commands/wizard-core-helpers.js +7 -3
  71. package/lib/commands/wizard-core.js +78 -9
  72. package/lib/datasource/bulk-loader-run-batches.js +4 -2
  73. package/lib/datasource/bulk-loader-service.js +5 -1
  74. package/lib/datasource/datasource-identifier.js +4 -3
  75. package/lib/datasource/datasource-validate-summary.js +2 -2
  76. package/lib/datasource/integration-context.js +3 -3
  77. package/lib/datasource/resolve-app.js +90 -8
  78. package/lib/datasource/test-e2e.js +2 -2
  79. package/lib/datasource/unified-validation-run-body.js +15 -1
  80. package/lib/datasource/unified-validation-run-resolve.js +2 -2
  81. package/lib/datasource/validate.js +13 -6
  82. package/lib/external-system/deploy-helpers.js +39 -1
  83. package/lib/external-system/deploy.js +25 -11
  84. package/lib/external-system/download-helpers.js +111 -2
  85. package/lib/external-system/download-role-assistant.js +55 -0
  86. package/lib/external-system/download.js +45 -26
  87. package/lib/external-system/test-helpers.js +1 -1
  88. package/lib/external-system/test-system-level.js +21 -3
  89. package/lib/external-system/test.js +43 -7
  90. package/lib/generator/builders.js +12 -15
  91. package/lib/generator/wizard.js +51 -4
  92. package/lib/lifecycle/access-control-abac.js +121 -0
  93. package/lib/lifecycle/lifecycle-governance-options.js +4 -1
  94. package/lib/lifecycle/product-model.js +3 -2
  95. package/lib/lifecycle/report-display.js +14 -2
  96. package/lib/programmatic/capability-registry.js +20 -1
  97. package/lib/programmatic/command-options.js +1 -0
  98. package/lib/programmatic/index.js +4 -0
  99. package/lib/programmatic/manifest-patch-section.js +48 -9
  100. package/lib/programmatic/manifest-section-registry-data.js +3 -2
  101. package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
  102. package/lib/programmatic/openapi-component-schemas.js +16 -1
  103. package/lib/programmatic/openapi-description-enricher.js +3 -1
  104. package/lib/programmatic/openapi-descriptions.js +55 -5
  105. package/lib/programmatic/openapi-evidence-schemas.js +161 -0
  106. package/lib/programmatic/openapi-manifest-schemas.js +6 -2
  107. package/lib/programmatic/openapi-operation-bindings.js +99 -0
  108. package/lib/programmatic/openapi-request-schemas.js +36 -1
  109. package/lib/programmatic/openapi-result-schemas.js +1 -1
  110. package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
  111. package/lib/programmatic/openapi-schema-descriptions-core.js +1 -1
  112. package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
  113. package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
  114. package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
  115. package/lib/programmatic/openapi-spec.js +47 -28
  116. package/lib/programmatic/orchestration-openapi-meta.js +5 -0
  117. package/lib/programmatic/request-timeout.js +3 -0
  118. package/lib/programmatic/route-handler-map.js +89 -2
  119. package/lib/programmatic/run-certify.js +15 -2
  120. package/lib/programmatic/run-deploy.js +74 -0
  121. package/lib/programmatic/run-evidence-authoring.js +80 -0
  122. package/lib/programmatic/run-protection.js +124 -0
  123. package/lib/programmatic/run-template-workspace.js +28 -1
  124. package/lib/programmatic/workspace-context.js +6 -0
  125. package/lib/protection/auth-context.js +48 -6
  126. package/lib/protection/paths.js +22 -0
  127. package/lib/protection/run-protection-create-helpers.js +22 -1
  128. package/lib/protection/run-protection-create.js +1 -1
  129. package/lib/protection/sync-after-upload.js +1 -1
  130. package/lib/role-assistant/evidence-sync.js +450 -0
  131. package/lib/role-assistant/github-workflow.js +96 -0
  132. package/lib/role-assistant/knowledge-markdown-frontmatter.js +75 -0
  133. package/lib/role-assistant/knowledge-sync.js +485 -0
  134. package/lib/role-assistant/settings.js +126 -0
  135. package/lib/role-assistant/test-cases-evaluate.js +170 -0
  136. package/lib/role-assistant/test-cases-honesty.js +184 -0
  137. package/lib/role-assistant/test-cases.js +364 -0
  138. package/lib/role-assistant/test-runner-workhub-answers.js +221 -0
  139. package/lib/role-assistant/test-runner-workhub.js +399 -0
  140. package/lib/role-assistant/test-runner.js +500 -0
  141. package/lib/schema/application-schema.json +24 -28
  142. package/lib/schema/deployment-rules.yaml +1 -0
  143. package/lib/schema/external-datasource.schema.json +38 -4
  144. package/lib/schema/external-system.schema.json +4 -4
  145. package/lib/schema/role-assistant-settings.schema.json +108 -0
  146. package/lib/utils/api.js +52 -27
  147. package/lib/utils/app-path-resolve.js +72 -24
  148. package/lib/utils/authentication-shape.js +3 -1
  149. package/lib/utils/certify-external-workspace.js +40 -0
  150. package/lib/utils/deployment-validation.js +28 -3
  151. package/lib/utils/docker-run-ephemeral.js +115 -0
  152. package/lib/utils/enterprise-knowledge-paths.js +29 -12
  153. package/lib/utils/env-copy-keycloak.js +196 -0
  154. package/lib/utils/env-copy.js +34 -1
  155. package/lib/utils/external-system-readiness-compact-display.js +3 -0
  156. package/lib/utils/health-check-public-warn.js +31 -13
  157. package/lib/utils/health-check.js +11 -1
  158. package/lib/utils/help-builder.js +1 -0
  159. package/lib/utils/paths.js +80 -38
  160. package/lib/utils/pipeline-upload-auth-retry.js +15 -3
  161. package/lib/utils/role-assistant-paths.js +160 -0
  162. package/lib/utils/schema-loader.js +41 -0
  163. package/lib/utils/schema-resolver.js +36 -4
  164. package/lib/utils/token-manager.js +38 -29
  165. package/lib/utils/upload-sync-options.js +7 -4
  166. package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
  167. package/lib/validation/external-manifest-validator.js +31 -8
  168. package/lib/validation/reserved-system-key-prefixes.js +56 -0
  169. package/lib/validation/validate-external-file.js +8 -1
  170. package/lib/validation/validate.js +54 -19
  171. package/package.json +2 -1
  172. package/scripts/export-builder-api-evidence.js +1 -1
  173. package/templates/applications/builder-api/application.yaml +3 -3
  174. package/templates/applications/dataplane/application.yaml +24 -17
  175. package/templates/applications/dataplane/env.template +2 -2
  176. package/templates/applications/dataplane/rbac.yaml +24 -10
  177. package/templates/applications/keycloak/application.yaml +2 -2
  178. package/templates/applications/keycloak/env.template +5 -2
  179. package/templates/applications/miso-controller/application.yaml +3 -3
  180. package/templates/applications/miso-controller/env.template +17 -2
  181. package/templates/channels/chatgpt/install.template.md.hbs +82 -26
  182. package/templates/channels/chatgpt/integration/README.md +11 -7
  183. package/templates/channels/chatgpt/integration/application.json +2 -2
  184. package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
  185. package/templates/channels/chatgpt/integration/env.template +1 -1
  186. package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
  187. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
  188. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
  189. package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
  190. package/templates/channels/microsoft-copilot/integration/README.md +9 -7
  191. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  192. package/templates/channels/microsoft-copilot/integration/env.template +1 -1
  193. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
  194. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
  195. package/templates/channels/slack/install.template.md.hbs +6 -1
  196. package/templates/python/docker-compose.hbs +10 -0
  197. package/templates/typescript/docker-compose.hbs +10 -0
  198. /package/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
@@ -8,6 +8,11 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ const {
12
+ CHATGPT_RUNTIME_SYSTEM_KEY,
13
+ COPILOT_RUNTIME_SYSTEM_KEY
14
+ } = require('./chatgpt-runtime-contract');
15
+
11
16
  /** @typedef {'teams-bot'|'slack'|'microsoft-copilot'|'chatgpt'|'web-embed'} ChannelTargetKey */
12
17
 
13
18
  const DEFAULT_CAPABILITIES = ['chat', 'notify', 'documentApproval'];
@@ -44,6 +49,7 @@ const CHANNEL_TARGETS = {
44
49
  artifactFileName: 'channel-microsoft-copilot.json',
45
50
  artifactFormat: 'json',
46
51
  credentialKey: 'microsoft-copilot-channel',
52
+ routeSystemKey: COPILOT_RUNTIME_SYSTEM_KEY,
47
53
  capabilities: [...DEFAULT_CAPABILITIES, 'enterpriseActions'],
48
54
  approvalRequired: true,
49
55
  experimental: false
@@ -55,6 +61,7 @@ const CHANNEL_TARGETS = {
55
61
  artifactFileName: 'channel-chatgpt.json',
56
62
  artifactFormat: 'json',
57
63
  credentialKey: 'chatgpt-channel',
64
+ routeSystemKey: CHATGPT_RUNTIME_SYSTEM_KEY,
58
65
  capabilities: ['chat', 'enterpriseActions'],
59
66
  approvalRequired: true,
60
67
  experimental: false
@@ -106,10 +113,27 @@ function getDefaultChannelDescription() {
106
113
  );
107
114
  }
108
115
 
116
+ /**
117
+ * Human-readable supported channel list for CLI help and error hints.
118
+ * @returns {string}
119
+ */
120
+ function formatSupportedChannelTargetsHelp() {
121
+ const stable = CHANNEL_TARGET_KEYS.filter((key) => !CHANNEL_TARGETS[key].experimental);
122
+ const experimental = CHANNEL_TARGET_KEYS.filter((key) => CHANNEL_TARGETS[key].experimental);
123
+ const lines = ['Supported channels:', ` ${stable.join(', ')}`];
124
+ if (experimental.length > 0) {
125
+ lines.push(
126
+ ` ${experimental.join(', ')} (experimental — scaffold with --allow-experimental)`
127
+ );
128
+ }
129
+ return lines.join('\n');
130
+ }
131
+
109
132
  module.exports = {
110
133
  CHANNEL_TARGETS,
111
134
  CHANNEL_TARGET_KEYS,
112
135
  isChannelTargetKey,
113
136
  getChannelTarget,
114
- getDefaultChannelDescription
137
+ getDefaultChannelDescription,
138
+ formatSupportedChannelTargetsHelp
115
139
  };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * ChatGPT custom MCP app runtime contract constants (plan 163).
3
+ *
4
+ * @fileoverview Runtime-orchestration MCP contract fields used by chatgpt channel templates and probes
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const RUNTIME_ORCHESTRATION_SYSTEM_KEY = 'runtime-orchestration';
12
+
13
+ const CHATGPT_RUNTIME_SYSTEM_KEY = RUNTIME_ORCHESTRATION_SYSTEM_KEY;
14
+ const CHATGPT_RUNTIME_TRANSPORT = 'streamable-http';
15
+ const CHATGPT_RUNTIME_AUTH_MODE = 'oauth21-authorization-code-pkce-s256';
16
+
17
+ const COPILOT_RUNTIME_SYSTEM_KEY = RUNTIME_ORCHESTRATION_SYSTEM_KEY;
18
+ const COPILOT_RUNTIME_TRANSPORT = 'streamable-http';
19
+ const COPILOT_RUNTIME_AUTH_MODE = 'microsoft-entra-sso-or-oauth';
20
+
21
+ module.exports = {
22
+ RUNTIME_ORCHESTRATION_SYSTEM_KEY,
23
+ CHATGPT_RUNTIME_SYSTEM_KEY,
24
+ CHATGPT_RUNTIME_TRANSPORT,
25
+ CHATGPT_RUNTIME_AUTH_MODE,
26
+ COPILOT_RUNTIME_SYSTEM_KEY,
27
+ COPILOT_RUNTIME_TRANSPORT,
28
+ COPILOT_RUNTIME_AUTH_MODE
29
+ };
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Microsoft Copilot package artifact generation (plan 164).
3
+ *
4
+ * @fileoverview Build source files, package ZIP, and lifecycle summary for microsoft-copilot channel
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const crypto = require('crypto');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const AdmZip = require('adm-zip');
15
+
16
+ const PLACEHOLDER_ICON_BASE64 =
17
+ 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO2s9WQAAAAASUVORK5CYII=';
18
+
19
+ /**
20
+ * @param {string} outputPath
21
+ * @param {Object} runtimeValues
22
+ * @returns {Object}
23
+ */
24
+ function buildCopilotOutputPaths(outputPath, runtimeValues) {
25
+ const rootDir = path.dirname(outputPath);
26
+ const sourceDir = path.join(rootDir, 'source');
27
+ const buildDir = path.join(rootDir, 'build');
28
+ const installDir = path.join(rootDir, 'install');
29
+ const environment = String(runtimeValues.environment || 'dev').trim() || 'dev';
30
+ const zipFileName = `appPackage.${environment}.zip`;
31
+ return {
32
+ rootDir,
33
+ sourceDir,
34
+ buildDir,
35
+ installDir,
36
+ summaryPath: outputPath,
37
+ zipFileName,
38
+ zipPath: path.join(buildDir, zipFileName),
39
+ validationPath: path.join(installDir, 'validation.json'),
40
+ installPath: path.join(installDir, 'README.md')
41
+ };
42
+ }
43
+
44
+ /**
45
+ * @returns {{ color: Buffer, outline: Buffer }}
46
+ */
47
+ function getPlaceholderIcons() {
48
+ const icon = Buffer.from(PLACEHOLDER_ICON_BASE64, 'base64');
49
+ return { color: icon, outline: icon };
50
+ }
51
+
52
+ /**
53
+ * @param {Object} runtimeValues
54
+ * @param {(templatePath: string, context: Object) => string} renderTemplateFile
55
+ * @param {string} templatesDir
56
+ * @returns {{ sourceFiles: Record<string, string>, installText: string }}
57
+ */
58
+ function renderCopilotTemplates(runtimeValues, renderTemplateFile, templatesDir) {
59
+ const sourceFiles = {
60
+ 'manifest.json': renderTemplateFile(path.join(templatesDir, 'manifest.template.json.hbs'), runtimeValues),
61
+ 'declarativeAgent.json': renderTemplateFile(
62
+ path.join(templatesDir, 'declarative-agent.template.json.hbs'),
63
+ runtimeValues
64
+ ),
65
+ 'ai-plugin.json': renderTemplateFile(
66
+ path.join(templatesDir, 'ai-plugin.template.json.hbs'),
67
+ runtimeValues
68
+ )
69
+ };
70
+ const installText = renderTemplateFile(path.join(templatesDir, 'install.template.md.hbs'), runtimeValues);
71
+ return { sourceFiles, installText };
72
+ }
73
+
74
+ /**
75
+ * @param {Record<string, string>} sourceFiles
76
+ * @param {(content: string) => void} assertNoSecretsInArtifact
77
+ */
78
+ function assertNoSecretsInSourceFiles(sourceFiles, assertNoSecretsInArtifact) {
79
+ for (const content of Object.values(sourceFiles)) {
80
+ assertNoSecretsInArtifact(content);
81
+ }
82
+ }
83
+
84
+ /**
85
+ * @param {Record<string, string>} sourceFiles
86
+ * @param {{ color: Buffer, outline: Buffer }} icons
87
+ * @returns {Buffer}
88
+ */
89
+ function buildCopilotZipBuffer(sourceFiles, icons) {
90
+ const zip = new AdmZip();
91
+ zip.addFile('manifest.json', Buffer.from(sourceFiles['manifest.json'], 'utf8'));
92
+ zip.addFile('declarativeAgent.json', Buffer.from(sourceFiles['declarativeAgent.json'], 'utf8'));
93
+ zip.addFile('ai-plugin.json', Buffer.from(sourceFiles['ai-plugin.json'], 'utf8'));
94
+ zip.addFile('color.png', icons.color);
95
+ zip.addFile('outline.png', icons.outline);
96
+ return zip.toBuffer();
97
+ }
98
+
99
+ /**
100
+ * @param {Object} runtimeValues
101
+ * @param {Object} paths
102
+ * @param {string[]} sourceFileNames
103
+ * @returns {Object}
104
+ */
105
+ function buildCopilotValidation(runtimeValues, paths, sourceFileNames) {
106
+ return {
107
+ tier: 'builderValidated',
108
+ environment: runtimeValues.environment,
109
+ sourceFiles: sourceFileNames,
110
+ zipFile: paths.zipFileName,
111
+ runtimeSystemKey: runtimeValues.runtimeSystemKey,
112
+ runtimeMcpUrl: runtimeValues.mcpUrl,
113
+ runtimeTransport: runtimeValues.runtimeTransport,
114
+ expectedLayerBToolNames: runtimeValues.layerBToolNames || [],
115
+ boundaries: {
116
+ onePackagePerEnvironment: true,
117
+ topLevelVendorToolsExposed: false,
118
+ roleAssistantResolution: 'dynamic-runtime'
119
+ },
120
+ requiresMicrosoftAdmin: [
121
+ 'upload-package',
122
+ 'tenant-approval',
123
+ 'assignment-and-consent',
124
+ 'first-copilot-invoke'
125
+ ]
126
+ };
127
+ }
128
+
129
+ /**
130
+ * @param {Array<string|Buffer>} parts
131
+ * @returns {string}
132
+ */
133
+ function computeCopilotArtifactHash(parts) {
134
+ const hash = crypto.createHash('sha256');
135
+ for (const part of parts) {
136
+ if (Buffer.isBuffer(part)) {
137
+ hash.update(part);
138
+ continue;
139
+ }
140
+ hash.update(String(part), 'utf8');
141
+ }
142
+ return hash.digest('hex');
143
+ }
144
+
145
+ /**
146
+ * @param {Object} runtimeValues
147
+ * @param {Object} paths
148
+ * @param {Object} validation
149
+ * @param {string} artifactHash
150
+ * @returns {Object}
151
+ */
152
+ function buildCopilotSummary(runtimeValues, paths, validation, artifactHash) {
153
+ return {
154
+ channelTarget: runtimeValues.channelTarget,
155
+ name: runtimeValues.appName,
156
+ baseName: runtimeValues.baseName,
157
+ description: runtimeValues.appDescription,
158
+ environment: runtimeValues.environment,
159
+ runtime: {
160
+ runtimeSystemKey: runtimeValues.runtimeSystemKey,
161
+ remoteMcpUrl: runtimeValues.mcpUrl,
162
+ transport: runtimeValues.runtimeTransport,
163
+ assistantCatalogUrl: runtimeValues.assistantCatalogUrl,
164
+ roleAssistantResolution: 'dynamic-runtime',
165
+ layerBToolNames: runtimeValues.layerBToolNames || []
166
+ },
167
+ authentication: {
168
+ mode: runtimeValues.runtimeAuthMode,
169
+ credentialKey: runtimeValues.credentialKey,
170
+ credentialPortalUrl: runtimeValues.credentialPortalUrl,
171
+ scopes: runtimeValues.scopes || []
172
+ },
173
+ package: {
174
+ appId: runtimeValues.packageAppId,
175
+ version: runtimeValues.packageVersion,
176
+ sourceFiles: ['manifest.json', 'declarativeAgent.json', 'ai-plugin.json', 'color.png', 'outline.png'],
177
+ zipFileName: paths.zipFileName,
178
+ installGuide: path.relative(paths.rootDir, paths.installPath),
179
+ validationFile: path.relative(paths.rootDir, paths.validationPath)
180
+ },
181
+ probeTiers: {
182
+ builderValidated: true,
183
+ runtimeValidated: false,
184
+ requiresMicrosoftAdmin: true
185
+ },
186
+ artifact: {
187
+ format: 'microsoft-365-copilot-package',
188
+ hash: artifactHash,
189
+ generatedAt: new Date().toISOString()
190
+ },
191
+ validation
192
+ };
193
+ }
194
+
195
+ /**
196
+ * @param {Object} params
197
+ */
198
+ function writeCopilotArtifacts(params) {
199
+ const { paths, sourceFiles, icons, zipBuffer, installText, validationText, summaryText } = params;
200
+ fs.mkdirSync(paths.sourceDir, { recursive: true });
201
+ fs.mkdirSync(paths.buildDir, { recursive: true });
202
+ fs.mkdirSync(paths.installDir, { recursive: true });
203
+ fs.writeFileSync(path.join(paths.sourceDir, 'manifest.json'), sourceFiles['manifest.json'], 'utf8');
204
+ fs.writeFileSync(
205
+ path.join(paths.sourceDir, 'declarativeAgent.json'),
206
+ sourceFiles['declarativeAgent.json'],
207
+ 'utf8'
208
+ );
209
+ fs.writeFileSync(path.join(paths.sourceDir, 'ai-plugin.json'), sourceFiles['ai-plugin.json'], 'utf8');
210
+ fs.writeFileSync(path.join(paths.sourceDir, 'color.png'), icons.color);
211
+ fs.writeFileSync(path.join(paths.sourceDir, 'outline.png'), icons.outline);
212
+ fs.writeFileSync(paths.zipPath, zipBuffer);
213
+ fs.writeFileSync(paths.installPath, installText, 'utf8');
214
+ fs.writeFileSync(paths.validationPath, validationText, 'utf8');
215
+ fs.writeFileSync(paths.summaryPath, summaryText, 'utf8');
216
+ }
217
+
218
+ /**
219
+ * @param {Object} params
220
+ * @param {Object} params.runtimeValues
221
+ * @param {string} params.templatesDir
222
+ * @param {string} params.outputPath
223
+ * @param {boolean} [params.dryRun]
224
+ * @param {(content: string) => void} params.assertNoSecretsInArtifact
225
+ * @param {(templatePath: string, context: Object) => string} params.renderTemplateFile
226
+ * @returns {{ outputPath: string, artifactHash: string, content: string, installPath: string }}
227
+ */
228
+ function generateMicrosoftCopilotPackage(params) {
229
+ const runtimeValues = params.runtimeValues || {};
230
+ const paths = buildCopilotOutputPaths(params.outputPath, runtimeValues);
231
+ const icons = getPlaceholderIcons();
232
+ const { sourceFiles, installText } = renderCopilotTemplates(
233
+ runtimeValues,
234
+ params.renderTemplateFile,
235
+ params.templatesDir
236
+ );
237
+ assertNoSecretsInSourceFiles(sourceFiles, params.assertNoSecretsInArtifact);
238
+ params.assertNoSecretsInArtifact(installText);
239
+ const zipBuffer = buildCopilotZipBuffer(sourceFiles, icons);
240
+ const validation = buildCopilotValidation(runtimeValues, paths, Object.keys(sourceFiles));
241
+ const validationText = JSON.stringify(validation, null, 2);
242
+ const artifactHash = computeCopilotArtifactHash([
243
+ sourceFiles['manifest.json'],
244
+ sourceFiles['declarativeAgent.json'],
245
+ sourceFiles['ai-plugin.json'],
246
+ installText,
247
+ validationText,
248
+ zipBuffer
249
+ ]);
250
+ const summary = buildCopilotSummary(runtimeValues, paths, validation, artifactHash);
251
+ const summaryText = JSON.stringify(summary, null, 2);
252
+ params.assertNoSecretsInArtifact(summaryText);
253
+ if (!params.dryRun) {
254
+ writeCopilotArtifacts({
255
+ paths,
256
+ sourceFiles,
257
+ icons,
258
+ zipBuffer,
259
+ installText,
260
+ validationText,
261
+ summaryText
262
+ });
263
+ }
264
+ return {
265
+ outputPath: paths.summaryPath,
266
+ artifactHash,
267
+ content: summaryText,
268
+ installPath: paths.installPath
269
+ };
270
+ }
271
+
272
+ module.exports = {
273
+ generateMicrosoftCopilotPackage,
274
+ buildCopilotOutputPaths,
275
+ renderCopilotTemplates,
276
+ buildCopilotZipBuffer,
277
+ buildCopilotValidation,
278
+ buildCopilotSummary,
279
+ computeCopilotArtifactHash
280
+ };
@@ -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
@@ -24,6 +24,7 @@ const { setupDatasourceCommands } = require('../commands/datasource');
24
24
  const { setupDimensionCommands } = require('../commands/dimension');
25
25
  const { setupResourceTypeCommands } = require('../commands/resource-type');
26
26
  const { setupRoleCommands } = require('../commands/role');
27
+ const { setupRoleAssistantCommands } = require('../commands/role-assistant');
27
28
  const { setupEvidenceKindCommands } = require('../commands/evidence-kind');
28
29
  const { setupEnterpriseKnowledgeCommands } = require('../commands/enterprise-knowledge');
29
30
  const { setupIdentityCommands } = require('../commands/identity');
@@ -76,6 +77,7 @@ function setupExtendedCliCommands(program) {
76
77
  setupDimensionCommands(program);
77
78
  setupResourceTypeCommands(program);
78
79
  setupRoleCommands(program);
80
+ setupRoleAssistantCommands(program);
79
81
  setupEvidenceKindCommands(program);
80
82
  setupEnterpriseKnowledgeCommands(program);
81
83
  setupIdentityCommands(program);
@@ -95,7 +95,7 @@ function logPlatformSetupDurationHint(scope = 'platform') {
95
95
  const line =
96
96
  scope === 'dataplane'
97
97
  ? 'Installation may take a few minutes. Authenticating and starting Dataplane — please wait.'
98
- : 'Installation may take a few minutes. Keycloak, Miso Controller, and Dataplane are starting — please wait.';
98
+ : 'Installation may take a few minutes. Keycloak, Miso Controller, Dataplane, and Builder API are starting — please wait.';
99
99
  logger.log(chalk.yellow(`⚠ ${line}`));
100
100
  }
101
101
 
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @fileoverview Consolidate deferred public-URL health warnings for guided install UX.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const logger = require('../utils/logger');
8
+ const { formatWarningLine } = require('../utils/cli-test-layout-chalk');
9
+
10
+ /**
11
+ * @param {string} message
12
+ * @returns {{ kind: 'dns'|'localhost', url: string }|null}
13
+ */
14
+ function extractPublicUrlFromWarning(message) {
15
+ const text = String(message || '');
16
+ const dnsMatch = text.match(/Public URL was not verified \(DNS\):\s*(\S+)/);
17
+ if (dnsMatch) {
18
+ return { kind: 'dns', url: dnsMatch[1].replace(/\.$/, '') };
19
+ }
20
+ const match = text.match(/Public URL was not verified:\s*(\S+)/);
21
+ if (match) {
22
+ return { kind: 'localhost', url: match[1].replace(/\.$/, '') };
23
+ }
24
+ return null;
25
+ }
26
+
27
+ /**
28
+ * Print one consolidated public-URL warning (avoid N near-duplicate lines).
29
+ * @param {string[]} messages
30
+ */
31
+ function flushDeferredPublicUrlWarnings(messages) {
32
+ const list = (messages || []).filter(Boolean);
33
+ if (list.length === 0) {
34
+ return;
35
+ }
36
+ const parsed = list.map(extractPublicUrlFromWarning).filter(Boolean);
37
+ if (parsed.length === 0) {
38
+ for (const message of list) {
39
+ logger.log(formatWarningLine(message));
40
+ }
41
+ return;
42
+ }
43
+ const urls = [...new Set(parsed.map((row) => row.url))];
44
+ const hasDns = parsed.some((row) => row.kind === 'dns');
45
+ const urlPart = urls.length === 1 ? urls[0] : urls.join(', ');
46
+ const detail = hasDns
47
+ ? 'Hostname DNS and/or Traefik routing/TLS could not be verified; health succeeded via localhost only.'
48
+ : 'Health checks succeeded via localhost only. Validate Traefik routing, TLS, and DNS.';
49
+ logger.log(formatWarningLine(`Public URL was not verified: ${urlPart}. ${detail}`));
50
+ }
51
+
52
+ module.exports = {
53
+ extractPublicUrlFromWarning,
54
+ flushDeferredPublicUrlWarnings
55
+ };