@clipboard-health/groundcrew 3.1.3 → 3.1.5

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/README.md CHANGED
@@ -71,7 +71,7 @@ Installs the `crew` binary. `@clipboard-health/clearance` is pulled in transitiv
71
71
 
72
72
  Or drop `crew.config.ts` at the root of any repo you run `crew` from — `crew` discovers it via cosmiconfig project-walk. Any of `crew.config.{ts,mjs,js,json}`, `.crewrc{,.json,.ts}`, `.config/crew.config.{ts,json}`, or `.config/crewrc{,.json}` work.
73
73
 
74
- Set `linear.projectSlug` (paste the trailing slug of your Linear project URL, e.g. `ai-strategy-5152195762f3`), `workspace.projectDir`, and `workspace.knownRepositories`. Defaults cover everything else.
74
+ Set `linear.projects[].projectSlug` (paste the trailing slug of your Linear project URL, e.g. `ai-strategy-5152195762f3`), `workspace.projectDir`, and `workspace.knownRepositories`. Defaults cover everything else. To watch multiple projects from one `crew` instance, add more entries to `linear.projects`; they all share the same `orchestrator.maximumInProgress` budget.
75
75
 
76
76
  Then clone each repo before the first `crew run` — groundcrew creates per-ticket worktrees from these clones, it does not auto-clone:
77
77
 
@@ -163,11 +163,11 @@ Watch `${XDG_CACHE_HOME:-$HOME/.cache}/clearance/clearance.log` for `DENY` lines
163
163
 
164
164
  Three keys are required; everything else has a default.
165
165
 
166
- | Key | What |
167
- | ----------------------------- | -------------------------------------------------------------------------- |
168
- | `linear.projectSlug` | Trailing slug of the Linear project URL (e.g. `ai-strategy-5152195762f3`). |
169
- | `workspace.projectDir` | Parent dir for cloned repos and sibling ticket worktrees. |
170
- | `workspace.knownRepositories` | Repos searched for in ticket descriptions to infer where work belongs. |
166
+ | Key | What |
167
+ | ------------------------------- | --------------------------------------------------------------------------------------------------------- |
168
+ | `linear.projects[].projectSlug` | Trailing slug of each Linear project URL to watch (e.g. `ai-strategy-5152195762f3`). One or more entries. |
169
+ | `workspace.projectDir` | Parent dir for cloned repos and sibling ticket worktrees. |
170
+ | `workspace.knownRepositories` | Repos searched for in ticket descriptions to infer where work belongs. |
171
171
 
172
172
  `crew` resolves config as: `GROUNDCREW_CONFIG` if set → project-walk from cwd (cosmiconfig: `crew.config.{ts,mjs,js,json}`, `.crewrc{,.json,.ts}`, `.config/crew.config.{ts,json}`, `.config/crewrc{,.json}`) → `${XDG_CONFIG_HOME:-$HOME/.config}/groundcrew/crew.config.ts` (also accepts legacy `config.ts` for one release). The branch prefix (`<prefix>-<TICKET>`) is derived from `os.userInfo().username` — not configurable.
173
173
 
@@ -197,16 +197,17 @@ This keeps package defaults portable while letting your private config reference
197
197
 
198
198
  | Key | Default | What it does |
199
199
  | --------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
200
- | `linear.projectSlug` | **required** | Linear project URL slug (e.g. `ai-strategy-5152195762f3`). The trailing 12-char hex `slugId` is what's matched against Linear's API; the leading name keeps `crew.config.ts` self-documenting and the lookup survives project renames. |
201
- | `linear.statuses.todo` | `"Todo"` | Status name picked up for new work. |
202
- | `linear.statuses.inProgress` | `"In Progress"` | Status set after a workspace is provisioned; counts toward `maximumInProgress`. |
203
- | `linear.statuses.done` | `"Done"` | Status that triggers worktree cleanup. |
204
- | `linear.statuses.terminal` | `["Done"]` | Additional status names treated as terminal for cleanup, board remaining counts, and blocker checks. The `done` status is always included. |
200
+ | `linear.projects` | **required** | Non-empty array of Linear projects to watch. One `crew` instance dispatches across every entry under a shared `maximumInProgress` budget. |
201
+ | `linear.projects[].projectSlug` | **required** | Linear project URL slug (e.g. `ai-strategy-5152195762f3`). The trailing 12-char hex `slugId` is what's matched against Linear's API; the leading name keeps `crew.config.ts` self-documenting and the lookup survives project renames. |
202
+ | `linear.projects[].statuses.todo` | `"Todo"` | Status name picked up for new work in this project. Per-project so multi-team setups with divergent state names can coexist. |
203
+ | `linear.projects[].statuses.inProgress` | `"In Progress"` | Status set after a workspace is provisioned; counts toward the shared `maximumInProgress`. |
204
+ | `linear.projects[].statuses.done` | `"Done"` | Status that triggers worktree cleanup for this project. |
205
+ | `linear.projects[].statuses.terminal` | `["Done"]` | Additional status names treated as terminal for cleanup and blocker checks. The project's `done` status is always included. |
205
206
  | `git.remote` | `"origin"` | Remote used for `fetch` and as the worktree base ref. |
206
207
  | `git.defaultBranch` | `"main"` | Branch fetched from `git.remote` and used as the worktree base. |
207
208
  | `workspace.projectDir` | **required** | Parent dir for cloned repos and sibling ticket worktrees. |
208
209
  | `workspace.knownRepositories` | **required** | Repos searched for in ticket descriptions to infer where work belongs. A ticket labeled for groundcrew (`agent-*`) fails fast when no known repo appears; unlabeled tickets are ignored. |
209
- | `orchestrator.maximumInProgress` | `4` | Cap on tickets in `linear.statuses.inProgress` at once. |
210
+ | `orchestrator.maximumInProgress` | `4` | Cap on in-progress tickets at once, shared across every project in `linear.projects`. |
210
211
  | `orchestrator.pollIntervalMilliseconds` | `120_000` | Poll interval in `--watch` mode. |
211
212
  | `orchestrator.sessionLimitPercentage` | `85` | Number in `(0, 100]`. A model whose codexbar session window exceeds this percentage is skipped that tick. |
212
213
  | `models.default` | `"claude"` | Tiebreak for `agent-any` resolution and fallback for explicit but unknown `agent-*` labels. Also used by `crew run --ticket <TICKET>` for unlabeled tickets. `crew run` without `--ticket` ignores unlabeled tickets and does not apply this default. Must exist in `models.definitions`. |
@@ -443,7 +444,7 @@ When a wrapped agent command fails (e.g. `safehouse-clearance` not found, `npm i
443
444
  <details>
444
445
  <summary>Status names matter</summary>
445
446
 
446
- If your team uses `Started` instead of `In Progress`, set `linear.statuses.inProgress = "Started"`.
447
+ If your team uses `Started` instead of `In Progress`, set `linear.projects[].statuses.inProgress = "Started"` on that project's entry. Status overrides are per-project so divergent team workflows coexist.
447
448
 
448
449
  </details>
449
450
 
@@ -462,9 +463,9 @@ Groundcrew sets a ticket to `inProgress` when it provisions a workspace and neve
462
463
  </details>
463
464
 
464
465
  <details>
465
- <summary>Project must be on a single Linear team in practice</summary>
466
+ <summary>Cross-team projects need a consistent `inProgress` name per project</summary>
466
467
 
467
- Cross-team projects work — the orchestrator caches the in-progress state ID per team — but every team in the project must use the same status name for `linear.statuses.inProgress`.
468
+ Cross-team projects work — the orchestrator caches the in-progress state ID per `(team, statusName)` pair — but every team in a given project must use the same status name for that project's `statuses.inProgress`. If you watch two projects that share a Linear team but configure different `inProgress` names, each project's lookup is independent.
468
469
 
469
470
  </details>
470
471
 
@@ -65,6 +65,7 @@ registry.npmjs.org
65
65
  www.npmjs.com
66
66
 
67
67
  # Developer tooling
68
+ app.terraform.io
68
69
  buf.build
69
70
  cdn.playwright.dev
70
71
  formulae.brew.sh
@@ -3,16 +3,30 @@ import type { Config } from "./src/lib/config.js";
3
3
 
4
4
  export default {
5
5
  linear: {
6
- // Project URL slug to scope polling. Copy the trailing segment of
7
- // your Linear project URL
8
- // https://linear.app/<workspace>/project/<projectSlug>
9
- // — verbatim, for example "ai-strategy-5152195762f3". The 12-char hex
10
- // tail is the canonical ID groundcrew uses, so the orchestrator stays
11
- // resilient across project renames and across same-name projects in
12
- // different teams. The leading name segment keeps the file
13
- // self-documenting at a glance.
14
- projectSlug: "your-project-name-0123456789ab",
15
- // statuses: { todo: "Todo", inProgress: "In Progress", done: "Done", terminal: ["Done"] },
6
+ // One or more Linear projects to watch. A single `crew` process
7
+ // dispatches across all configured projects under a shared
8
+ // `orchestrator.maximumInProgress` budget.
9
+ //
10
+ // Each entry's `projectSlug` is the trailing segment of your Linear
11
+ // project URL copy it verbatim, e.g. "ai-strategy-5152195762f3"
12
+ // from "https://linear.app/<workspace>/project/ai-strategy-5152195762f3".
13
+ // The 12-char hex tail is the canonical ID groundcrew uses, so the
14
+ // orchestrator stays resilient across project renames and across
15
+ // same-name projects in different teams. The leading name segment
16
+ // keeps the file self-documenting at a glance.
17
+ //
18
+ // `statuses` is per-project so multi-team setups with divergent
19
+ // workflow state names (e.g. "Todo" vs "To Do", "Shipped" vs
20
+ // "Done") can coexist. Each field falls back to its default when
21
+ // omitted: { todo: "Todo", inProgress: "In Progress",
22
+ // done: "Done", terminal: ["Done"] }.
23
+ projects: [
24
+ { projectSlug: "your-project-name-0123456789ab" },
25
+ // {
26
+ // projectSlug: "platform-aaaaaaaaaaaa",
27
+ // statuses: { inProgress: "Doing", done: "Released", terminal: ["Released", "Won't Do"] },
28
+ // },
29
+ ],
16
30
  },
17
31
  workspace: {
18
32
  // Parent directory under which groundcrew clones repositories and
@@ -29,6 +43,7 @@ export default {
29
43
  // git: { remote: "origin", defaultBranch: "main" },
30
44
  //
31
45
  // orchestrator: {
46
+ // // Shared across all watched projects in linear.projects.
32
47
  // maximumInProgress: 4,
33
48
  // pollIntervalMilliseconds: 120_000,
34
49
  // sessionLimitPercentage: 85,
@@ -1 +1 @@
1
- {"version":3,"file":"cleaner.d.ts","sourceRoot":"","sources":["../../src/commands/cleaner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,qBAAqB,CAAC;AAGpE,UAAU,WAAW;IACnB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,UAAU,EAAE;QAClB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAsDxD"}
1
+ {"version":3,"file":"cleaner.d.ts","sourceRoot":"","sources":["../../src/commands/cleaner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,UAAU,EAA4B,MAAM,uBAAuB,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,qBAAqB,CAAC;AAGpE,UAAU,WAAW;IACnB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,UAAU,EAAE;QAClB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAsDxD"}
@@ -3,7 +3,7 @@
3
3
  * tickets that have reached a terminal status. One per `orchestrate()`
4
4
  * invocation; stateless across iterations. Mirrors `Dispatcher`.
5
5
  */
6
- import { isTerminalStatus } from "../lib/boardSource.js";
6
+ import { isTerminalStatusForIssue } from "../lib/boardSource.js";
7
7
  import { recordCleanedUpRuns } from "../lib/runStateCleanup.js";
8
8
  import { log, logEvent } from "../lib/util.js";
9
9
  import { worktrees } from "../lib/worktrees.js";
@@ -12,10 +12,10 @@ export function createCleaner(deps) {
12
12
  const { config } = deps;
13
13
  async function runOnce(arguments_) {
14
14
  const { state, worktreeEntries, dryRun, signal } = arguments_;
15
- // Only act on tickets in this project — if the dir name happens to look
16
- // like a Linear ticket from another project, leave it alone.
15
+ // Only act on tickets in configured projects — if the dir name happens to
16
+ // look like a Linear ticket from another project, leave it alone.
17
17
  const terminalTickets = new Set(state.issues
18
- .filter((issue) => isTerminalStatus(issue.status, config))
18
+ .filter((issue) => isTerminalStatusForIssue(issue, config))
19
19
  .map((issue) => issue.id));
20
20
  if (terminalTickets.size === 0) {
21
21
  return;
@@ -23,6 +23,12 @@ export interface Dispatcher {
23
23
  usage: (signal?: AbortSignal) => Promise<UsageByModel>;
24
24
  dryRun: boolean;
25
25
  signal?: AbortSignal;
26
+ /**
27
+ * Appended to the dispatcher's idle-branch log lines so the watch loop
28
+ * can fold its `next poll in Xs` heartbeat into the same line instead of
29
+ * printing a second line per tick.
30
+ */
31
+ idleSuffix?: string;
26
32
  }): Promise<void>;
27
33
  }
28
34
  export declare function createDispatcher(deps: DispatcherDeps): Dispatcher;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/commands/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,KAAK,UAAU,EAA2C,MAAM,uBAAuB,CAAC;AACjG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,UAAU,cAAc;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,UAAU,EAAE;QAClB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,+FAA+F;QAC/F,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAuLjE"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/commands/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWzD,UAAU,cAAc;IACtB,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,UAAU,EAAE;QAClB,KAAK,EAAE,UAAU,CAAC;QAClB,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;QAC1C,+FAA+F;QAC/F,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB;;;;WAIG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAwLjE"}
@@ -6,7 +6,7 @@
6
6
  * Pure verdict logic lives in `eligibility.ts`; this module is responsible
7
7
  * for telemetry, Linear writes, and side-effecting setupWorkspace calls.
8
8
  */
9
- import { isGroundcrewIssue } from "../lib/boardSource.js";
9
+ import { isGroundcrewIssue, projectFor, } from "../lib/boardSource.js";
10
10
  import { createLinearIssueStatusUpdater } from "../lib/linearIssueStatus.js";
11
11
  import { errorMessage, log, logEvent } from "../lib/util.js";
12
12
  import { workspaces } from "../lib/workspaces.js";
@@ -85,19 +85,19 @@ export function createDispatcher(deps) {
85
85
  }
86
86
  }
87
87
  async function runOnce(arguments_) {
88
- const { state, worktreeEntries, usage, dryRun, signal } = arguments_;
88
+ const { state, worktreeEntries, usage, dryRun, signal, idleSuffix = "" } = arguments_;
89
89
  issueStatusUpdater.resetMissingInProgressCache();
90
- const activeCount = state.issues.filter((issue) => issue.status === config.linear.statuses.inProgress).length;
90
+ const activeCount = state.issues.filter((issue) => issue.status === projectFor(issue, config).statuses.inProgress).length;
91
91
  const slots = config.orchestrator.maximumInProgress - activeCount;
92
92
  // Narrow Todo to tickets that opted in via an `agent-*` label.
93
93
  // Unlabeled tickets are not groundcrew's concern even when in Todo.
94
- const todo = state.issues.filter((issue) => issue.status === config.linear.statuses.todo && isGroundcrewIssue(issue));
94
+ const todo = state.issues.filter((issue) => issue.status === projectFor(issue, config).statuses.todo && isGroundcrewIssue(issue));
95
95
  if (slots <= 0) {
96
- log(`At capacity (${activeCount}/${config.orchestrator.maximumInProgress}), no new work to start`);
96
+ log(`At capacity (${activeCount}/${config.orchestrator.maximumInProgress}), no new work to start${idleSuffix}`);
97
97
  return;
98
98
  }
99
99
  if (todo.length === 0) {
100
- log(`No ${config.linear.statuses.todo} tickets to pick up`);
100
+ log(`No Todo tickets to pick up${idleSuffix}`);
101
101
  return;
102
102
  }
103
103
  // Run the blocker pre-pass first so an all-blocked board short-circuits
@@ -107,7 +107,7 @@ export function createDispatcher(deps) {
107
107
  logSkip(skip);
108
108
  }
109
109
  if (unblocked.length === 0) {
110
- log(`No eligible ${config.linear.statuses.todo} tickets after blocker filtering`);
110
+ log(`No eligible Todo tickets after blocker filtering${idleSuffix}`);
111
111
  return;
112
112
  }
113
113
  // usage() is an HTTP call; workspaces.probe shells tmux/cmux. Kick off
@@ -146,7 +146,7 @@ export function createDispatcher(deps) {
146
146
  logSkip(skip);
147
147
  }
148
148
  if (starts.length === 0) {
149
- log(`No eligible ${config.linear.statuses.todo} tickets after eligibility filtering`);
149
+ log(`No eligible Todo tickets after eligibility filtering${idleSuffix}`);
150
150
  return;
151
151
  }
152
152
  log(`${slots} slot(s) available, starting ${starts.length} ticket(s): ${starts.map(({ issue }) => `${issue.id}(${issue.model})`).join(", ")}`);
@@ -1 +1 @@
1
- {"version":3,"file":"eligibility.d.ts","sourceRoot":"","sources":["../../src/commands/eligibility.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAgB,KAAK,eAAe,EAAoB,MAAM,uBAAuB,CAAC;AAC7F,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOzD,KAAK,UAAU,GACX,SAAS,GACT,oBAAoB,GACpB,oBAAoB,GACpB,iBAAiB,GACjB,4BAA4B,GAC5B,mBAAmB,CAAC;AAExB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,CAAC;IACvB,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,WAAW,EAAE,UAAU,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;AAE1C,MAAM,MAAM,oBAAoB,GAC5B;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB;;;;;OAKG;IACH,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;IACtC,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,oDAAoD;IACpD,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,qBAAqB;IAC7B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAqCD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,MAAM,GAAG,SAAS,CAepB;AAaD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,YAAY,GAClB,oBAAoB,EAAE,CAmCxB;AA4CD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,SAAS,eAAe,EAAE,GAC/B,qBAAqB,CAYvB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,EAAE,CAgE5E"}
1
+ {"version":3,"file":"eligibility.d.ts","sourceRoot":"","sources":["../../src/commands/eligibility.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOzD,KAAK,UAAU,GACX,SAAS,GACT,oBAAoB,GACpB,oBAAoB,GACpB,iBAAiB,GACjB,4BAA4B,GAC5B,mBAAmB,CAAC;AAExB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,eAAe,CAAC;IACvB,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,WAAW,EAAE,UAAU,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,OAAO,GAAG,YAAY,GAAG,WAAW,CAAC;AAE1C,MAAM,MAAM,oBAAoB,GAC5B;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB;;;;;OAKG;IACH,SAAS,EAAE,SAAS,eAAe,EAAE,CAAC;IACtC,eAAe,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,oDAAoD;IACpD,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,qBAAqB;IAC7B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAqCD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,YAAY,EACnB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,MAAM,GAAG,SAAS,CAepB;AAaD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,EACtB,KAAK,EAAE,YAAY,GAClB,oBAAoB,EAAE,CAmCxB;AA4CD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,SAAS,eAAe,EAAE,GAC/B,qBAAqB,CAYvB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,EAAE,CAgE5E"}
@@ -6,7 +6,7 @@
6
6
  * The Dispatcher consumes the verdict list to drive logging and side
7
7
  * effects.
8
8
  */
9
- import { isTerminalStatus } from "../lib/boardSource.js";
9
+ import { isTerminalStatusForBlocker, } from "../lib/boardSource.js";
10
10
  import { AGENT_ANY_MODEL } from "../lib/config.js";
11
11
  const PERCENT_FRACTION_DIVISOR = 100;
12
12
  const DAYS_PER_WEEK = 7;
@@ -26,7 +26,7 @@ function blockerVerdictFor(issue, config) {
26
26
  blockers,
27
27
  };
28
28
  }
29
- const unresolved = issue.blockers.filter((blocker) => blocker.status === undefined || !isTerminalStatus(blocker.status, config));
29
+ const unresolved = issue.blockers.filter((blocker) => !isTerminalStatusForBlocker(blocker, config));
30
30
  if (unresolved.length === 0) {
31
31
  return undefined;
32
32
  }
@@ -1,6 +1,8 @@
1
1
  /**
2
- * groundcrew orchestrator — polls a Linear project and spins up
3
- * workspace + git-worktree pairs for ready tickets.
2
+ * groundcrew orchestrator — polls Linear projects and spins up workspace +
3
+ * git-worktree pairs for ready tickets. Each tick fetches the board, runs
4
+ * the cleaner, and runs the dispatcher; logging from those modules is the
5
+ * orchestrator's user-facing output.
4
6
  */
5
7
  export interface OrchestratorOptions {
6
8
  watch: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4LH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAiBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC7E"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2DH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAiBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC7E"}
@@ -1,36 +1,20 @@
1
1
  /**
2
- * groundcrew orchestrator — polls a Linear project and spins up
3
- * workspace + git-worktree pairs for ready tickets.
2
+ * groundcrew orchestrator — polls Linear projects and spins up workspace +
3
+ * git-worktree pairs for ready tickets. Each tick fetches the board, runs
4
+ * the cleaner, and runs the dispatcher; logging from those modules is the
5
+ * orchestrator's user-facing output.
4
6
  */
5
- import { createBoardSource, isTerminalStatus, RepositoryResolutionError, } from "../lib/boardSource.js";
7
+ import { createBoardSource, RepositoryResolutionError, } from "../lib/boardSource.js";
6
8
  import { loadConfig } from "../lib/config.js";
7
9
  import { getUsageByModel } from "../lib/usage.js";
8
- import { clearOutput, errorMessage, getLinearClient, log, sleep, writeOutput, } from "../lib/util.js";
10
+ import { errorMessage, getLinearClient, log, sleep } from "../lib/util.js";
9
11
  import { worktrees } from "../lib/worktrees.js";
10
12
  import { createCleaner } from "./cleaner.js";
11
13
  import { createDispatcher } from "./dispatcher.js";
12
14
  const RATE_LIMIT_DELAY_MS = 60_000;
13
15
  const RETRY_BASE_DELAY_MS = 1000;
14
16
  const RETRY_MAX_ATTEMPTS = 3;
15
- const STATUS_CARD_TITLE_WIDTH = 42;
16
- const STATUS_CARD_ID_WIDTH = 8;
17
- const STATUS_CARD_LIMIT = 10;
18
- const HEADER_BAR_WIDTH = 70;
19
- const SECTION_BAR_WIDTH = 50;
20
17
  const MS_PER_SECOND = 1000;
21
- const STATUS_ICON_DEFAULT = " ";
22
- function statusIconFor(status, config) {
23
- if (status === config.linear.statuses.inProgress) {
24
- return ">>";
25
- }
26
- if (status === config.linear.statuses.todo) {
27
- return "--";
28
- }
29
- if (isTerminalStatus(status, config)) {
30
- return "ok";
31
- }
32
- return STATUS_ICON_DEFAULT;
33
- }
34
18
  async function withRetry(function_, signal, maxRetries = RETRY_MAX_ATTEMPTS, baseDelayMs = RETRY_BASE_DELAY_MS) {
35
19
  for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
36
20
  try {
@@ -64,86 +48,6 @@ class WatchLoopShutdownError extends Error {
64
48
  this.name = "WatchLoopShutdownError";
65
49
  }
66
50
  }
67
- function groupByStatus(issues, knownOrder) {
68
- const groups = new Map();
69
- for (const status of knownOrder) {
70
- groups.set(status, []);
71
- }
72
- for (const issue of issues) {
73
- /* v8 ignore next @preserve -- knownOrder seeds an entry for each issue.status returned by buildStatusOrder */
74
- const group = groups.get(issue.status) ?? [];
75
- group.push(issue);
76
- groups.set(issue.status, group);
77
- }
78
- return groups;
79
- }
80
- function buildStatusOrder(state, config) {
81
- const head = [
82
- ...new Set([
83
- config.linear.statuses.inProgress,
84
- config.linear.statuses.todo,
85
- config.linear.statuses.done,
86
- ...config.linear.statuses.terminal,
87
- ]),
88
- ];
89
- const seen = new Set(head);
90
- const tail = [];
91
- for (const issue of state.issues) {
92
- if (!seen.has(issue.status)) {
93
- seen.add(issue.status);
94
- tail.push(issue.status);
95
- }
96
- }
97
- return [...head, ...tail];
98
- }
99
- function render(state, config, previous) {
100
- const order = buildStatusOrder(state, config);
101
- const grouped = groupByStatus(state.issues, order);
102
- const previousGrouped = previous ? groupByStatus(previous.issues, order) : undefined;
103
- const previousById = previous
104
- ? new Map(previous.issues.map((issue) => [issue.id, issue]))
105
- : undefined;
106
- clearOutput();
107
- writeOutput(`groundcrew — ${config.linear.projectSlug} — ${new Date(state.timestamp).toLocaleTimeString()}`);
108
- writeOutput(`Max in progress: ${config.orchestrator.maximumInProgress}`);
109
- writeOutput("=".repeat(HEADER_BAR_WIDTH));
110
- writeOutput();
111
- for (const [status, issues] of grouped) {
112
- if (issues.length === 0) {
113
- continue;
114
- }
115
- const previousCount = previousGrouped?.get(status)?.length ?? issues.length;
116
- const delta = issues.length === previousCount
117
- ? ""
118
- : ` (${issues.length > previousCount ? "+" : ""}${issues.length - previousCount})`;
119
- writeOutput(`${statusIconFor(status, config)} ${status} (${issues.length})${delta}`);
120
- writeOutput("-".repeat(SECTION_BAR_WIDTH));
121
- // Cap each status at the N most recent so a backlog of hundreds of Done
122
- // tickets doesn't clog the terminal. Sort only when truncating so smaller
123
- // statuses keep whatever order Linear returned.
124
- const visible = issues.length > STATUS_CARD_LIMIT
125
- ? issues
126
- .toSorted((a, b) => b.updatedAt.localeCompare(a.updatedAt))
127
- .slice(0, STATUS_CARD_LIMIT)
128
- : issues;
129
- for (const issue of visible) {
130
- const previousIssue = previousById?.get(issue.id);
131
- const changed = previousIssue && previousIssue.status !== issue.status
132
- ? ` [was: ${previousIssue.status}]`
133
- : "";
134
- writeOutput(` ${issue.id.padEnd(STATUS_CARD_ID_WIDTH)} ${issue.title.slice(0, STATUS_CARD_TITLE_WIDTH).padEnd(STATUS_CARD_TITLE_WIDTH)} ${issue.assignee}${changed}`);
135
- }
136
- if (issues.length > STATUS_CARD_LIMIT) {
137
- writeOutput(` … showing ${STATUS_CARD_LIMIT} most recent of ${issues.length}; ${issues.length - STATUS_CARD_LIMIT} older hidden`);
138
- }
139
- writeOutput();
140
- }
141
- const total = state.issues.length;
142
- const done = state.issues.filter((issue) => isTerminalStatus(issue.status, config)).length;
143
- /* v8 ignore next @preserve -- grouped has all known statuses pre-seeded by groupByStatus */
144
- const active = grouped.get(config.linear.statuses.inProgress)?.length ?? 0;
145
- writeOutput(`Total: ${total} | Active: ${active}/${config.orchestrator.maximumInProgress} | Done: ${done} | Remaining: ${total - done}`);
146
- }
147
51
  async function fetchUsageOrEmpty(config, signal) {
148
52
  try {
149
53
  return await getUsageByModel(config, signal);
@@ -163,10 +67,13 @@ export async function orchestrate(options) {
163
67
  await boardSource.verify();
164
68
  const cleaner = createCleaner({ config });
165
69
  const dispatcher = createDispatcher({ config, client });
166
- let previous;
70
+ // Folded into the dispatcher's idle log lines in watch mode so each idle
71
+ // tick prints one combined line instead of "<reason>" + "Next poll in Xs".
72
+ const idleSuffix = options.watch
73
+ ? `; next poll in ${config.orchestrator.pollIntervalMilliseconds / MS_PER_SECOND}s`
74
+ : undefined;
167
75
  const tick = async (signal) => {
168
76
  const state = await withRetry(async () => await boardSource.fetch(), signal);
169
- render(state, config, previous);
170
77
  const worktreeEntries = worktrees.list(config);
171
78
  const tickArguments = {
172
79
  state,
@@ -180,8 +87,8 @@ export async function orchestrate(options) {
180
87
  // Lazy: dispatcher only invokes this after its own early-returns, so
181
88
  // an idle board doesn't burn a codexbar shell-out per tick.
182
89
  usage: async (usageSignal) => await fetchUsageOrEmpty(config, usageSignal),
90
+ ...(idleSuffix === undefined ? {} : { idleSuffix }),
183
91
  });
184
- previous = state;
185
92
  };
186
93
  await (options.watch ? runWatchLoop(tick, config) : tick());
187
94
  }
@@ -249,7 +156,6 @@ async function runWatchLoop(tick, config) {
249
156
  if (shutdown.signal.aborted) {
250
157
  break;
251
158
  }
252
- log(`Next poll in ${config.orchestrator.pollIntervalMilliseconds / MS_PER_SECOND}s...`);
253
159
  // oxlint-disable-next-line no-await-in-loop -- watch loop is intentionally serial
254
160
  await sleep(config.orchestrator.pollIntervalMilliseconds, shutdown.signal);
255
161
  }
@@ -1 +1 @@
1
- {"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAenE,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAqBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CA6Gf;AAwHD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAoBf"}
1
+ {"version":3,"file":"setupWorkspace.d.ts","sourceRoot":"","sources":["../../src/commands/setupWorkspace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAenE,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAqBD,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,qBAAqB,EAC9B,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CA6Gf;AAwHD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAqBf"}
@@ -241,5 +241,6 @@ export async function setupWorkspaceCli(ticket, options = {}) {
241
241
  id: ticket.toLowerCase(),
242
242
  uuid: resolved.uuid,
243
243
  teamId: resolved.teamId,
244
+ projectSlugId: resolved.projectSlugId,
244
245
  });
245
246
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ticketDoctor.d.ts","sourceRoot":"","sources":["../../src/commands/ticketDoctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ticketDoctor.d.ts","sourceRoot":"","sources":["../../src/commands/ticketDoctor.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ import { existsSync } from "node:fs";
18
18
  import { join } from "node:path";
19
19
  import { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, resolveModelFor, resolveRepositoryFor, } from "../lib/boardSource.js";
20
20
  import { runCommandAsync } from "../lib/commandRunner.js";
21
- import { AGENT_ANY_MODEL, loadConfig } from "../lib/config.js";
21
+ import { AGENT_ANY_MODEL, findProjectBySlugId, loadConfig, } from "../lib/config.js";
22
22
  import { which } from "../lib/host.js";
23
23
  import { readRunState } from "../lib/runState.js";
24
24
  import { getUsageByModel } from "../lib/usage.js";
@@ -270,6 +270,8 @@ async function runEligibilityChecks(arguments_) {
270
270
  assignee: "",
271
271
  updatedAt: "",
272
272
  teamId: raw.teamId,
273
+ /* v8 ignore next @preserve -- probeLinear gates off-config projects upstream so raw.projectSlugId is always defined here */
274
+ projectSlugId: raw.projectSlugId ?? "",
273
275
  repository: resolvedRepository,
274
276
  model: resolvedModel,
275
277
  blockers: [...blockers],
@@ -372,8 +374,31 @@ async function probeLinear(deps, upperTicket) {
372
374
  }
373
375
  try {
374
376
  const raw = await deps.fetchRawIssue({ ticket: upperTicket });
375
- const isTerminal = deps.config.linear.statuses.terminal.includes(raw.stateName);
376
- const todoState = deps.config.linear.statuses.todo;
377
+ const project = raw.projectSlugId === undefined
378
+ ? undefined
379
+ : findProjectBySlugId(deps.config, raw.projectSlugId);
380
+ if (project === undefined) {
381
+ const configured = deps.config.linear.projects.map((entry) => entry.slugId).join(", ");
382
+ const detail = raw.projectSlugId === undefined
383
+ ? `ticket has no associated Linear project; configure linear.projects (${configured})`
384
+ : `project slugId "${raw.projectSlugId}" is not in linear.projects (configured: ${configured})`;
385
+ return {
386
+ linearStatus: { kind: "unresolvable", reason: detail },
387
+ resolution: [
388
+ { name: "Ticket exists in Linear", status: "ok", detail: `"${raw.title}"` },
389
+ {
390
+ name: "Project is configured",
391
+ status: "fail",
392
+ detail,
393
+ failureSummary: detail,
394
+ },
395
+ ],
396
+ title: raw.title,
397
+ raw,
398
+ };
399
+ }
400
+ const isTerminal = project.statuses.terminal.includes(raw.stateName);
401
+ const todoState = project.statuses.todo;
377
402
  const resolution = [
378
403
  { name: "Ticket exists in Linear", status: "ok", detail: `"${raw.title}"` },
379
404
  ];
package/dist/index.d.ts CHANGED
@@ -5,10 +5,10 @@ export { interruptWorkspace, type InterruptWorkspaceOptions, } from "./commands/
5
5
  export { orchestrate, type OrchestratorOptions } from "./commands/orchestrator.ts";
6
6
  export { resumeWorkspace, type ResumeWorkspaceOptions } from "./commands/resumeWorkspace.ts";
7
7
  export { setupWorkspace, type SetupWorkspaceOptions } from "./commands/setupWorkspace.ts";
8
- export type { Config, ModelDefinition, ResolvedConfig } from "./lib/config.ts";
9
- export { loadConfig } from "./lib/config.ts";
8
+ export type { Config, ModelDefinition, ProjectConfig, ResolvedConfig, ResolvedProjectConfig, } from "./lib/config.ts";
9
+ export { findProjectBySlugId, loadConfig, unionTerminalStatuses } from "./lib/config.ts";
10
10
  export { readRunState, recordRunState, removeRunState, runStateDirectory, runStatePath, updateRunState, type RunLifecycleState, type RunState, } from "./lib/runState.ts";
11
- export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, resolveModelFor, resolveRepositoryFor, type ModelResolution, type RawLinearIssue, type RepositoryResolution, } from "./lib/boardSource.ts";
11
+ export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, isTerminalStatusForBlocker, isTerminalStatusForIssue, projectFor, resolveModelFor, resolveRepositoryFor, UnknownProjectError, type ModelResolution, type RawLinearIssue, type RepositoryResolution, } from "./lib/boardSource.ts";
12
12
  export { getUsageByModel, type UsageByModel } from "./lib/usage.ts";
13
13
  export type { TicketCheck } from "./commands/ticketCheck.ts";
14
14
  export { ticketDoctor, type TicketDoctorDependencies, type TicketDoctorResult, type TicketDoctorVerdict, } from "./commands/ticketDoctor.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAChG,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,EACf,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAChG,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1F,YAAY,EACV,MAAM,EACN,eAAe,EACf,aAAa,EACb,cAAc,EACd,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,EACL,YAAY,EACZ,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,QAAQ,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACnB,kBAAkB,EAClB,0BAA0B,EAC1B,wBAAwB,EACxB,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ export { interruptWorkspace, } from "./commands/interruptWorkspace.js";
5
5
  export { orchestrate } from "./commands/orchestrator.js";
6
6
  export { resumeWorkspace } from "./commands/resumeWorkspace.js";
7
7
  export { setupWorkspace } from "./commands/setupWorkspace.js";
8
- export { loadConfig } from "./lib/config.js";
8
+ export { findProjectBySlugId, loadConfig, unionTerminalStatuses } from "./lib/config.js";
9
9
  export { readRunState, recordRunState, removeRunState, runStateDirectory, runStatePath, updateRunState, } from "./lib/runState.js";
10
- export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, resolveModelFor, resolveRepositoryFor, } from "./lib/boardSource.js";
10
+ export { fetchBlockersForTicket, fetchInProgressIssueCount, fetchRawLinearIssue, fetchResolvedIssue, isTerminalStatusForBlocker, isTerminalStatusForIssue, projectFor, resolveModelFor, resolveRepositoryFor, UnknownProjectError, } from "./lib/boardSource.js";
11
11
  export { getUsageByModel } from "./lib/usage.js";
12
12
  export { ticketDoctor, } from "./commands/ticketDoctor.js";