@detergent-software/conductor 3.0.0-dev.2 → 3.0.0-dev.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +169 -0
- package/README.md +158 -45
- package/build/brief-cli.js +1 -1
- package/build/brief-cli.js.map +1 -1
- package/build/broker-cli.js +24 -25
- package/build/broker-cli.js.map +1 -1
- package/build/broker.js +66 -92
- package/build/broker.js.map +1 -1
- package/build/claude.js +50 -7
- package/build/claude.js.map +1 -1
- package/build/cli.js +119 -54
- package/build/cli.js.map +1 -1
- package/build/clones.js +92 -0
- package/build/clones.js.map +1 -0
- package/build/code-host-cli.js +101 -26
- package/build/code-host-cli.js.map +1 -1
- package/build/code-host.js +13 -8
- package/build/code-host.js.map +1 -1
- package/build/config.js +31 -12
- package/build/config.js.map +1 -1
- package/build/console.js +40 -24
- package/build/console.js.map +1 -1
- package/build/credentials.js +26 -24
- package/build/credentials.js.map +1 -1
- package/build/daemon.js +35 -21
- package/build/daemon.js.map +1 -1
- package/build/help.js +141 -30
- package/build/help.js.map +1 -1
- package/build/host/credential-manager.js +109 -0
- package/build/host/credential-manager.js.map +1 -0
- package/build/host/keychain.js +44 -0
- package/build/host/keychain.js.map +1 -0
- package/build/host/libsecret.js +40 -0
- package/build/host/libsecret.js.map +1 -0
- package/build/host/macos-terminal.js +63 -0
- package/build/host/macos-terminal.js.map +1 -0
- package/build/host/platform.js +4 -0
- package/build/host/platform.js.map +1 -0
- package/build/host/secrets.js +46 -0
- package/build/host/secrets.js.map +1 -0
- package/build/host/shell.js +26 -0
- package/build/host/shell.js.map +1 -0
- package/build/host/terminal.js +46 -0
- package/build/host/terminal.js.map +1 -0
- package/build/host/tmux.js +39 -0
- package/build/host/tmux.js.map +1 -0
- package/build/host/windows-terminal.js +46 -0
- package/build/host/windows-terminal.js.map +1 -0
- package/build/in-process.js +6 -5
- package/build/in-process.js.map +1 -1
- package/build/inbox.js +50 -5
- package/build/inbox.js.map +1 -1
- package/build/init.js +508 -0
- package/build/init.js.map +1 -0
- package/build/lib/providers/ado/pipelines.js +102 -17
- package/build/lib/providers/ado/pipelines.js.map +1 -1
- package/build/lib/providers/ado/trigger.js +5 -0
- package/build/lib/providers/ado/trigger.js.map +1 -1
- package/build/lib/providers/github/actions.js +85 -2
- package/build/lib/providers/github/actions.js.map +1 -1
- package/build/lib/providers/index.js +3 -2
- package/build/lib/providers/index.js.map +1 -1
- package/build/lib/providers/npm/stage.js +14 -4
- package/build/lib/providers/npm/stage.js.map +1 -1
- package/build/lib/providers/timing.js +10 -0
- package/build/lib/providers/timing.js.map +1 -0
- package/build/lib/providers/verdicts/runs.js +12 -2
- package/build/lib/providers/verdicts/runs.js.map +1 -1
- package/build/local-files.js +95 -0
- package/build/local-files.js.map +1 -0
- package/build/manager.js +171 -47
- package/build/manager.js.map +1 -1
- package/build/note.js +1 -1
- package/build/note.js.map +1 -1
- package/build/npm-reads.js +323 -0
- package/build/npm-reads.js.map +1 -0
- package/build/paths.js +44 -1
- package/build/paths.js.map +1 -1
- package/build/plugin.js +10 -0
- package/build/plugin.js.map +1 -1
- package/build/profile-fields.js +149 -0
- package/build/profile-fields.js.map +1 -0
- package/build/profile-layers.js +264 -0
- package/build/profile-layers.js.map +1 -0
- package/build/profile.js +60 -38
- package/build/profile.js.map +1 -1
- package/build/project-check-cli.js +18 -10
- package/build/project-check-cli.js.map +1 -1
- package/build/project-check.js +179 -97
- package/build/project-check.js.map +1 -1
- package/build/pushover.js +5 -5
- package/build/pushover.js.map +1 -1
- package/build/registry.js +195 -36
- package/build/registry.js.map +1 -1
- package/build/rule-actions.js +3 -1
- package/build/rule-actions.js.map +1 -1
- package/build/rules-service.js +101 -44
- package/build/rules-service.js.map +1 -1
- package/build/rules.js +11 -2
- package/build/rules.js.map +1 -1
- package/build/runs.js +88 -14
- package/build/runs.js.map +1 -1
- package/build/scheduler.js +11 -1
- package/build/scheduler.js.map +1 -1
- package/build/server.js +4 -25
- package/build/server.js.map +1 -1
- package/build/spend.js +4 -0
- package/build/spend.js.map +1 -1
- package/build/store.js +82 -25
- package/build/store.js.map +1 -1
- package/build/timeline.js +104 -0
- package/build/timeline.js.map +1 -0
- package/build/tracker-reads-cli.js +4 -5
- package/build/tracker-reads-cli.js.map +1 -1
- package/build/train-cli.js +6 -5
- package/build/train-cli.js.map +1 -1
- package/build/upgrade.js +16 -1
- package/build/upgrade.js.map +1 -1
- package/build/wait.js +6 -6
- package/build/wait.js.map +1 -1
- package/build/watchers/ado.js +3 -2
- package/build/watchers/ado.js.map +1 -1
- package/build/watchers/github.js +3 -2
- package/build/watchers/github.js.map +1 -1
- package/build/watchers/npm.js +6 -4
- package/build/watchers/npm.js.map +1 -1
- package/build/worktrees.js +199 -92
- package/build/worktrees.js.map +1 -1
- package/package.json +61 -61
- package/plugin/skills/conductor-console/SKILL.md +3 -3
- package/plugin/skills/work-item/SKILL.md +8 -6
- package/build/checkout-sync.js +0 -249
- package/build/checkout-sync.js.map +0 -1
- package/build/credential.js +0 -66
- package/build/credential.js.map +0 -1
- package/build/tab.js +0 -32
- package/build/tab.js.map +0 -1
package/README.md
CHANGED
|
@@ -10,12 +10,18 @@ conduct start start the daemon detached and wait until it an
|
|
|
10
10
|
conduct stop stop the running daemon
|
|
11
11
|
conduct supervise [--fail-fast] run the daemon and restart it when it dies (see Restarts)
|
|
12
12
|
conduct status [--json] the daemon's pid, port, projects, workers and held locks
|
|
13
|
-
conduct
|
|
13
|
+
conduct init [<path>] [--name <name>] [--base <branch>] [--tracker <kind>] [--key <KEY>] [--team <key>]
|
|
14
|
+
[--query <query>] [--shared] [--yes]
|
|
15
|
+
onboard a repo: a starter profile, then project add and check (see Projects)
|
|
16
|
+
conduct project add <url | path> [--name <name>]
|
|
17
|
+
clone the project's remote into ~/.conductor/projects/<name>/repo and register it
|
|
14
18
|
conduct project list [--json] the registered projects
|
|
15
19
|
conduct project remove <name> drop a registration (a renamed project's old name), resolving its inbox items
|
|
16
20
|
conduct project check <name> [--no-worktree] [--json]
|
|
17
21
|
whether the project can be conducted, before a launch finds out
|
|
18
|
-
conduct
|
|
22
|
+
conduct profile <project> [--json]
|
|
23
|
+
the project's profile, machine over repo, each field with its source (see Projects)
|
|
24
|
+
conduct launch <item> start a worker: worktree and background session (a tab with workers.tab)
|
|
19
25
|
[--project <name>] [--probe] [--prompt <text>] [--conductor <name>]
|
|
20
26
|
conduct retire <worker> [--force] stop a worker, remove its worktree and session
|
|
21
27
|
conduct attach <worker> wake a parked worker (no event text) and open it in a tab
|
|
@@ -38,7 +44,7 @@ conduct focus <project> [--slots <n>] [--weight <n>] --until <when>
|
|
|
38
44
|
conduct why <event id | item> [--json]
|
|
39
45
|
the rule behind an action, and the events that led to it
|
|
40
46
|
conduct console [--here]
|
|
41
|
-
open the console in a Windows Terminal
|
|
47
|
+
open the console in a tab (Windows Terminal, iTerm or Terminal, tmux), or in this terminal (see Console)
|
|
42
48
|
conduct escalations [--json] what rules escalated to the console and it hasn't handled
|
|
43
49
|
conduct escalations done <id> [--ask] <text>
|
|
44
50
|
the console's finding on an escalation; --ask puts it in the inbox
|
|
@@ -76,12 +82,17 @@ conduct reply <pr> [<thread>] --body-file <file> [--repo <repo>]
|
|
|
76
82
|
answer on the worker's PR, headed as a note
|
|
77
83
|
conduct runs <sha> [--for <pipeline>[,<pipeline>…]] [--repo <repo>]
|
|
78
84
|
a merge's runs, their verdict, failed logs and npm stages (see Worker verbs)
|
|
85
|
+
conduct runs <sha> --for <pipeline>[,<pipeline>…] --grep <pattern> [--repo <repo>]
|
|
86
|
+
the same, with the lines of those runs' logs that match, whatever their result
|
|
79
87
|
conduct runs <sha> --requeue <pipeline>
|
|
80
88
|
queue the item's merge's cancelled run again on the base (see Worker verbs)
|
|
89
|
+
conduct timeline <run> [--task <regex>] [--grep <regex>] [--repo <repo>]
|
|
90
|
+
a run's tasks with their times, and the named tasks' log lines that match (see Worker verbs)
|
|
91
|
+
conduct timeline --for <pipeline> [--branch <branch>] [--count <n>] [--task <regex>] [--grep <regex>] [--repo <repo>]
|
|
92
|
+
the same for a pipeline's last finished runs on a branch
|
|
81
93
|
conduct train [<project>] [--dry-run]
|
|
82
94
|
merge the waiting skill publishes into one registry PR (see Skill trains)
|
|
83
|
-
conduct ports [<path>] [--
|
|
84
|
-
a checkout's dev ports from the port broker, or every worktree's (see Broker)
|
|
95
|
+
conduct ports [<path>] [--json] a conducted worktree's dev ports from the port broker, or every worktree's (see Broker)
|
|
85
96
|
conduct lock acquire|release|status <name> [--owner <id>] [--wait <minutes>]
|
|
86
97
|
a lock every project shares, such as chrome (see Broker)
|
|
87
98
|
conduct events [--since <id>] [--follow] [--console]
|
|
@@ -100,11 +111,27 @@ A `<worker>` is its item (`ATK-309`) or its name (`probe-ATK-309`).
|
|
|
100
111
|
|
|
101
112
|
The session manager owns the `claude --bg` sessions it launches, and only those:
|
|
102
113
|
|
|
103
|
-
- **launch:** the worktree comes first,
|
|
114
|
+
- **launch:** the worktree comes first, made by the daemon itself (design note v2, section 2; ATK-526), with no hooks:
|
|
115
|
+
1. the broker gives it a port for each name in the profile's `ports` (see Broker);
|
|
116
|
+
2. `git worktree add`, run in the project's clone (see Projects), makes `~/.conductor/projects/<project>/worktrees/<name>` on `worktree-<name>` from `origin/<base>`, fetched first (after `git worktree prune`, and on Windows with `core.longpaths` on). It doesn't fetch, pull, add worktrees to or change a checkout of yours (a `localFilesFrom` checkout is only read). A worktree git still reads there is reused, its own changes and all; one with a `.git` git can't read is never deleted, and fails the launch. A `worktree-<name>` branch that is left is checked out again, with any commits it kept;
|
|
117
|
+
3. with `localFilesFrom` (an absolute path to a checkout the operator keeps), the gitignored files there that match its `.worktreeinclude` are copied in, as they are now;
|
|
118
|
+
4. the profile's `setup` commands run in order in the worktree, through the shell, with `CONDUCTOR_PORT_<NAME>` (such as `CONDUCTOR_PORT_WEB=41000`), `CONDUCTOR_ITEM`, `CONDUCTOR_PROJECT` and `CONDUCTOR_WORKTREE` set. They build its gitignored files from what the repo commits (ATK's: `pnpm install`, `atk setup --tool claude-code --yes`, `node scripts/dev-ports.mjs assign`, `atk install`). The first that fails fails the launch, with the end of its output. So does a setup that leaves changes git sees, such as an `.atk-lock.json` that `atk install` rewrote: the worker would take them for its own;
|
|
119
|
+
5. the ports go into the worktree's `.claude/settings.local.json` as `env`, merged into what the file had. A `claude --bg` session doesn't inherit the environment it is started from, but Claude Code applies that file's `env` to every session in the folder and to each resume;
|
|
120
|
+
6. the profile's work and verify skills must be there: a `conductor:<skill>` in the plugin, any other in the worktree's `.claude/skills` or `~/.claude/skills`.
|
|
121
|
+
|
|
122
|
+
A launch that fails removes the worktree it made when it is clean, with its branch while that still has the launch's name; a worktree that was there before the launch stays.
|
|
123
|
+
|
|
124
|
+
Then `claude --bg -n <name> --plugin-dir <home>/plugin --disallowedTools EnterPlanMode ExitPlanMode --permission-mode auto -- <prompt>` runs with its cwd in the worktree (see Plugin), never `--worktree`. Workers run headless. A machine whose `config.json` sets `"workers": { "tab": true }` also gets a tab attached to each session, `claude attach <session>`, in the terminal `workers.terminal` names (see Tabs); `conduct attach` opens one either way. A tab that fails to open is a `worker.tab-failed` event and never fails the launch.
|
|
104
125
|
- **park:** a worker with a wait (`POST /waits`) is stopped once `claude agents` shows its turn has ended. Its status becomes `parked`, and its tab closes.
|
|
105
126
|
- **resume:** when a wait resolves, the daemon lets the stop settle (`sessions.settleSeconds`). It checks the process has exited, then runs `claude --bg --resume <session> -- "[conductor] event: …"`. The session keeps its name, model, permission mode and disallowed tools. A resume of a session that still runs starts a copy; the daemon stops and removes the copy, then tries again.
|
|
106
127
|
- **compact:** a parked worker with no resolved wait, whose context the rules find too big (the default `compact-on-park`: past `sessions.compactTokens`, 300k), is resumed with `/compact <what to keep>` once its stop has settled (`worker.compacting`). It runs until its transcript shows the compaction's boundary (`worker.compacted`, with the context before it and the conversation it kept), then parks again on its waits, which resume it as usual. Each turn of a session re-reads its whole context from cache, so a worker left to grow pays for it every turn (ATK-454 reached 883k). A resume that starts a copy is tried again on a later sweep (`worker.compact-deferred`), as a resume is. A compaction whose resume fails, or whose turn ends with no boundary 10 minutes on, logs `worker.compact-failed`, which raises a `context` item in the inbox. The worker still parks, and the daemon doesn't try it again until it restarts or the session compacts some other way: any boundary in its transcript, Claude Code's own included, logs `worker.compacted` and resolves that item. A worker whose context is unknown is never compacted, so even a rule with no threshold can't compact it on every park.
|
|
107
|
-
- **retire:** refuses
|
|
128
|
+
- **retire:** refuses a worker whose turn still runs, unless `--force`, and never retires a session that is still starting. What happens to the worktree depends on the worker's PR (design note v2, section 2):
|
|
129
|
+
- **merged** (read from the code host): it refuses uncommitted or unpushed work unless `--force`, then stops the session, removes the worktree and deletes its local branch, and runs `claude rm`;
|
|
130
|
+
- **no PR, and nothing uncommitted or unpushed** (a canceled item, a worker retired before its first commit): as merged, with nothing to lose;
|
|
131
|
+
- **not merged** (abandoned or closed, or no PR with work in it): it stops and removes the session and frees the ports, and keeps the worktree and its branch, so nothing the PR didn't land is lost. `worker.retired` names it under `kept`, which raises one `failed` inbox item with the path, the branch and the commands that remove them. A PR the project's code host can't read at all counts as not merged;
|
|
132
|
+
- **unread** (the code host didn't answer): it refuses, as a refusal that passes on its own, and the scheduler tries again.
|
|
133
|
+
|
|
134
|
+
A probe's worktree and a `--force` retire's always go. The removal moves the worktree aside, has git forget it, deletes the branch and then the directory with Node, which unlinks pnpm's junctions without following them (`git worktree remove` leaves them on Windows). The delete is asynchronous, so the API goes on answering through a minute of `node_modules`. It works in the repository the worktree's own `.git` names, so a worker launched before the daemon owned clones retires from the checkout its worktree was made in; it removes only a linked worktree that repository lists, never a main checkout. With the directory gone already, it deletes the `worktree-<name>` branch in the project's clone only when none of its commits is unpushed. If the stop fails, nothing is removed.
|
|
108
135
|
- **restarts:** a launch the daemon was stopped in adopts its session if one was started, and otherwise fails and removes its clean worktree.
|
|
109
136
|
- **attach:** a parked worker is resumed with no event text, so it wakes idle and keeps running when its tab closes. An attached worker isn't parked until it registers a new wait, or until its turn has been over `sessions.idleMinutes` (`worker.detached`). The daemon can't see the tab, so this also delivers a wait that resolved while it was attached. A wait that resolves after the attach, on a worker whose transcript shows no turn since then, is delivered at once: the worker is detached (`reason: wait resolved`), parked, which closes its tab, and resumed with the event. A worker someone woke outside the daemon counts as attached since its stop, so the turn that woke it counts. One that took a turn since the attach (or has no transcript to tell), or whose wait resolved before the attach, keeps it until the idle release, logs `worker.resume-held` (`reason: attached`) once, and `conduct status` shows it as `idle, holding resolved waits for the attached session`.
|
|
110
137
|
- **park failures:** a session whose process outlives `claude stop` by 30 s logs one `worker.park-failed` per spell, which raises a `stall` in the inbox (see Inbox), and the park is tried again every 5 minutes.
|
|
@@ -115,6 +142,19 @@ The session manager owns the `claude --bg` sessions it launches, and only those:
|
|
|
115
142
|
|
|
116
143
|
Worker statuses: `launching`, `running`, `parked`, `stopped-unexpectedly`, `failed`, `exited`. Every step is an event (`worker.launched`, `worker.parked`, `worker.resumed`, …) on `GET /events`.
|
|
117
144
|
|
|
145
|
+
### Tabs
|
|
146
|
+
|
|
147
|
+
Workers are background sessions, and a tab is only a view of one: the session runs without it, and a tab closes when its worker parks. `~/.conductor/config.json` says whether each launch opens one and where tabs open:
|
|
148
|
+
|
|
149
|
+
```jsonc
|
|
150
|
+
{ "workers": { "tab": true, "terminal": "auto" } }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- `tab` (false): open a tab on each launch. `conduct attach <worker>` opens one whatever it says. It was the profile's `workers.tab` until ATK-529: a profile may still set it, for older daemons, but it is ignored, and `conduct project check` warns about it. Set it in `config.json` on each machine that wants tabs.
|
|
154
|
+
- `terminal` (`auto`): `windows-terminal` (`wt.exe`, a window per project, "Conductor · <project>"), `iterm` (a tab in its front window), `terminal` (macOS Terminal, a window per tab) or `tmux` (a detached session per window, such as `conductor-atk`, and a tmux window per tab). `auto` is Windows Terminal on Windows, iTerm on macOS where it is installed and Terminal where not, and tmux elsewhere.
|
|
155
|
+
|
|
156
|
+
A tmux tab runs where no desktop is, so `conduct attach` and `conduct console` print the `tmux attach -t <session>` that reaches it. With no terminal to open in (no tmux on a server), `conduct attach` prints the `claude attach <session>` to run yourself, and `conduct console` refuses with `conduct console --here --force` (`--force` because the refused start is claimed for a minute). A worker's tab whose `claude attach` fails stays open on the failure, until Enter, so you can read it. Tabs on macOS and tmux run their command through `sh -c`, whatever the login shell. macOS asks once whether the conductor may control Terminal or iTerm (Automation, in Privacy & Security). Terminal opens a window per tab, and closes it when the tab's shell exits only if the profile's "When the shell exits" says so (Settings, Profiles, Shell); otherwise a parked worker leaves its window behind.
|
|
157
|
+
|
|
118
158
|
## Notes
|
|
119
159
|
|
|
120
160
|
A worker writes each phase note (`## <work skill> · <Phase>[ · <kind>: <one line>]`, such as `## work-issue · PR opened`) with `conduct note <item> <file>`. The daemon posts the file as a comment on the item in the tracker, then records the phase at once: on the worker (`phase` in `GET /fleet` and `conduct status`), on the item, and as a `note.posted` event. A PR opened note also records the worker's PR (`pr`, such as `ado:Emergent.AgenticToolkit#1850` or `github:<owner>/<repo>#458`) from its first PR link, replacing an earlier one; until then, the worker's first `pr:` wait records it. `conduct status` and the console's fleet pane show it. The worker is `--worker <worker>`, else the one whose worktree is the current checkout, else the project's live worker on that item. The project is the worker's, else the one whose tracker key (the Linear team, or the Boards or GitHub Issues `key`) is the item's key prefix.
|
|
@@ -190,11 +230,17 @@ Protocol 2's verbs on git and the code host (providers design note, section 4),
|
|
|
190
230
|
- `conduct pr threads <pr>` lists the PR's threads (on GitHub each comment and review) with `needsAnswer` (ATK-384). `conduct reply <pr> [<thread>]` answers on the worker's own PR: in the ADO thread named, or as a note on the PR. The text is headed `## <work skill> · Reply` unless it starts with a note heading. The daemon logs `code-host.replied`. `--repo` takes `github:<owner>/<repo>` (from its `.scratch/repos` checkout, into its default branch) or `ado:<repository>`; the profile's `codeHost` is the default.
|
|
191
231
|
- `conduct runs <sha>` is one look at a merge's runs, as the helper's `runs-watch --once` and `stage` were (ATK-455). It is a read, so it runs here (except with `--requeue`).
|
|
192
232
|
- **Which runs.** On Azure Pipelines (the profile's `ci: ado-pipelines`, for its Azure DevOps repo), they are the pipelines whose YAML trigger the merge fires. The YAML and the merge's changed files are read in the worktree, which fetches the base when it hasn't got the commit. On GitHub Actions (`--repo github:<owner>/<repo>`, or `ci: github-actions` for a GitHub repo), they are the runs the merge's push started.
|
|
193
|
-
- **The verdict.** It is `runsVerdict`: `succeeded`, `failed`, `cancelled`, `waiting-for-approval`, `missing`, `none` or `waiting`. On Azure Pipelines `none` comes at once when nothing is triggered. On GitHub it comes after 5 minutes with no run, and on Azure Pipelines a triggered pipeline gets 15 minutes to queue before it is `missing`.
|
|
233
|
+
- **The verdict.** It is `runsVerdict`: `succeeded`, `failed`, `cancelled`, `waiting-for-approval`, `missing`, `none` or `waiting`. On Azure Pipelines `none` comes at once when nothing is triggered. On GitHub it comes after 5 minutes with no run, and on Azure Pipelines a triggered pipeline gets 15 minutes to queue before it is `missing`. The note gives a `missing` pipeline's `--requeue` line.
|
|
234
|
+
- **A batch behind a run (ATK-434).** A `batch: true` pipeline holds a push while its run on the base still goes, and builds the newest commit when that run ends. So a merge with no run of such a pipeline yet reads that pipeline's newest builds on the base, and the newest that doesn't carry the merge is the run its batch queues after (`behind`: its `run`, and `finished`, null while it goes; state `not-queued`). The verdict is `waiting` for as long as that run goes and 2 minutes after it ends, while Azure DevOps lists the batch's run, past the 15 minutes too: a long deploy, or a `main` run waiting on its prod approval, can hold it longer. A `[skip ci]` release commit pushed in that time isn't in the deploy pipelines' batch (it touches only `apps/cli/` or `apps/conductor/`), and the batch still runs.
|
|
194
235
|
- **A cancelled run (ATK-547).** On Azure Pipelines a canceled build is `cancelled`, not `failed`. A later run on the base whose commit contains the merge stands in for it: the first that wasn't cancelled is the merge's run, with `supersedes` naming the cancelled one. So `cancelled` means no newer run carries the merge, and the note gives the `--requeue` line. GitHub reads runs by the merge's SHA alone, so its `cancelled` says nothing about newer runs.
|
|
195
|
-
- **`--requeue <pipeline>`.** It queues that pipeline
|
|
236
|
+
- **`--requeue <pipeline>`.** It queues that pipeline on the base at its tip (`POST build/builds` with the tip as `sourceVersion`), after checking that the tip contains the merge: a cancelled run no newer run carries, or a missing one (`replaces: null`). It is a write, for the item's own merge only: the checkout's branch carries the item's key, and that branch's PR merged as `<sha>`. It refuses a run that is waiting, running, succeeded or failed, so a run already listed is never queued twice, and a batch still behind a run, which queues when that run ends. It also refuses a merge under 15 minutes old, since Azure DevOps can still list a newer run that carries it. A newer merge's batched run that ADO hasn't listed yet isn't caught. It refuses a pipeline the merge didn't trigger and a GitHub repo. The daemon queues it for the worker that owns the checkout (`POST /workers/:id/requeues`) and logs `code-host.run-requeued`; with no daemon it runs here. `conduct wait merge <sha>` then follows the new run, which carries the merge.
|
|
196
237
|
- **`--for`.** It settles on the named pipelines alone, by YAML file name, path or name, and lists the rest under `others`. Azure Pipelines refuses a name no pipeline answers to.
|
|
238
|
+
- **`--grep <pattern>` (ATK-622).** With `--for`, it reads every task log of those pipelines' runs, succeeded or not (`Ci.taskLogs`: Azure Pipelines' timeline tasks under their stage, through the reader `failureLog` uses; GitHub Actions' `gh run view --log` steps under their job). It tests each line against a JavaScript regular expression, case-sensitive. `grep.runs` gives each run's `matches` by stage and task, at most 200 lines a task with `truncated` beyond that, and `searched`, each task with its line count. So a dev proof can show that a run never printed a line. Some runs carry a note saying why they were searched in part or not at all: a pipeline with no run yet (`run: null`), a run still queued or running, one waiting on an approval (its later stages haven't run), and a log the provider won't give. A transient failure or a lost login is thrown instead.
|
|
197
239
|
- **Logs and stages.** Each failed run comes with its failed tasks and log tail (`logs`). For the project's repo, each of the profile's `releases` whose run succeeded gives what it staged (`stages.<key>`): package, version, `stageId`, the `npm stage approve` line, and `published`.
|
|
240
|
+
- `conduct timeline` (ATK-623) reads when a run's tasks ran, so a worker can measure a step (a cache that has to pay for itself) without a merge commit. It is a read, so it runs here.
|
|
241
|
+
- **One run.** `conduct timeline <run>` gives the run's start, finish and `seconds`, and each task in the order it started, with its `stage`, `job`, `started`, `finished`, `seconds` (null until it has both times), and the host's `state` and `result` (`Ci.timeline`: Azure Pipelines' timeline `Task` records under their stage and job; GitHub Actions' jobs API steps under their job, with no stage).
|
|
242
|
+
- **A pipeline's last runs.** `conduct timeline --for <pipeline>` reads the last finished runs of one pipeline on a branch instead, newest first (`Ci.recentRuns`): the profile's base and 3 runs by default, `--branch` and `--count` (at most 20) to change them. The pipeline is named as `runs --for` names one, and a name no pipeline, or more than one, answers to is refused. A branch with fewer runs says so in a note.
|
|
243
|
+
- **`--task <regex>` and `--grep <regex>`.** `--task` keeps the tasks whose name matches, not case-sensitive, so `Cache Next build` also keeps its `Post-job: Cache Next build` save. One that matches nothing says so and lists the run's tasks. `--grep`, which needs `--task`, reads only those tasks' logs (`Ci.taskLogs` with `only`) and gives `grep` in `runs --grep`'s shape: `matches` and `searched` by task, with a note for a log the provider won't give. A run not finished says its tasks may be partial.
|
|
198
244
|
- `conduct wait merge <sha> [--for …] [--repo …]` parks the worker until that verdict isn't `waiting` (see Waits), on either CI, so no worker polls with `wait time`. It absorbs ATK-430, ATK-246 and ATK-182.
|
|
199
245
|
|
|
200
246
|
## Writes
|
|
@@ -214,7 +260,7 @@ Every write the conductor makes outside its own store, with what triggers it and
|
|
|
214
260
|
| ADO: a +10 vote (auto mode) and auto-complete; GitHub: auto-merge with a merge commit (auto mode). Then the Landing note | `conduct land` → `POST /workers/:id/landings` | the project's `az` identity, or its gh account |
|
|
215
261
|
| ADO: an expired build queued again, a cleared vote restored | a verdict wait on a landing `conduct land` armed (the ADO watcher, `code-host.kept-armed`) | the project's `az` identity |
|
|
216
262
|
| A reply on the worker's PR | `conduct reply` → `POST /workers/:id/replies` | the project's `az` identity, or its gh account |
|
|
217
|
-
| ADO: a pipeline queued
|
|
263
|
+
| ADO: a pipeline queued on the base, for the worker's merge whose run was cancelled or is missing | `conduct runs <sha> --requeue` → `POST /workers/:id/requeues` | the project's `az` identity |
|
|
218
264
|
| A train: its branch, the members' merges into it, its PR, a note on each member | `conduct train` (you) | the project's gh account |
|
|
219
265
|
|
|
220
266
|
Accounts are per project (see Accounts). Each code-host write is an event: `code-host.pr-created`, `code-host.landing-armed`, `code-host.kept-armed`, `code-host.replied`, `code-host.run-requeued`. So is each tracker write a worker causes: `tracker.transitioned` (or `tracker.transition-failed`) and `tracker.filed`. Rules still never change an item's state: only its phase notes do.
|
|
@@ -229,7 +275,7 @@ The `inbox` table holds everything that waits on the operator, across projects.
|
|
|
229
275
|
- the exact commands, and its links, each named (`{ label, href }`);
|
|
230
276
|
- when it was raised.
|
|
231
277
|
|
|
232
|
-
The console gives each link a button of its own, `open <label>`, and `conduct inbox` and `/inbox` print it as `<label>: <href>`. The daemon names the links it knows: a run is `run <n>`, a conflict's PR is `PR <n>`, a refused file is `rules` or `profile`, a
|
|
278
|
+
The console gives each link a button of its own, `open <label>`, and `conduct inbox` and `/inbox` print it as `<label>: <href>`. The daemon names the links it knows: a run is `run <n>`, a conflict's PR is `PR <n>`, a refused file is `rules` or `profile`, a train's are `<repo> PRs` and `train PR <n>`. Every other link is named from its shape:
|
|
233
279
|
|
|
234
280
|
- A pull request is `PR <n>`, or `<repo> PR <n>` when it isn't the project's repo.
|
|
235
281
|
- An Azure Pipelines or GitHub Actions run is `run <n>`.
|
|
@@ -278,7 +324,7 @@ If the tracker refuses the comment, nothing is resolved. Only a plan takes appro
|
|
|
278
324
|
The notifier routes each new inbox item to the phone, on two channels:
|
|
279
325
|
|
|
280
326
|
- **Remote Control:** the daemon appends `notify.requested` (`channel: "remote-control"`), and the conductor mod in the console pushes it with PushNotification. It reaches the phone only while the console is connected to Remote Control (see Mod). On Claude Code 2.1.296 these pushes are reported sent but never reach the phone (ATK-359), so the built-in `default` and `focus` also send to Pushover until a Claude Code release fixes it.
|
|
281
|
-
- **Pushover:** sent from the daemon. The keys are `PUSHOVER_TOKEN` and `PUSHOVER_USER`, or else the
|
|
327
|
+
- **Pushover:** sent from the daemon. The keys are `PUSHOVER_TOKEN` and `PUSHOVER_USER`, or else the credential `conductor-pushover` in the machine's secret store (`notify.pushover.credential`; see Accounts): its **user name is your Pushover user key** and its **password is the application's API token**. Save it with `cmdkey /generic:conductor-pushover /user:<user key> /pass` on Windows, `security add-generic-password -s conductor-pushover -a <user key> -w` on macOS, or `secret-tool store --label=conductor-pushover service conductor target conductor-pushover user <user key>` on Linux; each asks for the token. On macOS and Linux, delete an older item first (`conduct project check` prints the line that does). A credential saved while the daemon runs is read on the next push. The keys are never logged or stored. Only `~/.conductor` falls back to `conductor-pushover`: a daemon on another `CONDUCTOR_HOME` (a scratch home for a test) reads a credential only when its `config.json` names `notify.pushover.credential`, so it pushes to your phone only with that or with `PUSHOVER_TOKEN` and `PUSHOVER_USER` in its environment (ATK-506).
|
|
282
328
|
|
|
283
329
|
**Profiles** pick the channels. A profile is a list of rules, and the first rule that matches an item says where it goes; when none matches, the item stays in the inbox, unpushed. Three are built in, and `notify.profiles` in `config.json` replaces one by name or adds more:
|
|
284
330
|
|
|
@@ -326,11 +372,11 @@ Rules say what the conductor does when something happens (design note, section 9
|
|
|
326
372
|
]
|
|
327
373
|
```
|
|
328
374
|
|
|
329
|
-
- **Sources, in order:** the item's project's `rules
|
|
330
|
-
- **when:** `and`, `or`, `not` and parentheses over comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in [a, b]`, `<label> in item.labels`, `Started in item.phases`) and events. An event rule fires when one of its events happens: `note`, `plan`, `wait.resolved`, `run.failed` (a failed launch, a session that stopped unexpectedly, or a PR's red checks: `pr.checks-failed`), `worker.idle`, `worker.exited`, `worker.permission`, `worker.waiting`, `worker.parked` (a park; the session manager also asks it of each parked worker on a sweep, for `compact`), `inbox.raised`, `pr.comment`, `item.unblocked`, `item.closed`, `provider.login-failed` (a project's login lost, once per spell; see Accounts), `queue.pick`, `queue.drained`, `queue.ready-to-release`, `queue.triage`. A rule without one is a state rule, checked on each scheduler tick against each wait, inbox item, worker or project, or once for the machine, by the fields it reads. Fields: `project`, `item.id/area/labels/tier/priority`, `item.phases` (the phases of every note the item has had, the one being posted too), `plan.tier/landing`, `note.phase/kind`, `wait.kind/age`, `inbox.kind/age`, `worker.retries/phase`, `worker.context` (the session's context in tokens, see Workers), `spend.worker/item/project/today` (input, output and cache-write tokens, without cache reads: the worker's and the item's in all, the project's and the machine's today), `time`, `day`, `notify.profile`. Values carry units: `15m`, `2h`, `500k`, `2M`, `22:00`, `saturday`.
|
|
375
|
+
- **Sources, in order:** the item's project's `rules`, its machine profile's (`~/.conductor/projects/<project>.json`, named `project.<project>.machine:<id>`) before its repo's (`.claude/conductor.json`, changed by PR, named `project.<project>:<id>`; see Projects), then `~/.conductor/rules.json`, then the built-in defaults: conduct-atk's behavior written as rules (`launch`, `retire-closed`, `park-on-wait`, `resume-on-wait`, `compact-on-park`, `runaway`, `daily-cap`, `ready-to-release`, `queue-drained`, `triage`, which raises a new item that waits on the profile's triage label in the inbox, `conductor-handoff`, which escalates a worker's `Handoff · conductor` note to the console, and `hold-pre-start-handoff`, which adds the human label when a worker hands off as `human`, `operator`, `blocked` or `scope` before its `Started` note, so the scheduler never launches work no worker can do again; remove the label if the item should be picked later), and `release-pre-start-hold`, which takes that label off again when the worker clears the hold itself (its `Resumed`, or its `Started` after the hold), and leaves a human label the hold didn't add (ATK-575). A rule with an `id` replaces the rule with the same id further down, so a file holds only the differences, and a machine-profile rule replaces the repo's rule of its id (`"do": "none"` switches it off).
|
|
376
|
+
- **when:** `and`, `or`, `not` and parentheses over comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in [a, b]`, `<label> in item.labels`, `Started in item.phases`) and events. An event rule fires when one of its events happens: `note`, `plan`, `wait.resolved`, `run.failed` (a failed launch, a session that stopped unexpectedly, or a PR's red checks: `pr.checks-failed`), `worker.idle`, `worker.exited`, `worker.permission`, `worker.waiting`, `worker.parked` (a park; the session manager also asks it of each parked worker on a sweep, for `compact`), `inbox.raised`, `pr.comment`, `item.unblocked`, `item.closed`, `provider.login-failed` (a project's login lost, once per spell; see Accounts), `queue.pick`, `queue.drained`, `queue.ready-to-release`, `queue.triage`. A rule without one is a state rule, checked on each scheduler tick against each wait, inbox item, worker or project, or once for the machine, by the fields it reads. Fields: `project`, `item.id/area/labels/tier/priority`, `item.phases` (the phases of every note the item has had, the one being posted too), `item.labelled-by` (the ids of the rules whose label add still stands on the item: a label they added, not one it had already, that no rule removed since), `plan.tier/landing`, `note.phase/kind`, `wait.kind/age`, `inbox.kind/age`, `worker.retries/phase`, `worker.context` (the session's context in tokens, see Workers), `spend.worker/item/project/today` (input, output and cache-write tokens, without cache reads: the worker's and the item's in all, the project's and the machine's today), `time`, `day`, `notify.profile`. Values carry units: `15m`, `2h`, `500k`, `2M`, `22:00`, `saturday`.
|
|
331
377
|
- **do:** `launch`, `retire`, `park`, `resume worker`, `retry`, `pause launches [in <project>] [until <when> | for <duration>]`, `pause all launches …`, `unpause launches`, `focus [<project>] weight|slots <n> until <when>`, `auto-approve now`, `auto-approve after <duration>`, `inbox <kind> ["<text>"]`, `remind operator`, `notify <channel> ["<text>"]`, `notify profile <name> [until <when>]`, `label add|remove human|triage|shipped-open`, `flag shipped-open`, `escalate console "<ask>"`, `none`. One string, or a list.
|
|
332
378
|
- **Guardrails:** rules act inside Area locks, slots, quiet hours and config.json's limits. A rule that would go past one is refused when it loads: `focus … slots` over `scheduler.slots`, an override with no end or one over 14 days, `retire` on anything but `item.closed`, `launch` outside `queue.pick` / `item.unblocked`, `park` outside `worker.waiting`, `resume` outside `wait.resolved` / `pr.comment`, `compact` outside `worker.parked`, `retry` outside `run.failed`. `merge`, `push`, `publish`, `approve`, `delete` and `run` aren't in the vocabulary: rules never merge, push, publish, approve prod, delete or run commands, and the daemon writes to a code host only when the owning worker asks (see Writes).
|
|
333
|
-
- **Reload:** saving `rules.json` or a project's profile reloads its rules.
|
|
379
|
+
- **Reload:** saving `rules.json` or a project's machine profile reloads its rules, and so does a fetch of its clone that brings another `.claude/conductor.json` on the base branch. A profile changed either way, or while the daemon was down, is taken whole: the daemon stores it and logs `project.updated` with the fields that `changed`, and the scheduler, watchers and the rest use it from then on. A project keeps the name its folder gives it: the repo's `name` is only what `project add` takes when no `--name` is given, and a machine profile that names another project is refused. To rename one, `conduct project remove <old name>`, then `conduct project add <url> --name <new name>` (in that order: with both registered, both would read the same queue and could launch the same item). The remove drops the old registration and its queue read, resolves its open inbox items (the refusal's among them) and logs `project.removed`, on which the daemon drops its rules and its watch of the file. It is refused while the project has workers in flight, and works without the daemon. A file the conductor refuses leaves its last good rules (for a profile, the whole last good profile) in force, logs `rules.rejected` and raises a `failed` inbox item until it loads again (`rules.loaded`), including after a restart. `conduct project add` refuses a profile whose rules don't load, with or without the daemon.
|
|
334
380
|
- **Checking:** `conduct rules` lists the rules in force (`project.atk:#2`, `machine:runaway`, `default:launch`) and what replaces what. `conduct rules test <file>` dry-runs a sample, such as `{ "event": "pr.comment", "project": "atk", "fields": { "wait.kind": "merge", "wait.age": "3h" } }` (leave out `event` for a state rule), and shows what fires, each action's guardrail, and why every other rule of the trigger didn't. Both read the files directly when the daemon isn't running.
|
|
335
381
|
|
|
336
382
|
- **Why:** every action the conductor takes is an event that names its rule, directly (`rule`) or through the event that caused it (`data.cause`). `conduct why <event id>` follows that chain back and shows the rule as it fired; `conduct why ATK-315` does it for the item's newest actions.
|
|
@@ -386,15 +432,47 @@ The scheduler moves conduct-atk's tick into the daemon (design note, section 8).
|
|
|
386
432
|
|
|
387
433
|
**Overrides** end on their own: `conduct pause atk --until 17:00`, `conduct pause --until tomorrow` (every project), `conduct unpause atk`, `conduct focus atk --slots 3 --until monday`. `--until` takes `17:00` (the next one), `tomorrow`, a day, or a date and time. Each is an `override.set` event, which `conduct why` attributes to the command, and they show in `conduct rules`.
|
|
388
434
|
|
|
389
|
-
##
|
|
435
|
+
## Projects
|
|
436
|
+
|
|
437
|
+
A conducted project is a clone the daemon owns (design note v2, sections 2 and 7; ATK-527). Everything of it lives under `~/.conductor/projects`:
|
|
438
|
+
|
|
439
|
+
| Path | Holds |
|
|
440
|
+
|---|---|
|
|
441
|
+
| `<name>.json` | its machine profile: what this machine says about the project, which wins over the repo's |
|
|
442
|
+
| `<name>/repo` | the clone of its remote, which the daemon fetches and adds worktrees to |
|
|
443
|
+
| `<name>/worktrees/<item>` | a worker's worktree (see Workers) |
|
|
444
|
+
|
|
445
|
+
**Your first conducted project.** `conduct init` takes a repo from a checkout to a passing `conduct project check` with no hand-written JSON (ATK-528). The repo is on GitHub or Azure DevOps and has at least one commit on its base branch.
|
|
446
|
+
|
|
447
|
+
1. Install the conductor (see On PATH) and sign in to the code host and tracker (see Accounts).
|
|
448
|
+
2. In a checkout of the repo, run `conduct init`. It shows what it detected:
|
|
449
|
+
- the code host from `origin`;
|
|
450
|
+
- CI as the code host's own (a hint when the pipeline files are another's);
|
|
451
|
+
- the base branch from `origin/HEAD`;
|
|
452
|
+
- `setup` from the lockfile at the root (`pnpm install --frozen-lockfile`, `npm ci`, `yarn install`, `bun install`, `uv sync`, `poetry install` or `go mod download`);
|
|
453
|
+
- a `verify-*` skill in `.claude/skills`;
|
|
454
|
+
- the item key most recent commit subjects carry.
|
|
455
|
+
|
|
456
|
+
Then it asks for the rest, each detected value the default: the name, the base, the tracker (the code host's own issues or Boards, or Linear), its key, team or query, `setup` and the verify skill. `--yes` asks nothing and refuses, with each one's flag, what it couldn't detect. Without `--yes` it needs a terminal to ask in: node sees none in Git Bash's mintty, so use Windows Terminal there, or `--yes`.
|
|
457
|
+
3. It writes a starter profile to `~/.conductor/projects/<name>.json`: the code host, CI, base, tracker, `conductor:work-item` and the verify skill, 2 slots, the plan and merge gates, a release handoff and `setup`, with the `conductor` minimum its fields need. `--shared` writes `.claude/conductor.json` in the checkout instead, which the conductor reads only on `origin/<base>`: commit it, push it and run `conduct init` again. A profile file that is there is never overwritten, and a repo profile on `origin/<base>` that names the project means nothing is written; one only in the working tree stops `init` until it is pushed.
|
|
458
|
+
4. It runs `conduct project add` on the checkout. For a new clone it prints the trust step: run `claude` in the clone once and accept the prompt. In a terminal it waits for Enter; with `--yes` it stops there.
|
|
459
|
+
5. It runs `conduct project check`. With no verify skill, the worktree check fails as a launch would, and `init` points at the conductor plugin's `/conductor:create-verification-skill`, which loads only with the plugin: run `claude --plugin-dir <the plugin>` in the checkout (`init` prints the folder), make the skill under the name the profile's `skills.verify` gives, commit it and push it.
|
|
460
|
+
6. Run `conduct init` again after each step: it keeps what is done, fetches the clone and checks again. On a project that is set up, ATK among them, it writes nothing and only fetches and checks. Once the check passes, give the tracker's projects a priority (Linear) or label items `conduct` (GitHub Issues), and `conduct launch <item>`.
|
|
461
|
+
|
|
462
|
+
**Adding one.** `conduct project add <url | path> [--name <name>]` clones the remote into `<name>/repo`, in the CLI's own process, so its output shows and no API timeout applies. Given a path, it reads that checkout's `origin` and clones from the remote: the folder itself is never cloned, and nothing the conductor does touches it again. The name is `--name`, else the `name` the repo's `.claude/conductor.json` gives on its default branch; a repo with no profile needs `--name`. The clone is made in a staging folder first, so one that fails leaves nothing. Adding a project again fetches its clone (its origin must be the same remote) and updates the registration in place: its inbox, items and workers stay. Then the daemon registers it (or the store, with none running). Claude Code trusts a worktree by its repository, and nobody has opened a new clone in Claude Code yet, so `add` ends with the one step that trusts it: run `claude` in the clone once and accept the trust prompt, then `conduct project check <name>`.
|
|
463
|
+
|
|
464
|
+
**Its profile** comes in two layers, merged as the files are written, before the schema reads them:
|
|
390
465
|
|
|
391
|
-
|
|
466
|
+
- the **machine profile**, `<name>.json` (JSONC), optional beside a repo profile. A project with no repo profile keeps a whole profile here;
|
|
467
|
+
- the **repo profile**, `.claude/conductor.json` at `origin/<base>` in the clone, optional, changed by PR and shared by the team. `<base>` is the machine profile's `baseBranch`, else the remote's default branch (`origin/HEAD`); when the file there names another `baseBranch`, it is read once more at that one.
|
|
392
468
|
|
|
393
|
-
|
|
394
|
-
2. When they differ, it records the pins as pending (a `checkout.pending` event). With the main checkout on `<base>` and no local changes to `.atk-lock.json`, it then runs `git merge --ff-only origin/<base>`.
|
|
395
|
-
3. Once `HEAD` has the pins, whether by this pull or yours, it runs `atk install` for the pending assets. A `checkout.updated` event lists each `name old → new`. An install that fails or leaves drift stays pending, and the next check tries it again, in this daemon or the next.
|
|
469
|
+
Objects merge key by key and the machine's value wins; arrays (`ports`, `setup`, `approvers`, `gates`, …) are replaced whole. `rules` stack instead: the machine profile's first, then the repo's, then `rules.json`, then the defaults, so a machine rule replaces the repo's rule of its id (see Rules). Each layer's `conductor` minimum is checked on its own, and `protocol` on the merge. `name` is the registered one: a machine profile may repeat it, not change it.
|
|
396
470
|
|
|
397
|
-
|
|
471
|
+
`conduct profile <name>` prints the merged profile from the files and the clone as fetched last, one line per field with its value and its source (`machine`, `repo` or `default`), then each rule with its layer; `--json` gives `{ profile, sources }`. It works with or without the daemon.
|
|
472
|
+
|
|
473
|
+
**Keeping it current.** When the daemon starts and every `clones.fetchMinutes` (10) after, it runs `git fetch --quiet --prune origin` in each clone and then reads the profile again, so a changed `.claude/conductor.json` on the base branch is in force as a saved machine profile is (a watch on `<name>.json` takes that at once). A worktree create waits out a fetch that is running, and the fetches pass a clone by while a create works in it, so the two never write the clone's refs at once. A fetch can't prompt for credentials (`GIT_TERMINAL_PROMPT=0`) and gives up after 2 minutes. A failed fetch is logged once a spell, and the profile stays as it was. Nothing is pulled, installed or fast-forwarded anywhere else: a worktree's `setup` installs what its branch pins.
|
|
474
|
+
|
|
475
|
+
**From a project registered by its checkout** (before ATK-527): the daemon conducts such a row no longer. Its profile is refused with the step that moves it, `conduct project add "<that checkout>"`, which clones the checkout's origin and keeps the registration, and the scheduler launches none of its items meanwhile. Workers in flight keep their worktrees in that checkout, and retire from it: that retire is the one time the conductor runs git there (`git worktree prune`, and `git branch -D` of the worker's branch). A profile refusal of the project, whichever file it named, resolves once the project's profile loads.
|
|
398
476
|
|
|
399
477
|
## Skill trains
|
|
400
478
|
|
|
@@ -453,11 +531,23 @@ Accounts belong to the person running the daemon, not to the repo, so each proje
|
|
|
453
531
|
|
|
454
532
|
| Order | Source | Azure DevOps (PRs, runs, Boards) | GitHub (reads, and writes such as `conduct train`'s) | Linear (waits, notes, labels, queue, briefs) |
|
|
455
533
|
|---|---|---|---|---|
|
|
456
|
-
| 1 | **project token**: a
|
|
457
|
-
| 2 | **machine token**: a conductor-only env var, else a
|
|
534
|
+
| 1 | **project token**: a credential in the machine's secret store that the project names | `projects.<name>.ado.token`: a PAT, sent as Basic auth | `projects.<name>.github.token`: a token, as `GH_TOKEN` | `projects.<name>.linear.credential`: an API key |
|
|
535
|
+
| 2 | **machine token**: a conductor-only env var, else a credential in the store | `CONDUCTOR_ADO_TOKEN`, else `conductor-ado` | `CONDUCTOR_GITHUB_TOKEN`, else `conductor-github` | `CONDUCTOR_LINEAR_KEY` or `LINEAR_API_KEY`, else `conductor-linear` (`CONDUCTOR_LINEAR_CREDENTIAL` names another) |
|
|
458
536
|
| 3 | **CLI login**, last: it usually carries the widest permissions | `az account get-access-token --resource 499b84ac-…`, with `--tenant <tenant>` when `ado.tenant` names one | `gh auth token`, with `--user <user>` when `github.user` names one, so gh's active account doesn't change | none |
|
|
459
537
|
|
|
460
|
-
|
|
538
|
+
**The secret store** is the platform's own:
|
|
539
|
+
|
|
540
|
+
| Platform | Store | Save a token (each asks for the secret) |
|
|
541
|
+
|---|---|---|
|
|
542
|
+
| Windows | Credential Manager (generic credentials) | `cmdkey /generic:<target> /user:pat /pass` |
|
|
543
|
+
| macOS | the login keychain (generic passwords, the target as service) | `security delete-generic-password -s <target>; security add-generic-password -s <target> -a pat -w` |
|
|
544
|
+
| Linux | libsecret (the Secret Service: GNOME Keyring, KeePassXC …), attributes `service=conductor target=<target>` | `secret-tool clear service conductor target <target>; secret-tool store --label=<target> service conductor target <target> user pat` |
|
|
545
|
+
|
|
546
|
+
Linear's key is saved with the user name `linear` instead of `pat`. On macOS and Linux the old item is deleted first: an item there is kept per user name (macOS) or per set of attributes (Linux), so saving under another user name would leave two. `conduct project check` prints the line for its platform. **Env fallback:** where the store has no such credential, or can't be read (`secret-tool` missing, or a headless Linux box with no D-Bus session or keyring), the conductor reads `CONDUCTOR_SECRET_<TARGET>` instead: the target in upper snake case, so `conductor-atk-ado` is `CONDUCTOR_SECRET_CONDUCTOR_ATK_ADO`, with its user name, when one is needed (Pushover), in the same name plus `_USER`. Targets that differ only in punctuation (`a.b`, `a-b`) share a variable, so give them names that differ in letters or digits.
|
|
547
|
+
|
|
548
|
+
**The names lost their ATK prefix in ATK-529:** the machine's Linear key is `conductor-linear` (it was `atk-conductor-linear`), Pushover's `conductor-pushover` (it was `atk-conductor-pushover`), and `CONDUCTOR_LINEAR_CREDENTIAL` replaces `ATK_CONDUCT_LINEAR_CREDENTIAL`, which is no longer read. On Windows, the first read of a new name that finds none copies the old Credential Manager entry to it, with its user name and secret, and leaves the old one in place for an older conductor; after that the new one is found, so the old name is never read again. Delete the old ones with `cmdkey /delete:atk-conductor-linear` and `cmdkey /delete:atk-conductor-pushover` once no older conductor runs.
|
|
549
|
+
|
|
550
|
+
Only the conductor's own env names count: another tool's `AZURE_DEVOPS_PAT` or `GITHUB_TOKEN` never changes what the conductor signs in as. A token scoped to one project wants:
|
|
461
551
|
- **Azure DevOps:** Code (read & write) and Build (read & execute), plus Work Items (read & write) for Boards;
|
|
462
552
|
- **GitHub:** a fine-grained token on the repo with Contents, Pull requests and Issues (read & write) and Actions (read);
|
|
463
553
|
- **Linear:** an API key limited to the project's team.
|
|
@@ -466,7 +556,7 @@ Only the conductor's own env names count: another tool's `AZURE_DEVOPS_PAT` or `
|
|
|
466
556
|
|
|
467
557
|
A project whose entry names its CLI account (`ado.tenant`, `github.user`) keeps that account ahead of the machine's token, which is another identity and may not reach the project's organization. One machine ADO PAT serves every other project, so a project in another organization than the PAT's gets a token of its own.
|
|
468
558
|
|
|
469
|
-
Found means there: a project token that is named but missing, or any token that is there but refused, is a lost login (below), never a quiet fall back to a wider credential. A refused PAT is read again once, so a replaced one is tried; the same one refused again is the lost login. The machine credential is optional: one that
|
|
559
|
+
Found means there: a project token that is named but missing, or any token that is there but refused, is a lost login (below), never a quiet fall back to a wider credential. A refused PAT is read again once, so a replaced one is tried; the same one refused again is the lost login. The machine credential is optional: one that the store says isn't saved (on Windows `cmdkey /list`, so no PowerShell starts), or that can't be read, is passed over.
|
|
470
560
|
|
|
471
561
|
Each credential is kept per account: an az token 20 minutes, renewed when ADO answers 401 or 203; a token read again every 20 minutes, so a replaced or removed one is seen; a gh token asked again once on a 401; a Linear key until Linear answers 401, when it is read again once. Projects on the same account share it. The secrets are never logged, stored or put on a command line.
|
|
472
562
|
|
|
@@ -542,14 +632,11 @@ Everything goes through the project's gh account (`projects.<name>.github.user`,
|
|
|
542
632
|
|
|
543
633
|
The broker shares what every project on the machine uses (ATK-318).
|
|
544
634
|
|
|
545
|
-
**Ports.** Each profile
|
|
546
|
-
- A
|
|
547
|
-
-
|
|
548
|
-
- A
|
|
549
|
-
-
|
|
550
|
-
- A project's dev scripts read the assignment with `--json`, as ATK's `scripts/dev-ports.mjs assign` does. They keep their own scheme when it exits 1 (`not brokered`): no daemon, an older one, or a checkout in no registered project.
|
|
551
|
-
- The broker knows only the slots it gave out. A slot a script picked on its own while no daemon answered stays unknown until that worktree asks the broker; until then only the listening probe keeps the slot clear. So `--prefer` is the slot the script would pick itself (`dev-ports.mjs` passes the checkout's own slot or its own free-slot scan's). The preferred slot is taken without the listening probe, because the checkout's own servers may be what listens there.
|
|
552
|
-
- A stored assignment follows its project's profile: when the base ports or `maxSlot` change, the worktree moves, its old slot first.
|
|
635
|
+
**Ports.** Each profile names the ports a worktree's dev servers need, such as ATK's `"ports": ["web", "api"]` (design note v2, section 2; ATK-526).
|
|
636
|
+
- A launch gives the worktree one port per name from the machine's pool, `ports.first` to `ports.last` in config.json (41000 to 41999): each the pool's first port that no other worktree of any project holds, nothing listens on (IPv4 or IPv6 loopback), and that binds, which also skips a range Windows reserves. They reach `setup` and the worker as `CONDUCTOR_PORT_<NAME>` (see Workers).
|
|
637
|
+
- The pool sits away from the usual dev ports and their slot schemes, such as ATK's 3000+N and 7071+N for a person's own worktrees, so those never take a port a worker was given.
|
|
638
|
+
- A worktree keeps its ports while the profile names the same ports; a changed list gives it new ones. Retiring the worker frees them, and so does a worktree whose directory is gone (at the next assignment).
|
|
639
|
+
- `conduct ports` lists the assignments, and `conduct ports <path>` gives one worktree's (`--json` for either). Only a launch assigns. `conduct project check` previews the ports a new worktree would get, saving nothing.
|
|
553
640
|
|
|
554
641
|
**Locks.** `conduct lock acquire chrome` takes the lock every project's verify runs share. It answers the work-issue helper's JSON (`acquired`, `heldBy`, `since`, `refreshed`; `released` for a release; `verdict` for a status).
|
|
555
642
|
- The owner is `--owner`, else the item of the worker whose worktree this is.
|
|
@@ -597,7 +684,8 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
|
|
|
597
684
|
|
|
598
685
|
| File | Holds |
|
|
599
686
|
|---|---|
|
|
600
|
-
| `
|
|
687
|
+
| `projects/` | each conducted project's machine profile, clone and worktrees (see Projects) |
|
|
688
|
+
| `config.json` | machine settings, JSONC (comments allowed), validated at startup; `clones.fetchMinutes` (10, see Projects); `inbox.runawayTokens` (1500000, the `runaway` rule's number); `notify` and `quietHours` (see Notifications); `scheduler` holds `mode` (`on`, `observe` or `off`), `slots` (4, across projects, and the most any rule can give one project), `dailyTokens` (20000000, the `daily-cap` rule's number) and `tickSeconds` (120); `sessions` holds `pollSeconds` (10), `settleSeconds` (5), `permissionMinutes` (5), `idleMinutes` (20), `compactTokens` (300000, the `compact-on-park` rule's number); `watchers` holds `ado`, `github`, `health`, `linear` and `npm`, each `{ intervalSeconds, perMinute }` (30/60, 30/30, 30/30, 30/10, 20/30), `statsMinutes` (10) and `conflictMinutes` (30); `workers` holds `tab` (false: workers run headless) and `terminal` (`auto`; see Tabs) |
|
|
601
689
|
| `rules.json` | machine rules, JSONC, reloaded on save (see Rules) |
|
|
602
690
|
| `token` | the API token, readable by this user only; every request sends `Authorization: Bearer <token>` |
|
|
603
691
|
| `conductor.pid`, `port` | the single-instance lock and where the API listens (`127.0.0.1`) |
|
|
@@ -606,7 +694,7 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
|
|
|
606
694
|
|
|
607
695
|
## API
|
|
608
696
|
|
|
609
|
-
- `GET /projects`: the registered projects
|
|
697
|
+
- `GET /projects`: the registered projects, each with its `clone`, `url`, profile and `sources`. `POST /projects` with `{ "name": "<name>" }` registers the clone `conduct project add` made at `~/.conductor/projects/<name>/repo` (400 when there is none, or its profile doesn't read). `DELETE /projects/<name>` removes one: `{ project, resolved }` (the inbox items it resolved), 404 for a name no project is registered under, or 409 naming its workers in flight. `POST /projects/<name>/check` with `{ "worktree": false }` or `{}` runs `conduct project check` as the daemon's accounts: `{ project, results: [{ check, status, summary, details, fix }] }`, or 404 for a name no project is registered under.
|
|
610
698
|
- `GET /events`: the event log as server-sent events. Add `?since=<id>` (or send `Last-Event-ID`) to replay from an id. Without either, the stream starts at the live end. `conduct events` prints it one JSON event per line: the events after `--since` (all of them without it), or with `--follow` everything from there on (live without `--since`). `--follow` reconnects with `Last-Event-ID` when the daemon goes away, so a restart loses nothing, and prints the stream's state as lines without an id: `{"kind":"conduct.connected"}` and, once per outage, `{"kind":"conduct.disconnected","error":…}`. `?console=1` (`conduct events --follow --console`, which the conductor mod runs, or `conduct events --follow` with `CONDUCTOR_CONSOLE=1`, as a mod from before `--console` runs it until `/reload-plugins`) marks the console's stream: while one is open, escalations have a console to wake (see Console).
|
|
611
699
|
- `POST /shutdown`: a clean stop (`conduct stop`).
|
|
612
700
|
- `GET /console/escalations`: the open escalations, oldest first (see Console).
|
|
@@ -616,7 +704,7 @@ Everything lives in `~/.conductor` (`CONDUCTOR_HOME` overrides it):
|
|
|
616
704
|
- `GET /fleet`: the workers in flight, with session activity, phase, PR, waits and spend (today, total).
|
|
617
705
|
- `POST /workers` with `{ "item": "ATK-309", "project"?, "probe"?, "prompt"?, "conductor"? }`: launch; answers 202 with the `launching` worker. `GET /workers/:id` shows it with its latest events.
|
|
618
706
|
- `DELETE /workers/:id` (`?force=true`): retire; 409 with the unfinished work (the worktree's, and each `.scratch/repos` checkout's under `checkouts`) when it refuses.
|
|
619
|
-
- `POST /workers/:id/attach`: wake if parked, mark attached, open the tab.
|
|
707
|
+
- `POST /workers/:id/attach`: wake if parked, mark attached, open the tab; `tab` is why none opened, else null, and `hint` how to reach one off the desktop (`tmux attach -t <session>`).
|
|
620
708
|
- `POST /workers/:id/prs` with `{ "title", "body", "repo"? }`: open the worker's PR after the ownership checks (see Worker verbs); 201 with the PR, 409 refused, 503 a lost login (with `login.provider` and `login.command`), 502 the host failed.
|
|
621
709
|
- `POST /workers/:id/landings` with `{ "pr", "reason", "mode"?, "rearm"?, "repo"? }`: `conduct land` for the worker; 200 with the landing and its verdict. `POST /workers/:id/replies` with `{ "pr", "body", "thread"?, "repo"? }`: `conduct reply`; 201. Both answer 409, 503 and 502 as `/prs` does.
|
|
622
710
|
- `POST /items/:id/notes` with `{ "body": "## work-issue · …", "worker"?: 1 }`: post a phase note (see Notes); 201 with the note and the worker. 409 when it won't post it; 502 when the tracker didn't take it, with `posted: "no"` or `"unknown"`.
|
|
@@ -659,24 +747,49 @@ Install the package globally, next to `atk`. `dev` follows `develop`; `latest` f
|
|
|
659
747
|
```bash
|
|
660
748
|
npm install --global @detergent-software/conductor@dev
|
|
661
749
|
conduct install-startup
|
|
662
|
-
conduct project add <
|
|
750
|
+
conduct project add <the project's remote URL, or a checkout of it>
|
|
663
751
|
```
|
|
664
752
|
|
|
665
|
-
`conduct project add`
|
|
753
|
+
`conduct project add` clones the remote into `~/.conductor/projects/<name>/repo` (see Projects). After that the daemon reads the profile again when it starts, when the machine profile is saved and after each fetch of the clone, so a merge that changes `slots` or `skills.work` needs no `conduct project add`. An older daemon refuses a profile with fields it doesn't know, so upgrade the daemon before a profile that uses new ones lands.
|
|
754
|
+
|
|
755
|
+
A profile that uses new fields says which conductor reads them: `"conductor": "3.0.0-dev.9"`, the version that first read the newest of them (a `-dev.N` while it is only on `dev`; a stable minimum such as `3.0.0` is newer than every `3.0.0-dev.N`, as semver orders them). Every conductor from the one that knows this key (ATK-573) checks it before the rest of the profile, and an older one refuses the file with one line instead of a list of fields: `conductor: needs 3.0.0-dev.9 or newer; this is 3.0.0-dev.7: run \`conduct upgrade --tag dev\`` (`--tag latest` for a stable minimum). The worker verbs that read the profile in a worktree (`conduct state`, `conduct branch`, `conduct search`, a lock with no daemon) say the same and exit 1, and the daemon's inbox item carries the line and the upgrade command. While a project's profile on disk doesn't read (a minimum above this conductor, a schema problem, another protocol), the scheduler launches none of the project's items: each waits in `conduct queue` as `profile refused: <its first problem>`, since a new worktree would hold the same file and its verbs would refuse it. A profile that reads but whose rules are refused, or that renames the project, keeps the last good profile and launches as before. Workers already running carry on, and launches resume on the first tick after the file loads.
|
|
756
|
+
|
|
757
|
+
`src/profile-fields.ts` records the conductor that first read each field as it is written today (`FIELD_SINCE`, ATK-577), and its type makes a schema field without a record a typecheck error. Fields that 2.0.0 read, the first conductor that reads protocol 2, need no minimum: an older one refuses the profile on `protocol` first. `minimumProblems` reads a profile as written, so a field a default fills in doesn't count. It names each field the profile writes that is newer than its minimum, or newer than 2.0.0 when the profile sets none. A conductor test holds ATK's `.claude/conductor.json` to it, and `atk-conductor-ci` runs on changes to that file. Any other project hears it from `conduct project check`, as a `warn` on its profile check.
|
|
758
|
+
|
|
759
|
+
A PR that adds or reshapes a field can't know the number semantic-release will give it, so it takes the next one:
|
|
760
|
+
|
|
761
|
+
1. Find the newest conductor tag: `git tag -l 'conductor-v*' --sort=-v:refname` (after a `git fetch --tags`). On `develop` the next release is its `-dev.N` plus one, such as `3.0.0-dev.12` after `3.0.0-dev.11`, unless the PR's commits make a bigger bump than that series: after a stable release, the first `-dev.1` of the version its commit type makes (a fix's patch, a feature's minor), and for a breaking change the next major's `-dev.1`, as `2.2.0-dev.3` was followed by `3.0.0-dev.1`.
|
|
762
|
+
2. Record that version for the field in `FIELD_SINCE`. If ATK's profile writes the field in the same PR, raise its `conductor` to it too. Its launches are then held, with the upgrade line, until the daemon runs that release (`conduct upgrade --tag dev`, once Jason has approved its stage).
|
|
763
|
+
3. After the merge, `conduct runs <merge>` gives the version `atk-conductor-release` staged. If another conductor PR took the number first, the record and the minimum are one too low: fix both in a follow-up. Too low lets the version before the field read the profile, and fail with the field list this key replaces. Too high holds launches until that version exists.
|
|
764
|
+
|
|
765
|
+
A `test`, `chore` or `docs` change stages no release and records nothing.
|
|
766
|
+
|
|
767
|
+
After an `--allow-downgrade` to a version without those fields, the stored copy no longer validates either: the project shows `the stored profile no longer validates` and isn't conducted until its file, saved without them, is read again.
|
|
666
768
|
|
|
667
769
|
Then `conduct project check <name>` says whether the project can be conducted, before its first launch finds out. Each check prints one line, `ok`, `warn`, `fail` or `skip`, with a fix under a warn or a fail, and the command exits 1 when any check fails (`--json` prints the same as data):
|
|
668
770
|
|
|
669
|
-
- **profile:** the
|
|
670
|
-
- **auth:** which credential each provider the project uses signs in with (project token, machine token or CLI login; see Accounts), probed as the daemon would. For each that isn't the project's own token, a detail line gives the scopes, the `cmdkey`
|
|
771
|
+
- **profile:** the layers (see Projects) read with this build's schema; a `warn` lists the fields that differ from the daemon's stored copy, which it takes on the next save, fetch or start, and each field a file writes that is newer than its `conductor` minimum (`minimumProblems`, above), with the version to raise it to (ATK-580). A project still registered by a checkout fails, with the `conduct project add` that moves it to a clone. The later checks use the resolved profile when it reads, else the stored copy; with neither they are `skip`.
|
|
772
|
+
- **auth:** which credential each provider the project uses signs in with (project token, machine token or CLI login; see Accounts), probed as the daemon would. For each that isn't the project's own token, a detail line gives the scopes, the line that saves a token in the platform's store (`cmdkey`, `security` or `secret-tool`) and the config key that would scope it; that is advice, and the check passes. A token that is there but refused, or no credential at all, fails.
|
|
671
773
|
- **tracker:** the tracker's login answers, and the queue reads (Linear: the team, and whether any of its projects has a priority; Boards: the saved query; GitHub Issues: the labelled issues).
|
|
672
774
|
- **code-host** and **ci:** the code host's login answers and the base branch exists; each release's `pipeline` names exactly one of the repo's pipelines.
|
|
673
|
-
- **worktree:** the launch's
|
|
674
|
-
- **skills:** `
|
|
675
|
-
- **ports:** the
|
|
775
|
+
- **worktree:** the launch's worktree steps on a throwaway `conduct-check-<time>` in the project's worktrees folder: `git worktree add` in the clone from `origin/<base>`, `localFilesFrom`'s files, the ports the broker would give, and `setup`. Then the profile's skills must be there after it, and a `warn` says when git doesn't ignore `.claude/settings.local.json`, where the ports go. A `claude --bg` with no prompt then checks that Claude Code would start a session there: it starts idle, costs no tokens and is removed at once. Claude Code keeps workspace trust per repository, so a clone nobody has opened in Claude Code fails here with the one step that trusts it, `claude` run in the clone once with its trust prompt accepted (ATK-571). It is removed with its branch, whatever happened. The one check that writes; `--no-worktree` skips it, since setup can take a while (ATK's runs `pnpm install`).
|
|
776
|
+
- **skills:** a `conductor:<skill>` is in this package's plugin, and `skills.work` declares `protocol: 2` in its SKILL.md frontmatter (worker protocol 2). A project's own skills arrive through its `setup` (ATK's runs `atk install`), not in the clone, so the worktree check looks for them.
|
|
777
|
+
- **ports:** the machine's pool has a free port for each of the profile's `ports`, saving nothing; `skip` for a profile with none.
|
|
676
778
|
- **health:** each `health` URL answers; a `warn` at most, since an environment can be down.
|
|
677
779
|
|
|
678
780
|
With the daemon running it checks through the API, as the daemon's own accounts; without it, here, as the machine's.
|
|
679
781
|
|
|
782
|
+
A new worktree's local files come from the profile (design note v2, section 2; see Workers):
|
|
783
|
+
|
|
784
|
+
```jsonc
|
|
785
|
+
// The dev ports a worktree needs, by name: CONDUCTOR_PORT_WEB and CONDUCTOR_PORT_API.
|
|
786
|
+
"ports": ["web", "api"],
|
|
787
|
+
// Run in order in each new worktree; they build its gitignored files from what the repo commits.
|
|
788
|
+
"setup": ["pnpm install --frozen-lockfile", "node scripts/dev-ports.mjs assign"],
|
|
789
|
+
// Optional: copy the .worktreeinclude files of a checkout you keep, for local files made by hand.
|
|
790
|
+
"localFilesFrom": "C:\\Users\\you\\src\\project"
|
|
791
|
+
```
|
|
792
|
+
|
|
680
793
|
The profile's optional `work` section is for the project's work skill; the daemon only checks it:
|
|
681
794
|
|
|
682
795
|
```jsonc
|
|
@@ -696,7 +809,7 @@ conduct upgrade
|
|
|
696
809
|
|
|
697
810
|
It takes the tag the installed version came from (`dev` for an `X.Y.Z-dev.N`, `latest` otherwise; `--tag` picks one), and does nothing when that tag's version is already installed. When the tag points at an older version (semver, so `1.2.0-dev.4` is older than `1.2.0`), it refuses before it stops anything and names that version; `--allow-downgrade` installs it anyway and reports `downgraded`. Otherwise it stops the daemon, runs `npm install --global @detergent-software/conductor@<the tag's version>` (the exact version it compared, in case the tag moves) and starts the daemon again: through the `Conductor` logon task when the task runs this `cli.js`, else as a detached `conduct supervise --fail-fast`. A supervisor waiting to restart a daemon that keeps dying is stopped the same way before npm runs (see Restarts), so it can't restart `serve` from the `cli.js` npm is replacing, and the conductor starts again on the new version. A daemon that wasn't running stays stopped. If npm fails, the daemon still starts again on whatever npm left in place, and `upgrade` exits 1 with npm's output. A linked build (below) refuses: its `cli.js` isn't under npm's global `node_modules`.
|
|
698
811
|
|
|
699
|
-
**From a checkout instead (development).** `npm link` puts
|
|
812
|
+
**From a checkout instead (development).** `npm link` puts a checkout's build on PATH, so every worktree and the logon task run that build. Run it from your own checkout of the conductor's repo, and upgrade by pulling `develop`, building, then `conduct stop` and `conduct serve`:
|
|
700
813
|
|
|
701
814
|
```bash
|
|
702
815
|
pnpm install
|
|
@@ -714,7 +827,7 @@ The console (design note, section 11) is the one Claude session that stays open
|
|
|
714
827
|
The console belongs to the machine, not to a project (design note v2, section 1): it runs in `<home>/console` (`~/.conductor/console`), a folder of the conductor's own, and opens with no project registered. It reads items through the `conduct` verbs, which find the project from the item while the daemon runs, and a subagent that reads a project's code or logs works in that project's checkout, from `conduct status`.
|
|
715
828
|
|
|
716
829
|
```bash
|
|
717
|
-
conduct console # a tab in Windows Terminal (window "conductor"),
|
|
830
|
+
conduct console # a tab in ~/.conductor/console: Windows Terminal (window "conductor"), iTerm or Terminal, or tmux (session conductor)
|
|
718
831
|
conduct console --here # the same session in this terminal
|
|
719
832
|
```
|
|
720
833
|
|
package/build/brief-cli.js
CHANGED
|
@@ -114,7 +114,7 @@ async function briefHere(paths, item, io, why) {
|
|
|
114
114
|
if (!ITEM.test(item))
|
|
115
115
|
throw new ConductorError(`"${item}" is not a tracker item, such as ATK-311`);
|
|
116
116
|
const key = item.toUpperCase();
|
|
117
|
-
const here = await checkoutProject(io.cwd, key, why, 'read it from');
|
|
117
|
+
const here = await checkoutProject(paths, io.cwd, key, why, 'read it from');
|
|
118
118
|
if ('refusal' in here)
|
|
119
119
|
return notBriefed(here.refusal);
|
|
120
120
|
const { profile } = here;
|
package/build/brief-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brief-cli.js","sourceRoot":"","sources":["../src/brief-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAEL,UAAU,EACV,UAAU,EACV,OAAO,EAEP,QAAQ,EAER,YAAY,EACZ,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAoB,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,mGAAmG;AACnG,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAWhC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAEvG,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;SAC3G,QAAQ,EAAE;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACxB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC,KAAK,CACf,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;QACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACzB,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;QACvB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE;KAC3G,CAAC,CACH;IACD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,KAAK,CACZ,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC1G;IACD,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,EAAE,EAAE,CAAC;SACF,MAAM,CAAC;QACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,OAAO,EAAE,CAAC;aACP,IAAI,CAAC;YACJ,WAAW;YACX,sBAAsB;YACtB,cAAc;YACd,mBAAmB;YACnB,WAAW;YACX,cAAc;YACd,QAAQ;YACR,gBAAgB;YAChB,SAAS;SACV,CAAC;aACD,QAAQ,EAAE;QACb,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;QACf,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;QACtD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC3B,CAAC;SACD,QAAQ,EAAE;IACb,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACtB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC3F,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;IACnE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACrC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC3B,CAA4B,CAAC;AAE9B,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEzF,kGAAkG;AAClG,kGAAkG;AAClG,+BAA+B;AAC/B,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAqB,EACrB,IAAY,EACZ,OAA8D,EAC9D,EAAW;IAEX,KAAK,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,CAAC;AACX,CAAC;AAED,qGAAqG;AACrG,iGAAiG;AACjG,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAAqB,EACrB,IAAY,EACZ,OAA+C,EAC/C,EAAW;IAEX,IAAI,MAAyC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE;YAC5B,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,UAAU,kBAAkB,CAAC,IAAI,CAAC,UAAU,IAAI,eAAe,CAAC;gBACpE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3C,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAClD,CAAC,CAAC,QAAQ,EAAE,EAAE;YACf,SAAS,EAAE,gBAAgB;SAC5B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,eAAe;YAAE,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,8BAA8B,CAAC,CAAC;QACxG,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtE,uFAAuF;QACvF,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,8CAA8C,CAAC,CAAC;QACtG,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IAClD,iGAAiG;IACjG,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,KAAK,KAAK,WAAW;QACvD,OAAO,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,iCAAiC,CAAC,CAAC;IACvE,sEAAsE;IACtE,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG;QACvB,OAAO,UAAU,CACf,GAAG,KAAK,EAAE,KAAK,IAAI,0CAA0C,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACjI,CAAC;IACJ,MAAM,IAAI,cAAc,CAAC,KAAK,EAAE,KAAK,IAAI,oBAAoB,MAAM,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;AACtG,CAAC;AAED,8FAA8F;AAC9F,0FAA0F;AAC1F,KAAK,UAAU,SAAS,CAAC,KAAqB,EAAE,IAAY,EAAE,EAAW,EAAE,GAAW;IACpF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,cAAc,CAAC,IAAI,IAAI,0CAA0C,CAAC,CAAC;IACnG,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"brief-cli.js","sourceRoot":"","sources":["../src/brief-cli.ts"],"names":[],"mappings":"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"}
|