@jcjeon/integration-cli 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/.gitignore +23 -0
  2. package/.npmignore +21 -0
  3. package/.prettierignore +6 -0
  4. package/.prettierrc +26 -0
  5. package/AGENTS.md +10 -0
  6. package/CLAUDE.md +10 -0
  7. package/README.md +384 -0
  8. package/apps/server/README.md +294 -0
  9. package/apps/server/eslint.config.mjs +20 -0
  10. package/apps/server/nest-cli.json +8 -0
  11. package/apps/server/package.json +89 -0
  12. package/apps/server/scripts/postinstall.js +53 -0
  13. package/apps/server/src/__mocks__/glob.js +6 -0
  14. package/apps/server/src/__mocks__/uuid.js +5 -0
  15. package/apps/server/src/app.controller.spec.ts +24 -0
  16. package/apps/server/src/app.controller.ts +13 -0
  17. package/apps/server/src/app.module.ts +18 -0
  18. package/apps/server/src/app.service.ts +8 -0
  19. package/apps/server/src/common/ji-paths.ts +41 -0
  20. package/apps/server/src/database/database.module.ts +27 -0
  21. package/apps/server/src/database/entities/agent-changelog.entity.ts +39 -0
  22. package/apps/server/src/database/entities/agent-session.entity.ts +29 -0
  23. package/apps/server/src/database/entities/conversation.entity.ts +41 -0
  24. package/apps/server/src/database/entities/session.entity.ts +16 -0
  25. package/apps/server/src/database/entities/task-agent-run.entity.ts +40 -0
  26. package/apps/server/src/database/entities/task-agent.entity.ts +42 -0
  27. package/apps/server/src/database/entities/task-requirement.entity.ts +27 -0
  28. package/apps/server/src/database/entities/task-run.entity.ts +41 -0
  29. package/apps/server/src/database/entities/task.entity.ts +44 -0
  30. package/apps/server/src/main.ts +65 -0
  31. package/apps/server/src/modules/agents/agent-model-settings.spec.ts +80 -0
  32. package/apps/server/src/modules/agents/agents.module.ts +11 -0
  33. package/apps/server/src/modules/agents/claude/claude-auth.manager.ts +83 -0
  34. package/apps/server/src/modules/agents/claude/claude-pty.manager.ts +380 -0
  35. package/apps/server/src/modules/agents/claude/claude.controller.ts +85 -0
  36. package/apps/server/src/modules/agents/claude/claude.gateway.ts +158 -0
  37. package/apps/server/src/modules/agents/claude/claude.module.ts +18 -0
  38. package/apps/server/src/modules/agents/claude/claude.service.ts +67 -0
  39. package/apps/server/src/modules/agents/claude/dto/create-session.dto.ts +24 -0
  40. package/apps/server/src/modules/agents/claude/dto/resize-session.dto.ts +13 -0
  41. package/apps/server/src/modules/agents/claude/dto/send-input.dto.ts +9 -0
  42. package/apps/server/src/modules/agents/claude/interfaces/claude-session.interface.ts +26 -0
  43. package/apps/server/src/modules/agents/claude/interfaces/pty-event.interface.ts +10 -0
  44. package/apps/server/src/modules/agents/claude/interfaces/stream-event.interface.ts +61 -0
  45. package/apps/server/src/modules/agents/codex/codex-auth.manager.ts +107 -0
  46. package/apps/server/src/modules/agents/codex/codex-session.manager.ts +357 -0
  47. package/apps/server/src/modules/agents/codex/codex.controller.ts +64 -0
  48. package/apps/server/src/modules/agents/codex/codex.gateway.ts +97 -0
  49. package/apps/server/src/modules/agents/codex/codex.module.ts +17 -0
  50. package/apps/server/src/modules/agents/codex/dto/configure-auth.dto.ts +7 -0
  51. package/apps/server/src/modules/agents/gemini/dto/configure-auth.dto.ts +15 -0
  52. package/apps/server/src/modules/agents/gemini/dto/create-session.dto.ts +9 -0
  53. package/apps/server/src/modules/agents/gemini/dto/send-input.dto.ts +9 -0
  54. package/apps/server/src/modules/agents/gemini/gemini-auth.manager.ts +157 -0
  55. package/apps/server/src/modules/agents/gemini/gemini-session.manager.ts +287 -0
  56. package/apps/server/src/modules/agents/gemini/gemini.controller.ts +93 -0
  57. package/apps/server/src/modules/agents/gemini/gemini.gateway.ts +149 -0
  58. package/apps/server/src/modules/agents/gemini/gemini.module.ts +17 -0
  59. package/apps/server/src/modules/agents/gemini/interfaces/gemini-session.interface.ts +18 -0
  60. package/apps/server/src/modules/agents/gemini/interfaces/stream-event.interface.ts +14 -0
  61. package/apps/server/src/modules/agents/session-termination.spec.ts +103 -0
  62. package/apps/server/src/modules/changelog/changelog.controller.ts +20 -0
  63. package/apps/server/src/modules/changelog/changelog.module.ts +14 -0
  64. package/apps/server/src/modules/changelog/changelog.service.spec.ts +531 -0
  65. package/apps/server/src/modules/changelog/changelog.service.ts +690 -0
  66. package/apps/server/src/modules/conversations/conversation.controller.spec.ts +106 -0
  67. package/apps/server/src/modules/conversations/conversation.controller.ts +60 -0
  68. package/apps/server/src/modules/conversations/conversation.module.ts +14 -0
  69. package/apps/server/src/modules/conversations/conversation.service.spec.ts +176 -0
  70. package/apps/server/src/modules/conversations/conversation.service.ts +54 -0
  71. package/apps/server/src/modules/conversations/dto/create-conversation.dto.ts +37 -0
  72. package/apps/server/src/modules/conversations/enums/conversation.enum.ts +13 -0
  73. package/apps/server/src/modules/fs/fs.controller.ts +29 -0
  74. package/apps/server/src/modules/fs/fs.module.ts +8 -0
  75. package/apps/server/src/modules/harness/dto/save-harness.dto.ts +9 -0
  76. package/apps/server/src/modules/harness/harness.controller.spec.ts +95 -0
  77. package/apps/server/src/modules/harness/harness.controller.ts +35 -0
  78. package/apps/server/src/modules/harness/harness.module.ts +11 -0
  79. package/apps/server/src/modules/harness/harness.service.spec.ts +217 -0
  80. package/apps/server/src/modules/harness/harness.service.ts +112 -0
  81. package/apps/server/src/modules/sessions/session.controller.spec.ts +68 -0
  82. package/apps/server/src/modules/sessions/session.controller.ts +43 -0
  83. package/apps/server/src/modules/sessions/session.module.ts +14 -0
  84. package/apps/server/src/modules/sessions/session.service.spec.ts +106 -0
  85. package/apps/server/src/modules/sessions/session.service.ts +35 -0
  86. package/apps/server/src/modules/tasks/dto/create-task.dto.ts +54 -0
  87. package/apps/server/src/modules/tasks/dto/execute-task.dto.ts +22 -0
  88. package/apps/server/src/modules/tasks/dto/merge-file.dto.ts +7 -0
  89. package/apps/server/src/modules/tasks/dto/rerun-task.dto.ts +14 -0
  90. package/apps/server/src/modules/tasks/dto/update-task.dto.ts +55 -0
  91. package/apps/server/src/modules/tasks/task-execution.service.ts +978 -0
  92. package/apps/server/src/modules/tasks/task.gateway.ts +140 -0
  93. package/apps/server/src/modules/tasks/tasks.controller.spec.ts +210 -0
  94. package/apps/server/src/modules/tasks/tasks.controller.ts +139 -0
  95. package/apps/server/src/modules/tasks/tasks.module.ts +30 -0
  96. package/apps/server/src/modules/tasks/tasks.service.spec.ts +552 -0
  97. package/apps/server/src/modules/tasks/tasks.service.ts +333 -0
  98. package/apps/server/test/app.e2e-spec.ts +28 -0
  99. package/apps/server/test/jest-e2e.json +9 -0
  100. package/apps/server/tsconfig.build.json +4 -0
  101. package/apps/server/tsconfig.json +13 -0
  102. package/apps/web/AGENTS.md +7 -0
  103. package/apps/web/CLAUDE.md +1 -0
  104. package/apps/web/README.md +36 -0
  105. package/apps/web/eslint.config.mjs +21 -0
  106. package/apps/web/next-env.d.ts +6 -0
  107. package/apps/web/next.config.ts +7 -0
  108. package/apps/web/package.json +49 -0
  109. package/apps/web/postcss.config.mjs +7 -0
  110. package/apps/web/public/file.svg +1 -0
  111. package/apps/web/public/globe.svg +1 -0
  112. package/apps/web/public/next.svg +1 -0
  113. package/apps/web/public/vercel.svg +1 -0
  114. package/apps/web/public/window.svg +1 -0
  115. package/apps/web/src/app/claude/page.tsx +5 -0
  116. package/apps/web/src/app/codex/page.tsx +126 -0
  117. package/apps/web/src/app/favicon.ico +0 -0
  118. package/apps/web/src/app/gemini/page.tsx +130 -0
  119. package/apps/web/src/app/globals.css +149 -0
  120. package/apps/web/src/app/layout.tsx +40 -0
  121. package/apps/web/src/app/login/page.tsx +67 -0
  122. package/apps/web/src/app/page.tsx +497 -0
  123. package/apps/web/src/app/task/[id]/page.tsx +11 -0
  124. package/apps/web/src/app/test/page.tsx +298 -0
  125. package/apps/web/src/components/ui/Modal.tsx +78 -0
  126. package/apps/web/src/components/ui/WorkingDirPicker.tsx +195 -0
  127. package/apps/web/src/components/ui/__tests__/Modal.test.tsx +68 -0
  128. package/apps/web/src/features/auth/api/__tests__/auth.api.test.ts +83 -0
  129. package/apps/web/src/features/auth/api/auth.api.ts +81 -0
  130. package/apps/web/src/features/auth/hooks/__tests__/useClaudeAuth.test.ts +166 -0
  131. package/apps/web/src/features/auth/hooks/__tests__/useCodexAuth.test.ts +127 -0
  132. package/apps/web/src/features/auth/hooks/__tests__/useGeminiAuth.test.ts +120 -0
  133. package/apps/web/src/features/auth/hooks/useClaudeAuth.ts +88 -0
  134. package/apps/web/src/features/auth/hooks/useCodexAuth.ts +149 -0
  135. package/apps/web/src/features/auth/hooks/useGeminiAuth.ts +125 -0
  136. package/apps/web/src/features/auth/ui/CodexLoginPanel.tsx +302 -0
  137. package/apps/web/src/features/auth/ui/GeminiLoginPanel.tsx +316 -0
  138. package/apps/web/src/features/auth/ui/LoginForm.tsx +190 -0
  139. package/apps/web/src/features/auth/ui/LoginPanel.tsx +114 -0
  140. package/apps/web/src/features/auth/ui/__tests__/LoginPanel.test.tsx +105 -0
  141. package/apps/web/src/features/chat/api/__tests__/sessions.api.test.ts +187 -0
  142. package/apps/web/src/features/chat/api/sessions.api.ts +161 -0
  143. package/apps/web/src/features/chat/container/ClaudePageContainer.tsx +152 -0
  144. package/apps/web/src/features/chat/hooks/__tests__/useCodexSessions.test.ts +131 -0
  145. package/apps/web/src/features/chat/hooks/__tests__/useGeminiSessions.test.ts +130 -0
  146. package/apps/web/src/features/chat/hooks/useAgentModelSettings.ts +54 -0
  147. package/apps/web/src/features/chat/hooks/useClaudeSessions.ts +323 -0
  148. package/apps/web/src/features/chat/hooks/useCodexSessions.ts +275 -0
  149. package/apps/web/src/features/chat/hooks/useGeminiSessions.ts +255 -0
  150. package/apps/web/src/features/chat/hooks/useSessionCommand.ts +66 -0
  151. package/apps/web/src/features/chat/hooks/useSessionRename.ts +61 -0
  152. package/apps/web/src/features/chat/hooks/useSessionWorkingDirectories.ts +34 -0
  153. package/apps/web/src/features/chat/hooks/useUnifiedSessions.ts +156 -0
  154. package/apps/web/src/features/chat/lib/agentModelOptions.ts +72 -0
  155. package/apps/web/src/features/chat/ui/AgentModelPicker.tsx +134 -0
  156. package/apps/web/src/features/chat/ui/AgentSelectModal.tsx +236 -0
  157. package/apps/web/src/features/chat/ui/ChatInput.tsx +162 -0
  158. package/apps/web/src/features/chat/ui/ChatMessage.tsx +204 -0
  159. package/apps/web/src/features/chat/ui/ChatWorkspace.tsx +207 -0
  160. package/apps/web/src/features/chat/ui/CheckingSkeleton.tsx +44 -0
  161. package/apps/web/src/features/chat/ui/ClaudeLoginView.tsx +44 -0
  162. package/apps/web/src/features/chat/ui/PermissionCard.tsx +37 -0
  163. package/apps/web/src/features/chat/ui/SessionSidebar.tsx +280 -0
  164. package/apps/web/src/features/chat/ui/__tests__/AgentSelectModal.test.tsx +58 -0
  165. package/apps/web/src/features/chat/ui/__tests__/ChatInput.test.tsx +134 -0
  166. package/apps/web/src/features/chat/ui/__tests__/ChatMessage.test.tsx +106 -0
  167. package/apps/web/src/features/chat/ui/__tests__/ChatWorkspace.test.tsx +66 -0
  168. package/apps/web/src/features/diff/ui/DiffFileRow.tsx +73 -0
  169. package/apps/web/src/features/diff/ui/DiffHunk.tsx +61 -0
  170. package/apps/web/src/features/diff/ui/FileChangeBadge.tsx +23 -0
  171. package/apps/web/src/features/diff/ui/__tests__/DiffFileRow.test.tsx +40 -0
  172. package/apps/web/src/features/diff/ui/__tests__/DiffHunk.test.tsx +24 -0
  173. package/apps/web/src/features/diff/ui/__tests__/FileChangeBadge.test.tsx +16 -0
  174. package/apps/web/src/features/fs/api/fs.api.ts +14 -0
  175. package/apps/web/src/features/fs/hooks/useDirBrowser.ts +50 -0
  176. package/apps/web/src/features/harness/api/__tests__/harness.api.test.ts +73 -0
  177. package/apps/web/src/features/harness/api/harness.api.ts +46 -0
  178. package/apps/web/src/features/harness/hooks/__tests__/useHarness.test.ts +65 -0
  179. package/apps/web/src/features/harness/hooks/useHarness.ts +66 -0
  180. package/apps/web/src/features/harness/ui/HarnessModal.tsx +171 -0
  181. package/apps/web/src/features/harness/ui/__tests__/HarnessModal.test.tsx +46 -0
  182. package/apps/web/src/features/status/ui/AgentStatusModal.tsx +267 -0
  183. package/apps/web/src/features/status/ui/__tests__/AgentStatusModal.test.tsx +71 -0
  184. package/apps/web/src/features/tasks/api/__tests__/changelog.api.test.ts +89 -0
  185. package/apps/web/src/features/tasks/api/__tests__/tasks.api.test.ts +282 -0
  186. package/apps/web/src/features/tasks/api/changelog.api.ts +52 -0
  187. package/apps/web/src/features/tasks/api/tasks.api.ts +175 -0
  188. package/apps/web/src/features/tasks/container/TaskDetailPageContainer.tsx +69 -0
  189. package/apps/web/src/features/tasks/hooks/__tests__/useChangelogCodeCopy.test.ts +48 -0
  190. package/apps/web/src/features/tasks/hooks/__tests__/useTaskChangelog.test.ts +48 -0
  191. package/apps/web/src/features/tasks/hooks/__tests__/useTaskCreate.test.ts +217 -0
  192. package/apps/web/src/features/tasks/hooks/__tests__/useTaskEdit.test.ts +152 -0
  193. package/apps/web/src/features/tasks/hooks/__tests__/useTaskExecution.test.ts +143 -0
  194. package/apps/web/src/features/tasks/hooks/__tests__/useTaskList.test.ts +168 -0
  195. package/apps/web/src/features/tasks/hooks/__tests__/useTaskNotification.test.ts +125 -0
  196. package/apps/web/src/features/tasks/hooks/__tests__/useTaskRuns.test.ts +51 -0
  197. package/apps/web/src/features/tasks/hooks/useChangelogCodeCopy.ts +52 -0
  198. package/apps/web/src/features/tasks/hooks/useCopyToClipboard.ts +47 -0
  199. package/apps/web/src/features/tasks/hooks/useTaskChangelog.ts +32 -0
  200. package/apps/web/src/features/tasks/hooks/useTaskCreate.ts +137 -0
  201. package/apps/web/src/features/tasks/hooks/useTaskDetail.ts +217 -0
  202. package/apps/web/src/features/tasks/hooks/useTaskEdit.ts +130 -0
  203. package/apps/web/src/features/tasks/hooks/useTaskExecution.ts +137 -0
  204. package/apps/web/src/features/tasks/hooks/useTaskList.ts +159 -0
  205. package/apps/web/src/features/tasks/hooks/useTaskNotification.ts +80 -0
  206. package/apps/web/src/features/tasks/hooks/useTaskRuns.ts +32 -0
  207. package/apps/web/src/features/tasks/ui/AgentOutputPanel.tsx +203 -0
  208. package/apps/web/src/features/tasks/ui/AgentRoleSelect.tsx +97 -0
  209. package/apps/web/src/features/tasks/ui/ChangelogPanel.tsx +321 -0
  210. package/apps/web/src/features/tasks/ui/RunHistoryPanel.tsx +193 -0
  211. package/apps/web/src/features/tasks/ui/TaskCreateModal.tsx +205 -0
  212. package/apps/web/src/features/tasks/ui/TaskDetailView.tsx +413 -0
  213. package/apps/web/src/features/tasks/ui/TaskEditModal.tsx +165 -0
  214. package/apps/web/src/features/tasks/ui/TaskListModal.tsx +591 -0
  215. package/apps/web/src/features/tasks/ui/__tests__/AgentRoleSelect.test.tsx +91 -0
  216. package/apps/web/src/features/tasks/ui/__tests__/ChangelogPanel.test.tsx +94 -0
  217. package/apps/web/src/features/tasks/ui/__tests__/RunHistoryPanel.test.tsx +71 -0
  218. package/apps/web/src/features/tasks/ui/__tests__/TaskCreateModal.test.tsx +153 -0
  219. package/apps/web/src/features/tasks/ui/__tests__/TaskEditModal.test.tsx +75 -0
  220. package/apps/web/src/features/tasks/ui/__tests__/TaskListModal.test.tsx +243 -0
  221. package/apps/web/src/hooks/useWorkingDir.ts +28 -0
  222. package/apps/web/src/lib/__tests__/ansi.test.ts +88 -0
  223. package/apps/web/src/lib/ansi.ts +105 -0
  224. package/apps/web/src/lib/constants.ts +4 -0
  225. package/apps/web/src/lib/quota.ts +22 -0
  226. package/apps/web/src/lib/theme.tsx +78 -0
  227. package/apps/web/src/lib/toast.tsx +175 -0
  228. package/apps/web/src/store/agentStatusStore.ts +38 -0
  229. package/apps/web/tsconfig.json +18 -0
  230. package/apps/web/vitest.config.ts +25 -0
  231. package/apps/web/vitest.setup.ts +10 -0
  232. package/package.json +85 -0
  233. package/packages/cli/dist/commands/check.d.ts +1 -0
  234. package/packages/cli/dist/commands/check.js +89 -0
  235. package/packages/cli/dist/commands/init.d.ts +5 -0
  236. package/packages/cli/dist/commands/init.js +183 -0
  237. package/packages/cli/dist/commands/start.d.ts +4 -0
  238. package/packages/cli/dist/commands/start.js +188 -0
  239. package/packages/cli/dist/index.d.ts +2 -0
  240. package/packages/cli/dist/index.js +71 -0
  241. package/packages/cli/dist/utils/agent-tools.d.ts +28 -0
  242. package/packages/cli/dist/utils/agent-tools.js +193 -0
  243. package/packages/cli/dist/utils/project-init.d.ts +12 -0
  244. package/packages/cli/dist/utils/project-init.js +258 -0
  245. package/packages/cli/dist/utils/proxy.d.ts +8 -0
  246. package/packages/cli/dist/utils/proxy.js +138 -0
  247. package/packages/cli/package.json +30 -0
  248. package/packages/cli/src/commands/check.ts +77 -0
  249. package/packages/cli/src/commands/init.ts +209 -0
  250. package/packages/cli/src/commands/start.ts +183 -0
  251. package/packages/cli/src/index.ts +91 -0
  252. package/packages/cli/src/utils/agent-tools.ts +201 -0
  253. package/packages/cli/src/utils/project-init.ts +252 -0
  254. package/packages/cli/src/utils/proxy.ts +123 -0
  255. package/packages/cli/tsconfig.json +14 -0
  256. package/packages/eslint-config/base.mjs +31 -0
  257. package/packages/eslint-config/nest.mjs +55 -0
  258. package/packages/eslint-config/next.mjs +23 -0
  259. package/packages/eslint-config/package.json +20 -0
  260. package/packages/typescript-config/base.json +16 -0
  261. package/packages/typescript-config/nestjs.json +17 -0
  262. package/packages/typescript-config/nextjs.json +15 -0
  263. package/packages/typescript-config/package.json +11 -0
  264. package/turbo.json +28 -0
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.ensureProjectReady = ensureProjectReady;
40
+ exports.findProjectRoot = findProjectRoot;
41
+ const fs_1 = require("fs");
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const child_process_1 = require("child_process");
45
+ const chalk_1 = __importDefault(require("chalk"));
46
+ const ora_1 = __importDefault(require("ora"));
47
+ const agent_tools_1 = require("./agent-tools");
48
+ const PROJECT_MARKER_WORKSPACES = ['apps/*', 'packages/*'];
49
+ const RUNTIME_DIRS = [
50
+ '.ji',
51
+ path.join('.ji', 'logs'),
52
+ path.join('.ji', 'worktrees'),
53
+ path.join('.ji', 'harness'),
54
+ path.join('.ji', 'agents'),
55
+ path.join('.ji', 'agents', 'gemini'),
56
+ path.join('.ji', 'agents', 'codex'),
57
+ ];
58
+ const COPY_EXCLUDES = new Set([
59
+ '.git',
60
+ '.claude',
61
+ '.turbo',
62
+ 'node_modules',
63
+ '.next',
64
+ 'out',
65
+ 'coverage',
66
+ '.env',
67
+ '.env.local',
68
+ ]);
69
+ const COPY_EXCLUDED_SUFFIXES = [
70
+ path.normalize('apps/server/dist'),
71
+ path.normalize('apps/web/.next'),
72
+ path.normalize('apps/web/out'),
73
+ path.normalize('packages/typescript-config/dist'),
74
+ ];
75
+ function ensureProjectReady(options, platform) {
76
+ try {
77
+ const cwdProjectRoot = findProjectRoot(process.cwd());
78
+ const targetRoot = resolveTargetRoot(options.targetDir, cwdProjectRoot);
79
+ if (!cwdProjectRoot || path.resolve(cwdProjectRoot) !== path.resolve(targetRoot)) {
80
+ const scaffoldOk = scaffoldProject(targetRoot, Boolean(options.force));
81
+ if (!scaffoldOk)
82
+ return { ok: false, projectRoot: targetRoot };
83
+ }
84
+ else {
85
+ console.log(chalk_1.default.green(`βœ“ ν”„λ‘œμ νŠΈ 감지: ${cwdProjectRoot}`));
86
+ }
87
+ ensureRuntimeDirs();
88
+ if (options.skipInstall) {
89
+ console.log(chalk_1.default.yellow('ν”„λ‘œμ νŠΈ μ˜μ‘΄μ„± μ„€μΉ˜λ₯Ό κ±΄λ„ˆλœλ‹ˆλ‹€.\n'));
90
+ return { ok: true, projectRoot: targetRoot };
91
+ }
92
+ const installOk = ensureDependencies(targetRoot, platform);
93
+ return { ok: installOk, projectRoot: targetRoot };
94
+ }
95
+ catch (error) {
96
+ console.error(chalk_1.default.red('ν”„λ‘œμ νŠΈ μ΄ˆκΈ°ν™” 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.'));
97
+ console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
98
+ return { ok: false, projectRoot: process.cwd() };
99
+ }
100
+ }
101
+ function resolveTargetRoot(targetDir, cwdProjectRoot) {
102
+ if (targetDir) {
103
+ return path.resolve(process.cwd(), targetDir);
104
+ }
105
+ return cwdProjectRoot ?? process.cwd();
106
+ }
107
+ function findProjectRoot(startDir) {
108
+ let current = path.resolve(startDir);
109
+ while (true) {
110
+ if (isProjectRoot(current))
111
+ return current;
112
+ const parent = path.dirname(current);
113
+ if (parent === current)
114
+ return null;
115
+ current = parent;
116
+ }
117
+ }
118
+ function isProjectRoot(dir) {
119
+ const packageJsonPath = path.join(dir, 'package.json');
120
+ if (!(0, fs_1.existsSync)(packageJsonPath))
121
+ return false;
122
+ try {
123
+ const packageJson = require(packageJsonPath);
124
+ const workspaces = packageJson.workspaces ?? [];
125
+ return PROJECT_MARKER_WORKSPACES.every((workspace) => workspaces.includes(workspace));
126
+ }
127
+ catch {
128
+ return false;
129
+ }
130
+ }
131
+ function scaffoldProject(targetRoot, force) {
132
+ const sourceRoot = getTemplateRoot();
133
+ if (!isDirectoryUsableForScaffold(targetRoot, force)) {
134
+ console.error(chalk_1.default.red(`λŒ€μƒ 폴더가 λΉ„μ–΄ μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€: ${targetRoot}`));
135
+ console.error(chalk_1.default.gray(' 빈 ν΄λ”μ—μ„œ μ‹€ν–‰ν•˜κ±°λ‚˜ jccli init <folder> λ₯Ό μ‚¬μš©ν•΄ μ£Όμ„Έμš”.'));
136
+ console.error(chalk_1.default.gray(' κΈ°μ‘΄ 파일 μœ„μ— λ³΅μ‚¬ν•˜λ €λ©΄ --force μ˜΅μ…˜μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.'));
137
+ return false;
138
+ }
139
+ (0, fs_1.mkdirSync)(targetRoot, { recursive: true });
140
+ const spinner = (0, ora_1.default)({
141
+ text: `ν”„λ‘œμ νŠΈ 파일 볡사 쀑: ${targetRoot}`,
142
+ color: 'cyan',
143
+ }).start();
144
+ try {
145
+ copyDirectory(sourceRoot, targetRoot, sourceRoot);
146
+ spinner.succeed('ν”„λ‘œμ νŠΈ 파일 볡사 μ™„λ£Œ');
147
+ return true;
148
+ }
149
+ catch (error) {
150
+ spinner.fail('ν”„λ‘œμ νŠΈ 파일 볡사 μ‹€νŒ¨');
151
+ console.error(chalk_1.default.red(error instanceof Error ? error.message : String(error)));
152
+ return false;
153
+ }
154
+ }
155
+ function getTemplateRoot() {
156
+ return path.resolve(__dirname, '..', '..', '..', '..');
157
+ }
158
+ function isDirectoryUsableForScaffold(targetRoot, force) {
159
+ if (!(0, fs_1.existsSync)(targetRoot))
160
+ return true;
161
+ if (!(0, fs_1.statSync)(targetRoot).isDirectory())
162
+ return false;
163
+ if (force)
164
+ return true;
165
+ return (0, fs_1.readdirSync)(targetRoot).filter((entry) => entry !== '.DS_Store').length === 0;
166
+ }
167
+ function copyDirectory(sourceDir, targetDir, sourceRoot) {
168
+ (0, fs_1.mkdirSync)(targetDir, { recursive: true });
169
+ for (const entry of (0, fs_1.readdirSync)(sourceDir, { withFileTypes: true })) {
170
+ const sourcePath = path.join(sourceDir, entry.name);
171
+ const targetPath = path.join(targetDir, entry.name);
172
+ const relativePath = path.relative(sourceRoot, sourcePath);
173
+ if (shouldSkipCopy(entry.name, relativePath))
174
+ continue;
175
+ if (entry.isDirectory()) {
176
+ copyDirectory(sourcePath, targetPath, sourceRoot);
177
+ continue;
178
+ }
179
+ if (entry.isFile()) {
180
+ (0, fs_1.copyFileSync)(sourcePath, targetPath);
181
+ }
182
+ }
183
+ }
184
+ function shouldSkipCopy(entryName, relativePath) {
185
+ if (COPY_EXCLUDES.has(entryName))
186
+ return true;
187
+ if (entryName.endsWith('.log'))
188
+ return true;
189
+ if (entryName.endsWith('.tsbuildinfo'))
190
+ return true;
191
+ if (/^\.env\..*\.local$/.test(entryName))
192
+ return true;
193
+ const normalized = path.normalize(relativePath);
194
+ return COPY_EXCLUDED_SUFFIXES.some((suffix) => normalized === suffix || normalized.startsWith(`${suffix}${path.sep}`));
195
+ }
196
+ function ensureRuntimeDirs() {
197
+ const home = os.homedir();
198
+ try {
199
+ for (const dir of RUNTIME_DIRS) {
200
+ (0, fs_1.mkdirSync)(path.join(home, dir), { recursive: true });
201
+ }
202
+ console.log(chalk_1.default.green(`βœ“ λŸ°νƒ€μž„ 디렉터리 μ€€λΉ„: ${path.join(home, '.ji')}`));
203
+ }
204
+ catch (error) {
205
+ console.error(chalk_1.default.red('λŸ°νƒ€μž„ 디렉터리λ₯Ό λ§Œλ“€ 수 μ—†μŠ΅λ‹ˆλ‹€.'));
206
+ throw error;
207
+ }
208
+ }
209
+ function ensureDependencies(projectRoot, platform) {
210
+ if ((0, fs_1.existsSync)(path.join(projectRoot, 'node_modules'))) {
211
+ console.log(chalk_1.default.green('βœ“ ν”„λ‘œμ νŠΈ μ˜μ‘΄μ„± μ„€μΉ˜ 확인: node_modules 감지\n'));
212
+ return true;
213
+ }
214
+ const spinner = (0, ora_1.default)({
215
+ text: 'ν”„λ‘œμ νŠΈ μ˜μ‘΄μ„± μ„€μΉ˜ 쀑...',
216
+ color: 'cyan',
217
+ }).start();
218
+ const result = runNpmInstall(projectRoot, platform);
219
+ if (result.ok) {
220
+ spinner.succeed('ν”„λ‘œμ νŠΈ μ˜μ‘΄μ„± μ„€μΉ˜ μ™„λ£Œ');
221
+ console.log();
222
+ return true;
223
+ }
224
+ spinner.fail('ν”„λ‘œμ νŠΈ μ˜μ‘΄μ„± μ„€μΉ˜ μ‹€νŒ¨');
225
+ if (result.stderr)
226
+ console.error(chalk_1.default.red(result.stderr));
227
+ if (result.error)
228
+ console.error(chalk_1.default.red(result.error));
229
+ console.error(chalk_1.default.yellow('\nμˆ˜λ™ μ„€μΉ˜ λͺ…λ Ή:'));
230
+ console.error(chalk_1.default.gray(` cd ${projectRoot}`));
231
+ console.error(chalk_1.default.gray(' npm install\n'));
232
+ return false;
233
+ }
234
+ function runNpmInstall(projectRoot, platform) {
235
+ try {
236
+ const result = (0, child_process_1.spawnSync)((0, agent_tools_1.getNpmCommand)(platform), ['install'], {
237
+ cwd: projectRoot,
238
+ stdio: ['inherit', 'pipe', 'pipe'],
239
+ encoding: 'utf8',
240
+ shell: platform === 'windows',
241
+ windowsHide: true,
242
+ });
243
+ return {
244
+ ok: result.status === 0 && !result.error,
245
+ stdout: result.stdout?.trim() ?? '',
246
+ stderr: result.stderr?.trim() ?? '',
247
+ error: result.error?.message,
248
+ };
249
+ }
250
+ catch (error) {
251
+ return {
252
+ ok: false,
253
+ stdout: '',
254
+ stderr: '',
255
+ error: error instanceof Error ? error.message : 'Unknown npm install error',
256
+ };
257
+ }
258
+ }
@@ -0,0 +1,8 @@
1
+ import * as http from 'http';
2
+ export interface ProxyServerOptions {
3
+ port: number;
4
+ serverPort: number;
5
+ webPort: number;
6
+ }
7
+ export declare function startProxyServer(options: ProxyServerOptions): Promise<http.Server>;
8
+ export declare function waitForPort(port: number, timeoutMs: number): Promise<boolean>;
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.startProxyServer = startProxyServer;
37
+ exports.waitForPort = waitForPort;
38
+ const http = __importStar(require("http"));
39
+ const net = __importStar(require("net"));
40
+ // NestJS 컨트둀러/κ²Œμ΄νŠΈμ›¨μ΄κ°€ μ‚¬μš©ν•˜λŠ” 경둜 prefix. λ‚˜λ¨Έμ§€λŠ” λͺ¨λ‘ Next.js둜 보낸닀.
41
+ const BACKEND_PREFIXES = [
42
+ 'agents',
43
+ 'tasks',
44
+ 'fs',
45
+ 'harness',
46
+ 'sessions',
47
+ 'conversations',
48
+ 'docs',
49
+ 'docs-json',
50
+ 'socket.io',
51
+ ];
52
+ function isBackendPath(url) {
53
+ const pathname = url.split('?')[0] ?? '';
54
+ return BACKEND_PREFIXES.some((prefix) => pathname === `/${prefix}` || pathname.startsWith(`/${prefix}/`));
55
+ }
56
+ function startProxyServer(options) {
57
+ const { port, serverPort, webPort } = options;
58
+ const resolveTargetPort = (url) => isBackendPath(url ?? '/') ? serverPort : webPort;
59
+ const server = http.createServer((req, res) => {
60
+ try {
61
+ const targetPort = resolveTargetPort(req.url);
62
+ const proxyReq = http.request({
63
+ host: '127.0.0.1',
64
+ port: targetPort,
65
+ path: req.url,
66
+ method: req.method,
67
+ headers: req.headers,
68
+ }, (proxyRes) => {
69
+ res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
70
+ proxyRes.pipe(res);
71
+ });
72
+ proxyReq.on('error', () => {
73
+ try {
74
+ if (!res.headersSent) {
75
+ res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' });
76
+ }
77
+ res.end('μ—…μŠ€νŠΈλ¦Ό μ„œλ²„κ°€ 아직 μ€€λΉ„λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ μƒˆλ‘œκ³ μΉ¨ν•΄ μ£Όμ„Έμš”.');
78
+ }
79
+ catch {
80
+ res.destroy();
81
+ }
82
+ });
83
+ req.pipe(proxyReq);
84
+ }
85
+ catch {
86
+ res.destroy();
87
+ }
88
+ });
89
+ // WebSocket(socket.io, Next.js HMR) μ—…κ·Έλ ˆμ΄λ“œ μš”μ²­μ„ 원본 헀더 κ·ΈλŒ€λ‘œ ν„°λ„λ§ν•œλ‹€.
90
+ server.on('upgrade', (req, socket, head) => {
91
+ try {
92
+ const targetPort = resolveTargetPort(req.url);
93
+ const upstream = net.connect(targetPort, '127.0.0.1', () => {
94
+ const headerLines = [`${req.method} ${req.url} HTTP/1.1`];
95
+ for (let i = 0; i < req.rawHeaders.length; i += 2) {
96
+ headerLines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);
97
+ }
98
+ upstream.write(`${headerLines.join('\r\n')}\r\n\r\n`);
99
+ if (head.length > 0)
100
+ upstream.write(head);
101
+ socket.pipe(upstream).pipe(socket);
102
+ });
103
+ upstream.on('error', () => socket.destroy());
104
+ socket.on('error', () => upstream.destroy());
105
+ }
106
+ catch {
107
+ socket.destroy();
108
+ }
109
+ });
110
+ return new Promise((resolve, reject) => {
111
+ server.once('error', reject);
112
+ server.listen(port, () => {
113
+ server.removeListener('error', reject);
114
+ resolve(server);
115
+ });
116
+ });
117
+ }
118
+ function waitForPort(port, timeoutMs) {
119
+ const deadline = Date.now() + timeoutMs;
120
+ return new Promise((resolve) => {
121
+ const tryConnect = () => {
122
+ const socket = net.connect(port, '127.0.0.1');
123
+ socket.once('connect', () => {
124
+ socket.destroy();
125
+ resolve(true);
126
+ });
127
+ socket.once('error', () => {
128
+ socket.destroy();
129
+ if (Date.now() > deadline) {
130
+ resolve(false);
131
+ return;
132
+ }
133
+ setTimeout(tryConnect, 500);
134
+ });
135
+ };
136
+ tryConnect();
137
+ });
138
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@ji/cli",
3
+ "version": "0.2.0",
4
+ "description": "jccli - Claude Code, Gemini CLI, and Codex web integration CLI",
5
+ "private": true,
6
+ "bin": {
7
+ "jccli": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "clean": "rm -rf dist",
14
+ "lint": "eslint \"src/**/*.ts\"",
15
+ "lint:fix": "eslint \"src/**/*.ts\" --fix"
16
+ },
17
+ "dependencies": {
18
+ "chalk": "^5.4.1",
19
+ "commander": "^13.1.0",
20
+ "ora": "^8.2.0"
21
+ },
22
+ "devDependencies": {
23
+ "@ji/typescript-config": "*",
24
+ "@types/node": "^24.0.0",
25
+ "typescript": "^5.7.3"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }
@@ -0,0 +1,77 @@
1
+ import * as os from 'os';
2
+
3
+ import chalk from 'chalk';
4
+
5
+ import {
6
+ AGENT_TOOLS,
7
+ findWindowsGitBashPath,
8
+ getCommandVersion,
9
+ getPlatform,
10
+ isCommandAvailable,
11
+ type AgentTool,
12
+ type SupportedPlatform,
13
+ } from '../utils/agent-tools';
14
+
15
+ interface ToolStatus {
16
+ name: string;
17
+ packageName: string;
18
+ version: string | null;
19
+ installed: boolean;
20
+ }
21
+
22
+ export function runCheck(): void {
23
+ const platform = getPlatform();
24
+ const results = AGENT_TOOLS.map((tool) => getToolStatus(tool, platform));
25
+
26
+ console.log(chalk.bold('\nπŸ” μ—μ΄μ „νŠΈ CLI μ„€μΉ˜ μƒνƒœ 확인\n'));
27
+ console.log(chalk.gray(`ν”Œλž«νΌ: ${platform} (${os.arch()})\n`));
28
+
29
+ for (const result of results) {
30
+ if (result.installed) {
31
+ console.log(chalk.green(` βœ“ ${result.name.padEnd(14)} ${result.version ?? ''}`));
32
+ continue;
33
+ }
34
+
35
+ console.log(chalk.red(` βœ— ${result.name.padEnd(14)} λ―Έμ„€μΉ˜`));
36
+ console.log(chalk.gray(` μ„€μΉ˜: npm install -g ${result.packageName}`));
37
+ }
38
+
39
+ printWindowsClaudeNotice(platform);
40
+ printSummary(results);
41
+ }
42
+
43
+ function getToolStatus(tool: AgentTool, platform: SupportedPlatform): ToolStatus {
44
+ const installed = isCommandAvailable(tool.command, platform);
45
+
46
+ return {
47
+ name: tool.name,
48
+ packageName: tool.packageName,
49
+ installed,
50
+ version: installed ? getCommandVersion(tool.command, platform) : null,
51
+ };
52
+ }
53
+
54
+ function printWindowsClaudeNotice(platform: SupportedPlatform): void {
55
+ if (platform !== 'windows') return;
56
+
57
+ const gitBashPath = findWindowsGitBashPath();
58
+ if (gitBashPath) {
59
+ console.log(chalk.gray(`\nClaude Code Git Bash 감지: ${gitBashPath}`));
60
+ return;
61
+ }
62
+
63
+ console.log(chalk.yellow('\nClaude Code μ‹€ν–‰μ—λŠ” Git for Windows λ˜λŠ” WSL이 ν•„μš”ν•  수 μžˆμŠ΅λ‹ˆλ‹€.'));
64
+ }
65
+
66
+ function printSummary(results: ToolStatus[]): void {
67
+ const missing = results.filter((result) => !result.installed);
68
+
69
+ console.log();
70
+ if (missing.length === 0) {
71
+ console.log(chalk.bold.green('λͺ¨λ“  도ꡬ가 μ„€μΉ˜λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.'));
72
+ } else {
73
+ console.log(chalk.yellow(`λ―Έμ„€μΉ˜ 도ꡬ: ${missing.map((result) => result.name).join(', ')}`));
74
+ console.log(chalk.gray(' jccli init 으둜 ν•œ λ²ˆμ— μ„€μΉ˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.'));
75
+ }
76
+ console.log();
77
+ }