dsh-thoughtdag 0.4.5 → 0.4.7
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.
- package/README.md +11 -1
- package/dist-app/assets/{canonical-DDfsxGbh.js → canonical-D2XBb2dX.js} +2 -2
- package/dist-app/assets/{canvas-record-vunI4XSG.js → canvas-record-GBNDUaVp.js} +1 -1
- package/dist-app/assets/{claude-code-session-w7XeYCbv.js → claude-code-session-KqpMLSSi.js} +1 -1
- package/dist-app/assets/{codex-session-BteJdhnJ.js → codex-session-Dcy2uWFk.js} +1 -1
- package/dist-app/assets/{dsh-session-DtVkAUjy.js → dsh-session-DtUFFQiI.js} +2 -2
- package/dist-app/assets/{experiment-loop-cKs-OaUA.js → experiment-loop-DmwbMQzX.js} +1 -1
- package/dist-app/assets/index-D1pfymrb.css +1 -0
- package/dist-app/assets/{index-CZgf0TxH.js → index-DalA8OYo.js} +1 -1
- package/dist-app/assets/index-NvCD8Rvo.js +3 -0
- package/dist-app/assets/{index-ZY9zV6mj.js → index-XXbBaf-t.js} +1 -1
- package/dist-app/assets/{index-BgFLKHxw.js → index-zDvcuppH.js} +141 -139
- package/dist-app/assets/{live-mirror-Cil__utB.js → live-mirror-DHhvAkDw.js} +2 -2
- package/dist-app/assets/pi-session-BQNKkZYe.js +14 -0
- package/dist-app/assets/{sensitive-scan-NBqP2Srd.js → sensitive-scan-BVopW_mj.js} +1 -1
- package/dist-app/assets/{session-handoff-C_88Qy1y.js → session-handoff-CdTJCZJl.js} +2 -2
- package/dist-app/assets/{shared-0Cyt1YSM.js → shared-DWUtbV9j.js} +1 -1
- package/dist-app/assets/{turndown-plugin-gfm.cjs-BkQZDlXD.js → turndown-plugin-gfm.cjs-DmDDHBxg.js} +1 -1
- package/dist-app/assets/{update-check-Ca6SiYKC.js → update-check-DFw8Y8PB.js} +1 -1
- package/dist-app/index.html +2 -2
- package/lib/index.js +68 -6
- package/lib/why.mjs +199 -16
- package/package.json +1 -1
- package/dist-app/assets/index-DEHbIrRr.css +0 -1
- package/dist-app/assets/index-DbmziCje.js +0 -3
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-
|
|
2
|
-
import{_ as l,i as j,t as p,a as h,f as R}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-zDvcuppH.js","assets/index-D1pfymrb.css","assets/experiment-loop-DmwbMQzX.js","assets/index-NvCD8Rvo.js","assets/canonical-D2XBb2dX.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as l,i as j,t as p,a as h,f as R}from"./index-zDvcuppH.js";function K(d,S){return d.find(y=>(y.rel.split("/").pop()??y.rel).includes(S))}let D=!1,I=null;function H(){I?.()}function z(){const d=window.desktopSessions;if(!d||D)return;D=!0,d.watchStart();let S=!1,y=null;const g=async s=>{if(S){y=s;return}S=!0;try{window.dispatchEvent(new CustomEvent("td:sessions-changed"));const{useProjects:a,subscribedSessionIds:i}=await l(async()=>{const{useProjects:w,subscribedSessionIds:E}=await import("./index-zDvcuppH.js").then(b=>b.H);return{useProjects:w,subscribedSessionIds:E}},__vite__mapDeps([0,1])),{activeId:c,projects:o}=a.getState(),m=o.find(w=>w.id===c),t=await d.head(s.rootKey,s.rel,262144).catch(()=>"");if(!t)return;const e=j(t);if(!e)return;const f=!!m&&i(m).includes(e);let r=null;if(!f){if(o.some(v=>i(v).includes(e)))return;const{useStore:E}=await l(async()=>{const{useStore:v}=await import("./index-zDvcuppH.js").then(A=>A.G);return{useStore:v}},__vite__mapDeps([0,1]));if(!E.getState().nodes.some(v=>v.data.importSource?.sessionId===e)){const{parseAnchor:v}=await l(async()=>{const{parseAnchor:k}=await import("./experiment-loop-DmwbMQzX.js");return{parseAnchor:k}},__vite__mapDeps([2,0,1])),A=v(t);if(!A||!o.some(k=>k.id===A.project))return;if(r=A.project,r!==c){p("info",h("atlas.mountPending"),9e3);return}}}const{streamRunnerConversation:n}=await l(async()=>{const{streamRunnerConversation:w}=await import("./index-NvCD8Rvo.js");return{streamRunnerConversation:w}},__vite__mapDeps([3,0,1])),{importOrAppendConversation:u,shellSessionReader:_}=await l(async()=>{const{importOrAppendConversation:w,shellSessionReader:E}=await import("./canonical-D2XBb2dX.js");return{importOrAppendConversation:w,shellSessionReader:E}},__vite__mapDeps([4,0,1])),V=await n(_(s.rootKey,s.rel)).catch(()=>null),P=await u(V);P?.kind==="appended"?p("success",R(h("atlas.liveAppended"),{n:P.turns}),8e3):P?.kind==="mounted"&&p("success",R(h(P.mode==="continue"?"atlas.mountedChapter":"atlas.mountedBranch"),{n:P.turns}),9e3)}finally{if(S=!1,y){const a=y;y=null,g(a)}}};d.onSessionsChanged(s=>{g(s)});const C=async s=>{if(!s)return;const{useStore:a}=await l(async()=>{const{useStore:o}=await import("./index-zDvcuppH.js").then(m=>m.G);return{useStore:o}},__vite__mapDeps([0,1])),{useUiStore:i}=await l(async()=>{const{useUiStore:o}=await import("./index-zDvcuppH.js").then(m=>m.F);return{useUiStore:o}},__vite__mapDeps([0,1])),c=a.getState().nodes.find(o=>o.data.importSource?.itemIds?.includes(s));c&&i.getState().setArrivalFocusNodeId(c.id)},T=async(s,a)=>{const{useProjects:i,switchProject:c}=await l(async()=>{const{useProjects:e,switchProject:f}=await import("./index-zDvcuppH.js").then(r=>r.H);return{useProjects:e,switchProject:f}},__vite__mapDeps([0,1])),o=i.getState().projects,m=o.filter(e=>e.name===s),t=o.find(e=>e.id===s)??(m.length===1?m[0]:void 0);if(!t){p("error",h("handoff.deeplinkMiss"));return}if(await c(t.id),a){const{useStore:e}=await l(async()=>{const{useStore:r}=await import("./index-zDvcuppH.js").then(n=>n.G);return{useStore:r}},__vite__mapDeps([0,1])),{useUiStore:f}=await l(async()=>{const{useUiStore:r}=await import("./index-zDvcuppH.js").then(n=>n.F);return{useUiStore:r}},__vite__mapDeps([0,1]));e.getState().nodes.some(r=>r.id===a)&&f.getState().setArrivalFocusNodeId(a)}},O=async s=>{let a="",i="";try{const n=new URL(s),u=n.searchParams.get("canvas");if(u){await T(u,n.searchParams.get("node")??"");return}a=n.searchParams.get("session")??"",i=n.searchParams.get("turn")??""}catch{return}if(!/^[A-Za-z0-9_-]{8,}$/.test(a))return;/^[A-Za-z0-9_-]*$/.test(i)||(i="");const c=await d.roots().catch(()=>[]);let o=null;for(const n of c){const u=await d.list(n.key).catch(()=>[]),_=K(u,a);if(_){o={rootKey:n.key,rel:_.rel};break}}if(!o){const n=[];for(const u of c)for(const _ of await d.list(u.key).catch(()=>[]))n.push({rootKey:u.key,rel:_.rel,mtime:_.mtime});n.sort((u,_)=>_.mtime-u.mtime);for(const u of n.slice(0,40)){const _=await d.head(u.rootKey,u.rel,262144).catch(()=>"");if(_&&j(_)===a){o=u;break}}}if(!o){p("error",h("handoff.deeplinkMiss"));return}const{streamRunnerConversation:m}=await l(async()=>{const{streamRunnerConversation:n}=await import("./index-NvCD8Rvo.js");return{streamRunnerConversation:n}},__vite__mapDeps([3,0,1])),{importOrAppendConversation:t,shellSessionReader:e}=await l(async()=>{const{importOrAppendConversation:n,shellSessionReader:u}=await import("./canonical-D2XBb2dX.js");return{importOrAppendConversation:n,shellSessionReader:u}},__vite__mapDeps([4,0,1])),f=await m(e(o.rootKey,o.rel)).catch(()=>null),r=await t(f);r?r.kind==="appended"?p("success",R(h("atlas.liveAppended"),{n:r.turns}),8e3):r.kind==="mounted"?p("success",R(h(r.mode==="continue"?"atlas.mountedChapter":"atlas.mountedBranch"),{n:r.turns}),9e3):r.kind==="imported"&&p("success",R(h("toast.importedChats"),{n:1,m:r.nodeCount}),8e3):p("error",h("handoff.notASession")),r&&i&&await C(i)};d.onDeepLink?.(s=>{O(s)}),(async()=>{const{bootProjects:s}=await l(async()=>{const{bootProjects:i}=await import("./index-zDvcuppH.js").then(c=>c.H);return{bootProjects:i}},__vite__mapDeps([0,1]));await s();const a=await d.pendingDeepLink?.().catch(()=>null);a&&O(a)})();const L="thoughtdag.atlas.sweepmark";I=async()=>{const{bootProjects:s}=await l(async()=>{const{bootProjects:t}=await import("./index-zDvcuppH.js").then(e=>e.H);return{bootProjects:t}},__vite__mapDeps([0,1]));await s();const a=await d.roots().catch(()=>[]),i=[];for(const t of a){const e=await d.list(t.key).catch(()=>[]);for(const f of e)i.push({rootKey:t.key,rel:f.rel,mtime:f.mtime,size:f.size})}let c={};try{c=JSON.parse(localStorage.getItem(L)??"{}")}catch{}const o=Object.keys(c).length===0;i.sort((t,e)=>e.mtime-t.mtime);const m=i.filter((t,e)=>{const f=`${t.mtime}|${t.size}`;return c[`${t.rootKey}|${t.rel}`]===f?!1:o?e<30:!0});for(const t of m)await g({rootKey:t.rootKey,rel:t.rel});for(const t of i)c[`${t.rootKey}|${t.rel}`]=`${t.mtime}|${t.size}`;localStorage.setItem(L,JSON.stringify(c))},I()}export{K as pickSessionFile,z as startLiveMirror,H as sweepRecentSessions};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{v as w,B as x,o as T}from"./index-zDvcuppH.js";import{t as A,a as I,e as l,d as C,T as L,A as h,g as m,f as O,s as S}from"./shared-DWUtbV9j.js";const f=r=>typeof r=="string"?r:Array.isArray(r)?r.filter(t=>t&&t.type==="text"&&typeof t.text=="string").map(t=>t.text).join(`
|
|
2
|
+
`):"";function b(r,t){const s=t&&typeof t=="object"?t:{},e=I(r),n=typeof s.path=="string"&&s.path&&(e==="read"||e==="edit"||e==="write")?[s.path]:[];let o;if(e==="read"&&(typeof s.offset=="number"||typeof s.limit=="number")){const c=Math.max(1,typeof s.offset=="number"?s.offset:1),d=typeof s.limit=="number"?c+Math.max(0,s.limit)-1:c;o={lines:[c,Math.max(c,d)]}}if(e==="write"&&typeof s.content=="string")return{...l(`${s.path??""}
|
|
3
|
+
|
|
4
|
+
${s.content}`,h),paths:n};if(e==="edit"){const c=Array.isArray(s.edits)?s.edits:typeof s.newText=="string"?[{oldText:s.oldText,newText:s.newText}]:[];if(c.length){const d=c.map(i=>`${s.path??""}
|
|
5
|
+
--- old
|
|
6
|
+
${i.oldText??""}
|
|
7
|
+
+++ new
|
|
8
|
+
${i.newText??""}`).join(`
|
|
9
|
+
|
|
10
|
+
`);return{...l(d,h),paths:n}}}return e==="run"&&typeof s.command=="string"?{...l(s.command,m),paths:n}:{...l(JSON.stringify(t??{}),m),paths:n,...o?{locator:o}:{}}}class q{turns=[];pending=new Map;current=null;sessionId=null;cwd=null;firstQuestion=null;feedLine(t){const s=t.trim();if(!s)return;let e;try{e=JSON.parse(s)}catch{return}this.feed(e)}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==="session"&&typeof t.id=="string"){this.sessionId||(this.sessionId=t.id),typeof t.cwd=="string"&&!this.cwd&&(this.cwd=t.cwd);return}if(t.type!=="message"){this.current&&typeof t.id=="string"&&this.current.itemIds.push(t.id);return}const s=t.message;if(s){if(s.role==="user"){const e=f(s.content).trim();if(!e)return;this.flush(),this.firstQuestion||(this.firstQuestion=e.split(`
|
|
11
|
+
`)[0].slice(0,80));const n=typeof t.timestamp=="string"?t.timestamp:typeof s.timestamp=="number"?new Date(s.timestamp).toISOString():void 0;this.current={question:e,response:"",itemIds:typeof t.id=="string"?[t.id]:[],tools:[],...typeof t.parentId=="string"?{parentItemId:t.parentId}:{},...n?{at:n}:{}};return}if(s.role==="assistant"){const e=this.current??(this.current={question:"",response:"",itemIds:[],tools:[]});typeof t.id=="string"&&e.itemIds.push(t.id);const n=f(s.content).trim();if(n&&(e.response=e.response?`${e.response}
|
|
12
|
+
|
|
13
|
+
${n}`:n),Array.isArray(s.content))for(const o of s.content){if(o?.type!=="toolCall"||typeof o.id!="string"||typeof o.name!="string")continue;const a=b(o.name,o.arguments);this.pending.set(o.id,{name:o.name,call:a.text,truncated:a.truncated,op:I(o.name),paths:a.paths,...a.locator?{locator:a.locator}:{}})}return}if(s.role==="toolResult"){const e=s.toolCallId;if(!e)return;const n=this.pending.get(e);if(!n)return;const o=this.current??(this.current={question:"",response:"",itemIds:[],tools:[]});typeof t.id=="string"&&o.itemIds.push(t.id);const a=l(f(s.content),L);o.tools.push({name:n.name,call:n.call,result:a.text,truncated:n.truncated||a.truncated,op:n.op,nativeCallId:e,...n.paths.length?{paths:n.paths}:{},...n.locator?{locator:n.locator}:{}}),this.pending.delete(e)}}}finish(){if(this.flush(),!this.sessionId)return null;const t=this.firstQuestion??`session ${this.sessionId.slice(0,8)}`;return{sessionId:this.sessionId,title:t,turns:C(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:"pi",sessionId:t.sessionId,build:()=>v(t.turns,t.sessionId,t.cwd)}}}function y(r){const t=new q;for(const s of r.split(`
|
|
14
|
+
`))t.feedLine(s);return t}function v(r,t,s){const e=s?{cwd:s}:{},n=[],o=[],a=new Map,c=(u,i)=>o.push({id:T(),source:u.id,target:i.id,type:"smoothstep"});let d=null;for(const u of r){const i=w(u.question||"(tool-only turn)",u.response,d===null);i.data.importSource={runner:"pi",sessionId:t,itemIds:u.itemIds,...e},i.data.source={question:i.data.question,response:i.data.response},i.data.attachments=O(u),S(i),n.push(i);const p=u.parentItemId?a.get(u.parentItemId):void 0;p?c(p,i):d&&c(d,i);for(const g of u.itemIds)a.set(g,i);d=i}return{nodes:x(n,o),edges:o}}function _(r,t){const s=y(r).finish();return s?A(s.turns,s.sessionId,"pi",t,s.cwd):null}function Q(r){return y(r).toConversation()}export{q as PiSessionCollector,v as buildGraphFromTurns,_ as piSessionAsBranch,Q as piSessionConversation};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{f as c,a,w as g}from"./index-
|
|
1
|
+
import{f as c,a,w as g}from"./index-zDvcuppH.js";const k=[{kind:"sk-… key",re:/\bsk-[A-Za-z0-9_-]{16,}\b/g},{kind:"GitHub token",re:/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g},{kind:"AWS access key",re:/\bAKIA[0-9A-Z]{16}\b/g},{kind:"Slack token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g},{kind:"Google API key",re:/\bAIza[0-9A-Za-z_-]{35}\b/g},{kind:"JWT",re:/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{6,}\b/g},{kind:"private key block",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/g},{kind:"token assignment",re:/\b(?:API_KEY|APIKEY|SECRET|TOKEN|PASSWORD|ACCESS_KEY|AUTH_TOKEN)[A-Z_]*\s*[=:]\s*['"]?[A-Za-z0-9_/+-]{16,}/g},{kind:"HuggingFace token",re:/\bhf_[A-Za-z0-9]{30,}\b/g},{kind:"npm token",re:/\bnpm_[A-Za-z0-9]{30,}\b/g}],f=t=>t.length<=10?`${t.slice(0,4)}…`:`${t.slice(0,6)}…${t.slice(-2)}`;function o(t,e,s){if(t)for(const{kind:i,re:n}of k){n.lastIndex=0;const r=n.exec(t);if(r&&s.push({where:e,kind:i,sample:f(r[0])}),s.length>=20)return}}function l(t){const e=[];for(const s of t){const i=(s.data.question||s.data.summaries?.[0]||s.id).replace(/\s+/g," ").slice(0,28);o(s.data.question,i,e);for(const n of s.data.responses??[])o(n,i,e);for(const n of s.data.attachments??[])n.type.startsWith("image/")||o(n.content,`${i} · ${n.name}`,e);if(e.length>=20)break}return e}async function b(t){const e=l(t);if(e.length===0)return!0;const s=e.slice(0,5).map(n=>`· ${n.where} — ${n.kind}(${n.sample})`).join(`
|
|
2
2
|
`),i=e.length>5?`
|
|
3
3
|
${c(a("sensitive.more"),{n:e.length-5})}`:"";return g({title:a("sensitive.title"),message:`${c(a("sensitive.body"),{n:e.length})}
|
|
4
4
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/canonical-
|
|
2
|
-
import{t as n,a as e,_ as p,f as a,u as h}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/canonical-D2XBb2dX.js","assets/index-zDvcuppH.js","assets/index-D1pfymrb.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{t as n,a as e,_ as p,f as a,u as h}from"./index-zDvcuppH.js";const l=/^http:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?\//i;async function w(){const s=window.location.hash,r=s.match(/[#&]import-url=([^&]+)/);if(!r)return;const c=/[#&]mode=harvest\b/.test(s);history.replaceState(null,"",window.location.pathname+window.location.search);const i=decodeURIComponent(r[1]);if(!l.test(i)){n("error",e("handoff.notLoopback"),9e3);return}try{const o=await fetch(i);if(!o.ok)throw new Error(`HTTP ${o.status}`);const d=await o.text(),{importOrAppendSession:f}=await p(async()=>{const{importOrAppendSession:u}=await import("./canonical-D2XBb2dX.js");return{importOrAppendSession:u}},__vite__mapDeps([0,1,2])),t=await f(d);if(!t)throw new Error(e("handoff.notASession"));t.kind==="appended"?n("success",a(e("atlas.appended"),{n:t.turns}),9e3):t.kind==="mounted"?n("success",a(e(t.mode==="continue"?"atlas.mountedChapter":"atlas.mountedBranch"),{n:t.turns}),12e3):t.kind==="opened"?n("info",e("atlas.upToDate"),6e3):n("info",a(e("handoff.saved"),{n:t.nodeCount}),12e3,{label:e("handoff.backupAction"),run:()=>h.getState().setBackupDialogOpen(!0)})}catch(o){n("error",a(e("handoff.failed"),{msg:o instanceof Error?o.message:String(o)}),12e3)}}export{w as consumeSessionHandoff};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{v as m,o as p,B as h,C as g}from"./index-
|
|
1
|
+
import{v as m,o as p,B as h,C as g}from"./index-zDvcuppH.js";const _=[[/^(Read|NotebookRead|read_file|view_image)$/i,"read"],[/^(Write|write_file)$/i,"write"],[/^(Edit|MultiEdit|NotebookEdit|apply_patch)$/i,"edit"],[/^(Bash|BashOutput|Shell|exec_command|local_shell|write_stdin)$/i,"run"],[/^(Grep|Glob|LS|Search|WebSearch|web_search)$/i,"search"],[/^(WebFetch|Fetch)$/i,"fetch"],[/^(Task|Agent)$/i,"agent"]];function y(e){return _.find(([t])=>t.test(e))?.[1]??"other"}const x=800,O=32e3,S=4e3,I=(e,t)=>e.length>t?{text:`${e.slice(0,t)}
|
|
2
2
|
…[truncated, ${e.length} chars total]`,truncated:!0}:{text:e,truncated:!1},$=["<command-name>/thoughtdag</command-name>","[[thoughtdag:command]]"];function M(e){return e.filter(t=>!$.some(n=>t.question.includes(n)))}function w(e){e.width=460}function b(e){const t=g(e.data.response,90);t&&(e.data.summaries=[t])}function L(e){return e.tools.map(t=>({id:p(),name:`tool: ${t.name}${t.truncated?" (truncated)":""}`,type:"text/plain",size:t.call.length+t.result.length,content:`[call] ${t.call}
|
|
3
3
|
[result]
|
|
4
4
|
${t.result}`,...t.paths?.length?{paths:t.paths}:{},...t.op?{op:t.op}:{}}))}function k(e,t,n,s,i){if(e.length===0)return null;const r=[],l=[];let u={id:s.id};for(const o of e){const a=m(o.question||"(tool-only turn)",o.response,!1);a.data.importSource={runner:n,sessionId:t,itemIds:o.itemIds,...i?{cwd:i}:{}},a.data.source={question:a.data.question,response:a.data.response},a.data.attachments=L(o),b(a),r.length===0&&(a.data.isBranch=!0),r.push(a),l.push({id:p(),source:u.id,target:a.id,type:"smoothstep"}),u=a}const c=h(r,l.filter(o=>o.source!==s.id)),f=Math.min(...c.map(o=>o.position.x)),d=Math.min(...c.map(o=>o.position.y));for(const o of c)o.position={x:o.position.x-f+s.x+560,y:o.position.y-d+s.y};return{nodes:c,edges:l,turnCount:e.length}}function A(e){const t=e??{},n={};typeof t.url=="string"&&/^https?:\/\//.test(t.url)&&(n.url=t.url);const s={};if(typeof t.pages=="string"&&t.pages.trim()&&(s.pages=t.pages.trim()),typeof t.offset=="number"||typeof t.limit=="number"){const i=Math.max(1,typeof t.offset=="number"?t.offset:1),r=typeof t.limit=="number"?i+Math.max(0,t.limit)-1:i;s.lines=[i,Math.max(i,r)]}return Object.keys(s).length&&(n.locator=s),n}function C(e){const t=e??{},n=t.file_path??t.notebook_path;return typeof n=="string"&&n?[n]:[]}function q(e,t){const n=t??{},s=y(e);return s==="write"&&typeof n.content=="string"?`${n.file_path??""}
|
package/dist-app/assets/{turndown-plugin-gfm.cjs-BkQZDlXD.js → turndown-plugin-gfm.cjs-DmDDHBxg.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{A as W}from"./index-
|
|
1
|
+
import{A as W}from"./index-zDvcuppH.js";function Y(d,p){for(var g=0;g<p.length;g++){const s=p[g];if(typeof s!="string"&&!Array.isArray(s)){for(const c in s)if(c!=="default"&&!(c in d)){const o=Object.getOwnPropertyDescriptor(s,c);o&&Object.defineProperty(d,c,o.get?o:{enumerable:!0,get:()=>s[c]})}}}return Object.freeze(Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}))}var u={},E;function J(){if(E)return u;E=1,Object.defineProperty(u,"__esModule",{value:!0});var d=/highlight-(?:text|source)-([a-z0-9]+)/;function p(t){t.addRule("highlightedCodeBlock",{filter:function(e){var r=e.firstChild;return e.nodeName==="DIV"&&d.test(e.className)&&r&&r.nodeName==="PRE"},replacement:function(e,r,n){var l=r.className||"",i=(l.match(d)||[null,""])[1];return`
|
|
2
2
|
|
|
3
3
|
`+n.fence+i+`
|
|
4
4
|
`+r.firstChild.textContent+`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as u,a as n,f}from"./index-
|
|
1
|
+
import{t as u,a as n,f}from"./index-zDvcuppH.js";const h=15*6e4;let i=!1;const d=new URLSearchParams(window.location.search),s=d.get("dv"),p=d.get("su")==="1",w=30*6e4;let c=!1,r=0;async function a(){if(!(!s||p||c)&&!(Date.now()-r<w)){r=Date.now();try{const t=await fetch("https://api.github.com/repos/chenxiachan/thoughtdag/releases?per_page=1");if(!t.ok)return;const o=(await t.json())?.[0]?.tag_name?.replace(/^v/,"");if(!o||o===s)return;c=!0,u("info",f(n("update.desktopAvailable"),{v:o}),0,{label:n("update.desktopDownload"),run:()=>window.open("https://chenxiachan.github.io/thoughtdag/#download","_blank")})}catch{}}}function v(){for(const t of document.querySelectorAll("script[src]")){const e=t.src.match(/assets\/index-[^/?#]+\.js/);if(e)return e[0]}return null}async function m(){try{const t=await fetch(`${window.location.pathname}?u=${Date.now()}`,{cache:"no-store"});if(!t.ok)return null;const e=(await t.text()).match(/assets\/index-[^"'?#]+\.js/);return e?e[0]:null}catch{return null}}async function l(){if(i)return;const t=v();if(!t)return;const e=await m();e&&e!==t&&(i=!0,u("info",n("update.available"),0,{label:n("update.refresh"),run:()=>window.location.reload()}))}function b(){document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&(l(),a())}),setInterval(()=>{l(),a()},h),s&&setTimeout(()=>{a()},5e3)}export{b as bootUpdateCheck};
|
package/dist-app/index.html
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
<meta name="twitter:title" content="ThoughtDAG — Your thinking deserves a map" />
|
|
23
23
|
<meta name="twitter:description" content="Wires are the context: an infinite canvas where LLM conversations grow into an editable thought graph. No signup; the example canvas needs no key." />
|
|
24
24
|
<meta name="twitter:image" content="https://app.thoughtdag.workers.dev/og-twitter.jpg" />
|
|
25
|
-
<script type="module" crossorigin src="/thoughtdag/assets/index-
|
|
26
|
-
<link rel="stylesheet" crossorigin href="/thoughtdag/assets/index-
|
|
25
|
+
<script type="module" crossorigin src="/thoughtdag/assets/index-zDvcuppH.js"></script>
|
|
26
|
+
<link rel="stylesheet" crossorigin href="/thoughtdag/assets/index-D1pfymrb.css">
|
|
27
27
|
</head>
|
|
28
28
|
<body>
|
|
29
29
|
<div id="root"></div>
|
package/lib/index.js
CHANGED
|
@@ -75,7 +75,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
75
75
|
import { zstdDecompressSync } from 'node:zlib'
|
|
76
76
|
|
|
77
77
|
export const name = 'thoughtdag'
|
|
78
|
-
export const inject = ['webServer', 'sessions', 'sessionController', 'agents', 'llm', 'attachments', 'web', 'tools', 'commands', 'systemPrompt']
|
|
78
|
+
export const inject = ['webServer', 'sessions', 'sessionController', 'agents', 'llm', 'attachments', 'web', 'tools', 'commands', 'systemPrompt', 'approval']
|
|
79
79
|
|
|
80
80
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
81
81
|
const APP_DIR = resolve(__dirname, '../dist-app')
|
|
@@ -368,6 +368,7 @@ const SOURCE = { kind: 'plugin', plugin: 'dsh-thoughtdag' }
|
|
|
368
368
|
const FILE_ROOTS = {
|
|
369
369
|
'claude-projects': join(os.homedir(), '.claude', 'projects'),
|
|
370
370
|
'codex-sessions': join(os.homedir(), '.codex', 'sessions'),
|
|
371
|
+
'pi-sessions': join(os.homedir(), '.pi', 'agent', 'sessions'),
|
|
371
372
|
}
|
|
372
373
|
const FILE_READ_MAX = 256 * 1024 * 1024
|
|
373
374
|
|
|
@@ -544,9 +545,55 @@ function toolQuery(name, args) {
|
|
|
544
545
|
return first ? first.slice(0, 120) : ''
|
|
545
546
|
}
|
|
546
547
|
|
|
548
|
+
// ── approvals from the canvas ──────────────────────────────────────────
|
|
549
|
+
// A turn launched from the canvas runs behind the harness's own approval
|
|
550
|
+
// panel, which the canvas view covers. So the plugin answers first: while a
|
|
551
|
+
// canvas turn is running, its session is registered here; an approval the
|
|
552
|
+
// harness asks for that session becomes an `approval` frame on the turn's
|
|
553
|
+
// stream, the node shows the question, and the person's answer comes back
|
|
554
|
+
// through POST /approvals/:id. When the canvas stream is gone, the request
|
|
555
|
+
// is handed down the chain (`next()`) to the harness's panel instead.
|
|
556
|
+
|
|
557
|
+
/** sessionId → the canvas turn running in it: its frame emitter, its
|
|
558
|
+
* close probe, and the tool calls seen so far (callId → name, arguments). */
|
|
559
|
+
const canvasTurns = new Map()
|
|
560
|
+
/** approval id → the resolver waiting for the person's decision */
|
|
561
|
+
const pendingApprovals = new Map()
|
|
562
|
+
|
|
563
|
+
const APPROVAL_OUTCOMES = new Set(['allowed-once', 'rejected'])
|
|
564
|
+
|
|
565
|
+
function installApprovalAnswerer(ctx) {
|
|
566
|
+
ctx.on('approval/request', async function (req, next) {
|
|
567
|
+
const entry = canvasTurns.get(req?.agent?.id)
|
|
568
|
+
if (!entry) return next()
|
|
569
|
+
const id = 'td-' + randomUUID()
|
|
570
|
+
const call = req.callId !== undefined ? entry.calls.get(req.callId) : undefined
|
|
571
|
+
const name = call?.name ?? req.toolName
|
|
572
|
+
entry.emit({ approval: {
|
|
573
|
+
id, toolName: req.toolName, callId: req.callId ?? null, reason: req.reason ?? null,
|
|
574
|
+
name, query: call ? toolQuery(name, call.arguments) : '', arguments: typeof call?.arguments === 'string' ? call.arguments : (call?.arguments ? JSON.stringify(call.arguments) : null),
|
|
575
|
+
} })
|
|
576
|
+
let clear
|
|
577
|
+
const decision = new Promise(resolve => { pendingApprovals.set(id, { resolve, sessionId: req.agent.id }) })
|
|
578
|
+
const closed = new Promise(resolve => { const t = setInterval(() => { if (entry.isClosed()) { clearInterval(t); resolve('closed') } }, 500); clear = () => clearInterval(t) })
|
|
579
|
+
const aborted = new Promise(resolve => {
|
|
580
|
+
if (!req.signal) return
|
|
581
|
+
if (req.signal.aborted) resolve('aborted')
|
|
582
|
+
else req.signal.addEventListener('abort', () => resolve('aborted'), { once: true })
|
|
583
|
+
})
|
|
584
|
+
const r = await Promise.race([decision, closed, aborted])
|
|
585
|
+
pendingApprovals.delete(id)
|
|
586
|
+
clear?.()
|
|
587
|
+
if (r === 'closed') return next()
|
|
588
|
+
const outcome = r === 'aborted' ? 'cancelled' : r
|
|
589
|
+
entry.emit({ approvalDecided: { id, outcome } })
|
|
590
|
+
return outcome
|
|
591
|
+
}, true)
|
|
592
|
+
}
|
|
593
|
+
|
|
547
594
|
/** Run one question through the harness's agent loop in a fresh session and
|
|
548
595
|
* report it as SSE-style frames via `emit`; resolves when the turn ends. */
|
|
549
|
-
async function runAgentTurn(ctx, body, emit, isClosed) {
|
|
596
|
+
async function runAgentTurn(ctx, body, emit, isClosed, { answerApprovals = true } = {}) {
|
|
550
597
|
const { question, context } = compileForAgent(body)
|
|
551
598
|
// continue the session the canvas mirrors (a tail follow-up), else a fresh
|
|
552
599
|
// session in the requested working directory (the canvas's project)
|
|
@@ -559,6 +606,10 @@ async function runAgentTurn(ctx, body, emit, isClosed) {
|
|
|
559
606
|
sessionId = (await ctx.sessionController.create({ ...cwd })).sessionId
|
|
560
607
|
}
|
|
561
608
|
emit({ harnessSession: sessionId, continued: sessionId === continueId })
|
|
609
|
+
// a streaming caller can show and answer approvals; a one-shot caller
|
|
610
|
+
// (/claude) cannot, so its requests fall through to the harness's own panel
|
|
611
|
+
const turnEntry = { emit, isClosed, calls: new Map() }
|
|
612
|
+
if (answerApprovals) canvasTurns.set(sessionId, turnEntry)
|
|
562
613
|
const hasImages = Array.isArray(body?.images) && body.images.length > 0
|
|
563
614
|
if (hasImages) {
|
|
564
615
|
const vm = await visionModel(ctx).catch(() => null)
|
|
@@ -588,9 +639,8 @@ async function runAgentTurn(ctx, body, emit, isClosed) {
|
|
|
588
639
|
// chunks did not reach us live (e.g. a compacted row): the whole text at once
|
|
589
640
|
const text = (event.data?.message?.content ?? []).filter(b => b.type === 'text').map(b => b.text).join('')
|
|
590
641
|
if (text) { fullText += text; emit({ text }) }
|
|
591
|
-
} else if (event.type === 'tool/call') {
|
|
592
|
-
|
|
593
|
-
} else if (event.type === 'tool/code-dispatch-start') {
|
|
642
|
+
} else if (event.type === 'tool/call' || event.type === 'tool/code-dispatch-start') {
|
|
643
|
+
if (event.data?.callId) turnEntry.calls.set(event.data.callId, { name: event.data?.name ?? 'tool', arguments: event.data?.arguments })
|
|
594
644
|
emit({ tool: { name: event.data?.name ?? 'tool', query: toolQuery(event.data?.name, event.data?.arguments) } })
|
|
595
645
|
} else if (event.type === 'turn/end') {
|
|
596
646
|
done()
|
|
@@ -610,6 +660,7 @@ async function runAgentTurn(ctx, body, emit, isClosed) {
|
|
|
610
660
|
if (isClosed()) { try { agent.cancel({ kind: 'user' }) } catch { /* best effort */ } }
|
|
611
661
|
} finally {
|
|
612
662
|
if (typeof off === 'function') off()
|
|
663
|
+
if (canvasTurns.get(sessionId) === turnEntry) canvasTurns.delete(sessionId)
|
|
613
664
|
}
|
|
614
665
|
return { sessionId, text: fullText }
|
|
615
666
|
}
|
|
@@ -819,11 +870,21 @@ export async function apply(ctx, config) {
|
|
|
819
870
|
}
|
|
820
871
|
// ── model connection (the SPA's proxy protocol, on the harness's providers) ──
|
|
821
872
|
if (path === '/models' && req.method === 'GET') return sendJson(res, 200, await modelsPayload(ctx))
|
|
873
|
+
const approvalRoute = /^\/approvals\/([^/]+)$/.exec(path)
|
|
874
|
+
if (approvalRoute !== null && req.method === 'POST') {
|
|
875
|
+
const id = decodeURIComponent(approvalRoute[1])
|
|
876
|
+
const body = await readJson(req, MAX_WRITE_BODY_BYTES)
|
|
877
|
+
const pending = pendingApprovals.get(id)
|
|
878
|
+
if (!pending) return sendJson(res, 404, { error: 'no such pending approval' })
|
|
879
|
+
const outcome = APPROVAL_OUTCOMES.has(body?.outcome) ? body.outcome : 'rejected'
|
|
880
|
+
pending.resolve(outcome)
|
|
881
|
+
return sendJson(res, 200, { id, outcome })
|
|
882
|
+
}
|
|
822
883
|
if ((path === '/stream' || path === '/claude') && req.method === 'POST') {
|
|
823
884
|
const body = await readJson(req, MAX_CALL_BODY_BYTES)
|
|
824
885
|
if (body?.model === AGENT_MODEL) {
|
|
825
886
|
if (path === '/claude') {
|
|
826
|
-
const r = await runAgentTurn(ctx, body, () => {}, () => false)
|
|
887
|
+
const r = await runAgentTurn(ctx, body, () => {}, () => false, { answerApprovals: false })
|
|
827
888
|
return sendJson(res, 200, { text: r.text, model: AGENT_MODEL, harnessSession: r.sessionId })
|
|
828
889
|
}
|
|
829
890
|
res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-cache', connection: 'keep-alive' })
|
|
@@ -934,5 +995,6 @@ export async function apply(ctx, config) {
|
|
|
934
995
|
ctx.effect(() => ctx.webServer.register({ kind: 'prefix', path: prefix + '/api', handler: api }), 'thoughtdag: api')
|
|
935
996
|
ctx.effect(() => ctx.webServer.register({ kind: 'prefix', path: prefix, handler: staticHandler }), 'thoughtdag: static')
|
|
936
997
|
ctx.logger.info('[dsh-thoughtdag] ThoughtDAG mounted at ' + prefix + '/')
|
|
998
|
+
installApprovalAnswerer(ctx)
|
|
937
999
|
await installWhyLayer(ctx, config)
|
|
938
1000
|
}
|
package/lib/why.mjs
CHANGED
|
@@ -80,11 +80,10 @@ function autoLayout(allNodes, allEdges) {
|
|
|
80
80
|
const mats = allEdges.filter((e) => e.target === root.id && !e.data?.isCrossLink && contentIds.has(e.source)).map((e) => allNodes.find((n) => n.id === e.source)).filter((m) => !!m);
|
|
81
81
|
if (mats.length === 0) continue;
|
|
82
82
|
const lowest = mats.reduce((a, b) => a.position.y + nodeHeight(a) > b.position.y + nodeHeight(b) ? a : b);
|
|
83
|
-
const midX = mats.reduce((t, m) => t + m.position.x, 0) / mats.length;
|
|
84
83
|
const k = perMaterialCount.get(lowest.id) ?? 0;
|
|
85
84
|
perMaterialCount.set(lowest.id, k + 1);
|
|
86
85
|
materialAnchors.set(root.id, {
|
|
87
|
-
x:
|
|
86
|
+
x: lowest.position.x - 60 + k * (LAYOUT_COL_WIDTH + LAYOUT_H_GAP),
|
|
88
87
|
y: lowest.position.y + nodeHeight(lowest) + LAYOUT_V_GAP
|
|
89
88
|
});
|
|
90
89
|
}
|
|
@@ -172,18 +171,12 @@ function autoLayout(allNodes, allEdges) {
|
|
|
172
171
|
}
|
|
173
172
|
return { nodeColumn: nodeColumn2, colX: colX2 };
|
|
174
173
|
}
|
|
175
|
-
const provisional = assignAllColumns(/* @__PURE__ */ new Map());
|
|
176
174
|
const claimant = /* @__PURE__ */ new Map();
|
|
177
175
|
for (const [child, ps] of structuralParents) {
|
|
178
176
|
if (ps.length < 2) continue;
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
if (!pool.length) continue;
|
|
183
|
-
const ranked = [...pool].sort(
|
|
184
|
-
(a, b) => provisional.colX(provisional.nodeColumn.get(a)) - provisional.colX(provisional.nodeColumn.get(b)) || (a < b ? -1 : a > b ? 1 : 0)
|
|
185
|
-
);
|
|
186
|
-
claimant.set(child, ranked[Math.floor((ranked.length - 1) / 2)]);
|
|
177
|
+
const continued = ps.filter((p) => !exploreEdges.has(edgeKey(p, child)));
|
|
178
|
+
const pool = continued.length ? continued : ps;
|
|
179
|
+
claimant.set(child, pool[0]);
|
|
187
180
|
}
|
|
188
181
|
const { nodeColumn, colX } = assignAllColumns(claimant);
|
|
189
182
|
const nodeHeightMap = /* @__PURE__ */ new Map();
|
|
@@ -943,7 +936,7 @@ var DshSessionCollector = class {
|
|
|
943
936
|
return this.current;
|
|
944
937
|
}
|
|
945
938
|
feed(line) {
|
|
946
|
-
if (line.type === "session" && line.id) {
|
|
939
|
+
if (line.type === "session" && line.id && !("timestamp" in line)) {
|
|
947
940
|
if (!this.sessionId) this.sessionId = line.id;
|
|
948
941
|
if (line.cwd && !this.cwd) this.cwd = line.cwd;
|
|
949
942
|
return;
|
|
@@ -1069,6 +1062,176 @@ function buildGraphFromTurns3(turns, sessionId, cwd) {
|
|
|
1069
1062
|
return { nodes: autoLayout(nodes, edges), edges };
|
|
1070
1063
|
}
|
|
1071
1064
|
|
|
1065
|
+
// ../src/lib/adapters/pi-session.ts
|
|
1066
|
+
var textOf = (content) => {
|
|
1067
|
+
if (typeof content === "string") return content;
|
|
1068
|
+
if (!Array.isArray(content)) return "";
|
|
1069
|
+
return content.filter((b) => b && b.type === "text" && typeof b.text === "string").map((b) => b.text).join("\n");
|
|
1070
|
+
};
|
|
1071
|
+
function renderCall2(name, args) {
|
|
1072
|
+
const a = args && typeof args === "object" ? args : {};
|
|
1073
|
+
const op = toolOpOf(name);
|
|
1074
|
+
const paths = typeof a.path === "string" && a.path && (op === "read" || op === "edit" || op === "write") ? [a.path] : [];
|
|
1075
|
+
let locator;
|
|
1076
|
+
if (op === "read" && (typeof a.offset === "number" || typeof a.limit === "number")) {
|
|
1077
|
+
const start = Math.max(1, typeof a.offset === "number" ? a.offset : 1);
|
|
1078
|
+
const end = typeof a.limit === "number" ? start + Math.max(0, a.limit) - 1 : start;
|
|
1079
|
+
locator = { lines: [start, Math.max(start, end)] };
|
|
1080
|
+
}
|
|
1081
|
+
if (op === "write" && typeof a.content === "string") {
|
|
1082
|
+
const c2 = clipText(`${a.path ?? ""}
|
|
1083
|
+
|
|
1084
|
+
${a.content}`, ARTIFACT_CALL_LIMIT);
|
|
1085
|
+
return { ...c2, paths };
|
|
1086
|
+
}
|
|
1087
|
+
if (op === "edit") {
|
|
1088
|
+
const edits = Array.isArray(a.edits) ? a.edits : typeof a.newText === "string" ? [{ oldText: a.oldText, newText: a.newText }] : [];
|
|
1089
|
+
if (edits.length) {
|
|
1090
|
+
const body = edits.map((e) => `${a.path ?? ""}
|
|
1091
|
+
--- old
|
|
1092
|
+
${e.oldText ?? ""}
|
|
1093
|
+
+++ new
|
|
1094
|
+
${e.newText ?? ""}`).join("\n\n");
|
|
1095
|
+
const c2 = clipText(body, ARTIFACT_CALL_LIMIT);
|
|
1096
|
+
return { ...c2, paths };
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
if (op === "run" && typeof a.command === "string") {
|
|
1100
|
+
const c2 = clipText(a.command, TOOL_CALL_LIMIT);
|
|
1101
|
+
return { ...c2, paths };
|
|
1102
|
+
}
|
|
1103
|
+
const c = clipText(JSON.stringify(args ?? {}), TOOL_CALL_LIMIT);
|
|
1104
|
+
return { ...c, paths, ...locator ? { locator } : {} };
|
|
1105
|
+
}
|
|
1106
|
+
var PiSessionCollector = class {
|
|
1107
|
+
turns = [];
|
|
1108
|
+
pending = /* @__PURE__ */ new Map();
|
|
1109
|
+
current = null;
|
|
1110
|
+
sessionId = null;
|
|
1111
|
+
cwd = null;
|
|
1112
|
+
firstQuestion = null;
|
|
1113
|
+
feedLine(raw) {
|
|
1114
|
+
const t = raw.trim();
|
|
1115
|
+
if (!t) return;
|
|
1116
|
+
let e;
|
|
1117
|
+
try {
|
|
1118
|
+
e = JSON.parse(t);
|
|
1119
|
+
} catch {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
this.feed(e);
|
|
1123
|
+
}
|
|
1124
|
+
flush() {
|
|
1125
|
+
const c = this.current;
|
|
1126
|
+
if (c && (c.question || c.response || c.tools.length)) this.turns.push(c);
|
|
1127
|
+
this.current = null;
|
|
1128
|
+
}
|
|
1129
|
+
feed(e) {
|
|
1130
|
+
if (e.type === "session" && typeof e.id === "string") {
|
|
1131
|
+
if (!this.sessionId) this.sessionId = e.id;
|
|
1132
|
+
if (typeof e.cwd === "string" && !this.cwd) this.cwd = e.cwd;
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
if (e.type !== "message") {
|
|
1136
|
+
if (this.current && typeof e.id === "string") this.current.itemIds.push(e.id);
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
const m = e.message;
|
|
1140
|
+
if (!m) return;
|
|
1141
|
+
if (m.role === "user") {
|
|
1142
|
+
const text = textOf(m.content).trim();
|
|
1143
|
+
if (!text) return;
|
|
1144
|
+
this.flush();
|
|
1145
|
+
if (!this.firstQuestion) this.firstQuestion = text.split("\n")[0].slice(0, 80);
|
|
1146
|
+
const at = typeof e.timestamp === "string" ? e.timestamp : typeof m.timestamp === "number" ? new Date(m.timestamp).toISOString() : void 0;
|
|
1147
|
+
this.current = {
|
|
1148
|
+
question: text,
|
|
1149
|
+
response: "",
|
|
1150
|
+
itemIds: typeof e.id === "string" ? [e.id] : [],
|
|
1151
|
+
tools: [],
|
|
1152
|
+
...typeof e.parentId === "string" ? { parentItemId: e.parentId } : {},
|
|
1153
|
+
...at ? { at } : {}
|
|
1154
|
+
};
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
if (m.role === "assistant") {
|
|
1158
|
+
const cur = this.current ?? (this.current = { question: "", response: "", itemIds: [], tools: [] });
|
|
1159
|
+
if (typeof e.id === "string") cur.itemIds.push(e.id);
|
|
1160
|
+
const text = textOf(m.content).trim();
|
|
1161
|
+
if (text) cur.response = cur.response ? `${cur.response}
|
|
1162
|
+
|
|
1163
|
+
${text}` : text;
|
|
1164
|
+
if (Array.isArray(m.content)) {
|
|
1165
|
+
for (const b of m.content) {
|
|
1166
|
+
if (b?.type !== "toolCall" || typeof b.id !== "string" || typeof b.name !== "string") continue;
|
|
1167
|
+
const r = renderCall2(b.name, b.arguments);
|
|
1168
|
+
this.pending.set(b.id, { name: b.name, call: r.text, truncated: r.truncated, op: toolOpOf(b.name), paths: r.paths, ...r.locator ? { locator: r.locator } : {} });
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
if (m.role === "toolResult") {
|
|
1174
|
+
const id = m.toolCallId;
|
|
1175
|
+
if (!id) return;
|
|
1176
|
+
const reg = this.pending.get(id);
|
|
1177
|
+
if (!reg) return;
|
|
1178
|
+
const cur = this.current ?? (this.current = { question: "", response: "", itemIds: [], tools: [] });
|
|
1179
|
+
if (typeof e.id === "string") cur.itemIds.push(e.id);
|
|
1180
|
+
const res = clipText(textOf(m.content), TOOL_RESULT_LIMIT);
|
|
1181
|
+
cur.tools.push({
|
|
1182
|
+
name: reg.name,
|
|
1183
|
+
call: reg.call,
|
|
1184
|
+
result: res.text,
|
|
1185
|
+
truncated: reg.truncated || res.truncated,
|
|
1186
|
+
op: reg.op,
|
|
1187
|
+
nativeCallId: id,
|
|
1188
|
+
...reg.paths.length ? { paths: reg.paths } : {},
|
|
1189
|
+
...reg.locator ? { locator: reg.locator } : {}
|
|
1190
|
+
});
|
|
1191
|
+
this.pending.delete(id);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
finish() {
|
|
1195
|
+
this.flush();
|
|
1196
|
+
if (!this.sessionId) return null;
|
|
1197
|
+
const title = this.firstQuestion ?? `session ${this.sessionId.slice(0, 8)}`;
|
|
1198
|
+
return { sessionId: this.sessionId, title, turns: dropSelfCommandTurns(this.turns), ...this.cwd ? { cwd: this.cwd } : {} };
|
|
1199
|
+
}
|
|
1200
|
+
toConversation() {
|
|
1201
|
+
const s = this.finish();
|
|
1202
|
+
if (!s || s.turns.length === 0) return null;
|
|
1203
|
+
return {
|
|
1204
|
+
title: s.title,
|
|
1205
|
+
messageCount: s.turns.length,
|
|
1206
|
+
source: "pi",
|
|
1207
|
+
sessionId: s.sessionId,
|
|
1208
|
+
build: () => buildGraphFromTurns4(s.turns, s.sessionId, s.cwd)
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
function buildGraphFromTurns4(turns, sessionId, cwd) {
|
|
1213
|
+
const origin = cwd ? { cwd } : {};
|
|
1214
|
+
const nodes = [];
|
|
1215
|
+
const edges = [];
|
|
1216
|
+
const byItem = /* @__PURE__ */ new Map();
|
|
1217
|
+
const link = (a, b) => edges.push({ id: generateId(), source: a.id, target: b.id, type: "smoothstep" });
|
|
1218
|
+
let prev = null;
|
|
1219
|
+
for (const turn of turns) {
|
|
1220
|
+
const node = makeNode(turn.question || "(tool-only turn)", turn.response, prev === null);
|
|
1221
|
+
node.data.importSource = { runner: "pi", sessionId, itemIds: turn.itemIds, ...origin };
|
|
1222
|
+
node.data.source = { question: node.data.question, response: node.data.response };
|
|
1223
|
+
node.data.attachments = toolAttachments(turn);
|
|
1224
|
+
seedPlaque(node);
|
|
1225
|
+
nodes.push(node);
|
|
1226
|
+
const parent = turn.parentItemId ? byItem.get(turn.parentItemId) : void 0;
|
|
1227
|
+
if (parent) link(parent, node);
|
|
1228
|
+
else if (prev) link(prev, node);
|
|
1229
|
+
for (const id of turn.itemIds) byItem.set(id, node);
|
|
1230
|
+
prev = node;
|
|
1231
|
+
}
|
|
1232
|
+
return { nodes: autoLayout(nodes, edges), edges };
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1072
1235
|
// ../src/lib/adapters/dsh-zstd.ts
|
|
1073
1236
|
var ZSTD_MAGIC = 4247762216;
|
|
1074
1237
|
function scanZstdFrames(buf) {
|
|
@@ -1462,6 +1625,24 @@ var THOUGHTDAG_MANIFEST = {
|
|
|
1462
1625
|
contextSurface: OBS_PART2
|
|
1463
1626
|
// exact for logged commits, upstream-only before
|
|
1464
1627
|
};
|
|
1628
|
+
var PI_MANIFEST = {
|
|
1629
|
+
runner: "pi",
|
|
1630
|
+
schema: "pi-session/v3",
|
|
1631
|
+
turns: OBS_FULL2,
|
|
1632
|
+
// one user message opens every turn
|
|
1633
|
+
parenting: OBS_FULL2,
|
|
1634
|
+
// every entry names its parent; the session is a tree
|
|
1635
|
+
messages: OBS_PART2,
|
|
1636
|
+
// assistant text blocks fold per turn; thinking is dropped
|
|
1637
|
+
toolPairing: OBS_FULL2,
|
|
1638
|
+
// toolCall blocks ↔ toolResult messages pair by toolCallId
|
|
1639
|
+
artifactTouch: OBS_FULL2,
|
|
1640
|
+
// `path` on read/edit/write; shell commands stay opaque, as for every runner
|
|
1641
|
+
compaction: UNKNOWN,
|
|
1642
|
+
// not projected yet
|
|
1643
|
+
contextSurface: UNKNOWN
|
|
1644
|
+
// the log records messages, not requests
|
|
1645
|
+
};
|
|
1465
1646
|
var DSH_MANIFEST = {
|
|
1466
1647
|
runner: "dsh",
|
|
1467
1648
|
schema: "dsh-events/2026-09",
|
|
@@ -1484,6 +1665,7 @@ var MANIFESTS = {
|
|
|
1484
1665
|
"claude-code": CLAUDE_CODE_MANIFEST,
|
|
1485
1666
|
codex: CODEX_MANIFEST,
|
|
1486
1667
|
dsh: DSH_MANIFEST,
|
|
1668
|
+
pi: PI_MANIFEST,
|
|
1487
1669
|
thoughtdag: THOUGHTDAG_MANIFEST
|
|
1488
1670
|
};
|
|
1489
1671
|
|
|
@@ -1752,7 +1934,8 @@ var TEXT_LINES = path.join(HOME, "text-index.jsonl");
|
|
|
1752
1934
|
var LEGACY_FILE = path.join(HOME, "why-index.json");
|
|
1753
1935
|
var CONFIG_FILE = path.join(HOME, "config.json");
|
|
1754
1936
|
var DSH_ROOT = path.join(process.env.DSH_HOME ?? path.join(os.homedir(), ".dsh"), "sessions");
|
|
1755
|
-
var
|
|
1937
|
+
var PI_ROOT = path.join(os.homedir(), ".pi", "agent", "sessions");
|
|
1938
|
+
var ROOTS = process.env.THOUGHTDAG_SESSION_ROOTS?.split(path.delimiter).filter(Boolean) ?? [path.join(os.homedir(), ".claude", "projects"), path.join(os.homedir(), ".codex", "sessions"), DSH_ROOT, PI_ROOT];
|
|
1756
1939
|
var CANVAS_RECORDS = path.join(HOME, "canvases");
|
|
1757
1940
|
async function canvasRoots() {
|
|
1758
1941
|
const env = process.env.THOUGHTDAG_CANVAS_ROOTS?.split(path.delimiter).filter(Boolean);
|
|
@@ -1924,8 +2107,8 @@ async function eventsOf(file, sourceId) {
|
|
|
1924
2107
|
}
|
|
1925
2108
|
lines = createInterface({ input: createReadStream(file, { encoding: "utf8", highWaterMark: 1 << 20 }) });
|
|
1926
2109
|
}
|
|
1927
|
-
const runner = meta.type === "session_meta" ? "codex" : meta.type === "session" && typeof meta.id === "string" ? "dsh" : "claude-code";
|
|
1928
|
-
const collector = runner === "codex" ? new CodexSessionCollector() : runner === "dsh" ? new DshSessionCollector() : new ClaudeSessionCollector();
|
|
2110
|
+
const runner = meta.type === "session_meta" ? "codex" : meta.type === "session" && typeof meta.id === "string" ? typeof meta.timestamp === "string" ? "pi" : "dsh" : "claude-code";
|
|
2111
|
+
const collector = runner === "codex" ? new CodexSessionCollector() : runner === "dsh" ? new DshSessionCollector() : runner === "pi" ? new PiSessionCollector() : new ClaudeSessionCollector();
|
|
1929
2112
|
for await (const line of lines) collector.feedLine(line);
|
|
1930
2113
|
const s = collector.finish();
|
|
1931
2114
|
if (!s) return null;
|
|
@@ -2528,7 +2711,7 @@ ${turn.response.trim() || "(none)"}
|
|
|
2528
2711
|
var CLI_VERSION = "0.1.0";
|
|
2529
2712
|
var MCP_TOOLS = [
|
|
2530
2713
|
{ name: "why_check", description: "Cheap first question before editing a file: does this artifact have any history in local agent sessions? One line; history true/false.", inputSchema: { type: "object", properties: { path: { type: "string", description: "file path (absolute or relative to cwd), URL, or arxiv:<id>" } }, required: ["path"] } },
|
|
2531
|
-
{ name: "why_file", description: "The turns across local Claude Code, Codex, DeepSeek Harness and ThoughtDAG sessions that touched a file, URL or paper: when, what changed (\u0394, observed), what was asked, what the answer said about it (\u2248, a candidate explanation, not a verified reason). Each hit carries a deep link.", inputSchema: { type: "object", properties: { path: { type: "string" }, include_read: { type: "boolean", description: "also list turns that only read it (default false)" }, limit: { type: "number", description: "max hits (default 10)" } }, required: ["path"] } },
|
|
2714
|
+
{ name: "why_file", description: "The turns across local Claude Code, Codex, DeepSeek Harness, Pi and ThoughtDAG sessions that touched a file, URL or paper: when, what changed (\u0394, observed), what was asked, what the answer said about it (\u2248, a candidate explanation, not a verified reason). Each hit carries a deep link.", inputSchema: { type: "object", properties: { path: { type: "string" }, include_read: { type: "boolean", description: "also list turns that only read it (default false)" }, limit: { type: "number", description: "max hits (default 10)" } }, required: ["path"] } },
|
|
2532
2715
|
{ name: "find", description: "Where these exact words were asked (Q), answered (A) or attached (M) across local sessions and canvases. Exact, case-insensitive match; every hit is a verbatim snippet with a pointer.", inputSchema: { type: "object", properties: { phrase: { type: "string" }, in: { type: "string", enum: ["q", "a", "m", "all"] }, limit: { type: "number" } }, required: ["phrase"] } },
|
|
2533
2716
|
{ name: "recall_turn", description: "One turn in full \u2014 the question, the answer, the tool calls with their diffs \u2014 by session id (or prefix) and turn number as shown by why_file.", inputSchema: { type: "object", properties: { session: { type: "string" }, turn: { type: "number" } }, required: ["session", "turn"] } }
|
|
2534
2717
|
];
|
package/package.json
CHANGED