Skip to content

Commit 2da39f9

Browse files
committed
fix(cli-plugin-copilot): narrow JsonValue before reading tool-call arg properties
@github/copilot-sdk's tool-call arguments are typed JsonValue (a union including primitives/arrays), so accessing .url/.path/.load/.selector directly no longer type-checks and was breaking the build on main.
1 parent 95af7fc commit 2da39f9

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@equinor/fusion-framework-cli-plugin-copilot": patch
3+
---
4+
5+
Fix a build failure caused by `@github/copilot-sdk`'s stricter `JsonValue` typing on tool-call `arguments`. Tool-call detail extraction (`url`/`path`/`load`/`selector`) now narrows the union type before reading properties instead of relying on unchecked optional chaining.

packages/cli-plugins/copilot/src/commands/app/attach-session-logger.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,31 @@
11
import chalk from 'chalk';
22
import ora from 'ora';
33

4-
import type { CopilotSession } from '@github/copilot-sdk';
4+
import type { CopilotSession, JsonValue } from '@github/copilot-sdk';
55

66
import { tryFormatMessage } from './try-format-message.js';
77

8+
/**
9+
* Extracts the first string-valued property found among `keys` on a tool-call's
10+
* JSON arguments, narrowing the untyped `JsonValue` union to its object branch first.
11+
* @param value - The tool-call arguments to inspect, as reported by the Copilot SDK
12+
* @param keys - Property names to check, in priority order
13+
* @returns The first matching string value, or `undefined` if none match
14+
*/
15+
function firstStringProp(value: JsonValue | undefined, keys: string[]): string | undefined {
16+
// Primitives and arrays have no named properties to read
17+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
18+
return undefined;
19+
}
20+
// Return the first key present with a string value, in caller-specified priority order
21+
for (const key of keys) {
22+
const prop = value[key];
23+
// Skip non-string values (numbers, nested objects, etc.) rather than stringifying them
24+
if (typeof prop === 'string') return prop;
25+
}
26+
return undefined;
27+
}
28+
829
const TOOL_ICONS: Record<string, string> = {
930
browser_screenshot: '📷',
1031
browser_navigate: '🌐',
@@ -69,7 +90,7 @@ export function attachSessionLogger(
6990
switch (event.type) {
7091
case 'tool.execution_start': {
7192
const { toolCallId, toolName, arguments: args } = event.data;
72-
const detail = args?.url ?? args?.path ?? args?.load ?? args?.selector;
93+
const detail = firstStringProp(args, ['url', 'path', 'load', 'selector']);
7394
const icon = TOOL_ICONS[toolName] ?? '🔧';
7495
const label =
7596
typeof detail === 'string' ? `${icon} ${toolName} (${detail})` : `${icon} ${toolName}`;

0 commit comments

Comments
 (0)