Skip to content

Commit 3ba283b

Browse files
The extension should use MD fromat as well to lower the amount of complex serialize and deserialize the data
1 parent 0381211 commit 3ba283b

File tree

7 files changed

+224
-87
lines changed

7 files changed

+224
-87
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<PropertyGroup Label="Default Versioning">
3737
<!-- Default version for all projects (can be overridden per project) -->
3838
<VersionPrefix>1.1.0</VersionPrefix>
39-
<VersionSuffix>60</VersionSuffix>
39+
<VersionSuffix>61</VersionSuffix>
4040

4141
<!-- Calculated version -->
4242
<Version Condition="'$(Version)' == ''">$(VersionPrefix).$(VersionSuffix)</Version>

nexus_engine/nexus_engine_extensions/ExtensionScripts/basic_crash_analysis/basic_crash_analysis.ps1

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,47 @@ try {
5555

5656
Write-NexusLog "Basic crash analysis completed successfully (5 commands executed, 4 using async batching)" -Level Information
5757

58-
# Return structured result
59-
$result = @{
60-
success = $true
61-
workflow = "basic_crash_analysis"
62-
steps = @{
63-
automaticAnalysis = @{
64-
command = "!analyze -v"
65-
output = $results["analyze"]
66-
}
67-
threadInfo = @{
68-
command = "!threads"
69-
output = $results["threads"]
70-
}
71-
allThreadStacks = @{
72-
command = "~*k"
73-
output = $results["allStacks"]
74-
}
75-
locks = @{
76-
command = "!locks"
77-
output = $results["locks"]
78-
}
79-
cpuUsage = @{
80-
command = "!runaway"
81-
output = $results["runaway"]
82-
}
83-
}
84-
message = "Basic crash analysis completed successfully using async batching. Review the outputs to identify faulting thread, exception type, and crash context."
85-
} | ConvertTo-Json -Depth 10
86-
87-
Write-Output $result
58+
# Compose Markdown report
59+
$now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
60+
$md = @"
61+
## Basic Crash Analysis
62+
63+
**Workflow:** `basic_crash_analysis`
64+
**Executed:** $now
65+
66+
### !analyze -v
67+
68+
```
69+
$($results["analyze"])
70+
```
71+
72+
### !threads
73+
74+
```
75+
$($results["threads"])
76+
```
77+
78+
### ~*k
79+
80+
```
81+
$($results["allStacks"])
82+
```
83+
84+
### !locks
85+
86+
```
87+
$($results["locks"])
88+
```
89+
90+
### !runaway
91+
92+
```
93+
$($results["runaway"])
94+
```
95+
96+
"@
97+
98+
Write-Output $md
8899
exit 0
89100
}
90101
catch {

nexus_engine/nexus_engine_extensions/ExtensionScripts/stack_with_sources/stack_with_sources.ps1

Lines changed: 112 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,21 @@ try {
7878

7979
Write-NexusLog "[$threadDisplay] Thread not found or invalid (ThreadId: $ThreadId)" -Level Error
8080

81-
$result = @{
82-
success = $false
83-
threadId = $ThreadId
84-
totalFrames = 0
85-
sourcesDownloaded = 0
86-
addresses = @()
87-
error = "Thread '$ThreadId' not found. The thread ID may be invalid or the thread may not exist in this dump file."
88-
suggestion = "Use the '!threads' or '~' command to list available threads, then try again with a valid thread ID."
89-
stackTrace = $stackOutput
90-
} | ConvertTo-Json -Depth 10
91-
Write-Output $result
81+
$md = @"
82+
## Stack With Sources
83+
84+
**Success:** False
85+
**Thread ID:** `$ThreadId`
86+
**Message:** Thread '$ThreadId' not found. The thread ID may be invalid or may not exist in this dump.
87+
**Suggestion:** Use `!threads` or `~` to list available threads, then retry with a valid thread ID.
88+
89+
### Stack Trace
90+
91+
```
92+
$stackOutput
93+
```
94+
"@
95+
Write-Output $md
9296
exit 0
9397
}
9498

@@ -116,16 +120,20 @@ try {
116120

117121
if ($addresses.Count -eq 0) {
118122
Write-NexusLog "No valid return addresses found in stack trace" -Level Warning
119-
$result = @{
120-
success = $false
121-
threadId = $ThreadId
122-
totalFrames = 0
123-
sourcesDownloaded = 0
124-
addresses = @()
125-
error = "No valid return addresses found in stack trace"
126-
stackTrace = $stackOutput
127-
} | ConvertTo-Json -Depth 10
128-
Write-Output $result
123+
$md = @"
124+
## Stack With Sources
125+
126+
**Success:** False
127+
**Thread ID:** `$ThreadId`
128+
**Message:** No valid return addresses found in stack trace
129+
130+
### Stack Trace
131+
132+
```
133+
$stackOutput
134+
```
135+
"@
136+
Write-Output $md
129137
exit 0
130138
}
131139

@@ -161,21 +169,31 @@ try {
161169

162170
if ($addressesWithSymbols.Count -eq 0) {
163171
Write-NexusLog "No addresses with symbols found to download sources for" -Level Warning
164-
$result = @{
165-
success = $true
166-
threadId = $ThreadId
167-
totalFrames = $addresses.Count
168-
framesWithSymbols = 0
169-
sourcesDownloaded = 0
170-
sourcesMissing = 0
171-
successRate = 0
172-
addresses = $addresses
173-
failedAddresses = @()
174-
message = "No addresses with symbols found, nothing to download"
175-
stackTrace = $stackOutput
176-
sourceOutputs = @{}
177-
} | ConvertTo-Json -Depth 10
178-
Write-Output $result
172+
$addrList = ($addresses -join "\n")
173+
$md = @"
174+
## Stack With Sources
175+
176+
**Success:** True
177+
**Thread ID:** `$ThreadId`
178+
**Total Frames:** $($addresses.Count)
179+
**Frames With Symbols:** 0
180+
**Sources Downloaded:** 0
181+
**Success Rate:** 0%
182+
**Message:** No addresses with symbols found, nothing to download
183+
184+
### Stack Trace
185+
186+
```
187+
$stackOutput
188+
```
189+
190+
### Addresses (All)
191+
192+
```
193+
$addrList
194+
```
195+
"@
196+
Write-Output $md
179197
exit 0
180198
}
181199

@@ -232,24 +250,64 @@ try {
232250
Write-NexusLog "Failed to download sources for $($failedAddresses.Count) addresses" -Level Warning
233251
}
234252

235-
# Return structured result with all command outputs
236-
$result = @{
237-
success = $true
238-
threadId = $ThreadId
239-
totalFrames = $addresses.Count
240-
framesWithSymbols = $addressesWithSymbols.Count
241-
sourcesDownloaded = $downloadedCount
242-
sourcesMissing = $failedAddresses.Count
243-
successRate = $successRate
244-
addresses = $addresses
245-
addressesWithSymbols = $addressesWithSymbols
246-
failedAddresses = $failedAddresses
247-
message = "Successfully downloaded and verified $downloadedCount of $($addressesWithSymbols.Count) source files (filtered from $($addresses.Count) total addresses)"
248-
stackTrace = $stackOutput
249-
sourceOutputs = $sourceOutputs
250-
} | ConvertTo-Json -Depth 10
251-
252-
Write-Output $result
253+
# Compose Markdown report with summary and outputs
254+
$now = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
255+
$addrAll = ($addresses -join "\n")
256+
$addrWithSymbols = ($addressesWithSymbols -join "\n")
257+
$failedList = ($failedAddresses -join "\n")
258+
259+
# Flatten sourceOutputs into a readable section
260+
$sourceOutputsText = New-Object System.Text.StringBuilder
261+
foreach ($kv in $sourceOutputs.GetEnumerator()) {
262+
[void]$sourceOutputsText.AppendLine("[$($kv.Key)]")
263+
[void]$sourceOutputsText.AppendLine($kv.Value)
264+
[void]$sourceOutputsText.AppendLine()
265+
}
266+
267+
$md = @"
268+
## Stack With Sources
269+
270+
**Success:** True
271+
**Thread ID:** `$ThreadId`
272+
**Executed:** $now
273+
**Total Frames:** $($addresses.Count)
274+
**Frames With Symbols:** $($addressesWithSymbols.Count)
275+
**Sources Downloaded:** $downloadedCount
276+
**Sources Missing:** $($failedAddresses.Count)
277+
**Success Rate:** $successRate%
278+
279+
### Stack Trace
280+
281+
```
282+
$stackOutput
283+
```
284+
285+
### Addresses With Symbols
286+
287+
```
288+
$addrWithSymbols
289+
```
290+
291+
### Failed Addresses
292+
293+
```
294+
$failedList
295+
```
296+
297+
### All Addresses
298+
299+
```
300+
$addrAll
301+
```
302+
303+
### Source Verification Outputs
304+
305+
```
306+
$($sourceOutputsText.ToString())
307+
```
308+
"@
309+
310+
Write-Output $md
253311
exit 0
254312
}
255313
catch {

nexus_protocol/Middleware/JsonRpcLoggingMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal class JsonRpcLoggingMiddleware
1515
{
1616
private readonly RequestDelegate m_Next;
1717
private readonly Logger m_Logger;
18-
private const int MaxLength = 500;
18+
private const int MaxLength = 1500;
1919

2020
/// <summary>
2121
/// Initializes a new instance of the <see cref="JsonRpcLoggingMiddleware"/> class.

nexus_protocol/Tools/ReadDumpAnalyzeCommandResultTool.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public static async Task<object> nexus_read_dump_analyze_command_result(
5151

5252
if (!string.IsNullOrEmpty(commandInfo.AggregatedOutput))
5353
{
54-
markdown += MarkdownFormatter.CreateCodeBlock(commandInfo.AggregatedOutput, "Output");
54+
markdown += MarkdownFormatter.AppendOutputForCommand(commandInfo.Command, commandInfo.AggregatedOutput, "Output");
5555
}
5656

5757
if (!string.IsNullOrEmpty(commandInfo.ErrorMessage))

nexus_protocol/Utilities/MarkdownFormatter.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,27 @@ public static string CreateOperationResult(
440440
return markdown.ToString();
441441
}
442442

443+
/// <summary>
444+
/// Appends command output according to its origin. For extension commands (prefix "Extension: "),
445+
/// returns the output verbatim (expected to be Markdown). For all other commands, wraps output
446+
/// in a code block with an optional title.
447+
/// </summary>
448+
/// <param name="command">The command label as stored in command info.</param>
449+
/// <param name="output">The raw output to append.</param>
450+
/// <param name="titleForNonExtension">Optional title when wrapping non-extension output.</param>
451+
/// <returns>Markdown to append for the given output.</returns>
452+
public static string AppendOutputForCommand(string? command, string? output, string? titleForNonExtension = "Output")
453+
{
454+
if (string.IsNullOrEmpty(output))
455+
{
456+
return string.Empty;
457+
}
458+
459+
return !string.IsNullOrEmpty(command) && command.StartsWith("Extension: ", StringComparison.Ordinal)
460+
? output
461+
: CreateCodeBlock(output, titleForNonExtension);
462+
}
463+
443464
/// <summary>
444465
/// Helper method to get property value from anonymous object.
445466
/// </summary>
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using FluentAssertions;
2+
3+
using Nexus.Protocol.Utilities;
4+
5+
using Xunit;
6+
7+
namespace Nexus.Protocol.Tests.Tools;
8+
9+
/// <summary>
10+
/// Tests for output wrapping decision for extension vs non-extension commands.
11+
/// </summary>
12+
public class ReadDumpAnalyzeCommandResultToolTests
13+
{
14+
/// <inheritdoc/>
15+
[Fact]
16+
public void AppendOutputForCommand_NonExtension_WrapsInCodeBlock()
17+
{
18+
// Arrange
19+
var command = "!threads";
20+
var output = "line1\nline2";
21+
22+
// Act
23+
var result = MarkdownFormatter.AppendOutputForCommand(command, output, "Output");
24+
25+
// Assert
26+
_ = result.Should().Contain("```");
27+
_ = result.Should().Contain("line1");
28+
_ = result.Should().Contain("line2");
29+
}
30+
31+
/// <inheritdoc/>
32+
[Fact]
33+
public void AppendOutputForCommand_Extension_ReturnsVerbatim()
34+
{
35+
// Arrange
36+
var command = "Extension: basic_crash_analysis";
37+
var output = "## Some Markdown\n\n``\ncode\n``".Replace("``", "```");
38+
39+
// Act
40+
var result = MarkdownFormatter.AppendOutputForCommand(command, output, "Output");
41+
42+
// Assert
43+
_ = result.Should().Be(output);
44+
}
45+
}
46+
47+

0 commit comments

Comments
 (0)