@benzotti/jedi 0.1.27 → 0.1.29

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.
@@ -30,6 +30,8 @@ on:
30
30
  types: [created]
31
31
  pull_request_review_comment:
32
32
  types: [created]
33
+ pull_request_review:
34
+ types: [submitted]
33
35
  push:
34
36
  branches: [main, master]
35
37
 
@@ -40,23 +42,30 @@ permissions:
40
42
  id-token: write
41
43
 
42
44
  jobs:
43
- # ── Triggered by "Hey Jedi" comments on issues/PRs ──
45
+ # ── Triggered by "Hey Jedi" comments on issues/PRs or PR reviews ──
44
46
  jedi:
45
47
  if: >-
46
- (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment')
47
- && contains(github.event.comment.body, 'Hey Jedi')
48
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, 'Hey Jedi'))
49
+ || (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, 'Hey Jedi'))
50
+ || (github.event_name == 'pull_request_review' && contains(github.event.review.body, 'Hey Jedi'))
48
51
  runs-on: ubuntu-latest
49
52
  steps:
50
- # Resolve the PR head branch for issue_comment events
51
- # (github.head_ref is only set on pull_request events, not issue_comment)
53
+ # Resolve the PR head branch
54
+ # - issue_comment: github.head_ref is empty, resolve via API
55
+ # - pull_request_review / pull_request_review_comment: github.event.pull_request.head.ref is available
52
56
  - name: Resolve PR branch
53
57
  id: pr
54
- if: github.event.issue.pull_request
55
58
  run: |
56
- PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }} --jq '{head_ref: .head.ref, head_sha: .head.sha}')
57
- echo "branch=$(echo "$PR_DATA" | jq -r .head_ref)" >> "$GITHUB_OUTPUT"
59
+ if [ -n "$PR_HEAD_REF" ]; then
60
+ echo "branch=$PR_HEAD_REF" >> "$GITHUB_OUTPUT"
61
+ elif [ -n "$PR_NUMBER" ]; then
62
+ BRANCH=$(gh api repos/${{ github.repository }}/pulls/$PR_NUMBER --jq '.head.ref')
63
+ echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
64
+ fi
58
65
  env:
59
66
  GH_TOKEN: ${{ github.token }}
67
+ PR_HEAD_REF: ${{ github.event.pull_request.head.ref || '' }}
68
+ PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number || '' }}
60
69
 
61
70
  - uses: actions/checkout@v4
62
71
  with:
@@ -118,20 +127,22 @@ jobs:
118
127
  run: bun install -g @anthropic-ai/claude-code
119
128
 
120
129
  # Run Jedi CLI directly — full pipeline with routing, agents, and comment posting
130
+ # IMPORTANT: All user input is passed via env vars to avoid shell injection
121
131
  - name: Run Jedi
122
132
  run: |
123
- COMMENT_BODY="${{ github.event.comment.body }}"
124
- COMMENT_ID="${{ github.event.comment.id }}"
125
- PR_NUMBER="${{ github.event.issue.pull_request && github.event.issue.number || '' }}"
126
- ISSUE_NUMBER="${{ github.event.issue.number }}"
127
-
128
- ARGS="--repo ${{ github.repository }}"
133
+ ARGS="--repo $REPO"
129
134
  [ -n "$COMMENT_ID" ] && ARGS="$ARGS --comment-id $COMMENT_ID"
130
135
  [ -n "$PR_NUMBER" ] && ARGS="$ARGS --pr-number $PR_NUMBER"
131
136
  [ -n "$ISSUE_NUMBER" ] && ARGS="$ARGS --issue-number $ISSUE_NUMBER"
132
137
 
133
138
  bunx @benzotti/jedi@latest action "$COMMENT_BODY" $ARGS
134
139
  env:
140
+ # Resolve comment body from whichever event type triggered this
141
+ COMMENT_BODY: ${{ github.event.comment.body || github.event.review.body || '' }}
142
+ COMMENT_ID: ${{ github.event.comment.id || github.event.review.id || '' }}
143
+ PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number || '' }}
144
+ ISSUE_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number || '' }}
145
+ REPO: ${{ github.repository }}
135
146
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
136
147
  CLICKUP_API_TOKEN: ${{ secrets.CLICKUP_API_TOKEN }}
137
148
  GH_TOKEN: ${{ github.token }}
package/dist/index.js CHANGED
@@ -11169,8 +11169,9 @@ function buildConversationContext(thread, currentCommentId) {
11169
11169
  }
11170
11170
  const previousJediRuns = jediSegments.filter((c3) => c3.isJedi).length;
11171
11171
  const isFollowUp = previousJediRuns > 0;
11172
+ const isPostImplementation = jediSegments.some((c3) => c3.isJedi && c3.body.includes("<sup>implement</sup>"));
11172
11173
  if (jediSegments.length === 0) {
11173
- return { history: "", previousJediRuns: 0, isFollowUp: false };
11174
+ return { history: "", previousJediRuns: 0, isFollowUp: false, isPostImplementation: false };
11174
11175
  }
11175
11176
  const lines = ["## Previous Conversation", ""];
11176
11177
  for (const comment of jediSegments) {
@@ -11186,7 +11187,7 @@ function buildConversationContext(thread, currentCommentId) {
11186
11187
  lines.push("");
11187
11188
  }
11188
11189
  return { history: lines.join(`
11189
- `), previousJediRuns, isFollowUp };
11190
+ `), previousJediRuns, isFollowUp, isPostImplementation };
11190
11191
  }
11191
11192
  var COMMAND_EMOJI = {
11192
11193
  plan: "\uD83D\uDD2E",
@@ -11321,13 +11322,15 @@ var actionCommand = defineCommand({
11321
11322
  const issueNumber = Number(args["pr-number"] ?? args["issue-number"] ?? 0);
11322
11323
  let conversationHistory = "";
11323
11324
  let isFollowUp = false;
11325
+ let isPostImplementation = false;
11324
11326
  if (repo && issueNumber) {
11325
11327
  const thread = await fetchCommentThread(repo, issueNumber);
11326
11328
  const context = buildConversationContext(thread, commentId ?? 0);
11327
11329
  conversationHistory = context.history;
11328
11330
  isFollowUp = context.isFollowUp;
11331
+ isPostImplementation = context.isPostImplementation;
11329
11332
  if (isFollowUp) {
11330
- consola.info(`Continuing conversation (${context.previousJediRuns} previous Jedi run(s))`);
11333
+ consola.info(`Continuing conversation (${context.previousJediRuns} previous Jedi run(s))${isPostImplementation ? " [post-implementation]" : ""}`);
11331
11334
  }
11332
11335
  }
11333
11336
  const intent = parseComment(args.comment, isFollowUp);
@@ -11339,7 +11342,7 @@ var actionCommand = defineCommand({
11339
11342
  if (repo && commentId) {
11340
11343
  await reactToComment(repo, commentId, "eyes").catch(() => {});
11341
11344
  }
11342
- const commandLabel = intent.isApproval ? "plan" : intent.isFeedback ? "feedback" : intent.command;
11345
+ const commandLabel = intent.isApproval ? "plan" : intent.isFeedback && isPostImplementation ? "implement" : intent.isFeedback ? "feedback" : intent.command;
11343
11346
  let placeholderCommentId = null;
11344
11347
  if (repo && issueNumber) {
11345
11348
  const thinkingBody = `<h3>\uD83E\uDDE0 Jedi <sup>thinking</sup></h3>
@@ -11349,6 +11352,49 @@ var actionCommand = defineCommand({
11349
11352
  _Working on it..._`;
11350
11353
  placeholderCommentId = await postGitHubComment(repo, issueNumber, thinkingBody).catch(() => null);
11351
11354
  }
11355
+ if (intent.isFeedback && intent.isApproval) {
11356
+ const { existsSync: existsSync13 } = await import("fs");
11357
+ const { join: join12 } = await import("path");
11358
+ const statePath = join12(cwd, ".jdi/config/state.yaml");
11359
+ if (existsSync13(statePath)) {
11360
+ const stateContent = await Bun.file(statePath).text();
11361
+ const now = new Date().toISOString();
11362
+ let updated = stateContent;
11363
+ if (/review\.status:/.test(updated)) {
11364
+ updated = updated.replace(/review\.status:\s*.+/, `review.status: approved`);
11365
+ } else {
11366
+ updated += `
11367
+ review.status: approved
11368
+ `;
11369
+ }
11370
+ if (/review\.approved_at:/.test(updated)) {
11371
+ updated = updated.replace(/review\.approved_at:\s*.+/, `review.approved_at: ${now}`);
11372
+ } else {
11373
+ updated += `review.approved_at: ${now}
11374
+ `;
11375
+ }
11376
+ await Bun.write(statePath, updated);
11377
+ }
11378
+ const approvalBody = `Plan approved and locked in.
11379
+
11380
+ Say **\`Hey Jedi implement\`** when you're ready to go.`;
11381
+ const finalBody = formatJediComment("plan", approvalBody);
11382
+ if (repo && placeholderCommentId) {
11383
+ await updateGitHubComment(repo, placeholderCommentId, finalBody).catch((err) => {
11384
+ consola.error("Failed to update approval comment:", err);
11385
+ });
11386
+ } else if (repo && issueNumber) {
11387
+ await postGitHubComment(repo, issueNumber, finalBody).catch((err) => {
11388
+ consola.error("Failed to post approval comment:", err);
11389
+ });
11390
+ } else {
11391
+ console.log(finalBody);
11392
+ }
11393
+ if (repo && commentId) {
11394
+ await reactToComment(repo, commentId, "+1").catch(() => {});
11395
+ }
11396
+ return;
11397
+ }
11352
11398
  if (intent.command === "ping") {
11353
11399
  const { existsSync: existsSync13 } = await import("fs");
11354
11400
  const { join: join12 } = await import("path");
@@ -11427,7 +11473,7 @@ _Working on it..._`;
11427
11473
  }
11428
11474
  const baseProtocol = resolve9(cwd, ".jdi/framework/components/meta/AgentBase.md");
11429
11475
  let prompt2;
11430
- if (intent.isFeedback && intent.isApproval) {
11476
+ if (intent.isFeedback && isPostImplementation) {
11431
11477
  prompt2 = [
11432
11478
  `Read ${baseProtocol} for the base agent protocol.`,
11433
11479
  ``,
@@ -11435,15 +11481,21 @@ _Working on it..._`;
11435
11481
  ``,
11436
11482
  conversationHistory,
11437
11483
  ``,
11438
- `## Plan Approved`,
11484
+ `## Feedback on Implementation`,
11439
11485
  `> ${intent.description}`,
11440
11486
  ``,
11441
- `The user has approved the plan. Finalise it:`,
11442
- `1. Read \`.jdi/config/state.yaml\` and update \`review.status\` to "approved" and \`review.approved_at\` to now`,
11443
- `2. Do NOT implement any code \u2014 approval and implementation are separate gates`,
11487
+ `## Instructions`,
11488
+ `The user is iterating on code that Jedi already implemented. Review the conversation above to understand what was built.`,
11489
+ `Be conversational \u2014 if the user asks a question, answer it first. Then make changes if needed.`,
11490
+ `Apply changes incrementally to the existing code \u2014 do not rewrite from scratch.`,
11444
11491
  ``,
11445
- `Respond with a short confirmation that the plan is approved and ready, then ask:`,
11446
- `"Say **implement** when you're ready to go."`
11492
+ `## Auto-Commit`,
11493
+ `You are already on the correct PR branch. Do NOT create new branches or switch branches.`,
11494
+ `After making changes:`,
11495
+ `1. \`git add\` only source files you changed (NOT .jdi/ or .claude/)`,
11496
+ `2. \`git commit -m "fix: ..."\` or \`git commit -m "refactor: ..."\` with a conventional commit message`,
11497
+ `3. \`git push\` (no -u, no origin, no branch name \u2014 just \`git push\`)`,
11498
+ `Present a summary of what you changed.`
11447
11499
  ].join(`
11448
11500
  `);
11449
11501
  } else if (intent.isFeedback) {
@@ -11681,7 +11733,7 @@ Use the ClickUp ticket above as the primary requirements source.` : ``,
11681
11733
  if (saved.codebaseIndexSaved)
11682
11734
  consola.info("Codebase index persisted to storage");
11683
11735
  if (repo && issueNumber) {
11684
- const actionLabel = intent.isApproval ? "implement" : intent.isFeedback ? "feedback" : intent.command;
11736
+ const actionLabel = intent.isFeedback ? "feedback" : intent.command;
11685
11737
  let commentBody;
11686
11738
  if (success && fullResponse) {
11687
11739
  commentBody = formatJediComment(actionLabel, fullResponse);
@@ -11770,7 +11822,7 @@ var setupActionCommand = defineCommand({
11770
11822
  // package.json
11771
11823
  var package_default = {
11772
11824
  name: "@benzotti/jedi",
11773
- version: "0.1.27",
11825
+ version: "0.1.29",
11774
11826
  description: "JDI - Context-efficient AI development framework for Claude Code",
11775
11827
  type: "module",
11776
11828
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@benzotti/jedi",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "JDI - Context-efficient AI development framework for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {