@benzotti/jedi 0.1.32 → 0.1.34
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 +242 -50
- package/framework/agents/jdi-planner.md +33 -18
- package/framework/commands/create-plan.md +12 -6
- package/framework/commands/implement-plan.md +9 -9
- package/framework/commands/pr-review.md +18 -0
- package/framework/components/meta/StateUpdate.md +7 -1
- package/framework/components/quality/PRReview.md +12 -1
- package/framework/templates/CLAUDE-SHARED.md +23 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9355,7 +9355,7 @@ Recognise natural language JDI intents and invoke the matching skill via the Ski
|
|
|
9355
9355
|
|
|
9356
9356
|
Extract flags from context: "in a worktree" \u2192 \`--worktree\`, "lightweight" \u2192 \`--worktree-lightweight\`, "single agent" \u2192 \`--single\`, "use teams" \u2192 \`--team\`. If the intent is unclear, ask. Never guess.
|
|
9357
9357
|
|
|
9358
|
-
Planning and implementation are separate
|
|
9358
|
+
Planning and implementation are separate human-gated phases \u2014 NEVER auto-proceed to implementation after plan approval. When a plan is approved, STOP and wait for an explicit implementation request.
|
|
9359
9359
|
|
|
9360
9360
|
## Iterative Refinement
|
|
9361
9361
|
|
|
@@ -9379,7 +9379,7 @@ Recognise natural language JDI intents and invoke the matching skill via the Ski
|
|
|
9379
9379
|
|
|
9380
9380
|
Extract flags from context: "in a worktree" \u2192 \`--worktree\`, "lightweight" \u2192 \`--worktree-lightweight\`, "single agent" \u2192 \`--single\`, "use teams" \u2192 \`--team\`. If the intent is unclear, ask. Never guess.
|
|
9381
9381
|
|
|
9382
|
-
Planning and implementation are separate
|
|
9382
|
+
Planning and implementation are separate human-gated phases \u2014 NEVER auto-proceed to implementation after plan approval. When a plan is approved, STOP and wait for an explicit implementation request.
|
|
9383
9383
|
|
|
9384
9384
|
## Iterative Refinement
|
|
9385
9385
|
|
|
@@ -9975,6 +9975,9 @@ function buildReviewPrompt(ctx, prNum, meta, diff) {
|
|
|
9975
9975
|
``,
|
|
9976
9976
|
meta,
|
|
9977
9977
|
``,
|
|
9978
|
+
...buildLearningsBlock(ctx.techStack),
|
|
9979
|
+
`Cross-reference learnings against every change \u2014 flag violations and praise adherence.`,
|
|
9980
|
+
``,
|
|
9978
9981
|
`## Diff`,
|
|
9979
9982
|
"```diff",
|
|
9980
9983
|
diff,
|
|
@@ -9992,6 +9995,7 @@ function buildReviewPrompt(ctx, prNum, meta, diff) {
|
|
|
9992
9995
|
`- Does it follow the project's existing patterns?`,
|
|
9993
9996
|
`- Are naming conventions consistent?`,
|
|
9994
9997
|
`- Is the code well-organised?`,
|
|
9998
|
+
`- Does it follow the team's documented learnings?`,
|
|
9995
9999
|
``,
|
|
9996
10000
|
`### Security`,
|
|
9997
10001
|
`- Any injection risks (SQL, XSS, command)?`,
|
|
@@ -10080,6 +10084,72 @@ async function writeState(cwd, state) {
|
|
|
10080
10084
|
}
|
|
10081
10085
|
|
|
10082
10086
|
// src/utils/state-handlers.ts
|
|
10087
|
+
var import_yaml4 = __toESM(require_dist(), 1);
|
|
10088
|
+
import { join as join9 } from "path";
|
|
10089
|
+
import { existsSync as existsSync9 } from "fs";
|
|
10090
|
+
function parseFrontmatter(content) {
|
|
10091
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
10092
|
+
if (!match)
|
|
10093
|
+
return null;
|
|
10094
|
+
try {
|
|
10095
|
+
return import_yaml4.parse(match[1]);
|
|
10096
|
+
} catch {
|
|
10097
|
+
return null;
|
|
10098
|
+
}
|
|
10099
|
+
}
|
|
10100
|
+
async function transitionToPlanReady(cwd, planPath, planName) {
|
|
10101
|
+
const state = await readState(cwd) ?? {};
|
|
10102
|
+
const fullPlanPath = planPath.startsWith("/") ? planPath : join9(cwd, planPath);
|
|
10103
|
+
let phase;
|
|
10104
|
+
let planNumber;
|
|
10105
|
+
let taskFiles = [];
|
|
10106
|
+
if (existsSync9(fullPlanPath)) {
|
|
10107
|
+
const content = await Bun.file(fullPlanPath).text();
|
|
10108
|
+
const fm = parseFrontmatter(content);
|
|
10109
|
+
if (fm) {
|
|
10110
|
+
if (fm.phase != null)
|
|
10111
|
+
phase = Number(fm.phase);
|
|
10112
|
+
if (fm.plan != null)
|
|
10113
|
+
planNumber = String(fm.plan);
|
|
10114
|
+
if (Array.isArray(fm.task_files))
|
|
10115
|
+
taskFiles = fm.task_files;
|
|
10116
|
+
}
|
|
10117
|
+
}
|
|
10118
|
+
state.position = {
|
|
10119
|
+
...state.position,
|
|
10120
|
+
...phase != null ? { phase } : {},
|
|
10121
|
+
plan: planNumber ?? planPath,
|
|
10122
|
+
plan_name: planName,
|
|
10123
|
+
status: "planning"
|
|
10124
|
+
};
|
|
10125
|
+
state.current_plan = {
|
|
10126
|
+
...state.current_plan,
|
|
10127
|
+
path: planPath,
|
|
10128
|
+
tasks: taskFiles,
|
|
10129
|
+
completed_tasks: [],
|
|
10130
|
+
current_task_index: taskFiles.length > 0 ? 0 : null
|
|
10131
|
+
};
|
|
10132
|
+
state.progress = {
|
|
10133
|
+
...state.progress,
|
|
10134
|
+
tasks_total: taskFiles.length,
|
|
10135
|
+
tasks_completed: 0
|
|
10136
|
+
};
|
|
10137
|
+
state.review = {
|
|
10138
|
+
...state.review,
|
|
10139
|
+
status: "in_review",
|
|
10140
|
+
scope: "plan"
|
|
10141
|
+
};
|
|
10142
|
+
await updateSessionActivity(cwd, state);
|
|
10143
|
+
}
|
|
10144
|
+
async function transitionToApproved(cwd) {
|
|
10145
|
+
const state = await readState(cwd) ?? {};
|
|
10146
|
+
state.review = {
|
|
10147
|
+
...state.review,
|
|
10148
|
+
status: "approved",
|
|
10149
|
+
approved_at: new Date().toISOString()
|
|
10150
|
+
};
|
|
10151
|
+
await updateSessionActivity(cwd, state);
|
|
10152
|
+
}
|
|
10083
10153
|
async function transitionToExecuting(cwd, taskId, taskName) {
|
|
10084
10154
|
const state = await readState(cwd) ?? {};
|
|
10085
10155
|
state.position = {
|
|
@@ -10098,6 +10168,24 @@ async function transitionToComplete(cwd) {
|
|
|
10098
10168
|
};
|
|
10099
10169
|
await updateSessionActivity(cwd, state);
|
|
10100
10170
|
}
|
|
10171
|
+
async function advanceTask(cwd, completedTaskId) {
|
|
10172
|
+
const state = await readState(cwd) ?? {};
|
|
10173
|
+
if (state.current_plan) {
|
|
10174
|
+
const completed = state.current_plan.completed_tasks ?? [];
|
|
10175
|
+
if (!completed.includes(completedTaskId)) {
|
|
10176
|
+
completed.push(completedTaskId);
|
|
10177
|
+
}
|
|
10178
|
+
state.current_plan.completed_tasks = completed;
|
|
10179
|
+
const tasks = state.current_plan.tasks ?? [];
|
|
10180
|
+
const nextIndex = completed.length;
|
|
10181
|
+
state.current_plan.current_task_index = nextIndex < tasks.length ? nextIndex : null;
|
|
10182
|
+
}
|
|
10183
|
+
if (!state.progress) {
|
|
10184
|
+
state.progress = { phases_total: 0, phases_completed: 0, plans_total: 0, plans_completed: 0, tasks_total: 0, tasks_completed: 0 };
|
|
10185
|
+
}
|
|
10186
|
+
state.progress.tasks_completed = (state.progress.tasks_completed ?? 0) + 1;
|
|
10187
|
+
await updateSessionActivity(cwd, state);
|
|
10188
|
+
}
|
|
10101
10189
|
async function updateSessionActivity(cwd, state) {
|
|
10102
10190
|
state.session = {
|
|
10103
10191
|
...state.session,
|
|
@@ -10278,15 +10366,15 @@ var statusCommand = defineCommand({
|
|
|
10278
10366
|
import { relative } from "path";
|
|
10279
10367
|
|
|
10280
10368
|
// src/utils/resolve-components.ts
|
|
10281
|
-
import { join as
|
|
10369
|
+
import { join as join10, basename } from "path";
|
|
10282
10370
|
import { homedir } from "os";
|
|
10283
10371
|
async function resolveComponents(cwd) {
|
|
10284
10372
|
const components = [];
|
|
10285
10373
|
const seen = new Set;
|
|
10286
10374
|
const sources = [
|
|
10287
|
-
{ dir:
|
|
10288
|
-
{ dir:
|
|
10289
|
-
{ dir:
|
|
10375
|
+
{ dir: join10(cwd, ".jdi", "framework", "components"), source: "project" },
|
|
10376
|
+
{ dir: join10(homedir(), ".jdi", "components"), source: "user" },
|
|
10377
|
+
{ dir: join10(import.meta.dir, "../framework/components"), source: "builtin" }
|
|
10290
10378
|
];
|
|
10291
10379
|
for (const { dir, source } of sources) {
|
|
10292
10380
|
try {
|
|
@@ -10295,7 +10383,7 @@ async function resolveComponents(cwd) {
|
|
|
10295
10383
|
const name = basename(file, ".md");
|
|
10296
10384
|
if (!seen.has(name)) {
|
|
10297
10385
|
seen.add(name);
|
|
10298
|
-
components.push({ name, path:
|
|
10386
|
+
components.push({ name, path: join10(dir, file), source });
|
|
10299
10387
|
}
|
|
10300
10388
|
}
|
|
10301
10389
|
} catch {}
|
|
@@ -10441,8 +10529,8 @@ Use --all to stage and commit all, or stage files manually.`);
|
|
|
10441
10529
|
});
|
|
10442
10530
|
|
|
10443
10531
|
// src/commands/pr.ts
|
|
10444
|
-
import { existsSync as
|
|
10445
|
-
import { join as
|
|
10532
|
+
import { existsSync as existsSync10 } from "fs";
|
|
10533
|
+
import { join as join11 } from "path";
|
|
10446
10534
|
async function hasGhCli() {
|
|
10447
10535
|
const { exitCode } = await exec(["which", "gh"]);
|
|
10448
10536
|
return exitCode === 0;
|
|
@@ -10493,8 +10581,8 @@ var prCommand = defineCommand({
|
|
|
10493
10581
|
let verificationChecks = [];
|
|
10494
10582
|
const planPath = state?.current_plan?.path;
|
|
10495
10583
|
if (planPath) {
|
|
10496
|
-
const fullPlanPath =
|
|
10497
|
-
if (
|
|
10584
|
+
const fullPlanPath = join11(cwd, planPath);
|
|
10585
|
+
if (existsSync10(fullPlanPath)) {
|
|
10498
10586
|
try {
|
|
10499
10587
|
const planContent = await Bun.file(fullPlanPath).text();
|
|
10500
10588
|
const nameMatch = planContent.match(/^#\s+(.+)/m);
|
|
@@ -10517,8 +10605,8 @@ ${taskLines.map((l2) => `- ${l2.split("|").slice(2, 3).join("").trim()}`).join(`
|
|
|
10517
10605
|
}
|
|
10518
10606
|
}
|
|
10519
10607
|
let template = "";
|
|
10520
|
-
const templatePath =
|
|
10521
|
-
if (
|
|
10608
|
+
const templatePath = join11(cwd, ".github", "pull_request_template.md");
|
|
10609
|
+
if (existsSync10(templatePath)) {
|
|
10522
10610
|
template = await Bun.file(templatePath).text();
|
|
10523
10611
|
}
|
|
10524
10612
|
const title = branch.replace(/^(feat|fix|chore|docs|refactor|test|ci)\//, "").replace(/[-_]/g, " ").replace(/^\w/, (c3) => c3.toUpperCase());
|
|
@@ -10621,7 +10709,8 @@ ${data.body}` : ""
|
|
|
10621
10709
|
meta = metaResult.stdout;
|
|
10622
10710
|
}
|
|
10623
10711
|
}
|
|
10624
|
-
const
|
|
10712
|
+
const ctx = await gatherPromptContext(process.cwd());
|
|
10713
|
+
const prompt2 = buildReviewPrompt(ctx, String(prNum), meta, diffResult.stdout);
|
|
10625
10714
|
if (args.output) {
|
|
10626
10715
|
await Bun.write(resolve7(process.cwd(), args.output), prompt2);
|
|
10627
10716
|
consola.success(`Review prompt written to ${args.output}`);
|
|
@@ -10813,7 +10902,7 @@ var quickCommand = defineCommand({
|
|
|
10813
10902
|
});
|
|
10814
10903
|
|
|
10815
10904
|
// src/commands/worktree.ts
|
|
10816
|
-
import { existsSync as
|
|
10905
|
+
import { existsSync as existsSync11 } from "fs";
|
|
10817
10906
|
function slugify(name) {
|
|
10818
10907
|
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
10819
10908
|
}
|
|
@@ -10847,7 +10936,7 @@ var worktreeCommand = defineCommand({
|
|
|
10847
10936
|
}
|
|
10848
10937
|
const slug = slugify(args.name);
|
|
10849
10938
|
const worktreePath = `${root}/.worktrees/${slug}`;
|
|
10850
|
-
if (
|
|
10939
|
+
if (existsSync11(worktreePath)) {
|
|
10851
10940
|
consola.error(`Worktree already exists at ${worktreePath}`);
|
|
10852
10941
|
return;
|
|
10853
10942
|
}
|
|
@@ -11013,7 +11102,7 @@ Specify a worktree name: jdi worktree-remove <name>`);
|
|
|
11013
11102
|
|
|
11014
11103
|
// src/commands/plan-review.ts
|
|
11015
11104
|
import { resolve as resolve9 } from "path";
|
|
11016
|
-
import { existsSync as
|
|
11105
|
+
import { existsSync as existsSync12 } from "fs";
|
|
11017
11106
|
function parsePlanSummary(content) {
|
|
11018
11107
|
const nameMatch = content.match(/^# .+?: (.+)$/m);
|
|
11019
11108
|
const name = nameMatch?.[1] ?? "Unknown";
|
|
@@ -11052,7 +11141,7 @@ var planReviewCommand = defineCommand({
|
|
|
11052
11141
|
consola.error("No plan found. Run `jdi plan` first.");
|
|
11053
11142
|
return;
|
|
11054
11143
|
}
|
|
11055
|
-
if (!
|
|
11144
|
+
if (!existsSync12(planPath)) {
|
|
11056
11145
|
consola.error(`Plan not found: ${planPath}`);
|
|
11057
11146
|
return;
|
|
11058
11147
|
}
|
|
@@ -11142,7 +11231,7 @@ Tasks (${tasks.length}):`);
|
|
|
11142
11231
|
|
|
11143
11232
|
// src/commands/plan-approve.ts
|
|
11144
11233
|
import { resolve as resolve10 } from "path";
|
|
11145
|
-
import { existsSync as
|
|
11234
|
+
import { existsSync as existsSync13 } from "fs";
|
|
11146
11235
|
var planApproveCommand = defineCommand({
|
|
11147
11236
|
meta: {
|
|
11148
11237
|
name: "plan-approve",
|
|
@@ -11171,7 +11260,7 @@ var planApproveCommand = defineCommand({
|
|
|
11171
11260
|
consola.error("No plan to approve. Run `jdi plan` first.");
|
|
11172
11261
|
return;
|
|
11173
11262
|
}
|
|
11174
|
-
if (!
|
|
11263
|
+
if (!existsSync13(planPath)) {
|
|
11175
11264
|
consola.error(`Plan not found: ${planPath}`);
|
|
11176
11265
|
return;
|
|
11177
11266
|
}
|
|
@@ -11648,16 +11737,16 @@ Say **\`Hey Jedi implement\`** when you're ready to go.`;
|
|
|
11648
11737
|
return;
|
|
11649
11738
|
}
|
|
11650
11739
|
if (intent.command === "ping") {
|
|
11651
|
-
const { existsSync:
|
|
11652
|
-
const { join:
|
|
11653
|
-
const frameworkExists =
|
|
11654
|
-
const claudeMdExists =
|
|
11655
|
-
const stateExists =
|
|
11656
|
-
const learningsExists =
|
|
11740
|
+
const { existsSync: existsSync14 } = await import("fs");
|
|
11741
|
+
const { join: join13 } = await import("path");
|
|
11742
|
+
const frameworkExists = existsSync14(join13(cwd, ".jdi/framework"));
|
|
11743
|
+
const claudeMdExists = existsSync14(join13(cwd, ".claude/CLAUDE.md"));
|
|
11744
|
+
const stateExists = existsSync14(join13(cwd, ".jdi/config/state.yaml"));
|
|
11745
|
+
const learningsExists = existsSync14(join13(cwd, ".jdi/persistence/learnings.md"));
|
|
11657
11746
|
let version = "unknown";
|
|
11658
11747
|
try {
|
|
11659
|
-
const pkgPath =
|
|
11660
|
-
if (
|
|
11748
|
+
const pkgPath = join13(cwd, "node_modules/@benzotti/jedi/package.json");
|
|
11749
|
+
if (existsSync14(pkgPath)) {
|
|
11661
11750
|
const pkg = JSON.parse(await Bun.file(pkgPath).text());
|
|
11662
11751
|
version = pkg.version;
|
|
11663
11752
|
}
|
|
@@ -11773,11 +11862,12 @@ Say **\`Hey Jedi implement\`** when you're ready to go.`;
|
|
|
11773
11862
|
`## Instructions`,
|
|
11774
11863
|
`Read state.yaml and existing plan files. Apply feedback incrementally \u2014 do not restart from scratch.`,
|
|
11775
11864
|
`If the feedback is a question, answer it conversationally. If it implies a plan change, update the plan.`,
|
|
11865
|
+
`Maintain the SPLIT plan format: update the index file and individual task files (.T{n}.md) separately.`,
|
|
11776
11866
|
``,
|
|
11777
11867
|
`## Response Format (MANDATORY)`,
|
|
11778
|
-
`1-2 sentence summary of what changed. Then the
|
|
11868
|
+
`1-2 sentence summary of what changed. Then the updated plan summary in a collapsible block:`,
|
|
11779
11869
|
`\`<details><summary>View full plan</summary> ... </details>\``,
|
|
11780
|
-
`
|
|
11870
|
+
`Show the tasks manifest table and brief summaries \u2014 full task details are in the task files.`,
|
|
11781
11871
|
`End with: "Any changes before implementation?"`
|
|
11782
11872
|
].join(`
|
|
11783
11873
|
`);
|
|
@@ -11810,8 +11900,14 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
11810
11900
|
`## Learnings`,
|
|
11811
11901
|
`Before planning, read .jdi/persistence/learnings.md and .jdi/framework/learnings/ if they exist. Apply any team preferences found.`,
|
|
11812
11902
|
``,
|
|
11903
|
+
`## Plan File Format`,
|
|
11904
|
+
`CRITICAL: You MUST write plan files in SPLIT format as defined in your spec (Step 7a):`,
|
|
11905
|
+
`1. Write the index file: \`.jdi/plans/{phase}-{plan}-{slug}.plan.md\` \u2014 contains frontmatter with \`task_files:\` list and a manifest table only (NO inline task details)`,
|
|
11906
|
+
`2. Write each task as a separate file: \`.jdi/plans/{phase}-{plan}-{slug}.T{n}.md\` \u2014 one file per task with full implementation details`,
|
|
11907
|
+
`This split format is MANDATORY \u2014 it reduces token usage by letting agents load only their assigned task.`,
|
|
11908
|
+
``,
|
|
11813
11909
|
`## Response Format`,
|
|
11814
|
-
`
|
|
11910
|
+
`After writing the split plan files, respond with EXACTLY this structure (no deviations, no meta-commentary):`,
|
|
11815
11911
|
``,
|
|
11816
11912
|
`1-2 sentence summary of the approach.`,
|
|
11817
11913
|
``,
|
|
@@ -11828,16 +11924,7 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
11828
11924
|
`|------|------|------|------|------|`,
|
|
11829
11925
|
`| T1 | {name} | {S|M|L} | auto | 1 |`,
|
|
11830
11926
|
``,
|
|
11831
|
-
|
|
11832
|
-
`**Objective:** {what this achieves}`,
|
|
11833
|
-
``,
|
|
11834
|
-
`**Steps:**`,
|
|
11835
|
-
`1. {step}`,
|
|
11836
|
-
``,
|
|
11837
|
-
`**Done when:** {completion criterion}`,
|
|
11838
|
-
``,
|
|
11839
|
-
`---`,
|
|
11840
|
-
`(repeat for each task)`,
|
|
11927
|
+
`(For each task, show a brief 1-2 line summary \u2014 full details are in the task files)`,
|
|
11841
11928
|
``,
|
|
11842
11929
|
`### Verification`,
|
|
11843
11930
|
`- [ ] {check 1}`,
|
|
@@ -12036,8 +12123,8 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
12036
12123
|
});
|
|
12037
12124
|
|
|
12038
12125
|
// src/commands/setup-action.ts
|
|
12039
|
-
import { join as
|
|
12040
|
-
import { existsSync as
|
|
12126
|
+
import { join as join13, dirname as dirname3 } from "path";
|
|
12127
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4 } from "fs";
|
|
12041
12128
|
var setupActionCommand = defineCommand({
|
|
12042
12129
|
meta: {
|
|
12043
12130
|
name: "setup-action",
|
|
@@ -12046,18 +12133,18 @@ var setupActionCommand = defineCommand({
|
|
|
12046
12133
|
args: {},
|
|
12047
12134
|
async run() {
|
|
12048
12135
|
const cwd = process.cwd();
|
|
12049
|
-
const workflowDest =
|
|
12050
|
-
if (
|
|
12136
|
+
const workflowDest = join13(cwd, ".github", "workflows", "jedi.yml");
|
|
12137
|
+
if (existsSync14(workflowDest)) {
|
|
12051
12138
|
consola.warn(`Workflow already exists at ${workflowDest}`);
|
|
12052
12139
|
consola.info("Skipping workflow copy. Delete it manually to regenerate.");
|
|
12053
12140
|
} else {
|
|
12054
|
-
const templatePath =
|
|
12055
|
-
if (!
|
|
12141
|
+
const templatePath = join13(import.meta.dir, "../action/workflow-template.yml");
|
|
12142
|
+
if (!existsSync14(templatePath)) {
|
|
12056
12143
|
consola.error("Workflow template not found. Ensure @benzotti/jedi is properly installed.");
|
|
12057
12144
|
process.exit(1);
|
|
12058
12145
|
}
|
|
12059
12146
|
const dir = dirname3(workflowDest);
|
|
12060
|
-
if (!
|
|
12147
|
+
if (!existsSync14(dir))
|
|
12061
12148
|
mkdirSync4(dir, { recursive: true });
|
|
12062
12149
|
const template = await Bun.file(templatePath).text();
|
|
12063
12150
|
await Bun.write(workflowDest, template);
|
|
@@ -12093,10 +12180,114 @@ var setupActionCommand = defineCommand({
|
|
|
12093
12180
|
`));
|
|
12094
12181
|
}
|
|
12095
12182
|
});
|
|
12183
|
+
|
|
12184
|
+
// src/commands/state.ts
|
|
12185
|
+
var planReadyCommand = defineCommand({
|
|
12186
|
+
meta: {
|
|
12187
|
+
name: "plan-ready",
|
|
12188
|
+
description: "Transition state after plan creation"
|
|
12189
|
+
},
|
|
12190
|
+
args: {
|
|
12191
|
+
"plan-path": {
|
|
12192
|
+
type: "string",
|
|
12193
|
+
description: "Path to the plan file",
|
|
12194
|
+
required: true
|
|
12195
|
+
},
|
|
12196
|
+
"plan-name": {
|
|
12197
|
+
type: "string",
|
|
12198
|
+
description: "Human-readable plan name",
|
|
12199
|
+
required: true
|
|
12200
|
+
}
|
|
12201
|
+
},
|
|
12202
|
+
async run({ args }) {
|
|
12203
|
+
const cwd = process.cwd();
|
|
12204
|
+
await transitionToPlanReady(cwd, args["plan-path"], args["plan-name"]);
|
|
12205
|
+
consola.success(`State \u2192 plan-ready (${args["plan-name"]})`);
|
|
12206
|
+
}
|
|
12207
|
+
});
|
|
12208
|
+
var approvedCommand = defineCommand({
|
|
12209
|
+
meta: {
|
|
12210
|
+
name: "approved",
|
|
12211
|
+
description: "Transition state after plan approval"
|
|
12212
|
+
},
|
|
12213
|
+
async run() {
|
|
12214
|
+
const cwd = process.cwd();
|
|
12215
|
+
await transitionToApproved(cwd);
|
|
12216
|
+
consola.success("State \u2192 approved");
|
|
12217
|
+
}
|
|
12218
|
+
});
|
|
12219
|
+
var executingCommand = defineCommand({
|
|
12220
|
+
meta: {
|
|
12221
|
+
name: "executing",
|
|
12222
|
+
description: "Transition state when implementation starts"
|
|
12223
|
+
},
|
|
12224
|
+
args: {
|
|
12225
|
+
"task-id": {
|
|
12226
|
+
type: "string",
|
|
12227
|
+
description: "Current task ID",
|
|
12228
|
+
required: false
|
|
12229
|
+
},
|
|
12230
|
+
"task-name": {
|
|
12231
|
+
type: "string",
|
|
12232
|
+
description: "Current task name",
|
|
12233
|
+
required: false
|
|
12234
|
+
}
|
|
12235
|
+
},
|
|
12236
|
+
async run({ args }) {
|
|
12237
|
+
const cwd = process.cwd();
|
|
12238
|
+
await transitionToExecuting(cwd, args["task-id"], args["task-name"]);
|
|
12239
|
+
consola.success("State \u2192 executing");
|
|
12240
|
+
}
|
|
12241
|
+
});
|
|
12242
|
+
var completeCommand = defineCommand({
|
|
12243
|
+
meta: {
|
|
12244
|
+
name: "complete",
|
|
12245
|
+
description: "Transition state after implementation finishes"
|
|
12246
|
+
},
|
|
12247
|
+
async run() {
|
|
12248
|
+
const cwd = process.cwd();
|
|
12249
|
+
await transitionToComplete(cwd);
|
|
12250
|
+
consola.success("State \u2192 complete");
|
|
12251
|
+
}
|
|
12252
|
+
});
|
|
12253
|
+
var advanceTaskCommand = defineCommand({
|
|
12254
|
+
meta: {
|
|
12255
|
+
name: "advance-task",
|
|
12256
|
+
description: "Mark a task as completed and advance to next"
|
|
12257
|
+
},
|
|
12258
|
+
args: {
|
|
12259
|
+
"task-id": {
|
|
12260
|
+
type: "positional",
|
|
12261
|
+
description: "ID of the completed task",
|
|
12262
|
+
required: true
|
|
12263
|
+
}
|
|
12264
|
+
},
|
|
12265
|
+
async run({ args }) {
|
|
12266
|
+
const cwd = process.cwd();
|
|
12267
|
+
await advanceTask(cwd, args["task-id"]);
|
|
12268
|
+
const state = await readState(cwd);
|
|
12269
|
+
const completed = state?.current_plan?.completed_tasks?.length ?? 0;
|
|
12270
|
+
const total = state?.current_plan?.tasks?.length ?? 0;
|
|
12271
|
+
consola.success(`Task ${args["task-id"]} completed (${completed}/${total})`);
|
|
12272
|
+
}
|
|
12273
|
+
});
|
|
12274
|
+
var stateCommand = defineCommand({
|
|
12275
|
+
meta: {
|
|
12276
|
+
name: "state",
|
|
12277
|
+
description: "Manage JDI state transitions"
|
|
12278
|
+
},
|
|
12279
|
+
subCommands: {
|
|
12280
|
+
"plan-ready": planReadyCommand,
|
|
12281
|
+
approved: approvedCommand,
|
|
12282
|
+
executing: executingCommand,
|
|
12283
|
+
complete: completeCommand,
|
|
12284
|
+
"advance-task": advanceTaskCommand
|
|
12285
|
+
}
|
|
12286
|
+
});
|
|
12096
12287
|
// package.json
|
|
12097
12288
|
var package_default = {
|
|
12098
12289
|
name: "@benzotti/jedi",
|
|
12099
|
-
version: "0.1.
|
|
12290
|
+
version: "0.1.34",
|
|
12100
12291
|
description: "JDI - Context-efficient AI development framework for Claude Code",
|
|
12101
12292
|
type: "module",
|
|
12102
12293
|
bin: {
|
|
@@ -12158,7 +12349,8 @@ var main = defineCommand({
|
|
|
12158
12349
|
"plan-review": planReviewCommand,
|
|
12159
12350
|
"plan-approve": planApproveCommand,
|
|
12160
12351
|
action: actionCommand,
|
|
12161
|
-
"setup-action": setupActionCommand
|
|
12352
|
+
"setup-action": setupActionCommand,
|
|
12353
|
+
state: stateCommand
|
|
12162
12354
|
}
|
|
12163
12355
|
});
|
|
12164
12356
|
runMain(main);
|
|
@@ -15,14 +15,16 @@ You create executable implementation plans with proper task sizing, dependency m
|
|
|
15
15
|
|
|
16
16
|
## CRITICAL: Scope Discipline
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Do not add unrelated extras (tooling, testing, linting, CI) unless the user explicitly requests them. But you MUST thoroughly investigate the full scope of what WAS requested — including implicit requirements.
|
|
19
19
|
|
|
20
20
|
**Rules:**
|
|
21
|
-
1. **
|
|
22
|
-
2. **
|
|
23
|
-
3. **
|
|
24
|
-
4. **
|
|
25
|
-
5. **
|
|
21
|
+
1. **Do not add unrelated extras.** If the user says "react app with vite and typescript", plan scaffold and config — not linting, CI, or testing unless asked.
|
|
22
|
+
2. **DO investigate the full scope of the request.** "Scope discipline" means no unrelated additions — it does NOT mean ignoring requirements that are clearly implied by the request. If the user asks for a UI view with specific columns, you must verify those columns exist in the backend response, and plan to add them if they don't.
|
|
23
|
+
3. **When reference PRs/tickets are provided, analyse them thoroughly.** Read the actual diff, files changed, patterns used, columns/fields added, routes created, and data flow. The user provides reference PRs so you follow the same pattern — extract the full pattern, don't just skim.
|
|
24
|
+
4. **When the user says "backend is already done", verify it.** Read the actual API endpoint, check what fields it returns, and confirm they match the frontend requirements. If there's a gap, include it in the plan.
|
|
25
|
+
5. **Do not make subjective decisions.** If something is ambiguous (e.g. folder structure, routing library, state management), list it as an open question and ask the user — do not guess.
|
|
26
|
+
6. **Suggest optional additions separately.** After presenting the plan, list 3-5 common additions the user might want. These are suggestions, NOT part of the plan.
|
|
27
|
+
7. **Same request = same plan.** Two identical requests must produce structurally identical plans. Achieve this by following the templates exactly and not improvising.
|
|
26
28
|
|
|
27
29
|
## CRITICAL: Read Learnings First
|
|
28
30
|
|
|
@@ -35,13 +37,18 @@ Before planning, ALWAYS:
|
|
|
35
37
|
|
|
36
38
|
You MUST write files using Write/Edit tools. Returning plan content as text is NOT acceptable.
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
**SANDBOX OVERRIDE:** Plan file creation is an EXCEPTION to AgentBase sandbox rules. You MUST use the Write tool to create plan files directly — do NOT defer them to `files_to_create`. Plan files WILL persist when written via the Write tool. This override applies ONLY to `.jdi/plans/` and `.jdi/config/` files listed below.
|
|
41
|
+
|
|
42
|
+
Required files (SPLIT FORMAT — one file per task):
|
|
43
|
+
1. `.jdi/plans/{phase}-{plan}-{slug}.plan.md` (index file — manifest table only, NO inline task details)
|
|
44
|
+
2. `.jdi/plans/{phase}-{plan}-{slug}.T{n}.md` (one per task — full implementation details)
|
|
45
|
+
3. `.jdi/config/variables.yaml`
|
|
46
|
+
4. `.jdi/ROADMAP.yaml` (add plan entry)
|
|
47
|
+
5. `.jdi/REQUIREMENTS.yaml` (add traceability)
|
|
48
|
+
|
|
49
|
+
The split format is MANDATORY. Each task MUST be a separate `.T{n}.md` file. The index file contains ONLY the frontmatter (with `task_files:` list) and a manifest table — NEVER inline task implementation details.
|
|
50
|
+
|
|
51
|
+
**Do NOT manually edit `.jdi/config/state.yaml`** — state transitions are handled via CLI commands (e.g. `npx jdi state plan-ready`).
|
|
45
52
|
|
|
46
53
|
## File Naming
|
|
47
54
|
|
|
@@ -87,6 +94,15 @@ Never use time estimates. Use S/M/L sizing in task manifests and plan summaries.
|
|
|
87
94
|
4. Research: standard stack, architecture patterns, common pitfalls
|
|
88
95
|
5. Findings feed directly into planning (no separate RESEARCH.md)
|
|
89
96
|
|
|
97
|
+
### Step 0b: Reference Analysis (when provided)
|
|
98
|
+
|
|
99
|
+
If the user provides reference PRs, tickets, or example implementations:
|
|
100
|
+
|
|
101
|
+
1. **Reference PRs**: Fetch each PR's diff (`gh pr diff {number}`), list of changed files (`gh pr view {number} --json files`), and description. Analyse the **complete pattern**: what files were changed, what columns/fields were added, what routes were created, what data transformations were applied. The reference PR defines the pattern you must follow — extract every detail.
|
|
102
|
+
2. **Existing backend/API work**: When the user states "backend is already done" or implies API endpoints exist, verify by reading the actual route files, controllers, and response shapes. Confirm the API returns all fields the frontend will need. If fields are missing, include them in the plan.
|
|
103
|
+
3. **ClickUp/ticket context**: If a ticket URL is provided, read the ticket's description, acceptance criteria, and any attached specifications. Cross-reference against what the plan covers.
|
|
104
|
+
4. **Data requirements for UI work**: When planning a view/page/table, explicitly list every column/field the UI needs, verify each one exists in the API response, and plan to add any that are missing (both backend and frontend).
|
|
105
|
+
|
|
90
106
|
### Step 1: Discovery
|
|
91
107
|
|
|
92
108
|
<JDI:TaskBreakdown source="requirements" />
|
|
@@ -94,6 +110,8 @@ Never use time estimates. Use S/M/L sizing in task manifests and plan summaries.
|
|
|
94
110
|
#### Mandatory Verification (never skip)
|
|
95
111
|
- **Bug fixes**: Grep the symptom across entire codebase. Trace every occurrence through all layers. Do not stop at first match.
|
|
96
112
|
- **API boundaries**: Read backend route, controller, and request validation (or frontend consumer). Never assume endpoint fields.
|
|
113
|
+
- **UI views/tables**: List every column from the requirements. Verify each column's data source exists in the backend response. Plan to add missing fields end-to-end (backend + frontend).
|
|
114
|
+
- **Reference PR patterns**: If reference PRs were provided, verify the plan covers every layer those PRs touched (routes, controllers, types, components, hooks, etc.).
|
|
97
115
|
|
|
98
116
|
### Step 2: Scope Estimation
|
|
99
117
|
If >4 tasks or >3 hours, split into multiple plans.
|
|
@@ -133,12 +151,9 @@ Types: `checkpoint:human-verify`, `checkpoint:decision`, `checkpoint:human-actio
|
|
|
133
151
|
|
|
134
152
|
### Step 7: Generate Plan Document and Update Scaffolding (WRITE FILES)
|
|
135
153
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
#### 7-pre: Update State Files
|
|
139
|
-
Read `.jdi/config/state.yaml` (create from template if missing). Update: `position.phase`, `position.plan`, `position.status` → `"planning"`, `progress.plans_total`, `progress.tasks_total`, `current_plan.path`, `current_plan.tasks`. Each task entry must include `file:` field pointing to the task file path.
|
|
154
|
+
**Do NOT manually edit `.jdi/config/state.yaml`** — use `npx jdi state` CLI commands for transitions. Only record decisions, deviations, or blockers via `<JDI:StateUpdate />`.
|
|
140
155
|
|
|
141
|
-
#### 7-pre
|
|
156
|
+
#### 7-pre: Update Variables
|
|
142
157
|
Read `.jdi/config/variables.yaml` (create from template if missing). Update: `feature.name`, `feature.description`, `feature.type`.
|
|
143
158
|
|
|
144
159
|
#### 7a: Write Plan Files (Split Format)
|
|
@@ -20,12 +20,18 @@ Create an implementation plan using a single planner agent (includes research).
|
|
|
20
20
|
2. Read codebase context (`.jdi/codebase/SUMMARY.md` if exists)
|
|
21
21
|
3. Read scaffolding (.jdi/PROJECT.yaml, REQUIREMENTS.yaml, ROADMAP.yaml) — create from templates if missing
|
|
22
22
|
4. Quick Mode Detection — suggest /jdi:quick for trivial tasks
|
|
23
|
-
5. Spawn `jdi-planner` agent (subagent_type="general-purpose") — creates
|
|
24
|
-
6. Collect and execute deferred ops
|
|
25
|
-
7. Update state
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
5. Spawn `jdi-planner` agent (subagent_type="general-purpose") — creates split plan files (index .plan.md + per-task .T{n}.md files). The planner MUST write these files directly via Write tool (sandbox override for plan files).
|
|
24
|
+
6. Collect and execute deferred ops — if the agent returned `files_to_create`, create them now using Write tool. Verify split plan files exist: index `.plan.md` + individual `.T{n}.md` task files.
|
|
25
|
+
7. **Update state via CLI** — do NOT manually edit state.yaml. Run:
|
|
26
|
+
```bash
|
|
27
|
+
npx jdi state plan-ready --plan-path ".jdi/plans/{plan-file}" --plan-name "{plan name}"
|
|
28
|
+
```
|
|
29
|
+
8. **Present summary** (name, objective, task table, files) then ask: _"Provide feedback to refine, or say **approved** to finalise."_
|
|
30
|
+
9. **Review loop**: Feedback → revise plan in-place, increment revision, re-present summary. Repeat until approved. Approval → run `npx jdi state approved`, then **STOP**.
|
|
31
|
+
|
|
32
|
+
## HARD STOP — Planning Gate
|
|
33
|
+
|
|
34
|
+
After the user approves the plan, your work is **DONE**. Output: _"Plan approved and finalised. Run `/jdi:implement-plan` when ready to execute."_ Then **STOP completely**. Do NOT invoke `/jdi:implement-plan`, do NOT spawn implementation agents, do NOT begin writing source code. Planning and implementation are separate human-gated phases.
|
|
29
35
|
|
|
30
36
|
Agent base (read FIRST for cache): .jdi/framework/components/meta/AgentBase.md | Agent spec: .jdi/framework/agents/jdi-planner.md
|
|
31
37
|
|
|
@@ -15,18 +15,18 @@ Execute a PLAN.md with complexity-based routing.
|
|
|
15
15
|
|
|
16
16
|
1. Read codebase context (`.jdi/codebase/SUMMARY.md` if exists)
|
|
17
17
|
2. Read plan index file and state.yaml — parse frontmatter for tasks, deps, waves, tech_stack
|
|
18
|
-
3. **
|
|
19
|
-
4. **
|
|
20
|
-
5. **
|
|
21
|
-
6.
|
|
18
|
+
3. **Read learnings:** Always read `.jdi/framework/learnings/general.md`. Then read domain-specific learnings based on tech_stack from plan frontmatter: PHP → `backend.md`, TS/React → `frontend.md`. Follow any conventions found — learnings override defaults.
|
|
19
|
+
4. **Format detection:** If frontmatter contains `task_files:`, this is a split plan — task details are in separate files. If absent, legacy monolithic plan — all tasks inline.
|
|
20
|
+
5. **Complexity routing** (`<JDI:ComplexityRouter />`): Simple (≤3 tasks, single stack/wave) → single agent. Complex → Agent Teams swarm. Override: `--team` / `--single`
|
|
21
|
+
6. **Tech routing**: PHP → jdi-backend | TS/React → jdi-frontend | Full-stack → both
|
|
22
|
+
7. Execute:
|
|
22
23
|
- **Single agent:** Pass `PLAN: {index-path}`. For split plans, agent reads task files one at a time via `file:` field in state.yaml.
|
|
23
24
|
- **Agent Teams:** For split plans, pass `TASK_FILE: {task-file-path}` in each agent's spawn prompt so they load only their assigned task file(s). For legacy plans, pass `PLAN: {plan-path}` as before.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
10. Initialise review: `review.status` → `"draft"`, `review.revision` → 1, `review.scope` → `"implementation"`
|
|
25
|
+
8. Collect and execute deferred ops (files, commits)
|
|
26
|
+
9. Run verification (tests, lint, typecheck)
|
|
27
|
+
10. **Update state via CLI** — do NOT manually edit state.yaml. Run `npx jdi state executing` before execution and `npx jdi state complete` after. Use `npx jdi state advance-task {task-id}` after each task completes.
|
|
28
28
|
11. **Present summary** (tasks completed, files changed, verification results, deviations) then ask: _"Provide feedback to adjust, or say **approved** to finalise."_
|
|
29
|
-
12. **Review loop**:
|
|
29
|
+
12. **Review loop**: Feedback → apply code changes, run tests, increment revision, re-present. Approval → suggest commit/PR. Natural conversation — no separate command needed.
|
|
30
30
|
|
|
31
31
|
Agent base (read FIRST for cache): .jdi/framework/components/meta/AgentBase.md | Agent specs: .jdi/framework/agents/jdi-backend.md, .jdi/framework/agents/jdi-frontend.md
|
|
32
32
|
Orchestration: .jdi/framework/components/meta/AgentTeamsOrchestration.md | Routing: .jdi/framework/components/meta/ComplexityRouter.md
|
|
@@ -5,11 +5,29 @@ description: "JDI: Review pull request"
|
|
|
5
5
|
|
|
6
6
|
# /jdi:pr-review
|
|
7
7
|
|
|
8
|
+
Review a pull request with learnings-aware analysis.
|
|
9
|
+
|
|
10
|
+
## Flags
|
|
11
|
+
|
|
12
|
+
- `--no-comments` — Do not post comments to GitHub. Write review to `.jdi/reviews/PR-{number}-review.md` instead.
|
|
13
|
+
|
|
8
14
|
## Delegation
|
|
9
15
|
|
|
16
|
+
Parse flags from $ARGUMENTS. Map `--no-comments` to `post="false"`.
|
|
17
|
+
|
|
10
18
|
Use Task tool with subagent_type="general-purpose" and prompt:
|
|
11
19
|
|
|
12
20
|
Read ./.jdi/framework/components/meta/AgentBase.md for the base protocol.
|
|
21
|
+
|
|
22
|
+
Read learnings before reviewing — these represent the team's coding standards and MUST be cross-referenced during review:
|
|
23
|
+
- Always read: `.jdi/framework/learnings/general.md`
|
|
24
|
+
- For PHP/Laravel PRs: also read `.jdi/framework/learnings/backend.md`
|
|
25
|
+
- For React/TypeScript PRs: also read `.jdi/framework/learnings/frontend.md`
|
|
26
|
+
- For test changes: also read `.jdi/framework/learnings/testing.md`
|
|
27
|
+
- For CI/Docker changes: also read `.jdi/framework/learnings/devops.md`
|
|
28
|
+
Apply learnings as additional review criteria — flag violations and praise adherence.
|
|
29
|
+
|
|
13
30
|
Read ./.jdi/framework/components/quality/PRReview.md for review instructions.
|
|
31
|
+
{If --no-comments flag was present: Include `post="false"` parameter — invoke as `<JDI:PRReview post="false" />`}
|
|
14
32
|
|
|
15
33
|
Review PR: $ARGUMENTS
|
|
@@ -6,7 +6,13 @@ description: Record decisions, deviations, and blockers in state.yaml
|
|
|
6
6
|
|
|
7
7
|
# StateUpdate
|
|
8
8
|
|
|
9
|
-
> **Status transitions are handled
|
|
9
|
+
> **Status transitions are handled via CLI commands.** Do NOT manually edit `position`, `progress`, `current_plan`, `review`, or `session` fields in state.yaml. Use these commands instead:
|
|
10
|
+
>
|
|
11
|
+
> - `npx jdi state plan-ready --plan-path "{path}" --plan-name "{name}"`
|
|
12
|
+
> - `npx jdi state approved`
|
|
13
|
+
> - `npx jdi state executing`
|
|
14
|
+
> - `npx jdi state complete`
|
|
15
|
+
> - `npx jdi state advance-task {task-id}`
|
|
10
16
|
|
|
11
17
|
Use state.yaml ONLY to record decisions, deviations, or blockers:
|
|
12
18
|
|
|
@@ -74,9 +74,20 @@ If context provided:
|
|
|
74
74
|
|
|
75
75
|
Read each changed file in its entirety (not just the diff). **NEVER** use limit/offset.
|
|
76
76
|
|
|
77
|
+
### Step 5b: Cross-Reference Learnings (MANDATORY)
|
|
78
|
+
|
|
79
|
+
If learnings files were loaded (via the command stub or agent prompt), cross-reference every changed file against the team's learnings:
|
|
80
|
+
|
|
81
|
+
1. For each finding from the review checklist, check if a learning exists that addresses it — cite the learning in your comment.
|
|
82
|
+
2. Flag any code that **violates** a documented learning (e.g. a learning says "always use path aliases" but the PR uses relative imports).
|
|
83
|
+
3. **Praise** code that follows learnings the team has documented — this reinforces good patterns.
|
|
84
|
+
4. If no learnings were loaded, skip this step (but note it in your review summary as a gap).
|
|
85
|
+
|
|
86
|
+
Learnings-based findings should use the same severity classification as other findings. A violation of a documented team convention is at minimum a **minor** finding.
|
|
87
|
+
|
|
77
88
|
### Step 6: Perform Code Review
|
|
78
89
|
|
|
79
|
-
Apply <JDI:PRReview:Checklist /> to analyse each change.
|
|
90
|
+
Apply <JDI:PRReview:Checklist /> to analyse each change. Include learnings violations alongside standard checklist findings.
|
|
80
91
|
|
|
81
92
|
### Step 7: Categorise Findings (Internal)
|
|
82
93
|
|
|
@@ -30,13 +30,31 @@ When you learn something new from a review or feedback, update the appropriate c
|
|
|
30
30
|
|
|
31
31
|
## Scope Discipline
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Do not add unrelated extras, tooling, or features the user did not ask for. But DO investigate the full scope of what was requested — including implicit requirements that are clearly part of the ask (e.g. if a UI view needs columns, verify the backend provides them).
|
|
34
34
|
If something is ambiguous, ask — do not guess.
|
|
35
35
|
NEVER use time estimates (minutes, hours, etc). Use S/M/L t-shirt sizing for all task and plan sizing.
|
|
36
36
|
Follow response templates exactly as instructed in the prompt — do not improvise the layout or structure.
|
|
37
37
|
|
|
38
|
-
## Approval Gate
|
|
38
|
+
## Approval Gate — HARD STOP
|
|
39
39
|
|
|
40
|
-
Planning and implementation are separate
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
Planning and implementation are **separate human-gated phases**. NEVER auto-proceed to implementation after planning or plan refinement.
|
|
41
|
+
|
|
42
|
+
- When the user says "approved" / "lgtm" / "looks good" to a **plan**: this means the plan is finalised. It does NOT mean "go implement it." Finalise the plan review, output _"Plan approved. Run `/jdi:implement-plan` when ready."_, then **STOP**.
|
|
43
|
+
- When the user provides refinement feedback on a plan, ONLY update the plan files in `.jdi/plans/`. Do NOT implement code.
|
|
44
|
+
- Implementation ONLY happens when the user explicitly requests it: "implement", "build", "execute", or `/jdi:implement-plan`.
|
|
45
|
+
|
|
46
|
+
## State Management
|
|
47
|
+
|
|
48
|
+
Do NOT manually edit `.jdi/config/state.yaml` for status transitions. Use the CLI instead:
|
|
49
|
+
|
|
50
|
+
- `npx jdi state plan-ready --plan-path "{path}" --plan-name "{name}"` — after plan creation
|
|
51
|
+
- `npx jdi state approved` — after plan approval
|
|
52
|
+
- `npx jdi state executing` — before implementation starts
|
|
53
|
+
- `npx jdi state complete` — after implementation finishes
|
|
54
|
+
- `npx jdi state advance-task {task-id}` — after each task completes
|
|
55
|
+
|
|
56
|
+
You may only append to `decisions`, `deviations`, or `blockers` arrays in state.yaml directly via `<JDI:StateUpdate />`.
|
|
57
|
+
|
|
58
|
+
## Self-Testing (Jedi development only)
|
|
59
|
+
|
|
60
|
+
If the current project is the Jedi framework itself (`@benzotti/jedi`), run `bun test` after modifying prompt builders, action commands, or framework files. This catches regressions in split format references, learnings inclusion, and framework invariants.
|