@azerogluemin/ai-bootstrap 0.4.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +153 -0
- package/dist/applier/agents-installer.d.ts +1 -6
- package/dist/applier/agents-installer.js +16 -64
- package/dist/applier/agents-installer.js.map +1 -1
- package/dist/applier/pool.d.ts +34 -0
- package/dist/applier/pool.js +166 -0
- package/dist/applier/pool.js.map +1 -0
- package/dist/applier/preset-definitions.d.ts +15 -0
- package/dist/applier/preset-definitions.js +225 -0
- package/dist/applier/preset-definitions.js.map +1 -0
- package/dist/applier/preset-scaffolder.d.ts +14 -0
- package/dist/applier/preset-scaffolder.js +526 -0
- package/dist/applier/preset-scaffolder.js.map +1 -0
- package/dist/applier/skills-installer.d.ts +5 -3
- package/dist/applier/skills-installer.js +26 -75
- package/dist/applier/skills-installer.js.map +1 -1
- package/dist/commands/help.d.ts +1 -0
- package/dist/commands/help.js +98 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/mcp.js +50 -5
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/new.js +74 -164
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/scan.d.ts +1 -0
- package/dist/commands/scan.js +42 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/skills.js +65 -1
- package/dist/commands/skills.js.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/paths.d.ts +3 -0
- package/dist/utils/paths.js +8 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/wizard.js +63 -75
- package/dist/wizard.js.map +1 -1
- package/package.json +1 -1
- package/templates/skills/art-director/SKILL.md +209 -0
- package/templates/skills/backend-developer/SKILL.md +198 -0
- package/templates/skills/cinematographer/SKILL.md +233 -0
- package/templates/skills/colorist/SKILL.md +210 -0
- package/templates/skills/devops-developer/SKILL.md +263 -0
- package/templates/skills/editor/SKILL.md +166 -0
- package/templates/skills/frontend-developer/SKILL.md +147 -0
- package/templates/skills/mobile-developer/SKILL.md +227 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,159 @@ All notable changes to `@azerogluemin/ai-bootstrap` are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.0] — 2026-06-21
|
|
9
|
+
|
|
10
|
+
Preset-based project bootstrap — folder scaffolding + CLAUDE.md per preset.
|
|
11
|
+
|
|
12
|
+
### Added — 8 new production skills
|
|
13
|
+
|
|
14
|
+
Real production-quality content (~150-280 lines each, with sources):
|
|
15
|
+
|
|
16
|
+
Dev specialists:
|
|
17
|
+
- `frontend-developer` — React 19/Next 16/Vue 3/Svelte 5, state mgmt, performance, WCAG 2.2, testing
|
|
18
|
+
- `backend-developer` — REST/GraphQL, NestJS/Hono/FastAPI, multi-tenant, OWASP, caching, queues
|
|
19
|
+
- `devops-developer` — Docker, K8s, CI/CD, IaC, secrets, monitoring, SLOs
|
|
20
|
+
- `mobile-developer` — React Native (New Arch), Flutter, native iOS/Android, offline sync
|
|
21
|
+
|
|
22
|
+
Film production specialists:
|
|
23
|
+
- `editor` — Cut grammar, J/L cuts, vertical pacing, sound editing, Resolve/Premiere/FCP/CapCut
|
|
24
|
+
- `colorist` — Scopes (waveform/vector/parade), LUT design, Pixar/Wong Kar-wai/Deakins/A24 looks
|
|
25
|
+
- `art-director` — Visual treatment, mood board, palette per scene/character, era research (AZ-specific)
|
|
26
|
+
- `cinematographer` — Camera/lens/light decision trees, Deakins/Lubezki/Fraser craft
|
|
27
|
+
|
|
28
|
+
### Added — 3 project presets
|
|
29
|
+
|
|
30
|
+
Replaces bundle abstraction in user-facing CLI. Each preset includes
|
|
31
|
+
folder structure + CLAUDE.md template + skill+agent install list + MCP suggestions.
|
|
32
|
+
|
|
33
|
+
**SaaS Development** (~58 skills, ~50 agents, ~22 MCPs)
|
|
34
|
+
- Folders: \`apps/{web,api,admin}\`, \`packages/{ui,db,shared}\`, \`docs/00-27\`, \`infra/\`, \`scripts/\`
|
|
35
|
+
- CLAUDE.md rules: TS strict, multi-tenant, JWT+refresh, OWASP, decisions-log append-only
|
|
36
|
+
- 28 numbered docs scaffolded (00-claude-code-guide → 27-go-live-runbook)
|
|
37
|
+
|
|
38
|
+
**Social Page** (~44 skills, ~22 agents, ~21 MCPs)
|
|
39
|
+
- Folders: \`strategy/\`, \`calendar/\`, \`days/YYYY-MM-DD/{characters,shots,video,music,thumbnail,final}\`,
|
|
40
|
+
\`prompts-library/\`, \`assets/\`, \`analytics/\`
|
|
41
|
+
- CLAUDE.md rules: **Prompt-first** (vizual təsdiqsiz fayl qadağa), daily folder isolation
|
|
42
|
+
- Strategy MD skeletons: brand-guide, content-pillars, audience-personas, competitors
|
|
43
|
+
|
|
44
|
+
**AI Studio** (~34 skills, ~11 agents, ~14 MCPs)
|
|
45
|
+
- Folders: \`projects/<client>/{brief,characters,locations,shots,video,music}\`,
|
|
46
|
+
\`days/YYYY-MM-DD/\`, \`references/{pixar-style,cinematography,color-grading}\`,
|
|
47
|
+
\`prompts-library/\`
|
|
48
|
+
- CLAUDE.md rules: Prompt-first, style refs before prompt, file naming convention
|
|
49
|
+
- NO social platform skills/MCPs (studio doesn't publish)
|
|
50
|
+
|
|
51
|
+
### Changed — `ai-bootstrap new` is now preset-based
|
|
52
|
+
|
|
53
|
+
Previous (v0.5.0): multi-select bundle checkbox
|
|
54
|
+
New (v0.6.0): single-select preset → 3 questions only:
|
|
55
|
+
1. Layihə adı?
|
|
56
|
+
2. Bu qovluqda nə qurmaq istəyirsən? (SaaS / Social Page / AI Studio)
|
|
57
|
+
3. Qısa təsvir?
|
|
58
|
+
|
|
59
|
+
After selection: skills+agents symlinked from pool, MCPs auto-suggested,
|
|
60
|
+
folder structure scaffolded, CLAUDE.md written with preset-specific rules.
|
|
61
|
+
|
|
62
|
+
### Architecture
|
|
63
|
+
|
|
64
|
+
- New: \`packages/cli/src/applier/preset-definitions.ts\` — 3 preset metadata
|
|
65
|
+
- New: \`packages/cli/src/applier/preset-scaffolder.ts\` — folder scaffolder per preset
|
|
66
|
+
- Bundles still exist internally (\`resolvePlan\`, \`SKILL_BUNDLES\`, \`AGENT_BUNDLES\`)
|
|
67
|
+
but no longer surface to users — presets replaced them
|
|
68
|
+
- Project state schema bumped to v2.0: \`{ preset, name, description, createdAt }\`
|
|
69
|
+
|
|
70
|
+
### Tests
|
|
71
|
+
|
|
72
|
+
- 176 passing (was 142): 121 smoke + 55 e2e
|
|
73
|
+
- New: 30+ preset definition assertions (skill counts, MCP presence, preset uniqueness)
|
|
74
|
+
- New: 11 scaffolder assertions (SaaS 28 docs, Social strategy MDs, AI Studio refs)
|
|
75
|
+
|
|
76
|
+
### Migration
|
|
77
|
+
|
|
78
|
+
- v0.5.0 projects (multi-bundle): continue to work; new \`ai-bootstrap new\` writes preset state
|
|
79
|
+
- Old multi-bundle CLAUDE.md template still readable; project state v2.0 backward compat
|
|
80
|
+
|
|
81
|
+
[0.6.0]: https://github.com/eminazeroglu/ai-bootstrap/releases/tag/v0.6.0
|
|
82
|
+
|
|
83
|
+
## [0.5.0] — 2026-06-21
|
|
84
|
+
|
|
85
|
+
Big architectural + UX redesign from real-world test feedback.
|
|
86
|
+
|
|
87
|
+
### Added — Pool + Symlink architecture
|
|
88
|
+
|
|
89
|
+
- `~/.claude/skills-pool/` — ALL skills stored ONCE on disk (~3.8 MB total)
|
|
90
|
+
- `~/.claude/agents-pool/` — same for agents
|
|
91
|
+
- User-scope (`~/.claude/skills/`) and project-scope (`<project>/.claude/skills/`)
|
|
92
|
+
are now **symlinks** pointing to pool entries (POSIX), junctions (Windows),
|
|
93
|
+
or copies (Windows fallback when admin not available)
|
|
94
|
+
- **Result**: 10 creator projects = 1 pool copy + 260 symlinks, not 260 file copies
|
|
95
|
+
- Updates to a skill propagate to every project automatically (pnpm-style pattern)
|
|
96
|
+
|
|
97
|
+
### Changed — wizard simplified 6 steps → 1
|
|
98
|
+
|
|
99
|
+
Previous (v0.4.x): 15+ questions across 6 steps. Real user got overwhelmed,
|
|
100
|
+
hit SIGINT mid-flow, asked "why is this asking globally?".
|
|
101
|
+
|
|
102
|
+
New (v0.5.0): **3 questions only**:
|
|
103
|
+
1. Adın?
|
|
104
|
+
2. Əsas dilin? (az/en/ru/tr)
|
|
105
|
+
3. Sən kimsən, nə edirsən? (1-2 cümlə)
|
|
106
|
+
|
|
107
|
+
Removed entirely:
|
|
108
|
+
- Projects scan step (no projects on fresh machine — `ai-bootstrap scan <path>` later)
|
|
109
|
+
- Bundle selection step (auto-installs `foundation` user-scope; project bundles via `new`)
|
|
110
|
+
- MCPs full picker (auto-installs 9 free MCPs: filesystem, memory, git, fetch,
|
|
111
|
+
time, arxiv, youtube-transcript, puppeteer, playwright)
|
|
112
|
+
- Memory configuration step (defaults: markdown-only, learning-keeper ON, all logs ON)
|
|
113
|
+
- GitHub backup step (use `ai-bootstrap backup init` when ready)
|
|
114
|
+
|
|
115
|
+
### Changed — `ai-bootstrap new` simplified
|
|
116
|
+
|
|
117
|
+
Previous: 5 questions (single-bundle + override confirm + custom rules).
|
|
118
|
+
New: **3 questions only**:
|
|
119
|
+
1. Layihə adı?
|
|
120
|
+
2. Bundle(lər)? (**multi-select checkbox** — pick multiple at once)
|
|
121
|
+
3. Qısa təsvir? (1-2 cümlə)
|
|
122
|
+
|
|
123
|
+
Removed:
|
|
124
|
+
- Single-bundle intent selection (replaced by multi-select)
|
|
125
|
+
- Bundle override confirm (multi-select handles it)
|
|
126
|
+
- Custom rules question (placeholder added to CLAUDE.md instead)
|
|
127
|
+
|
|
128
|
+
### Added — new commands
|
|
129
|
+
|
|
130
|
+
- `ai-bootstrap help` — comprehensive guide (full tour, not just brief --help)
|
|
131
|
+
- `ai-bootstrap add` (no args) — **interactive multi-select** of all bundles + skills + agents
|
|
132
|
+
- `ai-bootstrap mcp add` — multi-select MCP picker (was missing)
|
|
133
|
+
- `ai-bootstrap mcp add github notion slack` — direct add
|
|
134
|
+
- `ai-bootstrap scan ~/MyJobs` — manual project scan (replaces removed wizard step)
|
|
135
|
+
|
|
136
|
+
### Quality
|
|
137
|
+
|
|
138
|
+
- Cross-platform link helper: `linkFromPool()` tries symlink → junction → copy
|
|
139
|
+
- Pool sync detects newer template versions and refreshes pool entries
|
|
140
|
+
- 142 tests still passing (87 smoke + 55 e2e)
|
|
141
|
+
|
|
142
|
+
### Workflow
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# 1) Maşına bir dəfə (3 sual, 30 saniyə):
|
|
146
|
+
npm install -g @azerogluemin/ai-bootstrap@latest
|
|
147
|
+
ai-bootstrap
|
|
148
|
+
|
|
149
|
+
# 2) Hər yeni layihə (3 sual, 20 saniyə):
|
|
150
|
+
cd ~/Projects/yeni-layihə
|
|
151
|
+
ai-bootstrap new
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Migration
|
|
155
|
+
|
|
156
|
+
- v0.4.x project copies → v0.5.0 symlinks: run `ai-bootstrap update` to switch
|
|
157
|
+
- Or `ai-bootstrap remove --all` then `ai-bootstrap new` per project
|
|
158
|
+
|
|
159
|
+
[0.5.0]: https://github.com/eminazeroglu/ai-bootstrap/releases/tag/v0.5.0
|
|
160
|
+
|
|
8
161
|
## [0.4.2] — 2026-06-21
|
|
9
162
|
|
|
10
163
|
README quick-start fixed — global install upfront.
|
|
@@ -8,11 +8,6 @@ export interface AgentInstallResult {
|
|
|
8
8
|
agent: string;
|
|
9
9
|
error: string;
|
|
10
10
|
}[];
|
|
11
|
+
linkMode?: 'symlink' | 'junction' | 'copy';
|
|
11
12
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Install agents into a target agents directory.
|
|
14
|
-
* @param agentNames List of agent IDs to install
|
|
15
|
-
* @param targetAgentsDir Absolute path. Default `~/.claude/agents/`; pass
|
|
16
|
-
* `<project>/.claude/agents/` for project-scope.
|
|
17
|
-
*/
|
|
18
13
|
export declare function installAgents(agentNames: string[], targetAgentsDir?: string): AgentInstallResult;
|
|
@@ -1,79 +1,31 @@
|
|
|
1
|
-
// Install
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import { join, resolve } from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
1
|
+
// Install agents into a target agents directory by linking from the pool.
|
|
2
|
+
// Same architecture as skills-installer (v0.5.0 Pool+Symlink).
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
7
5
|
import { ensureDir, AGENTS_DIR } from '../utils/paths.js';
|
|
8
|
-
|
|
9
|
-
// Lookup order:
|
|
10
|
-
// 1) ./templates/agents/ — published npm package (bundled via prepack)
|
|
11
|
-
// 2) ../templates/agents/ — sibling templates package (monorepo dev)
|
|
12
|
-
const here = fileURLToPath(import.meta.url);
|
|
13
|
-
const cliRoot = resolve(here, '..', '..', '..');
|
|
14
|
-
const candidates = [
|
|
15
|
-
join(cliRoot, 'templates', 'agents'),
|
|
16
|
-
resolve(cliRoot, '..', 'templates', 'agents'),
|
|
17
|
-
];
|
|
18
|
-
for (const c of candidates) {
|
|
19
|
-
if (existsSync(c))
|
|
20
|
-
return c;
|
|
21
|
-
}
|
|
22
|
-
return candidates[0];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Install agents into a target agents directory.
|
|
26
|
-
* @param agentNames List of agent IDs to install
|
|
27
|
-
* @param targetAgentsDir Absolute path. Default `~/.claude/agents/`; pass
|
|
28
|
-
* `<project>/.claude/agents/` for project-scope.
|
|
29
|
-
*/
|
|
6
|
+
import { ensurePool, linkFromPool, poolHasAgent, poolAgentPath } from './pool.js';
|
|
30
7
|
export function installAgents(agentNames, targetAgentsDir = AGENTS_DIR) {
|
|
31
|
-
const result = {
|
|
32
|
-
|
|
33
|
-
skipped: [],
|
|
34
|
-
errors: [],
|
|
35
|
-
};
|
|
8
|
+
const result = { installed: [], skipped: [], errors: [] };
|
|
9
|
+
ensurePool();
|
|
36
10
|
ensureDir(targetAgentsDir);
|
|
37
|
-
const templatesDir = templatesAgentsPath();
|
|
38
|
-
if (!existsSync(templatesDir)) {
|
|
39
|
-
for (const name of agentNames) {
|
|
40
|
-
result.skipped.push({
|
|
41
|
-
agent: name,
|
|
42
|
-
reason: 'agents templates folder yoxdur (Mərhələ C-5-də yaradılır)',
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return result;
|
|
46
|
-
}
|
|
47
11
|
for (const name of agentNames) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (!existsSync(sourceDir)) {
|
|
51
|
-
result.skipped.push({
|
|
52
|
-
agent: name,
|
|
53
|
-
reason: `template yoxdur: ${name} (skill hələ yazılmayıb)`,
|
|
54
|
-
});
|
|
12
|
+
if (!poolHasAgent(name)) {
|
|
13
|
+
result.skipped.push({ agent: name, reason: `Pool-da yoxdur: ${name}` });
|
|
55
14
|
continue;
|
|
56
15
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
reason: 'artıq install olunub',
|
|
61
|
-
});
|
|
16
|
+
const target = join(targetAgentsDir, name);
|
|
17
|
+
if (existsSync(target)) {
|
|
18
|
+
result.skipped.push({ agent: name, reason: 'artıq quraşdırılıb' });
|
|
62
19
|
continue;
|
|
63
20
|
}
|
|
64
21
|
try {
|
|
65
|
-
|
|
22
|
+
const mode = linkFromPool(poolAgentPath(name), target);
|
|
66
23
|
result.installed.push(name);
|
|
24
|
+
if (!result.linkMode)
|
|
25
|
+
result.linkMode = mode;
|
|
67
26
|
}
|
|
68
27
|
catch (err) {
|
|
69
|
-
|
|
70
|
-
rmSync(targetDir, { recursive: true, force: true });
|
|
71
|
-
}
|
|
72
|
-
catch { /* best-effort */ }
|
|
73
|
-
result.errors.push({
|
|
74
|
-
agent: name,
|
|
75
|
-
error: err instanceof Error ? err.message : String(err),
|
|
76
|
-
});
|
|
28
|
+
result.errors.push({ agent: name, error: err instanceof Error ? err.message : String(err) });
|
|
77
29
|
}
|
|
78
30
|
}
|
|
79
31
|
return result;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-installer.js","sourceRoot":"","sources":["../../src/applier/agents-installer.ts"],"names":[],"mappings":"AAAA,+
|
|
1
|
+
{"version":3,"file":"agents-installer.js","sourceRoot":"","sources":["../../src/applier/agents-installer.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,+DAA+D;AAE/D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AASlF,MAAM,UAAU,aAAa,CAC3B,UAAoB,EACpB,kBAA0B,UAAU;IAEpC,MAAM,MAAM,GAAuB,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAE9E,UAAU,EAAE,CAAC;IACb,SAAS,CAAC,eAAe,CAAC,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,IAAI,EAAE,EAAE,CAAC,CAAC;YACxE,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QAC3C,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;YACnE,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;YACvD,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface PoolResult {
|
|
2
|
+
skillsPool: string;
|
|
3
|
+
agentsPool: string;
|
|
4
|
+
skillsAdded: number;
|
|
5
|
+
skillsUpdated: number;
|
|
6
|
+
agentsAdded: number;
|
|
7
|
+
agentsUpdated: number;
|
|
8
|
+
errors: {
|
|
9
|
+
item: string;
|
|
10
|
+
error: string;
|
|
11
|
+
}[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Ensure the pool exists and is up-to-date with the bundled templates.
|
|
15
|
+
* Idempotent: safe to call on every install/update.
|
|
16
|
+
*
|
|
17
|
+
* Strategy: compare modification times. If template is newer, refresh pool entry.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensurePool(): PoolResult;
|
|
20
|
+
/**
|
|
21
|
+
* Create a cross-platform link from a pool entry to a target location.
|
|
22
|
+
* - POSIX: symlink
|
|
23
|
+
* - Windows: try junction (no admin needed for dirs), fall back to copy on failure
|
|
24
|
+
*
|
|
25
|
+
* Returns 'symlink' | 'junction' | 'copy' to indicate what was used.
|
|
26
|
+
*/
|
|
27
|
+
export declare function linkFromPool(poolEntry: string, targetPath: string): 'symlink' | 'junction' | 'copy';
|
|
28
|
+
/**
|
|
29
|
+
* Check whether a pool entry exists for the given name.
|
|
30
|
+
*/
|
|
31
|
+
export declare function poolHasSkill(name: string): boolean;
|
|
32
|
+
export declare function poolHasAgent(name: string): boolean;
|
|
33
|
+
export declare function poolSkillPath(name: string): string;
|
|
34
|
+
export declare function poolAgentPath(name: string): string;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// Pool — single source of truth for skill + agent templates.
|
|
2
|
+
//
|
|
3
|
+
// Architecture (v0.5.0):
|
|
4
|
+
// ~/.claude/skills-pool/<skill>/ — every skill, ONE copy on disk
|
|
5
|
+
// ~/.claude/agents-pool/<agent>/ — every agent, ONE copy
|
|
6
|
+
// ~/.claude/skills/<skill> — symlink → pool (user scope)
|
|
7
|
+
// <project>/.claude/skills/<skill> — symlink → pool (project scope)
|
|
8
|
+
//
|
|
9
|
+
// Pool is populated from the bundled templates on first run (or update).
|
|
10
|
+
// pnpm-style: many references, one underlying store.
|
|
11
|
+
//
|
|
12
|
+
// Cross-platform:
|
|
13
|
+
// macOS / Linux / WSL2 — symlinkSync('dir')
|
|
14
|
+
// Windows native — try junction ('junction'); fall back to copy if no admin
|
|
15
|
+
//
|
|
16
|
+
// When a new version of @azerogluemin/ai-bootstrap is installed:
|
|
17
|
+
// - `ai-bootstrap update` re-runs ensurePool() → pool gets new content
|
|
18
|
+
// - All symlinks in user-scope + projects auto-see the update
|
|
19
|
+
// - No per-project re-install needed
|
|
20
|
+
import { existsSync, readdirSync, statSync, lstatSync, cpSync, symlinkSync, rmSync, realpathSync } from 'node:fs';
|
|
21
|
+
import { join, resolve, dirname } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { IS_WINDOWS, SKILLS_POOL_DIR, AGENTS_POOL_DIR, ensureDir } from '../utils/paths.js';
|
|
24
|
+
/**
|
|
25
|
+
* Resolve absolute path to the bundled templates folder.
|
|
26
|
+
* Same lookup as skills-installer used in v0.4.x.
|
|
27
|
+
*/
|
|
28
|
+
function templatesRoot() {
|
|
29
|
+
const here = fileURLToPath(import.meta.url);
|
|
30
|
+
const cliRoot = resolve(here, '..', '..', '..');
|
|
31
|
+
const candidates = [
|
|
32
|
+
join(cliRoot, 'templates'), // published npm pkg (prepack)
|
|
33
|
+
resolve(cliRoot, '..', 'templates'), // monorepo dev sibling
|
|
34
|
+
];
|
|
35
|
+
for (const c of candidates) {
|
|
36
|
+
if (existsSync(c))
|
|
37
|
+
return c;
|
|
38
|
+
}
|
|
39
|
+
return candidates[0];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Ensure the pool exists and is up-to-date with the bundled templates.
|
|
43
|
+
* Idempotent: safe to call on every install/update.
|
|
44
|
+
*
|
|
45
|
+
* Strategy: compare modification times. If template is newer, refresh pool entry.
|
|
46
|
+
*/
|
|
47
|
+
export function ensurePool() {
|
|
48
|
+
const result = {
|
|
49
|
+
skillsPool: SKILLS_POOL_DIR,
|
|
50
|
+
agentsPool: AGENTS_POOL_DIR,
|
|
51
|
+
skillsAdded: 0,
|
|
52
|
+
skillsUpdated: 0,
|
|
53
|
+
agentsAdded: 0,
|
|
54
|
+
agentsUpdated: 0,
|
|
55
|
+
errors: [],
|
|
56
|
+
};
|
|
57
|
+
ensureDir(SKILLS_POOL_DIR);
|
|
58
|
+
ensureDir(AGENTS_POOL_DIR);
|
|
59
|
+
const root = templatesRoot();
|
|
60
|
+
syncCategory(join(root, 'skills'), SKILLS_POOL_DIR, result, 'skills');
|
|
61
|
+
syncCategory(join(root, 'agents'), AGENTS_POOL_DIR, result, 'agents');
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function syncCategory(src, dst, result, category) {
|
|
65
|
+
if (!existsSync(src))
|
|
66
|
+
return;
|
|
67
|
+
const items = readdirSync(src);
|
|
68
|
+
for (const name of items) {
|
|
69
|
+
const srcItem = join(src, name);
|
|
70
|
+
const dstItem = join(dst, name);
|
|
71
|
+
try {
|
|
72
|
+
const srcStat = statSync(srcItem);
|
|
73
|
+
if (!srcStat.isDirectory())
|
|
74
|
+
continue;
|
|
75
|
+
if (!existsSync(dstItem)) {
|
|
76
|
+
cpSync(srcItem, dstItem, { recursive: true, dereference: true });
|
|
77
|
+
if (category === 'skills')
|
|
78
|
+
result.skillsAdded++;
|
|
79
|
+
else
|
|
80
|
+
result.agentsAdded++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// Update check: if template SKILL.md/AGENT.md is newer than pool's, refresh
|
|
84
|
+
const markerFile = category === 'skills' ? 'SKILL.md' : 'AGENT.md';
|
|
85
|
+
const srcMarker = join(srcItem, markerFile);
|
|
86
|
+
const dstMarker = join(dstItem, markerFile);
|
|
87
|
+
if (existsSync(srcMarker) && existsSync(dstMarker)) {
|
|
88
|
+
const srcM = statSync(srcMarker).mtimeMs;
|
|
89
|
+
const dstM = statSync(dstMarker).mtimeMs;
|
|
90
|
+
if (srcM > dstM) {
|
|
91
|
+
rmSync(dstItem, { recursive: true, force: true });
|
|
92
|
+
cpSync(srcItem, dstItem, { recursive: true, dereference: true });
|
|
93
|
+
if (category === 'skills')
|
|
94
|
+
result.skillsUpdated++;
|
|
95
|
+
else
|
|
96
|
+
result.agentsUpdated++;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
result.errors.push({ item: name, error: err instanceof Error ? err.message : String(err) });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a cross-platform link from a pool entry to a target location.
|
|
107
|
+
* - POSIX: symlink
|
|
108
|
+
* - Windows: try junction (no admin needed for dirs), fall back to copy on failure
|
|
109
|
+
*
|
|
110
|
+
* Returns 'symlink' | 'junction' | 'copy' to indicate what was used.
|
|
111
|
+
*/
|
|
112
|
+
export function linkFromPool(poolEntry, targetPath) {
|
|
113
|
+
const parent = dirname(targetPath);
|
|
114
|
+
ensureDir(parent);
|
|
115
|
+
if (existsSync(targetPath) || isBrokenSymlink(targetPath)) {
|
|
116
|
+
// Caller is responsible for skipping; we don't overwrite blindly
|
|
117
|
+
throw new Error(`Target already exists: ${targetPath}`);
|
|
118
|
+
}
|
|
119
|
+
if (!IS_WINDOWS) {
|
|
120
|
+
symlinkSync(poolEntry, targetPath, 'dir');
|
|
121
|
+
return 'symlink';
|
|
122
|
+
}
|
|
123
|
+
// Windows: try junction first (no admin needed for directories)
|
|
124
|
+
try {
|
|
125
|
+
symlinkSync(poolEntry, targetPath, 'junction');
|
|
126
|
+
return 'junction';
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Fall back to copy (admin required for true symlinks; junctions failed too)
|
|
130
|
+
cpSync(poolEntry, targetPath, { recursive: true, dereference: true });
|
|
131
|
+
return 'copy';
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function isBrokenSymlink(p) {
|
|
135
|
+
try {
|
|
136
|
+
const ls = lstatSync(p);
|
|
137
|
+
if (!ls.isSymbolicLink())
|
|
138
|
+
return false;
|
|
139
|
+
try {
|
|
140
|
+
realpathSync(p);
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Check whether a pool entry exists for the given name.
|
|
153
|
+
*/
|
|
154
|
+
export function poolHasSkill(name) {
|
|
155
|
+
return existsSync(join(SKILLS_POOL_DIR, name));
|
|
156
|
+
}
|
|
157
|
+
export function poolHasAgent(name) {
|
|
158
|
+
return existsSync(join(AGENTS_POOL_DIR, name));
|
|
159
|
+
}
|
|
160
|
+
export function poolSkillPath(name) {
|
|
161
|
+
return join(SKILLS_POOL_DIR, name);
|
|
162
|
+
}
|
|
163
|
+
export function poolAgentPath(name) {
|
|
164
|
+
return join(AGENTS_POOL_DIR, name);
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/applier/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type PresetId = 'saas-development' | 'social-page' | 'ai-studio';
|
|
2
|
+
export interface PresetDefinition {
|
|
3
|
+
id: PresetId;
|
|
4
|
+
label: string;
|
|
5
|
+
description: string;
|
|
6
|
+
skills: string[];
|
|
7
|
+
agents: string[];
|
|
8
|
+
mcps: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare const SAAS_DEVELOPMENT: PresetDefinition;
|
|
11
|
+
export declare const SOCIAL_PAGE: PresetDefinition;
|
|
12
|
+
export declare const AI_STUDIO: PresetDefinition;
|
|
13
|
+
export declare const PRESETS: Record<PresetId, PresetDefinition>;
|
|
14
|
+
export declare function getPreset(id: PresetId): PresetDefinition;
|
|
15
|
+
export declare function listPresets(): PresetDefinition[];
|