@renseiai/agentfactory 0.8.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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/config/repository-config.d.ts +44 -0
- package/dist/src/config/repository-config.d.ts.map +1 -0
- package/dist/src/config/repository-config.js +88 -0
- package/dist/src/config/repository-config.test.d.ts +2 -0
- package/dist/src/config/repository-config.test.d.ts.map +1 -0
- package/dist/src/config/repository-config.test.js +249 -0
- package/dist/src/deployment/deployment-checker.d.ts +110 -0
- package/dist/src/deployment/deployment-checker.d.ts.map +1 -0
- package/dist/src/deployment/deployment-checker.js +242 -0
- package/dist/src/deployment/index.d.ts +3 -0
- package/dist/src/deployment/index.d.ts.map +1 -0
- package/dist/src/deployment/index.js +2 -0
- package/dist/src/frontend/index.d.ts +2 -0
- package/dist/src/frontend/index.d.ts.map +1 -0
- package/dist/src/frontend/index.js +1 -0
- package/dist/src/frontend/types.d.ts +106 -0
- package/dist/src/frontend/types.d.ts.map +1 -0
- package/dist/src/frontend/types.js +11 -0
- package/dist/src/governor/decision-engine.d.ts +52 -0
- package/dist/src/governor/decision-engine.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.js +220 -0
- package/dist/src/governor/decision-engine.test.d.ts +2 -0
- package/dist/src/governor/decision-engine.test.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.test.js +629 -0
- package/dist/src/governor/event-bus.d.ts +43 -0
- package/dist/src/governor/event-bus.d.ts.map +1 -0
- package/dist/src/governor/event-bus.js +8 -0
- package/dist/src/governor/event-deduplicator.d.ts +43 -0
- package/dist/src/governor/event-deduplicator.d.ts.map +1 -0
- package/dist/src/governor/event-deduplicator.js +53 -0
- package/dist/src/governor/event-driven-governor.d.ts +131 -0
- package/dist/src/governor/event-driven-governor.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.js +379 -0
- package/dist/src/governor/event-driven-governor.test.d.ts +2 -0
- package/dist/src/governor/event-driven-governor.test.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.test.js +673 -0
- package/dist/src/governor/event-types.d.ts +78 -0
- package/dist/src/governor/event-types.d.ts.map +1 -0
- package/dist/src/governor/event-types.js +32 -0
- package/dist/src/governor/governor-types.d.ts +82 -0
- package/dist/src/governor/governor-types.d.ts.map +1 -0
- package/dist/src/governor/governor-types.js +21 -0
- package/dist/src/governor/governor.d.ts +100 -0
- package/dist/src/governor/governor.d.ts.map +1 -0
- package/dist/src/governor/governor.js +262 -0
- package/dist/src/governor/governor.test.d.ts +2 -0
- package/dist/src/governor/governor.test.d.ts.map +1 -0
- package/dist/src/governor/governor.test.js +514 -0
- package/dist/src/governor/human-touchpoints.d.ts +131 -0
- package/dist/src/governor/human-touchpoints.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.js +251 -0
- package/dist/src/governor/human-touchpoints.test.d.ts +2 -0
- package/dist/src/governor/human-touchpoints.test.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.test.js +366 -0
- package/dist/src/governor/in-memory-event-bus.d.ts +29 -0
- package/dist/src/governor/in-memory-event-bus.d.ts.map +1 -0
- package/dist/src/governor/in-memory-event-bus.js +79 -0
- package/dist/src/governor/index.d.ts +14 -0
- package/dist/src/governor/index.d.ts.map +1 -0
- package/dist/src/governor/index.js +13 -0
- package/dist/src/governor/override-parser.d.ts +60 -0
- package/dist/src/governor/override-parser.d.ts.map +1 -0
- package/dist/src/governor/override-parser.js +98 -0
- package/dist/src/governor/override-parser.test.d.ts +2 -0
- package/dist/src/governor/override-parser.test.d.ts.map +1 -0
- package/dist/src/governor/override-parser.test.js +312 -0
- package/dist/src/governor/platform-adapter.d.ts +69 -0
- package/dist/src/governor/platform-adapter.d.ts.map +1 -0
- package/dist/src/governor/platform-adapter.js +11 -0
- package/dist/src/governor/processing-state.d.ts +66 -0
- package/dist/src/governor/processing-state.d.ts.map +1 -0
- package/dist/src/governor/processing-state.js +43 -0
- package/dist/src/governor/processing-state.test.d.ts +2 -0
- package/dist/src/governor/processing-state.test.d.ts.map +1 -0
- package/dist/src/governor/processing-state.test.js +96 -0
- package/dist/src/governor/top-of-funnel.d.ts +118 -0
- package/dist/src/governor/top-of-funnel.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.js +168 -0
- package/dist/src/governor/top-of-funnel.test.d.ts +2 -0
- package/dist/src/governor/top-of-funnel.test.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.test.js +331 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/linear-cli.d.ts +38 -0
- package/dist/src/linear-cli.d.ts.map +1 -0
- package/dist/src/linear-cli.js +674 -0
- package/dist/src/logger.d.ts +117 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +430 -0
- package/dist/src/manifest/generate.d.ts +20 -0
- package/dist/src/manifest/generate.d.ts.map +1 -0
- package/dist/src/manifest/generate.js +65 -0
- package/dist/src/manifest/index.d.ts +4 -0
- package/dist/src/manifest/index.d.ts.map +1 -0
- package/dist/src/manifest/index.js +2 -0
- package/dist/src/manifest/route-manifest.d.ts +34 -0
- package/dist/src/manifest/route-manifest.d.ts.map +1 -0
- package/dist/src/manifest/route-manifest.js +148 -0
- package/dist/src/orchestrator/activity-emitter.d.ts +119 -0
- package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/activity-emitter.js +306 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts +167 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/api-activity-emitter.js +417 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts +57 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts.map +1 -0
- package/dist/src/orchestrator/heartbeat-writer.js +137 -0
- package/dist/src/orchestrator/index.d.ts +20 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -0
- package/dist/src/orchestrator/index.js +22 -0
- package/dist/src/orchestrator/log-analyzer.d.ts +160 -0
- package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -0
- package/dist/src/orchestrator/log-analyzer.js +572 -0
- package/dist/src/orchestrator/log-config.d.ts +39 -0
- package/dist/src/orchestrator/log-config.d.ts.map +1 -0
- package/dist/src/orchestrator/log-config.js +45 -0
- package/dist/src/orchestrator/orchestrator.d.ts +316 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/orchestrator.js +3290 -0
- package/dist/src/orchestrator/parse-work-result.d.ts +16 -0
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.js +135 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts +2 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.test.js +234 -0
- package/dist/src/orchestrator/progress-logger.d.ts +72 -0
- package/dist/src/orchestrator/progress-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/progress-logger.js +135 -0
- package/dist/src/orchestrator/session-logger.d.ts +159 -0
- package/dist/src/orchestrator/session-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/session-logger.js +275 -0
- package/dist/src/orchestrator/state-recovery.d.ts +96 -0
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -0
- package/dist/src/orchestrator/state-recovery.js +302 -0
- package/dist/src/orchestrator/state-types.d.ts +165 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -0
- package/dist/src/orchestrator/state-types.js +7 -0
- package/dist/src/orchestrator/stream-parser.d.ts +151 -0
- package/dist/src/orchestrator/stream-parser.d.ts.map +1 -0
- package/dist/src/orchestrator/stream-parser.js +137 -0
- package/dist/src/orchestrator/types.d.ts +232 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -0
- package/dist/src/orchestrator/types.js +4 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts +2 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts.map +1 -0
- package/dist/src/orchestrator/validate-git-remote.test.js +61 -0
- package/dist/src/providers/a2a-auth.d.ts +81 -0
- package/dist/src/providers/a2a-auth.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.js +188 -0
- package/dist/src/providers/a2a-auth.test.d.ts +2 -0
- package/dist/src/providers/a2a-auth.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.test.js +232 -0
- package/dist/src/providers/a2a-provider.d.ts +254 -0
- package/dist/src/providers/a2a-provider.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts +9 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.js +665 -0
- package/dist/src/providers/a2a-provider.js +811 -0
- package/dist/src/providers/a2a-provider.test.d.ts +2 -0
- package/dist/src/providers/a2a-provider.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.test.js +681 -0
- package/dist/src/providers/amp-provider.d.ts +20 -0
- package/dist/src/providers/amp-provider.d.ts.map +1 -0
- package/dist/src/providers/amp-provider.js +24 -0
- package/dist/src/providers/claude-provider.d.ts +18 -0
- package/dist/src/providers/claude-provider.d.ts.map +1 -0
- package/dist/src/providers/claude-provider.js +437 -0
- package/dist/src/providers/codex-provider.d.ts +133 -0
- package/dist/src/providers/codex-provider.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.js +381 -0
- package/dist/src/providers/codex-provider.test.d.ts +2 -0
- package/dist/src/providers/codex-provider.test.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.test.js +387 -0
- package/dist/src/providers/index.d.ts +44 -0
- package/dist/src/providers/index.d.ts.map +1 -0
- package/dist/src/providers/index.js +85 -0
- package/dist/src/providers/spring-ai-provider.d.ts +90 -0
- package/dist/src/providers/spring-ai-provider.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts +13 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.js +351 -0
- package/dist/src/providers/spring-ai-provider.js +317 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts +2 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.test.js +200 -0
- package/dist/src/providers/types.d.ts +165 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +13 -0
- package/dist/src/templates/adapters.d.ts +51 -0
- package/dist/src/templates/adapters.d.ts.map +1 -0
- package/dist/src/templates/adapters.js +104 -0
- package/dist/src/templates/adapters.test.d.ts +2 -0
- package/dist/src/templates/adapters.test.d.ts.map +1 -0
- package/dist/src/templates/adapters.test.js +165 -0
- package/dist/src/templates/agent-definition.d.ts +85 -0
- package/dist/src/templates/agent-definition.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.js +97 -0
- package/dist/src/templates/agent-definition.test.d.ts +2 -0
- package/dist/src/templates/agent-definition.test.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.test.js +209 -0
- package/dist/src/templates/index.d.ts +14 -0
- package/dist/src/templates/index.d.ts.map +1 -0
- package/dist/src/templates/index.js +11 -0
- package/dist/src/templates/loader.d.ts +41 -0
- package/dist/src/templates/loader.d.ts.map +1 -0
- package/dist/src/templates/loader.js +114 -0
- package/dist/src/templates/registry.d.ts +80 -0
- package/dist/src/templates/registry.d.ts.map +1 -0
- package/dist/src/templates/registry.js +177 -0
- package/dist/src/templates/registry.test.d.ts +2 -0
- package/dist/src/templates/registry.test.d.ts.map +1 -0
- package/dist/src/templates/registry.test.js +198 -0
- package/dist/src/templates/renderer.d.ts +29 -0
- package/dist/src/templates/renderer.d.ts.map +1 -0
- package/dist/src/templates/renderer.js +35 -0
- package/dist/src/templates/strategy-templates.test.d.ts +2 -0
- package/dist/src/templates/strategy-templates.test.d.ts.map +1 -0
- package/dist/src/templates/strategy-templates.test.js +619 -0
- package/dist/src/templates/types.d.ts +233 -0
- package/dist/src/templates/types.d.ts.map +1 -0
- package/dist/src/templates/types.js +127 -0
- package/dist/src/templates/types.test.d.ts +2 -0
- package/dist/src/templates/types.test.d.ts.map +1 -0
- package/dist/src/templates/types.test.js +232 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/linear-runner.d.ts +34 -0
- package/dist/src/tools/linear-runner.d.ts.map +1 -0
- package/dist/src/tools/linear-runner.js +700 -0
- package/dist/src/tools/plugins/linear.d.ts +9 -0
- package/dist/src/tools/plugins/linear.d.ts.map +1 -0
- package/dist/src/tools/plugins/linear.js +138 -0
- package/dist/src/tools/registry.d.ts +9 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +18 -0
- package/dist/src/tools/types.d.ts +18 -0
- package/dist/src/tools/types.d.ts.map +1 -0
- package/dist/src/tools/types.js +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ClaudeToolPermissionAdapter, CodexToolPermissionAdapter, SpringAiToolPermissionAdapter, createToolPermissionAdapter, } from './adapters.js';
|
|
3
|
+
describe('ClaudeToolPermissionAdapter', () => {
|
|
4
|
+
const adapter = new ClaudeToolPermissionAdapter();
|
|
5
|
+
it('translates shell command with glob', () => {
|
|
6
|
+
const result = adapter.translatePermissions([{ shell: 'pnpm *' }]);
|
|
7
|
+
expect(result).toEqual(['Bash(pnpm:*)']);
|
|
8
|
+
});
|
|
9
|
+
it('translates multi-word shell command', () => {
|
|
10
|
+
const result = adapter.translatePermissions([{ shell: 'git commit *' }]);
|
|
11
|
+
expect(result).toEqual(['Bash(git commit:*)']);
|
|
12
|
+
});
|
|
13
|
+
it('translates git push command', () => {
|
|
14
|
+
const result = adapter.translatePermissions([{ shell: 'git push *' }]);
|
|
15
|
+
expect(result).toEqual(['Bash(git push:*)']);
|
|
16
|
+
});
|
|
17
|
+
it('translates user-input to AskUserQuestion', () => {
|
|
18
|
+
const result = adapter.translatePermissions(['user-input']);
|
|
19
|
+
expect(result).toEqual(['AskUserQuestion']);
|
|
20
|
+
});
|
|
21
|
+
it('passes through other string permissions', () => {
|
|
22
|
+
const result = adapter.translatePermissions(['Read', 'Write']);
|
|
23
|
+
expect(result).toEqual(['Read', 'Write']);
|
|
24
|
+
});
|
|
25
|
+
it('translates single-word shell command', () => {
|
|
26
|
+
const result = adapter.translatePermissions([{ shell: 'ls' }]);
|
|
27
|
+
expect(result).toEqual(['Bash(ls:*)']);
|
|
28
|
+
});
|
|
29
|
+
it('handles mixed permissions', () => {
|
|
30
|
+
const result = adapter.translatePermissions([
|
|
31
|
+
{ shell: 'pnpm *' },
|
|
32
|
+
'user-input',
|
|
33
|
+
{ shell: 'gh pr *' },
|
|
34
|
+
]);
|
|
35
|
+
expect(result).toEqual([
|
|
36
|
+
'Bash(pnpm:*)',
|
|
37
|
+
'AskUserQuestion',
|
|
38
|
+
'Bash(gh pr:*)',
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('CodexToolPermissionAdapter', () => {
|
|
43
|
+
const adapter = new CodexToolPermissionAdapter();
|
|
44
|
+
it('translates shell command to shell: prefix format', () => {
|
|
45
|
+
const result = adapter.translatePermissions([{ shell: 'pnpm *' }]);
|
|
46
|
+
expect(result).toEqual(['shell:pnpm *']);
|
|
47
|
+
});
|
|
48
|
+
it('translates multi-word shell command', () => {
|
|
49
|
+
const result = adapter.translatePermissions([{ shell: 'git commit *' }]);
|
|
50
|
+
expect(result).toEqual(['shell:git commit *']);
|
|
51
|
+
});
|
|
52
|
+
it('passes through user-input as-is (Codex exec is non-interactive)', () => {
|
|
53
|
+
const result = adapter.translatePermissions(['user-input']);
|
|
54
|
+
expect(result).toEqual(['user-input']);
|
|
55
|
+
});
|
|
56
|
+
it('passes through other string permissions as-is', () => {
|
|
57
|
+
const result = adapter.translatePermissions(['Read', 'Write']);
|
|
58
|
+
expect(result).toEqual(['Read', 'Write']);
|
|
59
|
+
});
|
|
60
|
+
it('translates single-word shell command', () => {
|
|
61
|
+
const result = adapter.translatePermissions([{ shell: 'ls' }]);
|
|
62
|
+
expect(result).toEqual(['shell:ls']);
|
|
63
|
+
});
|
|
64
|
+
it('handles mixed permissions', () => {
|
|
65
|
+
const result = adapter.translatePermissions([
|
|
66
|
+
{ shell: 'pnpm *' },
|
|
67
|
+
'user-input',
|
|
68
|
+
{ shell: 'gh pr *' },
|
|
69
|
+
]);
|
|
70
|
+
expect(result).toEqual([
|
|
71
|
+
'shell:pnpm *',
|
|
72
|
+
'user-input',
|
|
73
|
+
'shell:gh pr *',
|
|
74
|
+
]);
|
|
75
|
+
});
|
|
76
|
+
it('handles empty permissions array', () => {
|
|
77
|
+
const result = adapter.translatePermissions([]);
|
|
78
|
+
expect(result).toEqual([]);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('SpringAiToolPermissionAdapter', () => {
|
|
82
|
+
const adapter = new SpringAiToolPermissionAdapter();
|
|
83
|
+
it('translates shell command to spring-tool format', () => {
|
|
84
|
+
const result = adapter.translatePermissions([{ shell: 'pnpm *' }]);
|
|
85
|
+
expect(result).toEqual(['spring-tool:shell:pnpm *']);
|
|
86
|
+
});
|
|
87
|
+
it('translates multi-word shell command', () => {
|
|
88
|
+
const result = adapter.translatePermissions([{ shell: 'git commit *' }]);
|
|
89
|
+
expect(result).toEqual(['spring-tool:shell:git commit *']);
|
|
90
|
+
});
|
|
91
|
+
it('passes through user-input as-is (Spring AI agent is non-interactive)', () => {
|
|
92
|
+
const result = adapter.translatePermissions(['user-input']);
|
|
93
|
+
expect(result).toEqual(['user-input']);
|
|
94
|
+
});
|
|
95
|
+
it('passes through other string permissions as-is', () => {
|
|
96
|
+
const result = adapter.translatePermissions(['Read', 'Write']);
|
|
97
|
+
expect(result).toEqual(['Read', 'Write']);
|
|
98
|
+
});
|
|
99
|
+
it('translates single-word shell command', () => {
|
|
100
|
+
const result = adapter.translatePermissions([{ shell: 'ls' }]);
|
|
101
|
+
expect(result).toEqual(['spring-tool:shell:ls']);
|
|
102
|
+
});
|
|
103
|
+
it('handles mixed permissions', () => {
|
|
104
|
+
const result = adapter.translatePermissions([
|
|
105
|
+
{ shell: 'pnpm *' },
|
|
106
|
+
'user-input',
|
|
107
|
+
{ shell: 'gh pr *' },
|
|
108
|
+
]);
|
|
109
|
+
expect(result).toEqual([
|
|
110
|
+
'spring-tool:shell:pnpm *',
|
|
111
|
+
'user-input',
|
|
112
|
+
'spring-tool:shell:gh pr *',
|
|
113
|
+
]);
|
|
114
|
+
});
|
|
115
|
+
it('handles empty permissions array', () => {
|
|
116
|
+
const result = adapter.translatePermissions([]);
|
|
117
|
+
expect(result).toEqual([]);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('createToolPermissionAdapter', () => {
|
|
121
|
+
it('returns ClaudeToolPermissionAdapter for claude', () => {
|
|
122
|
+
const adapter = createToolPermissionAdapter('claude');
|
|
123
|
+
expect(adapter).toBeInstanceOf(ClaudeToolPermissionAdapter);
|
|
124
|
+
});
|
|
125
|
+
it('returns CodexToolPermissionAdapter for codex', () => {
|
|
126
|
+
const adapter = createToolPermissionAdapter('codex');
|
|
127
|
+
expect(adapter).toBeInstanceOf(CodexToolPermissionAdapter);
|
|
128
|
+
});
|
|
129
|
+
it('returns ClaudeToolPermissionAdapter for amp (fallback)', () => {
|
|
130
|
+
const adapter = createToolPermissionAdapter('amp');
|
|
131
|
+
expect(adapter).toBeInstanceOf(ClaudeToolPermissionAdapter);
|
|
132
|
+
});
|
|
133
|
+
it('returns SpringAiToolPermissionAdapter for spring-ai', () => {
|
|
134
|
+
const adapter = createToolPermissionAdapter('spring-ai');
|
|
135
|
+
expect(adapter).toBeInstanceOf(SpringAiToolPermissionAdapter);
|
|
136
|
+
});
|
|
137
|
+
it('returns ClaudeToolPermissionAdapter for unknown provider', () => {
|
|
138
|
+
const adapter = createToolPermissionAdapter('unknown');
|
|
139
|
+
expect(adapter).toBeInstanceOf(ClaudeToolPermissionAdapter);
|
|
140
|
+
});
|
|
141
|
+
it('claude and codex adapters produce different output for same input', () => {
|
|
142
|
+
const claudeAdapter = createToolPermissionAdapter('claude');
|
|
143
|
+
const codexAdapter = createToolPermissionAdapter('codex');
|
|
144
|
+
const permissions = [{ shell: 'pnpm *' }];
|
|
145
|
+
const claudeResult = claudeAdapter.translatePermissions([...permissions]);
|
|
146
|
+
const codexResult = codexAdapter.translatePermissions([...permissions]);
|
|
147
|
+
expect(claudeResult).toEqual(['Bash(pnpm:*)']);
|
|
148
|
+
expect(codexResult).toEqual(['shell:pnpm *']);
|
|
149
|
+
expect(claudeResult).not.toEqual(codexResult);
|
|
150
|
+
});
|
|
151
|
+
it('all three provider adapters produce different output for shell permissions', () => {
|
|
152
|
+
const claudeAdapter = createToolPermissionAdapter('claude');
|
|
153
|
+
const codexAdapter = createToolPermissionAdapter('codex');
|
|
154
|
+
const springAiAdapter = createToolPermissionAdapter('spring-ai');
|
|
155
|
+
const permissions = [{ shell: 'pnpm *' }];
|
|
156
|
+
const claudeResult = claudeAdapter.translatePermissions([...permissions]);
|
|
157
|
+
const codexResult = codexAdapter.translatePermissions([...permissions]);
|
|
158
|
+
const springAiResult = springAiAdapter.translatePermissions([...permissions]);
|
|
159
|
+
expect(claudeResult).toEqual(['Bash(pnpm:*)']);
|
|
160
|
+
expect(codexResult).toEqual(['shell:pnpm *']);
|
|
161
|
+
expect(springAiResult).toEqual(['spring-tool:shell:pnpm *']);
|
|
162
|
+
// All three formats are distinct
|
|
163
|
+
expect(new Set([claudeResult[0], codexResult[0], springAiResult[0]]).size).toBe(3);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Definition Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses agent definition markdown files with YAML frontmatter.
|
|
5
|
+
* Supports configurable build/test/CLI commands in frontmatter that
|
|
6
|
+
* can be referenced in the body via Handlebars interpolation.
|
|
7
|
+
*
|
|
8
|
+
* Example frontmatter:
|
|
9
|
+
* ---
|
|
10
|
+
* name: developer
|
|
11
|
+
* description: General-purpose development agent
|
|
12
|
+
* tools: Read, Edit, Write, Grep, Glob, Bash
|
|
13
|
+
* model: opus
|
|
14
|
+
* build_commands:
|
|
15
|
+
* verify: "cmake --build build-arm64/ --target engine-headless"
|
|
16
|
+
* full: "cmake --build build-arm64/ --target engine-legacy"
|
|
17
|
+
* test_commands:
|
|
18
|
+
* unit: "cargo test"
|
|
19
|
+
* integration: "cargo test -- --ignored"
|
|
20
|
+
* af_linear: "bash tools/af-linear.sh"
|
|
21
|
+
* ---
|
|
22
|
+
*/
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
/**
|
|
25
|
+
* Parsed frontmatter from an agent definition markdown file.
|
|
26
|
+
*/
|
|
27
|
+
export interface AgentDefinitionFrontmatter {
|
|
28
|
+
/** Agent name (e.g., "developer", "qa-reviewer") */
|
|
29
|
+
name: string;
|
|
30
|
+
/** When the orchestrator should select this agent */
|
|
31
|
+
description?: string;
|
|
32
|
+
/** Comma-separated list of allowed tools */
|
|
33
|
+
tools?: string;
|
|
34
|
+
/** Model to use (opus, sonnet, haiku) */
|
|
35
|
+
model?: string;
|
|
36
|
+
/** Named build commands (e.g., { verify: "cmake --build ...", full: "make all" }) */
|
|
37
|
+
build_commands?: Record<string, string>;
|
|
38
|
+
/** Named test commands (e.g., { unit: "cargo test", integration: "cargo test -- --ignored" }) */
|
|
39
|
+
test_commands?: Record<string, string>;
|
|
40
|
+
/** Custom Linear CLI command override (e.g., "bash tools/af-linear.sh") */
|
|
41
|
+
af_linear?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Fully parsed agent definition with frontmatter and body.
|
|
45
|
+
*/
|
|
46
|
+
export interface AgentDefinition {
|
|
47
|
+
/** Parsed and validated frontmatter fields */
|
|
48
|
+
frontmatter: AgentDefinitionFrontmatter;
|
|
49
|
+
/** Raw markdown body (after frontmatter) */
|
|
50
|
+
rawBody: string;
|
|
51
|
+
/** Body rendered with frontmatter variables interpolated */
|
|
52
|
+
renderedBody: string;
|
|
53
|
+
}
|
|
54
|
+
export declare const AgentDefinitionFrontmatterSchema: z.ZodObject<{
|
|
55
|
+
name: z.ZodString;
|
|
56
|
+
description: z.ZodOptional<z.ZodString>;
|
|
57
|
+
tools: z.ZodOptional<z.ZodString>;
|
|
58
|
+
model: z.ZodOptional<z.ZodEnum<{
|
|
59
|
+
opus: "opus";
|
|
60
|
+
sonnet: "sonnet";
|
|
61
|
+
haiku: "haiku";
|
|
62
|
+
}>>;
|
|
63
|
+
build_commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
64
|
+
test_commands: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
65
|
+
af_linear: z.ZodOptional<z.ZodString>;
|
|
66
|
+
}, z.core.$strip>;
|
|
67
|
+
/**
|
|
68
|
+
* Parse a markdown string with YAML frontmatter into an AgentDefinition.
|
|
69
|
+
*
|
|
70
|
+
* The body supports Handlebars interpolation for frontmatter fields:
|
|
71
|
+
* - {{build_commands.verify}} → the "verify" build command
|
|
72
|
+
* - {{test_commands.unit}} → the "unit" test command
|
|
73
|
+
* - {{af_linear}} → the Linear CLI override
|
|
74
|
+
* - {{name}}, {{description}}, {{model}} → basic fields
|
|
75
|
+
*
|
|
76
|
+
* @throws {Error} If frontmatter is malformed or fails validation
|
|
77
|
+
*/
|
|
78
|
+
export declare function parseAgentDefinition(content: string): AgentDefinition;
|
|
79
|
+
/**
|
|
80
|
+
* Parse an agent definition from a file path.
|
|
81
|
+
*
|
|
82
|
+
* @throws {Error} If file cannot be read or parsed
|
|
83
|
+
*/
|
|
84
|
+
export declare function parseAgentDefinitionFile(filePath: string): AgentDefinition;
|
|
85
|
+
//# sourceMappingURL=agent-definition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-definition.d.ts","sourceRoot":"","sources":["../../../src/templates/agent-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAOvB;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,iGAAiG;IACjG,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,WAAW,EAAE,0BAA0B,CAAA;IACvC,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,YAAY,EAAE,MAAM,CAAA;CACrB;AAMD,eAAO,MAAM,gCAAgC;;;;;;;;;;;;iBAQ3C,CAAA;AAQF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAcrE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAQ1E"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Definition Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses agent definition markdown files with YAML frontmatter.
|
|
5
|
+
* Supports configurable build/test/CLI commands in frontmatter that
|
|
6
|
+
* can be referenced in the body via Handlebars interpolation.
|
|
7
|
+
*
|
|
8
|
+
* Example frontmatter:
|
|
9
|
+
* ---
|
|
10
|
+
* name: developer
|
|
11
|
+
* description: General-purpose development agent
|
|
12
|
+
* tools: Read, Edit, Write, Grep, Glob, Bash
|
|
13
|
+
* model: opus
|
|
14
|
+
* build_commands:
|
|
15
|
+
* verify: "cmake --build build-arm64/ --target engine-headless"
|
|
16
|
+
* full: "cmake --build build-arm64/ --target engine-legacy"
|
|
17
|
+
* test_commands:
|
|
18
|
+
* unit: "cargo test"
|
|
19
|
+
* integration: "cargo test -- --ignored"
|
|
20
|
+
* af_linear: "bash tools/af-linear.sh"
|
|
21
|
+
* ---
|
|
22
|
+
*/
|
|
23
|
+
import fs from 'node:fs';
|
|
24
|
+
import { parse as parseYaml } from 'yaml';
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import Handlebars from 'handlebars';
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Zod Schema
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
export const AgentDefinitionFrontmatterSchema = z.object({
|
|
31
|
+
name: z.string().min(1),
|
|
32
|
+
description: z.string().optional(),
|
|
33
|
+
tools: z.string().optional(),
|
|
34
|
+
model: z.enum(['opus', 'sonnet', 'haiku']).optional(),
|
|
35
|
+
build_commands: z.record(z.string(), z.string()).optional(),
|
|
36
|
+
test_commands: z.record(z.string(), z.string()).optional(),
|
|
37
|
+
af_linear: z.string().optional(),
|
|
38
|
+
});
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Parser
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
43
|
+
/**
|
|
44
|
+
* Parse a markdown string with YAML frontmatter into an AgentDefinition.
|
|
45
|
+
*
|
|
46
|
+
* The body supports Handlebars interpolation for frontmatter fields:
|
|
47
|
+
* - {{build_commands.verify}} → the "verify" build command
|
|
48
|
+
* - {{test_commands.unit}} → the "unit" test command
|
|
49
|
+
* - {{af_linear}} → the Linear CLI override
|
|
50
|
+
* - {{name}}, {{description}}, {{model}} → basic fields
|
|
51
|
+
*
|
|
52
|
+
* @throws {Error} If frontmatter is malformed or fails validation
|
|
53
|
+
*/
|
|
54
|
+
export function parseAgentDefinition(content) {
|
|
55
|
+
const match = content.match(FRONTMATTER_RE);
|
|
56
|
+
if (!match) {
|
|
57
|
+
throw new Error('Agent definition must start with YAML frontmatter delimited by ---');
|
|
58
|
+
}
|
|
59
|
+
const [, yamlBlock, body] = match;
|
|
60
|
+
const parsed = parseYaml(yamlBlock);
|
|
61
|
+
const frontmatter = AgentDefinitionFrontmatterSchema.parse(parsed);
|
|
62
|
+
const rawBody = body.trimStart();
|
|
63
|
+
const renderedBody = renderBody(rawBody, frontmatter);
|
|
64
|
+
return { frontmatter, rawBody, renderedBody };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Parse an agent definition from a file path.
|
|
68
|
+
*
|
|
69
|
+
* @throws {Error} If file cannot be read or parsed
|
|
70
|
+
*/
|
|
71
|
+
export function parseAgentDefinitionFile(filePath) {
|
|
72
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
73
|
+
try {
|
|
74
|
+
return parseAgentDefinition(content);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
78
|
+
throw new Error(`Failed to parse agent definition ${filePath}: ${message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Body Rendering
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
/**
|
|
85
|
+
* Render the markdown body with frontmatter values as Handlebars context.
|
|
86
|
+
* Uses noEscape to preserve markdown formatting.
|
|
87
|
+
*/
|
|
88
|
+
function renderBody(body, frontmatter) {
|
|
89
|
+
try {
|
|
90
|
+
const template = Handlebars.compile(body, { noEscape: true });
|
|
91
|
+
return template(frontmatter);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// If body has no Handlebars expressions or they fail, return raw body
|
|
95
|
+
return body;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-definition.test.d.ts","sourceRoot":"","sources":["../../../src/templates/agent-definition.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { parseAgentDefinition, AgentDefinitionFrontmatterSchema, } from './agent-definition.js';
|
|
3
|
+
describe('AgentDefinitionFrontmatterSchema', () => {
|
|
4
|
+
it('validates a minimal frontmatter', () => {
|
|
5
|
+
const result = AgentDefinitionFrontmatterSchema.parse({ name: 'developer' });
|
|
6
|
+
expect(result.name).toBe('developer');
|
|
7
|
+
expect(result.build_commands).toBeUndefined();
|
|
8
|
+
expect(result.test_commands).toBeUndefined();
|
|
9
|
+
expect(result.af_linear).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
it('validates a complete frontmatter', () => {
|
|
12
|
+
const result = AgentDefinitionFrontmatterSchema.parse({
|
|
13
|
+
name: 'developer',
|
|
14
|
+
description: 'General-purpose development agent',
|
|
15
|
+
tools: 'Read, Edit, Write, Grep, Glob, Bash',
|
|
16
|
+
model: 'opus',
|
|
17
|
+
build_commands: {
|
|
18
|
+
verify: 'cmake --build build/',
|
|
19
|
+
full: 'cmake --build build/ --target all',
|
|
20
|
+
},
|
|
21
|
+
test_commands: {
|
|
22
|
+
unit: 'ctest --test-dir build/',
|
|
23
|
+
integration: '',
|
|
24
|
+
},
|
|
25
|
+
af_linear: 'bash tools/af-linear.sh',
|
|
26
|
+
});
|
|
27
|
+
expect(result.name).toBe('developer');
|
|
28
|
+
expect(result.model).toBe('opus');
|
|
29
|
+
expect(result.build_commands).toEqual({
|
|
30
|
+
verify: 'cmake --build build/',
|
|
31
|
+
full: 'cmake --build build/ --target all',
|
|
32
|
+
});
|
|
33
|
+
expect(result.test_commands).toEqual({
|
|
34
|
+
unit: 'ctest --test-dir build/',
|
|
35
|
+
integration: '',
|
|
36
|
+
});
|
|
37
|
+
expect(result.af_linear).toBe('bash tools/af-linear.sh');
|
|
38
|
+
});
|
|
39
|
+
it('rejects invalid model', () => {
|
|
40
|
+
expect(() => AgentDefinitionFrontmatterSchema.parse({ name: 'test', model: 'gpt-4' })).toThrow();
|
|
41
|
+
});
|
|
42
|
+
it('rejects empty name', () => {
|
|
43
|
+
expect(() => AgentDefinitionFrontmatterSchema.parse({ name: '' })).toThrow();
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('parseAgentDefinition', () => {
|
|
47
|
+
it('parses a simple agent definition', () => {
|
|
48
|
+
const content = `---
|
|
49
|
+
name: developer
|
|
50
|
+
description: Implements features
|
|
51
|
+
tools: Read, Edit, Write
|
|
52
|
+
model: opus
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
# Developer Agent
|
|
56
|
+
|
|
57
|
+
Implements features and fixes bugs.
|
|
58
|
+
`;
|
|
59
|
+
const result = parseAgentDefinition(content);
|
|
60
|
+
expect(result.frontmatter.name).toBe('developer');
|
|
61
|
+
expect(result.frontmatter.description).toBe('Implements features');
|
|
62
|
+
expect(result.frontmatter.tools).toBe('Read, Edit, Write');
|
|
63
|
+
expect(result.frontmatter.model).toBe('opus');
|
|
64
|
+
expect(result.rawBody).toContain('# Developer Agent');
|
|
65
|
+
expect(result.renderedBody).toContain('# Developer Agent');
|
|
66
|
+
});
|
|
67
|
+
it('parses and interpolates build_commands in body', () => {
|
|
68
|
+
const content = `---
|
|
69
|
+
name: developer
|
|
70
|
+
build_commands:
|
|
71
|
+
verify: "cmake --build build/"
|
|
72
|
+
full: "make all"
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Build
|
|
76
|
+
|
|
77
|
+
Verify build: \`{{build_commands.verify}}\`
|
|
78
|
+
Full build: \`{{build_commands.full}}\`
|
|
79
|
+
`;
|
|
80
|
+
const result = parseAgentDefinition(content);
|
|
81
|
+
expect(result.frontmatter.build_commands).toEqual({
|
|
82
|
+
verify: 'cmake --build build/',
|
|
83
|
+
full: 'make all',
|
|
84
|
+
});
|
|
85
|
+
expect(result.renderedBody).toContain('Verify build: `cmake --build build/`');
|
|
86
|
+
expect(result.renderedBody).toContain('Full build: `make all`');
|
|
87
|
+
});
|
|
88
|
+
it('parses and interpolates test_commands in body', () => {
|
|
89
|
+
const content = `---
|
|
90
|
+
name: qa
|
|
91
|
+
test_commands:
|
|
92
|
+
unit: "cargo test"
|
|
93
|
+
integration: "cargo test -- --ignored"
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
Run unit tests: \`{{test_commands.unit}}\`
|
|
97
|
+
Run integration tests: \`{{test_commands.integration}}\`
|
|
98
|
+
`;
|
|
99
|
+
const result = parseAgentDefinition(content);
|
|
100
|
+
expect(result.renderedBody).toContain('Run unit tests: `cargo test`');
|
|
101
|
+
expect(result.renderedBody).toContain('Run integration tests: `cargo test -- --ignored`');
|
|
102
|
+
});
|
|
103
|
+
it('parses and interpolates af_linear in body', () => {
|
|
104
|
+
const content = `---
|
|
105
|
+
name: developer
|
|
106
|
+
af_linear: "bash tools/af-linear.sh"
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
Use \`{{af_linear}}\` for all Linear operations.
|
|
110
|
+
`;
|
|
111
|
+
const result = parseAgentDefinition(content);
|
|
112
|
+
expect(result.renderedBody).toContain('Use `bash tools/af-linear.sh` for all Linear operations.');
|
|
113
|
+
});
|
|
114
|
+
it('preserves raw body without modifying it', () => {
|
|
115
|
+
const content = `---
|
|
116
|
+
name: developer
|
|
117
|
+
build_commands:
|
|
118
|
+
verify: "cmake --build build/"
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
Build: \`{{build_commands.verify}}\`
|
|
122
|
+
`;
|
|
123
|
+
const result = parseAgentDefinition(content);
|
|
124
|
+
expect(result.rawBody).toContain('{{build_commands.verify}}');
|
|
125
|
+
expect(result.renderedBody).toContain('cmake --build build/');
|
|
126
|
+
});
|
|
127
|
+
it('handles body with no Handlebars expressions', () => {
|
|
128
|
+
const content = `---
|
|
129
|
+
name: developer
|
|
130
|
+
tools: Read, Edit
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
# Simple Agent
|
|
134
|
+
|
|
135
|
+
No interpolation here.
|
|
136
|
+
`;
|
|
137
|
+
const result = parseAgentDefinition(content);
|
|
138
|
+
expect(result.renderedBody).toContain('No interpolation here.');
|
|
139
|
+
});
|
|
140
|
+
it('handles empty build_commands gracefully', () => {
|
|
141
|
+
const content = `---
|
|
142
|
+
name: developer
|
|
143
|
+
build_commands: {}
|
|
144
|
+
test_commands: {}
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
# Agent
|
|
148
|
+
`;
|
|
149
|
+
const result = parseAgentDefinition(content);
|
|
150
|
+
expect(result.frontmatter.build_commands).toEqual({});
|
|
151
|
+
expect(result.frontmatter.test_commands).toEqual({});
|
|
152
|
+
});
|
|
153
|
+
it('throws on missing frontmatter delimiters', () => {
|
|
154
|
+
const content = `# No frontmatter here
|
|
155
|
+
|
|
156
|
+
Just a regular markdown file.
|
|
157
|
+
`;
|
|
158
|
+
expect(() => parseAgentDefinition(content)).toThrow('must start with YAML frontmatter');
|
|
159
|
+
});
|
|
160
|
+
it('throws on invalid frontmatter schema', () => {
|
|
161
|
+
const content = `---
|
|
162
|
+
model: gpt-4
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
# Agent
|
|
166
|
+
`;
|
|
167
|
+
expect(() => parseAgentDefinition(content)).toThrow();
|
|
168
|
+
});
|
|
169
|
+
it('works with existing TypeScript agent definitions (backward compat)', () => {
|
|
170
|
+
// This mimics the existing developer.md format
|
|
171
|
+
const content = `---
|
|
172
|
+
name: developer
|
|
173
|
+
description: General-purpose development agent. Implements features, fixes bugs, and writes tests.
|
|
174
|
+
tools: Read, Edit, Write, Grep, Glob, Bash
|
|
175
|
+
model: opus
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
# Developer Agent
|
|
179
|
+
|
|
180
|
+
Implements features and fixes bugs based on Linear issue requirements.
|
|
181
|
+
|
|
182
|
+
## Testing
|
|
183
|
+
|
|
184
|
+
\`\`\`bash
|
|
185
|
+
pnpm turbo run test --filter=[package-name]
|
|
186
|
+
pnpm turbo run typecheck --filter=[package-name]
|
|
187
|
+
pnpm turbo run build --filter=[package-name]
|
|
188
|
+
\`\`\`
|
|
189
|
+
`;
|
|
190
|
+
const result = parseAgentDefinition(content);
|
|
191
|
+
expect(result.frontmatter.name).toBe('developer');
|
|
192
|
+
expect(result.frontmatter.build_commands).toBeUndefined();
|
|
193
|
+
expect(result.frontmatter.test_commands).toBeUndefined();
|
|
194
|
+
expect(result.frontmatter.af_linear).toBeUndefined();
|
|
195
|
+
expect(result.renderedBody).toContain('pnpm turbo run test');
|
|
196
|
+
});
|
|
197
|
+
it('interpolates name and other basic fields in body', () => {
|
|
198
|
+
const content = `---
|
|
199
|
+
name: my-agent
|
|
200
|
+
description: A special agent
|
|
201
|
+
model: sonnet
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
This is the {{name}} agent. Model: {{model}}.
|
|
205
|
+
`;
|
|
206
|
+
const result = parseAgentDefinition(content);
|
|
207
|
+
expect(result.renderedBody).toContain('This is the my-agent agent. Model: sonnet.');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Template System
|
|
3
|
+
*
|
|
4
|
+
* Configurable, composable workflow templates using YAML with Handlebars.
|
|
5
|
+
*/
|
|
6
|
+
export type { WorkflowTemplate, PartialTemplate, TemplateContext, ToolPermission, ToolPermissionAdapter, TemplateRegistryConfig, } from './types.js';
|
|
7
|
+
export { WorkflowTemplateSchema, PartialTemplateSchema, TemplateContextSchema, AgentWorkTypeSchema, ToolPermissionSchema, validateWorkflowTemplate, validatePartialTemplate, } from './types.js';
|
|
8
|
+
export { TemplateRegistry } from './registry.js';
|
|
9
|
+
export { loadTemplatesFromDir, loadTemplateFile, loadPartialsFromDir, getBuiltinDefaultsDir, getBuiltinPartialsDir, } from './loader.js';
|
|
10
|
+
export { ClaudeToolPermissionAdapter, CodexToolPermissionAdapter, createToolPermissionAdapter } from './adapters.js';
|
|
11
|
+
export { renderPromptWithFallback } from './renderer.js';
|
|
12
|
+
export type { AgentDefinition, AgentDefinitionFrontmatter } from './agent-definition.js';
|
|
13
|
+
export { parseAgentDefinition, parseAgentDefinitionFile, AgentDefinitionFrontmatterSchema } from './agent-definition.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAEhD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAA;AAEpH,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAA;AAExD,YAAY,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAA;AACxF,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,gCAAgC,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Template System
|
|
3
|
+
*
|
|
4
|
+
* Configurable, composable workflow templates using YAML with Handlebars.
|
|
5
|
+
*/
|
|
6
|
+
export { WorkflowTemplateSchema, PartialTemplateSchema, TemplateContextSchema, AgentWorkTypeSchema, ToolPermissionSchema, validateWorkflowTemplate, validatePartialTemplate, } from './types.js';
|
|
7
|
+
export { TemplateRegistry } from './registry.js';
|
|
8
|
+
export { loadTemplatesFromDir, loadTemplateFile, loadPartialsFromDir, getBuiltinDefaultsDir, getBuiltinPartialsDir, } from './loader.js';
|
|
9
|
+
export { ClaudeToolPermissionAdapter, CodexToolPermissionAdapter, createToolPermissionAdapter } from './adapters.js';
|
|
10
|
+
export { renderPromptWithFallback } from './renderer.js';
|
|
11
|
+
export { parseAgentDefinition, parseAgentDefinitionFile, AgentDefinitionFrontmatterSchema } from './agent-definition.js';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template Loader
|
|
3
|
+
*
|
|
4
|
+
* Discovers, parses, and validates workflow templates from YAML files.
|
|
5
|
+
* Supports layered resolution:
|
|
6
|
+
* 1. Built-in defaults (packages/core/src/templates/defaults/)
|
|
7
|
+
* 2. Project-level overrides (.agentfactory/templates/ in repo root)
|
|
8
|
+
* 3. Inline config overrides (programmatic)
|
|
9
|
+
*/
|
|
10
|
+
import type { WorkflowTemplate } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Load all workflow templates from a directory.
|
|
13
|
+
* Only processes .yaml and .yml files at the top level.
|
|
14
|
+
*
|
|
15
|
+
* The map key is determined by `metadata.name` when it differs from `metadata.workType`,
|
|
16
|
+
* enabling strategy-specific compound keys like "refinement-context-enriched".
|
|
17
|
+
* When `metadata.name` equals `metadata.workType`, the key is simply the work type.
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadTemplatesFromDir(dir: string): Map<string, WorkflowTemplate>;
|
|
20
|
+
/**
|
|
21
|
+
* Load and validate a single workflow template YAML file.
|
|
22
|
+
*/
|
|
23
|
+
export declare function loadTemplateFile(filePath: string): WorkflowTemplate | null;
|
|
24
|
+
/**
|
|
25
|
+
* Load all partial templates from a directory (including subdirectories).
|
|
26
|
+
* Returns a map of partial name → content string.
|
|
27
|
+
*
|
|
28
|
+
* Partial names are derived from file paths relative to the partials directory:
|
|
29
|
+
* partials/cli-instructions.yaml → "cli-instructions"
|
|
30
|
+
* partials/frontend/linear-cli.yaml → "frontend/linear-cli"
|
|
31
|
+
*/
|
|
32
|
+
export declare function loadPartialsFromDir(dir: string, frontend?: string): Map<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Get the path to the built-in default templates directory.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getBuiltinDefaultsDir(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Get the path to the built-in default partials directory.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getBuiltinPartialsDir(): string;
|
|
41
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/templates/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAmB,MAAM,YAAY,CAAA;AAGnE;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAyB/E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAS1E;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CASrB;AA4CD;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAG9C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
|