@programinglive/dev-workflow-mcp-server 1.5.2 → 1.5.4

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 (78) hide show
  1. package/.agent/workflows/dev-workflow-bugfix.md +250 -250
  2. package/.agent/workflows/dev-workflow-feature.md +201 -201
  3. package/.agent/workflows/dev-workflow-full-cycle.md +400 -400
  4. package/.agent/workflows/dev-workflow-refactor.md +238 -238
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +34 -34
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +25 -25
  7. package/.github/pull_request_template.md +22 -22
  8. package/.github/workflows/github-release.yml +56 -0
  9. package/.github/workflows/npm-publish.yml +50 -50
  10. package/.husky/commit-msg +0 -0
  11. package/CHANGELOG.md +759 -741
  12. package/CODE_OF_CONDUCT.md +79 -79
  13. package/CONTRIBUTING.md +60 -60
  14. package/LICENSE +21 -21
  15. package/README.md +632 -632
  16. package/SECURITY.md +20 -20
  17. package/db/index.js +204 -204
  18. package/docs/NETLIFY_DEPLOYMENT.md +125 -125
  19. package/docs/PLESK_DEPLOYMENT.md +170 -170
  20. package/docs/WORKFLOW-BEST-PRACTICES.md +58 -58
  21. package/docs/antigravity/EXAMPLES.md +535 -535
  22. package/docs/antigravity/GETTING-STARTED.md +292 -292
  23. package/docs/antigravity/TROUBLESHOOTING.md +742 -742
  24. package/docs/antigravity/WALKTHROUGH.md +25 -25
  25. package/docs/antigravity/WORKFLOW-TEMPLATES.md +670 -670
  26. package/docs/product/PRD.md +67 -67
  27. package/docs/release-notes/RELEASE_NOTES.md +233 -226
  28. package/docs/web-dashboard.md +175 -175
  29. package/exec.js +49 -49
  30. package/index.js +279 -279
  31. package/install.js +73 -73
  32. package/package.json +4 -4
  33. package/release-wrapper.js +192 -192
  34. package/scripts/build-docs.js +63 -63
  35. package/scripts/extract-release-notes.cjs +78 -0
  36. package/scripts/hello-world.js +1 -1
  37. package/scripts/release.cjs +252 -252
  38. package/scripts/release.js +252 -0
  39. package/scripts/update-release-notes.cjs +178 -178
  40. package/scripts/update-release-notes.js +182 -0
  41. package/server.json +23 -23
  42. package/tailwind.config.js +8 -8
  43. package/tests/build.test.js +83 -83
  44. package/tests/exec.test.js +35 -35
  45. package/tests/handlers.test.js +1058 -1058
  46. package/tests/hello-world.test.js +13 -13
  47. package/tests/mcpRegistry.test.js +65 -65
  48. package/tests/patch-release.test.js +7 -0
  49. package/tests/release-wrapper.test.js +107 -107
  50. package/tests/workflowState.test.js +505 -505
  51. package/tools/definitions.js +332 -332
  52. package/tools/handlers.js +1019 -1019
  53. package/vite.config.js +43 -43
  54. package/vite.web.config.js +23 -23
  55. package/web/README.md +36 -36
  56. package/web/app/docs/page.tsx +202 -202
  57. package/web/app/globals.css +90 -90
  58. package/web/app/layout.tsx +36 -36
  59. package/web/app/page.tsx +15 -15
  60. package/web/components/ApiReference.tsx +20 -20
  61. package/web/components/Features.tsx +61 -61
  62. package/web/components/Footer.tsx +9 -9
  63. package/web/components/Hero.tsx +96 -96
  64. package/web/components/History.tsx +143 -143
  65. package/web/components/Navbar.tsx +64 -64
  66. package/web/components/Terminal.tsx +114 -114
  67. package/web/eslint.config.mjs +18 -18
  68. package/web/lib/db.js +131 -131
  69. package/web/lib/docs.js +73 -73
  70. package/web/netlify.toml +3 -3
  71. package/web/next.config.ts +12 -12
  72. package/web/package-lock.json +6560 -6560
  73. package/web/package.json +28 -28
  74. package/web/postcss.config.mjs +9 -9
  75. package/web/server.js +31 -31
  76. package/web/tailwind.config.ts +19 -19
  77. package/web/tsconfig.json +42 -42
  78. package/workflow-state.js +612 -612
@@ -1,96 +1,96 @@
1
- "use client";
2
-
3
- import Link from "next/link";
4
- import { ArrowRight } from "lucide-react";
5
- import Terminal from "./Terminal";
6
- import { useEffect, useState } from "react";
7
-
8
- export default function Hero() {
9
- const [downloads, setDownloads] = useState<number | null>(null);
10
- const [version, setVersion] = useState<string | null>(null);
11
-
12
- useEffect(() => {
13
- // Fetch npm downloads directly from npm API
14
- fetch("https://api.npmjs.org/downloads/point/last-month/@programinglive/dev-workflow-mcp-server")
15
- .then(res => res.json())
16
- .then(data => setDownloads(data.downloads || 0))
17
- .catch(() => setDownloads(null));
18
-
19
- // Version is hardcoded for static export
20
- setVersion("1.5.1");
21
- }, []);
22
-
23
- const formatDownloads = (num: number) => {
24
- if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;
25
- if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;
26
- return num.toString();
27
- };
28
-
29
- return (
30
- <section className="min-h-screen flex items-center justify-center px-4 pt-16 relative overflow-hidden">
31
- <div className="absolute inset-0 bg-gradient-to-br from-indigo-500/10 via-purple-500/10 to-pink-500/10"></div>
32
- <div className="max-w-7xl mx-auto grid lg:grid-cols-2 gap-12 items-center relative z-10">
33
- {/* Left Column - Content */}
34
- <div>
35
- <div className="animate-fade-in-up" style={{ animationDelay: "0.1s" }}>
36
- <div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-sm mb-8">
37
- <span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span>
38
- <span>v{version ?? "..."} - Active</span>
39
- </div>
40
- </div>
41
-
42
- <h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold mb-6 leading-tight animate-fade-in-up" style={{ animationDelay: "0.2s" }}>
43
- Master Your<br />
44
- <span className="bg-gradient-to-r from-indigo-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">Workflow</span>
45
- </h1>
46
- <p className="text-lg md:text-xl text-gray-400 mb-8 max-w-xl animate-fade-in-up" style={{ animationDelay: "0.3s" }}>
47
- An MCP server that acts as your coding conscience. Enforce test-driven development, ensure documentation, and never skip a step in your release process.
48
- </p>
49
- <div className="flex flex-col sm:flex-row gap-4 mb-8 animate-fade-in-up" style={{ animationDelay: "0.4s" }}>
50
- <Link href="#history" className="px-6 py-3 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-lg font-semibold hover:shadow-lg hover:shadow-indigo-500/50 transition inline-flex items-center justify-center gap-2">
51
- View History <ArrowRight className="w-4 h-4" />
52
- </Link>
53
- <Link href="/docs" className="px-6 py-3 bg-white/5 border border-white/10 rounded-lg font-semibold hover:bg-white/10 transition text-center">
54
- Documentation
55
- </Link>
56
- </div>
57
- <div className="flex flex-wrap gap-6 sm:gap-8 text-sm animate-fade-in-up" style={{ animationDelay: "0.5s" }}>
58
- <div>
59
- <div className="text-2xl font-bold">{version ?? "..."}</div>
60
- <div className="text-gray-500">Latest Version</div>
61
- </div>
62
- <div>
63
- <div className="text-2xl font-bold">MIT</div>
64
- <div className="text-gray-500">License</div>
65
- </div>
66
- <div>
67
- <div className="text-2xl font-bold">Node 18+</div>
68
- <div className="text-gray-500">Compatibility</div>
69
- </div>
70
- {downloads !== null && (
71
- <div>
72
- <div className="text-2xl font-bold">{formatDownloads(downloads)}</div>
73
- <div className="text-gray-500">Downloads/mo</div>
74
- </div>
75
- )}
76
- </div>
77
- </div>
78
- {/* Right Column - Terminal */}
79
- <div className="hidden lg:block">
80
- <div className="relative">
81
- <div className="absolute inset-0 bg-gradient-to-r from-indigo-500/20 to-purple-500/20 blur-3xl"></div>
82
- <div className="relative bg-[#1a1a24] rounded-xl border border-white/10 p-6 shadow-2xl">
83
- <div className="flex items-center gap-2 mb-4">
84
- <div className="w-3 h-3 rounded-full bg-red-500"></div>
85
- <div className="w-3 h-3 rounded-full bg-yellow-500"></div>
86
- <div className="w-3 h-3 rounded-full bg-green-500"></div>
87
- <span className="ml-auto text-xs text-gray-500">terminal</span>
88
- </div>
89
- <Terminal />
90
- </div>
91
- </div>
92
- </div>
93
- </div>
94
- </section>
95
- );
96
- }
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { ArrowRight } from "lucide-react";
5
+ import Terminal from "./Terminal";
6
+ import { useEffect, useState } from "react";
7
+
8
+ export default function Hero() {
9
+ const [downloads, setDownloads] = useState<number | null>(null);
10
+ const [version, setVersion] = useState<string | null>(null);
11
+
12
+ useEffect(() => {
13
+ // Fetch npm downloads directly from npm API
14
+ fetch("https://api.npmjs.org/downloads/point/last-month/@programinglive/dev-workflow-mcp-server")
15
+ .then(res => res.json())
16
+ .then(data => setDownloads(data.downloads || 0))
17
+ .catch(() => setDownloads(null));
18
+
19
+ // Version is hardcoded for static export
20
+ setVersion("1.5.3");
21
+ }, []);
22
+
23
+ const formatDownloads = (num: number) => {
24
+ if (num >= 1000000) return `${(num / 1000000).toFixed(1)}M`;
25
+ if (num >= 1000) return `${(num / 1000).toFixed(1)}K`;
26
+ return num.toString();
27
+ };
28
+
29
+ return (
30
+ <section className="min-h-screen flex items-center justify-center px-4 pt-16 relative overflow-hidden">
31
+ <div className="absolute inset-0 bg-gradient-to-br from-indigo-500/10 via-purple-500/10 to-pink-500/10"></div>
32
+ <div className="max-w-7xl mx-auto grid lg:grid-cols-2 gap-12 items-center relative z-10">
33
+ {/* Left Column - Content */}
34
+ <div>
35
+ <div className="animate-fade-in-up" style={{ animationDelay: "0.1s" }}>
36
+ <div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-sm mb-8">
37
+ <span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse"></span>
38
+ <span>v{version ?? "..."} - Active</span>
39
+ </div>
40
+ </div>
41
+
42
+ <h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-bold mb-6 leading-tight animate-fade-in-up" style={{ animationDelay: "0.2s" }}>
43
+ Master Your<br />
44
+ <span className="bg-gradient-to-r from-indigo-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">Workflow</span>
45
+ </h1>
46
+ <p className="text-lg md:text-xl text-gray-400 mb-8 max-w-xl animate-fade-in-up" style={{ animationDelay: "0.3s" }}>
47
+ An MCP server that acts as your coding conscience. Enforce test-driven development, ensure documentation, and never skip a step in your release process.
48
+ </p>
49
+ <div className="flex flex-col sm:flex-row gap-4 mb-8 animate-fade-in-up" style={{ animationDelay: "0.4s" }}>
50
+ <Link href="#history" className="px-6 py-3 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-lg font-semibold hover:shadow-lg hover:shadow-indigo-500/50 transition inline-flex items-center justify-center gap-2">
51
+ View History <ArrowRight className="w-4 h-4" />
52
+ </Link>
53
+ <Link href="/docs" className="px-6 py-3 bg-white/5 border border-white/10 rounded-lg font-semibold hover:bg-white/10 transition text-center">
54
+ Documentation
55
+ </Link>
56
+ </div>
57
+ <div className="flex flex-wrap gap-6 sm:gap-8 text-sm animate-fade-in-up" style={{ animationDelay: "0.5s" }}>
58
+ <div>
59
+ <div className="text-2xl font-bold">{version ?? "..."}</div>
60
+ <div className="text-gray-500">Latest Version</div>
61
+ </div>
62
+ <div>
63
+ <div className="text-2xl font-bold">MIT</div>
64
+ <div className="text-gray-500">License</div>
65
+ </div>
66
+ <div>
67
+ <div className="text-2xl font-bold">Node 18+</div>
68
+ <div className="text-gray-500">Compatibility</div>
69
+ </div>
70
+ {downloads !== null && (
71
+ <div>
72
+ <div className="text-2xl font-bold">{formatDownloads(downloads)}</div>
73
+ <div className="text-gray-500">Downloads/mo</div>
74
+ </div>
75
+ )}
76
+ </div>
77
+ </div>
78
+ {/* Right Column - Terminal */}
79
+ <div className="hidden lg:block">
80
+ <div className="relative">
81
+ <div className="absolute inset-0 bg-gradient-to-r from-indigo-500/20 to-purple-500/20 blur-3xl"></div>
82
+ <div className="relative bg-[#1a1a24] rounded-xl border border-white/10 p-6 shadow-2xl">
83
+ <div className="flex items-center gap-2 mb-4">
84
+ <div className="w-3 h-3 rounded-full bg-red-500"></div>
85
+ <div className="w-3 h-3 rounded-full bg-yellow-500"></div>
86
+ <div className="w-3 h-3 rounded-full bg-green-500"></div>
87
+ <span className="ml-auto text-xs text-gray-500">terminal</span>
88
+ </div>
89
+ <Terminal />
90
+ </div>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </section>
95
+ );
96
+ }
@@ -1,143 +1,143 @@
1
- "use client";
2
-
3
- import { useState, useEffect } from "react";
4
-
5
- type HistoryItem = {
6
- task_description: string;
7
- created_at: string;
8
- };
9
-
10
- type SummaryData = {
11
- summary: {
12
- totalTasks: number;
13
- };
14
- };
15
-
16
- export default function History() {
17
- const [history, setHistory] = useState<HistoryItem[]>([]);
18
- const [summary, setSummary] = useState<SummaryData | null>(null);
19
- const [page, setPage] = useState(1);
20
- const [totalPages, setTotalPages] = useState(1);
21
- const [filters, setFilters] = useState({
22
- userId: "",
23
- startDate: "",
24
- endDate: ""
25
- });
26
-
27
- const loadData = async () => {
28
- const params = new URLSearchParams({
29
- page: page.toString(),
30
- pageSize: "20",
31
- ...(filters.userId && { user: filters.userId }),
32
- ...(filters.startDate && { startDate: filters.startDate }),
33
- ...(filters.endDate && { endDate: filters.endDate }),
34
- });
35
-
36
- try {
37
- const res = await fetch(`/api/history?${params}`);
38
- const data = await res.json();
39
- setHistory(data.data || []);
40
- setTotalPages(data.totalPages || 1);
41
- } catch (err) {
42
- console.error("Failed to load history", err);
43
- }
44
-
45
- try {
46
- const res = await fetch(`/api/summary?${params}`);
47
- const data = await res.json();
48
- setSummary(data);
49
- } catch (err) {
50
- console.error("Failed to load summary", err);
51
- }
52
- };
53
-
54
- useEffect(() => {
55
- loadData();
56
- }, [page]); // Reload when page changes
57
-
58
- const handleApplyFilters = () => {
59
- setPage(1);
60
- loadData();
61
- };
62
-
63
- return (
64
- <section id="history" className="py-20 px-4 bg-white/5">
65
- <div className="max-w-7xl mx-auto">
66
- <h2 className="text-3xl md:text-4xl font-bold mb-8">Workflow History</h2>
67
- <p className="text-gray-400 mb-12">Track your development progress and analyze your workflow patterns.</p>
68
- <div className="bg-[#0a0a0f] rounded-xl border border-white/10 p-6">
69
- <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4 mb-6">
70
- <input
71
- type="text"
72
- placeholder="User ID"
73
- value={filters.userId}
74
- onChange={(e) => setFilters({ ...filters, userId: e.target.value })}
75
- className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 text-white"
76
- />
77
- <input
78
- type="date"
79
- value={filters.startDate}
80
- onChange={(e) => setFilters({ ...filters, startDate: e.target.value })}
81
- className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 [color-scheme:dark]"
82
- />
83
- <input
84
- type="date"
85
- value={filters.endDate}
86
- onChange={(e) => setFilters({ ...filters, endDate: e.target.value })}
87
- className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 [color-scheme:dark]"
88
- />
89
- <button
90
- onClick={handleApplyFilters}
91
- className="px-4 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-lg font-semibold hover:shadow-lg hover:shadow-indigo-500/50 transition"
92
- >
93
- Apply Filters
94
- </button>
95
- </div>
96
-
97
- {summary && (
98
- <div className="mb-6">
99
- <h3 className="text-lg font-semibold mb-4">Project Summary</h3>
100
- <div className="text-gray-400">
101
- <p>Total tasks: {summary.summary?.totalTasks || 0}</p>
102
- </div>
103
- </div>
104
- )}
105
-
106
- <div>
107
- <h3 className="text-lg font-semibold mb-4">Recent History</h3>
108
- <div className="space-y-3">
109
- {history.length > 0 ? (
110
- history.map((row, i) => (
111
- <div key={i} className="p-4 rounded-lg bg-white/5 border border-white/10">
112
- <div className="font-semibold">{row.task_description}</div>
113
- <div className="text-sm text-gray-400 mt-1">{new Date(row.created_at).toLocaleString()}</div>
114
- </div>
115
- ))
116
- ) : (
117
- <p className="text-gray-500">No history yet.</p>
118
- )}
119
- </div>
120
-
121
- <div className="flex items-center justify-between mt-6">
122
- <button
123
- onClick={() => setPage(p => Math.max(1, p - 1))}
124
- disabled={page <= 1}
125
- className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg hover:bg-white/10 disabled:opacity-50"
126
- >
127
- Previous
128
- </button>
129
- <span className="text-sm text-gray-400">Page {page} of {totalPages}</span>
130
- <button
131
- onClick={() => setPage(p => Math.min(totalPages, p + 1))}
132
- disabled={page >= totalPages}
133
- className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg hover:bg-white/10 disabled:opacity-50"
134
- >
135
- Next
136
- </button>
137
- </div>
138
- </div>
139
- </div>
140
- </div>
141
- </section>
142
- );
143
- }
1
+ "use client";
2
+
3
+ import { useState, useEffect } from "react";
4
+
5
+ type HistoryItem = {
6
+ task_description: string;
7
+ created_at: string;
8
+ };
9
+
10
+ type SummaryData = {
11
+ summary: {
12
+ totalTasks: number;
13
+ };
14
+ };
15
+
16
+ export default function History() {
17
+ const [history, setHistory] = useState<HistoryItem[]>([]);
18
+ const [summary, setSummary] = useState<SummaryData | null>(null);
19
+ const [page, setPage] = useState(1);
20
+ const [totalPages, setTotalPages] = useState(1);
21
+ const [filters, setFilters] = useState({
22
+ userId: "",
23
+ startDate: "",
24
+ endDate: ""
25
+ });
26
+
27
+ const loadData = async () => {
28
+ const params = new URLSearchParams({
29
+ page: page.toString(),
30
+ pageSize: "20",
31
+ ...(filters.userId && { user: filters.userId }),
32
+ ...(filters.startDate && { startDate: filters.startDate }),
33
+ ...(filters.endDate && { endDate: filters.endDate }),
34
+ });
35
+
36
+ try {
37
+ const res = await fetch(`/api/history?${params}`);
38
+ const data = await res.json();
39
+ setHistory(data.data || []);
40
+ setTotalPages(data.totalPages || 1);
41
+ } catch (err) {
42
+ console.error("Failed to load history", err);
43
+ }
44
+
45
+ try {
46
+ const res = await fetch(`/api/summary?${params}`);
47
+ const data = await res.json();
48
+ setSummary(data);
49
+ } catch (err) {
50
+ console.error("Failed to load summary", err);
51
+ }
52
+ };
53
+
54
+ useEffect(() => {
55
+ loadData();
56
+ }, [page]); // Reload when page changes
57
+
58
+ const handleApplyFilters = () => {
59
+ setPage(1);
60
+ loadData();
61
+ };
62
+
63
+ return (
64
+ <section id="history" className="py-20 px-4 bg-white/5">
65
+ <div className="max-w-7xl mx-auto">
66
+ <h2 className="text-3xl md:text-4xl font-bold mb-8">Workflow History</h2>
67
+ <p className="text-gray-400 mb-12">Track your development progress and analyze your workflow patterns.</p>
68
+ <div className="bg-[#0a0a0f] rounded-xl border border-white/10 p-6">
69
+ <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4 mb-6">
70
+ <input
71
+ type="text"
72
+ placeholder="User ID"
73
+ value={filters.userId}
74
+ onChange={(e) => setFilters({ ...filters, userId: e.target.value })}
75
+ className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 text-white"
76
+ />
77
+ <input
78
+ type="date"
79
+ value={filters.startDate}
80
+ onChange={(e) => setFilters({ ...filters, startDate: e.target.value })}
81
+ className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 [color-scheme:dark]"
82
+ />
83
+ <input
84
+ type="date"
85
+ value={filters.endDate}
86
+ onChange={(e) => setFilters({ ...filters, endDate: e.target.value })}
87
+ className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 [color-scheme:dark]"
88
+ />
89
+ <button
90
+ onClick={handleApplyFilters}
91
+ className="px-4 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 rounded-lg font-semibold hover:shadow-lg hover:shadow-indigo-500/50 transition"
92
+ >
93
+ Apply Filters
94
+ </button>
95
+ </div>
96
+
97
+ {summary && (
98
+ <div className="mb-6">
99
+ <h3 className="text-lg font-semibold mb-4">Project Summary</h3>
100
+ <div className="text-gray-400">
101
+ <p>Total tasks: {summary.summary?.totalTasks || 0}</p>
102
+ </div>
103
+ </div>
104
+ )}
105
+
106
+ <div>
107
+ <h3 className="text-lg font-semibold mb-4">Recent History</h3>
108
+ <div className="space-y-3">
109
+ {history.length > 0 ? (
110
+ history.map((row, i) => (
111
+ <div key={i} className="p-4 rounded-lg bg-white/5 border border-white/10">
112
+ <div className="font-semibold">{row.task_description}</div>
113
+ <div className="text-sm text-gray-400 mt-1">{new Date(row.created_at).toLocaleString()}</div>
114
+ </div>
115
+ ))
116
+ ) : (
117
+ <p className="text-gray-500">No history yet.</p>
118
+ )}
119
+ </div>
120
+
121
+ <div className="flex items-center justify-between mt-6">
122
+ <button
123
+ onClick={() => setPage(p => Math.max(1, p - 1))}
124
+ disabled={page <= 1}
125
+ className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg hover:bg-white/10 disabled:opacity-50"
126
+ >
127
+ Previous
128
+ </button>
129
+ <span className="text-sm text-gray-400">Page {page} of {totalPages}</span>
130
+ <button
131
+ onClick={() => setPage(p => Math.min(totalPages, p + 1))}
132
+ disabled={page >= totalPages}
133
+ className="px-4 py-2 bg-white/5 border border-white/10 rounded-lg hover:bg-white/10 disabled:opacity-50"
134
+ >
135
+ Next
136
+ </button>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </section>
142
+ );
143
+ }
@@ -1,64 +1,64 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import Link from "next/link";
5
- import { Github, Menu, X } from "lucide-react";
6
- import Image from "next/image";
7
-
8
- export default function Navbar() {
9
- const [isOpen, setIsOpen] = useState(false);
10
-
11
- return (
12
- <nav className="fixed top-0 left-0 right-0 z-50 bg-[#0a0a0f]/80 backdrop-blur-lg border-b border-white/10">
13
- <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
14
- <div className="flex items-center justify-between h-16">
15
- <Link href="/" className="flex items-center gap-2">
16
- <Image src="/assets/logo.png" alt="Dev Workflow" width={32} height={32} className="rounded-lg" />
17
- <span className="text-lg font-bold">Dev Workflow</span>
18
- </Link>
19
- <div className="hidden md:flex items-center gap-6">
20
- <Link href="/#features" className="text-gray-300 hover:text-white transition">Features</Link>
21
- <Link href="/#history" className="text-gray-300 hover:text-white transition">History</Link>
22
- <Link href="/#api" className="text-gray-300 hover:text-white transition">API</Link>
23
- <Link href="/docs" className="text-gray-300 hover:text-white transition">Docs</Link>
24
- <a
25
- href="https://github.com/programinglive/dev-workflow-mcp-server"
26
- target="_blank"
27
- rel="noopener noreferrer"
28
- className="flex items-center gap-2 px-4 py-2 bg-white/5 hover:bg-white/10 rounded-lg transition"
29
- >
30
- <Github className="w-4 h-4" />
31
- GitHub
32
- </a>
33
- </div>
34
- <button
35
- className="md:hidden p-2 rounded-lg hover:bg-white/5"
36
- onClick={() => setIsOpen(!isOpen)}
37
- >
38
- {isOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
39
- </button>
40
- </div>
41
- </div>
42
- {/* Mobile Menu */}
43
- {isOpen && (
44
- <div className="md:hidden border-t border-white/10 bg-[#0a0a0f]">
45
- <div className="px-4 py-4 space-y-3">
46
- <Link href="/#features" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>Features</Link>
47
- <Link href="/#history" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>History</Link>
48
- <Link href="/#api" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>API</Link>
49
- <Link href="/docs" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>Docs</Link>
50
- <a
51
- href="https://github.com/programinglive/dev-workflow-mcp-server"
52
- target="_blank"
53
- rel="noopener noreferrer"
54
- className="flex items-center gap-2 text-gray-300 hover:text-white transition"
55
- >
56
- <Github className="w-4 h-4" />
57
- GitHub
58
- </a>
59
- </div>
60
- </div>
61
- )}
62
- </nav>
63
- );
64
- }
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import Link from "next/link";
5
+ import { Github, Menu, X } from "lucide-react";
6
+ import Image from "next/image";
7
+
8
+ export default function Navbar() {
9
+ const [isOpen, setIsOpen] = useState(false);
10
+
11
+ return (
12
+ <nav className="fixed top-0 left-0 right-0 z-50 bg-[#0a0a0f]/80 backdrop-blur-lg border-b border-white/10">
13
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
14
+ <div className="flex items-center justify-between h-16">
15
+ <Link href="/" className="flex items-center gap-2">
16
+ <Image src="/assets/logo.png" alt="Dev Workflow" width={32} height={32} className="rounded-lg" />
17
+ <span className="text-lg font-bold">Dev Workflow</span>
18
+ </Link>
19
+ <div className="hidden md:flex items-center gap-6">
20
+ <Link href="/#features" className="text-gray-300 hover:text-white transition">Features</Link>
21
+ <Link href="/#history" className="text-gray-300 hover:text-white transition">History</Link>
22
+ <Link href="/#api" className="text-gray-300 hover:text-white transition">API</Link>
23
+ <Link href="/docs" className="text-gray-300 hover:text-white transition">Docs</Link>
24
+ <a
25
+ href="https://github.com/programinglive/dev-workflow-mcp-server"
26
+ target="_blank"
27
+ rel="noopener noreferrer"
28
+ className="flex items-center gap-2 px-4 py-2 bg-white/5 hover:bg-white/10 rounded-lg transition"
29
+ >
30
+ <Github className="w-4 h-4" />
31
+ GitHub
32
+ </a>
33
+ </div>
34
+ <button
35
+ className="md:hidden p-2 rounded-lg hover:bg-white/5"
36
+ onClick={() => setIsOpen(!isOpen)}
37
+ >
38
+ {isOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
39
+ </button>
40
+ </div>
41
+ </div>
42
+ {/* Mobile Menu */}
43
+ {isOpen && (
44
+ <div className="md:hidden border-t border-white/10 bg-[#0a0a0f]">
45
+ <div className="px-4 py-4 space-y-3">
46
+ <Link href="/#features" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>Features</Link>
47
+ <Link href="/#history" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>History</Link>
48
+ <Link href="/#api" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>API</Link>
49
+ <Link href="/docs" className="block text-gray-300 hover:text-white transition" onClick={() => setIsOpen(false)}>Docs</Link>
50
+ <a
51
+ href="https://github.com/programinglive/dev-workflow-mcp-server"
52
+ target="_blank"
53
+ rel="noopener noreferrer"
54
+ className="flex items-center gap-2 text-gray-300 hover:text-white transition"
55
+ >
56
+ <Github className="w-4 h-4" />
57
+ GitHub
58
+ </a>
59
+ </div>
60
+ </div>
61
+ )}
62
+ </nav>
63
+ );
64
+ }