@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,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend Adapter Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the interface for storage backends (local SQLite, SpecFlux API, Linear, Notion).
|
|
5
|
+
* All adapters must implement BackendAdapter to ensure consistent behavior.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Entity Types
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
export type PrdStatus =
|
|
13
|
+
| "DRAFT"
|
|
14
|
+
| "PENDING_REVIEW"
|
|
15
|
+
| "REVIEWED"
|
|
16
|
+
| "APPROVED"
|
|
17
|
+
| "BREAKDOWN_READY"
|
|
18
|
+
| "COMPLETED"
|
|
19
|
+
| "ARCHIVED";
|
|
20
|
+
|
|
21
|
+
export type EpicStatus = "PENDING" | "IN_PROGRESS" | "COMPLETED";
|
|
22
|
+
export type TaskStatus = "PENDING" | "IN_PROGRESS" | "COMPLETED";
|
|
23
|
+
export type Priority = "LOW" | "MEDIUM" | "HIGH";
|
|
24
|
+
|
|
25
|
+
export interface Prd {
|
|
26
|
+
id: string;
|
|
27
|
+
projectId: string;
|
|
28
|
+
ref: string;
|
|
29
|
+
title: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
status: PrdStatus;
|
|
32
|
+
tag?: string;
|
|
33
|
+
folderPath?: string;
|
|
34
|
+
createdAt: string;
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface Epic {
|
|
39
|
+
id: string;
|
|
40
|
+
prdId: string;
|
|
41
|
+
ref: string;
|
|
42
|
+
title: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
status: EpicStatus;
|
|
45
|
+
createdAt: string;
|
|
46
|
+
updatedAt: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface Task {
|
|
50
|
+
id: string;
|
|
51
|
+
epicId: string;
|
|
52
|
+
ref: string;
|
|
53
|
+
title: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
status: TaskStatus;
|
|
56
|
+
priority: Priority;
|
|
57
|
+
createdAt: string;
|
|
58
|
+
updatedAt: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface AcceptanceCriterion {
|
|
62
|
+
id: string;
|
|
63
|
+
parentType: "epic" | "task";
|
|
64
|
+
parentId: string;
|
|
65
|
+
criteria: string;
|
|
66
|
+
isMet: boolean;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface Document {
|
|
71
|
+
prdRef: string;
|
|
72
|
+
filename: string;
|
|
73
|
+
content: string;
|
|
74
|
+
/** For external adapters (Linear/Notion), this is the URL */
|
|
75
|
+
url?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// Input Types (for create/update operations)
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
export interface CreatePrdInput {
|
|
83
|
+
title: string;
|
|
84
|
+
description?: string;
|
|
85
|
+
tag?: string;
|
|
86
|
+
folderPath?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface UpdatePrdInput {
|
|
90
|
+
title?: string;
|
|
91
|
+
description?: string;
|
|
92
|
+
status?: PrdStatus;
|
|
93
|
+
tag?: string;
|
|
94
|
+
folderPath?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface CreateEpicInput {
|
|
98
|
+
prdRef: string;
|
|
99
|
+
title: string;
|
|
100
|
+
description?: string;
|
|
101
|
+
acceptanceCriteria?: string[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface UpdateEpicInput {
|
|
105
|
+
title?: string;
|
|
106
|
+
description?: string;
|
|
107
|
+
status?: EpicStatus;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface CreateTaskInput {
|
|
111
|
+
epicRef: string;
|
|
112
|
+
title: string;
|
|
113
|
+
description?: string;
|
|
114
|
+
priority?: Priority;
|
|
115
|
+
acceptanceCriteria?: string[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface UpdateTaskInput {
|
|
119
|
+
title?: string;
|
|
120
|
+
description?: string;
|
|
121
|
+
status?: TaskStatus;
|
|
122
|
+
priority?: Priority;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface AddCriterionInput {
|
|
126
|
+
parentRef: string;
|
|
127
|
+
criteria: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// =============================================================================
|
|
131
|
+
// Query Types
|
|
132
|
+
// =============================================================================
|
|
133
|
+
|
|
134
|
+
export interface PrdFilters {
|
|
135
|
+
status?: PrdStatus;
|
|
136
|
+
tag?: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface EpicFilters {
|
|
140
|
+
prdRef?: string;
|
|
141
|
+
status?: EpicStatus;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface TaskFilters {
|
|
145
|
+
epicRef?: string;
|
|
146
|
+
status?: TaskStatus;
|
|
147
|
+
priority?: Priority;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface PaginationOptions {
|
|
151
|
+
limit?: number;
|
|
152
|
+
offset?: number;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface PaginatedResult<T> {
|
|
156
|
+
items: T[];
|
|
157
|
+
total: number;
|
|
158
|
+
limit: number;
|
|
159
|
+
offset: number;
|
|
160
|
+
hasMore: boolean;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// =============================================================================
|
|
164
|
+
// Stats Types
|
|
165
|
+
// =============================================================================
|
|
166
|
+
|
|
167
|
+
export interface Stats {
|
|
168
|
+
prds: {
|
|
169
|
+
total: number;
|
|
170
|
+
draft: number;
|
|
171
|
+
pendingReview: number;
|
|
172
|
+
reviewed: number;
|
|
173
|
+
approved: number;
|
|
174
|
+
breakdownReady: number;
|
|
175
|
+
completed: number;
|
|
176
|
+
archived: number;
|
|
177
|
+
};
|
|
178
|
+
epics: {
|
|
179
|
+
total: number;
|
|
180
|
+
pending: number;
|
|
181
|
+
inProgress: number;
|
|
182
|
+
completed: number;
|
|
183
|
+
};
|
|
184
|
+
tasks: {
|
|
185
|
+
total: number;
|
|
186
|
+
pending: number;
|
|
187
|
+
inProgress: number;
|
|
188
|
+
completed: number;
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// =============================================================================
|
|
193
|
+
// Backend Adapter Interface
|
|
194
|
+
// =============================================================================
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* BackendAdapter defines the contract for storage backends.
|
|
198
|
+
*
|
|
199
|
+
* Implementations:
|
|
200
|
+
* - LocalAdapter: SQLite + filesystem (default)
|
|
201
|
+
* - SpecFluxAdapter: SpecFlux REST API (future)
|
|
202
|
+
* - LinearAdapter: Linear API (future)
|
|
203
|
+
* - NotionAdapter: Notion API (future)
|
|
204
|
+
*/
|
|
205
|
+
export interface BackendAdapter {
|
|
206
|
+
// -------------------------------------------------------------------------
|
|
207
|
+
// PRD Operations
|
|
208
|
+
// -------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
createPrd(input: CreatePrdInput): Promise<Prd>;
|
|
211
|
+
updatePrd(ref: string, input: UpdatePrdInput): Promise<Prd>;
|
|
212
|
+
getPrd(ref: string): Promise<Prd | null>;
|
|
213
|
+
listPrds(
|
|
214
|
+
filters?: PrdFilters,
|
|
215
|
+
pagination?: PaginationOptions,
|
|
216
|
+
): Promise<PaginatedResult<Prd>>;
|
|
217
|
+
deletePrd(ref: string): Promise<{ deleted: string; cascade: CascadeResult }>;
|
|
218
|
+
|
|
219
|
+
// -------------------------------------------------------------------------
|
|
220
|
+
// Epic Operations
|
|
221
|
+
// -------------------------------------------------------------------------
|
|
222
|
+
|
|
223
|
+
createEpic(input: CreateEpicInput): Promise<Epic>;
|
|
224
|
+
updateEpic(ref: string, input: UpdateEpicInput): Promise<Epic>;
|
|
225
|
+
getEpic(ref: string): Promise<Epic | null>;
|
|
226
|
+
listEpics(
|
|
227
|
+
filters?: EpicFilters,
|
|
228
|
+
pagination?: PaginationOptions,
|
|
229
|
+
): Promise<PaginatedResult<Epic>>;
|
|
230
|
+
deleteEpic(ref: string): Promise<{ deleted: string; cascade: CascadeResult }>;
|
|
231
|
+
|
|
232
|
+
// -------------------------------------------------------------------------
|
|
233
|
+
// Task Operations
|
|
234
|
+
// -------------------------------------------------------------------------
|
|
235
|
+
|
|
236
|
+
createTask(input: CreateTaskInput): Promise<Task>;
|
|
237
|
+
updateTask(ref: string, input: UpdateTaskInput): Promise<Task>;
|
|
238
|
+
getTask(ref: string): Promise<Task | null>;
|
|
239
|
+
listTasks(
|
|
240
|
+
filters?: TaskFilters,
|
|
241
|
+
pagination?: PaginationOptions,
|
|
242
|
+
): Promise<PaginatedResult<Task>>;
|
|
243
|
+
deleteTask(ref: string): Promise<{ deleted: string; cascade: CascadeResult }>;
|
|
244
|
+
|
|
245
|
+
// -------------------------------------------------------------------------
|
|
246
|
+
// Acceptance Criteria Operations
|
|
247
|
+
// -------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
addCriterion(input: AddCriterionInput): Promise<AcceptanceCriterion>;
|
|
250
|
+
markCriterionMet(criterionId: string): Promise<AcceptanceCriterion>;
|
|
251
|
+
getCriteria(parentRef: string): Promise<AcceptanceCriterion[]>;
|
|
252
|
+
|
|
253
|
+
// -------------------------------------------------------------------------
|
|
254
|
+
// Dependency Operations
|
|
255
|
+
// -------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
addDependency(ref: string, dependsOnRef: string): Promise<void>;
|
|
258
|
+
removeDependency(ref: string, dependsOnRef: string): Promise<void>;
|
|
259
|
+
getDependencies(ref: string): Promise<string[]>;
|
|
260
|
+
|
|
261
|
+
// -------------------------------------------------------------------------
|
|
262
|
+
// Document Operations (for PRD supporting files)
|
|
263
|
+
// -------------------------------------------------------------------------
|
|
264
|
+
|
|
265
|
+
saveDocument(doc: Document): Promise<Document>;
|
|
266
|
+
getDocuments(prdRef: string): Promise<Document[]>;
|
|
267
|
+
deleteDocument(prdRef: string, filename: string): Promise<void>;
|
|
268
|
+
|
|
269
|
+
// -------------------------------------------------------------------------
|
|
270
|
+
// Query Operations
|
|
271
|
+
// -------------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
getStats(): Promise<Stats>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// =============================================================================
|
|
277
|
+
// Helper Types
|
|
278
|
+
// =============================================================================
|
|
279
|
+
|
|
280
|
+
export interface CascadeResult {
|
|
281
|
+
criteria: number;
|
|
282
|
+
tasks: number;
|
|
283
|
+
epics: number;
|
|
284
|
+
dependencies: number;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Adapter configuration stored in project.json
|
|
289
|
+
*/
|
|
290
|
+
export interface AdapterConfig {
|
|
291
|
+
type: "local" | "specflux" | "linear" | "notion";
|
|
292
|
+
config?: Record<string, unknown>;
|
|
293
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
|
|
4
|
+
function findFluxRoot(startDir: string): string | null {
|
|
5
|
+
let dir = startDir;
|
|
6
|
+
const root = "/";
|
|
7
|
+
|
|
8
|
+
while (dir !== root) {
|
|
9
|
+
if (existsSync(`${dir}/.flux/project.json`)) {
|
|
10
|
+
return dir;
|
|
11
|
+
}
|
|
12
|
+
const parent = dirname(dir);
|
|
13
|
+
if (parent === dir) break;
|
|
14
|
+
dir = parent;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (existsSync(`${root}.flux/project.json`)) {
|
|
18
|
+
return root;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let cachedProjectRoot: string | null = null;
|
|
25
|
+
|
|
26
|
+
export const config = {
|
|
27
|
+
fluxDir: ".flux",
|
|
28
|
+
dbFile: "flux.db",
|
|
29
|
+
projectFile: "project.json",
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the project root directory.
|
|
33
|
+
* Priority: env var > walk up to find .flux > cwd fallback
|
|
34
|
+
*/
|
|
35
|
+
get projectRoot() {
|
|
36
|
+
if (cachedProjectRoot) {
|
|
37
|
+
return cachedProjectRoot;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const envVar = process.env.FLUX_PROJECT_ROOT;
|
|
41
|
+
if (envVar && !envVar.startsWith("${")) {
|
|
42
|
+
cachedProjectRoot = envVar;
|
|
43
|
+
return envVar;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const cwd = process.cwd();
|
|
47
|
+
const found = findFluxRoot(cwd);
|
|
48
|
+
if (found) {
|
|
49
|
+
cachedProjectRoot = found;
|
|
50
|
+
return found;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return cwd;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
clearCache() {
|
|
57
|
+
cachedProjectRoot = null;
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
get fluxPath() {
|
|
61
|
+
return `${this.projectRoot}/${this.fluxDir}`;
|
|
62
|
+
},
|
|
63
|
+
get dbPath() {
|
|
64
|
+
return `${this.fluxPath}/${this.dbFile}`;
|
|
65
|
+
},
|
|
66
|
+
get projectJsonPath() {
|
|
67
|
+
return `${this.fluxPath}/${this.projectFile}`;
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
get projectExists() {
|
|
71
|
+
return existsSync(this.projectJsonPath);
|
|
72
|
+
},
|
|
73
|
+
};
|