codemini-cli 0.1.13 → 0.1.15
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 +17 -2
- package/README.md +80 -0
- package/package.json +1 -1
- package/skills/{brainstorming-lite → brainstorm}/SKILL.md +36 -4
- package/skills/superpowers-lite/SKILL.md +12 -2
- package/src/cli.js +1 -1
- package/src/core/agent-loop.js +29 -0
- package/src/core/chat-runtime.js +146 -21
- package/src/core/config-store.js +10 -0
- package/src/core/shell-profile.js +1 -1
- package/src/core/shell.js +135 -9
- package/src/core/tools.js +445 -9
- package/src/tui/chat-app.js +206 -21
- package/skills/executing-plan-lite/SKILL.md +0 -41
package/src/tui/chat-app.js
CHANGED
|
@@ -316,6 +316,11 @@ function getActivityDisplayParts(activity) {
|
|
|
316
316
|
read_file: 'Read',
|
|
317
317
|
write_file: 'Write',
|
|
318
318
|
run_command: 'Command',
|
|
319
|
+
start_service: 'Service',
|
|
320
|
+
list_services: 'Service',
|
|
321
|
+
get_service_status: 'Service',
|
|
322
|
+
get_service_logs: 'Service',
|
|
323
|
+
stop_service: 'Service',
|
|
319
324
|
list_files: 'Glob',
|
|
320
325
|
create_task: 'Task',
|
|
321
326
|
update_task: 'Task'
|
|
@@ -357,6 +362,13 @@ function describeToolActivity(name, copy, { done = false, blocked = false } = {}
|
|
|
357
362
|
? `${copy.toolActivity.doneCommand}: ${safeTarget || 'run_command'}`
|
|
358
363
|
: `${copy.toolActivity.doingCommand}: ${safeTarget || 'run_command'}`;
|
|
359
364
|
}
|
|
365
|
+
if (base === 'start_service' || base === 'list_services' || base === 'get_service_status' || base === 'get_service_logs' || base === 'stop_service') {
|
|
366
|
+
return blocked
|
|
367
|
+
? `${copy.toolActivity.blocked}: ${safeTarget || base}`
|
|
368
|
+
: done
|
|
369
|
+
? `${copy.toolActivity.doneGeneric}: ${safeTarget || base}`
|
|
370
|
+
: `${copy.toolActivity.doingGeneric}: ${safeTarget || base}`;
|
|
371
|
+
}
|
|
360
372
|
if (base === 'create_task') {
|
|
361
373
|
return blocked ? `${copy.toolActivity.blocked}: create_task` : done ? copy.toolActivity.doneCreateTask : copy.toolActivity.doingCreateTask;
|
|
362
374
|
}
|
|
@@ -472,9 +484,13 @@ function PlanStrip({ planState, copy }) {
|
|
|
472
484
|
...planState.steps.slice(-4).map((step, idx) =>
|
|
473
485
|
h(
|
|
474
486
|
Box,
|
|
475
|
-
{ key: `plan-step-${idx}
|
|
487
|
+
{ key: `plan-step-${idx}`, marginTop: idx === 0 ? 0 : 1 },
|
|
476
488
|
h(Text, { color: step.status === 'active' ? 'cyanBright' : step.status === 'failed' ? 'redBright' : 'gray' }, `${step.status === 'active' ? '>' : step.status === 'failed' ? 'x' : '·'} `),
|
|
477
|
-
h(Text, { color: step.status === 'active' ? '
|
|
489
|
+
h(Text, { color: step.status === 'active' ? 'yellowBright' : step.status === 'failed' ? 'redBright' : 'gray' }, `${step.index}/${step.total}`),
|
|
490
|
+
h(Text, { color: 'gray' }, ' '),
|
|
491
|
+
h(Text, { color: step.status === 'active' ? 'magentaBright' : step.status === 'failed' ? 'redBright' : 'gray' }, String(step.role || 'agent').toUpperCase()),
|
|
492
|
+
h(Text, { color: 'gray' }, ' '),
|
|
493
|
+
h(Text, { color: step.status === 'active' ? 'white' : step.status === 'failed' ? 'redBright' : 'gray' }, step.title)
|
|
478
494
|
)
|
|
479
495
|
)
|
|
480
496
|
)
|
|
@@ -583,6 +599,39 @@ export function parseAutoPlanSummaryMessage(text) {
|
|
|
583
599
|
return parsed;
|
|
584
600
|
}
|
|
585
601
|
|
|
602
|
+
export function parsePlanProgressLine(text) {
|
|
603
|
+
const raw = String(text || '').trim();
|
|
604
|
+
const match = raw.match(/^\[plan\]\s+Step\s+(\d+)\/(\d+)\s+->\s+([^:]+):\s+(.+)$/i);
|
|
605
|
+
if (!match) return null;
|
|
606
|
+
return {
|
|
607
|
+
current: Number(match[1]),
|
|
608
|
+
total: Number(match[2]),
|
|
609
|
+
role: String(match[3] || '').trim(),
|
|
610
|
+
title: String(match[4] || '').trim()
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export function injectPlanStateMessage(messages, planState, activeUserMessageId, activeAssistantId) {
|
|
615
|
+
const source = Array.isArray(messages) ? messages : [];
|
|
616
|
+
if (!planState || !planState.total) return source;
|
|
617
|
+
const synthetic = {
|
|
618
|
+
id: `plan-state-${planState.current}-${planState.total}-${planState.role || 'agent'}`,
|
|
619
|
+
label: 'system',
|
|
620
|
+
planStrip: true,
|
|
621
|
+
planState
|
|
622
|
+
};
|
|
623
|
+
const withNoPlanStrip = source.filter((message) => !message?.planStrip);
|
|
624
|
+
const userIdx = withNoPlanStrip.findIndex((message) => message.id === activeUserMessageId);
|
|
625
|
+
if (userIdx !== -1) {
|
|
626
|
+
return [...withNoPlanStrip.slice(0, userIdx + 1), synthetic, ...withNoPlanStrip.slice(userIdx + 1)];
|
|
627
|
+
}
|
|
628
|
+
const assistantIdx = withNoPlanStrip.findIndex((message) => message.id === activeAssistantId);
|
|
629
|
+
if (assistantIdx !== -1) {
|
|
630
|
+
return [...withNoPlanStrip.slice(0, assistantIdx), synthetic, ...withNoPlanStrip.slice(assistantIdx)];
|
|
631
|
+
}
|
|
632
|
+
return [...withNoPlanStrip, synthetic];
|
|
633
|
+
}
|
|
634
|
+
|
|
586
635
|
function PlanSummaryBubble({ msg, copy }) {
|
|
587
636
|
const theme = roleStyle(msg.label);
|
|
588
637
|
const summary = msg.planSummary || parseAutoPlanSummaryMessage(msg.text);
|
|
@@ -760,6 +809,114 @@ function pushWrappedRow(rows, baseRow, contentWidth) {
|
|
|
760
809
|
});
|
|
761
810
|
}
|
|
762
811
|
|
|
812
|
+
function isActivityRow(row) {
|
|
813
|
+
return row?.kind === 'activity' || row?.kind === 'activity-summary';
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
function isBlankTextRow(row) {
|
|
817
|
+
return row?.kind === 'text' && String(row?.text || '').trim() === '';
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
export function normalizeActivitySpacingRows(inputRows) {
|
|
821
|
+
const rows = Array.isArray(inputRows) ? inputRows : [];
|
|
822
|
+
const normalized = [];
|
|
823
|
+
|
|
824
|
+
for (let index = 0; index < rows.length; index += 1) {
|
|
825
|
+
const row = rows[index];
|
|
826
|
+
const prev = normalized.at(-1);
|
|
827
|
+
const next = rows[index + 1];
|
|
828
|
+
|
|
829
|
+
if (isBlankTextRow(row)) {
|
|
830
|
+
let lookahead = index + 1;
|
|
831
|
+
while (lookahead < rows.length && isBlankTextRow(rows[lookahead])) {
|
|
832
|
+
lookahead += 1;
|
|
833
|
+
}
|
|
834
|
+
if (isActivityRow(rows[lookahead])) {
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (isBlankTextRow(row) && isActivityRow(next)) {
|
|
840
|
+
continue;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
normalized.push(row);
|
|
844
|
+
|
|
845
|
+
if (isActivityRow(row) && !isActivityRow(next) && next) {
|
|
846
|
+
const last = normalized.at(-1);
|
|
847
|
+
if (!isBlankTextRow(last) && !(next.kind === 'status')) {
|
|
848
|
+
normalized.push({
|
|
849
|
+
kind: 'text',
|
|
850
|
+
text: ' ',
|
|
851
|
+
color: 'white'
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (isBlankTextRow(row) && isBlankTextRow(prev)) {
|
|
857
|
+
normalized.pop();
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
return normalized;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
function isReadActivityName(name) {
|
|
865
|
+
const parsed = parseToolDisplayName(name);
|
|
866
|
+
return parsed.base === 'read_file' || parsed.base === 'Read';
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
function isIgnorableSegmentAfterRead(item, activityType, activityName) {
|
|
870
|
+
if (!item) return true;
|
|
871
|
+
if (item.type === 'text') {
|
|
872
|
+
return String(item.text || '').trim() === '';
|
|
873
|
+
}
|
|
874
|
+
return (item.type || 'tool') === activityType && item.name === activityName;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
export function findActivityUpdateIndex(items, toolEvent) {
|
|
878
|
+
const source = Array.isArray(items) ? items : [];
|
|
879
|
+
const activityType = toolEvent?.type || 'tool';
|
|
880
|
+
const byId = toolEvent?.id
|
|
881
|
+
? source.findIndex((item) => item.type === activityType && item.id && item.id === toolEvent.id)
|
|
882
|
+
: -1;
|
|
883
|
+
if (byId !== -1) return byId;
|
|
884
|
+
|
|
885
|
+
const byNameRunning = source.findIndex(
|
|
886
|
+
(item) => (item.type || 'tool') === activityType && item.name === toolEvent?.name && item.status !== 'done'
|
|
887
|
+
);
|
|
888
|
+
if (byNameRunning !== -1) return byNameRunning;
|
|
889
|
+
|
|
890
|
+
if (isReadActivityName(toolEvent?.name)) {
|
|
891
|
+
for (let index = source.length - 1; index >= 0; index -= 1) {
|
|
892
|
+
const item = source[index];
|
|
893
|
+
if ((item?.type || 'tool') !== activityType || item?.name !== toolEvent?.name) continue;
|
|
894
|
+
const trailing = source.slice(index + 1);
|
|
895
|
+
if (trailing.every((entry) => isIgnorableSegmentAfterRead(entry, activityType, toolEvent?.name))) {
|
|
896
|
+
return index;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
return -1;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
export function mergeActivitySummary(previousSummary, nextSummary, activityName) {
|
|
905
|
+
const prev = String(previousSummary || '').trim();
|
|
906
|
+
const next = String(nextSummary || '').trim();
|
|
907
|
+
if (!next) return prev;
|
|
908
|
+
if (!prev) return next;
|
|
909
|
+
if (!isReadActivityName(activityName) || prev === next) return next;
|
|
910
|
+
|
|
911
|
+
const lines = [];
|
|
912
|
+
for (const line of `${prev}\n${next}`.split('\n')) {
|
|
913
|
+
const trimmed = String(line || '').trim();
|
|
914
|
+
if (!trimmed) continue;
|
|
915
|
+
if (!lines.includes(trimmed)) lines.push(trimmed);
|
|
916
|
+
}
|
|
917
|
+
return lines.join('\n');
|
|
918
|
+
}
|
|
919
|
+
|
|
763
920
|
function buildMessageRows(msg, showToolDetails, contentWidth = 72) {
|
|
764
921
|
const rows = [];
|
|
765
922
|
const pushTextRows = (text) => {
|
|
@@ -767,6 +924,17 @@ function buildMessageRows(msg, showToolDetails, contentWidth = 72) {
|
|
|
767
924
|
let codeFence = false;
|
|
768
925
|
for (const line of lines) {
|
|
769
926
|
const trimmed = line.trim();
|
|
927
|
+
const planProgress = parsePlanProgressLine(trimmed);
|
|
928
|
+
if (planProgress) {
|
|
929
|
+
rows.push({
|
|
930
|
+
kind: 'plan-progress',
|
|
931
|
+
current: planProgress.current,
|
|
932
|
+
total: planProgress.total,
|
|
933
|
+
role: planProgress.role,
|
|
934
|
+
title: trimText(planProgress.title, Math.max(12, contentWidth - 18))
|
|
935
|
+
});
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
770
938
|
if (trimmed.startsWith('```')) {
|
|
771
939
|
codeFence = !codeFence;
|
|
772
940
|
continue;
|
|
@@ -843,7 +1011,7 @@ function buildMessageRows(msg, showToolDetails, contentWidth = 72) {
|
|
|
843
1011
|
);
|
|
844
1012
|
}
|
|
845
1013
|
|
|
846
|
-
return rows;
|
|
1014
|
+
return normalizeActivitySpacingRows(rows);
|
|
847
1015
|
}
|
|
848
1016
|
|
|
849
1017
|
|
|
@@ -945,6 +1113,13 @@ export function moveSuggestionSelection(currentIndex, itemCount, direction, page
|
|
|
945
1113
|
}
|
|
946
1114
|
|
|
947
1115
|
function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, contentWidth = 72, copy }) {
|
|
1116
|
+
if (msg?.planStrip) {
|
|
1117
|
+
return h(
|
|
1118
|
+
Box,
|
|
1119
|
+
{ marginBottom: 1 },
|
|
1120
|
+
h(PlanStrip, { planState: msg.planState, copy })
|
|
1121
|
+
);
|
|
1122
|
+
}
|
|
948
1123
|
if (msg?.planSummary || parseAutoPlanSummaryMessage(msg?.text)) {
|
|
949
1124
|
return h(PlanSummaryBubble, { msg, copy });
|
|
950
1125
|
}
|
|
@@ -991,6 +1166,18 @@ function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, con
|
|
|
991
1166
|
h(Text, { color: 'gray' }, `└ ${row.text}`)
|
|
992
1167
|
);
|
|
993
1168
|
}
|
|
1169
|
+
if (row.kind === 'plan-progress') {
|
|
1170
|
+
return h(
|
|
1171
|
+
Box,
|
|
1172
|
+
{ key: `row-plan-progress-${msg.id}-${idx}`, marginTop: 1, marginBottom: 1 },
|
|
1173
|
+
h(Text, { color: 'cyanBright' }, '[plan] '),
|
|
1174
|
+
h(Text, { color: 'yellowBright' }, `Step ${row.current}/${row.total}`),
|
|
1175
|
+
h(Text, { color: 'gray' }, ' -> '),
|
|
1176
|
+
h(Text, { color: 'magentaBright' }, String(row.role || 'agent').toUpperCase()),
|
|
1177
|
+
h(Text, { color: 'gray' }, ': '),
|
|
1178
|
+
h(Text, { color: 'white' }, row.title)
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
994
1181
|
if (row.kind === 'status') {
|
|
995
1182
|
const dots = '.'.repeat((loaderTick % 3) + 1);
|
|
996
1183
|
const phase = msg.phase;
|
|
@@ -1456,13 +1643,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1456
1643
|
if (m.id !== targetId) return m;
|
|
1457
1644
|
const toolCalls = Array.isArray(m.toolCalls) ? [...m.toolCalls] : [];
|
|
1458
1645
|
const activityType = toolEvent.type || 'tool';
|
|
1459
|
-
const
|
|
1460
|
-
? toolCalls.findIndex((t) => t.type === activityType && t.id && t.id === toolEvent.id)
|
|
1461
|
-
: -1;
|
|
1462
|
-
const byNameRunning = toolCalls.findIndex(
|
|
1463
|
-
(t) => (t.type || 'tool') === activityType && t.name === toolEvent.name && t.status !== 'done'
|
|
1464
|
-
);
|
|
1465
|
-
const idx = byId !== -1 ? byId : byNameRunning;
|
|
1646
|
+
const idx = findActivityUpdateIndex(toolCalls, toolEvent);
|
|
1466
1647
|
|
|
1467
1648
|
if (idx === -1) {
|
|
1468
1649
|
toolCalls.push({
|
|
@@ -1480,17 +1661,13 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1480
1661
|
id: toolEvent.id || toolCalls[idx].id,
|
|
1481
1662
|
status: toolEvent.status,
|
|
1482
1663
|
...(toolEvent.durationMs !== undefined ? { durationMs: toolEvent.durationMs } : {}),
|
|
1483
|
-
...(toolEvent.summary
|
|
1664
|
+
...(toolEvent.summary
|
|
1665
|
+
? { summary: mergeActivitySummary(toolCalls[idx].summary, toolEvent.summary, toolEvent.name) }
|
|
1666
|
+
: {})
|
|
1484
1667
|
};
|
|
1485
1668
|
}
|
|
1486
1669
|
const segments = Array.isArray(m.segments) ? [...m.segments] : [];
|
|
1487
|
-
const
|
|
1488
|
-
? segments.findIndex((segment) => segment.type === activityType && segment.id === toolEvent.id)
|
|
1489
|
-
: -1;
|
|
1490
|
-
const bySegmentName = segments.findIndex(
|
|
1491
|
-
(segment) => segment.type === activityType && segment.name === toolEvent.name && segment.status !== 'done'
|
|
1492
|
-
);
|
|
1493
|
-
const segmentIdx = bySegmentId !== -1 ? bySegmentId : bySegmentName;
|
|
1670
|
+
const segmentIdx = findActivityUpdateIndex(segments, toolEvent);
|
|
1494
1671
|
const patch = {
|
|
1495
1672
|
type: activityType,
|
|
1496
1673
|
id: toolEvent.id || '',
|
|
@@ -1504,7 +1681,10 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1504
1681
|
} else {
|
|
1505
1682
|
segments[segmentIdx] = {
|
|
1506
1683
|
...segments[segmentIdx],
|
|
1507
|
-
...patch
|
|
1684
|
+
...patch,
|
|
1685
|
+
...(toolEvent.summary
|
|
1686
|
+
? { summary: mergeActivitySummary(segments[segmentIdx].summary, toolEvent.summary, toolEvent.name) }
|
|
1687
|
+
: {})
|
|
1508
1688
|
};
|
|
1509
1689
|
}
|
|
1510
1690
|
return { ...m, toolCalls, segments };
|
|
@@ -2192,16 +2372,21 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2192
2372
|
const hasConversationStarted = messages.some((m) =>
|
|
2193
2373
|
['you', 'coder', 'pending', 'error'].includes(m.label)
|
|
2194
2374
|
);
|
|
2195
|
-
const
|
|
2375
|
+
const baseVisibleMessages = hasConversationStarted
|
|
2196
2376
|
? messages.filter((m) => !(m.label === 'system' && m.text === startupHint))
|
|
2197
2377
|
: messages;
|
|
2378
|
+
const visibleMessages = injectPlanStateMessage(
|
|
2379
|
+
baseVisibleMessages,
|
|
2380
|
+
planState,
|
|
2381
|
+
activeUserMessageIdRef.current,
|
|
2382
|
+
activeAssistantIdRef.current
|
|
2383
|
+
);
|
|
2198
2384
|
|
|
2199
2385
|
return h(
|
|
2200
2386
|
Box,
|
|
2201
2387
|
{ flexDirection: 'column' },
|
|
2202
2388
|
h(Header, { sessionId: displaySessionId, model: displayModel, shellName }),
|
|
2203
2389
|
h(RuntimeStrip, { busy, runtimeStatus, loaderTick, copy }),
|
|
2204
|
-
h(PlanStrip, { planState, copy }),
|
|
2205
2390
|
h(MessageList, {
|
|
2206
2391
|
messages: visibleMessages,
|
|
2207
2392
|
loaderTick,
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: executing-plan-lite
|
|
3
|
-
description: Lightweight plan execution skill for 30B-class models. Execute the plan in small verified steps with narrow context and frequent checks.
|
|
4
|
-
version: 0.1.0
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
Use this skill when a direction is chosen and the next job is to carry out implementation reliably.
|
|
8
|
-
|
|
9
|
-
Rules:
|
|
10
|
-
|
|
11
|
-
1. Execute the plan in small verified steps.
|
|
12
|
-
Take one bounded step at a time. Avoid mixing planning, implementation, and verification into one big jump.
|
|
13
|
-
|
|
14
|
-
2. Keep the active context narrow.
|
|
15
|
-
Work from the smallest relevant file set and recent evidence. If needed, use sub-agents for independent subtasks.
|
|
16
|
-
|
|
17
|
-
3. Search before editing.
|
|
18
|
-
Use `rg` to locate code, inspect the smallest useful context, then edit.
|
|
19
|
-
|
|
20
|
-
4. Verify after each meaningful change.
|
|
21
|
-
Run the most relevant test or command before claiming success.
|
|
22
|
-
|
|
23
|
-
5. Report progress briefly.
|
|
24
|
-
Summarize what changed, what was verified, and what remains.
|
|
25
|
-
|
|
26
|
-
Suggested flow:
|
|
27
|
-
- identify the next step
|
|
28
|
-
- search and inspect
|
|
29
|
-
- edit
|
|
30
|
-
- verify
|
|
31
|
-
- either continue or stop at a clear checkpoint
|
|
32
|
-
|
|
33
|
-
Use sub-agents when:
|
|
34
|
-
- the task can be split cleanly
|
|
35
|
-
- the write scope is disjoint
|
|
36
|
-
- the result can be reviewed independently
|
|
37
|
-
|
|
38
|
-
Avoid:
|
|
39
|
-
- broad refactors without a reason
|
|
40
|
-
- carrying full history into each step
|
|
41
|
-
- declaring completion without verification
|