ai-engineering-starter-kit 0.4.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/LICENSE.md +21 -0
- package/README.md +243 -0
- package/bin/ai-engineering-starter-kit.js +295 -0
- package/package.json +22 -0
- package/skills/ppp/SKILL.md +627 -0
- package/skills/ppp-cloud/SKILL.md +602 -0
- package/templates/AGENTS.md +100 -0
- package/templates/PULL_REQUEST_TEMPLATE.md +22 -0
- package/templates/copilot-instructions.md +19 -0
- package/templates/cursor-ppp-rule.mdc +20 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marcus Bransbury
|
|
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,243 @@
|
|
|
1
|
+
# AI Engineering Starter Kit
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bransbury/ai-engineering-starter-kit/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE.md)
|
|
5
|
+
[](https://github.com/bransbury/ai-engineering-starter-kit/releases)
|
|
6
|
+
|
|
7
|
+
AI coding agents are now part of everyday engineering work, but the process is often inconsistent. Engineers can prompt normally, yet the quality of the outcome still depends on whether the agent inspects the right code, asks only the necessary questions, plans a safe change, and proves it before PR.
|
|
8
|
+
|
|
9
|
+
**Plan. Patch. Prove.**
|
|
10
|
+
|
|
11
|
+
The practical AI coding loop: inspect first, change safely, verify before PR.
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
Inspect → Clarify → Plan → Prove → Patch → Review → PR
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
PPP is a simple, practical workflow for everyday tasks and tickets. It gives AI coding agents a fast, reliable, consistent, and token-efficient loop: inspect first, plan the smallest safe complete change, patch in small validated steps, and prove the result before handoff.
|
|
20
|
+
|
|
21
|
+
The starter kit includes:
|
|
22
|
+
|
|
23
|
+
- **Plan. Patch. Prove. (`/ppp`)** — an interactive workflow for engineers using an IDE agent
|
|
24
|
+
- **Plan. Patch. Prove. Cloud (`ppp-cloud`)** — a non-interactive workflow for autonomous cloud coding agents
|
|
25
|
+
- repo templates for agent guidance, Copilot instructions, PR templates, and Cursor rules
|
|
26
|
+
- practical docs and examples for adoption
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx ai-engineering-starter-kit install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
If slash commands are supported in your tool, run:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
/ppp <prompt>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## If `/ppp` does not work
|
|
41
|
+
|
|
42
|
+
`/ppp` works only where your agent tool loads skills as slash commands.
|
|
43
|
+
|
|
44
|
+
Fallback invocation:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
Use the Plan. Patch. Prove workflow on this prompt:
|
|
48
|
+
<paste prompt>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Not sure which setup to use? See [IDE setup](docs/ide-setup.md).
|
|
52
|
+
|
|
53
|
+
Prefer shell scripts instead of `npx`?
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
git clone https://github.com/bransbury/ai-engineering-starter-kit
|
|
57
|
+
cd ai-engineering-starter-kit
|
|
58
|
+
./install.sh
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## How PPP works
|
|
62
|
+
|
|
63
|
+
PPP stands for:
|
|
64
|
+
|
|
65
|
+
- **Plan** the smallest safe complete change.
|
|
66
|
+
- **Patch** the code in small, controlled steps.
|
|
67
|
+
- **Prove** it works before PR.
|
|
68
|
+
|
|
69
|
+
The actual workflow is deliberately proof-first:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
Inspect → Clarify → Plan → Prove → Patch → Review → PR
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Prove starts before Patch: the agent defines the proof first, then patches in small loops and runs the proof as it goes.
|
|
76
|
+
|
|
77
|
+
### IDE flow
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
Ticket
|
|
81
|
+
↓
|
|
82
|
+
/ppp
|
|
83
|
+
↓
|
|
84
|
+
Inspect → Clarify → Plan → Prove → Patch → Review → PR
|
|
85
|
+
↓
|
|
86
|
+
PR handoff
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Cloud flow
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
Issue
|
|
93
|
+
↓
|
|
94
|
+
ppp-cloud
|
|
95
|
+
↓
|
|
96
|
+
Draft PR or blocker
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Which setup should I use?
|
|
100
|
+
|
|
101
|
+
| I am... | Do this |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| Trying PPP personally | Run `npx ai-engineering-starter-kit install` |
|
|
104
|
+
| Rolling out to a repo | Copy `templates/AGENTS.md` and `templates/copilot-instructions.md` |
|
|
105
|
+
| Using Cursor | Copy `templates/cursor-ppp-rule.mdc` |
|
|
106
|
+
| Assigning cloud-agent tasks | Use `ppp-cloud` and repo instructions |
|
|
107
|
+
|
|
108
|
+
## What gets installed?
|
|
109
|
+
|
|
110
|
+
The installers copy the skills to both common personal skill locations:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
~/.agents/skills/ppp/SKILL.md
|
|
114
|
+
~/.agents/skills/ppp-cloud/SKILL.md
|
|
115
|
+
~/.copilot/skills/ppp/SKILL.md
|
|
116
|
+
~/.copilot/skills/ppp-cloud/SKILL.md
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If a `.cursor/` directory is detected in the current directory, it also installs the Cursor rule:
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
.cursor/rules/ppp.mdc
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Run `npx ai-engineering-starter-kit install` or `./install.sh` from each project where you want the Cursor rule active.
|
|
126
|
+
|
|
127
|
+
## Repo-local install
|
|
128
|
+
|
|
129
|
+
GitHub supports project skills in `.github/skills`, `.claude/skills`, or `.agents/skills`. If you want PPP to live with a specific repo instead of your personal environment, copy the skills into one of those project-local locations.
|
|
130
|
+
|
|
131
|
+
For GitHub project skills:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx ai-engineering-starter-kit install --repo-local
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
For most teams, the most reliable repo rollout is:
|
|
138
|
+
|
|
139
|
+
- repo-local skills for `/ppp` and `ppp-cloud`
|
|
140
|
+
- `AGENTS.md` at the repo root
|
|
141
|
+
- `.github/copilot-instructions.md` for VS Code + Copilot
|
|
142
|
+
- `.cursor/rules/ppp.mdc` for Cursor projects
|
|
143
|
+
|
|
144
|
+
## When to use `/ppp`
|
|
145
|
+
|
|
146
|
+
Use `/ppp` for normal engineering work that should fit in one focused PR:
|
|
147
|
+
|
|
148
|
+
- bug fixes
|
|
149
|
+
- small features
|
|
150
|
+
- tests
|
|
151
|
+
- UI tweaks
|
|
152
|
+
- small refactors
|
|
153
|
+
|
|
154
|
+
Good examples:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
/ppp Fix whitespace-only report names being accepted.
|
|
158
|
+
/ppp Add an empty state to the experiment results table when there are no rows.
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## When not to use `/ppp`
|
|
162
|
+
|
|
163
|
+
Do not use `/ppp` to implement a whole large feature in one go.
|
|
164
|
+
|
|
165
|
+
Examples that are too large:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
/ppp Build a new analytics dashboard.
|
|
169
|
+
/ppp Implement the new permissions system.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
For large work, ask `/ppp` to identify the smallest first task, or use a feature-slicing workflow.
|
|
173
|
+
|
|
174
|
+
## What good looks like
|
|
175
|
+
|
|
176
|
+
A good PPP run should:
|
|
177
|
+
|
|
178
|
+
- inspect relevant code before editing
|
|
179
|
+
- ask only important questions
|
|
180
|
+
- define how the change will be verified before editing
|
|
181
|
+
- add or update tests/checks where appropriate
|
|
182
|
+
- stop after two focused failed fix attempts
|
|
183
|
+
- review production readiness
|
|
184
|
+
- prepare a PR title/body using repo conventions
|
|
185
|
+
|
|
186
|
+
See a [full example run](examples/prompts/ppp-examples.md#what-good-output-looks-like).
|
|
187
|
+
|
|
188
|
+
## Cloud agent usage
|
|
189
|
+
|
|
190
|
+
| | `/ppp` | `ppp-cloud` |
|
|
191
|
+
| --- | --- | --- |
|
|
192
|
+
| **Who drives it** | Engineer in IDE | Autonomous cloud agent |
|
|
193
|
+
| **Interaction** | Interactive menus | Non-interactive, runs to completion |
|
|
194
|
+
| **Output** | Guided session → PR handoff | Draft PR or blocker report |
|
|
195
|
+
| **Best for** | Any normal ticket with a human in the loop | Clear, bounded tasks you can assign and review |
|
|
196
|
+
|
|
197
|
+
Use `ppp-cloud` for autonomous coding agents. It is designed for clear, bounded, verifiable tasks where the agent should either:
|
|
198
|
+
|
|
199
|
+
- create one focused draft PR; or
|
|
200
|
+
- stop with a clear blocker explaining why it could not proceed safely.
|
|
201
|
+
|
|
202
|
+
See [Cloud agent usage](docs/cloud-agent-usage.md).
|
|
203
|
+
|
|
204
|
+
## How is this different?
|
|
205
|
+
|
|
206
|
+
- Some skills are broad libraries of composable expert workflows.
|
|
207
|
+
- Some tools are opinionated operating systems for full-stack or product development.
|
|
208
|
+
- PPP is a narrow, practical workflow for everyday engineering tasks.
|
|
209
|
+
- It focuses on a simple loop: inspect first, plan the smallest safe change, prove it before patching broadly, and hand off a reviewable PR.
|
|
210
|
+
|
|
211
|
+
## Docs and templates
|
|
212
|
+
|
|
213
|
+
### Docs
|
|
214
|
+
|
|
215
|
+
- [How to use PPP](docs/how-to-use-ppp.md)
|
|
216
|
+
- [IDE setup](docs/ide-setup.md)
|
|
217
|
+
- [Cloud agent usage](docs/cloud-agent-usage.md)
|
|
218
|
+
- [Adoption rollout](docs/adoption-rollout.md)
|
|
219
|
+
- [Release automation spec](docs/release-automation-spec.md)
|
|
220
|
+
- [Troubleshooting](docs/troubleshooting.md)
|
|
221
|
+
|
|
222
|
+
### Templates
|
|
223
|
+
|
|
224
|
+
If you don't already have them, copy these into your repos to give AI agents consistent guidance:
|
|
225
|
+
|
|
226
|
+
| Template | Copy to | Purpose |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| `templates/AGENTS.md` | `AGENTS.md` (repo root) | Tells agents which workflow to use and what requires human approval |
|
|
229
|
+
| `templates/copilot-instructions.md` | `.github/copilot-instructions.md` | Repo-level Copilot instructions picked up automatically in VS Code |
|
|
230
|
+
| `templates/PULL_REQUEST_TEMPLATE.md` | `.github/PULL_REQUEST_TEMPLATE.md` | Consistent PR descriptions across human and AI-authored PRs |
|
|
231
|
+
| `templates/cursor-ppp-rule.mdc` | `.cursor/rules/ppp.mdc` | Cursor project rule — automatically installed by `npx ai-engineering-starter-kit install` or `./install.sh` if `.cursor/` exists |
|
|
232
|
+
|
|
233
|
+
Each template is intentionally minimal. Add repo-specific conventions (architecture rules, test commands, forbidden areas) directly in `AGENTS.md` and `copilot-instructions.md`.
|
|
234
|
+
|
|
235
|
+
## Security note
|
|
236
|
+
|
|
237
|
+
Skills are operational instructions that can influence AI agent behaviour. Review changes to `SKILL.md` files carefully.
|
|
238
|
+
|
|
239
|
+
Do not add secrets, credentials, internal-only URLs, or sensitive customer data to skills or examples.
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
[MIT](LICENSE.md) © 2026 Marcus Bransbury
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const readline = require("readline");
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(__dirname, "..");
|
|
9
|
+
const home = os.homedir();
|
|
10
|
+
const skills = ["ppp", "ppp-cloud"];
|
|
11
|
+
const personalTargets = [
|
|
12
|
+
path.join(home, ".agents", "skills"),
|
|
13
|
+
path.join(home, ".copilot", "skills"),
|
|
14
|
+
];
|
|
15
|
+
const repoLocalTargets = [path.join(process.cwd(), ".github", "skills")];
|
|
16
|
+
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
const positional = [];
|
|
19
|
+
const flags = new Set();
|
|
20
|
+
|
|
21
|
+
for (const arg of argv) {
|
|
22
|
+
if (arg.startsWith("-")) {
|
|
23
|
+
flags.add(arg);
|
|
24
|
+
} else {
|
|
25
|
+
positional.push(arg);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
command: positional[0] || null,
|
|
31
|
+
dryRun: flags.has("--dry-run"),
|
|
32
|
+
force: flags.has("--force"),
|
|
33
|
+
yes: flags.has("--yes") || flags.has("-y"),
|
|
34
|
+
repoLocal: flags.has("--repo-local"),
|
|
35
|
+
help: flags.has("--help") || flags.has("-h"),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function usage() {
|
|
40
|
+
console.log(`AI Engineering Starter Kit
|
|
41
|
+
|
|
42
|
+
Usage:
|
|
43
|
+
ai-engineering-starter-kit install [--yes] [--dry-run] [--force] [--repo-local]
|
|
44
|
+
ai-engineering-starter-kit uninstall [--yes] [--dry-run] [--repo-local]
|
|
45
|
+
ai-engineering-starter-kit help
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
npx ai-engineering-starter-kit install --yes
|
|
49
|
+
npx ai-engineering-starter-kit install --dry-run
|
|
50
|
+
npx ai-engineering-starter-kit install --repo-local
|
|
51
|
+
`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function log(message = "") {
|
|
55
|
+
console.log(message);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function skillVersion(skillName) {
|
|
59
|
+
const src = path.join(root, "skills", skillName, "SKILL.md");
|
|
60
|
+
const content = fs.readFileSync(src, "utf8");
|
|
61
|
+
const match = content.match(/^version:\s*(.+)$/m);
|
|
62
|
+
return match ? match[1].trim() : "unknown";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function timestamp() {
|
|
66
|
+
const now = new Date();
|
|
67
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
68
|
+
return [
|
|
69
|
+
now.getFullYear(),
|
|
70
|
+
pad(now.getMonth() + 1),
|
|
71
|
+
pad(now.getDate()),
|
|
72
|
+
pad(now.getHours()),
|
|
73
|
+
pad(now.getMinutes()),
|
|
74
|
+
pad(now.getSeconds()),
|
|
75
|
+
].join("");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function actionWord(dryRun, verb) {
|
|
79
|
+
return dryRun ? `Would ${verb}` : verb[0].toUpperCase() + verb.slice(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function runMkdir(destDir, dryRun) {
|
|
83
|
+
if (dryRun) {
|
|
84
|
+
log(`[dry-run] mkdir -p ${destDir}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function runCopy(src, dest, dryRun) {
|
|
91
|
+
if (dryRun) {
|
|
92
|
+
log(`[dry-run] copy ${src} -> ${dest}`);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
fs.copyFileSync(src, dest);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function runRemove(target, dryRun) {
|
|
99
|
+
if (dryRun) {
|
|
100
|
+
log(`[dry-run] remove ${target}`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function backupFile(filePath, dryRun) {
|
|
107
|
+
const backupPath = `${filePath}.bak.${timestamp()}`;
|
|
108
|
+
runCopy(filePath, backupPath, dryRun);
|
|
109
|
+
log(`${actionWord(dryRun, "back up existing file")} to ${backupPath}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function confirmOverwrite(targetFile) {
|
|
113
|
+
const rl = readline.createInterface({
|
|
114
|
+
input: process.stdin,
|
|
115
|
+
output: process.stderr,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const reply = await new Promise((resolve) => {
|
|
119
|
+
rl.question(`Overwrite ${targetFile}? [y/N] `, resolve);
|
|
120
|
+
});
|
|
121
|
+
rl.close();
|
|
122
|
+
|
|
123
|
+
return /^(y|yes)$/i.test(reply.trim());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function shouldOverwrite(targetFile, options) {
|
|
127
|
+
if (!fs.existsSync(targetFile)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (options.force) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (options.yes || !process.stdin.isTTY) {
|
|
136
|
+
log(`Exists at ${targetFile} - skipping (use --force to overwrite)`);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const confirmed = await confirmOverwrite(targetFile);
|
|
141
|
+
if (!confirmed) {
|
|
142
|
+
log(`Skipping ${targetFile}`);
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function installSkill(skillName, targetRoot, options) {
|
|
149
|
+
const src = path.join(root, "skills", skillName, "SKILL.md");
|
|
150
|
+
const destDir = path.join(targetRoot, skillName);
|
|
151
|
+
const destFile = path.join(destDir, "SKILL.md");
|
|
152
|
+
|
|
153
|
+
if (!fs.existsSync(src)) {
|
|
154
|
+
throw new Error(`Missing skill source: ${src}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
runMkdir(destDir, options.dryRun);
|
|
158
|
+
|
|
159
|
+
if (!(await shouldOverwrite(destFile, options))) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (fs.existsSync(destFile)) {
|
|
164
|
+
backupFile(destFile, options.dryRun);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
runCopy(src, destFile, options.dryRun);
|
|
168
|
+
log(`${actionWord(options.dryRun, "install")} ${skillName} ${skillVersion(skillName)} to ${destFile}`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async function installCursorRule(options) {
|
|
172
|
+
const src = path.join(root, "templates", "cursor-ppp-rule.mdc");
|
|
173
|
+
const destDir = path.join(process.cwd(), ".cursor", "rules");
|
|
174
|
+
const destFile = path.join(destDir, "ppp.mdc");
|
|
175
|
+
|
|
176
|
+
if (!fs.existsSync(src)) {
|
|
177
|
+
throw new Error(`Missing Cursor rule template: ${src}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (!fs.existsSync(path.join(process.cwd(), ".cursor"))) {
|
|
181
|
+
log("Cursor not detected in current directory - skipping Cursor rule install.");
|
|
182
|
+
log("To install manually: copy templates/cursor-ppp-rule.mdc to .cursor/rules/ppp.mdc");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
runMkdir(destDir, options.dryRun);
|
|
187
|
+
|
|
188
|
+
if (!(await shouldOverwrite(destFile, options))) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (fs.existsSync(destFile)) {
|
|
193
|
+
backupFile(destFile, options.dryRun);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
runCopy(src, destFile, options.dryRun);
|
|
197
|
+
log(`${actionWord(options.dryRun, "install")} Cursor rule to ${destFile}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function install(options) {
|
|
201
|
+
const targetRoots = options.repoLocal ? repoLocalTargets : personalTargets;
|
|
202
|
+
|
|
203
|
+
log("PPP installer");
|
|
204
|
+
log(`Version: ${skillVersion("ppp")}`);
|
|
205
|
+
if (options.repoLocal) {
|
|
206
|
+
log("Mode: repo-local");
|
|
207
|
+
}
|
|
208
|
+
if (options.dryRun) {
|
|
209
|
+
log("Mode: dry-run");
|
|
210
|
+
}
|
|
211
|
+
if (options.force) {
|
|
212
|
+
log("Overwrite mode: force");
|
|
213
|
+
}
|
|
214
|
+
log();
|
|
215
|
+
|
|
216
|
+
for (const skill of skills) {
|
|
217
|
+
for (const targetRoot of targetRoots) {
|
|
218
|
+
await installSkill(skill, targetRoot, options);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
log();
|
|
223
|
+
if (!options.repoLocal) {
|
|
224
|
+
await installCursorRule(options);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
log();
|
|
228
|
+
log("Done.");
|
|
229
|
+
log("Important: /ppp works only where your tool loads skills as slash commands.");
|
|
230
|
+
log("Fallback: Use the Plan. Patch. Prove workflow on this prompt:");
|
|
231
|
+
log("<paste prompt>");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function removeSkillDirs(targetRoots, options) {
|
|
235
|
+
for (const skill of skills) {
|
|
236
|
+
for (const targetRoot of targetRoots) {
|
|
237
|
+
const targetDir = path.join(targetRoot, skill);
|
|
238
|
+
if (fs.existsSync(targetDir)) {
|
|
239
|
+
runRemove(targetDir, options.dryRun);
|
|
240
|
+
log(`${actionWord(options.dryRun, "remove")} ${targetDir}`);
|
|
241
|
+
} else {
|
|
242
|
+
log(`Not found, skipping: ${targetDir}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function removeCursorRule(options) {
|
|
249
|
+
const cursorRule = path.join(process.cwd(), ".cursor", "rules", "ppp.mdc");
|
|
250
|
+
if (fs.existsSync(cursorRule)) {
|
|
251
|
+
runRemove(cursorRule, options.dryRun);
|
|
252
|
+
log(`${actionWord(options.dryRun, "remove")} ${cursorRule}`);
|
|
253
|
+
} else {
|
|
254
|
+
log(`Not found, skipping: ${cursorRule}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function uninstall(options) {
|
|
259
|
+
const targetRoots = options.repoLocal ? repoLocalTargets : personalTargets;
|
|
260
|
+
|
|
261
|
+
removeSkillDirs(targetRoots, options);
|
|
262
|
+
if (!options.repoLocal) {
|
|
263
|
+
removeCursorRule(options);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
log("Done.");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function main() {
|
|
270
|
+
const options = parseArgs(process.argv.slice(2));
|
|
271
|
+
|
|
272
|
+
if (!options.command || options.help || options.command === "help") {
|
|
273
|
+
usage();
|
|
274
|
+
process.exit(0);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (options.command === "install") {
|
|
278
|
+
await install(options);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (options.command === "uninstall") {
|
|
283
|
+
uninstall(options);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
console.error(`Unknown command: ${options.command}`);
|
|
288
|
+
usage();
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
main().catch((error) => {
|
|
293
|
+
console.error(error.message);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ai-engineering-starter-kit",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Plan. Patch. Prove. Practical AI-assisted engineering workflows for IDE and cloud coding agents.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ai-engineering-starter-kit": "bin/ai-engineering-starter-kit.js",
|
|
10
|
+
"aesk": "bin/ai-engineering-starter-kit.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin",
|
|
14
|
+
"skills",
|
|
15
|
+
"templates",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE.md"
|
|
18
|
+
],
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
}
|
|
22
|
+
}
|