harness-auto-docs 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.
Files changed (67) hide show
  1. package/.nvmrc +1 -0
  2. package/AGENTS.md +69 -0
  3. package/ARCHITECTURE.md +123 -0
  4. package/README.md +52 -0
  5. package/dist/ai/anthropic.d.ts +7 -0
  6. package/dist/ai/anthropic.js +20 -0
  7. package/dist/ai/interface.d.ts +3 -0
  8. package/dist/ai/interface.js +1 -0
  9. package/dist/ai/minimax.d.ts +7 -0
  10. package/dist/ai/minimax.js +21 -0
  11. package/dist/ai/openai.d.ts +7 -0
  12. package/dist/ai/openai.js +16 -0
  13. package/dist/cli.d.ts +2 -0
  14. package/dist/cli.js +103 -0
  15. package/dist/core/diff.d.ts +17 -0
  16. package/dist/core/diff.js +46 -0
  17. package/dist/core/generator.d.ts +10 -0
  18. package/dist/core/generator.js +238 -0
  19. package/dist/core/relevance.d.ts +3 -0
  20. package/dist/core/relevance.js +29 -0
  21. package/dist/core/writer.d.ts +2 -0
  22. package/dist/core/writer.js +23 -0
  23. package/dist/providers/github.d.ts +13 -0
  24. package/dist/providers/github.js +43 -0
  25. package/dist/providers/gitlab.d.ts +9 -0
  26. package/dist/providers/gitlab.js +6 -0
  27. package/dist/providers/interface.d.ts +8 -0
  28. package/dist/providers/interface.js +1 -0
  29. package/docs/DESIGN.md +94 -0
  30. package/docs/QUALITY_SCORE.md +74 -0
  31. package/docs/design-docs/core-beliefs.md +71 -0
  32. package/docs/design-docs/index.md +32 -0
  33. package/docs/exec-plans/tech-debt-tracker.md +26 -0
  34. package/docs/product-specs/index.md +39 -0
  35. package/docs/references/anthropic-sdk-llms.txt +40 -0
  36. package/docs/references/octokit-rest-llms.txt +44 -0
  37. package/docs/references/openai-sdk-llms.txt +38 -0
  38. package/docs/superpowers/plans/2026-04-03-harness-engineering-auto-docs.md +1863 -0
  39. package/docs/superpowers/specs/2026-04-03-harness-engineering-auto-docs-design.md +169 -0
  40. package/examples/github-workflow.yml +32 -0
  41. package/markdown/harness-engineering-codex-agent-first-world.md +215 -0
  42. package/package.json +30 -0
  43. package/src/ai/anthropic.ts +23 -0
  44. package/src/ai/interface.ts +3 -0
  45. package/src/ai/minimax.ts +25 -0
  46. package/src/ai/openai.ts +20 -0
  47. package/src/cli.ts +122 -0
  48. package/src/core/diff.ts +77 -0
  49. package/src/core/generator.ts +294 -0
  50. package/src/core/relevance.ts +53 -0
  51. package/src/core/writer.ts +25 -0
  52. package/src/providers/github.ts +53 -0
  53. package/src/providers/gitlab.ts +16 -0
  54. package/src/providers/interface.ts +9 -0
  55. package/tests/core/anthropic.test.ts +33 -0
  56. package/tests/core/diff.test.ts +49 -0
  57. package/tests/core/generator.test.ts +93 -0
  58. package/tests/core/openai.test.ts +38 -0
  59. package/tests/core/relevance.test.ts +62 -0
  60. package/tests/core/writer.test.ts +56 -0
  61. package/tests/fixtures/diff-frontend.txt +11 -0
  62. package/tests/fixtures/diff-schema.txt +12 -0
  63. package/tests/fixtures/diff-small.txt +16 -0
  64. package/tests/integration/generate.test.ts +49 -0
  65. package/tests/providers/github.test.ts +69 -0
  66. package/tsconfig.json +15 -0
  67. package/vitest.config.ts +7 -0
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 24
package/AGENTS.md ADDED
@@ -0,0 +1,69 @@
1
+ # AGENTS.md
2
+
3
+ This is the entry point for AI coding agents working in this repository.
4
+ Read this file first, then follow the pointers below for deeper context.
5
+
6
+ ## What this project does
7
+
8
+ `harness-engineering-auto-docs` is a TypeScript CLI that auto-generates Harness Engineering-style
9
+ documentation when a git tag is pushed. It diffs two adjacent tags, selects relevant
10
+ doc targets, calls an LLM (Claude or GPT), writes Markdown files, and opens a GitHub PR.
11
+
12
+ ## Repository map
13
+
14
+ | Path | Purpose |
15
+ |------|---------|
16
+ | `src/cli.ts` | CLI entry point — env wiring, orchestration, git/PR ops |
17
+ | `src/core/diff.ts` | Extract git diff between last two tags; group changed files |
18
+ | `src/core/relevance.ts` | Select which doc targets to generate from file groups |
19
+ | `src/core/generator.ts` | LLM prompts per target; generate + write file paths |
20
+ | `src/core/writer.ts` | `appendSection` / `createFile` helpers |
21
+ | `src/ai/interface.ts` | `AIProvider` interface |
22
+ | `src/ai/anthropic.ts` | Claude implementation |
23
+ | `src/ai/openai.ts` | OpenAI Chat implementation |
24
+ | `src/providers/interface.ts` | `PlatformProvider` interface |
25
+ | `src/providers/github.ts` | GitHub PR creation/update via Octokit |
26
+ | `src/providers/gitlab.ts` | GitLab stub — **not yet implemented** |
27
+ | `tests/` | Vitest unit + integration tests, diff fixtures |
28
+ | `examples/github-workflow.yml` | Copy into target repos to enable automation |
29
+
30
+ ## Knowledge store
31
+
32
+ | Document | What it covers |
33
+ |----------|---------------|
34
+ | `ARCHITECTURE.md` | Domain layers, dependency rules, module map |
35
+ | `docs/DESIGN.md` | Design philosophy, key decisions, trade-offs |
36
+ | `docs/QUALITY_SCORE.md` | Per-domain quality grades and gap tracking |
37
+ | `docs/design-docs/index.md` | Index of all per-release design docs |
38
+ | `docs/design-docs/core-beliefs.md` | Agent-first operating principles |
39
+ | `docs/exec-plans/tech-debt-tracker.md` | Known tech debt, active work items |
40
+ | `docs/product-specs/index.md` | Feature spec index |
41
+ | `docs/references/` | Library-specific LLM reference files |
42
+
43
+ ## Conventions
44
+
45
+ - **Language / runtime**: TypeScript, ESM (`"type": "module"`), Node ≥18, built with `tsc`
46
+ - **Package manager**: pnpm
47
+ - **Test runner**: Vitest (`npm test`)
48
+ - **Build**: `npm run build` → `dist/`
49
+ - **AI dispatch**: model prefix determines provider — `claude-*` → Anthropic, `gpt-*` → OpenAI, `MiniMax-*` → MiniMax (Anthropic-compatible, base URL `https://api.minimax.io/anthropic`)
50
+ - **File grouping heuristics** live in `src/core/diff.ts:groupFiles` — update there first when changing routing logic
51
+ - **Doc target set** is defined in `src/core/relevance.ts` — `CORE_TARGETS` always run; conditional targets gated on file groups
52
+ - **Prompts** are all colocated in `src/core/generator.ts:PROMPTS` — one entry per `DocTarget`
53
+ - **Output paths** are defined in `src/core/generator.ts:writeResult` switch — keep in sync with README table
54
+
55
+ ## Required environment variables
56
+
57
+ | Variable | Description |
58
+ |----------|-------------|
59
+ | `AI_MODEL` | Model name: `claude-sonnet-4-6`, `gpt-4o`, etc. |
60
+ | `AI_API_KEY` | Anthropic or OpenAI API key |
61
+ | `GITHUB_TOKEN` | GitHub PAT or Actions token |
62
+
63
+ ## How to extend
64
+
65
+ 1. Add a new `DocTarget` literal to the union in `src/core/relevance.ts`
66
+ 2. Add an entry to `CORE_TARGETS` or a conditional push in `selectTargets`
67
+ 3. Add a prompt function in `PROMPTS` in `src/core/generator.ts`
68
+ 4. Add an output path case in `writeResult`
69
+ 5. Add tests in `tests/core/`
@@ -0,0 +1,123 @@
1
+ # ARCHITECTURE.md
2
+
3
+ Top-level architecture of `harness-engineering-auto-docs`.
4
+ See `AGENTS.md` for navigation and `docs/design-docs/` for per-release decisions.
5
+
6
+ ## Overview
7
+
8
+ `harness-engineering-auto-docs` is a single-binary CLI (Node.js ESM) with no server or database.
9
+ It is invoked once per git tag event, runs to completion, and exits.
10
+
11
+ ```
12
+ CLI entry (src/cli.ts)
13
+
14
+ ├─ Core pipeline
15
+ │ ├─ diff.ts — git diff extraction & file classification
16
+ │ ├─ relevance.ts — doc target selection
17
+ │ ├─ generator.ts — LLM prompt dispatch & file writing
18
+ │ └─ writer.ts — filesystem helpers
19
+
20
+ ├─ AI layer (src/ai/)
21
+ │ ├─ interface.ts — AIProvider { generate(prompt): Promise<string> }
22
+ │ ├─ anthropic.ts — AnthropicProvider
23
+ │ └─ openai.ts — OpenAIProvider
24
+
25
+ └─ Platform layer (src/providers/)
26
+ ├─ interface.ts — PlatformProvider { createOrUpdatePR(opts) }
27
+ ├─ github.ts — GitHubProvider (Octokit)
28
+ └─ gitlab.ts — GitLabProvider (stub — NOT IMPLEMENTED)
29
+ ```
30
+
31
+ ## Layers and dependency rules
32
+
33
+ Dependencies flow strictly **downward**. No layer may import from a layer above it.
34
+
35
+ ```
36
+ cli.ts (orchestration)
37
+ └── core/ (pure business logic — no AI or platform imports)
38
+ └── ai/ (AI provider abstraction)
39
+ └── providers/ (platform PR abstraction)
40
+ ```
41
+
42
+ - `core/` must not import from `ai/` or `providers/` — it accepts them as injected interfaces
43
+ - `ai/` and `providers/` must not import from each other
44
+ - All cross-cutting types (`AIProvider`, `PlatformProvider`) live in `interface.ts` files within their layer
45
+
46
+ ## Data flow
47
+
48
+ ```
49
+ git tag push
50
+ → GitHub Actions triggers workflow
51
+ → npx harness-engineering-auto-docs
52
+ → extractDiff() reads git history, returns DiffResult
53
+ → selectTargets() classifies files, returns DocTarget[]
54
+ → generateDocs() calls AI provider in parallel, returns GenerationResult[]
55
+ → writeResults() writes/appends Markdown files, returns written paths
56
+ → git branch + commit + push
57
+ → createOrUpdatePR() opens or updates GitHub PR
58
+ ```
59
+
60
+ ## Key interfaces
61
+
62
+ ### `DiffResult` (`src/core/diff.ts`)
63
+
64
+ ```typescript
65
+ interface DiffResult {
66
+ raw: string; // full git diff text (truncated to 8000 chars in prompts)
67
+ prevTag: string; // e.g. "v0.1.0" or "(initial)"
68
+ currentTag: string; // e.g. "v0.2.0"
69
+ changedFiles: string[];
70
+ fileGroups: FileGroups; // { frontend, schema, auth, infra, other }
71
+ }
72
+ ```
73
+
74
+ ### `AIProvider` (`src/ai/interface.ts`)
75
+
76
+ ```typescript
77
+ interface AIProvider {
78
+ generate(prompt: string): Promise<string>;
79
+ }
80
+ ```
81
+
82
+ ### `PlatformProvider` (`src/providers/interface.ts`)
83
+
84
+ ```typescript
85
+ interface PlatformProvider {
86
+ createOrUpdatePR(opts: PROptions): Promise<string>; // returns PR URL
87
+ }
88
+ ```
89
+
90
+ ## Doc output layout (in target repositories)
91
+
92
+ ```
93
+ <repo-root>/
94
+ ├── AGENTS.md
95
+ ├── ARCHITECTURE.md
96
+ ├── changelog/
97
+ │ └── vX.Y.Z.md
98
+ └── docs/
99
+ ├── DESIGN.md
100
+ ├── QUALITY_SCORE.md
101
+ ├── FRONTEND.md (conditional)
102
+ ├── SECURITY.md (conditional)
103
+ ├── RELIABILITY.md (conditional)
104
+ ├── design-docs/
105
+ │ ├── index.md
106
+ │ └── vX.Y.Z.md
107
+ ├── exec-plans/
108
+ │ └── tech-debt-tracker.md
109
+ ├── generated/
110
+ │ └── db-schema.md (conditional)
111
+ ├── product-specs/
112
+ │ └── index.md (conditional)
113
+ └── references/
114
+ └── <lib>-llms.txt (conditional)
115
+ ```
116
+
117
+ ## Constraints
118
+
119
+ - **No global state** — all state flows through function arguments
120
+ - **Parallel AI calls** — `generateDocs` uses `Promise.all`; each target is independent
121
+ - **Diff truncation** — prompts cap raw diff at 8 000 characters (see `PROMPTS` in `generator.ts`)
122
+ - **ESM only** — all imports use `.js` extensions per NodeNext module resolution
123
+ - **Strict TypeScript** — `strict: true` in `tsconfig.json`; no `any` types
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # harness-engineering-auto-docs
2
+
3
+ Auto-generate [Harness Engineering](https://openai.com/research/harness-engineering) style documentation when your project creates a git tag. Opens a PR with updated docs.
4
+
5
+ ## Usage
6
+
7
+ Add `.github/workflows/harness-docs.yml` to your project (see `examples/github-workflow.yml`), then set:
8
+
9
+ - `AI_API_KEY` — your Anthropic, OpenAI, or MiniMax API key (repository secret)
10
+ - `AI_MODEL` — model name, e.g. `claude-sonnet-4-6`, `gpt-4o`, or `MiniMax-Text-01`
11
+ - `GITHUB_TOKEN` — provided automatically by GitHub Actions
12
+
13
+ When you push a tag (`git tag v1.2.0 && git push --tags`), a PR is automatically opened with updated documentation.
14
+
15
+ ## What gets updated
16
+
17
+ | File | Always | Conditional |
18
+ |------|--------|-------------|
19
+ | `AGENTS.md` | ✓ | |
20
+ | `ARCHITECTURE.md` | ✓ | |
21
+ | `docs/DESIGN.md` | ✓ | |
22
+ | `docs/QUALITY_SCORE.md` | ✓ | |
23
+ | `changelog/vX.Y.Z.md` | ✓ | |
24
+ | `docs/design-docs/vX.Y.Z.md` | ✓ | |
25
+ | `docs/design-docs/index.md` | ✓ | |
26
+ | `docs/exec-plans/tech-debt-tracker.md` | ✓ | |
27
+ | `docs/FRONTEND.md` | | frontend files changed |
28
+ | `docs/SECURITY.md` | | auth/security files changed |
29
+ | `docs/RELIABILITY.md` | | infra files changed |
30
+ | `docs/generated/db-schema.md` | | SQL/schema files changed |
31
+ | `docs/product-specs/index.md` | | new features detected |
32
+ | `docs/references/` | | new dependencies added |
33
+
34
+ ## Local run
35
+
36
+ ```bash
37
+ AI_MODEL=claude-sonnet-4-6 AI_API_KEY=sk-ant-... GITHUB_TOKEN=ghp_... npx harness-engineering-auto-docs
38
+ ```
39
+
40
+ ## Supported models
41
+
42
+ Model routing is determined by the prefix of `AI_MODEL`:
43
+
44
+ | Prefix | Provider | Example models |
45
+ |--------|----------|----------------|
46
+ | `claude-*` | Anthropic | `claude-sonnet-4-6`, `claude-opus-4-6`, `claude-haiku-4-5-20251001` |
47
+ | `gpt-*` | OpenAI | `gpt-4o`, `gpt-4o-mini`, `o3` |
48
+ | `MiniMax-*` | MiniMax (Anthropic-compatible) | `MiniMax-Text-01` |
49
+
50
+ ## Future
51
+
52
+ - GitLab support (MR creation)
@@ -0,0 +1,7 @@
1
+ import type { AIProvider } from './interface.js';
2
+ export declare class AnthropicProvider implements AIProvider {
3
+ private client;
4
+ private model;
5
+ constructor(apiKey: string, model: string);
6
+ generate(prompt: string): Promise<string>;
7
+ }
@@ -0,0 +1,20 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ export class AnthropicProvider {
3
+ client;
4
+ model;
5
+ constructor(apiKey, model) {
6
+ this.client = new Anthropic({ apiKey });
7
+ this.model = model;
8
+ }
9
+ async generate(prompt) {
10
+ const message = await this.client.messages.create({
11
+ model: this.model,
12
+ max_tokens: 4096,
13
+ messages: [{ role: 'user', content: prompt }],
14
+ });
15
+ const content = message.content[0];
16
+ if (content.type !== 'text')
17
+ throw new Error('Unexpected response type');
18
+ return content.text;
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ export interface AIProvider {
2
+ generate(prompt: string): Promise<string>;
3
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { AIProvider } from './interface.js';
2
+ export declare class MiniMaxProvider implements AIProvider {
3
+ private client;
4
+ private model;
5
+ constructor(apiKey: string, model: string);
6
+ generate(prompt: string): Promise<string>;
7
+ }
@@ -0,0 +1,21 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ const MINIMAX_BASE_URL = 'https://api.minimax.io/anthropic';
3
+ export class MiniMaxProvider {
4
+ client;
5
+ model;
6
+ constructor(apiKey, model) {
7
+ this.client = new Anthropic({ apiKey, baseURL: MINIMAX_BASE_URL });
8
+ this.model = model;
9
+ }
10
+ async generate(prompt) {
11
+ const message = await this.client.messages.create({
12
+ model: this.model,
13
+ max_tokens: 4096,
14
+ messages: [{ role: 'user', content: prompt }],
15
+ });
16
+ const content = message.content[0];
17
+ if (content.type !== 'text')
18
+ throw new Error('Unexpected response type');
19
+ return content.text;
20
+ }
21
+ }
@@ -0,0 +1,7 @@
1
+ import type { AIProvider } from './interface.js';
2
+ export declare class OpenAIProvider implements AIProvider {
3
+ private client;
4
+ private model;
5
+ constructor(apiKey: string, model: string);
6
+ generate(prompt: string): Promise<string>;
7
+ }
@@ -0,0 +1,16 @@
1
+ import OpenAI from 'openai';
2
+ export class OpenAIProvider {
3
+ client;
4
+ model;
5
+ constructor(apiKey, model) {
6
+ this.client = new OpenAI({ apiKey });
7
+ this.model = model;
8
+ }
9
+ async generate(prompt) {
10
+ const completion = await this.client.chat.completions.create({
11
+ model: this.model,
12
+ messages: [{ role: 'user', content: prompt }],
13
+ });
14
+ return completion.choices[0].message.content ?? '';
15
+ }
16
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ // src/cli.ts
3
+ import { execSync } from 'child_process';
4
+ import { extractDiff } from './core/diff.js';
5
+ import { selectTargets } from './core/relevance.js';
6
+ import { generateDocs, writeResults } from './core/generator.js';
7
+ import { GitHubProvider } from './providers/github.js';
8
+ import { GitLabProvider } from './providers/gitlab.js';
9
+ import { AnthropicProvider } from './ai/anthropic.js';
10
+ import { OpenAIProvider } from './ai/openai.js';
11
+ import { MiniMaxProvider } from './ai/minimax.js';
12
+ function requireEnv(name) {
13
+ const value = process.env[name];
14
+ if (!value) {
15
+ console.error(`Error: ${name} environment variable is required`);
16
+ process.exit(1);
17
+ }
18
+ return value;
19
+ }
20
+ function detectPlatform() {
21
+ if (process.env.GITHUB_ACTIONS) {
22
+ return new GitHubProvider(requireEnv('GITHUB_TOKEN'));
23
+ }
24
+ if (process.env.GITLAB_CI) {
25
+ return new GitLabProvider();
26
+ }
27
+ const token = process.env.GITHUB_TOKEN;
28
+ if (!token) {
29
+ console.error('Error: GITHUB_TOKEN is required (or run in GITHUB_ACTIONS / GITLAB_CI)');
30
+ process.exit(1);
31
+ }
32
+ return new GitHubProvider(token);
33
+ }
34
+ function selectAI(model, apiKey) {
35
+ if (model.startsWith('claude-'))
36
+ return new AnthropicProvider(apiKey, model);
37
+ if (model.startsWith('gpt-'))
38
+ return new OpenAIProvider(apiKey, model);
39
+ if (model.startsWith('MiniMax-'))
40
+ return new MiniMaxProvider(apiKey, model);
41
+ console.error(`Error: Unknown model "${model}". Use a claude-*, gpt-*, or MiniMax-* model.`);
42
+ process.exit(1);
43
+ }
44
+ function getDefaultBranch() {
45
+ try {
46
+ return execSync('git symbolic-ref refs/remotes/origin/HEAD --short')
47
+ .toString().trim().replace('origin/', '');
48
+ }
49
+ catch {
50
+ return 'main';
51
+ }
52
+ }
53
+ async function main() {
54
+ const model = requireEnv('AI_MODEL');
55
+ const apiKey = requireEnv('AI_API_KEY');
56
+ const diff = extractDiff();
57
+ if (!diff.raw.trim()) {
58
+ console.log('No diff between tags. Nothing to document.');
59
+ process.exit(0);
60
+ }
61
+ console.log(`Generating docs: ${diff.prevTag} → ${diff.currentTag}`);
62
+ const ai = selectAI(model, apiKey);
63
+ const targets = selectTargets(diff.fileGroups, diff.changedFiles);
64
+ console.log(`Updating ${targets.length} documents: ${targets.join(', ')}`);
65
+ const results = await generateDocs(ai, diff, targets);
66
+ const failures = results.filter(r => r.error);
67
+ if (failures.length > 0) {
68
+ console.warn(`\nWarning: ${failures.length} document(s) failed:`);
69
+ failures.forEach(f => console.warn(` - ${f.target}: ${f.error}`));
70
+ }
71
+ const cwd = process.cwd();
72
+ const writtenFiles = writeResults(results.filter(r => !r.error), diff, cwd);
73
+ console.log(`\nWrote ${writtenFiles.length} files.`);
74
+ if (writtenFiles.length === 0) {
75
+ console.log('No files written. Skipping PR creation.');
76
+ process.exit(0);
77
+ }
78
+ const branch = `harness-docs/${diff.currentTag}`;
79
+ const baseBranch = getDefaultBranch();
80
+ execSync(`git checkout -b ${branch}`);
81
+ execSync(`git add ${writtenFiles.map(f => `"${f}"`).join(' ')}`);
82
+ execSync(`git commit -m "docs: Harness Engineering docs update for ${diff.currentTag}"`, { env: { ...process.env, GIT_AUTHOR_NAME: 'harness-engineering-auto-docs', GIT_AUTHOR_EMAIL: 'bot@harness-engineering-auto-docs' } });
83
+ execSync(`git push -u origin ${branch}`);
84
+ const platform = detectPlatform();
85
+ const prUrl = await platform.createOrUpdatePR({
86
+ branch,
87
+ title: `docs: Harness Engineering docs for ${diff.currentTag}`,
88
+ body: [
89
+ `Auto-generated by [harness-engineering-auto-docs](https://github.com/your-org/harness-engineering-auto-docs).`,
90
+ ``,
91
+ `Updates documentation based on changes from **${diff.prevTag}** to **${diff.currentTag}**.`,
92
+ ``,
93
+ `**Updated files:**`,
94
+ writtenFiles.map(f => `- \`${f.replace(cwd + '/', '')}\``).join('\n'),
95
+ ].join('\n'),
96
+ baseBranch,
97
+ });
98
+ console.log(`\nPR created: ${prUrl}`);
99
+ }
100
+ main().catch(err => {
101
+ console.error('Fatal:', err);
102
+ process.exit(1);
103
+ });
@@ -0,0 +1,17 @@
1
+ export interface FileGroups {
2
+ frontend: string[];
3
+ schema: string[];
4
+ auth: string[];
5
+ infra: string[];
6
+ other: string[];
7
+ }
8
+ export interface DiffResult {
9
+ raw: string;
10
+ prevTag: string;
11
+ currentTag: string;
12
+ changedFiles: string[];
13
+ fileGroups: FileGroups;
14
+ }
15
+ export declare function extractDiff(): DiffResult;
16
+ export declare function parseChangedFiles(diff: string): string[];
17
+ export declare function groupFiles(files: string[]): FileGroups;
@@ -0,0 +1,46 @@
1
+ // src/core/diff.ts
2
+ import { execSync } from 'child_process';
3
+ export function extractDiff() {
4
+ const tags = execSync('git tag --sort=version:refname')
5
+ .toString()
6
+ .trim()
7
+ .split('\n')
8
+ .filter(Boolean);
9
+ if (tags.length === 0)
10
+ throw new Error('No tags found in repository');
11
+ const currentTag = tags[tags.length - 1];
12
+ const prevTag = tags.length >= 2 ? tags[tags.length - 2] : null;
13
+ const raw = prevTag
14
+ ? execSync(`git diff ${prevTag} ${currentTag}`).toString()
15
+ : execSync(`git show ${currentTag} --format='' -p`).toString();
16
+ const changedFiles = parseChangedFiles(raw);
17
+ const fileGroups = groupFiles(changedFiles);
18
+ return {
19
+ raw,
20
+ prevTag: prevTag ?? '(initial)',
21
+ currentTag,
22
+ changedFiles,
23
+ fileGroups,
24
+ };
25
+ }
26
+ export function parseChangedFiles(diff) {
27
+ const matches = diff.match(/^diff --git a\/.+ b\/(.+)$/gm) ?? [];
28
+ return matches.map(line => {
29
+ const match = line.match(/^diff --git a\/.+ b\/(.+)$/);
30
+ return match ? match[1] : '';
31
+ }).filter(Boolean);
32
+ }
33
+ export function groupFiles(files) {
34
+ const isFrontend = (f) => /\.(tsx?|jsx?|css|scss|html|vue|svelte)$/.test(f) ||
35
+ /\b(ui|frontend|components|pages|views)\b/.test(f);
36
+ const isSchema = (f) => /\.sql$/.test(f) || /\b(schema|migration|migrate)\b/i.test(f);
37
+ const isAuth = (f) => /\b(auth|permission|security|oauth|jwt|session|token)\b/i.test(f);
38
+ const isInfra = (f) => /\b(infra|deploy|k8s|docker|compose|helm|terraform|service|gateway)\b/i.test(f);
39
+ return {
40
+ frontend: files.filter(isFrontend),
41
+ schema: files.filter(isSchema),
42
+ auth: files.filter(isAuth),
43
+ infra: files.filter(isInfra),
44
+ other: files.filter(f => !isFrontend(f) && !isSchema(f) && !isAuth(f) && !isInfra(f)),
45
+ };
46
+ }
@@ -0,0 +1,10 @@
1
+ import type { AIProvider } from '../ai/interface.js';
2
+ import type { DocTarget } from './relevance.js';
3
+ import type { DiffResult } from './diff.js';
4
+ export interface GenerationResult {
5
+ target: DocTarget;
6
+ content: string;
7
+ error?: string;
8
+ }
9
+ export declare function generateDocs(ai: AIProvider, diff: DiffResult, targets: DocTarget[]): Promise<GenerationResult[]>;
10
+ export declare function writeResults(results: GenerationResult[], diff: DiffResult, cwd: string): string[];