forge-cc 0.1.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.
- package/.forge.json +5 -0
- package/AGENTS.md +42 -0
- package/README.md +283 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +148 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +2 -0
- package/dist/config/loader.js +44 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +57 -0
- package/dist/config/schema.js +15 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/gates/index.d.ts +11 -0
- package/dist/gates/index.js +106 -0
- package/dist/gates/index.js.map +1 -0
- package/dist/gates/lint-gate.d.ts +2 -0
- package/dist/gates/lint-gate.js +66 -0
- package/dist/gates/lint-gate.js.map +1 -0
- package/dist/gates/prd-gate.d.ts +7 -0
- package/dist/gates/prd-gate.js +193 -0
- package/dist/gates/prd-gate.js.map +1 -0
- package/dist/gates/runtime-gate.d.ts +5 -0
- package/dist/gates/runtime-gate.js +99 -0
- package/dist/gates/runtime-gate.js.map +1 -0
- package/dist/gates/tests-gate.d.ts +2 -0
- package/dist/gates/tests-gate.js +116 -0
- package/dist/gates/tests-gate.js.map +1 -0
- package/dist/gates/types-gate.d.ts +2 -0
- package/dist/gates/types-gate.js +59 -0
- package/dist/gates/types-gate.js.map +1 -0
- package/dist/gates/visual-gate.d.ts +6 -0
- package/dist/gates/visual-gate.js +118 -0
- package/dist/gates/visual-gate.js.map +1 -0
- package/dist/go/auto-chain.d.ts +107 -0
- package/dist/go/auto-chain.js +303 -0
- package/dist/go/auto-chain.js.map +1 -0
- package/dist/go/executor.d.ts +130 -0
- package/dist/go/executor.js +409 -0
- package/dist/go/executor.js.map +1 -0
- package/dist/go/finalize.d.ts +58 -0
- package/dist/go/finalize.js +200 -0
- package/dist/go/finalize.js.map +1 -0
- package/dist/go/linear-sync.d.ts +75 -0
- package/dist/go/linear-sync.js +239 -0
- package/dist/go/linear-sync.js.map +1 -0
- package/dist/go/verify-loop.d.ts +47 -0
- package/dist/go/verify-loop.js +172 -0
- package/dist/go/verify-loop.js.map +1 -0
- package/dist/hooks/pre-commit.d.ts +5 -0
- package/dist/hooks/pre-commit.js +69 -0
- package/dist/hooks/pre-commit.js.map +1 -0
- package/dist/linear/client.d.ts +108 -0
- package/dist/linear/client.js +388 -0
- package/dist/linear/client.js.map +1 -0
- package/dist/linear/issues.d.ts +20 -0
- package/dist/linear/issues.js +39 -0
- package/dist/linear/issues.js.map +1 -0
- package/dist/linear/milestones.d.ts +11 -0
- package/dist/linear/milestones.js +32 -0
- package/dist/linear/milestones.js.map +1 -0
- package/dist/linear/projects.d.ts +16 -0
- package/dist/linear/projects.js +50 -0
- package/dist/linear/projects.js.map +1 -0
- package/dist/reporter/human.d.ts +2 -0
- package/dist/reporter/human.js +63 -0
- package/dist/reporter/human.js.map +1 -0
- package/dist/reporter/json.d.ts +2 -0
- package/dist/reporter/json.js +4 -0
- package/dist/reporter/json.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +109 -0
- package/dist/server.js.map +1 -0
- package/dist/spec/generator.d.ts +14 -0
- package/dist/spec/generator.js +206 -0
- package/dist/spec/generator.js.map +1 -0
- package/dist/spec/interview.d.ts +104 -0
- package/dist/spec/interview.js +342 -0
- package/dist/spec/interview.js.map +1 -0
- package/dist/spec/linear-sync.d.ts +48 -0
- package/dist/spec/linear-sync.js +125 -0
- package/dist/spec/linear-sync.js.map +1 -0
- package/dist/spec/scanner.d.ts +45 -0
- package/dist/spec/scanner.js +473 -0
- package/dist/spec/scanner.js.map +1 -0
- package/dist/spec/templates.d.ts +345 -0
- package/dist/spec/templates.js +86 -0
- package/dist/spec/templates.js.map +1 -0
- package/dist/state/reader.d.ts +29 -0
- package/dist/state/reader.js +116 -0
- package/dist/state/reader.js.map +1 -0
- package/dist/state/writer.d.ts +60 -0
- package/dist/state/writer.js +222 -0
- package/dist/state/writer.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/browser.d.ts +10 -0
- package/dist/utils/browser.js +89 -0
- package/dist/utils/browser.js.map +1 -0
- package/hooks/pre-commit-verify.js +103 -0
- package/package.json +68 -0
- package/skills/README.md +33 -0
- package/skills/forge-go.md +332 -0
- package/skills/forge-spec.md +251 -0
- package/skills/forge-triage.md +133 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed wrapper around the Linear GraphQL API.
|
|
3
|
+
* Used by lifecycle modules (projects.ts, milestones.ts, issues.ts)
|
|
4
|
+
* and the execution engine for programmatic Linear management.
|
|
5
|
+
*/
|
|
6
|
+
const LINEAR_API_URL = "https://api.linear.app/graphql";
|
|
7
|
+
const MAX_RETRIES = 3;
|
|
8
|
+
const INITIAL_BACKOFF_MS = 500;
|
|
9
|
+
const REQUEST_TIMEOUT_MS = 30_000; // 30 seconds per request
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Error
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
export class LinearClientError extends Error {
|
|
14
|
+
statusCode;
|
|
15
|
+
errors;
|
|
16
|
+
constructor(message, statusCode, errors) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.statusCode = statusCode;
|
|
19
|
+
this.errors = errors;
|
|
20
|
+
this.name = "LinearClientError";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Client
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
export class LinearClient {
|
|
27
|
+
apiKey;
|
|
28
|
+
constructor(apiKey) {
|
|
29
|
+
const key = apiKey ?? process.env.LINEAR_API_KEY;
|
|
30
|
+
if (!key) {
|
|
31
|
+
throw new LinearClientError("Linear API key not found. Set the LINEAR_API_KEY environment variable or pass it to the constructor.");
|
|
32
|
+
}
|
|
33
|
+
this.apiKey = key;
|
|
34
|
+
}
|
|
35
|
+
// -------------------------------------------------------------------------
|
|
36
|
+
// Projects
|
|
37
|
+
// -------------------------------------------------------------------------
|
|
38
|
+
async listProjects(opts) {
|
|
39
|
+
const filter = {};
|
|
40
|
+
if (opts?.query) {
|
|
41
|
+
filter.name = { containsIgnoreCase: opts.query };
|
|
42
|
+
}
|
|
43
|
+
if (opts?.state) {
|
|
44
|
+
filter.state = { eq: opts.state };
|
|
45
|
+
}
|
|
46
|
+
const hasFilter = Object.keys(filter).length > 0;
|
|
47
|
+
const filterVar = hasFilter ? ", $filter: ProjectFilter" : "";
|
|
48
|
+
const filterArg = hasFilter ? ", filter: $filter" : "";
|
|
49
|
+
const query = `
|
|
50
|
+
query ListProjects($after: String${filterVar}) {
|
|
51
|
+
projects(first: 50, after: $after${filterArg}) {
|
|
52
|
+
pageInfo { hasNextPage endCursor }
|
|
53
|
+
nodes {
|
|
54
|
+
id name description state url
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
return this.paginate(query, "projects", {
|
|
60
|
+
...(hasFilter ? { filter } : {}),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async createProject(input) {
|
|
64
|
+
const mutation = `
|
|
65
|
+
mutation CreateProject($input: ProjectCreateInput!) {
|
|
66
|
+
projectCreate(input: $input) {
|
|
67
|
+
success
|
|
68
|
+
project { id name description state url }
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
const variables = {
|
|
73
|
+
input: {
|
|
74
|
+
name: input.name,
|
|
75
|
+
...(input.description != null && { description: input.description }),
|
|
76
|
+
teamIds: input.teamIds,
|
|
77
|
+
...(input.state != null && { state: input.state }),
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
const data = await this.request(mutation, variables);
|
|
81
|
+
const result = data.projectCreate;
|
|
82
|
+
if (!result?.success) {
|
|
83
|
+
throw new LinearClientError("Failed to create project");
|
|
84
|
+
}
|
|
85
|
+
return result.project;
|
|
86
|
+
}
|
|
87
|
+
async updateProject(id, input) {
|
|
88
|
+
const mutation = `
|
|
89
|
+
mutation UpdateProject($id: String!, $input: ProjectUpdateInput!) {
|
|
90
|
+
projectUpdate(id: $id, input: $input) {
|
|
91
|
+
success
|
|
92
|
+
project { id name description state url }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
const data = await this.request(mutation, { id, input });
|
|
97
|
+
const result = data.projectUpdate;
|
|
98
|
+
if (!result?.success) {
|
|
99
|
+
throw new LinearClientError(`Failed to update project ${id}`);
|
|
100
|
+
}
|
|
101
|
+
return result.project;
|
|
102
|
+
}
|
|
103
|
+
// -------------------------------------------------------------------------
|
|
104
|
+
// Milestones (Project Milestones)
|
|
105
|
+
// -------------------------------------------------------------------------
|
|
106
|
+
async listMilestones(projectId) {
|
|
107
|
+
const query = `
|
|
108
|
+
query ListMilestones($projectId: String!, $after: String) {
|
|
109
|
+
project(id: $projectId) {
|
|
110
|
+
projectMilestones(first: 50, after: $after) {
|
|
111
|
+
pageInfo { hasNextPage endCursor }
|
|
112
|
+
nodes {
|
|
113
|
+
id name description progress sortOrder
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
// Custom pagination because the nodes are nested under project
|
|
120
|
+
const all = [];
|
|
121
|
+
let after = null;
|
|
122
|
+
for (;;) {
|
|
123
|
+
const data = await this.request(query, { projectId, after });
|
|
124
|
+
const connection = data.project?.projectMilestones;
|
|
125
|
+
if (!connection)
|
|
126
|
+
break;
|
|
127
|
+
all.push(...connection.nodes);
|
|
128
|
+
if (connection.pageInfo.hasNextPage) {
|
|
129
|
+
after = connection.pageInfo.endCursor;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return all;
|
|
136
|
+
}
|
|
137
|
+
async createMilestone(input) {
|
|
138
|
+
const mutation = `
|
|
139
|
+
mutation CreateMilestone($input: ProjectMilestoneCreateInput!) {
|
|
140
|
+
projectMilestoneCreate(input: $input) {
|
|
141
|
+
success
|
|
142
|
+
projectMilestone { id name description progress sortOrder }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
`;
|
|
146
|
+
const variables = {
|
|
147
|
+
input: {
|
|
148
|
+
projectId: input.projectId,
|
|
149
|
+
name: input.name,
|
|
150
|
+
...(input.description != null && { description: input.description }),
|
|
151
|
+
...(input.targetDate != null && { targetDate: input.targetDate }),
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
const data = await this.request(mutation, variables);
|
|
155
|
+
const result = data.projectMilestoneCreate;
|
|
156
|
+
if (!result?.success) {
|
|
157
|
+
throw new LinearClientError("Failed to create milestone");
|
|
158
|
+
}
|
|
159
|
+
return result.projectMilestone;
|
|
160
|
+
}
|
|
161
|
+
// -------------------------------------------------------------------------
|
|
162
|
+
// Issues
|
|
163
|
+
// -------------------------------------------------------------------------
|
|
164
|
+
async listIssues(opts) {
|
|
165
|
+
const filter = {};
|
|
166
|
+
if (opts?.projectId) {
|
|
167
|
+
filter.project = { id: { eq: opts.projectId } };
|
|
168
|
+
}
|
|
169
|
+
if (opts?.milestoneId) {
|
|
170
|
+
filter.projectMilestone = { id: { eq: opts.milestoneId } };
|
|
171
|
+
}
|
|
172
|
+
if (opts?.state) {
|
|
173
|
+
filter.state = { name: { eqIgnoreCase: opts.state } };
|
|
174
|
+
}
|
|
175
|
+
const hasFilter = Object.keys(filter).length > 0;
|
|
176
|
+
const filterVar = hasFilter ? ", $filter: IssueFilter" : "";
|
|
177
|
+
const filterArg = hasFilter ? ", filter: $filter" : "";
|
|
178
|
+
const query = `
|
|
179
|
+
query ListIssues($after: String${filterVar}) {
|
|
180
|
+
issues(first: 50, after: $after${filterArg}) {
|
|
181
|
+
pageInfo { hasNextPage endCursor }
|
|
182
|
+
nodes {
|
|
183
|
+
id identifier title description url
|
|
184
|
+
state { name }
|
|
185
|
+
project { id }
|
|
186
|
+
projectMilestone { id }
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
`;
|
|
191
|
+
const raw = await this.paginate(query, "issues", hasFilter ? { filter } : {});
|
|
192
|
+
return raw.map((node) => this.mapIssue(node));
|
|
193
|
+
}
|
|
194
|
+
async createIssue(input) {
|
|
195
|
+
const mutation = `
|
|
196
|
+
mutation CreateIssue($input: IssueCreateInput!) {
|
|
197
|
+
issueCreate(input: $input) {
|
|
198
|
+
success
|
|
199
|
+
issue {
|
|
200
|
+
id identifier title description url
|
|
201
|
+
state { name }
|
|
202
|
+
project { id }
|
|
203
|
+
projectMilestone { id }
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
const issueInput = {
|
|
209
|
+
title: input.title,
|
|
210
|
+
teamId: input.teamId,
|
|
211
|
+
...(input.description != null && { description: input.description }),
|
|
212
|
+
...(input.projectId != null && { projectId: input.projectId }),
|
|
213
|
+
...(input.milestoneId != null && {
|
|
214
|
+
projectMilestoneId: input.milestoneId,
|
|
215
|
+
}),
|
|
216
|
+
...(input.priority != null && { priority: input.priority }),
|
|
217
|
+
};
|
|
218
|
+
// state is a name string; Linear expects stateId. The caller should resolve
|
|
219
|
+
// this upstream, but if provided we pass it as-is and let Linear resolve.
|
|
220
|
+
if (input.state != null) {
|
|
221
|
+
issueInput.stateId = input.state;
|
|
222
|
+
}
|
|
223
|
+
const data = await this.request(mutation, { input: issueInput });
|
|
224
|
+
const result = data.issueCreate;
|
|
225
|
+
if (!result?.success) {
|
|
226
|
+
throw new LinearClientError("Failed to create issue");
|
|
227
|
+
}
|
|
228
|
+
return this.mapIssue(result.issue);
|
|
229
|
+
}
|
|
230
|
+
async updateIssue(id, input) {
|
|
231
|
+
const mutation = `
|
|
232
|
+
mutation UpdateIssue($id: String!, $input: IssueUpdateInput!) {
|
|
233
|
+
issueUpdate(id: $id, input: $input) {
|
|
234
|
+
success
|
|
235
|
+
issue {
|
|
236
|
+
id identifier title description url
|
|
237
|
+
state { name }
|
|
238
|
+
project { id }
|
|
239
|
+
projectMilestone { id }
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
`;
|
|
244
|
+
const issueInput = {};
|
|
245
|
+
if (input.title != null)
|
|
246
|
+
issueInput.title = input.title;
|
|
247
|
+
if (input.description != null)
|
|
248
|
+
issueInput.description = input.description;
|
|
249
|
+
if (input.state != null)
|
|
250
|
+
issueInput.stateId = input.state;
|
|
251
|
+
if (input.milestoneId != null)
|
|
252
|
+
issueInput.projectMilestoneId = input.milestoneId;
|
|
253
|
+
if (input.priority != null)
|
|
254
|
+
issueInput.priority = input.priority;
|
|
255
|
+
const data = await this.request(mutation, { id, input: issueInput });
|
|
256
|
+
const result = data.issueUpdate;
|
|
257
|
+
if (!result?.success) {
|
|
258
|
+
throw new LinearClientError(`Failed to update issue ${id}`);
|
|
259
|
+
}
|
|
260
|
+
return this.mapIssue(result.issue);
|
|
261
|
+
}
|
|
262
|
+
async createComment(issueId, body) {
|
|
263
|
+
const mutation = `
|
|
264
|
+
mutation CreateComment($input: CommentCreateInput!) {
|
|
265
|
+
commentCreate(input: $input) {
|
|
266
|
+
success
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
`;
|
|
270
|
+
const data = await this.request(mutation, {
|
|
271
|
+
input: { issueId, body },
|
|
272
|
+
});
|
|
273
|
+
if (!data.commentCreate?.success) {
|
|
274
|
+
throw new LinearClientError(`Failed to create comment on issue ${issueId}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// -------------------------------------------------------------------------
|
|
278
|
+
// Teams
|
|
279
|
+
// -------------------------------------------------------------------------
|
|
280
|
+
async listTeams() {
|
|
281
|
+
const query = `
|
|
282
|
+
query ListTeams($after: String) {
|
|
283
|
+
teams(first: 50, after: $after) {
|
|
284
|
+
pageInfo { hasNextPage endCursor }
|
|
285
|
+
nodes { id name key }
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
`;
|
|
289
|
+
return this.paginate(query, "teams", {});
|
|
290
|
+
}
|
|
291
|
+
// -------------------------------------------------------------------------
|
|
292
|
+
// Internals
|
|
293
|
+
// -------------------------------------------------------------------------
|
|
294
|
+
/**
|
|
295
|
+
* Execute a GraphQL request against the Linear API with retry + backoff.
|
|
296
|
+
*/
|
|
297
|
+
async request(query, variables = {}) {
|
|
298
|
+
let lastError;
|
|
299
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
300
|
+
if (attempt > 0) {
|
|
301
|
+
const delay = INITIAL_BACKOFF_MS * 2 ** (attempt - 1);
|
|
302
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
303
|
+
}
|
|
304
|
+
let res;
|
|
305
|
+
try {
|
|
306
|
+
const controller = new AbortController();
|
|
307
|
+
const timeoutId = globalThis.setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
308
|
+
try {
|
|
309
|
+
res = await fetch(LINEAR_API_URL, {
|
|
310
|
+
method: "POST",
|
|
311
|
+
headers: {
|
|
312
|
+
"Content-Type": "application/json",
|
|
313
|
+
Authorization: this.apiKey,
|
|
314
|
+
},
|
|
315
|
+
body: JSON.stringify({ query, variables }),
|
|
316
|
+
signal: controller.signal,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
finally {
|
|
320
|
+
clearTimeout(timeoutId);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
if (err instanceof DOMException && err.name === "AbortError" || (err instanceof Error && err.name === "AbortError")) {
|
|
325
|
+
lastError = new LinearClientError(`Linear API request timed out after ${REQUEST_TIMEOUT_MS / 1000}s`);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
lastError =
|
|
329
|
+
err instanceof Error ? err : new Error(String(err));
|
|
330
|
+
}
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
if (res.status === 429 || res.status >= 500) {
|
|
334
|
+
lastError = new LinearClientError(`Linear API returned ${res.status}`, res.status);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (!res.ok) {
|
|
338
|
+
const body = await res.text().catch(() => "");
|
|
339
|
+
throw new LinearClientError(`Linear API error ${res.status}: ${body}`, res.status);
|
|
340
|
+
}
|
|
341
|
+
const json = (await res.json());
|
|
342
|
+
if (json.errors?.length) {
|
|
343
|
+
throw new LinearClientError(`GraphQL errors: ${json.errors.map((e) => e.message).join("; ")}`, undefined, json.errors);
|
|
344
|
+
}
|
|
345
|
+
if (!json.data) {
|
|
346
|
+
throw new LinearClientError("No data in Linear API response");
|
|
347
|
+
}
|
|
348
|
+
return json.data;
|
|
349
|
+
}
|
|
350
|
+
throw lastError ?? new LinearClientError("Request failed after retries");
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Auto-paginate a connection query. The query MUST accept `$after: String`
|
|
354
|
+
* and the root field must return `{ pageInfo { hasNextPage endCursor } nodes { ... } }`.
|
|
355
|
+
*/
|
|
356
|
+
async paginate(query, rootField, variables) {
|
|
357
|
+
const all = [];
|
|
358
|
+
let after = null;
|
|
359
|
+
for (;;) {
|
|
360
|
+
const data = await this.request(query, { ...variables, after });
|
|
361
|
+
const connection = data[rootField];
|
|
362
|
+
if (!connection)
|
|
363
|
+
break;
|
|
364
|
+
all.push(...connection.nodes);
|
|
365
|
+
if (connection.pageInfo.hasNextPage) {
|
|
366
|
+
after = connection.pageInfo.endCursor;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return all;
|
|
373
|
+
}
|
|
374
|
+
/** Normalize a raw issue node from GraphQL into our flat LinearIssue shape. */
|
|
375
|
+
mapIssue(node) {
|
|
376
|
+
return {
|
|
377
|
+
id: node.id,
|
|
378
|
+
identifier: node.identifier,
|
|
379
|
+
title: node.title,
|
|
380
|
+
description: node.description ?? undefined,
|
|
381
|
+
state: node.state?.name ?? "Unknown",
|
|
382
|
+
projectId: node.project?.id ?? undefined,
|
|
383
|
+
milestoneId: node.projectMilestone?.id ?? undefined,
|
|
384
|
+
url: node.url,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/linear/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LinearClient, type LinearIssue } from "./client.js";
|
|
2
|
+
/** Valid issue states */
|
|
3
|
+
export declare const ISSUE_STATES: readonly ["Backlog", "Todo", "In Progress", "In Review", "Done", "Canceled"];
|
|
4
|
+
export type IssueState = (typeof ISSUE_STATES)[number];
|
|
5
|
+
/** Create an issue under a project milestone */
|
|
6
|
+
export declare function createMilestoneIssue(client: LinearClient, input: {
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
teamId: string;
|
|
10
|
+
projectId: string;
|
|
11
|
+
milestoneId: string;
|
|
12
|
+
priority?: number;
|
|
13
|
+
}): Promise<LinearIssue>;
|
|
14
|
+
/** Transition all issues in a milestone to a target state */
|
|
15
|
+
export declare function transitionMilestoneIssues(client: LinearClient, projectId: string, milestoneId: string, targetState: string): Promise<{
|
|
16
|
+
updated: number;
|
|
17
|
+
issues: LinearIssue[];
|
|
18
|
+
}>;
|
|
19
|
+
/** Add a progress comment to an issue */
|
|
20
|
+
export declare function addProgressComment(client: LinearClient, issueId: string, message: string): Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Valid issue states */
|
|
2
|
+
export const ISSUE_STATES = [
|
|
3
|
+
"Backlog",
|
|
4
|
+
"Todo",
|
|
5
|
+
"In Progress",
|
|
6
|
+
"In Review",
|
|
7
|
+
"Done",
|
|
8
|
+
"Canceled",
|
|
9
|
+
];
|
|
10
|
+
/** Create an issue under a project milestone */
|
|
11
|
+
export async function createMilestoneIssue(client, input) {
|
|
12
|
+
return client.createIssue({
|
|
13
|
+
title: input.title,
|
|
14
|
+
description: input.description,
|
|
15
|
+
teamId: input.teamId,
|
|
16
|
+
projectId: input.projectId,
|
|
17
|
+
milestoneId: input.milestoneId,
|
|
18
|
+
priority: input.priority,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** Transition all issues in a milestone to a target state */
|
|
22
|
+
export async function transitionMilestoneIssues(client, projectId, milestoneId, targetState) {
|
|
23
|
+
const issues = await client.listIssues({ projectId, milestoneId });
|
|
24
|
+
const updatedIssues = [];
|
|
25
|
+
for (const issue of issues) {
|
|
26
|
+
if (issue.state !== targetState) {
|
|
27
|
+
const updated = await client.updateIssue(issue.id, {
|
|
28
|
+
state: targetState,
|
|
29
|
+
});
|
|
30
|
+
updatedIssues.push(updated);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { updated: updatedIssues.length, issues: updatedIssues };
|
|
34
|
+
}
|
|
35
|
+
/** Add a progress comment to an issue */
|
|
36
|
+
export async function addProgressComment(client, issueId, message) {
|
|
37
|
+
await client.createComment(issueId, message);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/linear/issues.ts"],"names":[],"mappings":"AAEA,yBAAyB;AACzB,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,SAAS;IACT,MAAM;IACN,aAAa;IACb,WAAW;IACX,MAAM;IACN,UAAU;CACF,CAAC;AAGX,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoB,EACpB,KAOC;IAED,OAAO,MAAM,CAAC,WAAW,CAAC;QACxB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC,CAAC;AACL,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAoB,EACpB,SAAiB,EACjB,WAAmB,EACnB,WAAmB;IAEnB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;IAEnE,MAAM,aAAa,GAAkB,EAAE,CAAC;IACxC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE;gBACjD,KAAK,EAAE,WAAW;aACnB,CAAC,CAAC;YACH,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAClE,CAAC;AAED,yCAAyC;AACzC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAoB,EACpB,OAAe,EACf,OAAe;IAEf,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LinearClient, type LinearMilestone } from "./client.js";
|
|
2
|
+
/** Create a milestone under a project */
|
|
3
|
+
export declare function createProjectMilestone(client: LinearClient, projectId: string, name: string, description?: string, targetDate?: string): Promise<LinearMilestone>;
|
|
4
|
+
/** Get milestone progress: total and completed issue counts */
|
|
5
|
+
export declare function getMilestoneProgress(client: LinearClient, projectId: string, milestoneName: string): Promise<{
|
|
6
|
+
milestone: LinearMilestone;
|
|
7
|
+
totalIssues: number;
|
|
8
|
+
completedIssues: number;
|
|
9
|
+
}>;
|
|
10
|
+
/** Find a milestone by name within a project */
|
|
11
|
+
export declare function findMilestoneByName(client: LinearClient, projectId: string, name: string): Promise<LinearMilestone | null>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Create a milestone under a project */
|
|
2
|
+
export async function createProjectMilestone(client, projectId, name, description, targetDate) {
|
|
3
|
+
return client.createMilestone({
|
|
4
|
+
projectId,
|
|
5
|
+
name,
|
|
6
|
+
description,
|
|
7
|
+
targetDate,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
/** Get milestone progress: total and completed issue counts */
|
|
11
|
+
export async function getMilestoneProgress(client, projectId, milestoneName) {
|
|
12
|
+
const milestone = await findMilestoneByName(client, projectId, milestoneName);
|
|
13
|
+
if (!milestone) {
|
|
14
|
+
throw new Error(`Milestone not found: "${milestoneName}" in project ${projectId}`);
|
|
15
|
+
}
|
|
16
|
+
const issues = await client.listIssues({
|
|
17
|
+
projectId,
|
|
18
|
+
milestoneId: milestone.id,
|
|
19
|
+
});
|
|
20
|
+
const completedIssues = issues.filter((i) => i.state === "Done" || i.state === "Canceled").length;
|
|
21
|
+
return {
|
|
22
|
+
milestone,
|
|
23
|
+
totalIssues: issues.length,
|
|
24
|
+
completedIssues,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** Find a milestone by name within a project */
|
|
28
|
+
export async function findMilestoneByName(client, projectId, name) {
|
|
29
|
+
const milestones = await client.listMilestones(projectId);
|
|
30
|
+
return milestones.find((m) => m.name === name) ?? null;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=milestones.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"milestones.js","sourceRoot":"","sources":["../../src/linear/milestones.ts"],"names":[],"mappings":"AAEA,yCAAyC;AACzC,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAoB,EACpB,SAAiB,EACjB,IAAY,EACZ,WAAoB,EACpB,UAAmB;IAEnB,OAAO,MAAM,CAAC,eAAe,CAAC;QAC5B,SAAS;QACT,IAAI;QACJ,WAAW;QACX,UAAU;KACX,CAAC,CAAC;AACL,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoB,EACpB,SAAiB,EACjB,aAAqB;IAMrB,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;IAC9E,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,yBAAyB,aAAa,gBAAgB,SAAS,EAAE,CAClE,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC;QACrC,SAAS;QACT,WAAW,EAAE,SAAS,CAAC,EAAE;KAC1B,CAAC,CAAC;IACH,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,KAAK,UAAU,CACpD,CAAC,MAAM,CAAC;IAET,OAAO;QACL,SAAS;QACT,WAAW,EAAE,MAAM,CAAC,MAAM;QAC1B,eAAe;KAChB,CAAC;AACJ,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAoB,EACpB,SAAiB,EACjB,IAAY;IAEZ,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAC1D,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { LinearClient, type LinearProject } from "./client.js";
|
|
2
|
+
/** Valid project states in forward-only order */
|
|
3
|
+
export declare const PROJECT_STATES: readonly ["Backlog", "Planned", "In Progress", "In Review", "Done"];
|
|
4
|
+
export type ProjectState = (typeof PROJECT_STATES)[number];
|
|
5
|
+
/**
|
|
6
|
+
* Validate that a project state transition is forward-only.
|
|
7
|
+
* Backlog -> Planned -> In Progress -> In Review -> Done.
|
|
8
|
+
* Same-state transitions are not valid (no-op).
|
|
9
|
+
*/
|
|
10
|
+
export declare function isValidTransition(from: string, to: string): boolean;
|
|
11
|
+
/** Create a new project in Backlog state (used during triage) */
|
|
12
|
+
export declare function createTriageProject(client: LinearClient, name: string, description: string, teamIds: string[]): Promise<LinearProject>;
|
|
13
|
+
/** Transition a project to a target state with forward-only validation */
|
|
14
|
+
export declare function transitionProject(client: LinearClient, projectId: string, targetState: string): Promise<LinearProject>;
|
|
15
|
+
/** Find an existing project by exact name (for dedup during triage) */
|
|
16
|
+
export declare function findProjectByName(client: LinearClient, name: string): Promise<LinearProject | null>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Valid project states in forward-only order */
|
|
2
|
+
export const PROJECT_STATES = [
|
|
3
|
+
"Backlog",
|
|
4
|
+
"Planned",
|
|
5
|
+
"In Progress",
|
|
6
|
+
"In Review",
|
|
7
|
+
"Done",
|
|
8
|
+
];
|
|
9
|
+
/** State index map for transition validation */
|
|
10
|
+
const stateIndex = new Map(PROJECT_STATES.map((s, i) => [s, i]));
|
|
11
|
+
/**
|
|
12
|
+
* Validate that a project state transition is forward-only.
|
|
13
|
+
* Backlog -> Planned -> In Progress -> In Review -> Done.
|
|
14
|
+
* Same-state transitions are not valid (no-op).
|
|
15
|
+
*/
|
|
16
|
+
export function isValidTransition(from, to) {
|
|
17
|
+
const fromIdx = stateIndex.get(from);
|
|
18
|
+
const toIdx = stateIndex.get(to);
|
|
19
|
+
if (fromIdx === undefined || toIdx === undefined)
|
|
20
|
+
return false;
|
|
21
|
+
return toIdx > fromIdx;
|
|
22
|
+
}
|
|
23
|
+
/** Create a new project in Backlog state (used during triage) */
|
|
24
|
+
export async function createTriageProject(client, name, description, teamIds) {
|
|
25
|
+
return client.createProject({
|
|
26
|
+
name,
|
|
27
|
+
description,
|
|
28
|
+
teamIds,
|
|
29
|
+
state: "Backlog",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Transition a project to a target state with forward-only validation */
|
|
33
|
+
export async function transitionProject(client, projectId, targetState) {
|
|
34
|
+
// Fetch current project to validate transition
|
|
35
|
+
const projects = await client.listProjects();
|
|
36
|
+
const project = projects.find((p) => p.id === projectId);
|
|
37
|
+
if (!project) {
|
|
38
|
+
throw new Error(`Project not found: ${projectId}`);
|
|
39
|
+
}
|
|
40
|
+
if (!isValidTransition(project.state, targetState)) {
|
|
41
|
+
throw new Error(`Invalid project transition: ${project.state} -> ${targetState}`);
|
|
42
|
+
}
|
|
43
|
+
return client.updateProject(projectId, { state: targetState });
|
|
44
|
+
}
|
|
45
|
+
/** Find an existing project by exact name (for dedup during triage) */
|
|
46
|
+
export async function findProjectByName(client, name) {
|
|
47
|
+
const projects = await client.listProjects({ query: name });
|
|
48
|
+
return projects.find((p) => p.name === name) ?? null;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/linear/projects.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,SAAS;IACT,aAAa;IACb,WAAW;IACX,MAAM;CACE,CAAC;AAGX,gDAAgD;AAChD,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CACrC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,EAAU;IACxD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC/D,OAAO,KAAK,GAAG,OAAO,CAAC;AACzB,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAoB,EACpB,IAAY,EACZ,WAAmB,EACnB,OAAiB;IAEjB,OAAO,MAAM,CAAC,aAAa,CAAC;QAC1B,IAAI;QACJ,WAAW;QACX,OAAO;QACP,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAoB,EACpB,SAAiB,EACjB,WAAmB;IAEnB,+CAA+C;IAC/C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;IACzD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,+BAA+B,OAAO,CAAC,KAAK,OAAO,WAAW,EAAE,CACjE,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAoB,EACpB,IAAY;IAEZ,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export function formatHumanReport(result) {
|
|
2
|
+
const lines = [];
|
|
3
|
+
// Header
|
|
4
|
+
const status = result.passed ? "PASSED" : "FAILED";
|
|
5
|
+
lines.push("## Verification Report");
|
|
6
|
+
lines.push(`**Status:** ${status}`);
|
|
7
|
+
lines.push(`**Iterations:** ${result.iteration}/${result.maxIterations}`);
|
|
8
|
+
const totalMs = result.gates.reduce((sum, g) => sum + g.duration_ms, 0);
|
|
9
|
+
lines.push(`**Duration:** ${formatDuration(totalMs)}`);
|
|
10
|
+
lines.push("");
|
|
11
|
+
// Gate results
|
|
12
|
+
lines.push("### Gates");
|
|
13
|
+
for (const gate of result.gates) {
|
|
14
|
+
const icon = gate.passed ? "[x]" : "[ ]";
|
|
15
|
+
const statusText = gate.passed ? "PASS" : "FAIL";
|
|
16
|
+
const dur = formatDuration(gate.duration_ms);
|
|
17
|
+
let suffix = "";
|
|
18
|
+
if (!gate.passed && gate.errors.length > 0) {
|
|
19
|
+
suffix = ` — ${gate.errors.length} error${gate.errors.length === 1 ? "" : "s"}`;
|
|
20
|
+
}
|
|
21
|
+
else if (gate.passed && gate.warnings.length > 0) {
|
|
22
|
+
suffix = ` — ${gate.warnings.length} warning${gate.warnings.length === 1 ? "" : "s"}`;
|
|
23
|
+
}
|
|
24
|
+
lines.push(`- ${icon} ${gate.gate}: ${statusText} (${dur})${suffix}`);
|
|
25
|
+
}
|
|
26
|
+
lines.push("");
|
|
27
|
+
// Errors section
|
|
28
|
+
const gatesWithErrors = result.gates.filter((g) => g.errors.length > 0);
|
|
29
|
+
if (gatesWithErrors.length > 0) {
|
|
30
|
+
lines.push("### Errors");
|
|
31
|
+
for (const gate of gatesWithErrors) {
|
|
32
|
+
lines.push(`#### ${gate.gate}`);
|
|
33
|
+
for (const err of gate.errors) {
|
|
34
|
+
const loc = err.file
|
|
35
|
+
? `${err.file}${err.line ? `:${err.line}` : ""}`
|
|
36
|
+
: "";
|
|
37
|
+
const prefix = loc ? `${loc}: ` : "";
|
|
38
|
+
lines.push(`- ${prefix}${err.message}`);
|
|
39
|
+
if (err.remediation) {
|
|
40
|
+
lines.push(` > Fix: ${err.remediation}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
lines.push("");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Warnings section
|
|
47
|
+
const gatesWithWarnings = result.gates.filter((g) => g.warnings.length > 0);
|
|
48
|
+
if (gatesWithWarnings.length > 0) {
|
|
49
|
+
lines.push("### Warnings");
|
|
50
|
+
for (const gate of gatesWithWarnings) {
|
|
51
|
+
lines.push(`#### ${gate.gate}`);
|
|
52
|
+
for (const warning of gate.warnings) {
|
|
53
|
+
lines.push(`- ${warning}`);
|
|
54
|
+
}
|
|
55
|
+
lines.push("");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return lines.join("\n");
|
|
59
|
+
}
|
|
60
|
+
function formatDuration(ms) {
|
|
61
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=human.js.map
|