jinzd-ai-cli 0.4.77 → 0.4.79

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.
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ConfigManager
4
+ } from "./chunk-34OKHMTQ.js";
5
+ import "./chunk-2ZD3YTVM.js";
6
+ import "./chunk-RRL5572W.js";
7
+
8
+ // src/cli/batch.ts
9
+ import Anthropic from "@anthropic-ai/sdk";
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
11
+ import { join } from "path";
12
+ function parseBatchInput(jsonl) {
13
+ const lines = jsonl.split("\n").map((l) => l.trim()).filter(Boolean);
14
+ if (lines.length === 0) throw new Error("Input file is empty");
15
+ if (lines.length > 1e5) throw new Error(`Too many requests: ${lines.length} (Anthropic limit: 100000)`);
16
+ const seen = /* @__PURE__ */ new Set();
17
+ const out = [];
18
+ for (let i = 0; i < lines.length; i++) {
19
+ const line = lines[i];
20
+ let obj;
21
+ try {
22
+ obj = JSON.parse(line);
23
+ } catch (err) {
24
+ throw new Error(`Line ${i + 1}: invalid JSON (${err instanceof Error ? err.message : String(err)})`);
25
+ }
26
+ if (!obj || typeof obj !== "object") {
27
+ throw new Error(`Line ${i + 1}: expected JSON object`);
28
+ }
29
+ const rec = obj;
30
+ const customId = String(rec.customId ?? rec.custom_id ?? "");
31
+ if (!customId) throw new Error(`Line ${i + 1}: missing customId`);
32
+ if (!/^[A-Za-z0-9_-]{1,64}$/.test(customId)) {
33
+ throw new Error(`Line ${i + 1}: customId "${customId}" must be 1-64 chars of [A-Za-z0-9_-]`);
34
+ }
35
+ if (seen.has(customId)) throw new Error(`Line ${i + 1}: duplicate customId "${customId}"`);
36
+ seen.add(customId);
37
+ const messages = rec.messages;
38
+ if (!Array.isArray(messages) || messages.length === 0) {
39
+ throw new Error(`Line ${i + 1}: messages must be a non-empty array`);
40
+ }
41
+ for (let j = 0; j < messages.length; j++) {
42
+ const m = messages[j];
43
+ if (!m || m.role !== "user" && m.role !== "assistant") {
44
+ throw new Error(`Line ${i + 1}: messages[${j}].role must be 'user' or 'assistant'`);
45
+ }
46
+ if (typeof m.content !== "string") {
47
+ throw new Error(`Line ${i + 1}: messages[${j}].content must be a string`);
48
+ }
49
+ }
50
+ out.push({
51
+ customId,
52
+ messages,
53
+ model: typeof rec.model === "string" ? rec.model : void 0,
54
+ system: typeof rec.system === "string" ? rec.system : void 0,
55
+ maxTokens: typeof rec.maxTokens === "number" ? rec.maxTokens : typeof rec.max_tokens === "number" ? rec.max_tokens : void 0
56
+ });
57
+ }
58
+ return out;
59
+ }
60
+ function getBatchesPath(config) {
61
+ return join(config.getConfigDir(), "batches.json");
62
+ }
63
+ function loadTrackedBatches(config) {
64
+ const p = getBatchesPath(config);
65
+ if (!existsSync(p)) return [];
66
+ try {
67
+ const data = JSON.parse(readFileSync(p, "utf-8"));
68
+ return Array.isArray(data.batches) ? data.batches : [];
69
+ } catch {
70
+ return [];
71
+ }
72
+ }
73
+ function saveTrackedBatches(config, batches) {
74
+ mkdirSync(config.getConfigDir(), { recursive: true });
75
+ writeFileSync(getBatchesPath(config), JSON.stringify({ batches }, null, 2), "utf-8");
76
+ }
77
+ function getClaudeClient(config) {
78
+ const apiKey = config.getApiKey("claude");
79
+ if (!apiKey) {
80
+ throw new Error("No Claude API key configured. Run `aicli config` or set AICLI_API_KEY_CLAUDE.");
81
+ }
82
+ return new Anthropic({ apiKey });
83
+ }
84
+ function getDefaultModel(config) {
85
+ const models = config.get("defaultModels");
86
+ return models?.claude ?? "claude-sonnet-4-5-20250929";
87
+ }
88
+ async function cmdSubmit(inputFile, options = {}) {
89
+ const config = new ConfigManager();
90
+ if (!existsSync(inputFile)) throw new Error(`Input file not found: ${inputFile}`);
91
+ const raw = readFileSync(inputFile, "utf-8");
92
+ const requests = parseBatchInput(raw);
93
+ const defaultModel = getDefaultModel(config);
94
+ console.log(`Parsed ${requests.length} request(s) from ${inputFile}`);
95
+ console.log(`Default model: ${defaultModel}`);
96
+ if (options.dryRun) {
97
+ console.log("[dry-run] Not submitting. Sample request:");
98
+ console.log(JSON.stringify(requests[0], null, 2));
99
+ return;
100
+ }
101
+ const client = getClaudeClient(config);
102
+ const apiRequests = requests.map((r) => ({
103
+ custom_id: r.customId,
104
+ params: {
105
+ model: r.model ?? defaultModel,
106
+ max_tokens: r.maxTokens ?? 4096,
107
+ messages: r.messages,
108
+ ...r.system ? { system: r.system } : {}
109
+ }
110
+ }));
111
+ console.log(`Submitting ${apiRequests.length} request(s) to Anthropic Batches API\u2026`);
112
+ const batch = await client.messages.batches.create({ requests: apiRequests });
113
+ const tracked = loadTrackedBatches(config);
114
+ tracked.unshift({
115
+ id: batch.id,
116
+ provider: "claude",
117
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
118
+ inputFile,
119
+ requestCount: requests.length,
120
+ model: defaultModel
121
+ });
122
+ saveTrackedBatches(config, tracked.slice(0, 200));
123
+ console.log(`
124
+ Batch submitted:`);
125
+ console.log(` ID: ${batch.id}`);
126
+ console.log(` Processing: ${batch.processing_status}`);
127
+ console.log(` Expires: ${batch.expires_at}`);
128
+ console.log(`
129
+ Check status: aicli batch status ${batch.id}`);
130
+ console.log(`Get results: aicli batch results ${batch.id}`);
131
+ }
132
+ async function cmdList() {
133
+ const config = new ConfigManager();
134
+ const tracked = loadTrackedBatches(config);
135
+ if (tracked.length === 0) {
136
+ console.log("No tracked batches. Submit one with `aicli batch submit <input.jsonl>`.");
137
+ return;
138
+ }
139
+ const client = getClaudeClient(config);
140
+ console.log(`
141
+ ${tracked.length} tracked batch(es):
142
+ `);
143
+ console.log(" ID Requests Status Created");
144
+ console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
145
+ for (const b of tracked.slice(0, 20)) {
146
+ let status = "(unknown)";
147
+ try {
148
+ const fresh = await client.messages.batches.retrieve(b.id);
149
+ status = fresh.processing_status;
150
+ } catch {
151
+ status = "(fetch-failed)";
152
+ }
153
+ const created = new Date(b.createdAt).toLocaleString();
154
+ console.log(` ${b.id.padEnd(42)} ${String(b.requestCount).padStart(8)} ${status.padEnd(18)} ${created}`);
155
+ }
156
+ console.log("");
157
+ }
158
+ async function cmdStatus(batchId) {
159
+ const config = new ConfigManager();
160
+ const client = getClaudeClient(config);
161
+ const batch = await client.messages.batches.retrieve(batchId);
162
+ console.log(`
163
+ Batch ${batch.id}`);
164
+ console.log(` Processing: ${batch.processing_status}`);
165
+ console.log(` Created: ${batch.created_at}`);
166
+ console.log(` Expires: ${batch.expires_at}`);
167
+ if (batch.ended_at) console.log(` Ended: ${batch.ended_at}`);
168
+ const counts = batch.request_counts;
169
+ if (counts) {
170
+ console.log(` Counts: processing=${counts.processing} succeeded=${counts.succeeded} errored=${counts.errored} canceled=${counts.canceled} expired=${counts.expired}`);
171
+ }
172
+ if (batch.results_url) console.log(` Results URL: ${batch.results_url}`);
173
+ console.log("");
174
+ }
175
+ async function cmdResults(batchId, outPath) {
176
+ const config = new ConfigManager();
177
+ const client = getClaudeClient(config);
178
+ const batch = await client.messages.batches.retrieve(batchId);
179
+ if (batch.processing_status !== "ended") {
180
+ console.log(`Batch is not ready yet (status: ${batch.processing_status}). Try again later.`);
181
+ return;
182
+ }
183
+ const stream = await client.messages.batches.results(batchId);
184
+ const lines = [];
185
+ let ok = 0, err = 0;
186
+ for await (const result of stream) {
187
+ lines.push(JSON.stringify(result));
188
+ const type = result.result?.type;
189
+ if (type === "succeeded") ok++;
190
+ else err++;
191
+ }
192
+ const body = lines.join("\n") + "\n";
193
+ if (outPath) {
194
+ writeFileSync(outPath, body, "utf-8");
195
+ console.log(`Saved ${lines.length} result(s) to ${outPath} (${ok} succeeded, ${err} failed/errored).`);
196
+ } else {
197
+ process.stdout.write(body);
198
+ process.stderr.write(`
199
+ [Summary] ${lines.length} results: ${ok} succeeded, ${err} failed/errored.
200
+ `);
201
+ }
202
+ }
203
+ async function cmdCancel(batchId) {
204
+ const config = new ConfigManager();
205
+ const client = getClaudeClient(config);
206
+ const batch = await client.messages.batches.cancel(batchId);
207
+ console.log(`Canceled batch ${batch.id} (status: ${batch.processing_status}).`);
208
+ }
209
+ export {
210
+ cmdCancel,
211
+ cmdList,
212
+ cmdResults,
213
+ cmdStatus,
214
+ cmdSubmit,
215
+ loadTrackedBatches,
216
+ parseBatchInput,
217
+ saveTrackedBatches
218
+ };
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-S4WDPHKS.js";
11
+ } from "./chunk-RRL5572W.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  schemaToJsonSchema,
4
4
  truncateForPersist
5
- } from "./chunk-LKDX2GOW.js";
5
+ } from "./chunk-MOE2D3NR.js";
6
6
  import {
7
7
  AuthError,
8
8
  ProviderError,
@@ -18,7 +18,7 @@ import {
18
18
  MCP_PROTOCOL_VERSION,
19
19
  MCP_TOOL_PREFIX,
20
20
  VERSION
21
- } from "./chunk-S4WDPHKS.js";
21
+ } from "./chunk-RRL5572W.js";
22
22
 
23
23
  // src/providers/claude.ts
24
24
  import Anthropic from "@anthropic-ai/sdk";
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.77";
9
+ var VERSION = "0.4.79";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-6VRJGH25.js";
20
20
  import {
21
21
  runTestsTool
22
- } from "./chunk-QATT4NCL.js";
22
+ } from "./chunk-ZT7RZYWE.js";
23
23
  import {
24
24
  CONFIG_DIR_NAME,
25
25
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
@@ -27,7 +27,7 @@ import {
27
27
  SUBAGENT_ALLOWED_TOOLS,
28
28
  SUBAGENT_DEFAULT_MAX_ROUNDS,
29
29
  SUBAGENT_MAX_ROUNDS_LIMIT
30
- } from "./chunk-S4WDPHKS.js";
30
+ } from "./chunk-RRL5572W.js";
31
31
 
32
32
  // src/tools/builtin/bash.ts
33
33
  import { execSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.77";
4
+ var VERSION = "0.4.79";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-S4WDPHKS.js";
4
+ } from "./chunk-RRL5572W.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync } from "child_process";