adaptive-director-skill 0.1.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 +149 -0
- package/SKILL.md +395 -0
- package/data/registry.json +42 -0
- package/package.json +40 -0
- package/references/capability-registry.md +92 -0
- package/references/delegate-integration.md +115 -0
- package/references/handoff-schema.md +137 -0
- package/references/routing-rules.md +99 -0
- package/scripts/discover.mjs +132 -0
- package/scripts/resume.mjs +70 -0
- package/scripts/route.mjs +244 -0
- package/scripts/run-state.mjs +343 -0
- package/scripts/setup.mjs +123 -0
- package/scripts/smoke-test.mjs +89 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Capability Registry Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The capability registry assigns numeric scores to known models and defines minimum requirements per phase.
|
|
6
|
+
|
|
7
|
+
All scores are 1–5:
|
|
8
|
+
|
|
9
|
+
| Score | Meaning |
|
|
10
|
+
|-------|---------|
|
|
11
|
+
| 1 | Weak — unreliable for this capability |
|
|
12
|
+
| 2 | Limited — acceptable only for simple tasks |
|
|
13
|
+
| 3 | Acceptable — meets baseline requirements |
|
|
14
|
+
| 4 | Strong — reliable for most tasks |
|
|
15
|
+
| 5 | Excellent — best available |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Registry File
|
|
20
|
+
|
|
21
|
+
Location: `data/registry.json`
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"models": {
|
|
26
|
+
"claude-sonnet-4-5": { "planning": 4, "coding": 4, "review": 4 },
|
|
27
|
+
"codex-default": { "planning": 2, "coding": 5, "review": 2 },
|
|
28
|
+
"unknown": { "planning": 1, "coding": 1, "review": 1 }
|
|
29
|
+
},
|
|
30
|
+
"phase_requirements": {
|
|
31
|
+
"plan": { "min_planning": 3 },
|
|
32
|
+
"implement": { "min_coding": 2 },
|
|
33
|
+
"review": { "min_review": 3 },
|
|
34
|
+
"fix": { "min_coding": 2 },
|
|
35
|
+
"verify": { "min_planning": 2 }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Phase Requirements
|
|
43
|
+
|
|
44
|
+
| Phase | Minimum Requirement |
|
|
45
|
+
|-------|-------------------|
|
|
46
|
+
| plan | planning ≥ 3 |
|
|
47
|
+
| implement | coding ≥ 2 |
|
|
48
|
+
| review | review ≥ 3 |
|
|
49
|
+
| fix | coding ≥ 2 |
|
|
50
|
+
| verify | planning ≥ 2 |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Priority Chain
|
|
55
|
+
|
|
56
|
+
The routing script applies this order:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
1. User explicit override (config.yaml agentOverrides.*)
|
|
60
|
+
2. Delegate lane preference (fleet.yaml, only when --delegate)
|
|
61
|
+
3. Built-in registry (best available agent by score)
|
|
62
|
+
4. Fallback (claude)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## User Override (config.yaml)
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
agentOverrides.plan: claude
|
|
71
|
+
agentOverrides.implement: codex
|
|
72
|
+
agentOverrides.review: claude
|
|
73
|
+
agentOverrides.verify: claude
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Uncomment lines in `~/.adaptive-orchestrator/config.yaml` to activate.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Adding a New Model
|
|
81
|
+
|
|
82
|
+
Edit `data/registry.json` and add an entry under `models`:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
"my-custom-model": {
|
|
86
|
+
"planning": 3,
|
|
87
|
+
"coding": 4,
|
|
88
|
+
"review": 3
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Then set `ADAPTIVE_CURRENT_MODEL=my-custom-model` in your environment.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Delegate Integration Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Delegate execution is **optional** and **disabled by default**.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Default: native execution
|
|
9
|
+
--delegate flag: delegate execution allowed (not forced)
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Adaptive Orchestrator always remains the top-level controller.
|
|
13
|
+
`delegate-skills` is the execution channel — never the orchestrator.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## How It Works
|
|
18
|
+
|
|
19
|
+
When `--delegate` is passed:
|
|
20
|
+
|
|
21
|
+
1. Adaptive Orchestrator reads the `delegate-skills` fleet config
|
|
22
|
+
2. For each phase, it checks if a matching lane exists
|
|
23
|
+
3. If yes → dispatches the phase brief to that lane's implementer
|
|
24
|
+
4. If no → falls back to native execution
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
Plan → native claude (no planning lane)
|
|
28
|
+
Implement → delegate → codex (feature lane matches)
|
|
29
|
+
Review → native claude (no review lane)
|
|
30
|
+
Verify → native claude (no verify lane)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## delegate-skills Fleet Config
|
|
36
|
+
|
|
37
|
+
Location: `~/.delegate/fleet.yaml` or `./.delegate/fleet.yaml`
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
```yaml
|
|
41
|
+
lanes:
|
|
42
|
+
feature:
|
|
43
|
+
implementer: codex
|
|
44
|
+
model: o4-mini
|
|
45
|
+
effort: medium
|
|
46
|
+
tests:
|
|
47
|
+
implementer: aider
|
|
48
|
+
ui:
|
|
49
|
+
implementer: cursor
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Adaptive Orchestrator reads these lanes during routing and maps them to phases by keyword:
|
|
53
|
+
|
|
54
|
+
| Phase | Matching Lane Keywords |
|
|
55
|
+
|-------|----------------------|
|
|
56
|
+
| implement | feature, impl, code, build |
|
|
57
|
+
| fix | fix, repair, feature |
|
|
58
|
+
| plan | plan, planning |
|
|
59
|
+
| review | review, check |
|
|
60
|
+
| verify | test, verify, qa |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Installing delegate-skills
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx skills add amElnagdy/delegate-skills
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or specific skills:
|
|
71
|
+
```bash
|
|
72
|
+
npx skills add amElnagdy/delegate-skills --skill codex-delegate
|
|
73
|
+
npx skills add amElnagdy/delegate-skills --skill claude-delegate
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Relay Location
|
|
79
|
+
|
|
80
|
+
The routing engine looks for relay scripts at:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
./.skills/amElnagdy/delegate-skills/skills/<agent>-delegate/scripts/relay.mjs
|
|
84
|
+
~/.skills/amElnagdy/delegate-skills/skills/<agent>-delegate/scripts/relay.mjs
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Delegate Rule (MVP)
|
|
90
|
+
|
|
91
|
+
> One delegated executor per phase maximum.
|
|
92
|
+
|
|
93
|
+
The delegate should receive a focused brief and return a structured result.
|
|
94
|
+
It must NOT start its own orchestration loop.
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Orchestrator → brief → Delegate → result.json → Orchestrator
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The delegate NEVER commits. Committing belongs to the reviewer (you).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Runtime Flags
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Enable delegate
|
|
108
|
+
adaptive-orchestrator --delegate "Implement Stripe in Flutter"
|
|
109
|
+
|
|
110
|
+
# Delegate + max reasoning
|
|
111
|
+
adaptive-orchestrator --delegate --allow-max "Refactor payment architecture"
|
|
112
|
+
|
|
113
|
+
# Dry run (shows routing, no execution)
|
|
114
|
+
adaptive-orchestrator --dry-run --delegate "Implement Stripe in Flutter"
|
|
115
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Handoff Schema Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Every run gets an isolated workspace. Agents communicate through files — not shared chat history.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
.adaptive-orchestrator/runs/<run-id>/
|
|
9
|
+
├── metadata.json ← machine-readable run state
|
|
10
|
+
├── task.md ← original task (human + machine)
|
|
11
|
+
├── plan.md ← planner output (human readable)
|
|
12
|
+
├── plan.json ← planner output (machine contract)
|
|
13
|
+
├── implementation.md ← implementer report (human readable)
|
|
14
|
+
├── implementation.json ← implementer report (machine contract)
|
|
15
|
+
├── review.md ← reviewer findings (human readable)
|
|
16
|
+
├── review.json ← reviewer findings (machine contract)
|
|
17
|
+
└── final.md / final.json ← verification result
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## metadata.json
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"runId": "run-abc123",
|
|
27
|
+
"task": "Implement Stripe in Flutter",
|
|
28
|
+
"status": "running",
|
|
29
|
+
"currentPhase": "review",
|
|
30
|
+
"size": "medium",
|
|
31
|
+
"budget": "balanced",
|
|
32
|
+
"allowMax": false,
|
|
33
|
+
"useDelegate": false,
|
|
34
|
+
"routing": [],
|
|
35
|
+
"startedAt": "2026-09-17T01:00:00Z",
|
|
36
|
+
"updatedAt": "2026-09-17T01:15:00Z"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### RunStatus values
|
|
41
|
+
|
|
42
|
+
| Status | Meaning |
|
|
43
|
+
|--------|---------|
|
|
44
|
+
| pending | initialized, not started |
|
|
45
|
+
| running | currently executing |
|
|
46
|
+
| verified | completed successfully |
|
|
47
|
+
| blocked | review or verify failed after max cycles |
|
|
48
|
+
| failed | agent returned an error |
|
|
49
|
+
| interrupted | stopped mid-run (can resume) |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Phase JSON Contract
|
|
54
|
+
|
|
55
|
+
All phase results follow this schema:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"phase": "review",
|
|
60
|
+
"status": "completed",
|
|
61
|
+
"summary": "Found 1 critical issue...",
|
|
62
|
+
"findings": [
|
|
63
|
+
{
|
|
64
|
+
"severity": "critical",
|
|
65
|
+
"title": "Duplicate PaymentIntent confirmation",
|
|
66
|
+
"file": "lib/payment_service.dart",
|
|
67
|
+
"description": "PaymentIntent.confirm() is called twice on retry."
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"touchedFiles": ["lib/payment_service.dart"],
|
|
71
|
+
"sessionId": "sess-xyz"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### severity values
|
|
76
|
+
|
|
77
|
+
| Value | Behavior |
|
|
78
|
+
|-------|---------|
|
|
79
|
+
| critical | Must fix — triggers fix loop |
|
|
80
|
+
| warning | Report and continue |
|
|
81
|
+
| suggestion | Informational only |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Managing State with run-state.mjs
|
|
86
|
+
|
|
87
|
+
### Init a run
|
|
88
|
+
```bash
|
|
89
|
+
node scripts/run-state.mjs init \
|
|
90
|
+
--task "Implement Stripe in Flutter" \
|
|
91
|
+
--size medium \
|
|
92
|
+
--budget balanced
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Update status
|
|
96
|
+
```bash
|
|
97
|
+
node scripts/run-state.mjs update --run-id run-abc123 --status running --phase plan
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Write a phase result
|
|
101
|
+
```bash
|
|
102
|
+
node scripts/run-state.mjs write-phase \
|
|
103
|
+
--run-id run-abc123 \
|
|
104
|
+
--phase review \
|
|
105
|
+
--status completed \
|
|
106
|
+
--summary "Found 1 critical issue" \
|
|
107
|
+
--findings-json '[{"severity":"critical","title":"...","description":"..."}]'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Read a phase result
|
|
111
|
+
```bash
|
|
112
|
+
node scripts/run-state.mjs read-phase --run-id run-abc123 --phase review
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Build a brief for a phase
|
|
116
|
+
```bash
|
|
117
|
+
node scripts/run-state.mjs build-brief --run-id run-abc123 --phase implement
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### List all runs
|
|
121
|
+
```bash
|
|
122
|
+
node scripts/run-state.mjs list
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Brief Format (what each agent receives)
|
|
128
|
+
|
|
129
|
+
Each agent receives ONLY what it needs — not the full chat history.
|
|
130
|
+
|
|
131
|
+
| Phase | Receives |
|
|
132
|
+
|-------|---------|
|
|
133
|
+
| plan | task.md + instructions |
|
|
134
|
+
| implement | task.md + plan.md + instructions |
|
|
135
|
+
| review | task.md + plan.md + implementation.md + instructions |
|
|
136
|
+
| fix | task.md + review.md + instructions |
|
|
137
|
+
| verify | task.md + plan.md + instructions |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Routing Rules Reference
|
|
2
|
+
|
|
3
|
+
## Task Classification
|
|
4
|
+
|
|
5
|
+
Initial classification uses keyword heuristics:
|
|
6
|
+
|
|
7
|
+
| Size | Examples |
|
|
8
|
+
|------|---------|
|
|
9
|
+
| small | rename, fix typo, update text, minor fix, change color |
|
|
10
|
+
| medium | Stripe integration, password reset, new API, module refactor |
|
|
11
|
+
| large | architecture refactor, auth system, payment architecture, migration |
|
|
12
|
+
|
|
13
|
+
Default when no keyword matches: **medium**
|
|
14
|
+
|
|
15
|
+
### Reclassification
|
|
16
|
+
|
|
17
|
+
After the Planner inspects the repository, it appends a JSON block to its plan:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{"recommended_size": "large", "reason": "discovered webhooks + saved cards + refunds"}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If `recommended_size` differs from initial, Adaptive Orchestrator reclassifies and rebuilds the routing table.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Phase Map
|
|
28
|
+
|
|
29
|
+
| Task Size | Phases |
|
|
30
|
+
|-----------|--------|
|
|
31
|
+
| small | implement → review |
|
|
32
|
+
| medium | plan → implement → review → verify |
|
|
33
|
+
| large | plan → implement → review → [fix] → verify |
|
|
34
|
+
|
|
35
|
+
`fix` only runs if review finds CRITICAL issues.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Effort Table
|
|
40
|
+
|
|
41
|
+
| Phase | conservative | balanced | quality |
|
|
42
|
+
|-------|-------------|---------|---------|
|
|
43
|
+
| plan | medium | high | high |
|
|
44
|
+
| implement | medium | medium | medium |
|
|
45
|
+
| review | high | high | high |
|
|
46
|
+
| fix | medium | medium | medium |
|
|
47
|
+
| verify | medium | medium | high |
|
|
48
|
+
|
|
49
|
+
`max` is never used unless `--allow-max` is passed AND the routing engine selects it.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Agent Priority
|
|
54
|
+
|
|
55
|
+
### For planning/review/verify phases:
|
|
56
|
+
```
|
|
57
|
+
claude → agy → gemini → opencode → cursor → cline → copilot → aider → codex
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### For implementation/fix phases:
|
|
61
|
+
```
|
|
62
|
+
codex → aider → opencode → cursor → cline → claude → agy → copilot → gemini
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The first agent in the list whose representative model meets the phase requirement is selected.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Execution Mode
|
|
70
|
+
|
|
71
|
+
| Condition | Execution |
|
|
72
|
+
|-----------|-----------|
|
|
73
|
+
| Default | native |
|
|
74
|
+
| `--delegate` + matching fleet lane | delegate |
|
|
75
|
+
| `--delegate` + no matching lane | native (fallback) |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Using route.mjs
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
echo '{
|
|
83
|
+
"taskSize": "medium",
|
|
84
|
+
"phase": "review",
|
|
85
|
+
"budget": "balanced",
|
|
86
|
+
"allowMax": false,
|
|
87
|
+
"delegateEnabled": false
|
|
88
|
+
}' | node scripts/route.mjs
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"agent": "claude",
|
|
95
|
+
"model": "claude-sonnet-4-5",
|
|
96
|
+
"effort": "high",
|
|
97
|
+
"execution": "native"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* discover.mjs
|
|
4
|
+
* ─────────────
|
|
5
|
+
* Detects installed coding-agent CLIs and delegate-skills fleet.
|
|
6
|
+
* Never guesses. If a capability cannot be verified, it is marked unknown/false.
|
|
7
|
+
*
|
|
8
|
+
* Output: JSON on stdout.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/discover.mjs
|
|
12
|
+
* node scripts/discover.mjs --json (same, explicit)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { execFileSync, execSync } from 'node:child_process'
|
|
16
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
17
|
+
import { join } from 'node:path'
|
|
18
|
+
import { homedir } from 'node:os'
|
|
19
|
+
|
|
20
|
+
// ─── Known agents ─────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
const KNOWN_AGENTS = [
|
|
23
|
+
{ id: 'claude', bins: ['claude'], versionArgs: ['--version'] },
|
|
24
|
+
{ id: 'codex', bins: ['codex'], versionArgs: ['--version'] },
|
|
25
|
+
{ id: 'agy', bins: ['agy'], versionArgs: ['--version'] },
|
|
26
|
+
{ id: 'gemini', bins: ['gemini'], versionArgs: ['--version'] },
|
|
27
|
+
{ id: 'opencode', bins: ['opencode'], versionArgs: ['--version'] },
|
|
28
|
+
{ id: 'aider', bins: ['aider'], versionArgs: ['--version'] },
|
|
29
|
+
{ id: 'cursor', bins: ['cursor-agent'], versionArgs: ['--version'] },
|
|
30
|
+
{ id: 'cline', bins: ['cline'], versionArgs: ['--version'] },
|
|
31
|
+
{ id: 'copilot', bins: ['copilot'], versionArgs: ['--version'] },
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
function isOnPath(bin) {
|
|
37
|
+
try {
|
|
38
|
+
execSync(
|
|
39
|
+
process.platform === 'win32' ? `where ${bin}` : `which ${bin}`,
|
|
40
|
+
{ stdio: 'ignore', timeout: 3000 }
|
|
41
|
+
)
|
|
42
|
+
return true
|
|
43
|
+
} catch {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function findBinary(bins) {
|
|
49
|
+
for (const bin of bins) {
|
|
50
|
+
if (isOnPath(bin)) return bin
|
|
51
|
+
}
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getVersion(bin, args) {
|
|
56
|
+
try {
|
|
57
|
+
const out = execFileSync(bin, args, {
|
|
58
|
+
encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore']
|
|
59
|
+
})
|
|
60
|
+
return out.trim().split('\n')[0].trim()
|
|
61
|
+
} catch {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Delegate-skills fleet ────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
function readFleet(path) {
|
|
69
|
+
if (!existsSync(path)) return null
|
|
70
|
+
try {
|
|
71
|
+
const raw = readFileSync(path, 'utf8')
|
|
72
|
+
// Simple YAML lane parser (avoids dependency on js-yaml in scripts)
|
|
73
|
+
const lanes = {}
|
|
74
|
+
let currentLane = null
|
|
75
|
+
for (const line of raw.split('\n')) {
|
|
76
|
+
const laneMatch = line.match(/^ (\w[\w-]*):\s*$/)
|
|
77
|
+
const implementerMatch = line.match(/^\s+implementer:\s*(.+)$/)
|
|
78
|
+
const modelMatch = line.match(/^\s+model:\s*(.+)$/)
|
|
79
|
+
const effortMatch = line.match(/^\s+effort:\s*(.+)$/)
|
|
80
|
+
if (laneMatch) { currentLane = laneMatch[1]; lanes[currentLane] = {} }
|
|
81
|
+
else if (currentLane && implementerMatch) lanes[currentLane].implementer = implementerMatch[1].trim()
|
|
82
|
+
else if (currentLane && modelMatch) lanes[currentLane].model = modelMatch[1].trim()
|
|
83
|
+
else if (currentLane && effortMatch) lanes[currentLane].effort = effortMatch[1].trim()
|
|
84
|
+
}
|
|
85
|
+
return Object.keys(lanes).length > 0 ? lanes : null
|
|
86
|
+
} catch {
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function discoverDelegate() {
|
|
92
|
+
const globalPath = join(homedir(), '.delegate', 'fleet.yaml')
|
|
93
|
+
const projectPath = join(process.cwd(), '.delegate', 'fleet.yaml')
|
|
94
|
+
|
|
95
|
+
const globalLanes = readFleet(globalPath)
|
|
96
|
+
const projectLanes = readFleet(projectPath)
|
|
97
|
+
|
|
98
|
+
if (!globalLanes && !projectLanes) {
|
|
99
|
+
return { installed: false, lanes: {} }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const merged = { ...(globalLanes ?? {}), ...(projectLanes ?? {}) }
|
|
103
|
+
return { installed: true, lanes: merged }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
function discover() {
|
|
109
|
+
const agents = {}
|
|
110
|
+
|
|
111
|
+
for (const desc of KNOWN_AGENTS) {
|
|
112
|
+
const bin = findBinary(desc.bins)
|
|
113
|
+
if (!bin) {
|
|
114
|
+
agents[desc.id] = { installed: false, available: false }
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const version = getVersion(bin, desc.versionArgs)
|
|
119
|
+
agents[desc.id] = {
|
|
120
|
+
installed: true,
|
|
121
|
+
available: version !== null,
|
|
122
|
+
version: version ?? 'unknown',
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const delegateSkills = discoverDelegate()
|
|
127
|
+
|
|
128
|
+
const result = { agents, delegateSkills }
|
|
129
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
discover()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* resume.mjs
|
|
4
|
+
* ───────────
|
|
5
|
+
* Finds interrupted or running runs and returns state for resumption.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node scripts/resume.mjs → most recent interrupted run
|
|
9
|
+
* node scripts/resume.mjs --run-id run-abc → specific run
|
|
10
|
+
* node scripts/resume.mjs --list → all runs with status
|
|
11
|
+
*
|
|
12
|
+
* Output: JSON metadata of the run, or null if nothing to resume.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
16
|
+
import { join } from 'node:path'
|
|
17
|
+
|
|
18
|
+
const RUNS_ROOT = existsSync(join(process.cwd(), '.adaptive-orchestrator', 'runs'))
|
|
19
|
+
? join(process.cwd(), '.adaptive-orchestrator', 'runs')
|
|
20
|
+
: join(process.cwd(), '.adaptive-director', 'runs')
|
|
21
|
+
const RESUMABLE = new Set(['interrupted', 'running', 'pending'])
|
|
22
|
+
|
|
23
|
+
function metaPath(runId) {
|
|
24
|
+
return join(RUNS_ROOT, runId, 'metadata.json')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function allRuns() {
|
|
28
|
+
if (!existsSync(RUNS_ROOT)) return []
|
|
29
|
+
return readdirSync(RUNS_ROOT, { withFileTypes: true })
|
|
30
|
+
.filter(d => d.isDirectory())
|
|
31
|
+
.map(d => {
|
|
32
|
+
try { return JSON.parse(readFileSync(metaPath(d.name), 'utf8')) }
|
|
33
|
+
catch { return null }
|
|
34
|
+
})
|
|
35
|
+
.filter(Boolean)
|
|
36
|
+
.sort((a, b) => b.startedAt.localeCompare(a.startedAt))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── Arg parser ───────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
const args = {}
|
|
42
|
+
const argv = process.argv.slice(2)
|
|
43
|
+
for (let i = 0; i < argv.length; i++) {
|
|
44
|
+
if (argv[i].startsWith('--')) {
|
|
45
|
+
args[argv[i]] = argv[i + 1] && !argv[i + 1].startsWith('--') ? argv[++i] : true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
function out(data) { process.stdout.write(JSON.stringify(data, null, 2) + '\n') }
|
|
52
|
+
|
|
53
|
+
if (args['--list']) {
|
|
54
|
+
out(allRuns())
|
|
55
|
+
process.exit(0)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (args['--run-id']) {
|
|
59
|
+
const path = metaPath(args['--run-id'])
|
|
60
|
+
if (!existsSync(path)) {
|
|
61
|
+
process.stderr.write(`Run not found: ${args['--run-id']}\n`)
|
|
62
|
+
process.exit(1)
|
|
63
|
+
}
|
|
64
|
+
out(JSON.parse(readFileSync(path, 'utf8')))
|
|
65
|
+
process.exit(0)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Find most recent resumable run
|
|
69
|
+
const resumable = allRuns().find(r => RESUMABLE.has(r.status))
|
|
70
|
+
out(resumable ?? null)
|