codemini-cli 0.5.10 → 0.5.12
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/OPERATIONS.md +242 -242
- package/README.md +588 -588
- package/codemini-web/dist/assets/{highlighted-body-OFNGDK62-7HL7yft8.js → highlighted-body-OFNGDK62-B-G99D0A.js} +1 -1
- package/codemini-web/dist/assets/{index-BK75hMb2.js → index-DIGUEzan.js} +108 -108
- package/codemini-web/dist/assets/index-Dkq1DdDX.css +2 -0
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-va2Kl89u.js +1 -0
- package/codemini-web/dist/index.html +35 -23
- package/codemini-web/lib/approval-manager.js +32 -32
- package/codemini-web/lib/runtime-bridge.js +17 -11
- package/codemini-web/server.js +534 -205
- package/deployment.md +212 -212
- package/package.json +2 -2
- package/skills/brainstorm/SKILL.md +77 -77
- package/skills/codemini.skills.json +40 -40
- package/skills/grill-me/SKILL.md +30 -30
- package/skills/superpowers-lite/SKILL.md +82 -82
- package/src/cli.js +74 -74
- package/src/commands/chat.js +210 -210
- package/src/commands/run.js +313 -313
- package/src/commands/skill.js +438 -304
- package/src/commands/web.js +57 -57
- package/src/core/agent-loop.js +980 -980
- package/src/core/ast.js +309 -307
- package/src/core/chat-runtime.js +6261 -6253
- package/src/core/command-evaluator.js +72 -72
- package/src/core/command-loader.js +311 -311
- package/src/core/command-policy.js +301 -301
- package/src/core/command-risk.js +156 -156
- package/src/core/config-store.js +286 -285
- package/src/core/constants.js +18 -1
- package/src/core/context-compact.js +365 -365
- package/src/core/default-system-prompt.js +114 -107
- package/src/core/dream-audit.js +105 -105
- package/src/core/dream-consolidate.js +229 -229
- package/src/core/dream-evaluator.js +185 -185
- package/src/core/fff-adapter.js +383 -383
- package/src/core/memory-store.js +543 -543
- package/src/core/project-index.js +737 -548
- package/src/core/project-instructions.js +98 -98
- package/src/core/provider/anthropic.js +514 -514
- package/src/core/provider/openai-compatible.js +501 -501
- package/src/core/reflect-skill.js +178 -178
- package/src/core/reply-language.js +40 -40
- package/src/core/session-store.js +474 -474
- package/src/core/shell-profile.js +237 -237
- package/src/core/shell.js +323 -323
- package/src/core/soul.js +69 -69
- package/src/core/system-prompt-composer.js +52 -52
- package/src/core/tool-args.js +199 -154
- package/src/core/tool-output.js +184 -184
- package/src/core/tool-result-store.js +206 -206
- package/src/core/tools.js +3024 -2893
- package/src/core/version.js +11 -11
- package/src/tui/chat-app.js +5173 -5171
- package/src/tui/tool-activity/presenters/misc.js +30 -30
- package/src/tui/tool-activity/presenters/system.js +20 -20
- package/templates/project-requirements/report-shell.html +582 -582
- package/codemini-web/dist/assets/index-BSdIdn3L.css +0 -2
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-Dg9qh8mg.js +0 -1
package/src/commands/chat.js
CHANGED
|
@@ -1,210 +1,210 @@
|
|
|
1
|
-
import readline from 'node:readline/promises';
|
|
2
|
-
import { stdin as input, stdout as output } from 'node:process';
|
|
3
|
-
import { loadConfig } from '../core/config-store.js';
|
|
4
|
-
import { createChatRuntime } from '../core/chat-runtime.js';
|
|
5
|
-
import { buildDefaultSystemPrompt } from '../core/default-system-prompt.js';
|
|
6
|
-
import { resolveSession } from '../core/session-store.js';
|
|
7
|
-
import { VERSION } from '../core/version.js';
|
|
8
|
-
|
|
9
|
-
function parseChatArgs(args) {
|
|
10
|
-
const parsed = {
|
|
11
|
-
prompt: '',
|
|
12
|
-
sessionId: undefined,
|
|
13
|
-
model: undefined,
|
|
14
|
-
fast: false,
|
|
15
|
-
system: undefined,
|
|
16
|
-
plain: false
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
20
|
-
const arg = args[i];
|
|
21
|
-
if (arg === '--session') {
|
|
22
|
-
parsed.sessionId = args[i + 1];
|
|
23
|
-
i += 1;
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (arg === '--model') {
|
|
27
|
-
parsed.model = args[i + 1];
|
|
28
|
-
i += 1;
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
if (arg === '--fast' || arg === '--lite') {
|
|
32
|
-
parsed.fast = true;
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
if (arg === '--system') {
|
|
36
|
-
parsed.system = args[i + 1];
|
|
37
|
-
i += 1;
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (arg === '--plain') {
|
|
41
|
-
parsed.plain = true;
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
parsed.prompt += `${parsed.prompt ? ' ' : ''}${arg}`;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return parsed;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export async function submitAndPrint(runtime, line, { output: out = process.stdout, showSystemTools = false } = {}) {
|
|
51
|
-
let streamed = false;
|
|
52
|
-
let atLineStart = true;
|
|
53
|
-
const write = (text) => {
|
|
54
|
-
const value = String(text || '');
|
|
55
|
-
if (!value) return;
|
|
56
|
-
out.write(value);
|
|
57
|
-
atLineStart = value.endsWith('\n');
|
|
58
|
-
};
|
|
59
|
-
const writeActivity = (event, label) => {
|
|
60
|
-
const name = String(event?.name || '').trim();
|
|
61
|
-
if (!name) return;
|
|
62
|
-
const summary = String(event?.summary || '').trim();
|
|
63
|
-
if (!atLineStart) write('\n');
|
|
64
|
-
write(`[${label}] ${name}${summary ? ` - ${summary}` : ''}\n`);
|
|
65
|
-
};
|
|
66
|
-
const result = await runtime.submit(line, (event) => {
|
|
67
|
-
if (event?.type === 'assistant:delta' && event.text) {
|
|
68
|
-
streamed = true;
|
|
69
|
-
write(event.text);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (event?.type === 'tool:start') {
|
|
73
|
-
streamed = true;
|
|
74
|
-
writeActivity(event, 'tool:start');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
if (event?.type === 'tool:end') {
|
|
78
|
-
streamed = true;
|
|
79
|
-
writeActivity(event, 'tool:end');
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (event?.type === 'tool:blocked') {
|
|
83
|
-
streamed = true;
|
|
84
|
-
writeActivity(event, 'tool:blocked');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (event?.type === 'tool:error') {
|
|
88
|
-
streamed = true;
|
|
89
|
-
writeActivity(event, 'tool:error');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (!showSystemTools && String(event?.type || '').startsWith('system_tool:')) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (event?.type === 'system_tool:start') {
|
|
96
|
-
streamed = true;
|
|
97
|
-
writeActivity(event, 'system:start');
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
if (event?.type === 'system_tool:end') {
|
|
101
|
-
streamed = true;
|
|
102
|
-
writeActivity(event, 'system:end');
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
if (event?.type === 'system_tool:error') {
|
|
106
|
-
streamed = true;
|
|
107
|
-
writeActivity(event, 'system:error');
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
if (result.type === 'exit' || result.type === 'noop') return result;
|
|
111
|
-
if (streamed) {
|
|
112
|
-
if (!atLineStart) write('\n');
|
|
113
|
-
return result;
|
|
114
|
-
}
|
|
115
|
-
if (result.text) write(`${result.text}\n`);
|
|
116
|
-
return result;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function runPlainLoop(runtime) {
|
|
120
|
-
console.log('Codemini CLI plain mode. Use /help and /exit.');
|
|
121
|
-
const rl = readline.createInterface({ input, output });
|
|
122
|
-
try {
|
|
123
|
-
while (true) {
|
|
124
|
-
let line;
|
|
125
|
-
try {
|
|
126
|
-
line = await rl.question('codemini> ');
|
|
127
|
-
} catch {
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
const result = await submitAndPrint(runtime, line, { output });
|
|
131
|
-
if (result.type === 'exit') break;
|
|
132
|
-
}
|
|
133
|
-
} finally {
|
|
134
|
-
rl.close();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export async function handleChat(args) {
|
|
139
|
-
const parsed = parseChatArgs(args);
|
|
140
|
-
const config = await loadConfig();
|
|
141
|
-
const session = await resolveSession(parsed.sessionId);
|
|
142
|
-
const selectedModel = parsed.fast ? (config.model?.fast_name || config.model?.name) : parsed.model;
|
|
143
|
-
const systemPrompt =
|
|
144
|
-
parsed.system ||
|
|
145
|
-
buildDefaultSystemPrompt(config);
|
|
146
|
-
|
|
147
|
-
const runtime = await createChatRuntime({
|
|
148
|
-
session,
|
|
149
|
-
config,
|
|
150
|
-
model: selectedModel,
|
|
151
|
-
systemPrompt
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
if (parsed.prompt) {
|
|
156
|
-
await submitAndPrint(runtime, parsed.prompt, { output: process.stdout });
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (parsed.plain || !process.stdout.isTTY) {
|
|
161
|
-
await runPlainLoop(runtime);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const React = (await import('react')).default;
|
|
166
|
-
const { render } = await import('ink');
|
|
167
|
-
const { ChatApp } = await import('../tui/chat-app.js');
|
|
168
|
-
|
|
169
|
-
const instance = render(
|
|
170
|
-
React.createElement(ChatApp, {
|
|
171
|
-
runtime,
|
|
172
|
-
sessionId: session.id,
|
|
173
|
-
model: selectedModel || config.model.name,
|
|
174
|
-
sdkProvider: config.sdk?.provider || 'openai-compatible',
|
|
175
|
-
language: config.ui?.language || 'zh',
|
|
176
|
-
shellName: config.shell?.default || 'powershell',
|
|
177
|
-
safeMode: config.policy?.safe_mode !== false,
|
|
178
|
-
version: VERSION
|
|
179
|
-
})
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
// Patch Ink's renderInteractiveFrame to never use clearTerminal.
|
|
183
|
-
// Ink calls clearTerminal (ESC[2J + ESC[H]) when the output frame exceeds
|
|
184
|
-
// the terminal viewport height, which resets the scroll position to the top
|
|
185
|
-
// and prevents the user from scrolling freely during streaming.
|
|
186
|
-
// By always using incremental logUpdate updates instead, old content scrolls
|
|
187
|
-
// into the terminal's scrollback naturally and the user can scroll freely.
|
|
188
|
-
const origRenderFrame = instance.renderInteractiveFrame;
|
|
189
|
-
instance.renderInteractiveFrame = function (output, outputHeight, staticOutput) {
|
|
190
|
-
const hasStaticOutput = staticOutput !== '';
|
|
191
|
-
const outputToRender = output + '\n';
|
|
192
|
-
|
|
193
|
-
if (hasStaticOutput) {
|
|
194
|
-
this.fullStaticOutput += staticOutput;
|
|
195
|
-
this.log.clear();
|
|
196
|
-
this.options.stdout.write(staticOutput);
|
|
197
|
-
this.log(outputToRender);
|
|
198
|
-
} else if (output !== this.lastOutput || this.log.isCursorDirty()) {
|
|
199
|
-
this.throttledLog(outputToRender);
|
|
200
|
-
}
|
|
201
|
-
this.lastOutput = output;
|
|
202
|
-
this.lastOutputToRender = outputToRender;
|
|
203
|
-
this.lastOutputHeight = outputHeight;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
await instance.waitUntilExit();
|
|
207
|
-
} finally {
|
|
208
|
-
await runtime.dispose?.();
|
|
209
|
-
}
|
|
210
|
-
}
|
|
1
|
+
import readline from 'node:readline/promises';
|
|
2
|
+
import { stdin as input, stdout as output } from 'node:process';
|
|
3
|
+
import { loadConfig } from '../core/config-store.js';
|
|
4
|
+
import { createChatRuntime } from '../core/chat-runtime.js';
|
|
5
|
+
import { buildDefaultSystemPrompt } from '../core/default-system-prompt.js';
|
|
6
|
+
import { resolveSession } from '../core/session-store.js';
|
|
7
|
+
import { VERSION } from '../core/version.js';
|
|
8
|
+
|
|
9
|
+
function parseChatArgs(args) {
|
|
10
|
+
const parsed = {
|
|
11
|
+
prompt: '',
|
|
12
|
+
sessionId: undefined,
|
|
13
|
+
model: undefined,
|
|
14
|
+
fast: false,
|
|
15
|
+
system: undefined,
|
|
16
|
+
plain: false
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
20
|
+
const arg = args[i];
|
|
21
|
+
if (arg === '--session') {
|
|
22
|
+
parsed.sessionId = args[i + 1];
|
|
23
|
+
i += 1;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === '--model') {
|
|
27
|
+
parsed.model = args[i + 1];
|
|
28
|
+
i += 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (arg === '--fast' || arg === '--lite') {
|
|
32
|
+
parsed.fast = true;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (arg === '--system') {
|
|
36
|
+
parsed.system = args[i + 1];
|
|
37
|
+
i += 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (arg === '--plain') {
|
|
41
|
+
parsed.plain = true;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
parsed.prompt += `${parsed.prompt ? ' ' : ''}${arg}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return parsed;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function submitAndPrint(runtime, line, { output: out = process.stdout, showSystemTools = false } = {}) {
|
|
51
|
+
let streamed = false;
|
|
52
|
+
let atLineStart = true;
|
|
53
|
+
const write = (text) => {
|
|
54
|
+
const value = String(text || '');
|
|
55
|
+
if (!value) return;
|
|
56
|
+
out.write(value);
|
|
57
|
+
atLineStart = value.endsWith('\n');
|
|
58
|
+
};
|
|
59
|
+
const writeActivity = (event, label) => {
|
|
60
|
+
const name = String(event?.name || '').trim();
|
|
61
|
+
if (!name) return;
|
|
62
|
+
const summary = String(event?.summary || '').trim();
|
|
63
|
+
if (!atLineStart) write('\n');
|
|
64
|
+
write(`[${label}] ${name}${summary ? ` - ${summary}` : ''}\n`);
|
|
65
|
+
};
|
|
66
|
+
const result = await runtime.submit(line, (event) => {
|
|
67
|
+
if (event?.type === 'assistant:delta' && event.text) {
|
|
68
|
+
streamed = true;
|
|
69
|
+
write(event.text);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (event?.type === 'tool:start') {
|
|
73
|
+
streamed = true;
|
|
74
|
+
writeActivity(event, 'tool:start');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (event?.type === 'tool:end') {
|
|
78
|
+
streamed = true;
|
|
79
|
+
writeActivity(event, 'tool:end');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (event?.type === 'tool:blocked') {
|
|
83
|
+
streamed = true;
|
|
84
|
+
writeActivity(event, 'tool:blocked');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (event?.type === 'tool:error') {
|
|
88
|
+
streamed = true;
|
|
89
|
+
writeActivity(event, 'tool:error');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (!showSystemTools && String(event?.type || '').startsWith('system_tool:')) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (event?.type === 'system_tool:start') {
|
|
96
|
+
streamed = true;
|
|
97
|
+
writeActivity(event, 'system:start');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (event?.type === 'system_tool:end') {
|
|
101
|
+
streamed = true;
|
|
102
|
+
writeActivity(event, 'system:end');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (event?.type === 'system_tool:error') {
|
|
106
|
+
streamed = true;
|
|
107
|
+
writeActivity(event, 'system:error');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
if (result.type === 'exit' || result.type === 'noop') return result;
|
|
111
|
+
if (streamed) {
|
|
112
|
+
if (!atLineStart) write('\n');
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
if (result.text) write(`${result.text}\n`);
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function runPlainLoop(runtime) {
|
|
120
|
+
console.log('Codemini CLI plain mode. Use /help and /exit.');
|
|
121
|
+
const rl = readline.createInterface({ input, output });
|
|
122
|
+
try {
|
|
123
|
+
while (true) {
|
|
124
|
+
let line;
|
|
125
|
+
try {
|
|
126
|
+
line = await rl.question('codemini> ');
|
|
127
|
+
} catch {
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
const result = await submitAndPrint(runtime, line, { output });
|
|
131
|
+
if (result.type === 'exit') break;
|
|
132
|
+
}
|
|
133
|
+
} finally {
|
|
134
|
+
rl.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function handleChat(args) {
|
|
139
|
+
const parsed = parseChatArgs(args);
|
|
140
|
+
const config = await loadConfig();
|
|
141
|
+
const session = await resolveSession(parsed.sessionId);
|
|
142
|
+
const selectedModel = parsed.fast ? (config.model?.fast_name || config.model?.name) : parsed.model;
|
|
143
|
+
const systemPrompt =
|
|
144
|
+
parsed.system ||
|
|
145
|
+
buildDefaultSystemPrompt(config);
|
|
146
|
+
|
|
147
|
+
const runtime = await createChatRuntime({
|
|
148
|
+
session,
|
|
149
|
+
config,
|
|
150
|
+
model: selectedModel,
|
|
151
|
+
systemPrompt
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
if (parsed.prompt) {
|
|
156
|
+
await submitAndPrint(runtime, parsed.prompt, { output: process.stdout });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (parsed.plain || !process.stdout.isTTY) {
|
|
161
|
+
await runPlainLoop(runtime);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const React = (await import('react')).default;
|
|
166
|
+
const { render } = await import('ink');
|
|
167
|
+
const { ChatApp } = await import('../tui/chat-app.js');
|
|
168
|
+
|
|
169
|
+
const instance = render(
|
|
170
|
+
React.createElement(ChatApp, {
|
|
171
|
+
runtime,
|
|
172
|
+
sessionId: session.id,
|
|
173
|
+
model: selectedModel || config.model.name,
|
|
174
|
+
sdkProvider: config.sdk?.provider || 'openai-compatible',
|
|
175
|
+
language: config.ui?.language || 'zh',
|
|
176
|
+
shellName: config.shell?.default || 'powershell',
|
|
177
|
+
safeMode: config.policy?.safe_mode !== false,
|
|
178
|
+
version: VERSION
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// Patch Ink's renderInteractiveFrame to never use clearTerminal.
|
|
183
|
+
// Ink calls clearTerminal (ESC[2J + ESC[H]) when the output frame exceeds
|
|
184
|
+
// the terminal viewport height, which resets the scroll position to the top
|
|
185
|
+
// and prevents the user from scrolling freely during streaming.
|
|
186
|
+
// By always using incremental logUpdate updates instead, old content scrolls
|
|
187
|
+
// into the terminal's scrollback naturally and the user can scroll freely.
|
|
188
|
+
const origRenderFrame = instance.renderInteractiveFrame;
|
|
189
|
+
instance.renderInteractiveFrame = function (output, outputHeight, staticOutput) {
|
|
190
|
+
const hasStaticOutput = staticOutput !== '';
|
|
191
|
+
const outputToRender = output + '\n';
|
|
192
|
+
|
|
193
|
+
if (hasStaticOutput) {
|
|
194
|
+
this.fullStaticOutput += staticOutput;
|
|
195
|
+
this.log.clear();
|
|
196
|
+
this.options.stdout.write(staticOutput);
|
|
197
|
+
this.log(outputToRender);
|
|
198
|
+
} else if (output !== this.lastOutput || this.log.isCursorDirty()) {
|
|
199
|
+
this.throttledLog(outputToRender);
|
|
200
|
+
}
|
|
201
|
+
this.lastOutput = output;
|
|
202
|
+
this.lastOutputToRender = outputToRender;
|
|
203
|
+
this.lastOutputHeight = outputHeight;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
await instance.waitUntilExit();
|
|
207
|
+
} finally {
|
|
208
|
+
await runtime.dispose?.();
|
|
209
|
+
}
|
|
210
|
+
}
|