From ac8db11eafb74a4a6c283ce4c2e7553627723eb8 Mon Sep 17 00:00:00 2001 From: konard Date: Mon, 8 Jun 2026 07:55:37 +0000 Subject: [PATCH 1/3] Initial commit with task details Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: https://github.com/ProverCoderAI/docker-git/issues/383 --- .gitkeep | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitkeep diff --git a/.gitkeep b/.gitkeep new file mode 100644 index 00000000..223c2faf --- /dev/null +++ b/.gitkeep @@ -0,0 +1 @@ +# .gitkeep file auto-generated at 2026-06-08T07:55:37.526Z for PR creation at branch issue-383-173b143467d9 for issue https://github.com/ProverCoderAI/docker-git/issues/383 \ No newline at end of file From 31bcdc61f5aebc6782b818b4241150e2cacd26c6 Mon Sep 17 00:00:00 2001 From: konard Date: Wed, 10 Jun 2026 10:23:11 +0000 Subject: [PATCH 2/3] fix(api): hide browser-connection MCP helpers from task manager The Rust browser MCP helpers (`browser-connection` / `docker-git-browser-connection`) run on an allocated pty, so `hasInteractiveTty` classified each one as a visible `ssh` terminal. That flooded the container task manager with many identical `browser-connection --project ... --network container:...` rows (issue #383). Classify these helper processes as internal `system` tasks so they are hidden by default (includeDefault=false) and only shown when system processes are explicitly requested. Fixes #383 --- .gitkeep | 1 - .../api/src/services/container-tasks-core.ts | 12 +++++++++- .../api/tests/container-tasks-core.test.ts | 24 +++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) delete mode 100644 .gitkeep diff --git a/.gitkeep b/.gitkeep deleted file mode 100644 index 223c2faf..00000000 --- a/.gitkeep +++ /dev/null @@ -1 +0,0 @@ -# .gitkeep file auto-generated at 2026-06-08T07:55:37.526Z for PR creation at branch issue-383-173b143467d9 for issue https://github.com/ProverCoderAI/docker-git/issues/383 \ No newline at end of file diff --git a/packages/api/src/services/container-tasks-core.ts b/packages/api/src/services/container-tasks-core.ts index 1b9850fd..7945aee4 100644 --- a/packages/api/src/services/container-tasks-core.ts +++ b/packages/api/src/services/container-tasks-core.ts @@ -27,6 +27,13 @@ const commandSuggestsSsh = (command: string): boolean => command.startsWith("ssh const commandSuggestsAgent = (command: string): boolean => interactiveAgentPattern.test(command) || command.includes("docker-git-agent-") +// Rust browser MCP helpers (`browser-connection`, `docker-git-browser-connection`) +// run on an allocated pty, so without this they would be misclassified as visible +// `ssh` terminals and flood the task manager (issue #383). +const browserConnectionPattern = /(?:^|\/)(?:docker-git-browser-connection|browser-connection)\b/u + +const commandSuggestsBrowserHelper = (command: string): boolean => browserConnectionPattern.test(command) + const resolveAncestorManagedId = ( process: RawContainerProcess, pidToProcess: ReadonlyMap, @@ -49,6 +56,9 @@ const classifyProcess = ( process: RawContainerProcess, managedId: string | undefined ): ContainerTaskKind => { + if (commandSuggestsBrowserHelper(process.command)) { + return "system" + } if (managedId !== undefined || commandSuggestsAgent(process.command)) { return "agent" } @@ -78,7 +88,7 @@ const compareTasks = (left: ContainerTask, right: ContainerTask): number => { // FORMAT THEOREM: forall p in Processes: classify(p) in ContainerTaskKind // PURITY: CORE // EFFECT: none -// INVARIANT: includeDefault=false excludes only baseline system processes +// INVARIANT: includeDefault=false excludes system processes (baseline + browser helpers) // COMPLEXITY: O(n * h) where h is maximum process ancestry depth export const buildContainerTasks = ( processes: ReadonlyArray, diff --git a/packages/api/tests/container-tasks-core.test.ts b/packages/api/tests/container-tasks-core.test.ts index a9404ac9..fe8c1c89 100644 --- a/packages/api/tests/container-tasks-core.test.ts +++ b/packages/api/tests/container-tasks-core.test.ts @@ -31,6 +31,30 @@ describe("container task classification", () => { .toHaveLength(1) }) + it("hides browser-connection MCP helpers as internal system tasks", () => { + const browserCommand = + "browser-connection --project dg-docker-git-issue-376 --network container:dg-docker-git-issue-376" + const visible = buildContainerTasks( + [ + processOf({ command: browserCommand, pid: 11502, ppid: 5142, tty: "pts/1" }), + processOf({ command: "/usr/local/bin/docker-git-browser-connection start", pid: 11600, ppid: 5142, tty: "pts/1" }), + processOf({ command: "node server.js", pid: 20, ppid: 1, tty: "pts/2" }) + ], + [], + false + ) + + expect(visible.map((task) => task.pid)).toEqual([20]) + + const withSystem = buildContainerTasks( + [processOf({ command: browserCommand, pid: 11502, ppid: 5142, tty: "pts/1" })], + [], + true + ) + + expect(withSystem.map((task) => [task.pid, task.kind])).toEqual([[11502, "system"]]) + }) + it("marks descendants of managed agent pid as agent tasks", () => { const tasks = buildContainerTasks( [ From fc40a9e52a9339538c8c7fc70d978e033ae0c025 Mon Sep 17 00:00:00 2001 From: skulidropek <66840575+skulidropek@users.noreply.github.com> Date: Fri, 12 Jun 2026 06:20:44 +0000 Subject: [PATCH 3/3] docs(api): add structured functional comment and fast-check property test for browser-helper classifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace prose comment above browserConnectionPattern with full CHANGE/WHY/FORMAT THEOREM/PURITY/INVARIANT/COMPLEXITY block per project conventions (CodeRabbit review on PR #399) - Add fast-check property-based test covering bare and absolute-path variants of browser-connection / docker-git-browser-connection: ∀ cmd ∈ helperCommands: hidden when includeDefault=false, kind="system" when includeDefault=true Co-Authored-By: Claude Sonnet 4.6 --- .../api/src/services/container-tasks-core.ts | 15 ++++++-- .../api/tests/container-tasks-core.test.ts | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/api/src/services/container-tasks-core.ts b/packages/api/src/services/container-tasks-core.ts index 7945aee4..03542238 100644 --- a/packages/api/src/services/container-tasks-core.ts +++ b/packages/api/src/services/container-tasks-core.ts @@ -27,9 +27,18 @@ const commandSuggestsSsh = (command: string): boolean => command.startsWith("ssh const commandSuggestsAgent = (command: string): boolean => interactiveAgentPattern.test(command) || command.includes("docker-git-agent-") -// Rust browser MCP helpers (`browser-connection`, `docker-git-browser-connection`) -// run on an allocated pty, so without this they would be misclassified as visible -// `ssh` terminals and flood the task manager (issue #383). +// CHANGE: classify browser-connection / docker-git-browser-connection helpers as system +// WHY: these Rust MCP helpers run on allocated ptys (pts/N); without this guard +// hasInteractiveTty classifies each as a visible "ssh" terminal and floods the +// task manager with duplicate rows (issue #383) +// QUOTE(ТЗ): n/a +// REF: https://github.com/ProverCoderAI/docker-git/issues/383 +// SOURCE: n/a +// FORMAT THEOREM: ∀ cmd ∈ Commands: commandSuggestsBrowserHelper(cmd) → classifyProcess(cmd) = "system" +// PURITY: CORE +// INVARIANT: browserConnectionPattern matches the binary name at start or after '/' +// with a word boundary — covers bare invocations and full absolute paths +// COMPLEXITY: O(1) time / O(1) space — single constant regex test const browserConnectionPattern = /(?:^|\/)(?:docker-git-browser-connection|browser-connection)\b/u const commandSuggestsBrowserHelper = (command: string): boolean => browserConnectionPattern.test(command) diff --git a/packages/api/tests/container-tasks-core.test.ts b/packages/api/tests/container-tasks-core.test.ts index fe8c1c89..cb4dedf6 100644 --- a/packages/api/tests/container-tasks-core.test.ts +++ b/packages/api/tests/container-tasks-core.test.ts @@ -1,3 +1,4 @@ +import fc from "fast-check" import { describe, expect, it } from "vitest" import { buildContainerTasks } from "../src/services/container-tasks-core.js" @@ -55,6 +56,41 @@ describe("container task classification", () => { expect(withSystem.map((task) => [task.pid, task.kind])).toEqual([[11502, "system"]]) }) + it("hides any browser-helper command variant regardless of path prefix or arguments", () => { + const optArgs = fc.option(fc.string({ maxLength: 40 }), { nil: undefined }) + + const browserCommandArbitrary = fc.oneof( + optArgs.map((args) => (args === undefined ? "browser-connection" : `browser-connection ${args}`)), + optArgs.map((args) => + args === undefined ? "docker-git-browser-connection" : `docker-git-browser-connection ${args}` + ), + optArgs.map((args) => + args === undefined ? "/usr/local/bin/browser-connection" : `/usr/local/bin/browser-connection ${args}` + ), + optArgs.map((args) => + args === undefined + ? "/usr/local/bin/docker-git-browser-connection" + : `/usr/local/bin/docker-git-browser-connection ${args}` + ) + ) + + fc.assert( + fc.property(browserCommandArbitrary, fc.integer({ min: 1, max: 99999 }), (command, pid) => { + const hidden = buildContainerTasks( + [processOf({ command, pid, ppid: 0, tty: "pts/1" })], + [], + false + ) + const shown = buildContainerTasks( + [processOf({ command, pid, ppid: 0, tty: "pts/1" })], + [], + true + ) + return hidden.length === 0 && shown.every((t) => t.kind === "system") + }) + ) + }) + it("marks descendants of managed agent pid as agent tasks", () => { const tasks = buildContainerTasks( [