khala-cli 0.4.6 → 0.4.8

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/README.md +18 -1
  2. package/dist/{chunk-2U4E7AM7.mjs → chunk-2DHIAFEV.mjs} +294 -101
  3. package/dist/{chunk-CWHGNVZV.mjs → chunk-2VCAW4GH.mjs} +1 -1
  4. package/dist/{chunk-P5CP32X2.mjs → chunk-54XFVSEC.mjs} +1 -1
  5. package/dist/chunk-5BQTYU66.mjs +886 -0
  6. package/dist/{chunk-RRBIVI77.mjs → chunk-5LIE5GUU.mjs} +1 -1
  7. package/dist/{chunk-6E3UCO22.mjs → chunk-5PUQT3YS.mjs} +200 -20
  8. package/dist/{chunk-55KBLEX5.mjs → chunk-7HBRFY3Z.mjs} +1 -1
  9. package/dist/{chunk-PFDUXY3N.mjs → chunk-APMWDF6B.mjs} +1 -1
  10. package/dist/{chunk-PY2ZNVNY.mjs → chunk-BKLW2SPG.mjs} +55 -8
  11. package/dist/{chunk-OW3DSTEZ.mjs → chunk-CBPLCCRZ.mjs} +5 -5
  12. package/dist/{chunk-JG5J3SHW.mjs → chunk-CJTCU755.mjs} +4 -4
  13. package/dist/{chunk-AWBKVTLV.mjs → chunk-FH34B3I3.mjs} +14 -17
  14. package/dist/chunk-FV32AQTC.mjs +40 -0
  15. package/dist/{chunk-FH2CZX5T.mjs → chunk-H3K4GA2P.mjs} +83 -36
  16. package/dist/{chunk-AUJEUKVM.mjs → chunk-IQJQ4RF5.mjs} +1 -1
  17. package/dist/{chunk-SN3STAO2.mjs → chunk-NKX3SLS7.mjs} +40 -3
  18. package/dist/{chunk-Z4EDYB6Y.mjs → chunk-RNDUFTBF.mjs} +97 -57
  19. package/dist/{chunk-OECJ45NM.mjs → chunk-VAI7IUI4.mjs} +24 -8
  20. package/dist/{chunk-XUJIJ4KB.mjs → chunk-VKQ3KUYO.mjs} +16 -2
  21. package/dist/{chunk-4X35OUAN.mjs → chunk-VUSV2ADL.mjs} +92 -97
  22. package/dist/{chunk-2XTYRBYX.mjs → chunk-W6R4UJUQ.mjs} +12 -5
  23. package/dist/{chunk-B2MOLCJM.mjs → chunk-Z4JF2M5C.mjs} +7 -9
  24. package/dist/{chunk-SZIEG3RS.mjs → chunk-ZJ4W7P33.mjs} +12 -14
  25. package/dist/khala.mjs +11 -11
  26. package/dist/web/assets/local-BQl2KrE1.js +9 -0
  27. package/dist/web/assets/local-OwDq47O4.css +1 -0
  28. package/dist/web/index.html +2 -2
  29. package/package.json +1 -1
  30. package/dist/chunk-DPW43YNC.mjs +0 -36
  31. package/dist/chunk-IULQYQJZ.mjs +0 -144
  32. package/dist/chunk-WHONG7UF.mjs +0 -267
  33. package/dist/chunk-ZHMGB3PP.mjs +0 -82
  34. package/dist/web/assets/local-K8EcTVxW.js +0 -9
  35. package/dist/web/assets/local-R2y0Gl4T.css +0 -1
@@ -2,15 +2,7 @@ import { createRequire as __khalaCreateRequire } from 'node:module'; const requi
2
2
  import {
3
3
  parseChannelLink,
4
4
  resolveLocalOwnerName
5
- } from "./chunk-OECJ45NM.mjs";
6
- import {
7
- KHALA_AGENT_VERSION
8
- } from "./chunk-RRBIVI77.mjs";
9
- import {
10
- ensureHelper,
11
- helperPaths,
12
- readHelperFile
13
- } from "./chunk-IULQYQJZ.mjs";
5
+ } from "./chunk-VAI7IUI4.mjs";
14
6
  import {
15
7
  LOCAL_AGENT_DEVICE_PREFIX,
16
8
  LOCAL_IDLE_EXIT_MS,
@@ -28,6 +20,8 @@ import {
28
20
  decodeOwnerProfile,
29
21
  defaultAgentName,
30
22
  defaultHumanColor,
23
+ ensureHelper,
24
+ helperPaths,
31
25
  isDefaultAgentName,
32
26
  isHumanColorId,
33
27
  isLocalRoomId,
@@ -35,25 +29,29 @@ import {
35
29
  newLocalAgentUserId,
36
30
  newLocalEventId,
37
31
  newLocalRoomId,
38
- normalizeInitials
39
- } from "./chunk-2U4E7AM7.mjs";
32
+ normalizeInitials,
33
+ olderHelperVersion,
34
+ readHelperFile
35
+ } from "./chunk-2DHIAFEV.mjs";
36
+ import {
37
+ KHALA_AGENT_VERSION
38
+ } from "./chunk-5LIE5GUU.mjs";
40
39
  import {
41
40
  bundle
42
- } from "./chunk-PFDUXY3N.mjs";
41
+ } from "./chunk-APMWDF6B.mjs";
43
42
  import "./chunk-5GLTKWJ5.mjs";
44
43
  import {
45
44
  CHANNEL_EVENT_TYPE,
46
45
  decodeChannelEvent,
47
46
  encodeChannelEvent,
48
47
  memberRenameContent
49
- } from "./chunk-P5CP32X2.mjs";
50
- import "./chunk-DPW43YNC.mjs";
48
+ } from "./chunk-54XFVSEC.mjs";
51
49
  import {
52
50
  StateError,
53
51
  ensureStateDir,
54
52
  readJson,
55
53
  writeJsonAtomic
56
- } from "./chunk-OW3DSTEZ.mjs";
54
+ } from "./chunk-CBPLCCRZ.mjs";
57
55
  import {
58
56
  DEFAULT_LISTENING_MODE,
59
57
  LISTENING_MODE_COMMAND_TYPE,
@@ -61,17 +59,18 @@ import {
61
59
  decodeListeningMode,
62
60
  decodeListeningModeCommand,
63
61
  memberListeningMode
64
- } from "./chunk-AUJEUKVM.mjs";
62
+ } from "./chunk-IQJQ4RF5.mjs";
65
63
  import {
66
- HARNESSES,
64
+ LEGACY_HARNESSES,
67
65
  agentConfirmPagePath,
68
66
  decodeWith,
67
+ isHarnessId,
69
68
  object,
70
69
  utf8Length,
71
70
  validAgentRejoinSecret,
72
71
  validAgentSessionId
73
- } from "./chunk-SN3STAO2.mjs";
74
- import "./chunk-55KBLEX5.mjs";
72
+ } from "./chunk-NKX3SLS7.mjs";
73
+ import "./chunk-7HBRFY3Z.mjs";
75
74
 
76
75
  // src/local/cli.ts
77
76
  import { setTimeout as sleepDefault } from "node:timers/promises";
@@ -123,6 +122,7 @@ async function openLocalStore(input) {
123
122
  byTxn: /* @__PURE__ */ new Map(),
124
123
  lastMember: /* @__PURE__ */ new Map(),
125
124
  previousMembers: /* @__PURE__ */ new Map(),
125
+ harnesses: {},
126
126
  secrets: emptySecrets(),
127
127
  waiters: /* @__PURE__ */ new Set()
128
128
  };
@@ -166,6 +166,10 @@ async function openLocalStore(input) {
166
166
  if (error2.code === "ENOENT") continue;
167
167
  throw error2;
168
168
  }
169
+ const harnesses = await readJson(path.join(channel.dir, "harness.json"));
170
+ if (typeof harnesses === "object" && harnesses !== null && !Array.isArray(harnesses)) {
171
+ channel.harnesses = Object.fromEntries(Object.entries(harnesses).filter(([, id]) => isHarnessId(id)));
172
+ }
169
173
  const completeBytes = buffer.lastIndexOf(10) + 1;
170
174
  if (completeBytes < buffer.length) channel.validBytes = completeBytes;
171
175
  for (const line of buffer.subarray(0, completeBytes).toString("utf8").split("\n")) {
@@ -176,7 +180,13 @@ async function openLocalStore(input) {
176
180
  continue;
177
181
  }
178
182
  const decoded = decodeLocalEvent(parsed);
179
- if (decoded.ok && decoded.value.roomId === roomId && decoded.value.seq > lastSeq(channel)) indexEvent(channel, decoded.value);
183
+ if (!decoded.ok || decoded.value.roomId !== roomId || decoded.value.seq <= lastSeq(channel)) continue;
184
+ const event = decoded.value;
185
+ if (event.type === "m.room.member" && event.content.harness === void 0) {
186
+ const harness = channel.harnesses[event.content.user];
187
+ if (harness) event.content.harness = harness;
188
+ }
189
+ indexEvent(channel, event);
180
190
  }
181
191
  if (channel.events[0]?.type !== "m.room.create") continue;
182
192
  const names = await readJson(path.join(channel.dir, "names.json"));
@@ -219,6 +229,27 @@ async function openLocalStore(input) {
219
229
  content: eventInput.content
220
230
  };
221
231
  const stored = structuredClone(event);
232
+ const disk = { ...stored, content: { ...stored.content } };
233
+ if (disk.type === "m.room.member") {
234
+ const user = disk.content.user;
235
+ const harness = disk.content.harness;
236
+ if (harness !== void 0 && !LEGACY_HARNESSES.includes(harness)) {
237
+ if (!isHarnessId(harness)) throw new LocalStoreError("storage_failed");
238
+ if (channel.harnesses[user] !== harness) {
239
+ const next = { ...channel.harnesses, [user]: harness };
240
+ await writeJsonAtomic(path.join(channel.dir, "harness.json"), next);
241
+ channel.harnesses = next;
242
+ }
243
+ delete disk.content.harness;
244
+ } else if (harness !== void 0 && Object.hasOwn(channel.harnesses, user)) {
245
+ const next = { ...channel.harnesses };
246
+ delete next[user];
247
+ await writeJsonAtomic(path.join(channel.dir, "harness.json"), next);
248
+ channel.harnesses = next;
249
+ } else if (harness === void 0 && channel.harnesses[user]) {
250
+ stored.content.harness = channel.harnesses[user];
251
+ }
252
+ }
222
253
  const logPath = path.join(channel.dir, "log.jsonl");
223
254
  if (channel.validBytes !== void 0) {
224
255
  await fs.truncate(logPath, channel.validBytes);
@@ -227,7 +258,7 @@ async function openLocalStore(input) {
227
258
  channel.handle ??= await fs.open(logPath, "a", 384);
228
259
  const start = (await channel.handle.stat()).size;
229
260
  try {
230
- await channel.handle.writeFile(JSON.stringify(stored) + "\n", "utf8");
261
+ await channel.handle.writeFile(JSON.stringify(disk) + "\n", "utf8");
231
262
  } catch (error2) {
232
263
  channel.validBytes = start;
233
264
  throw error2;
@@ -861,7 +892,7 @@ function agentJoinRoutes() {
861
892
  if (Object.hasOwn(body, "sessionId") && !validAgentSessionId(body.sessionId)) return fail2(400, "invalid_link");
862
893
  if (Object.hasOwn(body, "rejoinSecret") && !validAgentRejoinSecret(body.rejoinSecret)) return fail2(400, "invalid_link");
863
894
  const harness = body.harness;
864
- if (!HARNESSES.includes(harness)) return fail2(400, "invalid_harness");
895
+ if (!isHarnessId(harness)) return fail2(400, "invalid_harness");
865
896
  const url = new URL(body.link);
866
897
  if (url.origin !== ctx.origin && url.origin !== ctx.origin.replace("://127.0.0.1:", "://localhost:")) return fail2(404, "link_unavailable");
867
898
  const token = url.pathname.slice("/join/".length);
@@ -939,6 +970,14 @@ function agentJoinRoutes() {
939
970
  ];
940
971
  }
941
972
 
973
+ // src/local/wire.ts
974
+ function legacyHarnessView(content) {
975
+ if (!("harness" in content) || content.harness === void 0 || LEGACY_HARNESSES.includes(content.harness)) return content;
976
+ const legacy = { ...content };
977
+ delete legacy.harness;
978
+ return legacy;
979
+ }
980
+
942
981
  // src/local/routes/rooms.ts
943
982
  var fail3 = (status, error2) => ({ status, json: { error: error2 } });
944
983
  function serial2() {
@@ -1077,10 +1116,14 @@ function roomRoutes() {
1077
1116
  if ("status" in current) return current;
1078
1117
  events = ctx.store.eventsAfter(caller.roomId, after, 200);
1079
1118
  }
1080
- const delivered = req.query.get("prev") === "1" ? events : events.map((event) => {
1081
- const legacy = { ...event };
1082
- delete legacy.previousContent;
1083
- return legacy;
1119
+ const delivered = events.map((event) => {
1120
+ const view = { ...event };
1121
+ if (req.query.get("prev") !== "1") delete view.previousContent;
1122
+ if (req.query.get("wire") !== "2") {
1123
+ view.content = legacyHarnessView(view.content);
1124
+ if (view.previousContent) view.previousContent = legacyHarnessView(view.previousContent);
1125
+ }
1126
+ return view;
1084
1127
  });
1085
1128
  return { status: 200, json: { events: delivered, next: events.at(-1)?.seq ?? after } };
1086
1129
  }),
@@ -1088,7 +1131,11 @@ function roomRoutes() {
1088
1131
  const before = req.query.get("before");
1089
1132
  const limit = req.query.get("limit") ?? "50";
1090
1133
  if (before !== null && !/^\$[A-Za-z0-9_-]{1,128}$/u.test(before) || !/^\d{1,3}$/u.test(limit) || Number(limit) < 1 || Number(limit) > 100) return fail3(400, "invalid_request");
1091
- return { status: 200, json: ctx.store.history(caller.roomId, before ?? void 0, Number(limit)) };
1134
+ const page = ctx.store.history(caller.roomId, before ?? void 0, Number(limit));
1135
+ return { status: 200, json: req.query.get("wire") === "2" ? page : {
1136
+ ...page,
1137
+ events: page.events.map((event) => ({ ...event, content: legacyHarnessView(event.content) }))
1138
+ } };
1092
1139
  }),
1093
1140
  route("POST", /^\/api\/local\/rooms\/([^/]+)\/send$/u, "joined", async (req, params, ctx) => {
1094
1141
  const decoded = decodeWith(() => {
@@ -1114,9 +1161,9 @@ function roomRoutes() {
1114
1161
  return { status: 200, json: { eventId: event.eventId } };
1115
1162
  });
1116
1163
  }),
1117
- route("GET", /^\/api\/local\/rooms\/([^/]+)\/members$/u, "joined", async (_req, _params, ctx, caller) => ({
1164
+ route("GET", /^\/api\/local\/rooms\/([^/]+)\/members$/u, "joined", async (req, _params, ctx, caller) => ({
1118
1165
  status: 200,
1119
- json: { members: ctx.store.members(caller.roomId) }
1166
+ json: { members: ctx.store.members(caller.roomId).map((member) => req.query.get("wire") === "2" ? member : legacyHarnessView(member)) }
1120
1167
  })),
1121
1168
  route("PUT", /^\/api\/local\/rooms\/([^/]+)\/members\/([^/]+)$/u, "joined", async (req, params, ctx, caller) => {
1122
1169
  let target;
@@ -1211,7 +1258,7 @@ function ownerRoutes(options = {}) {
1211
1258
  const wait = req.query.get("wait") ?? "0";
1212
1259
  if (since !== null && !/^\d{1,15}$/u.test(since) || !/^\d{1,2}$/u.test(wait) || Number(wait) > LOCAL_LONG_POLL_MAX_S) return fail4(400, "invalid_request");
1213
1260
  if (since !== null && Number(since) === store.revision() && Number(wait) > 0) await store.waitForRevision(Number(since), Number(wait) * 1e3, req.signal);
1214
- return { status: 200, json: { revision: store.revision(), channels: store.listChannels() } };
1261
+ return { status: 200, json: { revision: store.revision(), channels: store.listChannels().map((summary) => ({ ...summary, members: summary.members.map((member) => req.query.get("wire") === "2" ? member : legacyHarnessView(member)) })) } };
1215
1262
  }),
1216
1263
  route("GET", /^\/api\/local\/channels\/by-operation\/([^/]+)$/u, async (_req, params, { store }) => {
1217
1264
  const id = decodeParam(params[0]);
@@ -1219,10 +1266,10 @@ function ownerRoutes(options = {}) {
1219
1266
  const roomId = store.findByOperation(id);
1220
1267
  return roomId === void 0 ? fail4(404, "not_found") : { status: 200, json: { roomId } };
1221
1268
  }),
1222
- route("GET", /^\/api\/local\/channels\/([^/]+)$/u, async (_req, params, { store }) => {
1269
+ route("GET", /^\/api\/local\/channels\/([^/]+)$/u, async (req, params, { store }) => {
1223
1270
  const roomId = channelParam(params[0], store);
1224
1271
  const summary = roomId === null ? void 0 : store.channelSummary(roomId);
1225
- return summary === void 0 ? fail4(404, "not_found") : { status: 200, json: summary };
1272
+ return summary === void 0 ? fail4(404, "not_found") : { status: 200, json: { ...summary, members: summary.members.map((member) => req.query.get("wire") === "2" ? member : legacyHarnessView(member)) } };
1226
1273
  }),
1227
1274
  route("POST", /^\/api\/local\/channels$/u, async (req, _params, ctx) => {
1228
1275
  const body = req.body;
@@ -1242,7 +1289,7 @@ function ownerRoutes(options = {}) {
1242
1289
  const open2 = ctx.mintOpenToken(roomId);
1243
1290
  return { status: 201, json: { roomId, name: store.channelName(roomId), selfLink: `${ctx.origin}/join/${self.token}`, shareLink: `${ctx.origin}/join/${share.token}`, openUrl: `${ctx.origin}/open/${open2.token}`, expiresAt: self.expiresAt } };
1244
1291
  }, { serial: true }),
1245
- route("DELETE", /^\/api\/local\/channels\/([^/]+)$/u, async (_req, params, ctx) => {
1292
+ route("DELETE", /^\/api\/local\/channels\/([^/]+)$/u, async (req, params, ctx) => {
1246
1293
  const roomId = channelParam(params[0], ctx.store);
1247
1294
  if (roomId === null) return fail4(404, "not_found");
1248
1295
  await ctx.store.deleteChannel(roomId);
@@ -1639,7 +1686,7 @@ async function runLocalCommand(argv, deps = {}) {
1639
1686
  return null;
1640
1687
  }
1641
1688
  const body = await response.json();
1642
- return body?.ok === true && body.pid === file.pid && typeof body.version === "string" ? body : null;
1689
+ return body?.ok === true && body.pid === file.pid ? body : null;
1643
1690
  } catch {
1644
1691
  return null;
1645
1692
  }
@@ -1691,7 +1738,7 @@ async function runLocalCommand(argv, deps = {}) {
1691
1738
  return value;
1692
1739
  }
1693
1740
  async function channels() {
1694
- const page = await call("GET", "/api/local/channels");
1741
+ const page = await call("GET", "/api/local/channels?wire=2");
1695
1742
  if (!Array.isArray(page?.channels)) throw new CliError("internal_error");
1696
1743
  return page.channels;
1697
1744
  }
@@ -1735,7 +1782,7 @@ async function runLocalCommand(argv, deps = {}) {
1735
1782
  break;
1736
1783
  }
1737
1784
  case "status":
1738
- result = { running: true, origin: file.origin, pid: file.pid, version: healthy.version, channels: (await channels()).length };
1785
+ result = { running: true, origin: file.origin, pid: file.pid, version: healthy.version, ...olderHelperVersion(healthy.version) ? { detail: "older helper in use" } : {}, channels: (await channels()).length };
1739
1786
  break;
1740
1787
  case "stop": {
1741
1788
  if (await call("POST", "/api/local/shutdown") !== null) throw new CliError("internal_error");
@@ -5,7 +5,7 @@ import {
5
5
  object,
6
6
  readMatrixUserId,
7
7
  version
8
- } from "./chunk-SN3STAO2.mjs";
8
+ } from "./chunk-NKX3SLS7.mjs";
9
9
 
10
10
  // ../contracts/src/delivery/decode.ts
11
11
  var MAX_IDENTIFIER_BYTES = 512;
@@ -114,6 +114,39 @@ function utcTimestamp(input, path) {
114
114
  return input;
115
115
  }
116
116
 
117
+ // ../contracts/src/m1/harness.ts
118
+ var HARNESS_ID = /^[a-z][a-z0-9-]{1,23}$/;
119
+ function isHarnessId(input) {
120
+ return typeof input === "string" && HARNESS_ID.exec(input)?.[0] === input;
121
+ }
122
+ var LEGACY_HARNESSES = ["claude", "codex", "cursor"];
123
+ var HARNESS_REGISTRY = [
124
+ { id: "claude", displayName: "Claude Code", modelName: "Claude", logoKey: "claude", steer: true, sync: true, idleWake: "default", registered: true },
125
+ { id: "codex", displayName: "Codex", modelName: "Codex", logoKey: "codex", steer: true, sync: true, idleWake: "default", registered: true },
126
+ { id: "cursor", displayName: "Cursor", modelName: "Cursor", logoKey: "cursor", steer: true, sync: true, idleWake: "none", registered: true },
127
+ { id: "opencode", displayName: "OpenCode", modelName: "OpenCode", logoKey: "opencode", steer: true, sync: true, idleWake: "default", registered: true },
128
+ { id: "copilot", displayName: "Copilot CLI", modelName: "Copilot", logoKey: "copilot", steer: true, sync: true, idleWake: "opt-in", registered: true },
129
+ { id: "vscode", displayName: "Copilot (VS Code)", modelName: "VSCode", logoKey: "copilot", steer: true, sync: true, idleWake: "opt-in", registered: true },
130
+ { id: "gemini", displayName: "Gemini CLI", modelName: "Gemini", logoKey: "gemini", steer: true, sync: true, idleWake: "opt-in", registered: true },
131
+ // U29 and U33 establish these capabilities after their spikes.
132
+ { id: "antigravity", displayName: "Antigravity CLI", modelName: "Antigravity", logoKey: null, steer: false, sync: false, idleWake: "none", registered: true },
133
+ { id: "qwen", displayName: "Qwen Code", modelName: "Qwen", logoKey: "qwen", steer: true, sync: true, idleWake: "default", registered: true },
134
+ { id: "muse", displayName: "Muse Code", modelName: "Muse", logoKey: null, steer: false, sync: false, idleWake: "none", registered: true },
135
+ { id: "generic", displayName: "MCP agent", modelName: "Agent", logoKey: null, steer: false, sync: false, idleWake: "none", registered: true }
136
+ ];
137
+ function harnessInfo(id) {
138
+ return HARNESS_REGISTRY.find((row) => row.id === id) ?? {
139
+ id,
140
+ displayName: id.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "),
141
+ modelName: "Agent",
142
+ logoKey: null,
143
+ steer: false,
144
+ sync: false,
145
+ idleWake: "none",
146
+ registered: false
147
+ };
148
+ }
149
+
117
150
  // ../contracts/src/messaging/agent-names.ts
118
151
  var MAX_AGENT_NAME_BYTES = 80;
119
152
  var unsafe = /[\u0000-\u001f\u007f-\u009f\u061c\u200b-\u200f\u2028-\u202e\u2060-\u2069\ufeff]/u;
@@ -129,11 +162,12 @@ function validateAgentName(input) {
129
162
  }
130
163
 
131
164
  // ../contracts/src/m1/agent-join.ts
132
- var HARNESSES = ["claude", "codex", "cursor"];
133
165
  var M1_LABEL_MAX_BYTES = 512;
134
166
  var agentConfirmPagePath = (id) => `/agent/confirm?joinId=${encodeURIComponent(id)}`;
135
167
  function readHarness(input, path) {
136
- return literal(input, path, HARNESSES);
168
+ if (typeof input !== "string") fail(path, "wrong_type");
169
+ if (!isHarnessId(input)) fail(path, "invalid_value");
170
+ return input;
137
171
  }
138
172
  function readHttpUrl(input, path) {
139
173
  if (typeof input !== "string") fail(path, "wrong_type");
@@ -178,7 +212,10 @@ export {
178
212
  utcTimestamp,
179
213
  reserved,
180
214
  validateAgentName,
181
- HARNESSES,
215
+ isHarnessId,
216
+ LEGACY_HARNESSES,
217
+ HARNESS_REGISTRY,
218
+ harnessInfo,
182
219
  M1_LABEL_MAX_BYTES,
183
220
  agentConfirmPagePath,
184
221
  readHarness,