* feat(daemon): bound daemon.log size with rotation (MUL-4330)
The background daemon redirected its stdout/stderr into daemon.log opened
O_APPEND and never rotated it, so the file grew without limit until it was
too large to open. Every structured log line already flows through slog
(including agent subprocess stderr, forwarded via newLogWriter), so the
daemon's logger is effectively the sole author of the file's volume.
Route the foreground daemon's slog output — both the injected component
logger and the package-global slog default — through a size-based rotating
writer (lumberjack) that keeps the active daemon.log small (20MB default,
5 gzip-compressed backups, 30d), all env-overridable. Raw crash output
(Go runtime panics, pre-logger errors) now goes to a separate daemon.err.log
so the child's inherited fds never hold daemon.log open, which would block
rotation's rename on Windows.
The Desktop app spawns the daemon via this same launcher and its log tail
already handles size-shrink, so both CLI and Desktop are covered.
Co-authored-by: multica-agent <github@multica.ai>
* fix(daemon): address log-rotation review — foreground output, Windows handles, bounded err log (MUL-4330)
Resolves the blocking review items on the daemon.log rotation change:
1. Windows first-upgrade rotation: a foreground managed daemon now re-points
its own stdout/stderr to daemon.err.log at startup (SetStdHandle) before
building the rotator, releasing any daemon.log handle an older self-update
launcher inherited (Go opens files without FILE_SHARE_DELETE, which would
otherwise block rename-on-rotate). No-op on Unix, where an open fd never
blocks rename.
2. `daemon logs -f` vs rotation: Unix uses `tail -F` (reopen by name); Windows
opens the reader with FILE_SHARE_DELETE so it can't block the rotator's
rename, and reopens the file on size-shrink to follow across rotation.
3. Self-update handoff no longer briefly runs two rotators on one file: the old
process closes its rotator and moves remaining handoff logs (incl. the slog
default) to the crash sink before the successor starts.
4. daemon.err.log is now bounded: it rolls to a single ".1" backup once past
5MB at open time, so a crash loop can't move the growth problem to it. It is
also surfaced in the troubleshooting docs.
5. Explicit `--foreground` in a terminal keeps live stdout/stderr logging (a
documented debugging path); only detached/background children rotate into
daemon.log. Decided by whether stderr is a terminal.
Also: rotation env knobs now reject 0/negative (0 means 100MB / keep-all in
lumberjack), preventing an accidental unbounded config. Adds unit tests for
the err-log rolling and positive-int parsing; Windows/Linux(arm64) cross-builds
and `GOOS=windows go vet` pass.
Co-authored-by: multica-agent <github@multica.ai>
* docs: sync zh/ja/ko troubleshooting with daemon.log rotation + daemon.err.log (MUL-4330)
Co-authored-by: multica-agent <github@multica.ai>
* test(handler): bump the agent's own runtime version in quick-create parent test (MUL-4330)
TestQuickCreateIssueParentTrustBoundary bumped an arbitrary `LIMIT 1`
agent_runtime, but the handler version-checks agent.RuntimeID — the runtime
bound to the request's agent. In the shared handler test workspace, other
tests register additional runtimes, so the two diverge and the agent's real
runtime keeps the seed's empty cli_version, tripping the daemon-version gate
(422 daemon_version_unsupported) before the parent_issue_id assertions run.
Bump the runtime tied to the agent instead, making the setup deterministic.
Co-authored-by: multica-agent <github@multica.ai>
---------
Co-authored-by: J <j@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
* fix(create-issue): preserve parent_issue_id through Create with agent flow (MUL-2534)
When the create-issue modal was opened from the "Add sub issue" entry on
an existing issue and the user switched to "Create with agent", the
parent_issue_id was silently dropped: switchToAgent only forwarded
prompt + actor + project_id, the AgentCreatePanel had no notion of
parent context, and the daemon prompt never instructed the agent to
pass --parent <uuid>. The sub-issue intent was lost and the new issue
landed as a standalone.
This fix threads parent_issue_id through the whole pipeline silently —
no new editable form field, the existing carry channel handles it:
- Frontend: ManualCreatePanel.switchToAgent + AgentCreatePanel.switchToManual
now carry parent_issue_id (and identifier, for display) so the sub-issue
intent survives mode flips in either direction. AgentCreatePanel reads
parent from `data`, forwards to api.quickCreateIssue, and renders a
read-only "Sub-issue of MUL-XX" chip so the user can see the relationship.
- API: quickCreateIssue accepts optional parent_issue_id.
- Backend: QuickCreateIssueRequest validates parent_issue_id belongs to the
same workspace (same path as CreateIssue), persists it in
QuickCreateContext, and the daemon claim handler resolves the parent's
identifier for prompt context.
- Daemon prompt: when ParentIssueID is set, buildQuickCreatePrompt instructs
the agent to pass `--parent <uuid>` and treat the modal entry point as
authoritative.
Tests cover all three hops: switchToAgent carry payload, AgentCreatePanel →
api.quickCreateIssue, and the daemon prompt's --parent injection (with both
identifier-present and UUID-only fallback branches).
Co-authored-by: multica-agent <github@multica.ai>
* test(create-issue): cover quick-create parent trust boundary + identifier fallback (MUL-2534)
Address review on PR #3083:
- Add server-side test for POST /api/issues/quick-create parent_issue_id:
same-workspace parent threads through QuickCreateContext.ParentIssueID,
foreign-workspace and bogus UUIDs return 400 and never enqueue a task.
- Fall back to `data.parent_issue_identifier` in ManualCreatePanel's
switchToAgent when the parent detail query hasn't hydrated yet, so the
agent chip never renders "Sub-issue of " with an empty tail.
Co-authored-by: multica-agent <github@multica.ai>
---------
Co-authored-by: multica-agent <github@multica.ai>