chief-clancy 0.5.12 → 0.7.0

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 (102) hide show
  1. package/README.md +15 -8
  2. package/dist/bundle/clancy-afk.js +6 -2
  3. package/dist/bundle/clancy-once.js +71 -48
  4. package/dist/installer/hook-installer/hook-installer.d.ts +2 -0
  5. package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -1
  6. package/dist/installer/hook-installer/hook-installer.js +36 -1
  7. package/dist/installer/hook-installer/hook-installer.js.map +1 -1
  8. package/dist/installer/install.js +16 -1
  9. package/dist/installer/install.js.map +1 -1
  10. package/dist/schemas/env.d.ts +36 -0
  11. package/dist/schemas/env.d.ts.map +1 -1
  12. package/dist/schemas/env.js +11 -0
  13. package/dist/schemas/env.js.map +1 -1
  14. package/dist/schemas/github-issues.d.ts +6 -0
  15. package/dist/schemas/github-issues.d.ts.map +1 -1
  16. package/dist/schemas/github-issues.js +3 -0
  17. package/dist/schemas/github-issues.js.map +1 -1
  18. package/dist/schemas/jira.d.ts +21 -0
  19. package/dist/schemas/jira.d.ts.map +1 -1
  20. package/dist/schemas/jira.js +18 -0
  21. package/dist/schemas/jira.js.map +1 -1
  22. package/dist/schemas/linear.d.ts +41 -0
  23. package/dist/schemas/linear.d.ts.map +1 -1
  24. package/dist/schemas/linear.js +34 -0
  25. package/dist/schemas/linear.js.map +1 -1
  26. package/dist/scripts/afk/afk.d.ts.map +1 -1
  27. package/dist/scripts/afk/afk.js +28 -0
  28. package/dist/scripts/afk/afk.js.map +1 -1
  29. package/dist/scripts/afk/report/report.d.ts +47 -0
  30. package/dist/scripts/afk/report/report.d.ts.map +1 -0
  31. package/dist/scripts/afk/report/report.js +194 -0
  32. package/dist/scripts/afk/report/report.js.map +1 -0
  33. package/dist/scripts/board/github/github.d.ts +33 -3
  34. package/dist/scripts/board/github/github.d.ts.map +1 -1
  35. package/dist/scripts/board/github/github.js +112 -27
  36. package/dist/scripts/board/github/github.js.map +1 -1
  37. package/dist/scripts/board/jira/jira.d.ts +36 -4
  38. package/dist/scripts/board/jira/jira.d.ts.map +1 -1
  39. package/dist/scripts/board/jira/jira.js +138 -65
  40. package/dist/scripts/board/jira/jira.js.map +1 -1
  41. package/dist/scripts/board/linear/linear.d.ts +32 -5
  42. package/dist/scripts/board/linear/linear.d.ts.map +1 -1
  43. package/dist/scripts/board/linear/linear.js +135 -17
  44. package/dist/scripts/board/linear/linear.js.map +1 -1
  45. package/dist/scripts/once/board-ops/board-ops.d.ts.map +1 -1
  46. package/dist/scripts/once/board-ops/board-ops.js +1 -1
  47. package/dist/scripts/once/board-ops/board-ops.js.map +1 -1
  48. package/dist/scripts/once/cost/cost.d.ts +10 -0
  49. package/dist/scripts/once/cost/cost.d.ts.map +1 -0
  50. package/dist/scripts/once/cost/cost.js +23 -0
  51. package/dist/scripts/once/cost/cost.js.map +1 -0
  52. package/dist/scripts/once/deliver/deliver.d.ts.map +1 -1
  53. package/dist/scripts/once/deliver/deliver.js +18 -1
  54. package/dist/scripts/once/deliver/deliver.js.map +1 -1
  55. package/dist/scripts/once/fetch-ticket/fetch-ticket.d.ts +19 -1
  56. package/dist/scripts/once/fetch-ticket/fetch-ticket.d.ts.map +1 -1
  57. package/dist/scripts/once/fetch-ticket/fetch-ticket.js +93 -29
  58. package/dist/scripts/once/fetch-ticket/fetch-ticket.js.map +1 -1
  59. package/dist/scripts/once/lock/lock.d.ts +17 -0
  60. package/dist/scripts/once/lock/lock.d.ts.map +1 -0
  61. package/dist/scripts/once/lock/lock.js +70 -0
  62. package/dist/scripts/once/lock/lock.js.map +1 -0
  63. package/dist/scripts/once/once.d.ts.map +1 -1
  64. package/dist/scripts/once/once.js +100 -4
  65. package/dist/scripts/once/once.js.map +1 -1
  66. package/dist/scripts/once/resume/resume.d.ts +24 -0
  67. package/dist/scripts/once/resume/resume.d.ts.map +1 -0
  68. package/dist/scripts/once/resume/resume.js +159 -0
  69. package/dist/scripts/once/resume/resume.js.map +1 -0
  70. package/dist/scripts/shared/format/format.d.ts.map +1 -1
  71. package/dist/scripts/shared/format/format.js +6 -1
  72. package/dist/scripts/shared/format/format.js.map +1 -1
  73. package/dist/scripts/shared/progress/progress.d.ts +18 -2
  74. package/dist/scripts/shared/progress/progress.d.ts.map +1 -1
  75. package/dist/scripts/shared/progress/progress.js +31 -4
  76. package/dist/scripts/shared/progress/progress.js.map +1 -1
  77. package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts +2 -1
  78. package/dist/scripts/shared/pull-request/pr-body/pr-body.d.ts.map +1 -1
  79. package/dist/scripts/shared/pull-request/pr-body/pr-body.js +10 -1
  80. package/dist/scripts/shared/pull-request/pr-body/pr-body.js.map +1 -1
  81. package/dist/types/remote.d.ts +1 -1
  82. package/dist/types/remote.d.ts.map +1 -1
  83. package/hooks/clancy-branch-guard.js +129 -0
  84. package/hooks/clancy-check-update.js +43 -0
  85. package/hooks/clancy-context-monitor.js +134 -46
  86. package/hooks/clancy-post-compact.js +53 -0
  87. package/hooks/package.json +3 -0
  88. package/package.json +3 -2
  89. package/src/agents/devils-advocate.md +53 -0
  90. package/src/agents/verification-gate.md +128 -0
  91. package/src/roles/planner/workflows/approve-plan.md +2 -2
  92. package/src/roles/reviewer/workflows/logs.md +9 -6
  93. package/src/roles/setup/commands/help.md +7 -0
  94. package/src/roles/setup/workflows/init.md +111 -6
  95. package/src/roles/setup/workflows/scaffold.md +57 -0
  96. package/src/roles/setup/workflows/settings.md +145 -0
  97. package/src/roles/setup/workflows/update.md +18 -0
  98. package/src/roles/strategist/commands/approve-brief.md +20 -0
  99. package/src/roles/strategist/commands/brief.md +27 -0
  100. package/src/roles/strategist/workflows/approve-brief.md +763 -0
  101. package/src/roles/strategist/workflows/brief.md +732 -0
  102. package/src/templates/CLAUDE.md +8 -1
@@ -39,7 +39,7 @@ export declare function pingJira(baseUrl: string, projectKey: string, auth: stri
39
39
  * @param label - If set, adds a label filter.
40
40
  * @returns The JQL query string.
41
41
  */
42
- export declare function buildJql(projectKey: string, status: string, sprint?: string, label?: string): string;
42
+ export declare function buildJql(projectKey: string, status: string, sprint?: string, label?: string, excludeHitl?: boolean): string;
43
43
  /**
44
44
  * Extract all text strings from a Jira ADF (Atlassian Document Format) description.
45
45
  *
@@ -64,16 +64,48 @@ export declare function fetchTicket(baseUrl: string, auth: string, projectKey: s
64
64
  epicKey?: string;
65
65
  blockers: string[];
66
66
  }) | undefined>;
67
+ /** Jira ticket with epic and blocker info. */
68
+ export type JiraTicket = Ticket & {
69
+ epicKey?: string;
70
+ blockers: string[];
71
+ };
72
+ /**
73
+ * Fetch multiple candidate tickets from Jira.
74
+ *
75
+ * @param baseUrl - The Jira Cloud base URL.
76
+ * @param auth - The Base64-encoded Basic auth string.
77
+ * @param projectKey - The Jira project key.
78
+ * @param status - The JQL status to filter by.
79
+ * @param sprint - Optional sprint filter.
80
+ * @param label - Optional label filter.
81
+ * @param excludeHitl - If `true`, excludes tickets with the `clancy:hitl` label.
82
+ * @param limit - Maximum number of results to return (default: 5).
83
+ * @returns Array of fetched tickets (may be empty).
84
+ */
85
+ export declare function fetchTickets(baseUrl: string, auth: string, projectKey: string, status: string, sprint?: string, label?: string, excludeHitl?: boolean, limit?: number): Promise<JiraTicket[]>;
86
+ /**
87
+ * Check whether a Jira issue is blocked by unresolved blockers.
88
+ *
89
+ * Fetches the issue's links and checks for inward "Blocks" relationships
90
+ * where the blocking issue's statusCategory is not "done".
91
+ *
92
+ * @param baseUrl - The Jira Cloud base URL.
93
+ * @param auth - The Base64-encoded Basic auth string.
94
+ * @param key - The Jira issue key (e.g., `'PROJ-123'`).
95
+ * @returns `true` if any blocker is unresolved, `false` otherwise.
96
+ */
97
+ export declare function fetchBlockerStatus(baseUrl: string, auth: string, key: string): Promise<boolean>;
67
98
  /** Result of checking children status for an epic. */
68
99
  export type ChildrenStatus = {
69
100
  total: number;
70
101
  incomplete: number;
71
102
  };
72
103
  /**
73
- * Fetch the children status of a Jira epic.
104
+ * Fetch the children status of a Jira epic (dual-mode).
74
105
  *
75
- * Returns the total number of children and how many are incomplete
76
- * (statusCategory != 'done'). Used to determine if an epic is complete.
106
+ * Tries the `Epic: {key}` text convention first (children with "Epic: PROJ-100"
107
+ * in their description). If no results, falls back to the native `parent = {key}`
108
+ * JQL query for backward compatibility with pre-v0.6.0 children.
77
109
  *
78
110
  * @param baseUrl - The Jira Cloud base URL.
79
111
  * @param auth - The Base64-encoded Basic auth string.
@@ -1 +1 @@
1
- {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/jira/jira.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK/C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CAUR;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CA0BnD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CACN,CAAC,MAAM,GAAG;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC,GACF,SAAS,CACZ,CA0EA;AAED,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAgDrC;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAgClB"}
1
+ {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/jira/jira.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK/C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,OAAO,GACpB,MAAM,CAWR;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CA0BnD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CACN,CAAC,MAAM,GAAG;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC,GACF,SAAS,CACZ,CAYA;AAED,8CAA8C;AAC9C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,OAAO,EACrB,KAAK,SAAI,GACR,OAAO,CAAC,UAAU,EAAE,CAAC,CAyEvB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAiClB;AAED,sDAAsD;AACtD,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAmBrC;AAuDD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAgClB"}
@@ -7,7 +7,7 @@
7
7
  * Uses the new POST `/rest/api/3/search/jql` endpoint (old GET `/search`
8
8
  * was removed by Atlassian in August 2025).
9
9
  */
10
- import { jiraSearchResponseSchema, jiraTransitionsResponseSchema, } from '../../../schemas/jira.js';
10
+ import { jiraIssueLinksResponseSchema, jiraSearchResponseSchema, jiraTransitionsResponseSchema, } from '../../../schemas/jira.js';
11
11
  import { jiraHeaders, pingEndpoint } from '../../../scripts/shared/http/http.js';
12
12
  const SAFE_VALUE_PATTERN = /^[a-zA-Z0-9 _\-'.]+$/;
13
13
  const ISSUE_KEY_PATTERN = /^[A-Z][A-Z0-9]+-\d+$/;
@@ -60,12 +60,14 @@ export async function pingJira(baseUrl, projectKey, auth) {
60
60
  * @param label - If set, adds a label filter.
61
61
  * @returns The JQL query string.
62
62
  */
63
- export function buildJql(projectKey, status, sprint, label) {
63
+ export function buildJql(projectKey, status, sprint, label, excludeHitl) {
64
64
  const parts = [`project="${projectKey}"`];
65
65
  if (sprint)
66
66
  parts.push('sprint in openSprints()');
67
67
  if (label)
68
68
  parts.push(`labels = "${label}"`);
69
+ if (excludeHitl)
70
+ parts.push('labels != "clancy:hitl"');
69
71
  parts.push(`assignee=currentUser()`);
70
72
  parts.push(`status="${status}"`);
71
73
  return parts.join(' AND ') + ' ORDER BY priority ASC';
@@ -113,7 +115,24 @@ export function extractAdfText(adf) {
113
115
  * @returns The fetched ticket, or `undefined` if no tickets are available.
114
116
  */
115
117
  export async function fetchTicket(baseUrl, auth, projectKey, status, sprint, label) {
116
- const jql = buildJql(projectKey, status, sprint, label);
118
+ const results = await fetchTickets(baseUrl, auth, projectKey, status, sprint, label, false, 1);
119
+ return results[0];
120
+ }
121
+ /**
122
+ * Fetch multiple candidate tickets from Jira.
123
+ *
124
+ * @param baseUrl - The Jira Cloud base URL.
125
+ * @param auth - The Base64-encoded Basic auth string.
126
+ * @param projectKey - The Jira project key.
127
+ * @param status - The JQL status to filter by.
128
+ * @param sprint - Optional sprint filter.
129
+ * @param label - Optional label filter.
130
+ * @param excludeHitl - If `true`, excludes tickets with the `clancy:hitl` label.
131
+ * @param limit - Maximum number of results to return (default: 5).
132
+ * @returns Array of fetched tickets (may be empty).
133
+ */
134
+ export async function fetchTickets(baseUrl, auth, projectKey, status, sprint, label, excludeHitl, limit = 5) {
135
+ const jql = buildJql(projectKey, status, sprint, label, excludeHitl);
117
136
  let response;
118
137
  try {
119
138
  response = await fetch(`${baseUrl}/rest/api/3/search/jql`, {
@@ -124,7 +143,7 @@ export async function fetchTicket(baseUrl, auth, projectKey, status, sprint, lab
124
143
  },
125
144
  body: JSON.stringify({
126
145
  jql,
127
- maxResults: 1,
146
+ maxResults: limit,
128
147
  fields: [
129
148
  'summary',
130
149
  'description',
@@ -137,11 +156,11 @@ export async function fetchTicket(baseUrl, auth, projectKey, status, sprint, lab
137
156
  }
138
157
  catch (err) {
139
158
  console.warn(`⚠ Jira API request failed: ${err instanceof Error ? err.message : String(err)}`);
140
- return undefined;
159
+ return [];
141
160
  }
142
161
  if (!response.ok) {
143
162
  console.warn(`⚠ Jira API returned HTTP ${response.status}`);
144
- return undefined;
163
+ return [];
145
164
  }
146
165
  let json;
147
166
  try {
@@ -149,38 +168,78 @@ export async function fetchTicket(baseUrl, auth, projectKey, status, sprint, lab
149
168
  }
150
169
  catch {
151
170
  console.warn('⚠ Jira API returned invalid JSON');
152
- return undefined;
171
+ return [];
153
172
  }
154
173
  const parsed = jiraSearchResponseSchema.safeParse(json);
155
174
  if (!parsed.success) {
156
175
  console.warn(`⚠ Unexpected Jira response shape: ${parsed.error.message}`);
157
- return undefined;
176
+ return [];
177
+ }
178
+ return parsed.data.issues.map((issue) => {
179
+ const fields = issue.fields;
180
+ // Extract blockers
181
+ const blockers = (fields.issuelinks ?? [])
182
+ .filter((link) => link.type?.name === 'Blocks' && link.inwardIssue?.key)
183
+ .map((link) => link.inwardIssue?.key)
184
+ .filter((key) => Boolean(key));
185
+ // Extract epic (next-gen parent OR classic customfield)
186
+ const epicKey = fields.parent?.key ?? fields.customfield_10014 ?? undefined;
187
+ return {
188
+ key: issue.key,
189
+ title: fields.summary,
190
+ description: extractAdfText(fields.description),
191
+ provider: 'jira',
192
+ epicKey,
193
+ blockers,
194
+ };
195
+ });
196
+ }
197
+ /**
198
+ * Check whether a Jira issue is blocked by unresolved blockers.
199
+ *
200
+ * Fetches the issue's links and checks for inward "Blocks" relationships
201
+ * where the blocking issue's statusCategory is not "done".
202
+ *
203
+ * @param baseUrl - The Jira Cloud base URL.
204
+ * @param auth - The Base64-encoded Basic auth string.
205
+ * @param key - The Jira issue key (e.g., `'PROJ-123'`).
206
+ * @returns `true` if any blocker is unresolved, `false` otherwise.
207
+ */
208
+ export async function fetchBlockerStatus(baseUrl, auth, key) {
209
+ if (!ISSUE_KEY_PATTERN.test(key))
210
+ return false;
211
+ try {
212
+ const response = await fetch(`${baseUrl}/rest/api/3/issue/${key}?fields=issuelinks`, { headers: jiraHeaders(auth) });
213
+ if (!response.ok)
214
+ return false;
215
+ const json = await response.json();
216
+ const parsed = jiraIssueLinksResponseSchema.safeParse(json);
217
+ if (!parsed.success)
218
+ return false;
219
+ const links = parsed.data.fields?.issuelinks ?? [];
220
+ // Check for inward "Blocks" links with unresolved status
221
+ return links.some((link) => {
222
+ if (link.type?.name !== 'Blocks')
223
+ return false;
224
+ if (!link.inwardIssue?.key)
225
+ return false;
226
+ const categoryKey = link.inwardIssue.fields?.status?.statusCategory?.key;
227
+ // If status info is missing, assume not blocked
228
+ if (!categoryKey)
229
+ return false;
230
+ return categoryKey !== 'done';
231
+ });
232
+ }
233
+ catch {
234
+ return false;
158
235
  }
159
- if (!parsed.data.issues.length)
160
- return undefined;
161
- const issue = parsed.data.issues[0];
162
- const fields = issue.fields;
163
- // Extract blockers
164
- const blockers = (fields.issuelinks ?? [])
165
- .filter((link) => link.type?.name === 'Blocks' && link.inwardIssue?.key)
166
- .map((link) => link.inwardIssue?.key)
167
- .filter((key) => Boolean(key));
168
- // Extract epic (next-gen parent OR classic customfield)
169
- const epicKey = fields.parent?.key ?? fields.customfield_10014 ?? undefined;
170
- return {
171
- key: issue.key,
172
- title: fields.summary,
173
- description: extractAdfText(fields.description),
174
- provider: 'jira',
175
- epicKey,
176
- blockers,
177
- };
178
236
  }
179
237
  /**
180
- * Fetch the children status of a Jira epic.
238
+ * Fetch the children status of a Jira epic (dual-mode).
181
239
  *
182
- * Returns the total number of children and how many are incomplete
183
- * (statusCategory != 'done'). Used to determine if an epic is complete.
240
+ * Tries the `Epic: {key}` text convention first (children with "Epic: PROJ-100"
241
+ * in their description). If no results, falls back to the native `parent = {key}`
242
+ * JQL query for backward compatibility with pre-v0.6.0 children.
184
243
  *
185
244
  * @param baseUrl - The Jira Cloud base URL.
186
245
  * @param auth - The Base64-encoded Basic auth string.
@@ -191,46 +250,60 @@ export async function fetchChildrenStatus(baseUrl, auth, parentKey) {
191
250
  if (!ISSUE_KEY_PATTERN.test(parentKey))
192
251
  return undefined;
193
252
  try {
194
- // Fetch all children
195
- const totalResponse = await fetch(`${baseUrl}/rest/api/3/search/jql`, {
196
- method: 'POST',
197
- headers: {
198
- ...jiraHeaders(auth),
199
- 'Content-Type': 'application/json',
200
- },
201
- body: JSON.stringify({
202
- jql: `parent = ${parentKey}`,
203
- maxResults: 0,
204
- }),
205
- });
206
- if (!totalResponse.ok)
207
- return undefined;
208
- const totalJson = (await totalResponse.json());
209
- const total = totalJson.total ?? 0;
210
- if (total === 0)
211
- return { total: 0, incomplete: 0 };
212
- // Fetch incomplete children
213
- const incompleteResponse = await fetch(`${baseUrl}/rest/api/3/search/jql`, {
214
- method: 'POST',
215
- headers: {
216
- ...jiraHeaders(auth),
217
- 'Content-Type': 'application/json',
218
- },
219
- body: JSON.stringify({
220
- jql: `parent = ${parentKey} AND statusCategory != "done"`,
221
- maxResults: 0,
222
- }),
223
- });
224
- if (!incompleteResponse.ok)
225
- return undefined;
226
- const incompleteJson = (await incompleteResponse.json());
227
- const incomplete = incompleteJson.total ?? 0;
228
- return { total, incomplete };
253
+ // Mode 1: Try Epic: text convention (scoped to project to avoid cross-project matches)
254
+ const projectPrefix = parentKey.split('-')[0];
255
+ const epicTextResult = await fetchChildrenByJql(baseUrl, auth, `project = "${projectPrefix}" AND description ~ "Epic: ${parentKey}"`);
256
+ if (epicTextResult && epicTextResult.total > 0)
257
+ return epicTextResult;
258
+ // Mode 2: Fall back to native parent API
259
+ return await fetchChildrenByJql(baseUrl, auth, `parent = ${parentKey}`);
229
260
  }
230
261
  catch {
231
262
  return undefined;
232
263
  }
233
264
  }
265
+ /**
266
+ * Fetch children status using a JQL query (total and incomplete counts).
267
+ *
268
+ * @param baseUrl - The Jira Cloud base URL.
269
+ * @param auth - The Base64-encoded Basic auth string.
270
+ * @param jql - The JQL query to find children.
271
+ * @returns The children status, or `undefined` on failure.
272
+ */
273
+ async function fetchChildrenByJql(baseUrl, auth, jql) {
274
+ // Fetch total count
275
+ const totalResponse = await fetch(`${baseUrl}/rest/api/3/search/jql`, {
276
+ method: 'POST',
277
+ headers: {
278
+ ...jiraHeaders(auth),
279
+ 'Content-Type': 'application/json',
280
+ },
281
+ body: JSON.stringify({ jql, maxResults: 0 }),
282
+ });
283
+ if (!totalResponse.ok)
284
+ return undefined;
285
+ const totalJson = (await totalResponse.json());
286
+ const total = totalJson.total ?? 0;
287
+ if (total === 0)
288
+ return { total: 0, incomplete: 0 };
289
+ // Fetch incomplete count
290
+ const incompleteResponse = await fetch(`${baseUrl}/rest/api/3/search/jql`, {
291
+ method: 'POST',
292
+ headers: {
293
+ ...jiraHeaders(auth),
294
+ 'Content-Type': 'application/json',
295
+ },
296
+ body: JSON.stringify({
297
+ jql: `${jql} AND statusCategory != "done"`,
298
+ maxResults: 0,
299
+ }),
300
+ });
301
+ if (!incompleteResponse.ok)
302
+ return undefined;
303
+ const incompleteJson = (await incompleteResponse.json());
304
+ const incomplete = incompleteJson.total ?? 0;
305
+ return { total, incomplete };
306
+ }
234
307
  /**
235
308
  * Look up a Jira transition ID by status name.
236
309
  *
@@ -1 +1 @@
1
- {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../../../src/scripts/board/jira/jira.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../../../src/scripts/board/jira/jira.ts"],"names":[],"mappings":"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"}
@@ -50,23 +50,50 @@ export declare function fetchIssue(env: LinearEnv): Promise<(Ticket & {
50
50
  issueId: string;
51
51
  parentIdentifier?: string;
52
52
  }) | undefined>;
53
+ /** Linear ticket with issue ID and optional parent info. */
54
+ export type LinearTicket = Ticket & {
55
+ issueId: string;
56
+ parentIdentifier?: string;
57
+ };
58
+ /**
59
+ * Fetch multiple candidate issues from Linear.
60
+ *
61
+ * @param env - The Linear environment variables.
62
+ * @param excludeHitl - If `true`, excludes issues with the `clancy:hitl` label.
63
+ * @param limit - Maximum number of results to return (default: 5).
64
+ * @returns Array of fetched tickets (may be empty).
65
+ */
66
+ export declare function fetchIssues(env: LinearEnv, excludeHitl?: boolean, limit?: number): Promise<LinearTicket[]>;
67
+ /**
68
+ * Check whether a Linear issue is blocked by unresolved blockers.
69
+ *
70
+ * Queries the issue's relations for `blockedBy` type relationships and checks
71
+ * if any blocking issues have an unresolved state (not "completed" or "canceled").
72
+ *
73
+ * @param apiKey - The Linear personal API key.
74
+ * @param issueId - The Linear issue UUID.
75
+ * @returns `true` if any blocker is unresolved, `false` otherwise.
76
+ */
77
+ export declare function fetchBlockerStatus(apiKey: string, issueId: string): Promise<boolean>;
53
78
  /** Result of checking children status for a parent issue. */
54
79
  export type ChildrenStatus = {
55
80
  total: number;
56
81
  incomplete: number;
57
82
  };
58
83
  /**
59
- * Fetch the children status of a Linear parent issue.
84
+ * Fetch the children status of a Linear parent issue (dual-mode).
60
85
  *
61
- * Queries the parent's children and counts total vs incomplete
62
- * (state.type not in ["completed", "canceled"]). Used to determine
63
- * if all children are done.
86
+ * Tries the `Epic: {identifier}` text convention first (searches for issues
87
+ * with "Epic: {parentIdentifier}" in their description). If no results, falls
88
+ * back to the native `children` API for backward compatibility.
64
89
  *
65
90
  * @param apiKey - The Linear personal API key.
66
91
  * @param parentId - The Linear parent issue UUID.
92
+ * @param parentIdentifier - The Linear parent identifier (e.g., `'ENG-42'`).
93
+ * Required for Epic: text convention search. Falls back to native API only if not provided.
67
94
  * @returns The children status, or `undefined` on failure.
68
95
  */
69
- export declare function fetchChildrenStatus(apiKey: string, parentId: string): Promise<ChildrenStatus | undefined>;
96
+ export declare function fetchChildrenStatus(apiKey: string, parentId: string, parentIdentifier?: string): Promise<ChildrenStatus | undefined>;
70
97
  /**
71
98
  * Look up a Linear workflow state ID by name and team.
72
99
  *
@@ -1 +1 @@
1
- {"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/linear/linear.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK/C,KAAK,SAAS,GAAG;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CACrD,CAAC,MAAM,GAAG;IACR,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC,GACF,SAAS,CACZ,CA0DA;AAED,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAqCrC;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuB7B;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAelB"}
1
+ {"version":3,"file":"linear.d.ts","sourceRoot":"","sources":["../../../../src/scripts/board/linear/linear.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAK/C,KAAK,SAAS,GAAG;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC1C;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CACrD,CAAC,MAAM,GAAG;IACR,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC,GACF,SAAS,CACZ,CAGA;AAED,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,SAAS,EACd,WAAW,CAAC,EAAE,OAAO,EACrB,KAAK,SAAI,GACR,OAAO,CAAC,YAAY,EAAE,CAAC,CA8EzB;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CA8BlB;AAED,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAiBrC;AAuFD;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuB7B;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAelB"}
@@ -7,7 +7,7 @@
7
7
  * Important: Linear personal API keys do NOT use "Bearer" prefix.
8
8
  * Only OAuth tokens use "Bearer". This is intentional per Linear docs.
9
9
  */
10
- import { linearIssueUpdateResponseSchema, linearIssuesResponseSchema, linearViewerResponseSchema, linearWorkflowStatesResponseSchema, } from '../../../schemas/linear.js';
10
+ import { linearIssueRelationsResponseSchema, linearIssueSearchResponseSchema, linearIssueUpdateResponseSchema, linearIssuesResponseSchema, linearViewerResponseSchema, linearWorkflowStatesResponseSchema, } from '../../../schemas/linear.js';
11
11
  const SAFE_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
12
12
  const LINEAR_API_URL = 'https://api.linear.app/graphql';
13
13
  /**
@@ -111,19 +111,40 @@ export async function pingLinear(apiKey) {
111
111
  * @returns The fetched ticket with optional parent info, or `undefined` if none available.
112
112
  */
113
113
  export async function fetchIssue(env) {
114
+ const results = await fetchIssues(env, false, 1);
115
+ return results[0];
116
+ }
117
+ /**
118
+ * Fetch multiple candidate issues from Linear.
119
+ *
120
+ * @param env - The Linear environment variables.
121
+ * @param excludeHitl - If `true`, excludes issues with the `clancy:hitl` label.
122
+ * @param limit - Maximum number of results to return (default: 5).
123
+ * @returns Array of fetched tickets (may be empty).
124
+ */
125
+ export async function fetchIssues(env, excludeHitl, limit = 5) {
114
126
  const label = env.CLANCY_LABEL?.trim();
115
127
  const hasLabel = Boolean(label);
116
128
  const labelFilter = hasLabel ? 'labels: { name: { eq: $label } }' : '';
129
+ // Build variable declarations for the query
130
+ const varDecls = [
131
+ '$teamId: String!',
132
+ ...(hasLabel ? ['$label: String!'] : []),
133
+ ];
134
+ // Build filter parts
135
+ const filterParts = [
136
+ 'state: { type: { eq: "unstarted" } }',
137
+ 'team: { id: { eq: $teamId } }',
138
+ labelFilter,
139
+ ].filter(Boolean);
117
140
  const query = `
118
- query($teamId: String!${hasLabel ? ', $label: String!' : ''}) {
141
+ query(${varDecls.join(', ')}) {
119
142
  viewer {
120
143
  assignedIssues(
121
144
  filter: {
122
- state: { type: { eq: "unstarted" } }
123
- team: { id: { eq: $teamId } }
124
- ${labelFilter}
145
+ ${filterParts.join('\n ')}
125
146
  }
126
- first: 1
147
+ first: ${excludeHitl ? limit * 3 : limit}
127
148
  orderBy: priority
128
149
  ) {
129
150
  nodes {
@@ -132,6 +153,7 @@ export async function fetchIssue(env) {
132
153
  title
133
154
  description
134
155
  parent { identifier title }
156
+ labels { nodes { name } }
135
157
  }
136
158
  }
137
159
  }
@@ -146,33 +168,129 @@ export async function fetchIssue(env) {
146
168
  const parsed = linearIssuesResponseSchema.safeParse(raw);
147
169
  if (!parsed.success) {
148
170
  console.warn(`⚠ Unexpected Linear response shape: ${parsed.error.message}`);
149
- return undefined;
171
+ return [];
150
172
  }
151
- const nodes = parsed.data.data?.viewer?.assignedIssues?.nodes;
173
+ let nodes = parsed.data.data?.viewer?.assignedIssues?.nodes;
152
174
  if (!nodes?.length)
153
- return undefined;
154
- const issue = nodes[0];
155
- return {
175
+ return [];
176
+ // HITL/AFK filtering: exclude issues with clancy:hitl label (using parsed schema data)
177
+ if (excludeHitl) {
178
+ nodes = nodes.filter((n) => !n.labels?.nodes?.some((l) => l.name === 'clancy:hitl'));
179
+ }
180
+ // Trim to requested limit after filtering
181
+ nodes = nodes.slice(0, limit);
182
+ return nodes.map((issue) => ({
156
183
  key: issue.identifier,
157
184
  title: issue.title,
158
185
  description: issue.description ?? '',
159
186
  provider: 'linear',
160
187
  issueId: issue.id,
161
188
  parentIdentifier: issue.parent?.identifier,
162
- };
189
+ }));
163
190
  }
164
191
  /**
165
- * Fetch the children status of a Linear parent issue.
192
+ * Check whether a Linear issue is blocked by unresolved blockers.
193
+ *
194
+ * Queries the issue's relations for `blockedBy` type relationships and checks
195
+ * if any blocking issues have an unresolved state (not "completed" or "canceled").
196
+ *
197
+ * @param apiKey - The Linear personal API key.
198
+ * @param issueId - The Linear issue UUID.
199
+ * @returns `true` if any blocker is unresolved, `false` otherwise.
200
+ */
201
+ export async function fetchBlockerStatus(apiKey, issueId) {
202
+ const query = `
203
+ query($issueId: String!) {
204
+ issue(id: $issueId) {
205
+ relations {
206
+ nodes {
207
+ type
208
+ relatedIssue {
209
+ state { type }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+ `;
216
+ const raw = await linearGraphql(apiKey, query, { issueId });
217
+ const parsed = linearIssueRelationsResponseSchema.safeParse(raw);
218
+ if (!parsed.success)
219
+ return false;
220
+ const relations = parsed.data.data?.issue?.relations?.nodes ?? [];
221
+ const doneTypes = new Set(['completed', 'canceled']);
222
+ return relations.some((rel) => {
223
+ if (rel.type !== 'blockedBy')
224
+ return false;
225
+ const stateType = rel.relatedIssue?.state?.type;
226
+ if (!stateType)
227
+ return false;
228
+ return !doneTypes.has(stateType);
229
+ });
230
+ }
231
+ /**
232
+ * Fetch the children status of a Linear parent issue (dual-mode).
233
+ *
234
+ * Tries the `Epic: {identifier}` text convention first (searches for issues
235
+ * with "Epic: {parentIdentifier}" in their description). If no results, falls
236
+ * back to the native `children` API for backward compatibility.
166
237
  *
167
- * Queries the parent's children and counts total vs incomplete
168
- * (state.type not in ["completed", "canceled"]). Used to determine
169
- * if all children are done.
238
+ * @param apiKey - The Linear personal API key.
239
+ * @param parentId - The Linear parent issue UUID.
240
+ * @param parentIdentifier - The Linear parent identifier (e.g., `'ENG-42'`).
241
+ * Required for Epic: text convention search. Falls back to native API only if not provided.
242
+ * @returns The children status, or `undefined` on failure.
243
+ */
244
+ export async function fetchChildrenStatus(apiKey, parentId, parentIdentifier) {
245
+ try {
246
+ // Mode 1: Try Epic: text convention (only if identifier is available)
247
+ if (parentIdentifier) {
248
+ const epicTextResult = await fetchChildrenByDescription(apiKey, `Epic: ${parentIdentifier}`);
249
+ if (epicTextResult && epicTextResult.total > 0)
250
+ return epicTextResult;
251
+ }
252
+ // Mode 2: Fall back to native children API
253
+ return await fetchChildrenByNativeApi(apiKey, parentId);
254
+ }
255
+ catch {
256
+ return undefined;
257
+ }
258
+ }
259
+ /**
260
+ * Fetch children status by searching for a description substring.
261
+ *
262
+ * @param apiKey - The Linear personal API key.
263
+ * @param descriptionRef - The description substring to search for.
264
+ * @returns The children status, or `undefined` on failure.
265
+ */
266
+ async function fetchChildrenByDescription(apiKey, descriptionRef) {
267
+ const query = `
268
+ query($filter: String!) {
269
+ issueSearch(query: $filter) {
270
+ nodes {
271
+ state { type }
272
+ }
273
+ }
274
+ }
275
+ `;
276
+ const raw = await linearGraphql(apiKey, query, { filter: descriptionRef });
277
+ const parsed = linearIssueSearchResponseSchema.safeParse(raw);
278
+ if (!parsed.success)
279
+ return undefined;
280
+ const nodes = parsed.data.data?.issueSearch?.nodes ?? [];
281
+ const total = nodes.length;
282
+ const doneTypes = new Set(['completed', 'canceled']);
283
+ const incomplete = nodes.filter((n) => !n.state?.type || !doneTypes.has(n.state.type)).length;
284
+ return { total, incomplete };
285
+ }
286
+ /**
287
+ * Fetch children status using the native parent-child API.
170
288
  *
171
289
  * @param apiKey - The Linear personal API key.
172
290
  * @param parentId - The Linear parent issue UUID.
173
291
  * @returns The children status, or `undefined` on failure.
174
292
  */
175
- export async function fetchChildrenStatus(apiKey, parentId) {
293
+ async function fetchChildrenByNativeApi(apiKey, parentId) {
176
294
  const query = `
177
295
  query($issueId: String!) {
178
296
  issue(id: $issueId) {