Skip to content

Commit f1e065d

Browse files
committed
fix(terminal): merge upstream terminal profile override (Zoo-Code-Org#277) with shell detection (Zoo-Code-Org#333)
Resolve conflicts between upstream PR Zoo-Code-Org#277 (VS Code integrated-terminal profile override) and our PR Zoo-Code-Org#333 (shell detection via vscode.env.shell + WSL support). Key merge decisions: - Terminal.ts: combine upstream's getProfileShell() system with our shellIntegrationReady pre-initialization; adopt activeShellExecution property from upstream; pass reuseKey to BaseTerminal constructor - TerminalProcess.ts: keep our no-sendText double-execution fix; adopt upstream's typed no_shell_integration payload {message, commandSubmitted}; keep our aborting guard for Ctrl+C retry loops - Remove broken WSL marker completion code referencing undefined variables (commandOutputStarted/preOutput) — use upstream's simple completion - Terminal.spec.ts: update constructor tests for profile-based creation; replace WSL/execaShellPath branch tests with getProfileShell() tests - TerminalProcess.spec.ts: update no_shell_integration assertions to typed format; fix executeCommand mock for streamAvailable timeout test - TerminalRegistry.spec.ts: adopt upstream's afterEach cleanup, keep our more specific iconPath assertion format Test results: 53/53 terminal tests pass, type check passes
2 parents 35ef0a6 + 52a8cc0 commit f1e065d

141 files changed

Lines changed: 8304 additions & 1164 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

PRIVACY.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ go—and, importantly, where they don't.
4040
We retain telemetry only as long as needed for product analytics and debugging.
4141
Telemetry does **not** collect your code or AI prompts, and you can opt out at
4242
any time through the settings.
43-
- **Zoo Code Observability (Authenticated Subscribers Only):** If you sign in to
44-
Zoo Code and have an active subscription, Zoo Code will send LLM usage
45-
telemetry to the Zoo Code backend (zoocode.dev). This includes task ID, AI
46-
provider name, model name, token counts (input/output/cache), and estimated
47-
cost. This data is linked to your authenticated Zoo Code account. You can stop
48-
this collection at any time by signing out via the Zoo Code badge in the chat
49-
area.
5043
- **Marketplace Requests**: When you browse or search the Marketplace for Model
5144
Configuration Profiles (MCPs) or Custom Modes, Zoo Code makes a secure API
5245
call to Zoo Code's backend servers to retrieve listing information. These
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"fixtures": [
3+
{
4+
"match": {
5+
"userMessage": "TERMINAL_PROFILE_E2E_OVERRIDE"
6+
},
7+
"response": {
8+
"toolCalls": [
9+
{
10+
"name": "execute_command",
11+
"arguments": "{\"command\":\"printf 'zoo-profile-override-ok\\\\n' > terminal-profile-e2e/terminal-profile-override.txt\"}",
12+
"id": "call_terminal_profile_override_001"
13+
}
14+
]
15+
}
16+
},
17+
{
18+
"match": {
19+
"userMessage": "TERMINAL_PROFILE_E2E_DEFAULT"
20+
},
21+
"response": {
22+
"toolCalls": [
23+
{
24+
"name": "execute_command",
25+
"arguments": "{\"command\":\"printf 'zoo-profile-default-ok\\\\n' > terminal-profile-e2e/terminal-profile-default.txt\"}",
26+
"id": "call_terminal_profile_default_001"
27+
}
28+
]
29+
}
30+
}
31+
]
32+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { LLMock } from "@copilotkit/aimock"
2+
import type { ChatCompletionRequest } from "@copilotkit/aimock"
3+
4+
import { toolResultContains } from "./tool-result"
5+
6+
const SUBTASK_PARENT_MARKER = "SUBTASK_PARENT_CANCELLATION_SMOKE"
7+
const SUBTASK_CHILD_MARKER = "SUBTASK_CHILD_CALCULATOR_SMOKE"
8+
9+
const SUBTASK_CHILD_PROMPT = `${SUBTASK_CHILD_MARKER}: Ask the user exactly this follow-up question: What is the square root of 81? After the user answers, complete with only the answer.`
10+
export const SUBTASK_PARENT_PROMPT = `${SUBTASK_PARENT_MARKER}: Use the new_task tool exactly once. Create an ask-mode subtask with this exact message: "${SUBTASK_CHILD_PROMPT}" Do not answer directly.`
11+
export const SUBTASK_CHILD_FOLLOWUP_ANSWER = "9"
12+
13+
const requestContains = (req: ChatCompletionRequest, expected: string[]) => {
14+
const rawRequest = JSON.stringify(req)
15+
return expected.every((text) => rawRequest.includes(text))
16+
}
17+
18+
const completionAfterAnswer = (followupId: string, completionId: string) => ({
19+
match: {
20+
predicate: (req: ChatCompletionRequest) =>
21+
// Preferred: structured tool-result message carries the followup answer.
22+
toolResultContains(req, followupId, [SUBTASK_CHILD_FOLLOWUP_ANSWER]) ||
23+
// Fallback 1: answer present alongside the tool-call ID but not in a role:tool message.
24+
requestContains(req, [followupId, SUBTASK_CHILD_FOLLOWUP_ANSWER]) ||
25+
// Fallback 2: answer arrives as a bare user message after task resume (no tool-call ID context).
26+
requestContains(req, [
27+
SUBTASK_CHILD_MARKER,
28+
`<user_message>\\n${SUBTASK_CHILD_FOLLOWUP_ANSWER}\\n</user_message>`,
29+
]),
30+
},
31+
response: {
32+
toolCalls: [
33+
{
34+
name: "attempt_completion",
35+
arguments: JSON.stringify({ result: "9" }),
36+
id: completionId,
37+
},
38+
],
39+
},
40+
})
41+
42+
export function addSubtaskFixtures(mock: InstanceType<typeof LLMock>) {
43+
mock.addFixture({
44+
match: {
45+
userMessage: new RegExp(SUBTASK_PARENT_MARKER),
46+
},
47+
response: {
48+
toolCalls: [
49+
{
50+
name: "new_task",
51+
arguments: JSON.stringify({
52+
mode: "ask",
53+
message: SUBTASK_CHILD_PROMPT,
54+
}),
55+
id: "call_subtasks_parent_new_task_001",
56+
},
57+
],
58+
},
59+
})
60+
61+
mock.addFixture({
62+
match: {
63+
userMessage: new RegExp(SUBTASK_CHILD_MARKER),
64+
},
65+
response: {
66+
toolCalls: [
67+
{
68+
name: "ask_followup_question",
69+
arguments: JSON.stringify({
70+
question: "What is the square root of 81?",
71+
follow_up: [{ text: SUBTASK_CHILD_FOLLOWUP_ANSWER }],
72+
}),
73+
id: "call_subtasks_child_followup_001",
74+
},
75+
],
76+
},
77+
})
78+
79+
mock.addFixture(completionAfterAnswer("call_subtasks_child_followup_001", "call_subtasks_child_completion_002"))
80+
81+
mock.addFixture({
82+
match: {
83+
toolCallId: "call_subtasks_parent_new_task_001",
84+
},
85+
response: {
86+
toolCalls: [
87+
{
88+
name: "attempt_completion",
89+
arguments: JSON.stringify({ result: "Parent task resumed" }),
90+
id: "call_subtasks_parent_completion_003",
91+
},
92+
],
93+
},
94+
})
95+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { LLMock } from "@copilotkit/aimock"
2+
3+
import { toolResultContains } from "./tool-result"
4+
5+
type TerminalProfileToolCall = {
6+
name: "execute_command" | "attempt_completion"
7+
params: Record<string, unknown>
8+
id: string
9+
}
10+
11+
type TerminalProfileFixture = {
12+
toolCallId: string
13+
expected: string[]
14+
toolCalls: TerminalProfileToolCall[]
15+
}
16+
17+
export function addTerminalProfileResultFixtures(mock: InstanceType<typeof LLMock>) {
18+
const fixtures: TerminalProfileFixture[] = [
19+
{
20+
toolCallId: "call_terminal_profile_override_001",
21+
expected: ["Exit code: 0"],
22+
toolCalls: [
23+
{
24+
name: "attempt_completion",
25+
params: { result: "Ran the command using the Zoo E2E Bash profile override." },
26+
id: "call_terminal_profile_override_002",
27+
},
28+
],
29+
},
30+
{
31+
toolCallId: "call_terminal_profile_default_001",
32+
expected: ["Exit code: 0"],
33+
toolCalls: [
34+
{
35+
name: "attempt_completion",
36+
params: { result: "Ran the command using the default terminal profile." },
37+
id: "call_terminal_profile_default_002",
38+
},
39+
],
40+
},
41+
]
42+
43+
for (const fixture of fixtures) {
44+
mock.addFixture({
45+
match: {
46+
toolCallId: fixture.toolCallId,
47+
predicate: (req) => toolResultContains(req, fixture.toolCallId, fixture.expected),
48+
},
49+
response: {
50+
toolCalls: fixture.toolCalls.map((toolCall) => ({
51+
name: toolCall.name,
52+
arguments: JSON.stringify(toolCall.params),
53+
id: toolCall.id,
54+
})),
55+
},
56+
})
57+
}
58+
}

apps/vscode-e2e/src/runTest.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ import { LLMock } from "@copilotkit/aimock"
77

88
import { addApplyDiffResultFixtures } from "./fixtures/apply-diff"
99
import { addExecuteCommandResultFixtures } from "./fixtures/execute-command"
10+
import { addTerminalProfileResultFixtures } from "./fixtures/terminal-profile"
1011
import { addListFilesResultFixtures } from "./fixtures/list-files"
1112
import { addReadFileResultFixtures } from "./fixtures/read-file"
1213
import { addSearchFilesResultFixtures } from "./fixtures/search-files"
14+
import { addSubtaskFixtures } from "./fixtures/subtasks"
1315
import { addUseMcpToolResultFixtures } from "./fixtures/use-mcp-tool"
1416
import { addWriteToFileResultFixtures } from "./fixtures/write-to-file"
1517

@@ -107,9 +109,11 @@ async function main() {
107109
if (!isRecord) {
108110
addApplyDiffResultFixtures(mock)
109111
addExecuteCommandResultFixtures(mock)
112+
addTerminalProfileResultFixtures(mock)
110113
addListFilesResultFixtures(mock)
111114
addReadFileResultFixtures(mock)
112115
addSearchFilesResultFixtures(mock)
116+
addSubtaskFixtures(mock)
113117
addUseMcpToolResultFixtures(mock)
114118
addWriteToFileResultFixtures(mock)
115119

0 commit comments

Comments
 (0)