adaptive-director-skill 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -142,10 +142,11 @@ The repository separates the **npm management/installer layer** from the **self-
142
142
  Adaptive-Director-Skill/
143
143
  ├── scripts/ # Management & CLI layer
144
144
  │ ├── cli.mjs # Main CLI router
145
- │ ├── setup.mjs # Interactive host setup
145
+ │ ├── setup.mjs # Interactive host setup & delegate integration
146
+ │ ├── delegate-cli.mjs # Delegate skills integration CLI
146
147
  │ ├── install.mjs # Idempotent skill copier
147
148
  │ ├── refresh.mjs # Safe config refresher
148
- │ ├── discover.mjs # Local agent discovery
149
+ │ ├── discover.mjs # Local agent & delegate discovery
149
150
  │ ├── doctor.mjs # Installation diagnostics
150
151
  │ └── smoke-test.mjs # Automated test suite
151
152
 
@@ -163,19 +164,25 @@ Adaptive-Director-Skill/
163
164
  ## CLI Commands
164
165
 
165
166
  ```bash
166
- adaptive-director setup # Interactive: discover hosts, install Skill, create config
167
- adaptive-director install # Re-install/update Skill in host directories
168
- adaptive-director refresh # Re-discover hosts & update config (preserves overrides)
169
- adaptive-director doctor # Validate installation and health
170
- adaptive-director help # Show usage
167
+ adaptive-director setup # Interactive: discover hosts, install Skill, configure delegate
168
+ adaptive-director setup --with-delegate # Setup and automatically install delegate-skills
169
+ adaptive-director setup --no-delegate # Setup skipping delegate-skills (native execution)
170
+ adaptive-director delegate install # Install delegate-skills via official installer
171
+ adaptive-director delegate status # Check delegate-skills discovery and relay status
172
+ adaptive-director install # Re-install/update Skill in host directories
173
+ adaptive-director refresh # Re-discover hosts & update config (preserves overrides)
174
+ adaptive-director doctor # Validate installation and health
175
+ adaptive-director help # Show usage
171
176
  ```
172
177
 
173
178
  ---
174
179
 
175
180
  ## Core Principles
176
181
 
177
- - **Routing Priority:** User overrides Delegate fleet lanes Capability registry Default fallback.
182
+ - **Dynamic Discovery:** Discovers installed host CLIs and inspects locally available models at runtime rather than assuming static pairings.
183
+ - **Routing Priority:** User overrides → Delegate fleet lanes → Dynamic Host Discovery → Capability registry → Default fallback.
178
184
  - **Independent Review:** The coder never reviews its own work.
185
+ - **Verification Dimension:** Independent verification requires dedicated verification capabilities (`min_verification: 3`).
179
186
  - **Max Reasoning Opt-in:** `max` effort is locked by default; requires `--allow-max`.
180
187
  - **Runaway Loop Protection:** Maximum 1 automated fix cycle before alerting the user.
181
188
  - **Context Isolation:** Each agent receives only a self-contained brief on disk (`.adaptive-director/runs/`), preventing context window bloat.
@@ -183,6 +190,31 @@ adaptive-director help # Show usage
183
190
 
184
191
  ---
185
192
 
193
+ ## Dynamic Model Discovery & Heuristics
194
+
195
+ Adaptive Director does **not** rely on rigid, hardcoded host-to-model pairings. Real-world model availability depends on local CLI versions, host configurations, and account subscriptions.
196
+
197
+ ### Routing Pipeline
198
+
199
+ ```text
200
+ Detect Host CLI
201
+
202
+ Discover Locally Available Models (cache / config / env)
203
+
204
+ Resolve Aliases (e.g. 'astra' → 'gpt-6-astra')
205
+
206
+ Intersect with Registry Capabilities & Phase Requirements
207
+
208
+ Score Compatible Candidates for Current Phase
209
+
210
+ Route to Optimal Candidate (with Graceful Fallback)
211
+ ```
212
+
213
+ > [!NOTE]
214
+ > **Heuristic Calibration Disclaimer:** Capability scores (1–5) in `data/registry.json` represent internal routing heuristics and priors calibrated for phase allocation. They are **not** vendor laboratory benchmarks or absolute leaderboards.
215
+
216
+ ---
217
+
186
218
  ## Configuration (`~/.adaptive-director/config.json`)
187
219
 
188
220
  ```json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adaptive-director-skill",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Adaptive Director Skill — Skill-first adaptive multi-agent orchestration for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "skills/"
20
20
  ],
21
21
  "scripts": {
22
- "test": "node scripts/smoke-test.mjs",
22
+ "test": "node scripts/smoke-test.mjs && node scripts/test-setup-delegate.mjs",
23
23
  "setup": "node scripts/setup.mjs",
24
24
  "discover": "node scripts/discover.mjs",
25
25
  "doctor": "node scripts/doctor.mjs"
package/scripts/cli.mjs CHANGED
@@ -15,20 +15,23 @@ const commands = {
15
15
  install: 'install.mjs',
16
16
  refresh: 'refresh.mjs',
17
17
  doctor: 'doctor.mjs',
18
+ delegate: 'delegate-cli.mjs',
18
19
  };
19
20
 
20
21
  if (command === 'help' || command === '--help' || command === '-h') {
21
- console.log(`Adaptive Director Skill CLI v1.0.0
22
+ console.log(`Adaptive Director Skill CLI v1.1.1
22
23
 
23
24
  Usage:
24
- adaptive-director <command>
25
+ adaptive-director <command> [options]
25
26
 
26
27
  Commands:
27
- setup - Initial interactive setup and installation
28
- install - Install/copy the Skill into supported host skill directories
29
- refresh - Re-run discovery and update config without destroying user overrides
30
- doctor - Validate installation and report health
31
- help - Show this help message
28
+ setup - Initial interactive setup and host/delegate configuration
29
+ Flags: --with-delegate, --no-delegate, --yes
30
+ install - Install/copy the Skill into supported host skill directories
31
+ refresh - Re-run discovery and update config without destroying user overrides
32
+ doctor - Validate installation and report health
33
+ delegate - Manage delegate-skills integration (install, status)
34
+ help - Show this help message
32
35
  `);
33
36
  process.exit(0);
34
37
  }
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync, spawnSync } from 'node:child_process';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { join, dirname } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+
10
+ const args = process.argv.slice(2);
11
+ const subcmd = args[0] || 'help';
12
+
13
+ function run(script, scriptArgs = []) {
14
+ try {
15
+ const out = execFileSync(process.execPath, [script, ...scriptArgs], {
16
+ encoding: 'utf8',
17
+ timeout: 15000,
18
+ cwd: process.cwd(),
19
+ env: process.env,
20
+ });
21
+ return JSON.parse(out.trim());
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ if (subcmd === 'help' || subcmd === '--help' || subcmd === '-h') {
28
+ console.log(`Adaptive Director — Delegate Skills Management
29
+
30
+ Usage:
31
+ adaptive-director delegate <subcommand> [options]
32
+
33
+ Subcommands:
34
+ install Install delegate-skills via official installer and update config
35
+ status Display delegate-skills discovery, detected relays, and lanes
36
+ help Show this help message
37
+
38
+ Examples:
39
+ adaptive-director delegate install
40
+ adaptive-director delegate status
41
+ `);
42
+ process.exit(0);
43
+ }
44
+
45
+ if (subcmd === 'install') {
46
+ const setupScript = join(__dirname, 'setup.mjs');
47
+ const forwardArgs = [setupScript, '--with-delegate', '--delegate-only', ...args.slice(1)];
48
+ const res = spawnSync(process.execPath, forwardArgs, {
49
+ stdio: 'inherit',
50
+ env: process.env,
51
+ });
52
+ process.exit(res.status ?? 0);
53
+ }
54
+
55
+ if (subcmd === 'status') {
56
+ console.log('\nAdaptive Director — Delegate Integration Status\n');
57
+
58
+ const configPath = join(homedir(), '.adaptive-director', 'config.json');
59
+ let config = {};
60
+ if (existsSync(configPath)) {
61
+ try {
62
+ config = JSON.parse(readFileSync(configPath, 'utf8'));
63
+ } catch {}
64
+ }
65
+
66
+ const discovery = run(join(__dirname, 'discover.mjs'));
67
+ const ds = discovery?.delegateSkills ?? { installed: false, relays: [], lanes: {} };
68
+
69
+ console.log(` Installed: ${ds.installed ? 'Yes' : 'No'}`);
70
+ console.log(` Config execution: ${config.execution || 'native'}`);
71
+ console.log(` Config enabled: ${config.delegate?.enabled ?? config.delegateEnabled ?? false}`);
72
+ if (config.delegate?.lastInstallAttempt) {
73
+ console.log(` Last install attempt: ${config.delegate.lastInstallAttempt}`);
74
+ }
75
+
76
+ const skills = ds.skills ?? ds.relays ?? [];
77
+ const relays = ds.relays ?? [];
78
+ console.log(`\n Detected Delegate Skills (${skills.length}):`);
79
+ if (skills.length > 0) {
80
+ for (const s of skills) {
81
+ const isRelay = relays.includes(s);
82
+ console.log(` - ${s}${isRelay ? ' (execution relay)' : ''}`);
83
+ }
84
+ } else {
85
+ console.log(' (none detected)');
86
+ }
87
+
88
+ const lanes = ds.lanes ?? {};
89
+ const laneKeys = Object.keys(lanes);
90
+ console.log(`\n Active Execution Lanes (${laneKeys.length}):`);
91
+ if (laneKeys.length > 0) {
92
+ for (const k of laneKeys) {
93
+ const lane = lanes[k];
94
+ console.log(` - ${k}: agent=${lane.agent || lane.implementer || 'unknown'}${lane.model ? `, model=${lane.model}` : ''}`);
95
+ }
96
+ } else {
97
+ console.log(' (none configured)');
98
+ }
99
+
100
+ console.log('');
101
+ process.exit(0);
102
+ }
103
+
104
+ console.error(`Unknown delegate subcommand: ${subcmd}`);
105
+ console.log(`Run 'adaptive-director delegate help' for usage.`);
106
+ process.exit(1);
@@ -13,9 +13,10 @@
13
13
  */
14
14
 
15
15
  import { execFileSync, execSync } from 'node:child_process'
16
- import { existsSync, readFileSync } from 'node:fs'
16
+ import { existsSync, readFileSync, readdirSync } from 'node:fs'
17
17
  import { join } from 'node:path'
18
18
  import { homedir } from 'node:os'
19
+ import { discoverHostModels } from '../skills/adaptive-director/scripts/discover-models.mjs'
19
20
 
20
21
  // ─── Known agents ─────────────────────────────────────────────────────────────
21
22
 
@@ -88,19 +89,113 @@ function readFleet(path) {
88
89
  }
89
90
  }
90
91
 
92
+ function readJsonConfig(path) {
93
+ if (!existsSync(path)) return null
94
+ try {
95
+ const raw = JSON.parse(readFileSync(path, 'utf8'))
96
+ if (raw.lanes && typeof raw.lanes === 'object') {
97
+ const result = {}
98
+ for (const [lane, def] of Object.entries(raw.lanes)) {
99
+ result[lane] = {
100
+ agent: def.implementer ?? def.agent,
101
+ model: def.model ?? null,
102
+ effort: def.effort ?? def.variant ?? null,
103
+ implementer: def.implementer ?? def.agent,
104
+ }
105
+ }
106
+ return Object.keys(result).length > 0 ? result : null
107
+ }
108
+ } catch {}
109
+ return null
110
+ }
111
+
91
112
  function discoverDelegate() {
92
- const globalPath = join(homedir(), '.delegate', 'fleet.yaml')
93
- const projectPath = join(process.cwd(), '.delegate', 'fleet.yaml')
113
+ const paths = [
114
+ join(process.cwd(), '.delegate', 'fleet.yaml'),
115
+ join(homedir(), '.delegate', 'fleet.yaml'),
116
+ join(process.cwd(), '.delegate', 'config.json'),
117
+ join(homedir(), '.config', 'delegate-skills', 'config.json'),
118
+ ]
119
+
120
+ let lanes = {}
121
+ for (const p of paths) {
122
+ if (p.endsWith('.json')) {
123
+ const jsonLanes = readJsonConfig(p)
124
+ if (jsonLanes) lanes = { ...lanes, ...jsonLanes }
125
+ } else {
126
+ const fleetLanes = readFleet(p)
127
+ if (fleetLanes) lanes = { ...lanes, ...fleetLanes }
128
+ }
129
+ }
94
130
 
95
- const globalLanes = readFleet(globalPath)
96
- const projectLanes = readFleet(projectPath)
131
+ // Check if delegate-skills is installed on disk
132
+ const agentsSkillsDir = join(homedir(), '.agents', 'skills')
133
+ const codexSkillsDir = join(homedir(), '.codex', 'skills')
134
+ const hasAgentsSkills = existsSync(join(agentsSkillsDir, 'delegate-setup')) ||
135
+ existsSync(join(agentsSkillsDir, 'codex-delegate')) ||
136
+ existsSync(join(agentsSkillsDir, 'agy-delegate')) ||
137
+ existsSync(join(codexSkillsDir, 'delegate-review-loop'))
138
+
139
+ let hasSkillLock = false
140
+ const skillLockPath = join(homedir(), '.agents', '.skill-lock.json')
141
+ if (existsSync(skillLockPath)) {
142
+ try {
143
+ const lockContent = readFileSync(skillLockPath, 'utf8')
144
+ if (lockContent.includes('delegate-skills')) hasSkillLock = true
145
+ } catch {}
146
+ }
97
147
 
98
- if (!globalLanes && !projectLanes) {
99
- return { installed: false, lanes: {} }
148
+ // Detect installed delegate relays across candidate directories
149
+ const relayDirs = [
150
+ agentsSkillsDir,
151
+ codexSkillsDir,
152
+ join(process.cwd(), '.agents', 'skills'),
153
+ join(process.cwd(), 'delegate-skills', 'skills'),
154
+ join(homedir(), '.skills', 'amElnagdy', 'delegate-skills', 'skills'),
155
+ ]
156
+ const skillsSet = new Set()
157
+ const relaysSet = new Set()
158
+ for (const dir of relayDirs) {
159
+ if (!existsSync(dir)) continue
160
+ try {
161
+ const entries = readdirSync(dir, { withFileTypes: true })
162
+ for (const entry of entries) {
163
+ if (!entry.isDirectory()) continue
164
+ if (entry.name.endsWith('-delegate') || entry.name === 'delegate-setup' || entry.name.startsWith('delegate-')) {
165
+ skillsSet.add(entry.name)
166
+ if (entry.name.endsWith('-delegate')) {
167
+ relaysSet.add(entry.name)
168
+ }
169
+ }
170
+ }
171
+ } catch {}
100
172
  }
173
+ const skills = Array.from(skillsSet).sort()
174
+ const relays = Array.from(relaysSet).sort()
101
175
 
102
- const merged = { ...(globalLanes ?? {}), ...(projectLanes ?? {}) }
103
- return { installed: true, lanes: merged }
176
+ const installed = Object.keys(lanes).length > 0 || hasAgentsSkills || hasSkillLock || skills.length > 0
177
+
178
+ // If installed but no explicit fleet lanes file configured, synthesize lanes from installed delegate skills
179
+ if (installed && Object.keys(lanes).length === 0 && (hasAgentsSkills || relays.length > 0)) {
180
+ if (relays.includes('codex-delegate') || existsSync(join(agentsSkillsDir, 'codex-delegate'))) {
181
+ lanes.feature = { agent: 'codex', implementer: 'codex' }
182
+ lanes.implement = { agent: 'codex', implementer: 'codex' }
183
+ lanes.fix = { agent: 'codex', implementer: 'codex' }
184
+ }
185
+ if (relays.includes('agy-delegate') || existsSync(join(agentsSkillsDir, 'agy-delegate'))) {
186
+ lanes.plan = { agent: 'agy', implementer: 'agy' }
187
+ lanes.review = { agent: 'agy', implementer: 'agy' }
188
+ lanes.verify = { agent: 'agy', implementer: 'agy' }
189
+ }
190
+ }
191
+
192
+ return {
193
+ installed,
194
+ lanes,
195
+ skills,
196
+ relays,
197
+ source: hasSkillLock ? 'amElnagdy/delegate-skills' : (hasAgentsSkills ? 'local-skills' : (Object.keys(lanes).length > 0 ? 'fleet-config' : (skills.length > 0 ? 'detected-skills' : null)))
198
+ }
104
199
  }
105
200
 
106
201
  // ─── Main ─────────────────────────────────────────────────────────────────────
@@ -128,11 +223,12 @@ function discover() {
128
223
  }
129
224
 
130
225
  agents[desc.id] = {
131
- installed: true,
132
- available: version !== null,
133
- version: version ?? 'unknown',
134
- skillPath: detectedSkillPath,
135
- hasSkill: detectedSkillPath ? existsSync(join(detectedSkillPath, 'adaptive-director')) || existsSync(join(detectedSkillPath, 'Adaptive-Director')) || existsSync(join(detectedSkillPath, 'adaptive-director-skill')) : false
226
+ installed: true,
227
+ available: version !== null,
228
+ version: version ?? 'unknown',
229
+ skillPath: detectedSkillPath,
230
+ hasSkill: detectedSkillPath ? existsSync(join(detectedSkillPath, 'adaptive-director')) || existsSync(join(detectedSkillPath, 'Adaptive-Director')) || existsSync(join(detectedSkillPath, 'adaptive-director-skill')) : false,
231
+ availableModels: discoverHostModels(desc.id),
136
232
  }
137
233
  }
138
234
 
@@ -7,11 +7,12 @@ import { fileURLToPath } from 'node:url';
7
7
 
8
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
9
 
10
- function run(script, args = []) {
10
+ function run(script, args = [], env = process.env) {
11
11
  try {
12
12
  const out = execFileSync(process.execPath, [script, ...args], {
13
13
  encoding: 'utf8', timeout: 15000,
14
14
  cwd: process.cwd(),
15
+ env,
15
16
  });
16
17
  return JSON.parse(out.trim());
17
18
  } catch {
@@ -65,9 +66,10 @@ if (check('Registry exists', existsSync(registryPath))) {
65
66
  }
66
67
 
67
68
  // ── Config ────────────────────────────────────────────────────────────────
69
+ let configObj = null;
68
70
  if (check('Config exists', existsSync(configPath), 'adaptive-director setup')) {
69
71
  try {
70
- JSON.parse(readFileSync(configPath, 'utf8'));
72
+ configObj = JSON.parse(readFileSync(configPath, 'utf8'));
71
73
  check('Config valid', true);
72
74
  } catch {
73
75
  allGood &= check('Config valid', false, 'rm ~/.adaptive-director/config.json && adaptive-director setup');
@@ -99,7 +101,7 @@ allGood &= check('Resume script exists', existsSync(join(skillRoot, 'scripts'
99
101
 
100
102
  // ── Host discovery ────────────────────────────────────────────────────────
101
103
  console.log('');
102
- const discovery = run(join(__dirname, 'discover.mjs'));
104
+ const discovery = run(join(__dirname, 'discover.mjs'), [], process.env);
103
105
  if (discovery) {
104
106
  let anyHost = false;
105
107
  for (const [id, info] of Object.entries(discovery.agents ?? {})) {
@@ -122,11 +124,18 @@ if (discovery) {
122
124
  if (!anyHost) warn('No supported hosts detected');
123
125
 
124
126
  console.log('');
125
- const ds = discovery.delegateSkills ?? { installed: false };
127
+ const ds = discovery.delegateSkills ?? { installed: false, skills: [], relays: [], lanes: {} };
126
128
  if (ds.installed) {
127
- check(`delegate-skills detected (${Object.keys(ds.lanes ?? {}).length} lane(s))`, true);
129
+ const skillCount = (ds.skills ?? ds.relays ?? []).length;
130
+ const laneCount = Object.keys(ds.lanes ?? {}).length;
131
+ check(`delegate-skills detected (${skillCount} delegate skill(s), ${laneCount} lane(s))`, true);
128
132
  } else {
129
- warn('delegate-skills not detected (optional)');
133
+ warn('delegate-skills not detected (optional — native execution active)');
134
+ if (configObj?.delegate?.lastInstallAttempt === 'failed') {
135
+ warn('Last delegate-skills install attempt failed (run "adaptive-director delegate install" to retry)');
136
+ } else if (configObj?.delegate?.lastInstallAttempt === 'unverified') {
137
+ warn('delegate-skills installation unverified: no relays detected');
138
+ }
130
139
  }
131
140
  } else {
132
141
  allGood &= check('Discovery script works', false, 'Check Node version or reinstall');
@@ -7,11 +7,12 @@ import { fileURLToPath } from 'node:url';
7
7
 
8
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
9
 
10
- function run(script, args = []) {
10
+ function run(script, args = [], env = process.env) {
11
11
  try {
12
12
  const out = execFileSync(process.execPath, [script, ...args], {
13
13
  encoding: 'utf8', timeout: 15000,
14
14
  cwd: process.cwd(),
15
+ env,
15
16
  });
16
17
  return JSON.parse(out.trim());
17
18
  } catch (e) {
@@ -24,7 +25,7 @@ const configPath = join(configDir, 'config.json');
24
25
 
25
26
  console.log('Refreshing Adaptive Director config...\n');
26
27
 
27
- const discovery = run(join(__dirname, 'discover.mjs'));
28
+ const discovery = run(join(__dirname, 'discover.mjs'), [], process.env);
28
29
  if (!discovery) {
29
30
  console.error('✗ Discovery failed.');
30
31
  process.exit(1);
@@ -39,11 +40,20 @@ if (existsSync(configPath)) {
39
40
  }
40
41
  }
41
42
 
43
+ const delegateInstalled = Boolean(discovery.delegateSkills?.installed);
44
+ const delegateEnabled = existingConfig.delegate?.enabled ?? existingConfig.delegateEnabled ?? false;
45
+
42
46
  const config = {
43
47
  version: 1,
48
+ execution: existingConfig.execution || 'native',
44
49
  defaultBudget: existingConfig.defaultBudget || 'balanced',
45
50
  allowMax: existingConfig.allowMax || false,
46
- delegateEnabled: existingConfig.delegateEnabled || false,
51
+ delegateEnabled,
52
+ delegate: {
53
+ installed: delegateInstalled,
54
+ enabled: delegateEnabled,
55
+ ...(existingConfig.delegate?.lastInstallAttempt ? { lastInstallAttempt: existingConfig.delegate.lastInstallAttempt } : {})
56
+ },
47
57
  hosts: {},
48
58
  overrides: existingConfig.overrides || {}
49
59
  };
@@ -51,6 +61,7 @@ const config = {
51
61
  for (const [id, info] of Object.entries(discovery.agents ?? {})) {
52
62
  if (info.installed) {
53
63
  config.hosts[id] = {
64
+ ...existingConfig.hosts?.[id],
54
65
  enabled: existingConfig.hosts?.[id]?.enabled ?? true,
55
66
  skillPath: info.skillPath
56
67
  };