@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.
- package/README.md +8 -0
- package/lib/agent-kit/apply-ops.js +82 -0
- package/lib/agent-kit/checksums.js +28 -0
- package/lib/agent-kit/classify.js +113 -0
- package/lib/agent-kit/claude-shim.js +61 -0
- package/lib/agent-kit/constants.js +55 -0
- package/lib/agent-kit/file-list.js +103 -0
- package/lib/agent-kit/host-approve.js +130 -0
- package/lib/agent-kit/hosting/github.js +63 -0
- package/lib/agent-kit/hosts.js +71 -0
- package/lib/agent-kit/init.js +319 -0
- package/lib/agent-kit/kit-root.js +17 -0
- package/lib/agent-kit/managed-section.js +79 -0
- package/lib/agent-kit/package-load.js +45 -0
- package/lib/agent-kit/plan-ops.js +69 -0
- package/lib/agent-kit/remote-prompts.js +239 -0
- package/lib/agent-kit/render-host-markdown.js +40 -0
- package/lib/agent-kit/repo-guard.js +47 -0
- package/lib/agent-kit/report.js +107 -0
- package/lib/agent-kit/run.js +82 -0
- package/lib/agent-kit/scm/git.js +122 -0
- package/lib/agent-kit/state-file.js +83 -0
- package/lib/agent-kit/status.js +50 -0
- package/lib/agent-kit/v1-detect.js +81 -0
- package/lib/agent-kit/validate-kit.js +87 -0
- package/lib/agent-kit/workspace-name.js +40 -0
- package/lib/agent-kit/workspace-skeleton.js +103 -0
- package/lib/api/role-assistant-test-pack.api.js +86 -0
- package/lib/api/work-search.api.js +31 -4
- package/lib/api/work.api.js +19 -12
- package/lib/app/list-external-systems.js +2 -1
- package/lib/app/show-display.js +33 -6
- package/lib/app/show.js +25 -2
- package/lib/channels/add-channel.js +1 -0
- package/lib/channels/approval-guides/claude.js +2 -2
- package/lib/channels/channel-add-failure.js +1 -0
- package/lib/channels/channel-add-remaining.js +15 -9
- package/lib/channels/channel-definition-status.js +115 -0
- package/lib/channels/channel-description.js +2 -1
- package/lib/channels/channel-install-envelope.js +4 -2
- package/lib/channels/channel-integration-generator.js +2 -0
- package/lib/channels/channel-runtime-resolver.js +14 -0
- package/lib/channels/channel-targets.js +31 -5
- package/lib/channels/claude-setup-values.js +4 -1
- package/lib/channels/slack-channel-add.js +59 -6
- package/lib/channels/slack-mcp-callback.js +51 -0
- package/lib/channels/slack-mcp-runtime.js +156 -0
- package/lib/channels/slack-provisioning/install-cli.js +14 -2
- package/lib/channels/slack-provisioning/with-curl-on-path.js +6 -1
- package/lib/cli/index.js +4 -0
- package/lib/cli/setup-certification-commands.js +2 -2
- package/lib/cli/setup-certification.help.js +3 -1
- package/lib/commands/agent-kit-help.js +79 -0
- package/lib/commands/agent-kit.js +346 -0
- package/lib/commands/channel-add-help.js +5 -5
- package/lib/commands/datasource-capability-relate-cli.js +5 -4
- package/lib/commands/repair-auth-apply.js +1 -1
- package/lib/commands/repair-datasource-key-skip.js +39 -0
- package/lib/commands/repair-datasource-keys.js +24 -12
- package/lib/commands/repair-rbac.js +16 -10
- package/lib/commands/role-assistant-copy-output.js +61 -0
- package/lib/commands/role-assistant-copy.js +155 -0
- package/lib/commands/role-assistant-test-output.js +8 -9
- package/lib/commands/role-assistant-test-result-rows.js +42 -0
- package/lib/commands/role-assistant.js +117 -48
- package/lib/commands/search.js +143 -0
- package/lib/commands/test-trust-external.js +7 -5
- package/lib/commands/upload-sidecar-followups.js +4 -1
- package/lib/commands/verify-operations-skip-e2e.js +131 -0
- package/lib/commands/verify-operations-step-plan.js +6 -33
- package/lib/commands/verify-operations-steps.js +3 -1
- package/lib/datasource/capability/relate-operations.js +28 -10
- package/lib/datasource/capability/run-capability-relate.js +48 -25
- package/lib/datasource/datasource-identifier.js +13 -5
- package/lib/deployment/deployer-poll-run.js +117 -35
- package/lib/external-system/deploy-dataplane-published.js +70 -0
- package/lib/external-system/deploy.js +12 -2
- package/lib/external-system/download-role-assistant.js +41 -15
- package/lib/external-system/download.js +7 -1
- package/lib/generator/wizard-datasource-key.js +54 -0
- package/lib/generator/wizard.js +55 -54
- package/lib/integration-definition/apply-datasource-keys.js +75 -0
- package/lib/integration-definition/apply-relationships.js +195 -0
- package/lib/integration-definition/apply-static-enterprise.js +229 -0
- package/lib/integration-definition/apply-system-file.js +71 -0
- package/lib/integration-definition/apply-test-endpoint.js +89 -0
- package/lib/integration-definition/apply-viewpoint-defaults.js +157 -0
- package/lib/integration-definition/apply.js +78 -59
- package/lib/integration-definition/enrich-openapi-operations.js +36 -10
- package/lib/integration-definition/enrich-openapi-pick.js +87 -0
- package/lib/lifecycle/role-assistant-governance.js +56 -21
- package/lib/programmatic/capability-registry.js +1 -0
- package/lib/programmatic/index.js +2 -0
- package/lib/programmatic/openapi-apply-result-schemas.js +8 -0
- package/lib/programmatic/openapi-channel-install-schemas.js +4 -1
- package/lib/programmatic/openapi-component-schemas.js +1 -0
- package/lib/programmatic/openapi-descriptions.js +9 -3
- package/lib/programmatic/openapi-envelope-examples.js +7 -0
- package/lib/programmatic/openapi-operation-bindings.js +5 -0
- package/lib/programmatic/openapi-request-schemas.js +5 -0
- package/lib/programmatic/openapi-schema-descriptions-channel.js +8 -5
- package/lib/programmatic/openapi-schema-descriptions-operations.js +19 -0
- package/lib/programmatic/openapi-spec.js +1 -0
- package/lib/programmatic/request-timeout.js +3 -0
- package/lib/programmatic/route-handler-map.js +7 -0
- package/lib/programmatic/run-channel-catalog.js +50 -8
- package/lib/programmatic/run-channel-install-options.js +5 -1
- package/lib/programmatic/run-download.js +41 -0
- package/lib/protection/auth-context.js +3 -1
- package/lib/protection/protection-display.js +3 -2
- package/lib/protection/report-exit.js +50 -0
- package/lib/protection/run-commands.js +2 -0
- package/lib/role-assistant/package-validate.js +175 -0
- package/lib/role-assistant/test-case-assertion-row.js +36 -0
- package/lib/role-assistant/test-case-copy-bind.js +77 -0
- package/lib/role-assistant/test-case-copy-expected.js +127 -0
- package/lib/role-assistant/test-case-copy-from-work.js +90 -0
- package/lib/role-assistant/test-case-copy-interactions.js +67 -0
- package/lib/role-assistant/test-case-copy.js +119 -0
- package/lib/role-assistant/test-case-expected-catalog.js +135 -0
- package/lib/role-assistant/test-case-validate.js +88 -0
- package/lib/role-assistant/test-cases-bid.js +117 -4
- package/lib/role-assistant/test-cases-evaluate.js +137 -30
- package/lib/role-assistant/test-cases-honesty.js +155 -6
- package/lib/role-assistant/test-cases-lifecycle.js +291 -0
- package/lib/role-assistant/test-cases-search-graph.js +122 -0
- package/lib/role-assistant/test-cases-search.js +20 -2
- package/lib/role-assistant/test-cases.js +34 -168
- package/lib/role-assistant/test-pack-map.js +180 -0
- package/lib/role-assistant/test-pack-sync.js +187 -0
- package/lib/role-assistant/test-runner-debug.js +54 -0
- package/lib/role-assistant/test-runner-respond-body.js +36 -0
- package/lib/role-assistant/test-runner-search.js +20 -5
- package/lib/role-assistant/test-runner-start-payload.js +63 -10
- package/lib/role-assistant/test-runner-workhub-answers.js +45 -16
- package/lib/role-assistant/test-runner-workhub.js +45 -21
- package/lib/role-assistant/test-runner.js +50 -10
- package/lib/schema/external-datasource.schema.json +36 -5
- package/lib/schema/external-system.schema.json +20 -2
- package/lib/schema/role-assistant-test-case.schema.json +408 -0
- package/lib/search/dataplane-context.js +23 -0
- package/lib/search/search-args.js +211 -0
- package/lib/search/search-display.js +238 -0
- package/lib/search/search-errors.js +50 -0
- package/lib/search/search-prompts.js +119 -0
- package/lib/search/search-roles.js +85 -0
- package/lib/search/search-run.js +241 -0
- package/lib/search/search-skills.js +198 -0
- package/lib/utils/authentication-slot-show.js +153 -0
- package/lib/utils/credential-display.js +43 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +5 -1
- package/lib/utils/external-system-readiness-compact-display.js +30 -1
- package/lib/utils/external-system-validators.js +2 -1
- package/lib/utils/help-builder.js +3 -1
- package/lib/utils/schema-loader.js +37 -0
- package/lib/validation/validate-external-file.js +5 -1
- package/lib/validation/validate.js +3 -2
- package/package.json +1 -1
- package/templates/agent-kit/adapters/claude/nested.CLAUDE.md +1 -0
- package/templates/agent-kit/adapters/claude/root.CLAUDE.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-0-plan.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-1-validate.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-2-build.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-3-push.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-1-validate.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-2-build.md +5 -0
- package/templates/agent-kit/adapters/cursor/commands/cust-biz-3-prove.md +5 -0
- package/templates/agent-kit/agent-kit.yaml +45 -0
- package/templates/agent-kit/instructions/AGENTKIT.md +83 -0
- package/templates/agent-kit/instructions/integration.AGENTS.md +25 -0
- package/templates/agent-kit/instructions/role-assistant.AGENTS.md +22 -0
- package/templates/agent-kit/instructions/root.AGENTS.md +37 -0
- package/templates/agent-kit/parity-inventory.yaml +188 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +58 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/contract-checklist.md +40 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +54 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/references/production-safety.md +35 -0
- package/templates/agent-kit/skills/aifabrix-connected-system/scripts/reserved-system-key.js +19 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +51 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/challenge-checklist.md +108 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +34 -0
- package/templates/agent-kit/skills/aifabrix-plan/references/plan-template.md +182 -0
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +50 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/demo-template.md +65 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +68 -0
- package/templates/agent-kit/skills/aifabrix-prove/references/learning-template.md +66 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +42 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/package-boundary.md +21 -0
- package/templates/agent-kit/skills/shared/hosts.md +78 -0
- package/templates/agent-kit/workspace/.cursor/plans/README.md +22 -0
- package/templates/agent-kit/workspace/LICENSE.mit +21 -0
- package/templates/agent-kit/workspace/README.md +89 -0
- package/templates/applications/builder-api/Dockerfile +3 -1
- package/templates/applications/dataplane/application.yaml +2 -2
- package/templates/applications/dataplane/env.template +1 -1
- package/templates/applications/dataplane/rbac.yaml +28 -0
- package/templates/applications/keycloak/env.template +3 -3
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +8 -9
- package/templates/channels/claude/TROUBLESHOOTING.md +3 -0
- package/templates/channels/claude/channel.json +1 -1
- package/templates/channels/claude/install.template.md.hbs +1 -0
- package/templates/channels/claude/integration/claude-system.json +1 -1
- package/templates/channels/slack/channel.json +11 -0
- package/templates/channels/slack/install.template.md.hbs +9 -0
- package/templates/channels/slack/integration/slack-system.json +11 -0
- package/templates/channels/slack/manifest.template.json.hbs +6 -3
- package/templates/channels/teams-bot/channel.json +1 -0
- package/templates/python/docker-compose.hbs +14 -0
- 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 };
|