khala-cli 0.4.8 → 0.4.9

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 (48) hide show
  1. package/README.md +4 -4
  2. package/dist/THIRD_PARTY_NOTICES.txt +781 -0
  3. package/dist/{chunk-APMWDF6B.mjs → chunk-3KDOTR54.mjs} +4 -2
  4. package/dist/{chunk-VUSV2ADL.mjs → chunk-3R6HFSLL.mjs} +147 -36
  5. package/dist/{chunk-2VCAW4GH.mjs → chunk-47XNLAJG.mjs} +5 -1
  6. package/dist/chunk-6BO3JSUP.mjs +33 -0
  7. package/dist/chunk-7R3EIDGR.mjs +58 -0
  8. package/dist/{chunk-5LIE5GUU.mjs → chunk-ANSR4IAW.mjs} +5 -1
  9. package/dist/chunk-BEO7WIIM.mjs +153 -0
  10. package/dist/chunk-BLCRVRIK.mjs +1000 -0
  11. package/dist/{chunk-54XFVSEC.mjs → chunk-BV45NK7K.mjs} +5 -1
  12. package/dist/{chunk-Z4JF2M5C.mjs → chunk-DJM23SIU.mjs} +8 -7
  13. package/dist/{chunk-2DHIAFEV.mjs → chunk-FO5GXCST.mjs} +24 -10
  14. package/dist/{chunk-CJTCU755.mjs → chunk-FZEH2IXZ.mjs} +95 -15
  15. package/dist/{chunk-RNDUFTBF.mjs → chunk-GSZADJMW.mjs} +233 -77
  16. package/dist/chunk-ITFD3JZS.mjs +1137 -0
  17. package/dist/chunk-K7V7X6WU.mjs +207 -0
  18. package/dist/chunk-KMLXOPBQ.mjs +20 -0
  19. package/dist/chunk-LBT47HLZ.mjs +19 -0
  20. package/dist/{chunk-IQJQ4RF5.mjs → chunk-NGSYOVQ4.mjs} +12 -1
  21. package/dist/chunk-NIX5F4LT.mjs +863 -0
  22. package/dist/chunk-NPSQNCOY.mjs +590 -0
  23. package/dist/chunk-P3YIN7G7.mjs +26 -0
  24. package/dist/chunk-PAJ4JJPV.mjs +9827 -0
  25. package/dist/{chunk-VAI7IUI4.mjs → chunk-PDZ5Z5ZE.mjs} +9 -6
  26. package/dist/chunk-QKWEZXR3.mjs +52 -0
  27. package/dist/chunk-SSO5RFOX.mjs +7 -0
  28. package/dist/{chunk-ZJ4W7P33.mjs → chunk-T7IL7V7Q.mjs} +11 -9
  29. package/dist/{chunk-VKQ3KUYO.mjs → chunk-TANCKTDK.mjs} +9 -4
  30. package/dist/{chunk-FV32AQTC.mjs → chunk-TEFOQXBK.mjs} +10 -6
  31. package/dist/{chunk-W6R4UJUQ.mjs → chunk-UK5GJO4Y.mjs} +15 -9
  32. package/dist/{chunk-BKLW2SPG.mjs → chunk-V4F3SYKW.mjs} +19 -10
  33. package/dist/{chunk-H3K4GA2P.mjs → chunk-WDOHRV3D.mjs} +31 -19
  34. package/dist/chunk-XBQDIKB5.mjs +18 -0
  35. package/dist/chunk-XUCWSYVS.mjs +148 -0
  36. package/dist/khala.mjs +20 -13
  37. package/dist/web/assets/local-CFzRHZpB.js +9 -0
  38. package/dist/web/assets/{local-OwDq47O4.css → local-ciypUFoK.css} +1 -1
  39. package/dist/web/index.html +2 -2
  40. package/package.json +5 -3
  41. package/dist/chunk-5BQTYU66.mjs +0 -886
  42. package/dist/chunk-5GLTKWJ5.mjs +0 -1
  43. package/dist/chunk-5PUQT3YS.mjs +0 -569
  44. package/dist/chunk-7HBRFY3Z.mjs +0 -8
  45. package/dist/chunk-CBPLCCRZ.mjs +0 -191
  46. package/dist/chunk-FH34B3I3.mjs +0 -235
  47. package/dist/chunk-NKX3SLS7.mjs +0 -227
  48. package/dist/web/assets/local-BQl2KrE1.js +0 -9
@@ -9,9 +9,13 @@ import {
9
9
  utcTimestamp,
10
10
  utf8Length,
11
11
  version
12
- } from "./chunk-NKX3SLS7.mjs";
12
+ } from "./chunk-NPSQNCOY.mjs";
13
+ import {
14
+ init_define_KHALA_BUNDLE
15
+ } from "./chunk-7R3EIDGR.mjs";
13
16
 
14
17
  // ../contracts/src/m1/channel-event.ts
18
+ init_define_KHALA_BUNDLE();
15
19
  var CHANNEL_EVENT_TYPE = "com.khala.event.v1";
16
20
  var CHANNEL_EVENT_STATUSES = ["info", "pending", "success", "failure", "attention"];
17
21
  var MAX_CHANNEL_EVENT_BYTES = 4096;
@@ -3,19 +3,20 @@ import {
3
3
  WATCH_USAGE,
4
4
  mentions,
5
5
  monitorArmed,
6
+ monitorOwner,
6
7
  run,
7
8
  watchSession
8
- } from "./chunk-FH34B3I3.mjs";
9
- import "./chunk-5BQTYU66.mjs";
10
- import "./chunk-VKQ3KUYO.mjs";
11
- import "./chunk-CBPLCCRZ.mjs";
12
- import "./chunk-IQJQ4RF5.mjs";
13
- import "./chunk-NKX3SLS7.mjs";
14
- import "./chunk-7HBRFY3Z.mjs";
9
+ } from "./chunk-NIX5F4LT.mjs";
10
+ import "./chunk-NGSYOVQ4.mjs";
11
+ import "./chunk-TANCKTDK.mjs";
12
+ import "./chunk-NPSQNCOY.mjs";
13
+ import "./chunk-K7V7X6WU.mjs";
14
+ import "./chunk-7R3EIDGR.mjs";
15
15
  export {
16
16
  WATCH_USAGE,
17
17
  run as default,
18
18
  mentions,
19
19
  monitorArmed,
20
+ monitorOwner,
20
21
  watchSession
21
22
  };
@@ -1,26 +1,22 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
  import {
3
3
  KHALA_AGENT_VERSION
4
- } from "./chunk-5LIE5GUU.mjs";
4
+ } from "./chunk-ANSR4IAW.mjs";
5
5
  import {
6
6
  bundle
7
- } from "./chunk-APMWDF6B.mjs";
8
- import {
9
- StateError,
10
- ensureStateDir,
11
- readJson,
12
- stateRoot
13
- } from "./chunk-CBPLCCRZ.mjs";
7
+ } from "./chunk-3KDOTR54.mjs";
14
8
  import {
15
9
  LISTENING_MODES
16
- } from "./chunk-IQJQ4RF5.mjs";
10
+ } from "./chunk-NGSYOVQ4.mjs";
17
11
  import {
18
12
  HARNESS_REGISTRY,
19
13
  M1_LABEL_MAX_BYTES,
14
+ StateError,
20
15
  array,
21
16
  decodeWith,
22
17
  displayText,
23
18
  elementPath,
19
+ ensureStateDir,
24
20
  fail,
25
21
  harnessInfo,
26
22
  identifier,
@@ -29,17 +25,23 @@ import {
29
25
  object,
30
26
  readHarness,
31
27
  readHttpUrl,
28
+ readJson,
32
29
  readMatrixUserId,
33
30
  readRoomId,
34
31
  reserved,
35
32
  safeInteger,
33
+ stateRoot,
36
34
  text,
37
35
  utcTimestamp,
38
36
  utf8Length,
39
37
  version
40
- } from "./chunk-NKX3SLS7.mjs";
38
+ } from "./chunk-NPSQNCOY.mjs";
39
+ import {
40
+ init_define_KHALA_BUNDLE
41
+ } from "./chunk-7R3EIDGR.mjs";
41
42
 
42
43
  // src/client.ts
44
+ init_define_KHALA_BUNDLE();
43
45
  var KhalaClientError = class extends Error {
44
46
  constructor(code, message, extra) {
45
47
  super(message ?? code);
@@ -51,7 +53,11 @@ var KhalaClientError = class extends Error {
51
53
  code;
52
54
  };
53
55
 
56
+ // ../contracts/src/m1/local.ts
57
+ init_define_KHALA_BUNDLE();
58
+
54
59
  // ../contracts/src/m1/colors.ts
60
+ init_define_KHALA_BUNDLE();
55
61
  var HUMAN_COLOR_IDS = ["red", "orange", "amber", "lime", "green", "teal", "blue", "indigo", "purple", "pink"];
56
62
  function isHumanColorId(value) {
57
63
  return typeof value === "string" && HUMAN_COLOR_IDS.includes(value);
@@ -73,6 +79,7 @@ function readHumanColorId(input, path2) {
73
79
  }
74
80
 
75
81
  // ../contracts/src/m1/initials.ts
82
+ init_define_KHALA_BUNDLE();
76
83
  function normalizeInitials(input) {
77
84
  if (typeof input !== "string") return null;
78
85
  const nfc = input.normalize("NFC");
@@ -88,6 +95,12 @@ function readHumanInitials(input, path2) {
88
95
  return input;
89
96
  }
90
97
 
98
+ // ../contracts/src/m1/names.ts
99
+ init_define_KHALA_BUNDLE();
100
+
101
+ // ../contracts/src/m1/participants.ts
102
+ init_define_KHALA_BUNDLE();
103
+
91
104
  // ../contracts/src/m1/names.ts
92
105
  var USERNAME_MIN = 2;
93
106
  var USERNAME_MAX = 24;
@@ -488,6 +501,7 @@ function decodeChannelSecrets(input) {
488
501
  }
489
502
 
490
503
  // src/local/lifecycle.ts
504
+ init_define_KHALA_BUNDLE();
491
505
  import * as fs from "node:fs/promises";
492
506
  import { close as closeFd } from "node:fs";
493
507
  import path from "node:path";
@@ -1,19 +1,25 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
- import "./chunk-5GLTKWJ5.mjs";
2
+ import "./chunk-SSO5RFOX.mjs";
3
3
  import {
4
4
  CHANNEL_EVENT_TYPE,
5
5
  encodeChannelEvent,
6
6
  memberRenameContent
7
- } from "./chunk-54XFVSEC.mjs";
7
+ } from "./chunk-BV45NK7K.mjs";
8
8
  import {
9
9
  LISTENING_MODE_COMMAND_TYPE,
10
10
  LISTENING_MODE_MEMBER_KEY,
11
11
  memberListeningMode
12
- } from "./chunk-IQJQ4RF5.mjs";
13
- import "./chunk-NKX3SLS7.mjs";
14
- import "./chunk-7HBRFY3Z.mjs";
12
+ } from "./chunk-NGSYOVQ4.mjs";
13
+ import {
14
+ StateError
15
+ } from "./chunk-NPSQNCOY.mjs";
16
+ import {
17
+ init_define_KHALA_BUNDLE
18
+ } from "./chunk-7R3EIDGR.mjs";
15
19
 
16
20
  // src/matrix/session.ts
21
+ init_define_KHALA_BUNDLE();
22
+ import { randomUUID } from "node:crypto";
17
23
  import { createClient, ClientEvent, RoomEvent, MatrixEventEvent, SyncState, Direction, Method, EventType } from "matrix-js-sdk";
18
24
  function message(event) {
19
25
  const type = event.getType();
@@ -36,8 +42,10 @@ function message(event) {
36
42
  }
37
43
  async function createAgentMatrixSession(creds, opts) {
38
44
  const started = Date.now();
45
+ const rejoinTxnId = `khala.rejoin.${randomUUID()}`;
39
46
  const log = (line) => opts?.log?.(line);
40
- const client = createClient({ baseUrl: creds.homeserver, userId: creds.userId, accessToken: creds.accessToken, deviceId: creds.deviceId });
47
+ const persistent = opts?.cryptoStore ? await (await import("./chunk-PAJ4JJPV.mjs")).openCryptoStore(opts.cryptoStore.dir, opts.cryptoStore.root, creds) : void 0;
48
+ const client = createClient({ ...persistent ? { store: persistent.sync } : {}, baseUrl: creds.homeserver, userId: creds.userId, accessToken: creds.accessToken, deviceId: creds.deviceId });
41
49
  const handlers = /* @__PURE__ */ new Set();
42
50
  const ended = /* @__PURE__ */ new Set();
43
51
  const modeHandlers = /* @__PURE__ */ new Set();
@@ -48,8 +56,9 @@ async function createAgentMatrixSession(creds, opts) {
48
56
  const cancellations = /* @__PURE__ */ new Set();
49
57
  let joinedRoom;
50
58
  let stopped = false;
59
+ let recovering = persistent?.restored ?? false;
51
60
  const deliver = (event) => {
52
- if (stopped || !liveEvents.has(event)) return;
61
+ if (stopped || recovering || !liveEvents.has(event)) return;
53
62
  const command = event.getType() === LISTENING_MODE_COMMAND_TYPE && !event.isDecryptionFailure() && event.getId() && event.getRoomId() && event.getSender() ? { eventId: event.getId(), roomId: event.getRoomId(), sender: event.getSender(), ts: event.getTs(), content: event.getContent() } : void 0;
54
63
  const m = command ?? message(event);
55
64
  if (!m) {
@@ -85,7 +94,7 @@ async function createAgentMatrixSession(creds, opts) {
85
94
  }
86
95
  };
87
96
  const timeline = (event, _room, toStart, _removed, data) => {
88
- if (stopped || toStart || data?.liveEvent === false) return;
97
+ if (stopped || toStart || data?.liveEvent === false && !persistent?.restored) return;
89
98
  liveEvents.add(event);
90
99
  void client.decryptEventIfNeeded(event).then(() => deliver(event), () => log("live_decryption_failed"));
91
100
  };
@@ -152,9 +161,35 @@ async function createAgentMatrixSession(creds, opts) {
152
161
  check();
153
162
  });
154
163
  };
155
- const stop = async () => {
164
+ let stopping;
165
+ let wipe = false;
166
+ const stop = () => stopping ??= stopSession();
167
+ const stopSession = async () => {
156
168
  if (stopped) return;
157
169
  stopped = true;
170
+ if (wipe && persistent?.forgetIdentity) {
171
+ try {
172
+ await persistent.forgetIdentity();
173
+ } catch {
174
+ log("crypto_cleanup_failed");
175
+ }
176
+ }
177
+ let syncStopped;
178
+ if (persistent && client.getSyncState() !== null && client.getSyncState() !== SyncState.Stopped) {
179
+ syncStopped = new Promise((resolve, reject) => {
180
+ const done = (state) => {
181
+ if (state === SyncState.Stopped) finish();
182
+ };
183
+ const timer = setTimeout(() => finish(new Error("crypto_sync_stop_timeout")), 1e4);
184
+ const finish = (error) => {
185
+ clearTimeout(timer);
186
+ client.removeListener(ClientEvent.Sync, done);
187
+ if (error) reject(error);
188
+ else resolve();
189
+ };
190
+ client.on(ClientEvent.Sync, done);
191
+ });
192
+ }
158
193
  client.stopClient();
159
194
  client.removeListener(RoomEvent.Timeline, timeline);
160
195
  client.removeListener(MatrixEventEvent.Decrypted, decrypted);
@@ -166,6 +201,14 @@ async function createAgentMatrixSession(creds, opts) {
166
201
  handlers.clear();
167
202
  modeHandlers.clear();
168
203
  ended.clear();
204
+ if (persistent) {
205
+ try {
206
+ await syncStopped;
207
+ if (wipe) await persistent.wipe();
208
+ } finally {
209
+ await persistent.close();
210
+ }
211
+ }
169
212
  };
170
213
  const membershipEnded = (room, membership) => {
171
214
  if (stopped || room.roomId !== joinedRoom || !["leave", "ban"].includes(membership)) return;
@@ -174,7 +217,11 @@ async function createAgentMatrixSession(creds, opts) {
174
217
  const end = (reason) => {
175
218
  if (stopped) return;
176
219
  const listeners = [...ended];
177
- void stop();
220
+ wipe = true;
221
+ void stop().catch(() => {
222
+ log("crypto_cleanup_failed");
223
+ console.error("khala: crypto_cleanup_failed");
224
+ });
178
225
  for (const handler of listeners) {
179
226
  try {
180
227
  handler(reason);
@@ -184,7 +231,14 @@ async function createAgentMatrixSession(creds, opts) {
184
231
  }
185
232
  };
186
233
  try {
187
- await client.initRustCrypto({ useIndexedDB: false });
234
+ if (persistent) await persistent.sync.startup();
235
+ try {
236
+ await client.initRustCrypto(persistent ? { useIndexedDB: true, cryptoDatabasePrefix: persistent.prefix } : { useIndexedDB: false });
237
+ } catch (error) {
238
+ if (!persistent?.restored || error instanceof StateError && error.code === "unsafe_state_dir") throw error;
239
+ wipe = true;
240
+ throw new (await import("./chunk-PAJ4JJPV.mjs")).CryptoStoreCorruptError();
241
+ }
188
242
  const crypto = client.getCrypto();
189
243
  if (!crypto) throw new Error("crypto_unavailable");
190
244
  log(`crypto_version=${crypto.getVersion()}`);
@@ -227,6 +281,7 @@ async function createAgentMatrixSession(creds, opts) {
227
281
  }, ready, timeoutMs, error);
228
282
  return {
229
283
  userId: creds.userId,
284
+ ...persistent?.recovered ? { cryptoReset: true } : {},
230
285
  onEnded(handler) {
231
286
  if (!stopped) ended.add(handler);
232
287
  return () => {
@@ -277,16 +332,41 @@ async function createAgentMatrixSession(creds, opts) {
277
332
  const owner = ownJoin.getContent()["com.khala.invited_by"];
278
333
  if (typeof owner === "string") inviters.set(roomId, owner);
279
334
  const event = encodeChannelEvent({ kind: "member", summary: `${ownJoin.getContent().displayname ?? creds.userId} rejoined`, status: "info", source: { system: "khala-agent" } });
280
- if (event.ok) await client.sendEvent(roomId, CHANNEL_EVENT_TYPE, event.value, `khala.rejoin.${creds.deviceId}`);
335
+ if (event.ok) await client.sendEvent(roomId, CHANNEL_EVENT_TYPE, event.value, rejoinTxnId);
281
336
  }
282
337
  if (membership !== "join" && inviters.has(roomId)) {
283
338
  const content = { ...ownJoin.getContent(), membership: "join", "com.khala.invited_by": inviters.get(roomId) };
284
339
  await client.sendStateEvent(roomId, EventType.RoomMember, content, creds.userId);
285
340
  }
286
- joinTimes.set(roomId, membership === "join" ? rejoinedAt : ownJoin.getTs());
341
+ const joinedAt = persistent?.joinedAt ?? (membership === "join" ? rejoinedAt : ownJoin.getTs());
342
+ await persistent?.rememberJoin(joinedAt);
343
+ joinTimes.set(roomId, joinedAt);
344
+ if (persistent?.restored) {
345
+ let token = null;
346
+ const seenTokens = /* @__PURE__ */ new Set();
347
+ for (; ; ) {
348
+ if (stopped) throw new Error("session_stopped");
349
+ const page = await client.createMessagesRequest(roomId, token, 100, Direction.Backward);
350
+ let reachedJoin = false;
351
+ for (const raw of page.chunk) {
352
+ const event = client.getEventMapper()({ ...raw, room_id: roomId });
353
+ if (event.getTs() < joinedAt) {
354
+ reachedJoin = true;
355
+ continue;
356
+ }
357
+ liveEvents.add(event);
358
+ await client.decryptEventIfNeeded(event).catch(() => log("recovery_decryption_failed"));
359
+ }
360
+ if (reachedJoin || page.chunk.length === 0 || !page.end) break;
361
+ if (seenTokens.has(page.end)) throw new Error("recovery_pagination_stalled");
362
+ seenTokens.add(page.end);
363
+ token = page.end;
364
+ }
365
+ }
366
+ recovering = false;
287
367
  if (!joinedRoom) client.on(RoomEvent.MyMembership, membershipEnded);
288
368
  joinedRoom = roomId;
289
- for (const event of liveEvents) {
369
+ for (const event of [...liveEvents].sort((a, b) => a.getTs() - b.getTs())) {
290
370
  if (event.getRoomId() === roomId) deliver(event);
291
371
  }
292
372
  },
@@ -310,7 +390,7 @@ async function createAgentMatrixSession(creds, opts) {
310
390
  undecryptable++;
311
391
  const eventId = event.getId(), sender = event.getSender();
312
392
  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.]";
393
+ const body = "[Encrypted message unavailable: this device does not have its key. Keys may not have been shared for messages sent before joining or while this agent was offline.]";
314
394
  messages.push({
315
395
  eventId,
316
396
  roomId,