khala-cli 0.4.7 → 0.4.8

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.
Files changed (27) hide show
  1. package/README.md +18 -1
  2. package/dist/{chunk-25AX7UMF.mjs → chunk-2DHIAFEV.mjs} +5 -5
  3. package/dist/{chunk-OAFYPBCP.mjs → chunk-2VCAW4GH.mjs} +1 -1
  4. package/dist/{chunk-LNG3ZZBK.mjs → chunk-54XFVSEC.mjs} +1 -1
  5. package/dist/{chunk-JEI32DEA.mjs → chunk-5BQTYU66.mjs} +285 -33
  6. package/dist/{chunk-YIHRHD7W.mjs → chunk-5LIE5GUU.mjs} +1 -1
  7. package/dist/{chunk-S3FX7VCY.mjs → chunk-5PUQT3YS.mjs} +200 -17
  8. package/dist/{chunk-APIWKRKG.mjs → chunk-7HBRFY3Z.mjs} +1 -1
  9. package/dist/{chunk-SU6362YU.mjs → chunk-APMWDF6B.mjs} +1 -1
  10. package/dist/{chunk-C5SMOUTO.mjs → chunk-BKLW2SPG.mjs} +27 -9
  11. package/dist/{chunk-WNOIHCCC.mjs → chunk-CBPLCCRZ.mjs} +1 -1
  12. package/dist/{chunk-IG2NU5J6.mjs → chunk-CJTCU755.mjs} +4 -4
  13. package/dist/{chunk-4LSCOWWN.mjs → chunk-FH34B3I3.mjs} +6 -8
  14. package/dist/chunk-FV32AQTC.mjs +40 -0
  15. package/dist/{chunk-L7L6UNXN.mjs → chunk-H3K4GA2P.mjs} +9 -9
  16. package/dist/{chunk-3OFKVYOX.mjs → chunk-IQJQ4RF5.mjs} +1 -1
  17. package/dist/{chunk-TOBQUAPD.mjs → chunk-RNDUFTBF.mjs} +56 -32
  18. package/dist/{chunk-ODTSGEID.mjs → chunk-VAI7IUI4.mjs} +3 -3
  19. package/dist/{chunk-OP2HZ7EM.mjs → chunk-VKQ3KUYO.mjs} +16 -2
  20. package/dist/{chunk-K6EJSZYO.mjs → chunk-VUSV2ADL.mjs} +13 -15
  21. package/dist/{chunk-7V2YQIRI.mjs → chunk-W6R4UJUQ.mjs} +12 -5
  22. package/dist/{chunk-6YEYXZZB.mjs → chunk-Z4JF2M5C.mjs} +7 -8
  23. package/dist/{chunk-W5HS2PQO.mjs → chunk-ZJ4W7P33.mjs} +8 -8
  24. package/dist/khala.mjs +11 -11
  25. package/package.json +1 -1
  26. package/dist/chunk-5RGEO5HN.mjs +0 -142
  27. package/dist/{chunk-U3MKSPRO.mjs → chunk-NKX3SLS7.mjs} +37 -37
@@ -1,20 +1,22 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
  import {
3
3
  bundle
4
- } from "./chunk-SU6362YU.mjs";
4
+ } from "./chunk-APMWDF6B.mjs";
5
5
  import {
6
6
  CURSOR_WORKSPACE_ENV,
7
7
  adapterFor
8
- } from "./chunk-JEI32DEA.mjs";
9
- import "./chunk-OP2HZ7EM.mjs";
10
- import "./chunk-WNOIHCCC.mjs";
11
- import "./chunk-3OFKVYOX.mjs";
12
- import "./chunk-U3MKSPRO.mjs";
13
- import "./chunk-APIWKRKG.mjs";
8
+ } from "./chunk-5BQTYU66.mjs";
9
+ import "./chunk-VKQ3KUYO.mjs";
10
+ import "./chunk-CBPLCCRZ.mjs";
11
+ import "./chunk-IQJQ4RF5.mjs";
12
+ import {
13
+ isHarnessId
14
+ } from "./chunk-NKX3SLS7.mjs";
15
+ import "./chunk-7HBRFY3Z.mjs";
14
16
 
15
17
  // src/install/main.ts
16
18
  import { spawnSync } from "node:child_process";
17
- import * as fs2 from "node:fs/promises";
19
+ import * as fs3 from "node:fs/promises";
18
20
  import os from "node:os";
19
21
  import path from "node:path";
20
22
 
@@ -79,6 +81,35 @@ function mergeCodexHooks(config, action, hooksFragment = codexHooksFragment()) {
79
81
  return { config, warnings };
80
82
  }
81
83
 
84
+ // src/install/mcp.ts
85
+ var USAGE = "usage: khala install mcp --print [--harness <id>]";
86
+ async function runMcpInstall(flags, deps) {
87
+ const stdout = deps.stdout ?? ((line) => {
88
+ process.stdout.write(line + "\n");
89
+ });
90
+ const stderr = deps.stderr ?? ((line) => {
91
+ process.stderr.write(line + "\n");
92
+ });
93
+ let harness = "generic";
94
+ let print = false;
95
+ for (let i = 0; i < flags.length; i++) {
96
+ if (flags[i] === "--print" && !print) print = true;
97
+ else if (flags[i] === "--harness" && isHarnessId(flags[i + 1])) harness = flags[++i];
98
+ else {
99
+ stderr(USAGE);
100
+ return 1;
101
+ }
102
+ }
103
+ if (!print) {
104
+ stderr(USAGE);
105
+ return 1;
106
+ }
107
+ const args = ["-y", "khala-cli", "mcp", "--harness", harness];
108
+ stdout(JSON.stringify({ mcpServers: { khala: { command: "npx", args } } }, null, 2));
109
+ stdout(`npx ${args.join(" ")}`);
110
+ return 0;
111
+ }
112
+
82
113
  // src/install/cursor.ts
83
114
  import * as fs from "node:fs/promises";
84
115
  var CURSOR_HOOK_EVENTS = ["beforeSubmitPrompt", "postToolUse", "stop"];
@@ -195,9 +226,120 @@ async function installCursor(input) {
195
226
  return 0;
196
227
  }
197
228
 
229
+ // src/install/opencode.ts
230
+ import * as fs2 from "node:fs/promises";
231
+ function opencodePaths(input) {
232
+ const { path: path2, home, env, platform } = input;
233
+ const configHome = env.XDG_CONFIG_HOME && path2.isAbsolute(env.XDG_CONFIG_HOME) ? env.XDG_CONFIG_HOME : path2.join(home, ".config");
234
+ const configDir = path2.join(configHome, "opencode");
235
+ const { prefix } = cursorPaths(input);
236
+ return {
237
+ configDir,
238
+ configFile: path2.join(configDir, "opencode.json"),
239
+ prefix,
240
+ bin: platform === "win32" ? path2.join(prefix, "khala.cmd") : path2.join(prefix, "bin", "khala")
241
+ };
242
+ }
243
+ function opencodeMcpEntry(platform, bin) {
244
+ return {
245
+ type: "local",
246
+ command: [...platform === "win32" ? ["cmd", "/c"] : [], bin, "mcp", "--harness", "opencode"],
247
+ environment: {},
248
+ enabled: true
249
+ };
250
+ }
251
+ var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
252
+ var isPlugin = (spec) => spec === "khala-opencode" || spec.startsWith("khala-opencode@") || /^file:.*[/\\]khala-opencode-[^/\\]+\.tgz$/u.test(spec);
253
+ var isMcp = (entry) => {
254
+ if (!isObject2(entry) || !Array.isArray(entry.command)) return false;
255
+ const at = entry.command.indexOf("--harness");
256
+ return entry.command.includes("mcp") && at >= 0 && entry.command[at + 1] === "opencode";
257
+ };
258
+ function mergeOpenCodeConfig(config, plugin, previousOverride) {
259
+ if (!isObject2(config) || config.plugin !== void 0 && (!Array.isArray(config.plugin) || config.plugin.some((p) => typeof p !== "string")) || config.mcp !== void 0 && !isObject2(config.mcp)) return { error: "invalid_config" };
260
+ const plugins = (config.plugin ?? []).filter((spec) => !isPlugin(spec) && spec !== previousOverride && spec !== plugin);
261
+ if (plugin) plugins.push(plugin);
262
+ const next = { ...config };
263
+ if (plugins.length) next.plugin = plugins;
264
+ else delete next.plugin;
265
+ if (isObject2(config.mcp) && isMcp(config.mcp.khala)) {
266
+ const mcp = { ...config.mcp };
267
+ delete mcp.khala;
268
+ if (Object.keys(mcp).length) next.mcp = mcp;
269
+ else delete next.mcp;
270
+ }
271
+ return { config: next };
272
+ }
273
+ async function installOpenCode(input) {
274
+ const { paths, uninstall, stdout, stderr } = input;
275
+ try {
276
+ await fs2.stat(paths.configFile.replace(/\.json$/u, ".jsonc"));
277
+ stderr(`khala: opencode.jsonc exists in ${paths.configDir}; ${uninstall ? "remove" : "merge"} the Khala config manually or convert it to opencode.json before retrying`);
278
+ return 1;
279
+ } catch (error) {
280
+ if (error.code !== "ENOENT") throw error;
281
+ }
282
+ let text = null;
283
+ try {
284
+ text = await fs2.readFile(paths.configFile, "utf8");
285
+ } catch (error) {
286
+ if (error.code !== "ENOENT") throw error;
287
+ }
288
+ let config;
289
+ try {
290
+ config = text?.trim() ? JSON.parse(text.replace(/^\uFEFF/u, "")) : {};
291
+ } catch {
292
+ stderr(`khala: invalid JSON in ${paths.configFile}`);
293
+ return 1;
294
+ }
295
+ const marker = paths.configFile + ".khala-plugin";
296
+ let previousOverride;
297
+ try {
298
+ previousOverride = (await fs2.readFile(marker, "utf8")).trim();
299
+ } catch (error) {
300
+ if (error.code !== "ENOENT") throw error;
301
+ }
302
+ const merged = mergeOpenCodeConfig(config, uninstall ? null : input.plugin, previousOverride ?? input.plugin ?? void 0);
303
+ if ("error" in merged) {
304
+ stderr(`khala: invalid config in ${paths.configFile}`);
305
+ return 1;
306
+ }
307
+ if (!uninstall && input.plugin === null) {
308
+ if (isObject2(config) && isObject2(config.mcp) && Object.hasOwn(config.mcp, "khala") && !isMcp(config.mcp.khala)) {
309
+ stderr(`khala: refusing to overwrite existing mcp.khala in ${paths.configFile}; remove or rename it before retrying`);
310
+ return 1;
311
+ }
312
+ merged.config.mcp = { ...merged.config.mcp, khala: opencodeMcpEntry(input.platform, paths.bin) };
313
+ }
314
+ if (!uninstall && input.install && !input.install()) return 1;
315
+ if (uninstall && text === null) return 0;
316
+ await fs2.mkdir(paths.configDir, { recursive: true });
317
+ if (!uninstall && text !== null) {
318
+ try {
319
+ await fs2.writeFile(paths.configFile + ".khala-bak", text, { flag: "wx" });
320
+ } catch (error) {
321
+ if (error.code !== "EEXIST") throw error;
322
+ }
323
+ }
324
+ const next = JSON.stringify(merged.config, null, 2) + "\n";
325
+ if (next !== text) await fs2.writeFile(paths.configFile, next);
326
+ if (uninstall || input.plugin === null) await fs2.rm(marker, { force: true });
327
+ else await fs2.writeFile(marker, input.plugin + "\n");
328
+ stdout(uninstall ? `removed the Khala plugin and MCP entry from ${paths.configFile}; delete ${paths.prefix} to remove the CLI` : input.plugin ? `configured ${paths.configFile}; restart OpenCode to load the Khala plugin` : "OpenCode installed in MCP-only mode (Async, no wake); re-run khala install opencode after updating");
329
+ return 0;
330
+ }
331
+ async function opencodePluginPublished(version, fetchRegistry = fetch) {
332
+ try {
333
+ const response = await fetchRegistry(`https://registry.npmjs.org/khala-opencode/${encodeURIComponent(version)}`, { signal: AbortSignal.timeout(3e3) });
334
+ return response.ok;
335
+ } catch {
336
+ return false;
337
+ }
338
+ }
339
+
198
340
  // src/install/main.ts
199
341
  var MCP_MARKER = "# Khala MCP server, managed by `khala install codex`";
200
- var USAGE = "usage: khala install codex [--codex-home <dir>] [--uninstall] | khala install cursor [--uninstall]";
342
+ var USAGE2 = "usage: khala install codex [--codex-home <dir>] [--uninstall] | khala install cursor [--uninstall] | khala install opencode [--uninstall] | khala install mcp --print [--harness <id>]";
201
343
  async function runCursorInstall(flags, deps) {
202
344
  const env = deps.env ?? process.env;
203
345
  const stdout = deps.stdout ?? ((line) => {
@@ -210,7 +352,7 @@ async function runCursorInstall(flags, deps) {
210
352
  for (const flag of flags) {
211
353
  if (flag === "--uninstall") uninstall = true;
212
354
  else {
213
- stderr(USAGE);
355
+ stderr(USAGE2);
214
356
  return 1;
215
357
  }
216
358
  }
@@ -239,6 +381,45 @@ async function runCursorInstall(flags, deps) {
239
381
  }
240
382
  });
241
383
  }
384
+ async function runOpenCodeInstall(flags, deps) {
385
+ const env = deps.env ?? process.env;
386
+ const stdout = deps.stdout ?? ((line) => {
387
+ process.stdout.write(line + "\n");
388
+ });
389
+ const stderr = deps.stderr ?? ((line) => {
390
+ process.stderr.write(line + "\n");
391
+ });
392
+ if (flags.some((flag) => flag !== "--uninstall")) {
393
+ stderr(USAGE2);
394
+ return 1;
395
+ }
396
+ const uninstall = flags.includes("--uninstall");
397
+ const pkg = "package" in deps ? deps.package : bundle;
398
+ if (!pkg && !uninstall) {
399
+ stderr("khala: install runs from the published package (npx -y khala-cli install opencode)");
400
+ return 1;
401
+ }
402
+ const platform = deps.platform ?? process.platform;
403
+ const home = deps.home ?? (platform === "win32" ? env.USERPROFILE || os.homedir() : env.HOME || os.homedir());
404
+ const paths = opencodePaths({ platform, path: platform === "win32" ? path.win32 : path.posix, home, env });
405
+ const spec = pkg ? env.KHALA_INSTALL_SPEC || `${pkg.name}@${pkg.version}` : "";
406
+ const override = env.KHALA_OPENCODE_PLUGIN_SPEC;
407
+ const plugin = uninstall ? null : override || (await opencodePluginPublished(pkg.version, deps.fetchRegistry) ? `khala-opencode@${pkg.version}` : null);
408
+ return installOpenCode({
409
+ paths,
410
+ platform,
411
+ uninstall,
412
+ stdout,
413
+ stderr,
414
+ plugin,
415
+ install: () => {
416
+ stdout(`installing ${spec} into ${paths.prefix}`);
417
+ if ((deps.npmInstall ?? defaultNpmInstall)(paths.prefix, spec)) return true;
418
+ stderr("khala: npm install failed for " + spec);
419
+ return false;
420
+ }
421
+ });
422
+ }
242
423
  function shellQuote(value) {
243
424
  return /^[A-Za-z0-9_./-]+$/u.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
244
425
  }
@@ -278,7 +459,7 @@ function codexMcpBlock(bin, env) {
278
459
  }
279
460
  async function readOr(file, fallback) {
280
461
  try {
281
- return { text: await fs2.readFile(file, "utf8"), mode: (await fs2.stat(file)).mode & 511 };
462
+ return { text: await fs3.readFile(file, "utf8"), mode: (await fs3.stat(file)).mode & 511 };
282
463
  } catch (error) {
283
464
  if (error.code === "ENOENT") return { text: fallback, mode: 384 };
284
465
  throw error;
@@ -298,7 +479,7 @@ async function runCodexInstall(flags, deps) {
298
479
  if (flags[i] === "--uninstall") uninstall = true;
299
480
  else if (flags[i] === "--codex-home" && flags[i + 1]) codexHome = path.resolve(flags[++i]);
300
481
  else {
301
- stderr(USAGE);
482
+ stderr(USAGE2);
302
483
  return 1;
303
484
  }
304
485
  }
@@ -342,17 +523,17 @@ async function runCodexInstall(flags, deps) {
342
523
  return 1;
343
524
  }
344
525
  }
345
- await fs2.mkdir(codexHome, { recursive: true });
526
+ await fs3.mkdir(codexHome, { recursive: true });
346
527
  if (!uninstall) {
347
528
  try {
348
- await fs2.writeFile(hooksFile + ".khala-bak", hooks.text, { flag: "wx", mode: hooks.mode });
529
+ await fs3.writeFile(hooksFile + ".khala-bak", hooks.text, { flag: "wx", mode: hooks.mode });
349
530
  } catch (error) {
350
531
  if (error.code !== "EEXIST") throw error;
351
532
  }
352
533
  }
353
534
  for (const warning of merged.warnings) stderr(warning);
354
- await fs2.writeFile(hooksFile, JSON.stringify(merged.config, null, 2) + "\n", { mode: hooks.mode });
355
- await fs2.writeFile(tomlFile, nextToml.text, { mode: toml.mode });
535
+ await fs3.writeFile(hooksFile, JSON.stringify(merged.config, null, 2) + "\n", { mode: hooks.mode });
536
+ await fs3.writeFile(tomlFile, nextToml.text, { mode: toml.mode });
356
537
  if (uninstall) {
357
538
  stdout(`removed the Khala MCP server and hooks from ${codexHome}; delete ${prefix} to remove the CLI`);
358
539
  } else {
@@ -363,12 +544,13 @@ async function runCodexInstall(flags, deps) {
363
544
  }
364
545
  async function runInstall(argv, deps = {}) {
365
546
  const [target = "", ...flags] = argv;
547
+ if (target === "mcp") return runMcpInstall(flags, deps);
366
548
  const adapter = adapterFor(target);
367
549
  const run = adapter?.install;
368
550
  if (run) return run(flags, deps);
369
551
  (deps.stderr ?? ((line) => {
370
552
  process.stderr.write(line + "\n");
371
- }))(USAGE);
553
+ }))(USAGE2);
372
554
  return 1;
373
555
  }
374
556
  async function main(argv) {
@@ -381,6 +563,7 @@ export {
381
563
  runCodexInstall,
382
564
  runCursorInstall,
383
565
  runInstall,
566
+ runOpenCodeInstall,
384
567
  shellQuote,
385
568
  updateCodexToml
386
569
  };
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
 
3
3
  // <define:__KHALA_BUNDLE__>
4
- var define_KHALA_BUNDLE_default = { name: "khala-cli", version: "0.4.7" };
4
+ var define_KHALA_BUNDLE_default = { name: "khala-cli", version: "0.4.8" };
5
5
 
6
6
  export {
7
7
  define_KHALA_BUNDLE_default
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
  import {
3
3
  define_KHALA_BUNDLE_default
4
- } from "./chunk-APIWKRKG.mjs";
4
+ } from "./chunk-7HBRFY3Z.mjs";
5
5
 
6
6
  // src/bundle.ts
7
7
  var bundle = typeof define_KHALA_BUNDLE_default === "undefined" ? void 0 : define_KHALA_BUNDLE_default;
@@ -1,14 +1,18 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ sessionStartWakeChannels
4
+ } from "./chunk-FV32AQTC.mjs";
2
5
  import {
3
6
  adapterFor
4
- } from "./chunk-JEI32DEA.mjs";
5
- import "./chunk-OP2HZ7EM.mjs";
7
+ } from "./chunk-5BQTYU66.mjs";
8
+ import "./chunk-VKQ3KUYO.mjs";
6
9
  import {
10
+ filesForDir,
7
11
  resolveStateDir
8
- } from "./chunk-WNOIHCCC.mjs";
9
- import "./chunk-3OFKVYOX.mjs";
10
- import "./chunk-U3MKSPRO.mjs";
11
- import "./chunk-APIWKRKG.mjs";
12
+ } from "./chunk-CBPLCCRZ.mjs";
13
+ import "./chunk-IQJQ4RF5.mjs";
14
+ import "./chunk-NKX3SLS7.mjs";
15
+ import "./chunk-7HBRFY3Z.mjs";
12
16
 
13
17
  // hooks/claude-wake.ts
14
18
  import fs from "node:fs/promises";
@@ -86,9 +90,14 @@ async function watch(stdin, _argv, io = { stderr: process.stderr, env: process.e
86
90
  try {
87
91
  const parent = process.ppid;
88
92
  const input = JSON.parse(stdin);
89
- if (input?.hook_event_name !== "Stop" || typeof input.session_id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(input.session_id)) return 0;
93
+ if (!["Stop", "SessionStart"].includes(input?.hook_event_name) || typeof input.session_id !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(input.session_id)) return 0;
90
94
  const dir = resolveStateDir(adapterFor("claude").id, input.session_id, io.env);
91
95
  if (!(await fs.stat(dir)).isDirectory()) return 0;
96
+ if (input.hook_event_name === "SessionStart") {
97
+ if (io.env.CLAUDE_CODE_ENTRYPOINT !== "cli" || !["startup", "resume"].includes(input.source)) return 0;
98
+ const files = filesForDir(dir);
99
+ if (!(await sessionStartWakeChannels(files, io.env)).length) return 0;
100
+ }
92
101
  const nonce = randomBytes(6).toString("hex");
93
102
  const owner = path.join(dir, "watcher.json");
94
103
  temporary = path.join(dir, `.watcher-${nonce}.tmp`);
@@ -115,10 +124,19 @@ async function watch(stdin, _argv, io = { stderr: process.stderr, env: process.e
115
124
  const activity = await readJson(path.join(dir, "activity.json"));
116
125
  return activity?.state === "idle" && typeof activity.updatedAt === "string" && Number.isFinite(Date.parse(activity.updatedAt));
117
126
  };
127
+ const unread = async () => {
128
+ if (input.hook_event_name !== "SessionStart") return unreadMessages(dir);
129
+ let messages = 0;
130
+ for (const channel of await sessionStartWakeChannels(filesForDir(dir), io.env)) {
131
+ if (channel.connected && (await readJson(channel.files.mode))?.mode !== "async") messages += await unreadChannelMessages(channel.files.dir);
132
+ }
133
+ return messages;
134
+ };
118
135
  while (io.now().getTime() < deadline) {
119
136
  if (!await owns() || !parentAlive(parent)) return 0;
120
- if (await idle() && await unreadMessages(dir) > 0) {
121
- if (await unreadMessages(dir) > 0 && await idle() && await owns() && parentAlive(parent) && io.now().getTime() < deadline) {
137
+ if (input.hook_event_name === "SessionStart" && !(await sessionStartWakeChannels(filesForDir(dir), io.env)).length) return 0;
138
+ if (await idle() && await unread() > 0) {
139
+ if (await unread() > 0 && await idle() && await owns() && parentAlive(parent) && io.now().getTime() < deadline) {
122
140
  io.stderr.write(NOTICE);
123
141
  state = "woke";
124
142
  return 2;
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
  import {
3
3
  isHarnessId
4
- } from "./chunk-U3MKSPRO.mjs";
4
+ } from "./chunk-NKX3SLS7.mjs";
5
5
 
6
6
  // src/state.ts
7
7
  import { constants } from "node:fs";
@@ -4,14 +4,14 @@ import {
4
4
  CHANNEL_EVENT_TYPE,
5
5
  encodeChannelEvent,
6
6
  memberRenameContent
7
- } from "./chunk-LNG3ZZBK.mjs";
7
+ } from "./chunk-54XFVSEC.mjs";
8
8
  import {
9
9
  LISTENING_MODE_COMMAND_TYPE,
10
10
  LISTENING_MODE_MEMBER_KEY,
11
11
  memberListeningMode
12
- } from "./chunk-3OFKVYOX.mjs";
13
- import "./chunk-U3MKSPRO.mjs";
14
- import "./chunk-APIWKRKG.mjs";
12
+ } from "./chunk-IQJQ4RF5.mjs";
13
+ import "./chunk-NKX3SLS7.mjs";
14
+ import "./chunk-7HBRFY3Z.mjs";
15
15
 
16
16
  // src/matrix/session.ts
17
17
  import { createClient, ClientEvent, RoomEvent, MatrixEventEvent, SyncState, Direction, Method, EventType } from "matrix-js-sdk";
@@ -1,23 +1,21 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
- import {
3
- resolveSources
4
- } from "./chunk-5RGEO5HN.mjs";
5
2
  import {
6
3
  adapterFor,
7
- readListeningMode
8
- } from "./chunk-JEI32DEA.mjs";
4
+ readListeningMode,
5
+ resolveSources
6
+ } from "./chunk-5BQTYU66.mjs";
9
7
  import {
10
8
  listChannels,
11
9
  readCursor,
12
10
  readEntries
13
- } from "./chunk-OP2HZ7EM.mjs";
11
+ } from "./chunk-VKQ3KUYO.mjs";
14
12
  import {
15
13
  SESSION_ID_PATTERN,
16
14
  readJson,
17
15
  readStatus,
18
16
  sessionFiles,
19
17
  writeJsonAtomic
20
- } from "./chunk-WNOIHCCC.mjs";
18
+ } from "./chunk-CBPLCCRZ.mjs";
21
19
 
22
20
  // src/watch.ts
23
21
  import * as fs from "node:fs/promises";
@@ -206,7 +204,7 @@ ${WATCH_USAGE}`);
206
204
  };
207
205
  if (argv.length !== 0 && !(argv.length === 2 && argv[0] === "--session") && !(argv.length === 4 && argv[0] === "--harness" && argv[2] === "--session")) return invalid("invalid_arguments");
208
206
  const harness = resolveHarness(argv, process.env);
209
- if (harness === "invalid") return invalid("invalid_harness");
207
+ if (harness === "invalid" || !adapterFor(harness)?.codec) return invalid("invalid_harness");
210
208
  const index = argv.indexOf("--session");
211
209
  const id = index === -1 ? await resolveSessionId(harness, void 0, process.env) : argv[index + 1];
212
210
  if (!id) return invalid("session_unknown");
@@ -0,0 +1,40 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ listChannels
4
+ } from "./chunk-VKQ3KUYO.mjs";
5
+ import {
6
+ TERMINAL_SESSION_DETAILS,
7
+ readStateFile,
8
+ readStatus
9
+ } from "./chunk-CBPLCCRZ.mjs";
10
+ import {
11
+ validAgentRejoinSecret
12
+ } from "./chunk-NKX3SLS7.mjs";
13
+
14
+ // src/session-start-wake.ts
15
+ import { createHash } from "node:crypto";
16
+ import path from "node:path";
17
+ async function sessionStartWakeChannels(files, env) {
18
+ const channels = await listChannels(files);
19
+ const secret = (await readStateFile(files.dir, "rejoin.json"))?.secret;
20
+ const hash = validAgentRejoinSecret(secret) ? createHash("sha256").update(secret).digest("hex") : void 0;
21
+ const candidates = channels.length ? channels : [{ files, roomId: void 0 }];
22
+ const result = [];
23
+ for (const channel of candidates) {
24
+ const status = await readStatus(channel.files);
25
+ if (TERMINAL_SESSION_DETAILS.some((detail) => detail === status?.detail)) continue;
26
+ if (status?.state === "connected" || status?.state === "send_failed") {
27
+ result.push({ files: channel.files, connected: true });
28
+ continue;
29
+ }
30
+ if (!channel.roomId || !hash || !["joining", "disconnected"].includes(status?.state ?? "")) continue;
31
+ const authorization = await readStateFile(channel.files.dir, "resume.json");
32
+ if (!authorization || authorization.roomId !== channel.roomId || authorization.workspace !== path.resolve(env.PWD ?? process.cwd()) || authorization.secretHash !== hash || typeof authorization.link !== "string" || typeof authorization.label !== "string" || authorization.localCredentials && (authorization.localCredentials.transport !== "local" || authorization.localCredentials.roomId !== channel.roomId)) continue;
33
+ result.push({ files: channel.files, connected: false });
34
+ }
35
+ return result;
36
+ }
37
+
38
+ export {
39
+ sessionStartWakeChannels
40
+ };
@@ -2,7 +2,7 @@ import { createRequire as __khalaCreateRequire } from 'node:module'; const requi
2
2
  import {
3
3
  parseChannelLink,
4
4
  resolveLocalOwnerName
5
- } from "./chunk-ODTSGEID.mjs";
5
+ } from "./chunk-VAI7IUI4.mjs";
6
6
  import {
7
7
  LOCAL_AGENT_DEVICE_PREFIX,
8
8
  LOCAL_IDLE_EXIT_MS,
@@ -32,26 +32,26 @@ import {
32
32
  normalizeInitials,
33
33
  olderHelperVersion,
34
34
  readHelperFile
35
- } from "./chunk-25AX7UMF.mjs";
35
+ } from "./chunk-2DHIAFEV.mjs";
36
36
  import {
37
37
  KHALA_AGENT_VERSION
38
- } from "./chunk-YIHRHD7W.mjs";
38
+ } from "./chunk-5LIE5GUU.mjs";
39
39
  import {
40
40
  bundle
41
- } from "./chunk-SU6362YU.mjs";
41
+ } from "./chunk-APMWDF6B.mjs";
42
42
  import "./chunk-5GLTKWJ5.mjs";
43
43
  import {
44
44
  CHANNEL_EVENT_TYPE,
45
45
  decodeChannelEvent,
46
46
  encodeChannelEvent,
47
47
  memberRenameContent
48
- } from "./chunk-LNG3ZZBK.mjs";
48
+ } from "./chunk-54XFVSEC.mjs";
49
49
  import {
50
50
  StateError,
51
51
  ensureStateDir,
52
52
  readJson,
53
53
  writeJsonAtomic
54
- } from "./chunk-WNOIHCCC.mjs";
54
+ } from "./chunk-CBPLCCRZ.mjs";
55
55
  import {
56
56
  DEFAULT_LISTENING_MODE,
57
57
  LISTENING_MODE_COMMAND_TYPE,
@@ -59,7 +59,7 @@ import {
59
59
  decodeListeningMode,
60
60
  decodeListeningModeCommand,
61
61
  memberListeningMode
62
- } from "./chunk-3OFKVYOX.mjs";
62
+ } from "./chunk-IQJQ4RF5.mjs";
63
63
  import {
64
64
  LEGACY_HARNESSES,
65
65
  agentConfirmPagePath,
@@ -69,8 +69,8 @@ import {
69
69
  utf8Length,
70
70
  validAgentRejoinSecret,
71
71
  validAgentSessionId
72
- } from "./chunk-U3MKSPRO.mjs";
73
- import "./chunk-APIWKRKG.mjs";
72
+ } from "./chunk-NKX3SLS7.mjs";
73
+ import "./chunk-7HBRFY3Z.mjs";
74
74
 
75
75
  // src/local/cli.ts
76
76
  import { setTimeout as sleepDefault } from "node:timers/promises";
@@ -5,7 +5,7 @@ import {
5
5
  object,
6
6
  readMatrixUserId,
7
7
  version
8
- } from "./chunk-U3MKSPRO.mjs";
8
+ } from "./chunk-NKX3SLS7.mjs";
9
9
 
10
10
  // ../contracts/src/delivery/decode.ts
11
11
  var MAX_IDENTIFIER_BYTES = 512;