@detergent-software/conductor 2.2.0-dev.2 → 3.0.0-dev.1

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +46 -24
  3. package/build/checkout-sync.js +4 -21
  4. package/build/checkout-sync.js.map +1 -1
  5. package/build/claude.js +6 -2
  6. package/build/claude.js.map +1 -1
  7. package/build/cli.js +32 -25
  8. package/build/cli.js.map +1 -1
  9. package/build/console.js +13 -29
  10. package/build/console.js.map +1 -1
  11. package/build/daemon.js +42 -0
  12. package/build/daemon.js.map +1 -1
  13. package/build/follow-ups.js +0 -3
  14. package/build/follow-ups.js.map +1 -1
  15. package/build/help.js +9 -21
  16. package/build/help.js.map +1 -1
  17. package/build/inbox.js +8 -0
  18. package/build/inbox.js.map +1 -1
  19. package/build/manager.js +74 -3
  20. package/build/manager.js.map +1 -1
  21. package/build/paths.js +2 -0
  22. package/build/paths.js.map +1 -1
  23. package/build/plugin.js +136 -0
  24. package/build/plugin.js.map +1 -0
  25. package/build/profile.js +12 -5
  26. package/build/profile.js.map +1 -1
  27. package/build/project-check.js +21 -9
  28. package/build/project-check.js.map +1 -1
  29. package/build/queue.js +21 -0
  30. package/build/queue.js.map +1 -1
  31. package/build/server.js +11 -0
  32. package/build/server.js.map +1 -1
  33. package/build/upgrade.js +9 -2
  34. package/build/upgrade.js.map +1 -1
  35. package/build/watchers/boards-queue.js +43 -2
  36. package/build/watchers/boards-queue.js.map +1 -1
  37. package/build/watchers/boards-writes.js +6 -2
  38. package/build/watchers/boards-writes.js.map +1 -1
  39. package/build/watchers/boards.js +15 -6
  40. package/build/watchers/boards.js.map +1 -1
  41. package/build/watchers/issues-queue.js +47 -5
  42. package/build/watchers/issues-queue.js.map +1 -1
  43. package/build/watchers/issues-writes.js +21 -2
  44. package/build/watchers/issues-writes.js.map +1 -1
  45. package/build/watchers/issues.js +6 -5
  46. package/build/watchers/issues.js.map +1 -1
  47. package/build/watchers/linear-queue.js +6 -20
  48. package/build/watchers/linear-queue.js.map +1 -1
  49. package/build/watchers/release-wait.js +30 -0
  50. package/build/watchers/release-wait.js.map +1 -0
  51. package/package.json +8 -8
  52. package/plugin/.claude-plugin/plugin.json +7 -0
  53. package/plugin/README.md +18 -0
  54. package/{mod → plugin}/hooks/model.ts +22 -4
  55. package/{mod → plugin}/hooks/register.tsx +63 -17
  56. package/plugin/skills/conductor-console/SKILL.md +94 -0
  57. package/plugin/skills/create-verification-skill/LICENSE +21 -0
  58. package/plugin/skills/create-verification-skill/README.md +9 -0
  59. package/plugin/skills/create-verification-skill/SKILL.md +44 -0
  60. package/plugin/skills/create-verification-skill/manifest.json +27 -0
  61. package/plugin/skills/create-verification-skill/references/feature-map-example/README.md +47 -0
  62. package/plugin/skills/create-verification-skill/references/feature-map-example/create-note.md +39 -0
  63. package/plugin/skills/create-verification-skill/references/feature-map-example/search.md +45 -0
  64. package/plugin/skills/maintain-verification-skill/LICENSE +21 -0
  65. package/plugin/skills/maintain-verification-skill/README.md +9 -0
  66. package/plugin/skills/maintain-verification-skill/SKILL.md +39 -0
  67. package/plugin/skills/maintain-verification-skill/manifest.json +23 -0
  68. package/plugin/skills/work-item/SKILL.md +253 -0
  69. package/plugin/skills/work-item/trackers/ado-boards.md +23 -0
  70. package/plugin/skills/work-item/trackers/github-issues.md +23 -0
  71. package/plugin/skills/work-item/trackers/linear.md +21 -0
  72. package/protocol/PROTOCOL.md +1 -1
  73. package/build/mod.js +0 -53
  74. package/build/mod.js.map +0 -1
  75. package/mod/.claude-plugin/marketplace.json +0 -6
  76. package/mod/.claude-plugin/plugin.json +0 -7
  77. package/mod/README.md +0 -19
  78. /package/{mod → plugin}/hooks/hooks.json +0 -0
  79. /package/{mod → plugin}/types/index.d.ts +0 -0
@@ -0,0 +1,23 @@
1
+ # ADO Boards
2
+
3
+ For a profile with `"tracker": { "kind": "ado-boards", "key": "<KEY>", "query": "…" }`. Items are Azure DevOps work items, keyed `<KEY>-<work item id>` (`CAD-1234` is work item 1234), because ADO's ids are numbers alone. In `Approved via:`, this tracker's name is `Azure DevOps Boards`.
4
+
5
+ Every read and write goes through `conduct` (SKILL.md), as the identity the conductor uses for Boards (the project's ADO token, else the `az login`): never `az boards` or a helper. This file is the vocabulary.
6
+
7
+ **States** go by the state's type. These are the built-in names for the Scrum, Agile, Basic and CMMI processes. The profile's `tracker.states` adds names or overrides them (`{ "Blocked": "started" }`), and the conductor reads them the same way. A state neither knows is neither open nor closed: ask Jason before moving an item out of it. `conduct brief` gives the state and its type.
8
+
9
+ | Phase table says | Type | Built-in states (Scrum process first) |
10
+ |---|---|---|
11
+ | not started | `backlog`, `unstarted` | New, Approved, To Do, Proposed (`backlog` only through `tracker.states`) |
12
+ | in progress | `started` | Committed, Active, In Progress, Doing, Resolved |
13
+ | in review | `started` | none of its own: the item stays in progress (Committed on Scrum), and the linked PR shows the review. A profile that adds a review state in `tracker.states` names it there. |
14
+ | done | `completed` | Done, Closed |
15
+ | canceled | `canceled` | Removed |
16
+
17
+ The Started, PR opened and Landed notes move the item: Started to Committed and assigned, PR opened links the PR (an `ArtifactLink` for an ADO PR, a `Hyperlink` for a GitHub one), Landed to Done, by the profile's `tracker.transitions` over those defaults. A move ADO refuses (one its process doesn't allow) is a warning on `conduct note`'s stderr; the note stands.
18
+
19
+ **Areas** are Area Paths below the profile's `tracker.areaRoot`, written with `/` (`Web`, `Api/Auth`). `conduct brief` gives the item's, and `conduct file` refuses any other and lists them.
20
+
21
+ **Links.** A Predecessor is a blocker, a Successor an item it blocks, and Related is related; `conduct brief` lists each with its state.
22
+
23
+ **Approvals.** The conductor reads an `approve` (or `approved`) or `revise: …` discussion comment by an approver (the conductor's identity, or one the profile's `approvers` names, by unique name) after the newest `<skill> · Plan` note, under the skill's name or an alias. A comment that is itself a `<skill> · ` note doesn't count, and one typed in the web UI counts as its text. `conduct brief KEY-n --fresh` gives the answer's words and `createdAt` (`approval`); quote it: `Approved via: Azure DevOps Boards (Jason's comment "<text>", <createdAt>)`.
@@ -0,0 +1,23 @@
1
+ # GitHub Issues
2
+
3
+ For a profile with `"tracker": { "kind": "github-issues", "key": "<KEY>" }`. Items are the issues of the code host's repo (or `tracker.owner` / `tracker.repo`), keyed `<KEY>-<issue number>` (`PAR-12` is issue #12). In `Approved via:`, this tracker's name is `GitHub Issues`.
4
+
5
+ Every read and write goes through `conduct` (SKILL.md), as the project's gh account: never `gh issue` or the GitHub MCP tools. This file is the vocabulary.
6
+
7
+ **States.** An issue is open or closed; the open phases are labels. `conduct brief` gives the state the conductor reads:
8
+
9
+ | Phase table says | Issue |
10
+ |---|---|
11
+ | not started | open, with the queue label (`tracker.queueLabel`) and no phase label |
12
+ | in progress | open, labelled `in-progress` |
13
+ | in review | open, labelled `in-review` |
14
+ | done | closed as completed |
15
+ | canceled | closed as not planned, or as a duplicate |
16
+
17
+ The Started, PR opened and Landed notes move the issue: Started labels it `in-progress` and assigns the gh account, PR opened swaps that for `in-review` and links the PR (a GitHub PR by the `Refs <owner>/<repo>#<n>` that `conduct pr create` adds to its body, any other by a comment with its URL), Landed closes it as completed and takes the phase label off. The profile's `tracker.transitions` names other labels.
18
+
19
+ **Areas** are the labels that start with the profile's `tracker.areaPrefix` (such as `area:api`): the Area is the rest (`api`). `conduct brief` gives the issue's, and `conduct file` refuses any other.
20
+
21
+ **Links.** Blockers are GitHub's issue dependencies ("blocked by"); one in another repo is `<owner>/<repo>#<n>`. GitHub has no related relation, so `conduct file` writes `Related: #n` in the new issue's body.
22
+
23
+ **Approvals.** The conductor reads an `approve` or `revise: …` comment by an approver (the project's gh account, or a login the profile's `approvers` names) after the newest `<skill> · Plan` note, under the skill's name or an alias. `conduct brief KEY-n --fresh` gives the answer's words and `createdAt` (`approval`); quote it: `Approved via: GitHub Issues (Jason's comment "<text>", <createdAt>)`.
@@ -0,0 +1,21 @@
1
+ # Linear
2
+
3
+ For a profile with `"tracker": { "kind": "linear", "team": "<KEY>" }`. Items are Linear issues (`KEY-n`) of that team. In `Approved via:`, this tracker's name is `Linear`.
4
+
5
+ Every read and write goes through `conduct` (SKILL.md), as the Linear key the conductor uses: never the Linear MCP tools. This file is the vocabulary.
6
+
7
+ **Statuses** go by Linear's status type, which every team has, whatever it names its statuses. `conduct brief` gives both (`status.name`, `status.type`):
8
+
9
+ | Phase table says | Status type | Usual name |
10
+ |---|---|---|
11
+ | not started | `backlog`, `unstarted`, `triage` | Backlog, Todo, Triage |
12
+ | in progress | `started` | In Progress |
13
+ | in review | `started` | In Review (the team's second started status) |
14
+ | done | `completed` | Done |
15
+ | canceled | `canceled`, `duplicate` | Canceled, Duplicate |
16
+
17
+ The Started, PR opened and Landed notes move the item to in progress (and assign it to the key's owner), to in review (with the PR attached), and to done, by the profile's `tracker.transitions` over those defaults. A move Linear refuses is a warning on `conduct note`'s stderr; the note stands.
18
+
19
+ **Areas** are labels of the profile's `tracker.areaLabelGroup` group (ATK's is `Area`, with labels such as `apps/conductor` or `skills/verify-atk`). An issue takes one; the group is single-select, so a change to several sub-Areas takes their parent (`skills`, not `skills/a` and `skills/b`). `conduct brief` gives the item's, and `conduct file` refuses any other and lists them.
20
+
21
+ **Approvals.** The conductor reads an `approve` or `revise: …` comment by an approver (the account behind the conductor's Linear key, or one the profile's `approvers` names) after the newest `<skill> · Plan` note, under the skill's name or an alias. When Claude writes with Jason's key, his comments and Claude's notes carry the same author, so the `<skill> · ` heading is what tells them apart: a note is never an answer. `conduct brief KEY-n --fresh` gives the answer's words and `createdAt` (`approval`). An auto-approve rule's comment comes the same way, also as the key's owner, with words that start `approve: auto-approved by the conductor:`; record it as `Approved via: auto (…)`, not as Jason's comment. A read can lag a minute behind a write.
@@ -18,7 +18,7 @@ A note is a tracker comment whose first non-blank line is its heading:
18
18
  ## <skill> · <Phase>[ · <kind>: <one line>]
19
19
  ```
20
20
 
21
- - `<skill>` is the profile's `skills.work`, or one of its `skills.aliases`.
21
+ - `<skill>` is the profile's `skills.work`, or one of its `skills.aliases`, without a `conductor:` prefix: the conductor plugin's `conductor:work-item` heads its notes `work-item · `.
22
22
  - `<Phase>` is one of the phases below.
23
23
  - A Handoff must carry a kind and a one-line text. A few other phases may carry one of their own kinds. All other phases carry none.
24
24
  - The heading is what tells a worker's note from a person's comment, since both can carry the same author.
package/build/mod.js DELETED
@@ -1,53 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import { join, sep } from 'node:path';
3
- import { ConductorError } from "./errors.js";
4
- import { outputOf } from "./run.js";
5
- // The plugin's name and its marketplace's, both from mod/.claude-plugin.
6
- export const MOD_NAME = 'conductor';
7
- const MARKETPLACE = 'conductor';
8
- // `conduct install-mod`: installs the conductor mod (a Claude Code plugin) for every session of this
9
- // user, from the mod folder of this package as a folder marketplace. Claude Code reads a folder
10
- // marketplace's plugin from the folder itself, so `conduct upgrade` replaces the mod with the daemon,
11
- // and open sessions pick it up with /reload-plugins.
12
- export async function installMod(dir, deps) {
13
- if (!existsSync(join(dir, '.claude-plugin', 'marketplace.json'))) {
14
- throw new ConductorError(`${dir} holds no conductor mod`, [
15
- 'reinstall the package: npm i -g @detergent-software/conductor',
16
- ]);
17
- }
18
- // Every session would read the mod from a folder that goes away with its worktree.
19
- if (dir.includes(`${sep}.claude${sep}worktrees${sep}`)) {
20
- throw new ConductorError(`${dir} is in a worktree, which goes away`, [
21
- 'run install-mod from the main checkout or the npm package',
22
- 'to try a worktree build: claude --plugin-dir apps/conductor/mod',
23
- ]);
24
- }
25
- // A marketplace of that name added from another folder (a linked build, an older install) would
26
- // keep its path, since install adds a marketplace only when none of the name is there. None is fine.
27
- await deps.claude(['plugin', 'marketplace', 'remove', MARKETPLACE]);
28
- const result = await deps.claude(['plugin', 'install', MOD_NAME, '--marketplace', dir, '--scope', 'user']);
29
- if (result.code !== 0)
30
- throw new ConductorError('could not install the conductor mod', [outputOf(result, 1000)]);
31
- deps.out(`installed the conductor mod from ${dir}`);
32
- deps.out('open sessions load it with /reload-plugins; the console session is the one started with CONDUCTOR_CONSOLE=1');
33
- }
34
- // `conduct install-mod --remove`: uninstalls the mod and forgets its marketplace, saying what each
35
- // step did.
36
- export async function removeMod(deps) {
37
- const uninstalled = await deps.claude(['plugin', 'uninstall', `${MOD_NAME}@${MARKETPLACE}`, '--scope', 'user']);
38
- const forgot = await deps.claude(['plugin', 'marketplace', 'remove', MARKETPLACE]);
39
- if (uninstalled.code !== 0 && forgot.code !== 0) {
40
- throw new ConductorError('could not remove the conductor mod', [outputOf(uninstalled, 500), outputOf(forgot, 500)]);
41
- }
42
- if (uninstalled.code !== 0) {
43
- deps.out(`removed the conductor marketplace; the plugin uninstall said: ${outputOf(uninstalled, 500)}`);
44
- }
45
- else if (forgot.code !== 0) {
46
- deps.out(`uninstalled the conductor mod; removing its marketplace said: ${outputOf(forgot, 500)}`);
47
- }
48
- else {
49
- deps.out('removed the conductor mod');
50
- }
51
- deps.out('open sessions drop it with /reload-plugins');
52
- }
53
- //# sourceMappingURL=mod.js.map
package/build/mod.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
@@ -1,6 +0,0 @@
1
- {
2
- "name": "conductor",
3
- "description": "The conductor mod, shipped inside @detergent-software/conductor and installed by `conduct install-mod`.",
4
- "owner": { "name": "Emergent Software" },
5
- "plugins": [{ "name": "conductor", "source": "./" }]
6
- }
@@ -1,7 +0,0 @@
1
- {
2
- "name": "conductor",
3
- "version": "1.0.0",
4
- "description": "The conductor console's plumbing: the inbox band, the fleet pane, zero-token commands, Remote Control pushes and escalation wake-ups.",
5
- "author": { "name": "Emergent Software" },
6
- "types": "./types/index.d.ts"
7
- }
package/mod/README.md DELETED
@@ -1,19 +0,0 @@
1
- # Conductor mod
2
-
3
- A Claude Code plugin (a hooks module) that does the conductor console's plumbing in code, so it costs no tokens. Only the console (`CONDUCTOR_CONSOLE=1`) gets anything from it: the inbox band, the fleet pane, `/conductor` `/inbox` `/approve` `/revise` `/attach` `/notify` `/pause` `/unpause` `/focus-project`, toasts, Remote Control pushes (and the one warning when Remote Control is off), the one model wake-up for an escalation, a nudge to load `/conductor-console` in a console started without it, and a warm prompt cache while the console idles (a ping every 55 minutes, or a `/clear` past 150k or a night of pings). What it shows and does is in the conductor README's *Mod* section (`apps/conductor/README.md`).
4
-
5
- Install it with the daemon's CLI, which ships this folder:
6
-
7
- ```text
8
- conduct install-mod
9
- ```
10
-
11
- | File | Holds |
12
- |---|---|
13
- | `hooks/register.tsx` | the hooks: session start, commands, the band, the pane, the event stream; only its top-level functions take `$` |
14
- | `hooks/model.ts` | the logic without the engine: parsing the daemon's answers, what the band and pane show, what each event asks for |
15
- | `types/index.d.ts` | the `$.state` contract (`conductor.snapshot`, `confirming`, `expanded`) |
16
- | `tests/conductor.test.tsx` | `claude plugin test`: the hooks against the engine, the daemon faked beneath them |
17
- | `tests/model.spec.ts` | vitest (`pnpm -C apps/conductor test`, in CI): `model.ts` |
18
-
19
- `pnpm -C apps/conductor typecheck` type-checks this folder in CI against Claude Code's plugin API, kept in `apps/conductor/mod-types/` (the conductor README's *Mod* section says how to refresh it).
File without changes
File without changes