@aifabrix/builder 2.54.1 → 2.55.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) 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 +172 -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 +272 -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/start.js +310 -0
  23. package/lib/agent-kit/state-file.js +83 -0
  24. package/lib/agent-kit/status.js +50 -0
  25. package/lib/agent-kit/v1-detect.js +81 -0
  26. package/lib/agent-kit/validate-kit.js +87 -0
  27. package/lib/agent-kit/workspace-name.js +40 -0
  28. package/lib/agent-kit/workspace-skeleton.js +103 -0
  29. package/lib/api/role-assistant-test-pack.api.js +86 -0
  30. package/lib/api/work-search.api.js +31 -4
  31. package/lib/api/work.api.js +19 -12
  32. package/lib/app/deploy.js +7 -4
  33. package/lib/app/list-external-systems.js +2 -1
  34. package/lib/app/offer-create-from-template.js +184 -0
  35. package/lib/app/show-display.js +33 -6
  36. package/lib/app/show.js +25 -2
  37. package/lib/channels/add-channel.js +1 -0
  38. package/lib/channels/approval-guides/claude.js +2 -2
  39. package/lib/channels/channel-add-failure.js +1 -0
  40. package/lib/channels/channel-add-remaining.js +15 -9
  41. package/lib/channels/channel-definition-status.js +115 -0
  42. package/lib/channels/channel-description.js +2 -1
  43. package/lib/channels/channel-install-envelope.js +4 -2
  44. package/lib/channels/channel-integration-generator.js +2 -0
  45. package/lib/channels/channel-runtime-resolver.js +14 -0
  46. package/lib/channels/channel-targets.js +31 -5
  47. package/lib/channels/claude-setup-values.js +4 -1
  48. package/lib/channels/slack-channel-add.js +59 -6
  49. package/lib/channels/slack-mcp-callback.js +51 -0
  50. package/lib/channels/slack-mcp-runtime.js +156 -0
  51. package/lib/channels/slack-provisioning/install-cli.js +14 -2
  52. package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
  53. package/lib/cli/index.js +4 -0
  54. package/lib/cli/setup-app.js +8 -1
  55. package/lib/cli/setup-auth.js +11 -2
  56. package/lib/cli/setup-certification-commands.js +2 -2
  57. package/lib/cli/setup-certification.help.js +3 -1
  58. package/lib/commands/agent-kit-help.js +149 -0
  59. package/lib/commands/agent-kit.js +417 -0
  60. package/lib/commands/auth-status-user.js +99 -0
  61. package/lib/commands/auth-status.js +14 -4
  62. package/lib/commands/channel-add-help.js +5 -5
  63. package/lib/commands/datasource-capability-relate-cli.js +5 -4
  64. package/lib/commands/datasource-load-export-cli.js +7 -2
  65. package/lib/commands/datasource-test-trust-cli.js +5 -1
  66. package/lib/commands/governance-command-action.js +5 -4
  67. package/lib/commands/identity-membership-role-cache.js +6 -1
  68. package/lib/commands/lifecycle-command-action.js +16 -15
  69. package/lib/commands/login-credentials.js +8 -3
  70. package/lib/commands/login-device.js +14 -5
  71. package/lib/commands/login.js +14 -1
  72. package/lib/commands/logout.js +50 -15
  73. package/lib/commands/repair-auth-apply.js +1 -1
  74. package/lib/commands/repair-datasource-key-skip.js +39 -0
  75. package/lib/commands/repair-datasource-keys.js +24 -12
  76. package/lib/commands/repair-rbac.js +16 -10
  77. package/lib/commands/role-assistant-copy-output.js +61 -0
  78. package/lib/commands/role-assistant-copy.js +155 -0
  79. package/lib/commands/role-assistant-test-output.js +8 -9
  80. package/lib/commands/role-assistant-test-result-rows.js +42 -0
  81. package/lib/commands/role-assistant.js +140 -59
  82. package/lib/commands/search.js +143 -0
  83. package/lib/commands/test-trust-external.js +7 -5
  84. package/lib/commands/upload-sidecar-followups.js +4 -1
  85. package/lib/commands/verify-governance-command-action.js +9 -7
  86. package/lib/commands/verify-operations-command-action.js +9 -8
  87. package/lib/commands/verify-operations-skip-e2e.js +131 -0
  88. package/lib/commands/verify-operations-step-plan.js +6 -33
  89. package/lib/commands/verify-operations-steps.js +3 -1
  90. package/lib/commands/verify-trust-command-action.js +6 -5
  91. package/lib/datasource/capability/relate-operations.js +28 -10
  92. package/lib/datasource/capability/run-capability-relate.js +48 -25
  93. package/lib/datasource/datasource-identifier.js +13 -5
  94. package/lib/deployment/deployer-poll-run.js +117 -35
  95. package/lib/external-system/deploy-dataplane-published.js +70 -0
  96. package/lib/external-system/deploy.js +12 -2
  97. package/lib/external-system/download-role-assistant.js +41 -15
  98. package/lib/external-system/download.js +8 -3
  99. package/lib/generator/helpers.js +12 -1
  100. package/lib/generator/wizard-datasource-key.js +54 -0
  101. package/lib/generator/wizard.js +55 -54
  102. package/lib/integration-definition/apply-datasource-keys.js +75 -0
  103. package/lib/integration-definition/apply-relationships.js +195 -0
  104. package/lib/integration-definition/apply-static-enterprise.js +232 -0
  105. package/lib/integration-definition/apply-system-file.js +71 -0
  106. package/lib/integration-definition/apply-test-endpoint.js +89 -0
  107. package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
  108. package/lib/integration-definition/apply.js +78 -59
  109. package/lib/integration-definition/enrich-openapi-operations.js +36 -10
  110. package/lib/integration-definition/enrich-openapi-pick.js +87 -0
  111. package/lib/lifecycle/role-assistant-governance.js +56 -21
  112. package/lib/programmatic/capability-registry.js +1 -0
  113. package/lib/programmatic/index.js +2 -0
  114. package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
  115. package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
  116. package/lib/programmatic/openapi-component-schemas.js +1 -0
  117. package/lib/programmatic/openapi-descriptions.js +9 -3
  118. package/lib/programmatic/openapi-envelope-examples.js +7 -0
  119. package/lib/programmatic/openapi-operation-bindings.js +5 -0
  120. package/lib/programmatic/openapi-request-schemas.js +5 -0
  121. package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
  122. package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
  123. package/lib/programmatic/openapi-spec.js +1 -0
  124. package/lib/programmatic/request-timeout.js +3 -0
  125. package/lib/programmatic/route-handler-map.js +7 -0
  126. package/lib/programmatic/run-channel-catalog.js +50 -8
  127. package/lib/programmatic/run-channel-install-options.js +5 -1
  128. package/lib/programmatic/run-download.js +41 -0
  129. package/lib/protection/auth-context.js +3 -1
  130. package/lib/protection/protection-display.js +3 -2
  131. package/lib/protection/report-exit.js +50 -0
  132. package/lib/protection/run-commands.js +2 -0
  133. package/lib/role-assistant/knowledge-sync-settings-push.js +172 -0
  134. package/lib/role-assistant/knowledge-sync.js +9 -126
  135. package/lib/role-assistant/package-validate.js +175 -0
  136. package/lib/role-assistant/test-case-assertion-row.js +36 -0
  137. package/lib/role-assistant/test-case-copy-bind.js +77 -0
  138. package/lib/role-assistant/test-case-copy-expected.js +127 -0
  139. package/lib/role-assistant/test-case-copy-from-work.js +90 -0
  140. package/lib/role-assistant/test-case-copy-interactions.js +67 -0
  141. package/lib/role-assistant/test-case-copy.js +119 -0
  142. package/lib/role-assistant/test-case-expected-catalog.js +135 -0
  143. package/lib/role-assistant/test-case-validate.js +88 -0
  144. package/lib/role-assistant/test-cases-bid.js +117 -4
  145. package/lib/role-assistant/test-cases-evaluate.js +149 -31
  146. package/lib/role-assistant/test-cases-evidence.js +44 -5
  147. package/lib/role-assistant/test-cases-honesty.js +155 -6
  148. package/lib/role-assistant/test-cases-lifecycle.js +297 -0
  149. package/lib/role-assistant/test-cases-search-graph.js +122 -0
  150. package/lib/role-assistant/test-cases-search.js +20 -2
  151. package/lib/role-assistant/test-cases.js +34 -168
  152. package/lib/role-assistant/test-pack-map.js +180 -0
  153. package/lib/role-assistant/test-pack-sync.js +187 -0
  154. package/lib/role-assistant/test-runner-debug.js +54 -0
  155. package/lib/role-assistant/test-runner-respond-body.js +36 -0
  156. package/lib/role-assistant/test-runner-search.js +20 -5
  157. package/lib/role-assistant/test-runner-start-payload.js +63 -10
  158. package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
  159. package/lib/role-assistant/test-runner-workhub.js +45 -21
  160. package/lib/role-assistant/test-runner.js +53 -10
  161. package/lib/schema/external-datasource.schema.json +36 -5
  162. package/lib/schema/external-system.schema.json +20 -2
  163. package/lib/schema/infra-parameter.schema.json +51 -3
  164. package/lib/schema/infra.parameter.yaml +476 -40
  165. package/lib/schema/role-assistant-test-case.schema.json +408 -0
  166. package/lib/schema/type/document-storage.json +1 -1
  167. package/lib/search/dataplane-context.js +23 -0
  168. package/lib/search/search-args.js +211 -0
  169. package/lib/search/search-display.js +238 -0
  170. package/lib/search/search-errors.js +50 -0
  171. package/lib/search/search-prompts.js +119 -0
  172. package/lib/search/search-roles.js +85 -0
  173. package/lib/search/search-run.js +241 -0
  174. package/lib/search/search-skills.js +198 -0
  175. package/lib/utils/api-required-permissions.js +271 -0
  176. package/lib/utils/api.js +16 -13
  177. package/lib/utils/authentication-slot-show.js +153 -0
  178. package/lib/utils/cli-json-exit.js +41 -0
  179. package/lib/utils/cli-utils.js +23 -5
  180. package/lib/utils/controller-url.js +78 -4
  181. package/lib/utils/credential-display.js +43 -1
  182. package/lib/utils/deployment-errors.js +15 -0
  183. package/lib/utils/deployment-validation-helpers.js +4 -1
  184. package/lib/utils/device-code.js +31 -10
  185. package/lib/utils/error-formatters/error-parser.js +16 -1
  186. package/lib/utils/error-formatters/permission-errors.js +19 -5
  187. package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
  188. package/lib/utils/external-system-readiness-compact-display.js +30 -1
  189. package/lib/utils/external-system-validators.js +2 -1
  190. package/lib/utils/help-builder.js +3 -1
  191. package/lib/utils/keycloak-realm-ready.js +5 -2
  192. package/lib/utils/logger.js +1 -0
  193. package/lib/utils/paths.js +26 -5
  194. package/lib/utils/schema-loader.js +37 -0
  195. package/lib/utils/secrets-helpers.js +2 -2
  196. package/lib/utils/write-stream-and-wait.js +63 -0
  197. package/lib/validation/validate-external-file.js +5 -1
  198. package/lib/validation/validate.js +3 -2
  199. package/package.json +20 -6
  200. package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
  201. package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
  202. package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
  203. package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
  204. package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
  205. package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
  206. package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
  207. package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
  208. package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
  209. package/templates/agent-kit/agent-kit.yaml +45 -0
  210. package/templates/agent-kit/instructions/AGENTKIT.md +104 -0
  211. package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
  212. package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
  213. package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
  214. package/templates/agent-kit/parity-inventory.yaml +188 -0
  215. package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +59 -0
  216. package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
  217. package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
  218. package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
  219. package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
  220. package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +52 -0
  221. package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
  222. package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
  223. package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
  224. package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +51 -0
  225. package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
  226. package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
  227. package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
  228. package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +43 -0
  229. package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
  230. package/templates/agent-kit/skills/shared/hosts.md +65 -0
  231. package/templates/agent-kit/skills/shared/login.md +16 -0
  232. package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
  233. package/templates/agent-kit/workspace/LICENSE.mit +21 -0
  234. package/templates/agent-kit/workspace/README.md +89 -0
  235. package/templates/applications/builder-api/Dockerfile +3 -1
  236. package/templates/applications/dataplane/application.yaml +2 -3
  237. package/templates/applications/dataplane/env.template +5 -5
  238. package/templates/applications/dataplane/rbac.yaml +28 -0
  239. package/templates/applications/keycloak/env.template +3 -3
  240. package/templates/applications/miso-controller/application.yaml +21 -2
  241. package/templates/applications/miso-controller/env.template +96 -25
  242. package/templates/applications/miso-controller/rbac.yaml +5 -0
  243. package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
  244. package/templates/channels/claude/channel.json +1 -1
  245. package/templates/channels/claude/install.template.md.hbs +1 -0
  246. package/templates/channels/claude/integration/claude-system.json +1 -1
  247. package/templates/channels/slack/channel.json +11 -0
  248. package/templates/channels/slack/install.template.md.hbs +9 -0
  249. package/templates/channels/slack/integration/slack-system.json +11 -0
  250. package/templates/channels/slack/manifest.template.json.hbs +6 -3
  251. package/templates/channels/teams-bot/channel.json +1 -0
  252. package/templates/python/docker-compose.hbs +14 -0
  253. package/templates/typescript/docker-compose.hbs +14 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Push role-assistant.yaml knowledge/debug/runtime settings to Assistants.
3
+ *
4
+ * @fileoverview Map local Role Assistant settings onto dataplane Assistants PATCH
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { updateAssistantSettings } = require('../api/assistants.api');
12
+ const {
13
+ readRoleAssistantSettings,
14
+ resolveDocumentStorageKeyFromRoleAssistantSettings,
15
+ resolveRoleAssistantEnvironmentSettings
16
+ } = require('./settings');
17
+
18
+ function resolveRoleAssistantSettingsEnvKey(environment) {
19
+ const token = String(environment || '').trim().toLowerCase();
20
+ return token === 'dev' || token === 'tst' || token === 'pro' ? token : 'dev';
21
+ }
22
+
23
+ /**
24
+ * Map role-assistant.yaml debug.* → Assistants settings PATCH fields.
25
+ * includePromptTrace → fullDebugEnabled (LLM prompt capture gate).
26
+ * enabled → debugEnabled (runtime debug traces).
27
+ * @param {Object|null|undefined} debugSection
28
+ * @returns {{ debugEnabled?: boolean, fullDebugEnabled?: boolean }}
29
+ */
30
+ function mapRoleAssistantDebugToAssistantsSettings(debugSection) {
31
+ if (!debugSection || typeof debugSection !== 'object') {
32
+ return {};
33
+ }
34
+ const body = {};
35
+ if (typeof debugSection.enabled === 'boolean') {
36
+ body.debugEnabled = debugSection.enabled;
37
+ }
38
+ if (typeof debugSection.includePromptTrace === 'boolean') {
39
+ body.fullDebugEnabled = debugSection.includePromptTrace;
40
+ }
41
+ return body;
42
+ }
43
+
44
+ /**
45
+ * Map role-assistant.yaml runtime.* to the governed Assistants settings names.
46
+ * Provider selection remains platform-owned; the assistant may override only
47
+ * its workflow reasoning model and execution profile.
48
+ * @param {Object|null|undefined} runtimeSection
49
+ * @returns {{ workflowReasoningModel?: string, temperature?: number, maxLlmLoops?: number, maxToolLoops?: number }}
50
+ */
51
+ function mapRoleAssistantRuntimeToAssistantsSettings(runtimeSection) {
52
+ if (!runtimeSection || typeof runtimeSection !== 'object') {
53
+ return {};
54
+ }
55
+ const body = {};
56
+ if (typeof runtimeSection.model === 'string' && runtimeSection.model.trim()) {
57
+ body.workflowReasoningModel = runtimeSection.model.trim();
58
+ }
59
+ if (typeof runtimeSection.temperature === 'number') {
60
+ body.temperature = runtimeSection.temperature;
61
+ }
62
+ if (Number.isInteger(runtimeSection.maxLoops)) {
63
+ body.maxLlmLoops = runtimeSection.maxLoops;
64
+ body.maxToolLoops = runtimeSection.maxLoops;
65
+ }
66
+ return body;
67
+ }
68
+
69
+ /**
70
+ * Push role-assistant.yaml knowledge + debug settings to dataplane Assistants.
71
+ * Called on upload/deploy so the operator UI and CLI stay aligned.
72
+ */
73
+ function resolveAssistantSettingsPush(params) {
74
+ const {
75
+ systemKey,
76
+ environment = 'dev',
77
+ pathOptions = {}
78
+ } = params;
79
+ const settingsEnv = resolveRoleAssistantSettingsEnvKey(environment);
80
+ const settings = readRoleAssistantSettings(systemKey, { required: false, pathOptions });
81
+ if (!settings) {
82
+ return { result: { skipped: true, reason: 'missing-role-assistant-settings' } };
83
+ }
84
+ const section = resolveRoleAssistantEnvironmentSettings(settings, settingsEnv, {
85
+ required: false
86
+ });
87
+ if (!section) {
88
+ return { result: { skipped: true, reason: 'missing-env-settings' } };
89
+ }
90
+ const documentStorageKey =
91
+ resolveDocumentStorageKeyFromRoleAssistantSettings(settings, settingsEnv) || '';
92
+ const debugBody = mapRoleAssistantDebugToAssistantsSettings(section.debug);
93
+ const runtimeBody = mapRoleAssistantRuntimeToAssistantsSettings(section.runtime);
94
+ const settingsBody = { ...runtimeBody, ...debugBody };
95
+ if (!documentStorageKey && Object.keys(settingsBody).length === 0) {
96
+ return { result: { skipped: true, reason: 'no-document-storage-key', documentStorageKey: null } };
97
+ }
98
+ const patchBody = { ...settingsBody };
99
+ if (documentStorageKey) {
100
+ patchBody.documentStorageKey = documentStorageKey;
101
+ }
102
+ return { documentStorageKey, debugBody: settingsBody, patchBody };
103
+ }
104
+
105
+ async function applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush) {
106
+ const { documentStorageKey, debugBody, patchBody } = settingsPush;
107
+ const hasDocumentStorageKey = documentStorageKey !== '';
108
+ const hasDebugSettings = Object.keys(debugBody).length > 0;
109
+ const assistantKey = String(systemKey || '').trim();
110
+ let response = await updateAssistantSettings(
111
+ dataplaneUrl,
112
+ assistantKey,
113
+ authConfig,
114
+ patchBody
115
+ );
116
+ if (response && response.success === false && hasDocumentStorageKey && hasDebugSettings) {
117
+ response = await updateAssistantSettings(
118
+ dataplaneUrl,
119
+ assistantKey,
120
+ authConfig,
121
+ debugBody
122
+ );
123
+ if (response && response.success === false) {
124
+ throw new Error(
125
+ response.formattedError ||
126
+ response.error ||
127
+ 'Failed to update Assistants debug settings'
128
+ );
129
+ }
130
+ return {
131
+ skipped: false,
132
+ documentStorageKey: null,
133
+ documentStoragePushFailed: true,
134
+ ...debugBody
135
+ };
136
+ }
137
+ if (response && response.success === false) {
138
+ throw new Error(
139
+ response.formattedError ||
140
+ response.error ||
141
+ 'Failed to update Knowledge document storage settings'
142
+ );
143
+ }
144
+ return {
145
+ skipped: false,
146
+ documentStorageKey: documentStorageKey || null,
147
+ ...debugBody
148
+ };
149
+ }
150
+
151
+ async function pushRoleAssistantDocumentStorageSettings(params) {
152
+ const { systemKey, dataplaneUrl, authConfig, dryRun = false } = params;
153
+ const settingsPush = resolveAssistantSettingsPush(params);
154
+ if (settingsPush.result) {
155
+ return settingsPush.result;
156
+ }
157
+ const { documentStorageKey, debugBody } = settingsPush;
158
+ if (dryRun) {
159
+ return { skipped: false, dryRun: true, documentStorageKey: documentStorageKey || null, ...debugBody };
160
+ }
161
+ if (!dataplaneUrl || !authConfig) {
162
+ return { skipped: true, reason: 'missing-dataplane-auth' };
163
+ }
164
+ return applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush);
165
+ }
166
+
167
+ module.exports = {
168
+ resolveRoleAssistantSettingsEnvKey,
169
+ mapRoleAssistantDebugToAssistantsSettings,
170
+ mapRoleAssistantRuntimeToAssistantsSettings,
171
+ pushRoleAssistantDocumentStorageSettings
172
+ };
@@ -15,8 +15,7 @@ const yaml = require('js-yaml');
15
15
  const { listDocuments, validateDocuments, bulkDocuments } = require('../api/datasources-extended.api');
16
16
  const {
17
17
  extractDocumentStorageKeyFromAssistantDetails,
18
- getAssistantDetails,
19
- updateAssistantSettings
18
+ getAssistantDetails
20
19
  } = require('../api/assistants.api');
21
20
  const { resolveExternalSystemPath } = require('../utils/app-path-resolve');
22
21
  const { bareRoleKey } = require('../utils/role-assistant-paths');
@@ -24,9 +23,14 @@ const {
24
23
  SYSTEM_KIND_DIGITAL_WORKER,
25
24
  getRoleAssistantYamlPath,
26
25
  readRoleAssistantSettings,
27
- resolveDocumentStorageKeyFromRoleAssistantSettings,
28
- resolveRoleAssistantEnvironmentSettings
26
+ resolveDocumentStorageKeyFromRoleAssistantSettings
29
27
  } = require('./settings');
28
+ const {
29
+ resolveRoleAssistantSettingsEnvKey,
30
+ mapRoleAssistantDebugToAssistantsSettings,
31
+ mapRoleAssistantRuntimeToAssistantsSettings,
32
+ pushRoleAssistantDocumentStorageSettings
33
+ } = require('./knowledge-sync-settings-push');
30
34
  const {
31
35
  knowledgeSearchMetadataFromFrontmatter,
32
36
  splitMarkdownFrontmatter
@@ -87,123 +91,6 @@ async function resolveDocumentStorageKeyFromDataplane(dataplaneUrl, authConfig,
87
91
  }
88
92
  }
89
93
 
90
- /**
91
- * Map role-assistant.yaml debug.* → Assistants settings PATCH fields.
92
- * includePromptTrace → fullDebugEnabled (LLM prompt capture gate).
93
- * enabled → debugEnabled (runtime debug traces).
94
- * @param {Object|null|undefined} debugSection
95
- * @returns {{ debugEnabled?: boolean, fullDebugEnabled?: boolean }}
96
- */
97
- function mapRoleAssistantDebugToAssistantsSettings(debugSection) {
98
- if (!debugSection || typeof debugSection !== 'object') {
99
- return {};
100
- }
101
- const body = {};
102
- if (typeof debugSection.enabled === 'boolean') {
103
- body.debugEnabled = debugSection.enabled;
104
- }
105
- if (typeof debugSection.includePromptTrace === 'boolean') {
106
- body.fullDebugEnabled = debugSection.includePromptTrace;
107
- }
108
- return body;
109
- }
110
-
111
- /**
112
- * Push role-assistant.yaml knowledge + debug settings to dataplane Assistants.
113
- * Called on upload/deploy so the operator UI and CLI stay aligned.
114
- */
115
- function resolveAssistantSettingsPush(params) {
116
- const {
117
- systemKey,
118
- environment = 'dev',
119
- pathOptions = {}
120
- } = params;
121
- const settingsEnv = resolveRoleAssistantSettingsEnvKey(environment);
122
- const settings = readRoleAssistantSettings(systemKey, { required: false, pathOptions });
123
- if (!settings) {
124
- return { result: { skipped: true, reason: 'missing-role-assistant-settings' } };
125
- }
126
- const section = resolveRoleAssistantEnvironmentSettings(settings, settingsEnv, {
127
- required: false
128
- });
129
- if (!section) {
130
- return { result: { skipped: true, reason: 'missing-env-settings' } };
131
- }
132
- const documentStorageKey =
133
- resolveDocumentStorageKeyFromRoleAssistantSettings(settings, settingsEnv) || '';
134
- const debugBody = mapRoleAssistantDebugToAssistantsSettings(section.debug);
135
- if (!documentStorageKey && Object.keys(debugBody).length === 0) {
136
- return { result: { skipped: true, reason: 'no-document-storage-key', documentStorageKey: null } };
137
- }
138
- const patchBody = { ...debugBody };
139
- if (documentStorageKey) {
140
- patchBody.documentStorageKey = documentStorageKey;
141
- }
142
- return { documentStorageKey, debugBody, patchBody };
143
- }
144
-
145
- async function applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush) {
146
- const { documentStorageKey, debugBody, patchBody } = settingsPush;
147
- const hasDocumentStorageKey = documentStorageKey !== '';
148
- const hasDebugSettings = Object.keys(debugBody).length > 0;
149
- const assistantKey = String(systemKey || '').trim();
150
- let response = await updateAssistantSettings(
151
- dataplaneUrl,
152
- assistantKey,
153
- authConfig,
154
- patchBody
155
- );
156
- if (response && response.success === false && hasDocumentStorageKey && hasDebugSettings) {
157
- response = await updateAssistantSettings(
158
- dataplaneUrl,
159
- assistantKey,
160
- authConfig,
161
- debugBody
162
- );
163
- if (response && response.success === false) {
164
- throw new Error(
165
- response.formattedError ||
166
- response.error ||
167
- 'Failed to update Assistants debug settings'
168
- );
169
- }
170
- return {
171
- skipped: false,
172
- documentStorageKey: null,
173
- documentStoragePushFailed: true,
174
- ...debugBody
175
- };
176
- }
177
- if (response && response.success === false) {
178
- throw new Error(
179
- response.formattedError ||
180
- response.error ||
181
- 'Failed to update Knowledge document storage settings'
182
- );
183
- }
184
- return {
185
- skipped: false,
186
- documentStorageKey: documentStorageKey || null,
187
- ...debugBody
188
- };
189
- }
190
-
191
- async function pushRoleAssistantDocumentStorageSettings(params) {
192
- const { systemKey, dataplaneUrl, authConfig, dryRun = false } = params;
193
- const settingsPush = resolveAssistantSettingsPush(params);
194
- if (settingsPush.result) {
195
- return settingsPush.result;
196
- }
197
- const { documentStorageKey, debugBody } = settingsPush;
198
- if (dryRun) {
199
- return { skipped: false, dryRun: true, documentStorageKey: documentStorageKey || null, ...debugBody };
200
- }
201
- if (!dataplaneUrl || !authConfig) {
202
- return { skipped: true, reason: 'missing-dataplane-auth' };
203
- }
204
- return applyAssistantSettingsPush(dataplaneUrl, systemKey, authConfig, settingsPush);
205
- }
206
-
207
94
  /**
208
95
  * Resolve Knowledge document storage key.
209
96
  * Order: role-assistant.yaml → dataplane Assistants settings → package dataSources.
@@ -341,11 +228,6 @@ function resolveDocumentFileName(row, index) {
341
228
  return filePath.startsWith('/') ? filePath.slice(1) : filePath;
342
229
  }
343
230
 
344
- function resolveRoleAssistantSettingsEnvKey(environment) {
345
- const token = String(environment || '').trim().toLowerCase();
346
- return token === 'dev' || token === 'tst' || token === 'pro' ? token : 'dev';
347
- }
348
-
349
231
  function writeRoleAssistantSettingsFile(systemKey, docStorageKey, environment = 'dev', pathOptions = {}) {
350
232
  const roleAssistantPath = resolveExternalSystemPath(systemKey, pathOptions);
351
233
  const roleAssistantYamlPath = getRoleAssistantYamlPath(systemKey, { pathOptions });
@@ -477,6 +359,7 @@ module.exports = {
477
359
  resolveRoleAssistantSettingsEnvKey,
478
360
  resolveRoleAssistantDocumentStorageKey,
479
361
  mapRoleAssistantDebugToAssistantsSettings,
362
+ mapRoleAssistantRuntimeToAssistantsSettings,
480
363
  pushRoleAssistantDocumentStorageSettings,
481
364
  importRoleAssistantKnowledge,
482
365
  exportRoleAssistantKnowledge,
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Role Assistant package folder validation (settings, tests, evidence, knowledge).
3
+ * @fileoverview Walk ra-* governed files. Ignore leftover Connected System artifacts.
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { validateExternalFile, parseJsonFileContent } = require('../validation/validate-external-file');
11
+ const { listTestCaseFiles } = require('./test-cases');
12
+ const { validateTestCaseFile } = require('./test-case-validate');
13
+
14
+ const SETTINGS_TYPE = 'role-assistant-settings';
15
+ const EMPTY_TESTS_SKIP = 'tests/: skipped (no test cases)';
16
+
17
+ function fileRow(filePath, type, result) {
18
+ return {
19
+ file: path.basename(filePath),
20
+ type,
21
+ valid: result.valid,
22
+ path: filePath,
23
+ errors: result.errors || [],
24
+ warnings: result.warnings || []
25
+ };
26
+ }
27
+
28
+ function listFilesByExt(dirPath, ext, acc) {
29
+ if (!fs.existsSync(dirPath)) {
30
+ return acc;
31
+ }
32
+ for (const name of fs.readdirSync(dirPath)) {
33
+ if (String(name).startsWith('.')) {
34
+ continue;
35
+ }
36
+ const full = path.join(dirPath, name);
37
+ const st = fs.statSync(full);
38
+ if (st.isDirectory()) {
39
+ listFilesByExt(full, ext, acc);
40
+ } else if (String(name).toLowerCase().endsWith(ext)) {
41
+ acc.push(full);
42
+ }
43
+ }
44
+ return acc;
45
+ }
46
+
47
+ function evidenceRows(parsed) {
48
+ if (Array.isArray(parsed)) {
49
+ return parsed;
50
+ }
51
+ if (parsed && typeof parsed === 'object') {
52
+ return [parsed];
53
+ }
54
+ return null;
55
+ }
56
+
57
+ function validateEvidenceJsonFile(filePath) {
58
+ const parseResult = parseJsonFileContent(filePath);
59
+ if (parseResult.error) {
60
+ return { ...parseResult.error, file: filePath, type: 'evidence' };
61
+ }
62
+ const rows = evidenceRows(parseResult.parsed);
63
+ const errors = [];
64
+ if (!rows) {
65
+ errors.push(`${filePath}: Evidence JSON must be an object or array of objects`);
66
+ } else {
67
+ rows.forEach((row, index) => {
68
+ const key = row && typeof row === 'object' && !Array.isArray(row) ? String(row.key || '').trim() : '';
69
+ if (!key) {
70
+ errors.push(`${filePath}: item ${index} is missing key`);
71
+ }
72
+ });
73
+ }
74
+ return { valid: errors.length === 0, errors, warnings: [], file: filePath, type: 'evidence' };
75
+ }
76
+
77
+ function validateKnowledgeMarkdown(filePath) {
78
+ const text = fs.readFileSync(filePath, 'utf8');
79
+ if (!String(text).trim()) {
80
+ return {
81
+ valid: false,
82
+ errors: [`${filePath}: knowledge markdown must not be empty`],
83
+ warnings: [],
84
+ file: filePath,
85
+ type: 'knowledge'
86
+ };
87
+ }
88
+ return { valid: true, errors: [], warnings: [], file: filePath, type: 'knowledge' };
89
+ }
90
+
91
+ async function validateSettingsFile(appPath) {
92
+ const yamlPath = path.join(appPath, 'role-assistant.yaml');
93
+ try {
94
+ const result = await validateExternalFile(yamlPath, SETTINGS_TYPE);
95
+ return fileRow(yamlPath, SETTINGS_TYPE, result);
96
+ } catch (error) {
97
+ return fileRow(yamlPath, SETTINGS_TYPE, {
98
+ valid: false,
99
+ errors: [error.message],
100
+ warnings: []
101
+ });
102
+ }
103
+ }
104
+
105
+ function collectDuplicateCaseIdErrors(caseFiles) {
106
+ const seen = new Map();
107
+ const errors = [];
108
+ for (const row of caseFiles) {
109
+ const parseResult = parseJsonFileContent(row.path);
110
+ const caseId = parseResult.parsed && String(parseResult.parsed.caseId || '').trim();
111
+ if (!caseId) {
112
+ continue;
113
+ }
114
+ if (seen.has(caseId)) {
115
+ errors.push(`${row.path}: duplicate caseId "${caseId}" (also ${seen.get(caseId)})`);
116
+ } else {
117
+ seen.set(caseId, row.path);
118
+ }
119
+ }
120
+ return errors;
121
+ }
122
+
123
+ function validateTestFiles(appPath) {
124
+ const testsDir = path.join(appPath, 'tests');
125
+ const yamlFiles = listTestCaseFiles(testsDir);
126
+ if (yamlFiles.length === 0) {
127
+ return { files: [], errors: [], warnings: [EMPTY_TESTS_SKIP] };
128
+ }
129
+ const files = yamlFiles.map((filePath) => fileRow(filePath, 'role-assistant-test-case', validateTestCaseFile(filePath)));
130
+ const errors = files.flatMap((row) => row.errors);
131
+ errors.push(...collectDuplicateCaseIdErrors(files));
132
+ return { files, errors, warnings: [] };
133
+ }
134
+
135
+ function validateEvidenceFiles(appPath) {
136
+ const jsonFiles = listFilesByExt(path.join(appPath, 'evidence'), '.json', []);
137
+ const files = jsonFiles.map((filePath) => fileRow(filePath, 'evidence', validateEvidenceJsonFile(filePath)));
138
+ return { files, errors: files.flatMap((row) => row.errors), warnings: [] };
139
+ }
140
+
141
+ function validateKnowledgeFiles(appPath) {
142
+ const mdFiles = listFilesByExt(path.join(appPath, 'knowledge'), '.md', []).filter((filePath) => {
143
+ return path.dirname(filePath) === path.join(appPath, 'knowledge');
144
+ });
145
+ const files = mdFiles.map((filePath) => fileRow(filePath, 'knowledge', validateKnowledgeMarkdown(filePath)));
146
+ return { files, errors: files.flatMap((row) => row.errors), warnings: [] };
147
+ }
148
+
149
+ async function validateRoleAssistantPackage(appPath) {
150
+ const settings = await validateSettingsFile(appPath);
151
+ const tests = validateTestFiles(appPath);
152
+ const evidence = validateEvidenceFiles(appPath);
153
+ const knowledge = validateKnowledgeFiles(appPath);
154
+ const files = [settings, ...tests.files, ...evidence.files, ...knowledge.files];
155
+ const errors = [
156
+ ...settings.errors,
157
+ ...tests.errors,
158
+ ...evidence.errors,
159
+ ...knowledge.errors
160
+ ];
161
+ const warnings = [...settings.warnings, ...tests.warnings, ...evidence.warnings, ...knowledge.warnings];
162
+ return {
163
+ valid: errors.length === 0,
164
+ errors,
165
+ warnings,
166
+ files
167
+ };
168
+ }
169
+
170
+ module.exports = {
171
+ EMPTY_TESTS_SKIP,
172
+ validateRoleAssistantPackage,
173
+ validateEvidenceJsonFile,
174
+ validateKnowledgeMarkdown
175
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared assertion row helpers (pass/fail/warn/notes/skip).
3
+ * @fileoverview Kind flags for Role Assistant test result rows
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ function skipRow(id, message) {
9
+ return { id, passed: true, skip: true, kind: 'skip', message };
10
+ }
11
+
12
+ function notesRow(id, message) {
13
+ return { id, passed: true, notes: true, kind: 'notes', message };
14
+ }
15
+
16
+ function withKind(row) {
17
+ if (!row || row.kind) {
18
+ return row;
19
+ }
20
+ if (row.notes === true) {
21
+ return { ...row, kind: 'notes' };
22
+ }
23
+ if (row.skip === true) {
24
+ return { ...row, kind: 'skip' };
25
+ }
26
+ if (row.warn === true) {
27
+ return { ...row, kind: 'warn' };
28
+ }
29
+ return { ...row, kind: row.passed ? 'pass' : 'fail' };
30
+ }
31
+
32
+ module.exports = {
33
+ skipRow,
34
+ notesRow,
35
+ withKind
36
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Bind a Work Hub execution to the Role Assistant named on copy.
3
+ *
4
+ * @fileoverview Fail closed on mismatch; trust the CLI role when identity is absent
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const {
10
+ bareRoleKey,
11
+ roleAssistantSystemKey
12
+ } = require('../utils/role-assistant-paths');
13
+
14
+ const PLACEHOLDER = new Set(['', 'unknown', 'none', 'null']);
15
+
16
+ function throwCopyStatus(message, status) {
17
+ const err = new Error(message);
18
+ err.status = status;
19
+ throw err;
20
+ }
21
+
22
+ function usableIdentity(value) {
23
+ const token = String(value || '').trim();
24
+ if (!token || PLACEHOLDER.has(token.toLowerCase())) {
25
+ return '';
26
+ }
27
+ return token;
28
+ }
29
+
30
+ function pushIdentity(acc, value) {
31
+ const token = usableIdentity(value);
32
+ if (token) {
33
+ acc.push(token);
34
+ }
35
+ }
36
+
37
+ function boundIdentityTokens(status, result) {
38
+ const acc = [];
39
+ const task = result && result.task && typeof result.task === 'object' ? result.task : {};
40
+ pushIdentity(acc, status && status.assistantKey);
41
+ pushIdentity(acc, status && status.digitalWorkerKey);
42
+ pushIdentity(acc, result && result.assistantKey);
43
+ pushIdentity(acc, result && result.digitalWorkerKey);
44
+ pushIdentity(acc, task.assistantKey);
45
+ pushIdentity(acc, task.digitalWorkerKey);
46
+ pushIdentity(acc, task.activeBusinessRoleRef);
47
+ pushIdentity(acc, task.roleKey);
48
+ return [...new Set(acc)];
49
+ }
50
+
51
+ function identityMatchesSystem(token, systemKey) {
52
+ const expectedSystem = roleAssistantSystemKey(systemKey);
53
+ const expectedBare = bareRoleKey(systemKey).toLowerCase();
54
+ const lower = token.toLowerCase();
55
+ if (lower === expectedSystem.toLowerCase()) {
56
+ return true;
57
+ }
58
+ return bareRoleKey(token).toLowerCase() === expectedBare;
59
+ }
60
+
61
+ function assertCopyBoundToSystem(systemKey, status, result) {
62
+ const tokens = boundIdentityTokens(status, result);
63
+ if (tokens.length === 0) {
64
+ return { bound: false };
65
+ }
66
+ const mismatch = tokens.find((token) => !identityMatchesSystem(token, systemKey));
67
+ if (mismatch) {
68
+ throwCopyStatus('Execution belongs to a different Role Assistant', 409);
69
+ }
70
+ return { bound: true };
71
+ }
72
+
73
+ module.exports = {
74
+ throwCopyStatus,
75
+ boundIdentityTokens,
76
+ assertCopyBoundToSystem
77
+ };