docs(worker): document company mode (fetch, push, draft PR) and its open smoke tests
This commit is contained in:
@@ -36,6 +36,8 @@ Worker/
|
||||
Prime/ — "Prime Claude" schedules: PrimeScheduler, PrimeRunner, PrimePrompts,
|
||||
DailyPrepPrompt, PrimeScheduleValidation, NextDueCalculator, PrimeScheduleSignal
|
||||
Online/ — optional Online Inbox sync (off by default; zero network when disabled)
|
||||
AzureDevOps/ — company-repo push + draft PR: AzureDevOpsClient (REST, port of pr-create.ps1),
|
||||
PullRequestPublisher (push, find-or-create draft PR, pull_request_url)
|
||||
Tickets/ — Bandel ticket-system integration (per-list import + status write-back),
|
||||
inactive without ticket_api_base_url: TicketSystemConfig/TicketClientFactory,
|
||||
BandelTicketClient, TicketDtos, TicketStatusMap, TicketStatusSync,
|
||||
@@ -151,8 +153,8 @@ Full flow, invariants, and model/effort/max-turns resolution (including the low-
|
||||
- **ClaudeProcess** — spawns `claude -p --output-format stream-json --verbose --permission-mode auto` (or whatever app settings specify). Prompt via stdin, NDJSON from stdout. CancellationToken kills the process tree. Resolves `_cfg.ClaudeBin` via `ExecutableResolver` (`ClaudeDo.Data`, shared with `ClaudeCliPreflight` and the Installer's checks) before spawning — a `.cmd`/`.bat` shim (e.g. an npm-installed `claude`) is launched through `cmd.exe /c` since `UseShellExecute = false` can't exec a shim directly; a resolved `.exe` starts exactly as before. Throws if nothing resolves. *(Not yet on `main` — see `Environment Checks` in `ClaudeDo.Installer/CLAUDE.md`.)*
|
||||
- **ClaudeArgsBuilder** — `--model`, `--effort`, `--max-turns`, `--append-system-prompt`, `--agents`, `--json-schema`, `--resume`
|
||||
- **StreamAnalyzer** — parses NDJSON; extracts session_id, token counts, turn counts, result text, structured output. Replaced MessageParser.
|
||||
- **WorktreeManager** — worktrees on `<typ>/<nummer>-<slug>` branches, same leaf as the folder (`NameFor`, slug capped at 40 chars, umlauts transliterated). Typ from `BranchTypeFor` (`feat`→`feature`, `fix/refactor/docs/test/chore` as-is, anything else `chore`). Nummer = ticket id (own `TicketRef` or the parent's), else the task number — in a company repo (`CompanyRepo`, origin matches `company_remote_pattern`) without a ticket no number at all. A taken folder/branch name gets an 8-char task-id suffix, so the self-heal never force-deletes a foreign branch. Base = `rev-parse <unit branch>` for a child whose parent has an Active worktree, else `list_config.base_branch`, else the checked-out HEAD. Commits with semantic messages, updates DB with head commit + diff stats
|
||||
- **CommitMessageBuilder** — `{commitType}(slug): title\n\ndescription\n\nClaudeDo-Task: taskId`; `BuildMerge` is the merge-commit variant (`{commitType}(slug): merge title` + trailer). **Every merge caller passes a blank commit message on purpose** — `TaskMergeService` fills in `BuildMerge` from the task's commit type and its list's name, which is the only place that knows both. Don't reintroduce a caller-side literal.
|
||||
- **WorktreeManager** — worktrees on `<typ>/<nummer>-<slug>` branches, same leaf as the folder (`NameFor`, slug capped at 40 chars, umlauts transliterated). Typ from `BranchTypeFor` (`feat`→`feature`, `fix/refactor/docs/test/chore` as-is, anything else `chore`). Nummer = ticket id (own `TicketRef` or the parent's), else the task number — in a company repo (`CompanyRepo`, origin matches `company_remote_pattern`) without a ticket no number at all. A taken folder/branch name gets an 8-char task-id suffix, so the self-heal never force-deletes a foreign branch. Base = `rev-parse <unit branch>` for a child whose parent has an Active worktree, else `list_config.base_branch`, else the checked-out HEAD — in a company repo a unit root first fetches its basis (see Azure DevOps below). Commits with semantic messages, updates DB with head commit + diff stats
|
||||
- **CommitMessageBuilder** — `{commitType}(slug): title\n\ndescription\n\nClaudeDo-Task: taskId` (no trailer in company repos — the convention forbids signature trailers and nothing reads it); `BuildMerge` is the merge-commit variant (`{commitType}(slug): merge title` + trailer). **Every merge caller passes a blank commit message on purpose** — `TaskMergeService` fills in `BuildMerge` from the task's commit type and its list's name, which is the only place that knows both. Don't reintroduce a caller-side literal.
|
||||
- **TaskResetService** — discards a failed task's worktree, resets the row to Idle, preserves run history
|
||||
- **AgentFileService** — manages `~/.claudeDo/agents/*.md`; list/refresh via SignalR
|
||||
- **LogWriter** — async StreamWriter wrapper, auto-creates parent dirs
|
||||
@@ -273,10 +275,10 @@ non-obvious, behaviour-changing. A fixed bug is git history, not a finding.
|
||||
- `db_path`, `sandbox_root`, `log_root`
|
||||
- `worktree_root_strategy` (`sibling` | `central`), `central_worktree_root`
|
||||
- `queue_backstop_interval_ms` (30000) — also the gate/throttle recovery timer
|
||||
- `company_remote_pattern` (`/_git/`) — Teilstring der origin-URL, an dem `CompanyRepo` ein Firmen-Repo erkennt; nur per Hand editierbar.
|
||||
- `company_remote_pattern` (`/_git/`) — Teilstring der origin-URL, an dem `CompanyRepo` ein Firmen-Repo erkennt; nur per Hand editierbar. Schaltet Fetch vor dem Unit-Root, Approve = Push + Draft-PR und Commits ohne Trailer (siehe Azure DevOps).
|
||||
- `signalr_port` (47821), `claude_bin`, `ticket_api_base_url` — the two UI-writable fields
|
||||
(`claude_bin`: Settings → Dateien → CLAUDE CLI, hub `GetClaudeBin`/`SetClaudeBin`;
|
||||
`ticket_api_base_url`: Settings → Ticketsystem, hub `GetTicketSettings`/`SetTicketApiBaseUrl`).
|
||||
`ticket_api_base_url`: Settings → Externe Dienste, hub `GetTicketSettings`/`SetTicketApiBaseUrl`).
|
||||
Both edit the DI-singleton `WorkerConfig` in place *and* persist via their own `SaveKey` call
|
||||
(`SaveClaudeBin`/`SaveTicketApiBaseUrl`), so each applies without a restart. Every other field
|
||||
here is hand-edit only.
|
||||
@@ -341,6 +343,39 @@ distinguish the two singletons). The token never touches `worker.config.json` or
|
||||
`TicketStatusMap.NameOf` supplies the canonical name.
|
||||
⚠️ The base URL must be the **IP** — `bandelapis.fb-tuning.local` still refuses the connection.
|
||||
|
||||
## Azure DevOps (company repos)
|
||||
|
||||
Active when origin matches `company_remote_pattern` (live `git remote get-url`, no cache). The PAT
|
||||
(scope Code Read & Write) is DPAPI-encrypted at `~/.claudeDo/azdo.pat` (DI marker
|
||||
`AzureDevOpsPatStore`), set via Settings → Externe Dienste (hub `GetAzureDevOpsSettings` /
|
||||
`SetAzureDevOpsToken` / `ClearAzureDevOpsToken` / `TestAzureDevOpsConnection` — the test reads the
|
||||
first list whose origin matches and parses). Deliberately independent of the work-conventions
|
||||
plugin's PAT file.
|
||||
|
||||
- **`AzureDevOpsClient`** — the only HTTP surface. `ParseRemote` splits at `/_git/` (API base =
|
||||
everything before it, embedded credentials stripped, http(s) only). `GitAuthEnv(pat)` is the
|
||||
env for every git network call: `GIT_TERMINAL_PROMPT=0`, `GCM_INTERACTIVE=never`, PAT as
|
||||
`http.extraHeader` via `GIT_CONFIG_COUNT/KEY_0/VALUE_0` — never on a command line. API version
|
||||
starts at 6.0 and retries once with the version an out-of-range error names. ⚠️ A rejected PAT
|
||||
is HTTP **203** + an HTML login page, which `IsSuccessStatusCode` counts as success — handled
|
||||
explicitly.
|
||||
- **Fetch before a unit root** (`WorktreeManager.FetchCompanyBaseAsync`, once per unit root, never
|
||||
per child): basis = `base_branch` → ADO `defaultBranch` → `origin/HEAD`; `git fetch origin
|
||||
+refs/heads/<b>:refs/remotes/origin/<b>`; the worktree starts from `origin/<b>`. Local `<b>` is
|
||||
pulled along best-effort: not checked out → `git fetch . origin/<b>:<b>` (no network, git
|
||||
refuses a non-ff), checked out + clean → `merge --ff-only`, dirty/diverged → warning only. A
|
||||
failed fetch warns and continues from the local branch — it never fails the task.
|
||||
- **Approve** → `TaskMergeService.ApproveCompanyAsync` → `PullRequestPublisher`; details in
|
||||
[review-merge](../../docs/explore-notes/review-merge.md). PR title
|
||||
`<type>(<list-slug>): <title>, Resolves #<ticket>`; description
|
||||
`Resolves [#id](https://ticket.fb-tuning.local/board/project/<p>/ticket/<id>)` (project id = walk
|
||||
`GET /api/ticket/{id}` up until `parentTicketID` is null — a ticket's parent is its project, a
|
||||
task's parent is a ticket, live-checked 2026-10-01; unknown → plain `Resolves #id`), the task
|
||||
description, `Geprüft: …` with only what actually ran. Target = `base_branch`, else the ADO
|
||||
default branch.
|
||||
- Not done on purpose: PR status polling / auto-`Done`, other PR providers, worktree cleanup on
|
||||
`Done`, fetch in private repos, a UI for `company_remote_pattern`.
|
||||
|
||||
## Notes
|
||||
|
||||
- The worker runs standalone — start it separately from the UI. Loopback only (127.0.0.1).
|
||||
|
||||
Reference in New Issue
Block a user