squad-skills 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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +184 -0
  3. package/bin/cli.mjs +13 -0
  4. package/dist/cli/cli.d.mts +1 -0
  5. package/dist/cli/cli.mjs +450 -0
  6. package/package.json +70 -0
  7. package/skills/squad-backend/SKILL.md +128 -0
  8. package/skills/squad-backend/references/backend-api-data-and-messaging.md +67 -0
  9. package/skills/squad-backend/references/backend-performance-reliability-and-observability.md +49 -0
  10. package/skills/squad-backend/references/backend-security-auth-and-privacy.md +62 -0
  11. package/skills/squad-backend/references/backend-stack-and-runtime-matrix.md +68 -0
  12. package/skills/squad-backend/references/backend-system-design-and-distributed-systems.md +61 -0
  13. package/skills/squad-backend/references/backend-testing-debugging-and-mindset.md +48 -0
  14. package/skills/squad-backend/references/backend-worked-decisions.md +63 -0
  15. package/skills/squad-backend/references/official-sources.md +56 -0
  16. package/skills/squad-backend/references/quality-bar-and-preflight.md +54 -0
  17. package/skills/squad-backend/references/runtime-capability-fallbacks.md +46 -0
  18. package/skills/squad-code-review/SKILL.md +112 -0
  19. package/skills/squad-code-review/references/code-review-worked-decisions.md +58 -0
  20. package/skills/squad-code-review/references/cross-stack-review-dimensions.md +55 -0
  21. package/skills/squad-code-review/references/language-runtime-review-signatures.md +37 -0
  22. package/skills/squad-code-review/references/official-sources.md +24 -0
  23. package/skills/squad-code-review/references/quality-bar-and-preflight.md +48 -0
  24. package/skills/squad-code-review/references/review-methodology-debugging-and-mindset.md +53 -0
  25. package/skills/squad-code-review/references/review-runtime-and-verdict.md +69 -0
  26. package/skills/squad-code-review/references/security-architecture-data-and-operations-review.md +47 -0
  27. package/skills/squad-designer/SKILL.md +134 -0
  28. package/skills/squad-designer/references/anti-slop-quality-review.md +106 -0
  29. package/skills/squad-designer/references/codebase-first-examples.md +121 -0
  30. package/skills/squad-designer/references/design-system-ux-accessibility-and-handoff.md +109 -0
  31. package/skills/squad-designer/references/official-sources.md +85 -0
  32. package/skills/squad-designer/references/platform-adaptive-layout-and-input.md +40 -0
  33. package/skills/squad-designer/references/platform-native-apple-android.md +54 -0
  34. package/skills/squad-designer/references/platform-native-cross-platform.md +59 -0
  35. package/skills/squad-designer/references/platform-web-foundations-and-motion.md +104 -0
  36. package/skills/squad-designer/references/task-specific-ui-ux-research.md +91 -0
  37. package/skills/squad-devops/SKILL.md +131 -0
  38. package/skills/squad-devops/references/devops-testing-debugging-and-mindset.md +51 -0
  39. package/skills/squad-devops/references/devops-worked-decisions.md +70 -0
  40. package/skills/squad-devops/references/official-sources.md +58 -0
  41. package/skills/squad-devops/references/platform-iac-and-delivery-matrix.md +71 -0
  42. package/skills/squad-devops/references/quality-bar-and-preflight.md +52 -0
  43. package/skills/squad-devops/references/runtime-and-safe-delivery-fallbacks.md +49 -0
  44. package/skills/squad-devops/references/security-networking-secrets-and-supply-chain.md +54 -0
  45. package/skills/squad-devops/references/self-hosted-vps-and-reverse-proxy.md +124 -0
  46. package/skills/squad-devops/references/sre-observability-resilience-and-cost.md +52 -0
  47. package/skills/squad-fix/SKILL.md +143 -0
  48. package/skills/squad-fix/references/bug-routing-and-ownership.md +57 -0
  49. package/skills/squad-fix/references/diagnosis-root-cause-and-fix-loop.md +69 -0
  50. package/skills/squad-fix/references/official-sources.md +57 -0
  51. package/skills/squad-fix/references/quality-bar-and-preflight.md +47 -0
  52. package/skills/squad-fix/references/runtime-capability-fallbacks.md +65 -0
  53. package/skills/squad-fix/references/verification-qa-review-and-reporting.md +61 -0
  54. package/skills/squad-fix/references/worked-bugfix-examples.md +65 -0
  55. package/skills/squad-frontend/SKILL.md +134 -0
  56. package/skills/squad-frontend/references/designer-gate-and-design-intake.md +71 -0
  57. package/skills/squad-frontend/references/frontend-architecture-state-data-and-forms.md +68 -0
  58. package/skills/squad-frontend/references/frontend-security-accessibility-and-performance.md +55 -0
  59. package/skills/squad-frontend/references/frontend-stack-and-motion-selection.md +99 -0
  60. package/skills/squad-frontend/references/frontend-testing-debugging-and-mindset.md +51 -0
  61. package/skills/squad-frontend/references/frontend-worked-decisions.md +71 -0
  62. package/skills/squad-frontend/references/official-sources.md +52 -0
  63. package/skills/squad-frontend/references/quality-bar-and-preflight.md +49 -0
  64. package/skills/squad-frontend/references/runtime-capability-fallbacks.md +49 -0
  65. package/skills/squad-mobile/SKILL.md +120 -0
  66. package/skills/squad-mobile/references/design-platform-and-lifecycle-gates.md +50 -0
  67. package/skills/squad-mobile/references/mobile-debugging-and-mindset.md +40 -0
  68. package/skills/squad-mobile/references/mobile-security-performance-testing-and-release.md +61 -0
  69. package/skills/squad-mobile/references/mobile-stack-architecture-and-data.md +65 -0
  70. package/skills/squad-mobile/references/mobile-worked-decisions.md +53 -0
  71. package/skills/squad-mobile/references/official-sources.md +45 -0
  72. package/skills/squad-mobile/references/quality-bar-and-preflight.md +50 -0
  73. package/skills/squad-mobile/references/runtime-capability-fallbacks.md +42 -0
  74. package/skills/squad-product/SKILL.md +132 -0
  75. package/skills/squad-product/references/framing-and-acceptance-criteria.md +60 -0
  76. package/skills/squad-product/references/official-sources.md +42 -0
  77. package/skills/squad-product/references/plan-document-contract.md +53 -0
  78. package/skills/squad-product/references/product-worked-decisions.md +66 -0
  79. package/skills/squad-product/references/quality-bar-and-preflight.md +54 -0
  80. package/skills/squad-product/references/requirements-and-unknowns.md +68 -0
  81. package/skills/squad-product/references/scope-phasing-and-sequencing.md +55 -0
  82. package/skills/squad-qa/SKILL.md +112 -0
  83. package/skills/squad-qa/references/official-sources.md +42 -0
  84. package/skills/squad-qa/references/qa-debugging-and-mindset.md +45 -0
  85. package/skills/squad-qa/references/qa-worked-decisions.md +63 -0
  86. package/skills/squad-qa/references/quality-bar-and-preflight.md +48 -0
  87. package/skills/squad-qa/references/security-accessibility-performance-and-release.md +49 -0
  88. package/skills/squad-qa/references/test-architecture-data-flakiness-and-ci.md +66 -0
  89. package/skills/squad-qa/references/test-strategy-runtime-and-verdict.md +81 -0
  90. package/skills/squad-qa/references/testing-domains-and-tooling-matrix.md +57 -0
  91. package/skills/squads-team/SKILL.md +121 -0
  92. package/skills/squads-team/references/coordination-contract.md +115 -0
  93. package/skills/squads-team/references/coordination-worked-decisions.md +60 -0
  94. package/skills/squads-team/references/delivery-pipeline-and-roster.md +119 -0
  95. package/skills/squads-team/references/domain-coverage-contracts.md +82 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Harry Nguyen
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,184 @@
1
+ # Squad Skills
2
+
3
+ [![skills.sh](https://skills.sh/b/danh121097/squad-skills)](https://skills.sh/danh121097/squad-skills)
4
+
5
+ Supports **OpenCode**, **Claude Code**, **Codex**, **Cursor**, and
6
+ [**73 more**](https://www.npmjs.com/package/skills#supported-agents).
7
+
8
+ Role-specialized engineering skills for AI coding agents. The collection covers
9
+ product framing, design, frontend, backend, mobile, DevOps, QA, code review, bug
10
+ fixing, and coordinated squad delivery while preserving clear ownership
11
+ boundaries.
12
+
13
+ The repository follows the open Agent Skills format and keeps each installable
14
+ skill under `skills/<skill-name>/SKILL.md`.
15
+
16
+ ## Install
17
+
18
+ Every path installs the same set of skills. They differ in how the matching
19
+ subagents arrive.
20
+
21
+ | Path | Skills | Subagents | Tools |
22
+ | ------------------ | ------ | ---------------- | ----------------------------------- |
23
+ | Claude Code plugin | ✅ | ✅ same step | Claude Code |
24
+ | npm CLI | ✅ | ✅ same step | Claude Code, Codex |
25
+ | `npx skills add` | ✅ | one more command | every agent the Skills CLI supports |
26
+
27
+ ### As a Claude Code plugin
28
+
29
+ The plugin ships the skills and the subagents together, so one command installs
30
+ both:
31
+
32
+ ```sh
33
+ /plugin marketplace add danh121097/squad-skills
34
+ /plugin install squad-skills@squad-skills
35
+ ```
36
+
37
+ Each role then exists twice over: as a skill you invoke, and as a subagent you
38
+ spawn by name.
39
+
40
+ ### From the npm package (recommended)
41
+
42
+ Run without a permanent CLI installation:
43
+
44
+ ```sh
45
+ npx squad-skills list
46
+ npx squad-skills add --skill squads-team
47
+ npx squad-skills add --skill squad-frontend --global --agent codex
48
+ ```
49
+
50
+ Or install the command globally first:
51
+
52
+ ```sh
53
+ npm install --global squad-skills
54
+ squad-skills add --skill squads-team
55
+ ```
56
+
57
+ The npm command delegates installation to the official `skills` package and
58
+ defaults to copied files, so installed skills do not depend on an ephemeral
59
+ `npx` package-cache path.
60
+
61
+ ### Each role as a subagent too
62
+
63
+ `squad-skills add` also writes a subagent definition for every skill it
64
+ installs, so a role can be spawned by name instead of only loaded as a skill.
65
+ Claude Code reads `.claude/agents/<name>.md`; Codex reads
66
+ `.codex/agents/<name>.toml` and loads it only once `config.toml` names the file,
67
+ which the CLI registers after backing that config up. Each definition points at
68
+ the `SKILL.md` just installed rather than copying it, so the skill stays the one
69
+ source of truth.
70
+
71
+ Use `--no-agents` to install skills alone. A catalog installed through
72
+ `npx skills add` never runs this CLI, so generate the definitions afterwards:
73
+
74
+ ```sh
75
+ npx squad-skills agents --global
76
+ ```
77
+
78
+ `--model` and `--effort` write those fields into each Claude Code subagent file,
79
+ so a spawned role runs on the model you picked and survives the next reinstall:
80
+
81
+ ```sh
82
+ npx squad-skills agents --global --model opus --effort medium
83
+ ```
84
+
85
+ No skill in this catalog names a model. Which one to run is a property of your
86
+ machine, not of the role, so it lives in the command that writes your files.
87
+ Codex takes no per-agent model; set `[agents] default_subagent_model` in
88
+ `~/.codex/config.toml` instead, and the CLI says so rather than dropping the
89
+ flag silently.
90
+
91
+ See [the installation guide](docs/installation.md) for local-checkout commands,
92
+ installation scope, copy versus symlink behavior, and publishing notes.
93
+
94
+ ### From GitHub or skills.sh
95
+
96
+ List the available skills directly from the public repository:
97
+
98
+ ```sh
99
+ npx skills add danh121097/squad-skills --list
100
+ ```
101
+
102
+ Install the squad orchestrator globally for selected agents:
103
+
104
+ ```sh
105
+ npx skills add danh121097/squad-skills \
106
+ --skill squads-team --global \
107
+ --agent codex --agent claude-code --agent cursor --agent opencode
108
+ ```
109
+
110
+ Install a single role:
111
+
112
+ ```sh
113
+ npx skills add danh121097/squad-skills \
114
+ --skill squad-frontend --global --agent codex
115
+ ```
116
+
117
+ This route installs skills only. The upstream Skills CLI has no hook a source
118
+ repository can use, so generate the subagent definitions after it:
119
+
120
+ ```sh
121
+ npx squad-skills agents --global
122
+ ```
123
+
124
+ ## Develop
125
+
126
+ Requires Node.js 22.20 or newer. The repository pins pnpm through `package.json`.
127
+
128
+ ```sh
129
+ pnpm install
130
+ pnpm test
131
+ pnpm release:check
132
+ ```
133
+
134
+ `pnpm test` runs TypeScript type checking, formatting verification, Vitest,
135
+ skill-contract validation, knowledge-card validation, and catalog discovery
136
+ through the pinned Skills CLI.
137
+
138
+ Read [AGENTS.md](AGENTS.md) before contributing with a coding agent.
139
+ Use [the publishing guide](docs/publishing.md) when the local repository and npm
140
+ package are ready to be made public.
141
+
142
+ ## Contribute
143
+
144
+ [CONTRIBUTING.md](CONTRIBUTING.md) is the contract: the contribution types that
145
+ are accepted, the ones that are rejected and why, the provenance a knowledge
146
+ card must carry, and the evidence a skill-content change must carry before it
147
+ ships.
148
+
149
+ Two things are worth knowing before you start. Knowledge enters through a
150
+ reviewed card citing a dated first-party source, never through crawling or a
151
+ pasted page. And a change to anything an agent reads at runtime ships on the
152
+ full deterministic gate plus maintainer review — that gate shows the catalog is
153
+ consistent, contract-bound and within its payload ceiling, which is not the same
154
+ as showing the output got better, so a claim that it did needs its own evidence.
155
+ [AGENTS.md](AGENTS.md) states the rule.
156
+
157
+ If you used one of these skills on real work and its output got something wrong,
158
+ open the [skill output problem](https://github.com/danh121097/squad-skills/issues/new?template=skill-feedback.yml)
159
+ form. You do not need to know the fix.
160
+ [`docs/feedback-and-weekly-improvement.md`](docs/feedback-and-weekly-improvement.md)
161
+ is what happens to a report after that, and
162
+ [`docs/skill-observations.md`](docs/skill-observations.md) is how one becomes a
163
+ rule.
164
+
165
+ ## Skill format
166
+
167
+ Each skill directory must contain a `SKILL.md` whose YAML `name` matches the
168
+ directory name and whose `description` explains when the skill applies. Bundle
169
+ supporting material inside that same skill directory so installations remain
170
+ self-contained.
171
+
172
+ The executable contract is owned by the TypeScript validator and tests. Run
173
+ `pnpm validate` for a focused catalog check or `pnpm test` for the full gate.
174
+
175
+ ## License
176
+
177
+ MIT. See [LICENSE](LICENSE).
178
+
179
+ ## Discovery
180
+
181
+ After this repository is public, run the documented GitHub smoke install once.
182
+ Public GitHub skills become eligible for skills.sh discovery through anonymous
183
+ Skills CLI installation telemetry; the npm package remains an additional
184
+ distribution path and does not replace the GitHub source.
package/bin/cli.mjs ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+
3
+ import module from 'node:module';
4
+
5
+ if (module.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
6
+ try {
7
+ module.enableCompileCache();
8
+ } catch {
9
+ // Compile caching is an optional startup optimization.
10
+ }
11
+ }
12
+
13
+ await import('../dist/cli/cli.mjs');
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,450 @@
1
+ import { createRequire } from "node:module";
2
+ import { spawn } from "node:child_process";
3
+ import { homedir } from "node:os";
4
+ import path, { dirname, resolve } from "node:path";
5
+ import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
+ import { copyFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
8
+ const agentsTablePattern = /^\s*\[agents\]\s*$/;
9
+ const tableHeaderPattern = /^\s*\[([^\]]+)\]\s*$/;
10
+ function registerCodexAgents(source, names) {
11
+ const added = [];
12
+ const alreadyRegistered = [];
13
+ const missing = [];
14
+ for (const name of names) if (hasAgentEntry(source, name)) alreadyRegistered.push(name);
15
+ else missing.push(name);
16
+ if (missing.length === 0) return {
17
+ added,
18
+ alreadyRegistered,
19
+ source
20
+ };
21
+ const entries = missing.flatMap((name) => [
22
+ ` [agents.${name}]`,
23
+ ` config_file = "agents/${name}.toml"`,
24
+ ` description = ${JSON.stringify(name)}`
25
+ ]);
26
+ added.push(...missing);
27
+ return {
28
+ added,
29
+ alreadyRegistered,
30
+ source: insertIntoAgentsTable(source, entries)
31
+ };
32
+ }
33
+ function hasAgentEntry(source, name) {
34
+ return source.split(/\r?\n/).some((line) => tableHeaderPattern.exec(line)?.[1] === `agents.${name}`);
35
+ }
36
+ function insertIntoAgentsTable(source, entries) {
37
+ const lines = source.split("\n");
38
+ const tableStart = lines.findIndex((line) => agentsTablePattern.test(line));
39
+ if (tableStart === -1) return `${source}${source.length > 0 && !source.endsWith("\n") ? "\n" : ""}\n[agents]\n${entries.join("\n")}\n`;
40
+ let insertAt = lines.length;
41
+ for (let index = tableStart + 1; index < lines.length; index += 1) {
42
+ const header = tableHeaderPattern.exec(lines[index])?.[1];
43
+ if (header !== void 0 && !header.startsWith("agents.")) {
44
+ insertAt = index;
45
+ break;
46
+ }
47
+ }
48
+ while (insertAt > tableStart + 1 && lines[insertAt - 1].trim() === "") insertAt -= 1;
49
+ return [
50
+ ...lines.slice(0, insertAt),
51
+ ...entries,
52
+ ...lines.slice(insertAt)
53
+ ].join("\n");
54
+ }
55
+ const generatedMarker = "Generated by squad-skills";
56
+ const frontmatterPattern = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
57
+ function readSkillAgentDefinition(source) {
58
+ const frontmatter = source.match(frontmatterPattern)?.[1];
59
+ if (frontmatter === void 0) return null;
60
+ const name = readScalar(frontmatter, "name");
61
+ const description = readScalar(frontmatter, "description");
62
+ if (name === null || description === null) return null;
63
+ return {
64
+ description,
65
+ name,
66
+ whenToUse: readScalar(frontmatter, "when_to_use") ?? ""
67
+ };
68
+ }
69
+ function renderAgentBody(definition, context) {
70
+ const description = [definition.description, definition.whenToUse].filter((part) => part.length > 0).join(" ");
71
+ return `---
72
+ ${[
73
+ `name: ${definition.name}`,
74
+ `description: ${JSON.stringify(description)}`,
75
+ ...context.frontmatter ?? []
76
+ ].join("\n")}
77
+ ---
78
+
79
+ <!-- ${generatedMarker} from ${definition.name}/SKILL.md. ${context.origin} -->
80
+
81
+ ${context.instruction}
82
+
83
+ That file, together with the references it routes to, is the authoritative
84
+ definition of this role — its scope, its ownership boundaries, its handoff
85
+ contract, and its completion checklist. Read it before acting, and follow its
86
+ own routing rules to decide which of its references to open. Do not act on this
87
+ summary alone, and do not substitute your own process for the one it states.
88
+
89
+ If that file cannot be read, say so and stop rather than improvising the role.
90
+ `;
91
+ }
92
+ function renderClaudeAgentFile(definition, installedSkillPath, preferences = {}) {
93
+ return renderAgentBody(definition, {
94
+ ...installedSkillContext(installedSkillPath),
95
+ frontmatter: renderPreferenceLines(preferences)
96
+ });
97
+ }
98
+ function renderPreferenceLines(preferences) {
99
+ const lines = [];
100
+ if (preferences.model !== void 0 && preferences.model !== null) lines.push(`model: ${preferences.model}`);
101
+ if (preferences.effort !== void 0 && preferences.effort !== null) lines.push(`effort: ${preferences.effort}`);
102
+ return lines;
103
+ }
104
+ function installedSkillContext(installedSkillPath) {
105
+ return {
106
+ instruction: `Read \`${installedSkillPath}\` and follow it for this task.`,
107
+ origin: "Reinstalling regenerates it."
108
+ };
109
+ }
110
+ function renderCodexAgentFile(definition, installedSkillPath) {
111
+ const body = renderAgentBody(definition, installedSkillContext(installedSkillPath));
112
+ if (body.includes("'''")) throw new Error(`${definition.name}: agent body contains ''' and cannot be written as a TOML literal string.`);
113
+ return `# ${generatedMarker}. Reinstalling regenerates this file.
114
+ [agents.${definition.name}]
115
+ developer_instructions = '''
116
+ ${body}'''
117
+ `;
118
+ }
119
+ function readScalar(frontmatter, key) {
120
+ const line = frontmatter.split(/\r?\n/).find((candidate) => candidate.startsWith(`${key}:`))?.slice(key.length + 1).trim();
121
+ if (line === void 0 || line.length === 0) return null;
122
+ if (line.startsWith("\"")) return JSON.parse(line);
123
+ if (line.startsWith("'")) return line.slice(1, -1).replaceAll("''", "'");
124
+ return line;
125
+ }
126
+ const supportedTools = /* @__PURE__ */ new Set(["claude-code", "codex"]);
127
+ async function installAgentDefinitions(request) {
128
+ const messages = [];
129
+ const written = [];
130
+ const definitions = await readDefinitions(request, messages);
131
+ if (definitions.length === 0) return {
132
+ messages,
133
+ written
134
+ };
135
+ for (const tool of request.agents) {
136
+ if (!supportedTools.has(tool)) continue;
137
+ const target = resolveTarget(tool, request);
138
+ if (target === null) {
139
+ messages.push(`Skipped ${tool} agents: project scope is not a verified location for them; install with --global.`);
140
+ continue;
141
+ }
142
+ await mkdir(target.agentsDirectory, { recursive: true });
143
+ const preferences = {
144
+ effort: request.effort,
145
+ model: request.model
146
+ };
147
+ if ((preferences.model != null || preferences.effort != null) && !target.carriesPreferences) messages.push(`Ignored --model and --effort for ${tool}: this CLI writes them into Claude Code agent files only. Codex reads a subagent default from [agents] default_subagent_model and default_subagent_reasoning_effort in config.toml.`);
148
+ const registered = [];
149
+ for (const definition of definitions) {
150
+ const installedSkillFile = await findInstalledSkill(target.skillsRoots, definition.name);
151
+ if (installedSkillFile === null) {
152
+ messages.push(`Skipped ${tool}/${definition.name}: the skill is not installed there.`);
153
+ continue;
154
+ }
155
+ const agentFile = path.join(target.agentsDirectory, `${definition.name}${target.extension}`);
156
+ if (!request.force && await isForeignFile(agentFile)) {
157
+ messages.push(`Kept ${agentFile}: not generated by squad-skills. Use --force to replace.`);
158
+ continue;
159
+ }
160
+ await writeFile(agentFile, target.render(definition, installedSkillFile, target.carriesPreferences ? preferences : {}), "utf8");
161
+ written.push(agentFile);
162
+ registered.push(definition.name);
163
+ }
164
+ if (target.codexConfigFile !== void 0 && registered.length > 0) messages.push(...await registerInCodexConfig(target.codexConfigFile, registered));
165
+ }
166
+ return {
167
+ messages,
168
+ written
169
+ };
170
+ }
171
+ async function readDefinitions(request, messages) {
172
+ const skillsRoot = path.join(request.packageRoot, "skills");
173
+ const names = request.skills.length > 0 ? request.skills : await readSkillDirectories(skillsRoot, messages);
174
+ const definitions = [];
175
+ for (const name of names) {
176
+ let source;
177
+ try {
178
+ source = await readFile(path.join(skillsRoot, name, "SKILL.md"), "utf8");
179
+ } catch {
180
+ messages.push(`Skipped ${name}: no packaged SKILL.md.`);
181
+ continue;
182
+ }
183
+ const definition = readSkillAgentDefinition(source);
184
+ if (definition === null) {
185
+ messages.push(`Skipped ${name}: SKILL.md frontmatter is missing a name or description.`);
186
+ continue;
187
+ }
188
+ definitions.push(definition);
189
+ }
190
+ return definitions;
191
+ }
192
+ async function readSkillDirectories(skillsRoot, messages) {
193
+ try {
194
+ return (await readdir(skillsRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
195
+ } catch {
196
+ messages.push(`Skipped every agent: ${skillsRoot} is unreadable.`);
197
+ return [];
198
+ }
199
+ }
200
+ function resolveTarget(tool, request) {
201
+ const root = request.scope === "global" ? request.homeDirectory : request.projectRoot;
202
+ if (tool === "claude-code") return {
203
+ agentsDirectory: path.join(root, ".claude", "agents"),
204
+ carriesPreferences: true,
205
+ extension: ".md",
206
+ render: renderClaudeAgentFile,
207
+ skillsRoots: [path.join(root, ".claude", "skills"), path.join(root, ".agents", "skills")],
208
+ tool
209
+ };
210
+ if (request.scope !== "global") return null;
211
+ return {
212
+ agentsDirectory: path.join(root, ".codex", "agents"),
213
+ carriesPreferences: false,
214
+ codexConfigFile: path.join(root, ".codex", "config.toml"),
215
+ extension: ".toml",
216
+ render: renderCodexAgentFile,
217
+ skillsRoots: [path.join(root, ".agents", "skills"), path.join(root, ".codex", "skills")],
218
+ tool
219
+ };
220
+ }
221
+ async function registerInCodexConfig(configFile, names) {
222
+ let source;
223
+ try {
224
+ source = await readFile(configFile, "utf8");
225
+ } catch {
226
+ source = "";
227
+ }
228
+ const result = registerCodexAgents(source, names);
229
+ if (result.added.length === 0) return [];
230
+ if (source.length > 0) await copyFile(configFile, `${configFile}.squad-skills-backup`);
231
+ else await mkdir(path.dirname(configFile), { recursive: true });
232
+ await writeFile(configFile, result.source, "utf8");
233
+ return [`Registered ${result.added.join(", ")} in ${configFile}.`];
234
+ }
235
+ async function findInstalledSkill(roots, name) {
236
+ for (const root of roots) {
237
+ const candidate = path.join(root, name, "SKILL.md");
238
+ try {
239
+ await readFile(candidate, "utf8");
240
+ return candidate;
241
+ } catch {
242
+ continue;
243
+ }
244
+ }
245
+ return null;
246
+ }
247
+ async function isForeignFile(file) {
248
+ try {
249
+ return !(await readFile(file, "utf8")).includes(generatedMarker);
250
+ } catch {
251
+ return false;
252
+ }
253
+ }
254
+ const supportedAgentTools = ["claude-code", "codex"];
255
+ const helpFlags = /* @__PURE__ */ new Set(["--help", "-h"]);
256
+ const versionFlags = /* @__PURE__ */ new Set(["--version", "-v"]);
257
+ const addCommands = /* @__PURE__ */ new Set([
258
+ "add",
259
+ "install",
260
+ "i"
261
+ ]);
262
+ const noAgentsFlag = "--no-agents";
263
+ const modelFlags = ["--model"];
264
+ const effortFlags = ["--effort"];
265
+ function createCliAction(arguments_, packageRoot, version) {
266
+ const [command, ...forwardedArguments] = arguments_;
267
+ if (command === void 0 || helpFlags.has(command)) return {
268
+ kind: "print",
269
+ message: createHelpText(),
270
+ exitCode: 0
271
+ };
272
+ if (versionFlags.has(command)) return {
273
+ kind: "print",
274
+ message: version,
275
+ exitCode: 0
276
+ };
277
+ const malformed = findMalformedScalarOption(forwardedArguments);
278
+ if (malformed !== null) return {
279
+ kind: "print",
280
+ message: `${malformed} needs a value.\n\n${createHelpText()}`,
281
+ exitCode: 1
282
+ };
283
+ if (addCommands.has(command)) {
284
+ const forwardable = dropPreferenceArguments(forwardedArguments.filter((argument) => argument !== noAgentsFlag));
285
+ return {
286
+ kind: "delegate",
287
+ agentPlan: forwardedArguments.includes(noAgentsFlag) ? null : createAgentPlan(forwardedArguments),
288
+ arguments: [
289
+ "add",
290
+ packageRoot,
291
+ ...ensureCopyInstallation(forwardable)
292
+ ]
293
+ };
294
+ }
295
+ if (command === "agents") return {
296
+ kind: "install-agents",
297
+ agentPlan: createAgentPlan(forwardedArguments)
298
+ };
299
+ if (command === "list" || command === "ls") return {
300
+ kind: "delegate",
301
+ agentPlan: null,
302
+ arguments: [
303
+ "add",
304
+ packageRoot,
305
+ "--list",
306
+ ...forwardedArguments
307
+ ]
308
+ };
309
+ return {
310
+ kind: "print",
311
+ message: `Unknown command: ${command}\n\n${createHelpText()}`,
312
+ exitCode: 1
313
+ };
314
+ }
315
+ function createAgentPlan(arguments_) {
316
+ return {
317
+ agents: readListOption(arguments_, ["--agent", "-a"], supportedAgentTools),
318
+ effort: readScalarOption(arguments_, effortFlags),
319
+ force: arguments_.includes("--force"),
320
+ model: readScalarOption(arguments_, modelFlags),
321
+ scope: arguments_.includes("--global") || arguments_.includes("-g") ? "global" : "project",
322
+ skills: readListOption(arguments_, ["--skill", "-s"], [])
323
+ };
324
+ }
325
+ function readScalarOption(arguments_, flags) {
326
+ for (const [index, argument] of arguments_.entries()) {
327
+ const inlineFlag = flags.find((flag) => argument.startsWith(`${flag}=`));
328
+ if (inlineFlag !== void 0) {
329
+ const value = argument.slice(inlineFlag.length + 1).trim();
330
+ if (value.length > 0) return value;
331
+ continue;
332
+ }
333
+ if (!flags.includes(argument)) continue;
334
+ const value = arguments_[index + 1]?.trim() ?? "";
335
+ if (value.length > 0 && !value.startsWith("-")) return value;
336
+ }
337
+ return null;
338
+ }
339
+ function findMalformedScalarOption(arguments_) {
340
+ for (const flags of [modelFlags, effortFlags]) if (arguments_.some((argument) => flags.includes(argument) || flags.some((flag) => argument.startsWith(`${flag}=`))) && readScalarOption(arguments_, flags) === null) return flags[0];
341
+ return null;
342
+ }
343
+ function dropPreferenceArguments(arguments_) {
344
+ const flags = [...modelFlags, ...effortFlags];
345
+ return arguments_.filter((argument, index) => {
346
+ if (flags.some((flag) => argument === flag || argument.startsWith(`${flag}=`))) return false;
347
+ return !flags.includes(arguments_[index - 1]);
348
+ });
349
+ }
350
+ function readListOption(arguments_, flags, wildcard) {
351
+ const values = [];
352
+ for (const [index, argument] of arguments_.entries()) {
353
+ const inlineFlag = flags.find((flag) => argument.startsWith(`${flag}=`));
354
+ if (inlineFlag !== void 0) values.push(argument.slice(inlineFlag.length + 1));
355
+ else if (flags.includes(argument)) values.push(arguments_[index + 1] ?? "");
356
+ }
357
+ const parsed = values.flatMap((value) => value.split(",")).map((value) => value.trim()).filter((value) => value.length > 0);
358
+ return parsed.includes("*") || parsed.length === 0 ? wildcard : parsed;
359
+ }
360
+ function ensureCopyInstallation(arguments_) {
361
+ if (arguments_.includes("--copy")) return arguments_;
362
+ return [...arguments_, "--copy"];
363
+ }
364
+ function createHelpText() {
365
+ return `Squad Skills
366
+
367
+ Install role-specialized engineering skills through the Skills CLI.
368
+
369
+ Usage:
370
+ squad-skills add [skills options]
371
+ squad-skills list [skills options]
372
+ squad-skills agents [options]
373
+
374
+ Commands:
375
+ add, install, i Install skills from this package, then generate an agent
376
+ definition for each installed skill
377
+ list, ls List the packaged skills
378
+ agents Generate agent definitions for skills already installed,
379
+ for a catalog installed through \`npx skills add\`
380
+
381
+ Agent options:
382
+ --no-agents Install skills only (add)
383
+ --force Replace an agent file this CLI did not generate
384
+ --global, -g Read and write the user-level location
385
+ --agent, -a Limit to ${supportedAgentTools.join(", ")}
386
+ --skill, -s Limit to named skills
387
+ --model Write this model into each Claude Code agent file
388
+ --effort Write this reasoning effort into each Claude Code agent file
389
+
390
+ Examples:
391
+ squad-skills list
392
+ squad-skills add --skill squads-team
393
+ squad-skills add --skill squad-frontend --global --agent codex
394
+ squad-skills agents --global
395
+ squad-skills agents --global --agent claude-code --model opus --effort medium
396
+
397
+ Claude Code reads an agent from .claude/agents/<name>.md. Codex reads one from
398
+ .codex/agents/<name>.toml and loads it only once config.toml names it, so this
399
+ CLI registers it there and backs the file up first. Codex agents are written at
400
+ global scope only, and carry no model field: Codex takes a subagent default from
401
+ [agents] default_subagent_model in config.toml instead.
402
+
403
+ --model and --effort are machine preferences, not catalog content. They are
404
+ written only where the caller asks for them, so a reinstall keeps them.
405
+
406
+ All other options after add or list are forwarded to the Skills CLI.`;
407
+ }
408
+ const require = createRequire(import.meta.url);
409
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
410
+ const packageMetadata = require(resolve(packageRoot, "package.json"));
411
+ const skillsPackagePath = require.resolve("skills/package.json");
412
+ const skillsCliPath = resolve(dirname(skillsPackagePath), "bin/cli.mjs");
413
+ const action = createCliAction(process.argv.slice(2), packageRoot, packageMetadata.version);
414
+ if (action.kind === "print") {
415
+ console.log(action.message);
416
+ process.exitCode = action.exitCode;
417
+ } else if (action.kind === "install-agents") await writeAgentDefinitions(action.agentPlan);
418
+ else {
419
+ const exitCode = await runSkillsCli(skillsCliPath, action.arguments);
420
+ process.exitCode = exitCode;
421
+ if (exitCode === 0 && action.agentPlan !== null) await writeAgentDefinitions(action.agentPlan);
422
+ }
423
+ async function writeAgentDefinitions(agentPlan) {
424
+ const result = await installAgentDefinitions({
425
+ ...agentPlan,
426
+ homeDirectory: homedir(),
427
+ packageRoot,
428
+ projectRoot: process.cwd()
429
+ });
430
+ for (const message of result.messages) console.log(message);
431
+ console.log(result.written.length === 0 ? "No agent definitions written." : `Wrote ${result.written.length} agent definition(s).`);
432
+ }
433
+ function runSkillsCli(cliPath, arguments_) {
434
+ return new Promise((resolveExitCode) => {
435
+ const child = spawn(process.execPath, [cliPath, ...arguments_], { stdio: "inherit" });
436
+ child.once("error", (error) => {
437
+ console.error(`Unable to start the Skills CLI: ${error.message}`);
438
+ resolveExitCode(1);
439
+ });
440
+ child.once("exit", (code, signal) => {
441
+ if (signal !== null) {
442
+ console.error(`Skills CLI stopped by signal ${signal}.`);
443
+ resolveExitCode(1);
444
+ return;
445
+ }
446
+ resolveExitCode(code ?? 1);
447
+ });
448
+ });
449
+ }
450
+ export {};