@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.
- package/jest.isolated-projects.js +77 -1
- package/jest.projects.js +5 -426
- package/lib/api/assistants.api.js +67 -0
- package/lib/api/datasources-extended.api.js +6 -6
- package/lib/api/evidence-authoring-helpers.js +267 -0
- package/lib/api/evidence-authoring.api.js +337 -0
- package/lib/api/evidence.api.js +57 -1
- package/lib/api/index.js +24 -7
- package/lib/api/pipeline.api.js +43 -3
- package/lib/api/records-bulk.api.js +28 -3
- package/lib/api/types/evidence.types.js +156 -8
- package/lib/api/work.api.js +283 -0
- package/lib/app/run-container-start.js +4 -0
- package/lib/app/run-deploy-job.js +216 -0
- package/lib/app/run-env-compose.js +32 -0
- package/lib/app/run-env-recovery.js +35 -0
- package/lib/app/run-helpers.js +15 -9
- package/lib/app/run.js +18 -2
- package/lib/channels/add-channel.js +54 -23
- package/lib/channels/approval-guides/chatgpt.js +13 -9
- package/lib/channels/approval-guides/microsoft-copilot.js +7 -8
- package/lib/channels/channel-artifact-generator.js +14 -2
- package/lib/channels/channel-credential.js +3 -1
- package/lib/channels/channel-probe-evidence.js +79 -0
- package/lib/channels/channel-probe.js +265 -13
- package/lib/channels/channel-runtime-resolver.js +120 -29
- package/lib/channels/channel-status-display.js +44 -0
- package/lib/channels/channel-targets.js +25 -1
- package/lib/channels/chatgpt-runtime-contract.js +29 -0
- package/lib/channels/microsoft-copilot-package.js +280 -0
- package/lib/channels/runtime-tool-catalog.js +165 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/infra-guided-footers.js +1 -1
- package/lib/cli/infra-guided-public-url-warn.js +55 -0
- package/lib/cli/infra-guided.js +65 -56
- package/lib/cli/setup-app.help.js +4 -0
- package/lib/cli/setup-app.js +4 -0
- package/lib/cli/setup-app.test-commands.js +59 -28
- package/lib/cli/setup-external-system-help.js +8 -2
- package/lib/cli/setup-external-system.js +62 -12
- package/lib/commands/app-test.js +2 -14
- package/lib/commands/channel-add-setup.js +8 -2
- package/lib/commands/channel.js +16 -5
- package/lib/commands/datasource-load-export-cli.js +6 -1
- package/lib/commands/deploy-gate-failure-details.js +19 -17
- package/lib/commands/deploy-gate-orchestrator.js +3 -2
- package/lib/commands/dev-down.js +2 -6
- package/lib/commands/evidence-kind.js +65 -15
- package/lib/commands/governance-generate-external.js +56 -21
- package/lib/commands/governance-verify-external.js +2 -5
- package/lib/commands/lifecycle-external.js +21 -8
- package/lib/commands/repair-datasource-apply.js +10 -1
- package/lib/commands/repair-datasource-run.js +4 -2
- package/lib/commands/repair-datasource-test-payload.js +80 -19
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +42 -3
- package/lib/commands/repair-internal.js +9 -1
- package/lib/commands/repair-openapi-sync.js +34 -17
- package/lib/commands/role-assistant.js +371 -0
- package/lib/commands/test-governance-external.js +2 -5
- package/lib/commands/up-miso.js +61 -24
- package/lib/commands/upload-data-sync-finalize.js +25 -7
- package/lib/commands/upload-sidecar-followups.js +144 -47
- package/lib/commands/upload.js +43 -6
- package/lib/commands/verify-governance-combined-external.js +73 -9
- package/lib/commands/verify-governance-db.js +80 -25
- package/lib/commands/verify-governance-external.js +31 -10
- package/lib/commands/verify-operations-external.js +2 -5
- package/lib/commands/verify-operations-step-plan.js +31 -0
- package/lib/commands/verify-trust-command-action.js +2 -5
- package/lib/commands/wizard-core-helpers.js +7 -3
- package/lib/commands/wizard-core.js +78 -9
- package/lib/datasource/bulk-loader-run-batches.js +4 -2
- package/lib/datasource/bulk-loader-service.js +5 -1
- package/lib/datasource/datasource-identifier.js +4 -3
- package/lib/datasource/datasource-validate-summary.js +2 -2
- package/lib/datasource/integration-context.js +3 -3
- package/lib/datasource/resolve-app.js +90 -8
- package/lib/datasource/test-e2e.js +2 -2
- package/lib/datasource/unified-validation-run-body.js +15 -1
- package/lib/datasource/unified-validation-run-resolve.js +2 -2
- package/lib/datasource/validate.js +13 -6
- package/lib/external-system/deploy-helpers.js +39 -1
- package/lib/external-system/deploy.js +25 -11
- package/lib/external-system/download-helpers.js +111 -2
- package/lib/external-system/download-role-assistant.js +55 -0
- package/lib/external-system/download.js +45 -26
- package/lib/external-system/test-helpers.js +1 -1
- package/lib/external-system/test-system-level.js +21 -3
- package/lib/external-system/test.js +43 -7
- package/lib/generator/builders.js +12 -15
- package/lib/generator/wizard.js +51 -4
- package/lib/lifecycle/access-control-abac.js +121 -0
- package/lib/lifecycle/lifecycle-governance-options.js +4 -1
- package/lib/lifecycle/product-model.js +3 -2
- package/lib/lifecycle/report-display.js +14 -2
- package/lib/programmatic/capability-registry.js +20 -1
- package/lib/programmatic/command-options.js +1 -0
- package/lib/programmatic/index.js +4 -0
- package/lib/programmatic/manifest-patch-section.js +48 -9
- package/lib/programmatic/manifest-section-registry-data.js +3 -2
- package/lib/programmatic/openapi-apply-result-schemas.js +44 -0
- package/lib/programmatic/openapi-component-schemas.js +16 -1
- package/lib/programmatic/openapi-description-enricher.js +3 -1
- package/lib/programmatic/openapi-descriptions.js +55 -5
- package/lib/programmatic/openapi-evidence-schemas.js +161 -0
- package/lib/programmatic/openapi-manifest-schemas.js +6 -2
- package/lib/programmatic/openapi-operation-bindings.js +99 -0
- package/lib/programmatic/openapi-request-schemas.js +36 -1
- package/lib/programmatic/openapi-result-schemas.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-certify.js +5 -1
- package/lib/programmatic/openapi-schema-descriptions-core.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-evidence.js +156 -0
- package/lib/programmatic/openapi-schema-descriptions-manifest.js +4 -3
- package/lib/programmatic/openapi-schema-descriptions-operations.js +70 -0
- package/lib/programmatic/openapi-spec.js +47 -28
- package/lib/programmatic/orchestration-openapi-meta.js +5 -0
- package/lib/programmatic/request-timeout.js +3 -0
- package/lib/programmatic/route-handler-map.js +89 -2
- package/lib/programmatic/run-certify.js +15 -2
- package/lib/programmatic/run-deploy.js +74 -0
- package/lib/programmatic/run-evidence-authoring.js +80 -0
- package/lib/programmatic/run-protection.js +124 -0
- package/lib/programmatic/run-template-workspace.js +28 -1
- package/lib/programmatic/workspace-context.js +6 -0
- package/lib/protection/auth-context.js +48 -6
- package/lib/protection/paths.js +22 -0
- package/lib/protection/run-protection-create-helpers.js +22 -1
- package/lib/protection/run-protection-create.js +1 -1
- package/lib/protection/sync-after-upload.js +1 -1
- package/lib/role-assistant/evidence-sync.js +450 -0
- package/lib/role-assistant/github-workflow.js +96 -0
- package/lib/role-assistant/knowledge-markdown-frontmatter.js +75 -0
- package/lib/role-assistant/knowledge-sync.js +485 -0
- package/lib/role-assistant/settings.js +126 -0
- package/lib/role-assistant/test-cases-evaluate.js +170 -0
- package/lib/role-assistant/test-cases-honesty.js +184 -0
- package/lib/role-assistant/test-cases.js +364 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +221 -0
- package/lib/role-assistant/test-runner-workhub.js +399 -0
- package/lib/role-assistant/test-runner.js +500 -0
- package/lib/schema/application-schema.json +24 -28
- package/lib/schema/deployment-rules.yaml +1 -0
- package/lib/schema/external-datasource.schema.json +38 -4
- package/lib/schema/external-system.schema.json +4 -4
- package/lib/schema/role-assistant-settings.schema.json +108 -0
- package/lib/utils/api.js +52 -27
- package/lib/utils/app-path-resolve.js +72 -24
- package/lib/utils/authentication-shape.js +3 -1
- package/lib/utils/certify-external-workspace.js +40 -0
- package/lib/utils/deployment-validation.js +28 -3
- package/lib/utils/docker-run-ephemeral.js +115 -0
- package/lib/utils/enterprise-knowledge-paths.js +29 -12
- package/lib/utils/env-copy-keycloak.js +196 -0
- package/lib/utils/env-copy.js +34 -1
- package/lib/utils/external-system-readiness-compact-display.js +3 -0
- package/lib/utils/health-check-public-warn.js +31 -13
- package/lib/utils/health-check.js +11 -1
- package/lib/utils/help-builder.js +1 -0
- package/lib/utils/paths.js +80 -38
- package/lib/utils/pipeline-upload-auth-retry.js +15 -3
- package/lib/utils/role-assistant-paths.js +160 -0
- package/lib/utils/schema-loader.js +41 -0
- package/lib/utils/schema-resolver.js +36 -4
- package/lib/utils/token-manager.js +38 -29
- package/lib/utils/upload-sync-options.js +7 -4
- package/lib/utils/url-declarative-resolve-load-doc.js +38 -1
- package/lib/validation/external-manifest-validator.js +31 -8
- package/lib/validation/reserved-system-key-prefixes.js +56 -0
- package/lib/validation/validate-external-file.js +8 -1
- package/lib/validation/validate.js +54 -19
- package/package.json +2 -1
- package/scripts/export-builder-api-evidence.js +1 -1
- package/templates/applications/builder-api/application.yaml +3 -3
- package/templates/applications/dataplane/application.yaml +24 -17
- package/templates/applications/dataplane/env.template +2 -2
- package/templates/applications/dataplane/rbac.yaml +24 -10
- package/templates/applications/keycloak/application.yaml +2 -2
- package/templates/applications/keycloak/env.template +5 -2
- package/templates/applications/miso-controller/application.yaml +3 -3
- package/templates/applications/miso-controller/env.template +17 -2
- package/templates/channels/chatgpt/install.template.md.hbs +82 -26
- package/templates/channels/chatgpt/integration/README.md +11 -7
- package/templates/channels/chatgpt/integration/application.json +2 -2
- package/templates/channels/chatgpt/integration/chatgpt-system.json +3 -3
- package/templates/channels/chatgpt/integration/env.template +1 -1
- package/templates/channels/chatgpt/manifest.template.json.hbs +36 -5
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +28 -0
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +22 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +32 -22
- package/templates/channels/microsoft-copilot/integration/README.md +9 -7
- package/templates/channels/microsoft-copilot/integration/application.json +2 -2
- package/templates/channels/microsoft-copilot/integration/env.template +1 -1
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +7 -6
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -6
- package/templates/channels/slack/install.template.md.hbs +6 -1
- package/templates/python/docker-compose.hbs +10 -0
- package/templates/typescript/docker-compose.hbs +10 -0
- /package/.cursor/plans/{157.1-security-quality-violations-by-type.csv → Done/157.1-security-quality-violations-by-type.csv} +0 -0
package/lib/cli/infra-guided.js
CHANGED
|
@@ -8,8 +8,6 @@ const chalk = require('chalk');
|
|
|
8
8
|
const logger = require('../utils/logger');
|
|
9
9
|
const config = require('../core/config');
|
|
10
10
|
const devConfig = require('../utils/dev-config');
|
|
11
|
-
const pathsUtil = require('../utils/paths');
|
|
12
|
-
const { loadConfigFile } = require('../utils/config-format');
|
|
13
11
|
const { withMutedLogger } = require('../utils/with-muted-logger');
|
|
14
12
|
const infra = require('../infrastructure');
|
|
15
13
|
const { execWithDockerEnv } = require('../utils/docker-exec');
|
|
@@ -41,12 +39,72 @@ const {
|
|
|
41
39
|
logUpPlatformForceCleanSummary,
|
|
42
40
|
logStoppedServices
|
|
43
41
|
} = require('./infra-guided-footers');
|
|
44
|
-
const healthCheck = require('../utils/health-check');
|
|
45
42
|
const { prepareUrlsLocalRegistryForUpPlatform } = require('../commands/up-common');
|
|
46
43
|
const { assertDevInfraUp } = require('../commands/dev-infra-gate');
|
|
47
44
|
const {
|
|
48
45
|
emitSystemBuilderAppManifestLineIfTTY
|
|
49
46
|
} = require('../utils/manifest-source-emit');
|
|
47
|
+
const { flushDeferredPublicUrlWarnings } = require('./infra-guided-public-url-warn');
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Guided Keycloak → Miso Controller start with one spinner per app (no second health wait).
|
|
51
|
+
* @param {Object} options
|
|
52
|
+
* @param {Function} handleUpMiso
|
|
53
|
+
* @returns {Promise<string[]>} Deferred public-URL warning messages
|
|
54
|
+
*/
|
|
55
|
+
async function runGuidedKeycloakAndMisoControllerPhase(options, handleUpMiso) {
|
|
56
|
+
const deferredWarnings = [];
|
|
57
|
+
const misoSpinnerRef = { current: null };
|
|
58
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'keycloak');
|
|
59
|
+
const kcSpin = startSpinner('Starting Keycloak...');
|
|
60
|
+
// Fully mute inner run logs — any newline (✔ / Manifest / blank) splits the ora line.
|
|
61
|
+
await withMutedLogger(
|
|
62
|
+
() =>
|
|
63
|
+
handleUpMiso({
|
|
64
|
+
...options,
|
|
65
|
+
platformInstall: true,
|
|
66
|
+
onAfterKeycloak: () => {
|
|
67
|
+
stopSpinnerSuccess(kcSpin, 'Keycloak ready');
|
|
68
|
+
logger.log('');
|
|
69
|
+
emitSystemBuilderAppManifestLineIfTTY(logger, 'miso-controller');
|
|
70
|
+
misoSpinnerRef.current = startSpinner('Starting Miso Controller...');
|
|
71
|
+
},
|
|
72
|
+
onMisoPollText: (text) => {
|
|
73
|
+
const spin = misoSpinnerRef.current;
|
|
74
|
+
if (spin) {
|
|
75
|
+
// Keep app name; append health progress so the spinner does not look like a new step.
|
|
76
|
+
spin.text = `Starting Miso Controller… ${stripHealthPrefix(text)}`;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
logger.log(text);
|
|
80
|
+
},
|
|
81
|
+
onDeferredPublicUrlWarning: (message) => deferredWarnings.push(message)
|
|
82
|
+
}),
|
|
83
|
+
{ allow: () => false }
|
|
84
|
+
);
|
|
85
|
+
if (misoSpinnerRef.current) {
|
|
86
|
+
stopSpinnerSuccess(misoSpinnerRef.current, 'Miso Controller ready');
|
|
87
|
+
} else {
|
|
88
|
+
stopSpinnerSuccess(kcSpin, 'Keycloak ready');
|
|
89
|
+
}
|
|
90
|
+
flushDeferredPublicUrlWarnings(deferredWarnings);
|
|
91
|
+
logger.log('');
|
|
92
|
+
return deferredWarnings;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** ESC + CSI SGR — built without a control-char regex literal (no-control-regex). */
|
|
96
|
+
const ANSI_SGR_RE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, 'g');
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Turn "Waiting for health check… (4/45)" into "(4/45)" for nested spinner text.
|
|
100
|
+
* @param {string} text
|
|
101
|
+
* @returns {string}
|
|
102
|
+
*/
|
|
103
|
+
function stripHealthPrefix(text) {
|
|
104
|
+
const raw = String(text || '');
|
|
105
|
+
const match = raw.match(/\((\d+\/\d+)\)/);
|
|
106
|
+
return match ? `(${match[1]})` : raw.replace(ANSI_SGR_RE, '').trim();
|
|
107
|
+
}
|
|
50
108
|
|
|
51
109
|
async function getRunningContainerNameForApp(appName) {
|
|
52
110
|
const apps = await infra.getAppStatus();
|
|
@@ -86,31 +144,6 @@ async function validateAppErrorLogs(appNames) {
|
|
|
86
144
|
logger.log('');
|
|
87
145
|
}
|
|
88
146
|
|
|
89
|
-
async function waitForAppReady(appName, opts = {}) {
|
|
90
|
-
const timeoutSeconds = Number.isFinite(opts.timeoutSeconds) ? opts.timeoutSeconds : 90;
|
|
91
|
-
const builderPath = pathsUtil.getBuilderPath(appName);
|
|
92
|
-
const configPath = pathsUtil.resolveApplicationConfigPath(builderPath);
|
|
93
|
-
const appConfig = loadConfigFile(configPath) || {};
|
|
94
|
-
|
|
95
|
-
const apps = await infra.getAppStatus();
|
|
96
|
-
const hit = (apps || []).find(a => a && a.name === appName && typeof a.url === 'string');
|
|
97
|
-
const portMatch = hit && hit.url ? hit.url.match(/:(\d+)$/) : null;
|
|
98
|
-
const hostPort = portMatch ? parseInt(portMatch[1], 10) : null;
|
|
99
|
-
if (!hostPort) {
|
|
100
|
-
throw new Error(`Could not determine host port for ${appName}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const userCfg = await config.getConfig();
|
|
104
|
-
const healthRunOpts = { profile: 'docker' };
|
|
105
|
-
if (userCfg && userCfg.traefik === true) {
|
|
106
|
-
healthRunOpts.traefikEnabled = true;
|
|
107
|
-
}
|
|
108
|
-
if (typeof opts.onPollText === 'function') {
|
|
109
|
-
healthRunOpts.onPollText = opts.onPollText;
|
|
110
|
-
}
|
|
111
|
-
await healthCheck.waitForHealthCheck(appName, timeoutSeconds, hostPort, appConfig, false, healthRunOpts);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
147
|
function resolveInfraHost(remoteServer) {
|
|
115
148
|
const raw = String(remoteServer || '').trim().replace(/\/+$/, '');
|
|
116
149
|
if (!raw) return 'localhost';
|
|
@@ -179,16 +212,7 @@ async function runGuidedUpMiso(options, handleUpMiso) {
|
|
|
179
212
|
logger.log('');
|
|
180
213
|
logPlatformSetupDurationHint('platform');
|
|
181
214
|
logger.log('');
|
|
182
|
-
|
|
183
|
-
await withMutedLogger(() => handleUpMiso({ ...options, platformInstall: true }));
|
|
184
|
-
stopSpinnerSuccess(kcSpin, 'Keycloak ready');
|
|
185
|
-
logger.log('');
|
|
186
|
-
const mcSpin = startSpinner('Starting Miso Controller...');
|
|
187
|
-
await waitForAppReady('miso-controller', {
|
|
188
|
-
timeoutSeconds: 120,
|
|
189
|
-
onPollText: createSpinnerTextUpdater(mcSpin)
|
|
190
|
-
});
|
|
191
|
-
stopSpinnerSuccess(mcSpin, 'Miso Controller ready');
|
|
215
|
+
await runGuidedKeycloakAndMisoControllerPhase(options, handleUpMiso);
|
|
192
216
|
await logMisoReadyFooter();
|
|
193
217
|
await validateAppErrorLogs(['miso-controller']);
|
|
194
218
|
}
|
|
@@ -241,22 +265,6 @@ async function refreshDataplaneVersionAfterPlatformInstall() {
|
|
|
241
265
|
}
|
|
242
266
|
}
|
|
243
267
|
|
|
244
|
-
async function runGuidedKeycloakAndMisoControllerPhase(options, handleUpMiso) {
|
|
245
|
-
emitSystemBuilderAppManifestLineIfTTY(logger, 'keycloak');
|
|
246
|
-
const kcSpin = startSpinner('Starting Keycloak...');
|
|
247
|
-
await withMutedLogger(() => handleUpMiso({ ...options, platformInstall: true }));
|
|
248
|
-
stopSpinnerSuccess(kcSpin, 'Keycloak ready');
|
|
249
|
-
logger.log('');
|
|
250
|
-
emitSystemBuilderAppManifestLineIfTTY(logger, 'miso-controller');
|
|
251
|
-
const mcSpin = startSpinner('Starting Miso Controller...');
|
|
252
|
-
await waitForAppReady('miso-controller', {
|
|
253
|
-
timeoutSeconds: 120,
|
|
254
|
-
onPollText: createSpinnerTextUpdater(mcSpin)
|
|
255
|
-
});
|
|
256
|
-
stopSpinnerSuccess(mcSpin, 'Miso Controller ready');
|
|
257
|
-
logger.log('');
|
|
258
|
-
}
|
|
259
|
-
|
|
260
268
|
async function runGuidedDataplaneInstallPhase(options, handleUpDataplane, handleLoginFn, controllerUrl) {
|
|
261
269
|
logger.log('');
|
|
262
270
|
emitSystemBuilderAppManifestLineIfTTY(logger, 'dataplane');
|
|
@@ -310,7 +318,7 @@ async function runGuidedUpPlatform(options, handleUpMiso, handleUpDataplane, han
|
|
|
310
318
|
await runGuidedAuthStep(handleLogin, authOpts, { startSpinner, stopSpinnerSuccess });
|
|
311
319
|
const controllerUrl = await resolveGuidedAuthControllerUrl(authOpts);
|
|
312
320
|
await runGuidedDataplaneInstallPhase(options, handleUpDataplane, handleLogin, controllerUrl);
|
|
313
|
-
const baSpin = startSpinner('Starting
|
|
321
|
+
const baSpin = startSpinner('Starting Builder API...');
|
|
314
322
|
await withMutedLogger(() => handleUpBuilderApi({ ...options, platformInstall: true }));
|
|
315
323
|
stopSpinnerSuccess(baSpin, 'Builder API ready');
|
|
316
324
|
await validateAppErrorLogs(['miso-controller', 'dataplane', 'builder-api']);
|
|
@@ -353,5 +361,6 @@ module.exports = {
|
|
|
353
361
|
runGuidedUpMiso,
|
|
354
362
|
runGuidedUpDataplane,
|
|
355
363
|
runGuidedUpPlatform,
|
|
356
|
-
runGuidedDownInfra
|
|
364
|
+
runGuidedDownInfra,
|
|
365
|
+
stripHealthPrefix
|
|
357
366
|
};
|
|
@@ -11,6 +11,10 @@ Examples:
|
|
|
11
11
|
$ aifabrix test hubspot -v
|
|
12
12
|
$ aifabrix test hubspot -d
|
|
13
13
|
|
|
14
|
+
# Role Assistant (role-assistant/ra-<roleKey>/) — lifecycle checks
|
|
15
|
+
$ aifabrix test ra-business-transformation
|
|
16
|
+
$ aifabrix role-assistant test business-transformation
|
|
17
|
+
|
|
14
18
|
# Builder app (builder/<app>/) — runs in container
|
|
15
19
|
$ aifabrix test myapp -e dev
|
|
16
20
|
$ aifabrix test myapp -e tst
|
package/lib/cli/setup-app.js
CHANGED
|
@@ -56,12 +56,16 @@ Examples:
|
|
|
56
56
|
$ aifabrix validate hubspot-demo
|
|
57
57
|
$ aifabrix upload hubspot-demo --probe
|
|
58
58
|
$ aifabrix deploy hubspot-demo --probe -v
|
|
59
|
+
# Prove pillars in tst/CI, then promote (plain deploy seals cert on published Deploy)
|
|
59
60
|
$ aifabrix deploy ek-sales --gate full --subject-email ops@example.com
|
|
61
|
+
$ aifabrix deploy ek-sales
|
|
60
62
|
|
|
61
63
|
Notes:
|
|
62
64
|
- Login or set MISO_CONTROLLER_URL + environment (aifabrix login / aifabrix auth).
|
|
63
65
|
- CI: register once (aifabrix app register <appKey>), store DEV_MISO_CLIENTID and DEV_MISO_CLIENTSECRET in pipeline secrets.
|
|
64
66
|
- upload = dataplane publish for dev iteration; deploy = controller validate + deploy (Azure or local Docker).
|
|
67
|
+
- Prove (tst/CI): use --gate full (optional --subject-email) before promote; plain deploy promotes without live E2E gates.
|
|
68
|
+
- After a successful published Deploy, the platform seals the integration certificate (no separate certificates issue step).
|
|
65
69
|
- Default output is a compact status card; use -v for expanded preflight and readiness detail.
|
|
66
70
|
- Controller deploy always polls to a terminal status (no --poll / --no-poll on this command).
|
|
67
71
|
- --repository-url overrides repo URL for pipeline validate (default: application.yaml repository.repositoryUrl).
|
|
@@ -12,9 +12,56 @@ const {
|
|
|
12
12
|
TEST_E2E_HELP_AFTER
|
|
13
13
|
} = require('./setup-app.help');
|
|
14
14
|
|
|
15
|
+
/** External packages that use local unit validation (not builder container tests). */
|
|
16
|
+
function isExternalUnitTestWorkspace(baseDir) {
|
|
17
|
+
return baseDir === 'integration' || baseDir === 'enterprise-knowledge';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Dispatch aifabrix test by detected workspace (builder / integration / role-assistant).
|
|
22
|
+
* @param {string} appName
|
|
23
|
+
* @param {Object} options
|
|
24
|
+
* @param {Object} cmd
|
|
25
|
+
* @returns {Promise<void>}
|
|
26
|
+
*/
|
|
27
|
+
async function runTestCommandAction(appName, options, cmd) {
|
|
28
|
+
const rawArgs = Array.isArray(cmd?.rawArgs) ? cmd.rawArgs : [];
|
|
29
|
+
const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
|
|
30
|
+
const pathsUtil = require('../utils/paths');
|
|
31
|
+
const appType = await pathsUtil.detectAppType(appName).catch(() => null);
|
|
32
|
+
if (options.sync === true) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
'Option --sync is not supported for aifabrix test (local or container runs do not publish to the dataplane). ' +
|
|
35
|
+
'Use: aifabrix upload <systemKey>, then aifabrix test-integration <systemKey> --sync or aifabrix datasource test-integration <datasourceKey> --sync.'
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
if (appType && appType.baseDir === 'role-assistant') {
|
|
39
|
+
const { runRoleAssistantTestAction } = require('../commands/role-assistant');
|
|
40
|
+
await runRoleAssistantTestAction(appName, options, cmd);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (appType && isExternalUnitTestWorkspace(appType.baseDir)) {
|
|
44
|
+
const test = require('../external-system/test');
|
|
45
|
+
const externalOpts = {
|
|
46
|
+
...options,
|
|
47
|
+
// Keep help default but don't override auth/env behavior unless user explicitly set it.
|
|
48
|
+
env: envExplicit ? options.env : undefined
|
|
49
|
+
};
|
|
50
|
+
const results = await test.testExternalSystem(appName, externalOpts);
|
|
51
|
+
test.displayTestResults(results, options.verbose, appName);
|
|
52
|
+
if (!results.valid) process.exit(1);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const { runAppTest } = require('../commands/app-test');
|
|
56
|
+
await runAppTest(appName, { env: options.env });
|
|
57
|
+
}
|
|
58
|
+
|
|
15
59
|
function setupTestCommand(program) {
|
|
16
60
|
program.command('test <appKey|systemKey>')
|
|
17
|
-
.description(
|
|
61
|
+
.description(
|
|
62
|
+
'Tests: builder appKey in container; integration/EK = local validation; ' +
|
|
63
|
+
'role-assistant = lifecycle (same as role-assistant test)'
|
|
64
|
+
)
|
|
18
65
|
.option('-e, --env <env>', 'For builder app: dev (running container) or tst (ephemeral)', 'dev')
|
|
19
66
|
.option('-v, --verbose', 'Verbose output')
|
|
20
67
|
.option('-d, --debug', 'Certification debug + log to integration/<systemKey>/logs/ (external only)')
|
|
@@ -25,30 +72,7 @@ function setupTestCommand(program) {
|
|
|
25
72
|
.addHelpText('after', TEST_HELP_AFTER)
|
|
26
73
|
.action(async(appName, options, cmd) => {
|
|
27
74
|
try {
|
|
28
|
-
|
|
29
|
-
const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
|
|
30
|
-
const pathsUtil = require('../utils/paths');
|
|
31
|
-
const appType = await pathsUtil.detectAppType(appName).catch(() => null);
|
|
32
|
-
if (options.sync === true) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
'Option --sync is not supported for aifabrix test (local or container runs do not publish to the dataplane). ' +
|
|
35
|
-
'Use: aifabrix upload <systemKey>, then aifabrix test-integration <systemKey> --sync or aifabrix datasource test-integration <datasourceKey> --sync.'
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
if (appType && appType.baseDir === 'integration') {
|
|
39
|
-
const test = require('../external-system/test');
|
|
40
|
-
const externalOpts = {
|
|
41
|
-
...options,
|
|
42
|
-
// Keep help default but don't override auth/env behavior unless user explicitly set it.
|
|
43
|
-
env: envExplicit ? options.env : undefined
|
|
44
|
-
};
|
|
45
|
-
const results = await test.testExternalSystem(appName, externalOpts);
|
|
46
|
-
test.displayTestResults(results, options.verbose, appName);
|
|
47
|
-
if (!results.valid) process.exit(1);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const { runAppTest } = require('../commands/app-test');
|
|
51
|
-
await runAppTest(appName, { env: options.env });
|
|
75
|
+
await runTestCommandAction(appName, options, cmd);
|
|
52
76
|
} catch (error) {
|
|
53
77
|
handleCommandError(error, 'test');
|
|
54
78
|
process.exit(1);
|
|
@@ -106,7 +130,14 @@ async function runTestE2ECommand(appName, options, cmd) {
|
|
|
106
130
|
'Remove --no-publish for builder app E2E.'
|
|
107
131
|
);
|
|
108
132
|
}
|
|
109
|
-
if (appType && appType.baseDir === '
|
|
133
|
+
if (appType && appType.baseDir === 'role-assistant') {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`'${appName}' is a Role Assistant under role-assistant/. ` +
|
|
136
|
+
'Datasource E2E does not apply. Use: aifabrix role-assistant test <roleKey> ' +
|
|
137
|
+
'(or: aifabrix test <roleKey>).'
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
if (appType && isExternalUnitTestWorkspace(appType.baseDir)) {
|
|
110
141
|
await runExternalIntegrationE2EAndExit(appName, options, cmd);
|
|
111
142
|
return;
|
|
112
143
|
}
|
|
@@ -122,7 +153,7 @@ function setupInstallCommand(program) {
|
|
|
122
153
|
try {
|
|
123
154
|
const pathsUtil = require('../utils/paths');
|
|
124
155
|
const appType = await pathsUtil.detectAppType(appName).catch(() => null);
|
|
125
|
-
if (appType && appType.baseDir === '
|
|
156
|
+
if (appType && (isExternalUnitTestWorkspace(appType.baseDir) || appType.baseDir === 'role-assistant')) {
|
|
126
157
|
logger.log(
|
|
127
158
|
chalk.gray('Install is for builder appKey only. Use aifabrix shell <appKey> for builder apps or External Systems commands for integrations.')
|
|
128
159
|
);
|
|
@@ -186,7 +217,7 @@ function setupLintCommand(program) {
|
|
|
186
217
|
try {
|
|
187
218
|
const pathsUtil = require('../utils/paths');
|
|
188
219
|
const appType = await pathsUtil.detectAppType(appName).catch(() => null);
|
|
189
|
-
if (appType && appType.baseDir === '
|
|
220
|
+
if (appType && (isExternalUnitTestWorkspace(appType.baseDir) || appType.baseDir === 'role-assistant')) {
|
|
190
221
|
logger.log(chalk.gray('lint is for builder appKey only. Use aifabrix shell <appKey> then make lint or pnpm lint.'));
|
|
191
222
|
return;
|
|
192
223
|
}
|
|
@@ -10,6 +10,7 @@ Examples:
|
|
|
10
10
|
$ aifabrix upload hubspot-demo
|
|
11
11
|
$ aifabrix upload hubspot-demo -v
|
|
12
12
|
$ aifabrix upload hubspot-demo --probe
|
|
13
|
+
$ aifabrix upload hubspot-demo --timeout 600000
|
|
13
14
|
|
|
14
15
|
# Build and validate payload only (no API calls)
|
|
15
16
|
$ aifabrix upload hubspot-demo --dry-run
|
|
@@ -18,11 +19,16 @@ Examples:
|
|
|
18
19
|
$ aifabrix upload .protection
|
|
19
20
|
$ aifabrix upload .protection --warnings-as-errors
|
|
20
21
|
|
|
22
|
+
# Role Assistant package (settings section + Evidence sidecars)
|
|
23
|
+
$ aifabrix upload sales-representative --env dev
|
|
24
|
+
|
|
21
25
|
Notes:
|
|
22
26
|
- Requires login (aifabrix auth status).
|
|
23
|
-
- Reads files under integration/<systemKey>/
|
|
27
|
+
- Reads files under integration/<systemKey>/ or role-assistant/<roleKey>/ for digital workers.
|
|
24
28
|
- Default output is a compact readiness summary; use -v for expanded detail and server-side validate warnings.
|
|
25
|
-
- --probe runs dataplane runtime checks after publish (slower
|
|
29
|
+
- --probe runs dataplane runtime checks after publish (slower).
|
|
30
|
+
- --timeout sets publish budget in ms (HTTP client and dataplane); default 300000.
|
|
31
|
+
- --env selects role-assistant.yaml section (dev|tst|pro) for digital workers; default dev.
|
|
26
32
|
- test-e2e and test-integration publish local files first by default; use --no-publish on those commands to skip.
|
|
27
33
|
- After dimension/FK edits on active datasources, use --force (or test-e2e / test-integration / datasource test-* with --sync --force).
|
|
28
34
|
- For one datasource only: aifabrix datasource upload <datasourceKey>
|
|
@@ -45,13 +45,16 @@ async function handleUploadCommandAction(systemKey, options) {
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
const upload = require('../commands/upload');
|
|
48
|
+
const { resolvePipelineUploadTimeoutMs } = require('../api/pipeline.api');
|
|
48
49
|
const probeTimeout =
|
|
49
50
|
options.probeTimeout === undefined || options.probeTimeout === null
|
|
50
51
|
? 120000
|
|
51
52
|
: Number(options.probeTimeout);
|
|
53
|
+
const timeoutMs = resolvePipelineUploadTimeoutMs(options.timeout);
|
|
52
54
|
await upload.uploadExternalSystem(systemKey, {
|
|
53
55
|
...options,
|
|
54
56
|
probeTimeout: Number.isFinite(probeTimeout) ? probeTimeout : 120000,
|
|
57
|
+
timeoutMs,
|
|
55
58
|
pathOptions: {}
|
|
56
59
|
});
|
|
57
60
|
}
|
|
@@ -98,10 +101,19 @@ function setupUploadCommand(program) {
|
|
|
98
101
|
.option('-v, --verbose', 'Expanded upload summary and server-side pipeline validate warnings before publish')
|
|
99
102
|
.option('--probe', 'After publish, run dataplane runtime checks (validation/run); slower')
|
|
100
103
|
.option('--probe-timeout <ms>', 'Timeout for --probe (default: 120000)', '120000')
|
|
104
|
+
.option(
|
|
105
|
+
'--timeout <ms>',
|
|
106
|
+
'Publish timeout in ms for HTTP and dataplane budget (default: 300000; min 5000, max 2700000)'
|
|
107
|
+
)
|
|
101
108
|
.option(
|
|
102
109
|
'--force',
|
|
103
110
|
'Bypass schema guards on active datasources during publish (dangerous; shows a warning)'
|
|
104
111
|
)
|
|
112
|
+
.option(
|
|
113
|
+
'-e, --env <env>',
|
|
114
|
+
'Role Assistant settings environment section: dev, tst, or pro (default: dev)',
|
|
115
|
+
'dev'
|
|
116
|
+
)
|
|
105
117
|
.action(async(systemKey, options) => {
|
|
106
118
|
try {
|
|
107
119
|
await handleUploadCommandAction(systemKey, options);
|
|
@@ -147,10 +159,44 @@ function setupDeleteCommand(program) {
|
|
|
147
159
|
* @param {Object} options - CLI options
|
|
148
160
|
* @returns {Promise<boolean>} True if builder test was run, false otherwise
|
|
149
161
|
*/
|
|
150
|
-
|
|
162
|
+
/**
|
|
163
|
+
* @param {string} appName
|
|
164
|
+
* @param {Object} options
|
|
165
|
+
* @returns {Promise<boolean>} True if a builder-app integration test was started
|
|
166
|
+
*/
|
|
167
|
+
async function tryRunBuilderAppIntegration(appName, options) {
|
|
151
168
|
const fsSync = require('fs');
|
|
169
|
+
const { getBuilderPath } = require('../utils/paths');
|
|
170
|
+
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
171
|
+
const builderPath = getBuilderPath(appName);
|
|
172
|
+
if (!fsSync.existsSync(builderPath)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
let builderConfigPath;
|
|
176
|
+
try {
|
|
177
|
+
builderConfigPath = resolveApplicationConfigPath(builderPath);
|
|
178
|
+
} catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
if (!fsSync.existsSync(builderConfigPath)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const { runAppTestIntegration } = require('../commands/app-test');
|
|
185
|
+
await runAppTestIntegration(appName, {
|
|
186
|
+
env: options.env || options.environment || 'dev'
|
|
187
|
+
});
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Prefer builder-app container tests when no externalIntegration folder exists.
|
|
193
|
+
* @param {string} appName - App or system key
|
|
194
|
+
* @param {Object} options - CLI options
|
|
195
|
+
* @returns {Promise<boolean>} True if builder test was run, false otherwise
|
|
196
|
+
*/
|
|
197
|
+
async function tryBuilderTestIntegration(appName, options) {
|
|
152
198
|
const pathsUtil = require('../utils/paths');
|
|
153
|
-
const { getIntegrationPath
|
|
199
|
+
const { getIntegrationPath } = pathsUtil;
|
|
154
200
|
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
155
201
|
const { loadConfigFile } = require('../utils/config-format');
|
|
156
202
|
const integrationPath = getIntegrationPath(appName);
|
|
@@ -161,17 +207,10 @@ async function tryBuilderTestIntegration(appName, options) {
|
|
|
161
207
|
} catch {
|
|
162
208
|
// integration path or config missing
|
|
163
209
|
}
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
const builderConfigPath = resolveApplicationConfigPath(builderPath);
|
|
167
|
-
if (fsSync.existsSync(builderPath) && fsSync.existsSync(builderConfigPath)) {
|
|
168
|
-
const { runAppTestIntegration } = require('../commands/app-test');
|
|
169
|
-
const opts = { env: options.env || options.environment || 'dev' };
|
|
170
|
-
await runAppTestIntegration(appName, opts);
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
210
|
+
if (hasExternalIntegration) {
|
|
211
|
+
return false;
|
|
173
212
|
}
|
|
174
|
-
return
|
|
213
|
+
return tryRunBuilderAppIntegration(appName, options);
|
|
175
214
|
}
|
|
176
215
|
|
|
177
216
|
/**
|
|
@@ -221,6 +260,17 @@ async function runTestIntegrationCommand(appName, options) {
|
|
|
221
260
|
await runAppTestIntegration(appName, opts);
|
|
222
261
|
return;
|
|
223
262
|
}
|
|
263
|
+
// Role Assistant / EK / integration packages must use the dataplane path — do not
|
|
264
|
+
// probe builder/<app> (resolveApplicationConfigPath throws when the folder is absent).
|
|
265
|
+
if (
|
|
266
|
+
appType &&
|
|
267
|
+
(appType.baseDir === 'role-assistant' ||
|
|
268
|
+
appType.baseDir === 'enterprise-knowledge' ||
|
|
269
|
+
appType.baseDir === 'integration')
|
|
270
|
+
) {
|
|
271
|
+
await runExternalSystemTestIntegration(appName, options);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
224
274
|
const ranBuilder = await tryBuilderTestIntegration(appName, options);
|
|
225
275
|
if (ranBuilder) {
|
|
226
276
|
if (options.sync === true) {
|
package/lib/commands/app-test.js
CHANGED
|
@@ -166,20 +166,8 @@ async function runDockerExec(containerName, testCmd, envFilePath = null) {
|
|
|
166
166
|
* @returns {Promise<number>} Exit code
|
|
167
167
|
*/
|
|
168
168
|
async function runDockerRunEphemeral(fullImage, testCmd, envFilePath = null) {
|
|
169
|
-
const {
|
|
170
|
-
|
|
171
|
-
return new Promise((resolve) => {
|
|
172
|
-
const args = ['run', '--rm'];
|
|
173
|
-
if (envFilePath) args.push('--env-file', envFilePath);
|
|
174
|
-
args.push(fullImage, 'sh', '-c', testCmd);
|
|
175
|
-
const proc = spawn('docker', args, {
|
|
176
|
-
stdio: 'inherit',
|
|
177
|
-
shell: false,
|
|
178
|
-
env: dockerEnv
|
|
179
|
-
});
|
|
180
|
-
proc.on('close', code => resolve(code !== null ? code : 1));
|
|
181
|
-
proc.on('error', () => resolve(1));
|
|
182
|
-
});
|
|
169
|
+
const { runDockerRunEphemeral: runEphemeral } = require('../utils/docker-run-ephemeral');
|
|
170
|
+
return runEphemeral(fullImage, testCmd, envFilePath);
|
|
183
171
|
}
|
|
184
172
|
|
|
185
173
|
/**
|
|
@@ -9,15 +9,21 @@
|
|
|
9
9
|
const chalk = require('chalk');
|
|
10
10
|
const logger = require('../utils/logger');
|
|
11
11
|
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
formatSupportedChannelTargetsHelp,
|
|
14
|
+
isChannelTargetKey
|
|
15
|
+
} = require('../channels/channel-targets');
|
|
13
16
|
const { addChannelCommand } = require('../channels/add-channel');
|
|
14
17
|
|
|
15
18
|
const CHANNEL_ADD_HELP_AFTER = `
|
|
19
|
+
${formatSupportedChannelTargetsHelp()}
|
|
16
20
|
|
|
17
21
|
Examples:
|
|
18
22
|
# After upload/deploy of the communication external system
|
|
19
23
|
$ aifabrix channel add slack --name "Elsa"
|
|
20
24
|
$ aifabrix channel add teams-bot --name "Elsa" --description "Enterprise AI assistant for employees"
|
|
25
|
+
$ aifabrix channel add chatgpt --name "Your Assistant"
|
|
26
|
+
$ aifabrix channel add microsoft-copilot --name "Your Assistant"
|
|
21
27
|
|
|
22
28
|
# Slack slash-command prefix (registers /{prefix}-help in manifest)
|
|
23
29
|
$ aifabrix channel add slack --name "Elsa" --command-prefix af
|
|
@@ -49,7 +55,7 @@ async function runChannelAddAction(channelTarget, options, meta = {}) {
|
|
|
49
55
|
}
|
|
50
56
|
if (!isChannelTargetKey(channelTarget)) {
|
|
51
57
|
throw new Error(
|
|
52
|
-
`Unknown channel target "${channelTarget}".
|
|
58
|
+
`Unknown channel target "${channelTarget}". ${formatSupportedChannelTargetsHelp()}`
|
|
53
59
|
);
|
|
54
60
|
}
|
|
55
61
|
await addChannelCommand(channelTarget, {
|
package/lib/commands/channel.js
CHANGED
|
@@ -16,7 +16,10 @@ const {
|
|
|
16
16
|
sectionTitle,
|
|
17
17
|
metadata
|
|
18
18
|
} = require('../utils/cli-test-layout-chalk');
|
|
19
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
formatSupportedChannelTargetsHelp,
|
|
21
|
+
isChannelTargetKey
|
|
22
|
+
} = require('../channels/channel-targets');
|
|
20
23
|
const { scaffoldChannelIntegration } = require('../channels/channel-integration-generator');
|
|
21
24
|
const { registerChannelAddCommand } = require('./channel-add-setup');
|
|
22
25
|
|
|
@@ -25,9 +28,7 @@ Subcommands:
|
|
|
25
28
|
scaffold <target> Create integration/<target>/ files locally (step 1)
|
|
26
29
|
add <target> Channel install guide + manifest/credential patch (step 3)
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
teams-bot, slack, microsoft-copilot, chatgpt
|
|
30
|
-
web-embed (experimental — scaffold with --allow-experimental)
|
|
31
|
+
${formatSupportedChannelTargetsHelp()}
|
|
31
32
|
|
|
32
33
|
Typical flow (channels are connected systems, not controller apps):
|
|
33
34
|
aifabrix channel scaffold slack
|
|
@@ -39,6 +40,15 @@ Controller pipeline apps only: aifabrix app register · aifabrix app list
|
|
|
39
40
|
Requires: aifabrix login (for add)
|
|
40
41
|
`;
|
|
41
42
|
|
|
43
|
+
const CHANNEL_SCAFFOLD_HELP_AFTER = `
|
|
44
|
+
${formatSupportedChannelTargetsHelp()}
|
|
45
|
+
|
|
46
|
+
Typical flow:
|
|
47
|
+
aifabrix channel scaffold slack
|
|
48
|
+
aifabrix upload slack --force
|
|
49
|
+
aifabrix channel add slack --name "Your Assistant" --probe
|
|
50
|
+
`;
|
|
51
|
+
|
|
42
52
|
/**
|
|
43
53
|
* @param {import('commander').Command} program
|
|
44
54
|
*/
|
|
@@ -57,11 +67,12 @@ function setupChannelCommands(program) {
|
|
|
57
67
|
)
|
|
58
68
|
.option('--force', 'Overwrite generated scaffold files when folder exists')
|
|
59
69
|
.option('--allow-experimental', 'Allow web-embed scaffold')
|
|
70
|
+
.addHelpText('after', CHANNEL_SCAFFOLD_HELP_AFTER)
|
|
60
71
|
.action(async(channelTarget, options) => {
|
|
61
72
|
try {
|
|
62
73
|
if (!isChannelTargetKey(channelTarget)) {
|
|
63
74
|
throw new Error(
|
|
64
|
-
`Unknown channel target "${channelTarget}".
|
|
75
|
+
`Unknown channel target "${channelTarget}". ${formatSupportedChannelTargetsHelp()}`
|
|
65
76
|
);
|
|
66
77
|
}
|
|
67
78
|
const result = await scaffoldChannelIntegration(channelTarget, {
|
|
@@ -76,7 +76,8 @@ async function datasourceLoadAction(datasourceKey, options) {
|
|
|
76
76
|
dryRun: options.dryRun,
|
|
77
77
|
batchSize: options.batchSize,
|
|
78
78
|
syncType: options.syncType,
|
|
79
|
-
format: options.format
|
|
79
|
+
format: options.format,
|
|
80
|
+
timeoutMs: options.timeout
|
|
80
81
|
});
|
|
81
82
|
|
|
82
83
|
if (options.json) {
|
|
@@ -141,6 +142,10 @@ function setupDatasourceLoadExportCommands(datasource) {
|
|
|
141
142
|
'Dataplane syncType',
|
|
142
143
|
'incremental'
|
|
143
144
|
)
|
|
145
|
+
.option(
|
|
146
|
+
'--timeout <ms>',
|
|
147
|
+
'Per-batch HTTP timeout for records/bulk (default 120000)'
|
|
148
|
+
)
|
|
144
149
|
.option('--dry-run', 'Parse and validate only; no upload')
|
|
145
150
|
.option('-v, --verbose', 'Per-batch progress')
|
|
146
151
|
.option('--json', 'Machine-readable result JSON')
|
|
@@ -113,6 +113,24 @@ function formatOperationsGateFailure(result) {
|
|
|
113
113
|
return 'E2E validation did not succeed for one or more datasources';
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @param {Object} row
|
|
118
|
+
* @returns {string|null}
|
|
119
|
+
*/
|
|
120
|
+
function formatFailedDatasourceRowHint(row) {
|
|
121
|
+
if (!row || row.success !== false) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const key = row.key || row.datasourceKey || 'datasource';
|
|
125
|
+
const issues = row.datasourceTestRun?.validation?.issues;
|
|
126
|
+
if (Array.isArray(issues) && issues.length > 0) {
|
|
127
|
+
const first = issues[0];
|
|
128
|
+
const code = first.code ? `${first.code}: ` : '';
|
|
129
|
+
return `${key}: ${code}${first.message || 'validation failed'}`;
|
|
130
|
+
}
|
|
131
|
+
return row.error ? `${key}: ${row.error}` : null;
|
|
132
|
+
}
|
|
133
|
+
|
|
116
134
|
/**
|
|
117
135
|
* @param {Object} result
|
|
118
136
|
* @returns {string}
|
|
@@ -125,23 +143,7 @@ function formatIntegrationGateFailure(result) {
|
|
|
125
143
|
return String(result.message);
|
|
126
144
|
}
|
|
127
145
|
const rows = Array.isArray(result?.datasourceResults) ? result.datasourceResults : [];
|
|
128
|
-
const hints =
|
|
129
|
-
for (const row of rows) {
|
|
130
|
-
if (!row || row.success !== false) {
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const key = row.key || row.datasourceKey || 'datasource';
|
|
134
|
-
const issues = row.datasourceTestRun?.validation?.issues;
|
|
135
|
-
if (Array.isArray(issues) && issues.length > 0) {
|
|
136
|
-
const first = issues[0];
|
|
137
|
-
const code = first.code ? `${first.code}: ` : '';
|
|
138
|
-
hints.push(`${key}: ${code}${first.message || 'validation failed'}`);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (row.error) {
|
|
142
|
-
hints.push(`${key}: ${row.error}`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
146
|
+
const hints = rows.map(formatFailedDatasourceRowHint).filter(Boolean);
|
|
145
147
|
if (hints.length > 0) {
|
|
146
148
|
return hints.slice(0, 3).join('; ');
|
|
147
149
|
}
|
|
@@ -142,7 +142,6 @@ async function runDeployBaselineSteps(systemKey, options) {
|
|
|
142
142
|
uploadStatus: 'published',
|
|
143
143
|
minimal: true,
|
|
144
144
|
suppressSummary: true,
|
|
145
|
-
suppressPipelineSpinner: true,
|
|
146
145
|
uploadContext: 'deploy-preflight'
|
|
147
146
|
});
|
|
148
147
|
stepOptions = mergeUploadAuthOptions({ ...options, uploadStatus: 'published' }, uploadCtx);
|
|
@@ -322,7 +321,9 @@ function inferGatePillarFromLabel(label) {
|
|
|
322
321
|
* @returns {Promise<{ baseline: { unitPassed: boolean, integrationPassed: boolean }, gates: Object[] }>}
|
|
323
322
|
*/
|
|
324
323
|
async function runDeployGateOrchestrator(systemKey, options = {}) {
|
|
325
|
-
|
|
324
|
+
// Default: show unit/integration/publish progress (parity with upload).
|
|
325
|
+
// Only hush when caller opts in (json / explicit quietDeployUi).
|
|
326
|
+
const quiet = options.quietDeployUi === true;
|
|
326
327
|
if (!quiet) {
|
|
327
328
|
logger.log('');
|
|
328
329
|
logger.log(sectionTitle('Deploy preflight'));
|