Skip to content

feat(guardrails): plan→auto chain + upstream sync infra + v1.4.1 merge#151

Merged
terisuke merged 27 commits intodevfrom
feat/plan-auto-chain
Apr 9, 2026
Merged

feat(guardrails): plan→auto chain + upstream sync infra + v1.4.1 merge#151
terisuke merged 27 commits intodevfrom
feat/plan-auto-chain

Conversation

@terisuke
Copy link
Copy Markdown

@terisuke terisuke commented Apr 9, 2026

Summary

Changes

Phase 1: Mode Accessibility (Issue #148)

  • .opencode/opencode.jsonc: Merged duplicate hooks keys (guardrails.sh was silently lost)
  • packages/guardrails/bin/opencode-guardrails: Added OPENCODE_EXPERIMENTAL_PLAN_MODE=true
  • packages/guardrails/profile/plugins/guardrail.ts: plan→auto chain in tool.execute.after with phase guard + try/catch
  • package.json: Added dev:guardrails script

Phase 2: Upstream Sync

  • .gitattributes: merge=ours for fork-only paths (hook, memory, guardrails, notification, etc.)
  • scripts/upstream-sync.sh: Automated selective merge script
  • FORK.md: Fork documentation
  • Merged 22 upstream commits, resolved 2 conflicts (processor.ts, prompt.ts)

Key Finding

hooks/memory/guardrails were never in upstream — they are 100% fork-only. Upstream never "removed" them.

Review

  • Double review: code-reviewer agent + Codex CLI (経路A)
  • Both flagged regex bypass + unconditional chain → both fixed
  • Regex: 9/9 test cases validated via Node.js
  • Build: bun turbo build pass, typecheck 13/13 pass

Test plan

  • bun dev:guardrails → TUI launches
  • /auto, /plan, /review, /ship visible in command list
  • /plan → plan agent → plan_exit → workflow_phase="implementing"
  • Hooks loaded: guardrails.sh + factcheck (write + edit)
  • Future upstream sync: ./scripts/upstream-sync.sh auto-protects fork paths

Closes #148

🤖 Generated with Claude Code

Brendonovich and others added 25 commits April 8, 2026 17:01
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
…nomalyco#19955)

Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: LukeParkerDev <10430890+Hona@users.noreply.github.com>
…c infra

- Fix duplicate hooks key in .opencode/opencode.jsonc (guardrails.sh was silently lost)
- Add OPENCODE_EXPERIMENTAL_PLAN_MODE to guardrails wrapper (enables PlanExitTool)
- Implement plan→auto chain in tool.execute.after (Issue #148) with phase guard + try/catch
- Improve redirect regex: /\s>\s*[\/~$._a-zA-Z]|^>/ — detects file redirects, avoids comparison false positives (9/9 tests)
- Add dev:guardrails script for local dev DX
- Add .gitattributes with merge=ours for fork-only paths (auto-protect during upstream merge)
- Add scripts/upstream-sync.sh for selective upstream merge automation
- Add FORK.md documenting fork-only systems and sync strategy

Closes #148

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merge upstream/dev (22 commits) using .gitattributes merge=ours for fork-only paths.
Fork-only systems (hook, memory, guardrails, notification) auto-protected.

Conflicts resolved manually:
- packages/opencode/src/session/processor.ts: kept both imports (fork repetition + upstream isRecord)
- packages/opencode/src/session/prompt.ts: kept fork memory injection + adopted upstream toModelMessagesEffect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 9, 2026 14:31
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

New PR opened -- automated review will run on the next push.

To trigger a manual review, comment /review on this PR.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

The following comment was made by an LLM, it may be inaccurate:

…sktop app

Desktop app and bare `opencode` CLI read commands from `.opencode/command/`
and agents from `.opencode/agent/`, NOT from the guardrails profile.
This caused /auto, /plan, /ship, etc. to be invisible outside the wrapper.

Fix: symlink 25 commands and 33 agents from guardrails profile into .opencode/
so they're available to ALL launch methods (desktop, CLI, wrapper).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR merges upstream v1.4.1 into the fork while adding fork-specific infrastructure for future upstream syncs and improving guardrails/workflow ergonomics (notably /plan/auto chaining), plus a set of server/tooling refactors and UI/test updates to match the new behaviors.

Changes:

  • Add upstream sync tooling (.gitattributes merge=ours + scripts/upstream-sync.sh) and document fork-only areas (FORK.md).
  • Improve runtime behavior around tools/workflows (Task tool refactor, abort propagation, provider-executed tool handling, /planimplementing chain).
  • Update server/desktop/web UI integration (Server.Default API shape, websocket proxying, new desktop-electron embedded server approach) and bump versions to 1.4.1.

Reviewed changes

Copilot reviewed 165 out of 171 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
sdks/vscode/package.json Bump VS Code extension version to 1.4.1.
scripts/upstream-sync.sh New selective upstream merge helper script.
packages/web/package.json Bump web package version to 1.4.1.
packages/util/package.json Bump util package version to 1.4.1.
packages/ui/src/components/session-turn.tsx Adjust sticky accordion offset.
packages/ui/src/components/session-turn.css Make diffs header sticky and adjust layout.
packages/ui/src/components/session-review.tsx Harden diffs input handling via type guards/normalization.
packages/ui/src/components/message-part.tsx Route apply_patch rendering through normalized patch file parsing.
packages/ui/src/components/apply-patch-file.ts New patch metadata normalizer to ViewDiff for UI diffs.
packages/ui/src/components/apply-patch-file.test.ts New unit tests for patch metadata parsing/legacy payloads.
packages/ui/package.json Bump UI package version to 1.4.1.
packages/slack/package.json Bump slack package version to 1.4.1.
packages/sdk/openapi.json Update OpenAPI schemas (assistant message shape, provider schema ref, provider config fields).
packages/sdk/js/src/v2/gen/types.gen.ts Regenerate SDK types to match OpenAPI updates (provider config, hooks/memory, response shapes).
packages/sdk/js/package.json Bump JS SDK version to 1.4.1.
packages/plugin/package.json Bump plugin package version to 1.4.1.
packages/opencode/test/tool/webfetch.test.ts Update webfetch tests to use Bun.serve and remove timeout test.
packages/opencode/test/tool/task.test.ts Expand Task tool tests (resume/create child, permission shaping, bypass checks).
packages/opencode/test/storage/json-migration.test.ts Update migration tests to pass drizzle DB (not raw sqlite client).
packages/opencode/test/session/prompt-effect.test.ts Refactor task tool mocking via ToolRegistry + add abort propagation tests for inline read tool.
packages/opencode/test/session/processor-effect.test.ts Add tests for text timing + interrupted tool metadata and cleanup behavior.
packages/opencode/test/session/message-v2.test.ts Add test to forward partial tool output on abort.
packages/opencode/test/session/compaction.test.ts Remove now-nonexistent processor.abort in fake.
packages/opencode/test/server/session-select.test.ts Adjust for Server.Default now returning object with .app.
packages/opencode/test/server/session-messages.test.ts Adjust for Server.Default now returning object with .app.
packages/opencode/test/server/session-actions.test.ts Adjust for Server.Default now returning object with .app.
packages/opencode/test/server/project-init-git.test.ts Adjust for Server.Default now returning object with .app.
packages/opencode/src/tool/tool.ts Improve Tool typing (InferDef, typed id for define/defineEffect, typed init).
packages/opencode/src/tool/task.ts Refactor Task tool to defineEffect; centralize parameters; Effect-based execution and improved session handling.
packages/opencode/src/tool/registry.ts Replace fromID with named tool access; pre-init builtins; add Agent layer dependency.
packages/opencode/src/tool/read.ts Simplify symlink stat handling with Effect.catch + void return.
packages/opencode/src/storage/json-migration.ts Change migration API to accept drizzle DB and run PRAGMA/transactions through it.
packages/opencode/src/shell/shell.ts Switch to internal which() and adjust Windows shell detection.
packages/opencode/src/session/retry.ts Export GO upsell message constant for reuse by TUI logic.
packages/opencode/src/session/prompt.ts Use ToolRegistry.named; improve read tool execution for file parts; avoid re-looping provider-executed tools; restructure ensuring/finalizers.
packages/opencode/src/session/processor.ts Track provider-executed tool metadata; preserve text start time; mark interrupted tools with metadata; change interrupt handling.
packages/opencode/src/session/message-v2.ts Strip providerExecuted from provider metadata; forward partial output for interrupted tool errors; propagate providerExecuted flag.
packages/opencode/src/session/llm.ts Add workflow model session context + approval handler wiring for tool approvals.
packages/opencode/src/session/compaction.ts Remove dependence on processor.abort for interrupts.
packages/opencode/src/server/server.ts Server.Default now returns server object; add auth_token query handling for basic auth; reorder imports.
packages/opencode/src/server/routes/session.ts Simplify prompt_async endpoint; update OpenAPI response schema to WithParts.
packages/opencode/src/server/routes/provider.ts Update provider route schema to Provider.Info.
packages/opencode/src/server/router.ts Pass upgrade into websocket proxy call.
packages/opencode/src/server/proxy.ts Move websocket upgrade wiring to injected UpgradeWebSocket (no bun-only upgradeWebSocket).
packages/opencode/src/server/instance.ts Switch embedded UI file serving to node fs + explicit mime type detection.
packages/opencode/src/provider/transform.ts Add big-pickle to variant bypass list.
packages/opencode/src/provider/provider.ts Ensure ModelsDev→Provider model conversion aligns with snapshot schema changes.
packages/opencode/src/provider/models.ts Remove options/headers/variants from ModelsDev.Model schema (align to upstream snapshot).
packages/opencode/src/provider/models-snapshot.d.ts New generated types for models snapshot.
packages/opencode/src/project/project.ts Simplify Effect.catch to Effect.void for project ID file read.
packages/opencode/src/plugin/index.ts Update server fetch usage to Server.Default().app.fetch.
packages/opencode/src/node.ts Export additional Node entrypoints (Config/bootstrap/Log/Database/JsonMigration).
packages/opencode/src/mcp/index.ts Simplify Effect.catch to Effect.void in MCP create.
packages/opencode/src/lsp/server.ts Narrow clangd root detection targets.
packages/opencode/src/lsp/index.ts Add root to “spawned lsp server” log.
packages/opencode/src/index.ts Pass drizzle DB to JsonMigration.run; other upstream merge adjustments.
packages/opencode/src/file/time.ts Simplify stat error handling to Effect.void.
packages/opencode/src/config/config.ts Rework Provider/Model schema definitions and provider options/whitelist/blacklist fields.
packages/opencode/src/cli/cmd/tui/worker.ts Update Server.Default fetch usage to .app.fetch.
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx Add Go upsell dialog trigger based on retry message.
packages/opencode/src/cli/cmd/tui/component/dialog-go-upsell.tsx New TUI dialog for Go upsell CTA.
packages/opencode/src/cli/cmd/run.ts Update Server.Default fetch usage to .app.fetch.
packages/opencode/src/cli/cmd/db.ts Pass drizzle DB to JsonMigration.run.
packages/opencode/script/generate.ts New script to generate models snapshot artifacts.
packages/opencode/script/build.ts Delegate models snapshot generation to generate.ts.
packages/opencode/script/build-node.ts Build node distribution into dist/node; generate snapshot; adjust externals/files.
packages/opencode/package.json Bump version to 1.4.1; update deps (node-pty via catalog, gitlab-ai-provider).
packages/opencode/.claude/state/tool-failure-counter.txt New Claude state artifact file (likely accidental commit).
packages/opencode/.claude/state/test-recommendation.json New Claude state artifact file (likely accidental commit).
packages/opencode/.claude/state/task-quality-gate.json New Claude state artifact file (likely accidental commit).
packages/opencode/.claude/state/runtime-reactive.jsonl New Claude state artifact file (likely accidental commit).
packages/opencode/.claude/state/breezing-timeline.jsonl New Claude state artifact file (likely accidental commit).
packages/opencode/.claude/sessions/.last_inbox_check New Claude state artifact file (likely accidental commit).
packages/guardrails/profile/plugins/guardrail.ts Tighten redirect regex and add plan_exit → implementing chain logic.
packages/guardrails/bin/opencode-guardrails Force-enable experimental plan mode for guardrails wrapper.
packages/function/package.json Bump function package version to 1.4.1.
packages/extensions/zed/extension.toml Bump Zed extension version + release URLs to 1.4.1 artifacts.
packages/enterprise/package.json Bump enterprise package version to 1.4.1.
packages/desktop/package.json Bump desktop package version to 1.4.1.
packages/desktop-electron/src/main/shell-env.ts Rename constants/functions and standardize log prefixes.
packages/desktop-electron/src/main/server.ts Replace sidecar CLI spawn with in-process virtual server module.
packages/desktop-electron/src/main/menu.ts Remove “Install CLI…” menu item.
packages/desktop-electron/src/main/ipc.ts Remove IPC handler for CLI installation.
packages/desktop-electron/src/main/index.ts Wire new server lifecycle; remove sidecar/CLI sync logic; disable embedded web UI.
packages/desktop-electron/src/main/env.d.ts Add virtual module typing for embedded server exports.
packages/desktop-electron/src/main/cli.ts Deleted: old sidecar/CLI install + spawn implementation.
packages/desktop-electron/scripts/prepare.ts Delegate to prebuild script; simplify prepare workflow.
packages/desktop-electron/scripts/predev.ts Build embedded server via opencode build-node script.
packages/desktop-electron/scripts/prebuild.ts New prebuild script (icons + build-node).
packages/desktop-electron/package.json Bump version; restructure deps/devDeps; add optional node-pty platform deps.
packages/desktop-electron/electron.vite.config.ts Add virtual server module resolver + copy wasm assets; narrow node-pty dependency by platform.
packages/desktop-electron/electron-builder.config.ts Remove extraResources for opencode-cli sidecar artifact.
packages/console/mail/package.json Bump console-mail version to 1.4.1.
packages/console/function/package.json Bump console-function version to 1.4.1.
packages/console/core/package.json Bump console-core version to 1.4.1.
packages/console/app/package.json Bump console-app version to 1.4.1.
packages/app/src/utils/diffs.ts New diff/summary normalization utilities for app UI.
packages/app/src/utils/diffs.test.ts Tests for diffs/message normalization utilities.
packages/app/src/pages/session.tsx Normalize session diffs and review diffs through shared utility.
packages/app/src/context/sync.tsx Sanitize incoming message summaries and normalize diffs before storing.
packages/app/src/context/global-sync/event-reducer.ts Normalize diffs and sanitize message.updated payloads.
packages/app/src/components/terminal.tsx Add cross-origin websocket auth_token support and same-origin detection.
packages/app/src/app.tsx Remove effectMinDuration usage from connection health check path.
packages/app/package.json Bump app package version to 1.4.1.
package.json Add dev:guardrails; add node-pty to workspace overrides.
nix/hashes.json Update Nix nodeModules hashes.
FORK.md New documentation for fork-only systems and upstream sync strategy.
bun.lock Lockfile updates for version bumps/deps reshuffling.
.opencode/opencode.jsonc Merge duplicate hooks keys; ensure guardrails hook retained.
.gitattributes New merge=ours rules for fork-only paths during upstream sync.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +291 to +297
if (await fs.exists(match)) {
const mime = getMimeType(match) ?? "text/plain"
c.header("Content-Type", mime)
if (mime.startsWith("text/html")) {
c.header("Content-Security-Policy", DEFAULT_CSP)
}
return c.body(await file.arrayBuffer())
return c.body(new Uint8Array(await fs.readFile(match)))
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node:fs/promises does not provide an exists() API, so await fs.exists(match) will throw at runtime and break embedded Web UI file serving. Use fs.access/fs.stat with try/catch (or existsSync from node:fs) to perform an existence check instead.

Copilot uses AI. Check for mistakes.
Comment on lines 53 to 60
if (c.req.method === "OPTIONS") return next()
const password = Flag.OPENCODE_SERVER_PASSWORD
if (!password) return next()
const username = Flag.OPENCODE_SERVER_USERNAME ?? "opencode"

if (c.req.query("auth_token")) c.req.raw.headers.set("authorization", `Basic ${c.req.query("auth_token")}`)

return basicAuth({ username, password })(c, next)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using auth_token as a query parameter to inject a Basic Authorization header can leak credentials via logs, browser history, proxies, and referrers. Consider scoping this to the WebSocket endpoints only and/or using a short-lived token mechanism (or a dedicated header/subprotocol) instead of passing credentials in the URL.

Copilot uses AI. Check for mistakes.
Comment on lines +524 to +527
next.searchParams.set("auth_token", btoa(`${username}:${password}`))
// For same-origin requests, let the browser reuse the page's existing auth.
next.username = username
next.password = password
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch sets both an auth_token query param and also embeds username/password into the WebSocket URL. If auth_token is the intended cross-origin auth mechanism, avoid also setting next.username/next.password (which can be exposed via URL inspection/debug tooling) and keep auth strictly in one place.

Suggested change
next.searchParams.set("auth_token", btoa(`${username}:${password}`))
// For same-origin requests, let the browser reuse the page's existing auth.
next.username = username
next.password = password
// For cross-origin requests, send auth only via the auth_token parameter.
next.searchParams.set("auth_token", btoa(`${username}:${password}`))

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
1 1775664051
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like local Claude runtime state/artifact and is likely not intended to be committed. Consider removing it from the repo and adding an ignore rule (e.g. **/.claude/) to prevent future accidental commits.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +7
{
"timestamp": "2026-04-08T16:02:47Z",
"changed_file": "/Users/teradakousuke/Developer/opencode/packages/guardrails/profile/plugins/guardrail.ts",
"test_command": "npm test",
"related_test": "",
"recommendation": "テストの実行を推奨します"
}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be local Claude runtime state/artifact and is likely not intended to be committed. Consider removing it from the repo and adding an ignore rule (e.g. **/.claude/) to prevent future accidental commits.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
{
"7": {
"failure_count": 0,
"last_action": "reset",
"updated_at": "2026-04-08T08:34:25Z"
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be local Claude runtime state/artifact and is likely not intended to be committed. Consider removing it from the repo and adding an ignore rule (e.g. **/.claude/) to prevent future accidental commits.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
{"event":"TaskCreated","timestamp":"2026-04-08T08:58:54Z","session_id":"185ec502-7ca0-4a88-8112-8389a55fa852","cwd":"/Users/teradakousuke/Developer/opencode/packages/opencode","file_path":"","previous_cwd":"","task_id":"8","task_title":""}
{"event":"TaskCreated","timestamp":"2026-04-08T08:58:57Z","session_id":"185ec502-7ca0-4a88-8112-8389a55fa852","cwd":"/Users/teradakousuke/Developer/opencode/packages/opencode","file_path":"","previous_cwd":"","task_id":"9","task_title":""}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be local Claude runtime state/artifact and is likely not intended to be committed. Consider removing it from the repo and adding an ignore rule (e.g. **/.claude/) to prevent future accidental commits.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
{"event":"task_completed","teammate":"","task_id":"7","subject":"Phase 3: Local deploy & firing verification","description":"Build the project, deploy locally, verify all new hooks fire correctly with actual plugin load log v","agent_id":"","agent_type":"","timestamp":"2026-04-06T11:10:19Z"}
{"event":"task_completed","teammate":"","task_id":"9","subject":"ビルド・発火検証・コミット・PR","description":"bun run build --single → wrapper 起動検証 → コミット → PR 作成 → マージ","agent_id":"","agent_type":"","timestamp":"2026-04-08T07:43:31Z"}
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be local Claude runtime state/artifact and is likely not intended to be committed. Consider removing it from the repo and adding an ignore rule (e.g. **/.claude/) to prevent future accidental commits.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
1775663913
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a machine-local timestamp file and is likely not intended to be committed. Consider removing it from the repo and adding an ignore rule (e.g. **/.claude/) to prevent future accidental commits.

Copilot uses AI. Check for mistakes.
Add scripts/link-guardrails.sh that symlinks guardrails profile commands
and agents into .opencode/ on every `bun install`. This ensures the
desktop app and bare `opencode` CLI always see all commands.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@terisuke terisuke merged commit 4408a3d into dev Apr 9, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(guardrails): /plan → /auto 自動連鎖 — ExitPlanMode 後に自律パイプラインを自動起動

9 participants