@benzotti/jedi 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/dist/index.js +270 -73
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7676,6 +7676,69 @@ var require_public_api = __commonJS((exports) => {
7676
7676
  exports.stringify = stringify;
7677
7677
  });
7678
7678
 
7679
+ // src/utils/git.ts
7680
+ var exports_git = {};
7681
+ __export(exports_git, {
7682
+ gitStatus: () => gitStatus,
7683
+ gitRoot: () => gitRoot,
7684
+ gitMergeBase: () => gitMergeBase,
7685
+ gitLog: () => gitLog,
7686
+ gitDiffNames: () => gitDiffNames,
7687
+ gitDiff: () => gitDiff,
7688
+ gitBranch: () => gitBranch,
7689
+ exec: () => exec
7690
+ });
7691
+ async function exec(cmd, cwd) {
7692
+ const proc = Bun.spawn(cmd, {
7693
+ cwd: cwd ?? process.cwd(),
7694
+ stdout: "pipe",
7695
+ stderr: "pipe"
7696
+ });
7697
+ const stdout2 = await new Response(proc.stdout).text();
7698
+ const exitCode = await proc.exited;
7699
+ return { stdout: stdout2.trim(), exitCode };
7700
+ }
7701
+ async function gitDiff(staged) {
7702
+ const args = ["git", "diff"];
7703
+ if (staged)
7704
+ args.push("--cached");
7705
+ const { stdout: stdout2 } = await exec(args);
7706
+ return stdout2;
7707
+ }
7708
+ async function gitDiffNames(staged) {
7709
+ const args = ["git", "diff", "--name-only"];
7710
+ if (staged)
7711
+ args.push("--cached");
7712
+ const { stdout: stdout2 } = await exec(args);
7713
+ return stdout2 ? stdout2.split(`
7714
+ `) : [];
7715
+ }
7716
+ async function gitLog(range) {
7717
+ const args = ["git", "log", "--oneline"];
7718
+ if (range)
7719
+ args.push(range);
7720
+ else
7721
+ args.push("-20");
7722
+ const { stdout: stdout2 } = await exec(args);
7723
+ return stdout2;
7724
+ }
7725
+ async function gitBranch() {
7726
+ const { stdout: stdout2 } = await exec(["git", "rev-parse", "--abbrev-ref", "HEAD"]);
7727
+ return stdout2;
7728
+ }
7729
+ async function gitRoot() {
7730
+ const { stdout: stdout2 } = await exec(["git", "rev-parse", "--show-toplevel"]);
7731
+ return stdout2;
7732
+ }
7733
+ async function gitStatus() {
7734
+ const { stdout: stdout2 } = await exec(["git", "status", "--porcelain"]);
7735
+ return stdout2;
7736
+ }
7737
+ async function gitMergeBase(branch) {
7738
+ const { stdout: stdout2 } = await exec(["git", "merge-base", "HEAD", branch]);
7739
+ return stdout2;
7740
+ }
7741
+
7679
7742
  // node_modules/consola/dist/core.mjs
7680
7743
  var LogLevels = {
7681
7744
  silent: Number.NEGATIVE_INFINITY,
@@ -9292,11 +9355,135 @@ async function readAdapter(cwd) {
9292
9355
  return $parse(content);
9293
9356
  }
9294
9357
 
9358
+ // src/utils/claude.ts
9359
+ var PROMPT_LENGTH_THRESHOLD = 1e5;
9360
+ async function findClaude() {
9361
+ const path = Bun.which("claude");
9362
+ if (path)
9363
+ return path;
9364
+ const { exec: exec2 } = await Promise.resolve().then(() => exports_git);
9365
+ const { stdout: stdout2, exitCode } = await exec2(["which", "claude"]);
9366
+ if (exitCode === 0 && stdout2)
9367
+ return stdout2;
9368
+ throw new Error("Claude CLI not found. Install it from https://docs.anthropic.com/en/docs/claude-code");
9369
+ }
9370
+ var lastEventType = "";
9371
+ function formatStreamEvent(event) {
9372
+ if (event.type === "assistant" && event.message?.content) {
9373
+ const parts = [];
9374
+ for (const block of event.message.content) {
9375
+ if (block.type === "text" && block.text) {
9376
+ const prefix = lastEventType === "tool" ? `
9377
+ ` : "";
9378
+ parts.push(prefix + block.text.trim());
9379
+ lastEventType = "text";
9380
+ } else if (block.type === "tool_use") {
9381
+ const name = block.name ?? "tool";
9382
+ const input = block.input;
9383
+ let detail = "";
9384
+ if (input?.file_path) {
9385
+ const segments = input.file_path.split("/");
9386
+ detail = ` \u2192 ${segments.slice(-3).join("/")}`;
9387
+ } else if (name === "Bash" && input?.command) {
9388
+ detail = ` \u2192 ${input.command.slice(0, 60)}`;
9389
+ } else if (input?.pattern) {
9390
+ detail = ` \u2192 ${input.pattern}`;
9391
+ }
9392
+ parts.push(` \u26A1 ${name}${detail}`);
9393
+ lastEventType = "tool";
9394
+ }
9395
+ }
9396
+ if (parts.length > 0)
9397
+ return parts.join(`
9398
+ `) + `
9399
+ `;
9400
+ }
9401
+ if (event.type === "result" && event.subtype === "error_tool_result") {
9402
+ lastEventType = "error";
9403
+ return ` \u274C Tool error
9404
+ `;
9405
+ }
9406
+ return null;
9407
+ }
9408
+ async function spawnClaude(prompt2, opts) {
9409
+ const claudePath = await findClaude();
9410
+ const args = [
9411
+ claudePath,
9412
+ "-p",
9413
+ "--verbose",
9414
+ "--output-format",
9415
+ "stream-json",
9416
+ "--permission-mode",
9417
+ opts?.permissionMode ?? "acceptEdits"
9418
+ ];
9419
+ if (opts?.allowedTools) {
9420
+ for (const tool of opts.allowedTools) {
9421
+ args.push("--allowedTools", tool);
9422
+ }
9423
+ }
9424
+ if (opts?.model) {
9425
+ args.push("--model", opts.model);
9426
+ }
9427
+ const useStdin = prompt2.length >= PROMPT_LENGTH_THRESHOLD;
9428
+ if (!useStdin) {
9429
+ args.push(prompt2);
9430
+ }
9431
+ consola.start(`Launching Claude Code...
9432
+ `);
9433
+ const proc = Bun.spawn(args, {
9434
+ cwd: opts?.cwd ?? process.cwd(),
9435
+ stdout: "pipe",
9436
+ stderr: "inherit",
9437
+ stdin: useStdin ? "pipe" : "ignore"
9438
+ });
9439
+ if (useStdin) {
9440
+ proc.stdin.write(prompt2);
9441
+ proc.stdin.end();
9442
+ }
9443
+ const reader = proc.stdout.getReader();
9444
+ const decoder = new TextDecoder;
9445
+ let buffer = "";
9446
+ try {
9447
+ while (true) {
9448
+ const { done, value } = await reader.read();
9449
+ if (done)
9450
+ break;
9451
+ buffer += decoder.decode(value, { stream: true });
9452
+ const lines = buffer.split(`
9453
+ `);
9454
+ buffer = lines.pop() ?? "";
9455
+ for (const line of lines) {
9456
+ const trimmed = line.trim();
9457
+ if (!trimmed)
9458
+ continue;
9459
+ try {
9460
+ const event = JSON.parse(trimmed);
9461
+ const output = formatStreamEvent(event);
9462
+ if (output)
9463
+ process.stdout.write(output);
9464
+ } catch {}
9465
+ }
9466
+ }
9467
+ if (buffer.trim()) {
9468
+ try {
9469
+ const event = JSON.parse(buffer.trim());
9470
+ const output = formatStreamEvent(event);
9471
+ if (output)
9472
+ process.stdout.write(output);
9473
+ } catch {}
9474
+ }
9475
+ } catch {}
9476
+ const exitCode = await proc.exited;
9477
+ process.stdout.write(`
9478
+ `);
9479
+ return { exitCode };
9480
+ }
9481
+
9295
9482
  // src/commands/plan.ts
9296
9483
  var planCommand = defineCommand({
9297
9484
  meta: {
9298
9485
  name: "plan",
9299
- description: "Generate a planning prompt for Claude Code"
9486
+ description: "Plan a feature using Claude Code"
9300
9487
  },
9301
9488
  args: {
9302
9489
  description: {
@@ -9307,6 +9494,11 @@ var planCommand = defineCommand({
9307
9494
  output: {
9308
9495
  type: "string",
9309
9496
  description: "Write prompt to file instead of stdout"
9497
+ },
9498
+ print: {
9499
+ type: "boolean",
9500
+ description: "Print the prompt to stdout instead of executing",
9501
+ default: false
9310
9502
  }
9311
9503
  },
9312
9504
  async run({ args }) {
@@ -9336,29 +9528,57 @@ var planCommand = defineCommand({
9336
9528
  if (args.output) {
9337
9529
  await Bun.write(resolve2(cwd, args.output), prompt2);
9338
9530
  consola.success(`Prompt written to ${args.output}`);
9339
- } else {
9531
+ } else if (args.print) {
9340
9532
  console.log(prompt2);
9533
+ } else {
9534
+ const { exitCode } = await spawnClaude(prompt2, { cwd });
9535
+ if (exitCode !== 0) {
9536
+ consola.error(`Claude exited with code ${exitCode}`);
9537
+ process.exit(exitCode);
9538
+ }
9341
9539
  }
9342
9540
  }
9343
9541
  });
9344
9542
 
9345
9543
  // src/commands/implement.ts
9346
9544
  import { resolve as resolve3 } from "path";
9545
+
9546
+ // src/utils/state.ts
9547
+ import { join as join5 } from "path";
9548
+ import { existsSync as existsSync4 } from "fs";
9549
+ async function readState(cwd) {
9550
+ const statePath = join5(cwd, ".jdi", "config", "state.yaml");
9551
+ if (!existsSync4(statePath))
9552
+ return null;
9553
+ const content = await Bun.file(statePath).text();
9554
+ return $parse(content);
9555
+ }
9556
+ async function writeState(cwd, state) {
9557
+ const statePath = join5(cwd, ".jdi", "config", "state.yaml");
9558
+ await Bun.write(statePath, $stringify(state));
9559
+ }
9560
+
9561
+ // src/commands/implement.ts
9347
9562
  var implementCommand = defineCommand({
9348
9563
  meta: {
9349
9564
  name: "implement",
9350
- description: "Generate an implementation prompt for Claude Code"
9565
+ description: "Execute an implementation plan using Claude Code"
9351
9566
  },
9352
9567
  args: {
9353
9568
  plan: {
9354
9569
  type: "positional",
9355
- description: "Path to the PLAN.md file to execute",
9356
- required: true
9570
+ description: "Path to the PLAN.md file (auto-detected from state if omitted)",
9571
+ required: false
9357
9572
  },
9358
9573
  output: {
9359
9574
  type: "string",
9360
9575
  description: "Write prompt to file instead of stdout"
9361
9576
  },
9577
+ print: {
9578
+ type: "boolean",
9579
+ description: "Print the prompt to stdout instead of executing",
9580
+ default: false
9581
+ },
9362
9582
  team: {
9363
9583
  type: "boolean",
9364
9584
  description: "Force Agent Teams mode",
@@ -9372,6 +9592,16 @@ var implementCommand = defineCommand({
9372
9592
  },
9373
9593
  async run({ args }) {
9374
9594
  const cwd = process.cwd();
9595
+ let planPath = args.plan;
9596
+ if (!planPath) {
9597
+ const state = await readState(cwd);
9598
+ planPath = state?.current_plan?.path ?? null;
9599
+ if (!planPath) {
9600
+ consola.error("No plan specified and no current plan found in state. Run `jdi plan` first or provide a plan path.");
9601
+ process.exit(1);
9602
+ }
9603
+ consola.info(`Using current plan: ${planPath}`);
9604
+ }
9375
9605
  const baseProtocol = resolve3(cwd, ".jdi/framework/components/meta/AgentBase.md");
9376
9606
  const complexityRouter = resolve3(cwd, ".jdi/framework/components/meta/ComplexityRouter.md");
9377
9607
  const orchestration = resolve3(cwd, ".jdi/framework/components/meta/AgentTeamsOrchestration.md");
@@ -9394,7 +9624,7 @@ Override: --single (force single-agent mode)` : "";
9394
9624
  `- Working directory: ${cwd}`,
9395
9625
  ``,
9396
9626
  `## Task`,
9397
- `Execute implementation plan: ${resolve3(cwd, args.plan)}${overrideFlag}`,
9627
+ `Execute implementation plan: ${resolve3(cwd, planPath)}${overrideFlag}`,
9398
9628
  ``,
9399
9629
  `Follow the implement-plan orchestration:`,
9400
9630
  `1. Read codebase context (.jdi/codebase/SUMMARY.md if exists)`,
@@ -9410,27 +9640,18 @@ Override: --single (force single-agent mode)` : "";
9410
9640
  if (args.output) {
9411
9641
  await Bun.write(resolve3(cwd, args.output), prompt2);
9412
9642
  consola.success(`Prompt written to ${args.output}`);
9413
- } else {
9643
+ } else if (args.print) {
9414
9644
  console.log(prompt2);
9645
+ } else {
9646
+ const { exitCode } = await spawnClaude(prompt2, { cwd });
9647
+ if (exitCode !== 0) {
9648
+ consola.error(`Claude exited with code ${exitCode}`);
9649
+ process.exit(exitCode);
9650
+ }
9415
9651
  }
9416
9652
  }
9417
9653
  });
9418
9654
 
9419
- // src/utils/state.ts
9420
- import { join as join5 } from "path";
9421
- import { existsSync as existsSync4 } from "fs";
9422
- async function readState(cwd) {
9423
- const statePath = join5(cwd, ".jdi", "config", "state.yaml");
9424
- if (!existsSync4(statePath))
9425
- return null;
9426
- const content = await Bun.file(statePath).text();
9427
- return $parse(content);
9428
- }
9429
- async function writeState(cwd, state) {
9430
- const statePath = join5(cwd, ".jdi", "config", "state.yaml");
9431
- await Bun.write(statePath, $stringify(state));
9432
- }
9433
-
9434
9655
  // src/commands/status.ts
9435
9656
  var statusCommand = defineCommand({
9436
9657
  meta: {
@@ -9523,51 +9744,6 @@ var componentsCommand = defineCommand({
9523
9744
  }
9524
9745
  });
9525
9746
 
9526
- // src/utils/git.ts
9527
- async function exec(cmd, cwd) {
9528
- const proc = Bun.spawn(cmd, {
9529
- cwd: cwd ?? process.cwd(),
9530
- stdout: "pipe",
9531
- stderr: "pipe"
9532
- });
9533
- const stdout2 = await new Response(proc.stdout).text();
9534
- const exitCode = await proc.exited;
9535
- return { stdout: stdout2.trim(), exitCode };
9536
- }
9537
- async function gitDiffNames(staged) {
9538
- const args = ["git", "diff", "--name-only"];
9539
- if (staged)
9540
- args.push("--cached");
9541
- const { stdout: stdout2 } = await exec(args);
9542
- return stdout2 ? stdout2.split(`
9543
- `) : [];
9544
- }
9545
- async function gitLog(range) {
9546
- const args = ["git", "log", "--oneline"];
9547
- if (range)
9548
- args.push(range);
9549
- else
9550
- args.push("-20");
9551
- const { stdout: stdout2 } = await exec(args);
9552
- return stdout2;
9553
- }
9554
- async function gitBranch() {
9555
- const { stdout: stdout2 } = await exec(["git", "rev-parse", "--abbrev-ref", "HEAD"]);
9556
- return stdout2;
9557
- }
9558
- async function gitRoot() {
9559
- const { stdout: stdout2 } = await exec(["git", "rev-parse", "--show-toplevel"]);
9560
- return stdout2;
9561
- }
9562
- async function gitStatus() {
9563
- const { stdout: stdout2 } = await exec(["git", "status", "--porcelain"]);
9564
- return stdout2;
9565
- }
9566
- async function gitMergeBase(branch) {
9567
- const { stdout: stdout2 } = await exec(["git", "merge-base", "HEAD", branch]);
9568
- return stdout2;
9569
- }
9570
-
9571
9747
  // src/commands/commit.ts
9572
9748
  import { dirname as dirname2 } from "path";
9573
9749
  function detectScope(files) {
@@ -9791,7 +9967,7 @@ import { resolve as resolve5 } from "path";
9791
9967
  var reviewCommand = defineCommand({
9792
9968
  meta: {
9793
9969
  name: "review",
9794
- description: "Fetch PR diff and generate a structured review prompt"
9970
+ description: "Review a PR using Claude Code"
9795
9971
  },
9796
9972
  args: {
9797
9973
  pr: {
@@ -9802,6 +9978,11 @@ var reviewCommand = defineCommand({
9802
9978
  output: {
9803
9979
  type: "string",
9804
9980
  description: "Write prompt to file instead of stdout"
9981
+ },
9982
+ print: {
9983
+ type: "boolean",
9984
+ description: "Print the prompt to stdout instead of executing",
9985
+ default: false
9805
9986
  }
9806
9987
  },
9807
9988
  async run({ args }) {
@@ -9878,8 +10059,14 @@ ${data.body}` : ""
9878
10059
  if (args.output) {
9879
10060
  await Bun.write(resolve5(process.cwd(), args.output), prompt2);
9880
10061
  consola.success(`Review prompt written to ${args.output}`);
9881
- } else {
10062
+ } else if (args.print) {
9882
10063
  console.log(prompt2);
10064
+ } else {
10065
+ const { exitCode } = await spawnClaude(prompt2, { cwd: process.cwd() });
10066
+ if (exitCode !== 0) {
10067
+ consola.error(`Claude exited with code ${exitCode}`);
10068
+ process.exit(exitCode);
10069
+ }
9883
10070
  }
9884
10071
  }
9885
10072
  });
@@ -10013,7 +10200,7 @@ import { resolve as resolve6 } from "path";
10013
10200
  var quickCommand = defineCommand({
10014
10201
  meta: {
10015
10202
  name: "quick",
10016
- description: "Generate a focused change prompt for Claude Code"
10203
+ description: "Make a focused change using Claude Code"
10017
10204
  },
10018
10205
  args: {
10019
10206
  description: {
@@ -10024,6 +10211,11 @@ var quickCommand = defineCommand({
10024
10211
  output: {
10025
10212
  type: "string",
10026
10213
  description: "Write prompt to file instead of stdout"
10214
+ },
10215
+ print: {
10216
+ type: "boolean",
10217
+ description: "Print the prompt to stdout instead of executing",
10218
+ default: false
10027
10219
  }
10028
10220
  },
10029
10221
  async run({ args }) {
@@ -10057,8 +10249,14 @@ var quickCommand = defineCommand({
10057
10249
  if (args.output) {
10058
10250
  await Bun.write(resolve6(cwd, args.output), prompt2);
10059
10251
  consola.success(`Prompt written to ${args.output}`);
10060
- } else {
10252
+ } else if (args.print) {
10061
10253
  console.log(prompt2);
10254
+ } else {
10255
+ const { exitCode } = await spawnClaude(prompt2, { cwd });
10256
+ if (exitCode !== 0) {
10257
+ consola.error(`Claude exited with code ${exitCode}`);
10258
+ process.exit(exitCode);
10259
+ }
10062
10260
  }
10063
10261
  }
10064
10262
  });
@@ -10171,7 +10369,6 @@ var worktreeCommand = defineCommand({
10171
10369
  consola.info(` cd ${worktreePath}`);
10172
10370
  }
10173
10371
  });
10174
-
10175
10372
  // src/commands/worktree-remove.ts
10176
10373
  var worktreeRemoveCommand = defineCommand({
10177
10374
  meta: {
@@ -10450,7 +10647,7 @@ var planApproveCommand = defineCommand({
10450
10647
  // package.json
10451
10648
  var package_default = {
10452
10649
  name: "@benzotti/jedi",
10453
- version: "0.1.2",
10650
+ version: "0.1.3",
10454
10651
  description: "JDI - Context-efficient AI development framework for Claude Code",
10455
10652
  type: "module",
10456
10653
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benzotti/jedi",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "JDI - Context-efficient AI development framework for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {