@codexhost/cli-linux-arm64 0.11.0 → 0.12.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.
@@ -5,9 +5,351 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
8
+ // ../../harness-discovery/dist/environment.js
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ function targetPath(platform) {
12
+ return platform === "win32" ? path.win32 : path.posix;
13
+ }
14
+ function environmentValue(environment, name) {
15
+ const lowered = name.toLowerCase();
16
+ for (const [key, value] of Object.entries(environment)) {
17
+ if (key.toLowerCase() === lowered)
18
+ return value;
19
+ }
20
+ return void 0;
21
+ }
22
+ function pathDelimiter(platform) {
23
+ return platform === "win32" ? ";" : ":";
24
+ }
25
+ function pathDirectories(environment, platform) {
26
+ return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
27
+ }
28
+ function executableExtensions(command, platform, environment) {
29
+ if (platform !== "win32")
30
+ return [""];
31
+ if (targetPath(platform).extname(command) !== "")
32
+ return [""];
33
+ return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
34
+ }
35
+ function isExecutableFile(filePath, platform) {
36
+ try {
37
+ fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
38
+ return fs.statSync(filePath).isFile();
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ function subdirectoryNames(directory) {
44
+ try {
45
+ return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
46
+ } catch {
47
+ return [];
48
+ }
49
+ }
50
+ function newestFirst(names) {
51
+ return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
52
+ }
53
+
54
+ // ../../harness-discovery/dist/invocation.js
55
+ import path2 from "node:path";
56
+ function commandInvocation(command, arguments_, environment, platform = process.platform) {
57
+ const extension = path2.win32.extname(command).toLowerCase();
58
+ if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
59
+ return { command, arguments: [...arguments_], windowsVerbatimArguments: false };
60
+ }
61
+ const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
62
+ const commandLine = [command, ...arguments_].map(quote).join(" ");
63
+ return {
64
+ command: environmentValue(environment, "ComSpec") ?? "cmd.exe",
65
+ arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
66
+ windowsVerbatimArguments: true
67
+ };
68
+ }
69
+
70
+ // ../../harness-discovery/dist/node-runtime.js
71
+ import path3 from "node:path";
72
+ function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
73
+ const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
74
+ const delimiter = platform === "win32" ? ";" : ":";
75
+ const runtimeDirectory = path3.dirname(runtimeExecutable);
76
+ const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
77
+ const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
78
+ if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
79
+ directories.push(runtimeDirectory);
80
+ }
81
+ return { ...environment, [pathKey]: directories.join(delimiter) };
82
+ }
83
+
84
+ // ../../harness-discovery/dist/resolve.js
85
+ import os from "node:os";
86
+
87
+ // ../../harness-discovery/dist/version-managers.js
88
+ function versionManagerBinaryDirectories(context) {
89
+ const { platform, environment, home } = context;
90
+ const list = context.subdirectories ?? subdirectoryNames;
91
+ const pathFlavor = targetPath(platform);
92
+ const value = (name) => environmentValue(environment, name);
93
+ const directories = [];
94
+ const versioned = (root, ...tail) => {
95
+ for (const version2 of newestFirst(list(root))) {
96
+ directories.push(pathFlavor.join(root, version2, ...tail));
97
+ }
98
+ };
99
+ if (platform === "win32") {
100
+ const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
101
+ const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
102
+ versioned(pathFlavor.join(appData, "nvm"));
103
+ versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
104
+ directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
105
+ directories.push(pathFlavor.join(home, ".bun", "bin"));
106
+ const pnpmHome2 = value("PNPM_HOME");
107
+ if (pnpmHome2)
108
+ directories.push(pnpmHome2);
109
+ directories.push(pathFlavor.join(localAppData, "pnpm"));
110
+ return directories;
111
+ }
112
+ versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
113
+ const fnmRoots = [
114
+ value("FNM_DIR"),
115
+ pathFlavor.join(home, ".local", "share", "fnm"),
116
+ pathFlavor.join(home, "Library", "Application Support", "fnm")
117
+ ].filter((root) => root !== void 0);
118
+ for (const root of fnmRoots) {
119
+ versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
120
+ }
121
+ const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
122
+ versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
123
+ directories.push(pathFlavor.join(voltaHome, "bin"));
124
+ const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
125
+ versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
126
+ directories.push(pathFlavor.join(asdfHome, "shims"));
127
+ const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
128
+ versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
129
+ directories.push(pathFlavor.join(nodenvHome, "shims"));
130
+ versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
131
+ directories.push(pathFlavor.join(home, ".bun", "bin"));
132
+ const pnpmHome = value("PNPM_HOME");
133
+ if (pnpmHome)
134
+ directories.push(pnpmHome);
135
+ directories.push(pathFlavor.join(home, "Library", "pnpm"));
136
+ directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
137
+ for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
138
+ for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
139
+ directories.push(pathFlavor.join(prefix, formula, "bin"));
140
+ }
141
+ }
142
+ return directories;
143
+ }
144
+
145
+ // ../../harness-discovery/dist/resolve.js
146
+ var VERSION_MANAGER_ROOTS = "<version-managers>";
147
+ function installRootExtensions(platform) {
148
+ return platform === "win32" ? [".exe", ".cmd"] : [""];
149
+ }
150
+ function resolveHomeDirectory(input) {
151
+ return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
152
+ }
153
+ function templateVariables(environment, platform, home) {
154
+ const pathFlavor = targetPath(platform);
155
+ return {
156
+ HOME: home,
157
+ USERPROFILE: home,
158
+ APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
159
+ LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
160
+ };
161
+ }
162
+ function joinTemplate(platform, value) {
163
+ const pathFlavor = targetPath(platform);
164
+ const segments = value.split("/");
165
+ const head = segments[0] ?? "";
166
+ const tail = segments.slice(1);
167
+ if (head === "")
168
+ return pathFlavor.join(pathFlavor.sep, ...tail);
169
+ return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
170
+ }
171
+ function expandInstallRoot(template, environment, platform, home) {
172
+ const variables = templateVariables(environment, platform, home);
173
+ let unresolved = false;
174
+ const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
175
+ const value = variables[name] ?? environmentValue(environment, name);
176
+ if (value === void 0 || value === "") {
177
+ unresolved = true;
178
+ return "";
179
+ }
180
+ return value;
181
+ });
182
+ return unresolved ? void 0 : joinTemplate(platform, substituted);
183
+ }
184
+ function installRootDirectories(spec, input, dependencies, platform, home) {
185
+ const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
186
+ const directories = [];
187
+ for (const template of templates) {
188
+ if (template === VERSION_MANAGER_ROOTS) {
189
+ directories.push(...versionManagerBinaryDirectories({
190
+ platform,
191
+ environment: input.environment,
192
+ home,
193
+ ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
194
+ }));
195
+ continue;
196
+ }
197
+ const directory = expandInstallRoot(template, input.environment, platform, home);
198
+ if (directory !== void 0)
199
+ directories.push(directory);
200
+ }
201
+ return directories;
202
+ }
203
+ function harnessCandidates(spec, input, dependencies = {}) {
204
+ const platform = input.platform ?? process.platform;
205
+ const pathFlavor = targetPath(platform);
206
+ const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
207
+ const command = configured ?? spec.command;
208
+ if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
209
+ return [{ candidate: command, source: "configured" }];
210
+ }
211
+ const candidates = [];
212
+ const extensions = executableExtensions(command, platform, input.environment);
213
+ for (const directory of pathDirectories(input.environment, platform)) {
214
+ for (const extension of extensions) {
215
+ candidates.push({
216
+ candidate: pathFlavor.join(directory, command + extension),
217
+ source: "path"
218
+ });
219
+ }
220
+ }
221
+ if (configured !== void 0)
222
+ return candidates;
223
+ const home = resolveHomeDirectory(input);
224
+ for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
225
+ for (const extension of installRootExtensions(platform)) {
226
+ candidates.push({
227
+ candidate: pathFlavor.join(directory, spec.command + extension),
228
+ source: "install-root"
229
+ });
230
+ }
231
+ }
232
+ return candidates;
233
+ }
234
+ function resolveHarnessExecutable(spec, input, dependencies = {}) {
235
+ const platform = input.platform ?? process.platform;
236
+ const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
237
+ const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
238
+ const context = { platform, isExecutable };
239
+ for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
240
+ const executable = runnable(candidate, context);
241
+ if (executable !== void 0 && isExecutable(executable))
242
+ return { executable, source };
243
+ }
244
+ return void 0;
245
+ }
246
+
247
+ // ../../harness-discovery/dist/installation.js
248
+ import { execFile } from "node:child_process";
249
+ import { homedir } from "node:os";
250
+ function runInstallationCommand(command, args, environment, timeout = 3e4) {
251
+ const env = withNodeRuntimeOnPath(environment);
252
+ const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
253
+ return new Promise((resolve, reject) => {
254
+ const child = execFile(invocation.command, invocation.arguments, {
255
+ env,
256
+ cwd: env.HOME ?? env.USERPROFILE ?? homedir(),
257
+ encoding: "utf8",
258
+ timeout,
259
+ killSignal: "SIGKILL",
260
+ maxBuffer: 1024 * 1024,
261
+ windowsHide: true,
262
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
263
+ }, (error51, stdout, stderr) => {
264
+ if (error51)
265
+ reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
266
+ else
267
+ resolve((stdout || stderr).trim());
268
+ });
269
+ child.stdin?.end();
270
+ });
271
+ }
272
+ function installationVersion(value) {
273
+ if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
274
+ throw new Error("Harness returned an invalid version");
275
+ return value.trim().replace(/^v/, "");
276
+ }
277
+ function versionFromOutput(output) {
278
+ return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
279
+ }
280
+ async function fetchInstallationText(url2) {
281
+ const request = async () => {
282
+ const response = await fetch(url2, { signal: AbortSignal.timeout(15e3) });
283
+ if (!response.ok)
284
+ throw new Error("Could not check the latest Harness version");
285
+ return response.text();
286
+ };
287
+ try {
288
+ return await request();
289
+ } catch (error51) {
290
+ if (error51 instanceof DOMException && (error51.name === "AbortError" || error51.name === "TimeoutError"))
291
+ throw error51;
292
+ return request();
293
+ }
294
+ }
295
+
296
+ // ../../harness-discovery/dist/installer.js
297
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
298
+ import { tmpdir } from "node:os";
299
+ import { join } from "node:path";
300
+ function createHarnessInstaller(environment, source) {
301
+ return async () => {
302
+ if (!["darwin", "linux", "win32"].includes(process.platform))
303
+ throw new Error("Unsupported installation platform");
304
+ const env = withNodeRuntimeOnPath(environment);
305
+ if ("npm" in source) {
306
+ const npm = resolveHarnessExecutable({
307
+ id: "npm",
308
+ command: "npm",
309
+ installRoots: {
310
+ posix: [
311
+ "~/.npm-global/bin",
312
+ "~/.local/bin",
313
+ VERSION_MANAGER_ROOTS,
314
+ "/opt/homebrew/bin",
315
+ "/usr/local/bin",
316
+ "/usr/bin"
317
+ ],
318
+ windows: [
319
+ "${APPDATA}/npm",
320
+ VERSION_MANAGER_ROOTS,
321
+ "${ProgramFiles}/nodejs",
322
+ "${LOCALAPPDATA}/Programs/nodejs"
323
+ ]
324
+ }
325
+ }, { environment: env });
326
+ if (!npm)
327
+ throw new Error("Install Node.js and npm first");
328
+ await runInstallationCommand(npm.executable, ["install", "--global", source.npm], {
329
+ ...env,
330
+ ...source.allowScripts ? { npm_config_allow_scripts: source.allowScripts } : {}
331
+ }, 6e5);
332
+ return;
333
+ }
334
+ const windows = process.platform === "win32";
335
+ const url2 = windows ? source.windows : source.posix;
336
+ if (new URL(url2).protocol !== "https:")
337
+ throw new Error("Installer requires HTTPS");
338
+ const script = await fetchInstallationText(url2);
339
+ const directory = await mkdtemp(join(tmpdir(), "codexhost-installer-"));
340
+ try {
341
+ const file2 = join(directory, windows ? "install.ps1" : "install.sh");
342
+ await writeFile(file2, script, { mode: 384 });
343
+ await runInstallationCommand(windows ? "powershell.exe" : source.shell ?? "bash", windows ? ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", file2] : [file2], env, 6e5);
344
+ } finally {
345
+ await rm(directory, { recursive: true, force: true });
346
+ }
347
+ };
348
+ }
349
+
8
350
  // dist/kiro-adapter.js
9
351
  import { randomUUID } from "node:crypto";
10
- import path7 from "node:path";
352
+ import path8 from "node:path";
11
353
 
12
354
  // ../../../node_modules/zod/v4/classic/external.js
13
355
  var external_exports = {};
@@ -775,10 +1117,10 @@ function mergeDefs(...defs) {
775
1117
  function cloneDef(schema) {
776
1118
  return mergeDefs(schema._zod.def);
777
1119
  }
778
- function getElementAtPath(obj, path8) {
779
- if (!path8)
1120
+ function getElementAtPath(obj, path9) {
1121
+ if (!path9)
780
1122
  return obj;
781
- return path8.reduce((acc, key) => acc?.[key], obj);
1123
+ return path9.reduce((acc, key) => acc?.[key], obj);
782
1124
  }
783
1125
  function promiseAllObject(promisesObj) {
784
1126
  const keys = Object.keys(promisesObj);
@@ -1187,11 +1529,11 @@ function explicitlyAborted(x, startIndex = 0) {
1187
1529
  }
1188
1530
  return false;
1189
1531
  }
1190
- function prefixIssues(path8, issues) {
1532
+ function prefixIssues(path9, issues) {
1191
1533
  return issues.map((iss) => {
1192
1534
  var _a3;
1193
1535
  (_a3 = iss).path ?? (_a3.path = []);
1194
- iss.path.unshift(path8);
1536
+ iss.path.unshift(path9);
1195
1537
  return iss;
1196
1538
  });
1197
1539
  }
@@ -1338,16 +1680,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1338
1680
  }
1339
1681
  function formatError(error51, mapper = (issue2) => issue2.message) {
1340
1682
  const fieldErrors = { _errors: [] };
1341
- const processError = (error52, path8 = []) => {
1683
+ const processError = (error52, path9 = []) => {
1342
1684
  for (const issue2 of error52.issues) {
1343
1685
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1344
- issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
1686
+ issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
1345
1687
  } else if (issue2.code === "invalid_key") {
1346
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1688
+ processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1347
1689
  } else if (issue2.code === "invalid_element") {
1348
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1690
+ processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1349
1691
  } else {
1350
- const fullpath = [...path8, ...issue2.path];
1692
+ const fullpath = [...path9, ...issue2.path];
1351
1693
  if (fullpath.length === 0) {
1352
1694
  fieldErrors._errors.push(mapper(issue2));
1353
1695
  } else {
@@ -1374,17 +1716,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1374
1716
  }
1375
1717
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1376
1718
  const result = { errors: [] };
1377
- const processError = (error52, path8 = []) => {
1719
+ const processError = (error52, path9 = []) => {
1378
1720
  var _a3, _b;
1379
1721
  for (const issue2 of error52.issues) {
1380
1722
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1381
- issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
1723
+ issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
1382
1724
  } else if (issue2.code === "invalid_key") {
1383
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1725
+ processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1384
1726
  } else if (issue2.code === "invalid_element") {
1385
- processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1727
+ processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1386
1728
  } else {
1387
- const fullpath = [...path8, ...issue2.path];
1729
+ const fullpath = [...path9, ...issue2.path];
1388
1730
  if (fullpath.length === 0) {
1389
1731
  result.errors.push(mapper(issue2));
1390
1732
  continue;
@@ -1416,8 +1758,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1416
1758
  }
1417
1759
  function toDotPath(_path) {
1418
1760
  const segs = [];
1419
- const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1420
- for (const seg of path8) {
1761
+ const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1762
+ for (const seg of path9) {
1421
1763
  if (typeof seg === "number")
1422
1764
  segs.push(`[${seg}]`);
1423
1765
  else if (typeof seg === "symbol")
@@ -14109,13 +14451,13 @@ function resolveRef(ref, ctx) {
14109
14451
  if (!ref.startsWith("#")) {
14110
14452
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14111
14453
  }
14112
- const path8 = ref.slice(1).split("/").filter(Boolean);
14113
- if (path8.length === 0) {
14454
+ const path9 = ref.slice(1).split("/").filter(Boolean);
14455
+ if (path9.length === 0) {
14114
14456
  return ctx.rootSchema;
14115
14457
  }
14116
14458
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14117
- if (path8[0] === defsKey) {
14118
- const key = path8[1];
14459
+ if (path9[0] === defsKey) {
14460
+ const key = path9[1];
14119
14461
  if (!key || !ctx.defs[key]) {
14120
14462
  throw new Error(`Reference not found: ${ref}`);
14121
14463
  }
@@ -14609,6 +14951,7 @@ var CONSOLE_HOST_METHODS = Object.freeze([
14609
14951
  "codexhost/harness/display-settings/get",
14610
14952
  "codexhost/harness/display-settings/set",
14611
14953
  "codexhost/harness/inspect",
14954
+ "codexhost/harness/installation",
14612
14955
  "codexhost/harness/launch-settings/get",
14613
14956
  "codexhost/harness/launch-settings/set",
14614
14957
  "codexhost/harness/web-ui/open",
@@ -15255,14 +15598,17 @@ var harnessLaunchSettingsSchema = external_exports.object({
15255
15598
  // ../../shared-contracts/dist/harness-installation.js
15256
15599
  var harnessInstallationParamsSchema = external_exports.object({
15257
15600
  harnessId: harnessIdSchema,
15258
- action: external_exports.enum(["check", "update"])
15601
+ action: external_exports.enum(["check", "update", "install"])
15259
15602
  }).strict();
15260
15603
  var harnessInstallationStateSchema = external_exports.object({
15261
15604
  currentVersion: external_exports.string().min(1).max(128),
15262
15605
  latestVersion: external_exports.string().min(1).max(128),
15263
15606
  updateAvailable: external_exports.boolean(),
15264
15607
  canUpdate: external_exports.boolean(),
15265
- message: external_exports.string().max(2048).optional()
15608
+ // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15609
+ message: external_exports.string().max(2048).optional(),
15610
+ messageCode: external_exports.string().min(1).max(128).optional(),
15611
+ latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15266
15612
  }).strict();
15267
15613
 
15268
15614
  // ../../shared-contracts/dist/codex-accounts.js
@@ -15564,6 +15910,38 @@ var updateStatusResultSchema = external_exports.strictObject({
15564
15910
  status: updateStatusSchema.nullable()
15565
15911
  });
15566
15912
 
15913
+ // ../../shared-contracts/dist/remote-runtime.js
15914
+ var remoteUpdatePhaseSchema = external_exports.enum([
15915
+ "idle",
15916
+ "installing",
15917
+ "restarting",
15918
+ "succeeded",
15919
+ "failed"
15920
+ ]);
15921
+ var runtimeStatusSchema = external_exports.object({
15922
+ runningVersion: external_exports.string().nullable(),
15923
+ installedVersion: external_exports.string().nullable(),
15924
+ restartRequired: external_exports.boolean(),
15925
+ remote: external_exports.boolean(),
15926
+ updateSupported: external_exports.boolean(),
15927
+ update: external_exports.object({
15928
+ phase: remoteUpdatePhaseSchema,
15929
+ targetVersion: external_exports.string().nullable(),
15930
+ error: external_exports.string().nullable()
15931
+ })
15932
+ });
15933
+ var remoteUpdateParamsSchema = external_exports.object({
15934
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
15935
+ }).strict();
15936
+ var remoteSshSetupParamsSchema = external_exports.object({
15937
+ hostname: external_exports.string().min(1).max(1024).refine((value) => !value.startsWith("-") && !/\s/u.test(value)),
15938
+ port: external_exports.number().int().min(1).max(65535).nullable(),
15939
+ identity: external_exports.string().max(4096).nullable(),
15940
+ action: external_exports.enum(["inspect", "install", "update", "repair"]),
15941
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/u).nullable()
15942
+ }).strict();
15943
+ var remoteSshSetupResultSchema = external_exports.object({ state: external_exports.enum(["installed", "not-installed"]) }).strict();
15944
+
15567
15945
  // ../../shared-contracts/dist/index.js
15568
15946
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
15569
15947
 
@@ -15582,581 +15960,308 @@ function invalidRequest2(message) {
15582
15960
  function validateHostQuestionResponse(interaction, response) {
15583
15961
  const questionIds = new Set(interaction.questions.map(({ id }) => id));
15584
15962
  if (response.cancelled) {
15585
- return Object.keys(response.answers).length === 0 ? null : invalidRequest2("Cancelled Question Response must not contain answers");
15586
- }
15587
- for (const answerId of Object.keys(response.answers)) {
15588
- if (!questionIds.has(answerId)) {
15589
- return invalidRequest2("Question Response contains an unknown Question ID");
15590
- }
15591
- }
15592
- for (const question of interaction.questions) {
15593
- const answers = response.answers[question.id] ?? [];
15594
- if (!question.optional && answers.length === 0) {
15595
- return invalidRequest2("Question Response omits a required answer");
15596
- }
15597
- if (question.type === "text") {
15598
- if (answers.length > 1) {
15599
- return invalidRequest2("Text Question accepts at most one answer");
15600
- }
15601
- continue;
15602
- }
15603
- if (!question.multiple && answers.length > 1) {
15604
- return invalidRequest2("Single-choice Question accepts at most one answer");
15605
- }
15606
- const declared = new Set(question.options.map(({ value }) => value));
15607
- if (!question.allowOther && answers.some((answer) => !declared.has(answer))) {
15608
- return invalidRequest2("Question Response contains an undeclared choice");
15609
- }
15610
- }
15611
- return null;
15612
- }
15613
-
15614
- // ../../harness-adapter/dist/output-channel.js
15615
- var HarnessOutputChannel = class {
15616
- outputs;
15617
- #consumerCreated = false;
15618
- #ended = false;
15619
- #pending = [];
15620
- #values = [];
15621
- constructor() {
15622
- this.outputs = {
15623
- [Symbol.asyncIterator]: () => {
15624
- if (this.#consumerCreated) {
15625
- throw new Error("Harness outputs allow only one consumer");
15626
- }
15627
- this.#consumerCreated = true;
15628
- return {
15629
- next: () => this.#next()
15630
- };
15631
- }
15632
- };
15633
- }
15634
- emit(value) {
15635
- if (this.#ended)
15636
- return false;
15637
- const resolve = this.#pending.shift();
15638
- if (resolve)
15639
- resolve({ done: false, value });
15640
- else
15641
- this.#values.push(value);
15642
- return true;
15643
- }
15644
- end() {
15645
- if (this.#ended)
15646
- return;
15647
- this.#ended = true;
15648
- if (this.#values.length !== 0)
15649
- return;
15650
- for (const resolve of this.#pending.splice(0))
15651
- resolve({ done: true, value: void 0 });
15652
- }
15653
- #next() {
15654
- const value = this.#values.shift();
15655
- if (value !== void 0)
15656
- return Promise.resolve({ done: false, value });
15657
- if (this.#ended)
15658
- return Promise.resolve({ done: true, value: void 0 });
15659
- return new Promise((resolve) => this.#pending.push(resolve));
15660
- }
15661
- };
15662
-
15663
- // ../../harness-adapter/dist/diagnostics.js
15664
- var DIAGNOSTIC_TAIL_MAX_LENGTH = 8e3;
15665
- var SENSITIVE_VALUE_PATTERN = /(api[_-]?key|access[_-]?token|auth(?:orization)?|password|secret)(\s*[:=]\s*)([^\s,;]+)/giu;
15666
- var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
15667
- function sanitizeDiagnosticTail(value) {
15668
- const redacted = value.replace(BEARER_PATTERN, "Bearer [redacted]").replace(SENSITIVE_VALUE_PATTERN, "$1$2[redacted]");
15669
- return redacted.length <= DIAGNOSTIC_TAIL_MAX_LENGTH ? redacted : redacted.slice(-DIAGNOSTIC_TAIL_MAX_LENGTH);
15670
- }
15671
-
15672
- // ../../harness-adapter/dist/usage.js
15673
- var tokenFields = [
15674
- "inputTokens",
15675
- "cachedInputTokens",
15676
- "cacheWriteInputTokens",
15677
- "outputTokens",
15678
- "outputTokensPerSecond",
15679
- "reasoningOutputTokens",
15680
- "totalTokens",
15681
- "contextWindowTokens",
15682
- "contextUsedTokens"
15683
- ];
15684
- var safeIntegerFields = [
15685
- "planFiveHourResetsAtUnix",
15686
- "planSevenDayResetsAtUnix"
15687
- ];
15688
- var percentFields = [
15689
- "cacheHitRatePercent",
15690
- "planFiveHourUsedPercent",
15691
- "planSevenDayUsedPercent"
15692
- ];
15693
- var usageFields = /* @__PURE__ */ new Set([
15694
- ...tokenFields,
15695
- ...safeIntegerFields,
15696
- ...percentFields,
15697
- "totalCostUsd",
15698
- "totalCredits",
15699
- "contextUsagePercent"
15700
- ]);
15701
- function isRecord(value) {
15702
- return typeof value === "object" && value !== null && !Array.isArray(value);
15703
- }
15704
- function parseHostUsage(value) {
15705
- if (!isRecord(value))
15706
- throw new Error("Harness Usage must be an object");
15707
- const keys = Object.keys(value);
15708
- if (keys.length === 0)
15709
- throw new Error("Harness Usage must contain a reliable field");
15710
- for (const key of keys) {
15711
- if (!usageFields.has(key)) {
15712
- throw new Error(`Harness Usage contains unknown field '${key}'`);
15713
- }
15963
+ return Object.keys(response.answers).length === 0 ? null : invalidRequest2("Cancelled Question Response must not contain answers");
15714
15964
  }
15715
- for (const field of ["totalCredits", "contextUsagePercent"]) {
15716
- const candidate = value[field];
15717
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
15718
- throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
15965
+ for (const answerId of Object.keys(response.answers)) {
15966
+ if (!questionIds.has(answerId)) {
15967
+ return invalidRequest2("Question Response contains an unknown Question ID");
15719
15968
  }
15720
15969
  }
15721
- for (const field of tokenFields) {
15722
- const candidate = value[field];
15723
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
15724
- throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
15970
+ for (const question of interaction.questions) {
15971
+ const answers = response.answers[question.id] ?? [];
15972
+ if (!question.optional && answers.length === 0) {
15973
+ return invalidRequest2("Question Response omits a required answer");
15725
15974
  }
15726
- }
15727
- for (const field of safeIntegerFields) {
15728
- const candidate = value[field];
15729
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
15730
- throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
15975
+ if (question.type === "text") {
15976
+ if (answers.length > 1) {
15977
+ return invalidRequest2("Text Question accepts at most one answer");
15978
+ }
15979
+ continue;
15731
15980
  }
15732
- }
15733
- if (value.outputTokensPerSecond !== void 0 && (typeof value.outputTokensPerSecond !== "number" || !Number.isFinite(value.outputTokensPerSecond) || value.outputTokensPerSecond < 0)) {
15734
- throw new Error("Harness Usage 'outputTokensPerSecond' must be a finite non-negative number");
15735
- }
15736
- if (value.totalCostUsd !== void 0 && (typeof value.totalCostUsd !== "number" || !Number.isFinite(value.totalCostUsd) || value.totalCostUsd < 0)) {
15737
- throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
15738
- }
15739
- for (const field of percentFields) {
15740
- const candidate = value[field];
15741
- if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
15742
- throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
15981
+ if (!question.multiple && answers.length > 1) {
15982
+ return invalidRequest2("Single-choice Question accepts at most one answer");
15983
+ }
15984
+ const declared = new Set(question.options.map(({ value }) => value));
15985
+ if (!question.allowOther && answers.some((answer) => !declared.has(answer))) {
15986
+ return invalidRequest2("Question Response contains an undeclared choice");
15743
15987
  }
15744
15988
  }
15745
- const hasContextUsed = value.contextUsedTokens !== void 0;
15746
- const hasContextWindow = value.contextWindowTokens !== void 0;
15747
- if (hasContextUsed !== hasContextWindow) {
15748
- throw new Error("Harness Usage context fields must be provided together");
15749
- }
15750
- if (hasContextWindow && value.contextWindowTokens === 0) {
15751
- throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
15752
- }
15753
- if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
15754
- throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
15755
- }
15756
- if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
15757
- throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
15758
- }
15759
- return { ...value };
15760
- }
15761
-
15762
- // ../../harness-adapter/dist/live-command-catalog.js
15763
- var COMMON_EXCLUDED_LIVE_COMMANDS = /* @__PURE__ */ new Set([
15764
- // Session lifecycle
15765
- "branch",
15766
- "clear",
15767
- "exit",
15768
- "fork",
15769
- "fresh",
15770
- "new",
15771
- "quit",
15772
- "rename",
15773
- "rename-chat",
15774
- "reset",
15775
- "resume",
15776
- "rewind",
15777
- "session",
15778
- "sessions",
15779
- // Desktop-owned configuration
15780
- "autocompact",
15781
- "color",
15782
- "config",
15783
- "effort",
15784
- "fast",
15785
- "keybindings",
15786
- "model",
15787
- "models",
15788
- "output-style",
15789
- "permissions",
15790
- "settings",
15791
- "statusline",
15792
- "terminal-setup",
15793
- "theme",
15794
- "vim",
15795
- // Trust and approval policy
15796
- "always-approve",
15797
- "auto-mode-setup",
15798
- // Native login
15799
- "login",
15800
- "logout",
15801
- // Work outliving the Turn
15802
- "autopilot",
15803
- "background",
15804
- "bg",
15805
- "goal",
15806
- "jobs",
15807
- "loop",
15808
- "multitask",
15809
- "queue",
15810
- "remote-control",
15811
- "schedule",
15812
- "steer",
15813
- // Native terminal UI
15814
- "copy",
15815
- "debug",
15816
- "feedback",
15817
- "heapdump",
15818
- "share",
15819
- "shell",
15820
- // Plugin and MCP management
15821
- "marketplace",
15822
- "mcp",
15823
- "plugins",
15824
- "reload-plugins"
15825
- ]);
15826
- var COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES = ["__", "hooks-"];
15827
- function isExcludedLiveCommand(name, kind, extra = {}) {
15828
- const normalized = name.trim().replace(/^\//u, "");
15829
- if (new Set(extra.names ?? []).has(normalized))
15830
- return true;
15831
- if (extra.prefixes?.some((prefix) => normalized.startsWith(prefix)))
15832
- return true;
15833
- if (kind === "skill")
15834
- return false;
15835
- return COMMON_EXCLUDED_LIVE_COMMANDS.has(normalized) || COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES.some((prefix) => normalized.startsWith(prefix));
15836
- }
15837
- function liveHarnessCommandPrompt(catalog, idPrefix, commandId, argumentText) {
15838
- if (!commandId.startsWith(idPrefix))
15839
- return null;
15840
- const descriptor = catalog.commands.find(({ id }) => id === commandId);
15841
- if (!descriptor)
15842
- return null;
15843
- const text = typeof argumentText === "string" ? argumentText.trim() : "";
15844
- return text ? `${descriptor.invocation} ${text}` : descriptor.invocation;
15845
- }
15846
- function mergeLiveHarnessCommands(builtIns, idPrefix, live, exclusions = {}) {
15847
- if (!live)
15848
- return builtIns;
15849
- const invocations = new Set(builtIns.commands.map(({ invocation }) => invocation));
15850
- const ids = new Set(builtIns.commands.map(({ id }) => id));
15851
- const dynamic = [];
15852
- for (const command of live) {
15853
- const name = command.name.trim().replace(/^\//u, "");
15854
- if (!name || /\s/u.test(name))
15855
- continue;
15856
- if (isExcludedLiveCommand(name, command.kind, exclusions))
15857
- continue;
15858
- const invocation = `/${name}`;
15859
- const id = `${idPrefix}${name.replace(/[^A-Za-z0-9._:-]/gu, "-")}`.slice(0, 128);
15860
- if (invocations.has(invocation) || ids.has(id))
15861
- continue;
15862
- const description = command.description?.trim().slice(0, 512);
15863
- const parsed = harnessCommandDescriptorSchema.safeParse({
15864
- id,
15865
- invocation,
15866
- label: name.slice(0, 128),
15867
- ...description ? { description } : {},
15868
- argumentMode: "text",
15869
- kind: command.kind
15870
- });
15871
- if (!parsed.success)
15872
- continue;
15873
- invocations.add(invocation);
15874
- ids.add(id);
15875
- dynamic.push(parsed.data);
15876
- }
15877
- return harnessCommandCatalogSchema.parse({ commands: [...builtIns.commands, ...dynamic] });
15989
+ return null;
15878
15990
  }
15879
15991
 
15880
- // dist/acp-transport.js
15881
- import { spawn, spawnSync } from "node:child_process";
15882
- import { Readable, Writable } from "node:stream";
15883
- import { execFile as execFile2 } from "node:child_process";
15884
- import { promisify } from "node:util";
15885
- import { setTimeout as delay } from "node:timers/promises";
15886
-
15887
- // ../../harness-discovery/dist/environment.js
15888
- import fs from "node:fs";
15889
- import path from "node:path";
15890
- function targetPath(platform) {
15891
- return platform === "win32" ? path.win32 : path.posix;
15892
- }
15893
- function environmentValue(environment, name) {
15894
- const lowered = name.toLowerCase();
15895
- for (const [key, value] of Object.entries(environment)) {
15896
- if (key.toLowerCase() === lowered)
15897
- return value;
15992
+ // ../../harness-adapter/dist/output-channel.js
15993
+ var HarnessOutputChannel = class {
15994
+ outputs;
15995
+ #consumerCreated = false;
15996
+ #ended = false;
15997
+ #pending = [];
15998
+ #values = [];
15999
+ constructor() {
16000
+ this.outputs = {
16001
+ [Symbol.asyncIterator]: () => {
16002
+ if (this.#consumerCreated) {
16003
+ throw new Error("Harness outputs allow only one consumer");
16004
+ }
16005
+ this.#consumerCreated = true;
16006
+ return {
16007
+ next: () => this.#next()
16008
+ };
16009
+ }
16010
+ };
15898
16011
  }
15899
- return void 0;
15900
- }
15901
- function pathDelimiter(platform) {
15902
- return platform === "win32" ? ";" : ":";
15903
- }
15904
- function pathDirectories(environment, platform) {
15905
- return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
15906
- }
15907
- function executableExtensions(command, platform, environment) {
15908
- if (platform !== "win32")
15909
- return [""];
15910
- if (targetPath(platform).extname(command) !== "")
15911
- return [""];
15912
- return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
15913
- }
15914
- function isExecutableFile(filePath, platform) {
15915
- try {
15916
- fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
15917
- return fs.statSync(filePath).isFile();
15918
- } catch {
15919
- return false;
16012
+ emit(value) {
16013
+ if (this.#ended)
16014
+ return false;
16015
+ const resolve = this.#pending.shift();
16016
+ if (resolve)
16017
+ resolve({ done: false, value });
16018
+ else
16019
+ this.#values.push(value);
16020
+ return true;
15920
16021
  }
15921
- }
15922
- function subdirectoryNames(directory) {
15923
- try {
15924
- return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
15925
- } catch {
15926
- return [];
16022
+ end() {
16023
+ if (this.#ended)
16024
+ return;
16025
+ this.#ended = true;
16026
+ if (this.#values.length !== 0)
16027
+ return;
16028
+ for (const resolve of this.#pending.splice(0))
16029
+ resolve({ done: true, value: void 0 });
15927
16030
  }
15928
- }
15929
- function newestFirst(names) {
15930
- return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
15931
- }
15932
-
15933
- // ../../harness-discovery/dist/invocation.js
15934
- import path2 from "node:path";
15935
- function commandInvocation(command, arguments_, environment, platform = process.platform) {
15936
- const extension = path2.win32.extname(command).toLowerCase();
15937
- if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
15938
- return { command, arguments: [...arguments_], windowsVerbatimArguments: false };
16031
+ #next() {
16032
+ const value = this.#values.shift();
16033
+ if (value !== void 0)
16034
+ return Promise.resolve({ done: false, value });
16035
+ if (this.#ended)
16036
+ return Promise.resolve({ done: true, value: void 0 });
16037
+ return new Promise((resolve) => this.#pending.push(resolve));
15939
16038
  }
15940
- const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
15941
- const commandLine = [command, ...arguments_].map(quote).join(" ");
15942
- return {
15943
- command: environmentValue(environment, "ComSpec") ?? "cmd.exe",
15944
- arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
15945
- windowsVerbatimArguments: true
15946
- };
15947
- }
16039
+ };
15948
16040
 
15949
- // ../../harness-discovery/dist/node-runtime.js
15950
- import path3 from "node:path";
15951
- function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
15952
- const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
15953
- const delimiter = platform === "win32" ? ";" : ":";
15954
- const runtimeDirectory = path3.dirname(runtimeExecutable);
15955
- const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
15956
- const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
15957
- if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
15958
- directories.push(runtimeDirectory);
15959
- }
15960
- return { ...environment, [pathKey]: directories.join(delimiter) };
16041
+ // ../../harness-adapter/dist/diagnostics.js
16042
+ var DIAGNOSTIC_TAIL_MAX_LENGTH = 8e3;
16043
+ var SENSITIVE_VALUE_PATTERN = /(api[_-]?key|access[_-]?token|auth(?:orization)?|password|secret)(\s*[:=]\s*)([^\s,;]+)/giu;
16044
+ var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
16045
+ function sanitizeDiagnosticTail(value) {
16046
+ const redacted = value.replace(BEARER_PATTERN, "Bearer [redacted]").replace(SENSITIVE_VALUE_PATTERN, "$1$2[redacted]");
16047
+ return redacted.length <= DIAGNOSTIC_TAIL_MAX_LENGTH ? redacted : redacted.slice(-DIAGNOSTIC_TAIL_MAX_LENGTH);
15961
16048
  }
15962
16049
 
15963
- // ../../harness-discovery/dist/resolve.js
15964
- import os from "node:os";
15965
-
15966
- // ../../harness-discovery/dist/version-managers.js
15967
- function versionManagerBinaryDirectories(context) {
15968
- const { platform, environment, home } = context;
15969
- const list = context.subdirectories ?? subdirectoryNames;
15970
- const pathFlavor = targetPath(platform);
15971
- const value = (name) => environmentValue(environment, name);
15972
- const directories = [];
15973
- const versioned = (root, ...tail) => {
15974
- for (const version2 of newestFirst(list(root))) {
15975
- directories.push(pathFlavor.join(root, version2, ...tail));
16050
+ // ../../harness-adapter/dist/usage.js
16051
+ var tokenFields = [
16052
+ "inputTokens",
16053
+ "cachedInputTokens",
16054
+ "cacheWriteInputTokens",
16055
+ "outputTokens",
16056
+ "outputTokensPerSecond",
16057
+ "reasoningOutputTokens",
16058
+ "totalTokens",
16059
+ "contextWindowTokens",
16060
+ "contextUsedTokens"
16061
+ ];
16062
+ var safeIntegerFields = [
16063
+ "planFiveHourResetsAtUnix",
16064
+ "planSevenDayResetsAtUnix"
16065
+ ];
16066
+ var percentFields = [
16067
+ "cacheHitRatePercent",
16068
+ "planFiveHourUsedPercent",
16069
+ "planSevenDayUsedPercent"
16070
+ ];
16071
+ var usageFields = /* @__PURE__ */ new Set([
16072
+ ...tokenFields,
16073
+ ...safeIntegerFields,
16074
+ ...percentFields,
16075
+ "totalCostUsd",
16076
+ "totalCredits",
16077
+ "contextUsagePercent"
16078
+ ]);
16079
+ function isRecord(value) {
16080
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16081
+ }
16082
+ function parseHostUsage(value) {
16083
+ if (!isRecord(value))
16084
+ throw new Error("Harness Usage must be an object");
16085
+ const keys = Object.keys(value);
16086
+ if (keys.length === 0)
16087
+ throw new Error("Harness Usage must contain a reliable field");
16088
+ for (const key of keys) {
16089
+ if (!usageFields.has(key)) {
16090
+ throw new Error(`Harness Usage contains unknown field '${key}'`);
15976
16091
  }
15977
- };
15978
- if (platform === "win32") {
15979
- const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
15980
- const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
15981
- versioned(pathFlavor.join(appData, "nvm"));
15982
- versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
15983
- directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
15984
- directories.push(pathFlavor.join(home, ".bun", "bin"));
15985
- const pnpmHome2 = value("PNPM_HOME");
15986
- if (pnpmHome2)
15987
- directories.push(pnpmHome2);
15988
- directories.push(pathFlavor.join(localAppData, "pnpm"));
15989
- return directories;
15990
- }
15991
- versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
15992
- const fnmRoots = [
15993
- value("FNM_DIR"),
15994
- pathFlavor.join(home, ".local", "share", "fnm"),
15995
- pathFlavor.join(home, "Library", "Application Support", "fnm")
15996
- ].filter((root) => root !== void 0);
15997
- for (const root of fnmRoots) {
15998
- versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
15999
16092
  }
16000
- const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
16001
- versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
16002
- directories.push(pathFlavor.join(voltaHome, "bin"));
16003
- const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
16004
- versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
16005
- directories.push(pathFlavor.join(asdfHome, "shims"));
16006
- const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
16007
- versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
16008
- directories.push(pathFlavor.join(nodenvHome, "shims"));
16009
- versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
16010
- directories.push(pathFlavor.join(home, ".bun", "bin"));
16011
- const pnpmHome = value("PNPM_HOME");
16012
- if (pnpmHome)
16013
- directories.push(pnpmHome);
16014
- directories.push(pathFlavor.join(home, "Library", "pnpm"));
16015
- directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
16016
- for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
16017
- for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
16018
- directories.push(pathFlavor.join(prefix, formula, "bin"));
16093
+ for (const field of ["totalCredits", "contextUsagePercent"]) {
16094
+ const candidate = value[field];
16095
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
16096
+ throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
16019
16097
  }
16020
16098
  }
16021
- return directories;
16022
- }
16023
-
16024
- // ../../harness-discovery/dist/resolve.js
16025
- var VERSION_MANAGER_ROOTS = "<version-managers>";
16026
- function installRootExtensions(platform) {
16027
- return platform === "win32" ? [".exe", ".cmd"] : [""];
16028
- }
16029
- function resolveHomeDirectory(input) {
16030
- return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
16031
- }
16032
- function templateVariables(environment, platform, home) {
16033
- const pathFlavor = targetPath(platform);
16034
- return {
16035
- HOME: home,
16036
- USERPROFILE: home,
16037
- APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
16038
- LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
16039
- };
16040
- }
16041
- function joinTemplate(platform, value) {
16042
- const pathFlavor = targetPath(platform);
16043
- const segments = value.split("/");
16044
- const head = segments[0] ?? "";
16045
- const tail = segments.slice(1);
16046
- if (head === "")
16047
- return pathFlavor.join(pathFlavor.sep, ...tail);
16048
- return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
16049
- }
16050
- function expandInstallRoot(template, environment, platform, home) {
16051
- const variables = templateVariables(environment, platform, home);
16052
- let unresolved = false;
16053
- const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
16054
- const value = variables[name] ?? environmentValue(environment, name);
16055
- if (value === void 0 || value === "") {
16056
- unresolved = true;
16057
- return "";
16099
+ for (const field of tokenFields) {
16100
+ const candidate = value[field];
16101
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
16102
+ throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
16058
16103
  }
16059
- return value;
16060
- });
16061
- return unresolved ? void 0 : joinTemplate(platform, substituted);
16062
- }
16063
- function installRootDirectories(spec, input, dependencies, platform, home) {
16064
- const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
16065
- const directories = [];
16066
- for (const template of templates) {
16067
- if (template === VERSION_MANAGER_ROOTS) {
16068
- directories.push(...versionManagerBinaryDirectories({
16069
- platform,
16070
- environment: input.environment,
16071
- home,
16072
- ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
16073
- }));
16074
- continue;
16104
+ }
16105
+ for (const field of safeIntegerFields) {
16106
+ const candidate = value[field];
16107
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
16108
+ throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
16075
16109
  }
16076
- const directory = expandInstallRoot(template, input.environment, platform, home);
16077
- if (directory !== void 0)
16078
- directories.push(directory);
16079
16110
  }
16080
- return directories;
16081
- }
16082
- function harnessCandidates(spec, input, dependencies = {}) {
16083
- const platform = input.platform ?? process.platform;
16084
- const pathFlavor = targetPath(platform);
16085
- const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
16086
- const command = configured ?? spec.command;
16087
- if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
16088
- return [{ candidate: command, source: "configured" }];
16111
+ if (value.outputTokensPerSecond !== void 0 && (typeof value.outputTokensPerSecond !== "number" || !Number.isFinite(value.outputTokensPerSecond) || value.outputTokensPerSecond < 0)) {
16112
+ throw new Error("Harness Usage 'outputTokensPerSecond' must be a finite non-negative number");
16089
16113
  }
16090
- const candidates = [];
16091
- const extensions = executableExtensions(command, platform, input.environment);
16092
- for (const directory of pathDirectories(input.environment, platform)) {
16093
- for (const extension of extensions) {
16094
- candidates.push({
16095
- candidate: pathFlavor.join(directory, command + extension),
16096
- source: "path"
16097
- });
16098
- }
16114
+ if (value.totalCostUsd !== void 0 && (typeof value.totalCostUsd !== "number" || !Number.isFinite(value.totalCostUsd) || value.totalCostUsd < 0)) {
16115
+ throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
16099
16116
  }
16100
- if (configured !== void 0)
16101
- return candidates;
16102
- const home = resolveHomeDirectory(input);
16103
- for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
16104
- for (const extension of installRootExtensions(platform)) {
16105
- candidates.push({
16106
- candidate: pathFlavor.join(directory, spec.command + extension),
16107
- source: "install-root"
16108
- });
16117
+ for (const field of percentFields) {
16118
+ const candidate = value[field];
16119
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
16120
+ throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
16109
16121
  }
16110
16122
  }
16111
- return candidates;
16112
- }
16113
- function resolveHarnessExecutable(spec, input, dependencies = {}) {
16114
- const platform = input.platform ?? process.platform;
16115
- const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
16116
- const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
16117
- const context = { platform, isExecutable };
16118
- for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
16119
- const executable = runnable(candidate, context);
16120
- if (executable !== void 0 && isExecutable(executable))
16121
- return { executable, source };
16123
+ const hasContextUsed = value.contextUsedTokens !== void 0;
16124
+ const hasContextWindow = value.contextWindowTokens !== void 0;
16125
+ if (hasContextUsed !== hasContextWindow) {
16126
+ throw new Error("Harness Usage context fields must be provided together");
16127
+ }
16128
+ if (hasContextWindow && value.contextWindowTokens === 0) {
16129
+ throw new Error("Harness Usage 'contextWindowTokens' must be greater than zero");
16130
+ }
16131
+ if (value.planFiveHourResetsAtUnix !== void 0 && value.planFiveHourUsedPercent === void 0) {
16132
+ throw new Error("Harness Usage 'planFiveHourResetsAtUnix' must be provided with 'planFiveHourUsedPercent'");
16133
+ }
16134
+ if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
16135
+ throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
16122
16136
  }
16123
- return void 0;
16137
+ return { ...value };
16124
16138
  }
16125
16139
 
16126
- // ../../harness-discovery/dist/installation.js
16127
- import { execFile } from "node:child_process";
16128
- import { homedir } from "node:os";
16129
- function runInstallationCommand(command, args, environment, timeout = 3e4) {
16130
- const env = withNodeRuntimeOnPath(environment);
16131
- const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
16132
- return new Promise((resolve, reject) => {
16133
- const child = execFile(invocation.command, invocation.arguments, {
16134
- env,
16135
- cwd: env.HOME ?? env.USERPROFILE ?? homedir(),
16136
- encoding: "utf8",
16137
- timeout,
16138
- killSignal: "SIGKILL",
16139
- maxBuffer: 1024 * 1024,
16140
- windowsHide: true,
16141
- windowsVerbatimArguments: invocation.windowsVerbatimArguments
16142
- }, (error51, stdout, stderr) => {
16143
- if (error51)
16144
- reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
16145
- else
16146
- resolve((stdout || stderr).trim());
16147
- });
16148
- child.stdin?.end();
16149
- });
16140
+ // ../../harness-adapter/dist/live-command-catalog.js
16141
+ var COMMON_EXCLUDED_LIVE_COMMANDS = /* @__PURE__ */ new Set([
16142
+ // Session lifecycle
16143
+ "branch",
16144
+ "clear",
16145
+ "exit",
16146
+ "fork",
16147
+ "fresh",
16148
+ "new",
16149
+ "quit",
16150
+ "rename",
16151
+ "rename-chat",
16152
+ "reset",
16153
+ "resume",
16154
+ "rewind",
16155
+ "session",
16156
+ "sessions",
16157
+ // Desktop-owned configuration
16158
+ "autocompact",
16159
+ "color",
16160
+ "config",
16161
+ "effort",
16162
+ "fast",
16163
+ "keybindings",
16164
+ "model",
16165
+ "models",
16166
+ "output-style",
16167
+ "permissions",
16168
+ "settings",
16169
+ "statusline",
16170
+ "terminal-setup",
16171
+ "theme",
16172
+ "vim",
16173
+ // Trust and approval policy
16174
+ "always-approve",
16175
+ "auto-mode-setup",
16176
+ // Native login
16177
+ "login",
16178
+ "logout",
16179
+ // Work outliving the Turn
16180
+ "autopilot",
16181
+ "background",
16182
+ "bg",
16183
+ "goal",
16184
+ "jobs",
16185
+ "loop",
16186
+ "multitask",
16187
+ "queue",
16188
+ "remote-control",
16189
+ "schedule",
16190
+ "steer",
16191
+ // Native terminal UI
16192
+ "copy",
16193
+ "debug",
16194
+ "feedback",
16195
+ "heapdump",
16196
+ "share",
16197
+ "shell",
16198
+ // Plugin and MCP management
16199
+ "marketplace",
16200
+ "mcp",
16201
+ "plugins",
16202
+ "reload-plugins"
16203
+ ]);
16204
+ var COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES = ["__", "hooks-"];
16205
+ function isExcludedLiveCommand(name, kind, extra = {}) {
16206
+ const normalized = name.trim().replace(/^\//u, "");
16207
+ if (new Set(extra.names ?? []).has(normalized))
16208
+ return true;
16209
+ if (extra.prefixes?.some((prefix) => normalized.startsWith(prefix)))
16210
+ return true;
16211
+ if (kind === "skill")
16212
+ return false;
16213
+ return COMMON_EXCLUDED_LIVE_COMMANDS.has(normalized) || COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES.some((prefix) => normalized.startsWith(prefix));
16150
16214
  }
16151
- function installationVersion(value) {
16152
- if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
16153
- throw new Error("Harness returned an invalid version");
16154
- return value.trim().replace(/^v/, "");
16215
+ function liveHarnessCommandPrompt(catalog, idPrefix, commandId, argumentText) {
16216
+ if (!commandId.startsWith(idPrefix))
16217
+ return null;
16218
+ const descriptor = catalog.commands.find(({ id }) => id === commandId);
16219
+ if (!descriptor)
16220
+ return null;
16221
+ const text = typeof argumentText === "string" ? argumentText.trim() : "";
16222
+ return text ? `${descriptor.invocation} ${text}` : descriptor.invocation;
16155
16223
  }
16156
- function versionFromOutput(output) {
16157
- return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
16224
+ function mergeLiveHarnessCommands(builtIns, idPrefix, live, exclusions = {}) {
16225
+ if (!live)
16226
+ return builtIns;
16227
+ const invocations = new Set(builtIns.commands.map(({ invocation }) => invocation));
16228
+ const ids = new Set(builtIns.commands.map(({ id }) => id));
16229
+ const dynamic = [];
16230
+ for (const command of live) {
16231
+ const name = command.name.trim().replace(/^\//u, "");
16232
+ if (!name || /\s/u.test(name))
16233
+ continue;
16234
+ if (isExcludedLiveCommand(name, command.kind, exclusions))
16235
+ continue;
16236
+ const invocation = `/${name}`;
16237
+ const id = `${idPrefix}${name.replace(/[^A-Za-z0-9._:-]/gu, "-")}`.slice(0, 128);
16238
+ if (invocations.has(invocation) || ids.has(id))
16239
+ continue;
16240
+ const description = command.description?.trim().slice(0, 512);
16241
+ const parsed = harnessCommandDescriptorSchema.safeParse({
16242
+ id,
16243
+ invocation,
16244
+ label: name.slice(0, 128),
16245
+ ...description ? { description } : {},
16246
+ argumentMode: "text",
16247
+ kind: command.kind
16248
+ });
16249
+ if (!parsed.success)
16250
+ continue;
16251
+ invocations.add(invocation);
16252
+ ids.add(id);
16253
+ dynamic.push(parsed.data);
16254
+ }
16255
+ return harnessCommandCatalogSchema.parse({ commands: [...builtIns.commands, ...dynamic] });
16158
16256
  }
16159
16257
 
16258
+ // dist/acp-transport.js
16259
+ import { spawn, spawnSync } from "node:child_process";
16260
+ import { Readable, Writable } from "node:stream";
16261
+ import { execFile as execFile2 } from "node:child_process";
16262
+ import { promisify } from "node:util";
16263
+ import { setTimeout as delay } from "node:timers/promises";
16264
+
16160
16265
  // ../../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
16161
16266
  var AGENT_METHODS = {
16162
16267
  initialize: "initialize",
@@ -20527,18 +20632,19 @@ function isRecord5(value) {
20527
20632
  function errorText(error51) {
20528
20633
  return error51 instanceof Error ? error51.message : String(error51);
20529
20634
  }
20530
- function classifyStartupError(error51) {
20531
- if (error51 instanceof KiroTransportError)
20532
- return error51;
20635
+ function classifyStartupError(error51, stderr = "") {
20533
20636
  if (error51 instanceof KiroExecutableError) {
20534
20637
  return new KiroTransportError("notInstalled", error51.message, { cause: error51 });
20535
20638
  }
20536
- const text = errorText(error51).toLowerCase();
20537
- if (text.includes("auth_required") || text.includes("authentication") || text.includes("not logged in") || text.includes("sign in") || text.includes("unauthorized")) {
20538
- return new KiroTransportError("authenticationRequired", "Kiro CLI authentication is required", {
20639
+ const text = `${errorText(error51)}
20640
+ ${stderr}`.toLowerCase();
20641
+ if (text.includes("auth_required") || text.includes("authentication") || text.includes("not logged in") || text.includes("not log in") || text.includes("sign in") || text.includes("unauthorized")) {
20642
+ return new KiroTransportError("authenticationRequired", "Kiro CLI authentication is required (run `kiro-cli login`)", {
20539
20643
  cause: error51
20540
20644
  });
20541
20645
  }
20646
+ if (error51 instanceof KiroTransportError)
20647
+ return error51;
20542
20648
  return new KiroTransportError("unavailable", "Kiro CLI could not start", { cause: error51 });
20543
20649
  }
20544
20650
  var KiroRequestTimeoutError = class extends KiroTransportError {
@@ -20648,9 +20754,8 @@ var KiroAcpTransport = class {
20648
20754
  });
20649
20755
  return { ...initialize, catalog: parseKiroCliModels(JSON.parse(stdout)) };
20650
20756
  } catch (error51) {
20651
- const classified = classifyStartupError(error51);
20652
20757
  await this.close().catch(() => void 0);
20653
- throw classified;
20758
+ throw classifyStartupError(error51, this.#stderrTail);
20654
20759
  }
20655
20760
  }
20656
20761
  async open(input) {
@@ -20738,9 +20843,8 @@ var KiroAcpTransport = class {
20738
20843
  replay
20739
20844
  };
20740
20845
  } catch (error51) {
20741
- const classified = classifyStartupError(error51);
20742
20846
  await this.close().catch(() => void 0);
20743
- throw classified;
20847
+ throw classifyStartupError(error51, this.#stderrTail);
20744
20848
  }
20745
20849
  }
20746
20850
  async setConfigOption(configId, value) {
@@ -21329,16 +21433,16 @@ var Diff = class {
21329
21433
  }
21330
21434
  }
21331
21435
  }
21332
- addToPath(path8, added, removed, oldPosInc, options) {
21333
- const last = path8.lastComponent;
21436
+ addToPath(path9, added, removed, oldPosInc, options) {
21437
+ const last = path9.lastComponent;
21334
21438
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
21335
21439
  return {
21336
- oldPos: path8.oldPos + oldPosInc,
21440
+ oldPos: path9.oldPos + oldPosInc,
21337
21441
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
21338
21442
  };
21339
21443
  } else {
21340
21444
  return {
21341
- oldPos: path8.oldPos + oldPosInc,
21445
+ oldPos: path9.oldPos + oldPosInc,
21342
21446
  lastComponent: { count: 1, added, removed, previousComponent: last }
21343
21447
  };
21344
21448
  }
@@ -22618,10 +22722,265 @@ async function readKiroSnapshot(location) {
22618
22722
  };
22619
22723
  }
22620
22724
 
22621
- // dist/kiro-adapter.js
22725
+ // dist/session-import.js
22726
+ import { opendir, readFile as readFile2, stat } from "node:fs/promises";
22727
+ import path7 from "node:path";
22728
+
22729
+ // ../../harness-adapter/dist/session-import.js
22730
+ import { lstat } from "node:fs/promises";
22731
+ var SessionImportChangedError = class extends Error {
22732
+ constructor(message = "Native Session changed during discovery; refresh and retry") {
22733
+ super(message);
22734
+ this.name = "SessionImportChangedError";
22735
+ }
22736
+ };
22737
+ function isMissingFileError(error51) {
22738
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
22739
+ }
22740
+ function sameFileFingerprint(left, right) {
22741
+ return left === null || right === null ? left === right : left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
22742
+ }
22743
+ var STORAGE_ACCESS_ERRORS = /* @__PURE__ */ new Set(["EACCES", "EPERM", "EIO", "EMFILE", "ENFILE"]);
22744
+ function isStorageAccessError(error51) {
22745
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && typeof error51.code === "string" && STORAGE_ACCESS_ERRORS.has(error51.code);
22746
+ }
22747
+ async function optionalLstat(file2) {
22748
+ try {
22749
+ return await lstat(file2);
22750
+ } catch (error51) {
22751
+ if (isMissingFileError(error51))
22752
+ return null;
22753
+ throw error51;
22754
+ }
22755
+ }
22756
+ async function readStableFiles(files, read) {
22757
+ const before = await Promise.all(files.map(optionalLstat));
22758
+ const value = await read(before);
22759
+ const after = await Promise.all(files.map(optionalLstat));
22760
+ if (before.some((info, index) => !sameFileFingerprint(info, after[index] ?? null)))
22761
+ throw new SessionImportChangedError();
22762
+ return value;
22763
+ }
22764
+ function sessionImportTitle(value, maxLength = HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) {
22765
+ if (typeof value !== "string")
22766
+ return null;
22767
+ const normalized = value.replaceAll("\0", "").replaceAll(/\s+/gu, " ").trim();
22768
+ if (!normalized)
22769
+ return null;
22770
+ if (normalized.length <= maxLength)
22771
+ return normalized;
22772
+ const characters = [...normalized];
22773
+ if (characters.length <= maxLength)
22774
+ return normalized;
22775
+ return `${characters.slice(0, maxLength - 1).join("").trimEnd()}…`;
22776
+ }
22777
+ function sessionImportCandidate(input) {
22778
+ const time3 = typeof input.updatedAt === "number" ? input.updatedAt : typeof input.updatedAt === "string" ? Date.parse(input.updatedAt) : Number.NaN;
22779
+ const parsed = harnessSessionImportCandidateSchema.safeParse({
22780
+ nativeSessionId: input.nativeSessionId,
22781
+ cwd: input.cwd,
22782
+ title: typeof input.title === "string" && input.title.trim().length > 0 ? input.title : null,
22783
+ updatedAt: Math.floor(time3),
22784
+ // Unknown must stay unknown; only an explicit boolean is a native statement.
22785
+ running: typeof input.running === "boolean" ? input.running : null
22786
+ });
22787
+ return parsed.success ? parsed.data : null;
22788
+ }
22789
+ var SessionImportScope = class {
22790
+ #abort = new AbortController();
22791
+ #options;
22792
+ #pending = /* @__PURE__ */ new Set();
22793
+ constructor(options) {
22794
+ this.#options = options;
22795
+ }
22796
+ #closed() {
22797
+ return {
22798
+ ok: false,
22799
+ error: { code: "invalidState", message: this.#options.closedMessage, retryable: false }
22800
+ };
22801
+ }
22802
+ read(operation) {
22803
+ const signal = this.#abort.signal;
22804
+ if (signal.aborted)
22805
+ return Promise.resolve(this.#closed());
22806
+ let started;
22807
+ try {
22808
+ started = operation(signal);
22809
+ } catch (error51) {
22810
+ started = Promise.reject(error51 instanceof Error ? error51 : new Error("Session read failed"));
22811
+ }
22812
+ const request = started.then((value) => signal.aborted ? this.#closed() : { ok: true, value }).catch(() => signal.aborted ? this.#closed() : {
22813
+ ok: false,
22814
+ error: {
22815
+ code: "unavailable",
22816
+ message: this.#options.unavailableMessage,
22817
+ retryable: true
22818
+ }
22819
+ }).finally(() => this.#pending.delete(request));
22820
+ this.#pending.add(request);
22821
+ return request;
22822
+ }
22823
+ /** `read` for `resolveCandidate`: a null source is the selected Session having disappeared. */
22824
+ async resolve(operation) {
22825
+ const result = await this.read(operation);
22826
+ if (!result.ok)
22827
+ return result;
22828
+ return result.value ? { ok: true, value: result.value } : {
22829
+ ok: false,
22830
+ error: {
22831
+ code: "sessionNotFound",
22832
+ message: this.#options.notFoundMessage,
22833
+ retryable: false
22834
+ }
22835
+ };
22836
+ }
22837
+ /** Idempotent. Resolves after every started read has settled. */
22838
+ async close() {
22839
+ this.#abort.abort();
22840
+ await Promise.allSettled(this.#pending);
22841
+ }
22842
+ };
22843
+
22844
+ // dist/session-import.js
22845
+ var MAX_METADATA_BYTES = 1024 * 1024;
22846
+ var NON_WORKSPACE_DIRECTORIES = /* @__PURE__ */ new Set(["cli"]);
22622
22847
  function isRecord11(value) {
22623
22848
  return typeof value === "object" && value !== null && !Array.isArray(value);
22624
22849
  }
22850
+ function userText(row) {
22851
+ const { content, text } = row.payload;
22852
+ return kiroVisibleText(typeof content === "string" ? content : text ?? "");
22853
+ }
22854
+ var KiroSessionImport = class {
22855
+ #environment;
22856
+ #scope = new SessionImportScope({
22857
+ closedMessage: "Kiro Session import is closed",
22858
+ unavailableMessage: "Kiro sessions could not be read; close native clients, check storage access and retry",
22859
+ notFoundMessage: "Kiro Session is no longer importable"
22860
+ });
22861
+ constructor(environment) {
22862
+ this.#environment = { ...environment };
22863
+ }
22864
+ listCandidates() {
22865
+ return this.#scope.read(async (signal) => {
22866
+ const candidates = [];
22867
+ for (const [, directories] of await this.#sessionDirectories(signal)) {
22868
+ if (directories.length !== 1 || !directories[0])
22869
+ continue;
22870
+ try {
22871
+ const candidate = await this.#candidate(directories[0], signal);
22872
+ if (candidate)
22873
+ candidates.push(candidate);
22874
+ } catch (error51) {
22875
+ if (!(error51 instanceof SessionImportChangedError))
22876
+ throw error51;
22877
+ }
22878
+ }
22879
+ return candidates;
22880
+ });
22881
+ }
22882
+ resolveCandidate(nativeSessionId) {
22883
+ return this.#scope.resolve(async (signal) => {
22884
+ const directories = (await this.#sessionDirectories(signal)).get(nativeSessionId);
22885
+ if (directories?.length !== 1 || !directories[0])
22886
+ return null;
22887
+ const candidate = await this.#candidate(directories[0], signal);
22888
+ if (!candidate)
22889
+ return null;
22890
+ return {
22891
+ candidate,
22892
+ nativeRef: nativeSessionRefSchema.parse({
22893
+ harnessId: "kiro-cli",
22894
+ nativeSessionId,
22895
+ formatVersion: 1
22896
+ })
22897
+ };
22898
+ });
22899
+ }
22900
+ close() {
22901
+ return this.#scope.close();
22902
+ }
22903
+ /** Session ID to every directory claiming it. Enumerated links are not followed. */
22904
+ async #sessionDirectories(signal) {
22905
+ const root = path7.join(kiroHomeDir(this.#environment), "sessions");
22906
+ const found = /* @__PURE__ */ new Map();
22907
+ const info = await optionalLstat(root);
22908
+ if (!info)
22909
+ return found;
22910
+ if (!info.isDirectory())
22911
+ throw new Error("Kiro Session store is not a directory");
22912
+ for await (const workspace of await opendir(root)) {
22913
+ signal.throwIfAborted();
22914
+ if (!workspace.isDirectory() || NON_WORKSPACE_DIRECTORIES.has(workspace.name))
22915
+ continue;
22916
+ const workspaceDirectory = path7.join(root, workspace.name);
22917
+ const sessions = await opendir(workspaceDirectory).catch((error51) => {
22918
+ if (isMissingFileError(error51))
22919
+ return null;
22920
+ throw error51;
22921
+ });
22922
+ if (!sessions)
22923
+ continue;
22924
+ for await (const session of sessions) {
22925
+ signal.throwIfAborted();
22926
+ if (!session.isDirectory())
22927
+ continue;
22928
+ const directories = found.get(session.name) ?? [];
22929
+ directories.push(path7.join(workspaceDirectory, session.name));
22930
+ found.set(session.name, directories);
22931
+ }
22932
+ }
22933
+ return found;
22934
+ }
22935
+ async #candidate(sessionDirectory, signal) {
22936
+ signal.throwIfAborted();
22937
+ const files = [
22938
+ path7.join(sessionDirectory, "session.json"),
22939
+ path7.join(sessionDirectory, "messages.jsonl")
22940
+ ];
22941
+ return readStableFiles(files, async ([metadata, messages]) => {
22942
+ if (!metadata?.isFile() || !messages?.isFile() || metadata.size > MAX_METADATA_BYTES)
22943
+ return null;
22944
+ try {
22945
+ const meta3 = JSON.parse(await readFile2(files[0], { encoding: "utf8", signal }));
22946
+ if (!isRecord11(meta3) || meta3.id !== path7.basename(sessionDirectory))
22947
+ return null;
22948
+ const workspacePath = Array.isArray(meta3.workspacePaths) ? meta3.workspacePaths[0] : void 0;
22949
+ if (typeof workspacePath !== "string" || !path7.isAbsolute(workspacePath) || workspacePath.includes("\0"))
22950
+ return null;
22951
+ const cwd = path7.resolve(workspacePath);
22952
+ if (!(await stat(cwd)).isDirectory())
22953
+ return null;
22954
+ signal.throwIfAborted();
22955
+ const rows = await readKiroSessionMessages({
22956
+ sessionDirectory,
22957
+ sessionMeta: meta3,
22958
+ cwd
22959
+ });
22960
+ const firstUser = rows.find((row) => row.payload.type === "user");
22961
+ if (!firstUser)
22962
+ return null;
22963
+ const modified = typeof meta3.lastModifiedAt === "string" ? Date.parse(meta3.lastModifiedAt) : Number.NaN;
22964
+ return sessionImportCandidate({
22965
+ nativeSessionId: meta3.id,
22966
+ cwd,
22967
+ title: sessionImportTitle(meta3.title) ?? sessionImportTitle(userText(firstUser)),
22968
+ updatedAt: Number.isFinite(modified) && modified >= 0 ? modified : messages.mtimeMs
22969
+ });
22970
+ } catch (error51) {
22971
+ signal.throwIfAborted();
22972
+ if (isStorageAccessError(error51))
22973
+ throw error51;
22974
+ return null;
22975
+ }
22976
+ });
22977
+ }
22978
+ };
22979
+
22980
+ // dist/kiro-adapter.js
22981
+ function isRecord12(value) {
22982
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22983
+ }
22625
22984
  var KIRO_SESSION_CAPABILITIES = {
22626
22985
  configuration: {
22627
22986
  selectModel: true,
@@ -22646,6 +23005,7 @@ var KiroAdapter = class {
22646
23005
  harnessId = harnessIdSchema.parse("kiro-cli");
22647
23006
  commandCatalog = KIRO_COMMAND_CATALOG;
22648
23007
  liveCommandCatalog = true;
23008
+ sessionImport;
22649
23009
  #options;
22650
23010
  #deps;
22651
23011
  #sessions = /* @__PURE__ */ new Set();
@@ -22654,9 +23014,10 @@ var KiroAdapter = class {
22654
23014
  constructor(options = {}, deps = {}) {
22655
23015
  this.#options = options;
22656
23016
  this.#deps = deps;
23017
+ this.sessionImport = new KiroSessionImport({ ...process.env, ...options.environment });
22657
23018
  }
22658
23019
  async inspect(input = {}) {
22659
- const cwd = path7.resolve(input.cwd ?? process.cwd());
23020
+ const cwd = path8.resolve(input.cwd ?? process.cwd());
22660
23021
  const cached2 = this.#inspectionCache.get(cwd);
22661
23022
  if (!input.refresh && cached2) {
22662
23023
  if (cached2.refreshAfter <= Date.now()) {
@@ -22717,7 +23078,7 @@ var KiroAdapter = class {
22717
23078
  const transport = this.#createTransport(cwd);
22718
23079
  try {
22719
23080
  const initialize = await transport.inspect();
22720
- const modelCatalog = isRecord11(initialize) && isRecord11(initialize.catalog) ? initialize.catalog : parseKiroModelCatalog(isRecord11(initialize) ? initialize.configOptions : void 0);
23081
+ const modelCatalog = isRecord12(initialize) && isRecord12(initialize.catalog) ? initialize.catalog : parseKiroModelCatalog(isRecord12(initialize) ? initialize.configOptions : void 0);
22721
23082
  if (modelCatalog.models.length === 0)
22722
23083
  throw new Error("Kiro returned no native model catalog");
22723
23084
  return {
@@ -22733,7 +23094,7 @@ var KiroAdapter = class {
22733
23094
  status: "error",
22734
23095
  error: {
22735
23096
  code: "authenticationRequired",
22736
- message: "Kiro CLI authentication is required",
23097
+ message: "Kiro CLI authentication is required (run `kiro-cli login`)",
22737
23098
  retryable: false
22738
23099
  }
22739
23100
  };
@@ -22971,6 +23332,7 @@ var KiroAdapter = class {
22971
23332
  async close() {
22972
23333
  try {
22973
23334
  await Promise.all([
23335
+ this.sessionImport.close(),
22974
23336
  ...this.#inspectionInFlight.values(),
22975
23337
  ...[...this.#sessions].map((session) => session.close())
22976
23338
  ]);
@@ -23138,7 +23500,7 @@ var KiroSession = class {
23138
23500
  }
23139
23501
  };
23140
23502
  } catch (error51) {
23141
- if (this.#newSessionWithoutTurn && isRecord11(error51) && error51.code === "ENOENT") {
23503
+ if (this.#newSessionWithoutTurn && isRecord12(error51) && error51.code === "ENOENT") {
23142
23504
  return { ok: true, value: { turns: [], state: this.#state() } };
23143
23505
  }
23144
23506
  return {
@@ -23199,7 +23561,7 @@ var KiroSession = class {
23199
23561
  kind: "event",
23200
23562
  event: { type: "turn.started", turnId }
23201
23563
  });
23202
- const userText = command.input.map((i) => i.text).join("\n");
23564
+ const userText2 = command.input.map((i) => i.text).join("\n");
23203
23565
  const output = new KiroTurnOutput(turnId, this.#cwd, (event) => this.#channel.emit(event));
23204
23566
  let assignedUserMessageId;
23205
23567
  const stopped = new Promise((_resolve, reject) => {
@@ -23210,14 +23572,14 @@ var KiroSession = class {
23210
23572
  try {
23211
23573
  const promptResult = await Promise.race([
23212
23574
  stopped,
23213
- this.#transport.runTurn(userText, (event) => {
23575
+ this.#transport.runTurn(userText2, (event) => {
23214
23576
  if (this.#closed || this.#activeTurnId !== turnId)
23215
23577
  return;
23216
23578
  output.accept(event);
23217
23579
  if (event.type === "usage") {
23218
23580
  this.observeUsage(event);
23219
23581
  const meta3 = event.metadata?.kiro;
23220
- if (isRecord11(meta3) && meta3.kind === "user_message_id_assigned" && typeof meta3.userMessageId === "string") {
23582
+ if (isRecord12(meta3) && meta3.kind === "user_message_id_assigned" && typeof meta3.userMessageId === "string") {
23221
23583
  assignedUserMessageId = meta3.userMessageId;
23222
23584
  }
23223
23585
  } else if (event.type === "compaction.completed") {
@@ -23299,7 +23661,7 @@ var KiroSession = class {
23299
23661
  });
23300
23662
  })
23301
23663
  ]);
23302
- if (isRecord11(promptResult) && promptResult.stopReason === "cancelled") {
23664
+ if (isRecord12(promptResult) && promptResult.stopReason === "cancelled") {
23303
23665
  turnOutcome = { status: "cancelled", reason: "User cancelled" };
23304
23666
  } else {
23305
23667
  turnOutcome = { status: "succeeded" };
@@ -23628,7 +23990,7 @@ var KiroSession = class {
23628
23990
  }
23629
23991
  });
23630
23992
  const result2 = await Promise.race([stopped, this.#transport.compact()]);
23631
- if (isRecord11(result2) && result2.success === false) {
23993
+ if (isRecord12(result2) && result2.success === false) {
23632
23994
  throw new Error("Kiro context compaction did not complete");
23633
23995
  }
23634
23996
  this.#channel.emit({
@@ -23780,6 +24142,7 @@ function createKiroInstallation(environment, command) {
23780
24142
  latestVersion: "Unknown",
23781
24143
  updateAvailable: false,
23782
24144
  canUpdate: false,
24145
+ messageCode: "kiro-native-updater",
23783
24146
  message: "Use Kiro CLI's original installer or native updater to check for and install updates."
23784
24147
  };
23785
24148
  };
@@ -23792,7 +24155,13 @@ function createHarnessAdapter(context) {
23792
24155
  return Object.assign(new KiroAdapter({
23793
24156
  ...environment[CODEXHOST_KIRO_COMMAND] ? { command: environment[CODEXHOST_KIRO_COMMAND] } : {},
23794
24157
  environment
23795
- }), { installation: createKiroInstallation(environment, environment[CODEXHOST_KIRO_COMMAND]) });
24158
+ }), {
24159
+ installation: createKiroInstallation(environment, environment[CODEXHOST_KIRO_COMMAND]),
24160
+ install: createHarnessInstaller(environment, {
24161
+ posix: "https://cli.kiro.dev/install",
24162
+ windows: "https://cli.kiro.dev/install.ps1"
24163
+ })
24164
+ });
23796
24165
  }
23797
24166
  export {
23798
24167
  CODEXHOST_KIRO_COMMAND,