@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
@@ -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) {
@@ -29,12 +29,33 @@ const PILLAR_LABELS = Object.freeze({
29
29
  governance: 'Governance'
30
30
  });
31
31
 
32
+ /** Connected System lifecycle labels — same Draft / Published / Archived as the web. */
33
+ const CONNECTED_SYSTEM_LIFECYCLE_LABELS = Object.freeze({
34
+ draft: 'Draft',
35
+ published: 'Published',
36
+ archived: 'Archived',
37
+ deployed: 'Published'
38
+ });
39
+
40
+ /**
41
+ * Product lifecycle label, or null when the value is not Draft/Published/Archived
42
+ * (controller `active` is not Published).
43
+ * @param {string|null|undefined} status
44
+ * @returns {string|null}
45
+ */
46
+ function formatConnectedSystemLifecycleLabel(status) {
47
+ const raw = String(status || '').trim().toLowerCase();
48
+ return CONNECTED_SYSTEM_LIFECYCLE_LABELS[raw] || null;
49
+ }
50
+
32
51
  /**
33
52
  * @param {string|null|undefined} status
34
53
  * @returns {string}
35
54
  */
36
55
  function formatLifecycleLabel(status) {
37
56
  const raw = String(status || 'unknown').trim().toLowerCase();
57
+ const lifecycle = formatConnectedSystemLifecycleLabel(raw);
58
+ if (lifecycle) return lifecycle;
38
59
  if (!raw || raw === 'unknown') return 'Unknown';
39
60
  return raw.charAt(0).toUpperCase() + raw.slice(1);
40
61
  }
@@ -159,8 +180,14 @@ function resolveManifestAuthMethod(systemCfg) {
159
180
  * @returns {string}
160
181
  */
161
182
  function resolveConnectedSystemStatus(opts = {}) {
162
- const fromPub = opts.publication?.system?.status;
163
183
  const fromGet = opts.systemFromDataplane?.status;
184
+ if (fromGet) {
185
+ return formatLifecycleLabel(fromGet);
186
+ }
187
+ if (opts.command === 'upload') {
188
+ return formatLifecycleLabel('draft');
189
+ }
190
+ const fromPub = opts.publication?.system?.status;
164
191
  return formatLifecycleLabel(fromGet || fromPub || opts.status);
165
192
  }
166
193
 
@@ -307,6 +334,8 @@ function logCompactTip(opts) {
307
334
 
308
335
  module.exports = {
309
336
  PILLAR_LABELS,
337
+ CONNECTED_SYSTEM_LIFECYCLE_LABELS,
338
+ formatConnectedSystemLifecycleLabel,
310
339
  formatLifecycleLabel,
311
340
  truncateKeyList,
312
341
  formatCredentialPushLine,
@@ -52,7 +52,8 @@ function validateFieldMappingExpression(expression) {
52
52
  'replace',
53
53
  'join',
54
54
  'split',
55
- 'normalizeWhitespace'
55
+ 'normalizeWhitespace',
56
+ 'index'
56
57
  ];
57
58
  for (const trans of transformations) {
58
59
  const transName = trans.split('(')[0].trim();
@@ -80,6 +80,7 @@ const CATEGORIES = [
80
80
  { name: 'resource-type' },
81
81
  { name: 'role' },
82
82
  { name: 'role-assistant' },
83
+ { name: 'search' },
83
84
  { name: 'evidence-kind' },
84
85
  { name: 'enterprise-knowledge' },
85
86
  { name: 'identity' },
@@ -133,7 +134,8 @@ const CATEGORIES = [
133
134
  { name: 'dev' },
134
135
  { name: 'secret' },
135
136
  { name: 'npm', term: 'npm config' },
136
- { name: 'secure' }
137
+ { name: 'secure' },
138
+ { name: 'agent-kit' }
137
139
  ]
138
140
  }
139
141
  ];
@@ -82,15 +82,18 @@ async function waitForKeycloakRealmReady(opts = {}) {
82
82
  const directUrl = directBase ? buildRealmWellKnownUrl(directBase) : null;
83
83
  const deadline = Date.now() + timeoutSeconds * 1000;
84
84
 
85
- while (Date.now() < deadline) {
85
+ do {
86
86
  if (await probeRealmWellKnown(url)) {
87
87
  return;
88
88
  }
89
89
  if (directUrl && (await probeRealmWellKnown(directUrl))) {
90
90
  return;
91
91
  }
92
+ if (Date.now() >= deadline) {
93
+ break;
94
+ }
92
95
  await new Promise((resolve) => setTimeout(resolve, intervalMs));
93
- }
96
+ } while (Date.now() < deadline);
94
97
 
95
98
  throw new Error(
96
99
  `Keycloak realm "aifabrix" was not ready within ${timeoutSeconds}s (checked ${url}${directUrl ? ` and ${directUrl}` : ''}). ` +
@@ -83,4 +83,5 @@ const logger = {
83
83
  };
84
84
 
85
85
  module.exports = logger;
86
+ module.exports.sanitizeValue = sanitizeValue;
86
87
 
@@ -957,6 +957,24 @@ async function ensureShippedBuilderAppTemplate(appName) {
957
957
  return true;
958
958
  }
959
959
 
960
+ /**
961
+ * Finds an existing local app workspace without copying shipped templates.
962
+ *
963
+ * @param {string} appName - Application name
964
+ * @param {Object} [options] - Detection options (reserved; options.type is ignored)
965
+ * @returns {{isExternal: boolean, appPath: string, appType: string, baseDir?: string}|null}
966
+ */
967
+ function findExistingAppType(appName, options = {}) {
968
+ if (!appName || typeof appName !== 'string') {
969
+ return null;
970
+ }
971
+ const externalResult = checkExternalWorkspaceFolder(appName, options);
972
+ if (externalResult) {
973
+ return externalResult;
974
+ }
975
+ return checkBuilderFolder(appName);
976
+ }
977
+
960
978
  /**
961
979
  * Detects if an app is external type by checking application config.
962
980
  * Resolution order: integration/ first, then builder/; if neither exists, throws.
@@ -971,13 +989,15 @@ async function detectAppType(appName, options = {}) {
971
989
  if (!appName || typeof appName !== 'string') {
972
990
  throw new Error('App name is required and must be a string');
973
991
  }
974
- const externalResult = checkExternalWorkspaceFolder(appName, options);
975
- if (externalResult) return externalResult;
976
- const builderResult = checkBuilderFolder(appName);
977
- if (builderResult) return builderResult;
992
+ const existing = findExistingAppType(appName, options);
993
+ if (existing) {
994
+ return existing;
995
+ }
978
996
  await ensureShippedBuilderAppTemplate(appName);
979
997
  const builderAfterTemplate = checkBuilderFolder(appName);
980
- if (builderAfterTemplate) return builderAfterTemplate;
998
+ if (builderAfterTemplate) {
999
+ return builderAfterTemplate;
1000
+ }
981
1001
  throw new Error(
982
1002
  `App '${appName}' not found in integration/${appName}, enterprise-knowledge/${appName}, role-assistant/${appName}, or builder/${appName}`
983
1003
  );
@@ -1121,6 +1141,7 @@ module.exports = {
1121
1141
  resolveApplicationConfigPath,
1122
1142
  resolveRbacPath,
1123
1143
  ensureShippedBuilderAppTemplate,
1144
+ findExistingAppType,
1124
1145
  detectAppType,
1125
1146
  getResolveAppPath,
1126
1147
  resolveIntegrationAppKeyFromCwd,
@@ -19,6 +19,7 @@ const addFormats = require('ajv-formats');
19
19
  let externalSystemValidator = null;
20
20
  let externalDataSourceValidator = null;
21
21
  let roleAssistantSettingsValidator = null;
22
+ let roleAssistantTestCaseValidator = null;
22
23
 
23
24
  /**
24
25
  * Reset validators cache (for testing)
@@ -28,6 +29,7 @@ function resetValidators() {
28
29
  externalSystemValidator = null;
29
30
  externalDataSourceValidator = null;
30
31
  roleAssistantSettingsValidator = null;
32
+ roleAssistantTestCaseValidator = null;
31
33
  }
32
34
 
33
35
  /**
@@ -172,6 +174,37 @@ function loadRoleAssistantSettingsSchema() {
172
174
  return roleAssistantSettingsValidator;
173
175
  }
174
176
 
177
+ /**
178
+ * Loads and compiles role-assistant test-case schema.
179
+ * @function loadRoleAssistantTestCaseSchema
180
+ * @returns {Function}
181
+ */
182
+ function loadRoleAssistantTestCaseSchema() {
183
+ if (roleAssistantTestCaseValidator) {
184
+ return roleAssistantTestCaseValidator;
185
+ }
186
+
187
+ const schemaPath = path.join(__dirname, '..', 'schema', 'role-assistant-test-case.schema.json');
188
+ let schema;
189
+ try {
190
+ schema = JSON.parse(fsRealSync.readFileSync(schemaPath, 'utf8'));
191
+ } catch (error) {
192
+ try {
193
+ schema = require('../schema/role-assistant-test-case.schema.json');
194
+ } catch {
195
+ if (error && error.code === 'ENOENT') {
196
+ throw new Error(`Role assistant test-case schema not found: ${schemaPath}`);
197
+ }
198
+ throw new Error(`Invalid JSON in role-assistant-test-case.schema.json: ${error.message}`);
199
+ }
200
+ }
201
+
202
+ const ajv = new Ajv({ allErrors: true, verbose: true, strict: false, strictSchema: false });
203
+ addFormats(ajv);
204
+ roleAssistantTestCaseValidator = ajv.compile(schema);
205
+ return roleAssistantTestCaseValidator;
206
+ }
207
+
175
208
  /**
176
209
  * Detect schema type from $id field
177
210
  * @param {Object} parsed - Parsed JSON object
@@ -194,6 +227,9 @@ function detectFromId(parsed) {
194
227
  if (parsed.$id.includes('role-assistant-settings')) {
195
228
  return 'role-assistant-settings';
196
229
  }
230
+ if (parsed.$id.includes('role-assistant-test-case')) {
231
+ return 'role-assistant-test-case';
232
+ }
197
233
 
198
234
  return null;
199
235
  }
@@ -388,6 +424,7 @@ module.exports = {
388
424
  loadExternalSystemSchema,
389
425
  loadExternalDataSourceSchema,
390
426
  loadRoleAssistantSettingsSchema,
427
+ loadRoleAssistantTestCaseSchema,
391
428
  registerExternalDatasourceAjvDependencies,
392
429
  detectSchemaType,
393
430
  detectSchemaTypeFromParsed,
@@ -47,7 +47,8 @@ const { resolveBashKvFromProcessEnv } = require('./secrets-bash-kv');
47
47
  const EMPTY_ALLOWED_KV_FALLBACK = new Set([
48
48
  'redis-passwordKeyVault',
49
49
  'azure-openaiapi-urlKeyVault',
50
- 'secrets-azureOpenaiApiKeyVault'
50
+ 'secrets-azureOpenaiApiKeyVault',
51
+ 'miso-controller-secrets-apiKeyVault'
51
52
  ]);
52
53
 
53
54
  /**
@@ -486,4 +487,3 @@ module.exports = {
486
487
  rewriteInfraEndpoints,
487
488
  getEnvHosts
488
489
  };
489
-
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Flush a writable stream chunk without hanging on Jest write mocks.
3
+ *
4
+ * @fileoverview Shared stdout/stderr write + wait for CLI exits.
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * @param {unknown} writeFn - Stream write implementation
13
+ * @returns {boolean}
14
+ */
15
+ function isJestMockWrite(writeFn) {
16
+ return typeof jest !== 'undefined'
17
+ && typeof jest.isMockFunction === 'function'
18
+ && jest.isMockFunction(writeFn);
19
+ }
20
+
21
+ /**
22
+ * Write `chunk` and resolve after the stream flushes.
23
+ *
24
+ * Piped stdout/stderr on Linux is asynchronous; exiting before the write
25
+ * callback can truncate output. Jest spies that ignore the callback, and
26
+ * native writes inside a Jest worker, must not hang the test.
27
+ *
28
+ * @param {NodeJS.WritableStream} stream - stdout or stderr
29
+ * @param {string} chunk - Bytes to write
30
+ * @returns {Promise<void>}
31
+ */
32
+ function writeStreamAndWait(stream, chunk) {
33
+ return new Promise(resolve => {
34
+ let settled = false;
35
+ const finish = () => {
36
+ if (settled) {
37
+ return;
38
+ }
39
+ settled = true;
40
+ resolve();
41
+ };
42
+ if (!stream || typeof stream.write !== 'function') {
43
+ finish();
44
+ return;
45
+ }
46
+ const writeFn = stream.write;
47
+ try {
48
+ writeFn.call(stream, chunk, finish);
49
+ } catch {
50
+ finish();
51
+ return;
52
+ }
53
+ if (isJestMockWrite(writeFn) && writeFn.length < 2) {
54
+ finish();
55
+ return;
56
+ }
57
+ if (!isJestMockWrite(writeFn) && process.env.JEST_WORKER_ID) {
58
+ setImmediate(finish);
59
+ }
60
+ });
61
+ }
62
+
63
+ module.exports = { writeStreamAndWait };
@@ -13,7 +13,8 @@ const yaml = require('js-yaml');
13
13
  const {
14
14
  loadExternalSystemSchema,
15
15
  loadExternalDataSourceSchema,
16
- loadRoleAssistantSettingsSchema
16
+ loadRoleAssistantSettingsSchema,
17
+ loadRoleAssistantTestCaseSchema
17
18
  } = require('../utils/schema-loader');
18
19
  const { formatValidationErrors } = require('../utils/error-formatter');
19
20
  const { validateFieldReferences } = require('../datasource/field-reference-validator');
@@ -60,6 +61,9 @@ function getValidatorForType(normalizedType) {
60
61
  if (normalizedType === 'role-assistant-settings') {
61
62
  return loadRoleAssistantSettingsSchema();
62
63
  }
64
+ if (normalizedType === 'role-assistant-test-case') {
65
+ return loadRoleAssistantTestCaseSchema();
66
+ }
63
67
  throw new Error(`Unknown file type: ${normalizedType}`);
64
68
  }
65
69
 
@@ -27,6 +27,7 @@ const {
27
27
  isRoleAssistantWorkspace,
28
28
  isEnterpriseKnowledgeWorkspace
29
29
  } = require('../utils/platform-shell-package');
30
+ const { validateRoleAssistantPackage } = require('../role-assistant/package-validate');
30
31
 
31
32
  /**
32
33
  * Validates a file path (detects type and validates)
@@ -335,7 +336,7 @@ function skippedComponentsStep() {
335
336
  return { valid: true, errors: [], warnings: [], files: [], skipped: true };
336
337
  }
337
338
 
338
- async function validatePlatformShellPackage(appName, baseDir, appPath, options) {
339
+ async function validatePlatformShellPackage(_appName, baseDir, appPath, _options) {
339
340
  if (isEnterpriseKnowledgeWorkspace(baseDir)) {
340
341
  return aggregateExternalValidationSteps({
341
342
  application: skippedValidationStep(),
@@ -348,7 +349,7 @@ async function validatePlatformShellPackage(appName, baseDir, appPath, options)
348
349
  }
349
350
  return aggregateExternalValidationSteps({
350
351
  application: skippedValidationStep(),
351
- components: await validateComponentsStep(appName, options),
352
+ components: await validateRoleAssistantPackage(appPath),
352
353
  manifest: skippedValidationStep()
353
354
  }, appPath);
354
355
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.54.1",
3
+ "version": "2.55.2",
4
4
  "description": "AI Fabrix Builder — CLI and developer scripts (pnpm + af)",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -86,28 +86,42 @@
86
86
  "overrides": {
87
87
  "@babel/core": "^7.29.7",
88
88
  "@babel/plugin-transform-modules-systemjs": "^7.29.7",
89
- "fast-uri": "^4.1.0",
89
+ "baseline-browser-mapping": "^2.11.21",
90
+ "brace-expansion@5": "5.0.9",
91
+ "browserslist": "^4.28.9",
92
+ "fast-uri": "^4.1.4",
90
93
  "flatted": "^3.4.2",
91
94
  "follow-redirects": "^1.16.0",
92
95
  "form-data": "^4.0.6",
96
+ "js-yaml@3": "3.15.2",
97
+ "js-yaml@5": "5.4.1",
93
98
  "lodash": "^4.18.1",
94
99
  "minimatch": "^10.2.5",
100
+ "multer": "^2.3.0",
95
101
  "picomatch": "^4.0.5",
96
- "qs": "^6.15.3"
102
+ "qs": "^6.16.0",
103
+ "smol-toml": "^1.8.0"
97
104
  },
98
105
  "pnpm": {
99
106
  "overrides": {
100
107
  "@bcoe/v8-coverage": "^1.0.2",
101
108
  "@babel/core": "^7.29.7",
102
109
  "@babel/plugin-transform-modules-systemjs": "^7.29.7",
103
- "fast-uri": "^4.1.0",
110
+ "baseline-browser-mapping": "^2.11.21",
111
+ "brace-expansion@5": "5.0.9",
112
+ "browserslist": "^4.28.9",
113
+ "fast-uri": "^4.1.4",
104
114
  "flatted": "^3.4.2",
105
115
  "follow-redirects": "^1.16.0",
106
116
  "form-data": "^4.0.6",
117
+ "js-yaml@3": "3.15.2",
118
+ "js-yaml@5": "5.4.1",
107
119
  "lodash": "^4.18.1",
108
120
  "minimatch": "^10.2.5",
121
+ "multer": "^2.3.0",
109
122
  "picomatch": "^4.0.5",
110
- "qs": "^6.15.3"
123
+ "qs": "^6.16.0",
124
+ "smol-toml": "^1.8.0"
111
125
  }
112
126
  },
113
127
  "dependencies": {
@@ -121,7 +135,7 @@
121
135
  "handlebars": "^4.7.9",
122
136
  "inquirer": "^8.2.5",
123
137
  "inquirer-autocomplete-prompt": "^2.0.0",
124
- "js-yaml": "^4.3.0",
138
+ "js-yaml": "^4.3.2",
125
139
  "ora": "^5.4.1",
126
140
  "yaml": "^2.9.0"
127
141
  },
@@ -0,0 +1,5 @@
1
+ @AGENTS.md
2
+
3
+ Delivery skills: `/aifabrix-plan`, `/aifabrix-connected-system`, `/aifabrix-role-assistant`, `/aifabrix-prove`.
4
+ The skill body lives under `.agents/skills/`. Do not invent a parallel workflow.
5
+ Local vs SSH (tmux, Remote Control): `.agents/skills/shared/hosts.md`.
@@ -0,0 +1,5 @@
1
+ # cust-0-plan
2
+
3
+ Compatibility alias for skill **aifabrix-plan**. Optional system key.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-plan` on fresh installs.
@@ -0,0 +1,5 @@
1
+ # cust-1-validate
2
+
3
+ Compatibility alias for skill **aifabrix-connected-system** phase `validate`.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-connected-system`.
@@ -0,0 +1,5 @@
1
+ # cust-2-build
2
+
3
+ Compatibility alias for skill **aifabrix-connected-system** phase `build`.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-connected-system`.
@@ -0,0 +1,5 @@
1
+ # cust-3-push
2
+
3
+ Compatibility alias for skill **aifabrix-connected-system** phase `publish`.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-connected-system`.
@@ -0,0 +1,5 @@
1
+ # cust-biz-1-validate
2
+
3
+ Compatibility alias for skill **aifabrix-prove** phase `validate`.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-prove`.
@@ -0,0 +1,5 @@
1
+ # cust-biz-2-build
2
+
3
+ Compatibility alias for skill **aifabrix-prove** phase `build`.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-prove`.
@@ -0,0 +1,5 @@
1
+ # cust-biz-3-prove
2
+
3
+ Compatibility alias for skill **aifabrix-prove** phase `prove`.
4
+
5
+ Contains no business rules. Prefer `/aifabrix-prove`.
@@ -0,0 +1,45 @@
1
+ schemaVersion: "1"
2
+ kitVersion: "1.1.2"
3
+ minimumBuilderVersion: "2.54.2"
4
+ skills:
5
+ - aifabrix-plan
6
+ - aifabrix-connected-system
7
+ - aifabrix-role-assistant
8
+ - aifabrix-prove
9
+ managed:
10
+ - source: skills
11
+ target: .agents/skills
12
+ mode: tree
13
+ - source: instructions/root.AGENTS.md
14
+ target: AGENTS.md
15
+ mode: managed-section
16
+ - source: instructions/integration.AGENTS.md
17
+ target: integration/AGENTS.md
18
+ mode: managed-section
19
+ - source: instructions/role-assistant.AGENTS.md
20
+ target: role-assistant/AGENTS.md
21
+ mode: managed-section
22
+ - source: instructions/AGENTKIT.md
23
+ target: AGENTKIT.md
24
+ mode: file
25
+ render: hosts
26
+ - source: workspace/README.md
27
+ target: README.md
28
+ mode: if-missing
29
+ optional:
30
+ - source: adapters/cursor/commands
31
+ target: .cursor/commands
32
+ mode: tree
33
+ when: v1-migration
34
+ - source: adapters/claude/root.CLAUDE.md
35
+ target: CLAUDE.md
36
+ mode: managed-section
37
+ when: host-claude
38
+ - source: adapters/claude/nested.CLAUDE.md
39
+ target: integration/CLAUDE.md
40
+ mode: managed-section
41
+ when: host-claude
42
+ - source: adapters/claude/nested.CLAUDE.md
43
+ target: role-assistant/CLAUDE.md
44
+ mode: managed-section
45
+ when: host-claude
@@ -0,0 +1,104 @@
1
+ # Agent Kit
2
+
3
+ Builder-owned. `aifabrix agent-kit update` refreshes this file. If workspace `README.md` is missing, install/update creates it. An existing README is never overwritten.
4
+
5
+ ## Install
6
+
7
+ From this git repository (Builder CLI on PATH):
8
+
9
+ ```bash
10
+ aifabrix agent-kit install --host {{hostFlag}}{{#if autoApprove}} --approve-all --yes{{/if}}
11
+ aifabrix agent-kit status
12
+ ```
13
+
14
+ `--host` may be `all`, `cursor`, `codex`, or `claude`. Shared skills always land in `.agents/skills/`.
15
+ {{#if claude}}
16
+ `claude` also writes `CLAUDE.md` and thin `.claude/skills` pointers.
17
+ {{/if}}
18
+
19
+ ## Update
20
+
21
+ When this CLI is newer than the workspace kit, or you add or switch coding hosts:
22
+
23
+ ```bash
24
+ aifabrix agent-kit update --host {{hostFlag}}{{#if autoApprove}} --approve-all --yes{{/if}}
25
+ aifabrix agent-kit validate
26
+ ```
27
+
28
+ Omit `--host` to keep the hosts already recorded. Pass `--host` when the developer changes Cursor / Claude Code / Codex.
29
+
30
+ New workspace instead of an existing repo: `aifabrix agent-kit init <workspaceName> --host {{hostFlag}}`.
31
+
32
+ ## Activate hosts
33
+
34
+ Install the coding app, then sign in. How to **run** it locally or over SSH is in `.agents/skills/shared/hosts.md` (linked from every Agent Kit skill).
35
+ {{#if autoApprove}}
36
+
37
+ On TTY, install **asks** which hosts to support (omit `--host`) and which tools to auto-approve. `--approve-all claude` or `--approve-all codex` writes only that host's config. Claude Code also allows `Bash(aifabrix *)` (delivery CLI) and `Read(~/**)` (home Read). Silent (`--yes` / non-TTY) writes them; `--skip-approve-all` skips.
38
+ {{#if claude}}
39
+ - Claude Code writes `.claude/settings.local.json` (gitignored).
40
+ {{/if}}
41
+ {{#if codex}}
42
+ - Codex writes `.codex/config.toml` (gitignored).
43
+ {{/if}}
44
+ {{/if}}
45
+ {{#if cursor}}
46
+
47
+ ### Cursor
48
+
49
+ Open this folder in Cursor (this machine, or Cursor Remote SSH). Skills: `/aifabrix-plan`, `/aifabrix-connected-system`, `/aifabrix-role-assistant`, `/aifabrix-prove`.
50
+ {{/if}}
51
+ {{#if claude}}
52
+
53
+ ### Claude Code
54
+
55
+ ```bash
56
+ curl -fsSL https://claude.ai/install.sh | bash
57
+ claude auth login
58
+ ```
59
+
60
+ **Run in tmux** from this workspace so closing the terminal does not kill Claude. `--remote-control` is the **same** session on this PC, [claude.ai/code](https://claude.ai/code), and the Claude mobile app (Code). That is not `claude --cloud` (a separate cloud VM). Claude `--tmux` is for worktrees only.
61
+
62
+ ```bash
63
+ aifabrix agent-kit start claude --remote-control --approve-all --yes
64
+ ```
65
+
66
+ tmux session name defaults to this folder. Remote Control name is `hostname-user-folder` (for example `builder01-dev03-aifabrix-docs`). Override the folder with `--name`. Detach: `Ctrl-b` then `d`. Reattach: `tmux attach -t <folder>`. Several workspaces can run at once. Same account on phone and PC (`claude auth login`, Pro/Max/Team — not an API key). On the phone: Claude app → **Code**. Skills: `/aifabrix-plan` (and the other `/aifabrix-*` names). First `claude` must run inside this workspace, not your home directory. Full notes: `.agents/skills/shared/hosts.md`.
67
+ {{/if}}
68
+ {{#if codex}}
69
+
70
+ ### Codex
71
+
72
+ Install the Codex CLI (`@openai/codex`, not the unrelated `codex` package), then sign in with ChatGPT (Plus, Pro, Business, Edu, or Enterprise):
73
+
74
+ ```bash
75
+ npm install -g @openai/codex
76
+ codex login
77
+ ```
78
+
79
+ **Run in tmux** from this workspace so the session stays if you close the terminal:
80
+
81
+ ```bash
82
+ aifabrix agent-kit start codex --approve-all --yes
83
+ ```
84
+
85
+ Detach: `Ctrl-b` then `d`. Reattach: `tmux attach -t <folder>`, or `aifabrix agent-kit start codex` from this workspace. Default session name is this folder. Skills: `$aifabrix-plan` (and the other `$aifabrix-*` names). Codex reads `AGENTS.md`. Full notes: `.agents/skills/shared/hosts.md`.
86
+ {{/if}}
87
+
88
+ ## Auth for delivery CLI
89
+
90
+ Do not tell the user to open a terminal for Builder login. Follow `.agents/skills/shared/login.md`.
91
+
92
+ ```bash
93
+ aifabrix auth status
94
+ ```
95
+
96
+ If that is not authenticated, ask for the Miso Controller URL, run device login, and paste the printed authenticate URL into chat.
97
+
98
+ ## How to start
99
+
100
+ After this folder is open in the coding host, follow **How to start** in the workspace `README.md` (how to use prompts, then plan → validate/build → publish, then Role Assistant).
101
+
102
+ ## Docs
103
+
104
+ Agents load the public index from `AGENTS.md`. Humans: the workspace `README.md` Docs section.