@@ -6,7 +6,6 @@ import type { ToolContext } from "@opencode-ai/plugin";
66import {
77 createInspectTier2IdleScheduler ,
88 inspectTools ,
9- renderInspectDiagnostics ,
109 shouldRegisterInspectTool ,
1110} from "../tools/inspect.js" ;
1211import type { PluginContext } from "../types.js" ;
@@ -18,6 +17,12 @@ type SendCall = {
1817 params : Record < string , unknown > ;
1918 options ?: Record < string , unknown > ;
2019} ;
20+ type ToolCallCall = {
21+ sessionId : string | undefined ;
22+ name : string ;
23+ rawArgs : Record < string , unknown > ;
24+ options ?: Record < string , unknown > ;
25+ } ;
2126
2227type CapturedTimer = {
2328 callback : ( ) => void ;
@@ -66,6 +71,7 @@ function createInspectHarness(
6671 ) => Promise < BridgeResponse > | BridgeResponse ,
6772) {
6873 const sendCalls : SendCall [ ] = [ ] ;
74+ const toolCallCalls : ToolCallCall [ ] = [ ] ;
6975 const localBridge = {
7076 send : async (
7177 command : string ,
@@ -75,12 +81,22 @@ function createInspectHarness(
7581 sendCalls . push ( { command, params, options } ) ;
7682 return await sendImpl ( command , params ) ;
7783 } ,
84+ toolCall : async (
85+ sessionId : string | undefined ,
86+ name : string ,
87+ rawArgs : Record < string , unknown > = { } ,
88+ options ?: Record < string , unknown > ,
89+ ) => {
90+ toolCallCalls . push ( { sessionId, name, rawArgs, options } ) ;
91+ return await sendImpl ( name , rawArgs ) ;
92+ } ,
7893 } ;
7994 const pool = {
8095 getBridge : ( ) => localBridge ,
8196 } as unknown as BridgePool ;
8297 return {
8398 sendCalls,
99+ toolCallCalls,
84100 tools : inspectTools ( createPluginContext ( pool , { } ) ) ,
85101 } ;
86102}
@@ -101,21 +117,25 @@ describe("aft_inspect tool", () => {
101117 } ) ;
102118
103119 test ( "sends corrected inspect field names to the bridge" , async ( ) => {
104- const { sendCalls, tools } = createInspectHarness ( ( ) => ( { success : true , summary : { } } ) ) ;
120+ const { sendCalls, toolCallCalls, tools } = createInspectHarness ( ( ) => ( {
121+ success : true ,
122+ text : "ok" ,
123+ } ) ) ;
105124
106125 await tools . aft_inspect . execute (
107126 { sections : [ "todos" , "dead_code" ] , scope : "src" , topK : 7 } ,
108127 createMockSdkContext ( "/repo" ) ,
109128 ) ;
110129
111- expect ( sendCalls ) . toEqual ( [
130+ expect ( sendCalls ) . toEqual ( [ ] ) ;
131+ expect ( toolCallCalls ) . toEqual ( [
112132 {
113- command : "inspect" ,
114- params : {
133+ sessionId : "inspect-session" ,
134+ name : "inspect" ,
135+ rawArgs : {
115136 sections : [ "todos" , "dead_code" ] ,
116137 scope : "/repo/src" ,
117138 topK : 7 ,
118- session_id : "inspect-session" ,
119139 } ,
120140 options : expect . objectContaining ( {
121141 keepBridgeOnTimeout : true ,
@@ -126,87 +146,34 @@ describe("aft_inspect tool", () => {
126146 } ) ;
127147
128148 test ( "normalizes empty sections and scope sentinels" , async ( ) => {
129- const { sendCalls , tools } = createInspectHarness ( ( ) => ( { success : true , summary : { } } ) ) ;
149+ const { toolCallCalls , tools } = createInspectHarness ( ( ) => ( { success : true , text : "ok" } ) ) ;
130150
131151 await tools . aft_inspect . execute (
132152 { sections : [ ] , scope : "" , topK : undefined } ,
133153 createMockSdkContext ( "/repo" ) ,
134154 ) ;
135155
136- expect ( sendCalls [ 0 ] ?. params . sections ) . toBeUndefined ( ) ;
137- expect ( sendCalls [ 0 ] ?. params . scope ) . toBeUndefined ( ) ;
138- expect ( sendCalls [ 0 ] ?. params . topK ) . toBeUndefined ( ) ;
139- } ) ;
140-
141- test ( "renders diagnostics counts, sentinels, and details defensively" , ( ) => {
142- expect (
143- renderInspectDiagnostics ( {
144- summary : { diagnostics : { errors : 1 , warnings : 2 , info : 0 , hints : 3 } } ,
145- details : {
146- diagnostics : [
147- {
148- file : "src/app.ts" ,
149- line : 7 ,
150- column : 2 ,
151- severity : "error" ,
152- message : "bad type" ,
153- source : "tsserver" ,
154- } ,
155- ] ,
156- } ,
157- } ) ,
158- ) . toContain ( "diagnostics: 1 errors, 2 warnings, 0 info, 3 hints" ) ;
159-
160- const pending = renderInspectDiagnostics ( {
161- summary : {
162- diagnostics : {
163- status : "pending" ,
164- servers_pending : [ "typescript-language-server" ] ,
165- servers_not_installed : [ "pyright" ] ,
166- } ,
167- } ,
168- } ) ;
169- expect ( pending ) . toContain ( "diagnostics: pending" ) ;
170- expect ( pending ) . toContain ( "typescript-language-server" ) ;
171- expect ( pending ) . toContain ( "pyright" ) ;
172- expect ( pending ) . not . toContain ( "0 errors" ) ;
173-
174- // Partial result with counts-so-far AND a pending server: must show BOTH
175- // the already-found counts and the pending signal, so real errors found by
176- // one server aren't hidden while another server is still working.
177- const partial = renderInspectDiagnostics ( {
178- summary : {
179- diagnostics : {
180- errors : 2 ,
181- warnings : 0 ,
182- info : 0 ,
183- hints : 0 ,
184- status : "pending" ,
185- servers_pending : [ "oxlint" ] ,
186- } ,
187- } ,
188- } ) ;
189- expect ( partial ) . toContain ( "2 errors" ) ;
190- expect ( partial ) . toContain ( "so far" ) ;
191- expect ( partial ) . toContain ( "oxlint" ) ;
156+ expect ( toolCallCalls [ 0 ] ?. rawArgs . sections ) . toBeUndefined ( ) ;
157+ expect ( toolCallCalls [ 0 ] ?. rawArgs . scope ) . toBeUndefined ( ) ;
158+ expect ( toolCallCalls [ 0 ] ?. rawArgs . topK ) . toBeUndefined ( ) ;
192159 } ) ;
193160
194- test ( "returns the Rust text body with diagnostics appended (no JSON dump)" , async ( ) => {
161+ test ( "returns the server-rendered Rust text body without JSON fallback" , async ( ) => {
162+ const rendered =
163+ "Duplicates: 2 (top by cost):\n 1083 a.ts == b.ts\nDead code: 1 (rust 1):\n x.rs::foo\n\ndiagnostics: 1 errors, 0 warnings, 0 info, 2 hints" ;
195164 const { tools } = createInspectHarness ( ( ) => ( {
196165 success : true ,
197- text : "Duplicates: 2 (top by cost):\n 1083 a.ts == b.ts\nDead code: 1 (rust 1):\n x.rs::foo" ,
166+ text : rendered ,
198167 summary : { diagnostics : { errors : 1 , warnings : 0 , info : 0 , hints : 2 } } ,
199168 } ) ) ;
200169
201170 const result = await tools . aft_inspect . execute ( { } , createMockSdkContext ( "/repo" ) ) ;
202171 const text = typeof result === "string" ? result : ( result . output as string ) ;
203172
204- // Rust body is surfaced verbatim …
173+ expect ( text ) . toBe ( rendered ) ;
205174 expect ( text ) . toContain ( "Duplicates: 2 (top by cost):" ) ;
206175 expect ( text ) . toContain ( " x.rs::foo" ) ;
207- // … with the diagnostics line appended after it …
208176 expect ( text ) . toContain ( "diagnostics: 1 errors, 0 warnings, 0 info, 2 hints" ) ;
209- // … and never the raw JSON fallback.
210177 expect ( text ) . not . toContain ( '"success"' ) ;
211178 expect ( text ) . not . toContain ( "scanner_state" ) ;
212179 } ) ;
0 commit comments