@wukazis/euphony 0.1.46 → 0.1.47

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 CHANGED
@@ -160,6 +160,12 @@ To open the local Codex sessions index directly:
160
160
  http://127.0.0.1:8020/?path=codex%3Asessions
161
161
  ```
162
162
 
163
+ To open the local Claude Code sessions index directly:
164
+
165
+ ```text
166
+ http://127.0.0.1:8020/?path=claude%3Asessions
167
+ ```
168
+
163
169
  To open the Codex token usage overview directly:
164
170
 
165
171
  ```text
@@ -172,7 +178,13 @@ The `codex:sessions` path scans:
172
178
  ~/.codex/sessions/**/*.jsonl
173
179
  ```
174
180
 
175
- Each session is shown as a lightweight row with its session path, first user message, relative time, compact total token count, and event count. Use the search box to filter by session path or first user message. Click a row to load the full session. On a full session page, use the `Sessions` button in the toolbar to return to the index.
181
+ The `claude:sessions` path scans:
182
+
183
+ ```text
184
+ ~/.claude/projects/**/*.jsonl
185
+ ```
186
+
187
+ Each Codex or Claude session is shown as a lightweight row with its session path, first user message, relative time, compact total token count, and event count. Use the search box to filter by session path or first user message. Click a row to load the full session. On a full session page, use the `Sessions` button in the toolbar to return to the index.
176
188
 
177
189
  The `codex:usage` path reads each Codex session's latest `total_token_usage` and groups it into selectable ranges: `7d`, `30d`, and `1y`. The usage page includes a line chart with hover tooltips and compact token labels, for example `45,034 tokens` becomes `45k tokens` and million-scale counts become `m tokens`.
178
190
 
@@ -182,6 +194,12 @@ To read Codex sessions from another directory:
182
194
  CODEX_SESSIONS_DIR=/path/to/sessions pnpm start
183
195
  ```
184
196
 
197
+ To read Claude Code sessions from another directory:
198
+
199
+ ```bash
200
+ CLAUDE_PROJECTS_DIR=/path/to/projects pnpm start
201
+ ```
202
+
185
203
  If you want backend translation, set either `OPENAI_API_KEY` or `OPEN_AI_API_KEY` before starting the backend.
186
204
 
187
205
  To use another host or port:
@@ -0,0 +1,2 @@
1
+ (function(){"use strict";const f=new Set(["session_meta","response_item","event_msg","turn_context","compacted"]),p=new Set(["message","function_call","function_call_output","custom_tool_call","custom_tool_call_output","reasoning"]),y=new Set(["user_message","agent_message","agent_reasoning","context_compacted","turn_aborted","token_count"]),d=new Set(["user","assistant","system","summary","permission-mode","file-history-snapshot","last-prompt","ai-title"]),i=t=>typeof t=="object"&&t!==null,u=t=>{try{return JSON.parse(t)}catch{return null}},m=t=>{const e=[];for(const s of t){if(typeof s=="string"){const o=u(s);i(o)&&e.push(o);continue}i(s)&&e.push(s)}return e},g=t=>{const e=[];for(const s of t){if(typeof s=="string"){const o=u(s);i(o)&&e.push(o);continue}i(s)&&e.push(s)}return e},h=t=>{if(typeof t.type!="string")return!1;if(f.has(t.type)){if(t.type==="response_item"){const e=t.payload&&typeof t.payload.type=="string"?t.payload.type:null;return e?p.has(e):!0}if(t.type==="event_msg"){const e=t.payload&&typeof t.payload.type=="string"?t.payload.type:null;return e?y.has(e):!0}return!0}return t.type.startsWith("response_")||t.type.startsWith("event_")},_=t=>typeof t.type!="string"||!d.has(t.type)?!1:t.type==="user"||t.type==="assistant"?i(t.message):typeof t.sessionId=="string"||i(t.snapshot),S=t=>{if(!Array.isArray(t)||t.length===0)return!1;const e=m(t).filter(h);return e.length===0||e.length/t.length<.6?!1:e.some(o=>o.type==="session_meta")?!0:e.filter(o=>f.has(o.type??"")).length/e.length>=.6},N=t=>{if(!Array.isArray(t)||t.length===0)return!1;const e=g(t).filter(_);return e.length===0||e.filter(o=>o.type==="user"||o.type==="assistant").length===0?!1:e.length/t.length>=.4},E=t=>S(t)||N(t),l=t=>typeof t!="object"||t===null?!1:"messages"in t&&Array.isArray(t.messages),O=t=>{let e=null;if(t.length>0&&typeof t[0]=="object"&&!l(t[0])&&(e=t),t.length>0&&typeof t[0]=="string"){let s=!1;try{const o=JSON.parse(t[0]);l(o)&&(s=!0)}catch{s=!0}if(!s){e=[];for(const o of t){const n=JSON.parse(o);e.push(n)}}}if(e!==null){let s=null,o=!1;for(const n in e[0])if(typeof e[0][n]=="string")try{const r=JSON.parse(e[0][n]);if(l(r)){s=n,o=!0;break}}catch{continue}else if(l(e[0][n])){s=n;break}if(s!==null){const n=[];for(const r of e){const a=o?JSON.parse(r[s]):r[s];a.metadata??={};for(const c in r)c!==s&&(a.metadata[`euphonyTransformed-${c}`]=r[c]);n.push(a)}return n}}return null},v=t=>{const e=[];for(const[s,o]of t.entries())if(typeof o=="string"){const n=JSON.parse(o);let r=o;n.conversation_id!==void 0&&n.id===void 0&&(n.id=n.conversation_id,r=JSON.stringify(n)),t[s]=r,e.push(Array.isArray(n.messages))}else{const n=o;n.conversation_id!==void 0&&n.id===void 0&&(n.id=n.conversation_id),t[s]=n,e.push(Array.isArray(n.messages))}return e.every(Boolean)},T=t=>{const e=[];try{const s=JSON.parse(t);return e.push(s),e}catch{for(const o of t.split(`
2
+ `))try{e.push(JSON.parse(o))}catch{}}return e},J=t=>{let e=T(t);if(e.length===0)throw new Error("Failed to read any JSON or JSONL data.");if(E(e))return{dataType:"codex",codexSessionData:e};const s=O(e);if(s&&(e=s),!v(e))return{dataType:"json",jsonData:e};const o=[];for(const n of e)typeof n=="string"?o.push(JSON.parse(n)):o.push(n);return{dataType:"conversation",conversationData:o}};self.onmessage=async t=>{if(t.data.command!=="startParseData"){console.error("Worker: unknown message",t.data.command);return}const{requestID:e,sourceName:s,sourceText:o,sourceFile:n}=t.data.payload;try{const r=o??await n?.text();if(r===void 0)throw new Error("No source text or file was provided.");const a=J(r),c={command:"finishParseData",payload:{requestID:e,sourceName:s,...a}};postMessage(c)}catch(r){const a={command:"error",payload:{requestID:e,sourceName:s,message:r instanceof Error?r.message:String(r)}};postMessage(a)}}})();