@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.
Files changed (210) hide show
  1. package/README.md +8 -0
  2. package/lib/agent-kit/apply-ops.js +82 -0
  3. package/lib/agent-kit/checksums.js +28 -0
  4. package/lib/agent-kit/classify.js +113 -0
  5. package/lib/agent-kit/claude-shim.js +61 -0
  6. package/lib/agent-kit/constants.js +55 -0
  7. package/lib/agent-kit/file-list.js +103 -0
  8. package/lib/agent-kit/host-approve.js +130 -0
  9. package/lib/agent-kit/hosting/github.js +63 -0
  10. package/lib/agent-kit/hosts.js +71 -0
  11. package/lib/agent-kit/init.js +319 -0
  12. package/lib/agent-kit/kit-root.js +17 -0
  13. package/lib/agent-kit/managed-section.js +79 -0
  14. package/lib/agent-kit/package-load.js +45 -0
  15. package/lib/agent-kit/plan-ops.js +69 -0
  16. package/lib/agent-kit/remote-prompts.js +239 -0
  17. package/lib/agent-kit/render-host-markdown.js +40 -0
  18. package/lib/agent-kit/repo-guard.js +47 -0
  19. package/lib/agent-kit/report.js +107 -0
  20. package/lib/agent-kit/run.js +82 -0
  21. package/lib/agent-kit/scm/git.js +122 -0
  22. package/lib/agent-kit/state-file.js +83 -0
  23. package/lib/agent-kit/status.js +50 -0
  24. package/lib/agent-kit/v1-detect.js +81 -0
  25. package/lib/agent-kit/validate-kit.js +87 -0
  26. package/lib/agent-kit/workspace-name.js +40 -0
  27. package/lib/agent-kit/workspace-skeleton.js +103 -0
  28. package/lib/api/role-assistant-test-pack.api.js +86 -0
  29. package/lib/api/work-search.api.js +31 -4
  30. package/lib/api/work.api.js +19 -12
  31. package/lib/app/list-external-systems.js +2 -1
  32. package/lib/app/show-display.js +33 -6
  33. package/lib/app/show.js +25 -2
  34. package/lib/channels/add-channel.js +1 -0
  35. package/lib/channels/approval-guides/claude.js +2 -2
  36. package/lib/channels/channel-add-failure.js +1 -0
  37. package/lib/channels/channel-add-remaining.js +15 -9
  38. package/lib/channels/channel-definition-status.js +115 -0
  39. package/lib/channels/channel-description.js +2 -1
  40. package/lib/channels/channel-install-envelope.js +4 -2
  41. package/lib/channels/channel-integration-generator.js +2 -0
  42. package/lib/channels/channel-runtime-resolver.js +14 -0
  43. package/lib/channels/channel-targets.js +31 -5
  44. package/lib/channels/claude-setup-values.js +4 -1
  45. package/lib/channels/slack-channel-add.js +59 -6
  46. package/lib/channels/slack-mcp-callback.js +51 -0
  47. package/lib/channels/slack-mcp-runtime.js +156 -0
  48. package/lib/channels/slack-provisioning/install-cli.js +14 -2
  49. package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
  50. package/lib/cli/index.js +4 -0
  51. package/lib/cli/setup-certification-commands.js +2 -2
  52. package/lib/cli/setup-certification.help.js +3 -1
  53. package/lib/commands/agent-kit-help.js +79 -0
  54. package/lib/commands/agent-kit.js +346 -0
  55. package/lib/commands/channel-add-help.js +5 -5
  56. package/lib/commands/datasource-capability-relate-cli.js +5 -4
  57. package/lib/commands/repair-auth-apply.js +1 -1
  58. package/lib/commands/repair-datasource-key-skip.js +39 -0
  59. package/lib/commands/repair-datasource-keys.js +24 -12
  60. package/lib/commands/repair-rbac.js +16 -10
  61. package/lib/commands/role-assistant-copy-output.js +61 -0
  62. package/lib/commands/role-assistant-copy.js +155 -0
  63. package/lib/commands/role-assistant-test-output.js +8 -9
  64. package/lib/commands/role-assistant-test-result-rows.js +42 -0
  65. package/lib/commands/role-assistant.js +117 -48
  66. package/lib/commands/search.js +143 -0
  67. package/lib/commands/test-trust-external.js +7 -5
  68. package/lib/commands/upload-sidecar-followups.js +4 -1
  69. package/lib/commands/verify-operations-skip-e2e.js +131 -0
  70. package/lib/commands/verify-operations-step-plan.js +6 -33
  71. package/lib/commands/verify-operations-steps.js +3 -1
  72. package/lib/datasource/capability/relate-operations.js +28 -10
  73. package/lib/datasource/capability/run-capability-relate.js +48 -25
  74. package/lib/datasource/datasource-identifier.js +13 -5
  75. package/lib/deployment/deployer-poll-run.js +117 -35
  76. package/lib/external-system/deploy-dataplane-published.js +70 -0
  77. package/lib/external-system/deploy.js +12 -2
  78. package/lib/external-system/download-role-assistant.js +41 -15
  79. package/lib/external-system/download.js +7 -1
  80. package/lib/generator/wizard-datasource-key.js +54 -0
  81. package/lib/generator/wizard.js +55 -54
  82. package/lib/integration-definition/apply-datasource-keys.js +75 -0
  83. package/lib/integration-definition/apply-relationships.js +195 -0
  84. package/lib/integration-definition/apply-static-enterprise.js +229 -0
  85. package/lib/integration-definition/apply-system-file.js +71 -0
  86. package/lib/integration-definition/apply-test-endpoint.js +89 -0
  87. package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
  88. package/lib/integration-definition/apply.js +78 -59
  89. package/lib/integration-definition/enrich-openapi-operations.js +36 -10
  90. package/lib/integration-definition/enrich-openapi-pick.js +87 -0
  91. package/lib/lifecycle/role-assistant-governance.js +56 -21
  92. package/lib/programmatic/capability-registry.js +1 -0
  93. package/lib/programmatic/index.js +2 -0
  94. package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
  95. package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
  96. package/lib/programmatic/openapi-component-schemas.js +1 -0
  97. package/lib/programmatic/openapi-descriptions.js +9 -3
  98. package/lib/programmatic/openapi-envelope-examples.js +7 -0
  99. package/lib/programmatic/openapi-operation-bindings.js +5 -0
  100. package/lib/programmatic/openapi-request-schemas.js +5 -0
  101. package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
  102. package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
  103. package/lib/programmatic/openapi-spec.js +1 -0
  104. package/lib/programmatic/request-timeout.js +3 -0
  105. package/lib/programmatic/route-handler-map.js +7 -0
  106. package/lib/programmatic/run-channel-catalog.js +50 -8
  107. package/lib/programmatic/run-channel-install-options.js +5 -1
  108. package/lib/programmatic/run-download.js +41 -0
  109. package/lib/protection/auth-context.js +3 -1
  110. package/lib/protection/protection-display.js +3 -2
  111. package/lib/protection/report-exit.js +50 -0
  112. package/lib/protection/run-commands.js +2 -0
  113. package/lib/role-assistant/package-validate.js +175 -0
  114. package/lib/role-assistant/test-case-assertion-row.js +36 -0
  115. package/lib/role-assistant/test-case-copy-bind.js +77 -0
  116. package/lib/role-assistant/test-case-copy-expected.js +127 -0
  117. package/lib/role-assistant/test-case-copy-from-work.js +90 -0
  118. package/lib/role-assistant/test-case-copy-interactions.js +67 -0
  119. package/lib/role-assistant/test-case-copy.js +119 -0
  120. package/lib/role-assistant/test-case-expected-catalog.js +135 -0
  121. package/lib/role-assistant/test-case-validate.js +88 -0
  122. package/lib/role-assistant/test-cases-bid.js +117 -4
  123. package/lib/role-assistant/test-cases-evaluate.js +137 -30
  124. package/lib/role-assistant/test-cases-honesty.js +155 -6
  125. package/lib/role-assistant/test-cases-lifecycle.js +291 -0
  126. package/lib/role-assistant/test-cases-search-graph.js +122 -0
  127. package/lib/role-assistant/test-cases-search.js +20 -2
  128. package/lib/role-assistant/test-cases.js +34 -168
  129. package/lib/role-assistant/test-pack-map.js +180 -0
  130. package/lib/role-assistant/test-pack-sync.js +187 -0
  131. package/lib/role-assistant/test-runner-debug.js +54 -0
  132. package/lib/role-assistant/test-runner-respond-body.js +36 -0
  133. package/lib/role-assistant/test-runner-search.js +20 -5
  134. package/lib/role-assistant/test-runner-start-payload.js +63 -10
  135. package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
  136. package/lib/role-assistant/test-runner-workhub.js +45 -21
  137. package/lib/role-assistant/test-runner.js +50 -10
  138. package/lib/schema/external-datasource.schema.json +36 -5
  139. package/lib/schema/external-system.schema.json +20 -2
  140. package/lib/schema/role-assistant-test-case.schema.json +408 -0
  141. package/lib/search/dataplane-context.js +23 -0
  142. package/lib/search/search-args.js +211 -0
  143. package/lib/search/search-display.js +238 -0
  144. package/lib/search/search-errors.js +50 -0
  145. package/lib/search/search-prompts.js +119 -0
  146. package/lib/search/search-roles.js +85 -0
  147. package/lib/search/search-run.js +241 -0
  148. package/lib/search/search-skills.js +198 -0
  149. package/lib/utils/authentication-slot-show.js +153 -0
  150. package/lib/utils/credential-display.js +43 -1
  151. package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
  152. package/lib/utils/external-system-readiness-compact-display.js +30 -1
  153. package/lib/utils/external-system-validators.js +2 -1
  154. package/lib/utils/help-builder.js +3 -1
  155. package/lib/utils/schema-loader.js +37 -0
  156. package/lib/validation/validate-external-file.js +5 -1
  157. package/lib/validation/validate.js +3 -2
  158. package/package.json +1 -1
  159. package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
  160. package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
  161. package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
  162. package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
  163. package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
  164. package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
  165. package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
  166. package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
  167. package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
  168. package/templates/agent-kit/agent-kit.yaml +45 -0
  169. package/templates/agent-kit/instructions/AGENTKIT.md +83 -0
  170. package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
  171. package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
  172. package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
  173. package/templates/agent-kit/parity-inventory.yaml +188 -0
  174. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +58 -0
  175. package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
  176. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
  177. package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
  178. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
  179. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +51 -0
  180. package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
  181. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
  182. package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
  183. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +50 -0
  184. package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
  185. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
  186. package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
  187. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +42 -0
  188. package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
  189. package/templates/agent-kit/skills/shared/hosts.md +78 -0
  190. package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
  191. package/templates/agent-kit/workspace/LICENSE.mit +21 -0
  192. package/templates/agent-kit/workspace/README.md +89 -0
  193. package/templates/applications/builder-api/Dockerfile +3 -1
  194. package/templates/applications/dataplane/application.yaml +2 -2
  195. package/templates/applications/dataplane/env.template +1 -1
  196. package/templates/applications/dataplane/rbac.yaml +28 -0
  197. package/templates/applications/keycloak/env.template +3 -3
  198. package/templates/applications/miso-controller/application.yaml +1 -1
  199. package/templates/applications/miso-controller/env.template +8 -9
  200. package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
  201. package/templates/channels/claude/channel.json +1 -1
  202. package/templates/channels/claude/install.template.md.hbs +1 -0
  203. package/templates/channels/claude/integration/claude-system.json +1 -1
  204. package/templates/channels/slack/channel.json +11 -0
  205. package/templates/channels/slack/install.template.md.hbs +9 -0
  206. package/templates/channels/slack/integration/slack-system.json +11 -0
  207. package/templates/channels/slack/manifest.template.json.hbs +6 -3
  208. package/templates/channels/teams-bot/channel.json +1 -0
  209. package/templates/python/docker-compose.hbs +14 -0
  210. 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
+ };