@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,83 @@
1
+ /**
2
+ * Installed Agent Kit state file.
3
+ * @fileoverview Read/write .aifabrix/agent-kit.yaml
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const yaml = require('js-yaml');
10
+ const fs = require('../internal/fs-real-sync');
11
+ const { STATE_RELATIVE, SECTION_ID } = require('./constants');
12
+
13
+ /**
14
+ * @param {string} repoRoot
15
+ * @returns {string}
16
+ */
17
+ function statePath(repoRoot) {
18
+ return path.join(repoRoot, STATE_RELATIVE);
19
+ }
20
+
21
+ /**
22
+ * @param {string} repoRoot
23
+ * @returns {object|null}
24
+ */
25
+ function loadState(repoRoot) {
26
+ const filePath = statePath(repoRoot);
27
+ if (!fs.existsSync(filePath)) {
28
+ return null;
29
+ }
30
+ const parsed = yaml.load(fs.readFileSync(filePath, 'utf8'));
31
+ if (!parsed || typeof parsed !== 'object') {
32
+ return null;
33
+ }
34
+ return parsed;
35
+ }
36
+
37
+ /**
38
+ * @param {object} kit
39
+ * @param {string[]} hosts
40
+ * @param {object[]} ops
41
+ * @param {string} builderVersion
42
+ * @returns {object}
43
+ */
44
+ function buildStateDocument(kit, hosts, ops, builderVersion) {
45
+ const managedFiles = [];
46
+ for (const op of ops) {
47
+ if (op.action === 'delete' || op.action === 'retain' || op.action === 'conflict') {
48
+ continue;
49
+ }
50
+ if (op.action === 'skip' && op.fileState === 'MISSING') {
51
+ continue;
52
+ }
53
+ if (!op.targetRel || op.mode === 'obsolete' || op.mode === 'if-missing') {
54
+ continue;
55
+ }
56
+ const row = { path: op.targetRel, sha256: op.sourceHash };
57
+ if (op.mode === 'managed-section') {
58
+ row.section = SECTION_ID;
59
+ }
60
+ managedFiles.push(row);
61
+ }
62
+ return {
63
+ schemaVersion: '1',
64
+ kitVersion: kit.manifest.kitVersion,
65
+ builderVersion,
66
+ installedAt: new Date().toISOString(),
67
+ hosts,
68
+ managedFiles
69
+ };
70
+ }
71
+
72
+ /**
73
+ * @param {string} repoRoot
74
+ * @param {object} doc
75
+ * @returns {void}
76
+ */
77
+ function writeState(repoRoot, doc) {
78
+ const filePath = statePath(repoRoot);
79
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
80
+ fs.writeFileSync(filePath, yaml.dump(doc, { lineWidth: 120, noRefs: true, sortKeys: false }), 'utf8');
81
+ }
82
+
83
+ module.exports = { statePath, loadState, buildStateDocument, writeState };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Agent Kit status.
3
+ * @fileoverview Classify installed files without writing
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { getCliVersion } = require('../utils/installation-log-core');
9
+ const { resolveGitRoot } = require('./repo-guard');
10
+ const { loadKitPackage } = require('./package-load');
11
+ const { listManagedTargets } = require('./file-list');
12
+ const { classifyItems } = require('./classify');
13
+ const { detectV1, listObsoleteV1Items } = require('./v1-detect');
14
+ const { loadState } = require('./state-file');
15
+ const { ACTION } = require('./constants');
16
+ const { kitStateName, buildJsonReport } = require('./report');
17
+ const { ALL_HOSTS } = require('./hosts');
18
+
19
+ /**
20
+ * @param {object} options
21
+ * @returns {object}
22
+ */
23
+ function runStatus(options) {
24
+ const repoRoot = resolveGitRoot(options.cwd || process.cwd());
25
+ const kit = loadKitPackage();
26
+ const state = loadState(repoRoot);
27
+ const includeShims = detectV1(repoRoot);
28
+ const hosts = (state && state.hosts) || ALL_HOSTS.slice();
29
+ const includeClaude = hosts.includes('claude');
30
+ const items = listManagedTargets(kit, repoRoot, {
31
+ includeShims: includeShims && hosts.includes('cursor'),
32
+ includeClaude
33
+ });
34
+ classifyItems(items, state, hosts);
35
+ items.push(...listObsoleteV1Items(kit, repoRoot, new Set(items.map((item) => item.targetRel))));
36
+ const ops = items.map((item) => ({ ...item, action: ACTION.SKIP }));
37
+ const kitState = kitStateName(state, kit, ops);
38
+ return buildJsonReport({
39
+ command: 'status',
40
+ kit,
41
+ state,
42
+ hosts,
43
+ ops,
44
+ dryRun: true,
45
+ builderVersion: getCliVersion(),
46
+ kitState
47
+ });
48
+ }
49
+
50
+ module.exports = { runStatus };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Detect v1 Agent Kit files in a customer repository.
3
+ * @fileoverview Name + hash detection for migration
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { V1_MARKERS, FILE_STATE } = require('./constants');
11
+ const { sha256File } = require('./checksums');
12
+
13
+ /**
14
+ * @param {string} repoRoot
15
+ * @returns {boolean}
16
+ */
17
+ function detectV1(repoRoot) {
18
+ return V1_MARKERS.some((rel) => fs.existsSync(path.join(repoRoot, rel)));
19
+ }
20
+
21
+ /**
22
+ * @param {object} kit
23
+ * @param {string} repoRoot
24
+ * @param {Set<string>} managedRels
25
+ * @returns {object[]}
26
+ */
27
+ function listObsoleteV1Items(kit, repoRoot, managedRels) {
28
+ const rows = (kit.inventory && kit.inventory.v1Files) || [];
29
+ const items = [];
30
+ for (const row of rows) {
31
+ if (row.disposition === 'shim' || !row.installedPath) {
32
+ continue;
33
+ }
34
+ if (managedRels.has(row.installedPath)) {
35
+ continue;
36
+ }
37
+ const targetAbs = path.join(repoRoot, row.installedPath);
38
+ if (!fs.existsSync(targetAbs)) {
39
+ continue;
40
+ }
41
+ const hash = sha256File(targetAbs);
42
+ const unchanged = hash === row.sha256;
43
+ items.push({
44
+ sourceAbs: null,
45
+ targetRel: row.installedPath,
46
+ targetAbs,
47
+ mode: 'obsolete',
48
+ sourceHash: row.sha256,
49
+ currentHash: hash,
50
+ fileState: unchanged
51
+ ? FILE_STATE.OBSOLETE_UNCHANGED_MANAGED
52
+ : FILE_STATE.OBSOLETE_MODIFIED_MANAGED,
53
+ v1Owner: row.owner
54
+ });
55
+ }
56
+ return items;
57
+ }
58
+
59
+ /**
60
+ * Replace unmodified v1 command files with thin shims on install.
61
+ * @param {object[]} items
62
+ * @param {object} kit
63
+ * @returns {void}
64
+ */
65
+ function markV1ShimReplacements(items, kit) {
66
+ const byPath = new Map();
67
+ for (const row of (kit.inventory && kit.inventory.v1Files) || []) {
68
+ byPath.set(row.installedPath, row);
69
+ }
70
+ for (const item of items) {
71
+ if (!item.optional || !item.currentHash) {
72
+ continue;
73
+ }
74
+ const row = byPath.get(item.targetRel);
75
+ if (row && row.disposition === 'shim' && item.currentHash === row.sha256) {
76
+ item.replaceOnInstall = true;
77
+ }
78
+ }
79
+ }
80
+
81
+ module.exports = { detectV1, listObsoleteV1Items, markV1ShimReplacements };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Validate bundled Agent Kit package and optional install.
3
+ * @fileoverview Schema, paths, skill names, installed conflicts
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { loadKitPackage } = require('./package-load');
11
+ const { listTreeFiles } = require('./file-list');
12
+ const { runStatus } = require('./status');
13
+ const { KIT_STATE } = require('./constants');
14
+
15
+ const FORBIDDEN_RE = /@[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}|kv:\/\/[^\s]+\/[A-Za-z0-9+/]{12,}|\/home\/[a-z0-9]+\/(?!dev)/i;
16
+
17
+ /**
18
+ * @param {object} kit
19
+ * @returns {string[]}
20
+ */
21
+ function collectPackageErrors(kit) {
22
+ const errors = [];
23
+ const names = kit.manifest.skills || [];
24
+ if (new Set(names).size !== names.length) {
25
+ errors.push('Duplicate skill name in agent-kit.yaml.');
26
+ }
27
+ for (const name of names) {
28
+ const skillMd = path.join(kit.root, 'skills', name, 'SKILL.md');
29
+ if (!fs.existsSync(skillMd)) {
30
+ errors.push(`Missing SKILL.md for ${name}.`);
31
+ }
32
+ }
33
+ for (const spec of [...(kit.manifest.managed || []), ...(kit.manifest.optional || [])]) {
34
+ const sourceAbs = path.join(kit.root, spec.source);
35
+ if (!fs.existsSync(sourceAbs)) {
36
+ errors.push(`Managed source missing: ${spec.source}`);
37
+ }
38
+ }
39
+ return errors;
40
+ }
41
+
42
+ /**
43
+ * @param {object} kit
44
+ * @returns {string[]}
45
+ */
46
+ function collectContentErrors(kit) {
47
+ const errors = [];
48
+ for (const file of listTreeFiles(kit.root, '')) {
49
+ if (file.rel === 'parity-inventory.yaml') {
50
+ continue;
51
+ }
52
+ const text = fs.readFileSync(file.abs, 'utf8');
53
+ if (FORBIDDEN_RE.test(text)) {
54
+ errors.push(`Forbidden customer/secret pattern in ${file.rel}`);
55
+ }
56
+ }
57
+ return errors;
58
+ }
59
+
60
+ /**
61
+ * @param {object} [options]
62
+ * @returns {object}
63
+ */
64
+ function runValidate(options = {}) {
65
+ const kit = loadKitPackage();
66
+ const errors = [...collectPackageErrors(kit), ...collectContentErrors(kit)];
67
+ let install = null;
68
+ try {
69
+ install = runStatus(options);
70
+ } catch (error) {
71
+ if (!String(error.message || '').includes('git repository')) {
72
+ throw error;
73
+ }
74
+ }
75
+ if (install && install.state === KIT_STATE.CONFLICTS) {
76
+ errors.push(`Install conflicts: ${install.conflicts.join(', ')}`);
77
+ }
78
+ return {
79
+ success: errors.length === 0,
80
+ command: 'validate',
81
+ kitVersion: kit.manifest.kitVersion,
82
+ errors,
83
+ install
84
+ };
85
+ }
86
+
87
+ module.exports = { runValidate, collectPackageErrors, collectContentErrors };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Resolve workspace directory name for agent-kit init.
3
+ * @fileoverview Name authority — never rewrite cust-* to aif-*
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+
10
+ /**
11
+ * @param {string|undefined} nameOrPath
12
+ * @param {string} cwd
13
+ * @returns {{ targetAbs: string, workspaceName: string }}
14
+ */
15
+ function resolveWorkspaceTarget(nameOrPath, cwd) {
16
+ const base = path.resolve(cwd || process.cwd());
17
+ if (!nameOrPath || !String(nameOrPath).trim()) {
18
+ throw new Error('Workspace name or path is required. Example: aifabrix agent-kit init cust-demo');
19
+ }
20
+ const raw = String(nameOrPath).trim();
21
+ const looksLikePath =
22
+ path.isAbsolute(raw) || raw.includes('/') || raw.includes('\\') || raw === '.' || raw.startsWith('.');
23
+ const targetAbs = looksLikePath ? path.resolve(base, raw) : path.join(base, raw);
24
+ const workspaceName = path.basename(targetAbs);
25
+ if (!workspaceName || workspaceName === '.' || workspaceName === '..') {
26
+ throw new Error('Could not derive a workspace name from the path.');
27
+ }
28
+ return { targetAbs, workspaceName };
29
+ }
30
+
31
+ /**
32
+ * Preserve user-supplied names; never rewrite cust-* prefixes.
33
+ * @param {string} name
34
+ * @returns {string}
35
+ */
36
+ function assertNameUnchanged(name) {
37
+ return name;
38
+ }
39
+
40
+ module.exports = { resolveWorkspaceTarget, assertNameUnchanged };
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Copy product-neutral workspace skeleton for agent-kit init.
3
+ * @fileoverview templates/agent-kit/workspace → target
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { getKitRoot } = require('./kit-root');
11
+
12
+ /**
13
+ * @returns {string}
14
+ */
15
+ function getWorkspaceTemplateRoot() {
16
+ return path.join(getKitRoot(), 'workspace');
17
+ }
18
+
19
+ /**
20
+ * @param {string} text
21
+ * @param {{ workspaceName: string, year?: number, copyrightHolder?: string }} vars
22
+ * @returns {string}
23
+ */
24
+ function applyPlaceholders(text, vars) {
25
+ return String(text)
26
+ .replace(/\{\{workspaceName\}\}/g, vars.workspaceName)
27
+ .replace(/\{\{year\}\}/g, String(vars.year || new Date().getFullYear()))
28
+ .replace(/\{\{copyrightHolder\}\}/g, vars.copyrightHolder || 'Copyright Holder');
29
+ }
30
+
31
+ /**
32
+ * @param {string} absDir
33
+ * @param {string} relPrefix
34
+ * @returns {{ rel: string, abs: string }[]}
35
+ */
36
+ function listTemplateFiles(absDir, relPrefix) {
37
+ if (!fs.existsSync(absDir)) {
38
+ return [];
39
+ }
40
+ const out = [];
41
+ for (const ent of fs.readdirSync(absDir, { withFileTypes: true })) {
42
+ const rel = relPrefix ? `${relPrefix}/${ent.name}` : ent.name;
43
+ const abs = path.join(absDir, ent.name);
44
+ if (ent.isDirectory()) {
45
+ out.push(...listTemplateFiles(abs, rel));
46
+ } else if (ent.name !== 'LICENSE.mit') {
47
+ out.push({ rel, abs });
48
+ }
49
+ }
50
+ return out;
51
+ }
52
+
53
+ /**
54
+ * @param {string} targetAbs
55
+ * @param {{ workspaceName: string, license?: string, dryRun?: boolean }} options
56
+ * @returns {string[]} written relative paths
57
+ */
58
+ function writeWorkspaceSkeleton(targetAbs, options) {
59
+ const written = [];
60
+ const vars = { workspaceName: options.workspaceName };
61
+ const root = getWorkspaceTemplateRoot();
62
+ for (const file of listTemplateFiles(root, '')) {
63
+ const dest = path.join(targetAbs, file.rel);
64
+ if (!options.dryRun) {
65
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
66
+ const body = applyPlaceholders(fs.readFileSync(file.abs, 'utf8'), vars);
67
+ fs.writeFileSync(dest, body, 'utf8');
68
+ }
69
+ written.push(file.rel);
70
+ }
71
+ if (options.license === 'mit') {
72
+ const src = path.join(root, 'LICENSE.mit');
73
+ const dest = path.join(targetAbs, 'LICENSE');
74
+ if (!options.dryRun && fs.existsSync(src)) {
75
+ fs.writeFileSync(dest, applyPlaceholders(fs.readFileSync(src, 'utf8'), vars), 'utf8');
76
+ }
77
+ written.push('LICENSE');
78
+ }
79
+ if (!options.dryRun) {
80
+ fs.mkdirSync(path.join(targetAbs, 'integration'), { recursive: true });
81
+ fs.mkdirSync(path.join(targetAbs, 'role-assistant'), { recursive: true });
82
+ }
83
+ return written;
84
+ }
85
+
86
+ /**
87
+ * @param {string} targetAbs
88
+ * @returns {boolean}
89
+ */
90
+ function isNonEmptyDirectory(targetAbs) {
91
+ if (!fs.existsSync(targetAbs)) {
92
+ return false;
93
+ }
94
+ const entries = fs.readdirSync(targetAbs).filter((name) => name !== '.git');
95
+ return entries.length > 0;
96
+ }
97
+
98
+ module.exports = {
99
+ getWorkspaceTemplateRoot,
100
+ applyPlaceholders,
101
+ writeWorkspaceSkeleton,
102
+ isNonEmptyDirectory
103
+ };
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Dataplane Role Assistant test pack CRUD + case status.
3
+ *
4
+ * @fileoverview PUT/GET pack and PATCH case status
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { createDataplaneApiClient } = require('./index');
12
+ const { throwIfApiFailed } = require('./api-response-errors');
13
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
14
+
15
+ function packEndpoint(dataplaneUrl, systemIdOrKey, suffix) {
16
+ const base = String(dataplaneUrl || '').replace(/\/$/, '');
17
+ const key = encodeURIComponent(systemIdOrKey);
18
+ return `${base}/api/v1/external/systems/${key}/role-assistant-tests${suffix || ''}`;
19
+ }
20
+
21
+ function packPath(systemIdOrKey, suffix) {
22
+ const key = encodeURIComponent(systemIdOrKey);
23
+ return `/api/v1/external/systems/${key}/role-assistant-tests${suffix || ''}`;
24
+ }
25
+
26
+ function isMissingPackResponse(res) {
27
+ return Boolean(res && res.success === false && Number(res.status) === 404);
28
+ }
29
+
30
+ /**
31
+ * PUT /api/v1/external/systems/{systemIdOrKey}/role-assistant-tests
32
+ * @requiresPermission {Dataplane} external-system:update
33
+ * @async
34
+ */
35
+ async function upsertRoleAssistantTestPack(dataplaneUrl, authConfig, systemIdOrKey, pack) {
36
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
37
+ const res = await client.put(packPath(systemIdOrKey), { body: { pack } });
38
+ throwIfApiFailed(res, {
39
+ endpointUrl: packEndpoint(dataplaneUrl, systemIdOrKey, '')
40
+ });
41
+ return unwrapApiData(res);
42
+ }
43
+
44
+ /**
45
+ * GET /api/v1/external/systems/{systemIdOrKey}/role-assistant-tests
46
+ * @requiresPermission {Dataplane} external-system:read
47
+ * @async
48
+ */
49
+ async function getRoleAssistantTestPack(dataplaneUrl, authConfig, systemIdOrKey, options = {}) {
50
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
51
+ const res = await client.get(packPath(systemIdOrKey));
52
+ if (options.allowMissing === true && isMissingPackResponse(res)) {
53
+ return null;
54
+ }
55
+ throwIfApiFailed(res, {
56
+ endpointUrl: packEndpoint(dataplaneUrl, systemIdOrKey, '')
57
+ });
58
+ return unwrapApiData(res);
59
+ }
60
+
61
+ /**
62
+ * PATCH /api/v1/external/systems/{systemIdOrKey}/role-assistant-tests/cases/{caseId}/status
63
+ * @requiresPermission {Dataplane} external-system:update
64
+ * @async
65
+ */
66
+ async function patchRoleAssistantTestCaseStatus(
67
+ dataplaneUrl,
68
+ authConfig,
69
+ systemIdOrKey,
70
+ caseId,
71
+ body
72
+ ) {
73
+ const suffix = `/cases/${encodeURIComponent(caseId)}/status`;
74
+ const client = createDataplaneApiClient(dataplaneUrl, authConfig);
75
+ const res = await client.patch(packPath(systemIdOrKey, suffix), { body });
76
+ throwIfApiFailed(res, {
77
+ endpointUrl: packEndpoint(dataplaneUrl, systemIdOrKey, suffix)
78
+ });
79
+ return unwrapApiData(res);
80
+ }
81
+
82
+ module.exports = {
83
+ upsertRoleAssistantTestPack,
84
+ getRoleAssistantTestPack,
85
+ patchRoleAssistantTestCaseStatus
86
+ };
@@ -14,6 +14,7 @@ const { unwrapApiData } = require('../utils/external-system-readiness-core');
14
14
  const SEARCH_TIMEOUT_MS = 120000;
15
15
  const LAYER_B_SYSTEM_KEY = process.env.RUNTIME_ORCHESTRATION_SYSTEM_KEY || 'runtime-orchestration';
16
16
  const LAYER_B_TOOLS = Object.freeze({
17
+ roles: { resourceType: 'work-roles', toolName: 'work_roles.list' },
17
18
  skills: { resourceType: 'work-skills', toolName: 'work_skills.get' },
18
19
  search: { resourceType: 'work-search', toolName: 'work_search.create' }
19
20
  });
@@ -45,19 +46,31 @@ function extractErrorText(res) {
45
46
  return parts.join(' ');
46
47
  }
47
48
 
49
+ /**
50
+ * MCP execute sometimes wraps a single JSON object as a one-element array.
51
+ * @param {*} value
52
+ * @returns {*}
53
+ */
54
+ function unwrapSingletonObject(value) {
55
+ if (Array.isArray(value) && value.length === 1 && value[0] && typeof value[0] === 'object') {
56
+ return value[0];
57
+ }
58
+ return value;
59
+ }
60
+
48
61
  function unwrapExecutePayload(res) {
49
- const body = unwrapApiData(res);
62
+ const body = unwrapSingletonObject(unwrapApiData(res));
50
63
  if (!body || typeof body !== 'object') {
51
64
  return body;
52
65
  }
53
66
  if (body.result && typeof body.result === 'object') {
54
- return body.result;
67
+ return unwrapSingletonObject(body.result);
55
68
  }
56
69
  if (body.json && typeof body.json === 'object') {
57
- return body.json;
70
+ return unwrapSingletonObject(body.json);
58
71
  }
59
72
  if (body.root && typeof body.root === 'object') {
60
- return body.root;
73
+ return unwrapSingletonObject(body.root);
61
74
  }
62
75
  return body;
63
76
  }
@@ -94,6 +107,18 @@ async function executeLayerBTool(dataplaneUrl, authConfig, tool, args = {}) {
94
107
  return normalizeLayerBResult(res);
95
108
  }
96
109
 
110
+ /**
111
+ * GET-equivalent work.roles for the current caller.
112
+ * @requiresPermission {Dataplane} Authenticated (oauth2: [])
113
+ * @async
114
+ * @param {string} dataplaneUrl
115
+ * @param {Object} authConfig
116
+ * @returns {Promise<{ status: number, payload: Object|null, errorText: string, raw: Object }>}
117
+ */
118
+ async function getWorkRoles(dataplaneUrl, authConfig) {
119
+ return executeLayerBTool(dataplaneUrl, authConfig, LAYER_B_TOOLS.roles, {});
120
+ }
121
+
97
122
  /**
98
123
  * GET-equivalent work.skills for one roleRef.
99
124
  * Requests detail=full so search.resourceTypes (executable grammar) is present.
@@ -128,9 +153,11 @@ module.exports = {
128
153
  SEARCH_TIMEOUT_MS,
129
154
  buildLayerBExecutePath,
130
155
  extractErrorText,
156
+ unwrapSingletonObject,
131
157
  unwrapExecutePayload,
132
158
  normalizeLayerBResult,
133
159
  executeLayerBTool,
160
+ getWorkRoles,
134
161
  getWorkSkills,
135
162
  searchWork
136
163
  };