@aifabrix/builder 2.53.1 → 2.54.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/bin/aifabrix.js +2 -2
- package/lib/api/assistants.api.js +8 -5
- package/lib/api/channel-identity.api.js +41 -0
- package/lib/api/evidence-authoring.api.js +5 -1
- package/lib/api/evidence.api.js +2 -0
- package/lib/api/types/evidence.types.js +2 -0
- package/lib/api/work-search.api.js +136 -0
- package/lib/channels/add-channel.js +163 -126
- package/lib/channels/approval-guides/chatgpt.js +14 -18
- package/lib/channels/approval-guides/claude.js +29 -0
- package/lib/channels/approval-guides/index.js +88 -22
- package/lib/channels/approval-guides/mcp-client.js +27 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +52 -3
- package/lib/channels/approval-guides/slack.js +10 -10
- package/lib/channels/approval-guides/teams-bot.js +8 -12
- package/lib/channels/channel-add-continuations.js +91 -0
- package/lib/channels/channel-add-ensure.js +124 -27
- package/lib/channels/channel-add-existing.js +160 -28
- package/lib/channels/channel-add-failure.js +60 -0
- package/lib/channels/channel-add-remaining.js +486 -0
- package/lib/channels/channel-add-tty.js +190 -0
- package/lib/channels/channel-add-wizard-config.js +138 -0
- package/lib/channels/channel-add-wizard.js +250 -0
- package/lib/channels/channel-artifact-generator.js +27 -13
- package/lib/channels/channel-cardinality.js +83 -0
- package/lib/channels/channel-catalog-icon.js +45 -0
- package/lib/channels/channel-cli-instructions.js +75 -0
- package/lib/channels/channel-configuration-map.js +213 -0
- package/lib/channels/channel-credential.js +11 -14
- package/lib/channels/channel-definition-project.js +101 -0
- package/lib/channels/channel-definition-registry.js +154 -0
- package/lib/channels/channel-description.js +59 -2
- package/lib/channels/channel-discovery.js +16 -2
- package/lib/channels/channel-external-system.js +86 -9
- package/lib/channels/channel-install-envelope-actions.js +88 -0
- package/lib/channels/channel-install-envelope-microsoft.js +155 -0
- package/lib/channels/channel-install-envelope.js +356 -0
- package/lib/channels/channel-install-help-md.js +172 -0
- package/lib/channels/channel-install-http-payload.js +62 -0
- package/lib/channels/channel-install-inventory.js +115 -0
- package/lib/channels/channel-install-profiles.js +90 -0
- package/lib/channels/channel-instance-collision.js +118 -0
- package/lib/channels/channel-instance-key.js +100 -0
- package/lib/channels/channel-instance-materialize.js +240 -0
- package/lib/channels/channel-integration-generator.js +16 -9
- package/lib/channels/channel-integration-template.js +101 -22
- package/lib/channels/channel-inventory-fetch.js +79 -0
- package/lib/channels/channel-oauth-preflight.js +104 -0
- package/lib/channels/channel-package-version.js +76 -0
- package/lib/channels/channel-predefined-client.js +154 -0
- package/lib/channels/channel-probe.js +7 -2
- package/lib/channels/channel-runtime-resolver.js +180 -72
- package/lib/channels/channel-status-display.js +86 -16
- package/lib/channels/channel-targets.js +106 -92
- package/lib/channels/chatgpt-callback.js +318 -0
- package/lib/channels/chatgpt-channel-add.js +229 -0
- package/lib/channels/chatgpt-preflight.js +396 -0
- package/lib/channels/chatgpt-runtime-contract.js +17 -0
- package/lib/channels/chatgpt-setup-values.js +124 -0
- package/lib/channels/claude-callback.js +67 -0
- package/lib/channels/claude-channel-add.js +254 -0
- package/lib/channels/claude-runtime-contract.js +40 -0
- package/lib/channels/claude-runtime.js +58 -0
- package/lib/channels/claude-setup-values.js +89 -0
- package/lib/channels/mcp-client/config-merge.js +148 -0
- package/lib/channels/mcp-client/ensure-client.js +231 -0
- package/lib/channels/mcp-client/paths.js +53 -0
- package/lib/channels/mcp-client/profiles.js +122 -0
- package/lib/channels/mcp-client/redirect-uris.js +99 -0
- package/lib/channels/mcp-client/runtime.js +59 -0
- package/lib/channels/mcp-client-channel-add.js +186 -0
- package/lib/channels/microsoft-copilot-channel-add.js +117 -7
- package/lib/channels/microsoft-copilot-entra-identifier-uris.js +187 -0
- package/lib/channels/microsoft-copilot-entra-sso-form.js +106 -18
- package/lib/channels/microsoft-copilot-entra-sso.js +31 -2
- package/lib/channels/microsoft-copilot-package-prior.js +107 -0
- package/lib/channels/microsoft-copilot-package.js +29 -28
- package/lib/channels/microsoft-provisioning/a365.js +80 -0
- package/lib/channels/microsoft-provisioning/auth-config.js +240 -0
- package/lib/channels/microsoft-provisioning/auth.js +179 -0
- package/lib/channels/microsoft-provisioning/cli.js +71 -0
- package/lib/channels/microsoft-provisioning/constants.js +75 -0
- package/lib/channels/microsoft-provisioning/errors.js +117 -0
- package/lib/channels/microsoft-provisioning/index.js +55 -0
- package/lib/channels/microsoft-provisioning/install-atk.js +158 -0
- package/lib/channels/microsoft-provisioning/install-teams.js +115 -0
- package/lib/channels/microsoft-provisioning/login-portal-device.js +236 -0
- package/lib/channels/microsoft-provisioning/login-portal-parse.js +71 -0
- package/lib/channels/microsoft-provisioning/login-portal-teams.js +193 -0
- package/lib/channels/microsoft-provisioning/login-portal.js +230 -0
- package/lib/channels/microsoft-provisioning/persist.js +110 -0
- package/lib/channels/microsoft-provisioning/teams-bot-args.js +119 -0
- package/lib/channels/microsoft-provisioning/teams-bot-controller.js +123 -0
- package/lib/channels/microsoft-provisioning/teams-bot-parse.js +134 -0
- package/lib/channels/microsoft-provisioning/teams-bot-persist.js +113 -0
- package/lib/channels/microsoft-provisioning/teams-bot-provision.js +234 -0
- package/lib/channels/microsoft-provisioning/teams-bot-secrets.js +45 -0
- package/lib/channels/microsoft-provisioning/teams-cli.js +82 -0
- package/lib/channels/runtime-tool-catalog.js +5 -2
- package/lib/channels/slack-channel-add-portal.js +130 -0
- package/lib/channels/slack-channel-add-tty-auth.js +95 -0
- package/lib/channels/slack-channel-add.js +258 -0
- package/lib/channels/slack-provisioning/apps.js +181 -0
- package/lib/channels/slack-provisioning/auth-store.js +110 -0
- package/lib/channels/slack-provisioning/auth-ticket.js +185 -0
- package/lib/channels/slack-provisioning/auth.js +115 -0
- package/lib/channels/slack-provisioning/callbacks.js +41 -0
- package/lib/channels/slack-provisioning/cli.js +226 -0
- package/lib/channels/slack-provisioning/constants.js +37 -0
- package/lib/channels/slack-provisioning/credentials.js +169 -0
- package/lib/channels/slack-provisioning/curl-shim.js +132 -0
- package/lib/channels/slack-provisioning/developer-install.js +118 -0
- package/lib/channels/slack-provisioning/env-file.js +120 -0
- package/lib/channels/slack-provisioning/errors.js +47 -0
- package/lib/channels/slack-provisioning/go-ca-bundle.js +137 -0
- package/lib/channels/slack-provisioning/index.js +250 -0
- package/lib/channels/slack-provisioning/install-cli.js +323 -0
- package/lib/channels/slack-provisioning/manifest.js +89 -0
- package/lib/channels/slack-provisioning/oauth-lock.js +33 -0
- package/lib/channels/slack-provisioning/offer-cli.js +113 -0
- package/lib/channels/slack-provisioning/onboard-members.js +122 -0
- package/lib/channels/slack-provisioning/onboard.js +89 -0
- package/lib/channels/slack-provisioning/persist.js +95 -0
- package/lib/channels/slack-provisioning/remaining-urls.js +158 -0
- package/lib/channels/slack-provisioning/with-curl-on-path.js +48 -0
- package/lib/channels/teams-bot-channel-add.js +94 -0
- package/lib/channels/vendor-dataplane-url.js +249 -0
- package/lib/cli/setup-certification.help.js +2 -0
- package/lib/cli/setup-external-system-help.js +2 -0
- package/lib/cli/setup-external-system.js +1 -1
- package/lib/commands/channel-add-help.js +366 -0
- package/lib/commands/channel-add-setup.js +162 -80
- package/lib/commands/channel-configure.js +118 -0
- package/lib/commands/channel.js +10 -1
- package/lib/commands/governance-upload-external.js +6 -3
- package/lib/commands/lifecycle-command-action.js +2 -5
- package/lib/commands/lifecycle-external.js +93 -21
- package/lib/commands/repair-datasource-test-payload.js +4 -2
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +23 -2
- package/lib/commands/repair-datasource.js +3 -0
- package/lib/commands/repair-external-run.js +59 -25
- package/lib/commands/repair-openapi-rest-runtime.js +127 -0
- package/lib/commands/repair-orchestration-tag-merge.js +339 -0
- package/lib/commands/repair-rbac-catalog-defaults.js +96 -0
- package/lib/commands/repair-rbac-platform-preset.js +26 -15
- package/lib/commands/repair-rbac-reader-roles.js +8 -21
- package/lib/commands/repair-rbac.js +10 -34
- package/lib/commands/repair-system-permissions.js +24 -22
- package/lib/commands/role-assistant-test-output.js +14 -0
- package/lib/commands/role-assistant.js +59 -21
- package/lib/commands/test-e2e-external.js +148 -21
- package/lib/commands/upload-credential-push-log.js +2 -1
- package/lib/commands/upload-publish-context.js +1 -1
- package/lib/commands/upload-role-assistant-shell.js +124 -0
- package/lib/commands/upload-sidecar-followups.js +6 -3
- package/lib/commands/upload.js +18 -3
- package/lib/core/secrets-docker-env.js +4 -1
- package/lib/core/secrets-env-content.js +17 -3
- package/lib/datasource/capability/capability-manifest.js +0 -3
- package/lib/datasource/capability/copy-test-payload.js +3 -0
- package/lib/external-system/deploy-helpers.js +26 -1
- package/lib/external-system/deploy.js +10 -6
- package/lib/external-system/download-helpers.js +29 -2
- package/lib/external-system/download-role-assistant.js +83 -4
- package/lib/external-system/download.js +40 -30
- package/lib/external-system/sync-deploy-manifest.js +3 -2
- package/lib/external-system/upload-identity.js +42 -0
- package/lib/generator/index.js +19 -15
- package/lib/generator/split.js +13 -2
- package/lib/lifecycle/role-assistant-governance.js +146 -0
- package/lib/lifecycle/scenario-upload.js +181 -30
- package/lib/programmatic/builder-api-cors.js +143 -0
- package/lib/programmatic/builder-api-request.js +6 -0
- package/lib/programmatic/builder-api-route-dispatch.js +56 -42
- package/lib/programmatic/builder-api-server.js +8 -1
- package/lib/programmatic/capability-registry.js +54 -0
- package/lib/programmatic/channel-install-help-resolve.js +359 -0
- package/lib/programmatic/channel-install-session.js +218 -0
- package/lib/programmatic/help-content/channel-onboarding.md +2 -0
- package/lib/programmatic/help-content/cip-overview.md +3 -1
- package/lib/programmatic/http-raw-response.js +62 -0
- package/lib/programmatic/openapi-channel-install-bindings.js +179 -0
- package/lib/programmatic/openapi-channel-install-schemas.js +286 -0
- package/lib/programmatic/openapi-component-schemas.js +18 -1
- package/lib/programmatic/openapi-description-enricher.js +3 -1
- package/lib/programmatic/openapi-descriptions.js +74 -3
- package/lib/programmatic/openapi-envelope-examples.js +117 -0
- package/lib/programmatic/openapi-operation-bindings.js +4 -1
- package/lib/programmatic/openapi-schema-descriptions-channel.js +316 -0
- package/lib/programmatic/openapi-spec.js +12 -8
- package/lib/programmatic/platform-rbac-catalog.js +36 -18
- package/lib/programmatic/route-handler-map.js +51 -1
- package/lib/programmatic/route-handlers-context.js +2 -1
- package/lib/programmatic/run-auth-permissions.js +54 -0
- package/lib/programmatic/run-channel-catalog.js +196 -0
- package/lib/programmatic/run-channel-install-artifacts.js +137 -0
- package/lib/programmatic/run-channel-install-copilot.js +353 -0
- package/lib/programmatic/run-channel-install-options.js +232 -0
- package/lib/programmatic/run-channel-install-teams-bot.js +204 -0
- package/lib/programmatic/run-channel-install.js +346 -0
- package/lib/programmatic/run-channel-package.js +87 -7
- package/lib/programmatic/workspace-context.js +2 -0
- package/lib/role-assistant/evidence-sync.js +4 -2
- package/lib/role-assistant/evidence-validation-issues.js +51 -0
- package/lib/role-assistant/knowledge-sync.js +10 -4
- package/lib/role-assistant/settings.js +49 -2
- package/lib/role-assistant/test-cases-evaluate.js +30 -2
- package/lib/role-assistant/test-cases-evidence.js +175 -0
- package/lib/role-assistant/test-cases-search.js +229 -0
- package/lib/role-assistant/test-cases.js +37 -4
- package/lib/role-assistant/test-runner-search.js +149 -0
- package/lib/role-assistant/test-runner-workhub-helpers.js +40 -2
- package/lib/role-assistant/test-runner-workhub-soft.js +9 -3
- package/lib/role-assistant/test-runner-workhub.js +29 -11
- package/lib/role-assistant/test-runner.js +16 -1
- package/lib/schema/external-datasource.schema.json +112 -18
- package/lib/schema/external-system.schema.json +159 -2
- package/lib/schema/mcp-client-profile.schema.json +103 -0
- package/lib/utils/app-path-resolve.js +4 -0
- package/lib/utils/authentication-env-template.js +44 -6
- package/lib/utils/credential-secrets-env.js +6 -1
- package/lib/utils/env-copy.js +19 -7
- package/lib/utils/external-env-template.js +20 -2
- package/lib/utils/paths.js +18 -1
- package/lib/utils/platform-shell-package.js +69 -0
- package/lib/utils/port-resolver.js +50 -1
- package/lib/utils/rewrite-name-flag.js +20 -0
- package/lib/utils/role-assistant-paths.js +13 -10
- package/lib/utils/schema-resolver.js +11 -1
- package/lib/utils/secrets-helpers.js +12 -21
- package/lib/utils/token-manager.js +10 -5
- package/lib/validation/validate.js +40 -0
- package/package.json +1 -1
- package/templates/README.md +1 -1
- package/templates/applications/builder-api/Dockerfile +1 -1
- package/templates/applications/builder-api/env.template +7 -0
- package/templates/applications/dataplane/application.yaml +6 -5
- package/templates/applications/dataplane/env.template +2 -2
- package/templates/applications/dataplane/rbac.yaml +7 -2
- package/templates/applications/keycloak/Dockerfile +30 -4
- package/templates/applications/keycloak/application.yaml +2 -2
- package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +896 -0
- package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +19 -0
- package/templates/applications/keycloak/env.template +3 -0
- package/templates/applications/miso-controller/application.yaml +1 -2
- package/templates/applications/miso-controller/env.template +2 -0
- package/templates/channels/README.md +5 -5
- package/templates/channels/chatgpt/TROUBLESHOOTING.md +51 -0
- package/templates/channels/chatgpt/channel.json +59 -0
- package/templates/channels/chatgpt/icon.svg +1 -0
- package/templates/channels/chatgpt/install.template.md.hbs +20 -95
- package/templates/channels/chatgpt/integration/README.md +1 -1
- package/templates/channels/chatgpt/integration/application.json +2 -2
- package/templates/channels/chatgpt/integration/chatgpt-system.json +49 -4
- package/templates/channels/chatgpt/integration/env.template +2 -4
- package/templates/channels/chatgpt/integration/rbac.json +13 -0
- package/templates/channels/claude/TROUBLESHOOTING.md +41 -0
- package/templates/channels/claude/channel.json +59 -0
- package/templates/channels/claude/icon.svg +1 -0
- package/templates/channels/claude/install.template.md.hbs +21 -0
- package/templates/channels/claude/integration/README.md +14 -0
- package/templates/channels/claude/integration/application.json +15 -0
- package/templates/channels/claude/integration/claude-system.json +59 -0
- package/templates/channels/claude/integration/env.template +2 -0
- package/templates/channels/claude/integration/rbac.json +13 -0
- package/templates/channels/claude/manifest.template.json.hbs +40 -0
- package/templates/channels/mcp-client/channel.json +72 -0
- package/templates/channels/mcp-client/icon.svg +1 -0
- package/templates/channels/mcp-client/install.template.md.hbs +24 -0
- package/templates/channels/mcp-client/integration/README.md +13 -0
- package/templates/channels/mcp-client/integration/application.json +15 -0
- package/templates/channels/mcp-client/integration/env.template +2 -0
- package/templates/channels/mcp-client/integration/mcp-client-system.json +72 -0
- package/templates/channels/mcp-client/integration/rbac.json +13 -0
- package/templates/channels/mcp-client/manifest.template.json.hbs +41 -0
- package/templates/channels/mcp-client/profiles/cursor.json +26 -0
- package/templates/channels/mcp-client/profiles/github-copilot.json +29 -0
- package/templates/channels/mcp-client/profiles/vscode.json +29 -0
- package/templates/channels/microsoft-copilot/channel.json +73 -0
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +8 -4
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +65 -5
- package/templates/channels/microsoft-copilot/icon.svg +1 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +9 -9
- package/templates/channels/microsoft-copilot/integration/README.md +1 -1
- package/templates/channels/microsoft-copilot/integration/application.json +2 -2
- package/templates/channels/microsoft-copilot/integration/env.template +3 -6
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +63 -4
- package/templates/channels/microsoft-copilot/integration/rbac.json +13 -0
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +5 -5
- package/templates/channels/slack/channel.json +223 -0
- package/templates/channels/slack/icon.svg +1 -0
- package/templates/channels/slack/install.template.md.hbs +36 -28
- package/templates/channels/slack/integration/README.md +245 -22
- package/templates/channels/slack/integration/application.json +44 -7
- package/templates/channels/slack/integration/env.template +15 -6
- package/templates/channels/slack/integration/openapi/openapi.json +126 -0
- package/templates/channels/slack/integration/rbac.json +84 -0
- package/templates/channels/slack/integration/slack-datasource-commands.json +154 -0
- package/templates/channels/slack/integration/slack-datasource-conversations.json +28 -3
- package/templates/channels/slack/integration/slack-datasource-events.json +154 -0
- package/templates/channels/slack/integration/slack-datasource-interactive.json +154 -0
- package/templates/channels/slack/integration/slack-datasource-messages.json +40 -2
- package/templates/channels/slack/integration/slack-system.json +155 -77
- package/templates/channels/slack/manifest.template.json.hbs +5 -2
- package/templates/channels/teams-bot/channel.json +161 -0
- package/templates/channels/teams-bot/icon.svg +1 -0
- package/templates/channels/teams-bot/install.template.md.hbs +12 -13
- package/templates/channels/teams-bot/integration/README.md +5 -4
- package/templates/channels/teams-bot/integration/application.json +6 -4
- package/templates/channels/teams-bot/integration/env.template +5 -4
- package/templates/channels/teams-bot/integration/openapi/openapi.json +68 -0
- package/templates/channels/teams-bot/integration/rbac.json +21 -0
- package/templates/channels/teams-bot/integration/teams-bot-datasource-activities.json +154 -0
- package/templates/channels/teams-bot/integration/teams-bot-system.json +128 -23
- package/templates/channels/web-embed/channel.json +60 -0
- package/templates/channels/web-embed/install.template.md.hbs +1 -1
- package/templates/channels/web-embed/integration/README.md +2 -2
- package/templates/channels/web-embed/integration/application.json +2 -2
- package/templates/channels/web-embed/integration/env.template +1 -1
- package/templates/channels/web-embed/integration/rbac.json +13 -0
- package/templates/channels/web-embed/integration/web-embed-system.json +50 -4
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map ES configuration[] names to consumer propertyKeys and install options.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview CHANNEL_COMMAND_PREFIX → commandPrefix
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const SECRET_NAME_RE = /(SECRET|PASSWORD|TOKEN|KEY|CREDENTIAL)/i;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string} envName
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
17
|
+
function envNameToPropertyKey(envName) {
|
|
18
|
+
const stripped = String(envName || '').replace(/^CHANNEL_/, '');
|
|
19
|
+
const lower = stripped.toLowerCase();
|
|
20
|
+
return lower.replace(/_([a-z0-9])/g, (_, ch) => ch.toUpperCase());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Object} definition
|
|
25
|
+
* @returns {Object[]}
|
|
26
|
+
*/
|
|
27
|
+
function listDefinitionConfiguration(definition) {
|
|
28
|
+
const rows = definition && Array.isArray(definition.configuration) ? definition.configuration : [];
|
|
29
|
+
return rows.filter((row) => row && typeof row.name === 'string');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {Object} definition
|
|
34
|
+
* @returns {Map<string, Object>}
|
|
35
|
+
*/
|
|
36
|
+
function configurationByPropertyKey(definition) {
|
|
37
|
+
const map = new Map();
|
|
38
|
+
for (const row of listDefinitionConfiguration(definition)) {
|
|
39
|
+
map.set(envNameToPropertyKey(row.name), row);
|
|
40
|
+
}
|
|
41
|
+
return map;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {unknown} value
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
function isSecretShapedValue(value) {
|
|
49
|
+
if (typeof value !== 'string') {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return /kv:\/\//i.test(value) || SECRET_NAME_RE.test(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Safe configuration for GET definition (no secret-shaped values).
|
|
57
|
+
* @param {Object} definition
|
|
58
|
+
* @returns {Object[]}
|
|
59
|
+
*/
|
|
60
|
+
function toSafeConfiguration(definition) {
|
|
61
|
+
return listDefinitionConfiguration(definition).map((row) => {
|
|
62
|
+
const copy = { ...row };
|
|
63
|
+
if (isSecretShapedValue(copy.value)) {
|
|
64
|
+
copy.value = '';
|
|
65
|
+
}
|
|
66
|
+
copy.propertyKey = envNameToPropertyKey(row.name);
|
|
67
|
+
return copy;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {Object} row
|
|
73
|
+
* @returns {Object|null}
|
|
74
|
+
*/
|
|
75
|
+
function toPortalField(row) {
|
|
76
|
+
const portal = row && row.portalInput;
|
|
77
|
+
if (!portal || typeof portal !== 'object') {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (typeof portal.label !== 'string' || !portal.label.trim()) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (isSecretShapedValue(row.value)) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const propertyKey = envNameToPropertyKey(row.name);
|
|
87
|
+
const field = {
|
|
88
|
+
propertyKey,
|
|
89
|
+
label: portal.label.trim(),
|
|
90
|
+
required: row.required === true,
|
|
91
|
+
envName: row.name
|
|
92
|
+
};
|
|
93
|
+
if (portal.field) {
|
|
94
|
+
field.inputKind = portal.field;
|
|
95
|
+
}
|
|
96
|
+
if (portal.placeholder) {
|
|
97
|
+
field.placeholder = portal.placeholder;
|
|
98
|
+
}
|
|
99
|
+
if (Array.isArray(portal.options) && portal.options.length > 0) {
|
|
100
|
+
field.options = portal.options;
|
|
101
|
+
}
|
|
102
|
+
if (
|
|
103
|
+
typeof row.value === 'string' &&
|
|
104
|
+
row.value.trim() &&
|
|
105
|
+
!row.value.includes('{{') &&
|
|
106
|
+
!/kv:\/\//i.test(row.value)
|
|
107
|
+
) {
|
|
108
|
+
field.defaultValue = row.value.trim();
|
|
109
|
+
}
|
|
110
|
+
assignPortalConstraints(field, portal.validation);
|
|
111
|
+
return field;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {Object} field
|
|
116
|
+
* @param {unknown} validation
|
|
117
|
+
*/
|
|
118
|
+
function assignPortalConstraints(field, validation) {
|
|
119
|
+
if (!validation || typeof validation !== 'object') {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const rules = /** @type {Record<string, unknown>} */ (validation);
|
|
123
|
+
if (typeof rules.minLength === 'number' && rules.minLength > 0) {
|
|
124
|
+
field.minLength = rules.minLength;
|
|
125
|
+
}
|
|
126
|
+
if (typeof rules.maxLength === 'number' && rules.maxLength > 0) {
|
|
127
|
+
field.maxLength = rules.maxLength;
|
|
128
|
+
}
|
|
129
|
+
if (typeof rules.pattern === 'string' && rules.pattern.trim()) {
|
|
130
|
+
field.pattern = rules.pattern.trim();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Portal-facing fields only. Rows without portalInput are hidden system variables.
|
|
136
|
+
* @param {Object} definition
|
|
137
|
+
* @returns {Object[]}
|
|
138
|
+
*/
|
|
139
|
+
function toPortalFields(definition) {
|
|
140
|
+
return listDefinitionConfiguration(definition)
|
|
141
|
+
.map(toPortalField)
|
|
142
|
+
.filter(Boolean);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @param {Object} definition
|
|
147
|
+
* @param {Object} configuration
|
|
148
|
+
* @returns {string[]}
|
|
149
|
+
*/
|
|
150
|
+
function unknownConfigurationKeys(definition, configuration) {
|
|
151
|
+
if (!configuration || typeof configuration !== 'object') {
|
|
152
|
+
return [];
|
|
153
|
+
}
|
|
154
|
+
const known = configurationByPropertyKey(definition);
|
|
155
|
+
return Object.keys(configuration).filter((key) => !known.has(key));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param {Object} definition
|
|
160
|
+
* @param {Object} configuration
|
|
161
|
+
* @returns {string[]}
|
|
162
|
+
*/
|
|
163
|
+
function missingRequiredConfigurationKeys(definition, configuration) {
|
|
164
|
+
const provided = configuration && typeof configuration === 'object' ? configuration : {};
|
|
165
|
+
const missing = [];
|
|
166
|
+
for (const [propertyKey, row] of configurationByPropertyKey(definition).entries()) {
|
|
167
|
+
if (row.required === true && (provided[propertyKey] === undefined || provided[propertyKey] === '')) {
|
|
168
|
+
missing.push(propertyKey);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return missing;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const OPTION_BY_PROPERTY_KEY = {
|
|
175
|
+
commandPrefix: 'commandPrefix',
|
|
176
|
+
packageVersion: 'packageVersion',
|
|
177
|
+
oauthPluginVaultReferenceId: 'oauthPluginVaultReferenceId',
|
|
178
|
+
appDescription: 'description'
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @param {Object} options
|
|
183
|
+
* @param {Object} configuration
|
|
184
|
+
* @returns {Object}
|
|
185
|
+
*/
|
|
186
|
+
function applyConfigurationToAddOptions(options, configuration) {
|
|
187
|
+
if (!configuration || typeof configuration !== 'object') {
|
|
188
|
+
return options;
|
|
189
|
+
}
|
|
190
|
+
const next = { ...options };
|
|
191
|
+
for (const [propertyKey, value] of Object.entries(configuration)) {
|
|
192
|
+
if (SECRET_NAME_RE.test(propertyKey) && !OPTION_BY_PROPERTY_KEY[propertyKey]) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
const optionKey = OPTION_BY_PROPERTY_KEY[propertyKey] || propertyKey;
|
|
196
|
+
if (value !== undefined) {
|
|
197
|
+
next[optionKey] = value;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return next;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = {
|
|
204
|
+
envNameToPropertyKey,
|
|
205
|
+
listDefinitionConfiguration,
|
|
206
|
+
configurationByPropertyKey,
|
|
207
|
+
toSafeConfiguration,
|
|
208
|
+
toPortalFields,
|
|
209
|
+
unknownConfigurationKeys,
|
|
210
|
+
missingRequiredConfigurationKeys,
|
|
211
|
+
applyConfigurationToAddOptions,
|
|
212
|
+
isSecretShapedValue
|
|
213
|
+
};
|
|
@@ -26,7 +26,8 @@ const CREDENTIAL_SPECS = {
|
|
|
26
26
|
method: 'hmac',
|
|
27
27
|
credentialConfig: {
|
|
28
28
|
type: 'hmac',
|
|
29
|
-
signingSecret: '
|
|
29
|
+
signingSecret: 'kv://slack/signingSecret',
|
|
30
|
+
botToken: 'kv://slack/botToken',
|
|
30
31
|
algorithm: 'sha256',
|
|
31
32
|
signatureHeader: 'X-Slack-Signature',
|
|
32
33
|
timestampHeader: 'X-Slack-Request-Timestamp',
|
|
@@ -57,15 +58,6 @@ const CREDENTIAL_SPECS = {
|
|
|
57
58
|
clientSecret: 'pending-channel-install'
|
|
58
59
|
}
|
|
59
60
|
},
|
|
60
|
-
chatgpt: {
|
|
61
|
-
method: 'apiKey',
|
|
62
|
-
credentialConfig: {
|
|
63
|
-
type: 'apiKey',
|
|
64
|
-
apiKey: 'pending-channel-install',
|
|
65
|
-
headerName: 'Authorization',
|
|
66
|
-
prefix: 'Bearer'
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
61
|
'web-embed': {
|
|
70
62
|
method: 'apiKey',
|
|
71
63
|
credentialConfig: {
|
|
@@ -148,10 +140,15 @@ async function createChannelCredential(ctx, channelTarget, target) {
|
|
|
148
140
|
* @returns {Promise<{ pushed: number }>}
|
|
149
141
|
*/
|
|
150
142
|
async function pushIntegrationSecrets(ctx, channelTarget) {
|
|
151
|
-
const
|
|
152
|
-
|
|
143
|
+
const folderKey =
|
|
144
|
+
ctx && typeof ctx.instanceSystemKey === 'string' && ctx.instanceSystemKey.trim()
|
|
145
|
+
? ctx.instanceSystemKey.trim()
|
|
146
|
+
: channelTarget;
|
|
147
|
+
const integrationDir = ctx && ctx.projectRoot
|
|
148
|
+
? path.join(path.resolve(ctx.projectRoot), 'integration', folderKey)
|
|
149
|
+
: getIntegrationPath(folderKey);
|
|
153
150
|
const result = await pushCredentialSecrets(ctx.dataplaneUrl, ctx.authConfig, {
|
|
154
|
-
envFilePath:
|
|
151
|
+
envFilePath: path.join(integrationDir, '.env'),
|
|
155
152
|
appName: channelTarget,
|
|
156
153
|
quiet: true
|
|
157
154
|
});
|
|
@@ -175,7 +172,7 @@ async function ensureChannelCredential(params) {
|
|
|
175
172
|
if (skipsChannelOauthCredential(channelTarget)) {
|
|
176
173
|
return {
|
|
177
174
|
skipped: true,
|
|
178
|
-
reason: 'entraSsoTrustedIssuer',
|
|
175
|
+
reason: channelTarget === 'microsoft-copilot' ? 'entraSsoTrustedIssuer' : 'integrationClientOAuth',
|
|
179
176
|
credentialKey: target.credentialKey
|
|
180
177
|
};
|
|
181
178
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Channel Definitions into the historic CHANNEL_TARGETS row shape.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Catalog / wizard / adapter packaging from channel.json
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { definitionRuntimeSystemKey } = require('./channel-definition-registry');
|
|
12
|
+
|
|
13
|
+
const DEFAULT_CAPABILITIES = ['chat', 'notify', 'documentApproval'];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {Object} definition
|
|
17
|
+
* @returns {Object}
|
|
18
|
+
*/
|
|
19
|
+
function packagingOf(definition) {
|
|
20
|
+
const packing = definition && definition.channel && definition.channel.packaging;
|
|
21
|
+
return packing && typeof packing === 'object' ? packing : {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {Object} definition
|
|
26
|
+
* @param {Object} packing
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
function credentialKeyOf(definition, packing) {
|
|
30
|
+
const fromAuth =
|
|
31
|
+
definition.authentication && definition.authentication.credential
|
|
32
|
+
? definition.authentication.credential.credentialKey
|
|
33
|
+
: null;
|
|
34
|
+
return fromAuth || packing.credentialKey || `${definition.key}-channel`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {Object} definition
|
|
39
|
+
* @param {Object} channel
|
|
40
|
+
* @returns {Object}
|
|
41
|
+
*/
|
|
42
|
+
function runtimeTargetOf(definition, channel) {
|
|
43
|
+
return (
|
|
44
|
+
channel.runtimeTarget || {
|
|
45
|
+
defaultSystemKey: definitionRuntimeSystemKey(definition),
|
|
46
|
+
configurable: true
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {Object} definition
|
|
53
|
+
* @param {Object} packing
|
|
54
|
+
* @returns {Object}
|
|
55
|
+
*/
|
|
56
|
+
function packagingFields(definition, packing) {
|
|
57
|
+
return {
|
|
58
|
+
channelType: packing.channelType || definition.key,
|
|
59
|
+
templateDir: packing.templateDir || definition.key,
|
|
60
|
+
artifactFileName: packing.artifactFileName || `channel-${definition.key}.json`,
|
|
61
|
+
artifactFormat: packing.artifactFormat || 'json',
|
|
62
|
+
displayLabel: packing.displayLabel || definition.displayName,
|
|
63
|
+
category: packing.category || 'communication',
|
|
64
|
+
wizardOrder: Number.isInteger(packing.wizardOrder) ? packing.wizardOrder : 100,
|
|
65
|
+
remainingManualStep: packing.remainingManualStep || '',
|
|
66
|
+
docsAnchor: packing.docsAnchor || definition.key,
|
|
67
|
+
approvalRequired: packing.approvalRequired !== false,
|
|
68
|
+
vendorAuthRequired: packing.vendorAuthRequired !== false,
|
|
69
|
+
capabilities: Array.isArray(packing.capabilities)
|
|
70
|
+
? [...packing.capabilities]
|
|
71
|
+
: [...DEFAULT_CAPABILITIES]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {Object} definition
|
|
77
|
+
* @returns {Object}
|
|
78
|
+
*/
|
|
79
|
+
function toChannelTargetProjection(definition) {
|
|
80
|
+
const packing = packagingOf(definition);
|
|
81
|
+
const channel = definition.channel || {};
|
|
82
|
+
return {
|
|
83
|
+
key: definition.key,
|
|
84
|
+
...packagingFields(definition, packing),
|
|
85
|
+
credentialKey: credentialKeyOf(definition, packing),
|
|
86
|
+
description: definition.description,
|
|
87
|
+
experimental: channel.experimental === true,
|
|
88
|
+
automatedProvisioning: Boolean(channel.provisioning && channel.provisioning.mode === 'automatic'),
|
|
89
|
+
provisioning: channel.provisioning || { mode: 'guided' },
|
|
90
|
+
runtimeTarget: runtimeTargetOf(definition, channel),
|
|
91
|
+
profiles: Array.isArray(channel.profiles) ? channel.profiles.map((row) => ({ ...row })) : [],
|
|
92
|
+
definitionKey: channel.definitionKey || definition.key,
|
|
93
|
+
artifacts: Array.isArray(channel.artifacts) ? [...channel.artifacts] : []
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
packagingOf,
|
|
99
|
+
toChannelTargetProjection,
|
|
100
|
+
DEFAULT_CAPABILITIES
|
|
101
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Load Channel Definitions from templates/channels/<key>/channel.json.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Canonical ES documents plus channel specialization
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const TEMPLATES_ROOT = path.join(__dirname, '..', '..', 'templates', 'channels');
|
|
14
|
+
const DEFAULT_RUNTIME = 'runtime-orchestration';
|
|
15
|
+
|
|
16
|
+
/** @type {Map<string, Object>|null} */
|
|
17
|
+
let cachedDefinitions = null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Disk SSOT must ignore Jest `fs` mocks (brand/ is an icon pack, not a definition).
|
|
21
|
+
* @returns {typeof import('node:fs')}
|
|
22
|
+
*/
|
|
23
|
+
function channelDiskFs() {
|
|
24
|
+
const jestApi = typeof globalThis.jest === 'object' ? globalThis.jest : null;
|
|
25
|
+
if (jestApi && typeof jestApi.requireActual === 'function') {
|
|
26
|
+
return jestApi.requireActual('node:fs');
|
|
27
|
+
}
|
|
28
|
+
const snap = global.__AIFABRIX_NODE_FS_UNMOCKED__;
|
|
29
|
+
if (snap && typeof snap.readdirSync === 'function' && typeof snap.readFileSync === 'function') {
|
|
30
|
+
return snap;
|
|
31
|
+
}
|
|
32
|
+
return require('node:fs');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {string} raw
|
|
37
|
+
* @param {string} filePath
|
|
38
|
+
* @returns {Object}
|
|
39
|
+
*/
|
|
40
|
+
function parseDefinition(raw, filePath) {
|
|
41
|
+
const parsed = JSON.parse(raw);
|
|
42
|
+
if (!parsed || typeof parsed !== 'object' || typeof parsed.key !== 'string') {
|
|
43
|
+
throw new Error(`Invalid Channel Definition: ${filePath}`);
|
|
44
|
+
}
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {object} disk
|
|
50
|
+
* @param {string} templatesRoot
|
|
51
|
+
* @param {string} name
|
|
52
|
+
* @param {Map<string, Object>} map
|
|
53
|
+
* @returns {void}
|
|
54
|
+
*/
|
|
55
|
+
function loadOneDefinition(disk, templatesRoot, name, map) {
|
|
56
|
+
if (typeof name !== 'string' || name.startsWith('.')) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const filePath = path.join(templatesRoot, name, 'channel.json');
|
|
60
|
+
let raw;
|
|
61
|
+
try {
|
|
62
|
+
raw = disk.readFileSync(filePath, 'utf8');
|
|
63
|
+
} catch (err) {
|
|
64
|
+
if (err && (err.code === 'ENOENT' || err.code === 'EISDIR' || err.code === 'ENOTDIR')) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
if (typeof raw !== 'string' || !raw.trim()) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const definition = parseDefinition(raw, filePath);
|
|
73
|
+
map.set(definition.key, definition);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {string} [templatesRoot]
|
|
78
|
+
* @returns {Map<string, Object>}
|
|
79
|
+
*/
|
|
80
|
+
function loadChannelDefinitions(templatesRoot = TEMPLATES_ROOT) {
|
|
81
|
+
const disk = channelDiskFs();
|
|
82
|
+
const map = new Map();
|
|
83
|
+
let names;
|
|
84
|
+
try {
|
|
85
|
+
names = disk.readdirSync(templatesRoot);
|
|
86
|
+
} catch {
|
|
87
|
+
return map;
|
|
88
|
+
}
|
|
89
|
+
if (!Array.isArray(names)) {
|
|
90
|
+
return map;
|
|
91
|
+
}
|
|
92
|
+
for (const name of names) {
|
|
93
|
+
loadOneDefinition(disk, templatesRoot, name, map);
|
|
94
|
+
}
|
|
95
|
+
return map;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @returns {Map<string, Object>}
|
|
100
|
+
*/
|
|
101
|
+
function getChannelDefinitionMap() {
|
|
102
|
+
if (cachedDefinitions && cachedDefinitions.size > 0) {
|
|
103
|
+
return cachedDefinitions;
|
|
104
|
+
}
|
|
105
|
+
cachedDefinitions = loadChannelDefinitions();
|
|
106
|
+
return cachedDefinitions;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Test hook — clear cached definitions.
|
|
111
|
+
* @returns {void}
|
|
112
|
+
*/
|
|
113
|
+
function resetChannelDefinitionCache() {
|
|
114
|
+
cachedDefinitions = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {string} key
|
|
119
|
+
* @returns {Object|null}
|
|
120
|
+
*/
|
|
121
|
+
function getChannelDefinition(key) {
|
|
122
|
+
return getChannelDefinitionMap().get(key) || null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @returns {string[]}
|
|
127
|
+
*/
|
|
128
|
+
function listChannelDefinitionKeys() {
|
|
129
|
+
return [...getChannelDefinitionMap().keys()];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {Object} definition
|
|
134
|
+
* @returns {string}
|
|
135
|
+
*/
|
|
136
|
+
function definitionRuntimeSystemKey(definition) {
|
|
137
|
+
const fromDoc = definition && definition.channel && definition.channel.runtimeTarget;
|
|
138
|
+
if (fromDoc && typeof fromDoc.defaultSystemKey === 'string' && fromDoc.defaultSystemKey) {
|
|
139
|
+
return fromDoc.defaultSystemKey;
|
|
140
|
+
}
|
|
141
|
+
return DEFAULT_RUNTIME;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = {
|
|
145
|
+
TEMPLATES_ROOT,
|
|
146
|
+
DEFAULT_RUNTIME,
|
|
147
|
+
channelDiskFs,
|
|
148
|
+
loadChannelDefinitions,
|
|
149
|
+
getChannelDefinitionMap,
|
|
150
|
+
getChannelDefinition,
|
|
151
|
+
listChannelDefinitionKeys,
|
|
152
|
+
resetChannelDefinitionCache,
|
|
153
|
+
definitionRuntimeSystemKey
|
|
154
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Slack manifest description limits
|
|
2
|
+
* Slack manifest description limits.
|
|
3
3
|
*
|
|
4
|
-
* @fileoverview Enforce Slack display_information
|
|
4
|
+
* @fileoverview Enforce Slack display_information short and long description lengths
|
|
5
5
|
* @author AI Fabrix Team
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
@@ -11,6 +11,18 @@
|
|
|
11
11
|
/** Slack manifest `display_information.description` max (api.slack.com/reference/manifests). */
|
|
12
12
|
const SLACK_APP_DESCRIPTION_MAX_LENGTH = 140;
|
|
13
13
|
|
|
14
|
+
/** Slack App Settings reject `long_description` shorter than this. */
|
|
15
|
+
const SLACK_APP_LONG_DESCRIPTION_MIN_LENGTH = 175;
|
|
16
|
+
|
|
17
|
+
/** Slack manifest `display_information.long_description` max. */
|
|
18
|
+
const SLACK_APP_LONG_DESCRIPTION_MAX_LENGTH = 4000;
|
|
19
|
+
|
|
20
|
+
const DEFAULT_SLACK_APP_LONG_DESCRIPTION =
|
|
21
|
+
'This Slack app connects employees to governed Role Assistants. Chat in DM, ' +
|
|
22
|
+
'follow work that needs you, and open documents waiting for review. Access is ' +
|
|
23
|
+
'limited by enterprise identity, and actions stay auditable. If a Slack ' +
|
|
24
|
+
'profile email does not match a platform user, they can still link their account.';
|
|
25
|
+
|
|
14
26
|
/**
|
|
15
27
|
* @param {string} description
|
|
16
28
|
* @returns {string}
|
|
@@ -51,9 +63,54 @@ function resolveAppDescription(channelTarget, description) {
|
|
|
51
63
|
return text;
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @param {string} description
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
function normalizeSlackAppLongDescription(description) {
|
|
71
|
+
const text = String(description ?? '').trim();
|
|
72
|
+
if (text.length >= SLACK_APP_LONG_DESCRIPTION_MIN_LENGTH) {
|
|
73
|
+
return text.length > SLACK_APP_LONG_DESCRIPTION_MAX_LENGTH
|
|
74
|
+
? text.slice(0, SLACK_APP_LONG_DESCRIPTION_MAX_LENGTH)
|
|
75
|
+
: text;
|
|
76
|
+
}
|
|
77
|
+
if (!text) {
|
|
78
|
+
return DEFAULT_SLACK_APP_LONG_DESCRIPTION;
|
|
79
|
+
}
|
|
80
|
+
const combined = `${text} ${DEFAULT_SLACK_APP_LONG_DESCRIPTION}`;
|
|
81
|
+
if (combined.length > SLACK_APP_LONG_DESCRIPTION_MAX_LENGTH) {
|
|
82
|
+
return combined.slice(0, SLACK_APP_LONG_DESCRIPTION_MAX_LENGTH);
|
|
83
|
+
}
|
|
84
|
+
return combined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string} channelTarget
|
|
89
|
+
* @param {Object} runtimeValues
|
|
90
|
+
* @returns {Object}
|
|
91
|
+
*/
|
|
92
|
+
function fillSlackManifestDescriptions(channelTarget, runtimeValues) {
|
|
93
|
+
if (channelTarget !== 'slack' || !runtimeValues || typeof runtimeValues !== 'object') {
|
|
94
|
+
return runtimeValues;
|
|
95
|
+
}
|
|
96
|
+
const appLongDescription = normalizeSlackAppLongDescription(
|
|
97
|
+
runtimeValues.appLongDescription || runtimeValues.appDescription
|
|
98
|
+
);
|
|
99
|
+
return {
|
|
100
|
+
...runtimeValues,
|
|
101
|
+
appLongDescription,
|
|
102
|
+
appLongDescriptionJson: JSON.stringify(appLongDescription)
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
54
106
|
module.exports = {
|
|
55
107
|
SLACK_APP_DESCRIPTION_MAX_LENGTH,
|
|
108
|
+
SLACK_APP_LONG_DESCRIPTION_MIN_LENGTH,
|
|
109
|
+
SLACK_APP_LONG_DESCRIPTION_MAX_LENGTH,
|
|
110
|
+
DEFAULT_SLACK_APP_LONG_DESCRIPTION,
|
|
56
111
|
normalizeSlackAppDescription,
|
|
112
|
+
normalizeSlackAppLongDescription,
|
|
113
|
+
fillSlackManifestDescriptions,
|
|
57
114
|
assertSlackAppDescription,
|
|
58
115
|
resolveAppDescription
|
|
59
116
|
};
|
|
@@ -75,6 +75,18 @@ function extractGovernedToolNames(discovery) {
|
|
|
75
75
|
return tools.map((tool) => (tool && tool.name ? String(tool.name) : '')).filter(Boolean);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Live discovery uses `publication.remoteMcpReady`. Older fixtures used `mcpReady`.
|
|
80
|
+
* @param {Object|null|undefined} publication
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
function isPublicationRemoteMcpReady(publication) {
|
|
84
|
+
if (!publication || typeof publication !== 'object') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return publication.remoteMcpReady === true || publication.mcpReady === true;
|
|
88
|
+
}
|
|
89
|
+
|
|
78
90
|
/**
|
|
79
91
|
* @param {Object} discovery
|
|
80
92
|
* @param {Object|null} adapter
|
|
@@ -93,7 +105,7 @@ function resolveMcpConnection(discovery, adapter, dataplaneBaseUrl) {
|
|
|
93
105
|
'Gateway tools catalog must not be used as MCP server URL for channel packages'
|
|
94
106
|
);
|
|
95
107
|
}
|
|
96
|
-
const mcpReady = discovery
|
|
108
|
+
const mcpReady = isPublicationRemoteMcpReady(discovery && discovery.publication);
|
|
97
109
|
const connectable = adapter ? adapter.connectable === true : mcpReady;
|
|
98
110
|
const remoteAvailable = discovery?.transport?.remoteMcp?.status === 'available';
|
|
99
111
|
const installReady = Boolean(mcpReady && connectable && remoteAvailable && mcpServerUrl);
|
|
@@ -213,7 +225,8 @@ function mapDiscoveryToPackageContext(params) {
|
|
|
213
225
|
authentication: mapAdapterAuthentication(adapter?.authentication || null),
|
|
214
226
|
authenticationCapabilities: authCaps,
|
|
215
227
|
publication: {
|
|
216
|
-
mcpReady: discovery.publication
|
|
228
|
+
mcpReady: isPublicationRemoteMcpReady(discovery.publication),
|
|
229
|
+
remoteMcpReady: isPublicationRemoteMcpReady(discovery.publication),
|
|
217
230
|
environment: discovery.publication?.environment || null
|
|
218
231
|
},
|
|
219
232
|
brandingApplied: isBrandingApplied(branding)
|
|
@@ -321,6 +334,7 @@ async function loadChannelPackageContext(params) {
|
|
|
321
334
|
module.exports = {
|
|
322
335
|
GATEWAY_TOOLS_CATALOG_MARKER,
|
|
323
336
|
isGatewayToolsCatalogUrl,
|
|
337
|
+
isPublicationRemoteMcpReady,
|
|
324
338
|
resolveDiscoveryUrl,
|
|
325
339
|
mapDiscoveryToPackageContext,
|
|
326
340
|
fetchExternalAiDiscovery,
|