@aifabrix/builder 2.52.0 → 2.52.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/jest.isolated-projects.js +25 -2
- package/jest.projects.js +4 -1
- package/lib/api/datasources-extended.api.js +8 -8
- package/lib/api/keycloak.api.js +92 -0
- package/lib/api/token-providers.api.js +77 -0
- package/lib/api/types/keycloak.types.js +23 -0
- package/lib/api/types/token-providers.types.js +65 -0
- package/lib/app/down.js +16 -1
- package/lib/channels/add-channel.js +126 -19
- package/lib/channels/approval-guides/chatgpt.js +1 -1
- package/lib/channels/approval-guides/microsoft-copilot.js +16 -12
- package/lib/channels/channel-add-ensure.js +128 -0
- package/lib/channels/channel-artifact-generator.js +11 -1
- package/lib/channels/channel-branding.js +94 -0
- package/lib/channels/channel-credential.js +8 -0
- package/lib/channels/channel-discovery.js +330 -0
- package/lib/channels/channel-external-system.js +1 -1
- package/lib/channels/channel-runtime-resolver.js +103 -14
- package/lib/channels/channel-status-display.js +7 -1
- package/lib/channels/microsoft-copilot-channel-add.js +138 -0
- package/lib/channels/microsoft-copilot-entra-sso-form.js +180 -0
- package/lib/channels/microsoft-copilot-entra-sso.js +264 -0
- package/lib/channels/microsoft-copilot-icons.js +74 -0
- package/lib/channels/microsoft-copilot-limits.js +84 -0
- package/lib/channels/microsoft-copilot-package.js +130 -49
- package/lib/channels/microsoft-copilot-validate.js +197 -0
- package/lib/cli/index.js +2 -0
- package/lib/cli/infra-guided.js +13 -6
- package/lib/cli/setup-infra.js +31 -4
- package/lib/commands/channel-add-setup.js +28 -9
- package/lib/commands/channel.js +14 -10
- package/lib/commands/integration-definition.js +158 -0
- package/lib/commands/repair-auth-apply.js +19 -5
- package/lib/commands/repair-datasource-sync-operations.js +4 -1
- package/lib/commands/role-assistant-test-output.js +200 -0
- package/lib/commands/role-assistant.js +125 -166
- package/lib/datasource/capability/capability-resolve.js +15 -5
- package/lib/datasource/capability/copy-operations.js +14 -4
- package/lib/infrastructure/index.js +19 -4
- package/lib/integration-definition/apply.js +478 -0
- package/lib/integration-definition/canonical-json.js +51 -0
- package/lib/integration-definition/emit-suite-bid.js +94 -0
- package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
- package/lib/integration-definition/enrich-openapi-operations.js +434 -0
- package/lib/integration-definition/from-discovery.js +339 -0
- package/lib/integration-definition/hash.js +37 -0
- package/lib/integration-definition/index.js +37 -0
- package/lib/integration-definition/openapi-enrichment/hubspot-crm-companies.json +205 -0
- package/lib/integration-definition/resource-type-catalog.js +59 -0
- package/lib/integration-definition/system-kind-enum.js +40 -0
- package/lib/integration-definition/validate.js +148 -0
- package/lib/programmatic/builder-api-request.js +5 -1
- package/lib/programmatic/builder-help-governance.js +3 -2
- package/lib/programmatic/capability-registry.js +19 -0
- package/lib/programmatic/openapi-component-schemas.js +6 -1
- package/lib/programmatic/openapi-descriptions.js +40 -0
- package/lib/programmatic/openapi-envelope-examples.js +269 -0
- package/lib/programmatic/openapi-operation-bindings.js +45 -0
- package/lib/programmatic/openapi-request-schemas.js +14 -0
- package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
- package/lib/programmatic/openapi-result-schemas.js +46 -99
- package/lib/programmatic/openapi-schema-descriptions-core.js +7 -4
- package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-operations.js +24 -0
- package/lib/programmatic/openapi-schema-helpers.js +9 -9
- package/lib/programmatic/openapi-spec.js +11 -1
- package/lib/programmatic/orchestration-openapi-meta.js +10 -0
- package/lib/programmatic/route-handler-map.js +29 -1
- package/lib/programmatic/run-channel-package.js +236 -0
- package/lib/programmatic/run-integration-definition.js +69 -0
- package/lib/role-assistant/knowledge-sync-logging.js +58 -0
- package/lib/role-assistant/knowledge-sync.js +88 -93
- package/lib/role-assistant/test-cases-bid.js +155 -0
- package/lib/role-assistant/test-cases-evaluate.js +9 -1
- package/lib/role-assistant/test-cases-honesty.js +24 -10
- package/lib/role-assistant/test-cases.js +28 -0
- package/lib/role-assistant/test-runner-bid-apply.js +122 -0
- package/lib/role-assistant/test-runner-bid-document.js +278 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +245 -20
- package/lib/role-assistant/test-runner-workhub.js +100 -18
- package/lib/role-assistant/test-suite.js +119 -0
- package/lib/schema/application-schema.json +56 -6
- package/lib/schema/external-datasource.schema.json +103 -17
- package/lib/schema/external-system.schema.json +54 -3
- package/lib/schema/integration-definition.schema.json +195 -0
- package/lib/utils/authentication-shape.js +6 -0
- package/lib/utils/docker-build.js +3 -3
- package/lib/utils/help-builder.js +1 -0
- package/lib/utils/promote-dev-docker-image.js +97 -18
- package/lib/utils/transient-developer-id.js +28 -0
- package/package.json +1 -1
- package/scripts/pnpm/af.mjs +24 -9
- package/scripts/pnpm/help.mjs +1 -1
- package/templates/applications/dataplane/application.yaml +3 -2
- package/templates/applications/dataplane/env.template +7 -6
- package/templates/applications/miso-controller/application.yaml +23 -9
- package/templates/applications/miso-controller/env.template +8 -2
- package/templates/channels/README.md +11 -1
- package/templates/channels/brand/color-192.png +0 -0
- package/templates/channels/brand/dark/128.png +0 -0
- package/templates/channels/brand/dark/192.png +0 -0
- package/templates/channels/brand/dark/256.png +0 -0
- package/templates/channels/brand/dark/32.png +0 -0
- package/templates/channels/brand/dark/512.png +0 -0
- package/templates/channels/brand/dark/64.png +0 -0
- package/templates/channels/brand/light/128.png +0 -0
- package/templates/channels/brand/light/192.png +0 -0
- package/templates/channels/brand/light/256.png +0 -0
- package/templates/channels/brand/light/32.png +0 -0
- package/templates/channels/brand/light/512.png +0 -0
- package/templates/channels/brand/light/64.png +0 -0
- package/templates/channels/brand/mono-white/128.png +0 -0
- package/templates/channels/brand/mono-white/192.png +0 -0
- package/templates/channels/brand/mono-white/256.png +0 -0
- package/templates/channels/brand/mono-white/32.png +0 -0
- package/templates/channels/brand/mono-white/512.png +0 -0
- package/templates/channels/brand/mono-white/64.png +0 -0
- package/templates/channels/brand/outline-32.png +0 -0
- package/templates/channels/chatgpt/install.template.md.hbs +6 -4
- package/templates/channels/chatgpt/integration/README.md +4 -5
- package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +10 -16
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +27 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +39 -20
- package/templates/channels/microsoft-copilot/integration/README.md +2 -3
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +7 -7
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +11 -0
- package/templates/channels/slack/integration/README.md +2 -4
- package/templates/channels/teams-bot/install.template.md.hbs +4 -0
- package/templates/channels/teams-bot/integration/README.md +3 -5
- package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
- /package/.cursor/plans/{Done → Archive}/157.1-security-quality-violations-by-type.csv +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Suite BID load / discovery emit for Work Hub apply waits (512.4 GP).
|
|
3
|
+
* @fileoverview Case BID template + discovery compile + suite stamp
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const fs = require('../internal/fs-real-sync');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} testCase
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
function resolveTargetSystemKey(testCase) {
|
|
16
|
+
const input =
|
|
17
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
18
|
+
for (const key of ['targetSystemKey', 'integrationSystemKey', 'systemKey']) {
|
|
19
|
+
const value = input[key];
|
|
20
|
+
if (typeof value === 'string' && value.trim()) {
|
|
21
|
+
return value.trim();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Object} testCase
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
function shouldStampSuiteBid(testCase) {
|
|
32
|
+
const input =
|
|
33
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
34
|
+
if (input.stampSuiteBid === true) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (input.stampSuiteBid === false) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const expected =
|
|
41
|
+
testCase && typeof testCase.expected === 'object' && testCase.expected
|
|
42
|
+
? testCase.expected
|
|
43
|
+
: {};
|
|
44
|
+
return expected.soft === false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {Object} testCase
|
|
49
|
+
* @returns {string}
|
|
50
|
+
*/
|
|
51
|
+
function resolveSuiteRunId(testCase) {
|
|
52
|
+
const fromActive = String(testCase?._activeProcessExecutionId || '').trim();
|
|
53
|
+
if (fromActive) {
|
|
54
|
+
return fromActive;
|
|
55
|
+
}
|
|
56
|
+
const input =
|
|
57
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
58
|
+
return String(input.suiteRunId || '').trim();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {Object} testCase
|
|
63
|
+
* @param {Object} bid
|
|
64
|
+
*/
|
|
65
|
+
function maybePersistEmittedBid(testCase, bid) {
|
|
66
|
+
const input =
|
|
67
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
68
|
+
const outPath = typeof input.emittedBidPath === 'string' ? input.emittedBidPath.trim() : '';
|
|
69
|
+
if (!outPath || !bid) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const baseDir =
|
|
73
|
+
typeof testCase.sourceFile === 'string' && testCase.sourceFile.trim()
|
|
74
|
+
? path.dirname(testCase.sourceFile)
|
|
75
|
+
: process.cwd();
|
|
76
|
+
const abs = path.isAbsolute(outPath) ? outPath : path.resolve(baseDir, outPath);
|
|
77
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
78
|
+
fs.writeFileSync(abs, `${JSON.stringify(bid, null, 2)}\n`, 'utf8');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {Object} testCase
|
|
83
|
+
* @returns {Object|undefined}
|
|
84
|
+
*/
|
|
85
|
+
function loadBidTemplate(testCase) {
|
|
86
|
+
const input =
|
|
87
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
88
|
+
const bidPath = typeof input.bidPath === 'string' ? input.bidPath.trim() : '';
|
|
89
|
+
if (!bidPath) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
const baseDir =
|
|
93
|
+
typeof testCase.sourceFile === 'string' && testCase.sourceFile.trim()
|
|
94
|
+
? path.dirname(testCase.sourceFile)
|
|
95
|
+
: process.cwd();
|
|
96
|
+
const abs = path.isAbsolute(bidPath) ? bidPath : path.resolve(baseDir, bidPath);
|
|
97
|
+
if (!fs.existsSync(abs)) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(fs.readFileSync(abs, 'utf8'));
|
|
102
|
+
return parsed && typeof parsed === 'object' ? parsed : undefined;
|
|
103
|
+
} catch (_err) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {Object} testCase
|
|
110
|
+
* @returns {boolean}
|
|
111
|
+
*/
|
|
112
|
+
function shouldEmitBidFromAnswers(testCase) {
|
|
113
|
+
const input =
|
|
114
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
115
|
+
if (input.emitBidFromAnswers === false) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (!shouldStampSuiteBid(testCase) && input.emitBidFromAnswers !== true) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
const answers = Array.isArray(testCase.answers) ? testCase.answers : [];
|
|
122
|
+
return answers.some((entry) => {
|
|
123
|
+
const key = String(entry?.when?.questionKey || '')
|
|
124
|
+
.trim()
|
|
125
|
+
.toLowerCase();
|
|
126
|
+
return key === 'system.apigroups';
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {Object} testCase
|
|
132
|
+
* @returns {string|undefined}
|
|
133
|
+
*/
|
|
134
|
+
function resolveAssistantKey(testCase) {
|
|
135
|
+
const input =
|
|
136
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
137
|
+
if (typeof input.digitalWorkerKey === 'string' && input.digitalWorkerKey.trim()) {
|
|
138
|
+
return input.digitalWorkerKey.trim();
|
|
139
|
+
}
|
|
140
|
+
if (typeof input.businessRoleRef === 'string' && input.businessRoleRef.trim()) {
|
|
141
|
+
return input.businessRoleRef.trim();
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function resolveConnectionRefs(input, template) {
|
|
147
|
+
if (input.connectionRefs && typeof input.connectionRefs === 'object') {
|
|
148
|
+
return input.connectionRefs;
|
|
149
|
+
}
|
|
150
|
+
if (template && template.system && template.system.connectionRefs) {
|
|
151
|
+
return template.system.connectionRefs;
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function packageField(template, field, fallback) {
|
|
157
|
+
const identity = template && template.packageIdentity;
|
|
158
|
+
if (identity && identity[field]) {
|
|
159
|
+
return identity[field];
|
|
160
|
+
}
|
|
161
|
+
return fallback;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function buildDiscoveryEmitOptions(testCase, suiteRunId, template, systemKey) {
|
|
165
|
+
const input =
|
|
166
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
167
|
+
const openapiSourceRefs =
|
|
168
|
+
input.openapiSourceRefs && typeof input.openapiSourceRefs === 'object'
|
|
169
|
+
? input.openapiSourceRefs
|
|
170
|
+
: undefined;
|
|
171
|
+
const knowledgePackRefs =
|
|
172
|
+
template && template.meta && Array.isArray(template.meta.knowledgePackRefs)
|
|
173
|
+
? template.meta.knowledgePackRefs
|
|
174
|
+
: undefined;
|
|
175
|
+
return {
|
|
176
|
+
answers: testCase.answers,
|
|
177
|
+
systemKey,
|
|
178
|
+
displayName: packageField(template, 'displayName', systemKey),
|
|
179
|
+
packageVersion: packageField(template, 'packageVersion', '0.1.0'),
|
|
180
|
+
systemKind: (template && template.system && template.system.systemKind) || 'crm',
|
|
181
|
+
connectionRefs: resolveConnectionRefs(input, template),
|
|
182
|
+
openapiSourceRefs,
|
|
183
|
+
suiteRunId,
|
|
184
|
+
definitionId: template && template.definitionId,
|
|
185
|
+
btAssistantKey: resolveAssistantKey(testCase),
|
|
186
|
+
knowledgePackRefs
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @param {Object} testCase
|
|
192
|
+
* @param {string} suiteRunId
|
|
193
|
+
* @param {Object|undefined} template
|
|
194
|
+
* @returns {Object|undefined}
|
|
195
|
+
*/
|
|
196
|
+
function emitBidFromCaseAnswers(testCase, suiteRunId, template) {
|
|
197
|
+
const systemKey = resolveTargetSystemKey(testCase);
|
|
198
|
+
if (!systemKey) {
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
const { bidFromDiscovery } = require('../integration-definition/from-discovery');
|
|
202
|
+
return bidFromDiscovery(buildDiscoveryEmitOptions(testCase, suiteRunId, template, systemKey));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function cachedEmittedBid(testCase, suiteRunId) {
|
|
206
|
+
if (
|
|
207
|
+
testCase._emittedBid &&
|
|
208
|
+
typeof testCase._emittedBid === 'object' &&
|
|
209
|
+
testCase._emittedBid.meta &&
|
|
210
|
+
testCase._emittedBid.meta.suiteRunId === suiteRunId
|
|
211
|
+
) {
|
|
212
|
+
return testCase._emittedBid;
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function tryEmitFromAnswers(testCase, suiteRunId, template) {
|
|
218
|
+
if (!shouldEmitBidFromAnswers(testCase)) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const emitted = emitBidFromCaseAnswers(testCase, suiteRunId, template);
|
|
223
|
+
if (emitted) {
|
|
224
|
+
testCase._emittedBid = emitted;
|
|
225
|
+
maybePersistEmittedBid(testCase, emitted);
|
|
226
|
+
return emitted;
|
|
227
|
+
}
|
|
228
|
+
} catch (_err) {
|
|
229
|
+
// Fall through to template stamp.
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Load BID for apply: discovery-compiled (preferred) or stamped template.
|
|
236
|
+
* @param {Object} testCase
|
|
237
|
+
* @returns {Object|undefined}
|
|
238
|
+
*/
|
|
239
|
+
function loadCaseBidDocument(testCase) {
|
|
240
|
+
const input =
|
|
241
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
242
|
+
const template = loadBidTemplate(testCase);
|
|
243
|
+
if (!shouldStampSuiteBid(testCase) && input.emitBidFromAnswers !== true) {
|
|
244
|
+
return template;
|
|
245
|
+
}
|
|
246
|
+
const suiteRunId = resolveSuiteRunId(testCase);
|
|
247
|
+
if (!suiteRunId) {
|
|
248
|
+
return template;
|
|
249
|
+
}
|
|
250
|
+
const cached = cachedEmittedBid(testCase, suiteRunId);
|
|
251
|
+
if (cached) {
|
|
252
|
+
return cached;
|
|
253
|
+
}
|
|
254
|
+
const fromAnswers = tryEmitFromAnswers(testCase, suiteRunId, template);
|
|
255
|
+
if (fromAnswers) {
|
|
256
|
+
return fromAnswers;
|
|
257
|
+
}
|
|
258
|
+
if (!template) {
|
|
259
|
+
return undefined;
|
|
260
|
+
}
|
|
261
|
+
const { emitSuiteBid } = require('../integration-definition/emit-suite-bid');
|
|
262
|
+
const emitted = emitSuiteBid(template, {
|
|
263
|
+
suiteRunId,
|
|
264
|
+
btAssistantKey: resolveAssistantKey(testCase),
|
|
265
|
+
answers: testCase.answers
|
|
266
|
+
});
|
|
267
|
+
testCase._emittedBid = emitted;
|
|
268
|
+
maybePersistEmittedBid(testCase, emitted);
|
|
269
|
+
return emitted;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
module.exports = {
|
|
273
|
+
resolveTargetSystemKey,
|
|
274
|
+
shouldStampSuiteBid,
|
|
275
|
+
resolveSuiteRunId,
|
|
276
|
+
loadCaseBidDocument,
|
|
277
|
+
shouldEmitBidFromAnswers
|
|
278
|
+
};
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const {
|
|
9
|
+
resolveTargetSystemKey,
|
|
10
|
+
shouldStampSuiteBid,
|
|
11
|
+
resolveSuiteRunId,
|
|
12
|
+
loadCaseBidDocument
|
|
13
|
+
} = require('./test-runner-bid-document');
|
|
14
|
+
|
|
8
15
|
function resolveWorkHubAnswerValue(answer) {
|
|
9
16
|
if (answer === null || answer === undefined) {
|
|
10
17
|
return undefined;
|
|
@@ -69,25 +76,159 @@ function extractObjectiveHints(objective) {
|
|
|
69
76
|
return { email, domain, name, address };
|
|
70
77
|
}
|
|
71
78
|
|
|
72
|
-
function
|
|
79
|
+
function resolveCaseSystemKey(testCase) {
|
|
80
|
+
const input =
|
|
81
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
82
|
+
for (const key of ['digitalWorkerKey', 'systemKey', 'businessRoleRef']) {
|
|
83
|
+
const value = input[key];
|
|
84
|
+
if (typeof value === 'string' && value.trim()) {
|
|
85
|
+
return value.trim();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Target Connected System key for workspace/template lifecycle (not the RA package key).
|
|
93
|
+
*/
|
|
94
|
+
/**
|
|
95
|
+
* Capability identity for a wait. Prefer structured keys; fall back to prompt
|
|
96
|
+
* text so "Missing … for project.runupload (fields: systemKey)" still routes
|
|
97
|
+
* to the target integration key (not the Role Assistant package key).
|
|
98
|
+
* @param {Object} wait
|
|
99
|
+
* @returns {string}
|
|
100
|
+
*/
|
|
101
|
+
function resolveWaitCapabilityText(wait) {
|
|
102
|
+
return String(
|
|
103
|
+
wait?.questionKey ||
|
|
104
|
+
wait?.objectRef?.capabilityKey ||
|
|
105
|
+
wait?.requestKey ||
|
|
106
|
+
wait?.prompt ||
|
|
107
|
+
''
|
|
108
|
+
).toLowerCase();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function isTargetIntegrationLifecycleCapability(capability) {
|
|
112
|
+
const text = String(capability || '').toLowerCase();
|
|
113
|
+
return (
|
|
114
|
+
text.includes('workspace') ||
|
|
115
|
+
text.includes('createsystem') ||
|
|
116
|
+
text.includes('template') ||
|
|
117
|
+
text.includes('applyintegrationdefinition') ||
|
|
118
|
+
text.includes('wizard') ||
|
|
119
|
+
text.includes('repair') ||
|
|
120
|
+
text.includes('validate') ||
|
|
121
|
+
text.includes('upload') ||
|
|
122
|
+
text.includes('project.') ||
|
|
123
|
+
text.includes('document.') ||
|
|
124
|
+
text.includes('certifypillar') ||
|
|
125
|
+
text.includes('approval.')
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function resolveCaseCertifyPillar(testCase) {
|
|
130
|
+
const input =
|
|
131
|
+
testCase && typeof testCase.input === 'object' && testCase.input ? testCase.input : {};
|
|
132
|
+
const raw = input.certifyPillar || input.pillar;
|
|
133
|
+
if (typeof raw === 'string' && raw.trim()) {
|
|
134
|
+
return raw.trim();
|
|
135
|
+
}
|
|
136
|
+
return 'operations';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @param {Object} wait
|
|
141
|
+
* @param {Object} testCase
|
|
142
|
+
* @param {string} systemKey
|
|
143
|
+
* @returns {Object|undefined}
|
|
144
|
+
*/
|
|
145
|
+
function synthesizeCertifyAnswer(wait, testCase, systemKey) {
|
|
146
|
+
if (!systemKey) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
const capability = resolveWaitCapabilityText(wait);
|
|
150
|
+
if (!capability.includes('certifypillar') && !capability.includes('certify')) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
return { systemKey, pillar: resolveCaseCertifyPillar(testCase) };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function isBidApplyWait(wait) {
|
|
157
|
+
const capability = resolveWaitCapabilityText(wait);
|
|
158
|
+
return (
|
|
159
|
+
capability.includes('applyintegrationdefinition') ||
|
|
160
|
+
capability.includes('integrationdefinition') ||
|
|
161
|
+
capability.includes('integration-definition')
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function resolveSystemKeyForWait(testCase, wait) {
|
|
166
|
+
const capability = resolveWaitCapabilityText(wait);
|
|
167
|
+
const target = resolveTargetSystemKey(testCase);
|
|
168
|
+
if (target && isTargetIntegrationLifecycleCapability(capability)) {
|
|
169
|
+
return target;
|
|
170
|
+
}
|
|
171
|
+
return resolveCaseSystemKey(testCase);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function valueFromHintField(lower, hints, testCase, systemKey) {
|
|
175
|
+
if (hints[lower]) {
|
|
176
|
+
return hints[lower];
|
|
177
|
+
}
|
|
178
|
+
if (lower === 'systemkey' && systemKey) {
|
|
179
|
+
return systemKey;
|
|
180
|
+
}
|
|
181
|
+
if (lower === 'pillar') {
|
|
182
|
+
return resolveCaseCertifyPillar(testCase);
|
|
183
|
+
}
|
|
184
|
+
if (lower === 'force') {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
if (lower.includes('mail') && hints.email) {
|
|
188
|
+
return hints.email;
|
|
189
|
+
}
|
|
190
|
+
if (lower.includes('name') && hints.name) {
|
|
191
|
+
return hints.name;
|
|
192
|
+
}
|
|
193
|
+
if (lower.includes('domain') && hints.domain) {
|
|
194
|
+
return hints.domain;
|
|
195
|
+
}
|
|
196
|
+
if (lower.includes('address') && hints.address) {
|
|
197
|
+
return hints.address;
|
|
198
|
+
}
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function fillFieldsFromHints(fields, hints, testCase, wait) {
|
|
73
203
|
const out = {};
|
|
204
|
+
const systemKey = resolveSystemKeyForWait(testCase, wait);
|
|
74
205
|
for (const key of fields) {
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
out[key] =
|
|
78
|
-
} else if (lower.includes('mail') && hints.email) {
|
|
79
|
-
out[key] = hints.email;
|
|
80
|
-
} else if (lower.includes('name') && hints.name) {
|
|
81
|
-
out[key] = hints.name;
|
|
82
|
-
} else if (lower.includes('domain') && hints.domain) {
|
|
83
|
-
out[key] = hints.domain;
|
|
84
|
-
} else if (lower.includes('address') && hints.address) {
|
|
85
|
-
out[key] = hints.address;
|
|
206
|
+
const value = valueFromHintField(key.toLowerCase(), hints, testCase, systemKey);
|
|
207
|
+
if (value !== undefined) {
|
|
208
|
+
out[key] = value;
|
|
86
209
|
}
|
|
87
210
|
}
|
|
88
211
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
89
212
|
}
|
|
90
213
|
|
|
214
|
+
/**
|
|
215
|
+
* Soft-loop upload often rewrites BID-shaped schemas over prior packages.
|
|
216
|
+
* Include force so project.runupload can replace non-overlapping attributes.
|
|
217
|
+
* @param {Object} wait
|
|
218
|
+
* @param {string} systemKey
|
|
219
|
+
* @returns {Object|undefined}
|
|
220
|
+
*/
|
|
221
|
+
function synthesizeUploadAnswer(wait, systemKey) {
|
|
222
|
+
if (!systemKey || !isTargetIntegrationLifecycleCapability(resolveWaitCapabilityText(wait))) {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
const capability = resolveWaitCapabilityText(wait);
|
|
226
|
+
if (!capability.includes('upload') && !capability.includes('project.runupload')) {
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
return { systemKey, force: true };
|
|
230
|
+
}
|
|
231
|
+
|
|
91
232
|
function _synthContactFields(hints) {
|
|
92
233
|
const out = {};
|
|
93
234
|
if (hints.email) {
|
|
@@ -144,12 +285,77 @@ function synthesizeFromCapability(capability, hints) {
|
|
|
144
285
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
145
286
|
}
|
|
146
287
|
|
|
147
|
-
function
|
|
288
|
+
function synthesizeFieldAnswer(wait, statusRow, objective, testCase) {
|
|
148
289
|
const prompt = String(wait.prompt || statusRow?.message || '').trim();
|
|
149
290
|
const hints = extractObjectiveHints(objective);
|
|
150
291
|
const fields = parseFieldsFromPrompt(prompt);
|
|
151
|
-
|
|
152
|
-
|
|
292
|
+
const filled = fields.length > 0 ? fillFieldsFromHints(fields, hints, testCase, wait) : undefined;
|
|
293
|
+
if (filled === undefined) {
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
const targetKey = filled.systemKey || resolveTargetSystemKey(testCase);
|
|
297
|
+
const uploadExtra = synthesizeUploadAnswer(wait, targetKey);
|
|
298
|
+
const certifyExtra = synthesizeCertifyAnswer(wait, testCase, targetKey);
|
|
299
|
+
return uploadExtra || certifyExtra ? { ...filled, ...(uploadExtra || {}), ...(certifyExtra || {}) } : filled;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function synthesizePathParameterAnswer(wait, prompt, kind, testCase) {
|
|
303
|
+
if (kind !== 'missingPathParams' && !/missing required path params/i.test(prompt)) {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
const targetSystemKey = resolveTargetSystemKey(testCase);
|
|
307
|
+
if (targetSystemKey && isTargetIntegrationLifecycleCapability(resolveWaitCapabilityText(wait))) {
|
|
308
|
+
return (
|
|
309
|
+
synthesizeUploadAnswer(wait, targetSystemKey) ||
|
|
310
|
+
synthesizeCertifyAnswer(wait, testCase, targetSystemKey) ||
|
|
311
|
+
{ systemKey: targetSystemKey }
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
const pathSystemKey = resolveCaseSystemKey(testCase);
|
|
315
|
+
return pathSystemKey ? { systemKey: pathSystemKey } : undefined;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function synthesizeBidApplyAnswer(wait, prompt, kind, testCase) {
|
|
319
|
+
if (!isBidApplyWait(wait)) {
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
const wantsBody = kind === 'missingRequestBody' || /missing required request body/i.test(prompt);
|
|
323
|
+
const wantsPath = kind === 'missingPathParams' || /missing required path params/i.test(prompt);
|
|
324
|
+
const bid = loadCaseBidDocument(testCase);
|
|
325
|
+
if (!bid || (!wantsBody && !wantsPath)) {
|
|
326
|
+
return undefined;
|
|
327
|
+
}
|
|
328
|
+
const out = wantsBody ? { integrationDefinition: bid } : {};
|
|
329
|
+
const targetSystemKey = resolveTargetSystemKey(testCase);
|
|
330
|
+
if (targetSystemKey) {
|
|
331
|
+
out.systemKey = targetSystemKey;
|
|
332
|
+
}
|
|
333
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function synthesizeTargetSystemKeyAnswer(wait, prompt, kind, testCase) {
|
|
337
|
+
const targetSystemKey = resolveTargetSystemKey(testCase);
|
|
338
|
+
const needsBody = kind === 'missingRequestBody' || /missing required request body/i.test(prompt);
|
|
339
|
+
if (!targetSystemKey || (!needsBody && !/systemKey is required/i.test(prompt))) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
const capability = resolveWaitCapabilityText(wait);
|
|
343
|
+
const supportsTarget =
|
|
344
|
+
capability.includes('workspace') ||
|
|
345
|
+
capability.includes('createsystem') ||
|
|
346
|
+
(capability.includes('template') && !isBidApplyWait(wait)) ||
|
|
347
|
+
capability.includes('wizard') ||
|
|
348
|
+
capability.includes('upload') ||
|
|
349
|
+
capability.includes('project.') ||
|
|
350
|
+
/systemkey is required/i.test(prompt);
|
|
351
|
+
return supportsTarget ? { systemKey: targetSystemKey } : undefined;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function synthesizeWaitAnswer(wait, statusRow, objective, testCase) {
|
|
355
|
+
const prompt = String(wait.prompt || statusRow?.message || '').trim();
|
|
356
|
+
const fieldAnswer = synthesizeFieldAnswer(wait, statusRow, objective, testCase);
|
|
357
|
+
if (fieldAnswer !== undefined) {
|
|
358
|
+
return fieldAnswer;
|
|
153
359
|
}
|
|
154
360
|
const kind = String(wait.objectRef?.kind || '').trim();
|
|
155
361
|
const isMissingInput =
|
|
@@ -159,18 +365,29 @@ function synthesizeWaitAnswer(wait, statusRow, objective) {
|
|
|
159
365
|
if (!isMissingInput) {
|
|
160
366
|
return undefined;
|
|
161
367
|
}
|
|
162
|
-
const
|
|
163
|
-
|
|
368
|
+
const pathAnswer = synthesizePathParameterAnswer(wait, prompt, kind, testCase);
|
|
369
|
+
if (pathAnswer !== undefined) {
|
|
370
|
+
return pathAnswer;
|
|
371
|
+
}
|
|
372
|
+
const bidAnswer = synthesizeBidApplyAnswer(wait, prompt, kind, testCase);
|
|
373
|
+
if (bidAnswer !== undefined) {
|
|
374
|
+
return bidAnswer;
|
|
375
|
+
}
|
|
376
|
+
const targetAnswer = synthesizeTargetSystemKeyAnswer(wait, prompt, kind, testCase);
|
|
377
|
+
return targetAnswer || synthesizeFromCapability(resolveWaitCapabilityText(wait), extractObjectiveHints(objective));
|
|
164
378
|
}
|
|
165
379
|
|
|
166
380
|
function resolveRespondValue(testCase, wait, statusRow, objective) {
|
|
167
381
|
const answers = Array.isArray(testCase.answers) ? testCase.answers : [];
|
|
168
|
-
|
|
382
|
+
// Only use an answer whose when.questionKey matches this wait.
|
|
383
|
+
// Never fall back to answers[0] — that poisons capability waits (e.g. task.runtest)
|
|
384
|
+
// with unrelated discovery payloads (system.apiGroups).
|
|
385
|
+
const matched = pickAnswerForWait(answers, wait);
|
|
169
386
|
const fromCase = matched ? resolveWorkHubAnswerValue(matched) : undefined;
|
|
170
387
|
if (fromCase !== undefined) {
|
|
171
388
|
return fromCase;
|
|
172
389
|
}
|
|
173
|
-
return synthesizeWaitAnswer(wait, statusRow, objective);
|
|
390
|
+
return synthesizeWaitAnswer(wait, statusRow, objective, testCase);
|
|
174
391
|
}
|
|
175
392
|
|
|
176
393
|
function waitRespondFingerprint(wait) {
|
|
@@ -181,7 +398,10 @@ function waitRespondFingerprint(wait) {
|
|
|
181
398
|
|
|
182
399
|
function alreadyResponded(interactions, fingerprint) {
|
|
183
400
|
return interactions.some(
|
|
184
|
-
(row) =>
|
|
401
|
+
(row) =>
|
|
402
|
+
row &&
|
|
403
|
+
(row.type === 'respond' || row.type === 'respond-skipped') &&
|
|
404
|
+
row.fingerprint === fingerprint
|
|
185
405
|
);
|
|
186
406
|
}
|
|
187
407
|
|
|
@@ -214,6 +434,11 @@ module.exports = {
|
|
|
214
434
|
pickAnswerForWait,
|
|
215
435
|
synthesizeWaitAnswer,
|
|
216
436
|
extractObjectiveHints,
|
|
437
|
+
resolveCaseSystemKey,
|
|
438
|
+
resolveTargetSystemKey,
|
|
439
|
+
shouldStampSuiteBid,
|
|
440
|
+
resolveSuiteRunId,
|
|
441
|
+
loadCaseBidDocument,
|
|
217
442
|
resolveRespondValue,
|
|
218
443
|
waitRespondFingerprint,
|
|
219
444
|
alreadyResponded,
|