miii-cli 0.2.6 → 0.2.7

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.
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useCallback, useRef } from 'react';
2
+ import { useState, useCallback, useRef, useMemo } from 'react';
3
3
  import { Box, Text, useStdout } from 'ink';
4
4
  import { InputArea } from './components/InputArea.js';
5
5
  import { ModelPicker } from './components/ModelPicker.js';
@@ -42,6 +42,7 @@ function buildAtContext(text) {
42
42
  export function InputBar({ config, skills, cwd, session, version }) {
43
43
  const { stdout } = useStdout();
44
44
  const cols = stdout.columns ?? 80;
45
+ const phraseSeq = useMemo(() => Array.from({ length: 100 }, () => Math.floor(Math.random() * THINKING_PHRASES.length)), []);
45
46
  const [planningMode, setPlanningMode] = useState(false);
46
47
  const macroQueueRef = useRef(new MacroQueue());
47
48
  const executorRef = useRef(new TaskExecutor(tools));
@@ -446,7 +447,7 @@ export function InputBar({ config, skills, cwd, session, version }) {
446
447
  }, [skills, runLoop, openPicker]);
447
448
  const skillList = skills.list();
448
449
  // ─── render ────────────────────────────────────────────────────────────────
449
- return (_jsxs(Box, { flexDirection: "column", children: [pickerOpen ? (_jsxs(_Fragment, { children: [_jsx(ModelPicker, { models: pickerModels, current: currentModel, loading: pickerLoading, error: pickerError, pull: pullState, onSelect: handleModelSelect, onPull: handleModelPull, onClose: () => { setPickerOpen(false); } }), _jsx(Divider, { cols: cols })] })) : (status === 'thinking' || status === 'tool') ? (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, color: "green", children: "miii" }), _jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [_jsx(Box, { children: status === 'thinking'
450
- ? _jsxs(_Fragment, { children: [_jsxs(Text, { color: "yellow", children: [SPARKLE[tick % SPARKLE.length], " "] }), _jsx(Text, { color: "gray", dimColor: true, italic: true, children: THINKING_PHRASES[Math.floor(tick / 62) % THINKING_PHRASES.length] })] })
451
- : _jsxs(Text, { color: "yellow", dimColor: true, children: ["\u2699 running ", currentTool ?? 'tool', "\u2026"] }) }), _jsxs(Box, { gap: 2, children: [_jsxs(Text, { color: "gray", dimColor: true, children: [Math.floor((Date.now() - thinkingStartRef.current) / 1000), "s"] }), taskLabel && _jsx(Text, { color: "cyan", dimColor: true, children: taskLabel })] })] })] }), _jsx(Divider, { cols: cols })] })) : null, _jsx(InputArea, { status: status, skills: skillList, cwd: cwd, planningMode: planningMode, onSubmit: handleSubmit, onAbort: handleAbort })] }));
450
+ return (_jsxs(Box, { flexDirection: "column", children: [pickerOpen ? (_jsxs(_Fragment, { children: [_jsx(ModelPicker, { models: pickerModels, current: currentModel, loading: pickerLoading, error: pickerError, pull: pullState, onSelect: handleModelSelect, onPull: handleModelPull, onClose: () => { setPickerOpen(false); } }), _jsx(Divider, { cols: cols })] })) : (status === 'thinking' || status === 'tool') ? (_jsxs(_Fragment, { children: [_jsx(Box, { flexDirection: "column", paddingX: 1, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: status === 'thinking'
451
+ ? _jsxs(_Fragment, { children: [_jsxs(Text, { color: "yellow", children: [SPARKLE[tick % SPARKLE.length], " "] }), _jsx(Text, { color: "gray", dimColor: true, italic: true, children: THINKING_PHRASES[phraseSeq[Math.floor(tick / 62) % phraseSeq.length]] })] })
452
+ : _jsxs(Text, { color: "yellow", dimColor: true, children: ["\u2699 running ", currentTool ?? 'tool', "\u2026"] }) }), _jsxs(Box, { gap: 2, children: [_jsxs(Text, { color: "gray", dimColor: true, children: [Math.floor((Date.now() - thinkingStartRef.current) / 1000), "s"] }), taskLabel && _jsx(Text, { color: "cyan", dimColor: true, children: taskLabel })] })] }) }), _jsx(Divider, { cols: cols })] })) : null, _jsx(InputArea, { status: status, skills: skillList, cwd: cwd, planningMode: planningMode, onSubmit: handleSubmit, onAbort: handleAbort })] }));
452
453
  }
@@ -10,6 +10,8 @@ const green = (s) => col(92, s);
10
10
  const cyan = (s) => col(96, s);
11
11
  const gray = (s) => col(90, s);
12
12
  const yellow = (s) => col(93, s);
13
+ const purple = (s) => col(95, s);
14
+ const red = (s) => col(91, s);
13
15
  function indent(text, pad = ' ') {
14
16
  return text.split('\n').map(l => pad + l).join('\n');
15
17
  }
@@ -84,18 +86,39 @@ export function welcome(provider, model, cwd, version, updateAvailable, linked)
84
86
  function row(l, r) {
85
87
  return gray('│') + cell(l, leftW) + gray('│') + cell(r, rightW) + gray('│');
86
88
  }
87
- function blank() {
88
- return gray('│') + ' '.repeat(leftW) + gray('│') + ' '.repeat(rightW) + gray('│');
89
- }
90
- function rcmd(key, desc, keyW = 10) {
91
- return ' ' + cyan(key) + ' '.repeat(Math.max(1, keyW - key.length)) + gray(desc);
92
- }
93
89
  const versionStr = version ? ` v${version}` : '';
94
90
  const titleStr = `─ MIII - CLI${versionStr} `;
95
91
  const dashCount = Math.max(0, cols - 2 - titleStr.length);
96
92
  const top = gray('╭') + gray('─') + bold(cyan(` MIII - CLI${versionStr} `)) + gray('─'.repeat(dashCount) + '╮');
97
93
  const bottom = gray('╰' + '─'.repeat(innerW) + '╯');
98
94
  const shortCwd = cwd.replace(process.env.HOME ?? '', '~');
95
+ const username = process.env.USER ?? 'there';
96
+ const miniArt = [
97
+ ` ${purple(' ● ● ')}`,
98
+ ` ${purple(' ╱ ╲ ╱ ╲ ')}`,
99
+ ` ${purple(' ╱ ╲ ╱ ╲ ')}`,
100
+ ` ${purple('● ● ●')}`,
101
+ ];
102
+ const leftLines = [
103
+ '',
104
+ ...miniArt,
105
+ '',
106
+ ` ${gray(model + ' · ' + provider)}`,
107
+ ` ${gray(shortCwd)}`,
108
+ '',
109
+ ];
110
+ const rightLines = [
111
+ '',
112
+ ` ${bold(yellow('Tips for getting started'))}`,
113
+ ` Type ${cyan('@filename')} to inject file into context`,
114
+ ` Use ${cyan('/skill')} to run a skill or command`,
115
+ ` Use ${cyan('/models')} to switch or pull models`,
116
+ '',
117
+ ];
118
+ const maxLen = Math.max(leftLines.length, rightLines.length);
119
+ const pl = [...leftLines, ...Array(Math.max(0, maxLen - leftLines.length)).fill('')];
120
+ const pr = [...rightLines, ...Array(Math.max(0, maxLen - rightLines.length)).fill('')];
121
+ const contentRows = pl.map((l, i) => row(l, pr[i]));
99
122
  const upgradeCmd = linked ? 'cd <miii-dir> && npm run build' : 'npm install -g miii-cli';
100
123
  const separator = gray('│') + bold(yellow(' ⬆ update available: v' + updateAvailable + ' — run: ' + upgradeCmd)).padEnd(innerW - 1) + gray('│');
101
124
  const updateRow = updateAvailable
@@ -103,33 +126,34 @@ export function welcome(provider, model, cwd, version, updateAvailable, linked)
103
126
  : [];
104
127
  const lines = [
105
128
  top,
106
- blank(),
107
- row(` ${bold(cyan('MIII - CLI'))}`, ` ${bold(yellow('Getting started'))}`),
108
- row(` ${gray('Claude Code-level terminal')}`, rcmd('@filename', 'inject file into context')),
109
- row(` ${gray('workflows, local models.')}`, rcmd('/skill', 'run a skill or command')),
110
- row('', rcmd('/models', 'switch or pull models')),
111
- row('', rcmd('/list', 'list all skills')),
112
- row('', rcmd('/session', 'manage sessions')),
113
- blank(),
114
- row(` ${gray(provider + '/' + model)}`, ` ${bold(yellow('Tips'))}`),
115
- row(` ${gray(shortCwd)}`, rcmd('ctrl+c', 'stop thinking')),
116
- row('', rcmd('ctrl+c x2', 'exit')),
129
+ ...contentRows,
117
130
  ...updateRow,
118
- blank(),
119
131
  bottom,
120
132
  ];
121
133
  process.stdout.write(lines.join('\n') + '\n');
122
134
  }
123
135
  export function userMsg(text) {
124
136
  const atHighlighted = text.replace(/(@[\w./\-]+)/g, (m) => cyan(m));
125
- console.log(`\n${bold(blue('You'))}\n${indent(atHighlighted)}`);
137
+ console.log(`\n${gray('>>')} ${atHighlighted}`);
126
138
  }
127
139
  export function assistantMsg(text) {
128
- console.log(`\n${bold(green('miii'))}\n${formatContent(text)}`);
140
+ const content = formatContent(text);
141
+ if (!content.trim())
142
+ return;
143
+ const lines = content.split('\n');
144
+ const idx = lines.findIndex(l => l.trim());
145
+ if (idx === -1)
146
+ return;
147
+ const head = lines[idx].replace(/^ {2}/, '');
148
+ const tail = lines.slice(idx + 1).join('\n');
149
+ console.log(`\n${blue('●')} ${head}${tail ? '\n' + tail : ''}`);
129
150
  }
151
+ const EDIT_TOOLS = new Set(['edit_file', 'patch_file', 'create_file', 'write_file']);
152
+ const DELETE_TOOLS = new Set(['delete_file', 'remove_file']);
130
153
  export function toolCallStart(name, args) {
131
154
  const summary = toolArgSummary(args);
132
- process.stdout.write(` ${gray('')} ${cyan(name)}${summary ? gray('(' + summary + ')') : ''}\n`);
155
+ const dot = DELETE_TOOLS.has(name) ? red('') : EDIT_TOOLS.has(name) ? green('') : blue('');
156
+ process.stdout.write(` ${dot} ${cyan(name)}${summary ? gray('(' + summary + ')') : ''}\n`);
133
157
  }
134
158
  export function toolMsg(name, result) {
135
159
  const preview = result.length > 250 ? result.slice(0, 250) + '…' : result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miii-cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "description": "Claude Code-level terminal workflows powered by your local models.",
6
6
  "license": "MIT",