@probelabs/probe 0.6.0-rc291 → 0.6.0-rc293

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.
@@ -27566,7 +27566,7 @@ var init_vercel = __esm({
27566
27566
  name: "search",
27567
27567
  description: searchDelegate ? searchDelegateDescription : searchDescription,
27568
27568
  inputSchema: searchSchema,
27569
- execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language, session, nextPage }) => {
27569
+ execute: async ({ query: searchQuery, path: path9, allow_tests, exact, maxTokens: paramMaxTokens, language, session, nextPage, workingDirectory }) => {
27570
27570
  if (!exact && searchQuery) {
27571
27571
  const originalQuery = searchQuery;
27572
27572
  searchQuery = autoQuoteSearchTerms(searchQuery);
@@ -27575,18 +27575,19 @@ var init_vercel = __esm({
27575
27575
  }
27576
27576
  }
27577
27577
  const effectiveMaxTokens = paramMaxTokens || maxTokens;
27578
+ const effectiveSearchCwd = workingDirectory || options.cwd || ".";
27578
27579
  let searchPaths;
27579
27580
  if (path9) {
27580
- searchPaths = parseAndResolvePaths(path9, options.cwd);
27581
+ searchPaths = parseAndResolvePaths(path9, effectiveSearchCwd);
27581
27582
  }
27582
27583
  if (!searchPaths || searchPaths.length === 0) {
27583
- searchPaths = [options.cwd || "."];
27584
+ searchPaths = [effectiveSearchCwd];
27584
27585
  }
27585
27586
  const searchPath = searchPaths.join(" ");
27586
27587
  const searchOptions = {
27587
27588
  query: searchQuery,
27588
27589
  path: searchPath,
27589
- cwd: options.cwd,
27590
+ cwd: effectiveSearchCwd,
27590
27591
  // Working directory for resolving relative paths
27591
27592
  allowTests: allow_tests ?? true,
27592
27593
  exact,
@@ -27637,7 +27638,7 @@ var init_vercel = __esm({
27637
27638
  try {
27638
27639
  const result = maybeAnnotate(await runRawSearch());
27639
27640
  if (options.fileTracker && typeof result === "string") {
27640
- options.fileTracker.trackFilesFromOutput(result, options.cwd || ".").catch(() => {
27641
+ options.fileTracker.trackFilesFromOutput(result, effectiveSearchCwd).catch(() => {
27641
27642
  });
27642
27643
  }
27643
27644
  return result;
@@ -27690,7 +27691,7 @@ var init_vercel = __esm({
27690
27691
  }
27691
27692
  const fallbackResult = maybeAnnotate(await runRawSearch());
27692
27693
  if (options.fileTracker && typeof fallbackResult === "string") {
27693
- options.fileTracker.trackFilesFromOutput(fallbackResult, options.cwd || ".").catch(() => {
27694
+ options.fileTracker.trackFilesFromOutput(fallbackResult, effectiveSearchCwd).catch(() => {
27694
27695
  });
27695
27696
  }
27696
27697
  return fallbackResult;
@@ -27753,7 +27754,7 @@ var init_vercel = __esm({
27753
27754
  try {
27754
27755
  const fallbackResult2 = maybeAnnotate(await runRawSearch());
27755
27756
  if (options.fileTracker && typeof fallbackResult2 === "string") {
27756
- options.fileTracker.trackFilesFromOutput(fallbackResult2, options.cwd || ".").catch(() => {
27757
+ options.fileTracker.trackFilesFromOutput(fallbackResult2, effectiveSearchCwd).catch(() => {
27757
27758
  });
27758
27759
  }
27759
27760
  return fallbackResult2;
@@ -27807,9 +27808,9 @@ var init_vercel = __esm({
27807
27808
  name: "extract",
27808
27809
  description: extractDescription,
27809
27810
  inputSchema: extractSchema,
27810
- execute: async ({ targets, input_content, line, end_line, allow_tests, context_lines, format }) => {
27811
+ execute: async ({ targets, input_content, line, end_line, allow_tests, context_lines, format, workingDirectory }) => {
27811
27812
  try {
27812
- const effectiveCwd = options.cwd || ".";
27813
+ const effectiveCwd = workingDirectory || options.cwd || ".";
27813
27814
  if (debug) {
27814
27815
  if (targets) {
27815
27816
  console.error(`Executing extract with targets: "${targets}", cwd: "${effectiveCwd}", context lines: ${context_lines || 10}`);
@@ -29908,7 +29909,14 @@ function lineTrimmedMatch(contentLines, searchLines) {
29908
29909
  }
29909
29910
  }
29910
29911
  if (allMatch) {
29911
- const matchedText = contentLines.slice(i, i + windowSize).join("\n");
29912
+ const windowLines = contentLines.slice(i, i + windowSize);
29913
+ const windowMinIndent = getMinIndent(windowLines);
29914
+ const searchMinIndent = getMinIndent(searchLines);
29915
+ const indentDiff = Math.abs(windowMinIndent - searchMinIndent);
29916
+ if (isIndentDiffTooLarge(windowLines, searchLines, indentDiff)) {
29917
+ continue;
29918
+ }
29919
+ const matchedText = windowLines.join("\n");
29912
29920
  matches.push(matchedText);
29913
29921
  }
29914
29922
  }
@@ -29938,6 +29946,15 @@ function whitespaceNormalizedMatch(content, search2) {
29938
29946
  actualEnd++;
29939
29947
  }
29940
29948
  const matchedText = content.substring(originalStart, actualEnd);
29949
+ const matchedLines = matchedText.split("\n");
29950
+ const searchLines = search2.split("\n");
29951
+ const matchMinIndent = getMinIndent(matchedLines);
29952
+ const searchMinIndent = getMinIndent(searchLines);
29953
+ const indentDiff = Math.abs(matchMinIndent - searchMinIndent);
29954
+ if (isIndentDiffTooLarge(matchedLines, searchLines, indentDiff)) {
29955
+ searchStart = idx + 1;
29956
+ continue;
29957
+ }
29941
29958
  matches.push(matchedText);
29942
29959
  searchStart = idx + 1;
29943
29960
  }
@@ -29989,6 +30006,10 @@ function indentFlexibleMatch(contentLines, searchLines) {
29989
30006
  }
29990
30007
  }
29991
30008
  if (allMatch) {
30009
+ const indentDiff = Math.abs(windowMinIndent - searchMinIndent);
30010
+ if (isIndentDiffTooLarge(windowLines, searchLines, indentDiff)) {
30011
+ continue;
30012
+ }
29992
30013
  const matchedText = windowLines.join("\n");
29993
30014
  matches.push(matchedText);
29994
30015
  }
@@ -29999,6 +30020,14 @@ function indentFlexibleMatch(contentLines, searchLines) {
29999
30020
  count: matches.length
30000
30021
  };
30001
30022
  }
30023
+ function isIndentDiffTooLarge(linesA, linesB, indentDiff) {
30024
+ if (indentDiff <= 0) return false;
30025
+ const sampleA = linesA.find((l) => l.trim().length > 0) || "";
30026
+ const sampleB = linesB.find((l) => l.trim().length > 0) || "";
30027
+ const useTabs = sampleA.startsWith(" ") || sampleB.startsWith(" ");
30028
+ const maxAllowedDiff = useTabs ? 1 : 4;
30029
+ return indentDiff > maxAllowedDiff;
30030
+ }
30002
30031
  function getMinIndent(lines) {
30003
30032
  let min = Infinity;
30004
30033
  for (const line of lines) {
@@ -30158,6 +30187,12 @@ function restoreIndentation(newStr, originalLines) {
30158
30187
  const targetIndent = detectBaseIndent(originalCode);
30159
30188
  const newIndent = detectBaseIndent(newStr);
30160
30189
  if (targetIndent !== newIndent) {
30190
+ const indentDiff = Math.abs(targetIndent.length - newIndent.length);
30191
+ const useTabs = targetIndent.includes(" ") || newIndent.includes(" ");
30192
+ const maxAllowedDiff = useTabs ? 1 : 4;
30193
+ if (indentDiff > maxAllowedDiff) {
30194
+ return { result: newStr, modifications };
30195
+ }
30161
30196
  const reindented = reindent(newStr, targetIndent);
30162
30197
  if (reindented !== newStr) {
30163
30198
  modifications.push(`reindented from "${newIndent}" to "${targetIndent}"`);
@@ -40531,7 +40566,12 @@ function generateSandboxGlobals(options) {
40531
40566
  }
40532
40567
  return tryParseJSONValue(text);
40533
40568
  };
40534
- globals[name15] = traceToolCall(name15, rawMcpFn, tracer, logFn);
40569
+ const tracedFn = traceToolCall(name15, rawMcpFn, tracer, logFn);
40570
+ globals[name15] = tracedFn;
40571
+ const sanitized = name15.replace(/[^a-zA-Z0-9_$]/g, "_");
40572
+ if (sanitized !== name15) {
40573
+ globals[sanitized] = tracedFn;
40574
+ }
40535
40575
  }
40536
40576
  }
40537
40577
  if (llmCall) {
@@ -40886,9 +40926,17 @@ ${validation.errors.join("\n")}`,
40886
40926
  "dsl.duration_ms": elapsed,
40887
40927
  "dsl.error": e.message?.substring(0, 500)
40888
40928
  });
40929
+ let errorMsg = `Execution failed: ${e.message}`;
40930
+ if (e.message && e.message.includes("is not defined")) {
40931
+ const globalNames = Object.keys(toolGlobals).sort();
40932
+ errorMsg += `
40933
+ Available functions: ${globalNames.join(", ")}`;
40934
+ errorMsg += `
40935
+ Note: Tools with hyphens (e.g. "my-tool") are available with underscores: my_tool()`;
40936
+ }
40889
40937
  return {
40890
40938
  status: "error",
40891
- error: `Execution failed: ${e.message}`,
40939
+ error: errorMsg,
40892
40940
  logs
40893
40941
  };
40894
40942
  }
@@ -48591,6 +48639,10 @@ var init_file_lister = __esm({
48591
48639
  });
48592
48640
 
48593
48641
  // src/tools/fileTracker.js
48642
+ function normalizePath(filePath) {
48643
+ if (!filePath) return filePath;
48644
+ return (0, import_path10.resolve)(filePath);
48645
+ }
48594
48646
  function computeContentHash(content) {
48595
48647
  const normalized = (content || "").split("\n").map((l) => l.trimEnd()).join("\n");
48596
48648
  return (0, import_crypto3.createHash)("sha256").update(normalized).digest("hex").slice(0, 16);
@@ -48653,10 +48705,11 @@ var init_fileTracker = __esm({
48653
48705
  * @param {string} resolvedPath - Absolute path to the file
48654
48706
  */
48655
48707
  markFileSeen(resolvedPath) {
48656
- this._seenFiles.add(resolvedPath);
48657
- this._textEditCounts.set(resolvedPath, 0);
48708
+ const normalized = normalizePath(resolvedPath);
48709
+ this._seenFiles.add(normalized);
48710
+ this._textEditCounts.set(normalized, 0);
48658
48711
  if (this.debug) {
48659
- console.error(`[FileTracker] Marked as seen: ${resolvedPath}`);
48712
+ console.error(`[FileTracker] Marked as seen: ${normalized}`);
48660
48713
  }
48661
48714
  }
48662
48715
  /**
@@ -48665,7 +48718,7 @@ var init_fileTracker = __esm({
48665
48718
  * @returns {boolean}
48666
48719
  */
48667
48720
  isFileSeen(resolvedPath) {
48668
- return this._seenFiles.has(resolvedPath);
48721
+ return this._seenFiles.has(normalizePath(resolvedPath));
48669
48722
  }
48670
48723
  /**
48671
48724
  * Store a content hash for a symbol in a file.
@@ -48677,7 +48730,7 @@ var init_fileTracker = __esm({
48677
48730
  * @param {string} [source='extract'] - How the content was obtained
48678
48731
  */
48679
48732
  trackSymbolContent(resolvedPath, symbolName, code, startLine, endLine, source = "extract") {
48680
- const key = `${resolvedPath}#${symbolName}`;
48733
+ const key = `${normalizePath(resolvedPath)}#${symbolName}`;
48681
48734
  const contentHash = computeContentHash(code);
48682
48735
  this._contentRecords.set(key, {
48683
48736
  contentHash,
@@ -48698,7 +48751,7 @@ var init_fileTracker = __esm({
48698
48751
  * @returns {Object|null} The stored record or null
48699
48752
  */
48700
48753
  getSymbolRecord(resolvedPath, symbolName) {
48701
- return this._contentRecords.get(`${resolvedPath}#${symbolName}`) || null;
48754
+ return this._contentRecords.get(`${normalizePath(resolvedPath)}#${symbolName}`) || null;
48702
48755
  }
48703
48756
  /**
48704
48757
  * Check if a symbol's current content matches what was stored.
@@ -48708,7 +48761,7 @@ var init_fileTracker = __esm({
48708
48761
  * @returns {{ok: boolean, reason?: string, message?: string}}
48709
48762
  */
48710
48763
  checkSymbolContent(resolvedPath, symbolName, currentCode) {
48711
- const key = `${resolvedPath}#${symbolName}`;
48764
+ const key = `${normalizePath(resolvedPath)}#${symbolName}`;
48712
48765
  const record2 = this._contentRecords.get(key);
48713
48766
  if (!record2) {
48714
48767
  return { ok: true };
@@ -48785,7 +48838,7 @@ var init_fileTracker = __esm({
48785
48838
  * @returns {{ok: boolean, reason?: string, message?: string}}
48786
48839
  */
48787
48840
  checkBeforeEdit(resolvedPath) {
48788
- if (!this._seenFiles.has(resolvedPath)) {
48841
+ if (!this._seenFiles.has(normalizePath(resolvedPath))) {
48789
48842
  return {
48790
48843
  ok: false,
48791
48844
  reason: "untracked",
@@ -48800,8 +48853,9 @@ var init_fileTracker = __esm({
48800
48853
  * @param {string} resolvedPath - Absolute path to the file
48801
48854
  */
48802
48855
  async trackFileAfterWrite(resolvedPath) {
48803
- this._seenFiles.add(resolvedPath);
48804
- this.invalidateFileRecords(resolvedPath);
48856
+ const normalized = normalizePath(resolvedPath);
48857
+ this._seenFiles.add(normalized);
48858
+ this.invalidateFileRecords(normalized);
48805
48859
  }
48806
48860
  /**
48807
48861
  * Record a text-mode edit (old_string/new_string) to a file.
@@ -48809,10 +48863,11 @@ var init_fileTracker = __esm({
48809
48863
  * @param {string} resolvedPath - Absolute path to the file
48810
48864
  */
48811
48865
  recordTextEdit(resolvedPath) {
48812
- const count = (this._textEditCounts.get(resolvedPath) || 0) + 1;
48813
- this._textEditCounts.set(resolvedPath, count);
48866
+ const normalized = normalizePath(resolvedPath);
48867
+ const count = (this._textEditCounts.get(normalized) || 0) + 1;
48868
+ this._textEditCounts.set(normalized, count);
48814
48869
  if (this.debug) {
48815
- console.error(`[FileTracker] Text edit #${count} for ${resolvedPath}`);
48870
+ console.error(`[FileTracker] Text edit #${count} for ${normalized}`);
48816
48871
  }
48817
48872
  }
48818
48873
  /**
@@ -48821,7 +48876,7 @@ var init_fileTracker = __esm({
48821
48876
  * @returns {{ok: boolean, editCount?: number, message?: string}}
48822
48877
  */
48823
48878
  checkTextEditStaleness(resolvedPath) {
48824
- const count = this._textEditCounts.get(resolvedPath) || 0;
48879
+ const count = this._textEditCounts.get(normalizePath(resolvedPath)) || 0;
48825
48880
  if (count >= this.maxConsecutiveTextEdits) {
48826
48881
  return {
48827
48882
  ok: false,
@@ -48850,7 +48905,7 @@ var init_fileTracker = __esm({
48850
48905
  * @param {string} resolvedPath - Absolute path to the file
48851
48906
  */
48852
48907
  invalidateFileRecords(resolvedPath) {
48853
- const prefix = resolvedPath + "#";
48908
+ const prefix = normalizePath(resolvedPath) + "#";
48854
48909
  for (const key of this._contentRecords.keys()) {
48855
48910
  if (key.startsWith(prefix)) {
48856
48911
  this._contentRecords.delete(key);
@@ -48866,7 +48921,7 @@ var init_fileTracker = __esm({
48866
48921
  * @returns {boolean}
48867
48922
  */
48868
48923
  isTracked(resolvedPath) {
48869
- return this.isFileSeen(resolvedPath);
48924
+ return this.isFileSeen(normalizePath(resolvedPath));
48870
48925
  }
48871
48926
  /**
48872
48927
  * Clear all tracking state.
@@ -68979,7 +69034,7 @@ var init_graph_builder = __esm({
68979
69034
  applyLinkStyles() {
68980
69035
  if (!this.pendingLinkStyles.length || !this.edges.length)
68981
69036
  return;
68982
- const normalize3 = (s) => {
69037
+ const normalize4 = (s) => {
68983
69038
  const out = {};
68984
69039
  for (const [kRaw, vRaw] of Object.entries(s)) {
68985
69040
  const k = kRaw.trim().toLowerCase();
@@ -69000,7 +69055,7 @@ var init_graph_builder = __esm({
69000
69055
  return out;
69001
69056
  };
69002
69057
  for (const cmd of this.pendingLinkStyles) {
69003
- const style = normalize3(cmd.props);
69058
+ const style = normalize4(cmd.props);
69004
69059
  for (const idx of cmd.indices) {
69005
69060
  if (idx >= 0 && idx < this.edges.length) {
69006
69061
  const e = this.edges[idx];
@@ -76267,7 +76322,7 @@ var require_layout = __commonJS({
76267
76322
  "use strict";
76268
76323
  var _ = require_lodash2();
76269
76324
  var acyclic = require_acyclic();
76270
- var normalize3 = require_normalize();
76325
+ var normalize4 = require_normalize();
76271
76326
  var rank = require_rank();
76272
76327
  var normalizeRanks = require_util().normalizeRanks;
76273
76328
  var parentDummyChains = require_parent_dummy_chains();
@@ -76329,7 +76384,7 @@ var require_layout = __commonJS({
76329
76384
  removeEdgeLabelProxies(g);
76330
76385
  });
76331
76386
  time3(" normalize.run", function() {
76332
- normalize3.run(g);
76387
+ normalize4.run(g);
76333
76388
  });
76334
76389
  time3(" parentDummyChains", function() {
76335
76390
  parentDummyChains(g);
@@ -76356,7 +76411,7 @@ var require_layout = __commonJS({
76356
76411
  removeBorderNodes(g);
76357
76412
  });
76358
76413
  time3(" normalize.undo", function() {
76359
- normalize3.undo(g);
76414
+ normalize4.undo(g);
76360
76415
  });
76361
76416
  time3(" fixupEdgeLabelCoords", function() {
76362
76417
  fixupEdgeLabelCoords(g);
@@ -82727,8 +82782,8 @@ var require_resolve = __commonJS({
82727
82782
  }
82728
82783
  return count;
82729
82784
  }
82730
- function getFullPath(resolver, id = "", normalize3) {
82731
- if (normalize3 !== false)
82785
+ function getFullPath(resolver, id = "", normalize4) {
82786
+ if (normalize4 !== false)
82732
82787
  id = normalizeId(id);
82733
82788
  const p = resolver.parse(id);
82734
82789
  return _getFullPath(resolver, p);
@@ -84068,7 +84123,7 @@ var require_fast_uri = __commonJS({
84068
84123
  "use strict";
84069
84124
  var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils2();
84070
84125
  var { SCHEMES, getSchemeHandler } = require_schemes();
84071
- function normalize3(uri, options) {
84126
+ function normalize4(uri, options) {
84072
84127
  if (typeof uri === "string") {
84073
84128
  uri = /** @type {T} */
84074
84129
  serialize(parse11(uri, options), options);
@@ -84304,7 +84359,7 @@ var require_fast_uri = __commonJS({
84304
84359
  }
84305
84360
  var fastUri = {
84306
84361
  SCHEMES,
84307
- normalize: normalize3,
84362
+ normalize: normalize4,
84308
84363
  resolve: resolve9,
84309
84364
  resolveComponent,
84310
84365
  equal,
@@ -88511,9 +88566,9 @@ If the solution is clear, you can jump to implementation right away. If not, ask
88511
88566
  - Do not add code comments unless the logic is genuinely complex and non-obvious.
88512
88567
 
88513
88568
  # Before Implementation
88514
- - Focus on high-level design patterns and system organization
88515
- - Identify architectural patterns and component relationships
88516
- - Evaluate system structure and suggest architectural improvements
88569
+ - Read tests first \u2014 find existing test files for the module you're changing. They reveal expected behavior, edge cases, and the project's testing patterns.
88570
+ - Read neighboring files \u2014 understand naming conventions, error handling patterns, import style, and existing utilities before creating new ones.
88571
+ - Trace the call chain \u2014 follow how the code you're changing is called and what depends on it. Check interfaces, types, and consumers.
88517
88572
  - Focus on backward compatibility
88518
88573
  - Consider scalability, maintainability, and extensibility in your analysis
88519
88574
 
@@ -88538,6 +88593,20 @@ Before building or testing, determine the project's toolchain:
88538
88593
  - Read README for build/test instructions if the above are unclear
88539
88594
  - Common patterns: \`make build\`/\`make test\`, \`npm run build\`/\`npm test\`, \`cargo build\`/\`cargo test\`, \`go build ./...\`/\`go test ./...\`, \`python -m pytest\`
88540
88595
 
88596
+ # File Editing Rules
88597
+ You have access to the \`edit\`, \`create\`, and \`multi_edit\` tools for modifying files. You MUST use these tools for ALL code changes. They are purpose-built, atomic, and safe.
88598
+
88599
+ DO NOT use sed, awk, echo/cat redirection, or heredocs to modify source code. These commands cause real damage in practice: truncated lines, duplicate code blocks, broken syntax. Every bad edit wastes iterations on fix-up commits.
88600
+
88601
+ Use the right tool:
88602
+ 1. To MODIFY existing code \u2192 \`edit\` tool (old_string \u2192 new_string, or start_line/end_line)
88603
+ 2. To CREATE a new file \u2192 \`create\` tool
88604
+ 3. To CHANGE multiple files at once \u2192 \`multi_edit\` tool
88605
+ 4. To READ code \u2192 \`extract\` or \`search\` tools
88606
+ 5. If \`edit\` fails with "file has not been read yet" \u2192 use \`extract\` with the EXACT same file path you will pass to \`edit\`. Relative vs absolute path mismatch causes this error. Use the same path format consistently. If it still fails, use bash \`cat\` to read the file, then use \`create\` to write the entire modified file. Do NOT fall back to sed.
88607
+
88608
+ Bash is fine for: formatters (gofmt, prettier, black), build/test/lint commands, git operations, and read-only file inspection (cat, head, tail). sed/awk should ONLY be used for trivial non-code tasks (e.g., config file tweaks) where the replacement is a simple literal string swap.
88609
+
88541
88610
  # During Implementation
88542
88611
  - Always create a new branch before making changes to the codebase.
88543
88612
  - Fix problems at the root cause, not with surface-level patches. Prefer general solutions over special cases.
@@ -88564,6 +88633,22 @@ Before committing or creating a PR, run through this checklist:
88564
88633
 
88565
88634
  Do NOT skip verification. Do NOT proceed to PR creation with a broken build or failing tests.
88566
88635
 
88636
+ # Output Integrity
88637
+ Your final output MUST accurately reflect what ACTUALLY happened. Do NOT fabricate, hallucinate, or report aspirational results.
88638
+
88639
+ - Only report PR URLs you actually created or updated with \`gh pr create\` or \`git push\`. If you checked out an existing PR but did NOT push changes to it, do NOT claim you updated it.
88640
+ - Describe what you ACTUALLY DID, not what you planned or intended to do. If you ran out of iterations, say so. If tests failed, say so.
88641
+ - Only list files you actually modified AND committed.
88642
+ - If you could not complete the task \u2014 ran out of iterations, tests failed, build broken, push rejected \u2014 report the real reason honestly.
88643
+
88644
+ NEVER claim success when:
88645
+ - You did not run \`git push\` successfully
88646
+ - Tests failed and you did not fix them
88647
+ - You hit the iteration limit before completing the work
88648
+ - You only analyzed/investigated but did not implement changes
88649
+
88650
+ A false success report is WORSE than an honest failure \u2014 it misleads the user into thinking work is done when it is not.
88651
+
88567
88652
  # GitHub Integration
88568
88653
  - Use the \`gh\` CLI for all GitHub operations: issues, pull requests, checks, releases.
88569
88654
  - To view issues or PRs: \`gh issue view <number>\`, \`gh pr view <number>\`.