@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
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
const TOOL_DEFINITIONS = [
|
|
3
|
+
{
|
|
4
|
+
id: 'claude-code',
|
|
5
|
+
binary: 'claude',
|
|
6
|
+
headlessFlag: '-p',
|
|
7
|
+
skillsDir: `${process.env.HOME}/.claude/skills/acs`,
|
|
8
|
+
displayName: 'Claude Code',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: 'codex',
|
|
12
|
+
binary: 'codex',
|
|
13
|
+
headlessFlag: 'exec',
|
|
14
|
+
skillsDir: '', // codex installs into repo, not global
|
|
15
|
+
displayName: 'Codex CLI',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'gemini',
|
|
19
|
+
binary: 'gemini',
|
|
20
|
+
headlessFlag: '-p',
|
|
21
|
+
skillsDir: `${process.env.HOME}/.gemini/skills/acs`,
|
|
22
|
+
displayName: 'Gemini CLI',
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
function inPath(binary) {
|
|
26
|
+
try {
|
|
27
|
+
execSync(`which ${binary}`, { stdio: 'ignore' });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function detectInstalledTools() {
|
|
35
|
+
return TOOL_DEFINITIONS
|
|
36
|
+
.filter(def => inPath(def.binary))
|
|
37
|
+
.map(def => ({
|
|
38
|
+
id: def.id,
|
|
39
|
+
command: `${def.binary} ${def.headlessFlag}`,
|
|
40
|
+
skillsDir: def.skillsDir,
|
|
41
|
+
displayName: def.displayName,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
export function primaryLlmCommand(tools) {
|
|
45
|
+
// Prefer claude-code, then codex, then gemini
|
|
46
|
+
const preferred = ['claude-code', 'codex', 'gemini'];
|
|
47
|
+
for (const id of preferred) {
|
|
48
|
+
const tool = tools.find(t => t.id === id);
|
|
49
|
+
if (tool)
|
|
50
|
+
return tool.command;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/core/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAW7C,MAAM,gBAAgB,GAMjB;IACH;QACE,EAAE,EAAE,aAAa;QACjB,MAAM,EAAE,QAAQ;QAChB,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,qBAAqB;QACnD,WAAW,EAAE,aAAa;KAC3B;IACD;QACE,EAAE,EAAE,OAAO;QACX,MAAM,EAAE,OAAO;QACf,YAAY,EAAE,MAAM;QACpB,SAAS,EAAE,EAAE,EAAE,uCAAuC;QACtD,WAAW,EAAE,WAAW;KACzB;IACD;QACE,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,QAAQ;QAChB,YAAY,EAAE,IAAI;QAClB,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,qBAAqB;QACnD,WAAW,EAAE,YAAY;KAC1B;CACF,CAAA;AAED,SAAS,MAAM,CAAC,MAAc;IAC5B,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QAChD,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,gBAAgB;SACpB,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;SACjC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACX,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,YAAY,EAAE;QAC5C,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW,EAAE,GAAG,CAAC,WAAW;KAC7B,CAAC,CAAC,CAAA;AACP,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAqB;IACrD,8CAA8C;IAC9C,MAAM,SAAS,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAA;IAC7D,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;QACzC,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC,OAAO,CAAA;IAC/B,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type SimpleGit } from 'simple-git';
|
|
2
|
+
export declare function getGit(repoRoot: string): SimpleGit;
|
|
3
|
+
export declare function getRepoRoot(): Promise<string>;
|
|
4
|
+
export declare function getCurrentBranch(repoRoot: string): Promise<string>;
|
|
5
|
+
export declare function getAuthor(repoRoot: string): Promise<string>;
|
|
6
|
+
export declare function getStagedDiff(repoRoot: string): Promise<string>;
|
|
7
|
+
export declare function getStagedFiles(repoRoot: string): Promise<string[]>;
|
|
8
|
+
export declare function getCommitDiff(repoRoot: string, commitHash: string): Promise<string>;
|
|
9
|
+
export declare function getCommitMessage(repoRoot: string, commitHash: string): Promise<string>;
|
|
10
|
+
export declare function getCommitFiles(repoRoot: string, commitHash: string): Promise<{
|
|
11
|
+
files: string[];
|
|
12
|
+
insertions: number;
|
|
13
|
+
deletions: number;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function getFilesChangedSince(repoRoot: string, file: string): Promise<string[]>;
|
|
16
|
+
export declare function isMergeCommit(commitHash: string): boolean;
|
|
17
|
+
export declare function stageFile(repoRoot: string, filepath: string): Promise<void>;
|
|
18
|
+
export declare function commitWithTag(repoRoot: string, message: string): Promise<void>;
|
|
19
|
+
export declare function getHeadHash(repoRoot: string): Promise<string>;
|
|
20
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AAGtD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAElD;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnD;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIxE;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKjE;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAIxE;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQzF;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5F;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAClF,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAC,CAmBD;AAED,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAI5F;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAUzD;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGjF;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpF;AAED,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE"}
|
package/dist/core/git.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { simpleGit } from 'simple-git';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
export function getGit(repoRoot) {
|
|
4
|
+
return simpleGit(repoRoot);
|
|
5
|
+
}
|
|
6
|
+
export async function getRepoRoot() {
|
|
7
|
+
const git = simpleGit();
|
|
8
|
+
return git.revparse(['--show-toplevel']);
|
|
9
|
+
}
|
|
10
|
+
export async function getCurrentBranch(repoRoot) {
|
|
11
|
+
const git = getGit(repoRoot);
|
|
12
|
+
const branch = await git.revparse(['--abbrev-ref', 'HEAD']);
|
|
13
|
+
return branch.trim();
|
|
14
|
+
}
|
|
15
|
+
export async function getAuthor(repoRoot) {
|
|
16
|
+
const git = getGit(repoRoot);
|
|
17
|
+
const name = await git.raw(['config', 'user.name']);
|
|
18
|
+
const email = await git.raw(['config', 'user.email']);
|
|
19
|
+
return `${name.trim()} <${email.trim()}>`;
|
|
20
|
+
}
|
|
21
|
+
export async function getStagedDiff(repoRoot) {
|
|
22
|
+
const git = getGit(repoRoot);
|
|
23
|
+
return git.diff(['--cached']);
|
|
24
|
+
}
|
|
25
|
+
export async function getStagedFiles(repoRoot) {
|
|
26
|
+
const git = getGit(repoRoot);
|
|
27
|
+
const result = await git.diff(['--cached', '--name-only']);
|
|
28
|
+
return result.trim().split('\n').filter(Boolean);
|
|
29
|
+
}
|
|
30
|
+
export async function getCommitDiff(repoRoot, commitHash) {
|
|
31
|
+
const git = getGit(repoRoot);
|
|
32
|
+
// Handle first commit (no parent)
|
|
33
|
+
try {
|
|
34
|
+
return git.show([commitHash, '--format=', '--stat', '-p']);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return git.diff(['4b825dc642cb6eb9a060e54bf8d69288fbee4904', commitHash]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function getCommitMessage(repoRoot, commitHash) {
|
|
41
|
+
const git = getGit(repoRoot);
|
|
42
|
+
return (await git.log(['-1', '--format=%B', commitHash])).latest?.message ?? '';
|
|
43
|
+
}
|
|
44
|
+
export async function getCommitFiles(repoRoot, commitHash) {
|
|
45
|
+
const git = getGit(repoRoot);
|
|
46
|
+
const stat = await git.show([commitHash, '--format=', '--numstat']);
|
|
47
|
+
const lines = stat.trim().split('\n').filter(Boolean);
|
|
48
|
+
let insertions = 0;
|
|
49
|
+
let deletions = 0;
|
|
50
|
+
const files = [];
|
|
51
|
+
for (const line of lines) {
|
|
52
|
+
const parts = line.split('\t');
|
|
53
|
+
if (parts.length >= 3) {
|
|
54
|
+
insertions += parseInt(parts[0]) || 0;
|
|
55
|
+
deletions += parseInt(parts[1]) || 0;
|
|
56
|
+
files.push(parts[2]);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { files, insertions, deletions };
|
|
60
|
+
}
|
|
61
|
+
export async function getFilesChangedSince(repoRoot, file) {
|
|
62
|
+
const git = getGit(repoRoot);
|
|
63
|
+
const log = await git.log(['--follow', '--format=%H', '--', file]);
|
|
64
|
+
return log.all.map(entry => entry.hash);
|
|
65
|
+
}
|
|
66
|
+
export function isMergeCommit(commitHash) {
|
|
67
|
+
try {
|
|
68
|
+
const parents = execSync(`git log -1 --format="%P" ${commitHash}`, {
|
|
69
|
+
cwd: process.cwd(),
|
|
70
|
+
encoding: 'utf8',
|
|
71
|
+
}).trim();
|
|
72
|
+
return parents.split(' ').length >= 2;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export async function stageFile(repoRoot, filepath) {
|
|
79
|
+
const git = getGit(repoRoot);
|
|
80
|
+
await git.add(filepath);
|
|
81
|
+
}
|
|
82
|
+
export async function commitWithTag(repoRoot, message) {
|
|
83
|
+
const git = getGit(repoRoot);
|
|
84
|
+
await git.commit(message);
|
|
85
|
+
}
|
|
86
|
+
export async function getHeadHash(repoRoot) {
|
|
87
|
+
const git = getGit(repoRoot);
|
|
88
|
+
return (await git.revparse(['HEAD'])).trim();
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAA;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAE7C,MAAM,UAAU,MAAM,CAAC,QAAgB;IACrC,OAAO,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,GAAG,GAAG,SAAS,EAAE,CAAA;IACvB,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3D,OAAO,MAAM,CAAC,IAAI,EAAE,CAAA;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAA;IACnD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAA;IACrD,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,IAAI,EAAE,GAAG,CAAA;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,CAAA;IAC1D,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,UAAkB;IACtE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,kCAAkC;IAClC,IAAI,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAA;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,0CAA0C,EAAE,UAAU,CAAC,CAAC,CAAA;IAC3E,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,UAAkB;IACzE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAA;AACjF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,UAAkB;IAKvE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAA;IACnE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAErD,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACtB,UAAU,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACrC,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACpC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAA;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,QAAgB,EAAE,IAAY;IACvE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAClE,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAAkB;IAC9C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,4BAA4B,UAAU,EAAE,EAAE;YACjE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC,IAAI,EAAE,CAAA;QACT,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,QAAgB;IAChE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IACnE,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5B,OAAO,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;AAC9C,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type DetectedTool } from './detector.js';
|
|
2
|
+
export interface InstallResult {
|
|
3
|
+
tool: string;
|
|
4
|
+
success: boolean;
|
|
5
|
+
path: string;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function installForTool(tool: DetectedTool, repoRoot: string): Promise<InstallResult>;
|
|
9
|
+
export declare function verifySkill(tool: DetectedTool): Promise<boolean>;
|
|
10
|
+
//# sourceMappingURL=installer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/core/installer.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAA;AAMjD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC,CAWxB;AA6GD,wBAAsB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAYtE"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
// When installed via npm, skills are at ../../src/skills relative to dist/core/
|
|
7
|
+
const SKILLS_DIR = resolve(__dirname, '../../src/skills');
|
|
8
|
+
export async function installForTool(tool, repoRoot) {
|
|
9
|
+
if (tool.id === 'claude-code') {
|
|
10
|
+
return installClaudeCode(tool, repoRoot);
|
|
11
|
+
}
|
|
12
|
+
if (tool.id === 'codex') {
|
|
13
|
+
return installCodex(repoRoot);
|
|
14
|
+
}
|
|
15
|
+
if (tool.id === 'gemini') {
|
|
16
|
+
return installGemini(tool);
|
|
17
|
+
}
|
|
18
|
+
return { tool: tool.id, success: false, path: '', message: 'Unknown tool' };
|
|
19
|
+
}
|
|
20
|
+
function installClaudeCode(tool, repoRoot) {
|
|
21
|
+
const targetDir = tool.skillsDir;
|
|
22
|
+
const skillSrc = resolve(SKILLS_DIR, 'claude-code', 'SKILL.md');
|
|
23
|
+
try {
|
|
24
|
+
mkdirSync(targetDir, { recursive: true });
|
|
25
|
+
copyFileSync(skillSrc, resolve(targetDir, 'SKILL.md'));
|
|
26
|
+
// Write project-level Claude Code hooks
|
|
27
|
+
installClaudeCodeHooks(repoRoot);
|
|
28
|
+
return {
|
|
29
|
+
tool: 'claude-code',
|
|
30
|
+
success: true,
|
|
31
|
+
path: targetDir,
|
|
32
|
+
message: `Skill installed to ${targetDir}`,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
return {
|
|
37
|
+
tool: 'claude-code',
|
|
38
|
+
success: false,
|
|
39
|
+
path: targetDir,
|
|
40
|
+
message: `Failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function installClaudeCodeHooks(repoRoot) {
|
|
45
|
+
const hooksPath = resolve(repoRoot, '.claude', 'settings.json');
|
|
46
|
+
mkdirSync(dirname(hooksPath), { recursive: true });
|
|
47
|
+
let settings = {};
|
|
48
|
+
if (existsSync(hooksPath)) {
|
|
49
|
+
try {
|
|
50
|
+
settings = JSON.parse(readFileSync(hooksPath, 'utf8'));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
settings = {};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// We don't overwrite existing hooks — acs just uses SKILL.md instructions
|
|
57
|
+
// and the pre-commit hook for enforcement. No PostToolUse hook needed.
|
|
58
|
+
if (!settings._acs_installed) {
|
|
59
|
+
settings._acs_installed = true;
|
|
60
|
+
settings._acs_version = '0.1.0';
|
|
61
|
+
writeFileSync(hooksPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function installCodex(repoRoot) {
|
|
65
|
+
const agentsDir = resolve(repoRoot, 'agents');
|
|
66
|
+
const contextSrc = resolve(SKILLS_DIR, 'codex', 'acs-context.md');
|
|
67
|
+
const contextDst = resolve(agentsDir, 'acs-context.md');
|
|
68
|
+
try {
|
|
69
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
70
|
+
copyFileSync(contextSrc, contextDst);
|
|
71
|
+
// Update AGENTS.md
|
|
72
|
+
updateAgentsMd(repoRoot);
|
|
73
|
+
return {
|
|
74
|
+
tool: 'codex',
|
|
75
|
+
success: true,
|
|
76
|
+
path: agentsDir,
|
|
77
|
+
message: `agents/acs-context.md written, AGENTS.md updated`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
return {
|
|
82
|
+
tool: 'codex',
|
|
83
|
+
success: false,
|
|
84
|
+
path: agentsDir,
|
|
85
|
+
message: `Failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function updateAgentsMd(repoRoot) {
|
|
90
|
+
const agentsMdPath = resolve(repoRoot, 'AGENTS.md');
|
|
91
|
+
const acsSection = '\n## ACS Context\nSee `agents/acs-context.md` for AI context sync instructions.\n';
|
|
92
|
+
if (existsSync(agentsMdPath)) {
|
|
93
|
+
const content = readFileSync(agentsMdPath, 'utf8');
|
|
94
|
+
if (!content.includes('acs-context.md')) {
|
|
95
|
+
writeFileSync(agentsMdPath, content + acsSection, 'utf8');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const tmplSrc = resolve(SKILLS_DIR, 'shared', 'AGENTS.md.tmpl');
|
|
100
|
+
const tmpl = readFileSync(tmplSrc, 'utf8');
|
|
101
|
+
writeFileSync(agentsMdPath, tmpl, 'utf8');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function installGemini(tool) {
|
|
105
|
+
// Gemini uses same SKILL.md pattern as Claude Code (placeholder for when Gemini CLI stabilizes)
|
|
106
|
+
const targetDir = tool.skillsDir;
|
|
107
|
+
const skillSrc = resolve(SKILLS_DIR, 'claude-code', 'SKILL.md');
|
|
108
|
+
try {
|
|
109
|
+
mkdirSync(targetDir, { recursive: true });
|
|
110
|
+
copyFileSync(skillSrc, resolve(targetDir, 'SKILL.md'));
|
|
111
|
+
return { tool: 'gemini', success: true, path: targetDir, message: `Skill installed to ${targetDir}` };
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
return { tool: 'gemini', success: false, path: targetDir, message: `Failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export async function verifySkill(tool) {
|
|
118
|
+
if (tool.id !== 'claude-code')
|
|
119
|
+
return true; // only verifiable for Claude Code currently
|
|
120
|
+
try {
|
|
121
|
+
const result = execSync(`${tool.command} 'Reply with only the single word: READY'`, { timeout: 15000, encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
122
|
+
return result.trim().toUpperCase().includes('READY');
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/core/installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const REQUIRED_SECTIONS: readonly ["What Changed", "Why (AI Context)", "Architectural Impact", "Patterns Used", "Integration Points", "Gotchas", "How to Extend"];
|
|
2
|
+
export type SectionName = typeof REQUIRED_SECTIONS[number];
|
|
3
|
+
export interface ValidationResult {
|
|
4
|
+
valid: boolean;
|
|
5
|
+
missing: SectionName[];
|
|
6
|
+
tooShort: SectionName[];
|
|
7
|
+
secretsFound: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function validateChangelog(content: string): ValidationResult;
|
|
10
|
+
export interface ChangelogMetadata {
|
|
11
|
+
commit: string | null;
|
|
12
|
+
date: string | null;
|
|
13
|
+
branch: string | null;
|
|
14
|
+
aiTool: string | null;
|
|
15
|
+
sessionQuality: 'HIGH' | 'MED' | 'INFERRED' | 'NO_AI' | null;
|
|
16
|
+
}
|
|
17
|
+
export declare function parseMetadata(content: string): ChangelogMetadata;
|
|
18
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,0IAQpB,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAA;AAE1D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,QAAQ,EAAE,WAAW,EAAE,CAAA;IACvB,YAAY,EAAE,OAAO,CAAA;CACtB;AAWD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CA+BnE;AAeD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,cAAc,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,IAAI,CAAA;CAC7D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAehE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Changelog schema validation
|
|
2
|
+
export const REQUIRED_SECTIONS = [
|
|
3
|
+
'What Changed',
|
|
4
|
+
'Why (AI Context)',
|
|
5
|
+
'Architectural Impact',
|
|
6
|
+
'Patterns Used',
|
|
7
|
+
'Integration Points',
|
|
8
|
+
'Gotchas',
|
|
9
|
+
'How to Extend',
|
|
10
|
+
];
|
|
11
|
+
// Patterns that look like secrets — secondary scan on generated content
|
|
12
|
+
const SECRET_PATTERNS = [
|
|
13
|
+
/-----BEGIN (RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/,
|
|
14
|
+
/sk-[a-zA-Z0-9]{32,}/, // OpenAI key shape
|
|
15
|
+
/ghp_[a-zA-Z0-9]{36}/, // GitHub personal access token
|
|
16
|
+
/AKIA[0-9A-Z]{16}/, // AWS access key
|
|
17
|
+
/[a-zA-Z0-9_-]{20,}\.[a-zA-Z0-9_-]{6,}\.[a-zA-Z0-9_-]{27,}/, // JWT shape
|
|
18
|
+
];
|
|
19
|
+
export function validateChangelog(content) {
|
|
20
|
+
const missing = [];
|
|
21
|
+
const tooShort = [];
|
|
22
|
+
for (const section of REQUIRED_SECTIONS) {
|
|
23
|
+
const headerRegex = new RegExp(`^##\\s+${escapeRegex(section)}\\s*$`, 'm');
|
|
24
|
+
if (!headerRegex.test(content)) {
|
|
25
|
+
missing.push(section);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// Extract section body (text between this header and next ## or end)
|
|
29
|
+
const sectionBodyRegex = new RegExp(`##\\s+${escapeRegex(section)}\\s*\\n([\\s\\S]*?)(?=\\n##\\s|$)`);
|
|
30
|
+
const match = content.match(sectionBodyRegex);
|
|
31
|
+
const body = match?.[1]?.trim() ?? '';
|
|
32
|
+
if (sentenceCount(body) < 2) {
|
|
33
|
+
tooShort.push(section);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const secretsFound = SECRET_PATTERNS.some(pattern => pattern.test(content));
|
|
37
|
+
return {
|
|
38
|
+
valid: missing.length === 0 && tooShort.length === 0 && !secretsFound,
|
|
39
|
+
missing,
|
|
40
|
+
tooShort,
|
|
41
|
+
secretsFound,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function sentenceCount(text) {
|
|
45
|
+
if (!text || text.trim().length === 0)
|
|
46
|
+
return 0;
|
|
47
|
+
// Split on sentence-ending punctuation followed by whitespace or end
|
|
48
|
+
const sentences = text
|
|
49
|
+
.split(/[.!?]+(?:\s|$)/)
|
|
50
|
+
.filter(s => s.trim().length > 3); // ignore very short fragments
|
|
51
|
+
return sentences.length;
|
|
52
|
+
}
|
|
53
|
+
function escapeRegex(str) {
|
|
54
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
55
|
+
}
|
|
56
|
+
export function parseMetadata(content) {
|
|
57
|
+
const get = (field) => {
|
|
58
|
+
const match = content.match(new RegExp(`^${field}:\\s*(.+)$`, 'm'));
|
|
59
|
+
return match?.[1]?.trim() ?? null;
|
|
60
|
+
};
|
|
61
|
+
const quality = get('Session-Quality');
|
|
62
|
+
return {
|
|
63
|
+
commit: get('Commit'),
|
|
64
|
+
date: get('Date'),
|
|
65
|
+
branch: get('Branch'),
|
|
66
|
+
aiTool: get('AI-Tool'),
|
|
67
|
+
sessionQuality: quality,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/core/schema.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { resolve, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { runInit } from './cli/init.js';
|
|
7
|
+
import { runWhy } from './cli/why.js';
|
|
8
|
+
import { runStatus } from './cli/status.js';
|
|
9
|
+
import { runOnboard } from './cli/onboard.js';
|
|
10
|
+
import { runPrPrepare } from './cli/pr.js';
|
|
11
|
+
import { runRetry } from './cli/retry.js';
|
|
12
|
+
import { runSkip } from './cli/skip.js';
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf8'));
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('acs')
|
|
18
|
+
.description('AI Context Sync — git-native AI team memory')
|
|
19
|
+
.version(pkg.version);
|
|
20
|
+
program
|
|
21
|
+
.command('init')
|
|
22
|
+
.description('Set up acs in the current git repository')
|
|
23
|
+
.option('--skip-verify', 'Skip Claude Code skill verification smoke test')
|
|
24
|
+
.action(async (opts) => {
|
|
25
|
+
await runInit({ skipVerify: opts.skipVerify });
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command('why <file>')
|
|
29
|
+
.description('Explain why a file looks the way it does (aggregates changelogs)')
|
|
30
|
+
.option('--budget <tokens>', 'Token budget in characters (default: 20000)', '20000')
|
|
31
|
+
.action(async (file, opts) => {
|
|
32
|
+
await runWhy(file, { budget: parseInt(opts.budget, 10) });
|
|
33
|
+
});
|
|
34
|
+
program
|
|
35
|
+
.command('status')
|
|
36
|
+
.description('Show pending changelogs, failed generations, and errors')
|
|
37
|
+
.action(async () => {
|
|
38
|
+
await runStatus();
|
|
39
|
+
});
|
|
40
|
+
program
|
|
41
|
+
.command('onboard')
|
|
42
|
+
.description('Print full project context bundle for AI tools or new developers')
|
|
43
|
+
.action(async () => {
|
|
44
|
+
await runOnboard();
|
|
45
|
+
});
|
|
46
|
+
const pr = program.command('pr').description('PR-related commands');
|
|
47
|
+
pr
|
|
48
|
+
.command('prepare')
|
|
49
|
+
.description('Aggregate branch changelogs for PR description')
|
|
50
|
+
.option('--no-llm-fallback', 'Metadata-only output (for fork PRs in CI)')
|
|
51
|
+
.option('--format <format>', 'Output format: text or markdown', 'text')
|
|
52
|
+
.action(async (opts) => {
|
|
53
|
+
await runPrPrepare({
|
|
54
|
+
noLlmFallback: opts.noLlmFallback,
|
|
55
|
+
format: opts.format ?? 'text',
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
program
|
|
59
|
+
.command('retry')
|
|
60
|
+
.description('Find minimal changelogs and enrich them with AI context')
|
|
61
|
+
.action(async () => {
|
|
62
|
+
await runRetry();
|
|
63
|
+
});
|
|
64
|
+
program
|
|
65
|
+
.command('skip <pattern>')
|
|
66
|
+
.description('Add a commit prefix pattern to .ai/.skiprc (skips changelog generation)')
|
|
67
|
+
.action(async (pattern) => {
|
|
68
|
+
await runSkip(pattern);
|
|
69
|
+
});
|
|
70
|
+
program.parse();
|
|
71
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tosanoob/acs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Git-native AI team memory protocol. Auto-generates changelogs for every commit so your AI tools share context.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"acs": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"src/hooks",
|
|
13
|
+
"src/skills",
|
|
14
|
+
"src/templates"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"test:coverage": "vitest run --coverage",
|
|
22
|
+
"lint": "tsc --noEmit",
|
|
23
|
+
"prepublishOnly": "npm run build && npm test"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"ai",
|
|
27
|
+
"git",
|
|
28
|
+
"context",
|
|
29
|
+
"changelog",
|
|
30
|
+
"claude",
|
|
31
|
+
"codex",
|
|
32
|
+
"developer-tools"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"chalk": "^5.4.1",
|
|
40
|
+
"commander": "^12.1.0",
|
|
41
|
+
"cosmiconfig": "^9.0.0",
|
|
42
|
+
"execa": "^9.5.2",
|
|
43
|
+
"ignore": "^6.0.2",
|
|
44
|
+
"simple-git": "^3.27.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
49
|
+
"typescript": "^5.6.0",
|
|
50
|
+
"vitest": "^2.1.0"
|
|
51
|
+
}
|
|
52
|
+
}
|