kimaki 0.3.0 → 0.3.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/discordBot.js +46 -34
- package/package.json +2 -2
- package/src/discordBot.ts +42 -34
package/dist/discordBot.js
CHANGED
|
@@ -718,22 +718,29 @@ function formatPart(part) {
|
|
|
718
718
|
return `▪︎ thinking: ${escapeDiscordFormatting(part.text || '')}`;
|
|
719
719
|
case 'tool':
|
|
720
720
|
if (part.state.status === 'completed' || part.state.status === 'error') {
|
|
721
|
-
// console.log(part)
|
|
722
|
-
// Escape triple backticks so Discord does not break code blocks
|
|
723
721
|
let language = '';
|
|
724
722
|
let outputToDisplay = '';
|
|
723
|
+
let summaryText = '';
|
|
725
724
|
if (part.tool === 'bash') {
|
|
726
|
-
|
|
727
|
-
part.state.
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
725
|
+
const output = part.state.status === 'completed'
|
|
726
|
+
? part.state.output
|
|
727
|
+
: part.state.error;
|
|
728
|
+
const lines = (output || '').split('\n').filter((l) => l.trim());
|
|
729
|
+
summaryText = `(${lines.length} line${lines.length === 1 ? '' : 's'})`;
|
|
731
730
|
}
|
|
732
|
-
if (part.tool === 'edit') {
|
|
733
|
-
|
|
734
|
-
|
|
731
|
+
else if (part.tool === 'edit') {
|
|
732
|
+
const newString = part.state.input?.newString || '';
|
|
733
|
+
const oldString = part.state.input?.oldString || '';
|
|
734
|
+
const added = newString.split('\n').length;
|
|
735
|
+
const removed = oldString.split('\n').length;
|
|
736
|
+
summaryText = `(+${added}-${removed})`;
|
|
735
737
|
}
|
|
736
|
-
if (part.tool === '
|
|
738
|
+
else if (part.tool === 'write') {
|
|
739
|
+
const content = part.state.input?.content || '';
|
|
740
|
+
const lines = content.split('\n').length;
|
|
741
|
+
summaryText = `(${lines} line${lines === 1 ? '' : 's'})`;
|
|
742
|
+
}
|
|
743
|
+
else if (part.tool === 'todowrite') {
|
|
737
744
|
const todos = part.state.input?.todos || [];
|
|
738
745
|
outputToDisplay = todos
|
|
739
746
|
.map((todo) => {
|
|
@@ -756,20 +763,27 @@ function formatPart(part) {
|
|
|
756
763
|
})
|
|
757
764
|
.filter(Boolean)
|
|
758
765
|
.join('\n');
|
|
759
|
-
language = '';
|
|
760
766
|
}
|
|
761
|
-
if (part.tool === '
|
|
762
|
-
|
|
763
|
-
|
|
767
|
+
else if (part.tool === 'webfetch') {
|
|
768
|
+
const url = part.state.input?.url || '';
|
|
769
|
+
const urlWithoutProtocol = url.replace(/^https?:\/\//, '');
|
|
770
|
+
summaryText = urlWithoutProtocol ? `(${urlWithoutProtocol})` : '';
|
|
771
|
+
}
|
|
772
|
+
else if (part.state.input) {
|
|
773
|
+
const inputFields = Object.entries(part.state.input)
|
|
774
|
+
.map(([key, value]) => {
|
|
775
|
+
if (value === null || value === undefined)
|
|
776
|
+
return null;
|
|
777
|
+
const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
|
|
778
|
+
const truncatedValue = stringValue.length > 100 ? stringValue.slice(0, 100) + '…' : stringValue;
|
|
779
|
+
return `${key}: ${truncatedValue}`;
|
|
780
|
+
})
|
|
781
|
+
.filter(Boolean);
|
|
782
|
+
if (inputFields.length > 0) {
|
|
783
|
+
outputToDisplay = inputFields.join('\n');
|
|
784
|
+
}
|
|
764
785
|
}
|
|
765
|
-
outputToDisplay =
|
|
766
|
-
outputToDisplay.length > 500
|
|
767
|
-
? outputToDisplay.slice(0, 497) + `…`
|
|
768
|
-
: outputToDisplay;
|
|
769
|
-
// Escape Discord formatting characters that could break code blocks
|
|
770
|
-
outputToDisplay = escapeDiscordFormatting(outputToDisplay);
|
|
771
786
|
let toolTitle = part.state.status === 'completed' ? part.state.title || '' : 'error';
|
|
772
|
-
// Escape backticks in the title before wrapping in backticks
|
|
773
787
|
if (toolTitle) {
|
|
774
788
|
toolTitle = `\`${escapeInlineCode(toolTitle)}\``;
|
|
775
789
|
}
|
|
@@ -778,19 +792,10 @@ function formatPart(part) {
|
|
|
778
792
|
: part.state.status === 'error'
|
|
779
793
|
? '⨯'
|
|
780
794
|
: '';
|
|
781
|
-
const title = `${icon} ${part.tool} ${toolTitle}`;
|
|
795
|
+
const title = `${icon} ${part.tool} ${toolTitle} ${summaryText}`;
|
|
782
796
|
let text = title;
|
|
783
797
|
if (outputToDisplay) {
|
|
784
|
-
|
|
785
|
-
if (part.tool === 'todowrite') {
|
|
786
|
-
text += '\n\n' + outputToDisplay;
|
|
787
|
-
}
|
|
788
|
-
else {
|
|
789
|
-
if (language.startsWith('.')) {
|
|
790
|
-
language = language.slice(1);
|
|
791
|
-
}
|
|
792
|
-
text += '\n\n```' + language + '\n' + outputToDisplay + '\n```';
|
|
793
|
-
}
|
|
798
|
+
text += '\n\n' + outputToDisplay;
|
|
794
799
|
}
|
|
795
800
|
return text;
|
|
796
801
|
}
|
|
@@ -1168,7 +1173,14 @@ async function handleOpencodeSession(prompt, thread, projectDirectory, originalM
|
|
|
1168
1173
|
discordLogger.log(`Could not update reaction:`, e);
|
|
1169
1174
|
}
|
|
1170
1175
|
}
|
|
1171
|
-
|
|
1176
|
+
// Always log the error's constructor name (if any) and make error reporting more readable
|
|
1177
|
+
const errorName = error && typeof error === 'object' && 'constructor' in error && error.constructor && typeof error.constructor.name === 'string'
|
|
1178
|
+
? error.constructor.name
|
|
1179
|
+
: typeof error;
|
|
1180
|
+
const errorMsg = error instanceof Error
|
|
1181
|
+
? (error.stack || error.message)
|
|
1182
|
+
: String(error);
|
|
1183
|
+
await sendThreadMessage(thread, `✗ Unexpected bot Error: [${errorName}]\n${errorMsg}`);
|
|
1172
1184
|
}
|
|
1173
1185
|
}
|
|
1174
1186
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "kimaki",
|
|
3
3
|
"module": "index.ts",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.1",
|
|
6
6
|
"repository": "https://github.com/remorses/kimaki",
|
|
7
7
|
"bin": "bin.js",
|
|
8
8
|
"files": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"zod": "^4.0.17"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
|
-
"dev": "pnpm tsc &&
|
|
48
|
+
"dev": "pnpm tsc && tsx --env-file .env src/cli.ts",
|
|
49
49
|
"dev:bun": "DEBUG=1 bun --env-file .env src/cli.ts",
|
|
50
50
|
"test": "tsx scripts/test-opencode.ts",
|
|
51
51
|
"watch": "tsx scripts/watch-session.ts",
|
package/src/discordBot.ts
CHANGED
|
@@ -954,22 +954,28 @@ function formatPart(part: Part): string {
|
|
|
954
954
|
return `▪︎ thinking: ${escapeDiscordFormatting(part.text || '')}`
|
|
955
955
|
case 'tool':
|
|
956
956
|
if (part.state.status === 'completed' || part.state.status === 'error') {
|
|
957
|
-
// console.log(part)
|
|
958
|
-
// Escape triple backticks so Discord does not break code blocks
|
|
959
957
|
let language = ''
|
|
960
958
|
let outputToDisplay = ''
|
|
959
|
+
let summaryText = ''
|
|
960
|
+
|
|
961
961
|
if (part.tool === 'bash') {
|
|
962
|
-
|
|
962
|
+
const output =
|
|
963
963
|
part.state.status === 'completed'
|
|
964
964
|
? part.state.output
|
|
965
965
|
: part.state.error
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
if (part.tool === 'edit') {
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
966
|
+
const lines = (output || '').split('\n').filter((l) => l.trim())
|
|
967
|
+
summaryText = `(${lines.length} line${lines.length === 1 ? '' : 's'})`
|
|
968
|
+
} else if (part.tool === 'edit') {
|
|
969
|
+
const newString = (part.state.input?.newString as string) || ''
|
|
970
|
+
const oldString = (part.state.input?.oldString as string) || ''
|
|
971
|
+
const added = newString.split('\n').length
|
|
972
|
+
const removed = oldString.split('\n').length
|
|
973
|
+
summaryText = `(+${added}-${removed})`
|
|
974
|
+
} else if (part.tool === 'write') {
|
|
975
|
+
const content = (part.state.input?.content as string) || ''
|
|
976
|
+
const lines = content.split('\n').length
|
|
977
|
+
summaryText = `(${lines} line${lines === 1 ? '' : 's'})`
|
|
978
|
+
} else if (part.tool === 'todowrite') {
|
|
973
979
|
const todos =
|
|
974
980
|
(part.state.input?.todos as {
|
|
975
981
|
content: string
|
|
@@ -996,23 +1002,26 @@ function formatPart(part: Part): string {
|
|
|
996
1002
|
})
|
|
997
1003
|
.filter(Boolean)
|
|
998
1004
|
.join('\n')
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1005
|
+
} else if (part.tool === 'webfetch') {
|
|
1006
|
+
const url = (part.state.input?.url as string) || ''
|
|
1007
|
+
const urlWithoutProtocol = url.replace(/^https?:\/\//, '')
|
|
1008
|
+
summaryText = urlWithoutProtocol ? `(${urlWithoutProtocol})` : ''
|
|
1009
|
+
} else if (part.state.input) {
|
|
1010
|
+
const inputFields = Object.entries(part.state.input)
|
|
1011
|
+
.map(([key, value]) => {
|
|
1012
|
+
if (value === null || value === undefined) return null
|
|
1013
|
+
const stringValue = typeof value === 'string' ? value : JSON.stringify(value)
|
|
1014
|
+
const truncatedValue = stringValue.length > 100 ? stringValue.slice(0, 100) + '…' : stringValue
|
|
1015
|
+
return `${key}: ${truncatedValue}`
|
|
1016
|
+
})
|
|
1017
|
+
.filter(Boolean)
|
|
1018
|
+
if (inputFields.length > 0) {
|
|
1019
|
+
outputToDisplay = inputFields.join('\n')
|
|
1020
|
+
}
|
|
1004
1021
|
}
|
|
1005
|
-
outputToDisplay =
|
|
1006
|
-
outputToDisplay.length > 500
|
|
1007
|
-
? outputToDisplay.slice(0, 497) + `…`
|
|
1008
|
-
: outputToDisplay
|
|
1009
|
-
|
|
1010
|
-
// Escape Discord formatting characters that could break code blocks
|
|
1011
|
-
outputToDisplay = escapeDiscordFormatting(outputToDisplay)
|
|
1012
1022
|
|
|
1013
1023
|
let toolTitle =
|
|
1014
1024
|
part.state.status === 'completed' ? part.state.title || '' : 'error'
|
|
1015
|
-
// Escape backticks in the title before wrapping in backticks
|
|
1016
1025
|
if (toolTitle) {
|
|
1017
1026
|
toolTitle = `\`${escapeInlineCode(toolTitle)}\``
|
|
1018
1027
|
}
|
|
@@ -1022,20 +1031,12 @@ function formatPart(part: Part): string {
|
|
|
1022
1031
|
: part.state.status === 'error'
|
|
1023
1032
|
? '⨯'
|
|
1024
1033
|
: ''
|
|
1025
|
-
const title = `${icon} ${part.tool} ${toolTitle}`
|
|
1034
|
+
const title = `${icon} ${part.tool} ${toolTitle} ${summaryText}`
|
|
1026
1035
|
|
|
1027
1036
|
let text = title
|
|
1028
1037
|
|
|
1029
1038
|
if (outputToDisplay) {
|
|
1030
|
-
|
|
1031
|
-
if (part.tool === 'todowrite') {
|
|
1032
|
-
text += '\n\n' + outputToDisplay
|
|
1033
|
-
} else {
|
|
1034
|
-
if (language.startsWith('.')) {
|
|
1035
|
-
language = language.slice(1)
|
|
1036
|
-
}
|
|
1037
|
-
text += '\n\n```' + language + '\n' + outputToDisplay + '\n```'
|
|
1038
|
-
}
|
|
1039
|
+
text += '\n\n' + outputToDisplay
|
|
1039
1040
|
}
|
|
1040
1041
|
return text
|
|
1041
1042
|
}
|
|
@@ -1513,9 +1514,16 @@ async function handleOpencodeSession(
|
|
|
1513
1514
|
discordLogger.log(`Could not update reaction:`, e)
|
|
1514
1515
|
}
|
|
1515
1516
|
}
|
|
1517
|
+
// Always log the error's constructor name (if any) and make error reporting more readable
|
|
1518
|
+
const errorName = error && typeof error === 'object' && 'constructor' in error && error.constructor && typeof error.constructor.name === 'string'
|
|
1519
|
+
? error.constructor.name
|
|
1520
|
+
: typeof error
|
|
1521
|
+
const errorMsg = error instanceof Error
|
|
1522
|
+
? (error.stack || error.message)
|
|
1523
|
+
: String(error)
|
|
1516
1524
|
await sendThreadMessage(
|
|
1517
1525
|
thread,
|
|
1518
|
-
`✗ Unexpected bot Error: ${
|
|
1526
|
+
`✗ Unexpected bot Error: [${errorName}]\n${errorMsg}`,
|
|
1519
1527
|
)
|
|
1520
1528
|
}
|
|
1521
1529
|
}
|