@aifabrix/builder 2.54.1 → 2.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/lib/agent-kit/apply-ops.js +82 -0
- package/lib/agent-kit/checksums.js +28 -0
- package/lib/agent-kit/classify.js +113 -0
- package/lib/agent-kit/claude-shim.js +61 -0
- package/lib/agent-kit/constants.js +55 -0
- package/lib/agent-kit/file-list.js +103 -0
- package/lib/agent-kit/host-approve.js +130 -0
- package/lib/agent-kit/hosting/github.js +63 -0
- package/lib/agent-kit/hosts.js +71 -0
- package/lib/agent-kit/init.js +319 -0
- package/lib/agent-kit/kit-root.js +17 -0
- package/lib/agent-kit/managed-section.js +79 -0
- package/lib/agent-kit/package-load.js +45 -0
- package/lib/agent-kit/plan-ops.js +69 -0
- package/lib/agent-kit/remote-prompts.js +239 -0
- package/lib/agent-kit/render-host-markdown.js +40 -0
- package/lib/agent-kit/repo-guard.js +47 -0
- package/lib/agent-kit/report.js +107 -0
- package/lib/agent-kit/run.js +82 -0
- package/lib/agent-kit/scm/git.js +122 -0
- package/lib/agent-kit/state-file.js +83 -0
- package/lib/agent-kit/status.js +50 -0
- package/lib/agent-kit/v1-detect.js +81 -0
- package/lib/agent-kit/validate-kit.js +87 -0
- package/lib/agent-kit/workspace-name.js +40 -0
- package/lib/agent-kit/workspace-skeleton.js +103 -0
- package/lib/api/role-assistant-test-pack.api.js +86 -0
- package/lib/api/work-search.api.js +31 -4
- package/lib/api/work.api.js +19 -12
- package/lib/app/list-external-systems.js +2 -1
- package/lib/app/show-display.js +33 -6
- package/lib/app/show.js +25 -2
- package/lib/channels/add-channel.js +1 -0
- package/lib/channels/approval-guides/claude.js +2 -2
- package/lib/channels/channel-add-failure.js +1 -0
- package/lib/channels/channel-add-remaining.js +15 -9
- package/lib/channels/channel-definition-status.js +115 -0
- package/lib/channels/channel-description.js +2 -1
- package/lib/channels/channel-install-envelope.js +4 -2
- package/lib/channels/channel-integration-generator.js +2 -0
- package/lib/channels/channel-runtime-resolver.js +14 -0
- package/lib/channels/channel-targets.js +31 -5
- package/lib/channels/claude-setup-values.js +4 -1
- package/lib/channels/slack-channel-add.js +59 -6
- package/lib/channels/slack-mcp-callback.js +51 -0
- package/lib/channels/slack-mcp-runtime.js +156 -0
- package/lib/channels/slack-provisioning/install-cli.js +14 -2
- package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
- package/lib/cli/index.js +4 -0
- package/lib/cli/setup-certification-commands.js +2 -2
- package/lib/cli/setup-certification.help.js +3 -1
- package/lib/commands/agent-kit-help.js +79 -0
- package/lib/commands/agent-kit.js +346 -0
- package/lib/commands/channel-add-help.js +5 -5
- package/lib/commands/datasource-capability-relate-cli.js +5 -4
- package/lib/commands/repair-auth-apply.js +1 -1
- package/lib/commands/repair-datasource-key-skip.js +39 -0
- package/lib/commands/repair-datasource-keys.js +24 -12
- package/lib/commands/repair-rbac.js +16 -10
- package/lib/commands/role-assistant-copy-output.js +61 -0
- package/lib/commands/role-assistant-copy.js +155 -0
- package/lib/commands/role-assistant-test-output.js +8 -9
- package/lib/commands/role-assistant-test-result-rows.js +42 -0
- package/lib/commands/role-assistant.js +117 -48
- package/lib/commands/search.js +143 -0
- package/lib/commands/test-trust-external.js +7 -5
- package/lib/commands/upload-sidecar-followups.js +4 -1
- package/lib/commands/verify-operations-skip-e2e.js +131 -0
- package/lib/commands/verify-operations-step-plan.js +6 -33
- package/lib/commands/verify-operations-steps.js +3 -1
- package/lib/datasource/capability/relate-operations.js +28 -10
- package/lib/datasource/capability/run-capability-relate.js +48 -25
- package/lib/datasource/datasource-identifier.js +13 -5
- package/lib/deployment/deployer-poll-run.js +117 -35
- package/lib/external-system/deploy-dataplane-published.js +70 -0
- package/lib/external-system/deploy.js +12 -2
- package/lib/external-system/download-role-assistant.js +41 -15
- package/lib/external-system/download.js +7 -1
- package/lib/generator/wizard-datasource-key.js +54 -0
- package/lib/generator/wizard.js +55 -54
- package/lib/integration-definition/apply-datasource-keys.js +75 -0
- package/lib/integration-definition/apply-relationships.js +195 -0
- package/lib/integration-definition/apply-static-enterprise.js +229 -0
- package/lib/integration-definition/apply-system-file.js +71 -0
- package/lib/integration-definition/apply-test-endpoint.js +89 -0
- package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
- package/lib/integration-definition/apply.js +78 -59
- package/lib/integration-definition/enrich-openapi-operations.js +36 -10
- package/lib/integration-definition/enrich-openapi-pick.js +87 -0
- package/lib/lifecycle/role-assistant-governance.js +56 -21
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/index.js +2 -0
- package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
- package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +9 -3
- package/lib/programmatic/openapi-envelope-examples.js +7 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +5 -0
- package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/openapi-spec.js +1 -0
- package/lib/programmatic/request-timeout.js +3 -0
- package/lib/programmatic/route-handler-map.js +7 -0
- package/lib/programmatic/run-channel-catalog.js +50 -8
- package/lib/programmatic/run-channel-install-options.js +5 -1
- package/lib/programmatic/run-download.js +41 -0
- package/lib/protection/auth-context.js +3 -1
- package/lib/protection/protection-display.js +3 -2
- package/lib/protection/report-exit.js +50 -0
- package/lib/protection/run-commands.js +2 -0
- package/lib/role-assistant/package-validate.js +175 -0
- package/lib/role-assistant/test-case-assertion-row.js +36 -0
- package/lib/role-assistant/test-case-copy-bind.js +77 -0
- package/lib/role-assistant/test-case-copy-expected.js +127 -0
- package/lib/role-assistant/test-case-copy-from-work.js +90 -0
- package/lib/role-assistant/test-case-copy-interactions.js +67 -0
- package/lib/role-assistant/test-case-copy.js +119 -0
- package/lib/role-assistant/test-case-expected-catalog.js +135 -0
- package/lib/role-assistant/test-case-validate.js +88 -0
- package/lib/role-assistant/test-cases-bid.js +117 -4
- package/lib/role-assistant/test-cases-evaluate.js +137 -30
- package/lib/role-assistant/test-cases-honesty.js +155 -6
- package/lib/role-assistant/test-cases-lifecycle.js +291 -0
- package/lib/role-assistant/test-cases-search-graph.js +122 -0
- package/lib/role-assistant/test-cases-search.js +20 -2
- package/lib/role-assistant/test-cases.js +34 -168
- package/lib/role-assistant/test-pack-map.js +180 -0
- package/lib/role-assistant/test-pack-sync.js +187 -0
- package/lib/role-assistant/test-runner-debug.js +54 -0
- package/lib/role-assistant/test-runner-respond-body.js +36 -0
- package/lib/role-assistant/test-runner-search.js +20 -5
- package/lib/role-assistant/test-runner-start-payload.js +63 -10
- package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
- package/lib/role-assistant/test-runner-workhub.js +45 -21
- package/lib/role-assistant/test-runner.js +50 -10
- package/lib/schema/external-datasource.schema.json +36 -5
- package/lib/schema/external-system.schema.json +20 -2
- package/lib/schema/role-assistant-test-case.schema.json +408 -0
- package/lib/search/dataplane-context.js +23 -0
- package/lib/search/search-args.js +211 -0
- package/lib/search/search-display.js +238 -0
- package/lib/search/search-errors.js +50 -0
- package/lib/search/search-prompts.js +119 -0
- package/lib/search/search-roles.js +85 -0
- package/lib/search/search-run.js +241 -0
- package/lib/search/search-skills.js +198 -0
- package/lib/utils/authentication-slot-show.js +153 -0
- package/lib/utils/credential-display.js +43 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
- package/lib/utils/external-system-readiness-compact-display.js +30 -1
- package/lib/utils/external-system-validators.js +2 -1
- package/lib/utils/help-builder.js +3 -1
- package/lib/utils/schema-loader.js +37 -0
- package/lib/validation/validate-external-file.js +5 -1
- package/lib/validation/validate.js +3 -2
- package/package.json +1 -1
- package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
- package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
- package/templates/agent-kit/agent-kit.yaml +45 -0
- package/templates/agent-kit/instructions/AGENTKIT.md +83 -0
- package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
- package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
- package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
- package/templates/agent-kit/parity-inventory.yaml +188 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +58 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +51 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +50 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +42 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
- package/templates/agent-kit/skills/shared/hosts.md +78 -0
- package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
- package/templates/agent-kit/workspace/LICENSE.mit +21 -0
- package/templates/agent-kit/workspace/README.md +89 -0
- package/templates/applications/builder-api/Dockerfile +3 -1
- package/templates/applications/dataplane/application.yaml +2 -2
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/dataplane/rbac.yaml +28 -0
- package/templates/applications/keycloak/env.template +3 -3
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +8 -9
- package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
- package/templates/channels/claude/channel.json +1 -1
- package/templates/channels/claude/install.template.md.hbs +1 -0
- package/templates/channels/claude/integration/claude-system.json +1 -1
- package/templates/channels/slack/channel.json +11 -0
- package/templates/channels/slack/install.template.md.hbs +9 -0
- package/templates/channels/slack/integration/slack-system.json +11 -0
- package/templates/channels/slack/manifest.template.json.hbs +6 -3
- package/templates/channels/teams-bot/channel.json +1 -0
- package/templates/python/docker-compose.hbs +14 -0
- package/templates/typescript/docker-compose.hbs +14 -0
|
@@ -8,11 +8,14 @@ const path = require('path');
|
|
|
8
8
|
const fs = require('../internal/fs-real-sync');
|
|
9
9
|
const yaml = require('js-yaml');
|
|
10
10
|
const { resolveExternalSystemPath } = require('../utils/app-path-resolve');
|
|
11
|
-
const { VERDICT } = require('../lifecycle/product-model');
|
|
12
11
|
const {
|
|
13
12
|
buildHonestyObservation,
|
|
14
13
|
evaluateHonestyExpectations
|
|
15
14
|
} = require('./test-cases-honesty');
|
|
15
|
+
const {
|
|
16
|
+
SUPPORTED_LIFECYCLE_STATES,
|
|
17
|
+
deriveLifecycleState
|
|
18
|
+
} = require('./test-cases-lifecycle');
|
|
16
19
|
function loadNodeFsSnapshot() {
|
|
17
20
|
if (global.__AIFABRIX_NODE_FS_UNMOCKED__) {
|
|
18
21
|
return global.__AIFABRIX_NODE_FS_UNMOCKED__;
|
|
@@ -22,32 +25,6 @@ function loadNodeFsSnapshot() {
|
|
|
22
25
|
: require('node:fs');
|
|
23
26
|
}
|
|
24
27
|
const nodeFs = loadNodeFsSnapshot();
|
|
25
|
-
const SUPPORTED_LIFECYCLE_STATES = new Set(['completed', 'question', 'approval-required', 'dependency', 'safe-stop', 'rejected', 'failed']);
|
|
26
|
-
const LIFECYCLE_STATE_ALIASES = Object.freeze({
|
|
27
|
-
completed: ['completed', 'complete', 'done', 'success', 'verified'],
|
|
28
|
-
question: ['question', 'question_required', 'awaiting_question', 'pending_question'],
|
|
29
|
-
'approval-required': ['approval_required', 'awaiting_approval', 'pending_approval', 'requires_approval'],
|
|
30
|
-
dependency: ['dependency', 'dependency_wait', 'dependency_blocked', 'awaiting_dependency'],
|
|
31
|
-
'safe-stop': ['safe_stop', 'safe_stopped', 'policy_blocked', 'halted', 'paused'],
|
|
32
|
-
rejected: ['rejected', 'denied', 'declined', 'policy_rejected'],
|
|
33
|
-
failed: ['failed', 'error', 'errored', 'timeout', 'cancelled', 'canceled']
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const WORK_STATUS_TO_LIFECYCLE = Object.freeze({
|
|
37
|
-
completed: 'completed', waiting: 'question', running: 'dependency', stopped: 'safe-stop'
|
|
38
|
-
});
|
|
39
|
-
const WAIT_REASON_TO_LIFECYCLE = Object.freeze({
|
|
40
|
-
ask: 'question', approval: 'approval-required', ownerroute: 'dependency',
|
|
41
|
-
realityconfirm: 'question', knowledgeconfirm: 'question'
|
|
42
|
-
});
|
|
43
|
-
const WORKER_TASK_STATUS_TO_LIFECYCLE = Object.freeze({
|
|
44
|
-
draft: 'dependency', pendingapproval: 'approval-required', approved: 'dependency',
|
|
45
|
-
running: 'dependency', completed: 'completed', failed: 'failed',
|
|
46
|
-
cancelled: 'rejected', canceled: 'rejected'
|
|
47
|
-
});
|
|
48
|
-
const WORKER_APPROVAL_STATE_TO_LIFECYCLE = Object.freeze({
|
|
49
|
-
pending: 'approval-required', approved: 'dependency', rejected: 'rejected'
|
|
50
|
-
});
|
|
51
28
|
function safeExistsSync(filePath) {
|
|
52
29
|
// Prefer unmocked node:fs so Jest worker fs mocks cannot hide real temp files.
|
|
53
30
|
return nodeFs.existsSync(filePath) || fs.existsSync(filePath);
|
|
@@ -105,6 +82,7 @@ function normalizeCaseFromFile(filePath, parsed) {
|
|
|
105
82
|
answers: Array.isArray(parsed.answers) ? parsed.answers : [],
|
|
106
83
|
approvals: Array.isArray(parsed.approvals) ? parsed.approvals : [],
|
|
107
84
|
expected,
|
|
85
|
+
metadata: parsed.metadata && typeof parsed.metadata === 'object' ? parsed.metadata : {},
|
|
108
86
|
preflight: parsed.preflight && typeof parsed.preflight === 'object' ? parsed.preflight : {},
|
|
109
87
|
sourceFile: filePath
|
|
110
88
|
};
|
|
@@ -202,150 +180,11 @@ function loadRoleAssistantTestCase(roleKey, selector, options = {}) {
|
|
|
202
180
|
throw new Error(`Role assistant test case ${lookup} not found in ${testsDir}`);
|
|
203
181
|
}
|
|
204
182
|
const parsed = parseCaseYamlFile(filePath);
|
|
183
|
+
const { assertTestCaseDocument } = require('./test-case-validate');
|
|
184
|
+
assertTestCaseDocument(parsed, filePath);
|
|
205
185
|
return normalizeCaseFromFile(filePath, parsed);
|
|
206
186
|
}
|
|
207
187
|
|
|
208
|
-
function normalizeLifecycleStateToken(value) {
|
|
209
|
-
if (typeof value !== 'string') {
|
|
210
|
-
return '';
|
|
211
|
-
}
|
|
212
|
-
return value
|
|
213
|
-
.trim()
|
|
214
|
-
.toLowerCase()
|
|
215
|
-
.replace(/[^a-z0-9]+/g, '_')
|
|
216
|
-
.replace(/^_+|_+$/g, '');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function lifecycleStateFromToken(token) {
|
|
220
|
-
if (!token) {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
for (const [state, aliases] of Object.entries(LIFECYCLE_STATE_ALIASES)) {
|
|
224
|
-
for (const alias of aliases) {
|
|
225
|
-
if (token === alias || token.startsWith(`${alias}_`)) {
|
|
226
|
-
return state;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function lifecycleStateFromSignalValue(value) {
|
|
234
|
-
if (value === null || value === undefined) {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
if (typeof value === 'string') {
|
|
238
|
-
return lifecycleStateFromToken(normalizeLifecycleStateToken(value));
|
|
239
|
-
}
|
|
240
|
-
if (Array.isArray(value)) {
|
|
241
|
-
for (const row of value) {
|
|
242
|
-
const state = lifecycleStateFromSignalValue(row);
|
|
243
|
-
if (state) {
|
|
244
|
-
return state;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return null;
|
|
248
|
-
}
|
|
249
|
-
if (typeof value === 'object') {
|
|
250
|
-
const fields = [
|
|
251
|
-
'lifecycleState',
|
|
252
|
-
'state',
|
|
253
|
-
'status',
|
|
254
|
-
'code',
|
|
255
|
-
'type',
|
|
256
|
-
'reason',
|
|
257
|
-
'kind',
|
|
258
|
-
'category',
|
|
259
|
-
'errorCode'
|
|
260
|
-
];
|
|
261
|
-
for (const field of fields) {
|
|
262
|
-
const state = lifecycleStateFromSignalValue(value[field]);
|
|
263
|
-
if (state) {
|
|
264
|
-
return state;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
return null;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function mapWorkStatusFromResult(result) {
|
|
272
|
-
const rawStatus = normalizeLifecycleStateToken(result?.status);
|
|
273
|
-
if (rawStatus && WORK_STATUS_TO_LIFECYCLE[rawStatus]) {
|
|
274
|
-
const waitReason = normalizeLifecycleStateToken(result?.wait?.waitReason || '');
|
|
275
|
-
if (rawStatus === 'waiting' && waitReason && WAIT_REASON_TO_LIFECYCLE[waitReason]) {
|
|
276
|
-
return WAIT_REASON_TO_LIFECYCLE[waitReason];
|
|
277
|
-
}
|
|
278
|
-
return WORK_STATUS_TO_LIFECYCLE[rawStatus];
|
|
279
|
-
}
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function mapWorkerTaskStateFromResult(result) {
|
|
284
|
-
const statusCandidates = [result?.task?.status, result?.status, result?.workerTask?.status];
|
|
285
|
-
for (const row of statusCandidates) {
|
|
286
|
-
const token = normalizeLifecycleStateToken(row);
|
|
287
|
-
if (token && WORKER_TASK_STATUS_TO_LIFECYCLE[token]) {
|
|
288
|
-
return WORKER_TASK_STATUS_TO_LIFECYCLE[token];
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
const approvalCandidates = [result?.task?.approvalState, result?.approvalState, result?.workerTask?.approvalState];
|
|
292
|
-
for (const row of approvalCandidates) {
|
|
293
|
-
const token = normalizeLifecycleStateToken(row);
|
|
294
|
-
if (token && WORKER_APPROVAL_STATE_TO_LIFECYCLE[token]) {
|
|
295
|
-
return WORKER_APPROVAL_STATE_TO_LIFECYCLE[token];
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function resolveLifecycleStateFromResult(result) {
|
|
302
|
-
const workState = mapWorkStatusFromResult(result);
|
|
303
|
-
if (workState) {
|
|
304
|
-
return workState;
|
|
305
|
-
}
|
|
306
|
-
const workerTaskState = mapWorkerTaskStateFromResult(result);
|
|
307
|
-
if (workerTaskState) {
|
|
308
|
-
return workerTaskState;
|
|
309
|
-
}
|
|
310
|
-
const topLevelCandidates = [
|
|
311
|
-
result?.lifecycleState, result?.state, result?.status, result?.lifecycle?.state,
|
|
312
|
-
result?.report?.lifecycleState, result?.report?.state, result?.report?.status,
|
|
313
|
-
result?.report?.lifecycle?.state, result?.report?.runtime?.state, result?.report?.work?.state
|
|
314
|
-
];
|
|
315
|
-
for (const candidate of topLevelCandidates) {
|
|
316
|
-
const state = lifecycleStateFromSignalValue(candidate);
|
|
317
|
-
if (state) {
|
|
318
|
-
return state;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
const steps = Array.isArray(result?.stepsRun) ? result.stepsRun : [];
|
|
322
|
-
for (const row of steps) {
|
|
323
|
-
const stepCandidates = [
|
|
324
|
-
row?.lifecycleState, row?.state, row?.status, row?.code, row?.errorCode, row?.reason,
|
|
325
|
-
row?.kind, row?.type, row?.error, row?.failure, row?.details, row?.result
|
|
326
|
-
];
|
|
327
|
-
for (const candidate of stepCandidates) {
|
|
328
|
-
const state = lifecycleStateFromSignalValue(candidate);
|
|
329
|
-
if (state) {
|
|
330
|
-
return state;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
function deriveLifecycleState(result, lifecycleVerdict) {
|
|
338
|
-
if (lifecycleVerdict === VERDICT.VERIFIED) {
|
|
339
|
-
return 'completed';
|
|
340
|
-
}
|
|
341
|
-
const structuredState = resolveLifecycleStateFromResult(result);
|
|
342
|
-
if (structuredState) {
|
|
343
|
-
return structuredState;
|
|
344
|
-
}
|
|
345
|
-
if (lifecycleVerdict === VERDICT.NOT_VERIFIED) return 'safe-stop';
|
|
346
|
-
return 'failed';
|
|
347
|
-
}
|
|
348
|
-
|
|
349
188
|
function addCapabilityToken(set, value) {
|
|
350
189
|
if (typeof value === 'string' && value.trim()) set.add(value.trim());
|
|
351
190
|
}
|
|
@@ -361,9 +200,34 @@ function collectCapabilitiesFromWorkSteps(out, steps) {
|
|
|
361
200
|
addCapabilityToken(out, row.executionOutcome.capabilityKey);
|
|
362
201
|
addCapabilityToken(out, row.executionOutcome.capability);
|
|
363
202
|
}
|
|
203
|
+
const execution = row.capabilityExecution;
|
|
204
|
+
if (execution && typeof execution === 'object') {
|
|
205
|
+
addCapabilityToken(out, execution.capabilityKey);
|
|
206
|
+
addCapabilityToken(out, execution.capability);
|
|
207
|
+
}
|
|
364
208
|
}
|
|
365
209
|
}
|
|
366
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Identity-preflight CIP fallback uses operationId "operation" (or omits it).
|
|
213
|
+
* That is a Reality probe log, not an observed write capability.
|
|
214
|
+
* @param {object} row
|
|
215
|
+
* @returns {boolean}
|
|
216
|
+
*/
|
|
217
|
+
function cipArtifactIsUnspecifiedOperation(row) {
|
|
218
|
+
const fingerprint = typeof row.fingerprint === 'string' ? row.fingerprint : '';
|
|
219
|
+
const opMatch = fingerprint.match(/(?:^|[|,])operationId=([^|,]+)/);
|
|
220
|
+
if (opMatch) {
|
|
221
|
+
const operationId = opMatch[1].trim();
|
|
222
|
+
return !operationId || operationId === 'operation';
|
|
223
|
+
}
|
|
224
|
+
const artifactRef = typeof row.artifactRef === 'string' ? row.artifactRef : '';
|
|
225
|
+
if (/^cip-log:[^:]+:[^:]+:operation:/.test(artifactRef)) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
return /(?:^|[|,])capabilityKey=/.test(fingerprint);
|
|
229
|
+
}
|
|
230
|
+
|
|
367
231
|
/**
|
|
368
232
|
* Work-result artifactIndex often carries CIP fingerprints like
|
|
369
233
|
* `capabilityKey=customer.createBasic|operationId=createbasic` when steps[] is empty.
|
|
@@ -374,6 +238,7 @@ function collectCapabilitiesFromArtifactIndex(out, artifacts) {
|
|
|
374
238
|
if (!Array.isArray(artifacts)) return;
|
|
375
239
|
for (const row of artifacts) {
|
|
376
240
|
if (!row || typeof row !== 'object') continue;
|
|
241
|
+
if (cipArtifactIsUnspecifiedOperation(row)) continue;
|
|
377
242
|
addCapabilityToken(out, row.capabilityKey);
|
|
378
243
|
addCapabilityToken(out, row.capability);
|
|
379
244
|
const fingerprint = typeof row.fingerprint === 'string' ? row.fingerprint : '';
|
|
@@ -414,6 +279,7 @@ function collectObservedCapabilities(result) {
|
|
|
414
279
|
module.exports = {
|
|
415
280
|
SUPPORTED_LIFECYCLE_STATES,
|
|
416
281
|
roleAssistantTestsDir,
|
|
282
|
+
listTestCaseFiles,
|
|
417
283
|
loadRoleAssistantTestCase,
|
|
418
284
|
deriveLifecycleState,
|
|
419
285
|
collectObservedCapabilities,
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map local Role Assistant YAML cases to a published test pack (and back).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview YAML specification only — currentStatus stays on dataplane
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const yaml = require('js-yaml');
|
|
13
|
+
const fs = require('../internal/fs-real-sync');
|
|
14
|
+
const { roleAssistantTestsDir } = require('./test-cases');
|
|
15
|
+
const { discoverSuiteCaseFiles } = require('./test-suite');
|
|
16
|
+
const { roleAssistantSystemKey } = require('../utils/role-assistant-paths');
|
|
17
|
+
|
|
18
|
+
const PACK_API_VERSION = 'dataplane.aifabrix.ai/v1';
|
|
19
|
+
const PACK_KIND = 'RoleAssistantTestPack';
|
|
20
|
+
const STATUS_KEYS = new Set(['currentStatus', 'lastTestedAt', 'summary', 'sourceFile']);
|
|
21
|
+
const YAML_SPEC_KEYS = [
|
|
22
|
+
'caseId',
|
|
23
|
+
'input',
|
|
24
|
+
'answers',
|
|
25
|
+
'approvals',
|
|
26
|
+
'expected',
|
|
27
|
+
'preflight',
|
|
28
|
+
'metadata'
|
|
29
|
+
];
|
|
30
|
+
const PACK_INPUT_ALIASES = ['executionPath', 'roleRef', 'businessRoleRef'];
|
|
31
|
+
|
|
32
|
+
function isYamlName(name) {
|
|
33
|
+
return /\.(ya?ml)$/i.test(name);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function listRootYamlFiles(testsDir) {
|
|
37
|
+
if (!fs.existsSync(testsDir)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
return fs.readdirSync(testsDir)
|
|
41
|
+
.filter((name) => isYamlName(name))
|
|
42
|
+
.map((name) => path.join(testsDir, name));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function copySpecFields(parsed, caseId) {
|
|
46
|
+
const out = { caseId };
|
|
47
|
+
for (const key of YAML_SPEC_KEYS) {
|
|
48
|
+
if (key === 'caseId' || parsed[key] === undefined) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
out[key] = parsed[key];
|
|
52
|
+
}
|
|
53
|
+
const input = out.input && typeof out.input === 'object' && !Array.isArray(out.input)
|
|
54
|
+
? out.input
|
|
55
|
+
: {};
|
|
56
|
+
for (const key of PACK_INPUT_ALIASES) {
|
|
57
|
+
if (input[key] !== undefined) {
|
|
58
|
+
out[key] = input[key];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function specCaseFromFile(filePath) {
|
|
65
|
+
const parsed = yaml.load(fs.readFileSync(filePath, 'utf8'));
|
|
66
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
67
|
+
throw new Error(`Test case must be an object: ${filePath}`);
|
|
68
|
+
}
|
|
69
|
+
const fileBase = path.basename(filePath, path.extname(filePath));
|
|
70
|
+
const caseId = String(parsed.caseId || fileBase).trim();
|
|
71
|
+
if (!caseId) {
|
|
72
|
+
throw new Error(`Test case is missing caseId: ${filePath}`);
|
|
73
|
+
}
|
|
74
|
+
return copySpecFields(parsed, caseId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function collectSuiteMap(testsDir) {
|
|
78
|
+
const suites = new Map();
|
|
79
|
+
const add = (suiteId, filePath) => {
|
|
80
|
+
const id = String(suiteId || 'default').trim() || 'default';
|
|
81
|
+
if (!suites.has(id)) {
|
|
82
|
+
suites.set(id, []);
|
|
83
|
+
}
|
|
84
|
+
suites.get(id).push(specCaseFromFile(filePath));
|
|
85
|
+
};
|
|
86
|
+
for (const filePath of listRootYamlFiles(testsDir)) {
|
|
87
|
+
add('default', filePath);
|
|
88
|
+
}
|
|
89
|
+
for (const row of discoverSuiteCaseFiles(testsDir)) {
|
|
90
|
+
add(row.suite, row.absPath);
|
|
91
|
+
}
|
|
92
|
+
return suites;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildRoleAssistantTestPack(systemKey, suiteMap) {
|
|
96
|
+
const key = roleAssistantSystemKey(systemKey);
|
|
97
|
+
const suites = [];
|
|
98
|
+
for (const [suiteId, cases] of suiteMap.entries()) {
|
|
99
|
+
if (cases.length > 0) {
|
|
100
|
+
suites.push({ suiteId, cases });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
apiVersion: PACK_API_VERSION,
|
|
105
|
+
kind: PACK_KIND,
|
|
106
|
+
metadata: { key },
|
|
107
|
+
spec: { suites }
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function mapLocalTestsToPack(systemKey, options = {}) {
|
|
112
|
+
const testsDir = roleAssistantTestsDir(systemKey, options);
|
|
113
|
+
if (!fs.existsSync(testsDir)) {
|
|
114
|
+
return { skipped: true, reason: 'No tests folder' };
|
|
115
|
+
}
|
|
116
|
+
const suiteMap = collectSuiteMap(testsDir);
|
|
117
|
+
const pack = buildRoleAssistantTestPack(systemKey, suiteMap);
|
|
118
|
+
if (!pack.spec.suites.length) {
|
|
119
|
+
return { skipped: true, reason: 'No test cases in tests folder' };
|
|
120
|
+
}
|
|
121
|
+
return { skipped: false, pack, testsDir };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function mergePackAliasesIntoInput(packCase, input) {
|
|
125
|
+
const next = { ...input };
|
|
126
|
+
for (const key of PACK_INPUT_ALIASES) {
|
|
127
|
+
if (packCase[key] !== undefined && next[key] === undefined) {
|
|
128
|
+
next[key] = packCase[key];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return next;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function yamlFromPackCase(packCase) {
|
|
135
|
+
const body = {};
|
|
136
|
+
for (const key of YAML_SPEC_KEYS) {
|
|
137
|
+
if (packCase[key] === undefined || STATUS_KEYS.has(key)) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
body[key] = packCase[key];
|
|
141
|
+
}
|
|
142
|
+
const input = body.input && typeof body.input === 'object' && !Array.isArray(body.input)
|
|
143
|
+
? body.input
|
|
144
|
+
: {};
|
|
145
|
+
const merged = mergePackAliasesIntoInput(packCase, input);
|
|
146
|
+
if (Object.keys(merged).length > 0) {
|
|
147
|
+
body.input = merged;
|
|
148
|
+
}
|
|
149
|
+
return yaml.dump(body, { lineWidth: 120, noRefs: true, sortKeys: false });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function writePackToTestsDir(pack, testsDir) {
|
|
153
|
+
const suites = pack && pack.spec && Array.isArray(pack.spec.suites) ? pack.spec.suites : [];
|
|
154
|
+
fs.mkdirSync(testsDir, { recursive: true });
|
|
155
|
+
let written = 0;
|
|
156
|
+
for (const suite of suites) {
|
|
157
|
+
const suiteId = String((suite && suite.suiteId) || 'default').trim() || 'default';
|
|
158
|
+
const suiteDir = path.join(testsDir, suiteId);
|
|
159
|
+
fs.mkdirSync(suiteDir, { recursive: true });
|
|
160
|
+
const cases = Array.isArray(suite.cases) ? suite.cases : [];
|
|
161
|
+
for (const row of cases) {
|
|
162
|
+
const caseId = String((row && row.caseId) || '').trim();
|
|
163
|
+
if (!caseId) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
fs.writeFileSync(path.join(suiteDir, `${caseId}.yaml`), yamlFromPackCase(row), 'utf8');
|
|
167
|
+
written += 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return written;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
PACK_API_VERSION,
|
|
175
|
+
PACK_KIND,
|
|
176
|
+
YAML_SPEC_KEYS,
|
|
177
|
+
mapLocalTestsToPack,
|
|
178
|
+
writePackToTestsDir,
|
|
179
|
+
specCaseFromFile
|
|
180
|
+
};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Assistant test-pack sidecar: upload PUT, download GET, case status PATCH.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Shared CLI and builder-api adapters — no Task/PE or /runs
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const os = require('os');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const logger = require('../utils/logger');
|
|
14
|
+
const { formatWarningLine } = require('../utils/cli-test-layout-chalk');
|
|
15
|
+
const { isDigitalWorkerKind } = require('../utils/platform-shell-package');
|
|
16
|
+
const { roleAssistantTestsDir } = require('./test-cases');
|
|
17
|
+
const { mapLocalTestsToPack, writePackToTestsDir } = require('./test-pack-map');
|
|
18
|
+
const {
|
|
19
|
+
upsertRoleAssistantTestPack,
|
|
20
|
+
getRoleAssistantTestPack,
|
|
21
|
+
patchRoleAssistantTestCaseStatus
|
|
22
|
+
} = require('../api/role-assistant-test-pack.api');
|
|
23
|
+
const fs = require('../internal/fs-real-sync');
|
|
24
|
+
|
|
25
|
+
function skipResult(reason) {
|
|
26
|
+
return { skipped: true, reason };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isRoleAssistantPayload(payload) {
|
|
30
|
+
return isDigitalWorkerKind(payload && payload.application);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function runTestsSidecar(ctx, sidecar, quietSidecar) {
|
|
34
|
+
if (!isRoleAssistantPayload(ctx.payload)) {
|
|
35
|
+
sidecar.tests = skipResult('Not a Role Assistant package');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (ctx.options && ctx.options.dryRun === true) {
|
|
39
|
+
sidecar.tests = skipResult('Dry run');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const mapped = mapLocalTestsToPack(ctx.systemKey, {
|
|
43
|
+
pathOptions: (ctx.options && ctx.options.pathOptions) || {},
|
|
44
|
+
testsDir: ctx.options && ctx.options.testsDir
|
|
45
|
+
});
|
|
46
|
+
if (mapped.skipped) {
|
|
47
|
+
sidecar.tests = skipResult(mapped.reason);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const uploaded = await upsertRoleAssistantTestPack(
|
|
52
|
+
ctx.dataplaneUrl,
|
|
53
|
+
ctx.authConfig,
|
|
54
|
+
ctx.systemKey,
|
|
55
|
+
mapped.pack
|
|
56
|
+
);
|
|
57
|
+
sidecar.tests = {
|
|
58
|
+
skipped: false,
|
|
59
|
+
packVersion: uploaded && uploaded.packVersion,
|
|
60
|
+
packKey: uploaded && uploaded.packKey
|
|
61
|
+
};
|
|
62
|
+
} catch (err) {
|
|
63
|
+
sidecar.tests = skipResult(err.message || String(err));
|
|
64
|
+
if (!quietSidecar) {
|
|
65
|
+
logger.log(formatWarningLine(`Role assistant tests upload skipped: ${err.message}`));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function exportRoleAssistantTests(params) {
|
|
71
|
+
const { systemKey, dataplaneUrl, authConfig, options = {} } = params;
|
|
72
|
+
const row = await getRoleAssistantTestPack(dataplaneUrl, authConfig, systemKey, {
|
|
73
|
+
allowMissing: true
|
|
74
|
+
});
|
|
75
|
+
if (!row || !row.pack) {
|
|
76
|
+
return skipResult('No published test pack');
|
|
77
|
+
}
|
|
78
|
+
const testsDir = roleAssistantTestsDir(systemKey, {
|
|
79
|
+
pathOptions: options.pathOptions || {},
|
|
80
|
+
testsDir: options.testsDir
|
|
81
|
+
});
|
|
82
|
+
const written = writePackToTestsDir(row.pack, testsDir);
|
|
83
|
+
return { skipped: false, written, testsDir };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function publishedTestsOwnerToken() {
|
|
87
|
+
if (typeof process.getuid === 'function') {
|
|
88
|
+
return String(process.getuid());
|
|
89
|
+
}
|
|
90
|
+
return 'u';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function publishedTestsTempDir(systemKey) {
|
|
94
|
+
const key = String(systemKey || 'pack').replace(/[^a-zA-Z0-9._-]+/g, '_');
|
|
95
|
+
return path.join(os.tmpdir(), `aifabrix-ra-tests-${publishedTestsOwnerToken()}`, key);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function materializePublishedTests(systemKey, dataplaneUrl, authConfig, destRoot) {
|
|
99
|
+
const row = await getRoleAssistantTestPack(dataplaneUrl, authConfig, systemKey, {
|
|
100
|
+
allowMissing: true
|
|
101
|
+
});
|
|
102
|
+
if (!row || !row.pack) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`No published tests for ${systemKey}. Upload the Role Assistant package first.`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (fs.existsSync(destRoot)) {
|
|
108
|
+
fs.rmSync(destRoot, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
const written = writePackToTestsDir(row.pack, destRoot);
|
|
111
|
+
return { testsDir: destRoot, written };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function caseStatusFromEvaluation(evaluation) {
|
|
115
|
+
if (!evaluation) {
|
|
116
|
+
return 'skipped';
|
|
117
|
+
}
|
|
118
|
+
if (evaluation.passed === true) {
|
|
119
|
+
return 'passed';
|
|
120
|
+
}
|
|
121
|
+
if (evaluation.passed === false) {
|
|
122
|
+
return 'failed';
|
|
123
|
+
}
|
|
124
|
+
return 'skipped';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function caseSummaryFromEvaluation(evaluation) {
|
|
128
|
+
if (!evaluation) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
const summary = evaluation.summary || evaluation.reason || evaluation.error;
|
|
132
|
+
return typeof summary === 'string' && summary.trim() ? summary.trim() : undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function loadPublishedTestsIntoOptions(systemKey, opts, authContext) {
|
|
136
|
+
if (!opts || opts.fromDataplane !== true) {
|
|
137
|
+
return opts;
|
|
138
|
+
}
|
|
139
|
+
const dest = publishedTestsTempDir(systemKey);
|
|
140
|
+
await materializePublishedTests(
|
|
141
|
+
systemKey,
|
|
142
|
+
authContext.dataplaneUrl,
|
|
143
|
+
authContext.authConfig,
|
|
144
|
+
dest
|
|
145
|
+
);
|
|
146
|
+
return { ...opts, casesRoot: dest, testsDir: dest };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function patchCaseStatusAfterRun(params) {
|
|
150
|
+
const { systemKey, caseId, evaluation, dataplaneUrl, authConfig } = params;
|
|
151
|
+
if (!dataplaneUrl || !authConfig || !caseId) {
|
|
152
|
+
return { skipped: true, reason: 'Missing dataplane context' };
|
|
153
|
+
}
|
|
154
|
+
const body = {
|
|
155
|
+
status: caseStatusFromEvaluation(evaluation),
|
|
156
|
+
testedAt: new Date().toISOString()
|
|
157
|
+
};
|
|
158
|
+
const summary = caseSummaryFromEvaluation(evaluation);
|
|
159
|
+
if (summary) {
|
|
160
|
+
body.summary = summary;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
await patchRoleAssistantTestCaseStatus(
|
|
164
|
+
dataplaneUrl,
|
|
165
|
+
authConfig,
|
|
166
|
+
systemKey,
|
|
167
|
+
caseId,
|
|
168
|
+
body
|
|
169
|
+
);
|
|
170
|
+
return { skipped: false, status: body.status };
|
|
171
|
+
} catch (err) {
|
|
172
|
+
logger.log(
|
|
173
|
+
formatWarningLine(`Could not update published case status for ${caseId}: ${err.message}`)
|
|
174
|
+
);
|
|
175
|
+
return { skipped: true, reason: err.message || String(err) };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
runTestsSidecar,
|
|
181
|
+
exportRoleAssistantTests,
|
|
182
|
+
publishedTestsTempDir,
|
|
183
|
+
materializePublishedTests,
|
|
184
|
+
loadPublishedTestsIntoOptions,
|
|
185
|
+
caseStatusFromEvaluation,
|
|
186
|
+
patchCaseStatusAfterRun
|
|
187
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role assistant --debug Work Result fetch and log persistence.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Technical work-result depth and logs under role-assistant/<role>/logs/
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('../internal/fs-real-sync');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { getWorkExecutionResult } = require('../api/work.api');
|
|
14
|
+
const { sanitizeForLog } = require('../utils/test-log-writer');
|
|
15
|
+
const {
|
|
16
|
+
getRoleAssistantPath,
|
|
17
|
+
roleAssistantSystemKey
|
|
18
|
+
} = require('../utils/role-assistant-paths');
|
|
19
|
+
|
|
20
|
+
function requestedWorkResultDepth(options) {
|
|
21
|
+
return options && options.debug === true ? 'technical' : 'business';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function fetchWorkHubResult(dataplaneUrl, authConfig, processExecutionId, options = {}) {
|
|
25
|
+
try {
|
|
26
|
+
const workResult = await getWorkExecutionResult(dataplaneUrl, authConfig, processExecutionId, {
|
|
27
|
+
requestedDepth: requestedWorkResultDepth(options),
|
|
28
|
+
format: 'json'
|
|
29
|
+
});
|
|
30
|
+
return { workResult, workResultError: null };
|
|
31
|
+
} catch (error) {
|
|
32
|
+
return { workResult: null, workResultError: error.message || String(error) };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function persistRoleAssistantDebugLog(roleKey, payload, options = {}) {
|
|
37
|
+
if (!options || options.debug !== true) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const systemKey = roleAssistantSystemKey(roleKey);
|
|
41
|
+
const logsDir = path.join(getRoleAssistantPath(systemKey), 'logs');
|
|
42
|
+
fs.mkdirSync(logsDir, { recursive: true });
|
|
43
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
44
|
+
const filePath = path.join(logsDir, `work-result-technical-${timestamp}.json`);
|
|
45
|
+
const sanitized = sanitizeForLog(payload);
|
|
46
|
+
fs.writeFileSync(filePath, `${JSON.stringify(sanitized, null, 2)}\n`, 'utf8');
|
|
47
|
+
return filePath;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
requestedWorkResultDepth,
|
|
52
|
+
fetchWorkHubResult,
|
|
53
|
+
persistRoleAssistantDebugLog
|
|
54
|
+
};
|