@codewithahsan/paperclip-plugin-gsd 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.
@@ -0,0 +1,536 @@
1
+ // src/ui/index.tsx
2
+ import { useState } from "react";
3
+ import {
4
+ usePluginAction,
5
+ usePluginData,
6
+ usePluginToast
7
+ } from "@paperclipai/plugin-sdk/ui";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ var card = {
10
+ border: "1px solid var(--border-secondary, #374151)",
11
+ borderRadius: 8,
12
+ padding: 16,
13
+ marginBottom: 12,
14
+ background: "var(--bg-secondary, #1f2937)"
15
+ };
16
+ var badge = (color) => ({
17
+ display: "inline-block",
18
+ padding: "2px 8px",
19
+ borderRadius: 4,
20
+ fontSize: 12,
21
+ fontWeight: 600,
22
+ color: "#fff",
23
+ background: color
24
+ });
25
+ var progressBar = {
26
+ height: 8,
27
+ borderRadius: 4,
28
+ background: "var(--border-secondary, #374151)",
29
+ overflow: "hidden",
30
+ marginTop: 4
31
+ };
32
+ var progressFill = (pct) => ({
33
+ height: "100%",
34
+ width: `${pct}%`,
35
+ background: pct === 100 ? "#22c55e" : "#3b82f6",
36
+ borderRadius: 4,
37
+ transition: "width 0.3s ease"
38
+ });
39
+ var muted = {
40
+ color: "var(--text-tertiary, #9ca3af)",
41
+ fontSize: 13
42
+ };
43
+ var heading = {
44
+ fontSize: 15,
45
+ fontWeight: 600,
46
+ marginBottom: 8
47
+ };
48
+ var emptyState = {
49
+ textAlign: "center",
50
+ padding: 32,
51
+ color: "var(--text-tertiary, #9ca3af)"
52
+ };
53
+ function phaseStatusColor(phase, isCurrent = false) {
54
+ const status = phase.computedStatus;
55
+ if (isCurrent) return "#3b82f6";
56
+ switch (status) {
57
+ case "complete":
58
+ return "#22c55e";
59
+ case "verifying":
60
+ return "#22c55e";
61
+ case "executing":
62
+ return "#f59e0b";
63
+ case "planned":
64
+ return "#8b5cf6";
65
+ case "researching":
66
+ return "#6366f1";
67
+ case "context":
68
+ return "#6366f1";
69
+ case "diagnosed":
70
+ return "#ef4444";
71
+ case "not-started":
72
+ default:
73
+ return "#94a3b8";
74
+ }
75
+ }
76
+ function phaseStatusLabel(phase, isCurrent = false) {
77
+ if (isCurrent) {
78
+ const status = phase.computedStatus;
79
+ if (status === "researching" || status === "context") return "Researching";
80
+ if (status === "planned") return "Ready to Execute";
81
+ if (status === "diagnosed") return "Gaps Found";
82
+ if (status === "verifying") return "Verifying";
83
+ if (status === "complete") return "Finishing";
84
+ return "Executing";
85
+ }
86
+ switch (phase.computedStatus) {
87
+ case "complete":
88
+ return "Complete";
89
+ case "verifying":
90
+ return "Verifying";
91
+ case "diagnosed":
92
+ return "Gaps Found";
93
+ case "executing":
94
+ return "In Progress";
95
+ case "planned":
96
+ return "Planned";
97
+ case "researching":
98
+ return "Researched";
99
+ case "context":
100
+ return "Context Gathered";
101
+ case "not-started":
102
+ default:
103
+ return "Not Started";
104
+ }
105
+ }
106
+ function GsdDashboardWidget({ context }) {
107
+ const { data, loading } = usePluginData("gsd-overview", { companyId: context.companyId });
108
+ if (loading) return /* @__PURE__ */ jsx("div", { style: muted, children: "Loading GSD status..." });
109
+ const projects = data?.projects ?? [];
110
+ if (projects.length === 0) {
111
+ return /* @__PURE__ */ jsxs("div", { style: emptyState, children: [
112
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 24, marginBottom: 8 }, children: "No GSD projects" }),
113
+ /* @__PURE__ */ jsx("div", { children: "GSD state will appear here after agents run with GSD enabled." })
114
+ ] });
115
+ }
116
+ return /* @__PURE__ */ jsxs("div", { children: [
117
+ /* @__PURE__ */ jsx("div", { style: heading, children: "GSD Progress" }),
118
+ projects.map((p) => /* @__PURE__ */ jsxs("div", { style: card, children: [
119
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: 4 }, children: [
120
+ /* @__PURE__ */ jsx("strong", { children: p.projectName }),
121
+ p.milestone && /* @__PURE__ */ jsx("span", { style: badge("#6366f1"), children: p.milestone })
122
+ ] }),
123
+ /* @__PURE__ */ jsxs("div", { style: muted, children: [
124
+ p.completedPhases,
125
+ "/",
126
+ p.totalPhases,
127
+ " phases \\u2022 ",
128
+ p.percent,
129
+ "%"
130
+ ] }),
131
+ /* @__PURE__ */ jsx("div", { style: progressBar, children: /* @__PURE__ */ jsx("div", { style: progressFill(p.percent) }) })
132
+ ] }, p.projectId))
133
+ ] });
134
+ }
135
+ function GsdProjectTab({ context }) {
136
+ const projectId = context.entityId;
137
+ const { data, loading, refresh } = usePluginData(
138
+ "gsd-project-detail",
139
+ { projectId }
140
+ );
141
+ const syncProject = usePluginAction("sync-project");
142
+ const toast = usePluginToast();
143
+ const handleSync = async () => {
144
+ await syncProject({ projectId, companyId: context.companyId });
145
+ refresh();
146
+ toast({ title: "GSD synced", tone: "success" });
147
+ };
148
+ if (loading) return /* @__PURE__ */ jsx("div", { style: muted, children: "Loading GSD state..." });
149
+ if (!data || data.phases.length === 0) {
150
+ return /* @__PURE__ */ jsxs("div", { style: emptyState, children: [
151
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 20, marginBottom: 8 }, children: "No GSD data found" }),
152
+ /* @__PURE__ */ jsx("div", { style: { marginBottom: 16 }, children: "GSD state will appear here once an agent runs with GSD enabled in this project's workspace." }),
153
+ /* @__PURE__ */ jsx("button", { onClick: handleSync, style: syncButtonStyle, children: "Sync GSD" })
154
+ ] });
155
+ }
156
+ const state = data.state;
157
+ return /* @__PURE__ */ jsxs("div", { children: [
158
+ /* @__PURE__ */ jsxs(
159
+ "div",
160
+ {
161
+ style: {
162
+ display: "flex",
163
+ justifyContent: "space-between",
164
+ alignItems: "center",
165
+ marginBottom: 16
166
+ },
167
+ children: [
168
+ /* @__PURE__ */ jsxs("div", { children: [
169
+ /* @__PURE__ */ jsxs("div", { style: heading, children: [
170
+ "GSD Roadmap",
171
+ state?.milestone && /* @__PURE__ */ jsx("span", { style: { ...badge("#6366f1"), marginLeft: 8 }, children: state.milestone })
172
+ ] }),
173
+ state && /* @__PURE__ */ jsxs("div", { style: muted, children: [
174
+ "Phase ",
175
+ state.currentPhase,
176
+ ": ",
177
+ state.currentPhaseName,
178
+ " \\u2022",
179
+ " ",
180
+ state.status,
181
+ " \\u2022 ",
182
+ state.progress.percent,
183
+ "% overall"
184
+ ] })
185
+ ] }),
186
+ /* @__PURE__ */ jsx("button", { onClick: handleSync, style: syncButtonStyle, children: "Sync GSD" })
187
+ ]
188
+ }
189
+ ),
190
+ state && /* @__PURE__ */ jsxs("div", { style: { marginBottom: 16 }, children: [
191
+ /* @__PURE__ */ jsx("div", { style: progressBar, children: /* @__PURE__ */ jsx("div", { style: progressFill(state.progress.percent) }) }),
192
+ /* @__PURE__ */ jsxs("div", { style: { ...muted, marginTop: 4 }, children: [
193
+ state.progress.completedPhases,
194
+ "/",
195
+ state.progress.totalPhases,
196
+ " ",
197
+ "phases \\u2022 ",
198
+ state.progress.completedPlans,
199
+ "/",
200
+ state.progress.totalPlans,
201
+ " plans"
202
+ ] })
203
+ ] }),
204
+ data.phases.map((phase) => /* @__PURE__ */ jsx(
205
+ PhaseCard,
206
+ {
207
+ phase,
208
+ linkedIssueId: data.phaseIssueLinks[phase.number] ?? null,
209
+ isCurrent: state?.currentPhase === phase.number
210
+ },
211
+ phase.number
212
+ )),
213
+ data.lastSyncAt && /* @__PURE__ */ jsxs("div", { style: { ...muted, marginTop: 16 }, children: [
214
+ "Last synced: ",
215
+ new Date(data.lastSyncAt).toLocaleString()
216
+ ] })
217
+ ] });
218
+ }
219
+ function PhaseCard({
220
+ phase,
221
+ linkedIssueId,
222
+ isCurrent
223
+ }) {
224
+ const total = phase.plans.length;
225
+ const done = phase.plans.filter((p) => p.status === "complete").length;
226
+ const pct = total > 0 ? Math.round(done / total * 100) : 0;
227
+ return /* @__PURE__ */ jsxs(
228
+ "div",
229
+ {
230
+ style: {
231
+ ...card,
232
+ borderLeft: isCurrent ? "3px solid #3b82f6" : "1px solid var(--border-secondary, #374151)"
233
+ },
234
+ children: [
235
+ /* @__PURE__ */ jsxs(
236
+ "div",
237
+ {
238
+ style: {
239
+ display: "flex",
240
+ justifyContent: "space-between",
241
+ alignItems: "center"
242
+ },
243
+ children: [
244
+ /* @__PURE__ */ jsxs("div", { children: [
245
+ /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
246
+ "Phase ",
247
+ phase.number,
248
+ ":",
249
+ " "
250
+ ] }),
251
+ /* @__PURE__ */ jsx("span", { children: phase.slug.replace(/-/g, " ") }),
252
+ isCurrent && /* @__PURE__ */ jsx(
253
+ "span",
254
+ {
255
+ style: { ...badge("#3b82f6"), marginLeft: 8, fontSize: 11 },
256
+ children: "CURRENT"
257
+ }
258
+ )
259
+ ] }),
260
+ /* @__PURE__ */ jsx("span", { style: badge(phaseStatusColor(phase, isCurrent)), children: phaseStatusLabel(phase, isCurrent) })
261
+ ]
262
+ }
263
+ ),
264
+ total > 0 && /* @__PURE__ */ jsxs("div", { style: { marginTop: 8 }, children: [
265
+ /* @__PURE__ */ jsx("div", { style: progressBar, children: /* @__PURE__ */ jsx("div", { style: progressFill(pct) }) }),
266
+ /* @__PURE__ */ jsxs("div", { style: { ...muted, marginTop: 2 }, children: [
267
+ done,
268
+ "/",
269
+ total,
270
+ " plans"
271
+ ] })
272
+ ] }),
273
+ /* @__PURE__ */ jsxs("div", { style: { marginTop: 6, display: "flex", gap: 6, flexWrap: "wrap" }, children: [
274
+ phase.hasContext && /* @__PURE__ */ jsx("span", { style: artifactBadge, children: "Context" }),
275
+ phase.hasResearch && /* @__PURE__ */ jsx("span", { style: artifactBadge, children: "Research" }),
276
+ phase.hasVerification && /* @__PURE__ */ jsx("span", { style: {
277
+ ...artifactBadge,
278
+ color: phase.verificationStatus === "passed" ? "#22c55e" : phase.verificationStatus === "gaps_found" ? "#ef4444" : "#f59e0b"
279
+ }, children: phase.verificationStatus === "passed" ? "Verified" : phase.verificationStatus === "gaps_found" ? "Gaps Found" : phase.verificationStatus === "human_needed" ? "Needs Review" : "Verified" }),
280
+ phase.hasUat && /* @__PURE__ */ jsxs("span", { style: {
281
+ ...artifactBadge,
282
+ color: phase.uatStatus === "complete" ? "#22c55e" : phase.uatStatus === "diagnosed" ? "#ef4444" : "#f59e0b"
283
+ }, children: [
284
+ "UAT ",
285
+ phase.uatStatus === "complete" ? "Passed" : phase.uatStatus === "diagnosed" ? "Diagnosed" : "Testing"
286
+ ] }),
287
+ phase.hasContinueHere && /* @__PURE__ */ jsx("span", { style: { ...artifactBadge, color: "#f59e0b" }, children: "Paused" })
288
+ ] }),
289
+ !linkedIssueId && /* @__PURE__ */ jsx("div", { style: { ...muted, marginTop: 4, fontStyle: "italic" }, children: "Not linked to an issue" })
290
+ ]
291
+ }
292
+ );
293
+ }
294
+ function GsdIssueTab({ context }) {
295
+ const { data, loading } = usePluginData("gsd-issue-phase", {
296
+ issueId: context.entityId,
297
+ projectId: context.projectId ?? context.parentEntityId
298
+ });
299
+ if (loading) return /* @__PURE__ */ jsx("div", { style: muted, children: "Loading..." });
300
+ if (!data || !data.linked) {
301
+ return /* @__PURE__ */ jsxs("div", { style: emptyState, children: [
302
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 18, marginBottom: 8 }, children: "No GSD phase linked" }),
303
+ /* @__PURE__ */ jsx("div", { children: "Link this issue to a GSD phase from the project's GSD tab." })
304
+ ] });
305
+ }
306
+ if (!data.phase) {
307
+ return /* @__PURE__ */ jsx("div", { style: muted, children: "Linked phase not found in current GSD state." });
308
+ }
309
+ const phase = data.phase;
310
+ const total = phase.plans.length;
311
+ const done = phase.plans.filter((p) => p.status === "complete").length;
312
+ const pct = total > 0 ? Math.round(done / total * 100) : 0;
313
+ return /* @__PURE__ */ jsxs("div", { children: [
314
+ /* @__PURE__ */ jsxs("div", { style: heading, children: [
315
+ "Phase ",
316
+ phase.number,
317
+ ": ",
318
+ phase.slug.replace(/-/g, " ")
319
+ ] }),
320
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: 12 }, children: [
321
+ /* @__PURE__ */ jsx("span", { style: badge(phaseStatusColor(phase)), children: phaseStatusLabel(phase) }),
322
+ phase.hasVerification && /* @__PURE__ */ jsx("span", { style: { ...badge("#22c55e"), marginLeft: 8 }, children: "Verified" })
323
+ ] }),
324
+ total > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
325
+ /* @__PURE__ */ jsx("div", { style: progressBar, children: /* @__PURE__ */ jsx("div", { style: progressFill(pct) }) }),
326
+ /* @__PURE__ */ jsxs("div", { style: { ...muted, marginTop: 4, marginBottom: 12 }, children: [
327
+ done,
328
+ "/",
329
+ total,
330
+ " plans complete (",
331
+ pct,
332
+ "%)"
333
+ ] }),
334
+ phase.plans.map((plan) => /* @__PURE__ */ jsxs(
335
+ "div",
336
+ {
337
+ style: {
338
+ display: "flex",
339
+ alignItems: "center",
340
+ gap: 8,
341
+ padding: "4px 0",
342
+ borderBottom: "1px solid var(--border-secondary, #f1f5f9)"
343
+ },
344
+ children: [
345
+ /* @__PURE__ */ jsx("span", { style: { fontSize: 14 }, children: plan.status === "complete" ? "\u2705" : "\u2B1C" }),
346
+ /* @__PURE__ */ jsxs("span", { children: [
347
+ "Plan ",
348
+ plan.planNumber,
349
+ plan.objective && /* @__PURE__ */ jsxs("span", { style: muted, children: [
350
+ " \\u2014 ",
351
+ plan.objective.slice(0, 80),
352
+ plan.objective.length > 80 ? "..." : ""
353
+ ] })
354
+ ] }),
355
+ plan.wave != null && /* @__PURE__ */ jsxs("span", { style: { ...muted, fontSize: 11 }, children: [
356
+ "wave ",
357
+ plan.wave
358
+ ] })
359
+ ]
360
+ },
361
+ `${plan.phaseNumber}-${plan.planNumber}`
362
+ ))
363
+ ] })
364
+ ] });
365
+ }
366
+ function GsdSyncButton({ context }) {
367
+ const syncProject = usePluginAction("sync-project");
368
+ const toast = usePluginToast();
369
+ const handleSync = async () => {
370
+ await syncProject({
371
+ projectId: context.entityId,
372
+ companyId: context.companyId
373
+ });
374
+ toast({ title: "GSD synced", tone: "success" });
375
+ };
376
+ return /* @__PURE__ */ jsx("button", { onClick: handleSync, style: syncButtonStyle, children: "Sync GSD" });
377
+ }
378
+ function GsdSettingsPage({ context }) {
379
+ const { data: compatData, loading: compatLoading } = usePluginData("gsd-adapter-compat", { companyId: context.companyId });
380
+ const { data: configData, loading: configLoading, refresh: refreshConfig } = usePluginData("gsd-config", {});
381
+ const syncAll = usePluginAction("sync-all");
382
+ const updateConfig = usePluginAction("update-config");
383
+ const toast = usePluginToast();
384
+ const [autoSync, setAutoSync] = useState(null);
385
+ const [interval, setInterval] = useState("");
386
+ const [saving, setSaving] = useState(false);
387
+ const currentAutoSync = autoSync ?? configData?.autoSyncEnabled ?? true;
388
+ const currentInterval = interval || String(configData?.syncIntervalSeconds ?? 30);
389
+ const handleSyncAll = async () => {
390
+ const result = await syncAll({
391
+ companyId: context.companyId
392
+ });
393
+ toast({
394
+ title: `Synced ${result?.synced ?? 0} workspace(s)`,
395
+ tone: "success"
396
+ });
397
+ };
398
+ const handleSaveConfig = async () => {
399
+ const parsedInterval = Math.max(10, Math.min(600, Number(currentInterval) || 30));
400
+ setSaving(true);
401
+ try {
402
+ await updateConfig({
403
+ autoSyncEnabled: currentAutoSync,
404
+ syncIntervalSeconds: parsedInterval
405
+ });
406
+ refreshConfig();
407
+ setAutoSync(null);
408
+ setInterval("");
409
+ toast({ title: "Settings saved", tone: "success" });
410
+ } catch {
411
+ toast({ title: "Failed to save settings", tone: "error" });
412
+ } finally {
413
+ setSaving(false);
414
+ }
415
+ };
416
+ const hasChanges = autoSync !== null || interval !== "" && Number(interval) !== configData?.syncIntervalSeconds;
417
+ return /* @__PURE__ */ jsxs("div", { style: { maxWidth: 640 }, children: [
418
+ /* @__PURE__ */ jsx("div", { style: heading, children: "GSD Settings" }),
419
+ /* @__PURE__ */ jsxs("div", { style: { ...card, marginBottom: 24 }, children: [
420
+ /* @__PURE__ */ jsx("div", { style: { ...heading, marginBottom: 12 }, children: "Auto-Sync" }),
421
+ configLoading ? /* @__PURE__ */ jsx("div", { style: muted, children: "Loading configuration..." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
422
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }, children: /* @__PURE__ */ jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, cursor: "pointer" }, children: [
423
+ /* @__PURE__ */ jsx(
424
+ "input",
425
+ {
426
+ type: "checkbox",
427
+ checked: currentAutoSync,
428
+ onChange: (e) => setAutoSync(e.target.checked),
429
+ style: { width: 16, height: 16, cursor: "pointer" }
430
+ }
431
+ ),
432
+ /* @__PURE__ */ jsx("span", { children: "Enable periodic sync" })
433
+ ] }) }),
434
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: 12 }, children: [
435
+ /* @__PURE__ */ jsx("label", { style: { display: "block", marginBottom: 4 }, children: /* @__PURE__ */ jsx("span", { style: muted, children: "Sync interval (seconds, 10\\u2013600)" }) }),
436
+ /* @__PURE__ */ jsx(
437
+ "input",
438
+ {
439
+ type: "number",
440
+ min: 10,
441
+ max: 600,
442
+ value: currentInterval,
443
+ onChange: (e) => setInterval(e.target.value),
444
+ disabled: !currentAutoSync,
445
+ style: {
446
+ ...inputStyle,
447
+ opacity: currentAutoSync ? 1 : 0.5
448
+ }
449
+ }
450
+ )
451
+ ] }),
452
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
453
+ /* @__PURE__ */ jsx(
454
+ "button",
455
+ {
456
+ onClick: handleSaveConfig,
457
+ disabled: saving || !hasChanges,
458
+ style: {
459
+ ...syncButtonStyle,
460
+ opacity: saving || !hasChanges ? 0.5 : 1
461
+ },
462
+ children: saving ? "Saving..." : "Save"
463
+ }
464
+ ),
465
+ /* @__PURE__ */ jsx("button", { onClick: handleSyncAll, style: syncButtonStyle, children: "Sync All Projects" })
466
+ ] })
467
+ ] })
468
+ ] }),
469
+ /* @__PURE__ */ jsx("div", { style: heading, children: "Agent Compatibility" }),
470
+ compatLoading && /* @__PURE__ */ jsx("div", { style: muted, children: "Loading..." }),
471
+ compatData?.agents.map((agent) => /* @__PURE__ */ jsxs("div", { style: card, children: [
472
+ /* @__PURE__ */ jsxs(
473
+ "div",
474
+ {
475
+ style: {
476
+ display: "flex",
477
+ justifyContent: "space-between",
478
+ alignItems: "center"
479
+ },
480
+ children: [
481
+ /* @__PURE__ */ jsx("strong", { children: agent.agentName }),
482
+ /* @__PURE__ */ jsx(
483
+ "span",
484
+ {
485
+ style: badge(
486
+ agent.compatibility === "supported" ? "#22c55e" : agent.compatibility === "partial" ? "#f59e0b" : "#ef4444"
487
+ ),
488
+ children: agent.compatibility
489
+ }
490
+ )
491
+ ]
492
+ }
493
+ ),
494
+ /* @__PURE__ */ jsxs("div", { style: { ...muted, marginTop: 4 }, children: [
495
+ agent.adapterType,
496
+ " \u2014 ",
497
+ agent.message
498
+ ] })
499
+ ] }, agent.agentId)),
500
+ !compatLoading && (!compatData?.agents || compatData.agents.length === 0) && /* @__PURE__ */ jsx("div", { style: muted, children: "No agents found for this company." })
501
+ ] });
502
+ }
503
+ var artifactBadge = {
504
+ fontSize: 11,
505
+ color: "var(--text-tertiary, #9ca3af)",
506
+ border: "1px solid var(--border-secondary, #374151)",
507
+ borderRadius: 4,
508
+ padding: "1px 6px"
509
+ };
510
+ var syncButtonStyle = {
511
+ padding: "6px 16px",
512
+ borderRadius: 6,
513
+ border: "1px solid var(--border-secondary, #374151)",
514
+ background: "var(--bg-secondary, #1f2937)",
515
+ color: "var(--text-primary, #e5e7eb)",
516
+ cursor: "pointer",
517
+ fontSize: 13,
518
+ fontWeight: 500
519
+ };
520
+ var inputStyle = {
521
+ padding: "6px 10px",
522
+ borderRadius: 6,
523
+ border: "1px solid var(--border-secondary, #374151)",
524
+ background: "var(--bg-primary, #111827)",
525
+ color: "var(--text-primary, #e5e7eb)",
526
+ fontSize: 13,
527
+ width: 120
528
+ };
529
+ export {
530
+ GsdDashboardWidget,
531
+ GsdIssueTab,
532
+ GsdProjectTab,
533
+ GsdSettingsPage,
534
+ GsdSyncButton
535
+ };
536
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ui/index.tsx"],
4
+ "sourcesContent": ["import { useState } from \"react\";\nimport {\n useHostContext,\n usePluginAction,\n usePluginData,\n usePluginToast,\n type PluginDetailTabProps,\n type PluginPageProps,\n type PluginWidgetProps,\n} from \"@paperclipai/plugin-sdk/ui\";\nimport type {\n GsdPhase,\n GsdPluginState,\n GsdProjectSummary,\n} from \"../gsd-types.js\";\n\n// --- Styles ---\n\nconst card: React.CSSProperties = {\n border: \"1px solid var(--border-secondary, #374151)\",\n borderRadius: 8,\n padding: 16,\n marginBottom: 12,\n background: \"var(--bg-secondary, #1f2937)\",\n};\n\nconst badge = (\n color: string,\n): React.CSSProperties => ({\n display: \"inline-block\",\n padding: \"2px 8px\",\n borderRadius: 4,\n fontSize: 12,\n fontWeight: 600,\n color: \"#fff\",\n background: color,\n});\n\nconst progressBar: React.CSSProperties = {\n height: 8,\n borderRadius: 4,\n background: \"var(--border-secondary, #374151)\",\n overflow: \"hidden\",\n marginTop: 4,\n};\n\nconst progressFill = (pct: number): React.CSSProperties => ({\n height: \"100%\",\n width: `${pct}%`,\n background: pct === 100 ? \"#22c55e\" : \"#3b82f6\",\n borderRadius: 4,\n transition: \"width 0.3s ease\",\n});\n\nconst muted: React.CSSProperties = {\n color: \"var(--text-tertiary, #9ca3af)\",\n fontSize: 13,\n};\n\nconst heading: React.CSSProperties = {\n fontSize: 15,\n fontWeight: 600,\n marginBottom: 8,\n};\n\nconst emptyState: React.CSSProperties = {\n textAlign: \"center\" as const,\n padding: 32,\n color: \"var(--text-tertiary, #9ca3af)\",\n};\n\n// --- Status helpers ---\n\nfunction phaseStatusColor(phase: GsdPhase, isCurrent = false): string {\n const status = phase.computedStatus;\n if (isCurrent) return \"#3b82f6\";\n switch (status) {\n case \"complete\": return \"#22c55e\";\n case \"verifying\": return \"#22c55e\";\n case \"executing\": return \"#f59e0b\";\n case \"planned\": return \"#8b5cf6\";\n case \"researching\": return \"#6366f1\";\n case \"context\": return \"#6366f1\";\n case \"diagnosed\": return \"#ef4444\";\n case \"not-started\":\n default: return \"#94a3b8\";\n }\n}\n\nfunction phaseStatusLabel(phase: GsdPhase, isCurrent = false): string {\n // Current phase in STATE.md means GSD is actively working on it \u2014\n // even if all SUMMARY.md exist, verification/UAT may still be running\n if (isCurrent) {\n const status = phase.computedStatus;\n if (status === \"researching\" || status === \"context\") return \"Researching\";\n if (status === \"planned\") return \"Ready to Execute\";\n if (status === \"diagnosed\") return \"Gaps Found\";\n if (status === \"verifying\") return \"Verifying\";\n // All plans done but still current phase \u2192 verification/UAT in progress\n if (status === \"complete\") return \"Finishing\";\n return \"Executing\";\n }\n switch (phase.computedStatus) {\n case \"complete\": return \"Complete\";\n case \"verifying\": return \"Verifying\";\n case \"diagnosed\": return \"Gaps Found\";\n case \"executing\": return \"In Progress\";\n case \"planned\": return \"Planned\";\n case \"researching\": return \"Researched\";\n case \"context\": return \"Context Gathered\";\n case \"not-started\":\n default: return \"Not Started\";\n }\n}\n\n// --- Dashboard Widget ---\n\nexport function GsdDashboardWidget({ context }: PluginWidgetProps) {\n const { data, loading } = usePluginData<{\n projects: GsdProjectSummary[];\n }>(\"gsd-overview\", { companyId: context.companyId });\n\n if (loading) return <div style={muted}>Loading GSD status...</div>;\n\n const projects = data?.projects ?? [];\n\n if (projects.length === 0) {\n return (\n <div style={emptyState}>\n <div style={{ fontSize: 24, marginBottom: 8 }}>No GSD projects</div>\n <div>GSD state will appear here after agents run with GSD enabled.</div>\n </div>\n );\n }\n\n return (\n <div>\n <div style={heading}>GSD Progress</div>\n {projects.map((p) => (\n <div key={p.projectId} style={card}>\n <div style={{ display: \"flex\", justifyContent: \"space-between\", marginBottom: 4 }}>\n <strong>{p.projectName}</strong>\n {p.milestone && (\n <span style={badge(\"#6366f1\")}>{p.milestone}</span>\n )}\n </div>\n <div style={muted}>\n {p.completedPhases}/{p.totalPhases} phases \\u2022 {p.percent}%\n </div>\n <div style={progressBar}>\n <div style={progressFill(p.percent)} />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\n// --- Project Detail Tab ---\n\nexport function GsdProjectTab({ context }: PluginDetailTabProps) {\n const projectId = context.entityId;\n const { data, loading, refresh } = usePluginData<GsdPluginState | null>(\n \"gsd-project-detail\",\n { projectId },\n );\n const syncProject = usePluginAction(\"sync-project\");\n const toast = usePluginToast();\n\n const handleSync = async () => {\n await syncProject({ projectId, companyId: context.companyId });\n refresh();\n toast({ title: \"GSD synced\", tone: \"success\" });\n };\n\n if (loading) return <div style={muted}>Loading GSD state...</div>;\n\n if (!data || data.phases.length === 0) {\n return (\n <div style={emptyState}>\n <div style={{ fontSize: 20, marginBottom: 8 }}>\n No GSD data found\n </div>\n <div style={{ marginBottom: 16 }}>\n GSD state will appear here once an agent runs with GSD enabled in\n this project's workspace.\n </div>\n <button onClick={handleSync} style={syncButtonStyle}>\n Sync GSD\n </button>\n </div>\n );\n }\n\n const state = data.state;\n\n return (\n <div>\n {/* Header */}\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: 16,\n }}\n >\n <div>\n <div style={heading}>\n GSD Roadmap\n {state?.milestone && (\n <span style={{ ...badge(\"#6366f1\"), marginLeft: 8 }}>\n {state.milestone}\n </span>\n )}\n </div>\n {state && (\n <div style={muted}>\n Phase {state.currentPhase}: {state.currentPhaseName} \\u2022{\" \"}\n {state.status} \\u2022 {state.progress.percent}% overall\n </div>\n )}\n </div>\n <button onClick={handleSync} style={syncButtonStyle}>\n Sync GSD\n </button>\n </div>\n\n {/* Overall progress */}\n {state && (\n <div style={{ marginBottom: 16 }}>\n <div style={progressBar}>\n <div style={progressFill(state.progress.percent)} />\n </div>\n <div style={{ ...muted, marginTop: 4 }}>\n {state.progress.completedPhases}/{state.progress.totalPhases}{\" \"}\n phases \\u2022 {state.progress.completedPlans}/\n {state.progress.totalPlans} plans\n </div>\n </div>\n )}\n\n {/* Phase list */}\n {data.phases.map((phase) => (\n <PhaseCard\n key={phase.number}\n phase={phase}\n linkedIssueId={data.phaseIssueLinks[phase.number] ?? null}\n isCurrent={state?.currentPhase === phase.number}\n />\n ))}\n\n {/* Last sync */}\n {data.lastSyncAt && (\n <div style={{ ...muted, marginTop: 16 }}>\n Last synced: {new Date(data.lastSyncAt).toLocaleString()}\n </div>\n )}\n </div>\n );\n}\n\nfunction PhaseCard({\n phase,\n linkedIssueId,\n isCurrent,\n}: {\n phase: GsdPhase;\n linkedIssueId: string | null;\n isCurrent: boolean;\n}) {\n const total = phase.plans.length;\n const done = phase.plans.filter((p) => p.status === \"complete\").length;\n const pct = total > 0 ? Math.round((done / total) * 100) : 0;\n\n return (\n <div\n style={{\n ...card,\n borderLeft: isCurrent\n ? \"3px solid #3b82f6\"\n : \"1px solid var(--border-secondary, #374151)\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <div>\n <span style={{ fontWeight: 600 }}>\n Phase {phase.number}:{\" \"}\n </span>\n <span>{phase.slug.replace(/-/g, \" \")}</span>\n {isCurrent && (\n <span\n style={{ ...badge(\"#3b82f6\"), marginLeft: 8, fontSize: 11 }}\n >\n CURRENT\n </span>\n )}\n </div>\n <span style={badge(phaseStatusColor(phase, isCurrent))}>\n {phaseStatusLabel(phase, isCurrent)}\n </span>\n </div>\n\n {total > 0 && (\n <div style={{ marginTop: 8 }}>\n <div style={progressBar}>\n <div style={progressFill(pct)} />\n </div>\n <div style={{ ...muted, marginTop: 2 }}>\n {done}/{total} plans\n </div>\n </div>\n )}\n\n {/* Phase artifacts */}\n <div style={{ marginTop: 6, display: \"flex\", gap: 6, flexWrap: \"wrap\" }}>\n {phase.hasContext && (\n <span style={artifactBadge}>Context</span>\n )}\n {phase.hasResearch && (\n <span style={artifactBadge}>Research</span>\n )}\n {phase.hasVerification && (\n <span style={{\n ...artifactBadge,\n color: phase.verificationStatus === \"passed\" ? \"#22c55e\"\n : phase.verificationStatus === \"gaps_found\" ? \"#ef4444\"\n : \"#f59e0b\",\n }}>\n {phase.verificationStatus === \"passed\" ? \"Verified\"\n : phase.verificationStatus === \"gaps_found\" ? \"Gaps Found\"\n : phase.verificationStatus === \"human_needed\" ? \"Needs Review\"\n : \"Verified\"}\n </span>\n )}\n {phase.hasUat && (\n <span style={{\n ...artifactBadge,\n color: phase.uatStatus === \"complete\" ? \"#22c55e\"\n : phase.uatStatus === \"diagnosed\" ? \"#ef4444\"\n : \"#f59e0b\",\n }}>\n UAT {phase.uatStatus === \"complete\" ? \"Passed\"\n : phase.uatStatus === \"diagnosed\" ? \"Diagnosed\"\n : \"Testing\"}\n </span>\n )}\n {phase.hasContinueHere && (\n <span style={{ ...artifactBadge, color: \"#f59e0b\" }}>Paused</span>\n )}\n </div>\n\n {!linkedIssueId && (\n <div style={{ ...muted, marginTop: 4, fontStyle: \"italic\" }}>\n Not linked to an issue\n </div>\n )}\n </div>\n );\n}\n\n// --- Issue Detail Tab ---\n\nexport function GsdIssueTab({ context }: PluginDetailTabProps) {\n const { data, loading } = usePluginData<{\n linked: boolean;\n phase: GsdPhase | null;\n state: { currentPhase: string; status: string } | null;\n } | null>(\"gsd-issue-phase\", {\n issueId: context.entityId,\n projectId: context.projectId ?? context.parentEntityId,\n });\n\n if (loading) return <div style={muted}>Loading...</div>;\n if (!data || !data.linked) {\n return (\n <div style={emptyState}>\n <div style={{ fontSize: 18, marginBottom: 8 }}>\n No GSD phase linked\n </div>\n <div>\n Link this issue to a GSD phase from the project's GSD tab.\n </div>\n </div>\n );\n }\n\n if (!data.phase) {\n return <div style={muted}>Linked phase not found in current GSD state.</div>;\n }\n\n const phase = data.phase;\n const total = phase.plans.length;\n const done = phase.plans.filter((p) => p.status === \"complete\").length;\n const pct = total > 0 ? Math.round((done / total) * 100) : 0;\n\n return (\n <div>\n <div style={heading}>\n Phase {phase.number}: {phase.slug.replace(/-/g, \" \")}\n </div>\n <div style={{ marginBottom: 12 }}>\n <span style={badge(phaseStatusColor(phase))}>\n {phaseStatusLabel(phase)}\n </span>\n {phase.hasVerification && (\n <span style={{ ...badge(\"#22c55e\"), marginLeft: 8 }}>\n Verified\n </span>\n )}\n </div>\n\n {total > 0 && (\n <>\n <div style={progressBar}>\n <div style={progressFill(pct)} />\n </div>\n <div style={{ ...muted, marginTop: 4, marginBottom: 12 }}>\n {done}/{total} plans complete ({pct}%)\n </div>\n\n {/* Plan list */}\n {phase.plans.map((plan) => (\n <div\n key={`${plan.phaseNumber}-${plan.planNumber}`}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"4px 0\",\n borderBottom:\n \"1px solid var(--border-secondary, #f1f5f9)\",\n }}\n >\n <span style={{ fontSize: 14 }}>\n {plan.status === \"complete\" ? \"\\u2705\" : \"\\u2B1C\"}\n </span>\n <span>\n Plan {plan.planNumber}\n {plan.objective && (\n <span style={muted}> \\u2014 {plan.objective.slice(0, 80)}{plan.objective.length > 80 ? \"...\" : \"\"}</span>\n )}\n </span>\n {plan.wave != null && (\n <span style={{ ...muted, fontSize: 11 }}>\n wave {plan.wave}\n </span>\n )}\n </div>\n ))}\n </>\n )}\n </div>\n );\n}\n\n// --- Sync Toolbar Button ---\n\nexport function GsdSyncButton({ context }: PluginDetailTabProps) {\n const syncProject = usePluginAction(\"sync-project\");\n const toast = usePluginToast();\n\n const handleSync = async () => {\n await syncProject({\n projectId: context.entityId,\n companyId: context.companyId,\n });\n toast({ title: \"GSD synced\", tone: \"success\" });\n };\n\n return (\n <button onClick={handleSync} style={syncButtonStyle}>\n Sync GSD\n </button>\n );\n}\n\n// --- Settings Page ---\n\nexport function GsdSettingsPage({ context }: PluginPageProps) {\n const { data: compatData, loading: compatLoading } = usePluginData<{\n agents: Array<{\n agentId: string;\n agentName: string;\n adapterType: string;\n compatibility: string;\n message: string;\n }>;\n }>(\"gsd-adapter-compat\", { companyId: context.companyId });\n const { data: configData, loading: configLoading, refresh: refreshConfig } = usePluginData<{\n autoSyncEnabled: boolean;\n syncIntervalSeconds: number;\n }>(\"gsd-config\", {});\n const syncAll = usePluginAction(\"sync-all\");\n const updateConfig = usePluginAction(\"update-config\");\n const toast = usePluginToast();\n\n const [autoSync, setAutoSync] = useState<boolean | null>(null);\n const [interval, setInterval] = useState<string>(\"\");\n const [saving, setSaving] = useState(false);\n\n // Use local state if set, otherwise fall back to server data\n const currentAutoSync = autoSync ?? configData?.autoSyncEnabled ?? true;\n const currentInterval = interval || String(configData?.syncIntervalSeconds ?? 30);\n\n const handleSyncAll = async () => {\n const result = (await syncAll({\n companyId: context.companyId,\n })) as { ok: boolean; synced: number } | undefined;\n toast({\n title: `Synced ${result?.synced ?? 0} workspace(s)`,\n tone: \"success\",\n });\n };\n\n const handleSaveConfig = async () => {\n const parsedInterval = Math.max(10, Math.min(600, Number(currentInterval) || 30));\n setSaving(true);\n try {\n await updateConfig({\n autoSyncEnabled: currentAutoSync,\n syncIntervalSeconds: parsedInterval,\n });\n refreshConfig();\n setAutoSync(null);\n setInterval(\"\");\n toast({ title: \"Settings saved\", tone: \"success\" });\n } catch {\n toast({ title: \"Failed to save settings\", tone: \"error\" });\n } finally {\n setSaving(false);\n }\n };\n\n const hasChanges =\n autoSync !== null ||\n (interval !== \"\" && Number(interval) !== configData?.syncIntervalSeconds);\n\n return (\n <div style={{ maxWidth: 640 }}>\n <div style={heading}>GSD Settings</div>\n\n {/* Auto-sync configuration */}\n <div style={{ ...card, marginBottom: 24 }}>\n <div style={{ ...heading, marginBottom: 12 }}>Auto-Sync</div>\n\n {configLoading ? (\n <div style={muted}>Loading configuration...</div>\n ) : (\n <>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 12, marginBottom: 12 }}>\n <label style={{ display: \"flex\", alignItems: \"center\", gap: 8, cursor: \"pointer\" }}>\n <input\n type=\"checkbox\"\n checked={currentAutoSync}\n onChange={(e) => setAutoSync(e.target.checked)}\n style={{ width: 16, height: 16, cursor: \"pointer\" }}\n />\n <span>Enable periodic sync</span>\n </label>\n </div>\n\n <div style={{ marginBottom: 12 }}>\n <label style={{ display: \"block\", marginBottom: 4 }}>\n <span style={muted}>Sync interval (seconds, 10\\u2013600)</span>\n </label>\n <input\n type=\"number\"\n min={10}\n max={600}\n value={currentInterval}\n onChange={(e) => setInterval(e.target.value)}\n disabled={!currentAutoSync}\n style={{\n ...inputStyle,\n opacity: currentAutoSync ? 1 : 0.5,\n }}\n />\n </div>\n\n <div style={{ display: \"flex\", gap: 8 }}>\n <button\n onClick={handleSaveConfig}\n disabled={saving || !hasChanges}\n style={{\n ...syncButtonStyle,\n opacity: saving || !hasChanges ? 0.5 : 1,\n }}\n >\n {saving ? \"Saving...\" : \"Save\"}\n </button>\n <button onClick={handleSyncAll} style={syncButtonStyle}>\n Sync All Projects\n </button>\n </div>\n </>\n )}\n </div>\n\n {/* Agent compatibility */}\n <div style={heading}>Agent Compatibility</div>\n {compatLoading && <div style={muted}>Loading...</div>}\n\n {compatData?.agents.map((agent) => (\n <div key={agent.agentId} style={card}>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <strong>{agent.agentName}</strong>\n <span\n style={badge(\n agent.compatibility === \"supported\"\n ? \"#22c55e\"\n : agent.compatibility === \"partial\"\n ? \"#f59e0b\"\n : \"#ef4444\",\n )}\n >\n {agent.compatibility}\n </span>\n </div>\n <div style={{ ...muted, marginTop: 4 }}>\n {agent.adapterType} \u2014 {agent.message}\n </div>\n </div>\n ))}\n\n {!compatLoading && (!compatData?.agents || compatData.agents.length === 0) && (\n <div style={muted}>No agents found for this company.</div>\n )}\n </div>\n );\n}\n\n// --- Shared styles ---\n\nconst artifactBadge: React.CSSProperties = {\n fontSize: 11,\n color: \"var(--text-tertiary, #9ca3af)\",\n border: \"1px solid var(--border-secondary, #374151)\",\n borderRadius: 4,\n padding: \"1px 6px\",\n};\n\nconst syncButtonStyle: React.CSSProperties = {\n padding: \"6px 16px\",\n borderRadius: 6,\n border: \"1px solid var(--border-secondary, #374151)\",\n background: \"var(--bg-secondary, #1f2937)\",\n color: \"var(--text-primary, #e5e7eb)\",\n cursor: \"pointer\",\n fontSize: 13,\n fontWeight: 500,\n};\n\nconst inputStyle: React.CSSProperties = {\n padding: \"6px 10px\",\n borderRadius: 6,\n border: \"1px solid var(--border-secondary, #374151)\",\n background: \"var(--bg-primary, #111827)\",\n color: \"var(--text-primary, #e5e7eb)\",\n fontSize: 13,\n width: 120,\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }