code-agent-auto-commit 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,23 +44,20 @@ cac --help
44
44
  # 1. Initialize config
45
45
  cac init
46
46
 
47
- # 2. Configure AI API key for commit messages
48
- # Edit .cac/.code-agent-auto-commit.jsonset your model and defaultProvider.
49
- # Fill keys in .cac/.env and load them:
50
- source .cac/.env
51
- # OR:
52
- cac ai set-key <provider|ENV_VAR> <api-key> [--config <path>]
47
+ # 2. Configure AI API key (pick one method):
48
+ # Global (recommendedworks across all projects):
49
+ cac ai set-key <provider|ENV_VAR> <api-key>
50
+ # Or project-level (edit .cac/.env):
51
+ echo 'MINIMAX_API_KEY=sk-xxx' >> .cac/.env
53
52
 
54
53
  # 3. Install hooks
55
54
  cac install --tool all --scope project
56
55
 
57
56
  # 4. Verify
58
57
  cac status --scope project
58
+ cac ai "hello"
59
59
 
60
- # 5. Git config
61
- git init
62
-
63
- # 6. Agentic coding
60
+ # 5. Agentic coding
64
61
  opencode / claude / codex
65
62
  ```
66
63
 
@@ -69,7 +66,7 @@ opencode / claude / codex
69
66
  > generic `chore(auto): ...` prefixed messages.
70
67
  >
71
68
  > **Model tip:** Choose a fast, lightweight model (e.g. `gpt-4.1-mini`,
72
- > `MiniMax-M2.1-highspeed`). Commit messages are short — speed matters more
69
+ > `MiniMax-M2.5-highspeed`). Commit messages are short — speed matters more
73
70
  > than intelligence here.
74
71
 
75
72
  ## Commands
@@ -116,11 +113,17 @@ Full schema and options:
116
113
  - `doc/CONFIG.md`
117
114
  - `doc/zh-CN.md`
118
115
 
119
- ### AI Key Fields
116
+ ### AI Key Resolution
117
+
118
+ `cac` resolves API keys automatically in this order (first match wins):
119
+
120
+ 1. **`process.env`** — environment variable already set in the current shell
121
+ 2. **`~/.config/code-agent-auto-commit/keys.env`** — global keys file (written by `cac ai set-key`)
122
+ 3. **`.cac/.env`** — project-level env file (created by `cac init`)
123
+ 4. **`ai.providers.<name>.apiKey`** — key stored directly in config (not recommended)
120
124
 
121
- - `ai.providers.<name>.apiKeyEnv` expects an environment variable name (for example, `MINIMAX_API_KEY`), not the raw key value.
122
- - If you prefer storing a key directly in config, use `ai.providers.<name>.apiKey`.
123
- - If AI request fails (missing key, invalid provider/model, or non-2xx response), `cac` falls back to `commit.fallbackPrefix`-style messages.
125
+ This means **hooks work out of the box** no need to manually `source .cac/.env` before running.
126
+ If AI request fails (missing key, invalid provider/model, or non-2xx response), `cac` falls back to `commit.fallbackPrefix`-style messages.
124
127
 
125
128
  ## AI Models (Multi-Provider)
126
129
 
package/dist/cli.js CHANGED
@@ -369,6 +369,7 @@ async function commandAI(flags, positionals) {
369
369
  const worktree = node_path_1.default.resolve(getStringFlag(flags, "worktree") ?? process.cwd());
370
370
  const explicitConfig = getStringFlag(flags, "config");
371
371
  const loaded = (0, config_1.loadConfig)({ explicitPath: explicitConfig, worktree });
372
+ (0, fs_1.loadProjectAndGlobalEnv)(worktree);
372
373
  const subcommand = positionals[0];
373
374
  if (subcommand === "set-key") {
374
375
  const target = positionals[1];
package/dist/core/exec.js CHANGED
@@ -8,6 +8,7 @@ function runCommand(command, args, cwd) {
8
8
  cwd,
9
9
  encoding: "utf8",
10
10
  stdio: ["ignore", "pipe", "pipe"],
11
+ maxBuffer: 10 * 1024 * 1024,
11
12
  });
12
13
  return {
13
14
  exitCode: result.status ?? 1,
package/dist/core/fs.d.ts CHANGED
@@ -10,3 +10,5 @@ export declare function ensureDirForFile(filePath: string): void;
10
10
  export declare function readJsonFile<T>(filePath: string): T | undefined;
11
11
  export declare function writeJsonFile(filePath: string, value: unknown): void;
12
12
  export declare function writeTextFile(filePath: string, content: string): void;
13
+ export declare function loadEnvFileIntoProcess(filePath: string): void;
14
+ export declare function loadProjectAndGlobalEnv(worktree: string): void;
package/dist/core/fs.js CHANGED
@@ -15,6 +15,8 @@ exports.ensureDirForFile = ensureDirForFile;
15
15
  exports.readJsonFile = readJsonFile;
16
16
  exports.writeJsonFile = writeJsonFile;
17
17
  exports.writeTextFile = writeTextFile;
18
+ exports.loadEnvFileIntoProcess = loadEnvFileIntoProcess;
19
+ exports.loadProjectAndGlobalEnv = loadProjectAndGlobalEnv;
18
20
  const node_fs_1 = __importDefault(require("node:fs"));
19
21
  const node_os_1 = __importDefault(require("node:os"));
20
22
  const node_path_1 = __importDefault(require("node:path"));
@@ -78,3 +80,31 @@ function writeTextFile(filePath, content) {
78
80
  ensureDirForFile(filePath);
79
81
  node_fs_1.default.writeFileSync(filePath, content, "utf8");
80
82
  }
83
+ function parseEnvValue(raw) {
84
+ const trimmed = raw.trim();
85
+ if ((trimmed.startsWith("'") && trimmed.endsWith("'")) ||
86
+ (trimmed.startsWith("\"") && trimmed.endsWith("\""))) {
87
+ return trimmed.slice(1, -1);
88
+ }
89
+ return trimmed;
90
+ }
91
+ function loadEnvFileIntoProcess(filePath) {
92
+ if (!node_fs_1.default.existsSync(filePath)) {
93
+ return;
94
+ }
95
+ const lines = node_fs_1.default.readFileSync(filePath, "utf8").split(/\r?\n/);
96
+ for (const line of lines) {
97
+ const match = line.match(/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
98
+ if (!match) {
99
+ continue;
100
+ }
101
+ const [, key, rawValue] = match;
102
+ if (process.env[key] === undefined || process.env[key] === "") {
103
+ process.env[key] = parseEnvValue(rawValue);
104
+ }
105
+ }
106
+ }
107
+ function loadProjectAndGlobalEnv(worktree) {
108
+ loadEnvFileIntoProcess(getGlobalKeysEnvPath());
109
+ loadEnvFileIntoProcess(getProjectEnvPath(worktree));
110
+ }
package/dist/core/run.js CHANGED
@@ -8,6 +8,7 @@ const node_path_1 = __importDefault(require("node:path"));
8
8
  const ai_1 = require("./ai");
9
9
  const config_1 = require("./config");
10
10
  const filter_1 = require("./filter");
11
+ const fs_1 = require("./fs");
11
12
  const git_1 = require("./git");
12
13
  function normalizeFallbackType(prefix) {
13
14
  const value = prefix.toLowerCase();
@@ -72,6 +73,7 @@ async function buildMessage(prefix, maxLength, aiConfig, stagedPath, fallback, w
72
73
  async function runAutoCommit(context, configOptions) {
73
74
  const { config } = (0, config_1.loadConfig)(configOptions);
74
75
  const worktree = node_path_1.default.resolve(context.worktree ?? config.worktree);
76
+ (0, fs_1.loadProjectAndGlobalEnv)(worktree);
75
77
  if (!config.enabled) {
76
78
  return {
77
79
  skipped: true,
package/doc/CONFIG.md CHANGED
@@ -20,28 +20,28 @@
20
20
  "maxMessageLength": 72
21
21
  },
22
22
  "ai": {
23
- "enabled": false,
23
+ "enabled": true,
24
24
  "timeoutMs": 15000,
25
- "model": "openai/gpt-4.1-mini",
26
- "defaultProvider": "openai",
25
+ "model": "minimax/MiniMax-M2.5-highspeed",
26
+ "defaultProvider": "minimax",
27
27
  "providers": {
28
28
  "openai": {
29
29
  "api": "openai-completions",
30
30
  "baseUrl": "https://api.openai.com/v1",
31
31
  "apiKeyEnv": "OPENAI_API_KEY"
32
32
  },
33
- "anthropic": {
34
- "api": "anthropic-messages",
35
- "baseUrl": "https://api.anthropic.com/v1",
36
- "apiKeyEnv": "ANTHROPIC_API_KEY"
33
+ "minimax": {
34
+ "api": "openai-completions",
35
+ "baseUrl": "https://api.minimaxi.chat/v1",
36
+ "apiKeyEnv": "MINIMAX_API_KEY"
37
37
  }
38
38
  }
39
39
  },
40
40
  "push": {
41
- "enabled": false,
41
+ "enabled": true,
42
42
  "provider": "github",
43
43
  "remote": "origin",
44
- "branch": ""
44
+ "branch": "main"
45
45
  },
46
46
  "filters": {
47
47
  "include": [],
@@ -61,6 +61,22 @@
61
61
  - `ai.providers.<name>.apiKey` or `apiKeyEnv`: API key source (env preferred).
62
62
  - `ai.providers.<name>.headers`: optional custom headers.
63
63
 
64
+ ## API Key Resolution
65
+
66
+ `cac` resolves API keys automatically in this order (first match wins, no override):
67
+
68
+ | Priority | Source | Description |
69
+ |----------|--------|-------------|
70
+ | 1 | `process.env` | Environment variable in current shell |
71
+ | 2 | `~/.config/code-agent-auto-commit/keys.env` | Global keys file (`cac ai set-key` writes here) |
72
+ | 3 | `.cac/.env` | Project-level env file (`cac init` generates this) |
73
+ | 4 | `ai.providers.<name>.apiKey` | Direct key in config JSON (not recommended) |
74
+
75
+ Both `export KEY='value'` and `KEY=value` formats are supported in env files.
76
+
77
+ This auto-loading ensures **hooks work without manual `source`** — the subprocess
78
+ reads keys from files even when shell env vars are not inherited.
79
+
64
80
  ## Notes
65
81
 
66
82
  - `commit.mode`
@@ -70,6 +86,5 @@
70
86
  - `github`: remote URL must contain `github`
71
87
  - `gitlab`: remote URL must contain `gitlab`
72
88
  - `generic`: no provider URL validation
73
- - Keep API keys in environment variables when possible.
74
- - `cac init` also creates `.cac/.env.example` and `.cac/.env` with provider key variables.
89
+ - `cac init` creates `.cac/.env.example` and `.cac/.env` with provider key variables.
75
90
  - Hook-triggered `cac run` writes output logs to `.cac/run-<timestamp>.log`.
package/doc/zh-CN.md CHANGED
@@ -14,26 +14,30 @@ It runs commits automatically when a chat/agent turn ends.
14
14
  # 1. 初始化配置
15
15
  cac init
16
16
 
17
- # 2. 配置 AI API Key(必须,否则无法生成 AI commit message)
18
- # 编辑 .cac/.code-agent-auto-commit.json,设置 model 和 defaultProvider。
19
- # 在 .cac/.env 中填入 API Key 后加载:
20
- source .cac/.env
21
- # 或者:
22
- cac ai set-key <provider|ENV_VAR> <api-key> [--config <path>]
17
+ # 2. 配置 AI API Key(必须,二选一)
18
+ # 全局设置(推荐,所有项目通用):
19
+ cac ai set-key <provider|ENV_VAR> <api-key>
20
+ # 或项目级(编辑 .cac/.env):
21
+ echo 'MINIMAX_API_KEY=sk-xxx' >> .cac/.env
23
22
 
24
23
  # 3. 安装钩子
25
24
  cac install --tool all --scope project
26
25
 
27
- # 4. 验证状态
26
+ # 4. 验证
28
27
  cac status --scope project
28
+ cac ai "hello"
29
29
  ```
30
30
 
31
31
  > **重要:** `cac init` 之后**必须**配置 AI provider 的 API Key。
32
32
  > 没有有效的 Key,AI 生成 commit message 会失败,`cac` 会退回到
33
33
  > `chore(auto): ...` 格式的通用消息。
34
34
  >
35
+ > **Key 自动加载:** 无需手动 `source .cac/.env`。`cac run` 和 `cac ai` 启动时
36
+ > 会自动从 `~/.config/.../keys.env`(全局)和 `.cac/.env`(项目级)加载 API Key。
37
+ > Hook 触发的子进程也能正常工作。
38
+ >
35
39
  > **模型选择建议:** 推荐选择速度快、轻量的模型(如 `gpt-4.1-mini`、
36
- > `MiniMax-M2.1-highspeed`)。Commit message 内容很短,速度比智能更重要。
40
+ > `MiniMax-M2.5-highspeed`)。Commit message 内容很短,速度比智能更重要。
37
41
 
38
42
  ## Command Reference
39
43
 
@@ -85,10 +89,22 @@ Default location in repository root: `.cac/.code-agent-auto-commit.json`
85
89
 
86
90
  For full field details, see `doc/CONFIG.md`.
87
91
 
92
+ ## API Key 解析顺序
93
+
94
+ `cac` 按以下优先级自动查找 API Key(先到先得,不覆盖):
95
+
96
+ | 优先级 | 来源 | 说明 |
97
+ |--------|------|------|
98
+ | 1 | `process.env` | 当前 shell 已有的环境变量 |
99
+ | 2 | `~/.config/code-agent-auto-commit/keys.env` | 全局 key 文件(`cac ai set-key` 写入) |
100
+ | 3 | `.cac/.env` | 项目级 env 文件(`cac init` 生成) |
101
+ | 4 | `ai.providers.<name>.apiKey` | 配置文件中直接写的 key(不推荐) |
102
+
103
+ env 文件支持 `export KEY='value'` 和 `KEY=value` 两种格式。
104
+
88
105
  ## Important Notes
89
106
 
90
107
  - `.env` and key-like files are excluded by default.
91
108
  - `per-file` mode requires a clean staging area.
92
109
  - Push is disabled by default; verify remote and branch settings before enabling.
93
- - `ai.providers.<name>.apiKeyEnv` must be an environment variable name (for example, `MINIMAX_API_KEY`), not the raw key.
94
- - If you want to store the key directly in config, use `ai.providers.<name>.apiKey`.
110
+ - Hook 触发的 `cac run` 会自动加载 env 文件,无需手动 `source`。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-agent-auto-commit",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "CAC provides configurable AI auto-commit(using your git account) for OpenCode, Claude Code, Codex, and other AI code agents",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -23,13 +23,6 @@
23
23
  "publishConfig": {
24
24
  "access": "public"
25
25
  },
26
- "scripts": {
27
- "clean": "rm -rf dist",
28
- "build": "tsc -p tsconfig.json",
29
- "typecheck": "tsc -p tsconfig.json --noEmit",
30
- "test": "tsc -p tsconfig.test.json && node --test dist-test/tests/*.test.js",
31
- "prepare": "pnpm run build"
32
- },
33
26
  "keywords": [
34
27
  "git",
35
28
  "commit",
@@ -41,7 +34,6 @@
41
34
  "engines": {
42
35
  "node": ">=20"
43
36
  },
44
- "packageManager": "pnpm@10.28.2",
45
37
  "repository": {
46
38
  "type": "git",
47
39
  "url": "https://github.com/0xtresser/code-agent-auto-commit.git"
@@ -53,5 +45,11 @@
53
45
  "devDependencies": {
54
46
  "@types/node": "^22.10.0",
55
47
  "typescript": "^5.7.2"
48
+ },
49
+ "scripts": {
50
+ "clean": "rm -rf dist",
51
+ "build": "tsc -p tsconfig.json",
52
+ "typecheck": "tsc -p tsconfig.json --noEmit",
53
+ "test": "tsc -p tsconfig.test.json && node --test dist-test/tests/*.test.js"
56
54
  }
57
- }
55
+ }