kiro-memory 1.0.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.
- package/LICENSE +661 -0
- package/README.md +290 -0
- package/package.json +117 -0
- package/plugin/dist/cli/contextkit.js +1259 -0
- package/plugin/dist/hooks/agentSpawn.js +1187 -0
- package/plugin/dist/hooks/kiro-hooks.js +1184 -0
- package/plugin/dist/hooks/postToolUse.js +1219 -0
- package/plugin/dist/hooks/stop.js +1163 -0
- package/plugin/dist/hooks/userPromptSubmit.js +1152 -0
- package/plugin/dist/index.js +2103 -0
- package/plugin/dist/sdk/index.js +1083 -0
- package/plugin/dist/servers/mcp-server.js +266 -0
- package/plugin/dist/services/search/ChromaManager.js +357 -0
- package/plugin/dist/services/search/HybridSearch.js +502 -0
- package/plugin/dist/services/search/index.js +511 -0
- package/plugin/dist/services/sqlite/Database.js +625 -0
- package/plugin/dist/services/sqlite/Observations.js +46 -0
- package/plugin/dist/services/sqlite/Prompts.js +39 -0
- package/plugin/dist/services/sqlite/Search.js +143 -0
- package/plugin/dist/services/sqlite/Sessions.js +60 -0
- package/plugin/dist/services/sqlite/Summaries.js +44 -0
- package/plugin/dist/services/sqlite/index.js +951 -0
- package/plugin/dist/shared/paths.js +315 -0
- package/plugin/dist/types/worker-types.js +0 -0
- package/plugin/dist/utils/logger.js +222 -0
- package/plugin/dist/viewer.html +252 -0
- package/plugin/dist/viewer.js +23965 -0
- package/plugin/dist/worker-service.js +1782 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// src/shared/paths.ts
|
|
2
|
+
import { join as join2, dirname, basename } from "path";
|
|
3
|
+
import { homedir as homedir2 } from "os";
|
|
4
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
// src/utils/logger.ts
|
|
9
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
13
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
14
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
15
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
16
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
17
|
+
LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
|
|
18
|
+
return LogLevel2;
|
|
19
|
+
})(LogLevel || {});
|
|
20
|
+
var DEFAULT_DATA_DIR = join(homedir(), ".contextkit");
|
|
21
|
+
var Logger = class {
|
|
22
|
+
level = null;
|
|
23
|
+
useColor;
|
|
24
|
+
logFilePath = null;
|
|
25
|
+
logFileInitialized = false;
|
|
26
|
+
constructor() {
|
|
27
|
+
this.useColor = process.stdout.isTTY ?? false;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Initialize log file path and ensure directory exists (lazy initialization)
|
|
31
|
+
*/
|
|
32
|
+
ensureLogFileInitialized() {
|
|
33
|
+
if (this.logFileInitialized) return;
|
|
34
|
+
this.logFileInitialized = true;
|
|
35
|
+
try {
|
|
36
|
+
const logsDir = join(DEFAULT_DATA_DIR, "logs");
|
|
37
|
+
if (!existsSync(logsDir)) {
|
|
38
|
+
mkdirSync(logsDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
41
|
+
this.logFilePath = join(logsDir, `contextkit-${date}.log`);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error("[LOGGER] Failed to initialize log file:", error);
|
|
44
|
+
this.logFilePath = null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Lazy-load log level from settings file
|
|
49
|
+
*/
|
|
50
|
+
getLevel() {
|
|
51
|
+
if (this.level === null) {
|
|
52
|
+
try {
|
|
53
|
+
const settingsPath = join(DEFAULT_DATA_DIR, "settings.json");
|
|
54
|
+
if (existsSync(settingsPath)) {
|
|
55
|
+
const settingsData = readFileSync(settingsPath, "utf-8");
|
|
56
|
+
const settings = JSON.parse(settingsData);
|
|
57
|
+
const envLevel = (settings.CONTEXTKIT_LOG_LEVEL || "INFO").toUpperCase();
|
|
58
|
+
this.level = LogLevel[envLevel] ?? 1 /* INFO */;
|
|
59
|
+
} else {
|
|
60
|
+
this.level = 1 /* INFO */;
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
this.level = 1 /* INFO */;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return this.level;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create correlation ID for tracking an observation through the pipeline
|
|
70
|
+
*/
|
|
71
|
+
correlationId(sessionId, observationNum) {
|
|
72
|
+
return `obs-${sessionId}-${observationNum}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create session correlation ID
|
|
76
|
+
*/
|
|
77
|
+
sessionId(sessionId) {
|
|
78
|
+
return `session-${sessionId}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Format data for logging - create compact summaries instead of full dumps
|
|
82
|
+
*/
|
|
83
|
+
formatData(data) {
|
|
84
|
+
if (data === null || data === void 0) return "";
|
|
85
|
+
if (typeof data === "string") return data;
|
|
86
|
+
if (typeof data === "number") return data.toString();
|
|
87
|
+
if (typeof data === "boolean") return data.toString();
|
|
88
|
+
if (typeof data === "object") {
|
|
89
|
+
if (data instanceof Error) {
|
|
90
|
+
return this.getLevel() === 0 /* DEBUG */ ? `${data.message}
|
|
91
|
+
${data.stack}` : data.message;
|
|
92
|
+
}
|
|
93
|
+
if (Array.isArray(data)) {
|
|
94
|
+
return `[${data.length} items]`;
|
|
95
|
+
}
|
|
96
|
+
const keys = Object.keys(data);
|
|
97
|
+
if (keys.length === 0) return "{}";
|
|
98
|
+
if (keys.length <= 3) {
|
|
99
|
+
return JSON.stringify(data);
|
|
100
|
+
}
|
|
101
|
+
return `{${keys.length} keys: ${keys.slice(0, 3).join(", ")}...}`;
|
|
102
|
+
}
|
|
103
|
+
return String(data);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Format timestamp in local timezone (YYYY-MM-DD HH:MM:SS.mmm)
|
|
107
|
+
*/
|
|
108
|
+
formatTimestamp(date) {
|
|
109
|
+
const year = date.getFullYear();
|
|
110
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
111
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
112
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
113
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
114
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
115
|
+
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
|
116
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Core logging method
|
|
120
|
+
*/
|
|
121
|
+
log(level, component, message, context, data) {
|
|
122
|
+
if (level < this.getLevel()) return;
|
|
123
|
+
this.ensureLogFileInitialized();
|
|
124
|
+
const timestamp = this.formatTimestamp(/* @__PURE__ */ new Date());
|
|
125
|
+
const levelStr = LogLevel[level].padEnd(5);
|
|
126
|
+
const componentStr = component.padEnd(6);
|
|
127
|
+
let correlationStr = "";
|
|
128
|
+
if (context?.correlationId) {
|
|
129
|
+
correlationStr = `[${context.correlationId}] `;
|
|
130
|
+
} else if (context?.sessionId) {
|
|
131
|
+
correlationStr = `[session-${context.sessionId}] `;
|
|
132
|
+
}
|
|
133
|
+
let dataStr = "";
|
|
134
|
+
if (data !== void 0 && data !== null) {
|
|
135
|
+
if (data instanceof Error) {
|
|
136
|
+
dataStr = this.getLevel() === 0 /* DEBUG */ ? `
|
|
137
|
+
${data.message}
|
|
138
|
+
${data.stack}` : ` ${data.message}`;
|
|
139
|
+
} else if (this.getLevel() === 0 /* DEBUG */ && typeof data === "object") {
|
|
140
|
+
dataStr = "\n" + JSON.stringify(data, null, 2);
|
|
141
|
+
} else {
|
|
142
|
+
dataStr = " " + this.formatData(data);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
let contextStr = "";
|
|
146
|
+
if (context) {
|
|
147
|
+
const { sessionId, memorySessionId, correlationId, ...rest } = context;
|
|
148
|
+
if (Object.keys(rest).length > 0) {
|
|
149
|
+
const pairs = Object.entries(rest).map(([k, v]) => `${k}=${v}`);
|
|
150
|
+
contextStr = ` {${pairs.join(", ")}}`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const logLine = `[${timestamp}] [${levelStr}] [${componentStr}] ${correlationStr}${message}${contextStr}${dataStr}`;
|
|
154
|
+
if (this.logFilePath) {
|
|
155
|
+
try {
|
|
156
|
+
appendFileSync(this.logFilePath, logLine + "\n", "utf8");
|
|
157
|
+
} catch (error) {
|
|
158
|
+
process.stderr.write(`[LOGGER] Failed to write to log file: ${error}
|
|
159
|
+
`);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
process.stderr.write(logLine + "\n");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Public logging methods
|
|
166
|
+
debug(component, message, context, data) {
|
|
167
|
+
this.log(0 /* DEBUG */, component, message, context, data);
|
|
168
|
+
}
|
|
169
|
+
info(component, message, context, data) {
|
|
170
|
+
this.log(1 /* INFO */, component, message, context, data);
|
|
171
|
+
}
|
|
172
|
+
warn(component, message, context, data) {
|
|
173
|
+
this.log(2 /* WARN */, component, message, context, data);
|
|
174
|
+
}
|
|
175
|
+
error(component, message, context, data) {
|
|
176
|
+
this.log(3 /* ERROR */, component, message, context, data);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Log data flow: input → processing
|
|
180
|
+
*/
|
|
181
|
+
dataIn(component, message, context, data) {
|
|
182
|
+
this.info(component, `\u2192 ${message}`, context, data);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Log data flow: processing → output
|
|
186
|
+
*/
|
|
187
|
+
dataOut(component, message, context, data) {
|
|
188
|
+
this.info(component, `\u2190 ${message}`, context, data);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Log successful completion
|
|
192
|
+
*/
|
|
193
|
+
success(component, message, context, data) {
|
|
194
|
+
this.info(component, `\u2713 ${message}`, context, data);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Log failure
|
|
198
|
+
*/
|
|
199
|
+
failure(component, message, context, data) {
|
|
200
|
+
this.error(component, `\u2717 ${message}`, context, data);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Log timing information
|
|
204
|
+
*/
|
|
205
|
+
timing(component, message, durationMs, context) {
|
|
206
|
+
this.info(component, `\u23F1 ${message}`, context, { duration: `${durationMs}ms` });
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Happy Path Error - logs when the expected "happy path" fails but we have a fallback
|
|
210
|
+
*/
|
|
211
|
+
happyPathError(component, message, context, data, fallback = "") {
|
|
212
|
+
const stack = new Error().stack || "";
|
|
213
|
+
const stackLines = stack.split("\n");
|
|
214
|
+
const callerLine = stackLines[2] || "";
|
|
215
|
+
const callerMatch = callerLine.match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/);
|
|
216
|
+
const location = callerMatch ? `${callerMatch[1].split("/").pop()}:${callerMatch[2]}` : "unknown";
|
|
217
|
+
const enhancedContext = {
|
|
218
|
+
...context,
|
|
219
|
+
location
|
|
220
|
+
};
|
|
221
|
+
this.warn(component, `[HAPPY-PATH] ${message}`, enhancedContext, data);
|
|
222
|
+
return fallback;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
var logger = new Logger();
|
|
226
|
+
|
|
227
|
+
// src/shared/paths.ts
|
|
228
|
+
function getDirname() {
|
|
229
|
+
if (typeof __dirname !== "undefined") {
|
|
230
|
+
return __dirname;
|
|
231
|
+
}
|
|
232
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
233
|
+
}
|
|
234
|
+
var _dirname = getDirname();
|
|
235
|
+
var DATA_DIR = process.env.CONTEXTKIT_DATA_DIR || join2(homedir2(), ".contextkit");
|
|
236
|
+
var KIRO_CONFIG_DIR = process.env.KIRO_CONFIG_DIR || join2(homedir2(), ".kiro");
|
|
237
|
+
var PLUGIN_ROOT = join2(KIRO_CONFIG_DIR, "plugins", "contextkit");
|
|
238
|
+
var ARCHIVES_DIR = join2(DATA_DIR, "archives");
|
|
239
|
+
var LOGS_DIR = join2(DATA_DIR, "logs");
|
|
240
|
+
var TRASH_DIR = join2(DATA_DIR, "trash");
|
|
241
|
+
var BACKUPS_DIR = join2(DATA_DIR, "backups");
|
|
242
|
+
var MODES_DIR = join2(DATA_DIR, "modes");
|
|
243
|
+
var USER_SETTINGS_PATH = join2(DATA_DIR, "settings.json");
|
|
244
|
+
var DB_PATH = join2(DATA_DIR, "contextkit.db");
|
|
245
|
+
var VECTOR_DB_DIR = join2(DATA_DIR, "vector-db");
|
|
246
|
+
var OBSERVER_SESSIONS_DIR = join2(DATA_DIR, "observer-sessions");
|
|
247
|
+
var KIRO_SETTINGS_PATH = join2(KIRO_CONFIG_DIR, "settings.json");
|
|
248
|
+
var KIRO_CONTEXT_PATH = join2(KIRO_CONFIG_DIR, "context.md");
|
|
249
|
+
function getProjectArchiveDir(projectName) {
|
|
250
|
+
return join2(ARCHIVES_DIR, projectName);
|
|
251
|
+
}
|
|
252
|
+
function getWorkerSocketPath(sessionId) {
|
|
253
|
+
return join2(DATA_DIR, `worker-${sessionId}.sock`);
|
|
254
|
+
}
|
|
255
|
+
function ensureDir(dirPath) {
|
|
256
|
+
mkdirSync2(dirPath, { recursive: true });
|
|
257
|
+
}
|
|
258
|
+
function ensureAllDataDirs() {
|
|
259
|
+
ensureDir(DATA_DIR);
|
|
260
|
+
ensureDir(ARCHIVES_DIR);
|
|
261
|
+
ensureDir(LOGS_DIR);
|
|
262
|
+
ensureDir(TRASH_DIR);
|
|
263
|
+
ensureDir(BACKUPS_DIR);
|
|
264
|
+
ensureDir(MODES_DIR);
|
|
265
|
+
}
|
|
266
|
+
function ensureModesDir() {
|
|
267
|
+
ensureDir(MODES_DIR);
|
|
268
|
+
}
|
|
269
|
+
function getCurrentProjectName() {
|
|
270
|
+
try {
|
|
271
|
+
const gitRoot = execSync("git rev-parse --show-toplevel", {
|
|
272
|
+
cwd: process.cwd(),
|
|
273
|
+
encoding: "utf8",
|
|
274
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
275
|
+
windowsHide: true
|
|
276
|
+
}).trim();
|
|
277
|
+
return basename(gitRoot);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
logger.debug("SYSTEM", "Git root detection failed, using cwd basename", {
|
|
280
|
+
cwd: process.cwd()
|
|
281
|
+
}, error);
|
|
282
|
+
return basename(process.cwd());
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function getPackageRoot() {
|
|
286
|
+
return join2(_dirname, "..");
|
|
287
|
+
}
|
|
288
|
+
function createBackupFilename(originalPath) {
|
|
289
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, 19);
|
|
290
|
+
return `${originalPath}.backup.${timestamp}`;
|
|
291
|
+
}
|
|
292
|
+
export {
|
|
293
|
+
ARCHIVES_DIR,
|
|
294
|
+
BACKUPS_DIR,
|
|
295
|
+
DATA_DIR,
|
|
296
|
+
DB_PATH,
|
|
297
|
+
KIRO_CONFIG_DIR,
|
|
298
|
+
KIRO_CONTEXT_PATH,
|
|
299
|
+
KIRO_SETTINGS_PATH,
|
|
300
|
+
LOGS_DIR,
|
|
301
|
+
MODES_DIR,
|
|
302
|
+
OBSERVER_SESSIONS_DIR,
|
|
303
|
+
PLUGIN_ROOT,
|
|
304
|
+
TRASH_DIR,
|
|
305
|
+
USER_SETTINGS_PATH,
|
|
306
|
+
VECTOR_DB_DIR,
|
|
307
|
+
createBackupFilename,
|
|
308
|
+
ensureAllDataDirs,
|
|
309
|
+
ensureDir,
|
|
310
|
+
ensureModesDir,
|
|
311
|
+
getCurrentProjectName,
|
|
312
|
+
getPackageRoot,
|
|
313
|
+
getProjectArchiveDir,
|
|
314
|
+
getWorkerSocketPath
|
|
315
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// src/utils/logger.ts
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
6
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
7
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
8
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
9
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
10
|
+
LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
|
|
11
|
+
return LogLevel2;
|
|
12
|
+
})(LogLevel || {});
|
|
13
|
+
var DEFAULT_DATA_DIR = join(homedir(), ".contextkit");
|
|
14
|
+
var Logger = class {
|
|
15
|
+
level = null;
|
|
16
|
+
useColor;
|
|
17
|
+
logFilePath = null;
|
|
18
|
+
logFileInitialized = false;
|
|
19
|
+
constructor() {
|
|
20
|
+
this.useColor = process.stdout.isTTY ?? false;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Initialize log file path and ensure directory exists (lazy initialization)
|
|
24
|
+
*/
|
|
25
|
+
ensureLogFileInitialized() {
|
|
26
|
+
if (this.logFileInitialized) return;
|
|
27
|
+
this.logFileInitialized = true;
|
|
28
|
+
try {
|
|
29
|
+
const logsDir = join(DEFAULT_DATA_DIR, "logs");
|
|
30
|
+
if (!existsSync(logsDir)) {
|
|
31
|
+
mkdirSync(logsDir, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
34
|
+
this.logFilePath = join(logsDir, `contextkit-${date}.log`);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error("[LOGGER] Failed to initialize log file:", error);
|
|
37
|
+
this.logFilePath = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Lazy-load log level from settings file
|
|
42
|
+
*/
|
|
43
|
+
getLevel() {
|
|
44
|
+
if (this.level === null) {
|
|
45
|
+
try {
|
|
46
|
+
const settingsPath = join(DEFAULT_DATA_DIR, "settings.json");
|
|
47
|
+
if (existsSync(settingsPath)) {
|
|
48
|
+
const settingsData = readFileSync(settingsPath, "utf-8");
|
|
49
|
+
const settings = JSON.parse(settingsData);
|
|
50
|
+
const envLevel = (settings.CONTEXTKIT_LOG_LEVEL || "INFO").toUpperCase();
|
|
51
|
+
this.level = LogLevel[envLevel] ?? 1 /* INFO */;
|
|
52
|
+
} else {
|
|
53
|
+
this.level = 1 /* INFO */;
|
|
54
|
+
}
|
|
55
|
+
} catch (error) {
|
|
56
|
+
this.level = 1 /* INFO */;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return this.level;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create correlation ID for tracking an observation through the pipeline
|
|
63
|
+
*/
|
|
64
|
+
correlationId(sessionId, observationNum) {
|
|
65
|
+
return `obs-${sessionId}-${observationNum}`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create session correlation ID
|
|
69
|
+
*/
|
|
70
|
+
sessionId(sessionId) {
|
|
71
|
+
return `session-${sessionId}`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Format data for logging - create compact summaries instead of full dumps
|
|
75
|
+
*/
|
|
76
|
+
formatData(data) {
|
|
77
|
+
if (data === null || data === void 0) return "";
|
|
78
|
+
if (typeof data === "string") return data;
|
|
79
|
+
if (typeof data === "number") return data.toString();
|
|
80
|
+
if (typeof data === "boolean") return data.toString();
|
|
81
|
+
if (typeof data === "object") {
|
|
82
|
+
if (data instanceof Error) {
|
|
83
|
+
return this.getLevel() === 0 /* DEBUG */ ? `${data.message}
|
|
84
|
+
${data.stack}` : data.message;
|
|
85
|
+
}
|
|
86
|
+
if (Array.isArray(data)) {
|
|
87
|
+
return `[${data.length} items]`;
|
|
88
|
+
}
|
|
89
|
+
const keys = Object.keys(data);
|
|
90
|
+
if (keys.length === 0) return "{}";
|
|
91
|
+
if (keys.length <= 3) {
|
|
92
|
+
return JSON.stringify(data);
|
|
93
|
+
}
|
|
94
|
+
return `{${keys.length} keys: ${keys.slice(0, 3).join(", ")}...}`;
|
|
95
|
+
}
|
|
96
|
+
return String(data);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Format timestamp in local timezone (YYYY-MM-DD HH:MM:SS.mmm)
|
|
100
|
+
*/
|
|
101
|
+
formatTimestamp(date) {
|
|
102
|
+
const year = date.getFullYear();
|
|
103
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
104
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
105
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
106
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
107
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
108
|
+
const ms = String(date.getMilliseconds()).padStart(3, "0");
|
|
109
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Core logging method
|
|
113
|
+
*/
|
|
114
|
+
log(level, component, message, context, data) {
|
|
115
|
+
if (level < this.getLevel()) return;
|
|
116
|
+
this.ensureLogFileInitialized();
|
|
117
|
+
const timestamp = this.formatTimestamp(/* @__PURE__ */ new Date());
|
|
118
|
+
const levelStr = LogLevel[level].padEnd(5);
|
|
119
|
+
const componentStr = component.padEnd(6);
|
|
120
|
+
let correlationStr = "";
|
|
121
|
+
if (context?.correlationId) {
|
|
122
|
+
correlationStr = `[${context.correlationId}] `;
|
|
123
|
+
} else if (context?.sessionId) {
|
|
124
|
+
correlationStr = `[session-${context.sessionId}] `;
|
|
125
|
+
}
|
|
126
|
+
let dataStr = "";
|
|
127
|
+
if (data !== void 0 && data !== null) {
|
|
128
|
+
if (data instanceof Error) {
|
|
129
|
+
dataStr = this.getLevel() === 0 /* DEBUG */ ? `
|
|
130
|
+
${data.message}
|
|
131
|
+
${data.stack}` : ` ${data.message}`;
|
|
132
|
+
} else if (this.getLevel() === 0 /* DEBUG */ && typeof data === "object") {
|
|
133
|
+
dataStr = "\n" + JSON.stringify(data, null, 2);
|
|
134
|
+
} else {
|
|
135
|
+
dataStr = " " + this.formatData(data);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
let contextStr = "";
|
|
139
|
+
if (context) {
|
|
140
|
+
const { sessionId, memorySessionId, correlationId, ...rest } = context;
|
|
141
|
+
if (Object.keys(rest).length > 0) {
|
|
142
|
+
const pairs = Object.entries(rest).map(([k, v]) => `${k}=${v}`);
|
|
143
|
+
contextStr = ` {${pairs.join(", ")}}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const logLine = `[${timestamp}] [${levelStr}] [${componentStr}] ${correlationStr}${message}${contextStr}${dataStr}`;
|
|
147
|
+
if (this.logFilePath) {
|
|
148
|
+
try {
|
|
149
|
+
appendFileSync(this.logFilePath, logLine + "\n", "utf8");
|
|
150
|
+
} catch (error) {
|
|
151
|
+
process.stderr.write(`[LOGGER] Failed to write to log file: ${error}
|
|
152
|
+
`);
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
process.stderr.write(logLine + "\n");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Public logging methods
|
|
159
|
+
debug(component, message, context, data) {
|
|
160
|
+
this.log(0 /* DEBUG */, component, message, context, data);
|
|
161
|
+
}
|
|
162
|
+
info(component, message, context, data) {
|
|
163
|
+
this.log(1 /* INFO */, component, message, context, data);
|
|
164
|
+
}
|
|
165
|
+
warn(component, message, context, data) {
|
|
166
|
+
this.log(2 /* WARN */, component, message, context, data);
|
|
167
|
+
}
|
|
168
|
+
error(component, message, context, data) {
|
|
169
|
+
this.log(3 /* ERROR */, component, message, context, data);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Log data flow: input → processing
|
|
173
|
+
*/
|
|
174
|
+
dataIn(component, message, context, data) {
|
|
175
|
+
this.info(component, `\u2192 ${message}`, context, data);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Log data flow: processing → output
|
|
179
|
+
*/
|
|
180
|
+
dataOut(component, message, context, data) {
|
|
181
|
+
this.info(component, `\u2190 ${message}`, context, data);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Log successful completion
|
|
185
|
+
*/
|
|
186
|
+
success(component, message, context, data) {
|
|
187
|
+
this.info(component, `\u2713 ${message}`, context, data);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Log failure
|
|
191
|
+
*/
|
|
192
|
+
failure(component, message, context, data) {
|
|
193
|
+
this.error(component, `\u2717 ${message}`, context, data);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Log timing information
|
|
197
|
+
*/
|
|
198
|
+
timing(component, message, durationMs, context) {
|
|
199
|
+
this.info(component, `\u23F1 ${message}`, context, { duration: `${durationMs}ms` });
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Happy Path Error - logs when the expected "happy path" fails but we have a fallback
|
|
203
|
+
*/
|
|
204
|
+
happyPathError(component, message, context, data, fallback = "") {
|
|
205
|
+
const stack = new Error().stack || "";
|
|
206
|
+
const stackLines = stack.split("\n");
|
|
207
|
+
const callerLine = stackLines[2] || "";
|
|
208
|
+
const callerMatch = callerLine.match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/);
|
|
209
|
+
const location = callerMatch ? `${callerMatch[1].split("/").pop()}:${callerMatch[2]}` : "unknown";
|
|
210
|
+
const enhancedContext = {
|
|
211
|
+
...context,
|
|
212
|
+
location
|
|
213
|
+
};
|
|
214
|
+
this.warn(component, `[HAPPY-PATH] ${message}`, enhancedContext, data);
|
|
215
|
+
return fallback;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var logger = new Logger();
|
|
219
|
+
export {
|
|
220
|
+
LogLevel,
|
|
221
|
+
logger
|
|
222
|
+
};
|