mu-coding 0.2.0 → 0.5.0

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.
Files changed (72) hide show
  1. package/README.md +0 -2
  2. package/bin/mu.js +1 -1
  3. package/package.json +12 -4
  4. package/src/app/shutdown.ts +94 -0
  5. package/src/app/startApp.ts +40 -0
  6. package/src/cli/args.ts +128 -0
  7. package/src/{install.ts → cli/install.ts} +19 -15
  8. package/src/config/index.test.ts +51 -0
  9. package/src/config/index.ts +181 -0
  10. package/src/main.ts +4 -0
  11. package/src/runtime/createRegistry.ts +58 -0
  12. package/src/runtime/pluginLoader.ts +109 -0
  13. package/src/sessions/index.test.ts +66 -0
  14. package/src/sessions/index.ts +190 -0
  15. package/src/sessions/peek.test.ts +88 -0
  16. package/src/sessions/project.ts +51 -0
  17. package/src/tui/{context/chat.ts → chat/ChatContext.ts} +1 -1
  18. package/src/tui/chat/ToolDisplayContext.ts +33 -0
  19. package/src/tui/{useAbort.ts → chat/useAbort.ts} +16 -7
  20. package/src/tui/chat/useAttachment.ts +74 -0
  21. package/src/tui/{useChat.ts → chat/useChat.ts} +32 -6
  22. package/src/tui/chat/useChatPanel.ts +96 -0
  23. package/src/tui/chat/useChatSession.ts +115 -0
  24. package/src/tui/{useModelList.ts → chat/useModels.ts} +10 -1
  25. package/src/tui/chat/usePluginStatus.ts +44 -0
  26. package/src/tui/chat/useSessionPersistence.ts +57 -0
  27. package/src/tui/chat/useStatusSegments.ts +49 -0
  28. package/src/tui/chat/useStreamConsumer.ts +118 -0
  29. package/src/tui/components/chat/ChatPanel.tsx +12 -38
  30. package/src/tui/components/chat/ChatPanelBody.tsx +30 -52
  31. package/src/tui/components/chat/Pickers.tsx +2 -2
  32. package/src/tui/components/messageView.tsx +70 -0
  33. package/src/tui/components/messages/EditOutput.tsx +42 -27
  34. package/src/tui/components/messages/ReadOutput.tsx +27 -22
  35. package/src/tui/components/messages/ToolHeader.tsx +26 -0
  36. package/src/tui/components/messages/WriteOutput.tsx +12 -24
  37. package/src/tui/components/messages/messageItem.tsx +4 -15
  38. package/src/tui/components/messages/toolCallBlock.tsx +56 -34
  39. package/src/tui/components/{ui → primitives}/dropdown.tsx +32 -7
  40. package/src/tui/components/primitives/pickerModal.tsx +45 -0
  41. package/src/tui/components/primitives/scrollbar.tsx +27 -0
  42. package/src/tui/components/statusBar.tsx +25 -0
  43. package/src/tui/components/ui/dialogLayer.tsx +21 -7
  44. package/src/tui/hooks/useScroll.ts +11 -3
  45. package/src/tui/input/InputBox.tsx +6 -0
  46. package/src/tui/{components/inputBox.tsx → input/InputBoxView.tsx} +24 -49
  47. package/src/tui/input/commands.test.ts +49 -0
  48. package/src/tui/input/commands.ts +39 -0
  49. package/src/tui/input/sanitize.ts +33 -0
  50. package/src/tui/input/useCommandExecutor.ts +32 -0
  51. package/src/tui/input/useInputBox.ts +88 -0
  52. package/src/tui/{hooks → input}/useInputHandler.ts +21 -26
  53. package/src/tui/{services/uiService.ts → plugins/InkUIService.ts} +68 -35
  54. package/src/tui/renderApp.tsx +30 -0
  55. package/src/utils/clipboard.ts +97 -0
  56. package/src/utils/diff.test.ts +56 -0
  57. package/src/cli.ts +0 -92
  58. package/src/clipboard.ts +0 -62
  59. package/src/config.ts +0 -116
  60. package/src/main.tsx +0 -161
  61. package/src/project.ts +0 -32
  62. package/src/session.ts +0 -95
  63. package/src/singleShot.ts +0 -42
  64. package/src/tui/commands.ts +0 -33
  65. package/src/tui/components/chatLayout.tsx +0 -192
  66. package/src/tui/useChatSession.ts +0 -155
  67. package/src/tui/useChatUI.ts +0 -51
  68. package/tsconfig.json +0 -10
  69. /package/src/{subcommands.ts → cli/subcommands.ts} +0 -0
  70. /package/src/tui/components/{ui → primitives}/modal.tsx +0 -0
  71. /package/src/tui/components/{ui → primitives}/toast.tsx +0 -0
  72. /package/src/{diff.ts → utils/diff.ts} +0 -0
@@ -1,155 +0,0 @@
1
- import { type AgentEvent, type PluginRegistry, runAgent } from 'mu-agents';
2
- import type { ChatMessage, ProviderConfig } from 'mu-provider';
3
- import { useCallback, useRef, useState } from 'react';
4
- import { generateSessionPath, loadSession, saveSession } from '../session';
5
- import type { AttachmentState } from './useChatUI';
6
-
7
- export interface StreamState {
8
- text: string;
9
- reasoning: string;
10
- totalTokens: number;
11
- tps: number;
12
- }
13
-
14
- const EMPTY_STREAM: StreamState = { text: '', reasoning: '', totalTokens: 0, tps: 0 };
15
-
16
- export interface ChatSessionState {
17
- messages: ChatMessage[];
18
- streaming: boolean;
19
- error: string | null;
20
- stream: StreamState;
21
- inputHistory: string[];
22
- onSend: (text: string) => Promise<void>;
23
- onNew: () => void;
24
- onLoadSession: (path: string) => void;
25
- }
26
-
27
- interface SessionDeps {
28
- config: ProviderConfig;
29
- currentModel: string;
30
- attachment: AttachmentState;
31
- controllerRef: React.RefObject<AbortController | null>;
32
- initialMessages?: ChatMessage[];
33
- registry: PluginRegistry;
34
- }
35
-
36
- function applyEvent(prev: StreamState, event: AgentEvent, tps: number): StreamState {
37
- switch (event.type) {
38
- case 'content':
39
- return { ...prev, text: event.text, tps };
40
- case 'reasoning':
41
- return { ...prev, reasoning: event.text, tps };
42
- case 'usage':
43
- return { ...prev, totalTokens: prev.totalTokens + event.totalTokens };
44
- case 'turn_end':
45
- return { ...prev, text: '', reasoning: '' };
46
- default:
47
- return prev;
48
- }
49
- }
50
-
51
- async function consumeAgent(
52
- events: AsyncGenerator<AgentEvent>,
53
- onStream: (updater: (prev: StreamState) => StreamState) => void,
54
- onMessages: (messages: ChatMessage[]) => void,
55
- ): Promise<ChatMessage[] | null> {
56
- let final: ChatMessage[] | null = null;
57
- const start = Date.now();
58
- let tokenCount = 0;
59
-
60
- for await (const event of events) {
61
- if (event.type === 'content' || event.type === 'reasoning') {
62
- tokenCount++;
63
- const elapsed = (Date.now() - start) / 1000;
64
- const tps = elapsed > 0.5 ? Math.round(tokenCount / elapsed) : 0;
65
- onStream((prev) => applyEvent(prev, event, tps));
66
- } else if (event.type === 'messages') {
67
- final = event.messages;
68
- onMessages(event.messages);
69
- } else {
70
- onStream((prev) => applyEvent(prev, event, 0));
71
- }
72
- }
73
- return final;
74
- }
75
-
76
- export function useChatSession(deps: SessionDeps): ChatSessionState {
77
- const { config, currentModel, attachment, controllerRef, initialMessages, registry } = deps;
78
- const [messages, setMessages] = useState<ChatMessage[]>(initialMessages ?? []);
79
- const [streaming, setStreaming] = useState(false);
80
- const [error, setError] = useState<string | null>(null);
81
- const [stream, setStream] = useState<StreamState>(EMPTY_STREAM);
82
- const [inputHistory, setInputHistory] = useState<string[]>(
83
- initialMessages?.filter((m) => m.role === 'user').map((m) => m.content) ?? [],
84
- );
85
- const sessionPathRef = useRef(generateSessionPath());
86
-
87
- const reset = useCallback(() => {
88
- setStream(EMPTY_STREAM);
89
- setError(null);
90
- }, []);
91
-
92
- const onSend = useCallback(
93
- async (text: string) => {
94
- if (streaming) {
95
- return;
96
- }
97
- const userMsg: ChatMessage = {
98
- role: 'user',
99
- content: text,
100
- ...(attachment.attachment ? { images: [attachment.attachment] } : {}),
101
- };
102
- setMessages((prev) => [...prev, userMsg]);
103
- setInputHistory((prev) => [...prev, text]);
104
- reset();
105
- setStreaming(true);
106
- attachment.clear();
107
-
108
- const controller = new AbortController();
109
- controllerRef.current = controller;
110
-
111
- try {
112
- const final = await consumeAgent(
113
- runAgent([...messages, userMsg], config, currentModel, controller.signal, registry),
114
- setStream,
115
- setMessages,
116
- );
117
- if (final) {
118
- saveSession(sessionPathRef.current, final);
119
- }
120
- } catch (err) {
121
- if (!(err instanceof Error && err.name === 'AbortError')) {
122
- setError(err instanceof Error ? err.message : 'Unknown error');
123
- }
124
- } finally {
125
- setStreaming(false);
126
- controllerRef.current = null;
127
- if (!controller.signal.aborted) {
128
- setStream((s) => ({ ...s, text: '', reasoning: '' }));
129
- }
130
- }
131
- },
132
- [streaming, messages, config, currentModel, attachment, controllerRef, reset, registry],
133
- );
134
-
135
- const onNew = useCallback(() => {
136
- setMessages([]);
137
- reset();
138
- sessionPathRef.current = generateSessionPath();
139
- attachment.clear();
140
- }, [attachment, reset]);
141
-
142
- const onLoadSession = useCallback(
143
- (path: string) => {
144
- const msgs = loadSession(path);
145
- if (msgs.length > 0) {
146
- setMessages(msgs);
147
- sessionPathRef.current = path;
148
- reset();
149
- }
150
- },
151
- [reset],
152
- );
153
-
154
- return { messages, streaming, error, stream, inputHistory, onSend, onNew, onLoadSession };
155
- }
@@ -1,51 +0,0 @@
1
- import type { ImageAttachment } from 'mu-provider';
2
- import { useCallback, useState } from 'react';
3
- import { readClipboardImage } from '../clipboard';
4
-
5
- export interface AttachmentState {
6
- attachment: ImageAttachment | null;
7
- attachmentError: string | null;
8
- onPaste: () => void;
9
- clear: () => void;
10
- }
11
-
12
- export function useAttachment(): AttachmentState {
13
- const [attachment, setAttachment] = useState<ImageAttachment | null>(null);
14
- const [attachmentError, setAttachmentError] = useState<string | null>(null);
15
-
16
- const onPaste = useCallback(() => {
17
- const img = readClipboardImage();
18
- if (img) {
19
- setAttachment(img);
20
- setAttachmentError(null);
21
- return;
22
- }
23
- setAttachmentError('No image on clipboard');
24
- setTimeout(() => setAttachmentError(null), 3000);
25
- }, []);
26
-
27
- const clear = useCallback(() => {
28
- setAttachment(null);
29
- setAttachmentError(null);
30
- }, []);
31
-
32
- return { attachment, attachmentError, onPaste, clear };
33
- }
34
-
35
- export interface TogglesState {
36
- showModelPicker: boolean;
37
- showSessionPicker: boolean;
38
- onTogglePicker: () => void;
39
- onToggleSessionPicker: () => void;
40
- }
41
-
42
- export function useToggles(): TogglesState {
43
- const [showModelPicker, setShowModelPicker] = useState(false);
44
- const [showSessionPicker, setShowSessionPicker] = useState(false);
45
- return {
46
- showModelPicker,
47
- showSessionPicker,
48
- onTogglePicker: useCallback(() => setShowModelPicker((p) => !p), []),
49
- onToggleSessionPicker: useCallback(() => setShowSessionPicker((p) => !p), []),
50
- };
51
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src"
6
- },
7
- "include": ["src/**/*"],
8
- "exclude": ["node_modules", "dist"],
9
- "references": [{ "path": "../mu-provider" }, { "path": "../mu-agents" }, { "path": "../mu-repomap" }]
10
- }
File without changes
File without changes
File without changes
File without changes