@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,71 @@
1
+ /**
2
+ * Normalize Agent Kit --host values.
3
+ * @fileoverview Host selection for install reporting and adapters
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const ALL_HOSTS = ['cursor', 'codex', 'claude'];
9
+ const HOST_LABELS = {
10
+ cursor: 'Cursor',
11
+ codex: 'Codex',
12
+ claude: 'Claude Code'
13
+ };
14
+
15
+ /**
16
+ * @param {string|string[]} [value]
17
+ * @returns {string[]}
18
+ */
19
+ function normalizeHosts(value) {
20
+ if (Array.isArray(value)) {
21
+ const unique = [...new Set(value.map((h) => String(h || '').trim()).filter(Boolean))];
22
+ if (!unique.length) {
23
+ throw new Error('Invalid --host. Use all, cursor, codex, or claude.');
24
+ }
25
+ if (unique.some((h) => !ALL_HOSTS.includes(h) && h !== 'all')) {
26
+ throw new Error('Invalid --host. Use all, cursor, codex, or claude.');
27
+ }
28
+ if (unique.includes('all') || unique.length === ALL_HOSTS.length) {
29
+ return ALL_HOSTS.slice();
30
+ }
31
+ return unique.filter((h) => ALL_HOSTS.includes(h));
32
+ }
33
+ const host = value || 'all';
34
+ if (host === 'all') {
35
+ return ALL_HOSTS.slice();
36
+ }
37
+ if (host.includes(',')) {
38
+ return normalizeHosts(host.split(',').map((part) => part.trim()));
39
+ }
40
+ if (ALL_HOSTS.includes(host)) {
41
+ return [host];
42
+ }
43
+ throw new Error('Invalid --host. Use all, cursor, codex, or claude.');
44
+ }
45
+
46
+ /**
47
+ * @param {string} host
48
+ * @returns {string}
49
+ */
50
+ function hostLabel(host) {
51
+ return HOST_LABELS[host] || host;
52
+ }
53
+
54
+ /**
55
+ * Install uses --host (default all). Update keeps recorded hosts unless --host is set.
56
+ * @param {object} [options]
57
+ * @param {object|null} [state]
58
+ * @param {'install'|'update'} [mode]
59
+ * @returns {string[]}
60
+ */
61
+ function resolveManagedHosts(options, state, mode) {
62
+ if (options && options.host) {
63
+ return normalizeHosts(options.host);
64
+ }
65
+ if (mode === 'update' && state && Array.isArray(state.hosts) && state.hosts.length) {
66
+ return normalizeHosts(state.hosts);
67
+ }
68
+ return normalizeHosts('all');
69
+ }
70
+
71
+ module.exports = { ALL_HOSTS, HOST_LABELS, normalizeHosts, hostLabel, resolveManagedHosts };
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Agent Kit workspace init and remote-create runners.
3
+ * @fileoverview Skeleton + git + install + optional GitHub remote
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+ const fs = require('../internal/fs-real-sync');
10
+ const { isUnsafeRoot } = require('./repo-guard');
11
+ const { resolveWorkspaceTarget } = require('./workspace-name');
12
+ const { writeWorkspaceSkeleton, isNonEmptyDirectory } = require('./workspace-skeleton');
13
+ const { ensureGitRepository, ensureInitialCommit, hasOriginRemote, isGitRepository } = require('./scm/git');
14
+ const { getGithubAuthStatus, createGithubRemote } = require('./hosting/github');
15
+ const { runInstall } = require('./run');
16
+ const { loadKitPackage } = require('./package-load');
17
+ const { getCliVersion } = require('../utils/installation-log-core');
18
+
19
+ /**
20
+ * @param {string} scm
21
+ * @returns {string}
22
+ */
23
+ function normalizeScm(scm) {
24
+ const value = scm || 'git';
25
+ if (value !== 'git' && value !== 'none') {
26
+ throw new Error('Invalid --scm. Use git or none.');
27
+ }
28
+ return value;
29
+ }
30
+
31
+ /**
32
+ * @param {string} visibility
33
+ * @returns {string}
34
+ */
35
+ function normalizeVisibility(visibility) {
36
+ const value = visibility || 'private';
37
+ if (value !== 'private' && value !== 'public') {
38
+ throw new Error('Invalid --visibility. Use private or public.');
39
+ }
40
+ return value;
41
+ }
42
+
43
+ /**
44
+ * @param {object} options
45
+ * @returns {boolean}
46
+ */
47
+ function wantsRemote(options) {
48
+ if (options.noRemote) {
49
+ return false;
50
+ }
51
+ return Boolean(options.remote);
52
+ }
53
+
54
+ /**
55
+ * @param {string} targetAbs
56
+ * @param {boolean} force
57
+ */
58
+ function assertSafeTarget(targetAbs, force) {
59
+ if (isUnsafeRoot(targetAbs)) {
60
+ throw new Error('Refusing to init the Agent Kit into a filesystem root or home directory.');
61
+ }
62
+ if (isNonEmptyDirectory(targetAbs) && !force) {
63
+ throw new Error(
64
+ `Target is not empty: ${targetAbs}. Use --force to continue, or choose another path.`
65
+ );
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param {object} options
71
+ * @param {boolean} interactive
72
+ */
73
+ function assertRemoteFlags(options, interactive) {
74
+ if (!wantsRemote(options)) {
75
+ return;
76
+ }
77
+ if (!interactive && !options.org) {
78
+ throw new Error('Non-interactive --remote requires --org <owner>.');
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param {object} options
84
+ * @returns {object}
85
+ */
86
+ function checkRemoteAuth(options) {
87
+ const auth = getGithubAuthStatus({ execFileSync: options.execFileSync });
88
+ if (!auth.authenticated) {
89
+ throw new Error(
90
+ 'GitHub authentication required for --remote. Run: gh auth login\n' +
91
+ 'Then retry, or omit --remote and later run: aifabrix agent-kit remote create'
92
+ );
93
+ }
94
+ return auth;
95
+ }
96
+
97
+ /**
98
+ * @param {object} ctx
99
+ * @returns {object|null}
100
+ */
101
+ function maybeCreateRemote(ctx) {
102
+ const { options, targetAbs, workspaceName, dryRun } = ctx;
103
+ if (!wantsRemote(options)) {
104
+ return null;
105
+ }
106
+ checkRemoteAuth(options);
107
+ return createGithubRemote({
108
+ name: workspaceName,
109
+ org: options.org,
110
+ visibility: normalizeVisibility(options.visibility),
111
+ cwd: targetAbs,
112
+ dryRun,
113
+ execFileSync: options.execFileSync
114
+ });
115
+ }
116
+
117
+ /**
118
+ * @param {object} options
119
+ * @returns {object}
120
+ */
121
+ function runInit(options) {
122
+ const cwd = options.cwd || process.cwd();
123
+ const dryRun = Boolean(options.dryRun);
124
+ const scm = normalizeScm(options.scm);
125
+ const interactive =
126
+ typeof options.interactive === 'boolean' ? options.interactive : Boolean(process.stdout.isTTY);
127
+ const { targetAbs, workspaceName } = resolveWorkspaceTarget(options.nameOrPath, cwd);
128
+ assertSafeTarget(targetAbs, Boolean(options.force));
129
+ assertRemoteFlags(options, interactive);
130
+
131
+ const phases = [];
132
+ if (!dryRun) {
133
+ fs.mkdirSync(targetAbs, { recursive: true });
134
+ }
135
+ const skeletonFiles = writeWorkspaceSkeleton(targetAbs, {
136
+ workspaceName,
137
+ license: options.license === 'mit' ? 'mit' : 'none',
138
+ dryRun
139
+ });
140
+ phases.push({ phase: 'skeleton', files: skeletonFiles });
141
+
142
+ let gitResult = { initialized: false, skipped: true };
143
+ if (scm === 'git') {
144
+ gitResult = ensureGitRepository(targetAbs, { dryRun, execFileSync: options.execFileSync });
145
+ phases.push({ phase: 'scm', provider: 'git', ...gitResult });
146
+ } else {
147
+ phases.push({ phase: 'scm', provider: 'none' });
148
+ }
149
+
150
+ const kit = installKitPhase({
151
+ scm,
152
+ dryRun,
153
+ targetAbs,
154
+ host: options.host || 'all',
155
+ approveAll: Boolean(options.approveAll),
156
+ force: Boolean(options.force),
157
+ gitResult,
158
+ phases
159
+ });
160
+
161
+ const remote = remotePhase({ options, targetAbs, workspaceName, dryRun, phases });
162
+
163
+ return buildInitReport({
164
+ dryRun,
165
+ targetAbs,
166
+ workspaceName,
167
+ scm,
168
+ kit,
169
+ remote,
170
+ phases
171
+ });
172
+ }
173
+
174
+ /**
175
+ * @param {object} p
176
+ * @returns {object|null}
177
+ */
178
+ function installKitPhase(p) {
179
+ if (p.scm !== 'git') {
180
+ return null;
181
+ }
182
+ if (p.dryRun) {
183
+ const kitPkg = loadKitPackage();
184
+ const skills = (kitPkg.manifest.skills || []).length;
185
+ p.phases.push({ phase: 'agent-kit', planned: true });
186
+ return {
187
+ state: 'CURRENT',
188
+ kitVersion: kitPkg.manifest.kitVersion,
189
+ skills: { expected: skills, installed: 0 }
190
+ };
191
+ }
192
+ if (!isGitRepository(p.targetAbs) && !p.gitResult.initialized) {
193
+ return null;
194
+ }
195
+ const kit = runInstall({
196
+ cwd: p.targetAbs,
197
+ host: p.host,
198
+ approveAll: Boolean(p.approveAll),
199
+ force: Boolean(p.force)
200
+ });
201
+ p.phases.push({ phase: 'agent-kit', state: kit.state });
202
+ return kit;
203
+ }
204
+
205
+ /**
206
+ * @param {object} p
207
+ * @returns {object|null}
208
+ */
209
+ function remotePhase(p) {
210
+ if (!wantsRemote(p.options)) {
211
+ p.phases.push({
212
+ phase: 'remote',
213
+ skipped: true,
214
+ hint: 'aifabrix agent-kit remote create'
215
+ });
216
+ return null;
217
+ }
218
+ const commit = ensureInitialCommit(p.targetAbs, {
219
+ dryRun: p.dryRun,
220
+ execFileSync: p.options.execFileSync
221
+ });
222
+ p.phases.push({ phase: 'commit', ...commit });
223
+ const remote = maybeCreateRemote(p);
224
+ p.phases.push({ phase: 'remote', ...remote });
225
+ return remote;
226
+ }
227
+
228
+ /**
229
+ * @param {object} p
230
+ * @returns {object}
231
+ */
232
+ function buildInitReport(p) {
233
+ return {
234
+ success: true,
235
+ command: 'init',
236
+ dryRun: p.dryRun,
237
+ path: p.targetAbs,
238
+ name: p.workspaceName,
239
+ scm: p.scm,
240
+ hosts: p.kit && p.kit.hosts ? p.kit.hosts : undefined,
241
+ remote: p.remote,
242
+ builderVersion: getCliVersion(),
243
+ kit: p.kit
244
+ ? {
245
+ state: p.kit.state,
246
+ kitVersion: p.kit.kitVersion,
247
+ skills: p.kit.skills
248
+ }
249
+ : null,
250
+ phases: p.phases
251
+ };
252
+ }
253
+
254
+ /**
255
+ * @param {object} options
256
+ * @returns {object}
257
+ */
258
+ function runRemoteCreate(options) {
259
+ const cwd = options.cwd || process.cwd();
260
+ const dryRun = Boolean(options.dryRun);
261
+ const interactive =
262
+ typeof options.interactive === 'boolean' ? options.interactive : Boolean(process.stdout.isTTY);
263
+ const targetAbs = path.resolve(cwd);
264
+ if (isUnsafeRoot(targetAbs)) {
265
+ throw new Error(
266
+ 'Run remote create from inside the workspace (for example: cd ~/cust-demo && aifabrix agent-kit remote create).'
267
+ );
268
+ }
269
+ if (!isGitRepository(targetAbs)) {
270
+ throw new Error(
271
+ 'remote create requires a git repository. cd into the workspace, then run: aifabrix agent-kit remote create'
272
+ );
273
+ }
274
+ if (hasOriginRemote(targetAbs, { execFileSync: options.execFileSync })) {
275
+ return {
276
+ success: true,
277
+ command: 'remote-create',
278
+ dryRun,
279
+ path: targetAbs,
280
+ remote: { provider: 'github', skipped: true, reason: 'origin-exists' },
281
+ builderVersion: getCliVersion()
282
+ };
283
+ }
284
+ if (!interactive && !options.org) {
285
+ throw new Error('Non-interactive remote create requires --org <owner>.');
286
+ }
287
+ checkRemoteAuth(options);
288
+ const commit = ensureInitialCommit(targetAbs, {
289
+ dryRun,
290
+ execFileSync: options.execFileSync
291
+ });
292
+ const name = options.name || path.basename(targetAbs);
293
+ const remote = createGithubRemote({
294
+ name,
295
+ org: options.org,
296
+ visibility: normalizeVisibility(options.visibility),
297
+ cwd: targetAbs,
298
+ dryRun,
299
+ execFileSync: options.execFileSync
300
+ });
301
+ return {
302
+ success: true,
303
+ command: 'remote-create',
304
+ dryRun,
305
+ path: targetAbs,
306
+ name,
307
+ commit,
308
+ remote,
309
+ builderVersion: getCliVersion()
310
+ };
311
+ }
312
+
313
+ module.exports = {
314
+ runInit,
315
+ runRemoteCreate,
316
+ normalizeScm,
317
+ normalizeVisibility,
318
+ wantsRemote
319
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Resolve the bundled Agent Kit template root.
3
+ * @fileoverview Path to templates/agent-kit
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const path = require('path');
9
+
10
+ /**
11
+ * @returns {string}
12
+ */
13
+ function getKitRoot() {
14
+ return path.join(__dirname, '..', '..', 'templates', 'agent-kit');
15
+ }
16
+
17
+ module.exports = { getKitRoot };
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Managed-section markers for kit-owned markdown (AGENTS.md, CLAUDE.md).
3
+ * @fileoverview Extract, append, and replace kit-owned sections
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { BEGIN_MARKER, END_MARKER } = require('./constants');
9
+
10
+ /**
11
+ * @param {string} body
12
+ * @returns {string}
13
+ */
14
+ function wrapSection(body) {
15
+ const trimmed = String(body || '').replace(/^\n+|\n+$/g, '');
16
+ return `${BEGIN_MARKER}\n${trimmed}\n${END_MARKER}\n`;
17
+ }
18
+
19
+ /**
20
+ * @param {string} text
21
+ * @returns {string|null}
22
+ */
23
+ function extractSection(text) {
24
+ const start = text.indexOf(BEGIN_MARKER);
25
+ const end = text.indexOf(END_MARKER);
26
+ if (start < 0 || end < 0 || end <= start) {
27
+ return null;
28
+ }
29
+ return text.slice(start + BEGIN_MARKER.length, end).replace(/^\n+|\n+$/g, '');
30
+ }
31
+
32
+ /**
33
+ * @param {string} text
34
+ * @returns {boolean}
35
+ */
36
+ function hasManagedSection(text) {
37
+ return extractSection(text) !== null;
38
+ }
39
+
40
+ /**
41
+ * Append a managed section; leave existing bytes unchanged.
42
+ * @param {string} text
43
+ * @param {string} body
44
+ * @returns {string}
45
+ */
46
+ function appendManagedSection(text, body) {
47
+ const wrapped = wrapSection(body);
48
+ if (!text) {
49
+ return wrapped;
50
+ }
51
+ const prefix = text.endsWith('\n') ? text : `${text}\n`;
52
+ return `${prefix}\n${wrapped}`;
53
+ }
54
+
55
+ /**
56
+ * Replace only the marked section. Unmarked prose stays byte-identical.
57
+ * @param {string} text
58
+ * @param {string} body
59
+ * @returns {string}
60
+ */
61
+ function replaceManagedSection(text, body) {
62
+ if (!hasManagedSection(text)) {
63
+ return appendManagedSection(text, body);
64
+ }
65
+ const start = text.indexOf(BEGIN_MARKER);
66
+ const end = text.indexOf(END_MARKER) + END_MARKER.length;
67
+ const after = text.slice(end);
68
+ const wrapped = wrapSection(body).replace(/\n$/, '');
69
+ const suffix = after.startsWith('\n') || after.length === 0 ? after : `\n${after}`;
70
+ return `${text.slice(0, start)}${wrapped}${suffix}`;
71
+ }
72
+
73
+ module.exports = {
74
+ wrapSection,
75
+ extractSection,
76
+ hasManagedSection,
77
+ appendManagedSection,
78
+ replaceManagedSection
79
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Load bundled Agent Kit package manifest and inventory.
3
+ * @fileoverview Read templates/agent-kit YAML contracts
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 { getKitRoot } = require('./kit-root');
12
+
13
+ /**
14
+ * @param {string} relativeName
15
+ * @returns {object}
16
+ */
17
+ function loadYamlFromKit(relativeName) {
18
+ const filePath = path.join(getKitRoot(), relativeName);
19
+ const raw = fs.readFileSync(filePath, 'utf8');
20
+ const parsed = yaml.load(raw);
21
+ if (!parsed || typeof parsed !== 'object') {
22
+ throw new Error(`Invalid Agent Kit file: ${relativeName} (${typeof raw})`);
23
+ }
24
+ return parsed;
25
+ }
26
+
27
+ /**
28
+ * @returns {object}
29
+ */
30
+ function loadKitPackage() {
31
+ const manifest = loadYamlFromKit('agent-kit.yaml');
32
+ if (manifest.schemaVersion !== '1' || !manifest.kitVersion) {
33
+ throw new Error('agent-kit.yaml must declare schemaVersion 1 and kitVersion.');
34
+ }
35
+ if (!Array.isArray(manifest.skills) || manifest.skills.length !== 4) {
36
+ throw new Error('agent-kit.yaml must list exactly four skills.');
37
+ }
38
+ return {
39
+ root: getKitRoot(),
40
+ manifest,
41
+ inventory: loadYamlFromKit('parity-inventory.yaml')
42
+ };
43
+ }
44
+
45
+ module.exports = { loadKitPackage, loadYamlFromKit };
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Map file classification to install/update actions.
3
+ * @fileoverview Agent Kit action planner
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { ACTION, FILE_STATE } = require('./constants');
9
+
10
+ /**
11
+ * @param {object} item
12
+ * @param {boolean} force
13
+ * @returns {string}
14
+ */
15
+ function actionForInstall(item, force) {
16
+ if (item.mode === 'if-missing') {
17
+ return item.fileState === FILE_STATE.MISSING ? ACTION.CREATE : ACTION.SKIP;
18
+ }
19
+ if (item.replaceOnInstall) {
20
+ return ACTION.REPLACE;
21
+ }
22
+ const fileState = item.fileState;
23
+ if (fileState === FILE_STATE.MISSING) {
24
+ return ACTION.CREATE;
25
+ }
26
+ if (fileState === FILE_STATE.UNCHANGED_MANAGED) {
27
+ return ACTION.SKIP;
28
+ }
29
+ if (fileState === FILE_STATE.USER_FILE_NO_MANAGED_SECTION) {
30
+ return ACTION.APPEND_SECTION;
31
+ }
32
+ if (fileState === FILE_STATE.MODIFIED_MANAGED) {
33
+ return force ? ACTION.REPLACE : ACTION.CONFLICT;
34
+ }
35
+ if (fileState === FILE_STATE.OBSOLETE_UNCHANGED_MANAGED) {
36
+ return ACTION.DELETE;
37
+ }
38
+ if (fileState === FILE_STATE.OBSOLETE_MODIFIED_MANAGED) {
39
+ return ACTION.RETAIN;
40
+ }
41
+ return ACTION.SKIP;
42
+ }
43
+
44
+ /**
45
+ * @param {object} item
46
+ * @param {boolean} force
47
+ * @returns {string}
48
+ */
49
+ function actionForUpdate(item, force) {
50
+ if (item.mode === 'if-missing') {
51
+ return item.fileState === FILE_STATE.MISSING ? ACTION.CREATE : ACTION.SKIP;
52
+ }
53
+ if (item.fileState === FILE_STATE.UNCHANGED_MANAGED) {
54
+ return ACTION.REPLACE;
55
+ }
56
+ return actionForInstall({ ...item, replaceOnInstall: item.replaceOnInstall }, force);
57
+ }
58
+
59
+ /**
60
+ * @param {object[]} items
61
+ * @param {(item: object, force: boolean) => string} picker
62
+ * @param {boolean} force
63
+ * @returns {object[]}
64
+ */
65
+ function assignActions(items, picker, force) {
66
+ return items.map((item) => ({ ...item, action: picker(item, force) }));
67
+ }
68
+
69
+ module.exports = { actionForInstall, actionForUpdate, assignActions };