khala-cli 0.4.8 → 0.4.10

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 (53) hide show
  1. package/README.md +4 -4
  2. package/dist/THIRD_PARTY_NOTICES.txt +809 -0
  3. package/dist/chunk-2AMWQ7RB.mjs +1127 -0
  4. package/dist/chunk-3E5DH3Y6.mjs +9864 -0
  5. package/dist/{chunk-IQJQ4RF5.mjs → chunk-4BP7V3OP.mjs} +12 -1
  6. package/dist/{chunk-FV32AQTC.mjs → chunk-4BZQ4GVW.mjs} +10 -6
  7. package/dist/chunk-5JSGA6OB.mjs +1483 -0
  8. package/dist/chunk-6AQVW5W7.mjs +60 -0
  9. package/dist/{chunk-W6R4UJUQ.mjs → chunk-6J2PUM7L.mjs} +16 -9
  10. package/dist/chunk-6SUV3EW6.mjs +27 -0
  11. package/dist/{chunk-RNDUFTBF.mjs → chunk-ARIDZOTI.mjs} +499 -115
  12. package/dist/chunk-C2WEDMAF.mjs +15 -0
  13. package/dist/{chunk-Z4JF2M5C.mjs → chunk-CHC4VZF5.mjs} +9 -9
  14. package/dist/chunk-CKLCR5G4.mjs +1369 -0
  15. package/dist/chunk-EVT2DWNZ.mjs +58 -0
  16. package/dist/chunk-FJVVSKZ3.mjs +22 -0
  17. package/dist/{chunk-APMWDF6B.mjs → chunk-G3NMB4PY.mjs} +4 -2
  18. package/dist/chunk-HHEZVPRR.mjs +7 -0
  19. package/dist/{chunk-54XFVSEC.mjs → chunk-JKOJQTFT.mjs} +103 -5
  20. package/dist/{chunk-ZJ4W7P33.mjs → chunk-NDMFD5IM.mjs} +15 -10
  21. package/dist/{chunk-VKQ3KUYO.mjs → chunk-OEV5DFLW.mjs} +77 -7
  22. package/dist/chunk-OIZ4R5H7.mjs +173 -0
  23. package/dist/{chunk-CJTCU755.mjs → chunk-PJKI7SRI.mjs} +256 -26
  24. package/dist/chunk-PN25BUQ4.mjs +599 -0
  25. package/dist/chunk-QDPJ4VT2.mjs +432 -0
  26. package/dist/{chunk-2DHIAFEV.mjs → chunk-SRZTHCXP.mjs} +24 -10
  27. package/dist/chunk-TSK3HJEG.mjs +20 -0
  28. package/dist/chunk-UX34IVN5.mjs +33 -0
  29. package/dist/{chunk-BKLW2SPG.mjs → chunk-VAC3JTAV.mjs} +34 -17
  30. package/dist/{chunk-VAI7IUI4.mjs → chunk-VDZK4LW3.mjs} +30 -12
  31. package/dist/chunk-W6HM6F2U.mjs +901 -0
  32. package/dist/{chunk-H3K4GA2P.mjs → chunk-WPNMWNCL.mjs} +33 -21
  33. package/dist/chunk-WUDXHF2Q.mjs +14 -0
  34. package/dist/chunk-WZJ6DQJV.mjs +19 -0
  35. package/dist/{chunk-5LIE5GUU.mjs → chunk-XR625T3I.mjs} +5 -1
  36. package/dist/chunk-ZSKLNZWZ.mjs +224 -0
  37. package/dist/iterm2_send.py +56 -0
  38. package/dist/khala.mjs +20 -13
  39. package/dist/web/assets/local-CSPuGnH2.css +1 -0
  40. package/dist/web/assets/local-Dtyxaacx.js +9 -0
  41. package/dist/web/index.html +2 -2
  42. package/package.json +5 -3
  43. package/dist/chunk-2VCAW4GH.mjs +0 -34
  44. package/dist/chunk-5BQTYU66.mjs +0 -886
  45. package/dist/chunk-5GLTKWJ5.mjs +0 -1
  46. package/dist/chunk-5PUQT3YS.mjs +0 -569
  47. package/dist/chunk-7HBRFY3Z.mjs +0 -8
  48. package/dist/chunk-CBPLCCRZ.mjs +0 -191
  49. package/dist/chunk-FH34B3I3.mjs +0 -235
  50. package/dist/chunk-NKX3SLS7.mjs +0 -227
  51. package/dist/chunk-VUSV2ADL.mjs +0 -267
  52. package/dist/web/assets/local-BQl2KrE1.js +0 -9
  53. package/dist/web/assets/local-OwDq47O4.css +0 -1
@@ -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-VAI7IUI4.mjs";
5
+ } from "./chunk-VDZK4LW3.mjs";
6
6
  import {
7
7
  LOCAL_AGENT_DEVICE_PREFIX,
8
8
  LOCAL_IDLE_EXIT_MS,
@@ -32,26 +32,14 @@ import {
32
32
  normalizeInitials,
33
33
  olderHelperVersion,
34
34
  readHelperFile
35
- } from "./chunk-2DHIAFEV.mjs";
35
+ } from "./chunk-SRZTHCXP.mjs";
36
+ import "./chunk-HHEZVPRR.mjs";
36
37
  import {
37
38
  KHALA_AGENT_VERSION
38
- } from "./chunk-5LIE5GUU.mjs";
39
+ } from "./chunk-XR625T3I.mjs";
39
40
  import {
40
41
  bundle
41
- } from "./chunk-APMWDF6B.mjs";
42
- import "./chunk-5GLTKWJ5.mjs";
43
- import {
44
- CHANNEL_EVENT_TYPE,
45
- decodeChannelEvent,
46
- encodeChannelEvent,
47
- memberRenameContent
48
- } from "./chunk-54XFVSEC.mjs";
49
- import {
50
- StateError,
51
- ensureStateDir,
52
- readJson,
53
- writeJsonAtomic
54
- } from "./chunk-CBPLCCRZ.mjs";
42
+ } from "./chunk-G3NMB4PY.mjs";
55
43
  import {
56
44
  DEFAULT_LISTENING_MODE,
57
45
  LISTENING_MODE_COMMAND_TYPE,
@@ -59,29 +47,44 @@ import {
59
47
  decodeListeningMode,
60
48
  decodeListeningModeCommand,
61
49
  memberListeningMode
62
- } from "./chunk-IQJQ4RF5.mjs";
50
+ } from "./chunk-4BP7V3OP.mjs";
51
+ import {
52
+ CHANNEL_EVENT_TYPE,
53
+ decodeChannelEvent,
54
+ encodeChannelEvent,
55
+ memberRenameContent
56
+ } from "./chunk-JKOJQTFT.mjs";
63
57
  import {
64
58
  LEGACY_HARNESSES,
59
+ StateError,
65
60
  agentConfirmPagePath,
66
61
  decodeWith,
62
+ ensureStateDir,
67
63
  isHarnessId,
68
64
  object,
65
+ readJson,
69
66
  utf8Length,
70
67
  validAgentRejoinSecret,
71
- validAgentSessionId
72
- } from "./chunk-NKX3SLS7.mjs";
73
- import "./chunk-7HBRFY3Z.mjs";
68
+ validAgentSessionId,
69
+ writeJsonAtomic
70
+ } from "./chunk-PN25BUQ4.mjs";
71
+ import {
72
+ init_define_KHALA_BUNDLE
73
+ } from "./chunk-EVT2DWNZ.mjs";
74
74
 
75
75
  // src/local/cli.ts
76
+ init_define_KHALA_BUNDLE();
76
77
  import { setTimeout as sleepDefault } from "node:timers/promises";
77
78
 
78
79
  // src/local/serve.ts
80
+ init_define_KHALA_BUNDLE();
79
81
  import { createHash as createHash3, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
80
82
  import { unlink } from "node:fs/promises";
81
83
  import path3 from "node:path";
82
84
  import { fileURLToPath } from "node:url";
83
85
 
84
86
  // src/local/store.ts
87
+ init_define_KHALA_BUNDLE();
85
88
  import * as fs from "node:fs/promises";
86
89
  import path from "node:path";
87
90
  import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
@@ -564,6 +567,7 @@ async function openLocalStore(input) {
564
567
  }
565
568
 
566
569
  // src/local/http.ts
570
+ init_define_KHALA_BUNDLE();
567
571
  import { createServer } from "node:http";
568
572
  import * as fs2 from "node:fs/promises";
569
573
  import path2 from "node:path";
@@ -838,9 +842,11 @@ function createHelperServer(options) {
838
842
  }
839
843
 
840
844
  // src/local/routes/agent-join.ts
845
+ init_define_KHALA_BUNDLE();
841
846
  import { createHash as createHash2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
842
847
 
843
848
  // ../contracts/src/m1/channel-names.ts
849
+ init_define_KHALA_BUNDLE();
844
850
  var key = (name) => name.trim().toLowerCase();
845
851
  function takenNames(names) {
846
852
  return new Set([...names].map(key));
@@ -970,7 +976,11 @@ function agentJoinRoutes() {
970
976
  ];
971
977
  }
972
978
 
979
+ // src/local/routes/rooms.ts
980
+ init_define_KHALA_BUNDLE();
981
+
973
982
  // src/local/wire.ts
983
+ init_define_KHALA_BUNDLE();
974
984
  function legacyHarnessView(content) {
975
985
  if (!("harness" in content) || content.harness === void 0 || LEGACY_HARNESSES.includes(content.harness)) return content;
976
986
  const legacy = { ...content };
@@ -1191,6 +1201,7 @@ function roomRoutes() {
1191
1201
  }
1192
1202
 
1193
1203
  // src/local/routes/owner.ts
1204
+ init_define_KHALA_BUNDLE();
1194
1205
  var ID = /^[A-Za-z0-9._-]{1,64}$/u;
1195
1206
  var USER = /^@[^\s:]+:\S+$/u;
1196
1207
  var fail4 = (status, error2) => ({ status, json: { error: error2 } });
@@ -1382,6 +1393,7 @@ function ownerRoutes(options = {}) {
1382
1393
  }
1383
1394
 
1384
1395
  // src/local/routes/profile.ts
1396
+ init_define_KHALA_BUNDLE();
1385
1397
  var fail5 = (status, error2) => ({ status, json: { error: error2 } });
1386
1398
  var field = (body, key2) => decodeWith(() => object(body, "", [key2]).field(key2));
1387
1399
  var iso = (ctx) => new Date(ctx.now()).toISOString();
@@ -0,0 +1,14 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ init_define_KHALA_BUNDLE
4
+ } from "./chunk-EVT2DWNZ.mjs";
5
+
6
+ // src/transport.ts
7
+ init_define_KHALA_BUNDLE();
8
+ var RESTORE_HISTORY_MAX_PAGES = 20;
9
+ var startChannelSession = async (creds, options) => creds.transport === "local" ? (await import("./chunk-NDMFD5IM.mjs")).createLocalSession(creds) : (await import("./chunk-PJKI7SRI.mjs")).createAgentMatrixSession(creds, options);
10
+
11
+ export {
12
+ RESTORE_HISTORY_MAX_PAGES,
13
+ startChannelSession
14
+ };
@@ -0,0 +1,19 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ ADAPTERS,
4
+ adapterFor,
5
+ createAdapterRegistry
6
+ } from "./chunk-5JSGA6OB.mjs";
7
+ import "./chunk-6AQVW5W7.mjs";
8
+ import "./chunk-2AMWQ7RB.mjs";
9
+ import "./chunk-4BP7V3OP.mjs";
10
+ import "./chunk-OEV5DFLW.mjs";
11
+ import "./chunk-JKOJQTFT.mjs";
12
+ import "./chunk-PN25BUQ4.mjs";
13
+ import "./chunk-ZSKLNZWZ.mjs";
14
+ import "./chunk-EVT2DWNZ.mjs";
15
+ export {
16
+ ADAPTERS,
17
+ adapterFor,
18
+ createAdapterRegistry
19
+ };
@@ -1,9 +1,13 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
  import {
3
3
  bundle
4
- } from "./chunk-APMWDF6B.mjs";
4
+ } from "./chunk-G3NMB4PY.mjs";
5
+ import {
6
+ init_define_KHALA_BUNDLE
7
+ } from "./chunk-EVT2DWNZ.mjs";
5
8
 
6
9
  // src/version.ts
10
+ init_define_KHALA_BUNDLE();
7
11
  var KHALA_AGENT_VERSION = bundle?.version ?? "0.0.0";
8
12
 
9
13
  export {
@@ -0,0 +1,224 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ init_define_KHALA_BUNDLE
4
+ } from "./chunk-EVT2DWNZ.mjs";
5
+
6
+ // src/wake/shared/nonce.ts
7
+ init_define_KHALA_BUNDLE();
8
+ import * as fs2 from "node:fs/promises";
9
+ import path2 from "node:path";
10
+ import { randomBytes as randomBytes3 } from "node:crypto";
11
+
12
+ // src/wake/shared/rules.ts
13
+ init_define_KHALA_BUNDLE();
14
+ import { randomBytes } from "node:crypto";
15
+ var CODEX_IDLE_WAKE_NOTICE = "Khala: channel messages are waiting. Continue.";
16
+ function newNonce() {
17
+ return randomBytes(4).toString("hex");
18
+ }
19
+ function wakeLine(nonce) {
20
+ if (!/^[a-f0-9]{8}$/.test(nonce)) throw new Error("invalid_wake_nonce");
21
+ return `${CODEX_IDLE_WAKE_NOTICE} (k-${nonce})`;
22
+ }
23
+
24
+ // src/wake/shared/lock.ts
25
+ init_define_KHALA_BUNDLE();
26
+ import * as fs from "node:fs/promises";
27
+ import path from "node:path";
28
+ import { randomBytes as randomBytes2 } from "node:crypto";
29
+ async function clearAbandonedLock(lock) {
30
+ let entries;
31
+ try {
32
+ entries = await fs.readdir(lock);
33
+ } catch (error) {
34
+ if (error.code === "ENOENT") return;
35
+ throw error;
36
+ }
37
+ for (const entry of entries) {
38
+ const owner = /^owner-(\d+)-[a-f0-9]{16}$/.exec(entry);
39
+ if (!owner) continue;
40
+ try {
41
+ process.kill(Number(owner[1]), 0);
42
+ } catch (error) {
43
+ if (error.code !== "ESRCH") continue;
44
+ await fs.rm(path.join(lock, entry), { force: true });
45
+ }
46
+ }
47
+ try {
48
+ await fs.rmdir(lock);
49
+ } catch (error) {
50
+ if (!["ENOENT", "ENOTEMPTY", "EEXIST"].includes(error.code ?? "")) throw error;
51
+ }
52
+ }
53
+ async function withWakeLock(dir, name, work) {
54
+ await fs.mkdir(dir, { recursive: true, mode: 448 });
55
+ const lock = path.join(dir, name);
56
+ const owner = `owner-${process.pid}-${randomBytes2(8).toString("hex")}`;
57
+ const candidate = path.join(dir, `.${owner}`);
58
+ await fs.mkdir(candidate, { mode: 448 });
59
+ await fs.writeFile(path.join(candidate, owner), "", { mode: 384 });
60
+ let acquired = false;
61
+ try {
62
+ for (let tries = 0; tries < 200; tries++) {
63
+ try {
64
+ await fs.rename(candidate, lock);
65
+ acquired = true;
66
+ break;
67
+ } catch (error) {
68
+ if (!["EEXIST", "ENOTEMPTY", "EPERM", "EACCES"].includes(error.code ?? "")) throw error;
69
+ }
70
+ await clearAbandonedLock(lock);
71
+ await new Promise((resolve) => setTimeout(resolve, 10));
72
+ }
73
+ } finally {
74
+ if (!acquired) await fs.rm(candidate, { recursive: true, force: true });
75
+ }
76
+ if (!acquired) throw new Error("wake_state_locked");
77
+ try {
78
+ return await work();
79
+ } finally {
80
+ await fs.rm(path.join(lock, owner), { force: true });
81
+ try {
82
+ await fs.rmdir(lock);
83
+ } catch (error) {
84
+ if (!["ENOENT", "ENOTEMPTY", "EEXIST"].includes(error.code ?? "")) throw error;
85
+ }
86
+ }
87
+ }
88
+
89
+ // src/wake/shared/nonce.ts
90
+ async function readJson(file, fallback) {
91
+ try {
92
+ return JSON.parse(await fs2.readFile(file, "utf8"));
93
+ } catch (error) {
94
+ if (error.code === "ENOENT") return fallback;
95
+ throw error;
96
+ }
97
+ }
98
+ async function atomic(file, value) {
99
+ const temp = `${file}.${randomBytes3(8).toString("hex")}.tmp`;
100
+ try {
101
+ await fs2.writeFile(temp, JSON.stringify(value), { mode: 384 });
102
+ await fs2.rename(temp, file);
103
+ } finally {
104
+ await fs2.rm(temp, { force: true });
105
+ }
106
+ }
107
+ async function locked(dir, work) {
108
+ return withWakeLock(dir, "wake.lock", async () => {
109
+ const data = await readJson(path2.join(dir, "wake-journal.json"), { attempts: [], state: {} });
110
+ const before = JSON.stringify(data);
111
+ const result = work(data);
112
+ if (JSON.stringify(data) === before) return result;
113
+ await atomic(path2.join(dir, "wake-journal.json"), data);
114
+ await atomic(path2.join(dir, "wake-state.json"), data.state);
115
+ return result;
116
+ });
117
+ }
118
+ async function readWakeState(dir) {
119
+ return (await readJson(path2.join(dir, "wake-journal.json"), { attempts: [], state: {} })).state;
120
+ }
121
+ async function recordAttempt(dir, attempt) {
122
+ wakeLine(attempt.nonce);
123
+ if (!attempt.driver || ["__proto__", "constructor", "prototype"].includes(attempt.driver) || !Number.isFinite(attempt.at) || !Number.isFinite(attempt.deadline) || attempt.deadline <= attempt.at) throw new Error("invalid_wake_attempt");
124
+ await locked(dir, (data) => {
125
+ if (data.attempts.some((item) => item.nonce === attempt.nonce)) throw new Error("duplicate_wake_nonce");
126
+ data.attempts.push(attempt);
127
+ });
128
+ }
129
+ async function settleAttempts(dir, input) {
130
+ const snapshot = await readJson(path2.join(dir, "wake-journal.json"), { attempts: [], state: {} });
131
+ if (!snapshot.attempts.length) return [];
132
+ return locked(dir, (data) => {
133
+ const results = [];
134
+ const remaining = [];
135
+ const activityAt = typeof input.activity?.updatedAt === "number" ? input.activity.updatedAt : Date.parse(input.activity?.updatedAt ?? "");
136
+ for (const attempt of data.attempts) {
137
+ let status;
138
+ const baselineAt = typeof attempt.activityUpdatedAt === "number" ? attempt.activityUpdatedAt : attempt.activityUpdatedAt === void 0 ? attempt.at : Date.parse(attempt.activityUpdatedAt);
139
+ const verified = input.promptText?.includes(`(k-${attempt.nonce})`);
140
+ const activityChanged = input.activity && (input.activity.state !== "idle" || activityAt > baselineAt);
141
+ if (input.deferVerification && !activityChanged) attempt.verificationDeferred = true;
142
+ if (attempt.verification === "transcript") {
143
+ if (input.now >= attempt.deadline && input.activity?.state === "idle") status = "failure";
144
+ } else if (verified && input.verifiedAt !== void 0 && input.verifiedAt >= attempt.at && input.verifiedAt <= attempt.deadline) status = "success";
145
+ else if (attempt.verificationDeferred) {
146
+ if (verified && input.now <= attempt.deadline) status = "success";
147
+ else if (input.now >= attempt.deadline) status = activityChanged ? "void" : "failure";
148
+ } else if (activityChanged && !(attempt.startsActivity && input.activity?.state === "busy" && input.promptText === void 0)) status = "void";
149
+ else if (verified && input.verifiedAt === void 0 && input.now <= attempt.deadline) status = "success";
150
+ else if (input.now >= attempt.deadline && input.activity?.state === "idle") status = "failure";
151
+ else if (input.promptText !== void 0) status = "void";
152
+ if (!status) {
153
+ remaining.push(attempt);
154
+ continue;
155
+ }
156
+ results.push({ nonce: attempt.nonce, driver: attempt.driver, status });
157
+ if (status === "void") continue;
158
+ const prior = data.state[attempt.driver] ?? { failures: 0 };
159
+ if (status === "success") data.state[attempt.driver] = { failures: 0 };
160
+ else {
161
+ const failures = prior.failures + 1;
162
+ data.state[attempt.driver] = failures >= 2 ? { ...prior, failures, disabled: true, reason: "nonce_timeout", at: new Date(input.now).toISOString() } : { failures };
163
+ }
164
+ }
165
+ data.attempts = remaining;
166
+ return results;
167
+ });
168
+ }
169
+ async function cancelAttempt(dir, nonce) {
170
+ await locked(dir, (data) => {
171
+ data.attempts = data.attempts.filter((attempt) => attempt.nonce !== nonce);
172
+ });
173
+ }
174
+ async function failAttempt(dir, nonce, now) {
175
+ await locked(dir, (data) => {
176
+ const attempt = data.attempts.find((item) => item.nonce === nonce);
177
+ if (!attempt) return;
178
+ data.attempts = data.attempts.filter((item) => item.nonce !== nonce);
179
+ const prior = data.state[attempt.driver] ?? { failures: 0 };
180
+ const failures = prior.failures + 1;
181
+ data.state[attempt.driver] = failures >= 2 ? { ...prior, failures, disabled: true, reason: "nonce_timeout", at: new Date(now).toISOString() } : { failures };
182
+ });
183
+ }
184
+ async function resetWakeDriver(dir, driver) {
185
+ await locked(dir, (data) => {
186
+ delete data.state[driver];
187
+ data.attempts = data.attempts.filter((attempt) => attempt.driver !== driver);
188
+ });
189
+ }
190
+ async function takeWakeDisableNotices(dir) {
191
+ return locked(dir, (data) => {
192
+ const drivers = [];
193
+ for (const [driver, state] of Object.entries(data.state)) {
194
+ if (!state.disabled || state.noticeShown) continue;
195
+ state.noticeShown = true;
196
+ drivers.push(driver);
197
+ }
198
+ return drivers;
199
+ });
200
+ }
201
+ async function confirmWakeText(dir, driver, text, now) {
202
+ await locked(dir, (data) => {
203
+ data.attempts = data.attempts.filter((attempt) => {
204
+ if (attempt.driver !== driver || now > attempt.deadline || !text.includes(`(k-${attempt.nonce})`)) return true;
205
+ data.state[driver] = { failures: 0 };
206
+ return false;
207
+ });
208
+ });
209
+ }
210
+
211
+ export {
212
+ CODEX_IDLE_WAKE_NOTICE,
213
+ newNonce,
214
+ wakeLine,
215
+ withWakeLock,
216
+ readWakeState,
217
+ recordAttempt,
218
+ settleAttempts,
219
+ cancelAttempt,
220
+ failAttempt,
221
+ resetWakeDriver,
222
+ takeWakeDisableNotices,
223
+ confirmWakeText
224
+ };
@@ -0,0 +1,56 @@
1
+ """Read only by default; guarded sends never activate a session or broadcast."""
2
+ import json
3
+ import re
4
+ import sys
5
+
6
+
7
+ async def operate(connection, uuid, text=None, expected=None):
8
+ import iterm2
9
+
10
+ app = await iterm2.async_get_app(connection)
11
+ session = app.get_session_by_id(uuid)
12
+ if session is None:
13
+ return {"reason": "iterm2_session_missing"}
14
+ screen = await session.async_get_screen_contents()
15
+ cursor = screen.cursor_coord
16
+ # ScreenContents uses absolute buffer coordinates, including lost history.
17
+ row = cursor.y - screen.windowed_coord_range.coord_range.start.y
18
+ if row < 0 or row >= screen.number_of_lines:
19
+ return {"reason": "iterm2_cursor_unavailable"}
20
+ contents = screen.line(row)
21
+ styled = ""
22
+ for column in range(session.grid_size.width):
23
+ try:
24
+ character = contents.string_at(column)
25
+ except IndexError:
26
+ break
27
+ style = contents.style_at(column)
28
+ styled += ("\x1b[2m" if style and style.faint else "\x1b[22m") + character
29
+ if re.sub(r"\x1b\[[0-9;]*m", "", styled) != contents.string:
30
+ return {"reason": "iterm2_style_unavailable"}
31
+ view = {"tty": await session.async_get_variable("tty"),
32
+ "cursorX": cursor.x, "cursorY": cursor.y,
33
+ "line": styled}
34
+ if text is None:
35
+ return view
36
+ # The TypeScript prompt guard approved this exact snapshot. A full literal
37
+ # pattern avoids translating JavaScript regex syntax or trusting a draft.
38
+ if (expected is None or view["tty"] != expected["tty"]
39
+ or view["cursorX"] != expected["cursorX"]
40
+ or view["cursorY"] != expected["cursorY"]
41
+ or re.fullmatch(re.escape(expected["line"]), view["line"]) is None):
42
+ return {"status": "not_empty"}
43
+ await session.async_send_text(text, suppress_broadcast=True)
44
+ return {"status": "sent"}
45
+
46
+
47
+ if __name__ == "__main__":
48
+ import iterm2
49
+
50
+ async def main(connection):
51
+ expected = json.loads(sys.argv[3]) if len(sys.argv) > 3 else None
52
+ result = await operate(connection, sys.argv[1],
53
+ sys.argv[2] if len(sys.argv) > 2 else None, expected)
54
+ print(json.dumps(result))
55
+
56
+ iterm2.run_until_complete(main)
package/dist/khala.mjs CHANGED
@@ -2,14 +2,20 @@
2
2
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
3
3
  import {
4
4
  KHALA_AGENT_VERSION
5
- } from "./chunk-5LIE5GUU.mjs";
6
- import "./chunk-APMWDF6B.mjs";
7
- import "./chunk-7HBRFY3Z.mjs";
5
+ } from "./chunk-XR625T3I.mjs";
6
+ import "./chunk-G3NMB4PY.mjs";
7
+ import {
8
+ init_define_KHALA_BUNDLE
9
+ } from "./chunk-EVT2DWNZ.mjs";
10
+
11
+ // src/cli-bundle.ts
12
+ init_define_KHALA_BUNDLE();
8
13
 
9
14
  // src/cli.ts
15
+ init_define_KHALA_BUNDLE();
10
16
  var HOOK_NAME = /^[a-z][a-z0-9-]{0,31}$/;
11
17
  var STDIN_CAP = 1024 * 1024;
12
- var USAGE = "usage: khala mcp | khala watch [--harness claude|codex|cursor --session <id>] | khala hook <name> | khala local <command> | khala install codex | khala install cursor | khala install opencode | khala install mcp --print [--harness <id>] | khala --version";
18
+ var USAGE = "usage: khala mcp | khala watch [--harness <id>] [--session <id>] | khala hook <name> | khala local <command> | khala install codex | khala install cursor | khala wake on|off|status [--driver <d>] [--harness <id>] [--json] | khala install copilot | khala install opencode | khala install gemini [--trust-tools] [--wake|--no-wake] [--uninstall] | khala install muse | khala install mcp --print [--harness <id>] | khala --version";
13
19
  async function readStdin() {
14
20
  if (process.stdin.isTTY) return "";
15
21
  const chunks = [];
@@ -31,8 +37,8 @@ async function runCli(argv, modules) {
31
37
  console.log(KHALA_AGENT_VERSION);
32
38
  return 0;
33
39
  }
34
- if (cmd === "mcp" || cmd === "install" || cmd === "watch") {
35
- const load = modules[cmd]();
40
+ if (cmd === "mcp" || cmd === "install" || cmd === "watch" || cmd === "wake") {
41
+ const load = modules[cmd]?.();
36
42
  if (!load) {
37
43
  console.error(`khala: ${cmd} not available`);
38
44
  return 1;
@@ -78,14 +84,15 @@ async function runCli(argv, modules) {
78
84
 
79
85
  // src/cli-bundle.ts
80
86
  var hooks = {
81
- "session-start": () => import("./chunk-W6R4UJUQ.mjs"),
82
- deliver: () => import("./chunk-VUSV2ADL.mjs"),
83
- "claude-wake": () => import("./chunk-BKLW2SPG.mjs")
87
+ "session-start": () => import("./chunk-6J2PUM7L.mjs"),
88
+ deliver: () => import("./chunk-QDPJ4VT2.mjs"),
89
+ "claude-wake": () => import("./chunk-VAC3JTAV.mjs")
84
90
  };
85
91
  process.exitCode = await runCli(process.argv.slice(2), {
86
- mcp: () => () => import("./chunk-RNDUFTBF.mjs"),
87
- watch: () => () => import("./chunk-Z4JF2M5C.mjs"),
88
- local: () => () => import("./chunk-H3K4GA2P.mjs"),
89
- install: () => () => import("./chunk-5PUQT3YS.mjs"),
92
+ mcp: () => () => import("./chunk-ARIDZOTI.mjs"),
93
+ watch: () => () => import("./chunk-CHC4VZF5.mjs"),
94
+ local: () => () => import("./chunk-WPNMWNCL.mjs"),
95
+ install: () => () => import("./chunk-CKLCR5G4.mjs"),
96
+ wake: () => () => import("./chunk-6SUV3EW6.mjs"),
90
97
  hook: (name) => Object.hasOwn(hooks, name) ? hooks[name] : void 0
91
98
  });