@aifabrix/builder 2.52.1 → 2.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app/deploy-config.js +3 -2
- package/lib/channels/add-channel.js +11 -41
- package/lib/channels/approval-guides/index.js +3 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +26 -17
- package/lib/channels/channel-add-existing.js +72 -0
- package/lib/channels/channel-runtime-resolver.js +5 -1
- package/lib/channels/channel-status-display.js +30 -3
- package/lib/channels/microsoft-copilot-entra-sso-form.js +73 -2
- package/lib/channels/microsoft-copilot-entra-sso.js +26 -5
- package/lib/channels/microsoft-copilot-limits.js +22 -3
- package/lib/channels/microsoft-copilot-package.js +59 -14
- package/lib/channels/microsoft-copilot-validate.js +40 -10
- package/lib/cli/attach-default-help-examples.js +102 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-credential-deployment.js +7 -5
- package/lib/cli/setup-utility-validate.js +1 -0
- package/lib/commands/credential-push.js +37 -5
- package/lib/commands/package-score.js +72 -0
- package/lib/commands/role-assistant.js +46 -8
- package/lib/deployment/deployer-poll-run.js +2 -2
- package/lib/deployment/deployer.js +1 -1
- package/lib/deployment/environment.js +2 -2
- package/lib/external-system/deploy.js +11 -21
- package/lib/integration-definition/apply.js +12 -14
- package/lib/integration-definition/enrich-openapi-operations.js +9 -10
- package/lib/lab/package-parity-score.js +417 -0
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/help-content/channel-onboarding.md +35 -0
- package/lib/programmatic/help-content/cip-overview.md +27 -0
- package/lib/programmatic/help-content/connected-system-ui.md +70 -0
- package/lib/programmatic/help-content/dimensions-guide.md +23 -0
- package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
- package/lib/programmatic/help-content/overview.md +25 -0
- package/lib/programmatic/help-content/subscription-guide.md +27 -0
- package/lib/programmatic/help-content/workflow.md +50 -0
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +6 -0
- package/lib/programmatic/openapi-envelope-examples.js +11 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +39 -13
- package/lib/programmatic/openapi-result-schemas.js +30 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +18 -0
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/persist-supplied-openapi.js +180 -0
- package/lib/programmatic/route-handler-map.js +6 -0
- package/lib/programmatic/run-integration-definition.js +13 -5
- package/lib/role-assistant/evidence-sync.js +55 -7
- package/lib/role-assistant/test-runner-attachments.js +118 -0
- package/lib/role-assistant/test-runner-bid-apply.js +100 -21
- package/lib/role-assistant/test-runner-bid-document.js +1 -1
- package/lib/role-assistant/test-runner-start-payload.js +96 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +11 -7
- package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
- package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
- package/lib/role-assistant/test-runner-workhub.js +68 -105
- package/lib/role-assistant/test-runner.js +5 -63
- package/lib/role-assistant/test-suite.js +33 -40
- package/lib/schema/external-datasource.schema.json +13 -4
- package/lib/utils/compose-generator.js +10 -1
- package/lib/utils/compose-traefik-extra-routes.js +107 -0
- package/lib/utils/docker-build.js +2 -2
- package/lib/utils/help-builder.js +2 -1
- package/lib/utils/promote-dev-docker-image.js +15 -10
- package/package.json +14 -16
- package/templates/README.md +12 -1
- package/templates/applications/dataplane/application.yaml +8 -1
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/miso-controller/application.yaml +2 -1
- package/templates/applications/miso-controller/rbac.yaml +1 -0
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +6 -2
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +8 -5
- package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +74 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +29 -14
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +6 -2
- package/templates/python/docker-compose.hbs +36 -0
- package/templates/typescript/docker-compose.hbs +36 -0
- package/.cursor/plans/Archive/157.1-security-quality-violations-by-type.csv +0 -374
- package/.cursor/process/README.md +0 -9
- package/.cursor/rules/anchor-docs.mdc +0 -15
- package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
- package/.cursor/rules/cli-layout.mdc +0 -81
- package/.cursor/rules/cli-product-neutral.mdc +0 -43
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
- package/.cursor/rules/docs-rules.mdc +0 -32
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
- package/.cursor/rules/project-rules.mdc +0 -913
- package/.cursor/skills/README.md +0 -15
- package/.dockerignore +0 -52
- package/.eslintignore +0 -22
- package/.markdownlint.json +0 -14
- package/anchor-docs/README.md +0 -10
- package/anchor-docs/_TEMPLATE +0 -24
- package/babel.config.js +0 -6
- package/bin/builder-api-cleanup.js +0 -26
- package/bin/builder-api-nest.js +0 -10
- package/bin/builder-api-spike.js +0 -19
- package/enterprise-knowledge/README.md +0 -50
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
- package/integration/README.md +0 -81
- package/integration/github/README.md +0 -53
- package/integration/github/application.json +0 -21
- package/integration/github/deploy.js +0 -72
- package/integration/github/env.template +0 -11
- package/integration/github/github-datasource-issue-comments.json +0 -239
- package/integration/github/github-datasource-issues.json +0 -399
- package/integration/github/github-datasource-repository.json +0 -354
- package/integration/github/github-deploy.json +0 -1202
- package/integration/github/github-system.json +0 -82
- package/integration/hubspot-test/README.md +0 -159
- package/integration/hubspot-test/application.json +0 -54
- package/integration/hubspot-test/companies.json +0 -2048
- package/integration/hubspot-test/create-hubspot.js +0 -523
- package/integration/hubspot-test/env.template +0 -4
- package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
- package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
- package/integration/hubspot-test/hubspot-test-system.json +0 -74
- package/integration/hubspot-test/rbac.json +0 -166
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
- package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
- package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
- package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
- package/integration/hubspot-test/test-dataplane-down.js +0 -209
- package/integration/hubspot-test/test.js +0 -1588
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
- package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
- package/integration/roundtrip-test-local/README.md +0 -143
- package/integration/roundtrip-test-local/application.yaml +0 -13
- package/integration/roundtrip-test-local/env.template +0 -15
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
- package/integration/roundtrip-test-local2/README.md +0 -143
- package/integration/roundtrip-test-local2/application.yaml +0 -13
- package/integration/roundtrip-test-local2/env.template +0 -15
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
- package/integration/test/wizard.yaml +0 -8
- package/jest.config.coverage.js +0 -37
- package/jest.config.default.js +0 -11
- package/jest.config.integration.fixtures.js +0 -22
- package/jest.config.integration.js +0 -33
- package/jest.config.isolated.js +0 -11
- package/jest.config.manual.js +0 -30
- package/jest.global-live-fabrix-hooks.js +0 -36
- package/jest.isolated-projects.js +0 -283
- package/jest.projects.js +0 -79
- package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +0 -205
- package/packages/builder-api/README.md +0 -120
- package/packages/builder-api/package.json +0 -30
- package/packages/builder-api/src/app.module.ts +0 -7
- package/packages/builder-api/src/auth/auth.module.ts +0 -5
- package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
- package/packages/builder-api/src/main.ts +0 -16
- package/packages/builder-api/tsconfig.json +0 -15
- package/scripts/check-builder-api-architecture-grep.js +0 -79
- package/scripts/check-datasource-test-run-schema-sync.js +0 -34
- package/scripts/ci-fix.sh +0 -19
- package/scripts/ci-simulate.sh +0 -19
- package/scripts/diagnose-cli.js +0 -150
- package/scripts/docker_image_content_gate.js +0 -47
- package/scripts/docker_image_content_gate.sh +0 -5
- package/scripts/export-builder-api-evidence.js +0 -262
- package/scripts/install-local.js +0 -490
- package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
- package/scripts/lib/builder-api-docker-staging-core.js +0 -183
- package/scripts/lib/docker-image-content-gate-core.js +0 -166
- package/scripts/lib/plan-actor.js +0 -109
- package/scripts/lib/plan-config.js +0 -20
- package/scripts/lib/plan-gates.js +0 -154
- package/scripts/lib/plan-meta.js +0 -104
- package/scripts/lib/plan-parse.js +0 -162
- package/scripts/lib/plan-prevalidate-gates.js +0 -337
- package/scripts/lib/plan-run-core.js +0 -125
- package/scripts/lib/plan-run-report.js +0 -119
- package/scripts/plan-approve.js +0 -24
- package/scripts/plan-archive.js +0 -49
- package/scripts/plan-run.js +0 -13
- package/scripts/plan-set-actor.js +0 -21
- package/scripts/plan-validate.js +0 -80
- package/scripts/pnpm/af.mjs +0 -125
- package/scripts/pnpm/check-quiet.mjs +0 -32
- package/scripts/pnpm/dev-install.mjs +0 -29
- package/scripts/pnpm/dev-reload.mjs +0 -18
- package/scripts/pnpm/help.mjs +0 -55
- package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
- package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
- package/scripts/pnpm/lib/spinner.mjs +0 -42
- package/scripts/pnpm-global-remove.js +0 -48
- package/scripts/stage_builder_api_for_docker.js +0 -65
- package/scripts/sync-builder-api-template.js +0 -44
- package/scripts/test-dataplane-bootstrap.js +0 -331
package/lib/app/deploy-config.js
CHANGED
|
@@ -78,9 +78,10 @@ async function extractDeploymentConfig(options, _variables) {
|
|
|
78
78
|
// Used by guided installers which already show a top-level spinner.
|
|
79
79
|
silentPoll: options.silentPoll === true,
|
|
80
80
|
repositoryUrl: options.repositoryUrl,
|
|
81
|
-
// Omit default here so deployer can resolve
|
|
81
|
+
// Omit default here so deployer can resolve 1s vs 5s from controller deploymentType (GET /api/v1/health)
|
|
82
82
|
pollInterval: Number.isFinite(pollIntervalExplicit) ? pollIntervalExplicit : undefined,
|
|
83
|
-
|
|
83
|
+
// Default 300 attempts: ~5 min at 1s (local) / ~25 min at 5s (azure) — deploy may run tests/gates
|
|
84
|
+
pollMaxAttempts: options.pollMaxAttempts || 300,
|
|
84
85
|
deploymentAuth: options.deploymentAuth
|
|
85
86
|
};
|
|
86
87
|
}
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
const path = require('path');
|
|
11
12
|
const { getChannelTarget, getDefaultChannelDescription } = require('./channel-targets');
|
|
12
13
|
const { resolveAppDescription } = require('./channel-description');
|
|
13
|
-
const path = require('path');
|
|
14
14
|
const { resolveChannelRuntimeValues } = require('./channel-runtime-resolver');
|
|
15
15
|
const { generateChannelArtifact } = require('./channel-artifact-generator');
|
|
16
16
|
const { fetchRuntimeLayerBToolNames } = require('./runtime-tool-catalog');
|
|
@@ -43,11 +43,9 @@ const {
|
|
|
43
43
|
normalizeBaseChannelName,
|
|
44
44
|
resolveChannelDisplayName
|
|
45
45
|
} = require('./channel-display-name');
|
|
46
|
-
const {
|
|
47
|
-
displayExistingChannelStatus,
|
|
48
|
-
displayChannelInstallResult
|
|
49
|
-
} = require('./channel-status-display');
|
|
46
|
+
const { displayChannelInstallResult } = require('./channel-status-display');
|
|
50
47
|
const { ensureChannelReadyForAdd } = require('./channel-add-ensure');
|
|
48
|
+
const { showExistingChannelStatus } = require('./channel-add-existing');
|
|
51
49
|
const {
|
|
52
50
|
assertMicrosoftCopilotOauthReference,
|
|
53
51
|
assertMicrosoftCopilotOauthReferenceBeforeForce,
|
|
@@ -84,41 +82,6 @@ function toValidationDisplay(validation) {
|
|
|
84
82
|
};
|
|
85
83
|
}
|
|
86
84
|
|
|
87
|
-
/**
|
|
88
|
-
* @param {Object} params
|
|
89
|
-
* @returns {Object|null}
|
|
90
|
-
*/
|
|
91
|
-
function showExistingChannelStatus(params) {
|
|
92
|
-
const { existing, options, channelTarget, name, baseName, ctx } = params;
|
|
93
|
-
if (!existing || options.force || options.dryRun) return null;
|
|
94
|
-
const sameInstall =
|
|
95
|
-
(existing.baseName && existing.baseName === baseName) ||
|
|
96
|
-
(!existing.baseName && existing.name === name);
|
|
97
|
-
if (!sameInstall) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
`Channel already configured as "${existing.name}". ` +
|
|
100
|
-
`Use --force to replace with "${name}".`
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
const projectRoot = options.projectRoot || process.cwd();
|
|
104
|
-
const approvalGuide =
|
|
105
|
-
existing.status === 'approvalRequired'
|
|
106
|
-
? buildChannelApprovalGuide(channelTarget, {
|
|
107
|
-
projectRoot,
|
|
108
|
-
name: existing.name || name,
|
|
109
|
-
baseName,
|
|
110
|
-
dataplaneBaseUrl: ctx?.dataplaneUrl
|
|
111
|
-
})
|
|
112
|
-
: null;
|
|
113
|
-
displayExistingChannelStatus({
|
|
114
|
-
channelTarget,
|
|
115
|
-
name: existing.name || name,
|
|
116
|
-
channelExt: existing,
|
|
117
|
-
approvalGuide
|
|
118
|
-
});
|
|
119
|
-
return { skipped: true, channelExt: existing };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
85
|
/**
|
|
123
86
|
* @param {string} channelTarget
|
|
124
87
|
* @param {Object} artifactParams
|
|
@@ -245,7 +208,8 @@ async function completeLiveInstall(params) {
|
|
|
245
208
|
name,
|
|
246
209
|
baseName,
|
|
247
210
|
artifactPath: artifact.outputPath,
|
|
248
|
-
dataplaneBaseUrl: ctx.dataplaneUrl
|
|
211
|
+
dataplaneBaseUrl: ctx.dataplaneUrl,
|
|
212
|
+
environment: ctx.environment || options.environment || 'dev'
|
|
249
213
|
})
|
|
250
214
|
: null;
|
|
251
215
|
if (approvalGuide?.portalUrl) {
|
|
@@ -266,6 +230,12 @@ async function completeLiveInstall(params) {
|
|
|
266
230
|
zipPath: artifact.zipPath,
|
|
267
231
|
installReady: artifact.installReady,
|
|
268
232
|
blocker: artifact.blocker,
|
|
233
|
+
packageReady: artifact.packageReady,
|
|
234
|
+
packageBlocker: artifact.packageBlocker,
|
|
235
|
+
microsoftPublicationPending:
|
|
236
|
+
artifact.microsoftPublicationPending !== undefined
|
|
237
|
+
? artifact.microsoftPublicationPending
|
|
238
|
+
: status === 'approvalRequired',
|
|
269
239
|
validation: toValidationDisplay(validation),
|
|
270
240
|
approvalGuide
|
|
271
241
|
});
|
|
@@ -71,6 +71,9 @@ function buildChannelApprovalGuide(channelTarget, context = {}) {
|
|
|
71
71
|
: null;
|
|
72
72
|
const baseCtx = {
|
|
73
73
|
channelTarget,
|
|
74
|
+
name,
|
|
75
|
+
baseName: context.baseName || name,
|
|
76
|
+
environment: context.environment || 'dev',
|
|
74
77
|
artifactPath,
|
|
75
78
|
resumeCommand,
|
|
76
79
|
credentialKey: target.credentialKey,
|
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Microsoft Copilot channel install / approval steps.
|
|
3
3
|
*
|
|
4
|
-
* @fileoverview
|
|
4
|
+
* @fileoverview Organisation publish via Developer Portal + Teams admin approval
|
|
5
5
|
* @author AI Fabrix Team
|
|
6
|
-
* @version 1.
|
|
6
|
+
* @version 1.2.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
} = require('../microsoft-copilot-entra-sso-form');
|
|
11
|
+
const DEVELOPER_PORTAL_URL = 'https://dev.teams.microsoft.com/';
|
|
12
|
+
const TEAMS_ADMIN_APPS_URL = 'https://admin.teams.microsoft.com/policies/manage-apps';
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* @param {Object} ctx
|
|
17
16
|
* @returns {{ portalUrl: string, steps: string[] }}
|
|
18
17
|
*/
|
|
19
18
|
function buildMicrosoftCopilotApprovalGuide(ctx) {
|
|
19
|
+
const env = typeof ctx.environment === 'string' && ctx.environment.trim()
|
|
20
|
+
? ctx.environment.trim()
|
|
21
|
+
: 'dev';
|
|
22
|
+
const zipName = `appPackage.${env}.zip`;
|
|
23
|
+
const appName =
|
|
24
|
+
(typeof ctx.name === 'string' && ctx.name.trim()) ||
|
|
25
|
+
(typeof ctx.baseName === 'string' && ctx.baseName.trim()) ||
|
|
26
|
+
'your app';
|
|
20
27
|
return {
|
|
21
|
-
portalUrl:
|
|
28
|
+
portalUrl: DEVELOPER_PORTAL_URL,
|
|
22
29
|
steps: [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
'
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'Confirm Runtime MCP and governed tools using INSTALL.md, then re-run with --probe after Teams install.',
|
|
32
|
-
`After the app is available in Teams, re-run: ${ctx.resumeCommand}`
|
|
30
|
+
`Open Teams Developer Portal (${DEVELOPER_PORTAL_URL}).`,
|
|
31
|
+
`Click Import an app → import ${zipName}. Preserve the generated stable manifest.json.id. Do not create an unrelated new Teams app.`,
|
|
32
|
+
'Developer Portal → selected app → Publish to your org → Distribute / submit.',
|
|
33
|
+
`Teams admin approves in ${TEAMS_ADMIN_APPS_URL} (Manage apps → search → allow). Expect Published / Unblocked per organisation policy. Allow several minutes for propagation.`,
|
|
34
|
+
`Open Teams → Apps (Built for your org), click "${appName}", Add the application, then choose Open with Copilot.`,
|
|
35
|
+
'In Copilot, click "Show my role assistants" and run the command.',
|
|
36
|
+
'Confirm Runtime MCP and governed tools using INSTALL.md, then re-run with --probe after organisation publish.',
|
|
37
|
+
`After the app is available under Built for your org, re-run: ${ctx.resumeCommand}`
|
|
33
38
|
]
|
|
34
39
|
};
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
module.exports = {
|
|
42
|
+
module.exports = {
|
|
43
|
+
buildMicrosoftCopilotApprovalGuide,
|
|
44
|
+
DEVELOPER_PORTAL_URL,
|
|
45
|
+
TEAMS_ADMIN_APPS_URL
|
|
46
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Existing-channel skip path for aifabrix channel add.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Keep add-channel.js under the 500-line limit
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { getArtifactOutputPath } = require('./channel-artifact-generator');
|
|
14
|
+
const { buildChannelApprovalGuide } = require('./channel-approval-guide');
|
|
15
|
+
const { displayExistingChannelStatus } = require('./channel-status-display');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* True when local channel package files are present under dist/channels/<target>/.
|
|
19
|
+
* @param {string} projectRoot
|
|
20
|
+
* @param {string} channelTarget
|
|
21
|
+
* @returns {boolean}
|
|
22
|
+
*/
|
|
23
|
+
function localChannelArtifactsExist(projectRoot, channelTarget) {
|
|
24
|
+
const summaryPath = getArtifactOutputPath(projectRoot, channelTarget);
|
|
25
|
+
const installPath = path.join(path.dirname(summaryPath), 'INSTALL.md');
|
|
26
|
+
return fs.existsSync(summaryPath) && fs.existsSync(installPath);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {Object} params
|
|
31
|
+
* @returns {Object|null}
|
|
32
|
+
*/
|
|
33
|
+
function showExistingChannelStatus(params) {
|
|
34
|
+
const { existing, options, channelTarget, name, baseName, ctx } = params;
|
|
35
|
+
if (!existing || options.force || options.dryRun) return null;
|
|
36
|
+
const sameInstall =
|
|
37
|
+
(existing.baseName && existing.baseName === baseName) ||
|
|
38
|
+
(!existing.baseName && existing.name === name);
|
|
39
|
+
if (!sameInstall) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Channel already configured as "${existing.name}". ` +
|
|
42
|
+
`Use --force to replace with "${name}".`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
46
|
+
// Dataplane may still have the channel while local dist/ was deleted — regenerate.
|
|
47
|
+
if (!localChannelArtifactsExist(projectRoot, channelTarget)) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const approvalGuide =
|
|
51
|
+
existing.status === 'approvalRequired'
|
|
52
|
+
? buildChannelApprovalGuide(channelTarget, {
|
|
53
|
+
projectRoot,
|
|
54
|
+
name: existing.name || name,
|
|
55
|
+
baseName,
|
|
56
|
+
dataplaneBaseUrl: ctx?.dataplaneUrl,
|
|
57
|
+
environment: ctx?.environment || 'dev'
|
|
58
|
+
})
|
|
59
|
+
: null;
|
|
60
|
+
displayExistingChannelStatus({
|
|
61
|
+
channelTarget,
|
|
62
|
+
name: existing.name || name,
|
|
63
|
+
channelExt: existing,
|
|
64
|
+
approvalGuide
|
|
65
|
+
});
|
|
66
|
+
return { skipped: true, channelExt: existing };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
localChannelArtifactsExist,
|
|
71
|
+
showExistingChannelStatus
|
|
72
|
+
};
|
|
@@ -247,10 +247,14 @@ function applyMicrosoftCopilotRuntimeValues(resolved, params) {
|
|
|
247
247
|
packageContext: params.packageContext,
|
|
248
248
|
oauthPluginVaultReferenceId: resolved.oauthPluginVaultReferenceId,
|
|
249
249
|
scopes: resolved.scopes,
|
|
250
|
-
entraProvider: params.entraProvider || null
|
|
250
|
+
entraProvider: params.entraProvider || null,
|
|
251
|
+
mcpServerUrl: resolved.mcpUrl || null
|
|
251
252
|
});
|
|
252
253
|
resolved.installReady = readiness.installReady;
|
|
253
254
|
resolved.discoveryBlocker = readiness.blocker;
|
|
255
|
+
resolved.packageReady = readiness.packageReady;
|
|
256
|
+
resolved.packageBlocker = readiness.packageBlocker;
|
|
257
|
+
resolved.microsoftPublicationPending = readiness.microsoftPublicationPending !== false;
|
|
254
258
|
resolved.discoveryAuthentication = readiness.packageAuthentication;
|
|
255
259
|
if (params.entraProvider?.issuer) {
|
|
256
260
|
resolved.entraIssuer = params.entraProvider.issuer;
|
|
@@ -55,10 +55,10 @@ function displayApprovalGuideSection(approvalGuide) {
|
|
|
55
55
|
const heading =
|
|
56
56
|
approvalGuide.approvalRequired === false
|
|
57
57
|
? 'Go-live steps'
|
|
58
|
-
: '
|
|
58
|
+
: 'Organisation publish / Teams admin approval required';
|
|
59
59
|
logger.log(formatWarningLine(heading));
|
|
60
60
|
if (approvalGuide.portalUrl) {
|
|
61
|
-
logger.log(metadata('
|
|
61
|
+
logger.log(metadata('Developer Portal:'));
|
|
62
62
|
logger.log(chalk.cyan(approvalGuide.portalUrl));
|
|
63
63
|
}
|
|
64
64
|
logger.log('');
|
|
@@ -130,7 +130,34 @@ function displayChannelCoreFields(result) {
|
|
|
130
130
|
if (result.zipPath) {
|
|
131
131
|
logger.log(metadata(`Package ZIP: ${result.zipPath}`));
|
|
132
132
|
}
|
|
133
|
-
|
|
133
|
+
displayReadinessLines(result);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Split package/Runtime readiness from Microsoft organisation publication.
|
|
138
|
+
* @param {Object} result
|
|
139
|
+
*/
|
|
140
|
+
function displayReadinessLines(result) {
|
|
141
|
+
const packageReady =
|
|
142
|
+
result.packageReady === true ||
|
|
143
|
+
(result.packageReady === undefined && result.installReady === true);
|
|
144
|
+
const packageBlocker = result.packageBlocker || result.blocker || null;
|
|
145
|
+
if (packageReady) {
|
|
146
|
+
logger.log(metadata('Package / Runtime ready: yes'));
|
|
147
|
+
} else if (packageBlocker) {
|
|
148
|
+
logger.log(metadata(`Package / Runtime ready: no (${packageBlocker})`));
|
|
149
|
+
} else if (result.installReady === false) {
|
|
150
|
+
logger.log(metadata('Package / Runtime ready: no'));
|
|
151
|
+
}
|
|
152
|
+
if (result.microsoftPublicationPending === true) {
|
|
153
|
+
logger.log(
|
|
154
|
+
metadata(
|
|
155
|
+
'Microsoft publication: pending (Developer Portal import → Publish to your org → Teams admin approval)'
|
|
156
|
+
)
|
|
157
|
+
);
|
|
158
|
+
} else if (result.microsoftPublicationPending === false) {
|
|
159
|
+
logger.log(metadata('Microsoft publication: cleared'));
|
|
160
|
+
} else if (result.installReady === false && result.blocker && !packageBlocker) {
|
|
134
161
|
logger.log(metadata(`Install ready: no (${result.blocker})`));
|
|
135
162
|
}
|
|
136
163
|
}
|
|
@@ -101,8 +101,10 @@ function applyCopilotEntraSsoFormFields(resolved, params = {}) {
|
|
|
101
101
|
const entraIdentityProvider = params.entraIdentityProvider || null;
|
|
102
102
|
const auth = resolved.discoveryAuthentication || null;
|
|
103
103
|
resolved.entraSsoRegistrationUrl = ENTRA_SSO_REGISTRATION_URL;
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
// Teams Entra SSO form Base URL = exact Remote MCP URL from package discovery.
|
|
105
|
+
const mcpUrl =
|
|
106
|
+
(typeof resolved.mcpUrl === 'string' && resolved.mcpUrl.trim()) || null;
|
|
107
|
+
resolved.entraSsoBaseUrl = mcpUrl || originFromUrl(resolved.dataplaneBaseUrl) || null;
|
|
106
108
|
resolved.entraSsoClientId = resolveEntraSsoClientId(
|
|
107
109
|
entraIdentityProvider,
|
|
108
110
|
entraProvider,
|
|
@@ -119,6 +121,73 @@ function applyCopilotEntraSsoFormFields(resolved, params = {}) {
|
|
|
119
121
|
if (entraIdentityProvider?.enterpriseAppId) {
|
|
120
122
|
resolved.entraEnterpriseAppId = String(entraIdentityProvider.enterpriseAppId).trim();
|
|
121
123
|
}
|
|
124
|
+
applyWebApplicationInfoFields(resolved, params);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const TEAMS_AUTH_CONFIG_GUID =
|
|
128
|
+
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {string|unknown} value
|
|
132
|
+
* @returns {string}
|
|
133
|
+
*/
|
|
134
|
+
function trimNonEmptyString(value) {
|
|
135
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Teams Entra SSO Application ID URI: api://auth-{authConfigId}/{clientId}.
|
|
140
|
+
* Only when oauthPluginVaultReferenceId is a GUID (Teams auth-config id).
|
|
141
|
+
* @param {string|null} authConfigId
|
|
142
|
+
* @param {string|null} clientId
|
|
143
|
+
* @returns {string|null}
|
|
144
|
+
*/
|
|
145
|
+
function buildTeamsWebApplicationInfoResource(authConfigId, clientId) {
|
|
146
|
+
const configId = trimNonEmptyString(authConfigId);
|
|
147
|
+
const appId = trimNonEmptyString(clientId);
|
|
148
|
+
if (!configId || !TEAMS_AUTH_CONFIG_GUID.test(configId) || !appId) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
return `api://auth-${configId}/${appId}`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @param {Object} resolved
|
|
156
|
+
* @returns {string|null}
|
|
157
|
+
*/
|
|
158
|
+
function resolveWebApplicationClientId(resolved) {
|
|
159
|
+
return (
|
|
160
|
+
trimNonEmptyString(resolved.entraSsoClientId) ||
|
|
161
|
+
trimNonEmptyString(resolved.entraEnterpriseAppId) ||
|
|
162
|
+
null
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Preserve / derive Teams webApplicationInfo for Entra SSO packages.
|
|
168
|
+
* Prefer explicit params, then prior package values, then GUID auth-config + SSO client id.
|
|
169
|
+
* Do not invent resource URIs from opaque (non-GUID) vault references.
|
|
170
|
+
* @param {Object} resolved
|
|
171
|
+
* @param {Object} params
|
|
172
|
+
* @returns {void}
|
|
173
|
+
*/
|
|
174
|
+
function applyWebApplicationInfoFields(resolved, params = {}) {
|
|
175
|
+
const prior = params.priorWebApplicationInfo || null;
|
|
176
|
+
const explicitId = trimNonEmptyString(params.webApplicationInfoId);
|
|
177
|
+
const explicitResource = trimNonEmptyString(params.webApplicationInfoResource);
|
|
178
|
+
const priorId = trimNonEmptyString(prior && prior.id);
|
|
179
|
+
const priorResource = trimNonEmptyString(prior && prior.resource);
|
|
180
|
+
const clientId = resolveWebApplicationClientId(resolved);
|
|
181
|
+
const derivedResource = buildTeamsWebApplicationInfoResource(
|
|
182
|
+
resolved.oauthPluginVaultReferenceId,
|
|
183
|
+
clientId
|
|
184
|
+
);
|
|
185
|
+
const id = explicitId || priorId || (derivedResource ? clientId : null);
|
|
186
|
+
const resource = explicitResource || priorResource || derivedResource || null;
|
|
187
|
+
if (id && resource) {
|
|
188
|
+
resolved.webApplicationInfoId = id;
|
|
189
|
+
resolved.webApplicationInfoResource = resource;
|
|
190
|
+
}
|
|
122
191
|
}
|
|
123
192
|
|
|
124
193
|
/**
|
|
@@ -175,6 +244,8 @@ module.exports = {
|
|
|
175
244
|
resolveEntraSsoClientId,
|
|
176
245
|
resolveEntraTenantId,
|
|
177
246
|
applyCopilotEntraSsoFormFields,
|
|
247
|
+
applyWebApplicationInfoFields,
|
|
248
|
+
buildTeamsWebApplicationInfoResource,
|
|
178
249
|
renderCopilotChannelTemplate,
|
|
179
250
|
formatOauthPluginVaultReferenceRequiredError
|
|
180
251
|
};
|
|
@@ -131,6 +131,9 @@ function resolveCopilotEntraScopes(params) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
|
+
* Package/Runtime readiness blocker (not Microsoft org-publish state).
|
|
135
|
+
* Having a Remote MCP URL is enough for packaging even when live remote status
|
|
136
|
+
* is temporarily unavailable — Microsoft publication is tracked separately.
|
|
134
137
|
* @param {Object} params
|
|
135
138
|
* @returns {string|null}
|
|
136
139
|
*/
|
|
@@ -138,13 +141,15 @@ function firstCopilotEntraBlocker(params) {
|
|
|
138
141
|
const {
|
|
139
142
|
discoveryReady,
|
|
140
143
|
discoveryBlocker,
|
|
144
|
+
mcpServerUrl,
|
|
141
145
|
recommended,
|
|
142
146
|
referenceId,
|
|
143
147
|
issuer,
|
|
144
148
|
audience,
|
|
145
149
|
scopes
|
|
146
150
|
} = params;
|
|
147
|
-
|
|
151
|
+
const hasMcpUrl = typeof mcpServerUrl === 'string' && mcpServerUrl.trim();
|
|
152
|
+
if (!hasMcpUrl && !discoveryReady) {
|
|
148
153
|
return discoveryBlocker || 'remoteMcpUnavailable';
|
|
149
154
|
}
|
|
150
155
|
if (recommended !== TRUSTED_ISSUER) {
|
|
@@ -185,7 +190,14 @@ function resolveAudienceAndIssuer(auth, entraProvider) {
|
|
|
185
190
|
|
|
186
191
|
/**
|
|
187
192
|
* @param {Object} params
|
|
188
|
-
* @returns {{
|
|
193
|
+
* @returns {{
|
|
194
|
+
* installReady: boolean,
|
|
195
|
+
* blocker: string|null,
|
|
196
|
+
* packageReady: boolean,
|
|
197
|
+
* packageBlocker: string|null,
|
|
198
|
+
* microsoftPublicationPending: boolean,
|
|
199
|
+
* packageAuthentication: Object|null
|
|
200
|
+
* }}
|
|
189
201
|
*/
|
|
190
202
|
function evaluateCopilotEntraSsoReadiness(params) {
|
|
191
203
|
const packageContext = params.packageContext || null;
|
|
@@ -197,6 +209,10 @@ function evaluateCopilotEntraSsoReadiness(params) {
|
|
|
197
209
|
: '';
|
|
198
210
|
const scopes = normalizeScopeList(params.scopes);
|
|
199
211
|
const { audience, issuer } = resolveAudienceAndIssuer(auth, params.entraProvider || null);
|
|
212
|
+
const mcpServerUrl =
|
|
213
|
+
(typeof packageContext?.mcpServerUrl === 'string' && packageContext.mcpServerUrl.trim()) ||
|
|
214
|
+
(typeof params.mcpServerUrl === 'string' && params.mcpServerUrl.trim()) ||
|
|
215
|
+
null;
|
|
200
216
|
|
|
201
217
|
if (auth) {
|
|
202
218
|
auth.issuer = issuer;
|
|
@@ -204,18 +220,23 @@ function evaluateCopilotEntraSsoReadiness(params) {
|
|
|
204
220
|
auth.scopes = scopes;
|
|
205
221
|
}
|
|
206
222
|
|
|
207
|
-
const
|
|
223
|
+
const packageBlocker = firstCopilotEntraBlocker({
|
|
208
224
|
discoveryReady: packageContext?.installReady === true,
|
|
209
225
|
discoveryBlocker: packageContext?.blocker || null,
|
|
226
|
+
mcpServerUrl,
|
|
210
227
|
recommended,
|
|
211
228
|
referenceId,
|
|
212
229
|
issuer,
|
|
213
230
|
audience,
|
|
214
231
|
scopes
|
|
215
232
|
});
|
|
233
|
+
const packageReady = packageBlocker === null;
|
|
216
234
|
return {
|
|
217
|
-
installReady:
|
|
218
|
-
blocker,
|
|
235
|
+
installReady: packageReady,
|
|
236
|
+
blocker: packageBlocker,
|
|
237
|
+
packageReady,
|
|
238
|
+
packageBlocker,
|
|
239
|
+
microsoftPublicationPending: true,
|
|
219
240
|
packageAuthentication: auth
|
|
220
241
|
};
|
|
221
242
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @fileoverview Truncate and normalize Copilot package display fields to schema limits
|
|
5
5
|
* @author AI Fabrix Team
|
|
6
|
-
* @version 1.
|
|
6
|
+
* @version 1.1.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
@@ -15,6 +15,11 @@ const TEAMS_DESCRIPTION_FULL_MAX = 4000;
|
|
|
15
15
|
const PLUGIN_NAME_FOR_HUMAN_MAX = 20;
|
|
16
16
|
const PLUGIN_DESCRIPTION_FOR_HUMAN_MAX = 100;
|
|
17
17
|
|
|
18
|
+
const FI_DEFAULT_SHORT =
|
|
19
|
+
'Yrityksen tekoälyavustaja työntekijöille AI Fabrix Runtime -ympäristössä.';
|
|
20
|
+
const FI_DEFAULT_FULL =
|
|
21
|
+
'Yrityksen tekoälyavustaja työntekijöille. Hyväksytyt avustajat, yritystieto, työnkulut ja hallitut toiminnot AI Fabrixin kautta.';
|
|
22
|
+
|
|
18
23
|
/**
|
|
19
24
|
* @param {string} text
|
|
20
25
|
* @param {number} max
|
|
@@ -52,7 +57,8 @@ function applyMicrosoftCopilotDisplayLimits(runtimeValues) {
|
|
|
52
57
|
const appDescription = String(runtimeValues.appDescription || '').trim();
|
|
53
58
|
const baseName = String(runtimeValues.baseName || runtimeValues.appName || 'Assistant').trim();
|
|
54
59
|
const appName = String(runtimeValues.appName || baseName).trim();
|
|
55
|
-
|
|
60
|
+
// Teams short + full both use the environment-scoped display name (e.g. "Onni (dev)").
|
|
61
|
+
runtimeValues.shortName = truncateForSchema(appName, TEAMS_NAME_SHORT_MAX);
|
|
56
62
|
runtimeValues.fullName = truncateForSchema(appName, TEAMS_NAME_FULL_MAX);
|
|
57
63
|
runtimeValues.shortDescription = truncateForSchema(
|
|
58
64
|
appDescription || 'Enterprise AI assistant via AI Fabrix Runtime.',
|
|
@@ -62,12 +68,23 @@ function applyMicrosoftCopilotDisplayLimits(runtimeValues) {
|
|
|
62
68
|
appDescription || runtimeValues.shortDescription,
|
|
63
69
|
TEAMS_DESCRIPTION_FULL_MAX
|
|
64
70
|
);
|
|
65
|
-
|
|
71
|
+
// Plugin name_for_human matches the env-scoped display name (e.g. "Onni (dev)").
|
|
72
|
+
runtimeValues.pluginNameForHuman = truncateForSchema(appName, PLUGIN_NAME_FOR_HUMAN_MAX);
|
|
66
73
|
runtimeValues.pluginDescriptionForHuman = truncateForSchema(
|
|
67
74
|
appDescription || runtimeValues.shortDescription,
|
|
68
75
|
PLUGIN_DESCRIPTION_FOR_HUMAN_MAX
|
|
69
76
|
);
|
|
70
77
|
runtimeValues.pluginNamespace = buildPluginNamespace(baseName);
|
|
78
|
+
const fiShort =
|
|
79
|
+
typeof runtimeValues.fiShortDescription === 'string' && runtimeValues.fiShortDescription.trim()
|
|
80
|
+
? runtimeValues.fiShortDescription.trim()
|
|
81
|
+
: FI_DEFAULT_SHORT;
|
|
82
|
+
const fiFull =
|
|
83
|
+
typeof runtimeValues.fiFullDescription === 'string' && runtimeValues.fiFullDescription.trim()
|
|
84
|
+
? runtimeValues.fiFullDescription.trim()
|
|
85
|
+
: FI_DEFAULT_FULL;
|
|
86
|
+
runtimeValues.fiShortDescription = truncateForSchema(fiShort, TEAMS_DESCRIPTION_SHORT_MAX);
|
|
87
|
+
runtimeValues.fiFullDescription = truncateForSchema(fiFull, TEAMS_DESCRIPTION_FULL_MAX);
|
|
71
88
|
return runtimeValues;
|
|
72
89
|
}
|
|
73
90
|
|
|
@@ -78,6 +95,8 @@ module.exports = {
|
|
|
78
95
|
TEAMS_DESCRIPTION_FULL_MAX,
|
|
79
96
|
PLUGIN_NAME_FOR_HUMAN_MAX,
|
|
80
97
|
PLUGIN_DESCRIPTION_FOR_HUMAN_MAX,
|
|
98
|
+
FI_DEFAULT_SHORT,
|
|
99
|
+
FI_DEFAULT_FULL,
|
|
81
100
|
truncateForSchema,
|
|
82
101
|
buildPluginNamespace,
|
|
83
102
|
applyMicrosoftCopilotDisplayLimits
|