# cloudcli-taskwork — workspace Meta-repository for the **Task Work** plugin for CloudCLI UI (`siteboon/claudecodeui`). It holds the specification, the developer scripts and two submodules. It contains **no code of its own** — no `package.json`, no dependencies. Specification: [`spec/SPEC-v3.md`](spec/SPEC-v3.md) (current), design input: [`spec/DESIGN-DOC.md`](spec/DESIGN-DOC.md). ## Repository map | Path | Repository | Role | |---|---|---| | *(this repo)* | `gitea:ai-first/cloudcli-taskwork` | Workspace: spec, scripts, submodule pins | | `plugin-taskwork/` | `gitea:ai-first/cloudcli-plugin-taskwork` | **The product**, developed here; `manifest.json` lives in its root | | — | `github:bvn13/cloudcli-plugin-taskwork` | **Where users install the plugin from** — public, anonymous HTTPS clone | | `cloudcli/` | `github:bvn13/claudecodeui` | Fork of the host; source of the three upstream PRs | | — | `github:siteboon/claudecodeui` | Upstream: source of updates, target of the PRs | | — | `gitea:ai-first/cloudcli` | Pull mirror of the fork, **read-only** | The plugin lives in two places on purpose: development and the submodule pin stay on Gitea, while the host installs it over anonymous HTTPS, which a private Gitea repository cannot serve. The GitHub copy is a **push mirror** — pushing to Gitea is enough, it syncs on its own. Do not add a GitHub remote to `plugin-taskwork/` and do not push there by hand. > ⚠️ Never push to `gitea:ai-first/cloudcli`. It is a pull mirror — anything pushed > there is silently overwritten on the next sync. The `cloudcli/` submodule points > at the GitHub fork, and the mirror is deliberately not wired up as a remote. ## Getting started ```bash git clone --recurse-submodules ssh://git@gitea.bvn13.me:2221/ai-first/cloudcli-taskwork.git cd cloudcli-taskwork ./scripts/bootstrap.sh ``` Then: ```bash ./scripts/dev-host.sh start # installs the built plugin and starts the host ``` It prints the URL — `http://localhost:5183` by default. `stop`, `restart`, `status` and `logs` do what they say; `SERVER_PORT`/`VITE_PORT` override the ports. The host runs against your **real** environment: the same `~/.claude` projects, the same `~/.cloudcli/auth.db`, the same `~/.claude-code-ui/plugins`. Nothing is sandboxed, so you see what a user would see. Ports default to 3010/5183 rather than 3001/5173 so an already installed CloudCLI keeps running — but note that both instances then share one database. Set `DATABASE_PATH` to separate them. After changing the plugin: ```bash cd plugin-taskwork && npm run build cd .. && ./scripts/link-plugin.sh # the host reads a copy, not a symlink ``` Client changes need only the plugin surface reopened; server changes need the host restarted (`./scripts/dev-host.sh restart`), because the plugin's backend process is spawned at host startup. The plugin stores its data **outside** its own directory, in `~/.claude-code-ui/taskwork/tasks.json` — the plugin directory is wiped on *Update*. ### Access All submodule URLs are SSH, so both submodules are writable with the same key setup: `ssh://git@gitea.bvn13.me:2221/…` for the plugin (the Gitea repositories are private) and `git@github.com:bvn13/claudecodeui.git` for the fork. The `upstream` remote stays on HTTPS — it is fetch-only and public. Cloning therefore needs an SSH key registered with both hosts; check with `ssh -T git@github.com` and `ssh -T -p 2221 git@gitea.bvn13.me`. Distribution goes through the public GitHub copy (`github:bvn13/cloudcli-plugin-taskwork`), because the host clones a plugin anonymously over HTTPS and the Gitea repository is private. The submodule keeps pointing at Gitea: that is where the plugin is developed and pushed first. ## Scripts | Script | Purpose | |---|---| | `scripts/bootstrap.sh` | Init submodules, wire the `upstream` remote, install deps, build the host's native modules and the plugin | | `scripts/dev-host.sh` | Run the patched host locally: `start`, `stop`, `restart`, `status`, `logs` | | `scripts/export-patches.sh` | Regenerate `plugin-taskwork/patches/*.patch` from the fork's feature branches (§12.0) | | `scripts/link-plugin.sh` | Symlink the local plugin into the host's plugin directory (`--unlink` to remove) | | `scripts/check-submodule-pins.sh` | Verify every pinned submodule commit is reachable from its origin | ## Branches in `cloudcli/` Each feature branch is cut **from the upstream tag `v1.37.2`**, never from another feature branch — that is what keeps the three pull requests independent. | Branch | Base | Purpose | |---|---|---| | `main` | tracks `upstream/main` | Upstream sync. Carries no commits of ours | | `feat/resizable-sidebar` | `v1.37.2` | PR-1 — resizable sidebar | | `feat/plugin-host-api` | `v1.37.2` | PR-2 — authenticated host API for plugins | | `feat/plugin-sidebar-surface` | `v1.37.2` | PR-3 — sidebar surface for plugins | | `dev/taskwork` | merge of the three | Local run and debugging; the submodule is pinned here | `dev/taskwork` never takes part in a pull request and may be recreated at any time. ## Working with the submodules - Commit code **inside** the submodule, push it, and only then record the new pin here with a separate commit `chore: bump to `. - Update with `git submodule update --remote --merge`. - Run `./scripts/check-submodule-pins.sh` before pushing a pin bump. ## Status | Piece | State | |---|---| | Plugin | `v1.0.0`, pushed to Gitea; installs, builds and runs (`npm install --ignore-scripts` + `npm run build` in ~3 s) | | `feat/resizable-sidebar` | Pushed to the fork. PR-1 not opened yet; no issue needed | | `feat/plugin-host-api` | Pushed to the fork. Issue text in `spec/upstream/issue-1-plugin-host-api.md`, PR text in `plugin-taskwork/docs/upstream-pr-2.md` | | `feat/plugin-sidebar-surface` | Pushed to the fork. Issue text in `spec/upstream/issue-2-plugin-sidebar-surface.md`, PR text in `plugin-taskwork/docs/upstream-pr-3.md` | | `dev/taskwork` | Merge of the three plus one integration commit (host API in the sidebar surface) that never goes upstream; the `cloudcli` pin points here | Remaining before upstream contact (§19 of the spec): open issue #1, then PR-2; issue #2, then PR-3; PR-1 can go on its own. Also outstanding: the manual acceptance checklist (§15.4), which needs a running host in a browser. ## Release See §13.2 of the spec. In short: export patches → bump the plugin version in `package.json` and `manifest.json` → build, typecheck, test → commit `build/`, `patches/`, `CHANGELOG.md` → tag `vX.Y.Z` in the plugin repo → bump the pins here. ## Licence The plugin and the fork are AGPL-3.0-or-later, following the upstream host.