@wukazis/euphony 0.1.45 → 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 +28 -2
- package/dist/assets/local-data-worker-DTkq_bcN.js +2 -0
- package/dist/assets/{main-CmldcHcT.js → main-BMLAkPsC.js} +676 -498
- package/dist/index.html +1 -1
- package/lib/components/app/app.d.ts +24 -4
- package/lib/components/codex/codex.js +5 -5
- package/lib/euphony.js +1 -1
- package/lib/types/common-types.d.ts +15 -2
- package/lib/utils/api-manager.d.ts +6 -2
- package/lib/utils/codex-session.d.ts +4 -0
- package/package.json +1 -1
- package/server-dist/node-main.js +659 -17
- package/dist/assets/local-data-worker-CHLGzNeW.js +0 -2
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ structured chat data and Codex sessions in the browser.
|
|
|
37
37
|
| Filtering and focus mode | Filters datasets with JMESPath and narrows visible messages by role, recipient, or content type. |
|
|
38
38
|
| Grid and editor modes | Supports dataset skimming in grid view and direct JSONL editing in editor mode. |
|
|
39
39
|
| Harmony token rendering | Shows Harmony renderer output, token IDs, decoded tokens, and rendered display strings. |
|
|
40
|
-
| Local Codex sessions index | Scans local Codex history under `~/.codex/sessions`,
|
|
40
|
+
| Local Codex sessions index | Scans local Codex history under `~/.codex/sessions`, supports keyword search, and opens full sessions on demand. |
|
|
41
41
|
| Embeddable web components | Ships reusable custom elements for integrating the viewer into other web apps in any framework (e.g., React, Svelte, Vue). |
|
|
42
42
|
|
|
43
43
|
## Get Started
|
|
@@ -160,13 +160,33 @@ 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
|
+
|
|
169
|
+
To open the Codex token usage overview directly:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
http://127.0.0.1:8020/?path=codex%3Ausage
|
|
173
|
+
```
|
|
174
|
+
|
|
163
175
|
The `codex:sessions` path scans:
|
|
164
176
|
|
|
165
177
|
```text
|
|
166
178
|
~/.codex/sessions/**/*.jsonl
|
|
167
179
|
```
|
|
168
180
|
|
|
169
|
-
|
|
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.
|
|
188
|
+
|
|
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`.
|
|
170
190
|
|
|
171
191
|
To read Codex sessions from another directory:
|
|
172
192
|
|
|
@@ -174,6 +194,12 @@ To read Codex sessions from another directory:
|
|
|
174
194
|
CODEX_SESSIONS_DIR=/path/to/sessions pnpm start
|
|
175
195
|
```
|
|
176
196
|
|
|
197
|
+
To read Claude Code sessions from another directory:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
CLAUDE_PROJECTS_DIR=/path/to/projects pnpm start
|
|
201
|
+
```
|
|
202
|
+
|
|
177
203
|
If you want backend translation, set either `OPENAI_API_KEY` or `OPEN_AI_API_KEY` before starting the backend.
|
|
178
204
|
|
|
179
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)}}})();
|