plan-flow-skill 1.0.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/.claude/commands/create-contract.md +468 -0
- package/.claude/commands/create-plan.md +512 -0
- package/.claude/commands/discovery-plan.md +561 -0
- package/.claude/commands/execute-plan.md +682 -0
- package/.claude/commands/review-code.md +459 -0
- package/.claude/commands/review-pr.md +651 -0
- package/.claude/commands/setup.md +1609 -0
- package/.claude/commands/write-tests.md +543 -0
- package/.claude/rules/core/allowed-patterns.md +175 -0
- package/.claude/rules/core/complexity-scoring.md +225 -0
- package/.claude/rules/core/forbidden-patterns.md +253 -0
- package/.claude/rules/languages/python-patterns.md +6 -0
- package/.claude/rules/languages/typescript-patterns.md +7 -0
- package/.claude/rules/patterns/contract-patterns.md +332 -0
- package/.claude/rules/patterns/discovery-patterns.md +342 -0
- package/.claude/rules/patterns/discovery-templates.md +319 -0
- package/.claude/rules/patterns/jest-patterns.md +482 -0
- package/.claude/rules/patterns/plans-patterns.md +225 -0
- package/.claude/rules/patterns/plans-templates.md +227 -0
- package/.claude/rules/patterns/pytest-patterns.md +457 -0
- package/.claude/rules/patterns/review-code-templates.md +305 -0
- package/.claude/rules/patterns/review-pr-patterns.md +360 -0
- package/.claude/rules/tools/auth-pr-tool.md +30 -0
- package/.claude/rules/tools/interactive-questions-tool.md +235 -0
- package/.claude/rules/tools/jest-testing-tool.md +73 -0
- package/.claude/rules/tools/plan-mode-tool.md +164 -0
- package/.claude/rules/tools/pytest-testing-tool.md +121 -0
- package/.claude/rules/tools/reference-expansion-tool.md +326 -0
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +139 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/handlers/claude.d.ts +9 -0
- package/dist/cli/handlers/claude.d.ts.map +1 -0
- package/dist/cli/handlers/claude.js +119 -0
- package/dist/cli/handlers/claude.js.map +1 -0
- package/dist/cli/handlers/codex.d.ts +9 -0
- package/dist/cli/handlers/codex.d.ts.map +1 -0
- package/dist/cli/handlers/codex.js +100 -0
- package/dist/cli/handlers/codex.js.map +1 -0
- package/dist/cli/handlers/cursor.d.ts +8 -0
- package/dist/cli/handlers/cursor.d.ts.map +1 -0
- package/dist/cli/handlers/cursor.js +34 -0
- package/dist/cli/handlers/cursor.js.map +1 -0
- package/dist/cli/handlers/openclaw.d.ts +8 -0
- package/dist/cli/handlers/openclaw.d.ts.map +1 -0
- package/dist/cli/handlers/openclaw.js +34 -0
- package/dist/cli/handlers/openclaw.js.map +1 -0
- package/dist/cli/handlers/shared.d.ts +9 -0
- package/dist/cli/handlers/shared.d.ts.map +1 -0
- package/dist/cli/handlers/shared.js +44 -0
- package/dist/cli/handlers/shared.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +43 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/types.d.ts +26 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +5 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/utils/files.d.ts +37 -0
- package/dist/cli/utils/files.d.ts.map +1 -0
- package/dist/cli/utils/files.js +122 -0
- package/dist/cli/utils/files.js.map +1 -0
- package/dist/cli/utils/logger.d.ts +11 -0
- package/dist/cli/utils/logger.d.ts.map +1 -0
- package/dist/cli/utils/logger.js +34 -0
- package/dist/cli/utils/logger.js.map +1 -0
- package/dist/cli/utils/prompts.d.ts +10 -0
- package/dist/cli/utils/prompts.d.ts.map +1 -0
- package/dist/cli/utils/prompts.js +65 -0
- package/dist/cli/utils/prompts.js.map +1 -0
- package/dist/test/setup.d.ts +5 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +7 -0
- package/dist/test/setup.js.map +1 -0
- package/package.json +63 -0
- package/rules/core/_index.mdc +89 -0
- package/rules/core/allowed-patterns.mdc +185 -0
- package/rules/core/complexity-scoring.mdc +235 -0
- package/rules/core/forbidden-patterns.mdc +263 -0
- package/rules/languages/_index.mdc +80 -0
- package/rules/languages/python-patterns.mdc +188 -0
- package/rules/languages/typescript-patterns.mdc +128 -0
- package/rules/patterns/_index.mdc +185 -0
- package/rules/patterns/contract-patterns.mdc +344 -0
- package/rules/patterns/discovery-patterns.mdc +354 -0
- package/rules/patterns/discovery-templates.mdc +329 -0
- package/rules/patterns/jest-patterns.mdc +492 -0
- package/rules/patterns/plans-patterns.mdc +237 -0
- package/rules/patterns/plans-templates.mdc +237 -0
- package/rules/patterns/pytest-patterns.mdc +467 -0
- package/rules/patterns/review-code-templates.mdc +315 -0
- package/rules/patterns/review-pr-patterns.mdc +370 -0
- package/rules/skills/_index.mdc +174 -0
- package/rules/skills/create-contract-skill.mdc +239 -0
- package/rules/skills/create-plan-skill.mdc +271 -0
- package/rules/skills/discovery-skill.mdc +295 -0
- package/rules/skills/execute-plan-skill.mdc +388 -0
- package/rules/skills/review-code-skill.mdc +308 -0
- package/rules/skills/review-pr-skill.mdc +496 -0
- package/rules/skills/setup-skill.mdc +923 -0
- package/rules/skills/write-tests-skill.mdc +294 -0
- package/rules/templates/index-template.mdc +126 -0
- package/rules/tools/_index.mdc +114 -0
- package/rules/tools/auth-pr-tool.mdc +362 -0
- package/rules/tools/interactive-questions-tool.mdc +337 -0
- package/rules/tools/jest-testing-tool.mdc +96 -0
- package/rules/tools/plan-mode-tool.mdc +229 -0
- package/rules/tools/pytest-testing-tool.mdc +144 -0
- package/rules/tools/reference-expansion-tool.mdc +338 -0
- package/skills/plan-flow/SKILL.md +109 -0
- package/skills/plan-flow/create-contract/SKILL.md +139 -0
- package/skills/plan-flow/create-plan/SKILL.md +93 -0
- package/skills/plan-flow/discovery/SKILL.md +85 -0
- package/skills/plan-flow/execute-plan/SKILL.md +89 -0
- package/skills/plan-flow/review-code/SKILL.md +100 -0
- package/skills/plan-flow/review-pr/SKILL.md +122 -0
- package/skills/plan-flow/setup/SKILL.md +73 -0
- package/skills/plan-flow/write-tests/SKILL.md +115 -0
- package/templates/shared/AGENTS.md.template +60 -0
- package/templates/shared/CLAUDE.md.template +62 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File operation utilities for the init command
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, copyFileSync, readdirSync, readFileSync, statSync, } from 'node:fs';
|
|
5
|
+
import { join, dirname, relative, resolve } from 'node:path';
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the package root directory by finding the nearest package.json
|
|
8
|
+
* with name "plan-flow" starting from a known internal path.
|
|
9
|
+
*
|
|
10
|
+
* Works with:
|
|
11
|
+
* - Local development (src/cli/utils/)
|
|
12
|
+
* - Built output (dist/cli/utils/)
|
|
13
|
+
* - npx / global install (node_modules/plan-flow/dist/cli/utils/)
|
|
14
|
+
* - Jest/CJS (__dirname available)
|
|
15
|
+
*/
|
|
16
|
+
export function getPackageRoot() {
|
|
17
|
+
// __dirname works in CJS (jest) and is polyfilled by NodeNext in ESM build
|
|
18
|
+
// For ESM, TypeScript with NodeNext module outputs proper __dirname equivalent
|
|
19
|
+
let startDir;
|
|
20
|
+
try {
|
|
21
|
+
// Works in CJS (jest) and NodeNext ESM builds
|
|
22
|
+
startDir = __dirname;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// Fallback: resolve from process.cwd() and look for package.json
|
|
26
|
+
startDir = process.cwd();
|
|
27
|
+
}
|
|
28
|
+
// Walk up looking for package.json with "name": "plan-flow"
|
|
29
|
+
let dir = startDir;
|
|
30
|
+
for (let i = 0; i < 10; i++) {
|
|
31
|
+
const pkgPath = join(dir, 'package.json');
|
|
32
|
+
if (existsSync(pkgPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
35
|
+
if (pkg.name === 'plan-flow') {
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Not valid JSON, continue walking up
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const parent = dirname(dir);
|
|
44
|
+
if (parent === dir)
|
|
45
|
+
break; // reached filesystem root
|
|
46
|
+
dir = parent;
|
|
47
|
+
}
|
|
48
|
+
// If we can't find it, fall back to 3 levels up from startDir
|
|
49
|
+
return resolve(startDir, '..', '..', '..');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Recursively copies a directory, preserving structure.
|
|
53
|
+
* Returns a CopyResult with created, skipped, and updated files.
|
|
54
|
+
*/
|
|
55
|
+
export function copyDir(src, dest, options) {
|
|
56
|
+
const result = { created: [], skipped: [], updated: [] };
|
|
57
|
+
if (!existsSync(src)) {
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
ensureDir(dest);
|
|
61
|
+
const entries = readdirSync(src);
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
const srcPath = join(src, entry);
|
|
64
|
+
const destPath = join(dest, entry);
|
|
65
|
+
const stat = statSync(srcPath);
|
|
66
|
+
if (stat.isDirectory()) {
|
|
67
|
+
const subResult = copyDir(srcPath, destPath, options);
|
|
68
|
+
result.created.push(...subResult.created);
|
|
69
|
+
result.skipped.push(...subResult.skipped);
|
|
70
|
+
result.updated.push(...subResult.updated);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const fileResult = copyFile(srcPath, destPath, options);
|
|
74
|
+
result.created.push(...fileResult.created);
|
|
75
|
+
result.skipped.push(...fileResult.skipped);
|
|
76
|
+
result.updated.push(...fileResult.updated);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Copies a single file with skip/overwrite logic.
|
|
83
|
+
*/
|
|
84
|
+
export function copyFile(src, dest, options) {
|
|
85
|
+
const result = { created: [], skipped: [], updated: [] };
|
|
86
|
+
ensureDir(dirname(dest));
|
|
87
|
+
if (existsSync(dest)) {
|
|
88
|
+
if (options.force) {
|
|
89
|
+
copyFileSync(src, dest);
|
|
90
|
+
result.updated.push(dest);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
result.skipped.push(dest);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
copyFileSync(src, dest);
|
|
98
|
+
result.created.push(dest);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Creates a directory recursively if it doesn't exist.
|
|
104
|
+
*/
|
|
105
|
+
export function ensureDir(dir) {
|
|
106
|
+
if (!existsSync(dir)) {
|
|
107
|
+
mkdirSync(dir, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Checks if a file or directory exists.
|
|
112
|
+
*/
|
|
113
|
+
export function fileExists(filePath) {
|
|
114
|
+
return existsSync(filePath);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Formats a file path relative to a base for display.
|
|
118
|
+
*/
|
|
119
|
+
export function relativePath(filePath, base) {
|
|
120
|
+
return relative(base, filePath);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../../src/cli/utils/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console output with ANSI colors (no external dependencies)
|
|
3
|
+
*/
|
|
4
|
+
export declare function success(msg: string): void;
|
|
5
|
+
export declare function warn(msg: string): void;
|
|
6
|
+
export declare function info(msg: string): void;
|
|
7
|
+
export declare function error(msg: string): void;
|
|
8
|
+
export declare function skip(msg: string): void;
|
|
9
|
+
export declare function header(msg: string): void;
|
|
10
|
+
export declare function blank(): void;
|
|
11
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtC;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEvC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtC;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAExC;AAED,wBAAgB,KAAK,IAAI,IAAI,CAE5B"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console output with ANSI colors (no external dependencies)
|
|
3
|
+
*/
|
|
4
|
+
const colors = {
|
|
5
|
+
green: '\x1b[32m',
|
|
6
|
+
yellow: '\x1b[33m',
|
|
7
|
+
blue: '\x1b[34m',
|
|
8
|
+
red: '\x1b[31m',
|
|
9
|
+
gray: '\x1b[90m',
|
|
10
|
+
bold: '\x1b[1m',
|
|
11
|
+
reset: '\x1b[0m',
|
|
12
|
+
};
|
|
13
|
+
export function success(msg) {
|
|
14
|
+
console.log(`${colors.green} +${colors.reset} ${msg}`);
|
|
15
|
+
}
|
|
16
|
+
export function warn(msg) {
|
|
17
|
+
console.log(`${colors.yellow} ~${colors.reset} ${msg}`);
|
|
18
|
+
}
|
|
19
|
+
export function info(msg) {
|
|
20
|
+
console.log(`${colors.blue} i${colors.reset} ${msg}`);
|
|
21
|
+
}
|
|
22
|
+
export function error(msg) {
|
|
23
|
+
console.log(`${colors.red} x${colors.reset} ${msg}`);
|
|
24
|
+
}
|
|
25
|
+
export function skip(msg) {
|
|
26
|
+
console.log(`${colors.gray} -${colors.reset} ${msg}`);
|
|
27
|
+
}
|
|
28
|
+
export function header(msg) {
|
|
29
|
+
console.log(`\n${colors.bold}${msg}${colors.reset}`);
|
|
30
|
+
}
|
|
31
|
+
export function blank() {
|
|
32
|
+
console.log('');
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/cli/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,GAAG;IACb,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,UAAU;IAChB,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;CACjB,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,MAAM,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,MAAM,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,MAAM,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive prompts using Node.js readline/promises
|
|
3
|
+
*/
|
|
4
|
+
import type { Platform } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Asks the user which platforms to install for.
|
|
7
|
+
* Returns selected platform names.
|
|
8
|
+
*/
|
|
9
|
+
export declare function selectPlatforms(): Promise<Platform[]>;
|
|
10
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CA6D3D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive prompts using Node.js readline/promises
|
|
3
|
+
*/
|
|
4
|
+
import { createInterface } from 'node:readline/promises';
|
|
5
|
+
import { stdin, stdout } from 'node:process';
|
|
6
|
+
/**
|
|
7
|
+
* Asks the user which platforms to install for.
|
|
8
|
+
* Returns selected platform names.
|
|
9
|
+
*/
|
|
10
|
+
export async function selectPlatforms() {
|
|
11
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
12
|
+
try {
|
|
13
|
+
console.log('\nWhich platform(s) would you like to install for?\n');
|
|
14
|
+
console.log(' 1. Claude Code (slash commands + rules)');
|
|
15
|
+
console.log(' 2. Cursor (rules)');
|
|
16
|
+
console.log(' 3. OpenClaw (skill manifests)');
|
|
17
|
+
console.log(' 4. Codex CLI (skills + AGENTS.md)');
|
|
18
|
+
console.log(' 5. All of the above');
|
|
19
|
+
console.log('');
|
|
20
|
+
const answer = await rl.question('Enter your choice (1-5, comma-separated): ');
|
|
21
|
+
const choices = answer
|
|
22
|
+
.split(',')
|
|
23
|
+
.map((s) => s.trim())
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
const platforms = [];
|
|
26
|
+
for (const choice of choices) {
|
|
27
|
+
switch (choice) {
|
|
28
|
+
case '1':
|
|
29
|
+
if (!platforms.includes('claude'))
|
|
30
|
+
platforms.push('claude');
|
|
31
|
+
break;
|
|
32
|
+
case '2':
|
|
33
|
+
if (!platforms.includes('cursor'))
|
|
34
|
+
platforms.push('cursor');
|
|
35
|
+
break;
|
|
36
|
+
case '3':
|
|
37
|
+
if (!platforms.includes('openclaw'))
|
|
38
|
+
platforms.push('openclaw');
|
|
39
|
+
break;
|
|
40
|
+
case '4':
|
|
41
|
+
if (!platforms.includes('codex'))
|
|
42
|
+
platforms.push('codex');
|
|
43
|
+
break;
|
|
44
|
+
case '5':
|
|
45
|
+
return ['claude', 'cursor', 'openclaw', 'codex'];
|
|
46
|
+
default:
|
|
47
|
+
// Try matching platform names directly
|
|
48
|
+
if (['claude', 'cursor', 'openclaw', 'codex'].includes(choice.toLowerCase())) {
|
|
49
|
+
const p = choice.toLowerCase();
|
|
50
|
+
if (!platforms.includes(p))
|
|
51
|
+
platforms.push(p);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (platforms.length === 0) {
|
|
56
|
+
console.log('\nNo valid platforms selected. Use --claude, --cursor, --openclaw, or --all flags.');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
return platforms;
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
rl.close();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/cli/utils/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG7C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC,CAAC;QAE/E,MAAM,OAAO,GAAG,MAAM;aACnB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnB,MAAM,SAAS,GAAe,EAAE,CAAC;QAEjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,GAAG;oBACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC5D,MAAM;gBACR,KAAK,GAAG;oBACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;wBAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC5D,MAAM;gBACR,KAAK,GAAG;oBACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC;wBAAE,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAChE,MAAM;gBACR,KAAK,GAAG;oBACN,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC;wBAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC1D,MAAM;gBACR,KAAK,GAAG;oBACN,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;gBACnD;oBACE,uCAAuC;oBACvC,IACE,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,QAAQ,CAChD,MAAM,CAAC,WAAW,EAAc,CACjC,EACD,CAAC;wBACD,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAc,CAAC;wBAC3C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;4BAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;oBAChD,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CACT,oFAAoF,CACrF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/test/setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,uCAAuC;AACvC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "plan-flow-skill",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Structured AI-assisted development workflows for discovery, planning, execution, code reviews, and testing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/cli/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"plan-flow": "./dist/cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/cli/index.js",
|
|
13
|
+
"dev": "tsx src/cli/index.ts",
|
|
14
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
15
|
+
"test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
|
|
16
|
+
"test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
|
|
17
|
+
"lint": "eslint src --ext .ts",
|
|
18
|
+
"lint:fix": "eslint src --ext .ts --fix",
|
|
19
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
20
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
21
|
+
"typecheck": "tsc --noEmit"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist/",
|
|
25
|
+
".claude/commands/",
|
|
26
|
+
".claude/rules/",
|
|
27
|
+
"rules/",
|
|
28
|
+
"skills/",
|
|
29
|
+
"templates/",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"keywords": [
|
|
34
|
+
"ai",
|
|
35
|
+
"cursor",
|
|
36
|
+
"claude",
|
|
37
|
+
"openclaw",
|
|
38
|
+
"codex",
|
|
39
|
+
"code-review",
|
|
40
|
+
"planning",
|
|
41
|
+
"development",
|
|
42
|
+
"structured-development",
|
|
43
|
+
"workflow",
|
|
44
|
+
"ai-assisted"
|
|
45
|
+
],
|
|
46
|
+
"author": "",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"commander": "^14.0.3"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/jest": "^29.5.14",
|
|
53
|
+
"@types/node": "^22.10.5",
|
|
54
|
+
"jest": "^29.7.0",
|
|
55
|
+
"prettier": "^3.4.2",
|
|
56
|
+
"ts-jest": "^29.2.5",
|
|
57
|
+
"tsx": "^4.7.0",
|
|
58
|
+
"typescript": "^5.9.3"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=18"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Summary index for core rules - load this to see available references"
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Core Rules Index
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Core rules define the foundational coding standards that apply across the entire project. These include best practices to follow (allowed patterns), anti-patterns to avoid (forbidden patterns), and complexity scoring for implementation planning.
|
|
11
|
+
|
|
12
|
+
**Total Files**: 3 files, ~683 lines
|
|
13
|
+
**Reference Codes**: COR-AP-1 through COR-CS-5
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Reference Codes
|
|
18
|
+
|
|
19
|
+
### Allowed Patterns (`allowed-patterns.mdc`)
|
|
20
|
+
|
|
21
|
+
| Code | Description | Source | Lines |
|
|
22
|
+
|------|-------------|--------|-------|
|
|
23
|
+
| COR-AP-1 | Example patterns (Naming, SRP, Errors, Types, Organization) | allowed-patterns.mdc | 45-152 |
|
|
24
|
+
| COR-AP-2 | Template for adding new patterns | allowed-patterns.mdc | 167-186 |
|
|
25
|
+
|
|
26
|
+
### Forbidden Patterns (`forbidden-patterns.mdc`)
|
|
27
|
+
|
|
28
|
+
| Code | Description | Source | Lines |
|
|
29
|
+
|------|-------------|--------|-------|
|
|
30
|
+
| COR-FP-1 | Example anti-patterns (Magic Numbers, Silent Errors, Ternaries, Mutation, Async) | forbidden-patterns.mdc | 41-230 |
|
|
31
|
+
| COR-FP-2 | Template for adding new anti-patterns | forbidden-patterns.mdc | 245-264 |
|
|
32
|
+
|
|
33
|
+
### Complexity Scoring (`complexity-scoring.mdc`)
|
|
34
|
+
|
|
35
|
+
| Code | Description | Source | Lines |
|
|
36
|
+
|------|-------------|--------|-------|
|
|
37
|
+
| COR-CS-1 | Complexity scale table (0-10 levels) | complexity-scoring.mdc | 12-21 |
|
|
38
|
+
| COR-CS-2 | Scoring criteria modifiers (+/- points) | complexity-scoring.mdc | 23-51 |
|
|
39
|
+
| COR-CS-3 | Execution strategy and aggregation rules | complexity-scoring.mdc | 53-70 |
|
|
40
|
+
| COR-CS-4 | Common complexity patterns table | complexity-scoring.mdc | 168-185 |
|
|
41
|
+
| COR-CS-5 | Real-world scoring examples | complexity-scoring.mdc | 187-236 |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## When to Expand
|
|
46
|
+
|
|
47
|
+
| Code | Expand When |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| COR-AP-1 | Need to see example good patterns for code generation |
|
|
50
|
+
| COR-AP-2 | Adding a new allowed pattern to the project |
|
|
51
|
+
| COR-FP-1 | Need to see anti-patterns to avoid |
|
|
52
|
+
| COR-FP-2 | Adding a new forbidden pattern to the project |
|
|
53
|
+
| COR-CS-1 | Need complexity level definitions |
|
|
54
|
+
| COR-CS-2 | Calculating complexity score for a phase |
|
|
55
|
+
| COR-CS-3 | Determining execution strategy for plan phases |
|
|
56
|
+
| COR-CS-4 | Quick lookup of typical complexity scores |
|
|
57
|
+
| COR-CS-5 | Need detailed scoring examples |
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Quick Reference
|
|
62
|
+
|
|
63
|
+
### Allowed Patterns Summary
|
|
64
|
+
- **Descriptive Naming**: Clear, self-documenting names
|
|
65
|
+
- **Single Responsibility**: One function = one purpose
|
|
66
|
+
- **Error Handling**: Explicit errors with logging
|
|
67
|
+
- **Type Safety**: Leverage TypeScript types
|
|
68
|
+
- **Code Organization**: Consistent folder structure
|
|
69
|
+
|
|
70
|
+
### Forbidden Patterns Summary
|
|
71
|
+
- **No Magic Numbers**: Use named constants
|
|
72
|
+
- **No Silent Errors**: Always log and handle
|
|
73
|
+
- **No Nested Ternaries**: Use if/else or switch
|
|
74
|
+
- **No Parameter Mutation**: Return new objects/arrays
|
|
75
|
+
- **No Mixed Async**: Use async/await consistently
|
|
76
|
+
|
|
77
|
+
### Complexity Levels
|
|
78
|
+
- **0-2 Trivial**: Simple, mechanical changes
|
|
79
|
+
- **3-4 Low**: Straightforward implementation
|
|
80
|
+
- **5-6 Medium**: Moderate complexity, some decisions
|
|
81
|
+
- **7-8 High**: Complex, multiple concerns
|
|
82
|
+
- **9-10 Very High**: Requires careful attention
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Notes
|
|
87
|
+
|
|
88
|
+
- `allowed-patterns.mdc` and `forbidden-patterns.mdc` have `alwaysApply: true` - they are loaded automatically by Cursor
|
|
89
|
+
- `complexity-scoring.mdc` is loaded on-demand when needed for planning
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Best practices and recommended patterns that should always be followed"
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Allowed Patterns
|
|
7
|
+
|
|
8
|
+
This file defines **best practices and recommended patterns** for your project. Add patterns that your team agrees upon and wants the AI to follow during code generation.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## How to Use This File
|
|
13
|
+
|
|
14
|
+
1. **Add patterns** that represent your team's coding standards
|
|
15
|
+
2. **Include examples** showing the correct way to implement each pattern
|
|
16
|
+
3. **Explain why** each pattern is beneficial
|
|
17
|
+
4. **Reference tools/rules** if applicable (ESLint, SonarQube, etc.)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Example Pattern Structure
|
|
22
|
+
|
|
23
|
+
### Pattern Name
|
|
24
|
+
|
|
25
|
+
Brief description of what this pattern accomplishes.
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// GOOD - Example of the correct approach
|
|
29
|
+
const example = doThingCorrectly()
|
|
30
|
+
|
|
31
|
+
// Optionally show the contrast
|
|
32
|
+
// BAD - What to avoid (but keep this minimal)
|
|
33
|
+
const badExample = doThingWrong()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Why**: Explain the benefit of following this pattern.
|
|
37
|
+
|
|
38
|
+
**Guidelines**:
|
|
39
|
+
|
|
40
|
+
- Specific guideline 1
|
|
41
|
+
- Specific guideline 2
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Example Patterns
|
|
46
|
+
|
|
47
|
+
### 1. Descriptive Naming
|
|
48
|
+
|
|
49
|
+
Use clear, descriptive names for functions, variables, and components.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// GOOD - Clear intent
|
|
53
|
+
function calculateOrderTotal(items: OrderItem[]): number
|
|
54
|
+
function fetchUserProfile(userId: string): Promise<User>
|
|
55
|
+
const isAuthenticated = checkAuthStatus()
|
|
56
|
+
|
|
57
|
+
// GOOD - Component names describe what they render
|
|
58
|
+
export const UserProfileCard = () => { ... }
|
|
59
|
+
export const OrderSummaryTable = () => { ... }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Why**: Improves code readability and makes the codebase self-documenting.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 2. Single Responsibility
|
|
67
|
+
|
|
68
|
+
Each function/component should do one thing well.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// GOOD - Focused function
|
|
72
|
+
function formatCurrency(amount: number): string {
|
|
73
|
+
return new Intl.NumberFormat('en-US', {
|
|
74
|
+
style: 'currency',
|
|
75
|
+
currency: 'USD',
|
|
76
|
+
}).format(amount)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// GOOD - Focused component
|
|
80
|
+
const PriceDisplay = ({ amount }: { amount: number }) => (
|
|
81
|
+
<span className="price">{formatCurrency(amount)}</span>
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Why**: Easier to test, maintain, and reuse.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### 3. Error Handling
|
|
90
|
+
|
|
91
|
+
Handle errors explicitly with meaningful messages.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// GOOD - Explicit error handling
|
|
95
|
+
async function fetchData(url: string) {
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch(url)
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
throw new ApiError(`Request failed: ${response.status}`)
|
|
100
|
+
}
|
|
101
|
+
return response.json()
|
|
102
|
+
} catch (error) {
|
|
103
|
+
logger.error('Failed to fetch data', { url, error })
|
|
104
|
+
throw error
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Why**: Makes debugging easier and provides better user feedback.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 4. Type Safety
|
|
114
|
+
|
|
115
|
+
Leverage TypeScript's type system to catch errors at compile time.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// GOOD - Explicit types for function signatures
|
|
119
|
+
interface User {
|
|
120
|
+
id: string
|
|
121
|
+
name: string
|
|
122
|
+
email: string
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function createUser(input: CreateUserInput): User {
|
|
126
|
+
// Implementation
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// GOOD - Use type inference where appropriate
|
|
130
|
+
const users = await fetchUsers() // Type inferred from function return
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Why**: Catches errors before runtime and improves IDE autocomplete.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### 5. Consistent Code Organization
|
|
138
|
+
|
|
139
|
+
Follow a consistent structure for files and folders.
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
src/
|
|
143
|
+
├── components/ # UI components
|
|
144
|
+
├── hooks/ # Custom React hooks
|
|
145
|
+
├── utils/ # Utility functions
|
|
146
|
+
├── types/ # TypeScript type definitions
|
|
147
|
+
├── services/ # API and external service integrations
|
|
148
|
+
└── stores/ # State management
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Why**: Makes the codebase navigable and predictable.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Adding Your Patterns
|
|
156
|
+
|
|
157
|
+
When adding new patterns to this file:
|
|
158
|
+
|
|
159
|
+
1. **Start with the pattern name** as a heading
|
|
160
|
+
2. **Provide code examples** showing the correct approach
|
|
161
|
+
3. **Explain the "Why"** - benefits of the pattern
|
|
162
|
+
4. **Add guidelines** for edge cases or nuances
|
|
163
|
+
5. **Reference external rules** if applicable (linting, etc.)
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Template for New Patterns
|
|
168
|
+
|
|
169
|
+
```markdown
|
|
170
|
+
### Pattern Name
|
|
171
|
+
|
|
172
|
+
Brief description of what this pattern accomplishes.
|
|
173
|
+
|
|
174
|
+
\`\`\`typescript
|
|
175
|
+
// GOOD - Example code
|
|
176
|
+
const example = correctApproach()
|
|
177
|
+
\`\`\`
|
|
178
|
+
|
|
179
|
+
**Why**: Explanation of benefits.
|
|
180
|
+
|
|
181
|
+
**Guidelines**:
|
|
182
|
+
|
|
183
|
+
- Guideline 1
|
|
184
|
+
- Guideline 2
|
|
185
|
+
```
|