@aifabrix/builder 2.54.1 → 2.55.2
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 +172 -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 +272 -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/start.js +310 -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/deploy.js +7 -4
- package/lib/app/list-external-systems.js +2 -1
- package/lib/app/offer-create-from-template.js +184 -0
- 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-app.js +8 -1
- package/lib/cli/setup-auth.js +11 -2
- 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 +149 -0
- package/lib/commands/agent-kit.js +417 -0
- package/lib/commands/auth-status-user.js +99 -0
- package/lib/commands/auth-status.js +14 -4
- package/lib/commands/channel-add-help.js +5 -5
- package/lib/commands/datasource-capability-relate-cli.js +5 -4
- package/lib/commands/datasource-load-export-cli.js +7 -2
- package/lib/commands/datasource-test-trust-cli.js +5 -1
- package/lib/commands/governance-command-action.js +5 -4
- package/lib/commands/identity-membership-role-cache.js +6 -1
- package/lib/commands/lifecycle-command-action.js +16 -15
- package/lib/commands/login-credentials.js +8 -3
- package/lib/commands/login-device.js +14 -5
- package/lib/commands/login.js +14 -1
- package/lib/commands/logout.js +50 -15
- 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 +140 -59
- 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-governance-command-action.js +9 -7
- package/lib/commands/verify-operations-command-action.js +9 -8
- 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/commands/verify-trust-command-action.js +6 -5
- 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 +8 -3
- package/lib/generator/helpers.js +12 -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 +232 -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/knowledge-sync-settings-push.js +172 -0
- package/lib/role-assistant/knowledge-sync.js +9 -126
- 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 +149 -31
- package/lib/role-assistant/test-cases-evidence.js +44 -5
- package/lib/role-assistant/test-cases-honesty.js +155 -6
- package/lib/role-assistant/test-cases-lifecycle.js +297 -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 +53 -10
- package/lib/schema/external-datasource.schema.json +36 -5
- package/lib/schema/external-system.schema.json +20 -2
- package/lib/schema/infra-parameter.schema.json +51 -3
- package/lib/schema/infra.parameter.yaml +476 -40
- package/lib/schema/role-assistant-test-case.schema.json +408 -0
- package/lib/schema/type/document-storage.json +1 -1
- 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/api-required-permissions.js +271 -0
- package/lib/utils/api.js +16 -13
- package/lib/utils/authentication-slot-show.js +153 -0
- package/lib/utils/cli-json-exit.js +41 -0
- package/lib/utils/cli-utils.js +23 -5
- package/lib/utils/controller-url.js +78 -4
- package/lib/utils/credential-display.js +43 -1
- package/lib/utils/deployment-errors.js +15 -0
- package/lib/utils/deployment-validation-helpers.js +4 -1
- package/lib/utils/device-code.js +31 -10
- package/lib/utils/error-formatters/error-parser.js +16 -1
- package/lib/utils/error-formatters/permission-errors.js +19 -5
- 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/keycloak-realm-ready.js +5 -2
- package/lib/utils/logger.js +1 -0
- package/lib/utils/paths.js +26 -5
- package/lib/utils/schema-loader.js +37 -0
- package/lib/utils/secrets-helpers.js +2 -2
- package/lib/utils/write-stream-and-wait.js +63 -0
- package/lib/validation/validate-external-file.js +5 -1
- package/lib/validation/validate.js +3 -2
- package/package.json +20 -6
- 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 +104 -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 +59 -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 +52 -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 +51 -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 +43 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
- package/templates/agent-kit/skills/shared/hosts.md +65 -0
- package/templates/agent-kit/skills/shared/login.md +16 -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 -3
- package/templates/applications/dataplane/env.template +5 -5
- package/templates/applications/dataplane/rbac.yaml +28 -0
- package/templates/applications/keycloak/env.template +3 -3
- package/templates/applications/miso-controller/application.yaml +21 -2
- package/templates/applications/miso-controller/env.template +96 -25
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- 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
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy product-neutral workspace skeleton for agent-kit init.
|
|
3
|
+
* @fileoverview templates/agent-kit/workspace → target
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('../internal/fs-real-sync');
|
|
10
|
+
const { getKitRoot } = require('./kit-root');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
function getWorkspaceTemplateRoot() {
|
|
16
|
+
return path.join(getKitRoot(), 'workspace');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} text
|
|
21
|
+
* @param {{ workspaceName: string, year?: number, copyrightHolder?: string }} vars
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
function applyPlaceholders(text, vars) {
|
|
25
|
+
return String(text)
|
|
26
|
+
.replace(/\{\{workspaceName\}\}/g, vars.workspaceName)
|
|
27
|
+
.replace(/\{\{year\}\}/g, String(vars.year || new Date().getFullYear()))
|
|
28
|
+
.replace(/\{\{copyrightHolder\}\}/g, vars.copyrightHolder || 'Copyright Holder');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {string} absDir
|
|
33
|
+
* @param {string} relPrefix
|
|
34
|
+
* @returns {{ rel: string, abs: string }[]}
|
|
35
|
+
*/
|
|
36
|
+
function listTemplateFiles(absDir, relPrefix) {
|
|
37
|
+
if (!fs.existsSync(absDir)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const ent of fs.readdirSync(absDir, { withFileTypes: true })) {
|
|
42
|
+
const rel = relPrefix ? `${relPrefix}/${ent.name}` : ent.name;
|
|
43
|
+
const abs = path.join(absDir, ent.name);
|
|
44
|
+
if (ent.isDirectory()) {
|
|
45
|
+
out.push(...listTemplateFiles(abs, rel));
|
|
46
|
+
} else if (ent.name !== 'LICENSE.mit') {
|
|
47
|
+
out.push({ rel, abs });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {string} targetAbs
|
|
55
|
+
* @param {{ workspaceName: string, license?: string, dryRun?: boolean }} options
|
|
56
|
+
* @returns {string[]} written relative paths
|
|
57
|
+
*/
|
|
58
|
+
function writeWorkspaceSkeleton(targetAbs, options) {
|
|
59
|
+
const written = [];
|
|
60
|
+
const vars = { workspaceName: options.workspaceName };
|
|
61
|
+
const root = getWorkspaceTemplateRoot();
|
|
62
|
+
for (const file of listTemplateFiles(root, '')) {
|
|
63
|
+
const dest = path.join(targetAbs, file.rel);
|
|
64
|
+
if (!options.dryRun) {
|
|
65
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
66
|
+
const body = applyPlaceholders(fs.readFileSync(file.abs, 'utf8'), vars);
|
|
67
|
+
fs.writeFileSync(dest, body, 'utf8');
|
|
68
|
+
}
|
|
69
|
+
written.push(file.rel);
|
|
70
|
+
}
|
|
71
|
+
if (options.license === 'mit') {
|
|
72
|
+
const src = path.join(root, 'LICENSE.mit');
|
|
73
|
+
const dest = path.join(targetAbs, 'LICENSE');
|
|
74
|
+
if (!options.dryRun && fs.existsSync(src)) {
|
|
75
|
+
fs.writeFileSync(dest, applyPlaceholders(fs.readFileSync(src, 'utf8'), vars), 'utf8');
|
|
76
|
+
}
|
|
77
|
+
written.push('LICENSE');
|
|
78
|
+
}
|
|
79
|
+
if (!options.dryRun) {
|
|
80
|
+
fs.mkdirSync(path.join(targetAbs, 'integration'), { recursive: true });
|
|
81
|
+
fs.mkdirSync(path.join(targetAbs, 'role-assistant'), { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
return written;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {string} targetAbs
|
|
88
|
+
* @returns {boolean}
|
|
89
|
+
*/
|
|
90
|
+
function isNonEmptyDirectory(targetAbs) {
|
|
91
|
+
if (!fs.existsSync(targetAbs)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
const entries = fs.readdirSync(targetAbs).filter((name) => name !== '.git');
|
|
95
|
+
return entries.length > 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = {
|
|
99
|
+
getWorkspaceTemplateRoot,
|
|
100
|
+
applyPlaceholders,
|
|
101
|
+
writeWorkspaceSkeleton,
|
|
102
|
+
isNonEmptyDirectory
|
|
103
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dataplane Role Assistant test pack CRUD + case status.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview PUT/GET pack and PATCH case status
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { createDataplaneApiClient } = require('./index');
|
|
12
|
+
const { throwIfApiFailed } = require('./api-response-errors');
|
|
13
|
+
const { unwrapApiData } = require('../utils/external-system-readiness-core');
|
|
14
|
+
|
|
15
|
+
function packEndpoint(dataplaneUrl, systemIdOrKey, suffix) {
|
|
16
|
+
const base = String(dataplaneUrl || '').replace(/\/$/, '');
|
|
17
|
+
const key = encodeURIComponent(systemIdOrKey);
|
|
18
|
+
return `${base}/api/v1/external/systems/${key}/role-assistant-tests${suffix || ''}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function packPath(systemIdOrKey, suffix) {
|
|
22
|
+
const key = encodeURIComponent(systemIdOrKey);
|
|
23
|
+
return `/api/v1/external/systems/${key}/role-assistant-tests${suffix || ''}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isMissingPackResponse(res) {
|
|
27
|
+
return Boolean(res && res.success === false && Number(res.status) === 404);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* PUT /api/v1/external/systems/{systemIdOrKey}/role-assistant-tests
|
|
32
|
+
* @requiresPermission {Dataplane} external-system:update
|
|
33
|
+
* @async
|
|
34
|
+
*/
|
|
35
|
+
async function upsertRoleAssistantTestPack(dataplaneUrl, authConfig, systemIdOrKey, pack) {
|
|
36
|
+
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
37
|
+
const res = await client.put(packPath(systemIdOrKey), { body: { pack } });
|
|
38
|
+
throwIfApiFailed(res, {
|
|
39
|
+
endpointUrl: packEndpoint(dataplaneUrl, systemIdOrKey, '')
|
|
40
|
+
});
|
|
41
|
+
return unwrapApiData(res);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* GET /api/v1/external/systems/{systemIdOrKey}/role-assistant-tests
|
|
46
|
+
* @requiresPermission {Dataplane} external-system:read
|
|
47
|
+
* @async
|
|
48
|
+
*/
|
|
49
|
+
async function getRoleAssistantTestPack(dataplaneUrl, authConfig, systemIdOrKey, options = {}) {
|
|
50
|
+
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
51
|
+
const res = await client.get(packPath(systemIdOrKey));
|
|
52
|
+
if (options.allowMissing === true && isMissingPackResponse(res)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
throwIfApiFailed(res, {
|
|
56
|
+
endpointUrl: packEndpoint(dataplaneUrl, systemIdOrKey, '')
|
|
57
|
+
});
|
|
58
|
+
return unwrapApiData(res);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* PATCH /api/v1/external/systems/{systemIdOrKey}/role-assistant-tests/cases/{caseId}/status
|
|
63
|
+
* @requiresPermission {Dataplane} external-system:update
|
|
64
|
+
* @async
|
|
65
|
+
*/
|
|
66
|
+
async function patchRoleAssistantTestCaseStatus(
|
|
67
|
+
dataplaneUrl,
|
|
68
|
+
authConfig,
|
|
69
|
+
systemIdOrKey,
|
|
70
|
+
caseId,
|
|
71
|
+
body
|
|
72
|
+
) {
|
|
73
|
+
const suffix = `/cases/${encodeURIComponent(caseId)}/status`;
|
|
74
|
+
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
75
|
+
const res = await client.patch(packPath(systemIdOrKey, suffix), { body });
|
|
76
|
+
throwIfApiFailed(res, {
|
|
77
|
+
endpointUrl: packEndpoint(dataplaneUrl, systemIdOrKey, suffix)
|
|
78
|
+
});
|
|
79
|
+
return unwrapApiData(res);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = {
|
|
83
|
+
upsertRoleAssistantTestPack,
|
|
84
|
+
getRoleAssistantTestPack,
|
|
85
|
+
patchRoleAssistantTestCaseStatus
|
|
86
|
+
};
|
|
@@ -14,6 +14,7 @@ const { unwrapApiData } = require('../utils/external-system-readiness-core');
|
|
|
14
14
|
const SEARCH_TIMEOUT_MS = 120000;
|
|
15
15
|
const LAYER_B_SYSTEM_KEY = process.env.RUNTIME_ORCHESTRATION_SYSTEM_KEY || 'runtime-orchestration';
|
|
16
16
|
const LAYER_B_TOOLS = Object.freeze({
|
|
17
|
+
roles: { resourceType: 'work-roles', toolName: 'work_roles.list' },
|
|
17
18
|
skills: { resourceType: 'work-skills', toolName: 'work_skills.get' },
|
|
18
19
|
search: { resourceType: 'work-search', toolName: 'work_search.create' }
|
|
19
20
|
});
|
|
@@ -45,19 +46,31 @@ function extractErrorText(res) {
|
|
|
45
46
|
return parts.join(' ');
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/**
|
|
50
|
+
* MCP execute sometimes wraps a single JSON object as a one-element array.
|
|
51
|
+
* @param {*} value
|
|
52
|
+
* @returns {*}
|
|
53
|
+
*/
|
|
54
|
+
function unwrapSingletonObject(value) {
|
|
55
|
+
if (Array.isArray(value) && value.length === 1 && value[0] && typeof value[0] === 'object') {
|
|
56
|
+
return value[0];
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
function unwrapExecutePayload(res) {
|
|
49
|
-
const body = unwrapApiData(res);
|
|
62
|
+
const body = unwrapSingletonObject(unwrapApiData(res));
|
|
50
63
|
if (!body || typeof body !== 'object') {
|
|
51
64
|
return body;
|
|
52
65
|
}
|
|
53
66
|
if (body.result && typeof body.result === 'object') {
|
|
54
|
-
return body.result;
|
|
67
|
+
return unwrapSingletonObject(body.result);
|
|
55
68
|
}
|
|
56
69
|
if (body.json && typeof body.json === 'object') {
|
|
57
|
-
return body.json;
|
|
70
|
+
return unwrapSingletonObject(body.json);
|
|
58
71
|
}
|
|
59
72
|
if (body.root && typeof body.root === 'object') {
|
|
60
|
-
return body.root;
|
|
73
|
+
return unwrapSingletonObject(body.root);
|
|
61
74
|
}
|
|
62
75
|
return body;
|
|
63
76
|
}
|
|
@@ -94,6 +107,18 @@ async function executeLayerBTool(dataplaneUrl, authConfig, tool, args = {}) {
|
|
|
94
107
|
return normalizeLayerBResult(res);
|
|
95
108
|
}
|
|
96
109
|
|
|
110
|
+
/**
|
|
111
|
+
* GET-equivalent work.roles for the current caller.
|
|
112
|
+
* @requiresPermission {Dataplane} Authenticated (oauth2: [])
|
|
113
|
+
* @async
|
|
114
|
+
* @param {string} dataplaneUrl
|
|
115
|
+
* @param {Object} authConfig
|
|
116
|
+
* @returns {Promise<{ status: number, payload: Object|null, errorText: string, raw: Object }>}
|
|
117
|
+
*/
|
|
118
|
+
async function getWorkRoles(dataplaneUrl, authConfig) {
|
|
119
|
+
return executeLayerBTool(dataplaneUrl, authConfig, LAYER_B_TOOLS.roles, {});
|
|
120
|
+
}
|
|
121
|
+
|
|
97
122
|
/**
|
|
98
123
|
* GET-equivalent work.skills for one roleRef.
|
|
99
124
|
* Requests detail=full so search.resourceTypes (executable grammar) is present.
|
|
@@ -128,9 +153,11 @@ module.exports = {
|
|
|
128
153
|
SEARCH_TIMEOUT_MS,
|
|
129
154
|
buildLayerBExecutePath,
|
|
130
155
|
extractErrorText,
|
|
156
|
+
unwrapSingletonObject,
|
|
131
157
|
unwrapExecutePayload,
|
|
132
158
|
normalizeLayerBResult,
|
|
133
159
|
executeLayerBTool,
|
|
160
|
+
getWorkRoles,
|
|
134
161
|
getWorkSkills,
|
|
135
162
|
searchWork
|
|
136
163
|
};
|
package/lib/api/work.api.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const { createDataplaneApiClient } = require('./index');
|
|
10
|
+
const { throwIfApiFailed } = require('./api-response-errors');
|
|
10
11
|
const { unwrapApiData } = require('../utils/external-system-readiness-core');
|
|
12
|
+
const { pickHumanRespondBody } = require('../role-assistant/test-runner-respond-body');
|
|
11
13
|
|
|
12
14
|
/** Work Hub plan create runs LLM planning; 30s default is too short under load/reload. */
|
|
13
15
|
const WORK_PLAN_TIMEOUT_MS = 120000;
|
|
@@ -59,7 +61,10 @@ function assertObjectShape(value, fallbackMessage) {
|
|
|
59
61
|
*/
|
|
60
62
|
async function startWorkIntent(dataplaneUrl, authConfig, body) {
|
|
61
63
|
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
62
|
-
const res = await client.post('/api/v1/work/start', {
|
|
64
|
+
const res = await client.post('/api/v1/work/start', {
|
|
65
|
+
body,
|
|
66
|
+
timeoutMs: WORK_PLAN_TIMEOUT_MS
|
|
67
|
+
});
|
|
63
68
|
if (res && res.success === false) {
|
|
64
69
|
throw new Error(extractApiErrorMessage(res, 'work.start request failed'));
|
|
65
70
|
}
|
|
@@ -70,7 +75,7 @@ async function startWorkIntent(dataplaneUrl, authConfig, body) {
|
|
|
70
75
|
|
|
71
76
|
/**
|
|
72
77
|
* GET /api/v1/work/executions/{processExecutionId}
|
|
73
|
-
* @requiresPermission {Dataplane} worker
|
|
78
|
+
* @requiresPermission {Dataplane} worker:read
|
|
74
79
|
* @async
|
|
75
80
|
* @param {string} dataplaneUrl
|
|
76
81
|
* @param {Object} authConfig
|
|
@@ -80,12 +85,13 @@ async function startWorkIntent(dataplaneUrl, authConfig, body) {
|
|
|
80
85
|
async function getWorkExecutionStatus(dataplaneUrl, authConfig, processExecutionId) {
|
|
81
86
|
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
82
87
|
const encodedId = encodeURIComponent(String(processExecutionId));
|
|
83
|
-
const
|
|
88
|
+
const endpoint = `/api/v1/work/executions/${encodedId}`;
|
|
89
|
+
const res = await client.get(endpoint, {
|
|
84
90
|
timeoutMs: WORK_TASK_TIMEOUT_MS
|
|
85
91
|
});
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
92
|
+
throwIfApiFailed(res, {
|
|
93
|
+
endpointUrl: `${String(dataplaneUrl || '').replace(/\/$/, '')}${endpoint}`
|
|
94
|
+
});
|
|
89
95
|
const unwrapped = unwrapWorkPayload(res);
|
|
90
96
|
assertObjectShape(unwrapped, 'work.status returned an unexpected response shape');
|
|
91
97
|
return unwrapped;
|
|
@@ -105,7 +111,7 @@ async function respondWorkExecution(dataplaneUrl, authConfig, processExecutionId
|
|
|
105
111
|
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
106
112
|
const encodedId = encodeURIComponent(String(processExecutionId));
|
|
107
113
|
const res = await client.post(`/api/v1/work/executions/${encodedId}/respond`, {
|
|
108
|
-
body,
|
|
114
|
+
body: pickHumanRespondBody(body),
|
|
109
115
|
timeoutMs: WORK_TASK_TIMEOUT_MS
|
|
110
116
|
});
|
|
111
117
|
if (res && res.success === false) {
|
|
@@ -143,7 +149,7 @@ async function continueWorkExecution(dataplaneUrl, authConfig, processExecutionI
|
|
|
143
149
|
|
|
144
150
|
/**
|
|
145
151
|
* GET /api/v1/work/executions/{processExecutionId}/result
|
|
146
|
-
* @requiresPermission {Dataplane} worker
|
|
152
|
+
* @requiresPermission {Dataplane} worker:read
|
|
147
153
|
* @async
|
|
148
154
|
* @param {string} dataplaneUrl
|
|
149
155
|
* @param {Object} authConfig
|
|
@@ -154,6 +160,7 @@ async function continueWorkExecution(dataplaneUrl, authConfig, processExecutionI
|
|
|
154
160
|
async function getWorkExecutionResult(dataplaneUrl, authConfig, processExecutionId, query = {}) {
|
|
155
161
|
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
156
162
|
const encodedId = encodeURIComponent(String(processExecutionId));
|
|
163
|
+
const endpoint = `/api/v1/work/executions/${encodedId}/result`;
|
|
157
164
|
const params = {};
|
|
158
165
|
if (query && typeof query === 'object') {
|
|
159
166
|
if (query.requestedDepth) {
|
|
@@ -166,13 +173,13 @@ async function getWorkExecutionResult(dataplaneUrl, authConfig, processExecution
|
|
|
166
173
|
params.projection = String(query.projection);
|
|
167
174
|
}
|
|
168
175
|
}
|
|
169
|
-
const res = await client.get(
|
|
176
|
+
const res = await client.get(endpoint, {
|
|
170
177
|
params,
|
|
171
178
|
timeoutMs: WORK_TASK_TIMEOUT_MS
|
|
172
179
|
});
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
180
|
+
throwIfApiFailed(res, {
|
|
181
|
+
endpointUrl: `${String(dataplaneUrl || '').replace(/\/$/, '')}${endpoint}`
|
|
182
|
+
});
|
|
176
183
|
const unwrapped = unwrapWorkPayload(res);
|
|
177
184
|
assertObjectShape(unwrapped, 'work.result returned an unexpected response shape');
|
|
178
185
|
return unwrapped;
|
package/lib/app/deploy.js
CHANGED
|
@@ -23,6 +23,7 @@ const pushUtils = require('../deployment/push');
|
|
|
23
23
|
const SEP = chalk.gray('────────────────────────────────────────');
|
|
24
24
|
const logger = require('../utils/logger');
|
|
25
25
|
const { detectAppType, getBuilderPath, getIntegrationPath } = require('../utils/paths');
|
|
26
|
+
const { offerCreateFromTemplateIfMissing } = require('./offer-create-from-template');
|
|
26
27
|
const { checkApplicationExists } = require('../utils/app-existence');
|
|
27
28
|
const { loadDeploymentConfig } = require('./deploy-config');
|
|
28
29
|
const { logOfflinePathWhenType } = require('../utils/cli-utils');
|
|
@@ -462,7 +463,7 @@ async function executeDeployPipeline(appName, options) {
|
|
|
462
463
|
* @param {boolean} [options.poll] - Poll for deployment status
|
|
463
464
|
* @param {number} [options.pollInterval] - Polling interval in milliseconds
|
|
464
465
|
* @param {number} [options.pollMaxAttempts] - Max polling attempts
|
|
465
|
-
* @returns {Promise<{ result: Object, usedExternalDeploy: boolean }>} Deployment result and whether external deploy was used
|
|
466
|
+
* @returns {Promise<{ result: Object, usedExternalDeploy: boolean, appKey: string }>} Deployment result and whether external deploy was used
|
|
466
467
|
* @throws {Error} If deployment fails
|
|
467
468
|
*
|
|
468
469
|
* Controller and environment come from config.yaml (set via aifabrix login or aifabrix auth config).
|
|
@@ -473,16 +474,18 @@ async function executeDeployPipeline(appName, options) {
|
|
|
473
474
|
async function deployApp(appName, options = {}) {
|
|
474
475
|
let controllerUrl = null;
|
|
475
476
|
let usedExternalDeploy = false;
|
|
477
|
+
let resolvedName = appName;
|
|
476
478
|
|
|
477
479
|
try {
|
|
478
480
|
assertDeployNotProtectionScope(appName);
|
|
479
481
|
validateAppName(appName);
|
|
480
|
-
|
|
482
|
+
resolvedName = await offerCreateFromTemplateIfMissing(appName, options);
|
|
483
|
+
const pipeline = await executeDeployPipeline(resolvedName, options);
|
|
481
484
|
controllerUrl = pipeline.controllerUrl ?? null;
|
|
482
485
|
usedExternalDeploy = pipeline.usedExternalDeploy;
|
|
483
|
-
return { result: pipeline.result, usedExternalDeploy };
|
|
486
|
+
return { result: pipeline.result, usedExternalDeploy, appKey: resolvedName };
|
|
484
487
|
} catch (error) {
|
|
485
|
-
await handleDeploymentError(error,
|
|
488
|
+
await handleDeploymentError(error, resolvedName, controllerUrl, usedExternalDeploy);
|
|
486
489
|
}
|
|
487
490
|
}
|
|
488
491
|
|
|
@@ -15,6 +15,7 @@ const { listExternalSystems } = require('../api/external-systems.api');
|
|
|
15
15
|
const { formatApiError } = require('../utils/api-error-handler');
|
|
16
16
|
const { getListAuthToken } = require('./list');
|
|
17
17
|
const logger = require('../utils/logger');
|
|
18
|
+
const { formatLifecycleLabel } = require('../utils/external-system-readiness-compact-display');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Normalize list response shapes from the dataplane API client.
|
|
@@ -56,7 +57,7 @@ function displayExternalSystems(systems, environment, dataplaneUrl, json) {
|
|
|
56
57
|
systems.forEach((system) => {
|
|
57
58
|
const key = system.key || system.systemKey || system.id || '—';
|
|
58
59
|
const displayName = system.displayName || key;
|
|
59
|
-
const status = system.status || 'unknown';
|
|
60
|
+
const status = formatLifecycleLabel(system.status || 'unknown');
|
|
60
61
|
logger.log(`✔ ${chalk.cyan(key)} - ${displayName} (${status})`);
|
|
61
62
|
});
|
|
62
63
|
logger.log(chalk.gray(' To show details: aifabrix show <systemKey> --online\n'));
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offer to materialize a missing app from shipped application templates.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Interactive create-from-template before deploy when the app is not on disk
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 2.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const logger = require('../utils/logger');
|
|
12
|
+
const { metadata } = require('../utils/cli-test-layout-chalk');
|
|
13
|
+
const { listAvailableTemplates } = require('../validation/template');
|
|
14
|
+
const { findExistingAppType } = require('../utils/paths');
|
|
15
|
+
const { ensureAppFromTemplate } = require('../commands/up-common');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {Object} [options]
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function assumeYesCreate(options = {}) {
|
|
22
|
+
return options.yes === true || options.assumeYes === true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {Object} [deps]
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function isInteractiveCreate(deps = {}) {
|
|
30
|
+
if (process.env.CI === 'true' || process.env.CI === '1') {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (typeof deps.isTty === 'function') {
|
|
34
|
+
return Boolean(deps.isTty());
|
|
35
|
+
}
|
|
36
|
+
return Boolean(process.stdin && process.stdin.isTTY);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string[]} templates
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
function formatTemplateNames(templates) {
|
|
44
|
+
return templates.join(', ');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {string} appName
|
|
49
|
+
* @param {string[]} templates
|
|
50
|
+
* @returns {Error}
|
|
51
|
+
*/
|
|
52
|
+
function buildMissingAppError(appName, templates) {
|
|
53
|
+
const listed = templates.length > 0
|
|
54
|
+
? `Shipped templates: ${formatTemplateNames(templates)}.`
|
|
55
|
+
: 'No shipped application templates were found.';
|
|
56
|
+
const hint = templates.includes(appName)
|
|
57
|
+
? `Create it with: aifabrix deploy ${appName} --yes`
|
|
58
|
+
: 'Pass a matching template name, or create the app first.';
|
|
59
|
+
return new Error(
|
|
60
|
+
`App '${appName}' was not found under integration/ or builder/. ${listed} ${hint}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {string} appName
|
|
66
|
+
* @param {Function} promptFn
|
|
67
|
+
* @returns {Promise<boolean>}
|
|
68
|
+
*/
|
|
69
|
+
async function confirmCreateMatchingTemplate(appName, promptFn) {
|
|
70
|
+
const ask = promptFn || ((qs) => require('inquirer').prompt(qs));
|
|
71
|
+
const { create } = await ask([{
|
|
72
|
+
type: 'confirm',
|
|
73
|
+
name: 'create',
|
|
74
|
+
message: `App '${appName}' is not available. Create it from the shipped '${appName}' template?`,
|
|
75
|
+
default: true
|
|
76
|
+
}]);
|
|
77
|
+
return Boolean(create);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {string[]} templates
|
|
82
|
+
* @param {Function} promptFn
|
|
83
|
+
* @returns {Promise<string|null>}
|
|
84
|
+
*/
|
|
85
|
+
async function pickShippedTemplate(templates, promptFn) {
|
|
86
|
+
const ask = promptFn || ((qs) => require('inquirer').prompt(qs));
|
|
87
|
+
const { template } = await ask([{
|
|
88
|
+
type: 'list',
|
|
89
|
+
name: 'template',
|
|
90
|
+
message: 'App was not found. Create from which shipped application template?',
|
|
91
|
+
choices: [
|
|
92
|
+
...templates.map((name) => ({ name, value: name })),
|
|
93
|
+
{ name: 'Cancel', value: null }
|
|
94
|
+
]
|
|
95
|
+
}]);
|
|
96
|
+
return template || null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @param {string} appName
|
|
101
|
+
* @param {Object} [deps]
|
|
102
|
+
* @returns {Promise<string>}
|
|
103
|
+
*/
|
|
104
|
+
async function materializeShippedTemplate(appName, deps = {}) {
|
|
105
|
+
const copy = deps.ensureAppFromTemplate || ensureAppFromTemplate;
|
|
106
|
+
await copy(appName);
|
|
107
|
+
return appName;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {string} appName
|
|
112
|
+
* @param {string[]} templates
|
|
113
|
+
* @param {Object} options
|
|
114
|
+
* @param {Object} deps
|
|
115
|
+
* @returns {Promise<string>}
|
|
116
|
+
*/
|
|
117
|
+
async function createMatchingTemplateApp(appName, templates, options, deps) {
|
|
118
|
+
if (assumeYesCreate(options)) {
|
|
119
|
+
return materializeShippedTemplate(appName, deps);
|
|
120
|
+
}
|
|
121
|
+
if (!isInteractiveCreate(deps)) {
|
|
122
|
+
throw buildMissingAppError(appName, templates);
|
|
123
|
+
}
|
|
124
|
+
const ok = await confirmCreateMatchingTemplate(appName, deps.prompt);
|
|
125
|
+
if (!ok) {
|
|
126
|
+
throw buildMissingAppError(appName, templates);
|
|
127
|
+
}
|
|
128
|
+
return materializeShippedTemplate(appName, deps);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {string} appName
|
|
133
|
+
* @param {string[]} templates
|
|
134
|
+
* @param {Object} options
|
|
135
|
+
* @param {Object} deps
|
|
136
|
+
* @returns {Promise<string>}
|
|
137
|
+
*/
|
|
138
|
+
async function createPickedTemplateApp(appName, templates, options, deps) {
|
|
139
|
+
if (assumeYesCreate(options) || !isInteractiveCreate(deps) || templates.length === 0) {
|
|
140
|
+
throw buildMissingAppError(appName, templates);
|
|
141
|
+
}
|
|
142
|
+
const chosen = await pickShippedTemplate(templates, deps.prompt);
|
|
143
|
+
if (!chosen) {
|
|
144
|
+
throw buildMissingAppError(appName, templates);
|
|
145
|
+
}
|
|
146
|
+
if (chosen !== appName) {
|
|
147
|
+
logger.log(metadata(
|
|
148
|
+
`Creating '${chosen}' from shipped template (requested '${appName}' was not found).`
|
|
149
|
+
));
|
|
150
|
+
}
|
|
151
|
+
await materializeShippedTemplate(chosen, deps);
|
|
152
|
+
return chosen;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* If the app is missing locally, offer to create it from shipped templates.
|
|
157
|
+
*
|
|
158
|
+
* @async
|
|
159
|
+
* @function offerCreateFromTemplateIfMissing
|
|
160
|
+
* @param {string} appName - Requested app or system key
|
|
161
|
+
* @param {Object} [options] - CLI options (`yes` skips the confirm when the name matches a template)
|
|
162
|
+
* @param {Object} [deps] - Test seams (prompt, isTty, listTemplates, findExisting, ensureAppFromTemplate)
|
|
163
|
+
* @returns {Promise<string>} App key to continue with (may differ if the user picked another template)
|
|
164
|
+
* @throws {Error} When the app is missing and the user declines or cannot be prompted
|
|
165
|
+
*/
|
|
166
|
+
async function offerCreateFromTemplateIfMissing(appName, options = {}, deps = {}) {
|
|
167
|
+
const findExisting = deps.findExisting || findExistingAppType;
|
|
168
|
+
if (findExisting(appName, options)) {
|
|
169
|
+
return appName;
|
|
170
|
+
}
|
|
171
|
+
const listTemplates = deps.listTemplates || listAvailableTemplates;
|
|
172
|
+
const templates = await listTemplates();
|
|
173
|
+
if (templates.includes(appName)) {
|
|
174
|
+
return createMatchingTemplateApp(appName, templates, options, deps);
|
|
175
|
+
}
|
|
176
|
+
return createPickedTemplateApp(appName, templates, options, deps);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
offerCreateFromTemplateIfMissing,
|
|
181
|
+
buildMissingAppError,
|
|
182
|
+
assumeYesCreate,
|
|
183
|
+
isInteractiveCreate
|
|
184
|
+
};
|
package/lib/app/show-display.js
CHANGED
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
const chalk = require('chalk');
|
|
13
13
|
const logger = require('../utils/logger');
|
|
14
|
+
const { formatCredentialShowLine } = require('../utils/authentication-slot-show');
|
|
15
|
+
const {
|
|
16
|
+
formatConnectedSystemLifecycleLabel,
|
|
17
|
+
formatLifecycleLabel
|
|
18
|
+
} = require('../utils/external-system-readiness-compact-display');
|
|
14
19
|
|
|
15
20
|
function logSourceAndHeader(summary) {
|
|
16
21
|
const isOffline = summary.source === 'offline';
|
|
@@ -93,14 +98,36 @@ function logApplicationFields(a) {
|
|
|
93
98
|
logApplicationOptional(a);
|
|
94
99
|
}
|
|
95
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Draft / Published / Archived only — never controller `active`.
|
|
103
|
+
* @param {Object} a
|
|
104
|
+
* @param {Object} [summary]
|
|
105
|
+
* @returns {string|null}
|
|
106
|
+
*/
|
|
107
|
+
function resolveExternalApplicationStatusLabel(a, summary) {
|
|
108
|
+
const ext = summary && summary.externalSystem;
|
|
109
|
+
const fromDataplane = ext && !ext.error ? (ext.status || ext.dataplaneStatus) : null;
|
|
110
|
+
return formatConnectedSystemLifecycleLabel(fromDataplane || a.status);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function logExternalApplicationStatus(a, summary) {
|
|
114
|
+
const label = resolveExternalApplicationStatusLabel(a, summary);
|
|
115
|
+
if (label) logger.log(` Status: ${label}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function formatDataplaneStatusDisplay(status) {
|
|
119
|
+
if (status === undefined || status === null || status === '' || status === '—') return '—';
|
|
120
|
+
return formatConnectedSystemLifecycleLabel(status) || formatLifecycleLabel(status);
|
|
121
|
+
}
|
|
122
|
+
|
|
96
123
|
/** Application section for online + external: Key, Display name, Description, Deployment, Status (no Type; Dataplane block follows). */
|
|
97
|
-
function logApplicationFieldsOnlineExternal(a) {
|
|
124
|
+
function logApplicationFieldsOnlineExternal(a, summary) {
|
|
98
125
|
logger.log('🧷 Application - external');
|
|
99
126
|
logger.log(` Key: ${a.key ?? '—'}`);
|
|
100
127
|
logger.log(` Display name: ${a.displayName ?? '—'}`);
|
|
101
128
|
logger.log(` Description: ${a.description ?? '—'}`);
|
|
102
129
|
logger.log(' Deployment: —');
|
|
103
|
-
|
|
130
|
+
logExternalApplicationStatus(a, summary);
|
|
104
131
|
}
|
|
105
132
|
|
|
106
133
|
/** Application section for offline + external: Key, Display name, Description, Deployment, Status, Version when present. */
|
|
@@ -110,7 +137,7 @@ function logApplicationFieldsOfflineExternal(a) {
|
|
|
110
137
|
logger.log(` Display name: ${a.displayName ?? '—'}`);
|
|
111
138
|
logger.log(` Description: ${a.description ?? '—'}`);
|
|
112
139
|
logger.log(' Deployment: —');
|
|
113
|
-
|
|
140
|
+
logExternalApplicationStatus(a);
|
|
114
141
|
if (a.version !== undefined && a.version !== null) logger.log(` Version: ${a.version}`);
|
|
115
142
|
}
|
|
116
143
|
|
|
@@ -129,7 +156,7 @@ function logApplicationSection(a, summary) {
|
|
|
129
156
|
const onlineExternal = summary.source === 'online' && isExternal;
|
|
130
157
|
const offlineExternal = summary.source === 'offline' && isExternal;
|
|
131
158
|
if (onlineExternal) {
|
|
132
|
-
logApplicationFieldsOnlineExternal(a);
|
|
159
|
+
logApplicationFieldsOnlineExternal(a, summary);
|
|
133
160
|
} else if (offlineExternal) {
|
|
134
161
|
logApplicationFieldsOfflineExternal(a);
|
|
135
162
|
} else {
|
|
@@ -205,8 +232,8 @@ function logDatabasesSection(dbNames) {
|
|
|
205
232
|
function logExternalSystemMain(ext) {
|
|
206
233
|
logger.log('🧩 Dataplane');
|
|
207
234
|
logger.log(` Version: ${ext.version ?? '—'}`);
|
|
208
|
-
logger.log(` Credential: ${ext
|
|
209
|
-
logger.log(` Status: ${ext.status
|
|
235
|
+
logger.log(` Credential: ${formatCredentialShowLine(ext)}`);
|
|
236
|
+
logger.log(` Status: ${formatDataplaneStatusDisplay(ext.status)}`);
|
|
210
237
|
logger.log(` API docs: ${ext.openApiDocsPageUrl ?? ext.apiDocumentUrl ?? '—'}`);
|
|
211
238
|
logger.log(` MCP server: ${ext.mcpServerUrl ?? '—'}`);
|
|
212
239
|
logger.log(` OpenAPI spec: ${ext.apiDocumentUrl ?? '—'}`);
|