@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,241 @@
1
+ /**
2
+ * Orchestrate aifabrix search and aifabrix search skills.
3
+ *
4
+ * @fileoverview Search command run path (retrieve only)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('../internal/fs-real-sync');
12
+ const logger = require('../utils/logger');
13
+ const { getWorkRoles, getWorkSkills, searchWork } = require('../api/work-search.api');
14
+ const { resolveSearchDataplaneContext } = require('./dataplane-context');
15
+ const { SearchCliError, authRequiredError } = require('./search-errors');
16
+ const { buildSearchBody, roleRefFromOptions, resourceTypeFromOptions } = require('./search-args');
17
+ const {
18
+ skillsEnvelope,
19
+ resourceTypesMap,
20
+ typeSpec,
21
+ isOperationRequired,
22
+ assertTypePublished,
23
+ assertOperationPublished
24
+ } = require('./search-skills');
25
+ const {
26
+ isInteractive,
27
+ missingFlagsError,
28
+ promptRoleAssistant,
29
+ promptResourceType,
30
+ promptOperation
31
+ } = require('./search-prompts');
32
+ const { emitSearchSuccess, emitSkillsSuccess } = require('./search-display');
33
+
34
+ /**
35
+ * @param {Object} [overrides]
36
+ * @returns {Object}
37
+ */
38
+ function defaultDeps(overrides = {}) {
39
+ return {
40
+ resolveContext: resolveSearchDataplaneContext,
41
+ getWorkRoles,
42
+ getWorkSkills,
43
+ searchWork,
44
+ prompt: (qs) => require('inquirer').prompt(qs),
45
+ logger,
46
+ isTty: () => Boolean(process.stdin && process.stdin.isTTY),
47
+ fsApi: fs,
48
+ ...overrides
49
+ };
50
+ }
51
+
52
+ /**
53
+ * @param {Object} options
54
+ * @param {Function} resolveContext
55
+ * @returns {Promise<Object>}
56
+ */
57
+ async function resolveContextOrThrow(options, resolveContext) {
58
+ try {
59
+ return await resolveContext(options);
60
+ } catch (err) {
61
+ const message = err.message || String(err);
62
+ if (/login|auth|token|controller url/i.test(message)) {
63
+ throw authRequiredError(message);
64
+ }
65
+ throw new SearchCliError(message);
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param {Object} options
71
+ */
72
+ function assertScriptSearchFlags(options) {
73
+ const missing = [];
74
+ if (!roleRefFromOptions(options)) missing.push('--role');
75
+ if (!resourceTypeFromOptions(options)) missing.push('--resource-type');
76
+ if (missing.length) {
77
+ throw missingFlagsError(missing);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @param {Object} res
83
+ * @param {string} fallback
84
+ * @returns {Object}
85
+ */
86
+ function payloadOrThrow(res, fallback) {
87
+ if (res && Number(res.status) === 200) {
88
+ const payload = skillsEnvelope(res.payload);
89
+ return payload && typeof payload === 'object' ? payload : {};
90
+ }
91
+ const text = String((res && res.errorText) || '').trim() || fallback;
92
+ throw new SearchCliError(text);
93
+ }
94
+
95
+ /**
96
+ * @param {Object} options
97
+ * @param {Object} ctx
98
+ * @param {Object} deps
99
+ * @returns {Promise<string>}
100
+ */
101
+ async function resolveRoleRef(options, ctx, deps) {
102
+ const existing = roleRefFromOptions(options);
103
+ if (existing) {
104
+ return existing;
105
+ }
106
+ return promptRoleAssistant(ctx, deps);
107
+ }
108
+
109
+ /**
110
+ * @param {string} explicitType
111
+ * @param {string[]} typeKeys
112
+ * @param {Object} typeMap
113
+ * @param {boolean} interactive
114
+ * @param {Object} deps
115
+ * @returns {Promise<string>}
116
+ */
117
+ async function resolveResourceType(explicitType, typeKeys, typeMap, interactive, deps) {
118
+ if (!typeKeys.length) {
119
+ throw new SearchCliError('No searchable resource types for this Role Assistant.');
120
+ }
121
+ if (explicitType) {
122
+ assertTypePublished(explicitType, typeMap);
123
+ return explicitType;
124
+ }
125
+ if (!interactive) {
126
+ throw missingFlagsError(['--resource-type']);
127
+ }
128
+ return promptResourceType(typeKeys, deps);
129
+ }
130
+
131
+ /**
132
+ * @param {string} explicitOp
133
+ * @param {Object} spec
134
+ * @param {boolean} interactive
135
+ * @param {Object} deps
136
+ * @returns {Promise<string>}
137
+ */
138
+ async function resolveOperation(explicitOp, spec, interactive, deps) {
139
+ if (explicitOp) {
140
+ assertOperationPublished(explicitOp, spec);
141
+ return explicitOp;
142
+ }
143
+ if (isOperationRequired(spec) && !interactive) {
144
+ throw new SearchCliError(
145
+ 'Operation is required for this resource type. Pass --operation.'
146
+ );
147
+ }
148
+ if (!interactive) {
149
+ return '';
150
+ }
151
+ return promptOperation(spec, deps);
152
+ }
153
+
154
+ /**
155
+ * @param {Object} body
156
+ * @param {Object} skillsPayload
157
+ * @param {Object} options
158
+ * @param {Object} deps
159
+ * @returns {Promise<Object>}
160
+ */
161
+ async function fillTypeAndOperation(body, skillsPayload, options, deps) {
162
+ const typeMap = resourceTypesMap(skillsPayload);
163
+ const typeKeys = Object.keys(typeMap);
164
+ const interactive = isInteractive(options, deps.isTty);
165
+ const resourceType = await resolveResourceType(
166
+ body.resourceType || '',
167
+ typeKeys,
168
+ typeMap,
169
+ interactive,
170
+ deps
171
+ );
172
+ body.resourceType = resourceType;
173
+ const spec = typeSpec(typeMap, resourceType);
174
+ const operation = await resolveOperation(body.operation || '', spec, interactive, deps);
175
+ if (operation) {
176
+ body.operation = operation;
177
+ } else {
178
+ delete body.operation;
179
+ }
180
+ if (isOperationRequired(spec) && !body.operation) {
181
+ throw new SearchCliError(
182
+ 'Operation is required for this resource type. Pass --operation.'
183
+ );
184
+ }
185
+ return body;
186
+ }
187
+
188
+ /**
189
+ * @param {Object} options
190
+ * @param {Object} [depOverrides]
191
+ * @returns {Promise<number>}
192
+ */
193
+ async function runSearch(options, depOverrides) {
194
+ const deps = defaultDeps(depOverrides);
195
+ const body = buildSearchBody(options, deps.fsApi);
196
+ const interactive = isInteractive(options, deps.isTty);
197
+ if (!interactive) {
198
+ assertScriptSearchFlags(options);
199
+ }
200
+ const ctx = await resolveContextOrThrow(options, deps.resolveContext);
201
+ if (!body.roleRef) {
202
+ body.roleRef = await resolveRoleRef(options, ctx, deps);
203
+ }
204
+ const skillsRes = await deps.getWorkSkills(ctx.dataplaneUrl, ctx.authConfig, body.roleRef);
205
+ const skillsPayload = payloadOrThrow(skillsRes, 'Unable to load search skills.');
206
+ await fillTypeAndOperation(body, skillsPayload, options, deps);
207
+ const searchRes = await deps.searchWork(ctx.dataplaneUrl, ctx.authConfig, body);
208
+ const payload = payloadOrThrow(searchRes, 'Search request failed.');
209
+ emitSearchSuccess(options, body, payload, deps.logger, deps.fsApi);
210
+ return 0;
211
+ }
212
+
213
+ /**
214
+ * @param {Object} options
215
+ * @param {Object} [depOverrides]
216
+ * @returns {Promise<number>}
217
+ */
218
+ async function runSearchSkills(options, depOverrides) {
219
+ const deps = defaultDeps(depOverrides);
220
+ const interactive = isInteractive(options, deps.isTty);
221
+ if (!interactive && !roleRefFromOptions(options)) {
222
+ throw missingFlagsError(['--role']);
223
+ }
224
+ const ctx = await resolveContextOrThrow(options, deps.resolveContext);
225
+ const roleRef = await resolveRoleRef(options, ctx, deps);
226
+ const skillsRes = await deps.getWorkSkills(ctx.dataplaneUrl, ctx.authConfig, roleRef);
227
+ const payload = payloadOrThrow(skillsRes, 'Unable to load search skills.');
228
+ if (!payload.roleRef) {
229
+ payload.roleRef = roleRef;
230
+ }
231
+ emitSkillsSuccess(options, payload, deps.logger, deps.fsApi);
232
+ return 0;
233
+ }
234
+
235
+ module.exports = {
236
+ defaultDeps,
237
+ runSearch,
238
+ runSearchSkills,
239
+ fillTypeAndOperation,
240
+ resolveRoleRef
241
+ };
@@ -0,0 +1,198 @@
1
+ /**
2
+ * YAML-free copies of work.skills helpers (do not import the test runner).
3
+ *
4
+ * @fileoverview Resource type / operation keys from a skills payload
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { SearchCliError } = require('./search-errors');
12
+
13
+ /** Table retrieve keys stamped by the search grammar (list/search page, get one). */
14
+ const RETRIEVE_TABLE_KEYS = new Set(['list', 'get', 'search']);
15
+
16
+ /**
17
+ * @param {*} item
18
+ * @returns {string}
19
+ */
20
+ function operationKeyFromItem(item) {
21
+ if (typeof item === 'string' && item.trim()) {
22
+ return item.trim();
23
+ }
24
+ if (item && typeof item === 'object') {
25
+ return String(item.key || '').trim();
26
+ }
27
+ return '';
28
+ }
29
+
30
+ /**
31
+ * @param {*} item
32
+ * @returns {boolean}
33
+ */
34
+ function hasResultMode(item) {
35
+ return Boolean(item && typeof item === 'object' && String(item.resultMode || '').trim());
36
+ }
37
+
38
+ /**
39
+ * Retrieve/analyze only. Write-shaped keys stay off search.
40
+ * Keep table retrieve keys (list/get/search) and named views (source viewpoint).
41
+ *
42
+ * @param {*} item
43
+ * @param {boolean} grammarPresent
44
+ * @param {boolean} tableRetrievePresent
45
+ * @returns {boolean}
46
+ */
47
+ function isRetrieveOperation(item, grammarPresent, tableRetrievePresent) {
48
+ const key = operationKeyFromItem(item);
49
+ if (!key) {
50
+ return false;
51
+ }
52
+ if (RETRIEVE_TABLE_KEYS.has(key)) {
53
+ return true;
54
+ }
55
+ if (typeof item === 'string') {
56
+ return !tableRetrievePresent;
57
+ }
58
+ const source = String((item && item.source) || '')
59
+ .trim()
60
+ .toLowerCase();
61
+ if (source === 'viewpoint') {
62
+ return true;
63
+ }
64
+ if (!source && !grammarPresent && !tableRetrievePresent) {
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+
70
+ /**
71
+ * @param {Object|null|undefined} spec
72
+ * @returns {*[]}
73
+ */
74
+ function operationItems(spec) {
75
+ return Array.isArray(spec && spec.operations) ? spec.operations : [];
76
+ }
77
+
78
+ /**
79
+ * @param {Object|null|undefined} spec
80
+ * @returns {string[]}
81
+ */
82
+ function operationKeys(spec) {
83
+ const raw = operationItems(spec);
84
+ const grammarPresent = raw.some(hasResultMode);
85
+ const tableRetrievePresent = raw.some((item) =>
86
+ RETRIEVE_TABLE_KEYS.has(operationKeyFromItem(item))
87
+ );
88
+ const keys = [];
89
+ for (const item of raw) {
90
+ if (!isRetrieveOperation(item, grammarPresent, tableRetrievePresent)) {
91
+ continue;
92
+ }
93
+ const key = operationKeyFromItem(item);
94
+ if (key) {
95
+ keys.push(key);
96
+ }
97
+ }
98
+ return keys;
99
+ }
100
+
101
+ /**
102
+ * @param {Object|null|undefined} spec
103
+ * @returns {string[]}
104
+ */
105
+ function allOperationKeys(spec) {
106
+ return operationItems(spec).map(operationKeyFromItem).filter(Boolean);
107
+ }
108
+
109
+ /**
110
+ * work.skills is an object. MCP execute may wrap it as a one-element array.
111
+ * @param {*} skillsPayload
112
+ * @returns {Object|null}
113
+ */
114
+ function skillsEnvelope(skillsPayload) {
115
+ let cur = skillsPayload;
116
+ if (Array.isArray(cur) && cur.length === 1 && cur[0] && typeof cur[0] === 'object') {
117
+ cur = cur[0];
118
+ }
119
+ if (!cur || typeof cur !== 'object' || Array.isArray(cur)) {
120
+ return null;
121
+ }
122
+ if (cur.search && typeof cur.search === 'object') {
123
+ return cur;
124
+ }
125
+ if (cur.data && typeof cur.data === 'object' && !Array.isArray(cur.data) && cur.data.search) {
126
+ return cur.data;
127
+ }
128
+ return cur;
129
+ }
130
+
131
+ /**
132
+ * @param {Object|null|undefined} skillsPayload
133
+ * @returns {Object}
134
+ */
135
+ function resourceTypesMap(skillsPayload) {
136
+ const root = skillsEnvelope(skillsPayload);
137
+ const rts = root && root.search && root.search.resourceTypes;
138
+ return rts && typeof rts === 'object' && !Array.isArray(rts) ? rts : {};
139
+ }
140
+
141
+ /**
142
+ * @param {Object} typeMap
143
+ * @param {string} resourceType
144
+ * @returns {Object}
145
+ */
146
+ function typeSpec(typeMap, resourceType) {
147
+ const spec = typeMap && typeMap[resourceType];
148
+ return spec && typeof spec === 'object' ? spec : {};
149
+ }
150
+
151
+ /**
152
+ * @param {Object} spec
153
+ * @returns {boolean}
154
+ */
155
+ function isOperationRequired(spec) {
156
+ return spec && spec.operationRequired === true;
157
+ }
158
+
159
+ /**
160
+ * @param {string} resourceType
161
+ * @param {Object} typeMap
162
+ */
163
+ function assertTypePublished(resourceType, typeMap) {
164
+ if (!Object.prototype.hasOwnProperty.call(typeMap, resourceType)) {
165
+ throw new SearchCliError(
166
+ `Resource type "${resourceType}" is not published for this Role Assistant.`
167
+ );
168
+ }
169
+ }
170
+
171
+ /**
172
+ * @param {string} operation
173
+ * @param {Object} spec
174
+ */
175
+ function assertOperationPublished(operation, spec) {
176
+ const keys = operationKeys(spec);
177
+ if (keys.includes(operation)) {
178
+ return;
179
+ }
180
+ if (allOperationKeys(spec).includes(operation)) {
181
+ throw new SearchCliError(
182
+ `Operation "${operation}" is not a retrieve operation for this resource type.`
183
+ );
184
+ }
185
+ throw new SearchCliError(
186
+ `Operation "${operation}" is not published for this resource type.`
187
+ );
188
+ }
189
+
190
+ module.exports = {
191
+ operationKeys,
192
+ skillsEnvelope,
193
+ resourceTypesMap,
194
+ typeSpec,
195
+ isOperationRequired,
196
+ assertTypePublished,
197
+ assertOperationPublished
198
+ };
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Connected System credential line for `aifabrix show` (usage slots + online/offline).
3
+ *
4
+ * @fileoverview TTY formatter for authentications[] / legacy authentication
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const chalk = require('chalk');
12
+ const { getAuthMethodFromAuthentication } = require('./authentication-shape');
13
+
14
+ /** Same labels as the dataplane Connected System authentication tab. */
15
+ const AUTHENTICATION_USAGE_LABELS = Object.freeze({
16
+ api: 'API calls',
17
+ webhookInbound: 'Webhook inbound',
18
+ syncExecution: 'Sync execution',
19
+ messageInbound: 'Message inbound',
20
+ messageOutbound: 'Message outbound',
21
+ callback: 'Callback',
22
+ provisioning: 'Provisioning'
23
+ });
24
+
25
+ /**
26
+ * @param {string} method
27
+ * @param {string} glyph
28
+ * @returns {string}
29
+ */
30
+ function chalkGlyph(method, glyph) {
31
+ const fn = chalk[method];
32
+ return typeof fn === 'function' ? fn(glyph) : glyph;
33
+ }
34
+
35
+ /**
36
+ * @param {string|null|undefined} status
37
+ * @returns {string}
38
+ */
39
+ function formatOnlineOfflineIcon(status) {
40
+ const raw = String(status || 'offline').trim().toLowerCase();
41
+ if (raw === 'online') return chalkGlyph('green', '✔');
42
+ if (raw === 'partially') return chalkGlyph('yellow', '⚠');
43
+ return chalkGlyph('red', '✖');
44
+ }
45
+
46
+ /**
47
+ * @param {unknown} value
48
+ * @returns {Object|null}
49
+ */
50
+ function asObject(value) {
51
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
52
+ }
53
+
54
+ /**
55
+ * @param {Object} slot
56
+ * @returns {string}
57
+ */
58
+ function formatSlotType(slot) {
59
+ const authType = String(slot.authType || '').trim().toLowerCase();
60
+ if (authType === 'system' || authType === 'none') return authType;
61
+ if (authType === 'apiprovider') return 'apiProvider';
62
+ const method = getAuthMethodFromAuthentication(slot);
63
+ if (method) return method;
64
+ const nested = asObject(slot.credential);
65
+ const nestedMethod = nested && typeof nested.method === 'string' ? nested.method.trim() : '';
66
+ return nestedMethod || authType || '—';
67
+ }
68
+
69
+ /**
70
+ * @param {Object} slot
71
+ * @param {string|null|undefined} systemStatus
72
+ * @returns {string}
73
+ */
74
+ function slotStatus(slot, systemStatus) {
75
+ const authType = String(slot.authType || '').trim().toLowerCase();
76
+ if (authType === 'system' || authType === 'none') return 'online';
77
+ return systemStatus || 'offline';
78
+ }
79
+
80
+ /**
81
+ * @param {Object} slot
82
+ * @param {string|null|undefined} systemStatus
83
+ * @param {boolean} includeUsage
84
+ * @returns {string}
85
+ */
86
+ function formatOneSlot(slot, systemStatus, includeUsage) {
87
+ const type = formatSlotType(slot);
88
+ const icon = formatOnlineOfflineIcon(slotStatus(slot, systemStatus));
89
+ if (!includeUsage) return `${type} ${icon}`;
90
+ const usage = String(slot.usage || 'api').trim() || 'api';
91
+ const label = AUTHENTICATION_USAGE_LABELS[usage] || usage;
92
+ return `${label}: ${type} ${icon}`;
93
+ }
94
+
95
+ /**
96
+ * @param {unknown} entry
97
+ * @returns {Object|null}
98
+ */
99
+ function normalizeSlot(entry) {
100
+ const obj = asObject(entry);
101
+ if (!obj) return null;
102
+ const key = typeof obj.key === 'string' && obj.key.trim() ? obj.key.trim() : 'default';
103
+ const usage = typeof obj.usage === 'string' && obj.usage.trim() ? obj.usage.trim() : 'api';
104
+ return { ...obj, key, usage };
105
+ }
106
+
107
+ /**
108
+ * @param {Object|null|undefined} config
109
+ * @param {Object|null|undefined} system
110
+ * @returns {Object[]}
111
+ */
112
+ function resolveAuthenticationSlots(config, system) {
113
+ const cfg = asObject(config) || {};
114
+ const sys = asObject(system) || {};
115
+ const fromCfg = Array.isArray(cfg.authentications) && cfg.authentications.length > 0
116
+ ? cfg.authentications
117
+ : null;
118
+ const fromSys = Array.isArray(sys.authentications) && sys.authentications.length > 0
119
+ ? sys.authentications
120
+ : null;
121
+ const rawSlots = fromCfg || fromSys;
122
+ if (rawSlots) return rawSlots.map(normalizeSlot).filter(Boolean);
123
+ const legacy = asObject(cfg.authentication) || asObject(sys.authentication);
124
+ if (!legacy) return [];
125
+ return [normalizeSlot({ ...legacy, key: 'default', usage: 'api' })];
126
+ }
127
+
128
+ /**
129
+ * One slot: `oauth2 ✔`. Several: `API calls: oauth2 ✔, Webhook inbound: hmac ✔`.
130
+ * @param {Object} ext
131
+ * @returns {string}
132
+ */
133
+ function formatCredentialShowLine(ext) {
134
+ if (!ext || typeof ext !== 'object') return '—';
135
+ const slots = Array.isArray(ext.authenticationSlots) ? ext.authenticationSlots : [];
136
+ const status = ext.authenticationStatus;
137
+ if (slots.length === 1) return formatOneSlot(slots[0], status, false);
138
+ if (slots.length > 1) {
139
+ return slots.map((slot) => formatOneSlot(slot, status, true)).join(', ');
140
+ }
141
+ const method = typeof ext.credentialMethod === 'string' ? ext.credentialMethod.trim() : '';
142
+ if (method && method.toLowerCase() !== 'unknown') {
143
+ return `${method} ${formatOnlineOfflineIcon(status)}`;
144
+ }
145
+ return '—';
146
+ }
147
+
148
+ module.exports = {
149
+ AUTHENTICATION_USAGE_LABELS,
150
+ resolveAuthenticationSlots,
151
+ formatCredentialShowLine,
152
+ formatOnlineOfflineIcon
153
+ };
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  const chalk = require('chalk');
11
+ const { formatCredentialShowLine } = require('./authentication-slot-show');
11
12
 
12
13
  /** @type {{ verified: string, pending: string, failed: string, expired: string }} */
13
14
  const STATUS_ICONS = {
@@ -74,10 +75,51 @@ function formatCredentialWithStatus(credential) {
74
75
  return { key, name, statusFormatted, statusLabel };
75
76
  }
76
77
 
78
+ /**
79
+ * @param {unknown[]} values
80
+ * @returns {string|null}
81
+ */
82
+ function firstNonEmptyScalar(values) {
83
+ for (const value of values) {
84
+ if (typeof value === 'number') return String(value);
85
+ if (typeof value === 'string' && value.trim()) return value.trim();
86
+ }
87
+ return null;
88
+ }
89
+
90
+ /**
91
+ * Identity from a dataplane credential id or ForeignKeyReference. Never `[object Object]`.
92
+ * @param {unknown} value
93
+ * @returns {string|null}
94
+ */
95
+ function formatCredentialIdentity(value) {
96
+ if (value === null || value === undefined || value === '') return null;
97
+ if (typeof value !== 'object') return String(value);
98
+ return firstNonEmptyScalar([
99
+ value.name,
100
+ value.displayName,
101
+ value.key,
102
+ value.id,
103
+ value.credentialKey,
104
+ value.credentialId
105
+ ]);
106
+ }
107
+
108
+ /**
109
+ * Scalar credential id/key for show output. Objects must not print as [object Object].
110
+ * @param {unknown} value
111
+ * @returns {string}
112
+ */
113
+ function formatCredentialIdValue(value) {
114
+ return formatCredentialIdentity(value) || '—';
115
+ }
116
+
77
117
  module.exports = {
78
118
  STATUS_ICONS,
79
119
  STATUS_LABELS,
80
120
  STATUS_CHALK,
81
121
  formatCredentialStatus,
82
- formatCredentialWithStatus
122
+ formatCredentialWithStatus,
123
+ formatCredentialIdValue,
124
+ formatCredentialShowLine
83
125
  };
@@ -75,7 +75,11 @@ function logUploadReadinessSummaryCompact(ctx) {
75
75
  const genMcp = publication?.generateMcpContract !== false;
76
76
  const tierA = summarizeDatasourceTiersA(publication?.datasources || [], genMcp);
77
77
  const systemCfg = manifest?.system || {};
78
- const statusLabel = resolveConnectedSystemStatus({ publication });
78
+ const statusLabel = resolveConnectedSystemStatus({
79
+ command: 'upload',
80
+ publication,
81
+ systemFromDataplane: ctx.systemFromDataplane
82
+ });
79
83
 
80
84
  logCompactHeader({ command: 'upload', systemKey, environment, dataplaneUrl });
81
85
  if (forcePublish) {