spiracha 1.1.2 → 1.2.0
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/AGENTS.md +13 -7
- package/README.md +6 -2
- package/apps/ui/AGENTS.md +2 -0
- package/apps/ui/README.md +3 -1
- package/apps/ui/dist/client/assets/{analytics-CqWZmyV6.js → analytics-Cv0JMDN2.js} +1 -1
- package/apps/ui/dist/client/assets/{checkbox-DXM4lkJq.js → checkbox-DjHij7DJ.js} +1 -1
- package/apps/ui/dist/client/assets/{data-table-DnPYMPCD.js → data-table-Bgnh7phF.js} +1 -1
- package/apps/ui/dist/client/assets/{delete-confirm-dialog-CcZaRX33.js → delete-confirm-dialog-CIZy_LXD.js} +1 -1
- package/apps/ui/dist/client/assets/download-DQtfva4z.js +1 -0
- package/apps/ui/dist/client/assets/{es2015-Bm0kEzx2.js → es2015-DsDKdYCE.js} +1 -1
- package/apps/ui/dist/client/assets/{formatters-C12LmYaa.js → formatters-CWFrMKSn.js} +1 -1
- package/apps/ui/dist/client/assets/{index-DdJ7ahIt.js → index-C_-e0lDI.js} +2 -2
- package/apps/ui/dist/client/assets/{input-CEsI7EpI.js → input-BbgApiqZ.js} +1 -1
- package/apps/ui/dist/client/assets/{metric-card-9jwBF7rG.js → metric-card-BJX5rkHK.js} +1 -1
- package/apps/ui/dist/client/assets/{page-header-Dr_h1CVv.js → page-header-ODLuGLAB.js} +1 -1
- package/apps/ui/dist/client/assets/{projects._project-uyNGnpjH.js → projects._project-C2Pys_bB.js} +1 -1
- package/apps/ui/dist/client/assets/{projects._project-zoM8d2nH.js → projects._project-CHvAKvlu.js} +1 -1
- package/apps/ui/dist/client/assets/{projects.index-D1CWVN-O.js → projects.index-BmwtS1x-.js} +1 -1
- package/apps/ui/dist/client/assets/{projects.index-DukMuny6.js → projects.index-CuLw73mt.js} +1 -1
- package/apps/ui/dist/client/assets/{routes-Gr2Wwh83.js → routes-CfnaTOlj.js} +1 -1
- package/apps/ui/dist/client/assets/{select-CFim44gT.js → select-B1kH_5lx.js} +1 -1
- package/apps/ui/dist/client/assets/{settings-DqhyDxo2.js → settings-mYTB3sso.js} +1 -1
- package/apps/ui/dist/client/assets/{threads._threadId-DT75NiBa.js → threads._threadId-CUiCZSwo.js} +1 -1
- package/apps/ui/dist/client/assets/{threads._threadId-Df5VXIuZ.js → threads._threadId-C_47okme.js} +1 -1
- package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-kj_QB_26.js +99 -0
- package/apps/ui/dist/server/assets/{analytics-BMxW_bZL.js → analytics-2QpLKjlG.js} +1 -1
- package/apps/ui/dist/server/assets/{codex-queries-CAF6HYiG.js → codex-queries-BH4Cb0v3.js} +2 -2
- package/apps/ui/dist/server/assets/{codex-server-C01sv0JJ.js → codex-server-DqzruLmg.js} +17 -86
- package/apps/ui/dist/server/assets/{download-C5rkk_Bo.js → download-Drctxary.js} +7 -7
- package/apps/ui/dist/server/assets/{projects._project-CcJLp_A8.js → projects._project-DreIU5b0.js} +3 -3
- package/apps/ui/dist/server/assets/{projects._project-CJ7l0ynC.js → projects._project-gT01HBqH.js} +2 -2
- package/apps/ui/dist/server/assets/{projects.index-srtogpuF.js → projects.index-BYmgSGAj.js} +1 -1
- package/apps/ui/dist/server/assets/{router-C_w-haH6.js → router-Qj5Kn7bl.js} +6 -6
- package/apps/ui/dist/server/assets/{routes-BhbxvJE7.js → routes-BtcXuK0x.js} +2 -2
- package/apps/ui/dist/server/assets/{routes-CPe-ppmC.js → routes-_LbCIjtJ.js} +2 -2
- package/apps/ui/dist/server/assets/{threads._threadId-euyNckhj.js → threads._threadId-D5m6ypGw.js} +3 -3
- package/apps/ui/dist/server/assets/{threads._threadId-Ba7vv6-K.js → threads._threadId-DcbAJkwf.js} +2 -2
- package/apps/ui/dist/server/server.js +19 -36
- package/bin/codex-chats-claude.js +5 -0
- package/bin/codex-chats.js +5 -0
- package/bin/spiracha.js +5 -0
- package/package.json +9 -6
- package/src/lib/codex-browser-export.ts +2 -2
- package/src/lib/codex-exporter-cli.ts +9 -9
- package/src/lib/codex-exporter-transcript.ts +16 -190
- package/src/lib/codex-exporter-types.ts +1 -1
- package/src/lib/codex-exporter.ts +0 -1
- package/src/lib/interactive-cli.ts +2 -2
- package/src/mcp-server.ts +2 -2
- package/apps/ui/dist/client/assets/download-DOwxk-cG.js +0 -1
- package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-C0V305Nt.js +0 -99
package/apps/ui/dist/server/assets/{threads._threadId-euyNckhj.js → threads._threadId-D5m6ypGw.js}
RENAMED
|
@@ -2,14 +2,14 @@ import { t as applyPathTransforms$1 } from "./path-transforms-DL2IwtYd.js";
|
|
|
2
2
|
import { t as cn } from "./utils-C_uf36nf.js";
|
|
3
3
|
import { t as Button } from "./button-CmTDnzOn.js";
|
|
4
4
|
import { n as useSettings } from "./settings-store-DpEJEQ7M.js";
|
|
5
|
-
import { a as threadSnapshotQueryOptions, c as deleteThreadFn, o as threadTranscriptQueryOptions, u as exportThreadFn } from "./codex-queries-
|
|
6
|
-
import { t as Route } from "./threads._threadId-
|
|
5
|
+
import { a as threadSnapshotQueryOptions, c as deleteThreadFn, o as threadTranscriptQueryOptions, u as exportThreadFn } from "./codex-queries-BH4Cb0v3.js";
|
|
6
|
+
import { t as Route } from "./threads._threadId-DcbAJkwf.js";
|
|
7
7
|
import { t as Checkbox$1 } from "./checkbox-C0hovF41.js";
|
|
8
8
|
import { t as MetricCard } from "./metric-card-ByEeLu0r.js";
|
|
9
9
|
import { t as PageHeader } from "./page-header-CxdZM86z.js";
|
|
10
10
|
import { a as formatModelLabel, i as formatList, n as formatBytes, r as formatDateTime, s as formatTokens, t as formatBooleanLabel } from "./formatters-FJaGZgJk.js";
|
|
11
11
|
import { t as DeleteConfirmDialog } from "./delete-confirm-dialog-CWqcTXTF.js";
|
|
12
|
-
import { n as downloadUrlFile, r as ExportDialog, t as downloadTextFile } from "./download-
|
|
12
|
+
import { n as downloadUrlFile, r as ExportDialog, t as downloadTextFile } from "./download-Drctxary.js";
|
|
13
13
|
import { useEffect, useRef, useState } from "react";
|
|
14
14
|
import { Link, useNavigate } from "@tanstack/react-router";
|
|
15
15
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
package/apps/ui/dist/server/assets/{threads._threadId-Ba7vv6-K.js → threads._threadId-DcbAJkwf.js}
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { a as threadSnapshotQueryOptions } from "./codex-queries-
|
|
1
|
+
import { a as threadSnapshotQueryOptions } from "./codex-queries-BH4Cb0v3.js";
|
|
2
2
|
import { t as LoadingPanel } from "./loading-panel-DbLdvjtR.js";
|
|
3
3
|
import { createFileRoute, lazyRouteComponent } from "@tanstack/react-router";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/routes/threads.$threadId.tsx
|
|
6
6
|
var $$splitErrorComponentImporter = () => import("./threads._threadId-BSSK4nkI.js");
|
|
7
|
-
var $$splitComponentImporter = () => import("./threads._threadId-
|
|
7
|
+
var $$splitComponentImporter = () => import("./threads._threadId-D5m6ypGw.js");
|
|
8
8
|
var Route = createFileRoute("/threads/$threadId")({
|
|
9
9
|
component: lazyRouteComponent($$splitComponentImporter, "component"),
|
|
10
10
|
errorComponent: lazyRouteComponent($$splitErrorComponentImporter, "errorComponent"),
|
|
@@ -23,7 +23,7 @@ var NullProtoObj = /* @__PURE__ */ (() => {
|
|
|
23
23
|
return e.prototype = Object.create(null), Object.freeze(e.prototype), e;
|
|
24
24
|
})();
|
|
25
25
|
//#endregion
|
|
26
|
-
//#region ../../node_modules/.bun/srvx@0.11.
|
|
26
|
+
//#region ../../node_modules/.bun/srvx@0.11.16/node_modules/srvx/dist/_chunks/_url.mjs
|
|
27
27
|
function lazyInherit(target, source, sourceKey) {
|
|
28
28
|
for (const key of [...Object.getOwnPropertyNames(source), ...Object.getOwnPropertySymbols(source)]) {
|
|
29
29
|
if (key === "constructor") continue;
|
|
@@ -52,20 +52,6 @@ function lazyInherit(target, source, sourceKey) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
var _needsNormRE = /(?:(?:^|\/)(?:\.|\.\.|%2e|%2e\.|\.%2e|%2e%2e)(?:\/|$))|[\\^\x80-\uffff]/i;
|
|
55
|
-
/**
|
|
56
|
-
* URL wrapper with fast paths to access to the following props:
|
|
57
|
-
*
|
|
58
|
-
* - `url.pathname`
|
|
59
|
-
* - `url.search`
|
|
60
|
-
* - `url.searchParams`
|
|
61
|
-
* - `url.protocol`
|
|
62
|
-
*
|
|
63
|
-
* **NOTES:**
|
|
64
|
-
*
|
|
65
|
-
* - It is assumed that the input URL is **already encoded** and formatted from an HTTP request and contains no hash.
|
|
66
|
-
* - Triggering the setters or getters on other props will deoptimize to full URL parsing.
|
|
67
|
-
* - Changes to `searchParams` will be discarded as we don't track them.
|
|
68
|
-
*/
|
|
69
55
|
var FastURL = /* @__PURE__ */ (() => {
|
|
70
56
|
const NativeURL = globalThis.URL;
|
|
71
57
|
const FastURL = class URL {
|
|
@@ -113,10 +99,11 @@ var FastURL = /* @__PURE__ */ (() => {
|
|
|
113
99
|
const url = this.href;
|
|
114
100
|
const protoIndex = url.indexOf("://");
|
|
115
101
|
const pathnameIndex = protoIndex === -1 ? -1 : url.indexOf("/", protoIndex + 4);
|
|
102
|
+
const qIndex = pathnameIndex === -1 ? -1 : url.indexOf("?", pathnameIndex);
|
|
116
103
|
this.#pos = [
|
|
117
104
|
protoIndex,
|
|
118
105
|
pathnameIndex,
|
|
119
|
-
|
|
106
|
+
qIndex
|
|
120
107
|
];
|
|
121
108
|
}
|
|
122
109
|
return this.#pos;
|
|
@@ -150,7 +137,8 @@ var FastURL = /* @__PURE__ */ (() => {
|
|
|
150
137
|
if (this.#protocol === void 0) {
|
|
151
138
|
const [protocolIndex] = this.#getPos();
|
|
152
139
|
if (protocolIndex === -1) return this._url.protocol;
|
|
153
|
-
|
|
140
|
+
const url = this.href;
|
|
141
|
+
this.#protocol = url.slice(0, protocolIndex + 1);
|
|
154
142
|
}
|
|
155
143
|
return this.#protocol;
|
|
156
144
|
}
|
|
@@ -167,12 +155,7 @@ var FastURL = /* @__PURE__ */ (() => {
|
|
|
167
155
|
return FastURL;
|
|
168
156
|
})();
|
|
169
157
|
//#endregion
|
|
170
|
-
//#region ../../node_modules/.bun/srvx@0.11.
|
|
171
|
-
/**
|
|
172
|
-
* Fast Response for Node.js runtime
|
|
173
|
-
*
|
|
174
|
-
* It is faster because in most cases it doesn't create a full Response instance.
|
|
175
|
-
*/
|
|
158
|
+
//#region ../../node_modules/.bun/srvx@0.11.16/node_modules/srvx/dist/adapters/node.mjs
|
|
176
159
|
var NodeResponse = /* @__PURE__ */ (() => {
|
|
177
160
|
const NativeResponse = globalThis.Response;
|
|
178
161
|
const STATUS_CODES = globalThis.process?.getBuiltinModule?.("node:http")?.STATUS_CODES || {};
|
|
@@ -3471,7 +3454,7 @@ var defaultSerovalPlugins = [
|
|
|
3471
3454
|
* the dev styles URL for route-scoped CSS collection.
|
|
3472
3455
|
*/
|
|
3473
3456
|
async function getStartManifest(matchedRoutes) {
|
|
3474
|
-
const { tsrStartManifest } = await import("./assets/_tanstack-start-manifest_v-
|
|
3457
|
+
const { tsrStartManifest } = await import("./assets/_tanstack-start-manifest_v-kj_QB_26.js");
|
|
3475
3458
|
const startManifest = tsrStartManifest();
|
|
3476
3459
|
let routes = startManifest.routes;
|
|
3477
3460
|
routes[rootRouteId];
|
|
@@ -3498,47 +3481,47 @@ async function getStartManifest(matchedRoutes) {
|
|
|
3498
3481
|
var manifest = {
|
|
3499
3482
|
"0814663c3bdc58135f97d210d145ef0be5ca54ef9a5f1e3030be9b1bfc901e30": {
|
|
3500
3483
|
functionName: "exportThreadFn_createServerFn_handler",
|
|
3501
|
-
importer: () => import("./assets/codex-server-
|
|
3484
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3502
3485
|
},
|
|
3503
3486
|
"164ee82cdd565ed96591a64312f0f7bd961040baf066a89d9f5636330d11360b": {
|
|
3504
3487
|
functionName: "deleteProjectFn_createServerFn_handler",
|
|
3505
|
-
importer: () => import("./assets/codex-server-
|
|
3488
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3506
3489
|
},
|
|
3507
3490
|
"29727b7ad5b8fe42e83817376653e064d9fe8888799f056b2e59296b3396568b": {
|
|
3508
3491
|
functionName: "deleteThreadFn_createServerFn_handler",
|
|
3509
|
-
importer: () => import("./assets/codex-server-
|
|
3492
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3510
3493
|
},
|
|
3511
3494
|
"4712520da0f07bbd1f0907e5a162fe518516ff4caca3fd23876cc65539d87d7a": {
|
|
3512
3495
|
functionName: "getAnalyticsFn_createServerFn_handler",
|
|
3513
|
-
importer: () => import("./assets/codex-server-
|
|
3496
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3514
3497
|
},
|
|
3515
3498
|
"59fb2cb4d60c8e7d47e0afcc914ee6f9d9f4bf076c8e66eab1693066753655b3": {
|
|
3516
3499
|
functionName: "listProjectThreadsFn_createServerFn_handler",
|
|
3517
|
-
importer: () => import("./assets/codex-server-
|
|
3500
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3518
3501
|
},
|
|
3519
3502
|
"5da27045f7e28ded6353bc16aace284af7ef1b4010ef04d0186a6feadb466497": {
|
|
3520
3503
|
functionName: "getThreadTranscriptFn_createServerFn_handler",
|
|
3521
|
-
importer: () => import("./assets/codex-server-
|
|
3504
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3522
3505
|
},
|
|
3523
3506
|
"72991e2b6e0adbf8d63bb8b139dad88a00b77b7030ec28ceac36c3cce7846b4c": {
|
|
3524
3507
|
functionName: "getThreadSnapshotFn_createServerFn_handler",
|
|
3525
|
-
importer: () => import("./assets/codex-server-
|
|
3508
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3526
3509
|
},
|
|
3527
3510
|
"792690638a3b10035a5b7368c3d98bdc70cbfe1e36a4aa5f45b1c49b8b1025b0": {
|
|
3528
3511
|
functionName: "getDashboardSummaryFn_createServerFn_handler",
|
|
3529
|
-
importer: () => import("./assets/codex-server-
|
|
3512
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3530
3513
|
},
|
|
3531
3514
|
"96aa60bf7dd9b5bde415bcf3ad6f6955a975eecd9aa0516cf401cc39bebebe6c": {
|
|
3532
3515
|
functionName: "deleteThreadsFn_createServerFn_handler",
|
|
3533
|
-
importer: () => import("./assets/codex-server-
|
|
3516
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3534
3517
|
},
|
|
3535
3518
|
"b4e15c006e9a277470958bb008f89b5b0acc7256109581de44cf17d587d174a5": {
|
|
3536
3519
|
functionName: "exportThreadsFn_createServerFn_handler",
|
|
3537
|
-
importer: () => import("./assets/codex-server-
|
|
3520
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3538
3521
|
},
|
|
3539
3522
|
"ccefccb816ba13508f23db4e31067b3403e750225257592d3ae11071ffc3fd6f": {
|
|
3540
3523
|
functionName: "listProjectsFn_createServerFn_handler",
|
|
3541
|
-
importer: () => import("./assets/codex-server-
|
|
3524
|
+
importer: () => import("./assets/codex-server-DqzruLmg.js")
|
|
3542
3525
|
}
|
|
3543
3526
|
};
|
|
3544
3527
|
async function getServerFnById(id, access) {
|
|
@@ -5328,7 +5311,7 @@ var getBaseManifest = getProdBaseManifest;
|
|
|
5328
5311
|
var createEarlyHintsForRequest = createEarlyHintsCollector;
|
|
5329
5312
|
async function loadEntries() {
|
|
5330
5313
|
const [routerEntry, startEntry, pluginAdapters] = await Promise.all([
|
|
5331
|
-
import("./assets/router-
|
|
5314
|
+
import("./assets/router-Qj5Kn7bl.js"),
|
|
5332
5315
|
import("./assets/start-HeKLHD9b.js"),
|
|
5333
5316
|
import("./assets/__23tanstack-start-plugin-adapters-BzCA6dXo.js")
|
|
5334
5317
|
]);
|
package/bin/spiracha.js
ADDED
package/package.json
CHANGED
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
"url": "https://github.com/ragaeeb"
|
|
5
5
|
},
|
|
6
6
|
"bin": {
|
|
7
|
-
"codex-chats": "./
|
|
8
|
-
"codex-chats-claude": "./
|
|
9
|
-
"spiracha": "./
|
|
7
|
+
"codex-chats": "./bin/codex-chats.js",
|
|
8
|
+
"codex-chats-claude": "./bin/codex-chats-claude.js",
|
|
9
|
+
"spiracha": "./bin/spiracha.js"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ragaeeb/spiracha/issues"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@inquirer/prompts": "^8.
|
|
15
|
+
"@inquirer/prompts": "^8.5.0",
|
|
16
16
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
17
17
|
"@tanstack/react-query": "5.100.14",
|
|
18
18
|
"@tanstack/react-router": "1.170.8",
|
|
19
19
|
"@tanstack/react-router-ssr-query": "1.167.0",
|
|
20
20
|
"@tanstack/react-table": "8.21.3",
|
|
21
|
-
"@tanstack/react-virtual": "3.13.
|
|
21
|
+
"@tanstack/react-virtual": "3.13.26",
|
|
22
22
|
"class-variance-authority": "0.7.1",
|
|
23
23
|
"clsx": "2.1.1",
|
|
24
24
|
"iconv-lite": "^0.7.2",
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
"bun": ">=1.3.13"
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
42
|
+
"bin/codex-chats.js",
|
|
43
|
+
"bin/codex-chats-claude.js",
|
|
44
|
+
"bin/spiracha.js",
|
|
42
45
|
"src/export-chats.ts",
|
|
43
46
|
"src/export-claude.ts",
|
|
44
47
|
"src/mcp-server.ts",
|
|
@@ -109,7 +112,7 @@
|
|
|
109
112
|
"ui:preview": "bun run --cwd apps/ui preview"
|
|
110
113
|
},
|
|
111
114
|
"type": "module",
|
|
112
|
-
"version": "1.
|
|
115
|
+
"version": "1.2.0",
|
|
113
116
|
"workspaces": [
|
|
114
117
|
"apps/*"
|
|
115
118
|
]
|
|
@@ -11,9 +11,9 @@ import { buildUiExportDownloadUrl, ensureUiExportDir } from './ui-export-files';
|
|
|
11
11
|
type RenderCodexThreadDownloadInput = {
|
|
12
12
|
dbPath: string;
|
|
13
13
|
includeCommentary: boolean;
|
|
14
|
+
includeMetadata: boolean;
|
|
14
15
|
includeTools: boolean;
|
|
15
16
|
largeExportThresholdBytes?: number;
|
|
16
|
-
optimized: boolean;
|
|
17
17
|
outputFormat: ExportFormat;
|
|
18
18
|
pathDisplaySettings?: Pick<PathDisplaySettings, 'convertToProjectRoot' | 'redactUsername'>;
|
|
19
19
|
publicExportDir?: string;
|
|
@@ -101,9 +101,9 @@ const toDownloadOptions = (input: RenderCodexThreadDownloadInput): CodexCliOptio
|
|
|
101
101
|
dbPath: input.dbPath,
|
|
102
102
|
flat: false,
|
|
103
103
|
includeCommentary: input.includeCommentary,
|
|
104
|
+
includeMetadata: input.includeMetadata,
|
|
104
105
|
includeTools: input.includeTools,
|
|
105
106
|
inputDir: '',
|
|
106
|
-
optimized: input.optimized,
|
|
107
107
|
outputDir: '',
|
|
108
108
|
outputFormat: input.outputFormat,
|
|
109
109
|
projectFilter: null,
|
|
@@ -10,7 +10,7 @@ export const parseCodexCliArgs = (argv: string[]): CodexCliOptions => {
|
|
|
10
10
|
let projectFilter: string | null = null;
|
|
11
11
|
let threadIds: string[] = [];
|
|
12
12
|
let outputProvided = false;
|
|
13
|
-
let
|
|
13
|
+
let includeMetadata = true;
|
|
14
14
|
let includeCommentary = true;
|
|
15
15
|
let includeTools = false;
|
|
16
16
|
let outputFormat: ExportFormat = 'md';
|
|
@@ -22,9 +22,9 @@ export const parseCodexCliArgs = (argv: string[]): CodexCliOptions => {
|
|
|
22
22
|
dbPath,
|
|
23
23
|
flat,
|
|
24
24
|
includeCommentary,
|
|
25
|
+
includeMetadata,
|
|
25
26
|
includeTools,
|
|
26
27
|
inputDir,
|
|
27
|
-
optimized,
|
|
28
28
|
outputDir,
|
|
29
29
|
outputFormat,
|
|
30
30
|
outputProvided,
|
|
@@ -37,9 +37,9 @@ export const parseCodexCliArgs = (argv: string[]): CodexCliOptions => {
|
|
|
37
37
|
dbPath,
|
|
38
38
|
flat,
|
|
39
39
|
includeCommentary,
|
|
40
|
+
includeMetadata,
|
|
40
41
|
includeTools,
|
|
41
42
|
inputDir,
|
|
42
|
-
optimized,
|
|
43
43
|
outputDir,
|
|
44
44
|
outputFormat,
|
|
45
45
|
outputProvided,
|
|
@@ -58,9 +58,9 @@ export const parseCodexCliArgs = (argv: string[]): CodexCliOptions => {
|
|
|
58
58
|
dbPath,
|
|
59
59
|
flat,
|
|
60
60
|
includeCommentary,
|
|
61
|
+
includeMetadata,
|
|
61
62
|
includeTools,
|
|
62
63
|
inputDir,
|
|
63
|
-
optimized,
|
|
64
64
|
outputDir: outputDir ?? DEFAULT_OUTPUT_DIR,
|
|
65
65
|
outputFormat,
|
|
66
66
|
projectFilter,
|
|
@@ -73,9 +73,9 @@ type CodexCliState = {
|
|
|
73
73
|
dbPath: string;
|
|
74
74
|
flat: boolean;
|
|
75
75
|
includeCommentary: boolean;
|
|
76
|
+
includeMetadata: boolean;
|
|
76
77
|
includeTools: boolean;
|
|
77
78
|
inputDir: string;
|
|
78
|
-
optimized: boolean;
|
|
79
79
|
outputDir: string | null;
|
|
80
80
|
outputFormat: ExportFormat;
|
|
81
81
|
outputProvided: boolean;
|
|
@@ -142,12 +142,12 @@ const applyCodexCliArg = (argv: string[], index: number, state: CodexCliState):
|
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
if (arg === '--
|
|
145
|
+
if (arg === '--no-metadata') {
|
|
146
146
|
return {
|
|
147
147
|
index,
|
|
148
148
|
state: {
|
|
149
149
|
...state,
|
|
150
|
-
|
|
150
|
+
includeMetadata: false,
|
|
151
151
|
},
|
|
152
152
|
};
|
|
153
153
|
}
|
|
@@ -220,7 +220,7 @@ export const getCodexHelpText = (): string => {
|
|
|
220
220
|
'Usage:',
|
|
221
221
|
' codex-chats',
|
|
222
222
|
' codex-chats --interactive',
|
|
223
|
-
' codex-chats [--db FILE] [--input DIR] [--output DIR] [--cwd DIR] [--project NAME] [--
|
|
223
|
+
' codex-chats [--db FILE] [--input DIR] [--output DIR] [--cwd DIR] [--project NAME] [--no-metadata] [--tools] [--flat] [--output-format md|txt] [codex://threads/<thread-id> ...]',
|
|
224
224
|
'',
|
|
225
225
|
'Options:',
|
|
226
226
|
` --db Thread database path (default: ${DEFAULT_DB_PATH})`,
|
|
@@ -230,7 +230,7 @@ export const getCodexHelpText = (): string => {
|
|
|
230
230
|
' --project Only export chats whose cwd basename matches this project name',
|
|
231
231
|
' codex://threads/<id>',
|
|
232
232
|
' Only export the exact threads referenced by these Codex deeplinks',
|
|
233
|
-
' --
|
|
233
|
+
' --no-metadata Omit the chat metadata section from the export header',
|
|
234
234
|
' --tools Include tool-call logs such as exec_command invocations',
|
|
235
235
|
' --flat Write all exports into one folder instead of nested subfolders',
|
|
236
236
|
' --output-format Output file format: md or txt (default: md)',
|
|
@@ -40,16 +40,16 @@ export const convertSessionFile = async (target: ExportTarget, options: CodexCli
|
|
|
40
40
|
return null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
if (options.optimized) {
|
|
44
|
-
return transcriptState.sections.join('\n\n').trimEnd() + '\n';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
43
|
const title = getTitle(target, transcriptState.sessionMeta);
|
|
48
|
-
const metadata = buildMetadataEntries(target, transcriptState.sessionMeta, options);
|
|
49
44
|
const parts = [
|
|
50
45
|
renderDocumentTitle(title, options.outputFormat),
|
|
51
46
|
'',
|
|
52
|
-
|
|
47
|
+
options.includeMetadata
|
|
48
|
+
? renderMetadataBlock(
|
|
49
|
+
buildMetadataEntries(target, transcriptState.sessionMeta, options),
|
|
50
|
+
options.outputFormat,
|
|
51
|
+
)
|
|
52
|
+
: '',
|
|
53
53
|
...transcriptState.sections,
|
|
54
54
|
].filter(Boolean);
|
|
55
55
|
return parts.join('\n').trimEnd() + '\n';
|
|
@@ -69,7 +69,6 @@ export const writeSessionFileExport = async (
|
|
|
69
69
|
assistantModel: target.thread?.model ?? null,
|
|
70
70
|
sections: [],
|
|
71
71
|
sessionMeta: {},
|
|
72
|
-
startedTranscript: false,
|
|
73
72
|
};
|
|
74
73
|
let wroteSection = false;
|
|
75
74
|
|
|
@@ -82,7 +81,7 @@ export const writeSessionFileExport = async (
|
|
|
82
81
|
continue;
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
transcriptStream.write(transform(wroteSection ? `${getSectionSeparator(
|
|
84
|
+
transcriptStream.write(transform(wroteSection ? `${getSectionSeparator()}${block}` : block));
|
|
86
85
|
wroteSection = true;
|
|
87
86
|
}
|
|
88
87
|
await finalizeExportWriteStream(transcriptStream);
|
|
@@ -124,7 +123,6 @@ type CodexTranscriptState = {
|
|
|
124
123
|
assistantModel: string | null;
|
|
125
124
|
sessionMeta: SessionMeta;
|
|
126
125
|
sections: string[];
|
|
127
|
-
startedTranscript: boolean;
|
|
128
126
|
};
|
|
129
127
|
|
|
130
128
|
const collectCodexTranscript = async (
|
|
@@ -136,7 +134,6 @@ const collectCodexTranscript = async (
|
|
|
136
134
|
assistantModel,
|
|
137
135
|
sections: [],
|
|
138
136
|
sessionMeta: {},
|
|
139
|
-
startedTranscript: false,
|
|
140
137
|
};
|
|
141
138
|
|
|
142
139
|
for await (const parsed of readJsonlObjects(sessionFile)) {
|
|
@@ -146,9 +143,7 @@ const collectCodexTranscript = async (
|
|
|
146
143
|
return state;
|
|
147
144
|
};
|
|
148
145
|
|
|
149
|
-
const getSectionSeparator = (
|
|
150
|
-
return options.optimized ? '\n\n' : '\n';
|
|
151
|
-
};
|
|
146
|
+
const getSectionSeparator = () => '\n';
|
|
152
147
|
|
|
153
148
|
const processCodexTranscriptRecord = (
|
|
154
149
|
parsed: Record<string, JsonValue>,
|
|
@@ -181,58 +176,23 @@ const renderCodexTranscriptRecord = (
|
|
|
181
176
|
return '';
|
|
182
177
|
}
|
|
183
178
|
|
|
184
|
-
return options.
|
|
185
|
-
? renderCompactToolBlock(tool, options.outputFormat)
|
|
186
|
-
: renderToolBlock(tool, options.outputFormat);
|
|
179
|
+
return renderToolBlock(tool, options.outputFormat);
|
|
187
180
|
};
|
|
188
181
|
|
|
189
182
|
const processCodexMessageRecord = (message: MessageRecord, options: CodexCliOptions, state: CodexTranscriptState) => {
|
|
190
|
-
if (options.optimized) {
|
|
191
|
-
return processOptimizedCodexMessageRecord(message, options, state);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
183
|
return renderMessageBlock(message, options.outputFormat, state.assistantModel, options.includeCommentary);
|
|
195
184
|
};
|
|
196
185
|
|
|
197
|
-
const processOptimizedCodexMessageRecord = (
|
|
198
|
-
message: MessageRecord,
|
|
199
|
-
options: CodexCliOptions,
|
|
200
|
-
state: CodexTranscriptState,
|
|
201
|
-
) => {
|
|
202
|
-
if (message.role !== 'user' && message.role !== 'assistant') {
|
|
203
|
-
return '';
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (message.role === 'assistant' && message.phase === 'commentary' && !options.includeCommentary) {
|
|
207
|
-
return '';
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const compact = compactMessageText(message, true);
|
|
211
|
-
if (!compact) {
|
|
212
|
-
return '';
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (!state.startedTranscript) {
|
|
216
|
-
if (shouldSkipOptimizedPrelude(message.role, compact)) {
|
|
217
|
-
return '';
|
|
218
|
-
}
|
|
219
|
-
state.startedTranscript = true;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return renderCompactBlock(message, compact, options.outputFormat, state.assistantModel);
|
|
223
|
-
};
|
|
224
|
-
|
|
225
186
|
const buildStreamExportPrefix = (target: ExportTarget, sessionMeta: SessionMeta, options: CodexCliOptions) => {
|
|
226
|
-
if (options.
|
|
187
|
+
if (!options.includeMetadata) {
|
|
227
188
|
return '';
|
|
228
189
|
}
|
|
229
190
|
|
|
230
191
|
const title = getTitle(target, sessionMeta);
|
|
231
|
-
const metadata = buildMetadataEntries(target, sessionMeta, options);
|
|
232
192
|
const parts = [
|
|
233
193
|
renderDocumentTitle(title, options.outputFormat),
|
|
234
194
|
'',
|
|
235
|
-
renderMetadataBlock(
|
|
195
|
+
renderMetadataBlock(buildMetadataEntries(target, sessionMeta, options), options.outputFormat),
|
|
236
196
|
]
|
|
237
197
|
.filter(Boolean)
|
|
238
198
|
.join('\n');
|
|
@@ -240,13 +200,6 @@ const buildStreamExportPrefix = (target: ExportTarget, sessionMeta: SessionMeta,
|
|
|
240
200
|
return `${parts}\n`;
|
|
241
201
|
};
|
|
242
202
|
|
|
243
|
-
export const compactMessageText = (message: MessageRecord, optimized: boolean): string => {
|
|
244
|
-
const rawText = extractText(message.content);
|
|
245
|
-
const cleaned = stripPreviewBlock(rawText);
|
|
246
|
-
|
|
247
|
-
return optimized ? optimizePlainText(optimizeRenderedText(cleaned)) : cleaned.trim();
|
|
248
|
-
};
|
|
249
|
-
|
|
250
203
|
export const formatToolOutputSummary = (outputText: string, outputFormat: ExportFormat): string => {
|
|
251
204
|
if (!outputText) {
|
|
252
205
|
return '';
|
|
@@ -308,27 +261,6 @@ const getTitle = (target: ExportTarget, sessionMeta: SessionMeta): string => {
|
|
|
308
261
|
return sessionMeta.id ?? path.basename(target.sessionFile, '.jsonl');
|
|
309
262
|
};
|
|
310
263
|
|
|
311
|
-
const shouldSkipOptimizedPrelude = (role: string, text: string): boolean => {
|
|
312
|
-
if (role !== 'user') {
|
|
313
|
-
return true;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return (
|
|
317
|
-
text.startsWith('AGENTS.md instructions for ') ||
|
|
318
|
-
text.startsWith('# AGENTS.md instructions for ') ||
|
|
319
|
-
text.startsWith('<permissions instructions>') ||
|
|
320
|
-
text.startsWith('<environment_context>') ||
|
|
321
|
-
text.startsWith('<app-context>') ||
|
|
322
|
-
text.startsWith('<collaboration_mode>') ||
|
|
323
|
-
text.startsWith('<skills_instructions>') ||
|
|
324
|
-
text.startsWith('You are Codex, a coding agent based on GPT-5.') ||
|
|
325
|
-
text.startsWith('Read this before making changes.') ||
|
|
326
|
-
text.includes('Filesystem sandboxing defines which files can be read or written.') ||
|
|
327
|
-
text.includes('approval_policy') ||
|
|
328
|
-
text.includes('base_instructions')
|
|
329
|
-
);
|
|
330
|
-
};
|
|
331
|
-
|
|
332
264
|
const buildMetadataEntries = (
|
|
333
265
|
target: ExportTarget,
|
|
334
266
|
sessionMeta: SessionMeta,
|
|
@@ -585,7 +517,7 @@ const renderMessageBlock = (
|
|
|
585
517
|
return '';
|
|
586
518
|
}
|
|
587
519
|
|
|
588
|
-
const text = cleanExtractedText(extractText(message.content)).trim();
|
|
520
|
+
const text = cleanExtractedText(stripPreviewBlock(extractText(message.content))).trim();
|
|
589
521
|
if (!text || shouldSkipMessage(message.role, text)) {
|
|
590
522
|
return '';
|
|
591
523
|
}
|
|
@@ -606,36 +538,6 @@ const renderToolBlock = (tool: ToolRecord, outputFormat: ExportFormat): string =
|
|
|
606
538
|
return summary ? renderSection('Tool Output', summary, outputFormat) : '';
|
|
607
539
|
};
|
|
608
540
|
|
|
609
|
-
const renderCompactBlock = (
|
|
610
|
-
message: MessageRecord,
|
|
611
|
-
text: string,
|
|
612
|
-
outputFormat: ExportFormat,
|
|
613
|
-
assistantModel: string | null,
|
|
614
|
-
): string => {
|
|
615
|
-
const prefix = message.role === 'user' ? 'U:' : `${formatModelLabel(message.model ?? assistantModel)}:`;
|
|
616
|
-
const lines = text.split('\n');
|
|
617
|
-
const [firstLine, ...rest] = lines;
|
|
618
|
-
|
|
619
|
-
if (rest.length === 0) {
|
|
620
|
-
return `${prefix} ${normalizeCompactLiteral(firstLine, outputFormat)}`;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
return [
|
|
624
|
-
`${prefix} ${normalizeCompactLiteral(firstLine, outputFormat)}`,
|
|
625
|
-
...rest.map((line) => normalizeCompactLiteral(line, outputFormat)),
|
|
626
|
-
].join('\n');
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
const renderCompactToolBlock = (tool: ToolRecord, outputFormat: ExportFormat): string => {
|
|
630
|
-
if (tool.kind === 'call') {
|
|
631
|
-
const details = formatCompactToolCall(tool, outputFormat);
|
|
632
|
-
return details ? `T: ${details}` : '';
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const summary = formatCompactToolOutput(tool.outputText ?? '');
|
|
636
|
-
return summary ? `R: ${summary}` : '';
|
|
637
|
-
};
|
|
638
|
-
|
|
639
541
|
const stripPreviewBlock = (text: string): string => {
|
|
640
542
|
const parts = text
|
|
641
543
|
.split(/\n{2,}/)
|
|
@@ -662,49 +564,15 @@ const stripPreviewBlock = (text: string): string => {
|
|
|
662
564
|
return parts.slice(1).join('\n\n');
|
|
663
565
|
};
|
|
664
566
|
|
|
665
|
-
const optimizeRenderedText = (text: string): string => {
|
|
666
|
-
return text
|
|
667
|
-
.replace(/^\*Phase:\s+`[^`]+`\*\s*\n*/gm, '')
|
|
668
|
-
.replace(/^\s*<image\b[^>]*>\s*$/gim, '')
|
|
669
|
-
.replace(/^\s*<\/image>\s*$/gim, '')
|
|
670
|
-
.replace(/^\s*\[Image attached\]\s*$/gim, '')
|
|
671
|
-
.replace(/^#{1,6}\s+/gm, '')
|
|
672
|
-
.replace(/^```[^\n]*\n?/gm, '')
|
|
673
|
-
.replace(/\n```$/gm, '')
|
|
674
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
675
|
-
.replace(/^##\s+User\s*$/gm, 'User:')
|
|
676
|
-
.replace(/^##\s+Assistant\s*$/gm, 'Assistant:')
|
|
677
|
-
.replace(/`([^`]+)`/g, '$1')
|
|
678
|
-
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
679
|
-
.replace(/\*([^*\n]+)\*/g, '$1')
|
|
680
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
681
|
-
.trim();
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
const optimizePlainText = (text: string): string => {
|
|
685
|
-
const normalized = text
|
|
686
|
-
.replace(/\r/g, '')
|
|
687
|
-
.replace(/^\s*<image\b[^>]*>\s*$/gim, '')
|
|
688
|
-
.replace(/^\s*<\/image>\s*$/gim, '')
|
|
689
|
-
.replace(/^\s*\[Image attached\]\s*$/gim, '')
|
|
690
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
691
|
-
.replace(/`([^`]+)`/g, '$1')
|
|
692
|
-
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
693
|
-
.replace(/\*([^*\n]+)\*/g, '$1');
|
|
694
|
-
|
|
695
|
-
return normalized
|
|
696
|
-
.split('\n')
|
|
697
|
-
.map((line) => line.replace(/[ \t]+$/g, ''))
|
|
698
|
-
.join('\n')
|
|
699
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
700
|
-
.trim();
|
|
701
|
-
};
|
|
702
|
-
|
|
703
567
|
const shouldSkipMessage = (role: string, text: string): boolean => {
|
|
704
568
|
if (text.startsWith('<environment_context>')) {
|
|
705
569
|
return true;
|
|
706
570
|
}
|
|
707
571
|
|
|
572
|
+
if (text.startsWith('AGENTS.md instructions for ')) {
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
|
|
708
576
|
if (text.startsWith('# AGENTS.md instructions for ')) {
|
|
709
577
|
return true;
|
|
710
578
|
}
|
|
@@ -725,44 +593,6 @@ const formatToolCallDetails = (tool: ToolRecord, outputFormat: ExportFormat): st
|
|
|
725
593
|
return details.cmd ? `Command: ${formatInlineLiteral(details.cmd, outputFormat)}` : '';
|
|
726
594
|
};
|
|
727
595
|
|
|
728
|
-
const formatCompactToolCall = (tool: ToolRecord, outputFormat: ExportFormat): string => {
|
|
729
|
-
if (tool.name === 'exec_command') {
|
|
730
|
-
const details = parseExecCommandArguments(tool.argumentsText);
|
|
731
|
-
if (!details.cmd) {
|
|
732
|
-
return 'exec_command';
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
const command = formatInlineLiteral(details.cmd, outputFormat);
|
|
736
|
-
return details.workdir ? `exec_command ${command} @ ${details.workdir}` : `exec_command ${command}`;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
return tool.callId ? `${tool.name} (${tool.callId})` : tool.name;
|
|
740
|
-
};
|
|
741
|
-
|
|
742
|
-
const formatCompactToolOutput = (outputText: string): string => {
|
|
743
|
-
if (!outputText) {
|
|
744
|
-
return '';
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
const lines = outputText
|
|
748
|
-
.split('\n')
|
|
749
|
-
.map((line) => line.trim())
|
|
750
|
-
.filter(Boolean);
|
|
751
|
-
|
|
752
|
-
const exit = lines.find((line) => line.startsWith('Process exited with code '));
|
|
753
|
-
const wall = lines.find((line) => line.startsWith('Wall time: '));
|
|
754
|
-
|
|
755
|
-
if (exit && wall) {
|
|
756
|
-
return `${exit.replace('Process ', '')}; ${wall.toLowerCase()}`;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
if (exit) {
|
|
760
|
-
return exit.replace('Process ', '');
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
return '';
|
|
764
|
-
};
|
|
765
|
-
|
|
766
596
|
const extractText = (content: JsonValue): string => {
|
|
767
597
|
if (typeof content === 'string') {
|
|
768
598
|
return content;
|
|
@@ -802,7 +632,3 @@ const extractContentPart = (value: JsonValue): string => {
|
|
|
802
632
|
|
|
803
633
|
return text ?? '';
|
|
804
634
|
};
|
|
805
|
-
|
|
806
|
-
const normalizeCompactLiteral = (value: string, outputFormat: ExportFormat): string => {
|
|
807
|
-
return outputFormat === 'md' ? value : value.replace(/`([^`]+)`/g, '$1');
|
|
808
|
-
};
|