@benzotti/jedi 0.1.14 → 0.1.16

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.
@@ -15,6 +15,7 @@
15
15
  # Hey Jedi review — Review the current PR
16
16
  # Hey Jedi feedback — Address PR review comments
17
17
  # Hey Jedi do <clickup-ticket-url> — Full flow: plan + implement from ticket
18
+ # Hey Jedi ping — Check framework status
18
19
  #
19
20
  # Conversation: Jedi supports back-and-forth iteration. After Jedi responds,
20
21
  # reply with feedback to refine, or say "approved" to finalise.
@@ -87,17 +88,28 @@ jobs:
87
88
  grep -qxF "$pattern" .git/info/exclude 2>/dev/null || echo "$pattern" >> .git/info/exclude
88
89
  done
89
90
 
90
- # Run Jedi via the official Claude Code Action (tag mode posts comments automatically)
91
- # NOTE: No 'prompt' input — Jedi instructions live in .claude/CLAUDE.md (written by bootstrap)
92
- # Using prompt would switch to agent mode which doesn't post comments back to the PR/issue
91
+ # Install Claude Code CLI (required by Jedi for AI invocations)
92
+ - name: Install Claude Code
93
+ run: bun install -g @anthropic-ai/claude-code
94
+
95
+ # Run Jedi CLI directly — full pipeline with routing, agents, and comment posting
93
96
  - name: Run Jedi
94
- uses: anthropics/claude-code-action@v1
95
- with:
96
- anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
97
- trigger_phrase: 'Hey Jedi'
98
- bot_name: 'jedi[bot]'
97
+ run: |
98
+ COMMENT_BODY="${{ github.event.comment.body }}"
99
+ COMMENT_ID="${{ github.event.comment.id }}"
100
+ PR_NUMBER="${{ github.event.issue.pull_request && github.event.issue.number || '' }}"
101
+ ISSUE_NUMBER="${{ github.event.issue.number }}"
102
+
103
+ ARGS="--repo ${{ github.repository }}"
104
+ [ -n "$COMMENT_ID" ] && ARGS="$ARGS --comment-id $COMMENT_ID"
105
+ [ -n "$PR_NUMBER" ] && ARGS="$ARGS --pr-number $PR_NUMBER"
106
+ [ -n "$ISSUE_NUMBER" ] && ARGS="$ARGS --issue-number $ISSUE_NUMBER"
107
+
108
+ bunx @benzotti/jedi@latest action "$COMMENT_BODY" $ARGS
99
109
  env:
110
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
100
111
  CLICKUP_API_TOKEN: ${{ secrets.CLICKUP_API_TOKEN }}
112
+ GH_TOKEN: ${{ github.token }}
101
113
 
102
114
  # Save Jedi state — framework, config, persistence all cached together
103
115
  - name: Save Jedi state
package/dist/index.js CHANGED
@@ -9604,6 +9604,7 @@ async function spawnClaude(prompt2, opts) {
9604
9604
  const reader = proc.stdout.getReader();
9605
9605
  const decoder = new TextDecoder;
9606
9606
  let buffer = "";
9607
+ let lastTextResponse = "";
9607
9608
  try {
9608
9609
  while (true) {
9609
9610
  const { done, value } = await reader.read();
@@ -9622,6 +9623,16 @@ async function spawnClaude(prompt2, opts) {
9622
9623
  const output = formatStreamEvent(event);
9623
9624
  if (output)
9624
9625
  process.stdout.write(output);
9626
+ if (event.type === "assistant" && event.message?.content) {
9627
+ for (const block of event.message.content) {
9628
+ if (block.type === "text" && block.text) {
9629
+ lastTextResponse = block.text;
9630
+ }
9631
+ }
9632
+ }
9633
+ if (event.type === "result" && event.result) {
9634
+ lastTextResponse = event.result;
9635
+ }
9625
9636
  } catch {}
9626
9637
  }
9627
9638
  }
@@ -9631,13 +9642,23 @@ async function spawnClaude(prompt2, opts) {
9631
9642
  const output = formatStreamEvent(event);
9632
9643
  if (output)
9633
9644
  process.stdout.write(output);
9645
+ if (event.type === "assistant" && event.message?.content) {
9646
+ for (const block of event.message.content) {
9647
+ if (block.type === "text" && block.text) {
9648
+ lastTextResponse = block.text;
9649
+ }
9650
+ }
9651
+ }
9652
+ if (event.type === "result" && event.result) {
9653
+ lastTextResponse = event.result;
9654
+ }
9634
9655
  } catch {}
9635
9656
  }
9636
9657
  } catch {}
9637
9658
  const exitCode = await proc.exited;
9638
9659
  process.stdout.write(`
9639
9660
  `);
9640
- return { exitCode };
9661
+ return { exitCode, response: lastTextResponse };
9641
9662
  }
9642
9663
 
9643
9664
  // src/storage/index.ts
@@ -11085,7 +11106,7 @@ async function fetchCommentThread(repo, issueNumber) {
11085
11106
  author: parsed.author,
11086
11107
  body: parsed.body,
11087
11108
  createdAt: parsed.createdAt,
11088
- isJedi: parsed.body.includes("Powered by [@benzotti/jedi]") || parsed.body.includes("Jedi plan") || parsed.body.includes("Jedi quick") || parsed.body.includes("Jedi implement")
11109
+ isJedi: parsed.body.includes("### \u2694\uFE0F Jedi")
11089
11110
  });
11090
11111
  } catch {}
11091
11112
  }
@@ -11126,21 +11147,19 @@ function buildConversationContext(thread, currentCommentId) {
11126
11147
  return { history: lines.join(`
11127
11148
  `), previousJediRuns, isFollowUp };
11128
11149
  }
11129
- function formatResultComment(command, success, summary) {
11130
- const status = success ? "Completed" : "Failed";
11131
- const icon = success ? "white_check_mark" : "x";
11150
+ function formatJediComment(response) {
11132
11151
  return [
11133
- `### :${icon}: Jedi ${command} \u2014 ${status}`,
11134
- ``,
11135
- `<details>`,
11136
- `<summary>Details</summary>`,
11152
+ `### \u2694\uFE0F Jedi`,
11137
11153
  ``,
11138
- summary,
11139
- ``,
11140
- `</details>`,
11154
+ response
11155
+ ].join(`
11156
+ `);
11157
+ }
11158
+ function formatErrorComment(command, summary) {
11159
+ return [
11160
+ `### \u2694\uFE0F Jedi`,
11141
11161
  ``,
11142
- `---`,
11143
- `_Powered by [@benzotti/jedi](https://github.com/zottiben/jedi)_`
11162
+ `**${command} failed.** ${summary}`
11144
11163
  ].join(`
11145
11164
  `);
11146
11165
  }
@@ -11165,6 +11184,9 @@ function parseComment(comment, isFollowUp) {
11165
11184
  const clickUpUrl = clickUpMatch ? clickUpMatch[1] : null;
11166
11185
  const description = body.replace(/(https?:\/\/[^\s]*clickup\.com\/t\/[a-z0-9]+)/i, "").replace(/\s+/g, " ").trim();
11167
11186
  const lower = body.toLowerCase();
11187
+ if (lower.startsWith("ping") || lower.startsWith("status")) {
11188
+ return { command: "ping", description: "", clickUpUrl: null, fullFlow: false, isFeedback: false };
11189
+ }
11168
11190
  if (lower.startsWith("plan ")) {
11169
11191
  return { command: "plan", description, clickUpUrl, fullFlow: false, isFeedback: false };
11170
11192
  }
@@ -11259,6 +11281,49 @@ var actionCommand = defineCommand({
11259
11281
  if (repo && commentId) {
11260
11282
  await reactToComment(repo, commentId, "eyes").catch(() => {});
11261
11283
  }
11284
+ if (intent.command === "ping") {
11285
+ const { existsSync: existsSync13 } = await import("fs");
11286
+ const { join: join12 } = await import("path");
11287
+ const frameworkExists = existsSync13(join12(cwd, ".jdi/framework"));
11288
+ const claudeMdExists = existsSync13(join12(cwd, ".claude/CLAUDE.md"));
11289
+ const stateExists = existsSync13(join12(cwd, ".jdi/config/state.yaml"));
11290
+ const learningsExists = existsSync13(join12(cwd, ".jdi/persistence/learnings.md"));
11291
+ let version = "unknown";
11292
+ try {
11293
+ const pkgPath = join12(cwd, "node_modules/@benzotti/jedi/package.json");
11294
+ if (existsSync13(pkgPath)) {
11295
+ const pkg = JSON.parse(await Bun.file(pkgPath).text());
11296
+ version = pkg.version;
11297
+ }
11298
+ } catch {}
11299
+ const statusBody = [
11300
+ `**Framework Status**`,
11301
+ ``,
11302
+ `| Component | Status |`,
11303
+ `|-----------|--------|`,
11304
+ `| Framework files | ${frameworkExists ? "found" : "missing"} |`,
11305
+ `| CLAUDE.md | ${claudeMdExists ? "found" : "missing"} |`,
11306
+ `| State config | ${stateExists ? "found" : "missing"} |`,
11307
+ `| Learnings | ${learningsExists ? "found" : "missing"} |`,
11308
+ `| Version | \`${version}\` |`
11309
+ ].join(`
11310
+ `);
11311
+ const lines = formatJediComment(statusBody).split(`
11312
+ `);
11313
+ if (repo && issueNumber) {
11314
+ await postGitHubComment(repo, issueNumber, lines.join(`
11315
+ `)).catch((err) => {
11316
+ consola.error("Failed to post ping comment:", err);
11317
+ });
11318
+ } else {
11319
+ console.log(lines.join(`
11320
+ `));
11321
+ }
11322
+ if (repo && commentId) {
11323
+ await reactToComment(repo, commentId, "+1").catch(() => {});
11324
+ }
11325
+ return;
11326
+ }
11262
11327
  const storage = await createStorage(cwd);
11263
11328
  const { learningsPath, codebaseIndexPath } = await loadPersistedState(cwd, storage);
11264
11329
  let ticketContext = "";
@@ -11401,11 +11466,13 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
11401
11466
  }
11402
11467
  }
11403
11468
  let success = true;
11469
+ let fullResponse = "";
11404
11470
  try {
11405
- const { exitCode } = await spawnClaude(prompt2, {
11471
+ const { exitCode, response } = await spawnClaude(prompt2, {
11406
11472
  cwd,
11407
11473
  permissionMode: "bypassPermissions"
11408
11474
  });
11475
+ fullResponse = response;
11409
11476
  if (exitCode !== 0) {
11410
11477
  success = false;
11411
11478
  consola.error(`Claude exited with code ${exitCode}`);
@@ -11431,6 +11498,13 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
11431
11498
  if (implResult.exitCode !== 0) {
11432
11499
  success = false;
11433
11500
  }
11501
+ if (implResult.response) {
11502
+ fullResponse += `
11503
+
11504
+ ---
11505
+
11506
+ ` + implResult.response;
11507
+ }
11434
11508
  }
11435
11509
  } catch (err) {
11436
11510
  success = false;
@@ -11443,8 +11517,14 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
11443
11517
  consola.info("Codebase index persisted to storage");
11444
11518
  if (repo && issueNumber) {
11445
11519
  const actionLabel = intent.isFeedback ? "feedback" : intent.command;
11446
- const summary = success ? `Executed \`${actionLabel}\` successfully.${saved.learningsSaved ? " Learnings updated." : ""}` : `Execution of \`${actionLabel}\` failed. Check workflow logs for details.`;
11447
- const commentBody = formatResultComment(actionLabel, success, summary);
11520
+ let commentBody;
11521
+ if (success && fullResponse) {
11522
+ commentBody = formatJediComment(fullResponse);
11523
+ } else if (!success) {
11524
+ commentBody = formatErrorComment(actionLabel, "Check workflow logs for details.");
11525
+ } else {
11526
+ commentBody = formatJediComment(`Executed \`${actionLabel}\` successfully.`);
11527
+ }
11448
11528
  await postGitHubComment(repo, issueNumber, commentBody).catch((err) => {
11449
11529
  consola.error("Failed to post result comment:", err);
11450
11530
  });
@@ -11508,6 +11588,7 @@ var setupActionCommand = defineCommand({
11508
11588
  " Hey Jedi do <clickup-ticket-url>",
11509
11589
  " Hey Jedi review",
11510
11590
  " Hey Jedi feedback",
11591
+ " Hey Jedi ping",
11511
11592
  "",
11512
11593
  "Conversation: Reply to Jedi with feedback to iterate,",
11513
11594
  "or say 'approved' to finalise."
@@ -11518,7 +11599,7 @@ var setupActionCommand = defineCommand({
11518
11599
  // package.json
11519
11600
  var package_default = {
11520
11601
  name: "@benzotti/jedi",
11521
- version: "0.1.14",
11602
+ version: "0.1.16",
11522
11603
  description: "JDI - Context-efficient AI development framework for Claude Code",
11523
11604
  type: "module",
11524
11605
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benzotti/jedi",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "JDI - Context-efficient AI development framework for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {