opencodekit 0.18.5 → 0.18.6
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/dist/index.js +107 -53
- package/dist/template/.opencode/agent/explore.md +25 -28
- package/dist/template/.opencode/command/ship.md +7 -5
- package/dist/template/.opencode/memory.db +0 -0
- package/dist/template/.opencode/memory.db-shm +0 -0
- package/dist/template/.opencode/memory.db-wal +0 -0
- package/dist/template/.opencode/skill/executing-plans/SKILL.md +155 -138
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { cac } from "cac";
|
|
4
4
|
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { basename, dirname, join, relative
|
|
5
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
6
6
|
import * as p from "@clack/prompts";
|
|
7
7
|
import color from "picocolors";
|
|
8
8
|
import { z } from "zod";
|
|
@@ -18,11 +18,35 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
18
18
|
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region package.json
|
|
21
|
-
var version = "0.18.
|
|
21
|
+
var version = "0.18.6";
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region src/utils/errors.ts
|
|
25
25
|
/**
|
|
26
|
+
* Resolve the .opencode directory path.
|
|
27
|
+
* Handles two cases:
|
|
28
|
+
* 1. Standard project: cwd has .opencode/ subdirectory
|
|
29
|
+
* 2. Global config dir: cwd IS the opencode config dir (has opencode.json directly)
|
|
30
|
+
* Returns null if neither case applies.
|
|
31
|
+
*/
|
|
32
|
+
function resolveOpencodePath() {
|
|
33
|
+
const nested = join(process.cwd(), ".opencode");
|
|
34
|
+
if (existsSync(nested)) return nested;
|
|
35
|
+
if (existsSync(join(process.cwd(), "opencode.json"))) return process.cwd();
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve opencode path or show "not initialized" error and return null.
|
|
40
|
+
*/
|
|
41
|
+
function requireOpencodePath() {
|
|
42
|
+
const resolved = resolveOpencodePath();
|
|
43
|
+
if (!resolved) {
|
|
44
|
+
notInitialized();
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return resolved;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
26
50
|
* Display a styled error message with optional fix suggestion
|
|
27
51
|
*/
|
|
28
52
|
function showError(message, fix) {
|
|
@@ -79,7 +103,8 @@ const InitOptionsSchema = z.object({
|
|
|
79
103
|
yes: z.boolean().optional().default(false),
|
|
80
104
|
backup: z.boolean().optional().default(false),
|
|
81
105
|
prune: z.boolean().optional().default(false),
|
|
82
|
-
pruneAll: z.boolean().optional().default(false)
|
|
106
|
+
pruneAll: z.boolean().optional().default(false),
|
|
107
|
+
projectOnly: z.boolean().optional().default(false)
|
|
83
108
|
});
|
|
84
109
|
const UpgradeOptionsSchema = z.object({
|
|
85
110
|
force: z.boolean().optional().default(false),
|
|
@@ -192,11 +217,8 @@ function parseAction(schema, action) {
|
|
|
192
217
|
//#region src/commands/agent.ts
|
|
193
218
|
async function agentCommand(action) {
|
|
194
219
|
const validatedAction = parseAction(AgentActionSchema, action);
|
|
195
|
-
const opencodePath =
|
|
196
|
-
if (!
|
|
197
|
-
notInitialized();
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
220
|
+
const opencodePath = requireOpencodePath();
|
|
221
|
+
if (!opencodePath) return;
|
|
200
222
|
const agentPath = join(opencodePath, "agent");
|
|
201
223
|
switch (validatedAction) {
|
|
202
224
|
case "list":
|
|
@@ -473,11 +495,8 @@ async function removeAgent(agentPath, agentNameArg) {
|
|
|
473
495
|
//#region src/commands/command.ts
|
|
474
496
|
async function commandCommand(action) {
|
|
475
497
|
const validatedAction = parseAction(CommandActionSchema, action);
|
|
476
|
-
const opencodePath =
|
|
477
|
-
if (!
|
|
478
|
-
notInitialized();
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
498
|
+
const opencodePath = requireOpencodePath();
|
|
499
|
+
if (!opencodePath) return;
|
|
481
500
|
const commandDir = join(opencodePath, "command");
|
|
482
501
|
switch (validatedAction) {
|
|
483
502
|
case "list":
|
|
@@ -982,12 +1001,9 @@ async function getAgentsFromServer() {
|
|
|
982
1001
|
return fetchFromServer("/agent");
|
|
983
1002
|
}
|
|
984
1003
|
async function configCommand(action) {
|
|
985
|
-
const opencodePath =
|
|
1004
|
+
const opencodePath = requireOpencodePath();
|
|
1005
|
+
if (!opencodePath) return;
|
|
986
1006
|
const configPath = join(opencodePath, "opencode.json");
|
|
987
|
-
if (!existsSync(opencodePath)) {
|
|
988
|
-
notInitialized();
|
|
989
|
-
return;
|
|
990
|
-
}
|
|
991
1007
|
if (!existsSync(configPath)) {
|
|
992
1008
|
showError("opencode.json not found", "ock init --force");
|
|
993
1009
|
return;
|
|
@@ -2758,6 +2774,34 @@ const EXCLUDED_FILES = [
|
|
|
2758
2774
|
"pnpm-lock.yaml"
|
|
2759
2775
|
];
|
|
2760
2776
|
const PRESERVE_USER_DIRS = ["memory/project", "context"];
|
|
2777
|
+
const SHARED_CONFIG_DIRS = [
|
|
2778
|
+
"agent",
|
|
2779
|
+
"command",
|
|
2780
|
+
"skill",
|
|
2781
|
+
"tool"
|
|
2782
|
+
];
|
|
2783
|
+
/**
|
|
2784
|
+
* Detect if global config has any of the shared dirs populated.
|
|
2785
|
+
* Returns null if no global config or no shared dirs found.
|
|
2786
|
+
*/
|
|
2787
|
+
function detectGlobalConfig() {
|
|
2788
|
+
const globalDir = getGlobalConfigDir();
|
|
2789
|
+
if (!existsSync(globalDir)) return null;
|
|
2790
|
+
const coveredDirs = SHARED_CONFIG_DIRS.filter((d) => {
|
|
2791
|
+
const dirPath = join(globalDir, d);
|
|
2792
|
+
if (!existsSync(dirPath)) return false;
|
|
2793
|
+
try {
|
|
2794
|
+
return readdirSync(dirPath).filter((e) => !e.startsWith(".")).length > 0;
|
|
2795
|
+
} catch {
|
|
2796
|
+
return false;
|
|
2797
|
+
}
|
|
2798
|
+
});
|
|
2799
|
+
if (coveredDirs.length === 0) return null;
|
|
2800
|
+
return {
|
|
2801
|
+
dir: globalDir,
|
|
2802
|
+
coveredDirs
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2761
2805
|
/**
|
|
2762
2806
|
* Get the global OpenCode config directory based on OS.
|
|
2763
2807
|
* - macOS/Linux: ~/.config/opencode/ (respects XDG_CONFIG_HOME)
|
|
@@ -2801,10 +2845,25 @@ async function copyDir(src, dest) {
|
|
|
2801
2845
|
else writeFileSync(destPath, readFileSync(srcPath, "utf-8"));
|
|
2802
2846
|
}
|
|
2803
2847
|
}
|
|
2804
|
-
async function copyOpenCodeOnly(templateRoot, targetDir) {
|
|
2848
|
+
async function copyOpenCodeOnly(templateRoot, targetDir, skipDirs) {
|
|
2805
2849
|
const opencodeSrc = join(templateRoot, ".opencode");
|
|
2806
2850
|
const opencodeDest = join(targetDir, ".opencode");
|
|
2807
2851
|
if (!existsSync(opencodeSrc)) return false;
|
|
2852
|
+
if (skipDirs && skipDirs.length > 0) {
|
|
2853
|
+
const skipSet = new Set(skipDirs);
|
|
2854
|
+
mkdirSync(opencodeDest, { recursive: true });
|
|
2855
|
+
for (const entry of readdirSync(opencodeSrc, { withFileTypes: true })) {
|
|
2856
|
+
if (EXCLUDED_DIRS.includes(entry.name)) continue;
|
|
2857
|
+
if (!entry.isDirectory() && EXCLUDED_FILES.includes(entry.name)) continue;
|
|
2858
|
+
if (entry.isSymbolicLink()) continue;
|
|
2859
|
+
if (entry.isDirectory() && skipSet.has(entry.name)) continue;
|
|
2860
|
+
const srcPath = join(opencodeSrc, entry.name);
|
|
2861
|
+
const destPath = join(opencodeDest, entry.name);
|
|
2862
|
+
if (entry.isDirectory()) await copyDir(srcPath, destPath);
|
|
2863
|
+
else writeFileSync(destPath, readFileSync(srcPath, "utf-8"));
|
|
2864
|
+
}
|
|
2865
|
+
return true;
|
|
2866
|
+
}
|
|
2808
2867
|
await copyDir(opencodeSrc, opencodeDest);
|
|
2809
2868
|
return true;
|
|
2810
2869
|
}
|
|
@@ -3100,18 +3159,36 @@ async function initCommand(rawOptions = {}) {
|
|
|
3100
3159
|
}
|
|
3101
3160
|
projectName = name || projectName;
|
|
3102
3161
|
}
|
|
3162
|
+
let skipDirs = [];
|
|
3163
|
+
if (!options.global) {
|
|
3164
|
+
const globalConfig = detectGlobalConfig();
|
|
3165
|
+
if (globalConfig && options.projectOnly) {
|
|
3166
|
+
skipDirs = globalConfig.coveredDirs;
|
|
3167
|
+
p.log.info(`Using global config from ${color.cyan(globalConfig.dir)}`);
|
|
3168
|
+
p.log.info(`Skipping: ${skipDirs.map((d) => color.dim(d)).join(", ")}`);
|
|
3169
|
+
} else if (globalConfig && !options.yes) {
|
|
3170
|
+
p.log.info(`Global config found at ${color.cyan(globalConfig.dir)}`);
|
|
3171
|
+
p.log.info(`Available globally: ${globalConfig.coveredDirs.map((d) => color.green(d)).join(", ")}`);
|
|
3172
|
+
const useGlobal = await p.confirm({
|
|
3173
|
+
message: "Skip these (use global config)? Only project-scope files will be created locally.",
|
|
3174
|
+
initialValue: true
|
|
3175
|
+
});
|
|
3176
|
+
if (!p.isCancel(useGlobal) && useGlobal) skipDirs = globalConfig.coveredDirs;
|
|
3177
|
+
} else if (globalConfig && options.yes) p.log.info(`Global config found at ${color.cyan(globalConfig.dir)} — use ${color.bold("--project-only")} to skip shared dirs`);
|
|
3178
|
+
}
|
|
3103
3179
|
const s = p.spinner();
|
|
3104
3180
|
if (mode === "scaffold") {
|
|
3105
3181
|
s.start("Scaffolding project");
|
|
3106
3182
|
mkdirSync(targetDir, { recursive: true });
|
|
3107
3183
|
} else if (mode === "add-config") s.start("Adding OpenCodeKit");
|
|
3108
3184
|
else s.start("Reinitializing");
|
|
3109
|
-
if (!await copyOpenCodeOnly(templateRoot, targetDir)) {
|
|
3185
|
+
if (!await copyOpenCodeOnly(templateRoot, targetDir, skipDirs)) {
|
|
3110
3186
|
s.stop("Failed");
|
|
3111
3187
|
p.outro(color.red("Template copy failed"));
|
|
3112
3188
|
process.exit(1);
|
|
3113
3189
|
}
|
|
3114
3190
|
s.stop("Done");
|
|
3191
|
+
if (skipDirs.length > 0) p.log.info(`Project-only init: skipped ${skipDirs.map((d) => color.dim(d)).join(", ")} (using global config)`);
|
|
3115
3192
|
const restoredFileCount = finalizeInstalledFiles(targetDir, getPackageVersion$1(), preservedFiles);
|
|
3116
3193
|
if (restoredFileCount > 0) p.log.info(`Preserved ${restoredFileCount} user memory files (memory/project/)`);
|
|
3117
3194
|
if (options.free) {
|
|
@@ -3280,11 +3357,8 @@ async function initCommand(rawOptions = {}) {
|
|
|
3280
3357
|
//#region src/commands/skill.ts
|
|
3281
3358
|
async function skillCommand(action) {
|
|
3282
3359
|
const validatedAction = parseAction(SkillActionSchema, action);
|
|
3283
|
-
const opencodePath =
|
|
3284
|
-
if (!
|
|
3285
|
-
notInitialized();
|
|
3286
|
-
return;
|
|
3287
|
-
}
|
|
3360
|
+
const opencodePath = requireOpencodePath();
|
|
3361
|
+
if (!opencodePath) return;
|
|
3288
3362
|
const skillDir = join(opencodePath, "skill");
|
|
3289
3363
|
switch (validatedAction) {
|
|
3290
3364
|
case "list":
|
|
@@ -3684,12 +3758,9 @@ function findUpgradeOrphans(installedFiles, templateFiles) {
|
|
|
3684
3758
|
async function upgradeCommand(rawOptions = {}) {
|
|
3685
3759
|
const options = parseOptions(UpgradeOptionsSchema, rawOptions);
|
|
3686
3760
|
if (process.argv.includes("--quiet")) return;
|
|
3687
|
-
const opencodeDir =
|
|
3761
|
+
const opencodeDir = requireOpencodePath();
|
|
3762
|
+
if (!opencodeDir) return;
|
|
3688
3763
|
const manifest = loadManifest(opencodeDir);
|
|
3689
|
-
if (!existsSync(opencodeDir)) {
|
|
3690
|
-
notInitialized();
|
|
3691
|
-
return;
|
|
3692
|
-
}
|
|
3693
3764
|
p.intro(color.bgCyan(color.black(" Upgrade ")));
|
|
3694
3765
|
const versionInfo = await checkVersion(opencodeDir);
|
|
3695
3766
|
console.log();
|
|
@@ -4120,11 +4191,8 @@ function displayChecks(checks) {
|
|
|
4120
4191
|
async function statusCommand() {
|
|
4121
4192
|
if (process.argv.includes("--quiet")) return;
|
|
4122
4193
|
const cwd = process.cwd();
|
|
4123
|
-
const opencodeDir =
|
|
4124
|
-
if (!
|
|
4125
|
-
notInitialized();
|
|
4126
|
-
return;
|
|
4127
|
-
}
|
|
4194
|
+
const opencodeDir = requireOpencodePath();
|
|
4195
|
+
if (!opencodeDir) return;
|
|
4128
4196
|
const projectName = basename(cwd);
|
|
4129
4197
|
p.intro(color.bgCyan(color.black(` ${projectName} `)));
|
|
4130
4198
|
const agentDir = join(opencodeDir, "agent");
|
|
@@ -4163,14 +4231,6 @@ async function statusCommand() {
|
|
|
4163
4231
|
|
|
4164
4232
|
//#endregion
|
|
4165
4233
|
//#region src/commands/patch.ts
|
|
4166
|
-
function getOpencodeDir() {
|
|
4167
|
-
const opencodeDir = join(resolve("."), ".opencode");
|
|
4168
|
-
if (!existsSync(opencodeDir)) {
|
|
4169
|
-
notInitialized();
|
|
4170
|
-
return null;
|
|
4171
|
-
}
|
|
4172
|
-
return opencodeDir;
|
|
4173
|
-
}
|
|
4174
4234
|
function listPatches(opencodeDir) {
|
|
4175
4235
|
const metadata = loadPatchMetadata(opencodeDir);
|
|
4176
4236
|
const entries = Object.entries(metadata.patches);
|
|
@@ -4399,7 +4459,7 @@ function togglePatch(opencodeDir, disable) {
|
|
|
4399
4459
|
}
|
|
4400
4460
|
}
|
|
4401
4461
|
async function patchCommand(action) {
|
|
4402
|
-
const opencodeDir =
|
|
4462
|
+
const opencodeDir = requireOpencodePath();
|
|
4403
4463
|
if (!opencodeDir) return;
|
|
4404
4464
|
const validatedAction = parseAction(PatchActionSchema, action);
|
|
4405
4465
|
if (!validatedAction) {
|
|
@@ -5416,7 +5476,7 @@ function stripAnsi(str) {
|
|
|
5416
5476
|
//#region src/tui/hooks/useData.ts
|
|
5417
5477
|
function loadProjectData() {
|
|
5418
5478
|
const cwd = process.cwd();
|
|
5419
|
-
const opencodeDir = join(cwd, ".opencode");
|
|
5479
|
+
const opencodeDir = resolveOpencodePath() ?? join(cwd, ".opencode");
|
|
5420
5480
|
const projectName = basename(cwd);
|
|
5421
5481
|
const agentDir = join(opencodeDir, "agent");
|
|
5422
5482
|
let agents = [];
|
|
@@ -5445,9 +5505,6 @@ function loadProjectData() {
|
|
|
5445
5505
|
mcpServers
|
|
5446
5506
|
};
|
|
5447
5507
|
}
|
|
5448
|
-
function isInitialized() {
|
|
5449
|
-
return existsSync(join(process.cwd(), ".opencode"));
|
|
5450
|
-
}
|
|
5451
5508
|
|
|
5452
5509
|
//#endregion
|
|
5453
5510
|
//#region src/tui/index.ts
|
|
@@ -5455,10 +5512,7 @@ function isInitialized() {
|
|
|
5455
5512
|
* Launch the TUI dashboard with interactive navigation.
|
|
5456
5513
|
*/
|
|
5457
5514
|
async function launchTUI() {
|
|
5458
|
-
if (!
|
|
5459
|
-
notInitialized();
|
|
5460
|
-
return;
|
|
5461
|
-
}
|
|
5515
|
+
if (!requireOpencodePath()) return;
|
|
5462
5516
|
await mainMenu();
|
|
5463
5517
|
}
|
|
5464
5518
|
async function mainMenu() {
|
|
@@ -5561,7 +5615,7 @@ const cli = cac("ock");
|
|
|
5561
5615
|
cli.option("--verbose", "Enable verbose logging");
|
|
5562
5616
|
cli.option("--quiet", "Suppress all output");
|
|
5563
5617
|
cli.version(`${packageVersion}`);
|
|
5564
|
-
cli.command("init", "Initialize OpenCodeKit in current directory").option("--force", "Reinitialize even if already exists").option("--beads", "Also initialize .beads/ for multi-agent coordination").option("--global", "Install to global OpenCode config (~/.config/opencode/)").option("--free", "Use free models (default)").option("--recommend", "Use recommended premium models").option("-y, --yes", "Skip prompts, use defaults (for CI)").option("--backup", "Backup existing .opencode before overwriting").option("--prune", "Manually select orphan files to delete").option("--prune-all", "Auto-delete all orphan files").action(initCommand);
|
|
5618
|
+
cli.command("init", "Initialize OpenCodeKit in current directory").option("--force", "Reinitialize even if already exists").option("--beads", "Also initialize .beads/ for multi-agent coordination").option("--global", "Install to global OpenCode config (~/.config/opencode/)").option("--free", "Use free models (default)").option("--recommend", "Use recommended premium models").option("-y, --yes", "Skip prompts, use defaults (for CI)").option("--backup", "Backup existing .opencode before overwriting").option("--prune", "Manually select orphan files to delete").option("--prune-all", "Auto-delete all orphan files").option("--project-only", "Only init project-scope files (skip if global config has agents/skills/commands/tools)").action(initCommand);
|
|
5565
5619
|
cli.command("agent [action]", "Manage agents (list, add, view)").action(async (action) => {
|
|
5566
5620
|
if (!action) {
|
|
5567
5621
|
console.log("\nUsage: ock agent <action>\n");
|
|
@@ -11,6 +11,9 @@ tools:
|
|
|
11
11
|
memory-update: false
|
|
12
12
|
observation: false
|
|
13
13
|
question: false
|
|
14
|
+
websearch: false
|
|
15
|
+
webfetch: false
|
|
16
|
+
codesearch: false
|
|
14
17
|
---
|
|
15
18
|
|
|
16
19
|
You are OpenCode, the best coding agent on the planet.
|
|
@@ -19,8 +22,6 @@ You are OpenCode, the best coding agent on the planet.
|
|
|
19
22
|
|
|
20
23
|
**Purpose**: Read-only codebase cartographer — you map terrain, you don't build on it.
|
|
21
24
|
|
|
22
|
-
> _"Agency is knowing where the levers are before you pull them."_
|
|
23
|
-
|
|
24
25
|
## Identity
|
|
25
26
|
|
|
26
27
|
You are a read-only codebase explorer. You output concise, evidence-backed findings with absolute paths only.
|
|
@@ -29,45 +30,41 @@ You are a read-only codebase explorer. You output concise, evidence-backed findi
|
|
|
29
30
|
|
|
30
31
|
Find relevant files, symbols, and usage paths quickly for the caller.
|
|
31
32
|
|
|
32
|
-
##
|
|
33
|
+
## Tools — Use These for Local Code Search
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
| Tool | Use For | Example |
|
|
36
|
+
|------|---------|--------|
|
|
37
|
+
| `grep` | Find text/regex patterns in files | `grep(pattern: "PatchEntry", include: "*.ts")` |
|
|
38
|
+
| `glob` | Find files by name/pattern | `glob(pattern: "src/**/*.ts")` |
|
|
39
|
+
| `lsp` (goToDefinition) | Jump to symbol definition | `lsp(operation: "goToDefinition", filePath: "...", line: N, character: N)` |
|
|
40
|
+
| `lsp` (findReferences) | Find all usages of a symbol | `lsp(operation: "findReferences", ...)` |
|
|
41
|
+
| `lsp` (hover) | Get type info and docs | `lsp(operation: "hover", ...)` |
|
|
42
|
+
| `read` | Read file content | `read(filePath: "src/utils/patch.ts")` |
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
skill({ name: "code-navigation" });
|
|
38
|
-
```
|
|
44
|
+
**NEVER** use `websearch`, `webfetch`, or `codesearch` — those search the internet, not your project.
|
|
39
45
|
|
|
40
46
|
## Rules
|
|
41
47
|
|
|
42
48
|
- Never modify files — read-only is a hard constraint
|
|
43
49
|
- Return absolute paths in final output
|
|
44
50
|
- Cite `file:line` evidence whenever possible
|
|
45
|
-
-
|
|
46
|
-
-
|
|
51
|
+
- **Always start with `grep` or `glob`** to locate files and symbols — do NOT read directories to browse
|
|
52
|
+
- Use LSP for precise navigation after finding candidate locations
|
|
53
|
+
- Stop when you can answer with concrete evidence
|
|
47
54
|
|
|
48
|
-
##
|
|
55
|
+
## Navigation Patterns
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- **Cite evidence**: Every finding needs file:line reference
|
|
57
|
+
1. **Search first, read second**: `grep` to find where a symbol lives, then `read` only that section
|
|
58
|
+
2. **Don't re-read**: If you already read a file, reference what you learned — don't read it again
|
|
59
|
+
3. **Follow the chain**: definition → usages → callers via LSP findReferences
|
|
60
|
+
4. **Target ≤3 tool calls per symbol**: grep → read section → done
|
|
55
61
|
|
|
56
62
|
## Workflow
|
|
57
63
|
|
|
58
|
-
1.
|
|
59
|
-
2.
|
|
60
|
-
3.
|
|
61
|
-
4.
|
|
62
|
-
5. Return findings + next steps
|
|
63
|
-
|
|
64
|
-
## Thoroughness Levels
|
|
65
|
-
|
|
66
|
-
| Level | Scope | Use When |
|
|
67
|
-
| --------------- | ----------------------------- | ------------------------------------------ |
|
|
68
|
-
| `quick` | 1-3 files, direct answer | Simple lookups, known symbol names |
|
|
69
|
-
| `medium` | 3-6 files, include call paths | Understanding feature flow |
|
|
70
|
-
| `very thorough` | Dependency map + edge cases | Complex refactor prep, architecture review |
|
|
64
|
+
1. `grep` or `glob` to discover candidate files
|
|
65
|
+
2. `lsp` goToDefinition/findReferences for precise symbol navigation
|
|
66
|
+
3. `read` only the relevant sections (use offset/limit)
|
|
67
|
+
4. Return findings with file:line evidence
|
|
71
68
|
|
|
72
69
|
## Output
|
|
73
70
|
|
|
@@ -75,13 +75,15 @@ ls .beads/artifacts/$ARGUMENTS/
|
|
|
75
75
|
|
|
76
76
|
If `plan.md` exists with dependency graph:
|
|
77
77
|
|
|
78
|
-
1. **
|
|
79
|
-
2. **
|
|
80
|
-
3. **
|
|
81
|
-
|
|
78
|
+
1. **Load skill:** `skill({ name: "executing-plans" })`
|
|
79
|
+
2. **Parse waves** from dependency graph section
|
|
80
|
+
3. **Execute wave-by-wave:**
|
|
81
|
+
- Single-task wave → execute directly (no subagent overhead)
|
|
82
|
+
- Multi-task wave → dispatch parallel `task({ subagent_type: "general" })` subagents, one per task
|
|
83
|
+
4. **Review after each wave** — run verification gates, report, wait for feedback
|
|
82
84
|
5. **Continue** until all waves complete
|
|
83
85
|
|
|
84
|
-
**Parallel safety:** Only tasks within same wave run in parallel. Tasks in Wave N+1 wait for Wave N.
|
|
86
|
+
**Parallel safety:** Only tasks within same wave run in parallel. Tasks must NOT share files. Tasks in Wave N+1 wait for Wave N.
|
|
85
87
|
|
|
86
88
|
### Phase 3A: PRD Task Loop (Sequential Fallback)
|
|
87
89
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: executing-plans
|
|
3
|
-
description: Use when
|
|
4
|
-
version:
|
|
5
|
-
tags: [workflow, planning]
|
|
3
|
+
description: Use when a complete implementation plan exists — parses dependency waves, executes independent tasks in parallel via subagents, runs review checkpoints between waves
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
tags: [workflow, planning, parallel]
|
|
6
6
|
dependencies: [writing-plans]
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Executing Plans
|
|
10
10
|
|
|
11
|
-
> **Replaces**
|
|
11
|
+
> **Replaces** sequential task-by-task implementation — detects parallelizable waves and dispatches subagents concurrently within each wave
|
|
12
|
+
|
|
12
13
|
## When to Use
|
|
13
14
|
|
|
14
|
-
- A complete implementation plan exists
|
|
15
|
-
-
|
|
15
|
+
- A complete implementation plan exists (`.beads/artifacts/<id>/plan.md` or provided directly)
|
|
16
|
+
- The plan has a dependency graph with wave assignments from `/plan`
|
|
16
17
|
|
|
17
18
|
## When NOT to Use
|
|
18
19
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
20
|
+
- No plan yet (use `writing-plans` or `prd` first)
|
|
21
|
+
- All tasks are tightly sequential with no parallelism opportunity
|
|
22
|
+
- Fewer than 3 tasks (just execute directly, overhead not worth it)
|
|
21
23
|
|
|
22
24
|
## Overview
|
|
23
25
|
|
|
24
|
-
Load plan
|
|
26
|
+
Load plan → parse dependency waves → execute each wave (parallel within, sequential between) → review after each wave → next wave.
|
|
25
27
|
|
|
26
|
-
**Core principle:**
|
|
28
|
+
**Core principle:** Parallel within waves, sequential between waves, review at wave boundaries.
|
|
27
29
|
|
|
28
30
|
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
|
|
29
31
|
|
|
@@ -36,104 +38,149 @@ Load plan, review critically, execute tasks in batches, report for review betwee
|
|
|
36
38
|
- [ ] Read the plan file end-to-end
|
|
37
39
|
- [ ] Identify goal, deliverables, risks, and missing pieces
|
|
38
40
|
- [ ] If concerns, ask via `question()` and wait for decision
|
|
39
|
-
- [ ] If no concerns,
|
|
41
|
+
- [ ] If no concerns, proceed to wave parsing
|
|
40
42
|
|
|
41
43
|
1. Read plan file
|
|
42
|
-
2. Review critically
|
|
43
|
-
3. If concerns:
|
|
44
|
+
2. Review critically — identify any questions or concerns
|
|
45
|
+
3. If concerns: raise them with `question()` tool
|
|
46
|
+
4. If no concerns: proceed
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
question({
|
|
47
|
-
questions: [
|
|
48
|
-
{
|
|
49
|
-
header: "Concerns",
|
|
50
|
-
question: "Plan review complete. Any concerns before proceeding?",
|
|
51
|
-
options: [
|
|
52
|
-
{
|
|
53
|
-
label: "No concerns (Recommended)",
|
|
54
|
-
description: "Plan looks good, execute batches",
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
label: "Has concerns",
|
|
58
|
-
description: "Need clarification before starting",
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
});
|
|
64
|
-
```
|
|
48
|
+
### Step 2: Parse Dependency Graph
|
|
65
49
|
|
|
66
|
-
|
|
67
|
-
- What is the goal?
|
|
68
|
-
- What are the deliverables?
|
|
69
|
-
- What are the risks?
|
|
70
|
-
- Does the approach make sense?
|
|
71
|
-
- Are there missing pieces?
|
|
50
|
+
Look for the dependency graph section in the plan. The `/plan` command generates this format:
|
|
72
51
|
|
|
73
|
-
|
|
74
|
-
|
|
52
|
+
```
|
|
53
|
+
## Dependency Graph
|
|
75
54
|
|
|
76
|
-
|
|
55
|
+
Task A: needs nothing, creates src/models/X.ts
|
|
56
|
+
Task B: needs Task A, creates src/api/X.ts
|
|
57
|
+
Task C: needs nothing, creates src/utils/Y.ts
|
|
58
|
+
Task D: needs Task B + Task C, creates src/routes/Z.ts
|
|
77
59
|
|
|
78
|
-
|
|
60
|
+
Wave 1: A, C (independent)
|
|
61
|
+
Wave 2: B (depends on A)
|
|
62
|
+
Wave 3: D (depends on B, C)
|
|
63
|
+
```
|
|
79
64
|
|
|
80
|
-
**
|
|
65
|
+
**Extract:**
|
|
66
|
+
- Which tasks belong to each wave
|
|
67
|
+
- Which files each task modifies (for conflict detection)
|
|
68
|
+
- Dependencies between tasks
|
|
81
69
|
|
|
82
|
-
|
|
83
|
-
# Tag the safe point before this batch/wave
|
|
84
|
-
git tag wave-${BATCH_NUMBER}-start
|
|
85
|
-
```
|
|
70
|
+
**If no dependency graph found:** Fall back to sequential execution (batch of 3 tasks).
|
|
86
71
|
|
|
87
|
-
|
|
72
|
+
**File conflict check:** Tasks in the same wave MUST NOT modify the same files. If they do, move one to the next wave.
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
- [ ] Mark each task in_progress
|
|
91
|
-
- [ ] Follow each step exactly as written
|
|
92
|
-
- [ ] Run all specified verifications
|
|
93
|
-
- [ ] Mark tasks completed
|
|
94
|
-
- [ ] Create wave complete tag: `git tag wave-${BATCH_NUMBER}-complete`
|
|
74
|
+
### Step 3: Create TodoWrite
|
|
95
75
|
|
|
96
|
-
|
|
76
|
+
Create todos for all tasks, grouped by wave:
|
|
97
77
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
78
|
+
```typescript
|
|
79
|
+
todowrite({
|
|
80
|
+
todos: [
|
|
81
|
+
{ content: "Wave 1: Task A — [description]", status: "pending", priority: "high" },
|
|
82
|
+
{ content: "Wave 1: Task C — [description]", status: "pending", priority: "high" },
|
|
83
|
+
{ content: "Wave 1 review checkpoint", status: "pending", priority: "high" },
|
|
84
|
+
{ content: "Wave 2: Task B — [description]", status: "pending", priority: "high" },
|
|
85
|
+
{ content: "Wave 2 review checkpoint", status: "pending", priority: "high" },
|
|
86
|
+
// ...
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Step 4: Execute Wave
|
|
102
92
|
|
|
103
|
-
**
|
|
93
|
+
**Before starting a wave:** create a git tag for safe rollback:
|
|
104
94
|
|
|
105
95
|
```bash
|
|
106
|
-
|
|
107
|
-
git tag wave-${BATCH_NUMBER}-complete
|
|
96
|
+
git tag wave-${WAVE_NUMBER}-start
|
|
108
97
|
```
|
|
109
98
|
|
|
110
|
-
|
|
99
|
+
#### Single-task wave (no parallelism needed)
|
|
111
100
|
|
|
112
|
-
|
|
101
|
+
Execute directly in the current agent context. No subagent overhead.
|
|
113
102
|
|
|
114
|
-
-
|
|
115
|
-
- [ ] Include verification output
|
|
116
|
-
- [ ] Confirm wave tag created (e.g., `wave-1-complete`)
|
|
117
|
-
- [ ] Ask for feedback before continuing
|
|
103
|
+
#### Multi-task wave (2+ independent tasks)
|
|
118
104
|
|
|
119
|
-
|
|
105
|
+
Dispatch parallel subagents — one per task:
|
|
120
106
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
107
|
+
```typescript
|
|
108
|
+
// Dispatch all tasks in this wave simultaneously
|
|
109
|
+
task({
|
|
110
|
+
subagent_type: "general",
|
|
111
|
+
description: `Wave ${N}: Task A — ${taskTitle}`,
|
|
112
|
+
prompt: `You are implementing Task A from the plan.
|
|
113
|
+
|
|
114
|
+
## Task
|
|
115
|
+
${taskDescription}
|
|
116
|
+
|
|
117
|
+
## Files to modify
|
|
118
|
+
${taskFiles.join('\n')}
|
|
119
|
+
|
|
120
|
+
## Constraints
|
|
121
|
+
- ONLY modify files listed above
|
|
122
|
+
- Follow each step exactly as written in the task
|
|
123
|
+
- Run verification commands specified in the task
|
|
124
|
+
- Commit your changes: git add <specific-files> && git commit -m "feat: ${taskTitle}"
|
|
125
|
+
|
|
126
|
+
## Report back
|
|
127
|
+
- What you implemented
|
|
128
|
+
- Files changed
|
|
129
|
+
- Verification results (pass/fail)
|
|
130
|
+
- Commit hash
|
|
131
|
+
- Any issues or blockers`
|
|
132
|
+
});
|
|
133
|
+
// ...dispatch other tasks in this wave simultaneously
|
|
134
|
+
```
|
|
125
135
|
|
|
126
|
-
|
|
136
|
+
**Critical rules for parallel dispatch:**
|
|
137
|
+
|
|
138
|
+
| Rule | Why |
|
|
139
|
+
| --- | --- |
|
|
140
|
+
| Non-overlapping files | Subagents editing same file = merge conflicts |
|
|
141
|
+
| Exact file list per subagent | Prevents scope creep into other tasks |
|
|
142
|
+
| Each subagent commits independently | Clean git history per task |
|
|
143
|
+
| Never `git add .` | Only stage files from this task |
|
|
144
|
+
|
|
145
|
+
#### Wave Execution Checklist
|
|
146
|
+
|
|
147
|
+
- [ ] Create wave start tag: `git tag wave-${WAVE_NUMBER}-start`
|
|
148
|
+
- [ ] Dispatch subagents for all tasks in this wave (parallel)
|
|
149
|
+
- [ ] Collect results from all subagents
|
|
150
|
+
- [ ] Check for failures — if any task failed, stop and report
|
|
151
|
+
- [ ] Run verification gates (typecheck + lint in parallel, then tests)
|
|
152
|
+
- [ ] Create wave complete tag: `git tag wave-${WAVE_NUMBER}-complete`
|
|
153
|
+
- [ ] Mark wave tasks as completed in TodoWrite
|
|
154
|
+
|
|
155
|
+
### Step 5: Review Wave
|
|
156
|
+
|
|
157
|
+
After each wave completes:
|
|
158
|
+
|
|
159
|
+
1. **Synthesize results** from all subagents
|
|
160
|
+
2. **Run verification gates** on the combined changes:
|
|
161
|
+
```bash
|
|
162
|
+
# Parallel: typecheck + lint
|
|
163
|
+
npm run typecheck & npm run lint & wait
|
|
164
|
+
# Sequential: tests
|
|
165
|
+
npm test
|
|
166
|
+
```
|
|
167
|
+
3. **Report to user:**
|
|
168
|
+
- Tasks completed in this wave
|
|
169
|
+
- Verification results
|
|
170
|
+
- Wave tag created
|
|
171
|
+
- Any issues found
|
|
172
|
+
4. **Wait for feedback** before proceeding to next wave
|
|
173
|
+
|
|
174
|
+
### Step 6: Next Wave
|
|
127
175
|
|
|
128
176
|
Based on feedback:
|
|
177
|
+
- Apply corrections if needed
|
|
178
|
+
- Execute next wave (repeat Steps 4-5)
|
|
179
|
+
- Continue until all waves complete
|
|
129
180
|
|
|
130
|
-
|
|
131
|
-
- Execute next batch
|
|
132
|
-
- Repeat until complete
|
|
133
|
-
|
|
134
|
-
### Step 5: Complete Development
|
|
181
|
+
### Step 7: Complete Development
|
|
135
182
|
|
|
136
|
-
After all
|
|
183
|
+
After all waves complete and verified:
|
|
137
184
|
|
|
138
185
|
- Announce: "I'm using finishing-a-development-branch skill to complete this work."
|
|
139
186
|
- **REQUIRED SUB-SKILL:** Use skill({ name: "finishing-a-development-branch" })
|
|
@@ -147,84 +194,54 @@ Git tags act as checkpoints between waves. If a wave fails irrecoverably, roll b
|
|
|
147
194
|
|
|
148
195
|
| When | Command | Purpose |
|
|
149
196
|
| ---------------------------- | ------------------------------- | ------------------------- |
|
|
150
|
-
| Before starting any
|
|
151
|
-
| After
|
|
197
|
+
| Before starting any wave | `git tag wave-N-start` | Mark rollback point |
|
|
198
|
+
| After wave passes all gates | `git tag wave-N-complete` | Seal confirmed-good state |
|
|
152
199
|
| On irrecoverable failure | `git reset --hard wave-N-start` | Restore to pre-wave state |
|
|
153
200
|
| Listing all wave checkpoints | `git tag --list "wave-*"` | Audit trail of execution |
|
|
154
201
|
|
|
155
202
|
### When to Rollback
|
|
156
203
|
|
|
157
204
|
Roll back (with user confirmation) when:
|
|
158
|
-
|
|
159
|
-
-
|
|
160
|
-
- Unexpected destructive changes were made
|
|
161
|
-
- Drift check detects unrecoverable scope creep
|
|
205
|
+
- Verification gates fail twice consecutively in the same wave
|
|
206
|
+
- Subagent made destructive changes outside its file scope
|
|
162
207
|
- Tests were broken and the cause is unclear
|
|
163
208
|
|
|
164
|
-
**Always ask the user before running `git reset --hard`**
|
|
165
|
-
|
|
166
|
-
### Rollback Steps
|
|
167
|
-
|
|
168
|
-
```bash
|
|
169
|
-
# 1. Identify safe point
|
|
170
|
-
git tag --list "wave-*"
|
|
171
|
-
# e.g.: wave-1-complete wave-2-start wave-2-complete wave-3-start
|
|
172
|
-
|
|
173
|
-
# 2. Confirm with user: rollback to which tag?
|
|
174
|
-
# e.g.: git reset --hard wave-2-complete (last known good)
|
|
209
|
+
**Always ask the user before running `git reset --hard`** — it discards uncommitted changes irreversibly.
|
|
175
210
|
|
|
176
|
-
|
|
177
|
-
git reset --hard wave-2-complete
|
|
211
|
+
## Sequential Fallback
|
|
178
212
|
|
|
179
|
-
|
|
180
|
-
npm run typecheck && npm run lint
|
|
213
|
+
If the plan has no dependency graph or waves:
|
|
181
214
|
|
|
182
|
-
|
|
183
|
-
|
|
215
|
+
1. Group tasks into batches of 3
|
|
216
|
+
2. Execute each batch sequentially (no parallel subagents)
|
|
217
|
+
3. Review between batches
|
|
218
|
+
4. Same wave-tag protocol applies
|
|
184
219
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
```
|
|
188
|
-
wave-1-start # Before batch 1 starts
|
|
189
|
-
wave-1-complete # After batch 1 passes all gates
|
|
190
|
-
wave-2-start # Before batch 2 starts
|
|
191
|
-
wave-2-complete # After batch 2 passes all gates
|
|
192
|
-
...
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
Use numeric batch numbers, not task names, for predictable reference.
|
|
220
|
+
This preserves backward compatibility with plans that don't have wave assignments.
|
|
196
221
|
|
|
197
222
|
## When to Stop and Ask for Help
|
|
198
223
|
|
|
199
224
|
**STOP executing immediately when:**
|
|
200
|
-
|
|
201
|
-
-
|
|
225
|
+
- Subagent reports a blocker or failure
|
|
226
|
+
- File conflict detected between parallel tasks
|
|
227
|
+
- Verification fails twice in the same wave
|
|
202
228
|
- Plan has critical gaps preventing starting
|
|
203
|
-
- You don't understand an instruction
|
|
204
|
-
- Verification fails repeatedly
|
|
205
229
|
|
|
206
230
|
**Ask for clarification rather than guessing.**
|
|
207
231
|
|
|
208
|
-
##
|
|
209
|
-
|
|
210
|
-
**Return to Review (Step 1) when:**
|
|
211
|
-
|
|
212
|
-
- Partner updates the plan based on your feedback
|
|
213
|
-
- Fundamental approach needs rethinking
|
|
214
|
-
|
|
215
|
-
**Don't force through blockers** - stop and ask.
|
|
216
|
-
|
|
217
|
-
## Remember
|
|
232
|
+
## Anti-Patterns
|
|
218
233
|
|
|
219
|
-
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
234
|
+
| Anti-Pattern | Why It Fails | Instead |
|
|
235
|
+
| --- | --- | --- |
|
|
236
|
+
| Dispatching parallel subagents for tasks that share files | Edit conflicts, lost changes, merge chaos | Move conflicting tasks to separate waves |
|
|
237
|
+
| Skipping verification between waves | Broken code compounds across waves | Run all gates after each wave before proceeding |
|
|
238
|
+
| Giving subagents the full plan instead of their task | Context pollution, scope creep | Extract only the specific task + file list |
|
|
239
|
+
| Running all tasks in one wave regardless of dependencies | Later tasks fail because prerequisites aren't ready | Respect the dependency graph strictly |
|
|
240
|
+
| Not committing per-task | Can't rollback individual tasks, messy git history | Each subagent commits its own changes |
|
|
225
241
|
|
|
226
242
|
## See Also
|
|
227
243
|
|
|
228
|
-
- `writing-plans`
|
|
229
|
-
- `swarm-coordination`
|
|
230
|
-
- `
|
|
244
|
+
- `writing-plans` — Create detailed, zero-ambiguity implementation plans before execution
|
|
245
|
+
- `swarm-coordination` — For 10+ task scenarios with full PARL orchestration
|
|
246
|
+
- `subagent-driven-development` — For sequential per-task execution with review between each
|
|
247
|
+
- `verification-before-completion` — Run final verification gates before claiming completion
|