@devness/useai 0.8.2 → 0.8.3

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 (2) hide show
  1. package/dist/index.js +175 -57
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -684,7 +684,7 @@ var VERSION;
684
684
  var init_version = __esm({
685
685
  "../shared/dist/constants/version.js"() {
686
686
  "use strict";
687
- VERSION = "0.8.2";
687
+ VERSION = "0.8.3";
688
688
  }
689
689
  });
690
690
 
@@ -34181,8 +34181,8 @@ function enrichAutoSealedSession(sealedSessionId, session2, args) {
34181
34181
  if (lastRecord.type === "session_seal" && lastRecord.data["seal"]) {
34182
34182
  try {
34183
34183
  const sealObj = JSON.parse(lastRecord.data["seal"]);
34184
- duration3 = sealObj.duration_seconds ?? Math.round((new Date(lastRecord.timestamp).getTime() - new Date(startedAt2).getTime()) / 1e3);
34185
- endedAt = sealObj.ended_at ?? lastRecord.timestamp;
34184
+ duration3 = sealObj.duration_seconds || Math.round((new Date(lastRecord.timestamp).getTime() - new Date(startedAt2).getTime()) / 1e3);
34185
+ endedAt = sealObj.ended_at && sealObj.ended_at !== startedAt2 ? sealObj.ended_at : lastRecord.timestamp;
34186
34186
  } catch {
34187
34187
  duration3 = Math.round((new Date(lastRecord.timestamp).getTime() - new Date(startedAt2).getTime()) / 1e3);
34188
34188
  endedAt = lastRecord.timestamp;
@@ -34270,7 +34270,10 @@ function enrichAutoSealedSession(sealedSessionId, session2, args) {
34270
34270
  files_touched: filesTouched,
34271
34271
  evaluation: args.evaluation ?? existing.evaluation,
34272
34272
  session_score: sessionScore ?? existing.session_score,
34273
- evaluation_framework: frameworkId ?? existing.evaluation_framework
34273
+ evaluation_framework: frameworkId ?? existing.evaluation_framework,
34274
+ // Fix duration/ended_at for auto-sealed sessions that had 0s duration
34275
+ duration_seconds: duration3 || existing.duration_seconds,
34276
+ ended_at: endedAt !== startedAt2 ? endedAt : existing.ended_at
34274
34277
  };
34275
34278
  } else {
34276
34279
  allSessions.push(richSeal);
@@ -34856,9 +34859,111 @@ var init_html = __esm({
34856
34859
  }
34857
34860
  });
34858
34861
 
34859
- // src/dashboard/local-api.ts
34860
- import { existsSync as existsSync9, unlinkSync as unlinkSync4 } from "fs";
34862
+ // src/reconcile.ts
34863
+ import { readFileSync as readFileSync6, existsSync as existsSync9 } from "fs";
34861
34864
  import { join as join8 } from "path";
34865
+ function extractSealFromChain(sessionId) {
34866
+ const chainPath = join8(SEALED_DIR, `${sessionId}.jsonl`);
34867
+ if (!existsSync9(chainPath)) return null;
34868
+ try {
34869
+ const content = readFileSync6(chainPath, "utf-8").trim();
34870
+ const lines = content.split("\n").filter(Boolean);
34871
+ if (lines.length === 0) return null;
34872
+ const records = lines.map((line) => JSON.parse(line));
34873
+ const integrity = verifyChain(records);
34874
+ if (!integrity.valid) return null;
34875
+ const sealRecord = records.find((r) => r.type === "session_seal");
34876
+ if (!sealRecord || !sealRecord.data["seal"]) return null;
34877
+ const sealData = JSON.parse(sealRecord.data["seal"]);
34878
+ return sealData;
34879
+ } catch {
34880
+ return null;
34881
+ }
34882
+ }
34883
+ function reconcileSession(indexEntry) {
34884
+ const chainSeal = extractSealFromChain(indexEntry.session_id);
34885
+ if (chainSeal === null) {
34886
+ const chainPath = join8(SEALED_DIR, `${indexEntry.session_id}.jsonl`);
34887
+ const corrupted = existsSync9(chainPath);
34888
+ return { session: indexEntry, corrected: false, corrupted };
34889
+ }
34890
+ let corrected = false;
34891
+ const fixed = { ...indexEntry };
34892
+ for (const field of RECONCILE_FIELDS) {
34893
+ const chainValue = chainSeal[field];
34894
+ const indexValue = indexEntry[field];
34895
+ if (chainValue === void 0 || chainValue === null) continue;
34896
+ if (chainValue !== indexValue) {
34897
+ fixed[field] = chainValue;
34898
+ corrected = true;
34899
+ }
34900
+ }
34901
+ if (chainSeal.evaluation && JSON.stringify(chainSeal.evaluation) !== JSON.stringify(indexEntry.evaluation)) {
34902
+ fixed.evaluation = chainSeal.evaluation;
34903
+ corrected = true;
34904
+ }
34905
+ return { session: fixed, corrected, corrupted: false };
34906
+ }
34907
+ function reconcileSessions(sessions2) {
34908
+ const result = {
34909
+ checked: 0,
34910
+ corrected: 0,
34911
+ corrupted: 0,
34912
+ correctedIds: [],
34913
+ corruptedIds: []
34914
+ };
34915
+ const reconciled = [];
34916
+ for (const session2 of sessions2) {
34917
+ const { session: fixed, corrected, corrupted } = reconcileSession(session2);
34918
+ result.checked++;
34919
+ if (corrupted) {
34920
+ result.corrupted++;
34921
+ result.corruptedIds.push(session2.session_id);
34922
+ }
34923
+ if (corrected) {
34924
+ result.corrected++;
34925
+ result.correctedIds.push(session2.session_id);
34926
+ }
34927
+ reconciled.push(fixed);
34928
+ }
34929
+ if (result.corrected > 0) {
34930
+ const allSessions = readJson(SESSIONS_FILE, []);
34931
+ for (const correctedId of result.correctedIds) {
34932
+ const correctedSession = reconciled.find((s) => s.session_id === correctedId);
34933
+ const idx = allSessions.findIndex((s) => s.session_id === correctedId);
34934
+ if (correctedSession && idx >= 0) {
34935
+ allSessions[idx] = correctedSession;
34936
+ }
34937
+ }
34938
+ writeJson(SESSIONS_FILE, allSessions);
34939
+ }
34940
+ return { sessions: reconciled, result };
34941
+ }
34942
+ function reconcileForSync(sessions2) {
34943
+ const { sessions: reconciled, result } = reconcileSessions(sessions2);
34944
+ const filtered = reconciled.filter(
34945
+ (s) => !result.corruptedIds.includes(s.session_id)
34946
+ );
34947
+ return { sessions: filtered, result };
34948
+ }
34949
+ var RECONCILE_FIELDS;
34950
+ var init_reconcile = __esm({
34951
+ "src/reconcile.ts"() {
34952
+ "use strict";
34953
+ init_dist();
34954
+ RECONCILE_FIELDS = [
34955
+ "duration_seconds",
34956
+ "ended_at",
34957
+ "started_at",
34958
+ "session_score",
34959
+ "files_touched"
34960
+ ];
34961
+ }
34962
+ });
34963
+
34964
+ // src/dashboard/local-api.ts
34965
+ import { existsSync as existsSync10, unlinkSync as unlinkSync4 } from "fs";
34966
+ import { join as join9 } from "path";
34862
34967
  function json(res, status, data) {
34863
34968
  const body = JSON.stringify(data);
34864
34969
  res.writeHead(status, {
@@ -34914,7 +35019,8 @@ function calculateStreak(sessions2) {
34914
35019
  }
34915
35020
  function handleLocalSessions(_req, res) {
34916
35021
  try {
34917
- const sessions2 = deduplicateSessions(readJson(SESSIONS_FILE, []));
35022
+ const deduplicated = deduplicateSessions(readJson(SESSIONS_FILE, []));
35023
+ const { sessions: sessions2 } = reconcileSessions(deduplicated);
34918
35024
  json(res, 200, sessions2);
34919
35025
  } catch (err) {
34920
35026
  json(res, 500, { error: err.message });
@@ -34922,7 +35028,8 @@ function handleLocalSessions(_req, res) {
34922
35028
  }
34923
35029
  function handleLocalStats(_req, res) {
34924
35030
  try {
34925
- const sessions2 = deduplicateSessions(readJson(SESSIONS_FILE, []));
35031
+ const deduplicated = deduplicateSessions(readJson(SESSIONS_FILE, []));
35032
+ const { sessions: sessions2 } = reconcileSessions(deduplicated);
34926
35033
  let totalSeconds = 0;
34927
35034
  let filesTouched = 0;
34928
35035
  const byClient = {};
@@ -35037,7 +35144,8 @@ async function performSync() {
35037
35144
  "Content-Type": "application/json",
35038
35145
  "Authorization": `Bearer ${token}`
35039
35146
  };
35040
- const sessions2 = deduplicateSessions(readJson(SESSIONS_FILE, []));
35147
+ const deduplicated = deduplicateSessions(readJson(SESSIONS_FILE, []));
35148
+ const { sessions: sessions2 } = reconcileForSync(deduplicated);
35041
35149
  const byDate = /* @__PURE__ */ new Map();
35042
35150
  for (const s of sessions2) {
35043
35151
  if (!s.started_at) continue;
@@ -35080,22 +35188,31 @@ async function performSync() {
35080
35188
  }
35081
35189
  if (syncInclude.milestones) {
35082
35190
  const MILESTONE_CHUNK = 50;
35083
- const milestones = readJson(MILESTONES_FILE, []);
35084
- const sanitizedMilestones = syncInclude.private_titles ? milestones : milestones.map((m) => {
35085
- const { private_title: _, ...rest } = m;
35086
- return rest;
35087
- });
35088
- for (let i = 0; i < sanitizedMilestones.length; i += MILESTONE_CHUNK) {
35089
- const chunk = sanitizedMilestones.slice(i, i + MILESTONE_CHUNK);
35090
- const milestonesRes = await fetch(`${USEAI_API}/api/publish`, {
35091
- method: "POST",
35092
- headers,
35093
- body: JSON.stringify({ milestones: chunk })
35191
+ const allMilestones = readJson(MILESTONES_FILE, []);
35192
+ const unpublished = allMilestones.filter((m) => !m.published && m.title && m.category);
35193
+ if (unpublished.length > 0) {
35194
+ const sanitizedMilestones = syncInclude.private_titles ? unpublished : unpublished.map((m) => {
35195
+ const { private_title: _, ...rest } = m;
35196
+ return rest;
35094
35197
  });
35095
- if (!milestonesRes.ok) {
35096
- const errBody = await milestonesRes.text();
35097
- return { success: false, error: `Milestones publish failed (chunk ${Math.floor(i / MILESTONE_CHUNK) + 1}): ${milestonesRes.status} ${errBody}` };
35198
+ for (let i = 0; i < sanitizedMilestones.length; i += MILESTONE_CHUNK) {
35199
+ const chunk = sanitizedMilestones.slice(i, i + MILESTONE_CHUNK);
35200
+ const milestonesRes = await fetch(`${USEAI_API}/api/publish`, {
35201
+ method: "POST",
35202
+ headers,
35203
+ body: JSON.stringify({ milestones: chunk })
35204
+ });
35205
+ if (!milestonesRes.ok) {
35206
+ const errBody = await milestonesRes.text();
35207
+ return { success: false, error: `Milestones publish failed (chunk ${Math.floor(i / MILESTONE_CHUNK) + 1}): ${milestonesRes.status} ${errBody}` };
35208
+ }
35098
35209
  }
35210
+ const sentIds = new Set(unpublished.map((m) => m.id));
35211
+ const now2 = (/* @__PURE__ */ new Date()).toISOString();
35212
+ const updated = allMilestones.map(
35213
+ (m) => sentIds.has(m.id) ? { ...m, published: true, published_at: now2 } : m
35214
+ );
35215
+ writeJson(MILESTONES_FILE, updated);
35099
35216
  }
35100
35217
  }
35101
35218
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -35283,8 +35400,8 @@ function handleDeleteSession(req, res, sessionId) {
35283
35400
  const remaining = milestones.filter((m) => m.session_id !== sessionId);
35284
35401
  const milestonesRemoved = milestones.length - remaining.length;
35285
35402
  if (milestonesRemoved > 0) writeJson(MILESTONES_FILE, remaining);
35286
- const chainPath = join8(SEALED_DIR, `${sessionId}.jsonl`);
35287
- if (existsSync9(chainPath)) unlinkSync4(chainPath);
35403
+ const chainPath = join9(SEALED_DIR, `${sessionId}.jsonl`);
35404
+ if (existsSync10(chainPath)) unlinkSync4(chainPath);
35288
35405
  json(res, 200, { deleted: true, session_id: sessionId, milestones_removed: milestonesRemoved });
35289
35406
  } catch (err) {
35290
35407
  json(res, 500, { error: err.message });
@@ -35306,8 +35423,8 @@ function handleDeleteConversation(req, res, conversationId) {
35306
35423
  const milestonesRemoved = milestones.length - remainingMilestones.length;
35307
35424
  if (milestonesRemoved > 0) writeJson(MILESTONES_FILE, remainingMilestones);
35308
35425
  for (const sid of sessionIds) {
35309
- const chainPath = join8(SEALED_DIR, `${sid}.jsonl`);
35310
- if (existsSync9(chainPath)) unlinkSync4(chainPath);
35426
+ const chainPath = join9(SEALED_DIR, `${sid}.jsonl`);
35427
+ if (existsSync10(chainPath)) unlinkSync4(chainPath);
35311
35428
  }
35312
35429
  json(res, 200, { deleted: true, conversation_id: conversationId, sessions_removed: sessionIds.size, milestones_removed: milestonesRemoved });
35313
35430
  } catch (err) {
@@ -35389,6 +35506,7 @@ var init_local_api = __esm({
35389
35506
  "use strict";
35390
35507
  init_dist();
35391
35508
  init_tools2();
35509
+ init_reconcile();
35392
35510
  _onConfigUpdated = null;
35393
35511
  USEAI_API = process.env.USEAI_API_URL || "https://api.useai.dev";
35394
35512
  }
@@ -35401,8 +35519,8 @@ __export(daemon_exports, {
35401
35519
  });
35402
35520
  import { createServer } from "http";
35403
35521
  import { createHash as createHash4, randomUUID as randomUUID4 } from "crypto";
35404
- import { existsSync as existsSync10, readdirSync as readdirSync2, readFileSync as readFileSync6, appendFileSync as appendFileSync2, renameSync as renameSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5, statSync } from "fs";
35405
- import { join as join9 } from "path";
35522
+ import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync7, appendFileSync as appendFileSync2, renameSync as renameSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync5, statSync } from "fs";
35523
+ import { join as join10 } from "path";
35406
35524
  function getActiveUseaiSessionIds() {
35407
35525
  const ids = /* @__PURE__ */ new Set();
35408
35526
  for (const [, active] of sessions) {
@@ -35414,10 +35532,10 @@ function getActiveUseaiSessionIds() {
35414
35532
  return ids;
35415
35533
  }
35416
35534
  function sealOrphanFile(sessionId) {
35417
- const filePath = join9(ACTIVE_DIR, `${sessionId}.jsonl`);
35418
- if (!existsSync10(filePath)) return;
35535
+ const filePath = join10(ACTIVE_DIR, `${sessionId}.jsonl`);
35536
+ if (!existsSync11(filePath)) return;
35419
35537
  try {
35420
- const content = readFileSync6(filePath, "utf-8").trim();
35538
+ const content = readFileSync7(filePath, "utf-8").trim();
35421
35539
  if (!content) return;
35422
35540
  const lines = content.split("\n").filter(Boolean);
35423
35541
  if (lines.length === 0) return;
@@ -35425,7 +35543,7 @@ function sealOrphanFile(sessionId) {
35425
35543
  const lastRecord = JSON.parse(lines[lines.length - 1]);
35426
35544
  if (lastRecord.type === "session_end" || lastRecord.type === "session_seal") {
35427
35545
  try {
35428
- renameSync3(filePath, join9(SEALED_DIR, `${sessionId}.jsonl`));
35546
+ renameSync3(filePath, join10(SEALED_DIR, `${sessionId}.jsonl`));
35429
35547
  } catch {
35430
35548
  }
35431
35549
  return;
@@ -35485,7 +35603,7 @@ function sealOrphanFile(sessionId) {
35485
35603
  }, endRecord.hash, daemonSigningKey)
35486
35604
  ) + "\n");
35487
35605
  try {
35488
- renameSync3(filePath, join9(SEALED_DIR, `${sessionId}.jsonl`));
35606
+ renameSync3(filePath, join10(SEALED_DIR, `${sessionId}.jsonl`));
35489
35607
  } catch {
35490
35608
  }
35491
35609
  const convId = startData["conversation_id"] ?? void 0;
@@ -35515,7 +35633,7 @@ function sealOrphanFile(sessionId) {
35515
35633
  }
35516
35634
  }
35517
35635
  function sealOrphanedSessions() {
35518
- if (!existsSync10(ACTIVE_DIR)) return;
35636
+ if (!existsSync11(ACTIVE_DIR)) return;
35519
35637
  const activeIds = getActiveUseaiSessionIds();
35520
35638
  const mcpMap = readMcpMap();
35521
35639
  const mappedUseaiIds = new Set(Object.values(mcpMap));
@@ -35527,7 +35645,7 @@ function sealOrphanedSessions() {
35527
35645
  if (activeIds.has(sessionId)) continue;
35528
35646
  if (mappedUseaiIds.has(sessionId)) {
35529
35647
  try {
35530
- const mtime = statSync(join9(ACTIVE_DIR, file)).mtimeMs;
35648
+ const mtime = statSync(join10(ACTIVE_DIR, file)).mtimeMs;
35531
35649
  if (Date.now() - mtime < IDLE_TIMEOUT_MS) continue;
35532
35650
  } catch {
35533
35651
  continue;
@@ -35543,8 +35661,8 @@ function sealOrphanedSessions() {
35543
35661
  }
35544
35662
  }
35545
35663
  function isSessionAlreadySealed(session2) {
35546
- const activePath = join9(ACTIVE_DIR, `${session2.sessionId}.jsonl`);
35547
- return !existsSync10(activePath);
35664
+ const activePath = join10(ACTIVE_DIR, `${session2.sessionId}.jsonl`);
35665
+ return !existsSync11(activePath);
35548
35666
  }
35549
35667
  function sealRichness(s) {
35550
35668
  let score = 0;
@@ -35631,10 +35749,10 @@ function autoSealSession(active) {
35631
35749
  seal_signature: sealSignature,
35632
35750
  auto_sealed: true
35633
35751
  });
35634
- const activePath = join9(ACTIVE_DIR, `${session2.sessionId}.jsonl`);
35635
- const sealedPath = join9(SEALED_DIR, `${session2.sessionId}.jsonl`);
35752
+ const activePath = join10(ACTIVE_DIR, `${session2.sessionId}.jsonl`);
35753
+ const sealedPath = join10(SEALED_DIR, `${session2.sessionId}.jsonl`);
35636
35754
  try {
35637
- if (existsSync10(activePath)) {
35755
+ if (existsSync11(activePath)) {
35638
35756
  renameSync3(activePath, sealedPath);
35639
35757
  }
35640
35758
  } catch {
@@ -35762,12 +35880,12 @@ function sendJsonRpcResult(res, rpcId, text) {
35762
35880
  }));
35763
35881
  }
35764
35882
  function readChainMetadata(useaiSessionId) {
35765
- const activePath = join9(ACTIVE_DIR, `${useaiSessionId}.jsonl`);
35766
- const sealedPath = join9(SEALED_DIR, `${useaiSessionId}.jsonl`);
35767
- const chainPath = existsSync10(activePath) ? activePath : existsSync10(sealedPath) ? sealedPath : null;
35883
+ const activePath = join10(ACTIVE_DIR, `${useaiSessionId}.jsonl`);
35884
+ const sealedPath = join10(SEALED_DIR, `${useaiSessionId}.jsonl`);
35885
+ const chainPath = existsSync11(activePath) ? activePath : existsSync11(sealedPath) ? sealedPath : null;
35768
35886
  if (!chainPath) return null;
35769
35887
  try {
35770
- const firstLine = readFileSync6(chainPath, "utf-8").split("\n")[0];
35888
+ const firstLine = readFileSync7(chainPath, "utf-8").split("\n")[0];
35771
35889
  if (!firstLine) return null;
35772
35890
  const record2 = JSON.parse(firstLine);
35773
35891
  const d = record2.data;
@@ -35788,8 +35906,8 @@ function readChainMetadata(useaiSessionId) {
35788
35906
  function recoverStartSession(staleMcpSessionId, args, rpcId, res, req) {
35789
35907
  const map = readMcpMap();
35790
35908
  const prevSessionId = map[staleMcpSessionId];
35791
- const prevActivePath = prevSessionId ? join9(ACTIVE_DIR, `${prevSessionId}.jsonl`) : null;
35792
- if (prevActivePath && existsSync10(prevActivePath)) {
35909
+ const prevActivePath = prevSessionId ? join10(ACTIVE_DIR, `${prevSessionId}.jsonl`) : null;
35910
+ if (prevActivePath && existsSync11(prevActivePath)) {
35793
35911
  sealOrphanFile(prevSessionId);
35794
35912
  }
35795
35913
  const meta = prevSessionId ? readChainMetadata(prevSessionId) : null;
@@ -35815,7 +35933,7 @@ function recoverStartSession(staleMcpSessionId, args, rpcId, res, req) {
35815
35933
  if (privateTitle) chainData["private_title"] = privateTitle;
35816
35934
  if (model) chainData["model"] = model;
35817
35935
  const record2 = buildChainRecord("session_start", newSessionId, chainData, "GENESIS", daemonSigningKey);
35818
- const chainPath = join9(ACTIVE_DIR, `${newSessionId}.jsonl`);
35936
+ const chainPath = join10(ACTIVE_DIR, `${newSessionId}.jsonl`);
35819
35937
  appendFileSync2(chainPath, JSON.stringify(record2) + "\n");
35820
35938
  writeMcpMapping(staleMcpSessionId, newSessionId);
35821
35939
  sendJsonRpcResult(
@@ -35830,13 +35948,13 @@ function recoverHeartbeat(staleMcpSessionId, rpcId, res) {
35830
35948
  const map = readMcpMap();
35831
35949
  const useaiSessionId = map[staleMcpSessionId];
35832
35950
  if (!useaiSessionId) return false;
35833
- const chainPath = join9(ACTIVE_DIR, `${useaiSessionId}.jsonl`);
35834
- if (!existsSync10(chainPath)) {
35951
+ const chainPath = join10(ACTIVE_DIR, `${useaiSessionId}.jsonl`);
35952
+ if (!existsSync11(chainPath)) {
35835
35953
  sendJsonRpcResult(res, rpcId, "Session already ended (recovered).");
35836
35954
  return true;
35837
35955
  }
35838
35956
  try {
35839
- const content = readFileSync6(chainPath, "utf-8").trim();
35957
+ const content = readFileSync7(chainPath, "utf-8").trim();
35840
35958
  const lines = content.split("\n").filter(Boolean);
35841
35959
  if (lines.length === 0) return false;
35842
35960
  const firstRecord = JSON.parse(lines[0]);
@@ -35866,12 +35984,12 @@ function recoverEndSession(staleMcpSessionId, args, rpcId, res) {
35866
35984
  const map = readMcpMap();
35867
35985
  const useaiSessionId = map[staleMcpSessionId];
35868
35986
  if (!useaiSessionId) return false;
35869
- const activePath = join9(ACTIVE_DIR, `${useaiSessionId}.jsonl`);
35870
- const sealedPath = join9(SEALED_DIR, `${useaiSessionId}.jsonl`);
35871
- const chainPath = existsSync10(activePath) ? activePath : existsSync10(sealedPath) ? sealedPath : null;
35987
+ const activePath = join10(ACTIVE_DIR, `${useaiSessionId}.jsonl`);
35988
+ const sealedPath = join10(SEALED_DIR, `${useaiSessionId}.jsonl`);
35989
+ const chainPath = existsSync11(activePath) ? activePath : existsSync11(sealedPath) ? sealedPath : null;
35872
35990
  if (!chainPath) return false;
35873
35991
  const isAlreadySealed = chainPath === sealedPath;
35874
- const content = readFileSync6(chainPath, "utf-8").trim();
35992
+ const content = readFileSync7(chainPath, "utf-8").trim();
35875
35993
  if (!content) return false;
35876
35994
  const lines = content.split("\n").filter(Boolean);
35877
35995
  if (lines.length === 0) return false;
@@ -36210,7 +36328,7 @@ async function startDaemon(port) {
36210
36328
  const listenPort = port ?? DAEMON_PORT;
36211
36329
  ensureDir();
36212
36330
  try {
36213
- if (existsSync10(KEYSTORE_FILE)) {
36331
+ if (existsSync11(KEYSTORE_FILE)) {
36214
36332
  const ks = readJson(KEYSTORE_FILE, null);
36215
36333
  if (ks) daemonSigningKey = decryptKeystore(ks);
36216
36334
  }
@@ -36480,7 +36598,7 @@ async function startDaemon(port) {
36480
36598
  }
36481
36599
  }
36482
36600
  try {
36483
- if (existsSync10(DAEMON_PID_FILE)) {
36601
+ if (existsSync11(DAEMON_PID_FILE)) {
36484
36602
  unlinkSync5(DAEMON_PID_FILE);
36485
36603
  }
36486
36604
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devness/useai",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Track your AI-assisted development workflow. MCP server that records usage metrics across all your AI tools.",
5
5
  "keywords": [
6
6
  "mcp",