@dyyz1993/create-agent 2.0.0 → 2.0.1

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 (141) hide show
  1. package/package.json +1 -1
  2. package/src/lib/copy.ts +23 -1
  3. package/templates/agent/eslint.config.mjs +15 -2
  4. package/templates/agent/package.json +10 -2
  5. package/templates/agent/src/__tests__/hybrid-mode.test.ts +126 -0
  6. package/templates/agent/src/__tests__/server-config-security.test.ts +55 -0
  7. package/templates/agent/src/bun/index.ts +96 -41
  8. package/templates/agent/src/bun/three.d.ts +1 -0
  9. package/templates/agent/src/gateway/__tests__/ws-handler-token.test.ts +118 -0
  10. package/templates/agent/src/gateway/http-routes.ts +1 -1
  11. package/templates/agent/src/gateway/ws-handler.ts +84 -56
  12. package/templates/agent/src/mainview/__tests__/i18n/i18n.test.ts +1 -0
  13. package/templates/agent/src/mainview/__tests__/setup.ts +32 -29
  14. package/templates/agent/src/mainview/__tests__/theme-variables.test.ts +36 -0
  15. package/templates/agent/src/mainview/components/common/ErrorBoundary.tsx +1 -58
  16. package/templates/agent/src/mainview/components/common/LanguageSwitcher.tsx +1 -0
  17. package/templates/agent/src/mainview/components/common/ThemeToggle.tsx +1 -0
  18. package/templates/agent/src/mainview/components/feed/FeedPanel.tsx +232 -210
  19. package/templates/agent/src/mainview/components/todo/TodoPanel.tsx +149 -122
  20. package/templates/agent/src/mainview/lib/api-client.ts +182 -172
  21. package/templates/agent/src/server-config.ts +34 -32
  22. package/templates/agent/src/server.ts +43 -54
  23. package/templates/agent/src/shared/handlers/__tests__/chat-concurrency.test.ts +127 -0
  24. package/templates/agent/src/shared/handlers/__tests__/handler-isolation.test.ts +244 -0
  25. package/templates/agent/src/shared/handlers/bash.ts +65 -65
  26. package/templates/agent/src/shared/handlers/chat.ts +189 -155
  27. package/templates/agent/src/shared/handlers/debug.ts +8 -0
  28. package/templates/agent/src/shared/handlers/feed.ts +31 -32
  29. package/templates/agent/src/shared/handlers/index.ts +1 -0
  30. package/templates/agent/src/shared/handlers/rules.ts +31 -31
  31. package/templates/agent/src/shared/handlers/todo.ts +31 -31
  32. package/templates/agent/src/shared/http-routes.ts +250 -0
  33. package/templates/agent/src/shared/lib/__tests__/web-server.test.ts +190 -0
  34. package/templates/agent/src/shared/lib/logger.ts +117 -95
  35. package/templates/agent/src/shared/lib/web-server.ts +128 -0
  36. package/templates/agent/src/shared/modules/debug.ts +8 -0
  37. package/templates/agent/src/shared/rpc-schema.ts +16 -3
  38. package/templates/agent/test-upload.txt +0 -0
  39. package/templates/agent/tsconfig.ipc.json +10 -0
  40. package/templates/agent/tsconfig.json +10 -2
  41. package/templates/chat/eslint.config.mjs +15 -2
  42. package/templates/chat/package.json +10 -2
  43. package/templates/chat/src/__tests__/hybrid-mode.test.ts +125 -0
  44. package/templates/chat/src/__tests__/server-config-security.test.ts +55 -0
  45. package/templates/chat/src/__tests__/server-config.test.ts +46 -44
  46. package/templates/chat/src/bun/index.ts +94 -44
  47. package/templates/chat/src/bun/three.d.ts +1 -0
  48. package/templates/chat/src/gateway/http-routes.ts +1 -1
  49. package/templates/chat/src/gateway/ws-handler.ts +84 -56
  50. package/templates/chat/src/mainview/App.tsx +6 -0
  51. package/templates/chat/src/mainview/__tests__/i18n/i18n.test.ts +1 -0
  52. package/templates/chat/src/mainview/__tests__/theme-variables.test.ts +36 -0
  53. package/templates/chat/src/mainview/components/common/LanguageSwitcher.tsx +1 -0
  54. package/templates/chat/src/mainview/components/common/ThemeToggle.tsx +1 -0
  55. package/templates/chat/src/mainview/lib/api-client.ts +183 -156
  56. package/templates/chat/src/mainview/lib/rpc-cache.ts +84 -0
  57. package/templates/chat/src/mainview/main.tsx +4 -3
  58. package/templates/chat/src/server-config.ts +33 -31
  59. package/templates/chat/src/server.ts +43 -60
  60. package/templates/chat/src/shared/handlers/chat.ts +196 -162
  61. package/templates/chat/src/shared/handlers/debug.ts +8 -0
  62. package/templates/chat/src/shared/handlers/index.ts +1 -0
  63. package/templates/chat/src/shared/http-routes.ts +250 -0
  64. package/templates/chat/src/shared/lib/__tests__/logger.test.ts +92 -0
  65. package/templates/chat/src/shared/lib/logger.ts +108 -95
  66. package/templates/chat/src/shared/lib/web-server.ts +128 -0
  67. package/templates/chat/src/shared/modules/debug.ts +8 -0
  68. package/templates/chat/src/shared/rpc-schema.ts +3 -2
  69. package/templates/chat/test-upload.txt +0 -0
  70. package/templates/chat/tsconfig.ipc.json +10 -0
  71. package/templates/general/eslint.config.mjs +15 -2
  72. package/templates/general/package.json +10 -2
  73. package/templates/general/src/__tests__/hybrid-mode.test.ts +125 -0
  74. package/templates/general/src/__tests__/server-config-security.test.ts +55 -0
  75. package/templates/general/src/__tests__/server-config.test.ts +46 -44
  76. package/templates/general/src/bun/index.ts +94 -44
  77. package/templates/general/src/bun/three.d.ts +1 -0
  78. package/templates/general/src/gateway/http-routes.ts +1 -1
  79. package/templates/general/src/gateway/ws-handler.ts +84 -56
  80. package/templates/general/src/mainview/__tests__/i18n/i18n.test.ts +1 -0
  81. package/templates/general/src/mainview/__tests__/theme-variables.test.ts +36 -0
  82. package/templates/general/src/mainview/components/common/LanguageSwitcher.tsx +1 -0
  83. package/templates/general/src/mainview/components/common/ThemeToggle.tsx +1 -0
  84. package/templates/general/src/mainview/components/feed/FeedPanel.tsx +241 -219
  85. package/templates/general/src/mainview/components/layout/AppLayout.tsx +6 -0
  86. package/templates/general/src/mainview/lib/api-client.ts +183 -156
  87. package/templates/general/src/mainview/lib/rpc-cache.ts +84 -0
  88. package/templates/general/src/mainview/main.tsx +4 -3
  89. package/templates/general/src/server-config.ts +33 -31
  90. package/templates/general/src/server.ts +43 -60
  91. package/templates/general/src/shared/handlers/__tests__/chat.test.ts +165 -160
  92. package/templates/general/src/shared/handlers/chat.ts +189 -155
  93. package/templates/general/src/shared/handlers/debug.ts +8 -0
  94. package/templates/general/src/shared/handlers/feed.ts +38 -40
  95. package/templates/general/src/shared/handlers/index.ts +1 -0
  96. package/templates/general/src/shared/http-routes.ts +250 -0
  97. package/templates/general/src/shared/lib/__tests__/logger.test.ts +92 -0
  98. package/templates/general/src/shared/lib/logger.ts +117 -95
  99. package/templates/general/src/shared/lib/web-server.ts +128 -0
  100. package/templates/general/src/shared/modules/debug.ts +8 -0
  101. package/templates/general/src/shared/rpc-schema.ts +12 -2
  102. package/templates/general/test-upload.txt +0 -0
  103. package/templates/general/tsconfig.ipc.json +10 -0
  104. package/templates/shared/__tests__/cors-security.test.ts +165 -0
  105. package/templates/shared/__tests__/file-path-security.test.ts +260 -0
  106. package/templates/shared/__tests__/http-routes.test.ts +174 -0
  107. package/templates/shared/__tests__/logger.test.ts +186 -0
  108. package/templates/shared/components/ErrorBoundary.tsx +58 -0
  109. package/templates/shared/env.d.ts +11 -0
  110. package/templates/shared/http-routes.ts +230 -0
  111. package/templates/shared/logger.ts +129 -0
  112. package/templates/shared/test-upload.txt +0 -0
  113. package/templates/shared/vite-base.config.ts +92 -0
  114. package/templates/shared/vitest-base.config.ts +42 -0
  115. package/templates/agent/eslint-plugin-rpc/index.js +0 -50
  116. package/templates/agent/eslint-plugin-rpc/package.json +0 -6
  117. package/templates/agent/eslint-plugin-rpc/rules/module-file-naming.js +0 -99
  118. package/templates/agent/eslint-plugin-rpc/rules/no-bare-method.js +0 -78
  119. package/templates/agent/eslint-plugin-rpc/rules/no-direct-register.js +0 -65
  120. package/templates/agent/eslint-plugin-rpc/rules/no-hardcoded-strings.js +0 -69
  121. package/templates/agent/eslint-plugin-rpc/rules/require-api-client.js +0 -58
  122. package/templates/agent/eslint-plugin-rpc/rules/require-typed-register.js +0 -78
  123. package/templates/agent/eslint-plugin-rpc/rules/schema-merge-only.js +0 -55
  124. package/templates/chat/eslint-plugin-rpc/index.js +0 -50
  125. package/templates/chat/eslint-plugin-rpc/package.json +0 -6
  126. package/templates/chat/eslint-plugin-rpc/rules/module-file-naming.js +0 -99
  127. package/templates/chat/eslint-plugin-rpc/rules/no-bare-method.js +0 -78
  128. package/templates/chat/eslint-plugin-rpc/rules/no-direct-register.js +0 -65
  129. package/templates/chat/eslint-plugin-rpc/rules/no-hardcoded-strings.js +0 -69
  130. package/templates/chat/eslint-plugin-rpc/rules/require-api-client.js +0 -58
  131. package/templates/chat/eslint-plugin-rpc/rules/require-typed-register.js +0 -78
  132. package/templates/chat/eslint-plugin-rpc/rules/schema-merge-only.js +0 -55
  133. package/templates/general/eslint-plugin-rpc/index.js +0 -50
  134. package/templates/general/eslint-plugin-rpc/package.json +0 -6
  135. package/templates/general/eslint-plugin-rpc/rules/module-file-naming.js +0 -99
  136. package/templates/general/eslint-plugin-rpc/rules/no-bare-method.js +0 -78
  137. package/templates/general/eslint-plugin-rpc/rules/no-direct-register.js +0 -65
  138. package/templates/general/eslint-plugin-rpc/rules/no-hardcoded-strings.js +0 -69
  139. package/templates/general/eslint-plugin-rpc/rules/require-api-client.js +0 -58
  140. package/templates/general/eslint-plugin-rpc/rules/require-typed-register.js +0 -78
  141. package/templates/general/eslint-plugin-rpc/rules/schema-merge-only.js +0 -55
@@ -2,140 +2,167 @@ import { useState, useEffect } from "react";
2
2
  import { useTranslation } from "react-i18next";
3
3
  import { Plus, Trash2, Circle, Clock, CheckCircle2, ListTodo } from "lucide-react";
4
4
  import { useTodoStore } from "../../stores/use-todo-store";
5
- import type { TodoStatus } from "../../../shared/modules/todo";
5
+ import type { TodoStatus } from "@shared/modules/todo";
6
6
 
7
7
  const nextStatus: Record<TodoStatus, TodoStatus> = {
8
- pending: "in_progress",
9
- in_progress: "completed",
10
- completed: "pending",
8
+ pending: "in_progress",
9
+ in_progress: "completed",
10
+ completed: "pending",
11
11
  };
12
12
 
13
13
  const statusFlow = ["pending", "in_progress", "completed"] as const;
14
14
 
15
15
  export function TodoPanel() {
16
- const { t } = useTranslation();
17
- const [showInput, setShowInput] = useState(false);
18
- const [input, setInput] = useState("");
19
- const items = useTodoStore((s) => s.items);
20
- const fetchItems = useTodoStore((s) => s.fetchItems);
21
- const addItem = useTodoStore((s) => s.addItem);
22
- const updateItem = useTodoStore((s) => s.updateItem);
23
- const removeItem = useTodoStore((s) => s.removeItem);
16
+ const { t } = useTranslation();
17
+ const [showInput, setShowInput] = useState(false);
18
+ const [input, setInput] = useState("");
19
+ const items = useTodoStore((s) => s.items);
20
+ const fetchItems = useTodoStore((s) => s.fetchItems);
21
+ const addItem = useTodoStore((s) => s.addItem);
22
+ const updateItem = useTodoStore((s) => s.updateItem);
23
+ const removeItem = useTodoStore((s) => s.removeItem);
24
24
 
25
- useEffect(() => {
26
- fetchItems();
27
- }, [fetchItems]);
25
+ useEffect(() => {
26
+ fetchItems();
27
+ }, [fetchItems]);
28
28
 
29
- const handleAdd = () => {
30
- if (!input.trim()) return;
31
- addItem(input.trim());
32
- setInput("");
33
- setShowInput(false);
34
- };
29
+ const handleAdd = () => {
30
+ if (!input.trim()) return;
31
+ addItem(input.trim());
32
+ setInput("");
33
+ setShowInput(false);
34
+ };
35
35
 
36
- const handleKeyDown = (e: React.KeyboardEvent) => {
37
- if (e.key === "Enter") handleAdd();
38
- if (e.key === "Escape") setShowInput(false);
39
- };
36
+ const handleKeyDown = (e: React.KeyboardEvent) => {
37
+ if (e.key === "Enter") handleAdd();
38
+ if (e.key === "Escape") setShowInput(false);
39
+ };
40
40
 
41
- const statusConfig: Record<TodoStatus, { icon: typeof Circle; color: string; label: string; circleColor: string }> = {
42
- pending: { icon: Circle, color: "text-gray-400", label: t("todo.statusPending"), circleColor: "border-gray-500" },
43
- in_progress: { icon: Clock, color: "text-yellow-400", label: t("todo.statusInProgress"), circleColor: "border-yellow-400 bg-yellow-400/20" },
44
- completed: { icon: CheckCircle2, color: "text-green-400", label: t("todo.statusCompleted"), circleColor: "border-green-400 bg-green-400/20" },
45
- };
41
+ const statusConfig: Record<
42
+ TodoStatus,
43
+ { icon: typeof Circle; color: string; label: string; circleColor: string }
44
+ > = {
45
+ pending: {
46
+ icon: Circle,
47
+ color: "text-gray-400",
48
+ label: t("todo.statusPending"),
49
+ circleColor: "border-gray-500",
50
+ },
51
+ in_progress: {
52
+ icon: Clock,
53
+ color: "text-yellow-400",
54
+ label: t("todo.statusInProgress"),
55
+ circleColor: "border-yellow-400 bg-yellow-400/20",
56
+ },
57
+ completed: {
58
+ icon: CheckCircle2,
59
+ color: "text-green-400",
60
+ label: t("todo.statusCompleted"),
61
+ circleColor: "border-green-400 bg-green-400/20",
62
+ },
63
+ };
46
64
 
47
- return (
48
- <div className="flex flex-col h-full">
49
- <div className="p-3 border-b border-[var(--color-border-primary)] flex items-center justify-between">
50
- <span className="text-sm text-[var(--color-text-secondary)]">{t("todo.title")}</span>
51
- <button
52
- onClick={() => setShowInput(!showInput)}
53
- className="flex items-center gap-1 px-2 py-1 text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] rounded text-[var(--color-text-primary)]"
54
- >
55
- <Plus className="w-3 h-3" />
56
- {t("todo.add")}
57
- </button>
58
- </div>
65
+ return (
66
+ <div className="flex flex-col h-full">
67
+ <div className="p-3 border-b border-[var(--color-border-primary)] flex items-center justify-between">
68
+ <span className="text-sm text-[var(--color-text-secondary)]">{t("todo.title")}</span>
69
+ <button
70
+ onClick={() => setShowInput(!showInput)}
71
+ className="flex items-center gap-1 px-2 py-1 text-xs bg-[var(--color-accent)] hover:bg-[var(--color-accent-hover)] rounded text-[var(--color-text-primary)]"
72
+ >
73
+ <Plus className="w-3 h-3" />
74
+ {t("todo.add")}
75
+ </button>
76
+ </div>
59
77
 
60
- {showInput && (
61
- <div className="p-3 border-b border-[var(--color-border-primary)] bg-[var(--color-bg-secondary)] flex items-center gap-2">
62
- <input
63
- type="text"
64
- value={input}
65
- onChange={(e) => setInput(e.target.value)}
66
- onKeyDown={handleKeyDown}
67
- placeholder={t("todo.placeholder")}
68
- autoFocus
69
- className="flex-1 bg-[var(--color-bg-primary)] text-[var(--color-text-secondary)] px-3 py-1.5 rounded text-sm border border-[var(--color-border-secondary)] focus:border-[var(--color-accent)] focus:outline-none"
70
- />
71
- <button
72
- onClick={handleAdd}
73
- disabled={!input.trim()}
74
- className="px-3 py-1 text-xs bg-green-600 hover:bg-green-500 disabled:opacity-40 rounded text-white"
75
- >
76
- {t("todo.save")}
77
- </button>
78
- </div>
79
- )}
78
+ {showInput && (
79
+ <div className="p-3 border-b border-[var(--color-border-primary)] bg-[var(--color-bg-secondary)] flex items-center gap-2">
80
+ <input
81
+ type="text"
82
+ value={input}
83
+ onChange={(e) => setInput(e.target.value)}
84
+ onKeyDown={handleKeyDown}
85
+ placeholder={t("todo.placeholder")}
86
+ autoFocus
87
+ className="flex-1 bg-[var(--color-bg-primary)] text-[var(--color-text-secondary)] px-3 py-1.5 rounded text-sm border border-[var(--color-border-secondary)] focus:border-[var(--color-accent)] focus:outline-none"
88
+ />
89
+ <button
90
+ onClick={handleAdd}
91
+ disabled={!input.trim()}
92
+ className="px-3 py-1 text-xs bg-green-600 hover:bg-green-500 disabled:opacity-40 rounded text-white"
93
+ >
94
+ {t("todo.save")}
95
+ </button>
96
+ </div>
97
+ )}
80
98
 
81
- <div className="flex-1 overflow-auto p-3">
82
- {items.length === 0 ? (
83
- <div className="flex flex-col items-center justify-center h-full text-gray-600">
84
- <ListTodo className="w-12 h-12 mb-3 opacity-30" />
85
- <span className="text-sm">{t("todo.empty")}</span>
86
- <span className="text-xs mt-1">{t("todo.emptyHint")}</span>
87
- </div>
88
- ) : (
89
- <div className="space-y-2.5">
90
- {items.map((item) => {
91
- const cfg = statusConfig[item.status as TodoStatus];
92
- const Icon = cfg.icon;
93
- return (
94
- <div
95
- key={item.id}
96
- className="group relative bg-[var(--color-bg-secondary)]/60 border border-[var(--color-border-primary)]/80 rounded-lg p-3 hover:bg-[var(--color-bg-secondary)] hover:border-[var(--color-border-secondary)] transition-all"
97
- >
98
- <div className="flex items-start gap-3">
99
- <button
100
- onClick={() => updateItem(item.id, nextStatus[item.status as TodoStatus])}
101
- className={`flex-shrink-0 mt-0.5 w-5 h-5 rounded-full border-2 flex items-center justify-center transition-all ${cfg.circleColor} ${cfg.color} hover:scale-110`}
102
- >
103
- <Icon className="w-3 h-3" />
104
- </button>
105
- <div className="flex-1 min-w-0">
106
- <p className={`text-sm leading-relaxed ${
107
- item.status === "completed" ? "text-[var(--color-text-placeholder)] line-through" : "text-[var(--color-text-secondary)]"
108
- }`}>
109
- {item.content}
110
- </p>
111
- <div className="flex items-center gap-1.5 mt-2 text-[11px] text-[var(--color-text-placeholder)]">
112
- <span>{t("todo.status")}</span>
113
- {statusFlow.map((s) => {
114
- const sc = statusConfig[s];
115
- const isActive = s === item.status;
116
- return (
117
- <span key={s} className={`inline-flex items-center gap-0.5 ${isActive ? sc.color + " font-medium" : ""}`}>
118
- {isActive && <sc.icon className="w-2.5 h-2.5" />}
119
- {sc.label}
120
- {s !== "completed" && <span className="text-gray-700 mx-0.5">&rarr;</span>}
121
- </span>
122
- );
123
- })}
124
- </div>
125
- </div>
126
- <button
127
- onClick={() => removeItem(item.id)}
128
- className="text-gray-600 hover:text-[var(--color-text-error)] opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0 self-start mt-0.5"
129
- >
130
- <Trash2 className="w-3.5 h-3.5" />
131
- </button>
132
- </div>
133
- </div>
134
- );
135
- })}
136
- </div>
137
- )}
138
- </div>
139
- </div>
140
- );
99
+ <div className="flex-1 overflow-auto p-3">
100
+ {items.length === 0 ? (
101
+ <div className="flex flex-col items-center justify-center h-full text-gray-600">
102
+ <ListTodo className="w-12 h-12 mb-3 opacity-30" />
103
+ <span className="text-sm">{t("todo.empty")}</span>
104
+ <span className="text-xs mt-1">{t("todo.emptyHint")}</span>
105
+ </div>
106
+ ) : (
107
+ <div className="space-y-2.5">
108
+ {items.map((item) => {
109
+ const cfg = statusConfig[item.status as TodoStatus];
110
+ const Icon = cfg.icon;
111
+ return (
112
+ <div
113
+ key={item.id}
114
+ className="group relative bg-[var(--color-bg-secondary)]/60 border border-[var(--color-border-primary)]/80 rounded-lg p-3 hover:bg-[var(--color-bg-secondary)] hover:border-[var(--color-border-secondary)] transition-all"
115
+ >
116
+ <div className="flex items-start gap-3">
117
+ <button
118
+ onClick={() => updateItem(item.id, nextStatus[item.status as TodoStatus])}
119
+ className={`flex-shrink-0 mt-0.5 w-5 h-5 rounded-full border-2 flex items-center justify-center transition-all ${cfg.circleColor} ${cfg.color} hover:scale-110`}
120
+ >
121
+ <Icon className="w-3 h-3" />
122
+ </button>
123
+ <div className="flex-1 min-w-0">
124
+ <p
125
+ className={`text-sm leading-relaxed ${
126
+ item.status === "completed"
127
+ ? "text-[var(--color-text-placeholder)] line-through"
128
+ : "text-[var(--color-text-secondary)]"
129
+ }`}
130
+ >
131
+ {item.content}
132
+ </p>
133
+ <div className="flex items-center gap-1.5 mt-2 text-[11px] text-[var(--color-text-placeholder)]">
134
+ <span>{t("todo.status")}</span>
135
+ {statusFlow.map((s) => {
136
+ const sc = statusConfig[s];
137
+ const isActive = s === item.status;
138
+ return (
139
+ <span
140
+ key={s}
141
+ className={`inline-flex items-center gap-0.5 ${isActive ? sc.color + " font-medium" : ""}`}
142
+ >
143
+ {isActive && <sc.icon className="w-2.5 h-2.5" />}
144
+ {sc.label}
145
+ {s !== "completed" && (
146
+ <span className="text-gray-700 mx-0.5">&rarr;</span>
147
+ )}
148
+ </span>
149
+ );
150
+ })}
151
+ </div>
152
+ </div>
153
+ <button
154
+ onClick={() => removeItem(item.id)}
155
+ className="text-gray-600 hover:text-[var(--color-text-error)] opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0 self-start mt-0.5"
156
+ >
157
+ <Trash2 className="w-3.5 h-3.5" />
158
+ </button>
159
+ </div>
160
+ </div>
161
+ );
162
+ })}
163
+ </div>
164
+ )}
165
+ </div>
166
+ </div>
167
+ );
141
168
  }