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
@@ -0,0 +1,58 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res, err) => function __init() {
9
+ if (err) throw err[0];
10
+ try {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ } catch (e) {
13
+ throw err = [e], e;
14
+ }
15
+ };
16
+ var __commonJS = (cb, mod) => function __require() {
17
+ try {
18
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
19
+ } catch (e) {
20
+ throw mod = 0, e;
21
+ }
22
+ };
23
+ var __export = (target, all) => {
24
+ for (var name in all)
25
+ __defProp(target, name, { get: all[name], enumerable: true });
26
+ };
27
+ var __copyProps = (to, from, except, desc) => {
28
+ if (from && typeof from === "object" || typeof from === "function") {
29
+ for (let key of __getOwnPropNames(from))
30
+ if (!__hasOwnProp.call(to, key) && key !== except)
31
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32
+ }
33
+ return to;
34
+ };
35
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
36
+ // If the importer is in node compatibility mode or this is not an ESM
37
+ // file that has been converted to a CommonJS file using a Babel-
38
+ // compatible transform (i.e. "__esModule" has not been set), then set
39
+ // "default" to the CommonJS "module.exports" for node compatibility.
40
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
41
+ mod
42
+ ));
43
+
44
+ // <define:__KHALA_BUNDLE__>
45
+ var define_KHALA_BUNDLE_default;
46
+ var init_define_KHALA_BUNDLE = __esm({
47
+ "<define:__KHALA_BUNDLE__>"() {
48
+ define_KHALA_BUNDLE_default = { name: "khala-cli", version: "0.4.10" };
49
+ }
50
+ });
51
+
52
+ export {
53
+ __commonJS,
54
+ __export,
55
+ __toESM,
56
+ init_define_KHALA_BUNDLE,
57
+ define_KHALA_BUNDLE_default
58
+ };
@@ -0,0 +1,22 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ cancelAttempt,
4
+ confirmWakeText,
5
+ failAttempt,
6
+ readWakeState,
7
+ recordAttempt,
8
+ resetWakeDriver,
9
+ settleAttempts,
10
+ takeWakeDisableNotices
11
+ } from "./chunk-ZSKLNZWZ.mjs";
12
+ import "./chunk-EVT2DWNZ.mjs";
13
+ export {
14
+ cancelAttempt,
15
+ confirmWakeText,
16
+ failAttempt,
17
+ readWakeState,
18
+ recordAttempt,
19
+ resetWakeDriver,
20
+ settleAttempts,
21
+ takeWakeDisableNotices
22
+ };
@@ -1,9 +1,11 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
2
  import {
3
- define_KHALA_BUNDLE_default
4
- } from "./chunk-7HBRFY3Z.mjs";
3
+ define_KHALA_BUNDLE_default,
4
+ init_define_KHALA_BUNDLE
5
+ } from "./chunk-EVT2DWNZ.mjs";
5
6
 
6
7
  // src/bundle.ts
8
+ init_define_KHALA_BUNDLE();
7
9
  var bundle = typeof define_KHALA_BUNDLE_default === "undefined" ? void 0 : define_KHALA_BUNDLE_default;
8
10
 
9
11
  export {
@@ -0,0 +1,7 @@
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/events/member-rename.ts
7
+ init_define_KHALA_BUNDLE();
@@ -5,16 +5,22 @@ import {
5
5
  fail,
6
6
  label,
7
7
  literal,
8
+ object,
8
9
  safeInteger,
9
10
  utcTimestamp,
10
11
  utf8Length,
11
12
  version
12
- } from "./chunk-NKX3SLS7.mjs";
13
+ } from "./chunk-PN25BUQ4.mjs";
14
+ import {
15
+ init_define_KHALA_BUNDLE
16
+ } from "./chunk-EVT2DWNZ.mjs";
13
17
 
14
18
  // ../contracts/src/m1/channel-event.ts
19
+ init_define_KHALA_BUNDLE();
15
20
  var CHANNEL_EVENT_TYPE = "com.khala.event.v1";
16
21
  var CHANNEL_EVENT_STATUSES = ["info", "pending", "success", "failure", "attention"];
17
22
  var MAX_CHANNEL_EVENT_BYTES = 4096;
23
+ var COORDINATION_KINDS = ["handoff", "handoff_ack", "verdict", "claim", "release", "note"];
18
24
  function record(input, path) {
19
25
  if (typeof input !== "object" || input === null || Array.isArray(input)) fail(path, "not_object");
20
26
  const prototype = Object.getPrototypeOf(input);
@@ -72,10 +78,66 @@ function decodeChannelEvent(raw) {
72
78
  ...r.has("url") ? { url: readUrl(r.field("url")) } : {},
73
79
  ...r.has("occurred_at") ? { occurred_at: utcTimestamp(r.field("occurred_at"), "occurred_at") } : {},
74
80
  ...r.has("source") ? { source: readSource(r.field("source")) } : {},
75
- ...r.has("key") ? { key: nonempty(label(r.field("key"), "key", 200), "key") } : {}
81
+ ...r.has("key") ? { key: nonempty(label(r.field("key"), "key", 200), "key") } : {},
82
+ // Older senders may use these kind names without data: such events stay plain events.
83
+ ...r.has("data") && isCoordinationKind(kind) ? { data: readData(kind, r.field("data")) } : {}
76
84
  };
77
85
  }));
78
86
  }
87
+ function isCoordinationKind(kind) {
88
+ return COORDINATION_KINDS.includes(kind);
89
+ }
90
+ var short = (input, path) => display(input, path, 256, 64);
91
+ var reason = (input, path) => display(input, path, 800, 200);
92
+ function readData(kind, input) {
93
+ const fields = {
94
+ handoff: ["ticket", "from", "to", "reason", "state"],
95
+ handoff_ack: ["ticket"],
96
+ verdict: ["pr", "verdict", "reason"],
97
+ claim: ["key"],
98
+ release: ["key"],
99
+ note: ["key", "value"]
100
+ }[kind];
101
+ const r = object(input, "data", fields);
102
+ const read = (key) => {
103
+ const value = r.field(key);
104
+ switch (key) {
105
+ case "pr": {
106
+ const pr = safeInteger(value, r.at(key));
107
+ if (pr === 0) fail(r.at(key), "invalid_value");
108
+ return pr;
109
+ }
110
+ case "verdict":
111
+ return literal(value, r.at(key), ["approved", "changes_requested"]);
112
+ case "reason":
113
+ return reason(value, r.at(key));
114
+ case "key":
115
+ return nonempty(label(value, r.at(key), 128), r.at(key));
116
+ // An empty value clears the note.
117
+ case "value":
118
+ return typeof value === "string" && value === "" ? "" : reason(value, r.at(key));
119
+ default:
120
+ return short(value, r.at(key));
121
+ }
122
+ };
123
+ return Object.fromEntries(fields.map((key) => [key, read(key)]));
124
+ }
125
+ function coordinationSummary(kind, d) {
126
+ switch (kind) {
127
+ case "handoff":
128
+ return `handoff ${d.ticket} ${d.from} \u2192 ${d.to} (${d.state}): ${d.reason}`;
129
+ case "handoff_ack":
130
+ return `handoff ${d.ticket} acknowledged`;
131
+ case "verdict":
132
+ return `PR #${d.pr} ${d.verdict === "approved" ? "approved" : "changes requested"}: ${d.reason}`;
133
+ case "claim":
134
+ return `claimed ${d.key}`;
135
+ case "release":
136
+ return `released ${d.key}`;
137
+ case "note":
138
+ return d.value === "" ? `note ${d.key} cleared` : `note ${d.key} = ${d.value}`;
139
+ }
140
+ }
79
141
  function readSubject(input) {
80
142
  const r = record(input, "subject");
81
143
  let pr;
@@ -123,8 +185,23 @@ function formatChannelEventLine(content) {
123
185
  function encodeChannelEvent(input) {
124
186
  return safely(() => {
125
187
  const checked = decodeWith(() => {
126
- record(input, "");
127
- return { ...input, v: 1, body: "" };
188
+ const r = record(input, "");
189
+ const raw = input;
190
+ const kind = raw.kind;
191
+ if (typeof kind !== "string" || !isCoordinationKind(kind)) {
192
+ if (r.has("data")) fail("data", "invalid_value");
193
+ return { ...raw, v: 1, body: "" };
194
+ }
195
+ const data = readData(kind, r.field("data"));
196
+ const derived = coordinationSummary(kind, data);
197
+ return {
198
+ ...raw,
199
+ v: 1,
200
+ body: "",
201
+ data,
202
+ ...r.has("summary") ? {} : { summary: [...derived].length > 200 ? [...derived].slice(0, 199).join("") + "\u2026" : derived },
203
+ ...r.has("status") || kind !== "verdict" ? {} : { status: data.verdict === "approved" ? "success" : "attention" }
204
+ };
128
205
  });
129
206
  if (!checked.ok) return checked;
130
207
  const decoded = decodeChannelEvent(checked.value);
@@ -159,6 +236,26 @@ function statusFor(content) {
159
236
  return content.kind.startsWith("agent.attention.") && !content.kind.endsWith(".resolved") ? "attention" : "info";
160
237
  }
161
238
  }
239
+ function foldCoordination(events) {
240
+ const handoffs = /* @__PURE__ */ new Map();
241
+ const claims = /* @__PURE__ */ new Map();
242
+ const notes = /* @__PURE__ */ new Map();
243
+ for (const { sender, by, at, content: { kind, data } } of events) {
244
+ if (!data) continue;
245
+ const s = (key) => String(data[key]);
246
+ if (kind === "handoff") {
247
+ handoffs.delete(s("ticket"));
248
+ handoffs.set(s("ticket"), { ticket: s("ticket"), from: s("from"), to: s("to"), reason: s("reason"), state: s("state"), by, at });
249
+ } else if (kind === "handoff_ack") handoffs.delete(s("ticket"));
250
+ else if (kind === "claim" && !claims.has(s("key"))) claims.set(s("key"), { key: s("key"), by, sender, at });
251
+ else if (kind === "release" && claims.get(s("key"))?.sender === sender) claims.delete(s("key"));
252
+ else if (kind === "note") {
253
+ notes.delete(s("key"));
254
+ if (s("value") !== "") notes.set(s("key"), s("value"));
255
+ }
256
+ }
257
+ return { openHandoffs: [...handoffs.values()], activeClaims: [...claims.values()], notes: Object.fromEntries(notes) };
258
+ }
162
259
 
163
260
  export {
164
261
  CHANNEL_EVENT_TYPE,
@@ -166,5 +263,6 @@ export {
166
263
  formatChannelEventLine,
167
264
  encodeChannelEvent,
168
265
  memberRenameContent,
169
- statusFor
266
+ statusFor,
267
+ foldCoordination
170
268
  };
@@ -14,22 +14,24 @@ import {
14
14
  decodeLocalSendResult,
15
15
  ensureHelper,
16
16
  localRoomPath
17
- } from "./chunk-2DHIAFEV.mjs";
18
- import "./chunk-5LIE5GUU.mjs";
19
- import "./chunk-APMWDF6B.mjs";
20
- import "./chunk-5GLTKWJ5.mjs";
17
+ } from "./chunk-SRZTHCXP.mjs";
18
+ import "./chunk-HHEZVPRR.mjs";
19
+ import "./chunk-XR625T3I.mjs";
20
+ import "./chunk-G3NMB4PY.mjs";
21
+ import {
22
+ LISTENING_MODE_COMMAND_TYPE
23
+ } from "./chunk-4BP7V3OP.mjs";
21
24
  import {
22
25
  CHANNEL_EVENT_TYPE,
23
26
  memberRenameContent
24
- } from "./chunk-54XFVSEC.mjs";
25
- import "./chunk-CBPLCCRZ.mjs";
27
+ } from "./chunk-JKOJQTFT.mjs";
28
+ import "./chunk-PN25BUQ4.mjs";
26
29
  import {
27
- LISTENING_MODE_COMMAND_TYPE
28
- } from "./chunk-IQJQ4RF5.mjs";
29
- import "./chunk-NKX3SLS7.mjs";
30
- import "./chunk-7HBRFY3Z.mjs";
30
+ init_define_KHALA_BUNDLE
31
+ } from "./chunk-EVT2DWNZ.mjs";
31
32
 
32
33
  // src/local/session.ts
34
+ init_define_KHALA_BUNDLE();
33
35
  import { randomUUID } from "node:crypto";
34
36
  var LocalCallError = class extends Error {
35
37
  constructor(status, code) {
@@ -122,6 +124,7 @@ async function createLocalSession(creds, opts = {}) {
122
124
  let name;
123
125
  let invitedBy;
124
126
  let after = 0;
127
+ let joinedAt;
125
128
  function check(roomId) {
126
129
  if (stopped) throw new Error("session_stopped");
127
130
  if (roomId !== creds.roomId) throw new Error("unknown_room");
@@ -321,6 +324,7 @@ async function createLocalSession(creds, opts = {}) {
321
324
  joining ??= (async () => {
322
325
  const result = decoded(await withHelper(() => request("POST", "join", {})), decodeLocalJoined);
323
326
  after = result.seq;
327
+ joinedAt = result.ts;
324
328
  await me();
325
329
  const members = decoded(await withHelper(() => request("GET", "members?wire=2")), decodeLocalMembersResponse);
326
330
  check(roomId);
@@ -338,6 +342,7 @@ async function createLocalSession(creds, opts = {}) {
338
342
  joining = void 0;
339
343
  }
340
344
  },
345
+ joinedAt: (roomId) => roomId === creds.roomId ? joinedAt : void 0,
341
346
  async history(roomId, limit, before) {
342
347
  check(roomId);
343
348
  const page = decoded(await withHelper(() => request("GET", `messages?wire=2&limit=${limit}${before !== void 0 ? `&before=${encodeURIComponent(before)}` : ""}`)), decodeLocalHistoryPage);
@@ -1,4 +1,8 @@
1
1
  import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ decodeChannelEvent,
4
+ formatChannelEventLine
5
+ } from "./chunk-JKOJQTFT.mjs";
2
6
  import {
3
7
  StateError,
4
8
  channelFiles,
@@ -6,14 +10,57 @@ import {
6
10
  ensureStateDir,
7
11
  filesForDir,
8
12
  readJson,
9
- readStatus,
10
13
  removeStateFile,
11
14
  stateKey,
12
15
  writeJsonAtomic,
13
16
  writeStateFile
14
- } from "./chunk-CBPLCCRZ.mjs";
17
+ } from "./chunk-PN25BUQ4.mjs";
18
+ import {
19
+ init_define_KHALA_BUNDLE
20
+ } from "./chunk-EVT2DWNZ.mjs";
21
+
22
+ // src/events/receive.ts
23
+ init_define_KHALA_BUNDLE();
24
+ function toEventInboxEntry(base, rawContent, you) {
25
+ const decoded = decodeChannelEvent(rawContent);
26
+ if (!decoded.ok) return null;
27
+ const content = decoded.value;
28
+ const to = content.kind === "handoff" ? String(content.data?.to ?? "").replace(/^@/u, "").toLowerCase() : "";
29
+ return {
30
+ entry: {
31
+ ...base,
32
+ kind: "event",
33
+ body: formatChannelEventLine(content) + (content.url ? " " + content.url : ""),
34
+ eventKind: content.kind,
35
+ ...content.data ? { data: content.data } : {},
36
+ ...to && to === you?.toLowerCase() ? { mention: true } : {}
37
+ },
38
+ ...content.key !== void 0 ? { key: content.key } : {}
39
+ };
40
+ }
41
+ function createEventKeyFilter() {
42
+ const seen = /* @__PURE__ */ new Set();
43
+ return (key) => {
44
+ if (key === void 0) return true;
45
+ if (seen.has(key)) return false;
46
+ seen.add(key);
47
+ return true;
48
+ };
49
+ }
50
+ function isWakeEntry(entry) {
51
+ return entry.kind === "message" || entry.mention === true;
52
+ }
53
+ function mentions(entry, name) {
54
+ if (!name) return false;
55
+ const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
56
+ return new RegExp(`(?<![\\p{L}\\p{N}_])@?${escaped}(?![\\p{L}\\p{N}_])`, "iu").test(entry.body);
57
+ }
58
+ function wakesAgent(entry, mode, you) {
59
+ return isWakeEntry(entry) && (mode !== "sync" || entry.senderKind !== "agent" || entry.mention === true || mentions(entry, you));
60
+ }
15
61
 
16
62
  // src/inbox.ts
63
+ init_define_KHALA_BUNDLE();
17
64
  import * as fs from "node:fs/promises";
18
65
  async function readEntries(files) {
19
66
  let content;
@@ -60,16 +107,18 @@ async function unread(files) {
60
107
  }
61
108
  async function unreadCounts(files) {
62
109
  const { entries } = await unread(files);
63
- return { total: entries.length, messages: entries.filter((entry) => entry.kind === "message").length };
110
+ return { total: entries.length, messages: entries.filter((entry) => isWakeEntry(entry)).length };
64
111
  }
65
- async function advanceCursor(files, expected, delivered) {
112
+ async function advanceCursor(files, expected, delivered, shown = false) {
66
113
  const current = await readCursor(files);
67
114
  if (current.deliveredCount !== expected.deliveredCount || current.lastDeliveredEventId !== expected.lastDeliveredEventId) return "conflict";
68
115
  if (!delivered.length) return expected;
69
116
  const entries = await readEntries(files);
70
117
  const slice = entries.slice(expected.deliveredCount, expected.deliveredCount + delivered.length);
71
118
  if (slice.length !== delivered.length || slice.some((entry, index) => entry.eventId !== delivered[index]?.eventId)) return "conflict";
72
- const next = { lastDeliveredEventId: delivered[delivered.length - 1].eventId, deliveredCount: expected.deliveredCount + delivered.length };
119
+ const last = delivered[delivered.length - 1].eventId;
120
+ const shownEventId = shown ? last : current.shownEventId;
121
+ const next = { lastDeliveredEventId: last, deliveredCount: expected.deliveredCount + delivered.length, ...shownEventId ? { shownEventId } : {} };
73
122
  await writeJsonAtomic(files.cursor, next);
74
123
  return next;
75
124
  }
@@ -81,6 +130,7 @@ function unreadCount(dir) {
81
130
  }
82
131
 
83
132
  // src/channels.ts
133
+ init_define_KHALA_BUNDLE();
84
134
  import * as fs2 from "node:fs/promises";
85
135
  import path from "node:path";
86
136
  function channelKey(roomId2) {
@@ -134,7 +184,7 @@ async function listChannels(files) {
134
184
  if (await exists(files.inbox)) {
135
185
  const id = await legacyRoomId(files);
136
186
  if (id) {
137
- const status = await readStatus(files);
187
+ const status = await readJson(files.status);
138
188
  channels.push({ key: channelKey(id), roomId: id, ...typeof status?.channelName === "string" ? { channelName: status.channelName } : {}, files, legacy: true });
139
189
  }
140
190
  }
@@ -161,7 +211,7 @@ async function migrateLegacy(files) {
161
211
  console.warn(`Khala cursor migration: conflicting cursors for ${id}; using earlier position ${safe.deliveredCount} to avoid skipping messages (legacy=${legacyCursor.deliveredCount}, channel=${channelCursor.deliveredCount}).`);
162
212
  }
163
213
  }
164
- const status = await readStatus(files);
214
+ const status = await readJson(files.status);
165
215
  const metadata = await readJson(path.join(nested.dir, "channel.json"));
166
216
  if (!metadata || roomId(metadata) !== id) {
167
217
  await writeStateFile(nested.dir, "channel.json", {
@@ -203,11 +253,23 @@ function resolveChannel(list, ref) {
203
253
  }
204
254
 
205
255
  // src/activity.ts
256
+ init_define_KHALA_BUNDLE();
257
+ import * as fs3 from "node:fs/promises";
206
258
  import path2 from "node:path";
207
259
  async function readActivity(files) {
208
260
  const activity = await readJson(path2.join(files.dir, "activity.json"));
209
261
  return activity && ["idle", "busy"].includes(activity.state) && typeof activity.updatedAt === "string" && Number.isFinite(Date.parse(activity.updatedAt)) ? activity : { state: "busy", updatedAt: (/* @__PURE__ */ new Date(0)).toISOString() };
210
262
  }
263
+ var USAGE_LIMIT = "usage-limit.json";
264
+ async function markUsageLimit(files, now = () => /* @__PURE__ */ new Date()) {
265
+ await writeJsonAtomic(path2.join(files.dir, USAGE_LIMIT), { at: now().toISOString() });
266
+ }
267
+ async function clearUsageLimit(files) {
268
+ await fs3.rm(path2.join(files.dir, USAGE_LIMIT), { force: true });
269
+ }
270
+ async function usageLimited(dir) {
271
+ return await readJson(path2.join(dir, USAGE_LIMIT)) !== null;
272
+ }
211
273
  async function writeActivity(files, state, now = () => /* @__PURE__ */ new Date()) {
212
274
  const activity = { state, updatedAt: now().toISOString() };
213
275
  await writeJsonAtomic(path2.join(files.dir, "activity.json"), activity);
@@ -215,6 +277,11 @@ async function writeActivity(files, state, now = () => /* @__PURE__ */ new Date(
215
277
  }
216
278
 
217
279
  export {
280
+ toEventInboxEntry,
281
+ createEventKeyFilter,
282
+ isWakeEntry,
283
+ mentions,
284
+ wakesAgent,
218
285
  readEntries,
219
286
  readCursor,
220
287
  unread,
@@ -226,5 +293,8 @@ export {
226
293
  migrateLegacy,
227
294
  resolveChannel,
228
295
  readActivity,
296
+ markUsageLimit,
297
+ clearUsageLimit,
298
+ usageLimited,
229
299
  writeActivity
230
300
  };
@@ -0,0 +1,173 @@
1
+ import { createRequire as __khalaCreateRequire } from 'node:module'; const require = __khalaCreateRequire(import.meta.url);
2
+ import {
3
+ WAKE_HARNESSES,
4
+ wakeDrivers,
5
+ wakeStatus
6
+ } from "./chunk-W6HM6F2U.mjs";
7
+ import {
8
+ adapterFor,
9
+ registerAntigravityWake,
10
+ resolveSources
11
+ } from "./chunk-5JSGA6OB.mjs";
12
+ import {
13
+ CURSOR_DEFAULT_SESSION,
14
+ updateWakeSettings
15
+ } from "./chunk-2AMWQ7RB.mjs";
16
+ import {
17
+ SESSION_ID_PATTERN,
18
+ filesForDir,
19
+ stateRoot
20
+ } from "./chunk-PN25BUQ4.mjs";
21
+ import {
22
+ resetWakeDriver
23
+ } from "./chunk-ZSKLNZWZ.mjs";
24
+ import {
25
+ init_define_KHALA_BUNDLE
26
+ } from "./chunk-EVT2DWNZ.mjs";
27
+
28
+ // src/wake/cli.ts
29
+ init_define_KHALA_BUNDLE();
30
+ import * as fs from "node:fs/promises";
31
+ import path from "node:path";
32
+ var WAKE_USAGE = "usage: khala wake on|off|status|register [--driver <d>] [--harness <id>] [--json]";
33
+ async function sessionIds(harness, env) {
34
+ try {
35
+ return (await fs.readdir(path.join(stateRoot(env), harness), { withFileTypes: true })).filter((entry) => entry.isDirectory() && SESSION_ID_PATTERN.test(entry.name)).map((entry) => entry.name);
36
+ } catch (error) {
37
+ if (error.code === "ENOENT") return [];
38
+ throw error;
39
+ }
40
+ }
41
+ async function setWake(harness, drivers, on, env) {
42
+ const root = stateRoot(env);
43
+ const at = (/* @__PURE__ */ new Date()).toISOString();
44
+ await updateWakeSettings(root, (settings) => {
45
+ for (const driver of drivers) {
46
+ const key = `${harness}/${driver}`;
47
+ if (on) {
48
+ settings.consent[key] = { at };
49
+ delete settings.off[key];
50
+ } else {
51
+ delete settings.consent[key];
52
+ settings.off[key] = { at };
53
+ }
54
+ }
55
+ });
56
+ if (on) for (const id of await sessionIds(harness, env)) {
57
+ for (const driver of drivers) {
58
+ const dir = filesForDir(path.join(root, harness, id)).dir;
59
+ await resetWakeDriver(dir, driver);
60
+ if (harness === "qwen" && driver === "socket") await fs.rm(path.join(dir, "qwen-receipt.json"), { force: true });
61
+ }
62
+ }
63
+ }
64
+ function consentLine(harness, drivers, on) {
65
+ if (harness === "antigravity" && on) return `Idle wake is on (${drivers.join(", ")}): native wake preserves drafts; terminal fallback requires an empty prompt. Wake and Sync continuation use billed model turns. Run \`khala wake off --harness antigravity\` to turn it off.`;
66
+ return on ? `Idle wake is on (${drivers.join(", ")}): Khala may send a fixed wake line into this agent's existing session when messages wait and ${harness === "muse" ? "the session is idle (through Muse\u2019s native monitor)" : "the prompt is empty"}. Run \`khala wake off --harness ${harness}\` to turn it off.` : `Idle wake is off for ${drivers.join(", ")}. Run \`khala wake on --harness ${harness}\` to turn it on.`;
67
+ }
68
+ async function currentSessionId(harness, env) {
69
+ const adapter = adapterFor(harness);
70
+ if (!adapter) return void 0;
71
+ const session = await resolveSources(adapter.sessionSources.filter((source) => source.kind !== "process"), void 0, env, { harness: adapter.id });
72
+ return session?.sessionId !== CURSOR_DEFAULT_SESSION ? session?.sessionId : void 0;
73
+ }
74
+ async function runWake(argv, deps = {}) {
75
+ const env = deps.env ?? process.env;
76
+ const out = deps.stdout ?? console.log;
77
+ const err = deps.stderr ?? console.error;
78
+ const [command, ...flags] = argv;
79
+ let harness;
80
+ let driver;
81
+ let json = false;
82
+ for (let i = 0; i < flags.length; i++) {
83
+ const flag = flags[i];
84
+ if (flag === "--json") json = true;
85
+ else if ((flag === "--harness" || flag === "--driver") && flags[i + 1] && !flags[i + 1].startsWith("--")) {
86
+ const value = flags[++i];
87
+ if (flag === "--harness") harness = value;
88
+ else driver = value;
89
+ } else {
90
+ err(WAKE_USAGE);
91
+ return 2;
92
+ }
93
+ }
94
+ if (command === "register") {
95
+ if (harness !== "antigravity" || driver || json) {
96
+ err(WAKE_USAGE);
97
+ return 2;
98
+ }
99
+ try {
100
+ await registerAntigravityWake(env);
101
+ out("Registered Antigravity native wake for this session.");
102
+ return 0;
103
+ } catch {
104
+ err("khala: Antigravity wake registration unavailable; run this command through the agent shell.");
105
+ return 1;
106
+ }
107
+ }
108
+ if (!["on", "off", "status"].includes(command ?? "")) {
109
+ err(WAKE_USAGE);
110
+ return 2;
111
+ }
112
+ if (harness && !WAKE_HARNESSES.includes(harness)) {
113
+ err(`Unknown harness ${harness}. Valid harnesses: ${WAKE_HARNESSES.join(", ")}`);
114
+ return 2;
115
+ }
116
+ const candidates = harness ? [harness] : WAKE_HARNESSES;
117
+ const valid = [...new Set(candidates.flatMap((id) => wakeDrivers(id).map((item) => item.id)))];
118
+ if (driver && !valid.includes(driver)) {
119
+ err(`Unknown driver ${driver}. Valid drivers: ${valid.join(", ") || "none"}`);
120
+ return 2;
121
+ }
122
+ if (!harness && command !== "status") {
123
+ for (const id of WAKE_HARNESSES) {
124
+ if (await currentSessionId(id, env) !== void 0) {
125
+ harness = id;
126
+ break;
127
+ }
128
+ }
129
+ if (!harness && driver) {
130
+ const matches = WAKE_HARNESSES.filter((id) => wakeDrivers(id).some((item) => item.id === driver));
131
+ if (matches.length === 1) harness = matches[0];
132
+ }
133
+ if (!harness) {
134
+ err(`Select --harness. Valid harnesses: ${WAKE_HARNESSES.join(", ")}`);
135
+ return 2;
136
+ }
137
+ if (driver && !wakeDrivers(harness).some((item) => item.id === driver)) {
138
+ err(`Unknown driver ${driver}. Valid drivers: ${wakeDrivers(harness).map((item) => item.id).join(", ") || "none"}`);
139
+ return 2;
140
+ }
141
+ }
142
+ const harnesses = harness ? [harness] : WAKE_HARNESSES;
143
+ if (command === "status") {
144
+ const rows = [];
145
+ for (const id of harnesses) {
146
+ const sessionId = await currentSessionId(id, env);
147
+ rows.push(...await wakeStatus(id, { env, ...sessionId ? { files: filesForDir(path.join(stateRoot(env), id, sessionId)), sessionId } : {} }));
148
+ }
149
+ const selected = driver ? rows.filter((row) => row.driver === driver) : rows;
150
+ out(json ? JSON.stringify(selected) : selected.map((row) => `${row.harness} ${row.driver} ${row.rung} ${row.state} ${row.reason}${row.remedy ? ` ${row.remedy}` : ""}${row.note ? ` ${row.note}` : ""}`).join("\n"));
151
+ } else {
152
+ const all = wakeDrivers(harness);
153
+ const selected = driver ? [driver] : command === "on" ? [all.find((item) => item.optIn)?.id ?? all[0]?.id].filter((id) => !!id) : all.map((item) => item.id);
154
+ if (!selected.length) {
155
+ err(`No wake drivers for ${harness}.`);
156
+ return 2;
157
+ }
158
+ await setWake(harness, selected, command === "on", env);
159
+ const message = consentLine(harness, selected, command === "on");
160
+ out(json ? JSON.stringify({ harness, drivers: selected, on: command === "on", message }) : message);
161
+ }
162
+ return 0;
163
+ }
164
+ var cli_default = runWake;
165
+
166
+ export {
167
+ WAKE_USAGE,
168
+ sessionIds,
169
+ setWake,
170
+ consentLine,
171
+ runWake,
172
+ cli_default
173
+ };