@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
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTY table, JSON stdout, and --output file for search / skills.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Search CLI display (no payload logging)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const chalk = require('chalk');
|
|
13
|
+
const { formatBlockingError } = require('../utils/cli-layout-chalk');
|
|
14
|
+
const { SearchCliError } = require('./search-errors');
|
|
15
|
+
const { operationKeys, resourceTypesMap, isOperationRequired } = require('./search-skills');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} filePath
|
|
19
|
+
* @param {Object} payload
|
|
20
|
+
* @param {{ existsSync: Function, writeFileSync: Function }} fsApi
|
|
21
|
+
*/
|
|
22
|
+
function writePayloadFile(filePath, payload, fsApi) {
|
|
23
|
+
const resolved = path.resolve(filePath);
|
|
24
|
+
const dir = path.dirname(resolved);
|
|
25
|
+
if (!fsApi.existsSync(dir)) {
|
|
26
|
+
throw new SearchCliError(`Output directory does not exist: ${dir}`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
fsApi.writeFileSync(resolved, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throw new SearchCliError(`Cannot write --output file: ${err.message || err}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {*} value
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
function cellValue(value) {
|
|
40
|
+
if (value === null || value === undefined) {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
if (typeof value === 'object') {
|
|
44
|
+
return JSON.stringify(value);
|
|
45
|
+
}
|
|
46
|
+
return String(value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} text
|
|
51
|
+
* @param {number} width
|
|
52
|
+
* @returns {string}
|
|
53
|
+
*/
|
|
54
|
+
function padCell(text, width) {
|
|
55
|
+
const value = String(text ?? '');
|
|
56
|
+
if (value.length <= width) {
|
|
57
|
+
return value.padEnd(width);
|
|
58
|
+
}
|
|
59
|
+
if (width <= 1) {
|
|
60
|
+
return value.slice(0, width);
|
|
61
|
+
}
|
|
62
|
+
return `${value.slice(0, width - 1)}…`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {Object[]} rows
|
|
67
|
+
* @param {string[]} [fieldList]
|
|
68
|
+
* @returns {string[]}
|
|
69
|
+
*/
|
|
70
|
+
function columnKeys(rows, fieldList) {
|
|
71
|
+
if (Array.isArray(fieldList) && fieldList.length) {
|
|
72
|
+
return fieldList;
|
|
73
|
+
}
|
|
74
|
+
const first = rows[0];
|
|
75
|
+
return first && typeof first === 'object' ? Object.keys(first) : [];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {Object} meta
|
|
80
|
+
* @param {Object[]} rows
|
|
81
|
+
* @returns {string}
|
|
82
|
+
*/
|
|
83
|
+
function formatHitsLine(meta, rows) {
|
|
84
|
+
const count = Array.isArray(rows) ? rows.length : 0;
|
|
85
|
+
const page = meta.currentPage || meta.page || 1;
|
|
86
|
+
const totalPages = meta.totalPages || 1;
|
|
87
|
+
const pageSize = meta.pageSize || count;
|
|
88
|
+
return `Hits ${count} page ${page}/${totalPages} pageSize=${pageSize}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {Object} body
|
|
93
|
+
* @param {Object} payload
|
|
94
|
+
* @returns {string}
|
|
95
|
+
*/
|
|
96
|
+
function formatSearchHeader(body, payload) {
|
|
97
|
+
const meta = (payload && payload.meta) || {};
|
|
98
|
+
const resultMode = meta.resultMode || '';
|
|
99
|
+
const op = body.operation ? ` operation=${body.operation}` : '';
|
|
100
|
+
const mode = resultMode ? ` resultMode=${resultMode}` : '';
|
|
101
|
+
return `Search role=${body.roleRef} type=${body.resourceType}${op}${mode}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {Object[]} rows
|
|
106
|
+
* @param {string[]} keys
|
|
107
|
+
* @param {Object} log
|
|
108
|
+
*/
|
|
109
|
+
function printHitsTable(rows, keys, log) {
|
|
110
|
+
if (!keys.length) {
|
|
111
|
+
log.log('(no rows)');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const widths = keys.map((key) =>
|
|
115
|
+
Math.min(
|
|
116
|
+
24,
|
|
117
|
+
Math.max(key.length, ...rows.map((row) => cellValue(row[key]).length), 4)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
log.log(chalk.gray(keys.map((key, i) => padCell(key, widths[i])).join(' ')));
|
|
121
|
+
for (const row of rows) {
|
|
122
|
+
log.log(keys.map((key, i) => padCell(cellValue(row[key]), widths[i])).join(' '));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {Object} related
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
function formatRelatedSummary(related) {
|
|
131
|
+
const parts = Object.keys(related).map((type) => {
|
|
132
|
+
const page = related[type];
|
|
133
|
+
const n = page && Array.isArray(page.data) ? page.data.length : 0;
|
|
134
|
+
return `${type} (${n})`;
|
|
135
|
+
});
|
|
136
|
+
return parts.length ? `Related ${parts.join(' ')}` : '';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @param {Object} payload
|
|
141
|
+
* @param {Object} log
|
|
142
|
+
*/
|
|
143
|
+
function printSkillsTTY(payload, log) {
|
|
144
|
+
const typeMap = resourceTypesMap(payload);
|
|
145
|
+
const keys = Object.keys(typeMap);
|
|
146
|
+
if (!keys.length) {
|
|
147
|
+
log.log('No searchable resource types for this Role Assistant.');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
log.log(`Skills role=${payload.roleRef || ''}`.trim());
|
|
151
|
+
for (const key of keys) {
|
|
152
|
+
const spec = typeMap[key] || {};
|
|
153
|
+
const ops = operationKeys(spec);
|
|
154
|
+
const req = isOperationRequired(spec) ? 'required' : 'optional';
|
|
155
|
+
const opText = ops.length ? ops.join(', ') : '(none)';
|
|
156
|
+
log.log(` ${key} operations=${opText} operationRequired=${req}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @param {Object} opts
|
|
162
|
+
* @param {Object} payload
|
|
163
|
+
* @param {Object} log
|
|
164
|
+
* @param {{ existsSync: Function, writeFileSync: Function }} fsApi
|
|
165
|
+
*/
|
|
166
|
+
function emitPayload(opts, payload, log, fsApi) {
|
|
167
|
+
const json = opts.json === true;
|
|
168
|
+
if (opts.output) {
|
|
169
|
+
writePayloadFile(opts.output, payload, fsApi);
|
|
170
|
+
}
|
|
171
|
+
if (json) {
|
|
172
|
+
log.log(JSON.stringify(payload));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @param {Object} opts
|
|
178
|
+
* @param {Object} body
|
|
179
|
+
* @param {Object} payload
|
|
180
|
+
* @param {Object} log
|
|
181
|
+
* @param {Object} fsApi
|
|
182
|
+
*/
|
|
183
|
+
function emitSearchSuccess(opts, body, payload, log, fsApi) {
|
|
184
|
+
emitPayload(opts, payload, log, fsApi);
|
|
185
|
+
if (opts.json === true) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const rows = payload && Array.isArray(payload.data) ? payload.data : [];
|
|
189
|
+
const meta = (payload && payload.meta) || {};
|
|
190
|
+
log.log(formatSearchHeader(body, payload));
|
|
191
|
+
log.log(formatHitsLine(meta, rows));
|
|
192
|
+
printHitsTable(rows, columnKeys(rows, body.fields), log);
|
|
193
|
+
if (payload && payload.related && typeof payload.related === 'object') {
|
|
194
|
+
const summary = formatRelatedSummary(payload.related);
|
|
195
|
+
if (summary) log.log(summary);
|
|
196
|
+
if (opts.verbose === true) {
|
|
197
|
+
log.log(JSON.stringify(payload.related, null, 2));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @param {Object} opts
|
|
204
|
+
* @param {Object} payload
|
|
205
|
+
* @param {Object} log
|
|
206
|
+
* @param {Object} fsApi
|
|
207
|
+
*/
|
|
208
|
+
function emitSkillsSuccess(opts, payload, log, fsApi) {
|
|
209
|
+
emitPayload(opts, payload, log, fsApi);
|
|
210
|
+
if (opts.json !== true) {
|
|
211
|
+
printSkillsTTY(payload, log);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @param {Object} opts
|
|
217
|
+
* @param {string} message
|
|
218
|
+
* @param {Object} log
|
|
219
|
+
*/
|
|
220
|
+
function emitSearchError(opts, message, log) {
|
|
221
|
+
if (opts && opts.json === true) {
|
|
222
|
+
log.log(JSON.stringify({ error: message }));
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
log.error(formatBlockingError(message));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
module.exports = {
|
|
229
|
+
writePayloadFile,
|
|
230
|
+
cellValue,
|
|
231
|
+
columnKeys,
|
|
232
|
+
formatHitsLine,
|
|
233
|
+
formatSearchHeader,
|
|
234
|
+
formatRelatedSummary,
|
|
235
|
+
emitSearchSuccess,
|
|
236
|
+
emitSkillsSuccess,
|
|
237
|
+
emitSearchError
|
|
238
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit codes and fail-closed errors for aifabrix search.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Search CLI errors (auth = 3, other blocking = 1)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message
|
|
13
|
+
* @param {number} [exitCode]
|
|
14
|
+
*/
|
|
15
|
+
class SearchCliError extends Error {
|
|
16
|
+
constructor(message, exitCode = 1) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'SearchCliError';
|
|
19
|
+
this.exitCode = exitCode;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Error|SearchCliError|string} err
|
|
25
|
+
* @returns {number}
|
|
26
|
+
*/
|
|
27
|
+
function exitCodeForSearchError(err) {
|
|
28
|
+
if (Number.isInteger(err && err.exitCode) && err.exitCode > 0) {
|
|
29
|
+
return err.exitCode;
|
|
30
|
+
}
|
|
31
|
+
const message = String((err && err.message) || err);
|
|
32
|
+
if (/auth|login|token|unreachable/i.test(message)) {
|
|
33
|
+
return 3;
|
|
34
|
+
}
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} message
|
|
40
|
+
* @returns {SearchCliError}
|
|
41
|
+
*/
|
|
42
|
+
function authRequiredError(message) {
|
|
43
|
+
return new SearchCliError(message, 3);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
SearchCliError,
|
|
48
|
+
exitCodeForSearchError,
|
|
49
|
+
authRequiredError
|
|
50
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTY inquirer lists for Role Assistant, resource type, and operation.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Interactive pickers for aifabrix search (inject prompt in tests)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { SearchCliError } = require('./search-errors');
|
|
12
|
+
const { listAssignedRoleAssistants } = require('./search-roles');
|
|
13
|
+
const { operationKeys } = require('./search-skills');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {Object} options
|
|
17
|
+
* @param {Function} [isTty]
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function isInteractive(options, isTty) {
|
|
21
|
+
if (options && options.json === true) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
if (options && options.interactive === false) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const check = isTty || (() => Boolean(process.stdin && process.stdin.isTTY));
|
|
28
|
+
return Boolean(check());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {string[]} missing
|
|
33
|
+
* @returns {SearchCliError}
|
|
34
|
+
*/
|
|
35
|
+
function missingFlagsError(missing) {
|
|
36
|
+
const listed = missing.join(' and ');
|
|
37
|
+
return new SearchCliError(
|
|
38
|
+
`Missing ${listed}. Run in a terminal to pick, or pass ${listed}.`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {Function} prompt
|
|
44
|
+
* @param {string} name
|
|
45
|
+
* @param {string} message
|
|
46
|
+
* @param {Array<{ name: string, value: string }>} choices
|
|
47
|
+
* @returns {Promise<string>}
|
|
48
|
+
*/
|
|
49
|
+
async function promptList(prompt, name, message, choices) {
|
|
50
|
+
const ask = prompt || ((qs) => require('inquirer').prompt(qs));
|
|
51
|
+
const answers = await ask([
|
|
52
|
+
{
|
|
53
|
+
type: 'list',
|
|
54
|
+
name,
|
|
55
|
+
message,
|
|
56
|
+
choices
|
|
57
|
+
}
|
|
58
|
+
]);
|
|
59
|
+
return String((answers && answers[name]) || '').trim();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {{ dataplaneUrl: string, authConfig: Object }} ctx
|
|
64
|
+
* @param {Object} deps
|
|
65
|
+
* @returns {Promise<string>}
|
|
66
|
+
*/
|
|
67
|
+
async function promptRoleAssistant(ctx, deps) {
|
|
68
|
+
const workers = await listAssignedRoleAssistants(
|
|
69
|
+
ctx.dataplaneUrl,
|
|
70
|
+
ctx.authConfig,
|
|
71
|
+
deps.getWorkRoles
|
|
72
|
+
);
|
|
73
|
+
if (!workers.length) {
|
|
74
|
+
throw new SearchCliError(
|
|
75
|
+
'No Role Assistants are assigned to your account.'
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const choices = workers.map((row) => ({
|
|
79
|
+
name: `${row.key} ${row.displayName}`,
|
|
80
|
+
value: row.key
|
|
81
|
+
}));
|
|
82
|
+
return promptList(deps.prompt, 'roleRef', 'Role Assistant', choices);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @param {string[]} typeKeys
|
|
87
|
+
* @param {Object} deps
|
|
88
|
+
* @returns {Promise<string>}
|
|
89
|
+
*/
|
|
90
|
+
async function promptResourceType(typeKeys, deps) {
|
|
91
|
+
if (!typeKeys.length) {
|
|
92
|
+
throw new SearchCliError('No searchable resource types for this Role Assistant.');
|
|
93
|
+
}
|
|
94
|
+
const choices = typeKeys.map((key) => ({ name: key, value: key }));
|
|
95
|
+
return promptList(deps.prompt, 'resourceType', 'Resource type', choices);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @param {Object} spec
|
|
100
|
+
* @param {Object} deps
|
|
101
|
+
* @returns {Promise<string>}
|
|
102
|
+
*/
|
|
103
|
+
async function promptOperation(spec, deps) {
|
|
104
|
+
const keys = operationKeys(spec);
|
|
105
|
+
if (!keys.length) {
|
|
106
|
+
return '';
|
|
107
|
+
}
|
|
108
|
+
const choices = keys.map((key) => ({ name: key, value: key }));
|
|
109
|
+
return promptList(deps.prompt, 'operation', 'Operation', choices);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = {
|
|
113
|
+
isInteractive,
|
|
114
|
+
missingFlagsError,
|
|
115
|
+
promptList,
|
|
116
|
+
promptRoleAssistant,
|
|
117
|
+
promptResourceType,
|
|
118
|
+
promptOperation
|
|
119
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Assistants assigned to the current caller (work.roles).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Parse work.roles for the search picker
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { SearchCliError } = require('./search-errors');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object|Array|null|undefined} payload
|
|
15
|
+
* @returns {Object[]}
|
|
16
|
+
*/
|
|
17
|
+
function rolesArrayFromPayload(payload) {
|
|
18
|
+
let envelope = payload;
|
|
19
|
+
if (Array.isArray(envelope) && envelope.length === 1 && envelope[0] && typeof envelope[0] === 'object') {
|
|
20
|
+
envelope = envelope[0];
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(envelope && envelope.roles)) {
|
|
23
|
+
return envelope.roles;
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(envelope && envelope.data)) {
|
|
26
|
+
return envelope.data;
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(envelope)) {
|
|
29
|
+
return envelope;
|
|
30
|
+
}
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {Object} row
|
|
36
|
+
* @returns {{ key: string, displayName: string }|null}
|
|
37
|
+
*/
|
|
38
|
+
function asAssignedWorker(row) {
|
|
39
|
+
if (!row || typeof row !== 'object') {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (row.availableToCaller === false) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const key = String(row.roleRef || row.role_ref || row.key || '').trim();
|
|
46
|
+
if (!key) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return { key, displayName: String(row.name || row.displayName || key).trim() };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {Object|Array|null|undefined} payload
|
|
54
|
+
* @returns {Array<{ key: string, displayName: string }>}
|
|
55
|
+
*/
|
|
56
|
+
function assignedWorkersFromPayload(payload) {
|
|
57
|
+
const workers = [];
|
|
58
|
+
for (const row of rolesArrayFromPayload(payload)) {
|
|
59
|
+
const worker = asAssignedWorker(row);
|
|
60
|
+
if (worker) workers.push(worker);
|
|
61
|
+
}
|
|
62
|
+
return workers;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {string} dataplaneUrl
|
|
67
|
+
* @param {Object} authConfig
|
|
68
|
+
* @param {Function} getWorkRolesFn
|
|
69
|
+
* @returns {Promise<Array<{ key: string, displayName: string }>>}
|
|
70
|
+
*/
|
|
71
|
+
async function listAssignedRoleAssistants(dataplaneUrl, authConfig, getWorkRolesFn) {
|
|
72
|
+
const res = await getWorkRolesFn(dataplaneUrl, authConfig);
|
|
73
|
+
if (!res || Number(res.status) !== 200) {
|
|
74
|
+
const text = String((res && res.errorText) || '').trim();
|
|
75
|
+
throw new SearchCliError(text || 'Unable to list Role Assistants. Check login and try again.');
|
|
76
|
+
}
|
|
77
|
+
return assignedWorkersFromPayload(res.payload);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
rolesArrayFromPayload,
|
|
82
|
+
asAssignedWorker,
|
|
83
|
+
assignedWorkersFromPayload,
|
|
84
|
+
listAssignedRoleAssistants
|
|
85
|
+
};
|