@24klynx/core 0.1.0

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.
@@ -0,0 +1,345 @@
1
+ import Database$1, { Database } from "better-sqlite3";
2
+
3
+ //#region src/types.d.ts
4
+ /**
5
+ * Core type definitions for the Lynx agent system.
6
+ * All other packages depend on these interfaces — keep them stable.
7
+ */
8
+ /** Opaque session identifier (UUID v4). */
9
+ type SessionId = string & {
10
+ readonly __brand: "SessionId";
11
+ };
12
+ /** Opaque message identifier (UUID v4). */
13
+ type MessageId = string & {
14
+ readonly __brand: "MessageId";
15
+ };
16
+ /**
17
+ * Discriminated union of all content types an LLM can emit or receive.
18
+ * The `reasoning` variant captures chain-of-thought from models like
19
+ * DeepSeek R1 and OpenAI o1.
20
+ */
21
+ type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ReasoningBlock;
22
+ interface TextBlock {
23
+ type: "text";
24
+ /** Plain text content emitted by the LLM. */
25
+ text: string;
26
+ }
27
+ interface ToolUseBlock {
28
+ type: "tool_use";
29
+ /** Unique ID for matching tool results back to calls. */
30
+ id: string;
31
+ /** Name of the tool being invoked. */
32
+ name: string;
33
+ /** Arguments passed to the tool. */
34
+ input: Record<string, unknown>;
35
+ }
36
+ interface ToolResultBlock {
37
+ type: "tool_result";
38
+ /** Matches the `id` of the corresponding `tool_use` block. */
39
+ toolUseId: string;
40
+ /** Text or structured output from the tool execution. */
41
+ content: string;
42
+ /** Set to true when the tool execution failed. */
43
+ isError?: boolean;
44
+ }
45
+ interface ReasoningBlock {
46
+ type: "reasoning";
47
+ /** Chain-of-thought text (e.g. DeepSeek R1, OpenAI o1). */
48
+ text: string;
49
+ }
50
+ interface Message {
51
+ /** Unique identifier (UUID v4). */
52
+ id: MessageId;
53
+ /** Who sent this message — user, assistant, or system. */
54
+ role: "user" | "assistant" | "system";
55
+ /** Content blocks making up the message body. */
56
+ content: ContentBlock[];
57
+ /** Unix timestamp in milliseconds. */
58
+ timestamp: number;
59
+ /** Zero-based index within the session's message list. */
60
+ turnIndex: number;
61
+ }
62
+ /**
63
+ * Flexible metadata bag attached to every session.
64
+ * Keys are strings to allow extension without breaking DB rows.
65
+ */
66
+ interface SessionMetadata {
67
+ /** Whether the last session run was interrupted (crash / SIGKILL). */
68
+ crashed?: boolean;
69
+ /** Model identifier used for this session (e.g. "deepseek-v3"). */
70
+ model?: string;
71
+ /** Active permission mode when the session was last saved. */
72
+ permissionMode?: string;
73
+ /** Additional entries injected by plugins or migrations. */
74
+ [key: string]: unknown;
75
+ }
76
+ interface Session {
77
+ /** Unique session identifier (UUID v4). */
78
+ id: SessionId;
79
+ /** User-visible label shown in the session picker. */
80
+ label: string;
81
+ /** Absolute path to the workspace directory. */
82
+ workspace: string;
83
+ /** Ordered message history. */
84
+ messages: Message[];
85
+ /** The session this one was forked from, if any. */
86
+ parentSessionId?: SessionId;
87
+ /** Message count at the time of fork. */
88
+ forkedFromMessageCount?: number;
89
+ /** Unix ms — set on create. */
90
+ createdAt: number;
91
+ /** Unix ms — bumped on every mutation. */
92
+ updatedAt: number;
93
+ /** Flexible metadata bag (model, permission mode, crash state, etc.). */
94
+ metadata: SessionMetadata;
95
+ }
96
+ /**
97
+ * Serializable record of a tool being invoked.
98
+ * The full tool descriptor lives in @lynx/tools; core only stores
99
+ * the invocation trace needed for session replay.
100
+ */
101
+ interface ToolCall {
102
+ /** Matches the `id` in `ToolUseBlock`. */
103
+ id: string;
104
+ /** Name of the tool being invoked. */
105
+ name: string;
106
+ /** Arguments supplied by the LLM. */
107
+ input: Record<string, unknown>;
108
+ /** Unix ms when the tool started executing. */
109
+ startedAt: number;
110
+ /** Unix ms when the tool finished (undefined if still running). */
111
+ finishedAt?: number;
112
+ }
113
+ interface ToolResult {
114
+ /** Matches `ToolCall.id`. */
115
+ toolCallId: string;
116
+ /** Text or structured output from the tool. */
117
+ output: string;
118
+ /** Whether the tool execution ended in an error. */
119
+ isError: boolean;
120
+ /** Unix ms when execution completed. */
121
+ finishedAt: number;
122
+ }
123
+ /** Create a new SessionId from a UUID string. */
124
+ declare function asSessionId(id: string): SessionId;
125
+ /** Create a new MessageId from a UUID string. */
126
+ declare function asMessageId(id: string): MessageId;
127
+ //#endregion
128
+ //#region src/errors.d.ts
129
+ /**
130
+ * Layered error system for Lynx.
131
+ *
132
+ * Layer 1 — LynxError subclasses: typed, machine‑actionable errors
133
+ * each carries recoverable / retryable / userVisible / diagnosticHint.
134
+ * Layer 2 — ErrorEnvelope: cross‑boundary wrapper with category + severity.
135
+ * Layer 3 — Top‑level catch in lynx‑cli/entry.ts formats and routes.
136
+ */
137
+ /**
138
+ * Which subsystem raised the error.
139
+ * Used by error reporters and /doctor to route diagnostics.
140
+ */
141
+ type ErrorCategory = "tool" | "llm" | "session" | "plugin" | "channel" | "config" | "storage";
142
+ /**
143
+ * Severity level for log routing and user notification.
144
+ * "debug"/"info" are suppressed in production; "fatal" triggers process exit.
145
+ */
146
+ type ErrorSeverity = "debug" | "info" | "warn" | "error" | "fatal";
147
+ /** Configuration for constructing a LynxError. */
148
+ interface LynxErrorOptions {
149
+ /** Which subsystem raised this error. */
150
+ category: ErrorCategory;
151
+ /** Whether the system can recover without user intervention. */
152
+ recoverable?: boolean;
153
+ /** Whether retrying the same operation might succeed. */
154
+ retryable?: boolean;
155
+ /** Whether the message should be shown to the user. */
156
+ userVisible?: boolean;
157
+ /** Pointer to a /doctor check (e.g. "storage_migration_failed"). */
158
+ diagnosticHint?: string;
159
+ }
160
+ declare class LynxError extends Error {
161
+ /** Which subsystem raised this error. */
162
+ readonly category: ErrorCategory;
163
+ /** Whether the system can recover without user intervention. */
164
+ readonly recoverable: boolean;
165
+ /** Whether retrying the same operation might succeed. */
166
+ readonly retryable: boolean;
167
+ /** Whether the message should be shown to the user. */
168
+ readonly userVisible: boolean;
169
+ /** Pointer to a /doctor check (e.g. "storage_migration_failed"). */
170
+ readonly diagnosticHint: string | undefined;
171
+ constructor(message: string, opts: LynxErrorOptions);
172
+ }
173
+ declare class ToolError extends LynxError {
174
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
175
+ }
176
+ declare class ToolTimeoutError extends ToolError {
177
+ constructor(message?: string);
178
+ }
179
+ declare class ToolAbortedError extends ToolError {
180
+ constructor(message?: string);
181
+ }
182
+ declare class ToolPermissionError extends ToolError {
183
+ constructor(message?: string);
184
+ }
185
+ declare class LlmError extends LynxError {
186
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
187
+ }
188
+ declare class LlmRateLimitError extends LlmError {
189
+ /** HTTP status code (429 for rate limit, 529 for overload). */
190
+ status: number;
191
+ constructor(message?: string, status?: number);
192
+ }
193
+ declare class LlmAuthError extends LlmError {
194
+ constructor(message?: string);
195
+ }
196
+ declare class LlmContextOverflowError extends LlmError {
197
+ constructor(message?: string);
198
+ }
199
+ declare class SessionError extends LynxError {
200
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
201
+ }
202
+ declare class SessionNotFoundError extends SessionError {
203
+ constructor(sessionId: string);
204
+ }
205
+ declare class SessionLockedError extends SessionError {
206
+ constructor(sessionId: string);
207
+ }
208
+ declare class AgentError extends LynxError {
209
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
210
+ }
211
+ declare class PluginError extends LynxError {
212
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
213
+ }
214
+ declare class PluginLoadError extends PluginError {
215
+ constructor(pluginName: string, cause?: unknown);
216
+ }
217
+ declare class PluginHookError extends PluginError {
218
+ constructor(hookName: string, cause?: unknown);
219
+ }
220
+ declare class ChannelError extends LynxError {
221
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
222
+ }
223
+ declare class ConfigError extends LynxError {
224
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
225
+ }
226
+ declare class StorageError extends LynxError {
227
+ constructor(message: string, opts?: Partial<LynxErrorOptions>);
228
+ }
229
+ declare class StorageCorruptedError extends StorageError {
230
+ constructor(message?: string);
231
+ }
232
+ declare class StorageFullError extends StorageError {
233
+ constructor(message?: string);
234
+ }
235
+ interface ErrorEnvelope {
236
+ category: ErrorCategory;
237
+ severity: ErrorSeverity;
238
+ recoverable: boolean;
239
+ retryable: boolean;
240
+ /** Machine‑readable error code, e.g. "LLM_RATE_LIMIT". */
241
+ code: string;
242
+ /** Human‑readable message. */
243
+ message: string;
244
+ /** Chained cause, if this error wraps another. */
245
+ cause?: ErrorEnvelope;
246
+ /** Opaque trace id for correlating logs with user reports. */
247
+ traceId?: string;
248
+ /** Current operation span (agent_loop / tool_exec / model_call). */
249
+ spanId?: string;
250
+ /** Session this error occurred in, if applicable. */
251
+ sessionId?: string;
252
+ /** Unix ms when the error was captured. */
253
+ wallTime?: number;
254
+ }
255
+ /** Lift any Error into a safe ErrorEnvelope for cross‑boundary transport. */
256
+ declare function toErrorEnvelope(err: unknown, overrides?: Partial<ErrorEnvelope>): ErrorEnvelope;
257
+ /**
258
+ * Throw this when a function body is intentionally not implemented yet.
259
+ * CI detects remaining `NotImplementedError` throws and fails the Phase gate.
260
+ */
261
+ declare class NotImplementedError extends Error {
262
+ constructor(feature: string);
263
+ }
264
+ //#endregion
265
+ //#region src/paths.d.ts
266
+ /**
267
+ * Centralised path resolution for all Lynx data directories.
268
+ *
269
+ * Default root is `~/.lynx` (or `%USERPROFILE%/.lynx` on Windows).
270
+ * Every sub‑directory can be overridden individually via environment variables
271
+ * so that state, logs, config, and skills can live on separate volumes.
272
+ */
273
+ interface LynxPaths {
274
+ /** Root data directory (~/.lynx or $LYNX_HOME). */
275
+ home: string;
276
+ /** Main JSON configuration file. */
277
+ configFile: string;
278
+ /** User preference file (theme, keybinds). */
279
+ settingsFile: string;
280
+ /** TUI‑specific preferences (survive across projects). */
281
+ tuiFile: string;
282
+ /** SQLite state database path. */
283
+ stateDb: string;
284
+ /** Directory holding per‑session JSON files. */
285
+ sessionsDir: string;
286
+ /** Log output directory. */
287
+ logDir: string;
288
+ /** Security audit log (JSONL). */
289
+ auditLog: string;
290
+ /** Capacity memory records. */
291
+ memoryDir: string;
292
+ /** Workspace snapshots (git side‑repo). */
293
+ snapshotsDir: string;
294
+ /** User‑level skills. */
295
+ skillsDir: string;
296
+ /** Shell completion cache. */
297
+ completionsDir: string;
298
+ /** Input history file. */
299
+ composerHistory: string;
300
+ /** Ctrl+S stash file. */
301
+ composerStash: string;
302
+ /** Update concurrency lock file. */
303
+ updateLock: string;
304
+ }
305
+ /**
306
+ * Resolve every data path from environment variables.
307
+ * Called once at startup; result is immutable for the lifetime of the process.
308
+ */
309
+ declare function resolvePaths(env?: NodeJS.ProcessEnv): LynxPaths;
310
+ //#endregion
311
+ //#region src/db.d.ts
312
+ interface DbConfig {
313
+ /** Absolute path to the .db file. */
314
+ dbPath: string;
315
+ /** If true (default), journal_mode = WAL. */
316
+ walMode?: boolean;
317
+ }
318
+ /**
319
+ * Open (or create) the Lynx state database with WAL mode enabled.
320
+ * Call this once per process in the bootstrap phase.
321
+ */
322
+ declare function openDatabase(config: DbConfig): Database$1.Database;
323
+ //#endregion
324
+ //#region src/migrate.d.ts
325
+ interface Migration {
326
+ /** Monotonically‑increasing schema version. */
327
+ version: number;
328
+ /** Human‑readable summary of what this migration does. */
329
+ description: string;
330
+ /** SQL statements executed inside a transaction. */
331
+ sql: string;
332
+ /** Optional rollback SQL. If omitted, a failed migration leaves the DB dirty. */
333
+ rollback?: string;
334
+ }
335
+ declare const MIGRATIONS: Migration[];
336
+ /** The schema version this build of Lynx expects. */
337
+ declare const EXPECTED_VERSION: number;
338
+ /**
339
+ * Apply any pending migrations to bring `db` up to EXPECTED_VERSION.
340
+ * Safe to call on every startup — no‑op if already current.
341
+ */
342
+ declare function migrate(db: Database$1.Database): void;
343
+ //#endregion
344
+ export { AgentError, ChannelError, ConfigError, type ContentBlock, type Database, type DbConfig, EXPECTED_VERSION, type ErrorCategory, type ErrorEnvelope, type ErrorSeverity, LlmAuthError, LlmContextOverflowError, LlmError, LlmRateLimitError, LynxError, type LynxPaths, MIGRATIONS, type Message, type MessageId, type Migration, NotImplementedError, PluginError, PluginHookError, PluginLoadError, type ReasoningBlock, type Session, SessionError, type SessionId, SessionLockedError, type SessionMetadata, SessionNotFoundError, StorageCorruptedError, StorageError, StorageFullError, type TextBlock, ToolAbortedError, type ToolCall, ToolError, ToolPermissionError, type ToolResult, type ToolResultBlock, ToolTimeoutError, type ToolUseBlock, asMessageId, asSessionId, migrate, openDatabase, resolvePaths, toErrorEnvelope };
345
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/errors.ts","../src/paths.ts","../src/db.ts","../src/migrate.ts"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,452 @@
1
+ import { homedir } from "node:os";
2
+ import { dirname, join } from "node:path";
3
+ import Database from "better-sqlite3";
4
+ import { mkdirSync } from "node:fs";
5
+ //#region src/types.ts
6
+ /** Create a new SessionId from a UUID string. */
7
+ function asSessionId(id) {
8
+ return id;
9
+ }
10
+ /** Create a new MessageId from a UUID string. */
11
+ function asMessageId(id) {
12
+ return id;
13
+ }
14
+ //#endregion
15
+ //#region src/errors.ts
16
+ var LynxError = class extends Error {
17
+ /** Which subsystem raised this error. */
18
+ category;
19
+ /** Whether the system can recover without user intervention. */
20
+ recoverable;
21
+ /** Whether retrying the same operation might succeed. */
22
+ retryable;
23
+ /** Whether the message should be shown to the user. */
24
+ userVisible;
25
+ /** Pointer to a /doctor check (e.g. "storage_migration_failed"). */
26
+ diagnosticHint;
27
+ constructor(message, opts) {
28
+ super(message);
29
+ this.name = "LynxError";
30
+ this.category = opts.category;
31
+ this.recoverable = opts.recoverable ?? false;
32
+ this.retryable = opts.retryable ?? false;
33
+ this.userVisible = opts.userVisible ?? true;
34
+ this.diagnosticHint = opts.diagnosticHint;
35
+ }
36
+ };
37
+ var ToolError = class extends LynxError {
38
+ constructor(message, opts) {
39
+ super(message, {
40
+ category: "tool",
41
+ recoverable: false,
42
+ retryable: false,
43
+ ...opts
44
+ });
45
+ this.name = "ToolError";
46
+ }
47
+ };
48
+ var ToolTimeoutError = class extends ToolError {
49
+ constructor(message = "Tool execution timed out (60s)") {
50
+ super(message, {
51
+ userVisible: false,
52
+ diagnosticHint: "tool_timeout"
53
+ });
54
+ this.name = "ToolTimeoutError";
55
+ }
56
+ };
57
+ var ToolAbortedError = class extends ToolError {
58
+ constructor(message = "Tool execution was cancelled") {
59
+ super(message, { userVisible: true });
60
+ this.name = "ToolAbortedError";
61
+ }
62
+ };
63
+ var ToolPermissionError = class extends ToolError {
64
+ constructor(message = "Permission denied for tool execution") {
65
+ super(message, { userVisible: true });
66
+ this.name = "ToolPermissionError";
67
+ }
68
+ };
69
+ var LlmError = class extends LynxError {
70
+ constructor(message, opts) {
71
+ super(message, {
72
+ category: "llm",
73
+ recoverable: true,
74
+ retryable: true,
75
+ ...opts
76
+ });
77
+ this.name = "LlmError";
78
+ }
79
+ };
80
+ var LlmRateLimitError = class extends LlmError {
81
+ /** HTTP status code (429 for rate limit, 529 for overload). */
82
+ status;
83
+ constructor(message = "LLM rate limited (429 / 529)", status = 429) {
84
+ super(message, { diagnosticHint: "llm_rate_limit" });
85
+ this.name = "LlmRateLimitError";
86
+ this.status = status;
87
+ }
88
+ };
89
+ var LlmAuthError = class extends LlmError {
90
+ constructor(message = "LLM authentication failed (401 / 403)") {
91
+ super(message, {
92
+ recoverable: true,
93
+ retryable: false,
94
+ diagnosticHint: "llm_auth"
95
+ });
96
+ this.name = "LlmAuthError";
97
+ }
98
+ };
99
+ var LlmContextOverflowError = class extends LlmError {
100
+ constructor(message = "Prompt exceeds model context window") {
101
+ super(message, {
102
+ recoverable: true,
103
+ retryable: true,
104
+ diagnosticHint: "llm_context_overflow"
105
+ });
106
+ this.name = "LlmContextOverflowError";
107
+ }
108
+ };
109
+ var SessionError = class extends LynxError {
110
+ constructor(message, opts) {
111
+ super(message, {
112
+ category: "session",
113
+ recoverable: false,
114
+ retryable: false,
115
+ ...opts
116
+ });
117
+ this.name = "SessionError";
118
+ }
119
+ };
120
+ var SessionNotFoundError = class extends SessionError {
121
+ constructor(sessionId) {
122
+ super(`Session not found: ${sessionId}`, { userVisible: true });
123
+ this.name = "SessionNotFoundError";
124
+ }
125
+ };
126
+ var SessionLockedError = class extends SessionError {
127
+ constructor(sessionId) {
128
+ super(`Session locked (concurrent write): ${sessionId}`, {
129
+ recoverable: true,
130
+ retryable: true
131
+ });
132
+ this.name = "SessionLockedError";
133
+ }
134
+ };
135
+ var AgentError = class extends LynxError {
136
+ constructor(message, opts) {
137
+ super(message, {
138
+ category: "llm",
139
+ recoverable: true,
140
+ retryable: false,
141
+ ...opts
142
+ });
143
+ this.name = "AgentError";
144
+ }
145
+ };
146
+ var PluginError = class extends LynxError {
147
+ constructor(message, opts) {
148
+ super(message, {
149
+ category: "plugin",
150
+ recoverable: true,
151
+ retryable: false,
152
+ ...opts
153
+ });
154
+ this.name = "PluginError";
155
+ }
156
+ };
157
+ var PluginLoadError = class extends PluginError {
158
+ constructor(pluginName, cause) {
159
+ super(`Plugin "${pluginName}" failed to load: ${String(cause)}`, { userVisible: true });
160
+ this.name = "PluginLoadError";
161
+ }
162
+ };
163
+ var PluginHookError = class extends PluginError {
164
+ constructor(hookName, cause) {
165
+ super(`Hook "${hookName}" threw: ${String(cause)}`, { userVisible: false });
166
+ this.name = "PluginHookError";
167
+ }
168
+ };
169
+ var ChannelError = class extends LynxError {
170
+ constructor(message, opts) {
171
+ super(message, {
172
+ category: "channel",
173
+ recoverable: true,
174
+ retryable: true,
175
+ ...opts
176
+ });
177
+ this.name = "ChannelError";
178
+ }
179
+ };
180
+ var ConfigError = class extends LynxError {
181
+ constructor(message, opts) {
182
+ super(message, {
183
+ category: "config",
184
+ recoverable: false,
185
+ retryable: false,
186
+ ...opts
187
+ });
188
+ this.name = "ConfigError";
189
+ }
190
+ };
191
+ var StorageError = class extends LynxError {
192
+ constructor(message, opts) {
193
+ super(message, {
194
+ category: "storage",
195
+ recoverable: false,
196
+ retryable: false,
197
+ ...opts
198
+ });
199
+ this.name = "StorageError";
200
+ }
201
+ };
202
+ var StorageCorruptedError = class extends StorageError {
203
+ constructor(message = "Database file is corrupted") {
204
+ super(message, { diagnosticHint: "storage_corrupted" });
205
+ this.name = "StorageCorruptedError";
206
+ }
207
+ };
208
+ var StorageFullError = class extends StorageError {
209
+ constructor(message = "Disk full — cannot write to storage") {
210
+ super(message, {
211
+ userVisible: true,
212
+ diagnosticHint: "storage_full"
213
+ });
214
+ this.name = "StorageFullError";
215
+ }
216
+ };
217
+ /** Lift any Error into a safe ErrorEnvelope for cross‑boundary transport. */
218
+ function toErrorEnvelope(err, overrides) {
219
+ if (err instanceof LynxError) return {
220
+ category: err.category,
221
+ severity: "error",
222
+ recoverable: err.recoverable,
223
+ retryable: err.retryable,
224
+ code: err.name.toUpperCase(),
225
+ message: err.message,
226
+ wallTime: Date.now(),
227
+ ...overrides
228
+ };
229
+ if (err instanceof Error) return {
230
+ category: "storage",
231
+ severity: "error",
232
+ recoverable: false,
233
+ retryable: false,
234
+ code: "UNKNOWN",
235
+ message: err.message,
236
+ wallTime: Date.now(),
237
+ ...overrides
238
+ };
239
+ return {
240
+ category: "storage",
241
+ severity: "fatal",
242
+ recoverable: false,
243
+ retryable: false,
244
+ code: "UNKNOWN",
245
+ message: String(err),
246
+ wallTime: Date.now(),
247
+ ...overrides
248
+ };
249
+ }
250
+ /**
251
+ * Throw this when a function body is intentionally not implemented yet.
252
+ * CI detects remaining `NotImplementedError` throws and fails the Phase gate.
253
+ */
254
+ var NotImplementedError = class extends Error {
255
+ constructor(feature) {
256
+ super(`Not implemented: ${feature}`);
257
+ this.name = "NotImplementedError";
258
+ }
259
+ };
260
+ //#endregion
261
+ //#region src/paths.ts
262
+ /**
263
+ * Centralised path resolution for all Lynx data directories.
264
+ *
265
+ * Default root is `~/.lynx` (or `%USERPROFILE%/.lynx` on Windows).
266
+ * Every sub‑directory can be overridden individually via environment variables
267
+ * so that state, logs, config, and skills can live on separate volumes.
268
+ */
269
+ /**
270
+ * Normalise path separators to forward slashes.
271
+ * Node.js on Windows accepts both `C:\Users` and `C:/Users`,
272
+ * but we want consistent POSIX‑style paths across the codebase.
273
+ */
274
+ function posix(p) {
275
+ return p.replace(/\\/g, "/");
276
+ }
277
+ /** Default data root. */
278
+ const DEFAULT_HOME = posix(join(homedir(), ".lynx"));
279
+ /**
280
+ * Resolve every data path from environment variables.
281
+ * Called once at startup; result is immutable for the lifetime of the process.
282
+ */
283
+ function resolvePaths(env = process.env) {
284
+ const home = env.LYNX_HOME ?? DEFAULT_HOME;
285
+ const stateDir = env.LYNX_STATE_DIR ?? posix(join(home, "sessions"));
286
+ const logDir = env.LYNX_LOG_DIR ?? posix(join(home, "logs"));
287
+ return {
288
+ home,
289
+ configFile: env.LYNX_CONFIG_PATH ?? posix(join(home, "config.json")),
290
+ settingsFile: posix(join(home, "settings.json")),
291
+ tuiFile: posix(join(home, "tui.json")),
292
+ stateDb: posix(join(home, "state.db")),
293
+ sessionsDir: stateDir,
294
+ logDir,
295
+ auditLog: posix(join(home, "audit.log")),
296
+ memoryDir: posix(join(home, "memory")),
297
+ snapshotsDir: posix(join(home, "snapshots")),
298
+ skillsDir: posix(join(home, "skills")),
299
+ completionsDir: posix(join(home, "completions")),
300
+ composerHistory: posix(join(home, "composer_history.txt")),
301
+ composerStash: posix(join(home, "composer_stash.jsonl")),
302
+ updateLock: posix(join(home, ".update.lock"))
303
+ };
304
+ }
305
+ //#endregion
306
+ //#region src/db.ts
307
+ /**
308
+ * Single entry‑point for opening the Lynx SQLite database.
309
+ *
310
+ * Every WAL‑mode pragma is set here so that all consumers (SessionManager,
311
+ * PluginRegistry, TaskManager) share the same connection settings without
312
+ * repeating the configuration.
313
+ */
314
+ /** Wait up to 5 seconds when a write lock is contended. */
315
+ const BUSY_TIMEOUT_MS = 5e3;
316
+ /** Maximum WAL file size before auto‑checkpoint (64 MiB). */
317
+ const JOURNAL_SIZE_LIMIT_BYTES = 67108864;
318
+ /** Page cache size in KB. Negative value = KB, so -8000 = 8 MiB. */
319
+ const CACHE_SIZE_KB = -8e3;
320
+ /** Memory‑mapped I/O window (256 MiB). */
321
+ const MMAP_SIZE_BYTES = 268435456;
322
+ /** Trigger passive checkpoint every N write operations. */
323
+ const WAL_AUTOCHECKPOINT = 1e3;
324
+ /**
325
+ * Open (or create) the Lynx state database with WAL mode enabled.
326
+ * Call this once per process in the bootstrap phase.
327
+ */
328
+ function openDatabase(config) {
329
+ mkdirSync(dirname(config.dbPath), {
330
+ mode: 448,
331
+ recursive: true
332
+ });
333
+ const db = new Database(config.dbPath);
334
+ if (config.walMode !== false) db.pragma("journal_mode = WAL");
335
+ db.pragma("synchronous = NORMAL");
336
+ db.pragma("foreign_keys = ON");
337
+ db.pragma(`busy_timeout = ${BUSY_TIMEOUT_MS}`);
338
+ db.pragma(`journal_size_limit = ${JOURNAL_SIZE_LIMIT_BYTES}`);
339
+ db.pragma(`cache_size = ${CACHE_SIZE_KB}`);
340
+ db.pragma(`mmap_size = ${MMAP_SIZE_BYTES}`);
341
+ db.pragma(`wal_autocheckpoint = ${WAL_AUTOCHECKPOINT}`);
342
+ return db;
343
+ }
344
+ //#endregion
345
+ //#region src/migrate.ts
346
+ const MIGRATIONS = [
347
+ {
348
+ version: 1,
349
+ description: "Initial schema: sessions",
350
+ sql: `
351
+ CREATE TABLE IF NOT EXISTS sessions (
352
+ id TEXT PRIMARY KEY,
353
+ label TEXT NOT NULL,
354
+ workspace TEXT NOT NULL,
355
+ parent_id TEXT,
356
+ forked_from_message_count INTEGER,
357
+ message_count INTEGER DEFAULT 0,
358
+ metadata TEXT NOT NULL DEFAULT '{}',
359
+ created_at INTEGER NOT NULL,
360
+ updated_at INTEGER NOT NULL,
361
+ FOREIGN KEY (parent_id) REFERENCES sessions(id) ON DELETE SET NULL
362
+ );
363
+
364
+ CREATE INDEX IF NOT EXISTS idx_sessions_updated_at
365
+ ON sessions(updated_at DESC);
366
+
367
+ CREATE INDEX IF NOT EXISTS idx_sessions_parent_id
368
+ ON sessions(parent_id);
369
+ `
370
+ },
371
+ {
372
+ version: 2,
373
+ description: "Draft auto‑save table",
374
+ sql: `
375
+ CREATE TABLE IF NOT EXISTS drafts (
376
+ session_id TEXT PRIMARY KEY,
377
+ messages_json TEXT NOT NULL,
378
+ updated_at INTEGER NOT NULL,
379
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
380
+ );
381
+ `,
382
+ rollback: "DROP TABLE IF EXISTS drafts;"
383
+ },
384
+ {
385
+ version: 3,
386
+ description: "Messages persistence table",
387
+ sql: `
388
+ CREATE TABLE IF NOT EXISTS messages (
389
+ id TEXT PRIMARY KEY,
390
+ session_id TEXT NOT NULL,
391
+ role TEXT NOT NULL CHECK(role IN ('user', 'assistant', 'system')),
392
+ content_json TEXT NOT NULL,
393
+ turn_index INTEGER NOT NULL DEFAULT 0,
394
+ timestamp INTEGER NOT NULL,
395
+ FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
396
+ );
397
+
398
+ CREATE INDEX IF NOT EXISTS idx_messages_session_id
399
+ ON messages(session_id);
400
+
401
+ CREATE INDEX IF NOT EXISTS idx_messages_session_turn
402
+ ON messages(session_id, turn_index);
403
+ `,
404
+ rollback: "DROP TABLE IF EXISTS messages;"
405
+ }
406
+ ];
407
+ /** The schema version this build of Lynx expects. */
408
+ const EXPECTED_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
409
+ /**
410
+ * Apply any pending migrations to bring `db` up to EXPECTED_VERSION.
411
+ * Safe to call on every startup — no‑op if already current.
412
+ */
413
+ function migrate(db) {
414
+ runMigrations(db, MIGRATIONS, EXPECTED_VERSION);
415
+ }
416
+ /**
417
+ * Run migrations with an explicit list and target version.
418
+ * Exported for testability — production code should use `migrate()`.
419
+ */
420
+ function runMigrations(db, migrations, expectedVersion) {
421
+ const currentVersion = db.pragma("user_version", { simple: true });
422
+ if (currentVersion > expectedVersion) throw new StorageError(`Database schema v${currentVersion} is newer than this Lynx build expects (v${expectedVersion}). Please upgrade Lynx to the latest version.`, {
423
+ recoverable: false,
424
+ retryable: false,
425
+ userVisible: true
426
+ });
427
+ if (currentVersion === expectedVersion) return;
428
+ const pending = migrations.filter((m) => m.version > currentVersion);
429
+ for (const migration of pending) {
430
+ const apply = db.transaction(() => {
431
+ db.exec(migration.sql);
432
+ db.pragma(`user_version = ${migration.version}`);
433
+ });
434
+ try {
435
+ apply();
436
+ } catch (err) {
437
+ if (migration.rollback) try {
438
+ db.exec(migration.rollback);
439
+ } catch {}
440
+ throw new StorageError(`Migration v${migration.version} (${migration.description}) failed: ${err.message}`, {
441
+ recoverable: false,
442
+ retryable: false,
443
+ userVisible: true,
444
+ diagnosticHint: "storage_migration_failed"
445
+ });
446
+ }
447
+ }
448
+ }
449
+ //#endregion
450
+ export { AgentError, ChannelError, ConfigError, EXPECTED_VERSION, LlmAuthError, LlmContextOverflowError, LlmError, LlmRateLimitError, LynxError, MIGRATIONS, NotImplementedError, PluginError, PluginHookError, PluginLoadError, SessionError, SessionLockedError, SessionNotFoundError, StorageCorruptedError, StorageError, StorageFullError, ToolAbortedError, ToolError, ToolPermissionError, ToolTimeoutError, asMessageId, asSessionId, migrate, openDatabase, resolvePaths, toErrorEnvelope };
451
+
452
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/types.ts","../src/errors.ts","../src/paths.ts","../src/db.ts","../src/migrate.ts"],"sourcesContent":["/**\n * Core type definitions for the Lynx agent system.\n * All other packages depend on these interfaces — keep them stable.\n */\n\n// ── Identifiers ────────────────────────────────────\n\n/** Opaque session identifier (UUID v4). */\nexport type SessionId = string & { readonly __brand: \"SessionId\" };\n\n/** Opaque message identifier (UUID v4). */\nexport type MessageId = string & { readonly __brand: \"MessageId\" };\n\n// ── Content blocks ─────────────────────────────────\n\n/**\n * Discriminated union of all content types an LLM can emit or receive.\n * The `reasoning` variant captures chain-of-thought from models like\n * DeepSeek R1 and OpenAI o1.\n */\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ReasoningBlock;\n\nexport interface TextBlock {\n type: \"text\";\n /** Plain text content emitted by the LLM. */\n text: string;\n}\n\nexport interface ToolUseBlock {\n type: \"tool_use\";\n /** Unique ID for matching tool results back to calls. */\n id: string;\n /** Name of the tool being invoked. */\n name: string;\n /** Arguments passed to the tool. */\n input: Record<string, unknown>;\n}\n\nexport interface ToolResultBlock {\n type: \"tool_result\";\n /** Matches the `id` of the corresponding `tool_use` block. */\n toolUseId: string;\n /** Text or structured output from the tool execution. */\n content: string;\n /** Set to true when the tool execution failed. */\n isError?: boolean;\n}\n\nexport interface ReasoningBlock {\n type: \"reasoning\";\n /** Chain-of-thought text (e.g. DeepSeek R1, OpenAI o1). */\n text: string;\n}\n\n// ── Messages ───────────────────────────────────────\n\nexport interface Message {\n /** Unique identifier (UUID v4). */\n id: MessageId;\n /** Who sent this message — user, assistant, or system. */\n role: \"user\" | \"assistant\" | \"system\";\n /** Content blocks making up the message body. */\n content: ContentBlock[];\n /** Unix timestamp in milliseconds. */\n timestamp: number;\n /** Zero-based index within the session's message list. */\n turnIndex: number;\n}\n\n// ── Sessions ───────────────────────────────────────\n\n/**\n * Flexible metadata bag attached to every session.\n * Keys are strings to allow extension without breaking DB rows.\n */\nexport interface SessionMetadata {\n /** Whether the last session run was interrupted (crash / SIGKILL). */\n crashed?: boolean;\n /** Model identifier used for this session (e.g. \"deepseek-v3\"). */\n model?: string;\n /** Active permission mode when the session was last saved. */\n permissionMode?: string;\n /** Additional entries injected by plugins or migrations. */\n [key: string]: unknown;\n}\n\nexport interface Session {\n /** Unique session identifier (UUID v4). */\n id: SessionId;\n /** User-visible label shown in the session picker. */\n label: string;\n /** Absolute path to the workspace directory. */\n workspace: string;\n /** Ordered message history. */\n messages: Message[];\n /** The session this one was forked from, if any. */\n parentSessionId?: SessionId;\n /** Message count at the time of fork. */\n forkedFromMessageCount?: number;\n /** Unix ms — set on create. */\n createdAt: number;\n /** Unix ms — bumped on every mutation. */\n updatedAt: number;\n /** Flexible metadata bag (model, permission mode, crash state, etc.). */\n metadata: SessionMetadata;\n}\n\n// ── Tool invocation (minimal forward-declaration) ───\n\n/**\n * Serializable record of a tool being invoked.\n * The full tool descriptor lives in @lynx/tools; core only stores\n * the invocation trace needed for session replay.\n */\nexport interface ToolCall {\n /** Matches the `id` in `ToolUseBlock`. */\n id: string;\n /** Name of the tool being invoked. */\n name: string;\n /** Arguments supplied by the LLM. */\n input: Record<string, unknown>;\n /** Unix ms when the tool started executing. */\n startedAt: number;\n /** Unix ms when the tool finished (undefined if still running). */\n finishedAt?: number;\n}\n\nexport interface ToolResult {\n /** Matches `ToolCall.id`. */\n toolCallId: string;\n /** Text or structured output from the tool. */\n output: string;\n /** Whether the tool execution ended in an error. */\n isError: boolean;\n /** Unix ms when execution completed. */\n finishedAt: number;\n}\n\n// ── Convenience helpers ────────────────────────────\n\n/** Create a new SessionId from a UUID string. */\nexport function asSessionId(id: string): SessionId {\n return id as SessionId;\n}\n\n/** Create a new MessageId from a UUID string. */\nexport function asMessageId(id: string): MessageId {\n return id as MessageId;\n}\n","/* oxlint-disable max-classes-per-file — error taxonomy by design */\n/**\n * Layered error system for Lynx.\n *\n * Layer 1 — LynxError subclasses: typed, machine‑actionable errors\n * each carries recoverable / retryable / userVisible / diagnosticHint.\n * Layer 2 — ErrorEnvelope: cross‑boundary wrapper with category + severity.\n * Layer 3 — Top‑level catch in lynx‑cli/entry.ts formats and routes.\n */\n\n// ── Error categories ───────────────────────────────\n\n/**\n * Which subsystem raised the error.\n * Used by error reporters and /doctor to route diagnostics.\n */\nexport type ErrorCategory =\n | \"tool\"\n | \"llm\"\n | \"session\"\n | \"plugin\"\n | \"channel\"\n | \"config\"\n | \"storage\";\n\n/**\n * Severity level for log routing and user notification.\n * \"debug\"/\"info\" are suppressed in production; \"fatal\" triggers process exit.\n */\nexport type ErrorSeverity = \"debug\" | \"info\" | \"warn\" | \"error\" | \"fatal\";\n\n// ── Layer 1: LynxError base ────────────────────────\n\n/** Configuration for constructing a LynxError. */\nexport interface LynxErrorOptions {\n /** Which subsystem raised this error. */\n category: ErrorCategory;\n /** Whether the system can recover without user intervention. */\n recoverable?: boolean;\n /** Whether retrying the same operation might succeed. */\n retryable?: boolean;\n /** Whether the message should be shown to the user. */\n userVisible?: boolean;\n /** Pointer to a /doctor check (e.g. \"storage_migration_failed\"). */\n diagnosticHint?: string;\n}\n\nexport class LynxError extends Error {\n /** Which subsystem raised this error. */\n readonly category: ErrorCategory;\n /** Whether the system can recover without user intervention. */\n readonly recoverable: boolean;\n /** Whether retrying the same operation might succeed. */\n readonly retryable: boolean;\n /** Whether the message should be shown to the user. */\n readonly userVisible: boolean;\n /** Pointer to a /doctor check (e.g. \"storage_migration_failed\"). */\n readonly diagnosticHint: string | undefined;\n\n constructor(message: string, opts: LynxErrorOptions) {\n super(message);\n this.name = \"LynxError\";\n this.category = opts.category;\n this.recoverable = opts.recoverable ?? false;\n this.retryable = opts.retryable ?? false;\n this.userVisible = opts.userVisible ?? true;\n this.diagnosticHint = opts.diagnosticHint;\n }\n}\n\n// ── Layer 1: Subclasses ────────────────────────────\n\nexport class ToolError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"tool\", recoverable: false, retryable: false, ...opts });\n this.name = \"ToolError\";\n }\n}\n\nexport class ToolTimeoutError extends ToolError {\n constructor(message = \"Tool execution timed out (60s)\") {\n super(message, { userVisible: false, diagnosticHint: \"tool_timeout\" });\n this.name = \"ToolTimeoutError\";\n }\n}\n\nexport class ToolAbortedError extends ToolError {\n constructor(message = \"Tool execution was cancelled\") {\n super(message, { userVisible: true });\n this.name = \"ToolAbortedError\";\n }\n}\n\nexport class ToolPermissionError extends ToolError {\n constructor(message = \"Permission denied for tool execution\") {\n super(message, { userVisible: true });\n this.name = \"ToolPermissionError\";\n }\n}\n\nexport class LlmError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"llm\", recoverable: true, retryable: true, ...opts });\n this.name = \"LlmError\";\n }\n}\n\nexport class LlmRateLimitError extends LlmError {\n /** HTTP status code (429 for rate limit, 529 for overload). */\n status: number;\n\n constructor(message = \"LLM rate limited (429 / 529)\", status = 429) {\n super(message, { diagnosticHint: \"llm_rate_limit\" });\n this.name = \"LlmRateLimitError\";\n this.status = status;\n }\n}\n\nexport class LlmAuthError extends LlmError {\n constructor(message = \"LLM authentication failed (401 / 403)\") {\n super(message, { recoverable: true, retryable: false, diagnosticHint: \"llm_auth\" });\n this.name = \"LlmAuthError\";\n }\n}\n\nexport class LlmContextOverflowError extends LlmError {\n constructor(message = \"Prompt exceeds model context window\") {\n super(message, { recoverable: true, retryable: true, diagnosticHint: \"llm_context_overflow\" });\n this.name = \"LlmContextOverflowError\";\n }\n}\n\nexport class SessionError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"session\", recoverable: false, retryable: false, ...opts });\n this.name = \"SessionError\";\n }\n}\n\nexport class SessionNotFoundError extends SessionError {\n constructor(sessionId: string) {\n super(`Session not found: ${sessionId}`, { userVisible: true });\n this.name = \"SessionNotFoundError\";\n }\n}\n\nexport class SessionLockedError extends SessionError {\n constructor(sessionId: string) {\n super(`Session locked (concurrent write): ${sessionId}`, {\n recoverable: true,\n retryable: true,\n });\n this.name = \"SessionLockedError\";\n }\n}\n\nexport class AgentError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"llm\", recoverable: true, retryable: false, ...opts });\n this.name = \"AgentError\";\n }\n}\n\nexport class PluginError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"plugin\", recoverable: true, retryable: false, ...opts });\n this.name = \"PluginError\";\n }\n}\n\nexport class PluginLoadError extends PluginError {\n constructor(pluginName: string, cause?: unknown) {\n super(`Plugin \"${pluginName}\" failed to load: ${String(cause)}`, { userVisible: true });\n this.name = \"PluginLoadError\";\n }\n}\n\nexport class PluginHookError extends PluginError {\n constructor(hookName: string, cause?: unknown) {\n super(`Hook \"${hookName}\" threw: ${String(cause)}`, { userVisible: false });\n this.name = \"PluginHookError\";\n }\n}\n\nexport class ChannelError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"channel\", recoverable: true, retryable: true, ...opts });\n this.name = \"ChannelError\";\n }\n}\n\nexport class ConfigError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"config\", recoverable: false, retryable: false, ...opts });\n this.name = \"ConfigError\";\n }\n}\n\nexport class StorageError extends LynxError {\n constructor(message: string, opts?: Partial<LynxErrorOptions>) {\n super(message, { category: \"storage\", recoverable: false, retryable: false, ...opts });\n this.name = \"StorageError\";\n }\n}\n\nexport class StorageCorruptedError extends StorageError {\n constructor(message = \"Database file is corrupted\") {\n super(message, { diagnosticHint: \"storage_corrupted\" });\n this.name = \"StorageCorruptedError\";\n }\n}\n\nexport class StorageFullError extends StorageError {\n constructor(message = \"Disk full — cannot write to storage\") {\n super(message, { userVisible: true, diagnosticHint: \"storage_full\" });\n this.name = \"StorageFullError\";\n }\n}\n\n// ── Layer 2: ErrorEnvelope ─────────────────────────\n\nexport interface ErrorEnvelope {\n category: ErrorCategory;\n severity: ErrorSeverity;\n recoverable: boolean;\n retryable: boolean;\n /** Machine‑readable error code, e.g. \"LLM_RATE_LIMIT\". */\n code: string;\n /** Human‑readable message. */\n message: string;\n /** Chained cause, if this error wraps another. */\n cause?: ErrorEnvelope;\n /** Opaque trace id for correlating logs with user reports. */\n traceId?: string;\n /** Current operation span (agent_loop / tool_exec / model_call). */\n spanId?: string;\n /** Session this error occurred in, if applicable. */\n sessionId?: string;\n /** Unix ms when the error was captured. */\n wallTime?: number;\n}\n\n/** Lift any Error into a safe ErrorEnvelope for cross‑boundary transport. */\nexport function toErrorEnvelope(err: unknown, overrides?: Partial<ErrorEnvelope>): ErrorEnvelope {\n if (err instanceof LynxError) {\n return {\n category: err.category,\n severity: \"error\",\n recoverable: err.recoverable,\n retryable: err.retryable,\n code: err.name.toUpperCase(),\n message: err.message,\n wallTime: Date.now(),\n ...overrides,\n };\n }\n\n if (err instanceof Error) {\n return {\n category: \"storage\",\n severity: \"error\",\n recoverable: false,\n retryable: false,\n code: \"UNKNOWN\",\n message: err.message,\n wallTime: Date.now(),\n ...overrides,\n };\n }\n\n return {\n category: \"storage\",\n severity: \"fatal\",\n recoverable: false,\n retryable: false,\n code: \"UNKNOWN\",\n message: String(err),\n wallTime: Date.now(),\n ...overrides,\n };\n}\n\n// ── Development‑only marker ────────────────────────\n\n/**\n * Throw this when a function body is intentionally not implemented yet.\n * CI detects remaining `NotImplementedError` throws and fails the Phase gate.\n */\nexport class NotImplementedError extends Error {\n constructor(feature: string) {\n super(`Not implemented: ${feature}`);\n this.name = \"NotImplementedError\";\n }\n}\n","/**\n * Centralised path resolution for all Lynx data directories.\n *\n * Default root is `~/.lynx` (or `%USERPROFILE%/.lynx` on Windows).\n * Every sub‑directory can be overridden individually via environment variables\n * so that state, logs, config, and skills can live on separate volumes.\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n// ── Helpers ────────────────────────────────────────\n\n/**\n * Normalise path separators to forward slashes.\n * Node.js on Windows accepts both `C:\\Users` and `C:/Users`,\n * but we want consistent POSIX‑style paths across the codebase.\n */\nfunction posix(p: string): string {\n return p.replace(/\\\\/g, \"/\");\n}\n\n/** Default data root. */\nconst DEFAULT_HOME = posix(join(homedir(), \".lynx\"));\n\n// ── Public API ──────────────────────────────────────\n\nexport interface LynxPaths {\n /** Root data directory (~/.lynx or $LYNX_HOME). */\n home: string;\n /** Main JSON configuration file. */\n configFile: string;\n /** User preference file (theme, keybinds). */\n settingsFile: string;\n /** TUI‑specific preferences (survive across projects). */\n tuiFile: string;\n /** SQLite state database path. */\n stateDb: string;\n /** Directory holding per‑session JSON files. */\n sessionsDir: string;\n /** Log output directory. */\n logDir: string;\n /** Security audit log (JSONL). */\n auditLog: string;\n /** Capacity memory records. */\n memoryDir: string;\n /** Workspace snapshots (git side‑repo). */\n snapshotsDir: string;\n /** User‑level skills. */\n skillsDir: string;\n /** Shell completion cache. */\n completionsDir: string;\n /** Input history file. */\n composerHistory: string;\n /** Ctrl+S stash file. */\n composerStash: string;\n /** Update concurrency lock file. */\n updateLock: string;\n}\n\n/**\n * Resolve every data path from environment variables.\n * Called once at startup; result is immutable for the lifetime of the process.\n */\nexport function resolvePaths(env: NodeJS.ProcessEnv = process.env): LynxPaths {\n const home = env.LYNX_HOME ?? DEFAULT_HOME;\n const stateDir = env.LYNX_STATE_DIR ?? posix(join(home, \"sessions\"));\n const logDir = env.LYNX_LOG_DIR ?? posix(join(home, \"logs\"));\n\n return {\n home,\n configFile: env.LYNX_CONFIG_PATH ?? posix(join(home, \"config.json\")),\n settingsFile: posix(join(home, \"settings.json\")),\n tuiFile: posix(join(home, \"tui.json\")),\n stateDb: posix(join(home, \"state.db\")),\n sessionsDir: stateDir,\n logDir,\n auditLog: posix(join(home, \"audit.log\")),\n memoryDir: posix(join(home, \"memory\")),\n snapshotsDir: posix(join(home, \"snapshots\")),\n skillsDir: posix(join(home, \"skills\")),\n completionsDir: posix(join(home, \"completions\")),\n composerHistory: posix(join(home, \"composer_history.txt\")),\n composerStash: posix(join(home, \"composer_stash.jsonl\")),\n updateLock: posix(join(home, \".update.lock\")),\n };\n}\n","/**\n * Single entry‑point for opening the Lynx SQLite database.\n *\n * Every WAL‑mode pragma is set here so that all consumers (SessionManager,\n * PluginRegistry, TaskManager) share the same connection settings without\n * repeating the configuration.\n */\n\nimport Database from \"better-sqlite3\";\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\n// ── Constants ──────────────────────────────────────\n\n/** Wait up to 5 seconds when a write lock is contended. */\nconst BUSY_TIMEOUT_MS = 5_000;\n\n/** Maximum WAL file size before auto‑checkpoint (64 MiB). */\nconst JOURNAL_SIZE_LIMIT_BYTES = 67_108_864;\n\n/** Page cache size in KB. Negative value = KB, so -8000 = 8 MiB. */\nconst CACHE_SIZE_KB = -8_000;\n\n/** Memory‑mapped I/O window (256 MiB). */\nconst MMAP_SIZE_BYTES = 268_435_456;\n\n/** Trigger passive checkpoint every N write operations. */\nconst WAL_AUTOCHECKPOINT = 1000;\n\n// ── Configuration ──────────────────────────────────\n\nexport interface DbConfig {\n /** Absolute path to the .db file. */\n dbPath: string;\n /** If true (default), journal_mode = WAL. */\n walMode?: boolean;\n}\n\n// ── Public API ─────────────────────────────────────\n\n/**\n * Open (or create) the Lynx state database with WAL mode enabled.\n * Call this once per process in the bootstrap phase.\n */\nexport function openDatabase(config: DbConfig): Database.Database {\n // Ensure parent directory exists with restricted permissions\n const dir = dirname(config.dbPath);\n mkdirSync(dir, { mode: 0o700, recursive: true });\n\n const db = new Database(config.dbPath);\n\n // Enable WAL by default — critical for concurrent read/write workloads\n // (e.g. draft auto‑save doesn't block the TUI session list)\n if (config.walMode !== false) {\n db.pragma(\"journal_mode = WAL\");\n }\n\n db.pragma(\"synchronous = NORMAL\");\n db.pragma(\"foreign_keys = ON\");\n db.pragma(`busy_timeout = ${BUSY_TIMEOUT_MS}`);\n db.pragma(`journal_size_limit = ${JOURNAL_SIZE_LIMIT_BYTES}`);\n db.pragma(`cache_size = ${CACHE_SIZE_KB}`);\n db.pragma(`mmap_size = ${MMAP_SIZE_BYTES}`);\n db.pragma(`wal_autocheckpoint = ${WAL_AUTOCHECKPOINT}`);\n\n return db;\n}\n","/**\n * Forward‑only schema migration system for Lynx's SQLite database.\n *\n * Each migration runs inside its own transaction. The `user_version` pragma\n * tracks which version the database is at. If the on‑disk version is newer\n * than the code expects, we throw — the user must upgrade Lynx.\n */\n\nimport type Database from \"better-sqlite3\";\nimport { StorageError } from \"./errors.js\";\n\n// ── Types ──────────────────────────────────────────\n\nexport interface Migration {\n /** Monotonically‑increasing schema version. */\n version: number;\n /** Human‑readable summary of what this migration does. */\n description: string;\n /** SQL statements executed inside a transaction. */\n sql: string;\n /** Optional rollback SQL. If omitted, a failed migration leaves the DB dirty. */\n rollback?: string;\n}\n\n// ── Migration registry ─────────────────────────────\n\nexport const MIGRATIONS: Migration[] = [\n {\n version: 1,\n description: \"Initial schema: sessions\",\n sql: `\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n label TEXT NOT NULL,\n workspace TEXT NOT NULL,\n parent_id TEXT,\n forked_from_message_count INTEGER,\n message_count INTEGER DEFAULT 0,\n metadata TEXT NOT NULL DEFAULT '{}',\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n FOREIGN KEY (parent_id) REFERENCES sessions(id) ON DELETE SET NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_updated_at\n ON sessions(updated_at DESC);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_parent_id\n ON sessions(parent_id);\n `,\n },\n {\n version: 2,\n description: \"Draft auto‑save table\",\n sql: `\n CREATE TABLE IF NOT EXISTS drafts (\n session_id TEXT PRIMARY KEY,\n messages_json TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n );\n `,\n rollback: \"DROP TABLE IF EXISTS drafts;\",\n },\n {\n version: 3,\n description: \"Messages persistence table\",\n sql: `\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n role TEXT NOT NULL CHECK(role IN ('user', 'assistant', 'system')),\n content_json TEXT NOT NULL,\n turn_index INTEGER NOT NULL DEFAULT 0,\n timestamp INTEGER NOT NULL,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session_id\n ON messages(session_id);\n\n CREATE INDEX IF NOT EXISTS idx_messages_session_turn\n ON messages(session_id, turn_index);\n `,\n rollback: \"DROP TABLE IF EXISTS messages;\",\n },\n];\n\n/** The schema version this build of Lynx expects. */\nexport const EXPECTED_VERSION: number = MIGRATIONS[MIGRATIONS.length - 1].version;\n\n// ── Migration runner ───────────────────────────────\n\n/**\n * Apply any pending migrations to bring `db` up to EXPECTED_VERSION.\n * Safe to call on every startup — no‑op if already current.\n */\nexport function migrate(db: Database.Database): void {\n runMigrations(db, MIGRATIONS, EXPECTED_VERSION);\n}\n\n/**\n * Run migrations with an explicit list and target version.\n * Exported for testability — production code should use `migrate()`.\n */\nexport function runMigrations(\n db: Database.Database,\n migrations: Migration[],\n expectedVersion: number,\n): void {\n const currentVersion = db.pragma(\"user_version\", { simple: true }) as number;\n\n if (currentVersion > expectedVersion) {\n throw new StorageError(\n `Database schema v${currentVersion} is newer than this Lynx build expects (v${expectedVersion}). ` +\n \"Please upgrade Lynx to the latest version.\",\n { recoverable: false, retryable: false, userVisible: true },\n );\n }\n\n if (currentVersion === expectedVersion) {\n return;\n }\n\n const pending = migrations.filter((m) => m.version > currentVersion);\n\n for (const migration of pending) {\n const apply = db.transaction(() => {\n db.exec(migration.sql);\n db.pragma(`user_version = ${migration.version}`);\n });\n\n try {\n apply();\n } catch (err) {\n // Best‑effort rollback\n if (migration.rollback) {\n try {\n db.exec(migration.rollback);\n } catch {\n // Rollback itself failed — DB may be in an inconsistent state.\n // The user should restore from the pre‑migration backup.\n }\n }\n throw new StorageError(\n `Migration v${migration.version} (${migration.description}) failed: ${(err as Error).message}`,\n {\n recoverable: false,\n retryable: false,\n userVisible: true,\n diagnosticHint: \"storage_migration_failed\",\n },\n );\n }\n }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@24klynx/core",
3
+ "version": "0.1.0",
4
+ "description": "Shared types and error infrastructure — zero dependencies",
5
+ "type": "module",
6
+ "main": "./dist/index.mjs",
7
+ "types": "./dist/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "types": "./dist/index.d.mts"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "better-sqlite3": "^12.10.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/better-sqlite3": "^7.6.13",
19
+ "@types/node": "^25.9.1"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "scripts": {
28
+ "build": "tsdown --config-loader tsx",
29
+ "test": "vitest run --passWithNoTests",
30
+ "typecheck": "tsgo --noEmit"
31
+ }
32
+ }