Commit Graph

100 Commits

Author SHA1 Message Date
Bohan Jiang
2cd6024851 Merge pull request #820 from zoharbabin/feat/local-storage-and-stdin
feat(cli): add --content-stdin flag to issue comment add
2026-04-14 13:02:01 +08:00
Jiayuan Zhang
bc1185f525 Merge pull request #755 from sanjay3290/feat/gemini-backend
feat(daemon): add Google Gemini CLI backend
2026-04-14 02:46:20 +08:00
Jiayuan Zhang
ff5f6ac2ee fix(daemon): prevent duplicate runtime registration on profile switch (#906)
* fix(daemon): prevent duplicate runtime registration on profile switch

The daemon_id included a profile name suffix (e.g. "hostname-staging"),
so switching profiles created a new daemon_id that bypassed the UPSERT
dedup constraint, leaving orphaned runtime records in the database.

Three changes:
- Remove profile suffix from daemon_id — use stable hostname only.
  The unique constraint (workspace_id, daemon_id, provider) already
  prevents collisions within the same workspace.
- Auto-migrate agents from old offline runtimes to the newly registered
  runtime during DaemonRegister (same workspace/provider/owner).
- Add TTL-based GC in the runtime sweeper to delete offline runtimes
  with no active agents after 7 days.

Closes MUL-695

* fix(daemon): address code review issues on PR #906

1. Move gcRuntimes() to the main sweep loop — previously it was inside
   sweepStaleRuntimes() after an early return, so it only ran when new
   runtimes were marked stale. Now it runs every sweep cycle independently.

2. Fix DeleteStaleOfflineRuntimes to exclude runtimes with ANY agent
   reference (not just active ones). The FK agent.runtime_id is ON DELETE
   RESTRICT, so archived agents also block deletion.

3. Scope MigrateAgentsToRuntime to the same machine by matching
   daemon_id LIKE '<current_daemon_id>-%'. This prevents cross-machine
   agent migration when the same user has multiple devices.
2026-04-14 01:52:34 +08:00
Bohan Jiang
1d71df8622 fix(daemon): include dispatched agent identity in CLAUDE.md (#877)
When an agent is triggered via @mention (not as the issue assignee),
the generated CLAUDE.md had no explicit agent identity. The agent would
infer its identity from the issue's assignee field, causing it to skip
work intended for it.

Now CLAUDE.md always includes "You are: <agent-name> (ID: <agent-id>)"
so the agent knows exactly who it is regardless of the issue assignee.

Closes MUL-709
2026-04-13 22:46:36 +08:00
devv-eve
6c92108b09 fix: replace hardcoded Unix path separators with filepath.Join and os.TempDir (#860)
- cmd_daemon.go: use filepath.Join for PID/log file paths instead of string concat with "/"
- codex_home.go: use os.TempDir() instead of hardcoded "/tmp" for cross-platform fallback

Co-authored-by: Devv <devv@Devvs-Mac-mini.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 04:11:51 -07:00
LinYushen
526e336081 feat(execenv): add Windows fallback for symlink operations (#859)
On Windows, os.Symlink requires Developer Mode or admin privileges.
Extract symlink creation into platform-specific files: on non-Windows,
behavior is unchanged (os.Symlink). On Windows, try os.Symlink first,
then fall back to directory junctions (mklink /J) for dirs and file
copy for files.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:23:41 +08:00
yushen
2f1000d815 merge: resolve conflict with main (runTask refactor + mergeUsage)
Main introduced executeAndDrain/mergeUsage refactor. Resolve by keeping
main's refactored structure and re-applying EnvRoot to the switch/case
in runTask. Rename newTestDaemon → newGCTestDaemon to avoid collision
with the helper added in daemon_test.go on main.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:51:02 +08:00
Bohan Jiang
afab4dfdef Merge pull request #840 from multica-ai/agent/j/9cf0cf3e
fix(daemon): run repo cache sync in background to unblock heartbeat
2026-04-13 15:27:45 +08:00
Jiang Bohan
99e973ba3e fix(daemon): run repo cache sync in background to unblock heartbeat
The repoCache.Sync() call in loadWatchedWorkspaces runs synchronous git
clone/fetch operations that can take minutes for large repos. Because
heartbeatLoop and pollLoop only start after loadWatchedWorkspaces returns,
the runtime's last_seen_at is never updated during the sync, causing the
server's sweeper to mark it offline after 45 seconds.

Move repo cache sync to a background goroutine so heartbeat and poll
loops start immediately after runtime registration.

Closes #825
2026-04-13 15:19:02 +08:00
yushen
14beaa6ce2 fix(daemon): extract pruneWorktree helper for idiomatic defer cancel
The context cancel in pruneRepoWorktrees was called explicitly after
CombinedOutput inside a loop. Extract to a helper method so defer
cancel() works correctly (scoped to the function, not the loop).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:05:59 +08:00
yushen
20809052f5 fix(daemon): address GC review feedback
- Move WriteGCMeta from runTask() to handleTask() so it runs after
  task completion, not at start. Mid-task crashes leave orphan dirs
  that get cleaned by GCOrphanTTL.
- Strengthen isBareRepo to check both HEAD and objects/ directory.
- Remove empty workspace directories after all task dirs are cleaned.
- Add 30s context timeout to git worktree prune to prevent hangs.
- Add comprehensive unit tests for shouldCleanTaskDir (8 scenarios),
  cleanTaskDir, gcWorkspace empty-dir cleanup, isBareRepo, and
  WriteGCMeta/ReadGCMeta roundtrip.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:00:37 +08:00
LinYushen
265d1854c9 fix(daemon): add fallback for failed session resume (#818)
* fix(daemon): add fallback for failed session resume

When the daemon tries to resume a prior session (--resume flag for
Claude, --session for OpenCode, session/resume RPC for Hermes) and the
session no longer exists, the agent fails immediately. This adds a
fallback that retries the execution with a fresh session instead of
marking the task as blocked.

Extracts the execute+drain logic into a reusable executeAndDrain method
to avoid code duplication between the initial attempt and the retry.

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

* fix(daemon): narrow session resume retry and merge usage

Address review feedback:
1. Narrow retry trigger: only retry when result.SessionID == "" (no
   session was established), not on any failure with PriorSessionID set
2. Merge token usage from both attempts so billing is accurate
3. Log errors when the retry itself fails to start
4. Add unit tests for mergeUsage, fallback behavior, and no-retry
   when session was already established

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:47:24 +08:00
yushen
ff206baa6f feat(daemon): add periodic GC for workspace isolation directories
Isolation directories accumulate indefinitely because they're preserved
for session reuse but never cleaned up after the issue is closed.

This adds a background GC loop that periodically scans local workspace
directories and removes those whose issue is done/canceled and hasn't
been updated for 5 days (configurable via MULTICA_GC_TTL). Orphan
directories with no metadata are cleaned after 30 days.

Changes:
- Write .gc_meta.json (issue_id, workspace_id) at task completion
- Add GET /api/daemon/issues/{issueId}/gc-check endpoint for status queries
- Add gcLoop goroutine to daemon with configurable interval/TTL
- Prune stale git worktree references from bare repo caches each cycle
- New env vars: MULTICA_GC_ENABLED, MULTICA_GC_INTERVAL, MULTICA_GC_TTL,
  MULTICA_GC_ORPHAN_TTL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 14:46:48 +08:00
Bohan Jiang
c54f9a0bc4 Merge pull request #829 from multica-ai/agent/j/03e8009e
fix(daemon): embed triggering comment content in agent prompt
2026-04-13 14:36:21 +08:00
Jiang Bohan
93fffad82a fix(daemon): embed triggering comment content in agent prompt
When a task is triggered by a comment, the agent prompt now includes
the comment content directly. This prevents the agent from ignoring
the comment when stale output files exist in a reused workdir.

Closes #805
2026-04-13 14:20:26 +08:00
Jiang Bohan
2ea778796a feat(daemon): add token usage log scanning for OpenCode, OpenClaw, and Hermes runtimes
Previously only Claude and Codex had log-scanning-level token usage
reporting (Flow B). This adds scanners for the remaining three runtimes:

- OpenCode: reads JSON message files from ~/.local/share/opencode/storage/message/
- OpenClaw: reads JSONL session files from ~/.openclaw/agents/*/sessions/
- Hermes: reads JSONL session files from ~/.hermes/sessions/

All three are registered in Scanner.Scan() and follow the same
(date, provider, model) aggregation pattern as existing scanners.
2026-04-13 13:42:05 +08:00
Zohar Babin
77dbcaefad feat(cli): add --content-stdin flag to issue comment add
Allow agents to pipe comment content through stdin instead of the
--content flag, avoiding shell escaping issues with backticks, quotes,
and other special characters in markdown content.

Usage: cat <<'COMMENT' | multica issue comment add <id> --content-stdin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 00:23:16 -04:00
bulai0408
47eb6cb612 fix(agent): enable network access for Codex sandbox so Multica CLI can reach API
Codex tasks running in workspace-write sandbox mode could not resolve
api.multica.ai because the hardcoded sandbox parameter in thread/start
overrode any config.toml settings, and the default sandbox policy blocks
network access.

Changes:
- Remove hardcoded `sandbox: "workspace-write"` from thread/start RPC —
  let Codex read sandbox config from its own config.toml instead
- Auto-generate config.toml in per-task CODEX_HOME with
  `sandbox_mode = "workspace-write"` and `network_access = true`,
  preserving any existing user settings
- Fix Reuse() to restore CodexHome for Codex provider on workdir reuse

Closes #368
2026-04-13 01:03:43 +08:00
Sanjay Ramadugu
f99f50eb0c feat(daemon): add Google Gemini CLI backend
Registers `gemini` as a sixth supported agent provider alongside claude,
codex, opencode, openclaw, and hermes.

- Daemon config probes for `gemini` on PATH (MULTICA_GEMINI_PATH /
  MULTICA_GEMINI_MODEL env overrides mirror the other providers).
- New agent.geminiBackend in pkg/agent/gemini.go: spawns
  `gemini -p <prompt> --yolo -o text [-m <model>] [-r <session>]`,
  reads stdout to completion, and returns a single MessageText plus
  the standard Result struct (Status / Output / DurationMs).
- Execution environment writes a GEMINI.md file into the task workdir
  (mirroring the existing CLAUDE.md / AGENTS.md injection for other
  providers) so Gemini discovers the Multica runtime meta-skill
  through its native mechanism.

Tests:

- pkg/agent/gemini_test.go — unit coverage for buildGeminiArgs
  (baseline, model override, resume session, omit-when-empty).
- internal/daemon/execenv/TestInjectRuntimeConfigGemini — verifies
  GEMINI.md is written and that CLAUDE.md/AGENTS.md are NOT.

Scope (intentional for v1):

- Text output only (`-o text`). Streaming tool events via
  `--output-format stream-json` is a follow-up once we have a
  reliable reproduction of Gemini's event schema.
- No MCP config plumbing. Gemini's `--allowed-mcp-server-names`
  filter pairs well with the per-agent MCP work on feat/per-agent-mcp;
  stacking the two can land as a follow-up.
- No token usage scraping (Gemini's accounting lives on the Google
  Cloud side, not a local JSONL log like claude/codex).
- No session resume wiring beyond accepting the ExecOptions field —
  the daemon does not yet persist Gemini session IDs because the text
  output mode does not expose them.

Migration / env changes:

- New optional environment variables MULTICA_GEMINI_PATH and
  MULTICA_GEMINI_MODEL. Default path is the string "gemini" (resolved
  via PATH at daemon startup). If no Gemini install is detected, the
  provider is simply absent from the runtime — no behavior change for
  existing deployments.
2026-04-11 22:58:49 -04:00
zerone0x
cc9a8ad6ec fix(daemon): make meta-skill workflow defer to agent Skills instead of hardcoding (#675)
Replaces the hardcoded assignment-triggered workflow in buildMetaSkillContent()
with a minimal version that defers to agent Skills and Identity. Keeps platform
capability docs and status management steps intact.

Fixes #669

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 14:48:58 +08:00
Bohan Jiang
28b9bf85ee feat(daemon): add minimum Claude Code version check (#625)
* feat(daemon): add minimum Claude Code version check during runtime registration

The daemon now validates the detected agent CLI version against a
minimum requirement before registering a runtime. Claude Code requires
>= 2.0.0 (when --output-format stream-json and --permission-mode
bypassPermissions were introduced). Older versions are skipped with a
warning log, preventing silent failures.

Closes #569

* feat(daemon): add minimum Codex CLI version check (>= 0.100.0)

The `codex app-server --listen stdio://` flag was introduced in v0.100.0.
Older versions lack this flag and fail silently. Add codex to the
MinVersions map so the daemon skips outdated codex CLIs with a clear
warning, matching the existing Claude version check.

Refs #490
2026-04-10 16:09:56 +08:00
LinYushen
a25886102a feat(agent): add Hermes Agent Provider via ACP protocol (#623)
* feat(agent): add Hermes Agent Provider via ACP protocol

Integrate Hermes as a new agent backend using the ACP (Agent
Communication Protocol) JSON-RPC 2.0 over stdio — the same pattern
as the Codex provider but with ACP-specific methods.

- New hermesBackend spawns `hermes acp` and drives initialize →
  session/new → session/prompt lifecycle
- Handles session/update notifications: agent_message_chunk,
  agent_thought_chunk, tool_call, tool_call_update, usage_update
- Auto-approves tool executions via HERMES_YOLO_MODE env var
- Supports session resume, model override, system prompt injection
- Token usage extracted from PromptResponse and usage_update events
- Auto-detected at daemon startup via MULTICA_HERMES_PATH env var

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

* feat(ui): optimize runtime icons and fix create-agent dialog overflow

- Replace OpenClaw pixel-art icon (32 rects) with clean vector paths
- Add Hermes provider icon (NousResearch mascot, 48x48 webp data URI)
- Use provider-specific icons in runtime selector instead of generic Monitor
- Fix dialog overflow: add min-w-0 to grid item so truncate works

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

* fix(agent): add required mcpServers param to Hermes ACP session/new

ACP SDK v0.11.2 requires mcpServers as a mandatory field in
NewSessionRequest. Without it, Pydantic validation fails with
"Invalid params" and the agent immediately errors out.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:40:11 +08:00
Jiayuan Zhang
2c1d1d989c fix(daemon): symlink Codex sessions dir to shared home for discoverability (#627)
Per-task CODEX_HOME isolated session logs in per-task directories, making
them invisible from the global ~/.codex/sessions/ where users expect to
find them. Symlink the sessions directory back to the shared home so
Codex writes session logs to the global location while keeping skills
isolated per task.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:38:34 +08:00
yushen
821b6ece57 merge: resolve conflicts with main (project feature)
Merge both chat and project types/events/routes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:49:55 +08:00
yushen
3ffebd097c feat(chat): improve chat UI, fix streaming, add stop/fullscreen/agent permissions
- Redesign chat UI: Linear-style FAB, agent selector, empty state, Markdown rendering
- Fix WS message broadcast for chat tasks (resolve workspaceID from chat_session)
- Fix streaming race condition using refs for pendingTaskId
- Save assistant replies to chat_message on task completion
- Add real-time timeline rendering (tool calls, results, thinking) with collapsible groups
- Add historical timeline loading for past assistant messages
- Persist activeSessionId in localStorage + auto-restore from server
- Add chat workspace context to agent prompt (CLI commands, repos, skills)
- Add stop button (cancel task) during agent execution
- Add fullscreen mode (right-side panel, 50% width)
- Filter agent selector by visibility permissions (same as assign picker)
- Add generic POST /api/tasks/{taskId}/cancel route for chat tasks
- Add new chat (+) button, remove duplicate close button
- Devtools toggle via NEXT_PUBLIC_DEVTOOLS env var

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:47:11 +08:00
gyh1621
6e475b9521 fix(daemon/repocache): unstick stale cache from initial snapshot
The bare cache used a mirror-style fetch refspec
(+refs/heads/*:refs/heads/*) which collided with worktree-locked
refs/heads/agent/<task> branches once those branches were pushed
back to origin as PRs. git fetch aborted with "refusing to fetch
into branch ... checked out at ...", the error was swallowed as a
warning, and every subsequent checkout reused the snapshot from
the original clone.

Fix:
- Clone / migrate bare caches to a remote-tracking layout
  (+refs/heads/*:refs/remotes/origin/*) so fetched heads never
  land in refs/heads/*.
- Resolve the base ref from refs/remotes/origin/HEAD with a
  5-level fallback (verified origin/HEAD symref to origin/main
  or origin/master to the bare HEAD bridged into origin/<same>
  to single-entry origin/* scan to bare HEAD for legacy caches).
- Refuse to guess when refs/remotes/origin/* has multiple
  candidates and none match a known fallback, so CreateWorktree
  fails loudly instead of basing work on an arbitrary branch.
- Refresh refs/remotes/origin/HEAD after every successful fetch,
  not just on the legacy migration path, so a cache that was
  already modern picks up an upstream default-branch change.
- Verify the primary symref target actually exists so a phantom
  refs/remotes/origin/HEAD from a broken set-head does not
  surface a deleted branch.
- Detect legacy caches on the fly and rewrite refspec +
  refs/remotes/origin/* + refs/remotes/origin/HEAD in place so
  existing clones self-heal on next use.
- Serialize per-bare-repo mutation (both Sync and CreateWorktree)
  with sync.Map-backed mutexes so concurrent fetch and worktree
  add on the same repo cannot race on git's own lockfiles.
- Narrow the already-exists retry to actual branch-collision
  errors so a path-collision no longer silently leaks a branch
  into the bare repo.
2026-04-09 14:34:51 +08:00
yushen
50f9e673e8 feat(chat): add agent chat feature (full stack)
Implement the Master Agent chat feature allowing users to chat with agents
directly from a floating window, separate from the issue-based workflow.

Backend:
- New chat_session and chat_message tables (migration 033)
- Make issue_id nullable on agent_task_queue for chat tasks
- REST API: create/list/get/archive sessions, send/list messages
- EnqueueChatTask in TaskService with session_id persistence
- WS events: chat:message, chat:done
- Daemon: chat task type with separate prompt builder
- ClaimTaskByRuntime populates chat context (session, message, repos)

Frontend:
- ChatSession/ChatMessage types + API client methods
- core/chat: TanStack Query options, mutations with optimistic updates, WS updaters
- features/chat: Zustand store, ChatFab (floating button), ChatWindow with
  real-time streaming via task:message events
- Mounted in dashboard layout (bottom-right corner)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:19:46 +08:00
Bohan Jiang
8403c97688 Merge pull request #482 from multica-ai/agent/j/674c6839
feat(usage): add per-task token usage tracking
2026-04-08 14:16:59 +08:00
LinYushen
7df5750979 fix(daemon): update existing worktree to latest remote on reuse (#489)
* fix(daemon): update existing worktree to latest remote on reuse

When an agent receives a new task on the same issue, the execution
environment is reused and the repo worktree already exists on disk.
Previously, `multica repo checkout` would fail because `git worktree add`
cannot create a path that already exists — so the agent worked on stale
code from the prior task.

Now `CreateWorktree` detects existing worktrees and updates them:
fetch origin, reset working tree, then checkout a new branch from the
latest remote default branch. The previous task's branch is preserved.

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

* fix(daemon): propagate actual branch name and use correct ref in worktree reuse

- Return (string, error) from updateExistingWorktree so collision-retried
  branch name propagates to WorktreeResult
- Use baseRef directly instead of origin/baseRef — bare clone refspec maps
  remote branches to local refs, so remote-tracking refs may not exist
- Remove redundant fetch (worktree shares object store with bare clone)

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 14:13:44 +08:00
Jiang Bohan
fa0c0fe747 fix(usage): address review feedback — independent usage reporting + all providers
1. Separate ReportTaskUsage endpoint (POST /api/daemon/tasks/{id}/usage)
   so usage is captured independently of complete/fail — fixes usage loss
   for failed/blocked tasks.

2. Add usage tracking for all four providers:
   - Claude: already done (stream-json message.usage)
   - OpenCode: extract from step_finish.part.tokens
   - OpenClaw: extract from step_end.data token fields
   - Codex: extract from turn/completed and task_complete usage fields

3. Remove usage from CompleteTask payload — all usage goes through the
   dedicated endpoint now.
2026-04-08 13:23:54 +08:00
Jiang Bohan
8a8d3ea20e feat(usage): add per-task token usage tracking
Extract token usage from Claude Code's stream-json output in real-time
during task execution, replacing the inaccurate global JSONL log scanner.

- New `task_usage` table: tracks (task_id, provider, model) level usage
- Agent SDK: parse `message.usage` from assistant messages, accumulate
  per-model and return in Result
- Daemon: convert agent usage to entries, send with CompleteTask
- Server: store usage on task completion, expose workspace-level
  aggregation APIs (GET /api/usage/daily, GET /api/usage/summary)
2026-04-08 13:08:15 +08:00
Bohan Jiang
23198f3c26 Merge pull request #461 from multica-ai/agent/j/70455bdb
fix(daemon): correct duplicate sub-step lettering in workflow instructions
2026-04-07 17:29:46 +08:00
Jiang Bohan
47917825d1 fix(daemon): correct duplicate sub-step lettering in workflow instructions
When repos are present, sub-steps c/d/e/f are now distinct instead of
having two 'c' steps. Each branch (with/without repos) now has its own
complete set of correctly lettered sub-steps.
2026-04-07 15:22:02 +08:00
Bohan Jiang
eab5f8e7e8 Merge pull request #457 from multica-ai/agent/j/4420d1bf
fix(daemon): ensure multica CLI is on PATH in agent task environment
2026-04-07 15:03:56 +08:00
Jiang Bohan
9495179923 fix(daemon): ensure multica CLI is on PATH in agent task environment
Prepend the directory of the running multica binary to PATH in the
agent's environment variables. This fixes the issue where isolated
runtimes (e.g. Codex sandbox) cannot find the multica CLI, causing
agent tasks to fail immediately with "command not found: multica".

Closes #451
2026-04-07 15:01:48 +08:00
Bohan Jiang
f16b36fbc8 Merge pull request #456 from multica-ai/agent/j/25583cc6
feat(agent): add OpenClaw runtime support
2026-04-07 14:53:53 +08:00
Jiang Bohan
5cf4ba803d feat(agent): add OpenClaw runtime support
Add OpenClaw as a fourth supported agent runtime alongside Claude Code,
Codex, and OpenCode. OpenClaw CLI (`openclaw agent -p ... --output-format
stream-json`) is integrated via the same Backend interface pattern.

Changes:
- Add openclawBackend in server/pkg/agent/openclaw.go with NDJSON
  event stream parsing (text, thinking, tool_call, error, step, result)
- Register "openclaw" in the agent factory (agent.go)
- Add MULTICA_OPENCLAW_PATH / MULTICA_OPENCLAW_MODEL env var detection
  in daemon config
- Include "openclaw" in AGENTS.md config injection alongside codex/opencode
- Add comprehensive unit tests for all event handlers and processEvents
2026-04-07 14:40:51 +08:00
Bohan Jiang
96d81f9836 Merge pull request #454 from multica-ai/agent/j/ea6693b0
fix(daemon): add missing CLI commands to agent instructions
2026-04-07 14:23:24 +08:00
Jiang Bohan
02a7598906 fix(daemon): add missing CLI commands to agent instructions
Add 5 missing commands to buildMetaSkillContent() so agents can
discover them:

Read:
- workspace members — query member IDs for mentions
- repo checkout — listed in command reference, not just prose

Write:
- issue create — create sub-issues and new tasks
- issue assign — assign/unassign issues
- issue comment delete — remove erroneous comments
2026-04-07 14:13:26 +08:00
devv-eve
52a9a6ae5f refactor(cli): overhaul help output to match gh CLI style (#423)
* refactor(cli): overhaul help output to match gh CLI style

- Add gh-style grouped help with CORE/RUNTIME/ADDITIONAL COMMANDS sections
- Use UPPERCASE section headers (USAGE, FLAGS, EXAMPLES, LEARN MORE)
- Format commands as "name:  description" with automatic alignment
- Add ENVIRONMENT VARIABLES and EXAMPLES sections to root help
- Apply consistent templates to root, subcommand, and leaf commands
- Update descriptions from "Manage X" to "Work with X" for gh parity

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

* fix(execenv): add explicit instruction for agents to always use multica CLI

Agents were using curl/wget to access Multica attachment URLs directly,
which fails due to authentication. Add a prominent "Important" section
to the generated CLAUDE.md template that explicitly prohibits direct
HTTP access and instructs agents to escalate missing CLI functionality
to their workspace owner.

---------

Co-authored-by: Devv <devv@Devvs-Mac-mini.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 15:30:40 -07:00
Jiayuan
c39470a53f fix(comments): address code review feedback on pagination
1. Update CLAUDE.md template to document --limit, --offset, --since
   params and guide agents to use pagination when comments are large
2. Add GetJSONWithHeaders to API client; CLI now prints "Showing X of Y
   comments" to stderr when paginating
3. Cap --since without --limit at 500 server-side to prevent unbounded
   result sets
2026-04-04 01:01:48 +08:00
devv-eve
8eb1caa72b fix(agent): instruct agents to use download_url for attachments (#356)
* fix(agent): instruct agents to use download_url for attachments

Agents were not aware of the signed vs unsigned URL distinction in
attachments, causing failures when trying to read images. Added an
Attachments section to the generated CLAUDE.md/AGENTS.md template that
tells agents to always use `download_url`. Also increased signed URL
expiry from 5 to 30 minutes to better accommodate agent processing time.

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

* feat(cli): add `multica attachment download` command

Adds a dedicated CLI command for downloading attachments by ID. The
command fetches attachment metadata from the API (which returns a fresh
signed URL), downloads the file, and saves it locally. This eliminates
the need for agents to understand signed vs unsigned URLs.

Changes:
- New `multica attachment download <id>` CLI command
- New `GET /api/attachments/{id}` backend endpoint
- `DownloadFile` helper on APIClient
- Updated CLAUDE.md template to document the command

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

* fix(cli): sanitize filename and add download size limit

- Use filepath.Base on attachment filename to prevent path traversal
- Add 100MB size limit to DownloadFile (matches upload limit)
- Include response body in download error messages for debugging

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

---------

Co-authored-by: Devv <devv@Devvs-Mac-mini.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 07:45:42 -07:00
Quake Wang
36db325d50 feat(daemon): add opencode as supported agent provider (#341)
* feat(daemon): add opencode as supported agent provider

Add opencode backend alongside claude and codex. The backend spawns
`opencode run --format json`, parses streaming JSON events (text,
tool_use, error, step_start/finish), and supports --prompt for system
prompts. Includes CLI detection, AGENTS.md runtime config, native skill
discovery via .config/opencode/skills/, and 21 tests covering handlers,
JSON parsing, and integration-level processEvents scenarios.

* chore: add .tool-versions to gitignore
2026-04-02 17:52:07 +08:00
LinYushen
606930725a feat(daemon): support direct download update for non-Homebrew installs (#334)
* feat(daemon): support direct download update for non-Homebrew installs

Previously, CLI auto-update only worked for Homebrew installations. Non-brew
binaries would fail with "not installed via Homebrew". Now the daemon and
`multica update` fall back to downloading the release binary directly from
GitHub Releases when Homebrew is not detected.

Also fixes:
- Daemon restart now uses the current executable's absolute path instead of
  searching PATH, ensuring the updated binary is used
- Brew installs preserve the symlink path so the new Cellar version is picked up
- Daemon startup logs now include the CLI version
- Update UI auto-clears "restarting" status after 5s to show the new version

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

* fix(cli): remove dead DetectNewBinaryPath and guard against nil latest version

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:38:06 +08:00
LinYushen
682dc20ba9 fix(runtime): display multica CLI version instead of agent CLI version (#332)
The runtime detail page was showing the agent CLI version (claude/codex)
as "CLI Version" because metadata.version stored the agent version from
agent.DetectVersion(). The multica CLI version was never sent.

Fix: daemon now sends cli_version in the registration request, server
stores it as metadata.cli_version alongside the existing agent version,
and frontend reads metadata.cli_version.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:40:35 +08:00
LinYushen
fdba410f11 feat(runtime): support CLI update from web runtime page (#331)
* feat(runtime): support CLI update from web runtime page

Add the ability to update the CLI daemon from the web Runtime detail page.
When a newer version is available on GitHub Releases, an update button
appears. Clicking it sends an update command through the server to the
daemon via the heartbeat mechanism (same pattern as ping). The daemon
executes `brew upgrade`, reports the result, and restarts itself with the
new binary.

Changes across all three layers:
- Frontend: version display, GitHub latest check, UpdateSection component
- Server: UpdateStore (in-memory), heartbeat extension, 3 new endpoints
- CLI: shared update logic, daemon handleUpdate + graceful restart

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

* fix(runtime): handle 'running' status in ReportUpdateResult

The daemon sends {"status":"running"} when it starts executing the
update, but ReportUpdateResult treated any non-"completed" status as
failure — immediately marking the update as failed before brew upgrade
even ran.

Fix: use a switch statement to handle "running" as a no-op (status is
already "running" from PopPending), and also timeout running updates
after 120 seconds in case brew upgrade hangs.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:12:49 +08:00
Bohan Jiang
f353e8db59 feat(mentions): support @mentioning issues + server-side auto-expansion (#242)
* feat(mentions): support @mentioning issues in comments

- Extend MentionItem type to include "issue" alongside "member"/"agent"
- Add issue search (by identifier and title) to mention suggestion dropdown
- Render issue mentions with CircleDot icon in autocomplete popup
- Issue mentions serialize as [MUL-117 Title](mention://issue/id) (no @ prefix)
- Markdown renderer shows issue mentions as clickable links to /issues/:id
- Backend mentionRe regex updated to match issue mention type

* feat(mentions): auto-expand issue identifiers and add mention format to agent instructions

1. Path A — CLAUDE.md template (runtime_config.go):
   Add a "## Mentions" section teaching agents the mention serialization
   format for issues, members, and agents. All agents automatically
   receive this via the auto-generated CLAUDE.md.

2. Approach 2 — Server-side auto-conversion (internal/mention/):
   New ExpandIssueIdentifiers() utility that scans comment content for
   bare issue identifiers (e.g. MUL-117) and replaces them with
   [MUL-117](mention://issue/<uuid>) mention links. Skips code blocks,
   inline code, and existing markdown links. Integrated into both:
   - handler.CreateComment (HTTP API path)
   - service.createAgentComment (agent task output path)
2026-04-02 13:48:53 +08:00
Jiayuan
ab505fd39c docs: add issue runs and run-messages to CLI documentation
Update the dynamic agent instructions (runtime_config.go) and the
CLI reference (CLI_AND_DAEMON.md) to document the new execution
history commands.
2026-04-02 03:34:25 +08:00
Jiang Bohan
4780540bd2 merge: resolve conflicts with main 2026-04-01 13:12:23 +08:00
Jiang Bohan
365b5b5f0e feat(agent): add task cancellation with stop button
Users can now interrupt running agents via a "Stop" button on the live
card. The daemon polls task status every 5 seconds and kills the agent
process when cancellation is detected.

Changes:
- New CancelAgentTask SQL query and CancelTask service method
- POST /api/issues/{id}/tasks/{taskId}/cancel endpoint
- Daemon polls GetTaskStatus during execution, cancels context on match
- Frontend: Stop button on AgentLiveCard, task:cancelled WS event
2026-03-31 18:43:37 +08:00