@wenathlan/devthink 2.0.13 → 2.0.15

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 (444) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/accounts.ts +2087 -0
  3. package/agent.ts +2331 -0
  4. package/antigravity.ts +2139 -0
  5. package/apifreeze.ts +4146 -0
  6. package/auth.ts +642 -0
  7. package/background.ts +16837 -0
  8. package/bridge.ts +2080 -0
  9. package/build.ts +54 -0
  10. package/bun.ts +26 -0
  11. package/capture.ts +1614 -0
  12. package/checksecrets.ts +72 -0
  13. package/cjs.ts +9 -0
  14. package/cli.ts +3500 -0
  15. package/commands.ts +1101 -0
  16. package/companion.ts +450 -0
  17. package/compatibility.ts +37 -0
  18. package/config.ts +3137 -0
  19. package/constants.ts +943 -0
  20. package/core.ts +1473 -0
  21. package/crossbrowser.ts +1359 -0
  22. package/dashdone.ts +605 -0
  23. package/data.ts +943 -0
  24. package/database.ts +133 -0
  25. package/debug.ts +850 -0
  26. package/deno.ts +27 -0
  27. package/devthink.ts +707 -0
  28. package/dist/accounts.d.ts +409 -0
  29. package/dist/agent.d.ts +837 -0
  30. package/dist/antigravity.d.ts +380 -0
  31. package/dist/apifreeze.d.ts +113 -0
  32. package/dist/auth.d.ts +224 -0
  33. package/{bridge.d.ts → dist/bridge.d.ts} +1 -1
  34. package/dist/capture.d.ts +595 -0
  35. package/dist/cjs.d.ts +6 -0
  36. package/{cli.js → dist/cli.js} +2 -2
  37. package/dist/commands.d.ts +310 -0
  38. package/dist/compatibility.d.ts +17 -0
  39. package/dist/config.d.ts +1853 -0
  40. package/dist/constants.d.ts +637 -0
  41. package/dist/core.d.ts +361 -0
  42. package/dist/data.d.ts +330 -0
  43. package/dist/database.d.ts +24 -0
  44. package/dist/debug.d.ts +270 -0
  45. package/dist/engine.d.ts +74 -0
  46. package/dist/environments.d.ts +244 -0
  47. package/dist/evidence.d.ts +277 -0
  48. package/dist/export.d.ts +311 -0
  49. package/dist/fingerprint.d.ts +594 -0
  50. package/dist/flow.d.ts +300 -0
  51. package/dist/gates.d.ts +103 -0
  52. package/dist/identity.d.ts +51 -0
  53. package/dist/ids.d.ts +7 -0
  54. package/dist/llm.d.ts +652 -0
  55. package/dist/models.d.ts +1807 -0
  56. package/dist/net.d.ts +325 -0
  57. package/dist/neutral.d.ts +41 -0
  58. package/dist/oauth.d.ts +703 -0
  59. package/dist/page.d.ts +1166 -0
  60. package/dist/perf.d.ts +481 -0
  61. package/dist/plan.d.ts +134 -0
  62. package/dist/project.d.ts +395 -0
  63. package/dist/providers.d.ts +37 -0
  64. package/dist/quota.d.ts +453 -0
  65. package/dist/recovery.d.ts +621 -0
  66. package/dist/request.d.ts +1492 -0
  67. package/dist/run.d.ts +779 -0
  68. package/dist/runtime.d.ts +212 -0
  69. package/dist/search.d.ts +375 -0
  70. package/dist/security.d.ts +534 -0
  71. package/dist/serve.d.ts +136 -0
  72. package/dist/session.d.ts +296 -0
  73. package/dist/storage.d.ts +53 -0
  74. package/dist/streaming.d.ts +1119 -0
  75. package/dist/swarm.d.ts +328 -0
  76. package/dist/tools.d.ts +170 -0
  77. package/dist/types.d.ts +8357 -0
  78. package/dist/utils.d.ts +82 -0
  79. package/dist/version.d.ts +7 -0
  80. package/dist/versionregistry.d.ts +406 -0
  81. package/dist/views.d.ts +579 -0
  82. package/dist/workbenchsession.d.ts +69 -0
  83. package/dist/workflow.d.ts +649 -0
  84. package/docs/readme.md +92 -0
  85. package/docs/schemas/antigravity.json +192 -0
  86. package/engine.ts +1524 -0
  87. package/environments.ts +1005 -0
  88. package/evidence.ts +643 -0
  89. package/export.ts +889 -0
  90. package/fingerprint.ts +1458 -0
  91. package/flow.ts +1190 -0
  92. package/gates.ts +307 -0
  93. package/gateway.ts +34 -0
  94. package/hardening.ts +191 -0
  95. package/headless.ts +369 -0
  96. package/http.ts +2110 -0
  97. package/identity.ts +246 -0
  98. package/ids.ts +26 -0
  99. package/index.ts +369 -0
  100. package/llm.ts +2682 -0
  101. package/mcp.ts +1835 -0
  102. package/{memory.js → memory.ts} +3834 -2310
  103. package/models.ts +3805 -0
  104. package/modes.ts +43 -0
  105. package/net.ts +1214 -0
  106. package/neutral.ts +362 -0
  107. package/node.ts +26 -0
  108. package/oauth.ts +2216 -0
  109. package/offscreen.ts +170 -0
  110. package/pack.ts +956 -0
  111. package/package.json +175 -82
  112. package/page.ts +7824 -0
  113. package/pagebridge.ts +1116 -0
  114. package/perf.ts +957 -0
  115. package/plan.ts +672 -0
  116. package/plugin.ts +76 -0
  117. package/{policy.js → policy.ts} +5073 -4679
  118. package/prisma.config.ts +27 -0
  119. package/progress.ts +1308 -0
  120. package/project.ts +1291 -0
  121. package/protocol.ts +4187 -0
  122. package/providers.ts +246 -0
  123. package/quota.ts +1887 -0
  124. package/recovery.ts +2433 -0
  125. package/request.ts +4482 -0
  126. package/run.ts +2135 -0
  127. package/runtime.ts +526 -0
  128. package/search.ts +1760 -0
  129. package/security.ts +1673 -0
  130. package/serve.ts +419 -0
  131. package/server.ts +5538 -0
  132. package/session.ts +1162 -0
  133. package/storage.ts +182 -0
  134. package/streaming.ts +4101 -0
  135. package/swarm.ts +884 -0
  136. package/sync.ts +56 -0
  137. package/tests/agentcert.test.ts +128 -0
  138. package/tests/agentfleet.test.ts +214 -0
  139. package/tests/agentreview.test.ts +241 -0
  140. package/tests/agentstream.test.ts +335 -0
  141. package/tests/agentwork.test.ts +356 -0
  142. package/tests/apifreeze.test.ts +290 -0
  143. package/tests/apimap.test.ts +112 -0
  144. package/tests/approvalgate.test.ts +175 -0
  145. package/tests/artifactmanifest.test.ts +204 -0
  146. package/tests/attentionfeed.test.ts +163 -0
  147. package/tests/backgroundruns.test.ts +100 -0
  148. package/tests/batchscheduling.test.ts +131 -0
  149. package/tests/blackboard.test.ts +238 -0
  150. package/tests/bridge.test.ts +1088 -0
  151. package/tests/browsercoverage.test.ts +134 -0
  152. package/tests/browserpolyfills.test.ts +124 -0
  153. package/tests/build.mjs +1260 -0
  154. package/tests/clientauth.test.ts +223 -0
  155. package/tests/clitools.test.ts +578 -0
  156. package/tests/confirmgates.test.ts +190 -0
  157. package/tests/containerpack.test.ts +143 -0
  158. package/tests/controlflow.test.ts +2120 -0
  159. package/tests/coordination.test.ts +345 -0
  160. package/tests/copyscreen.test.ts +139 -0
  161. package/tests/core.test.ts +417 -0
  162. package/tests/costcert.test.ts +95 -0
  163. package/tests/crossbrowser.test.ts +115 -0
  164. package/tests/cspaudit.test.ts +79 -0
  165. package/tests/dashdone.test.ts +615 -0
  166. package/tests/datagrid.test.ts +137 -0
  167. package/tests/doccheck.test.ts +107 -0
  168. package/tests/dombatch.test.ts +109 -0
  169. package/tests/emulation.test.ts +282 -0
  170. package/tests/environments.test.ts +259 -0
  171. package/tests/evidenceviews.test.ts +88 -0
  172. package/tests/exporttools.test.ts +185 -0
  173. package/tests/firefoxprep.test.ts +134 -0
  174. package/tests/flowlibrary.test.ts +242 -0
  175. package/tests/flowrun.test.ts +303 -0
  176. package/tests/forensics.test.ts +439 -0
  177. package/tests/gateway.test.ts +939 -0
  178. package/tests/headlesslib.test.ts +171 -0
  179. package/tests/httpstream.test.ts +277 -0
  180. package/tests/immutablelog.test.ts +157 -0
  181. package/tests/inboundguard.test.ts +177 -0
  182. package/tests/lazyload.test.ts +72 -0
  183. package/tests/librarymodes.test.ts +623 -0
  184. package/tests/llm.test.ts +696 -0
  185. package/tests/manifest.test.ts +226 -0
  186. package/tests/maskinputs.test.ts +150 -0
  187. package/tests/matrixverify.test.ts +111 -0
  188. package/tests/mavenpack.test.ts +75 -0
  189. package/tests/mcpserver.test.ts +704 -0
  190. package/tests/memory.test.ts +4155 -0
  191. package/tests/memorycare.test.ts +230 -0
  192. package/tests/migrateplan.test.ts +349 -0
  193. package/tests/minimization.test.ts +414 -0
  194. package/tests/modelroute.test.ts +112 -0
  195. package/tests/multiagent.test.ts +440 -0
  196. package/tests/nativebridge.test.ts +807 -0
  197. package/tests/navigation.test.ts +284 -0
  198. package/tests/nugetpack.test.ts +83 -0
  199. package/tests/orchestration.test.ts +449 -0
  200. package/tests/originpolicy.test.ts +405 -0
  201. package/tests/outputcompare.test.ts +97 -0
  202. package/tests/package.test.ts +91 -0
  203. package/tests/pagebridge.test.ts +5909 -0
  204. package/tests/pentest.test.ts +75 -0
  205. package/tests/perfrecords.test.ts +257 -0
  206. package/tests/permdiff.test.ts +85 -0
  207. package/tests/phishguard.test.ts +128 -0
  208. package/tests/pickerviews.test.ts +155 -0
  209. package/tests/pipelines.test.ts +381 -0
  210. package/tests/planlint.test.ts +240 -0
  211. package/tests/planreview.test.ts +383 -0
  212. package/tests/platformtargets.test.ts +56 -0
  213. package/tests/policy.test.ts +8284 -0
  214. package/tests/portability.test.ts +96 -0
  215. package/tests/progress.test.ts +1036 -0
  216. package/tests/promptlibrary.test.ts +116 -0
  217. package/tests/protocol.test.ts +4793 -0
  218. package/tests/publishingpipeline.test.ts +314 -0
  219. package/tests/quickactions.test.ts +164 -0
  220. package/tests/readiness.test.ts +78 -0
  221. package/tests/recipes.test.ts +163 -0
  222. package/tests/redactshots.test.ts +216 -0
  223. package/tests/registernvidiakeys.ts +51 -0
  224. package/tests/relayserve.test.ts +304 -0
  225. package/tests/releasenotes.test.ts +276 -0
  226. package/tests/resilience.test.ts +467 -0
  227. package/tests/resourceaware.test.ts +187 -0
  228. package/tests/runbudget.test.ts +125 -0
  229. package/tests/runhistory.test.ts +299 -0
  230. package/tests/runreplay.test.ts +113 -0
  231. package/tests/runresume.test.ts +184 -0
  232. package/tests/runstate.test.ts +288 -0
  233. package/tests/runtimeadapters.test.ts +251 -0
  234. package/tests/safariskeleton.test.ts +115 -0
  235. package/tests/sandboxframe.test.ts +196 -0
  236. package/tests/sbom.test.ts +105 -0
  237. package/tests/secretvault.test.ts +188 -0
  238. package/tests/selcache.test.ts +111 -0
  239. package/tests/sessioninterface.test.ts +791 -0
  240. package/tests/sessions.test.ts +591 -0
  241. package/tests/siteprefs.test.ts +228 -0
  242. package/tests/snapshotdelta.test.ts +165 -0
  243. package/tests/statusviews.test.ts +237 -0
  244. package/tests/stepmeter.test.ts +200 -0
  245. package/tests/streamparse.test.ts +163 -0
  246. package/tests/stylepruning.test.ts +90 -0
  247. package/tests/surfaces.test.ts +282 -0
  248. package/tests/sweep.test.ts +78 -0
  249. package/tests/syncbridge.test.ts +164 -0
  250. package/tests/taskqueue.test.ts +206 -0
  251. package/tests/toolcalls.test.ts +336 -0
  252. package/tests/toolcatalog.test.ts +201 -0
  253. package/tests/torture-agent.test.ts +706 -0
  254. package/tests/torture-auth.test.ts +461 -0
  255. package/tests/torture-commands.test.ts +895 -0
  256. package/tests/torture-data.test.ts +923 -0
  257. package/tests/torture-environments.test.ts +285 -0
  258. package/tests/torture-export.test.ts +263 -0
  259. package/tests/torture-http.test.ts +1379 -0
  260. package/tests/torture-llm.test.ts +808 -0
  261. package/tests/torture-memory.test.ts +1084 -0
  262. package/tests/torture-plan.test.ts +829 -0
  263. package/tests/torture-run.test.ts +626 -0
  264. package/tests/torture-session.test.ts +928 -0
  265. package/tests/torture-swarm.test.ts +1245 -0
  266. package/tests/torture-tools.test.ts +964 -0
  267. package/tests/torture-workflow.test.ts +2354 -0
  268. package/tests/tourviews.test.ts +52 -0
  269. package/tests/transparency.test.ts +147 -0
  270. package/tests/trigger.test.ts +941 -0
  271. package/tests/v1sunset.test.ts +428 -0
  272. package/tests/virtlist.test.ts +94 -0
  273. package/tests/vision.test.ts +540 -0
  274. package/tests/vsixpack.test.ts +145 -0
  275. package/tests/webapi.test.ts +523 -0
  276. package/tests/workflow.test.ts +1785 -0
  277. package/tests/workfloweditor.test.ts +759 -0
  278. package/tests/xpipack.test.ts +128 -0
  279. package/tools.ts +734 -0
  280. package/types.ts +9908 -0
  281. package/umd.ts +9 -0
  282. package/utils.ts +249 -0
  283. package/version.ts +8 -0
  284. package/versionregistry.ts +1310 -0
  285. package/views.ts +2153 -0
  286. package/vitest.config.ts +12 -0
  287. package/web/App.tsx +78 -0
  288. package/web/README.md +47 -0
  289. package/web/capacitor.config.ts +46 -0
  290. package/web/const.ts +19 -0
  291. package/web/control.shell.tsx +66 -0
  292. package/web/dashboardpage.ts +554 -0
  293. package/web/db.ts +493 -0
  294. package/web/design.html +541 -0
  295. package/web/gatewayview/Gateway.tsx +345 -0
  296. package/web/gatewayview/config.ts +1042 -0
  297. package/web/gatewayview/definition.ts +174 -0
  298. package/web/icons.ts +15 -0
  299. package/{manifest.json → web/manifest.json} +1 -1
  300. package/web/optionspage.ts +691 -0
  301. package/web/popup.ts +1651 -0
  302. package/web/schema.prisma +176 -0
  303. package/web/sidepanel.ts +7941 -0
  304. package/web/sitemanifest.json +13 -0
  305. package/web/terminal-ui.tsx +622 -0
  306. package/web/transparencypage.ts +541 -0
  307. package/web/vite.config.ts +39 -0
  308. package/web/workspace.ts +23 -0
  309. package/workbenchmemory.ts +104 -0
  310. package/workbenchsession.ts +304 -0
  311. package/workflow.ts +4495 -0
  312. package/bridge.d.ts.map +0 -1
  313. package/bridge.js +0 -1877
  314. package/bun.d.ts.map +0 -1
  315. package/bun.js +0 -52329
  316. package/caps/background.json +0 -712
  317. package/caps/cli.json +0 -360
  318. package/caps/library.json +0 -3611
  319. package/caps/mcp.json +0 -126
  320. package/caps/pagebridge.json +0 -377
  321. package/caps/popup.json +0 -51
  322. package/caps/sidepanel.json +0 -522
  323. package/checksums.txt +0 -142
  324. package/cli.d.ts.map +0 -1
  325. package/companion.d.ts.map +0 -1
  326. package/companion.js +0 -389
  327. package/crossbrowser.d.ts.map +0 -1
  328. package/crossbrowser.js +0 -1191
  329. package/dashdone.d.ts.map +0 -1
  330. package/dashdone.js +0 -368
  331. package/deno.d.ts.map +0 -1
  332. package/deno.js +0 -52325
  333. package/devthink.umd.js +0 -52346
  334. package/fixtures/bun.ts +0 -7
  335. package/fixtures/cjs.js +0 -6
  336. package/fixtures/deno.ts +0 -6
  337. package/fixtures/example-org-pagestate.json +0 -22
  338. package/fixtures/importers/automa-workflow.json +0 -18
  339. package/fixtures/importers/selenium-side.json +0 -20
  340. package/fixtures/importers/tabular-plan.csv +0 -7
  341. package/fixtures/importers/uivision-macro.json +0 -10
  342. package/fixtures/importers/v1-plan.json +0 -13
  343. package/fixtures/mcp-client.mjs +0 -14
  344. package/fixtures/pages/checkout.html +0 -192
  345. package/fixtures/pages/dashboard.html +0 -110
  346. package/fixtures/pages/feed.html +0 -113
  347. package/fixtures/pages/product-grid.html +0 -150
  348. package/fixtures/plans/form-inventory-plan.json +0 -11
  349. package/fixtures/plans/release-notes-plan.json +0 -11
  350. package/fixtures/recipes/agentscompete.json +0 -11
  351. package/fixtures/recipes/agentsforms.json +0 -11
  352. package/fixtures/recipes/agentsmonitor.json +0 -11
  353. package/fixtures/recipes/agentsreview.json +0 -29
  354. package/fixtures/recipes/agentswarm.json +0 -11
  355. package/fixtures/recipes/fillcalendar.json +0 -12
  356. package/fixtures/recipes/fillcheckout.json +0 -13
  357. package/fixtures/recipes/filldependentdropdowns.json +0 -12
  358. package/fixtures/recipes/fillfromcsv.json +0 -13
  359. package/fixtures/recipes/fillloginform.json +0 -12
  360. package/fixtures/recipes/fillmultistepwizard.json +0 -13
  361. package/fixtures/recipes/fillregistration.json +0 -12
  362. package/fixtures/recipes/fillsearchfilters.json +0 -12
  363. package/fixtures/recipes/filltypeahead.json +0 -11
  364. package/fixtures/recipes/monitoralerts.json +0 -12
  365. package/fixtures/recipes/monitoravailability.json +0 -11
  366. package/fixtures/recipes/monitornetworkquiet.json +0 -12
  367. package/fixtures/recipes/monitorpagechanges.json +0 -11
  368. package/fixtures/recipes/monitorpricechange.json +0 -11
  369. package/fixtures/recipes/monitorschedule.json +0 -12
  370. package/fixtures/recipes/scrapedynamicprices.json +0 -13
  371. package/fixtures/recipes/scrapeimagegallery.json +0 -12
  372. package/fixtures/recipes/scrapeinfinitefeed.json +0 -13
  373. package/fixtures/recipes/scrapenestedlists.json +0 -12
  374. package/fixtures/recipes/scrapeproductgrid.json +0 -12
  375. package/fixtures/recipes/scrapereviews.json +0 -12
  376. package/fixtures/recipes/scrapesearchresults.json +0 -12
  377. package/fixtures/recipes/scrapetablepagination.json +0 -12
  378. package/fixtures/recipes/testaccessibility.json +0 -34
  379. package/fixtures/recipes/testconsoleerrors.json +0 -12
  380. package/fixtures/recipes/testdeeplinks.json +0 -12
  381. package/fixtures/recipes/testformvalidation.json +0 -13
  382. package/fixtures/recipes/testlayoutshift.json +0 -12
  383. package/fixtures/recipes/testlinkcheck.json +0 -12
  384. package/fixtures/recipes/testloadtiming.json +0 -12
  385. package/fixtures/recipes/testvisualdiff.json +0 -12
  386. package/fixtures/workflows/changelog-digest-workflow.json +0 -13
  387. package/fixtures/workflows/form-survey-workflow.json +0 -13
  388. package/gallery.json +0 -706
  389. package/hardening.d.ts.map +0 -1
  390. package/hardening.js +0 -188
  391. package/headless.d.ts.map +0 -1
  392. package/headless.js +0 -11522
  393. package/http.d.ts.map +0 -1
  394. package/http.js +0 -2165
  395. package/index.cjs +0 -54682
  396. package/index.d.ts.map +0 -1
  397. package/index.js +0 -52310
  398. package/index.neutral.js +0 -46343
  399. package/mcp.d.ts.map +0 -1
  400. package/mcp.js +0 -20515
  401. package/memory.d.ts.map +0 -1
  402. package/nativehost.template.json +0 -10
  403. package/node.cjs +0 -54686
  404. package/node.d.ts.map +0 -1
  405. package/pack.d.ts.map +0 -1
  406. package/pack.js +0 -805
  407. package/policy.d.ts.map +0 -1
  408. package/progress.d.ts.map +0 -1
  409. package/progress.js +0 -645
  410. package/protocol.d.ts.map +0 -1
  411. package/protocol.js +0 -8334
  412. package/schemas/audit.schema.json +0 -226
  413. package/schemas/capability.schema.json +0 -113
  414. package/schemas/envelope.schema.json +0 -162
  415. package/schemas/memory.schema.json +0 -51
  416. package/schemas/observation.schema.json +0 -113
  417. package/schemas/plan.schema.json +0 -208
  418. package/schemas/progress.schema.json +0 -126
  419. package/schemas/proposal.schema.json +0 -68
  420. package/schemas/session.schema.json +0 -82
  421. package/schemas/tool.schema.json +0 -94
  422. package/server.d.ts.map +0 -1
  423. package/server.js +0 -28877
  424. package/umd-example.html +0 -18
  425. package/umd.d.ts.map +0 -1
  426. /package/{bun.d.ts → dist/bun.d.ts} +0 -0
  427. /package/{cli.d.ts → dist/cli.d.ts} +0 -0
  428. /package/{companion.d.ts → dist/companion.d.ts} +0 -0
  429. /package/{crossbrowser.d.ts → dist/crossbrowser.d.ts} +0 -0
  430. /package/{dashdone.d.ts → dist/dashdone.d.ts} +0 -0
  431. /package/{deno.d.ts → dist/deno.d.ts} +0 -0
  432. /package/{hardening.d.ts → dist/hardening.d.ts} +0 -0
  433. /package/{headless.d.ts → dist/headless.d.ts} +0 -0
  434. /package/{http.d.ts → dist/http.d.ts} +0 -0
  435. /package/{index.d.ts → dist/index.d.ts} +0 -0
  436. /package/{mcp.d.ts → dist/mcp.d.ts} +0 -0
  437. /package/{memory.d.ts → dist/memory.d.ts} +0 -0
  438. /package/{node.d.ts → dist/node.d.ts} +0 -0
  439. /package/{pack.d.ts → dist/pack.d.ts} +0 -0
  440. /package/{policy.d.ts → dist/policy.d.ts} +0 -0
  441. /package/{progress.d.ts → dist/progress.d.ts} +0 -0
  442. /package/{protocol.d.ts → dist/protocol.d.ts} +0 -0
  443. /package/{server.d.ts → dist/server.d.ts} +0 -0
  444. /package/{umd.d.ts → dist/umd.d.ts} +0 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * workbenchmemory.ts — the devthink workbench memory store (the 1.1.16
3
+ * surface of the grand merge; split from the extension memory domain on the
4
+ * platform boundary: the extension memory stays browser-pure, this node
5
+ * surface keeps the filesystem-backed layered store of the workbench CLI).
6
+ */
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import type { DevThinkPaths } from "./config.ts";
10
+
11
+ export type MemoryLayer = "session" | "project" | "global";
12
+
13
+ export type MemoryEntry = {
14
+ id: string;
15
+ layer: MemoryLayer;
16
+ key: string;
17
+ content: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ };
21
+
22
+ export type MemoryQuery = {
23
+ key?: string;
24
+ text?: string;
25
+ sessionId?: string;
26
+ };
27
+
28
+ function memoryFile(paths: DevThinkPaths, layer: MemoryLayer, sessionId?: string): string {
29
+ if (layer === "session") return join(paths.sessions, `${sessionId || "active"}.memory.json`);
30
+ if (layer === "project") return join(process.cwd(), ".devthink", "project-memory.json");
31
+ return join(paths.memory, "global-memory.json");
32
+ }
33
+
34
+ function readEntries(path: string, layer: MemoryLayer): MemoryEntry[] {
35
+ try {
36
+ if (!existsSync(path)) return [];
37
+ const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
38
+ return Array.isArray(parsed) ? (parsed as MemoryEntry[]).filter((entry) => entry.layer === layer) : [];
39
+ } catch {
40
+ return [];
41
+ }
42
+ }
43
+
44
+ function writeEntries(path: string, entries: MemoryEntry[]): void {
45
+ mkdirSync(join(path, ".."), { recursive: true });
46
+ writeFileSync(path, `${JSON.stringify(entries, null, 2)}\n`, "utf8");
47
+ }
48
+
49
+ function normalize(value: string): string {
50
+ return value.trim().toLowerCase();
51
+ }
52
+
53
+ function scoreEntry(entry: MemoryEntry, query: MemoryQuery): number {
54
+ const key = normalize(query.key || "");
55
+ const text = normalize(query.text || "");
56
+ let score = 0;
57
+ if (key && normalize(entry.key) === key) score += 10;
58
+ if (text && normalize(entry.content).includes(text)) score += 5;
59
+ if (!key && !text) score = 1;
60
+ return score;
61
+ }
62
+
63
+ export function createMemoryStore(paths: DevThinkPaths) {
64
+ return {
65
+ remember(entry: Omit<MemoryEntry, "id" | "createdAt" | "updatedAt">): MemoryEntry {
66
+ const now = new Date().toISOString();
67
+ const path = memoryFile(paths, entry.layer, entry.layer === "session" ? entry.key : undefined);
68
+ const entries = readEntries(path, entry.layer);
69
+ const current = entries.find((item) => item.key === entry.key);
70
+ const next: MemoryEntry = {
71
+ id: current?.id || crypto.randomUUID(),
72
+ ...entry,
73
+ createdAt: current?.createdAt || now,
74
+ updatedAt: now,
75
+ };
76
+ writeEntries(path, [...entries.filter((item) => item.id !== next.id), next]);
77
+ return next;
78
+ },
79
+ resolve(query: MemoryQuery): MemoryEntry | undefined {
80
+ const layers: MemoryLayer[] = ["session", "project", "global"];
81
+ for (const layer of layers) {
82
+ const entries = readEntries(memoryFile(paths, layer, query.sessionId), layer);
83
+ const match = entries
84
+ .map((entry) => ({ entry, score: scoreEntry(entry, query) }))
85
+ .filter((item) => item.score > 0)
86
+ .sort((a, b) => b.score - a.score)[0];
87
+ if (match) return match.entry;
88
+ }
89
+ return undefined;
90
+ },
91
+ list(layer?: MemoryLayer, sessionId?: string): MemoryEntry[] {
92
+ const layers: MemoryLayer[] = layer ? [layer] : ["session", "project", "global"];
93
+ return layers.flatMap((item) => readEntries(memoryFile(paths, item, sessionId), item));
94
+ },
95
+ };
96
+ }
97
+
98
+ export type MemoryStore = ReturnType<typeof createMemoryStore>;
99
+
100
+ export function memorySummary(store: MemoryStore): string {
101
+ const entries = store.list();
102
+ if (!entries.length) return "No local memory entries.";
103
+ return entries.map((entry) => `${entry.layer}:${entry.key} — ${entry.content}`).join("\n");
104
+ }
@@ -0,0 +1,304 @@
1
+ /**
2
+ * workbenchsession.ts — the devthink workbench chat sessions (the 1.1.16
3
+ * surface of the grand merge; split from the extension session domain on
4
+ * the platform boundary: the extension sessions stay browser-pure, this
5
+ * node surface keeps the workbench chat session files).
6
+ */
7
+ /** DevThink session model: one stable identity contract for CLI, gateway, local database, and URL-addressable web state. */
8
+ import { existsSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { ensurePaths, type DevThinkPaths } from "./config.js";
11
+ import type { ChatMessage } from "./providers.ts";
12
+ import { createCompactId } from "./ids.js";
13
+ import { mirrorSession, type StoredSession, type StoredWorkspace } from "./storage.js";
14
+
15
+ export type SessionSection =
16
+ | "chat"
17
+ | "inspector"
18
+ | "settings"
19
+ | "memory"
20
+ | "providers"
21
+ | "projects"
22
+ | "routes"
23
+ | "usage";
24
+ export type SessionTab = {
25
+ id: string;
26
+ sessionId: string;
27
+ workspaceId: string;
28
+ label: string;
29
+ provider?: string | undefined;
30
+ sectionId: SessionSection;
31
+ createdAt: string;
32
+ updatedAt: string;
33
+ };
34
+ export type SessionMessage = ChatMessage & {
35
+ id: string;
36
+ sessionId: string;
37
+ workspaceId: string;
38
+ tabId: string;
39
+ sectionId: SessionSection;
40
+ createdAt: string;
41
+ };
42
+ export type Workspace = { id: string; title: string; createdAt: string; updatedAt: string };
43
+
44
+ export type Session = {
45
+ id: string;
46
+ workspaceId: string;
47
+ title: string;
48
+ mode: string;
49
+ model?: string | undefined;
50
+ provider?: string | undefined;
51
+ createdAt: string;
52
+ updatedAt: string;
53
+ activeTabId: string;
54
+ tabs: SessionTab[];
55
+ messages: SessionMessage[];
56
+ };
57
+
58
+ function sessionPath(paths: DevThinkPaths, id: string): string {
59
+ return join(paths.sessions, `${id}.json`);
60
+ }
61
+
62
+ function safeTitle(messages: SessionMessage[]): string {
63
+ const first = messages.find((message) => message.role === "user");
64
+ return first?.content.slice(0, 80) || "Untitled session";
65
+ }
66
+
67
+ function workspacePath(paths: DevThinkPaths, id: string): string {
68
+ return join(paths.workspaces, `${id}.json`);
69
+ }
70
+
71
+ function atomicWrite(path: string, value: unknown): void {
72
+ const temporary = `${path}.${process.pid}.${Date.now()}.tmp`;
73
+ writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, "utf8");
74
+ renameSync(temporary, path);
75
+ }
76
+
77
+ function newWorkspace(
78
+ id = createCompactId("w"),
79
+ title = "Untitled workspace",
80
+ now = new Date().toISOString(),
81
+ ): Workspace {
82
+ return { id, title, createdAt: now, updatedAt: now };
83
+ }
84
+
85
+ function newTab(
86
+ sessionId: string,
87
+ workspaceId: string,
88
+ provider: string | undefined,
89
+ label: string,
90
+ sectionId: SessionSection,
91
+ now: string,
92
+ id = createCompactId("t"),
93
+ ): SessionTab {
94
+ return { id, sessionId, workspaceId, provider, label, sectionId, createdAt: now, updatedAt: now };
95
+ }
96
+
97
+ function normalizeSession(raw: Session): Session {
98
+ const now = raw.updatedAt || new Date().toISOString();
99
+ const workspaceId = raw.workspaceId || createCompactId("w");
100
+ const tabs = raw.tabs?.length
101
+ ? raw.tabs.map((tab) => ({
102
+ ...tab,
103
+ sessionId: raw.id,
104
+ workspaceId,
105
+ sectionId: tab.sectionId || ("chat" as SessionSection),
106
+ }))
107
+ : [newTab(raw.id, workspaceId, raw.provider, raw.title || "Untitled session", "chat", now)];
108
+ const activeTabId = tabs.some((tab) => tab.id === raw.activeTabId) ? raw.activeTabId : tabs[0].id;
109
+ const messages = (raw.messages || []).map((message) => ({
110
+ ...message,
111
+ id: message.id || createCompactId("m"),
112
+ sessionId: raw.id,
113
+ workspaceId,
114
+ tabId: message.tabId || activeTabId,
115
+ sectionId: message.sectionId || ("chat" as SessionSection),
116
+ createdAt: message.createdAt || now,
117
+ }));
118
+ return { ...raw, workspaceId, activeTabId, tabs, messages };
119
+ }
120
+
121
+ function readSession(path: string): Session | undefined {
122
+ try {
123
+ if (!existsSync(path)) return undefined;
124
+ return normalizeSession(JSON.parse(readFileSync(path, "utf8")) as Session);
125
+ } catch {
126
+ return undefined;
127
+ }
128
+ }
129
+
130
+ function workspaceFor(session: Session): Workspace {
131
+ const title = session.title === "Untitled session" ? "Untitled workspace" : session.title;
132
+ return newWorkspace(session.workspaceId, title, session.createdAt);
133
+ }
134
+
135
+ function saveSession(paths: DevThinkPaths, session: Session): Session {
136
+ ensurePaths(paths);
137
+ const normalized = normalizeSession(session);
138
+ const existing = loadWorkspace(paths, normalized.workspaceId);
139
+ const workspace = {
140
+ ...(existing || workspaceFor(normalized)),
141
+ title: normalized.title === "Untitled session" ? existing?.title || "Untitled workspace" : normalized.title,
142
+ updatedAt: normalized.updatedAt,
143
+ };
144
+ atomicWrite(sessionPath(paths, normalized.id), normalized);
145
+ atomicWrite(workspacePath(paths, workspace.id), workspace);
146
+ mirrorSession(paths, workspace as StoredWorkspace, normalized as StoredSession);
147
+ return normalized;
148
+ }
149
+
150
+ export function createWorkspace(
151
+ paths: DevThinkPaths,
152
+ title = "Untitled workspace",
153
+ id = createCompactId("w"),
154
+ ): Workspace {
155
+ ensurePaths(paths);
156
+ const workspace = newWorkspace(id, title);
157
+ atomicWrite(workspacePath(paths, id), workspace);
158
+ return workspace;
159
+ }
160
+
161
+ export function loadWorkspace(paths: DevThinkPaths, id: string): Workspace | undefined {
162
+ try {
163
+ if (!existsSync(workspacePath(paths, id))) return undefined;
164
+ return JSON.parse(readFileSync(workspacePath(paths, id), "utf8")) as Workspace;
165
+ } catch {
166
+ return undefined;
167
+ }
168
+ }
169
+
170
+ export function createSession(
171
+ paths: DevThinkPaths,
172
+ metadata: Pick<Session, "mode" | "model" | "provider"> & {
173
+ workspaceId?: string | undefined;
174
+ tabId?: string | undefined;
175
+ sectionId?: SessionSection;
176
+ title?: string | undefined;
177
+ },
178
+ ): Session {
179
+ const now = new Date().toISOString();
180
+ const id = createCompactId("s");
181
+ const workspace = metadata.workspaceId
182
+ ? loadWorkspace(paths, metadata.workspaceId) || createWorkspace(paths, "Untitled workspace", metadata.workspaceId)
183
+ : createWorkspace(paths);
184
+ const tab = newTab(
185
+ id,
186
+ workspace.id,
187
+ metadata.provider,
188
+ metadata.title || "Untitled session",
189
+ metadata.sectionId || "chat",
190
+ now,
191
+ metadata.tabId,
192
+ );
193
+ const session: Session = {
194
+ id,
195
+ workspaceId: workspace.id,
196
+ title: metadata.title || "Untitled session",
197
+ mode: metadata.mode,
198
+ model: metadata.model,
199
+ provider: metadata.provider,
200
+ createdAt: now,
201
+ updatedAt: now,
202
+ activeTabId: tab.id,
203
+ tabs: [tab],
204
+ messages: [],
205
+ };
206
+ return saveSession(paths, session);
207
+ }
208
+
209
+ export function loadSession(paths: DevThinkPaths, id: string): Session | undefined {
210
+ const session = readSession(sessionPath(paths, id));
211
+ return session ? saveSession(paths, session) : undefined;
212
+ }
213
+
214
+ export function createTab(
215
+ paths: DevThinkPaths,
216
+ session: Session,
217
+ input: {
218
+ id?: string | undefined;
219
+ label?: string | undefined;
220
+ provider?: string | undefined;
221
+ sectionId?: SessionSection;
222
+ },
223
+ ): Session {
224
+ const now = new Date().toISOString();
225
+ const tab = newTab(
226
+ session.id,
227
+ session.workspaceId,
228
+ input.provider || session.provider,
229
+ input.label || "New session",
230
+ input.sectionId || "chat",
231
+ now,
232
+ input.id,
233
+ );
234
+ return saveSession(paths, { ...session, activeTabId: tab.id, updatedAt: now, tabs: [...session.tabs, tab] });
235
+ }
236
+
237
+ export function updateTab(
238
+ paths: DevThinkPaths,
239
+ session: Session,
240
+ tabId: string,
241
+ input: { label?: string | undefined; provider?: string | undefined; sectionId?: SessionSection | undefined },
242
+ ): Session {
243
+ const now = new Date().toISOString();
244
+ const tabs = session.tabs.map((tab) =>
245
+ tab.id === tabId ? ({ ...tab, ...input, updatedAt: now } as SessionTab) : tab,
246
+ );
247
+ if (!tabs.some((tab) => tab.id === tabId)) throw new Error(`Tab not found: ${tabId}`);
248
+ return saveSession(paths, { ...session, activeTabId: tabId, updatedAt: now, tabs });
249
+ }
250
+
251
+ export function appendMessage(
252
+ paths: DevThinkPaths,
253
+ session: Session,
254
+ message: ChatMessage,
255
+ context?: { tabId?: string; sectionId?: SessionSection; id?: string },
256
+ ): Session {
257
+ const now = new Date().toISOString();
258
+ const tabId = context?.tabId || session.activeTabId;
259
+ if (!session.tabs.some((tab) => tab.id === tabId)) throw new Error(`Tab not found: ${tabId}`);
260
+ const nextMessages = [
261
+ ...session.messages,
262
+ {
263
+ ...message,
264
+ id: context?.id || createCompactId("m"),
265
+ sessionId: session.id,
266
+ workspaceId: session.workspaceId,
267
+ tabId,
268
+ sectionId: context?.sectionId || "chat",
269
+ createdAt: now,
270
+ },
271
+ ];
272
+ return saveSession(paths, { ...session, title: safeTitle(nextMessages), updatedAt: now, messages: nextMessages });
273
+ }
274
+
275
+ export function listSessions(paths: DevThinkPaths): Session[] {
276
+ if (!existsSync(paths.sessions)) return [];
277
+ return readdirSync(paths.sessions)
278
+ .filter((file) => file.endsWith(".json") && !file.endsWith(".memory.json"))
279
+ .map((file) => readSession(join(paths.sessions, file)))
280
+ .filter((session): session is Session => Boolean(session))
281
+ .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
282
+ }
283
+
284
+ export function renderSessionMarkdown(session: Session): string {
285
+ const lines = [
286
+ `# ${session.title}`,
287
+ "",
288
+ `- Workspace: ${session.workspaceId}`,
289
+ `- Session: ${session.id}`,
290
+ `- Active tab: ${session.activeTabId}`,
291
+ `- Mode: ${session.mode}`,
292
+ `- Provider: ${session.provider || "not configured"}`,
293
+ `- Model: ${session.model || "not configured"}`,
294
+ "",
295
+ ];
296
+ for (const message of session.messages) lines.push(`## ${message.role}`, "", message.content, "");
297
+ return `${lines.join("\n")}\n`;
298
+ }
299
+
300
+ export function exportSession(paths: DevThinkPaths, id: string, format: "json" | "markdown"): string {
301
+ const session = loadSession(paths, id);
302
+ if (!session) throw new Error(`Session not found: ${id}`);
303
+ return format === "json" ? `${JSON.stringify(session, null, 2)}\n` : renderSessionMarkdown(session);
304
+ }