@probelabs/probe 0.6.0-rc296 → 0.6.0-rc298

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
@@ -48058,7 +48058,22 @@ function mapFlowchartParserError(err, text) {
48058
48058
  const lineContent = allLines[Math.max(0, line - 1)] || "";
48059
48059
  const beforeQuote = lineContent.slice(0, Math.max(0, column - 1));
48060
48060
  const hasLinkBefore = beforeQuote.match(/--\s*$|==\s*$|-\.\s*$|-\.-\s*$|\[\s*$/);
48061
+ const caret0 = Math.max(0, column - 1);
48062
+ const firstBar = lineContent.lastIndexOf("|", caret0);
48063
+ const secondBar = firstBar >= 0 ? lineContent.indexOf("|", caret0 + 1) : -1;
48064
+ const inPipeLabel = firstBar >= 0 && secondBar > firstBar && firstBar < caret0 && secondBar > caret0;
48061
48065
  if (inLinkRule || hasLinkBefore) {
48066
+ if (tokType === "QuotedString" && inPipeLabel) {
48067
+ return {
48068
+ line,
48069
+ column,
48070
+ severity: "error",
48071
+ code: "FL-EDGE-LABEL-QUOTE-IN-PIPES",
48072
+ message: "Quotes are not supported inside pipe-delimited edge labels.",
48073
+ hint: "Use &quot; inside |...|, e.g., --|e.g. &quot;navigate to example.com&quot;|-->",
48074
+ length: len
48075
+ };
48076
+ }
48062
48077
  if (tokType === "DiamondOpen" || tokType === "DiamondClose") {
48063
48078
  return {
48064
48079
  line,
@@ -48660,17 +48675,6 @@ ${br.example}`,
48660
48675
  if (inRule("arrow") && err.name === "NoViableAltException") {
48661
48676
  return { line, column, severity: "error", code: "SE-ARROW-INVALID", message: `Invalid sequence arrow near '${found}'.`, hint: "Use ->, -->, ->>, -->>, -x, --x, -), --), <<->>, or <<-->>", length: len };
48662
48677
  }
48663
- if ((err.name === "NoViableAltException" || err.name === "MismatchedTokenException") && tokType === "Minus") {
48664
- return {
48665
- line,
48666
- column,
48667
- severity: "error",
48668
- code: "SE-BULLET-LINE-UNSUPPORTED",
48669
- message: "Bullet list lines starting with '-' are not supported in sequence diagrams.",
48670
- hint: "Wrap free\u2011form text in a note block instead, for example:\nNote over A : Item 1\nNote over A\n - Item 1\n - Item 2\nend note",
48671
- length: len
48672
- };
48673
- }
48674
48678
  if (inRule("noteStmt")) {
48675
48679
  if (err.name === "MismatchedTokenException" && exp("Colon")) {
48676
48680
  return { line, column, severity: "error", code: "SE-NOTE-MALFORMED", message: "Malformed note: missing colon before the note text.", hint: "Example: Note right of Alice: Hello", length: len };
@@ -48679,6 +48683,22 @@ ${br.example}`,
48679
48683
  return { line, column, severity: "error", code: "SE-NOTE-MALFORMED", message: "Malformed note statement. Use left|right of X or over X[,Y]: text", hint: "Examples: Note over A,B: hi", length: len };
48680
48684
  }
48681
48685
  }
48686
+ if ((err.name === "NoViableAltException" || err.name === "MismatchedTokenException") && tokType === "Minus") {
48687
+ const nonWs = ltxt.search(/\S/);
48688
+ const minusAtLineStart = nonWs >= 0 && ltxt[nonWs] === "-" && column === nonWs + 1;
48689
+ if (!minusAtLineStart) {
48690
+ } else {
48691
+ return {
48692
+ line,
48693
+ column,
48694
+ severity: "error",
48695
+ code: "SE-BULLET-LINE-UNSUPPORTED",
48696
+ message: "Bullet list lines starting with '-' are not supported in sequence diagrams.",
48697
+ hint: "Wrap free\u2011form text in a note block instead, for example:\nNote over A : Item 1\nNote over A\n - Item 1\n - Item 2\nend note",
48698
+ length: len
48699
+ };
48700
+ }
48701
+ }
48682
48702
  if (tokType === "ElseKeyword" && isInRule(err, "criticalBlock")) {
48683
48703
  return {
48684
48704
  line,
@@ -49478,7 +49498,7 @@ var Identifier2, NumberLiteral3, SequenceKeyword, ParticipantKeyword, ActorKeywo
49478
49498
  var init_lexer4 = __esm({
49479
49499
  "node_modules/@probelabs/maid/out/diagrams/sequence/lexer.js"() {
49480
49500
  init_api6();
49481
- Identifier2 = createToken({ name: "Identifier", pattern: /[A-Za-z_][A-Za-z0-9_]*/ });
49501
+ Identifier2 = createToken({ name: "Identifier", pattern: /[A-Za-z_][A-Za-z0-9_.]*(?:-(?![>x)\s])[A-Za-z0-9_.]+)*/ });
49482
49502
  NumberLiteral3 = createToken({ name: "NumberLiteral", pattern: /[0-9]+/ });
49483
49503
  SequenceKeyword = createToken({ name: "SequenceKeyword", pattern: /sequenceDiagram/, longer_alt: Identifier2 });
49484
49504
  ParticipantKeyword = createToken({ name: "ParticipantKeyword", pattern: /participant/i, longer_alt: Identifier2 });
@@ -51298,6 +51318,135 @@ var init_validate5 = __esm({
51298
51318
  }
51299
51319
  });
51300
51320
 
51321
+ // node_modules/@probelabs/maid/out/core/frontmatter.js
51322
+ function parseFrontmatter(input) {
51323
+ const text = input.startsWith("\uFEFF") ? input.slice(1) : input;
51324
+ const lines = text.split(/\r?\n/);
51325
+ if (lines.length < 3 || lines[0].trim() !== "---")
51326
+ return null;
51327
+ let i = 1;
51328
+ const block = [];
51329
+ while (i < lines.length && lines[i].trim() !== "---") {
51330
+ block.push(lines[i]);
51331
+ i++;
51332
+ }
51333
+ if (i >= lines.length)
51334
+ return null;
51335
+ const body = lines.slice(i + 1).join("\n");
51336
+ const bodyStartLine = i + 2;
51337
+ const raw = block.join("\n");
51338
+ const config2 = {};
51339
+ const themeVars = {};
51340
+ let themeUnderConfig = false;
51341
+ let ctx = "root";
51342
+ for (const line of block) {
51343
+ if (!line.trim())
51344
+ continue;
51345
+ const indent = line.match(/^\s*/)?.[0].length ?? 0;
51346
+ const mKey = line.match(/^\s*([A-Za-z0-9_\-]+):\s*(.*)$/);
51347
+ if (!mKey)
51348
+ continue;
51349
+ const key = mKey[1];
51350
+ let value = mKey[2] || "";
51351
+ if (indent === 0) {
51352
+ if (key === "config") {
51353
+ ctx = "config";
51354
+ continue;
51355
+ }
51356
+ if (key === "themeVariables") {
51357
+ ctx = "theme";
51358
+ continue;
51359
+ }
51360
+ ctx = "root";
51361
+ continue;
51362
+ }
51363
+ if (ctx === "config") {
51364
+ if (indent <= 2 && key !== "pie" && key !== "themeVariables")
51365
+ continue;
51366
+ if (key === "pie") {
51367
+ ctx = "config.pie";
51368
+ ensure(config2, "pie", {});
51369
+ continue;
51370
+ }
51371
+ if (key === "themeVariables") {
51372
+ ctx = "theme";
51373
+ themeUnderConfig = true;
51374
+ continue;
51375
+ }
51376
+ continue;
51377
+ }
51378
+ if (ctx === "config.pie") {
51379
+ if (indent < 4) {
51380
+ if (key === "pie") {
51381
+ ctx = "config.pie";
51382
+ ensure(config2, "pie", {});
51383
+ continue;
51384
+ }
51385
+ if (key === "themeVariables") {
51386
+ ctx = "theme";
51387
+ themeUnderConfig = true;
51388
+ continue;
51389
+ }
51390
+ ctx = "config";
51391
+ continue;
51392
+ }
51393
+ setKV(config2.pie, key, value);
51394
+ continue;
51395
+ }
51396
+ if (ctx === "theme") {
51397
+ if (indent < 2) {
51398
+ ctx = "root";
51399
+ continue;
51400
+ }
51401
+ setKV(themeVars, key, value);
51402
+ continue;
51403
+ }
51404
+ }
51405
+ if (themeUnderConfig && Object.keys(themeVars).length) {
51406
+ ensure(config2, "themeVariables", {});
51407
+ Object.assign(config2.themeVariables, themeVars);
51408
+ }
51409
+ return {
51410
+ raw,
51411
+ body,
51412
+ bodyStartLine,
51413
+ config: Object.keys(config2).length ? config2 : void 0,
51414
+ themeVariables: Object.keys(themeVars).length ? themeVars : void 0
51415
+ };
51416
+ }
51417
+ function ensure(obj, key, def) {
51418
+ if (obj[key] == null)
51419
+ obj[key] = def;
51420
+ }
51421
+ function unquote(val) {
51422
+ const v = val.trim();
51423
+ if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
51424
+ return v.slice(1, -1);
51425
+ }
51426
+ return v;
51427
+ }
51428
+ function setKV(target, key, rawValue) {
51429
+ const v = unquote(rawValue);
51430
+ if (v === "") {
51431
+ target[key] = "";
51432
+ return;
51433
+ }
51434
+ const num = Number(v);
51435
+ if (!Number.isNaN(num) && /^-?[0-9]+(\.[0-9]+)?$/.test(v)) {
51436
+ target[key] = num;
51437
+ return;
51438
+ }
51439
+ if (/^(true|false)$/i.test(v)) {
51440
+ target[key] = /^true$/i.test(v);
51441
+ return;
51442
+ }
51443
+ target[key] = v;
51444
+ }
51445
+ var init_frontmatter = __esm({
51446
+ "node_modules/@probelabs/maid/out/core/frontmatter.js"() {
51447
+ }
51448
+ });
51449
+
51301
51450
  // node_modules/@probelabs/maid/out/core/router.js
51302
51451
  function firstNonCommentLine(text) {
51303
51452
  const lines = text.split(/\r?\n/);
@@ -51312,7 +51461,8 @@ function firstNonCommentLine(text) {
51312
51461
  return void 0;
51313
51462
  }
51314
51463
  function detectDiagramType(text) {
51315
- const header = firstNonCommentLine(text);
51464
+ const { content } = stripFrontmatter(text);
51465
+ const header = firstNonCommentLine(content);
51316
51466
  if (!header)
51317
51467
  return "unknown";
51318
51468
  if (/^(flowchart|graph)\b/i.test(header))
@@ -51364,20 +51514,26 @@ function isOtherMermaidDiagram(headerLine) {
51364
51514
  return OTHER.has(t);
51365
51515
  }
51366
51516
  function validate(text, options = {}) {
51367
- const type = detectDiagramType(text);
51517
+ const { content, lineOffset } = stripFrontmatter(text);
51518
+ const type = detectDiagramType(content);
51519
+ const withOffset = (errors) => {
51520
+ if (lineOffset === 0)
51521
+ return errors;
51522
+ return errors.map((e) => ({ ...e, line: Math.max(1, (e.line || 1) + lineOffset) }));
51523
+ };
51368
51524
  switch (type) {
51369
51525
  case "flowchart":
51370
- return { type, errors: validateFlowchart(text, options) };
51526
+ return { type, errors: withOffset(validateFlowchart(content, options)) };
51371
51527
  case "pie":
51372
- return { type, errors: validatePie(text, options) };
51528
+ return { type, errors: withOffset(validatePie(content, options)) };
51373
51529
  case "sequence":
51374
- return { type, errors: validateSequence(text, options) };
51530
+ return { type, errors: withOffset(validateSequence(content, options)) };
51375
51531
  case "class":
51376
- return { type, errors: validateClass(text, options) };
51532
+ return { type, errors: withOffset(validateClass(content, options)) };
51377
51533
  case "state":
51378
- return { type, errors: validateState(text, options) };
51534
+ return { type, errors: withOffset(validateState(content, options)) };
51379
51535
  default:
51380
- const header = firstNonCommentLine(text);
51536
+ const header = firstNonCommentLine(content);
51381
51537
  if (isOtherMermaidDiagram(header)) {
51382
51538
  return { type, errors: [] };
51383
51539
  }
@@ -51385,7 +51541,7 @@ function validate(text, options = {}) {
51385
51541
  type,
51386
51542
  errors: [
51387
51543
  {
51388
- line: 1,
51544
+ line: lineOffset + 1,
51389
51545
  column: 1,
51390
51546
  message: 'Diagram must start with "graph", "flowchart", "pie", "sequenceDiagram", "classDiagram" or "stateDiagram[-v2]"',
51391
51547
  severity: "error",
@@ -51396,6 +51552,12 @@ function validate(text, options = {}) {
51396
51552
  };
51397
51553
  }
51398
51554
  }
51555
+ function stripFrontmatter(text) {
51556
+ const fm = parseFrontmatter(text);
51557
+ if (!fm)
51558
+ return { content: text, lineOffset: 0 };
51559
+ return { content: fm.body, lineOffset: fm.bodyStartLine - 1 };
51560
+ }
51399
51561
  var init_router = __esm({
51400
51562
  "node_modules/@probelabs/maid/out/core/router.js"() {
51401
51563
  init_validate();
@@ -51403,6 +51565,7 @@ var init_router = __esm({
51403
51565
  init_validate3();
51404
51566
  init_validate4();
51405
51567
  init_validate5();
51568
+ init_frontmatter();
51406
51569
  }
51407
51570
  });
51408
51571
 
@@ -51614,16 +51777,18 @@ function computeFixes(text, errors, level = "safe") {
51614
51777
  }
51615
51778
  continue;
51616
51779
  }
51617
- if (is("FL-EDGE-LABEL-BRACKET", e) || is("FL-EDGE-LABEL-CURLY-IN-PIPES", e)) {
51780
+ if (is("FL-EDGE-LABEL-BRACKET", e) || is("FL-EDGE-LABEL-CURLY-IN-PIPES", e) || is("FL-EDGE-LABEL-QUOTE-IN-PIPES", e)) {
51618
51781
  const lineText = lineTextAt(text, e.line);
51619
- const firstBar = lineText.indexOf("|");
51620
- const secondBar = firstBar >= 0 ? lineText.indexOf("|", firstBar + 1) : -1;
51782
+ const col = Math.max(0, e.column - 1);
51783
+ const firstBar = lineText.lastIndexOf("|", col);
51784
+ const secondBar = firstBar >= 0 ? lineText.indexOf("|", col + 1) : -1;
51621
51785
  if (firstBar >= 0 && secondBar > firstBar) {
51622
51786
  const before = lineText.slice(0, firstBar + 1);
51623
51787
  const label = lineText.slice(firstBar + 1, secondBar);
51624
51788
  const after = lineText.slice(secondBar);
51625
51789
  let fixedLabel = label.replace(/\[/g, "&#91;").replace(/\]/g, "&#93;");
51626
51790
  fixedLabel = fixedLabel.replace(/\{/g, "&#123;").replace(/\}/g, "&#125;");
51791
+ fixedLabel = fixedLabel.replace(/\\"/g, "&quot;").replace(/"/g, "&quot;");
51627
51792
  const fixedLine = before + fixedLabel + after;
51628
51793
  const finalLine = fixedLine.replace(/\[([^\]]*)\]/g, (m, seg) => "[" + String(seg).replace(/`/g, "") + "]");
51629
51794
  edits.push({ start: { line: e.line, column: 1 }, end: { line: e.line, column: lineText.length + 1 }, newText: finalLine });
@@ -63013,7 +63178,7 @@ ${overlay}</g>`;
63013
63178
  });
63014
63179
 
63015
63180
  // node_modules/@probelabs/maid/out/renderer/pie-builder.js
63016
- function unquote(s) {
63181
+ function unquote2(s) {
63017
63182
  if (!s)
63018
63183
  return s;
63019
63184
  const first2 = s.charAt(0);
@@ -63063,7 +63228,7 @@ function buildPieModel(text) {
63063
63228
  const collect = (k) => {
63064
63229
  const arr = tnode.children?.[k] ?? [];
63065
63230
  for (const tok of arr)
63066
- parts.push(unquote(tok.image));
63231
+ parts.push(unquote2(tok.image));
63067
63232
  };
63068
63233
  collect("QuotedString");
63069
63234
  collect("Text");
@@ -63076,7 +63241,7 @@ function buildPieModel(text) {
63076
63241
  const labelTok = snode.children?.sliceLabel?.[0]?.children?.QuotedString?.[0];
63077
63242
  const numTok = snode.children?.NumberLiteral?.[0];
63078
63243
  if (labelTok && numTok) {
63079
- const label = unquote(labelTok.image).trim();
63244
+ const label = unquote2(labelTok.image).trim();
63080
63245
  const value = Number(numTok.image);
63081
63246
  if (!Number.isNaN(value)) {
63082
63247
  model.slices.push({ label, value });
@@ -64232,128 +64397,6 @@ var init_state_renderer = __esm({
64232
64397
  }
64233
64398
  });
64234
64399
 
64235
- // node_modules/@probelabs/maid/out/core/frontmatter.js
64236
- function parseFrontmatter(input) {
64237
- const text = input.startsWith("\uFEFF") ? input.slice(1) : input;
64238
- const lines = text.split(/\r?\n/);
64239
- if (lines.length < 3 || lines[0].trim() !== "---")
64240
- return null;
64241
- let i = 1;
64242
- const block = [];
64243
- while (i < lines.length && lines[i].trim() !== "---") {
64244
- block.push(lines[i]);
64245
- i++;
64246
- }
64247
- if (i >= lines.length)
64248
- return null;
64249
- const body = lines.slice(i + 1).join("\n");
64250
- const raw = block.join("\n");
64251
- const config2 = {};
64252
- const themeVars = {};
64253
- let themeUnderConfig = false;
64254
- let ctx = "root";
64255
- for (const line of block) {
64256
- if (!line.trim())
64257
- continue;
64258
- const indent = line.match(/^\s*/)?.[0].length ?? 0;
64259
- const mKey = line.match(/^\s*([A-Za-z0-9_\-]+):\s*(.*)$/);
64260
- if (!mKey)
64261
- continue;
64262
- const key = mKey[1];
64263
- let value = mKey[2] || "";
64264
- if (indent === 0) {
64265
- if (key === "config") {
64266
- ctx = "config";
64267
- continue;
64268
- }
64269
- if (key === "themeVariables") {
64270
- ctx = "theme";
64271
- continue;
64272
- }
64273
- ctx = "root";
64274
- continue;
64275
- }
64276
- if (ctx === "config") {
64277
- if (indent <= 2 && key !== "pie" && key !== "themeVariables")
64278
- continue;
64279
- if (key === "pie") {
64280
- ctx = "config.pie";
64281
- ensure(config2, "pie", {});
64282
- continue;
64283
- }
64284
- if (key === "themeVariables") {
64285
- ctx = "theme";
64286
- themeUnderConfig = true;
64287
- continue;
64288
- }
64289
- continue;
64290
- }
64291
- if (ctx === "config.pie") {
64292
- if (indent < 4) {
64293
- if (key === "pie") {
64294
- ctx = "config.pie";
64295
- ensure(config2, "pie", {});
64296
- continue;
64297
- }
64298
- if (key === "themeVariables") {
64299
- ctx = "theme";
64300
- themeUnderConfig = true;
64301
- continue;
64302
- }
64303
- ctx = "config";
64304
- continue;
64305
- }
64306
- setKV(config2.pie, key, value);
64307
- continue;
64308
- }
64309
- if (ctx === "theme") {
64310
- if (indent < 2) {
64311
- ctx = "root";
64312
- continue;
64313
- }
64314
- setKV(themeVars, key, value);
64315
- continue;
64316
- }
64317
- }
64318
- if (themeUnderConfig && Object.keys(themeVars).length) {
64319
- ensure(config2, "themeVariables", {});
64320
- Object.assign(config2.themeVariables, themeVars);
64321
- }
64322
- return { raw, body, config: Object.keys(config2).length ? config2 : void 0, themeVariables: Object.keys(themeVars).length ? themeVars : void 0 };
64323
- }
64324
- function ensure(obj, key, def) {
64325
- if (obj[key] == null)
64326
- obj[key] = def;
64327
- }
64328
- function unquote2(val) {
64329
- const v = val.trim();
64330
- if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
64331
- return v.slice(1, -1);
64332
- }
64333
- return v;
64334
- }
64335
- function setKV(target, key, rawValue) {
64336
- const v = unquote2(rawValue);
64337
- if (v === "") {
64338
- target[key] = "";
64339
- return;
64340
- }
64341
- const num = Number(v);
64342
- if (!Number.isNaN(num) && /^-?[0-9]+(\.[0-9]+)?$/.test(v)) {
64343
- target[key] = num;
64344
- return;
64345
- }
64346
- if (/^(true|false)$/i.test(v)) {
64347
- target[key] = /^true$/i.test(v);
64348
- return;
64349
- }
64350
- target[key] = v;
64351
- }
64352
- var init_frontmatter = __esm({
64353
- "node_modules/@probelabs/maid/out/core/frontmatter.js"() {
64354
- }
64355
- });
64356
-
64357
64400
  // node_modules/@probelabs/maid/out/renderer/class-builder.js
64358
64401
  function textFromTokens3(tokens) {
64359
64402
  if (!tokens || tokens.length === 0)
@@ -73676,6 +73719,7 @@ var init_client = __esm({
73676
73719
  this.debug = options.debug || process.env.DEBUG_MCP === "1";
73677
73720
  this.config = null;
73678
73721
  this.tracer = options.tracer || null;
73722
+ this.agentEvents = options.agentEvents || null;
73679
73723
  }
73680
73724
  /**
73681
73725
  * Record an MCP telemetry event if tracer is available
@@ -73903,11 +73947,21 @@ var init_client = __esm({
73903
73947
  throw new Error(`Server ${tool6.serverName} not connected`);
73904
73948
  }
73905
73949
  const startTime = Date.now();
73950
+ const toolCallId = `mcp-${toolName}-${startTime}`;
73906
73951
  this.recordMcpEvent("tool.call_started", {
73907
73952
  toolName,
73908
73953
  serverName: tool6.serverName,
73909
73954
  originalToolName: tool6.originalName
73910
73955
  });
73956
+ if (this.agentEvents) {
73957
+ this.agentEvents.emit("toolCall", {
73958
+ toolCallId,
73959
+ name: toolName,
73960
+ args,
73961
+ status: "started",
73962
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
73963
+ });
73964
+ }
73911
73965
  try {
73912
73966
  if (this.debug) {
73913
73967
  console.error(`[MCP DEBUG] Calling ${toolName} with args:`, JSON.stringify(args, null, 2));
@@ -73937,6 +73991,14 @@ var init_client = __esm({
73937
73991
  originalToolName: tool6.originalName,
73938
73992
  durationMs
73939
73993
  });
73994
+ if (this.agentEvents) {
73995
+ this.agentEvents.emit("toolCall", {
73996
+ toolCallId,
73997
+ name: toolName,
73998
+ status: "completed",
73999
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
74000
+ });
74001
+ }
73940
74002
  return result;
73941
74003
  } catch (error40) {
73942
74004
  const durationMs = Date.now() - startTime;
@@ -73952,6 +74014,14 @@ var init_client = __esm({
73952
74014
  durationMs,
73953
74015
  isTimeout: error40.message.includes("timeout")
73954
74016
  });
74017
+ if (this.agentEvents) {
74018
+ this.agentEvents.emit("toolCall", {
74019
+ toolCallId,
74020
+ name: toolName,
74021
+ status: "error",
74022
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
74023
+ });
74024
+ }
73955
74025
  throw error40;
73956
74026
  }
73957
74027
  }
@@ -74137,6 +74207,7 @@ var init_xmlBridge = __esm({
74137
74207
  constructor(options = {}) {
74138
74208
  this.debug = options.debug || false;
74139
74209
  this.tracer = options.tracer || null;
74210
+ this.agentEvents = options.agentEvents || null;
74140
74211
  this.mcpTools = {};
74141
74212
  this.mcpManager = null;
74142
74213
  this.toolDescriptions = {};
@@ -74179,7 +74250,7 @@ var init_xmlBridge = __esm({
74179
74250
  if (this.debug) {
74180
74251
  console.error("[MCP DEBUG] Initializing MCP client manager...");
74181
74252
  }
74182
- this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer });
74253
+ this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer, agentEvents: this.agentEvents });
74183
74254
  const result = await this.mcpManager.initialize(mcpConfigs);
74184
74255
  const vercelTools = this.mcpManager.getVercelTools();
74185
74256
  this.mcpTools = vercelTools;
@@ -81626,7 +81697,7 @@ function deriveDescription(rawDescription, body) {
81626
81697
  }
81627
81698
  return truncateDescription(description);
81628
81699
  }
81629
- function stripFrontmatter(content) {
81700
+ function stripFrontmatter2(content) {
81630
81701
  const { body } = extractFrontmatter(content);
81631
81702
  return body.trim();
81632
81703
  }
@@ -81767,7 +81838,7 @@ var init_registry = __esm({
81767
81838
  const skill = this.skillsByName.get(name15);
81768
81839
  if (!skill) return null;
81769
81840
  const content = await (0, import_promises3.readFile)(skill.skillFilePath, "utf8");
81770
- return stripFrontmatter(content);
81841
+ return stripFrontmatter2(content);
81771
81842
  }
81772
81843
  async _resolveRealPath(target) {
81773
81844
  try {
@@ -98788,7 +98859,7 @@ var init_ProbeAgent = __esm({
98788
98859
  }
98789
98860
  mcpConfig = null;
98790
98861
  }
98791
- this.mcpBridge = new MCPXmlBridge({ debug: this.debug });
98862
+ this.mcpBridge = new MCPXmlBridge({ debug: this.debug, agentEvents: this.events });
98792
98863
  await this.mcpBridge.initialize(mcpConfig);
98793
98864
  const mcpToolNames = this.mcpBridge.getToolNames();
98794
98865
  const mcpToolCount = mcpToolNames.length;
@@ -99664,6 +99735,14 @@ or
99664
99735
  active_tools_count: activeToolsList.length
99665
99736
  });
99666
99737
  }
99738
+ this.events.emit("timeout.extended", {
99739
+ grantedMs,
99740
+ reason: decision.reason || "work in progress",
99741
+ extensionsUsed: negotiatedTimeoutState.extensionsUsed,
99742
+ extensionsRemaining: negotiatedTimeoutState.maxRequests - negotiatedTimeoutState.extensionsUsed,
99743
+ totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs,
99744
+ budgetRemainingMs: remainingBudgetMs - grantedMs
99745
+ });
99667
99746
  } else {
99668
99747
  if (this.debug) {
99669
99748
  console.log(`[DEBUG] Timeout observer: declined extension (reason: ${decision.reason}). Initiating graceful stop.`);
@@ -99677,6 +99756,11 @@ or
99677
99756
  active_tools: activeToolsList.map((t) => t.name)
99678
99757
  });
99679
99758
  }
99759
+ this.events.emit("timeout.windingDown", {
99760
+ reason: decision.reason || "observer declined",
99761
+ extensionsUsed: negotiatedTimeoutState.extensionsUsed,
99762
+ totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs
99763
+ });
99680
99764
  await this._initiateGracefulStop(gracefulTimeoutState, `observer declined: ${decision.reason}`);
99681
99765
  }
99682
99766
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc296",
3
+ "version": "0.6.0-rc298",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -81,7 +81,7 @@
81
81
  "@anthropic-ai/claude-agent-sdk": "^0.1.46",
82
82
  "@modelcontextprotocol/sdk": "^1.0.0",
83
83
  "@nyariv/sandboxjs": "github:probelabs/SandboxJS",
84
- "@probelabs/maid": "^0.0.27",
84
+ "@probelabs/maid": "^0.0.28",
85
85
  "acorn": "^8.15.0",
86
86
  "acorn-walk": "^8.3.4",
87
87
  "adm-zip": "^0.5.16",
@@ -118,6 +118,38 @@ export interface ProbeAgentOptions {
118
118
  negotiatedTimeoutMaxPerRequest?: number;
119
119
  }
120
120
 
121
+ /**
122
+ * Emitted when the negotiated timeout observer grants a time extension.
123
+ * Parent processes should listen to this event and extend their own deadlines accordingly.
124
+ */
125
+ export interface TimeoutExtendedEvent {
126
+ /** Duration of the granted extension in milliseconds */
127
+ grantedMs: number;
128
+ /** Reason the observer granted the extension */
129
+ reason: string;
130
+ /** Number of extensions used so far */
131
+ extensionsUsed: number;
132
+ /** Number of extensions remaining */
133
+ extensionsRemaining: number;
134
+ /** Total extra time granted across all extensions in ms */
135
+ totalExtraTimeMs: number;
136
+ /** Remaining budget for future extensions in ms */
137
+ budgetRemainingMs: number;
138
+ }
139
+
140
+ /**
141
+ * Emitted when the negotiated timeout observer declines an extension and begins wind-down.
142
+ * After this event, the agent will produce its final answer and no more extensions will be granted.
143
+ */
144
+ export interface TimeoutWindingDownEvent {
145
+ /** Reason the observer declined the extension */
146
+ reason: string;
147
+ /** Number of extensions used before declining */
148
+ extensionsUsed: number;
149
+ /** Total extra time granted across all extensions in ms */
150
+ totalExtraTimeMs: number;
151
+ }
152
+
121
153
  /**
122
154
  * Tool execution event data
123
155
  */
@@ -2759,7 +2759,7 @@ export class ProbeAgent {
2759
2759
  }
2760
2760
 
2761
2761
  // Initialize the MCP XML bridge
2762
- this.mcpBridge = new MCPXmlBridge({ debug: this.debug });
2762
+ this.mcpBridge = new MCPXmlBridge({ debug: this.debug, agentEvents: this.events });
2763
2763
  await this.mcpBridge.initialize(mcpConfig);
2764
2764
 
2765
2765
  const mcpToolNames = this.mcpBridge.getToolNames();
@@ -3847,6 +3847,18 @@ or
3847
3847
  active_tools_count: activeToolsList.length,
3848
3848
  });
3849
3849
  }
3850
+
3851
+ // Notify the parent that the agent extended its timeout (#522).
3852
+ // The parent can listen to this event and extend its own deadline
3853
+ // (e.g., adjust Promise.race timeout) instead of killing the agent.
3854
+ this.events.emit('timeout.extended', {
3855
+ grantedMs,
3856
+ reason: decision.reason || 'work in progress',
3857
+ extensionsUsed: negotiatedTimeoutState.extensionsUsed,
3858
+ extensionsRemaining: negotiatedTimeoutState.maxRequests - negotiatedTimeoutState.extensionsUsed,
3859
+ totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs,
3860
+ budgetRemainingMs: remainingBudgetMs - grantedMs,
3861
+ });
3850
3862
  } else {
3851
3863
  // Observer decided not to extend — two-phase graceful stop
3852
3864
  if (this.debug) {
@@ -3863,6 +3875,13 @@ or
3863
3875
  });
3864
3876
  }
3865
3877
 
3878
+ // Notify the parent that the agent is winding down — no more extensions (#522)
3879
+ this.events.emit('timeout.windingDown', {
3880
+ reason: decision.reason || 'observer declined',
3881
+ extensionsUsed: negotiatedTimeoutState.extensionsUsed,
3882
+ totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs,
3883
+ });
3884
+
3866
3885
  await this._initiateGracefulStop(gracefulTimeoutState, `observer declined: ${decision.reason}`);
3867
3886
  }
3868
3887
  };