@probelabs/probe 0.6.0-rc154 → 0.6.0-rc159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/bin/binaries/probe-v0.6.0-rc159-aarch64-apple-darwin.tar.gz +0 -0
  2. package/bin/binaries/probe-v0.6.0-rc159-aarch64-unknown-linux-musl.tar.gz +0 -0
  3. package/bin/binaries/probe-v0.6.0-rc159-x86_64-apple-darwin.tar.gz +0 -0
  4. package/bin/binaries/probe-v0.6.0-rc159-x86_64-pc-windows-msvc.zip +0 -0
  5. package/bin/binaries/probe-v0.6.0-rc159-x86_64-unknown-linux-musl.tar.gz +0 -0
  6. package/build/agent/ProbeAgent.d.ts +2 -0
  7. package/build/agent/ProbeAgent.js +20 -4
  8. package/build/agent/acp/server.js +1 -0
  9. package/build/agent/index.js +464 -216
  10. package/build/delegate.js +326 -201
  11. package/build/downloader.js +46 -17
  12. package/build/extractor.js +12 -12
  13. package/build/tools/vercel.js +55 -14
  14. package/build/utils.js +18 -9
  15. package/cjs/agent/ProbeAgent.cjs +478 -234
  16. package/cjs/index.cjs +41496 -41272
  17. package/package.json +2 -2
  18. package/src/agent/ProbeAgent.d.ts +2 -0
  19. package/src/agent/ProbeAgent.js +20 -4
  20. package/src/agent/acp/server.js +1 -0
  21. package/src/agent/index.js +8 -0
  22. package/src/delegate.js +326 -201
  23. package/src/downloader.js +46 -17
  24. package/src/extractor.js +12 -12
  25. package/src/tools/vercel.js +55 -14
  26. package/src/utils.js +18 -9
  27. package/bin/binaries/probe-v0.6.0-rc154-aarch64-apple-darwin.tar.gz +0 -0
  28. package/bin/binaries/probe-v0.6.0-rc154-aarch64-unknown-linux-gnu.tar.gz +0 -0
  29. package/bin/binaries/probe-v0.6.0-rc154-x86_64-apple-darwin.tar.gz +0 -0
  30. package/bin/binaries/probe-v0.6.0-rc154-x86_64-pc-windows-msvc.zip +0 -0
  31. package/bin/binaries/probe-v0.6.0-rc154-x86_64-unknown-linux-gnu.tar.gz +0 -0
@@ -1893,6 +1893,28 @@ import { exec as execCallback } from "child_process";
1893
1893
  import tar from "tar";
1894
1894
  import os2 from "os";
1895
1895
  import { fileURLToPath as fileURLToPath2 } from "url";
1896
+ function sanitizeError(err) {
1897
+ try {
1898
+ const status = err?.response?.status;
1899
+ const statusText = err?.response?.statusText;
1900
+ const url = err?.config?.url || err?.response?.config?.url;
1901
+ const code = err?.code;
1902
+ const serverMsg = typeof err?.response?.data === "string" ? err.response.data.slice(0, 500) : typeof err?.response?.data?.message === "string" ? err.response.data.message : void 0;
1903
+ const base = err?.message || String(err);
1904
+ const parts = [base];
1905
+ if (status || statusText) parts.push(`[${status ?? ""} ${statusText ?? ""}]`.trim());
1906
+ if (code) parts.push(`code=${code}`);
1907
+ if (url) parts.push(`url=${url}`);
1908
+ if (serverMsg) parts.push(`server="${String(serverMsg).replace(/\s+/g, " ").trim()}"`);
1909
+ const e = new Error(parts.filter(Boolean).join(" "));
1910
+ if (status) e.status = status;
1911
+ if (code) e.code = code;
1912
+ if (url) e.url = url;
1913
+ return e;
1914
+ } catch (_) {
1915
+ return new Error(err?.message || String(err));
1916
+ }
1917
+ }
1896
1918
  async function acquireFileLock(lockPath, version) {
1897
1919
  const lockData = {
1898
1920
  version,
@@ -2041,7 +2063,7 @@ function detectOsArch() {
2041
2063
  case "linux":
2042
2064
  osInfo = {
2043
2065
  type: "linux",
2044
- keywords: ["linux", "Linux", "gnu"]
2066
+ keywords: ["linux", "Linux", "musl", "gnu"]
2045
2067
  };
2046
2068
  break;
2047
2069
  case "darwin":
@@ -2085,7 +2107,7 @@ function constructAssetInfo(version, osInfo, archInfo) {
2085
2107
  let extension;
2086
2108
  switch (osInfo.type) {
2087
2109
  case "linux":
2088
- platform = `${archInfo.type}-unknown-linux-gnu`;
2110
+ platform = `${archInfo.type}-unknown-linux-musl`;
2089
2111
  extension = "tar.gz";
2090
2112
  break;
2091
2113
  case "darwin":
@@ -2202,7 +2224,7 @@ async function getLatestRelease(version) {
2202
2224
  }
2203
2225
  return { tag, assets };
2204
2226
  }
2205
- throw error;
2227
+ throw sanitizeError(error);
2206
2228
  }
2207
2229
  }
2208
2230
  function findBestAsset(assets, osInfo, archInfo) {
@@ -2416,7 +2438,7 @@ async function extractBinary(assetPath, outputDir) {
2416
2438
  return binaryPath;
2417
2439
  } catch (error) {
2418
2440
  console.error(`Error extracting binary: ${error instanceof Error ? error.message : String(error)}`);
2419
- throw error;
2441
+ throw sanitizeError(error);
2420
2442
  }
2421
2443
  }
2422
2444
  async function getVersionInfo(binDir) {
@@ -2581,8 +2603,8 @@ async function downloadProbeBinary(version) {
2581
2603
  }
2582
2604
  return await withDownloadLock(version, () => doDownload(version));
2583
2605
  } catch (error) {
2584
- console.error("Error downloading probe binary:", error);
2585
- throw error;
2606
+ console.error("Error downloading probe binary:", error?.message || String(error));
2607
+ throw sanitizeError(error);
2586
2608
  }
2587
2609
  }
2588
2610
  var exec, REPO_OWNER, REPO_NAME, BINARY_NAME, __filename2, __dirname2, downloadLocks, LOCK_TIMEOUT_MS, LOCK_POLL_INTERVAL_MS, MAX_LOCK_WAIT_MS;
@@ -2619,9 +2641,15 @@ async function getBinaryPath(options = {}) {
2619
2641
  probeBinaryPath = await downloadProbeBinary(version);
2620
2642
  return probeBinaryPath;
2621
2643
  }
2622
- const binDir = await getPackageBinDir();
2623
2644
  const isWindows = process.platform === "win32";
2624
2645
  const binaryName = isWindows ? "probe.exe" : "probe-binary";
2646
+ const localPackageBin = path3.resolve(__dirname3, "..", "bin");
2647
+ const localBinaryPath = path3.join(localPackageBin, binaryName);
2648
+ if (fs3.existsSync(localBinaryPath) && !forceDownload) {
2649
+ probeBinaryPath = localBinaryPath;
2650
+ return probeBinaryPath;
2651
+ }
2652
+ const binDir = await getPackageBinDir();
2625
2653
  const binaryPath = path3.join(binDir, binaryName);
2626
2654
  if (fs3.existsSync(binaryPath) && !forceDownload) {
2627
2655
  probeBinaryPath = binaryPath;
@@ -3063,6 +3091,262 @@ var init_grep = __esm({
3063
3091
  }
3064
3092
  });
3065
3093
 
3094
+ // src/delegate.js
3095
+ import { randomUUID } from "crypto";
3096
+ async function delegate({
3097
+ task,
3098
+ timeout = 300,
3099
+ debug = false,
3100
+ currentIteration = 0,
3101
+ maxIterations = 30,
3102
+ tracer = null,
3103
+ parentSessionId = null,
3104
+ path: path7 = null,
3105
+ provider = null,
3106
+ model = null
3107
+ }) {
3108
+ if (!task || typeof task !== "string") {
3109
+ throw new Error("Task parameter is required and must be a string");
3110
+ }
3111
+ const sessionId = randomUUID();
3112
+ const startTime = Date.now();
3113
+ const remainingIterations = Math.max(1, maxIterations - currentIteration);
3114
+ const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
3115
+ let timeoutId = null;
3116
+ let acquired = false;
3117
+ try {
3118
+ delegationManager.tryAcquire(parentSessionId);
3119
+ acquired = true;
3120
+ if (debug) {
3121
+ const stats = delegationManager.getStats();
3122
+ console.error(`[DELEGATE] Starting delegation session ${sessionId}`);
3123
+ console.error(`[DELEGATE] Parent session: ${parentSessionId || "none"}`);
3124
+ console.error(`[DELEGATE] Task: ${task}`);
3125
+ console.error(`[DELEGATE] Current iteration: ${currentIteration}/${maxIterations}`);
3126
+ console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
3127
+ console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
3128
+ console.error(`[DELEGATE] Global active delegations: ${stats.globalActive}/${stats.maxConcurrent}`);
3129
+ console.error(`[DELEGATE] Using ProbeAgent SDK with code-researcher prompt`);
3130
+ }
3131
+ const subagent = new ProbeAgent({
3132
+ sessionId,
3133
+ promptType: "code-researcher",
3134
+ // Clean prompt, not inherited from parent
3135
+ enableDelegate: false,
3136
+ // Explicitly disable delegation to prevent recursion
3137
+ disableMermaidValidation: true,
3138
+ // Faster processing
3139
+ disableJsonValidation: true,
3140
+ // Simpler responses
3141
+ maxIterations: remainingIterations,
3142
+ debug,
3143
+ tracer,
3144
+ path: path7,
3145
+ // Inherit from parent
3146
+ provider,
3147
+ // Inherit from parent
3148
+ model
3149
+ // Inherit from parent
3150
+ });
3151
+ if (debug) {
3152
+ console.error(`[DELEGATE] Created subagent with session ${sessionId}`);
3153
+ console.error(`[DELEGATE] Subagent config: promptType=code-researcher, enableDelegate=false, maxIterations=${remainingIterations}`);
3154
+ }
3155
+ const timeoutPromise = new Promise((_, reject2) => {
3156
+ timeoutId = setTimeout(() => {
3157
+ reject2(new Error(`Delegation timed out after ${timeout} seconds`));
3158
+ }, timeout * 1e3);
3159
+ });
3160
+ const answerPromise = subagent.answer(task);
3161
+ const response = await Promise.race([answerPromise, timeoutPromise]);
3162
+ if (timeoutId !== null) {
3163
+ clearTimeout(timeoutId);
3164
+ timeoutId = null;
3165
+ }
3166
+ const duration = Date.now() - startTime;
3167
+ if (typeof response !== "string") {
3168
+ throw new Error("Delegate agent returned invalid response (not a string)");
3169
+ }
3170
+ const trimmedResponse = response.trim();
3171
+ if (trimmedResponse.length === 0) {
3172
+ throw new Error("Delegate agent returned empty or whitespace-only response");
3173
+ }
3174
+ if (trimmedResponse.includes("\0")) {
3175
+ throw new Error("Delegate agent returned response containing null bytes");
3176
+ }
3177
+ if (debug) {
3178
+ console.error(`[DELEGATE] Task completed successfully for session ${sessionId}`);
3179
+ console.error(`[DELEGATE] Duration: ${(duration / 1e3).toFixed(2)}s`);
3180
+ console.error(`[DELEGATE] Response length: ${response.length} chars`);
3181
+ }
3182
+ if (tracer) {
3183
+ tracer.recordDelegationEvent("completed", {
3184
+ "delegation.session_id": sessionId,
3185
+ "delegation.parent_session_id": parentSessionId,
3186
+ "delegation.duration_ms": duration,
3187
+ "delegation.response_length": response.length,
3188
+ "delegation.success": true
3189
+ });
3190
+ if (delegationSpan) {
3191
+ delegationSpan.setAttributes({
3192
+ "delegation.result.success": true,
3193
+ "delegation.result.response_length": response.length,
3194
+ "delegation.result.duration_ms": duration
3195
+ });
3196
+ delegationSpan.setStatus({ code: 1 });
3197
+ delegationSpan.end();
3198
+ }
3199
+ }
3200
+ if (acquired) {
3201
+ delegationManager.release(parentSessionId, debug);
3202
+ }
3203
+ return response;
3204
+ } catch (error) {
3205
+ if (timeoutId !== null) {
3206
+ clearTimeout(timeoutId);
3207
+ timeoutId = null;
3208
+ }
3209
+ const duration = Date.now() - startTime;
3210
+ if (acquired) {
3211
+ delegationManager.release(parentSessionId, debug);
3212
+ }
3213
+ if (debug) {
3214
+ console.error(`[DELEGATE] Task failed for session ${sessionId} after ${duration}ms`);
3215
+ console.error(`[DELEGATE] Error: ${error.message}`);
3216
+ console.error(`[DELEGATE] Stack: ${error.stack}`);
3217
+ }
3218
+ if (tracer) {
3219
+ tracer.recordDelegationEvent("failed", {
3220
+ "delegation.session_id": sessionId,
3221
+ "delegation.parent_session_id": parentSessionId,
3222
+ "delegation.duration_ms": duration,
3223
+ "delegation.error_message": error.message,
3224
+ "delegation.success": false
3225
+ });
3226
+ if (delegationSpan) {
3227
+ delegationSpan.setAttributes({
3228
+ "delegation.result.success": false,
3229
+ "delegation.result.error": error.message,
3230
+ "delegation.result.duration_ms": duration
3231
+ });
3232
+ delegationSpan.setStatus({ code: 2, message: error.message });
3233
+ delegationSpan.end();
3234
+ }
3235
+ }
3236
+ throw new Error(`Delegation failed: ${error.message}`);
3237
+ }
3238
+ }
3239
+ var DelegationManager, delegationManager;
3240
+ var init_delegate = __esm({
3241
+ "src/delegate.js"() {
3242
+ "use strict";
3243
+ init_ProbeAgent();
3244
+ DelegationManager = class {
3245
+ constructor() {
3246
+ this.maxConcurrent = parseInt(process.env.MAX_CONCURRENT_DELEGATIONS || "3", 10);
3247
+ this.maxPerSession = parseInt(process.env.MAX_DELEGATIONS_PER_SESSION || "10", 10);
3248
+ this.sessionDelegations = /* @__PURE__ */ new Map();
3249
+ this.globalActive = 0;
3250
+ this.cleanupInterval = setInterval(() => {
3251
+ try {
3252
+ this.cleanupStaleSessions();
3253
+ } catch (error) {
3254
+ console.error("[DelegationManager] Error during cleanup:", error);
3255
+ }
3256
+ }, 5 * 60 * 1e3);
3257
+ if (this.cleanupInterval.unref) {
3258
+ this.cleanupInterval.unref();
3259
+ }
3260
+ }
3261
+ /**
3262
+ * Check limits and increment counters (synchronous, atomic in Node.js event loop)
3263
+ * @param {string|null|undefined} parentSessionId - Parent session ID for tracking
3264
+ */
3265
+ tryAcquire(parentSessionId) {
3266
+ if (parentSessionId !== null && parentSessionId !== void 0 && typeof parentSessionId !== "string") {
3267
+ throw new TypeError("parentSessionId must be a string, null, or undefined");
3268
+ }
3269
+ if (this.globalActive >= this.maxConcurrent) {
3270
+ throw new Error(`Maximum concurrent delegations (${this.maxConcurrent}) reached. Please wait for some delegations to complete.`);
3271
+ }
3272
+ if (parentSessionId) {
3273
+ const sessionData = this.sessionDelegations.get(parentSessionId);
3274
+ const sessionCount = sessionData?.count || 0;
3275
+ if (sessionCount >= this.maxPerSession) {
3276
+ throw new Error(`Maximum delegations per session (${this.maxPerSession}) reached for session ${parentSessionId}`);
3277
+ }
3278
+ }
3279
+ this.globalActive++;
3280
+ if (parentSessionId) {
3281
+ const sessionData = this.sessionDelegations.get(parentSessionId);
3282
+ if (sessionData) {
3283
+ sessionData.count++;
3284
+ sessionData.lastUpdated = Date.now();
3285
+ } else {
3286
+ this.sessionDelegations.set(parentSessionId, {
3287
+ count: 1,
3288
+ lastUpdated: Date.now()
3289
+ });
3290
+ }
3291
+ }
3292
+ return true;
3293
+ }
3294
+ /**
3295
+ * Decrement counters (synchronous, atomic in Node.js event loop)
3296
+ */
3297
+ release(parentSessionId, debug = false) {
3298
+ this.globalActive = Math.max(0, this.globalActive - 1);
3299
+ if (parentSessionId) {
3300
+ const sessionData = this.sessionDelegations.get(parentSessionId);
3301
+ if (sessionData) {
3302
+ sessionData.count = Math.max(0, sessionData.count - 1);
3303
+ if (sessionData.count === 0) {
3304
+ this.sessionDelegations.delete(parentSessionId);
3305
+ }
3306
+ }
3307
+ }
3308
+ if (debug) {
3309
+ console.error(`[DELEGATE] Released. Global active: ${this.globalActive}`);
3310
+ }
3311
+ }
3312
+ /**
3313
+ * Get current stats for monitoring
3314
+ */
3315
+ getStats() {
3316
+ return {
3317
+ globalActive: this.globalActive,
3318
+ maxConcurrent: this.maxConcurrent,
3319
+ maxPerSession: this.maxPerSession,
3320
+ sessionCount: this.sessionDelegations.size
3321
+ };
3322
+ }
3323
+ /**
3324
+ * Clean up stale sessions (sessions with count=0 that haven't been updated in 1 hour)
3325
+ */
3326
+ cleanupStaleSessions() {
3327
+ const oneHourAgo = Date.now() - 60 * 60 * 1e3;
3328
+ for (const [sessionId, data] of this.sessionDelegations.entries()) {
3329
+ if (data.count === 0 && data.lastUpdated < oneHourAgo) {
3330
+ this.sessionDelegations.delete(sessionId);
3331
+ }
3332
+ }
3333
+ }
3334
+ /**
3335
+ * Cleanup all resources (for testing or shutdown)
3336
+ */
3337
+ cleanup() {
3338
+ if (this.cleanupInterval) {
3339
+ clearInterval(this.cleanupInterval);
3340
+ this.cleanupInterval = null;
3341
+ }
3342
+ this.sessionDelegations.clear();
3343
+ this.globalActive = 0;
3344
+ }
3345
+ };
3346
+ delegationManager = new DelegationManager();
3347
+ }
3348
+ });
3349
+
3066
3350
  // node_modules/zod/v3/helpers/util.js
3067
3351
  var util, objectUtil, ZodParsedType, getParsedType;
3068
3352
  var init_util2 = __esm({
@@ -7276,7 +7560,7 @@ function parseTargets(targets) {
7276
7560
  }
7277
7561
  return targets.split(/\s+/).filter((f) => f.length > 0);
7278
7562
  }
7279
- var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, attemptCompletionToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
7563
+ var searchSchema, querySchema, extractSchema, delegateSchema, bashSchema, attemptCompletionSchema, searchToolDefinition, queryToolDefinition, extractToolDefinition, delegateToolDefinition, attemptCompletionToolDefinition, searchDescription, queryDescription, extractDescription, delegateDescription, DEFAULT_VALID_TOOLS;
7280
7564
  var init_common = __esm({
7281
7565
  "src/tools/common.js"() {
7282
7566
  "use strict";
@@ -7481,6 +7765,26 @@ User: Read file inside the dependency
7481
7765
  </extract>
7482
7766
 
7483
7767
  </examples>
7768
+ `;
7769
+ delegateToolDefinition = `
7770
+ ## delegate
7771
+ Description: Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Use this when you recognize that a user's request involves multiple large, distinct components that would benefit from parallel processing or specialized focus. The AI agent should automatically identify opportunities for task separation and use delegation without explicit user instruction.
7772
+
7773
+ Parameters:
7774
+ - task: (required) A complete, self-contained task that can be executed independently by a subagent. Should be specific and focused on one area of expertise.
7775
+
7776
+ Usage Pattern:
7777
+ When the AI agent encounters complex multi-part requests, it should automatically break them down and delegate:
7778
+
7779
+ <delegate>
7780
+ <task>Analyze all authentication and authorization code in the codebase for security vulnerabilities and provide specific remediation recommendations</task>
7781
+ </delegate>
7782
+
7783
+ <delegate>
7784
+ <task>Review database queries and API endpoints for performance bottlenecks and suggest optimization strategies</task>
7785
+ </delegate>
7786
+
7787
+ The agent uses this tool automatically when it identifies that work can be separated into distinct, parallel tasks for more efficient processing.
7484
7788
  `;
7485
7789
  attemptCompletionToolDefinition = `
7486
7790
  ## attempt_completion
@@ -7509,193 +7813,6 @@ I have refactored the search module according to the requirements and verified t
7509
7813
  }
7510
7814
  });
7511
7815
 
7512
- // src/delegate.js
7513
- import { spawn as spawn2 } from "child_process";
7514
- import { randomUUID } from "crypto";
7515
- async function delegate({ task, timeout = 300, debug = false, currentIteration = 0, maxIterations = 30, tracer = null }) {
7516
- if (!task || typeof task !== "string") {
7517
- throw new Error("Task parameter is required and must be a string");
7518
- }
7519
- const sessionId = randomUUID();
7520
- const startTime = Date.now();
7521
- const remainingIterations = Math.max(1, maxIterations - currentIteration);
7522
- if (debug) {
7523
- console.error(`[DELEGATE] Starting delegation session ${sessionId}`);
7524
- console.error(`[DELEGATE] Task: ${task}`);
7525
- console.error(`[DELEGATE] Current iteration: ${currentIteration}/${maxIterations}`);
7526
- console.error(`[DELEGATE] Remaining iterations for subagent: ${remainingIterations}`);
7527
- console.error(`[DELEGATE] Timeout configured: ${timeout} seconds`);
7528
- console.error(`[DELEGATE] Using clean agent environment with code-researcher prompt`);
7529
- }
7530
- try {
7531
- const binaryPath = await getBinaryPath();
7532
- const args = [
7533
- "agent",
7534
- "--task",
7535
- task,
7536
- "--session-id",
7537
- sessionId,
7538
- "--prompt-type",
7539
- "code-researcher",
7540
- // Automatically use default code researcher prompt
7541
- "--no-schema-validation",
7542
- // Automatically disable schema validation
7543
- "--no-mermaid-validation",
7544
- // Automatically disable mermaid validation
7545
- "--max-iterations",
7546
- remainingIterations.toString()
7547
- // Automatically limit to remaining iterations
7548
- ];
7549
- if (debug) {
7550
- args.push("--debug");
7551
- console.error(`[DELEGATE] Using binary at: ${binaryPath}`);
7552
- console.error(`[DELEGATE] Command args: ${args.join(" ")}`);
7553
- }
7554
- return new Promise((resolve5, reject2) => {
7555
- const delegationSpan = tracer ? tracer.createDelegationSpan(sessionId, task) : null;
7556
- const process2 = spawn2(binaryPath, args, {
7557
- stdio: ["pipe", "pipe", "pipe"],
7558
- timeout: timeout * 1e3
7559
- });
7560
- let stdout = "";
7561
- let stderr = "";
7562
- let isResolved = false;
7563
- process2.stdout.on("data", (data) => {
7564
- const chunk = data.toString();
7565
- stdout += chunk;
7566
- if (debug) {
7567
- const preview = createMessagePreview(chunk);
7568
- console.error(`[DELEGATE] stdout chunk received (${chunk.length} chars): ${preview}`);
7569
- }
7570
- });
7571
- process2.stderr.on("data", (data) => {
7572
- const chunk = data.toString();
7573
- stderr += chunk;
7574
- if (debug) {
7575
- const preview = createMessagePreview(chunk);
7576
- console.error(`[DELEGATE] stderr chunk received (${chunk.length} chars): ${preview}`);
7577
- }
7578
- });
7579
- process2.on("close", (code) => {
7580
- if (isResolved) return;
7581
- isResolved = true;
7582
- const duration = Date.now() - startTime;
7583
- if (debug) {
7584
- console.error(`[DELEGATE] Process completed with code ${code} in ${duration}ms`);
7585
- console.error(`[DELEGATE] Duration: ${(duration / 1e3).toFixed(2)}s`);
7586
- console.error(`[DELEGATE] Total stdout: ${stdout.length} chars`);
7587
- console.error(`[DELEGATE] Total stderr: ${stderr.length} chars`);
7588
- }
7589
- if (code === 0) {
7590
- const response = stdout.trim();
7591
- if (!response) {
7592
- if (debug) {
7593
- console.error(`[DELEGATE] Task completed but returned empty response for session ${sessionId}`);
7594
- }
7595
- reject2(new Error("Delegate agent returned empty response"));
7596
- return;
7597
- }
7598
- if (debug) {
7599
- console.error(`[DELEGATE] Task completed successfully for session ${sessionId}`);
7600
- console.error(`[DELEGATE] Response length: ${response.length} chars`);
7601
- }
7602
- if (tracer) {
7603
- tracer.recordDelegationEvent("completed", {
7604
- "delegation.session_id": sessionId,
7605
- "delegation.duration_ms": duration,
7606
- "delegation.response_length": response.length,
7607
- "delegation.success": true
7608
- });
7609
- if (delegationSpan) {
7610
- delegationSpan.setAttributes({
7611
- "delegation.result.success": true,
7612
- "delegation.result.response_length": response.length,
7613
- "delegation.result.duration_ms": duration
7614
- });
7615
- delegationSpan.setStatus({ code: 1 });
7616
- delegationSpan.end();
7617
- }
7618
- }
7619
- resolve5(response);
7620
- } else {
7621
- const errorMessage = stderr.trim() || `Delegate process failed with exit code ${code}`;
7622
- if (debug) {
7623
- console.error(`[DELEGATE] Task failed for session ${sessionId} with code ${code}`);
7624
- console.error(`[DELEGATE] Error message: ${errorMessage}`);
7625
- }
7626
- if (tracer) {
7627
- tracer.recordDelegationEvent("failed", {
7628
- "delegation.session_id": sessionId,
7629
- "delegation.duration_ms": duration,
7630
- "delegation.exit_code": code,
7631
- "delegation.error_message": errorMessage,
7632
- "delegation.success": false
7633
- });
7634
- if (delegationSpan) {
7635
- delegationSpan.setAttributes({
7636
- "delegation.result.success": false,
7637
- "delegation.result.exit_code": code,
7638
- "delegation.result.error": errorMessage,
7639
- "delegation.result.duration_ms": duration
7640
- });
7641
- delegationSpan.setStatus({ code: 2, message: errorMessage });
7642
- delegationSpan.end();
7643
- }
7644
- }
7645
- reject2(new Error(`Delegation failed: ${errorMessage}`));
7646
- }
7647
- });
7648
- process2.on("error", (error) => {
7649
- if (isResolved) return;
7650
- isResolved = true;
7651
- const duration = Date.now() - startTime;
7652
- if (debug) {
7653
- console.error(`[DELEGATE] Process spawn error after ${duration}ms:`, error);
7654
- console.error(`[DELEGATE] Session ${sessionId} failed during process creation`);
7655
- console.error(`[DELEGATE] Error type: ${error.code || "unknown"}`);
7656
- }
7657
- reject2(new Error(`Failed to start delegate process: ${error.message}`));
7658
- });
7659
- setTimeout(() => {
7660
- if (isResolved) return;
7661
- isResolved = true;
7662
- const duration = Date.now() - startTime;
7663
- if (debug) {
7664
- console.error(`[DELEGATE] Process timeout after ${(duration / 1e3).toFixed(2)}s (limit: ${timeout}s)`);
7665
- console.error(`[DELEGATE] Terminating session ${sessionId} due to timeout`);
7666
- console.error(`[DELEGATE] Partial stdout: ${stdout.substring(0, 500)}${stdout.length > 500 ? "..." : ""}`);
7667
- console.error(`[DELEGATE] Partial stderr: ${stderr.substring(0, 500)}${stderr.length > 500 ? "..." : ""}`);
7668
- }
7669
- process2.kill("SIGTERM");
7670
- setTimeout(() => {
7671
- if (!process2.killed) {
7672
- if (debug) {
7673
- console.error(`[DELEGATE] Force killing process ${sessionId} after graceful timeout`);
7674
- }
7675
- process2.kill("SIGKILL");
7676
- }
7677
- }, 5e3);
7678
- reject2(new Error(`Delegation timed out after ${timeout} seconds`));
7679
- }, timeout * 1e3);
7680
- });
7681
- } catch (error) {
7682
- const duration = Date.now() - startTime;
7683
- if (debug) {
7684
- console.error(`[DELEGATE] Error in delegate function after ${duration}ms:`, error);
7685
- console.error(`[DELEGATE] Session ${sessionId} failed during setup`);
7686
- console.error(`[DELEGATE] Error stack: ${error.stack}`);
7687
- }
7688
- throw new Error(`Delegation setup failed: ${error.message}`);
7689
- }
7690
- }
7691
- var init_delegate = __esm({
7692
- "src/delegate.js"() {
7693
- "use strict";
7694
- init_utils();
7695
- init_common();
7696
- }
7697
- });
7698
-
7699
7816
  // src/tools/vercel.js
7700
7817
  import { tool } from "ai";
7701
7818
  var searchTool, queryTool, extractTool, delegateTool;
@@ -7868,21 +7985,50 @@ var init_vercel = __esm({
7868
7985
  name: "delegate",
7869
7986
  description: delegateDescription,
7870
7987
  inputSchema: delegateSchema,
7871
- execute: async ({ task }) => {
7872
- try {
7873
- if (debug) {
7874
- console.error(`Executing delegate with task: "${task}"`);
7875
- }
7876
- const result = await delegate({
7877
- task,
7878
- timeout,
7879
- debug
7880
- });
7881
- return result;
7882
- } catch (error) {
7883
- console.error("Error executing delegate command:", error);
7884
- return `Error executing delegate command: ${error.message}`;
7988
+ execute: async ({ task, currentIteration, maxIterations, parentSessionId, path: path7, provider, model, tracer }) => {
7989
+ if (!task || typeof task !== "string") {
7990
+ throw new Error("Task parameter is required and must be a non-empty string");
7991
+ }
7992
+ if (task.trim().length === 0) {
7993
+ throw new Error("Task parameter cannot be empty or whitespace only");
7994
+ }
7995
+ if (currentIteration !== void 0 && (typeof currentIteration !== "number" || currentIteration < 0)) {
7996
+ throw new Error("currentIteration must be a non-negative number");
7885
7997
  }
7998
+ if (maxIterations !== void 0 && (typeof maxIterations !== "number" || maxIterations < 1)) {
7999
+ throw new Error("maxIterations must be a positive number");
8000
+ }
8001
+ if (parentSessionId !== void 0 && parentSessionId !== null && typeof parentSessionId !== "string") {
8002
+ throw new TypeError("parentSessionId must be a string, null, or undefined");
8003
+ }
8004
+ if (path7 !== void 0 && path7 !== null && typeof path7 !== "string") {
8005
+ throw new TypeError("path must be a string, null, or undefined");
8006
+ }
8007
+ if (provider !== void 0 && provider !== null && typeof provider !== "string") {
8008
+ throw new TypeError("provider must be a string, null, or undefined");
8009
+ }
8010
+ if (model !== void 0 && model !== null && typeof model !== "string") {
8011
+ throw new TypeError("model must be a string, null, or undefined");
8012
+ }
8013
+ if (debug) {
8014
+ console.error(`Executing delegate with task: "${task.substring(0, 100)}${task.length > 100 ? "..." : ""}"`);
8015
+ if (parentSessionId) {
8016
+ console.error(`Parent session: ${parentSessionId}`);
8017
+ }
8018
+ }
8019
+ const result = await delegate({
8020
+ task,
8021
+ timeout,
8022
+ debug,
8023
+ currentIteration: currentIteration || 0,
8024
+ maxIterations: maxIterations || 30,
8025
+ parentSessionId,
8026
+ path: path7,
8027
+ provider,
8028
+ model,
8029
+ tracer
8030
+ });
8031
+ return result;
7886
8032
  }
7887
8033
  });
7888
8034
  };
@@ -8711,7 +8857,7 @@ var init_bashPermissions = __esm({
8711
8857
  });
8712
8858
 
8713
8859
  // src/agent/bashExecutor.js
8714
- import { spawn as spawn3 } from "child_process";
8860
+ import { spawn as spawn2 } from "child_process";
8715
8861
  import { resolve, join } from "path";
8716
8862
  import { existsSync } from "fs";
8717
8863
  async function executeBashCommand(command, options = {}) {
@@ -8768,7 +8914,7 @@ async function executeBashCommand(command, options = {}) {
8768
8914
  return;
8769
8915
  }
8770
8916
  const [cmd, ...cmdArgs] = args;
8771
- const child = spawn3(cmd, cmdArgs, {
8917
+ const child = spawn2(cmd, cmdArgs, {
8772
8918
  cwd,
8773
8919
  env: processEnv,
8774
8920
  stdio: ["ignore", "pipe", "pipe"],
@@ -29929,13 +30075,24 @@ function mapFlowchartParserError(err, text) {
29929
30075
  length: len
29930
30076
  };
29931
30077
  }
29932
- if (tokType === "QuotedString") {
30078
+ if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
29933
30079
  const context = err?.context;
29934
30080
  const inLinkRule = context?.ruleStack?.includes("linkTextInline") || context?.ruleStack?.includes("link") || false;
29935
30081
  const lineContent = allLines[Math.max(0, line - 1)] || "";
29936
30082
  const beforeQuote = lineContent.slice(0, Math.max(0, column - 1));
29937
30083
  const hasLinkBefore = beforeQuote.match(/--\s*$|==\s*$|-\.\s*$|-\.-\s*$|\[\s*$/);
29938
30084
  if (inLinkRule || hasLinkBefore) {
30085
+ if (tokType === "SquareOpen" || tokType === "SquareClose") {
30086
+ return {
30087
+ line,
30088
+ column,
30089
+ severity: "error",
30090
+ code: "FL-EDGE-LABEL-BRACKET",
30091
+ message: "Square brackets [ ] are not supported inside inline edge labels.",
30092
+ hint: "Use HTML entities &#91; and &#93; inside |...|, e.g., --|run: &#91;aggregate&#93;|-->",
30093
+ length: len
30094
+ };
30095
+ }
29939
30096
  const quotedText = found.startsWith('"') ? found.slice(1, -1) : found;
29940
30097
  return {
29941
30098
  line,
@@ -30029,7 +30186,7 @@ function mapFlowchartParserError(err, text) {
30029
30186
  }
30030
30187
  }
30031
30188
  }
30032
- if (tokType === "QuotedString") {
30189
+ if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
30033
30190
  return {
30034
30191
  line,
30035
30192
  column,
@@ -30050,7 +30207,7 @@ function mapFlowchartParserError(err, text) {
30050
30207
  return { line, column, severity: "error", code: "FL-NODE-UNCLOSED-BRACKET", message: "Unclosed '['. Add a matching ']' before the arrow or newline.", hint: "Example: A[Label] --> B", length: 1 };
30051
30208
  }
30052
30209
  if (expecting(err, "RoundClose")) {
30053
- if (tokType === "QuotedString") {
30210
+ if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
30054
30211
  return {
30055
30212
  line,
30056
30213
  column,
@@ -30089,7 +30246,7 @@ function mapFlowchartParserError(err, text) {
30089
30246
  return { line, column, severity: "error", code: "FL-NODE-UNCLOSED-BRACKET", message: "Unclosed '('. Add a matching ')'.", hint: "Example: B(Label)", length: 1 };
30090
30247
  }
30091
30248
  if (expecting(err, "DiamondClose")) {
30092
- if (tokType === "QuotedString") {
30249
+ if (tokType === "QuotedString" || tokType === "SquareOpen" || tokType === "SquareClose") {
30093
30250
  return {
30094
30251
  line,
30095
30252
  column,
@@ -30935,6 +31092,53 @@ function validateFlowchart(text, options = {}) {
30935
31092
  }
30936
31093
  }
30937
31094
  }
31095
+ {
31096
+ const byLine = /* @__PURE__ */ new Map();
31097
+ const collect = (arr) => {
31098
+ for (const e of arr || []) {
31099
+ if (e && e.code === "FL-LABEL-PARENS-UNQUOTED") {
31100
+ const ln = e.line ?? 0;
31101
+ const col = e.column ?? 1;
31102
+ const list = byLine.get(ln) || [];
31103
+ list.push(col);
31104
+ byLine.set(ln, list);
31105
+ }
31106
+ }
31107
+ };
31108
+ collect(prevErrors);
31109
+ collect(errs);
31110
+ const lines2 = text2.split(/\r?\n/);
31111
+ for (let ii = 0; ii < lines2.length; ii++) {
31112
+ const raw2 = lines2[ii] || "";
31113
+ if (!raw2.includes("[") || !raw2.includes("]"))
31114
+ continue;
31115
+ let search2 = 0;
31116
+ while (true) {
31117
+ const open2 = raw2.indexOf("[", search2);
31118
+ if (open2 === -1)
31119
+ break;
31120
+ const close2 = raw2.indexOf("]", open2 + 1);
31121
+ if (close2 === -1)
31122
+ break;
31123
+ const seg2 = raw2.slice(open2 + 1, close2);
31124
+ const trimmed2 = seg2.trim();
31125
+ const ln2 = ii + 1;
31126
+ const lsp = trimmed2.slice(0, 1);
31127
+ const rsp = trimmed2.slice(-1);
31128
+ const isSlashPair = (lsp === "/" || lsp === "\\") && (rsp === "/" || rsp === "\\");
31129
+ const isParenWrapped = lsp === "(" && rsp === ")";
31130
+ const segStartCol = open2 + 2;
31131
+ const segEndCol = close2 + 1;
31132
+ const existing = byLine.get(ln2) || [];
31133
+ const covered = existing.some((c) => c >= segStartCol && c <= segEndCol);
31134
+ if (!covered && !/^".*"$/.test(trimmed2) && (seg2.includes("(") || seg2.includes(")")) && !isSlashPair && !isParenWrapped) {
31135
+ errs.push({ line: ln2, column: segStartCol, severity: "error", code: "FL-LABEL-PARENS-UNQUOTED", message: "Parentheses inside an unquoted label are not supported by Mermaid.", hint: 'Wrap the label in quotes, e.g., A["Mark (X)"] \u2014 or replace ( and ) with HTML entities: &#40; and &#41;.' });
31136
+ byLine.set(ln2, existing.concat([segStartCol]));
31137
+ }
31138
+ search2 = close2 + 1;
31139
+ }
31140
+ }
31141
+ }
30938
31142
  const dblEsc = (text2.match(/\\\"/g) || []).length;
30939
31143
  const dq = (text2.match(/\"/g) || []).length - dblEsc;
30940
31144
  const sq = (text2.match(/'/g) || []).length;
@@ -33279,6 +33483,21 @@ function computeFixes(text, errors, level = "safe") {
33279
33483
  }
33280
33484
  continue;
33281
33485
  }
33486
+ if (is("FL-EDGE-LABEL-BRACKET", e)) {
33487
+ const lineText = lineTextAt(text, e.line);
33488
+ const firstBar = lineText.indexOf("|");
33489
+ const secondBar = firstBar >= 0 ? lineText.indexOf("|", firstBar + 1) : -1;
33490
+ if (firstBar >= 0 && secondBar > firstBar) {
33491
+ const before = lineText.slice(0, firstBar + 1);
33492
+ const label = lineText.slice(firstBar + 1, secondBar);
33493
+ const after = lineText.slice(secondBar);
33494
+ const fixedLabel = label.replace(/\[/g, "&#91;").replace(/\]/g, "&#93;");
33495
+ const fixedLine = before + fixedLabel + after;
33496
+ const finalLine = fixedLine.replace(/\[([^\]]*)\]/g, (m, seg) => "[" + String(seg).replace(/`/g, "") + "]");
33497
+ edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line, column: lineText.length + 1 }, newText: finalLine });
33498
+ }
33499
+ continue;
33500
+ }
33282
33501
  if (is("FL-EDGE-LABEL-BACKTICK", e)) {
33283
33502
  const lineText = lineTextAt(text, e.line);
33284
33503
  const re = /^(.*?--)\s*([^|>]+?)\s*(-->|==>|\.->|->)(.*)$/;
@@ -55434,6 +55653,7 @@ var init_ProbeAgent = __esm({
55434
55653
  * @param {string} [options.customPrompt] - Custom prompt to replace the default system message
55435
55654
  * @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
55436
55655
  * @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
55656
+ * @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
55437
55657
  * @param {string} [options.path] - Search directory path
55438
55658
  * @param {string} [options.provider] - Force specific AI provider
55439
55659
  * @param {string} [options.model] - Override model name
@@ -55455,6 +55675,7 @@ var init_ProbeAgent = __esm({
55455
55675
  this.customPrompt = options.customPrompt || null;
55456
55676
  this.promptType = options.promptType || "code-explorer";
55457
55677
  this.allowEdit = !!options.allowEdit;
55678
+ this.enableDelegate = !!options.enableDelegate;
55458
55679
  this.debug = options.debug || process.env.DEBUG === "1";
55459
55680
  this.cancelled = false;
55460
55681
  this.tracer = options.tracer || null;
@@ -56049,6 +56270,10 @@ ${attemptCompletionToolDefinition}
56049
56270
  `;
56050
56271
  if (this.allowEdit) {
56051
56272
  toolDefinitions += `${implementToolDefinition}
56273
+ `;
56274
+ }
56275
+ if (this.enableDelegate) {
56276
+ toolDefinitions += `${delegateToolDefinition}
56052
56277
  `;
56053
56278
  }
56054
56279
  let xmlToolGuidelines = `
@@ -56112,7 +56337,7 @@ Available Tools:
56112
56337
  - extract: Extract specific code blocks or lines from files.
56113
56338
  - listFiles: List files and directories in a specified location.
56114
56339
  - searchFiles: Find files matching a glob pattern with recursive search capability.
56115
- ${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n" : ""}
56340
+ ${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n" : ""}${this.enableDelegate ? "- delegate: Delegate big distinct tasks to specialized probe subagents.\n" : ""}
56116
56341
  - attempt_completion: Finalize the task and provide the result to the user.
56117
56342
  - attempt_complete: Quick completion using previous response (shorthand).
56118
56343
  `;
@@ -56432,6 +56657,9 @@ You are working with a repository located at: ${searchDirectory}
56432
56657
  if (this.allowEdit) {
56433
56658
  validTools.push("implement");
56434
56659
  }
56660
+ if (this.enableDelegate) {
56661
+ validTools.push("delegate");
56662
+ }
56435
56663
  const nativeTools = validTools;
56436
56664
  const parsedTool = this.mcpBridge ? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge) : parseXmlToolCallWithThinking(assistantResponseContent, validTools);
56437
56665
  if (parsedTool) {
@@ -56545,11 +56773,21 @@ ${toolResultContent}
56545
56773
  ...toolParams,
56546
56774
  currentIteration,
56547
56775
  maxIterations,
56776
+ parentSessionId: this.sessionId,
56777
+ // Pass parent session ID for tracking
56778
+ path: this.searchPath,
56779
+ // Inherit search path
56780
+ provider: this.provider,
56781
+ // Inherit AI provider
56782
+ model: this.model,
56783
+ // Inherit model
56548
56784
  debug: this.debug,
56549
56785
  tracer: this.tracer
56550
56786
  };
56551
56787
  if (this.debug) {
56552
56788
  console.log(`[DEBUG] Executing delegate tool at iteration ${currentIteration}/${maxIterations}`);
56789
+ console.log(`[DEBUG] Parent session: ${this.sessionId}`);
56790
+ console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.provider}, model=${this.model}`);
56553
56791
  console.log(`[DEBUG] Delegate task: ${toolParams.task?.substring(0, 100)}...`);
56554
56792
  }
56555
56793
  if (this.tracer) {
@@ -57140,6 +57378,7 @@ Convert your previous response content into actual JSON data that follows this s
57140
57378
  customPrompt: this.customPrompt,
57141
57379
  promptType: this.promptType,
57142
57380
  allowEdit: this.allowEdit,
57381
+ enableDelegate: this.enableDelegate,
57143
57382
  path: this.allowedFolders[0],
57144
57383
  // Use first allowed folder as primary path
57145
57384
  allowedFolders: [...this.allowedFolders],
@@ -57896,6 +58135,7 @@ var ACPServer = class {
57896
58135
  provider: this.options.provider,
57897
58136
  model: this.options.model,
57898
58137
  allowEdit: this.options.allowEdit,
58138
+ enableDelegate: this.options.enableDelegate,
57899
58139
  debug: this.options.debug,
57900
58140
  enableMcp: this.options.enableMcp,
57901
58141
  mcpConfig: this.options.mcpConfig,
@@ -58070,6 +58310,7 @@ function parseArgs() {
58070
58310
  provider: null,
58071
58311
  model: null,
58072
58312
  allowEdit: false,
58313
+ enableDelegate: false,
58073
58314
  verbose: false,
58074
58315
  help: false,
58075
58316
  maxIterations: null,
@@ -58104,6 +58345,10 @@ function parseArgs() {
58104
58345
  config.verbose = true;
58105
58346
  } else if (arg === "--allow-edit") {
58106
58347
  config.allowEdit = true;
58348
+ } else if (arg === "--enable-delegate") {
58349
+ config.enableDelegate = true;
58350
+ } else if (arg === "--no-delegate") {
58351
+ config.enableDelegate = false;
58107
58352
  } else if (arg === "--path" && i + 1 < args.length) {
58108
58353
  config.path = args[++i];
58109
58354
  } else if (arg === "--allowed-folders" && i + 1 < args.length) {
@@ -58175,6 +58420,7 @@ Options:
58175
58420
  --provider <name> Force AI provider: anthropic, openai, google
58176
58421
  --model <name> Override model name
58177
58422
  --allow-edit Enable code modification capabilities
58423
+ --enable-delegate Enable delegate tool for task distribution to subagents
58178
58424
  --verbose Enable verbose output
58179
58425
  --outline Use outline-xml format for code search results
58180
58426
  --mcp Run as MCP server
@@ -58455,6 +58701,7 @@ async function main() {
58455
58701
  model: config.model,
58456
58702
  path: config.path,
58457
58703
  allowEdit: config.allowEdit,
58704
+ enableDelegate: config.enableDelegate,
58458
58705
  debug: config.verbose
58459
58706
  });
58460
58707
  await server.start();
@@ -58573,6 +58820,7 @@ async function main() {
58573
58820
  promptType: config.prompt,
58574
58821
  customPrompt: systemPrompt,
58575
58822
  allowEdit: config.allowEdit,
58823
+ enableDelegate: config.enableDelegate,
58576
58824
  debug: config.verbose,
58577
58825
  tracer: appTracer,
58578
58826
  outline: config.outline,