@wrongstack/core 0.303.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.
Files changed (76) hide show
  1. package/dist/chronicle/project-server.js +18 -48
  2. package/dist/coordination/agents/index.js +530 -130
  3. package/dist/coordination/agents/project-agent-consolidation.d.ts +5 -0
  4. package/dist/coordination/agents/project-agent-directive-outcome.d.ts +57 -0
  5. package/dist/coordination/agents/project-agent-identity.d.ts +26 -12
  6. package/dist/coordination/agents/project-agent-learning-policy.d.ts +22 -1
  7. package/dist/coordination/agents/project-agent-learning-structured.d.ts +46 -1
  8. package/dist/coordination/agents/project-agent-quarantine.d.ts +63 -0
  9. package/dist/coordination/agents/project-agent-skill-layer.d.ts +55 -10
  10. package/dist/coordination/agents/types.d.ts +10 -2
  11. package/dist/coordination/director-prompts.d.ts +19 -6
  12. package/dist/coordination/director-tools.d.ts +2 -2
  13. package/dist/coordination/fleet.d.ts +0 -6
  14. package/dist/coordination/index.d.ts +2 -1
  15. package/dist/coordination/index.js +1581 -955
  16. package/dist/coordination/mailbox-project-server.js +28 -57
  17. package/dist/core/agent-types.d.ts +4 -2
  18. package/dist/core/agent.d.ts +1 -0
  19. package/dist/core/context.d.ts +15 -0
  20. package/dist/core/conversation-state.d.ts +14 -0
  21. package/dist/core/fallback-profile-manager.d.ts +70 -2
  22. package/dist/core/index.js +308 -108
  23. package/dist/core/system-prompt-blocks.d.ts +1 -1
  24. package/dist/core/system-prompt-builder.d.ts +13 -1
  25. package/dist/core/system-prompt-glossary.d.ts +73 -0
  26. package/dist/core/system-prompt-memory-skills.d.ts +2 -2
  27. package/dist/defaults/index.js +910 -693
  28. package/dist/execution/council-orchestrator.d.ts +3 -13
  29. package/dist/execution/index.js +211 -75
  30. package/dist/execution/one-shot-llm.d.ts +5 -0
  31. package/dist/hq/index.js +17 -7
  32. package/dist/hq/protocol/kanban.d.ts +21 -0
  33. package/dist/hq/protocol.js +5 -1
  34. package/dist/hq/redaction.d.ts +14 -0
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.js +3505 -2539
  37. package/dist/infrastructure/index.js +247 -122
  38. package/dist/plugin/index.js +101 -3
  39. package/dist/registry/index.js +11 -0
  40. package/dist/registry/tool-registry.d.ts +8 -0
  41. package/dist/replay/hash.d.ts +9 -0
  42. package/dist/replay/index.js +14 -4
  43. package/dist/replay/replay-provider-runner.d.ts +31 -1
  44. package/dist/security/index.js +25 -20
  45. package/dist/security/secret-vault.d.ts +2 -0
  46. package/dist/session-catalog/index.js +62 -8
  47. package/dist/session-catalog/project-server.js +109 -78
  48. package/dist/session-catalog/protocol.d.ts +11 -4
  49. package/dist/session-catalog/store.d.ts +2 -2
  50. package/dist/storage/index.js +224 -67
  51. package/dist/storage/memory-consolidator.d.ts +4 -2
  52. package/dist/storage/session-resume-validation.d.ts +24 -0
  53. package/dist/storage/session-store/directory-scan.d.ts +5 -1
  54. package/dist/storage/session-store/fork-session.d.ts +13 -1
  55. package/dist/storage/session-store/load-cache.d.ts +11 -0
  56. package/dist/storage/session-store/prune-helpers.d.ts +5 -0
  57. package/dist/storage/session-store.d.ts +18 -0
  58. package/dist/tools/index.js +174 -74
  59. package/dist/types/config/mcp-features.d.ts +31 -1
  60. package/dist/types/config/root.d.ts +12 -0
  61. package/dist/types/config/tools.d.ts +22 -0
  62. package/dist/types/config/ui.d.ts +7 -4
  63. package/dist/types/default-config.d.ts +1 -0
  64. package/dist/types/index.js +24 -1
  65. package/dist/types/session.d.ts +9 -1
  66. package/dist/utils/index.d.ts +1 -0
  67. package/dist/utils/index.js +214 -76
  68. package/dist/utils/project-state-guard.d.ts +21 -0
  69. package/dist/utils/session-scoped-path.d.ts +17 -0
  70. package/dist/utils/todos-format.d.ts +20 -0
  71. package/instructions/leader-after-task.md +3 -4
  72. package/instructions/system-lite.md +10 -13
  73. package/instructions/system-pro.md +18 -25
  74. package/instructions/system.md +18 -23
  75. package/package.json +3 -3
  76. package/skills/wrongstack-kanban/SKILL.md +95 -124
@@ -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
@@ -567,6 +554,22 @@ function isPidAlive(pid) {
567
554
  }
568
555
  }
569
556
 
557
+ // src/utils/session-scoped-path.ts
558
+ var SESSION_SIDECAR_JSONL_SUFFIXES = [
559
+ ".replay.jsonl",
560
+ ".audit.jsonl",
561
+ ".annotations.jsonl"
562
+ ];
563
+ var RESERVED_SESSION_JSONL_NAMES = /* @__PURE__ */ new Set([
564
+ "_index.jsonl",
565
+ "_mailbox.jsonl"
566
+ ]);
567
+ function isSessionTranscriptFileName(name) {
568
+ if (!name.endsWith(".jsonl")) return false;
569
+ if (RESERVED_SESSION_JSONL_NAMES.has(name)) return false;
570
+ return !SESSION_SIDECAR_JSONL_SUFFIXES.some((suffix) => name.endsWith(suffix));
571
+ }
572
+
570
573
  // src/session-catalog/store.ts
571
574
  var SCHEMA_VERSION = 1;
572
575
  var MAX_LEASE_MS = 12e4;
@@ -616,7 +619,7 @@ var SessionCatalogStore = class {
616
619
  constructor(projectDir) {
617
620
  this.projectDir = projectDir;
618
621
  this.sessionsDir = path2.join(projectDir, "sessions");
619
- fs2.mkdirSync(this.sessionsDir, { recursive: true, mode: 448 });
622
+ fs.mkdirSync(this.sessionsDir, { recursive: true, mode: 448 });
620
623
  this.databasePath = path2.join(this.sessionsDir, "catalog.sqlite");
621
624
  const Database = loadDatabaseSync();
622
625
  this.db = new Database(this.databasePath);
@@ -634,12 +637,12 @@ var SessionCatalogStore = class {
634
637
  this.db.close();
635
638
  const quarantine = `${this.databasePath}.corrupt-${Date.now()}`;
636
639
  try {
637
- fs2.renameSync(this.databasePath, quarantine);
640
+ fs.renameSync(this.databasePath, quarantine);
638
641
  } catch {
639
642
  }
640
643
  for (const suffix of ["-wal", "-shm"]) {
641
644
  try {
642
- fs2.renameSync(`${this.databasePath}${suffix}`, `${quarantine}${suffix}`);
645
+ fs.renameSync(`${this.databasePath}${suffix}`, `${quarantine}${suffix}`);
643
646
  } catch {
644
647
  }
645
648
  }
@@ -865,7 +868,7 @@ var SessionCatalogStore = class {
865
868
  if (this.maintenanceExists(targetSessionId))
866
869
  throw conflict(`Session ${targetSessionId} is under maintenance`);
867
870
  const catalog = this.db.prepare("SELECT 1 AS yes FROM sessions WHERE session_id=?").get(targetSessionId);
868
- if (!catalog && !fs2.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
871
+ if (!catalog && !fs.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
869
872
  throw new Error(`Session not found: ${targetSessionId}`);
870
873
  const reservationId = randomUUID();
871
874
  const now = Date.now();
@@ -1011,7 +1014,7 @@ var SessionCatalogStore = class {
1011
1014
  transcriptRelativePath = normalizedTranscript;
1012
1015
  summaryRelativePath = normalizedSummary;
1013
1016
  const transcript = this.containedPath(transcriptRelativePath);
1014
- const stat = fs2.existsSync(transcript) ? fs2.statSync(transcript) : void 0;
1017
+ const stat = fs.existsSync(transcript) ? fs.statSync(transcript) : void 0;
1015
1018
  const now = (/* @__PURE__ */ new Date()).toISOString();
1016
1019
  return this.transaction(() => {
1017
1020
  const prior = this.db.prepare("SELECT summary_revision FROM sessions WHERE session_id=?").get(summary.id);
@@ -1052,13 +1055,51 @@ var SessionCatalogStore = class {
1052
1055
  damaged: row.damaged !== 0
1053
1056
  };
1054
1057
  }
1055
- listCatalog(limit = 100, search) {
1056
- const bounded = Math.min(MAX_PAGE, Math.max(1, Math.floor(limit)));
1057
- const rows = search?.trim() ? this.db.prepare(
1058
- "SELECT * FROM sessions WHERE session_id LIKE ? OR json_extract(summary_json,'$.title') LIKE ? OR json_extract(summary_json,'$.name') LIKE ? ORDER BY COALESCE(json_extract(summary_json,'$.lastActivityAt'),json_extract(summary_json,'$.startedAt')) DESC LIMIT ?"
1059
- ).all(`%${search.trim()}%`, `%${search.trim()}%`, `%${search.trim()}%`, bounded) : this.db.prepare(
1060
- "SELECT * FROM sessions ORDER BY COALESCE(json_extract(summary_json,'$.lastActivityAt'),json_extract(summary_json,'$.startedAt')) DESC LIMIT ?"
1061
- ).all(bounded);
1058
+ listCatalog(criteria = {}) {
1059
+ const requestedLimit = criteria.limit ?? 100;
1060
+ if (!Number.isFinite(requestedLimit)) throw new TypeError("Invalid session catalog limit");
1061
+ const bounded = Math.min(MAX_PAGE, Math.max(1, Math.floor(requestedLimit)));
1062
+ const clauses = [];
1063
+ const values = [];
1064
+ const jsonText = (field) => `CASE WHEN json_valid(summary_json) THEN json_extract(summary_json,'$.${field}') END`;
1065
+ const literalLike = (value) => `%${value.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_")}%`;
1066
+ const search = criteria.search?.trim();
1067
+ if (search) {
1068
+ const pattern = literalLike(search);
1069
+ clauses.push(
1070
+ `(session_id LIKE ? ESCAPE '\\' OR ${jsonText("title")} LIKE ? ESCAPE '\\' OR ${jsonText("name")} LIKE ? ESCAPE '\\')`
1071
+ );
1072
+ values.push(pattern, pattern, pattern);
1073
+ }
1074
+ if (criteria.since) {
1075
+ clauses.push(`${jsonText("startedAt")}>=?`);
1076
+ values.push(criteria.since);
1077
+ }
1078
+ if (criteria.until) {
1079
+ clauses.push(`${jsonText("startedAt")}<=?`);
1080
+ values.push(criteria.until);
1081
+ }
1082
+ if (criteria.provider) {
1083
+ clauses.push(`${jsonText("provider")}=?`);
1084
+ values.push(criteria.provider);
1085
+ }
1086
+ if (criteria.model) {
1087
+ clauses.push(`${jsonText("model")}=?`);
1088
+ values.push(criteria.model);
1089
+ }
1090
+ if (criteria.minTokens !== void 0) {
1091
+ if (!Number.isFinite(criteria.minTokens)) throw new TypeError("Invalid minimum token count");
1092
+ clauses.push(`CAST(COALESCE(${jsonText("tokenTotal")},0) AS REAL)>=?`);
1093
+ values.push(criteria.minTokens);
1094
+ }
1095
+ if (criteria.titleContains) {
1096
+ clauses.push(`${jsonText("title")} LIKE ? ESCAPE '\\'`);
1097
+ values.push(literalLike(criteria.titleContains.toLocaleLowerCase()));
1098
+ }
1099
+ const where = clauses.length > 0 ? ` WHERE ${clauses.join(" AND ")}` : "";
1100
+ const rows = this.db.prepare(
1101
+ `SELECT * FROM sessions${where} ORDER BY COALESCE(${jsonText("lastActivityAt")},${jsonText("endedAt")},${jsonText("startedAt")}) DESC,${jsonText("startedAt")} DESC,session_id ASC LIMIT ?`
1102
+ ).all(...values, bounded);
1062
1103
  return rows.map((row) => this.catalogRecord(row));
1063
1104
  }
1064
1105
  getSummary(sessionId) {
@@ -1096,7 +1137,7 @@ var SessionCatalogStore = class {
1096
1137
  if (trimmed) summary.name = this.scrubber.scrub(trimmed).slice(0, 500);
1097
1138
  else delete summary.name;
1098
1139
  const summaryPath = this.containedPath(current.summaryRelativePath);
1099
- fs2.mkdirSync(path2.dirname(summaryPath), { recursive: true, mode: 448 });
1140
+ fs.mkdirSync(path2.dirname(summaryPath), { recursive: true, mode: 448 });
1100
1141
  await atomicWrite(summaryPath, `${JSON.stringify(summary)}
1101
1142
  `, { mode: 384 });
1102
1143
  try {
@@ -1159,13 +1200,13 @@ var SessionCatalogStore = class {
1159
1200
  path2.join(path2.dirname(transcript), path2.basename(sessionId))
1160
1201
  ];
1161
1202
  const trashRoot = path2.join(this.sessionsDir, "_trash", lease.leaseId);
1162
- fs2.mkdirSync(trashRoot, { recursive: true, mode: 448 });
1203
+ fs.mkdirSync(trashRoot, { recursive: true, mode: 448 });
1163
1204
  const moved = [];
1164
1205
  try {
1165
1206
  artifacts.forEach((artifact, index) => {
1166
- if (!fs2.existsSync(artifact)) return;
1207
+ if (!fs.existsSync(artifact)) return;
1167
1208
  const target = path2.join(trashRoot, `${index}-${path2.basename(artifact)}`);
1168
- fs2.renameSync(artifact, target);
1209
+ fs.renameSync(artifact, target);
1169
1210
  moved.push({ from: artifact, to: target });
1170
1211
  });
1171
1212
  this.transaction(() => {
@@ -1180,17 +1221,17 @@ var SessionCatalogStore = class {
1180
1221
  } catch (error) {
1181
1222
  for (const item of moved.reverse()) {
1182
1223
  try {
1183
- fs2.mkdirSync(path2.dirname(item.from), { recursive: true, mode: 448 });
1184
- fs2.renameSync(item.to, item.from);
1224
+ fs.mkdirSync(path2.dirname(item.from), { recursive: true, mode: 448 });
1225
+ fs.renameSync(item.to, item.from);
1185
1226
  } catch {
1186
1227
  }
1187
1228
  }
1188
1229
  throw error;
1189
1230
  }
1190
1231
  try {
1191
- fs2.rmSync(trashRoot, { recursive: true, force: true });
1232
+ fs.rmSync(trashRoot, { recursive: true, force: true });
1192
1233
  const trashParent = path2.dirname(trashRoot);
1193
- if (fs2.readdirSync(trashParent).length === 0) fs2.rmdirSync(trashParent);
1234
+ if (fs.readdirSync(trashParent).length === 0) fs.rmdirSync(trashParent);
1194
1235
  } catch {
1195
1236
  }
1196
1237
  }
@@ -1213,7 +1254,7 @@ var SessionCatalogStore = class {
1213
1254
  rebuildCatalog() {
1214
1255
  const summaries = this.walkFiles(this.sessionsDir, ".summary.json");
1215
1256
  const transcripts = this.walkFiles(this.sessionsDir, ".jsonl").filter(
1216
- (file) => !file.endsWith("_index.jsonl")
1257
+ (file) => isSessionTranscriptFileName(path2.basename(file))
1217
1258
  );
1218
1259
  const ids = /* @__PURE__ */ new Set();
1219
1260
  for (const file of [...summaries, ...transcripts]) {
@@ -1227,10 +1268,10 @@ var SessionCatalogStore = class {
1227
1268
  for (const id of ids) {
1228
1269
  try {
1229
1270
  const summaryFile = this.containedPath(`${id}.summary.json`);
1230
- 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);
1231
1272
  if (!summary || summary.id !== id) throw new Error("summary identity mismatch");
1232
1273
  const transcript = this.containedPath(`${id}.jsonl`);
1233
- const stat = fs2.existsSync(transcript) ? fs2.statSync(transcript) : void 0;
1274
+ const stat = fs.existsSync(transcript) ? fs.statSync(transcript) : void 0;
1234
1275
  const now = (/* @__PURE__ */ new Date()).toISOString();
1235
1276
  this.db.prepare(
1236
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)"
@@ -1271,7 +1312,7 @@ var SessionCatalogStore = class {
1271
1312
  walkFiles(root, suffix) {
1272
1313
  const result = [];
1273
1314
  const visit = (dir) => {
1274
- for (const entry of fs2.readdirSync(dir, { withFileTypes: true })) {
1315
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
1275
1316
  if (entry.isDirectory()) {
1276
1317
  if (entry.name !== "_cas" && entry.name !== "_trash") visit(path2.join(dir, entry.name));
1277
1318
  } else if (entry.isFile() && entry.name.endsWith(suffix))
@@ -1283,7 +1324,7 @@ var SessionCatalogStore = class {
1283
1324
  }
1284
1325
  summarizeTranscript(id) {
1285
1326
  const file = this.containedPath(`${id}.jsonl`);
1286
- const lines = fs2.readFileSync(file, "utf8").split(/\r?\n/);
1327
+ const lines = fs.readFileSync(file, "utf8").split(/\r?\n/);
1287
1328
  let start;
1288
1329
  let endedAt;
1289
1330
  let lastActivityAt;
@@ -1422,7 +1463,16 @@ var OPERATION_KEYS = {
1422
1463
  subscribe: ["cursor"],
1423
1464
  unsubscribe: [],
1424
1465
  upsert_summary: ["summary", "transcriptRelativePath", "summaryRelativePath"],
1425
- list_catalog: ["limit", "search"],
1466
+ list_catalog: [
1467
+ "limit",
1468
+ "search",
1469
+ "since",
1470
+ "until",
1471
+ "provider",
1472
+ "model",
1473
+ "minTokens",
1474
+ "titleContains"
1475
+ ],
1426
1476
  resolve_id: ["query"],
1427
1477
  get_summary: ["sessionId"],
1428
1478
  rename: ["sessionId", "name"],
@@ -1580,10 +1630,7 @@ async function dispatch(op, args) {
1580
1630
  }
1581
1631
  case "list_catalog": {
1582
1632
  const value = args;
1583
- return catalog.listCatalog(
1584
- value.limit,
1585
- value.search
1586
- );
1633
+ return catalog.listCatalog(value);
1587
1634
  }
1588
1635
  case "resolve_id":
1589
1636
  return catalog.resolveId(
@@ -1786,7 +1833,6 @@ async function stop(_reason) {
1786
1833
  if (process.platform !== "win32") await fsp.rm(endpoint, { force: true }).catch(() => void 0);
1787
1834
  await removeOwnedMetadata();
1788
1835
  }
1789
- ensureSessionCatalogSocketDirectory(endpoint);
1790
1836
  var server = net.createServer((socket) => {
1791
1837
  if (stopping) {
1792
1838
  socket.destroy();
@@ -1810,42 +1856,28 @@ var server = net.createServer((socket) => {
1810
1856
  scheduleIdleStop(disconnectedIdleMs);
1811
1857
  });
1812
1858
  });
1813
- var probing = false;
1814
- function listen() {
1815
- server.listen(endpoint);
1816
- }
1817
- server.on("error", (error) => {
1818
- 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") {
1819
1862
  process.exitCode = 0;
1820
1863
  return;
1821
1864
  }
1822
- if (error.code === "EADDRINUSE" && !probing) {
1823
- probing = true;
1824
- const probe = net.createConnection(endpoint);
1825
- probe.once("connect", () => {
1826
- probe.destroy();
1827
- process.exitCode = 0;
1828
- });
1829
- probe.once("error", () => {
1830
- probe.destroy();
1831
- try {
1832
- fs3.rmSync(endpoint, { force: true });
1833
- } catch {
1834
- }
1835
- probing = false;
1836
- listen();
1837
- });
1865
+ if (bind.outcome === "failed") {
1866
+ process.stderr.write(`session-catalog project server failed: ${bind.error.message}
1867
+ `);
1868
+ process.exitCode = 1;
1838
1869
  return;
1839
1870
  }
1840
- process.exitCode = 1;
1841
- });
1842
- server.on("listening", () => {
1843
- if (process.platform !== "win32") {
1844
- try {
1845
- fs3.chmodSync(endpoint, 384);
1846
- } catch {
1847
- }
1871
+ if (bind.reclaimedStaleEndpoint) {
1872
+ process.stderr.write(`session-catalog project server reclaimed stale endpoint ${endpoint}
1873
+ `);
1848
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
+ });
1849
1881
  try {
1850
1882
  store = new SessionCatalogStore(parsed.projectDir);
1851
1883
  void writeMetadata().then(() => metadataReadyResolve?.()).catch(() => void stop("metadata write failed"));
@@ -1854,8 +1886,7 @@ server.on("listening", () => {
1854
1886
  return;
1855
1887
  }
1856
1888
  scheduleIdleStop();
1857
- });
1889
+ })();
1858
1890
  process.once("SIGINT", () => void stop("SIGINT"));
1859
1891
  process.once("SIGTERM", () => void stop("SIGTERM"));
1860
- listen();
1861
1892
  //# sourceMappingURL=project-server.js.map
@@ -67,6 +67,16 @@ export interface CatalogSessionRecord extends SessionSummary {
67
67
  indexedAt: string;
68
68
  damaged: boolean;
69
69
  }
70
+ export interface SessionCatalogListArgs {
71
+ limit?: number | undefined;
72
+ search?: string | undefined;
73
+ since?: string | undefined;
74
+ until?: string | undefined;
75
+ provider?: string | undefined;
76
+ model?: string | undefined;
77
+ minTokens?: number | undefined;
78
+ titleContains?: string | undefined;
79
+ }
70
80
  export type SessionCatalogEventKind = 'session.claimed' | 'session.presence_changed' | 'session.closing' | 'session.released' | 'session.catalog_changed' | 'session.deleted' | 'session.rebuild_started' | 'session.rebuild_completed';
71
81
  export interface SessionCatalogEvent {
72
82
  instanceId: string;
@@ -185,10 +195,7 @@ export interface SessionCatalogOperations {
185
195
  result: CatalogSessionRecord;
186
196
  };
187
197
  list_catalog: {
188
- args: {
189
- limit?: number;
190
- search?: string;
191
- };
198
+ args: SessionCatalogListArgs;
192
199
  result: CatalogSessionRecord[];
193
200
  };
194
201
  resolve_id: {
@@ -1,6 +1,6 @@
1
1
  import type { SessionRegistryEntry } from '../session-registry-types.js';
2
2
  import type { SessionSummary } from '../types/session.js';
3
- import type { CatalogSessionRecord, MaintenanceLease, ResumeReservation, SessionCatalogHealth, SessionLeaseCredential } from './protocol.js';
3
+ import type { CatalogSessionRecord, MaintenanceLease, ResumeReservation, SessionCatalogHealth, SessionCatalogListArgs, SessionLeaseCredential } from './protocol.js';
4
4
  export declare class SessionCatalogStore {
5
5
  readonly projectDir: string;
6
6
  readonly databasePath: string;
@@ -52,7 +52,7 @@ export declare class SessionCatalogStore {
52
52
  private containedPath;
53
53
  upsertSummary(summary: SessionSummary, transcriptRelativePath?: string, summaryRelativePath?: string): CatalogSessionRecord;
54
54
  private catalogRecord;
55
- listCatalog(limit?: number, search?: string): CatalogSessionRecord[];
55
+ listCatalog(criteria?: SessionCatalogListArgs): CatalogSessionRecord[];
56
56
  getSummary(sessionId: string): CatalogSessionRecord | null;
57
57
  resolveId(query: string): string;
58
58
  rename(sessionId: string, name: string): Promise<CatalogSessionRecord>;