codemini-cli 0.4.7 → 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.7.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.7.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.7.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.7.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.7.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.7",
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,7 +776,9 @@ 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
 
@@ -781,13 +787,17 @@ export async function runAgentLoop({
781
787
  if (!handler) {
782
788
  const available = Object.keys(toolHandlers).join(', ');
783
789
  const msg = `Unknown tool: "${toolName}". Available tools: ${available || '(none)'}`;
790
+ const summary = trimInline(msg, 200);
784
791
  if (onEvent) {
785
- onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary: trimInline(msg, 200) });
792
+ onEvent({ type: 'tool:error', name: displayName, id: call.id, arguments: effectiveArgs, durationMs: 0, summary });
786
793
  }
787
794
  return {
788
795
  callId: call.id,
789
796
  content: JSON.stringify({ error: msg }),
790
- error: true
797
+ error: true,
798
+ durationMs: 0,
799
+ summary,
800
+ status: 'error'
791
801
  };
792
802
  }
793
803
 
@@ -795,13 +805,17 @@ export async function runAgentLoop({
795
805
  if (blockedReason) {
796
806
  analysisGuard.blockedExplorations += 1;
797
807
  const content = clipToolResult({ error: blockedReason }, toolResultMaxChars);
808
+ const summary = trimInline(blockedReason, 120);
798
809
  if (onEvent) {
799
- 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 });
800
811
  }
801
812
  return {
802
813
  callId: call.id,
803
814
  content,
804
- error: true
815
+ error: true,
816
+ durationMs: 0,
817
+ summary,
818
+ status: 'error'
805
819
  };
806
820
  }
807
821
 
@@ -811,8 +825,9 @@ export async function runAgentLoop({
811
825
  } catch (error) {
812
826
  const durationMs = Date.now() - startedAt;
813
827
  const message = error instanceof Error ? error.message : String(error);
828
+ const summary = trimInline(message, 120);
814
829
  if (onEvent) {
815
- 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 });
816
831
  }
817
832
  if (isAutoCaptureEnabled(config) && shouldAutoCaptureError(toolName, message)) {
818
833
  await captureToolFailure(toolName, message, effectiveArgs, config).catch(() => {});
@@ -820,15 +835,19 @@ export async function runAgentLoop({
820
835
  return {
821
836
  callId: call.id,
822
837
  content: clipToolResult({ error: message }, toolResultMaxChars),
823
- error: true
838
+ error: true,
839
+ durationMs,
840
+ summary,
841
+ status: 'error'
824
842
  };
825
843
  }
826
844
 
827
845
  const durationMs = Date.now() - startedAt;
846
+ const summary = summarizeToolResult(toolResult);
828
847
  /* 提取文件改动统计 */
829
848
  const fileChange = extractFileChange(toolName, toolResult);
830
849
  if (onEvent) {
831
- 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 });
832
851
  }
833
852
 
834
853
  // Auto-capture non-throwing tool failures (e.g. shell non-zero exit)
@@ -866,7 +885,7 @@ export async function runAgentLoop({
866
885
  // P0: Persist to disk if still large
867
886
  formatted = await storeResultIfNeeded(call.id, formatted, toolResult);
868
887
 
869
- return { callId: call.id, content: formatted };
888
+ return { callId: call.id, content: formatted, durationMs, summary, status: 'done' };
870
889
  }
871
890
 
872
891
  // Separate read-only and write calls, preserving order
@@ -893,7 +912,8 @@ export async function runAgentLoop({
893
912
  if (!entry) continue;
894
913
 
895
914
  if (entry.blocked) {
896
- 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' });
897
917
  if (onEvent) {
898
918
  onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content, blocked: true });
899
919
  }
@@ -901,14 +921,16 @@ export async function runAgentLoop({
901
921
  }
902
922
 
903
923
  if (entry.error) {
904
- 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' });
905
926
  if (onEvent) {
906
927
  onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content, error: true });
907
928
  }
908
929
  continue;
909
930
  }
910
931
 
911
- 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' });
912
934
  if (onEvent) {
913
935
  onEvent({ type: 'tool:result', name: displayName, id: call.id, arguments: args, content: entry.content });
914
936
  }
@@ -943,3 +965,12 @@ function callsToPlanSummary(toolCalls = []) {
943
965
  return `- ${formatToolDisplayName(normalizeToolCallName(call?.name), args)}`;
944
966
  });
945
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
+ }