@clipboard-health/groundcrew 4.49.3 → 4.49.4

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.
@@ -89,7 +89,13 @@ function resolveCreateRepository(arguments_) {
89
89
  description: `Repository: ${input.repository}`,
90
90
  config,
91
91
  });
92
- if (resolution.kind === "missing") {
92
+ // `resolveRepositoryFor` reports an unconfigured *declared* repo as
93
+ // { kind: "ok", repository: <asserted name> } (the dispatch path relies on
94
+ // that so the host can WARN+skip it by name). Create is a manual, must-be-
95
+ // valid operation, so reject anything that didn't canonicalize to a known
96
+ // repository rather than routing a task at an unconfigured worktree.
97
+ if (resolution.kind === "missing" ||
98
+ !config.workspace.knownRepositories.includes(resolution.repository)) {
93
99
  throw new Error(`linear: repository "${input.repository}" is not in workspace.knownRepositories`);
94
100
  }
95
101
  return resolution.repository;
@@ -1 +1 @@
1
- {"version":3,"file":"parsing.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/parsing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC3F,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1F,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAG3C,MAAM,MAAM,oBAAoB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5F,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,wBAAgB,0BAA0B,CAAC,UAAU,EAAE;IACrD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjC,GAAG,mBAAmB,GAAG,SAAS,CAIlC;AASD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAUnE;AAiDD,wBAAgB,oBAAoB,CAAC,UAAU,EAAE;IAC/C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CACxB,GAAG,oBAAoB,CAuBvB;AAED,UAAU,wBAAwB;IAChC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,wBAAwB,GAAG,MAAM,CA2B5E;AAkDD,wBAAgB,eAAe,CAAC,UAAU,EAAE;IAC1C,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CACxB,GAAG,eAAe,CAiBlB"}
1
+ {"version":3,"file":"parsing.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapters/linear/parsing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAuC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC3F,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1F,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAG3C,MAAM,MAAM,oBAAoB,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAE5F,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,wBAAgB,0BAA0B,CAAC,UAAU,EAAE;IACrD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjC,GAAG,mBAAmB,GAAG,SAAS,CAIlC;AASD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAUnE;AA0FD,wBAAgB,oBAAoB,CAAC,UAAU,EAAE;IAC/C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CACxB,GAAG,oBAAoB,CAuBvB;AAED,UAAU,wBAAwB;IAChC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,wBAAwB,GAAG,MAAM,CA2B5E;AAkDD,wBAAgB,eAAe,CAAC,UAAU,EAAE;IAC1C,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,MAAM,EAAE,cAAc,CAAC;CACxB,GAAG,eAAe,CAiBlB"}
@@ -28,10 +28,56 @@ export function buildRepositoryRegex(config) {
28
28
  .join("|");
29
29
  return new RegExp(String.raw `\b(${alternation})\b`);
30
30
  }
31
+ // An explicit `Repository: <owner/repo>` (or bare `<repo>`) line is the
32
+ // author's authoritative target: it is the format `create.ts` emits and the
33
+ // one humans use in hand-written tickets. Case-insensitive (`i`) so
34
+ // `repository:` / `REPOSITORY:` are all honored; anchored to a line start so
35
+ // prose that merely contains the word "repository" can't trip it; optional
36
+ // wrapping backticks are tolerated.
37
+ const DECLARED_REPOSITORY_PATTERN = /^[^\S\n]*Repository:[^\S\n]*`?([^\s`]+)`?/im;
38
+ function extractDeclaredRepository(description) {
39
+ return DECLARED_REPOSITORY_PATTERN.exec(description)?.[1];
40
+ }
41
+ // Resolve one candidate name (full `owner/repo` or bare `repo`) against
42
+ // knownRepositories: a bare name canonicalizes to its full entry, a bare name
43
+ // matching several entries is ambiguous, and anything unconfigured is
44
+ // `unknown` (the caller decides whether that WARN+skips or errors). GitHub
45
+ // owners and repository names are case-insensitive, so the match ignores case
46
+ // (a mis-cased declared repo still resolves) while always returning the
47
+ // configured spelling.
48
+ function canonicalizeKnownRepositoryName(name, knownRepositories) {
49
+ const lowerName = name.toLowerCase();
50
+ const candidates = knownRepositories.filter((repo) => {
51
+ const lowerRepo = repo.toLowerCase();
52
+ return lowerRepo === lowerName || lowerRepo.endsWith(`/${lowerName}`);
53
+ });
54
+ if (candidates.length > 1) {
55
+ return { kind: "ambiguous" };
56
+ }
57
+ if (candidates.length === 1) {
58
+ /* v8 ignore next @preserve -- length-1 guarantees [0] defined */
59
+ // oxlint-disable-next-line typescript/no-non-null-assertion -- length-1 guarantees [0] is defined
60
+ return { kind: "canonical", repository: candidates[0] };
61
+ }
62
+ return { kind: "unknown", repository: name };
63
+ }
31
64
  function canonicalizeRepositoryMatch(description, config, repositoryRegex) {
32
65
  if (description === undefined || description.length === 0) {
33
66
  return { kind: "missing" };
34
67
  }
68
+ // An explicit `Repository:` line is authoritative — resolve on it alone and
69
+ // never fall through to the whole-description scan. That fall-through is how
70
+ // a task whose real target repo is unconfigured (so it can't be scanned for)
71
+ // gets hijacked by an incidental known-repo mention elsewhere in the body
72
+ // (e.g. a "contrast with X" note). An unconfigured declared repo returns
73
+ // `unknown` so the dispatcher WARN+skips it by name instead of silently
74
+ // running against the wrong worktree. Resolved before the empty-config guard
75
+ // below because canonicalization needs no regex, so an empty
76
+ // knownRepositories must not discard a name the author stated outright.
77
+ const declared = extractDeclaredRepository(description);
78
+ if (declared !== undefined) {
79
+ return canonicalizeKnownRepositoryName(declared, config.workspace.knownRepositories);
80
+ }
35
81
  // Guard against an empty knownRepositories config: buildRepositoryRegex
36
82
  // would produce /\b()\b/, which matches the empty string at any word
37
83
  // boundary and returns a bogus "" match. Treat that as "no repo could
@@ -44,16 +90,7 @@ function canonicalizeRepositoryMatch(description, config, repositoryRegex) {
44
90
  if (matched === undefined) {
45
91
  return { kind: "missing" };
46
92
  }
47
- const candidates = config.workspace.knownRepositories.filter((r) => r === matched || r.endsWith(`/${matched}`));
48
- if (candidates.length > 1) {
49
- return { kind: "ambiguous" };
50
- }
51
- if (candidates.length === 1) {
52
- /* v8 ignore next @preserve -- length-1 guarantees [0] defined */
53
- // oxlint-disable-next-line typescript/no-non-null-assertion -- length-1 guarantees [0] is defined
54
- return { kind: "canonical", repository: candidates[0] };
55
- }
56
- return { kind: "unknown", repository: matched };
93
+ return canonicalizeKnownRepositoryName(matched, config.workspace.knownRepositories);
57
94
  }
58
95
  export function resolveRepositoryFor(arguments_) {
59
96
  const { description, config } = arguments_;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/groundcrew",
3
- "version": "4.49.3",
3
+ "version": "4.49.4",
4
4
  "description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle and usage tracking.",
5
5
  "keywords": [
6
6
  "agent",
@@ -96,7 +96,7 @@
96
96
  "oxlint": "1.76.0",
97
97
  "oxlint-tsgolint": "7.0.2001",
98
98
  "syncpack": "15.3.2",
99
- "vite": "8.1.5",
99
+ "vite": "8.2.0",
100
100
  "vitest": "4.1.10"
101
101
  },
102
102
  "engines": {