Skip to content

Commit b5ddc20

Browse files
committed
feat: enhance release workflow and improve serial monitor functionality
1 parent ef83c78 commit b5ddc20

File tree

8 files changed

+34
-43
lines changed

8 files changed

+34
-43
lines changed

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ jobs:
2727
sudo apt-get update
2828
sudo apt-get install -y binfmt-support qemu-user-static
2929
- name: 'Build'
30-
run: pnpm run package
30+
run: pnpm run build && pnpm --filter wokwi-cli run package
3131
- name: Upload Release
3232
uses: ncipollo/release-action@v1
3333
with:
34-
artifacts: 'dist/bin/wokwi-cli-*,dist/bin/version.json'
34+
artifacts: 'packages/wokwi-cli/dist/bin/wokwi-cli-*,packages/wokwi-cli/dist/bin/version.json'
3535
token: ${{ secrets.GITHUB_TOKEN }}
3636
generateReleaseNotes: true

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"test:embed:playwright": "playwright test test/wokwi-embed",
1717
"test:embed:playwright:ui": "playwright test test/wokwi-embed --ui",
1818
"test:cli:integration": "pnpm exec tsx scripts/test-cli-integration.ts",
19-
"package": "pnpm -r run package",
19+
"package": "pnpm --filter wokwi-cli run package",
2020
"cli": "tsx packages/wokwi-cli/src/main.ts",
2121
"prepare": "husky install"
2222
},

packages/wokwi-cli/src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import YAML from 'yaml';
66
import { APIClient, type APIEvent, type ChipsLogPayload, type SerialMonitorDataPayload } from 'wokwi-client-js';
77
import { WebSocketTransport } from './transport/WebSocketTransport.js';
88
import { DEFAULT_SERVER } from './constants.js';
9+
import { createSerialMonitorWritable } from './utils/serialMonitorWritable.js';
910
import { ExpectEngine } from './ExpectEngine.js';
1011
import { SimulationTimeoutError } from './SimulationTimeoutError.js';
1112
import { TestScenario } from './TestScenario.js';
@@ -362,7 +363,7 @@ async function main() {
362363
});
363364

364365
if (interactive) {
365-
process.stdin.pipe(await client.serialMonitorWritable());
366+
process.stdin.pipe(await createSerialMonitorWritable(client));
366367
}
367368

368369
if (scenario != null) {

packages/wokwi-cli/src/mcp/SimulationManager.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { existsSync, readFileSync } from 'fs';
22
import path from 'path';
3-
import { APIClient, type APIEvent } from 'wokwi-client-js';
3+
import { APIClient, SerialMonitorDataPayload, type APIEvent } from 'wokwi-client-js';
44
import { WebSocketTransport } from '../transport/WebSocketTransport.js';
55
import { DEFAULT_SERVER } from '../constants.js';
66
import { parseConfig } from '../config.js';
@@ -49,13 +49,10 @@ export class SimulationManager {
4949
throw new Error(`API Error: ${error.message}`);
5050
};
5151

52-
this.client.onEvent = (event: APIEvent) => {
53-
if (event.event === 'serial-monitor:data') {
54-
const bytes = (event as any).payload.bytes;
55-
const text = bytes.map((byte: number) => String.fromCharCode(byte)).join('');
56-
this.addToSerialBuffer(text);
57-
}
58-
};
52+
this.client.listen('serial-monitor:data', (event: APIEvent<SerialMonitorDataPayload>) => {
53+
const { bytes } = event.payload;
54+
this.addToSerialBuffer(String.fromCharCode(...bytes));
55+
});
5956

6057
await this.client.connected;
6158
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { APIClient } from 'wokwi-client-js';
2+
import { Writable } from 'stream';
3+
import { Buffer } from 'buffer';
4+
5+
/**
6+
* Creates a Node.js Writable stream that forwards data to the serial monitor.
7+
* This function is Node.js-only and cannot be used in browser environments.
8+
*/
9+
export async function createSerialMonitorWritable(client: APIClient) {
10+
return new Writable({
11+
write: (chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void) => {
12+
if (typeof chunk === 'string') {
13+
chunk = Buffer.from(chunk, encoding);
14+
}
15+
client.serialMonitorWrite(chunk).then(() => {
16+
callback(null);
17+
}, callback);
18+
},
19+
});
20+
}

packages/wokwi-client-js/src/APIClient.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { ITransport } from './transport/ITransport.js';
1313
import { base64ToByteArray, byteArrayToBase64 } from './base64.js';
1414

1515
export class APIClient {
16-
private connectionAttempts = 0;
1716
private lastId = 0;
1817
private lastPausePointId = 0;
1918
private closed = false;
@@ -30,7 +29,6 @@ export class APIClient {
3029

3130
onConnected?: (helloMessage: APIHello) => void;
3231
onError?: (error: APIError) => void;
33-
onEvent?: (event: APIEvent) => void;
3432

3533
constructor(
3634
private readonly transport: ITransport,
@@ -106,22 +104,6 @@ export class APIClient {
106104
});
107105
}
108106

109-
async serialMonitorWritable() {
110-
// Dynamic import for Node.js-only API
111-
const { Writable } = await import('stream');
112-
const { Buffer } = await import('buffer');
113-
return new Writable({
114-
write: (chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void) => {
115-
if (typeof chunk === 'string') {
116-
chunk = Buffer.from(chunk, encoding);
117-
}
118-
this.serialMonitorWrite(chunk).then(() => {
119-
callback(null);
120-
}, callback);
121-
},
122-
});
123-
}
124-
125107
async framebufferRead(partId: string) {
126108
return await this.sendCommand<{ png: string }>('framebuffer:read', {
127109
id: partId,
@@ -249,7 +231,6 @@ export class APIClient {
249231
}
250232
}
251233
this._lastNanos = message.nanos;
252-
this.onEvent?.(message);
253234
this.apiEvents.dispatchEvent(new CustomEvent<APIEvent>(message.event, { detail: message }));
254235
}
255236

@@ -292,14 +273,10 @@ export class APIClient {
292273
if (this.closed) return;
293274
const target = (this as any).server ?? 'transport';
294275
const msg = `Connection to ${target} closed unexpectedly: code ${code}${reason ? ` (${reason})` : ''}`;
295-
const errorObj: APIError = { type: 'error', message: msg };
296-
this.onError?.(errorObj);
297-
console.error(msg);
276+
this.onError?.({ type: 'error', message: msg });
298277
}
299278

300279
private handleTransportError(error: Error) {
301-
const errorObj: APIError = { type: 'error', message: error.message };
302-
this.onError?.(errorObj);
303-
console.error('Transport error:', error.message);
280+
this.onError?.({ type: 'error', message: error.message });
304281
}
305282
}

packages/wokwi-client-js/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
export { APIClient } from './APIClient.js';
33

44
// Transport interfaces and implementations
5-
export { ITransport } from './transport/ITransport.js';
5+
export { type ITransport } from './transport/ITransport.js';
66
export { MessagePortTransport } from './transport/MessagePortTransport.js';
77

88
// Pause Point

packages/wokwi-client-js/tools/bundle-browser.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,9 @@ const options = {
1313
platform: 'browser',
1414
format: 'esm',
1515
target: 'es2020',
16-
// Explicitly mark Node.js-only packages as external
17-
external: ['ws', 'stream', 'buffer'],
1816
banner: {
1917
js: `// Browser bundle of wokwi-client-js
20-
// Note: serialMonitorWritable() requires Node.js and won't work in browsers
21-
// Use MessagePortTransport for browser communication with Wokwi Simulator
18+
// Use MessagePortTransport for browser communication with Wokwi Simulator
2219
`,
2320
},
2421
};
@@ -32,4 +29,3 @@ build(options)
3229
console.error('✗ Browser bundle failed:', error);
3330
process.exit(1);
3431
});
35-

0 commit comments

Comments
 (0)