perchai-cli 2.4.21 → 2.4.22

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/perch.mjs +53 -19
  2. package/package.json +1 -1
package/dist/perch.mjs CHANGED
@@ -75566,7 +75566,6 @@ var init_payroll = __esm({
75566
75566
  // lib/perchBusinessTools/index.ts
75567
75567
  var init_perchBusinessTools = __esm({
75568
75568
  "lib/perchBusinessTools/index.ts"() {
75569
- "use strict";
75570
75569
  init_generateAPAuditPacket();
75571
75570
  init_inventoryFolder();
75572
75571
  init_loadBusinessTables();
@@ -75900,6 +75899,7 @@ function isTurnAbortedError(error) {
75900
75899
  var TURN_STOPPED_BY_USER_MESSAGE;
75901
75900
  var init_turnAbort = __esm({
75902
75901
  "features/perchTerminal/runtime/turnAbort.ts"() {
75902
+ "use strict";
75903
75903
  TURN_STOPPED_BY_USER_MESSAGE = "Turn stopped by user.";
75904
75904
  }
75905
75905
  });
@@ -259813,7 +259813,7 @@ var require_websocket = __commonJS({
259813
259813
  var http2 = __require("http");
259814
259814
  var net = __require("net");
259815
259815
  var tls = __require("tls");
259816
- var { randomBytes, createHash: createHash4 } = __require("crypto");
259816
+ var { randomBytes, createHash: createHash5 } = __require("crypto");
259817
259817
  var { Duplex, Readable } = __require("stream");
259818
259818
  var { URL: URL2 } = __require("url");
259819
259819
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -260481,7 +260481,7 @@ var require_websocket = __commonJS({
260481
260481
  abortHandshake(websocket, socket, "Invalid Upgrade header");
260482
260482
  return;
260483
260483
  }
260484
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
260484
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
260485
260485
  if (res.headers["sec-websocket-accept"] !== digest) {
260486
260486
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
260487
260487
  return;
@@ -260850,7 +260850,7 @@ var require_websocket_server = __commonJS({
260850
260850
  var EventEmitter3 = __require("events");
260851
260851
  var http2 = __require("http");
260852
260852
  var { Duplex } = __require("stream");
260853
- var { createHash: createHash4 } = __require("crypto");
260853
+ var { createHash: createHash5 } = __require("crypto");
260854
260854
  var extension2 = require_extension();
260855
260855
  var PerMessageDeflate2 = require_permessage_deflate();
260856
260856
  var subprotocol2 = require_subprotocol();
@@ -261157,7 +261157,7 @@ var require_websocket_server = __commonJS({
261157
261157
  );
261158
261158
  }
261159
261159
  if (this._state > RUNNING) return abortHandshake(socket, 503);
261160
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
261160
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
261161
261161
  const headers = [
261162
261162
  "HTTP/1.1 101 Switching Protocols",
261163
261163
  "Upgrade: websocket",
@@ -283093,6 +283093,7 @@ __export(perch_cli_exports, {
283093
283093
  runPerchCli: () => runPerchCli
283094
283094
  });
283095
283095
  import fs14 from "node:fs";
283096
+ import { createHash as createHash4 } from "node:crypto";
283096
283097
  import os5 from "node:os";
283097
283098
  import path14 from "node:path";
283098
283099
  import readline from "node:readline/promises";
@@ -283123,7 +283124,8 @@ ${HELP_TEXT}`);
283123
283124
  const connection = await connectModelProxy({ appUrl: parsed.appUrl });
283124
283125
  try {
283125
283126
  const threadId = parsed.threadId?.trim() || "cli-default";
283126
- const persisted = await hydrateCliThreadState(threadId);
283127
+ const threadScopeKey = await resolveCliThreadScopeKey(connection);
283128
+ const persisted = await hydrateCliThreadState(threadId, threadScopeKey);
283127
283129
  const hostedContext = await fetchCliHostedContext(connection, {
283128
283130
  query: parsed.prompt,
283129
283131
  threadId
@@ -283165,6 +283167,7 @@ ${HELP_TEXT}`);
283165
283167
  });
283166
283168
  await persistCliThreadState({
283167
283169
  threadId: result3.threadId,
283170
+ threadScopeKey,
283168
283171
  recentMessages: nextRecentMessages,
283169
283172
  contextSnapshot: result3.contextSnapshot ?? persisted?.contextSnapshot ?? null
283170
283173
  });
@@ -283439,14 +283442,15 @@ async function runReadlineInteractivePerchCli(writer, deps, options) {
283439
283442
  terminal: true
283440
283443
  });
283441
283444
  const state = createInteractiveCliState(options);
283442
- await hydrateInteractiveCliState(state);
283443
283445
  const connectModelProxy = deps.connectModelProxy ?? connectCliModelProxy;
283444
283446
  let connection = await connectModelProxy({ appUrl: state.appUrl });
283445
283447
  if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
283448
+ await syncInteractiveCliThreadScope(state, connection, { force: true });
283446
283449
  const reconnect = async () => {
283447
283450
  connection.restore();
283448
283451
  connection = await connectModelProxy({ appUrl: state.appUrl });
283449
283452
  if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
283453
+ await syncInteractiveCliThreadScope(state, connection);
283450
283454
  };
283451
283455
  writer.stdout(renderInteractiveStartup(state, connection));
283452
283456
  try {
@@ -283532,14 +283536,15 @@ async function runInkInteractivePerchCli(writer, deps, options) {
283532
283536
  init_build2().then(() => build_exports)
283533
283537
  ]);
283534
283538
  const state = createInteractiveCliState(options);
283535
- await hydrateInteractiveCliState(state);
283536
283539
  const connectModelProxy = deps.connectModelProxy ?? connectCliModelProxy;
283537
283540
  let connection = await connectModelProxy({ appUrl: state.appUrl });
283538
283541
  if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
283542
+ await syncInteractiveCliThreadScope(state, connection, { force: true });
283539
283543
  const reconnect = async () => {
283540
283544
  connection.restore();
283541
283545
  connection = await connectModelProxy({ appUrl: state.appUrl });
283542
283546
  if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
283547
+ await syncInteractiveCliThreadScope(state, connection);
283543
283548
  };
283544
283549
  const runTurn = deps.runCliTurn ?? runPerchCliTurn;
283545
283550
  const instance = Ink2.render(
@@ -284340,7 +284345,7 @@ async function runInteractiveSlashCommand(input) {
284340
284345
  input.state.contextSnapshot = null;
284341
284346
  input.state.persistedThreadUpdatedAt = null;
284342
284347
  clearThreadSession(input.state.threadId);
284343
- await deleteCliThreadState(input.state.threadId);
284348
+ await deleteCliThreadState(input.state.threadId, input.state.threadScopeKey);
284344
284349
  writeModeLine(input.writer, "memory", "cleared");
284345
284350
  return "continue";
284346
284351
  case "login":
@@ -284539,6 +284544,7 @@ function createInteractiveCliState(options) {
284539
284544
  personaId: options.personaId ?? "saffron",
284540
284545
  permissionMode: options.permissionMode ?? "default",
284541
284546
  threadId: options.threadId?.trim() || "cli-default",
284547
+ threadScopeKey: null,
284542
284548
  desktopConnected: options.desktopConnected ?? false,
284543
284549
  cliLocalTools: options.cliLocalTools ?? true,
284544
284550
  appUrl: resolveCliAppUrl(options.appUrl ?? null, null),
@@ -284548,14 +284554,25 @@ function createInteractiveCliState(options) {
284548
284554
  };
284549
284555
  }
284550
284556
  async function hydrateInteractiveCliState(state) {
284551
- const persisted = await hydrateCliThreadState(state.threadId);
284557
+ const persisted = await hydrateCliThreadState(state.threadId, state.threadScopeKey);
284552
284558
  if (!persisted) return;
284553
284559
  state.recentMessages = persisted.recentMessages;
284554
284560
  state.contextSnapshot = persisted.contextSnapshot;
284555
284561
  state.persistedThreadUpdatedAt = persisted.updatedAt;
284556
284562
  }
284557
- async function hydrateCliThreadState(threadId) {
284558
- const persisted = await readCliThreadState(threadId);
284563
+ async function syncInteractiveCliThreadScope(state, connection, options = {}) {
284564
+ const nextScopeKey = await resolveCliThreadScopeKey(connection);
284565
+ if (!options.force && state.threadScopeKey === nextScopeKey) return;
284566
+ state.threadScopeKey = nextScopeKey;
284567
+ state.recentMessages = [];
284568
+ state.contextSnapshot = null;
284569
+ state.persistedThreadUpdatedAt = null;
284570
+ clearThreadSession(state.threadId);
284571
+ await hydrateInteractiveCliState(state);
284572
+ }
284573
+ async function hydrateCliThreadState(threadId, threadScopeKey) {
284574
+ const persisted = await readCliThreadState(threadId, threadScopeKey);
284575
+ clearThreadSession(threadId);
284559
284576
  if (!persisted) return null;
284560
284577
  if (persisted.threadSession) {
284561
284578
  await saveThreadSession(persisted.threadSession);
@@ -284565,6 +284582,7 @@ async function hydrateCliThreadState(threadId) {
284565
284582
  async function persistInteractiveCliState(state) {
284566
284583
  await persistCliThreadState({
284567
284584
  threadId: state.threadId,
284585
+ threadScopeKey: state.threadScopeKey,
284568
284586
  recentMessages: state.recentMessages,
284569
284587
  contextSnapshot: state.contextSnapshot
284570
284588
  });
@@ -284580,13 +284598,13 @@ async function persistCliThreadState(input) {
284580
284598
  threadSession,
284581
284599
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
284582
284600
  };
284583
- const filePath = cliThreadStatePath(input.threadId);
284601
+ const filePath = cliThreadStatePath(input.threadId, input.threadScopeKey);
284584
284602
  await fs14.promises.mkdir(path14.dirname(filePath), { recursive: true, mode: 448 });
284585
284603
  await fs14.promises.writeFile(filePath, JSON.stringify(payload, null, 2), { mode: 384 });
284586
284604
  }
284587
- async function readCliThreadState(threadId) {
284605
+ async function readCliThreadState(threadId, threadScopeKey) {
284588
284606
  try {
284589
- const raw = await fs14.promises.readFile(cliThreadStatePath(threadId), "utf8");
284607
+ const raw = await fs14.promises.readFile(cliThreadStatePath(threadId, threadScopeKey), "utf8");
284590
284608
  const parsed = JSON.parse(raw);
284591
284609
  if (parsed.version !== 1 || parsed.threadId !== threadId) return null;
284592
284610
  return {
@@ -284601,12 +284619,28 @@ async function readCliThreadState(threadId) {
284601
284619
  return null;
284602
284620
  }
284603
284621
  }
284604
- async function deleteCliThreadState(threadId) {
284605
- await fs14.promises.rm(cliThreadStatePath(threadId), { force: true }).catch(() => void 0);
284622
+ async function deleteCliThreadState(threadId, threadScopeKey) {
284623
+ await fs14.promises.rm(cliThreadStatePath(threadId, threadScopeKey), { force: true }).catch(() => void 0);
284606
284624
  }
284607
- function cliThreadStatePath(threadId) {
284625
+ function cliThreadStatePath(threadId, threadScopeKey) {
284608
284626
  const base = process.env.PERCH_CLI_STATE_DIR?.trim() || path14.join(os5.homedir(), ".perch", "threads");
284609
- return path14.join(base, `${safeCliThreadId(threadId)}.json`);
284627
+ return path14.join(base, safeCliThreadScopeKey(threadScopeKey), `${safeCliThreadId(threadId)}.json`);
284628
+ }
284629
+ async function resolveCliThreadScopeKey(connection) {
284630
+ const session = await readStoredCliAuthSession().catch(() => null);
284631
+ const sessionUsable = isStoredCliAuthSessionUsable(session);
284632
+ const authenticated = Boolean(connection?.authenticated || sessionUsable);
284633
+ const appUrl = connection?.appUrl ?? session?.appUrl ?? "local";
284634
+ const userId = connection?.userId ?? session?.userId ?? null;
284635
+ const email = connection?.email ?? session?.email ?? null;
284636
+ const fallbackToken = authenticated && !userId && !email ? session?.accessToken ?? null : null;
284637
+ const authKey = authenticated ? `user:${userId ?? ""}|email:${email ?? ""}|token:${fallbackToken ? createHash4("sha256").update(fallbackToken).digest("hex").slice(0, 20) : ""}` : "anonymous";
284638
+ const raw = `app:${appUrl}|${authKey}`;
284639
+ const prefix = authenticated ? "user" : "anon";
284640
+ return `${prefix}-${createHash4("sha256").update(raw).digest("hex").slice(0, 20)}`;
284641
+ }
284642
+ function safeCliThreadScopeKey(threadScopeKey) {
284643
+ return (threadScopeKey?.trim() || "anon-local").replace(/[^a-zA-Z0-9_.-]+/g, "_").slice(0, 96);
284610
284644
  }
284611
284645
  function safeCliThreadId(threadId) {
284612
284646
  return threadId.trim().replace(/[^a-zA-Z0-9_.-]+/g, "_").slice(0, 96) || "cli-default";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "perchai-cli",
3
- "version": "2.4.21",
3
+ "version": "2.4.22",
4
4
  "description": "Perch AI command-line interface",
5
5
  "bin": {
6
6
  "perch": "bin/perch"