promptarc 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +33 -25
  2. package/dist/bin.js +561 -45
  3. package/dist/share-direct.js +360 -0
  4. package/dist/web/.next/BUILD_ID +1 -1
  5. package/dist/web/.next/app-build-manifest.json +86 -79
  6. package/dist/web/.next/app-path-routes-manifest.json +17 -16
  7. package/dist/web/.next/build-manifest.json +2 -2
  8. package/dist/web/.next/prerender-manifest.json +14 -14
  9. package/dist/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  10. package/dist/web/.next/server/app/api/admin/backfill-ai/route_client-reference-manifest.js +1 -1
  11. package/dist/web/.next/server/app/api/admin/backfill-search/route_client-reference-manifest.js +1 -1
  12. package/dist/web/.next/server/app/api/ai/context/route.js +31 -0
  13. package/dist/web/.next/server/app/api/ai/context/route.js.nft.json +1 -0
  14. package/dist/web/.next/server/app/api/ai/context/route_client-reference-manifest.js +1 -0
  15. package/dist/web/.next/server/app/api/ai/pr-summary/route_client-reference-manifest.js +1 -1
  16. package/dist/web/.next/server/app/api/ai/pr-summary-local/route_client-reference-manifest.js +1 -1
  17. package/dist/web/.next/server/app/api/ai/process/route_client-reference-manifest.js +1 -1
  18. package/dist/web/.next/server/app/api/cli/download/route_client-reference-manifest.js +1 -1
  19. package/dist/web/.next/server/app/api/cli/feedback/route_client-reference-manifest.js +1 -1
  20. package/dist/web/.next/server/app/api/cli/init/route_client-reference-manifest.js +1 -1
  21. package/dist/web/.next/server/app/api/cli/my-shares/route_client-reference-manifest.js +1 -1
  22. package/dist/web/.next/server/app/api/cli/poll/route_client-reference-manifest.js +1 -1
  23. package/dist/web/.next/server/app/api/cli/project-settings/route_client-reference-manifest.js +1 -1
  24. package/dist/web/.next/server/app/api/cli/share-mutate/route_client-reference-manifest.js +1 -1
  25. package/dist/web/.next/server/app/api/cli/sync-list/route_client-reference-manifest.js +1 -1
  26. package/dist/web/.next/server/app/api/local/project-sessions/route_client-reference-manifest.js +1 -1
  27. package/dist/web/.next/server/app/api/local/watch/route_client-reference-manifest.js +1 -1
  28. package/dist/web/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  29. package/dist/web/.next/server/app/api/search-index/route_client-reference-manifest.js +1 -1
  30. package/dist/web/.next/server/app/api/share/download/[slug]/route_client-reference-manifest.js +1 -1
  31. package/dist/web/.next/server/app/api/share/route_client-reference-manifest.js +1 -1
  32. package/dist/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -1
  33. package/dist/web/.next/server/app/auth/callback/route_client-reference-manifest.js +1 -1
  34. package/dist/web/.next/server/app/auth/signout/route_client-reference-manifest.js +1 -1
  35. package/dist/web/.next/server/app/blog/ai-coding-agents-2026/page_client-reference-manifest.js +1 -1
  36. package/dist/web/.next/server/app/blog/page_client-reference-manifest.js +1 -1
  37. package/dist/web/.next/server/app/cli/login/page_client-reference-manifest.js +1 -1
  38. package/dist/web/.next/server/app/digest/page_client-reference-manifest.js +1 -1
  39. package/dist/web/.next/server/app/feedback/page_client-reference-manifest.js +1 -1
  40. package/dist/web/.next/server/app/my-projects/[projectKey]/page_client-reference-manifest.js +1 -1
  41. package/dist/web/.next/server/app/my-projects/page_client-reference-manifest.js +1 -1
  42. package/dist/web/.next/server/app/my-shares/page_client-reference-manifest.js +1 -1
  43. package/dist/web/.next/server/app/opengraph-image/route_client-reference-manifest.js +1 -1
  44. package/dist/web/.next/server/app/page.js +1 -1
  45. package/dist/web/.next/server/app/page_client-reference-manifest.js +1 -1
  46. package/dist/web/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
  47. package/dist/web/.next/server/app/projects/[id]/page_client-reference-manifest.js +1 -1
  48. package/dist/web/.next/server/app/r/[slug]/opengraph-image/route_client-reference-manifest.js +1 -1
  49. package/dist/web/.next/server/app/r/[slug]/page.js +1 -1
  50. package/dist/web/.next/server/app/r/[slug]/page_client-reference-manifest.js +1 -1
  51. package/dist/web/.next/server/app/robots.txt/route.js.nft.json +1 -1
  52. package/dist/web/.next/server/app/robots.txt/route_client-reference-manifest.js +1 -1
  53. package/dist/web/.next/server/app/search/page_client-reference-manifest.js +1 -1
  54. package/dist/web/.next/server/app/sessions/[projectId]/[sessionId]/page_client-reference-manifest.js +1 -1
  55. package/dist/web/.next/server/app/sign-in/page_client-reference-manifest.js +1 -1
  56. package/dist/web/.next/server/app/sitemap.xml/route.js.nft.json +1 -1
  57. package/dist/web/.next/server/app/sitemap.xml/route_client-reference-manifest.js +1 -1
  58. package/dist/web/.next/server/app/sitemap.xml.body +8 -8
  59. package/dist/web/.next/server/app/terms/page_client-reference-manifest.js +1 -1
  60. package/dist/web/.next/server/app-paths-manifest.json +17 -16
  61. package/dist/web/.next/server/functions-config-manifest.json +10 -7
  62. package/dist/web/.next/server/pages/500.html +1 -1
  63. package/dist/web/.next/server/server-reference-manifest.js +1 -1
  64. package/dist/web/.next/server/server-reference-manifest.json +1 -1
  65. package/dist/web/.next/static/LF69v3WA6LbEAkvRHNqfG/_buildManifest.js +1 -0
  66. package/dist/web/.next/static/chunks/app/_not-found/page-0f1123e35eb8f046.js +1 -0
  67. package/dist/web/.next/static/chunks/app/api/admin/backfill-ai/route-0f1123e35eb8f046.js +1 -0
  68. package/dist/web/.next/static/chunks/app/api/admin/backfill-search/route-0f1123e35eb8f046.js +1 -0
  69. package/dist/web/.next/static/chunks/app/api/ai/context/route-0f1123e35eb8f046.js +1 -0
  70. package/dist/web/.next/static/chunks/app/api/ai/pr-summary/route-0f1123e35eb8f046.js +1 -0
  71. package/dist/web/.next/static/chunks/app/api/ai/pr-summary-local/route-0f1123e35eb8f046.js +1 -0
  72. package/dist/web/.next/static/chunks/app/api/ai/process/route-0f1123e35eb8f046.js +1 -0
  73. package/dist/web/.next/static/chunks/app/api/cli/download/route-0f1123e35eb8f046.js +1 -0
  74. package/dist/web/.next/static/chunks/app/api/cli/feedback/route-0f1123e35eb8f046.js +1 -0
  75. package/dist/web/.next/static/chunks/app/api/cli/init/route-0f1123e35eb8f046.js +1 -0
  76. package/dist/web/.next/static/chunks/app/api/cli/my-shares/route-0f1123e35eb8f046.js +1 -0
  77. package/dist/web/.next/static/chunks/app/api/cli/poll/route-0f1123e35eb8f046.js +1 -0
  78. package/dist/web/.next/static/chunks/app/api/cli/project-settings/route-0f1123e35eb8f046.js +1 -0
  79. package/dist/web/.next/static/chunks/app/api/cli/share-mutate/route-0f1123e35eb8f046.js +1 -0
  80. package/dist/web/.next/static/chunks/app/api/cli/sync-list/route-0f1123e35eb8f046.js +1 -0
  81. package/dist/web/.next/static/chunks/app/api/local/project-sessions/route-0f1123e35eb8f046.js +1 -0
  82. package/dist/web/.next/static/chunks/app/api/local/watch/route-0f1123e35eb8f046.js +1 -0
  83. package/dist/web/.next/static/chunks/app/api/search/route-0f1123e35eb8f046.js +1 -0
  84. package/dist/web/.next/static/chunks/app/api/search-index/route-0f1123e35eb8f046.js +1 -0
  85. package/dist/web/.next/static/chunks/app/api/share/download/[slug]/route-0f1123e35eb8f046.js +1 -0
  86. package/dist/web/.next/static/chunks/app/api/share/route-0f1123e35eb8f046.js +1 -0
  87. package/dist/web/.next/static/chunks/app/api/upload/route-0f1123e35eb8f046.js +1 -0
  88. package/dist/web/.next/static/chunks/app/auth/callback/route-0f1123e35eb8f046.js +1 -0
  89. package/dist/web/.next/static/chunks/app/auth/signout/route-0f1123e35eb8f046.js +1 -0
  90. package/dist/web/.next/static/chunks/app/blog/ai-coding-agents-2026/page-0f1123e35eb8f046.js +1 -0
  91. package/dist/web/.next/static/chunks/app/opengraph-image/route-0f1123e35eb8f046.js +1 -0
  92. package/dist/web/.next/static/chunks/app/{page-f7b69fa944b46c20.js → page-95394e3c6370084f.js} +1 -1
  93. package/dist/web/.next/static/chunks/app/r/[slug]/opengraph-image/route-0f1123e35eb8f046.js +1 -0
  94. package/dist/web/.next/static/chunks/app/robots.txt/route-0f1123e35eb8f046.js +1 -0
  95. package/dist/web/.next/static/chunks/app/sitemap.xml/route-0f1123e35eb8f046.js +1 -0
  96. package/dist/web/.next/static/css/c76bb7513858c50c.css +3 -0
  97. package/package.json +1 -1
  98. package/dist/web/.next/static/ABHGCNY7MSdkh00Z4Y8wS/_buildManifest.js +0 -1
  99. package/dist/web/.next/static/chunks/app/_not-found/page-fd6592d30c58fa5e.js +0 -1
  100. package/dist/web/.next/static/chunks/app/api/admin/backfill-ai/route-fd6592d30c58fa5e.js +0 -1
  101. package/dist/web/.next/static/chunks/app/api/admin/backfill-search/route-fd6592d30c58fa5e.js +0 -1
  102. package/dist/web/.next/static/chunks/app/api/ai/pr-summary/route-fd6592d30c58fa5e.js +0 -1
  103. package/dist/web/.next/static/chunks/app/api/ai/pr-summary-local/route-fd6592d30c58fa5e.js +0 -1
  104. package/dist/web/.next/static/chunks/app/api/ai/process/route-fd6592d30c58fa5e.js +0 -1
  105. package/dist/web/.next/static/chunks/app/api/cli/download/route-fd6592d30c58fa5e.js +0 -1
  106. package/dist/web/.next/static/chunks/app/api/cli/feedback/route-fd6592d30c58fa5e.js +0 -1
  107. package/dist/web/.next/static/chunks/app/api/cli/init/route-fd6592d30c58fa5e.js +0 -1
  108. package/dist/web/.next/static/chunks/app/api/cli/my-shares/route-fd6592d30c58fa5e.js +0 -1
  109. package/dist/web/.next/static/chunks/app/api/cli/poll/route-fd6592d30c58fa5e.js +0 -1
  110. package/dist/web/.next/static/chunks/app/api/cli/project-settings/route-fd6592d30c58fa5e.js +0 -1
  111. package/dist/web/.next/static/chunks/app/api/cli/share-mutate/route-fd6592d30c58fa5e.js +0 -1
  112. package/dist/web/.next/static/chunks/app/api/cli/sync-list/route-fd6592d30c58fa5e.js +0 -1
  113. package/dist/web/.next/static/chunks/app/api/local/project-sessions/route-fd6592d30c58fa5e.js +0 -1
  114. package/dist/web/.next/static/chunks/app/api/local/watch/route-fd6592d30c58fa5e.js +0 -1
  115. package/dist/web/.next/static/chunks/app/api/search/route-fd6592d30c58fa5e.js +0 -1
  116. package/dist/web/.next/static/chunks/app/api/search-index/route-fd6592d30c58fa5e.js +0 -1
  117. package/dist/web/.next/static/chunks/app/api/share/download/[slug]/route-fd6592d30c58fa5e.js +0 -1
  118. package/dist/web/.next/static/chunks/app/api/share/route-fd6592d30c58fa5e.js +0 -1
  119. package/dist/web/.next/static/chunks/app/api/upload/route-fd6592d30c58fa5e.js +0 -1
  120. package/dist/web/.next/static/chunks/app/auth/callback/route-fd6592d30c58fa5e.js +0 -1
  121. package/dist/web/.next/static/chunks/app/auth/signout/route-fd6592d30c58fa5e.js +0 -1
  122. package/dist/web/.next/static/chunks/app/blog/ai-coding-agents-2026/page-fd6592d30c58fa5e.js +0 -1
  123. package/dist/web/.next/static/chunks/app/opengraph-image/route-fd6592d30c58fa5e.js +0 -1
  124. package/dist/web/.next/static/chunks/app/r/[slug]/opengraph-image/route-fd6592d30c58fa5e.js +0 -1
  125. package/dist/web/.next/static/chunks/app/robots.txt/route-fd6592d30c58fa5e.js +0 -1
  126. package/dist/web/.next/static/chunks/app/sitemap.xml/route-fd6592d30c58fa5e.js +0 -1
  127. package/dist/web/.next/static/css/b3ccdd7835e6edda.css +0 -3
  128. /package/dist/web/.next/static/{ABHGCNY7MSdkh00Z4Y8wS → LF69v3WA6LbEAkvRHNqfG}/_ssgManifest.js +0 -0
@@ -0,0 +1,360 @@
1
+ /**
2
+ * Direct share: build a SharedReplay artifact locally and POST it
3
+ * to the hosted /api/upload endpoint. No local dashboard needed.
4
+ *
5
+ * This is a self-contained implementation that reads a JSONL session
6
+ * file, builds a minimal SharedReplay, strips secrets, and uploads.
7
+ * It duplicates some logic from @promptarc/core intentionally — the
8
+ * CLI can't import from the core workspace package at runtime.
9
+ */
10
+ import { readFileSync } from 'node:fs';
11
+ import { basename } from 'node:path';
12
+ // ─── Secret patterns for redaction ────────────────────────────────────────
13
+ const SECRET_PATTERNS = [
14
+ /\bsk-ant-[a-zA-Z0-9_-]{10,}/g,
15
+ /\bsk-(?:proj-)?[a-zA-Z0-9_-]{20,}/g,
16
+ /\bAKIA[0-9A-Z]{16}/g,
17
+ /\bghp_[A-Za-z0-9]{20,}/g,
18
+ /\bghs_[A-Za-z0-9]{20,}/g,
19
+ /\bgho_[A-Za-z0-9]{20,}/g,
20
+ /\bglpat-[A-Za-z0-9_-]{20,}/g,
21
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g,
22
+ /\bsb_secret_[A-Za-z0-9_-]{10,}/g,
23
+ /\bxoxb-[0-9]{10,}-[A-Za-z0-9-]+/g,
24
+ /\bnpm_[A-Za-z0-9]{20,}/g,
25
+ ];
26
+ const HOME_RE = new RegExp(process.env.HOME?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') ?? '/dev/null', 'g');
27
+ function redactString(s) {
28
+ let secrets = 0;
29
+ let paths = 0;
30
+ let result = s;
31
+ for (const pat of SECRET_PATTERNS) {
32
+ result = result.replace(pat, () => { secrets++; return '[REDACTED]'; });
33
+ }
34
+ if (HOME_RE.test(result)) {
35
+ result = result.replace(HOME_RE, '~');
36
+ paths++;
37
+ }
38
+ return { text: result, secrets, paths };
39
+ }
40
+ // ─── JSONL → SharedReplay ─────────────────────────────────────────────────
41
+ export function buildReplayFromJsonl(filePath, projectName) {
42
+ const raw = readFileSync(filePath, 'utf8');
43
+ const lines = raw.split('\n').filter(Boolean);
44
+ const messages = [];
45
+ let msgIndex = 0;
46
+ let toolCallCount = 0;
47
+ let fileChangeCount = 0;
48
+ let userMessageCount = 0;
49
+ let firstTimestamp = '';
50
+ let lastTimestamp = '';
51
+ let title = '';
52
+ let totalSecrets = 0;
53
+ let totalPaths = 0;
54
+ for (const line of lines) {
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(line);
58
+ }
59
+ catch {
60
+ continue;
61
+ }
62
+ // Claude Code format.
63
+ if (parsed.type === 'user' || parsed.type === 'assistant') {
64
+ const role = parsed.type;
65
+ const ts = parsed.timestamp ?? new Date().toISOString();
66
+ if (!firstTimestamp)
67
+ firstTimestamp = ts;
68
+ lastTimestamp = ts;
69
+ const content = parseClaudeContent(parsed, role);
70
+ if (content.length === 0)
71
+ continue;
72
+ // Redact content.
73
+ const redacted = content.map((block) => redactBlock(block));
74
+ totalSecrets += redacted.reduce((n, r) => n + r.secrets, 0);
75
+ totalPaths += redacted.reduce((n, r) => n + r.paths, 0);
76
+ if (role === 'user') {
77
+ userMessageCount++;
78
+ if (!title) {
79
+ const textBlock = redacted.find((r) => r.block.type === 'text');
80
+ if (textBlock && textBlock.block.type === 'text') {
81
+ title = textBlock.block.text.slice(0, 200);
82
+ }
83
+ }
84
+ }
85
+ for (const r of redacted) {
86
+ if (r.block.type === 'tool_use')
87
+ toolCallCount++;
88
+ if (r.block.type === 'tool_use' && ['Edit', 'Write', 'apply_patch', 'write_file'].includes(r.block.name)) {
89
+ fileChangeCount++;
90
+ }
91
+ }
92
+ messages.push({
93
+ id: parsed.uuid ?? `msg-${msgIndex}`,
94
+ parentId: parsed.parentUuid ?? null,
95
+ role,
96
+ timestamp: ts,
97
+ content: redacted.map((r) => r.block),
98
+ ...(parsed.type === 'assistant' && parsed.message?.model
99
+ ? { model: parsed.message.model }
100
+ : {}),
101
+ isSidechain: parsed.isSidechain ?? false,
102
+ });
103
+ msgIndex++;
104
+ continue;
105
+ }
106
+ // Codex format.
107
+ if (parsed.type === 'response_item' || parsed.type === 'event_msg') {
108
+ const ts = parsed.timestamp ?? new Date().toISOString();
109
+ if (!firstTimestamp)
110
+ firstTimestamp = ts;
111
+ lastTimestamp = ts;
112
+ const payload = parsed.payload;
113
+ if (!payload)
114
+ continue;
115
+ if (payload.type === 'message' && (payload.role === 'user' || payload.role === 'assistant')) {
116
+ const role = payload.role;
117
+ const contentArr = payload.content;
118
+ if (!Array.isArray(contentArr))
119
+ continue;
120
+ const blocks = contentArr
121
+ .map((b) => parseCodexBlock(b))
122
+ .filter((b) => b !== null);
123
+ if (blocks.length === 0)
124
+ continue;
125
+ const redacted = blocks.map(redactBlock);
126
+ totalSecrets += redacted.reduce((n, r) => n + r.secrets, 0);
127
+ if (role === 'user')
128
+ userMessageCount++;
129
+ if (role === 'user' && !title) {
130
+ const tb = redacted.find((r) => r.block.type === 'text');
131
+ if (tb && tb.block.type === 'text')
132
+ title = tb.block.text.slice(0, 200);
133
+ }
134
+ messages.push({
135
+ id: `codex-${msgIndex}`,
136
+ parentId: null,
137
+ role,
138
+ timestamp: ts,
139
+ content: redacted.map((r) => r.block),
140
+ isSidechain: false,
141
+ });
142
+ msgIndex++;
143
+ }
144
+ else if (payload.type === 'function_call') {
145
+ toolCallCount++;
146
+ const block = {
147
+ type: 'tool_use',
148
+ id: payload.call_id ?? `call-${msgIndex}`,
149
+ name: payload.name ?? 'unknown',
150
+ input: safeParseJson(payload.arguments),
151
+ };
152
+ appendToLastAssistant(messages, block, ts, msgIndex++);
153
+ }
154
+ else if (payload.type === 'function_call_output') {
155
+ const output = payload.output ?? '';
156
+ const r = redactString(output);
157
+ totalSecrets += r.secrets;
158
+ const block = {
159
+ type: 'tool_result',
160
+ toolUseId: payload.call_id ?? '',
161
+ output: r.text.slice(0, 12000),
162
+ isError: false,
163
+ };
164
+ appendToLastAssistant(messages, block, ts, msgIndex++);
165
+ }
166
+ if (parsed.type === 'event_msg' && payload.type === 'user_message') {
167
+ const text = payload.message ?? '';
168
+ if (!text.trim())
169
+ continue;
170
+ const r = redactString(text);
171
+ totalSecrets += r.secrets;
172
+ if (!title)
173
+ title = r.text.slice(0, 200);
174
+ userMessageCount++;
175
+ messages.push({
176
+ id: `codex-user-${msgIndex}`,
177
+ parentId: null,
178
+ role: 'user',
179
+ timestamp: ts,
180
+ content: [{ type: 'text', text: r.text }],
181
+ isSidechain: false,
182
+ });
183
+ msgIndex++;
184
+ }
185
+ continue;
186
+ }
187
+ // Cursor format.
188
+ if (parsed.role === 'user' || parsed.role === 'assistant') {
189
+ const role = parsed.role;
190
+ const msg = parsed.message;
191
+ const contentArr = msg?.content;
192
+ if (!Array.isArray(contentArr))
193
+ continue;
194
+ const blocks = [];
195
+ for (const item of contentArr) {
196
+ const c = item;
197
+ if (c.type === 'text') {
198
+ let text = c.text ?? '';
199
+ text = text.replace(/<\/?user_query>/g, '').replace(/\[REDACTED\]/g, '').trim();
200
+ if (text) {
201
+ const r = redactString(text);
202
+ totalSecrets += r.secrets;
203
+ totalPaths += r.paths;
204
+ blocks.push({ type: 'text', text: r.text });
205
+ }
206
+ }
207
+ else if (c.type === 'tool_use') {
208
+ toolCallCount++;
209
+ blocks.push({
210
+ type: 'tool_use',
211
+ id: c.id ?? `cursor-tool-${msgIndex}`,
212
+ name: c.name ?? 'unknown',
213
+ input: c.input ?? {},
214
+ });
215
+ }
216
+ }
217
+ if (blocks.length === 0)
218
+ continue;
219
+ if (role === 'user') {
220
+ userMessageCount++;
221
+ if (!title) {
222
+ const tb = blocks.find((b) => b.type === 'text');
223
+ if (tb && tb.type === 'text')
224
+ title = tb.text.slice(0, 200);
225
+ }
226
+ }
227
+ messages.push({
228
+ id: `cursor-${msgIndex}`,
229
+ parentId: null,
230
+ role,
231
+ timestamp: new Date().toISOString(),
232
+ content: blocks,
233
+ isSidechain: false,
234
+ });
235
+ msgIndex++;
236
+ }
237
+ }
238
+ return {
239
+ formatVersion: 1,
240
+ createdAt: new Date().toISOString(),
241
+ meta: {
242
+ title: title || `Session from ${projectName}`,
243
+ projectName,
244
+ startedAt: firstTimestamp || new Date().toISOString(),
245
+ endedAt: lastTimestamp || null,
246
+ messageCount: messages.length,
247
+ userMessageCount,
248
+ toolCallCount,
249
+ fileChangeCount,
250
+ },
251
+ messages,
252
+ diffs: [],
253
+ tasks: [],
254
+ todos: [],
255
+ redactionStats: {
256
+ secretsRedacted: totalSecrets,
257
+ pathsRedacted: totalPaths,
258
+ imagesDropped: 0,
259
+ toolResultsTruncated: 0,
260
+ },
261
+ };
262
+ }
263
+ // ─── Helpers ──────────────────────────────────────────────────────────────
264
+ function parseClaudeContent(parsed, role) {
265
+ const msg = parsed.message;
266
+ if (typeof msg === 'string') {
267
+ return [{ type: 'text', text: msg }];
268
+ }
269
+ if (typeof msg === 'object' && msg) {
270
+ const content = msg.content;
271
+ if (typeof content === 'string') {
272
+ return [{ type: 'text', text: content }];
273
+ }
274
+ if (Array.isArray(content)) {
275
+ const blocks = [];
276
+ for (const item of content) {
277
+ const c = item;
278
+ if (c.type === 'text' && typeof c.text === 'string') {
279
+ blocks.push({ type: 'text', text: c.text });
280
+ }
281
+ else if (c.type === 'thinking' && typeof c.thinking === 'string') {
282
+ // Strip thinking blocks — same as buildSharedReplay.
283
+ }
284
+ else if (c.type === 'tool_use') {
285
+ blocks.push({
286
+ type: 'tool_use',
287
+ id: c.id ?? '',
288
+ name: c.name ?? '',
289
+ input: c.input ?? {},
290
+ });
291
+ }
292
+ else if (c.type === 'tool_result') {
293
+ const output = typeof c.content === 'string'
294
+ ? c.content
295
+ : typeof c.output === 'string'
296
+ ? c.output
297
+ : JSON.stringify(c.content ?? c.output ?? '');
298
+ blocks.push({
299
+ type: 'tool_result',
300
+ toolUseId: c.tool_use_id ?? c.toolUseId ?? '',
301
+ output: output.slice(0, 12000),
302
+ isError: Boolean(c.is_error ?? c.isError),
303
+ });
304
+ }
305
+ }
306
+ return blocks;
307
+ }
308
+ }
309
+ return [];
310
+ }
311
+ function parseCodexBlock(c) {
312
+ if ((c.type === 'input_text' || c.type === 'text') && typeof c.text === 'string') {
313
+ return { type: 'text', text: c.text };
314
+ }
315
+ if (c.type === 'output_text' && typeof c.text === 'string') {
316
+ return { type: 'text', text: c.text };
317
+ }
318
+ return null;
319
+ }
320
+ function redactBlock(block) {
321
+ if (block.type === 'text') {
322
+ const r = redactString(block.text);
323
+ return { block: { type: 'text', text: r.text }, secrets: r.secrets, paths: r.paths };
324
+ }
325
+ if (block.type === 'tool_result') {
326
+ const r = redactString(block.output);
327
+ return {
328
+ block: { type: 'tool_result', toolUseId: block.toolUseId, output: r.text, isError: block.isError },
329
+ secrets: r.secrets,
330
+ paths: r.paths,
331
+ };
332
+ }
333
+ return { block, secrets: 0, paths: 0 };
334
+ }
335
+ function appendToLastAssistant(messages, block, ts, idx) {
336
+ for (let i = messages.length - 1; i >= 0; i--) {
337
+ if (messages[i].role === 'assistant') {
338
+ messages[i].content.push(block);
339
+ return;
340
+ }
341
+ }
342
+ messages.push({
343
+ id: `auto-${idx}`,
344
+ parentId: null,
345
+ role: 'assistant',
346
+ timestamp: ts,
347
+ content: [block],
348
+ isSidechain: false,
349
+ });
350
+ }
351
+ function safeParseJson(s) {
352
+ if (!s)
353
+ return {};
354
+ try {
355
+ return JSON.parse(s);
356
+ }
357
+ catch {
358
+ return { raw: s };
359
+ }
360
+ }
@@ -1 +1 @@
1
- ABHGCNY7MSdkh00Z4Y8wS
1
+ LF69v3WA6LbEAkvRHNqfG