codemini-cli 0.4.6 → 0.4.8

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/deployment.md CHANGED
@@ -13,13 +13,13 @@ npm pack
13
13
  Expected output:
14
14
 
15
15
  ```text
16
- codemini-cli-0.4.6.tgz
16
+ codemini-cli-0.4.8.tgz
17
17
  ```
18
18
 
19
19
  If you want to verify the package contents:
20
20
 
21
21
  ```bash
22
- tar -tf codemini-cli-0.4.6.tgz
22
+ tar -tf codemini-cli-0.4.8.tgz
23
23
  ```
24
24
 
25
25
  ## 2. Copy To The Target Machine
@@ -34,7 +34,7 @@ Copy the generated `.tgz` file to the Win10 machine by one of these methods:
34
34
  Recommended target path:
35
35
 
36
36
  ```powershell
37
- C:\temp\codemini-cli-0.4.6.tgz
37
+ C:\temp\codemini-cli-0.4.8.tgz
38
38
  ```
39
39
 
40
40
  ## 3. Environment Requirements
@@ -58,7 +58,7 @@ npm -v
58
58
  Global install:
59
59
 
60
60
  ```powershell
61
- npm install -g C:\temp\codemini-cli-0.4.6.tgz
61
+ npm install -g C:\temp\codemini-cli-0.4.8.tgz
62
62
  ```
63
63
 
64
64
  If global install is blocked by company policy, install in a working directory instead:
@@ -66,7 +66,7 @@ If global install is blocked by company policy, install in a working directory i
66
66
  ```powershell
67
67
  mkdir C:\temp\coder-test
68
68
  cd C:\temp\coder-test
69
- npm install C:\temp\codemini-cli-0.4.6.tgz
69
+ npm install C:\temp\codemini-cli-0.4.8.tgz
70
70
  ```
71
71
 
72
72
  ## 5. Confirm Installation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemini-cli",
3
- "version": "0.4.6",
3
+ "version": "0.4.8",
4
4
  "description": "Coding CLI optimized for small-model workflows and Windows PowerShell",
5
5
  "keywords": [
6
6
  "cli",
package/src/cli.js CHANGED
@@ -10,11 +10,11 @@ const VERSION = pkg.version;
10
10
  function printHelp() {
11
11
  console.log(`codemini ${VERSION}
12
12
  Usage:
13
- codemini [prompt] [--plain]
14
- codemini chat [prompt] [--plain]
15
- codemini run <task> [--max-steps N] [--model <name>]
16
- codemini run --harness <role> <task> [--max-steps N] [--model <name>]
17
- codemini run --pipeline <task> [--model <name>]
13
+ codemini [prompt] [--plain] [--model <name>] [--fast]
14
+ codemini chat [prompt] [--plain] [--model <name>] [--fast]
15
+ codemini run <task> [--max-steps N] [--model <name>] [--fast]
16
+ codemini run --harness <role> <task> [--max-steps N] [--model <name>] [--fast]
17
+ codemini run --pipeline <task> [--model <name>] [--fast]
18
18
  codemini config set|get|list <key> [value]
19
19
  codemini doctor
20
20
  codemini skill list|install|enable|disable|inspect|reindex [--scope=project|global]
@@ -11,6 +11,7 @@ function parseChatArgs(args) {
11
11
  prompt: '',
12
12
  sessionId: undefined,
13
13
  model: undefined,
14
+ fast: false,
14
15
  system: undefined,
15
16
  plain: false
16
17
  };
@@ -27,6 +28,10 @@ function parseChatArgs(args) {
27
28
  i += 1;
28
29
  continue;
29
30
  }
31
+ if (arg === '--fast' || arg === '--lite') {
32
+ parsed.fast = true;
33
+ continue;
34
+ }
30
35
  if (arg === '--system') {
31
36
  parsed.system = args[i + 1];
32
37
  i += 1;
@@ -134,6 +139,7 @@ export async function handleChat(args) {
134
139
  const parsed = parseChatArgs(args);
135
140
  const config = await loadConfig();
136
141
  const session = await resolveSession(parsed.sessionId);
142
+ const selectedModel = parsed.fast ? (config.model?.fast_name || config.model?.name) : parsed.model;
137
143
  const systemPrompt =
138
144
  parsed.system ||
139
145
  buildDefaultSystemPrompt(config);
@@ -141,7 +147,7 @@ export async function handleChat(args) {
141
147
  const runtime = await createChatRuntime({
142
148
  session,
143
149
  config,
144
- model: parsed.model,
150
+ model: selectedModel,
145
151
  systemPrompt
146
152
  });
147
153
 
@@ -164,7 +170,7 @@ export async function handleChat(args) {
164
170
  React.createElement(ChatApp, {
165
171
  runtime,
166
172
  sessionId: session.id,
167
- model: parsed.model || config.model.name,
173
+ model: selectedModel || config.model.name,
168
174
  sdkProvider: config.sdk?.provider || 'openai-compatible',
169
175
  language: config.ui?.language || 'zh',
170
176
  shellName: config.shell?.default || 'powershell',
@@ -22,6 +22,7 @@ function parseRunArgs(args) {
22
22
  const parsed = {
23
23
  task: '',
24
24
  model: undefined,
25
+ fast: false,
25
26
  maxSteps: 8,
26
27
  harness: null,
27
28
  pipeline: false
@@ -33,6 +34,10 @@ function parseRunArgs(args) {
33
34
  i += 1;
34
35
  continue;
35
36
  }
37
+ if (arg === '--fast' || arg === '--lite') {
38
+ parsed.fast = true;
39
+ continue;
40
+ }
36
41
  if (arg === '--max-steps') {
37
42
  parsed.maxSteps = Number(args[i + 1] || 8);
38
43
  i += 1;
@@ -239,6 +244,7 @@ export async function handleRun(args) {
239
244
  }
240
245
 
241
246
  const config = await loadConfig();
247
+ const selectedModel = parsed.fast ? (config.model?.fast_name || config.model?.name) : parsed.model;
242
248
  const systemPrompt = await buildSystemPrompt(config);
243
249
 
244
250
  if (parsed.pipeline) {
@@ -246,7 +252,7 @@ export async function handleRun(args) {
246
252
  task: parsed.task,
247
253
  config,
248
254
  systemPrompt,
249
- model: parsed.model
255
+ model: selectedModel
250
256
  });
251
257
  for (const step of state.steps) {
252
258
  console.log(`\n--- [${step.role}] ${step.title} ---`);
@@ -261,7 +267,7 @@ export async function handleRun(args) {
261
267
  task: parsed.task,
262
268
  config,
263
269
  systemPrompt,
264
- model: parsed.model,
270
+ model: selectedModel,
265
271
  maxSteps: parsed.maxSteps
266
272
  });
267
273
  console.log(result.text);
@@ -276,7 +282,7 @@ export async function handleRun(args) {
276
282
  const result = await runAgentLoop({
277
283
  systemPrompt,
278
284
  userPrompt: parsed.task,
279
- model: parsed.model || config.model.name,
285
+ model: selectedModel || config.model.name,
280
286
  toolDefinitions: definitions,
281
287
  toolHandlers: handlers,
282
288
  toolFormatters: formatters,
@@ -65,7 +65,7 @@ async function setSkillEnabledConfig(name, enabled) {
65
65
  await saveConfig(config);
66
66
  }
67
67
 
68
- async function listSkillEntries({ scope = 'all', cwd = process.cwd() } = {}) {
68
+ export async function listSkillEntries({ scope = 'all', cwd = process.cwd() } = {}) {
69
69
  const commands = await loadCommandsAndSkills(cwd);
70
70
  const config = await loadConfig();
71
71
  const entries = [];
@@ -753,13 +753,17 @@ export async function runAgentLoop({
753
753
  const effectiveArgs = approvalState.args || args;
754
754
 
755
755
  if (approvalState.errorContent) {
756
+ const summary = trimInline(approvalState.errorContent, 120);
756
757
  if (onEvent) {
757
- onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary: trimInline(approvalState.errorContent, 120) });
758
+ onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary });
758
759
  }
759
760
  return {
760
761
  callId: call.id,
761
762
  content: approvalState.errorContent,
762
- error: true
763
+ error: true,
764
+ durationMs: 0,
765
+ summary,
766
+ status: 'error'
763
767
  };
764
768
  }
765
769
 
@@ -772,27 +776,46 @@ export async function runAgentLoop({
772
776
  return {
773
777
  callId: call.id,
774
778
  content: JSON.stringify(blockedPayload),
775
- blocked: true
779
+ blocked: true,
780
+ summary: 'Tool call requires approval',
781
+ status: 'blocked'
776
782
  };
777
783
  }
778
784
 
779
785
  if (onEvent) onEvent({ type: 'tool:start', name: displayName, id: call.id, arguments: effectiveArgs });
780
786
  const handler = toolHandlers[toolName];
781
787
  if (!handler) {
782
- throw new Error(`Unknown tool: ${call.name}`);
788
+ const available = Object.keys(toolHandlers).join(', ');
789
+ const msg = `Unknown tool: "${toolName}". Available tools: ${available || '(none)'}`;
790
+ const summary = trimInline(msg, 200);
791
+ if (onEvent) {
792
+ onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary });
793
+ }
794
+ return {
795
+ callId: call.id,
796
+ content: JSON.stringify({ error: msg }),
797
+ error: true,
798
+ durationMs: 0,
799
+ summary,
800
+ status: 'error'
801
+ };
783
802
  }
784
803
 
785
804
  const blockedReason = blockedExplorationReason(toolName, effectiveArgs, analysisGuard);
786
805
  if (blockedReason) {
787
806
  analysisGuard.blockedExplorations += 1;
788
807
  const content = clipToolResult({ error: blockedReason }, toolResultMaxChars);
808
+ const summary = trimInline(blockedReason, 120);
789
809
  if (onEvent) {
790
- onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary: trimInline(blockedReason, 120) });
810
+ onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary });
791
811
  }
792
812
  return {
793
813
  callId: call.id,
794
814
  content,
795
- error: true
815
+ error: true,
816
+ durationMs: 0,
817
+ summary,
818
+ status: 'error'
796
819
  };
797
820
  }
798
821
 
@@ -802,8 +825,9 @@ export async function runAgentLoop({
802
825
  } catch (error) {
803
826
  const durationMs = Date.now() - startedAt;
804
827
  const message = error instanceof Error ? error.message : String(error);
828
+ const summary = trimInline(message, 120);
805
829
  if (onEvent) {
806
- onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs, summary: trimInline(message, 120) });
830
+ onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs, summary });
807
831
  }
808
832
  if (isAutoCaptureEnabled(config) && shouldAutoCaptureError(toolName, message)) {
809
833
  await captureToolFailure(toolName, message, effectiveArgs, config).catch(() => {});
@@ -811,15 +835,19 @@ export async function runAgentLoop({
811
835
  return {
812
836
  callId: call.id,
813
837
  content: clipToolResult({ error: message }, toolResultMaxChars),
814
- error: true
838
+ error: true,
839
+ durationMs,
840
+ summary,
841
+ status: 'error'
815
842
  };
816
843
  }
817
844
 
818
845
  const durationMs = Date.now() - startedAt;
846
+ const summary = summarizeToolResult(toolResult);
819
847
  /* 提取文件改动统计 */
820
848
  const fileChange = extractFileChange(toolName, toolResult);
821
849
  if (onEvent) {
822
- onEvent({ type: 'tool:end', name: displayName, id: call.id, arguments: effectiveArgs, durationMs, summary: summarizeToolResult(toolResult), fileChange });
850
+ onEvent({ type: 'tool:end', name: displayName, id: call.id, arguments: effectiveArgs, durationMs, summary, fileChange });
823
851
  }
824
852
 
825
853
  // Auto-capture non-throwing tool failures (e.g. shell non-zero exit)
@@ -857,7 +885,7 @@ export async function runAgentLoop({
857
885
  // P0: Persist to disk if still large
858
886
  formatted = await storeResultIfNeeded(call.id, formatted, toolResult);
859
887
 
860
- return { callId: call.id, content: formatted };
888
+ return { callId: call.id, content: formatted, durationMs, summary, status: 'done' };
861
889
  }
862
890
 
863
891
  // Separate read-only and write calls, preserving order
@@ -884,7 +912,8 @@ export async function runAgentLoop({
884
912
  if (!entry) continue;
885
913
 
886
914
  if (entry.blocked) {
887
- messages.push({ role: 'tool', tool_call_id: call.id, content: entry.content });
915
+ attachToolCallSessionMeta(assistantMessage, call.id, { summary: entry.summary || '', status: entry.status || 'blocked' });
916
+ messages.push({ role: 'tool', tool_call_id: call.id, content: entry.content, tool_summary: entry.summary || '', tool_status: entry.status || 'blocked' });
888
917
  if (onEvent) {
889
918
  onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content, blocked: true });
890
919
  }
@@ -892,14 +921,16 @@ export async function runAgentLoop({
892
921
  }
893
922
 
894
923
  if (entry.error) {
895
- messages.push({ role: 'tool', tool_call_id: call.id, content: entry.content });
924
+ attachToolCallSessionMeta(assistantMessage, call.id, { durationMs: entry.durationMs, summary: entry.summary || '', status: entry.status || 'error' });
925
+ messages.push({ role: 'tool', tool_call_id: call.id, content: entry.content, tool_duration_ms: entry.durationMs, tool_summary: entry.summary || '', tool_status: entry.status || 'error' });
896
926
  if (onEvent) {
897
927
  onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content, error: true });
898
928
  }
899
929
  continue;
900
930
  }
901
931
 
902
- messages.push({ role: 'tool', tool_call_id: call.id, content: entry.content });
932
+ attachToolCallSessionMeta(assistantMessage, call.id, { durationMs: entry.durationMs, summary: entry.summary || '', status: entry.status || 'done' });
933
+ messages.push({ role: 'tool', tool_call_id: call.id, content: entry.content, tool_duration_ms: entry.durationMs, tool_summary: entry.summary || '', tool_status: entry.status || 'done' });
903
934
  if (onEvent) {
904
935
  onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content });
905
936
  }
@@ -934,3 +965,12 @@ function callsToPlanSummary(toolCalls = []) {
934
965
  return `- ${formatToolDisplayName(normalizeToolCallName(call?.name), args)}`;
935
966
  });
936
967
  }
968
+
969
+ function attachToolCallSessionMeta(assistantMessage, callId, meta = {}) {
970
+ if (!assistantMessage || !Array.isArray(assistantMessage.tool_calls)) return;
971
+ const call = assistantMessage.tool_calls.find((tc) => String(tc?.id || '') === String(callId || ''));
972
+ if (!call) return;
973
+ if (Number.isFinite(Number(meta.durationMs))) call.durationMs = Number(meta.durationMs);
974
+ if (typeof meta.summary === 'string' && meta.summary.trim()) call.summary = meta.summary.trim();
975
+ if (typeof meta.status === 'string' && meta.status.trim()) call.status = meta.status.trim();
976
+ }