agent-workflow-kit-cli 1.3.5 โ†’ 1.3.6

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 (31) hide show
  1. package/dist/cli/commands/create.js +162 -0
  2. package/dist/cli/index.js +15 -1
  3. package/package.json +1 -1
  4. package/templates/react-ts/project/.gitignore.hbs +24 -0
  5. package/templates/react-ts/project/eslint.config.js.hbs +34 -0
  6. package/templates/react-ts/project/index.html.hbs +17 -0
  7. package/templates/react-ts/project/package.json.hbs +28 -0
  8. package/templates/react-ts/project/src/App.tsx.hbs +60 -0
  9. package/templates/react-ts/project/src/components/Counter.tsx.hbs +16 -0
  10. package/templates/react-ts/project/src/components/ThemeToggle.tsx.hbs +29 -0
  11. package/templates/react-ts/project/src/hooks/useLocalStorage.ts.hbs +25 -0
  12. package/templates/react-ts/project/src/main.tsx.hbs +10 -0
  13. package/templates/react-ts/project/src/services/api.ts.hbs +16 -0
  14. package/templates/react-ts/project/src/styles/App.css.hbs +143 -0
  15. package/templates/react-ts/project/src/styles/index.css.hbs +34 -0
  16. package/templates/react-ts/project/src/vite-env.d.ts.hbs +1 -0
  17. package/templates/react-ts/project/tsconfig.app.json.hbs +26 -0
  18. package/templates/react-ts/project/tsconfig.json.hbs +7 -0
  19. package/templates/react-ts/project/tsconfig.node.json.hbs +24 -0
  20. package/templates/react-ts/project/vite.config.ts.hbs +7 -0
  21. package/templates/spring-boot/project/.gitignore.hbs +28 -0
  22. package/templates/spring-boot/project/pom.xml.hbs +69 -0
  23. package/templates/spring-boot/project/src/main/java/com/example/packageName/DemoApplication.java.hbs +13 -0
  24. package/templates/spring-boot/project/src/main/java/com/example/packageName/controller/UserController.java.hbs +37 -0
  25. package/templates/spring-boot/project/src/main/java/com/example/packageName/dto/UserDTO.java.hbs +16 -0
  26. package/templates/spring-boot/project/src/main/java/com/example/packageName/entity/User.java.hbs +27 -0
  27. package/templates/spring-boot/project/src/main/java/com/example/packageName/repository/UserRepository.java.hbs +9 -0
  28. package/templates/spring-boot/project/src/main/java/com/example/packageName/service/UserService.java.hbs +11 -0
  29. package/templates/spring-boot/project/src/main/java/com/example/packageName/service/impl/UserServiceImpl.java.hbs +55 -0
  30. package/templates/spring-boot/project/src/main/resources/application.yml.hbs +20 -0
  31. package/templates/spring-boot/project/src/test/java/com/example/packageName/DemoApplicationTests.java.hbs +13 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @license
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+ import chalk from "chalk";
6
+ import { promises as fs } from "fs";
7
+ import path from "path";
8
+ import { fileURLToPath } from "url";
9
+ import { runInit } from "./init.js";
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const TEMPLATES_DIR = path.resolve(__dirname, "../../../templates");
13
+ export async function runCreate(template, projectNameInput, options) {
14
+ console.log(chalk.bold.cyan("\n๐Ÿš€ Agent Workflow Kit - Creating New Project..."));
15
+ console.log(chalk.dim("------------------------------------------"));
16
+ const validTemplates = ["spring-boot", "react-ts"];
17
+ if (!validTemplates.includes(template)) {
18
+ console.error(chalk.red(`Error: Invalid template '${template}'. Supported templates are: ${validTemplates.join(", ")}`));
19
+ process.exit(1);
20
+ }
21
+ const projectName = projectNameInput || `my-${template}-project`;
22
+ const targetDir = path.resolve(process.cwd(), projectName);
23
+ console.log(`${chalk.bold("Template:")} ${chalk.green(template)}`);
24
+ console.log(`${chalk.bold("Project Name:")} ${chalk.green(projectName)}`);
25
+ console.log(`${chalk.bold("Target Dir:")} ${chalk.green(targetDir)}`);
26
+ console.log(`${chalk.bold("Dry Run:")} ${options.dryRun ? chalk.yellow("Enabled ๐Ÿงช") : chalk.gray("Disabled")}`);
27
+ console.log(chalk.dim("------------------------------------------\n"));
28
+ // Verify target directory doesn't exist or is empty
29
+ try {
30
+ const stat = await fs.stat(targetDir);
31
+ if (stat.isDirectory()) {
32
+ const files = await fs.readdir(targetDir);
33
+ if (files.length > 0) {
34
+ console.error(chalk.red(`Error: Directory '${targetDir}' already exists and is not empty.`));
35
+ process.exit(1);
36
+ }
37
+ }
38
+ }
39
+ catch {
40
+ // Directory doesn't exist, which is fine
41
+ }
42
+ const templateProjectDir = path.join(TEMPLATES_DIR, template, "project");
43
+ // Verify template project skeleton exists
44
+ try {
45
+ await fs.access(templateProjectDir);
46
+ }
47
+ catch {
48
+ console.error(chalk.red(`Error: Project template for '${template}' was not found.`));
49
+ process.exit(1);
50
+ }
51
+ const safePackageName = projectName
52
+ .toLowerCase()
53
+ .replace(/[^a-z0-9]/g, "");
54
+ if (options.dryRun) {
55
+ console.log(chalk.yellow(`[Dry Run] Would create project directory: ${targetDir}`));
56
+ await listTemplateFilesDry(templateProjectDir, templateProjectDir, targetDir, safePackageName);
57
+ console.log(chalk.bold.green("\n๐ŸŽ‰ Dry Run completed successfully!"));
58
+ return;
59
+ }
60
+ // Create project directory
61
+ await fs.mkdir(targetDir, { recursive: true });
62
+ // Copy and interpolate template files
63
+ await copyAndInterpolate(templateProjectDir, templateProjectDir, targetDir, projectName, safePackageName);
64
+ console.log(chalk.green(`โœ”๏ธ Project skeleton for ${template} created successfully.`));
65
+ // Initialize agent guidelines in the new project directory
66
+ console.log(chalk.cyan("\nInitializing AI agent guidelines inside project..."));
67
+ const originalCwd = process.cwd();
68
+ try {
69
+ process.chdir(targetDir);
70
+ await runInit({
71
+ stack: template,
72
+ agent: "both",
73
+ dryRun: false,
74
+ });
75
+ }
76
+ catch (err) {
77
+ console.error(chalk.red(`Warning: Failed to initialize agent guidelines: ${err instanceof Error ? err.message : String(err)}`));
78
+ }
79
+ finally {
80
+ process.chdir(originalCwd);
81
+ }
82
+ printCreateSuccess(projectName, template);
83
+ }
84
+ async function listTemplateFilesDry(baseSrc, currentSrc, destDir, safePackageName) {
85
+ const entries = await fs.readdir(currentSrc, { withFileTypes: true });
86
+ for (const entry of entries) {
87
+ const srcPath = path.join(currentSrc, entry.name);
88
+ // Resolve entry destination name (mapping packageName to safePackageName)
89
+ let destName = entry.name;
90
+ if (entry.name === "packageName") {
91
+ destName = safePackageName;
92
+ }
93
+ const relativePart = path.relative(baseSrc, srcPath);
94
+ let resolvedRelativePart = relativePart
95
+ .replace(/\\/g, "/")
96
+ .replace(/\bpackageName\b/g, safePackageName);
97
+ if (resolvedRelativePart.endsWith(".hbs")) {
98
+ resolvedRelativePart = resolvedRelativePart.slice(0, -4);
99
+ }
100
+ const targetPath = path.join(destDir, resolvedRelativePart);
101
+ if (entry.isDirectory()) {
102
+ console.log(chalk.gray(`[Dry Run] Would create directory: ${targetPath}`));
103
+ await listTemplateFilesDry(baseSrc, srcPath, destDir, safePackageName);
104
+ }
105
+ else {
106
+ console.log(chalk.gray(`[Dry Run] Would write file: ${targetPath}`));
107
+ }
108
+ }
109
+ }
110
+ async function copyAndInterpolate(baseSrc, currentSrc, destDir, projectName, safePackageName) {
111
+ const entries = await fs.readdir(currentSrc, { withFileTypes: true });
112
+ for (const entry of entries) {
113
+ const srcPath = path.join(currentSrc, entry.name);
114
+ // Resolve destination path (replaces 'packageName' directory or file parts)
115
+ let destName = entry.name;
116
+ if (entry.name === "packageName") {
117
+ destName = safePackageName;
118
+ }
119
+ const relativePart = path.relative(baseSrc, srcPath);
120
+ let resolvedRelativePart = relativePart
121
+ .replace(/\\/g, "/")
122
+ .replace(/\bpackageName\b/g, safePackageName);
123
+ if (resolvedRelativePart.endsWith(".hbs")) {
124
+ resolvedRelativePart = resolvedRelativePart.slice(0, -4);
125
+ }
126
+ const targetPath = path.join(destDir, resolvedRelativePart);
127
+ if (entry.isDirectory()) {
128
+ await fs.mkdir(targetPath, { recursive: true });
129
+ await copyAndInterpolate(baseSrc, srcPath, destDir, projectName, safePackageName);
130
+ }
131
+ else {
132
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
133
+ // Interpolate text files
134
+ const content = await fs.readFile(srcPath, "utf8");
135
+ const interpolated = content
136
+ .replace(/\{\{projectName\}\}/g, projectName)
137
+ .replace(/\{\{safePackageName\}\}/g, safePackageName);
138
+ await fs.writeFile(targetPath, interpolated, "utf8");
139
+ }
140
+ }
141
+ }
142
+ function printCreateSuccess(projectName, template) {
143
+ console.log(chalk.bold.green(`\n๐ŸŽ‰ Project '${projectName}' bootstrapped successfully!`));
144
+ console.log(chalk.bold.cyan("\n๐Ÿ‘‰ Next Steps to run/develop:"));
145
+ console.log(chalk.dim("------------------------------------------"));
146
+ console.log(chalk.white(`1. Change directory:`));
147
+ console.log(chalk.cyan(` cd ${projectName}`));
148
+ if (template === "spring-boot") {
149
+ console.log(chalk.white(`2. Build project using Maven:`));
150
+ console.log(chalk.cyan(` mvn clean install`));
151
+ console.log(chalk.white(`3. Run the Spring Boot application:`));
152
+ console.log(chalk.cyan(` mvn spring-boot:run`));
153
+ }
154
+ else if (template === "react-ts") {
155
+ console.log(chalk.white(`2. Install dependencies:`));
156
+ console.log(chalk.cyan(` npm install`));
157
+ console.log(chalk.white(`3. Start the Vite dev server:`));
158
+ console.log(chalk.cyan(` npm run dev`));
159
+ }
160
+ console.log(chalk.white(`4. Start coding! AI guidelines and rules are already configured.`));
161
+ console.log(chalk.dim("------------------------------------------\n"));
162
+ }
package/dist/cli/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  import { Command } from "commander";
6
6
  import chalk from "chalk";
7
7
  import { runInit } from "./commands/init.js";
8
+ import { runCreate } from "./commands/create.js";
8
9
  import { runUiServer } from "./commands/ui.js";
9
10
  import { runAdd } from "./commands/add.js";
10
11
  import { runSync } from "./commands/sync.js";
@@ -20,7 +21,20 @@ export function runCli() {
20
21
  program
21
22
  .name("agent-workflow-kit")
22
23
  .description("Generate AI coding workflows/rules/templates for Codex and Antigravity")
23
- .version("1.3.5");
24
+ .version("1.3.6");
25
+ program
26
+ .command("create <template> [projectName]")
27
+ .description("Bootstrap a new project structure with AI workflow rules pre-configured")
28
+ .option("--dry-run", "Output actions to console without creating folders", false)
29
+ .action(async (template, projectName, options) => {
30
+ try {
31
+ await runCreate(template, projectName, options);
32
+ }
33
+ catch (err) {
34
+ console.error(chalk.red(`Error running create: ${err instanceof Error ? err.message : String(err)}`));
35
+ process.exit(1);
36
+ }
37
+ });
24
38
  program
25
39
  .command("init")
26
40
  .description("Initialize agent guidelines and skills for the repository")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-workflow-kit-cli",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "AI-Ready Repository Workflow Generator & Guideline Optimizer for Codex and Antigravity",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,24 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
@@ -0,0 +1,34 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from '@typescript-eslint/eslint-plugin'
6
+ import tsparser from '@typescript-eslint/parser'
7
+
8
+ export default [
9
+ { ignores: ['dist'] },
10
+ {
11
+ files: ['**/*.{ts,tsx}'],
12
+ languageOptions: {
13
+ ecmaVersion: 2020,
14
+ globals: globals.browser,
15
+ parser: tsparser,
16
+ parserOptions: {
17
+ project: ['./tsconfig.app.json', './tsconfig.node.json'],
18
+ },
19
+ },
20
+ plugins: {
21
+ 'react-hooks': reactHooks,
22
+ 'react-refresh': reactRefresh,
23
+ '@typescript-eslint': tseslint,
24
+ },
25
+ rules: {
26
+ ...js.configs.recommended.rules,
27
+ ...tseslint.configs.recommended.rules,
28
+ 'react-refresh/only-export-components': [
29
+ 'warn',
30
+ { allowConstantExport: true },
31
+ ],
32
+ },
33
+ },
34
+ ]
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>โš›๏ธ</text></svg>" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>{{projectName}}</title>
8
+ <!-- Modern Outfit typography from Google Fonts -->
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap" rel="stylesheet">
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ <script type="module" src="/src/main.tsx"></script>
16
+ </body>
17
+ </html>
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "react": "^18.3.1",
14
+ "react-dom": "^18.3.1"
15
+ },
16
+ "devDependencies": {
17
+ "@types/react": "^18.3.12",
18
+ "@types/react-dom": "^18.3.1",
19
+ "@typescript-eslint/eslint-plugin": "^7.15.0",
20
+ "@typescript-eslint/parser": "^7.15.0",
21
+ "@vitejs/plugin-react": "^4.3.4",
22
+ "eslint": "^8.57.0",
23
+ "eslint-plugin-react-hooks": "^4.6.2",
24
+ "eslint-plugin-react-refresh": "^0.4.7",
25
+ "typescript": "^5.5.2",
26
+ "vite": "^5.4.11"
27
+ }
28
+ }
@@ -0,0 +1,60 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { Counter } from './components/Counter'
3
+ import { ThemeToggle } from './components/ThemeToggle'
4
+ import { fetchSystemStatus, SystemStatus } from './services/api'
5
+ import './styles/App.css'
6
+
7
+ function App() {
8
+ const [systemStatus, setSystemStatus] = useState<SystemStatus | null>(null)
9
+ const [loading, setLoading] = useState(true)
10
+
11
+ useEffect(() => {
12
+ fetchSystemStatus()
13
+ .then((status) => {
14
+ setSystemStatus(status)
15
+ setLoading(false)
16
+ })
17
+ .catch((err) => {
18
+ console.error('Failed to load system status:', err)
19
+ setLoading(false)
20
+ })
21
+ }, [])
22
+
23
+ return (
24
+ <div className="container">
25
+ <div className="logo-container">
26
+ <span className="logo react" style={{ fontSize: '4rem', userSelect: 'none' }}>โš›๏ธ</span>
27
+ </div>
28
+
29
+ <h1 className="title">{{projectName}}</h1>
30
+ <p className="subtitle">
31
+ Your AI-Ready React, Vite, and TypeScript project generated with Agent Workflow Kit.
32
+ </p>
33
+
34
+ {/* Standalone Interactive Component */}
35
+ <Counter />
36
+
37
+ {/* Component utilizing custom hooks */}
38
+ <ThemeToggle />
39
+
40
+ {/* Service layer display */}
41
+ <div className="api-status-card">
42
+ {loading ? (
43
+ <span>Loading system API status...</span>
44
+ ) : systemStatus ? (
45
+ <div>
46
+ API Status: <span className="status-badge online">{systemStatus.status}</span> (v{systemStatus.version})
47
+ </div>
48
+ ) : (
49
+ <span>API Status: <span className="status-badge" style={{ backgroundColor: 'rgba(239, 68, 68, 0.15)', color: '#f87171' }}>OFFLINE</span></span>
50
+ )}
51
+ </div>
52
+
53
+ <p className="footer">
54
+ Workflow guidelines and skills are configured in the <code>.agents/</code> directory.
55
+ </p>
56
+ </div>
57
+ )
58
+ }
59
+
60
+ export default App
@@ -0,0 +1,16 @@
1
+ import { useState } from 'react'
2
+
3
+ export function Counter() {
4
+ const [count, setCount] = useState(0)
5
+
6
+ return (
7
+ <div className="card">
8
+ <button className="counter-btn" onClick={() => setCount((c) => c + 1)}>
9
+ Count is {count}
10
+ </button>
11
+ <p className="instruction">
12
+ Edit <code>src/components/Counter.tsx</code> to test stateful hot updates.
13
+ </p>
14
+ </div>
15
+ )
16
+ }
@@ -0,0 +1,29 @@
1
+ import { useEffect } from 'react'
2
+ import { useLocalStorage } from '../hooks/useLocalStorage'
3
+
4
+ export function ThemeToggle() {
5
+ const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'dark')
6
+
7
+ useEffect(() => {
8
+ document.documentElement.setAttribute('data-theme', theme)
9
+ if (theme === 'light') {
10
+ document.body.style.backgroundColor = '#f8fafc'
11
+ document.body.style.color = '#0f172a'
12
+ } else {
13
+ document.body.style.backgroundColor = '#0b0f19'
14
+ document.body.style.color = '#e2e8f0'
15
+ }
16
+ }, [theme])
17
+
18
+ const toggleTheme = () => {
19
+ setTheme((prev) => (prev === 'light' ? 'dark' : 'light'))
20
+ }
21
+
22
+ return (
23
+ <div className="theme-toggle-container">
24
+ <button className="theme-btn" onClick={toggleTheme}>
25
+ {theme === 'light' ? '๐ŸŒ™ Dark Mode' : 'โ˜€๏ธ Light Mode'}
26
+ </button>
27
+ </div>
28
+ )
29
+ }
@@ -0,0 +1,25 @@
1
+ import { useState, Dispatch, SetStateAction } from 'react'
2
+
3
+ export function useLocalStorage<T>(key: string, initialValue: T): [T, Dispatch<SetStateAction<T>>] {
4
+ const [storedValue, setStoredValue] = useState<T>(() => {
5
+ try {
6
+ const item = window.localStorage.getItem(key)
7
+ return item ? JSON.parse(item) : initialValue
8
+ } catch (error) {
9
+ console.warn(`Error reading localStorage key "${key}":`, error)
10
+ return initialValue
11
+ }
12
+ })
13
+
14
+ const setValue: Dispatch<SetStateAction<T>> = (value) => {
15
+ try {
16
+ const valueToStore = value instanceof Function ? value(storedValue) : value
17
+ setStoredValue(valueToStore)
18
+ window.localStorage.setItem(key, JSON.stringify(valueToStore))
19
+ } catch (error) {
20
+ console.warn(`Error setting localStorage key "${key}":`, error)
21
+ }
22
+ }
23
+
24
+ return [storedValue, setValue]
25
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import App from './App.tsx'
4
+ import './styles/index.css'
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ )
@@ -0,0 +1,16 @@
1
+ export interface SystemStatus {
2
+ status: string;
3
+ version: string;
4
+ uptime: number;
5
+ }
6
+
7
+ export async function fetchSystemStatus(): Promise<SystemStatus> {
8
+ // Mock asynchronous API call delay
9
+ await new Promise((resolve) => setTimeout(resolve, 800));
10
+
11
+ return {
12
+ status: 'ONLINE',
13
+ version: '1.0.0',
14
+ uptime: Math.floor(process.uptime ? process.uptime() : performance.now() / 1000)
15
+ };
16
+ }
@@ -0,0 +1,143 @@
1
+ .container {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ gap: 1.5rem;
7
+ }
8
+
9
+ .logo-container {
10
+ display: flex;
11
+ gap: 2rem;
12
+ margin-bottom: 0.5rem;
13
+ }
14
+
15
+ .logo {
16
+ font-size: 4rem;
17
+ user-select: none;
18
+ display: inline-block;
19
+ transition: transform 0.3s;
20
+ }
21
+
22
+ .logo:hover {
23
+ transform: scale(1.15) rotate(10deg);
24
+ }
25
+
26
+ .title {
27
+ font-size: 3.2rem;
28
+ line-height: 1.1;
29
+ font-weight: 800;
30
+ margin: 0;
31
+ background: linear-gradient(135deg, #a5b4fc, #6366f1, #ec4899);
32
+ -webkit-background-clip: text;
33
+ -webkit-text-fill-color: transparent;
34
+ background-clip: text;
35
+ text-shadow: 0 4px 20px rgba(99, 102, 241, 0.15);
36
+ }
37
+
38
+ .subtitle {
39
+ font-size: 1.25rem;
40
+ color: #94a3b8;
41
+ max-width: 600px;
42
+ margin: 0 auto;
43
+ }
44
+
45
+ .card {
46
+ padding: 2.5rem;
47
+ background: rgba(30, 41, 59, 0.4);
48
+ border: 1px solid rgba(255, 255, 255, 0.08);
49
+ border-radius: 1.5rem;
50
+ backdrop-filter: blur(16px);
51
+ -webkit-backdrop-filter: blur(16px);
52
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
53
+ transition: border-color 0.3s, box-shadow 0.3s, transform 0.3s;
54
+ max-width: 480px;
55
+ width: 100%;
56
+ box-sizing: border-box;
57
+ }
58
+
59
+ .card:hover {
60
+ border-color: rgba(99, 102, 241, 0.4);
61
+ box-shadow: 0 15px 35px rgba(99, 102, 241, 0.1);
62
+ transform: translateY(-4px);
63
+ }
64
+
65
+ .counter-btn {
66
+ background: linear-gradient(135deg, #4f46e5, #6366f1);
67
+ color: white;
68
+ border: none;
69
+ padding: 0.75rem 2rem;
70
+ font-size: 1rem;
71
+ font-weight: 600;
72
+ border-radius: 9999px;
73
+ cursor: pointer;
74
+ transition: transform 0.2s, box-shadow 0.2s;
75
+ font-family: inherit;
76
+ box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
77
+ }
78
+
79
+ .counter-btn:hover {
80
+ transform: scale(1.05);
81
+ box-shadow: 0 6px 16px rgba(79, 70, 229, 0.5);
82
+ }
83
+
84
+ .theme-toggle-container {
85
+ margin-top: 1rem;
86
+ }
87
+
88
+ .theme-btn {
89
+ background: rgba(255, 255, 255, 0.05);
90
+ border: 1px solid rgba(255, 255, 255, 0.1);
91
+ color: inherit;
92
+ padding: 0.5rem 1.25rem;
93
+ border-radius: 0.5rem;
94
+ cursor: pointer;
95
+ transition: background 0.2s, border-color 0.2s;
96
+ font-family: inherit;
97
+ font-size: 0.9rem;
98
+ }
99
+
100
+ .theme-btn:hover {
101
+ background: rgba(255, 255, 255, 0.1);
102
+ border-color: rgba(255, 255, 255, 0.2);
103
+ }
104
+
105
+ .api-status-card {
106
+ margin-top: 1rem;
107
+ font-size: 0.9rem;
108
+ color: #94a3b8;
109
+ }
110
+
111
+ .status-badge {
112
+ display: inline-block;
113
+ padding: 0.25rem 0.75rem;
114
+ border-radius: 9999px;
115
+ font-size: 0.8rem;
116
+ font-weight: bold;
117
+ }
118
+
119
+ .status-badge.online {
120
+ background-color: rgba(34, 197, 94, 0.15);
121
+ color: #4ade80;
122
+ border: 1px solid rgba(34, 197, 94, 0.3);
123
+ }
124
+
125
+ .instruction {
126
+ margin-top: 1.5rem;
127
+ font-size: 0.875rem;
128
+ color: #64748b;
129
+ }
130
+
131
+ .instruction code {
132
+ background: rgba(15, 23, 42, 0.6);
133
+ padding: 0.2rem 0.5rem;
134
+ border-radius: 0.25rem;
135
+ font-family: monospace;
136
+ color: #a5b4fc;
137
+ }
138
+
139
+ .footer {
140
+ font-size: 0.875rem;
141
+ color: #475569;
142
+ margin-top: 2rem;
143
+ }
@@ -0,0 +1,34 @@
1
+ :root {
2
+ font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: dark;
7
+ color: #e2e8f0;
8
+ background-color: #0b0f19;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ }
15
+
16
+ body {
17
+ margin: 0;
18
+ display: flex;
19
+ place-items: center;
20
+ min-width: 320px;
21
+ min-height: 100vh;
22
+ background: radial-gradient(circle at top right, rgba(99, 102, 241, 0.15), transparent 40%),
23
+ radial-gradient(circle at bottom left, rgba(236, 72, 153, 0.12), transparent 40%),
24
+ #070a13;
25
+ transition: background-color 0.3s, color 0.3s;
26
+ }
27
+
28
+ #root {
29
+ max-width: 1280px;
30
+ margin: 0 auto;
31
+ padding: 2rem;
32
+ text-align: center;
33
+ width: 100%;
34
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5
+ "target": "ES2020",
6
+ "useDefineForClassFields": true,
7
+ "lib": ["DOM", "DOM.Iterable", "ES2020"],
8
+ "module": "ESNext",
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "noFallthroughCasesInSwitch": true
24
+ },
25
+ "include": ["src"]
26
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
5
+ "target": "ES2022",
6
+ "lib": ["ES2022"],
7
+ "module": "ESNext",
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "resolveJsonModule": true,
14
+ "isolatedModules": true,
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["vite.config.ts"]
24
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ // https://vitejs.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ })
@@ -0,0 +1,28 @@
1
+ target/
2
+ !.mvn/wrapper/maven-wrapper.jar
3
+ !**/src/main/resources/components/
4
+
5
+ ### STS ###
6
+ .apt_generated
7
+ .classpath
8
+ .factorypath
9
+ .project
10
+ .settings
11
+ .springBeans
12
+ .sts4-cache
13
+
14
+ ### IntelliJ IDEA ###
15
+ .idea
16
+ *.iws
17
+ *.iml
18
+ *.ipr
19
+
20
+ ### NetBeans ###
21
+ /nbproject/private/
22
+ /nbbuild/
23
+ /dist/
24
+ /nbdist/
25
+ /.nb-gradle/
26
+
27
+ ### VS Code ###
28
+ .vscode/
@@ -0,0 +1,69 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
+ <modelVersion>4.0.0</modelVersion>
5
+ <parent>
6
+ <groupId>org.springframework.boot</groupId>
7
+ <artifactId>spring-boot-starter-parent</artifactId>
8
+ <version>3.3.5</version>
9
+ <relativePath/> <!-- lookup parent from repository -->
10
+ </parent>
11
+ <groupId>com.example</groupId>
12
+ <artifactId>{{projectName}}</artifactId>
13
+ <version>0.0.1-SNAPSHOT</version>
14
+ <name>{{projectName}}</name>
15
+ <description>Demo project for Spring Boot and Agent Workflow Kit</description>
16
+ <properties>
17
+ <java.version>17</java.version>
18
+ </properties>
19
+ <dependencies>
20
+ <dependency>
21
+ <groupId>org.springframework.boot</groupId>
22
+ <artifactId>spring-boot-starter-web</artifactId>
23
+ </dependency>
24
+ <dependency>
25
+ <groupId>org.springframework.boot</groupId>
26
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
27
+ </dependency>
28
+ <dependency>
29
+ <groupId>com.h2database</groupId>
30
+ <artifactId>h2</artifactId>
31
+ <scope>runtime</scope>
32
+ </dependency>
33
+
34
+ <dependency>
35
+ <groupId>org.springframework.boot</groupId>
36
+ <artifactId>spring-boot-devtools</artifactId>
37
+ <scope>runtime</scope>
38
+ <optional>true</optional>
39
+ </dependency>
40
+ <dependency>
41
+ <groupId>org.projectlombok</groupId>
42
+ <artifactId>lombok</artifactId>
43
+ <optional>true</optional>
44
+ </dependency>
45
+ <dependency>
46
+ <groupId>org.springframework.boot</groupId>
47
+ <artifactId>spring-boot-starter-test</artifactId>
48
+ <scope>test</scope>
49
+ </dependency>
50
+ </dependencies>
51
+
52
+ <build>
53
+ <plugins>
54
+ <plugin>
55
+ <groupId>org.springframework.boot</groupId>
56
+ <artifactId>spring-boot-maven-plugin</artifactId>
57
+ <configuration>
58
+ <excludes>
59
+ <exclude>
60
+ <groupId>org.projectlombok</groupId>
61
+ <artifactId>lombok</artifactId>
62
+ </exclude>
63
+ </excludes>
64
+ </configuration>
65
+ </plugin>
66
+ </plugins>
67
+ </build>
68
+
69
+ </project>
@@ -0,0 +1,13 @@
1
+ package com.example.{{safePackageName}};
2
+
3
+ import org.springframework.boot.SpringApplication;
4
+ import org.springframework.boot.autoconfigure.SpringBootApplication;
5
+
6
+ @SpringBootApplication
7
+ public class DemoApplication {
8
+
9
+ public static void main(String[] args) {
10
+ SpringApplication.run(DemoApplication.class, args);
11
+ }
12
+
13
+ }
@@ -0,0 +1,37 @@
1
+ package com.example.{{safePackageName}}.controller;
2
+
3
+ import com.example.{{safePackageName}}.dto.UserDTO;
4
+ import com.example.{{safePackageName}}.service.UserService;
5
+ import lombok.RequiredArgsConstructor;
6
+ import org.springframework.http.ResponseEntity;
7
+ import org.springframework.web.bind.annotation.GetMapping;
8
+ import org.springframework.web.bind.annotation.PathVariable;
9
+ import org.springframework.web.bind.annotation.PostMapping;
10
+ import org.springframework.web.bind.annotation.RequestBody;
11
+ import org.springframework.web.bind.annotation.RequestMapping;
12
+ import org.springframework.web.bind.annotation.RestController;
13
+
14
+ import java.util.List;
15
+
16
+ @RestController
17
+ @RequestMapping("/api/users")
18
+ @RequiredArgsConstructor
19
+ public class UserController {
20
+
21
+ private final UserService userService;
22
+
23
+ @GetMapping
24
+ public ResponseEntity<List<UserDTO>> getAllUsers() {
25
+ return ResponseEntity.ok(userService.getAllUsers());
26
+ }
27
+
28
+ @PostMapping
29
+ public ResponseEntity<UserDTO> createUser(@RequestBody UserDTO userDTO) {
30
+ return ResponseEntity.ok(userService.createUser(userDTO));
31
+ }
32
+
33
+ @GetMapping("/{id}")
34
+ public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {
35
+ return ResponseEntity.ok(userService.getUserById(id));
36
+ }
37
+ }
@@ -0,0 +1,16 @@
1
+ package com.example.{{safePackageName}}.dto;
2
+
3
+ import lombok.AllArgsConstructor;
4
+ import lombok.Builder;
5
+ import lombok.Data;
6
+ import lombok.NoArgsConstructor;
7
+
8
+ @Data
9
+ @Builder
10
+ @NoArgsConstructor
11
+ @AllArgsConstructor
12
+ public class UserDTO {
13
+ private Long id;
14
+ private String name;
15
+ private String email;
16
+ }
@@ -0,0 +1,27 @@
1
+ package com.example.{{safePackageName}}.entity;
2
+
3
+ import jakarta.persistence.Entity;
4
+ import jakarta.persistence.GeneratedValue;
5
+ import jakarta.persistence.GenerationType;
6
+ import jakarta.persistence.Id;
7
+ import jakarta.persistence.Table;
8
+ import lombok.AllArgsConstructor;
9
+ import lombok.Builder;
10
+ import lombok.Data;
11
+ import lombok.NoArgsConstructor;
12
+
13
+ @Entity
14
+ @Table(name = "users")
15
+ @Data
16
+ @Builder
17
+ @NoArgsConstructor
18
+ @AllArgsConstructor
19
+ public class User {
20
+
21
+ @Id
22
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
23
+ private Long id;
24
+
25
+ private String name;
26
+ private String email;
27
+ }
@@ -0,0 +1,9 @@
1
+ package com.example.{{safePackageName}}.repository;
2
+
3
+ import com.example.{{safePackageName}}.entity.User;
4
+ import org.springframework.data.jpa.repository.JpaRepository;
5
+ import org.springframework.stereotype.Repository;
6
+
7
+ @Repository
8
+ public interface UserRepository extends JpaRepository<User, Long> {
9
+ }
@@ -0,0 +1,11 @@
1
+ package com.example.{{safePackageName}}.service;
2
+
3
+ import com.example.{{safePackageName}}.dto.UserDTO;
4
+
5
+ import java.util.List;
6
+
7
+ public interface UserService {
8
+ List<UserDTO> getAllUsers();
9
+ UserDTO createUser(UserDTO userDTO);
10
+ UserDTO getUserById(Long id);
11
+ }
@@ -0,0 +1,55 @@
1
+ package com.example.{{safePackageName}}.service.impl;
2
+
3
+ import com.example.{{safePackageName}}.dto.UserDTO;
4
+ import com.example.{{safePackageName}}.entity.User;
5
+ import com.example.{{safePackageName}}.repository.UserRepository;
6
+ import com.example.{{safePackageName}}.service.UserService;
7
+ import lombok.RequiredArgsConstructor;
8
+ import org.springframework.stereotype.Service;
9
+
10
+ import java.util.List;
11
+ import java.util.stream.Collectors;
12
+
13
+ @Service
14
+ @RequiredArgsConstructor
15
+ public class UserServiceImpl implements UserService {
16
+
17
+ private final UserRepository userRepository;
18
+
19
+ @Override
20
+ public List<UserDTO> getAllUsers() {
21
+ return userRepository.findAll().stream()
22
+ .map(this::convertToDTO)
23
+ .collect(Collectors.toList());
24
+ }
25
+
26
+ @Override
27
+ public UserDTO createUser(UserDTO userDTO) {
28
+ User user = convertToEntity(userDTO);
29
+ User savedUser = userRepository.save(user);
30
+ return convertToDTO(savedUser);
31
+ }
32
+
33
+ @Override
34
+ public UserDTO getUserById(Long id) {
35
+ User user = userRepository.findById(id)
36
+ .orElseThrow(() -> new RuntimeException("User not found with id: " + id));
37
+ return convertToDTO(user);
38
+ }
39
+
40
+ private UserDTO convertToDTO(User user) {
41
+ return UserDTO.builder()
42
+ .id(user.getId())
43
+ .name(user.getName())
44
+ .email(user.getEmail())
45
+ .build();
46
+ }
47
+
48
+ private User convertToEntity(UserDTO userDTO) {
49
+ return User.builder()
50
+ .id(userDTO.getId())
51
+ .name(userDTO.getName())
52
+ .email(userDTO.getEmail())
53
+ .build();
54
+ }
55
+ }
@@ -0,0 +1,20 @@
1
+ server:
2
+ port: 8080
3
+
4
+ spring:
5
+ application:
6
+ name: {{projectName}}
7
+ datasource:
8
+ url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
9
+ driver-class-name: org.h2.Driver
10
+ username: sa
11
+ password: password
12
+ h2:
13
+ console:
14
+ enabled: true
15
+ path: /h2-console
16
+ jpa:
17
+ database-platform: org.hibernate.dialect.H2Dialect
18
+ hibernate:
19
+ ddl-auto: update
20
+ show-sql: true
@@ -0,0 +1,13 @@
1
+ package com.example.{{safePackageName}};
2
+
3
+ import org.junit.jupiter.api.Test;
4
+ import org.springframework.boot.test.context.SpringBootTest;
5
+
6
+ @SpringBootTest
7
+ class DemoApplicationTests {
8
+
9
+ @Test
10
+ void contextLoads() {
11
+ }
12
+
13
+ }