@benzotti/jedi 0.1.11 → 0.1.13
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
|
@@ -9218,6 +9218,7 @@ async function runMain(cmd, opts = {}) {
|
|
|
9218
9218
|
|
|
9219
9219
|
// src/commands/init.ts
|
|
9220
9220
|
import { join as join3 } from "path";
|
|
9221
|
+
import { existsSync as existsSync3 } from "fs";
|
|
9221
9222
|
|
|
9222
9223
|
// src/utils/detect-project.ts
|
|
9223
9224
|
import { existsSync } from "fs";
|
|
@@ -9249,7 +9250,7 @@ async function copyFrameworkFiles(cwd, projectType, force, ci = false) {
|
|
|
9249
9250
|
const frameworkDest = join2(cwd, ".jdi", "framework");
|
|
9250
9251
|
const glob = new Bun.Glob("**/*");
|
|
9251
9252
|
for await (const file of glob.scan({ cwd: frameworkDir })) {
|
|
9252
|
-
if (file.startsWith("adapters/")
|
|
9253
|
+
if (file.startsWith("adapters/"))
|
|
9253
9254
|
continue;
|
|
9254
9255
|
const src2 = join2(frameworkDir, file);
|
|
9255
9256
|
const dest = join2(frameworkDest, file);
|
|
@@ -9365,6 +9366,8 @@ Recognise natural language JDI intents and invoke the matching skill via the Ski
|
|
|
9365
9366
|
|
|
9366
9367
|
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.
|
|
9367
9368
|
|
|
9369
|
+
Planning and implementation are separate gates \u2014 NEVER auto-proceed to implementation after plan approval.
|
|
9370
|
+
|
|
9368
9371
|
## Iterative Refinement
|
|
9369
9372
|
|
|
9370
9373
|
After \`/jdi:create-plan\` or \`/jdi:implement-plan\` completes, the conversation continues naturally \u2014 no new command invocation needed. When the user provides feedback (e.g. "change task 2", "move this to a helper", "add error handling"), apply the changes directly, update state, and present the updated summary. When the user approves (e.g. "approved", "looks good", "lgtm"), finalise the review state. The conversation IS the feedback loop.
|
|
@@ -9387,6 +9390,8 @@ Recognise natural language JDI intents and invoke the matching skill via the Ski
|
|
|
9387
9390
|
|
|
9388
9391
|
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.
|
|
9389
9392
|
|
|
9393
|
+
Planning and implementation are separate gates \u2014 NEVER auto-proceed to implementation after plan approval.
|
|
9394
|
+
|
|
9390
9395
|
## Iterative Refinement
|
|
9391
9396
|
|
|
9392
9397
|
After \`/jdi:create-plan\` or \`/jdi:implement-plan\` completes, the conversation continues naturally \u2014 no new command invocation needed. When the user provides feedback (e.g. "change task 2", "move this to a helper", "add error handling"), apply the changes directly, update state, and present the updated summary. When the user approves (e.g. "approved", "looks good", "lgtm"), finalise the review state. The conversation IS the feedback loop.
|
|
@@ -9436,12 +9441,31 @@ var initCommand = defineCommand({
|
|
|
9436
9441
|
".jdi/codebase",
|
|
9437
9442
|
".jdi/reviews",
|
|
9438
9443
|
".jdi/config",
|
|
9439
|
-
".jdi/persistence"
|
|
9444
|
+
".jdi/persistence",
|
|
9445
|
+
".jdi/feedback"
|
|
9440
9446
|
];
|
|
9441
9447
|
for (const dir of dirs) {
|
|
9442
9448
|
await Bun.write(join3(cwd, dir, ".gitkeep"), "");
|
|
9443
9449
|
}
|
|
9444
9450
|
await copyFrameworkFiles(cwd, projectType, args.force, args.ci);
|
|
9451
|
+
const configFiles = ["state.yaml", "variables.yaml", "jdi-config.yaml"];
|
|
9452
|
+
for (const file of configFiles) {
|
|
9453
|
+
const src2 = join3(cwd, ".jdi", "framework", "config", file);
|
|
9454
|
+
const dest = join3(cwd, ".jdi", "config", file);
|
|
9455
|
+
if (existsSync3(src2) && (args.force || !existsSync3(dest))) {
|
|
9456
|
+
const content = await Bun.file(src2).text();
|
|
9457
|
+
await Bun.write(dest, content);
|
|
9458
|
+
}
|
|
9459
|
+
}
|
|
9460
|
+
const scaffoldFiles = ["PROJECT.yaml", "REQUIREMENTS.yaml", "ROADMAP.yaml"];
|
|
9461
|
+
for (const file of scaffoldFiles) {
|
|
9462
|
+
const src2 = join3(cwd, ".jdi", "framework", "templates", file);
|
|
9463
|
+
const dest = join3(cwd, ".jdi", file);
|
|
9464
|
+
if (existsSync3(src2) && !existsSync3(dest)) {
|
|
9465
|
+
const content = await Bun.file(src2).text();
|
|
9466
|
+
await Bun.write(dest, content);
|
|
9467
|
+
}
|
|
9468
|
+
}
|
|
9445
9469
|
if (args.storage || args["storage-path"]) {
|
|
9446
9470
|
const { parse, stringify } = await Promise.resolve().then(() => __toESM(require_dist(), 1));
|
|
9447
9471
|
const configPath = join3(cwd, ".jdi", "config", "jdi-config.yaml");
|
|
@@ -9483,10 +9507,10 @@ import { resolve as resolve2 } from "path";
|
|
|
9483
9507
|
// src/utils/adapter.ts
|
|
9484
9508
|
var import_yaml = __toESM(require_dist(), 1);
|
|
9485
9509
|
import { join as join4 } from "path";
|
|
9486
|
-
import { existsSync as
|
|
9510
|
+
import { existsSync as existsSync4 } from "fs";
|
|
9487
9511
|
async function readAdapter(cwd) {
|
|
9488
9512
|
const adapterPath = join4(cwd, ".jdi", "config", "adapter.yaml");
|
|
9489
|
-
if (!
|
|
9513
|
+
if (!existsSync4(adapterPath))
|
|
9490
9514
|
return null;
|
|
9491
9515
|
const content = await Bun.file(adapterPath).text();
|
|
9492
9516
|
return import_yaml.parse(content);
|
|
@@ -9619,11 +9643,11 @@ async function spawnClaude(prompt2, opts) {
|
|
|
9619
9643
|
// src/storage/index.ts
|
|
9620
9644
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
9621
9645
|
import { join as join6 } from "path";
|
|
9622
|
-
import { existsSync as
|
|
9646
|
+
import { existsSync as existsSync6 } from "fs";
|
|
9623
9647
|
|
|
9624
9648
|
// src/storage/fs-storage.ts
|
|
9625
9649
|
import { join as join5 } from "path";
|
|
9626
|
-
import { existsSync as
|
|
9650
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
9627
9651
|
|
|
9628
9652
|
class FsStorage {
|
|
9629
9653
|
basePath;
|
|
@@ -9632,12 +9656,12 @@ class FsStorage {
|
|
|
9632
9656
|
}
|
|
9633
9657
|
async load(key) {
|
|
9634
9658
|
const filePath = join5(this.basePath, `${key}.md`);
|
|
9635
|
-
if (!
|
|
9659
|
+
if (!existsSync5(filePath))
|
|
9636
9660
|
return null;
|
|
9637
9661
|
return Bun.file(filePath).text();
|
|
9638
9662
|
}
|
|
9639
9663
|
async save(key, content) {
|
|
9640
|
-
if (!
|
|
9664
|
+
if (!existsSync5(this.basePath)) {
|
|
9641
9665
|
mkdirSync2(this.basePath, { recursive: true });
|
|
9642
9666
|
}
|
|
9643
9667
|
const filePath = join5(this.basePath, `${key}.md`);
|
|
@@ -9651,7 +9675,7 @@ async function createStorage(cwd, config) {
|
|
|
9651
9675
|
let basePath = config?.basePath;
|
|
9652
9676
|
if (!config?.adapter && !config?.basePath) {
|
|
9653
9677
|
const configPath = join6(cwd, ".jdi", "config", "jdi-config.yaml");
|
|
9654
|
-
if (
|
|
9678
|
+
if (existsSync6(configPath)) {
|
|
9655
9679
|
const content = await Bun.file(configPath).text();
|
|
9656
9680
|
const parsed = import_yaml2.parse(content);
|
|
9657
9681
|
if (parsed?.storage?.adapter)
|
|
@@ -9665,7 +9689,7 @@ async function createStorage(cwd, config) {
|
|
|
9665
9689
|
return new FsStorage(resolvedPath);
|
|
9666
9690
|
}
|
|
9667
9691
|
const adapterPath = join6(cwd, adapter);
|
|
9668
|
-
if (!
|
|
9692
|
+
if (!existsSync6(adapterPath)) {
|
|
9669
9693
|
throw new Error(`Storage adapter not found: ${adapterPath}
|
|
9670
9694
|
` + `Set storage.adapter in .jdi/config/jdi-config.yaml to "fs" or a path to a custom adapter module.`);
|
|
9671
9695
|
}
|
|
@@ -9689,14 +9713,14 @@ async function createStorage(cwd, config) {
|
|
|
9689
9713
|
|
|
9690
9714
|
// src/utils/storage-lifecycle.ts
|
|
9691
9715
|
import { join as join7 } from "path";
|
|
9692
|
-
import { existsSync as
|
|
9716
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
9693
9717
|
async function loadPersistedState(cwd, storage) {
|
|
9694
9718
|
let learningsPath = null;
|
|
9695
9719
|
let codebaseIndexPath = null;
|
|
9696
9720
|
const learnings = await storage.load("learnings");
|
|
9697
9721
|
if (learnings) {
|
|
9698
9722
|
const dir = join7(cwd, ".jdi", "framework", "learnings");
|
|
9699
|
-
if (!
|
|
9723
|
+
if (!existsSync7(dir))
|
|
9700
9724
|
mkdirSync3(dir, { recursive: true });
|
|
9701
9725
|
learningsPath = join7(dir, "_consolidated.md");
|
|
9702
9726
|
await Bun.write(learningsPath, learnings);
|
|
@@ -9704,7 +9728,7 @@ async function loadPersistedState(cwd, storage) {
|
|
|
9704
9728
|
const codebaseIndex = await storage.load("codebase-index");
|
|
9705
9729
|
if (codebaseIndex) {
|
|
9706
9730
|
const dir = join7(cwd, ".jdi", "codebase");
|
|
9707
|
-
if (!
|
|
9731
|
+
if (!existsSync7(dir))
|
|
9708
9732
|
mkdirSync3(dir, { recursive: true });
|
|
9709
9733
|
codebaseIndexPath = join7(dir, "INDEX.md");
|
|
9710
9734
|
await Bun.write(codebaseIndexPath, codebaseIndex);
|
|
@@ -9715,7 +9739,7 @@ async function savePersistedState(cwd, storage) {
|
|
|
9715
9739
|
let learningsSaved = false;
|
|
9716
9740
|
let codebaseIndexSaved = false;
|
|
9717
9741
|
const learningsDir = join7(cwd, ".jdi", "framework", "learnings");
|
|
9718
|
-
if (
|
|
9742
|
+
if (existsSync7(learningsDir)) {
|
|
9719
9743
|
const merged = await mergeLearningFiles(learningsDir);
|
|
9720
9744
|
if (merged) {
|
|
9721
9745
|
await storage.save("learnings", merged);
|
|
@@ -9723,7 +9747,7 @@ async function savePersistedState(cwd, storage) {
|
|
|
9723
9747
|
}
|
|
9724
9748
|
}
|
|
9725
9749
|
const indexPath = join7(cwd, ".jdi", "codebase", "INDEX.md");
|
|
9726
|
-
if (
|
|
9750
|
+
if (existsSync7(indexPath)) {
|
|
9727
9751
|
const content = await Bun.file(indexPath).text();
|
|
9728
9752
|
if (content.trim()) {
|
|
9729
9753
|
await storage.save("codebase-index", content);
|
|
@@ -9737,7 +9761,7 @@ async function mergeLearningFiles(dir) {
|
|
|
9737
9761
|
const sections = [];
|
|
9738
9762
|
for (const category of categories) {
|
|
9739
9763
|
const filePath = join7(dir, `${category}.md`);
|
|
9740
|
-
if (!
|
|
9764
|
+
if (!existsSync7(filePath))
|
|
9741
9765
|
continue;
|
|
9742
9766
|
const content = await Bun.file(filePath).text();
|
|
9743
9767
|
const trimmed = content.trim();
|
|
@@ -9748,7 +9772,7 @@ async function mergeLearningFiles(dir) {
|
|
|
9748
9772
|
sections.push(trimmed);
|
|
9749
9773
|
}
|
|
9750
9774
|
const consolidatedPath = join7(dir, "_consolidated.md");
|
|
9751
|
-
if (
|
|
9775
|
+
if (existsSync7(consolidatedPath)) {
|
|
9752
9776
|
const content = await Bun.file(consolidatedPath).text();
|
|
9753
9777
|
const trimmed = content.trim();
|
|
9754
9778
|
if (trimmed && !sections.some((s2) => s2.includes(trimmed))) {
|
|
@@ -9832,10 +9856,10 @@ import { resolve as resolve3 } from "path";
|
|
|
9832
9856
|
// src/utils/state.ts
|
|
9833
9857
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
9834
9858
|
import { join as join8 } from "path";
|
|
9835
|
-
import { existsSync as
|
|
9859
|
+
import { existsSync as existsSync8 } from "fs";
|
|
9836
9860
|
async function readState(cwd) {
|
|
9837
9861
|
const statePath = join8(cwd, ".jdi", "config", "state.yaml");
|
|
9838
|
-
if (!
|
|
9862
|
+
if (!existsSync8(statePath))
|
|
9839
9863
|
return null;
|
|
9840
9864
|
const content = await Bun.file(statePath).text();
|
|
9841
9865
|
return import_yaml3.parse(content);
|
|
@@ -10152,7 +10176,7 @@ Use --all to stage and commit all, or stage files manually.`);
|
|
|
10152
10176
|
});
|
|
10153
10177
|
|
|
10154
10178
|
// src/commands/pr.ts
|
|
10155
|
-
import { existsSync as
|
|
10179
|
+
import { existsSync as existsSync9 } from "fs";
|
|
10156
10180
|
import { join as join10 } from "path";
|
|
10157
10181
|
async function hasGhCli() {
|
|
10158
10182
|
const { exitCode } = await exec(["which", "gh"]);
|
|
@@ -10204,7 +10228,7 @@ var prCommand = defineCommand({
|
|
|
10204
10228
|
**Plan:** ${state.position.plan_name}` : "";
|
|
10205
10229
|
let template = "";
|
|
10206
10230
|
const templatePath = join10(cwd, ".github", "pull_request_template.md");
|
|
10207
|
-
if (
|
|
10231
|
+
if (existsSync9(templatePath)) {
|
|
10208
10232
|
template = await Bun.file(templatePath).text();
|
|
10209
10233
|
}
|
|
10210
10234
|
const title = branch.replace(/^(feat|fix|chore|docs|refactor|test|ci)\//, "").replace(/[-_]/g, " ").replace(/^\w/, (c3) => c3.toUpperCase());
|
|
@@ -10552,7 +10576,7 @@ var quickCommand = defineCommand({
|
|
|
10552
10576
|
});
|
|
10553
10577
|
|
|
10554
10578
|
// src/commands/worktree.ts
|
|
10555
|
-
import { existsSync as
|
|
10579
|
+
import { existsSync as existsSync10 } from "fs";
|
|
10556
10580
|
function slugify(name) {
|
|
10557
10581
|
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
10558
10582
|
}
|
|
@@ -10586,7 +10610,7 @@ var worktreeCommand = defineCommand({
|
|
|
10586
10610
|
}
|
|
10587
10611
|
const slug = slugify(args.name);
|
|
10588
10612
|
const worktreePath = `${root}/.worktrees/${slug}`;
|
|
10589
|
-
if (
|
|
10613
|
+
if (existsSync10(worktreePath)) {
|
|
10590
10614
|
consola.error(`Worktree already exists at ${worktreePath}`);
|
|
10591
10615
|
return;
|
|
10592
10616
|
}
|
|
@@ -10752,7 +10776,7 @@ Specify a worktree name: jdi worktree-remove <name>`);
|
|
|
10752
10776
|
|
|
10753
10777
|
// src/commands/plan-review.ts
|
|
10754
10778
|
import { resolve as resolve7 } from "path";
|
|
10755
|
-
import { existsSync as
|
|
10779
|
+
import { existsSync as existsSync11 } from "fs";
|
|
10756
10780
|
function parsePlanSummary(content) {
|
|
10757
10781
|
const nameMatch = content.match(/^# .+?: (.+)$/m);
|
|
10758
10782
|
const name = nameMatch?.[1] ?? "Unknown";
|
|
@@ -10791,7 +10815,7 @@ var planReviewCommand = defineCommand({
|
|
|
10791
10815
|
consola.error("No plan found. Run `jdi plan` first.");
|
|
10792
10816
|
return;
|
|
10793
10817
|
}
|
|
10794
|
-
if (!
|
|
10818
|
+
if (!existsSync11(planPath)) {
|
|
10795
10819
|
consola.error(`Plan not found: ${planPath}`);
|
|
10796
10820
|
return;
|
|
10797
10821
|
}
|
|
@@ -10881,7 +10905,7 @@ Tasks (${tasks.length}):`);
|
|
|
10881
10905
|
|
|
10882
10906
|
// src/commands/plan-approve.ts
|
|
10883
10907
|
import { resolve as resolve8 } from "path";
|
|
10884
|
-
import { existsSync as
|
|
10908
|
+
import { existsSync as existsSync12 } from "fs";
|
|
10885
10909
|
var planApproveCommand = defineCommand({
|
|
10886
10910
|
meta: {
|
|
10887
10911
|
name: "plan-approve",
|
|
@@ -10910,7 +10934,7 @@ var planApproveCommand = defineCommand({
|
|
|
10910
10934
|
consola.error("No plan to approve. Run `jdi plan` first.");
|
|
10911
10935
|
return;
|
|
10912
10936
|
}
|
|
10913
|
-
if (!
|
|
10937
|
+
if (!existsSync12(planPath)) {
|
|
10914
10938
|
consola.error(`Plan not found: ${planPath}`);
|
|
10915
10939
|
return;
|
|
10916
10940
|
}
|
|
@@ -11436,7 +11460,7 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
|
|
|
11436
11460
|
|
|
11437
11461
|
// src/commands/setup-action.ts
|
|
11438
11462
|
import { join as join12, dirname as dirname3 } from "path";
|
|
11439
|
-
import { existsSync as
|
|
11463
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync4 } from "fs";
|
|
11440
11464
|
var setupActionCommand = defineCommand({
|
|
11441
11465
|
meta: {
|
|
11442
11466
|
name: "setup-action",
|
|
@@ -11446,17 +11470,17 @@ var setupActionCommand = defineCommand({
|
|
|
11446
11470
|
async run() {
|
|
11447
11471
|
const cwd = process.cwd();
|
|
11448
11472
|
const workflowDest = join12(cwd, ".github", "workflows", "jedi.yml");
|
|
11449
|
-
if (
|
|
11473
|
+
if (existsSync13(workflowDest)) {
|
|
11450
11474
|
consola.warn(`Workflow already exists at ${workflowDest}`);
|
|
11451
11475
|
consola.info("Skipping workflow copy. Delete it manually to regenerate.");
|
|
11452
11476
|
} else {
|
|
11453
11477
|
const templatePath = join12(import.meta.dir, "../action/workflow-template.yml");
|
|
11454
|
-
if (!
|
|
11478
|
+
if (!existsSync13(templatePath)) {
|
|
11455
11479
|
consola.error("Workflow template not found. Ensure @benzotti/jedi is properly installed.");
|
|
11456
11480
|
process.exit(1);
|
|
11457
11481
|
}
|
|
11458
11482
|
const dir = dirname3(workflowDest);
|
|
11459
|
-
if (!
|
|
11483
|
+
if (!existsSync13(dir))
|
|
11460
11484
|
mkdirSync4(dir, { recursive: true });
|
|
11461
11485
|
const template = await Bun.file(templatePath).text();
|
|
11462
11486
|
await Bun.write(workflowDest, template);
|
|
@@ -11494,7 +11518,7 @@ var setupActionCommand = defineCommand({
|
|
|
11494
11518
|
// package.json
|
|
11495
11519
|
var package_default = {
|
|
11496
11520
|
name: "@benzotti/jedi",
|
|
11497
|
-
version: "0.1.
|
|
11521
|
+
version: "0.1.13",
|
|
11498
11522
|
description: "JDI - Context-efficient AI development framework for Claude Code",
|
|
11499
11523
|
type: "module",
|
|
11500
11524
|
bin: {
|
|
@@ -27,6 +27,6 @@ Create an implementation plan using a single planner agent (includes research).
|
|
|
27
27
|
9. **Present summary** (name, objective, task table, files) then ask: _"Provide feedback to refine, or say **approved** to finalise."_
|
|
28
28
|
10. **Review loop**: approval → update state to `"approved"`, confirm. Feedback → revise plan in-place, increment revision, re-present summary. Repeat until approved. This is natural conversation — no separate command needed.
|
|
29
29
|
|
|
30
|
-
Agent base (read FIRST for cache):
|
|
30
|
+
Agent base (read FIRST for cache): .jdi/framework/components/meta/AgentBase.md | Agent spec: .jdi/framework/agents/jdi-planner.md
|
|
31
31
|
|
|
32
32
|
Feature to plan: $ARGUMENTS
|
|
@@ -26,8 +26,8 @@ Execute a PLAN.md with complexity-based routing.
|
|
|
26
26
|
11. **Present summary** (tasks completed, files changed, verification results, deviations) then ask: _"Provide feedback to adjust, or say **approved** to finalise."_
|
|
27
27
|
12. **Review loop**: approval → update state to `"complete"`, suggest commit/PR. Feedback → apply code changes, run tests, increment revision, re-present. Repeat until approved. Natural conversation — no separate command needed.
|
|
28
28
|
|
|
29
|
-
Agent base (read FIRST for cache):
|
|
30
|
-
Orchestration:
|
|
29
|
+
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
|
|
30
|
+
Orchestration: .jdi/framework/components/meta/AgentTeamsOrchestration.md | Routing: .jdi/framework/components/meta/ComplexityRouter.md
|
|
31
31
|
|
|
32
32
|
When spawning agents, detect project type and include a `## Project Context` block (type, tech stack, quality gates, working directory) in the spawn prompt. This saves agents 2-3 discovery tool calls.
|
|
33
33
|
|
|
@@ -13,7 +13,7 @@ Initialise the JDI slash commands in the current project.
|
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
mkdir -p .claude/commands/jdi
|
|
16
|
-
mkdir -p .jdi/plans .jdi/research .jdi/config
|
|
16
|
+
mkdir -p .jdi/plans .jdi/research .jdi/codebase .jdi/reviews .jdi/config .jdi/persistence .jdi/feedback
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
### Step 2: Copy Command Stubs
|
|
@@ -27,6 +27,6 @@ Remove a git worktree and clean up all associated resources.
|
|
|
27
27
|
7. **Update state**: set `worktree.active: false`, clear `worktree.path`, `worktree.branch` in `.jdi/config/state.yaml`
|
|
28
28
|
8. **Report**: what was removed
|
|
29
29
|
|
|
30
|
-
Reference:
|
|
30
|
+
Reference: .jdi/framework/hooks/jdi-worktree-cleanup.md
|
|
31
31
|
|
|
32
32
|
Worktree to remove: $ARGUMENTS
|