@prustogi/buddy 0.3.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/LICENSE +21 -0
- package/README.md +131 -0
- package/agents/buddy-claude.agent.md +232 -0
- package/agents/buddy.agent.md +217 -0
- package/bin/buddy.js +69 -0
- package/package.json +42 -0
- package/src/commands/agent.js +138 -0
- package/src/commands/init.js +101 -0
- package/src/commands/link.js +70 -0
- package/src/commands/open.js +66 -0
- package/src/commands/precheck.js +65 -0
- package/src/commands/status.js +49 -0
- package/src/lib/git.js +40 -0
- package/src/lib/index.js +6 -0
- package/src/lib/manifest.js +32 -0
- package/src/lib/opener.js +44 -0
- package/src/lib/paths.js +59 -0
- package/src/lib/redact.js +46 -0
- package/src/lib/scaffold.js +31 -0
- package/templates/.buddy/ARCHITECTURE.md +28 -0
- package/templates/.buddy/CHANGELOG_SUMMARY.md +9 -0
- package/templates/.buddy/GETTING_STARTED.md +39 -0
- package/templates/.buddy/INDEX/links.json +4 -0
- package/templates/.buddy/INTEGRATIONS.md +15 -0
- package/templates/.buddy/LINKS.md +30 -0
- package/templates/.buddy/MAP/data_flow.md +13 -0
- package/templates/.buddy/MAP/entry_points.md +11 -0
- package/templates/.buddy/MAP/repo_map.md +17 -0
- package/templates/.buddy/NOTES/assumptions.md +9 -0
- package/templates/.buddy/NOTES/open_questions.md +9 -0
- package/templates/.buddy/README_FOR_HUMANS.md +44 -0
- package/templates/.buddy/TECH_STACK.md +27 -0
package/src/lib/paths.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
|
|
7
|
+
// Walk upward from cwd looking for a repo root signal (.git or .buddy or package.json).
|
|
8
|
+
// Falls back to cwd if nothing is found.
|
|
9
|
+
export function findRepoRoot(start = process.cwd()) {
|
|
10
|
+
let dir = resolve(start);
|
|
11
|
+
while (true) {
|
|
12
|
+
if (
|
|
13
|
+
existsSync(join(dir, '.git')) ||
|
|
14
|
+
existsSync(join(dir, '.buddy')) ||
|
|
15
|
+
existsSync(join(dir, 'package.json'))
|
|
16
|
+
) {
|
|
17
|
+
return dir;
|
|
18
|
+
}
|
|
19
|
+
const parent = dirname(dir);
|
|
20
|
+
if (parent === dir) return resolve(start);
|
|
21
|
+
dir = parent;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buddyDir(repoRoot = findRepoRoot()) {
|
|
26
|
+
return join(repoRoot, '.buddy');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function packageRoot() {
|
|
30
|
+
return resolve(__dirname, '..', '..');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function templatesDir() {
|
|
34
|
+
return join(packageRoot(), 'templates', '.buddy');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function agentPromptPath() {
|
|
38
|
+
return join(packageRoot(), 'agents', 'buddy.agent.md');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function claudeAgentPromptPath() {
|
|
42
|
+
return join(packageRoot(), 'agents', 'buddy-claude.agent.md');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isDir(p) {
|
|
46
|
+
try {
|
|
47
|
+
return statSync(p).isDirectory();
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isFile(p) {
|
|
54
|
+
try {
|
|
55
|
+
return statSync(p).isFile();
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Redact secrets from URLs before storing them.
|
|
2
|
+
// Returns { url, redacted: boolean, warnings: string[] }.
|
|
3
|
+
|
|
4
|
+
const SENSITIVE_QUERY_KEYS = [
|
|
5
|
+
'token', 'access_token', 'refresh_token', 'id_token',
|
|
6
|
+
'apikey', 'api_key', 'auth', 'authorization',
|
|
7
|
+
'password', 'pwd', 'secret', 'client_secret',
|
|
8
|
+
'sig', 'signature', 'sas', 'sastoken',
|
|
9
|
+
'key', 'private_key',
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export function redactUrl(input) {
|
|
13
|
+
const warnings = [];
|
|
14
|
+
let url;
|
|
15
|
+
try {
|
|
16
|
+
url = new URL(input);
|
|
17
|
+
} catch {
|
|
18
|
+
return { url: input, redacted: false, warnings: ['Not a valid URL — stored as-is.'] };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let redacted = false;
|
|
22
|
+
|
|
23
|
+
if (url.username || url.password) {
|
|
24
|
+
url.username = '';
|
|
25
|
+
url.password = '';
|
|
26
|
+
warnings.push('Stripped userinfo (user:pass@) from URL.');
|
|
27
|
+
redacted = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
31
|
+
if (SENSITIVE_QUERY_KEYS.includes(key.toLowerCase())) {
|
|
32
|
+
url.searchParams.set(key, 'REDACTED');
|
|
33
|
+
warnings.push(`Redacted query parameter: ${key}`);
|
|
34
|
+
redacted = true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Heuristic: hash fragment containing access_token=...
|
|
39
|
+
if (url.hash && /access_token=|id_token=/i.test(url.hash)) {
|
|
40
|
+
url.hash = '#REDACTED';
|
|
41
|
+
warnings.push('Redacted sensitive URL fragment.');
|
|
42
|
+
redacted = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { url: url.toString(), redacted, warnings };
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readdirSync, statSync, mkdirSync, copyFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
// Recursively copy a template directory tree without overwriting existing files.
|
|
5
|
+
// Returns { created: string[], skipped: string[] }.
|
|
6
|
+
export function copyTree(srcDir, dstDir) {
|
|
7
|
+
const created = [];
|
|
8
|
+
const skipped = [];
|
|
9
|
+
walk(srcDir, dstDir, created, skipped);
|
|
10
|
+
return { created, skipped };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function walk(src, dst, created, skipped) {
|
|
14
|
+
if (!existsSync(dst)) {
|
|
15
|
+
mkdirSync(dst, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
for (const entry of readdirSync(src)) {
|
|
18
|
+
const s = join(src, entry);
|
|
19
|
+
const d = join(dst, entry);
|
|
20
|
+
if (statSync(s).isDirectory()) {
|
|
21
|
+
walk(s, d, created, skipped);
|
|
22
|
+
} else {
|
|
23
|
+
if (existsSync(d)) {
|
|
24
|
+
skipped.push(d);
|
|
25
|
+
} else {
|
|
26
|
+
copyFileSync(s, d);
|
|
27
|
+
created.push(d);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
🏠 [Home](./README_FOR_HUMANS.md) · [Getting Started](./GETTING_STARTED.md) · [Architecture](./ARCHITECTURE.md) · [Tech](./TECH_STACK.md) · [Integrations](./INTEGRATIONS.md) · [Repo Map](./MAP/repo_map.md) · [Links](./LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Architecture
|
|
6
|
+
|
|
7
|
+
> ⚠️ This is an **initial template**. After Buddy scans the repo, sections here will be marked either **Verified** (read from code/docs) or **Inferred** (Buddy's best guess — double-check).
|
|
8
|
+
|
|
9
|
+
## Big picture
|
|
10
|
+
|
|
11
|
+
*(One paragraph: what the system does, in plain words.)*
|
|
12
|
+
|
|
13
|
+
## Major components
|
|
14
|
+
|
|
15
|
+
| Component | Where in the code | Responsibility |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| *(tbd)* | *(tbd)* | *(tbd)* |
|
|
18
|
+
|
|
19
|
+
## Request / data flow
|
|
20
|
+
|
|
21
|
+
*(Describe a typical request from start to finish, end-to-end.)*
|
|
22
|
+
|
|
23
|
+
1. *(tbd)*
|
|
24
|
+
2. *(tbd)*
|
|
25
|
+
|
|
26
|
+
## Key boundaries
|
|
27
|
+
|
|
28
|
+
- *(What lives where; what depends on what.)*
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
🏠 [Home](./README_FOR_HUMANS.md) · [Getting Started](./GETTING_STARTED.md) · [Architecture](./ARCHITECTURE.md) · [Tech](./TECH_STACK.md) · [Integrations](./INTEGRATIONS.md) · [Repo Map](./MAP/repo_map.md) · [Links](./LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Recent Changes (Human-Friendly)
|
|
6
|
+
|
|
7
|
+
> Buddy summarizes recent commits here in plain words. Updated when you run `buddy precheck` and ask Buddy to "update buddy".
|
|
8
|
+
|
|
9
|
+
*(empty — no commits scanned yet)*
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
🏠 [Home](./README_FOR_HUMANS.md) · [Getting Started](./GETTING_STARTED.md) · [Architecture](./ARCHITECTURE.md) · [Tech](./TECH_STACK.md) · [Integrations](./INTEGRATIONS.md) · [Repo Map](./MAP/repo_map.md) · [Links](./LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Getting Started
|
|
6
|
+
|
|
7
|
+
> Buddy will fill this in after scanning the repo. Until then, here's a template.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- *(e.g. Node 18+, Python 3.11, Docker)*
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Buddy will replace this with the real command from package.json / Makefile / etc.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Run locally
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Buddy will replace this with the real command.
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Run tests
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Buddy will replace this with the real command.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Common problems
|
|
32
|
+
|
|
33
|
+
*(Buddy will collect these as it learns from the repo and your questions.)*
|
|
34
|
+
|
|
35
|
+
## Where things live
|
|
36
|
+
|
|
37
|
+
- **Logs:**
|
|
38
|
+
- **Config:**
|
|
39
|
+
- **Secrets / env vars:**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
🏠 [Home](./README_FOR_HUMANS.md) · [Getting Started](./GETTING_STARTED.md) · [Architecture](./ARCHITECTURE.md) · [Tech](./TECH_STACK.md) · [Integrations](./INTEGRATIONS.md) · [Repo Map](./MAP/repo_map.md) · [Links](./LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# External Integrations
|
|
6
|
+
|
|
7
|
+
> Anything the project talks to: databases, queues, auth providers, third-party APIs.
|
|
8
|
+
|
|
9
|
+
| Service | What it's used for | Where configured |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| *(tbd)* | *(tbd)* | *(tbd)* |
|
|
12
|
+
|
|
13
|
+
## Secrets & env vars
|
|
14
|
+
|
|
15
|
+
- *(Where they live; never paste actual values here.)*
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
🏠 [Home](./README_FOR_HUMANS.md) · [Getting Started](./GETTING_STARTED.md) · [Architecture](./ARCHITECTURE.md) · [Tech](./TECH_STACK.md) · [Integrations](./INTEGRATIONS.md) · [Repo Map](./MAP/repo_map.md) · [Links](./LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Important Links
|
|
6
|
+
|
|
7
|
+
> External docs, design docs, runbooks, dashboards — anything a teammate would want to know about.
|
|
8
|
+
|
|
9
|
+
Add a link from the terminal:
|
|
10
|
+
```bash
|
|
11
|
+
buddy link https://example.com/doc --title "Payments design" --tags architecture,payments --relevance must-read
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or ask Buddy in Copilot CLI: *"here's a link: https://… it's our oncall runbook."*
|
|
15
|
+
|
|
16
|
+
> ⚠️ Buddy never reads the linked page. It only stores metadata. If you want a summary, paste the contents into the chat.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Must-read
|
|
21
|
+
|
|
22
|
+
*(none yet)*
|
|
23
|
+
|
|
24
|
+
## Helpful
|
|
25
|
+
|
|
26
|
+
*(none yet)*
|
|
27
|
+
|
|
28
|
+
## Optional
|
|
29
|
+
|
|
30
|
+
*(none yet)*
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
🏠 [Home](../README_FOR_HUMANS.md) · [Getting Started](../GETTING_STARTED.md) · [Architecture](../ARCHITECTURE.md) · [Tech](../TECH_STACK.md) · [Integrations](../INTEGRATIONS.md) · [Repo Map](../MAP/repo_map.md) · [Links](../LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Data Flow
|
|
6
|
+
|
|
7
|
+
> The simple version: "X happens → it goes here → then here → then here."
|
|
8
|
+
|
|
9
|
+
## Common flows
|
|
10
|
+
|
|
11
|
+
### *(flow name)*
|
|
12
|
+
1. *(tbd)*
|
|
13
|
+
2. *(tbd)*
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
🏠 [Home](../README_FOR_HUMANS.md) · [Getting Started](../GETTING_STARTED.md) · [Architecture](../ARCHITECTURE.md) · [Tech](../TECH_STACK.md) · [Integrations](../INTEGRATIONS.md) · [Repo Map](../MAP/repo_map.md) · [Links](../LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Entry Points
|
|
6
|
+
|
|
7
|
+
> Where execution starts. Servers, CLIs, jobs, schedulers — anything that runs.
|
|
8
|
+
|
|
9
|
+
| Entry | File | What it does |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| *(tbd)* | *(tbd)* | *(tbd)* |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
🏠 [Home](../README_FOR_HUMANS.md) · [Getting Started](../GETTING_STARTED.md) · [Architecture](../ARCHITECTURE.md) · [Tech](../TECH_STACK.md) · [Integrations](../INTEGRATIONS.md) · [Repo Map](../MAP/repo_map.md) · [Links](../LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Repo Map
|
|
6
|
+
|
|
7
|
+
> A folder-by-folder tour of where things live and where to start reading.
|
|
8
|
+
|
|
9
|
+
## Top-level folders
|
|
10
|
+
|
|
11
|
+
| Folder | Purpose | Start here? |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| *(tbd)* | *(tbd)* | *(tbd)* |
|
|
14
|
+
|
|
15
|
+
## Where to start reading code
|
|
16
|
+
|
|
17
|
+
1. *(tbd — Buddy will recommend a reading order)*
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
🏠 [Home](../README_FOR_HUMANS.md) · [Getting Started](../GETTING_STARTED.md) · [Architecture](../ARCHITECTURE.md) · [Tech](../TECH_STACK.md) · [Integrations](../INTEGRATIONS.md) · [Repo Map](../MAP/repo_map.md) · [Links](../LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Assumptions
|
|
6
|
+
|
|
7
|
+
> Anything Buddy guessed at. **These are not facts.** Verify before relying on them.
|
|
8
|
+
|
|
9
|
+
*(none yet)*
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
🏠 [Home](../README_FOR_HUMANS.md) · [Getting Started](../GETTING_STARTED.md) · [Architecture](../ARCHITECTURE.md) · [Tech](../TECH_STACK.md) · [Integrations](../INTEGRATIONS.md) · [Repo Map](../MAP/repo_map.md) · [Links](../LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Open Questions
|
|
6
|
+
|
|
7
|
+
> Things Buddy couldn't figure out from the repo alone. Help fill these in!
|
|
8
|
+
|
|
9
|
+
*(none yet)*
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Welcome! 👋
|
|
2
|
+
|
|
3
|
+
Hi there! I'm **Buddy**. This file is your home page in this repo.
|
|
4
|
+
|
|
5
|
+
> **First time here?** This file (and everything in `.buddy/`) is auto-generated to help you understand the project quickly. If sections below look empty or generic, ask Buddy in Copilot CLI: *"Scan this repo and fill in .buddy/."*
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is this project?
|
|
10
|
+
|
|
11
|
+
*(Buddy will fill this in after the first scan.)*
|
|
12
|
+
|
|
13
|
+
- **What it does:**
|
|
14
|
+
- **Who uses it:**
|
|
15
|
+
- **Why it exists:**
|
|
16
|
+
|
|
17
|
+
## Big-picture concepts
|
|
18
|
+
|
|
19
|
+
*(The 3-5 ideas you need to know before reading any code.)*
|
|
20
|
+
|
|
21
|
+
## Quick links
|
|
22
|
+
|
|
23
|
+
- 🚀 **Just want to run it?** → [`GETTING_STARTED.md`](./GETTING_STARTED.md)
|
|
24
|
+
- 🗺️ **Where does code live?** → [`MAP/repo_map.md`](./MAP/repo_map.md)
|
|
25
|
+
- 🏛️ **How is it built?** → [`ARCHITECTURE.md`](./ARCHITECTURE.md)
|
|
26
|
+
- 🧰 **What tech does it use?** → [`TECH_STACK.md`](./TECH_STACK.md)
|
|
27
|
+
- 🔌 **What does it talk to?** → [`INTEGRATIONS.md`](./INTEGRATIONS.md)
|
|
28
|
+
- 📎 **Important external docs** → [`LINKS.md`](./LINKS.md)
|
|
29
|
+
- ❓ **Things Buddy isn't sure about** → [`NOTES/open_questions.md`](./NOTES/open_questions.md)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## How to use Buddy
|
|
34
|
+
|
|
35
|
+
In your terminal:
|
|
36
|
+
- `buddy status` — Is the knowledge here up to date?
|
|
37
|
+
- `buddy precheck` — Show docs that may be stale based on recent changes.
|
|
38
|
+
- `buddy open <name>` — Open a Buddy doc (try: `buddy open getting-started`).
|
|
39
|
+
- `buddy link <url>` — Save an important link with safe redaction.
|
|
40
|
+
|
|
41
|
+
In Copilot CLI (after `buddy agent` and `/agents add buddy`):
|
|
42
|
+
- Ask: *"Scan this repo and fill in .buddy/"*
|
|
43
|
+
- Ask: *"Where does login happen?"*
|
|
44
|
+
- Ask: *"Update buddy for my changes"* (before committing)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
🏠 [Home](./README_FOR_HUMANS.md) · [Getting Started](./GETTING_STARTED.md) · [Architecture](./ARCHITECTURE.md) · [Tech](./TECH_STACK.md) · [Integrations](./INTEGRATIONS.md) · [Repo Map](./MAP/repo_map.md) · [Links](./LINKS.md)
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tech Stack
|
|
6
|
+
|
|
7
|
+
> Buddy fills this in based on actual repo evidence (package.json, requirements.txt, go.mod, pom.xml, etc.).
|
|
8
|
+
|
|
9
|
+
## Languages
|
|
10
|
+
|
|
11
|
+
- *(tbd)*
|
|
12
|
+
|
|
13
|
+
## Frameworks
|
|
14
|
+
|
|
15
|
+
- *(tbd)*
|
|
16
|
+
|
|
17
|
+
## Build & package
|
|
18
|
+
|
|
19
|
+
- *(tbd)*
|
|
20
|
+
|
|
21
|
+
## Tests
|
|
22
|
+
|
|
23
|
+
- *(tbd)*
|
|
24
|
+
|
|
25
|
+
## CI / Deploy
|
|
26
|
+
|
|
27
|
+
- *(tbd)*
|