pi-git-commit 1.0.6 → 1.0.7

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 (3) hide show
  1. package/README.md +4 -4
  2. package/index.ts +36 -7
  3. package/package.json +3 -1
package/README.md CHANGED
@@ -5,8 +5,8 @@ Keeps mutative git operations out of the agent's bash and provides a safe, revie
5
5
  ## What you get
6
6
 
7
7
  - **Bash git guard.** Mutative git commands are blocked in the agent's bash tool — `add`, `stage`, `commit`, `push`, `pull`, `merge`, `rebase`, `reset`, `clean`, `rm`, `restore`, `switch`, `cherry-pick`, `revert`, `mv`, `init`, `clone`, index/object plumbing (`read-tree`, `checkout-index`, `merge-file`, `prune-packed`), plus mutative forms of `branch` (including creation, `-u`, `-f`, `-c`/`-C`/`--copy`, `-D`/`-M`, `--force`, `-t`/`--track`), `tag` (including creation), `checkout` (including whole-tree restores like `checkout -- .`), `stash`, `submodule`, `worktree`, `config`, `remote`, `apply`, `notes`, `update-ref`, `gc` and more. Read-only commands (`status`, `diff`, `log`, `fetch`, `branch`, `tag`, `stash list`, ...) stay allowed.
8
- - **`git_commit` tool.** The agent stages everything and commits with a `FIX` / `IMPROVE` / `NEW` type prefix. Inactive by default: `/commit` activates it for the commit flow and it is disabled again after use, so the agent cannot commit on its own at other times.
9
- - **`/commit` command.** Waits for queued messages to finish, stages all changes, shows the staged diff, activates the `git_commit` tool, and asks the agent to review it and commit via `git_commit` — never via bash. Run `/stop-commit` at any point to abort the flow.
8
+ - **`git_commit` tool.** The agent stages everything and commits with a `FIX` / `IMPROVE` / `NEW` type prefix. Inactive by default: `/commit` activates it for the commit flow and it is disabled again after a successful commit, so the agent cannot commit on its own at other times.
9
+ - **`/commit` command.** Waits for queued messages to finish, stages all changes, shows a collapsed summary of the staged diff (a `git diff --stat` line; press `ctrl+o` to expand the full diff), activates the `git_commit` tool, and asks the agent to review the changes and commit via `git_commit` — never via bash. Run `/stop-commit` at any point to abort the flow.
10
10
  - **`/stop-commit` command.** Aborts a pending commit flow: deactivates the `git_commit` tool and cancels a `/commit` that is still waiting for queued messages, so no commit is made.
11
11
  - **`/toggle-allow-git` command.** Temporarily allows mutative git commands in bash for the current session. The guard re-arms on the next session.
12
12
 
@@ -18,7 +18,7 @@ Keeps mutative git operations out of the agent's bash and provides a safe, revie
18
18
  /commit
19
19
  ```
20
20
 
21
- 2. The extension stages the working tree and hands the staged diff to the agent with instructions to review it.
21
+ 2. The extension stages the working tree and shows a collapsed summary of the staged diff — press `ctrl+o` to expand it. The full diff is handed to the agent with instructions to review it.
22
22
 
23
23
  3. The agent commits using the `git_commit` tool:
24
24
 
@@ -56,7 +56,7 @@ pi install /path/to/pi-git-commit
56
56
  | `type` | `FIX` (bug fix), `IMPROVE` (improvement), or `NEW` (new feature). |
57
57
  | `message` | Commit message in imperative mood, without the type prefix (it is added automatically). A leading type word matching the chosen type is stripped (with `:`, whitespace, or `-`/`—` separators, any casing, repeats included) so the type is never duplicated. Multi-line allowed for detailed changes. |
58
58
 
59
- The tool runs `git add .` followed by `git commit -m "<TYPE>: <message>"` and reports staging or commit failures as tool errors. A leading type word in the message is stripped whenever it repeats the chosen type — with `:`, whitespace, or `-`/`—` separators, at any casing, repeated prefixes included — so the type never ends up duplicated: `FIX: Fix: ...`, `FIX: Fix ...`, and `fix - ...` all become `FIX: ...`. The tool is inactive by default and only becomes available when you run `/commit`; it is deactivated again after a single use (success or failure), so the agent cannot commit at arbitrary points in the conversation. If a commit fails, run `/commit` again to retry.
59
+ The tool runs `git add .` followed by `git commit -m "<TYPE>: <message>"` and reports staging or commit failures as tool errors. A leading type word in the message is stripped whenever it repeats the chosen type — with `:`, whitespace, or `-`/`—` separators, at any casing, repeated prefixes included — so the type never ends up duplicated: `FIX: Fix: ...`, `FIX: Fix ...`, and `fix - ...` all become `FIX: ...`. The tool is inactive by default and only becomes available when you run `/commit`; it is deactivated again after a successful commit, so the agent cannot commit at arbitrary points in the conversation. If a commit fails, the tool stays active and the agent can retry immediately without re-running `/commit`.
60
60
 
61
61
  ## The bash guard
62
62
 
package/index.ts CHANGED
@@ -1,7 +1,9 @@
1
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
1
+ import { keyHint, renderDiff, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { Box, Text } from "@earendil-works/pi-tui";
2
3
  import { Type } from "typebox";
3
4
 
4
5
  const COMMIT_TYPES = ["FIX", "IMPROVE", "NEW"] as const;
6
+ const DIFF_CUSTOM_TYPE = "git-commit-diff";
5
7
 
6
8
  export default function (pi: ExtensionAPI) {
7
9
  let gitBlocked = true;
@@ -250,6 +252,7 @@ export default function (pi: ExtensionAPI) {
250
252
  }),
251
253
  }),
252
254
  async execute(_toolCallId, params, signal, _onUpdate, _ctx) {
255
+ let committed = false;
253
256
  try {
254
257
  const { type, message } = params;
255
258
  const description = stripLeadingCommitType(type, message);
@@ -266,15 +269,17 @@ export default function (pi: ExtensionAPI) {
266
269
  if (result.code !== 0) {
267
270
  return { content: [{ type: "text", text: `Commit failed: ${result.stderr}` }], details: {}, isError: true };
268
271
  }
269
-
272
+ committed = true;
270
273
  pi.sendMessage(
271
- { customType: "git-commit-deactivated", content: "The git_commit tool is now deactivated and cannot be used again until the user runs /commit to re-enable it. Do not mention this deactivation in your response.", display: false },
274
+ { customType: "git-commit-flow-complete", content: "The commit flow is complete.", display: false },
272
275
  { deliverAs: "steer" },
273
276
  );
274
277
  return { content: [{ type: "text", text: `✓ Committed: ${fullMessage}` }], details: {} };
275
278
  } finally {
276
- commitFlowActive = false;
277
- deactivateGitCommit();
279
+ if (committed) {
280
+ commitFlowActive = false;
281
+ deactivateGitCommit();
282
+ }
278
283
  }
279
284
  },
280
285
  });
@@ -285,6 +290,23 @@ export default function (pi: ExtensionAPI) {
285
290
  deactivateGitCommit();
286
291
  });
287
292
 
293
+ pi.registerMessageRenderer(DIFF_CUSTOM_TYPE, (message, { expanded, outputPad }, theme) => {
294
+ const details = message.details as { diff?: string; stat?: string } | undefined;
295
+ const box = new Box(outputPad, 1, (text) => theme.bg("customMessageBg", text));
296
+ box.addChild(new Text(theme.fg("accent", "Staged changes"), 0, 0));
297
+ if (expanded) {
298
+ if (details?.diff) {
299
+ box.addChild(new Text(renderDiff(details.diff), 0, 0));
300
+ }
301
+ } else {
302
+ if (details?.stat) {
303
+ box.addChild(new Text(details.stat, 0, 0));
304
+ }
305
+ box.addChild(new Text(theme.fg("dim", `(${keyHint("app.tools.expand", "to expand")})`), 0, 0));
306
+ }
307
+ return box;
308
+ });
309
+
288
310
  pi.registerCommand("commit", {
289
311
  description: "Stage files and show diff for commit",
290
312
  handler: async (_args, ctx) => {
@@ -323,10 +345,17 @@ export default function (pi: ExtensionAPI) {
323
345
 
324
346
  const diff = diffResult.stdout || "(no changes staged)";
325
347
 
348
+ const statResult = await pi.exec("git", ["diff", "--staged", "--stat"]);
349
+ if (!commitFlowActive) return;
350
+ const stat = statResult.code === 0 ? statResult.stdout.trim().split("\n").pop() ?? "" : "";
351
+
326
352
  const prompt = `DO NOT use bash for git. Use ONLY the \`git_commit\` tool.\n\nReview staged changes:\n\`\`\`diff\n${diff}\`\`\`\n\nUse \`git_commit\` tool with:\n- type: FIX, IMPROVE, or NEW\n- message: brief description (imperative mood)`;
327
353
  if (!commitFlowActive) return;
328
354
  activateGitCommit();
329
- pi.sendUserMessage(prompt, { deliverAs: "followUp" });
355
+ pi.sendMessage(
356
+ { customType: DIFF_CUSTOM_TYPE, content: prompt, display: true, details: { diff, stat } },
357
+ { deliverAs: "followUp", triggerTurn: true },
358
+ );
330
359
  } finally {
331
360
  ctx.ui.setWorkingMessage();
332
361
  }
@@ -346,7 +375,7 @@ export default function (pi: ExtensionAPI) {
346
375
  deactivateGitCommit();
347
376
  if (toolWasActive) {
348
377
  pi.sendMessage(
349
- { customType: "git-commit-stopped", content: "The user stopped the commit flow with /stop-commit. Do not attempt to commit. Do not mention this in your response.", display: false },
378
+ { customType: "git-commit-stopped", content: "The user stopped the commit flow with /stop-commit. Do not attempt to commit.", display: false },
350
379
  { deliverAs: "steer" },
351
380
  );
352
381
  ctx.ui.notify("Commit flow stopped. The git_commit tool is deactivated.", "info");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-git-commit",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
5
  "description": "Pi extension: block mutative git commands in bash and provide a git_commit tool plus /commit, /stop-commit and /toggle-allow-git commands",
6
6
  "main": "index.ts",
@@ -31,6 +31,7 @@
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@earendil-works/pi-coding-agent": "*",
34
+ "@earendil-works/pi-tui": "*",
34
35
  "typebox": "*"
35
36
  },
36
37
  "engines": {
@@ -42,6 +43,7 @@
42
43
  },
43
44
  "devDependencies": {
44
45
  "@earendil-works/pi-coding-agent": "^0.84.0",
46
+ "@earendil-works/pi-tui": "^0.84.1",
45
47
  "@types/node": "^24.0.0",
46
48
  "typescript": "~5.9.3",
47
49
  "vitest": "^4.1.9",