dsh-thoughtdag 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +92 -0
  3. package/cordis.patch.yml +11 -0
  4. package/dist-app/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  5. package/dist-app/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  6. package/dist-app/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  7. package/dist-app/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  8. package/dist-app/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  9. package/dist-app/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  10. package/dist-app/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  11. package/dist-app/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  12. package/dist-app/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  13. package/dist-app/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  14. package/dist-app/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  15. package/dist-app/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  16. package/dist-app/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  17. package/dist-app/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  18. package/dist-app/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  19. package/dist-app/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  20. package/dist-app/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  21. package/dist-app/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  22. package/dist-app/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  23. package/dist-app/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  24. package/dist-app/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  25. package/dist-app/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  26. package/dist-app/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  27. package/dist-app/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  28. package/dist-app/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  29. package/dist-app/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  30. package/dist-app/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  31. package/dist-app/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  32. package/dist-app/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  33. package/dist-app/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  34. package/dist-app/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  35. package/dist-app/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  36. package/dist-app/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  37. package/dist-app/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  38. package/dist-app/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  39. package/dist-app/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  40. package/dist-app/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  41. package/dist-app/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  42. package/dist-app/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  43. package/dist-app/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  44. package/dist-app/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  45. package/dist-app/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  46. package/dist-app/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  47. package/dist-app/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  48. package/dist-app/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  49. package/dist-app/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  50. package/dist-app/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  51. package/dist-app/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  52. package/dist-app/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  53. package/dist-app/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  54. package/dist-app/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  55. package/dist-app/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  56. package/dist-app/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  57. package/dist-app/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  58. package/dist-app/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  59. package/dist-app/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  60. package/dist-app/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  61. package/dist-app/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  62. package/dist-app/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  63. package/dist-app/assets/canonical-DbPqsMYz.js +2 -0
  64. package/dist-app/assets/canvas-record-C1A8ExlM.js +1 -0
  65. package/dist-app/assets/claude-code-session-DQRgWy00.js +7 -0
  66. package/dist-app/assets/codex-session--KVj3_vb.js +12 -0
  67. package/dist-app/assets/dsh-session-6OCSm4h5.js +6 -0
  68. package/dist-app/assets/experiment-loop-BfxITu2e.js +2 -0
  69. package/dist-app/assets/index-6m02Pb4Q.js +761 -0
  70. package/dist-app/assets/index-BH-U0zVI.js +105 -0
  71. package/dist-app/assets/index-BL39OXsY.js +221 -0
  72. package/dist-app/assets/index-BeoRn2gJ.js +2 -0
  73. package/dist-app/assets/index-D-BTv0n0.js +3 -0
  74. package/dist-app/assets/index-DEHbIrRr.css +1 -0
  75. package/dist-app/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  76. package/dist-app/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  77. package/dist-app/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  78. package/dist-app/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  79. package/dist-app/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  80. package/dist-app/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  81. package/dist-app/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  82. package/dist-app/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  83. package/dist-app/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  84. package/dist-app/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  85. package/dist-app/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  86. package/dist-app/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  87. package/dist-app/assets/live-mirror-BElcCk_a.js +2 -0
  88. package/dist-app/assets/pdf-gh-BrLFn.js +12 -0
  89. package/dist-app/assets/pdf.worker.min-C_APr3k7.js +1 -0
  90. package/dist-app/assets/pdf.worker.min-yatZIOMy.mjs +21 -0
  91. package/dist-app/assets/purify.es-Cz4mVeUR.js +3 -0
  92. package/dist-app/assets/sensitive-scan-L0rFzufE.js +7 -0
  93. package/dist-app/assets/session-handoff-CGrowwZp.js +2 -0
  94. package/dist-app/assets/shared-CURSZnXt.js +10 -0
  95. package/dist-app/assets/turndown-plugin-gfm.cjs-p3SpZgsj.js +22 -0
  96. package/dist-app/assets/turndown.browser.es-kLzRgxYD.js +61 -0
  97. package/dist-app/assets/update-check-D5daO3Cz.js +1 -0
  98. package/dist-app/favicon.svg +10 -0
  99. package/dist-app/index.html +31 -0
  100. package/dist-app/logo-social.png +0 -0
  101. package/dist-app/logo-social.svg +52 -0
  102. package/dist-app/og-twitter.jpg +0 -0
  103. package/dist-app/og.jpg +0 -0
  104. package/dist-app/robots.txt +4 -0
  105. package/dist-app/sitemap.xml +6 -0
  106. package/dist-app/tutorial/map-en.gif +0 -0
  107. package/dist-app/tutorial/map-zh.gif +0 -0
  108. package/dist-app/tutorial/prune-en.gif +0 -0
  109. package/dist-app/tutorial/prune-zh.gif +0 -0
  110. package/dist-app/tutorial/reading-en.gif +0 -0
  111. package/dist-app/tutorial/reading-zh.gif +0 -0
  112. package/dist-app/tutorial/ref-en.gif +0 -0
  113. package/dist-app/tutorial/ref-zh.gif +0 -0
  114. package/lib/client.js +84 -0
  115. package/lib/index.js +845 -0
  116. package/package.json +107 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xia Chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # dsh-thoughtdag
2
+
3
+ This directory is the DeepSeek Harness plugin of [ThoughtDAG](../README.md), published to npm as `dsh-thoughtdag`; its version follows the app's, and the ThoughtDAG build it embeds is the one in this tree.
4
+
5
+ ThoughtDAG for DeepSeek Harness: open DSH sessions (live or on disk) as
6
+ editable thought graphs on ThoughtDAG's infinite canvas — from inside the
7
+ harness UI.
8
+
9
+ This is a [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
10
+ plugin (a Cordis plugin distributed as an npm package), built on the same shell
11
+ pattern as [dsh-synapse](https://github.com/liangmianya/dsh-synapse): the host
12
+ half mounts the ThoughtDAG SPA under `/thoughtdag/` on the EXISTING harness
13
+ web server (no second process, no second port), and the client half adds a
14
+ floating "对话 | 思维图" switch that shows the canvas in a same-origin
15
+ full-screen iframe.
16
+
17
+ ## What works
18
+
19
+ - `dsh plugin --profile web add dsh-thoughtdag` installs the plugin
20
+ - The harness GUI gains a view switch; "思维图" opens ThoughtDAG at
21
+ `/thoughtdag/` (same origin — no CORS, no second server)
22
+ - The host serves the SPA plus a read-only session bridge:
23
+
24
+ | Endpoint | Purpose |
25
+ |---|---|
26
+ | `GET /thoughtdag/api/disksessions` | list durable sessions on disk (id, title, cwd from the session header; newest first) |
27
+ | `GET /thoughtdag/api/disksessions/<id>/log` | one disk session as JSONL — the exact dialect ThoughtDAG's `dsh-session` adapter parses, so a past harness session imports like a local file |
28
+ | `GET /thoughtdag/api/sessions` | list live sessions in this process |
29
+ | `GET /thoughtdag/api/sessions/<id>/log` | one live session's events as JSONL |
30
+ | `GET /thoughtdag/api/sessions/<id>/turns` | turn boundaries (start/end seq, the person's message id) of a live or on-disk session — the fork points a canvas can name |
31
+ | `POST /thoughtdag/api/sessions/<id>/fork` | `{ afterTurn }` or `{ atSeq }` → a child session inheriting the prefix through that completed turn (`sessionController.fork`, so the chat UI lists it) |
32
+ | `POST /thoughtdag/api/sessions/<id>/inject` | `{ text }` or `{ blocks: [{type:'text',text}] }` → model-facing context for the next step (`agent.inject`; no wake; shown in the transcript as injected context from `dsh-thoughtdag`) |
33
+ | `POST /thoughtdag/api/sessions/<id>/followup` | `{ text | blocks, mode?: 'queue' | 'steer' }` → a user prompt through `sessionController.prompt`, exactly as the composer sends one |
34
+ | `GET /thoughtdag/api/roots` · `GET /thoughtdag/api/roots/<key>/list\|head\|read\|range` | the other agents' session directories on this machine (`claude-projects` = `~/.claude/projects`, `codex-sessions` = `~/.codex/sessions`) with the desktop bridge's file primitives, so Session Atlas inside the harness lists all three sources and mirrors a Claude Code or Codex session as the desktop does; `rel` never escapes its root |
35
+ | `GET /thoughtdag/api/models` | the harness's model catalog in the SPA's list shape (`<provider>/<model>` ids, the harness default) |
36
+ | `POST /thoughtdag/api/stream` · `POST /thoughtdag/api/claude` | the SPA's own proxy protocol, answered on the harness's providers and credentials (`ctx.llm.stream`); the embedded SPA is built with `VITE_API_BASE=/thoughtdag`, so its model picker and every canvas-native generation (summaries, condensing, a canvas that is not a mirrored session) run on the harness's models. These calls do not enter a session log; a mirrored session's turns go through `/followup` |
37
+ | `harness/agent` (a catalog entry) | pick it in the picker and the question goes INTO the harness: a fresh session per call, the canvas's wired context injected first (`agent.inject`, source `dsh-thoughtdag`), the question as a user follow-up, the harness's own agent loop with tools; text, reasoning and tool calls stream back as the SPA's frames, the first frame names the session (`{ harnessSession }`) and, once the question enters the surface, the turn it created (`{ harnessTurn: { turn, userMessageId, seq } }`), so the canvas can mark its node as that turn's mirror instead of receiving it twice. The session stays in the Chat and the atlas. `harness: { cwd }` sets the session's working directory (the canvas passes the project it mirrors, else the current chat session's); `harness: { session }` continues a mirrored session instead of forking a fresh one (a tail follow-up); `images` (base64) are admitted through the controller's prompt and a vision model is selected for that turn, so a picture the canvas holds is read by the harness's own eyes |
38
+ | `POST /thoughtdag/api/fetch-url` | the SPA's link snapshot (`{ url }` → `{ title, text, fetchedAt, html? }`) through the harness's bounded, credential-free fetcher (`ctx.web.fetch`) |
39
+
40
+ Disk logs are zstd *concatenated-frame* files; the bridge locates frame
41
+ boundaries structurally and decodes each with `node:zlib` (the same walk the
42
+ DSH persistence backend performs), so no external zstd binary or native
43
+ module is needed.
44
+ - The bridge is Host-header fenced (localhost/127.0.0.1 + `trustedHosts`)
45
+
46
+ ## Verified (2026-09)
47
+
48
+ - installed into the local `web` profile via `dsh plugin --profile web add <dir>`
49
+ - a fresh web-profile boot serves `/thoughtdag/` (SPA) and the bridge API; the
50
+ index injection table lists `dsh-thoughtdag/client.js`
51
+ - headless-browser walk: the "对话 | 思维图" switch appears, the full-screen
52
+ same-origin iframe opens, and ThoughtDAG boots inside it
53
+ - fetching the bridge from INSIDE the thoughtdag origin works with no extra
54
+ auth: `GET /thoughtdag/api/disksessions` lists every on-disk session (new
55
+ sessions created by the running instance appear automatically) and
56
+ `GET .../log` returns the full event stream
57
+ - real session logs decode correctly (multi-frame zstd → 15k+ JSONL lines,
58
+ identical to the `zstd` CLI)
59
+ - the live bridge (`/api/sessions`) reflects the running instance's active
60
+ session as soon as the GUI opens one (verified: opening the UI surfaces the
61
+ auto-created session with its live seq), complementing the disk archive
62
+
63
+ ### Canvas-side import
64
+
65
+ ThoughtDAG's own session importer (`dsh-session` adapter + the canonical
66
+ import path) accepts the bridge's JSONL verbatim. Wiring a "DSH sessions"
67
+ source into the in-iframe canvas UI (Session Atlas) is planned; the bridge is
68
+ the data plane it will read.
69
+
70
+ ## Not yet (roadmap)
71
+
72
+ - Canvas UI for the write bridge: name a fork point on a node, hand a compiled context to `inject`, continue with `followup`; the client already switches the chat to a session the canvas names (`td:select-session`)
73
+ - `replace`: shadow a surface range from the canvas (DSH's compaction primitive); needs a live check of how the chat renders a replaced range
74
+ - Theme sync and live session following in the iframe
75
+ - A real "import current session" affordance inside the canvas UI
76
+
77
+ ## Development
78
+
79
+ ```bash
80
+ # 1. build the embedded ThoughtDAG SPA with a /thoughtdag/ subpath base (from the repo root)
81
+ npm run dsh:build # writes dsh/dist-app, which git ignores
82
+
83
+ # 2. install into a profile from this directory (pnpm link)
84
+ dsh plugin --profile web add /abs/path/to/thoughtdag/dsh
85
+
86
+ # 3. restart the profile's web app; open the view switch in the GUI
87
+ ```
88
+
89
+ While developing, the profile keeps a pnpm *link* to this directory, so edits
90
+ to `lib/` apply on the next restart without reinstalling.
91
+
92
+ License: MIT
@@ -0,0 +1,11 @@
1
+ # dsh-thoughtdag extends the Web profile: it reuses the existing DSH server
2
+ # and mounts the ThoughtDAG SPA under /thoughtdag/ on the same origin.
3
+ - insert:
4
+ - id: thoughtdag
5
+ name: dsh-thoughtdag
6
+ config:
7
+ # Path prefix this plugin serves the SPA under.
8
+ mountPrefix: /thoughtdag
9
+ # Extra authorities the /thoughtdag/api Host check accepts; localhost
10
+ # and 127.0.0.1 are always allowed.
11
+ trustedHosts: []
@@ -0,0 +1,2 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-D-BTv0n0.js","assets/index-6m02Pb4Q.js","assets/index-DEHbIrRr.css","assets/experiment-loop-BfxITu2e.js"])))=>i.map(i=>d[i]);
2
+ import{c as N,b as y,_ as E,p as q,r as M,h as O,a as D,u as j,j as X,s as B,k as Q,l as z,f as U,m as $,n as W,t as Y,o as F,q as Z,v as tt}from"./index-6m02Pb4Q.js";const et=190;async function dt(o){const{anyRunnerSessionConversation:n}=await E(async()=>{const{anyRunnerSessionConversation:a}=await import("./index-D-BTv0n0.js");return{anyRunnerSessionConversation:a}},__vite__mapDeps([0,1,2])),e=await n(o);return V(e)}function at(o,n){let a=0,s=!1;return async()=>{if(s)return null;const c=await window.desktopSessions.readRange(o,n,a,8388608);return a=c.nextStart,c.eof&&(s=!0),c.text}}function L(o){if(!o)return null;for(const n of N.getState().projects){const e=n.sourceSession;if(!e)continue;if(e.sessionId===o)return{project:n,entry:e};const a=e.chapters?.find(c=>c.sessionId===o);if(a)return{project:n,entry:a};const s=e.branches?.find(c=>c.sessionId===o);if(s)return{project:n,entry:s}}return null}function H(o,n,e,a,s){const c=a.position.x+(s?560:0),m=c-40,d=c+580,t=o.nodes.reduce((w,S)=>{const x=S.width??S.measured?.width??540;if(S.position.x+x<m||S.position.x>d)return w;const l=S.height??S.measured?.height??300;return Math.max(w,S.position.y+l)},s?a.position.y-300:a.position.y+(a.height??140)),u=c-n[0].position.x,f=Math.max(t+et,s?a.position.y:-1/0)-n[0].position.y,i=n.map(w=>({...w,position:{x:w.position.x+u,y:w.position.y+f}})),h=[{id:F(),source:a.id,target:i[0].id,type:"smoothstep"},...e];return{moved:i,edges:h}}async function V(o){if(!o)return null;const n=o.build(),e=n.nodes.filter(m=>m.data.importSource),a=e.at(-1)?.id??n.nodes.at(-1)?.id??"";if(n.nodes.length===0)return null;const s=L(o.sessionId);if(s)return G(o,n,e,a,s);if(o.sessionId){const m=await st(o.sessionId);if(m){let d=-1,t="";if(e.forEach((u,f)=>{const i=u.data.importSource?.itemIds?.[0],h=i?m.byFirstId.get(i):void 0;h&&(d=f,t=h)}),d>=0){await M(m.projectId,"chapter",{sessionId:o.sessionId,runner:o.source,importedCount:d+1,tailNodeId:t});const u=L(o.sessionId);if(u)return G(o,n,e,a,u)}}}if(o.sessionId&&e.length>0){const{parseAnchor:m}=await E(async()=>{const{parseAnchor:t}=await import("./experiment-loop-BfxITu2e.js");return{parseAnchor:t}},__vite__mapDeps([3,1,2])),d=m(e[0].data.question??"");if(d&&N.getState().projects.some(t=>t.id===d.project)){await O(d.project);const t=y.getState(),u=N.getState().projects.find(i=>i.id===d.project);let f=t.nodes.find(i=>i.id===d.node)??null;if(!f&&d.mode==="continue"&&u.sourceSession?.sessionId){const i=u.sourceSession;f=t.nodes.find(h=>h.id===i.tailNodeId)??t.nodes.filter(h=>h.data.importSource?.sessionId===i.sessionId).at(-1)??null}if(f){const i=n.nodes.find(l=>l.data.importSource&&l.data.stepKind!=="note");if(i&&m(i.data.question??"")){const l=D("exp.openerMark");i.data={...i.data,question:l,source:i.data.source?{...i.data.source,question:l}:i.data.source}}const h=new Set(n.nodes.map(l=>l.id)),w=n.edges.filter(l=>h.has(l.source)&&h.has(l.target)),S=d.mode!=="continue",x=H(t,n.nodes,w,f,S);if(S){const l=x.moved.find(_=>_.data.importSource&&_.data.stepKind!=="note");l&&(l.data={...l.data,isBranch:!0})}return t.pushHistory(),y.setState(l=>({nodes:[...l.nodes,...x.moved],edges:[...l.edges,...x.edges]})),await M(d.project,S?"branch":"chapter",{sessionId:o.sessionId,runner:o.source,importedCount:e.length,tailNodeId:a,anchorNodeId:f.id}),j.getState().setArrivalFocusNodeId(x.moved[x.moved.length-1].id),{kind:"mounted",mode:S?"branch":"continue",turns:e.length}}}}const c=crypto.randomUUID();return await X(q(c),JSON.stringify({state:{nodes:B(n.nodes),edges:n.edges},version:1})),j.getState().setArrivalFocusNodeId(n.nodes[n.nodes.length-1].id),await Q(c,o.title.slice(0,60),"chat",o.sessionId?{sourceSession:{sessionId:o.sessionId,runner:o.source,importedCount:e.length,tailNodeId:a}}:void 0),{kind:"imported",nodeCount:n.nodes.length}}async function ct(o,n){if(!o||!o.sessionId)return null;if(L(o.sessionId))return V(o);const e=o.build(),a=e.nodes.filter(i=>i.data.importSource);if(e.nodes.length===0)return null;await O(n);const s=y.getState(),c=N.getState().projects.find(i=>i.id===n);if(!c)return null;const m=c.sourceSession,d=(m?.sessionId?s.nodes.find(i=>i.id===m.tailNodeId)??s.nodes.filter(i=>i.data.importSource?.sessionId===m.sessionId).at(-1):null)??s.nodes.at(-1)??null;if(!d)return null;const t=new Set(e.nodes.map(i=>i.id)),u=e.edges.filter(i=>t.has(i.source)&&t.has(i.target)),f=H(s,e.nodes,u,d,!1);return s.pushHistory(),y.setState(i=>({nodes:[...i.nodes,...f.moved],edges:[...i.edges,...f.edges]})),await M(n,"chapter",{sessionId:o.sessionId,runner:o.source,importedCount:a.length,tailNodeId:a.at(-1)?.id??e.nodes.at(-1).id,anchorNodeId:d.id}),j.getState().setArrivalFocusNodeId(f.moved[f.moved.length-1].id),{kind:"mounted",mode:"continue",turns:a.length}}async function st(o){const{projects:n,activeId:e}=N.getState(),a=[...n].sort((s,c)=>s.id===e?-1:c.id===e?1:c.updatedAt-s.updatedAt);for(const s of a){if(s.id!==e&&s.provenanceSessions&&!s.provenanceSessions.includes(o))continue;let c;if(s.id===e)c=y.getState().nodes;else try{const{get:d}=await E(async()=>{const{get:f}=await import("./index-6m02Pb4Q.js").then(i=>i.D);return{get:f}},__vite__mapDeps([1,2])),t=await d(q(s.id));c=(typeof t=="string"?JSON.parse(t):t)?.state?.nodes??[]}catch{continue}if(s.id!==e&&!s.provenanceSessions){const d=[...new Set(c.map(t=>t.data.importSource?.sessionId).filter(t=>!!t))];N.setState(t=>({projects:t.projects.map(u=>u.id===s.id?{...u,provenanceSessions:d}:u)}))}const m=new Map;for(const d of c)if(d.data.importSource?.sessionId===o&&d.data.stepKind!=="note"){const t=d.data.importSource.itemIds?.[0];t&&m.set(t,d.id)}if(m.size>0)return{projectId:s.id,byFirstId:m}}return null}async function G(o,n,e,a,s){await O(s.project.id);const c=y.getState(),m=c.nodes.filter(p=>p.data.importSource?.sessionId===o.sessionId),d=c.nodes.find(p=>p.id===s.entry.tailNodeId)??m.at(-1)??null,t=s.entry.importedCount>0&&e.length>=s.entry.importedCount?e[s.entry.importedCount-1]:null;if(t){const p=t.data.importSource?.itemIds?.[0],r=p?m.find(C=>C.data.importSource?.itemIds?.[0]===p):void 0,g=r?.data.source,k=!!g&&r.data.question===g.question&&(r.data.response??"")===(g.response??""),I=t.data,K=!!r&&(I.question!==r.data.question||(I.response??"")!==(r.data.response??"")),A=r?.data.attachments??[],T=I.attachments??[],J=!!r&&T.length>A.length&&A.every((C,R)=>T[R]?.name===C.name);if(r&&k&&(K||J)){const C=K?I.attachments:[...A,...T.slice(A.length)];y.setState(R=>({nodes:R.nodes.map(P=>P.id===r.id?{...P,data:{...P.data,question:I.question,response:I.response,responses:I.responses,responseIndex:I.responseIndex,tokenCount:I.tokenCount,attachments:C,importSource:I.importSource,source:I.source}}:P)})),y.getState().recomputeStaleness()}}if(e.length<=s.entry.importedCount)return j.getState().setArrivalFocusNodeId(d?.id??null),{kind:"opened"};const u=e[s.entry.importedCount],f=n.nodes.findIndex(p=>p.id===u.id),i=n.nodes.slice(f),h=new Set(i.map(p=>p.id)),w=n.edges.filter(p=>h.has(p.source)&&h.has(p.target)),S=new Map;for(const p of m){const r=p.data.importSource?.itemIds?.[0];r&&S.set(r,p.id)}const x=new Map;for(const p of n.nodes){const r=p.data.importSource?.itemIds?.[0];r&&!h.has(p.id)&&x.set(p.id,r)}const l=[];for(const p of n.edges){if(!h.has(p.target)||h.has(p.source))continue;const r=x.get(p.source),g=r?S.get(r):void 0;g&&l.push({...p,id:F(),source:g})}const _=new Set(l.map(p=>p.target));let v,b;if(d){const p=H(c,i,w,d,!1);v=p.moved;const r=new Set(w.map(g=>g.target));b=p.edges.filter(g=>!(g.source===d.id&&_.has(g.target)));for(const g of v)g.id!==v[0].id&&!r.has(g.id)&&!_.has(g.id)&&g.data.stepKind!=="note"&&b.push({id:F(),source:d.id,target:g.id,type:"smoothstep"});b=[...b,...l]}else{const r=(c.nodes.length?Math.max(...c.nodes.map(I=>I.position.x)):0)+560-i[0].position.x,g=-i[0].position.y;v=i.map(I=>({...I,position:{x:I.position.x+r,y:I.position.y+g}}));const k=nt(ot(e.length-s.entry.importedCount),v[0]);v=[k,...v],b=[{id:F(),source:k.id,target:v[1].id,type:"smoothstep"},...w]}return c.pushHistory(),y.setState(p=>({nodes:[...p.nodes,...v],edges:[...p.edges,...b]})),await Z(s.project.id,o.sessionId,{importedCount:e.length,tailNodeId:a}),j.getState().setArrivalFocusNodeId(v[d?0:1].id),{kind:"appended",turns:e.length-s.entry.importedCount}}function ot(o){return`[Mirror] The source session grew by ${o} turn(s); the earlier mirrored turns were removed from this canvas by hand, so the new turns land here on their own.`}function nt(o,n){const e=tt(o,"",!1);return e.data.stepKind="note",e.data.importSource=n.data.importSource?{...n.data.importSource,itemIds:[]}:void 0,e.width=460,e.position={x:n.position.x-520,y:n.position.y},e}async function ut(o){const{projects:n,activeId:e}=N.getState(),a=n.find(t=>t.id===o);if(!a?.sourceSession)return"native";if((a.sourceSession.chapters?.length??0)>0||(a.sourceSession.branches?.length??0)>0)return"diverged-mirror";let s;if(o===e)s=y.getState().nodes;else{const{get:t}=await E(async()=>{const{get:f}=await import("./index-6m02Pb4Q.js").then(i=>i.D);return{get:f}},__vite__mapDeps([1,2])),u=await t(q(o));try{s=(typeof u=="string"?JSON.parse(u):u)?.state?.nodes??[]}catch{return"diverged-mirror"}}const c=a.sourceSession.sessionId,m=s.filter(t=>t.data.importSource?.sessionId===c);return s.some(t=>!t.data.importSource)||s.some(t=>t.data.importSource&&t.data.importSource.sessionId!==c)||m.filter(t=>t.data.source).length<a.sourceSession.importedCount||m.some(t=>t.data.source&&(t.data.question!==t.data.source.question||t.data.response!==t.data.source.response))?"diverged-mirror":"pristine-mirror"}async function pt(){const{bootProjects:o}=await E(async()=>{const{bootProjects:u}=await import("./index-6m02Pb4Q.js").then(f=>f.H);return{bootProjects:u}},__vite__mapDeps([1,2]));await o();const{projects:n,activeId:e}=N.getState(),a=n.find(u=>u.id===e);if(!a?.sourceSession)return;const s=$(a);if(s.length===0)return;const c=new Set;for(const u of y.getState().nodes){const f=u.data.importSource?.sessionId;f&&c.add(f)}const m=s.filter(u=>!c.has(u));if(m.length===0)return;for(const u of m)await W(a.id,u);const t=N.getState().projects.find(u=>u.id===a.id)?.sourceSession?"toast.unsubscribed":"toast.unsubscribedNative";Y("info",U(D(t),{n:m.length}),8e3)}async function mt(o,n){const e=o.filter(d=>!!d&&!!d.sessionId);if(e.length===0)return null;const a=n??await z(U(D("atlas.mergedName"),{title:e[0].title.slice(0,24),n:e.length}));await O(a),y.getState().pushHistory();let s=0,c=0;for(const d of e){const t=d.sessionId;if(L(t)){c++;continue}const u=d.build();if(u.nodes.length===0){c++;continue}const f=u.nodes.filter(r=>r.data.importSource),i=y.getState().nodes,h=i.reduce((r,g)=>Math.max(r,g.position.x+(g.width??g.measured?.width??540)),-1/0),w=i.reduce((r,g)=>Math.min(r,g.position.y),1/0),S=Math.min(...u.nodes.map(r=>r.position.x)),x=Math.min(...u.nodes.map(r=>r.position.y)),l=(Number.isFinite(h)?h+180:0)-S,_=(Number.isFinite(w)?w:0)-x,v=u.nodes.map(r=>({...r,position:{x:r.position.x+l,y:r.position.y+_}})),b=new Set(v.map(r=>r.id)),p=u.edges.filter(r=>b.has(r.source)&&b.has(r.target));y.setState(r=>({nodes:[...r.nodes,...v],edges:[...r.edges,...p]})),await M(a,"chapter",{sessionId:t,runner:d.source,importedCount:f.length,tailNodeId:f.at(-1)?.id??v[v.length-1].id}),s++}y.getState().pushHistory();const m=y.getState().nodes.at(-1);return s>0&&m&&j.getState().setArrivalFocusNodeId(m.id),{mounted:s,skipped:c,projectId:a}}export{ut as canvasUniqueness,V as importOrAppendConversation,dt as importOrAppendSession,mt as mergeSessionsIntoProject,ct as mountConversationToProject,at as shellSessionReader,$ as subscribedSessionIds,pt as unsubscribeOrphanedSessions};
@@ -0,0 +1 @@
1
+ import{b as c,c as p,E as m,s as v,d as w,e as h,g}from"./index-6m02Pb4Q.js";const S=6e4,T=4e3;function y(e){const s=(e.data.attachments??[]).map(t=>({id:t.id,name:t.name,type:t.type,size:t.size,content:"",...t.addedAt?{addedAt:t.addedAt}:{},...t.extractedText?{extractedText:t.extractedText.slice(0,T)}:{},...t.paths?{paths:t.paths}:{},...t.op?{op:t.op}:{}}));return{...e,data:{...e.data,attachments:s}}}function j(){const{nodes:e,edges:s,events:t}=c.getState(),{projects:u,activeId:a}=p.getState();if(!a||e.length===0)return null;const r=u.find(l=>l.id===a),f=JSON.stringify({version:m,name:w(),projectId:a,exportedAt:new Date().toISOString(),record:"thoughtdag-canvas-record",instantiatedFrom:r?.instantiatedFrom,sourceSession:r?.sourceSession,nodes:v(e).map(y),edges:s,events:t});return{projectId:a,json:f}}let n=null,o=!1;async function d(){n&&(clearTimeout(n),n=null),o=!1;const e=window.desktopCanvas;if(!e)return!1;const s=j();return s?!!(await e.write(s.projectId,s.json).catch(()=>({ok:!1}))).ok:!1}function x(){o=!0,n&&clearTimeout(n),n=setTimeout(()=>{n=null,o&&d().catch(e=>console.warn("[thoughtdag] canvas record write failed:",e))},S)}let i=!1;function E(){i||h||typeof window>"u"||!window.desktopCanvas||(i=!0,c.subscribe((e,s)=>{(e.nodes!==s.nodes||e.edges!==s.edges||e.events!==s.events)&&x()}),g.push(async()=>{o&&await d()}),window.addEventListener("pagehide",()=>{o&&d()}))}async function R(e){await window.desktopCanvas?.remove(e).catch(()=>{})}export{j as canvasRecordPayload,d as flushCanvasRecord,R as removeCanvasRecord,E as startCanvasRecord};
@@ -0,0 +1,7 @@
1
+ import{v as I,B as g,o as T}from"./index-6m02Pb4Q.js";import{t as C,a as _,r as A,b as x,c as w,d as L,e as v,s as S,f as k,m as O,T as b,A as B,g as M}from"./shared-CURSZnXt.js";const q=16e3;function f(o){return typeof o=="string"?o:Array.isArray(o)?o.filter(t=>t.type==="text"&&t.text).map(t=>t.text).join(`
2
+ `):""}function N(o){return typeof o=="string"?o:Array.isArray(o)?o.map(t=>t.type==="text"&&t.text?t.text:t.type==="image"?"[image result omitted]":"").filter(Boolean).join(`
3
+ `):""}const p=v;class ${turns=[];pendingTools=new Map;current=null;pendingCompaction;sessionId=null;customTitle=null;summary=null;slug=null;firstQuestion=null;cwd=null;mode=null;feedLine(t){const s=t.trim();if(!s)return;let n;try{n=JSON.parse(s)}catch{return}this.feed(n)}flush(){const t=this.current;t&&(t.question||t.response||t.tools.length)&&this.turns.push(t),this.current=null}feed(t){if(t.type==="custom-title"&&t.customTitle&&(this.customTitle=t.customTitle),t.type==="summary"&&t.summary&&!this.summary&&(this.summary=t.summary),t.slug&&!this.slug&&(this.slug=t.slug),t.cwd&&!this.cwd&&(this.cwd=t.cwd),this.mode===null&&(t.type==="user"||t.type==="assistant")&&t.uuid&&(this.mode=t.isSidechain&&t.agentId?"sidechain":"main",this.mode==="sidechain"&&(this.sessionId=t.agentId)),!!t.isSidechain==(this.mode==="sidechain")){if(t.type==="system"&&t.subtype==="compact_boundary"){this.flush();const s=t.compactMetadata;this.pendingCompaction=`[Compaction] The source runner compacted its history here${s?.preTokens?` (${s.preTokens} → ${s.postTokens??"?"} tokens)`:""}. Everything above this point reached later turns only as a summary.`;return}if((t.type==="user"||t.type==="assistant")&&t.uuid&&t.sessionId&&!this.sessionId&&(this.sessionId=t.sessionId),t.type==="user"){const s=t.message?.content;if(Array.isArray(s)){for(const e of s)if(e.type==="tool_result"&&e.tool_use_id){const i=this.pendingTools.get(e.tool_use_id);if(i&&this.current){const a=p(N(e.content),b);this.current.tools.push({name:i.name,call:i.call,result:a.text,truncated:a.truncated,...i.paths.length?{paths:i.paths}:{},op:i.op,nativeCallId:e.tool_use_id,...i.url?{url:i.url}:{},...i.locator?{locator:i.locator}:{}}),this.pendingTools.delete(e.tool_use_id)}}}const n=f(s);if(!n.trim())return;if(/^\s*<task-notification>/.test(n)){if(this.current){const e=p(n,q);this.current.tools.push({name:"Agent",call:"(task notification)",result:e.text,truncated:e.truncated,op:"agent"})}return}this.flush(),this.firstQuestion||(this.firstQuestion=n.trim()),this.current={question:n,response:"",itemIds:t.uuid?[t.uuid]:[],tools:[],parentItemId:t.parentUuid??void 0,...t.timestamp?{at:t.timestamp}:{}},this.pendingCompaction&&(this.current.compactionBefore=this.pendingCompaction,this.pendingCompaction=void 0);return}if(t.type==="assistant"&&this.current){t.uuid&&this.current.itemIds.push(t.uuid);const s=t.message?.content,n=f(s);if(n.trim()&&(this.current.response=this.current.response?`${this.current.response}
4
+
5
+ ${n}`:n),Array.isArray(s)){for(const e of s)if(e.type==="tool_use"&&e.id&&e.name){const i=_(e.name),a=p(A(e.name,e.input),i==="write"||i==="edit"?B:M);this.pendingTools.set(e.id,{name:e.name,call:a.text,paths:w(e.input),op:i,...x(e.input)})}}}}}finish(){if(this.flush(),!this.sessionId)return null;const t=this.firstQuestion?.split(`
6
+ `).map(n=>n.trim()).find(n=>n&&!n.startsWith("<"))?.slice(0,80)??null,s=this.customTitle??this.summary??t??this.slug??`session ${this.sessionId.slice(0,8)}`;return{sessionId:this.sessionId,title:s,turns:L(this.turns),...this.cwd?{cwd:this.cwd}:{}}}toConversation(){const t=this.finish();return!t||t.turns.length===0?null:{title:t.title,messageCount:t.turns.length,source:"claude-code",sessionId:t.sessionId,build:()=>Q(t.turns,t.sessionId,t.cwd)}}}function y(o){const t=new $;for(const s of o.split(`
7
+ `))t.feedLine(s);return t}function F(o){const t=I(o,"",!1);return t.data.stepKind="note",O(t),t}function Q(o,t,s){const n=s?{cwd:s}:{},e=[],i=[];let a=null;const m=new Map,l=(u,c)=>{i.push({id:T(),source:u.id,target:c.id,type:"smoothstep"})};for(const u of o){let c=null;if(u.compactionBefore){const d=F(u.compactionBefore);d.data.importSource={runner:"claude-code",sessionId:t,itemIds:[],...n},e.push(d),c=d}const r=I(u.question,u.response,a===null);r.data.importSource={runner:"claude-code",sessionId:t,itemIds:u.itemIds,...n},r.data.source={question:r.data.question,response:r.data.response},S(r),r.data.attachments=k(u),e.push(r);const h=u.parentItemId?m.get(u.parentItemId):void 0;h?l(h,r):a&&l(a,r),c&&l(c,r);for(const d of u.itemIds)m.set(d,r);a=r}return{nodes:g(e,i),edges:i}}function E(o,t){const s=y(o).finish();return s?C(s.turns,s.sessionId,"claude-code",t,s.cwd):null}function R(o){return y(o).toConversation()}export{$ as ClaudeSessionCollector,E as claudeCodeSessionAsBranch,R as claudeCodeSessionConversation};
@@ -0,0 +1,12 @@
1
+ import{v as p,o as d,B as m}from"./index-6m02Pb4Q.js";import{t as y,a as _,d as g,e as I,m as x,f as T,s as C,A as w,g as v,T as A}from"./shared-CURSZnXt.js";function B(n){const t=[];for(const e of n.matchAll(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/gm))t.push(e[1].trim());return t}const h=I,L=n=>(n??[]).filter(t=>t.text&&(t.type==="input_text"||t.type==="output_text"||t.type==="text")).map(t=>t.text).join(`
2
+ `),S=/^\s*<\/?[a-zA-Z_][\w-]*[^>]*>/,q=n=>S.test(n)||n.trimStart().startsWith("# AGENTS.md instructions for "),O=n=>(n??[]).filter(t=>t.text&&(t.type==="input_text"||t.type==="text")&&!q(t.text)).map(t=>t.text).join(`
3
+ `),N=n=>typeof n=="string"?n:Array.isArray(n)?n.map(t=>t?.text??"").filter(Boolean).join(`
4
+ `):n==null?"":JSON.stringify(n);class ${turns=[];pendingCalls=new Map;current=null;pendingCompaction;sessionId=null;cwd="";day="";sawItems=!1;firstQuestion=null;parentThreadId=null;feedLine(t){const e=t.trim();if(!e)return;let s;try{s=JSON.parse(e)}catch{return}this.feed(s)}flush(){const t=this.current;t&&(t.question||t.response||t.tools.length)&&this.turns.push(t),this.current=null}ensure(){return this.current||(this.current={question:"",response:"",itemIds:[],tools:[]},this.pendingCompaction&&(this.current.compactionBefore=this.pendingCompaction,this.pendingCompaction=void 0)),this.current}feed(t){const e=t.payload??{};if(t.type==="session_meta"&&e.id&&!this.sessionId){this.sessionId=e.id,this.cwd=e.cwd??"",this.day=e.timestamp?.slice(0,10)??"",this.parentThreadId=e.parent_thread_id??null;return}if((t.type==="response_item"||t.type==="event_msg")&&(this.sawItems=!0),t.type==="compacted"){this.flush(),this.pendingCompaction="[Compaction] The source runner compacted its history here. Everything above this point reached later turns only as a summary.";return}if(t.type==="turn_context"||t.type==="event_msg"&&e.type==="task_started"){this.flush();const s=this.ensure();e.turn_id&&s.itemIds.push(e.turn_id);return}if(t.type==="response_item"){if(e.type==="message"){if(e.role==="user"){const s=O(e.content);if(s.trim()){this.firstQuestion||(this.firstQuestion=s.trim());const o=this.ensure();!o.at&&t.timestamp&&(o.at=t.timestamp),o.question=o.question?`${o.question}
5
+
6
+ ${s}`:s}}else if(e.role==="assistant"){const s=L(e.content);if(s.trim()){const o=this.ensure();o.response=o.response?`${o.response}
7
+
8
+ ${s}`:s}}}else if((e.type==="function_call"||e.type==="custom_tool_call")&&e.call_id&&e.name){const s=String(e.arguments??e.input??""),o=_(e.name),i=h(s,o==="edit"||o==="write"?w:v),r=o==="read"?(()=>{try{const a=JSON.parse(s);return typeof a.path=="string"&&a.path?[a.path]:[]}catch{return[]}})():[];this.pendingCalls.set(e.call_id,{name:e.name,call:i.text,paths:o==="edit"?B(s):r,op:o})}else if((e.type==="function_call_output"||e.type==="custom_tool_call_output")&&e.call_id){const s=this.pendingCalls.get(e.call_id);if(s){const o=this.ensure(),i=h(N(e.output),A);o.tools.push({name:s.name,call:s.call,result:i.text,truncated:i.truncated,...s.paths.length?{paths:s.paths}:{},op:s.op,nativeCallId:e.call_id}),this.pendingCalls.delete(e.call_id)}}}}finish(){if(this.flush(),!this.sessionId||!this.sawItems)return null;const t=[];let e;for(const i of this.turns){const r=t[t.length-1];!i.question.trim()&&r?(i.compactionBefore&&(e=e??i.compactionBefore),i.response&&(r.response=r.response?`${r.response}
9
+
10
+ ${i.response}`:i.response),r.tools.push(...i.tools),r.itemIds.push(...i.itemIds)):(e&&!i.compactionBefore&&(i.compactionBefore=e),e=void 0,t.push(i))}this.turns=t;const s=this.cwd.split("/").filter(Boolean).pop(),o=this.firstQuestion?.split(`
11
+ `)[0].slice(0,60)||["codex",s,this.day].filter(Boolean).join(" · ");return{sessionId:this.sessionId,title:o,turns:g(this.turns),subagent:!!this.parentThreadId,...this.cwd?{cwd:this.cwd}:{}}}toConversation(){const t=this.finish();return!t||t.turns.length===0?null:{title:t.title,messageCount:t.turns.length,source:"codex",sessionId:t.sessionId,build:()=>j(t.turns,t.sessionId,t.cwd)}}}function f(n){const t=new $;for(const e of n.split(`
12
+ `))t.feedLine(e);return t}function j(n,t,e){const s=e?{cwd:e}:{},o=[],i=[];let r=null;for(const a of n){let l=null;if(a.compactionBefore){const u=p(a.compactionBefore,"",!1);u.data.stepKind="note",u.data.importSource={runner:"codex",sessionId:t,itemIds:[],...s},x(u),o.push(u),l=u}const c=p(a.question||"(tool-only turn)",a.response,r===null);c.data.importSource={runner:"codex",sessionId:t,itemIds:a.itemIds,...s},c.data.source={question:c.data.question,response:c.data.response},c.data.attachments=T(a),C(c),o.push(c),r&&i.push({id:d(),source:r.id,target:c.id,type:"smoothstep"}),l&&i.push({id:d(),source:l.id,target:c.id,type:"smoothstep"}),r=c}return{nodes:m(o,i),edges:i}}function F(n,t){const e=f(n).finish();return e?y(e.turns,e.sessionId,"codex",t,e.cwd):null}function J(n){return f(n).toConversation()}export{$ as CodexSessionCollector,j as buildGraphFromTurns,F as codexSessionAsBranch,J as codexSessionConversation};
@@ -0,0 +1,6 @@
1
+ import{v as T,B as w,o as C}from"./index-6m02Pb4Q.js";import{t as x,a as l,b as f,c as p,e as d,r as g,d as L,T as m,A as h,g as I,f as S,s as A}from"./shared-CURSZnXt.js";function c(o,s=0){return typeof o=="string"?o:!Array.isArray(o)||s>2?"":o.map(t=>{if(!t||typeof t!="object")return"";const e=t;return e.type==="text"&&typeof e.text=="string"?e.text:e.type==="image"?"[image omitted]":e.type==="reasoning"?"":c(e.text??e.content,s+1)}).filter(Boolean).join(`
2
+ `)}function O(o,s,t){const e=l(o);if(e==="run"||/^run_code$/i.test(o)){const r=t??{};return d(typeof r.code=="string"?r.code:s,h)}const n=t&&typeof t=="object"?g(o,t):s;return d(n,e==="write"||e==="edit"?h:I)}const b=o=>{try{return JSON.parse(o??"")}catch{return}};class q{turns=[];pendingTools=new Map;current=null;sessionId=null;cwd=null;title=null;firstQuestion=null;feedLine(s){const t=s.trim();if(!t)return;let e;try{e=JSON.parse(t)}catch{return}this.feed(e)}flush(){const s=this.current;s&&(s.question||s.response||s.tools.length)&&this.turns.push(s),this.current=null}ensure(){return this.current||(this.current={question:"",response:"",itemIds:[],tools:[]}),this.current}feed(s){if(s.type==="session"&&s.id){this.sessionId||(this.sessionId=s.id),s.cwd&&!this.cwd&&(this.cwd=s.cwd);return}if(s.type==="session/title"&&s.data?.title&&!this.title){this.title=s.data.title;return}if(s.type==="user/message"){const t=s,e=t.data?.source?.kind;if(e&&e!=="user")return;const n=c(t.data?.content).trim();if(!n)return;this.firstQuestion||(this.firstQuestion=n.split(`
3
+ `)[0].slice(0,80)),this.flush();const r=this.ensure();r.question=n,r.itemIds=[t.data?.id??`u${t.seq}`],t.time&&(r.at=new Date(t.time).toISOString());return}if(s.type==="assistant/message"&&this.current){const t=s,e=t.data?.message?.content,n=c(e).trim(),r=t.data?.message?.id;r&&this.current.itemIds.push(r),n&&(this.current.response=this.current.response?`${this.current.response}
4
+
5
+ ${n}`:n);return}if(s.type==="tool/call"){const t=s;if(!t.data?.callId||!t.data?.name)return;const e=/^run_code$/i.test(t.data.name)?"run":l(t.data.name),n=b(t.data.arguments),r=O(t.data.name,t.data.arguments??"",n),i=e==="run"?{}:f(n);this.pendingTools.set(t.data.callId,{name:t.data.name,call:r.text,truncated:r.truncated,op:e,paths:e==="run"?[]:p(n),...i});return}if(s.type==="tool/result"){const t=s,e=t.data?.message?.source?.callId;if(!e)return;const n=this.pendingTools.get(e);if(!n)return;const r=d(c(t.data?.message?.content),m);this.ensure().tools.push({name:n.name,call:n.call,result:r.text,truncated:n.truncated||r.truncated,op:n.op,nativeCallId:e,...n.paths.length?{paths:n.paths}:{},...n.url?{url:n.url}:{},...n.locator?{locator:n.locator}:{}}),this.pendingTools.delete(e);return}if(s.type==="tool/code-dispatch"){const t=s.data;if(!t?.name||!t.subCallId)return;const e=p(t.arguments),n=f(t.arguments);if(!e.length&&!n.url)return;const r=l(t.name),i=d(g(t.name,t.arguments),r==="write"||r==="edit"?h:I),u=d(c(t.content),m);this.ensure().tools.push({name:t.name,call:i.text,result:u.text,truncated:i.truncated||u.truncated,op:r,nativeCallId:t.subCallId,...e.length?{paths:e}:{},...n.url?{url:n.url}:{},...n.locator?{locator:n.locator}:{}});return}}finish(){if(this.flush(),!this.sessionId)return null;const s=this.firstQuestion??null,t=this.title??s??`session ${this.sessionId.replace(/^session-/,"").slice(0,8)}`;return{sessionId:this.sessionId,title:t,turns:L(this.turns),...this.cwd?{cwd:this.cwd}:{}}}toConversation(){const s=this.finish();return!s||s.turns.length===0?null:{title:s.title,messageCount:s.turns.length,source:"dsh",sessionId:s.sessionId,build:()=>v(s.turns,s.sessionId,s.cwd)}}}function y(o){const s=new q;for(const t of o.split(`
6
+ `))s.feedLine(t);return s}function v(o,s,t){const e=t?{cwd:t}:{},n=[],r=[];let i=null;for(const u of o){const a=T(u.question||"(tool-only turn)",u.response,i===null);a.data.importSource={runner:"dsh",sessionId:s,itemIds:u.itemIds,...e},a.data.source={question:a.data.question,response:a.data.response},a.data.attachments=S(u),A(a),n.push(a),i&&r.push({id:C(),source:i.id,target:a.id,type:"smoothstep"}),i=a}return{nodes:w(n,r),edges:r}}function k(o,s){const t=y(o).finish();return t?x(t.turns,t.sessionId,"dsh",s,t.cwd):null}function B(o){return y(o).toConversation()}export{q as DshSessionCollector,v as buildGraphFromTurns,k as dshSessionAsBranch,B as dshSessionConversation};
@@ -0,0 +1,2 @@
1
+ import{a as c,b as l,c as p,x as h,t as u,f as m}from"./index-6m02Pb4Q.js";const b=/\[ThoughtDAG anchor: project=([\w-]+) node=([\w-]+) bundle=([\w-]+)(?: mode=(branch|continue))?\]/;function f(o){const n=o.match(b);return n?{project:n[1],node:n[2],bundle:n[3],mode:n[4]==="continue"?"continue":"branch"}:null}function g(o,n){const e=[];e.push(c("exp.mdIntro")),e.push("");for(const s of o.context.messages){const t=s.content[0].text;switch(s.source.layer){case"system":e.push(`**${c("exp.mdRole")}** ${t}`);break;case"chain":e.push(s.role==="assistant"?`**A:** ${t}`:`**Q:** ${t}`);break;default:e.push(t)}e.push("")}return e.push("---"),e.push(c("exp.mdOutro")),e.push(""),e.push(`[ThoughtDAG anchor: project=${n.project} node=${n.node} bundle=${n.bundle}${n.mode==="continue"?" mode=continue":""}]`),e.join(`
2
+ `)}async function w(o,n="branch"){const e=l.getState(),s=p.getState().activeId??"default",t=await h(o,e.nodes,e.edges,{now:new Date().toISOString(),projectId:s,staleIds:e.staleIds}),d={project:s,node:o,bundle:t.id,mode:n},i=g(t,d);try{await navigator.clipboard.writeText(i)}catch{return u("error",c("exp.clipboardFailed")),!1}{const a=[...new Set(t.context.messages.map(r=>r.source?.node_id).filter(r=>!!r))];e.logEvent("commit",o,{kind:"bundle",sha:t.integrity.content_hash,bundle:t.id,n:t.context.messages.length,...a.length?{m:a.slice(0,200).join(",")}:{},...a.length>200?{more:!0}:{}})}return u("success",m(c("exp.copied"),{n:t.context.messages.length,tok:t.budget.estimated_tokens}),12e3),!0}export{f as parseAnchor,g as renderHandoffMarkdown,w as takeToExperiment};