@clipboard-health/groundcrew 3.1.4 → 3.1.6

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 (62) hide show
  1. package/README.md +48 -0
  2. package/clearance-allow-hosts +1 -0
  3. package/crew.config.example.ts +20 -0
  4. package/dist/commands/dispatcher.d.ts +6 -0
  5. package/dist/commands/dispatcher.d.ts.map +1 -1
  6. package/dist/commands/dispatcher.js +17 -5
  7. package/dist/commands/orchestrator.d.ts.map +1 -1
  8. package/dist/commands/orchestrator.js +15 -1
  9. package/dist/commands/ticketDoctor.d.ts +12 -0
  10. package/dist/commands/ticketDoctor.d.ts.map +1 -1
  11. package/dist/commands/ticketDoctor.js +35 -8
  12. package/dist/index.d.ts +6 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +4 -0
  15. package/dist/lib/adapterDefinition.d.ts +27 -0
  16. package/dist/lib/adapterDefinition.d.ts.map +1 -0
  17. package/dist/lib/adapterDefinition.js +7 -0
  18. package/dist/lib/adapters/linear/factory.d.ts +27 -0
  19. package/dist/lib/adapters/linear/factory.d.ts.map +1 -0
  20. package/dist/lib/adapters/linear/factory.js +161 -0
  21. package/dist/lib/adapters/linear/index.d.ts +5 -0
  22. package/dist/lib/adapters/linear/index.d.ts.map +1 -0
  23. package/dist/lib/adapters/linear/index.js +8 -0
  24. package/dist/lib/adapters/linear/schema.d.ts +14 -0
  25. package/dist/lib/adapters/linear/schema.d.ts.map +1 -0
  26. package/dist/lib/adapters/linear/schema.js +15 -0
  27. package/dist/lib/adapters/registry.d.ts +38 -0
  28. package/dist/lib/adapters/registry.d.ts.map +1 -0
  29. package/dist/lib/adapters/registry.js +82 -0
  30. package/dist/lib/adapters/shell/factory.d.ts +21 -0
  31. package/dist/lib/adapters/shell/factory.d.ts.map +1 -0
  32. package/dist/lib/adapters/shell/factory.js +130 -0
  33. package/dist/lib/adapters/shell/index.d.ts +5 -0
  34. package/dist/lib/adapters/shell/index.d.ts.map +1 -0
  35. package/dist/lib/adapters/shell/index.js +8 -0
  36. package/dist/lib/adapters/shell/invoke.d.ts +45 -0
  37. package/dist/lib/adapters/shell/invoke.d.ts.map +1 -0
  38. package/dist/lib/adapters/shell/invoke.js +153 -0
  39. package/dist/lib/adapters/shell/schema.d.ts +90 -0
  40. package/dist/lib/adapters/shell/schema.d.ts.map +1 -0
  41. package/dist/lib/adapters/shell/schema.js +54 -0
  42. package/dist/lib/board.d.ts +20 -0
  43. package/dist/lib/board.d.ts.map +1 -0
  44. package/dist/lib/board.js +77 -0
  45. package/dist/lib/boardSource.d.ts +23 -7
  46. package/dist/lib/boardSource.d.ts.map +1 -1
  47. package/dist/lib/boardSource.js +51 -11
  48. package/dist/lib/buildSources.d.ts +19 -0
  49. package/dist/lib/buildSources.d.ts.map +1 -0
  50. package/dist/lib/buildSources.js +34 -0
  51. package/dist/lib/config.d.ts +27 -0
  52. package/dist/lib/config.d.ts.map +1 -1
  53. package/dist/lib/config.js +36 -0
  54. package/dist/lib/defaultBranch.d.ts +24 -0
  55. package/dist/lib/defaultBranch.d.ts.map +1 -0
  56. package/dist/lib/defaultBranch.js +39 -0
  57. package/dist/lib/ticketSource.d.ts +85 -0
  58. package/dist/lib/ticketSource.d.ts.map +1 -0
  59. package/dist/lib/ticketSource.js +26 -0
  60. package/dist/lib/worktrees.d.ts.map +1 -1
  61. package/dist/lib/worktrees.js +9 -2
  62. package/package.json +3 -2
package/README.md CHANGED
@@ -173,6 +173,53 @@ Three keys are required; everything else has a default.
173
173
 
174
174
  Agent selection uses Linear labels: `agent-claude`, `agent-codex`, `agent-<name>`. `crew run` without `--ticket` only fetches tickets carrying an `agent-*` label — the GraphQL query filters server-side, so unlabeled tickets are never returned by Linear and do not appear on the board. Use `crew run --ticket <TICKET>` to provision an unlabeled ticket on demand (falls back to `models.default`). `agent-any` routes to the model with the most available session capacity. Todo tickets blocked by non-terminal blockers are skipped until their blockers reach a terminal status.
175
175
 
176
+ ### Pluggable ticket sources
177
+
178
+ `sources` declares extra ticket-system adapters. The current release verifies configured extra sources during `crew run` startup; the dispatch loop still reads Linear through `linear.projects` until the consumer refactor lands. This lets you validate shell/Jira/local-plan integrations without changing existing Linear behavior.
179
+
180
+ The built-in `shell` adapter runs command templates and reads JSON from stdout:
181
+
182
+ ```ts
183
+ export default {
184
+ // ...
185
+ sources: [
186
+ {
187
+ kind: "shell",
188
+ name: "jira",
189
+ commands: {
190
+ verify: "jira me",
191
+ fetch: "~/.config/groundcrew/jira-fetch.sh",
192
+ resolveOne: "~/.config/groundcrew/jira-resolve.sh ${id}",
193
+ markInProgress: "jira issue move ${id} 'In Progress'",
194
+ },
195
+ timeouts: { fetch: 60_000 },
196
+ },
197
+ ],
198
+ };
199
+ ```
200
+
201
+ `commands.fetch` must print a JSON array of issues. `commands.resolveOne`, when set, must print one issue, print nothing for "not found", or exit `3` for "not found". `commands.markInProgress`, when set, receives the issue's `sourceRef` as JSON on stdin. `${id}`, `${canonicalId}`, and `${name}` placeholders are shell-quoted before substitution.
202
+
203
+ ```json
204
+ [
205
+ {
206
+ "id": "JIRA-123",
207
+ "title": "Add retry logic",
208
+ "description": "Ticket body",
209
+ "status": "todo",
210
+ "repository": "your-org/your-repo",
211
+ "model": "claude",
212
+ "assignee": "Alice",
213
+ "updatedAt": "2026-05-22T15:00:00Z",
214
+ "blockers": [{ "id": "JIRA-122", "title": "Schema migration", "status": "done" }],
215
+ "hasMoreBlockers": false,
216
+ "sourceRef": { "nativeId": "10042" }
217
+ }
218
+ ]
219
+ ```
220
+
221
+ Allowed `status` values are `todo`, `in-progress`, `in-review`, `done`, and `other`. Use `null` for `repository` or `model` when a ticket should not be groundcrew-eligible. `hasMoreBlockers` is optional and defaults to `false`; `sourceRef` is opaque data that groundcrew passes back to your writeback command.
222
+
176
223
  ### Prompt customization
177
224
 
178
225
  Groundcrew ships one model-agnostic unattended prompt by default. It tells the agent to make reasonable assumptions, follow repository instructions, run documented verification, review its diff, open a PR when GitHub/`gh` is available, and include a workspace continuation hint when known.
@@ -203,6 +250,7 @@ This keeps package defaults portable while letting your private config reference
203
250
  | `linear.projects[].statuses.inProgress` | `"In Progress"` | Status set after a workspace is provisioned; counts toward the shared `maximumInProgress`. |
204
251
  | `linear.projects[].statuses.done` | `"Done"` | Status that triggers worktree cleanup for this project. |
205
252
  | `linear.projects[].statuses.terminal` | `["Done"]` | Additional status names treated as terminal for cleanup and blocker checks. The project's `done` status is always included. |
253
+ | `sources` | `[]` | Additional pluggable ticket sources. Extra sources are verified at startup; Linear remains the dispatch read path until the consumer refactor. Built-in kinds: `shell`, `linear`. |
206
254
  | `git.remote` | `"origin"` | Remote used for `fetch` and as the worktree base ref. |
207
255
  | `git.defaultBranch` | `"main"` | Branch fetched from `git.remote` and used as the worktree base. |
208
256
  | `workspace.projectDir` | **required** | Parent dir for cloned repos and sibling ticket worktrees. |
@@ -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
@@ -40,6 +40,26 @@ export default {
40
40
  // Everything below is optional — defaults shown for reference. Uncomment
41
41
  // and edit to override.
42
42
  //
43
+ // // Additional pluggable ticket sources beyond the implicit built-in
44
+ // // Linear adapter (configured via `linear.projects` above). The most
45
+ // // common use is `kind: "shell"`, which wires any external system via
46
+ // // command templates that emit/consume JSON. See the shell adapter's
47
+ // // ShellIssue schema for the JSON contract `fetch` / `resolveOne` must
48
+ // // emit.
49
+ // sources: [
50
+ // {
51
+ // kind: "shell",
52
+ // name: "jira",
53
+ // commands: {
54
+ // verify: "jira me",
55
+ // fetch: "~/.config/groundcrew/jira-fetch.sh",
56
+ // resolveOne: "~/.config/groundcrew/jira-resolve.sh ${id}",
57
+ // markInProgress: "jira issue move ${id} 'In Progress'",
58
+ // },
59
+ // timeouts: { fetch: 60_000 },
60
+ // },
61
+ // ],
62
+ //
43
63
  // git: { remote: "origin", defaultBranch: "main" },
44
64
  //
45
65
  // orchestrator: {
@@ -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,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;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,CAuMjE"}
@@ -85,19 +85,31 @@ 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
+ // Surface parent tickets that fetchBoard silently dropped. Without this
91
+ // an operator sees "No Todo tickets to pick up" with no signal that an
92
+ // expected Todo+labelled ticket was skipped because it has sub-issues.
93
+ for (const skip of state.parentSkips) {
94
+ log(`Skipping ${skip.id}: parent ticket with ${skip.childCount} sub-issue(s) — groundcrew works sub-issues, not parents`);
95
+ logEvent("dispatch", {
96
+ outcome: "skipped",
97
+ reason: "parent_with_children",
98
+ ticket: skip.id,
99
+ children: skip.childCount,
100
+ });
101
+ }
90
102
  const activeCount = state.issues.filter((issue) => issue.status === projectFor(issue, config).statuses.inProgress).length;
91
103
  const slots = config.orchestrator.maximumInProgress - activeCount;
92
104
  // Narrow Todo to tickets that opted in via an `agent-*` label.
93
105
  // Unlabeled tickets are not groundcrew's concern even when in Todo.
94
106
  const todo = state.issues.filter((issue) => issue.status === projectFor(issue, config).statuses.todo && isGroundcrewIssue(issue));
95
107
  if (slots <= 0) {
96
- log(`At capacity (${activeCount}/${config.orchestrator.maximumInProgress}), no new work to start`);
108
+ log(`At capacity (${activeCount}/${config.orchestrator.maximumInProgress}), no new work to start${idleSuffix}`);
97
109
  return;
98
110
  }
99
111
  if (todo.length === 0) {
100
- log(`No Todo tickets to pick up`);
112
+ log(`No Todo tickets to pick up${idleSuffix}`);
101
113
  return;
102
114
  }
103
115
  // Run the blocker pre-pass first so an all-blocked board short-circuits
@@ -107,7 +119,7 @@ export function createDispatcher(deps) {
107
119
  logSkip(skip);
108
120
  }
109
121
  if (unblocked.length === 0) {
110
- log(`No eligible Todo tickets after blocker filtering`);
122
+ log(`No eligible Todo tickets after blocker filtering${idleSuffix}`);
111
123
  return;
112
124
  }
113
125
  // usage() is an HTTP call; workspaces.probe shells tmux/cmux. Kick off
@@ -146,7 +158,7 @@ export function createDispatcher(deps) {
146
158
  logSkip(skip);
147
159
  }
148
160
  if (starts.length === 0) {
149
- log(`No eligible Todo tickets after eligibility filtering`);
161
+ log(`No eligible Todo tickets after eligibility filtering${idleSuffix}`);
150
162
  return;
151
163
  }
152
164
  log(`${slots} slot(s) available, starting ${starts.length} ticket(s): ${starts.map(({ issue }) => `${issue.id}(${issue.model})`).join(", ")}`);
@@ -1 +1 @@
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,CA6B7E"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/commands/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA6DH,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,CA4C7E"}
@@ -5,6 +5,8 @@
5
5
  * orchestrator's user-facing output.
6
6
  */
7
7
  import { createBoardSource, RepositoryResolutionError, } from "../lib/boardSource.js";
8
+ import { createBoard } from "../lib/board.js";
9
+ import { buildSources } from "../lib/buildSources.js";
8
10
  import { loadConfig } from "../lib/config.js";
9
11
  import { getUsageByModel } from "../lib/usage.js";
10
12
  import { errorMessage, getLinearClient, log, sleep } from "../lib/util.js";
@@ -65,8 +67,20 @@ export async function orchestrate(options) {
65
67
  const client = getLinearClient();
66
68
  const boardSource = createBoardSource({ config, client });
67
69
  await boardSource.verify();
70
+ // Verify any pluggable sources declared in config.sources (shell adapters,
71
+ // future built-in adapters) at startup. The Linear path still runs through
72
+ // boardSource.fetch in the main loop; shell-source dispatch is a follow-up.
73
+ // An empty config.sources resolves to an empty Board and verify() is a no-op.
74
+ const extraSources = await buildSources(config.sources, { globalConfig: config });
75
+ const board = createBoard(extraSources);
76
+ await board.verify();
68
77
  const cleaner = createCleaner({ config });
69
78
  const dispatcher = createDispatcher({ config, client });
79
+ // Folded into the dispatcher's idle log lines in watch mode so each idle
80
+ // tick prints one combined line instead of "<reason>" + "Next poll in Xs".
81
+ const idleSuffix = options.watch
82
+ ? `; next poll in ${config.orchestrator.pollIntervalMilliseconds / MS_PER_SECOND}s`
83
+ : undefined;
70
84
  const tick = async (signal) => {
71
85
  const state = await withRetry(async () => await boardSource.fetch(), signal);
72
86
  const worktreeEntries = worktrees.list(config);
@@ -82,6 +96,7 @@ export async function orchestrate(options) {
82
96
  // Lazy: dispatcher only invokes this after its own early-returns, so
83
97
  // an idle board doesn't burn a codexbar shell-out per tick.
84
98
  usage: async (usageSignal) => await fetchUsageOrEmpty(config, usageSignal),
99
+ ...(idleSuffix === undefined ? {} : { idleSuffix }),
85
100
  });
86
101
  };
87
102
  await (options.watch ? runWatchLoop(tick, config) : tick());
@@ -150,7 +165,6 @@ async function runWatchLoop(tick, config) {
150
165
  if (shutdown.signal.aborted) {
151
166
  break;
152
167
  }
153
- log(`Next poll in ${config.orchestrator.pollIntervalMilliseconds / MS_PER_SECOND}s...`);
154
168
  // oxlint-disable-next-line no-await-in-loop -- watch loop is intentionally serial
155
169
  await sleep(config.orchestrator.pollIntervalMilliseconds, shutdown.signal);
156
170
  }
@@ -145,14 +145,26 @@ export interface TicketDoctorDependencies {
145
145
  probeWorkingTree: (input: {
146
146
  worktreeDir: string;
147
147
  }) => Promise<WorktreeDirtiness>;
148
+ /**
149
+ * Resolves the default branch for `repoDir` (e.g. "master" vs "main") from
150
+ * the local clone's `refs/remotes/<remote>/HEAD`, falling back to
151
+ * `config.git.defaultBranch`. Injected so probeLocalBranchSection can pass a
152
+ * per-repo branch into `probeLocalBranch` without each probe needing to
153
+ * shell out to git itself.
154
+ */
155
+ resolveDefaultBranch: (input: {
156
+ repoDir: string;
157
+ }) => Promise<string>;
148
158
  probeLocalBranch: (input: {
149
159
  repoDir: string;
150
160
  branch: string;
161
+ remote: string;
151
162
  defaultBranch: string;
152
163
  }) => Promise<LocalBranchProbe>;
153
164
  probeRemoteBranch: (input: {
154
165
  repoDir: string;
155
166
  branch: string;
167
+ remote: string;
156
168
  doFetch: boolean;
157
169
  }) => Promise<RemoteBranchProbe>;
158
170
  probePullRequest: (input: {
@@ -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,6 +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 { resolveDefaultBranch } from "../lib/defaultBranch.js";
21
22
  import { AGENT_ANY_MODEL, findProjectBySlugId, loadConfig, } from "../lib/config.js";
22
23
  import { which } from "../lib/host.js";
23
24
  import { readRunState } from "../lib/runState.js";
@@ -258,6 +259,17 @@ function buildRepoChecks(raw, config, ticket) {
258
259
  const resolvedRepository = repositoryResolution.kind === "ok" ? repositoryResolution.repository : "";
259
260
  return { resolvedRepository, checks };
260
261
  }
262
+ function buildChildrenCheck(raw) {
263
+ if (raw.hasChildren) {
264
+ return {
265
+ name: "Has no sub-issues",
266
+ status: "fail",
267
+ detail: "parent ticket with sub-issues — groundcrew works sub-issues, not parents; label a sub-issue or detach the children",
268
+ failureSummary: "parent ticket with sub-issues — groundcrew works sub-issues, not parents",
269
+ };
270
+ }
271
+ return { name: "Has no sub-issues", status: "ok" };
272
+ }
261
273
  async function runEligibilityChecks(arguments_) {
262
274
  const { ticket, raw, config, resolvedRepository, resolvedModel, dependencies, eligibility } = arguments_;
263
275
  const blockers = await dependencies.fetchBlockersFor({ ticket, uuid: raw.uuid });
@@ -531,10 +543,12 @@ async function probeLocalBranchSection(deps, entry) {
531
543
  };
532
544
  }
533
545
  const repoDir = repoDirFromEntry(entry, deps);
546
+ const defaultBranch = await deps.resolveDefaultBranch({ repoDir });
534
547
  const probe = await deps.probeLocalBranch({
535
548
  repoDir,
536
549
  branch: entry.branchName,
537
- defaultBranch: deps.config.git.defaultBranch,
550
+ remote: deps.config.git.remote,
551
+ defaultBranch,
538
552
  });
539
553
  if (probe.kind === "present") {
540
554
  const defaultBranchName = probe.defaultBranch ?? deps.config.git.defaultBranch;
@@ -543,7 +557,7 @@ async function probeLocalBranchSection(deps, entry) {
543
557
  {
544
558
  name: "Local branch exists",
545
559
  status: "ok",
546
- detail: `${entry.branchName}, ${probe.ahead} ahead / ${probe.behind} behind origin/${defaultBranchName}`,
560
+ detail: `${entry.branchName}, ${probe.ahead} ahead / ${probe.behind} behind ${deps.config.git.remote}/${defaultBranchName}`,
547
561
  },
548
562
  ],
549
563
  skipReason: "",
@@ -572,24 +586,26 @@ async function probeRemoteBranchSection(deps, entry) {
572
586
  return { checks: [], skipReason: "repo dir unresolved", probe: { kind: "absent" } };
573
587
  }
574
588
  const repoDir = repoDirFromEntry(entry, deps);
589
+ const checkName = `Branch present on ${deps.config.git.remote}`;
575
590
  const probe = await deps.probeRemoteBranch({
576
591
  repoDir,
577
592
  branch: entry.branchName,
593
+ remote: deps.config.git.remote,
578
594
  doFetch: deps.doFetch,
579
595
  });
580
596
  if (probe.kind === "present") {
581
- return { checks: [{ name: "Branch present on origin", status: "ok" }], skipReason: "", probe };
597
+ return { checks: [{ name: checkName, status: "ok" }], skipReason: "", probe };
582
598
  }
583
599
  if (probe.kind === "absent") {
584
600
  return {
585
- checks: [{ name: "Branch present on origin", status: "fail", detail: "not pushed" }],
601
+ checks: [{ name: checkName, status: "fail", detail: "not pushed" }],
586
602
  skipReason: "",
587
603
  probe,
588
604
  };
589
605
  }
590
606
  // probe.kind === "unknown"
591
607
  return {
592
- checks: [{ name: "Branch present on origin", status: "skipped", detail: probe.reason }],
608
+ checks: [{ name: checkName, status: "skipped", detail: probe.reason }],
593
609
  skipReason: "",
594
610
  probe,
595
611
  };
@@ -642,6 +658,12 @@ async function runPreDispatch(input) {
642
658
  const eligibility = [];
643
659
  const { resolvedModel, checks: modelChecks } = buildModelChecks(raw, config);
644
660
  resolutionExtra.push(...modelChecks);
661
+ // Children check comes before repo checks: a parent ticket is a
662
+ // structural property of the issue itself (filtered out by `fetchBoard`,
663
+ // so the dispatcher will never act on it). Reporting that first beats
664
+ // surfacing "your repo isn't cloned" for a ticket groundcrew won't pick
665
+ // up either way.
666
+ resolutionExtra.push(buildChildrenCheck(raw));
645
667
  const { resolvedRepository, checks: repoChecks } = buildRepoChecks(raw, config, ticket);
646
668
  resolutionExtra.push(...repoChecks);
647
669
  if (input.statusCheckFailed) {
@@ -969,6 +991,11 @@ export async function runTicketDoctor(parsed) {
969
991
  probeWorkspaces: async () => await workspaces.probe(config),
970
992
  workspaceAccessHint: async (name) => await workspaces.accessHint(config, name),
971
993
  probeWorkingTree: async ({ worktreeDir }) => await worktrees.probeWorkingTree({ worktreeDir }),
994
+ resolveDefaultBranch: async ({ repoDir }) => await resolveDefaultBranch({
995
+ repoDir,
996
+ remote: config.git.remote,
997
+ fallback: config.git.defaultBranch,
998
+ }),
972
999
  probeLocalBranch: probeLocalBranchImpl,
973
1000
  probeRemoteBranch: probeRemoteBranchImpl,
974
1001
  probePullRequest: probePullRequestImpl,
@@ -1028,7 +1055,7 @@ async function probeLocalBranchImpl(input) {
1028
1055
  "rev-list",
1029
1056
  "--left-right",
1030
1057
  "--count",
1031
- `${input.branch}...origin/${input.defaultBranch}`,
1058
+ `${input.branch}...${input.remote}/${input.defaultBranch}`,
1032
1059
  ]);
1033
1060
  const [aheadString, behindString] = output.trim().split(/\s+/);
1034
1061
  const ahead = Number.parseInt(aheadString ?? "0", 10);
@@ -1050,7 +1077,7 @@ async function probeRemoteBranchImpl(input) {
1050
1077
  input.repoDir,
1051
1078
  "fetch",
1052
1079
  "--quiet",
1053
- "origin",
1080
+ input.remote,
1054
1081
  input.branch,
1055
1082
  ]);
1056
1083
  }
@@ -1064,7 +1091,7 @@ async function probeRemoteBranchImpl(input) {
1064
1091
  input.repoDir,
1065
1092
  "ls-remote",
1066
1093
  "--exit-code",
1067
- "origin",
1094
+ input.remote,
1068
1095
  `refs/heads/${input.branch}`,
1069
1096
  ]);
1070
1097
  return { kind: "present" };
package/dist/index.d.ts CHANGED
@@ -5,11 +5,16 @@ 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, ProjectConfig, ResolvedConfig, ResolvedProjectConfig, } from "./lib/config.ts";
8
+ export type { Config, ModelDefinition, ProjectConfig, ResolvedConfig, ResolvedProjectConfig, SourceConfig, } from "./lib/config.ts";
9
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
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
+ export { type Board, createBoard } from "./lib/board.ts";
14
+ export { buildSources, buildSourcesWith } from "./lib/buildSources.ts";
15
+ export type { AdapterContext, AdapterDefinition } from "./lib/adapterDefinition.ts";
16
+ export { adapterRegistry, type AdapterLoader, buildRegistry, buildSourceConfigSchema, listAdapterDirectories, } from "./lib/adapters/registry.ts";
17
+ export { AmbiguousTicketError, type Blocker as CanonicalBlocker, type BoardState as CanonicalBoardState, type CanonicalStatus, type GroundcrewIssue as CanonicalGroundcrewIssue, type Issue as CanonicalIssue, isGroundcrewIssue as isCanonicalGroundcrewIssue, type TicketSource, } from "./lib/ticketSource.ts";
13
18
  export type { TicketCheck } from "./commands/ticketCheck.ts";
14
19
  export { ticketDoctor, type TicketDoctorDependencies, type TicketDoctorResult, type TicketDoctorVerdict, } from "./commands/ticketDoctor.ts";
15
20
  //# sourceMappingURL=index.d.ts.map
@@ -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,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"}
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,EACrB,YAAY,GACb,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,OAAO,EAAE,KAAK,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACvE,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EACL,eAAe,EACf,KAAK,aAAa,EAClB,aAAa,EACb,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,KAAK,OAAO,IAAI,gBAAgB,EAChC,KAAK,UAAU,IAAI,mBAAmB,EACtC,KAAK,eAAe,EACpB,KAAK,eAAe,IAAI,wBAAwB,EAChD,KAAK,KAAK,IAAI,cAAc,EAC5B,iBAAiB,IAAI,0BAA0B,EAC/C,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAE/B,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
@@ -9,4 +9,8 @@ export { findProjectBySlugId, loadConfig, unionTerminalStatuses } from "./lib/co
9
9
  export { readRunState, recordRunState, removeRunState, runStateDirectory, runStatePath, updateRunState, } from "./lib/runState.js";
10
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
+ export { createBoard } from "./lib/board.js";
13
+ export { buildSources, buildSourcesWith } from "./lib/buildSources.js";
14
+ export { adapterRegistry, buildRegistry, buildSourceConfigSchema, listAdapterDirectories, } from "./lib/adapters/registry.js";
15
+ export { AmbiguousTicketError, isGroundcrewIssue as isCanonicalGroundcrewIssue, } from "./lib/ticketSource.js";
12
16
  export { ticketDoctor, } from "./commands/ticketDoctor.js";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared `AdapterDefinition` shape that every built-in adapter
3
+ * (`src/lib/adapters/<kind>/index.ts`) default-exports. The runtime registry
4
+ * (`./adapters/registry.ts`) discovers adapters by enumerating that
5
+ * directory and reading each module's default export.
6
+ */
7
+ import type { z } from "zod";
8
+ import type { ResolvedConfig } from "./config.ts";
9
+ import type { TicketSource } from "./ticketSource.ts";
10
+ /**
11
+ * Cross-cutting context every adapter receives at construction time. Holds
12
+ * the global resolved config so adapters can read shared concerns (the
13
+ * `workspace.knownRepositories` list, `models.*` definitions, etc.) without
14
+ * each one duplicating them in its per-source config block.
15
+ */
16
+ export interface AdapterContext {
17
+ readonly globalConfig: ResolvedConfig;
18
+ }
19
+ export interface AdapterDefinition<TSchema extends z.ZodType = z.ZodType> {
20
+ /** Discriminator value used in `SourceConfig.kind`. Must equal the directory name. */
21
+ readonly kind: string;
22
+ /** Zod schema for this adapter's config block. The `kind` field must be `z.literal(kind)`. */
23
+ readonly configSchema: TSchema;
24
+ /** Builds a TicketSource from a validated config and the shared adapter context. */
25
+ readonly create: (config: z.infer<TSchema>, context: AdapterContext) => TicketSource;
26
+ }
27
+ //# sourceMappingURL=adapterDefinition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapterDefinition.d.ts","sourceRoot":"","sources":["../../src/lib/adapterDefinition.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;IACtE,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,cAAc,KAAK,YAAY,CAAC;CACtF"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared `AdapterDefinition` shape that every built-in adapter
3
+ * (`src/lib/adapters/<kind>/index.ts`) default-exports. The runtime registry
4
+ * (`./adapters/registry.ts`) discovers adapters by enumerating that
5
+ * directory and reading each module's default export.
6
+ */
7
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Linear `TicketSource` factory. Wraps the existing boardSource.ts machinery
3
+ * (createBoardSource, fetchResolvedIssue, createLinearIssueStatusUpdater) and
4
+ * converts the legacy Linear-specific `Issue`/`Blocker` shapes into the
5
+ * canonical `Issue`/`Blocker` shapes consumers (via `Board`) speak.
6
+ *
7
+ * Per-project canonical-status mapping lives here: each `Issue` is mapped
8
+ * against its own project's `statuses` block (the multi-project semantics
9
+ * shipped in PR #75). Off-config blockers fall back to the union of all
10
+ * configured projects' status sets — preserving today's
11
+ * `isTerminalStatusForBlocker` behavior.
12
+ *
13
+ * Description is not populated on `fetch()` Issues (boardSource's snapshot
14
+ * doesn't include it); `resolveOne()` Issues carry the full description
15
+ * because `fetchResolvedIssue` fetches it explicitly. Phase 6 can lift
16
+ * description onto the board snapshot when it refactors setupWorkspace.
17
+ */
18
+ import type { AdapterContext } from "../../adapterDefinition.ts";
19
+ import { type Blocker as LinearBlocker, type Issue as LinearIssue } from "../../boardSource.ts";
20
+ import { type ResolvedProjectConfig } from "../../config.ts";
21
+ import type { CanonicalStatus, Issue as CanonicalIssue, TicketSource } from "../../ticketSource.ts";
22
+ import type { LinearAdapterConfig } from "./schema.ts";
23
+ export declare function canonicalStatusForProject(nativeStatus: string, project: ResolvedProjectConfig): CanonicalStatus;
24
+ export declare function canonicalBlockerStatus(blocker: LinearBlocker, globalConfig: AdapterContext["globalConfig"]): CanonicalStatus;
25
+ export declare function toCanonicalIssue(linearIssue: LinearIssue, globalConfig: AdapterContext["globalConfig"], sourceName: string): CanonicalIssue;
26
+ export declare function createLinearTicketSource(config: LinearAdapterConfig, context: AdapterContext): TicketSource;
27
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EACL,KAAK,OAAO,IAAI,aAAa,EAG7B,KAAK,KAAK,IAAI,WAAW,EAE1B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAElF,OAAO,KAAK,EAEV,eAAe,EACf,KAAK,IAAI,cAAc,EACvB,YAAY,EACb,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAUvD,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,qBAAqB,GAC7B,eAAe,CAcjB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,EACtB,YAAY,EAAE,cAAc,CAAC,cAAc,CAAC,GAC3C,eAAe,CAoBjB;AAcD,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,cAAc,CAAC,cAAc,CAAC,EAC5C,UAAU,EAAE,MAAM,GACjB,cAAc,CA8BhB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,cAAc,GACtB,YAAY,CAwEd"}