Post-review fixes on top of the quality-pass-2 branch.
1. delegation.go: replaced insertDelegationRow's (bool, bool) return
with a typed insertDelegationOutcome enum (insertOK /
insertHandledByIdempotent / insertTrackingUnavailable). Eliminates
the positional-boolean decoding the caller had to do. Internal, no
behavior change.
2. ConfirmDialog.tsx: added singleButton prop. When true, hides the
Cancel button for single-action info toasts (Esc still dismisses
via onCancel). TemplatePalette's import notice uses it.
3. ErrorBoundary.tsx: fixed the floating clipboard promise. Added
.catch(() => {}) so a rejected writeText (permission denied,
insecure context) doesn't surface as unhandled rejection.
4. a2a_proxy_test.go: added 5 direct unit tests for
normalizeA2APayload (invalid JSON, wraps-bare, preserves-existing-
id, preserves-existing-messageId, missing-method). Fills the unit-
test gap for the helper extracted in the last pass.
Verification:
- go test -race ./internal/handlers/... passes (incl. 5 new tests)
- go build ./... clean
- canvas npm run build clean
- canvas npm test -- --run -> 352/352
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Second-pass cleanup after the monolith split. Addresses every issue
from the code-review pass.
Core additions in src/api.ts:
- toMcpResult(data) + toMcpText(text): single source of truth for the
MCP text-content envelope (was ~87 duplicated literals)
- ApiError type + isApiError(v) guard: typed discriminated-union for
the error-by-value pattern; replaces open-coded shape checks
- apiCall<T = unknown>: generic so callers can document expected
response shape without unchecked "as" casts
Bulk cleanups across all 12 tools/*.ts:
- Every handler now returns toMcpResult(data) or toMcpText(text)
- Open-coded "typeof obj === 'object' && 'error' in obj" in
remote_agents.ts replaced with isApiError(v)
- Extracted initialCanvasPosition() helper out of
handleCreateWorkspace; explains why random seeding exists
- Added runtime/workspace_dir/workspace_access to create_workspace
zod schema (previously accepted by handler but hidden from clients)
src/index.ts:
- Replaced "export * from" with explicit named re-exports so the
public surface is auditable and future name collisions fail loudly
Tests:
- createServer() smoke test that records every srv.tool(...) call and
asserts 87 registered tools unique by name. Catches future PRs that
forget to wire a registerXxxTools(srv).
Docs:
- Fix broken relative links in sdk/python/molecule_agent/README.md
(was ../../examples/ from inside sdk/python/, should be ../examples/)
- Update stale "61 tools" -> "87 tools" in CLAUDE.md + main() log
Verification:
- npm run build clean
- npx jest -> 97/97 passed (was 96; +1 smoke test)
- grep "content: [{ type: \"text\" as const" src/tools/ -> 0 matches
- No file over 216 lines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Second-pass cleanup after the monolith split. Addresses every issue
from the code-review pass.
Core additions in src/api.ts:
- toMcpResult(data) + toMcpText(text): single source of truth for the
MCP text-content envelope (was ~87 duplicated literals)
- ApiError type + isApiError(v) guard: typed discriminated-union for
the error-by-value pattern; replaces open-coded shape checks
- apiCall<T = unknown>: generic so callers can document expected
response shape without unchecked "as" casts
Bulk cleanups across all 12 tools/*.ts:
- Every handler now returns toMcpResult(data) or toMcpText(text)
- Open-coded "typeof obj === 'object' && 'error' in obj" in
remote_agents.ts replaced with isApiError(v)
- Extracted initialCanvasPosition() helper out of
handleCreateWorkspace; explains why random seeding exists
- Added runtime/workspace_dir/workspace_access to create_workspace
zod schema (previously accepted by handler but hidden from clients)
src/index.ts:
- Replaced "export * from" with explicit named re-exports so the
public surface is auditable and future name collisions fail loudly
Tests:
- createServer() smoke test that records every srv.tool(...) call and
asserts 87 registered tools unique by name. Catches future PRs that
forget to wire a registerXxxTools(srv).
Docs:
- Fix broken relative links in sdk/python/molecule_agent/README.md
(was ../../examples/ from inside sdk/python/, should be ../examples/)
- Update stale "61 tools" -> "87 tools" in CLAUDE.md + main() log
Verification:
- npm run build clean
- npx jest -> 97/97 passed (was 96; +1 smoke test)
- grep "content: [{ type: \"text\" as const" src/tools/ -> 0 matches
- No file over 216 lines
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The get_remote_agent_setup_command handler emitted
\`python3 -m examples.remote-agent.run\` — an invalid Python module path
(dashes not allowed in module names), so the command never actually
worked. Replace with a direct \`python3 -c "..."\` snippet that imports
from \`molecule_agent\` (the real SDK module) and points to the demo
script for reference.
Fixes the pre-existing jest failure in \`handleGetRemoteAgentSetupCommand
emits bash for external workspace\` that was flagged against PR #2.
Updates test expectation to \`molecule_agent\` (the actual importable
module name) from the never-valid \`molecule-agent\`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The get_remote_agent_setup_command handler emitted
\`python3 -m examples.remote-agent.run\` — an invalid Python module path
(dashes not allowed in module names), so the command never actually
worked. Replace with a direct \`python3 -c "..."\` snippet that imports
from \`molecule_agent\` (the real SDK module) and points to the demo
script for reference.
Fixes the pre-existing jest failure in \`handleGetRemoteAgentSetupCommand
emits bash for external workspace\` that was flagged against PR #2.
Updates test expectation to \`molecule_agent\` (the actual importable
module name) from the never-valid \`molecule-agent\`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete empty platform/plugins/ (dead remnant; plugins/ at repo root is
the real registry; router.go comment updated)
- Gitignore local dev cruft: platform/workspace-configs-templates/,
.agents/ (codex/gemini skill cache), backups/
- Untrack .agents/skills/ (keep local, stop tracking)
- Move examples/remote-agent/ → sdk/python/examples/remote-agent/
(co-locate with the SDK it exercises); update refs in
molecule_agent README + __init__ + PLAN.md + the demo's own README
- Move docs/superpowers/plans/ → plugins/superpowers/plans/
(plans were written by the superpowers plugin's writing-plans
subskill; belong with the plugin, not under docs)
- Add tests/README.md explaining the unit-tests-per-package +
root-E2E split so new contributors don't ask
- Add docs/README.md explaining why site tooling lives under docs/
rather than a separate docs-site/ (VitePress ergonomics)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete empty platform/plugins/ (dead remnant; plugins/ at repo root is
the real registry; router.go comment updated)
- Gitignore local dev cruft: platform/workspace-configs-templates/,
.agents/ (codex/gemini skill cache), backups/
- Untrack .agents/skills/ (keep local, stop tracking)
- Move examples/remote-agent/ → sdk/python/examples/remote-agent/
(co-locate with the SDK it exercises); update refs in
molecule_agent README + __init__ + PLAN.md + the demo's own README
- Move docs/superpowers/plans/ → plugins/superpowers/plans/
(plans were written by the superpowers plugin's writing-plans
subskill; belong with the plugin, not under docs)
- Add tests/README.md explaining the unit-tests-per-package +
root-E2E split so new contributors don't ask
- Add docs/README.md explaining why site tooling lives under docs/
rather than a separate docs-site/ (VitePress ergonomics)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure mechanical split, no behavior changes. Pulls the 70+ tool handlers
out of one monolith into api.ts (PLATFORM_URL + apiCall) plus 12
tools/*.ts files grouped by domain (workspaces, agents, secrets, files,
memory, plugins, channels, delegation, schedules, approvals, discovery,
remote_agents). Each module exports its handlers and a
registerXxxTools(srv) function; createServer() wires them up.
index.ts drops from 1697 → 89 lines. Largest new file is 183 lines.
All handlers still re-exported from index.ts so existing tests that
import them via "../index.js" keep working. Build clean; jest results
unchanged from pre-refactor baseline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure mechanical split, no behavior changes. Pulls the 70+ tool handlers
out of one monolith into api.ts (PLATFORM_URL + apiCall) plus 12
tools/*.ts files grouped by domain (workspaces, agents, secrets, files,
memory, plugins, channels, delegation, schedules, approvals, discovery,
remote_agents). Each module exports its handlers and a
registerXxxTools(srv) function; createServer() wires them up.
index.ts drops from 1697 → 89 lines. Largest new file is 183 lines.
All handlers still re-exported from index.ts so existing tests that
import them via "../index.js" keep working. Build clean; jest results
unchanged from pre-refactor baseline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two copyright/use-grant lines still referenced the pre-rebrand legal
entity name. Aligns LICENSE with the brand mapping in HANDOFF.md §2.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Swap in the new molecular-graph icon across canvas favicon, in-app logo,
and README branding paths. Add HANDOFF.md as the cross-session context
doc carried over from the Starfire→Molecule AI migration. Fix stale
"Starfire" reference in the pre-commit hook header.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>