@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Rensei AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# @renseiai/agentfactory
|
|
2
|
+
|
|
3
|
+
Core orchestrator for multi-agent fleet management. Turns your issue backlog into shipped code by coordinating coding agents (Claude, Codex, Amp) through an automated pipeline.
|
|
4
|
+
|
|
5
|
+
Part of the [AgentFactory](https://github.com/renseiai/agentfactory) monorepo.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @renseiai/agentfactory @renseiai/agentfactory-linear
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createOrchestrator } from '@renseiai/agentfactory'
|
|
17
|
+
|
|
18
|
+
const orchestrator = createOrchestrator({
|
|
19
|
+
maxConcurrent: 3,
|
|
20
|
+
worktreePath: '.worktrees',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// Process a single issue
|
|
24
|
+
await orchestrator.spawnAgentForIssue('PROJ-123')
|
|
25
|
+
await orchestrator.waitForAll()
|
|
26
|
+
|
|
27
|
+
// Check results
|
|
28
|
+
for (const agent of orchestrator.getAgents()) {
|
|
29
|
+
console.log(`${agent.identifier}: ${agent.status}`)
|
|
30
|
+
if (agent.pullRequestUrl) console.log(` PR: ${agent.pullRequestUrl}`)
|
|
31
|
+
if (agent.totalCostUsd) console.log(` Cost: $${agent.totalCostUsd.toFixed(4)}`)
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What It Does
|
|
36
|
+
|
|
37
|
+
1. **Issue selection** — queries Linear for backlog issues, filters by project, selects by priority
|
|
38
|
+
2. **Worktree creation** — creates isolated git worktrees per agent
|
|
39
|
+
3. **Agent spawning** — delegates to providers (Claude, Codex, Amp)
|
|
40
|
+
4. **Stream processing** — iterates `AgentEvent` from providers, emits activities to Linear
|
|
41
|
+
5. **Crash recovery** — persists state to `.agent/` directory, resumes on restart
|
|
42
|
+
6. **Inactivity timeout** — monitors idle agents and stops them
|
|
43
|
+
|
|
44
|
+
## Provider Abstraction
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
interface AgentProvider {
|
|
48
|
+
readonly name: 'claude' | 'codex' | 'amp'
|
|
49
|
+
spawn(config: AgentSpawnConfig): AgentHandle
|
|
50
|
+
resume(sessionId: string, config: AgentSpawnConfig): AgentHandle
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface AgentHandle {
|
|
54
|
+
sessionId: string | null
|
|
55
|
+
stream: AsyncIterable<AgentEvent>
|
|
56
|
+
injectMessage(text: string): Promise<void>
|
|
57
|
+
stop(): Promise<void>
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Provider resolution: `AGENT_PROVIDER_{WORKTYPE}` > `AGENT_PROVIDER_{PROJECT}` > `AGENT_PROVIDER` > `'claude'`
|
|
62
|
+
|
|
63
|
+
## Configuration
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const orchestrator = createOrchestrator({
|
|
67
|
+
provider: myProvider, // Agent provider instance
|
|
68
|
+
maxConcurrent: 3, // Max concurrent agents
|
|
69
|
+
project: 'MyProject', // Filter by project
|
|
70
|
+
worktreePath: '.worktrees', // Git worktree base path
|
|
71
|
+
inactivityTimeoutMs: 300_000, // 5 min idle timeout
|
|
72
|
+
maxSessionTimeoutMs: 7_200_000, // 2 hour hard cap
|
|
73
|
+
workTypeTimeouts: {
|
|
74
|
+
qa: { inactivityTimeoutMs: 600_000 },
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Workflow Governor
|
|
80
|
+
|
|
81
|
+
The core package includes the Workflow Governor — a central lifecycle manager that observes all issues and decides what work to dispatch.
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import {
|
|
85
|
+
WorkflowGovernor,
|
|
86
|
+
EventDrivenGovernor,
|
|
87
|
+
InMemoryEventBus,
|
|
88
|
+
InMemoryEventDeduplicator,
|
|
89
|
+
type GovernorDependencies,
|
|
90
|
+
} from '@renseiai/agentfactory'
|
|
91
|
+
|
|
92
|
+
// Poll-only mode (simple)
|
|
93
|
+
const governor = new WorkflowGovernor(
|
|
94
|
+
{ projects: ['MyProject'], scanIntervalMs: 60_000 },
|
|
95
|
+
myDependencies,
|
|
96
|
+
)
|
|
97
|
+
governor.start()
|
|
98
|
+
|
|
99
|
+
// Event-driven mode (production)
|
|
100
|
+
const eventGovernor = new EventDrivenGovernor(
|
|
101
|
+
{
|
|
102
|
+
projects: ['MyProject'],
|
|
103
|
+
eventBus: new InMemoryEventBus(), // or RedisEventBus
|
|
104
|
+
deduplicator: new InMemoryEventDeduplicator(), // or RedisEventDeduplicator
|
|
105
|
+
pollIntervalMs: 300_000, // 5 min safety net
|
|
106
|
+
},
|
|
107
|
+
myDependencies,
|
|
108
|
+
)
|
|
109
|
+
await eventGovernor.start()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The governor evaluates each issue against status, active sessions, cooldowns, human overrides (HOLD/RESUME/PRIORITY), and workflow strategy to decide what action to take. See [Architecture docs](https://github.com/renseiai/agentfactory/blob/main/docs/architecture.md#workflow-governor) for details.
|
|
113
|
+
|
|
114
|
+
## Related Packages
|
|
115
|
+
|
|
116
|
+
| Package | Description |
|
|
117
|
+
|---------|-------------|
|
|
118
|
+
| [@renseiai/agentfactory-linear](https://www.npmjs.com/package/@renseiai/agentfactory-linear) | Linear issue tracker integration |
|
|
119
|
+
| [@renseiai/agentfactory-server](https://www.npmjs.com/package/@renseiai/agentfactory-server) | Redis work queue, distributed workers |
|
|
120
|
+
| [@renseiai/agentfactory-cli](https://www.npmjs.com/package/@renseiai/agentfactory-cli) | CLI tools |
|
|
121
|
+
| [@renseiai/agentfactory-nextjs](https://www.npmjs.com/package/@renseiai/agentfactory-nextjs) | Next.js webhook server |
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AAClH,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { loadRepositoryConfig, RepositoryConfigSchema, getEffectiveAllowedProjects } from './repository-config.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Configuration
|
|
3
|
+
*
|
|
4
|
+
* Loads and validates the declarative .agentfactory/config.yaml file.
|
|
5
|
+
* This config controls repository-level settings such as:
|
|
6
|
+
* - Git remote validation (repository field)
|
|
7
|
+
* - Project allowlisting for the orchestrator (allowedProjects field)
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
export declare const RepositoryConfigSchema: z.ZodObject<{
|
|
11
|
+
apiVersion: z.ZodString;
|
|
12
|
+
kind: z.ZodLiteral<"RepositoryConfig">;
|
|
13
|
+
repository: z.ZodOptional<z.ZodString>;
|
|
14
|
+
allowedProjects: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
15
|
+
projectPaths: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
16
|
+
sharedPaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
17
|
+
linearCli: z.ZodOptional<z.ZodString>;
|
|
18
|
+
packageManager: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
pnpm: "pnpm";
|
|
20
|
+
npm: "npm";
|
|
21
|
+
yarn: "yarn";
|
|
22
|
+
bun: "bun";
|
|
23
|
+
none: "none";
|
|
24
|
+
}>>;
|
|
25
|
+
buildCommand: z.ZodOptional<z.ZodString>;
|
|
26
|
+
testCommand: z.ZodOptional<z.ZodString>;
|
|
27
|
+
validateCommand: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
export type RepositoryConfig = z.infer<typeof RepositoryConfigSchema>;
|
|
30
|
+
/**
|
|
31
|
+
* Returns the effective list of allowed project names.
|
|
32
|
+
* When `projectPaths` is set, the keys are the allowed projects.
|
|
33
|
+
* Otherwise falls back to `allowedProjects`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getEffectiveAllowedProjects(config: RepositoryConfig): string[] | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Load and validate .agentfactory/config.yaml from the given git root.
|
|
38
|
+
*
|
|
39
|
+
* @param gitRoot - The root directory of the git repository
|
|
40
|
+
* @returns The validated RepositoryConfig, or null if the file does not exist
|
|
41
|
+
* @throws {z.ZodError} If the file exists but fails schema validation
|
|
42
|
+
*/
|
|
43
|
+
export declare function loadRepositoryConfig(gitRoot: string): RepositoryConfig | null;
|
|
44
|
+
//# sourceMappingURL=repository-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-config.d.ts","sourceRoot":"","sources":["../../../src/config/repository-config.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AASvB,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;iBA0ClC,CAAA;AAMD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAMrE;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,GAAG,SAAS,CAK1F;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAQ7E"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository Configuration
|
|
3
|
+
*
|
|
4
|
+
* Loads and validates the declarative .agentfactory/config.yaml file.
|
|
5
|
+
* This config controls repository-level settings such as:
|
|
6
|
+
* - Git remote validation (repository field)
|
|
7
|
+
* - Project allowlisting for the orchestrator (allowedProjects field)
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { readFileSync, existsSync } from 'fs';
|
|
11
|
+
import { resolve } from 'path';
|
|
12
|
+
import YAML from 'yaml';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Zod Schema
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
export const RepositoryConfigSchema = z.object({
|
|
17
|
+
apiVersion: z.string(),
|
|
18
|
+
kind: z.literal('RepositoryConfig'),
|
|
19
|
+
repository: z.string().optional(),
|
|
20
|
+
allowedProjects: z.array(z.string()).optional(),
|
|
21
|
+
/** Maps Linear project names to their root directory within the repo (e.g., { Family: 'apps/family' }) */
|
|
22
|
+
projectPaths: z.record(z.string(), z.string()).optional(),
|
|
23
|
+
/** Shared directories that any project's agent may modify (e.g., ['packages/ui']) */
|
|
24
|
+
sharedPaths: z.array(z.string()).optional(),
|
|
25
|
+
/**
|
|
26
|
+
* Command to invoke the Linear CLI (default: "pnpm af-linear").
|
|
27
|
+
* For non-Node projects, set to a path or wrapper script, e.g.:
|
|
28
|
+
* "npx -y @renseiai/agentfactory-cli af-linear"
|
|
29
|
+
* "./tools/af-linear.sh"
|
|
30
|
+
* "/usr/local/bin/af-linear"
|
|
31
|
+
*/
|
|
32
|
+
linearCli: z.string().optional(),
|
|
33
|
+
/**
|
|
34
|
+
* Package manager used by the project (default: "pnpm").
|
|
35
|
+
* Set to "none" for non-Node projects (disables dependency linking and helper scripts).
|
|
36
|
+
* Supported values: "pnpm" | "npm" | "yarn" | "bun" | "none"
|
|
37
|
+
*/
|
|
38
|
+
packageManager: z.enum(['pnpm', 'npm', 'yarn', 'bun', 'none']).optional(),
|
|
39
|
+
/**
|
|
40
|
+
* Build command override (e.g. 'cargo build', 'cmake --build build', 'make').
|
|
41
|
+
* Injected into workflow templates as {{buildCommand}}.
|
|
42
|
+
*/
|
|
43
|
+
buildCommand: z.string().optional(),
|
|
44
|
+
/**
|
|
45
|
+
* Test command override (e.g. 'cargo test', 'ctest --test-dir build', 'make test').
|
|
46
|
+
* Injected into workflow templates as {{testCommand}}.
|
|
47
|
+
*/
|
|
48
|
+
testCommand: z.string().optional(),
|
|
49
|
+
/**
|
|
50
|
+
* Validation command override — replaces typecheck for compiled projects
|
|
51
|
+
* (e.g. 'cargo clippy', 'go vet ./...').
|
|
52
|
+
* Injected into workflow templates as {{validateCommand}}.
|
|
53
|
+
*/
|
|
54
|
+
validateCommand: z.string().optional(),
|
|
55
|
+
}).refine((data) => !(data.allowedProjects && data.projectPaths), { message: 'allowedProjects and projectPaths are mutually exclusive — use one or the other' });
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Helpers
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Returns the effective list of allowed project names.
|
|
61
|
+
* When `projectPaths` is set, the keys are the allowed projects.
|
|
62
|
+
* Otherwise falls back to `allowedProjects`.
|
|
63
|
+
*/
|
|
64
|
+
export function getEffectiveAllowedProjects(config) {
|
|
65
|
+
if (config.projectPaths) {
|
|
66
|
+
return Object.keys(config.projectPaths);
|
|
67
|
+
}
|
|
68
|
+
return config.allowedProjects;
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Loader
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Load and validate .agentfactory/config.yaml from the given git root.
|
|
75
|
+
*
|
|
76
|
+
* @param gitRoot - The root directory of the git repository
|
|
77
|
+
* @returns The validated RepositoryConfig, or null if the file does not exist
|
|
78
|
+
* @throws {z.ZodError} If the file exists but fails schema validation
|
|
79
|
+
*/
|
|
80
|
+
export function loadRepositoryConfig(gitRoot) {
|
|
81
|
+
const configPath = resolve(gitRoot, '.agentfactory', 'config.yaml');
|
|
82
|
+
if (!existsSync(configPath)) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
86
|
+
const parsed = YAML.parse(content);
|
|
87
|
+
return RepositoryConfigSchema.parse(parsed);
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-config.test.d.ts","sourceRoot":"","sources":["../../../src/config/repository-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { loadRepositoryConfig, RepositoryConfigSchema, getEffectiveAllowedProjects } from './repository-config.js';
|
|
4
|
+
vi.mock('fs', () => ({
|
|
5
|
+
existsSync: vi.fn(),
|
|
6
|
+
readFileSync: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
9
|
+
const mockReadFileSync = vi.mocked(readFileSync);
|
|
10
|
+
describe('loadRepositoryConfig', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
vi.clearAllMocks();
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
vi.restoreAllMocks();
|
|
16
|
+
});
|
|
17
|
+
it('returns null when config file does not exist', () => {
|
|
18
|
+
mockExistsSync.mockReturnValue(false);
|
|
19
|
+
const result = loadRepositoryConfig('/some/repo');
|
|
20
|
+
expect(result).toBeNull();
|
|
21
|
+
expect(mockExistsSync).toHaveBeenCalledWith('/some/repo/.agentfactory/config.yaml');
|
|
22
|
+
});
|
|
23
|
+
it('parses valid YAML with all fields', () => {
|
|
24
|
+
mockExistsSync.mockReturnValue(true);
|
|
25
|
+
mockReadFileSync.mockReturnValue(`apiVersion: v1
|
|
26
|
+
kind: RepositoryConfig
|
|
27
|
+
repository: github.com/renseiai/agentfactory
|
|
28
|
+
allowedProjects:
|
|
29
|
+
- Agent
|
|
30
|
+
- Dashboard
|
|
31
|
+
`);
|
|
32
|
+
const result = loadRepositoryConfig('/some/repo');
|
|
33
|
+
expect(result).toEqual({
|
|
34
|
+
apiVersion: 'v1',
|
|
35
|
+
kind: 'RepositoryConfig',
|
|
36
|
+
repository: 'github.com/renseiai/agentfactory',
|
|
37
|
+
allowedProjects: ['Agent', 'Dashboard'],
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
it('parses valid YAML with only required fields', () => {
|
|
41
|
+
mockExistsSync.mockReturnValue(true);
|
|
42
|
+
mockReadFileSync.mockReturnValue(`apiVersion: v1
|
|
43
|
+
kind: RepositoryConfig
|
|
44
|
+
`);
|
|
45
|
+
const result = loadRepositoryConfig('/some/repo');
|
|
46
|
+
expect(result).toEqual({
|
|
47
|
+
apiVersion: 'v1',
|
|
48
|
+
kind: 'RepositoryConfig',
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it('throws on invalid schema — wrong kind', () => {
|
|
52
|
+
mockExistsSync.mockReturnValue(true);
|
|
53
|
+
mockReadFileSync.mockReturnValue(`apiVersion: v1
|
|
54
|
+
kind: WorkflowTemplate
|
|
55
|
+
repository: github.com/renseiai/agentfactory
|
|
56
|
+
`);
|
|
57
|
+
expect(() => loadRepositoryConfig('/some/repo')).toThrow();
|
|
58
|
+
});
|
|
59
|
+
it('throws on invalid schema — missing apiVersion', () => {
|
|
60
|
+
mockExistsSync.mockReturnValue(true);
|
|
61
|
+
mockReadFileSync.mockReturnValue(`kind: RepositoryConfig
|
|
62
|
+
repository: github.com/renseiai/agentfactory
|
|
63
|
+
`);
|
|
64
|
+
expect(() => loadRepositoryConfig('/some/repo')).toThrow();
|
|
65
|
+
});
|
|
66
|
+
it('parses valid YAML with projectPaths and sharedPaths', () => {
|
|
67
|
+
mockExistsSync.mockReturnValue(true);
|
|
68
|
+
mockReadFileSync.mockReturnValue(`apiVersion: v1
|
|
69
|
+
kind: RepositoryConfig
|
|
70
|
+
repository: github.com/renseiai/renseiai
|
|
71
|
+
projectPaths:
|
|
72
|
+
Social: apps/social
|
|
73
|
+
Family: apps/family
|
|
74
|
+
sharedPaths:
|
|
75
|
+
- packages/ui
|
|
76
|
+
- packages/lexical
|
|
77
|
+
`);
|
|
78
|
+
const result = loadRepositoryConfig('/some/repo');
|
|
79
|
+
expect(result).toEqual({
|
|
80
|
+
apiVersion: 'v1',
|
|
81
|
+
kind: 'RepositoryConfig',
|
|
82
|
+
repository: 'github.com/renseiai/renseiai',
|
|
83
|
+
projectPaths: { Social: 'apps/social', Family: 'apps/family' },
|
|
84
|
+
sharedPaths: ['packages/ui', 'packages/lexical'],
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
it('throws on invalid schema — allowedProjects is not an array', () => {
|
|
88
|
+
mockExistsSync.mockReturnValue(true);
|
|
89
|
+
mockReadFileSync.mockReturnValue(`apiVersion: v1
|
|
90
|
+
kind: RepositoryConfig
|
|
91
|
+
allowedProjects: NotAnArray
|
|
92
|
+
`);
|
|
93
|
+
expect(() => loadRepositoryConfig('/some/repo')).toThrow();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('RepositoryConfigSchema', () => {
|
|
97
|
+
it('validates a complete config', () => {
|
|
98
|
+
const result = RepositoryConfigSchema.parse({
|
|
99
|
+
apiVersion: 'v1',
|
|
100
|
+
kind: 'RepositoryConfig',
|
|
101
|
+
repository: 'github.com/org/repo',
|
|
102
|
+
allowedProjects: ['ProjectA', 'ProjectB'],
|
|
103
|
+
});
|
|
104
|
+
expect(result.apiVersion).toBe('v1');
|
|
105
|
+
expect(result.kind).toBe('RepositoryConfig');
|
|
106
|
+
expect(result.repository).toBe('github.com/org/repo');
|
|
107
|
+
expect(result.allowedProjects).toEqual(['ProjectA', 'ProjectB']);
|
|
108
|
+
});
|
|
109
|
+
it('validates a minimal config with only required fields', () => {
|
|
110
|
+
const result = RepositoryConfigSchema.parse({
|
|
111
|
+
apiVersion: 'v1',
|
|
112
|
+
kind: 'RepositoryConfig',
|
|
113
|
+
});
|
|
114
|
+
expect(result.apiVersion).toBe('v1');
|
|
115
|
+
expect(result.kind).toBe('RepositoryConfig');
|
|
116
|
+
expect(result.repository).toBeUndefined();
|
|
117
|
+
expect(result.allowedProjects).toBeUndefined();
|
|
118
|
+
});
|
|
119
|
+
it('rejects invalid kind', () => {
|
|
120
|
+
expect(() => RepositoryConfigSchema.parse({
|
|
121
|
+
apiVersion: 'v1',
|
|
122
|
+
kind: 'InvalidKind',
|
|
123
|
+
})).toThrow();
|
|
124
|
+
});
|
|
125
|
+
it('validates config with projectPaths only', () => {
|
|
126
|
+
const result = RepositoryConfigSchema.parse({
|
|
127
|
+
apiVersion: 'v1',
|
|
128
|
+
kind: 'RepositoryConfig',
|
|
129
|
+
repository: 'github.com/org/monorepo',
|
|
130
|
+
projectPaths: {
|
|
131
|
+
Social: 'apps/social',
|
|
132
|
+
Family: 'apps/family',
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
expect(result.projectPaths).toEqual({ Social: 'apps/social', Family: 'apps/family' });
|
|
136
|
+
expect(result.allowedProjects).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
it('validates config with projectPaths and sharedPaths', () => {
|
|
139
|
+
const result = RepositoryConfigSchema.parse({
|
|
140
|
+
apiVersion: 'v1',
|
|
141
|
+
kind: 'RepositoryConfig',
|
|
142
|
+
projectPaths: {
|
|
143
|
+
Social: 'apps/social',
|
|
144
|
+
Family: 'apps/family',
|
|
145
|
+
},
|
|
146
|
+
sharedPaths: ['packages/ui', 'packages/lexical'],
|
|
147
|
+
});
|
|
148
|
+
expect(result.projectPaths).toEqual({ Social: 'apps/social', Family: 'apps/family' });
|
|
149
|
+
expect(result.sharedPaths).toEqual(['packages/ui', 'packages/lexical']);
|
|
150
|
+
});
|
|
151
|
+
it('rejects config with both allowedProjects and projectPaths', () => {
|
|
152
|
+
expect(() => RepositoryConfigSchema.parse({
|
|
153
|
+
apiVersion: 'v1',
|
|
154
|
+
kind: 'RepositoryConfig',
|
|
155
|
+
allowedProjects: ['Social'],
|
|
156
|
+
projectPaths: { Social: 'apps/social' },
|
|
157
|
+
})).toThrow(/mutually exclusive/);
|
|
158
|
+
});
|
|
159
|
+
it('validates config with build/test/validate commands', () => {
|
|
160
|
+
const result = RepositoryConfigSchema.parse({
|
|
161
|
+
apiVersion: 'v1',
|
|
162
|
+
kind: 'RepositoryConfig',
|
|
163
|
+
repository: 'github.com/org/native-project',
|
|
164
|
+
buildCommand: 'cargo build --release',
|
|
165
|
+
testCommand: 'cargo test',
|
|
166
|
+
validateCommand: 'cargo clippy -- -D warnings',
|
|
167
|
+
});
|
|
168
|
+
expect(result.buildCommand).toBe('cargo build --release');
|
|
169
|
+
expect(result.testCommand).toBe('cargo test');
|
|
170
|
+
expect(result.validateCommand).toBe('cargo clippy -- -D warnings');
|
|
171
|
+
});
|
|
172
|
+
it('allows omitting build/test/validate commands', () => {
|
|
173
|
+
const result = RepositoryConfigSchema.parse({
|
|
174
|
+
apiVersion: 'v1',
|
|
175
|
+
kind: 'RepositoryConfig',
|
|
176
|
+
});
|
|
177
|
+
expect(result.buildCommand).toBeUndefined();
|
|
178
|
+
expect(result.testCommand).toBeUndefined();
|
|
179
|
+
expect(result.validateCommand).toBeUndefined();
|
|
180
|
+
});
|
|
181
|
+
it('validates config with build commands and non-Node settings', () => {
|
|
182
|
+
const result = RepositoryConfigSchema.parse({
|
|
183
|
+
apiVersion: 'v1',
|
|
184
|
+
kind: 'RepositoryConfig',
|
|
185
|
+
packageManager: 'none',
|
|
186
|
+
linearCli: 'bash tools/af-linear.sh',
|
|
187
|
+
buildCommand: 'cmake --build build/',
|
|
188
|
+
testCommand: 'ctest --test-dir build/',
|
|
189
|
+
});
|
|
190
|
+
expect(result.packageManager).toBe('none');
|
|
191
|
+
expect(result.linearCli).toBe('bash tools/af-linear.sh');
|
|
192
|
+
expect(result.buildCommand).toBe('cmake --build build/');
|
|
193
|
+
expect(result.testCommand).toBe('ctest --test-dir build/');
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('loadRepositoryConfig with build commands', () => {
|
|
197
|
+
beforeEach(() => {
|
|
198
|
+
vi.clearAllMocks();
|
|
199
|
+
});
|
|
200
|
+
afterEach(() => {
|
|
201
|
+
vi.restoreAllMocks();
|
|
202
|
+
});
|
|
203
|
+
it('parses config with build/test/validate commands', () => {
|
|
204
|
+
mockExistsSync.mockReturnValue(true);
|
|
205
|
+
mockReadFileSync.mockReturnValue(`apiVersion: v1
|
|
206
|
+
kind: RepositoryConfig
|
|
207
|
+
repository: github.com/org/native-project
|
|
208
|
+
packageManager: none
|
|
209
|
+
buildCommand: "cargo build --release"
|
|
210
|
+
testCommand: "cargo test"
|
|
211
|
+
validateCommand: "cargo clippy -- -D warnings"
|
|
212
|
+
`);
|
|
213
|
+
const result = loadRepositoryConfig('/some/repo');
|
|
214
|
+
expect(result).toEqual({
|
|
215
|
+
apiVersion: 'v1',
|
|
216
|
+
kind: 'RepositoryConfig',
|
|
217
|
+
repository: 'github.com/org/native-project',
|
|
218
|
+
packageManager: 'none',
|
|
219
|
+
buildCommand: 'cargo build --release',
|
|
220
|
+
testCommand: 'cargo test',
|
|
221
|
+
validateCommand: 'cargo clippy -- -D warnings',
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
describe('getEffectiveAllowedProjects', () => {
|
|
226
|
+
it('returns keys from projectPaths when set', () => {
|
|
227
|
+
const config = RepositoryConfigSchema.parse({
|
|
228
|
+
apiVersion: 'v1',
|
|
229
|
+
kind: 'RepositoryConfig',
|
|
230
|
+
projectPaths: { Social: 'apps/social', Family: 'apps/family' },
|
|
231
|
+
});
|
|
232
|
+
expect(getEffectiveAllowedProjects(config)).toEqual(['Social', 'Family']);
|
|
233
|
+
});
|
|
234
|
+
it('returns allowedProjects when projectPaths is not set', () => {
|
|
235
|
+
const config = RepositoryConfigSchema.parse({
|
|
236
|
+
apiVersion: 'v1',
|
|
237
|
+
kind: 'RepositoryConfig',
|
|
238
|
+
allowedProjects: ['Agent', 'Dashboard'],
|
|
239
|
+
});
|
|
240
|
+
expect(getEffectiveAllowedProjects(config)).toEqual(['Agent', 'Dashboard']);
|
|
241
|
+
});
|
|
242
|
+
it('returns undefined when neither is set', () => {
|
|
243
|
+
const config = RepositoryConfigSchema.parse({
|
|
244
|
+
apiVersion: 'v1',
|
|
245
|
+
kind: 'RepositoryConfig',
|
|
246
|
+
});
|
|
247
|
+
expect(getEffectiveAllowedProjects(config)).toBeUndefined();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Status Checker
|
|
3
|
+
*
|
|
4
|
+
* Queries GitHub commit status API for Vercel deployment state.
|
|
5
|
+
* Used to verify deployments before QA/acceptance work can proceed.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Individual deployment status for a Vercel app
|
|
9
|
+
*/
|
|
10
|
+
export interface DeploymentStatus {
|
|
11
|
+
/** The app name (e.g., "renseiai-social") */
|
|
12
|
+
app: string;
|
|
13
|
+
/** Deployment state */
|
|
14
|
+
state: 'success' | 'pending' | 'error' | 'failure';
|
|
15
|
+
/** Status description (e.g., "Deployment has completed") */
|
|
16
|
+
description: string;
|
|
17
|
+
/** Vercel preview URL if available */
|
|
18
|
+
targetUrl: string | null;
|
|
19
|
+
/** Full context string from GitHub */
|
|
20
|
+
context: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Result of checking deployment status for a commit
|
|
24
|
+
*/
|
|
25
|
+
export interface DeploymentCheckResult {
|
|
26
|
+
/** Whether all deployments succeeded */
|
|
27
|
+
allSucceeded: boolean;
|
|
28
|
+
/** Whether any deployment failed */
|
|
29
|
+
anyFailed: boolean;
|
|
30
|
+
/** Whether any deployment is still pending */
|
|
31
|
+
anyPending: boolean;
|
|
32
|
+
/** Individual deployment statuses */
|
|
33
|
+
statuses: DeploymentStatus[];
|
|
34
|
+
/** The commit SHA that was checked */
|
|
35
|
+
commitSha: string;
|
|
36
|
+
/** Overall state from GitHub */
|
|
37
|
+
overallState: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Options for checking deployment status
|
|
41
|
+
*/
|
|
42
|
+
export interface DeploymentCheckOptions {
|
|
43
|
+
/** GitHub repository owner */
|
|
44
|
+
owner?: string;
|
|
45
|
+
/** GitHub repository name */
|
|
46
|
+
repo?: string;
|
|
47
|
+
/** Timeout for GitHub API call in milliseconds */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get the PR number for the current branch using gh CLI
|
|
52
|
+
*/
|
|
53
|
+
export declare function getPRNumber(timeout?: number): Promise<number | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Get the head commit SHA for a PR
|
|
56
|
+
*/
|
|
57
|
+
export declare function getPRHeadSha(prNumber: number, options?: DeploymentCheckOptions): Promise<string | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Check deployment status for a specific commit SHA
|
|
60
|
+
*/
|
|
61
|
+
export declare function checkDeploymentStatus(commitSha: string, options?: DeploymentCheckOptions): Promise<DeploymentCheckResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Check deployment status for a PR number
|
|
64
|
+
* Convenience function that gets the commit SHA and checks status
|
|
65
|
+
*/
|
|
66
|
+
export declare function checkPRDeploymentStatus(prNumber: number, options?: DeploymentCheckOptions): Promise<DeploymentCheckResult | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Format deployment check result for display
|
|
69
|
+
*/
|
|
70
|
+
export declare function formatDeploymentStatus(result: DeploymentCheckResult): string;
|
|
71
|
+
/**
|
|
72
|
+
* Format failed deployments for a comment
|
|
73
|
+
*/
|
|
74
|
+
export declare function formatFailedDeployments(result: DeploymentCheckResult): string;
|
|
75
|
+
/**
|
|
76
|
+
* PR information found for an issue
|
|
77
|
+
*/
|
|
78
|
+
export interface IssuePRInfo {
|
|
79
|
+
/** PR number */
|
|
80
|
+
number: number;
|
|
81
|
+
/** Head commit SHA */
|
|
82
|
+
headSha: string;
|
|
83
|
+
/** Branch name */
|
|
84
|
+
branch: string;
|
|
85
|
+
/** PR title */
|
|
86
|
+
title: string;
|
|
87
|
+
/** PR URL */
|
|
88
|
+
url: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Find open PRs associated with a Linear issue identifier
|
|
92
|
+
* Searches for PRs with the issue identifier in the branch name or title
|
|
93
|
+
*
|
|
94
|
+
* @param issueIdentifier - The Linear issue identifier (e.g., "SUP-123")
|
|
95
|
+
* @param options - Options for the search
|
|
96
|
+
* @returns Array of matching PRs
|
|
97
|
+
*/
|
|
98
|
+
export declare function findPRsForIssue(issueIdentifier: string, options?: DeploymentCheckOptions): Promise<IssuePRInfo[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Check deployment status for an issue by finding associated PRs
|
|
101
|
+
* Returns the first PR's deployment status, or null if no PRs found
|
|
102
|
+
*
|
|
103
|
+
* @param issueIdentifier - The Linear issue identifier (e.g., "SUP-123")
|
|
104
|
+
* @param options - Options for the search and check
|
|
105
|
+
* @returns Deployment check result with PR info, or null if no PR found
|
|
106
|
+
*/
|
|
107
|
+
export declare function checkIssueDeploymentStatus(issueIdentifier: string, options?: DeploymentCheckOptions): Promise<(DeploymentCheckResult & {
|
|
108
|
+
pr: IssuePRInfo;
|
|
109
|
+
}) | null>;
|
|
110
|
+
//# sourceMappingURL=deployment-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-checker.d.ts","sourceRoot":"","sources":["../../../src/deployment/deployment-checker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAA;IACX,uBAAuB;IACvB,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;IAClD,4DAA4D;IAC5D,WAAW,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,wCAAwC;IACxC,YAAY,EAAE,OAAO,CAAA;IACrB,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAA;IACnB,qCAAqC;IACrC,QAAQ,EAAE,gBAAgB,EAAE,CAAA;IAC5B,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAA;IACjB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAyDD;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,MAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWjF;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CA+ChC;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAMvC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAmD5E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,CAmB7E;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gBAAgB;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,eAAe;IACf,KAAK,EAAE,MAAM,CAAA;IACb,aAAa;IACb,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,WAAW,EAAE,CAAC,CAsCxB;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,CAAC,qBAAqB,GAAG;IAAE,EAAE,EAAE,WAAW,CAAA;CAAE,CAAC,GAAG,IAAI,CAAC,CAe/D"}
|