@dtlabs/ai-toolkit 0.1.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/.claude/agents/assessment-manager.md +218 -0
- package/.claude/agents/concurrency-safety-assessment.md +190 -0
- package/.claude/agents/define-feature.md +265 -0
- package/.claude/agents/dependency-injection-refactoring.md +237 -0
- package/.claude/agents/dependency-supply-chain-security.md +262 -0
- package/.claude/agents/developer-backend.md +105 -0
- package/.claude/agents/developer-frontend.md +111 -0
- package/.claude/agents/developer-testing.md +121 -0
- package/.claude/agents/domain-model-refactoring.md +208 -0
- package/.claude/agents/generate-requirements.md +168 -0
- package/.claude/agents/generate-tech-spec.md +259 -0
- package/.claude/agents/generate-work-breakdown.md +284 -0
- package/.claude/agents/generic-software-assessment.md +165 -0
- package/.claude/agents/god-class-decomposition.md +198 -0
- package/.claude/agents/init-agents-md.md +322 -0
- package/.claude/agents/install-toolkit.md +196 -0
- package/.claude/agents/intervention-documentation-standard.md +131 -0
- package/.claude/agents/layered-architecture-assessment.md +205 -0
- package/.claude/agents/project-manager.md +309 -0
- package/.claude/agents/review-solution.md +138 -0
- package/.claude/agents/security-hardening.md +240 -0
- package/.claude/agents/validate-feature-docs.md +171 -0
- package/.claude/commands/assessment-status.md +116 -0
- package/.claude/commands/check-docs.md +18 -0
- package/.claude/commands/feature-status.md +20 -0
- package/.claude/commands/next-task.md +37 -0
- package/.claude/commands/pr-description.md +34 -0
- package/.claude/skills/assess-codebase/SKILL.md +16 -0
- package/.claude/skills/define-feature/SKILL.md +13 -0
- package/.claude/skills/hi-gaia/SKILL.md +261 -0
- package/.claude/skills/implement-feature/SKILL.md +69 -0
- package/.claude/skills/init-agents/SKILL.md +14 -0
- package/.claude/skills/install-toolkit/SKILL.md +14 -0
- package/CLAUDE.md +135 -0
- package/README.md +77 -0
- package/bin/cli.js +350 -0
- package/docs/installation.md +80 -0
- package/docs/pricing.md +99 -0
- package/docs/procedures/approval-gates.md +142 -0
- package/docs/procedures/assessment-approval-gate.md +60 -0
- package/docs/procedures/code-generation.md +48 -0
- package/docs/procedures/code-review.md +63 -0
- package/docs/procedures/effort-estimation.md +86 -0
- package/docs/procedures/feature-registry.md +50 -0
- package/docs/procedures/issues-register.md +24 -0
- package/docs/procedures/process-log.md +28 -0
- package/docs/procedures/secure-coding.md +50 -0
- package/docs/procedures/testing.md +63 -0
- package/docs/procedures/token-estimation.md +123 -0
- package/docs/reference.md +228 -0
- package/package.json +23 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const crypto = require('crypto');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const packageRoot = path.join(__dirname, '..');
|
|
7
|
+
|
|
8
|
+
// ── colors ────────────────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
const c = {
|
|
11
|
+
reset: '\x1b[0m',
|
|
12
|
+
bold: '\x1b[1m',
|
|
13
|
+
dim: '\x1b[2m',
|
|
14
|
+
green: '\x1b[32m',
|
|
15
|
+
yellow: '\x1b[33m',
|
|
16
|
+
blue: '\x1b[34m',
|
|
17
|
+
magenta: '\x1b[35m',
|
|
18
|
+
cyan: '\x1b[36m',
|
|
19
|
+
red: '\x1b[31m',
|
|
20
|
+
gray: '\x1b[90m',
|
|
21
|
+
white: '\x1b[97m',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const clr = (color, text) => `${c[color]}${text}${c.reset}`;
|
|
25
|
+
const bold = (text) => `${c.bold}${text}${c.reset}`;
|
|
26
|
+
const dim = (text) => `${c.dim}${text}${c.reset}`;
|
|
27
|
+
|
|
28
|
+
function divider(char = '─', len = 60) {
|
|
29
|
+
return clr('gray', char.repeat(len));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function banner() {
|
|
33
|
+
console.log();
|
|
34
|
+
console.log(clr('cyan', '╔══════════════════════════════════════════════════════════╗'));
|
|
35
|
+
console.log(clr('cyan', '║') + bold(clr('white', ' AI Toolkit — Installer ')) + clr('cyan', '║'));
|
|
36
|
+
console.log(clr('cyan', '║') + clr('gray', ` @dtlabs/ai-toolkit v${require('../package.json').version.padEnd(22)}`) + clr('cyan', '║'));
|
|
37
|
+
console.log(clr('cyan', '╚══════════════════════════════════════════════════════════╝'));
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
function fileHash(filePath) {
|
|
44
|
+
return crypto.createHash('md5').update(fs.readFileSync(filePath)).digest('hex');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function ensureDir(filePath) {
|
|
48
|
+
const dir = path.dirname(filePath);
|
|
49
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function askConfirm(question) {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
55
|
+
rl.question(`${clr('cyan', '?')} ${question} ${dim('(y/N)')} `, (answer) => {
|
|
56
|
+
rl.close();
|
|
57
|
+
resolve(/^y(es)?$/i.test(answer.trim()));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── file enumeration ─────────────────────────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
function expandMappings(mappings) {
|
|
65
|
+
const files = [];
|
|
66
|
+
for (const { src, dest } of mappings) {
|
|
67
|
+
if (!fs.existsSync(src)) continue;
|
|
68
|
+
if (fs.statSync(src).isDirectory()) {
|
|
69
|
+
for (const entry of walkDir(src)) {
|
|
70
|
+
const rel = path.relative(src, entry);
|
|
71
|
+
files.push({ src: entry, dest: path.join(dest, rel) });
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
files.push({ src, dest });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return files;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function walkDir(dir) {
|
|
81
|
+
const results = [];
|
|
82
|
+
for (const item of fs.readdirSync(dir)) {
|
|
83
|
+
const full = path.join(dir, item);
|
|
84
|
+
if (fs.statSync(full).isDirectory()) results.push(...walkDir(full));
|
|
85
|
+
else results.push(full);
|
|
86
|
+
}
|
|
87
|
+
return results;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── categorize ───────────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
function categorize(files) {
|
|
93
|
+
return files.map(({ src, dest }) => {
|
|
94
|
+
if (!fs.existsSync(dest)) return { src, dest, status: 'new' };
|
|
95
|
+
return fileHash(src) === fileHash(dest)
|
|
96
|
+
? { src, dest, status: 'same' }
|
|
97
|
+
: { src, dest, status: 'modified' };
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── version check ─────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
const TOOLKIT_VERSION = require('../package.json').version;
|
|
104
|
+
const VERSION_FILE = '.ai-toolkit-version';
|
|
105
|
+
|
|
106
|
+
function readInstalledVersion(destRoot) {
|
|
107
|
+
const versionFile = path.join(destRoot, '.claude', VERSION_FILE);
|
|
108
|
+
if (!fs.existsSync(versionFile)) return null;
|
|
109
|
+
return fs.readFileSync(versionFile, 'utf8').trim();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function writeInstalledVersion(destRoot) {
|
|
113
|
+
const versionFile = path.join(destRoot, '.claude', VERSION_FILE);
|
|
114
|
+
ensureDir(versionFile);
|
|
115
|
+
fs.writeFileSync(versionFile, TOOLKIT_VERSION, 'utf8');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function checkVersion(destRoot, force) {
|
|
119
|
+
const installed = readInstalledVersion(destRoot);
|
|
120
|
+
if (!installed) return true;
|
|
121
|
+
|
|
122
|
+
console.log(divider());
|
|
123
|
+
console.log(bold(' Version check'));
|
|
124
|
+
console.log(divider());
|
|
125
|
+
|
|
126
|
+
if (installed === TOOLKIT_VERSION) {
|
|
127
|
+
console.log(` ${clr('green', '✔')} Installed : ${clr('green', `v${installed}`)}`);
|
|
128
|
+
console.log(` ${clr('blue', '●')} Available : ${clr('blue', `v${TOOLKIT_VERSION}`)}`);
|
|
129
|
+
console.log(`\n ${clr('yellow', 'Already up to date.')}`);
|
|
130
|
+
if (!force) {
|
|
131
|
+
const ok = await askConfirm('Re-install anyway?');
|
|
132
|
+
if (!ok) { console.log(`\n ${clr('gray', 'Aborted. Nothing was changed.')}\n`); process.exit(0); }
|
|
133
|
+
}
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log(` ${clr('yellow', '◎')} Installed : ${clr('yellow', `v${installed}`)}`);
|
|
138
|
+
console.log(` ${clr('green', '▲')} Available : ${clr('green', `v${TOOLKIT_VERSION}`)}`);
|
|
139
|
+
console.log();
|
|
140
|
+
const ok = await askConfirm(`Update toolkit from ${clr('yellow', `v${installed}`)} to ${clr('green', `v${TOOLKIT_VERSION}`)}?`);
|
|
141
|
+
if (!ok) {
|
|
142
|
+
console.log(`\n ${clr('gray', 'Aborted. Your installation was not changed.')}\n`);
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ── install ───────────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
async function runInstall(label, mappings, force) {
|
|
151
|
+
const files = expandMappings(mappings);
|
|
152
|
+
const entries = categorize(files);
|
|
153
|
+
|
|
154
|
+
const newFiles = entries.filter(e => e.status === 'new');
|
|
155
|
+
const modified = entries.filter(e => e.status === 'modified');
|
|
156
|
+
const same = entries.filter(e => e.status === 'same');
|
|
157
|
+
|
|
158
|
+
console.log();
|
|
159
|
+
console.log(`${bold('📦 Install plan')} ${clr('gray', '→')} ${clr('cyan', label)}`);
|
|
160
|
+
console.log(divider());
|
|
161
|
+
for (const e of newFiles) console.log(` ${clr('green', '✚')} ${clr('green', 'NEW ')} ${dim(path.relative(process.cwd(), e.dest))}`);
|
|
162
|
+
for (const e of modified) console.log(` ${clr('yellow', '~')} ${clr('yellow', 'MODIFIED')} ${path.relative(process.cwd(), e.dest)}`);
|
|
163
|
+
for (const e of same) console.log(` ${clr('gray', '=')} ${clr('gray', 'SAME ')} ${dim(path.relative(process.cwd(), e.dest))}`);
|
|
164
|
+
console.log(divider());
|
|
165
|
+
console.log(
|
|
166
|
+
` ${clr('green', `✚ New: ${newFiles.length}`)}` +
|
|
167
|
+
` ${clr('yellow', `~ Modified: ${modified.length}`)}` +
|
|
168
|
+
` ${clr('gray', `= Unchanged: ${same.length}`)}`
|
|
169
|
+
);
|
|
170
|
+
console.log();
|
|
171
|
+
|
|
172
|
+
for (const e of newFiles) {
|
|
173
|
+
ensureDir(e.dest);
|
|
174
|
+
fs.copyFileSync(e.src, e.dest);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (modified.length === 0) {
|
|
178
|
+
console.log(` ${clr('green', '✔')} All new files copied. No conflicts.\n`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (force) {
|
|
183
|
+
console.log(` ${clr('yellow', '⚑')} --force: overwriting all modified files.`);
|
|
184
|
+
for (const e of modified) {
|
|
185
|
+
ensureDir(e.dest);
|
|
186
|
+
fs.copyFileSync(e.src, e.dest);
|
|
187
|
+
console.log(` ${clr('yellow', '↺')} ${dim(path.relative(process.cwd(), e.dest))}`);
|
|
188
|
+
}
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log(` ${clr('yellow', 'These files differ from the toolkit version — decide for each:')}\n`);
|
|
193
|
+
|
|
194
|
+
let overwritten = 0;
|
|
195
|
+
let skipped = 0;
|
|
196
|
+
|
|
197
|
+
for (const e of modified) {
|
|
198
|
+
const rel = path.relative(process.cwd(), e.dest);
|
|
199
|
+
const ok = await askConfirm(` Overwrite ${clr('yellow', rel)}?`);
|
|
200
|
+
if (ok) {
|
|
201
|
+
ensureDir(e.dest);
|
|
202
|
+
fs.copyFileSync(e.src, e.dest);
|
|
203
|
+
console.log(` ${clr('green', '✔')} Overwritten\n`);
|
|
204
|
+
overwritten++;
|
|
205
|
+
} else {
|
|
206
|
+
console.log(` ${clr('gray', '✖')} Kept as-is\n`);
|
|
207
|
+
skipped++;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(divider());
|
|
212
|
+
console.log(
|
|
213
|
+
` ${clr('green', `✔ Overwritten: ${overwritten}`)}` +
|
|
214
|
+
` ${clr('gray', `✖ Kept as-is: ${skipped}`)}\n`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ── Matt Pocock skills ───────────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
function isMattPocockInstalled() {
|
|
221
|
+
const homedir = require('os').homedir();
|
|
222
|
+
// 'grilling' is a skill exclusive to Matt Pocock's package — not included in this toolkit
|
|
223
|
+
const pathsToCheck = [
|
|
224
|
+
path.join(homedir, '.claude', 'skills', 'grilling', 'SKILL.md'),
|
|
225
|
+
path.join(process.cwd(), '.claude', 'skills', 'grilling', 'SKILL.md'),
|
|
226
|
+
];
|
|
227
|
+
return pathsToCheck.some(p => fs.existsSync(p));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function installMattPocock() {
|
|
231
|
+
const { execSync } = require('child_process');
|
|
232
|
+
console.log(`\n ${clr('cyan', '↓')} Running: ${dim('npx skills@latest add mattpocock/skills')}\n`);
|
|
233
|
+
try {
|
|
234
|
+
execSync('npx skills@latest add mattpocock/skills', { stdio: 'inherit' });
|
|
235
|
+
console.log(`\n ${clr('green', '✔')} Matt Pocock skills installed successfully.\n`);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.error(`\n ${clr('red', '✖')} Install failed: ${err.message}`);
|
|
238
|
+
console.error(` Run manually: ${dim('npx skills@latest add mattpocock/skills')}\n`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function askMattPocock() {
|
|
243
|
+
const installed = isMattPocockInstalled();
|
|
244
|
+
|
|
245
|
+
console.log(divider());
|
|
246
|
+
console.log(bold(' Matt Pocock Skills'));
|
|
247
|
+
console.log(divider());
|
|
248
|
+
console.log(` ${dim('Includes: define-feature, grilling, TDD, prototype, handoff, and more.')}`);
|
|
249
|
+
console.log();
|
|
250
|
+
|
|
251
|
+
if (!installed) {
|
|
252
|
+
console.log(` ${clr('gray', '○')} Status : ${clr('gray', 'not installed')}\n`);
|
|
253
|
+
const ok = await askConfirm('Install Matt Pocock\'s skills now?');
|
|
254
|
+
if (ok) await installMattPocock();
|
|
255
|
+
else console.log(`\n ${clr('gray', 'Skipped. Install later with: npx skills@latest add mattpocock/skills')}\n`);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
console.log(` ${clr('green', '✔')} Status : ${clr('green', 'installed')}\n`);
|
|
260
|
+
const ok = await askConfirm('Re-install / update Matt Pocock skills?');
|
|
261
|
+
if (ok) await installMattPocock();
|
|
262
|
+
else console.log(` ${clr('gray', 'Skipped.')}\n`);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ── entry points ──────────────────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
async function installLocal(targetDir, force) {
|
|
268
|
+
banner();
|
|
269
|
+
targetDir = path.resolve(process.cwd(), targetDir || '.');
|
|
270
|
+
console.log(` ${clr('cyan', '▸')} Target: ${bold(targetDir)}\n`);
|
|
271
|
+
await checkVersion(targetDir, force);
|
|
272
|
+
const mappings = [
|
|
273
|
+
{ src: path.join(packageRoot, '.claude'), dest: path.join(targetDir, '.claude') },
|
|
274
|
+
{ src: path.join(packageRoot, 'docs'), dest: path.join(targetDir, 'docs') },
|
|
275
|
+
{ src: path.join(packageRoot, 'CLAUDE.md'), dest: path.join(targetDir, 'CLAUDE.md') },
|
|
276
|
+
];
|
|
277
|
+
await runInstall(`local project`, mappings, force);
|
|
278
|
+
writeInstalledVersion(targetDir);
|
|
279
|
+
console.log(` ${clr('green', '✔')} ${bold('Install complete.')}\n`);
|
|
280
|
+
await askMattPocock();
|
|
281
|
+
console.log(divider());
|
|
282
|
+
console.log(`\n ${bold('Next steps:')}`);
|
|
283
|
+
console.log(` ${clr('cyan', '1.')} Run ${clr('cyan', '/init-agents')} to generate AGENTS.md`);
|
|
284
|
+
console.log(` ${clr('cyan', '2.')} Create a feature doc and run ${clr('cyan', '/implement-feature')}`);
|
|
285
|
+
console.log();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async function installGlobal(force) {
|
|
289
|
+
banner();
|
|
290
|
+
try {
|
|
291
|
+
const homedir = require('os').homedir();
|
|
292
|
+
const target = path.join(homedir, '.claude');
|
|
293
|
+
console.log(` ${clr('cyan', '▸')} Target: ${bold(target)} ${clr('gray', '(global Claude folder)')}\n`);
|
|
294
|
+
await checkVersion(target, force);
|
|
295
|
+
const mappings = [
|
|
296
|
+
{ src: path.join(packageRoot, '.claude', 'agents'), dest: path.join(target, 'agents') },
|
|
297
|
+
{ src: path.join(packageRoot, '.claude', 'skills'), dest: path.join(target, 'skills') },
|
|
298
|
+
{ src: path.join(packageRoot, '.claude', 'commands'), dest: path.join(target, 'commands') },
|
|
299
|
+
{ src: path.join(packageRoot, 'docs'), dest: path.join(target, 'docs') },
|
|
300
|
+
{ src: path.join(packageRoot, 'CLAUDE.md'), dest: path.join(target, 'CLAUDE.md') },
|
|
301
|
+
];
|
|
302
|
+
await runInstall('global Claude folder', mappings, force);
|
|
303
|
+
writeInstalledVersion(target);
|
|
304
|
+
console.log(` ${clr('green', '✔')} ${bold('Global install complete.')}\n`);
|
|
305
|
+
await askMattPocock();
|
|
306
|
+
console.log(divider());
|
|
307
|
+
console.log(`\n ${bold('Next steps:')}`);
|
|
308
|
+
console.log(` ${clr('cyan', '1.')} The toolkit is now available in all your projects`);
|
|
309
|
+
console.log(` ${clr('cyan', '2.')} Open any project and run ${clr('cyan', '/init-agents')}`);
|
|
310
|
+
console.log();
|
|
311
|
+
} catch (err) {
|
|
312
|
+
console.error(`\n ${clr('red', '✖')} Global install failed: ${err.message}\n`);
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function help() {
|
|
318
|
+
banner();
|
|
319
|
+
console.log(` ${bold('Usage:')}`);
|
|
320
|
+
console.log(` ${clr('cyan', 'ai-toolkit')} Install into current directory`);
|
|
321
|
+
console.log(` ${clr('cyan', 'ai-toolkit')} ${clr('yellow', '--local <dir>')} Install into target directory`);
|
|
322
|
+
console.log(` ${clr('cyan', 'ai-toolkit')} ${clr('yellow', '--global')} Install into ~/.claude (global)`);
|
|
323
|
+
console.log(` ${clr('gray', ' --force')} Overwrite all files without prompting`);
|
|
324
|
+
console.log();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async function main() {
|
|
328
|
+
const argv = process.argv.slice(2);
|
|
329
|
+
const force = argv.includes('--force');
|
|
330
|
+
|
|
331
|
+
if (argv.length === 0 || (argv.length === 1 && argv[0] === '--force')) {
|
|
332
|
+
await installLocal('.', force);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (argv[0] === '--local') {
|
|
337
|
+
await installLocal(argv[1] || '.', force);
|
|
338
|
+
} else if (argv[0] === '--global') {
|
|
339
|
+
await installGlobal(force);
|
|
340
|
+
} else if (argv[0] === 'help' || argv[0] === '--help') {
|
|
341
|
+
help();
|
|
342
|
+
} else if (fs.existsSync(argv[0]) && fs.statSync(argv[0]).isDirectory()) {
|
|
343
|
+
await installLocal(argv[0], force);
|
|
344
|
+
} else {
|
|
345
|
+
help();
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
main();
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
The toolkit is published to the **public npm registry** under the `@dtlabs` organization.
|
|
4
|
+
|
|
5
|
+
- **Package**: `@dtlabs/ai-toolkit`
|
|
6
|
+
- **Registry**: `https://registry.npmjs.org/`
|
|
7
|
+
|
|
8
|
+
No authentication setup required — it is a public package.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Local installation (default)
|
|
15
|
+
|
|
16
|
+
Copies `.claude/`, `docs/`, and `CLAUDE.md` into the current directory:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @dtlabs/ai-toolkit
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Target a different directory:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @dtlabs/ai-toolkit --local /path/to/project
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Overwrite existing files without confirmation:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx @dtlabs/ai-toolkit --local . --force
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Global installation
|
|
35
|
+
|
|
36
|
+
Merges `.claude/agents`, `.claude/skills`, `docs/`, and `CLAUDE.md` into `~/.claude/`:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g @dtlabs/ai-toolkit
|
|
40
|
+
ai-toolkit --global
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Force overwrite:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
ai-toolkit --global --force
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### What gets copied where
|
|
50
|
+
|
|
51
|
+
| Mode | Source (in package) | Destination |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| Local | `.claude/` | `<target>/.claude/` |
|
|
54
|
+
| Local | `docs/` | `<target>/docs/` |
|
|
55
|
+
| Local | `CLAUDE.md` | `<target>/CLAUDE.md` |
|
|
56
|
+
| Global | `.claude/agents/` | `~/.claude/agents/` |
|
|
57
|
+
| Global | `.claude/skills/` | `~/.claude/skills/` |
|
|
58
|
+
| Global | `.claude/commands/` | `~/.claude/commands/` |
|
|
59
|
+
| Global | `docs/` | `~/.claude/docs/` |
|
|
60
|
+
| Global | `CLAUDE.md` | `~/.claude/CLAUDE.md` |
|
|
61
|
+
|
|
62
|
+
> The asymmetry is intentional: locally you mirror the package layout, globally you merge into Claude Code's standard folder structure.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Verify installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm view @dtlabs/ai-toolkit version
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Publishing a new version
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm login # authenticate with your npmjs.com account
|
|
78
|
+
npm version patch # bump version (patch / minor / major)
|
|
79
|
+
npm publish --access public # --access public is required for scoped packages
|
|
80
|
+
```
|
package/docs/pricing.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# AI Model Pricing Reference
|
|
2
|
+
|
|
3
|
+
> This file contains LLM pricing data used for cost estimation in feature delivery and assessment pipelines.
|
|
4
|
+
> Update manually when provider pricing changes.
|
|
5
|
+
>
|
|
6
|
+
> **Last updated:** 2026-07-10
|
|
7
|
+
> **Source:** https://platform.claude.com/docs/about-claude/pricing
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Cost estimation parameters
|
|
12
|
+
|
|
13
|
+
| Parameter | Value | Notes |
|
|
14
|
+
|-----------|-------|-------|
|
|
15
|
+
| Input token share | 80% | Assumed proportion of total tokens used as input |
|
|
16
|
+
| Output token share | 20% | Assumed proportion of total tokens used as output |
|
|
17
|
+
|
|
18
|
+
These two parameters drive the blended cost formula used by all pipeline agents:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
blended_cost = tokens × (0.80 × input_price_per_token + 0.20 × output_price_per_token)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Adjust the percentages here if empirical data suggests a different ratio.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Anthropic — Claude models
|
|
29
|
+
|
|
30
|
+
Prices are in **USD per million tokens ($/MTok)**.
|
|
31
|
+
|
|
32
|
+
### Standard API
|
|
33
|
+
|
|
34
|
+
| Model | Input ($/MTok) | Output ($/MTok) | Notes |
|
|
35
|
+
|-------|---------------|----------------|-------|
|
|
36
|
+
| Claude Fable 5 | $10.00 | $50.00 | |
|
|
37
|
+
| Claude Mythos 5 | $10.00 | $50.00 | |
|
|
38
|
+
| Claude Opus 4.8 | $5.00 | $25.00 | |
|
|
39
|
+
| Claude Opus 4.7 | $5.00 | $25.00 | |
|
|
40
|
+
| Claude Opus 4.6 | $5.00 | $25.00 | |
|
|
41
|
+
| Claude Opus 4.5 | $5.00 | $25.00 | |
|
|
42
|
+
| Claude Sonnet 5 | $2.00 | $10.00 | Promotional until 2026-08-31 |
|
|
43
|
+
| Claude Sonnet 5 | $3.00 | $15.00 | From 2026-09-01 |
|
|
44
|
+
| Claude Sonnet 4.6 | $3.00 | $15.00 | |
|
|
45
|
+
| Claude Sonnet 4.5 | $3.00 | $15.00 | |
|
|
46
|
+
| Claude Haiku 4.5 | $1.00 | $5.00 | |
|
|
47
|
+
|
|
48
|
+
### Prompt caching add-on ($/MTok on top of input price)
|
|
49
|
+
|
|
50
|
+
| Cache type | Write surcharge |
|
|
51
|
+
|------------|----------------|
|
|
52
|
+
| 5-minute cache write | +25% of input price |
|
|
53
|
+
| 1-hour cache write | +100% of input price |
|
|
54
|
+
| Cache read (hit) | −80% of input price |
|
|
55
|
+
|
|
56
|
+
### Batch API
|
|
57
|
+
|
|
58
|
+
50% discount on both input and output prices for all models.
|
|
59
|
+
|
|
60
|
+
### Tool use
|
|
61
|
+
|
|
62
|
+
| Tool | Cost |
|
|
63
|
+
|------|------|
|
|
64
|
+
| Web search | $10.00 / 1,000 searches |
|
|
65
|
+
| Code execution | Free (first 1,550 hours/month), then $0.05/hour |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Blended unit cost reference
|
|
70
|
+
|
|
71
|
+
Pre-computed blended cost per 1,000 tokens using the 80/20 split above.
|
|
72
|
+
Use these values for quick estimates without recalculating.
|
|
73
|
+
|
|
74
|
+
| Model | Input ($/MTok) | Output ($/MTok) | Blended ($/1k tokens) |
|
|
75
|
+
|-------|---------------|----------------|-----------------------|
|
|
76
|
+
| Claude Fable 5 | $10.00 | $50.00 | $0.018000 |
|
|
77
|
+
| Claude Opus 4.8 | $5.00 | $25.00 | $0.009000 |
|
|
78
|
+
| Claude Sonnet 5 (promo) | $2.00 | $10.00 | $0.003600 |
|
|
79
|
+
| Claude Sonnet 5 | $3.00 | $15.00 | $0.005400 |
|
|
80
|
+
| Claude Sonnet 4.5/4.6 | $3.00 | $15.00 | $0.005400 |
|
|
81
|
+
| Claude Haiku 4.5 | $1.00 | $5.00 | $0.001800 |
|
|
82
|
+
|
|
83
|
+
> Formula: `blended = (input × 0.80 + output × 0.20) / 1,000`
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Adding other providers
|
|
88
|
+
|
|
89
|
+
To add pricing for another provider (OpenAI, Google, Azure, etc.), append a new section following the same structure:
|
|
90
|
+
|
|
91
|
+
```markdown
|
|
92
|
+
## {Provider name} — {Model family}
|
|
93
|
+
|
|
94
|
+
| Model | Input ($/MTok) | Output ($/MTok) | Notes |
|
|
95
|
+
|-------|---------------|----------------|-------|
|
|
96
|
+
| ... | ... | ... | ... |
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Update the **Blended unit cost reference** table accordingly.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Procedure: Approval Gates
|
|
2
|
+
|
|
3
|
+
Two mandatory approval gates block the pipeline. **No phase after a gate may start without a
|
|
4
|
+
verified, written approval record.** This is a hard stop — not a suggestion.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Gate 1 — Docs Approval (after validation passes)
|
|
9
|
+
|
|
10
|
+
### Step 1 — Present documents
|
|
11
|
+
|
|
12
|
+
Show the user a summary of the generated documents:
|
|
13
|
+
- `{PREFIX}-Requirements.md` — N use cases, N business rules, N acceptance criteria
|
|
14
|
+
- `{PREFIX}-Tech-Spec.md` — N endpoints, N entities, N new files
|
|
15
|
+
- `{PREFIX}-Validation-Report.md` — N gaps found / 0 gaps
|
|
16
|
+
|
|
17
|
+
### Step 2 — Request explicit sign-off
|
|
18
|
+
|
|
19
|
+
Use `AskUserQuestion` with this exact phrasing:
|
|
20
|
+
|
|
21
|
+
> **"Please review the documents above and choose one of the options below.
|
|
22
|
+
> The pipeline CANNOT continue until you make a selection."**
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
- **"Approve — proceed to Work Breakdown"**
|
|
26
|
+
- **"Request changes"** — describe what to change; the pipeline re-runs affected agents, re-validates, and returns here (max 2 revision cycles)
|
|
27
|
+
- **"Approve with notes"** — accepted with comments recorded in the approval file
|
|
28
|
+
|
|
29
|
+
### Step 3 — Write approval record BEFORE continuing
|
|
30
|
+
|
|
31
|
+
Immediately after the user approves, write `{PREFIX}-Approvals.md`:
|
|
32
|
+
|
|
33
|
+
```markdown
|
|
34
|
+
# Approval Record — {PREFIX}
|
|
35
|
+
|
|
36
|
+
## Gate 1 — Document Approvals
|
|
37
|
+
|
|
38
|
+
| Document | Status | Date | Notes |
|
|
39
|
+
|----------|--------|------|-------|
|
|
40
|
+
| {PREFIX}-Requirements.md | ✅ Approved | {date} | {notes or —} |
|
|
41
|
+
| {PREFIX}-Tech-Spec.md | ✅ Approved | {date} | {notes or —} |
|
|
42
|
+
| {PREFIX}-Validation-Report.md | ✅ Approved | {date} | {notes or —} |
|
|
43
|
+
|
|
44
|
+
## Approval History
|
|
45
|
+
|
|
46
|
+
| Cycle | Action | Date | Details |
|
|
47
|
+
|-------|--------|------|---------|
|
|
48
|
+
| 1 | {action} | {date} | {details} |
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Step 4 — Verify the file was written
|
|
52
|
+
|
|
53
|
+
Read back `{PREFIX}-Approvals.md` and confirm it contains the Gate 1 section with ✅ status.
|
|
54
|
+
If the file is missing or incomplete, **do not proceed** — write it again.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Gate 2 — Work Breakdown Approval (after WB generation)
|
|
59
|
+
|
|
60
|
+
### Step 1 — Pre-condition check (MANDATORY)
|
|
61
|
+
|
|
62
|
+
**Before doing anything in this gate**, read `{PREFIX}-Approvals.md` and verify it contains
|
|
63
|
+
"Gate 1 — Document Approvals" with ✅ status on all three documents.
|
|
64
|
+
|
|
65
|
+
If Gate 1 approval is missing:
|
|
66
|
+
```
|
|
67
|
+
⛔ HARD STOP — Gate 1 approval not found in {PREFIX}-Approvals.md.
|
|
68
|
+
Work Breakdown Approval cannot proceed without prior document approval.
|
|
69
|
+
Returning to Gate 1.
|
|
70
|
+
```
|
|
71
|
+
Go back and execute Gate 1 before continuing.
|
|
72
|
+
|
|
73
|
+
### Step 2 — Present Work Breakdown
|
|
74
|
+
|
|
75
|
+
Show key metrics:
|
|
76
|
+
- User Stories: N (US-01 ÷ US-NN)
|
|
77
|
+
- Total tasks: N (DB:N, BE:N, FE:N, INFRA:N, TEST:N)
|
|
78
|
+
- Implementation phases: N
|
|
79
|
+
- Human estimate: ~Nh | Agent estimate: ~Nh Nmin
|
|
80
|
+
- Reference: `{PREFIX}-Effort-Estimate.md` for full detail
|
|
81
|
+
|
|
82
|
+
### Step 3 — Request explicit sign-off
|
|
83
|
+
|
|
84
|
+
Use `AskUserQuestion`:
|
|
85
|
+
|
|
86
|
+
> **"Please review the Work Breakdown above and choose one of the options below.
|
|
87
|
+
> Implementation CANNOT start until you approve."**
|
|
88
|
+
|
|
89
|
+
Options:
|
|
90
|
+
- **"Approve — start implementation"**
|
|
91
|
+
- **"Request changes"** — re-run `generate-work-breakdown` with feedback (max 2 cycles)
|
|
92
|
+
- **"Approve with notes"** — accepted with comments recorded
|
|
93
|
+
|
|
94
|
+
### Step 4 — Update approval record BEFORE starting implementation
|
|
95
|
+
|
|
96
|
+
Append to `{PREFIX}-Approvals.md`:
|
|
97
|
+
|
|
98
|
+
```markdown
|
|
99
|
+
## Gate 2 — Work Breakdown Approval
|
|
100
|
+
|
|
101
|
+
| Document | Status | Date | Notes |
|
|
102
|
+
|----------|--------|------|-------|
|
|
103
|
+
| {PREFIX}-Work-Breakdown.md | ✅ Approved | {date} | {N} tasks, {N} phases |
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Step 5 — Verify before proceeding
|
|
107
|
+
|
|
108
|
+
Read back `{PREFIX}-Approvals.md` and confirm Gate 2 section is present with ✅ status.
|
|
109
|
+
If missing, **do not start implementation** — write it again.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Pre-condition check for implementation (Phase 6)
|
|
114
|
+
|
|
115
|
+
**At the very start of Phase 6 (before creating the branch or writing any code)**,
|
|
116
|
+
read `{PREFIX}-Approvals.md` and verify BOTH gates are present and approved:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
✅ Gate 1 — Document Approvals: Requirements ✅ | Tech-Spec ✅ | Validation ✅
|
|
120
|
+
✅ Gate 2 — Work Breakdown Approval: Work-Breakdown ✅
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
If either gate is missing or shows a non-✅ status:
|
|
124
|
+
```
|
|
125
|
+
⛔ HARD STOP — Required approval missing in {PREFIX}-Approvals.md.
|
|
126
|
+
Gate {N} approval is required before implementation can start.
|
|
127
|
+
Returning to Gate {N}.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This check is the last line of defence. Even if the PM believes it ran the gates, it must
|
|
131
|
+
verify the file on disk before touching the codebase.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Rules
|
|
136
|
+
|
|
137
|
+
- **Gates are hard stops, not suggestions** — the PM must use `AskUserQuestion` and wait for a response; it cannot auto-approve or assume approval
|
|
138
|
+
- **Write the approval file before continuing** — the file is the contract; if it doesn't exist, the gate did not happen
|
|
139
|
+
- **Verify the file after writing** — read it back to confirm
|
|
140
|
+
- **Pre-condition check at Phase 6** — always verify both gates on disk before any code change
|
|
141
|
+
- **Max 2 revision cycles** per gate — if still not approved after 2 cycles, stop and escalate to user
|
|
142
|
+
- **Log every gate event** in the process log (gate opened, user response, file written, pre-condition check result)
|