@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.
Files changed (108) hide show
  1. package/README.md +11 -7
  2. package/agents/coder.md +150 -25
  3. package/bin/install.cjs +171 -16
  4. package/commands/breakdown.md +47 -10
  5. package/commands/dashboard.md +29 -0
  6. package/commands/flux.md +92 -12
  7. package/commands/implement.md +166 -17
  8. package/commands/linear.md +6 -5
  9. package/commands/prd.md +996 -82
  10. package/manifest.json +2 -1
  11. package/package.json +9 -11
  12. package/skills/flux-orchestrator/SKILL.md +11 -3
  13. package/skills/prd-writer/SKILL.md +761 -0
  14. package/skills/ux-ui-design/SKILL.md +346 -0
  15. package/skills/ux-ui-design/references/design-tokens.md +359 -0
  16. package/src/__tests__/version.test.ts +37 -0
  17. package/src/adapters/local/.gitkeep +0 -0
  18. package/src/dashboard/__tests__/api.test.ts +211 -0
  19. package/src/dashboard/browser.ts +35 -0
  20. package/src/dashboard/public/app.js +869 -0
  21. package/src/dashboard/public/index.html +90 -0
  22. package/src/dashboard/public/styles.css +807 -0
  23. package/src/dashboard/public/vendor/highlight.css +10 -0
  24. package/src/dashboard/public/vendor/highlight.min.js +8422 -0
  25. package/src/dashboard/public/vendor/marked.min.js +2210 -0
  26. package/src/dashboard/server.ts +296 -0
  27. package/src/dashboard/watchers.ts +83 -0
  28. package/src/server/__tests__/config.test.ts +163 -0
  29. package/src/server/adapters/__tests__/a-client-linear.test.ts +197 -0
  30. package/src/server/adapters/__tests__/adapter-factory.test.ts +230 -0
  31. package/src/server/adapters/__tests__/dependency-ops.test.ts +429 -0
  32. package/src/server/adapters/__tests__/document-ops.test.ts +306 -0
  33. package/src/server/adapters/__tests__/linear-adapter.test.ts +91 -0
  34. package/src/server/adapters/__tests__/linear-config.test.ts +425 -0
  35. package/src/server/adapters/__tests__/linear-criteria-parser.test.ts +287 -0
  36. package/src/server/adapters/__tests__/linear-description-test.ts +238 -0
  37. package/src/server/adapters/__tests__/linear-epic-crud.test.ts +496 -0
  38. package/src/server/adapters/__tests__/linear-mappers-description.test.ts +276 -0
  39. package/src/server/adapters/__tests__/linear-mappers-epic.test.ts +294 -0
  40. package/src/server/adapters/__tests__/linear-mappers-prd.test.ts +300 -0
  41. package/src/server/adapters/__tests__/linear-mappers-task.test.ts +197 -0
  42. package/src/server/adapters/__tests__/linear-prd-crud.test.ts +620 -0
  43. package/src/server/adapters/__tests__/linear-stats.test.ts +450 -0
  44. package/src/server/adapters/__tests__/linear-task-crud.test.ts +534 -0
  45. package/src/server/adapters/__tests__/linear-types.test.ts +243 -0
  46. package/src/server/adapters/__tests__/status-ops.test.ts +441 -0
  47. package/src/server/adapters/factory.ts +90 -0
  48. package/src/server/adapters/index.ts +9 -0
  49. package/src/server/adapters/linear/adapter.ts +1141 -0
  50. package/src/server/adapters/linear/client.ts +169 -0
  51. package/src/server/adapters/linear/config.ts +152 -0
  52. package/src/server/adapters/linear/helpers/criteria-parser.ts +197 -0
  53. package/src/server/adapters/linear/helpers/index.ts +7 -0
  54. package/src/server/adapters/linear/index.ts +16 -0
  55. package/src/server/adapters/linear/mappers/description.ts +136 -0
  56. package/src/server/adapters/linear/mappers/epic.ts +81 -0
  57. package/src/server/adapters/linear/mappers/index.ts +27 -0
  58. package/src/server/adapters/linear/mappers/prd.ts +178 -0
  59. package/src/server/adapters/linear/mappers/task.ts +82 -0
  60. package/src/server/adapters/linear/types.ts +264 -0
  61. package/src/server/adapters/local-adapter.ts +1009 -0
  62. package/src/server/adapters/types.ts +293 -0
  63. package/src/server/config.ts +73 -0
  64. package/src/server/db/__tests__/queries.test.ts +473 -0
  65. package/src/server/db/ids.ts +17 -0
  66. package/src/server/db/index.ts +69 -0
  67. package/src/server/db/queries.ts +142 -0
  68. package/src/server/db/refs.ts +60 -0
  69. package/src/server/db/schema.ts +97 -0
  70. package/src/server/db/sqlite.ts +10 -0
  71. package/src/server/index.ts +81 -0
  72. package/src/server/tools/__tests__/crud.test.ts +411 -0
  73. package/src/server/tools/__tests__/get-version.test.ts +27 -0
  74. package/src/server/tools/__tests__/mcp-interface.test.ts +479 -0
  75. package/src/server/tools/__tests__/query.test.ts +405 -0
  76. package/src/server/tools/__tests__/z-configure-linear.test.ts +511 -0
  77. package/src/server/tools/__tests__/z-get-linear-url.test.ts +108 -0
  78. package/src/server/tools/configure-linear.ts +373 -0
  79. package/src/server/tools/create-epic.ts +44 -0
  80. package/src/server/tools/create-prd.ts +40 -0
  81. package/src/server/tools/create-task.ts +47 -0
  82. package/src/server/tools/criteria.ts +50 -0
  83. package/src/server/tools/delete-entity.ts +76 -0
  84. package/src/server/tools/dependencies.ts +55 -0
  85. package/src/server/tools/get-entity.ts +240 -0
  86. package/src/server/tools/get-linear-url.ts +28 -0
  87. package/src/server/tools/get-stats.ts +52 -0
  88. package/src/server/tools/get-version.ts +20 -0
  89. package/src/server/tools/index.ts +158 -0
  90. package/src/server/tools/init-project.ts +108 -0
  91. package/src/server/tools/query-entities.ts +167 -0
  92. package/src/server/tools/render-status.ts +219 -0
  93. package/src/server/tools/update-entity.ts +140 -0
  94. package/src/server/tools/update-status.ts +166 -0
  95. package/src/server/utils/__tests__/mcp-response.test.ts +331 -0
  96. package/src/server/utils/logger.ts +9 -0
  97. package/src/server/utils/mcp-response.ts +254 -0
  98. package/src/server/utils/status-transitions.ts +160 -0
  99. package/src/status-line/__tests__/status-line.test.ts +215 -0
  100. package/src/status-line/index.ts +147 -0
  101. package/src/utils/__tests__/chalk-import.test.ts +32 -0
  102. package/src/utils/__tests__/display.test.ts +97 -0
  103. package/src/utils/__tests__/status-renderer.test.ts +310 -0
  104. package/src/utils/display.ts +62 -0
  105. package/src/utils/status-renderer.ts +214 -0
  106. package/src/version.ts +5 -0
  107. package/dist/server/index.js +0 -87063
  108. 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
+ };