repo-agent-brief 0.3.0 → 0.4.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/README.md CHANGED
@@ -45,6 +45,7 @@ Options:
45
45
  - `--max-file-bytes N` — max bytes to read per context file. Default: `12000`.
46
46
  - `--no-snippets` — omit source snippets.
47
47
  - `--diff [ref]` — include changed files, insertions/deletions, and high-impact path warnings versus a git ref. Defaults to `HEAD` when no ref is provided.
48
+ - `--bundle [dir]` — write a durable handoff bundle with `brief.md`, `brief.json`, and `verification.md`. Default: `.agent-brief`.
48
49
  - `--fail-on-high-risk` — exit `2` if high-severity risk patterns are found.
49
50
 
50
51
  Examples:
@@ -53,6 +54,7 @@ Examples:
53
54
  agent-brief . > AGENT_BRIEF.md
54
55
  agent-brief ~/dev/my-app --format json
55
56
  agent-brief . --diff origin/main
57
+ agent-brief . --diff HEAD --bundle
56
58
  agent-brief . --fail-on-high-risk
57
59
  ```
58
60
 
@@ -79,6 +81,26 @@ Every brief now includes a `Suggested verification plan` section. It turns disco
79
81
 
80
82
  If you pass `--diff`, the plan gets sharper: docs-only changes downgrade expensive checks, source changes promote tests/typechecks, and CI/deploy/infra/lockfile changes add a manual high-impact-path review. If no test/lint/build commands are found, the plan calls that gap out plainly so the agent does not pretend verification happened.
81
83
 
84
+ ## Handoff bundles
85
+
86
+ For longer-running work, use `--bundle` to leave a stable artifact another agent or human can inspect later:
87
+
88
+ ```bash
89
+ agent-brief . --diff HEAD --bundle
90
+ ```
91
+
92
+ This writes:
93
+
94
+ - `.agent-brief/brief.md` — the full human-readable project brief.
95
+ - `.agent-brief/brief.json` — the same data for automation.
96
+ - `.agent-brief/verification.md` — a focused checklist of the exact checks the next agent should run or document.
97
+
98
+ Use a custom directory when you want to attach the bundle to a ticket, run log, or CI artifact:
99
+
100
+ ```bash
101
+ agent-brief . --diff origin/main --bundle artifacts/agent-brief
102
+ ```
103
+
82
104
  ## Why this exists
83
105
 
84
106
  The current agent tooling boom has plenty of orchestration, MCP servers, and observability dashboards. The missing small thing is a cheap, local preflight that gives any agent the same crisp project orientation before it spends tokens or touches files.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repo-agent-brief",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Generate concise, safety-aware project briefs for coding agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -29,6 +29,14 @@ For machine-readable automation:
29
29
  npx repo-agent-brief . --format json > agent-brief.json
30
30
  ```
31
31
 
32
+ For durable handoffs:
33
+
34
+ ```bash
35
+ npx repo-agent-brief . --diff HEAD --bundle
36
+ sed -n '1,220p' .agent-brief/brief.md
37
+ sed -n '1,160p' .agent-brief/verification.md
38
+ ```
39
+
32
40
  ## When to use
33
41
 
34
42
  - First pass in an unfamiliar repo.
@@ -48,6 +56,7 @@ npx repo-agent-brief . --format json > agent-brief.json
48
56
  ```bash
49
57
  npx repo-agent-brief .
50
58
  npx repo-agent-brief . --diff HEAD
59
+ npx repo-agent-brief . --diff HEAD --bundle
51
60
  npx repo-agent-brief . --diff origin/main --fail-on-high-risk
52
61
  npx repo-agent-brief . --no-snippets
53
62
  ```
package/src/cli.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { resolve } from 'node:path';
3
- import { generateBrief, formatJson, formatMarkdown } from './index.js';
3
+ import { generateBrief, formatJson, formatMarkdown, writeBundle } from './index.js';
4
4
 
5
5
  function parseArgs(argv) {
6
- const args = { path: '.', format: 'markdown', maxFileBytes: 12000, noSnippets: false, failOnHighRisk: false, diffRef: null };
6
+ const args = { path: '.', format: 'markdown', maxFileBytes: 12000, noSnippets: false, failOnHighRisk: false, diffRef: null, bundleDir: null };
7
7
  for (let i = 0; i < argv.length; i++) {
8
8
  const arg = argv[i];
9
9
  if (arg === '--format' || arg === '-f') args.format = argv[++i];
@@ -11,6 +11,7 @@ function parseArgs(argv) {
11
11
  else if (arg === '--no-snippets') args.noSnippets = true;
12
12
  else if (arg === '--fail-on-high-risk') args.failOnHighRisk = true;
13
13
  else if (arg === '--diff') args.diffRef = argv[i + 1] && !argv[i + 1].startsWith('-') ? argv[++i] : 'HEAD';
14
+ else if (arg === '--bundle') args.bundleDir = argv[i + 1] && !argv[i + 1].startsWith('-') ? argv[++i] : '.agent-brief';
14
15
  else if (arg === '--help' || arg === '-h') args.help = true;
15
16
  else if (!arg.startsWith('-')) args.path = arg;
16
17
  else throw new Error(`Unknown option: ${arg}`);
@@ -29,13 +30,15 @@ Options:
29
30
  --max-file-bytes N Max bytes to read per context file (default: 12000)
30
31
  --no-snippets Omit context snippets from output
31
32
  --diff [ref] Include changed files vs ref (default: HEAD)
33
+ --bundle [dir] Write brief.md, brief.json, and verification.md (default: .agent-brief)
32
34
  --fail-on-high-risk Exit 2 if high-severity risk patterns are found
33
35
  -h, --help Show help
34
36
 
35
37
  Examples:
36
- npx @builtbyecho/agent-brief
38
+ npx repo-agent-brief
37
39
  agent-brief ~/dev/my-app --format json
38
40
  agent-brief . --diff origin/main
41
+ agent-brief . --diff HEAD --bundle
39
42
  agent-brief . --fail-on-high-risk > AGENT_BRIEF.md
40
43
  `;
41
44
  }
@@ -52,7 +55,15 @@ try {
52
55
  includeSnippets: !args.noSnippets,
53
56
  diffRef: args.diffRef
54
57
  });
55
- console.log(args.format === 'json' ? formatJson(brief) : formatMarkdown(brief));
58
+ if (args.bundleDir) {
59
+ const files = writeBundle(resolve(args.path), brief, args.bundleDir);
60
+ console.log(`Agent brief bundle written:
61
+ - Markdown: ${files.markdown}
62
+ - JSON: ${files.json}
63
+ - Verification: ${files.verification}`);
64
+ } else {
65
+ console.log(args.format === 'json' ? formatJson(brief) : formatMarkdown(brief));
66
+ }
56
67
  if (args.failOnHighRisk && brief.risks.some(r => r.severity === 'high')) process.exit(2);
57
68
  } catch (error) {
58
69
  console.error(`agent-brief: ${error.message}`);
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
- import { basename, join, relative } from 'node:path';
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { basename, join, resolve } from 'node:path';
3
3
  import { execFileSync } from 'node:child_process';
4
4
 
5
5
  const DEFAULT_IGNORES = new Set([
@@ -158,6 +158,61 @@ export function formatJson(brief) {
158
158
  return JSON.stringify(brief, null, 2);
159
159
  }
160
160
 
161
+ export function formatVerificationMarkdown(brief) {
162
+ const lines = [];
163
+ lines.push(`# Verification Plan: ${brief.project}`);
164
+ lines.push('');
165
+ lines.push(`Generated: ${brief.generatedAt}`);
166
+ if (brief.git.branch || brief.git.status) lines.push(`Git: ${brief.git.branch || 'unknown'}${brief.git.status ? ` - ${brief.git.status}` : ''}`);
167
+ lines.push('');
168
+
169
+ lines.push('## Checklist');
170
+ if (brief.verificationPlan.length) {
171
+ for (const step of brief.verificationPlan) {
172
+ const command = step.command ? `\n - Command: \`${step.command}\`` : '';
173
+ lines.push(`- [ ] [${step.priority}] ${step.reason}${command}`);
174
+ }
175
+ } else {
176
+ lines.push('- [ ] Do a focused manual smoke check and document what could not be verified.');
177
+ }
178
+ lines.push('');
179
+
180
+ if (brief.diff?.available) {
181
+ lines.push(`## Changed Files vs ${brief.diff.ref}`);
182
+ if (brief.diff.files.length) {
183
+ for (const file of brief.diff.files) {
184
+ lines.push(`- ${file.status} ${file.path}${file.risky ? ' (high-impact)' : ''}`);
185
+ }
186
+ } else {
187
+ lines.push('- No changed files detected.');
188
+ }
189
+ lines.push('');
190
+ }
191
+
192
+ lines.push('## Risk Notes');
193
+ if (brief.risks.length) {
194
+ for (const risk of brief.risks) lines.push(`- [${risk.severity}] ${risk.path}: ${risk.message}`);
195
+ } else {
196
+ lines.push('- No obvious secret/risky-instruction patterns found in scanned context files.');
197
+ }
198
+ lines.push('');
199
+ return lines.join('\n');
200
+ }
201
+
202
+ export function writeBundle(root, brief, bundleDir = '.agent-brief') {
203
+ const outDir = resolve(root, bundleDir);
204
+ mkdirSync(outDir, { recursive: true });
205
+ const files = {
206
+ markdown: join(outDir, 'brief.md'),
207
+ json: join(outDir, 'brief.json'),
208
+ verification: join(outDir, 'verification.md')
209
+ };
210
+ writeFileSync(files.markdown, formatMarkdown(brief));
211
+ writeFileSync(files.json, `${formatJson(brief)}\n`);
212
+ writeFileSync(files.verification, formatVerificationMarkdown(brief));
213
+ return files;
214
+ }
215
+
161
216
  function collectContext(root, opts) {
162
217
  const files = [];
163
218
  for (const name of CONTEXT_FILES) {