@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.
Files changed (69) hide show
  1. package/README.md +262 -0
  2. package/dist/cli/init.d.ts +4 -0
  3. package/dist/cli/init.d.ts.map +1 -0
  4. package/dist/cli/init.js +174 -0
  5. package/dist/cli/init.js.map +1 -0
  6. package/dist/cli/onboard.d.ts +2 -0
  7. package/dist/cli/onboard.d.ts.map +1 -0
  8. package/dist/cli/onboard.js +37 -0
  9. package/dist/cli/onboard.js.map +1 -0
  10. package/dist/cli/pr.d.ts +5 -0
  11. package/dist/cli/pr.d.ts.map +1 -0
  12. package/dist/cli/pr.js +90 -0
  13. package/dist/cli/pr.js.map +1 -0
  14. package/dist/cli/retry.d.ts +2 -0
  15. package/dist/cli/retry.d.ts.map +1 -0
  16. package/dist/cli/retry.js +79 -0
  17. package/dist/cli/retry.js.map +1 -0
  18. package/dist/cli/skip.d.ts +2 -0
  19. package/dist/cli/skip.d.ts.map +1 -0
  20. package/dist/cli/skip.js +30 -0
  21. package/dist/cli/skip.js.map +1 -0
  22. package/dist/cli/status.d.ts +2 -0
  23. package/dist/cli/status.d.ts.map +1 -0
  24. package/dist/cli/status.js +37 -0
  25. package/dist/cli/status.js.map +1 -0
  26. package/dist/cli/why.d.ts +4 -0
  27. package/dist/cli/why.d.ts.map +1 -0
  28. package/dist/cli/why.js +49 -0
  29. package/dist/cli/why.js.map +1 -0
  30. package/dist/core/aiignore.d.ts +8 -0
  31. package/dist/core/aiignore.d.ts.map +1 -0
  32. package/dist/core/aiignore.js +111 -0
  33. package/dist/core/aiignore.js.map +1 -0
  34. package/dist/core/changelog.d.ts +26 -0
  35. package/dist/core/changelog.d.ts.map +1 -0
  36. package/dist/core/changelog.js +107 -0
  37. package/dist/core/changelog.js.map +1 -0
  38. package/dist/core/config.d.ts +11 -0
  39. package/dist/core/config.d.ts.map +1 -0
  40. package/dist/core/config.js +33 -0
  41. package/dist/core/config.js.map +1 -0
  42. package/dist/core/detector.d.ts +10 -0
  43. package/dist/core/detector.d.ts.map +1 -0
  44. package/dist/core/detector.js +54 -0
  45. package/dist/core/detector.js.map +1 -0
  46. package/dist/core/git.d.ts +20 -0
  47. package/dist/core/git.d.ts.map +1 -0
  48. package/dist/core/git.js +90 -0
  49. package/dist/core/git.js.map +1 -0
  50. package/dist/core/installer.d.ts +10 -0
  51. package/dist/core/installer.d.ts.map +1 -0
  52. package/dist/core/installer.js +128 -0
  53. package/dist/core/installer.js.map +1 -0
  54. package/dist/core/schema.d.ts +18 -0
  55. package/dist/core/schema.d.ts.map +1 -0
  56. package/dist/core/schema.js +70 -0
  57. package/dist/core/schema.js.map +1 -0
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +71 -0
  61. package/dist/index.js.map +1 -0
  62. package/package.json +52 -0
  63. package/src/hooks/post-commit.sh +107 -0
  64. package/src/hooks/pre-commit.sh +159 -0
  65. package/src/skills/claude-code/SKILL.md +100 -0
  66. package/src/skills/codex/acs-context.md +62 -0
  67. package/src/skills/shared/AGENTS.md.tmpl +22 -0
  68. package/src/templates/CONSTITUTION.md.tmpl +32 -0
  69. package/src/templates/aiignore.default +45 -0
@@ -0,0 +1,79 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import chalk from 'chalk';
3
+ import { execa } from 'execa';
4
+ import { getRepoRoot, getCommitDiff, stageFile, getGit } from '../core/git.js';
5
+ import { listChangelogs } from '../core/changelog.js';
6
+ import { loadConfig } from '../core/config.js';
7
+ function buildEnrichPrompt(content, diff) {
8
+ return `Enrich this minimal AI changelog with full context based on the git diff.
9
+ Follow the schema exactly. Every section needs minimum 2 sentences.
10
+
11
+ ORIGINAL CHANGELOG:
12
+ ${content}
13
+
14
+ GIT DIFF:
15
+ ${diff}
16
+
17
+ Output the complete enriched changelog starting with # AI Changelog`;
18
+ }
19
+ export async function runRetry() {
20
+ let repoRoot;
21
+ try {
22
+ repoRoot = await getRepoRoot();
23
+ }
24
+ catch {
25
+ console.error(chalk.red('✗ Not inside a git repository.'));
26
+ process.exit(1);
27
+ }
28
+ const config = loadConfig(repoRoot);
29
+ if (!config.llm_command) {
30
+ console.error(chalk.red('✗ No LLM configured. Run acs init to detect AI tools.'));
31
+ process.exit(1);
32
+ }
33
+ const minimal = listChangelogs(repoRoot, { minimalOnly: true });
34
+ if (minimal.length === 0) {
35
+ console.log(chalk.green('✓ No minimal changelogs found. All changelogs have AI context.'));
36
+ return;
37
+ }
38
+ console.log(chalk.bold(`\n Enriching ${minimal.length} minimal changelog(s)...\n`));
39
+ let enriched = 0;
40
+ for (const entry of minimal) {
41
+ const hash = entry.metadata.commit;
42
+ if (!hash) {
43
+ console.log(chalk.yellow(` ⚠ Skipping ${entry.filename} — no commit hash in metadata`));
44
+ continue;
45
+ }
46
+ process.stdout.write(` ${entry.filename} ... `);
47
+ try {
48
+ const diff = await getCommitDiff(repoRoot, hash);
49
+ const prompt = buildEnrichPrompt(entry.content, diff);
50
+ const [cmd, ...args] = config.llm_command.split(' ');
51
+ const result = await execa(cmd, args, {
52
+ input: prompt,
53
+ timeout: (config.llm_timeout_seconds ?? 60) * 1000,
54
+ });
55
+ const enrichedContent = result.stdout.trim();
56
+ if (!enrichedContent.startsWith('# AI Changelog')) {
57
+ console.log(chalk.yellow('⚠ unexpected output, skipping'));
58
+ continue;
59
+ }
60
+ writeFileSync(entry.filepath, enrichedContent + '\n', 'utf8');
61
+ await stageFile(repoRoot, entry.filepath);
62
+ enriched++;
63
+ console.log(chalk.green('✓'));
64
+ }
65
+ catch (err) {
66
+ console.log(chalk.red('✗ failed'));
67
+ console.error(chalk.dim(` ${String(err)}`));
68
+ }
69
+ }
70
+ if (enriched > 0) {
71
+ const git = getGit(repoRoot);
72
+ await git.commit(`chore(ai): enrich ${enriched} changelog${enriched === 1 ? '' : 's'} [acs]`);
73
+ console.log(chalk.green(`\n ✓ Committed ${enriched} enriched changelog(s).`));
74
+ }
75
+ else {
76
+ console.log(chalk.yellow('\n No changelogs were successfully enriched.'));
77
+ }
78
+ }
79
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/cli/retry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runSkip(pattern: string): Promise<void>;
2
+ //# sourceMappingURL=skip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skip.d.ts","sourceRoot":"","sources":["../../src/cli/skip.ts"],"names":[],"mappings":"AAKA,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B5D"}
@@ -0,0 +1,30 @@
1
+ import { existsSync, readFileSync, appendFileSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { getRepoRoot } from '../core/git.js';
5
+ export async function runSkip(pattern) {
6
+ let repoRoot;
7
+ try {
8
+ repoRoot = await getRepoRoot();
9
+ }
10
+ catch {
11
+ console.error(chalk.red('✗ Not inside a git repository.'));
12
+ process.exit(1);
13
+ }
14
+ const skiprcPath = resolve(repoRoot, '.ai', '.skiprc');
15
+ if (existsSync(skiprcPath)) {
16
+ const lines = readFileSync(skiprcPath, 'utf8')
17
+ .split('\n')
18
+ .map(l => l.trim())
19
+ .filter(l => l && !l.startsWith('#'));
20
+ if (lines.includes(pattern)) {
21
+ console.log(chalk.dim(`Pattern '${pattern}' already in .ai/.skiprc`));
22
+ return;
23
+ }
24
+ }
25
+ appendFileSync(skiprcPath, `${pattern}\n`, 'utf8');
26
+ console.log(chalk.green('✓') +
27
+ ` Added '${chalk.cyan(pattern)}' to .ai/.skiprc. ` +
28
+ `Future commits matching this prefix will skip changelog generation.`);
29
+ }
30
+ //# sourceMappingURL=skip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skip.js","sourceRoot":"","sources":["../../src/cli/skip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAe;IAC3C,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,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAA;IAEtD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC;aAC3C,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;QAEvC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,OAAO,0BAA0B,CAAC,CAAC,CAAA;YACrE,OAAM;QACR,CAAC;IACH,CAAC;IAED,cAAc,CAAC,UAAU,EAAE,GAAG,OAAO,IAAI,EAAE,MAAM,CAAC,CAAA;IAClD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;QAChB,WAAW,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB;QAClD,qEAAqE,CACtE,CAAA;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runStatus(): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"AAMA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAoC/C"}
@@ -0,0 +1,37 @@
1
+ import { existsSync, readFileSync, readdirSync } from 'node:fs';
2
+ import chalk from 'chalk';
3
+ import { getRepoRoot } from '../core/git.js';
4
+ import { listChangelogs, changelogsDir, errorsFile } from '../core/changelog.js';
5
+ export async function runStatus() {
6
+ let repoRoot;
7
+ try {
8
+ repoRoot = await getRepoRoot();
9
+ }
10
+ catch {
11
+ console.error(chalk.red('✗ Not inside a git repository.'));
12
+ process.exit(1);
13
+ }
14
+ const all = listChangelogs(repoRoot);
15
+ const minimal = all.filter(e => e.metadata.aiTool === 'none' || e.metadata.sessionQuality === 'NO_AI');
16
+ const dir = changelogsDir(repoRoot);
17
+ const failed = existsSync(dir)
18
+ ? readdirSync(dir).filter(f => f.endsWith('.FAILED.md')).length
19
+ : 0;
20
+ console.log(chalk.bold('\n acs status\n'));
21
+ console.log(` Total changelogs : ${chalk.cyan(all.length)}`);
22
+ console.log(` Minimal (no AI) : ${minimal.length > 0 ? chalk.yellow(minimal.length) : chalk.green(minimal.length)}`);
23
+ console.log(` Failed : ${failed > 0 ? chalk.red(failed) : chalk.green(failed)}`);
24
+ if (minimal.length > 0) {
25
+ console.log(chalk.dim(`\n Run ${chalk.cyan('acs retry')} to enrich minimal changelogs with AI context.`));
26
+ }
27
+ const errFile = errorsFile(repoRoot);
28
+ if (existsSync(errFile)) {
29
+ const lines = readFileSync(errFile, 'utf8').trim().split('\n').filter(Boolean);
30
+ if (lines.length > 0) {
31
+ console.log(chalk.yellow('\n Recent errors (.ai/.errors):'));
32
+ lines.slice(-10).forEach(l => console.log(chalk.dim(` ${l}`)));
33
+ }
34
+ }
35
+ console.log();
36
+ }
37
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/cli/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function runWhy(file: string, options?: {
2
+ budget?: number;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=why.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"why.d.ts","sourceRoot":"","sources":["../../src/cli/why.ts"],"names":[],"mappings":"AAMA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoD3F"}
@@ -0,0 +1,49 @@
1
+ import chalk from 'chalk';
2
+ import { getRepoRoot, getFilesChangedSince } from '../core/git.js';
3
+ import { findChangelogForCommit } from '../core/changelog.js';
4
+ export async function runWhy(file, 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 hashes = await getFilesChangedSince(repoRoot, file);
14
+ if (hashes.length === 0) {
15
+ console.log(chalk.yellow(`No commits found for ${file}.`));
16
+ return;
17
+ }
18
+ // Collect changelogs, deduplicated by filename
19
+ const seen = new Set();
20
+ const changelogs = [];
21
+ for (const hash of hashes) {
22
+ const entry = findChangelogForCommit(repoRoot, hash);
23
+ if (entry && !seen.has(entry.filename)) {
24
+ seen.add(entry.filename);
25
+ changelogs.push(entry);
26
+ }
27
+ }
28
+ if (changelogs.length === 0) {
29
+ console.log(chalk.yellow(`No changelogs found for ${file}. Make some commits with acs installed.`));
30
+ return;
31
+ }
32
+ const budget = options.budget ?? 20000;
33
+ const totalContent = changelogs.reduce((sum, e) => sum + e.content.length, 0);
34
+ let toShow = changelogs;
35
+ let truncated = false;
36
+ if (totalContent > budget && changelogs.length > 6) {
37
+ const kept = [...changelogs.slice(0, 5), changelogs[changelogs.length - 1]];
38
+ console.log(chalk.dim(`Showing ${kept.length} of ${changelogs.length} changelogs (token budget: ${Math.round(budget / 1000)}k). ` +
39
+ `Use --budget=N to increase.`));
40
+ toShow = kept;
41
+ truncated = true;
42
+ }
43
+ for (let i = 0; i < toShow.length; i++) {
44
+ if (i > 0)
45
+ console.log('\n---\n');
46
+ console.log(toShow[i].content.trimEnd());
47
+ }
48
+ }
49
+ //# sourceMappingURL=why.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"why.js","sourceRoot":"","sources":["../../src/cli/why.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAG7D,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,UAA+B,EAAE;IAC1E,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,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IACzD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,IAAI,GAAG,CAAC,CAAC,CAAA;QAC1D,OAAM;IACR,CAAC;IAED,+CAA+C;IAC/C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,UAAU,GAAqB,EAAE,CAAA;IAEvC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,sBAAsB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACpD,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;YACxB,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,IAAI,yCAAyC,CAAC,CAAC,CAAA;QACnG,OAAM;IACR,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAA;IACtC,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAE7E,IAAI,MAAM,GAAG,UAAU,CAAA;IACvB,IAAI,SAAS,GAAG,KAAK,CAAA;IAErB,IAAI,YAAY,GAAG,MAAM,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;QAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,IAAI,CAAC,MAAM,OAAO,UAAU,CAAC,MAAM,8BAA8B,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;YAC3G,6BAA6B,CAC9B,CAAC,CAAA;QACF,MAAM,GAAG,IAAI,CAAA;QACb,SAAS,GAAG,IAAI,CAAA;IAClB,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QACjC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface AiIgnoreRules {
2
+ ig: any;
3
+ patterns: string[];
4
+ }
5
+ export declare function parseAiignore(repoRoot: string): AiIgnoreRules;
6
+ export declare function isIgnored(rules: AiIgnoreRules, filePath: string): boolean;
7
+ export declare function redactIgnored(rules: AiIgnoreRules, diff: string): string;
8
+ //# sourceMappingURL=aiignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiignore.d.ts","sourceRoot":"","sources":["../../src/core/aiignore.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,aAAa;IAE5B,EAAE,EAAE,GAAG,CAAA;IACP,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAoCD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAc7D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOzE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkCxE"}
@@ -0,0 +1,111 @@
1
+ import { createRequire } from 'node:module';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ const _require = createRequire(import.meta.url);
5
+ // ignore has a non-standard export — factory fn is the module itself
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ const ignoreLib = _require('ignore');
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ const createIgnore = typeof ignoreLib === 'function' ? ignoreLib : ignoreLib.default;
10
+ const DEFAULT_PATTERNS = [
11
+ // Secrets
12
+ '.env',
13
+ '.env.*',
14
+ '*.pem',
15
+ '*.key',
16
+ '*.p12',
17
+ '*.pfx',
18
+ 'secrets/',
19
+ 'credentials/',
20
+ '**/*secret*',
21
+ '**/*_secret*',
22
+ // Large generated files
23
+ 'package-lock.json',
24
+ 'yarn.lock',
25
+ 'pnpm-lock.yaml',
26
+ '*.lock',
27
+ 'dist/',
28
+ 'build/',
29
+ 'node_modules/',
30
+ '.next/',
31
+ '.nuxt/',
32
+ // Binary / non-text
33
+ '*.png',
34
+ '*.jpg',
35
+ '*.jpeg',
36
+ '*.gif',
37
+ '*.ico',
38
+ '*.pdf',
39
+ '*.zip',
40
+ '*.tar.gz',
41
+ '*.wasm',
42
+ ];
43
+ export function parseAiignore(repoRoot) {
44
+ const path = resolve(repoRoot, '.aiignore');
45
+ let patterns = [...DEFAULT_PATTERNS];
46
+ if (existsSync(path)) {
47
+ const lines = readFileSync(path, 'utf8')
48
+ .split('\n')
49
+ .map((l) => l.trim())
50
+ .filter((l) => l && !l.startsWith('#'));
51
+ patterns = [...patterns, ...lines];
52
+ }
53
+ const ig = createIgnore().add(patterns);
54
+ return { ig, patterns };
55
+ }
56
+ export function isIgnored(rules, filePath) {
57
+ const normalized = filePath.replace(/^\.\//, '');
58
+ try {
59
+ return rules.ig.ignores(normalized);
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ export function redactIgnored(rules, diff) {
66
+ const lines = diff.split('\n');
67
+ const result = [];
68
+ let inIgnoredFile = false;
69
+ let ignoredPattern = '';
70
+ for (const line of lines) {
71
+ if (line.startsWith('+++ b/')) {
72
+ const filePath = line.slice(6);
73
+ if (isIgnored(rules, filePath)) {
74
+ inIgnoredFile = true;
75
+ ignoredPattern = matchedPattern(rules, filePath);
76
+ result.push(line);
77
+ result.push(`[REDACTED - matches .aiignore: ${ignoredPattern}]`);
78
+ continue;
79
+ }
80
+ else {
81
+ inIgnoredFile = false;
82
+ result.push(line);
83
+ continue;
84
+ }
85
+ }
86
+ if (inIgnoredFile) {
87
+ if (line.startsWith('diff --git') || line.startsWith('--- ')) {
88
+ inIgnoredFile = false;
89
+ result.push(line);
90
+ }
91
+ continue;
92
+ }
93
+ result.push(line);
94
+ }
95
+ return result.join('\n');
96
+ }
97
+ function matchedPattern(rules, filePath) {
98
+ const normalized = filePath.replace(/^\.\//, '');
99
+ for (const pattern of rules.patterns) {
100
+ try {
101
+ const testIg = createIgnore().add(pattern);
102
+ if (testIg.ignores(normalized))
103
+ return pattern;
104
+ }
105
+ catch {
106
+ // skip malformed patterns
107
+ }
108
+ }
109
+ return '(unknown pattern)';
110
+ }
111
+ //# sourceMappingURL=aiignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiignore.js","sourceRoot":"","sources":["../../src/core/aiignore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC/C,qEAAqE;AACrE,8DAA8D;AAC9D,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAQ,CAAA;AAC3C,8DAA8D;AAC9D,MAAM,YAAY,GAAc,OAAO,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAA;AAQ/F,MAAM,gBAAgB,GAAG;IACvB,UAAU;IACV,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,UAAU;IACV,cAAc;IACd,aAAa;IACb,cAAc;IACd,wBAAwB;IACxB,mBAAmB;IACnB,WAAW;IACX,gBAAgB;IAChB,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,oBAAoB;IACpB,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,UAAU;IACV,QAAQ;CACT,CAAA;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;IAC3C,IAAI,QAAQ,GAAG,CAAC,GAAG,gBAAgB,CAAC,CAAA;IAEpC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;aACrC,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAC5B,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAA;QACjD,QAAQ,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAA;IACpC,CAAC;IAED,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACvC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAoB,EAAE,QAAgB;IAC9D,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAChD,IAAI,CAAC;QACH,OAAO,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAoB,EAAE,IAAY;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,aAAa,GAAG,KAAK,CAAA;IACzB,IAAI,cAAc,GAAG,EAAE,CAAA;IAEvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAC9B,IAAI,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,CAAC;gBAC/B,aAAa,GAAG,IAAI,CAAA;gBACpB,cAAc,GAAG,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;gBAChD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACjB,MAAM,CAAC,IAAI,CAAC,kCAAkC,cAAc,GAAG,CAAC,CAAA;gBAChE,SAAQ;YACV,CAAC;iBAAM,CAAC;gBACN,aAAa,GAAG,KAAK,CAAA;gBACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACjB,SAAQ;YACV,CAAC;QACH,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC7D,aAAa,GAAG,KAAK,CAAA;gBACrB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnB,CAAC;YACD,SAAQ;QACV,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED,SAAS,cAAc,CAAC,KAAoB,EAAE,QAAgB;IAC5D,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;IAChD,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC1C,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;gBAAE,OAAO,OAAO,CAAA;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,mBAAmB,CAAA;AAC5B,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type ChangelogMetadata } from './schema.js';
2
+ export interface ChangelogEntry {
3
+ filename: string;
4
+ filepath: string;
5
+ metadata: ChangelogMetadata;
6
+ content: string;
7
+ }
8
+ export declare function changelogsDir(repoRoot: string): string;
9
+ export declare function errorsFile(repoRoot: string): string;
10
+ export declare function generateFilename(): string;
11
+ export declare function writeChangelog(repoRoot: string, content: string): string;
12
+ export declare function findChangelogForCommit(repoRoot: string, commitHash: string): ChangelogEntry | null;
13
+ export declare function listChangelogs(repoRoot: string, options?: {
14
+ limit?: number;
15
+ minimalOnly?: boolean;
16
+ }): ChangelogEntry[];
17
+ export declare function logError(repoRoot: string, message: string): void;
18
+ export declare function buildMinimalChangelog(options: {
19
+ commitHash: string;
20
+ branch: string;
21
+ author: string;
22
+ filesChanged: string[];
23
+ insertions: number;
24
+ deletions: number;
25
+ }): string;
26
+ //# sourceMappingURL=changelog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/core/changelog.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEnE,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAQzC;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAOxE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAiBlG;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,cAAc,EAAE,CA2BxB;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIhE;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,MAAM,CAiCT"}
@@ -0,0 +1,107 @@
1
+ import { readFileSync, writeFileSync, readdirSync, existsSync, mkdirSync, appendFileSync } from 'node:fs';
2
+ import { resolve, join } from 'node:path';
3
+ import { randomBytes } from 'node:crypto';
4
+ import { parseMetadata } from './schema.js';
5
+ export function changelogsDir(repoRoot) {
6
+ return resolve(repoRoot, '.ai', 'changelogs');
7
+ }
8
+ export function errorsFile(repoRoot) {
9
+ return resolve(repoRoot, '.ai', '.errors');
10
+ }
11
+ export function generateFilename() {
12
+ const now = new Date();
13
+ const ts = now.toISOString()
14
+ .replace(/:/g, '-') // filesystem-safe
15
+ .replace(/\..+$/, '') // drop milliseconds
16
+ .replace('T', 'T');
17
+ const suffix = randomBytes(2).toString('hex'); // 4-char hex suffix
18
+ return `changelog-${ts}Z-${suffix}.md`;
19
+ }
20
+ export function writeChangelog(repoRoot, content) {
21
+ const dir = changelogsDir(repoRoot);
22
+ mkdirSync(dir, { recursive: true });
23
+ const filename = generateFilename();
24
+ const filepath = join(dir, filename);
25
+ writeFileSync(filepath, content, 'utf8');
26
+ return filepath;
27
+ }
28
+ export function findChangelogForCommit(repoRoot, commitHash) {
29
+ const dir = changelogsDir(repoRoot);
30
+ if (!existsSync(dir))
31
+ return null;
32
+ const files = readdirSync(dir)
33
+ .filter(f => f.startsWith('changelog-') && f.endsWith('.md'))
34
+ .sort(); // timestamp prefix sorts chronologically
35
+ for (const filename of files) {
36
+ const filepath = join(dir, filename);
37
+ const content = readFileSync(filepath, 'utf8');
38
+ const metadata = parseMetadata(content);
39
+ if (metadata.commit === commitHash || metadata.commit?.startsWith(commitHash)) {
40
+ return { filename, filepath, metadata, content };
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+ export function listChangelogs(repoRoot, options = {}) {
46
+ const dir = changelogsDir(repoRoot);
47
+ if (!existsSync(dir))
48
+ return [];
49
+ const files = readdirSync(dir)
50
+ .filter(f => f.startsWith('changelog-') && f.endsWith('.md'))
51
+ .sort()
52
+ .reverse(); // newest first
53
+ const entries = [];
54
+ for (const filename of files) {
55
+ if (options.limit && entries.length >= options.limit)
56
+ break;
57
+ const filepath = join(dir, filename);
58
+ const content = readFileSync(filepath, 'utf8');
59
+ const metadata = parseMetadata(content);
60
+ if (options.minimalOnly) {
61
+ const isMinimal = metadata.aiTool === 'none' || metadata.sessionQuality === 'NO_AI';
62
+ if (!isMinimal)
63
+ continue;
64
+ }
65
+ entries.push({ filename, filepath, metadata, content });
66
+ }
67
+ return entries;
68
+ }
69
+ export function logError(repoRoot, message) {
70
+ const errFile = errorsFile(repoRoot);
71
+ const line = `[${new Date().toISOString()}] ${message}\n`;
72
+ appendFileSync(errFile, line, 'utf8');
73
+ }
74
+ export function buildMinimalChangelog(options) {
75
+ const { commitHash, branch, author, filesChanged, insertions, deletions } = options;
76
+ const now = new Date().toISOString();
77
+ return `# AI Changelog
78
+ Commit: ${commitHash}
79
+ Date: ${now}
80
+ Author: ${author}
81
+ Branch: ${branch}
82
+ AI-Tool: none
83
+ Session-Quality: NO_AI
84
+
85
+ ## What Changed
86
+ ${filesChanged.length} file(s) modified: ${filesChanged.slice(0, 10).join(', ')}${filesChanged.length > 10 ? ` and ${filesChanged.length - 10} more` : ''}. +${insertions}/-${deletions} lines.
87
+
88
+ ## Why (AI Context)
89
+ No AI tool active during this commit. This is a human-authored commit captured by the acs fallback hook. Context can be enriched later by running \`acs retry\` inside a Claude Code or Codex session.
90
+
91
+ ## Architectural Impact
92
+ Not assessed — no AI session context available. Run \`acs retry\` to enrich.
93
+
94
+ ## Patterns Used
95
+ Not assessed — no AI session context available.
96
+
97
+ ## Integration Points
98
+ Not assessed — no AI session context available.
99
+
100
+ ## Gotchas
101
+ Not assessed — no AI session context available.
102
+
103
+ ## How to Extend
104
+ Not assessed — no AI session context available.
105
+ `;
106
+ }
107
+ //# sourceMappingURL=changelog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changelog.js","sourceRoot":"","sources":["../../src/core/changelog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface AcsConfig {
2
+ llm_command: string | null;
3
+ llm_timeout_seconds: number;
4
+ why_token_budget: number;
5
+ skip_patterns: string[];
6
+ }
7
+ export declare function configPath(repoRoot: string): string;
8
+ export declare function loadConfig(repoRoot: string): AcsConfig;
9
+ export declare function saveConfig(repoRoot: string, config: AcsConfig): void;
10
+ export declare function updateConfig(repoRoot: string, patch: Partial<AcsConfig>): AcsConfig;
11
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,gBAAgB,EAAE,MAAM,CAAA;IACxB,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB;AASD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAStD;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAEpE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAKnF"}
@@ -0,0 +1,33 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ const DEFAULTS = {
4
+ llm_command: null,
5
+ llm_timeout_seconds: 60,
6
+ why_token_budget: 20000,
7
+ skip_patterns: [],
8
+ };
9
+ export function configPath(repoRoot) {
10
+ return resolve(repoRoot, 'acs.config.json');
11
+ }
12
+ export function loadConfig(repoRoot) {
13
+ const path = configPath(repoRoot);
14
+ if (!existsSync(path))
15
+ return { ...DEFAULTS };
16
+ try {
17
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
18
+ return { ...DEFAULTS, ...raw };
19
+ }
20
+ catch {
21
+ return { ...DEFAULTS };
22
+ }
23
+ }
24
+ export function saveConfig(repoRoot, config) {
25
+ writeFileSync(configPath(repoRoot), JSON.stringify(config, null, 2) + '\n', 'utf8');
26
+ }
27
+ export function updateConfig(repoRoot, patch) {
28
+ const current = loadConfig(repoRoot);
29
+ const updated = { ...current, ...patch };
30
+ saveConfig(repoRoot, updated);
31
+ return updated;
32
+ }
33
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AASnC,MAAM,QAAQ,GAAc;IAC1B,WAAW,EAAE,IAAI;IACjB,mBAAmB,EAAE,EAAE;IACvB,gBAAgB,EAAE,KAAK;IACvB,aAAa,EAAE,EAAE;CAClB,CAAA;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,OAAO,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAuB,CAAA;QACxE,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,GAAG,EAAE,CAAA;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAA;IACxB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,MAAiB;IAC5D,aAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACrF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,KAAyB;IACtE,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACpC,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,EAAE,CAAA;IACxC,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type AiToolId = 'claude-code' | 'codex' | 'gemini';
2
+ export interface DetectedTool {
3
+ id: AiToolId;
4
+ command: string;
5
+ skillsDir: string;
6
+ displayName: string;
7
+ }
8
+ export declare function detectInstalledTools(): DetectedTool[];
9
+ export declare function primaryLlmCommand(tools: DetectedTool[]): string | null;
10
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/core/detector.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEzD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,QAAQ,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;CACpB;AAyCD,wBAAgB,oBAAoB,IAAI,YAAY,EAAE,CASrD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,GAAG,IAAI,CAQtE"}