@aifabrix/builder 2.46.0 → 2.47.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/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/jest.isolated-projects.js +18 -2
- package/jest.projects.js +24 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/lifecycle.api.js +22 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/down.js +58 -26
- package/lib/app/index.js +2 -2
- package/lib/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +17 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +18 -4
- package/lib/cli/infra-guided-auth.js +36 -12
- package/lib/cli/setup-app.js +54 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- package/lib/cli/setup-npm.js +59 -0
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-secrets.js +1 -1
- package/lib/cli/setup-utility-help-after.js +4 -1
- package/lib/cli/setup-utility-resolve.js +8 -5
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-dataplane-version.js +97 -61
- package/lib/commands/auth-status.js +2 -7
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource.js +1 -1
- package/lib/commands/identity-apply-sync.js +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/login-device.js +11 -3
- package/lib/commands/login.js +8 -3
- package/lib/commands/npm-config.js +103 -0
- package/lib/commands/repair-auth-apply.js +30 -4
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource.js +53 -18
- package/lib/commands/repair-env-template.js +12 -12
- package/lib/commands/repair-openapi-sync.js +26 -4
- package/lib/commands/repair-steps.js +28 -13
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/resource-type.js +371 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/setup-prompts-platform-mode.js +24 -21
- package/lib/commands/test-trust-external.js +39 -90
- package/lib/commands/up-common.js +33 -1
- package/lib/commands/up-dataplane.js +8 -4
- package/lib/commands/upload.js +24 -3
- package/lib/commands/verify-trust-command-action.js +4 -1
- package/lib/commands/verify-trust-external.js +12 -20
- package/lib/core/config-setup-platform-mode.js +3 -3
- package/lib/core/setup-platform-mode.js +41 -6
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/validate.js +41 -23
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +61 -122
- package/lib/external-system/generator.js +1 -59
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +5 -2
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -0
- package/lib/lifecycle/certification-progress.js +2 -2
- package/lib/lifecycle/report-display-trust.js +70 -0
- package/lib/lifecycle/report-display.js +14 -13
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +16 -0
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +372 -58
- package/lib/schema/external-system.schema.json +331 -2
- package/lib/schema/type/document-storage.json +9 -5
- package/lib/utils/api.js +2 -1
- package/lib/utils/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-utils.js +4 -0
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +9 -1
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/controller-url.js +4 -1
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +52 -262
- package/lib/utils/dataplane-resolver.js +4 -115
- package/lib/utils/declarative-url-ports.js +24 -1
- package/lib/utils/dev-platform-tls.js +148 -0
- package/lib/utils/docker-build.js +1 -4
- package/lib/utils/external-env-template.js +10 -3
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/health-check-request.js +114 -0
- package/lib/utils/health-check-url.js +3 -1
- package/lib/utils/health-check.js +1 -113
- package/lib/utils/help-builder.js +3 -0
- package/lib/utils/keycloak-realm-ready.js +5 -1
- package/lib/utils/localhost-public-host.js +31 -0
- package/lib/utils/npm-user-config.js +145 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +58 -4
- package/lib/utils/platform-kv-ref.js +57 -0
- package/lib/utils/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/url-declarative-public-base.js +33 -25
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +5 -0
- package/templates/applications/dataplane/env.template +26 -13
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +37 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/python/docker-compose.hbs +56 -0
- package/templates/typescript/docker-compose.hbs +52 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel install probe checks (plan 152).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Callback, assistant catalog, and inbound verification probes
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { ApiClient } = require('../api/index');
|
|
12
|
+
const { fetchDataplaneGeneralHealth } = require('../api/dataplane-health.api');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @async
|
|
16
|
+
* @param {string} url
|
|
17
|
+
* @returns {Promise<boolean>}
|
|
18
|
+
*/
|
|
19
|
+
async function isUrlReachable(url) {
|
|
20
|
+
if (!url) return false;
|
|
21
|
+
const client = new ApiClient(url.split('/api/')[0] || url);
|
|
22
|
+
try {
|
|
23
|
+
const pathPart = url.includes('/api/') ? url.substring(url.indexOf('/api/')) : '/health';
|
|
24
|
+
const res = await client.get(pathPart, { timeoutMs: 8000 });
|
|
25
|
+
return res && res.success !== false;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @async
|
|
33
|
+
* @param {string} dataplaneUrl
|
|
34
|
+
* @param {Object} authConfig
|
|
35
|
+
* @returns {Promise<boolean>}
|
|
36
|
+
*/
|
|
37
|
+
async function isAssistantCatalogReachable(dataplaneUrl, authConfig) {
|
|
38
|
+
const client = require('../api/index').createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
39
|
+
try {
|
|
40
|
+
const res = await client.get('/api/v1/workers/available', { timeoutMs: 10000 });
|
|
41
|
+
return res && res.success !== false;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {Object|null} channelExt
|
|
49
|
+
* @returns {Object}
|
|
50
|
+
*/
|
|
51
|
+
function evaluateInboundVerification(channelExt) {
|
|
52
|
+
const credentialKey = channelExt?.credentialKey || '';
|
|
53
|
+
return {
|
|
54
|
+
slackSigningSecretConfigured: credentialKey.includes('slack'),
|
|
55
|
+
teamsBotOidcValidationConfigured: credentialKey.includes('teams-bot'),
|
|
56
|
+
issuerAudienceConfigured: Boolean(channelExt?.type),
|
|
57
|
+
replayProtectionConfigured: Boolean(channelExt?.status === 'installed' || channelExt?.status === 'validated')
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @async
|
|
63
|
+
* @param {Object} ctx
|
|
64
|
+
* @param {Object|null} channelExt
|
|
65
|
+
* @returns {Promise<Object>}
|
|
66
|
+
*/
|
|
67
|
+
async function runChannelProbe(ctx, channelExt) {
|
|
68
|
+
const health = await fetchDataplaneGeneralHealth(ctx.dataplaneUrl, { timeoutMs: 8000 });
|
|
69
|
+
const catalogOk = await isAssistantCatalogReachable(ctx.dataplaneUrl, ctx.authConfig);
|
|
70
|
+
const callbackOk = health?.status === 'healthy' || health?.status === 'ok';
|
|
71
|
+
|
|
72
|
+
const inbound = evaluateInboundVerification(channelExt);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
dataplaneHealth: health?.status || 'unknown',
|
|
76
|
+
callbackReachable: callbackOk,
|
|
77
|
+
assistantCatalogReachable: catalogOk,
|
|
78
|
+
credentialValid: Boolean(channelExt?.credentialKey),
|
|
79
|
+
inboundVerification: inbound,
|
|
80
|
+
passed: callbackOk && catalogOk && Boolean(channelExt?.credentialKey)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
isUrlReachable,
|
|
86
|
+
isAssistantCatalogReachable,
|
|
87
|
+
evaluateInboundVerification,
|
|
88
|
+
runChannelProbe
|
|
89
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve runtime URLs for channel templates (no hardcoded env URLs).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Channel runtime value resolution (plan 152)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { getChannelTarget } = require('./channel-targets');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Normalize dataplane base URL (no trailing slash).
|
|
15
|
+
* @param {string} dataplaneBaseUrl
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
function normalizeBaseUrl(dataplaneBaseUrl) {
|
|
19
|
+
if (!dataplaneBaseUrl || typeof dataplaneBaseUrl !== 'string') {
|
|
20
|
+
throw new Error('dataplaneBaseUrl is required');
|
|
21
|
+
}
|
|
22
|
+
return dataplaneBaseUrl.trim().replace(/\/+$/, '');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} base
|
|
27
|
+
* @param {string} path
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
function joinUrl(base, path) {
|
|
31
|
+
return `${normalizeBaseUrl(base)}${path.startsWith('/') ? path : `/${path}`}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Dataplane external-system route prefix for webhook URLs.
|
|
36
|
+
* @param {string} routeSystemKey
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function externalSystemsPrefix(routeSystemKey) {
|
|
40
|
+
return `/api/v1/external/systems/${routeSystemKey}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Relative endpoint paths per channel target (under external/systems/{routeSystemKey}).
|
|
45
|
+
* @param {string} channelTarget
|
|
46
|
+
* @returns {Record<string, string>}
|
|
47
|
+
*/
|
|
48
|
+
function getEndpointPathSuffixes(channelTarget) {
|
|
49
|
+
const maps = {
|
|
50
|
+
slack: {
|
|
51
|
+
eventsUrl: '/events',
|
|
52
|
+
interactionUrl: '/interactive',
|
|
53
|
+
oauthCallbackUrl: '/oauth/callback',
|
|
54
|
+
commandUrl: '/commands'
|
|
55
|
+
},
|
|
56
|
+
'teams-bot': {
|
|
57
|
+
messagesUrl: '/messages',
|
|
58
|
+
notificationsUrl: '/notifications',
|
|
59
|
+
botConfigUrl: '/bot-config'
|
|
60
|
+
},
|
|
61
|
+
'microsoft-copilot': {
|
|
62
|
+
openapiUrl: '/openapi.yaml',
|
|
63
|
+
actionsBaseUrl: '/actions'
|
|
64
|
+
},
|
|
65
|
+
chatgpt: {
|
|
66
|
+
openapiUrl: '/openapi.yaml',
|
|
67
|
+
mcpUrl: '/mcp',
|
|
68
|
+
actionsBaseUrl: '/actions'
|
|
69
|
+
},
|
|
70
|
+
'web-embed': {
|
|
71
|
+
configUrl: '/config'
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return maps[channelTarget] || {};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Legacy / non-external-system paths (Copilot/ChatGPT until dataplane routes exist).
|
|
79
|
+
* @param {string} channelTarget
|
|
80
|
+
* @returns {Record<string, string>}
|
|
81
|
+
*/
|
|
82
|
+
function getLegacyApiPaths(channelTarget) {
|
|
83
|
+
const legacy = {
|
|
84
|
+
'microsoft-copilot': {
|
|
85
|
+
openapiUrl: '/api/v1/copilot/openapi.yaml',
|
|
86
|
+
actionsBaseUrl: '/api/v1/copilot/actions'
|
|
87
|
+
},
|
|
88
|
+
chatgpt: {
|
|
89
|
+
openapiUrl: '/api/v1/chatgpt/openapi.yaml',
|
|
90
|
+
mcpUrl: '/api/v1/chatgpt/mcp',
|
|
91
|
+
actionsBaseUrl: '/api/v1/chatgpt/actions'
|
|
92
|
+
},
|
|
93
|
+
'web-embed': {
|
|
94
|
+
configUrl: '/api/v1/web-embed/config'
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
return legacy[channelTarget] || {};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {Object} params
|
|
102
|
+
* @param {string} params.dataplaneBaseUrl
|
|
103
|
+
* @param {string} params.channelTarget
|
|
104
|
+
* @param {string} params.appName
|
|
105
|
+
* @param {string} [params.baseName]
|
|
106
|
+
* @param {string} [params.environment]
|
|
107
|
+
* @param {string} params.appDescription
|
|
108
|
+
* @param {string} [params.icon]
|
|
109
|
+
* @returns {Object}
|
|
110
|
+
*/
|
|
111
|
+
function resolveChannelRuntimeValues(params) {
|
|
112
|
+
const target = getChannelTarget(params.channelTarget);
|
|
113
|
+
const base = normalizeBaseUrl(params.dataplaneBaseUrl);
|
|
114
|
+
const routeKey = target.routeSystemKey || target.key;
|
|
115
|
+
const systemPrefix = externalSystemsPrefix(routeKey);
|
|
116
|
+
const suffixes = getEndpointPathSuffixes(params.channelTarget);
|
|
117
|
+
const legacy = getLegacyApiPaths(params.channelTarget);
|
|
118
|
+
|
|
119
|
+
const resolved = {
|
|
120
|
+
dataplaneBaseUrl: base,
|
|
121
|
+
channelTarget: params.channelTarget,
|
|
122
|
+
routeSystemKey: routeKey,
|
|
123
|
+
appName: params.appName,
|
|
124
|
+
baseName: params.baseName || params.appName,
|
|
125
|
+
environment: params.environment || 'dev',
|
|
126
|
+
appDescription: params.appDescription,
|
|
127
|
+
icon: params.icon || '',
|
|
128
|
+
credentialKey: target.credentialKey,
|
|
129
|
+
assistantCatalogUrl: joinUrl(base, '/api/v1/workers/available'),
|
|
130
|
+
scopes: []
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
for (const [key, suffix] of Object.entries(suffixes)) {
|
|
134
|
+
resolved[key] = joinUrl(base, `${systemPrefix}${suffix}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
for (const [key, legacyPath] of Object.entries(legacy)) {
|
|
138
|
+
if (!resolved[key]) {
|
|
139
|
+
resolved[key] = joinUrl(base, legacyPath);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return resolved;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = {
|
|
147
|
+
normalizeBaseUrl,
|
|
148
|
+
joinUrl,
|
|
149
|
+
externalSystemsPrefix,
|
|
150
|
+
getEndpointPathSuffixes,
|
|
151
|
+
resolveChannelRuntimeValues
|
|
152
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTY output for app add-channel (plan 152).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Channel install status display — customer language: Assistant
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
const logger = require('../utils/logger');
|
|
13
|
+
const {
|
|
14
|
+
formatSuccessLine,
|
|
15
|
+
formatWarningLine,
|
|
16
|
+
formatBlockingError,
|
|
17
|
+
sectionTitle,
|
|
18
|
+
metadata
|
|
19
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
20
|
+
|
|
21
|
+
/** @returns {string} */
|
|
22
|
+
function separatorLine() {
|
|
23
|
+
const gray = chalk.gray;
|
|
24
|
+
return typeof gray === 'function'
|
|
25
|
+
? gray('────────────────────────────────────────')
|
|
26
|
+
: '────────────────────────────────────────';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {Object} params
|
|
31
|
+
* @param {string} params.channelTarget
|
|
32
|
+
* @param {string} params.name
|
|
33
|
+
* @param {Object|null} params.channelExt
|
|
34
|
+
* @param {string} [params.approvalUrl]
|
|
35
|
+
*/
|
|
36
|
+
function displayExistingChannelStatus(params) {
|
|
37
|
+
logger.log(sectionTitle(`${params.channelTarget} channel: ${params.name}`));
|
|
38
|
+
logger.log('');
|
|
39
|
+
logger.log(metadata(`Status: ${params.channelExt?.status || 'unknown'}`));
|
|
40
|
+
if (params.channelExt?.baseName && params.channelExt.baseName !== params.name) {
|
|
41
|
+
logger.log(metadata(`Base name: ${params.channelExt.baseName}`));
|
|
42
|
+
}
|
|
43
|
+
logger.log(metadata(`External System: ${params.channelTarget}`));
|
|
44
|
+
logger.log(metadata(`Credential: ${params.channelExt?.credentialKey || '—'}`));
|
|
45
|
+
if (params.channelExt?.capabilities?.length) {
|
|
46
|
+
logger.log(metadata('Capabilities:'));
|
|
47
|
+
for (const cap of params.channelExt.capabilities) {
|
|
48
|
+
logger.log(` - ${cap}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
logger.log('');
|
|
52
|
+
logger.log(formatWarningLine('Channel install already configured. Use --force to regenerate artifacts.'));
|
|
53
|
+
if (params.approvalUrl) {
|
|
54
|
+
logger.log(metadata(`Approval URL: ${params.approvalUrl}`));
|
|
55
|
+
}
|
|
56
|
+
logger.log(separatorLine());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {Object} result
|
|
61
|
+
*/
|
|
62
|
+
function displayChannelCoreFields(result) {
|
|
63
|
+
logger.log(sectionTitle(`${result.channelTarget} channel: ${result.name}`));
|
|
64
|
+
logger.log('');
|
|
65
|
+
logger.log(metadata(`Status: ${result.statusLabel}`));
|
|
66
|
+
if (result.baseName && result.baseName !== result.name) {
|
|
67
|
+
logger.log(metadata(`Base name: ${result.baseName}`));
|
|
68
|
+
}
|
|
69
|
+
logger.log(metadata(`External System: ${result.channelTarget}`));
|
|
70
|
+
logger.log(metadata(`Credential: ${result.credentialKey}`));
|
|
71
|
+
if (result.capabilities?.length) {
|
|
72
|
+
logger.log(metadata('Capabilities:'));
|
|
73
|
+
for (const cap of result.capabilities) {
|
|
74
|
+
logger.log(` - ${cap}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (result.artifactPath) {
|
|
78
|
+
logger.log(metadata(`Artifact: ${result.artifactPath}`));
|
|
79
|
+
}
|
|
80
|
+
if (result.installGuidePath) {
|
|
81
|
+
logger.log(metadata(`Install guide: ${result.installGuidePath}`));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {Object|null} validation
|
|
87
|
+
*/
|
|
88
|
+
function displayValidationSection(validation) {
|
|
89
|
+
if (!validation) return;
|
|
90
|
+
logger.log('');
|
|
91
|
+
logger.log(metadata('Validation:'));
|
|
92
|
+
if (validation.callbackReachable) {
|
|
93
|
+
logger.log(formatSuccessLine('Callback reachable'));
|
|
94
|
+
}
|
|
95
|
+
if (validation.credentialValid) {
|
|
96
|
+
logger.log(formatSuccessLine('Credential valid'));
|
|
97
|
+
}
|
|
98
|
+
if (validation.assistantCatalogReachable) {
|
|
99
|
+
logger.log(formatSuccessLine('Assistant catalog reachable'));
|
|
100
|
+
}
|
|
101
|
+
if (validation.inboundVerification) {
|
|
102
|
+
logger.log(formatSuccessLine('Inbound verification configured'));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {Object} result
|
|
108
|
+
*/
|
|
109
|
+
function displayApprovalSection(result) {
|
|
110
|
+
if (!result.approvalUrl) return;
|
|
111
|
+
logger.log('');
|
|
112
|
+
logger.log(formatWarningLine('Approval required'));
|
|
113
|
+
logger.log(metadata('Open this URL as platform admin:'));
|
|
114
|
+
logger.log(chalk.cyan(result.approvalUrl));
|
|
115
|
+
logger.log('');
|
|
116
|
+
logger.log(metadata('After approval, run:'));
|
|
117
|
+
logger.log(chalk.white(` aifabrix app add-channel ${result.channelTarget} --name "${result.name}"`));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param {Object} result
|
|
122
|
+
*/
|
|
123
|
+
function displayChannelInstallResult(result) {
|
|
124
|
+
displayChannelCoreFields(result);
|
|
125
|
+
displayValidationSection(result.validation);
|
|
126
|
+
displayApprovalSection(result);
|
|
127
|
+
logger.log(separatorLine());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {string} message
|
|
132
|
+
*/
|
|
133
|
+
function displayChannelError(message) {
|
|
134
|
+
logger.error(formatBlockingError(message));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
displayExistingChannelStatus,
|
|
139
|
+
displayChannelInstallResult,
|
|
140
|
+
displayChannelError
|
|
141
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel target registry for assistant communication channels (plan 152).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Channel install targets — templates, capabilities, approval semantics
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/** @typedef {'teams-bot'|'slack'|'microsoft-copilot'|'chatgpt'|'web-embed'} ChannelTargetKey */
|
|
12
|
+
|
|
13
|
+
const DEFAULT_CAPABILITIES = ['chat', 'notify'];
|
|
14
|
+
|
|
15
|
+
const CHANNEL_TARGETS = {
|
|
16
|
+
'teams-bot': {
|
|
17
|
+
key: 'teams-bot',
|
|
18
|
+
channelType: 'teamsBot',
|
|
19
|
+
templateDir: 'teams-bot',
|
|
20
|
+
artifactFileName: 'channel-teams-bot.json',
|
|
21
|
+
artifactFormat: 'json',
|
|
22
|
+
credentialKey: 'teams-bot',
|
|
23
|
+
routeSystemKey: 'teams',
|
|
24
|
+
capabilities: DEFAULT_CAPABILITIES,
|
|
25
|
+
approvalRequired: true,
|
|
26
|
+
experimental: false
|
|
27
|
+
},
|
|
28
|
+
slack: {
|
|
29
|
+
key: 'slack',
|
|
30
|
+
channelType: 'slack',
|
|
31
|
+
templateDir: 'slack',
|
|
32
|
+
artifactFileName: 'channel-slack.json',
|
|
33
|
+
artifactFormat: 'json',
|
|
34
|
+
credentialKey: 'slack-app',
|
|
35
|
+
routeSystemKey: 'slack',
|
|
36
|
+
capabilities: DEFAULT_CAPABILITIES,
|
|
37
|
+
approvalRequired: true,
|
|
38
|
+
experimental: false
|
|
39
|
+
},
|
|
40
|
+
'microsoft-copilot': {
|
|
41
|
+
key: 'microsoft-copilot',
|
|
42
|
+
channelType: 'microsoftCopilot',
|
|
43
|
+
templateDir: 'microsoft-copilot',
|
|
44
|
+
artifactFileName: 'channel-microsoft-copilot.json',
|
|
45
|
+
artifactFormat: 'json',
|
|
46
|
+
credentialKey: 'microsoft-copilot-channel',
|
|
47
|
+
capabilities: [...DEFAULT_CAPABILITIES, 'enterpriseActions'],
|
|
48
|
+
approvalRequired: true,
|
|
49
|
+
experimental: false
|
|
50
|
+
},
|
|
51
|
+
chatgpt: {
|
|
52
|
+
key: 'chatgpt',
|
|
53
|
+
channelType: 'chatgpt',
|
|
54
|
+
templateDir: 'chatgpt',
|
|
55
|
+
artifactFileName: 'channel-chatgpt.json',
|
|
56
|
+
artifactFormat: 'json',
|
|
57
|
+
credentialKey: 'chatgpt-channel',
|
|
58
|
+
capabilities: ['chat', 'enterpriseActions'],
|
|
59
|
+
approvalRequired: true,
|
|
60
|
+
experimental: false
|
|
61
|
+
},
|
|
62
|
+
'web-embed': {
|
|
63
|
+
key: 'web-embed',
|
|
64
|
+
channelType: 'webEmbed',
|
|
65
|
+
templateDir: 'web-embed',
|
|
66
|
+
artifactFileName: 'channel-web-embed.json',
|
|
67
|
+
artifactFormat: 'json',
|
|
68
|
+
credentialKey: 'web-embed-channel',
|
|
69
|
+
capabilities: DEFAULT_CAPABILITIES,
|
|
70
|
+
approvalRequired: false,
|
|
71
|
+
experimental: true
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const CHANNEL_TARGET_KEYS = Object.keys(CHANNEL_TARGETS);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} channelTarget
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
function isChannelTargetKey(channelTarget) {
|
|
82
|
+
return typeof channelTarget === 'string' && CHANNEL_TARGET_KEYS.includes(channelTarget);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {string} channelTarget
|
|
87
|
+
* @returns {typeof CHANNEL_TARGETS[string]}
|
|
88
|
+
*/
|
|
89
|
+
function getChannelTarget(channelTarget) {
|
|
90
|
+
if (!isChannelTargetKey(channelTarget)) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Unknown channel target "${channelTarget}". Expected one of: ${CHANNEL_TARGET_KEYS.join(', ')}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return CHANNEL_TARGETS[channelTarget];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Default customer-facing description when --description is omitted.
|
|
100
|
+
* @returns {string}
|
|
101
|
+
*/
|
|
102
|
+
function getDefaultChannelDescription() {
|
|
103
|
+
return (
|
|
104
|
+
'Enterprise AI assistant for employees. Provides access to approved assistants, ' +
|
|
105
|
+
'enterprise knowledge, business workflows, and governed actions through AI Fabrix.'
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
CHANNEL_TARGETS,
|
|
111
|
+
CHANNEL_TARGET_KEYS,
|
|
112
|
+
isChannelTargetKey,
|
|
113
|
+
getChannelTarget,
|
|
114
|
+
getDefaultChannelDescription
|
|
115
|
+
};
|
package/lib/cli/index.js
CHANGED
|
@@ -22,6 +22,7 @@ const { setupExternalSystemCommands } = require('./setup-external-system');
|
|
|
22
22
|
const { setupAppCommands: setupAppManagementCommands } = require('../commands/app');
|
|
23
23
|
const { setupDatasourceCommands } = require('../commands/datasource');
|
|
24
24
|
const { setupDimensionCommands } = require('../commands/dimension');
|
|
25
|
+
const { setupResourceTypeCommands } = require('../commands/resource-type');
|
|
25
26
|
const { setupIdentityCommands } = require('../commands/identity');
|
|
26
27
|
const { setupProtectionCommands } = require('../commands/protection');
|
|
27
28
|
const { setupCredentialDeploymentCommands } = require('./setup-credential-deployment');
|
|
@@ -29,6 +30,20 @@ const { setupIntegrationClientCommands } = require('./setup-integration-client')
|
|
|
29
30
|
const { setupPlatformCommands } = require('./setup-platform');
|
|
30
31
|
const { setupCertificationCommands } = require('./setup-certification-commands');
|
|
31
32
|
const { setupGovernanceCommands } = require('../commands/governance');
|
|
33
|
+
const { setupChannelCommands } = require('../commands/channel');
|
|
34
|
+
const { setupNpmCommands } = require('./setup-npm');
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Dev, secrets, parameters, and platform commands (keeps setupCommands under statement limit).
|
|
38
|
+
* @param {import('commander').Command} program
|
|
39
|
+
*/
|
|
40
|
+
function setupDevAndPlatformCommands(program) {
|
|
41
|
+
setupDevCommands(program);
|
|
42
|
+
setupSecretsCommands(program);
|
|
43
|
+
setupNpmCommands(program);
|
|
44
|
+
setupParametersCommands(program);
|
|
45
|
+
setupPlatformCommands(program);
|
|
46
|
+
}
|
|
32
47
|
|
|
33
48
|
/**
|
|
34
49
|
* Sets up all CLI commands on the Commander program instance
|
|
@@ -42,18 +57,17 @@ function setupCommands(program) {
|
|
|
42
57
|
setupGovernanceCommands(program);
|
|
43
58
|
setupEnvironmentCommands(program);
|
|
44
59
|
setupAppManagementCommands(program);
|
|
60
|
+
setupChannelCommands(program);
|
|
45
61
|
setupDatasourceCommands(program);
|
|
46
62
|
setupDimensionCommands(program);
|
|
63
|
+
setupResourceTypeCommands(program);
|
|
47
64
|
setupIdentityCommands(program);
|
|
48
65
|
setupProtectionCommands(program);
|
|
49
66
|
setupUtilityCommands(program);
|
|
50
67
|
setupCredentialDeploymentCommands(program);
|
|
51
68
|
setupIntegrationClientCommands(program);
|
|
52
69
|
setupExternalSystemCommands(program);
|
|
53
|
-
|
|
54
|
-
setupSecretsCommands(program);
|
|
55
|
-
setupParametersCommands(program);
|
|
56
|
-
setupPlatformCommands(program);
|
|
70
|
+
setupDevAndPlatformCommands(program);
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
module.exports = {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
const chalk = require('chalk');
|
|
12
12
|
const logger = require('../utils/logger');
|
|
13
13
|
const config = require('../core/config');
|
|
14
|
-
const { resolvePlatformControllerUrl } = require('../utils/platform-controller-url');
|
|
14
|
+
const { resolvePlatformControllerUrl, resolveCliPlatformControllerUrl } = require('../utils/platform-controller-url');
|
|
15
15
|
const { withMutedLogger } = require('../utils/with-muted-logger');
|
|
16
16
|
const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
|
|
17
17
|
const { isAuthenticationError } = require('../utils/cli-utils');
|
|
@@ -19,29 +19,45 @@ const { resolveControllerUrl, isPlatformAuthValidForController } = require('../u
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @param {Object} authOpts
|
|
22
|
-
* @returns {Promise<string>}
|
|
22
|
+
* @returns {Promise<{ apiUrl: string, tokenUrl: string }>}
|
|
23
23
|
*/
|
|
24
|
-
async function
|
|
25
|
-
|
|
24
|
+
async function resolveGuidedAuthControllerUrls(authOpts = {}) {
|
|
25
|
+
const tokenUrl =
|
|
26
26
|
authOpts.platformControllerUrl ||
|
|
27
27
|
(await config.getPlatformControllerUrl()) ||
|
|
28
|
-
(await resolvePlatformControllerUrl())
|
|
29
|
-
);
|
|
28
|
+
(await resolvePlatformControllerUrl());
|
|
29
|
+
const remoteServer = await config.getRemoteServer();
|
|
30
|
+
let apiUrl = tokenUrl;
|
|
31
|
+
if (remoteServer && String(remoteServer).trim()) {
|
|
32
|
+
apiUrl = await resolveCliPlatformControllerUrl();
|
|
33
|
+
}
|
|
34
|
+
return { apiUrl, tokenUrl };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {Object} authOpts
|
|
39
|
+
* @returns {Promise<string>}
|
|
40
|
+
*/
|
|
41
|
+
async function resolveGuidedAuthControllerUrl(authOpts = {}) {
|
|
42
|
+
const { apiUrl } = await resolveGuidedAuthControllerUrls(authOpts);
|
|
43
|
+
return apiUrl;
|
|
30
44
|
}
|
|
31
45
|
|
|
32
46
|
/**
|
|
33
47
|
* @async
|
|
34
48
|
* @param {Function} handleLoginFn
|
|
35
|
-
* @param {string} controllerUrl
|
|
36
|
-
* @param {{ skipDataplaneVersionRefresh?: boolean }} [opts]
|
|
49
|
+
* @param {string} controllerUrl - Controller API base URL (may be localhost on builder host)
|
|
50
|
+
* @param {{ skipDataplaneVersionRefresh?: boolean, tokenControllerUrl?: string }} [opts]
|
|
37
51
|
* @returns {Promise<void>}
|
|
38
52
|
*/
|
|
39
53
|
async function runGuidedDeviceLogin(handleLoginFn, controllerUrl, opts = {}) {
|
|
40
54
|
await handleLoginFn({
|
|
41
55
|
method: 'device',
|
|
42
56
|
controller: controllerUrl,
|
|
57
|
+
tokenControllerUrl: opts.tokenControllerUrl,
|
|
43
58
|
environment: 'dev',
|
|
44
59
|
compact: true,
|
|
60
|
+
skipControllerUrlPersist: Boolean(opts.tokenControllerUrl),
|
|
45
61
|
skipDataplaneVersionRefresh: opts.skipDataplaneVersionRefresh === true,
|
|
46
62
|
exitOnFailure: false
|
|
47
63
|
});
|
|
@@ -56,20 +72,27 @@ async function runGuidedDeviceLogin(handleLoginFn, controllerUrl, opts = {}) {
|
|
|
56
72
|
*/
|
|
57
73
|
async function runGuidedAuthStep(handleLoginFn, authOpts, spinners) {
|
|
58
74
|
const spin = spinners.startSpinner('Authenticating...');
|
|
59
|
-
const
|
|
75
|
+
const { apiUrl, tokenUrl } = await resolveGuidedAuthControllerUrls(authOpts);
|
|
76
|
+
const loginOpts = { skipDataplaneVersionRefresh: true, tokenControllerUrl: tokenUrl };
|
|
60
77
|
const skipLogin =
|
|
61
78
|
authOpts.skipLoginIfAuthenticated === true ||
|
|
62
|
-
(await isPlatformAuthValidForController(
|
|
79
|
+
(await isPlatformAuthValidForController(tokenUrl));
|
|
63
80
|
try {
|
|
64
81
|
if (skipLogin) {
|
|
65
82
|
spinners.stopSpinnerSuccess(spin, 'Already authenticated');
|
|
66
83
|
return;
|
|
67
84
|
}
|
|
68
|
-
await runGuidedDeviceLogin(handleLoginFn,
|
|
85
|
+
await runGuidedDeviceLogin(handleLoginFn, apiUrl, loginOpts);
|
|
69
86
|
} catch (authErr) {
|
|
70
87
|
if (spin) spin.fail('Authentication required');
|
|
88
|
+
const retriable =
|
|
89
|
+
isAuthenticationError(authErr) ||
|
|
90
|
+
/device code|authorization_pending|complete sign-in|browser/i.test(String(authErr.message || ''));
|
|
91
|
+
if (!retriable) {
|
|
92
|
+
throw authErr;
|
|
93
|
+
}
|
|
71
94
|
logger.error(formatBlockingError('Authentication required. Complete sign-in in your browser.'));
|
|
72
|
-
await runGuidedDeviceLogin(handleLoginFn,
|
|
95
|
+
await runGuidedDeviceLogin(handleLoginFn, apiUrl, loginOpts);
|
|
73
96
|
}
|
|
74
97
|
spinners.stopSpinnerSuccess(spin, 'Authenticated');
|
|
75
98
|
}
|
|
@@ -102,6 +125,7 @@ async function runGuidedDataplaneWithAuthRecovery(options, handleUpDataplane, ha
|
|
|
102
125
|
}
|
|
103
126
|
|
|
104
127
|
module.exports = {
|
|
128
|
+
resolveGuidedAuthControllerUrls,
|
|
105
129
|
resolveGuidedAuthControllerUrl,
|
|
106
130
|
runGuidedDeviceLogin,
|
|
107
131
|
runGuidedAuthStep,
|