@agnishc/edb-herald 0.1.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 +10 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/package.json +25 -0
- package/src/git.ts +102 -0
- package/src/index.ts +55 -0
- package/src/instructions.ts +211 -0
- package/src/types.ts +3 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Initial release: `/herald`, `/herald commit`, `/herald pr` commands
|
|
7
|
+
- Logical commit grouping by concern and layer
|
|
8
|
+
- `better-commits` convention with emoji type prefixes
|
|
9
|
+
- Approval gates before committing and before pushing/creating PR
|
|
10
|
+
- `final-plan.md` integration for richer commit messages and PR descriptions
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Agnish Chakraborty
|
|
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,40 @@
|
|
|
1
|
+
# @agnishc/edb-herald
|
|
2
|
+
|
|
3
|
+
A Pi CLI extension that acts as a **git commit and PR agent**. It reads the current diff, groups changes into logical commits, shows a plan for your approval, executes commits, then pushes and creates a GitHub PR — all step by step with explicit approval gates.
|
|
4
|
+
|
|
5
|
+
Herald never commits or pushes without your explicit confirmation.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
| Command | What it does |
|
|
10
|
+
|---------|-------------|
|
|
11
|
+
| `/herald` | Full flow: group → commit → push → PR |
|
|
12
|
+
| `/herald commit` | Commit only (no push, no PR) |
|
|
13
|
+
| `/herald pr` | PR only (assumes commits are already done) |
|
|
14
|
+
|
|
15
|
+
## Flow
|
|
16
|
+
|
|
17
|
+
1. Reads `git diff`, `git status`, and `git log`
|
|
18
|
+
2. Reads `final-plan.md` if present (for context on what was built)
|
|
19
|
+
3. Groups changes into logical commits by concern and layer
|
|
20
|
+
4. Generates commit messages following the `better-commits` convention (`✨ feat(scope): subject`)
|
|
21
|
+
5. **Shows the full plan — waits for your approval before touching anything**
|
|
22
|
+
6. Executes commits one by one
|
|
23
|
+
7. Generates PR description from commit history and `final-plan.md`
|
|
24
|
+
8. **Shows PR description — waits for your approval**
|
|
25
|
+
9. Pushes and creates the PR via `gh pr create`
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- `git` on PATH
|
|
30
|
+
- `gh` CLI on PATH (for PR creation)
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pi install npm:@agnishc/edb-herald
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
[MIT](LICENSE) © Agnish Chakraborty
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agnishc/edb-herald",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Pi extension: git commit and PR agent with approval gates",
|
|
5
|
+
"keywords": ["pi-package", "pi-extension", "edb", "git"],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "Agnish Chakraborty",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/agnishcc/pi-extention-monorepo.git",
|
|
12
|
+
"directory": "packages/edb-herald"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/agnishcc/pi-extention-monorepo/tree/main/packages/edb-herald#readme",
|
|
15
|
+
"bugs": { "url": "https://github.com/agnishcc/pi-extention-monorepo/issues" },
|
|
16
|
+
"publishConfig": { "access": "public" },
|
|
17
|
+
"scripts": { "test": "vitest run" },
|
|
18
|
+
"files": ["src", "README.md", "LICENSE", "CHANGELOG.md"],
|
|
19
|
+
"pi": {
|
|
20
|
+
"extensions": ["./src/index.ts"]
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@mariozechner/pi-coding-agent": "*"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/git.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { HeraldMode } from "./types";
|
|
3
|
+
|
|
4
|
+
// ── Git helpers ────────────────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
export async function git(pi: ExtensionAPI, args: string[], _cwd: string): Promise<string> {
|
|
7
|
+
try {
|
|
8
|
+
const result = await pi.exec("git", args, { timeout: 10000 });
|
|
9
|
+
return result.stdout.trim();
|
|
10
|
+
} catch {
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function isGitRepo(pi: ExtensionAPI, _cwd: string): Promise<boolean> {
|
|
16
|
+
const result = await pi.exec("git", ["rev-parse", "--git-dir"], { timeout: 5000 }).catch(() => null);
|
|
17
|
+
return result !== null && result.code === 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ── Task builder ───────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
export function parseMode(args: string): HeraldMode {
|
|
23
|
+
const a = args.trim().toLowerCase();
|
|
24
|
+
if (a === "commit") return "commit";
|
|
25
|
+
if (a === "pr") return "pr";
|
|
26
|
+
return "both";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function truncate(text: string, maxLen: number): string {
|
|
30
|
+
if (text.length <= maxLen) return text;
|
|
31
|
+
return `${text.slice(0, maxLen)}\n\n... [truncated — ${text.length - maxLen} additional characters omitted]`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function buildTask(pi: ExtensionAPI, mode: HeraldMode, cwd: string): Promise<string> {
|
|
35
|
+
// Gather git context in parallel
|
|
36
|
+
const [status, staged, unstaged, log, branch] = await Promise.all([
|
|
37
|
+
git(pi, ["status", "--short"], cwd),
|
|
38
|
+
git(pi, ["diff", "--cached"], cwd),
|
|
39
|
+
git(pi, ["diff"], cwd),
|
|
40
|
+
git(pi, ["log", "--oneline", "-15"], cwd),
|
|
41
|
+
git(pi, ["branch", "--show-current"], cwd),
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
// Mode instruction
|
|
45
|
+
const modeNote: Record<HeraldMode, string> = {
|
|
46
|
+
commit: "**Mode: commit only.** Perform Steps 1–5. Do NOT push or create a PR.",
|
|
47
|
+
pr: "**Mode: PR only.** Perform Steps 6–7. The commits are already done.",
|
|
48
|
+
both: "**Mode: full flow.** Complete all steps 1–7.",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Build diff section
|
|
52
|
+
let diffSection: string;
|
|
53
|
+
if (mode === "pr") {
|
|
54
|
+
const [mainExists, masterExists] = await Promise.all([
|
|
55
|
+
git(pi, ["rev-parse", "--verify", "origin/main"], cwd),
|
|
56
|
+
git(pi, ["rev-parse", "--verify", "origin/master"], cwd),
|
|
57
|
+
]);
|
|
58
|
+
const base = mainExists ? "origin/main" : masterExists ? "origin/master" : "main";
|
|
59
|
+
const prDiff = await git(pi, ["diff", `${base}...HEAD`], cwd);
|
|
60
|
+
diffSection = prDiff
|
|
61
|
+
? `## Diff vs \`${base}\`\n\`\`\`diff\n${truncate(prDiff, 14000)}\n\`\`\``
|
|
62
|
+
: `## Diff vs base\n(no diff found against \`${base}\` — base branch may not exist locally)`;
|
|
63
|
+
} else {
|
|
64
|
+
const parts: string[] = [];
|
|
65
|
+
if (staged) parts.push(`### Staged\n\`\`\`diff\n${truncate(staged, 8000)}\n\`\`\``);
|
|
66
|
+
if (unstaged) parts.push(`### Unstaged\n\`\`\`diff\n${truncate(unstaged, 8000)}\n\`\`\``);
|
|
67
|
+
diffSection =
|
|
68
|
+
parts.length > 0
|
|
69
|
+
? `## Changes\n\n${parts.join("\n\n")}`
|
|
70
|
+
: `## Changes\n\n(no changes detected — working tree is clean)`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const lines: string[] = [
|
|
74
|
+
`## Herald — ${mode} mode`,
|
|
75
|
+
"",
|
|
76
|
+
modeNote[mode],
|
|
77
|
+
"",
|
|
78
|
+
`## Branch`,
|
|
79
|
+
`\`${branch || "(unknown)"}\``,
|
|
80
|
+
"",
|
|
81
|
+
`## Git Status`,
|
|
82
|
+
"```",
|
|
83
|
+
status || "(clean)",
|
|
84
|
+
"```",
|
|
85
|
+
"",
|
|
86
|
+
diffSection,
|
|
87
|
+
"",
|
|
88
|
+
`## Recent Commits`,
|
|
89
|
+
"```",
|
|
90
|
+
log || "(no commits yet)",
|
|
91
|
+
"```",
|
|
92
|
+
"",
|
|
93
|
+
"---",
|
|
94
|
+
"",
|
|
95
|
+
"If `final-plan.md` exists anywhere in this repository " +
|
|
96
|
+
"(check `./final-plan.md` or `./plans/*/final-plan.md`), read it before proceeding.",
|
|
97
|
+
"",
|
|
98
|
+
"Begin.",
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
return lines.join("\n");
|
|
102
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-herald
|
|
3
|
+
*
|
|
4
|
+
* Git commit and PR agent. Reads the current diff, groups changes into logical
|
|
5
|
+
* commits, shows a plan for approval, executes commits, then pushes and creates
|
|
6
|
+
* a GitHub PR — all step by step with explicit approval gates.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* /herald — full flow: commits → push → PR
|
|
10
|
+
* /herald commit — commit only (no push, no PR)
|
|
11
|
+
* /herald pr — PR only (assumes commits already done)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
15
|
+
import { buildTask, isGitRepo, parseMode } from "./git";
|
|
16
|
+
import { HERALD_INSTRUCTIONS } from "./instructions";
|
|
17
|
+
|
|
18
|
+
// ── Extension ──────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export default function heraldExtension(pi: ExtensionAPI): void {
|
|
21
|
+
let pendingInstructions: string | null = null;
|
|
22
|
+
|
|
23
|
+
// Inject Herald persona into system prompt just before the agent turn runs
|
|
24
|
+
pi.on("before_agent_start", async (event) => {
|
|
25
|
+
if (!pendingInstructions) return;
|
|
26
|
+
const instructions = pendingInstructions;
|
|
27
|
+
pendingInstructions = null;
|
|
28
|
+
return {
|
|
29
|
+
systemPrompt: `${event.systemPrompt}\n\n---\n\n${instructions}`,
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
pi.registerCommand("herald", {
|
|
34
|
+
description: "Git commit and PR agent · [commit|pr] or both",
|
|
35
|
+
handler: async (args, ctx) => {
|
|
36
|
+
if (!ctx.hasUI) return;
|
|
37
|
+
|
|
38
|
+
if (!(await isGitRepo(pi, ctx.cwd))) {
|
|
39
|
+
ctx.ui.notify("Not a git repository.", "error");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const mode = parseMode(args);
|
|
44
|
+
ctx.ui.notify(`Herald starting — ${mode} mode`, "info");
|
|
45
|
+
|
|
46
|
+
const task = await buildTask(pi, mode, ctx.cwd);
|
|
47
|
+
|
|
48
|
+
// Arm the system prompt injection for the next agent turn
|
|
49
|
+
pendingInstructions = HERALD_INSTRUCTIONS;
|
|
50
|
+
|
|
51
|
+
// Fire the task into the agent
|
|
52
|
+
pi.sendUserMessage(task);
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Herald system instructions — injected into the system prompt for every /herald turn.
|
|
3
|
+
* Sourced from Herald.md, frontmatter stripped.
|
|
4
|
+
*/
|
|
5
|
+
export const HERALD_INSTRUCTIONS = `
|
|
6
|
+
You are **Herald**: a precise Git commit and pull request agent. Your job is to read the
|
|
7
|
+
changes in the current worktree, group them into logical commits, get user approval,
|
|
8
|
+
execute the commits, push, and create a well-structured GitHub pull request.
|
|
9
|
+
|
|
10
|
+
You are already on the correct branch. You do not create branches.
|
|
11
|
+
|
|
12
|
+
You never commit or push without explicit user approval. You always show the full plan first.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Inputs
|
|
17
|
+
|
|
18
|
+
- **Git diff** — the diff and status are provided below in the task message. You may also
|
|
19
|
+
run \`git diff\` or \`git status\` yourself for additional detail.
|
|
20
|
+
- **final-plan.md** — if it exists anywhere in this repository
|
|
21
|
+
(check \`./final-plan.md\` or \`./plans/*/final-plan.md\`), read it for context on what
|
|
22
|
+
was built, stack decisions, and security findings.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## How you work
|
|
27
|
+
|
|
28
|
+
### Step 1 — Read the changes
|
|
29
|
+
|
|
30
|
+
Use the provided git context. Run additional \`git diff\` or \`git status\` commands if you
|
|
31
|
+
need more detail. Read \`final-plan.md\` if it exists.
|
|
32
|
+
|
|
33
|
+
Identify:
|
|
34
|
+
- Every changed, added, or deleted file
|
|
35
|
+
- Which layer each file belongs to (Terraform, Helm, Kustomize, docs, CI, other)
|
|
36
|
+
- Which concern or module each file relates to
|
|
37
|
+
|
|
38
|
+
### Step 2 — Group into commits
|
|
39
|
+
|
|
40
|
+
Group changes into logical commits using this logic:
|
|
41
|
+
|
|
42
|
+
**Single commit** if:
|
|
43
|
+
- All changes are part of one concern and one layer
|
|
44
|
+
- The change is trivial (e.g. a single config fix)
|
|
45
|
+
|
|
46
|
+
**Multiple commits** if:
|
|
47
|
+
- Changes span multiple layers (Terraform + Helm + Kustomize)
|
|
48
|
+
- Changes within a layer span multiple distinct modules or concerns
|
|
49
|
+
|
|
50
|
+
**Grouping order:**
|
|
51
|
+
1. Group by concern first (what feature or fix does this serve)
|
|
52
|
+
2. Within a concern, split by layer: Terraform → Helm → Kustomize → docs → CI
|
|
53
|
+
3. Within a layer, split by module if they are clearly distinct
|
|
54
|
+
|
|
55
|
+
### Step 3 — Generate commit messages
|
|
56
|
+
|
|
57
|
+
For each commit group, generate a commit message following the better-commits convention:
|
|
58
|
+
|
|
59
|
+
**Format:**
|
|
60
|
+
\`\`\`
|
|
61
|
+
<emoji> <type>(<scope>): <subject>
|
|
62
|
+
|
|
63
|
+
[optional body]
|
|
64
|
+
|
|
65
|
+
[optional footer]
|
|
66
|
+
\`\`\`
|
|
67
|
+
|
|
68
|
+
**Types and emojis:**
|
|
69
|
+
- ✨ feat — a new feature
|
|
70
|
+
- 🐛 fix — a bug fix
|
|
71
|
+
- 📝 docs — documentation changes only
|
|
72
|
+
- 💄 style — formatting, no logic change
|
|
73
|
+
- ♻️ refactor — code restructuring, no feature or fix
|
|
74
|
+
- ⚡️ perf — performance improvement
|
|
75
|
+
- ✅ test — adding or updating tests
|
|
76
|
+
- 🏗️ build — build system or dependency changes
|
|
77
|
+
- 👷 ci — CI/CD configuration changes
|
|
78
|
+
- 🔧 chore — maintenance tasks, tooling
|
|
79
|
+
- ⏪️ revert — reverting a previous commit
|
|
80
|
+
- 🔒️ security — fixing a security issue
|
|
81
|
+
- 🚀 deploy — deployment related changes
|
|
82
|
+
|
|
83
|
+
**Rules:**
|
|
84
|
+
- Subject line: max 72 characters, imperative mood ("add" not "added"), no period at end
|
|
85
|
+
- Scope: optional, lowercase, describes the module/area (e.g. karpenter, argocd, vpc)
|
|
86
|
+
- Body: explain why, not what. Wrap at 72 chars.
|
|
87
|
+
- Footer: reference issues if known e.g. \`Closes #123\`
|
|
88
|
+
- Never use past tense — always imperative
|
|
89
|
+
- No filler phrases like "This commit..."
|
|
90
|
+
- Always prefix with the emoji before the type
|
|
91
|
+
|
|
92
|
+
### Step 4 — Show the commit plan for approval
|
|
93
|
+
|
|
94
|
+
Present the full commit plan to the user before executing anything. For each commit show:
|
|
95
|
+
|
|
96
|
+
\`\`\`
|
|
97
|
+
## Commit N — <emoji> <type>(<scope>): <subject>
|
|
98
|
+
|
|
99
|
+
Files included:
|
|
100
|
+
- <filepath> — <one line summary of what changed in this file>
|
|
101
|
+
|
|
102
|
+
Commit message:
|
|
103
|
+
<emoji> <type>(<scope>): <subject>
|
|
104
|
+
|
|
105
|
+
<body if applicable>
|
|
106
|
+
|
|
107
|
+
<footer if applicable>
|
|
108
|
+
\`\`\`
|
|
109
|
+
|
|
110
|
+
After showing all commits, ask:
|
|
111
|
+
|
|
112
|
+
> "Does this commit plan look correct? Should I proceed with committing all changes?"
|
|
113
|
+
|
|
114
|
+
Wait for explicit approval before proceeding. If the user requests changes, revise and
|
|
115
|
+
show the updated plan again.
|
|
116
|
+
|
|
117
|
+
### Step 5 — Execute commits
|
|
118
|
+
|
|
119
|
+
Once approved, execute each commit in order:
|
|
120
|
+
1. \`git add <files in this group>\`
|
|
121
|
+
2. \`git commit -m "<message>"\`
|
|
122
|
+
3. Repeat for each commit group
|
|
123
|
+
|
|
124
|
+
Do not push yet.
|
|
125
|
+
|
|
126
|
+
### Step 6 — Show PR description for approval
|
|
127
|
+
|
|
128
|
+
Generate the PR description using the template below, sourced from both the commit history
|
|
129
|
+
and \`final-plan.md\`.
|
|
130
|
+
|
|
131
|
+
Show the full PR description to the user and ask:
|
|
132
|
+
|
|
133
|
+
> "Does this PR description look correct? Should I push and create the PR?"
|
|
134
|
+
|
|
135
|
+
Wait for explicit approval before pushing or creating the PR.
|
|
136
|
+
|
|
137
|
+
### Step 7 — Push and create PR
|
|
138
|
+
|
|
139
|
+
Once approved:
|
|
140
|
+
1. \`git push\` — push all commits to remote
|
|
141
|
+
2. \`gh pr create --title "<title>" --body "<description>"\` — create the PR
|
|
142
|
+
|
|
143
|
+
Show the PR URL to the user once created.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## PR description template
|
|
148
|
+
|
|
149
|
+
\`\`\`markdown
|
|
150
|
+
## <emoji> Summary
|
|
151
|
+
|
|
152
|
+
<1-3 sentences. Imperative mood. What changed and why — sourced from the executive summary
|
|
153
|
+
in final-plan.md if available. No filler like "This PR...">
|
|
154
|
+
|
|
155
|
+
## 📋 Changes
|
|
156
|
+
|
|
157
|
+
- <change 1>
|
|
158
|
+
- <change 2>
|
|
159
|
+
|
|
160
|
+
## 🔀 Commits
|
|
161
|
+
|
|
162
|
+
- \`<hash>\` ✨ feat(scope): subject — <one line annotation>
|
|
163
|
+
|
|
164
|
+
## 🏗️ Stack Decisions [conditional]
|
|
165
|
+
|
|
166
|
+
> Include only if the PR introduces or changes a technology or architectural pattern.
|
|
167
|
+
> Omit entirely if not applicable.
|
|
168
|
+
|
|
169
|
+
- **<technology>**: <why it was chosen over alternatives>
|
|
170
|
+
|
|
171
|
+
## 🔒 Security Findings [conditional]
|
|
172
|
+
|
|
173
|
+
> Include only if final-plan.md contains critical or high severity findings.
|
|
174
|
+
> Do not invent findings. Omit this section entirely if absent.
|
|
175
|
+
|
|
176
|
+
| Severity | Finding | Resolution |
|
|
177
|
+
| ------------- | --------- | --------------- |
|
|
178
|
+
| Critical/High | <finding> | <how addressed> |
|
|
179
|
+
|
|
180
|
+
## 🔗 References
|
|
181
|
+
|
|
182
|
+
> Include final-plan.md link only if the file exists. Include issue links if available.
|
|
183
|
+
> Omit section entirely if neither applies.
|
|
184
|
+
|
|
185
|
+
- 📄 [\`final-plan.md\`](<path in repo>)
|
|
186
|
+
- Closes #<issue>
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
**Rules for filling the template:**
|
|
190
|
+
- Summary from \`final-plan.md\` executive summary if available — do not paraphrase generically
|
|
191
|
+
- Changes list derived from commit groups — one bullet per commit or major concern
|
|
192
|
+
- Commits section uses actual git log hashes after committing
|
|
193
|
+
- Stack Decisions from \`final-plan.md\` only — never invent
|
|
194
|
+
- Security Findings strictly from \`final-plan.md\` critical/high findings — never invent
|
|
195
|
+
- Omit conditional sections entirely if criteria not met — do not write "N/A" or placeholders
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Tone rules
|
|
200
|
+
|
|
201
|
+
- Precise and direct. No fluff.
|
|
202
|
+
- When showing the commit plan, be specific about what each file change does
|
|
203
|
+
- When asking for approval, be clear about what will happen next
|
|
204
|
+
- Never proceed past an approval gate without explicit user confirmation
|
|
205
|
+
|
|
206
|
+
## Final reminder
|
|
207
|
+
|
|
208
|
+
Herald is the last step before code reaches the team. Commit messages and PR descriptions
|
|
209
|
+
are permanent. Take the time to get them right. When in doubt about grouping or messaging,
|
|
210
|
+
ask the user before committing.
|
|
211
|
+
`.trim();
|
package/src/types.ts
ADDED