docutrack 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/README.md +116 -0
- package/bin/docutrack.js +67 -0
- package/package.json +38 -0
- package/src/analyzer/complexity.js +145 -0
- package/src/analyzer/detect.js +124 -0
- package/src/analyzer/index.js +121 -0
- package/src/analyzer/parsers/express.js +110 -0
- package/src/analyzer/parsers/fastapi.js +89 -0
- package/src/commands/analyze.js +47 -0
- package/src/commands/badge.js +79 -0
- package/src/commands/check.js +187 -0
- package/src/commands/clear.js +17 -0
- package/src/commands/export.js +182 -0
- package/src/commands/init.js +182 -0
- package/src/commands/onboard.js +288 -0
- package/src/commands/scan.js +121 -0
- package/src/commands/serve.js +48 -0
- package/src/commands/status.js +94 -0
- package/src/utils/drift.js +167 -0
- package/src/utils/queue.js +62 -0
- package/src/utils/settings.js +69 -0
- package/src/utils/stale.js +80 -0
- package/src/viewer/index.html +1411 -0
- package/src/viewer/server.js +652 -0
- package/templates/ARCHITECTURE.md +51 -0
- package/templates/agents/documentalista.md +113 -0
- package/templates/claude-snippet.md +39 -0
- package/templates/commands/adr-new.md +58 -0
- package/templates/commands/arch-review.md +59 -0
- package/templates/commands/ask-docs.md +26 -0
- package/templates/commands/doc-map.md +50 -0
- package/templates/docs/api/.gitkeep +0 -0
- package/templates/docs/decisions/.gitkeep +0 -0
- package/templates/docs/modules/.gitkeep +0 -0
- package/templates/docutrack.config.json +13 -0
- package/templates/github/workflows/docutrack-docs.yml +42 -0
- package/templates/github/workflows/docutrack-gate.yml +31 -0
- package/templates/github/workflows/docutrack-pr.yml +93 -0
- package/templates/hooks/on-stop.js +39 -0
- package/templates/hooks/post-tool-use.js +52 -0
- package/templates/stacks/express/ARCHITECTURE.md +67 -0
- package/templates/stacks/express/documentalista.md +63 -0
- package/templates/stacks/fastapi/ARCHITECTURE.md +68 -0
- package/templates/stacks/fastapi/documentalista.md +88 -0
- package/templates/stacks/go/ARCHITECTURE.md +68 -0
- package/templates/stacks/go/documentalista.md +89 -0
- package/templates/stacks/monorepo/ARCHITECTURE.md +60 -0
- package/templates/stacks/monorepo/documentalista.md +59 -0
- package/templates/stacks/nextjs/ARCHITECTURE.md +76 -0
- package/templates/stacks/nextjs/documentalista.md +93 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: documentalista
|
|
3
|
+
description: Updates project documentation after code changes. Invoke when .docutrack/queue.json has pending files that need documentation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are the **documentalista** — a specialized documentation agent. Your only job is to write and maintain accurate, useful documentation. You never write feature code.
|
|
7
|
+
|
|
8
|
+
## Your workflow
|
|
9
|
+
|
|
10
|
+
When invoked, always follow these steps in order:
|
|
11
|
+
|
|
12
|
+
**1. Read the queue**
|
|
13
|
+
```bash
|
|
14
|
+
cat .docutrack/queue.json
|
|
15
|
+
```
|
|
16
|
+
This shows which files were modified and need documentation.
|
|
17
|
+
|
|
18
|
+
**2. Understand what changed**
|
|
19
|
+
Read each file in the queue. Understand its purpose, its public API, and how it fits into the system.
|
|
20
|
+
|
|
21
|
+
**3. Update or create module docs**
|
|
22
|
+
For each file in the queue, update or create `docs/modules/<module-name>.md` using this exact structure:
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
# <Module Name>
|
|
26
|
+
|
|
27
|
+
**Responsibility**: [one sentence — what this module does]
|
|
28
|
+
|
|
29
|
+
## Public API
|
|
30
|
+
|
|
31
|
+
| Export | Type | Description |
|
|
32
|
+
|--------|------|-------------|
|
|
33
|
+
| `functionName` | function | what it does |
|
|
34
|
+
|
|
35
|
+
## Dependencies
|
|
36
|
+
|
|
37
|
+
- **Imports from**: list of modules/packages this depends on
|
|
38
|
+
- **Used by**: list of modules that import from this one
|
|
39
|
+
|
|
40
|
+
## Data Shapes
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Key types, interfaces, or schemas
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
|
|
48
|
+
[Non-obvious constraints, gotchas, or design decisions]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**4. Update ARCHITECTURE.md if needed**
|
|
52
|
+
- If a new module was added: add a row to the Module Map table
|
|
53
|
+
- If a new external service was added: add to the Integrations table
|
|
54
|
+
- If a new env variable was added: add to the Environment Variables table
|
|
55
|
+
- If the tech stack changed: update the Tech Stack table
|
|
56
|
+
|
|
57
|
+
**5. Create an ADR for significant decisions**
|
|
58
|
+
Create `docs/decisions/ADR-NNN-<slug>.md` when you detect:
|
|
59
|
+
- A new service, database, or queue was added
|
|
60
|
+
- A significant library or framework was introduced
|
|
61
|
+
- An existing architecture was restructured
|
|
62
|
+
- A non-obvious tradeoff was made
|
|
63
|
+
|
|
64
|
+
ADR format:
|
|
65
|
+
```markdown
|
|
66
|
+
# ADR-NNN: Title
|
|
67
|
+
|
|
68
|
+
**Status**: Accepted
|
|
69
|
+
**Date**: YYYY-MM-DD
|
|
70
|
+
|
|
71
|
+
## Context
|
|
72
|
+
Why was this decision needed?
|
|
73
|
+
|
|
74
|
+
## Decision
|
|
75
|
+
What was decided?
|
|
76
|
+
|
|
77
|
+
## Consequences
|
|
78
|
+
Trade-offs, implications, and things to watch for.
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**6. Update API docs if needed**
|
|
82
|
+
If the modified file defines routes/endpoints, update or create `docs/api/<service>.md`:
|
|
83
|
+
|
|
84
|
+
```markdown
|
|
85
|
+
# <Service> API
|
|
86
|
+
|
|
87
|
+
## POST /path
|
|
88
|
+
**Auth**: Bearer token | None
|
|
89
|
+
**Body**: `{ field: type }`
|
|
90
|
+
**Response**: `{ field: type }`
|
|
91
|
+
**Notes**: ...
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**7. Clear the queue**
|
|
95
|
+
After all documentation is updated, run:
|
|
96
|
+
```bash
|
|
97
|
+
npx docutrack clear
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Quality rules
|
|
101
|
+
|
|
102
|
+
- Write for the next engineer, not for yourself
|
|
103
|
+
- One responsibility per module doc — if you can't describe it in one sentence, the module does too much
|
|
104
|
+
- Never copy-paste code into docs — describe behavior, not implementation
|
|
105
|
+
- ADRs are permanent records — mark old ones as `Deprecated`, never delete them
|
|
106
|
+
- If you're unsure about something, write what you can observe and add a `> Note: verify this with the team` callout
|
|
107
|
+
|
|
108
|
+
## What you don't do
|
|
109
|
+
|
|
110
|
+
- You don't write feature code
|
|
111
|
+
- You don't modify source files
|
|
112
|
+
- You don't create tests
|
|
113
|
+
- You don't refactor anything
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## Documentation Protocol (DocuTrack)
|
|
2
|
+
|
|
3
|
+
This project uses DocuTrack to maintain living documentation. After every code change, follow this protocol:
|
|
4
|
+
|
|
5
|
+
### When you create or modify a module
|
|
6
|
+
|
|
7
|
+
Update or create `docs/modules/<module-name>.md` with:
|
|
8
|
+
- **Responsibility**: what this module does (one sentence)
|
|
9
|
+
- **Public API**: exported functions/classes with brief descriptions
|
|
10
|
+
- **Dependencies**: what it imports from and what depends on it
|
|
11
|
+
- **Data shapes**: key types, schemas, or interfaces
|
|
12
|
+
- **Notes**: constraints, gotchas, non-obvious design decisions
|
|
13
|
+
|
|
14
|
+
### When you add or change an API endpoint
|
|
15
|
+
|
|
16
|
+
Update `docs/api/` — one file per service/router. Document:
|
|
17
|
+
- Method + path
|
|
18
|
+
- Request body / query params
|
|
19
|
+
- Response shape and status codes
|
|
20
|
+
- Auth requirements
|
|
21
|
+
|
|
22
|
+
### When you make a significant architectural decision
|
|
23
|
+
|
|
24
|
+
Create `docs/decisions/ADR-<NNN>-<slug>.md`. Use this format:
|
|
25
|
+
```
|
|
26
|
+
# ADR-NNN: Title
|
|
27
|
+
## Status: Proposed | Accepted | Deprecated
|
|
28
|
+
## Context: why this decision was needed
|
|
29
|
+
## Decision: what was decided
|
|
30
|
+
## Consequences: trade-offs and implications
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### When you modify `ARCHITECTURE.md`
|
|
34
|
+
|
|
35
|
+
Keep the Module Map table current. If you add a new service, integration, or env variable, add it to the relevant section.
|
|
36
|
+
|
|
37
|
+
### The Stop hook will warn you
|
|
38
|
+
|
|
39
|
+
If you end the session with modified files and no doc update, the Stop hook prints a list of what needs attention. Clear the queue with `npx docutrack clear` only after documentation is updated.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create a new Architecture Decision Record (ADR) interactively
|
|
3
|
+
allowed-tools: Read, Write, Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Guide the user through creating a new Architecture Decision Record.
|
|
7
|
+
|
|
8
|
+
**Step 1 — Find the next ADR number**
|
|
9
|
+
List files in `docs/decisions/`. Find the highest `ADR-NNN` number and increment by 1. If none exist, start at 001.
|
|
10
|
+
|
|
11
|
+
**Step 2 — Ask for the decision title**
|
|
12
|
+
Say: "What is the title of this architectural decision? (e.g., 'Use PostgreSQL for primary storage')"
|
|
13
|
+
|
|
14
|
+
Wait for the user's response.
|
|
15
|
+
|
|
16
|
+
**Step 3 — Ask for context**
|
|
17
|
+
Say: "What problem or situation made this decision necessary?"
|
|
18
|
+
|
|
19
|
+
Wait for the user's response.
|
|
20
|
+
|
|
21
|
+
**Step 4 — Ask for the decision**
|
|
22
|
+
Say: "What was decided? Be specific."
|
|
23
|
+
|
|
24
|
+
Wait for the user's response.
|
|
25
|
+
|
|
26
|
+
**Step 5 — Ask for consequences**
|
|
27
|
+
Say: "What are the trade-offs, implications, or things to watch for as a result of this decision?"
|
|
28
|
+
|
|
29
|
+
Wait for the user's response.
|
|
30
|
+
|
|
31
|
+
**Step 6 — Create the ADR file**
|
|
32
|
+
|
|
33
|
+
Create the file at `docs/decisions/ADR-<NNN>-<slug>.md` where:
|
|
34
|
+
- `<NNN>` is zero-padded to 3 digits (e.g., 001, 012, 123)
|
|
35
|
+
- `<slug>` is the title lowercased with spaces replaced by hyphens, max 40 chars
|
|
36
|
+
|
|
37
|
+
File content:
|
|
38
|
+
```markdown
|
|
39
|
+
# ADR-<NNN>: <Title>
|
|
40
|
+
|
|
41
|
+
**Status**: Accepted
|
|
42
|
+
**Date**: <today's date as YYYY-MM-DD>
|
|
43
|
+
|
|
44
|
+
## Context
|
|
45
|
+
|
|
46
|
+
<User's context answer>
|
|
47
|
+
|
|
48
|
+
## Decision
|
|
49
|
+
|
|
50
|
+
<User's decision answer>
|
|
51
|
+
|
|
52
|
+
## Consequences
|
|
53
|
+
|
|
54
|
+
<User's consequences answer>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
After creating the file, say:
|
|
58
|
+
"Created `docs/decisions/ADR-<NNN>-<slug>.md`. The ADR is now part of your living documentation and will appear in DocuTrack's Decisions section."
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Audit documentation coverage and surface stale, missing, or low-quality docs
|
|
3
|
+
allowed-tools: Read, Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Run a documentation coverage audit. Follow these steps:
|
|
7
|
+
|
|
8
|
+
**Step 1 — Collect source files**
|
|
9
|
+
Run: `find src -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" 2>/dev/null | grep -v node_modules | grep -v ".test." | grep -v ".spec." | head -100`
|
|
10
|
+
|
|
11
|
+
If `src/` doesn't exist, try `lib/`, `app/`, or `pkg/`.
|
|
12
|
+
|
|
13
|
+
**Step 2 — Collect documented modules**
|
|
14
|
+
List all `.md` files in `docs/modules/`.
|
|
15
|
+
|
|
16
|
+
**Step 3 — Read the queue**
|
|
17
|
+
Read `.docutrack/queue.json` to see files waiting for documentation.
|
|
18
|
+
|
|
19
|
+
**Step 4 — Read module docs**
|
|
20
|
+
For each doc in `docs/modules/`, check:
|
|
21
|
+
- Does it have a non-empty **Responsibility** line?
|
|
22
|
+
- Does it have a **Public API** section with at least one entry?
|
|
23
|
+
- Does it have a **Dependencies** section?
|
|
24
|
+
|
|
25
|
+
Flag any doc that is missing these sections as "incomplete".
|
|
26
|
+
|
|
27
|
+
**Step 5 — Output the report**
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
DocuTrack Coverage Report
|
|
31
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
32
|
+
Score: <N>% (<documented>/<total> source files)
|
|
33
|
+
|
|
34
|
+
✓ DOCUMENTED (<N>)
|
|
35
|
+
<module>.md ── <responsibility in one sentence>
|
|
36
|
+
|
|
37
|
+
✗ MISSING DOCS (<N>)
|
|
38
|
+
<file path> ── no documentation found
|
|
39
|
+
|
|
40
|
+
⚠ INCOMPLETE DOCS (<N>)
|
|
41
|
+
<module>.md ── missing: <what's missing>
|
|
42
|
+
|
|
43
|
+
⏱ PENDING IN QUEUE (<N>)
|
|
44
|
+
<file path> ── added <relative time>
|
|
45
|
+
|
|
46
|
+
RECOMMENDATIONS
|
|
47
|
+
1. <highest priority action>
|
|
48
|
+
2. <second priority action>
|
|
49
|
+
3. <third priority action>
|
|
50
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Rules for scoring:
|
|
54
|
+
- Score = (documented source files) / (total source files) × 100
|
|
55
|
+
- A source file is "documented" if a `docs/modules/<name>.md` exists for it (matching by basename without extension)
|
|
56
|
+
- Round to nearest integer
|
|
57
|
+
- Score ≥ 80: ✓ healthy | 50–79: ⚠ needs work | < 50: ✗ critical
|
|
58
|
+
|
|
59
|
+
After the report, ask: "Want me to write the missing documentation now?"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ask-docs
|
|
3
|
+
description: Ask a question about this codebase using the accumulated documentation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Answer the question: $ARGUMENTS
|
|
7
|
+
|
|
8
|
+
To answer, read and synthesize the following documentation sources:
|
|
9
|
+
|
|
10
|
+
1. `ARCHITECTURE.md` — system overview, module map, integrations, env variables
|
|
11
|
+
2. `docs/modules/` — all module docs (responsibility, public API, dependencies, data shapes)
|
|
12
|
+
3. `docs/api/openapi.json` — API spec (endpoints, parameters, request/response shapes)
|
|
13
|
+
4. `docs/decisions/` — ADRs explaining why things are the way they are
|
|
14
|
+
5. `.docutrack/queue.json` — pending files (what's being actively worked on)
|
|
15
|
+
|
|
16
|
+
**How to answer:**
|
|
17
|
+
- Be direct and specific — reference exact module names, function names, and file paths
|
|
18
|
+
- If the answer spans multiple modules, explain the interaction clearly
|
|
19
|
+
- If documentation doesn't cover the question, say what IS documented and suggest where to look in the source
|
|
20
|
+
- For API questions, quote the exact endpoint path and method
|
|
21
|
+
- For architecture questions, reference the ADR if one exists
|
|
22
|
+
|
|
23
|
+
**Format:**
|
|
24
|
+
- Lead with a one-sentence direct answer
|
|
25
|
+
- Follow with supporting detail from the docs
|
|
26
|
+
- End with the most relevant file path(s) to read next if the user wants more depth
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Render a live map of the system — modules, API surface, integrations, and doc coverage
|
|
3
|
+
allowed-tools: Read, Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Read the following files (skip gracefully if any don't exist):
|
|
7
|
+
1. `ARCHITECTURE.md`
|
|
8
|
+
2. All `.md` files in `docs/modules/`
|
|
9
|
+
3. `docs/api/openapi.json`
|
|
10
|
+
4. `.docutrack/queue.json`
|
|
11
|
+
|
|
12
|
+
Then output a formatted system map in this exact structure:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
╔══════════════════════════════════════════════════════╗
|
|
16
|
+
║ System Map — <project name> ║
|
|
17
|
+
╚══════════════════════════════════════════════════════╝
|
|
18
|
+
|
|
19
|
+
OVERVIEW
|
|
20
|
+
<one-sentence system description from ARCHITECTURE.md>
|
|
21
|
+
|
|
22
|
+
MODULES (<N> documented)
|
|
23
|
+
├── <module> — <responsibility>
|
|
24
|
+
├── <module> — <responsibility>
|
|
25
|
+
└── <module> — <responsibility>
|
|
26
|
+
|
|
27
|
+
API SURFACE (<N> endpoints)
|
|
28
|
+
GET /path/one [tag]
|
|
29
|
+
POST /path/two [tag]
|
|
30
|
+
...
|
|
31
|
+
|
|
32
|
+
INTEGRATIONS
|
|
33
|
+
<service> — <purpose>
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
COVERAGE
|
|
37
|
+
Documented : <N> modules
|
|
38
|
+
Pending : <N> files need documentation
|
|
39
|
+
Score : <N>% [▓▓▓▓▓▓░░░░]
|
|
40
|
+
|
|
41
|
+
PENDING DOCUMENTATION
|
|
42
|
+
- <file> (added <timestamp>)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Rules:
|
|
46
|
+
- Keep module names short — use the file basename without extension
|
|
47
|
+
- Show at most 20 API endpoints; if more exist, show the first 20 and append ` ... and N more`
|
|
48
|
+
- For the coverage bar, use ▓ for covered and ░ for uncovered (10 chars total)
|
|
49
|
+
- If a section has no data (no modules, no API, etc.), write ` (none yet)` under it
|
|
50
|
+
- Do not include markdown formatting — output plain text only
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Deploy DocuTrack Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'docs/**'
|
|
8
|
+
- 'ARCHITECTURE.md'
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pages: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
deploy:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
environment:
|
|
23
|
+
name: github-pages
|
|
24
|
+
url: ${{ steps.deploy.outputs.page_url }}
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- uses: actions/setup-node@v4
|
|
29
|
+
with:
|
|
30
|
+
node-version: 20
|
|
31
|
+
|
|
32
|
+
- name: Build docs site
|
|
33
|
+
run: npx docutrack build --out ./dist
|
|
34
|
+
|
|
35
|
+
- uses: actions/configure-pages@v4
|
|
36
|
+
|
|
37
|
+
- uses: actions/upload-pages-artifact@v3
|
|
38
|
+
with:
|
|
39
|
+
path: ./dist
|
|
40
|
+
|
|
41
|
+
- id: deploy
|
|
42
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: DocuTrack Coverage Gate
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
coverage-gate:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-node@v4
|
|
14
|
+
with:
|
|
15
|
+
node-version: 20
|
|
16
|
+
|
|
17
|
+
- name: Check documentation coverage
|
|
18
|
+
run: |
|
|
19
|
+
STATUS=$(npx docutrack status --json 2>/dev/null || echo '{"coverage":0}')
|
|
20
|
+
COVERAGE=$(echo $STATUS | node -e 'process.stdin.on("data",d=>process.stdout.write(""+JSON.parse(d).coverage))')
|
|
21
|
+
MIN=$(node -e "try{const c=require('./docutrack.config.json');process.stdout.write(''+c.minCoverage)}catch{process.stdout.write('80')}")
|
|
22
|
+
|
|
23
|
+
echo "Coverage: ${COVERAGE}% (minimum: ${MIN}%)"
|
|
24
|
+
|
|
25
|
+
if [ "$COVERAGE" -lt "$MIN" ]; then
|
|
26
|
+
echo "::error::Documentation coverage ${COVERAGE}% is below the minimum ${MIN}%."
|
|
27
|
+
echo "::error::Run /arch-review in your Claude Code session to generate missing docs."
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
echo "::notice::Documentation coverage ${COVERAGE}% meets the minimum ${MIN}%."
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
name: DocuTrack PR Check
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
pull-requests: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
doc-check:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: 20
|
|
22
|
+
|
|
23
|
+
- name: Get doc coverage
|
|
24
|
+
id: coverage
|
|
25
|
+
run: |
|
|
26
|
+
STATUS=$(npx docutrack status --json 2>/dev/null || echo '{"coverage":0,"pending":0,"staleCount":0,"docCount":0}')
|
|
27
|
+
echo "json=$STATUS" >> $GITHUB_OUTPUT
|
|
28
|
+
echo "coverage=$(echo $STATUS | node -e 'process.stdin.on("data",d=>process.stdout.write(JSON.parse(d).coverage+"%"))')" >> $GITHUB_OUTPUT
|
|
29
|
+
|
|
30
|
+
- name: Get changed doc files
|
|
31
|
+
id: changed
|
|
32
|
+
run: |
|
|
33
|
+
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- 'docs/**' 'ARCHITECTURE.md' | head -20)
|
|
34
|
+
echo "files<<EOF" >> $GITHUB_OUTPUT
|
|
35
|
+
echo "$CHANGED" >> $GITHUB_OUTPUT
|
|
36
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
37
|
+
|
|
38
|
+
- name: Post PR comment
|
|
39
|
+
uses: actions/github-script@v7
|
|
40
|
+
with:
|
|
41
|
+
script: |
|
|
42
|
+
const status = JSON.parse('${{ steps.coverage.outputs.json }}')
|
|
43
|
+
const changedFiles = `${{ steps.changed.outputs.files }}`.trim()
|
|
44
|
+
const files = changedFiles ? changedFiles.split('\n').filter(Boolean) : []
|
|
45
|
+
|
|
46
|
+
const scoreEmoji = status.coverage >= 80 ? '✅' : status.coverage >= 50 ? '⚠️' : '❌'
|
|
47
|
+
const docLines = files.length
|
|
48
|
+
? files.map(f => ` - \`${f}\``).join('\n')
|
|
49
|
+
: ' _No documentation changes in this PR_'
|
|
50
|
+
|
|
51
|
+
const body = [
|
|
52
|
+
'## 📋 DocuTrack Documentation Report',
|
|
53
|
+
'',
|
|
54
|
+
`| Metric | Value |`,
|
|
55
|
+
`|--------|-------|`,
|
|
56
|
+
`| Coverage | ${scoreEmoji} **${status.coverage}%** |`,
|
|
57
|
+
`| Doc files | ${status.docCount} |`,
|
|
58
|
+
`| Pending (undocumented) | ${status.pending} |`,
|
|
59
|
+
`| Stale docs | ${status.staleCount} |`,
|
|
60
|
+
'',
|
|
61
|
+
'### Documentation changes in this PR',
|
|
62
|
+
docLines,
|
|
63
|
+
'',
|
|
64
|
+
status.pending > 0
|
|
65
|
+
? `> ⚠️ **${status.pending} file(s) were modified without documentation updates.** Consider running \`/arch-review\` to address them.`
|
|
66
|
+
: '> ✅ All modified files have documentation.',
|
|
67
|
+
'',
|
|
68
|
+
'<sub>Generated by [DocuTrack](https://github.com/your-org/docutrack)</sub>',
|
|
69
|
+
].join('\n')
|
|
70
|
+
|
|
71
|
+
// Update existing comment if present, otherwise create new one
|
|
72
|
+
const { data: comments } = await github.rest.issues.listComments({
|
|
73
|
+
owner: context.repo.owner,
|
|
74
|
+
repo: context.repo.repo,
|
|
75
|
+
issue_number: context.issue.number,
|
|
76
|
+
})
|
|
77
|
+
const existing = comments.find(c => c.body.includes('DocuTrack Documentation Report'))
|
|
78
|
+
|
|
79
|
+
if (existing) {
|
|
80
|
+
await github.rest.issues.updateComment({
|
|
81
|
+
owner: context.repo.owner,
|
|
82
|
+
repo: context.repo.repo,
|
|
83
|
+
comment_id: existing.id,
|
|
84
|
+
body,
|
|
85
|
+
})
|
|
86
|
+
} else {
|
|
87
|
+
await github.rest.issues.createComment({
|
|
88
|
+
owner: context.repo.owner,
|
|
89
|
+
repo: context.repo.repo,
|
|
90
|
+
issue_number: context.issue.number,
|
|
91
|
+
body,
|
|
92
|
+
})
|
|
93
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Stop hook — fires when the Claude Code session ends
|
|
4
|
+
// Warns if there are files modified without documentation updates
|
|
5
|
+
|
|
6
|
+
const fs = require('fs')
|
|
7
|
+
const path = require('path')
|
|
8
|
+
|
|
9
|
+
const QUEUE_PATH = path.join('.docutrack', 'queue.json')
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(QUEUE_PATH)) process.exit(0)
|
|
12
|
+
|
|
13
|
+
let queue
|
|
14
|
+
try {
|
|
15
|
+
queue = JSON.parse(fs.readFileSync(QUEUE_PATH, 'utf8'))
|
|
16
|
+
} catch {
|
|
17
|
+
process.exit(0)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!queue.pending || queue.pending.length === 0) process.exit(0)
|
|
21
|
+
|
|
22
|
+
const count = queue.pending.length
|
|
23
|
+
const files = queue.pending.map(e => ` - ${e.file}`).join('\n')
|
|
24
|
+
|
|
25
|
+
console.log(`
|
|
26
|
+
╔════════════════════════════════════════════════════╗
|
|
27
|
+
║ DocuTrack: ${String(count).padEnd(3)} file(s) need documentation ║
|
|
28
|
+
╚════════════════════════════════════════════════════╝
|
|
29
|
+
|
|
30
|
+
${files}
|
|
31
|
+
|
|
32
|
+
To update the docs, tell the agent:
|
|
33
|
+
"Update the documentation for the files in .docutrack/queue.json"
|
|
34
|
+
|
|
35
|
+
To clear the queue manually:
|
|
36
|
+
npx docutrack clear
|
|
37
|
+
`)
|
|
38
|
+
|
|
39
|
+
process.exit(0)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// PostToolUse hook — fires after every Write, Edit, or MultiEdit
|
|
4
|
+
// Adds the modified file to .docutrack/queue.json
|
|
5
|
+
|
|
6
|
+
const fs = require('fs')
|
|
7
|
+
const path = require('path')
|
|
8
|
+
|
|
9
|
+
let raw = ''
|
|
10
|
+
process.stdin.setEncoding('utf8')
|
|
11
|
+
process.stdin.on('data', chunk => { raw += chunk })
|
|
12
|
+
process.stdin.on('end', () => {
|
|
13
|
+
try {
|
|
14
|
+
const event = JSON.parse(raw)
|
|
15
|
+
const filePath = extractFilePath(event)
|
|
16
|
+
if (filePath) addToQueue(filePath)
|
|
17
|
+
} catch {
|
|
18
|
+
// Never crash the agent session over a hook error
|
|
19
|
+
}
|
|
20
|
+
process.exit(0)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
function extractFilePath(event) {
|
|
24
|
+
const { tool_name, tool_input } = event
|
|
25
|
+
if (!tool_input) return null
|
|
26
|
+
|
|
27
|
+
if (tool_name === 'Write' || tool_name === 'Edit' || tool_name === 'MultiEdit') {
|
|
28
|
+
return tool_input.file_path || null
|
|
29
|
+
}
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function addToQueue(filePath) {
|
|
34
|
+
const normalized = filePath.replace(/\\/g, '/')
|
|
35
|
+
const ignored = [
|
|
36
|
+
'docs/', '.docutrack/', '.claude/', 'node_modules/', '.git/',
|
|
37
|
+
]
|
|
38
|
+
if (ignored.some(p => normalized.startsWith(p))) return
|
|
39
|
+
|
|
40
|
+
const queuePath = path.join('.docutrack', 'queue.json')
|
|
41
|
+
if (!fs.existsSync(path.dirname(queuePath))) return // not initialized
|
|
42
|
+
|
|
43
|
+
let queue = { pending: [], lastClear: null }
|
|
44
|
+
try {
|
|
45
|
+
queue = JSON.parse(fs.readFileSync(queuePath, 'utf8'))
|
|
46
|
+
} catch { /* start fresh */ }
|
|
47
|
+
|
|
48
|
+
if (queue.pending.some(e => e.file === normalized)) return
|
|
49
|
+
|
|
50
|
+
queue.pending.push({ file: normalized, addedAt: new Date().toISOString() })
|
|
51
|
+
fs.writeFileSync(queuePath, JSON.stringify(queue, null, 2))
|
|
52
|
+
}
|