thatgfsj-code 0.9.3 → 0.9.4

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/dist/cmd/index.js CHANGED
@@ -24,7 +24,7 @@ process.on('unhandledRejection', (reason) => {
24
24
  program
25
25
  .name('gfcode')
26
26
  .description('Thatgfsj Code - AI Coding Assistant')
27
- .version('0.9.3')
27
+ .version('0.9.4')
28
28
  .argument('[prompt]', 'Task to execute (omit to start interactive mode)')
29
29
  .option('-m, --model <model>', 'Specify model')
30
30
  .option('-i, --interactive', 'Force interactive mode')
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAgC,MAAM,OAAO,CAAC;AAUrD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG3C,UAAU,KAAK;IACb,GAAG,EAAE,GAAG,CAAC;CACV;AAED,wBAAgB,MAAM,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,qBA2FpC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAgC,MAAM,OAAO,CAAC;AAUrD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG3C,UAAU,KAAK;IACb,GAAG,EAAE,GAAG,CAAC;CACV;AAED,wBAAgB,MAAM,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,qBA+FpC"}
package/dist/tui/app.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /** @jsxImportSource react */
3
3
  import { useState, useCallback } from 'react';
4
- import { Box, useStdout } from 'ink';
4
+ import { Box, Text, useStdout } from 'ink';
5
5
  import { Header } from './components/Header.js';
6
6
  import { ChatList } from './components/ChatList.js';
7
7
  import { Thinking } from './components/Thinking.js';
@@ -11,14 +11,13 @@ import { ModelSelector } from './components/ModelSelector.js';
11
11
  import { useChat } from './hooks/useChat.js';
12
12
  import { useCommands } from './hooks/useCommands.js';
13
13
  export function TuiApp({ app }) {
14
- const { messages, isThinking, streaming, streamingToolCalls, sendMessage } = useChat(app);
14
+ const { messages, isThinking, streaming, streamingToolCalls, queuedMessage, sendMessage } = useChat(app);
15
15
  const { handleCommand } = useCommands(app);
16
16
  const [systemMessages, setSystemMessages] = useState([]);
17
17
  const [showModelSelector, setShowModelSelector] = useState(false);
18
18
  const { stdout } = useStdout();
19
19
  const terminalWidth = stdout?.columns || 80;
20
20
  const onSubmit = useCallback(async (input) => {
21
- // If model selector is showing, treat input as custom model name
22
21
  if (showModelSelector) {
23
22
  app.config.save({ model: input.trim() });
24
23
  setShowModelSelector(false);
@@ -30,7 +29,6 @@ export function TuiApp({ app }) {
30
29
  }
31
30
  const result = handleCommand(input);
32
31
  if (result.handled) {
33
- // Special: /model shows selector
34
32
  if (input.trim().toLowerCase() === '/model') {
35
33
  setShowModelSelector(true);
36
34
  return;
@@ -58,17 +56,17 @@ export function TuiApp({ app }) {
58
56
  }
59
57
  return;
60
58
  }
61
- await sendMessage(input);
59
+ sendMessage(input);
62
60
  }, [handleCommand, sendMessage, app, showModelSelector]);
63
61
  const allMessages = [...systemMessages, ...messages];
64
62
  const activeSkills = app.skills.listActive().map(s => s.id);
65
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { provider: app.config.get().provider, model: app.config.get().model }), _jsx(ChatList, { messages: allMessages, streaming: streaming, streamingToolCalls: streamingToolCalls, width: terminalWidth - 4 }), _jsx(Thinking, { active: isThinking }), showModelSelector ? (_jsx(ModelSelector, { currentModel: app.config.get().model, onSelect: (model) => {
63
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { provider: app.config.get().provider, model: app.config.get().model }), _jsx(ChatList, { messages: allMessages, streaming: streaming, streamingToolCalls: streamingToolCalls, width: terminalWidth - 4 }), _jsx(Thinking, { active: isThinking }), queuedMessage && (_jsxs(Box, { paddingLeft: 1, children: [_jsx(Text, { color: "#F59E0B", children: "\uD83D\uDCCE Queued: " }), _jsx(Text, { color: "#94A3B8", children: queuedMessage })] })), showModelSelector ? (_jsx(ModelSelector, { currentModel: app.config.get().model, onSelect: (model) => {
66
64
  app.config.save({ model });
67
65
  setShowModelSelector(false);
68
66
  setSystemMessages(prev => [
69
67
  ...prev,
70
68
  { role: 'assistant', content: `Model → ${model}` },
71
69
  ]);
72
- }, onCancel: () => setShowModelSelector(false) })) : (_jsx(UserInput, { onSubmit: onSubmit, disabled: isThinking })), _jsx(StatusBar, { messageCount: allMessages.length, skills: activeSkills })] }));
70
+ }, onCancel: () => setShowModelSelector(false) })) : (_jsx(UserInput, { onSubmit: onSubmit, disabled: false })), _jsx(StatusBar, { messageCount: allMessages.length, skills: activeSkills })] }));
73
71
  }
74
72
  //# sourceMappingURL=app.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,GAAG,EAAQ,SAAS,EAAE,MAAM,KAAK,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQrD,MAAM,UAAU,MAAM,CAAC,EAAE,GAAG,EAAS;IACnC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,kBAAkB,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1F,MAAM,EAAE,aAAa,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAgB,EAAE,CAAC,CAAC;IACxE,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,aAAa,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;IAE5C,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;QACnD,iEAAiE;QACjE,IAAI,iBAAiB,EAAE,CAAC;YACtB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAC5B,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,GAAG,IAAI;gBACP,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE;aAC1D,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QAEpC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,iCAAiC;YACjC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAC;gBAC5C,oBAAoB,CAAC,IAAI,CAAC,CAAC;gBAC3B,OAAO;YACT,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClB,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxB,GAAG,IAAI;oBACP,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE;oBAChC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,MAAO,EAAE;iBAC/C,CAAC,CAAC;YACL,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBAC9B,iBAAiB,CAAC,EAAE,CAAC,CAAC;YACxB,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;gBACvD,MAAM,aAAa,CAAC,gBAAgB,EAAE,CAAC;gBACvC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;gBAC1D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACvC,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC3B,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxB,GAAG,IAAI;oBACP,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,yBAAyB,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE;iBACnF,CAAC,CAAC;YACL,CAAC;YAED,OAAO;QACT,CAAC;QAED,MAAM,WAAW,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,EAAE,CAAC,aAAa,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAEzD,MAAM,WAAW,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,QAAQ,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5D,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,aACrC,KAAC,MAAM,IAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,GAAI,EAC9E,KAAC,QAAQ,IACP,QAAQ,EAAE,WAAW,EACrB,SAAS,EAAE,SAAS,EACpB,kBAAkB,EAAE,kBAAkB,EACtC,KAAK,EAAE,aAAa,GAAG,CAAC,GACxB,EACF,KAAC,QAAQ,IAAC,MAAM,EAAE,UAAU,GAAI,EAC/B,iBAAiB,CAAC,CAAC,CAAC,CACnB,KAAC,aAAa,IACZ,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,EACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;oBAClB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC3B,oBAAoB,CAAC,KAAK,CAAC,CAAC;oBAC5B,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxB,GAAG,IAAI;wBACP,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,KAAK,EAAE,EAAE;qBACnD,CAAC,CAAC;gBACL,CAAC,EACD,QAAQ,EAAE,GAAG,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAC3C,CACH,CAAC,CAAC,CAAC,CACF,KAAC,SAAS,IAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,GAAI,CACxD,EACD,KAAC,SAAS,IAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,GAAI,IACjE,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":"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"}
@@ -3,6 +3,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from 'react';
4
4
  import { Box, Text } from 'ink';
5
5
  export const Header = React.memo(function Header({ provider, model }) {
6
- return (_jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [_jsxs(Box, { justifyContent: "space-between", width: "100%", children: [_jsxs(Box, { children: [_jsx(Text, { color: "#06B6D4", bold: true, children: " \u26A1 " }), _jsx(Text, { color: "#22D3EE", bold: true, children: "THATGFSJ CODE" }), _jsx(Text, { dimColor: true, children: " v0.9.3" })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "#06B6D4", bold: true, children: [" ", provider, " "] }), _jsx(Text, { dimColor: true, children: "/" }), _jsxs(Text, { color: "#22D3EE", children: [" ", model, " "] })] })] }), _jsx(Text, { color: "#374151", children: '─'.repeat(80) })] }));
6
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [_jsxs(Box, { justifyContent: "space-between", width: "100%", children: [_jsxs(Box, { children: [_jsx(Text, { color: "#06B6D4", bold: true, children: " \u26A1 " }), _jsx(Text, { color: "#22D3EE", bold: true, children: "THATGFSJ CODE" }), _jsx(Text, { dimColor: true, children: " v0.9.4" })] }), _jsxs(Box, { children: [_jsxs(Text, { color: "#06B6D4", bold: true, children: [" ", provider, " "] }), _jsx(Text, { dimColor: true, children: "/" }), _jsxs(Text, { color: "#22D3EE", children: [" ", model, " "] })] })] }), _jsx(Text, { color: "#374151", children: '─'.repeat(80) })] }));
7
7
  });
8
8
  //# sourceMappingURL=Header.js.map
@@ -7,5 +7,6 @@ export declare function useChat(app: App): {
7
7
  isThinking: boolean;
8
8
  streaming: string;
9
9
  streamingToolCalls: ToolCallData[];
10
+ queuedMessage: string | null;
10
11
  };
11
12
  //# sourceMappingURL=useChat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../../src/tui/hooks/useChat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAS9C,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG;yBASU,MAAM;cAfpC,WAAW,EAAE;gBACX,OAAO;eACR,MAAM;wBACG,YAAY,EAAE;EA2InC"}
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../../src/tui/hooks/useChat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAU9C,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG;yBAwIU,MAAM;cA/IpC,WAAW,EAAE;gBACX,OAAO;eACR,MAAM;wBACG,YAAY,EAAE;mBACnB,MAAM,GAAG,IAAI;EAwJ7B"}
@@ -5,128 +5,141 @@ export function useChat(app) {
5
5
  isThinking: false,
6
6
  streaming: '',
7
7
  streamingToolCalls: [],
8
+ queuedMessage: null,
8
9
  });
9
10
  const processingRef = useRef(false);
10
- const sendMessage = useCallback((input) => {
11
- if (processingRef.current)
12
- return;
13
- processingRef.current = true;
11
+ const queuedRef = useRef(null);
12
+ const processStream = async (input) => {
14
13
  setState(prev => ({
15
14
  ...prev,
16
15
  messages: [...prev.messages, { role: 'user', content: input }],
17
16
  isThinking: true,
18
17
  streaming: '',
19
18
  streamingToolCalls: [],
19
+ queuedMessage: null,
20
20
  }));
21
21
  app.session.addMessage('user', input);
22
22
  const stream = app.streamResponse();
23
23
  let fullContent = '';
24
24
  let currentToolCalls = [];
25
25
  let lastUpdateTime = 0;
26
- const THROTTLE_MS = 50; // Update UI at most every 50ms
27
- const processStream = async () => {
28
- try {
29
- for await (const chunk of stream) {
30
- if (chunk.includes('@@TOOL@@')) {
31
- const parts = chunk.split('\n');
32
- for (const part of parts) {
33
- if (part.startsWith('@@TOOL@@')) {
34
- try {
35
- const data = JSON.parse(part.slice(8));
36
- if (data.action === 'call') {
37
- currentToolCalls.push({ name: data.name, args: data.args || '' });
38
- setState(prev => ({
39
- ...prev,
40
- isThinking: false,
41
- streamingToolCalls: [...currentToolCalls],
42
- }));
43
- }
44
- else if (data.action === 'result') {
45
- const lastIdx = currentToolCalls.length - 1;
46
- if (lastIdx >= 0) {
47
- currentToolCalls[lastIdx] = {
48
- ...currentToolCalls[lastIdx],
49
- result: data.output || data.error || '',
50
- isError: !!data.error,
51
- };
52
- }
53
- setState(prev => ({
54
- ...prev,
55
- streamingToolCalls: [...currentToolCalls],
56
- isThinking: true,
57
- }));
58
- }
26
+ const THROTTLE_MS = 50;
27
+ try {
28
+ for await (const chunk of stream) {
29
+ if (chunk.includes('@@TOOL@@')) {
30
+ const parts = chunk.split('\n');
31
+ for (const part of parts) {
32
+ if (part.startsWith('@@TOOL@@')) {
33
+ try {
34
+ const data = JSON.parse(part.slice(8));
35
+ if (data.action === 'call') {
36
+ currentToolCalls.push({ name: data.name, args: data.args || '' });
37
+ setState(prev => ({
38
+ ...prev,
39
+ isThinking: false,
40
+ streamingToolCalls: [...currentToolCalls],
41
+ }));
59
42
  }
60
- catch {
61
- fullContent += part;
43
+ else if (data.action === 'result') {
44
+ const lastIdx = currentToolCalls.length - 1;
45
+ if (lastIdx >= 0) {
46
+ currentToolCalls[lastIdx] = {
47
+ ...currentToolCalls[lastIdx],
48
+ result: data.output || data.error || '',
49
+ isError: !!data.error,
50
+ };
51
+ }
52
+ setState(prev => ({
53
+ ...prev,
54
+ streamingToolCalls: [...currentToolCalls],
55
+ isThinking: true,
56
+ }));
62
57
  }
63
58
  }
64
- else if (part) {
59
+ catch {
65
60
  fullContent += part;
66
61
  }
67
62
  }
68
- }
69
- else {
70
- fullContent += chunk;
71
- }
72
- // Throttle UI updates
73
- const now = Date.now();
74
- if (now - lastUpdateTime >= THROTTLE_MS) {
75
- lastUpdateTime = now;
76
- setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
63
+ else if (part) {
64
+ fullContent += part;
65
+ }
77
66
  }
78
67
  }
79
- // Final update
80
- if (fullContent.trim() || currentToolCalls.length > 0) {
81
- app.session.addMessage('assistant', fullContent);
68
+ else {
69
+ fullContent += chunk;
82
70
  }
83
- setState(prev => ({
84
- ...prev,
85
- messages: [
86
- ...prev.messages,
87
- ...(fullContent.trim() || currentToolCalls.length > 0
88
- ? [{
89
- role: 'assistant',
90
- content: fullContent,
91
- toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,
92
- }]
93
- : []),
94
- ],
95
- streaming: '',
96
- streamingToolCalls: [],
97
- isThinking: false,
98
- }));
99
- app.session.truncate();
100
- }
101
- catch (error) {
102
- const msg = error.message || String(error);
103
- let errorMsg = `Error: ${msg}`;
104
- if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
105
- errorMsg = `❌ API key invalid. Run \`gfcode init\` to reconfigure.`;
71
+ const now = Date.now();
72
+ if (now - lastUpdateTime >= THROTTLE_MS) {
73
+ lastUpdateTime = now;
74
+ setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
106
75
  }
107
- else if (msg.includes('429') || msg.includes('rate limit') || msg.includes('quota')) {
108
- errorMsg = `❌ Rate limit exceeded. Wait or run \`gfcode init\` to switch provider.`;
109
- }
110
- else if (msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
111
- errorMsg = `❌ Cannot connect. Check network or run \`gfcode init\`.`;
112
- }
113
- setState(prev => ({
114
- ...prev,
115
- messages: [
116
- ...prev.messages,
117
- ...(fullContent.trim()
118
- ? [{ role: 'assistant', content: fullContent }]
119
- : []),
120
- { role: 'assistant', content: errorMsg },
121
- ],
122
- streaming: '',
123
- streamingToolCalls: [],
124
- isThinking: false,
125
- }));
126
76
  }
77
+ if (fullContent.trim() || currentToolCalls.length > 0) {
78
+ app.session.addMessage('assistant', fullContent);
79
+ }
80
+ setState(prev => ({
81
+ ...prev,
82
+ messages: [
83
+ ...prev.messages,
84
+ ...(fullContent.trim() || currentToolCalls.length > 0
85
+ ? [{
86
+ role: 'assistant',
87
+ content: fullContent,
88
+ toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,
89
+ }]
90
+ : []),
91
+ ],
92
+ streaming: '',
93
+ streamingToolCalls: [],
94
+ isThinking: false,
95
+ }));
96
+ app.session.truncate();
97
+ }
98
+ catch (error) {
99
+ const msg = error.message || String(error);
100
+ let errorMsg = `Error: ${msg}`;
101
+ if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
102
+ errorMsg = `❌ API key invalid. Run \`gfcode init\` to reconfigure.`;
103
+ }
104
+ else if (msg.includes('429') || msg.includes('rate limit') || msg.includes('quota')) {
105
+ errorMsg = `❌ Rate limit exceeded. Wait or run \`gfcode init\` to switch provider.`;
106
+ }
107
+ else if (msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
108
+ errorMsg = `❌ Cannot connect. Check network or run \`gfcode init\`.`;
109
+ }
110
+ setState(prev => ({
111
+ ...prev,
112
+ messages: [
113
+ ...prev.messages,
114
+ ...(fullContent.trim()
115
+ ? [{ role: 'assistant', content: fullContent }]
116
+ : []),
117
+ { role: 'assistant', content: errorMsg },
118
+ ],
119
+ streaming: '',
120
+ streamingToolCalls: [],
121
+ isThinking: false,
122
+ }));
123
+ }
124
+ // Check if there's a queued message
125
+ if (queuedRef.current) {
126
+ const next = queuedRef.current;
127
+ queuedRef.current = null;
128
+ await processStream(next);
129
+ }
130
+ else {
127
131
  processingRef.current = false;
128
- };
129
- processStream();
132
+ }
133
+ };
134
+ const sendMessage = useCallback((input) => {
135
+ // If currently processing, queue the message
136
+ if (processingRef.current) {
137
+ queuedRef.current = input;
138
+ setState(prev => ({ ...prev, queuedMessage: input }));
139
+ return;
140
+ }
141
+ processingRef.current = true;
142
+ processStream(input);
130
143
  }, [app]);
131
144
  return { ...state, sendMessage };
132
145
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.js","sourceRoot":"","sources":["../../../src/tui/hooks/useChat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChat.js","sourceRoot":"","sources":["../../../src/tui/hooks/useChat.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thatgfsj-code",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Thatgfsj Code - AI Coding Assistant",
5
5
  "main": "dist/cmd/index.js",
6
6
  "type": "module",
package/src/cmd/index.tsx CHANGED
@@ -28,7 +28,7 @@ process.on('unhandledRejection', (reason) => {
28
28
  program
29
29
  .name('gfcode')
30
30
  .description('Thatgfsj Code - AI Coding Assistant')
31
- .version('0.9.3')
31
+ .version('0.9.4')
32
32
  .argument('[prompt]', 'Task to execute (omit to start interactive mode)')
33
33
  .option('-m, --model <model>', 'Specify model')
34
34
  .option('-i, --interactive', 'Force interactive mode')
package/src/tui/app.tsx CHANGED
@@ -17,7 +17,7 @@ interface Props {
17
17
  }
18
18
 
19
19
  export function TuiApp({ app }: Props) {
20
- const { messages, isThinking, streaming, streamingToolCalls, sendMessage } = useChat(app);
20
+ const { messages, isThinking, streaming, streamingToolCalls, queuedMessage, sendMessage } = useChat(app);
21
21
  const { handleCommand } = useCommands(app);
22
22
  const [systemMessages, setSystemMessages] = useState<MessageData[]>([]);
23
23
  const [showModelSelector, setShowModelSelector] = useState(false);
@@ -25,7 +25,6 @@ export function TuiApp({ app }: Props) {
25
25
  const terminalWidth = stdout?.columns || 80;
26
26
 
27
27
  const onSubmit = useCallback(async (input: string) => {
28
- // If model selector is showing, treat input as custom model name
29
28
  if (showModelSelector) {
30
29
  app.config.save({ model: input.trim() });
31
30
  setShowModelSelector(false);
@@ -39,7 +38,6 @@ export function TuiApp({ app }: Props) {
39
38
  const result = handleCommand(input);
40
39
 
41
40
  if (result.handled) {
42
- // Special: /model shows selector
43
41
  if (input.trim().toLowerCase() === '/model') {
44
42
  setShowModelSelector(true);
45
43
  return;
@@ -72,7 +70,7 @@ export function TuiApp({ app }: Props) {
72
70
  return;
73
71
  }
74
72
 
75
- await sendMessage(input);
73
+ sendMessage(input);
76
74
  }, [handleCommand, sendMessage, app, showModelSelector]);
77
75
 
78
76
  const allMessages = [...systemMessages, ...messages];
@@ -88,6 +86,12 @@ export function TuiApp({ app }: Props) {
88
86
  width={terminalWidth - 4}
89
87
  />
90
88
  <Thinking active={isThinking} />
89
+ {queuedMessage && (
90
+ <Box paddingLeft={1}>
91
+ <Text color="#F59E0B">📎 Queued: </Text>
92
+ <Text color="#94A3B8">{queuedMessage}</Text>
93
+ </Box>
94
+ )}
91
95
  {showModelSelector ? (
92
96
  <ModelSelector
93
97
  currentModel={app.config.get().model}
@@ -102,7 +106,7 @@ export function TuiApp({ app }: Props) {
102
106
  onCancel={() => setShowModelSelector(false)}
103
107
  />
104
108
  ) : (
105
- <UserInput onSubmit={onSubmit} disabled={isThinking} />
109
+ <UserInput onSubmit={onSubmit} disabled={false} />
106
110
  )}
107
111
  <StatusBar messageCount={allMessages.length} skills={activeSkills} />
108
112
  </Box>
@@ -14,7 +14,7 @@ export const Header = React.memo(function Header({ provider, model }: Props) {
14
14
  <Box>
15
15
  <Text color="#06B6D4" bold> ⚡ </Text>
16
16
  <Text color="#22D3EE" bold>THATGFSJ CODE</Text>
17
- <Text dimColor> v0.9.3</Text>
17
+ <Text dimColor> v0.9.4</Text>
18
18
  </Box>
19
19
  <Box>
20
20
  <Text color="#06B6D4" bold> {provider} </Text>
@@ -8,6 +8,7 @@ interface ChatState {
8
8
  isThinking: boolean;
9
9
  streaming: string;
10
10
  streamingToolCalls: ToolCallData[];
11
+ queuedMessage: string | null;
11
12
  }
12
13
 
13
14
  export function useChat(app: App) {
@@ -16,19 +17,19 @@ export function useChat(app: App) {
16
17
  isThinking: false,
17
18
  streaming: '',
18
19
  streamingToolCalls: [],
20
+ queuedMessage: null,
19
21
  });
20
22
  const processingRef = useRef(false);
23
+ const queuedRef = useRef<string | null>(null);
21
24
 
22
- const sendMessage = useCallback((input: string) => {
23
- if (processingRef.current) return;
24
- processingRef.current = true;
25
-
25
+ const processStream = async (input: string) => {
26
26
  setState(prev => ({
27
27
  ...prev,
28
28
  messages: [...prev.messages, { role: 'user', content: input }],
29
29
  isThinking: true,
30
30
  streaming: '',
31
31
  streamingToolCalls: [],
32
+ queuedMessage: null,
32
33
  }));
33
34
 
34
35
  app.session.addMessage('user', input);
@@ -37,112 +38,125 @@ export function useChat(app: App) {
37
38
  let fullContent = '';
38
39
  let currentToolCalls: ToolCallData[] = [];
39
40
  let lastUpdateTime = 0;
40
- const THROTTLE_MS = 50; // Update UI at most every 50ms
41
-
42
- const processStream = async () => {
43
- try {
44
- for await (const chunk of stream) {
45
- if (chunk.includes('@@TOOL@@')) {
46
- const parts = chunk.split('\n');
47
- for (const part of parts) {
48
- if (part.startsWith('@@TOOL@@')) {
49
- try {
50
- const data = JSON.parse(part.slice(8));
51
- if (data.action === 'call') {
52
- currentToolCalls.push({ name: data.name, args: data.args || '' });
53
- setState(prev => ({
54
- ...prev,
55
- isThinking: false,
56
- streamingToolCalls: [...currentToolCalls],
57
- }));
58
- } else if (data.action === 'result') {
59
- const lastIdx = currentToolCalls.length - 1;
60
- if (lastIdx >= 0) {
61
- currentToolCalls[lastIdx] = {
62
- ...currentToolCalls[lastIdx],
63
- result: data.output || data.error || '',
64
- isError: !!data.error,
65
- };
66
- }
67
- setState(prev => ({
68
- ...prev,
69
- streamingToolCalls: [...currentToolCalls],
70
- isThinking: true,
71
- }));
41
+ const THROTTLE_MS = 50;
42
+
43
+ try {
44
+ for await (const chunk of stream) {
45
+ if (chunk.includes('@@TOOL@@')) {
46
+ const parts = chunk.split('\n');
47
+ for (const part of parts) {
48
+ if (part.startsWith('@@TOOL@@')) {
49
+ try {
50
+ const data = JSON.parse(part.slice(8));
51
+ if (data.action === 'call') {
52
+ currentToolCalls.push({ name: data.name, args: data.args || '' });
53
+ setState(prev => ({
54
+ ...prev,
55
+ isThinking: false,
56
+ streamingToolCalls: [...currentToolCalls],
57
+ }));
58
+ } else if (data.action === 'result') {
59
+ const lastIdx = currentToolCalls.length - 1;
60
+ if (lastIdx >= 0) {
61
+ currentToolCalls[lastIdx] = {
62
+ ...currentToolCalls[lastIdx],
63
+ result: data.output || data.error || '',
64
+ isError: !!data.error,
65
+ };
72
66
  }
73
- } catch {
74
- fullContent += part;
67
+ setState(prev => ({
68
+ ...prev,
69
+ streamingToolCalls: [...currentToolCalls],
70
+ isThinking: true,
71
+ }));
75
72
  }
76
- } else if (part) {
73
+ } catch {
77
74
  fullContent += part;
78
75
  }
76
+ } else if (part) {
77
+ fullContent += part;
79
78
  }
80
- } else {
81
- fullContent += chunk;
82
- }
83
-
84
- // Throttle UI updates
85
- const now = Date.now();
86
- if (now - lastUpdateTime >= THROTTLE_MS) {
87
- lastUpdateTime = now;
88
- setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
89
79
  }
80
+ } else {
81
+ fullContent += chunk;
90
82
  }
91
83
 
92
- // Final update
93
- if (fullContent.trim() || currentToolCalls.length > 0) {
94
- app.session.addMessage('assistant', fullContent);
84
+ const now = Date.now();
85
+ if (now - lastUpdateTime >= THROTTLE_MS) {
86
+ lastUpdateTime = now;
87
+ setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
95
88
  }
89
+ }
96
90
 
97
- setState(prev => ({
98
- ...prev,
99
- messages: [
100
- ...prev.messages,
101
- ...(fullContent.trim() || currentToolCalls.length > 0
102
- ? [{
103
- role: 'assistant' as const,
104
- content: fullContent,
105
- toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,
106
- }]
107
- : []),
108
- ],
109
- streaming: '',
110
- streamingToolCalls: [],
111
- isThinking: false,
112
- }));
113
-
114
- app.session.truncate();
115
- } catch (error: any) {
116
- const msg = error.message || String(error);
117
- let errorMsg = `Error: ${msg}`;
118
-
119
- if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
120
- errorMsg = `❌ API key invalid. Run \`gfcode init\` to reconfigure.`;
121
- } else if (msg.includes('429') || msg.includes('rate limit') || msg.includes('quota')) {
122
- errorMsg = `❌ Rate limit exceeded. Wait or run \`gfcode init\` to switch provider.`;
123
- } else if (msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
124
- errorMsg = `❌ Cannot connect. Check network or run \`gfcode init\`.`;
125
- }
91
+ if (fullContent.trim() || currentToolCalls.length > 0) {
92
+ app.session.addMessage('assistant', fullContent);
93
+ }
126
94
 
127
- setState(prev => ({
128
- ...prev,
129
- messages: [
130
- ...prev.messages,
131
- ...(fullContent.trim()
132
- ? [{ role: 'assistant' as const, content: fullContent }]
133
- : []),
134
- { role: 'assistant', content: errorMsg },
135
- ],
136
- streaming: '',
137
- streamingToolCalls: [],
138
- isThinking: false,
139
- }));
95
+ setState(prev => ({
96
+ ...prev,
97
+ messages: [
98
+ ...prev.messages,
99
+ ...(fullContent.trim() || currentToolCalls.length > 0
100
+ ? [{
101
+ role: 'assistant' as const,
102
+ content: fullContent,
103
+ toolCalls: currentToolCalls.length > 0 ? currentToolCalls : undefined,
104
+ }]
105
+ : []),
106
+ ],
107
+ streaming: '',
108
+ streamingToolCalls: [],
109
+ isThinking: false,
110
+ }));
111
+
112
+ app.session.truncate();
113
+ } catch (error: any) {
114
+ const msg = error.message || String(error);
115
+ let errorMsg = `Error: ${msg}`;
116
+
117
+ if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
118
+ errorMsg = `❌ API key invalid. Run \`gfcode init\` to reconfigure.`;
119
+ } else if (msg.includes('429') || msg.includes('rate limit') || msg.includes('quota')) {
120
+ errorMsg = `❌ Rate limit exceeded. Wait or run \`gfcode init\` to switch provider.`;
121
+ } else if (msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
122
+ errorMsg = `❌ Cannot connect. Check network or run \`gfcode init\`.`;
140
123
  }
141
124
 
125
+ setState(prev => ({
126
+ ...prev,
127
+ messages: [
128
+ ...prev.messages,
129
+ ...(fullContent.trim()
130
+ ? [{ role: 'assistant' as const, content: fullContent }]
131
+ : []),
132
+ { role: 'assistant', content: errorMsg },
133
+ ],
134
+ streaming: '',
135
+ streamingToolCalls: [],
136
+ isThinking: false,
137
+ }));
138
+ }
139
+
140
+ // Check if there's a queued message
141
+ if (queuedRef.current) {
142
+ const next = queuedRef.current;
143
+ queuedRef.current = null;
144
+ await processStream(next);
145
+ } else {
142
146
  processingRef.current = false;
143
- };
147
+ }
148
+ };
144
149
 
145
- processStream();
150
+ const sendMessage = useCallback((input: string) => {
151
+ // If currently processing, queue the message
152
+ if (processingRef.current) {
153
+ queuedRef.current = input;
154
+ setState(prev => ({ ...prev, queuedMessage: input }));
155
+ return;
156
+ }
157
+
158
+ processingRef.current = true;
159
+ processStream(input);
146
160
  }, [app]);
147
161
 
148
162
  return { ...state, sendMessage };