@yanzc/claude-pro 0.0.0-stage → 0.4.1

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 (58) hide show
  1. package/.env.example +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +314 -3
  4. package/bin/claude-pro.js +32 -0
  5. package/package.json +40 -6
  6. package/src/agent.js +752 -0
  7. package/src/agents.js +186 -0
  8. package/src/api.js +529 -0
  9. package/src/cache.js +150 -0
  10. package/src/checkpoints.js +184 -0
  11. package/src/claude-code.js +60 -0
  12. package/src/codex/client.js +307 -0
  13. package/src/codex/translate-request.js +239 -0
  14. package/src/codex/translate-stream.js +328 -0
  15. package/src/commands.js +839 -0
  16. package/src/config.js +453 -0
  17. package/src/context.js +109 -0
  18. package/src/filestate.js +57 -0
  19. package/src/gateway.js +143 -0
  20. package/src/hooks.js +81 -0
  21. package/src/main.js +193 -0
  22. package/src/mcp.js +290 -0
  23. package/src/modes.js +154 -0
  24. package/src/oauth.js +287 -0
  25. package/src/peers.js +157 -0
  26. package/src/print.js +106 -0
  27. package/src/prompts.js +179 -0
  28. package/src/ratelimit.js +244 -0
  29. package/src/restart.js +115 -0
  30. package/src/runtime.js +162 -0
  31. package/src/selfcheck.js +71 -0
  32. package/src/session.js +139 -0
  33. package/src/supervisor.js +110 -0
  34. package/src/tasks.js +76 -0
  35. package/src/tools/bash.js +227 -0
  36. package/src/tools/effort.js +41 -0
  37. package/src/tools/files.js +352 -0
  38. package/src/tools/index.js +52 -0
  39. package/src/tools/interaction.js +157 -0
  40. package/src/tools/notebook.js +91 -0
  41. package/src/tools/peers.js +45 -0
  42. package/src/tools/restart.js +50 -0
  43. package/src/tools/search.js +458 -0
  44. package/src/tools/skill.js +32 -0
  45. package/src/tools/task.js +139 -0
  46. package/src/tools/web.js +283 -0
  47. package/src/ui/ansi.js +228 -0
  48. package/src/ui/dialogs.js +122 -0
  49. package/src/ui/editor.js +389 -0
  50. package/src/ui/markdown.js +249 -0
  51. package/src/ui/render.js +155 -0
  52. package/src/ui/repl.js +1460 -0
  53. package/src/ui/screen.js +259 -0
  54. package/src/updater.js +93 -0
  55. package/src/utils/clipboard.js +197 -0
  56. package/src/utils/diff.js +95 -0
  57. package/src/utils/paths.js +37 -0
  58. package/src/utils/shell.js +251 -0
@@ -0,0 +1,328 @@
1
+ // Copied from codex-gateway (src/translate-stream.mjs): OpenAI Responses SSE -> Anthropic Messages SSE events.
2
+ // OpenAI Responses SSE events -> Anthropic Messages SSE events (and a non-streaming aggregator).
3
+ import crypto from "node:crypto";
4
+ import { SIGNATURE_PREFIX } from "./translate-request.js";
5
+
6
+ /** Async iterator over parsed SSE `data:` JSON payloads from a Node readable stream. */
7
+ export async function* parseSSE(stream) {
8
+ let buf = "";
9
+ const decoder = new TextDecoder();
10
+ const parseFrame = (frame) => {
11
+ const data = frame
12
+ .split(/\r?\n/)
13
+ .filter((l) => l.startsWith("data:"))
14
+ .map((l) => l.slice(5).replace(/^ /, ""))
15
+ .join("\n");
16
+ if (!data || data === "[DONE]") return null;
17
+ try {
18
+ return JSON.parse(data);
19
+ } catch {
20
+ return null;
21
+ }
22
+ };
23
+ for await (const chunk of stream) {
24
+ buf += decoder.decode(chunk, { stream: true });
25
+ let m;
26
+ while ((m = buf.match(/\r?\n\r?\n/))) {
27
+ const frame = buf.slice(0, m.index);
28
+ buf = buf.slice(m.index + m[0].length);
29
+ const ev = parseFrame(frame);
30
+ if (ev) yield ev;
31
+ }
32
+ }
33
+ const ev = parseFrame(buf);
34
+ if (ev) yield ev;
35
+ }
36
+
37
+ /** Merges usage objects, skipping null/undefined fields so a partial update cannot erase counts. */
38
+ export function mergeUsage(base, update) {
39
+ const merged = { ...(base || {}) };
40
+ for (const [key, value] of Object.entries(update || {})) {
41
+ if (value !== null && value !== undefined) merged[key] = value;
42
+ }
43
+ return merged;
44
+ }
45
+
46
+ export function anthropicUsage(u) {
47
+ if (!u) return { input_tokens: 0, output_tokens: 0, cache_read_input_tokens: 0, cache_creation_input_tokens: 0 };
48
+ const cached = u.input_tokens_details?.cached_tokens || 0;
49
+ return {
50
+ input_tokens: Math.max(0, (u.input_tokens || 0) - cached),
51
+ output_tokens: u.output_tokens || 0,
52
+ cache_read_input_tokens: cached,
53
+ cache_creation_input_tokens: 0,
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Feed upstream events through handle(); Anthropic events come out through onEvent(name, data).
59
+ * Content blocks are emitted strictly one after another, as the Anthropic protocol requires.
60
+ */
61
+ export class ResponsesToAnthropic {
62
+ constructor({ model, toolNames, emitThinking = true, onEvent }) {
63
+ this.model = model;
64
+ this.toolNames = toolNames || new Map();
65
+ this.emitThinking = emitThinking;
66
+ this.onEvent = onEvent;
67
+ this.messageId = "msg_" + crypto.randomBytes(12).toString("hex");
68
+ this.index = -1;
69
+ this.open = null; // { key, type, sawDelta, summaryIndex, citations }
70
+ this.closedKeys = new Set();
71
+ this.sawToolUse = false;
72
+ this.started = false;
73
+ this.done = false;
74
+ this.usage = null;
75
+ this.error = null;
76
+ }
77
+
78
+ emit(name, data) {
79
+ this.onEvent(name, { type: name, ...data });
80
+ }
81
+
82
+ start() {
83
+ if (this.started) return;
84
+ this.started = true;
85
+ this.emit("message_start", {
86
+ message: {
87
+ id: this.messageId,
88
+ type: "message",
89
+ role: "assistant",
90
+ model: this.model,
91
+ content: [],
92
+ stop_reason: null,
93
+ stop_sequence: null,
94
+ usage: { input_tokens: 0, output_tokens: 0, cache_read_input_tokens: 0, cache_creation_input_tokens: 0 },
95
+ },
96
+ });
97
+ }
98
+
99
+ openBlock(key, contentBlock, extra = {}) {
100
+ if (this.open?.key === key) return this.open;
101
+ this.closeBlock();
102
+ this.index += 1;
103
+ this.open = { key, type: contentBlock.type, sawDelta: false, ...extra };
104
+ this.emit("content_block_start", { index: this.index, content_block: contentBlock });
105
+ return this.open;
106
+ }
107
+
108
+ closeBlock() {
109
+ if (!this.open) return;
110
+ this.emit("content_block_stop", { index: this.index });
111
+ this.closedKeys.add(this.open.key);
112
+ this.open = null;
113
+ }
114
+
115
+ delta(delta) {
116
+ this.emit("content_block_delta", { index: this.index, delta });
117
+ }
118
+
119
+ textBlock(key) {
120
+ return this.openBlock(key, { type: "text", text: "" }, { citations: [] });
121
+ }
122
+
123
+ thinkingBlock(key) {
124
+ return this.openBlock(key, { type: "thinking", thinking: "", signature: "" }, { summaryIndex: null });
125
+ }
126
+
127
+ handle(ev) {
128
+ if (this.done) return;
129
+ this.start();
130
+ const item = ev.item;
131
+ switch (ev.type) {
132
+ case "response.output_item.added":
133
+ // Reasoning blocks open lazily (first summary delta or item done) to avoid empty blocks.
134
+ if (item?.type === "function_call") this.toolBlock(ev.output_index, item);
135
+ break;
136
+
137
+ case "response.reasoning_summary_part.added":
138
+ case "response.reasoning_summary_text.delta":
139
+ case "response.reasoning_text.delta": {
140
+ if (!this.emitThinking) break;
141
+ const key = `rs:${ev.output_index}`;
142
+ if (this.closedKeys.has(key) || (!ev.delta && this.open?.key !== key)) break;
143
+ const blk = this.thinkingBlock(key);
144
+ const part = ev.summary_index ?? ev.content_index ?? 0;
145
+ if (blk.summaryIndex !== null && blk.summaryIndex !== part && blk.sawDelta) {
146
+ this.delta({ type: "thinking_delta", thinking: "\n\n" });
147
+ }
148
+ blk.summaryIndex = part;
149
+ if (ev.delta) {
150
+ blk.sawDelta = true;
151
+ this.delta({ type: "thinking_delta", thinking: ev.delta });
152
+ }
153
+ break;
154
+ }
155
+
156
+ case "response.output_text.delta":
157
+ case "response.refusal.delta": {
158
+ const key = `msg:${ev.output_index}:${ev.content_index ?? 0}`;
159
+ if (this.closedKeys.has(key)) break;
160
+ const blk = this.textBlock(key);
161
+ if (ev.delta) {
162
+ blk.sawDelta = true;
163
+ this.delta({ type: "text_delta", text: ev.delta });
164
+ }
165
+ break;
166
+ }
167
+
168
+ case "response.output_text.annotation.added": {
169
+ const a = ev.annotation;
170
+ if (a?.type === "url_citation" && this.open?.type === "text") this.open.citations.push(a);
171
+ break;
172
+ }
173
+
174
+ case "response.function_call_arguments.delta": {
175
+ const key = `fc:${ev.output_index}`;
176
+ if (this.open?.key !== key || !ev.delta) break;
177
+ this.open.sawDelta = true;
178
+ this.delta({ type: "input_json_delta", partial_json: ev.delta });
179
+ break;
180
+ }
181
+
182
+ case "response.output_item.done":
183
+ this.itemDone(ev.output_index, item);
184
+ break;
185
+
186
+ case "response.completed":
187
+ case "response.incomplete":
188
+ this.finish(ev.response);
189
+ break;
190
+
191
+ case "response.failed":
192
+ this.fail(ev.response?.error?.message || "Upstream response failed", ev.response?.error?.code);
193
+ break;
194
+
195
+ case "error":
196
+ this.fail(ev.message || ev.error?.message || "Upstream error", ev.code || ev.error?.code || ev.error?.type);
197
+ break;
198
+ }
199
+ }
200
+
201
+ toolBlock(outputIndex, item) {
202
+ this.sawToolUse = true;
203
+ return this.openBlock(`fc:${outputIndex}`, {
204
+ type: "tool_use",
205
+ id: item.call_id || item.id,
206
+ name: this.toolNames.get(item.name) || item.name,
207
+ input: {},
208
+ });
209
+ }
210
+
211
+ itemDone(outputIndex, item) {
212
+ if (!item) return;
213
+ if (item.type === "reasoning") {
214
+ if (!this.emitThinking) return;
215
+ const key = `rs:${outputIndex}`;
216
+ if (this.closedKeys.has(key)) return;
217
+ const text = (item.summary || []).map((s) => s.text).filter(Boolean).join("\n\n");
218
+ if (this.open?.key !== key && !text && !item.encrypted_content) return;
219
+ const blk = this.thinkingBlock(key);
220
+ if (!blk.sawDelta && text) this.delta({ type: "thinking_delta", thinking: text });
221
+ if (item.encrypted_content) {
222
+ this.delta({ type: "signature_delta", signature: SIGNATURE_PREFIX + item.encrypted_content });
223
+ }
224
+ this.closeBlock();
225
+ } else if (item.type === "function_call") {
226
+ const key = `fc:${outputIndex}`;
227
+ if (this.closedKeys.has(key)) return;
228
+ const blk = this.open?.key === key ? this.open : this.toolBlock(outputIndex, item);
229
+ if (!blk.sawDelta && item.arguments) this.delta({ type: "input_json_delta", partial_json: item.arguments });
230
+ this.closeBlock();
231
+ } else if (item.type === "message") {
232
+ (item.content || []).forEach((part, ci) => {
233
+ const key = `msg:${outputIndex}:${ci}`;
234
+ if (this.closedKeys.has(key)) return;
235
+ const text = part.text ?? part.refusal ?? "";
236
+ const blk = this.open?.key === key ? this.open : text ? this.textBlock(key) : null;
237
+ if (!blk) return;
238
+ if (!blk.sawDelta && text) this.delta({ type: "text_delta", text });
239
+ const cites = blk.citations.length ? blk.citations : (part.annotations || []).filter((a) => a.type === "url_citation");
240
+ const seen = new Set();
241
+ const lines = cites
242
+ .filter((c) => c.url && !seen.has(c.url) && seen.add(c.url))
243
+ .map((c) => `- [${c.title || c.url}](${c.url})`);
244
+ if (lines.length) this.delta({ type: "text_delta", text: `\n\nSources:\n${lines.join("\n")}` });
245
+ this.closeBlock();
246
+ });
247
+ }
248
+ }
249
+
250
+ finish(response) {
251
+ if (this.done) return;
252
+ this.closeBlock();
253
+ this.done = true;
254
+ this.usage = anthropicUsage(response?.usage);
255
+ let stop = this.sawToolUse ? "tool_use" : "end_turn";
256
+ if (response?.status === "incomplete") {
257
+ const reason = response.incomplete_details?.reason;
258
+ stop = reason === "max_output_tokens" ? "max_tokens" : reason === "content_filter" ? "refusal" : stop;
259
+ }
260
+ this.stopReason = stop;
261
+ this.emit("message_delta", { delta: { stop_reason: stop, stop_sequence: null }, usage: this.usage });
262
+ this.emit("message_stop", {});
263
+ }
264
+
265
+ fail(message, code) {
266
+ if (this.done) return;
267
+ this.closeBlock();
268
+ this.done = true;
269
+ const type = /rate|limit|quota/i.test(`${code} ${message}`) ? "rate_limit_error" : /overload|capacity/i.test(message) ? "overloaded_error" : "api_error";
270
+ this.error = { type, message: code ? `${message} (${code})` : message };
271
+ this.emit("error", { error: this.error });
272
+ }
273
+
274
+ /** Call when the upstream stream ended; reports truncated streams as errors. */
275
+ end() {
276
+ if (!this.done) {
277
+ this.start();
278
+ this.fail("Upstream stream ended before the response completed");
279
+ }
280
+ }
281
+ }
282
+
283
+ /** Rebuilds a complete Anthropic message object from the Anthropic event stream. */
284
+ export class MessageAggregator {
285
+ constructor() {
286
+ this.message = null;
287
+ this.json = new Map();
288
+ this.error = null;
289
+ }
290
+
291
+ onEvent = (name, data) => {
292
+ switch (name) {
293
+ case "message_start":
294
+ this.message = { ...data.message, content: [] };
295
+ break;
296
+ case "content_block_start":
297
+ this.message.content[data.index] = { ...data.content_block };
298
+ break;
299
+ case "content_block_delta": {
300
+ const b = this.message.content[data.index];
301
+ const d = data.delta;
302
+ if (d.type === "text_delta") b.text += d.text;
303
+ else if (d.type === "thinking_delta") b.thinking += d.thinking;
304
+ else if (d.type === "signature_delta") b.signature = d.signature;
305
+ else if (d.type === "input_json_delta") this.json.set(data.index, (this.json.get(data.index) || "") + d.partial_json);
306
+ break;
307
+ }
308
+ case "content_block_stop": {
309
+ const b = this.message.content[data.index];
310
+ if (b.type === "tool_use") {
311
+ try {
312
+ b.input = JSON.parse(this.json.get(data.index) || "{}");
313
+ } catch {
314
+ b.input = {};
315
+ }
316
+ }
317
+ break;
318
+ }
319
+ case "message_delta":
320
+ Object.assign(this.message, data.delta);
321
+ this.message.usage = mergeUsage(this.message.usage, data.usage);
322
+ break;
323
+ case "error":
324
+ this.error = data.error;
325
+ break;
326
+ }
327
+ };
328
+ }