Skip to content

feat(github,playwright): automated onboarding + pinned versions + CI smoke - #85

Closed
dylanneve1 wants to merge 2 commits into
mainfrom
feat/github-playwright-onboarding
Closed

feat(github,playwright): automated onboarding + pinned versions + CI smoke#85
dylanneve1 wants to merge 2 commits into
mainfrom
feat/github-playwright-onboarding

Conversation

@dylanneve1

Copy link
Copy Markdown
Owner

Summary

Same treatment as #84 (mempalace) for the two remaining internal plugins. Three things for each:

  1. Pinned version β€” GitHub MCP Docker image pinned via GITHUB_MCP_IMAGE = "ghcr.io/github/github-mcp-server:v1.0.2" (was :latest). @playwright/mcp pinned to exact 0.0.70 in package.json (was ^0.0.70 caret-drift). Both constants live in a dedicated install.ts module next to the plugin.

  2. Automated onboarding β€” opt-in config flags. Both default false so we never touch the user's Docker cache or disk without consent.

    • github.autoPull β†’ docker pull the pinned image on init if missing.
    • playwright.installBrowsers β†’ npx playwright install <browser> on init if the browser binary isn't there.
  3. Multi-OS functional CI β€” .github/workflows/plugin-smoke.yml with two jobs:

    • github-mcp β€” ubuntu-latest (Docker). Pulls the pinned image, spawns docker run -i, runs MCP initialize β†’ tools/list, asserts core tools are present (get_me, search_repositories, list_issues).
    • playwright-mcp β€” matrix ubuntu-latest / macos-latest / windows-latest Γ— chromium. Installs the browser, spawns @playwright/mcp via Node, runs initialize β†’ tools/list β†’ tools/call browser_navigate about:blank β†’ tools/call browser_close, asserts expected tool names and valid response shapes.

Triggered by plugin path changes, main pushes, nightly cron (05:45 UTC), and manual dispatch.

Files

File Purpose
src/plugins/github/install.ts New β€” GITHUB_MCP_IMAGE + ensureGithubMcpAvailable
src/plugins/github/index.ts Wires install helper into init; adds autoPull / image knobs
src/plugins/playwright/install.ts New β€” PLAYWRIGHT_MCP_VERSION, SUPPORTED_BROWSERS, ensurePlaywrightMcpAvailable
src/plugins/playwright/index.ts Wires install helper into init; adds installBrowsers knob
src/util/config.ts New zod fields: github.autoPull, github.image, playwright.installBrowsers
src/core/plugin.ts Passes new flags through
package.json @playwright/mcp: ^0.0.70 β†’ 0.0.70
src/__tests__/github-install.test.ts New β€” 8 cases on ensureGithubMcpAvailable
src/__tests__/playwright-install.test.ts New β€” 10 cases on ensurePlaywrightMcpAvailable
.github/workflows/plugin-smoke.yml New β€” 4-job matrix (Ubuntu Docker + 3 OS Γ— chromium)
scripts/github-mcp-smoke.mjs New β€” pull + stdio smoke driver
scripts/playwright-mcp-smoke.mjs New β€” install + stdio smoke driver
.gitignore Ignore .playwright-mcp/ artifact dir

Local verification

  • npx vitest run β€” 1379/1379 passing
  • npm run typecheck β€” clean
  • npm run format:check β€” clean
  • npm run lint β€” 0 errors
  • node scripts/github-mcp-smoke.mjs smoke β€” pulled v1.0.2, spawned, 41 tools detected, core subset verified
  • node scripts/playwright-mcp-smoke.mjs install + smoke β€” 21 tools detected, browser_navigate + browser_close both returned valid responses

Relationship to other PRs

Independent of #83 and #84 β€” this one only touches github + playwright. Can merge in any order.

…smoke

Same treatment as mempalace (#84) for the other two internal Talon plugins.

## GitHub plugin (src/plugins/github/)

- New install.ts with GITHUB_MCP_IMAGE pinned tag (previously: ':latest',
  which silently drifts on upstream releases).
- ensureGithubMcpAvailable helper: verifies docker daemon, checks image
  presence, optionally docker pull when github.autoPull=true.
- New config fields: github.autoPull (bool, default false) and
  github.image (string, advanced override).
- init() runs the ensure flow, logs steps, surfaces errors.

## Playwright plugin (src/plugins/playwright/)

- @playwright/mcp pinned to exact 0.0.70 in package.json (previously
  ^0.0.70 β€” caret allowed silent minor/patch drift).
- New install.ts with PLAYWRIGHT_MCP_VERSION constant, SUPPORTED_BROWSERS
  source-of-truth, and ensurePlaywrightMcpAvailable helper.
- ensurePlaywrightMcpAvailable: verifies the MCP CLI resolves, compares
  installed version to the pin, probes browser via
  'playwright install --dry-run', optionally runs the real install when
  playwright.installBrowsers=true.
- Browser check is skipped when using a remote endpoint (no local binary
  needed).

## Tests

- New github-install.test.ts β€” 8 cases on ensureGithubMcpAvailable
  (happy path, docker unreachable, missing image with/without autoPull,
  pull failure, post-pull still missing, image override).
- New playwright-install.test.ts β€” 10 cases covering the CLI presence
  check, unsupported browser rejection, installBrowsers=true install
  path, failure modes, and remote-endpoint mode.
- All 1379 tests pass, typecheck clean, prettier clean, lint 0 errors.

## Functional CI

- New .github/workflows/plugin-smoke.yml with two jobs:
    github-mcp  β€” ubuntu-latest only (Docker). Pulls the pinned image,
                  spawns via docker run -i, runs initialize +
                  tools/list, asserts core tools present (get_me,
                  search_repositories, list_issues).
    playwright-mcp β€” matrix ubuntu/macos/windows Γ— chromium. Installs
                     the browser, spawns @playwright/mcp via node, runs
                     initialize + tools/list + browser_navigate
                     about:blank + browser_close. Asserts expected tool
                     names and valid response shapes.
- Triggers on plugin path changes, main pushes, nightly cron (05:45 UTC
  to catch upstream breakage), and manual dispatch.

## Local verification

- npx vitest run β†’ 1379/1379 passing
- node scripts/github-mcp-smoke.mjs smoke β†’ 41 tools, core subset OK
- node scripts/playwright-mcp-smoke.mjs install + smoke β†’ 21 tools,
  navigate + close OK
…ion drift

## GitHub
- When autoPull=true, docker pull runs even if the image is already
  present β€” refreshes the digest in case upstream force-pushed the tag.
  'docker pull' is a cheap no-op when the digest hasn't changed, so the
  cost is minimal.
- New test covering the 'present + autoPull β†’ refresh' path.

## Playwright
- When the installed @playwright/mcp version drifts from
  PLAYWRIGHT_MCP_VERSION, ensurePlaywrightMcpAvailable now returns
  ok=false with an actionable error (was: just a step-note). Mutating
  node_modules at runtime would desync with the lockfile, so fail
  visibly instead and tell the user to run 'npm install'.
- New test exercising the version-mismatch failure path.

## Scope note
These two changes complete Dylan's 'auto-update installed versions'
request as far as is feasible per plugin:
  - mempalace (pip)  β†’ realigns to exact target (previous commit).
  - github  (Docker) β†’ re-pulls pinned tag to refresh digest.
  - playwright (npm) β†’ cannot safely auto-mutate node_modules; instead
                       fails fast with an actionable error.
@dylanneve1

Copy link
Copy Markdown
Owner Author

Superseded by #86 β€” unified plugin-lifecycle overhaul that removes opt-in flags, adds a shared self-heal layer, and consolidates the CI matrix.

@dylanneve1 dylanneve1 closed this Apr 23, 2026
dylanneve1 pushed a commit that referenced this pull request May 5, 2026
Overhaul of mempalace, github, and playwright to remove opt-in flags
and introduce a shared, robust self-heal layer. Replaces #83, #84, #85.

Enabling a built-in plugin now fully sets it up β€” no flags, no manual
bootstrap:

  { "mempalace": { "enabled": true } }
  { "github":    { "enabled": true, "token": "ghp_..." } }
  { "playwright":{ "enabled": true, "browser": "chromium" } }

On every start Talon re-verifies the install and realigns to the pinned
version if it drifted. Removed: autoInstall, autoPull, installBrowsers.
Added: structured per-step progress logging with timings that pinpoint
the slow/failing step.

- semver.ts     β€” tiny parse/compare for the floor + pin check
- errors.ts     β€” PluginError taxonomy (8 kinds) + subprocess stderr
                  classifier with regression-tested patterns
- progress.ts   β€” numbered, timed step tracker with pluggable log sink
- subprocess.ts β€” line-streaming spawn wrapper that normalises CR/LF/CR-only
                  output (docker pull uses bare \r), captures stderr, and
                  returns a classified PluginError on failure
- lifecycle.ts  β€” HealFn contract + runHeal() with hard timeout guard

Each plugin keeps the upstream version pin as a source-of-truth constant
and implements a dedicated heal() that uses the shared infra:

- mempalace/heal.ts: MEMPALACE_TARGET="3.3.2", MEMPALACE_FLOOR="3.3.2".
  Managed mode owns ~/.talon/mempalace-venv (create β†’ pip install β†’ verify).
  User-supplied pythonPath switches to verify-only mode β€” we never
  mutate a user's Python environment without consent.
- github/heal.ts: GITHUB_MCP_IMAGE="ghcr.io/github/github-mcp-server:v1.0.2".
  Always pulls on heal to refresh digest. Pull-fail with cached image β†’
  degraded (we run on stale); pull-fail without cache β†’ failed.
- playwright/heal.ts: PLAYWRIGHT_MCP_VERSION="0.0.70" (matches pin in
  package.json). Verify-only for the npm package (we do NOT mutate
  node_modules at runtime), auto-install for the chosen browser binary.

Deliberately targeted, not volume. Shared infra: 39 cases. Per-plugin
heal: 9 mempalace, 6 github, 11 playwright. Plugin factory: 5 mempalace.
All test at decision boundaries (managed vs verify-only, present vs
missing vs drift, happy vs classified-failure paths) β€” no mock-the-mock
redundancy.

1421/1421 total passing Β· typecheck clean Β· prettier clean Β· 0 lint errors.

Single workflow, three jobs:

  mempalace  β†’ matrix Ubuntu/macOS/Windows Γ— Python 3.11/3.12 (6 runs)
  github     β†’ Ubuntu (Docker-only)                            (1 run)
  playwright β†’ matrix Ubuntu/macOS/Windows Γ— chromium           (3 runs)

Each job: pull/install the pinned version, spawn the real MCP server
over stdio, handshake, tools/list, call a representative tool. No
mocks, no network fakes. Triggers: PRs touching plugin paths, main
pushes, nightly cron (05:30 UTC), manual dispatch.

- npx vitest run         β†’ 1421/1421 passing
- npm run typecheck       β†’ clean
- npm run format:check    β†’ clean
- npm run lint            β†’ 0 errors (9 pre-existing warnings)
- node scripts/smoke-mempalace.mjs install + smoke β†’ 29 tools, status ok
- node scripts/smoke-github.mjs pull + smoke       β†’ 41 tools, list ok
- node scripts/smoke-playwright.mjs install + smoke β†’ 21 tools, navigate + close ok
dylanneve1 pushed a commit that referenced this pull request May 8, 2026
Overhaul of mempalace, github, and playwright to remove opt-in flags
and introduce a shared, robust self-heal layer. Replaces #83, #84, #85.

Enabling a built-in plugin now fully sets it up β€” no flags, no manual
bootstrap:

  { "mempalace": { "enabled": true } }
  { "github":    { "enabled": true, "token": "ghp_..." } }
  { "playwright":{ "enabled": true, "browser": "chromium" } }

On every start Talon re-verifies the install and realigns to the pinned
version if it drifted. Removed: autoInstall, autoPull, installBrowsers.
Added: structured per-step progress logging with timings that pinpoint
the slow/failing step.

- semver.ts     β€” tiny parse/compare for the floor + pin check
- errors.ts     β€” PluginError taxonomy (8 kinds) + subprocess stderr
                  classifier with regression-tested patterns
- progress.ts   β€” numbered, timed step tracker with pluggable log sink
- subprocess.ts β€” line-streaming spawn wrapper that normalises CR/LF/CR-only
                  output (docker pull uses bare \r), captures stderr, and
                  returns a classified PluginError on failure
- lifecycle.ts  β€” HealFn contract + runHeal() with hard timeout guard

Each plugin keeps the upstream version pin as a source-of-truth constant
and implements a dedicated heal() that uses the shared infra:

- mempalace/heal.ts: MEMPALACE_TARGET="3.3.2", MEMPALACE_FLOOR="3.3.2".
  Managed mode owns ~/.talon/mempalace-venv (create β†’ pip install β†’ verify).
  User-supplied pythonPath switches to verify-only mode β€” we never
  mutate a user's Python environment without consent.
- github/heal.ts: GITHUB_MCP_IMAGE="ghcr.io/github/github-mcp-server:v1.0.2".
  Always pulls on heal to refresh digest. Pull-fail with cached image β†’
  degraded (we run on stale); pull-fail without cache β†’ failed.
- playwright/heal.ts: PLAYWRIGHT_MCP_VERSION="0.0.70" (matches pin in
  package.json). Verify-only for the npm package (we do NOT mutate
  node_modules at runtime), auto-install for the chosen browser binary.

Deliberately targeted, not volume. Shared infra: 39 cases. Per-plugin
heal: 9 mempalace, 6 github, 11 playwright. Plugin factory: 5 mempalace.
All test at decision boundaries (managed vs verify-only, present vs
missing vs drift, happy vs classified-failure paths) β€” no mock-the-mock
redundancy.

1421/1421 total passing Β· typecheck clean Β· prettier clean Β· 0 lint errors.

Single workflow, three jobs:

  mempalace  β†’ matrix Ubuntu/macOS/Windows Γ— Python 3.11/3.12 (6 runs)
  github     β†’ Ubuntu (Docker-only)                            (1 run)
  playwright β†’ matrix Ubuntu/macOS/Windows Γ— chromium           (3 runs)

Each job: pull/install the pinned version, spawn the real MCP server
over stdio, handshake, tools/list, call a representative tool. No
mocks, no network fakes. Triggers: PRs touching plugin paths, main
pushes, nightly cron (05:30 UTC), manual dispatch.

- npx vitest run         β†’ 1421/1421 passing
- npm run typecheck       β†’ clean
- npm run format:check    β†’ clean
- npm run lint            β†’ 0 errors (9 pre-existing warnings)
- node scripts/smoke-mempalace.mjs install + smoke β†’ 29 tools, status ok
- node scripts/smoke-github.mjs pull + smoke       β†’ 41 tools, list ok
- node scripts/smoke-playwright.mjs install + smoke β†’ 21 tools, navigate + close ok
dylanneve1 pushed a commit that referenced this pull request May 8, 2026
Overhaul of mempalace, github, and playwright to remove opt-in flags
and introduce a shared, robust self-heal layer. Replaces #83, #84, #85.

Enabling a built-in plugin now fully sets it up β€” no flags, no manual
bootstrap:

  { "mempalace": { "enabled": true } }
  { "github":    { "enabled": true, "token": "ghp_..." } }
  { "playwright":{ "enabled": true, "browser": "chromium" } }

On every start Talon re-verifies the install and realigns to the pinned
version if it drifted. Removed: autoInstall, autoPull, installBrowsers.
Added: structured per-step progress logging with timings that pinpoint
the slow/failing step.

- semver.ts     β€” tiny parse/compare for the floor + pin check
- errors.ts     β€” PluginError taxonomy (8 kinds) + subprocess stderr
                  classifier with regression-tested patterns
- progress.ts   β€” numbered, timed step tracker with pluggable log sink
- subprocess.ts β€” line-streaming spawn wrapper that normalises CR/LF/CR-only
                  output (docker pull uses bare \r), captures stderr, and
                  returns a classified PluginError on failure
- lifecycle.ts  β€” HealFn contract + runHeal() with hard timeout guard

Each plugin keeps the upstream version pin as a source-of-truth constant
and implements a dedicated heal() that uses the shared infra:

- mempalace/heal.ts: MEMPALACE_TARGET="3.3.2", MEMPALACE_FLOOR="3.3.2".
  Managed mode owns ~/.talon/mempalace-venv (create β†’ pip install β†’ verify).
  User-supplied pythonPath switches to verify-only mode β€” we never
  mutate a user's Python environment without consent.
- github/heal.ts: GITHUB_MCP_IMAGE="ghcr.io/github/github-mcp-server:v1.0.2".
  Always pulls on heal to refresh digest. Pull-fail with cached image β†’
  degraded (we run on stale); pull-fail without cache β†’ failed.
- playwright/heal.ts: PLAYWRIGHT_MCP_VERSION="0.0.70" (matches pin in
  package.json). Verify-only for the npm package (we do NOT mutate
  node_modules at runtime), auto-install for the chosen browser binary.

Deliberately targeted, not volume. Shared infra: 39 cases. Per-plugin
heal: 9 mempalace, 6 github, 11 playwright. Plugin factory: 5 mempalace.
All test at decision boundaries (managed vs verify-only, present vs
missing vs drift, happy vs classified-failure paths) β€” no mock-the-mock
redundancy.

1421/1421 total passing Β· typecheck clean Β· prettier clean Β· 0 lint errors.

Single workflow, three jobs:

  mempalace  β†’ matrix Ubuntu/macOS/Windows Γ— Python 3.11/3.12 (6 runs)
  github     β†’ Ubuntu (Docker-only)                            (1 run)
  playwright β†’ matrix Ubuntu/macOS/Windows Γ— chromium           (3 runs)

Each job: pull/install the pinned version, spawn the real MCP server
over stdio, handshake, tools/list, call a representative tool. No
mocks, no network fakes. Triggers: PRs touching plugin paths, main
pushes, nightly cron (05:30 UTC), manual dispatch.

- npx vitest run         β†’ 1421/1421 passing
- npm run typecheck       β†’ clean
- npm run format:check    β†’ clean
- npm run lint            β†’ 0 errors (9 pre-existing warnings)
- node scripts/smoke-mempalace.mjs install + smoke β†’ 29 tools, status ok
- node scripts/smoke-github.mjs pull + smoke       β†’ 41 tools, list ok
- node scripts/smoke-playwright.mjs install + smoke β†’ 21 tools, navigate + close ok
dylanneve1 pushed a commit that referenced this pull request May 9, 2026
Overhaul of mempalace, github, and playwright to remove opt-in flags
and introduce a shared, robust self-heal layer. Replaces #83, #84, #85.

Enabling a built-in plugin now fully sets it up β€” no flags, no manual
bootstrap:

  { "mempalace": { "enabled": true } }
  { "github":    { "enabled": true, "token": "ghp_..." } }
  { "playwright":{ "enabled": true, "browser": "chromium" } }

On every start Talon re-verifies the install and realigns to the pinned
version if it drifted. Removed: autoInstall, autoPull, installBrowsers.
Added: structured per-step progress logging with timings that pinpoint
the slow/failing step.

- semver.ts     β€” tiny parse/compare for the floor + pin check
- errors.ts     β€” PluginError taxonomy (8 kinds) + subprocess stderr
                  classifier with regression-tested patterns
- progress.ts   β€” numbered, timed step tracker with pluggable log sink
- subprocess.ts β€” line-streaming spawn wrapper that normalises CR/LF/CR-only
                  output (docker pull uses bare \r), captures stderr, and
                  returns a classified PluginError on failure
- lifecycle.ts  β€” HealFn contract + runHeal() with hard timeout guard

Each plugin keeps the upstream version pin as a source-of-truth constant
and implements a dedicated heal() that uses the shared infra:

- mempalace/heal.ts: MEMPALACE_TARGET="3.3.2", MEMPALACE_FLOOR="3.3.2".
  Managed mode owns ~/.talon/mempalace-venv (create β†’ pip install β†’ verify).
  User-supplied pythonPath switches to verify-only mode β€” we never
  mutate a user's Python environment without consent.
- github/heal.ts: GITHUB_MCP_IMAGE="ghcr.io/github/github-mcp-server:v1.0.2".
  Always pulls on heal to refresh digest. Pull-fail with cached image β†’
  degraded (we run on stale); pull-fail without cache β†’ failed.
- playwright/heal.ts: PLAYWRIGHT_MCP_VERSION="0.0.70" (matches pin in
  package.json). Verify-only for the npm package (we do NOT mutate
  node_modules at runtime), auto-install for the chosen browser binary.

Deliberately targeted, not volume. Shared infra: 39 cases. Per-plugin
heal: 9 mempalace, 6 github, 11 playwright. Plugin factory: 5 mempalace.
All test at decision boundaries (managed vs verify-only, present vs
missing vs drift, happy vs classified-failure paths) β€” no mock-the-mock
redundancy.

1421/1421 total passing Β· typecheck clean Β· prettier clean Β· 0 lint errors.

Single workflow, three jobs:

  mempalace  β†’ matrix Ubuntu/macOS/Windows Γ— Python 3.11/3.12 (6 runs)
  github     β†’ Ubuntu (Docker-only)                            (1 run)
  playwright β†’ matrix Ubuntu/macOS/Windows Γ— chromium           (3 runs)

Each job: pull/install the pinned version, spawn the real MCP server
over stdio, handshake, tools/list, call a representative tool. No
mocks, no network fakes. Triggers: PRs touching plugin paths, main
pushes, nightly cron (05:30 UTC), manual dispatch.

- npx vitest run         β†’ 1421/1421 passing
- npm run typecheck       β†’ clean
- npm run format:check    β†’ clean
- npm run lint            β†’ 0 errors (9 pre-existing warnings)
- node scripts/smoke-mempalace.mjs install + smoke β†’ 29 tools, status ok
- node scripts/smoke-github.mjs pull + smoke       β†’ 41 tools, list ok
- node scripts/smoke-playwright.mjs install + smoke β†’ 21 tools, navigate + close ok
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants