Address Greptile review feedback:
1. Wrap os.userInfo() in try/catch — it throws SystemError when the
current UID has no /etc/passwd entry (e.g. `docker run --user 1234`
with a minimal image). Falls back to process.env.HOME gracefully.
2. Add HOME to VOLATILE_ENV_KEY_EXACT so the discovery cache key is
not affected by the caller-supplied HOME vs the resolved HOME.
os.userInfo().homedir is constant for the process lifetime, so
HOME adds no useful cache differentiation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When Paperclip's server is started via `runuser -u node` (common in
Docker/Fly.io deployments), the HOME environment variable retains the
parent process's value (e.g. /root) instead of the target user's home
directory (/home/node). This causes `opencode models` to miss provider
auth credentials stored under the actual user's home, resulting in
"Configured OpenCode model is unavailable" errors for providers that
require API keys (e.g. zai/zhipuai).
Fix: use `os.userInfo().homedir` (reads from /etc/passwd, not env) to
ensure the child process always sees the correct HOME, regardless of
how the server was launched.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Decode HTML entities (e.g.  ) from title and description
before copying to clipboard, and trim trailing whitespace.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds a copy icon button to the left of the properties panel toggle
on the issue detail page. Clicking it copies a markdown representation
of the issue (identifier, title, description) to the clipboard and
shows a success toast. The icon briefly switches to a checkmark for
visual feedback.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Rearrange tabs to: Dashboard, Prompts, Skills, Configuration, Budget.
Move Prompt Template out of Configuration into a dedicated Prompts tab
with its own save/cancel flow and dirty tracking.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The execution workspace section wrapper div was rendered whenever a
project was selected, even when experimental workspaces were off.
The empty div's py-3 padding caused a visible layout bump. Now the
entire block only renders when currentProjectSupportsExecutionWorkspace
is true, and the redundant inner conditional is removed.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduce a singleton instance_settings store and experimental settings API, add the Experimental instance settings page, and gate execution workspace behavior behind the new enableIsolatedWorkspaces flag.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Same styling fix as NewIssueDialog — removes the rounded-md border
from the workspace toggle in the issue detail view.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Removes the rounded border around the execution workspace toggle section
and increases top/bottom padding for better visual spacing.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The zod schema validates archivedAt as a datetime string, but Drizzle's
timestamp column expects a Date object. The string was passed directly to
db.update(), causing a 500 error. Now we convert the string to a Date
in the route handler before calling the service.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When dragging or pasting an image into a markdown editor field, the cursor
would end up right next to the image making it hard to continue typing.
Now inserts two newlines after the image so a new paragraph is ready.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Headers were butting up against previous paragraphs too closely. Changed
rendered markdown header selectors from :where() to direct element selectors
to increase CSS specificity and beat Tailwind prose defaults. Bumped
margin-top from 1.15rem to 1.75rem. Also added top margins to MDXEditor
headers (h1: 1.4em, h2: 1.3em, h3: 1.2em) which previously had none.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap the browser alert dialog for an in-page confirm/cancel button pair.
Shows a loading spinner while the archive request is in flight, then the
redirect and toast (from prior commit) handle the rest.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The sticky float-right save/cancel bar was rendering (invisible via
opacity-0) on all tabs including runs, causing it to push the runs
layout content. Now only rendered when showConfigActionBar is true.
Also reverts the negative margin workaround from the previous attempt.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When no goals are linked, hide the "None" label and just show the
"+ Goal" button. When goals exist, add left margin to the button so
it doesn't crowd the goal badges.
Closes PAP-522
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously archiving a project silently navigated to /projects with no
feedback. Now it navigates to /dashboard and shows a success toast for
both archive and unarchive actions.
Closes PAP-521
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use negative right margin to counteract the Layout container padding,
giving the runs detail panel more horizontal space especially on
smaller screens.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename "List" tab to "Issues" and reorder: Issues, Overview, Configuration
- Cache the last active tab per project in localStorage
- On revisit, restore the cached tab instead of always defaulting to Issues
Closes PAP-520
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace break-all with <wbr> hints after / and - characters so paths
break at directory and word boundaries instead of mid-word
- Use overflow-wrap: anywhere as fallback for very long segments
- Apply natural breaking to the workspace name link as well
- Rename CopyablePath to CopyableValue with optional mono prop for
better semantic clarity
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Replace truncated paths with wrapping text (break-all) so full paths
are visible
- Add CopyablePath component with a copy icon that appears on hover and
shows a green checkmark after copying
- Apply to all workspace paths: cwd, branch name, repo URL, and the
project primary workspace fallback
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Display the absolute cwd path, branch name, and repo URL for the current
execution workspace in the issue properties panel. When no execution
workspace is active yet, show the project's primary workspace path as
a fallback.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Remove "Operator branch" and "Agent default" options from the workspace
mode dropdown in both NewIssueDialog and IssueProperties, keeping only
"Project default", "New isolated workspace", and "Reuse existing workspace"
- Deduplicate reusable workspaces by space identity (cwd path) so the
"choose existing workspace" dropdown shows unique worktrees instead of
duplicate entries from multiple issues sharing the same local folder
Co-Authored-By: Paperclip <noreply@paperclip.ing>
clearRepoWorkspace was calling updateWorkspace to null out the repo
even when there was no local folder, leaving an empty workspace.
Now falls through to persistCodebase which correctly removes the
entire workspace when both cwd and repoUrl would be null.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The invalidateProject() in ProjectProperties only invalidated
queryKeys.projects.detail(project.id) (UUID), but the parent
ProjectDetail query uses routeProjectRef which is typically the
URL key (e.g. "openclaw-testing"). This meant mutations succeeded
but the parent query was never refetched — the UI only updated on
page refresh.
Now also invalidates via project.urlKey so both UUID and URL-key
based query caches are cleared.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Allow saving empty values to clear repo URL or local folder from an existing workspace
- submitLocalWorkspace/submitRepoWorkspace now handle empty input as a "clear" operation
- Save button is only disabled for empty input when there's no existing workspace to clear
- removeWorkspace.onSuccess now resets form state (matching create/update handlers)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- When no goals are linked, just show the "+ Goal" button without
displaying "None" text
- Add left margin to the "+ Goal" button when goals exist above it
for better visual spacing
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The archive mutation lacked user feedback:
- No toast notification on success/failure
- Navigated to /projects instead of /dashboard after archiving
- No error handling if the API call failed
Added success/error toasts using the existing ToastContext, navigate
to /dashboard after archiving (matching user expectations), and error
toast on failure.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>