@ours.network/cli 1.0.1 → 2.0.1

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.
@@ -11,11 +11,11 @@ import {
11
11
  appendNotifyLog,
12
12
  bindSession,
13
13
  bootWrapper,
14
- buildMessagesPayload,
15
14
  capabilityReconcileSweep,
16
15
  clearNotifyHook,
17
16
  closeTemporaryIdentity,
18
17
  clusterSweep,
18
+ consumeOutboundHistoryFailure,
19
19
  contactRestoreSweep,
20
20
  decodeWireBin,
21
21
  delegateRole,
@@ -27,13 +27,18 @@ import {
27
27
  establishRoot,
28
28
  exportAdBlob,
29
29
  findIdentityFile,
30
+ getFileHistoryItem,
31
+ getMessageHistoryItem,
30
32
  hashLeaseToken,
31
33
  identities,
32
34
  isSelectableWireId,
33
35
  leaseByToken,
34
36
  leases,
37
+ listFileHistory,
38
+ listIncomingFiles,
39
+ listIncomingMessages,
40
+ listMessageHistory,
35
41
  log,
36
- mimeFromExt,
37
42
  mutatingTx,
38
43
  outboundRemovalInFlight,
39
44
  persistBindings,
@@ -41,16 +46,13 @@ import {
41
46
  provisionIdentity,
42
47
  publishToBook,
43
48
  readBook,
44
- readE2eWireIds,
45
49
  readonlyTx,
46
50
  refreshUnread,
47
51
  registrar,
48
52
  renderContactRoots,
49
53
  renderContacts,
50
54
  renderDegraded,
51
- renderFileMetadata,
52
55
  renderImportRenames,
53
- renderInbox,
54
56
  renderPending,
55
57
  requireAuth,
56
58
  reservedNames,
@@ -62,16 +64,21 @@ import {
62
64
  sessionHeaders,
63
65
  setNotifyHook,
64
66
  startupProgress,
67
+ structuredVoiceOutcome,
68
+ sttStatus,
65
69
  sweepStaleTempIdentities,
70
+ takeUnreadFiles,
71
+ takeUnreadMessages,
66
72
  tombstones,
73
+ transcribeVoice,
67
74
  unpublishFromBook,
68
75
  unreadSummary,
69
76
  validateName,
77
+ voiceDeliveryLine,
70
78
  withScope,
71
79
  withScopeAsync,
72
- writeIncomingFiles,
73
80
  writeTempMetaFile
74
- } from "./chunk-MHVYJY3H.js";
81
+ } from "./chunk-LJ35FDQH.js";
75
82
  import {
76
83
  buildIdentityFile,
77
84
  writeIdentityFile
@@ -96,13 +103,6 @@ function startGcTimer() {
96
103
  void (async () => {
97
104
  try {
98
105
  for (const id of identities.values()) {
99
- try {
100
- await withScopeAsync(async (lt) => {
101
- await mutatingTx(id, "::actor::gc", {}, lt);
102
- });
103
- } catch (e) {
104
- log(`gc(${id.name}) failed:`, String(e));
105
- }
106
106
  await contactRestoreSweep(id);
107
107
  await capabilityReconcileSweep(id);
108
108
  await e2eRecoverySweep(id);
@@ -113,7 +113,7 @@ function startGcTimer() {
113
113
  })();
114
114
  }, GC_INTERVAL_MS);
115
115
  gcTimer.unref?.();
116
- log(`message GC timer armed (every ${GC_INTERVAL_MS}ms)`);
116
+ log(`protocol maintenance timer armed (every ${GC_INTERVAL_MS}ms)`);
117
117
  }
118
118
  function stopGcTimer() {
119
119
  if (gcTimer) {
@@ -989,7 +989,37 @@ async function respondToIntroduction(ctx, a) {
989
989
 
990
990
  // ../../src/api/messaging.ts
991
991
  import { readFile } from "node:fs/promises";
992
- import { basename as basename2 } from "node:path";
992
+ import { basename as basename3 } from "node:path";
993
+
994
+ // ../../src/files.ts
995
+ import { basename as basename2, extname } from "node:path";
996
+ var FILE_MIME = {
997
+ ".png": "image/png",
998
+ ".jpg": "image/jpeg",
999
+ ".jpeg": "image/jpeg",
1000
+ ".gif": "image/gif",
1001
+ ".webp": "image/webp",
1002
+ ".svg": "image/svg+xml",
1003
+ ".bmp": "image/bmp",
1004
+ ".ico": "image/x-icon",
1005
+ ".pdf": "application/pdf",
1006
+ ".txt": "text/plain",
1007
+ ".md": "text/markdown",
1008
+ ".json": "application/json",
1009
+ ".csv": "text/csv",
1010
+ ".html": "text/html",
1011
+ ".xml": "application/xml",
1012
+ ".zip": "application/zip",
1013
+ ".gz": "application/gzip",
1014
+ ".tar": "application/x-tar",
1015
+ ".mp3": "audio/mpeg",
1016
+ ".wav": "audio/wav",
1017
+ ".mp4": "video/mp4",
1018
+ ".mov": "video/quicktime"
1019
+ };
1020
+ function mimeFromExt(p) {
1021
+ return FILE_MIME[extname(p).toLowerCase()] ?? "application/octet-stream";
1022
+ }
993
1023
 
994
1024
  // ../../src/messaging/send.ts
995
1025
  function findSibling(id, contact) {
@@ -1001,15 +1031,19 @@ function findSibling(id, contact) {
1001
1031
  }
1002
1032
  async function sendViaSibling(id, target, text) {
1003
1033
  const targetAd = exportAdBlob(target);
1004
- await withScopeAsync(async (lt) => {
1005
- await mutatingTx(id, "::actor::connect_sibling", {
1034
+ const wireId = await withScopeAsync(async (lt) => {
1035
+ const result = await mutatingTx(id, "::actor::connect_sibling", {
1006
1036
  name: target.name,
1007
1037
  target_ad: id.pw.packet.NewBinaryFromBuffer(targetAd).Attach(lt),
1008
1038
  text
1009
1039
  }, lt);
1040
+ return result.Reduce("wire_id").Visualize();
1010
1041
  });
1011
1042
  scheduleCapabilityReconcile(id);
1012
- return `"${target.name}" was not a contact yet \u2014 connected as an intra-root sibling (delegation-cert auto-accept) and delivered the message.`;
1043
+ return {
1044
+ text: `"${target.name}" was not a contact yet \u2014 connected as an intra-root sibling (delegation-cert auto-accept) and delivered the message.`,
1045
+ wireId
1046
+ };
1013
1047
  }
1014
1048
  async function sendViaLocalBook(id, contact, text) {
1015
1049
  if (!registrar) {
@@ -1028,22 +1062,26 @@ async function sendViaLocalBook(id, contact, text) {
1028
1062
  const targetAd = Buffer.from(entry.address_document, "base64url");
1029
1063
  const entrySig = Buffer.from(entry.registrar_sig, "base64url");
1030
1064
  const joinerAd = exportAdBlob(id);
1031
- await withScopeAsync(async (lt) => {
1065
+ const wireId = await withScopeAsync(async (lt) => {
1032
1066
  const minted = await mutatingTx(registrar, "::actor::mint_introduction", {
1033
1067
  joiner_ad: registrar.pw.packet.NewBinaryFromBuffer(joinerAd).Attach(lt),
1034
1068
  target_ad: registrar.pw.packet.NewBinaryFromBuffer(targetAd).Attach(lt)
1035
1069
  }, lt);
1036
1070
  const introBlob = Buffer.from(minted.Reduce("intro").GetBinary());
1037
- await mutatingTx(id, "::actor::connect_local", {
1071
+ const result = await mutatingTx(id, "::actor::connect_local", {
1038
1072
  name: entry.name,
1039
1073
  target_ad: id.pw.packet.NewBinaryFromBuffer(targetAd).Attach(lt),
1040
1074
  intro: id.pw.packet.NewBinaryFromBuffer(introBlob).Attach(lt),
1041
1075
  entry_sig: id.pw.packet.NewBinaryFromBuffer(entrySig).Attach(lt),
1042
1076
  text
1043
1077
  }, lt);
1078
+ return result.Reduce("wire_id").Visualize();
1044
1079
  });
1045
1080
  scheduleCapabilityReconcile(id);
1046
- return `"${entry.name}" was not a contact yet \u2014 connected via the local contact book and sent the message with the introduction. If "${entry.name}" requires approval for local introductions, delivery completes once they approve.`;
1081
+ return {
1082
+ text: `"${entry.name}" was not a contact yet \u2014 connected via the local contact book and sent the message with the introduction. If "${entry.name}" requires approval for local introductions, delivery completes once they approve.`,
1083
+ wireId
1084
+ };
1047
1085
  }
1048
1086
  var parseSendVerdict = (sent) => {
1049
1087
  const has = (f) => !sent.Reduce(f).IsNil();
@@ -1090,6 +1128,14 @@ async function sendMessage(ctx, a) {
1090
1128
  default:
1091
1129
  break;
1092
1130
  }
1131
+ if (v.kind === "sent" || v.kind === "e2e") {
1132
+ return {
1133
+ ...v,
1134
+ sent: true,
1135
+ wire_id: v.wireId,
1136
+ history_stored: !consumeOutboundHistoryFailure(id, v.wireId)
1137
+ };
1138
+ }
1093
1139
  return v;
1094
1140
  } catch (e) {
1095
1141
  if (!/Unknown contact/.test(String(e))) {
@@ -1098,7 +1144,14 @@ async function sendMessage(ctx, a) {
1098
1144
  try {
1099
1145
  const sibling = findSibling(id, contact);
1100
1146
  const sent = sibling ? await sendViaSibling(id, sibling, text) : await sendViaLocalBook(id, contact, text);
1101
- return { kind: "introduced", text: sent };
1147
+ return {
1148
+ kind: "introduced",
1149
+ text: sent.text,
1150
+ wireId: sent.wireId,
1151
+ wire_id: sent.wireId,
1152
+ sent: true,
1153
+ history_stored: !consumeOutboundHistoryFailure(id, sent.wireId)
1154
+ };
1102
1155
  } catch (e2) {
1103
1156
  throw errTool("send_message", String(e2), "FALLBACK_FAILED");
1104
1157
  }
@@ -1116,7 +1169,7 @@ async function sendFile(ctx, a) {
1116
1169
  try {
1117
1170
  if (path) {
1118
1171
  buf = await readFile(path);
1119
- fname = filename ?? basename2(path);
1172
+ fname = filename ?? basename3(path);
1120
1173
  } else if (upload_id) {
1121
1174
  const got = consumeStagedUpload(id, upload_id);
1122
1175
  if (!got) throw errUploadNotFound(upload_id);
@@ -1195,53 +1248,68 @@ async function sendFile(ctx, a) {
1195
1248
  default:
1196
1249
  break;
1197
1250
  }
1251
+ if (v.kind === "sent" || v.kind === "e2e") {
1252
+ return {
1253
+ ...v,
1254
+ filename: fname,
1255
+ bytes: buf.length,
1256
+ mime: mt,
1257
+ sent: true,
1258
+ wire_id: v.wireId,
1259
+ history_stored: !consumeOutboundHistoryFailure(id, v.wireId)
1260
+ };
1261
+ }
1198
1262
  return { ...v, filename: fname, bytes: buf.length, mime: mt };
1199
1263
  } catch (e) {
1200
1264
  throw errTool("send_file", String(e));
1201
1265
  }
1202
1266
  }
1203
- async function listIncomingMessages(ctx) {
1267
+ async function listIncomingMessages2(ctx) {
1204
1268
  const id = requireBound(ctx);
1205
1269
  try {
1206
- return withScope((lt) => renderInbox(readonlyTx(id, "::actor::list_incoming_messages", lt)));
1270
+ return listIncomingMessages(id);
1207
1271
  } catch (e) {
1208
1272
  throw errTool("list_incoming_messages", String(e));
1209
1273
  }
1210
1274
  }
1211
- async function getMessages(ctx) {
1275
+ async function getMessages(ctx, input = {}) {
1212
1276
  const id = requireBound(ctx);
1213
1277
  try {
1214
- const fresh = await withScopeAsync(async (lt) => {
1215
- const data = await mutatingTx(id, "::actor::get_messages", {}, lt);
1216
- return renderInbox(data.Reduce("messages"));
1217
- });
1278
+ const fresh = takeUnreadMessages(id, input);
1218
1279
  refreshUnread(id);
1219
- const e2eWireIds = readE2eWireIds(id);
1220
- return buildMessagesPayload(fresh, e2eWireIds);
1280
+ const bySender = /* @__PURE__ */ new Map();
1281
+ for (const message of fresh.messages) {
1282
+ let wireIds = bySender.get(message.from.id);
1283
+ if (!wireIds) {
1284
+ wireIds = [];
1285
+ bySender.set(message.from.id, wireIds);
1286
+ }
1287
+ wireIds.push(message.wire_id);
1288
+ }
1289
+ for (const [senderId, wireIds] of bySender) {
1290
+ try {
1291
+ await withScopeAsync(async (lt) => {
1292
+ await mutatingTx(id, "::actor::send_read_receipts", {
1293
+ sender_id: senderId,
1294
+ wire_ids: wireIds
1295
+ }, lt);
1296
+ });
1297
+ } catch (error) {
1298
+ log(`[${id.name}] read-receipt attempt failed sender_id=${senderId} count=${wireIds.length}:`, String(error));
1299
+ }
1300
+ }
1301
+ return fresh;
1221
1302
  } catch (e) {
1222
1303
  throw errTool("get_messages", String(e));
1223
1304
  }
1224
1305
  }
1225
- async function deferMessages(ctx, a) {
1226
- const id = requireBound(ctx);
1227
- const { msg_ids } = a;
1228
- try {
1229
- const n = await withScopeAsync(async (lt) => {
1230
- const data = await mutatingTx(id, "::actor::defer_messages", { msg_ids }, lt);
1231
- return data.Reduce("deferred").Visualize();
1232
- });
1233
- refreshUnread(id);
1234
- return { deferred: n };
1235
- } catch (e) {
1236
- throw errTool("defer_messages", String(e));
1237
- }
1238
- }
1239
1306
 
1240
1307
  // ../../src/api/files.ts
1241
- async function listIncomingFiles(ctx) {
1308
+ import { readFile as readFile2 } from "node:fs/promises";
1309
+ async function listIncomingFiles2(ctx) {
1242
1310
  const id = requireBound(ctx);
1243
1311
  try {
1244
- return withScope((lt) => renderFileMetadata(readonlyTx(id, "::actor::list_incoming_files", lt)));
1312
+ return listIncomingFiles(id);
1245
1313
  } catch (e) {
1246
1314
  throw errTool("list_incoming_files", String(e));
1247
1315
  }
@@ -1257,18 +1325,66 @@ async function getFiles(ctx, a = {}) {
1257
1325
  if (new Set(wire_ids).size !== wire_ids.length) throw errDuplicateId();
1258
1326
  }
1259
1327
  try {
1260
- const out = await withScopeAsync(async (lt) => {
1261
- const data = await mutatingTx(id, "::actor::get_files", wire_ids === void 0 ? {} : { wire_ids }, lt);
1262
- return await writeIncomingFiles(id, data.Reduce("files"));
1263
- });
1328
+ const selected = takeUnreadFiles(id, { wire_ids, limit: a.limit });
1329
+ const files = [];
1330
+ const lines = [];
1331
+ for (const file of selected.files) {
1332
+ const base = {
1333
+ file_id: file.file_id,
1334
+ wire_id: file.wire_id,
1335
+ from: file.from,
1336
+ filename: file.filename,
1337
+ path: file.blob_path,
1338
+ mime: file.mime,
1339
+ size: file.byte_length,
1340
+ sha256: file.sha256,
1341
+ status: "processed",
1342
+ date: file.date,
1343
+ kind: file.kind,
1344
+ sender: file.from.name
1345
+ };
1346
+ if (file.kind === "voice_message") {
1347
+ const st = sttStatus(CONFIG.stt);
1348
+ let outcome;
1349
+ if (!st.ready) outcome = { kind: "unconfigured", reason: st.reason };
1350
+ else {
1351
+ try {
1352
+ const result = await transcribeVoice(
1353
+ await readFile2(file.blob_path),
1354
+ file.filename,
1355
+ file.mime,
1356
+ CONFIG.stt
1357
+ );
1358
+ outcome = result.ok ? { kind: "transcript", text: result.text } : { kind: "failed", error: result.error };
1359
+ } catch (error) {
1360
+ outcome = { kind: "failed", error: error instanceof Error ? error.message : String(error) };
1361
+ }
1362
+ }
1363
+ base.transcription = structuredVoiceOutcome(st, outcome, {
1364
+ audioPath: file.blob_path,
1365
+ wireId: file.wire_id
1366
+ });
1367
+ lines.push(voiceDeliveryLine({
1368
+ sender: file.from.name,
1369
+ wire: file.wire_id,
1370
+ savedPath: file.blob_path,
1371
+ sizeBytes: file.byte_length
1372
+ }, outcome));
1373
+ } else {
1374
+ lines.push(
1375
+ ` \u2022 ${file.filename} (${file.mime}, ${file.byte_length} B, sha256 ${file.sha256}) from ${file.from.name} \u2192 ${file.blob_path} {${file.wire_id}}`
1376
+ );
1377
+ }
1378
+ files.push(base);
1379
+ }
1264
1380
  refreshUnread(id);
1265
1381
  return {
1266
- files: out.files,
1267
- // The finished summary travels; ours-mcp cannot re-derive it. See GetFilesResult.
1268
- text: out.text,
1382
+ files,
1383
+ text: lines.length === 0 ? "No new files." : `${lines.length} new file(s) available from immutable identity blob storage (bytes stay on disk, never in this result):
1384
+ ${lines.join("\n")}`,
1269
1385
  mode: wire_ids === void 0 ? "all_unread" : "selected",
1270
- // null NOT [] — for the bulk form. See GetFilesResult.
1271
- requested: wire_ids ?? null
1386
+ requested: wire_ids ?? null,
1387
+ remaining: selected.remaining
1272
1388
  };
1273
1389
  } catch (e) {
1274
1390
  const message = String(e);
@@ -1282,20 +1398,6 @@ function saveFileFallbackNotice(ctx, a) {
1282
1398
  const id = requireBound(ctx);
1283
1399
  return { existsOnDisk: findIdentityFile(id, a.wire_id) !== null };
1284
1400
  }
1285
- async function deferFiles(ctx, a) {
1286
- const id = requireBound(ctx);
1287
- const { file_ids } = a;
1288
- try {
1289
- const n = await withScopeAsync(async (lt) => {
1290
- const data = await mutatingTx(id, "::actor::defer_files", { file_ids }, lt);
1291
- return data.Reduce("deferred").Visualize();
1292
- });
1293
- refreshUnread(id);
1294
- return { deferred: n };
1295
- } catch (e) {
1296
- throw errTool("defer_files", String(e));
1297
- }
1298
- }
1299
1401
 
1300
1402
  // ../../src/api/profile.ts
1301
1403
  async function setBio2(ctx, a) {
@@ -1363,82 +1465,37 @@ async function readvertiseOnUpgrade(ctx) {
1363
1465
  }
1364
1466
  }
1365
1467
 
1366
- // ../../src/api/conversations.ts
1367
- function renderConversation(av) {
1368
- const out = [];
1369
- const msgs = av.Reduce("messages");
1370
- if (msgs.IsNil()) return out;
1371
- for (let i = 0; ; i++) {
1372
- const m = msgs.Reduce(i);
1373
- if (m.IsNil()) break;
1374
- const wire = m.Reduce("wire_id");
1375
- const receipt = m.Reduce("receipt");
1376
- out.push({
1377
- dir: m.Reduce("dir").Visualize() === "out" ? "out" : "in",
1378
- text: m.Reduce("text").Visualize(),
1379
- date: m.Reduce("date").Visualize(),
1380
- // GetBoolean, never Visualize: a MUFL boolean visualizes as '%%TRUE',
1381
- // never 'TRUE' — the G4 trap from wire-handlers, one layer up.
1382
- read: m.Reduce("read").GetBoolean(),
1383
- wire_id: wire.IsNil() ? "" : wire.Visualize(),
1384
- receipt: receipt.IsNil() ? null : receipt.Visualize()
1385
- });
1386
- }
1387
- return out;
1388
- }
1389
- async function getConversation(ctx, a) {
1468
+ // ../../src/api/history.ts
1469
+ function listHistory(ctx, query = {}) {
1390
1470
  const id = requireBound(ctx);
1391
1471
  try {
1392
- const messages = withScope(
1393
- (lt) => renderConversation(readonlyTx(id, "::actor::get_conversation", lt, { contact: a.contact }))
1394
- );
1395
- return { contact: a.contact, messages };
1396
- } catch (e) {
1397
- throw errTool("get_conversation", String(e));
1472
+ return listMessageHistory(id, query);
1473
+ } catch (error) {
1474
+ throw errTool("list_history", String(error));
1398
1475
  }
1399
1476
  }
1400
- async function getReceipts(ctx, a) {
1477
+ function getHistoryItem(ctx, input) {
1401
1478
  const id = requireBound(ctx);
1402
1479
  try {
1403
- const receipts = withScope((lt) => {
1404
- const av = readonlyTx(id, "::actor::get_receipts", lt, { contact: a.contact }).Reduce("receipts");
1405
- const out = {};
1406
- if (av.IsNil()) return out;
1407
- for (const key of av.GetKeys()) {
1408
- const wid = key.Visualize();
1409
- out[wid] = av.Reduce(wid).Visualize();
1410
- }
1411
- return out;
1412
- });
1413
- return { contact: a.contact, receipts };
1414
- } catch (e) {
1415
- throw errTool("get_receipts", String(e));
1480
+ return getMessageHistoryItem(id, input.wire_id);
1481
+ } catch (error) {
1482
+ throw errTool("get_history_item", String(error));
1416
1483
  }
1417
1484
  }
1418
- async function markRead(ctx, a) {
1485
+ function listFiles(ctx, query = {}) {
1419
1486
  const id = requireBound(ctx);
1420
1487
  try {
1421
- const marked = await withScopeAsync(async (lt) => {
1422
- const data = await mutatingTx(id, "::actor::mark_read", { contact: a.contact }, lt);
1423
- return Number(data.Reduce("marked").Visualize());
1424
- });
1425
- return { contact: a.contact, marked };
1426
- } catch (e) {
1427
- throw errTool("mark_read", String(e));
1488
+ return listFileHistory(id, query);
1489
+ } catch (error) {
1490
+ throw errTool("list_files", String(error));
1428
1491
  }
1429
1492
  }
1430
- async function setConversationPolicy(ctx, a) {
1493
+ function getFileInfo(ctx, input) {
1431
1494
  const id = requireBound(ctx);
1432
1495
  try {
1433
- return await withScopeAsync(async (lt) => {
1434
- const data = await mutatingTx(id, "::actor::set_local_policy", { keep_history: a.keep_history }, lt);
1435
- return {
1436
- keepHistory: data.Reduce("keep_history").GetBoolean(),
1437
- autoAccept: data.Reduce("auto_accept").GetBoolean()
1438
- };
1439
- });
1440
- } catch (e) {
1441
- throw errTool("set_local_policy", String(e));
1496
+ return getFileHistoryItem(id, input.wire_id);
1497
+ } catch (error) {
1498
+ throw errTool("get_file_info", String(error));
1442
1499
  }
1443
1500
  }
1444
1501
 
@@ -1478,18 +1535,14 @@ var API_OPERATIONS = {
1478
1535
  // ----- messaging (Task 12) -------------------------------------------------
1479
1536
  sendMessage: op(sendMessage),
1480
1537
  sendFile: op(sendFile),
1481
- listIncomingMessages: op0(listIncomingMessages),
1482
- getMessages: op0(getMessages),
1483
- deferMessages: op(deferMessages),
1484
- deferFiles: op(deferFiles),
1485
- // The messenger conversation surface. getConversation and getReceipts read
1486
- // without consuming or emitting; markRead is the human read event.
1487
- getConversation: op(getConversation),
1488
- getReceipts: op(getReceipts),
1489
- markRead: op(markRead),
1490
- setConversationPolicy: op(setConversationPolicy),
1538
+ listIncomingMessages: op0(listIncomingMessages2),
1539
+ getMessages: op(getMessages),
1540
+ listHistory: op(listHistory),
1541
+ getHistoryItem: op(getHistoryItem),
1542
+ listFiles: op(listFiles),
1543
+ getFileInfo: op(getFileInfo),
1491
1544
  // ----- files (Task 12) -----------------------------------------------------
1492
- listIncomingFiles: op0(listIncomingFiles),
1545
+ listIncomingFiles: op0(listIncomingFiles2),
1493
1546
  getFiles: op(getFiles),
1494
1547
  saveFileFallbackNotice: op(saveFileFallbackNotice)
1495
1548
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/cli",
3
- "version": "1.0.1",
3
+ "version": "2.0.1",
4
4
  "description": "Transport-neutral operator CLI for the ours shared daemon",
5
5
  "type": "module",
6
6
  "license": "FSL-1.1-Apache-2.0",
@@ -25,6 +25,7 @@
25
25
  "dependencies": {
26
26
  "@adapt-toolkit/sdk": "0.10.12",
27
27
  "@adapt-toolkit/sdk-native": "0.10.12",
28
- "@ours.network/sdk": "^2.0.0"
28
+ "@ours.network/sdk": "^3.0.0",
29
+ "better-sqlite3": "^11.10.0"
29
30
  }
30
31
  }