@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
package/README.md CHANGED
@@ -38,6 +38,14 @@ npm install -g @aifabrix/builder
38
38
 
39
39
  **Alias:** You can use `af` instead of `aifabrix` in any command.
40
40
 
41
+ Customer integration repositories can install the Agent Kit (Cursor, Codex, and Claude Code) with:
42
+
43
+ ```bash
44
+ aifabrix agent-kit install
45
+ ```
46
+
47
+ See [Agent Kit commands](docs/commands/agent-kit.md).
48
+
41
49
  ---
42
50
 
43
51
  ## Goal 1: Install the platform (one command)
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Apply planned Agent Kit file operations.
3
+ * @fileoverview Create, replace, append, or delete managed files
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { ACTION } = require('./constants');
11
+ const { wrapSection, appendManagedSection, replaceManagedSection } = require('./managed-section');
12
+
13
+ /**
14
+ * @param {string} filePath
15
+ * @returns {void}
16
+ */
17
+ function ensureParent(filePath) {
18
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
19
+ }
20
+
21
+ /**
22
+ * @param {object} item
23
+ * @returns {void}
24
+ */
25
+ function applyCreate(item) {
26
+ ensureParent(item.targetAbs);
27
+ const body =
28
+ item.mode === 'managed-section' ? wrapSection(item.sourceText) : item.sourceText;
29
+ fs.writeFileSync(item.targetAbs, body, 'utf8');
30
+ }
31
+
32
+ /**
33
+ * @param {object} item
34
+ * @returns {void}
35
+ */
36
+ function applyReplace(item) {
37
+ ensureParent(item.targetAbs);
38
+ if (item.mode === 'managed-section') {
39
+ const existing = fs.existsSync(item.targetAbs) ? fs.readFileSync(item.targetAbs, 'utf8') : '';
40
+ fs.writeFileSync(item.targetAbs, replaceManagedSection(existing, item.sourceText), 'utf8');
41
+ return;
42
+ }
43
+ fs.writeFileSync(item.targetAbs, item.sourceText, 'utf8');
44
+ }
45
+
46
+ /**
47
+ * @param {object} item
48
+ * @returns {void}
49
+ */
50
+ function applyAppend(item) {
51
+ const existing = fs.existsSync(item.targetAbs) ? fs.readFileSync(item.targetAbs, 'utf8') : '';
52
+ ensureParent(item.targetAbs);
53
+ fs.writeFileSync(item.targetAbs, appendManagedSection(existing, item.sourceText), 'utf8');
54
+ }
55
+
56
+ /**
57
+ * @param {object} item
58
+ * @returns {void}
59
+ */
60
+ function applyOne(item) {
61
+ if (item.action === ACTION.CREATE) {
62
+ applyCreate(item);
63
+ } else if (item.action === ACTION.REPLACE) {
64
+ applyReplace(item);
65
+ } else if (item.action === ACTION.APPEND_SECTION) {
66
+ applyAppend(item);
67
+ } else if (item.action === ACTION.DELETE) {
68
+ fs.unlinkSync(item.targetAbs);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * @param {object[]} ops
74
+ * @returns {void}
75
+ */
76
+ function applyOps(ops) {
77
+ for (const item of ops) {
78
+ applyOne(item);
79
+ }
80
+ }
81
+
82
+ module.exports = { applyOps, applyOne, applyCreate, applyReplace, applyAppend };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * SHA-256 helpers for Agent Kit file classification.
3
+ * @fileoverview Content hashes for managed files
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const crypto = require('crypto');
9
+ const fs = require('../internal/fs-real-sync');
10
+
11
+ /**
12
+ * @param {Buffer|string} value
13
+ * @returns {string}
14
+ */
15
+ function sha256(value) {
16
+ const buf = Buffer.isBuffer(value) ? value : Buffer.from(String(value), 'utf8');
17
+ return crypto.createHash('sha256').update(buf).digest('hex');
18
+ }
19
+
20
+ /**
21
+ * @param {string} filePath
22
+ * @returns {string}
23
+ */
24
+ function sha256File(filePath) {
25
+ return sha256(fs.readFileSync(filePath));
26
+ }
27
+
28
+ module.exports = { sha256, sha256File };
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Classify Agent Kit managed files against disk and recorded hashes.
3
+ * @fileoverview File-state machine for install/update
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('../internal/fs-real-sync');
9
+ const { FILE_STATE } = require('./constants');
10
+ const { sha256, sha256File } = require('./checksums');
11
+ const { extractSection, hasManagedSection } = require('./managed-section');
12
+ const { buildClaudeSkillShim } = require('./claude-shim');
13
+ const { renderHostMarkdown } = require('./render-host-markdown');
14
+ const { ALL_HOSTS } = require('./hosts');
15
+ const { applyPlaceholders } = require('./workspace-skeleton');
16
+
17
+ /**
18
+ * @param {object} item
19
+ * @returns {string}
20
+ */
21
+ function currentHash(item) {
22
+ if (!fs.existsSync(item.targetAbs)) {
23
+ return null;
24
+ }
25
+ if (item.mode === 'managed-section') {
26
+ const text = fs.readFileSync(item.targetAbs, 'utf8');
27
+ const section = extractSection(text);
28
+ return section === null ? sha256File(item.targetAbs) : sha256(section);
29
+ }
30
+ return sha256File(item.targetAbs);
31
+ }
32
+
33
+ /**
34
+ * @param {object} item
35
+ * @param {string|null} recorded
36
+ * @returns {string}
37
+ */
38
+ function classifyPresentFile(item, recorded) {
39
+ const hash = currentHash(item);
40
+ item.currentHash = hash;
41
+ if (item.mode === 'managed-section' && !hasManagedSection(fs.readFileSync(item.targetAbs, 'utf8'))) {
42
+ return FILE_STATE.USER_FILE_NO_MANAGED_SECTION;
43
+ }
44
+ if (recorded && hash === recorded) {
45
+ return FILE_STATE.UNCHANGED_MANAGED;
46
+ }
47
+ if (recorded && hash !== recorded) {
48
+ return FILE_STATE.MODIFIED_MANAGED;
49
+ }
50
+ if (hash === item.sourceHash) {
51
+ return FILE_STATE.UNCHANGED_MANAGED;
52
+ }
53
+ return FILE_STATE.MODIFIED_MANAGED;
54
+ }
55
+
56
+ /**
57
+ * @param {object} item
58
+ * @param {string[]} [hosts]
59
+ * @returns {string}
60
+ */
61
+ function materializeSource(item, hosts) {
62
+ const raw = fs.readFileSync(item.sourceAbs, 'utf8');
63
+ if (item.mode === 'claude-shim') {
64
+ return buildClaudeSkillShim(item.skillName, raw);
65
+ }
66
+ if (item.render === 'hosts') {
67
+ return renderHostMarkdown(raw, hosts);
68
+ }
69
+ if (item.mode === 'if-missing') {
70
+ return applyPlaceholders(raw, { workspaceName: item.workspaceName });
71
+ }
72
+ return raw;
73
+ }
74
+
75
+ /**
76
+ * @param {object} item
77
+ * @param {Map<string, string>} recordedByPath
78
+ * @param {string[]} hosts
79
+ * @returns {string}
80
+ */
81
+ function classifyItem(item, recordedByPath, hosts) {
82
+ item.sourceText = materializeSource(item, hosts);
83
+ item.sourceHash = item.mode === 'managed-section' ? sha256(item.sourceText.trim()) : sha256(item.sourceText);
84
+ if (!fs.existsSync(item.targetAbs)) {
85
+ item.currentHash = null;
86
+ return FILE_STATE.MISSING;
87
+ }
88
+ if (item.mode === 'if-missing') {
89
+ item.currentHash = sha256File(item.targetAbs);
90
+ return FILE_STATE.PROJECT_OWNED;
91
+ }
92
+ return classifyPresentFile(item, recordedByPath.get(item.targetRel) || null);
93
+ }
94
+
95
+ /**
96
+ * @param {object[]} items
97
+ * @param {object|null} state
98
+ * @param {string[]} [hosts]
99
+ * @returns {object[]}
100
+ */
101
+ function classifyItems(items, state, hosts) {
102
+ const recordedByPath = new Map();
103
+ const resolved = Array.isArray(hosts) && hosts.length ? hosts : ALL_HOSTS.slice();
104
+ for (const row of (state && state.managedFiles) || []) {
105
+ recordedByPath.set(row.path, row.sha256);
106
+ }
107
+ for (const item of items) {
108
+ item.fileState = classifyItem(item, recordedByPath, resolved);
109
+ }
110
+ return items;
111
+ }
112
+
113
+ module.exports = { classifyItems, classifyItem, currentHash };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Claude Code adapters: thin skill pointers, no duplicated skill bodies.
3
+ * @fileoverview Generate .claude/skills shims that load .agents/skills
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const yaml = require('js-yaml');
10
+
11
+ /**
12
+ * @param {string} skillMd
13
+ * @returns {string}
14
+ */
15
+ function extractSkillDescription(skillMd) {
16
+ const match = String(skillMd || '').match(/^---\r?\n([\s\S]*?)\r?\n---/);
17
+ if (!match) {
18
+ return '';
19
+ }
20
+ const parsed = yaml.load(match[1]);
21
+ return String((parsed && parsed.description) || '').trim();
22
+ }
23
+
24
+ /**
25
+ * @param {string} name
26
+ * @param {string} skillMd
27
+ * @returns {string}
28
+ */
29
+ function buildClaudeSkillShim(name, skillMd) {
30
+ const description = extractSkillDescription(skillMd) || name;
31
+ const folded = description.replace(/\n/g, '\n ');
32
+ return [
33
+ '---',
34
+ `name: ${name}`,
35
+ 'description: >',
36
+ ` ${folded}`,
37
+ '---',
38
+ '',
39
+ `Load and follow \`.agents/skills/${name}/SKILL.md\` and its \`references/\`.`,
40
+ 'That file is the skill body. Do not invent a parallel workflow.',
41
+ ''
42
+ ].join('\n');
43
+ }
44
+
45
+ /**
46
+ * @param {object} kit
47
+ * @param {string} repoRoot
48
+ * @returns {object[]}
49
+ */
50
+ function listClaudeSkillShims(kit, repoRoot) {
51
+ return (kit.manifest.skills || []).map((name) => ({
52
+ skillName: name,
53
+ sourceAbs: path.join(kit.root, 'skills', name, 'SKILL.md'),
54
+ targetRel: `.claude/skills/${name}/SKILL.md`,
55
+ targetAbs: path.join(repoRoot, '.claude/skills', name, 'SKILL.md'),
56
+ mode: 'claude-shim',
57
+ optional: true
58
+ }));
59
+ }
60
+
61
+ module.exports = { extractSkillDescription, buildClaudeSkillShim, listClaudeSkillShims };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Agent Kit constants.
3
+ * @fileoverview Shared markers, paths, and classification names
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const BEGIN_MARKER = '<!-- aifabrix-agent-kit:begin -->';
9
+ const END_MARKER = '<!-- aifabrix-agent-kit:end -->';
10
+ const STATE_RELATIVE = '.aifabrix/agent-kit.yaml';
11
+ const SECTION_ID = 'aifabrix-agent-kit';
12
+
13
+ const FILE_STATE = {
14
+ MISSING: 'MISSING',
15
+ UNCHANGED_MANAGED: 'UNCHANGED_MANAGED',
16
+ USER_FILE_NO_MANAGED_SECTION: 'USER_FILE_NO_MANAGED_SECTION',
17
+ MODIFIED_MANAGED: 'MODIFIED_MANAGED',
18
+ OBSOLETE_UNCHANGED_MANAGED: 'OBSOLETE_UNCHANGED_MANAGED',
19
+ OBSOLETE_MODIFIED_MANAGED: 'OBSOLETE_MODIFIED_MANAGED',
20
+ PROJECT_OWNED: 'PROJECT_OWNED'
21
+ };
22
+
23
+ const KIT_STATE = {
24
+ CURRENT: 'CURRENT',
25
+ UPDATE_AVAILABLE: 'UPDATE_AVAILABLE',
26
+ CONFLICTS: 'CONFLICTS',
27
+ NOT_INSTALLED: 'NOT_INSTALLED'
28
+ };
29
+
30
+ const ACTION = {
31
+ CREATE: 'create',
32
+ REPLACE: 'replace',
33
+ APPEND_SECTION: 'append-section',
34
+ SKIP: 'skip',
35
+ CONFLICT: 'conflict',
36
+ DELETE: 'delete',
37
+ RETAIN: 'retain'
38
+ };
39
+
40
+ const V1_MARKERS = [
41
+ '.cursor/commands/cust-0-plan.md',
42
+ '.cursor/rules/cust-commands.mdc',
43
+ '.cursor/skills/aifabrix-integration-lifecycle/SKILL.md'
44
+ ];
45
+
46
+ module.exports = {
47
+ BEGIN_MARKER,
48
+ END_MARKER,
49
+ STATE_RELATIVE,
50
+ SECTION_ID,
51
+ FILE_STATE,
52
+ KIT_STATE,
53
+ ACTION,
54
+ V1_MARKERS
55
+ };
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Enumerate managed Agent Kit source/target files.
3
+ * @fileoverview Walk kit trees from the package manifest
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { listClaudeSkillShims } = require('./claude-shim');
11
+
12
+ /**
13
+ * @param {string} absDir
14
+ * @param {string} relPrefix
15
+ * @returns {{ rel: string, abs: string }[]}
16
+ */
17
+ function listTreeFiles(absDir, relPrefix) {
18
+ if (!fs.existsSync(absDir)) {
19
+ return [];
20
+ }
21
+ const out = [];
22
+ const entries = fs.readdirSync(absDir, { withFileTypes: true });
23
+ for (const ent of entries) {
24
+ const rel = relPrefix ? `${relPrefix}/${ent.name}` : ent.name;
25
+ const abs = path.join(absDir, ent.name);
26
+ if (ent.isDirectory()) {
27
+ out.push(...listTreeFiles(abs, rel));
28
+ } else {
29
+ out.push({ rel, abs });
30
+ }
31
+ }
32
+ return out;
33
+ }
34
+
35
+ /**
36
+ * @param {object} spec
37
+ * @param {string} kitRoot
38
+ * @param {string} repoRoot
39
+ * @returns {object[]}
40
+ */
41
+ function expandManagedSpec(spec, kitRoot, repoRoot) {
42
+ const mode = spec.mode || 'tree';
43
+ const sourceAbs = path.join(kitRoot, spec.source);
44
+ if (mode === 'managed-section' || mode === 'file' || mode === 'if-missing') {
45
+ return [
46
+ {
47
+ sourceAbs,
48
+ targetRel: spec.target,
49
+ targetAbs: path.join(repoRoot, spec.target),
50
+ mode,
51
+ optional: false,
52
+ render: spec.render,
53
+ workspaceName: path.basename(repoRoot)
54
+ }
55
+ ];
56
+ }
57
+ return listTreeFiles(sourceAbs, '').map((file) => ({
58
+ sourceAbs: file.abs,
59
+ targetRel: path.posix.join(spec.target.replace(/\\/g, '/'), file.rel),
60
+ targetAbs: path.join(repoRoot, spec.target, file.rel),
61
+ mode: 'tree',
62
+ optional: Boolean(spec.when)
63
+ }));
64
+ }
65
+
66
+ /**
67
+ * @param {object} spec
68
+ * @param {{ includeShims?: boolean, includeClaude?: boolean }} opts
69
+ * @returns {boolean}
70
+ */
71
+ function shouldIncludeOptional(spec, opts) {
72
+ if (spec.when === 'host-claude') {
73
+ return Boolean(opts.includeClaude);
74
+ }
75
+ if (spec.when === 'v1-migration') {
76
+ return Boolean(opts.includeShims);
77
+ }
78
+ return false;
79
+ }
80
+
81
+ /**
82
+ * @param {object} kit
83
+ * @param {string} repoRoot
84
+ * @param {{ includeShims?: boolean, includeClaude?: boolean }} [opts]
85
+ * @returns {object[]}
86
+ */
87
+ function listManagedTargets(kit, repoRoot, opts = {}) {
88
+ const items = [];
89
+ for (const spec of kit.manifest.managed || []) {
90
+ items.push(...expandManagedSpec(spec, kit.root, repoRoot));
91
+ }
92
+ for (const spec of kit.manifest.optional || []) {
93
+ if (shouldIncludeOptional(spec, opts)) {
94
+ items.push(...expandManagedSpec(spec, kit.root, repoRoot));
95
+ }
96
+ }
97
+ if (opts.includeClaude) {
98
+ items.push(...listClaudeSkillShims(kit, repoRoot));
99
+ }
100
+ return items;
101
+ }
102
+
103
+ module.exports = { listTreeFiles, listManagedTargets };
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Claude Code and Codex auto-approve configs for Agent Kit install.
3
+ * @fileoverview Project-local settings only — never ~/.claude or ~/.codex
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+
11
+ const CLAUDE_REL = '.claude/settings.local.json';
12
+ const CODEX_REL = '.codex/config.toml';
13
+ const IGNORE_COMMENT = '# Host auto-approve (machine-local; aifabrix agent-kit)';
14
+ const IGNORE_LINES = [CLAUDE_REL, CODEX_REL];
15
+
16
+ /**
17
+ * This workspace for writes. Read(~/**) is home-anchored. Bash(aifabrix *)
18
+ * allows the delivery CLI without granting every shell command.
19
+ * @returns {object}
20
+ */
21
+ function buildClaudeSettings() {
22
+ return {
23
+ permissions: {
24
+ defaultMode: 'bypassPermissions',
25
+ allow: ['Bash(aifabrix *)', 'Read(~/**)']
26
+ }
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Auto-approve tools inside this workspace; do not disable the sandbox.
32
+ * @returns {string}
33
+ */
34
+ function buildCodexConfig() {
35
+ return ['approval_policy = "never"', 'sandbox_mode = "workspace-write"', ''].join('\n');
36
+ }
37
+
38
+ /**
39
+ * @param {string} repoRoot
40
+ * @param {object} fsApi
41
+ * @param {boolean} dryRun
42
+ * @returns {{ path: string, action: string }}
43
+ */
44
+ function ensureGitignore(repoRoot, fsApi, dryRun) {
45
+ const rel = '.gitignore';
46
+ const abs = path.join(repoRoot, rel);
47
+ const existing = fsApi.existsSync(abs) ? fsApi.readFileSync(abs, 'utf8') : '';
48
+ const missing = IGNORE_LINES.filter((line) => !existing.split(/\r?\n/).includes(line));
49
+ if (!missing.length) {
50
+ return { path: rel, action: 'skip' };
51
+ }
52
+ if (dryRun) {
53
+ return { path: rel, action: 'planned' };
54
+ }
55
+ const prefix = existing && !existing.endsWith('\n') ? `${existing}\n` : existing;
56
+ const block = `${prefix}${existing ? '\n' : ''}${IGNORE_COMMENT}\n${missing.join('\n')}\n`;
57
+ fsApi.writeFileSync(abs, block, 'utf8');
58
+ return { path: rel, action: existing ? 'update' : 'create' };
59
+ }
60
+
61
+ /**
62
+ * @param {object} p
63
+ * @returns {{ path: string, action: string }}
64
+ */
65
+ function writeHostFile(p) {
66
+ const { abs, rel, body, dryRun, force, fsApi } = p;
67
+ const exists = fsApi.existsSync(abs);
68
+ if (exists && !force) {
69
+ return { path: rel, action: 'exists' };
70
+ }
71
+ if (dryRun) {
72
+ return { path: rel, action: exists ? 'planned-replace' : 'planned' };
73
+ }
74
+ fsApi.mkdirSync(path.dirname(abs), { recursive: true });
75
+ fsApi.writeFileSync(abs, body, 'utf8');
76
+ return { path: rel, action: exists ? 'replace' : 'create' };
77
+ }
78
+
79
+ /**
80
+ * @param {object} options
81
+ * @returns {object[]}
82
+ */
83
+ function listApproveWrites(options) {
84
+ const writes = [];
85
+ if (options.hosts.includes('claude')) {
86
+ const body = `${JSON.stringify(buildClaudeSettings(), null, 2)}\n`;
87
+ writes.push({ abs: path.join(options.repoRoot, CLAUDE_REL), rel: CLAUDE_REL, body });
88
+ }
89
+ if (options.hosts.includes('codex')) {
90
+ writes.push({
91
+ abs: path.join(options.repoRoot, CODEX_REL),
92
+ rel: CODEX_REL,
93
+ body: buildCodexConfig()
94
+ });
95
+ }
96
+ return writes;
97
+ }
98
+
99
+ /**
100
+ * @param {object} options
101
+ * @returns {{ requested: boolean, files: { path: string, action: string }[] }}
102
+ */
103
+ function writeApproveAllFiles(options) {
104
+ if (!options.approveAll) {
105
+ return { requested: false, files: [] };
106
+ }
107
+ const fsApi = options.fs || fs;
108
+ const ctx = {
109
+ repoRoot: options.repoRoot,
110
+ hosts: options.hosts || [],
111
+ fsApi
112
+ };
113
+ const dryRun = Boolean(options.dryRun);
114
+ const force = Boolean(options.force);
115
+ const files = listApproveWrites(ctx).map((row) =>
116
+ writeHostFile({ ...row, dryRun, force, fsApi })
117
+ );
118
+ if (files.length) {
119
+ files.push(ensureGitignore(options.repoRoot, fsApi, dryRun));
120
+ }
121
+ return { requested: true, files };
122
+ }
123
+
124
+ module.exports = {
125
+ CLAUDE_REL,
126
+ CODEX_REL,
127
+ buildClaudeSettings,
128
+ buildCodexConfig,
129
+ writeApproveAllFiles
130
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * GitHub hosting adapter for agent-kit init / remote create.
3
+ * @fileoverview Uses gh CLI; injectable exec for tests
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { execFileSync } = require('child_process');
9
+
10
+ /**
11
+ * @param {{ execFileSync?: Function }} [options]
12
+ * @returns {{ authenticated: boolean }}
13
+ */
14
+ function getGithubAuthStatus(options = {}) {
15
+ const exec = options.execFileSync || execFileSync;
16
+ try {
17
+ exec('gh', ['auth', 'status'], {
18
+ encoding: 'utf8',
19
+ stdio: ['ignore', 'pipe', 'pipe']
20
+ });
21
+ return { authenticated: true };
22
+ } catch {
23
+ return { authenticated: false };
24
+ }
25
+ }
26
+
27
+ /**
28
+ * @param {object} params
29
+ * @param {string} params.name - repo name (basename)
30
+ * @param {string} [params.org]
31
+ * @param {string} [params.visibility]
32
+ * @param {string} params.cwd
33
+ * @param {boolean} [params.dryRun]
34
+ * @param {Function} [params.execFileSync]
35
+ * @returns {{ provider: string, fullName: string, visibility: string, pushed: boolean }}
36
+ */
37
+ function createGithubRemote(params) {
38
+ const visibility = params.visibility === 'public' ? 'public' : 'private';
39
+ const fullName = params.org ? `${params.org}/${params.name}` : params.name;
40
+ const exec = params.execFileSync || execFileSync;
41
+ if (params.dryRun) {
42
+ return { provider: 'github', fullName, visibility, pushed: false };
43
+ }
44
+ const args = [
45
+ 'repo',
46
+ 'create',
47
+ fullName,
48
+ visibility === 'public' ? '--public' : '--private',
49
+ '--source',
50
+ '.',
51
+ '--remote',
52
+ 'origin',
53
+ '--push'
54
+ ];
55
+ exec('gh', args, {
56
+ cwd: params.cwd,
57
+ encoding: 'utf8',
58
+ stdio: ['ignore', 'pipe', 'pipe']
59
+ });
60
+ return { provider: 'github', fullName, visibility, pushed: true };
61
+ }
62
+
63
+ module.exports = { getGithubAuthStatus, createGithubRemote };