@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,476 @@
1
+ import { useState, useEffect, useCallback, useRef, lazy, Suspense } from "react";
2
+ import {
3
+ getIssueApi,
4
+ createIssueApi,
5
+ updateIssueApi,
6
+ getErrorMessage,
7
+ isAbortError,
8
+ } from "@/lib/api";
9
+ import type { IssueDetail, IssueSummary } from "@/lib/api";
10
+ import { useAuth } from "@/contexts/AuthContext";
11
+ import { useToast } from "@/contexts/ToastContext";
12
+ import { usePeriodicSync } from "@/hooks/usePeriodicSync";
13
+ import {
14
+ GITHUB_SYNC_POLL_INTERVAL_MS,
15
+ hasIssueSnapshotChanged,
16
+ isIssueSnapshotStale,
17
+ } from "@/lib/github-sync";
18
+ import {
19
+ CircleDot,
20
+ CircleCheck,
21
+ ExternalLink,
22
+ Save,
23
+ X,
24
+ Pencil,
25
+ Plus,
26
+ } from "lucide-react";
27
+ import { ContentSkeleton, LoadingCircle } from "@/components/Skeleton";
28
+ import LabelSelector from "@/components/LabelSelector";
29
+ import IssueCommentThread from "@/components/IssueCommentThread";
30
+ import {
31
+ ISSUE_MOBILE_ACTION_BUTTON,
32
+ ISSUE_MOBILE_ACTION_ROW,
33
+ ISSUE_MOBILE_DETAIL_ROOT,
34
+ } from "@/lib/issue-mobile-layout";
35
+
36
+ const FileContentView = lazy(() => import("@/components/FileContentView"));
37
+
38
+ type IssueDetailViewProps = {
39
+ issueNumber: number | "new";
40
+ onCreated?: (issue: IssueSummary) => void;
41
+ onClose?: () => void;
42
+ onLabelsMutated?: () => void;
43
+ onExternalChange?: (issue: IssueDetail, options?: { background?: boolean }) => void;
44
+ syncEnabled?: boolean;
45
+ };
46
+
47
+ export default function IssueDetailView({
48
+ issueNumber,
49
+ onCreated,
50
+ onClose,
51
+ onLabelsMutated,
52
+ onExternalChange,
53
+ syncEnabled = false,
54
+ }: IssueDetailViewProps) {
55
+ const { canEdit } = useAuth();
56
+ const { showToast } = useToast();
57
+
58
+ const isNew = issueNumber === "new";
59
+ const [issue, setIssue] = useState<IssueDetail | null>(null);
60
+ const [loading, setLoading] = useState(!isNew);
61
+ const [editing, setEditing] = useState(isNew);
62
+ const [saving, setSaving] = useState(false);
63
+
64
+ const [title, setTitle] = useState("");
65
+ const [body, setBody] = useState("");
66
+ const [selectedLabels, setSelectedLabels] = useState<string[]>([]);
67
+
68
+ const loadRequestSeq = useRef(0);
69
+ const pollRequestSeq = useRef(0);
70
+ // freshness ゲート: 取得ごとに単調増加する世代を採番し、適用済み世代(appliedGen)以下の取得結果は
71
+ // 上書きしない。遅い foreground load が、後から始まったより新しい background poll を上書きするのを
72
+ // 防ぐ(#949・REQ-016-AC-13)。poll 失敗時は appliedGen を進めないため #934 / AC-10 の失敗ケースは維持。
73
+ // gen は単調増加のみでリセット不要: 別 Issue へ切り替わると `MainPage` が issueNumber を key に当 view を
74
+ // remount する(refs 初期化)。remount しない経路でも、旧 Issue の in-flight 取得は loadSeq/pollSeq で
75
+ // 棄却され、gen は衝突しないため誤適用は起きない。
76
+ const fetchGenSeq = useRef(0);
77
+ const appliedGen = useRef(0);
78
+ const editingRef = useRef(editing);
79
+ const issueRef = useRef(issue);
80
+ const mountedRef = useRef(true);
81
+
82
+ useEffect(() => {
83
+ mountedRef.current = true;
84
+ return () => {
85
+ mountedRef.current = false;
86
+ };
87
+ }, []);
88
+
89
+ useEffect(() => {
90
+ editingRef.current = editing;
91
+ }, [editing]);
92
+
93
+ useEffect(() => {
94
+ issueRef.current = issue;
95
+ }, [issue]);
96
+
97
+ const beginLoadRequest = useCallback(() => {
98
+ loadRequestSeq.current += 1;
99
+ pollRequestSeq.current += 1;
100
+ fetchGenSeq.current += 1;
101
+ return { requestId: loadRequestSeq.current, gen: fetchGenSeq.current };
102
+ }, []);
103
+
104
+ const beginPollRequest = useCallback(() => {
105
+ pollRequestSeq.current += 1;
106
+ fetchGenSeq.current += 1;
107
+ return { requestId: pollRequestSeq.current, gen: fetchGenSeq.current };
108
+ }, []);
109
+
110
+ const loadIssue = useCallback(() => {
111
+ if (isNew) return;
112
+ const targetNumber = issueNumber as number;
113
+ const { requestId, gen } = beginLoadRequest();
114
+ // setIssue(null) で issueRef が一旦クリアされるため、stale 判定・復元の基準となる
115
+ // 取得開始時点の表示スナップショットを先に捕捉する(#978)
116
+ const previousSnapshot = issueRef.current;
117
+ setIssue(null);
118
+ setLoading(true);
119
+ getIssueApi(targetNumber)
120
+ .then((data) => {
121
+ if (!mountedRef.current || requestId !== loadRequestSeq.current) return;
122
+ // より新しい取得が適用済みならデータは上書きしない(loading は finally が解除)(#949)
123
+ if (gen <= appliedGen.current) return;
124
+ // foreground load も書込(save / label 変更)直後の eventual consistency で更新前(stale)応答を
125
+ // 返しうる。in-flight 中に適用された最新スナップショット(issueRef.current)、無ければ取得開始時の
126
+ // スナップショットより古い updatedAt、または同一秒で内容が後退する応答は反映せず表示を巻き戻さない
127
+ // (#978 / 同一秒は #979・poll 経路 #971 と同種)。
128
+ // stale 時は appliedGen を進めず(捨てた取得で世代を消費しない)、setIssue(null) で消えた表示を
129
+ // 基準スナップショットへ復元する。
130
+ const previous = issueRef.current ?? previousSnapshot;
131
+ if (isIssueSnapshotStale(previous, data)) {
132
+ if (previous) setIssue(previous);
133
+ return;
134
+ }
135
+ appliedGen.current = gen;
136
+ setIssue(data);
137
+ // 編集中(editing)は loadIssue の SUCCESS でも form state を上書きしない(#987・REQ-016-AC-17)。
138
+ // ラベル変更(onLabelsMutated)起因の再取得が happy path で成功しても、ユーザーが入力途中の
139
+ // title / body / selectedLabels を server 値へ巻き戻さない。issue スナップショット同期(setIssue)は
140
+ // 継続しつつ form 反映のみガードする(poll 経路は editingRef で早期 return・編集中保護として同種)。
141
+ if (!editingRef.current) {
142
+ setTitle(data.title);
143
+ setBody(data.body);
144
+ setSelectedLabels(data.labels.map((l) => l.name));
145
+ }
146
+ })
147
+ .catch((e) => {
148
+ if (isAbortError(e) || !mountedRef.current || requestId !== loadRequestSeq.current) return;
149
+ setIssue(null);
150
+ showToast(`Issue の読み込みに失敗しました: ${getErrorMessage(e)}`, "error");
151
+ })
152
+ .finally(() => {
153
+ if (mountedRef.current && requestId === loadRequestSeq.current) {
154
+ setLoading(false);
155
+ }
156
+ });
157
+ }, [issueNumber, isNew, showToast, beginLoadRequest]);
158
+
159
+ useEffect(() => {
160
+ loadIssue();
161
+ }, [loadIssue]);
162
+
163
+ const pollIssue = useCallback(async () => {
164
+ if (isNew || editingRef.current) return;
165
+ const targetNumber = issueNumber;
166
+ if (typeof targetNumber !== "number") return;
167
+ const { requestId, gen } = beginPollRequest();
168
+ try {
169
+ const data = await getIssueApi(targetNumber);
170
+ if (!mountedRef.current || requestId !== pollRequestSeq.current) return;
171
+ if (editingRef.current) return;
172
+ // より新しい取得が適用済みなら、この poll 結果(古い)は反映も外部変更通知も行わない(#949)
173
+ if (gen <= appliedGen.current) return;
174
+
175
+ const previous = issueRef.current;
176
+ // 書込(save / close-reopen)直後の eventual consistency で、save より後に開始した poll が
177
+ // 更新前の応答を返すことがある。取得開始順の freshness ゲート(#949)は通過してしまうため、
178
+ // 現在表示中より古い updatedAt(#971)、または同一秒で内容が後退する応答(#979)は stale と
179
+ // みなし反映も通知も行わない。
180
+ // stale 応答では appliedGen を進めない(#949 ゲートの意味は「採用した取得」であり、捨てた取得で
181
+ // 世代を消費すると、より早く開始した in-flight 取得の正当な結果が棄却されうる)。
182
+ // 次周期の poll が整合後データを返した時点で通常どおり最新へ更新される。
183
+ if (isIssueSnapshotStale(previous, data)) return;
184
+
185
+ appliedGen.current = gen;
186
+
187
+ const snapshotChanged = previous != null && hasIssueSnapshotChanged(previous, data);
188
+ const bodyChanged = previous == null || previous.body !== data.body;
189
+ if (!snapshotChanged && !bodyChanged) return;
190
+
191
+ if (snapshotChanged) {
192
+ onExternalChange?.(data, { background: true });
193
+ }
194
+ setIssue(data);
195
+ setTitle(data.title);
196
+ setBody(data.body);
197
+ setSelectedLabels(data.labels.map((l) => l.name));
198
+ } catch {
199
+ // バックグラウンド同期の失敗は UI を乱さない(手動再読み込みでエラー表示)
200
+ }
201
+ }, [issueNumber, isNew, onExternalChange, beginPollRequest]);
202
+
203
+ usePeriodicSync({
204
+ enabled: syncEnabled && !isNew && !editing,
205
+ intervalMs: GITHUB_SYNC_POLL_INTERVAL_MS,
206
+ onSync: pollIssue,
207
+ // マウント時の初回 loadIssue と即時 pollIssue の二重 dispatch を回避(#929)
208
+ skipInitialSync: true,
209
+ });
210
+
211
+ const handleSave = useCallback(async () => {
212
+ if (!title.trim()) {
213
+ showToast("タイトルを入力してください", "error");
214
+ return;
215
+ }
216
+ setSaving(true);
217
+ try {
218
+ if (isNew) {
219
+ const created = await createIssueApi({
220
+ title: title.trim(),
221
+ body,
222
+ labels: selectedLabels.length > 0 ? selectedLabels : undefined,
223
+ });
224
+ if (!mountedRef.current) return;
225
+ showToast(`Issue #${created.number} を作成しました`, "success");
226
+ setIssue(created);
227
+ setEditing(false);
228
+ onCreated?.(created);
229
+ } else {
230
+ beginPollRequest();
231
+ const updated = await updateIssueApi(issueNumber as number, {
232
+ title: title.trim(),
233
+ body,
234
+ labels: selectedLabels,
235
+ });
236
+ if (!mountedRef.current) return;
237
+ setIssue(updated);
238
+ setEditing(false);
239
+ showToast("Issue を更新しました", "success");
240
+ onExternalChange?.(updated);
241
+ }
242
+ } catch (e) {
243
+ if (!mountedRef.current) return;
244
+ showToast(`保存に失敗しました: ${getErrorMessage(e)}`, "error");
245
+ } finally {
246
+ if (mountedRef.current) setSaving(false);
247
+ }
248
+ }, [title, body, selectedLabels, isNew, issueNumber, showToast, onCreated, onExternalChange, beginPollRequest]);
249
+
250
+ const handleToggleState = useCallback(async () => {
251
+ if (!issue) return;
252
+ const newState = issue.state === "open" ? "closed" : "open";
253
+ setSaving(true);
254
+ try {
255
+ beginPollRequest();
256
+ const updated = await updateIssueApi(issue.number, { state: newState });
257
+ if (!mountedRef.current) return;
258
+ setIssue(updated);
259
+ onExternalChange?.(updated);
260
+ showToast(
261
+ newState === "closed" ? "Issue をクローズしました" : "Issue を再オープンしました",
262
+ "success",
263
+ );
264
+ } catch (e) {
265
+ if (!mountedRef.current) return;
266
+ showToast(`状態変更に失敗しました: ${getErrorMessage(e)}`, "error");
267
+ } finally {
268
+ if (mountedRef.current) setSaving(false);
269
+ }
270
+ }, [issue, showToast, onExternalChange, beginPollRequest]);
271
+
272
+ if (loading) {
273
+ return <LoadingCircle message="Issue を読み込み中…" />;
274
+ }
275
+
276
+ if (editing) {
277
+ return (
278
+ <div className={ISSUE_MOBILE_DETAIL_ROOT}>
279
+ <h2 className="text-lg font-bold text-gray-200 mb-4 flex items-center gap-2">
280
+ {isNew ? (
281
+ <>
282
+ <Plus className="w-5 h-5 text-green-400" />
283
+ 新規 Issue 作成
284
+ </>
285
+ ) : (
286
+ <>
287
+ <Pencil className="w-5 h-5 text-blue-400" />
288
+ Issue #{issueNumber} 編集
289
+ </>
290
+ )}
291
+ </h2>
292
+
293
+ <div className="space-y-4">
294
+ <div>
295
+ <label className="block text-xs text-gray-400 mb-1">タイトル</label>
296
+ <input
297
+ type="text"
298
+ value={title}
299
+ onChange={(e) => setTitle(e.target.value)}
300
+ placeholder="Issue のタイトル"
301
+ className="w-full px-3 py-2.5 sm:py-2 rounded bg-gray-900 border border-gray-600 text-gray-200 placeholder-gray-500 outline-none focus:border-blue-500 text-sm min-h-11 sm:min-h-0"
302
+ autoFocus
303
+ />
304
+ </div>
305
+
306
+ <LabelSelector
307
+ selected={selectedLabels}
308
+ onChange={setSelectedLabels}
309
+ disabled={saving}
310
+ canManageLabels={canEdit}
311
+ onLabelsMutated={() => {
312
+ onLabelsMutated?.();
313
+ if (!isNew) {
314
+ loadIssue();
315
+ }
316
+ }}
317
+ />
318
+
319
+ <div>
320
+ <label className="block text-xs text-gray-400 mb-1">本文(Markdown)</label>
321
+ <textarea
322
+ value={body}
323
+ onChange={(e) => setBody(e.target.value)}
324
+ placeholder="Issue の詳細を Markdown で記述…"
325
+ rows={12}
326
+ 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"
327
+ />
328
+ </div>
329
+
330
+ <div className={ISSUE_MOBILE_ACTION_ROW}>
331
+ <button
332
+ type="button"
333
+ onClick={handleSave}
334
+ disabled={saving || !title.trim()}
335
+ 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`}
336
+ >
337
+ <Save className="w-4 h-4" />
338
+ {saving ? "保存中…" : isNew ? "作成" : "保存"}
339
+ </button>
340
+ <button
341
+ type="button"
342
+ onClick={() => {
343
+ if (isNew) {
344
+ onClose?.();
345
+ } else {
346
+ setTitle(issue?.title ?? "");
347
+ setBody(issue?.body ?? "");
348
+ setSelectedLabels(issue?.labels.map((l) => l.name) ?? []);
349
+ setEditing(false);
350
+ }
351
+ }}
352
+ className={`${ISSUE_MOBILE_ACTION_BUTTON} text-gray-400 hover:text-gray-200 hover:bg-gray-700 transition-colors flex items-center justify-center gap-1.5`}
353
+ >
354
+ <X className="w-4 h-4" />
355
+ キャンセル
356
+ </button>
357
+ </div>
358
+ </div>
359
+ </div>
360
+ );
361
+ }
362
+
363
+ if (!issue) {
364
+ return (
365
+ <div className="flex items-center justify-center h-full p-6">
366
+ <p className="text-gray-500">Issue が見つかりませんでした</p>
367
+ </div>
368
+ );
369
+ }
370
+
371
+ return (
372
+ <div className={ISSUE_MOBILE_DETAIL_ROOT}>
373
+ {/* Header */}
374
+ <div className="mb-4">
375
+ <h1 className="text-lg sm:text-xl font-bold text-gray-100 flex flex-col gap-1 sm:flex-row sm:items-start sm:gap-2 break-words">
376
+ <span className="flex items-start gap-2 min-w-0">
377
+ {issue.state === "open" ? (
378
+ <CircleDot className="w-5 h-5 text-green-400 mt-0.5 shrink-0" />
379
+ ) : (
380
+ <CircleCheck className="w-5 h-5 text-purple-400 mt-0.5 shrink-0" />
381
+ )}
382
+ <span className="min-w-0">{issue.title}</span>
383
+ </span>
384
+ <span className="text-gray-500 font-normal shrink-0">#{issue.number}</span>
385
+ </h1>
386
+
387
+ <div className="flex flex-wrap items-center gap-x-3 gap-y-1 mt-2 text-xs text-gray-400">
388
+ <span>{issue.author}</span>
389
+ <span>
390
+ {new Date(issue.createdAt).toLocaleDateString("ja-JP")}
391
+ </span>
392
+ {issue.url && (
393
+ <a
394
+ href={issue.url}
395
+ target="_blank"
396
+ rel="noopener noreferrer"
397
+ className="flex items-center gap-1 text-blue-400 hover:text-blue-300"
398
+ >
399
+ <ExternalLink className="w-3 h-3" />
400
+ GitHub
401
+ </a>
402
+ )}
403
+ </div>
404
+
405
+ {issue.labels.length > 0 && (
406
+ <div className="flex flex-wrap gap-1 mt-2">
407
+ {issue.labels.map((l) => (
408
+ <span
409
+ key={l.name}
410
+ className="px-2 py-0.5 rounded-full text-xs"
411
+ style={{
412
+ backgroundColor: `#${l.color}22`,
413
+ color: `#${l.color}`,
414
+ border: `1px solid #${l.color}44`,
415
+ }}
416
+ >
417
+ {l.name}
418
+ </span>
419
+ ))}
420
+ </div>
421
+ )}
422
+
423
+ {/* Action buttons */}
424
+ {canEdit && (
425
+ <div className={`${ISSUE_MOBILE_ACTION_ROW} mt-3`}>
426
+ <button
427
+ type="button"
428
+ onClick={() => setEditing(true)}
429
+ className={`${ISSUE_MOBILE_ACTION_BUTTON} bg-gray-700 hover:bg-gray-600 text-gray-200 transition-colors flex items-center justify-center gap-1.5`}
430
+ >
431
+ <Pencil className="w-3.5 h-3.5" />
432
+ 編集
433
+ </button>
434
+ <button
435
+ type="button"
436
+ onClick={handleToggleState}
437
+ disabled={saving}
438
+ className={`${ISSUE_MOBILE_ACTION_BUTTON} transition-colors flex items-center justify-center gap-1.5 disabled:opacity-50 ${
439
+ issue.state === "open"
440
+ ? "bg-purple-700/30 text-purple-300 hover:bg-purple-700/50"
441
+ : "bg-green-700/30 text-green-300 hover:bg-green-700/50"
442
+ }`}
443
+ >
444
+ {issue.state === "open" ? (
445
+ <>
446
+ <CircleCheck className="w-3.5 h-3.5" />
447
+ クローズ
448
+ </>
449
+ ) : (
450
+ <>
451
+ <CircleDot className="w-3.5 h-3.5" />
452
+ 再オープン
453
+ </>
454
+ )}
455
+ </button>
456
+ </div>
457
+ )}
458
+ </div>
459
+
460
+ {/* Body */}
461
+ {issue.body ? (
462
+ <div className="border-t border-gray-700 pt-4">
463
+ <Suspense fallback={<ContentSkeleton />}>
464
+ <FileContentView path="issue.md" content={issue.body} encoding="utf-8" />
465
+ </Suspense>
466
+ </div>
467
+ ) : (
468
+ <div className="border-t border-gray-700 pt-4">
469
+ <p className="text-gray-500 text-sm italic">本文がありません</p>
470
+ </div>
471
+ )}
472
+
473
+ <IssueCommentThread issueNumber={issue.number} canEdit={canEdit} />
474
+ </div>
475
+ );
476
+ }