codesesh 1.0.0 → 1.0.2
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.
- package/README.md +29 -5
- package/dist/{chunk-TIHF4T3K.js → chunk-PROMURPM.js} +80 -16
- package/dist/chunk-PROMURPM.js.map +1 -0
- package/dist/{chunk-BEF6LLRG.js → chunk-VAUC2W7I.js} +5317 -2268
- package/dist/chunk-VAUC2W7I.js.map +1 -0
- package/dist/{dist-3F467V44.js → dist-6QTGTYZT.js} +40 -4
- package/dist/index.js +1818 -454
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +274 -95
- package/dist/scan-refresh-worker.js.map +1 -1
- package/dist/search-index-worker.js +112 -50
- package/dist/search-index-worker.js.map +1 -1
- package/dist/smart-tag-worker.js +5 -3
- package/dist/smart-tag-worker.js.map +1 -1
- package/dist/web/assets/ErrorBoundary-D11tWzfn.js +1 -0
- package/dist/web/assets/OverviewScreen-DriPmCam.js +1 -0
- package/dist/web/assets/Projects-BPDIcUBK.js +1 -0
- package/dist/web/assets/SearchFilterBar-Bx73B5e9.js +1 -0
- package/dist/web/assets/SearchResultsPanel-A6_3TPhW.js +1 -0
- package/dist/web/assets/SessionDetail-BnpvDwtH.js +54 -0
- package/dist/web/assets/agents-BkRP_ww3.js +1 -0
- package/dist/web/assets/contract-V6QuD0UY.js +1 -0
- package/dist/web/assets/index-99ZxpV2y.js +1410 -0
- package/dist/web/assets/index-B2RqUgZ5.css +1 -0
- package/dist/web/assets/panel-C-gc79Gz.js +1 -0
- package/dist/web/assets/session-indexes-0oT5HSS5.js +4 -0
- package/dist/web/assets/utils-DgUgu15E.js +1 -0
- package/dist/web/icon/agent/dsh.svg +3 -0
- package/dist/web/index.html +10 -32
- package/dist/web/theme-bootstrap.js +19 -0
- package/package.json +10 -10
- package/dist/chunk-BEF6LLRG.js.map +0 -1
- package/dist/chunk-TIHF4T3K.js.map +0 -1
- package/dist/web/assets/ErrorBoundary-BY-N1QzJ.js +0 -1
- package/dist/web/assets/OverviewScreen-_ZaVjhxN.js +0 -1
- package/dist/web/assets/Projects-q6cEm2dc.js +0 -1
- package/dist/web/assets/SearchFilterBar-CrVBpo40.js +0 -1
- package/dist/web/assets/SearchResultsPanel-Cg5V8Ia6.js +0 -1
- package/dist/web/assets/SessionDetail-BSSuddsZ.js +0 -54
- package/dist/web/assets/chunk-62JRHF6Z-BWRsEBnL.js +0 -4
- package/dist/web/assets/index-C3KgxGwE.js +0 -1410
- package/dist/web/assets/index-DQX42cFQ.css +0 -1
- package/dist/web/assets/panel-B7kuE60V.js +0 -1
- package/dist/web/assets/session-indexes-DmnjZ_JL.js +0 -1
- package/dist/web/assets/utils-t2u9IbNT.js +0 -1
- /package/dist/{dist-3F467V44.js.map → dist-6QTGTYZT.js.map} +0 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center"><strong>One place to see every AI coding session you've ever had.</strong></p>
|
|
8
8
|
|
|
9
|
-
CodeSesh scans your local machine, finds every AI agent session (Claude Code, Cursor, Kimi, Kimi-Code, Codex, Grok, Pi, OpenCode, ZCode), and surfaces them in a unified, beautiful Web UI.
|
|
9
|
+
CodeSesh scans your local machine, finds every AI agent session (Claude Code, Cursor, Kimi, Kimi-Code, Codex, Grok, Pi, OpenCode, ZCode, DSH), and surfaces them in a unified, beautiful Web UI.
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
@@ -52,6 +52,7 @@ Your browser will open at `http://localhost:4521` with all your sessions ready t
|
|
|
52
52
|
| Pi | ✅ Supported |
|
|
53
53
|
| OpenCode | ✅ Supported |
|
|
54
54
|
| ZCode | ✅ Supported |
|
|
55
|
+
| DSH | ✅ Supported |
|
|
55
56
|
|
|
56
57
|
## Usage
|
|
57
58
|
|
|
@@ -87,7 +88,10 @@ npx codesesh --trace
|
|
|
87
88
|
| ----------- | ----- | ------- | ----------------------------------------------------------- |
|
|
88
89
|
| `--port` | `-p` | `4521` | HTTP server starting port; falls back to the next available port if busy |
|
|
89
90
|
| `--host` | — | `127.0.0.1` | HTTP server bind address; non-loopback values require `--remote-access` |
|
|
90
|
-
| `--remote-access` | — | `false` | Enable token-protected access
|
|
91
|
+
| `--remote-access` | — | `false` | Enable token-protected access for any remotely exposed transport |
|
|
92
|
+
| `--tls-cert` | — | — | Path to a TLS certificate; serves remote access over HTTPS |
|
|
93
|
+
| `--tls-key` | — | — | Path to the private key matching `--tls-cert` |
|
|
94
|
+
| `--trust-proxy` | — | `false` | A reverse proxy in front of CodeSesh terminates TLS |
|
|
91
95
|
| `--days` | `-d` | `7` | Only include sessions active in the last N days (`0` = all time) |
|
|
92
96
|
| `--cwd` | — | — | Filter to sessions from a project directory |
|
|
93
97
|
| `--agent` | `-a` | all | Filter to specific agent(s), comma-separated |
|
|
@@ -101,14 +105,34 @@ npx codesesh --trace
|
|
|
101
105
|
| `--clear-cache` | — | `false` | Clear scan cache before starting |
|
|
102
106
|
| `-v` | — | — | Print version number |
|
|
103
107
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
Non-loopback binding and `--trust-proxy` both require `--remote-access`. This includes the common
|
|
109
|
+
setup where CodeSesh listens on `127.0.0.1` and a same-machine reverse proxy exposes it publicly.
|
|
110
|
+
CodeSesh prints a startup URL containing a fresh access token. Anyone with that URL can read the
|
|
111
|
+
indexed AI session history, so treat it as a password and do not share or persist it.
|
|
112
|
+
|
|
113
|
+
A token authenticates the requester but does not encrypt traffic. Without TLS, the token and full
|
|
114
|
+
session content travel over the network in plaintext, and URL tokens may be recorded in proxy logs.
|
|
115
|
+
Use one of these protected transports:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# CodeSesh terminates TLS
|
|
119
|
+
npx codesesh --host 0.0.0.0 --remote-access --tls-cert ./cert.pem --tls-key ./key.pem
|
|
120
|
+
|
|
121
|
+
# A reverse proxy terminates TLS; CodeSesh stays bound to loopback
|
|
122
|
+
npx codesesh --host 127.0.0.1 --remote-access --trust-proxy
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`--trust-proxy` requires `X-Forwarded-Proto: https` on every API request. The listener must remain
|
|
126
|
+
unreachable except through that trusted proxy.
|
|
107
127
|
|
|
108
128
|
## Requirements
|
|
109
129
|
|
|
130
|
+
<!-- repo-fact:node-version:start -->
|
|
131
|
+
|
|
110
132
|
- Node.js 22+
|
|
111
133
|
|
|
134
|
+
<!-- repo-fact:node-version:end -->
|
|
135
|
+
|
|
112
136
|
## Links
|
|
113
137
|
|
|
114
138
|
- [GitHub](https://github.com/xingkaixin/codesesh)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
WORKER_LOG_MESSAGE_TYPE,
|
|
3
4
|
ensurePrivateDirectory,
|
|
5
|
+
isWorkerLogMessage,
|
|
4
6
|
restrictExistingPrivateFiles,
|
|
5
7
|
restrictPrivateFile,
|
|
6
8
|
setCoreDiagnostics
|
|
7
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VAUC2W7I.js";
|
|
8
10
|
|
|
9
11
|
// src/logging.ts
|
|
10
12
|
import { appendFileSync, existsSync, readdirSync, renameSync, statSync, unlinkSync } from "fs";
|
|
@@ -64,16 +66,34 @@ var AppLogger = class {
|
|
|
64
66
|
currentPath;
|
|
65
67
|
rotationIndex = 0;
|
|
66
68
|
restrictedExistingLogs = false;
|
|
69
|
+
workerTarget = null;
|
|
70
|
+
writeFailureReported = false;
|
|
67
71
|
constructor(options = {}) {
|
|
68
72
|
this.logDir = options.logDir ?? process.env.CODESESH_LOG_DIR ?? getDefaultLogDir();
|
|
69
73
|
this.level = options.level ?? parseLevel(process.env.CODESESH_LOG_LEVEL);
|
|
70
74
|
this.maxBytes = options.maxBytes ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_BYTES, 5e6);
|
|
71
75
|
this.maxFiles = options.maxFiles ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_FILES, 5);
|
|
72
|
-
this.currentPath = join(this.logDir,
|
|
76
|
+
this.currentPath = join(this.logDir, `codesesh-${process.pid}.log`);
|
|
73
77
|
}
|
|
74
78
|
getLogPath() {
|
|
75
79
|
return this.currentPath;
|
|
76
80
|
}
|
|
81
|
+
forwardToParent(port, threadId2) {
|
|
82
|
+
this.workerTarget = { port, threadId: threadId2 };
|
|
83
|
+
}
|
|
84
|
+
consumeWorkerMessage(message) {
|
|
85
|
+
if (!isWorkerLogMessage(message)) return false;
|
|
86
|
+
if (LEVEL_WEIGHT[message.level] < LEVEL_WEIGHT[this.level]) return true;
|
|
87
|
+
this.appendRecord({
|
|
88
|
+
...message.data,
|
|
89
|
+
ts: message.ts,
|
|
90
|
+
level: message.level,
|
|
91
|
+
event: message.event,
|
|
92
|
+
pid: message.pid,
|
|
93
|
+
thread_id: message.threadId
|
|
94
|
+
});
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
77
97
|
debug(event, data = {}) {
|
|
78
98
|
this.write("debug", event, data);
|
|
79
99
|
}
|
|
@@ -88,20 +108,53 @@ var AppLogger = class {
|
|
|
88
108
|
}
|
|
89
109
|
write(level, event, data) {
|
|
90
110
|
if (LEVEL_WEIGHT[level] < LEVEL_WEIGHT[this.level]) return;
|
|
111
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
112
|
+
const normalizedData = toLogValue(data);
|
|
113
|
+
if (this.workerTarget) {
|
|
114
|
+
try {
|
|
115
|
+
this.workerTarget.port.postMessage({
|
|
116
|
+
type: WORKER_LOG_MESSAGE_TYPE,
|
|
117
|
+
ts,
|
|
118
|
+
level,
|
|
119
|
+
event,
|
|
120
|
+
pid: process.pid,
|
|
121
|
+
threadId: this.workerTarget.threadId,
|
|
122
|
+
data: normalizedData
|
|
123
|
+
});
|
|
124
|
+
} catch (error) {
|
|
125
|
+
this.reportWriteFailure(error);
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.appendRecord({
|
|
130
|
+
...normalizedData,
|
|
131
|
+
ts,
|
|
132
|
+
level,
|
|
133
|
+
event,
|
|
134
|
+
pid: process.pid
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
appendRecord(record) {
|
|
91
138
|
try {
|
|
92
139
|
ensurePrivateDirectory(this.logDir);
|
|
93
140
|
this.restrictExistingLogs();
|
|
94
|
-
const line = `${JSON.stringify(
|
|
95
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
96
|
-
level,
|
|
97
|
-
event,
|
|
98
|
-
pid: process.pid,
|
|
99
|
-
...toLogValue(data)
|
|
100
|
-
})}
|
|
141
|
+
const line = `${JSON.stringify(record)}
|
|
101
142
|
`;
|
|
102
|
-
this.rotateIfNeeded(Buffer.byteLength(line));
|
|
143
|
+
const restrictCurrentFile = this.rotateIfNeeded(Buffer.byteLength(line));
|
|
103
144
|
appendFileSync(this.currentPath, line, "utf8");
|
|
104
|
-
restrictPrivateFile(this.currentPath);
|
|
145
|
+
if (restrictCurrentFile) restrictPrivateFile(this.currentPath);
|
|
146
|
+
this.writeFailureReported = false;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
this.reportWriteFailure(error);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
reportWriteFailure(error) {
|
|
152
|
+
if (this.writeFailureReported) return;
|
|
153
|
+
this.writeFailureReported = true;
|
|
154
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
155
|
+
try {
|
|
156
|
+
process.stderr.write(`[codesesh] Failed to write log ${this.currentPath}: ${message}
|
|
157
|
+
`);
|
|
105
158
|
} catch {
|
|
106
159
|
}
|
|
107
160
|
}
|
|
@@ -117,21 +170,23 @@ var AppLogger = class {
|
|
|
117
170
|
rotateIfNeeded(nextBytes) {
|
|
118
171
|
if (!existsSync(this.currentPath)) {
|
|
119
172
|
this.removeExpiredLogs();
|
|
120
|
-
return;
|
|
173
|
+
return true;
|
|
121
174
|
}
|
|
122
175
|
const currentSize = statSync(this.currentPath).size;
|
|
123
|
-
if (currentSize + nextBytes <= this.maxBytes) return;
|
|
176
|
+
if (currentSize + nextBytes <= this.maxBytes) return false;
|
|
124
177
|
this.rotationIndex += 1;
|
|
125
178
|
const rotatedPath = join(
|
|
126
179
|
this.logDir,
|
|
127
|
-
`codesesh-${timestampForFile()}-${
|
|
180
|
+
`codesesh-${process.pid}-${timestampForFile()}-${this.rotationIndex}.log`
|
|
128
181
|
);
|
|
129
182
|
renameSync(this.currentPath, rotatedPath);
|
|
130
183
|
restrictPrivateFile(rotatedPath);
|
|
131
184
|
this.removeExpiredLogs();
|
|
185
|
+
return true;
|
|
132
186
|
}
|
|
133
187
|
removeExpiredLogs() {
|
|
134
|
-
const
|
|
188
|
+
const ownedPrefix = `codesesh-${process.pid}-`;
|
|
189
|
+
const rotated = readdirSync(this.logDir).filter((name) => name.startsWith(ownedPrefix) && name.endsWith(".log")).map((name) => {
|
|
135
190
|
const path = join(this.logDir, name);
|
|
136
191
|
return { path, mtimeMs: statSync(path).mtimeMs };
|
|
137
192
|
}).toSorted((a, b) => b.mtimeMs - a.mtimeMs);
|
|
@@ -142,6 +197,13 @@ var AppLogger = class {
|
|
|
142
197
|
};
|
|
143
198
|
var appLogger = new AppLogger();
|
|
144
199
|
function logSearchIndexSync(context, result, data = {}) {
|
|
200
|
+
if (result?.failures?.length) {
|
|
201
|
+
appLogger.warn("search_index.sessions_skipped", {
|
|
202
|
+
context,
|
|
203
|
+
agent: result.agentName,
|
|
204
|
+
failures: result.failures
|
|
205
|
+
});
|
|
206
|
+
}
|
|
145
207
|
if (!result || result.mode !== "bulk" || result.rebuildDurationMs == null) {
|
|
146
208
|
return;
|
|
147
209
|
}
|
|
@@ -161,6 +223,8 @@ function logSearchIndexSync(context, result, data = {}) {
|
|
|
161
223
|
}
|
|
162
224
|
|
|
163
225
|
// src/diagnostics-bridge.ts
|
|
226
|
+
import { parentPort, threadId } from "worker_threads";
|
|
227
|
+
if (parentPort) appLogger.forwardToParent(parentPort, threadId);
|
|
164
228
|
setCoreDiagnostics({
|
|
165
229
|
info(event, detail) {
|
|
166
230
|
appLogger.info(event, detail);
|
|
@@ -174,4 +238,4 @@ export {
|
|
|
174
238
|
appLogger,
|
|
175
239
|
logSearchIndexSync
|
|
176
240
|
};
|
|
177
|
-
//# sourceMappingURL=chunk-
|
|
241
|
+
//# sourceMappingURL=chunk-PROMURPM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logging.ts","../src/diagnostics-bridge.ts"],"sourcesContent":["import { appendFileSync, existsSync, readdirSync, renameSync, statSync, unlinkSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n ensurePrivateDirectory,\n isWorkerLogMessage,\n restrictExistingPrivateFiles,\n restrictPrivateFile,\n WORKER_LOG_MESSAGE_TYPE,\n type WorkerLogLevel,\n type WorkerLogMessage,\n} from \"@codesesh/core\";\nimport type { SearchIndexSyncResult } from \"@codesesh/core\";\n\ntype LogLevel = WorkerLogLevel;\n\ninterface WorkerLogPort {\n postMessage(message: WorkerLogMessage): void;\n}\n\nconst LEVEL_WEIGHT: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\nexport interface LoggerOptions {\n logDir?: string;\n level?: LogLevel;\n maxBytes?: number;\n maxFiles?: number;\n}\n\nfunction parseLevel(value: string | undefined): LogLevel {\n if (value === \"debug\" || value === \"info\" || value === \"warn\" || value === \"error\") {\n return value;\n }\n return \"info\";\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;\n}\n\nfunction getDefaultLogDir(): string {\n const base = process.env.XDG_CACHE_HOME ?? join(homedir(), \".cache\");\n return join(base, \"codesesh\", \"logs\");\n}\n\nfunction toLogValue(value: unknown, depth = 0): unknown {\n if (value == null || typeof value === \"string\" || typeof value === \"number\") return value;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"bigint\") return value.toString();\n if (value instanceof Error) {\n return {\n name: value.name,\n message: value.message,\n stack: value.stack,\n };\n }\n if (depth >= 4) return \"[truncated]\";\n if (Array.isArray(value)) return value.slice(0, 50).map((item) => toLogValue(item, depth + 1));\n if (typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n key,\n toLogValue(item, depth + 1),\n ]),\n );\n }\n return String(value);\n}\n\nfunction timestampForFile(date = new Date()): string {\n return date.toISOString().replace(/[:.]/g, \"-\");\n}\n\nexport class AppLogger {\n private readonly logDir: string;\n private readonly level: LogLevel;\n private readonly maxBytes: number;\n private readonly maxFiles: number;\n private readonly currentPath: string;\n private rotationIndex = 0;\n private restrictedExistingLogs = false;\n private workerTarget: { port: WorkerLogPort; threadId: number } | null = null;\n private writeFailureReported = false;\n\n constructor(options: LoggerOptions = {}) {\n this.logDir = options.logDir ?? process.env.CODESESH_LOG_DIR ?? getDefaultLogDir();\n this.level = options.level ?? parseLevel(process.env.CODESESH_LOG_LEVEL);\n this.maxBytes =\n options.maxBytes ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_BYTES, 5_000_000);\n this.maxFiles = options.maxFiles ?? parsePositiveInt(process.env.CODESESH_LOG_MAX_FILES, 5);\n this.currentPath = join(this.logDir, `codesesh-${process.pid}.log`);\n }\n\n getLogPath(): string {\n return this.currentPath;\n }\n\n forwardToParent(port: WorkerLogPort, threadId: number): void {\n this.workerTarget = { port, threadId };\n }\n\n consumeWorkerMessage(message: unknown): boolean {\n if (!isWorkerLogMessage(message)) return false;\n if (LEVEL_WEIGHT[message.level] < LEVEL_WEIGHT[this.level]) return true;\n this.appendRecord({\n ...message.data,\n ts: message.ts,\n level: message.level,\n event: message.event,\n pid: message.pid,\n thread_id: message.threadId,\n });\n return true;\n }\n\n debug(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"debug\", event, data);\n }\n\n info(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"info\", event, data);\n }\n\n warn(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"warn\", event, data);\n }\n\n error(event: string, data: Record<string, unknown> = {}): void {\n this.write(\"error\", event, data);\n }\n\n private write(level: LogLevel, event: string, data: Record<string, unknown>): void {\n if (LEVEL_WEIGHT[level] < LEVEL_WEIGHT[this.level]) return;\n\n const ts = new Date().toISOString();\n const normalizedData = toLogValue(data) as Record<string, unknown>;\n if (this.workerTarget) {\n try {\n this.workerTarget.port.postMessage({\n type: WORKER_LOG_MESSAGE_TYPE,\n ts,\n level,\n event,\n pid: process.pid,\n threadId: this.workerTarget.threadId,\n data: normalizedData,\n });\n } catch (error) {\n this.reportWriteFailure(error);\n }\n return;\n }\n\n this.appendRecord({\n ...normalizedData,\n ts,\n level,\n event,\n pid: process.pid,\n });\n }\n\n private appendRecord(record: Record<string, unknown>): void {\n try {\n ensurePrivateDirectory(this.logDir);\n this.restrictExistingLogs();\n const line = `${JSON.stringify(record)}\\n`;\n const restrictCurrentFile = this.rotateIfNeeded(Buffer.byteLength(line));\n appendFileSync(this.currentPath, line, \"utf8\");\n if (restrictCurrentFile) restrictPrivateFile(this.currentPath);\n this.writeFailureReported = false;\n } catch (error) {\n this.reportWriteFailure(error);\n }\n }\n\n private reportWriteFailure(error: unknown): void {\n if (this.writeFailureReported) return;\n this.writeFailureReported = true;\n const message = error instanceof Error ? error.message : String(error);\n try {\n process.stderr.write(`[codesesh] Failed to write log ${this.currentPath}: ${message}\\n`);\n } catch {}\n }\n\n /** Logs rotated by an earlier run predate the owner-only policy. */\n private restrictExistingLogs(): void {\n if (this.restrictedExistingLogs) return;\n this.restrictedExistingLogs = true;\n restrictExistingPrivateFiles(\n this.logDir,\n (name) => name.startsWith(\"codesesh\") && name.endsWith(\".log\"),\n );\n }\n\n private rotateIfNeeded(nextBytes: number): boolean {\n if (!existsSync(this.currentPath)) {\n this.removeExpiredLogs();\n return true;\n }\n\n const currentSize = statSync(this.currentPath).size;\n if (currentSize + nextBytes <= this.maxBytes) return false;\n\n this.rotationIndex += 1;\n const rotatedPath = join(\n this.logDir,\n `codesesh-${process.pid}-${timestampForFile()}-${this.rotationIndex}.log`,\n );\n renameSync(this.currentPath, rotatedPath);\n restrictPrivateFile(rotatedPath);\n this.removeExpiredLogs();\n return true;\n }\n\n private removeExpiredLogs(): void {\n const ownedPrefix = `codesesh-${process.pid}-`;\n const rotated = readdirSync(this.logDir)\n .filter((name) => name.startsWith(ownedPrefix) && name.endsWith(\".log\"))\n .map((name) => {\n const path = join(this.logDir, name);\n return { path, mtimeMs: statSync(path).mtimeMs };\n })\n .toSorted((a, b) => b.mtimeMs - a.mtimeMs);\n\n for (const item of rotated.slice(Math.max(0, this.maxFiles - 1))) {\n unlinkSync(item.path);\n }\n }\n}\n\nexport const appLogger = new AppLogger();\n\nexport function logSearchIndexSync(\n context: string,\n result: SearchIndexSyncResult | null,\n data: Record<string, unknown> = {},\n): void {\n if (result?.failures?.length) {\n appLogger.warn(\"search_index.sessions_skipped\", {\n context,\n agent: result.agentName,\n failures: result.failures,\n });\n }\n if (!result || result.mode !== \"bulk\" || result.rebuildDurationMs == null) {\n return;\n }\n\n appLogger.info(\"search_index.sync\", {\n context,\n agent: result.agentName,\n mode: result.mode,\n sessions: result.sessions,\n changed: result.changed,\n deleted: result.deleted,\n indexed: result.indexed,\n skipped: result.skipped,\n duration_ms: Math.round(result.durationMs),\n rebuild_duration_ms: Math.round(result.rebuildDurationMs),\n ...data,\n });\n}\n","import { setCoreDiagnostics } from \"@codesesh/core\";\nimport { parentPort, threadId } from \"node:worker_threads\";\nimport { appLogger } from \"./logging.js\";\n\n/**\n * Bridges core's diagnostics sink to appLogger. Import this once, for its\n * side effect, from every entry point that gets its own module graph — the\n * main CLI thread and each worker_threads script (scan-refresh-worker,\n * search-index-worker, smart-tag-worker) — since core's module-level\n * diagnostics singleton is per-thread, not shared across workers.\n */\nif (parentPort) appLogger.forwardToParent(parentPort, threadId);\n\nsetCoreDiagnostics({\n info(event, detail) {\n appLogger.info(event, detail);\n },\n warn(event, detail) {\n appLogger.warn(event, detail);\n },\n});\n"],"mappings":"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","names":["threadId"]}
|