khala-cli 0.4.2 → 0.4.5

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 (35) hide show
  1. package/dist/{chunk-T6RZE5IQ.mjs → chunk-6LC66VHK.mjs} +10 -7
  2. package/dist/chunk-7G2G4E4U.mjs +236 -0
  3. package/dist/chunk-AUJEUKVM.mjs +121 -0
  4. package/dist/{chunk-NUS6M27N.mjs → chunk-EW22K3JO.mjs} +445 -199
  5. package/dist/chunk-EXHCVFVH.mjs +26 -0
  6. package/dist/{chunk-CDHHFC6C.mjs → chunk-H46OG22B.mjs} +22 -6
  7. package/dist/{chunk-YP45XTOH.mjs → chunk-HB3UGIZG.mjs} +5 -5
  8. package/dist/chunk-IR3VN2ID.mjs +52 -0
  9. package/dist/{chunk-B5BFL7OD.mjs → chunk-KCJFSVDN.mjs} +55 -4
  10. package/dist/{chunk-K4MDSFHU.mjs → chunk-MBLP7LQJ.mjs} +103 -38
  11. package/dist/{chunk-RW3DXWNC.mjs → chunk-OLZ62X7S.mjs} +1 -1
  12. package/dist/chunk-P5CP32X2.mjs +170 -0
  13. package/dist/{chunk-A3LJU4JA.mjs → chunk-PXKGKVGW.mjs} +1 -1
  14. package/dist/{chunk-7MQAMABY.mjs → chunk-RSDOTTZQ.mjs} +4 -4
  15. package/dist/chunk-SN3STAO2.mjs +190 -0
  16. package/dist/{chunk-MHZWR4A3.mjs → chunk-SQXDATEC.mjs} +1 -1
  17. package/dist/chunk-T7YRVE43.mjs +238 -0
  18. package/dist/{chunk-BZ53MZEE.mjs → chunk-TZKEQIHP.mjs} +8 -4
  19. package/dist/{chunk-46PTKRZC.mjs → chunk-V4Y26O4R.mjs} +171 -113
  20. package/dist/chunk-V7M27QLT.mjs +21 -0
  21. package/dist/{chunk-2OO725IZ.mjs → chunk-Y2DRTRBJ.mjs} +3 -3
  22. package/dist/{chunk-JRZZVTQ4.mjs → chunk-Y4WVILEJ.mjs} +94 -10
  23. package/dist/khala.mjs +12 -10
  24. package/dist/web/assets/apple-touch-icon-Du9V6qit.png +0 -0
  25. package/dist/web/assets/favicon-16x16-D5waNSZD.png +0 -0
  26. package/dist/web/assets/favicon-32x32-B9Ubw1Dx.png +0 -0
  27. package/dist/web/assets/favicon-zCD0pKtT.ico +0 -0
  28. package/dist/web/assets/local-C1vz22ps.js +9 -0
  29. package/dist/web/assets/local-DdjwMERJ.css +1 -0
  30. package/dist/web/index.html +7 -2
  31. package/package.json +1 -1
  32. package/dist/chunk-N6LMHR7P.mjs +0 -455
  33. package/dist/chunk-U5ZMOPUK.mjs +0 -149
  34. package/dist/web/assets/local-CVA9799w.js +0 -9
  35. package/dist/web/assets/local-DHYvcQG0.css +0 -1
@@ -0,0 +1,21 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ WATCH_USAGE,
4
+ mentions,
5
+ monitorArmed,
6
+ run,
7
+ watchSession
8
+ } from "./chunk-7G2G4E4U.mjs";
9
+ import "./chunk-T7YRVE43.mjs";
10
+ import "./chunk-VUE2DDYY.mjs";
11
+ import "./chunk-KCJFSVDN.mjs";
12
+ import "./chunk-AUJEUKVM.mjs";
13
+ import "./chunk-SN3STAO2.mjs";
14
+ import "./chunk-PXKGKVGW.mjs";
15
+ export {
16
+ WATCH_USAGE,
17
+ run as default,
18
+ mentions,
19
+ monitorArmed,
20
+ watchSession
21
+ };
@@ -4,17 +4,17 @@ import {
4
4
  MODEL_NAMES,
5
5
  checkName,
6
6
  isDefaultAgentName
7
- } from "./chunk-BZ53MZEE.mjs";
7
+ } from "./chunk-TZKEQIHP.mjs";
8
8
  import {
9
9
  StateError,
10
10
  readJson,
11
11
  stateRoot,
12
12
  writeJsonAtomic
13
- } from "./chunk-B5BFL7OD.mjs";
13
+ } from "./chunk-KCJFSVDN.mjs";
14
14
  import {
15
15
  HARNESSES,
16
16
  validateAgentName
17
- } from "./chunk-N6LMHR7P.mjs";
17
+ } from "./chunk-SN3STAO2.mjs";
18
18
 
19
19
  // src/local/identity.ts
20
20
  import * as fs from "node:fs/promises";
@@ -2,13 +2,16 @@ import { createRequire as __khalaCreateRequire } from 'node:module'; const requi
2
2
  import "./chunk-5GLTKWJ5.mjs";
3
3
  import {
4
4
  CHANNEL_EVENT_TYPE,
5
- LISTENING_MODE_COMMAND_TYPE,
6
- LISTENING_MODE_MEMBER_KEY,
7
5
  encodeChannelEvent,
8
- memberListeningMode,
9
6
  memberRenameContent
10
- } from "./chunk-N6LMHR7P.mjs";
11
- import "./chunk-A3LJU4JA.mjs";
7
+ } from "./chunk-P5CP32X2.mjs";
8
+ import {
9
+ LISTENING_MODE_COMMAND_TYPE,
10
+ LISTENING_MODE_MEMBER_KEY,
11
+ memberListeningMode
12
+ } from "./chunk-AUJEUKVM.mjs";
13
+ import "./chunk-SN3STAO2.mjs";
14
+ import "./chunk-PXKGKVGW.mjs";
12
15
 
13
16
  // src/matrix/session.ts
14
17
  import { createClient, ClientEvent, RoomEvent, MatrixEventEvent, SyncState, Direction, Method, EventType } from "matrix-js-sdk";
@@ -36,6 +39,7 @@ async function createAgentMatrixSession(creds, opts) {
36
39
  const log = (line) => opts?.log?.(line);
37
40
  const client = createClient({ baseUrl: creds.homeserver, userId: creds.userId, accessToken: creds.accessToken, deviceId: creds.deviceId });
38
41
  const handlers = /* @__PURE__ */ new Set();
42
+ const ended = /* @__PURE__ */ new Set();
39
43
  const modeHandlers = /* @__PURE__ */ new Set();
40
44
  const inviters = /* @__PURE__ */ new Map();
41
45
  const emitted = /* @__PURE__ */ new Set();
@@ -86,7 +90,45 @@ async function createAgentMatrixSession(creds, opts) {
86
90
  void client.decryptEventIfNeeded(event).then(() => deliver(event), () => log("live_decryption_failed"));
87
91
  };
88
92
  const decrypted = (event) => deliver(event);
89
- const syncLog = (state) => log(`sync_state=${state}`);
93
+ const syncLog = (state, _previous, data) => {
94
+ log(`sync_state=${state}`);
95
+ if (state === SyncState.Error && joinedRoom && matrixCode(data?.error) === "M_UNKNOWN_TOKEN") {
96
+ void checkEnded("unauthorized");
97
+ }
98
+ };
99
+ const matrixCode = (error) => typeof error === "object" && error !== null && "errcode" in error ? error.errcode : void 0;
100
+ let checkingEnded;
101
+ let pendingEndReason;
102
+ const checkEnded = (fallback) => {
103
+ if (stopped) return Promise.resolve();
104
+ if (fallback) pendingEndReason = fallback;
105
+ if (checkingEnded) return checkingEnded;
106
+ checkingEnded = (async () => {
107
+ let removed = false;
108
+ try {
109
+ removed = await opts?.checkRemoved?.() ?? false;
110
+ } catch {
111
+ }
112
+ if (removed) end("removed");
113
+ else if (pendingEndReason) end(pendingEndReason);
114
+ })().finally(() => {
115
+ checkingEnded = void 0;
116
+ pendingEndReason = void 0;
117
+ });
118
+ return checkingEnded;
119
+ };
120
+ const guarded = async (roomId, operation) => {
121
+ if (stopped) throw new Error("session_stopped");
122
+ try {
123
+ return await operation();
124
+ } catch (error) {
125
+ const code = matrixCode(error);
126
+ if (roomId === joinedRoom && (code === "M_FORBIDDEN" || code === "M_UNKNOWN_TOKEN")) {
127
+ await checkEnded(code === "M_UNKNOWN_TOKEN" ? "unauthorized" : void 0);
128
+ }
129
+ throw error;
130
+ }
131
+ };
90
132
  const wait = (subscribe, ready, timeoutMs, error) => {
91
133
  if (stopped) return Promise.reject(new Error("session_stopped"));
92
134
  if (ready()) return Promise.resolve();
@@ -117,11 +159,29 @@ async function createAgentMatrixSession(creds, opts) {
117
159
  client.removeListener(RoomEvent.Timeline, timeline);
118
160
  client.removeListener(MatrixEventEvent.Decrypted, decrypted);
119
161
  client.removeListener(ClientEvent.Sync, syncLog);
162
+ client.removeListener(RoomEvent.MyMembership, membershipEnded);
120
163
  for (const cancel of [...cancellations]) cancel();
121
164
  liveEvents.clear();
122
165
  emitted.clear();
123
166
  handlers.clear();
124
167
  modeHandlers.clear();
168
+ ended.clear();
169
+ };
170
+ const membershipEnded = (room, membership) => {
171
+ if (stopped || room.roomId !== joinedRoom || !["leave", "ban"].includes(membership)) return;
172
+ end("removed");
173
+ };
174
+ const end = (reason) => {
175
+ if (stopped) return;
176
+ const listeners = [...ended];
177
+ void stop();
178
+ for (const handler of listeners) {
179
+ try {
180
+ handler(reason);
181
+ } catch {
182
+ log("ended_handler_error");
183
+ }
184
+ }
125
185
  };
126
186
  try {
127
187
  await client.initRustCrypto({ useIndexedDB: false });
@@ -167,6 +227,12 @@ async function createAgentMatrixSession(creds, opts) {
167
227
  }, ready, timeoutMs, error);
168
228
  return {
169
229
  userId: creds.userId,
230
+ onEnded(handler) {
231
+ if (!stopped) ended.add(handler);
232
+ return () => {
233
+ ended.delete(handler);
234
+ };
235
+ },
170
236
  listeningMode: (roomId) => memberListeningMode(client.getRoom(roomId)?.currentState.getStateEvents("m.room.member", creds.userId)?.getContent()),
171
237
  inviter(roomId) {
172
238
  return inviters.get(roomId);
@@ -178,6 +244,7 @@ async function createAgentMatrixSession(creds, opts) {
178
244
  };
179
245
  },
180
246
  async publishListeningMode(roomId, mode, signal) {
247
+ if (stopped) throw new Error("session_stopped");
181
248
  const content = client.getRoom(roomId)?.currentState.getStateEvents("m.room.member", creds.userId)?.getContent();
182
249
  if (!content) throw new Error("join_state_unavailable");
183
250
  const next = { ...content, membership: "join", [LISTENING_MODE_MEMBER_KEY]: mode };
@@ -217,18 +284,20 @@ async function createAgentMatrixSession(creds, opts) {
217
284
  await client.sendStateEvent(roomId, EventType.RoomMember, content, creds.userId);
218
285
  }
219
286
  joinTimes.set(roomId, membership === "join" ? rejoinedAt : ownJoin.getTs());
287
+ if (!joinedRoom) client.on(RoomEvent.MyMembership, membershipEnded);
220
288
  joinedRoom = roomId;
221
289
  for (const event of liveEvents) {
222
290
  if (event.getRoomId() === roomId) deliver(event);
223
291
  }
224
292
  },
225
293
  async history(roomId, limit, before) {
294
+ if (stopped) throw new Error("session_stopped");
226
295
  let token = null;
227
296
  if (before !== void 0) {
228
- const context = await client.http.authedRequest(Method.Get, `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(before)}`, { limit: "0" });
297
+ const context = await guarded(roomId, () => client.http.authedRequest(Method.Get, `/rooms/${encodeURIComponent(roomId)}/context/${encodeURIComponent(before)}`, { limit: "0" }));
229
298
  token = context.start;
230
299
  }
231
- const res = await client.createMessagesRequest(roomId, token, limit, Direction.Backward);
300
+ const res = await guarded(roomId, () => client.createMessagesRequest(roomId, token, limit, Direction.Backward));
232
301
  const messages = [];
233
302
  let undecryptable = 0;
234
303
  for (const raw of res.chunk) {
@@ -239,6 +308,19 @@ async function createAgentMatrixSession(creds, opts) {
239
308
  }
240
309
  if (event.getType() === "m.room.encrypted" || event.isDecryptionFailure()) {
241
310
  undecryptable++;
311
+ const eventId = event.getId(), sender = event.getSender();
312
+ if (eventId && sender && eventId !== before) {
313
+ const body = "[Encrypted message unavailable: this device does not have its key. Messages from before joining may not have been shared.]";
314
+ messages.push({
315
+ eventId,
316
+ roomId,
317
+ sender,
318
+ ts: event.getTs(),
319
+ type: "m.room.message",
320
+ body,
321
+ content: { msgtype: "m.notice", body, "com.khala.unavailable": true }
322
+ });
323
+ }
242
324
  continue;
243
325
  }
244
326
  const m = message(event);
@@ -250,11 +332,13 @@ async function createAgentMatrixSession(creds, opts) {
250
332
  return typeof res.end === "string" && oldest ? { messages, nextBefore: oldest.eventId } : { messages };
251
333
  },
252
334
  async send(roomId, text) {
253
- const res = await client.sendTextMessage(roomId, text);
335
+ if (stopped) throw new Error("session_stopped");
336
+ const res = await guarded(roomId, () => client.sendTextMessage(roomId, text));
254
337
  return { eventId: res.event_id };
255
338
  },
256
339
  async sendChannelEvent(roomId, content, txnId) {
257
- const res = await client.sendEvent(roomId, CHANNEL_EVENT_TYPE, content, txnId);
340
+ if (stopped) throw new Error("session_stopped");
341
+ const res = await guarded(roomId, () => client.sendEvent(roomId, CHANNEL_EVENT_TYPE, content, txnId));
258
342
  return { eventId: res.event_id };
259
343
  },
260
344
  roomName(roomId) {
package/dist/khala.mjs CHANGED
@@ -2,14 +2,14 @@
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-MHZWR4A3.mjs";
6
- import "./chunk-RW3DXWNC.mjs";
7
- import "./chunk-A3LJU4JA.mjs";
5
+ } from "./chunk-SQXDATEC.mjs";
6
+ import "./chunk-OLZ62X7S.mjs";
7
+ import "./chunk-PXKGKVGW.mjs";
8
8
 
9
9
  // src/cli.ts
10
10
  var HOOK_NAME = /^[a-z][a-z0-9-]{0,31}$/;
11
11
  var STDIN_CAP = 1024 * 1024;
12
- var USAGE = "usage: khala mcp | khala hook <name> | khala local <command> | khala install codex | khala install cursor | khala --version";
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 --version";
13
13
  async function readStdin() {
14
14
  if (process.stdin.isTTY) return "";
15
15
  const chunks = [];
@@ -31,7 +31,7 @@ async function runCli(argv, modules) {
31
31
  console.log(KHALA_AGENT_VERSION);
32
32
  return 0;
33
33
  }
34
- if (cmd === "mcp" || cmd === "install") {
34
+ if (cmd === "mcp" || cmd === "install" || cmd === "watch") {
35
35
  const load = modules[cmd]();
36
36
  if (!load) {
37
37
  console.error(`khala: ${cmd} not available`);
@@ -78,12 +78,14 @@ async function runCli(argv, modules) {
78
78
 
79
79
  // src/cli-bundle.ts
80
80
  var hooks = {
81
- deliver: () => import("./chunk-K4MDSFHU.mjs"),
82
- "claude-wake": () => import("./chunk-CDHHFC6C.mjs")
81
+ "session-start": () => import("./chunk-EXHCVFVH.mjs"),
82
+ deliver: () => import("./chunk-MBLP7LQJ.mjs"),
83
+ "claude-wake": () => import("./chunk-H46OG22B.mjs")
83
84
  };
84
85
  process.exitCode = await runCli(process.argv.slice(2), {
85
- mcp: () => () => import("./chunk-NUS6M27N.mjs"),
86
- local: () => () => import("./chunk-46PTKRZC.mjs"),
87
- install: () => () => import("./chunk-7MQAMABY.mjs"),
86
+ mcp: () => () => import("./chunk-EW22K3JO.mjs"),
87
+ watch: () => () => import("./chunk-V7M27QLT.mjs"),
88
+ local: () => () => import("./chunk-V4Y26O4R.mjs"),
89
+ install: () => () => import("./chunk-RSDOTTZQ.mjs"),
88
90
  hook: (name) => Object.hasOwn(hooks, name) ? hooks[name] : void 0
89
91
  });