thatgfsj-code 0.8.4 → 0.9.1

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.8.4')
27
+ .version('0.9.1')
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')
@@ -4,16 +4,16 @@ import React from 'react';
4
4
  import { Box, Text } from 'ink';
5
5
  import { Markdown } from './Markdown.js';
6
6
  import { ToolCall } from './ToolCall.js';
7
- function UserMessage({ content, width }) {
8
- return (_jsx(Box, { borderStyle: "round", borderLeft: true, borderColor: "#06B6D4", paddingLeft: 1, marginBottom: 1, children: _jsxs(Box, { flexDirection: "column", width: width ? width - 4 : undefined, children: [_jsx(Text, { bold: true, color: "#06B6D4", children: "You" }), _jsx(Text, { children: content })] }) }));
7
+ function UserMessage({ content }) {
8
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, paddingLeft: 1, children: [_jsx(Text, { bold: true, color: "#06B6D4", children: "You" }), _jsx(Box, { paddingLeft: 2, children: _jsx(Text, { children: content }) })] }));
9
9
  }
10
- function AssistantMessage({ content, toolCalls, width }) {
11
- return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [toolCalls && toolCalls.map((tc, i) => (_jsx(ToolCall, { tool: tc, width: width }, i))), content && (_jsx(Box, { borderStyle: "round", borderLeft: true, borderColor: "#22D3EE", paddingLeft: 1, children: _jsxs(Box, { flexDirection: "column", width: width ? width - 4 : undefined, children: [_jsx(Text, { bold: true, color: "#22D3EE", children: "AI" }), _jsx(Markdown, { content: content })] }) }))] }));
10
+ function AssistantMessage({ content, toolCalls }) {
11
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [toolCalls && toolCalls.map((tc, i) => (_jsx(ToolCall, { tool: tc }, i))), content && (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { bold: true, color: "#22D3EE", children: "AI" }), _jsx(Box, { paddingLeft: 2, children: _jsx(Markdown, { content: content }) })] }))] }));
12
12
  }
13
- export const ChatMessage = React.memo(function ChatMessage({ message, width }) {
13
+ export const ChatMessage = React.memo(function ChatMessage({ message }) {
14
14
  if (message.role === 'user') {
15
- return _jsx(UserMessage, { content: message.content, width: width });
15
+ return _jsx(UserMessage, { content: message.content });
16
16
  }
17
- return _jsx(AssistantMessage, { content: message.content, toolCalls: message.toolCalls, width: width });
17
+ return _jsx(AssistantMessage, { content: message.content, toolCalls: message.toolCalls });
18
18
  });
19
19
  //# sourceMappingURL=ChatMessage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChatMessage.js","sourceRoot":"","sources":["../../../src/tui/components/ChatMessage.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAC;AAa5D,SAAS,WAAW,CAAC,EAAE,OAAO,EAAE,KAAK,EAAuC;IAC1E,OAAO,CACL,KAAC,GAAG,IAAC,WAAW,EAAC,OAAO,EAAC,UAAU,QAAC,WAAW,EAAC,SAAS,EAAC,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,YACvF,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAC9D,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,oBAAW,EACrC,KAAC,IAAI,cAAE,OAAO,GAAQ,IAClB,GACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAmE;IACtH,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACxC,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACrC,KAAC,QAAQ,IAAS,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,IAAzB,CAAC,CAA4B,CAC7C,CAAC,EACD,OAAO,IAAI,CACV,KAAC,GAAG,IAAC,WAAW,EAAC,OAAO,EAAC,UAAU,QAAC,WAAW,EAAC,SAAS,EAAC,WAAW,EAAE,CAAC,YACtE,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAC9D,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,mBAAU,EACpC,KAAC,QAAQ,IAAC,OAAO,EAAE,OAAO,GAAI,IAC1B,GACF,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,EAAE,OAAO,EAAE,KAAK,EAAS;IAClF,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,KAAC,WAAW,IAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,GAAI,CAAC;IACjE,CAAC;IACD,OAAO,KAAC,gBAAgB,IAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,GAAI,CAAC;AACpG,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"ChatMessage.js","sourceRoot":"","sources":["../../../src/tui/components/ChatMessage.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAqB,MAAM,eAAe,CAAC;AAa5D,SAAS,WAAW,CAAC,EAAE,OAAO,EAAuB;IACnD,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,aACzD,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,oBAAW,EACrC,KAAC,GAAG,IAAC,WAAW,EAAE,CAAC,YACjB,KAAC,IAAI,cAAE,OAAO,GAAQ,GAClB,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAmD;IAC/F,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aACxC,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CACrC,KAAC,QAAQ,IAAS,IAAI,EAAE,EAAE,IAAX,CAAC,CAAc,CAC/B,CAAC,EACD,OAAO,IAAI,CACV,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,SAAS,mBAAU,EACpC,KAAC,GAAG,IAAC,WAAW,EAAE,CAAC,YACjB,KAAC,QAAQ,IAAC,OAAO,EAAE,OAAO,GAAI,GAC1B,IACF,CACP,IACG,CACP,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,EAAE,OAAO,EAAS;IAC3E,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC5B,OAAO,KAAC,WAAW,IAAC,OAAO,EAAE,OAAO,CAAC,OAAO,GAAI,CAAC;IACnD,CAAC;IACD,OAAO,KAAC,gBAAgB,IAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,GAAI,CAAC;AACtF,CAAC,CAAC,CAAC"}
@@ -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.8.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) })] }));
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.1" })] }), _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
@@ -10,6 +10,6 @@ interface Props {
10
10
  tool: ToolCallData;
11
11
  width?: number;
12
12
  }
13
- export declare function ToolCall({ tool, width }: Props): React.JSX.Element;
13
+ export declare function ToolCall({ tool }: Props): React.JSX.Element;
14
14
  export type { ToolCallData };
15
15
  //# sourceMappingURL=ToolCall.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.d.ts","sourceRoot":"","sources":["../../../src/tui/components/ToolCall.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,KAAK;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmCD,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,qBAsB9C;AAED,YAAY,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"ToolCall.d.ts","sourceRoot":"","sources":["../../../src/tui/components/ToolCall.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,KAAK;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4BD,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,qBA0BvC;AAED,YAAY,EAAE,YAAY,EAAE,CAAC"}
@@ -1,6 +1,6 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from 'ink';
3
- function formatToolParams(name, args) {
3
+ function formatToolName(name, args) {
4
4
  try {
5
5
  const obj = JSON.parse(args);
6
6
  switch (name) {
@@ -9,34 +9,26 @@ function formatToolParams(name, args) {
9
9
  const path = (obj.path || '').replace(/.*[/\\]/, '');
10
10
  return `${action} ${path || obj.path || ''}`;
11
11
  }
12
- case 'shell': return obj.command || '';
12
+ case 'shell': return obj.command?.slice(0, 60) || '';
13
13
  case 'git': return obj.command || '';
14
14
  case 'search': return obj.query || obj.pattern || '';
15
15
  case 'nwt': return obj.action || '';
16
- default: {
17
- const first = Object.entries(obj)[0];
18
- if (!first)
19
- return '';
20
- const val = typeof first[1] === 'string' && first[1].length > 40
21
- ? first[1].slice(0, 40) + '...'
22
- : JSON.stringify(first[1]);
23
- return `${first[0]}=${val}`;
24
- }
16
+ default: return Object.keys(obj).slice(0, 2).join(', ');
25
17
  }
26
18
  }
27
19
  catch {
28
- return args.length > 50 ? args.slice(0, 50) + '...' : args;
20
+ return '';
29
21
  }
30
22
  }
31
- function formatResult(output, maxLines = 10) {
23
+ function truncateOutput(output, maxLines = 8) {
32
24
  const lines = output.split('\n');
33
25
  if (lines.length <= maxLines)
34
26
  return { text: output, truncated: false };
35
27
  return { text: lines.slice(0, maxLines).join('\n'), truncated: true };
36
28
  }
37
- export function ToolCall({ tool, width }) {
38
- const params = formatToolParams(tool.name, tool.args);
39
- const result = tool.result ? formatResult(tool.result) : null;
40
- return (_jsxs(Box, { borderStyle: "round", borderLeft: true, borderColor: "#06B6D4", paddingLeft: 1, flexDirection: "column", marginBottom: 0, children: [_jsxs(Box, { children: [_jsxs(Text, { color: "#06B6D4", bold: true, children: ["\u2699 ", tool.name, ": "] }), _jsx(Text, { color: "#94A3B8", children: params })] }), result && (_jsxs(Box, { paddingLeft: 1, flexDirection: "column", children: [result.text.split('\n').map((line, i) => (_jsx(Text, { color: tool.isError ? '#EF4444' : '#64748B', children: line }, i))), result.truncated && _jsx(Text, { dimColor: true, children: "..." })] }))] }));
29
+ export function ToolCall({ tool }) {
30
+ const label = formatToolName(tool.name, tool.args);
31
+ const result = tool.result ? truncateOutput(tool.result) : null;
32
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 0, paddingLeft: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u2699 " }), _jsx(Text, { color: "#06B6D4", children: tool.name }), label && _jsxs(Text, { color: "#64748B", children: [" ", label] })] }), result && (_jsxs(Box, { paddingLeft: 2, flexDirection: "column", children: [result.text.split('\n').map((line, i) => (_jsx(Text, { color: tool.isError ? '#EF4444' : '#64748B', wrap: "truncate", children: line }, i))), result.truncated && _jsx(Text, { dimColor: true, children: " ..." })] }))] }));
41
33
  }
42
34
  //# sourceMappingURL=ToolCall.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.js","sourceRoot":"","sources":["../../../src/tui/components/ToolCall.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAchC,SAAS,gBAAgB,CAAC,IAAY,EAAE,IAAY;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;gBAChC,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBACrD,OAAO,GAAG,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;YAC/C,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,OAAO,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;YACvC,KAAK,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;YACrC,KAAK,QAAQ,CAAC,CAAC,OAAO,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;YACrD,KAAK,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;YACpC,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrC,IAAI,CAAC,KAAK;oBAAE,OAAO,EAAE,CAAC;gBACtB,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;oBAC9D,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK;oBAC/B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,QAAQ,GAAG,EAAE;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACxE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAS;IAC7C,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE9D,OAAO,CACL,MAAC,GAAG,IAAC,WAAW,EAAC,OAAO,EAAC,UAAU,QAAC,WAAW,EAAC,SAAS,EAAC,WAAW,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC,aAC9G,MAAC,GAAG,eACF,MAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,8BAAI,IAAI,CAAC,IAAI,UAAU,EACjD,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,YAAE,MAAM,GAAQ,IACjC,EACL,MAAM,IAAI,CACT,MAAC,GAAG,IAAC,WAAW,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACxC,KAAC,IAAI,IAAS,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,YACtD,IAAI,IADI,CAAC,CAEL,CACR,CAAC,EACD,MAAM,CAAC,SAAS,IAAI,KAAC,IAAI,IAAC,QAAQ,0BAAW,IAC1C,CACP,IACG,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ToolCall.js","sourceRoot":"","sources":["../../../src/tui/components/ToolCall.tsx"],"names":[],"mappings":"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"}
@@ -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;yBAUU,MAAM;cAhBpC,WAAW,EAAE;gBACX,OAAO;eACR,MAAM;wBACG,YAAY,EAAE;EAgJnC"}
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"}
@@ -7,13 +7,10 @@ export function useChat(app) {
7
7
  streamingToolCalls: [],
8
8
  });
9
9
  const processingRef = useRef(false);
10
- const abortRef = useRef(false);
11
10
  const sendMessage = useCallback((input) => {
12
11
  if (processingRef.current)
13
12
  return;
14
13
  processingRef.current = true;
15
- abortRef.current = false;
16
- // Add user message
17
14
  setState(prev => ({
18
15
  ...prev,
19
16
  messages: [...prev.messages, { role: 'user', content: input }],
@@ -22,15 +19,14 @@ export function useChat(app) {
22
19
  streamingToolCalls: [],
23
20
  }));
24
21
  app.session.addMessage('user', input);
25
- // Process stream in background (non-blocking)
26
22
  const stream = app.streamResponse();
27
23
  let fullContent = '';
28
24
  let currentToolCalls = [];
25
+ let lastUpdateTime = 0;
26
+ const THROTTLE_MS = 50; // Update UI at most every 50ms
29
27
  const processStream = async () => {
30
28
  try {
31
29
  for await (const chunk of stream) {
32
- if (abortRef.current)
33
- break;
34
30
  if (chunk.includes('@@TOOL@@')) {
35
31
  const parts = chunk.split('\n');
36
32
  for (const part of parts) {
@@ -63,21 +59,24 @@ export function useChat(app) {
63
59
  }
64
60
  catch {
65
61
  fullContent += part;
66
- setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
67
62
  }
68
63
  }
69
64
  else if (part) {
70
65
  fullContent += part;
71
- setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
72
66
  }
73
67
  }
74
68
  }
75
69
  else {
76
70
  fullContent += chunk;
71
+ }
72
+ // Throttle UI updates
73
+ const now = Date.now();
74
+ if (now - lastUpdateTime >= THROTTLE_MS) {
75
+ lastUpdateTime = now;
77
76
  setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
78
77
  }
79
78
  }
80
- // Finalize
79
+ // Final update
81
80
  if (fullContent.trim() || currentToolCalls.length > 0) {
82
81
  app.session.addMessage('assistant', fullContent);
83
82
  }
@@ -102,15 +101,14 @@ export function useChat(app) {
102
101
  catch (error) {
103
102
  const msg = error.message || String(error);
104
103
  let errorMsg = `Error: ${msg}`;
105
- // Detect API auth/quota errors
106
104
  if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
107
- errorMsg = `❌ API key invalid or expired.\n\nRun \`gfcode init\` to reconfigure.`;
105
+ errorMsg = `❌ API key invalid. Run \`gfcode init\` to reconfigure.`;
108
106
  }
109
107
  else if (msg.includes('429') || msg.includes('rate limit') || msg.includes('quota')) {
110
- errorMsg = `❌ Rate limit or quota exceeded.\n\nWait a moment or run \`gfcode init\` to switch provider.`;
108
+ errorMsg = `❌ Rate limit exceeded. Wait or run \`gfcode init\` to switch provider.`;
111
109
  }
112
110
  else if (msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
113
- errorMsg = `❌ Cannot connect to API server.\n\nCheck your network or run \`gfcode init\` to change base URL.`;
111
+ errorMsg = `❌ Cannot connect. Check network or run \`gfcode init\`.`;
114
112
  }
115
113
  setState(prev => ({
116
114
  ...prev,
@@ -128,12 +126,8 @@ export function useChat(app) {
128
126
  }
129
127
  processingRef.current = false;
130
128
  };
131
- // Start processing without blocking
132
129
  processStream();
133
130
  }, [app]);
134
- return {
135
- ...state,
136
- sendMessage,
137
- };
131
+ return { ...state, sendMessage };
138
132
  }
139
133
  //# sourceMappingURL=useChat.js.map
@@ -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.8.4",
3
+ "version": "0.9.1",
4
4
  "description": "Thatgfsj Code - AI Coding Assistant",
5
5
  "main": "dist/cmd/index.js",
6
6
  "type": "module",
@@ -33,6 +33,7 @@
33
33
  "marked": "^15.0.12",
34
34
  "marked-terminal": "^7.3.0",
35
35
  "ora": "^7.0.1",
36
+ "playwright": "^1.61.1",
36
37
  "react": "^19.2.7",
37
38
  "readline": "^1.3.0"
38
39
  },
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.8.4')
31
+ .version('0.9.1')
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')
@@ -15,27 +15,27 @@ interface Props {
15
15
  width?: number;
16
16
  }
17
17
 
18
- function UserMessage({ content, width }: { content: string; width?: number }) {
18
+ function UserMessage({ content }: { content: string }) {
19
19
  return (
20
- <Box borderStyle="round" borderLeft borderColor="#06B6D4" paddingLeft={1} marginBottom={1}>
21
- <Box flexDirection="column" width={width ? width - 4 : undefined}>
22
- <Text bold color="#06B6D4">You</Text>
20
+ <Box flexDirection="column" marginBottom={1} paddingLeft={1}>
21
+ <Text bold color="#06B6D4">You</Text>
22
+ <Box paddingLeft={2}>
23
23
  <Text>{content}</Text>
24
24
  </Box>
25
25
  </Box>
26
26
  );
27
27
  }
28
28
 
29
- function AssistantMessage({ content, toolCalls, width }: { content: string; toolCalls?: ToolCallData[]; width?: number }) {
29
+ function AssistantMessage({ content, toolCalls }: { content: string; toolCalls?: ToolCallData[] }) {
30
30
  return (
31
31
  <Box flexDirection="column" marginBottom={1}>
32
32
  {toolCalls && toolCalls.map((tc, i) => (
33
- <ToolCall key={i} tool={tc} width={width} />
33
+ <ToolCall key={i} tool={tc} />
34
34
  ))}
35
35
  {content && (
36
- <Box borderStyle="round" borderLeft borderColor="#22D3EE" paddingLeft={1}>
37
- <Box flexDirection="column" width={width ? width - 4 : undefined}>
38
- <Text bold color="#22D3EE">AI</Text>
36
+ <Box flexDirection="column" paddingLeft={1}>
37
+ <Text bold color="#22D3EE">AI</Text>
38
+ <Box paddingLeft={2}>
39
39
  <Markdown content={content} />
40
40
  </Box>
41
41
  </Box>
@@ -44,11 +44,11 @@ function AssistantMessage({ content, toolCalls, width }: { content: string; tool
44
44
  );
45
45
  }
46
46
 
47
- export const ChatMessage = React.memo(function ChatMessage({ message, width }: Props) {
47
+ export const ChatMessage = React.memo(function ChatMessage({ message }: Props) {
48
48
  if (message.role === 'user') {
49
- return <UserMessage content={message.content} width={width} />;
49
+ return <UserMessage content={message.content} />;
50
50
  }
51
- return <AssistantMessage content={message.content} toolCalls={message.toolCalls} width={width} />;
51
+ return <AssistantMessage content={message.content} toolCalls={message.toolCalls} />;
52
52
  });
53
53
 
54
54
  export type { MessageData };
@@ -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.8.4</Text>
17
+ <Text dimColor> v0.9.1</Text>
18
18
  </Box>
19
19
  <Box>
20
20
  <Text color="#06B6D4" bold> {provider} </Text>
@@ -14,7 +14,7 @@ interface Props {
14
14
  width?: number;
15
15
  }
16
16
 
17
- function formatToolParams(name: string, args: string): string {
17
+ function formatToolName(name: string, args: string): string {
18
18
  try {
19
19
  const obj = JSON.parse(args);
20
20
  switch (name) {
@@ -23,48 +23,45 @@ function formatToolParams(name: string, args: string): string {
23
23
  const path = (obj.path || '').replace(/.*[/\\]/, '');
24
24
  return `${action} ${path || obj.path || ''}`;
25
25
  }
26
- case 'shell': return obj.command || '';
26
+ case 'shell': return obj.command?.slice(0, 60) || '';
27
27
  case 'git': return obj.command || '';
28
28
  case 'search': return obj.query || obj.pattern || '';
29
29
  case 'nwt': return obj.action || '';
30
- default: {
31
- const first = Object.entries(obj)[0];
32
- if (!first) return '';
33
- const val = typeof first[1] === 'string' && first[1].length > 40
34
- ? first[1].slice(0, 40) + '...'
35
- : JSON.stringify(first[1]);
36
- return `${first[0]}=${val}`;
37
- }
30
+ default: return Object.keys(obj).slice(0, 2).join(', ');
38
31
  }
39
32
  } catch {
40
- return args.length > 50 ? args.slice(0, 50) + '...' : args;
33
+ return '';
41
34
  }
42
35
  }
43
36
 
44
- function formatResult(output: string, maxLines = 10): { text: string; truncated: boolean } {
37
+ function truncateOutput(output: string, maxLines = 8): { text: string; truncated: boolean } {
45
38
  const lines = output.split('\n');
46
39
  if (lines.length <= maxLines) return { text: output, truncated: false };
47
40
  return { text: lines.slice(0, maxLines).join('\n'), truncated: true };
48
41
  }
49
42
 
50
- export function ToolCall({ tool, width }: Props) {
51
- const params = formatToolParams(tool.name, tool.args);
52
- const result = tool.result ? formatResult(tool.result) : null;
43
+ export function ToolCall({ tool }: Props) {
44
+ const label = formatToolName(tool.name, tool.args);
45
+ const result = tool.result ? truncateOutput(tool.result) : null;
53
46
 
54
47
  return (
55
- <Box borderStyle="round" borderLeft borderColor="#06B6D4" paddingLeft={1} flexDirection="column" marginBottom={0}>
48
+ <Box flexDirection="column" marginBottom={0} paddingLeft={1}>
49
+ {/* Tool header */}
56
50
  <Box>
57
- <Text color="#06B6D4" bold>⚙ {tool.name}: </Text>
58
- <Text color="#94A3B8">{params}</Text>
51
+ <Text color="#06B6D4" bold>⚙ </Text>
52
+ <Text color="#06B6D4">{tool.name}</Text>
53
+ {label && <Text color="#64748B"> {label}</Text>}
59
54
  </Box>
55
+
56
+ {/* Result */}
60
57
  {result && (
61
- <Box paddingLeft={1} flexDirection="column">
58
+ <Box paddingLeft={2} flexDirection="column">
62
59
  {result.text.split('\n').map((line, i) => (
63
- <Text key={i} color={tool.isError ? '#EF4444' : '#64748B'}>
60
+ <Text key={i} color={tool.isError ? '#EF4444' : '#64748B'} wrap="truncate">
64
61
  {line}
65
62
  </Text>
66
63
  ))}
67
- {result.truncated && <Text dimColor>...</Text>}
64
+ {result.truncated && <Text dimColor> ...</Text>}
68
65
  </Box>
69
66
  )}
70
67
  </Box>
@@ -1,4 +1,4 @@
1
- import { useState, useCallback, useRef, useEffect } from 'react';
1
+ import { useState, useCallback, useRef } from 'react';
2
2
  import type { MessageData } from '../components/ChatMessage.js';
3
3
  import type { ToolCallData } from '../components/ToolCall.js';
4
4
  import type { App } from '../../app/index.js';
@@ -18,14 +18,11 @@ export function useChat(app: App) {
18
18
  streamingToolCalls: [],
19
19
  });
20
20
  const processingRef = useRef(false);
21
- const abortRef = useRef(false);
22
21
 
23
22
  const sendMessage = useCallback((input: string) => {
24
23
  if (processingRef.current) return;
25
24
  processingRef.current = true;
26
- abortRef.current = false;
27
25
 
28
- // Add user message
29
26
  setState(prev => ({
30
27
  ...prev,
31
28
  messages: [...prev.messages, { role: 'user', content: input }],
@@ -36,16 +33,15 @@ export function useChat(app: App) {
36
33
 
37
34
  app.session.addMessage('user', input);
38
35
 
39
- // Process stream in background (non-blocking)
40
36
  const stream = app.streamResponse();
41
37
  let fullContent = '';
42
38
  let currentToolCalls: ToolCallData[] = [];
39
+ let lastUpdateTime = 0;
40
+ const THROTTLE_MS = 50; // Update UI at most every 50ms
43
41
 
44
42
  const processStream = async () => {
45
43
  try {
46
44
  for await (const chunk of stream) {
47
- if (abortRef.current) break;
48
-
49
45
  if (chunk.includes('@@TOOL@@')) {
50
46
  const parts = chunk.split('\n');
51
47
  for (const part of parts) {
@@ -76,20 +72,24 @@ export function useChat(app: App) {
76
72
  }
77
73
  } catch {
78
74
  fullContent += part;
79
- setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
80
75
  }
81
76
  } else if (part) {
82
77
  fullContent += part;
83
- setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
84
78
  }
85
79
  }
86
80
  } else {
87
81
  fullContent += chunk;
82
+ }
83
+
84
+ // Throttle UI updates
85
+ const now = Date.now();
86
+ if (now - lastUpdateTime >= THROTTLE_MS) {
87
+ lastUpdateTime = now;
88
88
  setState(prev => ({ ...prev, isThinking: false, streaming: fullContent }));
89
89
  }
90
90
  }
91
91
 
92
- // Finalize
92
+ // Final update
93
93
  if (fullContent.trim() || currentToolCalls.length > 0) {
94
94
  app.session.addMessage('assistant', fullContent);
95
95
  }
@@ -116,13 +116,12 @@ export function useChat(app: App) {
116
116
  const msg = error.message || String(error);
117
117
  let errorMsg = `Error: ${msg}`;
118
118
 
119
- // Detect API auth/quota errors
120
119
  if (msg.includes('401') || msg.includes('403') || msg.includes('Unauthorized')) {
121
- errorMsg = `❌ API key invalid or expired.\n\nRun \`gfcode init\` to reconfigure.`;
120
+ errorMsg = `❌ API key invalid. Run \`gfcode init\` to reconfigure.`;
122
121
  } else if (msg.includes('429') || msg.includes('rate limit') || msg.includes('quota')) {
123
- errorMsg = `❌ Rate limit or quota exceeded.\n\nWait a moment or run \`gfcode init\` to switch provider.`;
122
+ errorMsg = `❌ Rate limit exceeded. Wait or run \`gfcode init\` to switch provider.`;
124
123
  } else if (msg.includes('ECONNREFUSED') || msg.includes('ENOTFOUND')) {
125
- errorMsg = `❌ Cannot connect to API server.\n\nCheck your network or run \`gfcode init\` to change base URL.`;
124
+ errorMsg = `❌ Cannot connect. Check network or run \`gfcode init\`.`;
126
125
  }
127
126
 
128
127
  setState(prev => ({
@@ -143,12 +142,8 @@ export function useChat(app: App) {
143
142
  processingRef.current = false;
144
143
  };
145
144
 
146
- // Start processing without blocking
147
145
  processStream();
148
146
  }, [app]);
149
147
 
150
- return {
151
- ...state,
152
- sendMessage,
153
- };
148
+ return { ...state, sendMessage };
154
149
  }