@hienlh/ppm 0.8.39 → 0.8.41
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/CHANGELOG.md +21 -0
- package/chat-ui-test-1.png +0 -0
- package/chat-ui-test-mid.png +0 -0
- package/chat-ui-test-mid2.png +0 -0
- package/chat-ui-test-top.png +0 -0
- package/chat-ui-v2-mid.png +0 -0
- package/dist/web/assets/{api-settings-0Hx_9lIU.js → api-settings-CaKDC7_s.js} +1 -1
- package/dist/web/assets/chat-tab-CN-ULuHd.js +7 -0
- package/dist/web/assets/{code-editor-DZlXHMtA.js → code-editor-CFZAz_WA.js} +1 -1
- package/dist/web/assets/{database-viewer-BaxjPtYR.js → database-viewer-DT9IEf-4.js} +1 -1
- package/dist/web/assets/{diff-viewer-CDdO3tqP.js → diff-viewer-SZcQ0Arc.js} +1 -1
- package/dist/web/assets/git-graph-DsKiCtcj.js +1 -0
- package/dist/web/assets/{index-CvbNQ1mi.js → index-BiOW8qrf.js} +8 -8
- package/dist/web/assets/index-CGOBw13I.css +2 -0
- package/dist/web/assets/{input-4ElbicvY.js → input-CE3bFwLk.js} +1 -1
- package/dist/web/assets/keybindings-store-BShKvCCo.js +1 -0
- package/dist/web/assets/markdown-renderer-Cr3-VbIg.js +59 -0
- package/dist/web/assets/{postgres-viewer-hmqfZRr-.js → postgres-viewer-BhTz35TV.js} +1 -1
- package/dist/web/assets/{settings-store-Clv3ZNje.js → settings-store-xG6mKqkD.js} +2 -2
- package/dist/web/assets/settings-tab-TlZunMhi.js +1 -0
- package/dist/web/assets/{sqlite-viewer-9X_1ZHJE.js → sqlite-viewer-CnZbwR2F.js} +1 -1
- package/dist/web/assets/{tab-store-D7tRt0VT.js → tab-store-NOBndc0_.js} +1 -1
- package/dist/web/assets/tag-DJUYe5BQ.js +1 -0
- package/dist/web/assets/{terminal-tab-V7x81Qpr.js → terminal-tab-BBy02Lde.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-czriskTO.js → use-monaco-theme-DlFSiqvG.js} +1 -1
- package/dist/web/index.html +9 -9
- package/dist/web/sw.js +1 -1
- package/docs/lessons-learned.md +5 -12
- package/package.json +2 -3
- package/sdh-uit-edu-vn-screenshot.png +0 -0
- package/src/index.ts +0 -10
- package/src/providers/claude-agent-sdk.ts +57 -292
- package/src/server/routes/fs-browse.ts +21 -0
- package/src/types/config.ts +0 -8
- package/src/web/components/chat/message-list.tsx +163 -55
- package/src/web/components/settings/ai-settings-section.tsx +0 -24
- package/src/web/components/shared/markdown-renderer.tsx +48 -2
- package/src/web/lib/api-settings.ts +0 -1
- package/dist/web/assets/chat-tab-CGic5t8w.js +0 -7
- package/dist/web/assets/git-graph-C-TRbbx7.js +0 -1
- package/dist/web/assets/index-DXTts38q.css +0 -2
- package/dist/web/assets/keybindings-store-Dqs-i9cV.js +0 -1
- package/dist/web/assets/markdown-renderer-DE503g9L.js +0 -59
- package/dist/web/assets/settings-tab-BdgsQeES.js +0 -1
- package/scripts/patch-sdk.mjs +0 -214
- package/scripts/test-drain-bug.mjs +0 -131
- package/test-sdk.mjs +0 -106
- /package/dist/web/assets/{api-client-B0aMOJxF.js → api-client-TUmacMRS.js} +0 -0
- /package/dist/web/assets/{react-Dk7fkoaB.js → react-rgzL83kk.js} +0 -0
- /package/dist/web/assets/{utils-DBpa1UZX.js → utils-DC-bdPS3.js} +0 -0
|
@@ -118,173 +118,6 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
118
118
|
return null;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
/**
|
|
122
|
-
* Direct CLI fallback for Windows — spawns `claude -p` with stream-json output.
|
|
123
|
-
* Workaround for Bun + Windows SDK subprocess pipe buffering issue.
|
|
124
|
-
* Returns an async generator yielding the same event types as SDK query().
|
|
125
|
-
*
|
|
126
|
-
* TODO: Remove this fallback when TypeScript SDK fixes Windows stdin pipe buffering.
|
|
127
|
-
* Tracking issues:
|
|
128
|
-
* - Python SDK #208 (FIXED): https://github.com/anthropics/claude-agent-sdk-python/issues/208
|
|
129
|
-
* Fix: stdin drain() after writes — TypeScript SDK lacks equivalent fix.
|
|
130
|
-
* - TS SDK #44 (OPEN): https://github.com/anthropics/claude-agent-sdk-typescript/issues/44
|
|
131
|
-
* query() yields zero events for 3+ minutes on Windows.
|
|
132
|
-
* - TS SDK #64 (OPEN): https://github.com/anthropics/claude-agent-sdk-typescript/issues/64
|
|
133
|
-
* Bash tool hangs on empty output — related pipe/EOF handling issue.
|
|
134
|
-
* When these are resolved, switch back to SDK query() by removing the
|
|
135
|
-
* `useDirectCli` branch in sendMessage() and deleting this method.
|
|
136
|
-
*/
|
|
137
|
-
private async *queryDirectCli(opts: {
|
|
138
|
-
prompt: string;
|
|
139
|
-
cwd: string;
|
|
140
|
-
sessionId: string;
|
|
141
|
-
resumeSessionId?: string;
|
|
142
|
-
env: Record<string, string | undefined>;
|
|
143
|
-
providerConfig: Partial<import("../types/config.ts").AIProviderConfig>;
|
|
144
|
-
}): AsyncGenerator<any> {
|
|
145
|
-
const args = ["-p", opts.prompt, "--verbose", "--output-format", "stream-json"];
|
|
146
|
-
|
|
147
|
-
// Session management — resume if caller confirmed a valid session ID
|
|
148
|
-
if (opts.resumeSessionId) {
|
|
149
|
-
args.push("--resume", opts.resumeSessionId);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Config-driven options
|
|
153
|
-
if (opts.providerConfig.model) args.push("--model", opts.providerConfig.model);
|
|
154
|
-
const maxTurns = opts.providerConfig.max_turns ?? 100;
|
|
155
|
-
args.push("--max-turns", String(maxTurns));
|
|
156
|
-
if (opts.providerConfig.effort) args.push("--effort", opts.providerConfig.effort);
|
|
157
|
-
|
|
158
|
-
// Permission mode
|
|
159
|
-
args.push("--permission-mode", opts.providerConfig.permission_mode ?? "bypassPermissions");
|
|
160
|
-
if ((opts.providerConfig.permission_mode ?? "bypassPermissions") === "bypassPermissions") {
|
|
161
|
-
args.push("--dangerously-skip-permissions");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// System prompt — CLI uses --append-system-prompt flag
|
|
165
|
-
if (opts.providerConfig.system_prompt) {
|
|
166
|
-
args.push("--append-system-prompt", opts.providerConfig.system_prompt);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// On Windows, `claude` is a .cmd wrapper (npm global) — Bun.spawn can't resolve .cmd
|
|
170
|
-
// files directly. Use `cmd /c` to let the Windows shell find it via PATH.
|
|
171
|
-
const cmd = process.platform === "win32"
|
|
172
|
-
? ["cmd", "/c", "claude", ...args]
|
|
173
|
-
: ["claude", ...args];
|
|
174
|
-
console.log(`[sdk-cli] spawning: ${cmd.slice(0, 7).join(" ")}... cwd=${opts.cwd}`);
|
|
175
|
-
|
|
176
|
-
const proc = Bun.spawn({
|
|
177
|
-
cmd,
|
|
178
|
-
cwd: opts.cwd,
|
|
179
|
-
stdout: "pipe",
|
|
180
|
-
stderr: "pipe",
|
|
181
|
-
env: opts.env as Record<string, string>,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Store proc for abort support
|
|
185
|
-
const abortHandle = { close: () => { try { proc.kill(); } catch {} } };
|
|
186
|
-
this.activeQueries.set(opts.sessionId, abortHandle as any);
|
|
187
|
-
|
|
188
|
-
try {
|
|
189
|
-
const reader = proc.stdout.getReader();
|
|
190
|
-
const decoder = new TextDecoder();
|
|
191
|
-
let buffer = "";
|
|
192
|
-
|
|
193
|
-
while (true) {
|
|
194
|
-
const { done, value } = await reader.read();
|
|
195
|
-
if (done) break;
|
|
196
|
-
|
|
197
|
-
buffer += decoder.decode(value, { stream: true });
|
|
198
|
-
const lines = buffer.split("\n");
|
|
199
|
-
buffer = lines.pop() ?? ""; // Keep incomplete last line in buffer
|
|
200
|
-
|
|
201
|
-
for (const line of lines) {
|
|
202
|
-
const trimmed = line.trim();
|
|
203
|
-
if (!trimmed) continue;
|
|
204
|
-
try {
|
|
205
|
-
const event = JSON.parse(trimmed);
|
|
206
|
-
// CLI stream-json doesn't emit per-token stream_event deltas — it sends
|
|
207
|
-
// complete assistant messages. Synthesize stream_event deltas so the FE
|
|
208
|
-
// gets a smooth streaming experience (same as SDK with includePartialMessages).
|
|
209
|
-
if (event.type === "assistant" && event.message?.content) {
|
|
210
|
-
for (const block of event.message.content) {
|
|
211
|
-
if (block.type === "text" && block.text) {
|
|
212
|
-
// Emit text in ~30-char chunks as synthetic stream_event deltas
|
|
213
|
-
const text = block.text as string;
|
|
214
|
-
const CHUNK = 30;
|
|
215
|
-
for (let i = 0; i < text.length; i += CHUNK) {
|
|
216
|
-
yield {
|
|
217
|
-
type: "stream_event",
|
|
218
|
-
event: {
|
|
219
|
-
type: "content_block_delta",
|
|
220
|
-
delta: { type: "text_delta", text: text.slice(i, i + CHUNK) },
|
|
221
|
-
},
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
} else if (block.type === "thinking" && block.thinking) {
|
|
225
|
-
yield {
|
|
226
|
-
type: "stream_event",
|
|
227
|
-
event: {
|
|
228
|
-
type: "content_block_delta",
|
|
229
|
-
delta: { type: "thinking_delta", thinking: block.thinking },
|
|
230
|
-
},
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
// Log error/result events for diagnostics
|
|
236
|
-
if (event.type === "error") {
|
|
237
|
-
console.error(`[sdk-cli] error event: ${JSON.stringify(event).slice(0, 1000)}`);
|
|
238
|
-
} else if (event.type === "result" && event.is_error) {
|
|
239
|
-
console.error(`[sdk-cli] result error: ${JSON.stringify(event).slice(0, 1000)}`);
|
|
240
|
-
}
|
|
241
|
-
// Always yield the original event too (for init, result, rate_limit, etc.)
|
|
242
|
-
yield event;
|
|
243
|
-
} catch {
|
|
244
|
-
// Skip non-JSON lines (e.g. progress indicators)
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Process remaining buffer
|
|
250
|
-
if (buffer.trim()) {
|
|
251
|
-
try { yield JSON.parse(buffer.trim()); } catch {}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Wait for process to exit
|
|
255
|
-
const exitCode = await proc.exited;
|
|
256
|
-
console.log(`[sdk-cli] process exited: code=${exitCode}`);
|
|
257
|
-
|
|
258
|
-
// Always read stderr for diagnostics (errors can occur even with exit code 0)
|
|
259
|
-
try {
|
|
260
|
-
const errReader = proc.stderr.getReader();
|
|
261
|
-
const stderrDecoder = new TextDecoder();
|
|
262
|
-
const errParts: string[] = [];
|
|
263
|
-
while (true) {
|
|
264
|
-
const { done, value } = await errReader.read();
|
|
265
|
-
if (done) break;
|
|
266
|
-
if (value) errParts.push(stderrDecoder.decode(value, { stream: true }));
|
|
267
|
-
}
|
|
268
|
-
const fullStderr = errParts.join("").trim();
|
|
269
|
-
if (fullStderr) {
|
|
270
|
-
console.error(`[sdk-cli] stderr (last 1500): ${fullStderr.slice(-1500)}`);
|
|
271
|
-
if (exitCode !== 0) {
|
|
272
|
-
const errMatch = fullStderr.match(/\b(?:Error|TypeError|SyntaxError|ReferenceError|RangeError):\s*.+/);
|
|
273
|
-
const errorMsg = errMatch ? errMatch[0].slice(0, 500) : fullStderr.slice(-300);
|
|
274
|
-
yield {
|
|
275
|
-
type: "result",
|
|
276
|
-
subtype: "error_during_execution",
|
|
277
|
-
error: `CLI exited with code ${exitCode}: ${errorMsg}`,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
} catch {}
|
|
282
|
-
} finally {
|
|
283
|
-
this.activeQueries.delete(opts.sessionId);
|
|
284
|
-
try { proc.kill(); } catch {}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
121
|
/** Read current provider config from yaml (fresh each call) */
|
|
289
122
|
private getProviderConfig(): Partial<import("../types/config.ts").AIProviderConfig> {
|
|
290
123
|
const ai = configService.get("ai");
|
|
@@ -579,68 +412,40 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
579
412
|
}
|
|
580
413
|
console.log(`[sdk] query: session=${sessionId} sdkId=${sdkId} isFirst=${isFirstMessage} fork=${shouldFork} cwd=${effectiveCwd} platform=${process.platform} accountMode=${!!account} permissionMode=${permissionMode} isBypass=${isBypass}`);
|
|
581
414
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
prompt: message,
|
|
617
|
-
options: {
|
|
618
|
-
sessionId: isFirstMessage && !shouldFork ? sessionId : undefined,
|
|
619
|
-
resume: (isFirstMessage && !shouldFork) ? undefined : sdkId,
|
|
620
|
-
...(shouldFork && { forkSession: true }),
|
|
621
|
-
cwd: effectiveCwd,
|
|
622
|
-
systemPrompt: systemPromptOpt,
|
|
623
|
-
settingSources: ["user", "project"],
|
|
624
|
-
env: queryEnv,
|
|
625
|
-
settings: { permissions: { allow: [], deny: [] } },
|
|
626
|
-
allowedTools,
|
|
627
|
-
permissionMode,
|
|
628
|
-
allowDangerouslySkipPermissions: isBypass,
|
|
629
|
-
...(permissionHooks && { hooks: permissionHooks }),
|
|
630
|
-
...(providerConfig.model && { model: providerConfig.model }),
|
|
631
|
-
...(providerConfig.effort && { effort: providerConfig.effort }),
|
|
632
|
-
maxTurns: providerConfig.max_turns ?? 100,
|
|
633
|
-
...(providerConfig.max_budget_usd && { maxBudgetUsd: providerConfig.max_budget_usd }),
|
|
634
|
-
...(providerConfig.thinking_budget_tokens != null && {
|
|
635
|
-
thinkingBudgetTokens: providerConfig.thinking_budget_tokens,
|
|
636
|
-
}),
|
|
637
|
-
canUseTool,
|
|
638
|
-
includePartialMessages: true,
|
|
639
|
-
} as any,
|
|
640
|
-
});
|
|
641
|
-
this.activeQueries.set(sessionId, q);
|
|
642
|
-
eventSource = q;
|
|
643
|
-
}
|
|
415
|
+
const queryOptions: Record<string, any> = {
|
|
416
|
+
// On Windows, child_process.spawn("bun") fails with ENOENT — force node
|
|
417
|
+
...(process.platform === "win32" && { executable: "node" }),
|
|
418
|
+
sessionId: isFirstMessage && !shouldFork ? sessionId : undefined,
|
|
419
|
+
resume: (isFirstMessage && !shouldFork) ? undefined : sdkId,
|
|
420
|
+
...(shouldFork && { forkSession: true }),
|
|
421
|
+
cwd: effectiveCwd,
|
|
422
|
+
systemPrompt: systemPromptOpt,
|
|
423
|
+
settingSources: ["user", "project"],
|
|
424
|
+
env: queryEnv,
|
|
425
|
+
settings: { permissions: { allow: [], deny: [] } },
|
|
426
|
+
allowedTools,
|
|
427
|
+
permissionMode,
|
|
428
|
+
allowDangerouslySkipPermissions: isBypass,
|
|
429
|
+
...(providerConfig.model && { model: providerConfig.model }),
|
|
430
|
+
...(providerConfig.effort && { effort: providerConfig.effort }),
|
|
431
|
+
maxTurns: providerConfig.max_turns ?? 100,
|
|
432
|
+
...(providerConfig.max_budget_usd && { maxBudgetUsd: providerConfig.max_budget_usd }),
|
|
433
|
+
...(providerConfig.thinking_budget_tokens != null && {
|
|
434
|
+
thinkingBudgetTokens: providerConfig.thinking_budget_tokens,
|
|
435
|
+
}),
|
|
436
|
+
includePartialMessages: true,
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const q = query({
|
|
440
|
+
prompt: message,
|
|
441
|
+
options: {
|
|
442
|
+
...queryOptions,
|
|
443
|
+
...(permissionHooks && { hooks: permissionHooks }),
|
|
444
|
+
canUseTool,
|
|
445
|
+
} as any,
|
|
446
|
+
});
|
|
447
|
+
this.activeQueries.set(sessionId, q);
|
|
448
|
+
let eventSource: AsyncIterable<any> = q;
|
|
644
449
|
|
|
645
450
|
let lastPartialText = "";
|
|
646
451
|
/** Number of tool_use blocks pending results (top-level tools only, not subagent children) */
|
|
@@ -664,37 +469,13 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
664
469
|
retryCount++;
|
|
665
470
|
console.warn(`[sdk] transient error on first event — retrying (attempt ${retryCount}/${MAX_RETRIES})`);
|
|
666
471
|
// Re-create query for retry — don't reuse sessionId in case SDK partially created it
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
...(shouldFork && { forkSession: true }),
|
|
675
|
-
cwd: effectiveCwd,
|
|
676
|
-
systemPrompt: systemPromptOpt,
|
|
677
|
-
settingSources: ["user", "project"],
|
|
678
|
-
env: queryEnv,
|
|
679
|
-
settings: { permissions: { allow: [], deny: [] } },
|
|
680
|
-
allowedTools,
|
|
681
|
-
permissionMode,
|
|
682
|
-
allowDangerouslySkipPermissions: isBypass,
|
|
683
|
-
...(permissionHooks && { hooks: permissionHooks }),
|
|
684
|
-
...(providerConfig.model && { model: providerConfig.model }),
|
|
685
|
-
...(providerConfig.effort && { effort: providerConfig.effort }),
|
|
686
|
-
maxTurns: providerConfig.max_turns ?? 100,
|
|
687
|
-
...(providerConfig.max_budget_usd && { maxBudgetUsd: providerConfig.max_budget_usd }),
|
|
688
|
-
...(providerConfig.thinking_budget_tokens != null && {
|
|
689
|
-
thinkingBudgetTokens: providerConfig.thinking_budget_tokens,
|
|
690
|
-
}),
|
|
691
|
-
canUseTool,
|
|
692
|
-
includePartialMessages: true,
|
|
693
|
-
} as any,
|
|
694
|
-
});
|
|
695
|
-
this.activeQueries.set(sessionId, q);
|
|
696
|
-
eventSource = q;
|
|
697
|
-
}
|
|
472
|
+
const retryOpts = { ...queryOptions, sessionId: undefined, resume: undefined };
|
|
473
|
+
const rq = query({
|
|
474
|
+
prompt: message,
|
|
475
|
+
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
476
|
+
});
|
|
477
|
+
this.activeQueries.set(sessionId, rq);
|
|
478
|
+
eventSource = rq;
|
|
698
479
|
continue retryLoop;
|
|
699
480
|
}
|
|
700
481
|
}
|
|
@@ -836,33 +617,13 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
836
617
|
const refreshedAccount = accountService.getWithTokens(account.id);
|
|
837
618
|
if (refreshedAccount) {
|
|
838
619
|
const retryEnv = this.buildQueryEnv(meta.projectPath, refreshedAccount);
|
|
839
|
-
const
|
|
620
|
+
const retryOpts = { ...queryOptions, sessionId: undefined, resume: undefined, env: retryEnv };
|
|
621
|
+
const rq = query({
|
|
840
622
|
prompt: message,
|
|
841
|
-
options: {
|
|
842
|
-
sessionId: undefined,
|
|
843
|
-
resume: undefined,
|
|
844
|
-
cwd: effectiveCwd,
|
|
845
|
-
systemPrompt: systemPromptOpt,
|
|
846
|
-
settingSources: ["user", "project"],
|
|
847
|
-
env: retryEnv,
|
|
848
|
-
settings: { permissions: { allow: [], deny: [] } },
|
|
849
|
-
allowedTools,
|
|
850
|
-
permissionMode,
|
|
851
|
-
allowDangerouslySkipPermissions: isBypass,
|
|
852
|
-
...(permissionHooks && { hooks: permissionHooks }),
|
|
853
|
-
...(providerConfig.model && { model: providerConfig.model }),
|
|
854
|
-
...(providerConfig.effort && { effort: providerConfig.effort }),
|
|
855
|
-
maxTurns: providerConfig.max_turns ?? 100,
|
|
856
|
-
...(providerConfig.max_budget_usd && { maxBudgetUsd: providerConfig.max_budget_usd }),
|
|
857
|
-
...(providerConfig.thinking_budget_tokens != null && {
|
|
858
|
-
thinkingBudgetTokens: providerConfig.thinking_budget_tokens,
|
|
859
|
-
}),
|
|
860
|
-
canUseTool,
|
|
861
|
-
includePartialMessages: true,
|
|
862
|
-
} as any,
|
|
623
|
+
options: { ...retryOpts, ...(permissionHooks && { hooks: permissionHooks }), canUseTool } as any,
|
|
863
624
|
});
|
|
864
|
-
this.activeQueries.set(sessionId,
|
|
865
|
-
eventSource =
|
|
625
|
+
this.activeQueries.set(sessionId, rq);
|
|
626
|
+
eventSource = rq;
|
|
866
627
|
continue retryLoop;
|
|
867
628
|
}
|
|
868
629
|
} catch (refreshErr) {
|
|
@@ -1069,9 +830,8 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
1069
830
|
const effectiveCwd = meta.projectPath || homedir();
|
|
1070
831
|
const retryAccount = accountSelector.isEnabled() ? accountSelector.next() : null;
|
|
1071
832
|
const queryEnv = this.buildQueryEnv(meta.projectPath, retryAccount);
|
|
1072
|
-
const
|
|
1073
|
-
|
|
1074
|
-
options: {
|
|
833
|
+
const retryOptions = {
|
|
834
|
+
...(process.platform === "win32" && { executable: "node" }),
|
|
1075
835
|
cwd: effectiveCwd,
|
|
1076
836
|
systemPrompt: systemPromptOpt,
|
|
1077
837
|
settingSources: ["user", "project"],
|
|
@@ -1080,13 +840,18 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
1080
840
|
allowedTools,
|
|
1081
841
|
permissionMode,
|
|
1082
842
|
allowDangerouslySkipPermissions: isBypass,
|
|
1083
|
-
...(permissionHooks && { hooks: permissionHooks }),
|
|
1084
843
|
...(providerConfig.model && { model: providerConfig.model }),
|
|
1085
844
|
maxTurns: providerConfig.max_turns ?? 100,
|
|
1086
|
-
canUseTool,
|
|
1087
845
|
includePartialMessages: true,
|
|
1088
|
-
}
|
|
1089
|
-
|
|
846
|
+
};
|
|
847
|
+
const retryQuery = query({
|
|
848
|
+
prompt: message,
|
|
849
|
+
options: {
|
|
850
|
+
...retryOptions,
|
|
851
|
+
...(permissionHooks && { hooks: permissionHooks }),
|
|
852
|
+
canUseTool,
|
|
853
|
+
} as any,
|
|
854
|
+
});
|
|
1090
855
|
this.activeQueries.set(sessionId, retryQuery);
|
|
1091
856
|
for await (const retryMsg of retryQuery) {
|
|
1092
857
|
if (retryMsg.type === "system") continue;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
+
import { existsSync } from "fs";
|
|
2
3
|
import {
|
|
3
4
|
browse,
|
|
4
5
|
list,
|
|
@@ -52,6 +53,26 @@ fsBrowseRoutes.get("/read", (c) => {
|
|
|
52
53
|
}
|
|
53
54
|
});
|
|
54
55
|
|
|
56
|
+
/** GET /api/fs/raw?path=/some/file — serve file as binary (for images in markdown, etc.) */
|
|
57
|
+
fsBrowseRoutes.get("/raw", (c) => {
|
|
58
|
+
try {
|
|
59
|
+
const filePath = c.req.query("path");
|
|
60
|
+
if (!filePath) return c.json(err("path is required"), 400);
|
|
61
|
+
if (!existsSync(filePath)) return c.json(err("File not found"), 404);
|
|
62
|
+
|
|
63
|
+
const file = Bun.file(filePath);
|
|
64
|
+
return new Response(file.stream(), {
|
|
65
|
+
headers: {
|
|
66
|
+
"Content-Type": file.type || "application/octet-stream",
|
|
67
|
+
"Content-Disposition": "inline",
|
|
68
|
+
"Cache-Control": "private, max-age=3600",
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return c.json(err((e as Error).message), errorStatus(e));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
55
76
|
/** PUT /api/fs/write — write file outside project { path, content } */
|
|
56
77
|
fsBrowseRoutes.put("/write", async (c) => {
|
|
57
78
|
try {
|
package/src/types/config.ts
CHANGED
|
@@ -43,12 +43,8 @@ export interface AIConfig {
|
|
|
43
43
|
const VALID_PERMISSION_MODES = ["default", "acceptEdits", "plan", "bypassPermissions"] as const;
|
|
44
44
|
export type PermissionMode = typeof VALID_PERMISSION_MODES[number];
|
|
45
45
|
|
|
46
|
-
const VALID_EXECUTION_MODES = ["sdk", "cli"] as const;
|
|
47
|
-
export type ExecutionMode = typeof VALID_EXECUTION_MODES[number];
|
|
48
|
-
|
|
49
46
|
export interface AIProviderConfig {
|
|
50
47
|
type: "agent-sdk" | "mock";
|
|
51
|
-
execution_mode?: ExecutionMode;
|
|
52
48
|
api_key_env?: string;
|
|
53
49
|
base_url?: string;
|
|
54
50
|
// Agent SDK-specific settings (ignored by mock provider)
|
|
@@ -73,7 +69,6 @@ export const DEFAULT_CONFIG: PpmConfig = {
|
|
|
73
69
|
providers: {
|
|
74
70
|
claude: {
|
|
75
71
|
type: "agent-sdk",
|
|
76
|
-
execution_mode: "sdk",
|
|
77
72
|
api_key_env: "ANTHROPIC_API_KEY",
|
|
78
73
|
model: "claude-sonnet-4-6",
|
|
79
74
|
effort: "high",
|
|
@@ -97,9 +92,6 @@ export function validateAIProviderConfig(config: Partial<AIProviderConfig>): str
|
|
|
97
92
|
if (config.type != null && !VALID_TYPES.includes(config.type as any)) {
|
|
98
93
|
errors.push(`type must be one of: ${VALID_TYPES.join(", ")}`);
|
|
99
94
|
}
|
|
100
|
-
if (config.execution_mode != null && !VALID_EXECUTION_MODES.includes(config.execution_mode as any)) {
|
|
101
|
-
errors.push(`execution_mode must be one of: ${VALID_EXECUTION_MODES.join(", ")}`);
|
|
102
|
-
}
|
|
103
95
|
if (config.model != null && !VALID_MODELS.includes(config.model as any)) {
|
|
104
96
|
errors.push(`model must be one of: ${VALID_MODELS.join(", ")}`);
|
|
105
97
|
}
|