@cliangdev/flux-plugin 0.2.0 → 0.3.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/README.md +11 -7
- package/agents/coder.md +150 -25
- package/bin/install.cjs +171 -16
- package/commands/breakdown.md +47 -10
- package/commands/dashboard.md +29 -0
- package/commands/flux.md +92 -12
- package/commands/implement.md +166 -17
- package/commands/linear.md +6 -5
- package/commands/prd.md +996 -82
- package/manifest.json +2 -1
- package/package.json +9 -11
- package/skills/flux-orchestrator/SKILL.md +11 -3
- package/skills/prd-writer/SKILL.md +761 -0
- package/skills/ux-ui-design/SKILL.md +346 -0
- package/skills/ux-ui-design/references/design-tokens.md +359 -0
- package/src/__tests__/version.test.ts +37 -0
- package/src/adapters/local/.gitkeep +0 -0
- package/src/dashboard/__tests__/api.test.ts +211 -0
- package/src/dashboard/browser.ts +35 -0
- package/src/dashboard/public/app.js +869 -0
- package/src/dashboard/public/index.html +90 -0
- package/src/dashboard/public/styles.css +807 -0
- package/src/dashboard/public/vendor/highlight.css +10 -0
- package/src/dashboard/public/vendor/highlight.min.js +8422 -0
- package/src/dashboard/public/vendor/marked.min.js +2210 -0
- package/src/dashboard/server.ts +296 -0
- package/src/dashboard/watchers.ts +83 -0
- package/src/server/__tests__/config.test.ts +163 -0
- package/src/server/adapters/__tests__/a-client-linear.test.ts +197 -0
- package/src/server/adapters/__tests__/adapter-factory.test.ts +230 -0
- package/src/server/adapters/__tests__/dependency-ops.test.ts +429 -0
- package/src/server/adapters/__tests__/document-ops.test.ts +306 -0
- package/src/server/adapters/__tests__/linear-adapter.test.ts +91 -0
- package/src/server/adapters/__tests__/linear-config.test.ts +425 -0
- package/src/server/adapters/__tests__/linear-criteria-parser.test.ts +287 -0
- package/src/server/adapters/__tests__/linear-description-test.ts +238 -0
- package/src/server/adapters/__tests__/linear-epic-crud.test.ts +496 -0
- package/src/server/adapters/__tests__/linear-mappers-description.test.ts +276 -0
- package/src/server/adapters/__tests__/linear-mappers-epic.test.ts +294 -0
- package/src/server/adapters/__tests__/linear-mappers-prd.test.ts +300 -0
- package/src/server/adapters/__tests__/linear-mappers-task.test.ts +197 -0
- package/src/server/adapters/__tests__/linear-prd-crud.test.ts +620 -0
- package/src/server/adapters/__tests__/linear-stats.test.ts +450 -0
- package/src/server/adapters/__tests__/linear-task-crud.test.ts +534 -0
- package/src/server/adapters/__tests__/linear-types.test.ts +243 -0
- package/src/server/adapters/__tests__/status-ops.test.ts +441 -0
- package/src/server/adapters/factory.ts +90 -0
- package/src/server/adapters/index.ts +9 -0
- package/src/server/adapters/linear/adapter.ts +1141 -0
- package/src/server/adapters/linear/client.ts +169 -0
- package/src/server/adapters/linear/config.ts +152 -0
- package/src/server/adapters/linear/helpers/criteria-parser.ts +197 -0
- package/src/server/adapters/linear/helpers/index.ts +7 -0
- package/src/server/adapters/linear/index.ts +16 -0
- package/src/server/adapters/linear/mappers/description.ts +136 -0
- package/src/server/adapters/linear/mappers/epic.ts +81 -0
- package/src/server/adapters/linear/mappers/index.ts +27 -0
- package/src/server/adapters/linear/mappers/prd.ts +178 -0
- package/src/server/adapters/linear/mappers/task.ts +82 -0
- package/src/server/adapters/linear/types.ts +264 -0
- package/src/server/adapters/local-adapter.ts +1009 -0
- package/src/server/adapters/types.ts +293 -0
- package/src/server/config.ts +73 -0
- package/src/server/db/__tests__/queries.test.ts +473 -0
- package/src/server/db/ids.ts +17 -0
- package/src/server/db/index.ts +69 -0
- package/src/server/db/queries.ts +142 -0
- package/src/server/db/refs.ts +60 -0
- package/src/server/db/schema.ts +97 -0
- package/src/server/db/sqlite.ts +10 -0
- package/src/server/index.ts +81 -0
- package/src/server/tools/__tests__/crud.test.ts +411 -0
- package/src/server/tools/__tests__/get-version.test.ts +27 -0
- package/src/server/tools/__tests__/mcp-interface.test.ts +479 -0
- package/src/server/tools/__tests__/query.test.ts +405 -0
- package/src/server/tools/__tests__/z-configure-linear.test.ts +511 -0
- package/src/server/tools/__tests__/z-get-linear-url.test.ts +108 -0
- package/src/server/tools/configure-linear.ts +373 -0
- package/src/server/tools/create-epic.ts +44 -0
- package/src/server/tools/create-prd.ts +40 -0
- package/src/server/tools/create-task.ts +47 -0
- package/src/server/tools/criteria.ts +50 -0
- package/src/server/tools/delete-entity.ts +76 -0
- package/src/server/tools/dependencies.ts +55 -0
- package/src/server/tools/get-entity.ts +240 -0
- package/src/server/tools/get-linear-url.ts +28 -0
- package/src/server/tools/get-stats.ts +52 -0
- package/src/server/tools/get-version.ts +20 -0
- package/src/server/tools/index.ts +158 -0
- package/src/server/tools/init-project.ts +108 -0
- package/src/server/tools/query-entities.ts +167 -0
- package/src/server/tools/render-status.ts +219 -0
- package/src/server/tools/update-entity.ts +140 -0
- package/src/server/tools/update-status.ts +166 -0
- package/src/server/utils/__tests__/mcp-response.test.ts +331 -0
- package/src/server/utils/logger.ts +9 -0
- package/src/server/utils/mcp-response.ts +254 -0
- package/src/server/utils/status-transitions.ts +160 -0
- package/src/status-line/__tests__/status-line.test.ts +215 -0
- package/src/status-line/index.ts +147 -0
- package/src/utils/__tests__/chalk-import.test.ts +32 -0
- package/src/utils/__tests__/display.test.ts +97 -0
- package/src/utils/__tests__/status-renderer.test.ts +310 -0
- package/src/utils/display.ts +62 -0
- package/src/utils/status-renderer.ts +214 -0
- package/src/version.ts +5 -0
- package/dist/server/index.js +0 -87063
- package/skills/prd-template/SKILL.md +0 -242
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
isPrdIssue,
|
|
4
|
+
toFluxPrdStatus,
|
|
5
|
+
toFluxPrdStatusFromIssue,
|
|
6
|
+
toLinearPrdIssueState,
|
|
7
|
+
toLinearProjectState,
|
|
8
|
+
toPrd,
|
|
9
|
+
toPrdFromIssue,
|
|
10
|
+
} from "../linear/mappers/prd.js";
|
|
11
|
+
import type { LinearIssue, LinearProject } from "../linear/types.js";
|
|
12
|
+
import type { PrdStatus } from "../types.js";
|
|
13
|
+
|
|
14
|
+
describe("PRD Mapper", () => {
|
|
15
|
+
// ===========================================================================
|
|
16
|
+
// Issue-based PRD mapping (new approach)
|
|
17
|
+
// ===========================================================================
|
|
18
|
+
|
|
19
|
+
describe("toPrdFromIssue", () => {
|
|
20
|
+
test("transforms Linear Issue to Flux Prd", () => {
|
|
21
|
+
const issue: LinearIssue = {
|
|
22
|
+
id: "issue_abc123",
|
|
23
|
+
identifier: "ENG-42",
|
|
24
|
+
title: "User Authentication",
|
|
25
|
+
description: "Implement user login and registration",
|
|
26
|
+
state: { id: "state_1", name: "In Progress", type: "started" },
|
|
27
|
+
priority: 3,
|
|
28
|
+
labels: [{ id: "label_1", name: "prd" }],
|
|
29
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
30
|
+
updatedAt: "2024-01-02T00:00:00Z",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const prd = toPrdFromIssue(issue, "proj_xyz");
|
|
34
|
+
|
|
35
|
+
expect(prd.id).toBe("issue_abc123");
|
|
36
|
+
expect(prd.projectId).toBe("proj_xyz");
|
|
37
|
+
expect(prd.ref).toBe("ENG-42");
|
|
38
|
+
expect(prd.title).toBe("User Authentication");
|
|
39
|
+
expect(prd.description).toBe("Implement user login and registration");
|
|
40
|
+
expect(prd.status).toBe("APPROVED"); // In Progress -> APPROVED
|
|
41
|
+
expect(prd.createdAt).toBe("2024-01-01T00:00:00Z");
|
|
42
|
+
expect(prd.updatedAt).toBe("2024-01-02T00:00:00Z");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("handles issue without description", () => {
|
|
46
|
+
const issue: LinearIssue = {
|
|
47
|
+
id: "issue_xyz",
|
|
48
|
+
identifier: "ENG-99",
|
|
49
|
+
title: "Test PRD",
|
|
50
|
+
state: { id: "state_1", name: "Backlog", type: "backlog" },
|
|
51
|
+
priority: 3,
|
|
52
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
53
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const prd = toPrdFromIssue(issue, "proj_xyz");
|
|
57
|
+
|
|
58
|
+
expect(prd.title).toBe("Test PRD");
|
|
59
|
+
expect(prd.description).toBeUndefined();
|
|
60
|
+
expect(prd.status).toBe("DRAFT"); // Backlog -> DRAFT
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("isPrdIssue", () => {
|
|
65
|
+
test("returns true when issue has prd label", () => {
|
|
66
|
+
const issue: LinearIssue = {
|
|
67
|
+
id: "issue_1",
|
|
68
|
+
identifier: "ENG-1",
|
|
69
|
+
title: "Test",
|
|
70
|
+
state: { id: "state_1", name: "Backlog", type: "backlog" },
|
|
71
|
+
priority: 3,
|
|
72
|
+
labels: [{ id: "label_1", name: "prd" }],
|
|
73
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
74
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
expect(isPrdIssue(issue, "prd")).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("returns false when issue has no prd label", () => {
|
|
81
|
+
const issue: LinearIssue = {
|
|
82
|
+
id: "issue_1",
|
|
83
|
+
identifier: "ENG-1",
|
|
84
|
+
title: "Test",
|
|
85
|
+
state: { id: "state_1", name: "Backlog", type: "backlog" },
|
|
86
|
+
priority: 3,
|
|
87
|
+
labels: [{ id: "label_1", name: "epic" }],
|
|
88
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
89
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
expect(isPrdIssue(issue, "prd")).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("returns false when issue has no labels", () => {
|
|
96
|
+
const issue: LinearIssue = {
|
|
97
|
+
id: "issue_1",
|
|
98
|
+
identifier: "ENG-1",
|
|
99
|
+
title: "Test",
|
|
100
|
+
state: { id: "state_1", name: "Backlog", type: "backlog" },
|
|
101
|
+
priority: 3,
|
|
102
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
103
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
expect(isPrdIssue(issue, "prd")).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("uses custom label name", () => {
|
|
110
|
+
const issue: LinearIssue = {
|
|
111
|
+
id: "issue_1",
|
|
112
|
+
identifier: "ENG-1",
|
|
113
|
+
title: "Test",
|
|
114
|
+
state: { id: "state_1", name: "Backlog", type: "backlog" },
|
|
115
|
+
priority: 3,
|
|
116
|
+
labels: [{ id: "label_1", name: "custom-prd" }],
|
|
117
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
118
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
expect(isPrdIssue(issue, "custom-prd")).toBe(true);
|
|
122
|
+
expect(isPrdIssue(issue, "prd")).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe("toFluxPrdStatusFromIssue", () => {
|
|
127
|
+
test("maps Backlog to DRAFT", () => {
|
|
128
|
+
expect(toFluxPrdStatusFromIssue("Backlog")).toBe("DRAFT");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("maps In Progress to APPROVED", () => {
|
|
132
|
+
expect(toFluxPrdStatusFromIssue("In Progress")).toBe("APPROVED");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("maps Done to COMPLETED", () => {
|
|
136
|
+
expect(toFluxPrdStatusFromIssue("Done")).toBe("COMPLETED");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("maps Canceled to ARCHIVED", () => {
|
|
140
|
+
expect(toFluxPrdStatusFromIssue("Canceled")).toBe("ARCHIVED");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("defaults to DRAFT for unknown state", () => {
|
|
144
|
+
expect(toFluxPrdStatusFromIssue("Unknown")).toBe("DRAFT");
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
describe("toLinearPrdIssueState", () => {
|
|
149
|
+
test("maps DRAFT to Backlog", () => {
|
|
150
|
+
expect(toLinearPrdIssueState("DRAFT")).toBe("Backlog");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("maps PENDING_REVIEW to Todo", () => {
|
|
154
|
+
expect(toLinearPrdIssueState("PENDING_REVIEW")).toBe("Todo");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("maps REVIEWED to Todo", () => {
|
|
158
|
+
expect(toLinearPrdIssueState("REVIEWED")).toBe("Todo");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("maps APPROVED to In Progress", () => {
|
|
162
|
+
expect(toLinearPrdIssueState("APPROVED")).toBe("In Progress");
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test("maps BREAKDOWN_READY to In Progress", () => {
|
|
166
|
+
expect(toLinearPrdIssueState("BREAKDOWN_READY")).toBe("In Progress");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("maps COMPLETED to Done", () => {
|
|
170
|
+
expect(toLinearPrdIssueState("COMPLETED")).toBe("Done");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("maps ARCHIVED to Canceled", () => {
|
|
174
|
+
expect(toLinearPrdIssueState("ARCHIVED")).toBe("Canceled");
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// ===========================================================================
|
|
179
|
+
// Project-based PRD mapping (deprecated but kept for backward compatibility)
|
|
180
|
+
// ===========================================================================
|
|
181
|
+
|
|
182
|
+
describe("toPrd (deprecated)", () => {
|
|
183
|
+
test("transforms Linear Project to Flux Prd", () => {
|
|
184
|
+
const project: LinearProject = {
|
|
185
|
+
id: "proj_abc123",
|
|
186
|
+
name: "User Authentication",
|
|
187
|
+
description: "Implement user login and registration",
|
|
188
|
+
state: "started",
|
|
189
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
190
|
+
updatedAt: "2024-01-02T00:00:00Z",
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const prd = toPrd(project, "proj_abc123");
|
|
194
|
+
|
|
195
|
+
expect(prd.id).toBe("proj_abc123");
|
|
196
|
+
expect(prd.projectId).toBe("proj_abc123");
|
|
197
|
+
expect(prd.ref).toBe("proj_abc123");
|
|
198
|
+
expect(prd.title).toBe("User Authentication");
|
|
199
|
+
expect(prd.description).toBe("Implement user login and registration");
|
|
200
|
+
expect(prd.status).toBe("APPROVED"); // started -> APPROVED
|
|
201
|
+
expect(prd.createdAt).toBe("2024-01-01T00:00:00Z");
|
|
202
|
+
expect(prd.updatedAt).toBe("2024-01-02T00:00:00Z");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test("handles project without description", () => {
|
|
206
|
+
const project: LinearProject = {
|
|
207
|
+
id: "proj_xyz",
|
|
208
|
+
name: "Test Project",
|
|
209
|
+
state: "backlog",
|
|
210
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
211
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const prd = toPrd(project, "proj_xyz");
|
|
215
|
+
|
|
216
|
+
expect(prd.title).toBe("Test Project");
|
|
217
|
+
expect(prd.description).toBeUndefined();
|
|
218
|
+
expect(prd.status).toBe("DRAFT"); // backlog -> DRAFT
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test("maps all Linear project states to Flux statuses", () => {
|
|
222
|
+
const states: Array<{ linear: string; flux: PrdStatus }> = [
|
|
223
|
+
{ linear: "backlog", flux: "DRAFT" },
|
|
224
|
+
{ linear: "planned", flux: "PENDING_REVIEW" },
|
|
225
|
+
{ linear: "started", flux: "APPROVED" },
|
|
226
|
+
{ linear: "completed", flux: "COMPLETED" },
|
|
227
|
+
{ linear: "canceled", flux: "ARCHIVED" },
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
for (const { linear, flux } of states) {
|
|
231
|
+
const project: LinearProject = {
|
|
232
|
+
id: "proj_test",
|
|
233
|
+
name: "Test",
|
|
234
|
+
state: linear,
|
|
235
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
236
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const prd = toPrd(project, "proj_test");
|
|
240
|
+
expect(prd.status).toBe(flux);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe("toLinearProjectState (deprecated)", () => {
|
|
246
|
+
test("maps DRAFT to backlog", () => {
|
|
247
|
+
expect(toLinearProjectState("DRAFT")).toBe("backlog");
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test("maps PENDING_REVIEW to planned", () => {
|
|
251
|
+
expect(toLinearProjectState("PENDING_REVIEW")).toBe("planned");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("maps REVIEWED to planned", () => {
|
|
255
|
+
expect(toLinearProjectState("REVIEWED")).toBe("planned");
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
test("maps APPROVED to started", () => {
|
|
259
|
+
expect(toLinearProjectState("APPROVED")).toBe("started");
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("maps BREAKDOWN_READY to started", () => {
|
|
263
|
+
expect(toLinearProjectState("BREAKDOWN_READY")).toBe("started");
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("maps COMPLETED to completed", () => {
|
|
267
|
+
expect(toLinearProjectState("COMPLETED")).toBe("completed");
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("maps ARCHIVED to canceled", () => {
|
|
271
|
+
expect(toLinearProjectState("ARCHIVED")).toBe("canceled");
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe("toFluxPrdStatus (deprecated)", () => {
|
|
276
|
+
test("maps backlog to DRAFT", () => {
|
|
277
|
+
expect(toFluxPrdStatus("backlog")).toBe("DRAFT");
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("maps planned to PENDING_REVIEW", () => {
|
|
281
|
+
expect(toFluxPrdStatus("planned")).toBe("PENDING_REVIEW");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test("maps started to APPROVED", () => {
|
|
285
|
+
expect(toFluxPrdStatus("started")).toBe("APPROVED");
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test("maps completed to COMPLETED", () => {
|
|
289
|
+
expect(toFluxPrdStatus("completed")).toBe("COMPLETED");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("maps canceled to ARCHIVED", () => {
|
|
293
|
+
expect(toFluxPrdStatus("canceled")).toBe("ARCHIVED");
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("defaults to DRAFT for unknown state", () => {
|
|
297
|
+
expect(toFluxPrdStatus("unknown")).toBe("DRAFT");
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
toFluxPriority,
|
|
4
|
+
toFluxTaskStatus,
|
|
5
|
+
toLinearPriority,
|
|
6
|
+
toLinearTaskState,
|
|
7
|
+
toTask,
|
|
8
|
+
} from "../linear/mappers/task.js";
|
|
9
|
+
import type { LinearIssue } from "../linear/types.js";
|
|
10
|
+
|
|
11
|
+
describe("Linear Task Mapper", () => {
|
|
12
|
+
describe("toTask", () => {
|
|
13
|
+
test("transforms Linear Issue to Flux Task with all fields", () => {
|
|
14
|
+
const issue: LinearIssue = {
|
|
15
|
+
id: "issue_123",
|
|
16
|
+
identifier: "ENG-43",
|
|
17
|
+
title: "Implement login API",
|
|
18
|
+
description: "Add authentication endpoint",
|
|
19
|
+
state: {
|
|
20
|
+
id: "state_1",
|
|
21
|
+
name: "In Progress",
|
|
22
|
+
type: "started",
|
|
23
|
+
},
|
|
24
|
+
priority: 2, // HIGH in Flux
|
|
25
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
26
|
+
updatedAt: "2024-01-02T00:00:00Z",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const task = toTask(issue, "epic-123");
|
|
30
|
+
|
|
31
|
+
expect(task.id).toBe("issue_123");
|
|
32
|
+
expect(task.epicId).toBe("epic-123");
|
|
33
|
+
expect(task.ref).toBe("ENG-43");
|
|
34
|
+
expect(task.title).toBe("Implement login API");
|
|
35
|
+
expect(task.description).toBe("Add authentication endpoint");
|
|
36
|
+
expect(task.status).toBe("IN_PROGRESS");
|
|
37
|
+
expect(task.priority).toBe("HIGH");
|
|
38
|
+
expect(task.createdAt).toBe("2024-01-01T00:00:00Z");
|
|
39
|
+
expect(task.updatedAt).toBe("2024-01-02T00:00:00Z");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("handles missing description", () => {
|
|
43
|
+
const issue: LinearIssue = {
|
|
44
|
+
id: "issue_124",
|
|
45
|
+
identifier: "ENG-44",
|
|
46
|
+
title: "Fix bug",
|
|
47
|
+
state: {
|
|
48
|
+
id: "state_2",
|
|
49
|
+
name: "Backlog",
|
|
50
|
+
type: "backlog",
|
|
51
|
+
},
|
|
52
|
+
priority: 4,
|
|
53
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
54
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const task = toTask(issue, "epic-456");
|
|
58
|
+
|
|
59
|
+
expect(task.description).toBeUndefined();
|
|
60
|
+
expect(task.status).toBe("PENDING");
|
|
61
|
+
expect(task.priority).toBe("LOW");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("maps Backlog state to PENDING status", () => {
|
|
65
|
+
const issue: LinearIssue = {
|
|
66
|
+
id: "issue_125",
|
|
67
|
+
identifier: "ENG-45",
|
|
68
|
+
title: "Task in backlog",
|
|
69
|
+
state: {
|
|
70
|
+
id: "state_1",
|
|
71
|
+
name: "Backlog",
|
|
72
|
+
type: "backlog",
|
|
73
|
+
},
|
|
74
|
+
priority: 3,
|
|
75
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
76
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const task = toTask(issue, "epic-789");
|
|
80
|
+
|
|
81
|
+
expect(task.status).toBe("PENDING");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("maps In Progress state to IN_PROGRESS status", () => {
|
|
85
|
+
const issue: LinearIssue = {
|
|
86
|
+
id: "issue_126",
|
|
87
|
+
identifier: "ENG-46",
|
|
88
|
+
title: "Task in progress",
|
|
89
|
+
state: {
|
|
90
|
+
id: "state_2",
|
|
91
|
+
name: "In Progress",
|
|
92
|
+
type: "started",
|
|
93
|
+
},
|
|
94
|
+
priority: 2,
|
|
95
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
96
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const task = toTask(issue, "epic-789");
|
|
100
|
+
|
|
101
|
+
expect(task.status).toBe("IN_PROGRESS");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("maps Done state to COMPLETED status", () => {
|
|
105
|
+
const issue: LinearIssue = {
|
|
106
|
+
id: "issue_127",
|
|
107
|
+
identifier: "ENG-47",
|
|
108
|
+
title: "Task done",
|
|
109
|
+
state: {
|
|
110
|
+
id: "state_3",
|
|
111
|
+
name: "Done",
|
|
112
|
+
type: "completed",
|
|
113
|
+
},
|
|
114
|
+
priority: 3,
|
|
115
|
+
createdAt: "2024-01-01T00:00:00Z",
|
|
116
|
+
updatedAt: "2024-01-01T00:00:00Z",
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const task = toTask(issue, "epic-789");
|
|
120
|
+
|
|
121
|
+
expect(task.status).toBe("COMPLETED");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe("Priority Mapping", () => {
|
|
126
|
+
describe("toLinearPriority", () => {
|
|
127
|
+
test("maps LOW to 4 (no priority)", () => {
|
|
128
|
+
expect(toLinearPriority("LOW")).toBe(4);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("maps MEDIUM to 3", () => {
|
|
132
|
+
expect(toLinearPriority("MEDIUM")).toBe(3);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("maps HIGH to 2", () => {
|
|
136
|
+
expect(toLinearPriority("HIGH")).toBe(2);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe("toFluxPriority", () => {
|
|
141
|
+
test("maps 4 to LOW", () => {
|
|
142
|
+
expect(toFluxPriority(4)).toBe("LOW");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("maps 3 to MEDIUM", () => {
|
|
146
|
+
expect(toFluxPriority(3)).toBe("MEDIUM");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("maps 2 to HIGH", () => {
|
|
150
|
+
expect(toFluxPriority(2)).toBe("HIGH");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("maps 1 (urgent) to HIGH", () => {
|
|
154
|
+
expect(toFluxPriority(1)).toBe("HIGH");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("defaults to LOW for unknown priority", () => {
|
|
158
|
+
expect(toFluxPriority(0)).toBe("LOW");
|
|
159
|
+
expect(toFluxPriority(5)).toBe("LOW");
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
describe("Status Mapping", () => {
|
|
165
|
+
describe("toLinearTaskState", () => {
|
|
166
|
+
test("maps PENDING to Todo", () => {
|
|
167
|
+
expect(toLinearTaskState("PENDING")).toBe("Todo");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("maps IN_PROGRESS to In Progress", () => {
|
|
171
|
+
expect(toLinearTaskState("IN_PROGRESS")).toBe("In Progress");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("maps COMPLETED to Done", () => {
|
|
175
|
+
expect(toLinearTaskState("COMPLETED")).toBe("Done");
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("toFluxTaskStatus", () => {
|
|
180
|
+
test("maps Backlog to PENDING", () => {
|
|
181
|
+
expect(toFluxTaskStatus("Backlog")).toBe("PENDING");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("maps In Progress to IN_PROGRESS", () => {
|
|
185
|
+
expect(toFluxTaskStatus("In Progress")).toBe("IN_PROGRESS");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("maps Done to COMPLETED", () => {
|
|
189
|
+
expect(toFluxTaskStatus("Done")).toBe("COMPLETED");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("defaults to PENDING for unknown state", () => {
|
|
193
|
+
expect(toFluxTaskStatus("Unknown")).toBe("PENDING");
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|