@hasna/economy 0.2.25 → 0.2.27

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/dist/cli/index.js CHANGED
@@ -1087,9 +1087,7 @@ function queryAgentBreakdown(db, period = "all") {
1087
1087
  }
1088
1088
  return [...groups.values()].sort((a, b) => b.api_equivalent_usd - a.api_equivalent_usd);
1089
1089
  }
1090
- function labelForPath(projectPath, projectName) {
1091
- if (projectName && projectName.trim() !== "")
1092
- return projectName;
1090
+ function pathProjectLabel(projectPath) {
1093
1091
  if (!projectPath)
1094
1092
  return "";
1095
1093
  const segments = projectPath.split("/").filter(Boolean);
@@ -1098,12 +1096,45 @@ function labelForPath(projectPath, projectName) {
1098
1096
  if (projectPrefix.test(seg))
1099
1097
  return seg;
1100
1098
  }
1101
- const generic = new Set(["web", "app", "apps", "packages", "src", "lib", "server", "client", "api", "frontend", "backend"]);
1099
+ const generic = new Set([
1100
+ "web",
1101
+ "app",
1102
+ "apps",
1103
+ "packages",
1104
+ "src",
1105
+ "lib",
1106
+ "server",
1107
+ "client",
1108
+ "api",
1109
+ "frontend",
1110
+ "backend",
1111
+ "home",
1112
+ "users",
1113
+ "workspace",
1114
+ "workspaces",
1115
+ "hasna"
1116
+ ]);
1102
1117
  for (let i = segments.length - 1;i >= 0; i--) {
1103
1118
  if (!generic.has(segments[i].toLowerCase()))
1104
1119
  return segments[i];
1105
1120
  }
1106
- return segments[segments.length - 1] ?? projectPath;
1121
+ return null;
1122
+ }
1123
+ function isRepoLikeLabel(label) {
1124
+ return /^(open|skill|hook|service|connect|platform|agent|tool|iapp|project|scaffold|capp)-/.test(label) || label.includes("-");
1125
+ }
1126
+ function labelForPath(projectPath, projectName) {
1127
+ const pathLabel = pathProjectLabel(projectPath);
1128
+ if (pathLabel && (!projectName || projectName.trim() === "" || isRepoLikeLabel(pathLabel)))
1129
+ return pathLabel;
1130
+ if (projectName && projectName.trim() !== "")
1131
+ return projectName;
1132
+ if (pathLabel)
1133
+ return pathLabel;
1134
+ return projectPath;
1135
+ }
1136
+ function groupKeyForPath(projectPath, projectName) {
1137
+ return labelForPath(projectPath, projectName).trim().toLowerCase();
1107
1138
  }
1108
1139
  function queryProjectBreakdown(db, period = "all") {
1109
1140
  const requestWhere = requestPeriodWhere(period);
@@ -1118,14 +1149,15 @@ function queryProjectBreakdown(db, period = "all") {
1118
1149
  const label = labelForPath(s.project_path, s.project_name);
1119
1150
  if (!label)
1120
1151
  continue;
1121
- const g = groups.get(label) ?? { sessionIds: [], samplePath: s.project_path };
1152
+ const key = groupKeyForPath(s.project_path, s.project_name);
1153
+ const g = groups.get(key) ?? { label, sessionIds: [], samplePath: s.project_path };
1122
1154
  g.sessionIds.push(s.id);
1123
1155
  if (!g.samplePath)
1124
1156
  g.samplePath = s.project_path;
1125
- groups.set(label, g);
1157
+ groups.set(key, g);
1126
1158
  }
1127
1159
  const result = [];
1128
- for (const [label, g] of groups.entries()) {
1160
+ for (const g of groups.values()) {
1129
1161
  const placeholders = g.sessionIds.map(() => "?").join(",");
1130
1162
  const reqStats = placeholders.length ? db.prepare(`
1131
1163
  SELECT
@@ -1156,7 +1188,7 @@ function queryProjectBreakdown(db, period = "all") {
1156
1188
  const lastActive = [reqStats.last_active, sessionOnlyStats.last_active].filter(Boolean).sort().at(-1) ?? "";
1157
1189
  result.push({
1158
1190
  project_path: g.samplePath,
1159
- project_name: label,
1191
+ project_name: g.label,
1160
1192
  sessions: totalSessions,
1161
1193
  requests: reqStats.requests + sessionOnlyStats.requests,
1162
1194
  total_tokens: reqStats.total_tokens + sessionOnlyStats.total_tokens,
@@ -1488,17 +1520,21 @@ function listMachineRegistry(db) {
1488
1520
  }
1489
1521
  function dedupeRequests(db) {
1490
1522
  const dupes = db.prepare(`
1491
- SELECT source_request_id, agent, MIN(id) as keep_id, COUNT(*) as cnt
1523
+ SELECT source_request_id, agent, COALESCE(machine_id, '') as machine_id, MIN(id) as keep_id, COUNT(*) as cnt
1492
1524
  FROM requests
1493
1525
  WHERE source_request_id != '' AND source_request_id IS NOT NULL
1494
- GROUP BY source_request_id, agent
1526
+ GROUP BY source_request_id, agent, COALESCE(machine_id, '')
1495
1527
  HAVING cnt > 1
1496
1528
  `).all();
1497
1529
  let removed = 0;
1498
1530
  for (const row of dupes) {
1499
1531
  const result = db.prepare(`
1500
- DELETE FROM requests WHERE source_request_id = ? AND agent = ? AND id != ?
1501
- `).run(row.source_request_id, row.agent, row.keep_id);
1532
+ DELETE FROM requests
1533
+ WHERE source_request_id = ?
1534
+ AND agent = ?
1535
+ AND COALESCE(machine_id, '') = ?
1536
+ AND id != ?
1537
+ `).run(row.source_request_id, row.agent, row.machine_id, row.keep_id);
1502
1538
  removed += result.changes;
1503
1539
  }
1504
1540
  return removed;
@@ -2642,6 +2678,25 @@ function buildThreadQuery(codexDb) {
2642
2678
  FROM threads WHERE tokens_used > 0
2643
2679
  `;
2644
2680
  }
2681
+ function openCodexDb(dbPath, verbose) {
2682
+ let lastError;
2683
+ for (const readonly of [true, false]) {
2684
+ let codexDb = null;
2685
+ try {
2686
+ codexDb = readonly ? new BunDatabase(dbPath, { readonly: true }) : new BunDatabase(dbPath);
2687
+ codexDb.prepare("PRAGMA schema_version").get();
2688
+ return codexDb;
2689
+ } catch (error) {
2690
+ lastError = error;
2691
+ codexDb?.close();
2692
+ }
2693
+ }
2694
+ if (verbose) {
2695
+ const message = lastError instanceof Error ? lastError.message : String(lastError);
2696
+ console.log("Codex DB unreadable:", dbPath, message);
2697
+ }
2698
+ return null;
2699
+ }
2645
2700
  function readTokenEvents(rolloutPath) {
2646
2701
  if (!rolloutPath || !existsSync5(rolloutPath))
2647
2702
  return [];
@@ -2731,7 +2786,9 @@ async function ingestCodex(db, verbose = false) {
2731
2786
  let requests = 0;
2732
2787
  const account = await resolveAccountForAgent("codex");
2733
2788
  try {
2734
- codexDb = new BunDatabase(dbPath, { readonly: true });
2789
+ codexDb = openCodexDb(dbPath, verbose);
2790
+ if (!codexDb)
2791
+ return { sessions: 0, requests: 0 };
2735
2792
  const threads = codexDb.prepare(buildThreadQuery(codexDb)).all();
2736
2793
  for (const thread of threads) {
2737
2794
  const model = thread.model ?? readCodexModel();
@@ -4007,7 +4064,7 @@ __export(exports_config, {
4007
4064
  loadConfig: () => loadConfig2,
4008
4065
  getConfigValue: () => getConfigValue
4009
4066
  });
4010
- import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
4067
+ import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
4011
4068
  import { dirname as dirname2, join as join12 } from "path";
4012
4069
  function getConfigPath() {
4013
4070
  return process.env["HASNA_ECONOMY_CONFIG_PATH"] ?? join12(getDataDir(), "config.json");
@@ -4015,7 +4072,7 @@ function getConfigPath() {
4015
4072
  function loadConfig2() {
4016
4073
  try {
4017
4074
  const configPath = getConfigPath();
4018
- if (existsSync12(configPath)) {
4075
+ if (existsSync13(configPath)) {
4019
4076
  const raw = readFileSync11(configPath, "utf-8");
4020
4077
  return { ...DEFAULTS, ...JSON.parse(raw) };
4021
4078
  }
@@ -4025,7 +4082,7 @@ function loadConfig2() {
4025
4082
  function saveConfig2(config) {
4026
4083
  const configPath = getConfigPath();
4027
4084
  const dir = dirname2(configPath);
4028
- if (!existsSync12(dir))
4085
+ if (!existsSync13(dir))
4029
4086
  mkdirSync3(dir, { recursive: true });
4030
4087
  writeFileSync2(configPath, JSON.stringify(config, null, 2) + `
4031
4088
  `);
@@ -4169,7 +4226,7 @@ var init_webhooks = __esm(() => {
4169
4226
  });
4170
4227
 
4171
4228
  // src/lib/watch-paths.ts
4172
- import { existsSync as existsSync13 } from "fs";
4229
+ import { existsSync as existsSync14 } from "fs";
4173
4230
  function getWatchPaths() {
4174
4231
  const p = agentPaths();
4175
4232
  const candidates = [
@@ -4182,7 +4239,7 @@ function getWatchPaths() {
4182
4239
  p.piSessions,
4183
4240
  p.hermesDir
4184
4241
  ];
4185
- return candidates.filter((path) => existsSync13(path));
4242
+ return candidates.filter((path) => existsSync14(path));
4186
4243
  }
4187
4244
  var init_watch_paths = __esm(() => {
4188
4245
  init_paths();
@@ -4352,7 +4409,7 @@ __export(exports_serve, {
4352
4409
  createHandler: () => createHandler
4353
4410
  });
4354
4411
  import { randomUUID as randomUUID2 } from "crypto";
4355
- import { existsSync as existsSync14 } from "fs";
4412
+ import { existsSync as existsSync15 } from "fs";
4356
4413
  import { resolve, sep } from "path";
4357
4414
  function json(data, status = 200) {
4358
4415
  return new Response(JSON.stringify(data), {
@@ -4417,13 +4474,13 @@ function createServerFetch(apiHandler, dashboardDir = DEFAULT_DASHBOARD_DIR) {
4417
4474
  if (url.pathname.startsWith("/api") || url.pathname === "/health") {
4418
4475
  return apiHandler(req);
4419
4476
  }
4420
- if (existsSync14(dashboardDir)) {
4477
+ if (existsSync15(dashboardDir)) {
4421
4478
  const filePath = dashboardPath(dashboardDir, url.pathname);
4422
- if (filePath && existsSync14(filePath)) {
4479
+ if (filePath && existsSync15(filePath)) {
4423
4480
  return new Response(Bun.file(filePath));
4424
4481
  }
4425
4482
  const indexPath = dashboardPath(dashboardDir, "/");
4426
- if (indexPath && existsSync14(indexPath)) {
4483
+ if (indexPath && existsSync15(indexPath)) {
4427
4484
  return new Response(Bun.file(indexPath));
4428
4485
  }
4429
4486
  }
@@ -4820,14 +4877,14 @@ __export(exports_menubar, {
4820
4877
  });
4821
4878
  import chalk6 from "chalk";
4822
4879
  import { execFileSync as execFileSync2 } from "child_process";
4823
- import { cpSync, existsSync as existsSync15, mkdirSync as mkdirSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
4880
+ import { cpSync, existsSync as existsSync16, mkdirSync as mkdirSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
4824
4881
  import { tmpdir, arch } from "os";
4825
4882
  import { join as join13 } from "path";
4826
4883
  function getArch() {
4827
4884
  return arch() === "arm64" ? "arm64" : "x86_64";
4828
4885
  }
4829
4886
  function isInstalled() {
4830
- return existsSync15(APP_PATH);
4887
+ return existsSync16(APP_PATH);
4831
4888
  }
4832
4889
  function isRunning() {
4833
4890
  try {
@@ -6161,6 +6218,7 @@ var TOP_LEVEL = [
6161
6218
  "init",
6162
6219
  "estimate",
6163
6220
  "fleet",
6221
+ "merge-db",
6164
6222
  "todos",
6165
6223
  "serve",
6166
6224
  "mcp",
@@ -6514,6 +6572,285 @@ function registerFleetCommands(program) {
6514
6572
  init_agents();
6515
6573
  init_sync_all();
6516
6574
  init_cloud_sync();
6575
+
6576
+ // src/lib/peer-sync.ts
6577
+ init_database();
6578
+ init_package_metadata();
6579
+ import { Database as BunDatabase2 } from "bun:sqlite";
6580
+ import { existsSync as existsSync12 } from "fs";
6581
+ var GENERIC_PEER_TABLES = [
6582
+ "usage_snapshots",
6583
+ "subscriptions",
6584
+ "billing_daily",
6585
+ "savings_daily",
6586
+ "budgets",
6587
+ "goals",
6588
+ "model_pricing",
6589
+ "machines"
6590
+ ];
6591
+ function quoteIdent(identifier) {
6592
+ return `"${identifier.replace(/"/g, '""')}"`;
6593
+ }
6594
+ function tableExists(db, table) {
6595
+ const row = db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?`).get(table);
6596
+ return Boolean(row);
6597
+ }
6598
+ function tableColumns(db, table) {
6599
+ if (!tableExists(db, table))
6600
+ return [];
6601
+ return db.prepare(`PRAGMA table_info(${quoteIdent(table)})`).all();
6602
+ }
6603
+ function commonColumns(source, target, table) {
6604
+ const sourceCols = new Set(tableColumns(source, table).map((c) => c.name));
6605
+ return tableColumns(target, table).map((c) => c.name).filter((c) => sourceCols.has(c));
6606
+ }
6607
+ function primaryKeyColumns(db, table) {
6608
+ return tableColumns(db, table).filter((c) => c.pk > 0).sort((a, b) => a.pk - b.pk).map((c) => c.name);
6609
+ }
6610
+ function selectRows(source, table, columns) {
6611
+ if (columns.length === 0)
6612
+ return [];
6613
+ const select = columns.map(quoteIdent).join(", ");
6614
+ return source.prepare(`SELECT ${select} FROM ${quoteIdent(table)}`).all();
6615
+ }
6616
+ function rowByKey(target, table, keyColumns, row) {
6617
+ if (keyColumns.length === 0)
6618
+ return null;
6619
+ if (keyColumns.some((c) => row[c] == null))
6620
+ return null;
6621
+ const where = keyColumns.map((c) => `${quoteIdent(c)} = ?`).join(" AND ");
6622
+ return target.prepare(`SELECT * FROM ${quoteIdent(table)} WHERE ${where}`).get(...keyColumns.map((c) => row[c]));
6623
+ }
6624
+ function hasId(target, table, id) {
6625
+ return target.prepare(`SELECT id, machine_id FROM ${quoteIdent(table)} WHERE id = ?`).get(id);
6626
+ }
6627
+ function shouldReplace(source, existing) {
6628
+ if (!existing)
6629
+ return true;
6630
+ const sourceUpdated = source["updated_at"];
6631
+ const existingUpdated = existing["updated_at"];
6632
+ if (typeof sourceUpdated === "string" && typeof existingUpdated === "string" && existingUpdated !== "") {
6633
+ return sourceUpdated >= existingUpdated;
6634
+ }
6635
+ return true;
6636
+ }
6637
+ function normalizeRow(row, columns, sourceMachine, now) {
6638
+ const next = { ...row };
6639
+ if (columns.includes("machine_id") && (!next["machine_id"] || next["machine_id"] === "")) {
6640
+ next["machine_id"] = sourceMachine;
6641
+ }
6642
+ if (columns.includes("updated_at") && (!next["updated_at"] || next["updated_at"] === "")) {
6643
+ next["updated_at"] = next["timestamp"] ?? next["started_at"] ?? next["created_at"] ?? now;
6644
+ }
6645
+ if (columns.includes("synced_at") && next["synced_at"] == null)
6646
+ next["synced_at"] = "";
6647
+ if (columns.includes("attribution_tag") && next["attribution_tag"] == null)
6648
+ next["attribution_tag"] = "";
6649
+ return next;
6650
+ }
6651
+ function insertOrReplace(target, table, columns, row) {
6652
+ const colSql = columns.map(quoteIdent).join(", ");
6653
+ const placeholders = columns.map(() => "?").join(", ");
6654
+ target.prepare(`
6655
+ INSERT OR REPLACE INTO ${quoteIdent(table)} (${colSql})
6656
+ VALUES (${placeholders})
6657
+ `).run(...columns.map((c) => row[c] ?? null));
6658
+ }
6659
+ function collisionId(target, table, machine, originalId) {
6660
+ const base = `${machine || "peer"}:${originalId}`;
6661
+ const baseRow = hasId(target, table, base);
6662
+ if (!baseRow || String(baseRow["machine_id"] ?? "") === machine)
6663
+ return base;
6664
+ for (let i = 2;; i++) {
6665
+ const candidate = `${base}:${i}`;
6666
+ const row = hasId(target, table, candidate);
6667
+ if (!row || String(row["machine_id"] ?? "") === machine)
6668
+ return candidate;
6669
+ }
6670
+ }
6671
+ function mergeIdentityTable(target, source, table, sourceMachine, now, sessionIdMap) {
6672
+ const stats = { table, inserted: 0, updated: 0, skipped: 0, collisions: 0 };
6673
+ const columns = commonColumns(source, target, table);
6674
+ const rows = selectRows(source, table, columns);
6675
+ const idMap = new Map;
6676
+ for (const raw of rows) {
6677
+ const row = normalizeRow(raw, columns, sourceMachine, now);
6678
+ const originalId = String(row["id"] ?? "");
6679
+ if (!originalId) {
6680
+ stats.skipped++;
6681
+ continue;
6682
+ }
6683
+ const machine = String(row["machine_id"] ?? "");
6684
+ const directExisting = hasId(target, table, originalId);
6685
+ if (directExisting && String(directExisting["machine_id"] ?? "") !== machine) {
6686
+ row["id"] = collisionId(target, table, machine, originalId);
6687
+ stats.collisions++;
6688
+ }
6689
+ if (table === "requests" && sessionIdMap) {
6690
+ const originalSessionId = String(row["session_id"] ?? "");
6691
+ row["session_id"] = sessionIdMap.get(originalSessionId) ?? originalSessionId;
6692
+ }
6693
+ const existing = hasId(target, table, String(row["id"]));
6694
+ idMap.set(originalId, String(row["id"]));
6695
+ if (existing && !shouldReplace(row, existing)) {
6696
+ stats.skipped++;
6697
+ continue;
6698
+ }
6699
+ insertOrReplace(target, table, columns, row);
6700
+ if (existing)
6701
+ stats.updated++;
6702
+ else
6703
+ stats.inserted++;
6704
+ }
6705
+ return { stats, idMap };
6706
+ }
6707
+ function mergeProjects(target, source) {
6708
+ const table = "projects";
6709
+ const stats = { table, inserted: 0, updated: 0, skipped: 0, collisions: 0 };
6710
+ const columns = commonColumns(source, target, table);
6711
+ const rows = selectRows(source, table, columns);
6712
+ for (const raw of rows) {
6713
+ const row = { ...raw };
6714
+ const path = String(row["path"] ?? "");
6715
+ const id = String(row["id"] ?? "");
6716
+ if (!path || !id) {
6717
+ stats.skipped++;
6718
+ continue;
6719
+ }
6720
+ const existingByPath = target.prepare(`SELECT * FROM projects WHERE path = ?`).get(path);
6721
+ if (existingByPath) {
6722
+ row["id"] = existingByPath["id"] ?? id;
6723
+ insertOrReplace(target, table, columns, row);
6724
+ stats.updated++;
6725
+ continue;
6726
+ }
6727
+ const existingById = target.prepare(`SELECT * FROM projects WHERE id = ?`).get(id);
6728
+ if (existingById && String(existingById["path"] ?? "") !== path) {
6729
+ row["id"] = `peer:${id}`;
6730
+ stats.collisions++;
6731
+ while (target.prepare(`SELECT id FROM projects WHERE id = ?`).get(row["id"])) {
6732
+ row["id"] = `peer:${String(row["id"])}`;
6733
+ }
6734
+ }
6735
+ insertOrReplace(target, table, columns, row);
6736
+ stats.inserted++;
6737
+ }
6738
+ return stats;
6739
+ }
6740
+ function mergeGenericTable(target, source, table, sourceMachine, now) {
6741
+ const stats = { table, inserted: 0, updated: 0, skipped: 0, collisions: 0 };
6742
+ const columns = commonColumns(source, target, table);
6743
+ const keyColumns = primaryKeyColumns(target, table).filter((c) => columns.includes(c));
6744
+ const rows = selectRows(source, table, columns);
6745
+ for (const raw of rows) {
6746
+ const row = normalizeRow(raw, columns, sourceMachine, now);
6747
+ const existing = rowByKey(target, table, keyColumns, row);
6748
+ if (existing && !shouldReplace(row, existing)) {
6749
+ stats.skipped++;
6750
+ continue;
6751
+ }
6752
+ insertOrReplace(target, table, columns, row);
6753
+ if (existing)
6754
+ stats.updated++;
6755
+ else
6756
+ stats.inserted++;
6757
+ }
6758
+ return stats;
6759
+ }
6760
+ function detectSourceMachine(source, fallback) {
6761
+ if (fallback && fallback.trim())
6762
+ return fallback.trim();
6763
+ const counts = new Map;
6764
+ for (const table of ["sessions", "requests", "usage_snapshots"]) {
6765
+ if (!tableExists(source, table))
6766
+ continue;
6767
+ const rows = source.prepare(`
6768
+ SELECT machine_id, COUNT(*) as cnt
6769
+ FROM ${quoteIdent(table)}
6770
+ WHERE machine_id != '' AND machine_id IS NOT NULL
6771
+ GROUP BY machine_id
6772
+ `).all();
6773
+ for (const row of rows) {
6774
+ counts.set(row.machine_id, (counts.get(row.machine_id) ?? 0) + row.cnt);
6775
+ }
6776
+ }
6777
+ let best = "";
6778
+ let bestCount = -1;
6779
+ for (const [machine, count] of counts.entries()) {
6780
+ if (count > bestCount) {
6781
+ best = machine;
6782
+ bestCount = count;
6783
+ }
6784
+ }
6785
+ return best || "peer";
6786
+ }
6787
+ function ensureMachineRegistry(target, machine, now) {
6788
+ if (!machine)
6789
+ return;
6790
+ target.prepare(`
6791
+ INSERT INTO machines (machine_id, hostname, last_seen_at, last_push_at, last_pull_at, economy_version, updated_at)
6792
+ VALUES (?, ?, ?, NULL, ?, ?, ?)
6793
+ ON CONFLICT(machine_id) DO UPDATE SET
6794
+ hostname = COALESCE(NULLIF(machines.hostname, ''), excluded.hostname),
6795
+ last_seen_at = CASE
6796
+ WHEN machines.last_seen_at IS NULL OR machines.last_seen_at < excluded.last_seen_at THEN excluded.last_seen_at
6797
+ ELSE machines.last_seen_at
6798
+ END,
6799
+ last_pull_at = excluded.last_pull_at,
6800
+ economy_version = excluded.economy_version,
6801
+ updated_at = excluded.updated_at
6802
+ `).run(machine, machine, now, now, packageMetadata.version, now);
6803
+ }
6804
+ function openSourceDatabase(path) {
6805
+ try {
6806
+ return new BunDatabase2(path, { readonly: true });
6807
+ } catch {
6808
+ return new BunDatabase2(path);
6809
+ }
6810
+ }
6811
+ function mergePeerDatabase(target, sourcePath, opts = {}) {
6812
+ if (!existsSync12(sourcePath))
6813
+ throw new Error(`source database does not exist: ${sourcePath}`);
6814
+ const source = openSourceDatabase(sourcePath);
6815
+ const now = opts.now ?? new Date().toISOString();
6816
+ const sourceMachine = detectSourceMachine(source, opts.sourceMachine);
6817
+ const tables = [];
6818
+ try {
6819
+ target.exec("PRAGMA foreign_keys = OFF");
6820
+ target.exec("BEGIN IMMEDIATE");
6821
+ try {
6822
+ tables.push(mergeProjects(target, source));
6823
+ const sessionMerge = mergeIdentityTable(target, source, "sessions", sourceMachine, now);
6824
+ tables.push(sessionMerge.stats);
6825
+ tables.push(mergeIdentityTable(target, source, "requests", sourceMachine, now, sessionMerge.idMap).stats);
6826
+ for (const table of GENERIC_PEER_TABLES) {
6827
+ tables.push(mergeGenericTable(target, source, table, sourceMachine, now));
6828
+ }
6829
+ ensureMachineRegistry(target, sourceMachine, now);
6830
+ target.exec("COMMIT");
6831
+ } catch (err) {
6832
+ target.exec("ROLLBACK");
6833
+ throw err;
6834
+ } finally {
6835
+ target.exec("PRAGMA foreign_keys = ON");
6836
+ }
6837
+ } finally {
6838
+ source.close();
6839
+ }
6840
+ const deduped = dedupeRequests(target);
6841
+ const rowsWritten = tables.reduce((sum, table) => sum + table.inserted + table.updated, 0);
6842
+ const collisions = tables.reduce((sum, table) => sum + table.collisions, 0);
6843
+ return {
6844
+ source_path: sourcePath,
6845
+ source_machine: sourceMachine,
6846
+ rows_written: rowsWritten,
6847
+ collisions,
6848
+ deduped,
6849
+ tables: tables.filter((t) => t.inserted || t.updated || t.skipped || t.collisions)
6850
+ };
6851
+ }
6852
+
6853
+ // src/cli/index.ts
6517
6854
  init_database();
6518
6855
  init_database();
6519
6856
  init_billing();
@@ -7340,6 +7677,21 @@ program.command("machines").description("List all machines that have synced data
7340
7677
  ${chalk7.dim("Current machine:")} ${chalk7.bold(current)}`);
7341
7678
  console.log();
7342
7679
  });
7680
+ program.command("merge-db <source-db>").description("Merge another Economy SQLite database into this machine").option("--source-machine <id>", "Machine id to use for source rows that do not have one").option("--json", "Output JSON").action((sourceDb, opts) => {
7681
+ const db = openDatabase();
7682
+ const result = mergePeerDatabase(db, sourceDb, { sourceMachine: opts.sourceMachine });
7683
+ if (opts.json) {
7684
+ console.log(JSON.stringify(result, null, 2));
7685
+ return;
7686
+ }
7687
+ console.log();
7688
+ console.log(chalk7.bold.cyan(` Merged Economy DB \u2014 ${result.source_machine}`));
7689
+ console.log(` Rows written: ${fmtCount(result.rows_written)} \xB7 collisions remapped: ${fmtCount(result.collisions)} \xB7 deduped: ${fmtCount(result.deduped)}`);
7690
+ for (const table of result.tables) {
7691
+ console.log(` ${chalk7.white(table.table.padEnd(16))}` + ` inserted ${fmtCount(table.inserted).padStart(6)}` + ` updated ${fmtCount(table.updated).padStart(6)}` + ` skipped ${fmtCount(table.skipped).padStart(6)}` + ` collisions ${fmtCount(table.collisions).padStart(3)}`);
7692
+ }
7693
+ console.log();
7694
+ });
7343
7695
  program.command("export").description("Export data as CSV").option("--type <type>", "Data type: sessions or requests", "sessions").option("--period <period>", "Period: today|week|month|all", "month").option("--output <file>", "Output file path (default: stdout)").action(async (opts) => {
7344
7696
  await autoSync();
7345
7697
  const db = openDatabase();
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from './lib/pricing.js';
4
4
  export * from './lib/gatherer.js';
5
5
  export * from './lib/model-config.js';
6
6
  export * from './lib/open-projects.js';
7
+ export * from './lib/peer-sync.js';
7
8
  export * from './ingest/claude.js';
8
9
  export * from './ingest/codex.js';
9
10
  export * from './ingest/gemini.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,oBAAoB,CAAA"}