* docs(agents): add step-by-step workflows with posting and label procedures
Add numbered step-by-step workflows to all four automation agents
(pr-review, reproduce-issue, summarize, triage), each with an explicit
comment-posting sub-procedure: draft once, post via gh, capture result,
verify by reading comments back only, and retry once on failure.
pr-review also gains a Labels section that applies confidence:* and
risk:* labels matching the review scores, removing stale labels first
to avoid stacking. merge-conflict:true is left to its dedicated action.
triage renames its label-selection steps to Category 1-5 to avoid
colliding with the new workflow step numbering.
* fix(agents): avoid duplicate comments after ambiguous posts
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Adds label-merge-conflict workflow using eps1lon/actions-label-merge-conflict
to label PRs with merge-conflict:true when they have conflicts. Triggers on
push to main, pull_request_target (opened/synchronize/reopened), and manual
dispatch. Uses the bot app token for label writes and is scoped to the
openchamber/openchamber repo.
* perf(stores): defer safeStorage writes off the interaction path
Session switches funnel every persisted store slice through safeStorage.setItem,
and doing those large JSON.stringify writes synchronously blocked the main
thread for over a second. Add a write-behind buffer that:
- Defers each setItem/removeItem to a later task via setTimeout(0) so the
click-to-paint path is not blocked.
- Coalesces repeated writes to the same key into a single backing flush.
- Serves pending values from memory so read-after-write stays consistent
within the deferral window.
- Flushes synchronously on pagehide/beforeunload/visibilitychange/freeze so
deferred state survives tab close, reload, and the mobile freeze lifecycle.
Adds a test covering write deferral, coalescing, and pending read serving.
* fix(stores): defer persisted JSON serialization
* fix(stores): defer direct safeStorage writes
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
The stale-event check excluded heartbeats from lastActiveEventAt, so a
quiet-but-connected session (only receiving heartbeats) tripped the 20s
stale timer and triggered a full resync every ~15s. This re-fetched
listPendingQuestions, listPendingPermissions, session.get, and
session.messages despite the event stream being healthy.
Track all stream activity (including heartbeats) in a global
lastStreamActivityAt ref. The stale check now only fires when no events
at all arrive for 20s, meaning the stream is genuinely dead.
Resyncs still fire correctly on genuine reconnects, transport switches,
and status-poll escalation when a real discrepancy is detected.
Fixes#1656
Sending a message while a question prompt was open left the prompt
lingering, blocked the send, or collided with the still-blocked agent
turn. Two root causes:
useSessionActivity treated pending permissions as idle but not pending
questions, so the send button became Stop during a question and Enter
queued/collided instead of sending. handleSubmit also never dismissed
the open question, stranding the session in a half-answered state.
The send path now dismisses open questions for the session subtree
(optimistic local clear so the card vanishes instantly, plus a formal
question.reject) and queues the message. The queued-message auto-send
hook then delivers it as the next turn once the rejected turn winds
down and the session returns to idle. Queueing avoids aborting the
turn, which surfaced an unwanted "running turn was stopped" notice.
Regression tests cover the no-op, subtree dismissal (root + subagent
child), and QuestionNotFoundError paths.
Adds a 'Cron' schedule type option to the scheduled task editor, allowing
users to create and edit cron-based schedules through the UI.
- Add cron expression input with inline validation (cron-parser)
- Show next 4 upcoming run times as a preview
- Provide clickable example chips (every 5min, hourly, Monday 9am, etc.)
- Preserve cron expressions when editing existing cron tasks
- Add cron.ts utility module for validation and next-run computation
- Add i18n keys across all 8 locale files
Closes#1586
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* fix: pass effective workspace directory in Files API requests
The web Files API used useDirectoryStore.currentDirectory as the
workspace root, but the FilesView's effective directory comes from
useEffectiveDirectory() which can differ (e.g. worktree sessions).
When they diverged the server rejected file reads with 'Path is
outside of active workspace'.
Add directory override to FileReadOptions so callers can pass the
effective directory per-call. The FilesView now passes its root
(from useEffectiveDirectory) through readFile, statFile, image/PDF
URLs, and the desktop image fallback. The server receives the
correct workspace root via x-opencode-directory header or directory
query parameter.
Fixes#1456
* fix: cover files workspace directory regressions
* fix: sync directory store on draft session and forward cache options
The content cache wrapper in RuntimeAPIProvider was dropping the
options parameter (including the per-call directory override) when
making internal statFile and readFreshFile calls during cache
validation and misses. This caused the underlying web API to fall
back to getDirectory() which reads useDirectoryStore.currentDirectory.
Additionally, openNewSessionDraft, setNewSessionDraftTarget, and
overrideNewSessionDraftTarget updated the draft's directory without
ever syncing useDirectoryStore. Since the web API's getDirectory()
reads from that store, it returned the stale previous-project
directory during draft sessions, causing 'Path is outside of active
workspace' errors when opening files.
Forward options through all internal calls in the content cache
wrapper, and sync useDirectoryStore via setDirectory() whenever the
draft session directory changes.
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
The worktree dialog state was local React state in SessionSidebar,
which gets destroyed when the component unmounts (mobile drawer close,
VSCode view switch). This caused the modal to briefly appear then
disappear.
Three changes:
- Move newWorktreeDialogOpen from local state to useUIStore so it
survives component unmount
- Guard useProjectSessionSelection layout effect to skip when the
worktree dialog is open (prevents auto-session-selection from
closing the sidebar)
- Remove setSessionSwitcherOpen(false) from worktree button handler
on mobile (prevents drawer close that unmounts the sidebar)
Fixes#1414
* repro: add test reproducing issue #1564 - empty branch list in create worktree dialog
The NewWorktreeDialog does not auto-fetch branches when it opens
if branches haven't been cached yet. Branches only get populated
if the Git tab has been opened or a draft session has been started,
both of which call fetchBranches/fetchAll independently.
The test demonstrates:
1. Branches are null (empty list) for directories not yet fetched
2. Branches are available after fetchBranches is called
3. The ChatInput's draft session branch fetch explains why the
issue says 'list gets populated after starting a draft session'
4. The missing auto-fetch call when dialog opens
* fix: auto-fetch branches when opening create worktree dialog
---------
Co-authored-by: Reproduction Bot <repro-bot@openchamber.dev>
Adds `gh` CLI as a GitHub credential fallback for users who already have
`gh auth login` configured locally. OpenChamber-owned OAuth credentials
remain the primary source of truth; the `gh` token is only used when no
stored OpenChamber GitHub access token exists and the fallback is not
disabled.
The fallback is implemented as a credential provider only: GitHub features
continue to use the existing Octokit/GitHub API paths for issues, pull
requests, checks, merges, and related operations. The PR does not replace
those endpoints with `gh issue` or `gh pr` CLI commands.
Server changes:
- Add `gh-cli-credential.js` to read `gh auth token` with a bounded timeout.
- Cache the `gh` token lookup for 30 seconds, including negative results,
to avoid repeated subprocess spawning on status/polling paths.
- Hide the subprocess window on Windows via `windowsHide: true`.
- Clear the gh CLI token cache when the fallback setting changes.
- Update `getOctokitOrNull()` to prefer stored OpenChamber OAuth tokens and
fall back to the `gh` token only when enabled.
- Add `ghCliDisabled` persistence in the existing settings file with atomic
writes and `0o600` file permissions.
- Add `POST /api/github/auth/gh-cli` to enable or disable the fallback.
- Extend `/api/github/auth/status` with `ghCli` metadata: availability,
disabled state, active state, and active user when applicable.
UI/runtime changes:
- Extend `GitHubAuthStatus` and `GitHubAPI` with gh CLI fallback metadata
and toggle support.
- Add web RuntimeAPI support for toggling the gh CLI fallback through
`runtimeFetch`, preserving active runtime/remote target behavior.
- Add deterministic VS Code unsupported handling for the gh CLI toggle.
- Update GitHub Settings to show gh CLI availability and active status.
- When gh CLI is the active auth source, show it in the connected account
card and offer Disable instead of Disconnect.
- Keep Add Account available so users can still connect an OpenChamber OAuth
account, which then takes priority over gh CLI.
- Add localized gh CLI settings strings across supported settings locales.
Fixes addressed during review:
- Removed unreachable UI branches in the inactive gh CLI card.
- Avoided duplicate and repeated `gh auth token` subprocess calls.
- Hardened settings file permissions for the new persisted flag.
- Routed the gh CLI toggle through the RuntimeAPI/runtimeFetch path instead
of direct browser `fetch`.
- Added targeted tests for hidden subprocess options and negative-result
cache behavior.
- Fixed a VS Code webview Response body typing issue that blocked type-check.
Replace local-only filtering in GitHub issue/PR picker dialogs with
server-side GitHub Search API queries. Search text is sent as a query
parameter to the server, which uses the GitHub Search API
(issuesAndPullRequests endpoint) with repo: qualifiers including fork
network support. Results are debounced at 350ms to respect API rate
limits.
- Add query parameter to GitHubAPI issuesList/prsList interface
- Server routes use Search API when query is present, standard list
endpoint when absent
- Fork networks handled via repo:owner/repo OR repo:owner/upstream
- PR search fetches full PR details after Search API for head/base/draft
fields
- Remove local filter memos from all three picker dialogs
- Add debounced search effect with abort controller cleanup
- Update VS Code backend and webview API for parity
- Update search placeholders in all locales
Closes#1350
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>