kimaki 0.2.1 → 0.3.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.
@@ -18,6 +18,10 @@ import { transcribeAudio } from './voice.js';
18
18
  import { extractTagsArrays, extractNonXmlContent } from './xml.js';
19
19
  import prettyMilliseconds from 'pretty-ms';
20
20
  import { createLogger } from './logger.js';
21
+ import { isAbortError } from './utils.js';
22
+ import { setGlobalDispatcher, Agent } from 'undici';
23
+ // disables the automatic 5 minutes abort after no body
24
+ setGlobalDispatcher(new Agent({ headersTimeout: 0, bodyTimeout: 0 }));
21
25
  const discordLogger = createLogger('DISCORD');
22
26
  const voiceLogger = createLogger('VOICE');
23
27
  const opencodeLogger = createLogger('OPENCODE');
@@ -615,6 +619,41 @@ export async function initializeOpencodeForDirectory(directory) {
615
619
  cwd: directory,
616
620
  env: {
617
621
  ...process.env,
622
+ OPENCODE_CONFIG_CONTENT: JSON.stringify({
623
+ $schema: 'https://opencode.ai/config.json',
624
+ lsp: {
625
+ typescript: { disabled: true },
626
+ eslint: { disabled: true },
627
+ gopls: { disabled: true },
628
+ 'ruby-lsp': { disabled: true },
629
+ pyright: { disabled: true },
630
+ 'elixir-ls': { disabled: true },
631
+ zls: { disabled: true },
632
+ csharp: { disabled: true },
633
+ vue: { disabled: true },
634
+ rust: { disabled: true },
635
+ clangd: { disabled: true },
636
+ svelte: { disabled: true },
637
+ },
638
+ formatter: {
639
+ prettier: { disabled: true },
640
+ biome: { disabled: true },
641
+ gofmt: { disabled: true },
642
+ mix: { disabled: true },
643
+ zig: { disabled: true },
644
+ 'clang-format': { disabled: true },
645
+ ktlint: { disabled: true },
646
+ ruff: { disabled: true },
647
+ rubocop: { disabled: true },
648
+ standardrb: { disabled: true },
649
+ htmlbeautifier: { disabled: true },
650
+ },
651
+ permission: {
652
+ edit: 'allow',
653
+ bash: 'allow',
654
+ webfetch: 'allow',
655
+ },
656
+ }),
618
657
  OPENCODE_PORT: port.toString(),
619
658
  },
620
659
  });
@@ -1041,8 +1080,7 @@ async function handleOpencodeSession(prompt, thread, projectDirectory, originalM
1041
1080
  }
1042
1081
  }
1043
1082
  catch (e) {
1044
- if (e instanceof Error && e.name === 'AbortError') {
1045
- // Ignore abort controller errors as requested
1083
+ if (isAbortError(e, abortController.signal)) {
1046
1084
  sessionLogger.log('AbortController aborted event handling (normal exit)');
1047
1085
  return;
1048
1086
  }
@@ -1118,7 +1156,7 @@ async function handleOpencodeSession(prompt, thread, projectDirectory, originalM
1118
1156
  }
1119
1157
  catch (error) {
1120
1158
  sessionLogger.error(`ERROR: Failed to send prompt:`, error);
1121
- if (!(error instanceof Error && error.name === 'AbortError')) {
1159
+ if (!isAbortError(error, abortController.signal)) {
1122
1160
  abortController.abort('error');
1123
1161
  if (originalMessage) {
1124
1162
  try {
package/dist/utils.js CHANGED
@@ -30,7 +30,7 @@ export function generateBotInstallUrl({ clientId, permissions = [
30
30
  }
31
31
  export function deduplicateByKey(arr, keyFn) {
32
32
  const seen = new Set();
33
- return arr.filter(item => {
33
+ return arr.filter((item) => {
34
34
  const key = keyFn(item);
35
35
  if (seen.has(key)) {
36
36
  return false;
@@ -39,3 +39,12 @@ export function deduplicateByKey(arr, keyFn) {
39
39
  return true;
40
40
  });
41
41
  }
42
+ export function isAbortError(error, signal) {
43
+ return (error instanceof Error &&
44
+ (error.name === 'AbortError' ||
45
+ error.name === 'Aborterror' ||
46
+ error.name === 'aborterror' ||
47
+ error.name.toLowerCase() === 'aborterror' ||
48
+ error.message?.includes('aborted') ||
49
+ (signal?.aborted ?? false)));
50
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "kimaki",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.2.1",
5
+ "version": "0.3.0",
6
6
  "repository": "https://github.com/remorses/kimaki",
7
7
  "bin": "bin.js",
8
8
  "files": [
@@ -41,6 +41,7 @@
41
41
  "pretty-ms": "^9.3.0",
42
42
  "prism-media": "^1.3.5",
43
43
  "string-dedent": "^3.0.2",
44
+ "undici": "^7.16.0",
44
45
  "zod": "^4.0.17"
45
46
  },
46
47
  "scripts": {
package/src/discordBot.ts CHANGED
@@ -2,6 +2,7 @@ import {
2
2
  createOpencodeClient,
3
3
  type OpencodeClient,
4
4
  type Part,
5
+ type Config,
5
6
  } from '@opencode-ai/sdk'
6
7
 
7
8
  import { createGenAIWorker, type GenAIWorker } from './genai-worker-wrapper.js'
@@ -45,6 +46,10 @@ import { extractTagsArrays, extractNonXmlContent } from './xml.js'
45
46
  import prettyMilliseconds from 'pretty-ms'
46
47
  import type { Session } from '@google/genai'
47
48
  import { createLogger } from './logger.js'
49
+ import { isAbortError } from './utils.js'
50
+ import { setGlobalDispatcher, Agent } from 'undici'
51
+ // disables the automatic 5 minutes abort after no body
52
+ setGlobalDispatcher(new Agent({ headersTimeout: 0, bodyTimeout: 0 }))
48
53
 
49
54
  const discordLogger = createLogger('DISCORD')
50
55
  const voiceLogger = createLogger('VOICE')
@@ -833,6 +838,41 @@ export async function initializeOpencodeForDirectory(directory: string) {
833
838
  cwd: directory,
834
839
  env: {
835
840
  ...process.env,
841
+ OPENCODE_CONFIG_CONTENT: JSON.stringify({
842
+ $schema: 'https://opencode.ai/config.json',
843
+ lsp: {
844
+ typescript: { disabled: true },
845
+ eslint: { disabled: true },
846
+ gopls: { disabled: true },
847
+ 'ruby-lsp': { disabled: true },
848
+ pyright: { disabled: true },
849
+ 'elixir-ls': { disabled: true },
850
+ zls: { disabled: true },
851
+ csharp: { disabled: true },
852
+ vue: { disabled: true },
853
+ rust: { disabled: true },
854
+ clangd: { disabled: true },
855
+ svelte: { disabled: true },
856
+ },
857
+ formatter: {
858
+ prettier: { disabled: true },
859
+ biome: { disabled: true },
860
+ gofmt: { disabled: true },
861
+ mix: { disabled: true },
862
+ zig: { disabled: true },
863
+ 'clang-format': { disabled: true },
864
+ ktlint: { disabled: true },
865
+ ruff: { disabled: true },
866
+ rubocop: { disabled: true },
867
+ standardrb: { disabled: true },
868
+ htmlbeautifier: { disabled: true },
869
+ },
870
+ permission: {
871
+ edit: 'allow',
872
+ bash: 'allow',
873
+ webfetch: 'allow',
874
+ },
875
+ } satisfies Config),
836
876
  OPENCODE_PORT: port.toString(),
837
877
  },
838
878
  },
@@ -1364,8 +1404,7 @@ async function handleOpencodeSession(
1364
1404
  }
1365
1405
  }
1366
1406
  } catch (e) {
1367
- if (e instanceof Error && e.name === 'AbortError') {
1368
- // Ignore abort controller errors as requested
1407
+ if (isAbortError(e, abortController.signal)) {
1369
1408
  sessionLogger.log(
1370
1409
  'AbortController aborted event handling (normal exit)',
1371
1410
  )
@@ -1462,7 +1501,7 @@ async function handleOpencodeSession(
1462
1501
  } catch (error) {
1463
1502
  sessionLogger.error(`ERROR: Failed to send prompt:`, error)
1464
1503
 
1465
- if (!(error instanceof Error && error.name === 'AbortError')) {
1504
+ if (!isAbortError(error, abortController.signal)) {
1466
1505
  abortController.abort('error')
1467
1506
 
1468
1507
  if (originalMessage) {
package/src/utils.ts CHANGED
@@ -48,10 +48,9 @@ export function generateBotInstallUrl({
48
48
  return url.toString()
49
49
  }
50
50
 
51
-
52
51
  export function deduplicateByKey<T, K>(arr: T[], keyFn: (item: T) => K): T[] {
53
52
  const seen = new Set<K>()
54
- return arr.filter(item => {
53
+ return arr.filter((item) => {
55
54
  const key = keyFn(item)
56
55
  if (seen.has(key)) {
57
56
  return false
@@ -60,3 +59,18 @@ export function deduplicateByKey<T, K>(arr: T[], keyFn: (item: T) => K): T[] {
60
59
  return true
61
60
  })
62
61
  }
62
+
63
+ export function isAbortError(
64
+ error: unknown,
65
+ signal?: AbortSignal,
66
+ ): error is Error {
67
+ return (
68
+ error instanceof Error &&
69
+ (error.name === 'AbortError' ||
70
+ error.name === 'Aborterror' ||
71
+ error.name === 'aborterror' ||
72
+ error.name.toLowerCase() === 'aborterror' ||
73
+ error.message?.includes('aborted') ||
74
+ (signal?.aborted ?? false))
75
+ )
76
+ }