@aifabrix/builder 2.52.1 → 2.53.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.
- package/lib/app/deploy-config.js +3 -2
- package/lib/channels/add-channel.js +11 -41
- package/lib/channels/approval-guides/index.js +3 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +26 -17
- package/lib/channels/channel-add-existing.js +72 -0
- package/lib/channels/channel-runtime-resolver.js +5 -1
- package/lib/channels/channel-status-display.js +30 -3
- package/lib/channels/microsoft-copilot-entra-sso-form.js +73 -2
- package/lib/channels/microsoft-copilot-entra-sso.js +26 -5
- package/lib/channels/microsoft-copilot-limits.js +22 -3
- package/lib/channels/microsoft-copilot-package.js +59 -14
- package/lib/channels/microsoft-copilot-validate.js +40 -10
- package/lib/cli/attach-default-help-examples.js +102 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-credential-deployment.js +7 -5
- package/lib/cli/setup-utility-validate.js +1 -0
- package/lib/commands/credential-push.js +37 -5
- package/lib/commands/package-score.js +72 -0
- package/lib/commands/role-assistant.js +46 -8
- package/lib/deployment/deployer-poll-run.js +2 -2
- package/lib/deployment/deployer.js +1 -1
- package/lib/deployment/environment.js +2 -2
- package/lib/external-system/deploy.js +11 -21
- package/lib/integration-definition/apply.js +12 -14
- package/lib/integration-definition/enrich-openapi-operations.js +9 -10
- package/lib/lab/package-parity-score.js +417 -0
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/help-content/channel-onboarding.md +35 -0
- package/lib/programmatic/help-content/cip-overview.md +27 -0
- package/lib/programmatic/help-content/connected-system-ui.md +70 -0
- package/lib/programmatic/help-content/dimensions-guide.md +23 -0
- package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
- package/lib/programmatic/help-content/overview.md +25 -0
- package/lib/programmatic/help-content/subscription-guide.md +27 -0
- package/lib/programmatic/help-content/workflow.md +50 -0
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +6 -0
- package/lib/programmatic/openapi-envelope-examples.js +11 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +39 -13
- package/lib/programmatic/openapi-result-schemas.js +30 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +18 -0
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/persist-supplied-openapi.js +180 -0
- package/lib/programmatic/route-handler-map.js +6 -0
- package/lib/programmatic/run-integration-definition.js +13 -5
- package/lib/role-assistant/evidence-sync.js +55 -7
- package/lib/role-assistant/test-runner-attachments.js +118 -0
- package/lib/role-assistant/test-runner-bid-apply.js +100 -21
- package/lib/role-assistant/test-runner-bid-document.js +1 -1
- package/lib/role-assistant/test-runner-start-payload.js +96 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +11 -7
- package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
- package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
- package/lib/role-assistant/test-runner-workhub.js +68 -105
- package/lib/role-assistant/test-runner.js +5 -63
- package/lib/role-assistant/test-suite.js +33 -40
- package/lib/schema/external-datasource.schema.json +13 -4
- package/lib/utils/compose-generator.js +10 -1
- package/lib/utils/compose-traefik-extra-routes.js +107 -0
- package/lib/utils/docker-build.js +2 -2
- package/lib/utils/help-builder.js +2 -1
- package/lib/utils/promote-dev-docker-image.js +15 -10
- package/package.json +14 -16
- package/templates/README.md +12 -1
- package/templates/applications/dataplane/application.yaml +8 -1
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/miso-controller/application.yaml +2 -1
- package/templates/applications/miso-controller/rbac.yaml +1 -0
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +6 -2
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +8 -5
- package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +74 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +29 -14
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +6 -2
- package/templates/python/docker-compose.hbs +36 -0
- package/templates/typescript/docker-compose.hbs +36 -0
- package/.cursor/plans/Archive/157.1-security-quality-violations-by-type.csv +0 -374
- package/.cursor/process/README.md +0 -9
- package/.cursor/rules/anchor-docs.mdc +0 -15
- package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
- package/.cursor/rules/cli-layout.mdc +0 -81
- package/.cursor/rules/cli-product-neutral.mdc +0 -43
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
- package/.cursor/rules/docs-rules.mdc +0 -32
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
- package/.cursor/rules/project-rules.mdc +0 -913
- package/.cursor/skills/README.md +0 -15
- package/.dockerignore +0 -52
- package/.eslintignore +0 -22
- package/.markdownlint.json +0 -14
- package/anchor-docs/README.md +0 -10
- package/anchor-docs/_TEMPLATE +0 -24
- package/babel.config.js +0 -6
- package/bin/builder-api-cleanup.js +0 -26
- package/bin/builder-api-nest.js +0 -10
- package/bin/builder-api-spike.js +0 -19
- package/enterprise-knowledge/README.md +0 -50
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
- package/integration/README.md +0 -81
- package/integration/github/README.md +0 -53
- package/integration/github/application.json +0 -21
- package/integration/github/deploy.js +0 -72
- package/integration/github/env.template +0 -11
- package/integration/github/github-datasource-issue-comments.json +0 -239
- package/integration/github/github-datasource-issues.json +0 -399
- package/integration/github/github-datasource-repository.json +0 -354
- package/integration/github/github-deploy.json +0 -1202
- package/integration/github/github-system.json +0 -82
- package/integration/hubspot-test/README.md +0 -159
- package/integration/hubspot-test/application.json +0 -54
- package/integration/hubspot-test/companies.json +0 -2048
- package/integration/hubspot-test/create-hubspot.js +0 -523
- package/integration/hubspot-test/env.template +0 -4
- package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
- package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
- package/integration/hubspot-test/hubspot-test-system.json +0 -74
- package/integration/hubspot-test/rbac.json +0 -166
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
- package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
- package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
- package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
- package/integration/hubspot-test/test-dataplane-down.js +0 -209
- package/integration/hubspot-test/test.js +0 -1588
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
- package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
- package/integration/roundtrip-test-local/README.md +0 -143
- package/integration/roundtrip-test-local/application.yaml +0 -13
- package/integration/roundtrip-test-local/env.template +0 -15
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
- package/integration/roundtrip-test-local2/README.md +0 -143
- package/integration/roundtrip-test-local2/application.yaml +0 -13
- package/integration/roundtrip-test-local2/env.template +0 -15
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
- package/integration/test/wizard.yaml +0 -8
- package/jest.config.coverage.js +0 -37
- package/jest.config.default.js +0 -11
- package/jest.config.integration.fixtures.js +0 -22
- package/jest.config.integration.js +0 -33
- package/jest.config.isolated.js +0 -11
- package/jest.config.manual.js +0 -30
- package/jest.global-live-fabrix-hooks.js +0 -36
- package/jest.isolated-projects.js +0 -283
- package/jest.projects.js +0 -79
- package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +0 -205
- package/packages/builder-api/README.md +0 -120
- package/packages/builder-api/package.json +0 -30
- package/packages/builder-api/src/app.module.ts +0 -7
- package/packages/builder-api/src/auth/auth.module.ts +0 -5
- package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
- package/packages/builder-api/src/main.ts +0 -16
- package/packages/builder-api/tsconfig.json +0 -15
- package/scripts/check-builder-api-architecture-grep.js +0 -79
- package/scripts/check-datasource-test-run-schema-sync.js +0 -34
- package/scripts/ci-fix.sh +0 -19
- package/scripts/ci-simulate.sh +0 -19
- package/scripts/diagnose-cli.js +0 -150
- package/scripts/docker_image_content_gate.js +0 -47
- package/scripts/docker_image_content_gate.sh +0 -5
- package/scripts/export-builder-api-evidence.js +0 -262
- package/scripts/install-local.js +0 -490
- package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
- package/scripts/lib/builder-api-docker-staging-core.js +0 -183
- package/scripts/lib/docker-image-content-gate-core.js +0 -166
- package/scripts/lib/plan-actor.js +0 -109
- package/scripts/lib/plan-config.js +0 -20
- package/scripts/lib/plan-gates.js +0 -154
- package/scripts/lib/plan-meta.js +0 -104
- package/scripts/lib/plan-parse.js +0 -162
- package/scripts/lib/plan-prevalidate-gates.js +0 -337
- package/scripts/lib/plan-run-core.js +0 -125
- package/scripts/lib/plan-run-report.js +0 -119
- package/scripts/plan-approve.js +0 -24
- package/scripts/plan-archive.js +0 -49
- package/scripts/plan-run.js +0 -13
- package/scripts/plan-set-actor.js +0 -21
- package/scripts/plan-validate.js +0 -80
- package/scripts/pnpm/af.mjs +0 -125
- package/scripts/pnpm/check-quiet.mjs +0 -32
- package/scripts/pnpm/dev-install.mjs +0 -29
- package/scripts/pnpm/dev-reload.mjs +0 -18
- package/scripts/pnpm/help.mjs +0 -55
- package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
- package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
- package/scripts/pnpm/lib/spinner.mjs +0 -42
- package/scripts/pnpm-global-remove.js +0 -48
- package/scripts/stage_builder_api_for_docker.js +0 -65
- package/scripts/sync-builder-api-template.js +0 -44
- package/scripts/test-dataplane-bootstrap.js +0 -331
|
@@ -18,7 +18,10 @@ const { applyMicrosoftCopilotDisplayLimits } = require('./microsoft-copilot-limi
|
|
|
18
18
|
const {
|
|
19
19
|
assertCopilotPackageOauthPluginVaultReference
|
|
20
20
|
} = require('./microsoft-copilot-entra-sso');
|
|
21
|
-
const {
|
|
21
|
+
const {
|
|
22
|
+
renderCopilotChannelTemplate,
|
|
23
|
+
applyWebApplicationInfoFields
|
|
24
|
+
} = require('./microsoft-copilot-entra-sso-form');
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* @param {string} outputPath
|
|
@@ -73,7 +76,8 @@ function renderCopilotTemplates(runtimeValues, renderTemplateFile, templatesDir)
|
|
|
73
76
|
'ai-plugin.json': renderTemplateFile(
|
|
74
77
|
path.join(templatesDir, 'ai-plugin.template.json.hbs'),
|
|
75
78
|
runtimeValues
|
|
76
|
-
)
|
|
79
|
+
),
|
|
80
|
+
'fi-fi.json': renderTemplateFile(path.join(templatesDir, 'fi-fi.template.json.hbs'), runtimeValues)
|
|
77
81
|
};
|
|
78
82
|
// INSTALL prose + Entra SSO form table live in templates (partial entraSsoRegistration).
|
|
79
83
|
const installText = renderCopilotChannelTemplate('install.template.md.hbs', runtimeValues);
|
|
@@ -100,6 +104,7 @@ function buildCopilotZipBuffer(sourceFiles, icons) {
|
|
|
100
104
|
zip.addFile('manifest.json', Buffer.from(sourceFiles['manifest.json'], 'utf8'));
|
|
101
105
|
zip.addFile('declarativeAgent.json', Buffer.from(sourceFiles['declarativeAgent.json'], 'utf8'));
|
|
102
106
|
zip.addFile('ai-plugin.json', Buffer.from(sourceFiles['ai-plugin.json'], 'utf8'));
|
|
107
|
+
zip.addFile('fi-fi.json', Buffer.from(sourceFiles['fi-fi.json'], 'utf8'));
|
|
103
108
|
zip.addFile('color.png', icons.color);
|
|
104
109
|
zip.addFile('outline.png', icons.outline);
|
|
105
110
|
return zip.toBuffer();
|
|
@@ -130,8 +135,9 @@ function buildCopilotValidation(runtimeValues, paths, sourceFileNames) {
|
|
|
130
135
|
roleAssistantResolution: 'dynamic-runtime'
|
|
131
136
|
},
|
|
132
137
|
requiresMicrosoftAdmin: [
|
|
133
|
-
'
|
|
134
|
-
'
|
|
138
|
+
'developer-portal-import',
|
|
139
|
+
'publish-to-org',
|
|
140
|
+
'teams-admin-approval',
|
|
135
141
|
'assignment-and-consent',
|
|
136
142
|
'first-copilot-invoke'
|
|
137
143
|
]
|
|
@@ -206,7 +212,14 @@ function buildCopilotSummaryPackage(runtimeValues, paths) {
|
|
|
206
212
|
return {
|
|
207
213
|
appId: runtimeValues.packageAppId,
|
|
208
214
|
version: runtimeValues.packageVersion,
|
|
209
|
-
sourceFiles: [
|
|
215
|
+
sourceFiles: [
|
|
216
|
+
'manifest.json',
|
|
217
|
+
'declarativeAgent.json',
|
|
218
|
+
'ai-plugin.json',
|
|
219
|
+
'fi-fi.json',
|
|
220
|
+
'color.png',
|
|
221
|
+
'outline.png'
|
|
222
|
+
],
|
|
210
223
|
zipFileName: paths.zipFileName,
|
|
211
224
|
installGuide: 'INSTALL.md',
|
|
212
225
|
validationFile: path.relative(paths.rootDir, paths.validationPath)
|
|
@@ -232,6 +245,9 @@ function buildCopilotSummary(runtimeValues, paths, validation, artifactHash) {
|
|
|
232
245
|
package: buildCopilotSummaryPackage(runtimeValues, paths),
|
|
233
246
|
installReady: runtimeValues.installReady === true,
|
|
234
247
|
blocker: runtimeValues.discoveryBlocker || null,
|
|
248
|
+
packageReady: runtimeValues.packageReady !== false && runtimeValues.installReady === true,
|
|
249
|
+
packageBlocker: runtimeValues.packageBlocker || runtimeValues.discoveryBlocker || null,
|
|
250
|
+
microsoftPublicationPending: runtimeValues.microsoftPublicationPending !== false,
|
|
235
251
|
links: {
|
|
236
252
|
readme: paths.installPath,
|
|
237
253
|
zip: paths.zipPath,
|
|
@@ -267,6 +283,7 @@ function writeCopilotArtifacts(params) {
|
|
|
267
283
|
'utf8'
|
|
268
284
|
);
|
|
269
285
|
fs.writeFileSync(path.join(paths.sourceDir, 'ai-plugin.json'), sourceFiles['ai-plugin.json'], 'utf8');
|
|
286
|
+
fs.writeFileSync(path.join(paths.sourceDir, 'fi-fi.json'), sourceFiles['fi-fi.json'], 'utf8');
|
|
270
287
|
fs.writeFileSync(path.join(paths.sourceDir, 'color.png'), icons.color);
|
|
271
288
|
fs.writeFileSync(path.join(paths.sourceDir, 'outline.png'), icons.outline);
|
|
272
289
|
fs.writeFileSync(paths.zipPath, zipBuffer);
|
|
@@ -301,6 +318,7 @@ function buildCopilotPackagePayload(params, runtimeValues, paths, icons) {
|
|
|
301
318
|
sourceFiles['manifest.json'],
|
|
302
319
|
sourceFiles['declarativeAgent.json'],
|
|
303
320
|
sourceFiles['ai-plugin.json'],
|
|
321
|
+
sourceFiles['fi-fi.json'],
|
|
304
322
|
installText,
|
|
305
323
|
validationText,
|
|
306
324
|
zipBuffer
|
|
@@ -312,19 +330,43 @@ function buildCopilotPackagePayload(params, runtimeValues, paths, icons) {
|
|
|
312
330
|
}
|
|
313
331
|
|
|
314
332
|
/**
|
|
315
|
-
*
|
|
316
|
-
* @param {
|
|
317
|
-
* @
|
|
318
|
-
* @param {string} params.outputPath
|
|
319
|
-
* @param {boolean} [params.dryRun]
|
|
320
|
-
* @param {(content: string) => void} params.assertNoSecretsInArtifact
|
|
321
|
-
* @param {(templatePath: string, context: Object) => string} params.renderTemplateFile
|
|
322
|
-
* @returns {{ outputPath: string, artifactHash: string, content: string, installPath: string }}
|
|
333
|
+
* Read prior webApplicationInfo from an existing source manifest (preserve on regenerate).
|
|
334
|
+
* @param {string} sourceDir
|
|
335
|
+
* @returns {{ id: string, resource: string }|null}
|
|
323
336
|
*/
|
|
337
|
+
function readPriorWebApplicationInfo(sourceDir) {
|
|
338
|
+
const manifestPath = path.join(sourceDir, 'manifest.json');
|
|
339
|
+
if (!fs.existsSync(manifestPath)) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
try {
|
|
343
|
+
const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
344
|
+
const info = parsed && parsed.webApplicationInfo;
|
|
345
|
+
if (
|
|
346
|
+
info &&
|
|
347
|
+
typeof info.id === 'string' &&
|
|
348
|
+
info.id.trim() &&
|
|
349
|
+
typeof info.resource === 'string' &&
|
|
350
|
+
info.resource.trim()
|
|
351
|
+
) {
|
|
352
|
+
return { id: info.id.trim(), resource: info.resource.trim() };
|
|
353
|
+
}
|
|
354
|
+
} catch {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
|
|
324
360
|
function generateMicrosoftCopilotPackage(params) {
|
|
325
361
|
const runtimeValues = applyMicrosoftCopilotDisplayLimits({ ...(params.runtimeValues || {}) });
|
|
326
362
|
assertCopilotPackageOauthPluginVaultReference(runtimeValues);
|
|
327
363
|
const paths = buildCopilotOutputPaths(params.outputPath, runtimeValues);
|
|
364
|
+
const prior = readPriorWebApplicationInfo(paths.sourceDir);
|
|
365
|
+
applyWebApplicationInfoFields(runtimeValues, {
|
|
366
|
+
webApplicationInfoId: runtimeValues.webApplicationInfoId,
|
|
367
|
+
webApplicationInfoResource: runtimeValues.webApplicationInfoResource,
|
|
368
|
+
priorWebApplicationInfo: prior
|
|
369
|
+
});
|
|
328
370
|
const icons = resolvePackageIcons(runtimeValues);
|
|
329
371
|
const payload = buildCopilotPackagePayload(params, runtimeValues, paths, icons);
|
|
330
372
|
if (!params.dryRun) {
|
|
@@ -346,7 +388,10 @@ function generateMicrosoftCopilotPackage(params) {
|
|
|
346
388
|
zipPath: paths.zipPath,
|
|
347
389
|
links: payload.summary.links,
|
|
348
390
|
installReady: payload.summary.installReady === true,
|
|
349
|
-
blocker: payload.summary.blocker || null
|
|
391
|
+
blocker: payload.summary.blocker || null,
|
|
392
|
+
packageReady: payload.summary.packageReady === true,
|
|
393
|
+
packageBlocker: payload.summary.packageBlocker || null,
|
|
394
|
+
microsoftPublicationPending: payload.summary.microsoftPublicationPending !== false
|
|
350
395
|
};
|
|
351
396
|
}
|
|
352
397
|
|
|
@@ -123,21 +123,17 @@ function validateAiPlugin(plugin, errors) {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* @param {Object}
|
|
126
|
+
* @param {Object} runtime
|
|
127
127
|
* @param {string[]} errors
|
|
128
128
|
*/
|
|
129
|
-
function
|
|
130
|
-
const
|
|
131
|
-
if (!
|
|
132
|
-
errors.push('ai-plugin.runtimes[0].type must be RemoteMCPServer');
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (!ALLOWED_AUTH_TYPES.has(runtime.auth?.type)) {
|
|
129
|
+
function validateAiPluginAuth(runtime, errors) {
|
|
130
|
+
const authType = runtime.auth?.type;
|
|
131
|
+
if (!ALLOWED_AUTH_TYPES.has(authType)) {
|
|
136
132
|
errors.push(
|
|
137
133
|
`ai-plugin.runtimes[0].auth.type must be one of ${[...ALLOWED_AUTH_TYPES].join(', ')}`
|
|
138
134
|
);
|
|
139
135
|
}
|
|
140
|
-
if (
|
|
136
|
+
if (authType === 'OAuthPluginVault') {
|
|
141
137
|
const ref = runtime.auth.reference_id;
|
|
142
138
|
if (typeof ref !== 'string' || !ref.trim()) {
|
|
143
139
|
errors.push(
|
|
@@ -146,17 +142,51 @@ function validateAiPluginRuntime(plugin, errors) {
|
|
|
146
142
|
);
|
|
147
143
|
}
|
|
148
144
|
}
|
|
149
|
-
if (
|
|
145
|
+
if (authType === 'None') {
|
|
150
146
|
errors.push(
|
|
151
147
|
'ai-plugin.runtimes[0].auth.type None is not allowed; use OAuthPluginVault (Microsoft token / Entra)'
|
|
152
148
|
);
|
|
153
149
|
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @param {Object} plugin
|
|
154
|
+
* @param {Object} runtime
|
|
155
|
+
* @param {string[]} errors
|
|
156
|
+
*/
|
|
157
|
+
function validateAiPluginDiscovery(plugin, runtime, errors) {
|
|
154
158
|
const desc = runtime.spec?.mcp_tool_description;
|
|
155
159
|
if (desc && (desc.mode || desc.layerBToolNames)) {
|
|
156
160
|
errors.push(
|
|
157
161
|
'ai-plugin mcp_tool_description must not use mode/layerBToolNames; omit for dynamic discovery or use tools/file'
|
|
158
162
|
);
|
|
159
163
|
}
|
|
164
|
+
if (!Array.isArray(plugin.functions) || plugin.functions.length !== 0) {
|
|
165
|
+
errors.push(
|
|
166
|
+
'ai-plugin.functions must be [] for Microsoft dynamic MCP tool discovery ' +
|
|
167
|
+
'(see run_for_functions ["*"])'
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const runFor = runtime.run_for_functions;
|
|
171
|
+
if (!Array.isArray(runFor) || runFor.length !== 1 || runFor[0] !== '*') {
|
|
172
|
+
errors.push(
|
|
173
|
+
'ai-plugin.runtimes[0].run_for_functions must be ["*"] for dynamic MCP tool discovery'
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @param {Object} plugin
|
|
180
|
+
* @param {string[]} errors
|
|
181
|
+
*/
|
|
182
|
+
function validateAiPluginRuntime(plugin, errors) {
|
|
183
|
+
const runtime = Array.isArray(plugin.runtimes) ? plugin.runtimes[0] : null;
|
|
184
|
+
if (!runtime || runtime.type !== 'RemoteMCPServer') {
|
|
185
|
+
errors.push('ai-plugin.runtimes[0].type must be RemoteMCPServer');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
validateAiPluginAuth(runtime, errors);
|
|
189
|
+
validateAiPluginDiscovery(plugin, runtime, errors);
|
|
160
190
|
}
|
|
161
191
|
|
|
162
192
|
/**
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attach minimal product-neutral Examples: blocks to commands that lack them.
|
|
3
|
+
* Runs after setupCommands so intentional addHelpText Examples are preserved.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview Default CLI help Examples for check:cli-help gate
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const EXAMPLE_HEADER_RE = /Examples:/m;
|
|
11
|
+
const EXAMPLE_LINE_RE = /\$ aifabrix |\$ af /;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {import('commander').Command} cmd
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
function captureHelpOutput(cmd) {
|
|
18
|
+
if (!cmd || typeof cmd.outputHelp !== 'function') {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
let buf = '';
|
|
22
|
+
cmd.outputHelp({
|
|
23
|
+
write: (chunk) => {
|
|
24
|
+
buf += String(chunk);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return buf;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {string} text
|
|
32
|
+
* @returns {boolean}
|
|
33
|
+
*/
|
|
34
|
+
function hasValidExamples(text) {
|
|
35
|
+
return EXAMPLE_HEADER_RE.test(text) && EXAMPLE_LINE_RE.test(text);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} pathStr
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
function defaultExamplesBlock(pathStr) {
|
|
43
|
+
return `
|
|
44
|
+
Examples:
|
|
45
|
+
$ aifabrix ${pathStr}
|
|
46
|
+
$ aifabrix ${pathStr} -h
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {import('commander').Command} cmd
|
|
52
|
+
* @param {string[]} parts
|
|
53
|
+
* @param {Array<{ cmd: import('commander').Command, path: string }>} out
|
|
54
|
+
*/
|
|
55
|
+
function collectCommands(cmd, parts, out) {
|
|
56
|
+
// Tests sometimes pass mock nodes without Commander methods — skip those.
|
|
57
|
+
if (!cmd || typeof cmd.name !== 'function') {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const name = cmd.name();
|
|
61
|
+
if (name === 'help') {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const next = name && name !== 'aifabrix' ? parts.concat(name) : parts;
|
|
65
|
+
const subs = Array.isArray(cmd.commands) ? cmd.commands : [];
|
|
66
|
+
if (next.length > 0) {
|
|
67
|
+
out.push({ cmd, path: next.join(' ') });
|
|
68
|
+
}
|
|
69
|
+
for (const child of subs) {
|
|
70
|
+
collectCommands(child, next, out);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Ensure every leaf and parent has Examples with $ aifabrix / $ af.
|
|
76
|
+
* @param {import('commander').Command} program
|
|
77
|
+
* @returns {number} count of commands that received a default Examples block
|
|
78
|
+
*/
|
|
79
|
+
function attachDefaultHelpExamples(program) {
|
|
80
|
+
const entries = [];
|
|
81
|
+
collectCommands(program, [], entries);
|
|
82
|
+
let attached = 0;
|
|
83
|
+
for (const { cmd, path: pathStr } of entries) {
|
|
84
|
+
if (typeof cmd.addHelpText !== 'function') {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const text = captureHelpOutput(cmd);
|
|
88
|
+
if (hasValidExamples(text)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
cmd.addHelpText('after', defaultExamplesBlock(pathStr));
|
|
92
|
+
attached += 1;
|
|
93
|
+
}
|
|
94
|
+
return attached;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
attachDefaultHelpExamples,
|
|
99
|
+
hasValidExamples,
|
|
100
|
+
captureHelpOutput,
|
|
101
|
+
defaultExamplesBlock
|
|
102
|
+
};
|
package/lib/cli/index.js
CHANGED
|
@@ -100,6 +100,8 @@ function setupCommands(program) {
|
|
|
100
100
|
setupCoreCliCommands(program);
|
|
101
101
|
setupExtendedCliCommands(program);
|
|
102
102
|
setupDevAndPlatformCommands(program);
|
|
103
|
+
const { attachDefaultHelpExamples } = require('./attach-default-help-examples');
|
|
104
|
+
attachDefaultHelpExamples(program);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
module.exports = {
|
|
@@ -18,8 +18,10 @@ const { runDeploymentList } = require('../commands/deployment-list');
|
|
|
18
18
|
const CREDENTIAL_HELP_AFTER = `
|
|
19
19
|
Subcommands:
|
|
20
20
|
env <systemKey> Prompt for KV_* values → integration/<key>/.env
|
|
21
|
-
push <systemKey> Upload secrets from
|
|
21
|
+
push <systemKey> Upload secrets from an env file to Dataplane (--file recommended)
|
|
22
22
|
list List credentials (pagination: --page-size)
|
|
23
|
+
|
|
24
|
+
Secrets: pass paths only (e.g. --file ./path/to/.env). Never put secret values on the command line.
|
|
23
25
|
`;
|
|
24
26
|
|
|
25
27
|
const DEPLOYMENT_HELP_AFTER = `
|
|
@@ -42,10 +44,11 @@ function setupCredentialEnvAndPush(credential) {
|
|
|
42
44
|
});
|
|
43
45
|
credential
|
|
44
46
|
.command('push <systemKey>')
|
|
45
|
-
.description('Push KV_* secrets from
|
|
46
|
-
.
|
|
47
|
+
.description('Push KV_* secrets from an env file to Dataplane (file path only — no secret values on argv)')
|
|
48
|
+
.option('--file <path>', 'Env file with KV_* values (must exist; never put secret values on argv)')
|
|
49
|
+
.action(async(systemKey, options) => {
|
|
47
50
|
try {
|
|
48
|
-
await runCredentialPush(systemKey);
|
|
51
|
+
await runCredentialPush(systemKey, { file: options.file });
|
|
49
52
|
} catch (error) {
|
|
50
53
|
logger.error(chalk.red(`Error: ${error.message}`));
|
|
51
54
|
handleCommandError(error, 'credential push');
|
|
@@ -53,7 +56,6 @@ function setupCredentialEnvAndPush(credential) {
|
|
|
53
56
|
}
|
|
54
57
|
});
|
|
55
58
|
}
|
|
56
|
-
|
|
57
59
|
/**
|
|
58
60
|
* Sets up credential and deployment list commands
|
|
59
61
|
* @param {Command} program - Commander program instance
|
|
@@ -228,6 +228,7 @@ function setupValidateDiffCommands(program) {
|
|
|
228
228
|
setupValidateCommand(program);
|
|
229
229
|
setupValidateJsonCommand(program);
|
|
230
230
|
setupDiffCommand(program);
|
|
231
|
+
require('../commands/package-score').setupPackageScoreCommand(program);
|
|
231
232
|
}
|
|
232
233
|
|
|
233
234
|
module.exports = {
|
|
@@ -51,8 +51,10 @@ async function buildPayload(systemKey) {
|
|
|
51
51
|
* Runs credential push: push KV_* from .env to dataplane.
|
|
52
52
|
* @async
|
|
53
53
|
* @param {string} systemKey - External system key
|
|
54
|
+
* @param {Object} [options]
|
|
55
|
+
* @param {string} [options.file] - Explicit env file path (required to exist when set)
|
|
54
56
|
* @returns {Promise<{ pushed: number }>} Count of secrets pushed
|
|
55
|
-
* @throws {Error} If auth or push fails
|
|
57
|
+
* @throws {Error} If auth or push fails, or --file path is missing
|
|
56
58
|
*/
|
|
57
59
|
function logPushResult(pushResult) {
|
|
58
60
|
if (pushResult.pushed > 0) {
|
|
@@ -66,10 +68,35 @@ function logPushResult(pushResult) {
|
|
|
66
68
|
if (pushResult.warning) logger.log(chalk.yellow(`Warning: ${pushResult.warning}`));
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Resolve env file path for credential push.
|
|
73
|
+
* @param {string} systemKey
|
|
74
|
+
* @param {Object} [options]
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function resolveCredentialEnvFilePath(systemKey, options = {}) {
|
|
78
|
+
const fileOpt =
|
|
79
|
+
options.file !== undefined && options.file !== null ? String(options.file).trim() : '';
|
|
80
|
+
if (fileOpt) {
|
|
81
|
+
const resolved = path.resolve(fileOpt);
|
|
82
|
+
const fsReal = require('../internal/fs-real-sync');
|
|
83
|
+
let isFile = false;
|
|
84
|
+
try {
|
|
85
|
+
isFile = fsReal.existsSync(resolved) && fsReal.statSync(resolved).isFile();
|
|
86
|
+
} catch (_err) {
|
|
87
|
+
isFile = false;
|
|
88
|
+
}
|
|
89
|
+
if (!isFile) {
|
|
90
|
+
throw new Error(`Credential env file not found: ${resolved}`);
|
|
91
|
+
}
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|
|
94
|
+
return path.join(getIntegrationPath(systemKey), '.env');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function runCredentialPush(systemKey, options = {}) {
|
|
70
98
|
validateSystemKeyFormat(systemKey);
|
|
71
|
-
const
|
|
72
|
-
const envFilePath = path.join(appPath, '.env');
|
|
99
|
+
const envFilePath = resolveCredentialEnvFilePath(systemKey, options);
|
|
73
100
|
|
|
74
101
|
const { resolveEnvironment } = require('../core/config');
|
|
75
102
|
const environment = await resolveEnvironment();
|
|
@@ -99,4 +126,9 @@ async function runCredentialPush(systemKey) {
|
|
|
99
126
|
return { pushed: pushResult.pushed || 0 };
|
|
100
127
|
}
|
|
101
128
|
|
|
102
|
-
module.exports = {
|
|
129
|
+
module.exports = {
|
|
130
|
+
runCredentialPush,
|
|
131
|
+
validateSystemKeyFormat,
|
|
132
|
+
buildPayload,
|
|
133
|
+
resolveCredentialEnvFilePath
|
|
134
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI: score candidate integration package vs a reference package directory.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview package-score command — score-only parity; reference is never generation input
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const logger = require('../utils/logger');
|
|
12
|
+
const { scorePackageParity } = require('../lab/package-parity-score');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {Object} options
|
|
16
|
+
* @param {string} options.reference
|
|
17
|
+
* @param {string} options.candidate
|
|
18
|
+
* @param {boolean} [options.json]
|
|
19
|
+
* @returns {Promise<number>} process exit code
|
|
20
|
+
*/
|
|
21
|
+
async function runPackageScoreCommand(options = {}) {
|
|
22
|
+
const reference = String(options.reference || '').trim();
|
|
23
|
+
const candidate = String(options.candidate || '').trim();
|
|
24
|
+
if (!reference || !candidate) {
|
|
25
|
+
throw new Error('Both --reference <dir> and --candidate <dir> are required.');
|
|
26
|
+
}
|
|
27
|
+
const report = scorePackageParity(path.resolve(reference), path.resolve(candidate));
|
|
28
|
+
if (options.json === true) {
|
|
29
|
+
logger.log(JSON.stringify(report, null, 2));
|
|
30
|
+
} else {
|
|
31
|
+
logger.log(chalk.bold(`Package parity score: ${report.score}/${report.maxScore}`));
|
|
32
|
+
logger.log(chalk.gray(report.summary));
|
|
33
|
+
logger.log(chalk.gray(`Reference (score-only): ${report.referenceDir}`));
|
|
34
|
+
logger.log(chalk.gray(`Candidate: ${report.candidateDir}`));
|
|
35
|
+
for (const row of report.facets) {
|
|
36
|
+
const mark = row.ok ? chalk.green('✔') : chalk.red('✖');
|
|
37
|
+
logger.log(` ${mark} ${row.id}: ${row.detail}`);
|
|
38
|
+
}
|
|
39
|
+
if (report.goldIsScoreOnly) {
|
|
40
|
+
logger.log(chalk.yellow('Note: reference package is for scoring only — never use it as generation input.'));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return report.identical ? 0 : 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {import('commander').Command} program
|
|
48
|
+
*/
|
|
49
|
+
function setupPackageScoreCommand(program) {
|
|
50
|
+
program
|
|
51
|
+
.command('package-score')
|
|
52
|
+
.description(
|
|
53
|
+
'Score a candidate integration package directory against a reference package (score-only; not generation)'
|
|
54
|
+
)
|
|
55
|
+
.option('--reference <dir>', 'Reference integration package directory (score baseline only)')
|
|
56
|
+
.option('--candidate <dir>', 'Candidate integration package directory')
|
|
57
|
+
.option('--json', 'Emit structured JSON report', false)
|
|
58
|
+
.action(async(options) => {
|
|
59
|
+
try {
|
|
60
|
+
const code = await runPackageScoreCommand(options);
|
|
61
|
+
process.exitCode = code;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
logger.error(chalk.red(`Error: ${error.message}`));
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
setupPackageScoreCommand,
|
|
71
|
+
runPackageScoreCommand
|
|
72
|
+
};
|
|
@@ -50,6 +50,29 @@ const {
|
|
|
50
50
|
roleAssistantSystemKey
|
|
51
51
|
} = require('../utils/role-assistant-paths');
|
|
52
52
|
|
|
53
|
+
function roleAssistantGroupHelpAfter() {
|
|
54
|
+
return `
|
|
55
|
+
Subcommands:
|
|
56
|
+
test <roleKey> Run lifecycle checks, optional YAML cases/suites, and print a portal deep link
|
|
57
|
+
|
|
58
|
+
Package workspace (top-level commands — same digital-worker package):
|
|
59
|
+
download / validate / upload / deploy <roleKey> Manage role-assistant/ra-<roleKey>/
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
$ aifabrix role-assistant test customer-support-bot
|
|
63
|
+
$ aifabrix role-assistant test customer-support-bot --suite 001
|
|
64
|
+
$ aifabrix role-assistant test customer-support-bot --list-cases
|
|
65
|
+
$ aifabrix role-assistant test customer-support-bot --env tst --json
|
|
66
|
+
$ aifabrix upload customer-support-bot --env dev
|
|
67
|
+
$ aifabrix test ra-customer-support-bot
|
|
68
|
+
|
|
69
|
+
Notes:
|
|
70
|
+
- Local packages live under role-assistant/ra-<roleKey>/ (bare <roleKey> in CLI args).
|
|
71
|
+
- test uses the public/running worker by default; pass --publish (or upload) to refresh from local files.
|
|
72
|
+
- See: aifabrix role-assistant test -h
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
|
|
53
76
|
function roleAssistantHelpAfter() {
|
|
54
77
|
return `
|
|
55
78
|
Examples:
|
|
@@ -60,14 +83,16 @@ Examples:
|
|
|
60
83
|
$ aifabrix role-assistant test customer-support-bot --suite 001
|
|
61
84
|
$ aifabrix role-assistant test customer-support-bot --list-cases
|
|
62
85
|
$ aifabrix role-assistant test customer-support-bot --suite 001 --fail-fast --json
|
|
86
|
+
$ aifabrix test ra-customer-support-bot
|
|
63
87
|
|
|
64
88
|
Notes:
|
|
89
|
+
- <roleKey> is bare (e.g. customer-support-bot); package folder is role-assistant/ra-<roleKey>/.
|
|
65
90
|
- Uses the public/running Role Assistant on the dataplane by default (does not publish local datasources).
|
|
66
91
|
- Use \`aifabrix upload <roleKey> --env …\` (or \`--publish\`) when you intentionally refresh the package.
|
|
67
92
|
- Runs lifecycle checks, then prints a portal deep link for full step-by-step status.
|
|
68
93
|
- Case files with input.message/input.content execute Work Hub plan→accept (or work.start when executionPath: intent).
|
|
69
94
|
- answers[] and approvals[] are matched to runtime wait payloads (questionKey/requestKey/waitReason).
|
|
70
|
-
- --suite runs
|
|
95
|
+
- --suite runs YAML under role-assistant/ra-<roleKey>/tests/<suite>/ (preferred), or tests/ra-<roleKey>/<roleKey>/<suite>/, or legacy tests/role-assistant/ra-<roleKey>/<suite>/ (override with --cases-root).
|
|
71
96
|
- Use the portal URL for detailed human review while automation reads CLI/JSON output.
|
|
72
97
|
`;
|
|
73
98
|
}
|
|
@@ -163,13 +188,19 @@ function listRoleAssistantCases(roleKey, opts) {
|
|
|
163
188
|
}
|
|
164
189
|
|
|
165
190
|
async function resolveSuiteCaseResults(systemKey, opts, result, verdict, portalUrl) {
|
|
166
|
-
const
|
|
191
|
+
const cwd = process.cwd();
|
|
192
|
+
const root = resolveCasesRoot(systemKey, { casesRoot: opts.casesRoot || undefined, cwd });
|
|
167
193
|
const discovered = discoverSuiteCaseFiles(root, { suite: opts.suite || undefined });
|
|
168
194
|
const selected = filterDiscoveredCases(discovered, opts.case);
|
|
169
195
|
if (selected.length === 0) {
|
|
196
|
+
const { listCasesRootCandidates } = require('../role-assistant/test-suite');
|
|
197
|
+
const tried = opts.casesRoot
|
|
198
|
+
? [root]
|
|
199
|
+
: listCasesRootCandidates(systemKey, cwd);
|
|
170
200
|
throw new Error(
|
|
171
201
|
`No role-assistant cases found under ${root}` +
|
|
172
|
-
(opts.suite ? ` suite=${opts.suite}` : '')
|
|
202
|
+
(opts.suite ? ` suite=${opts.suite}` : '') +
|
|
203
|
+
`. Looked in: ${tried.join(', ')}`
|
|
173
204
|
);
|
|
174
205
|
}
|
|
175
206
|
const outcomes = [];
|
|
@@ -269,21 +300,26 @@ async function roleAssistantTestHandler(roleKey, options, cmd) {
|
|
|
269
300
|
function setupRoleAssistantCommands(program) {
|
|
270
301
|
const roleAssistant = program
|
|
271
302
|
.command('role-assistant')
|
|
272
|
-
.description(
|
|
303
|
+
.description(
|
|
304
|
+
'Role Assistant packages: lifecycle checks, YAML cases/suites, and portal deep links'
|
|
305
|
+
)
|
|
306
|
+
.addHelpText('after', roleAssistantGroupHelpAfter());
|
|
273
307
|
|
|
274
308
|
roleAssistant
|
|
275
309
|
.command('test <roleKey>')
|
|
276
|
-
.description(
|
|
310
|
+
.description(
|
|
311
|
+
'Lifecycle checks + optional cases/suites; prints portal deep link (bare <roleKey>)'
|
|
312
|
+
)
|
|
277
313
|
.option('-e, --env <env>', 'Environment: dev, tst, or pro', 'dev')
|
|
278
314
|
.option('--case <caseIdOrPath>', 'Run and evaluate one role-assistant test case')
|
|
279
315
|
.option('--tests-dir <dir>', 'Override role-assistant test case directory')
|
|
280
316
|
.option(
|
|
281
317
|
'--suite <suiteId>',
|
|
282
|
-
'Run all YAML
|
|
318
|
+
'Run all YAML under role-assistant/ra-<roleKey>/tests/<suiteId>/ (or tests/ra-<roleKey>/<roleKey>/<suiteId>/)'
|
|
283
319
|
)
|
|
284
320
|
.option(
|
|
285
321
|
'--cases-root <dir>',
|
|
286
|
-
'Override cases root (default: tests/
|
|
322
|
+
'Override cases root (default: package tests/, then tests/ra-<roleKey>/<roleKey>/)'
|
|
287
323
|
)
|
|
288
324
|
.option('--list-cases', 'List discoverable case files and exit')
|
|
289
325
|
.option('--fail-fast', 'Stop suite run after the first failing case')
|
|
@@ -326,5 +362,7 @@ module.exports = {
|
|
|
326
362
|
resolveRoleAssistantCaseResult,
|
|
327
363
|
resolveSuiteCaseResults,
|
|
328
364
|
listRoleAssistantCases,
|
|
329
|
-
formatStepsRunSummary
|
|
365
|
+
formatStepsRunSummary,
|
|
366
|
+
roleAssistantGroupHelpAfter,
|
|
367
|
+
roleAssistantHelpAfter
|
|
330
368
|
};
|
|
@@ -31,7 +31,7 @@ const { createDeployPollHandlers } = require('./deploy-poll-ui');
|
|
|
31
31
|
*/
|
|
32
32
|
async function pollDeploymentStatus(deploymentId, controllerUrl, envKey, authConfig, options = {}) {
|
|
33
33
|
const interval = options.interval || 5000;
|
|
34
|
-
const maxAttempts = options.maxAttempts ||
|
|
34
|
+
const maxAttempts = options.maxAttempts || 300;
|
|
35
35
|
|
|
36
36
|
const validatedEnvKey = validateEnvironmentKey(envKey);
|
|
37
37
|
const pipelineAuthConfig = convertToPipelineAuthConfig(authConfig);
|
|
@@ -74,7 +74,7 @@ async function pollDeployment(result, url, validatedEnvKey, authConfig, options)
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
const resolvedInterval = await resolvePollIntervalFromController(url, options.pollInterval);
|
|
77
|
-
const maxAttempts = options.pollMaxAttempts ||
|
|
77
|
+
const maxAttempts = options.pollMaxAttempts || 300;
|
|
78
78
|
const ownsPollUi = !options.pollUi;
|
|
79
79
|
const pollUi =
|
|
80
80
|
options.pollUi ||
|
|
@@ -387,7 +387,7 @@ async function deployToController(manifest, controllerUrl, envKey, authConfig, o
|
|
|
387
387
|
|
|
388
388
|
const usePollUi = options.poll !== false && options.silentPoll !== true;
|
|
389
389
|
const pollUi = usePollUi
|
|
390
|
-
? createDeployPollHandlers(options.pollMaxAttempts ||
|
|
390
|
+
? createDeployPollHandlers(options.pollMaxAttempts || 300, { silent: false })
|
|
391
391
|
: null;
|
|
392
392
|
const deployOpts = pollUi ? { ...options, pollUi } : options;
|
|
393
393
|
|
|
@@ -253,7 +253,7 @@ async function pollEnvironmentStatus(deploymentId, controllerUrl, envKey, authCo
|
|
|
253
253
|
const validatedUrl = validateControllerUrl(controllerUrl);
|
|
254
254
|
const validatedEnvKey = validateEnvironmentKey(envKey);
|
|
255
255
|
const pollInterval = options.pollInterval || 5000;
|
|
256
|
-
const maxAttempts = options.maxAttempts ||
|
|
256
|
+
const maxAttempts = options.maxAttempts || 300;
|
|
257
257
|
const apiAuthConfig = { type: 'bearer', token: authConfig.token };
|
|
258
258
|
|
|
259
259
|
logger.log(chalk.blue(`⏳ Polling environment status (${pollInterval}ms intervals)...`));
|
|
@@ -398,7 +398,7 @@ async function pollDeploymentStatusIfEnabled(result, validatedControllerUrl, env
|
|
|
398
398
|
authConfig,
|
|
399
399
|
{
|
|
400
400
|
pollInterval,
|
|
401
|
-
maxAttempts: options.pollMaxAttempts ||
|
|
401
|
+
maxAttempts: options.pollMaxAttempts || 300
|
|
402
402
|
}
|
|
403
403
|
);
|
|
404
404
|
result.status = pollResult.status;
|