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.
- package/README.md +4 -4
- package/dist/THIRD_PARTY_NOTICES.txt +809 -0
- package/dist/chunk-2AMWQ7RB.mjs +1127 -0
- package/dist/chunk-3E5DH3Y6.mjs +9864 -0
- package/dist/{chunk-IQJQ4RF5.mjs → chunk-4BP7V3OP.mjs} +12 -1
- package/dist/{chunk-FV32AQTC.mjs → chunk-4BZQ4GVW.mjs} +10 -6
- package/dist/chunk-5JSGA6OB.mjs +1483 -0
- package/dist/chunk-6AQVW5W7.mjs +60 -0
- package/dist/{chunk-W6R4UJUQ.mjs → chunk-6J2PUM7L.mjs} +16 -9
- package/dist/chunk-6SUV3EW6.mjs +27 -0
- package/dist/{chunk-RNDUFTBF.mjs → chunk-ARIDZOTI.mjs} +499 -115
- package/dist/chunk-C2WEDMAF.mjs +15 -0
- package/dist/{chunk-Z4JF2M5C.mjs → chunk-CHC4VZF5.mjs} +9 -9
- package/dist/chunk-CKLCR5G4.mjs +1369 -0
- package/dist/chunk-EVT2DWNZ.mjs +58 -0
- package/dist/chunk-FJVVSKZ3.mjs +22 -0
- package/dist/{chunk-APMWDF6B.mjs → chunk-G3NMB4PY.mjs} +4 -2
- package/dist/chunk-HHEZVPRR.mjs +7 -0
- package/dist/{chunk-54XFVSEC.mjs → chunk-JKOJQTFT.mjs} +103 -5
- package/dist/{chunk-ZJ4W7P33.mjs → chunk-NDMFD5IM.mjs} +15 -10
- package/dist/{chunk-VKQ3KUYO.mjs → chunk-OEV5DFLW.mjs} +77 -7
- package/dist/chunk-OIZ4R5H7.mjs +173 -0
- package/dist/{chunk-CJTCU755.mjs → chunk-PJKI7SRI.mjs} +256 -26
- package/dist/chunk-PN25BUQ4.mjs +599 -0
- package/dist/chunk-QDPJ4VT2.mjs +432 -0
- package/dist/{chunk-2DHIAFEV.mjs → chunk-SRZTHCXP.mjs} +24 -10
- package/dist/chunk-TSK3HJEG.mjs +20 -0
- package/dist/chunk-UX34IVN5.mjs +33 -0
- package/dist/{chunk-BKLW2SPG.mjs → chunk-VAC3JTAV.mjs} +34 -17
- package/dist/{chunk-VAI7IUI4.mjs → chunk-VDZK4LW3.mjs} +30 -12
- package/dist/chunk-W6HM6F2U.mjs +901 -0
- package/dist/{chunk-H3K4GA2P.mjs → chunk-WPNMWNCL.mjs} +33 -21
- package/dist/chunk-WUDXHF2Q.mjs +14 -0
- package/dist/chunk-WZJ6DQJV.mjs +19 -0
- package/dist/{chunk-5LIE5GUU.mjs → chunk-XR625T3I.mjs} +5 -1
- package/dist/chunk-ZSKLNZWZ.mjs +224 -0
- package/dist/iterm2_send.py +56 -0
- package/dist/khala.mjs +20 -13
- package/dist/web/assets/local-CSPuGnH2.css +1 -0
- package/dist/web/assets/local-Dtyxaacx.js +9 -0
- package/dist/web/index.html +2 -2
- package/package.json +5 -3
- package/dist/chunk-2VCAW4GH.mjs +0 -34
- package/dist/chunk-5BQTYU66.mjs +0 -886
- package/dist/chunk-5GLTKWJ5.mjs +0 -1
- package/dist/chunk-5PUQT3YS.mjs +0 -569
- package/dist/chunk-7HBRFY3Z.mjs +0 -8
- package/dist/chunk-CBPLCCRZ.mjs +0 -191
- package/dist/chunk-FH34B3I3.mjs +0 -235
- package/dist/chunk-NKX3SLS7.mjs +0 -227
- package/dist/chunk-VUSV2ADL.mjs +0 -267
- package/dist/web/assets/local-BQl2KrE1.js +0 -9
- 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-
|
|
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-
|
|
35
|
+
} from "./chunk-SRZTHCXP.mjs";
|
|
36
|
+
import "./chunk-HHEZVPRR.mjs";
|
|
36
37
|
import {
|
|
37
38
|
KHALA_AGENT_VERSION
|
|
38
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-XR625T3I.mjs";
|
|
39
40
|
import {
|
|
40
41
|
bundle
|
|
41
|
-
} from "./chunk-
|
|
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-
|
|
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
|
-
|
|
73
|
-
|
|
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-
|
|
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-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import
|
|
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
|
|
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-
|
|
82
|
-
deliver: () => import("./chunk-
|
|
83
|
-
"claude-wake": () => import("./chunk-
|
|
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-
|
|
87
|
-
watch: () => () => import("./chunk-
|
|
88
|
-
local: () => () => import("./chunk-
|
|
89
|
-
install: () => () => import("./chunk-
|
|
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
|
});
|