cli-five 0.1.6 → 0.2.2

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
@@ -2,21 +2,38 @@
2
2
 
3
3
  > **Code Like I'm Five** — scaffold a 5-agent VS Code Copilot team into any repo.
4
4
 
5
+ ## Two ways to install
6
+
7
+ ### Full setup (recommended for teams)
8
+
5
9
  ```bash
6
10
  npx cli-five init
7
11
  ```
8
12
 
9
- That's it. Run it in any folder. It interviews you, scaffolds `.github/agents/` + project memory files, searches skills.sh for relevant skills, and tells you what to do next.
13
+ Interviews you, scaffolds agents + memory files + stack-specific instructions, discovers skills from **awesome-copilot** and **skills.sh**, and tells you what to do next.
14
+
15
+ ### Quick plugin install (personal use)
16
+
17
+ ```
18
+ copilot plugin install idusortus/cli-five
19
+ ```
20
+
21
+ Installs the 5 agents to your Copilot profile. No project config, no interview — just the agents with sensible defaults.
10
22
 
11
23
  ## What you get
12
24
 
13
25
  ```
14
26
  your-repo/
15
27
  ├── .github/
16
- │ ├── agents/ # 5 agents: Orchestrator, Planner, Coder, Designer, Reviewer
28
+ │ ├── agents/ # 5 agents with handoffs + subagent delegation
29
+ │ │ ├── orchestrator.agent.md # 📋 Plan 💻 Code 🎨 Design 🔍 Review
30
+ │ │ ├── planner.agent.md # 🎯 Execute 💻 Code Directly
31
+ │ │ ├── coder.agent.md # 🔍 Review 🎯 Back to Orchestrator
32
+ │ │ ├── designer.agent.md # 🔍 Review 🎯 Back to Orchestrator
33
+ │ │ └── reviewer.agent.md # 🎯 Back to Orchestrator 💻 Fix Issues
17
34
  │ ├── copilot-instructions.md # Persona + project mandates from interview
18
- │ ├── instructions/ # Empty — populate via /agent-customization in chat
19
- │ └── skills/ # Empty — populate via skills.sh
35
+ │ ├── instructions/ # Stack-specific coding guidelines
36
+ │ └── skills/ # Installed skills from awesome-copilot + skills.sh
20
37
  ├── AGENTS.md # Tool-agnostic project context (agents.md standard)
21
38
  ├── PROJECT.md # Long-form vision (rarely changes)
22
39
  ├── STATE.md # Cross-session status (changes constantly)
@@ -25,6 +42,15 @@ your-repo/
25
42
  └── histories/ # Per-agent accumulated learnings
26
43
  ```
27
44
 
45
+ ## Orchestration modes
46
+
47
+ The Orchestrator supports **both** delegation patterns:
48
+
49
+ - **Handoff buttons** — Click `📋 Plan`, `💻 Code`, `🎨 Design`, or `🔍 Review` to manually transition between agents with pre-filled context.
50
+ - **Subagent delegation** — Ask the Orchestrator to handle a complex task and it calls Planner → Coder → Reviewer autonomously.
51
+
52
+ Each specialist also has handoffs: Coder/Designer → Reviewer, Reviewer → Coder (fix loop), and everyone → back to Orchestrator.
53
+
28
54
  ## Commands
29
55
 
30
56
  ```bash
@@ -51,9 +77,10 @@ npx cli-five help
51
77
  2. **git init** — if needed. Asks first.
52
78
  3. **Overwrite gate** — double-confirms ("Proceed?" then "R U Sure?"). Only `--force --yes` bypasses.
53
79
  4. **Interview** — name, one-liner, stack, frameworks, goals, constraints, cost mode, persona toggle.
54
- 5. **Scaffold** — writes 18 files. Substitutes answers into templates. Swaps `model:` per cost mode.
55
- 6. **Skill discovery** — queries skills.sh via `npx skills find <term>` per detected stack. Recommends known-good skills, offers multiselect install, and launches interactive browser.
56
- 7. **Next steps** — tells you to run `/agent-customization` for stack-specific instructions.
80
+ 5. **Scaffold** — writes 18 files. Substitutes answers into templates. Swaps `model:` per cost mode. Adds `handoffs:` to all agents.
81
+ 6. **Skill discovery** — the hero feature. Multi-source discovery from **awesome-copilot** (30k+ ★ community marketplace) and **skills.sh**. Color-coded recommendations, source attribution, multiselect install, and post-install breadcrumbs with copy-paste commands for the awesome-copilot suggestion skill and MCP server.
82
+ 7. **Custom instructions** — generates stack-specific `.instructions.md` files for detected languages.
83
+ 8. **Next steps** — tells you to use handoff buttons or autonomous mode, offers plugin install shortcut.
57
84
 
58
85
  ## Cost modes
59
86
 
@@ -76,6 +103,21 @@ Change anytime by editing the `model:` line in `.github/agents/*.agent.md`.
76
103
  }
77
104
  ```
78
105
 
106
+ ## Skill discovery
107
+
108
+ cli-five searches **two sources** for skills matching your detected stack:
109
+
110
+ | Source | What it has | Stars |
111
+ |---|---|---|
112
+ | **awesome-copilot** | Skills, instructions, agents, plugins from the GitHub community | 30k+ |
113
+ | **skills.sh** | Curated skill repos (Vercel, Anthropic, Microsoft, etc.) | — |
114
+
115
+ Recommendations show with source attribution and are pre-selected for one-click install. After installation, you get breadcrumbs for ongoing discovery:
116
+
117
+ - **Suggest skill** — `copilot plugin install awesome-copilot@suggest` (AI-driven repo analysis)
118
+ - **MCP server** — `awesome-copilot-mcp` for programmatic search from any agent
119
+ - **CLI browser** — `npx skills find` for interactive search
120
+
79
121
  ## What this is not
80
122
 
81
123
  - **Not a runtime.** Once scaffolded, your repo doesn't depend on `cli-five`. You can uninstall the package and the agents still work.
@@ -95,8 +137,8 @@ ELI5 → CLI5. Code Like I'm Five. Five agents. Get it? Yeah, it's a stretch. Bu
95
137
  ## Local development
96
138
 
97
139
  ```bash
98
- git clone https://github.com/idusortus/squad-mine
99
- cd squad-mine
140
+ git clone https://github.com/idusortus/cli-five
141
+ cd cli-five
100
142
  npm install
101
143
  node bin/cli-five.mjs init --cwd /tmp/test-target
102
144
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli-five",
3
- "version": "0.1.6",
3
+ "version": "0.2.2",
4
4
  "description": "Code Like I'm Five — scaffold a 5-agent VS Code Copilot team into any repo.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,8 @@
10
10
  "bin",
11
11
  "src",
12
12
  "templates",
13
+ "plugin-agents",
14
+ "plugin.json",
13
15
  "README.md",
14
16
  "LICENSE"
15
17
  ],
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: Coder
3
+ description: "Writes production code following workspace conventions. Use when: implementing features, fixing bugs, writing tests."
4
+ model: GPT-5.3-Codex (copilot)
5
+ tools: ['vscode', 'execute', 'read', 'github/*', 'edit', 'search', 'web', 'vscode/memory', 'todo']
6
+ agents: []
7
+ handoffs:
8
+ - label: "🔍 Review"
9
+ agent: Reviewer
10
+ prompt: "Review the changes I just made for correctness and conventions."
11
+ send: false
12
+ - label: "🎯 Back to Orchestrator"
13
+ agent: Orchestrator
14
+ prompt: "Implementation complete. Coordinate next steps."
15
+ send: false
16
+ ---
17
+
18
+ ## Mandatory Coding Principles
19
+
20
+ 1. **Structure** — Consistent layout. Group by feature. Shared patterns over duplication.
21
+ 2. **Architecture** — Flat, explicit code. No clever patterns or unnecessary indirection.
22
+ 3. **Functions** — Linear control flow. Small-to-medium functions. Pass state explicitly.
23
+ 4. **Naming** — Descriptive-but-simple names. Comment only for invariants or assumptions.
24
+ 5. **Logging** — Detailed, structured logs at key boundaries. Explicit errors.
25
+ 6. **Regenerability** — Any file can be rewritten from scratch without breaking the system.
26
+ 7. **Platform** — Use framework conventions directly and simply.
27
+ 8. **Quality** — Deterministic, testable behavior. Simple, focused tests.
28
+
29
+ ## Rules
30
+
31
+ - Follow existing patterns in the codebase
32
+ - Your final message MUST list every file created or modified
33
+ - Include build/test status if you ran them
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Designer
3
+ description: "Handles all UI/UX design tasks. Use when: creating screens, layouts, theming, navigation flows, design systems."
4
+ model: Claude Opus 4.6 (copilot)
5
+ tools: ['read', 'edit', 'search', 'web', 'vscode/memory']
6
+ agents: []
7
+ handoffs:
8
+ - label: "🔍 Review"
9
+ agent: Reviewer
10
+ prompt: "Review the UI changes for accessibility, conventions, and design quality."
11
+ send: false
12
+ - label: "🎯 Back to Orchestrator"
13
+ agent: Orchestrator
14
+ prompt: "Design work complete. Coordinate next steps."
15
+ send: false
16
+ ---
17
+
18
+ ## Design Principles
19
+
20
+ - Accessibility first: contrast ratios, touch targets, screen reader support
21
+ - Minimal cognitive load
22
+ - Platform conventions over custom patterns
23
+ - Responsive/adaptive layouts
24
+ - Use the project's designated design system and component library
25
+
26
+ ## Rules
27
+
28
+ - Your final message MUST list every UI file created or modified
29
+ - Include design decisions and accessibility choices applied
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: Orchestrator
3
+ description: "Coordinates multi-agent workflows. Delegates to Planner, Coder, Designer, and Reviewer. Use when: complex multi-step tasks, cross-cutting changes, feature implementation."
4
+ model: Claude Sonnet 4.6 (copilot)
5
+ tools: ['read/readFile', 'agent', 'vscode/memory', 'github/*']
6
+ agents: ['Planner', 'Coder', 'Designer', 'Reviewer']
7
+ handoffs:
8
+ - label: "📋 Plan"
9
+ agent: Planner
10
+ prompt: "Research the codebase and create an implementation plan for this task."
11
+ send: false
12
+ - label: "💻 Code"
13
+ agent: Coder
14
+ prompt: "Implement the approved plan."
15
+ send: false
16
+ - label: "🎨 Design"
17
+ agent: Designer
18
+ prompt: "Design the UI components described in the plan."
19
+ send: false
20
+ - label: "🔍 Review"
21
+ agent: Reviewer
22
+ prompt: "Review the implementation for correctness, conventions, and architecture."
23
+ send: false
24
+ ---
25
+
26
+ You are a project orchestrator. You break down complex requests into tasks and delegate to specialist subagents. You coordinate work but NEVER implement anything yourself.
27
+
28
+ ## Agents
29
+
30
+ | Agent | Role |
31
+ |---|---|
32
+ | **Planner** | Research codebase, check docs, create implementation plans |
33
+ | **Coder** | Write code, fix bugs, implement features |
34
+ | **Designer** | UI/UX design, layouts, theming |
35
+ | **Reviewer** | Review agent output for correctness and conventions |
36
+
37
+ ## Execution Model
38
+
39
+ 1. **Get the Plan** — Call Planner unless a plan is already in context or the task is trivial.
40
+ 2. **Parse Into Phases** — Group non-overlapping files into parallel phases. Dependencies go sequential.
41
+ 3. **Execute Each Phase** — Call appropriate agents. Never assign overlapping files to parallel tasks.
42
+ 4. **Review (MANDATORY)** — Call Reviewer. Max 2 fix-review rounds.
43
+ 5. **Report** — Summarize what was completed and the review verdict.
44
+
45
+ ## Rules
46
+
47
+ - Delegate WHAT (outcomes), never HOW (implementation details).
48
+ - Never assign overlapping files to agents in the same phase.
49
+ - Never implement anything yourself — you are a router, not a worker.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: Planner
3
+ description: "Creates implementation plans by researching the codebase, consulting documentation, and identifying edge cases."
4
+ model: Claude Opus 4.6 (copilot)
5
+ tools: ['read', 'search', 'web', 'vscode/memory']
6
+ user-invocable: false
7
+ handoffs:
8
+ - label: "🎯 Execute Plan"
9
+ agent: Orchestrator
10
+ prompt: "Plan is ready. Execute it phase by phase."
11
+ send: false
12
+ - label: "💻 Code Directly"
13
+ agent: Coder
14
+ prompt: "Implement this plan."
15
+ send: false
16
+ ---
17
+
18
+ # Planning Agent
19
+
20
+ You create plans. You do NOT write code.
21
+
22
+ ## Workflow
23
+
24
+ 1. **Research**: Search the codebase thoroughly. Read relevant files. Find existing patterns.
25
+ 2. **Verify**: Use web tools to check documentation for libraries/APIs involved.
26
+ 3. **Consider**: Identify edge cases, error states, and implicit requirements.
27
+ 4. **Plan**: Output WHAT needs to happen, not HOW to code it.
28
+
29
+ ## Output Format
30
+
31
+ - **Summary** (one paragraph)
32
+ - **Implementation steps** (ordered), each with file assignments and dependencies
33
+ - **Edge cases** to handle
34
+ - **Open questions** (if any)
35
+ - **Suggested phase grouping** (which steps can be parallelized)
36
+
37
+ ## Rules
38
+
39
+ - Never skip documentation checks for external APIs
40
+ - Note uncertainties — don't hide them
41
+ - Match existing codebase patterns
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: Reviewer
3
+ description: "Reviews code and agent output for correctness, convention compliance, and architectural alignment."
4
+ model: Claude Opus 4.6 (copilot)
5
+ tools: ['read', 'search', 'web', 'vscode/memory']
6
+ agents: []
7
+ user-invocable: true
8
+ handoffs:
9
+ - label: "🎯 Back to Orchestrator"
10
+ agent: Orchestrator
11
+ prompt: "Review complete. See verdict above. Coordinate fixes or proceed."
12
+ send: false
13
+ - label: "💻 Fix Issues"
14
+ agent: Coder
15
+ prompt: "Fix the issues identified in the review above."
16
+ send: false
17
+ ---
18
+
19
+ ## Identity
20
+
21
+ You are a code reviewer. You do NOT write code, fix things, or make changes. You READ, SEARCH, JUDGE, and REPORT.
22
+
23
+ ## Review Checklist
24
+
25
+ 1. **Workspace instructions** — Verify compliance with `.github/instructions/`
26
+ 2. **Architecture docs** — Verify component placement and boundaries
27
+ 3. **General quality** — OWASP Top 10, no leaked secrets, error handling, testability
28
+
29
+ ## Review Output Format
30
+
31
+ ```
32
+ ## Review Summary
33
+ **Verdict:** PASS | PASS WITH NOTES | NEEDS CHANGES | REJECT
34
+
35
+ ### Critical (must fix)
36
+ - [ ] Finding with file reference and line number
37
+
38
+ ### Warnings (should fix)
39
+ - [ ] Finding with file reference and line number
40
+
41
+ ### Notes
42
+ - Observations and suggestions
43
+
44
+ ### What was done well
45
+ - Positive observations
46
+ ```
47
+
48
+ ## Rules
49
+
50
+ - NEVER approve code you haven't read
51
+ - Be specific: file path, line number, what's wrong, what should change
52
+ - If the code is good, say so. Don't invent problems.
package/plugin.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "cli-five",
3
+ "description": "5-agent orchestration squad for GitHub Copilot — Orchestrator, Planner, Coder, Designer, Reviewer.",
4
+ "version": "0.2.0",
5
+ "author": {
6
+ "name": "idusortus"
7
+ },
8
+ "agents": "plugin-agents/",
9
+ "repository": "https://github.com/idusortus/cli-five"
10
+ }
@@ -93,11 +93,15 @@ function printNextSteps(answers) {
93
93
  log.raw(` 2. Enable Copilot subagent invocations (settings.json):`);
94
94
  log.raw(kleur.gray(` "chat.subagents.allowInvocationsFromSubagents": true`));
95
95
  log.raw(` 3. Open Copilot Chat — select an agent from the dropdown (${kleur.bold('not')} @mention).`);
96
- log.raw(` 4. Select ${kleur.bold('Orchestrator')} from the dropdown, then ask:`);
97
- log.raw(kleur.gray(` read PROJECT.md and propose Phase 1.`));
98
- log.raw(` 5. Review generated instruction files in .github/instructions/.`);
96
+ log.raw(` 4. Select ${kleur.bold('Orchestrator')} — use handoff buttons or ask it to delegate:`);
97
+ log.raw(kleur.gray(` 📋 Plan 💻 Code 🎨 Design 🔍 Review`));
98
+ log.raw(` 5. Or go autonomous:`);
99
+ log.raw(kleur.gray(` read PROJECT.md and implement Phase 1.`));
100
+ log.raw(` 6. Review generated instruction files in .github/instructions/.`);
99
101
  log.raw(kleur.gray(` Edit applyTo globs and guidelines to fit your project.`));
100
- log.raw(kleur.gray(` Installed skills are in .agents/skills/ (from skills.sh).`));
102
+ log.raw('');
103
+ log.raw(kleur.dim(' Quick plugin install (personal, no project config):'));
104
+ log.raw(kleur.dim(' copilot plugin install idusortus/cli-five'));
101
105
  log.raw('');
102
106
  log.raw(kleur.dim('Edit cost mode anytime by changing `model:` in .github/agents/*.agent.md.'));
103
107
  log.raw('');
@@ -6,6 +6,14 @@ import prompts from 'prompts';
6
6
  // Research via Context7: Next.js, Vite+React, Express, Hono all score
7
7
  // 80+ benchmark with high snippet counts and well-indexed docs.
8
8
  const STACK_PRESETS = [
9
+ {
10
+ title: 'Next.js + Supabase PWA (TypeScript)',
11
+ value: 'nextjs-supabase',
12
+ description: 'Next.js 15 static export, React 19, Tailwind v4, Supabase, SWR, Vercel hosting, PWA.',
13
+ stack: ['Node + TypeScript'],
14
+ frameworks: ['Next.js', 'React', 'Tailwind CSS', 'Supabase', 'SWR'],
15
+ quickstart: 'npx create-next-app@latest . --yes && npm i @supabase/supabase-js swr date-fns clsx && npm run dev',
16
+ },
9
17
  {
10
18
  title: 'Next.js (TypeScript)',
11
19
  value: 'nextjs',
@@ -1,11 +1,16 @@
1
1
  import prompts from 'prompts';
2
+ import kleur from 'kleur';
2
3
  import { spawn, execFileSync } from 'node:child_process';
3
4
  import { existsSync, mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs';
4
5
  import { join, dirname } from 'node:path';
5
6
  import { createRequire } from 'node:module';
6
7
  import { log } from '../util/log.mjs';
7
8
 
8
- // Well-known skill repos matched by stack term → repo + suggested skill names
9
+ // ── Known-good skill repos (verified working) ────────────────────────
10
+ // awesome-copilot skills are discovered dynamically via `skills find`.
11
+ const AWESOME_COPILOT_REPO = 'github/awesome-copilot';
12
+
13
+ // Well-known skill repos matched by stack term → repo + suggested skill names (skills.sh)
9
14
  const SKILL_CATALOG = [
10
15
  { terms: ['*'], repo: 'anthropics/skills', skills: ['frontend-design', 'skill-creator'] },
11
16
  { terms: ['*'], repo: 'vercel-labs/agent-skills', skills: ['vercel-react-best-practices', 'web-design-guidelines'] },
@@ -109,6 +114,7 @@ export async function skillDiscovery({ cwd, answers, args }) {
109
114
  if (!env) {
110
115
  log.warn('Cannot run skills CLI: no bundled binary, pnpm, or npx found.');
111
116
  log.warn('Install Node.js (includes npx) or pnpm, then re-run.');
117
+ printBreadcrumbs();
112
118
  return;
113
119
  }
114
120
 
@@ -131,73 +137,139 @@ export async function skillDiscovery({ cwd, answers, args }) {
131
137
  }
132
138
 
133
139
  log.ok(`Running skills via ${env.label}`);
134
- log.raw('');
135
140
 
136
- // ── Skill discovery ─────────────────────────────────────────────────
137
-
138
- // 1. Build recommendations from catalog based on stack
139
- const recs = buildRecommendations(answers);
140
- if (recs.length === 0) {
141
- log.dim('No stack-specific recommendations found.');
142
- } else {
143
- log.raw(` ${pad('Skill', 36)} ${pad('Repo', 36)}`);
144
- log.raw(` ${'─'.repeat(36)} ${'─'.repeat(36)}`);
145
- for (const r of recs) {
146
- log.raw(` ${pad(r.skill, 36)} ${pad(r.repo, 36)}`);
147
- }
148
- log.raw('');
149
- }
150
-
151
- // 2. Offer interactive search per stack term
141
+ // ── 1. Auto-search all stack terms silently ─────────────────────────
152
142
  const terms = suggestSearches(answers);
143
+ const searchResults = [];
144
+
153
145
  if (terms.length > 0) {
154
- log.dim(`Suggested searches: ${terms.map((t) => `"${t}"`).join(', ')}`);
155
146
  log.raw('');
147
+ log.info(`Searching skills.sh for: ${terms.map((t) => kleur.bold(t)).join(', ')} ...`);
148
+ for (const term of terms) {
149
+ const output = await runSkillsSilent(env, ['find', term], cwd);
150
+ searchResults.push(...parseSkillRefs(output));
151
+ }
152
+ if (searchResults.length > 0) {
153
+ log.ok(`Found ${searchResults.length} skill${searchResults.length > 1 ? 's' : ''} from search.`);
154
+ } else {
155
+ log.dim('No additional skills found via search.');
156
+ }
156
157
  }
157
158
 
158
- for (const term of terms) {
159
- const { go } = await prompts({
160
- type: 'confirm',
161
- name: 'go',
162
- message: `Search skills.sh for "${term}"?`,
163
- initial: true,
164
- });
165
- if (go) {
166
- await runSkills(env, ['find', term], cwd);
159
+ // ── 2. Build static catalog recommendations ─────────────────────────
160
+ const catalogRecs = buildRecommendations(answers);
161
+
162
+ // ── 3. Categorize search results by source ──────────────────────────
163
+ const awesomeResults = [];
164
+ const otherResults = [];
165
+ for (const r of searchResults) {
166
+ const parsed = parseRef(r.ref);
167
+ if (parsed && parsed.repo === AWESOME_COPILOT_REPO) {
168
+ awesomeResults.push({ ...r, ...parsed });
169
+ } else {
170
+ otherResults.push(r);
167
171
  }
168
172
  }
169
173
 
170
- // 3. Offer to install from well-known repos
171
- if (recs.length > 0) {
172
- const { install } = await prompts({
174
+ // ── 4. Display hero section ─────────────────────────────────────────
175
+ displayHeroRecommendations(awesomeResults, catalogRecs, answers);
176
+
177
+ // ── 5. Build unified picker ─────────────────────────────────────────
178
+ const seen = new Set();
179
+ const choices = [];
180
+
181
+ // awesome-copilot results from search (dynamic, real names)
182
+ for (const r of awesomeResults) {
183
+ const key = r.ref;
184
+ if (seen.has(key)) continue;
185
+ seen.add(key);
186
+ choices.push({
187
+ title: `${kleur.cyan('⬡')} ${r.skill} ${kleur.dim(`(${r.installs})`)} ${kleur.cyan('← awesome-copilot')}`,
188
+ value: { source: 'awesome', repo: r.repo, skill: r.skill, ref: r.ref },
189
+ selected: true,
190
+ });
191
+ }
192
+
193
+ // Static catalog recs (verified repos)
194
+ for (const r of catalogRecs) {
195
+ const ref = `${r.repo}@${r.skill}`;
196
+ if (seen.has(ref)) continue;
197
+ seen.add(ref);
198
+ choices.push({
199
+ title: `${kleur.yellow('◆')} ${r.skill} ${kleur.dim(`(${r.repo})`)} ${kleur.yellow('← skills.sh')}`,
200
+ value: { source: 'catalog', ref, repo: r.repo, skill: r.skill },
201
+ selected: true,
202
+ });
203
+ }
204
+
205
+ // Other search results (non-awesome-copilot)
206
+ for (const r of otherResults) {
207
+ if (seen.has(r.ref)) continue;
208
+ seen.add(r.ref);
209
+ const parsed = parseRef(r.ref);
210
+ choices.push({
211
+ title: `${kleur.yellow('◆')} ${parsed ? parsed.skill : r.ref} ${kleur.dim(`(${parsed ? parsed.repo : ''} — ${r.installs})`)} ${kleur.yellow('← skills.sh')}`,
212
+ value: { source: 'search', ref: r.ref, repo: parsed?.repo, skill: parsed?.skill },
213
+ selected: false,
214
+ });
215
+ }
216
+
217
+ // ── 6. Prompt user to select skills ─────────────────────────────────
218
+ const installResults = [];
219
+
220
+ if (choices.length > 0) {
221
+ log.raw('');
222
+ const { toInstall } = await prompts({
173
223
  type: 'multiselect',
174
- name: 'install',
175
- message: 'Install recommended skills?',
176
- choices: recs.map((r) => ({
177
- title: `${r.skill} (${r.repo})`,
178
- value: r,
179
- selected: false,
180
- })),
181
- hint: 'Space to select, Enter to confirm',
224
+ name: 'toInstall',
225
+ message: 'Select skills to install',
226
+ choices,
227
+ hint: 'Space to toggle, Enter to confirm',
182
228
  });
183
229
 
184
- if (install && install.length > 0) {
230
+ if (toInstall && toInstall.length > 0) {
231
+ log.raw('');
232
+
233
+ // Group by repo for batch install
185
234
  const byRepo = new Map();
186
- for (const r of install) {
187
- if (!byRepo.has(r.repo)) byRepo.set(r.repo, []);
188
- byRepo.get(r.repo).push(r.skill);
235
+ const standalone = [];
236
+
237
+ for (const item of toInstall) {
238
+ if (item.repo && item.skill) {
239
+ if (!byRepo.has(item.repo)) byRepo.set(item.repo, []);
240
+ byRepo.get(item.repo).push(item.skill);
241
+ } else if (item.ref) {
242
+ standalone.push(item.ref);
243
+ }
189
244
  }
245
+
246
+ // Batch install per repo
190
247
  for (const [repo, skills] of byRepo) {
191
248
  const skillArgs = skills.flatMap((s) => ['--skill', s]);
192
- log.info(`Installing from ${repo}: ${skills.join(', ')}`);
193
- await runSkills(env, ['add', repo, ...skillArgs, '-a', 'github-copilot'], cwd);
249
+ log.info(`Installing from ${kleur.bold(repo)}: ${skills.join(', ')}`);
250
+ const result = await runSkillsTracked(env, ['add', repo, ...skillArgs, '-a', 'github-copilot'], cwd);
251
+ for (const s of skills) {
252
+ installResults.push({ name: `${repo}@${s}`, ...result });
253
+ }
254
+ }
255
+
256
+ // Standalone refs
257
+ for (const ref of standalone) {
258
+ log.info(`Installing ${ref}...`);
259
+ const result = await runSkillsTracked(env, ['add', ref, '-a', 'github-copilot'], cwd);
260
+ installResults.push({ name: ref, ...result });
194
261
  }
195
262
 
196
263
  await relocateSkills(cwd);
197
264
  }
198
265
  }
199
266
 
200
- // 4. Offer freeform catch-all
267
+ // ── 7. Install summary ──────────────────────────────────────────────
268
+ if (installResults.length > 0) {
269
+ printInstallSummary(installResults);
270
+ }
271
+
272
+ // Offer freeform catch-all
201
273
  const { freeform } = await prompts({
202
274
  type: 'confirm',
203
275
  name: 'freeform',
@@ -209,10 +281,143 @@ export async function skillDiscovery({ cwd, answers, args }) {
209
281
  await relocateSkills(cwd);
210
282
  }
211
283
 
212
- log.dim('Done. Run `npx skills find` anytime to discover more.');
284
+ // ── Post-install breadcrumbs (THE HERO FINISH) ──────────────────────
285
+ printBreadcrumbs();
286
+ }
287
+
288
+ // ── Hero display ──────────────────────────────────────────────────────
289
+
290
+ function displayHeroRecommendations(awesomeResults, catalogRecs, answers) {
291
+ const stackLabel = [...(answers.stack || []), ...(answers.frameworks || [])].join(', ') || 'general';
292
+
293
+ log.raw('');
294
+ log.raw(kleur.bold().cyan(' ╔══════════════════════════════════════════════════════════════════╗'));
295
+ log.raw(kleur.bold().cyan(' ║') + kleur.bold(' 📦 RECOMMENDED FOR YOUR STACK: ') + kleur.bold().white(stackLabel) + pad('', Math.max(0, 30 - stackLabel.length)) + kleur.bold().cyan(' ║'));
296
+ log.raw(kleur.bold().cyan(' ╚══════════════════════════════════════════════════════════════════╝'));
297
+
298
+ if (awesomeResults.length > 0) {
299
+ log.raw('');
300
+ log.raw(kleur.cyan(' ⬡ Source: awesome-copilot') + kleur.dim(' (github/awesome-copilot · 30k+ ★)'));
301
+ log.raw(kleur.dim(' ─────────────────────────────────────────────────────────'));
302
+ for (const r of awesomeResults) {
303
+ log.raw(` ${kleur.green('✓')} ${pad(r.skill, 38)} ${kleur.dim(r.installs)}`);
304
+ }
305
+ }
306
+
307
+ if (catalogRecs.length > 0) {
308
+ log.raw('');
309
+ log.raw(kleur.yellow(' ◆ Source: skills.sh') + kleur.dim(' (verified repos)'));
310
+ log.raw(kleur.dim(' ─────────────────────────────────────────────────────────'));
311
+ for (const r of catalogRecs) {
312
+ log.raw(` ${kleur.green('✓')} ${pad(r.skill, 38)} ${kleur.dim(r.repo)}`);
313
+ }
314
+ }
315
+
316
+ log.raw('');
213
317
  }
214
318
 
215
- // ── Relocation ─────────────────────────────────────────────────────────
319
+ // ── Install summary ───────────────────────────────────────────────────
320
+
321
+ function printInstallSummary(results) {
322
+ const succeeded = results.filter((r) => r.ok);
323
+ const failed = results.filter((r) => !r.ok);
324
+
325
+ log.raw('');
326
+ if (succeeded.length > 0) {
327
+ log.ok(`Installed ${succeeded.length} skill${succeeded.length > 1 ? 's' : ''} successfully.`);
328
+ }
329
+
330
+ if (failed.length > 0) {
331
+ log.raw('');
332
+ log.warn(`${failed.length} skill${failed.length > 1 ? 's' : ''} failed to install:`);
333
+ for (const f of failed) {
334
+ log.raw(` ${kleur.red('✗')} ${f.name}`);
335
+ if (f.reason) {
336
+ log.raw(` ${kleur.dim(f.reason)}`);
337
+ }
338
+ }
339
+ log.raw('');
340
+ log.dim('Install failed skills manually: npx skills add <owner/repo> --skill <name>');
341
+ }
342
+ }
343
+
344
+ // ── Post-install breadcrumbs ──────────────────────────────────────────
345
+
346
+ function printBreadcrumbs() {
347
+ log.raw('');
348
+ log.raw(kleur.bold().green(' ┌──────────────────────────────────────────────────────────────────┐'));
349
+ log.raw(kleur.bold().green(' │') + kleur.bold(' 🎯 KEEP DISCOVERING — paste into VS Code / Copilot Chat: ') + kleur.bold().green('│'));
350
+ log.raw(kleur.bold().green(' ├──────────────────────────────────────────────────────────────────┤'));
351
+ log.raw(kleur.bold().green(' │') + ' ' + kleur.bold().green('│'));
352
+ log.raw(kleur.bold().green(' │') + ' Add awesome-copilot MCP for ongoing search: ' + kleur.bold().green('│'));
353
+ log.raw(kleur.bold().green(' │') + kleur.white(' Add to .vscode/mcp.json: ') + kleur.bold().green('│'));
354
+ log.raw(kleur.bold().green(' │') + kleur.dim(' "awesome-copilot": { ') + kleur.bold().green('│'));
355
+ log.raw(kleur.bold().green(' │') + kleur.dim(' "command": "npx", ') + kleur.bold().green('│'));
356
+ log.raw(kleur.bold().green(' │') + kleur.dim(' "args": ["-y", "awesome-copilot-mcp"] ') + kleur.bold().green('│'));
357
+ log.raw(kleur.bold().green(' │') + kleur.dim(' } ') + kleur.bold().green('│'));
358
+ log.raw(kleur.bold().green(' │') + ' ' + kleur.bold().green('│'));
359
+ log.raw(kleur.bold().green(' │') + ' Browse skills anytime: ' + kleur.bold().green('│'));
360
+ log.raw(kleur.bold().green(' │') + kleur.white(' npx skills find ') + kleur.bold().green('│'));
361
+ log.raw(kleur.bold().green(' │') + ' ' + kleur.bold().green('│'));
362
+ log.raw(kleur.bold().green(' └──────────────────────────────────────────────────────────────────┘'));
363
+ log.raw('');
364
+ }
365
+
366
+ // ── Runner ─────────────────────────────────────────────────────────────
367
+
368
+ /** Run skills CLI with stdio: inherit (visible to user). */
369
+ function runSkills(env, skillsArgs, cwd) {
370
+ const { cmd, args } = env.runner(skillsArgs);
371
+ return runInteractive(cmd, args, cwd);
372
+ }
373
+
374
+ /** Run skills CLI, capture output, track success/failure. Returns { ok, reason }. */
375
+ function runSkillsTracked(env, skillsArgs, cwd) {
376
+ const { cmd, args } = env.runner(skillsArgs);
377
+ return new Promise((resolve) => {
378
+ let output = '';
379
+ const proc = spawn(cmd, args, { cwd, stdio: ['inherit', 'pipe', 'pipe'] });
380
+ proc.stdout.on('data', (chunk) => {
381
+ const text = chunk.toString();
382
+ process.stdout.write(text);
383
+ output += text;
384
+ });
385
+ proc.stderr.on('data', (chunk) => {
386
+ const text = chunk.toString();
387
+ process.stderr.write(text);
388
+ output += text;
389
+ });
390
+ proc.on('exit', (code) => {
391
+ const clean = stripAnsi(output);
392
+ if (code !== 0 || /failed to clone|installation failed|canceled/i.test(clean)) {
393
+ const reason = extractFailureReason(clean);
394
+ resolve({ ok: false, reason });
395
+ } else {
396
+ resolve({ ok: true, reason: null });
397
+ }
398
+ });
399
+ proc.on('error', (err) => {
400
+ resolve({ ok: false, reason: err.message });
401
+ });
402
+ });
403
+ }
404
+
405
+ /** Run skills CLI silently — capture stdout/stderr without echoing. */
406
+ function runSkillsSilent(env, skillsArgs, cwd) {
407
+ const { cmd, args } = env.runner(skillsArgs);
408
+ return new Promise((resolve) => {
409
+ let output = '';
410
+ const proc = spawn(cmd, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
411
+ proc.stdout.on('data', (chunk) => {
412
+ output += chunk.toString();
413
+ });
414
+ proc.stderr.on('data', (chunk) => {
415
+ output += chunk.toString();
416
+ });
417
+ proc.on('exit', () => resolve(output));
418
+ proc.on('error', () => resolve(''));
419
+ });
420
+ }
216
421
 
217
422
  async function relocateSkills(cwd) {
218
423
  const src = join(cwd, '.agents', 'skills');
@@ -270,12 +475,7 @@ async function relocateSkills(cwd) {
270
475
  }
271
476
  }
272
477
 
273
- // ── Runner ─────────────────────────────────────────────────────────────
274
-
275
- function runSkills(env, skillsArgs, cwd) {
276
- const { cmd, args } = env.runner(skillsArgs);
277
- return runInteractive(cmd, args, cwd);
278
- }
478
+ // ── Helpers ────────────────────────────────────────────────────────────
279
479
 
280
480
  function buildRecommendations(a) {
281
481
  const stackLower = (a.stack || []).map((s) => s.toLowerCase());
@@ -315,6 +515,24 @@ function suggestSearches(a) {
315
515
  return [...out];
316
516
  }
317
517
 
518
+ /** Parse owner/repo@skill ref into { repo, skill }. */
519
+ function parseRef(ref) {
520
+ const match = /^(.+?\/.+?)@(.+)$/.exec(ref);
521
+ if (!match) return null;
522
+ return { repo: match[1], skill: match[2] };
523
+ }
524
+
525
+ /** Extract a concise failure reason from skills CLI output. */
526
+ function extractFailureReason(output) {
527
+ const cloneMatch = /Failed to clone[^:]*:\s*(.+)/i.exec(output);
528
+ if (cloneMatch) return cloneMatch[1].trim();
529
+
530
+ const errorMatch = /(?:error|failed)[:\s]+(.+)/im.exec(output);
531
+ if (errorMatch) return errorMatch[1].trim();
532
+
533
+ return 'Unknown error (check output above)';
534
+ }
535
+
318
536
  function pad(s, n) {
319
537
  return (s || '').padEnd(n);
320
538
  }
@@ -330,3 +548,20 @@ function runInteractive(cmd, args, cwd) {
330
548
  });
331
549
  });
332
550
  }
551
+
552
+ function stripAnsi(str) {
553
+ // eslint-disable-next-line no-control-regex
554
+ return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
555
+ }
556
+
557
+ /** Extract owner/repo@skill refs from `skills find <term>` output. */
558
+ function parseSkillRefs(output) {
559
+ const clean = stripAnsi(output);
560
+ const regex = /^(\S+\/\S+@\S+)\s+(.+?installs)/gm;
561
+ const results = [];
562
+ let match;
563
+ while ((match = regex.exec(clean))) {
564
+ results.push({ ref: match[1], installs: match[2].trim() });
565
+ }
566
+ return results;
567
+ }
@@ -4,6 +4,15 @@ description: "Writes production code following workspace conventions. Use when:
4
4
  model: GPT-5.3-Codex (copilot)
5
5
  tools: ['vscode', 'execute', 'read', 'io.github.upstash/context7/*', 'github/*', 'edit', 'search', 'web', 'vscode/memory', 'todo']
6
6
  agents: []
7
+ handoffs:
8
+ - label: "🔍 Review"
9
+ agent: Reviewer
10
+ prompt: "Review the changes I just made for correctness and conventions."
11
+ send: false
12
+ - label: "🎯 Back to Orchestrator"
13
+ agent: Orchestrator
14
+ prompt: "Implementation complete. Coordinate next steps."
15
+ send: false
7
16
  ---
8
17
 
9
18
  ## Model Selection
@@ -4,6 +4,15 @@ description: "Handles all UI/UX design tasks. Use when: creating screens, layout
4
4
  model: Claude Opus 4.6 (copilot)
5
5
  tools: ['read', 'edit', 'search', 'web', 'io.github.upstash/context7/*', 'vscode/memory']
6
6
  agents: []
7
+ handoffs:
8
+ - label: "🔍 Review"
9
+ agent: Reviewer
10
+ prompt: "Review the UI changes for accessibility, conventions, and design quality."
11
+ send: false
12
+ - label: "🎯 Back to Orchestrator"
13
+ agent: Orchestrator
14
+ prompt: "Design work complete. Coordinate next steps."
15
+ send: false
7
16
  ---
8
17
 
9
18
  ## Model Selection
@@ -4,6 +4,23 @@ description: "Coordinates multi-agent workflows. Delegates to Planner, Coder, De
4
4
  model: Claude Sonnet 4.6 (copilot)
5
5
  tools: ['read/readFile', 'agent', 'vscode/memory', 'github/*']
6
6
  agents: ['Planner', 'Coder', 'Designer', 'Reviewer']
7
+ handoffs:
8
+ - label: "📋 Plan"
9
+ agent: Planner
10
+ prompt: "Read PROJECT.md and STATE.md, then create an implementation plan for this task."
11
+ send: false
12
+ - label: "💻 Code"
13
+ agent: Coder
14
+ prompt: "Implement the approved plan. Read decisions.md for context."
15
+ send: false
16
+ - label: "🎨 Design"
17
+ agent: Designer
18
+ prompt: "Design the UI components described in the plan."
19
+ send: false
20
+ - label: "🔍 Review"
21
+ agent: Reviewer
22
+ prompt: "Review the implementation for correctness, conventions, and architecture."
23
+ send: false
7
24
  ---
8
25
 
9
26
  You are a project orchestrator. You break down complex requests into tasks and delegate to specialist subagents. You coordinate work but NEVER implement anything yourself.
@@ -4,6 +4,15 @@ description: "Creates implementation plans by researching the codebase, consulti
4
4
  model: Claude Opus 4.6 (copilot)
5
5
  tools: ['read', 'search', 'web', 'io.github.upstash/context7/*', 'vscode/memory']
6
6
  user-invocable: false
7
+ handoffs:
8
+ - label: "🎯 Execute Plan"
9
+ agent: Orchestrator
10
+ prompt: "Plan is ready. Execute it phase by phase."
11
+ send: false
12
+ - label: "💻 Code Directly"
13
+ agent: Coder
14
+ prompt: "Implement this plan."
15
+ send: false
7
16
  ---
8
17
 
9
18
  # Planning Agent
@@ -5,6 +5,15 @@ model: Claude Opus 4.6 (copilot)
5
5
  tools: ['read', 'search', 'web', 'vscode/memory']
6
6
  agents: []
7
7
  user-invocable: true
8
+ handoffs:
9
+ - label: "🎯 Back to Orchestrator"
10
+ agent: Orchestrator
11
+ prompt: "Review complete. See verdict above. Coordinate fixes or proceed."
12
+ send: false
13
+ - label: "💻 Fix Issues"
14
+ agent: Coder
15
+ prompt: "Fix the issues identified in the review above."
16
+ send: false
8
17
  ---
9
18
 
10
19
  ## Model Selection