dodo-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (447) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +425 -0
  3. package/dist/auth/adapter.js +43 -0
  4. package/dist/auth/adapter.js.map +1 -0
  5. package/dist/auth/clientDeletion.js +45 -0
  6. package/dist/auth/clientDeletion.js.map +1 -0
  7. package/dist/auth/clients.js +55 -0
  8. package/dist/auth/clients.js.map +1 -0
  9. package/dist/auth/constants.js +10 -0
  10. package/dist/auth/constants.js.map +1 -0
  11. package/dist/auth/interactions.js +184 -0
  12. package/dist/auth/interactions.js.map +1 -0
  13. package/dist/auth/keys.js +56 -0
  14. package/dist/auth/keys.js.map +1 -0
  15. package/dist/auth/provider.js +131 -0
  16. package/dist/auth/provider.js.map +1 -0
  17. package/dist/auth/verifier.js +74 -0
  18. package/dist/auth/verifier.js.map +1 -0
  19. package/dist/cli/kill.js +124 -0
  20. package/dist/cli/kill.js.map +1 -0
  21. package/dist/cli/main.js +1393 -0
  22. package/dist/cli/main.js.map +1 -0
  23. package/dist/cli/menu.js +127 -0
  24. package/dist/cli/menu.js.map +1 -0
  25. package/dist/cli/terminal.js +30 -0
  26. package/dist/cli/terminal.js.map +1 -0
  27. package/dist/config/globalConfig.js +144 -0
  28. package/dist/config/globalConfig.js.map +1 -0
  29. package/dist/config/limits.js +42 -0
  30. package/dist/config/limits.js.map +1 -0
  31. package/dist/config/paths.js +94 -0
  32. package/dist/config/paths.js.map +1 -0
  33. package/dist/config/projectConfig.js +63 -0
  34. package/dist/config/projectConfig.js.map +1 -0
  35. package/dist/config/stateImport.js +306 -0
  36. package/dist/config/stateImport.js.map +1 -0
  37. package/dist/config/tunnelConfig.js +23 -0
  38. package/dist/config/tunnelConfig.js.map +1 -0
  39. package/dist/errors.js +82 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/evaluation/contracts.js +86 -0
  42. package/dist/evaluation/contracts.js.map +1 -0
  43. package/dist/evaluation/dodoBench.js +69 -0
  44. package/dist/evaluation/dodoBench.js.map +1 -0
  45. package/dist/index.js +26 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/ipc/authentication.js +117 -0
  48. package/dist/ipc/authentication.js.map +1 -0
  49. package/dist/ipc/client.js +86 -0
  50. package/dist/ipc/client.js.map +1 -0
  51. package/dist/ipc/installationClient.js +83 -0
  52. package/dist/ipc/installationClient.js.map +1 -0
  53. package/dist/ipc/ownerControl.js +46 -0
  54. package/dist/ipc/ownerControl.js.map +1 -0
  55. package/dist/ipc/protocol.js +2 -0
  56. package/dist/ipc/protocol.js.map +1 -0
  57. package/dist/ipc/server.js +108 -0
  58. package/dist/ipc/server.js.map +1 -0
  59. package/dist/platform/execResolve.js +64 -0
  60. package/dist/platform/execResolve.js.map +1 -0
  61. package/dist/platform/fileIdentity.js +26 -0
  62. package/dist/platform/fileIdentity.js.map +1 -0
  63. package/dist/platform/fsRetry.js +22 -0
  64. package/dist/platform/fsRetry.js.map +1 -0
  65. package/dist/platform/pathPolicy.js +29 -0
  66. package/dist/platform/pathPolicy.js.map +1 -0
  67. package/dist/platform/privateFs.js +116 -0
  68. package/dist/platform/privateFs.js.map +1 -0
  69. package/dist/platform/processTree.js +31 -0
  70. package/dist/platform/processTree.js.map +1 -0
  71. package/dist/platform/shell.js +74 -0
  72. package/dist/platform/shell.js.map +1 -0
  73. package/dist/platform/speech.js +94 -0
  74. package/dist/platform/speech.js.map +1 -0
  75. package/dist/platform/system.js +28 -0
  76. package/dist/platform/system.js.map +1 -0
  77. package/dist/platform/windowsSandbox.js +129 -0
  78. package/dist/platform/windowsSandbox.js.map +1 -0
  79. package/dist/projects/federation.js +312 -0
  80. package/dist/projects/federation.js.map +1 -0
  81. package/dist/projects/registry.js +291 -0
  82. package/dist/projects/registry.js.map +1 -0
  83. package/dist/security/accessMode.js +19 -0
  84. package/dist/security/accessMode.js.map +1 -0
  85. package/dist/security/approvals.js +56 -0
  86. package/dist/security/approvals.js.map +1 -0
  87. package/dist/security/env.js +57 -0
  88. package/dist/security/env.js.map +1 -0
  89. package/dist/security/mutationQueue.js +78 -0
  90. package/dist/security/mutationQueue.js.map +1 -0
  91. package/dist/security/policy.js +22 -0
  92. package/dist/security/policy.js.map +1 -0
  93. package/dist/security/projectAuthority.js +22 -0
  94. package/dist/security/projectAuthority.js.map +1 -0
  95. package/dist/security/redact.js +30 -0
  96. package/dist/security/redact.js.map +1 -0
  97. package/dist/server/aiAdmin.js +201 -0
  98. package/dist/server/aiAdmin.js.map +1 -0
  99. package/dist/server/appServer.js +461 -0
  100. package/dist/server/appServer.js.map +1 -0
  101. package/dist/server/bootstrap.js +185 -0
  102. package/dist/server/bootstrap.js.map +1 -0
  103. package/dist/server/configUi/app.css +347 -0
  104. package/dist/server/configUi/app.js +958 -0
  105. package/dist/server/configUi/index.html +379 -0
  106. package/dist/server/configUi/ui/alerts.js +92 -0
  107. package/dist/server/configUi/ui/dom.js +19 -0
  108. package/dist/server/configUi/ui/tooltips.js +115 -0
  109. package/dist/server/configUi/vendor/VERSION.txt +1 -0
  110. package/dist/server/configUi/vendor/sweetalert2.min.css +1 -0
  111. package/dist/server/configUi/vendor/sweetalert2.min.js +5 -0
  112. package/dist/server/configUi/workbench.css +62 -0
  113. package/dist/server/configUi/workbench.js +394 -0
  114. package/dist/server/installationRuntime.js +155 -0
  115. package/dist/server/installationRuntime.js.map +1 -0
  116. package/dist/server/instructions.js +17 -0
  117. package/dist/server/instructions.js.map +1 -0
  118. package/dist/server/ipcDispatch.js +225 -0
  119. package/dist/server/ipcDispatch.js.map +1 -0
  120. package/dist/server/localConfig.js +561 -0
  121. package/dist/server/localConfig.js.map +1 -0
  122. package/dist/server/optionalServices.js +30 -0
  123. package/dist/server/optionalServices.js.map +1 -0
  124. package/dist/server/projectLease.js +46 -0
  125. package/dist/server/projectLease.js.map +1 -0
  126. package/dist/server/stdioServer.js +75 -0
  127. package/dist/server/stdioServer.js.map +1 -0
  128. package/dist/server/version.js +13 -0
  129. package/dist/server/version.js.map +1 -0
  130. package/dist/server/workspaceHost.js +194 -0
  131. package/dist/server/workspaceHost.js.map +1 -0
  132. package/dist/services/agent/agentService.js +598 -0
  133. package/dist/services/agent/agentService.js.map +1 -0
  134. package/dist/services/agent/contracts.js +102 -0
  135. package/dist/services/agent/contracts.js.map +1 -0
  136. package/dist/services/ai/adapters.js +287 -0
  137. package/dist/services/ai/adapters.js.map +1 -0
  138. package/dist/services/ai/contracts.js +39 -0
  139. package/dist/services/ai/contracts.js.map +1 -0
  140. package/dist/services/ai/credentials.js +77 -0
  141. package/dist/services/ai/credentials.js.map +1 -0
  142. package/dist/services/ai/network.js +113 -0
  143. package/dist/services/ai/network.js.map +1 -0
  144. package/dist/services/ai/settings.js +178 -0
  145. package/dist/services/ai/settings.js.map +1 -0
  146. package/dist/services/ai/subagents.js +468 -0
  147. package/dist/services/ai/subagents.js.map +1 -0
  148. package/dist/services/assistance/analysis.js +352 -0
  149. package/dist/services/assistance/analysis.js.map +1 -0
  150. package/dist/services/assistance/contracts.js +54 -0
  151. package/dist/services/assistance/contracts.js.map +1 -0
  152. package/dist/services/assistance/verification.js +274 -0
  153. package/dist/services/assistance/verification.js.map +1 -0
  154. package/dist/services/brain/brainParser.js +97 -0
  155. package/dist/services/brain/brainParser.js.map +1 -0
  156. package/dist/services/brain/brainService.js +733 -0
  157. package/dist/services/brain/brainService.js.map +1 -0
  158. package/dist/services/brain/brainWorker.js +212 -0
  159. package/dist/services/brain/brainWorker.js.map +1 -0
  160. package/dist/services/brain/contracts.js +154 -0
  161. package/dist/services/brain/contracts.js.map +1 -0
  162. package/dist/services/brain/protocol.js +2 -0
  163. package/dist/services/brain/protocol.js.map +1 -0
  164. package/dist/services/changes/applier.js +544 -0
  165. package/dist/services/changes/applier.js.map +1 -0
  166. package/dist/services/changes/contentBudget.js +11 -0
  167. package/dist/services/changes/contentBudget.js.map +1 -0
  168. package/dist/services/changes/planner.js +284 -0
  169. package/dist/services/changes/planner.js.map +1 -0
  170. package/dist/services/changes/types.js +3 -0
  171. package/dist/services/changes/types.js.map +1 -0
  172. package/dist/services/context/contextEngine.js +746 -0
  173. package/dist/services/context/contextEngine.js.map +1 -0
  174. package/dist/services/context/contracts.js +88 -0
  175. package/dist/services/context/contracts.js.map +1 -0
  176. package/dist/services/desktop/desktopPolicy.js +76 -0
  177. package/dist/services/desktop/desktopPolicy.js.map +1 -0
  178. package/dist/services/desktop/desktopService.js +130 -0
  179. package/dist/services/desktop/desktopService.js.map +1 -0
  180. package/dist/services/desktop/nativeBackend.js +174 -0
  181. package/dist/services/desktop/nativeBackend.js.map +1 -0
  182. package/dist/services/desktop/protocol.js +32 -0
  183. package/dist/services/desktop/protocol.js.map +1 -0
  184. package/dist/services/files/readService.js +136 -0
  185. package/dist/services/files/readService.js.map +1 -0
  186. package/dist/services/git/gitService.js +369 -0
  187. package/dist/services/git/gitService.js.map +1 -0
  188. package/dist/services/intelligence/intelService.js +136 -0
  189. package/dist/services/intelligence/intelService.js.map +1 -0
  190. package/dist/services/intelligence/protocol.js +2 -0
  191. package/dist/services/intelligence/protocol.js.map +1 -0
  192. package/dist/services/intelligence/tsWorker.js +419 -0
  193. package/dist/services/intelligence/tsWorker.js.map +1 -0
  194. package/dist/services/jobs/commandInput.js +34 -0
  195. package/dist/services/jobs/commandInput.js.map +1 -0
  196. package/dist/services/jobs/jobManager.js +398 -0
  197. package/dist/services/jobs/jobManager.js.map +1 -0
  198. package/dist/services/jobs/sandbox.js +156 -0
  199. package/dist/services/jobs/sandbox.js.map +1 -0
  200. package/dist/services/jobs/sandboxWiring.js +37 -0
  201. package/dist/services/jobs/sandboxWiring.js.map +1 -0
  202. package/dist/services/jobs/spool.js +112 -0
  203. package/dist/services/jobs/spool.js.map +1 -0
  204. package/dist/services/jobs/windowsSandboxChild.js +24 -0
  205. package/dist/services/jobs/windowsSandboxChild.js.map +1 -0
  206. package/dist/services/jobs/windowsSandboxWorker.js +155 -0
  207. package/dist/services/jobs/windowsSandboxWorker.js.map +1 -0
  208. package/dist/services/lsp/documentUri.js +16 -0
  209. package/dist/services/lsp/documentUri.js.map +1 -0
  210. package/dist/services/lsp/jsonrpc.js +382 -0
  211. package/dist/services/lsp/jsonrpc.js.map +1 -0
  212. package/dist/services/lsp/lspService.js +1051 -0
  213. package/dist/services/lsp/lspService.js.map +1 -0
  214. package/dist/services/memory/contracts.js +94 -0
  215. package/dist/services/memory/contracts.js.map +1 -0
  216. package/dist/services/memory/memoryService.js +683 -0
  217. package/dist/services/memory/memoryService.js.map +1 -0
  218. package/dist/services/multimodal/browserService.js +407 -0
  219. package/dist/services/multimodal/browserService.js.map +1 -0
  220. package/dist/services/multimodal/byteRange.js +31 -0
  221. package/dist/services/multimodal/byteRange.js.map +1 -0
  222. package/dist/services/multimodal/contracts.js +59 -0
  223. package/dist/services/multimodal/contracts.js.map +1 -0
  224. package/dist/services/multimodal/gameService.js +95 -0
  225. package/dist/services/multimodal/gameService.js.map +1 -0
  226. package/dist/services/multimodal/images.js +107 -0
  227. package/dist/services/multimodal/images.js.map +1 -0
  228. package/dist/services/multimodal/mediaService.js +279 -0
  229. package/dist/services/multimodal/mediaService.js.map +1 -0
  230. package/dist/services/multimodal/mediaWorker.js +143 -0
  231. package/dist/services/multimodal/mediaWorker.js.map +1 -0
  232. package/dist/services/multimodal/multimodalService.js +51 -0
  233. package/dist/services/multimodal/multimodalService.js.map +1 -0
  234. package/dist/services/multimodal/network.js +69 -0
  235. package/dist/services/multimodal/network.js.map +1 -0
  236. package/dist/services/multimodal/operations.js +40 -0
  237. package/dist/services/multimodal/operations.js.map +1 -0
  238. package/dist/services/multimodal/storage.js +160 -0
  239. package/dist/services/multimodal/storage.js.map +1 -0
  240. package/dist/services/multimodal/workflowService.js +179 -0
  241. package/dist/services/multimodal/workflowService.js.map +1 -0
  242. package/dist/services/overview.js +284 -0
  243. package/dist/services/overview.js.map +1 -0
  244. package/dist/services/resources/casStore.js +304 -0
  245. package/dist/services/resources/casStore.js.map +1 -0
  246. package/dist/services/resources/contracts.js +75 -0
  247. package/dist/services/resources/contracts.js.map +1 -0
  248. package/dist/services/resources/mime.js +77 -0
  249. package/dist/services/resources/mime.js.map +1 -0
  250. package/dist/services/resources/providerRegistry.js +22 -0
  251. package/dist/services/resources/providerRegistry.js.map +1 -0
  252. package/dist/services/resources/providers.js +120 -0
  253. package/dist/services/resources/providers.js.map +1 -0
  254. package/dist/services/resources/resourceService.js +282 -0
  255. package/dist/services/resources/resourceService.js.map +1 -0
  256. package/dist/services/runtime/contracts.js +65 -0
  257. package/dist/services/runtime/contracts.js.map +1 -0
  258. package/dist/services/runtime/runtimeService.js +364 -0
  259. package/dist/services/runtime/runtimeService.js.map +1 -0
  260. package/dist/services/schedules/scheduleService.js +198 -0
  261. package/dist/services/schedules/scheduleService.js.map +1 -0
  262. package/dist/services/search/searchService.js +434 -0
  263. package/dist/services/search/searchService.js.map +1 -0
  264. package/dist/services/search/searchWorker.js +58 -0
  265. package/dist/services/search/searchWorker.js.map +1 -0
  266. package/dist/setup/componentProbes.js +259 -0
  267. package/dist/setup/componentProbes.js.map +1 -0
  268. package/dist/setup/download.js +139 -0
  269. package/dist/setup/download.js.map +1 -0
  270. package/dist/setup/managedTools.js +118 -0
  271. package/dist/setup/managedTools.js.map +1 -0
  272. package/dist/setup/sandboxProbe.js +172 -0
  273. package/dist/setup/sandboxProbe.js.map +1 -0
  274. package/dist/setup/setup.js +522 -0
  275. package/dist/setup/setup.js.map +1 -0
  276. package/dist/setup/windowsChromiumAcl.js +56 -0
  277. package/dist/setup/windowsChromiumAcl.js.map +1 -0
  278. package/dist/setup/windowsSandboxInstall.js +94 -0
  279. package/dist/setup/windowsSandboxInstall.js.map +1 -0
  280. package/dist/setup/windowsSpeechInstall.js +86 -0
  281. package/dist/setup/windowsSpeechInstall.js.map +1 -0
  282. package/dist/store/db.js +711 -0
  283. package/dist/store/db.js.map +1 -0
  284. package/dist/store/scopeEncoding.js +15 -0
  285. package/dist/store/scopeEncoding.js.map +1 -0
  286. package/dist/store/store.js +467 -0
  287. package/dist/store/store.js.map +1 -0
  288. package/dist/tools/agentRuntimeTools.js +216 -0
  289. package/dist/tools/agentRuntimeTools.js.map +1 -0
  290. package/dist/tools/agentTools.js +317 -0
  291. package/dist/tools/agentTools.js.map +1 -0
  292. package/dist/tools/assistanceTools.js +126 -0
  293. package/dist/tools/assistanceTools.js.map +1 -0
  294. package/dist/tools/brainTools.js +130 -0
  295. package/dist/tools/brainTools.js.map +1 -0
  296. package/dist/tools/catalog.js +30 -0
  297. package/dist/tools/catalog.js.map +1 -0
  298. package/dist/tools/changeTools.js +188 -0
  299. package/dist/tools/changeTools.js.map +1 -0
  300. package/dist/tools/context.js +243 -0
  301. package/dist/tools/context.js.map +1 -0
  302. package/dist/tools/contextTools.js +57 -0
  303. package/dist/tools/contextTools.js.map +1 -0
  304. package/dist/tools/coreCatalog.js +82 -0
  305. package/dist/tools/coreCatalog.js.map +1 -0
  306. package/dist/tools/desktopTools.js +41 -0
  307. package/dist/tools/desktopTools.js.map +1 -0
  308. package/dist/tools/directTools.js +273 -0
  309. package/dist/tools/directTools.js.map +1 -0
  310. package/dist/tools/envelope.js +71 -0
  311. package/dist/tools/envelope.js.map +1 -0
  312. package/dist/tools/extraTools.js +298 -0
  313. package/dist/tools/extraTools.js.map +1 -0
  314. package/dist/tools/gitTools.js +93 -0
  315. package/dist/tools/gitTools.js.map +1 -0
  316. package/dist/tools/jobTools.js +454 -0
  317. package/dist/tools/jobTools.js.map +1 -0
  318. package/dist/tools/memoryTools.js +102 -0
  319. package/dist/tools/memoryTools.js.map +1 -0
  320. package/dist/tools/metaTools.js +153 -0
  321. package/dist/tools/metaTools.js.map +1 -0
  322. package/dist/tools/multimodalTools.js +262 -0
  323. package/dist/tools/multimodalTools.js.map +1 -0
  324. package/dist/tools/projectTools.js +261 -0
  325. package/dist/tools/projectTools.js.map +1 -0
  326. package/dist/tools/resourceTools.js +81 -0
  327. package/dist/tools/resourceTools.js.map +1 -0
  328. package/dist/tools/runtimeTools.js +137 -0
  329. package/dist/tools/runtimeTools.js.map +1 -0
  330. package/dist/tools/scheduleTools.js +10 -0
  331. package/dist/tools/scheduleTools.js.map +1 -0
  332. package/dist/tools/semanticTools.js +141 -0
  333. package/dist/tools/semanticTools.js.map +1 -0
  334. package/dist/tools/subagentTools.js +32 -0
  335. package/dist/tools/subagentTools.js.map +1 -0
  336. package/dist/tools/surface.js +644 -0
  337. package/dist/tools/surface.js.map +1 -0
  338. package/dist/tunnel/control.js +113 -0
  339. package/dist/tunnel/control.js.map +1 -0
  340. package/dist/tunnel/credentials.js +392 -0
  341. package/dist/tunnel/credentials.js.map +1 -0
  342. package/dist/tunnel/log.js +84 -0
  343. package/dist/tunnel/log.js.map +1 -0
  344. package/dist/tunnel/runtime.js +55 -0
  345. package/dist/tunnel/runtime.js.map +1 -0
  346. package/dist/tunnel/supervisor.js +280 -0
  347. package/dist/tunnel/supervisor.js.map +1 -0
  348. package/dist/util/bytes.js +53 -0
  349. package/dist/util/bytes.js.map +1 -0
  350. package/dist/util/hash.js +53 -0
  351. package/dist/util/hash.js.map +1 -0
  352. package/dist/workspace/fs.js +305 -0
  353. package/dist/workspace/fs.js.map +1 -0
  354. package/dist/workspace/identity.js +17 -0
  355. package/dist/workspace/identity.js.map +1 -0
  356. package/dist/workspace/ignores.js +173 -0
  357. package/dist/workspace/ignores.js.map +1 -0
  358. package/dist/workspace/root.js +59 -0
  359. package/dist/workspace/root.js.map +1 -0
  360. package/docs/AGENT_RUNTIME.md +154 -0
  361. package/docs/AI_PROVIDERS.md +110 -0
  362. package/docs/ARCHITECTURE.md +331 -0
  363. package/docs/ASSISTANCE.md +31 -0
  364. package/docs/AUTH.md +59 -0
  365. package/docs/BRAIN.md +92 -0
  366. package/docs/COMPATIBILITY.md +92 -0
  367. package/docs/CONFIRMATION.md +13 -0
  368. package/docs/CONTEXT.md +87 -0
  369. package/docs/DESKTOP.md +35 -0
  370. package/docs/EVALUATION.md +86 -0
  371. package/docs/LARGE_INPUTS.md +21 -0
  372. package/docs/LSP.md +21 -0
  373. package/docs/MANUAL_ACCEPTANCE.md +283 -0
  374. package/docs/MEMORY.md +128 -0
  375. package/docs/MULTIMODAL.md +32 -0
  376. package/docs/PROJECTS.md +146 -0
  377. package/docs/RELEASE_1.0.0.md +111 -0
  378. package/docs/RELEASE_NOTES.md +92 -0
  379. package/docs/RESOURCES.md +83 -0
  380. package/docs/RUNTIME.md +125 -0
  381. package/docs/SCHEDULES.md +23 -0
  382. package/docs/SECURITY.md +250 -0
  383. package/docs/TEST_REPORT.md +312 -0
  384. package/docs/TUNNEL.md +86 -0
  385. package/docs/WEB_CLIENTS.md +43 -0
  386. package/docs/WINDOWS.md +79 -0
  387. package/docs/adr/001-one-process-one-workspace.md +22 -0
  388. package/docs/adr/002-external-tunnel.md +19 -0
  389. package/docs/adr/003-sdk-v2-legacy-stateless.md +20 -0
  390. package/docs/adr/004-embedded-oauth-provider.md +19 -0
  391. package/docs/adr/005-static-client-baseline.md +19 -0
  392. package/docs/adr/006-guarded-fs-explicit-exec.md +16 -0
  393. package/docs/adr/007-preview-hash-journal.md +18 -0
  394. package/docs/adr/008-ts-js-semantics-first.md +17 -0
  395. package/docs/adr/009-jobs-polling.md +18 -0
  396. package/docs/adr/010-sqlite-better-sqlite3.md +18 -0
  397. package/docs/adr/011-env-example-secure-default.md +19 -0
  398. package/docs/adr/012-workspace-scope-grant.md +24 -0
  399. package/docs/adr/013-loopback-proxy-trust.md +18 -0
  400. package/docs/adr/014-direct-coding-tier.md +48 -0
  401. package/docs/adr/015-coding-agent-parity.md +56 -0
  402. package/docs/adr/016-oidc-openid-consent.md +15 -0
  403. package/docs/adr/017-installation-identity-local-config.md +44 -0
  404. package/docs/adr/018-access-scope-encoding.md +11 -0
  405. package/docs/adr/019-runtime-workspace-switch.md +59 -0
  406. package/docs/adr/020-desktop-access.md +50 -0
  407. package/docs/adr/021-persistent-desktop-consent.md +39 -0
  408. package/docs/adr/022-owner-kill-preserves-login.md +30 -0
  409. package/docs/adr/023-large-coding-inputs.md +49 -0
  410. package/docs/adr/024-usage-rounds-and-schedules.md +72 -0
  411. package/docs/adr/025-owner-chat-whitelist.md +53 -0
  412. package/docs/adr/026-remove-conversation-confirmation.md +35 -0
  413. package/docs/adr/027-workspace-client-list.md +20 -0
  414. package/docs/adr/028-owner-client-deletion.md +25 -0
  415. package/docs/adr/029-compact-tool-surface.md +121 -0
  416. package/docs/adr/030-windows-native-candidate.md +71 -0
  417. package/docs/adr/031-owner-selected-tunnel-supervision.md +13 -0
  418. package/docs/adr/032-owner-project-registry.md +43 -0
  419. package/docs/adr/033-read-only-project-federation.md +61 -0
  420. package/docs/adr/034-universal-resource-cas.md +60 -0
  421. package/docs/adr/035-project-brain-incremental-index.md +51 -0
  422. package/docs/adr/036-context-engine-evidence.md +53 -0
  423. package/docs/adr/037-owner-reviewed-memory.md +46 -0
  424. package/docs/adr/038-runtime-intelligence.md +46 -0
  425. package/docs/adr/039-advanced-agent-runtime.md +57 -0
  426. package/docs/adr/040-dodobench-release-gate.md +43 -0
  427. package/docs/adr/041-local-macos-docker-linux-gates.md +32 -0
  428. package/docs/adr/042-project-directory-generation-identity.md +36 -0
  429. package/docs/adr/043-trusted-self-hosted-platform-gates.md +38 -0
  430. package/docs/adr/044-global-launcher-and-cli-menu.md +43 -0
  431. package/docs/adr/045-ai-providers-multiproject.md +56 -0
  432. package/docs/adr/046-personal-access-mode.md +32 -0
  433. package/docs/adr/README.md +64 -0
  434. package/examples/.dodo.json.example +20 -0
  435. package/examples/cloudflared.yml +23 -0
  436. package/examples/reverse-proxy-fixture.mjs +37 -0
  437. package/native/desktop-linux.py +387 -0
  438. package/native/desktop-windows.cs +180 -0
  439. package/native/desktop.swift +212 -0
  440. package/package.json +145 -0
  441. package/schemas/global-config.schema.json +497 -0
  442. package/schemas/project-config.schema.json +75 -0
  443. package/schemas/tools.compact.json +3236 -0
  444. package/schemas/tools.hybrid.json +8194 -0
  445. package/schemas/tools.json +34518 -0
  446. package/scripts/guard-publish.mjs +12 -0
  447. package/scripts/setup-multimodal.mjs +70 -0
@@ -0,0 +1,379 @@
1
+ <!doctype html>
2
+ <html lang="th" data-theme="dark">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <meta name="color-scheme" content="dark light">
7
+ <meta name="referrer" content="no-referrer">
8
+ <title>DODO Local Config</title>
9
+ <link rel="stylesheet" href="/assets/vendor/sweetalert2.min.css">
10
+ <link rel="stylesheet" href="/assets/app.css">
11
+ <link rel="stylesheet" href="/assets/workbench.css">
12
+ </head>
13
+ <body>
14
+ <a class="skip" href="#main">ข้ามไปยังเนื้อหา</a>
15
+
16
+ <header class="topbar">
17
+ <div class="brand">
18
+ <span class="logo" aria-hidden="true">DD</span>
19
+ <div>
20
+ <h1>DODO <span class="version" id="version" aria-label="เวอร์ชัน">…</span></h1>
21
+ <p class="sub">Local Config · หน้าตั้งค่าเฉพาะเจ้าของเครื่อง</p>
22
+ </div>
23
+ </div>
24
+ <ul class="chips" aria-label="สถานะระบบ">
25
+ <li class="chip" id="chip-mcp" data-state="idle"><span class="dot" aria-hidden="true"></span><span class="chip-icon" aria-hidden="true">…</span><span class="chip-text"><b>MCP</b> <span class="chip-value">กำลังตรวจ…</span></span></li>
26
+ <li class="chip" id="chip-oauth" data-state="idle"><span class="dot" aria-hidden="true"></span><span class="chip-icon" aria-hidden="true">…</span><span class="chip-text"><b>OAuth</b> <span class="chip-value">กำลังตรวจ…</span></span></li>
27
+ <li class="chip" id="chip-config" data-state="idle"><span class="dot" aria-hidden="true"></span><span class="chip-icon" aria-hidden="true">…</span><span class="chip-text"><b>Local Config</b> <span class="chip-value">กำลังตรวจ…</span></span></li>
28
+ </ul>
29
+ <button type="button" class="btn ghost" id="theme-toggle" aria-label="สลับธีม: มืด">◐ มืด</button>
30
+ </header>
31
+
32
+ <div class="notice" id="notice" role="status" aria-live="polite" hidden>
33
+ <span class="notice-icon" aria-hidden="true"></span>
34
+ <span class="notice-text"></span>
35
+ <button type="button" class="btn ghost small notice-close" id="notice-close" aria-label="ปิดข้อความ">✕</button>
36
+ </div>
37
+
38
+ <nav class="workbench-nav" aria-label="เมนู DODO">
39
+ <button type="button" class="btn" data-wb-view="overview" aria-pressed="true">ภาพรวม</button>
40
+ <button type="button" class="btn" data-wb-view="projects" aria-pressed="false">โปรเจกต์</button>
41
+ <button type="button" class="btn" data-wb-view="providers" aria-pressed="false">Providers &amp; Profiles</button>
42
+ <button type="button" class="btn" data-wb-view="chat" aria-pressed="false">Chat &amp; Tasks</button>
43
+ <button type="button" class="btn" data-wb-view="runs" aria-pressed="false">Runs &amp; Jobs</button>
44
+ <button type="button" class="btn" data-wb-view="admin" aria-pressed="false">Approvals</button>
45
+ <button type="button" class="btn" data-wb-view="knowledge" aria-pressed="false">Knowledge</button>
46
+ <button type="button" class="btn" data-wb-view="settings" aria-pressed="false">Settings</button>
47
+ </nav>
48
+
49
+ <main id="main" class="page-stack" aria-busy="true">
50
+
51
+ <section class="card" id="card-auth" hidden aria-labelledby="h-auth">
52
+ <h2 id="h-auth">ต้องเปิดจากลิงก์ส่วนตัว</h2>
53
+ <p>หน้านี้ใช้ token ส่วนตัวที่แสดงใน terminal ตอน <code>dodo start</code> ให้คัดลอกลิงก์ <b>Private config</b> ทั้งบรรทัด (มี <code>#…</code> ต่อท้าย) มาเปิดในเบราว์เซอร์อีกครั้ง ลิงก์หมดอายุใน 8 ชั่วโมง restart DODO เพื่อออกลิงก์ใหม่</p>
54
+ <p class="muted">อย่าส่งลิงก์นี้ให้ AI หรือผู้อื่น และห้ามชี้ tunnel มาที่พอร์ตนี้</p>
55
+ </section>
56
+
57
+ <section id="workbench" hidden aria-label="DODO Workbench">
58
+ <div class="wb-intro">
59
+ <p id="wb-summary" class="muted"></p>
60
+ <div class="wb-toolbar" id="wb-toolbar"><label>โปรเจกต์สำหรับหน้านี้<select id="wb-project" aria-label="โปรเจกต์สำหรับหน้านี้"></select></label><button class="btn" type="button" id="wb-select">เปิดโปรเจกต์</button><button class="btn" type="button" id="wb-refresh">รีเฟรช</button></div>
61
+ <p id="wb-root" class="muted small-text">การเลือกที่นี่ไม่เปลี่ยน default workspace ของ AI ตัวอื่น</p>
62
+ </div>
63
+ <p id="wb-notice" role="status" aria-live="polite"></p><div id="wb-body"></div>
64
+ </section>
65
+
66
+ <!-- ============ Projects page (legacy cards, IDs unchanged) ============ -->
67
+ <div class="grid page" id="page-projects" hidden>
68
+
69
+ <section class="card" id="card-workspace" aria-labelledby="h-ws">
70
+ <div class="card-head">
71
+ <h2 id="h-ws">Default workspace <button type="button" class="help-tip" data-tip="โปรเจกต์ที่ AI client ภายนอก (เช่น ChatGPT) เห็นเป็นค่าเริ่มต้น การสลับจะออก workspace ID และ epoch ใหม่ทันที และ AI ทุกตัวต้องเรียก project_overview ใหม่" aria-label="คำอธิบาย: default workspace">?</button></h2>
72
+ <span class="badge" id="ws-state-badge" hidden></span>
73
+ </div>
74
+ <div class="card-state" id="ws-loading">กำลังโหลด…</div>
75
+ <div class="card-body" id="ws-body" hidden>
76
+ <div class="kv">
77
+ <div class="k">โปรเจกต์</div>
78
+ <div class="v"><strong id="ws-name" class="ws-name">…</strong></div>
79
+ <div class="k">Path</div>
80
+ <div class="v path-row">
81
+ <code id="ws-root" class="path">…</code>
82
+ <button type="button" class="btn small" id="ws-copy" aria-label="คัดลอก path ของ workspace">คัดลอก</button>
83
+ </div>
84
+ <div class="k">งานที่กำลังรัน</div>
85
+ <div class="v" id="ws-jobs">…</div>
86
+ </div>
87
+
88
+ <div class="callout warn" id="ws-hint" hidden>
89
+ <span aria-hidden="true">⚠</span>
90
+ <div><b>workspace เปลี่ยนแล้ว</b> — AI ทุกตัวต้องเรียก <code>project_overview</code> ใหม่ก่อนใช้งานต่อ คำขอที่ถือ context เดิมจะถูกปฏิเสธ (<code>WORKSPACE_MISMATCH</code>)</div>
91
+ </div>
92
+
93
+ <form id="ws-form" class="form" novalidate>
94
+ <label for="ws-path">เลือกหรือเปลี่ยนโปรเจกต์ (absolute path)</label>
95
+ <div class="input-row">
96
+ <input id="ws-path" name="path" type="text" inputmode="text" autocomplete="off" spellcheck="false" placeholder="/Users/you/projects/app" aria-describedby="ws-path-help ws-path-error" required>
97
+ <button type="submit" class="btn primary" id="ws-switch">เปิดโปรเจกต์</button>
98
+ </div>
99
+ <p class="help" id="ws-path-help">ต้องเป็นโฟลเดอร์ที่มีอยู่จริง ไม่ใช่ home หรือ root ของดิสก์ DODO จะปฏิเสธถ้ามีงานกำลังรันอยู่</p>
100
+ <p class="error" id="ws-path-error" role="alert" hidden></p>
101
+ <p class="progress" id="ws-progress" hidden><span class="spinner" aria-hidden="true"></span> กำลังสลับ workspace…</p>
102
+ </form>
103
+
104
+ <details class="details" id="ws-details">
105
+ <summary>รายละเอียดทางเทคนิค (Workspace ID / Epoch)</summary>
106
+ <dl class="dl">
107
+ <dt>Workspace ID <button type="button" class="help-tip" data-tip="รหัสประจำโปรเจกต์ที่คงที่ต่อ path AI ได้ค่านี้จาก project_overview และต้องส่งกลับมากับทุก tool call" aria-label="คำอธิบาย: workspace ID">?</button></dt><dd><code id="ws-id">…</code></dd>
108
+ <dt>Epoch <button type="button" class="help-tip" data-tip="ค่าประจำรอบการเปิด เปลี่ยนทุกครั้งที่ restart หรือสลับ workspace เพื่อกันคำขอที่ถือ context เก่า" aria-label="คำอธิบาย: epoch">?</button></dt><dd><code id="ws-epoch">…</code></dd>
109
+ <dt>Changeset ที่ต้องกู้คืนด้วยมือ</dt><dd id="ws-recovery">…</dd>
110
+ </dl>
111
+ </details>
112
+ </div>
113
+ <div class="card-state error-state" id="ws-error" hidden></div>
114
+ </section>
115
+
116
+ <section class="card" id="card-projects" aria-labelledby="h-projects">
117
+ <div class="card-head">
118
+ <h2 id="h-projects">Project Registry</h2>
119
+ <span class="badge" id="projects-count" hidden></span>
120
+ </div>
121
+ <div class="card-state" id="projects-loading">กำลังโหลด…</div>
122
+ <div class="card-body" id="projects-body" hidden>
123
+ <div id="projects-list" class="clients" aria-live="polite"></div>
124
+ <div class="empty" id="projects-empty" hidden>
125
+ <p><b>ยังไม่มีโปรเจกต์ใน registry</b></p>
126
+ <p>เพิ่ม absolute path ด้านล่างเพื่อเริ่มต้น</p>
127
+ </div>
128
+ <form id="project-add-form" class="form" novalidate>
129
+ <label for="project-add-path">เพิ่มโปรเจกต์ด้วย absolute path</label>
130
+ <input id="project-add-path" name="path" type="text" autocomplete="off" spellcheck="false" placeholder="/Users/you/projects/app" aria-describedby="project-add-help project-add-error" required>
131
+ <label for="project-add-name">ชื่อที่แสดง <span class="muted">(ไม่บังคับ)</span></label>
132
+ <div class="input-row">
133
+ <input id="project-add-name" name="displayName" type="text" autocomplete="off" maxlength="120" placeholder="Web application">
134
+ <button type="submit" class="btn primary" id="project-add">เพิ่มโปรเจกต์</button>
135
+ </div>
136
+ <label class="check"><input type="checkbox" id="project-add-open" checked><span>เปิดโปรเจกต์นี้ทันทีหลังเพิ่ม</span></label>
137
+ <p class="help" id="project-add-help">ห้ามใช้ home, filesystem root หรือ path ที่ไม่มีอยู่จริง</p>
138
+ <p class="error" id="project-add-error" role="alert" hidden></p>
139
+ </form>
140
+ <details class="details">
141
+ <summary>การเพิ่ม/นำออกมีผลอย่างไร</summary>
142
+ <p class="help">DODO บันทึก canonical realpath และ directory identity ของโปรเจกต์ การเพิ่มหรือนำรายการออกไม่เปลี่ยน trust, OAuth หรือสิทธิ์ client และไม่ลบไฟล์ใด ๆ</p>
143
+ </details>
144
+ </div>
145
+ <div class="card-state error-state" id="projects-error" hidden></div>
146
+ </section>
147
+
148
+ <p class="callout info" id="personal-note" hidden><span aria-hidden="true">ℹ</span><span>โหมดส่วนตัว: โปรเจกต์ที่เพิ่มแล้วพร้อมใช้ทันที ไม่ต้องตั้ง Client ACL หรือ Trust ต่อโปรเจกต์ <button type="button" class="help-tip" data-tip="ในโหมดส่วนตัว OAuth client ที่คุณอนุมัติใช้ได้ทุกโปรเจกต์ตาม scopes ของ token ส่วน sandbox, path/secret guards และ expected hash ยังทำงานครบ เปลี่ยนเป็นโหมดแยกสิทธิ์ได้ที่หน้า Settings" aria-label="คำอธิบาย: โหมดส่วนตัว">?</button></span></p>
149
+
150
+ <section class="card" id="card-perm" aria-labelledby="h-perm">
151
+ <div class="card-head">
152
+ <h2 id="h-perm">Trust ของโปรเจกต์นี้ <button type="button" class="help-tip" data-tip="ระดับสิทธิ์ที่บันทึกไว้ต่อโปรเจกต์ ส่วน 'สิทธิ์ที่มีผล' คือค่าที่ใช้จริงในรอบนี้ ซึ่งอาจต่างกันเมื่อรันด้วย override flag" aria-label="คำอธิบาย: trust และ effective trust">?</button></h2>
153
+ <span class="badge" id="perm-effective-badge" hidden></span>
154
+ </div>
155
+ <div class="card-state" id="perm-loading">กำลังโหลด…</div>
156
+ <div class="card-body" id="perm-body" hidden>
157
+ <div class="two-col">
158
+ <div class="stat">
159
+ <div class="stat-label">ค่าที่บันทึก</div>
160
+ <div class="stat-value" id="perm-saved">…</div>
161
+ </div>
162
+ <div class="stat">
163
+ <div class="stat-label">สิทธิ์ที่มีผลรอบนี้</div>
164
+ <div class="stat-value" id="perm-effective">…</div>
165
+ </div>
166
+ </div>
167
+ <div class="callout warn" id="perm-override" hidden>
168
+ <span aria-hidden="true">⚠</span>
169
+ <div id="perm-override-text"></div>
170
+ </div>
171
+ <form id="perm-form" class="form" novalidate>
172
+ <fieldset class="radios">
173
+ <legend>ระดับสิทธิ์ที่จะบันทึก</legend>
174
+ <label class="radio"><input type="radio" name="mode" value="inspect"><span><b>inspect</b><small>อ่านและค้นหาได้ แก้ไฟล์และรันคำสั่งต้องขออนุมัติทีละครั้ง (<code>dodo approve</code>)</small></span></label>
175
+ <label class="radio"><input type="radio" name="mode" value="edit"><span><b>edit</b><small>อ่านและแก้ไฟล์ได้ทันที รันคำสั่ง commit และ fetch_url ยังต้องขออนุมัติ</small></span></label>
176
+ <label class="radio"><input type="radio" name="mode" value="trusted"><span><b>trusted</b><small>แก้ไฟล์และรันคำสั่งได้ <b>คำสั่งรันด้วยสิทธิ์ OS ของบัญชีคุณ</b> เว้นแต่เปิด command sandbox</small><button type="button" class="help-tip" data-tip="command sandbox คือชั้นจำกัดคำสั่งของ OS (macOS sandbox-exec / Linux bwrap) เมื่อปิดอยู่ คำสั่งใน trusted mode เข้าถึงไฟล์ได้เท่าบัญชีผู้ใช้ของคุณ" aria-label="คำอธิบาย: command sandbox">?</button></span></label>
177
+ </fieldset>
178
+ <div class="actions">
179
+ <button type="submit" class="btn primary" id="perm-save">บันทึกสิทธิ์</button>
180
+ <span class="help" id="perm-help">มีผลกับคำขอถัดไป ไม่ยกเลิกงานที่รันอยู่แล้ว</span>
181
+ </div>
182
+ </form>
183
+ </div>
184
+ <div class="card-state error-state" id="perm-error" hidden></div>
185
+ </section>
186
+
187
+ <section class="card" id="card-clients" aria-labelledby="h-clients">
188
+ <div class="card-head"><h2 id="h-clients">Client access <button type="button" class="help-tip" data-tip="OAuth scopes กำหนดขอบเขตสูงสุดของ token (อ่าน/แก้ไฟล์/รันคำสั่ง) การอนุญาตที่นี่มีผลเฉพาะโฟลเดอร์นี้ และไม่เพิ่ม scope ให้ token ที่ออกไปแล้ว" aria-label="คำอธิบาย: OAuth scopes">?</button></h2><span class="badge" id="clients-count" hidden></span></div>
189
+ <div class="card-state" id="clients-loading">กำลังโหลด…</div>
190
+ <div class="card-body" id="clients-body" hidden>
191
+ <p class="help">โฟลเดอร์: <code id="clients-root" class="path"></code></p>
192
+ <div id="clients-list" class="clients"></div>
193
+ <div class="empty" id="clients-empty" hidden>
194
+ <p><b>ยังไม่มี client ที่อนุญาตในโฟลเดอร์นี้</b></p>
195
+ <p>เลือกเพิ่ม client ด้านล่างเพื่อใช้การเชื่อมต่อเดิมกับโฟลเดอร์นี้</p>
196
+ </div>
197
+ <details class="details client-add" id="clients-add">
198
+ <summary>เพิ่ม client ให้โฟลเดอร์นี้</summary>
199
+ <p class="help">เลือก client ที่ลงทะเบียนไว้แล้ว ตรวจ Client ID หากชื่อซ้ำกัน</p>
200
+ <p id="client-add-status" class="help" role="status" aria-live="polite"></p>
201
+ <button class="btn small" type="button" id="client-add-reload">โหลดรายการใหม่</button>
202
+ <form id="client-add-form" hidden>
203
+ <label for="client-add-select">Client ที่จะเพิ่ม</label>
204
+ <select id="client-add-select" required disabled><option value="">เลือก client</option></select>
205
+ <fieldset class="checks">
206
+ <legend>สิทธิ์ในโฟลเดอร์นี้</legend>
207
+ <label class="check"><input type="checkbox" name="scope" value="dodo:read" checked><span>อ่านและค้นหา</span></label>
208
+ <label class="check"><input type="checkbox" name="scope" value="dodo:write"><span>แก้ไฟล์</span></label>
209
+ <label class="check"><input type="checkbox" name="scope" value="dodo:exec"><span>รันคำสั่งตาม trust mode</span></label>
210
+ </fieldset>
211
+ <button type="submit" class="btn primary" id="client-add-save">เพิ่มและบันทึกสิทธิ์</button>
212
+ </form>
213
+ <details class="help">
214
+ <summary>ยังไม่เคยลงทะเบียน client</summary>
215
+ <p>ใช้ callback จริงจากแอป แล้วโหลดรายการใหม่:</p>
216
+ <pre><code>dodo auth add-client --name "ChatGPT" --redirect-uri "&lt;callback URL จาก client&gt;"</code></pre>
217
+ </details>
218
+ </details>
219
+ <details class="details client-add" id="clients-manage">
220
+ <summary>ล้าง client ที่ไม่ใช้</summary>
221
+ <p class="help">แสดงทะเบียน client ของทั้งเครื่อง การลบจะถอนล็อกอินและสิทธิ์ในทุกโฟลเดอร์</p>
222
+ <p id="client-manage-status" class="help" role="status" aria-live="polite"></p>
223
+ <button class="btn small" type="button" id="client-manage-reload">โหลดทะเบียนใหม่</button>
224
+ <label class="check"><input type="checkbox" id="client-manage-all" disabled><span>เลือกทั้งหมดในรายการนี้</span></label>
225
+ <div id="client-manage-list" class="clients"></div>
226
+ <button type="button" id="client-manage-delete" class="btn danger-outline" disabled>ล้าง client ที่เลือก</button>
227
+ <p class="help">ไม่ลบไฟล์โปรเจกต์ งานที่เริ่มไปแล้วอาจทำต่อได้ หากต้องการถอนเฉพาะโฟลเดอร์นี้ ให้ใช้ “ถอนสิทธิ์ทั้งหมด” บนการ์ดแทน</p>
228
+ </details>
229
+ </div>
230
+ <div class="card-state error-state" id="clients-error" hidden></div>
231
+ </section>
232
+
233
+ </div>
234
+
235
+ <!-- ============ Approvals page ============ -->
236
+ <div class="grid page" id="page-admin" hidden>
237
+ <section class="card" aria-labelledby="h-schedules">
238
+ <div class="card-head"><h2 id="h-schedules">Scheduled commands <button type="button" class="help-tip" data-tip="เจ้าของต้องอนุมัติคำสั่งและเวลาเฉพาะงาน ทำงานเฉพาะเมื่อ DODO แบบ HTTP เปิดโปรเจกต์นี้อยู่ และไม่รันรอบที่พลาดย้อนหลัง" aria-label="คำอธิบาย: scheduled commands">?</button></h2></div>
239
+ <p class="muted">สร้างรายการด้วย <code>dodo schedule create</code> หรือให้ AI เสนอผ่าน <code>schedule_propose</code></p>
240
+ <div id="schedules-list" class="clients"></div>
241
+ </section>
242
+ </div>
243
+
244
+ <!-- ============ Settings page ============ -->
245
+ <div class="grid page" id="page-settings" hidden>
246
+
247
+ <section class="card" id="card-conn" aria-labelledby="h-conn">
248
+ <div class="card-head"><h2 id="h-conn">Connection</h2></div>
249
+ <div class="card-state" id="conn-loading">กำลังโหลด…</div>
250
+ <div class="card-body" id="conn-body" hidden>
251
+ <div class="kv">
252
+ <div class="k">Local MCP URL</div>
253
+ <div class="v path-row"><code id="conn-local" class="path">…</code><button type="button" class="btn small" id="conn-local-copy" aria-label="คัดลอก Local MCP URL">คัดลอก</button></div>
254
+ <div class="k">Public MCP URL <button type="button" class="help-tip" data-tip="URL ที่ AI ฝั่งเว็บใช้เชื่อมต่อผ่าน tunnel ของคุณ ต้องเป็น HTTPS origin ที่ชี้มาที่พอร์ต MCP เท่านั้น ห้ามชี้มาที่หน้า Local Config" aria-label="คำอธิบาย: public URL">?</button></div>
255
+ <div class="v path-row"><code id="conn-public" class="path">…</code><button type="button" class="btn small" id="conn-public-copy" aria-label="คัดลอก Public MCP URL">คัดลอก</button></div>
256
+ <div class="k">Local Config</div>
257
+ <div class="v path-row"><code id="conn-config" class="path">…</code><span class="muted small-text">(ไม่รวม token)</span></div>
258
+ <div class="k">OAuth</div>
259
+ <div class="v" id="conn-oauth">…</div>
260
+ </div>
261
+ <form id="conn-form" class="form" novalidate>
262
+ <label for="conn-origin">Public origin (HTTPS ของ tunnel)</label>
263
+ <div class="input-row">
264
+ <input id="conn-origin" name="publicUrl" type="url" autocomplete="off" spellcheck="false" placeholder="https://dodo.example.com" aria-describedby="conn-origin-help conn-origin-error">
265
+ <button type="submit" class="btn primary" id="conn-save">บันทึก origin</button>
266
+ </div>
267
+ <p class="help" id="conn-origin-help">ต้องเป็น <code>https://</code> ไม่มี path มีผลหลัง restart DODO</p>
268
+ <p class="error" id="conn-origin-error" role="alert" hidden></p>
269
+ <p class="callout info" id="conn-restart" hidden><span aria-hidden="true">ℹ</span><span>ค่าที่บันทึกต่างจากค่าที่รันอยู่ ต้อง restart DODO เพื่อให้มีผล</span></p>
270
+ </form>
271
+ <details class="details">
272
+ <summary>หน้านี้รู้อะไรบ้าง</summary>
273
+ <p class="help">แสดงเฉพาะสถานะ MCP/config ที่ process นี้รู้จริง ไม่สรุปว่า tunnel หรือ AI client เชื่อมต่อแล้ว ตรวจ tunnel แยกด้วย <code>dodo tunnel doctor</code></p>
274
+ </details>
275
+ </div>
276
+ <div class="card-state error-state" id="conn-error" hidden></div>
277
+ </section>
278
+
279
+ <section class="card" id="card-tunnel" aria-labelledby="h-tunnel">
280
+ <div class="card-head"><h2 id="h-tunnel">Cloudflare Tunnel <button type="button" class="help-tip" data-tip="สถานะนี้มาจาก process ของ DODO เอง token ใช้เฉพาะรอบที่เปิดและไม่ถูกบันทึกลงเครื่อง ช่องกรอกจะถูกล้างหลังส่งเสมอ" aria-label="คำอธิบาย: tunnel status และ token">?</button></h2><span class="badge" id="tunnel-badge">กำลังตรวจ…</span></div>
281
+ <form id="tunnel-session-form" class="form" novalidate>
282
+ <label for="tunnel-session-token">Temporary Tunnel token</label>
283
+ <input id="tunnel-session-token" name="token" type="password" autocomplete="off" spellcheck="false" maxlength="8192" placeholder="ใช้กับ DODO process นี้เท่านั้น" aria-describedby="tunnel-session-help tunnel-session-error">
284
+ <p class="help" id="tunnel-session-help">เริ่มทันที ไม่บันทึกลงเครื่อง และ tunnel หยุดพร้อม DODO</p>
285
+ <p class="error" id="tunnel-session-error" role="alert" hidden></p>
286
+ <div class="actions">
287
+ <button type="submit" class="btn primary" id="tunnel-session-start">เปิด Tunnel รอบนี้</button>
288
+ <button type="button" class="btn danger-outline" id="tunnel-session-stop">หยุด Tunnel รอบนี้</button>
289
+ </div>
290
+ </form>
291
+ <details class="details">
292
+ <summary>การเริ่มอัตโนมัติและค่าขั้นสูง</summary>
293
+ <form id="tunnel-form" class="form" novalidate>
294
+ <label class="check"><input id="tunnel-auto" name="startWithDodo" type="checkbox"><span><b>ถาม token และเปิด Tunnel พร้อม DODO</b><small>มีผลเมื่อเริ่มรอบถัดไป กด Enter โดยไม่กรอก token เพื่อเปิดเฉพาะ local MCP ได้</small></span></label>
295
+ <p class="help" id="tunnel-help">สำหรับรอบที่ไม่ต้องการ Tunnel ใช้ <code>dodo start --no-tunnel</code> Token ไม่ถูกส่งมาหรือแสดงบนหน้าเว็บนี้</p>
296
+ <div class="two-col">
297
+ <label>Metrics port<input id="tunnel-metrics" type="number" min="1024" max="65535" inputmode="numeric"></label>
298
+ <label>จำนวน restart สูงสุด<input id="tunnel-restarts" type="number" min="0" max="5" inputmode="numeric"></label>
299
+ </div>
300
+ <p class="error" id="tunnel-error" role="alert" hidden></p>
301
+ <div class="actions">
302
+ <button type="submit" class="btn primary" id="tunnel-save">บันทึกการเริ่ม Tunnel</button>
303
+ </div>
304
+ </form>
305
+ </details>
306
+ </section>
307
+
308
+ <section class="card" id="card-desktop" aria-labelledby="h-desktop">
309
+ <div class="card-head"><h2 id="h-desktop">Desktop access <button type="button" class="help-tip" data-tip="สิทธิ์อ่าน/ควบคุมหน้าต่างเป็นระดับ installation เมื่อจำแบบ --persist และผูก workspace เมื่อเป็นแบบชั่วคราว แยกจาก OS permission (Screen Recording / Accessibility) ที่ต้องให้ผ่านหน้าต่างระบบ" aria-label="คำอธิบาย: desktop และ Chrome permission">?</button></h2><span class="badge" id="desktop-mode">off</span></div>
310
+ <div class="card-body">
311
+ <p id="desktop-summary">การอ่านและควบคุมหน้าต่างปิดอยู่</p>
312
+ <div class="desktop-command">
313
+ <div class="actions">
314
+ <b>อนุญาต Chrome และจำสิทธิ์ไว้</b>
315
+ <button type="button" class="btn small" id="desktop-command-copy" aria-label="คัดลอกคำสั่งอนุญาต Chrome แบบจำสิทธิ์">คัดลอกคำสั่ง</button>
316
+ </div>
317
+ <pre><code id="desktop-command">dodo desktop allow --app com.google.Chrome --mode control --persist --yes</code></pre>
318
+ </div>
319
+ <button type="button" class="btn danger" id="desktop-disable" disabled>ปิดและลืมสิทธิ์ Desktop</button>
320
+ <details class="details">
321
+ <summary>วิธีตั้งค่าและข้อจำกัด</summary>
322
+ <p class="help">รันคำสั่งด้านบนใน Terminal ที่ path ใดก็ได้ ครั้งเดียวใช้ได้ทุกโปรเจกต์ หากต้องการชั่วคราวเฉพาะ workspace ปัจจุบัน ใช้ <code>--minutes 60</code> แทน <code>--persist</code></p>
323
+ <p class="help">ก่อนใช้งานรัน <code>dodo setup --components desktop</code> ใน local interactive session: macOS ใช้ Screen Recording / Accessibility, Windows ใช้ interactive desktop + UI Automation, Linux รองรับ X11/XWayland ที่มี XTEST/AT-SPI เลือก app ID ด้วย <code>dodo desktop apps</code> (Windows/Linux) หรือ bundle ID บน macOS</p>
324
+ <p class="help">ปุ่ม “ปิดและลืมสิทธิ์” ลบสิทธิ์ที่จำไว้ทั้ง installation และหยุดคำสั่งถัดไป แต่ย้อน OS event ที่ส่งไปแล้วไม่ได้</p>
325
+ </details>
326
+ </div>
327
+ </section>
328
+
329
+ </div>
330
+
331
+ </main>
332
+
333
+ <footer class="foot">
334
+ <span>DODO Local Config · เฉพาะ loopback · token หมดอายุใน <span id="foot-expiry">…</span></span>
335
+ <button type="button" class="btn ghost small" id="refresh">⟳ โหลดใหม่</button>
336
+ </footer>
337
+
338
+ <dialog id="confirm" class="dialog" aria-labelledby="confirm-title">
339
+ <form method="dialog">
340
+ <h3 id="confirm-title">ยืนยัน</h3>
341
+ <p id="confirm-text"></p>
342
+ <div class="actions right">
343
+ <button type="submit" value="cancel" class="btn">ยกเลิก</button>
344
+ <button type="submit" value="ok" class="btn danger" id="confirm-ok">ยืนยัน</button>
345
+ </div>
346
+ </form>
347
+ </dialog>
348
+
349
+ <template id="client-template">
350
+ <article class="client">
351
+ <div class="client-head">
352
+ <div>
353
+ <div class="client-name"></div>
354
+ <code class="client-id"></code>
355
+ </div>
356
+ <span class="badge client-kind"></span>
357
+ </div>
358
+ <fieldset class="checks">
359
+ <legend class="sr-only">สิทธิ์</legend>
360
+ <label class="check"><input type="checkbox" value="dodo:read"><span><b>อ่าน</b><small>อ่านไฟล์ ค้นหา ดูโครงสร้างและ git status</small></span></label>
361
+ <label class="check"><input type="checkbox" value="dodo:write"><span><b>แก้ไฟล์</b><small>สร้าง แก้ ลบ ย้ายไฟล์ และ apply changes ภายใน workspace</small></span></label>
362
+ <label class="check"><input type="checkbox" value="dodo:exec"><span><b>รันคำสั่ง</b><small>run_command, exec_command, git_commit, fetch_url (ตามระดับ trust)</small></span></label>
363
+ </fieldset>
364
+ <div class="actions">
365
+ <button type="button" class="btn primary client-save">บันทึกสิทธิ์</button>
366
+ <button type="button" class="btn danger-outline client-revoke">ถอนสิทธิ์ทั้งหมด</button>
367
+ <span class="client-status help" role="status" aria-live="polite"></span>
368
+ </div>
369
+ </article>
370
+ </template>
371
+
372
+ <script src="/assets/vendor/sweetalert2.min.js"></script>
373
+ <script src="/assets/ui/dom.js"></script>
374
+ <script src="/assets/ui/tooltips.js"></script>
375
+ <script src="/assets/ui/alerts.js"></script>
376
+ <script src="/assets/app.js"></script>
377
+ <script src="/assets/workbench.js"></script>
378
+ </body>
379
+ </html>
@@ -0,0 +1,92 @@
1
+ /* DODO Local Config UI — SweetAlert2 wrappers (vendored, same-origin, no CDN).
2
+ * Safety contract:
3
+ * - ONLY `titleText` and `text` are ever passed to Swal (both render through
4
+ * textContent), so server/path/client/provider/model strings can never
5
+ * become markup. The `html` option is never used.
6
+ * - No secret is ever placed in an alert.
7
+ * - Motion respects prefers-reduced-motion.
8
+ * If the vendored script failed to load, callers fall back to the <dialog>
9
+ * confirm; browser alert()/confirm() are never the primary UI. */
10
+ 'use strict';
11
+ (() => {
12
+ const DodoUI = (window.DodoUI = window.DodoUI || {});
13
+ const swal = () => window.Sweetalert2 || window.Swal;
14
+
15
+ const motion = () =>
16
+ DodoUI.reducedMotion()
17
+ ? { showClass: { popup: '', backdrop: '' }, hideClass: { popup: '', backdrop: '' } }
18
+ : {};
19
+
20
+ const base = () => ({ heightAuto: false, buttonsStyling: false, ...motion(),
21
+ customClass: { confirmButton: 'btn primary', cancelButton: 'btn', denyButton: 'btn danger' } });
22
+
23
+ DodoUI.alerts = {
24
+ available: () => Boolean(swal()),
25
+
26
+ /** Yes/no confirmation. Danger style focuses Cancel and paints Confirm red. */
27
+ async confirm({ title, text, confirmText = 'ยืนยัน', cancelText = 'ยกเลิก', danger = false, icon }) {
28
+ const S = swal();
29
+ if (!S) return null; // caller falls back to the legacy <dialog>
30
+ const result = await S.fire({
31
+ ...base(),
32
+ titleText: title,
33
+ text,
34
+ icon: icon ?? (danger ? 'warning' : 'question'),
35
+ showCancelButton: true,
36
+ confirmButtonText: confirmText,
37
+ cancelButtonText: cancelText,
38
+ focusCancel: danger,
39
+ reverseButtons: true,
40
+ ...(danger ? { customClass: { confirmButton: 'btn danger', cancelButton: 'btn' } } : {}),
41
+ });
42
+ return result.isConfirmed === true;
43
+ },
44
+
45
+ /** Confirmation for actions that can cost money or whose outcome is uncertain. */
46
+ async confirmCost({ title, text, confirmText = 'ยืนยันและยอมรับค่าใช้จ่าย' }) {
47
+ return this.confirm({ title, text, confirmText, danger: true, icon: 'warning' });
48
+ },
49
+
50
+ /** Short toast for backend-confirmed outcomes. Errors stay until dismissed. */
51
+ toast(kind, text) {
52
+ const S = swal();
53
+ if (!S) return false;
54
+ void S.fire({
55
+ ...base(),
56
+ toast: true,
57
+ position: 'top-end',
58
+ icon: kind === 'success' ? 'success' : kind === 'error' ? 'error' : 'info',
59
+ titleText: text,
60
+ showConfirmButton: false,
61
+ timer: kind === 'error' ? undefined : 4000,
62
+ timerProgressBar: kind !== 'error' && !DodoUI.reducedMotion(),
63
+ showCloseButton: kind === 'error',
64
+ });
65
+ return true;
66
+ },
67
+
68
+ /** Blocking error modal for failures the owner must actually read. */
69
+ error({ title, text }) {
70
+ const S = swal();
71
+ if (!S) return false;
72
+ void S.fire({ ...base(), icon: 'error', titleText: title, text, confirmButtonText: 'ปิด' });
73
+ return true;
74
+ },
75
+
76
+ /** Modal spinner for an in-flight save/test. Returns a close() function. */
77
+ loading(title, text) {
78
+ const S = swal();
79
+ if (!S) return () => undefined;
80
+ void S.fire({
81
+ ...base(),
82
+ titleText: title,
83
+ text,
84
+ allowOutsideClick: false,
85
+ allowEscapeKey: false,
86
+ showConfirmButton: false,
87
+ didOpen: () => S.showLoading(),
88
+ });
89
+ return () => { if (S.isVisible() && S.isLoading()) S.close(); };
90
+ },
91
+ };
92
+ })();
@@ -0,0 +1,19 @@
1
+ /* DODO Local Config UI — shared DOM helpers.
2
+ * Everything that renders values from the server goes through textContent /
3
+ * DOM APIs, never HTML strings; these helpers keep that invariant in one place.
4
+ * Loaded before tooltips/alerts/app/workbench. No framework, no CDN. */
5
+ 'use strict';
6
+ (() => {
7
+ const DodoUI = (window.DodoUI = window.DodoUI || {});
8
+
9
+ /** Create an element with optional textContent (never HTML) and className. */
10
+ DodoUI.el = (tag, text, className) => {
11
+ const node = document.createElement(tag);
12
+ if (text !== undefined) node.textContent = text;
13
+ if (className) node.className = className;
14
+ return node;
15
+ };
16
+
17
+ /** True when the viewer asked the OS for less motion; alerts/tooltips honor it. */
18
+ DodoUI.reducedMotion = () => window.matchMedia('(prefers-reduced-motion: reduce)').matches;
19
+ })();
@@ -0,0 +1,115 @@
1
+ /* DODO Local Config UI — accessible tooltip system (WAI-ARIA tooltip pattern).
2
+ * One shared, non-interactive tooltip element:
3
+ * - opens on hover AND keyboard focus AND tap;
4
+ * - closes on Escape, blur, pointer leave, click outside, scroll, resize;
5
+ * - trigger gets aria-describedby while open + aria-expanded state;
6
+ * - repositions/flips near viewport edges and never captures pointer events,
7
+ * so it cannot block the control it describes;
8
+ * - all tip text is set through textContent (server/path/client/provider
9
+ * values can never become markup);
10
+ * - motion is CSS-only and disabled under prefers-reduced-motion.
11
+ * The title attribute is never used as the primary mechanism. */
12
+ 'use strict';
13
+ (() => {
14
+ const DodoUI = (window.DodoUI = window.DodoUI || {});
15
+ const TIP_ID = 'dodo-tooltip';
16
+ const tipText = new WeakMap();
17
+
18
+ let bubble = null;
19
+ let openFor = null;
20
+
21
+ function ensureBubble() {
22
+ if (bubble) return bubble;
23
+ bubble = document.createElement('div');
24
+ bubble.id = TIP_ID;
25
+ bubble.setAttribute('role', 'tooltip');
26
+ bubble.hidden = true;
27
+ document.body.append(bubble);
28
+ return bubble;
29
+ }
30
+
31
+ function place(trigger) {
32
+ const margin = 8;
33
+ const rect = trigger.getBoundingClientRect();
34
+ const tip = ensureBubble();
35
+ // Measure after content is set; fixed positioning, pointer-events: none.
36
+ tip.style.left = '0px';
37
+ tip.style.top = '0px';
38
+ const size = tip.getBoundingClientRect();
39
+ let left = rect.left + rect.width / 2 - size.width / 2;
40
+ left = Math.max(margin, Math.min(left, window.innerWidth - size.width - margin));
41
+ let top = rect.top - size.height - margin; // prefer above
42
+ let position = 'above';
43
+ if (top < margin) { top = rect.bottom + margin; position = 'below'; } // flip near the top edge
44
+ if (top + size.height > window.innerHeight - margin) top = Math.max(margin, window.innerHeight - size.height - margin);
45
+ tip.dataset.position = position;
46
+ tip.style.left = `${Math.round(left)}px`;
47
+ tip.style.top = `${Math.round(top)}px`;
48
+ }
49
+
50
+ function show(trigger) {
51
+ const text = tipText.get(trigger) ?? trigger.dataset.tip ?? '';
52
+ if (!text) return;
53
+ const tip = ensureBubble();
54
+ if (openFor && openFor !== trigger) hide();
55
+ openFor = trigger;
56
+ tip.textContent = text; // never HTML
57
+ tip.hidden = false;
58
+ trigger.setAttribute('aria-describedby', TIP_ID);
59
+ trigger.setAttribute('aria-expanded', 'true');
60
+ place(trigger);
61
+ }
62
+
63
+ function hide() {
64
+ if (!openFor) return;
65
+ openFor.removeAttribute('aria-describedby');
66
+ openFor.setAttribute('aria-expanded', 'false');
67
+ openFor = null;
68
+ if (bubble) bubble.hidden = true;
69
+ }
70
+
71
+ function wire(trigger) {
72
+ if (trigger.dataset.tipWired === '1') return;
73
+ trigger.dataset.tipWired = '1';
74
+ trigger.setAttribute('aria-expanded', 'false');
75
+ trigger.addEventListener('pointerenter', () => show(trigger));
76
+ trigger.addEventListener('pointerleave', () => { if (document.activeElement !== trigger) hide(); });
77
+ trigger.addEventListener('focus', () => show(trigger));
78
+ trigger.addEventListener('blur', hide);
79
+ // Tap (and click) always OPENS: with a mouse, hover has usually opened the
80
+ // tip already, so a toggle would close it on the same gesture. Closing is
81
+ // Escape / outside tap / blur / pointer leave.
82
+ trigger.addEventListener('click', (ev) => {
83
+ ev.preventDefault(); // help buttons never submit forms
84
+ show(trigger);
85
+ });
86
+ }
87
+
88
+ document.addEventListener('keydown', (ev) => { if (ev.key === 'Escape') hide(); });
89
+ document.addEventListener('pointerdown', (ev) => {
90
+ if (openFor && ev.target !== openFor && !openFor.contains(ev.target)) hide();
91
+ });
92
+ window.addEventListener('scroll', hide, true);
93
+ window.addEventListener('resize', hide);
94
+
95
+ DodoUI.tooltips = {
96
+ /** Create a `?` help button whose tooltip text is set via textContent only. */
97
+ helpButton(text, subject) {
98
+ const b = document.createElement('button');
99
+ b.type = 'button';
100
+ b.className = 'help-tip';
101
+ b.textContent = '?';
102
+ b.setAttribute('aria-label', subject ? `คำอธิบาย: ${subject}` : 'คำอธิบายเพิ่มเติม');
103
+ tipText.set(b, String(text));
104
+ wire(b);
105
+ return b;
106
+ },
107
+ /** Wire every element with a static data-tip attribute under root. */
108
+ attach(root = document) {
109
+ for (const node of root.querySelectorAll('[data-tip]')) wire(node);
110
+ },
111
+ hide,
112
+ };
113
+
114
+ DodoUI.tooltips.attach();
115
+ })();
@@ -0,0 +1 @@
1
+ sweetalert2 11.26.25 (MIT) — vendored by scripts/vendor-ui.mjs; do not edit by hand