claude-auto 0.12.4
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/.claude-auto/.claude.hooks.json +25 -0
- package/.claude-auto/reminders/reminder-auto.md +145 -0
- package/.claude-auto/reminders/reminder-documentation.md +30 -0
- package/.claude-auto/reminders/reminder-emergent-design.md +41 -0
- package/.claude-auto/reminders/reminder-extreme-ownership.md +27 -0
- package/.claude-auto/reminders/reminder-ide-diagnostics.md +25 -0
- package/.claude-auto/reminders/reminder-parallelization.md +27 -0
- package/.claude-auto/reminders/reminder-rethink-after-revert.md +25 -0
- package/.claude-auto/reminders/reminder-sub-agent-rules.md +27 -0
- package/.claude-auto/reminders/reminder-test-title-matches-spec.md +37 -0
- package/.claude-auto/validators/appeal-system.md +55 -0
- package/.claude-auto/validators/backwards-compat.md +33 -0
- package/.claude-auto/validators/burst-atomicity.md +37 -0
- package/.claude-auto/validators/coverage-rules.md +34 -0
- package/.claude-auto/validators/dead-code.md +36 -0
- package/.claude-auto/validators/hygiene.md +34 -0
- package/.claude-auto/validators/infra-commit-format.md +37 -0
- package/.claude-auto/validators/ketchup-plan-format.md +42 -0
- package/.claude-auto/validators/new-code-requires-tests.md +36 -0
- package/.claude-auto/validators/no-comments.md +35 -0
- package/.claude-auto/validators/no-dangerous-git.md +35 -0
- package/.claude-auto/validators/tcr-workflow.md +31 -0
- package/.claude-auto/validators/testing-no-state-peeking.md +37 -0
- package/.claude-auto/validators/testing-structure.md +37 -0
- package/.claude-auto/validators/testing-stubs-over-mocks.md +42 -0
- package/.claude-auto/validators/testing-weak-assertions.md +36 -0
- package/.claude-auto/validators/type-organization.md +30 -0
- package/README.md +172 -0
- package/bin/cli.ts +6 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +7 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bundle/scripts/auto-continue.js +5045 -0
- package/dist/bundle/scripts/pre-tool-use.js +11719 -0
- package/dist/bundle/scripts/session-start.js +8571 -0
- package/dist/bundle/scripts/user-prompt-submit.js +8585 -0
- package/dist/scripts/auto-continue.d.ts +3 -0
- package/dist/scripts/auto-continue.d.ts.map +1 -0
- package/dist/scripts/auto-continue.js +65 -0
- package/dist/scripts/auto-continue.js.map +1 -0
- package/dist/scripts/generate-changeset.d.ts +13 -0
- package/dist/scripts/generate-changeset.d.ts.map +1 -0
- package/dist/scripts/generate-changeset.js +322 -0
- package/dist/scripts/generate-changeset.js.map +1 -0
- package/dist/scripts/pre-tool-use.d.ts +3 -0
- package/dist/scripts/pre-tool-use.d.ts.map +1 -0
- package/dist/scripts/pre-tool-use.js +78 -0
- package/dist/scripts/pre-tool-use.js.map +1 -0
- package/dist/scripts/session-start.d.ts +3 -0
- package/dist/scripts/session-start.d.ts.map +1 -0
- package/dist/scripts/session-start.js +76 -0
- package/dist/scripts/session-start.js.map +1 -0
- package/dist/scripts/user-prompt-submit.d.ts +3 -0
- package/dist/scripts/user-prompt-submit.d.ts.map +1 -0
- package/dist/scripts/user-prompt-submit.js +76 -0
- package/dist/scripts/user-prompt-submit.js.map +1 -0
- package/dist/src/activity-logger.d.ts +2 -0
- package/dist/src/activity-logger.d.ts.map +1 -0
- package/dist/src/activity-logger.js +47 -0
- package/dist/src/activity-logger.js.map +1 -0
- package/dist/src/activity-logger.test.d.ts +2 -0
- package/dist/src/activity-logger.test.d.ts.map +1 -0
- package/dist/src/activity-logger.test.js +121 -0
- package/dist/src/activity-logger.test.js.map +1 -0
- package/dist/src/clean-logs.d.ts +6 -0
- package/dist/src/clean-logs.d.ts.map +1 -0
- package/dist/src/clean-logs.js +38 -0
- package/dist/src/clean-logs.js.map +1 -0
- package/dist/src/clean-logs.test.d.ts +2 -0
- package/dist/src/clean-logs.test.d.ts.map +1 -0
- package/dist/src/clean-logs.test.js +101 -0
- package/dist/src/clean-logs.test.js.map +1 -0
- package/dist/src/cli/cli.d.ts +3 -0
- package/dist/src/cli/cli.d.ts.map +1 -0
- package/dist/src/cli/cli.js +32 -0
- package/dist/src/cli/cli.js.map +1 -0
- package/dist/src/cli/cli.test.d.ts +2 -0
- package/dist/src/cli/cli.test.d.ts.map +1 -0
- package/dist/src/cli/cli.test.js +27 -0
- package/dist/src/cli/cli.test.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +7 -0
- package/dist/src/cli/doctor.d.ts.map +1 -0
- package/dist/src/cli/doctor.js +67 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/doctor.test.d.ts +2 -0
- package/dist/src/cli/doctor.test.d.ts.map +1 -0
- package/dist/src/cli/doctor.test.js +87 -0
- package/dist/src/cli/doctor.test.js.map +1 -0
- package/dist/src/cli/install.d.ts +10 -0
- package/dist/src/cli/install.d.ts.map +1 -0
- package/dist/src/cli/install.js +116 -0
- package/dist/src/cli/install.js.map +1 -0
- package/dist/src/cli/install.test.d.ts +2 -0
- package/dist/src/cli/install.test.d.ts.map +1 -0
- package/dist/src/cli/install.test.js +217 -0
- package/dist/src/cli/install.test.js.map +1 -0
- package/dist/src/cli/reminders.d.ts +12 -0
- package/dist/src/cli/reminders.d.ts.map +1 -0
- package/dist/src/cli/reminders.js +52 -0
- package/dist/src/cli/reminders.js.map +1 -0
- package/dist/src/cli/reminders.test.d.ts +2 -0
- package/dist/src/cli/reminders.test.d.ts.map +1 -0
- package/dist/src/cli/reminders.test.js +72 -0
- package/dist/src/cli/reminders.test.js.map +1 -0
- package/dist/src/cli/repair.d.ts +11 -0
- package/dist/src/cli/repair.d.ts.map +1 -0
- package/dist/src/cli/repair.js +91 -0
- package/dist/src/cli/repair.js.map +1 -0
- package/dist/src/cli/repair.test.d.ts +2 -0
- package/dist/src/cli/repair.test.d.ts.map +1 -0
- package/dist/src/cli/repair.test.js +95 -0
- package/dist/src/cli/repair.test.js.map +1 -0
- package/dist/src/cli/status.d.ts +10 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +55 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/cli/status.test.d.ts +2 -0
- package/dist/src/cli/status.test.d.ts.map +1 -0
- package/dist/src/cli/status.test.js +80 -0
- package/dist/src/cli/status.test.js.map +1 -0
- package/dist/src/clue-collector.d.ts +23 -0
- package/dist/src/clue-collector.d.ts.map +1 -0
- package/dist/src/clue-collector.js +221 -0
- package/dist/src/clue-collector.js.map +1 -0
- package/dist/src/clue-collector.test.d.ts +2 -0
- package/dist/src/clue-collector.test.d.ts.map +1 -0
- package/dist/src/clue-collector.test.js +278 -0
- package/dist/src/clue-collector.test.js.map +1 -0
- package/dist/src/commit-validator.d.ts +53 -0
- package/dist/src/commit-validator.d.ts.map +1 -0
- package/dist/src/commit-validator.js +356 -0
- package/dist/src/commit-validator.js.map +1 -0
- package/dist/src/commit-validator.test.d.ts +2 -0
- package/dist/src/commit-validator.test.d.ts.map +1 -0
- package/dist/src/commit-validator.test.js +733 -0
- package/dist/src/commit-validator.test.js.map +1 -0
- package/dist/src/config-loader.d.ts +15 -0
- package/dist/src/config-loader.d.ts.map +1 -0
- package/dist/src/config-loader.js +12 -0
- package/dist/src/config-loader.js.map +1 -0
- package/dist/src/config-loader.test.d.ts +2 -0
- package/dist/src/config-loader.test.d.ts.map +1 -0
- package/dist/src/config-loader.test.js +69 -0
- package/dist/src/config-loader.test.js.map +1 -0
- package/dist/src/debug-logger.d.ts +2 -0
- package/dist/src/debug-logger.d.ts.map +1 -0
- package/dist/src/debug-logger.js +23 -0
- package/dist/src/debug-logger.js.map +1 -0
- package/dist/src/debug-logger.test.d.ts +2 -0
- package/dist/src/debug-logger.test.d.ts.map +1 -0
- package/dist/src/debug-logger.test.js +63 -0
- package/dist/src/debug-logger.test.js.map +1 -0
- package/dist/src/default-validators.test.d.ts +2 -0
- package/dist/src/default-validators.test.d.ts.map +1 -0
- package/dist/src/default-validators.test.js +119 -0
- package/dist/src/default-validators.test.js.map +1 -0
- package/dist/src/deny-list.d.ts +3 -0
- package/dist/src/deny-list.d.ts.map +1 -0
- package/dist/src/deny-list.js +62 -0
- package/dist/src/deny-list.js.map +1 -0
- package/dist/src/deny-list.test.d.ts +2 -0
- package/dist/src/deny-list.test.d.ts.map +1 -0
- package/dist/src/deny-list.test.js +93 -0
- package/dist/src/deny-list.test.js.map +1 -0
- package/dist/src/e2e.test.d.ts +2 -0
- package/dist/src/e2e.test.d.ts.map +1 -0
- package/dist/src/e2e.test.js +82 -0
- package/dist/src/e2e.test.js.map +1 -0
- package/dist/src/gitignore-manager.d.ts +2 -0
- package/dist/src/gitignore-manager.d.ts.map +1 -0
- package/dist/src/gitignore-manager.js +45 -0
- package/dist/src/gitignore-manager.js.map +1 -0
- package/dist/src/gitignore-manager.test.d.ts +2 -0
- package/dist/src/gitignore-manager.test.d.ts.map +1 -0
- package/dist/src/gitignore-manager.test.js +65 -0
- package/dist/src/gitignore-manager.test.js.map +1 -0
- package/dist/src/hook-input.d.ts +9 -0
- package/dist/src/hook-input.d.ts.map +1 -0
- package/dist/src/hook-input.js +7 -0
- package/dist/src/hook-input.js.map +1 -0
- package/dist/src/hook-input.test.d.ts +2 -0
- package/dist/src/hook-input.test.d.ts.map +1 -0
- package/dist/src/hook-input.test.js +20 -0
- package/dist/src/hook-input.test.js.map +1 -0
- package/dist/src/hook-logger.d.ts +16 -0
- package/dist/src/hook-logger.d.ts.map +1 -0
- package/dist/src/hook-logger.js +90 -0
- package/dist/src/hook-logger.js.map +1 -0
- package/dist/src/hook-logger.test.d.ts +2 -0
- package/dist/src/hook-logger.test.d.ts.map +1 -0
- package/dist/src/hook-logger.test.js +205 -0
- package/dist/src/hook-logger.test.js.map +1 -0
- package/dist/src/hook-state.d.ts +44 -0
- package/dist/src/hook-state.d.ts.map +1 -0
- package/dist/src/hook-state.js +128 -0
- package/dist/src/hook-state.js.map +1 -0
- package/dist/src/hook-state.test.d.ts +2 -0
- package/dist/src/hook-state.test.d.ts.map +1 -0
- package/dist/src/hook-state.test.js +204 -0
- package/dist/src/hook-state.test.js.map +1 -0
- package/dist/src/hooks/auto-continue.d.ts +21 -0
- package/dist/src/hooks/auto-continue.d.ts.map +1 -0
- package/dist/src/hooks/auto-continue.js +70 -0
- package/dist/src/hooks/auto-continue.js.map +1 -0
- package/dist/src/hooks/auto-continue.test.d.ts +2 -0
- package/dist/src/hooks/auto-continue.test.d.ts.map +1 -0
- package/dist/src/hooks/auto-continue.test.js +171 -0
- package/dist/src/hooks/auto-continue.test.js.map +1 -0
- package/dist/src/hooks/pre-tool-use.d.ts +14 -0
- package/dist/src/hooks/pre-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/pre-tool-use.js +66 -0
- package/dist/src/hooks/pre-tool-use.js.map +1 -0
- package/dist/src/hooks/pre-tool-use.test.d.ts +2 -0
- package/dist/src/hooks/pre-tool-use.test.d.ts.map +1 -0
- package/dist/src/hooks/pre-tool-use.test.js +255 -0
- package/dist/src/hooks/pre-tool-use.test.js.map +1 -0
- package/dist/src/hooks/session-start.d.ts +20 -0
- package/dist/src/hooks/session-start.d.ts.map +1 -0
- package/dist/src/hooks/session-start.js +27 -0
- package/dist/src/hooks/session-start.js.map +1 -0
- package/dist/src/hooks/session-start.test.d.ts +2 -0
- package/dist/src/hooks/session-start.test.d.ts.map +1 -0
- package/dist/src/hooks/session-start.test.js +125 -0
- package/dist/src/hooks/session-start.test.js.map +1 -0
- package/dist/src/hooks/user-prompt-submit.d.ts +17 -0
- package/dist/src/hooks/user-prompt-submit.d.ts.map +1 -0
- package/dist/src/hooks/user-prompt-submit.js +28 -0
- package/dist/src/hooks/user-prompt-submit.js.map +1 -0
- package/dist/src/hooks/user-prompt-submit.test.d.ts +2 -0
- package/dist/src/hooks/user-prompt-submit.test.d.ts.map +1 -0
- package/dist/src/hooks/user-prompt-submit.test.js +119 -0
- package/dist/src/hooks/user-prompt-submit.test.js.map +1 -0
- package/dist/src/hooks/validate-commit.d.ts +12 -0
- package/dist/src/hooks/validate-commit.d.ts.map +1 -0
- package/dist/src/hooks/validate-commit.js +58 -0
- package/dist/src/hooks/validate-commit.js.map +1 -0
- package/dist/src/hooks/validate-commit.test.d.ts +2 -0
- package/dist/src/hooks/validate-commit.test.d.ts.map +1 -0
- package/dist/src/hooks/validate-commit.test.js +150 -0
- package/dist/src/hooks/validate-commit.test.js.map +1 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +42 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/linker.d.ts +6 -0
- package/dist/src/linker.d.ts.map +1 -0
- package/dist/src/linker.js +78 -0
- package/dist/src/linker.js.map +1 -0
- package/dist/src/linker.test.d.ts +2 -0
- package/dist/src/linker.test.d.ts.map +1 -0
- package/dist/src/linker.test.js +192 -0
- package/dist/src/linker.test.js.map +1 -0
- package/dist/src/logger.d.ts +21 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +117 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/logger.test.d.ts +2 -0
- package/dist/src/logger.test.d.ts.map +1 -0
- package/dist/src/logger.test.js +159 -0
- package/dist/src/logger.test.js.map +1 -0
- package/dist/src/path-resolver.d.ts +9 -0
- package/dist/src/path-resolver.d.ts.map +1 -0
- package/dist/src/path-resolver.js +52 -0
- package/dist/src/path-resolver.js.map +1 -0
- package/dist/src/reminder-loader.d.ts +24 -0
- package/dist/src/reminder-loader.d.ts.map +1 -0
- package/dist/src/reminder-loader.js +84 -0
- package/dist/src/reminder-loader.js.map +1 -0
- package/dist/src/reminder-loader.test.d.ts +2 -0
- package/dist/src/reminder-loader.test.d.ts.map +1 -0
- package/dist/src/reminder-loader.test.js +152 -0
- package/dist/src/reminder-loader.test.js.map +1 -0
- package/dist/src/root-finder.d.ts +2 -0
- package/dist/src/root-finder.d.ts.map +1 -0
- package/dist/src/root-finder.js +71 -0
- package/dist/src/root-finder.js.map +1 -0
- package/dist/src/root-finder.test.d.ts +2 -0
- package/dist/src/root-finder.test.d.ts.map +1 -0
- package/dist/src/root-finder.test.js +111 -0
- package/dist/src/root-finder.test.js.map +1 -0
- package/dist/src/settings-merger.d.ts +2 -0
- package/dist/src/settings-merger.d.ts.map +1 -0
- package/dist/src/settings-merger.js +133 -0
- package/dist/src/settings-merger.js.map +1 -0
- package/dist/src/settings-merger.test.d.ts +2 -0
- package/dist/src/settings-merger.test.d.ts.map +1 -0
- package/dist/src/settings-merger.test.js +379 -0
- package/dist/src/settings-merger.test.js.map +1 -0
- package/dist/src/settings-template.test.d.ts +2 -0
- package/dist/src/settings-template.test.d.ts.map +1 -0
- package/dist/src/settings-template.test.js +88 -0
- package/dist/src/settings-template.test.js.map +1 -0
- package/dist/src/state-manager.d.ts +5 -0
- package/dist/src/state-manager.d.ts.map +1 -0
- package/dist/src/state-manager.js +55 -0
- package/dist/src/state-manager.js.map +1 -0
- package/dist/src/state-manager.test.d.ts +2 -0
- package/dist/src/state-manager.test.d.ts.map +1 -0
- package/dist/src/state-manager.test.js +85 -0
- package/dist/src/state-manager.test.js.map +1 -0
- package/dist/src/subagent-classifier.d.ts +4 -0
- package/dist/src/subagent-classifier.d.ts.map +1 -0
- package/dist/src/subagent-classifier.js +53 -0
- package/dist/src/subagent-classifier.js.map +1 -0
- package/dist/src/subagent-classifier.test.d.ts +2 -0
- package/dist/src/subagent-classifier.test.d.ts.map +1 -0
- package/dist/src/subagent-classifier.test.js +84 -0
- package/dist/src/subagent-classifier.test.js.map +1 -0
- package/dist/src/validator-loader.d.ts +9 -0
- package/dist/src/validator-loader.d.ts.map +1 -0
- package/dist/src/validator-loader.js +71 -0
- package/dist/src/validator-loader.js.map +1 -0
- package/dist/src/validator-loader.test.d.ts +2 -0
- package/dist/src/validator-loader.test.d.ts.map +1 -0
- package/dist/src/validator-loader.test.js +140 -0
- package/dist/src/validator-loader.test.js.map +1 -0
- package/package.json +91 -0
- package/scripts/auto-continue.ts +39 -0
- package/scripts/generate-changeset.ts +405 -0
- package/scripts/pre-tool-use.ts +44 -0
- package/scripts/session-start.ts +42 -0
- package/scripts/tail-logs.sh +17 -0
- package/scripts/test-hooks.sh +910 -0
- package/scripts/user-prompt-submit.ts +42 -0
- package/templates/settings.json +48 -0
- package/templates/settings.local.json +48 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("node:fs"));
|
|
37
|
+
const os = __importStar(require("node:os"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const vitest_1 = require("vitest");
|
|
40
|
+
const validator_loader_js_1 = require("./validator-loader.js");
|
|
41
|
+
(0, vitest_1.describe)('loadValidators', () => {
|
|
42
|
+
let tempDir;
|
|
43
|
+
(0, vitest_1.beforeEach)(() => {
|
|
44
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ketchup-validators-'));
|
|
45
|
+
});
|
|
46
|
+
(0, vitest_1.afterEach)(() => {
|
|
47
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)('returns empty array when directory does not exist', () => {
|
|
50
|
+
const nonExistentDir = path.join(tempDir, 'validators');
|
|
51
|
+
const result = (0, validator_loader_js_1.loadValidators)([nonExistentDir]);
|
|
52
|
+
(0, vitest_1.expect)(result).toEqual([]);
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.it)('parses single .md file with frontmatter', () => {
|
|
55
|
+
const validatorsDir = path.join(tempDir, 'validators');
|
|
56
|
+
fs.mkdirSync(validatorsDir);
|
|
57
|
+
const validatorContent = `---
|
|
58
|
+
name: test-validator
|
|
59
|
+
description: A test validator
|
|
60
|
+
enabled: true
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
Check that tests pass.
|
|
64
|
+
|
|
65
|
+
Respond with JSON: {"decision":"ACK"} or {"decision":"NACK","reason":"..."}`;
|
|
66
|
+
fs.writeFileSync(path.join(validatorsDir, 'test.md'), validatorContent);
|
|
67
|
+
const result = (0, validator_loader_js_1.loadValidators)([validatorsDir]);
|
|
68
|
+
(0, vitest_1.expect)(result).toEqual([
|
|
69
|
+
{
|
|
70
|
+
name: 'test-validator',
|
|
71
|
+
description: 'A test validator',
|
|
72
|
+
enabled: true,
|
|
73
|
+
content: 'Check that tests pass.\n\nRespond with JSON: {"decision":"ACK"} or {"decision":"NACK","reason":"..."}',
|
|
74
|
+
path: path.join(validatorsDir, 'test.md'),
|
|
75
|
+
},
|
|
76
|
+
]);
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('filters disabled validators', () => {
|
|
79
|
+
const validatorsDir = path.join(tempDir, 'validators');
|
|
80
|
+
fs.mkdirSync(validatorsDir);
|
|
81
|
+
fs.writeFileSync(path.join(validatorsDir, 'enabled.md'), `---
|
|
82
|
+
name: enabled-validator
|
|
83
|
+
description: Enabled
|
|
84
|
+
enabled: true
|
|
85
|
+
---
|
|
86
|
+
Content`);
|
|
87
|
+
fs.writeFileSync(path.join(validatorsDir, 'disabled.md'), `---
|
|
88
|
+
name: disabled-validator
|
|
89
|
+
description: Disabled
|
|
90
|
+
enabled: false
|
|
91
|
+
---
|
|
92
|
+
Content`);
|
|
93
|
+
const result = (0, validator_loader_js_1.loadValidators)([validatorsDir]);
|
|
94
|
+
(0, vitest_1.expect)(result).toEqual([
|
|
95
|
+
{
|
|
96
|
+
name: 'enabled-validator',
|
|
97
|
+
description: 'Enabled',
|
|
98
|
+
enabled: true,
|
|
99
|
+
content: 'Content',
|
|
100
|
+
path: path.join(validatorsDir, 'enabled.md'),
|
|
101
|
+
},
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
(0, vitest_1.it)('loads from multiple directories', () => {
|
|
105
|
+
const dir1 = path.join(tempDir, 'validators1');
|
|
106
|
+
const dir2 = path.join(tempDir, 'validators2');
|
|
107
|
+
fs.mkdirSync(dir1);
|
|
108
|
+
fs.mkdirSync(dir2);
|
|
109
|
+
fs.writeFileSync(path.join(dir1, 'first.md'), `---
|
|
110
|
+
name: first
|
|
111
|
+
description: First validator
|
|
112
|
+
enabled: true
|
|
113
|
+
---
|
|
114
|
+
First content`);
|
|
115
|
+
fs.writeFileSync(path.join(dir2, 'second.md'), `---
|
|
116
|
+
name: second
|
|
117
|
+
description: Second validator
|
|
118
|
+
enabled: true
|
|
119
|
+
---
|
|
120
|
+
Second content`);
|
|
121
|
+
const result = (0, validator_loader_js_1.loadValidators)([dir1, dir2]);
|
|
122
|
+
(0, vitest_1.expect)(result).toEqual([
|
|
123
|
+
{
|
|
124
|
+
name: 'first',
|
|
125
|
+
description: 'First validator',
|
|
126
|
+
enabled: true,
|
|
127
|
+
content: 'First content',
|
|
128
|
+
path: path.join(dir1, 'first.md'),
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'second',
|
|
132
|
+
description: 'Second validator',
|
|
133
|
+
enabled: true,
|
|
134
|
+
content: 'Second content',
|
|
135
|
+
path: path.join(dir2, 'second.md'),
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=validator-loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator-loader.test.js","sourceRoot":"","sources":["../../src/validator-loader.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-auto",
|
|
3
|
+
"version": "0.12.4",
|
|
4
|
+
"authors": [
|
|
5
|
+
{
|
|
6
|
+
"name": "Sam Hatoum"
|
|
7
|
+
}
|
|
8
|
+
],
|
|
9
|
+
"description": "Husky-style hooks and skills management for Claude Code",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/BeOnAuto/claude-auto.git"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"registry": "https://registry.npmjs.org",
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"main": "dist/src/index.js",
|
|
19
|
+
"types": "dist/src/index.d.ts",
|
|
20
|
+
"bin": {
|
|
21
|
+
"claude-auto": "dist/bin/cli.js"
|
|
22
|
+
},
|
|
23
|
+
"lint-staged": {
|
|
24
|
+
"*.{ts,tsx,json,md}": [
|
|
25
|
+
"biome check --write --no-errors-on-unmatched"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"claude",
|
|
30
|
+
"claude-code",
|
|
31
|
+
"hooks",
|
|
32
|
+
"skills",
|
|
33
|
+
"automation"
|
|
34
|
+
],
|
|
35
|
+
"author": "Sam Hatoum",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"commander": "^12.0.0",
|
|
39
|
+
"cosmiconfig": "^9.0.0",
|
|
40
|
+
"gray-matter": "^4.0.3",
|
|
41
|
+
"micromatch": "^4.0.8",
|
|
42
|
+
"yaml": "^2.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@biomejs/biome": "^2.3.11",
|
|
46
|
+
"@changesets/changelog-github": "^0.5.2",
|
|
47
|
+
"@changesets/cli": "^2.29.8",
|
|
48
|
+
"@commitlint/cli": "^20.3.1",
|
|
49
|
+
"@commitlint/config-conventional": "^20.3.1",
|
|
50
|
+
"@types/micromatch": "^4.0.10",
|
|
51
|
+
"@types/node": "^20.0.0",
|
|
52
|
+
"@vitest/coverage-v8": "^1.6.1",
|
|
53
|
+
"esbuild": "^0.27.2",
|
|
54
|
+
"husky": "^9.1.7",
|
|
55
|
+
"lint-staged": "^16.2.7",
|
|
56
|
+
"tsx": "^4.0.0",
|
|
57
|
+
"turbo": "^2.7.5",
|
|
58
|
+
"typescript": "^5.0.0",
|
|
59
|
+
"vitepress": "^1.6.4",
|
|
60
|
+
"vitest": "^1.0.0"
|
|
61
|
+
},
|
|
62
|
+
"files": [
|
|
63
|
+
"dist/",
|
|
64
|
+
"bin/",
|
|
65
|
+
"templates/",
|
|
66
|
+
"scripts/",
|
|
67
|
+
"commands/",
|
|
68
|
+
".claude-auto/"
|
|
69
|
+
],
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=18.0.0"
|
|
72
|
+
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"build": "tsc && pnpm build:bundle",
|
|
75
|
+
"build:bundle": "esbuild scripts/session-start.ts scripts/pre-tool-use.ts scripts/user-prompt-submit.ts scripts/auto-continue.ts --bundle --platform=node --target=node18 --format=cjs --outdir=dist/bundle/scripts --external:typescript",
|
|
76
|
+
"test": "vitest run",
|
|
77
|
+
"test:watch": "vitest",
|
|
78
|
+
"type-check": "tsc --noEmit",
|
|
79
|
+
"lint": "biome check .",
|
|
80
|
+
"lint:fix": "biome check --write .",
|
|
81
|
+
"format": "biome format --write .",
|
|
82
|
+
"check": "turbo run build type-check test && pnpm lint",
|
|
83
|
+
"changeset": "changeset",
|
|
84
|
+
"version": "changeset version",
|
|
85
|
+
"release": "pnpm publish",
|
|
86
|
+
"docs:dev": "vitepress dev docs",
|
|
87
|
+
"docs:build": "vitepress build docs",
|
|
88
|
+
"docs:preview": "vitepress preview docs",
|
|
89
|
+
"install:local": "pnpm tsx bin/cli.ts install --local"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { writeHookLog } from '../src/hook-logger.js';
|
|
6
|
+
import { handleStop, type StopHookInput } from '../src/hooks/auto-continue.js';
|
|
7
|
+
import { resolvePaths } from '../src/path-resolver.js';
|
|
8
|
+
|
|
9
|
+
const claudeDir = path.resolve(process.cwd(), '.claude');
|
|
10
|
+
const stdin = fs.readFileSync(0, 'utf8').trim();
|
|
11
|
+
|
|
12
|
+
if (!stdin) {
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const input: StopHookInput = JSON.parse(stdin);
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
|
|
19
|
+
(async () => {
|
|
20
|
+
const { autoDir } = await resolvePaths(claudeDir);
|
|
21
|
+
const result = handleStop(autoDir, input);
|
|
22
|
+
|
|
23
|
+
const output =
|
|
24
|
+
result.decision === 'block' ? { stopReason: result.reason, forceResult: { behaviour: 'block' } } : null;
|
|
25
|
+
|
|
26
|
+
writeHookLog(autoDir, {
|
|
27
|
+
hookName: 'auto-continue',
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
input,
|
|
30
|
+
output: output ?? { decision: result.decision, reason: result.reason },
|
|
31
|
+
durationMs: Date.now() - startTime,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (output) {
|
|
35
|
+
console.log(JSON.stringify(output));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
process.exit(0);
|
|
39
|
+
})();
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* AI-powered changeset generation script
|
|
4
|
+
*
|
|
5
|
+
* This script:
|
|
6
|
+
* 1. Gets commits since last changeset/tag
|
|
7
|
+
* 2. Parses conventional commits (feat/fix/etc)
|
|
8
|
+
* 3. Determines bump type (breakingāmajor, featāminor, elseāpatch)
|
|
9
|
+
* 4. Generates changelog via Claude CLI (with simple fallback)
|
|
10
|
+
* 5. Creates .changeset/*.md file
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { execSync } from 'node:child_process';
|
|
14
|
+
import { randomBytes } from 'node:crypto';
|
|
15
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
|
|
18
|
+
// Exit codes
|
|
19
|
+
const EXIT_CODE = {
|
|
20
|
+
SUCCESS: 0,
|
|
21
|
+
ERROR: 1,
|
|
22
|
+
NO_COMMITS: 11,
|
|
23
|
+
NO_CONVENTIONAL_COMMITS: 12,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Types
|
|
27
|
+
type CommitType =
|
|
28
|
+
| 'feat'
|
|
29
|
+
| 'fix'
|
|
30
|
+
| 'docs'
|
|
31
|
+
| 'style'
|
|
32
|
+
| 'refactor'
|
|
33
|
+
| 'perf'
|
|
34
|
+
| 'test'
|
|
35
|
+
| 'build'
|
|
36
|
+
| 'ci'
|
|
37
|
+
| 'chore'
|
|
38
|
+
| 'revert';
|
|
39
|
+
type BumpType = 'major' | 'minor' | 'patch';
|
|
40
|
+
|
|
41
|
+
interface ConventionalCommit {
|
|
42
|
+
hash: string;
|
|
43
|
+
type: CommitType;
|
|
44
|
+
scope?: string;
|
|
45
|
+
subject: string;
|
|
46
|
+
body?: string;
|
|
47
|
+
breaking: boolean;
|
|
48
|
+
fullMessage: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Conventional commit pattern
|
|
52
|
+
const CONVENTIONAL_PATTERN = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(([^)]+)\))?: (.+)/;
|
|
53
|
+
|
|
54
|
+
// Configuration
|
|
55
|
+
const CHANGESET_DIR = '.changeset';
|
|
56
|
+
const PACKAGE_NAME = 'claude-auto';
|
|
57
|
+
|
|
58
|
+
// Logging utilities
|
|
59
|
+
function logStep(message: string): void {
|
|
60
|
+
console.log(`\nš ${message}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function logInfo(message: string): void {
|
|
64
|
+
console.log(` ${message}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function logSuccess(message: string): void {
|
|
68
|
+
console.log(`ā
${message}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function logWarning(message: string): void {
|
|
72
|
+
console.warn(`ā ļø ${message}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function logError(message: string): void {
|
|
76
|
+
console.error(`ā ${message}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Git utilities
|
|
80
|
+
function isGitRepository(): boolean {
|
|
81
|
+
try {
|
|
82
|
+
execSync('git rev-parse --git-dir', { stdio: 'pipe' });
|
|
83
|
+
return true;
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function getCommitMessage(hash: string): string {
|
|
90
|
+
return execSync(`git log -1 --format=%B ${hash}`, { encoding: 'utf8' }).trim();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getCommitsSinceLastChangeset(): string[] {
|
|
94
|
+
try {
|
|
95
|
+
const changesetPath = join(process.cwd(), CHANGESET_DIR);
|
|
96
|
+
|
|
97
|
+
if (!existsSync(changesetPath)) {
|
|
98
|
+
return getCommitsSinceLastTag();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const files = readdirSync(changesetPath).filter((f) => f.endsWith('.md') && f !== 'README.md');
|
|
102
|
+
|
|
103
|
+
if (files.length === 0) {
|
|
104
|
+
return getCommitsSinceLastTag();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Get the most recent changeset file by git commit time
|
|
108
|
+
const latestChangeset = files
|
|
109
|
+
.map((f) => {
|
|
110
|
+
try {
|
|
111
|
+
const time = execSync(`git log -1 --format=%ct -- ${CHANGESET_DIR}/${f}`, {
|
|
112
|
+
encoding: 'utf8',
|
|
113
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
114
|
+
}).trim();
|
|
115
|
+
return { file: f, time: Number(time) || 0 };
|
|
116
|
+
} catch {
|
|
117
|
+
return { file: f, time: 0 };
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
.filter((f) => f.time > 0)
|
|
121
|
+
.sort((a, b) => b.time - a.time)[0];
|
|
122
|
+
|
|
123
|
+
if (!latestChangeset) {
|
|
124
|
+
return getCommitsSinceLastTag();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Get commits since that changeset was added
|
|
128
|
+
const changesetCommit = execSync(`git log -1 --format=%H -- ${CHANGESET_DIR}/${latestChangeset.file}`, {
|
|
129
|
+
encoding: 'utf8',
|
|
130
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
131
|
+
}).trim();
|
|
132
|
+
|
|
133
|
+
return getCommitsInRange(changesetCommit, 'HEAD');
|
|
134
|
+
} catch (error) {
|
|
135
|
+
logWarning(`Could not get commits since last changeset: ${(error as Error).message}`);
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getCommitsInRange(since: string, until = 'HEAD'): string[] {
|
|
141
|
+
try {
|
|
142
|
+
const output = execSync(`git log ${since}..${until} --format=%H`, {
|
|
143
|
+
encoding: 'utf8',
|
|
144
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
145
|
+
}).trim();
|
|
146
|
+
|
|
147
|
+
return output ? output.split('\n').filter(Boolean) : [];
|
|
148
|
+
} catch {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function getCommitsSinceLastTag(): string[] {
|
|
154
|
+
try {
|
|
155
|
+
const lastTag = execSync('git describe --tags --abbrev=0', {
|
|
156
|
+
encoding: 'utf8',
|
|
157
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
158
|
+
}).trim();
|
|
159
|
+
|
|
160
|
+
return getCommitsInRange(lastTag, 'HEAD');
|
|
161
|
+
} catch {
|
|
162
|
+
// No tags exist, get recent commits (limit to 50)
|
|
163
|
+
try {
|
|
164
|
+
const output = execSync('git log -50 --format=%H', {
|
|
165
|
+
encoding: 'utf8',
|
|
166
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
167
|
+
}).trim();
|
|
168
|
+
|
|
169
|
+
return output ? output.split('\n').filter(Boolean) : [];
|
|
170
|
+
} catch {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Parsing utilities
|
|
177
|
+
function parseConventionalCommit(hash: string): ConventionalCommit | null {
|
|
178
|
+
try {
|
|
179
|
+
const fullMessage = getCommitMessage(hash);
|
|
180
|
+
const match = fullMessage.match(CONVENTIONAL_PATTERN);
|
|
181
|
+
|
|
182
|
+
if (!match) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const [, type, , scope, subject] = match;
|
|
187
|
+
const body = fullMessage.split('\n').slice(1).join('\n').trim();
|
|
188
|
+
const breaking = fullMessage.includes('BREAKING CHANGE:') || fullMessage.includes('!:');
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
hash,
|
|
192
|
+
type: type as CommitType,
|
|
193
|
+
scope,
|
|
194
|
+
subject,
|
|
195
|
+
body,
|
|
196
|
+
breaking,
|
|
197
|
+
fullMessage,
|
|
198
|
+
};
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function parseConventionalCommits(hashes: string[]): ConventionalCommit[] {
|
|
205
|
+
return hashes.map((hash) => parseConventionalCommit(hash)).filter((c): c is ConventionalCommit => c !== null);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Semver utilities
|
|
209
|
+
function determineBumpType(commits: ConventionalCommit[]): BumpType {
|
|
210
|
+
if (commits.some((c) => c.breaking)) {
|
|
211
|
+
return 'major';
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (commits.some((c) => c.type === 'feat')) {
|
|
215
|
+
return 'minor';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return 'patch';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Changelog generation
|
|
222
|
+
async function generateChangelogWithClaude(commits: ConventionalCommit[]): Promise<string | null> {
|
|
223
|
+
try {
|
|
224
|
+
// Check if claude CLI is available
|
|
225
|
+
execSync('which claude', { stdio: 'pipe' });
|
|
226
|
+
|
|
227
|
+
const commitSummary = commits
|
|
228
|
+
.map((c) => `- ${c.type}${c.scope ? `(${c.scope})` : ''}: ${c.subject}\n ${c.body || '(no additional details)'}`)
|
|
229
|
+
.join('\n\n');
|
|
230
|
+
|
|
231
|
+
const prompt = `You are analyzing git commits to generate a changelog entry. Here are the commits:
|
|
232
|
+
|
|
233
|
+
${commitSummary}
|
|
234
|
+
|
|
235
|
+
Generate a concise changelog description as bullet points. Rules:
|
|
236
|
+
- Use 2-5 bullet points maximum
|
|
237
|
+
- Focus on user-facing changes and impact
|
|
238
|
+
- Group related changes together
|
|
239
|
+
- Use clear, non-technical language where possible
|
|
240
|
+
- Start each bullet with a dash and capitalize the first word
|
|
241
|
+
- Do NOT include commit hashes, types, or scopes
|
|
242
|
+
- Do NOT use markdown formatting besides the dashes
|
|
243
|
+
|
|
244
|
+
Example format:
|
|
245
|
+
- Added user authentication with OAuth support
|
|
246
|
+
- Fixed critical bug in data synchronization
|
|
247
|
+
- Improved performance of search queries by 50%
|
|
248
|
+
|
|
249
|
+
Now generate the changelog for the commits above:`;
|
|
250
|
+
|
|
251
|
+
const tempFile = join(process.cwd(), `.changeset-prompt-${Date.now()}.txt`);
|
|
252
|
+
writeFileSync(tempFile, prompt);
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
const result = execSync(`claude -p --no-session-persistence "$(cat ${tempFile})"`, {
|
|
256
|
+
encoding: 'utf8',
|
|
257
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
258
|
+
timeout: 30000,
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
return result.trim();
|
|
262
|
+
} finally {
|
|
263
|
+
try {
|
|
264
|
+
execSync(`rm ${tempFile}`, { stdio: 'pipe' });
|
|
265
|
+
} catch {
|
|
266
|
+
// Ignore cleanup errors
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function generateSimpleChangelog(commits: ConventionalCommit[]): string {
|
|
275
|
+
const features = commits.filter((c) => c.type === 'feat');
|
|
276
|
+
const fixes = commits.filter((c) => c.type === 'fix');
|
|
277
|
+
const others = commits.filter((c) => !['feat', 'fix'].includes(c.type));
|
|
278
|
+
|
|
279
|
+
const lines: string[] = [];
|
|
280
|
+
|
|
281
|
+
if (features.length > 0) {
|
|
282
|
+
lines.push(...features.map((c) => `- ${c.scope ? `**${c.scope}**: ` : ''}${c.subject}`));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (fixes.length > 0) {
|
|
286
|
+
lines.push(...fixes.map((c) => `- ${c.scope ? `**${c.scope}**: ` : ''}${c.subject}`));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (others.length > 0 && lines.length < 5) {
|
|
290
|
+
lines.push(...others.map((c) => `- ${c.scope ? `**${c.scope}**: ` : ''}${c.subject}`).slice(0, 5 - lines.length));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return lines.slice(0, 5).join('\n');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function generateChangelog(commits: ConventionalCommit[]): Promise<string> {
|
|
297
|
+
logInfo('Attempting to generate changelog with Claude CLI...');
|
|
298
|
+
|
|
299
|
+
const aiChangelog = await generateChangelogWithClaude(commits);
|
|
300
|
+
|
|
301
|
+
if (aiChangelog) {
|
|
302
|
+
logSuccess('Changelog generated with Claude CLI');
|
|
303
|
+
return aiChangelog;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
logWarning('Claude CLI not available, using simple changelog generation');
|
|
307
|
+
return generateSimpleChangelog(commits);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Changeset file creation
|
|
311
|
+
function createChangesetFile(bumpType: BumpType, description: string): { filename: string; content: string } {
|
|
312
|
+
const changesetDir = join(process.cwd(), CHANGESET_DIR);
|
|
313
|
+
|
|
314
|
+
if (!existsSync(changesetDir)) {
|
|
315
|
+
mkdirSync(changesetDir, { recursive: true });
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const id = randomBytes(8).toString('hex');
|
|
319
|
+
const filename = `auto-${id}.md`;
|
|
320
|
+
const filepath = join(changesetDir, filename);
|
|
321
|
+
|
|
322
|
+
const content = `---
|
|
323
|
+
"${PACKAGE_NAME}": ${bumpType}
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
${description}
|
|
327
|
+
`;
|
|
328
|
+
|
|
329
|
+
writeFileSync(filepath, content);
|
|
330
|
+
|
|
331
|
+
return { filename, content };
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Main function
|
|
335
|
+
async function main(): Promise<void> {
|
|
336
|
+
const args = process.argv.slice(2);
|
|
337
|
+
const dryRun = args.includes('--dry-run');
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
if (!isGitRepository()) {
|
|
341
|
+
logError('Not a git repository');
|
|
342
|
+
process.exit(EXIT_CODE.ERROR);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
logStep('Checking for commits that need changesets...');
|
|
346
|
+
|
|
347
|
+
const commitHashes = getCommitsSinceLastChangeset();
|
|
348
|
+
|
|
349
|
+
if (commitHashes.length === 0) {
|
|
350
|
+
logInfo('No new commits found. Nothing to do.');
|
|
351
|
+
process.exit(EXIT_CODE.NO_COMMITS);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
logInfo(`Found ${commitHashes.length} commit(s) to process`);
|
|
355
|
+
|
|
356
|
+
const commits = parseConventionalCommits(commitHashes);
|
|
357
|
+
|
|
358
|
+
const skippedCount = commitHashes.length - commits.length;
|
|
359
|
+
if (skippedCount > 0) {
|
|
360
|
+
logWarning(`Skipped ${skippedCount} non-conventional commit(s). Use format: type(scope): subject`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (commits.length === 0) {
|
|
364
|
+
logWarning('No conventional commits found. Skipping changeset generation.');
|
|
365
|
+
logInfo('Commits must follow format: type(scope): subject (e.g., feat(cli): add new command)');
|
|
366
|
+
process.exit(EXIT_CODE.NO_CONVENTIONAL_COMMITS);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
logSuccess(`Found ${commits.length} valid conventional commit(s)`);
|
|
370
|
+
|
|
371
|
+
const bumpType = determineBumpType(commits);
|
|
372
|
+
logInfo(`Determined version bump: ${bumpType}`);
|
|
373
|
+
|
|
374
|
+
const description = await generateChangelog(commits);
|
|
375
|
+
|
|
376
|
+
if (dryRun) {
|
|
377
|
+
console.log('\nš Changeset Preview:');
|
|
378
|
+
console.log('---');
|
|
379
|
+
console.log(`Bump type: ${bumpType}`);
|
|
380
|
+
console.log(`Package: ${PACKAGE_NAME}`);
|
|
381
|
+
console.log('\nChangelog:');
|
|
382
|
+
console.log(description);
|
|
383
|
+
console.log('---');
|
|
384
|
+
process.exit(EXIT_CODE.SUCCESS);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const result = createChangesetFile(bumpType, description);
|
|
388
|
+
|
|
389
|
+
logSuccess(`Created changeset: ${result.filename}`);
|
|
390
|
+
logInfo(` Bump type: ${bumpType}`);
|
|
391
|
+
logInfo(` Commits: ${commits.length}`);
|
|
392
|
+
|
|
393
|
+
console.log('\nš Changelog preview:');
|
|
394
|
+
console.log('---');
|
|
395
|
+
console.log(description);
|
|
396
|
+
console.log('---');
|
|
397
|
+
|
|
398
|
+
process.exit(EXIT_CODE.SUCCESS);
|
|
399
|
+
} catch (error) {
|
|
400
|
+
logError(`Failed to generate changeset: ${(error as Error).message}`);
|
|
401
|
+
process.exit(EXIT_CODE.ERROR);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
main();
|