@tosanoob/acs 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 +262 -0
- package/dist/cli/init.d.ts +4 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +174 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/onboard.d.ts +2 -0
- package/dist/cli/onboard.d.ts.map +1 -0
- package/dist/cli/onboard.js +37 -0
- package/dist/cli/onboard.js.map +1 -0
- package/dist/cli/pr.d.ts +5 -0
- package/dist/cli/pr.d.ts.map +1 -0
- package/dist/cli/pr.js +90 -0
- package/dist/cli/pr.js.map +1 -0
- package/dist/cli/retry.d.ts +2 -0
- package/dist/cli/retry.d.ts.map +1 -0
- package/dist/cli/retry.js +79 -0
- package/dist/cli/retry.js.map +1 -0
- package/dist/cli/skip.d.ts +2 -0
- package/dist/cli/skip.d.ts.map +1 -0
- package/dist/cli/skip.js +30 -0
- package/dist/cli/skip.js.map +1 -0
- package/dist/cli/status.d.ts +2 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +37 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/why.d.ts +4 -0
- package/dist/cli/why.d.ts.map +1 -0
- package/dist/cli/why.js +49 -0
- package/dist/cli/why.js.map +1 -0
- package/dist/core/aiignore.d.ts +8 -0
- package/dist/core/aiignore.d.ts.map +1 -0
- package/dist/core/aiignore.js +111 -0
- package/dist/core/aiignore.js.map +1 -0
- package/dist/core/changelog.d.ts +26 -0
- package/dist/core/changelog.d.ts.map +1 -0
- package/dist/core/changelog.js +107 -0
- package/dist/core/changelog.js.map +1 -0
- package/dist/core/config.d.ts +11 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +33 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/detector.d.ts +10 -0
- package/dist/core/detector.d.ts.map +1 -0
- package/dist/core/detector.js +54 -0
- package/dist/core/detector.js.map +1 -0
- package/dist/core/git.d.ts +20 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +90 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/installer.d.ts +10 -0
- package/dist/core/installer.d.ts.map +1 -0
- package/dist/core/installer.js +128 -0
- package/dist/core/installer.js.map +1 -0
- package/dist/core/schema.d.ts +18 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +70 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
- package/src/hooks/post-commit.sh +107 -0
- package/src/hooks/pre-commit.sh +159 -0
- package/src/skills/claude-code/SKILL.md +100 -0
- package/src/skills/codex/acs-context.md +62 -0
- package/src/skills/shared/AGENTS.md.tmpl +22 -0
- package/src/templates/CONSTITUTION.md.tmpl +32 -0
- package/src/templates/aiignore.default +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# ai-context-sync (acs)
|
|
2
|
+
|
|
3
|
+
Git-native AI team memory. Every commit gets a structured changelog in `.ai/changelogs/` — automatically, without changing how your team works.
|
|
4
|
+
|
|
5
|
+
Your AI tools read it before starting. Your teammates read it during review. The context that usually disappears after a session stays in the repo forever.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The problem
|
|
10
|
+
|
|
11
|
+
Teams using AI coding tools ship features without leaving behind usable context. The AI generates artifacts but swallows the reasoning. Git captures *what* changed. Nobody captures *why*, *what was tried*, *what was rejected*, or *how to extend it*.
|
|
12
|
+
|
|
13
|
+
The result: Bob pulls John's feature branch and has to ask John what the AI did. Mark reviews a PR and can't explain the AI-generated code he's responsible for.
|
|
14
|
+
|
|
15
|
+
## How it works
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
You commit code
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
pre-commit hook fires
|
|
22
|
+
├── Claude Code already staged a changelog? → exit (it handled it)
|
|
23
|
+
├── llm_command configured? → call it, generate rich changelog
|
|
24
|
+
└── no AI tool? → write minimal changelog (enrichable later)
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
.ai/changelogs/changelog-2026-04-03T15-30-00Z-a3f2.md committed
|
|
28
|
+
|
|
29
|
+
post-commit hook
|
|
30
|
+
└── patch commit hash → validate schema → log errors if any
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Next developer pulls the branch, asks their AI tool anything about the code — it reads `.ai/` first (via `AGENTS.md` / `CLAUDE.md` installed by `acs init`) and actually knows what happened.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
**Mac / Linux / WSL:**
|
|
40
|
+
```sh
|
|
41
|
+
curl -fsSL https://raw.githubusercontent.com/USER/ai-context-sync/main/install.sh | sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Windows (PowerShell):**
|
|
45
|
+
```powershell
|
|
46
|
+
irm https://raw.githubusercontent.com/USER/ai-context-sync/main/install.ps1 | iex
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Already have Node.js >= 18:**
|
|
50
|
+
```sh
|
|
51
|
+
npm install -g @tosanoob/acs
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> Windows note: git hooks run in Git Bash. WSL also works. Native cmd.exe does not.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quickstart
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
cd your-repo
|
|
62
|
+
acs init
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
That's it. Make a commit. Check `.ai/changelogs/`.
|
|
66
|
+
|
|
67
|
+
`acs init` will:
|
|
68
|
+
- Create `.ai/changelogs/`, `.ai/CONSTITUTION.md`, `.aiignore`
|
|
69
|
+
- Detect Claude Code, Codex, or Gemini in your PATH
|
|
70
|
+
- Install the AI skill so Claude/Codex generates changelogs automatically
|
|
71
|
+
- Install `pre-commit` and `post-commit` git hooks
|
|
72
|
+
- Write `AGENTS.md` so AI tools know to read `.ai/` before starting
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Commands
|
|
77
|
+
|
|
78
|
+
### `acs init`
|
|
79
|
+
Set up acs in the current repository. Safe to re-run — skips anything already present.
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
acs init
|
|
83
|
+
acs init --skip-verify # skip Claude Code smoke test
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `acs why <file>`
|
|
87
|
+
Explain why a file looks the way it does. Aggregates all changelogs for commits that touched the file.
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
acs why src/auth.ts
|
|
91
|
+
acs why src/auth.ts --budget 40000 # default: 20k chars
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `acs status`
|
|
95
|
+
Show what's been captured, what failed schema validation, and what needs enrichment.
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
acs status
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `acs retry`
|
|
102
|
+
Find minimal changelogs (written without AI) and enrich them using your configured LLM.
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
acs retry
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `acs onboard`
|
|
109
|
+
Print a full project context bundle — CONSTITUTION.md plus the last 20 changelogs — for onboarding a new developer or AI agent.
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
acs onboard
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `acs pr prepare`
|
|
116
|
+
Aggregate changelogs from the current branch (not on main) for a PR description.
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
acs pr prepare
|
|
120
|
+
acs pr prepare --format markdown
|
|
121
|
+
acs pr prepare --no-llm-fallback # metadata only, safe for fork PRs in CI
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `acs skip <pattern>`
|
|
125
|
+
Add a commit prefix pattern to `.ai/.skiprc`. Commits matching this prefix skip changelog generation silently.
|
|
126
|
+
|
|
127
|
+
```sh
|
|
128
|
+
acs skip "chore:"
|
|
129
|
+
acs skip "docs:"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## What gets generated
|
|
135
|
+
|
|
136
|
+
Every commit produces a file like `.ai/changelogs/changelog-2026-04-03T15-30-00Z-a3f2.md`:
|
|
137
|
+
|
|
138
|
+
```markdown
|
|
139
|
+
# AI Changelog
|
|
140
|
+
Commit: abc123def456...
|
|
141
|
+
Date: 2026-04-03T15:30:00Z
|
|
142
|
+
Author: John Smith <john@example.com>
|
|
143
|
+
Branch: feat/auth-refactor
|
|
144
|
+
AI-Tool: claude-code
|
|
145
|
+
Session-Quality: INFERRED
|
|
146
|
+
|
|
147
|
+
## What Changed
|
|
148
|
+
Refactored JWT middleware in src/auth/jwt.ts to support refresh token rotation.
|
|
149
|
+
Added a new `refreshToken()` function and updated the session store interface.
|
|
150
|
+
|
|
151
|
+
## Why (AI Context)
|
|
152
|
+
The previous implementation stored tokens in memory, which caused session loss
|
|
153
|
+
on server restart. Switched to Redis-backed storage to support horizontal scaling.
|
|
154
|
+
|
|
155
|
+
## Architectural Impact
|
|
156
|
+
The auth middleware now depends on the Redis client. Any new service that handles
|
|
157
|
+
authentication must initialize the Redis connection before mounting the middleware.
|
|
158
|
+
|
|
159
|
+
## Patterns Used
|
|
160
|
+
Follows the middleware factory pattern established in CONSTITUTION.md. Uses the
|
|
161
|
+
project's standard error boundary wrapper for async middleware functions.
|
|
162
|
+
|
|
163
|
+
## Integration Points
|
|
164
|
+
`src/api/routes.ts` imports the middleware directly. The session store interface
|
|
165
|
+
in `src/core/session.ts` was updated — any code using `SessionStore` needs to
|
|
166
|
+
account for the new `refresh()` method.
|
|
167
|
+
|
|
168
|
+
## Gotchas
|
|
169
|
+
Refresh tokens are single-use. If the client calls refresh twice before the first
|
|
170
|
+
response arrives (e.g., tab duplication), the second call will receive a 401.
|
|
171
|
+
This is intentional — use the `X-Refresh-Nonce` header pattern described in CONSTITUTION.md.
|
|
172
|
+
|
|
173
|
+
## How to Extend
|
|
174
|
+
Start at `src/auth/jwt.ts:refreshToken()`. The token rotation logic is isolated
|
|
175
|
+
there. To add device fingerprinting, extend the `TokenPayload` interface first.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## How AI tools use it
|
|
181
|
+
|
|
182
|
+
When Claude Code (or Codex) opens a session in a repo with acs installed:
|
|
183
|
+
|
|
184
|
+
1. It reads `AGENTS.md` / `CLAUDE.md` (installed by `acs init`)
|
|
185
|
+
2. Those files tell it: read `.ai/CONSTITUTION.md` and recent changelogs first
|
|
186
|
+
3. It has real context — what decisions were made, what patterns to follow, what gotchas exist
|
|
187
|
+
4. After committing, it generates and stages a changelog automatically
|
|
188
|
+
|
|
189
|
+
You get consistent AI behavior across sessions without re-explaining the codebase every time.
|
|
190
|
+
|
|
191
|
+
### Slash commands (Claude Code)
|
|
192
|
+
|
|
193
|
+
After `acs init`, these work in any Claude Code session:
|
|
194
|
+
|
|
195
|
+
- `/acs-why <file>` — explain why a file looks the way it does
|
|
196
|
+
- `/acs-onboard` — get a full project briefing
|
|
197
|
+
- `/acs-commit` — propose a conventional commit message for staged changes
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## The `.ai/` directory
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
.ai/
|
|
205
|
+
CONSTITUTION.md # Project patterns, conventions, anti-patterns
|
|
206
|
+
# Updated via: acs update-constitution (coming in v1.1)
|
|
207
|
+
changelogs/ # One file per commit, append-only
|
|
208
|
+
changelog-*.md # Named by timestamp — sorts chronologically, no merge conflicts
|
|
209
|
+
.errors # Failed generations and schema errors (gitignored)
|
|
210
|
+
.skiprc # Commit prefix patterns to skip (committed)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`.aiignore` at the repo root works like `.gitignore` for AI: files matching it are redacted from the diff before it's sent to the LLM. Secrets, lock files, and binaries are excluded by default.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Sharing with your team
|
|
218
|
+
|
|
219
|
+
The hooks are installed per-machine (`acs init` per developer). Changelogs and CONSTITUTION.md live in the repo and are shared automatically via git.
|
|
220
|
+
|
|
221
|
+
**Share acs itself with your team:**
|
|
222
|
+
```sh
|
|
223
|
+
# Mac/Linux/WSL
|
|
224
|
+
curl -fsSL https://raw.githubusercontent.com/USER/ai-context-sync/main/install.sh | sh
|
|
225
|
+
|
|
226
|
+
# Windows
|
|
227
|
+
irm https://raw.githubusercontent.com/USER/ai-context-sync/main/install.ps1 | iex
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
After each teammate installs, they run `acs init` once per repo.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Configuration
|
|
235
|
+
|
|
236
|
+
`acs.config.json` is created by `acs init` at the repo root:
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"llm_command": "claude -p",
|
|
241
|
+
"version": "1"
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`llm_command` is the headless AI tool subprocess. Detected automatically from your PATH. Supports `claude -p`, `codex exec`, or any command that reads stdin and writes to stdout.
|
|
246
|
+
|
|
247
|
+
Set `ACS_AI_TOOL` in your environment to override the tool name recorded in changelogs.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Requirements
|
|
252
|
+
|
|
253
|
+
- Node.js >= 18
|
|
254
|
+
- Git >= 2.x
|
|
255
|
+
- An AI tool in PATH (optional — changelogs are written without one, enrichable later via `acs retry`)
|
|
256
|
+
- Git for Windows or WSL on Windows
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAaA,wBAAsB,OAAO,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA+HnF"}
|
package/dist/cli/init.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { mkdirSync, copyFileSync, writeFileSync, existsSync, readFileSync, chmodSync, statSync } from 'node:fs';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { detectInstalledTools, primaryLlmCommand } from '../core/detector.js';
|
|
6
|
+
import { installForTool, verifySkill } from '../core/installer.js';
|
|
7
|
+
import { saveConfig, loadConfig } from '../core/config.js';
|
|
8
|
+
import { getRepoRoot } from '../core/git.js';
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const TEMPLATES_DIR = resolve(__dirname, '../../src/templates');
|
|
11
|
+
const HOOKS_DIR = resolve(__dirname, '../../src/hooks');
|
|
12
|
+
export async function runInit(options = {}) {
|
|
13
|
+
let repoRoot;
|
|
14
|
+
try {
|
|
15
|
+
repoRoot = await getRepoRoot();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
console.error(chalk.red('✗ Not inside a git repository. Run git init first.'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
console.log(chalk.bold('\n acs init — AI Context Sync\n'));
|
|
22
|
+
// ── Step 1: Scaffold .ai/ directory ─────────────────────────────────────
|
|
23
|
+
const aiDir = resolve(repoRoot, '.ai');
|
|
24
|
+
const changelogsDir = resolve(aiDir, 'changelogs');
|
|
25
|
+
mkdirSync(changelogsDir, { recursive: true });
|
|
26
|
+
console.log(chalk.green(' ✓') + ' Created .ai/changelogs/');
|
|
27
|
+
// .ai/.errors (gitignored log file)
|
|
28
|
+
const errorsPath = resolve(aiDir, '.errors');
|
|
29
|
+
if (!existsSync(errorsPath)) {
|
|
30
|
+
writeFileSync(errorsPath, '', 'utf8');
|
|
31
|
+
}
|
|
32
|
+
// .ai/.skiprc (committed skip patterns)
|
|
33
|
+
const skiprcPath = resolve(aiDir, '.skiprc');
|
|
34
|
+
if (!existsSync(skiprcPath)) {
|
|
35
|
+
writeFileSync(skiprcPath, '# Commit prefix patterns to skip changelog generation\n# Example: chore: docs:\n', 'utf8');
|
|
36
|
+
}
|
|
37
|
+
// ── Step 2: Write CONSTITUTION.md ────────────────────────────────────────
|
|
38
|
+
const constitutionPath = resolve(aiDir, 'CONSTITUTION.md');
|
|
39
|
+
if (!existsSync(constitutionPath)) {
|
|
40
|
+
const tmpl = readFileSync(resolve(TEMPLATES_DIR, 'CONSTITUTION.md.tmpl'), 'utf8');
|
|
41
|
+
const projectName = repoRoot.split('/').at(-1) ?? 'this project';
|
|
42
|
+
const date = new Date().toISOString().split('T')[0];
|
|
43
|
+
const content = tmpl
|
|
44
|
+
.replace('{{PROJECT_NAME}}', projectName)
|
|
45
|
+
.replace('{{DATE}}', date);
|
|
46
|
+
writeFileSync(constitutionPath, content, 'utf8');
|
|
47
|
+
console.log(chalk.green(' ✓') + ' Created .ai/CONSTITUTION.md');
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.log(chalk.dim(' · .ai/CONSTITUTION.md already exists, skipping'));
|
|
51
|
+
}
|
|
52
|
+
// ── Step 3: Write .aiignore ───────────────────────────────────────────────
|
|
53
|
+
const aiignorePath = resolve(repoRoot, '.aiignore');
|
|
54
|
+
if (!existsSync(aiignorePath)) {
|
|
55
|
+
copyFileSync(resolve(TEMPLATES_DIR, 'aiignore.default'), aiignorePath);
|
|
56
|
+
console.log(chalk.green(' ✓') + ' Created .aiignore');
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
console.log(chalk.dim(' · .aiignore already exists, skipping'));
|
|
60
|
+
}
|
|
61
|
+
// ── Step 4: Detect AI tools ───────────────────────────────────────────────
|
|
62
|
+
console.log('\n Detecting AI tools...');
|
|
63
|
+
const tools = detectInstalledTools();
|
|
64
|
+
if (tools.length === 0) {
|
|
65
|
+
console.log(chalk.yellow(' ⚠ No AI tools detected in PATH (claude, codex, gemini)'));
|
|
66
|
+
console.log(chalk.dim(' Changelogs will be minimal until an AI tool is installed.'));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
for (const tool of tools) {
|
|
70
|
+
console.log(chalk.green(' ✓') + ` Detected: ${tool.displayName} (${tool.command})`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ── Step 5: Install skills ────────────────────────────────────────────────
|
|
74
|
+
if (tools.length > 0) {
|
|
75
|
+
console.log('\n Installing skills...');
|
|
76
|
+
for (const tool of tools) {
|
|
77
|
+
const result = await installForTool(tool, repoRoot);
|
|
78
|
+
if (result.success) {
|
|
79
|
+
console.log(chalk.green(' ✓') + ` ${tool.displayName}: ${result.message}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.log(chalk.yellow(' ⚠') + ` ${tool.displayName}: ${result.message}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ── Step 6: Write acs.config.json ────────────────────────────────────────
|
|
87
|
+
const config = loadConfig(repoRoot);
|
|
88
|
+
const llmCommand = primaryLlmCommand(tools);
|
|
89
|
+
if (llmCommand && config.llm_command !== llmCommand) {
|
|
90
|
+
config.llm_command = llmCommand;
|
|
91
|
+
saveConfig(repoRoot, config);
|
|
92
|
+
console.log(chalk.green('\n ✓') + ` LLM command set to: ${chalk.cyan(llmCommand)}`);
|
|
93
|
+
}
|
|
94
|
+
else if (!llmCommand) {
|
|
95
|
+
config.llm_command = null;
|
|
96
|
+
saveConfig(repoRoot, config);
|
|
97
|
+
}
|
|
98
|
+
// ── Step 7: Install git hooks ─────────────────────────────────────────────
|
|
99
|
+
console.log('\n Installing git hooks...');
|
|
100
|
+
installHook(repoRoot, 'pre-commit');
|
|
101
|
+
installHook(repoRoot, 'post-commit');
|
|
102
|
+
// ── Step 8: Write AGENTS.md ───────────────────────────────────────────────
|
|
103
|
+
const agentsMdPath = resolve(repoRoot, 'AGENTS.md');
|
|
104
|
+
if (!existsSync(agentsMdPath)) {
|
|
105
|
+
const tmplSrc = resolve(__dirname, '../../src/skills/shared/AGENTS.md.tmpl');
|
|
106
|
+
if (existsSync(tmplSrc)) {
|
|
107
|
+
copyFileSync(tmplSrc, agentsMdPath);
|
|
108
|
+
console.log(chalk.green(' ✓') + ' Created AGENTS.md');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.log(chalk.dim(' · AGENTS.md already exists, skipping'));
|
|
113
|
+
}
|
|
114
|
+
// ── Step 9: Verify Claude Code skill ─────────────────────────────────────
|
|
115
|
+
if (!options.skipVerify) {
|
|
116
|
+
const claudeTool = tools.find(t => t.id === 'claude-code');
|
|
117
|
+
if (claudeTool) {
|
|
118
|
+
process.stdout.write('\n Verifying Claude Code skill...');
|
|
119
|
+
const verified = await verifySkill(claudeTool);
|
|
120
|
+
if (verified) {
|
|
121
|
+
console.log(' ' + chalk.green('✓ active'));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(' ' + chalk.yellow('⚠ could not verify'));
|
|
125
|
+
console.log(chalk.dim(' If Claude Code was just installed, restart it and re-run acs init.'));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ── Done ──────────────────────────────────────────────────────────────────
|
|
130
|
+
console.log(chalk.bold('\n acs is ready.\n'));
|
|
131
|
+
console.log(' Next: make a commit and check .ai/changelogs/');
|
|
132
|
+
console.log(' Run ' + chalk.cyan('acs status') + ' to see what\'s been captured.\n');
|
|
133
|
+
}
|
|
134
|
+
function installHook(repoRoot, hookName) {
|
|
135
|
+
const hooksDir = resolve(repoRoot, '.git', 'hooks');
|
|
136
|
+
const hookPath = resolve(hooksDir, hookName);
|
|
137
|
+
const hookSrc = resolve(HOOKS_DIR, `${hookName}.sh`);
|
|
138
|
+
mkdirSync(hooksDir, { recursive: true });
|
|
139
|
+
if (existsSync(hookPath)) {
|
|
140
|
+
// Already has a hook — check if it's ours or wrap it
|
|
141
|
+
const existing = readFileSync(hookPath, 'utf8');
|
|
142
|
+
if (existing.includes('acs pre-commit hook') || existing.includes('acs post-commit hook')) {
|
|
143
|
+
// Ours — overwrite with latest
|
|
144
|
+
copyFileSync(hookSrc, hookPath);
|
|
145
|
+
chmodX(hookPath);
|
|
146
|
+
console.log(chalk.green(' ✓') + ` Updated .git/hooks/${hookName}`);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
// Someone else's hook — wrap it
|
|
150
|
+
const wrapped = `#!/usr/bin/env bash
|
|
151
|
+
# acs wrapper — runs existing ${hookName} hook, then acs hook
|
|
152
|
+
set -euo pipefail
|
|
153
|
+
|
|
154
|
+
# Original hook
|
|
155
|
+
${existing}
|
|
156
|
+
|
|
157
|
+
# ACS hook
|
|
158
|
+
${readFileSync(hookSrc, 'utf8')}
|
|
159
|
+
`;
|
|
160
|
+
writeFileSync(hookPath, wrapped, 'utf8');
|
|
161
|
+
chmodX(hookPath);
|
|
162
|
+
console.log(chalk.green(' ✓') + ` Wrapped existing .git/hooks/${hookName} with acs`);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
copyFileSync(hookSrc, hookPath);
|
|
166
|
+
chmodX(hookPath);
|
|
167
|
+
console.log(chalk.green(' ✓') + ` Installed .git/hooks/${hookName}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function chmodX(path) {
|
|
171
|
+
const mode = statSync(path).mode;
|
|
172
|
+
chmodSync(path, mode | 0o111);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboard.d.ts","sourceRoot":"","sources":["../../src/cli/onboard.ts"],"names":[],"mappings":"AAMA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA+BhD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { getRepoRoot } from '../core/git.js';
|
|
5
|
+
import { listChangelogs } from '../core/changelog.js';
|
|
6
|
+
export async function runOnboard() {
|
|
7
|
+
let repoRoot;
|
|
8
|
+
try {
|
|
9
|
+
repoRoot = await getRepoRoot();
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
console.error(chalk.red('✗ Not inside a git repository.'));
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
// Constitution
|
|
16
|
+
const constitutionPath = resolve(repoRoot, '.ai', 'CONSTITUTION.md');
|
|
17
|
+
console.log('=== PROJECT CONSTITUTION ===\n');
|
|
18
|
+
if (existsSync(constitutionPath)) {
|
|
19
|
+
console.log(readFileSync(constitutionPath, 'utf8').trimEnd());
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log(chalk.dim('(No CONSTITUTION.md found. Run `acs init` to create one.)'));
|
|
23
|
+
}
|
|
24
|
+
// Recent changelogs
|
|
25
|
+
const changelogs = listChangelogs(repoRoot, { limit: 20 });
|
|
26
|
+
console.log('\n=== RECENT CHANGELOGS ===\n');
|
|
27
|
+
if (changelogs.length === 0) {
|
|
28
|
+
console.log(chalk.dim('No changelogs yet. Make some commits with acs installed.'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (let i = 0; i < changelogs.length; i++) {
|
|
32
|
+
if (i > 0)
|
|
33
|
+
console.log('\n---\n');
|
|
34
|
+
console.log(changelogs[i].content.trimEnd());
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=onboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../src/cli/onboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAErD,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,QAAgB,CAAA;IACpB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,WAAW,EAAE,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAA;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,eAAe;IACf,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAA;IACpE,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAA;IAC7C,IAAI,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;IAC/D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC,CAAA;IACrF,CAAC;IAED,oBAAoB;IACpB,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAA;IAC1D,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;IAE5C,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC,CAAA;QAClF,OAAM;IACR,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACjC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC"}
|
package/dist/cli/pr.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr.d.ts","sourceRoot":"","sources":["../../src/cli/pr.ts"],"names":[],"mappings":"AAKA,wBAAsB,YAAY,CAAC,OAAO,GAAE;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyFrB"}
|
package/dist/cli/pr.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { getRepoRoot, getCurrentBranch, getGit } from '../core/git.js';
|
|
3
|
+
import { findChangelogForCommit } from '../core/changelog.js';
|
|
4
|
+
export async function runPrPrepare(options = {}) {
|
|
5
|
+
let repoRoot;
|
|
6
|
+
try {
|
|
7
|
+
repoRoot = await getRepoRoot();
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
console.error(chalk.red('✗ Not inside a git repository.'));
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const branch = await getCurrentBranch(repoRoot);
|
|
14
|
+
const git = getGit(repoRoot);
|
|
15
|
+
// Try origin/main then origin/master
|
|
16
|
+
let baseRef = 'origin/main';
|
|
17
|
+
try {
|
|
18
|
+
await git.raw(['rev-parse', '--verify', 'origin/main']);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
try {
|
|
22
|
+
await git.raw(['rev-parse', '--verify', 'origin/master']);
|
|
23
|
+
baseRef = 'origin/master';
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
baseRef = 'main';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Get commits on this branch not on base
|
|
30
|
+
let hashes;
|
|
31
|
+
try {
|
|
32
|
+
const raw = await git.raw(['log', '--format=%H', `HEAD...${baseRef}`]);
|
|
33
|
+
hashes = raw.trim().split('\n').filter(Boolean);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
console.error(chalk.red(`✗ Could not compare branch to ${baseRef}.`));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (hashes.length === 0) {
|
|
40
|
+
console.log(chalk.dim('No branch-only commits found. Branch may be up to date with base.'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Collect unique changelogs for those commits
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
const changelogs = [];
|
|
46
|
+
for (const hash of hashes) {
|
|
47
|
+
const entry = findChangelogForCommit(repoRoot, hash);
|
|
48
|
+
if (entry && !seen.has(entry.filename)) {
|
|
49
|
+
seen.add(entry.filename);
|
|
50
|
+
changelogs.push(entry);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (changelogs.length === 0) {
|
|
54
|
+
console.log(chalk.yellow('No changelogs found for commits on this branch.'));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const fmt = options.format ?? 'text';
|
|
58
|
+
for (let i = 0; i < changelogs.length; i++) {
|
|
59
|
+
const { metadata, content, filename } = changelogs[i];
|
|
60
|
+
// File count: parse from "What Changed" section if present
|
|
61
|
+
const fileCountMatch = content.match(/^(\d+) file/);
|
|
62
|
+
const fileCount = fileCountMatch ? fileCountMatch[1] : '?';
|
|
63
|
+
if (fmt === 'markdown') {
|
|
64
|
+
console.log(`## ${filename}\n`);
|
|
65
|
+
console.log(`- **Commit:** ${metadata.commit ?? 'unknown'}`);
|
|
66
|
+
console.log(`- **Date:** ${metadata.date ?? 'unknown'}`);
|
|
67
|
+
console.log(`- **Branch:** ${branch}`);
|
|
68
|
+
console.log(`- **AI-Tool:** ${metadata.aiTool ?? 'unknown'}`);
|
|
69
|
+
console.log(`- **Files:** ${fileCount}`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
console.log(`Commit : ${metadata.commit ?? 'unknown'}`);
|
|
73
|
+
console.log(`Date : ${metadata.date ?? 'unknown'}`);
|
|
74
|
+
console.log(`Branch : ${branch}`);
|
|
75
|
+
console.log(`AI-Tool: ${metadata.aiTool ?? 'unknown'}`);
|
|
76
|
+
console.log(`Files : ${fileCount}`);
|
|
77
|
+
}
|
|
78
|
+
if (!options.noLlmFallback) {
|
|
79
|
+
if (fmt === 'markdown') {
|
|
80
|
+
console.log(`\n<details><summary>Full changelog</summary>\n\n${content.trimEnd()}\n\n</details>`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.log(`\n${content.trimEnd()}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (i < changelogs.length - 1)
|
|
87
|
+
console.log('\n---\n');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=pr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr.js","sourceRoot":"","sources":["../../src/cli/pr.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/cli/retry.ts"],"names":[],"mappings":"AAoBA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAkE9C"}
|