pi-git-delegate 0.2.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ This project follows semantic versioning.
6
+
7
+ ## [0.2.0] - 2026-06-13
8
+
9
+ ### Added
10
+
11
+ - `git_diff_summary` typed tool — delegates `git diff` summarization to a subagent.
12
+ - `git_log_summary` typed tool — delegates `git log` digest generation to a subagent.
13
+ - `git_blame_summary` typed tool — delegates `git blame` contributor context to a subagent.
14
+ - `/git-delegate:configure` and `/git-delegate:status` commands for settings help.
15
+ - Removed template `skills/`, `prompts/`, and `themes/` resources to avoid Pi resource conflicts and invalid theme warnings.
16
+
17
+ ## [0.1.2] - 2026-06-04
18
+
19
+ ### Changed
20
+
21
+ - README and `docs/template-checklist.md` now follow the Pi OSS minimal-docs policy: `docs/` is optional, with explicit post-generation cleanup for template bootstrap docs.
22
+ - Template bootstrap docs (`github-template.md`, `repository-settings.md`, `typescript.md`) are labeled for delete-or-merge after setup.
23
+
24
+ ## [0.1.1] - 2026-06-01
25
+
26
+ ### Changed
27
+
28
+ - Publish workflow now supports npm publishing on merged package version bumps in addition to tags, releases, and manual dispatch.
29
+ - Publish workflow now installs a current npm CLI so npm Trusted Publishing OIDC is supported.
30
+ - CI and publish workflow commands no longer include literal trailing `\\n` text.
31
+
32
+ ## [0.1.0] - YYYY-MM-DD
33
+
34
+ ### Added
35
+
36
+ - Initial Pi package template.
37
+ - Example extension, Agent Skill, prompt, and theme.
38
+ - CI and npm Trusted Publishing workflow.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YOUR_NAME
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Pi Git Delegate
2
+
3
+ [![CI](https://github.com/eiei114/pi-git-delegate/actions/workflows/ci.yml/badge.svg)](https://github.com/eiei114/pi-git-delegate/actions/workflows/ci.yml)
4
+ [![Publish](https://github.com/eiei114/pi-git-delegate/actions/workflows/publish.yml/badge.svg)](https://github.com/eiei114/pi-git-delegate/actions/workflows/publish.yml)
5
+ [![npm version](https://img.shields.io/npm/v/pi-git-delegate.svg)](https://www.npmjs.com/package/pi-git-delegate)
6
+ [![npm downloads](https://img.shields.io/npm/dm/pi-git-delegate.svg)](https://www.npmjs.com/package/pi-git-delegate)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+ [![Pi package](https://img.shields.io/badge/pi-package-purple.svg)](https://pi.dev/packages)
9
+
10
+ > Delegate git operations (diff/log/blame) to cheaper models via subagents — keeping parent context clean and cutting costs.
11
+
12
+ ## What this is
13
+
14
+ Pi Git Delegate provides typed tools that internally delegate heavy git read operations (diff, log, blame) to subagents. The subagent processes the raw git output and returns only a concise summary to the parent session. This prevents large diffs from polluting the parent's context window and lets you route expensive operations to cheaper models.
15
+
16
+ ## When to delegate
17
+
18
+ The cost leverage principle: **delegate only when input is large and output is small.**
19
+
20
+ | Operation | Delegation | Why |
21
+ |---|---|---|
22
+ | `git diff` (→ summary) | ✅ Delegate | Diff is large (1000+ tokens), summary is tiny |
23
+ | `git log` (→ changelog) | ✅ Delegate | Many commits → compact digest |
24
+ | `git blame` (→ context) | ✅ Delegate | Full blame is verbose; what matters is who/when/why |
25
+ | `git status` | ❌ Direct | Output is tiny; subagent overhead not worth it |
26
+ | `git push` / `git commit` | ❌ Direct | Write operations stay in parent for safety |
27
+
28
+ ## Features
29
+
30
+ - **`git_diff_summary`** — delegate `git diff` to a subagent, return a 1-3 sentence summary
31
+ - **`git_log_summary`** — delegate `git log` range, return a structured digest
32
+ - **`git_blame_summary`** — delegate `git blame`, return who changed what and why
33
+ - **Per-tool model routing** — set `provider` and `model` per tool in `.pi/settings.json` (`null` uses the session defaults)
34
+ - **`/git-delegate:configure`** — interactive help for writing the settings block
35
+ - **`/git-delegate:status`** — show current model routing and example JSON
36
+ - **Model override parameter** — override model per-call via tool parameter
37
+ - **Fallback to current model** — no config needed; uses the parent session model
38
+ - **Write guard** — no write operations exposed as tools
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pi install npm:pi-git-delegate
44
+ ```
45
+
46
+ Install locally (project-scoped):
47
+
48
+ ```bash
49
+ pi install npm:pi-git-delegate -l
50
+ ```
51
+
52
+ Try without installing:
53
+
54
+ ```bash
55
+ pi -e .
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ Once installed, the tools are available automatically. Pi calls them via `pi list`.
61
+
62
+ ### Configure model per tool (optional)
63
+
64
+ Run in Pi:
65
+
66
+ ```txt
67
+ /git-delegate:configure
68
+ ```
69
+
70
+ This shows what each key does, prints a starter JSON block, and can save it to `.pi/settings.json` interactively.
71
+
72
+ Check the current routing anytime with:
73
+
74
+ ```txt
75
+ /git-delegate:status
76
+ ```
77
+
78
+ Manual example for `.pi/settings.json`:
79
+
80
+ ```json
81
+ {
82
+ "pi-git-delegate": {
83
+ "diff": { "provider": "anthropic", "model": "claude-3-5-haiku-latest" },
84
+ "log": { "provider": null, "model": null },
85
+ "blame": { "provider": null, "model": null }
86
+ }
87
+ }
88
+ ```
89
+
90
+ `null` means "use the current session provider/model".
91
+
92
+ ### Call a tool
93
+
94
+ ```txt
95
+ git_diff_summary({ref: "HEAD~3"})
96
+ → "feat: add avatar upload with resize (3 files, 2 commits)"
97
+
98
+ git_log_summary({range: "main..feature"})
99
+ → "3 commits: feat(avatar), fix(crop), chore(deps)"
100
+
101
+ git_blame_summary({path: "src/auth.ts"})
102
+ → "src/auth.ts: 3 authors, most recent by @alice (2026-06-01)"
103
+ ```
104
+
105
+ ## Package contents
106
+
107
+ | Path | Purpose |
108
+ |---|---|
109
+ | `extensions/` | Pi TypeScript extension entrypoints |
110
+ | `lib/` | Shared TypeScript helpers |
111
+ | `docs/` | Optional supporting docs |
112
+
113
+ ## Development
114
+
115
+ ```bash
116
+ npm install
117
+ npm run ci
118
+ ```
119
+
120
+ ## Release
121
+
122
+ This package is set up for npm Trusted Publishing, so no `NPM_TOKEN` is required.
123
+
124
+ ```bash
125
+ npm version patch
126
+ git push
127
+ ```
128
+
129
+ See [`docs/release.md`](docs/release.md) for setup details.
130
+
131
+ ## Docs
132
+
133
+ `docs/` is optional supporting documentation, not a fixed six-file set. README stays the GitHub/npm entrypoint; add `docs/*.md` only when they help users or maintainers.
134
+
135
+ - [`docs/examples.md`](docs/examples.md) — tool usage examples
136
+ - [`docs/release.md`](docs/release.md) — Trusted Publishing details (README Release summarizes the flow)
137
+
138
+ ## Security
139
+
140
+ Pi packages can execute code with your local permissions. Review extensions before installing third-party packages.
141
+
142
+ For vulnerability reporting, see [`SECURITY.md`](SECURITY.md).
143
+
144
+ ## Links
145
+
146
+ - npm: https://www.npmjs.com/package/pi-git-delegate
147
+ - GitHub: https://github.com/eiei114/pi-git-delegate
148
+ - Issues: https://github.com/eiei114/pi-git-delegate/issues
149
+
150
+ ## License
151
+
152
+ MIT\n
@@ -0,0 +1,50 @@
1
+ # Examples
2
+
3
+ Pi Git Delegate ships typed tools for delegating heavy git read operations to subagents.
4
+
5
+ ## Extension
6
+
7
+ `extensions/index.ts` registers:
8
+
9
+ - `git_diff_summary`
10
+ - `git_log_summary`
11
+ - `git_blame_summary`
12
+ - `/git-delegate:configure`
13
+ - `/git-delegate:status`
14
+
15
+ Try it locally:
16
+
17
+ ```bash
18
+ pi -e .
19
+ ```
20
+
21
+ Then call a tool from Pi:
22
+
23
+ ```txt
24
+ git_diff_summary({ref: "HEAD~3"})
25
+ git_log_summary({range: "HEAD~5..HEAD"})
26
+ git_blame_summary({path: "lib/config.ts"})
27
+ ```
28
+
29
+ ## Settings
30
+
31
+ Configure per-tool subagent models:
32
+
33
+ ```txt
34
+ /git-delegate:configure
35
+ /git-delegate:status
36
+ ```
37
+
38
+ Manual example for `.pi/settings.json`:
39
+
40
+ ```json
41
+ {
42
+ "pi-git-delegate": {
43
+ "diff": { "provider": "anthropic", "model": "claude-3-5-haiku-latest" },
44
+ "log": { "provider": null, "model": null },
45
+ "blame": { "provider": null, "model": null }
46
+ }
47
+ }
48
+ ```
49
+
50
+ `null` uses the current session provider/model.
@@ -0,0 +1,57 @@
1
+ # Release
2
+
3
+ This package uses npm Trusted Publishing with GitHub Actions OIDC.
4
+
5
+ Do not add `NPM_TOKEN` or long-lived npm tokens to GitHub Secrets.
6
+
7
+ ## One-time npm setup
8
+
9
+ On npmjs.com, configure Trusted Publishing for this package:
10
+
11
+ - Publisher: GitHub Actions
12
+ - Repository: this GitHub repository
13
+ - Workflow filename: `publish.yml`
14
+
15
+ ## Publish
16
+
17
+ ```bash
18
+ npm version patch
19
+ git push
20
+ ```
21
+
22
+ On `main`, `.github/workflows/auto-release.yml` checks `package.json` version. If `v<version>` does not exist yet, it creates the tag, creates the GitHub Release, then explicitly dispatches `.github/workflows/publish.yml` for that tag.
23
+
24
+ The `v*.*.*` tag also triggers `.github/workflows/publish.yml`, which runs CI and publishes to npm when tags are pushed manually.
25
+ Publishing also runs when a GitHub Release is published, and can be run manually from GitHub Actions with `workflow_dispatch`.
26
+
27
+ The workflow skips `name@version` if that exact package version already exists on npm.
28
+
29
+ ## Workflow guardrail
30
+
31
+ Do not ship a new Pi OSS package or version bump with only `package.json` changes.
32
+ The repository must include the release workflow pair:
33
+
34
+ - `.github/workflows/auto-release.yml` creates `v<version>` tags and GitHub Releases from `main` version bumps.
35
+ - `.github/workflows/publish.yml` publishes to npm through Trusted Publishing.
36
+
37
+ Important: tags or releases created by `GITHUB_TOKEN` do not reliably fan out into another workflow through normal `push.tags` or `release.published` triggers. The template keeps publishing reliable by having `auto-release.yml` explicitly dispatch `publish.yml` after creating the tag/release. If you change the release flow, keep one explicit handoff path: `workflow_dispatch` from auto-release, `repository_dispatch`, or `workflow_run` on the auto-release workflow.
38
+
39
+ ## GitHub Actions requirements
40
+
41
+ - `permissions: id-token: write`
42
+ - `permissions: actions: write` on auto-release so it can dispatch `publish.yml`
43
+ - `auto-release.yml` must call `gh workflow run publish.yml --ref "$TAG" -f ref="$TAG"`, or `publish.yml` must have an equivalent explicit handoff trigger such as `workflow_run`
44
+ - GitHub-hosted runner
45
+ - Node.js 24, so the release job uses a current npm CLI for Trusted Publishing
46
+ - No `NPM_TOKEN`
47
+ - `npm publish` from the configured workflow file
48
+
49
+ ## First release checklist
50
+
51
+ - [ ] `package.json` name is final
52
+ - [ ] `repository.url` points to the real GitHub repository
53
+ - [ ] npm Trusted Publisher is configured
54
+ - [ ] `npm run ci` passes
55
+ - [ ] `npm pack --dry-run` contains only intended files
56
+ - [ ] CHANGELOG.md has the release date
57
+
@@ -0,0 +1,144 @@
1
+ # Template Setup Checklist
2
+
3
+ このテンプレートから新しい Pi 拡張OSSを作った後に埋めること。
4
+
5
+ ## Recommended flow
6
+
7
+ - [ ] Vault project notes を `4_Project/<ProjectName>/` に作る
8
+ - [ ] `CONTEXT.md` / `README.md` / `ROADMAP.md` / `Docs/` / `Issues/` / `Progress/` を揃える
9
+ - [ ] PRD を `4_Project/<ProjectName>/Docs/` に置く
10
+ - [ ] approved issue を `4_Project/<ProjectName>/Issues/` に切る
11
+ - [ ] OSS repo 側で実装する
12
+ - [ ] `npm run ci` / `npm test` / `npm pack --dry-run` を通す
13
+ - [ ] release 後に Vault へ learnings / release notes を戻す
14
+
15
+ ## Repository
16
+
17
+ - [ ] GitHub repository name を決める
18
+ - [ ] GitHub About 欄を書く
19
+ - [ ] GitHub topics を設定する
20
+ - [ ] `pi`
21
+ - [ ] `pi-package`
22
+ - [ ] `agent-skill`
23
+ - [ ] `typescript`
24
+ - [ ] GitHub Settingsで `Template repository` をONにする
25
+ - [ ] Repository URL を `package.json` に反映する
26
+ - [ ] README の `OWNER/REPO` を実リポジトリに置き換える
27
+
28
+ ## Package metadata
29
+
30
+ - [ ] `package.json` の `name` を変更する
31
+ - [ ] `description` を書く
32
+ - [ ] `author` を入れる
33
+ - [ ] `repository.url` を埋める
34
+ - [ ] `bugs.url` を埋める
35
+ - [ ] `homepage` を埋める
36
+ - [ ] `keywords` を見直す
37
+ - [ ] `LICENSE` の年・名前を更新する
38
+
39
+ ## README placeholders
40
+
41
+ - [ ] `PACKAGE_DISPLAY_NAME` を置き換える
42
+ - [ ] `PACKAGE_NAME` を置き換える
43
+ - [ ] `OWNER/REPO` を置き換える
44
+ - [ ] one-line pitch を書く
45
+ - [ ] feature list を書く
46
+ - [ ] quick start command を実コマンドにする
47
+ - [ ] npm URL を確認する
48
+ - [ ] GitHub URL を確認する
49
+
50
+ ## Pi package manifest
51
+
52
+ - [ ] `pi.extensions` に公開する拡張だけを残す
53
+ - [ ] **extension のみで ship するなら** `pi.skills` / `pi.prompts` / `pi.themes` を `package.json` から削除する
54
+ - [ ] **extension のみで ship するなら** `skills/` / `prompts/` / `themes/` ディレクトリを削除する
55
+ - [ ] skill を出すなら `example-skill` を **package 固有名** にリネームする(例: `<pkg>-workflow`)
56
+ - [ ] prompt を出すなら `example.md` を **package 固有名** にリネームする(例: `<pkg>-summarize.md`)
57
+ - [ ] theme を出すなら built-in theme と同じ **全必須 color token** を入れる。未完成なら `themes/` ごと削除
58
+ - [ ] `package.json` の `files` から、削除した resource パスを外す
59
+ - [ ] skill を出さないなら `keywords` / GitHub topics から `agent-skill` を外す
60
+ - [ ] Pi 起動ログに `[Skill conflicts]` / `[Prompt conflicts]` / `[Theme conflicts]` が **自 package 分で出ない** ことを確認する
61
+
62
+ ## Documentation
63
+
64
+ `docs/` は固定6ファイル必須ではない。README を正とし、価値がある doc だけ残す。
65
+
66
+ ### Required root files (public)
67
+
68
+ - [ ] `README.md` — GitHub/npm の入口。Install / Quick start / Release / Security を含める
69
+ - [ ] `LICENSE`
70
+ - [ ] `SECURITY.md`
71
+ - [ ] `CHANGELOG.md`
72
+ - [ ] Release 手順が README と workflow で明確(Trusted Publishing 設定含む)
73
+
74
+ ### Recommended public docs (keep when useful)
75
+
76
+ - [ ] `docs/examples.md` — 例が README に載り切らないとき
77
+ - [ ] `docs/release.md` — Trusted Publishing や release 手順の詳細が README だけでは足りないとき
78
+ - [ ] `docs/usage.md` — 使い方が README に載り切らないとき(必要なら新規作成)
79
+
80
+ ### Optional maintainer docs
81
+
82
+ - [ ] `docs/template-checklist.md` — このファイル。成熟 repo では README からの主ナビにしない。不要なら削除可
83
+
84
+ ### Post-generation cleanup (delete or merge template setup docs)
85
+
86
+ テンプレート生成直後の bootstrap 用。プロジェクト固有の価値がなければ削除し、必要な内容は README / `docs/release.md` / `docs/examples.md` に統合する。
87
+
88
+ - [ ] `docs/github-template.md` を削除するか、固有の手順だけ README / Vault に移す
89
+ - [ ] `docs/repository-settings.md` を削除するか、About/topics など必要分だけ README に移す
90
+ - [ ] `docs/typescript.md` を削除するか、TypeScript 方針は README Development に要約する
91
+ - [ ] README の Docs 節から、削除したファイルへのリンクを外す
92
+ - [ ] `package.json` の `files` から、削除した `docs/` パスを外す(残す doc だけ明示する)
93
+
94
+ ## TypeScript
95
+
96
+ - [ ] `extensions/index.ts` を実装に合わせて更新する
97
+ - [ ] `extensions/hello.ts` が不要なら削除する
98
+ - [ ] 共通ロジックを `lib/` に切り出す
99
+ - [ ] `strict: true` を維持する
100
+ - [ ] custom tool parameters は TypeBox schema で定義する
101
+ - [ ] string choices は `StringEnum` helper を使う
102
+ - [ ] runtime dependency は `dependencies`、Pi提供packageは `peerDependencies` に置く
103
+ - [ ] `package.json.files` に公開対象だけを入れる
104
+ - [ ] 詳細はセットアップ中だけ `docs/typescript.md` を参照し、不要なら post-generation cleanup で削除
105
+
106
+ ## GitHub Template repo
107
+
108
+ - [ ] `gh repo create --template OWNER/pi-extension-template` で作成できることを確認する
109
+ - [ ] public/privateどちらの作成例もdocsに載せる(`docs/github-template.md` を残す場合)
110
+
111
+ ## CI / Release
112
+
113
+ - [ ] `npm run ci` が通る
114
+ - [ ] `npm pack --dry-run` が通る
115
+ - [ ] npm Trusted Publishing を設定する
116
+ - [ ] npm Trusted Publisher の workflow filename が `publish.yml` になっている
117
+ - [ ] `NPM_TOKEN` を使っていないことを確認する
118
+ - [ ] `auto-release.yml` が `main` の version bump から tag/release を作ることを確認する
119
+ - [ ] `publish.yml` が `workflow_dispatch` と `release.published` に対応していることを確認する
120
+ - [ ] 初回リリースで npm provenance が付いているか確認する
121
+
122
+ ### Workflow handoff guard
123
+
124
+ - [ ] `.github/workflows/auto-release.yml` exists before first release
125
+ - [ ] `.github/workflows/publish.yml` exists before first release
126
+ - [ ] `auto-release.yml` has `permissions: actions: write` and `contents: write`
127
+ - [ ] `publish.yml` has `permissions: id-token: write` for npm Trusted Publishing
128
+ - [ ] Auto release explicitly hands off to publish: `gh workflow run publish.yml --ref "$TAG" -f ref="$TAG"`, or `publish.yml` has an equivalent `workflow_run` / `repository_dispatch` trigger
129
+ - [ ] Do not rely only on `push.tags` or `release.published` when the tag/release is created by `GITHUB_TOKEN`; that can leave npm unchanged after merge
130
+
131
+ ## npm page
132
+
133
+ - [ ] npm package URL を README に追加する
134
+ - [ ] npm description が適切に表示されるか確認する
135
+ - [ ] provenance が付いているか確認する
136
+ - [ ] 不要なファイルが package に含まれていないか確認する(`npm pack --dry-run` で `docs/` の残し方も確認)
137
+
138
+ ## Before first release
139
+
140
+ - [ ] サンプルコードを実機 Pi でロードする
141
+ - [ ] `pi install git:github.com/OWNER/REPO` を試す
142
+ - [ ] `pi -e .` を試す
143
+ - [ ] README のコマンドがコピペで動くか確認する
144
+ - [ ] CHANGELOG に `0.1.0` を書く
@@ -0,0 +1,8 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { registerGitDelegateCommands } from "../lib/register-commands.ts";
3
+ import { registerGitDelegateTools } from "../lib/register-tools.ts";
4
+
5
+ export default function (pi: ExtensionAPI) {
6
+ registerGitDelegateCommands(pi);
7
+ registerGitDelegateTools(pi);
8
+ }
package/lib/config.ts ADDED
@@ -0,0 +1,122 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
4
+
5
+ export type GitDelegateToolName = "git_diff_summary" | "git_log_summary" | "git_blame_summary";
6
+ export type GitDelegateToolKey = "diff" | "log" | "blame";
7
+
8
+ export interface ModelRoute {
9
+ provider: string | null;
10
+ model: string | null;
11
+ }
12
+
13
+ export interface GitDelegateConfig {
14
+ diff: ModelRoute;
15
+ log: ModelRoute;
16
+ blame: ModelRoute;
17
+ }
18
+
19
+ export interface ResolvedSubagentRoute {
20
+ provider?: string;
21
+ model?: string;
22
+ }
23
+
24
+ export const NULL_MODEL_ROUTE: ModelRoute = {
25
+ provider: null,
26
+ model: null,
27
+ };
28
+
29
+ export const DEFAULT_GIT_DELEGATE_CONFIG: GitDelegateConfig = {
30
+ diff: { ...NULL_MODEL_ROUTE },
31
+ log: { ...NULL_MODEL_ROUTE },
32
+ blame: { ...NULL_MODEL_ROUTE },
33
+ };
34
+
35
+ const TOOL_CONFIG_KEYS: Record<GitDelegateToolName, GitDelegateToolKey> = {
36
+ git_diff_summary: "diff",
37
+ git_log_summary: "log",
38
+ git_blame_summary: "blame",
39
+ };
40
+
41
+ function isRecord(value: unknown): value is Record<string, unknown> {
42
+ return typeof value === "object" && value !== null && !Array.isArray(value);
43
+ }
44
+
45
+ function trimOrUndefined(value: string | null | undefined): string | undefined {
46
+ if (value === null || value === undefined) return undefined;
47
+ const trimmed = value.trim();
48
+ return trimmed ? trimmed : undefined;
49
+ }
50
+
51
+ function parseNullableString(value: unknown): string | null {
52
+ if (value === null || value === undefined) return null;
53
+ if (typeof value !== "string") return null;
54
+ const trimmed = value.trim();
55
+ return trimmed ? trimmed : null;
56
+ }
57
+
58
+ function parseRoute(value: unknown): ModelRoute {
59
+ if (!isRecord(value)) {
60
+ return { ...NULL_MODEL_ROUTE };
61
+ }
62
+
63
+ return {
64
+ provider: parseNullableString(value.provider),
65
+ model: parseNullableString(value.model),
66
+ };
67
+ }
68
+
69
+ function readSettingsFile(filePath: string): Record<string, unknown> | undefined {
70
+ if (!existsSync(filePath)) return undefined;
71
+ try {
72
+ const parsed = JSON.parse(readFileSync(filePath, "utf8")) as unknown;
73
+ return isRecord(parsed) ? parsed : undefined;
74
+ } catch {
75
+ return undefined;
76
+ }
77
+ }
78
+
79
+ function parseGitDelegateConfig(settings: Record<string, unknown> | undefined): GitDelegateConfig | undefined {
80
+ if (!settings) return undefined;
81
+ const raw = settings["pi-git-delegate"];
82
+ if (!isRecord(raw)) return undefined;
83
+
84
+ return {
85
+ diff: parseRoute(raw.diff),
86
+ log: parseRoute(raw.log),
87
+ blame: parseRoute(raw.blame),
88
+ };
89
+ }
90
+
91
+ export function loadGitDelegateConfig(cwd: string): GitDelegateConfig | undefined {
92
+ const projectSettings = readSettingsFile(join(cwd, ".pi", "settings.json"));
93
+ const projectConfig = parseGitDelegateConfig(projectSettings);
94
+ if (projectConfig !== undefined) return projectConfig;
95
+
96
+ const agentSettings = readSettingsFile(join(getAgentDir(), "settings.json"));
97
+ return parseGitDelegateConfig(agentSettings);
98
+ }
99
+
100
+ export function resolveSubagentRoute(
101
+ toolName: GitDelegateToolName,
102
+ config: GitDelegateConfig | undefined,
103
+ override?: { provider?: string; model?: string },
104
+ ): ResolvedSubagentRoute | undefined {
105
+ const overrideProvider = trimOrUndefined(override?.provider);
106
+ const overrideModel = trimOrUndefined(override?.model);
107
+ if (overrideProvider || overrideModel) {
108
+ return {
109
+ provider: overrideProvider,
110
+ model: overrideModel,
111
+ };
112
+ }
113
+
114
+ if (!config) return undefined;
115
+
116
+ const route = config[TOOL_CONFIG_KEYS[toolName]];
117
+ const provider = trimOrUndefined(route.provider);
118
+ const model = trimOrUndefined(route.model);
119
+ if (!provider && !model) return undefined;
120
+
121
+ return { provider, model };
122
+ }
@@ -0,0 +1,21 @@
1
+ import { spawnSync } from "node:child_process";
2
+
3
+ export interface GitRunResult {
4
+ stdout: string;
5
+ stderr: string;
6
+ status: number;
7
+ }
8
+
9
+ export function runGit(args: string[], cwd: string): GitRunResult {
10
+ const result = spawnSync("git", args, {
11
+ cwd,
12
+ encoding: "utf8",
13
+ maxBuffer: 10 * 1024 * 1024,
14
+ });
15
+
16
+ return {
17
+ stdout: (result.stdout ?? "").trim(),
18
+ stderr: (result.stderr ?? "").trim(),
19
+ status: result.status ?? 1,
20
+ };
21
+ }
package/lib/prompts.ts ADDED
@@ -0,0 +1,34 @@
1
+ export const DIFF_SUMMARY_PROMPT = `You are a git diff summarizer. Given a raw git diff output,
2
+ produce a concise summary in 1-3 sentences covering:
3
+ - What files changed
4
+ - The nature of the changes (feature, fix, refactor)
5
+ - Any notable patterns or risks
6
+
7
+ Do not output the diff back. Only output the summary.
8
+ Use no markdown formatting. One paragraph max.`;
9
+
10
+ export const LOG_SUMMARY_PROMPT = `You are a git log summarizer. Given a git log output with
11
+ commit hashes and messages, produce a concise digest in
12
+ 2-4 sentences covering:
13
+ - How many commits and their general theme
14
+ - The main types of changes (features, fixes, refactors)
15
+ - Any notable patterns
16
+
17
+ Do not output the raw log. Only output the summary.
18
+ Use no markdown formatting. Two paragraphs max.`;
19
+
20
+ export const BLAME_SUMMARY_PROMPT = `You are a git blame summarizer. Given a git blame output,
21
+ produce a concise summary in 2-3 sentences covering:
22
+ - Total number of contributors to this file
23
+ - Who made the most recent changes and when
24
+ - The general age of the file (new, actively maintained, stable)
25
+
26
+ Do not output the raw blame. Only output the summary.
27
+ Use no markdown formatting. Two paragraphs max.`;
28
+
29
+ export function buildSubagentPrompt(systemPrompt: string, gitOutput: string): string {
30
+ return `${systemPrompt}
31
+
32
+ Git output:
33
+ ${gitOutput}`;
34
+ }