@ripla/godd-mcp 1.0.4-canary.9 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/README.md +89 -94
  2. package/dist/godd.cjs +349 -233
  3. package/dist/godd.js +2193 -838
  4. package/dist/index.js +152 -122
  5. package/{notes-api → notes/api}/.env.example +6 -1
  6. package/{notes-api → notes/api}/README.md +6 -5
  7. package/{notes-api → notes/api}/app/main.py +29 -2
  8. package/{notes-api → notes/api}/app/routers/auth.py +6 -1
  9. package/{notes-api → notes/api}/app/routers/issues.py +157 -1
  10. package/{notes-api → notes/api}/app/routers/pr.py +2 -2
  11. package/{notes-api → notes/api}/app/services/github_app_token.py +32 -1
  12. package/{notes-api → notes/api}/app/services/github_issues.py +101 -11
  13. package/{notes-api → notes/api}/app/services/github_pr.py +6 -1
  14. package/{notes-api → notes/api}/tests/test_github_app_token.py +49 -1
  15. package/{notes-api → notes/api}/tests/test_github_service.py +42 -0
  16. package/notes/api/tests/test_health.py +52 -0
  17. package/{notes-api → notes/api}/tests/test_issues.py +216 -0
  18. package/{notes-api → notes/api}/tests/test_pr.py +24 -0
  19. package/{notes-api → notes/api}/tests/test_pr_chain.py +19 -0
  20. package/{notes-api → notes/api}/uv.lock +178 -2
  21. package/notes/app/DESIGN.md +273 -0
  22. package/{notes-app → notes/app}/README.md +4 -1
  23. package/notes/app/docker/Dockerfile.e2e +19 -0
  24. package/notes/app/docker/Dockerfile.prod +15 -0
  25. package/notes/app/docker/Dockerfile.test +17 -0
  26. package/notes/app/e2e/file-tree.spec.ts +26 -0
  27. package/notes/app/e2e/file-view.spec.ts +25 -0
  28. package/notes/app/e2e/fixtures.ts +28 -0
  29. package/{notes-app → notes/app}/e2e/global-setup.ts +5 -7
  30. package/notes/app/e2e/login.spec.ts +25 -0
  31. package/notes/app/e2e/pages/login-page.ts +29 -0
  32. package/notes/app/e2e/pages/main-page.ts +29 -0
  33. package/notes/app/e2e/panel-resize-handle.spec.ts +213 -0
  34. package/{notes-app → notes/app}/eslint.config.js +9 -0
  35. package/{notes-app → notes/app}/package.json +0 -3
  36. package/{notes-app → notes/app}/pnpm-workspace.yaml +1 -0
  37. package/notes/app/src/components/CommentPanel.test.tsx +194 -0
  38. package/{notes-app → notes/app}/src/components/CommentPanel.tsx +119 -10
  39. package/notes/app/src/components/CommentSelectionPopover.tsx +26 -0
  40. package/notes/app/src/components/EditToolbar.test.tsx +102 -0
  41. package/{notes-app → notes/app}/src/components/EditToolbar.tsx +5 -54
  42. package/notes/app/src/components/FileInfoPanel.branch-tab.test.tsx +250 -0
  43. package/notes/app/src/components/FileInfoPanel.history-tab.test.tsx +146 -0
  44. package/notes/app/src/components/FileInfoPanel.test.tsx +101 -0
  45. package/{notes-app → notes/app}/src/components/FileInfoPanel.tsx +135 -20
  46. package/notes/app/src/components/IssueCommentThread.test.tsx +93 -0
  47. package/notes/app/src/components/IssueCommentThread.tsx +156 -0
  48. package/notes/app/src/components/IssueDetailView.test.tsx +1118 -0
  49. package/notes/app/src/components/IssueDetailView.tsx +476 -0
  50. package/notes/app/src/components/IssueList.test.tsx +545 -0
  51. package/notes/app/src/components/IssueList.tsx +374 -0
  52. package/{notes-app → notes/app}/src/components/LabelSelector.test.tsx +94 -8
  53. package/notes/app/src/components/LabelSelector.tsx +452 -0
  54. package/{notes-app → notes/app}/src/components/MarkdownEditor.tsx +140 -2
  55. package/notes/app/src/components/PanelResizeHandle.test.tsx +481 -0
  56. package/notes/app/src/components/PanelResizeHandle.tsx +96 -0
  57. package/{notes-app → notes/app}/src/hooks/useEditSession.test.ts +171 -23
  58. package/{notes-app → notes/app}/src/hooks/useEditSession.ts +49 -62
  59. package/notes/app/src/hooks/useMdUpLayout.test.ts +10 -0
  60. package/notes/app/src/hooks/useMdUpLayout.ts +27 -0
  61. package/notes/app/src/hooks/usePeriodicSync.test.ts +244 -0
  62. package/notes/app/src/hooks/usePeriodicSync.ts +83 -0
  63. package/notes/app/src/hooks/useResizablePanelWidth.test.ts +251 -0
  64. package/notes/app/src/hooks/useResizablePanelWidth.ts +167 -0
  65. package/{notes-app → notes/app}/src/lib/api.test.ts +81 -1
  66. package/{notes-app → notes/app}/src/lib/api.ts +98 -4
  67. package/notes/app/src/lib/commentAnchor.test.ts +22 -0
  68. package/notes/app/src/lib/commentAnchor.ts +28 -0
  69. package/notes/app/src/lib/commentHighlight.test.ts +110 -0
  70. package/notes/app/src/lib/commentHighlight.ts +44 -0
  71. package/notes/app/src/lib/github-sync.test.ts +126 -0
  72. package/notes/app/src/lib/github-sync.ts +89 -0
  73. package/notes/app/src/lib/issue-list-utils.test.ts +275 -0
  74. package/notes/app/src/lib/issue-list-utils.ts +135 -0
  75. package/notes/app/src/lib/issue-mobile-layout.test.ts +17 -0
  76. package/notes/app/src/lib/issue-mobile-layout.ts +20 -0
  77. package/notes/app/src/lib/issue-url-sync.test.ts +73 -0
  78. package/notes/app/src/lib/issue-url-sync.ts +43 -0
  79. package/notes/app/src/lib/main-page-default-view.test.ts +37 -0
  80. package/notes/app/src/lib/main-page-default-view.ts +15 -0
  81. package/notes/app/src/lib/resizable-panel.test.ts +199 -0
  82. package/notes/app/src/lib/resizable-panel.ts +136 -0
  83. package/notes/app/src/pages/LoginPage.test.tsx +17 -0
  84. package/notes/app/src/pages/MainPage.branch-modal.test.tsx +226 -0
  85. package/notes/app/src/pages/MainPage.issue-sync.test.tsx +145 -0
  86. package/notes/app/src/pages/MainPage.sidebar.test.tsx +361 -0
  87. package/{notes-app → notes/app}/src/pages/MainPage.tsx +406 -61
  88. package/{notes-app → notes/app}/src/pages/SettingsPage.test.tsx +32 -23
  89. package/{notes-app → notes/app}/src/pages/UserManagementPage.test.tsx +8 -18
  90. package/notes/app/src/test/mocks.ts +156 -0
  91. package/notes/app/src/test/render.tsx +27 -0
  92. package/package.json +3 -5
  93. package/notes-api/tests/test_health.py +0 -11
  94. package/notes-app/docker/Dockerfile.e2e +0 -14
  95. package/notes-app/docker/Dockerfile.prod +0 -12
  96. package/notes-app/docker/Dockerfile.test +0 -12
  97. package/notes-app/e2e/file-tree.spec.ts +0 -29
  98. package/notes-app/e2e/file-view.spec.ts +0 -24
  99. package/notes-app/e2e/login.spec.ts +0 -32
  100. package/notes-app/src/components/IssueDetailView.test.tsx +0 -201
  101. package/notes-app/src/components/IssueDetailView.tsx +0 -318
  102. package/notes-app/src/components/IssueList.test.tsx +0 -93
  103. package/notes-app/src/components/IssueList.tsx +0 -169
  104. package/notes-app/src/components/LabelSelector.tsx +0 -276
  105. package/notes-app/src/pages/LoginPage.test.tsx +0 -29
  106. package/stacks/django-vue.yaml +0 -33
  107. package/stacks/fastapi-react.yaml +0 -160
  108. package/stacks/flutter-firebase.yaml +0 -58
  109. package/stacks/nextjs-prisma.yaml +0 -33
  110. package/stacks/schema.json +0 -144
  111. package/templates/agents/architect.hbs +0 -183
  112. package/templates/agents/auto-documenter.hbs +0 -36
  113. package/templates/agents/backend-developer.hbs +0 -175
  114. package/templates/agents/code-reviewer.hbs +0 -29
  115. package/templates/agents/database-developer.hbs +0 -52
  116. package/templates/agents/debug-specialist.hbs +0 -39
  117. package/templates/agents/environment-setup.hbs +0 -41
  118. package/templates/agents/frontend-developer.hbs +0 -45
  119. package/templates/agents/integration-qa.hbs +0 -26
  120. package/templates/agents/performance-qa.hbs +0 -24
  121. package/templates/agents/pr-writer.hbs +0 -53
  122. package/templates/agents/quality-lead.hbs +0 -26
  123. package/templates/agents/requirements-analyst.hbs +0 -26
  124. package/templates/agents/security-analyst.hbs +0 -21
  125. package/templates/agents/security-reviewer.hbs +0 -20
  126. package/templates/agents/ssot-updater.hbs +0 -45
  127. package/templates/agents/technical-writer.hbs +0 -28
  128. package/templates/agents/unit-test-engineer.hbs +0 -19
  129. package/templates/agents/user-clone.hbs +0 -49
  130. package/templates/github-actions/aws/deploy-notes.yml.hbs +0 -117
  131. package/templates/github-actions/azure/deploy-notes.yml.hbs +0 -78
  132. package/templates/github-actions/gcp/deploy-notes.yml.hbs +0 -76
  133. package/templates/github-actions/vercel-railway/deploy-notes.yml.hbs +0 -49
  134. package/templates/mindsets/agent-stdio.hbs +0 -51
  135. package/templates/mindsets/dart.hbs +0 -39
  136. package/templates/mindsets/ddd-clean-architecture.hbs +0 -52
  137. package/templates/mindsets/electron.hbs +0 -41
  138. package/templates/mindsets/fastapi.hbs +0 -40
  139. package/templates/mindsets/flutter.hbs +0 -56
  140. package/templates/mindsets/kotlin.hbs +0 -46
  141. package/templates/mindsets/postgresql.hbs +0 -39
  142. package/templates/mindsets/python.hbs +0 -39
  143. package/templates/mindsets/react.hbs +0 -51
  144. package/templates/mindsets/swift.hbs +0 -46
  145. package/templates/mindsets/terraform.hbs +0 -53
  146. package/templates/mindsets/typescript.hbs +0 -34
  147. package/templates/mindsets/vite.hbs +0 -37
  148. package/templates/notes-compose.yml +0 -82
  149. package/templates/partials/cogito-geo.hbs +0 -84
  150. package/templates/partials/cogito-godd.hbs +0 -22
  151. package/templates/partials/cogito-grammar.hbs +0 -105
  152. package/templates/partials/cogito-particle.hbs +0 -76
  153. package/templates/partials/cogito-root-ai.hbs +0 -79
  154. package/templates/partials/cogito-root-arch.hbs +0 -75
  155. package/templates/partials/cogito-root-core.hbs +0 -75
  156. package/templates/partials/cogito-root-daily.hbs +0 -58
  157. package/templates/partials/cogito-root-dev.hbs +0 -71
  158. package/templates/partials/cogito-root-devops.hbs +0 -71
  159. package/templates/partials/cogito-root-framework.hbs +0 -80
  160. package/templates/partials/cogito-root-lang.hbs +0 -74
  161. package/templates/partials/godd-core.hbs +0 -50
  162. package/templates/partials/project-context.hbs +0 -52
  163. package/templates/partials/ssot-header.hbs +0 -40
  164. package/templates/partials/ssot-rules.hbs +0 -30
  165. package/templates/prompts/adr.hbs +0 -39
  166. package/templates/prompts/agent-dev-workflow.hbs +0 -34
  167. package/templates/prompts/analyze-report.hbs +0 -36
  168. package/templates/prompts/auto-documentation.hbs +0 -37
  169. package/templates/prompts/check.hbs +0 -52
  170. package/templates/prompts/commit.hbs +0 -96
  171. package/templates/prompts/dev.hbs +0 -127
  172. package/templates/prompts/docs-init.hbs +0 -101
  173. package/templates/prompts/docs-update.hbs +0 -51
  174. package/templates/prompts/git-workflow.hbs +0 -125
  175. package/templates/prompts/impact-analysis.hbs +0 -43
  176. package/templates/prompts/install.hbs +0 -40
  177. package/templates/prompts/new-branch.hbs +0 -61
  178. package/templates/prompts/notes-deploy.hbs +0 -138
  179. package/templates/prompts/pr-analyze.hbs +0 -44
  180. package/templates/prompts/pr-create.hbs +0 -125
  181. package/templates/prompts/push-execute.hbs +0 -83
  182. package/templates/prompts/push.hbs +0 -24
  183. package/templates/prompts/release-notes.hbs +0 -38
  184. package/templates/prompts/requirements-to-business-flow.hbs +0 -29
  185. package/templates/prompts/requirements-to-tickets.hbs +0 -26
  186. package/templates/prompts/review.hbs +0 -126
  187. package/templates/prompts/setup.hbs +0 -247
  188. package/templates/prompts/spec.hbs +0 -35
  189. package/templates/prompts/specification-to-tickets.hbs +0 -24
  190. package/templates/prompts/submit.hbs +0 -143
  191. package/templates/prompts/sync.hbs +0 -63
  192. package/templates/prompts/test-plan.hbs +0 -56
  193. package/templates/scripts/aws/terraform-backend-setup.sh.hbs +0 -149
  194. package/templates/terraform/aws/alb.tf.hbs +0 -58
  195. package/templates/terraform/aws/backend.tf.hbs +0 -10
  196. package/templates/terraform/aws/cloudfront.tf.hbs +0 -96
  197. package/templates/terraform/aws/ecr.tf.hbs +0 -30
  198. package/templates/terraform/aws/ecs.tf.hbs +0 -142
  199. package/templates/terraform/aws/iam.tf.hbs +0 -88
  200. package/templates/terraform/aws/local.tf.hbs +0 -34
  201. package/templates/terraform/aws/output.tf.hbs +0 -49
  202. package/templates/terraform/aws/provider.tf.hbs +0 -26
  203. package/templates/terraform/aws/rds.tf.hbs +0 -38
  204. package/templates/terraform/aws/s3.tf.hbs +0 -34
  205. package/templates/terraform/aws/secrets.tf.hbs +0 -53
  206. package/templates/terraform/aws/security_groups.tf.hbs +0 -81
  207. package/templates/terraform/aws/vpc.tf.hbs +0 -63
  208. package/templates/terraform/azure/backend.tf.hbs +0 -8
  209. package/templates/terraform/azure/iam.tf.hbs +0 -36
  210. package/templates/terraform/azure/main.tf.hbs +0 -203
  211. package/templates/terraform/azure/output.tf.hbs +0 -19
  212. package/templates/terraform/azure/provider.tf.hbs +0 -19
  213. package/templates/terraform/gcp/backend.tf.hbs +0 -6
  214. package/templates/terraform/gcp/iam.tf.hbs +0 -47
  215. package/templates/terraform/gcp/main.tf.hbs +0 -175
  216. package/templates/terraform/gcp/output.tf.hbs +0 -15
  217. package/templates/terraform/gcp/provider.tf.hbs +0 -19
  218. package/templates/terraform/vercel-railway/main.tf.hbs +0 -64
  219. package/templates/terraform/vercel-railway/output.tf.hbs +0 -11
  220. /package/{notes-api → notes/api}/.dockerignore +0 -0
  221. /package/{notes-api → notes/api}/alembic/README +0 -0
  222. /package/{notes-api → notes/api}/alembic/env.py +0 -0
  223. /package/{notes-api → notes/api}/alembic/script.py.mako +0 -0
  224. /package/{notes-api → notes/api}/alembic/versions/001_initial_notes_tables.py +0 -0
  225. /package/{notes-api → notes/api}/alembic/versions/002_add_performance_indexes.py +0 -0
  226. /package/{notes-api → notes/api}/alembic/versions/003_add_yjs_documents.py +0 -0
  227. /package/{notes-api → notes/api}/alembic/versions/004_add_comments.py +0 -0
  228. /package/{notes-api → notes/api}/alembic/versions/005_add_github_username.py +0 -0
  229. /package/{notes-api → notes/api}/alembic/versions/006_add_check_constraints.py +0 -0
  230. /package/{notes-api → notes/api}/alembic.ini +0 -0
  231. /package/{notes-api → notes/api}/app/__init__.py +0 -0
  232. /package/{notes-api → notes/api}/app/config.py +0 -0
  233. /package/{notes-api → notes/api}/app/database.py +0 -0
  234. /package/{notes-api → notes/api}/app/http_client.py +0 -0
  235. /package/{notes-api → notes/api}/app/models/__init__.py +0 -0
  236. /package/{notes-api → notes/api}/app/models/audit.py +0 -0
  237. /package/{notes-api → notes/api}/app/models/base.py +0 -0
  238. /package/{notes-api → notes/api}/app/models/collab.py +0 -0
  239. /package/{notes-api → notes/api}/app/models/comment.py +0 -0
  240. /package/{notes-api → notes/api}/app/models/session.py +0 -0
  241. /package/{notes-api → notes/api}/app/models/setting.py +0 -0
  242. /package/{notes-api → notes/api}/app/models/user.py +0 -0
  243. /package/{notes-api → notes/api}/app/path_validation.py +0 -0
  244. /package/{notes-api → notes/api}/app/routers/__init__.py +0 -0
  245. /package/{notes-api → notes/api}/app/routers/collab.py +0 -0
  246. /package/{notes-api → notes/api}/app/routers/comments.py +0 -0
  247. /package/{notes-api → notes/api}/app/routers/files.py +0 -0
  248. /package/{notes-api → notes/api}/app/routers/settings.py +0 -0
  249. /package/{notes-api → notes/api}/app/routers/tree.py +0 -0
  250. /package/{notes-api → notes/api}/app/routers/upload.py +0 -0
  251. /package/{notes-api → notes/api}/app/routers/users.py +0 -0
  252. /package/{notes-api → notes/api}/app/schemas/__init__.py +0 -0
  253. /package/{notes-api → notes/api}/app/schemas/auth.py +0 -0
  254. /package/{notes-api → notes/api}/app/schemas/user.py +0 -0
  255. /package/{notes-api → notes/api}/app/security.py +0 -0
  256. /package/{notes-api → notes/api}/app/services/__init__.py +0 -0
  257. /package/{notes-api → notes/api}/app/services/audit.py +0 -0
  258. /package/{notes-api → notes/api}/app/services/business_date.py +0 -0
  259. /package/{notes-api → notes/api}/app/services/collab.py +0 -0
  260. /package/{notes-api → notes/api}/app/services/github.py +0 -0
  261. /package/{notes-api → notes/api}/app/services/pr_chain.py +0 -0
  262. /package/{notes-api → notes/api}/app/startup.py +0 -0
  263. /package/{notes-api → notes/api}/docker/Dockerfile +0 -0
  264. /package/{notes-api → notes/api}/docker/Dockerfile.test +0 -0
  265. /package/{notes-api → notes/api}/pyproject.toml +0 -0
  266. /package/{notes-api → notes/api}/tests/conftest.py +0 -0
  267. /package/{notes-api → notes/api}/tests/test_audit.py +0 -0
  268. /package/{notes-api → notes/api}/tests/test_auth.py +0 -0
  269. /package/{notes-api → notes/api}/tests/test_business_date.py +0 -0
  270. /package/{notes-api → notes/api}/tests/test_collab.py +0 -0
  271. /package/{notes-api → notes/api}/tests/test_comments.py +0 -0
  272. /package/{notes-api → notes/api}/tests/test_config_ssl.py +0 -0
  273. /package/{notes-api → notes/api}/tests/test_config_warnings.py +0 -0
  274. /package/{notes-api → notes/api}/tests/test_files.py +0 -0
  275. /package/{notes-api → notes/api}/tests/test_path_validation.py +0 -0
  276. /package/{notes-api → notes/api}/tests/test_security.py +0 -0
  277. /package/{notes-api → notes/api}/tests/test_settings.py +0 -0
  278. /package/{notes-api → notes/api}/tests/test_tree.py +0 -0
  279. /package/{notes-api → notes/api}/tests/test_upload.py +0 -0
  280. /package/{notes-api → notes/api}/tests/test_users.py +0 -0
  281. /package/{notes-app → notes/app}/.dockerignore +0 -0
  282. /package/{notes-app → notes/app}/index.html +0 -0
  283. /package/{notes-app → notes/app}/nginx.conf +0 -0
  284. /package/{notes-app → notes/app}/package-lock.json +0 -0
  285. /package/{notes-app → notes/app}/playwright.config.ts +0 -0
  286. /package/{notes-app → notes/app}/pnpm-lock.yaml +0 -0
  287. /package/{notes-app → notes/app}/src/App.tsx +0 -0
  288. /package/{notes-app → notes/app}/src/components/BranchSelectorModal.tsx +0 -0
  289. /package/{notes-app → notes/app}/src/components/CodeBlockView.test.tsx +0 -0
  290. /package/{notes-app → notes/app}/src/components/CodeBlockView.tsx +0 -0
  291. /package/{notes-app → notes/app}/src/components/CollabStatus.tsx +0 -0
  292. /package/{notes-app → notes/app}/src/components/DiffPreview.tsx +0 -0
  293. /package/{notes-app → notes/app}/src/components/DrawioEditor.tsx +0 -0
  294. /package/{notes-app → notes/app}/src/components/DrawioViewer.tsx +0 -0
  295. /package/{notes-app → notes/app}/src/components/ErrorBoundary.test.tsx +0 -0
  296. /package/{notes-app → notes/app}/src/components/ErrorBoundary.tsx +0 -0
  297. /package/{notes-app → notes/app}/src/components/FileContentView.tsx +0 -0
  298. /package/{notes-app → notes/app}/src/components/FileContextMenu.test.tsx +0 -0
  299. /package/{notes-app → notes/app}/src/components/FileContextMenu.tsx +0 -0
  300. /package/{notes-app → notes/app}/src/components/FileDialogs.test.tsx +0 -0
  301. /package/{notes-app → notes/app}/src/components/FileDialogs.tsx +0 -0
  302. /package/{notes-app → notes/app}/src/components/SaveStatusIndicator.test.tsx +0 -0
  303. /package/{notes-app → notes/app}/src/components/SaveStatusIndicator.tsx +0 -0
  304. /package/{notes-app → notes/app}/src/components/Skeleton.tsx +0 -0
  305. /package/{notes-app → notes/app}/src/components/SpreadsheetEditor.test.tsx +0 -0
  306. /package/{notes-app → notes/app}/src/components/SpreadsheetEditor.tsx +0 -0
  307. /package/{notes-app → notes/app}/src/components/TextEditor.tsx +0 -0
  308. /package/{notes-app → notes/app}/src/components/ToastContainer.tsx +0 -0
  309. /package/{notes-app → notes/app}/src/components/TreeNode.tsx +0 -0
  310. /package/{notes-app → notes/app}/src/contexts/AuthContext.test.tsx +0 -0
  311. /package/{notes-app → notes/app}/src/contexts/AuthContext.tsx +0 -0
  312. /package/{notes-app → notes/app}/src/contexts/ToastContext.test.ts +0 -0
  313. /package/{notes-app → notes/app}/src/contexts/ToastContext.tsx +0 -0
  314. /package/{notes-app → notes/app}/src/hooks/useAutoSave.test.ts +0 -0
  315. /package/{notes-app → notes/app}/src/hooks/useAutoSave.ts +0 -0
  316. /package/{notes-app → notes/app}/src/hooks/useCollaboration.ts +0 -0
  317. /package/{notes-app → notes/app}/src/hooks/useComments.ts +0 -0
  318. /package/{notes-app → notes/app}/src/hooks/useYText.ts +0 -0
  319. /package/{notes-app → notes/app}/src/lib/branch-diff.test.ts +0 -0
  320. /package/{notes-app → notes/app}/src/lib/branch-diff.ts +0 -0
  321. /package/{notes-app → notes/app}/src/lib/created-file.test.ts +0 -0
  322. /package/{notes-app → notes/app}/src/lib/created-file.ts +0 -0
  323. /package/{notes-app → notes/app}/src/lib/csv-utils.test.ts +0 -0
  324. /package/{notes-app → notes/app}/src/lib/csv-utils.ts +0 -0
  325. /package/{notes-app → notes/app}/src/lib/deepLinkPathToSearch.test.ts +0 -0
  326. /package/{notes-app → notes/app}/src/lib/deepLinkPathToSearch.ts +0 -0
  327. /package/{notes-app → notes/app}/src/lib/draft-storage.test.ts +0 -0
  328. /package/{notes-app → notes/app}/src/lib/draft-storage.ts +0 -0
  329. /package/{notes-app → notes/app}/src/lib/mermaid-render.ts +0 -0
  330. /package/{notes-app → notes/app}/src/lib/postLoginRedirect.test.ts +0 -0
  331. /package/{notes-app → notes/app}/src/lib/postLoginRedirect.ts +0 -0
  332. /package/{notes-app → notes/app}/src/lib/tree-utils.ts +0 -0
  333. /package/{notes-app → notes/app}/src/lib/user-colors.ts +0 -0
  334. /package/{notes-app → notes/app}/src/lib/xlsx-utils.test.ts +0 -0
  335. /package/{notes-app → notes/app}/src/lib/xlsx-utils.ts +0 -0
  336. /package/{notes-app → notes/app}/src/main.tsx +0 -0
  337. /package/{notes-app → notes/app}/src/pages/LoginPage.tsx +0 -0
  338. /package/{notes-app → notes/app}/src/pages/MainPage.insertChildEntry.test.ts +0 -0
  339. /package/{notes-app → notes/app}/src/pages/SettingsPage.tsx +0 -0
  340. /package/{notes-app → notes/app}/src/pages/UserManagementPage.tsx +0 -0
  341. /package/{notes-app → notes/app}/src/styles/globals.css +0 -0
  342. /package/{notes-app → notes/app}/src/types.ts +0 -0
  343. /package/{notes-app → notes/app}/src/vite-env.d.ts +0 -0
  344. /package/{notes-app → notes/app}/tsconfig.json +0 -0
  345. /package/{notes-app → notes/app}/tsconfig.node.json +0 -0
  346. /package/{notes-app → notes/app}/vite.config.js +0 -0
  347. /package/{notes-app → notes/app}/vite.config.ts +0 -0
  348. /package/{notes-app → notes/app}/vitest.config.ts +0 -0
@@ -0,0 +1,545 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { render, screen, waitFor, fireEvent, act } from "@testing-library/react";
3
+
4
+ const triggerPeriodicSync = vi.hoisted(() => vi.fn());
5
+
6
+ vi.mock("@/hooks/usePeriodicSync", () => ({
7
+ usePeriodicSync: ({ onSync, enabled }: { onSync: () => void; enabled: boolean }) => {
8
+ triggerPeriodicSync.mockImplementation(() => {
9
+ if (enabled) onSync();
10
+ });
11
+ },
12
+ }));
13
+
14
+ vi.mock("@/lib/api", () => ({
15
+ listIssuesApi: vi.fn(),
16
+ listIssueLabelsApi: vi.fn(),
17
+ getErrorMessage: vi.fn((e: unknown) => String(e)),
18
+ isAbortError: vi.fn(() => false),
19
+ }));
20
+
21
+ import { listIssuesApi, listIssueLabelsApi } from "@/lib/api";
22
+ import IssueList from "./IssueList";
23
+
24
+ const mockListIssues = vi.mocked(listIssuesApi);
25
+ const mockListLabels = vi.mocked(listIssueLabelsApi);
26
+
27
+ const MOCK_ISSUES = [
28
+ {
29
+ number: 10,
30
+ title: "Issue 10",
31
+ state: "open" as const,
32
+ author: "user1",
33
+ assignees: [],
34
+ comments: 0,
35
+ labels: [],
36
+ createdAt: "2026-05-19T00:00:00Z",
37
+ updatedAt: "2026-05-19T00:00:00Z",
38
+ },
39
+ {
40
+ number: 9,
41
+ title: "Issue 9",
42
+ state: "open" as const,
43
+ author: "user1",
44
+ assignees: [],
45
+ comments: 0,
46
+ labels: [],
47
+ createdAt: "2026-05-18T00:00:00Z",
48
+ updatedAt: "2026-05-18T00:00:00Z",
49
+ },
50
+ ];
51
+
52
+ describe("IssueList", () => {
53
+ beforeEach(() => {
54
+ vi.clearAllMocks();
55
+ mockListLabels.mockResolvedValue({
56
+ labels: [{ name: "bug", color: "d73a4a" }],
57
+ });
58
+ });
59
+
60
+ it("Issueリストを取得して表示する", async () => {
61
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
62
+
63
+ render(<IssueList onSelect={vi.fn()} selectedIssue={null} />);
64
+
65
+ await waitFor(() => {
66
+ expect(screen.getByText("Issue 10")).toBeTruthy();
67
+ expect(screen.getByText("Issue 9")).toBeTruthy();
68
+ });
69
+
70
+ const issueButton = screen.getByText("Issue 10").closest("button");
71
+ expect(issueButton?.className).toContain("min-h-11");
72
+ expect(issueButton?.className).toContain("touch-manipulation");
73
+ });
74
+
75
+ it("reloadTrigger が変わると listIssuesApi を再呼び出しする", async () => {
76
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
77
+
78
+ const { rerender } = render(
79
+ <IssueList onSelect={vi.fn()} selectedIssue={null} reloadTrigger={0} />,
80
+ );
81
+
82
+ await waitFor(() => {
83
+ expect(mockListIssues).toHaveBeenCalledTimes(1);
84
+ });
85
+
86
+ rerender(
87
+ <IssueList onSelect={vi.fn()} selectedIssue={null} reloadTrigger={1} />,
88
+ );
89
+
90
+ await waitFor(() => {
91
+ expect(mockListIssues).toHaveBeenCalledTimes(2);
92
+ });
93
+ });
94
+
95
+ it("reloadTrigger が同じ値のままなら再呼び出しされない", async () => {
96
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
97
+
98
+ const { rerender } = render(
99
+ <IssueList onSelect={vi.fn()} selectedIssue={null} reloadTrigger={0} />,
100
+ );
101
+
102
+ await waitFor(() => {
103
+ expect(mockListIssues).toHaveBeenCalledTimes(1);
104
+ });
105
+
106
+ rerender(
107
+ <IssueList onSelect={vi.fn()} selectedIssue={null} reloadTrigger={0} />,
108
+ );
109
+
110
+ expect(mockListIssues).toHaveBeenCalledTimes(1);
111
+ });
112
+
113
+ it("ラベルフィルタ変更時に labels クエリ付きで listIssuesApi を呼ぶ", async () => {
114
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
115
+
116
+ render(<IssueList onSelect={vi.fn()} selectedIssue={null} />);
117
+
118
+ await waitFor(() => {
119
+ expect(screen.getByLabelText("ラベルでフィルタ")).toBeTruthy();
120
+ });
121
+
122
+ fireEvent.change(screen.getByLabelText("ラベルでフィルタ"), {
123
+ target: { value: "bug" },
124
+ });
125
+
126
+ await waitFor(() => {
127
+ expect(mockListIssues).toHaveBeenCalledWith(
128
+ expect.objectContaining({ labels: "bug" }),
129
+ );
130
+ });
131
+ });
132
+
133
+ it("担当者 none フィルタ変更時に assignee クエリ付きで listIssuesApi を呼ぶ", async () => {
134
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
135
+
136
+ render(<IssueList onSelect={vi.fn()} selectedIssue={null} />);
137
+
138
+ await waitFor(() => {
139
+ expect(screen.getByLabelText("担当者でフィルタ")).toBeTruthy();
140
+ });
141
+
142
+ fireEvent.change(screen.getByLabelText("担当者でフィルタ"), {
143
+ target: { value: "none" },
144
+ });
145
+ fireEvent.blur(screen.getByLabelText("担当者でフィルタ"));
146
+
147
+ await waitFor(() => {
148
+ expect(mockListIssues).toHaveBeenCalledWith(
149
+ expect.objectContaining({ assignee: "none" }),
150
+ );
151
+ });
152
+ });
153
+
154
+ it("optimisticIssue が指定されると API 再取得前でも一覧に表示する", async () => {
155
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
156
+
157
+ const optimisticIssue = {
158
+ number: 11,
159
+ title: "New Issue",
160
+ state: "open" as const,
161
+ author: "user1",
162
+ assignees: [],
163
+ comments: 0,
164
+ labels: [],
165
+ createdAt: "2026-05-25T00:00:00Z",
166
+ updatedAt: "2026-05-25T00:00:00Z",
167
+ };
168
+
169
+ render(
170
+ <IssueList
171
+ onSelect={vi.fn()}
172
+ selectedIssue={11}
173
+ optimisticIssue={optimisticIssue}
174
+ />,
175
+ );
176
+
177
+ await waitFor(() => {
178
+ expect(screen.getByText("New Issue")).toBeTruthy();
179
+ });
180
+ });
181
+
182
+ it("optimisticIssue が API 取得結果に含まれたら onOptimisticSettled を呼ぶ", async () => {
183
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
184
+ const onOptimisticSettled = vi.fn();
185
+ const optimisticIssue = {
186
+ number: 10,
187
+ title: "Optimistic Issue 10",
188
+ state: "open" as const,
189
+ author: "user1",
190
+ assignees: [],
191
+ comments: 0,
192
+ labels: [],
193
+ createdAt: "2026-05-25T00:00:00Z",
194
+ updatedAt: "2026-05-25T00:00:00Z",
195
+ };
196
+
197
+ render(
198
+ <IssueList
199
+ onSelect={vi.fn()}
200
+ selectedIssue={10}
201
+ optimisticIssue={optimisticIssue}
202
+ onOptimisticSettled={onOptimisticSettled}
203
+ />,
204
+ );
205
+
206
+ await waitFor(() => {
207
+ expect(onOptimisticSettled).toHaveBeenCalledWith(10);
208
+ });
209
+ });
210
+
211
+ it("syncEnabled=false のときポーリングで追加 API を呼ばない(REQ-016-AC-03)", async () => {
212
+ mockListIssues.mockResolvedValueOnce({ issues: MOCK_ISSUES });
213
+
214
+ render(<IssueList onSelect={vi.fn()} selectedIssue={null} syncEnabled={false} />);
215
+
216
+ await waitFor(() => {
217
+ expect(screen.getByText("Issue 10")).toBeTruthy();
218
+ });
219
+
220
+ const callCount = mockListIssues.mock.calls.length;
221
+
222
+ await act(async () => {
223
+ triggerPeriodicSync();
224
+ });
225
+
226
+ expect(mockListIssues.mock.calls.length).toBe(callCount);
227
+ });
228
+
229
+ it("背景 poll 中の API 失敗では error を表示せず一覧を維持する", async () => {
230
+ mockListIssues.mockResolvedValueOnce({ issues: MOCK_ISSUES });
231
+
232
+ render(<IssueList onSelect={vi.fn()} selectedIssue={null} syncEnabled />);
233
+
234
+ await waitFor(() => {
235
+ expect(screen.getByText("Issue 10")).toBeTruthy();
236
+ });
237
+
238
+ mockListIssues.mockRejectedValueOnce(new Error("502 Bad Gateway"));
239
+
240
+ await act(async () => {
241
+ triggerPeriodicSync();
242
+ });
243
+
244
+ await waitFor(() => {
245
+ expect(mockListIssues).toHaveBeenCalledTimes(2);
246
+ });
247
+
248
+ expect(screen.getByText("Issue 10")).toBeTruthy();
249
+ expect(screen.queryByText("502 Bad Gateway")).toBeNull();
250
+ });
251
+
252
+ it("foreground 取得中に background reload が走っても loading が固着しない", async () => {
253
+ let resolveForeground: ((value: { issues: typeof MOCK_ISSUES }) => void) | undefined;
254
+ mockListIssues
255
+ .mockResolvedValueOnce({ issues: MOCK_ISSUES })
256
+ .mockImplementationOnce(
257
+ () =>
258
+ new Promise((resolve) => {
259
+ resolveForeground = resolve;
260
+ }),
261
+ )
262
+ .mockResolvedValueOnce({ issues: MOCK_ISSUES });
263
+
264
+ const { rerender } = render(
265
+ <IssueList
266
+ onSelect={vi.fn()}
267
+ selectedIssue={null}
268
+ reloadTrigger={0}
269
+ syncEnabled
270
+ />,
271
+ );
272
+
273
+ await waitFor(() => {
274
+ expect(screen.getByText("Issue 10")).toBeTruthy();
275
+ });
276
+
277
+ rerender(
278
+ <IssueList
279
+ onSelect={vi.fn()}
280
+ selectedIssue={null}
281
+ reloadTrigger={1}
282
+ syncEnabled
283
+ />,
284
+ );
285
+
286
+ await act(async () => {
287
+ triggerPeriodicSync();
288
+ });
289
+
290
+ await waitFor(() => {
291
+ const refreshIcon = document.querySelector(".lucide-refresh-cw");
292
+ expect(refreshIcon?.classList.contains("animate-spin")).toBe(false);
293
+ });
294
+
295
+ await act(async () => {
296
+ resolveForeground?.({ issues: MOCK_ISSUES });
297
+ await Promise.resolve();
298
+ });
299
+ });
300
+
301
+ it("backgroundSyncTrigger の変化は背景再取得として扱う", async () => {
302
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
303
+
304
+ const { rerender } = render(
305
+ <IssueList
306
+ onSelect={vi.fn()}
307
+ selectedIssue={null}
308
+ backgroundSyncTrigger={0}
309
+ />,
310
+ );
311
+
312
+ await waitFor(() => {
313
+ expect(mockListIssues).toHaveBeenCalledTimes(1);
314
+ });
315
+
316
+ mockListIssues.mockRejectedValueOnce(new Error("502 Bad Gateway"));
317
+
318
+ rerender(
319
+ <IssueList
320
+ onSelect={vi.fn()}
321
+ selectedIssue={null}
322
+ backgroundSyncTrigger={1}
323
+ />,
324
+ );
325
+
326
+ await waitFor(() => {
327
+ expect(mockListIssues).toHaveBeenCalledTimes(2);
328
+ });
329
+
330
+ expect(screen.getByText("Issue 10")).toBeTruthy();
331
+ expect(screen.queryByText("502 Bad Gateway")).toBeNull();
332
+ });
333
+
334
+ it("背景再取得成功時に過去の foreground エラーをクリアする", async () => {
335
+ mockListIssues
336
+ .mockResolvedValueOnce({ issues: MOCK_ISSUES })
337
+ .mockRejectedValueOnce(new Error("500 Internal Server Error"))
338
+ .mockResolvedValueOnce({ issues: MOCK_ISSUES })
339
+ .mockResolvedValue({ issues: MOCK_ISSUES });
340
+
341
+ const { rerender } = render(
342
+ <IssueList onSelect={vi.fn()} selectedIssue={null} reloadTrigger={0} syncEnabled />,
343
+ );
344
+
345
+ await waitFor(() => {
346
+ expect(screen.getByText("Issue 10")).toBeTruthy();
347
+ });
348
+
349
+ rerender(
350
+ <IssueList onSelect={vi.fn()} selectedIssue={null} reloadTrigger={1} syncEnabled />,
351
+ );
352
+
353
+ await waitFor(() => {
354
+ expect(screen.getByText(/500 Internal Server Error/)).toBeTruthy();
355
+ });
356
+
357
+ await act(async () => {
358
+ triggerPeriodicSync();
359
+ });
360
+
361
+ await waitFor(() => {
362
+ expect(screen.queryByText(/500 Internal Server Error/)).toBeNull();
363
+ expect(screen.getByText("Issue 10")).toBeTruthy();
364
+ });
365
+ });
366
+
367
+ it("手動再読み込みは background 同期より優先して API エラーを表示する", async () => {
368
+ let resolveBackground: ((value: { issues: typeof MOCK_ISSUES }) => void) | undefined;
369
+ mockListIssues
370
+ .mockResolvedValueOnce({ issues: MOCK_ISSUES })
371
+ .mockImplementationOnce(
372
+ () =>
373
+ new Promise((resolve) => {
374
+ resolveBackground = resolve;
375
+ }),
376
+ )
377
+ .mockRejectedValueOnce(new Error("503 Service Unavailable"))
378
+ .mockResolvedValue({ issues: MOCK_ISSUES });
379
+
380
+ render(<IssueList onSelect={vi.fn()} selectedIssue={null} syncEnabled />);
381
+
382
+ await waitFor(() => {
383
+ expect(screen.getByText("Issue 10")).toBeTruthy();
384
+ });
385
+
386
+ await act(async () => {
387
+ triggerPeriodicSync();
388
+ });
389
+
390
+ fireEvent.click(screen.getByTitle("更新"));
391
+
392
+ await waitFor(() => {
393
+ expect(screen.getByText(/503 Service Unavailable/)).toBeTruthy();
394
+ });
395
+
396
+ await act(async () => {
397
+ resolveBackground?.({ issues: MOCK_ISSUES });
398
+ await Promise.resolve();
399
+ });
400
+ });
401
+
402
+ it("snapshot モードでは一覧が古い間は更新行を即時表示しつつ settle しない(#945)", async () => {
403
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
404
+ const onOptimisticSettled = vi.fn();
405
+
406
+ render(
407
+ <IssueList
408
+ onSelect={vi.fn()}
409
+ selectedIssue={10}
410
+ optimisticIssue={{
411
+ number: 10,
412
+ title: "Issue 10 (更新済み)",
413
+ state: "open",
414
+ author: "user1",
415
+ assignees: [],
416
+ comments: 0,
417
+ labels: [{ name: "bug", color: "d73a4a" }],
418
+ createdAt: "2026-05-19T00:00:00Z",
419
+ updatedAt: "2026-06-10T00:00:00Z",
420
+ }}
421
+ optimisticSettleMode="snapshot"
422
+ onOptimisticSettled={onOptimisticSettled}
423
+ />,
424
+ );
425
+
426
+ // 追加の GET /api/issues なしで更新後の行が即時表示される
427
+ await waitFor(() => {
428
+ expect(screen.getByText("Issue 10 (更新済み)")).toBeTruthy();
429
+ });
430
+ expect(mockListIssues).toHaveBeenCalledTimes(1);
431
+ // 一覧側(#10 は 2026-05-19 のまま)が追いつくまでは解除しない
432
+ expect(onOptimisticSettled).not.toHaveBeenCalled();
433
+ });
434
+
435
+ it("snapshot モードで一覧の実体が追いついたら onOptimisticSettled を呼ぶ(#945)", async () => {
436
+ mockListIssues
437
+ .mockResolvedValueOnce({ issues: MOCK_ISSUES })
438
+ // 再取得で #10 が optimistic と同じ内容・updatedAt に追いつく(実体反映)
439
+ .mockResolvedValueOnce({
440
+ issues: [
441
+ { ...MOCK_ISSUES[0], title: "Issue 10 (更新済み)", updatedAt: "2026-06-10T00:00:00Z" },
442
+ MOCK_ISSUES[1],
443
+ ],
444
+ });
445
+ const onOptimisticSettled = vi.fn();
446
+
447
+ const optimisticIssue = {
448
+ number: 10,
449
+ title: "Issue 10 (更新済み)",
450
+ state: "open" as const,
451
+ author: "user1",
452
+ assignees: [],
453
+ comments: 0,
454
+ labels: [],
455
+ createdAt: "2026-05-19T00:00:00Z",
456
+ updatedAt: "2026-06-10T00:00:00Z",
457
+ };
458
+
459
+ const { rerender } = render(
460
+ <IssueList
461
+ onSelect={vi.fn()}
462
+ selectedIssue={10}
463
+ reloadTrigger={0}
464
+ optimisticIssue={optimisticIssue}
465
+ optimisticSettleMode="snapshot"
466
+ onOptimisticSettled={onOptimisticSettled}
467
+ />,
468
+ );
469
+
470
+ await waitFor(() => expect(mockListIssues).toHaveBeenCalledTimes(1));
471
+ expect(onOptimisticSettled).not.toHaveBeenCalled();
472
+
473
+ // 一覧が再取得され #10 の updatedAt が optimistic に追いつく
474
+ rerender(
475
+ <IssueList
476
+ onSelect={vi.fn()}
477
+ selectedIssue={10}
478
+ reloadTrigger={1}
479
+ optimisticIssue={optimisticIssue}
480
+ optimisticSettleMode="snapshot"
481
+ onOptimisticSettled={onOptimisticSettled}
482
+ />,
483
+ );
484
+
485
+ await waitFor(() => {
486
+ expect(onOptimisticSettled).toHaveBeenCalledWith(10);
487
+ });
488
+ });
489
+
490
+ it("snapshot モードで closed 化した optimistic は open 一覧から即時に除外する(#945)", async () => {
491
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
492
+
493
+ render(
494
+ <IssueList
495
+ onSelect={vi.fn()}
496
+ selectedIssue={10}
497
+ optimisticIssue={{
498
+ number: 10,
499
+ title: "Issue 10",
500
+ state: "closed",
501
+ author: "user1",
502
+ assignees: [],
503
+ comments: 0,
504
+ labels: [],
505
+ createdAt: "2026-05-19T00:00:00Z",
506
+ updatedAt: "2026-06-10T00:00:00Z",
507
+ }}
508
+ optimisticSettleMode="snapshot"
509
+ />,
510
+ );
511
+
512
+ await waitFor(() => {
513
+ expect(screen.getByText("Issue 9")).toBeTruthy();
514
+ });
515
+ expect(screen.queryByText("Issue 10")).toBeNull();
516
+ });
517
+
518
+ it("Open フィルタ中は closed の optimistic Issue を表示しない", async () => {
519
+ mockListIssues.mockResolvedValue({ issues: MOCK_ISSUES });
520
+
521
+ render(
522
+ <IssueList
523
+ onSelect={vi.fn()}
524
+ selectedIssue={null}
525
+ optimisticIssue={{
526
+ number: 11,
527
+ title: "Closed optimistic",
528
+ state: "closed",
529
+ author: "user1",
530
+ assignees: [],
531
+ comments: 0,
532
+ labels: [],
533
+ createdAt: "2026-05-25T00:00:00Z",
534
+ updatedAt: "2026-05-25T00:00:00Z",
535
+ }}
536
+ />,
537
+ );
538
+
539
+ await waitFor(() => {
540
+ expect(screen.getByText("Issue 10")).toBeTruthy();
541
+ });
542
+
543
+ expect(screen.queryByText("Closed optimistic")).toBeNull();
544
+ });
545
+ });