@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
@@ -1,4 +1,4 @@
1
- import { useState, useReducer, useEffect, useCallback } from "react";
1
+ import { useState, useReducer, useEffect, useCallback, useRef } from "react";
2
2
  import { X, RefreshCw, FileText, Clock, GitBranch, AlertCircle, Loader2, ExternalLink } from "lucide-react";
3
3
  import {
4
4
  fetchHistoryApi,
@@ -11,6 +11,10 @@ import type { CommitEntry, BranchStatus, SessionInfo } from "@/lib/api";
11
11
  import type { CollabUser } from "@/hooks/useCollaboration";
12
12
  import type { FileContent } from "@/types";
13
13
  import { getFileExt } from "@/types";
14
+ import PanelResizeHandle from "@/components/PanelResizeHandle";
15
+ import { RESIZABLE_RIGHT_PANEL_ASIDE_CLASS, type PanelResizeProps } from "@/lib/resizable-panel";
16
+ import { usePeriodicSync } from "@/hooks/usePeriodicSync";
17
+ import { GITHUB_SYNC_POLL_INTERVAL_MS } from "@/lib/github-sync";
14
18
 
15
19
  type Tab = "details" | "history" | "branch";
16
20
 
@@ -18,6 +22,8 @@ type Props = {
18
22
  fileContent: FileContent;
19
23
  collabUsers: CollabUser[];
20
24
  onClose: () => void;
25
+ panelResize?: PanelResizeProps;
26
+ syncEnabled?: boolean;
21
27
  };
22
28
 
23
29
  function TabButton({
@@ -116,20 +122,43 @@ function historyReducer(state: HistoryState, action: HistoryAction): HistoryStat
116
122
 
117
123
  function HistoryTab({ filePath }: { filePath: string }) {
118
124
  const [state, dispatch] = useReducer(historyReducer, { items: [], loading: false, error: null });
125
+ const requestSeq = useRef(0);
126
+ const mountedRef = useRef(true);
127
+ const abortRef = useRef<AbortController | null>(null);
128
+
129
+ useEffect(() => {
130
+ mountedRef.current = true;
131
+ return () => {
132
+ mountedRef.current = false;
133
+ };
134
+ }, []);
119
135
 
120
136
  const load = useCallback(() => {
137
+ // 進行中の取得をキャンセルし、後着の stale 応答で上書きされるのを防ぐ
138
+ abortRef.current?.abort();
139
+ const ac = new AbortController();
140
+ abortRef.current = ac;
141
+ const requestId = requestSeq.current + 1;
142
+ requestSeq.current = requestId;
143
+
121
144
  dispatch({ type: "LOADING" });
122
- fetchHistoryApi(filePath)
123
- .then((data) => dispatch({ type: "SUCCESS", items: data }))
145
+ fetchHistoryApi(filePath, { signal: ac.signal })
146
+ .then((data) => {
147
+ if (!mountedRef.current || requestSeq.current !== requestId) return;
148
+ dispatch({ type: "SUCCESS", items: data });
149
+ })
124
150
  .catch((err: unknown) => {
125
- if (!isAbortError(err)) {
126
- dispatch({ type: "ERROR", message: getErrorMessage(err, "履歴の取得に失敗しました") });
127
- }
151
+ if (!mountedRef.current || requestSeq.current !== requestId) return;
152
+ if (isAbortError(err)) return;
153
+ dispatch({ type: "ERROR", message: getErrorMessage(err, "履歴の取得に失敗しました") });
128
154
  });
129
155
  }, [filePath]);
130
156
 
131
157
  useEffect(() => {
132
158
  load();
159
+ return () => {
160
+ abortRef.current?.abort();
161
+ };
133
162
  }, [load]);
134
163
 
135
164
  const { items: history, loading, error } = state;
@@ -152,7 +181,7 @@ function HistoryTab({ filePath }: { filePath: string }) {
152
181
  </div>
153
182
  <button
154
183
  type="button"
155
- onClick={load}
184
+ onClick={() => load()}
156
185
  className="mt-2 text-xs text-blue-400 hover:text-blue-300 flex items-center gap-1"
157
186
  >
158
187
  <RefreshCw className="w-3 h-3" />
@@ -199,26 +228,92 @@ function branchReducer(state: BranchState, action: BranchAction): BranchState {
199
228
  }
200
229
  }
201
230
 
202
- function BranchTab() {
231
+ function BranchTab({ syncEnabled }: { syncEnabled: boolean }) {
203
232
  const [state, dispatch] = useReducer(branchReducer, { status: null, sessions: [], loading: false, error: null });
233
+ // foreground(初回・明示的再取得)と background poll で seq を分離し、即時 background poll が
234
+ // in-flight の foreground SUCCESS を stale 扱いで破棄しないようにする(#934)
235
+ const loadRequestSeq = useRef(0);
236
+ const pollRequestSeq = useRef(0);
237
+ // freshness ゲート: 取得ごとに単調増加する世代を採番し、適用済み世代(appliedGen)以下の取得結果は
238
+ // データを上書きしない。これにより「遅い foreground load が、後から始まったより新しい background poll の
239
+ // 結果を上書きする」順序を防ぐ(#949・REQ-016-AC-13)。background 失敗時は appliedGen を進めないため、
240
+ // 後着の foreground SUCCESS は従来どおり適用される(#934 / AC-10 の失敗ケースを維持)。
241
+ // BranchTab は単一のグローバル資源(branch-status / sessions)を扱い ID 単位の識別がないため、
242
+ // appliedGen のリセットは不要(gen は単調増加のみ)
243
+ const fetchGenSeq = useRef(0);
244
+ const appliedGen = useRef(0);
245
+ const mountedRef = useRef(true);
246
+
247
+ useEffect(() => {
248
+ mountedRef.current = true;
249
+ return () => {
250
+ mountedRef.current = false;
251
+ };
252
+ }, []);
253
+
254
+ // foreground 取得開始時は poll seq も進め、in-flight の background poll を無効化する。
255
+ // 併せて取得世代を採番する
256
+ const beginLoadRequest = useCallback(() => {
257
+ loadRequestSeq.current += 1;
258
+ pollRequestSeq.current += 1;
259
+ fetchGenSeq.current += 1;
260
+ return { requestId: loadRequestSeq.current, gen: fetchGenSeq.current };
261
+ }, []);
262
+
263
+ // background poll は poll seq のみ進め、in-flight の foreground load は無効化しない
264
+ const beginPollRequest = useCallback(() => {
265
+ pollRequestSeq.current += 1;
266
+ fetchGenSeq.current += 1;
267
+ return { requestId: pollRequestSeq.current, gen: fetchGenSeq.current };
268
+ }, []);
204
269
 
205
270
  const load = useCallback(() => {
271
+ const { requestId, gen } = beginLoadRequest();
206
272
  dispatch({ type: "LOADING" });
207
273
  Promise.all([fetchBranchStatusApi(), fetchSessionsApi()])
208
- .then(([branchStatus, allSessions]) =>
209
- dispatch({ type: "SUCCESS", status: branchStatus, sessions: allSessions }),
210
- )
274
+ .then(([branchStatus, allSessions]) => {
275
+ if (!mountedRef.current || requestId !== loadRequestSeq.current) return;
276
+ // より新しい取得が適用済みならデータは上書きしない(loading は poll の SUCCESS が解除済み)
277
+ if (gen <= appliedGen.current) return;
278
+ appliedGen.current = gen;
279
+ dispatch({ type: "SUCCESS", status: branchStatus, sessions: allSessions });
280
+ })
211
281
  .catch((err: unknown) => {
212
- if (!isAbortError(err)) {
213
- dispatch({ type: "ERROR", message: getErrorMessage(err, "ブランチ情報の取得に失敗しました") });
214
- }
282
+ if (!mountedRef.current || requestId !== loadRequestSeq.current) return;
283
+ if (isAbortError(err)) return;
284
+ dispatch({ type: "ERROR", message: getErrorMessage(err, "ブランチ情報の取得に失敗しました") });
215
285
  });
216
- }, []);
286
+ }, [beginLoadRequest]);
287
+
288
+ const poll = useCallback(() => {
289
+ const { requestId, gen } = beginPollRequest();
290
+ // Promise を返し、usePeriodicSync の in-flight ガード(#937)で並列 poll を防ぐ
291
+ return Promise.all([fetchBranchStatusApi(), fetchSessionsApi()])
292
+ .then(([branchStatus, allSessions]) => {
293
+ if (!mountedRef.current || requestId !== pollRequestSeq.current) return;
294
+ // より新しい取得が適用済みなら上書きしない(#949)
295
+ if (gen <= appliedGen.current) return;
296
+ appliedGen.current = gen;
297
+ dispatch({ type: "SUCCESS", status: branchStatus, sessions: allSessions });
298
+ })
299
+ .catch(() => {
300
+ // バックグラウンド同期の失敗は UI を乱さない(手動「再読み込み」でエラー表示)。
301
+ // loading は foreground load のみが管理するため、ここでは状態を更新しない
302
+ });
303
+ }, [beginPollRequest]);
217
304
 
218
305
  useEffect(() => {
219
306
  load();
220
307
  }, [load]);
221
308
 
309
+ usePeriodicSync({
310
+ enabled: syncEnabled,
311
+ intervalMs: GITHUB_SYNC_POLL_INTERVAL_MS,
312
+ onSync: poll,
313
+ // マウント時の初回 load と即時 sync の二重 dispatch を回避(#929)
314
+ skipInitialSync: true,
315
+ });
316
+
222
317
  const { status: branchStatus, sessions, loading, error } = state;
223
318
 
224
319
  if (loading) {
@@ -239,7 +334,7 @@ function BranchTab() {
239
334
  </div>
240
335
  <button
241
336
  type="button"
242
- onClick={load}
337
+ onClick={() => load()}
243
338
  className="mt-2 text-xs text-blue-400 hover:text-blue-300 flex items-center gap-1"
244
339
  >
245
340
  <RefreshCw className="w-3 h-3" />
@@ -296,7 +391,7 @@ function BranchTab() {
296
391
  <p className="text-xs font-medium text-gray-400">アクティブセッション</p>
297
392
  <button
298
393
  type="button"
299
- onClick={load}
394
+ onClick={() => load()}
300
395
  className="text-gray-500 hover:text-gray-300 transition-colors"
301
396
  aria-label="再読み込み"
302
397
  >
@@ -333,11 +428,31 @@ function BranchTab() {
333
428
  );
334
429
  }
335
430
 
336
- export default function FileInfoPanel({ fileContent, collabUsers, onClose }: Props) {
431
+ export default function FileInfoPanel({
432
+ fileContent,
433
+ collabUsers,
434
+ onClose,
435
+ panelResize,
436
+ syncEnabled = false,
437
+ }: Props) {
337
438
  const [tab, setTab] = useState<Tab>("details");
338
439
 
339
440
  return (
340
- <aside className="absolute inset-0 md:static md:w-72 z-20 border-l border-gray-700 bg-gray-800 flex flex-col shrink-0">
441
+ <aside
442
+ className={RESIZABLE_RIGHT_PANEL_ASIDE_CLASS}
443
+ style={panelResize != null ? { width: panelResize.width } : undefined}
444
+ >
445
+ {panelResize && panelResize.showResizeHandle !== false && (
446
+ <PanelResizeHandle
447
+ edge="inline-start"
448
+ onPointerDown={panelResize.onPointerDown}
449
+ width={panelResize.width}
450
+ minWidth={panelResize.minWidth}
451
+ maxWidth={panelResize.maxWidth}
452
+ onWidthChange={panelResize.onWidthChange}
453
+ ariaLabel="ファイル情報パネルの幅を変更"
454
+ />
455
+ )}
341
456
  {/* Header */}
342
457
  <div className="flex items-center justify-between px-3 py-2 border-b border-gray-700 shrink-0">
343
458
  <h3 className="text-sm font-semibold text-gray-300">ファイル情報</h3>
@@ -375,7 +490,7 @@ export default function FileInfoPanel({ fileContent, collabUsers, onClose }: Pro
375
490
  {tab === "history" && (
376
491
  <HistoryTab filePath={fileContent.path} />
377
492
  )}
378
- {tab === "branch" && <BranchTab />}
493
+ {tab === "branch" && <BranchTab syncEnabled={syncEnabled} />}
379
494
  </div>
380
495
  </aside>
381
496
  );
@@ -0,0 +1,93 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { render, screen, fireEvent, waitFor } from "@testing-library/react";
3
+
4
+ vi.mock("@/lib/api", async (importOriginal) => {
5
+ const actual = await importOriginal<typeof import("@/lib/api")>();
6
+ return {
7
+ ...actual,
8
+ listIssueCommentsApi: vi.fn(),
9
+ createIssueCommentApi: vi.fn(),
10
+ };
11
+ });
12
+
13
+ const mockShowToast = vi.hoisted(() => vi.fn());
14
+ vi.mock("@/contexts/ToastContext", () => ({
15
+ useToast: () => ({ showToast: mockShowToast }),
16
+ }));
17
+
18
+ vi.mock("@/components/FileContentView", () => ({
19
+ default: ({ content }: { content: string }) => (
20
+ <div data-testid="comment-body">{content}</div>
21
+ ),
22
+ }));
23
+
24
+ import { listIssueCommentsApi, createIssueCommentApi } from "@/lib/api";
25
+ import IssueCommentThread from "./IssueCommentThread";
26
+
27
+ const mockList = vi.mocked(listIssueCommentsApi);
28
+ const mockCreate = vi.mocked(createIssueCommentApi);
29
+
30
+ const COMMENT = {
31
+ id: 1001,
32
+ body: "Hello from GitHub",
33
+ author: "alice",
34
+ createdAt: "2026-05-19T10:00:00Z",
35
+ updatedAt: "2026-05-19T10:00:00Z",
36
+ url: "https://github.com/org/repo/issues/42#issuecomment-1001",
37
+ };
38
+
39
+ describe("IssueCommentThread", () => {
40
+ beforeEach(() => {
41
+ vi.clearAllMocks();
42
+ mockList.mockResolvedValue({ comments: [] });
43
+ });
44
+
45
+ it("コメント一覧を時系列で表示する", async () => {
46
+ mockList.mockResolvedValue({ comments: [COMMENT] });
47
+ render(<IssueCommentThread issueNumber={42} canEdit={true} />);
48
+ await waitFor(() => {
49
+ expect(screen.getByText("alice")).toBeTruthy();
50
+ expect(screen.getByTestId("comment-body").textContent).toBe("Hello from GitHub");
51
+ });
52
+ });
53
+
54
+ it("canEdit=true のとき投稿フォームを表示する", async () => {
55
+ render(<IssueCommentThread issueNumber={42} canEdit={true} />);
56
+ await waitFor(() => {
57
+ expect(screen.getByPlaceholderText("Markdown でコメントを入力…")).toBeTruthy();
58
+ expect(screen.getByText("コメント投稿")).toBeTruthy();
59
+ });
60
+ });
61
+
62
+ it("canEdit=false のとき投稿フォームを非表示にする", async () => {
63
+ render(<IssueCommentThread issueNumber={42} canEdit={false} />);
64
+ await waitFor(() => {
65
+ expect(screen.queryByPlaceholderText("Markdown でコメントを入力…")).toBeNull();
66
+ });
67
+ });
68
+
69
+ it("コメント投稿成功後に一覧へ追加する", async () => {
70
+ const newComment = { ...COMMENT, id: 1002, body: "Posted" };
71
+ mockCreate.mockResolvedValue(newComment);
72
+ render(<IssueCommentThread issueNumber={42} canEdit={true} />);
73
+ await waitFor(() => expect(screen.getByText("コメント投稿")).toBeTruthy());
74
+
75
+ fireEvent.change(screen.getByPlaceholderText("Markdown でコメントを入力…"), {
76
+ target: { value: "Posted" },
77
+ });
78
+ fireEvent.click(screen.getByText("コメント投稿"));
79
+
80
+ await waitFor(() => {
81
+ expect(mockCreate).toHaveBeenCalledWith(42, "Posted");
82
+ expect(screen.getByText("Posted")).toBeTruthy();
83
+ });
84
+ });
85
+
86
+ it("読み込み失敗時にエラーメッセージを表示する", async () => {
87
+ mockList.mockRejectedValue(new Error("GitHub API unavailable"));
88
+ render(<IssueCommentThread issueNumber={42} canEdit={true} />);
89
+ await waitFor(() => {
90
+ expect(screen.getByText("GitHub API unavailable")).toBeTruthy();
91
+ });
92
+ });
93
+ });
@@ -0,0 +1,156 @@
1
+ import { useState, useEffect, useCallback, lazy, Suspense } from "react";
2
+ import { MessageSquare, Send, ExternalLink } from "lucide-react";
3
+ import {
4
+ listIssueCommentsApi,
5
+ createIssueCommentApi,
6
+ getErrorMessage,
7
+ type IssueComment,
8
+ } from "@/lib/api";
9
+ import { useToast } from "@/contexts/ToastContext";
10
+ import { ContentSkeleton } from "@/components/Skeleton";
11
+ import { ISSUE_MOBILE_ACTION_BUTTON } from "@/lib/issue-mobile-layout";
12
+
13
+ const FileContentView = lazy(() => import("@/components/FileContentView"));
14
+
15
+ type Props = {
16
+ issueNumber: number;
17
+ canEdit: boolean;
18
+ };
19
+
20
+ function formatDate(iso: string): string {
21
+ const d = new Date(iso);
22
+ return d.toLocaleString("ja-JP", {
23
+ month: "2-digit",
24
+ day: "2-digit",
25
+ hour: "2-digit",
26
+ minute: "2-digit",
27
+ });
28
+ }
29
+
30
+ export default function IssueCommentThread({ issueNumber, canEdit }: Props) {
31
+ const { showToast } = useToast();
32
+ const [comments, setComments] = useState<IssueComment[]>([]);
33
+ const [loading, setLoading] = useState(true);
34
+ const [loadError, setLoadError] = useState<string | null>(null);
35
+ const [draft, setDraft] = useState("");
36
+ const [posting, setPosting] = useState(false);
37
+
38
+ const loadComments = useCallback(async () => {
39
+ setLoading(true);
40
+ setLoadError(null);
41
+ try {
42
+ const data = await listIssueCommentsApi(issueNumber);
43
+ setComments(data.comments);
44
+ } catch (e) {
45
+ setComments([]);
46
+ setLoadError(getErrorMessage(e, "コメントの読み込みに失敗しました"));
47
+ } finally {
48
+ setLoading(false);
49
+ }
50
+ }, [issueNumber]);
51
+
52
+ useEffect(() => {
53
+ void loadComments();
54
+ }, [loadComments]);
55
+
56
+ const handlePost = async () => {
57
+ const text = draft.trim();
58
+ if (!text) return;
59
+ setPosting(true);
60
+ try {
61
+ const created = await createIssueCommentApi(issueNumber, text);
62
+ setComments((prev) => [...prev, created]);
63
+ setDraft("");
64
+ showToast("コメントを投稿しました", "success");
65
+ } catch (e) {
66
+ showToast(`コメント投稿に失敗しました: ${getErrorMessage(e)}`, "error");
67
+ } finally {
68
+ setPosting(false);
69
+ }
70
+ };
71
+
72
+ return (
73
+ <div className="border-t border-gray-700 pt-4 mt-4">
74
+ <h2 className="text-sm font-semibold text-gray-300 flex items-center gap-2 mb-3">
75
+ <MessageSquare className="w-4 h-4" />
76
+ コメント
77
+ {!loading && (
78
+ <span className="text-gray-500 font-normal">({comments.length})</span>
79
+ )}
80
+ </h2>
81
+
82
+ {loading && <ContentSkeleton />}
83
+
84
+ {!loading && loadError && (
85
+ <p className="text-sm text-red-400">{loadError}</p>
86
+ )}
87
+
88
+ {!loading && !loadError && comments.length === 0 && (
89
+ <p className="text-sm text-gray-500 italic">コメントはまだありません</p>
90
+ )}
91
+
92
+ {!loading && !loadError && comments.length > 0 && (
93
+ <ul className="space-y-3 mb-4">
94
+ {comments.map((c) => (
95
+ <li
96
+ key={c.id}
97
+ className="rounded border border-gray-700 bg-gray-800/60 px-3 py-2 text-sm"
98
+ >
99
+ <div className="flex items-baseline justify-between gap-2 mb-1">
100
+ <span className="font-medium text-gray-200">{c.author}</span>
101
+ <div className="flex items-center gap-2 shrink-0 text-xs text-gray-500">
102
+ <span>{formatDate(c.createdAt)}</span>
103
+ {c.url && (
104
+ <a
105
+ href={c.url}
106
+ target="_blank"
107
+ rel="noopener noreferrer"
108
+ className="text-blue-400 hover:text-blue-300"
109
+ aria-label="GitHub で開く"
110
+ >
111
+ <ExternalLink className="w-3 h-3" />
112
+ </a>
113
+ )}
114
+ </div>
115
+ </div>
116
+ {c.body ? (
117
+ <Suspense fallback={<ContentSkeleton />}>
118
+ <FileContentView
119
+ path={`issue-comment-${c.id}.md`}
120
+ content={c.body}
121
+ encoding="utf-8"
122
+ />
123
+ </Suspense>
124
+ ) : (
125
+ <p className="text-gray-500 italic text-xs">(空のコメント)</p>
126
+ )}
127
+ </li>
128
+ ))}
129
+ </ul>
130
+ )}
131
+
132
+ {canEdit && (
133
+ <div className="space-y-2">
134
+ <label className="block text-xs text-gray-400">コメントを追加</label>
135
+ <textarea
136
+ value={draft}
137
+ onChange={(e) => setDraft(e.target.value)}
138
+ placeholder="Markdown でコメントを入力…"
139
+ rows={4}
140
+ disabled={posting}
141
+ className="w-full px-3 py-2 rounded bg-gray-900 border border-gray-600 text-gray-200 placeholder-gray-500 outline-none focus:border-blue-500 text-sm font-mono resize-y"
142
+ />
143
+ <button
144
+ type="button"
145
+ onClick={() => void handlePost()}
146
+ disabled={posting || !draft.trim()}
147
+ className={`${ISSUE_MOBILE_ACTION_BUTTON} bg-blue-600 hover:bg-blue-700 text-white transition-colors disabled:opacity-50 flex items-center justify-center gap-1.5`}
148
+ >
149
+ <Send className="w-3.5 h-3.5" />
150
+ {posting ? "投稿中…" : "コメント投稿"}
151
+ </button>
152
+ </div>
153
+ )}
154
+ </div>
155
+ );
156
+ }