Show the running instance's local server URL and tunnel URL (when a
tunnel is active) as labeled, click-to-open buttons on the About page.
/api/system/info now reports the instance port and tunnel URL, resolved
lazily from the tunnel runtime so each Git-worktree instance identifies
itself in the UI without parsing terminal output.
Refs OPE-194
adm-zip <0.6.0 allows a crafted ZIP to trigger a ~4GB memory
allocation (GHSA-xcpc-8h2w-3j85). Bump the dependency in the web
and vscode packages to ^0.6.0. The new AdmZip(buffer) and
extractAllTo(dir, overwrite) APIs are unchanged, so no call-site
adaptation is needed.
Add a vitest regression test for the ClawdHub install path that
builds a real ZIP with adm-zip and asserts extractAllTo restores
files (including nested subdirectories) into the target skill dir.
Native HTML5 drag starts after ~4px of pointer travel and suppresses the
click event for the gesture, so the draggable sidebar file tree rows
randomly ignored clicks on macOS trackpads/Magic Mouse: folders neither
expanded nor collapsed and files did not open.
Keep the rows draggable (dragging a file into the chat input inserts an
@mention) and recover the suppressed click on dragend: a drag that ended
within a small slop radius of its origin without dropping anywhere runs
the row's primary action. Also drop the misleading grab cursor so rows
read as clickable, matching FilesView.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
When a document (PPTX, DOCX, XLSX, ODP, ODT, ODS) is attached,
extracted slide images were left orphaned after removing the
parent text entry. This adds a sourceDocumentId field to
AttachedFile that links all entries from the same document
extraction, and cascades removal of all entries in the group
when any one is removed.
Fixes#2426
Co-authored-by: chiamsun <chiamsun@users.noreply.github.com>
The queue auto-send gate treated a missing session status entry as idle,
but the server's /session/status map only lists busy/retry sessions — a
missed busy event leaves no entry while a turn is still streaming. On a
client that missed the busy event (e.g. mobile reconnect window), queued
follow-ups were dispatched into the running turn; OpenCode then merged
both prompts into one model response instead of serializing them.
Extract resolveQueuedSessionStatusType and mirror useSessionActivity's
fallback: a trailing in-flight assistant message means the session is
still busy, so the queue waits for the real idle edge. Subscribe the
effect to messages so the queue drains as soon as the turn completes
even when status events were missed.
PR #2520fixed#2475 in the wrong layer (overflow classes on
SettingsView.tsx wrapper divs that aren't the actual scroll containers),
so the "no scrollbar in Settings" bug shipped in v1.17.2 unchanged, and
the sessions feed has the same underlying issue (#2402).
The actual scroll containers render through ScrollableOverlay ->
OverlayScrollbar, which hides the native scrollbar and draws its own
JS thumb that auto-hides ~1s after scroll activity stops, with a
second CSS rule fully hiding that thumb inside Settings specifically.
Fix both at the shared component/CSS layer so every consumer (Settings,
sessions feed, git panels, chat, etc.) gets a persistent scrollbar on
desktop shells (Electron + VS Code webview) in one change:
- OverlayScrollbar.tsx: skip the auto-hide timer and show the thumb
immediately on mount when content overflows, on desktop runtimes.
userIntentOnly consumers (chat auto-follow scroll, reasoning blocks)
keep today's intent-gated behavior unchanged.
- index.css: scope the Settings-specific hide rule to non-desktop, so
mobile/web keep existing behavior and desktop gets the thumb back.
User-facing onboarding for markdown loop tasks: where .agents/loops
files live (project + user scope), a copy-paste sample file, the
frontmatter field table, and the behavior contract (file authoritative,
off by default, rename/malformed semantics, run-now still available).
Also lists the cron schedule type in the UI task creation steps, which
the page previously omitted.
Review follow-up:
- runtime.test.js: add syncProject wiring tests with a real temp-dir
project and real project-config runtime — asserts reconcileLoopTasks is
driven with the discovered loops when the project path is known (task
created, nextRunAt computed) and that plain listing is used when the
path cannot be resolved (reconcile not called).
- service.js: DELETE on a loop-owned task is rejected with a 400 only
while its loop file still exists on disk; once the file is gone the
orphan task can be deleted directly instead of waiting for the next
reconcile. Tests use real temp files for both branches.
- DOCUMENTATION.md: delete semantics updated accordingly.
- PR description refreshed for the final HEAD (test counts, reconciliation
contract, evidence wording).
Review follow-up:
- Reject loop files whose frontmatter name exceeds MAX_TASK_NAME_LENGTH
(80): task names are clamped at storage time, so a raw name longer than
the limit could never match the stored task identity. The file is treated
as malformed (definition: null) instead of creating an unreachable
definition; MAX_TASK_NAME_LENGTH is now exported from project-config.js
and shared with loops.js.
- Surface loop-sourced tasks in the scheduled-tasks dialog: tasks carrying
loopFile show a 'Managed by loop file <path>' note, and the enable
toggle / edit / delete actions are disabled with an explanatory tooltip,
since the file remains authoritative and would revert any such change.
run-now stays available. New locale keys added to all 11 message files
(i18n parity test enforces exact key sets).
- ScheduledTask type gains an optional loopFile field (additive, unknown
to older clients).
Review fixes for the markdown loop feature:
- Loop-owned tasks now adopt by loop file path, not task name, so renaming
a loop (frontmatter name or UI rename) renames the task in place instead
of leaving a stale duplicate that keeps running the old definition;
orphan duplicates of the same file are unscheduled.
- Unparseable loop files are reported to the scheduler as
definition:null entries: a task whose file still exists is kept with its
last good definition, and only a genuinely removed file unschedules it.
Transiently malformed files (mid-edit, bad merge) no longer delete tasks
or their runtime state.
- Adoption preserves UI-only execution fields (goalEnabled, goalTokenBudget,
permissionAutoAccept, variant) that the portable format does not define.
- DELETE on a loop-sourced task now returns 400 with guidance to remove the
loop file, instead of being silently undone by the next reconcile.
- Loops default to enabled: false; discovery of repository content never
auto-executes scheduled sessions unless the file explicitly enables them.
Regression tests for each fix; DOCUMENTATION.md updated.