@kilocode/sdk 7.2.4 → 7.2.6

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/client.js CHANGED
@@ -2,6 +2,31 @@ export * from "./gen/types.gen.js";
2
2
  import { createClient } from "./gen/client/client.gen.js";
3
3
  import { KiloClient } from "./gen/sdk.gen.js";
4
4
  export { KiloClient };
5
+ function pick(value, fallback) {
6
+ if (!value)
7
+ return;
8
+ if (!fallback)
9
+ return value;
10
+ if (value === fallback)
11
+ return fallback;
12
+ if (value === encodeURIComponent(fallback))
13
+ return fallback;
14
+ return value;
15
+ }
16
+ function rewrite(request, directory) {
17
+ if (request.method !== "GET" && request.method !== "HEAD")
18
+ return request;
19
+ const value = pick(request.headers.get("x-kilo-directory"), directory);
20
+ if (!value)
21
+ return request;
22
+ const url = new URL(request.url);
23
+ if (!url.searchParams.has("directory")) {
24
+ url.searchParams.set("directory", value);
25
+ }
26
+ const next = new Request(url.href, request); // kilocode_change
27
+ next.headers.delete("x-kilo-directory");
28
+ return next;
29
+ }
5
30
  export function createKiloClient(config) {
6
31
  if (!config?.fetch) {
7
32
  const customFetch = (req) => {
@@ -30,5 +55,6 @@ export function createKiloClient(config) {
30
55
  ;
31
56
  config.duplex = "half";
32
57
  const client = createClient(config);
58
+ client.interceptors.request.use((request) => rewrite(request, config?.directory));
33
59
  return new KiloClient({ client });
34
60
  }
@@ -0,0 +1,3 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ export declare function stop(proc: ChildProcess): void;
3
+ export declare function bindAbort(proc: ChildProcess, signal?: AbortSignal, onAbort?: () => void): () => void;
@@ -0,0 +1,33 @@
1
+ import { spawnSync } from "node:child_process";
2
+ // Duplicated from `packages/opencode/src/util/process.ts` because the SDK cannot
3
+ // import `opencode` without creating a cycle (`opencode` depends on `@kilocode/sdk`).
4
+ export function stop(proc) {
5
+ if (proc.exitCode !== null || proc.signalCode !== null)
6
+ return;
7
+ if (process.platform === "win32" && proc.pid) {
8
+ const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true });
9
+ if (!out.error && out.status === 0)
10
+ return;
11
+ }
12
+ proc.kill();
13
+ }
14
+ export function bindAbort(proc, signal, onAbort) {
15
+ if (!signal)
16
+ return () => { };
17
+ const abort = () => {
18
+ clear();
19
+ stop(proc);
20
+ onAbort?.();
21
+ };
22
+ const clear = () => {
23
+ signal.removeEventListener("abort", abort);
24
+ proc.off("exit", clear);
25
+ proc.off("error", clear);
26
+ };
27
+ signal.addEventListener("abort", abort, { once: true });
28
+ proc.on("exit", clear);
29
+ proc.on("error", clear);
30
+ if (signal.aborted)
31
+ abort();
32
+ return clear;
33
+ }
package/dist/server.js CHANGED
@@ -1,4 +1,5 @@
1
- import { spawn } from "node:child_process";
1
+ import launch from "cross-spawn";
2
+ import { stop, bindAbort } from "./process.js";
2
3
  // kilocode_change start - Merge existing KILO_CONFIG_CONTENT with new config
3
4
  // This preserves Kilocode-injected modes when spawning nested CLI instances
4
5
  function mergeConfig(existing, incoming) {
@@ -39,22 +40,25 @@ export async function createKiloServer(options) {
39
40
  const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`];
40
41
  if (options.config?.logLevel)
41
42
  args.push(`--log-level=${options.config.logLevel}`);
42
- // kilocode_change start
43
- const proc = spawn(`kilo`, args, {
44
- // kilocode_change end
45
- signal: options.signal,
46
- windowsHide: true,
43
+ const proc = launch(`kilo`, args, {
44
+ // kilocode_change
47
45
  env: {
48
46
  ...process.env,
49
47
  KILO_CONFIG_CONTENT: buildConfigEnv(options.config), // kilocode_change
50
48
  },
51
49
  });
50
+ let clear = () => { };
52
51
  const url = await new Promise((resolve, reject) => {
53
52
  const id = setTimeout(() => {
53
+ clear();
54
+ stop(proc);
54
55
  reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`));
55
56
  }, options.timeout);
56
57
  let output = "";
58
+ let resolved = false;
57
59
  proc.stdout?.on("data", (chunk) => {
60
+ if (resolved)
61
+ return;
58
62
  output += chunk.toString();
59
63
  const lines = output.split("\n");
60
64
  for (const line of lines) {
@@ -63,9 +67,14 @@ export async function createKiloServer(options) {
63
67
  // kilocode_change end
64
68
  const match = line.match(/on\s+(https?:\/\/[^\s]+)/);
65
69
  if (!match) {
66
- throw new Error(`Failed to parse server url from output: ${line}`);
70
+ clear();
71
+ stop(proc);
72
+ clearTimeout(id);
73
+ reject(new Error(`Failed to parse server url from output: ${line}`));
74
+ return;
67
75
  }
68
76
  clearTimeout(id);
77
+ resolved = true;
69
78
  resolve(match[1]);
70
79
  return;
71
80
  }
@@ -86,17 +95,16 @@ export async function createKiloServer(options) {
86
95
  clearTimeout(id);
87
96
  reject(error);
88
97
  });
89
- if (options.signal) {
90
- options.signal.addEventListener("abort", () => {
91
- clearTimeout(id);
92
- reject(new Error("Aborted"));
93
- });
94
- }
98
+ clear = bindAbort(proc, options.signal, () => {
99
+ clearTimeout(id);
100
+ reject(options.signal?.reason);
101
+ });
95
102
  });
96
103
  return {
97
104
  url,
98
105
  close() {
99
- proc.kill();
106
+ clear();
107
+ stop(proc);
100
108
  },
101
109
  };
102
110
  }
@@ -114,10 +122,8 @@ export function createKiloTui(options) {
114
122
  if (options?.agent) {
115
123
  args.push(`--agent=${options.agent}`);
116
124
  }
117
- // kilocode_change start
118
- const proc = spawn(`kilo`, args, {
119
- // kilocode_change end
120
- signal: options?.signal,
125
+ const proc = launch(`kilo`, args, {
126
+ // kilocode_change
121
127
  stdio: "inherit",
122
128
  windowsHide: true,
123
129
  env: {
@@ -125,9 +131,11 @@ export function createKiloTui(options) {
125
131
  KILO_CONFIG_CONTENT: buildConfigEnv(options?.config), // kilocode_change
126
132
  },
127
133
  });
134
+ const clear = bindAbort(proc, options?.signal);
128
135
  return {
129
136
  close() {
130
- proc.kill();
137
+ clear();
138
+ stop(proc);
131
139
  },
132
140
  };
133
141
  }
package/dist/v2/client.js CHANGED
@@ -2,6 +2,41 @@ export * from "./gen/types.gen.js";
2
2
  import { createClient } from "./gen/client/client.gen.js";
3
3
  import { KiloClient } from "./gen/sdk.gen.js";
4
4
  export { KiloClient };
5
+ function pick(value, fallback, encode) {
6
+ if (!value)
7
+ return;
8
+ if (!fallback)
9
+ return value;
10
+ if (value === fallback)
11
+ return fallback;
12
+ if (encode && value === encode(fallback))
13
+ return fallback;
14
+ return value;
15
+ }
16
+ function rewrite(request, values) {
17
+ if (request.method !== "GET" && request.method !== "HEAD")
18
+ return request;
19
+ const url = new URL(request.url);
20
+ let changed = false;
21
+ for (const [name, key] of [
22
+ ["x-kilo-directory", "directory"],
23
+ ["x-kilo-workspace", "workspace"],
24
+ ]) {
25
+ const value = pick(request.headers.get(name), key === "directory" ? values.directory : values.workspace, key === "directory" ? encodeURIComponent : undefined);
26
+ if (!value)
27
+ continue;
28
+ if (!url.searchParams.has(key)) {
29
+ url.searchParams.set(key, value);
30
+ }
31
+ changed = true;
32
+ }
33
+ if (!changed)
34
+ return request;
35
+ const next = new Request(url, request);
36
+ next.headers.delete("x-kilo-directory");
37
+ next.headers.delete("x-kilo-workspace");
38
+ return next;
39
+ }
5
40
  export function createKiloClient(config) {
6
41
  if (!config?.fetch) {
7
42
  const customFetch = (req) => {
@@ -19,11 +54,9 @@ export function createKiloClient(config) {
19
54
  };
20
55
  }
21
56
  if (config?.directory) {
22
- const isNonASCII = /[^\x00-\x7F]/.test(config.directory);
23
- const encodedDirectory = isNonASCII ? encodeURIComponent(config.directory) : config.directory;
24
57
  config.headers = {
25
58
  ...config.headers,
26
- "x-kilo-directory": encodedDirectory,
59
+ "x-kilo-directory": encodeURIComponent(config.directory),
27
60
  };
28
61
  }
29
62
  if (config?.experimental_workspaceID) {
@@ -38,5 +71,9 @@ export function createKiloClient(config) {
38
71
  ;
39
72
  config.duplex = "half";
40
73
  const client = createClient(config);
74
+ client.interceptors.request.use((request) => rewrite(request, {
75
+ directory: config?.directory,
76
+ workspace: config?.experimental_workspaceID,
77
+ }));
41
78
  return new KiloClient({ client });
42
79
  }