codesesh 1.0.3 → 1.0.5

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 (66) hide show
  1. package/README.md +22 -14
  2. package/dist/chunk-FCYCBGEL.js +670 -0
  3. package/dist/chunk-FCYCBGEL.js.map +1 -0
  4. package/dist/chunk-NBJJGH5P.js +2053 -0
  5. package/dist/chunk-NBJJGH5P.js.map +1 -0
  6. package/dist/chunk-PAP2Q3WV.js +1271 -0
  7. package/dist/chunk-PAP2Q3WV.js.map +1 -0
  8. package/dist/chunk-QH2HOXJH.js +2 -0
  9. package/dist/chunk-TS3IWH5U.js +6097 -0
  10. package/dist/chunk-TS3IWH5U.js.map +1 -0
  11. package/dist/chunk-WUYSZAYR.js +8383 -0
  12. package/dist/chunk-WUYSZAYR.js.map +1 -0
  13. package/dist/chunk-XKZSX5BM.js +327 -0
  14. package/dist/chunk-XKZSX5BM.js.map +1 -0
  15. package/dist/chunk-YQFEGFWD.js +89 -0
  16. package/dist/chunk-YQFEGFWD.js.map +1 -0
  17. package/dist/discovery-D23RV7FY.js +108 -0
  18. package/dist/discovery-D23RV7FY.js.map +1 -0
  19. package/dist/index.js +2986 -1514
  20. package/dist/index.js.map +1 -1
  21. package/dist/project-identity-worker.js +4 -2
  22. package/dist/project-identity-worker.js.map +1 -1
  23. package/dist/scan-refresh-worker.js +129 -138
  24. package/dist/scan-refresh-worker.js.map +1 -1
  25. package/dist/search-index-worker.js +36 -12
  26. package/dist/search-index-worker.js.map +1 -1
  27. package/dist/session-detail-worker.js +79 -0
  28. package/dist/session-detail-worker.js.map +1 -0
  29. package/dist/smart-tag-worker.js +8 -5
  30. package/dist/smart-tag-worker.js.map +1 -1
  31. package/dist/web/assets/CustomTimeWindowDialog-C9XTZRm0.js +1 -0
  32. package/dist/web/assets/InteractiveReceipt-Sca1smpv.js +1 -0
  33. package/dist/web/assets/OverviewScreen-Vq6BQR9_.js +1 -0
  34. package/dist/web/assets/{PrismHighlighter-BZkkX0AU.js → PrismHighlighter-LWITDffT.js} +2 -2
  35. package/dist/web/assets/Projects-CwicV3Dk.js +1 -0
  36. package/dist/web/assets/SearchResultsPanel-DCO0Ak0c.js +1 -0
  37. package/dist/web/assets/SessionDetail-mdmTQgo1.js +53 -0
  38. package/dist/web/assets/api-CXVT9XcZ.js +1 -0
  39. package/dist/web/assets/contract-BS78VBCV.js +2 -0
  40. package/dist/web/assets/{index-3UfOiTBO.css → index-C5cyw58A.css} +1 -1
  41. package/dist/web/assets/index-H2cT-6c6.js +1423 -0
  42. package/dist/web/assets/{session-indexes-BPhf1X2P.js → session-indexes-yyyWpKLf.js} +2 -2
  43. package/dist/web/assets/utils-C7BqyxxV.js +1 -0
  44. package/dist/web/index.html +7 -11
  45. package/package.json +4 -10
  46. package/dist/chunk-PSHZZITB.js +0 -17307
  47. package/dist/chunk-PSHZZITB.js.map +0 -1
  48. package/dist/chunk-WAKW5OPS.js +0 -241
  49. package/dist/chunk-WAKW5OPS.js.map +0 -1
  50. package/dist/dist-RHDY2EZX.js +0 -173
  51. package/dist/web/assets/ErrorBoundary-DIwwrdlw.js +0 -1
  52. package/dist/web/assets/InteractiveReceipt-DmNBDVms.js +0 -1
  53. package/dist/web/assets/OverviewScreen-B5JekBLC.js +0 -1
  54. package/dist/web/assets/Projects-Bj6ma2k2.js +0 -1
  55. package/dist/web/assets/SearchFilterBar-B9VrUbym.js +0 -1
  56. package/dist/web/assets/SearchResultsPanel-C1cuuOKq.js +0 -1
  57. package/dist/web/assets/SessionDetail-Dc2CQ3hH.js +0 -54
  58. package/dist/web/assets/SmartTagChips-ux6idUGJ.js +0 -1
  59. package/dist/web/assets/agents-BkRP_ww3.js +0 -1
  60. package/dist/web/assets/code-metrics-UYFsCC7E.js +0 -1
  61. package/dist/web/assets/contract-DXvltqJG.js +0 -1
  62. package/dist/web/assets/index-DBMiEd61.js +0 -1410
  63. package/dist/web/assets/panel-CLnL4kMN.js +0 -1
  64. package/dist/web/assets/session-title-DdtlxtlR.js +0 -1
  65. package/dist/web/assets/utils-BKqufGdv.js +0 -1
  66. /package/dist/{dist-RHDY2EZX.js.map → chunk-QH2HOXJH.js.map} +0 -0
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ buildSessionTree,
4
+ getProjectIdentityKey,
5
+ getSessionAgentKey,
6
+ matchesProjectIdentity
7
+ } from "./chunk-NBJJGH5P.js";
8
+
9
+ // ../core/dist/chunk-SULHDCDQ.mjs
10
+ import * as os from "os";
11
+ import * as path from "path";
12
+ import { createHash } from "crypto";
13
+ import { existsSync, readFileSync } from "fs";
14
+ import { spawnSync } from "child_process";
15
+ function fallbackDisplayName(input) {
16
+ if (input === "/") return "(root)";
17
+ const trimmed = input.replace(/[/\\]+$/, "");
18
+ const parts = trimmed.split(/[/\\]+/).filter(Boolean);
19
+ return parts.at(-1) ?? trimmed;
20
+ }
21
+ var realFs = {
22
+ exists(path2) {
23
+ return existsSync(path2);
24
+ },
25
+ readText(path2) {
26
+ try {
27
+ return readFileSync(path2, "utf8");
28
+ } catch {
29
+ return null;
30
+ }
31
+ },
32
+ spawn(cmd, args, opts) {
33
+ const result = spawnSync(cmd, args, { cwd: opts.cwd, encoding: "utf8", timeout: 1e3 });
34
+ return {
35
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
36
+ exitCode: result.status ?? 1
37
+ };
38
+ }
39
+ };
40
+ var PROJECT_IDENTITY_RESOLVER_REVISION = "project-identity-v2";
41
+ var MANIFESTS = [
42
+ "package.json",
43
+ "Cargo.toml",
44
+ "pyproject.toml",
45
+ "go.mod",
46
+ "Gemfile",
47
+ "pom.xml",
48
+ "build.gradle"
49
+ ];
50
+ var PARSEABLE_MANIFESTS = ["package.json", "Cargo.toml", "pyproject.toml"];
51
+ var LOOSE_DIRS = /* @__PURE__ */ new Set(["/tmp", "/private/tmp"]);
52
+ var LOOSE_HOME_DIRS = ["Desktop", "Downloads", "Documents"];
53
+ function normalizeGitRemote(url) {
54
+ if (!url) return null;
55
+ let value = url.trim();
56
+ if (/^[a-z][a-z\d+.-]*:\/\//i.test(value)) {
57
+ try {
58
+ const parsed = new URL(value);
59
+ value = `${parsed.hostname}${parsed.pathname}`;
60
+ } catch {
61
+ return null;
62
+ }
63
+ } else {
64
+ const sshMatch = value.match(/^[^@]+@([^:]+):(.+)$/);
65
+ if (sshMatch) value = `${sshMatch[1]}/${sshMatch[2]}`;
66
+ }
67
+ value = value.replace(/\.git$/, "");
68
+ if (!value.includes("/")) return null;
69
+ return value.toLowerCase();
70
+ }
71
+ var IDENTITY_CACHE_TTL_MS = 10 * 60 * 1e3;
72
+ var IDENTITY_CACHE_MAX_ENTRIES = 512;
73
+ var identityCache = /* @__PURE__ */ new Map();
74
+ function computeIdentity(cwd, fs) {
75
+ return computeIdentityProjection(cwd, fs).identity;
76
+ }
77
+ function normalizeProjectDirectory(cwd) {
78
+ if (!cwd) return "";
79
+ return getPathOps(cwd).resolve(cwd);
80
+ }
81
+ function computeIdentityProjection(cwd, fs = realFs, resolverRevision = PROJECT_IDENTITY_RESOLVER_REVISION) {
82
+ if (fs !== realFs) return resolveIdentityProjection(cwd, fs, resolverRevision);
83
+ const key = normalizeProjectDirectory(cwd);
84
+ const cached = identityCache.get(key);
85
+ if (cached) {
86
+ if (cached.projection.resolverRevision === resolverRevision && Date.now() - cached.resolvedAt < IDENTITY_CACHE_TTL_MS) {
87
+ identityCache.delete(key);
88
+ identityCache.set(key, cached);
89
+ return cached.projection;
90
+ }
91
+ identityCache.delete(key);
92
+ }
93
+ const projection = resolveIdentityProjection(cwd, fs, resolverRevision);
94
+ identityCache.set(key, { projection, resolvedAt: Date.now() });
95
+ while (identityCache.size > IDENTITY_CACHE_MAX_ENTRIES) {
96
+ const oldestKey = identityCache.keys().next().value;
97
+ if (oldestKey == null) break;
98
+ identityCache.delete(oldestKey);
99
+ }
100
+ return projection;
101
+ }
102
+ function resolveIdentityProjection(cwd, fs, resolverRevision) {
103
+ if (!cwd) return projectIdentityProjection(loose(), resolverRevision, ["loose", "missing"]);
104
+ const pathOps = getPathOps(cwd);
105
+ const absoluteCwd = pathOps.resolve(cwd);
106
+ const homeDir = os.homedir();
107
+ const homePathOps = getPathOps(homeDir);
108
+ const home = homePathOps === pathOps ? pathOps.resolve(homeDir) : homeDir;
109
+ if (absoluteCwd === home || LOOSE_DIRS.has(absoluteCwd)) {
110
+ return projectIdentityProjection(loose(), resolverRevision, ["loose", absoluteCwd]);
111
+ }
112
+ if (homePathOps === pathOps && LOOSE_HOME_DIRS.some((dir) => absoluteCwd === pathOps.join(home, dir))) {
113
+ return projectIdentityProjection(loose(), resolverRevision, ["loose", absoluteCwd]);
114
+ }
115
+ const gitRoot = findGitRoot(absoluteCwd, fs, pathOps);
116
+ if (gitRoot) {
117
+ const remote = fs.spawn("git", ["config", "--get", "remote.origin.url"], { cwd: gitRoot });
118
+ if (remote.exitCode === 0) {
119
+ const normalized = normalizeGitRemote(remote.stdout.trim());
120
+ if (normalized) {
121
+ const identity2 = {
122
+ kind: "git_remote",
123
+ key: normalized,
124
+ displayName: deriveDisplayName({ kind: "git_remote", key: normalized, gitRoot, fs })
125
+ };
126
+ return projectIdentityProjection(identity2, resolverRevision, [
127
+ "git_remote",
128
+ gitRoot,
129
+ normalized,
130
+ identity2.displayName
131
+ ]);
132
+ }
133
+ }
134
+ const common = fs.spawn("git", ["rev-parse", "--git-common-dir"], { cwd: gitRoot });
135
+ if (common.exitCode === 0) {
136
+ const raw = common.stdout.trim();
137
+ if (raw) {
138
+ const key = pathOps.isAbsolute(raw) ? raw : pathOps.resolve(gitRoot, raw);
139
+ const identity2 = {
140
+ kind: "git_common_dir",
141
+ key,
142
+ displayName: deriveDisplayName({ kind: "git_common_dir", key, gitRoot, fs })
143
+ };
144
+ return projectIdentityProjection(identity2, resolverRevision, [
145
+ "git_common_dir",
146
+ gitRoot,
147
+ key,
148
+ identity2.displayName
149
+ ]);
150
+ }
151
+ }
152
+ }
153
+ const manifestDir = findManifestDir(absoluteCwd, fs, pathOps);
154
+ if (manifestDir) {
155
+ const identity2 = {
156
+ kind: "manifest_path",
157
+ key: manifestDir,
158
+ displayName: deriveDisplayName({ kind: "manifest_path", key: manifestDir, fs })
159
+ };
160
+ return projectIdentityProjection(identity2, resolverRevision, [
161
+ "manifest_path",
162
+ manifestDir,
163
+ identity2.displayName
164
+ ]);
165
+ }
166
+ if (homePathOps === pathOps) {
167
+ const synthetic = synthesizeCodexScratchIdentity(absoluteCwd, home, pathOps);
168
+ if (synthetic) {
169
+ return projectIdentityProjection(synthetic, resolverRevision, ["synthetic", synthetic.key]);
170
+ }
171
+ }
172
+ const identity = {
173
+ kind: "path",
174
+ key: absoluteCwd,
175
+ displayName: fallbackDisplayName(absoluteCwd)
176
+ };
177
+ return projectIdentityProjection(identity, resolverRevision, ["path", absoluteCwd]);
178
+ }
179
+ function projectIdentityProjection(identity, resolverRevision, inputs) {
180
+ return {
181
+ identity,
182
+ resolverRevision,
183
+ inputSignature: createHash("sha256").update(JSON.stringify(inputs)).digest("hex")
184
+ };
185
+ }
186
+ function loose() {
187
+ return { kind: "loose", key: "loose", displayName: "Loose" };
188
+ }
189
+ function synthesizeCodexScratchIdentity(absoluteCwd, home, pathOps) {
190
+ const root = pathOps.resolve(pathOps.join(home, "Documents", "Codex"));
191
+ const child = pathOps.relative(root, absoluteCwd);
192
+ if (!child || child === ".." || child.startsWith(`..${pathOps.sep}`) || pathOps.isAbsolute(child)) {
193
+ return null;
194
+ }
195
+ return { kind: "synthetic", key: "codex:scratch", displayName: "Chats" };
196
+ }
197
+ function getPathOps(input) {
198
+ if (/^[a-zA-Z]:[\\/]/.test(input) || input.startsWith("\\\\")) {
199
+ return path.win32;
200
+ }
201
+ if (input.startsWith("/")) return path.posix;
202
+ return path;
203
+ }
204
+ function findGitRoot(start, fs, pathOps) {
205
+ let current = start;
206
+ while (current) {
207
+ if (fs.exists(pathOps.join(current, ".git"))) return current;
208
+ const parent = pathOps.dirname(current);
209
+ if (parent === current) break;
210
+ current = parent;
211
+ }
212
+ return null;
213
+ }
214
+ function findManifestDir(start, fs, pathOps) {
215
+ let current = start;
216
+ while (current) {
217
+ for (const manifest of MANIFESTS) {
218
+ if (fs.exists(pathOps.join(current, manifest))) return current;
219
+ }
220
+ const parent = pathOps.dirname(current);
221
+ if (parent === current) break;
222
+ current = parent;
223
+ }
224
+ return null;
225
+ }
226
+ function deriveDisplayName(input) {
227
+ const pathOps = getPathOps(input.gitRoot ?? input.key);
228
+ const dir = input.gitRoot ?? (input.kind === "manifest_path" ? input.key : null);
229
+ if (dir) {
230
+ for (const manifest of PARSEABLE_MANIFESTS) {
231
+ const manifestPath = pathOps.join(dir, manifest);
232
+ if (input.fs.exists(manifestPath)) {
233
+ const name = parseManifestName(manifest, input.fs.readText(manifestPath) ?? "");
234
+ if (name) return name;
235
+ }
236
+ }
237
+ }
238
+ if (input.kind === "git_remote") {
239
+ return input.key.split("/").at(-1) || input.key;
240
+ }
241
+ if (input.gitRoot) return fallbackDisplayName(input.gitRoot);
242
+ return fallbackDisplayName(input.key);
243
+ }
244
+ function parseManifestName(file, text) {
245
+ if (!text) return null;
246
+ if (file === "package.json" || file === "Cargo.toml" || file === "pyproject.toml") {
247
+ const match = text.match(/"name"\s*:\s*"([^"]+)"/) || text.match(/^\s*name\s*=\s*"([^"]+)"/m);
248
+ if (match?.[1]) return match[1];
249
+ }
250
+ return null;
251
+ }
252
+ function createProjectScopeMatcher(queryPath, fs = realFs) {
253
+ const identity = computeIdentity(queryPath, fs);
254
+ return createProjectScopeMatcherFromIdentity(queryPath, identity);
255
+ }
256
+ function createProjectScopeMatcherFromIdentity(queryPath, identity) {
257
+ return {
258
+ identity: { kind: identity.kind, key: identity.key },
259
+ path: normalizeProjectScopePath(queryPath)
260
+ };
261
+ }
262
+ function matchesProjectScope(session, scope) {
263
+ if (matchesProjectIdentity(session.project_identity, scope.identity)) return true;
264
+ return session.directory ? isPathScopeMatch(scope.path, session.directory) : false;
265
+ }
266
+ function filterSessionsByProjectScope(sessions, queryPath, fs) {
267
+ const scope = createProjectScopeMatcher(queryPath, fs);
268
+ return sessions.filter((session) => matchesProjectScope(session, scope));
269
+ }
270
+ function isPathScopeMatch(queryPath, sessionPath) {
271
+ const session = normalizeProjectScopePath(sessionPath);
272
+ return session === queryPath || session.startsWith(queryPath + "/") || queryPath.startsWith(session + "/");
273
+ }
274
+ function normalizeProjectScopePath(path2) {
275
+ return normalizeProjectDirectory(path2).replaceAll("\\", "/");
276
+ }
277
+ function buildProjectGroups(sessions) {
278
+ const groups = /* @__PURE__ */ new Map();
279
+ const tree = buildSessionTree(sessions);
280
+ for (const session of sessions) {
281
+ if (tree.mountStateOf(session) === "mounted-child") continue;
282
+ const identity = session.project_identity;
283
+ if (!identity) continue;
284
+ const activity = session.time_updated ?? session.time_created;
285
+ const groupKey = getProjectIdentityKey(identity);
286
+ const current = groups.get(groupKey);
287
+ if (current) {
288
+ current.sources.add(getSessionAgentKey(session));
289
+ current.sessionCount += 1;
290
+ current.lastActivity = Math.max(current.lastActivity, activity);
291
+ } else {
292
+ groups.set(groupKey, {
293
+ identity,
294
+ sources: /* @__PURE__ */ new Set([getSessionAgentKey(session)]),
295
+ sessionCount: 1,
296
+ lastActivity: activity
297
+ });
298
+ }
299
+ }
300
+ return [...groups.values()].map((group) => ({
301
+ identityKind: group.identity.kind,
302
+ identityKey: group.identity.key,
303
+ displayName: group.identity.displayName,
304
+ sources: [...group.sources].sort(),
305
+ sessionCount: group.sessionCount,
306
+ lastActivity: group.lastActivity || null
307
+ })).sort((a, b) => {
308
+ if (a.identityKind === "loose" && b.identityKind !== "loose") return 1;
309
+ if (b.identityKind === "loose" && a.identityKind !== "loose") return -1;
310
+ return (b.lastActivity ?? 0) - (a.lastActivity ?? 0);
311
+ });
312
+ }
313
+
314
+ export {
315
+ realFs,
316
+ PROJECT_IDENTITY_RESOLVER_REVISION,
317
+ computeIdentity,
318
+ normalizeProjectDirectory,
319
+ computeIdentityProjection,
320
+ createProjectScopeMatcher,
321
+ createProjectScopeMatcherFromIdentity,
322
+ matchesProjectScope,
323
+ filterSessionsByProjectScope,
324
+ normalizeProjectScopePath,
325
+ buildProjectGroups
326
+ };
327
+ //# sourceMappingURL=chunk-XKZSX5BM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../core/src/projects/identity.ts","../../core/src/projects/display-name.ts","../../core/src/projects/fs.ts","../../core/src/projects/scope.ts","../../core/src/projects/groups.ts"],"sourcesContent":["import * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport type { ProjectIdentity, ProjectIdentityKind } from \"../types/index.js\";\nimport { fallbackDisplayName } from \"./display-name.js\";\nimport { realFs, type IdentityFs } from \"./fs.js\";\n\nexport type { IdentityFs } from \"./fs.js\";\n\nexport const PROJECT_IDENTITY_RESOLVER_REVISION = \"project-identity-v2\";\n\nexport interface ProjectIdentityProjection {\n identity: ProjectIdentity;\n resolverRevision: string;\n inputSignature: string;\n}\n\nconst MANIFESTS = [\n \"package.json\",\n \"Cargo.toml\",\n \"pyproject.toml\",\n \"go.mod\",\n \"Gemfile\",\n \"pom.xml\",\n \"build.gradle\",\n] as const;\n\nconst PARSEABLE_MANIFESTS = [\"package.json\", \"Cargo.toml\", \"pyproject.toml\"] as const;\n\nconst LOOSE_DIRS = new Set([\"/tmp\", \"/private/tmp\"]);\nconst LOOSE_HOME_DIRS = [\"Desktop\", \"Downloads\", \"Documents\"];\ntype PathOps = Pick<\n typeof path.posix,\n \"dirname\" | \"isAbsolute\" | \"join\" | \"relative\" | \"resolve\" | \"sep\"\n>;\n\n// Identity semantics live in the contract; this module only discovers them\n// from the filesystem and git.\nexport {\n getProjectIdentityKey,\n isProjectIdentityKind,\n matchesProjectIdentity,\n} from \"../contract/project-identity.js\";\n\nexport function normalizeGitRemote(url: string): string | null {\n if (!url) return null;\n let value = url.trim();\n if (/^[a-z][a-z\\d+.-]*:\\/\\//i.test(value)) {\n try {\n const parsed = new URL(value);\n value = `${parsed.hostname}${parsed.pathname}`;\n } catch {\n return null;\n }\n } else {\n const sshMatch = value.match(/^[^@]+@([^:]+):(.+)$/);\n if (sshMatch) value = `${sshMatch[1]}/${sshMatch[2]}`;\n }\n value = value.replace(/\\.git$/, \"\");\n if (!value.includes(\"/\")) return null;\n return value.toLowerCase();\n}\n\n// Process-lifetime identity cache, keyed by directory. Only used for the real\n// filesystem (fs === realFs); tests inject fake IdentityFs implementations and\n// must bypass the cache to stay isolated from each other. git remotes change\n// rarely, so a coarse TTL is enough — no file-watch invalidation needed.\nconst IDENTITY_CACHE_TTL_MS = 10 * 60 * 1000;\nexport const IDENTITY_CACHE_MAX_ENTRIES = 512;\n\ninterface IdentityCacheEntry {\n projection: ProjectIdentityProjection;\n resolvedAt: number;\n}\n\nconst identityCache = new Map<string, IdentityCacheEntry>();\n\n/** Clears the process-lifetime identity cache. For tests and explicit invalidation. */\nexport function clearIdentityCache(): void {\n identityCache.clear();\n}\n\nexport function computeIdentity(cwd: string | null | undefined, fs: IdentityFs): ProjectIdentity {\n return computeIdentityProjection(cwd, fs).identity;\n}\n\nexport function normalizeProjectDirectory(cwd: string | null | undefined): string {\n if (!cwd) return \"\";\n return getPathOps(cwd).resolve(cwd);\n}\n\nexport function computeIdentityProjection(\n cwd: string | null | undefined,\n fs: IdentityFs = realFs,\n resolverRevision = PROJECT_IDENTITY_RESOLVER_REVISION,\n): ProjectIdentityProjection {\n if (fs !== realFs) return resolveIdentityProjection(cwd, fs, resolverRevision);\n\n const key = normalizeProjectDirectory(cwd);\n const cached = identityCache.get(key);\n if (cached) {\n if (\n cached.projection.resolverRevision === resolverRevision &&\n Date.now() - cached.resolvedAt < IDENTITY_CACHE_TTL_MS\n ) {\n identityCache.delete(key);\n identityCache.set(key, cached);\n return cached.projection;\n }\n identityCache.delete(key);\n }\n const projection = resolveIdentityProjection(cwd, fs, resolverRevision);\n identityCache.set(key, { projection, resolvedAt: Date.now() });\n while (identityCache.size > IDENTITY_CACHE_MAX_ENTRIES) {\n const oldestKey = identityCache.keys().next().value;\n if (oldestKey == null) break;\n identityCache.delete(oldestKey);\n }\n return projection;\n}\n\nfunction resolveIdentityProjection(\n cwd: string | null | undefined,\n fs: IdentityFs,\n resolverRevision: string,\n): ProjectIdentityProjection {\n if (!cwd) return projectIdentityProjection(loose(), resolverRevision, [\"loose\", \"missing\"]);\n\n const pathOps = getPathOps(cwd);\n const absoluteCwd = pathOps.resolve(cwd);\n const homeDir = os.homedir();\n const homePathOps = getPathOps(homeDir);\n const home = homePathOps === pathOps ? pathOps.resolve(homeDir) : homeDir;\n if (absoluteCwd === home || LOOSE_DIRS.has(absoluteCwd)) {\n return projectIdentityProjection(loose(), resolverRevision, [\"loose\", absoluteCwd]);\n }\n if (\n homePathOps === pathOps &&\n LOOSE_HOME_DIRS.some((dir) => absoluteCwd === pathOps.join(home, dir))\n ) {\n return projectIdentityProjection(loose(), resolverRevision, [\"loose\", absoluteCwd]);\n }\n\n const gitRoot = findGitRoot(absoluteCwd, fs, pathOps);\n if (gitRoot) {\n const remote = fs.spawn(\"git\", [\"config\", \"--get\", \"remote.origin.url\"], { cwd: gitRoot });\n if (remote.exitCode === 0) {\n const normalized = normalizeGitRemote(remote.stdout.trim());\n if (normalized) {\n const identity: ProjectIdentity = {\n kind: \"git_remote\",\n key: normalized,\n displayName: deriveDisplayName({ kind: \"git_remote\", key: normalized, gitRoot, fs }),\n };\n return projectIdentityProjection(identity, resolverRevision, [\n \"git_remote\",\n gitRoot,\n normalized,\n identity.displayName,\n ]);\n }\n }\n\n const common = fs.spawn(\"git\", [\"rev-parse\", \"--git-common-dir\"], { cwd: gitRoot });\n if (common.exitCode === 0) {\n const raw = common.stdout.trim();\n if (raw) {\n const key = pathOps.isAbsolute(raw) ? raw : pathOps.resolve(gitRoot, raw);\n const identity: ProjectIdentity = {\n kind: \"git_common_dir\",\n key,\n displayName: deriveDisplayName({ kind: \"git_common_dir\", key, gitRoot, fs }),\n };\n return projectIdentityProjection(identity, resolverRevision, [\n \"git_common_dir\",\n gitRoot,\n key,\n identity.displayName,\n ]);\n }\n }\n }\n\n const manifestDir = findManifestDir(absoluteCwd, fs, pathOps);\n if (manifestDir) {\n const identity: ProjectIdentity = {\n kind: \"manifest_path\",\n key: manifestDir,\n displayName: deriveDisplayName({ kind: \"manifest_path\", key: manifestDir, fs }),\n };\n return projectIdentityProjection(identity, resolverRevision, [\n \"manifest_path\",\n manifestDir,\n identity.displayName,\n ]);\n }\n\n if (homePathOps === pathOps) {\n const synthetic = synthesizeCodexScratchIdentity(absoluteCwd, home, pathOps);\n if (synthetic) {\n return projectIdentityProjection(synthetic, resolverRevision, [\"synthetic\", synthetic.key]);\n }\n }\n\n const identity: ProjectIdentity = {\n kind: \"path\",\n key: absoluteCwd,\n displayName: fallbackDisplayName(absoluteCwd),\n };\n return projectIdentityProjection(identity, resolverRevision, [\"path\", absoluteCwd]);\n}\n\nfunction projectIdentityProjection(\n identity: ProjectIdentity,\n resolverRevision: string,\n inputs: readonly string[],\n): ProjectIdentityProjection {\n return {\n identity,\n resolverRevision,\n inputSignature: createHash(\"sha256\").update(JSON.stringify(inputs)).digest(\"hex\"),\n };\n}\n\nfunction loose(): ProjectIdentity {\n return { kind: \"loose\", key: \"loose\", displayName: \"Loose\" };\n}\n\nfunction synthesizeCodexScratchIdentity(\n absoluteCwd: string,\n home: string,\n pathOps: PathOps,\n): ProjectIdentity | null {\n const root = pathOps.resolve(pathOps.join(home, \"Documents\", \"Codex\"));\n const child = pathOps.relative(root, absoluteCwd);\n if (\n !child ||\n child === \"..\" ||\n child.startsWith(`..${pathOps.sep}`) ||\n pathOps.isAbsolute(child)\n ) {\n return null;\n }\n return { kind: \"synthetic\", key: \"codex:scratch\", displayName: \"Chats\" };\n}\n\nfunction getPathOps(input: string): PathOps {\n if (/^[a-zA-Z]:[\\\\/]/.test(input) || input.startsWith(\"\\\\\\\\\")) {\n return path.win32;\n }\n if (input.startsWith(\"/\")) return path.posix;\n return path;\n}\n\nfunction findGitRoot(start: string, fs: IdentityFs, pathOps: PathOps): string | null {\n let current = start;\n while (current) {\n if (fs.exists(pathOps.join(current, \".git\"))) return current;\n const parent = pathOps.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return null;\n}\n\nfunction findManifestDir(start: string, fs: IdentityFs, pathOps: PathOps): string | null {\n let current = start;\n while (current) {\n for (const manifest of MANIFESTS) {\n if (fs.exists(pathOps.join(current, manifest))) return current;\n }\n const parent = pathOps.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return null;\n}\n\ninterface DisplayNameInput {\n kind: ProjectIdentityKind;\n key: string;\n gitRoot?: string;\n fs: IdentityFs;\n}\n\nfunction deriveDisplayName(input: DisplayNameInput): string {\n const pathOps = getPathOps(input.gitRoot ?? input.key);\n const dir = input.gitRoot ?? (input.kind === \"manifest_path\" ? input.key : null);\n if (dir) {\n for (const manifest of PARSEABLE_MANIFESTS) {\n const manifestPath = pathOps.join(dir, manifest);\n if (input.fs.exists(manifestPath)) {\n const name = parseManifestName(manifest, input.fs.readText(manifestPath) ?? \"\");\n if (name) return name;\n }\n }\n }\n\n if (input.kind === \"git_remote\") {\n return input.key.split(\"/\").at(-1) || input.key;\n }\n if (input.gitRoot) return fallbackDisplayName(input.gitRoot);\n return fallbackDisplayName(input.key);\n}\n\nfunction parseManifestName(file: string, text: string): string | null {\n if (!text) return null;\n if (file === \"package.json\" || file === \"Cargo.toml\" || file === \"pyproject.toml\") {\n const match = text.match(/\"name\"\\s*:\\s*\"([^\"]+)\"/) || text.match(/^\\s*name\\s*=\\s*\"([^\"]+)\"/m);\n if (match?.[1]) return match[1];\n }\n return null;\n}\n","export function fallbackDisplayName(input: string): string {\n if (input === \"/\") return \"(root)\";\n const trimmed = input.replace(/[/\\\\]+$/, \"\");\n const parts = trimmed.split(/[/\\\\]+/).filter(Boolean);\n return parts.at(-1) ?? trimmed;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\n\nexport interface IdentityFs {\n exists(path: string): boolean;\n readText(path: string): string | null;\n spawn(cmd: string, args: string[], opts: { cwd: string }): { stdout: string; exitCode: number };\n}\n\nexport const realFs: IdentityFs = {\n exists(path) {\n return existsSync(path);\n },\n readText(path) {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n },\n spawn(cmd, args, opts) {\n const result = spawnSync(cmd, args, { cwd: opts.cwd, encoding: \"utf8\", timeout: 1000 });\n return {\n stdout: typeof result.stdout === \"string\" ? result.stdout : \"\",\n exitCode: result.status ?? 1,\n };\n },\n};\n","import type { ProjectIdentityRef, SessionHead } from \"../types/index.js\";\nimport {\n computeIdentity,\n matchesProjectIdentity,\n normalizeProjectDirectory,\n type IdentityFs,\n} from \"./identity.js\";\nimport { realFs } from \"./fs.js\";\n\nexport interface ProjectScopeMatcher {\n identity: ProjectIdentityRef;\n path: string;\n}\n\nexport function createProjectScopeMatcher(\n queryPath: string,\n fs: IdentityFs = realFs,\n): ProjectScopeMatcher {\n const identity = computeIdentity(queryPath, fs);\n return createProjectScopeMatcherFromIdentity(queryPath, identity);\n}\n\nexport function createProjectScopeMatcherFromIdentity(\n queryPath: string,\n identity: ProjectIdentityRef,\n): ProjectScopeMatcher {\n return {\n identity: { kind: identity.kind, key: identity.key },\n path: normalizeProjectScopePath(queryPath),\n };\n}\n\nexport function matchesProjectScope(session: SessionHead, scope: ProjectScopeMatcher): boolean {\n if (matchesProjectIdentity(session.project_identity, scope.identity)) return true;\n return session.directory ? isPathScopeMatch(scope.path, session.directory) : false;\n}\n\nexport function filterSessionsByProjectScope<T extends SessionHead>(\n sessions: T[],\n queryPath: string,\n fs?: IdentityFs,\n): T[] {\n const scope = createProjectScopeMatcher(queryPath, fs);\n return sessions.filter((session) => matchesProjectScope(session, scope));\n}\n\nfunction isPathScopeMatch(queryPath: string, sessionPath: string): boolean {\n const session = normalizeProjectScopePath(sessionPath);\n return (\n session === queryPath ||\n session.startsWith(queryPath + \"/\") ||\n queryPath.startsWith(session + \"/\")\n );\n}\n\nexport function normalizeProjectScopePath(path: string): string {\n return normalizeProjectDirectory(path).replaceAll(\"\\\\\", \"/\");\n}\n","import type { ProjectGroup, ProjectIdentity, SessionHead } from \"../types/index.js\";\nimport { buildSessionTree, getSessionAgentKey } from \"../contract/index.js\";\nimport { getProjectIdentityKey } from \"./identity.js\";\n\nexport function buildProjectGroups(sessions: SessionHead[]): ProjectGroup[] {\n const groups = new Map<\n string,\n { identity: ProjectIdentity; sources: Set<string>; sessionCount: number; lastActivity: number }\n >();\n\n const tree = buildSessionTree(sessions);\n for (const session of sessions) {\n if (tree.mountStateOf(session) === \"mounted-child\") continue;\n const identity = session.project_identity;\n if (!identity) continue;\n const activity = session.time_updated ?? session.time_created;\n const groupKey = getProjectIdentityKey(identity);\n const current = groups.get(groupKey);\n if (current) {\n current.sources.add(getSessionAgentKey(session));\n current.sessionCount += 1;\n current.lastActivity = Math.max(current.lastActivity, activity);\n } else {\n groups.set(groupKey, {\n identity,\n sources: new Set([getSessionAgentKey(session)]),\n sessionCount: 1,\n lastActivity: activity,\n });\n }\n }\n\n return [...groups.values()]\n .map((group) => ({\n identityKind: group.identity.kind,\n identityKey: group.identity.key,\n displayName: group.identity.displayName,\n sources: [...group.sources].sort(),\n sessionCount: group.sessionCount,\n lastActivity: group.lastActivity || null,\n }))\n .sort((a, b) => {\n if (a.identityKind === \"loose\" && b.identityKind !== \"loose\") return 1;\n if (b.identityKind === \"loose\" && a.identityKind !== \"loose\") return -1;\n return (b.lastActivity ?? 0) - (a.lastActivity ?? 0);\n });\n}\n"],"mappings":"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","names":["path","identity"]}
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ appLogger
4
+ } from "./chunk-PAP2Q3WV.js";
5
+
6
+ // src/worker-log-drain.ts
7
+ import { randomUUID } from "crypto";
8
+ var WORKER_LOG_DRAIN_REQUEST_TYPE = "codesesh.worker-log-drain";
9
+ var WORKER_LOG_DRAIN_ACK_TYPE = "codesesh.worker-log-drained";
10
+ var WORKER_LOG_DRAIN_TIMEOUT_MS = 100;
11
+ var terminations = /* @__PURE__ */ new WeakMap();
12
+ function isRecord(value) {
13
+ return value != null && typeof value === "object" && !Array.isArray(value);
14
+ }
15
+ function isWorkerLogDrainRequest(message) {
16
+ return isRecord(message) && message.type === WORKER_LOG_DRAIN_REQUEST_TYPE && typeof message.requestId === "string";
17
+ }
18
+ function isWorkerLogDrainAck(message, requestId) {
19
+ return isRecord(message) && message.type === WORKER_LOG_DRAIN_ACK_TYPE && message.requestId === requestId;
20
+ }
21
+ function acknowledgeWorkerLogDrain(port, message, after = Promise.resolve()) {
22
+ if (!isWorkerLogDrainRequest(message)) return false;
23
+ const acknowledge = () => {
24
+ try {
25
+ port.postMessage({
26
+ type: WORKER_LOG_DRAIN_ACK_TYPE,
27
+ requestId: message.requestId
28
+ });
29
+ } catch {
30
+ return;
31
+ }
32
+ };
33
+ void Promise.resolve(after).then(acknowledge, acknowledge);
34
+ return true;
35
+ }
36
+ function reportDrainTimeout(worker) {
37
+ try {
38
+ appLogger.warn("worker.log_drain_timeout", {
39
+ timeout_ms: WORKER_LOG_DRAIN_TIMEOUT_MS,
40
+ worker_thread_id: worker.threadId
41
+ });
42
+ } catch {
43
+ return;
44
+ }
45
+ }
46
+ function requestWorkerLogDrain(worker) {
47
+ return new Promise((resolve) => {
48
+ const requestId = randomUUID();
49
+ let settled = false;
50
+ const finish = (exitCode) => {
51
+ if (settled) return;
52
+ settled = true;
53
+ clearTimeout(timeout);
54
+ worker.off("message", onMessage);
55
+ worker.off("exit", onExit);
56
+ resolve(exitCode);
57
+ };
58
+ const onMessage = (message) => {
59
+ if (isWorkerLogDrainAck(message, requestId)) finish();
60
+ };
61
+ const onExit = (code) => finish(code);
62
+ const timeout = setTimeout(() => {
63
+ reportDrainTimeout(worker);
64
+ finish();
65
+ }, WORKER_LOG_DRAIN_TIMEOUT_MS);
66
+ worker.on("message", onMessage);
67
+ worker.once("exit", onExit);
68
+ try {
69
+ worker.postMessage({ type: WORKER_LOG_DRAIN_REQUEST_TYPE, requestId });
70
+ } catch {
71
+ finish(worker.threadId === -1 ? 0 : void 0);
72
+ }
73
+ });
74
+ }
75
+ function terminateWorkerAfterLogDrain(worker) {
76
+ const existing = terminations.get(worker);
77
+ if (existing) return existing;
78
+ const termination = requestWorkerLogDrain(worker).then(
79
+ (exitCode) => exitCode === void 0 ? worker.terminate() : exitCode
80
+ );
81
+ terminations.set(worker, termination);
82
+ return termination;
83
+ }
84
+
85
+ export {
86
+ acknowledgeWorkerLogDrain,
87
+ terminateWorkerAfterLogDrain
88
+ };
89
+ //# sourceMappingURL=chunk-YQFEGFWD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/worker-log-drain.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { MessagePort, Worker } from \"node:worker_threads\";\nimport { appLogger } from \"./logging.js\";\n\nconst WORKER_LOG_DRAIN_REQUEST_TYPE = \"codesesh.worker-log-drain\";\nconst WORKER_LOG_DRAIN_ACK_TYPE = \"codesesh.worker-log-drained\";\nconst WORKER_LOG_DRAIN_TIMEOUT_MS = 100;\n\ninterface WorkerLogDrainRequest {\n type: typeof WORKER_LOG_DRAIN_REQUEST_TYPE;\n requestId: string;\n}\n\ninterface WorkerLogDrainAck {\n type: typeof WORKER_LOG_DRAIN_ACK_TYPE;\n requestId: string;\n}\n\nconst terminations = new WeakMap<Worker, Promise<number>>();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isWorkerLogDrainRequest(message: unknown): boolean {\n return (\n isRecord(message) &&\n message.type === WORKER_LOG_DRAIN_REQUEST_TYPE &&\n typeof message.requestId === \"string\"\n );\n}\n\nfunction isWorkerLogDrainAck(message: unknown, requestId: string): boolean {\n return (\n isRecord(message) &&\n message.type === WORKER_LOG_DRAIN_ACK_TYPE &&\n message.requestId === requestId\n );\n}\n\nexport function acknowledgeWorkerLogDrain(\n port: MessagePort,\n message: unknown,\n after: PromiseLike<unknown> = Promise.resolve(),\n): boolean {\n if (!isWorkerLogDrainRequest(message)) return false;\n const acknowledge = () => {\n try {\n port.postMessage({\n type: WORKER_LOG_DRAIN_ACK_TYPE,\n requestId: (message as WorkerLogDrainRequest).requestId,\n } satisfies WorkerLogDrainAck);\n } catch {\n return;\n }\n };\n void Promise.resolve(after).then(acknowledge, acknowledge);\n return true;\n}\n\nfunction reportDrainTimeout(worker: Worker): void {\n try {\n appLogger.warn(\"worker.log_drain_timeout\", {\n timeout_ms: WORKER_LOG_DRAIN_TIMEOUT_MS,\n worker_thread_id: worker.threadId,\n });\n } catch {\n return;\n }\n}\n\nfunction requestWorkerLogDrain(worker: Worker): Promise<number | undefined> {\n return new Promise((resolve) => {\n const requestId = randomUUID();\n let settled = false;\n const finish = (exitCode?: number) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n worker.off(\"message\", onMessage);\n worker.off(\"exit\", onExit);\n resolve(exitCode);\n };\n const onMessage = (message: unknown) => {\n if (isWorkerLogDrainAck(message, requestId)) finish();\n };\n const onExit = (code: number) => finish(code);\n const timeout = setTimeout(() => {\n reportDrainTimeout(worker);\n finish();\n }, WORKER_LOG_DRAIN_TIMEOUT_MS);\n\n worker.on(\"message\", onMessage);\n worker.once(\"exit\", onExit);\n try {\n worker.postMessage({ type: WORKER_LOG_DRAIN_REQUEST_TYPE, requestId });\n } catch {\n finish(worker.threadId === -1 ? 0 : undefined);\n }\n });\n}\n\nexport function terminateWorkerAfterLogDrain(worker: Worker): Promise<number> {\n const existing = terminations.get(worker);\n if (existing) return existing;\n\n const termination = requestWorkerLogDrain(worker).then((exitCode) =>\n exitCode === undefined ? worker.terminate() : exitCode,\n );\n terminations.set(worker, termination);\n return termination;\n}\n"],"mappings":";;;;;;AAAA,SAAS,kBAAkB;AAI3B,IAAM,gCAAgC;AACtC,IAAM,4BAA4B;AAClC,IAAM,8BAA8B;AAYpC,IAAM,eAAe,oBAAI,QAAiC;AAE1D,SAAS,SAAS,OAAkD;AAClE,SAAO,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC3E;AAEA,SAAS,wBAAwB,SAA2B;AAC1D,SACE,SAAS,OAAO,KAChB,QAAQ,SAAS,iCACjB,OAAO,QAAQ,cAAc;AAEjC;AAEA,SAAS,oBAAoB,SAAkB,WAA4B;AACzE,SACE,SAAS,OAAO,KAChB,QAAQ,SAAS,6BACjB,QAAQ,cAAc;AAE1B;AAEO,SAAS,0BACd,MACA,SACA,QAA8B,QAAQ,QAAQ,GACrC;AACT,MAAI,CAAC,wBAAwB,OAAO,EAAG,QAAO;AAC9C,QAAM,cAAc,MAAM;AACxB,QAAI;AACF,WAAK,YAAY;AAAA,QACf,MAAM;AAAA,QACN,WAAY,QAAkC;AAAA,MAChD,CAA6B;AAAA,IAC/B,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,OAAK,QAAQ,QAAQ,KAAK,EAAE,KAAK,aAAa,WAAW;AACzD,SAAO;AACT;AAEA,SAAS,mBAAmB,QAAsB;AAChD,MAAI;AACF,cAAU,KAAK,4BAA4B;AAAA,MACzC,YAAY;AAAA,MACZ,kBAAkB,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH,QAAQ;AACN;AAAA,EACF;AACF;AAEA,SAAS,sBAAsB,QAA6C;AAC1E,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,YAAY,WAAW;AAC7B,QAAI,UAAU;AACd,UAAM,SAAS,CAAC,aAAsB;AACpC,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,OAAO;AACpB,aAAO,IAAI,WAAW,SAAS;AAC/B,aAAO,IAAI,QAAQ,MAAM;AACzB,cAAQ,QAAQ;AAAA,IAClB;AACA,UAAM,YAAY,CAAC,YAAqB;AACtC,UAAI,oBAAoB,SAAS,SAAS,EAAG,QAAO;AAAA,IACtD;AACA,UAAM,SAAS,CAAC,SAAiB,OAAO,IAAI;AAC5C,UAAM,UAAU,WAAW,MAAM;AAC/B,yBAAmB,MAAM;AACzB,aAAO;AAAA,IACT,GAAG,2BAA2B;AAE9B,WAAO,GAAG,WAAW,SAAS;AAC9B,WAAO,KAAK,QAAQ,MAAM;AAC1B,QAAI;AACF,aAAO,YAAY,EAAE,MAAM,+BAA+B,UAAU,CAAC;AAAA,IACvE,QAAQ;AACN,aAAO,OAAO,aAAa,KAAK,IAAI,MAAS;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;AAEO,SAAS,6BAA6B,QAAiC;AAC5E,QAAM,WAAW,aAAa,IAAI,MAAM;AACxC,MAAI,SAAU,QAAO;AAErB,QAAM,cAAc,sBAAsB,MAAM,EAAE;AAAA,IAAK,CAAC,aACtD,aAAa,SAAY,OAAO,UAAU,IAAI;AAAA,EAChD;AACA,eAAa,IAAI,QAAQ,WAAW;AACpC,SAAO;AACT;","names":[]}
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ attachMissingProjectIdentities,
4
+ beginAgentRefresh,
5
+ buildAgentCacheMeta,
6
+ buildSessionPersistenceDiff,
7
+ clearCache,
8
+ closeCacheStorage,
9
+ commitAgentRefreshCheck,
10
+ commitDurableSessionPublication,
11
+ computeSessionDiff,
12
+ ensureSessionTagsSync,
13
+ executeAgentScanPlan,
14
+ getAgentFullSyncCursor,
15
+ getAnalyticsRevision,
16
+ getSearchProjectDirectory,
17
+ hasStaleSessionTags,
18
+ inheritSessionTags,
19
+ inspectAgentRefresh,
20
+ listCachedProjectGroups,
21
+ listDashboardCostFacts,
22
+ listFileActivity,
23
+ listModelCostDistribution,
24
+ loadCachedSessionHeads,
25
+ markAgentCacheInitialized,
26
+ markAgentFullSyncCompleted,
27
+ markAgentFullSyncProgress,
28
+ markAgentFullSyncStarted,
29
+ matchesSessionQueryScope,
30
+ materializeCachedSessionDetailResponse,
31
+ materializeSessionDetailResponse,
32
+ mergeSearchQueryOptions,
33
+ planAgentScan,
34
+ readAgentCacheInitialization,
35
+ readAgentLastFullSyncAt,
36
+ readCachedSessions,
37
+ readPendingSearchIndexMaintenance,
38
+ resolveSessionSnapshotCompleteness,
39
+ saveCachedSessionChanges,
40
+ saveCachedSessions,
41
+ scanSessions,
42
+ selectAgentRefresh,
43
+ sessionDetailVersion,
44
+ sessionSignature,
45
+ sortSessions,
46
+ syncSessionSearchIndex,
47
+ syncSessionSearchIndexChanges
48
+ } from "./chunk-TS3IWH5U.js";
49
+ import "./chunk-XKZSX5BM.js";
50
+ import "./chunk-WUYSZAYR.js";
51
+ import {
52
+ SMART_TAGS,
53
+ filterSessionTreeByActivityWindow,
54
+ isSmartTag,
55
+ mergeSortedSessions
56
+ } from "./chunk-NBJJGH5P.js";
57
+ export {
58
+ SMART_TAGS,
59
+ attachMissingProjectIdentities,
60
+ beginAgentRefresh,
61
+ buildAgentCacheMeta,
62
+ buildSessionPersistenceDiff,
63
+ clearCache,
64
+ closeCacheStorage,
65
+ commitAgentRefreshCheck,
66
+ commitDurableSessionPublication,
67
+ computeSessionDiff,
68
+ ensureSessionTagsSync,
69
+ executeAgentScanPlan,
70
+ filterSessionTreeByActivityWindow,
71
+ getAgentFullSyncCursor,
72
+ getAnalyticsRevision,
73
+ getSearchProjectDirectory,
74
+ hasStaleSessionTags,
75
+ inheritSessionTags,
76
+ inspectAgentRefresh,
77
+ isSmartTag,
78
+ listCachedProjectGroups,
79
+ listDashboardCostFacts,
80
+ listFileActivity,
81
+ listModelCostDistribution,
82
+ loadCachedSessionHeads,
83
+ markAgentCacheInitialized,
84
+ markAgentFullSyncCompleted,
85
+ markAgentFullSyncProgress,
86
+ markAgentFullSyncStarted,
87
+ matchesSessionQueryScope,
88
+ materializeCachedSessionDetailResponse,
89
+ materializeSessionDetailResponse,
90
+ mergeSearchQueryOptions,
91
+ mergeSortedSessions,
92
+ planAgentScan,
93
+ readAgentCacheInitialization,
94
+ readAgentLastFullSyncAt,
95
+ readCachedSessions,
96
+ readPendingSearchIndexMaintenance,
97
+ resolveSessionSnapshotCompleteness,
98
+ saveCachedSessionChanges,
99
+ saveCachedSessions,
100
+ scanSessions,
101
+ selectAgentRefresh,
102
+ sessionDetailVersion,
103
+ sessionSignature,
104
+ sortSessions,
105
+ syncSessionSearchIndex,
106
+ syncSessionSearchIndexChanges
107
+ };
108
+ //# sourceMappingURL=discovery-D23RV7FY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}