@benzotti/jedi 0.1.33 → 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
CHANGED
|
@@ -10084,17 +10084,55 @@ async function writeState(cwd, state) {
|
|
|
10084
10084
|
}
|
|
10085
10085
|
|
|
10086
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
|
+
}
|
|
10087
10100
|
async function transitionToPlanReady(cwd, planPath, planName) {
|
|
10088
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
|
+
}
|
|
10089
10118
|
state.position = {
|
|
10090
10119
|
...state.position,
|
|
10091
|
-
|
|
10120
|
+
...phase != null ? { phase } : {},
|
|
10121
|
+
plan: planNumber ?? planPath,
|
|
10092
10122
|
plan_name: planName,
|
|
10093
10123
|
status: "planning"
|
|
10094
10124
|
};
|
|
10095
10125
|
state.current_plan = {
|
|
10096
10126
|
...state.current_plan,
|
|
10097
|
-
path: planPath
|
|
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
|
|
10098
10136
|
};
|
|
10099
10137
|
state.review = {
|
|
10100
10138
|
...state.review,
|
|
@@ -10142,9 +10180,10 @@ async function advanceTask(cwd, completedTaskId) {
|
|
|
10142
10180
|
const nextIndex = completed.length;
|
|
10143
10181
|
state.current_plan.current_task_index = nextIndex < tasks.length ? nextIndex : null;
|
|
10144
10182
|
}
|
|
10145
|
-
if (state.progress) {
|
|
10146
|
-
state.progress
|
|
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 };
|
|
10147
10185
|
}
|
|
10186
|
+
state.progress.tasks_completed = (state.progress.tasks_completed ?? 0) + 1;
|
|
10148
10187
|
await updateSessionActivity(cwd, state);
|
|
10149
10188
|
}
|
|
10150
10189
|
async function updateSessionActivity(cwd, state) {
|
|
@@ -10327,15 +10366,15 @@ var statusCommand = defineCommand({
|
|
|
10327
10366
|
import { relative } from "path";
|
|
10328
10367
|
|
|
10329
10368
|
// src/utils/resolve-components.ts
|
|
10330
|
-
import { join as
|
|
10369
|
+
import { join as join10, basename } from "path";
|
|
10331
10370
|
import { homedir } from "os";
|
|
10332
10371
|
async function resolveComponents(cwd) {
|
|
10333
10372
|
const components = [];
|
|
10334
10373
|
const seen = new Set;
|
|
10335
10374
|
const sources = [
|
|
10336
|
-
{ dir:
|
|
10337
|
-
{ dir:
|
|
10338
|
-
{ 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" }
|
|
10339
10378
|
];
|
|
10340
10379
|
for (const { dir, source } of sources) {
|
|
10341
10380
|
try {
|
|
@@ -10344,7 +10383,7 @@ async function resolveComponents(cwd) {
|
|
|
10344
10383
|
const name = basename(file, ".md");
|
|
10345
10384
|
if (!seen.has(name)) {
|
|
10346
10385
|
seen.add(name);
|
|
10347
|
-
components.push({ name, path:
|
|
10386
|
+
components.push({ name, path: join10(dir, file), source });
|
|
10348
10387
|
}
|
|
10349
10388
|
}
|
|
10350
10389
|
} catch {}
|
|
@@ -10490,8 +10529,8 @@ Use --all to stage and commit all, or stage files manually.`);
|
|
|
10490
10529
|
});
|
|
10491
10530
|
|
|
10492
10531
|
// src/commands/pr.ts
|
|
10493
|
-
import { existsSync as
|
|
10494
|
-
import { join as
|
|
10532
|
+
import { existsSync as existsSync10 } from "fs";
|
|
10533
|
+
import { join as join11 } from "path";
|
|
10495
10534
|
async function hasGhCli() {
|
|
10496
10535
|
const { exitCode } = await exec(["which", "gh"]);
|
|
10497
10536
|
return exitCode === 0;
|
|
@@ -10542,8 +10581,8 @@ var prCommand = defineCommand({
|
|
|
10542
10581
|
let verificationChecks = [];
|
|
10543
10582
|
const planPath = state?.current_plan?.path;
|
|
10544
10583
|
if (planPath) {
|
|
10545
|
-
const fullPlanPath =
|
|
10546
|
-
if (
|
|
10584
|
+
const fullPlanPath = join11(cwd, planPath);
|
|
10585
|
+
if (existsSync10(fullPlanPath)) {
|
|
10547
10586
|
try {
|
|
10548
10587
|
const planContent = await Bun.file(fullPlanPath).text();
|
|
10549
10588
|
const nameMatch = planContent.match(/^#\s+(.+)/m);
|
|
@@ -10566,8 +10605,8 @@ ${taskLines.map((l2) => `- ${l2.split("|").slice(2, 3).join("").trim()}`).join(`
|
|
|
10566
10605
|
}
|
|
10567
10606
|
}
|
|
10568
10607
|
let template = "";
|
|
10569
|
-
const templatePath =
|
|
10570
|
-
if (
|
|
10608
|
+
const templatePath = join11(cwd, ".github", "pull_request_template.md");
|
|
10609
|
+
if (existsSync10(templatePath)) {
|
|
10571
10610
|
template = await Bun.file(templatePath).text();
|
|
10572
10611
|
}
|
|
10573
10612
|
const title = branch.replace(/^(feat|fix|chore|docs|refactor|test|ci)\//, "").replace(/[-_]/g, " ").replace(/^\w/, (c3) => c3.toUpperCase());
|
|
@@ -10863,7 +10902,7 @@ var quickCommand = defineCommand({
|
|
|
10863
10902
|
});
|
|
10864
10903
|
|
|
10865
10904
|
// src/commands/worktree.ts
|
|
10866
|
-
import { existsSync as
|
|
10905
|
+
import { existsSync as existsSync11 } from "fs";
|
|
10867
10906
|
function slugify(name) {
|
|
10868
10907
|
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
10869
10908
|
}
|
|
@@ -10897,7 +10936,7 @@ var worktreeCommand = defineCommand({
|
|
|
10897
10936
|
}
|
|
10898
10937
|
const slug = slugify(args.name);
|
|
10899
10938
|
const worktreePath = `${root}/.worktrees/${slug}`;
|
|
10900
|
-
if (
|
|
10939
|
+
if (existsSync11(worktreePath)) {
|
|
10901
10940
|
consola.error(`Worktree already exists at ${worktreePath}`);
|
|
10902
10941
|
return;
|
|
10903
10942
|
}
|
|
@@ -11063,7 +11102,7 @@ Specify a worktree name: jdi worktree-remove <name>`);
|
|
|
11063
11102
|
|
|
11064
11103
|
// src/commands/plan-review.ts
|
|
11065
11104
|
import { resolve as resolve9 } from "path";
|
|
11066
|
-
import { existsSync as
|
|
11105
|
+
import { existsSync as existsSync12 } from "fs";
|
|
11067
11106
|
function parsePlanSummary(content) {
|
|
11068
11107
|
const nameMatch = content.match(/^# .+?: (.+)$/m);
|
|
11069
11108
|
const name = nameMatch?.[1] ?? "Unknown";
|
|
@@ -11102,7 +11141,7 @@ var planReviewCommand = defineCommand({
|
|
|
11102
11141
|
consola.error("No plan found. Run `jdi plan` first.");
|
|
11103
11142
|
return;
|
|
11104
11143
|
}
|
|
11105
|
-
if (!
|
|
11144
|
+
if (!existsSync12(planPath)) {
|
|
11106
11145
|
consola.error(`Plan not found: ${planPath}`);
|
|
11107
11146
|
return;
|
|
11108
11147
|
}
|
|
@@ -11192,7 +11231,7 @@ Tasks (${tasks.length}):`);
|
|
|
11192
11231
|
|
|
11193
11232
|
// src/commands/plan-approve.ts
|
|
11194
11233
|
import { resolve as resolve10 } from "path";
|
|
11195
|
-
import { existsSync as
|
|
11234
|
+
import { existsSync as existsSync13 } from "fs";
|
|
11196
11235
|
var planApproveCommand = defineCommand({
|
|
11197
11236
|
meta: {
|
|
11198
11237
|
name: "plan-approve",
|
|
@@ -11221,7 +11260,7 @@ var planApproveCommand = defineCommand({
|
|
|
11221
11260
|
consola.error("No plan to approve. Run `jdi plan` first.");
|
|
11222
11261
|
return;
|
|
11223
11262
|
}
|
|
11224
|
-
if (!
|
|
11263
|
+
if (!existsSync13(planPath)) {
|
|
11225
11264
|
consola.error(`Plan not found: ${planPath}`);
|
|
11226
11265
|
return;
|
|
11227
11266
|
}
|
|
@@ -11698,16 +11737,16 @@ Say **\`Hey Jedi implement\`** when you're ready to go.`;
|
|
|
11698
11737
|
return;
|
|
11699
11738
|
}
|
|
11700
11739
|
if (intent.command === "ping") {
|
|
11701
|
-
const { existsSync:
|
|
11702
|
-
const { join:
|
|
11703
|
-
const frameworkExists =
|
|
11704
|
-
const claudeMdExists =
|
|
11705
|
-
const stateExists =
|
|
11706
|
-
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"));
|
|
11707
11746
|
let version = "unknown";
|
|
11708
11747
|
try {
|
|
11709
|
-
const pkgPath =
|
|
11710
|
-
if (
|
|
11748
|
+
const pkgPath = join13(cwd, "node_modules/@benzotti/jedi/package.json");
|
|
11749
|
+
if (existsSync14(pkgPath)) {
|
|
11711
11750
|
const pkg = JSON.parse(await Bun.file(pkgPath).text());
|
|
11712
11751
|
version = pkg.version;
|
|
11713
11752
|
}
|
|
@@ -11823,11 +11862,12 @@ Say **\`Hey Jedi implement\`** when you're ready to go.`;
|
|
|
11823
11862
|
`## Instructions`,
|
|
11824
11863
|
`Read state.yaml and existing plan files. Apply feedback incrementally \u2014 do not restart from scratch.`,
|
|
11825
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.`,
|
|
11826
11866
|
``,
|
|
11827
11867
|
`## Response Format (MANDATORY)`,
|
|
11828
|
-
`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:`,
|
|
11829
11869
|
`\`<details><summary>View full plan</summary> ... </details>\``,
|
|
11830
|
-
`
|
|
11870
|
+
`Show the tasks manifest table and brief summaries \u2014 full task details are in the task files.`,
|
|
11831
11871
|
`End with: "Any changes before implementation?"`
|
|
11832
11872
|
].join(`
|
|
11833
11873
|
`);
|
|
@@ -11860,8 +11900,14 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
11860
11900
|
`## Learnings`,
|
|
11861
11901
|
`Before planning, read .jdi/persistence/learnings.md and .jdi/framework/learnings/ if they exist. Apply any team preferences found.`,
|
|
11862
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
|
+
``,
|
|
11863
11909
|
`## Response Format`,
|
|
11864
|
-
`
|
|
11910
|
+
`After writing the split plan files, respond with EXACTLY this structure (no deviations, no meta-commentary):`,
|
|
11865
11911
|
``,
|
|
11866
11912
|
`1-2 sentence summary of the approach.`,
|
|
11867
11913
|
``,
|
|
@@ -11878,16 +11924,7 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
11878
11924
|
`|------|------|------|------|------|`,
|
|
11879
11925
|
`| T1 | {name} | {S|M|L} | auto | 1 |`,
|
|
11880
11926
|
``,
|
|
11881
|
-
|
|
11882
|
-
`**Objective:** {what this achieves}`,
|
|
11883
|
-
``,
|
|
11884
|
-
`**Steps:**`,
|
|
11885
|
-
`1. {step}`,
|
|
11886
|
-
``,
|
|
11887
|
-
`**Done when:** {completion criterion}`,
|
|
11888
|
-
``,
|
|
11889
|
-
`---`,
|
|
11890
|
-
`(repeat for each task)`,
|
|
11927
|
+
`(For each task, show a brief 1-2 line summary \u2014 full details are in the task files)`,
|
|
11891
11928
|
``,
|
|
11892
11929
|
`### Verification`,
|
|
11893
11930
|
`- [ ] {check 1}`,
|
|
@@ -12086,8 +12123,8 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
12086
12123
|
});
|
|
12087
12124
|
|
|
12088
12125
|
// src/commands/setup-action.ts
|
|
12089
|
-
import { join as
|
|
12090
|
-
import { existsSync as
|
|
12126
|
+
import { join as join13, dirname as dirname3 } from "path";
|
|
12127
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4 } from "fs";
|
|
12091
12128
|
var setupActionCommand = defineCommand({
|
|
12092
12129
|
meta: {
|
|
12093
12130
|
name: "setup-action",
|
|
@@ -12096,18 +12133,18 @@ var setupActionCommand = defineCommand({
|
|
|
12096
12133
|
args: {},
|
|
12097
12134
|
async run() {
|
|
12098
12135
|
const cwd = process.cwd();
|
|
12099
|
-
const workflowDest =
|
|
12100
|
-
if (
|
|
12136
|
+
const workflowDest = join13(cwd, ".github", "workflows", "jedi.yml");
|
|
12137
|
+
if (existsSync14(workflowDest)) {
|
|
12101
12138
|
consola.warn(`Workflow already exists at ${workflowDest}`);
|
|
12102
12139
|
consola.info("Skipping workflow copy. Delete it manually to regenerate.");
|
|
12103
12140
|
} else {
|
|
12104
|
-
const templatePath =
|
|
12105
|
-
if (!
|
|
12141
|
+
const templatePath = join13(import.meta.dir, "../action/workflow-template.yml");
|
|
12142
|
+
if (!existsSync14(templatePath)) {
|
|
12106
12143
|
consola.error("Workflow template not found. Ensure @benzotti/jedi is properly installed.");
|
|
12107
12144
|
process.exit(1);
|
|
12108
12145
|
}
|
|
12109
12146
|
const dir = dirname3(workflowDest);
|
|
12110
|
-
if (!
|
|
12147
|
+
if (!existsSync14(dir))
|
|
12111
12148
|
mkdirSync4(dir, { recursive: true });
|
|
12112
12149
|
const template = await Bun.file(templatePath).text();
|
|
12113
12150
|
await Bun.write(workflowDest, template);
|
|
@@ -12250,7 +12287,7 @@ var stateCommand = defineCommand({
|
|
|
12250
12287
|
// package.json
|
|
12251
12288
|
var package_default = {
|
|
12252
12289
|
name: "@benzotti/jedi",
|
|
12253
|
-
version: "0.1.
|
|
12290
|
+
version: "0.1.34",
|
|
12254
12291
|
description: "JDI - Context-efficient AI development framework for Claude Code",
|
|
12255
12292
|
type: "module",
|
|
12256
12293
|
bin: {
|
|
@@ -37,13 +37,17 @@ Before planning, ALWAYS:
|
|
|
37
37
|
|
|
38
38
|
You MUST write files using Write/Edit tools. Returning plan content as text is NOT acceptable.
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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)
|
|
43
45
|
3. `.jdi/config/variables.yaml`
|
|
44
46
|
4. `.jdi/ROADMAP.yaml` (add plan entry)
|
|
45
47
|
5. `.jdi/REQUIREMENTS.yaml` (add traceability)
|
|
46
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
|
+
|
|
47
51
|
**Do NOT manually edit `.jdi/config/state.yaml`** — state transitions are handled via CLI commands (e.g. `npx jdi state plan-ready`).
|
|
48
52
|
|
|
49
53
|
## File Naming
|
|
@@ -20,8 +20,8 @@ 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
|
|
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
25
|
7. **Update state via CLI** — do NOT manually edit state.yaml. Run:
|
|
26
26
|
```bash
|
|
27
27
|
npx jdi state plan-ready --plan-path ".jdi/plans/{plan-file}" --plan-name "{plan name}"
|
|
@@ -54,3 +54,7 @@ Do NOT manually edit `.jdi/config/state.yaml` for status transitions. Use the CL
|
|
|
54
54
|
- `npx jdi state advance-task {task-id}` — after each task completes
|
|
55
55
|
|
|
56
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.
|