@wrongstack/core 0.305.0 → 0.305.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.
@@ -2,10 +2,10 @@
2
2
 
3
3
  // src/chronicle/project-server.ts
4
4
  import { randomBytes } from "node:crypto";
5
- import * as fs10 from "node:fs";
6
5
  import * as fsp4 from "node:fs/promises";
7
6
  import * as net from "node:net";
8
7
  import * as path15 from "node:path";
8
+ import { bindProjectEndpoint } from "@wrongstack/persistence";
9
9
 
10
10
  // src/utils/atomic-write.ts
11
11
  import {
@@ -2923,13 +2923,6 @@ import * as fs7 from "node:fs";
2923
2923
  import { createRequire } from "node:module";
2924
2924
  import * as path12 from "node:path";
2925
2925
 
2926
- // src/utils/socket-path.ts
2927
- import {
2928
- assertUnixSocketPathWithinLimit,
2929
- checkUnixSocketPath,
2930
- unixSocketPathLimit
2931
- } from "@wrongstack/persistence";
2932
-
2933
2926
  // src/chronicle/sqlite-query.ts
2934
2927
  var MAX_LIMIT = 1e4;
2935
2928
  function encodeCursor2(cursor) {
@@ -4766,7 +4759,6 @@ function normalizePathKey(value) {
4766
4759
 
4767
4760
  // src/chronicle/project-server-endpoint.ts
4768
4761
  import { createHash as createHash5 } from "node:crypto";
4769
- import * as fs9 from "node:fs";
4770
4762
  import * as os3 from "node:os";
4771
4763
  import * as path14 from "node:path";
4772
4764
 
@@ -4802,12 +4794,6 @@ function chronicleProjectServerEndpoint(projectDir) {
4802
4794
  function chronicleProjectServerMetadataPath(projectDir) {
4803
4795
  return path14.join(projectDir, "chronicle", CHRONICLE_PROJECT_SERVER_METADATA_FILE);
4804
4796
  }
4805
- function ensureChronicleProjectServerSocketDirectory(endpoint2) {
4806
- if (process.platform !== "win32") {
4807
- assertUnixSocketPathWithinLimit(endpoint2, "chronicle");
4808
- fs9.mkdirSync(path14.dirname(endpoint2), { recursive: true, mode: 448 });
4809
- }
4810
- }
4811
4797
 
4812
4798
  // src/chronicle/project-server.ts
4813
4799
  var DEFAULT_IDLE_MS = 5 * 6e4;
@@ -5264,7 +5250,6 @@ async function stop(_reason) {
5264
5250
  });
5265
5251
  await stopMemoryWatchdog();
5266
5252
  }
5267
- ensureChronicleProjectServerSocketDirectory(endpoint);
5268
5253
  var server = net.createServer((socket) => {
5269
5254
  if (stopping) {
5270
5255
  socket.destroy();
@@ -5284,42 +5269,28 @@ var server = net.createServer((socket) => {
5284
5269
  scheduleIdleStop();
5285
5270
  });
5286
5271
  });
5287
- var probingExistingEndpoint = false;
5288
- function listenForOwnership() {
5289
- server.listen(endpoint);
5290
- }
5291
- server.on("error", (error) => {
5292
- if (error.code === "EADDRINUSE" && process.platform === "win32") {
5272
+ void (async () => {
5273
+ const bind = await bindProjectEndpoint({ server, endpoint, service: "chronicle" });
5274
+ if (bind.outcome === "already-owned") {
5293
5275
  process.exitCode = 0;
5294
5276
  return;
5295
5277
  }
5296
- if (error.code === "EADDRINUSE" && !probingExistingEndpoint) {
5297
- probingExistingEndpoint = true;
5298
- const probe = net.createConnection(endpoint);
5299
- probe.once("connect", () => {
5300
- probe.destroy();
5301
- process.exitCode = 0;
5302
- });
5303
- probe.once("error", () => {
5304
- probe.destroy();
5305
- try {
5306
- fs10.rmSync(endpoint, { force: true });
5307
- } catch {
5308
- }
5309
- probingExistingEndpoint = false;
5310
- listenForOwnership();
5311
- });
5278
+ if (bind.outcome === "failed") {
5279
+ process.stderr.write(`chronicle project server failed: ${bind.error.message}
5280
+ `);
5281
+ process.exitCode = 1;
5312
5282
  return;
5313
5283
  }
5314
- process.exitCode = 1;
5315
- });
5316
- server.on("listening", () => {
5317
- if (process.platform !== "win32") {
5318
- try {
5319
- fs10.chmodSync(endpoint, 384);
5320
- } catch {
5321
- }
5284
+ if (bind.reclaimedStaleEndpoint) {
5285
+ process.stderr.write(`chronicle project server reclaimed stale endpoint ${endpoint}
5286
+ `);
5322
5287
  }
5288
+ server.on("error", (error) => {
5289
+ if (stopping) return;
5290
+ process.stderr.write(`chronicle project server error: ${error.message}
5291
+ `);
5292
+ process.exitCode = 1;
5293
+ });
5323
5294
  void writeMetadata().then(() => markMetadataWritten?.());
5324
5295
  void startChronicleFileObserver({
5325
5296
  projectRoot: parsed.projectRoot,
@@ -5337,8 +5308,7 @@ server.on("listening", () => {
5337
5308
  watcherLastError = error instanceof Error ? error.message : String(error);
5338
5309
  });
5339
5310
  scheduleIdleStop();
5340
- });
5311
+ })();
5341
5312
  process.once("SIGINT", () => void stop("SIGINT"));
5342
5313
  process.once("SIGTERM", () => void stop("SIGTERM"));
5343
- listenForOwnership();
5344
5314
  //# sourceMappingURL=project-server.js.map
@@ -34,6 +34,7 @@ export type { MailboxCredentialVerifier, RedactedMailboxCredential, } from './ma
34
34
  export { redactMailboxCredential } from './mailbox-credential-store.js';
35
35
  export { CREDENTIAL_VERIFY_COOLDOWN_MS, CREDENTIAL_VERIFY_MAX_FAILURES, CREDENTIAL_VERIFY_WINDOW_MS, CredentialVerifyThrottle, credentialVerifyThrottle, } from './mailbox-credential-throttle.js';
36
36
  export { MailboxEventEmitter } from './mailbox-events.js';
37
+ export { mailboxProjectServerEndpoint, mailboxProjectServerMetadataPath, } from './mailbox-project-server-endpoint.js';
37
38
  export { buildDownAlert, buildRecoveryAlert, type DownAlertInput, MAILBOX_HEALTH_DEFAULT_FAILURE_THRESHOLD, MAILBOX_HEALTH_DEFAULT_FROM, MAILBOX_HEALTH_DEFAULT_INTERVAL_MS, MAILBOX_HEALTH_DEFAULT_TIMEOUT_MS, type MailboxHealthEvent, MailboxHealthWatchdog, type MailboxHealthWatchdogOptions, type RecoveryAlertInput, validateWatchdogOptions, type WatchdogConfig, } from './mailbox-health.js';
38
39
  export { createMailboxHooks, type MailboxHooksOptions, } from './mailbox-hooks.js';
39
40
  export { authorizeMailboxBearerToken, authorizePersistedMailboxCredential, createMailboxHttpRouter, MAILBOX_HTTP_DEFAULT_MAX_AGE_MS, MAILBOX_HTTP_MAX_AGE_CEILING_MS, MAILBOX_HTTP_MAX_BODY_BYTES, MAILBOX_HTTP_RATE_LIMIT_PER_MINUTE, MAILBOX_HTTP_RATE_LIMIT_WINDOW_MS, type MailboxHttpAccessDecision, MailboxHttpRateLimiter, type MailboxHttpRouter, type MailboxHttpRouterOptions, } from './mailbox-http-router.js';
@@ -31042,6 +31042,8 @@ export {
31042
31042
  loadRoleKnowledgeManifest,
31043
31043
  loadSkillAffinity,
31044
31044
  mailboxIdentityBase,
31045
+ mailboxProjectServerEndpoint,
31046
+ mailboxProjectServerMetadataPath,
31045
31047
  mailboxSessionTag,
31046
31048
  makeAgentSubagentRunner,
31047
31049
  makeAskResultTool,
@@ -2,10 +2,10 @@
2
2
 
3
3
  // src/coordination/mailbox-project-server.ts
4
4
  import { randomBytes as randomBytes2 } from "node:crypto";
5
- import * as fs5 from "node:fs";
6
5
  import * as fsPromises from "node:fs/promises";
7
6
  import * as net from "node:net";
8
7
  import * as path7 from "node:path";
8
+ import { bindProjectEndpoint } from "@wrongstack/persistence";
9
9
 
10
10
  // src/kernel/events.ts
11
11
  var MAX_WILDCARDS = 500;
@@ -1173,17 +1173,9 @@ var MailboxEventEmitter = class {
1173
1173
 
1174
1174
  // src/coordination/mailbox-project-server-endpoint.ts
1175
1175
  import { createHash as createHash2 } from "node:crypto";
1176
- import * as fs2 from "node:fs";
1177
1176
  import * as os2 from "node:os";
1178
1177
  import * as path4 from "node:path";
1179
1178
 
1180
- // src/utils/socket-path.ts
1181
- import {
1182
- assertUnixSocketPathWithinLimit,
1183
- checkUnixSocketPath,
1184
- unixSocketPathLimit
1185
- } from "@wrongstack/persistence";
1186
-
1187
1179
  // src/coordination/mailbox-project-server-protocol.ts
1188
1180
  var MAILBOX_PROJECT_SERVER_PROTOCOL_VERSION = 4;
1189
1181
  var MAILBOX_PROJECT_SERVER_MAX_FRAME_CHARS = 16 * 1024 * 1024;
@@ -1317,16 +1309,10 @@ function mailboxProjectServerEndpoint(projectDir2) {
1317
1309
  function mailboxProjectServerMetadataPath(projectDir2) {
1318
1310
  return path4.join(path4.resolve(projectDir2), MAILBOX_PROJECT_SERVER_METADATA_FILE);
1319
1311
  }
1320
- function ensureMailboxProjectServerSocketDirectory(endpoint2) {
1321
- if (process.platform !== "win32") {
1322
- assertUnixSocketPathWithinLimit(endpoint2, "mailbox");
1323
- fs2.mkdirSync(path4.dirname(endpoint2), { recursive: true, mode: 448 });
1324
- }
1325
- }
1326
1312
 
1327
1313
  // src/coordination/sqlite-mailbox.ts
1328
1314
  import { randomUUID as randomUUID2 } from "node:crypto";
1329
- import * as fs4 from "node:fs";
1315
+ import * as fs3 from "node:fs";
1330
1316
  import * as path6 from "node:path";
1331
1317
 
1332
1318
  // src/coordination/global-mailbox-completion.ts
@@ -2218,7 +2204,7 @@ function credentialRotate(db, transaction, credentialId, options) {
2218
2204
  }
2219
2205
 
2220
2206
  // src/coordination/sqlite-mailbox-schema.ts
2221
- import * as fs3 from "node:fs";
2207
+ import * as fs2 from "node:fs";
2222
2208
  import { createRequire } from "node:module";
2223
2209
  import * as path5 from "node:path";
2224
2210
 
@@ -2473,7 +2459,7 @@ function migrateLegacyCredentials(ctx) {
2473
2459
  const legacyPath = path5.join(ctx.projectDir, CREDENTIAL_STORE_FILE);
2474
2460
  const credentials = [];
2475
2461
  try {
2476
- for (const line of fs3.readFileSync(legacyPath, "utf8").split(/\r?\n/u)) {
2462
+ for (const line of fs2.readFileSync(legacyPath, "utf8").split(/\r?\n/u)) {
2477
2463
  if (!line.trim()) continue;
2478
2464
  try {
2479
2465
  const credential = JSON.parse(line);
@@ -2526,7 +2512,7 @@ function migrateLegacyFiles(ctx) {
2526
2512
  function readLegacyMessages(projectDir2) {
2527
2513
  try {
2528
2514
  return parseMailboxFile(
2529
- fs3.readFileSync(path5.join(projectDir2, GLOBAL_MAILBOX_FILE), "utf8")
2515
+ fs2.readFileSync(path5.join(projectDir2, GLOBAL_MAILBOX_FILE), "utf8")
2530
2516
  );
2531
2517
  } catch (error) {
2532
2518
  if (error.code === "ENOENT") return [];
@@ -2535,7 +2521,7 @@ function readLegacyMessages(projectDir2) {
2535
2521
  }
2536
2522
  function readLegacyRegistry(filePath, parseEntry) {
2537
2523
  try {
2538
- const raw = JSON.parse(fs3.readFileSync(filePath, "utf8"));
2524
+ const raw = JSON.parse(fs2.readFileSync(filePath, "utf8"));
2539
2525
  const result = /* @__PURE__ */ new Map();
2540
2526
  for (const [id, value] of Object.entries(raw)) {
2541
2527
  const parsed = parseEntry(value);
@@ -2555,7 +2541,7 @@ var HEARTBEAT_TRACKING_TTL_MS = 30 * 6e4;
2555
2541
  var SqliteMailbox = class {
2556
2542
  constructor(projectDir2, events2, eventEmitter2) {
2557
2543
  this.projectDir = projectDir2;
2558
- fs4.mkdirSync(projectDir2, { recursive: true });
2544
+ fs3.mkdirSync(projectDir2, { recursive: true });
2559
2545
  this.databasePath = path6.join(projectDir2, SQLITE_MAILBOX_FILE);
2560
2546
  this.messagePath = this.databasePath;
2561
2547
  this.events = events2;
@@ -3451,7 +3437,6 @@ async function stop(_reason) {
3451
3437
  }
3452
3438
  await stopMemoryWatchdog();
3453
3439
  }
3454
- ensureMailboxProjectServerSocketDirectory(endpoint);
3455
3440
  var server = net.createServer((socket) => {
3456
3441
  if (stopping) {
3457
3442
  socket.destroy();
@@ -3481,42 +3466,28 @@ var leaseSweep = setInterval(() => {
3481
3466
  scheduleIdleStop();
3482
3467
  }, leaseSweepMs);
3483
3468
  leaseSweep.unref?.();
3484
- var probingExistingEndpoint = false;
3485
- function listenForOwnership() {
3486
- server.listen(endpoint);
3487
- }
3488
- server.on("error", (error) => {
3489
- if (error.code === "EADDRINUSE" && process.platform === "win32") {
3469
+ void (async () => {
3470
+ const bind = await bindProjectEndpoint({ server, endpoint, service: "mailbox" });
3471
+ if (bind.outcome === "already-owned") {
3490
3472
  process.exitCode = 0;
3491
3473
  return;
3492
3474
  }
3493
- if (error.code === "EADDRINUSE" && !probingExistingEndpoint) {
3494
- probingExistingEndpoint = true;
3495
- const probe = net.createConnection(endpoint);
3496
- probe.once("connect", () => {
3497
- probe.destroy();
3498
- process.exitCode = 0;
3499
- });
3500
- probe.once("error", () => {
3501
- probe.destroy();
3502
- try {
3503
- fs5.rmSync(endpoint, { force: true });
3504
- } catch {
3505
- }
3506
- probingExistingEndpoint = false;
3507
- listenForOwnership();
3508
- });
3475
+ if (bind.outcome === "failed") {
3476
+ process.stderr.write(`mailbox project server failed: ${bind.error.message}
3477
+ `);
3478
+ process.exitCode = 1;
3509
3479
  return;
3510
3480
  }
3511
- process.exitCode = 1;
3512
- });
3513
- server.on("listening", () => {
3514
- if (process.platform !== "win32") {
3515
- try {
3516
- fs5.chmodSync(endpoint, 384);
3517
- } catch {
3518
- }
3481
+ if (bind.reclaimedStaleEndpoint) {
3482
+ process.stderr.write(`mailbox project server reclaimed stale endpoint ${endpoint}
3483
+ `);
3519
3484
  }
3485
+ server.on("error", (error) => {
3486
+ if (stopping) return;
3487
+ process.stderr.write(`mailbox project server error: ${error.message}
3488
+ `);
3489
+ process.exitCode = 1;
3490
+ });
3520
3491
  try {
3521
3492
  mailbox = new SqliteMailbox(projectDir, events, eventEmitter);
3522
3493
  } catch {
@@ -3526,16 +3497,16 @@ server.on("listening", () => {
3526
3497
  return;
3527
3498
  }
3528
3499
  stopAutoCompact = mailbox.startAutoCompactTimer();
3529
- void writeMetadata().then(() => {
3500
+ try {
3501
+ await writeMetadata();
3530
3502
  markMetadataWritten?.();
3531
3503
  scheduleIdleStop();
3532
- }).catch(() => {
3504
+ } catch {
3533
3505
  void stop("metadata-write-failed").finally(() => {
3534
3506
  process.exitCode = 1;
3535
3507
  });
3536
- });
3537
- });
3538
- listenForOwnership();
3508
+ }
3509
+ })();
3539
3510
  for (const signal of ["SIGINT", "SIGTERM"]) {
3540
3511
  process.once(signal, () => {
3541
3512
  void stop(signal).finally(() => {
package/dist/index.js CHANGED
@@ -3524,7 +3524,27 @@ var THEME_PRESET_IDS = [
3524
3524
  "ayu-dark",
3525
3525
  "everforest",
3526
3526
  "night-owl",
3527
- "synthwave"
3527
+ "synthwave",
3528
+ "github-dark",
3529
+ "material-ocean",
3530
+ "nightfox",
3531
+ "oxocarbon",
3532
+ "catppuccin-macchiato",
3533
+ "catppuccin-frappe",
3534
+ "gruvbox-material",
3535
+ "tokyo-night-storm",
3536
+ "rose-pine-moon",
3537
+ "zenburn",
3538
+ "palenight",
3539
+ "horizon",
3540
+ "sonokai",
3541
+ "edge-dark",
3542
+ "moonfly",
3543
+ "melange",
3544
+ "poimandres",
3545
+ "vitesse-dark",
3546
+ "aura",
3547
+ "dark-plus"
3528
3548
  ];
3529
3549
 
3530
3550
  // src/types/default-config.ts
@@ -96346,6 +96366,8 @@ export {
96346
96366
  logHqAuthAudit,
96347
96367
  logicalCalendarTarget,
96348
96368
  mailboxIdentityBase,
96369
+ mailboxProjectServerEndpoint,
96370
+ mailboxProjectServerMetadataPath,
96349
96371
  mailboxSessionTag,
96350
96372
  makeAgentSubagentRunner,
96351
96373
  makeAskResultTool,
@@ -2,10 +2,10 @@
2
2
 
3
3
  // src/session-catalog/project-server.ts
4
4
  import { randomBytes as randomBytes2, randomUUID as randomUUID2 } from "node:crypto";
5
- import * as fs3 from "node:fs";
6
5
  import * as fsp from "node:fs/promises";
7
6
  import * as net from "node:net";
8
7
  import * as path3 from "node:path";
8
+ import { bindProjectEndpoint } from "@wrongstack/persistence";
9
9
 
10
10
  // src/security/file-permissions.ts
11
11
  import { chmod } from "node:fs/promises";
@@ -177,17 +177,9 @@ function useDaemonPerfDefaults() {
177
177
 
178
178
  // src/session-catalog/endpoint.ts
179
179
  import { createHash } from "node:crypto";
180
- import * as fs from "node:fs";
181
180
  import * as os from "node:os";
182
181
  import * as path from "node:path";
183
182
 
184
- // src/utils/socket-path.ts
185
- import {
186
- assertUnixSocketPathWithinLimit,
187
- checkUnixSocketPath,
188
- unixSocketPathLimit
189
- } from "@wrongstack/persistence";
190
-
191
183
  // src/session-catalog/protocol.ts
192
184
  var SESSION_CATALOG_PROTOCOL_VERSION = 1;
193
185
  var SESSION_CATALOG_MAX_FRAME_CHARS = 4 * 1024 * 1024;
@@ -218,15 +210,10 @@ function sessionCatalogProjectServerEndpoint(projectDir) {
218
210
  function sessionCatalogProjectServerMetadataPath(projectDir) {
219
211
  return path.join(projectDir, SESSION_CATALOG_METADATA_FILE);
220
212
  }
221
- function ensureSessionCatalogSocketDirectory(endpoint2) {
222
- if (process.platform === "win32") return;
223
- assertUnixSocketPathWithinLimit(endpoint2, "session-catalog");
224
- fs.mkdirSync(path.dirname(endpoint2), { recursive: true, mode: 448 });
225
- }
226
213
 
227
214
  // src/session-catalog/store.ts
228
215
  import { createHash as createHash2, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
229
- import * as fs2 from "node:fs";
216
+ import * as fs from "node:fs";
230
217
  import * as path2 from "node:path";
231
218
 
232
219
  // src/coordination/sqlite-mailbox-schema.ts
@@ -632,7 +619,7 @@ var SessionCatalogStore = class {
632
619
  constructor(projectDir) {
633
620
  this.projectDir = projectDir;
634
621
  this.sessionsDir = path2.join(projectDir, "sessions");
635
- fs2.mkdirSync(this.sessionsDir, { recursive: true, mode: 448 });
622
+ fs.mkdirSync(this.sessionsDir, { recursive: true, mode: 448 });
636
623
  this.databasePath = path2.join(this.sessionsDir, "catalog.sqlite");
637
624
  const Database = loadDatabaseSync();
638
625
  this.db = new Database(this.databasePath);
@@ -650,12 +637,12 @@ var SessionCatalogStore = class {
650
637
  this.db.close();
651
638
  const quarantine = `${this.databasePath}.corrupt-${Date.now()}`;
652
639
  try {
653
- fs2.renameSync(this.databasePath, quarantine);
640
+ fs.renameSync(this.databasePath, quarantine);
654
641
  } catch {
655
642
  }
656
643
  for (const suffix of ["-wal", "-shm"]) {
657
644
  try {
658
- fs2.renameSync(`${this.databasePath}${suffix}`, `${quarantine}${suffix}`);
645
+ fs.renameSync(`${this.databasePath}${suffix}`, `${quarantine}${suffix}`);
659
646
  } catch {
660
647
  }
661
648
  }
@@ -881,7 +868,7 @@ var SessionCatalogStore = class {
881
868
  if (this.maintenanceExists(targetSessionId))
882
869
  throw conflict(`Session ${targetSessionId} is under maintenance`);
883
870
  const catalog = this.db.prepare("SELECT 1 AS yes FROM sessions WHERE session_id=?").get(targetSessionId);
884
- if (!catalog && !fs2.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
871
+ if (!catalog && !fs.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
885
872
  throw new Error(`Session not found: ${targetSessionId}`);
886
873
  const reservationId = randomUUID();
887
874
  const now = Date.now();
@@ -1027,7 +1014,7 @@ var SessionCatalogStore = class {
1027
1014
  transcriptRelativePath = normalizedTranscript;
1028
1015
  summaryRelativePath = normalizedSummary;
1029
1016
  const transcript = this.containedPath(transcriptRelativePath);
1030
- const stat = fs2.existsSync(transcript) ? fs2.statSync(transcript) : void 0;
1017
+ const stat = fs.existsSync(transcript) ? fs.statSync(transcript) : void 0;
1031
1018
  const now = (/* @__PURE__ */ new Date()).toISOString();
1032
1019
  return this.transaction(() => {
1033
1020
  const prior = this.db.prepare("SELECT summary_revision FROM sessions WHERE session_id=?").get(summary.id);
@@ -1150,7 +1137,7 @@ var SessionCatalogStore = class {
1150
1137
  if (trimmed) summary.name = this.scrubber.scrub(trimmed).slice(0, 500);
1151
1138
  else delete summary.name;
1152
1139
  const summaryPath = this.containedPath(current.summaryRelativePath);
1153
- fs2.mkdirSync(path2.dirname(summaryPath), { recursive: true, mode: 448 });
1140
+ fs.mkdirSync(path2.dirname(summaryPath), { recursive: true, mode: 448 });
1154
1141
  await atomicWrite(summaryPath, `${JSON.stringify(summary)}
1155
1142
  `, { mode: 384 });
1156
1143
  try {
@@ -1213,13 +1200,13 @@ var SessionCatalogStore = class {
1213
1200
  path2.join(path2.dirname(transcript), path2.basename(sessionId))
1214
1201
  ];
1215
1202
  const trashRoot = path2.join(this.sessionsDir, "_trash", lease.leaseId);
1216
- fs2.mkdirSync(trashRoot, { recursive: true, mode: 448 });
1203
+ fs.mkdirSync(trashRoot, { recursive: true, mode: 448 });
1217
1204
  const moved = [];
1218
1205
  try {
1219
1206
  artifacts.forEach((artifact, index) => {
1220
- if (!fs2.existsSync(artifact)) return;
1207
+ if (!fs.existsSync(artifact)) return;
1221
1208
  const target = path2.join(trashRoot, `${index}-${path2.basename(artifact)}`);
1222
- fs2.renameSync(artifact, target);
1209
+ fs.renameSync(artifact, target);
1223
1210
  moved.push({ from: artifact, to: target });
1224
1211
  });
1225
1212
  this.transaction(() => {
@@ -1234,17 +1221,17 @@ var SessionCatalogStore = class {
1234
1221
  } catch (error) {
1235
1222
  for (const item of moved.reverse()) {
1236
1223
  try {
1237
- fs2.mkdirSync(path2.dirname(item.from), { recursive: true, mode: 448 });
1238
- fs2.renameSync(item.to, item.from);
1224
+ fs.mkdirSync(path2.dirname(item.from), { recursive: true, mode: 448 });
1225
+ fs.renameSync(item.to, item.from);
1239
1226
  } catch {
1240
1227
  }
1241
1228
  }
1242
1229
  throw error;
1243
1230
  }
1244
1231
  try {
1245
- fs2.rmSync(trashRoot, { recursive: true, force: true });
1232
+ fs.rmSync(trashRoot, { recursive: true, force: true });
1246
1233
  const trashParent = path2.dirname(trashRoot);
1247
- if (fs2.readdirSync(trashParent).length === 0) fs2.rmdirSync(trashParent);
1234
+ if (fs.readdirSync(trashParent).length === 0) fs.rmdirSync(trashParent);
1248
1235
  } catch {
1249
1236
  }
1250
1237
  }
@@ -1281,10 +1268,10 @@ var SessionCatalogStore = class {
1281
1268
  for (const id of ids) {
1282
1269
  try {
1283
1270
  const summaryFile = this.containedPath(`${id}.summary.json`);
1284
- const summary = fs2.existsSync(summaryFile) ? parseJson(fs2.readFileSync(summaryFile, "utf8")) : this.summarizeTranscript(id);
1271
+ const summary = fs.existsSync(summaryFile) ? parseJson(fs.readFileSync(summaryFile, "utf8")) : this.summarizeTranscript(id);
1285
1272
  if (!summary || summary.id !== id) throw new Error("summary identity mismatch");
1286
1273
  const transcript = this.containedPath(`${id}.jsonl`);
1287
- const stat = fs2.existsSync(transcript) ? fs2.statSync(transcript) : void 0;
1274
+ const stat = fs.existsSync(transcript) ? fs.statSync(transcript) : void 0;
1288
1275
  const now = (/* @__PURE__ */ new Date()).toISOString();
1289
1276
  this.db.prepare(
1290
1277
  "INSERT INTO sessions(session_id,transcript_relative_path,summary_relative_path,summary_json,transcript_size,transcript_mtime_ms,summary_revision,indexed_at,damaged) VALUES (?,?,?,?,?,?,?,?,0)"
@@ -1325,7 +1312,7 @@ var SessionCatalogStore = class {
1325
1312
  walkFiles(root, suffix) {
1326
1313
  const result = [];
1327
1314
  const visit = (dir) => {
1328
- for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
1315
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
1329
1316
  if (entry.isDirectory()) {
1330
1317
  if (entry.name !== "_cas" && entry.name !== "_trash") visit(path2.join(dir, entry.name));
1331
1318
  } else if (entry.isFile() && entry.name.endsWith(suffix))
@@ -1337,7 +1324,7 @@ var SessionCatalogStore = class {
1337
1324
  }
1338
1325
  summarizeTranscript(id) {
1339
1326
  const file = this.containedPath(`${id}.jsonl`);
1340
- const lines = fs2.readFileSync(file, "utf8").split(/\r?\n/);
1327
+ const lines = fs.readFileSync(file, "utf8").split(/\r?\n/);
1341
1328
  let start;
1342
1329
  let endedAt;
1343
1330
  let lastActivityAt;
@@ -1846,7 +1833,6 @@ async function stop(_reason) {
1846
1833
  if (process.platform !== "win32") await fsp.rm(endpoint, { force: true }).catch(() => void 0);
1847
1834
  await removeOwnedMetadata();
1848
1835
  }
1849
- ensureSessionCatalogSocketDirectory(endpoint);
1850
1836
  var server = net.createServer((socket) => {
1851
1837
  if (stopping) {
1852
1838
  socket.destroy();
@@ -1870,42 +1856,28 @@ var server = net.createServer((socket) => {
1870
1856
  scheduleIdleStop(disconnectedIdleMs);
1871
1857
  });
1872
1858
  });
1873
- var probing = false;
1874
- function listen() {
1875
- server.listen(endpoint);
1876
- }
1877
- server.on("error", (error) => {
1878
- if (error.code === "EADDRINUSE" && process.platform === "win32") {
1859
+ void (async () => {
1860
+ const bind = await bindProjectEndpoint({ server, endpoint, service: "session-catalog" });
1861
+ if (bind.outcome === "already-owned") {
1879
1862
  process.exitCode = 0;
1880
1863
  return;
1881
1864
  }
1882
- if (error.code === "EADDRINUSE" && !probing) {
1883
- probing = true;
1884
- const probe = net.createConnection(endpoint);
1885
- probe.once("connect", () => {
1886
- probe.destroy();
1887
- process.exitCode = 0;
1888
- });
1889
- probe.once("error", () => {
1890
- probe.destroy();
1891
- try {
1892
- fs3.rmSync(endpoint, { force: true });
1893
- } catch {
1894
- }
1895
- probing = false;
1896
- listen();
1897
- });
1865
+ if (bind.outcome === "failed") {
1866
+ process.stderr.write(`session-catalog project server failed: ${bind.error.message}
1867
+ `);
1868
+ process.exitCode = 1;
1898
1869
  return;
1899
1870
  }
1900
- process.exitCode = 1;
1901
- });
1902
- server.on("listening", () => {
1903
- if (process.platform !== "win32") {
1904
- try {
1905
- fs3.chmodSync(endpoint, 384);
1906
- } catch {
1907
- }
1871
+ if (bind.reclaimedStaleEndpoint) {
1872
+ process.stderr.write(`session-catalog project server reclaimed stale endpoint ${endpoint}
1873
+ `);
1908
1874
  }
1875
+ server.on("error", (error) => {
1876
+ if (stopping) return;
1877
+ process.stderr.write(`session-catalog project server error: ${error.message}
1878
+ `);
1879
+ process.exitCode = 1;
1880
+ });
1909
1881
  try {
1910
1882
  store = new SessionCatalogStore(parsed.projectDir);
1911
1883
  void writeMetadata().then(() => metadataReadyResolve?.()).catch(() => void stop("metadata write failed"));
@@ -1914,8 +1886,7 @@ server.on("listening", () => {
1914
1886
  return;
1915
1887
  }
1916
1888
  scheduleIdleStop();
1917
- });
1889
+ })();
1918
1890
  process.once("SIGINT", () => void stop("SIGINT"));
1919
1891
  process.once("SIGTERM", () => void stop("SIGTERM"));
1920
- listen();
1921
1892
  //# sourceMappingURL=project-server.js.map
@@ -5,10 +5,13 @@
5
5
  * the TUI runtime can all reference the same string union without
6
6
  * importing the TUI package (which would invert the dependency direction).
7
7
  *
8
- * Keep in lockstep with `THEME_OPTIONS` in `packages/tui/src/theme.ts`.
9
- * Adding a preset here is intentional it also requires updating the TUI
10
- * presets map AND the CLI `VALID_PRESETS` set in `tui-theme-adapter.ts`.
8
+ * This array is the CANONICAL list. The CLI `/theme` command and the boot
9
+ * theme adapter both derive their valid-id sets from it, so adding an entry
10
+ * here needs exactly ONE follow-up: a matching palette + `THEME_OPTIONS` row
11
+ * in `packages/tui/src/theme.ts`. Both are compile-enforced — `themePresets`
12
+ * is typed `Record<ThemePresetId, Theme>` (no cast) and the CLI's `THEME_META`
13
+ * is a total record — so a missing preset fails `tsc`, not the runtime.
11
14
  */
12
- export declare const THEME_PRESET_IDS: readonly ['catppuccin', 'tokyo-night', 'nord', 'cyberpunk', 'dracula', 'gruvbox-dark', 'solarized-dark', 'one-dark', 'monokai', 'rose-pine', 'kanagawa', 'ayu-dark', 'everforest', 'night-owl', 'synthwave'];
15
+ export declare const THEME_PRESET_IDS: readonly ['catppuccin', 'tokyo-night', 'nord', 'cyberpunk', 'dracula', 'gruvbox-dark', 'solarized-dark', 'one-dark', 'monokai', 'rose-pine', 'kanagawa', 'ayu-dark', 'everforest', 'night-owl', 'synthwave', 'github-dark', 'material-ocean', 'nightfox', 'oxocarbon', 'catppuccin-macchiato', 'catppuccin-frappe', 'gruvbox-material', 'tokyo-night-storm', 'rose-pine-moon', 'zenburn', 'palenight', 'horizon', 'sonokai', 'edge-dark', 'moonfly', 'melange', 'poimandres', 'vitesse-dark', 'aura', 'dark-plus'];
13
16
  export type ThemePresetId = (typeof THEME_PRESET_IDS)[number];
14
17
  //# sourceMappingURL=ui.d.ts.map
@@ -591,7 +591,27 @@ var THEME_PRESET_IDS = [
591
591
  "ayu-dark",
592
592
  "everforest",
593
593
  "night-owl",
594
- "synthwave"
594
+ "synthwave",
595
+ "github-dark",
596
+ "material-ocean",
597
+ "nightfox",
598
+ "oxocarbon",
599
+ "catppuccin-macchiato",
600
+ "catppuccin-frappe",
601
+ "gruvbox-material",
602
+ "tokyo-night-storm",
603
+ "rose-pine-moon",
604
+ "zenburn",
605
+ "palenight",
606
+ "horizon",
607
+ "sonokai",
608
+ "edge-dark",
609
+ "moonfly",
610
+ "melange",
611
+ "poimandres",
612
+ "vitesse-dark",
613
+ "aura",
614
+ "dark-plus"
595
615
  ];
596
616
 
597
617
  // src/types/session-markers.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/core",
3
- "version": "0.305.0",
3
+ "version": "0.305.1",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack core: kernel, types, defaults, and shared utilities for the WrongStack CLI agent.",
6
6
  "repository": {
@@ -177,8 +177,8 @@
177
177
  "wrongstackApiVersion": "0.1.10",
178
178
  "dependencies": {
179
179
  "zod": "4.4.3",
180
- "@wrongstack/persistence": "0.305.0",
181
- "@wrongstack/kanban": "0.305.0"
180
+ "@wrongstack/kanban": "0.305.1",
181
+ "@wrongstack/persistence": "0.305.1"
182
182
  },
183
183
  "devDependencies": {
184
184
  "@types/node": "^26.1.2",