@probelabs/probe 0.6.0-rc299 → 0.6.0-rc301

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/cjs/index.cjs CHANGED
@@ -25877,229 +25877,805 @@ var init_tokenCounter = __esm({
25877
25877
  }
25878
25878
  });
25879
25879
 
25880
- // src/agent/storage/StorageAdapter.js
25881
- var StorageAdapter;
25882
- var init_StorageAdapter = __esm({
25883
- "src/agent/storage/StorageAdapter.js"() {
25884
- "use strict";
25885
- StorageAdapter = class {
25886
- /**
25887
- * Load conversation history for a session
25888
- * @param {string} sessionId - Session identifier
25889
- * @returns {Promise<Array<Object>>} Array of message objects with {role, content, ...}
25890
- */
25891
- async loadHistory(sessionId) {
25892
- throw new Error("StorageAdapter.loadHistory() must be implemented by subclass");
25893
- }
25894
- /**
25895
- * Save a message to storage
25896
- * @param {string} sessionId - Session identifier
25897
- * @param {Object} message - Message object { role, content, ... }
25898
- * @returns {Promise<void>}
25899
- */
25900
- async saveMessage(sessionId, message) {
25901
- throw new Error("StorageAdapter.saveMessage() must be implemented by subclass");
25902
- }
25903
- /**
25904
- * Clear history for a session
25905
- * @param {string} sessionId - Session identifier
25906
- * @returns {Promise<void>}
25907
- */
25908
- async clearHistory(sessionId) {
25909
- throw new Error("StorageAdapter.clearHistory() must be implemented by subclass");
25880
+ // src/agent/otelLogBridge.js
25881
+ function getOtelApi() {
25882
+ if (otelApiAttempted) return otelApi;
25883
+ otelApiAttempted = true;
25884
+ try {
25885
+ otelApi = (function(name15) {
25886
+ return _require(name15);
25887
+ })("@opentelemetry/api");
25888
+ } catch {
25889
+ }
25890
+ return otelApi;
25891
+ }
25892
+ function getOtelLogger() {
25893
+ if (otelLoggerAttempted) return otelLogger;
25894
+ otelLoggerAttempted = true;
25895
+ try {
25896
+ const { logs } = (function(name15) {
25897
+ return _require(name15);
25898
+ })("@opentelemetry/api-logs");
25899
+ otelLogger = logs.getLogger("probe-agent");
25900
+ } catch {
25901
+ }
25902
+ return otelLogger;
25903
+ }
25904
+ function getTraceSuffix() {
25905
+ try {
25906
+ const api2 = getOtelApi();
25907
+ if (!api2) return "";
25908
+ const span = api2.trace.getSpan(api2.context.active());
25909
+ const ctx = span?.spanContext?.();
25910
+ if (!ctx?.traceId) return "";
25911
+ return ` [trace_id=${ctx.traceId} span_id=${ctx.spanId}]`;
25912
+ } catch {
25913
+ return "";
25914
+ }
25915
+ }
25916
+ function emitOtelLog(msg, level) {
25917
+ try {
25918
+ const logger = getOtelLogger();
25919
+ if (!logger) return;
25920
+ const api2 = getOtelApi();
25921
+ let traceId, spanId;
25922
+ if (api2) {
25923
+ const span = api2.trace.getSpan(api2.context.active());
25924
+ const ctx = span?.spanContext?.();
25925
+ if (ctx?.traceId) {
25926
+ traceId = ctx.traceId;
25927
+ spanId = ctx.spanId;
25910
25928
  }
25911
- /**
25912
- * Get session metadata (optional)
25913
- * @param {string} sessionId - Session identifier
25914
- * @returns {Promise<Object|null>} Session metadata or null
25915
- */
25916
- async getSessionMetadata(sessionId) {
25917
- return null;
25929
+ }
25930
+ logger.emit({
25931
+ severityNumber: OTEL_SEVERITY[level] || 9,
25932
+ severityText: level.toUpperCase(),
25933
+ body: msg,
25934
+ attributes: {
25935
+ "probe.logger": true,
25936
+ ...traceId ? { trace_id: traceId, span_id: spanId } : {}
25918
25937
  }
25919
- /**
25920
- * Update session activity timestamp (optional)
25921
- * @param {string} sessionId - Session identifier
25922
- * @returns {Promise<void>}
25923
- */
25924
- async updateSessionActivity(sessionId) {
25938
+ });
25939
+ } catch {
25940
+ }
25941
+ }
25942
+ function patchConsole() {
25943
+ if (patched) return;
25944
+ const methods = ["log", "info", "warn", "error"];
25945
+ const c = globalThis.console;
25946
+ for (const m of methods) {
25947
+ const orig = c[m].bind(c);
25948
+ originals[m] = orig;
25949
+ c[m] = (...args) => {
25950
+ const msgParts = args.map(
25951
+ (a) => typeof a === "string" ? a : a instanceof Error ? a.message : JSON.stringify(a)
25952
+ );
25953
+ const msg = msgParts.join(" ");
25954
+ emitOtelLog(msg, m === "log" ? "log" : m);
25955
+ const suffix = getTraceSuffix();
25956
+ if (suffix) {
25957
+ if (typeof args[0] === "string") {
25958
+ args[0] = args[0] + suffix;
25959
+ } else {
25960
+ args.push(suffix);
25961
+ }
25925
25962
  }
25963
+ return orig(...args);
25964
+ };
25965
+ }
25966
+ patched = true;
25967
+ }
25968
+ var import_module, _require, OTEL_SEVERITY, patched, originals, otelApi, otelApiAttempted, otelLogger, otelLoggerAttempted;
25969
+ var init_otelLogBridge = __esm({
25970
+ "src/agent/otelLogBridge.js"() {
25971
+ "use strict";
25972
+ import_module = require("module");
25973
+ _require = (0, import_module.createRequire)("file:///");
25974
+ OTEL_SEVERITY = {
25975
+ log: 9,
25976
+ // INFO
25977
+ info: 9,
25978
+ // INFO
25979
+ warn: 13,
25980
+ // WARN
25981
+ error: 17,
25982
+ // ERROR
25983
+ debug: 5
25984
+ // DEBUG
25926
25985
  };
25986
+ patched = false;
25987
+ originals = {};
25988
+ otelApi = null;
25989
+ otelApiAttempted = false;
25990
+ otelLogger = null;
25991
+ otelLoggerAttempted = false;
25927
25992
  }
25928
25993
  });
25929
25994
 
25930
- // src/agent/storage/InMemoryStorageAdapter.js
25931
- var InMemoryStorageAdapter;
25932
- var init_InMemoryStorageAdapter = __esm({
25933
- "src/agent/storage/InMemoryStorageAdapter.js"() {
25995
+ // src/agent/simpleTelemetry.js
25996
+ function truncateForSpan(text, maxLen = 4096) {
25997
+ if (!text || text.length <= maxLen) return text || "";
25998
+ const half = Math.floor((maxLen - 40) / 2);
25999
+ const omitted = text.length - half * 2;
26000
+ return text.substring(0, half) + `
26001
+ ... [${omitted} chars omitted] ...
26002
+ ` + text.substring(text.length - half);
26003
+ }
26004
+ function initializeSimpleTelemetryFromOptions(options) {
26005
+ const telemetry = new SimpleTelemetry({
26006
+ serviceName: "probe-agent",
26007
+ enableFile: options.traceFile !== void 0,
26008
+ enableConsole: options.traceConsole,
26009
+ filePath: options.traceFile || "./traces.jsonl"
26010
+ });
26011
+ patchConsole();
26012
+ return telemetry;
26013
+ }
26014
+ var import_fs4, import_path5, SimpleTelemetry, SimpleAppTracer;
26015
+ var init_simpleTelemetry = __esm({
26016
+ "src/agent/simpleTelemetry.js"() {
25934
26017
  "use strict";
25935
- init_StorageAdapter();
25936
- InMemoryStorageAdapter = class extends StorageAdapter {
25937
- constructor() {
25938
- super();
25939
- this.sessions = /* @__PURE__ */ new Map();
26018
+ import_fs4 = require("fs");
26019
+ import_path5 = require("path");
26020
+ init_otelLogBridge();
26021
+ SimpleTelemetry = class {
26022
+ constructor(options = {}) {
26023
+ this.serviceName = options.serviceName || "probe-agent";
26024
+ this.enableFile = options.enableFile || false;
26025
+ this.enableConsole = options.enableConsole || false;
26026
+ this.filePath = options.filePath || "./traces.jsonl";
26027
+ this.stream = null;
26028
+ if (this.enableFile) {
26029
+ this.initializeFileExporter();
26030
+ }
25940
26031
  }
25941
- async loadHistory(sessionId) {
25942
- const session = this.sessions.get(sessionId);
25943
- return session ? session.messages : [];
26032
+ initializeFileExporter() {
26033
+ try {
26034
+ const dir = (0, import_path5.dirname)(this.filePath);
26035
+ if (!(0, import_fs4.existsSync)(dir)) {
26036
+ (0, import_fs4.mkdirSync)(dir, { recursive: true });
26037
+ }
26038
+ this.stream = (0, import_fs4.createWriteStream)(this.filePath, { flags: "a" });
26039
+ this.stream.on("error", (error40) => {
26040
+ console.error(`[SimpleTelemetry] Stream error: ${error40.message}`);
26041
+ });
26042
+ console.log(`[SimpleTelemetry] File exporter initialized: ${this.filePath}`);
26043
+ } catch (error40) {
26044
+ console.error(`[SimpleTelemetry] Failed to initialize file exporter: ${error40.message}`);
26045
+ }
25944
26046
  }
25945
- async saveMessage(sessionId, message) {
25946
- if (!this.sessions.has(sessionId)) {
25947
- this.sessions.set(sessionId, {
25948
- messages: [],
25949
- metadata: {
25950
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
25951
- lastActivity: (/* @__PURE__ */ new Date()).toISOString()
26047
+ createSpan(name15, attributes = {}) {
26048
+ const span = {
26049
+ traceId: this.generateTraceId(),
26050
+ spanId: this.generateSpanId(),
26051
+ name: name15,
26052
+ startTime: Date.now(),
26053
+ attributes: { ...attributes, service: this.serviceName },
26054
+ events: [],
26055
+ status: "OK"
26056
+ };
26057
+ return {
26058
+ ...span,
26059
+ addEvent: (eventName, eventAttributes = {}) => {
26060
+ span.events.push({
26061
+ name: eventName,
26062
+ time: Date.now(),
26063
+ attributes: eventAttributes
26064
+ });
26065
+ },
26066
+ setAttributes: (attrs) => {
26067
+ Object.assign(span.attributes, attrs);
26068
+ },
26069
+ setStatus: (status) => {
26070
+ span.status = status;
26071
+ },
26072
+ end: () => {
26073
+ span.endTime = Date.now();
26074
+ span.duration = span.endTime - span.startTime;
26075
+ this.exportSpan(span);
26076
+ }
26077
+ };
26078
+ }
26079
+ exportSpan(span) {
26080
+ const spanData = {
26081
+ ...span,
26082
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
26083
+ };
26084
+ if (this.enableConsole) {
26085
+ console.log("[Trace]", JSON.stringify(spanData, null, 2));
26086
+ }
26087
+ if (this.enableFile && this.stream) {
26088
+ this.stream.write(JSON.stringify(spanData) + "\n");
26089
+ }
26090
+ }
26091
+ generateTraceId() {
26092
+ return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
26093
+ }
26094
+ generateSpanId() {
26095
+ return Math.random().toString(36).substring(2, 10);
26096
+ }
26097
+ async flush() {
26098
+ if (this.stream) {
26099
+ return new Promise((resolve9) => {
26100
+ this.stream.once("drain", resolve9);
26101
+ if (!this.stream.writableNeedDrain) {
26102
+ resolve9();
25952
26103
  }
25953
26104
  });
25954
26105
  }
25955
- const session = this.sessions.get(sessionId);
25956
- session.messages.push(message);
25957
- session.metadata.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
25958
26106
  }
25959
- async clearHistory(sessionId) {
25960
- this.sessions.delete(sessionId);
26107
+ async shutdown() {
26108
+ if (this.stream) {
26109
+ return new Promise((resolve9) => {
26110
+ this.stream.end(() => {
26111
+ console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
26112
+ resolve9();
26113
+ });
26114
+ });
26115
+ }
25961
26116
  }
25962
- async getSessionMetadata(sessionId) {
25963
- const session = this.sessions.get(sessionId);
25964
- return session ? session.metadata : null;
26117
+ };
26118
+ SimpleAppTracer = class {
26119
+ constructor(telemetry, sessionId = null) {
26120
+ this.telemetry = telemetry;
26121
+ this.sessionId = sessionId || this.generateSessionId();
25965
26122
  }
25966
- async updateSessionActivity(sessionId) {
25967
- const session = this.sessions.get(sessionId);
25968
- if (session) {
25969
- session.metadata.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
26123
+ generateSessionId() {
26124
+ return Math.random().toString(36).substring(2, 15);
26125
+ }
26126
+ isEnabled() {
26127
+ return this.telemetry !== null;
26128
+ }
26129
+ createSessionSpan(attributes = {}) {
26130
+ if (!this.isEnabled()) return null;
26131
+ return this.telemetry.createSpan("agent.session", {
26132
+ "session.id": this.sessionId,
26133
+ ...attributes
26134
+ });
26135
+ }
26136
+ createAISpan(modelName, provider, attributes = {}) {
26137
+ if (!this.isEnabled()) return null;
26138
+ return this.telemetry.createSpan("ai.request", {
26139
+ "ai.model": modelName,
26140
+ "ai.provider": provider,
26141
+ "session.id": this.sessionId,
26142
+ ...attributes
26143
+ });
26144
+ }
26145
+ createToolSpan(toolName, attributes = {}) {
26146
+ if (!this.isEnabled()) return null;
26147
+ return this.telemetry.createSpan("tool.call", {
26148
+ "tool.name": toolName,
26149
+ "session.id": this.sessionId,
26150
+ ...attributes
26151
+ });
26152
+ }
26153
+ addEvent(name15, attributes = {}) {
26154
+ if (this.telemetry && this.telemetry.enableConsole) {
26155
+ console.log("[Event]", name15, attributes);
25970
26156
  }
25971
26157
  }
25972
- };
25973
- }
25974
- });
25975
-
25976
- // src/agent/hooks/HookManager.js
25977
- var HookManager, HOOK_TYPES;
25978
- var init_HookManager = __esm({
25979
- "src/agent/hooks/HookManager.js"() {
25980
- "use strict";
25981
- HookManager = class {
25982
- constructor() {
25983
- this.hooks = /* @__PURE__ */ new Map();
26158
+ /**
26159
+ * Record a generic event (used by completionPrompt and other features)
26160
+ */
26161
+ // visor-disable: SimpleAppTracer uses this.sessionId because it's a per-session instance. AppTracer extracts from attributes because it's a singleton managing multiple sessions. Different architectures require different approaches.
26162
+ recordEvent(name15, attributes = {}) {
26163
+ if (!this.isEnabled()) return;
26164
+ this.addEvent(name15, {
26165
+ "session.id": this.sessionId,
26166
+ ...attributes
26167
+ });
25984
26168
  }
25985
26169
  /**
25986
- * Register a hook callback
25987
- * @param {string} hookName - Name of the hook
25988
- * @param {Function} callback - Callback function
25989
- * @returns {Function} Unregister function
26170
+ * Record delegation events
25990
26171
  */
25991
- on(hookName, callback) {
25992
- if (!this.hooks.has(hookName)) {
25993
- this.hooks.set(hookName, /* @__PURE__ */ new Set());
25994
- }
25995
- this.hooks.get(hookName).add(callback);
25996
- return () => this.off(hookName, callback);
26172
+ recordDelegationEvent(eventType, data2 = {}) {
26173
+ if (!this.isEnabled()) return;
26174
+ this.addEvent(`delegation.${eventType}`, {
26175
+ "session.id": this.sessionId,
26176
+ ...data2
26177
+ });
25997
26178
  }
25998
26179
  /**
25999
- * Register a one-time hook callback
26000
- * @param {string} hookName - Name of the hook
26001
- * @param {Function} callback - Callback function
26002
- * @returns {Function} Unregister function
26180
+ * Record JSON validation events
26003
26181
  */
26004
- once(hookName, callback) {
26005
- const wrappedCallback = async (data2) => {
26006
- this.off(hookName, wrappedCallback);
26007
- await callback(data2);
26008
- };
26009
- return this.on(hookName, wrappedCallback);
26182
+ recordJsonValidationEvent(eventType, data2 = {}) {
26183
+ if (!this.isEnabled()) return;
26184
+ this.addEvent(`json_validation.${eventType}`, {
26185
+ "session.id": this.sessionId,
26186
+ ...data2
26187
+ });
26010
26188
  }
26011
26189
  /**
26012
- * Unregister a hook callback
26013
- * @param {string} hookName - Name of the hook
26014
- * @param {Function} callback - Callback function
26190
+ * Record Mermaid validation events
26015
26191
  */
26016
- off(hookName, callback) {
26017
- const callbacks = this.hooks.get(hookName);
26018
- if (callbacks) {
26019
- callbacks.delete(callback);
26020
- }
26192
+ recordMermaidValidationEvent(eventType, data2 = {}) {
26193
+ if (!this.isEnabled()) return;
26194
+ this.addEvent(`mermaid_validation.${eventType}`, {
26195
+ "session.id": this.sessionId,
26196
+ ...data2
26197
+ });
26021
26198
  }
26022
26199
  /**
26023
- * Emit a hook event
26024
- * @param {string} hookName - Name of the hook
26025
- * @param {any} data - Data to pass to callbacks
26026
- * @returns {Promise<void>}
26200
+ * Record task management events
26027
26201
  */
26028
- async emit(hookName, data2) {
26029
- const callbacks = this.hooks.get(hookName);
26030
- if (!callbacks || callbacks.size === 0) return;
26031
- const promises = Array.from(callbacks).map((callback) => {
26032
- try {
26033
- return Promise.resolve(callback(data2));
26034
- } catch (error40) {
26035
- return Promise.reject(error40);
26036
- }
26202
+ recordTaskEvent(eventType, data2 = {}) {
26203
+ if (!this.isEnabled()) return;
26204
+ this.addEvent(`task.${eventType}`, {
26205
+ "session.id": this.sessionId,
26206
+ ...data2
26037
26207
  });
26038
- const results = await Promise.allSettled(promises);
26039
- results.forEach((result, index) => {
26040
- if (result.status === "rejected") {
26041
- console.error(`[HookManager] Error in hook "${hookName}" (callback ${index + 1}):`, result.reason);
26042
- }
26208
+ }
26209
+ /**
26210
+ * Record MCP (Model Context Protocol) events
26211
+ * Tracks server connections, tool discovery, method filtering, and tool execution
26212
+ */
26213
+ recordMcpEvent(eventType, data2 = {}) {
26214
+ if (!this.isEnabled()) return;
26215
+ this.addEvent(`mcp.${eventType}`, {
26216
+ "session.id": this.sessionId,
26217
+ ...data2
26043
26218
  });
26044
26219
  }
26045
26220
  /**
26046
- * Clear all hooks or hooks for a specific event
26047
- * @param {string} [hookName] - Optional hook name to clear
26221
+ * Record bash tool events
26222
+ * Tracks command permission checks, allowed/denied commands, and execution
26048
26223
  */
26049
- clear(hookName) {
26050
- if (hookName) {
26051
- this.hooks.delete(hookName);
26052
- } else {
26053
- this.hooks.clear();
26224
+ recordBashEvent(eventType, data2 = {}) {
26225
+ if (!this.isEnabled()) return;
26226
+ this.addEvent(`bash.${eventType}`, {
26227
+ "session.id": this.sessionId,
26228
+ ...data2
26229
+ });
26230
+ }
26231
+ setAttributes(attributes) {
26232
+ if (this.telemetry && this.telemetry.enableConsole) {
26233
+ console.log("[Attributes]", attributes);
26054
26234
  }
26055
26235
  }
26056
26236
  /**
26057
- * Get list of registered hook names
26058
- * @returns {string[]} Array of hook names
26237
+ * Hash content for deduplication/comparison purposes
26238
+ * @param {string} content - The content to hash
26239
+ * @returns {string} - Hex string hash
26059
26240
  */
26060
- getHookNames() {
26061
- return Array.from(this.hooks.keys());
26241
+ hashContent(content) {
26242
+ let hash2 = 0;
26243
+ const len = Math.min(content.length, 1e3);
26244
+ for (let i = 0; i < len; i++) {
26245
+ hash2 = (hash2 << 5) - hash2 + content.charCodeAt(i);
26246
+ hash2 |= 0;
26247
+ }
26248
+ return hash2.toString(16);
26062
26249
  }
26063
26250
  /**
26064
- * Get number of callbacks for a hook
26065
- * @param {string} hookName - Name of the hook
26066
- * @returns {number} Number of callbacks
26251
+ * Record a conversation turn (assistant response or tool result)
26252
+ * @param {string} role - The role (assistant, tool_result)
26253
+ * @param {string} content - The turn content
26254
+ * @param {Object} metadata - Additional metadata
26067
26255
  */
26068
- getCallbackCount(hookName) {
26069
- const callbacks = this.hooks.get(hookName);
26070
- return callbacks ? callbacks.size : 0;
26256
+ recordConversationTurn(role, content, metadata = {}) {
26257
+ if (!this.isEnabled()) return;
26258
+ this.addEvent(`conversation.turn.${role}`, {
26259
+ "session.id": this.sessionId,
26260
+ "conversation.role": role,
26261
+ "conversation.content": content.substring(0, 1e4),
26262
+ "conversation.content.length": content.length,
26263
+ "conversation.content.hash": this.hashContent(content),
26264
+ ...metadata
26265
+ });
26071
26266
  }
26072
- };
26073
- HOOK_TYPES = {
26074
- // Lifecycle hooks
26075
- AGENT_INITIALIZED: "agent:initialized",
26076
- AGENT_CLEANUP: "agent:cleanup",
26077
- // Message hooks
26078
- MESSAGE_USER: "message:user",
26079
- MESSAGE_ASSISTANT: "message:assistant",
26080
- MESSAGE_SYSTEM: "message:system",
26081
- // Tool execution hooks
26082
- TOOL_START: "tool:start",
26083
- TOOL_END: "tool:end",
26084
- TOOL_ERROR: "tool:error",
26085
- // AI streaming hooks
26086
- AI_STREAM_START: "ai:stream:start",
26087
- AI_STREAM_DELTA: "ai:stream:delta",
26088
- AI_STREAM_END: "ai:stream:end",
26089
- // Storage hooks
26090
- STORAGE_LOAD: "storage:load",
26091
- STORAGE_SAVE: "storage:save",
26092
- STORAGE_CLEAR: "storage:clear",
26093
- // Iteration hooks
26094
- ITERATION_START: "iteration:start",
26095
- ITERATION_END: "iteration:end"
26096
- };
26097
- }
26098
- });
26099
-
26100
- // src/agent/imageConfig.js
26101
- function isFormatSupportedByProvider(extension, provider) {
26102
- if (!extension || typeof extension !== "string") {
26267
+ /**
26268
+ * Record error events with classification
26269
+ * @param {string} errorType - The type of error (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker, etc.)
26270
+ * @param {Object} errorDetails - Error details including message, stack, context
26271
+ */
26272
+ recordErrorEvent(errorType, errorDetails = {}) {
26273
+ if (!this.isEnabled()) return;
26274
+ this.addEvent(`error.${errorType}`, {
26275
+ "session.id": this.sessionId,
26276
+ "error.type": errorType,
26277
+ "error.message": errorDetails.message?.substring(0, 1e3) || null,
26278
+ "error.stack": errorDetails.stack?.substring(0, 2e3) || null,
26279
+ "error.recoverable": errorDetails.recoverable ?? true,
26280
+ "error.context": JSON.stringify(errorDetails.context || {}).substring(0, 1e3),
26281
+ ...Object.fromEntries(
26282
+ Object.entries(errorDetails).filter(([k]) => !["message", "stack", "context", "recoverable"].includes(k)).map(([k, v]) => [`error.${k}`, v])
26283
+ )
26284
+ });
26285
+ }
26286
+ /**
26287
+ * Record AI thinking/reasoning content
26288
+ * @param {string} thinkingContent - The thinking content from AI response
26289
+ * @param {Object} metadata - Additional metadata
26290
+ */
26291
+ recordThinkingContent(thinkingContent, metadata = {}) {
26292
+ if (!this.isEnabled() || !thinkingContent) return;
26293
+ this.addEvent("ai.thinking", {
26294
+ "session.id": this.sessionId,
26295
+ "ai.thinking.content": thinkingContent.substring(0, 5e4),
26296
+ "ai.thinking.length": thinkingContent.length,
26297
+ "ai.thinking.hash": this.hashContent(thinkingContent),
26298
+ ...metadata
26299
+ });
26300
+ }
26301
+ /**
26302
+ * Record AI tool call decision
26303
+ * @param {string} toolName - The tool name AI decided to call
26304
+ * @param {Object} params - The parameters AI provided
26305
+ * @param {Object} metadata - Additional metadata
26306
+ */
26307
+ recordToolDecision(toolName, params, metadata = {}) {
26308
+ if (!this.isEnabled()) return;
26309
+ this.addEvent("ai.tool_decision", {
26310
+ "session.id": this.sessionId,
26311
+ "ai.tool_decision.name": toolName,
26312
+ "ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
26313
+ ...metadata
26314
+ });
26315
+ }
26316
+ /**
26317
+ * Record tool result after execution
26318
+ * @param {string} toolName - The tool that was executed
26319
+ * @param {string|Object} result - The tool result
26320
+ * @param {boolean} success - Whether the tool succeeded
26321
+ * @param {number} durationMs - Execution duration in milliseconds
26322
+ * @param {Object} metadata - Additional metadata
26323
+ */
26324
+ recordToolResult(toolName, result, success2, durationMs, metadata = {}) {
26325
+ if (!this.isEnabled()) return;
26326
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result);
26327
+ this.addEvent("tool.result", {
26328
+ "session.id": this.sessionId,
26329
+ "tool.name": toolName,
26330
+ "tool.result": resultStr.substring(0, 1e4),
26331
+ "tool.result.length": resultStr.length,
26332
+ "tool.result.hash": this.hashContent(resultStr),
26333
+ "tool.duration_ms": durationMs,
26334
+ "tool.success": success2,
26335
+ ...metadata
26336
+ });
26337
+ }
26338
+ /**
26339
+ * Record MCP tool execution start
26340
+ * @param {string} toolName - MCP tool name
26341
+ * @param {string} serverName - MCP server name
26342
+ * @param {Object} params - Tool parameters
26343
+ * @param {Object} metadata - Additional metadata
26344
+ */
26345
+ recordMcpToolStart(toolName, serverName, params, metadata = {}) {
26346
+ if (!this.isEnabled()) return;
26347
+ this.addEvent("mcp.tool.start", {
26348
+ "session.id": this.sessionId,
26349
+ "mcp.tool.name": toolName,
26350
+ "mcp.tool.server": serverName || "unknown",
26351
+ "mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
26352
+ ...metadata
26353
+ });
26354
+ }
26355
+ /**
26356
+ * Record MCP tool execution end
26357
+ * @param {string} toolName - MCP tool name
26358
+ * @param {string} serverName - MCP server name
26359
+ * @param {string|Object} result - Tool result
26360
+ * @param {boolean} success - Whether succeeded
26361
+ * @param {number} durationMs - Execution duration
26362
+ * @param {string} errorMessage - Error message if failed
26363
+ * @param {Object} metadata - Additional metadata
26364
+ */
26365
+ recordMcpToolEnd(toolName, serverName, result, success2, durationMs, errorMessage = null, metadata = {}) {
26366
+ if (!this.isEnabled()) return;
26367
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
26368
+ this.addEvent("mcp.tool.end", {
26369
+ "session.id": this.sessionId,
26370
+ "mcp.tool.name": toolName,
26371
+ "mcp.tool.server": serverName || "unknown",
26372
+ "mcp.tool.result": resultStr.substring(0, 1e4),
26373
+ "mcp.tool.result.length": resultStr.length,
26374
+ "mcp.tool.duration_ms": durationMs,
26375
+ "mcp.tool.success": success2,
26376
+ "mcp.tool.error": errorMessage,
26377
+ ...metadata
26378
+ });
26379
+ }
26380
+ /**
26381
+ * Record iteration lifecycle event
26382
+ * @param {string} eventType - start or end
26383
+ * @param {number} iteration - Iteration number
26384
+ * @param {Object} data - Additional data
26385
+ */
26386
+ recordIterationEvent(eventType, iteration, data2 = {}) {
26387
+ if (!this.isEnabled()) return;
26388
+ this.addEvent(`iteration.${eventType}`, {
26389
+ "session.id": this.sessionId,
26390
+ "iteration": iteration,
26391
+ ...data2
26392
+ });
26393
+ }
26394
+ /**
26395
+ * Record per-turn token breakdown
26396
+ * @param {number} iteration - Iteration number
26397
+ * @param {Object} tokenData - Token metrics
26398
+ */
26399
+ recordTokenTurn(iteration, tokenData = {}) {
26400
+ if (!this.isEnabled()) return;
26401
+ this.addEvent("tokens.turn", {
26402
+ "session.id": this.sessionId,
26403
+ "iteration": iteration,
26404
+ "tokens.input": tokenData.inputTokens || 0,
26405
+ "tokens.output": tokenData.outputTokens || 0,
26406
+ "tokens.total": (tokenData.inputTokens || 0) + (tokenData.outputTokens || 0),
26407
+ "tokens.cache_read": tokenData.cacheReadTokens || 0,
26408
+ "tokens.cache_write": tokenData.cacheWriteTokens || 0,
26409
+ "tokens.context_used": tokenData.contextTokens || 0,
26410
+ "tokens.context_remaining": tokenData.maxContextTokens ? tokenData.maxContextTokens - (tokenData.contextTokens || 0) : null
26411
+ });
26412
+ }
26413
+ async withSpan(spanName, fn, attributes = {}, onResult = null) {
26414
+ if (!this.isEnabled()) {
26415
+ return fn();
26416
+ }
26417
+ const span = this.telemetry.createSpan(spanName, {
26418
+ "session.id": this.sessionId,
26419
+ ...attributes
26420
+ });
26421
+ try {
26422
+ const result = await fn();
26423
+ span.setStatus("OK");
26424
+ if (onResult) {
26425
+ try {
26426
+ onResult(span, result);
26427
+ } catch (_) {
26428
+ }
26429
+ }
26430
+ return result;
26431
+ } catch (error40) {
26432
+ span.setStatus("ERROR");
26433
+ span.addEvent("exception", {
26434
+ "exception.message": error40.message,
26435
+ "exception.stack": error40.stack
26436
+ });
26437
+ throw error40;
26438
+ } finally {
26439
+ span.end();
26440
+ }
26441
+ }
26442
+ async flush() {
26443
+ if (this.telemetry) {
26444
+ await this.telemetry.flush();
26445
+ }
26446
+ }
26447
+ async shutdown() {
26448
+ if (this.telemetry) {
26449
+ await this.telemetry.shutdown();
26450
+ }
26451
+ }
26452
+ };
26453
+ }
26454
+ });
26455
+
26456
+ // src/agent/storage/StorageAdapter.js
26457
+ var StorageAdapter;
26458
+ var init_StorageAdapter = __esm({
26459
+ "src/agent/storage/StorageAdapter.js"() {
26460
+ "use strict";
26461
+ StorageAdapter = class {
26462
+ /**
26463
+ * Load conversation history for a session
26464
+ * @param {string} sessionId - Session identifier
26465
+ * @returns {Promise<Array<Object>>} Array of message objects with {role, content, ...}
26466
+ */
26467
+ async loadHistory(sessionId) {
26468
+ throw new Error("StorageAdapter.loadHistory() must be implemented by subclass");
26469
+ }
26470
+ /**
26471
+ * Save a message to storage
26472
+ * @param {string} sessionId - Session identifier
26473
+ * @param {Object} message - Message object { role, content, ... }
26474
+ * @returns {Promise<void>}
26475
+ */
26476
+ async saveMessage(sessionId, message) {
26477
+ throw new Error("StorageAdapter.saveMessage() must be implemented by subclass");
26478
+ }
26479
+ /**
26480
+ * Clear history for a session
26481
+ * @param {string} sessionId - Session identifier
26482
+ * @returns {Promise<void>}
26483
+ */
26484
+ async clearHistory(sessionId) {
26485
+ throw new Error("StorageAdapter.clearHistory() must be implemented by subclass");
26486
+ }
26487
+ /**
26488
+ * Get session metadata (optional)
26489
+ * @param {string} sessionId - Session identifier
26490
+ * @returns {Promise<Object|null>} Session metadata or null
26491
+ */
26492
+ async getSessionMetadata(sessionId) {
26493
+ return null;
26494
+ }
26495
+ /**
26496
+ * Update session activity timestamp (optional)
26497
+ * @param {string} sessionId - Session identifier
26498
+ * @returns {Promise<void>}
26499
+ */
26500
+ async updateSessionActivity(sessionId) {
26501
+ }
26502
+ };
26503
+ }
26504
+ });
26505
+
26506
+ // src/agent/storage/InMemoryStorageAdapter.js
26507
+ var InMemoryStorageAdapter;
26508
+ var init_InMemoryStorageAdapter = __esm({
26509
+ "src/agent/storage/InMemoryStorageAdapter.js"() {
26510
+ "use strict";
26511
+ init_StorageAdapter();
26512
+ InMemoryStorageAdapter = class extends StorageAdapter {
26513
+ constructor() {
26514
+ super();
26515
+ this.sessions = /* @__PURE__ */ new Map();
26516
+ }
26517
+ async loadHistory(sessionId) {
26518
+ const session = this.sessions.get(sessionId);
26519
+ return session ? session.messages : [];
26520
+ }
26521
+ async saveMessage(sessionId, message) {
26522
+ if (!this.sessions.has(sessionId)) {
26523
+ this.sessions.set(sessionId, {
26524
+ messages: [],
26525
+ metadata: {
26526
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
26527
+ lastActivity: (/* @__PURE__ */ new Date()).toISOString()
26528
+ }
26529
+ });
26530
+ }
26531
+ const session = this.sessions.get(sessionId);
26532
+ session.messages.push(message);
26533
+ session.metadata.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
26534
+ }
26535
+ async clearHistory(sessionId) {
26536
+ this.sessions.delete(sessionId);
26537
+ }
26538
+ async getSessionMetadata(sessionId) {
26539
+ const session = this.sessions.get(sessionId);
26540
+ return session ? session.metadata : null;
26541
+ }
26542
+ async updateSessionActivity(sessionId) {
26543
+ const session = this.sessions.get(sessionId);
26544
+ if (session) {
26545
+ session.metadata.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
26546
+ }
26547
+ }
26548
+ };
26549
+ }
26550
+ });
26551
+
26552
+ // src/agent/hooks/HookManager.js
26553
+ var HookManager, HOOK_TYPES;
26554
+ var init_HookManager = __esm({
26555
+ "src/agent/hooks/HookManager.js"() {
26556
+ "use strict";
26557
+ HookManager = class {
26558
+ constructor() {
26559
+ this.hooks = /* @__PURE__ */ new Map();
26560
+ }
26561
+ /**
26562
+ * Register a hook callback
26563
+ * @param {string} hookName - Name of the hook
26564
+ * @param {Function} callback - Callback function
26565
+ * @returns {Function} Unregister function
26566
+ */
26567
+ on(hookName, callback) {
26568
+ if (!this.hooks.has(hookName)) {
26569
+ this.hooks.set(hookName, /* @__PURE__ */ new Set());
26570
+ }
26571
+ this.hooks.get(hookName).add(callback);
26572
+ return () => this.off(hookName, callback);
26573
+ }
26574
+ /**
26575
+ * Register a one-time hook callback
26576
+ * @param {string} hookName - Name of the hook
26577
+ * @param {Function} callback - Callback function
26578
+ * @returns {Function} Unregister function
26579
+ */
26580
+ once(hookName, callback) {
26581
+ const wrappedCallback = async (data2) => {
26582
+ this.off(hookName, wrappedCallback);
26583
+ await callback(data2);
26584
+ };
26585
+ return this.on(hookName, wrappedCallback);
26586
+ }
26587
+ /**
26588
+ * Unregister a hook callback
26589
+ * @param {string} hookName - Name of the hook
26590
+ * @param {Function} callback - Callback function
26591
+ */
26592
+ off(hookName, callback) {
26593
+ const callbacks = this.hooks.get(hookName);
26594
+ if (callbacks) {
26595
+ callbacks.delete(callback);
26596
+ }
26597
+ }
26598
+ /**
26599
+ * Emit a hook event
26600
+ * @param {string} hookName - Name of the hook
26601
+ * @param {any} data - Data to pass to callbacks
26602
+ * @returns {Promise<void>}
26603
+ */
26604
+ async emit(hookName, data2) {
26605
+ const callbacks = this.hooks.get(hookName);
26606
+ if (!callbacks || callbacks.size === 0) return;
26607
+ const promises = Array.from(callbacks).map((callback) => {
26608
+ try {
26609
+ return Promise.resolve(callback(data2));
26610
+ } catch (error40) {
26611
+ return Promise.reject(error40);
26612
+ }
26613
+ });
26614
+ const results = await Promise.allSettled(promises);
26615
+ results.forEach((result, index) => {
26616
+ if (result.status === "rejected") {
26617
+ console.error(`[HookManager] Error in hook "${hookName}" (callback ${index + 1}):`, result.reason);
26618
+ }
26619
+ });
26620
+ }
26621
+ /**
26622
+ * Clear all hooks or hooks for a specific event
26623
+ * @param {string} [hookName] - Optional hook name to clear
26624
+ */
26625
+ clear(hookName) {
26626
+ if (hookName) {
26627
+ this.hooks.delete(hookName);
26628
+ } else {
26629
+ this.hooks.clear();
26630
+ }
26631
+ }
26632
+ /**
26633
+ * Get list of registered hook names
26634
+ * @returns {string[]} Array of hook names
26635
+ */
26636
+ getHookNames() {
26637
+ return Array.from(this.hooks.keys());
26638
+ }
26639
+ /**
26640
+ * Get number of callbacks for a hook
26641
+ * @param {string} hookName - Name of the hook
26642
+ * @returns {number} Number of callbacks
26643
+ */
26644
+ getCallbackCount(hookName) {
26645
+ const callbacks = this.hooks.get(hookName);
26646
+ return callbacks ? callbacks.size : 0;
26647
+ }
26648
+ };
26649
+ HOOK_TYPES = {
26650
+ // Lifecycle hooks
26651
+ AGENT_INITIALIZED: "agent:initialized",
26652
+ AGENT_CLEANUP: "agent:cleanup",
26653
+ // Message hooks
26654
+ MESSAGE_USER: "message:user",
26655
+ MESSAGE_ASSISTANT: "message:assistant",
26656
+ MESSAGE_SYSTEM: "message:system",
26657
+ // Tool execution hooks
26658
+ TOOL_START: "tool:start",
26659
+ TOOL_END: "tool:end",
26660
+ TOOL_ERROR: "tool:error",
26661
+ // AI streaming hooks
26662
+ AI_STREAM_START: "ai:stream:start",
26663
+ AI_STREAM_DELTA: "ai:stream:delta",
26664
+ AI_STREAM_END: "ai:stream:end",
26665
+ // Storage hooks
26666
+ STORAGE_LOAD: "storage:load",
26667
+ STORAGE_SAVE: "storage:save",
26668
+ STORAGE_CLEAR: "storage:clear",
26669
+ // Iteration hooks
26670
+ ITERATION_START: "iteration:start",
26671
+ ITERATION_END: "iteration:end"
26672
+ };
26673
+ }
26674
+ });
26675
+
26676
+ // src/agent/imageConfig.js
26677
+ function isFormatSupportedByProvider(extension, provider) {
26678
+ if (!extension || typeof extension !== "string") {
26103
26679
  return false;
26104
26680
  }
26105
26681
  if (extension.includes("/") || extension.includes("\\") || extension.includes("..")) {
@@ -27105,8 +27681,8 @@ function parseAndResolvePaths(pathStr, cwd) {
27105
27681
  if (/["']/.test(pathStr)) {
27106
27682
  const paths2 = splitQuotedString(pathStr);
27107
27683
  return paths2.map((p) => {
27108
- if ((0, import_path5.isAbsolute)(p)) return p;
27109
- return cwd ? (0, import_path5.resolve)(cwd, p) : p;
27684
+ if ((0, import_path6.isAbsolute)(p)) return p;
27685
+ return cwd ? (0, import_path6.resolve)(cwd, p) : p;
27110
27686
  });
27111
27687
  }
27112
27688
  let paths = pathStr.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
@@ -27118,8 +27694,8 @@ function parseAndResolvePaths(pathStr, cwd) {
27118
27694
  return allLookLikePaths ? parts : [p];
27119
27695
  });
27120
27696
  return paths.map((p) => {
27121
- if ((0, import_path5.isAbsolute)(p)) return p;
27122
- return cwd ? (0, import_path5.resolve)(cwd, p) : p;
27697
+ if ((0, import_path6.isAbsolute)(p)) return p;
27698
+ return cwd ? (0, import_path6.resolve)(cwd, p) : p;
27123
27699
  });
27124
27700
  }
27125
27701
  function resolveTargetPath(target, cwd) {
@@ -27137,17 +27713,17 @@ function resolveTargetPath(target, cwd) {
27137
27713
  filePart = target;
27138
27714
  suffix = "";
27139
27715
  }
27140
- if (!(0, import_path5.isAbsolute)(filePart) && cwd) {
27141
- filePart = (0, import_path5.resolve)(cwd, filePart);
27716
+ if (!(0, import_path6.isAbsolute)(filePart) && cwd) {
27717
+ filePart = (0, import_path6.resolve)(cwd, filePart);
27142
27718
  }
27143
27719
  return filePart + suffix;
27144
27720
  }
27145
- var import_path5, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription;
27721
+ var import_path6, searchSchema, searchAllSchema, querySchema, extractSchema, delegateSchema, listSkillsSchema, useSkillSchema, listFilesSchema, searchFilesSchema, readImageSchema, bashSchema, analyzeAllSchema, executePlanSchema, cleanupExecutePlanSchema, searchDescription, searchDelegateDescription, queryDescription, extractDescription, delegateDescription, bashDescription, analyzeAllDescription;
27146
27722
  var init_common = __esm({
27147
27723
  "src/tools/common.js"() {
27148
27724
  "use strict";
27149
27725
  init_zod();
27150
- import_path5 = require("path");
27726
+ import_path6 = require("path");
27151
27727
  searchSchema = external_exports2.object({
27152
27728
  query: external_exports2.string().describe("Search query \u2014 natural language questions or Elasticsearch-style keywords both work. For keywords: use quotes for exact phrases, AND/OR for boolean logic, - for negation. Probe handles stemming and camelCase/snake_case splitting automatically, so do NOT try case or style variations of the same keyword."),
27153
27729
  path: external_exports2.string().optional().default(".").describe('Path to search in. For dependencies use "go:github.com/owner/repo", "js:package_name", or "rust:cargo_name" etc.'),
@@ -27310,7 +27886,7 @@ var init_symbolEdit = __esm({
27310
27886
  // src/tools/fileTracker.js
27311
27887
  function normalizePath(filePath) {
27312
27888
  if (!filePath) return filePath;
27313
- return (0, import_path6.resolve)(filePath);
27889
+ return (0, import_path7.resolve)(filePath);
27314
27890
  }
27315
27891
  function computeContentHash(content) {
27316
27892
  const normalized = (content || "").split("\n").map((l) => l.trimEnd()).join("\n");
@@ -27350,12 +27926,12 @@ function parseFilePathsFromOutput(output) {
27350
27926
  }
27351
27927
  return paths;
27352
27928
  }
27353
- var import_crypto2, import_path6, FileTracker;
27929
+ var import_crypto2, import_path7, FileTracker;
27354
27930
  var init_fileTracker = __esm({
27355
27931
  "src/tools/fileTracker.js"() {
27356
27932
  "use strict";
27357
27933
  import_crypto2 = require("crypto");
27358
- import_path6 = require("path");
27934
+ import_path7 = require("path");
27359
27935
  init_symbolEdit();
27360
27936
  FileTracker = class {
27361
27937
  /**
@@ -27456,7 +28032,7 @@ var init_fileTracker = __esm({
27456
28032
  const symbolPromises = [];
27457
28033
  for (const target of targets) {
27458
28034
  const filePath = extractFilePath(target);
27459
- const resolved = (0, import_path6.isAbsolute)(filePath) ? filePath : (0, import_path6.resolve)(cwd, filePath);
28035
+ const resolved = (0, import_path7.isAbsolute)(filePath) ? filePath : (0, import_path7.resolve)(cwd, filePath);
27460
28036
  if (!seenPaths.has(resolved)) {
27461
28037
  seenPaths.add(resolved);
27462
28038
  this.markFileSeen(resolved);
@@ -27496,7 +28072,7 @@ var init_fileTracker = __esm({
27496
28072
  async trackFilesFromOutput(output, cwd) {
27497
28073
  const paths = parseFilePathsFromOutput(output);
27498
28074
  for (const filePath of paths) {
27499
- const resolved = (0, import_path6.isAbsolute)(filePath) ? filePath : (0, import_path6.resolve)(cwd, filePath);
28075
+ const resolved = (0, import_path7.isAbsolute)(filePath) ? filePath : (0, import_path7.resolve)(cwd, filePath);
27500
28076
  this.markFileSeen(resolved);
27501
28077
  }
27502
28078
  }
@@ -31643,22 +32219,22 @@ var init_esm3 = __esm({
31643
32219
  });
31644
32220
 
31645
32221
  // node_modules/path-scurry/dist/esm/index.js
31646
- var import_node_path, import_node_url, import_fs4, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize2, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
32222
+ var import_node_path, import_node_url, import_fs5, actualFS, import_promises, realpathSync2, defaultFS, fsFromOption, uncDriveRegexp, uncToDrive, eitherSep, UNKNOWN, IFIFO, IFCHR, IFDIR, IFBLK, IFREG, IFLNK, IFSOCK, IFMT, IFMT_UNKNOWN, READDIR_CALLED, LSTAT_CALLED, ENOTDIR, ENOENT, ENOREADLINK, ENOREALPATH, ENOCHILD, TYPEMASK, entToType, normalizeCache, normalize2, normalizeNocaseCache, normalizeNocase, ResolveCache, ChildrenCache, setAsCwd, PathBase, PathWin32, PathPosix, PathScurryBase, PathScurryWin32, PathScurryPosix, PathScurryDarwin, Path, PathScurry;
31647
32223
  var init_esm4 = __esm({
31648
32224
  "node_modules/path-scurry/dist/esm/index.js"() {
31649
32225
  init_esm2();
31650
32226
  import_node_path = require("node:path");
31651
32227
  import_node_url = require("node:url");
31652
- import_fs4 = require("fs");
32228
+ import_fs5 = require("fs");
31653
32229
  actualFS = __toESM(require("node:fs"), 1);
31654
32230
  import_promises = require("node:fs/promises");
31655
32231
  init_esm3();
31656
- realpathSync2 = import_fs4.realpathSync.native;
32232
+ realpathSync2 = import_fs5.realpathSync.native;
31657
32233
  defaultFS = {
31658
- lstatSync: import_fs4.lstatSync,
31659
- readdir: import_fs4.readdir,
31660
- readdirSync: import_fs4.readdirSync,
31661
- readlinkSync: import_fs4.readlinkSync,
32234
+ lstatSync: import_fs5.lstatSync,
32235
+ readdir: import_fs5.readdir,
32236
+ readdirSync: import_fs5.readdirSync,
32237
+ readlinkSync: import_fs5.readlinkSync,
31662
32238
  realpathSync: realpathSync2,
31663
32239
  promises: {
31664
32240
  lstat: import_promises.lstat,
@@ -34595,7 +35171,7 @@ function createWrappedTools(baseTools) {
34595
35171
  }
34596
35172
  return wrappedTools;
34597
35173
  }
34598
- var import_child_process6, import_util13, import_crypto3, import_events, import_fs5, import_fs6, import_path7, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
35174
+ var import_child_process6, import_util13, import_crypto3, import_events, import_fs6, import_fs7, import_path8, toolCallEmitter, activeToolExecutions, wrapToolWithEmitter, listFilesTool, searchFilesTool, listFilesToolInstance, searchFilesToolInstance;
34599
35175
  var init_probeTool = __esm({
34600
35176
  "src/agent/probeTool.js"() {
34601
35177
  "use strict";
@@ -34604,9 +35180,9 @@ var init_probeTool = __esm({
34604
35180
  import_util13 = require("util");
34605
35181
  import_crypto3 = require("crypto");
34606
35182
  import_events = require("events");
34607
- import_fs5 = __toESM(require("fs"), 1);
34608
- import_fs6 = require("fs");
34609
- import_path7 = __toESM(require("path"), 1);
35183
+ import_fs6 = __toESM(require("fs"), 1);
35184
+ import_fs7 = require("fs");
35185
+ import_path8 = __toESM(require("path"), 1);
34610
35186
  init_esm5();
34611
35187
  init_symlink_utils();
34612
35188
  toolCallEmitter = new import_events.EventEmitter();
@@ -34695,17 +35271,17 @@ var init_probeTool = __esm({
34695
35271
  execute: async (params) => {
34696
35272
  const { directory = ".", workingDirectory } = params;
34697
35273
  const baseCwd = workingDirectory || process.cwd();
34698
- const secureBaseDir = import_path7.default.resolve(baseCwd);
35274
+ const secureBaseDir = import_path8.default.resolve(baseCwd);
34699
35275
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
34700
35276
  let targetDir;
34701
- if (import_path7.default.isAbsolute(directory)) {
34702
- targetDir = import_path7.default.resolve(directory);
34703
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
35277
+ if (import_path8.default.isAbsolute(directory)) {
35278
+ targetDir = import_path8.default.resolve(directory);
35279
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
34704
35280
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
34705
35281
  }
34706
35282
  } else {
34707
- targetDir = import_path7.default.resolve(secureBaseDir, directory);
34708
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
35283
+ targetDir = import_path8.default.resolve(secureBaseDir, directory);
35284
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
34709
35285
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
34710
35286
  }
34711
35287
  }
@@ -34714,7 +35290,7 @@ var init_probeTool = __esm({
34714
35290
  console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
34715
35291
  }
34716
35292
  try {
34717
- const files = await import_fs6.promises.readdir(targetDir, { withFileTypes: true });
35293
+ const files = await import_fs7.promises.readdir(targetDir, { withFileTypes: true });
34718
35294
  const formatSize = (size) => {
34719
35295
  if (size < 1024) return `${size}B`;
34720
35296
  if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
@@ -34722,7 +35298,7 @@ var init_probeTool = __esm({
34722
35298
  return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
34723
35299
  };
34724
35300
  const entries = await Promise.all(files.map(async (file2) => {
34725
- const fullPath = import_path7.default.join(targetDir, file2.name);
35301
+ const fullPath = import_path8.default.join(targetDir, file2.name);
34726
35302
  const entryType = await getEntryType(file2, fullPath);
34727
35303
  return {
34728
35304
  name: file2.name,
@@ -34759,17 +35335,17 @@ var init_probeTool = __esm({
34759
35335
  throw new Error("Pattern is required for file search");
34760
35336
  }
34761
35337
  const baseCwd = workingDirectory || process.cwd();
34762
- const secureBaseDir = import_path7.default.resolve(baseCwd);
35338
+ const secureBaseDir = import_path8.default.resolve(baseCwd);
34763
35339
  const isDependencyPath = directory.startsWith("/dep/") || directory.startsWith("go:") || directory.startsWith("js:") || directory.startsWith("rust:");
34764
35340
  let targetDir;
34765
- if (import_path7.default.isAbsolute(directory)) {
34766
- targetDir = import_path7.default.resolve(directory);
34767
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
35341
+ if (import_path8.default.isAbsolute(directory)) {
35342
+ targetDir = import_path8.default.resolve(directory);
35343
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
34768
35344
  throw new Error(`Path traversal attempt detected. Cannot access directory outside workspace: ${directory}`);
34769
35345
  }
34770
35346
  } else {
34771
- targetDir = import_path7.default.resolve(secureBaseDir, directory);
34772
- if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
35347
+ targetDir = import_path8.default.resolve(secureBaseDir, directory);
35348
+ if (!isDependencyPath && !targetDir.startsWith(secureBaseDir + import_path8.default.sep) && targetDir !== secureBaseDir) {
34773
35349
  throw new Error(`Path traversal attempt detected. Access denied: ${directory}`);
34774
35350
  }
34775
35351
  }
@@ -73424,11 +74000,11 @@ function loadMCPConfigurationFromPath(configPath) {
73424
74000
  if (!configPath) {
73425
74001
  throw new Error("Config path is required");
73426
74002
  }
73427
- if (!(0, import_fs7.existsSync)(configPath)) {
74003
+ if (!(0, import_fs8.existsSync)(configPath)) {
73428
74004
  throw new Error(`MCP configuration file not found: ${configPath}`);
73429
74005
  }
73430
74006
  try {
73431
- const content = (0, import_fs7.readFileSync)(configPath, "utf8");
74007
+ const content = (0, import_fs8.readFileSync)(configPath, "utf8");
73432
74008
  const config2 = JSON.parse(content);
73433
74009
  if (process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1") {
73434
74010
  console.error(`[MCP DEBUG] Loaded configuration from: ${configPath}`);
@@ -73443,19 +74019,19 @@ function loadMCPConfiguration() {
73443
74019
  // Environment variable path
73444
74020
  process.env.MCP_CONFIG_PATH,
73445
74021
  // Local project paths
73446
- (0, import_path8.join)(process.cwd(), ".mcp", "config.json"),
73447
- (0, import_path8.join)(process.cwd(), "mcp.config.json"),
74022
+ (0, import_path9.join)(process.cwd(), ".mcp", "config.json"),
74023
+ (0, import_path9.join)(process.cwd(), "mcp.config.json"),
73448
74024
  // Home directory paths
73449
- (0, import_path8.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
73450
- (0, import_path8.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
74025
+ (0, import_path9.join)((0, import_os3.homedir)(), ".config", "probe", "mcp.json"),
74026
+ (0, import_path9.join)((0, import_os3.homedir)(), ".mcp", "config.json"),
73451
74027
  // Claude-style config location
73452
- (0, import_path8.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
74028
+ (0, import_path9.join)((0, import_os3.homedir)(), "Library", "Application Support", "Claude", "mcp_config.json")
73453
74029
  ].filter(Boolean);
73454
74030
  let config2 = null;
73455
74031
  for (const configPath of configPaths) {
73456
- if ((0, import_fs7.existsSync)(configPath)) {
74032
+ if ((0, import_fs8.existsSync)(configPath)) {
73457
74033
  try {
73458
- const content = (0, import_fs7.readFileSync)(configPath, "utf8");
74034
+ const content = (0, import_fs8.readFileSync)(configPath, "utf8");
73459
74035
  config2 = JSON.parse(content);
73460
74036
  if (process.env.DEBUG === "1" || process.env.DEBUG_MCP === "1") {
73461
74037
  console.error(`[MCP DEBUG] Loaded configuration from: ${configPath}`);
@@ -73576,16 +74152,16 @@ function parseEnabledServers(config2) {
73576
74152
  }
73577
74153
  return servers;
73578
74154
  }
73579
- var import_fs7, import_path8, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
74155
+ var import_fs8, import_path9, import_os3, import_url4, __filename4, __dirname4, DEFAULT_TIMEOUT, MAX_TIMEOUT, DEFAULT_CONFIG;
73580
74156
  var init_config = __esm({
73581
74157
  "src/agent/mcp/config.js"() {
73582
74158
  "use strict";
73583
- import_fs7 = require("fs");
73584
- import_path8 = require("path");
74159
+ import_fs8 = require("fs");
74160
+ import_path9 = require("path");
73585
74161
  import_os3 = require("os");
73586
74162
  import_url4 = require("url");
73587
74163
  __filename4 = (0, import_url4.fileURLToPath)("file:///");
73588
- __dirname4 = (0, import_path8.dirname)(__filename4);
74164
+ __dirname4 = (0, import_path9.dirname)(__filename4);
73589
74165
  DEFAULT_TIMEOUT = 3e4;
73590
74166
  MAX_TIMEOUT = (() => {
73591
74167
  if (process.env.MCP_MAX_TIMEOUT) {
@@ -73599,7 +74175,7 @@ var init_config = __esm({
73599
74175
  // Example probe server configuration
73600
74176
  "probe-local": {
73601
74177
  command: "node",
73602
- args: [(0, import_path8.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
74178
+ args: [(0, import_path9.join)(__dirname4, "../../../examples/chat/mcpServer.js")],
73603
74179
  transport: "stdio",
73604
74180
  enabled: false
73605
74181
  },
@@ -81749,17 +82325,17 @@ async function parseSkillFile(skillFilePath, directoryName) {
81749
82325
  description,
81750
82326
  skillFilePath,
81751
82327
  directoryName,
81752
- sourceDir: (0, import_path9.dirname)(skillFilePath)
82328
+ sourceDir: (0, import_path10.dirname)(skillFilePath)
81753
82329
  },
81754
82330
  error: null
81755
82331
  };
81756
82332
  }
81757
- var import_promises2, import_path9, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
82333
+ var import_promises2, import_path10, import_yaml, SKILL_NAME_REGEX, MAX_SKILL_NAME_LENGTH, MAX_DESCRIPTION_CHARS;
81758
82334
  var init_parser7 = __esm({
81759
82335
  "src/agent/skills/parser.js"() {
81760
82336
  "use strict";
81761
82337
  import_promises2 = require("fs/promises");
81762
- import_path9 = require("path");
82338
+ import_path10 = require("path");
81763
82339
  import_yaml = __toESM(require_dist(), 1);
81764
82340
  SKILL_NAME_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
81765
82341
  MAX_SKILL_NAME_LENGTH = 64;
@@ -81769,12 +82345,12 @@ var init_parser7 = __esm({
81769
82345
 
81770
82346
  // src/agent/skills/registry.js
81771
82347
  function isPathInside(basePath, targetPath) {
81772
- const base2 = (0, import_path10.resolve)(basePath);
81773
- const target = (0, import_path10.resolve)(targetPath);
81774
- const rel = (0, import_path10.relative)(base2, target);
82348
+ const base2 = (0, import_path11.resolve)(basePath);
82349
+ const target = (0, import_path11.resolve)(targetPath);
82350
+ const rel = (0, import_path11.relative)(base2, target);
81775
82351
  if (rel === "") return true;
81776
- if (rel === ".." || rel.startsWith(`..${import_path10.sep}`)) return false;
81777
- if ((0, import_path10.isAbsolute)(rel)) return false;
82352
+ if (rel === ".." || rel.startsWith(`..${import_path11.sep}`)) return false;
82353
+ if ((0, import_path11.isAbsolute)(rel)) return false;
81778
82354
  return true;
81779
82355
  }
81780
82356
  function isSafeEntryName(name15) {
@@ -81782,19 +82358,19 @@ function isSafeEntryName(name15) {
81782
82358
  if (name15.includes("\0")) return false;
81783
82359
  return !name15.includes("/") && !name15.includes("\\");
81784
82360
  }
81785
- var import_fs8, import_promises3, import_path10, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
82361
+ var import_fs9, import_promises3, import_path11, DEFAULT_SKILL_DIRS, SKILL_FILE_NAME, SkillRegistry;
81786
82362
  var init_registry = __esm({
81787
82363
  "src/agent/skills/registry.js"() {
81788
82364
  "use strict";
81789
- import_fs8 = require("fs");
82365
+ import_fs9 = require("fs");
81790
82366
  import_promises3 = require("fs/promises");
81791
- import_path10 = require("path");
82367
+ import_path11 = require("path");
81792
82368
  init_parser7();
81793
82369
  DEFAULT_SKILL_DIRS = [".claude/skills", ".codex/skills", "skills", ".skills"];
81794
82370
  SKILL_FILE_NAME = "SKILL.md";
81795
82371
  SkillRegistry = class {
81796
82372
  constructor({ repoRoot, skillDirs = DEFAULT_SKILL_DIRS, debug = false } = {}) {
81797
- this.repoRoot = repoRoot ? (0, import_path10.resolve)(repoRoot) : process.cwd();
82373
+ this.repoRoot = repoRoot ? (0, import_path11.resolve)(repoRoot) : process.cwd();
81798
82374
  this.repoRootReal = null;
81799
82375
  this.skillDirs = Array.isArray(skillDirs) && skillDirs.length > 0 ? skillDirs : DEFAULT_SKILL_DIRS;
81800
82376
  this.debug = debug;
@@ -81848,8 +82424,8 @@ var init_registry = __esm({
81848
82424
  }
81849
82425
  }
81850
82426
  async _resolveSkillDir(skillDir) {
81851
- const resolved = (0, import_path10.isAbsolute)(skillDir) ? (0, import_path10.resolve)(skillDir) : (0, import_path10.resolve)(this.repoRoot, skillDir);
81852
- const repoRoot = this.repoRootReal || (0, import_path10.resolve)(this.repoRoot);
82427
+ const resolved = (0, import_path11.isAbsolute)(skillDir) ? (0, import_path11.resolve)(skillDir) : (0, import_path11.resolve)(this.repoRoot, skillDir);
82428
+ const repoRoot = this.repoRootReal || (0, import_path11.resolve)(this.repoRoot);
81853
82429
  const resolvedReal = await this._resolveRealPath(resolved);
81854
82430
  if (!resolvedReal) return null;
81855
82431
  if (!isPathInside(repoRoot, resolvedReal)) {
@@ -81861,7 +82437,7 @@ var init_registry = __esm({
81861
82437
  return resolvedReal;
81862
82438
  }
81863
82439
  async _scanSkillDir(dirPath) {
81864
- if (!(0, import_fs8.existsSync)(dirPath)) return [];
82440
+ if (!(0, import_fs9.existsSync)(dirPath)) return [];
81865
82441
  let entries;
81866
82442
  try {
81867
82443
  entries = await (0, import_promises3.readdir)(dirPath, { withFileTypes: true });
@@ -81880,8 +82456,8 @@ var init_registry = __esm({
81880
82456
  }
81881
82457
  continue;
81882
82458
  }
81883
- const skillFolder = (0, import_path10.join)(dirPath, entry.name);
81884
- const skillFilePath = (0, import_path10.join)(skillFolder, SKILL_FILE_NAME);
82459
+ const skillFolder = (0, import_path11.join)(dirPath, entry.name);
82460
+ const skillFilePath = (0, import_path11.join)(skillFolder, SKILL_FILE_NAME);
81885
82461
  let skillStat;
81886
82462
  try {
81887
82463
  skillStat = await (0, import_promises3.lstat)(skillFilePath);
@@ -81901,7 +82477,7 @@ var init_registry = __esm({
81901
82477
  }
81902
82478
  continue;
81903
82479
  }
81904
- if (!(0, import_fs8.existsSync)(skillFilePath)) continue;
82480
+ if (!(0, import_fs9.existsSync)(skillFilePath)) continue;
81905
82481
  const { skill, error: error40 } = await parseSkillFile(skillFilePath, entry.name);
81906
82482
  if (!skill) {
81907
82483
  if (error40) {
@@ -82826,9 +83402,9 @@ async function truncateIfNeeded(content, tokenCounter, sessionId, maxTokens) {
82826
83402
  let tempFilePath = null;
82827
83403
  let fileError = null;
82828
83404
  try {
82829
- const tempDir = (0, import_path11.join)((0, import_os4.tmpdir)(), "probe-output");
83405
+ const tempDir = (0, import_path12.join)((0, import_os4.tmpdir)(), "probe-output");
82830
83406
  await (0, import_promises4.mkdir)(tempDir, { recursive: true });
82831
- tempFilePath = (0, import_path11.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto4.randomUUID)()}.txt`);
83407
+ tempFilePath = (0, import_path12.join)(tempDir, `tool-output-${sessionId || "unknown"}-${(0, import_crypto4.randomUUID)()}.txt`);
82832
83408
  await (0, import_promises4.writeFile)(tempFilePath, content, "utf8");
82833
83409
  } catch (err) {
82834
83410
  fileError = err.message || "Unknown file system error";
@@ -82876,13 +83452,13 @@ ${truncatedBody}
82876
83452
  error: fileError || void 0
82877
83453
  };
82878
83454
  }
82879
- var import_promises4, import_os4, import_path11, import_crypto4, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
83455
+ var import_promises4, import_os4, import_path12, import_crypto4, DEFAULT_MAX_OUTPUT_TOKENS, CHARS_PER_TOKEN, TAIL_TOKENS, MIN_LIMIT_FOR_TAIL;
82880
83456
  var init_outputTruncator = __esm({
82881
83457
  "src/agent/outputTruncator.js"() {
82882
83458
  "use strict";
82883
83459
  import_promises4 = require("fs/promises");
82884
83460
  import_os4 = require("os");
82885
- import_path11 = require("path");
83461
+ import_path12 = require("path");
82886
83462
  import_crypto4 = require("crypto");
82887
83463
  DEFAULT_MAX_OUTPUT_TOKENS = 2e4;
82888
83464
  CHARS_PER_TOKEN = 4;
@@ -94220,8 +94796,8 @@ async function executeBashCommand(command, options = {}) {
94220
94796
  } = options;
94221
94797
  let cwd = workingDirectory;
94222
94798
  try {
94223
- cwd = (0, import_path12.resolve)(cwd);
94224
- if (!(0, import_fs9.existsSync)(cwd)) {
94799
+ cwd = (0, import_path13.resolve)(cwd);
94800
+ if (!(0, import_fs10.existsSync)(cwd)) {
94225
94801
  throw new Error(`Working directory does not exist: ${cwd}`);
94226
94802
  }
94227
94803
  } catch (error40) {
@@ -94477,7 +95053,7 @@ function validateExecutionOptions(options = {}) {
94477
95053
  if (options.workingDirectory) {
94478
95054
  if (typeof options.workingDirectory !== "string") {
94479
95055
  errors.push("workingDirectory must be a string");
94480
- } else if (!(0, import_fs9.existsSync)(options.workingDirectory)) {
95056
+ } else if (!(0, import_fs10.existsSync)(options.workingDirectory)) {
94481
95057
  errors.push(`workingDirectory does not exist: ${options.workingDirectory}`);
94482
95058
  }
94483
95059
  }
@@ -94490,24 +95066,24 @@ function validateExecutionOptions(options = {}) {
94490
95066
  warnings
94491
95067
  };
94492
95068
  }
94493
- var import_child_process7, import_path12, import_fs9;
95069
+ var import_child_process7, import_path13, import_fs10;
94494
95070
  var init_bashExecutor = __esm({
94495
95071
  "src/agent/bashExecutor.js"() {
94496
95072
  "use strict";
94497
95073
  import_child_process7 = require("child_process");
94498
- import_path12 = require("path");
94499
- import_fs9 = require("fs");
95074
+ import_path13 = require("path");
95075
+ import_fs10 = require("fs");
94500
95076
  init_bashCommandUtils();
94501
95077
  }
94502
95078
  });
94503
95079
 
94504
95080
  // src/tools/bash.js
94505
- var import_ai, import_path13, bashTool;
95081
+ var import_ai, import_path14, bashTool;
94506
95082
  var init_bash = __esm({
94507
95083
  "src/tools/bash.js"() {
94508
95084
  "use strict";
94509
95085
  import_ai = require("ai");
94510
- import_path13 = require("path");
95086
+ import_path14 = require("path");
94511
95087
  init_bashPermissions();
94512
95088
  init_bashExecutor();
94513
95089
  init_path_validation();
@@ -94624,12 +95200,12 @@ For code exploration, try these safe alternatives:
94624
95200
  - npm list, pip list for package information`;
94625
95201
  }
94626
95202
  const defaultDir = getDefaultWorkingDirectory();
94627
- const workingDir = workingDirectory ? (0, import_path13.isAbsolute)(workingDirectory) ? (0, import_path13.resolve)(workingDirectory) : (0, import_path13.resolve)(defaultDir, workingDirectory) : defaultDir;
95203
+ const workingDir = workingDirectory ? (0, import_path14.isAbsolute)(workingDirectory) ? (0, import_path14.resolve)(workingDirectory) : (0, import_path14.resolve)(defaultDir, workingDirectory) : defaultDir;
94628
95204
  if (allowedFolders && allowedFolders.length > 0) {
94629
95205
  const resolvedWorkingDir = safeRealpath(workingDir);
94630
95206
  const isAllowed = allowedFolders.some((folder) => {
94631
95207
  const resolvedFolder = safeRealpath(folder);
94632
- return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path13.sep);
95208
+ return resolvedWorkingDir === resolvedFolder || resolvedWorkingDir.startsWith(resolvedFolder + import_path14.sep);
94633
95209
  });
94634
95210
  if (!isAllowed) {
94635
95211
  const relativeDir = toRelativePath(workingDir, workspaceRoot);
@@ -95943,12 +96519,12 @@ async function createEnhancedClaudeCLIEngine(options = {}) {
95943
96519
  console.log("[DEBUG] Built-in MCP server started");
95944
96520
  console.log("[DEBUG] MCP URL:", `http://${host}:${port}/mcp`);
95945
96521
  }
95946
- mcpConfigPath = import_path14.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
96522
+ mcpConfigPath = import_path15.default.join(import_os5.default.tmpdir(), `probe-mcp-${session.id}.json`);
95947
96523
  const mcpConfig = {
95948
96524
  mcpServers: {
95949
96525
  probe: {
95950
96526
  command: "node",
95951
- args: [import_path14.default.join(process.cwd(), "mcp-probe-server.js")],
96527
+ args: [import_path15.default.join(process.cwd(), "mcp-probe-server.js")],
95952
96528
  env: {
95953
96529
  PROBE_WORKSPACE: process.cwd(),
95954
96530
  DEBUG: debug ? "true" : "false"
@@ -96373,14 +96949,14 @@ function combinePrompts(systemPrompt, customPrompt, agent) {
96373
96949
  }
96374
96950
  return systemPrompt || "";
96375
96951
  }
96376
- var import_child_process8, import_crypto6, import_promises5, import_path14, import_os5, import_events3;
96952
+ var import_child_process8, import_crypto6, import_promises5, import_path15, import_os5, import_events3;
96377
96953
  var init_enhanced_claude_code = __esm({
96378
96954
  "src/agent/engines/enhanced-claude-code.js"() {
96379
96955
  "use strict";
96380
96956
  import_child_process8 = require("child_process");
96381
96957
  import_crypto6 = require("crypto");
96382
96958
  import_promises5 = __toESM(require("fs/promises"), 1);
96383
- import_path14 = __toESM(require("path"), 1);
96959
+ import_path15 = __toESM(require("path"), 1);
96384
96960
  import_os5 = __toESM(require("os"), 1);
96385
96961
  import_events3 = require("events");
96386
96962
  init_built_in_server();
@@ -96751,7 +97327,7 @@ function debugLogToolResults(toolResults) {
96751
97327
  console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
96752
97328
  }
96753
97329
  }
96754
- var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai4, import_crypto8, import_events4, import_fs10, import_promises6, import_path15, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
97330
+ var import_dotenv, import_anthropic2, import_openai2, import_google2, import_ai4, import_crypto8, import_events4, import_fs11, import_promises6, import_path16, ENGINE_ACTIVITY_TIMEOUT_DEFAULT, ENGINE_ACTIVITY_TIMEOUT_MIN, ENGINE_ACTIVITY_TIMEOUT_MAX, MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
96755
97331
  var init_ProbeAgent = __esm({
96756
97332
  "src/agent/ProbeAgent.js"() {
96757
97333
  "use strict";
@@ -96763,10 +97339,11 @@ var init_ProbeAgent = __esm({
96763
97339
  import_ai4 = require("ai");
96764
97340
  import_crypto8 = require("crypto");
96765
97341
  import_events4 = require("events");
96766
- import_fs10 = require("fs");
97342
+ import_fs11 = require("fs");
96767
97343
  import_promises6 = require("fs/promises");
96768
- import_path15 = require("path");
97344
+ import_path16 = require("path");
96769
97345
  init_tokenCounter();
97346
+ init_simpleTelemetry();
96770
97347
  init_InMemoryStorageAdapter();
96771
97348
  init_HookManager();
96772
97349
  init_imageConfig();
@@ -97430,7 +98007,7 @@ var init_ProbeAgent = __esm({
97430
98007
  if (!imagePath) {
97431
98008
  throw new Error("Image path is required");
97432
98009
  }
97433
- const filename = (0, import_path15.basename)(imagePath);
98010
+ const filename = (0, import_path16.basename)(imagePath);
97434
98011
  const extension = filename.toLowerCase().split(".").pop();
97435
98012
  if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
97436
98013
  throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
@@ -98170,10 +98747,10 @@ var init_ProbeAgent = __esm({
98170
98747
  execute: async (params) => {
98171
98748
  let resolvedWorkingDirectory = this.workspaceRoot || this.cwd || this.allowedFolders && this.allowedFolders[0] || process.cwd();
98172
98749
  if (params.workingDirectory) {
98173
- const requestedDir = safeRealpath((0, import_path15.isAbsolute)(params.workingDirectory) ? (0, import_path15.resolve)(params.workingDirectory) : (0, import_path15.resolve)(resolvedWorkingDirectory, params.workingDirectory));
98750
+ const requestedDir = safeRealpath((0, import_path16.isAbsolute)(params.workingDirectory) ? (0, import_path16.resolve)(params.workingDirectory) : (0, import_path16.resolve)(resolvedWorkingDirectory, params.workingDirectory));
98174
98751
  const isWithinAllowed = !this.allowedFolders || this.allowedFolders.length === 0 || this.allowedFolders.some((folder) => {
98175
98752
  const resolvedFolder = safeRealpath(folder);
98176
- return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path15.sep);
98753
+ return requestedDir === resolvedFolder || requestedDir.startsWith(resolvedFolder + import_path16.sep);
98177
98754
  });
98178
98755
  if (isWithinAllowed) {
98179
98756
  resolvedWorkingDirectory = requestedDir;
@@ -98262,7 +98839,7 @@ var init_ProbeAgent = __esm({
98262
98839
  });
98263
98840
  let toolResultContent = typeof result === "string" ? result : JSON.stringify(result, null, 2);
98264
98841
  if (this.workspaceRoot && toolResultContent) {
98265
- const wsPrefix = this.workspaceRoot.endsWith(import_path15.sep) ? this.workspaceRoot : this.workspaceRoot + import_path15.sep;
98842
+ const wsPrefix = this.workspaceRoot.endsWith(import_path16.sep) ? this.workspaceRoot : this.workspaceRoot + import_path16.sep;
98266
98843
  toolResultContent = toolResultContent.split(wsPrefix).join("");
98267
98844
  }
98268
98845
  const { cleanedContent, extractedBlocks } = extractRawOutputBlocks(toolResultContent);
@@ -98632,7 +99209,7 @@ var init_ProbeAgent = __esm({
98632
99209
  let resolvedPath = imagePath;
98633
99210
  if (!imagePath.includes("/") && !imagePath.includes("\\")) {
98634
99211
  for (const dir of listFilesDirectories) {
98635
- const potentialPath = (0, import_path15.resolve)(dir, imagePath);
99212
+ const potentialPath = (0, import_path16.resolve)(dir, imagePath);
98636
99213
  const loaded = await this.loadImageIfValid(potentialPath);
98637
99214
  if (loaded) {
98638
99215
  if (this.debug) {
@@ -98657,7 +99234,7 @@ var init_ProbeAgent = __esm({
98657
99234
  let match2;
98658
99235
  while ((match2 = fileHeaderPattern.exec(content)) !== null) {
98659
99236
  const filePath = match2[1].trim();
98660
- const dir = (0, import_path15.dirname)(filePath);
99237
+ const dir = (0, import_path16.dirname)(filePath);
98661
99238
  if (dir && dir !== ".") {
98662
99239
  directories.push(dir);
98663
99240
  if (this.debug) {
@@ -98702,17 +99279,17 @@ var init_ProbeAgent = __esm({
98702
99279
  const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
98703
99280
  let absolutePath;
98704
99281
  let isPathAllowed2 = false;
98705
- if ((0, import_path15.isAbsolute)(imagePath)) {
98706
- absolutePath = safeRealpath((0, import_path15.resolve)(imagePath));
99282
+ if ((0, import_path16.isAbsolute)(imagePath)) {
99283
+ absolutePath = safeRealpath((0, import_path16.resolve)(imagePath));
98707
99284
  isPathAllowed2 = allowedDirs.some((dir) => {
98708
99285
  const resolvedDir = safeRealpath(dir);
98709
- return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path15.sep);
99286
+ return absolutePath === resolvedDir || absolutePath.startsWith(resolvedDir + import_path16.sep);
98710
99287
  });
98711
99288
  } else {
98712
99289
  for (const dir of allowedDirs) {
98713
99290
  const resolvedDir = safeRealpath(dir);
98714
- const resolvedPath = safeRealpath((0, import_path15.resolve)(dir, imagePath));
98715
- if (resolvedPath === resolvedDir || resolvedPath.startsWith(resolvedDir + import_path15.sep)) {
99291
+ const resolvedPath = safeRealpath((0, import_path16.resolve)(dir, imagePath));
99292
+ if (resolvedPath === resolvedDir || resolvedPath.startsWith(resolvedDir + import_path16.sep)) {
98716
99293
  absolutePath = resolvedPath;
98717
99294
  isPathAllowed2 = true;
98718
99295
  break;
@@ -98900,8 +99477,8 @@ var init_ProbeAgent = __esm({
98900
99477
  const hasConfiguredName = !!configuredName;
98901
99478
  let guidanceCandidates = [];
98902
99479
  if (hasConfiguredName) {
98903
- const targetName = (0, import_path15.basename)(configuredName);
98904
- if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path15.isAbsolute)(configuredName)) {
99480
+ const targetName = (0, import_path16.basename)(configuredName);
99481
+ if (configuredName !== targetName || configuredName.includes("/") || configuredName.includes("\\") || configuredName.includes("..") || (0, import_path16.isAbsolute)(configuredName)) {
98905
99482
  console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
98906
99483
  } else if (targetName) {
98907
99484
  const targetLower = targetName.toLowerCase();
@@ -98914,7 +99491,7 @@ var init_ProbeAgent = __esm({
98914
99491
  } else {
98915
99492
  guidanceCandidates = ["agents.md", "claude.md"];
98916
99493
  }
98917
- if (!(0, import_fs10.existsSync)(rootDirectory)) {
99494
+ if (!(0, import_fs11.existsSync)(rootDirectory)) {
98918
99495
  this._architectureContextLoaded = true;
98919
99496
  return null;
98920
99497
  }
@@ -98968,7 +99545,7 @@ var init_ProbeAgent = __esm({
98968
99545
  pushEntry(architectureMatch);
98969
99546
  const contexts = [];
98970
99547
  for (const entry of uniqueEntries) {
98971
- const filePath = (0, import_path15.resolve)(rootDirectory, entry.name);
99548
+ const filePath = (0, import_path16.resolve)(rootDirectory, entry.name);
98972
99549
  try {
98973
99550
  const content = await (0, import_promises6.readFile)(filePath, "utf8");
98974
99551
  let kind = "other";
@@ -99033,10 +99610,10 @@ ${this.architectureContext.content}
99033
99610
  }
99034
99611
  _getSkillsRepoRoot() {
99035
99612
  if (this.workspaceRoot) {
99036
- return (0, import_path15.resolve)(this.workspaceRoot);
99613
+ return (0, import_path16.resolve)(this.workspaceRoot);
99037
99614
  }
99038
99615
  if (this.allowedFolders && this.allowedFolders.length > 0) {
99039
- return (0, import_path15.resolve)(this.allowedFolders[0]);
99616
+ return (0, import_path16.resolve)(this.allowedFolders[0]);
99040
99617
  }
99041
99618
  return process.cwd();
99042
99619
  }
@@ -100105,7 +100682,7 @@ Double-check your response based on the criteria above. If everything looks good
100105
100682
  };
100106
100683
  let aiResult;
100107
100684
  if (this.tracer) {
100108
- const inputPreview = message.length > 1e3 ? message.substring(0, 1e3) + "... [truncated]" : message;
100685
+ const inputPreview = truncateForSpan(message, 4096);
100109
100686
  aiResult = await this.tracer.withSpan("ai.request", executeAIRequest, {
100110
100687
  "ai.model": this.model,
100111
100688
  "ai.provider": this.clientApiProvider || "auto",
@@ -100115,6 +100692,12 @@ Double-check your response based on the criteria above. If everything looks good
100115
100692
  "max_tokens": maxResponseTokens,
100116
100693
  "temperature": 0.3,
100117
100694
  "message_count": currentMessages.length
100695
+ }, (span, result) => {
100696
+ const text = result?.finalText || "";
100697
+ span.setAttributes({
100698
+ "ai.output": truncateForSpan(text),
100699
+ "ai.output_length": text.length
100700
+ });
100118
100701
  });
100119
100702
  } else {
100120
100703
  aiResult = await executeAIRequest();
@@ -100138,6 +100721,9 @@ Double-check your response based on the criteria above. If everything looks good
100138
100721
  } else if (aiResult.finalText) {
100139
100722
  finalResult = aiResult.finalText;
100140
100723
  }
100724
+ if (finalResult === null || finalResult === void 0) {
100725
+ finalResult = "";
100726
+ }
100141
100727
  if (gracefulTimeoutState.triggered) {
100142
100728
  const timeoutNotice = "**Note: This response was generated under a time constraint. The research may be incomplete, and some planned searches or analysis steps were not completed.**\n\n";
100143
100729
  if (!finalResult || finalResult === DEFAULT_MAX_ITER_MSG || finalResult.startsWith("I was unable to complete your request after")) {
@@ -102451,7 +103037,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
102451
103037
  "Remember: if your search returned relevant results, use nextPage=true to check for more before outputting."
102452
103038
  ].join("\n");
102453
103039
  }
102454
- var import_ai5, import_fs11, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
103040
+ var import_ai5, import_fs12, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
102455
103041
  var init_vercel = __esm({
102456
103042
  "src/tools/vercel.js"() {
102457
103043
  "use strict";
@@ -102462,9 +103048,10 @@ var init_vercel = __esm({
102462
103048
  init_delegate();
102463
103049
  init_analyzeAll();
102464
103050
  init_common();
102465
- import_fs11 = require("fs");
103051
+ import_fs12 = require("fs");
102466
103052
  init_error_types();
102467
103053
  init_hashline();
103054
+ init_simpleTelemetry();
102468
103055
  CODE_SEARCH_SCHEMA = {
102469
103056
  type: "object",
102470
103057
  properties: {
@@ -102620,6 +103207,7 @@ var init_vercel = __esm({
102620
103207
  tracer: options.tracer || null,
102621
103208
  enableBash: false,
102622
103209
  bashConfig: null,
103210
+ allowEdit: options.allowEdit || false,
102623
103211
  architectureFileName: options.architectureFileName || null,
102624
103212
  promptType: "code-searcher",
102625
103213
  allowedTools: ["search", "extract", "listFiles"],
@@ -102630,6 +103218,12 @@ var init_vercel = __esm({
102630
103218
  const delegateResult = options.tracer?.withSpan ? await options.tracer.withSpan("search.delegate", runDelegation, {
102631
103219
  "search.query": searchQuery,
102632
103220
  "search.path": searchPath
103221
+ }, (span, result) => {
103222
+ const text = typeof result === "string" ? result : "";
103223
+ span.setAttributes({
103224
+ "search.delegate.output": truncateForSpan(text),
103225
+ "search.delegate.output_length": text.length
103226
+ });
102633
103227
  }) : await runDelegation();
102634
103228
  const targets = parseDelegatedTargets(delegateResult);
102635
103229
  if (!targets.length) {
@@ -102649,7 +103243,7 @@ var init_vercel = __esm({
102649
103243
  const validatedTargets = [];
102650
103244
  for (const target of resolvedTargets) {
102651
103245
  const { filePart, suffix } = splitTargetSuffix(target);
102652
- if ((0, import_fs11.existsSync)(filePart)) {
103246
+ if ((0, import_fs12.existsSync)(filePart)) {
102653
103247
  validatedTargets.push(target);
102654
103248
  continue;
102655
103249
  }
@@ -102658,7 +103252,7 @@ var init_vercel = __esm({
102658
103252
  for (let i = 0; i < parts.length - 1; i++) {
102659
103253
  if (parts[i] === parts[i + 1]) {
102660
103254
  const candidate = "/" + [...parts.slice(0, i), ...parts.slice(i + 1)].join("/");
102661
- if ((0, import_fs11.existsSync)(candidate)) {
103255
+ if ((0, import_fs12.existsSync)(candidate)) {
102662
103256
  validatedTargets.push(candidate + suffix);
102663
103257
  if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} \u2192 ${candidate}`);
102664
103258
  fixed = true;
@@ -102671,7 +103265,7 @@ var init_vercel = __esm({
102671
103265
  if (altBase === delegateBase) continue;
102672
103266
  const altResolved = resolveTargetPath(target, altBase);
102673
103267
  const { filePart: altFile } = splitTargetSuffix(altResolved);
102674
- if ((0, import_fs11.existsSync)(altFile)) {
103268
+ if ((0, import_fs12.existsSync)(altFile)) {
102675
103269
  validatedTargets.push(altResolved);
102676
103270
  if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} \u2192 ${altFile}`);
102677
103271
  fixed = true;
@@ -102796,13 +103390,13 @@ var init_vercel = __esm({
102796
103390
  const { join: pathJoin, sep: pathSep } = await import("path");
102797
103391
  extractFiles = extractFiles.map((target) => {
102798
103392
  const { filePart, suffix } = splitTargetSuffix(target);
102799
- if ((0, import_fs11.existsSync)(filePart)) return target;
103393
+ if ((0, import_fs12.existsSync)(filePart)) return target;
102800
103394
  const cwdPrefix = effectiveCwd.endsWith(pathSep) ? effectiveCwd : effectiveCwd + pathSep;
102801
103395
  const relativePart = filePart.startsWith(cwdPrefix) ? filePart.slice(cwdPrefix.length) : null;
102802
103396
  if (relativePart) {
102803
103397
  for (const folder of options.allowedFolders) {
102804
103398
  const candidate = pathJoin(folder, relativePart);
102805
- if ((0, import_fs11.existsSync)(candidate)) {
103399
+ if ((0, import_fs12.existsSync)(candidate)) {
102806
103400
  if (debug) console.error(`[extract] Auto-fixed path: ${filePart} \u2192 ${candidate}`);
102807
103401
  return candidate + suffix;
102808
103402
  }
@@ -102815,7 +103409,7 @@ var init_vercel = __esm({
102815
103409
  if (filePart.startsWith(wsParent)) {
102816
103410
  const tail = filePart.slice(wsParent.length);
102817
103411
  const candidate = pathJoin(folderPrefix, tail);
102818
- if (candidate !== filePart && (0, import_fs11.existsSync)(candidate)) {
103412
+ if (candidate !== filePart && (0, import_fs12.existsSync)(candidate)) {
102819
103413
  if (debug) console.error(`[extract] Auto-fixed path via workspace: ${filePart} \u2192 ${candidate}`);
102820
103414
  return candidate + suffix;
102821
103415
  }
@@ -102874,6 +103468,7 @@ var init_vercel = __esm({
102874
103468
  workspaceRoot,
102875
103469
  enableBash = false,
102876
103470
  bashConfig,
103471
+ allowEdit = false,
102877
103472
  architectureFileName,
102878
103473
  enableMcp = false,
102879
103474
  mcpConfig = null,
@@ -102968,6 +103563,7 @@ var init_vercel = __esm({
102968
103563
  model,
102969
103564
  tracer,
102970
103565
  enableBash,
103566
+ allowEdit,
102971
103567
  bashConfig,
102972
103568
  architectureFileName,
102973
103569
  searchDelegate,
@@ -103309,12 +103905,12 @@ function isPathAllowed(filePath, allowedFolders) {
103309
103905
  if (!allowedFolders || allowedFolders.length === 0) {
103310
103906
  const resolvedPath2 = safeRealpath(filePath);
103311
103907
  const cwd = safeRealpath(process.cwd());
103312
- return resolvedPath2 === cwd || resolvedPath2.startsWith(cwd + import_path16.sep);
103908
+ return resolvedPath2 === cwd || resolvedPath2.startsWith(cwd + import_path17.sep);
103313
103909
  }
103314
103910
  const resolvedPath = safeRealpath(filePath);
103315
103911
  return allowedFolders.some((folder) => {
103316
103912
  const allowedPath = safeRealpath(folder);
103317
- return resolvedPath === allowedPath || resolvedPath.startsWith(allowedPath + import_path16.sep);
103913
+ return resolvedPath === allowedPath || resolvedPath.startsWith(allowedPath + import_path17.sep);
103318
103914
  });
103319
103915
  }
103320
103916
  function parseFileToolOptions(options = {}) {
@@ -103354,7 +103950,7 @@ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualif
103354
103950
  return `Error editing ${file_path}: Symbol "${symbol17}" has changed since you last read it. Use the extract tool with targets="${file_path}#${symbol17}" to re-read the current content, then retry.`;
103355
103951
  }
103356
103952
  }
103357
- const content = await import_fs12.promises.readFile(resolvedPath, "utf-8");
103953
+ const content = await import_fs13.promises.readFile(resolvedPath, "utf-8");
103358
103954
  const lines = content.split("\n");
103359
103955
  if (position) {
103360
103956
  const refIndent = detectBaseIndent(symbolInfo.code);
@@ -103365,7 +103961,7 @@ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualif
103365
103961
  } else {
103366
103962
  lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
103367
103963
  }
103368
- await import_fs12.promises.writeFile(resolvedPath, lines.join("\n"), "utf-8");
103964
+ await import_fs13.promises.writeFile(resolvedPath, lines.join("\n"), "utf-8");
103369
103965
  if (fileTracker) {
103370
103966
  const updated = await findSymbol(resolvedPath, symbol17, cwd || process.cwd());
103371
103967
  if (updated) {
@@ -103383,7 +103979,7 @@ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualif
103383
103979
  const reindented = reindent(new_string, originalIndent);
103384
103980
  const newLines = reindented.split("\n");
103385
103981
  lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
103386
- await import_fs12.promises.writeFile(resolvedPath, lines.join("\n"), "utf-8");
103982
+ await import_fs13.promises.writeFile(resolvedPath, lines.join("\n"), "utf-8");
103387
103983
  if (fileTracker) {
103388
103984
  const updated = await findSymbol(resolvedPath, symbol17, cwd || process.cwd());
103389
103985
  if (updated) {
@@ -103438,7 +104034,7 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
103438
104034
  if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
103439
104035
  return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
103440
104036
  }
103441
- const content = await import_fs12.promises.readFile(resolvedPath, "utf-8");
104037
+ const content = await import_fs13.promises.readFile(resolvedPath, "utf-8");
103442
104038
  const fileLines = content.split("\n");
103443
104039
  if (startLine > fileLines.length) {
103444
104040
  return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
@@ -103467,20 +104063,20 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
103467
104063
  const newLines = cleaned === "" ? [] : cleaned.split("\n");
103468
104064
  if (position === "after") {
103469
104065
  fileLines.splice(startLine, 0, ...newLines);
103470
- await import_fs12.promises.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
104066
+ await import_fs13.promises.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
103471
104067
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath);
103472
104068
  const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
103473
104069
  return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
103474
104070
  } else if (position === "before") {
103475
104071
  fileLines.splice(startLine - 1, 0, ...newLines);
103476
- await import_fs12.promises.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
104072
+ await import_fs13.promises.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
103477
104073
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath);
103478
104074
  const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
103479
104075
  return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
103480
104076
  } else {
103481
104077
  const replacedCount = endLine - startLine + 1;
103482
104078
  fileLines.splice(startLine - 1, replacedCount, ...newLines);
103483
- await import_fs12.promises.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
104079
+ await import_fs13.promises.writeFile(resolvedPath, fileLines.join("\n"), "utf-8");
103484
104080
  if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath);
103485
104081
  let action;
103486
104082
  if (newLines.length === 0) {
@@ -103493,14 +104089,14 @@ async function handleLineEdit({ resolvedPath, file_path, start_line, end_line, n
103493
104089
  return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
103494
104090
  }
103495
104091
  }
103496
- var import_ai6, import_fs12, import_path16, import_fs13, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
104092
+ var import_ai6, import_fs13, import_path17, import_fs14, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
103497
104093
  var init_edit = __esm({
103498
104094
  "src/tools/edit.js"() {
103499
104095
  "use strict";
103500
104096
  import_ai6 = require("ai");
103501
- import_fs12 = require("fs");
103502
- import_path16 = require("path");
103503
104097
  import_fs13 = require("fs");
104098
+ import_path17 = require("path");
104099
+ import_fs14 = require("fs");
103504
104100
  init_path_validation();
103505
104101
  init_fuzzyMatch();
103506
104102
  init_symbolEdit();
@@ -103576,7 +104172,7 @@ Parameters:
103576
104172
  return `Error editing file: Invalid new_string - must be a string. Provide the replacement content as a string value (empty string "" is valid for deletions).`;
103577
104173
  }
103578
104174
  const effectiveCwd = workingDirectory || cwd || process.cwd();
103579
- const resolvedPath = (0, import_path16.isAbsolute)(file_path) ? file_path : (0, import_path16.resolve)(effectiveCwd, file_path);
104175
+ const resolvedPath = (0, import_path17.isAbsolute)(file_path) ? file_path : (0, import_path17.resolve)(effectiveCwd, file_path);
103580
104176
  if (debug) {
103581
104177
  console.error(`[Edit] Attempting to edit file: ${resolvedPath}`);
103582
104178
  }
@@ -103584,7 +104180,7 @@ Parameters:
103584
104180
  const relativePath = toRelativePath(resolvedPath, workspaceRoot);
103585
104181
  return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
103586
104182
  }
103587
- if (!(0, import_fs13.existsSync)(resolvedPath)) {
104183
+ if (!(0, import_fs14.existsSync)(resolvedPath)) {
103588
104184
  return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
103589
104185
  }
103590
104186
  if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath)) {
@@ -103612,7 +104208,7 @@ Parameters:
103612
104208
  Use the extract tool with targets="${displayPath}" to re-read the file, then retry.`;
103613
104209
  }
103614
104210
  }
103615
- const content = await import_fs12.promises.readFile(resolvedPath, "utf-8");
104211
+ const content = await import_fs13.promises.readFile(resolvedPath, "utf-8");
103616
104212
  let matchTarget = old_string;
103617
104213
  let matchStrategy = "exact";
103618
104214
  if (!content.includes(old_string)) {
@@ -103644,7 +104240,7 @@ Use the extract tool with targets="${displayPath}" to re-read the file, then ret
103644
104240
  if (newContent === content) {
103645
104241
  return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
103646
104242
  }
103647
- await import_fs12.promises.writeFile(resolvedPath, newContent, "utf-8");
104243
+ await import_fs13.promises.writeFile(resolvedPath, newContent, "utf-8");
103648
104244
  if (options.fileTracker) {
103649
104245
  await options.fileTracker.trackFileAfterWrite(resolvedPath);
103650
104246
  options.fileTracker.recordTextEdit(resolvedPath);
@@ -103707,7 +104303,7 @@ Important:
103707
104303
  return `Error creating file: Invalid content - must be a string. Provide the file content as a string value (empty string "" is valid for an empty file).`;
103708
104304
  }
103709
104305
  const effectiveCwd = workingDirectory || cwd || process.cwd();
103710
- const resolvedPath = (0, import_path16.isAbsolute)(file_path) ? file_path : (0, import_path16.resolve)(effectiveCwd, file_path);
104306
+ const resolvedPath = (0, import_path17.isAbsolute)(file_path) ? file_path : (0, import_path17.resolve)(effectiveCwd, file_path);
103711
104307
  if (debug) {
103712
104308
  console.error(`[Create] Attempting to create file: ${resolvedPath}`);
103713
104309
  }
@@ -103715,13 +104311,13 @@ Important:
103715
104311
  const relativePath = toRelativePath(resolvedPath, workspaceRoot);
103716
104312
  return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
103717
104313
  }
103718
- if ((0, import_fs13.existsSync)(resolvedPath) && !overwrite) {
104314
+ if ((0, import_fs14.existsSync)(resolvedPath) && !overwrite) {
103719
104315
  return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
103720
104316
  }
103721
- const existed = (0, import_fs13.existsSync)(resolvedPath);
103722
- const dir = (0, import_path16.dirname)(resolvedPath);
103723
- await import_fs12.promises.mkdir(dir, { recursive: true });
103724
- await import_fs12.promises.writeFile(resolvedPath, content, "utf-8");
104317
+ const existed = (0, import_fs14.existsSync)(resolvedPath);
104318
+ const dir = (0, import_path17.dirname)(resolvedPath);
104319
+ await import_fs13.promises.mkdir(dir, { recursive: true });
104320
+ await import_fs13.promises.writeFile(resolvedPath, content, "utf-8");
103725
104321
  if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath);
103726
104322
  const action = existed && overwrite ? "overwrote" : "created";
103727
104323
  const bytes = Buffer.byteLength(content, "utf-8");
@@ -104362,10 +104958,10 @@ async function listFilesByLevel(options) {
104362
104958
  maxFiles = 100,
104363
104959
  respectGitignore = true
104364
104960
  } = options;
104365
- if (!import_fs14.default.existsSync(directory)) {
104961
+ if (!import_fs15.default.existsSync(directory)) {
104366
104962
  throw new Error(`Directory does not exist: ${directory}`);
104367
104963
  }
104368
- const gitDirExists = import_fs14.default.existsSync(import_path17.default.join(directory, ".git"));
104964
+ const gitDirExists = import_fs15.default.existsSync(import_path18.default.join(directory, ".git"));
104369
104965
  if (gitDirExists && respectGitignore) {
104370
104966
  try {
104371
104967
  return await listFilesUsingGit(directory, maxFiles);
@@ -104380,8 +104976,8 @@ async function listFilesUsingGit(directory, maxFiles) {
104380
104976
  const { stdout } = await execAsync3("git ls-files", { cwd: directory });
104381
104977
  const files = stdout.split("\n").filter(Boolean);
104382
104978
  const sortedFiles = files.sort((a, b) => {
104383
- const depthA = a.split(import_path17.default.sep).length;
104384
- const depthB = b.split(import_path17.default.sep).length;
104979
+ const depthA = a.split(import_path18.default.sep).length;
104980
+ const depthB = b.split(import_path18.default.sep).length;
104385
104981
  return depthA - depthB;
104386
104982
  });
104387
104983
  return sortedFiles.slice(0, maxFiles);
@@ -104396,25 +104992,25 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
104396
104992
  while (queue.length > 0 && result.length < maxFiles) {
104397
104993
  const { dir, level } = queue.shift();
104398
104994
  try {
104399
- const entries = import_fs14.default.readdirSync(dir, { withFileTypes: true });
104995
+ const entries = import_fs15.default.readdirSync(dir, { withFileTypes: true });
104400
104996
  const files = entries.filter((entry) => {
104401
- const fullPath = import_path17.default.join(dir, entry.name);
104997
+ const fullPath = import_path18.default.join(dir, entry.name);
104402
104998
  return getEntryTypeSync(entry, fullPath).isFile;
104403
104999
  });
104404
105000
  for (const file2 of files) {
104405
105001
  if (result.length >= maxFiles) break;
104406
- const filePath = import_path17.default.join(dir, file2.name);
104407
- const relativePath = import_path17.default.relative(directory, filePath);
105002
+ const filePath = import_path18.default.join(dir, file2.name);
105003
+ const relativePath = import_path18.default.relative(directory, filePath);
104408
105004
  if (shouldIgnore(relativePath, ignorePatterns)) continue;
104409
105005
  result.push(relativePath);
104410
105006
  }
104411
105007
  const dirs = entries.filter((entry) => {
104412
- const fullPath = import_path17.default.join(dir, entry.name);
105008
+ const fullPath = import_path18.default.join(dir, entry.name);
104413
105009
  return getEntryTypeSync(entry, fullPath).isDirectory;
104414
105010
  });
104415
105011
  for (const subdir of dirs) {
104416
- const subdirPath = import_path17.default.join(dir, subdir.name);
104417
- const relativeSubdirPath = import_path17.default.relative(directory, subdirPath);
105012
+ const subdirPath = import_path18.default.join(dir, subdir.name);
105013
+ const relativeSubdirPath = import_path18.default.relative(directory, subdirPath);
104418
105014
  if (shouldIgnore(relativeSubdirPath, ignorePatterns)) continue;
104419
105015
  if (subdir.name === "node_modules" || subdir.name === ".git") continue;
104420
105016
  queue.push({ dir: subdirPath, level: level + 1 });
@@ -104426,12 +105022,12 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
104426
105022
  return result;
104427
105023
  }
104428
105024
  function loadGitignorePatterns(directory) {
104429
- const gitignorePath = import_path17.default.join(directory, ".gitignore");
104430
- if (!import_fs14.default.existsSync(gitignorePath)) {
105025
+ const gitignorePath = import_path18.default.join(directory, ".gitignore");
105026
+ if (!import_fs15.default.existsSync(gitignorePath)) {
104431
105027
  return [];
104432
105028
  }
104433
105029
  try {
104434
- const content = import_fs14.default.readFileSync(gitignorePath, "utf8");
105030
+ const content = import_fs15.default.readFileSync(gitignorePath, "utf8");
104435
105031
  return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
104436
105032
  } catch (error40) {
104437
105033
  console.error(`Warning: Could not read .gitignore: ${error40.message}`);
@@ -104449,12 +105045,12 @@ function shouldIgnore(filePath, ignorePatterns) {
104449
105045
  }
104450
105046
  return false;
104451
105047
  }
104452
- var import_fs14, import_path17, import_util14, import_child_process10, execAsync3;
105048
+ var import_fs15, import_path18, import_util14, import_child_process10, execAsync3;
104453
105049
  var init_file_lister = __esm({
104454
105050
  "src/utils/file-lister.js"() {
104455
105051
  "use strict";
104456
- import_fs14 = __toESM(require("fs"), 1);
104457
- import_path17 = __toESM(require("path"), 1);
105052
+ import_fs15 = __toESM(require("fs"), 1);
105053
+ import_path18 = __toESM(require("path"), 1);
104458
105054
  import_util14 = require("util");
104459
105055
  import_child_process10 = require("child_process");
104460
105056
  init_symlink_utils();
@@ -104462,568 +105058,6 @@ var init_file_lister = __esm({
104462
105058
  }
104463
105059
  });
104464
105060
 
104465
- // src/agent/otelLogBridge.js
104466
- function getOtelApi() {
104467
- if (otelApiAttempted) return otelApi;
104468
- otelApiAttempted = true;
104469
- try {
104470
- otelApi = (function(name15) {
104471
- return _require(name15);
104472
- })("@opentelemetry/api");
104473
- } catch {
104474
- }
104475
- return otelApi;
104476
- }
104477
- function getOtelLogger() {
104478
- if (otelLoggerAttempted) return otelLogger;
104479
- otelLoggerAttempted = true;
104480
- try {
104481
- const { logs } = (function(name15) {
104482
- return _require(name15);
104483
- })("@opentelemetry/api-logs");
104484
- otelLogger = logs.getLogger("probe-agent");
104485
- } catch {
104486
- }
104487
- return otelLogger;
104488
- }
104489
- function getTraceSuffix() {
104490
- try {
104491
- const api2 = getOtelApi();
104492
- if (!api2) return "";
104493
- const span = api2.trace.getSpan(api2.context.active());
104494
- const ctx = span?.spanContext?.();
104495
- if (!ctx?.traceId) return "";
104496
- return ` [trace_id=${ctx.traceId} span_id=${ctx.spanId}]`;
104497
- } catch {
104498
- return "";
104499
- }
104500
- }
104501
- function emitOtelLog(msg, level) {
104502
- try {
104503
- const logger = getOtelLogger();
104504
- if (!logger) return;
104505
- const api2 = getOtelApi();
104506
- let traceId, spanId;
104507
- if (api2) {
104508
- const span = api2.trace.getSpan(api2.context.active());
104509
- const ctx = span?.spanContext?.();
104510
- if (ctx?.traceId) {
104511
- traceId = ctx.traceId;
104512
- spanId = ctx.spanId;
104513
- }
104514
- }
104515
- logger.emit({
104516
- severityNumber: OTEL_SEVERITY[level] || 9,
104517
- severityText: level.toUpperCase(),
104518
- body: msg,
104519
- attributes: {
104520
- "probe.logger": true,
104521
- ...traceId ? { trace_id: traceId, span_id: spanId } : {}
104522
- }
104523
- });
104524
- } catch {
104525
- }
104526
- }
104527
- function patchConsole() {
104528
- if (patched) return;
104529
- const methods = ["log", "info", "warn", "error"];
104530
- const c = globalThis.console;
104531
- for (const m of methods) {
104532
- const orig = c[m].bind(c);
104533
- originals[m] = orig;
104534
- c[m] = (...args) => {
104535
- const msgParts = args.map(
104536
- (a) => typeof a === "string" ? a : a instanceof Error ? a.message : JSON.stringify(a)
104537
- );
104538
- const msg = msgParts.join(" ");
104539
- emitOtelLog(msg, m === "log" ? "log" : m);
104540
- const suffix = getTraceSuffix();
104541
- if (suffix) {
104542
- if (typeof args[0] === "string") {
104543
- args[0] = args[0] + suffix;
104544
- } else {
104545
- args.push(suffix);
104546
- }
104547
- }
104548
- return orig(...args);
104549
- };
104550
- }
104551
- patched = true;
104552
- }
104553
- var import_module, _require, OTEL_SEVERITY, patched, originals, otelApi, otelApiAttempted, otelLogger, otelLoggerAttempted;
104554
- var init_otelLogBridge = __esm({
104555
- "src/agent/otelLogBridge.js"() {
104556
- "use strict";
104557
- import_module = require("module");
104558
- _require = (0, import_module.createRequire)("file:///");
104559
- OTEL_SEVERITY = {
104560
- log: 9,
104561
- // INFO
104562
- info: 9,
104563
- // INFO
104564
- warn: 13,
104565
- // WARN
104566
- error: 17,
104567
- // ERROR
104568
- debug: 5
104569
- // DEBUG
104570
- };
104571
- patched = false;
104572
- originals = {};
104573
- otelApi = null;
104574
- otelApiAttempted = false;
104575
- otelLogger = null;
104576
- otelLoggerAttempted = false;
104577
- }
104578
- });
104579
-
104580
- // src/agent/simpleTelemetry.js
104581
- function initializeSimpleTelemetryFromOptions(options) {
104582
- const telemetry = new SimpleTelemetry({
104583
- serviceName: "probe-agent",
104584
- enableFile: options.traceFile !== void 0,
104585
- enableConsole: options.traceConsole,
104586
- filePath: options.traceFile || "./traces.jsonl"
104587
- });
104588
- patchConsole();
104589
- return telemetry;
104590
- }
104591
- var import_fs15, import_path18, SimpleTelemetry, SimpleAppTracer;
104592
- var init_simpleTelemetry = __esm({
104593
- "src/agent/simpleTelemetry.js"() {
104594
- "use strict";
104595
- import_fs15 = require("fs");
104596
- import_path18 = require("path");
104597
- init_otelLogBridge();
104598
- SimpleTelemetry = class {
104599
- constructor(options = {}) {
104600
- this.serviceName = options.serviceName || "probe-agent";
104601
- this.enableFile = options.enableFile || false;
104602
- this.enableConsole = options.enableConsole || false;
104603
- this.filePath = options.filePath || "./traces.jsonl";
104604
- this.stream = null;
104605
- if (this.enableFile) {
104606
- this.initializeFileExporter();
104607
- }
104608
- }
104609
- initializeFileExporter() {
104610
- try {
104611
- const dir = (0, import_path18.dirname)(this.filePath);
104612
- if (!(0, import_fs15.existsSync)(dir)) {
104613
- (0, import_fs15.mkdirSync)(dir, { recursive: true });
104614
- }
104615
- this.stream = (0, import_fs15.createWriteStream)(this.filePath, { flags: "a" });
104616
- this.stream.on("error", (error40) => {
104617
- console.error(`[SimpleTelemetry] Stream error: ${error40.message}`);
104618
- });
104619
- console.log(`[SimpleTelemetry] File exporter initialized: ${this.filePath}`);
104620
- } catch (error40) {
104621
- console.error(`[SimpleTelemetry] Failed to initialize file exporter: ${error40.message}`);
104622
- }
104623
- }
104624
- createSpan(name15, attributes = {}) {
104625
- const span = {
104626
- traceId: this.generateTraceId(),
104627
- spanId: this.generateSpanId(),
104628
- name: name15,
104629
- startTime: Date.now(),
104630
- attributes: { ...attributes, service: this.serviceName },
104631
- events: [],
104632
- status: "OK"
104633
- };
104634
- return {
104635
- ...span,
104636
- addEvent: (eventName, eventAttributes = {}) => {
104637
- span.events.push({
104638
- name: eventName,
104639
- time: Date.now(),
104640
- attributes: eventAttributes
104641
- });
104642
- },
104643
- setAttributes: (attrs) => {
104644
- Object.assign(span.attributes, attrs);
104645
- },
104646
- setStatus: (status) => {
104647
- span.status = status;
104648
- },
104649
- end: () => {
104650
- span.endTime = Date.now();
104651
- span.duration = span.endTime - span.startTime;
104652
- this.exportSpan(span);
104653
- }
104654
- };
104655
- }
104656
- exportSpan(span) {
104657
- const spanData = {
104658
- ...span,
104659
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
104660
- };
104661
- if (this.enableConsole) {
104662
- console.log("[Trace]", JSON.stringify(spanData, null, 2));
104663
- }
104664
- if (this.enableFile && this.stream) {
104665
- this.stream.write(JSON.stringify(spanData) + "\n");
104666
- }
104667
- }
104668
- generateTraceId() {
104669
- return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
104670
- }
104671
- generateSpanId() {
104672
- return Math.random().toString(36).substring(2, 10);
104673
- }
104674
- async flush() {
104675
- if (this.stream) {
104676
- return new Promise((resolve9) => {
104677
- this.stream.once("drain", resolve9);
104678
- if (!this.stream.writableNeedDrain) {
104679
- resolve9();
104680
- }
104681
- });
104682
- }
104683
- }
104684
- async shutdown() {
104685
- if (this.stream) {
104686
- return new Promise((resolve9) => {
104687
- this.stream.end(() => {
104688
- console.log(`[SimpleTelemetry] File stream closed: ${this.filePath}`);
104689
- resolve9();
104690
- });
104691
- });
104692
- }
104693
- }
104694
- };
104695
- SimpleAppTracer = class {
104696
- constructor(telemetry, sessionId = null) {
104697
- this.telemetry = telemetry;
104698
- this.sessionId = sessionId || this.generateSessionId();
104699
- }
104700
- generateSessionId() {
104701
- return Math.random().toString(36).substring(2, 15);
104702
- }
104703
- isEnabled() {
104704
- return this.telemetry !== null;
104705
- }
104706
- createSessionSpan(attributes = {}) {
104707
- if (!this.isEnabled()) return null;
104708
- return this.telemetry.createSpan("agent.session", {
104709
- "session.id": this.sessionId,
104710
- ...attributes
104711
- });
104712
- }
104713
- createAISpan(modelName, provider, attributes = {}) {
104714
- if (!this.isEnabled()) return null;
104715
- return this.telemetry.createSpan("ai.request", {
104716
- "ai.model": modelName,
104717
- "ai.provider": provider,
104718
- "session.id": this.sessionId,
104719
- ...attributes
104720
- });
104721
- }
104722
- createToolSpan(toolName, attributes = {}) {
104723
- if (!this.isEnabled()) return null;
104724
- return this.telemetry.createSpan("tool.call", {
104725
- "tool.name": toolName,
104726
- "session.id": this.sessionId,
104727
- ...attributes
104728
- });
104729
- }
104730
- addEvent(name15, attributes = {}) {
104731
- if (this.telemetry && this.telemetry.enableConsole) {
104732
- console.log("[Event]", name15, attributes);
104733
- }
104734
- }
104735
- /**
104736
- * Record a generic event (used by completionPrompt and other features)
104737
- */
104738
- // visor-disable: SimpleAppTracer uses this.sessionId because it's a per-session instance. AppTracer extracts from attributes because it's a singleton managing multiple sessions. Different architectures require different approaches.
104739
- recordEvent(name15, attributes = {}) {
104740
- if (!this.isEnabled()) return;
104741
- this.addEvent(name15, {
104742
- "session.id": this.sessionId,
104743
- ...attributes
104744
- });
104745
- }
104746
- /**
104747
- * Record delegation events
104748
- */
104749
- recordDelegationEvent(eventType, data2 = {}) {
104750
- if (!this.isEnabled()) return;
104751
- this.addEvent(`delegation.${eventType}`, {
104752
- "session.id": this.sessionId,
104753
- ...data2
104754
- });
104755
- }
104756
- /**
104757
- * Record JSON validation events
104758
- */
104759
- recordJsonValidationEvent(eventType, data2 = {}) {
104760
- if (!this.isEnabled()) return;
104761
- this.addEvent(`json_validation.${eventType}`, {
104762
- "session.id": this.sessionId,
104763
- ...data2
104764
- });
104765
- }
104766
- /**
104767
- * Record Mermaid validation events
104768
- */
104769
- recordMermaidValidationEvent(eventType, data2 = {}) {
104770
- if (!this.isEnabled()) return;
104771
- this.addEvent(`mermaid_validation.${eventType}`, {
104772
- "session.id": this.sessionId,
104773
- ...data2
104774
- });
104775
- }
104776
- /**
104777
- * Record task management events
104778
- */
104779
- recordTaskEvent(eventType, data2 = {}) {
104780
- if (!this.isEnabled()) return;
104781
- this.addEvent(`task.${eventType}`, {
104782
- "session.id": this.sessionId,
104783
- ...data2
104784
- });
104785
- }
104786
- /**
104787
- * Record MCP (Model Context Protocol) events
104788
- * Tracks server connections, tool discovery, method filtering, and tool execution
104789
- */
104790
- recordMcpEvent(eventType, data2 = {}) {
104791
- if (!this.isEnabled()) return;
104792
- this.addEvent(`mcp.${eventType}`, {
104793
- "session.id": this.sessionId,
104794
- ...data2
104795
- });
104796
- }
104797
- /**
104798
- * Record bash tool events
104799
- * Tracks command permission checks, allowed/denied commands, and execution
104800
- */
104801
- recordBashEvent(eventType, data2 = {}) {
104802
- if (!this.isEnabled()) return;
104803
- this.addEvent(`bash.${eventType}`, {
104804
- "session.id": this.sessionId,
104805
- ...data2
104806
- });
104807
- }
104808
- setAttributes(attributes) {
104809
- if (this.telemetry && this.telemetry.enableConsole) {
104810
- console.log("[Attributes]", attributes);
104811
- }
104812
- }
104813
- /**
104814
- * Hash content for deduplication/comparison purposes
104815
- * @param {string} content - The content to hash
104816
- * @returns {string} - Hex string hash
104817
- */
104818
- hashContent(content) {
104819
- let hash2 = 0;
104820
- const len = Math.min(content.length, 1e3);
104821
- for (let i = 0; i < len; i++) {
104822
- hash2 = (hash2 << 5) - hash2 + content.charCodeAt(i);
104823
- hash2 |= 0;
104824
- }
104825
- return hash2.toString(16);
104826
- }
104827
- /**
104828
- * Record a conversation turn (assistant response or tool result)
104829
- * @param {string} role - The role (assistant, tool_result)
104830
- * @param {string} content - The turn content
104831
- * @param {Object} metadata - Additional metadata
104832
- */
104833
- recordConversationTurn(role, content, metadata = {}) {
104834
- if (!this.isEnabled()) return;
104835
- this.addEvent(`conversation.turn.${role}`, {
104836
- "session.id": this.sessionId,
104837
- "conversation.role": role,
104838
- "conversation.content": content.substring(0, 1e4),
104839
- "conversation.content.length": content.length,
104840
- "conversation.content.hash": this.hashContent(content),
104841
- ...metadata
104842
- });
104843
- }
104844
- /**
104845
- * Record error events with classification
104846
- * @param {string} errorType - The type of error (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker, etc.)
104847
- * @param {Object} errorDetails - Error details including message, stack, context
104848
- */
104849
- recordErrorEvent(errorType, errorDetails = {}) {
104850
- if (!this.isEnabled()) return;
104851
- this.addEvent(`error.${errorType}`, {
104852
- "session.id": this.sessionId,
104853
- "error.type": errorType,
104854
- "error.message": errorDetails.message?.substring(0, 1e3) || null,
104855
- "error.stack": errorDetails.stack?.substring(0, 2e3) || null,
104856
- "error.recoverable": errorDetails.recoverable ?? true,
104857
- "error.context": JSON.stringify(errorDetails.context || {}).substring(0, 1e3),
104858
- ...Object.fromEntries(
104859
- Object.entries(errorDetails).filter(([k]) => !["message", "stack", "context", "recoverable"].includes(k)).map(([k, v]) => [`error.${k}`, v])
104860
- )
104861
- });
104862
- }
104863
- /**
104864
- * Record AI thinking/reasoning content
104865
- * @param {string} thinkingContent - The thinking content from AI response
104866
- * @param {Object} metadata - Additional metadata
104867
- */
104868
- recordThinkingContent(thinkingContent, metadata = {}) {
104869
- if (!this.isEnabled() || !thinkingContent) return;
104870
- this.addEvent("ai.thinking", {
104871
- "session.id": this.sessionId,
104872
- "ai.thinking.content": thinkingContent.substring(0, 5e4),
104873
- "ai.thinking.length": thinkingContent.length,
104874
- "ai.thinking.hash": this.hashContent(thinkingContent),
104875
- ...metadata
104876
- });
104877
- }
104878
- /**
104879
- * Record AI tool call decision
104880
- * @param {string} toolName - The tool name AI decided to call
104881
- * @param {Object} params - The parameters AI provided
104882
- * @param {Object} metadata - Additional metadata
104883
- */
104884
- recordToolDecision(toolName, params, metadata = {}) {
104885
- if (!this.isEnabled()) return;
104886
- this.addEvent("ai.tool_decision", {
104887
- "session.id": this.sessionId,
104888
- "ai.tool_decision.name": toolName,
104889
- "ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
104890
- ...metadata
104891
- });
104892
- }
104893
- /**
104894
- * Record tool result after execution
104895
- * @param {string} toolName - The tool that was executed
104896
- * @param {string|Object} result - The tool result
104897
- * @param {boolean} success - Whether the tool succeeded
104898
- * @param {number} durationMs - Execution duration in milliseconds
104899
- * @param {Object} metadata - Additional metadata
104900
- */
104901
- recordToolResult(toolName, result, success2, durationMs, metadata = {}) {
104902
- if (!this.isEnabled()) return;
104903
- const resultStr = typeof result === "string" ? result : JSON.stringify(result);
104904
- this.addEvent("tool.result", {
104905
- "session.id": this.sessionId,
104906
- "tool.name": toolName,
104907
- "tool.result": resultStr.substring(0, 1e4),
104908
- "tool.result.length": resultStr.length,
104909
- "tool.result.hash": this.hashContent(resultStr),
104910
- "tool.duration_ms": durationMs,
104911
- "tool.success": success2,
104912
- ...metadata
104913
- });
104914
- }
104915
- /**
104916
- * Record MCP tool execution start
104917
- * @param {string} toolName - MCP tool name
104918
- * @param {string} serverName - MCP server name
104919
- * @param {Object} params - Tool parameters
104920
- * @param {Object} metadata - Additional metadata
104921
- */
104922
- recordMcpToolStart(toolName, serverName, params, metadata = {}) {
104923
- if (!this.isEnabled()) return;
104924
- this.addEvent("mcp.tool.start", {
104925
- "session.id": this.sessionId,
104926
- "mcp.tool.name": toolName,
104927
- "mcp.tool.server": serverName || "unknown",
104928
- "mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
104929
- ...metadata
104930
- });
104931
- }
104932
- /**
104933
- * Record MCP tool execution end
104934
- * @param {string} toolName - MCP tool name
104935
- * @param {string} serverName - MCP server name
104936
- * @param {string|Object} result - Tool result
104937
- * @param {boolean} success - Whether succeeded
104938
- * @param {number} durationMs - Execution duration
104939
- * @param {string} errorMessage - Error message if failed
104940
- * @param {Object} metadata - Additional metadata
104941
- */
104942
- recordMcpToolEnd(toolName, serverName, result, success2, durationMs, errorMessage = null, metadata = {}) {
104943
- if (!this.isEnabled()) return;
104944
- const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
104945
- this.addEvent("mcp.tool.end", {
104946
- "session.id": this.sessionId,
104947
- "mcp.tool.name": toolName,
104948
- "mcp.tool.server": serverName || "unknown",
104949
- "mcp.tool.result": resultStr.substring(0, 1e4),
104950
- "mcp.tool.result.length": resultStr.length,
104951
- "mcp.tool.duration_ms": durationMs,
104952
- "mcp.tool.success": success2,
104953
- "mcp.tool.error": errorMessage,
104954
- ...metadata
104955
- });
104956
- }
104957
- /**
104958
- * Record iteration lifecycle event
104959
- * @param {string} eventType - start or end
104960
- * @param {number} iteration - Iteration number
104961
- * @param {Object} data - Additional data
104962
- */
104963
- recordIterationEvent(eventType, iteration, data2 = {}) {
104964
- if (!this.isEnabled()) return;
104965
- this.addEvent(`iteration.${eventType}`, {
104966
- "session.id": this.sessionId,
104967
- "iteration": iteration,
104968
- ...data2
104969
- });
104970
- }
104971
- /**
104972
- * Record per-turn token breakdown
104973
- * @param {number} iteration - Iteration number
104974
- * @param {Object} tokenData - Token metrics
104975
- */
104976
- recordTokenTurn(iteration, tokenData = {}) {
104977
- if (!this.isEnabled()) return;
104978
- this.addEvent("tokens.turn", {
104979
- "session.id": this.sessionId,
104980
- "iteration": iteration,
104981
- "tokens.input": tokenData.inputTokens || 0,
104982
- "tokens.output": tokenData.outputTokens || 0,
104983
- "tokens.total": (tokenData.inputTokens || 0) + (tokenData.outputTokens || 0),
104984
- "tokens.cache_read": tokenData.cacheReadTokens || 0,
104985
- "tokens.cache_write": tokenData.cacheWriteTokens || 0,
104986
- "tokens.context_used": tokenData.contextTokens || 0,
104987
- "tokens.context_remaining": tokenData.maxContextTokens ? tokenData.maxContextTokens - (tokenData.contextTokens || 0) : null
104988
- });
104989
- }
104990
- async withSpan(spanName, fn, attributes = {}) {
104991
- if (!this.isEnabled()) {
104992
- return fn();
104993
- }
104994
- const span = this.telemetry.createSpan(spanName, {
104995
- "session.id": this.sessionId,
104996
- ...attributes
104997
- });
104998
- try {
104999
- const result = await fn();
105000
- span.setStatus("OK");
105001
- return result;
105002
- } catch (error40) {
105003
- span.setStatus("ERROR");
105004
- span.addEvent("exception", {
105005
- "exception.message": error40.message,
105006
- "exception.stack": error40.stack
105007
- });
105008
- throw error40;
105009
- } finally {
105010
- span.end();
105011
- }
105012
- }
105013
- async flush() {
105014
- if (this.telemetry) {
105015
- await this.telemetry.flush();
105016
- }
105017
- }
105018
- async shutdown() {
105019
- if (this.telemetry) {
105020
- await this.telemetry.shutdown();
105021
- }
105022
- }
105023
- };
105024
- }
105025
- });
105026
-
105027
105061
  // src/agent/storage/index.js
105028
105062
  var init_storage = __esm({
105029
105063
  "src/agent/storage/index.js"() {