claude-auto 0.13.8 → 0.14.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/.claude-auto/agents/validator.md +4 -0
- package/dist/bundle/scripts/auto-continue.js +136 -79
- package/dist/bundle/scripts/pre-tool-use.js +57 -55
- package/dist/bundle/scripts/session-start.js +68 -52
- package/dist/bundle/scripts/user-prompt-submit.js +85 -64
- package/dist/scripts/auto-continue.js +28 -12
- package/dist/scripts/auto-continue.js.map +1 -1
- package/dist/scripts/pre-tool-use.js +3 -1
- package/dist/scripts/pre-tool-use.js.map +1 -1
- package/dist/scripts/session-start.js +3 -1
- package/dist/scripts/session-start.js.map +1 -1
- package/dist/scripts/user-prompt-submit.js +4 -2
- package/dist/scripts/user-prompt-submit.js.map +1 -1
- package/dist/src/cli/install.d.ts.map +1 -1
- package/dist/src/cli/install.js +1 -0
- package/dist/src/cli/install.js.map +1 -1
- package/dist/src/cli/install.test.js +7 -0
- package/dist/src/cli/install.test.js.map +1 -1
- package/dist/src/commit-validator.d.ts.map +1 -1
- package/dist/src/commit-validator.js +3 -3
- package/dist/src/commit-validator.js.map +1 -1
- package/dist/src/commit-validator.test.js +40 -29
- package/dist/src/commit-validator.test.js.map +1 -1
- package/dist/src/e2e.test.js +93 -0
- package/dist/src/e2e.test.js.map +1 -1
- package/dist/src/hook-input.d.ts +1 -0
- package/dist/src/hook-input.d.ts.map +1 -1
- package/dist/src/hook-input.js.map +1 -1
- package/dist/src/hook-input.test.js +13 -0
- package/dist/src/hook-input.test.js.map +1 -1
- package/dist/src/hooks/pre-tool-use.d.ts +1 -0
- package/dist/src/hooks/pre-tool-use.d.ts.map +1 -1
- package/dist/src/hooks/pre-tool-use.js +4 -3
- package/dist/src/hooks/pre-tool-use.js.map +1 -1
- package/dist/src/hooks/session-start.d.ts +1 -1
- package/dist/src/hooks/session-start.d.ts.map +1 -1
- package/dist/src/hooks/session-start.js +16 -1
- package/dist/src/hooks/session-start.js.map +1 -1
- package/dist/src/hooks/session-start.test.js +17 -0
- package/dist/src/hooks/session-start.test.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.d.ts +5 -2
- package/dist/src/hooks/user-prompt-submit.d.ts.map +1 -1
- package/dist/src/hooks/user-prompt-submit.js +24 -8
- package/dist/src/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.test.js +44 -8
- package/dist/src/hooks/user-prompt-submit.test.js.map +1 -1
- package/dist/src/validator-session.d.ts +2 -0
- package/dist/src/validator-session.d.ts.map +1 -0
- package/dist/src/validator-session.js +12 -0
- package/dist/src/validator-session.js.map +1 -0
- package/dist/src/validator-session.test.d.ts +2 -0
- package/dist/src/validator-session.test.d.ts.map +1 -0
- package/dist/src/validator-session.test.js +57 -0
- package/dist/src/validator-session.test.js.map +1 -0
- package/package.json +1 -1
- package/scripts/auto-continue.ts +31 -17
- package/scripts/pre-tool-use.ts +3 -1
- package/scripts/session-start.ts +3 -1
- package/scripts/user-prompt-submit.ts +4 -2
|
@@ -30,9 +30,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
var require_resolve_from = __commonJS({
|
|
31
31
|
"node_modules/.pnpm/resolve-from@4.0.0/node_modules/resolve-from/index.js"(exports2, module2) {
|
|
32
32
|
"use strict";
|
|
33
|
-
var
|
|
33
|
+
var path6 = require("path");
|
|
34
34
|
var Module = require("module");
|
|
35
|
-
var
|
|
35
|
+
var fs5 = require("fs");
|
|
36
36
|
var resolveFrom = (fromDir, moduleId, silent) => {
|
|
37
37
|
if (typeof fromDir !== "string") {
|
|
38
38
|
throw new TypeError(`Expected \`fromDir\` to be of type \`string\`, got \`${typeof fromDir}\``);
|
|
@@ -41,17 +41,17 @@ var require_resolve_from = __commonJS({
|
|
|
41
41
|
throw new TypeError(`Expected \`moduleId\` to be of type \`string\`, got \`${typeof moduleId}\``);
|
|
42
42
|
}
|
|
43
43
|
try {
|
|
44
|
-
fromDir =
|
|
44
|
+
fromDir = fs5.realpathSync(fromDir);
|
|
45
45
|
} catch (err) {
|
|
46
46
|
if (err.code === "ENOENT") {
|
|
47
|
-
fromDir =
|
|
47
|
+
fromDir = path6.resolve(fromDir);
|
|
48
48
|
} else if (silent) {
|
|
49
49
|
return null;
|
|
50
50
|
} else {
|
|
51
51
|
throw err;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
const fromFile =
|
|
54
|
+
const fromFile = path6.join(fromDir, "noop.js");
|
|
55
55
|
const resolveFileName = () => Module._resolveFilename(moduleId, {
|
|
56
56
|
id: fromFile,
|
|
57
57
|
filename: fromFile,
|
|
@@ -123,7 +123,7 @@ var require_parent_module = __commonJS({
|
|
|
123
123
|
var require_import_fresh = __commonJS({
|
|
124
124
|
"node_modules/.pnpm/import-fresh@3.3.1/node_modules/import-fresh/index.js"(exports2, module2) {
|
|
125
125
|
"use strict";
|
|
126
|
-
var
|
|
126
|
+
var path6 = require("path");
|
|
127
127
|
var resolveFrom = require_resolve_from();
|
|
128
128
|
var parentModule = require_parent_module();
|
|
129
129
|
module2.exports = (moduleId) => {
|
|
@@ -131,7 +131,7 @@ var require_import_fresh = __commonJS({
|
|
|
131
131
|
throw new TypeError("Expected a string");
|
|
132
132
|
}
|
|
133
133
|
const parentPath = parentModule(__filename);
|
|
134
|
-
const cwd = parentPath ?
|
|
134
|
+
const cwd = parentPath ? path6.dirname(parentPath) : __dirname;
|
|
135
135
|
const filePath = resolveFrom(cwd, moduleId);
|
|
136
136
|
const oldModule = require.cache[filePath];
|
|
137
137
|
if (oldModule && oldModule.parent) {
|
|
@@ -3889,7 +3889,7 @@ ${error.message}`;
|
|
|
3889
3889
|
return typescript.sys.fileExists(fileName);
|
|
3890
3890
|
});
|
|
3891
3891
|
if (filePath !== void 0) {
|
|
3892
|
-
const { config, error } = typescript.readConfigFile(filePath, (
|
|
3892
|
+
const { config, error } = typescript.readConfigFile(filePath, (path6) => typescript.sys.readFile(path6));
|
|
3893
3893
|
if (error) {
|
|
3894
3894
|
throw new Error(`Error in ${filePath}: ${error.messageText.toString()}`);
|
|
3895
3895
|
}
|
|
@@ -4012,42 +4012,42 @@ var require_defaults = __commonJS({
|
|
|
4012
4012
|
var require_env_paths = __commonJS({
|
|
4013
4013
|
"node_modules/.pnpm/env-paths@2.2.1/node_modules/env-paths/index.js"(exports2, module2) {
|
|
4014
4014
|
"use strict";
|
|
4015
|
-
var
|
|
4015
|
+
var path6 = require("path");
|
|
4016
4016
|
var os = require("os");
|
|
4017
4017
|
var homedir = os.homedir();
|
|
4018
4018
|
var tmpdir = os.tmpdir();
|
|
4019
4019
|
var { env } = process;
|
|
4020
4020
|
var macos = (name) => {
|
|
4021
|
-
const library =
|
|
4021
|
+
const library = path6.join(homedir, "Library");
|
|
4022
4022
|
return {
|
|
4023
|
-
data:
|
|
4024
|
-
config:
|
|
4025
|
-
cache:
|
|
4026
|
-
log:
|
|
4027
|
-
temp:
|
|
4023
|
+
data: path6.join(library, "Application Support", name),
|
|
4024
|
+
config: path6.join(library, "Preferences", name),
|
|
4025
|
+
cache: path6.join(library, "Caches", name),
|
|
4026
|
+
log: path6.join(library, "Logs", name),
|
|
4027
|
+
temp: path6.join(tmpdir, name)
|
|
4028
4028
|
};
|
|
4029
4029
|
};
|
|
4030
4030
|
var windows = (name) => {
|
|
4031
|
-
const appData = env.APPDATA ||
|
|
4032
|
-
const localAppData = env.LOCALAPPDATA ||
|
|
4031
|
+
const appData = env.APPDATA || path6.join(homedir, "AppData", "Roaming");
|
|
4032
|
+
const localAppData = env.LOCALAPPDATA || path6.join(homedir, "AppData", "Local");
|
|
4033
4033
|
return {
|
|
4034
4034
|
// Data/config/cache/log are invented by me as Windows isn't opinionated about this
|
|
4035
|
-
data:
|
|
4036
|
-
config:
|
|
4037
|
-
cache:
|
|
4038
|
-
log:
|
|
4039
|
-
temp:
|
|
4035
|
+
data: path6.join(localAppData, name, "Data"),
|
|
4036
|
+
config: path6.join(appData, name, "Config"),
|
|
4037
|
+
cache: path6.join(localAppData, name, "Cache"),
|
|
4038
|
+
log: path6.join(localAppData, name, "Log"),
|
|
4039
|
+
temp: path6.join(tmpdir, name)
|
|
4040
4040
|
};
|
|
4041
4041
|
};
|
|
4042
4042
|
var linux = (name) => {
|
|
4043
|
-
const username =
|
|
4043
|
+
const username = path6.basename(homedir);
|
|
4044
4044
|
return {
|
|
4045
|
-
data:
|
|
4046
|
-
config:
|
|
4047
|
-
cache:
|
|
4045
|
+
data: path6.join(env.XDG_DATA_HOME || path6.join(homedir, ".local", "share"), name),
|
|
4046
|
+
config: path6.join(env.XDG_CONFIG_HOME || path6.join(homedir, ".config"), name),
|
|
4047
|
+
cache: path6.join(env.XDG_CACHE_HOME || path6.join(homedir, ".cache"), name),
|
|
4048
4048
|
// https://wiki.debian.org/XDGBaseDirectorySpecification#state
|
|
4049
|
-
log:
|
|
4050
|
-
temp:
|
|
4049
|
+
log: path6.join(env.XDG_STATE_HOME || path6.join(homedir, ".local", "state"), name),
|
|
4050
|
+
temp: path6.join(tmpdir, username, name)
|
|
4051
4051
|
};
|
|
4052
4052
|
};
|
|
4053
4053
|
var envPaths = (name, options) => {
|
|
@@ -4115,11 +4115,11 @@ var require_util = __commonJS({
|
|
|
4115
4115
|
return result;
|
|
4116
4116
|
}
|
|
4117
4117
|
exports2.emplace = emplace;
|
|
4118
|
-
function getPropertyByPath(source,
|
|
4119
|
-
if (typeof
|
|
4120
|
-
return source[
|
|
4118
|
+
function getPropertyByPath(source, path6) {
|
|
4119
|
+
if (typeof path6 === "string" && Object.prototype.hasOwnProperty.call(source, path6)) {
|
|
4120
|
+
return source[path6];
|
|
4121
4121
|
}
|
|
4122
|
-
const parsedPath = typeof
|
|
4122
|
+
const parsedPath = typeof path6 === "string" ? path6.split(".") : path6;
|
|
4123
4123
|
return parsedPath.reduce((previous, key) => {
|
|
4124
4124
|
if (previous === void 0) {
|
|
4125
4125
|
return previous;
|
|
@@ -4132,9 +4132,9 @@ var require_util = __commonJS({
|
|
|
4132
4132
|
return Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0));
|
|
4133
4133
|
}
|
|
4134
4134
|
exports2.removeUndefinedValuesFromObject = removeUndefinedValuesFromObject;
|
|
4135
|
-
async function isDirectory(
|
|
4135
|
+
async function isDirectory(path6) {
|
|
4136
4136
|
try {
|
|
4137
|
-
const stat = await fs_1.promises.stat(
|
|
4137
|
+
const stat = await fs_1.promises.stat(path6);
|
|
4138
4138
|
return stat.isDirectory();
|
|
4139
4139
|
} catch (e) {
|
|
4140
4140
|
if (e.code === "ENOENT") {
|
|
@@ -4144,9 +4144,9 @@ var require_util = __commonJS({
|
|
|
4144
4144
|
}
|
|
4145
4145
|
}
|
|
4146
4146
|
exports2.isDirectory = isDirectory;
|
|
4147
|
-
function isDirectorySync(
|
|
4147
|
+
function isDirectorySync(path6) {
|
|
4148
4148
|
try {
|
|
4149
|
-
const stat = fs_1.default.statSync(
|
|
4149
|
+
const stat = fs_1.default.statSync(path6);
|
|
4150
4150
|
return stat.isDirectory();
|
|
4151
4151
|
} catch (e) {
|
|
4152
4152
|
if (e.code === "ENOENT") {
|
|
@@ -4244,7 +4244,7 @@ var require_ExplorerBase = __commonJS({
|
|
|
4244
4244
|
const idx = importStack.indexOf(fullPath);
|
|
4245
4245
|
if (idx !== -1) {
|
|
4246
4246
|
throw new Error(`Circular import detected:
|
|
4247
|
-
${[...importStack, fullPath].map((
|
|
4247
|
+
${[...importStack, fullPath].map((path6, i) => `${i + 1}. ${path6}`).join("\n")} (same as ${idx + 1}.)`);
|
|
4248
4248
|
}
|
|
4249
4249
|
}
|
|
4250
4250
|
}
|
|
@@ -4429,9 +4429,9 @@ var require_Explorer = __commonJS({
|
|
|
4429
4429
|
throw error;
|
|
4430
4430
|
}
|
|
4431
4431
|
}
|
|
4432
|
-
async #fileExists(
|
|
4432
|
+
async #fileExists(path6) {
|
|
4433
4433
|
try {
|
|
4434
|
-
await promises_1.default.stat(
|
|
4434
|
+
await promises_1.default.stat(path6);
|
|
4435
4435
|
return true;
|
|
4436
4436
|
} catch (e) {
|
|
4437
4437
|
return false;
|
|
@@ -4587,9 +4587,9 @@ var require_ExplorerSync = __commonJS({
|
|
|
4587
4587
|
throw error;
|
|
4588
4588
|
}
|
|
4589
4589
|
}
|
|
4590
|
-
#fileExists(
|
|
4590
|
+
#fileExists(path6) {
|
|
4591
4591
|
try {
|
|
4592
|
-
fs_1.default.statSync(
|
|
4592
|
+
fs_1.default.statSync(path6);
|
|
4593
4593
|
return true;
|
|
4594
4594
|
} catch (e) {
|
|
4595
4595
|
return false;
|
|
@@ -4709,7 +4709,7 @@ var require_dist = __commonJS({
|
|
|
4709
4709
|
};
|
|
4710
4710
|
}
|
|
4711
4711
|
function getResolvedSearchPlaces(moduleName, toolDefinedSearchPlaces, userConfiguredOptions) {
|
|
4712
|
-
const userConfiguredSearchPlaces = userConfiguredOptions.searchPlaces?.map((
|
|
4712
|
+
const userConfiguredSearchPlaces = userConfiguredOptions.searchPlaces?.map((path6) => path6.replace("{name}", moduleName));
|
|
4713
4713
|
if (userConfiguredOptions.mergeSearchPlaces) {
|
|
4714
4714
|
return [...userConfiguredSearchPlaces ?? [], ...toolDefinedSearchPlaces];
|
|
4715
4715
|
}
|
|
@@ -4807,22 +4807,65 @@ var require_dist = __commonJS({
|
|
|
4807
4807
|
});
|
|
4808
4808
|
|
|
4809
4809
|
// scripts/auto-continue.ts
|
|
4810
|
-
var
|
|
4811
|
-
var
|
|
4810
|
+
var fs4 = __toESM(require("node:fs"));
|
|
4811
|
+
var path5 = __toESM(require("node:path"));
|
|
4812
|
+
|
|
4813
|
+
// src/activity-logger.ts
|
|
4814
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
4815
|
+
var import_node_path = __toESM(require("node:path"));
|
|
4816
|
+
function matchesFilter(hookName, message) {
|
|
4817
|
+
const filter = process.env.KETCHUP_LOG;
|
|
4818
|
+
if (!filter) {
|
|
4819
|
+
return true;
|
|
4820
|
+
}
|
|
4821
|
+
const patterns = filter.split(",").map((p) => p.trim());
|
|
4822
|
+
const includes = patterns.filter((p) => !p.startsWith("-"));
|
|
4823
|
+
const excludes = patterns.filter((p) => p.startsWith("-")).map((p) => p.slice(1));
|
|
4824
|
+
const searchText = `${hookName}: ${message}`;
|
|
4825
|
+
const excluded = excludes.some((pattern) => searchText.includes(pattern));
|
|
4826
|
+
if (excluded) {
|
|
4827
|
+
return false;
|
|
4828
|
+
}
|
|
4829
|
+
if (includes.length === 0 || includes.includes("*")) {
|
|
4830
|
+
return true;
|
|
4831
|
+
}
|
|
4832
|
+
return includes.some((pattern) => searchText.includes(pattern));
|
|
4833
|
+
}
|
|
4834
|
+
function activityLog(autoDir, sessionId, hookName, message) {
|
|
4835
|
+
if (!matchesFilter(hookName, message)) {
|
|
4836
|
+
return;
|
|
4837
|
+
}
|
|
4838
|
+
const logsDir = import_node_path.default.join(autoDir, "logs");
|
|
4839
|
+
if (!import_node_fs.default.existsSync(logsDir)) {
|
|
4840
|
+
import_node_fs.default.mkdirSync(logsDir, { recursive: true });
|
|
4841
|
+
}
|
|
4842
|
+
const logPath = import_node_path.default.join(logsDir, "activity.log");
|
|
4843
|
+
const now = /* @__PURE__ */ new Date();
|
|
4844
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
4845
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
4846
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
4847
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
4848
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
4849
|
+
const timestamp = `${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
4850
|
+
const shortSessionId = sessionId.slice(-8);
|
|
4851
|
+
const entry = `${timestamp} [${shortSessionId}] ${hookName}: ${message}
|
|
4852
|
+
`;
|
|
4853
|
+
import_node_fs.default.appendFileSync(logPath, entry);
|
|
4854
|
+
}
|
|
4812
4855
|
|
|
4813
4856
|
// src/hook-logger.ts
|
|
4814
|
-
var
|
|
4815
|
-
var
|
|
4857
|
+
var fs2 = __toESM(require("node:fs"));
|
|
4858
|
+
var path2 = __toESM(require("node:path"));
|
|
4816
4859
|
function sanitizeForFilename(hookName) {
|
|
4817
4860
|
return hookName.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
4818
4861
|
}
|
|
4819
4862
|
function writeHookLog(autoDir, entry) {
|
|
4820
|
-
const logsDir =
|
|
4821
|
-
if (!
|
|
4822
|
-
|
|
4863
|
+
const logsDir = path2.join(autoDir, "logs", "hooks");
|
|
4864
|
+
if (!fs2.existsSync(logsDir)) {
|
|
4865
|
+
fs2.mkdirSync(logsDir, { recursive: true });
|
|
4823
4866
|
}
|
|
4824
4867
|
const sanitizedName = sanitizeForFilename(entry.hookName);
|
|
4825
|
-
const logPath =
|
|
4868
|
+
const logPath = path2.join(logsDir, `${sanitizedName}.log`);
|
|
4826
4869
|
const lines = [];
|
|
4827
4870
|
lines.push(`=== ${entry.hookName} hook log ===`);
|
|
4828
4871
|
lines.push(`Timestamp: ${entry.timestamp}`);
|
|
@@ -4862,13 +4905,13 @@ function writeHookLog(autoDir, entry) {
|
|
|
4862
4905
|
lines.push("--- Output ---");
|
|
4863
4906
|
lines.push(JSON.stringify(entry.output, null, 2));
|
|
4864
4907
|
lines.push("");
|
|
4865
|
-
|
|
4908
|
+
fs2.appendFileSync(logPath, `${lines.join("\n")}
|
|
4866
4909
|
`);
|
|
4867
4910
|
}
|
|
4868
4911
|
|
|
4869
4912
|
// src/hook-state.ts
|
|
4870
|
-
var
|
|
4871
|
-
var
|
|
4913
|
+
var fs3 = __toESM(require("node:fs"));
|
|
4914
|
+
var path3 = __toESM(require("node:path"));
|
|
4872
4915
|
var DEFAULT_HOOK_STATE = {
|
|
4873
4916
|
autoContinue: {
|
|
4874
4917
|
mode: "smart",
|
|
@@ -4896,18 +4939,18 @@ var DEFAULT_HOOK_STATE = {
|
|
|
4896
4939
|
updatedBy: "default"
|
|
4897
4940
|
};
|
|
4898
4941
|
function createHookState(autoDir) {
|
|
4899
|
-
if (!
|
|
4900
|
-
|
|
4942
|
+
if (!fs3.existsSync(autoDir)) {
|
|
4943
|
+
fs3.mkdirSync(autoDir, { recursive: true });
|
|
4901
4944
|
}
|
|
4902
|
-
const stateFile =
|
|
4945
|
+
const stateFile = path3.join(autoDir, ".claude.hooks.json");
|
|
4903
4946
|
function read() {
|
|
4904
|
-
if (!
|
|
4947
|
+
if (!fs3.existsSync(stateFile)) {
|
|
4905
4948
|
const state = { ...DEFAULT_HOOK_STATE, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), updatedBy: "init" };
|
|
4906
|
-
|
|
4949
|
+
fs3.writeFileSync(stateFile, `${JSON.stringify(state, null, 2)}
|
|
4907
4950
|
`);
|
|
4908
4951
|
return state;
|
|
4909
4952
|
}
|
|
4910
|
-
const content =
|
|
4953
|
+
const content = fs3.readFileSync(stateFile, "utf-8");
|
|
4911
4954
|
const partial = JSON.parse(content);
|
|
4912
4955
|
return {
|
|
4913
4956
|
autoContinue: { ...DEFAULT_HOOK_STATE.autoContinue, ...partial.autoContinue },
|
|
@@ -4921,7 +4964,7 @@ function createHookState(autoDir) {
|
|
|
4921
4964
|
}
|
|
4922
4965
|
function write(state) {
|
|
4923
4966
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4924
|
-
|
|
4967
|
+
fs3.writeFileSync(stateFile, `${JSON.stringify(state, null, 2)}
|
|
4925
4968
|
`);
|
|
4926
4969
|
}
|
|
4927
4970
|
function update(updates, updatedBy) {
|
|
@@ -4979,7 +5022,7 @@ function handleStop(autoDir, input2) {
|
|
|
4979
5022
|
}
|
|
4980
5023
|
|
|
4981
5024
|
// src/path-resolver.ts
|
|
4982
|
-
var
|
|
5025
|
+
var path4 = __toESM(require("node:path"));
|
|
4983
5026
|
|
|
4984
5027
|
// src/config-loader.ts
|
|
4985
5028
|
var import_cosmiconfig = __toESM(require_dist());
|
|
@@ -4992,22 +5035,22 @@ async function loadConfig(searchFrom) {
|
|
|
4992
5035
|
|
|
4993
5036
|
// src/path-resolver.ts
|
|
4994
5037
|
async function resolvePaths(claudeDir2) {
|
|
4995
|
-
const projectRoot =
|
|
5038
|
+
const projectRoot = path4.dirname(claudeDir2);
|
|
4996
5039
|
const config = await loadConfig(projectRoot);
|
|
4997
5040
|
const autoDirName = config.autoDir ?? DEFAULT_AUTO_DIR;
|
|
4998
|
-
const autoDir =
|
|
5041
|
+
const autoDir = path4.join(projectRoot, autoDirName);
|
|
4999
5042
|
return {
|
|
5000
5043
|
projectRoot,
|
|
5001
5044
|
claudeDir: claudeDir2,
|
|
5002
5045
|
autoDir,
|
|
5003
|
-
remindersDir:
|
|
5004
|
-
validatorsDir:
|
|
5046
|
+
remindersDir: path4.join(autoDir, "reminders"),
|
|
5047
|
+
validatorsDir: path4.join(autoDir, "validators")
|
|
5005
5048
|
};
|
|
5006
5049
|
}
|
|
5007
5050
|
|
|
5008
5051
|
// scripts/auto-continue.ts
|
|
5009
|
-
var claudeDir =
|
|
5010
|
-
var stdin =
|
|
5052
|
+
var claudeDir = path5.resolve(process.cwd(), ".claude");
|
|
5053
|
+
var stdin = fs4.readFileSync(0, "utf8").trim();
|
|
5011
5054
|
if (!stdin) {
|
|
5012
5055
|
process.exit(0);
|
|
5013
5056
|
}
|
|
@@ -5015,19 +5058,33 @@ var input = JSON.parse(stdin);
|
|
|
5015
5058
|
var startTime = Date.now();
|
|
5016
5059
|
(async () => {
|
|
5017
5060
|
const { autoDir } = await resolvePaths(claudeDir);
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5061
|
+
try {
|
|
5062
|
+
const result = handleStop(autoDir, input);
|
|
5063
|
+
const output = result.decision === "block" ? { decision: "block", reason: result.reason } : null;
|
|
5064
|
+
writeHookLog(autoDir, {
|
|
5065
|
+
hookName: "auto-continue",
|
|
5066
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5067
|
+
input,
|
|
5068
|
+
output: output ?? { decision: result.decision, reason: result.reason },
|
|
5069
|
+
durationMs: Date.now() - startTime
|
|
5070
|
+
});
|
|
5071
|
+
if (output) {
|
|
5072
|
+
console.log(JSON.stringify(output));
|
|
5073
|
+
}
|
|
5074
|
+
process.exit(0);
|
|
5075
|
+
} catch (err) {
|
|
5076
|
+
activityLog(autoDir, input.session_id ?? "unknown", "auto-continue", `error: ${String(err)}`);
|
|
5077
|
+
writeHookLog(autoDir, {
|
|
5078
|
+
hookName: "auto-continue",
|
|
5079
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5080
|
+
input,
|
|
5081
|
+
output: null,
|
|
5082
|
+
error: String(err),
|
|
5083
|
+
durationMs: Date.now() - startTime
|
|
5084
|
+
});
|
|
5085
|
+
console.error("auto-continue hook failed:", err);
|
|
5086
|
+
process.exit(1);
|
|
5029
5087
|
}
|
|
5030
|
-
process.exit(0);
|
|
5031
5088
|
})();
|
|
5032
5089
|
/*! Bundled license information:
|
|
5033
5090
|
|
|
@@ -11046,6 +11046,49 @@ var require_gray_matter = __commonJS({
|
|
|
11046
11046
|
var fs8 = __toESM(require("node:fs"));
|
|
11047
11047
|
var path9 = __toESM(require("node:path"));
|
|
11048
11048
|
|
|
11049
|
+
// src/activity-logger.ts
|
|
11050
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
11051
|
+
var import_node_path = __toESM(require("node:path"));
|
|
11052
|
+
function matchesFilter(hookName, message) {
|
|
11053
|
+
const filter = process.env.KETCHUP_LOG;
|
|
11054
|
+
if (!filter) {
|
|
11055
|
+
return true;
|
|
11056
|
+
}
|
|
11057
|
+
const patterns = filter.split(",").map((p) => p.trim());
|
|
11058
|
+
const includes = patterns.filter((p) => !p.startsWith("-"));
|
|
11059
|
+
const excludes = patterns.filter((p) => p.startsWith("-")).map((p) => p.slice(1));
|
|
11060
|
+
const searchText = `${hookName}: ${message}`;
|
|
11061
|
+
const excluded = excludes.some((pattern) => searchText.includes(pattern));
|
|
11062
|
+
if (excluded) {
|
|
11063
|
+
return false;
|
|
11064
|
+
}
|
|
11065
|
+
if (includes.length === 0 || includes.includes("*")) {
|
|
11066
|
+
return true;
|
|
11067
|
+
}
|
|
11068
|
+
return includes.some((pattern) => searchText.includes(pattern));
|
|
11069
|
+
}
|
|
11070
|
+
function activityLog(autoDir, sessionId, hookName, message) {
|
|
11071
|
+
if (!matchesFilter(hookName, message)) {
|
|
11072
|
+
return;
|
|
11073
|
+
}
|
|
11074
|
+
const logsDir = import_node_path.default.join(autoDir, "logs");
|
|
11075
|
+
if (!import_node_fs.default.existsSync(logsDir)) {
|
|
11076
|
+
import_node_fs.default.mkdirSync(logsDir, { recursive: true });
|
|
11077
|
+
}
|
|
11078
|
+
const logPath = import_node_path.default.join(logsDir, "activity.log");
|
|
11079
|
+
const now = /* @__PURE__ */ new Date();
|
|
11080
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
11081
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
11082
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
11083
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
11084
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
11085
|
+
const timestamp = `${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
11086
|
+
const shortSessionId = sessionId.slice(-8);
|
|
11087
|
+
const entry = `${timestamp} [${shortSessionId}] ${hookName}: ${message}
|
|
11088
|
+
`;
|
|
11089
|
+
import_node_fs.default.appendFileSync(logPath, entry);
|
|
11090
|
+
}
|
|
11091
|
+
|
|
11049
11092
|
// src/commit-validator.ts
|
|
11050
11093
|
var import_node_child_process = require("node:child_process");
|
|
11051
11094
|
function spawnAsync(cmd, args, _options) {
|
|
@@ -11198,7 +11241,7 @@ async function validateCommit(validators, context, executor = spawnAsync, onLog,
|
|
|
11198
11241
|
onLog?.("spawn", `batch-${chunkIndex}`, `validators: ${names.join(", ")}`);
|
|
11199
11242
|
try {
|
|
11200
11243
|
const prompt = buildBatchedPrompt(chunk, context);
|
|
11201
|
-
const args = ["-p", "--no-session-persistence", prompt, "--output-format", "json"];
|
|
11244
|
+
const args = ["-p", "--no-session-persistence", "--agent", "validator", prompt, "--output-format", "json"];
|
|
11202
11245
|
const opts = { encoding: "utf8" };
|
|
11203
11246
|
const spawnResult = await executor("claude", args, opts);
|
|
11204
11247
|
const batchResults2 = parseBatchedOutput(spawnResult.stdout, names);
|
|
@@ -11240,18 +11283,18 @@ function parseHookInput(json) {
|
|
|
11240
11283
|
}
|
|
11241
11284
|
|
|
11242
11285
|
// src/hook-logger.ts
|
|
11243
|
-
var
|
|
11244
|
-
var
|
|
11286
|
+
var fs2 = __toESM(require("node:fs"));
|
|
11287
|
+
var path2 = __toESM(require("node:path"));
|
|
11245
11288
|
function sanitizeForFilename(hookName) {
|
|
11246
11289
|
return hookName.replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
|
|
11247
11290
|
}
|
|
11248
11291
|
function writeHookLog(autoDir, entry) {
|
|
11249
|
-
const logsDir =
|
|
11250
|
-
if (!
|
|
11251
|
-
|
|
11292
|
+
const logsDir = path2.join(autoDir, "logs", "hooks");
|
|
11293
|
+
if (!fs2.existsSync(logsDir)) {
|
|
11294
|
+
fs2.mkdirSync(logsDir, { recursive: true });
|
|
11252
11295
|
}
|
|
11253
11296
|
const sanitizedName = sanitizeForFilename(entry.hookName);
|
|
11254
|
-
const logPath =
|
|
11297
|
+
const logPath = path2.join(logsDir, `${sanitizedName}.log`);
|
|
11255
11298
|
const lines = [];
|
|
11256
11299
|
lines.push(`=== ${entry.hookName} hook log ===`);
|
|
11257
11300
|
lines.push(`Timestamp: ${entry.timestamp}`);
|
|
@@ -11291,53 +11334,10 @@ function writeHookLog(autoDir, entry) {
|
|
|
11291
11334
|
lines.push("--- Output ---");
|
|
11292
11335
|
lines.push(JSON.stringify(entry.output, null, 2));
|
|
11293
11336
|
lines.push("");
|
|
11294
|
-
|
|
11337
|
+
fs2.appendFileSync(logPath, `${lines.join("\n")}
|
|
11295
11338
|
`);
|
|
11296
11339
|
}
|
|
11297
11340
|
|
|
11298
|
-
// src/activity-logger.ts
|
|
11299
|
-
var import_node_fs = __toESM(require("node:fs"));
|
|
11300
|
-
var import_node_path = __toESM(require("node:path"));
|
|
11301
|
-
function matchesFilter(hookName, message) {
|
|
11302
|
-
const filter = process.env.KETCHUP_LOG;
|
|
11303
|
-
if (!filter) {
|
|
11304
|
-
return true;
|
|
11305
|
-
}
|
|
11306
|
-
const patterns = filter.split(",").map((p) => p.trim());
|
|
11307
|
-
const includes = patterns.filter((p) => !p.startsWith("-"));
|
|
11308
|
-
const excludes = patterns.filter((p) => p.startsWith("-")).map((p) => p.slice(1));
|
|
11309
|
-
const searchText = `${hookName}: ${message}`;
|
|
11310
|
-
const excluded = excludes.some((pattern) => searchText.includes(pattern));
|
|
11311
|
-
if (excluded) {
|
|
11312
|
-
return false;
|
|
11313
|
-
}
|
|
11314
|
-
if (includes.length === 0 || includes.includes("*")) {
|
|
11315
|
-
return true;
|
|
11316
|
-
}
|
|
11317
|
-
return includes.some((pattern) => searchText.includes(pattern));
|
|
11318
|
-
}
|
|
11319
|
-
function activityLog(autoDir, sessionId, hookName, message) {
|
|
11320
|
-
if (!matchesFilter(hookName, message)) {
|
|
11321
|
-
return;
|
|
11322
|
-
}
|
|
11323
|
-
const logsDir = import_node_path.default.join(autoDir, "logs");
|
|
11324
|
-
if (!import_node_fs.default.existsSync(logsDir)) {
|
|
11325
|
-
import_node_fs.default.mkdirSync(logsDir, { recursive: true });
|
|
11326
|
-
}
|
|
11327
|
-
const logPath = import_node_path.default.join(logsDir, "activity.log");
|
|
11328
|
-
const now = /* @__PURE__ */ new Date();
|
|
11329
|
-
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
11330
|
-
const day = String(now.getDate()).padStart(2, "0");
|
|
11331
|
-
const hours = String(now.getHours()).padStart(2, "0");
|
|
11332
|
-
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
11333
|
-
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
11334
|
-
const timestamp = `${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
11335
|
-
const shortSessionId = sessionId.slice(-8);
|
|
11336
|
-
const entry = `${timestamp} [${shortSessionId}] ${hookName}: ${message}
|
|
11337
|
-
`;
|
|
11338
|
-
import_node_fs.default.appendFileSync(logPath, entry);
|
|
11339
|
-
}
|
|
11340
|
-
|
|
11341
11341
|
// src/debug-logger.ts
|
|
11342
11342
|
var import_node_fs2 = __toESM(require("node:fs"));
|
|
11343
11343
|
var import_node_path2 = __toESM(require("node:path"));
|
|
@@ -11578,7 +11578,8 @@ async function handlePreToolUse(claudeDir2, sessionId, toolInput, options2 = {})
|
|
|
11578
11578
|
const paths = await resolvePaths(claudeDir2);
|
|
11579
11579
|
const command = toolInput.command;
|
|
11580
11580
|
if (command && isCommitCommand(command)) {
|
|
11581
|
-
|
|
11581
|
+
const gitCwd = options2.cwd ?? process.cwd();
|
|
11582
|
+
return handleCommitValidation(claudeDir2, sessionId, command, options2, paths.autoDir, gitCwd);
|
|
11582
11583
|
}
|
|
11583
11584
|
const patterns = loadDenyPatterns(claudeDir2);
|
|
11584
11585
|
const filePath = toolInput.file_path;
|
|
@@ -11614,7 +11615,7 @@ async function handlePreToolUse(claudeDir2, sessionId, toolInput, options2 = {})
|
|
|
11614
11615
|
}
|
|
11615
11616
|
};
|
|
11616
11617
|
}
|
|
11617
|
-
async function handleCommitValidation(claudeDir2, sessionId, command, options2, autoDir) {
|
|
11618
|
+
async function handleCommitValidation(claudeDir2, sessionId, command, options2, autoDir, gitCwd) {
|
|
11618
11619
|
const paths = await resolvePaths(claudeDir2);
|
|
11619
11620
|
const allValidators = loadValidators([paths.validatorsDir]);
|
|
11620
11621
|
const validators = allValidators.filter((v) => v.name !== "appeal-system");
|
|
@@ -11627,7 +11628,7 @@ async function handleCommitValidation(claudeDir2, sessionId, command, options2,
|
|
|
11627
11628
|
}
|
|
11628
11629
|
};
|
|
11629
11630
|
}
|
|
11630
|
-
const context = getCommitContext(
|
|
11631
|
+
const context = getCommitContext(gitCwd, command);
|
|
11631
11632
|
const state = createHookState(autoDir).read();
|
|
11632
11633
|
const onLog = (event, name, detail) => {
|
|
11633
11634
|
activityLog(autoDir, sessionId, "pre-tool-use", `validator ${event}: ${name} \u2192 ${detail}`);
|
|
@@ -11665,7 +11666,7 @@ var startTime = Date.now();
|
|
|
11665
11666
|
try {
|
|
11666
11667
|
const toolInput = input.tool_input || {};
|
|
11667
11668
|
const command = toolInput.command;
|
|
11668
|
-
const result = await handlePreToolUse(claudeDir, input.session_id, toolInput);
|
|
11669
|
+
const result = await handlePreToolUse(claudeDir, input.session_id, toolInput, { cwd: input.cwd });
|
|
11669
11670
|
if (command && isCommitCommand(command)) {
|
|
11670
11671
|
writeHookLog(autoDir, {
|
|
11671
11672
|
hookName: "pre-tool-use",
|
|
@@ -11678,6 +11679,7 @@ var startTime = Date.now();
|
|
|
11678
11679
|
console.log(JSON.stringify(result));
|
|
11679
11680
|
process.exit(0);
|
|
11680
11681
|
} catch (err) {
|
|
11682
|
+
activityLog(autoDir, input.session_id, "pre-tool-use", `error: ${String(err)}`);
|
|
11681
11683
|
writeHookLog(autoDir, {
|
|
11682
11684
|
hookName: "pre-tool-use",
|
|
11683
11685
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|