@hienlh/ppm 0.5.12 → 0.5.14
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 +10 -0
- package/docs/lessons-learned.md +19 -0
- package/package.json +1 -1
- package/src/providers/claude-agent-sdk.ts +50 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.14] - 2026-03-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Windows: `claude` .cmd resolution** — `Bun.spawn` can't resolve `.cmd` wrapper scripts (npm globals) directly. Now spawns via `cmd /c claude` so Windows shell resolves PATH correctly
|
|
7
|
+
|
|
8
|
+
## [0.5.13] - 2026-03-18
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Windows: simulated token streaming** — CLI `stream-json` only emits complete `assistant` messages (no per-token deltas). Now synthesizes `stream_event` / `content_block_delta` events in ~30-char chunks so FE gets smooth typing effect instead of all text appearing at once
|
|
12
|
+
|
|
3
13
|
## [0.5.12] - 2026-03-18
|
|
4
14
|
|
|
5
15
|
### Fixed
|
package/docs/lessons-learned.md
CHANGED
|
@@ -42,6 +42,25 @@ settingSources: [],
|
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
+
### Windows: SDK query() hangs — direct CLI fallback
|
|
46
|
+
|
|
47
|
+
**Problem**: On Windows, Bun subprocess stdin pipe buffering prevents SDK `query()` from working. Data written to stdin stays in buffer, never reaches the CLI child process → async iterator yields zero events → hangs forever.
|
|
48
|
+
|
|
49
|
+
**Root cause**: Python SDK had identical issue (#208), fixed with `asyncio.StreamWriter.drain()`. TypeScript SDK lacks this fix.
|
|
50
|
+
|
|
51
|
+
**Workaround**: Bypass SDK on Windows — spawn `claude -p --verbose --output-format stream-json` directly. CLI stream-json output uses same event types as SDK (`system/init`, `assistant`, `result`, `rate_limit_event`), so existing event handling works unchanged.
|
|
52
|
+
|
|
53
|
+
**Caveat**: CLI stream-json doesn't emit per-token `stream_event` deltas. Provider synthesizes them by chunking `assistant` message text into ~30-char pieces as synthetic `content_block_delta` events.
|
|
54
|
+
|
|
55
|
+
**Tracking**:
|
|
56
|
+
- Python SDK #208 (FIXED): stdin drain fix
|
|
57
|
+
- TS SDK #44 (OPEN): query() yields zero events
|
|
58
|
+
- TS SDK #64 (OPEN): bash tool hangs on empty output
|
|
59
|
+
|
|
60
|
+
**File**: `src/providers/claude-agent-sdk.ts` — `queryDirectCli()` method
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
45
64
|
## WebSocket Chat Architecture
|
|
46
65
|
|
|
47
66
|
### Event flow: SDK → Provider → WS → Frontend
|
package/package.json
CHANGED
|
@@ -92,6 +92,17 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
92
92
|
* Direct CLI fallback for Windows — spawns `claude -p` with stream-json output.
|
|
93
93
|
* Workaround for Bun + Windows SDK subprocess pipe buffering issue.
|
|
94
94
|
* Returns an async generator yielding the same event types as SDK query().
|
|
95
|
+
*
|
|
96
|
+
* TODO: Remove this fallback when TypeScript SDK fixes Windows stdin pipe buffering.
|
|
97
|
+
* Tracking issues:
|
|
98
|
+
* - Python SDK #208 (FIXED): https://github.com/anthropics/claude-agent-sdk-python/issues/208
|
|
99
|
+
* Fix: stdin drain() after writes — TypeScript SDK lacks equivalent fix.
|
|
100
|
+
* - TS SDK #44 (OPEN): https://github.com/anthropics/claude-agent-sdk-typescript/issues/44
|
|
101
|
+
* query() yields zero events for 3+ minutes on Windows.
|
|
102
|
+
* - TS SDK #64 (OPEN): https://github.com/anthropics/claude-agent-sdk-typescript/issues/64
|
|
103
|
+
* Bash tool hangs on empty output — related pipe/EOF handling issue.
|
|
104
|
+
* When these are resolved, switch back to SDK query() by removing the
|
|
105
|
+
* `useDirectCli` branch in sendMessage() and deleting this method.
|
|
95
106
|
*/
|
|
96
107
|
private async *queryDirectCli(opts: {
|
|
97
108
|
prompt: string;
|
|
@@ -119,10 +130,15 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
119
130
|
// Permission mode
|
|
120
131
|
args.push("--permission-mode", "bypassPermissions", "--dangerously-skip-permissions");
|
|
121
132
|
|
|
122
|
-
|
|
133
|
+
// On Windows, `claude` is a .cmd wrapper (npm global) — Bun.spawn can't resolve .cmd
|
|
134
|
+
// files directly. Use `cmd /c` to let the Windows shell find it via PATH.
|
|
135
|
+
const cmd = process.platform === "win32"
|
|
136
|
+
? ["cmd", "/c", "claude", ...args]
|
|
137
|
+
: ["claude", ...args];
|
|
138
|
+
console.log(`[sdk-cli] spawning: ${cmd.slice(0, 7).join(" ")}... cwd=${opts.cwd}`);
|
|
123
139
|
|
|
124
140
|
const proc = Bun.spawn({
|
|
125
|
-
cmd
|
|
141
|
+
cmd,
|
|
126
142
|
cwd: opts.cwd,
|
|
127
143
|
stdout: "pipe",
|
|
128
144
|
stderr: "pipe",
|
|
@@ -151,6 +167,36 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
151
167
|
if (!trimmed) continue;
|
|
152
168
|
try {
|
|
153
169
|
const event = JSON.parse(trimmed);
|
|
170
|
+
// CLI stream-json doesn't emit per-token stream_event deltas — it sends
|
|
171
|
+
// complete assistant messages. Synthesize stream_event deltas so the FE
|
|
172
|
+
// gets a smooth streaming experience (same as SDK with includePartialMessages).
|
|
173
|
+
if (event.type === "assistant" && event.message?.content) {
|
|
174
|
+
for (const block of event.message.content) {
|
|
175
|
+
if (block.type === "text" && block.text) {
|
|
176
|
+
// Emit text in ~30-char chunks as synthetic stream_event deltas
|
|
177
|
+
const text = block.text as string;
|
|
178
|
+
const CHUNK = 30;
|
|
179
|
+
for (let i = 0; i < text.length; i += CHUNK) {
|
|
180
|
+
yield {
|
|
181
|
+
type: "stream_event",
|
|
182
|
+
event: {
|
|
183
|
+
type: "content_block_delta",
|
|
184
|
+
delta: { type: "text_delta", text: text.slice(i, i + CHUNK) },
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
} else if (block.type === "thinking" && block.thinking) {
|
|
189
|
+
yield {
|
|
190
|
+
type: "stream_event",
|
|
191
|
+
event: {
|
|
192
|
+
type: "content_block_delta",
|
|
193
|
+
delta: { type: "thinking_delta", thinking: block.thinking },
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Always yield the original event too (for init, result, rate_limit, etc.)
|
|
154
200
|
yield event;
|
|
155
201
|
} catch {
|
|
156
202
|
// Skip non-JSON lines (e.g. progress indicators)
|
|
@@ -394,7 +440,8 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
394
440
|
const queryEnv = { ...process.env, ...this.getProjectEnvOverrides(meta.projectPath) };
|
|
395
441
|
console.log(`[sdk] query: session=${sessionId} sdkId=${sdkId} isFirst=${isFirstMessage} fork=${shouldFork} cwd=${effectiveCwd} platform=${process.platform}`);
|
|
396
442
|
|
|
397
|
-
//
|
|
443
|
+
// TODO: Remove when TS SDK fixes Windows stdin pipe buffering (see queryDirectCli() JSDoc for tracking issues)
|
|
444
|
+
// On Windows, SDK query() hangs because Bun subprocess stdin pipe never flushes to child process.
|
|
398
445
|
const useDirectCli = process.platform === "win32";
|
|
399
446
|
let eventSource: AsyncIterable<any>;
|
|
400
447
|
|