From a355b6f0adebab25d0ad67c5883364c3b8ce7c8d Mon Sep 17 00:00:00 2001 From: core-be Date: Sun, 10 May 2026 04:23:46 -0700 Subject: [PATCH] fix(workspace-server): emit Gitea/PyPI URLs for external user instructions (RFC #229 P2-5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Molecule-AI GitHub org was suspended 2026-05-06; canonical SCM is now git.moleculesai.app. external_connection.go was still emitting github.com URLs in operator-facing copy-paste blocks, breaking external-agent onboarding silently. Per-site decisions (8 emit sites in 1 file): - L124 (channel template doc comment): swap source-of-truth comment to Gitea host. - L137 /plugin marketplace add Molecule-AI/...: swap to explicit Gitea HTTPS URL form. End-to-end-verified path per internal#37 § 1.A. - L138 /plugin install molecule@molecule-mcp-claude-channel: marketplace name is molecule-channel (per remote .claude-plugin/marketplace.json), not the repo name. Fix to molecule@molecule-channel. - L157 --channels plugin:molecule@molecule-mcp-claude-channel: same marketplace-name fix. - L179 user-facing GitHub URL: swap to Gitea. - L261 pip install git+https://github.com/Molecule-AI/molecule-sdk-python: not on PyPI; swap to git+https://git.moleculesai.app/molecule-ai/... - L310 hermes-channel doc comment: swap source-of-truth comment. - L339 pip install git+https://github.com/Molecule-AI/hermes-channel-molecule: not on PyPI; swap to Gitea. - L369 issue-tracker URL: swap to Gitea. Verification: - molecule-ai-workspace-runtime, codex-channel-molecule are on PyPI (200); no swap needed for those pip lines (they were already package-name form). - molecule-mcp-claude-channel, molecule-sdk-python, hermes-channel-molecule are NOT on PyPI; swapped to git+https://git.moleculesai.app/molecule-ai/ form. All three repos are public on Gitea (default branch main) and serve git-upload-pack unauthenticated (verified curl 200 against /info/refs?service=git-upload-pack). - Third-party github URLs (gin import, openai/codex, NousResearch/ hermes-agent upstream issue trackers, npm @openai/codex) intentionally preserved. Adds TestExternalTemplates_NoBrokenMoleculeAIGitHubURLs regression guard to prevent the same broken URLs from re-emerging on future template edits. go vet / go build / existing TestExternal* — all clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../internal/handlers/external_connection.go | 18 ++++---- .../handlers/external_connection_test.go | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/workspace-server/internal/handlers/external_connection.go b/workspace-server/internal/handlers/external_connection.go index 320e761e..ef213ae0 100644 --- a/workspace-server/internal/handlers/external_connection.go +++ b/workspace-server/internal/handlers/external_connection.go @@ -121,7 +121,7 @@ curl -fsS -X POST "{{PLATFORM_URL}}/registry/register" \ // operators whose external agent IS a Claude Code session (laptop or // remote dev VM); routes the workspace's A2A traffic into the running // Claude Code session as conversation turns via MCP. The plugin source -// lives at github.com/Molecule-AI/molecule-mcp-claude-channel — polling +// lives at git.moleculesai.app/molecule-ai/molecule-mcp-claude-channel — polling // based, no tunnel required (uses /workspaces/:id/activity?since_secs=, // platform-side support shipped in #2300). const externalChannelTemplate = `# Claude Code channel — bridges this workspace's A2A traffic into your @@ -134,8 +134,8 @@ const externalChannelTemplate = `# Claude Code channel — bridges this workspac # The plugin is NOT on Anthropic's default allowlist, so a one-time # marketplace-add is needed before install: # -# /plugin marketplace add Molecule-AI/molecule-mcp-claude-channel -# /plugin install molecule@molecule-mcp-claude-channel +# /plugin marketplace add https://git.moleculesai.app/molecule-ai/molecule-mcp-claude-channel.git +# /plugin install molecule@molecule-channel # # Then either run /reload-plugins or restart Claude Code so the # plugin is registered. @@ -154,7 +154,7 @@ chmod 600 ~/.claude/channels/molecule/.env # flag to opt in — without it, you'll see "not on the approved channels # allowlist" on startup. claude --dangerously-load-development-channels \ - --channels plugin:molecule@molecule-mcp-claude-channel + --channels plugin:molecule@molecule-channel # You should see on stderr: # molecule channel: connected — watching 1 workspace(s) at {{PLATFORM_URL}} @@ -176,7 +176,7 @@ claude --dangerously-load-development-channels \ # add the plugin to allowedChannelPlugins in claude.ai admin settings. # # Multi-workspace: comma-separate IDs and tokens (same order). See -# https://github.com/Molecule-AI/molecule-mcp-claude-channel for +# https://git.moleculesai.app/molecule-ai/molecule-mcp-claude-channel for # pairing flow, push-mode upgrade, and v0.2 roadmap. # Need help? @@ -258,7 +258,7 @@ claude mcp add molecule -s user -- env \ // externalPythonTemplate uses molecule-sdk-python's RemoteAgentClient + // A2AServer (PR #13 in that repo). Until the SDK cuts a v0.y release // to PyPI the snippet pins git+main. -const externalPythonTemplate = `# pip install 'git+https://github.com/Molecule-AI/molecule-sdk-python.git@main' +const externalPythonTemplate = `# pip install 'git+https://git.moleculesai.app/molecule-ai/molecule-sdk-python.git@main' import asyncio from molecule_agent import RemoteAgentClient, A2AServer @@ -307,7 +307,7 @@ if __name__ == "__main__": // A2A traffic into the running hermes gateway as platform messages // via the molecule-channel plugin. // -// The plugin (Molecule-AI/hermes-channel-molecule) is a hermes +// The plugin (molecule-ai/hermes-channel-molecule on Gitea) is a hermes // platform adapter that: // 1. Spawns ``python -m molecule_runtime.a2a_mcp_server`` as a // stdio MCP subprocess (separate from any hermes-side MCP @@ -336,7 +336,7 @@ const externalHermesChannelTemplate = `# Hermes channel — bridges this workspa # # 1. Install the runtime + plugin: pip install molecule-ai-workspace-runtime -pip install 'git+https://github.com/Molecule-AI/hermes-channel-molecule.git' +pip install 'git+https://git.moleculesai.app/molecule-ai/hermes-channel-molecule.git' # 2. Export the workspace credentials: export MOLECULE_WORKSPACE_ID={{WORKSPACE_ID}} @@ -366,7 +366,7 @@ hermes gateway --replace # by the plugin's molecule_runtime MCP subprocess). # # Source + issue tracker: -# https://github.com/Molecule-AI/hermes-channel-molecule +# https://git.moleculesai.app/molecule-ai/hermes-channel-molecule # Need help? # Documentation: https://doc.moleculesai.app/docs/guides/external-agent-registration diff --git a/workspace-server/internal/handlers/external_connection_test.go b/workspace-server/internal/handlers/external_connection_test.go index cd843693..0b9a0fa3 100644 --- a/workspace-server/internal/handlers/external_connection_test.go +++ b/workspace-server/internal/handlers/external_connection_test.go @@ -75,3 +75,46 @@ func TestExternalMcpTemplates_UseMoleculeMcpWrapper(t *testing.T) { } } } + +// TestExternalTemplates_NoBrokenMoleculeAIGitHubURLs pins the invariant +// that operator-facing snippets never embed github.com URLs pointing at +// Molecule-AI repos. +// +// Why: the Molecule-AI GitHub org was suspended 2026-05-06 and the +// canonical SCM is now git.moleculesai.app. Any `pip install +// git+https://github.com/Molecule-AI/...` or marketplace-add Molecule-AI/ +// URL emitted to an external operator hits a 404 / org-suspended page, +// breaking onboarding silently. RFC #229 P2-5. +// +// Third-party github URLs (gin, openai/codex, NousResearch/hermes-agent +// upstream issue trackers, npm @openai/codex) remain valid — only +// Molecule-AI/ paths are broken. +func TestExternalTemplates_NoBrokenMoleculeAIGitHubURLs(t *testing.T) { + templates := map[string]string{ + "externalCurlTemplate": externalCurlTemplate, + "externalChannelTemplate": externalChannelTemplate, + "externalUniversalMcpTemplate": externalUniversalMcpTemplate, + "externalPythonTemplate": externalPythonTemplate, + "externalHermesChannelTemplate": externalHermesChannelTemplate, + "externalCodexTemplate": externalCodexTemplate, + "externalOpenClawTemplate": externalOpenClawTemplate, + } + // Substrings that imply the snippet is pointing an operator at the + // suspended Molecule-AI GitHub org. + bannedSubstrings := []string{ + "github.com/Molecule-AI/", + "github.com/molecule-ai/", + // Bare `Molecule-AI/` form used by `/plugin marketplace add` + // resolves through GitHub by default — explicit Gitea URL is + // required post-suspension. + "marketplace add Molecule-AI/", + "marketplace add molecule-ai/", + } + for name, body := range templates { + for _, banned := range bannedSubstrings { + if strings.Contains(body, banned) { + t.Errorf("%s contains %q — Molecule-AI GitHub org is suspended; use git.moleculesai.app/molecule-ai/ instead (RFC #229 P2-5)", name, banned) + } + } + } +}