mindforge-sdk 11.8.0 → 11.9.5
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/README.md +28 -7
- package/dist/events.d.ts +8 -0
- package/dist/events.js +51 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# mindforge-sdk
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for embedding MindForge in tools, dashboards, and CI pipelines.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install
|
|
8
|
+
npm install mindforge-sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Quick start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import { MindForgeClient } from '
|
|
14
|
+
import { MindForgeClient } from 'mindforge-sdk';
|
|
15
15
|
|
|
16
16
|
const client = new MindForgeClient({
|
|
17
17
|
projectRoot: '/path/to/project',
|
|
@@ -33,8 +33,29 @@ console.log(metrics);
|
|
|
33
33
|
|
|
34
34
|
## Real-time event streaming
|
|
35
35
|
|
|
36
|
+
`MindForgeEventStream` is the supported path and it is self-contained: it starts its own SSE server,
|
|
37
|
+
tails `.planning/AUDIT.jsonl`, and broadcasts each new entry as an `audit_entry` event. Verified end to
|
|
38
|
+
end — `GET /events` returns `text/event-stream`, and appending to the audit log produces a broadcast.
|
|
39
|
+
Note the `watchAuditLog()` call below is required: `start()` serves the stream but does not begin
|
|
40
|
+
tailing on its own.
|
|
41
|
+
|
|
42
|
+
`WebSocketEventStream` is also exported, and it comes with two constraints worth knowing before you
|
|
43
|
+
reach for it:
|
|
44
|
+
|
|
45
|
+
- **It needs a global `WebSocket` that this package does not provide.** `engines.node` is `>=18.0.0`
|
|
46
|
+
and `dependencies` is empty, so on Node 18 or 20 you must install `ws` yourself and assign it to
|
|
47
|
+
`globalThis.WebSocket`. On Node 22+ the global exists. Calling `connect()` without one throws an
|
|
48
|
+
error saying so, rather than a bare `ReferenceError`.
|
|
49
|
+
- **MindForge ships no WebSocket server.** The default URL is `ws://127.0.0.1:7337/ws`, but the
|
|
50
|
+
dashboard exposes no `/ws` upgrade path — so this client is for connecting to a server *you* run,
|
|
51
|
+
not to MindForge itself. Use `MindForgeEventStream` if you want events from MindForge.
|
|
52
|
+
|
|
53
|
+
Reconnection is automatic (5 attempts, linear backoff). A reconnect that fails is delivered to an
|
|
54
|
+
`'error'` listener registered with `on('error', handler)`; once the attempts are exhausted a `'close'`
|
|
55
|
+
event fires with the reason, so a dead stream is observable rather than silent.
|
|
56
|
+
|
|
36
57
|
```typescript
|
|
37
|
-
import { MindForgeEventStream } from '
|
|
58
|
+
import { MindForgeEventStream } from 'mindforge-sdk';
|
|
38
59
|
|
|
39
60
|
const stream = new MindForgeEventStream();
|
|
40
61
|
await stream.start(7337);
|
|
@@ -64,7 +85,7 @@ if (!valid) console.error(errors);
|
|
|
64
85
|
- The SDK operates on local files and provides no network authentication. Do not expose SDK
|
|
65
86
|
endpoints to the public internet.
|
|
66
87
|
|
|
67
|
-
## New in v11.
|
|
88
|
+
## New in v11.9.5
|
|
68
89
|
|
|
69
90
|
### Additional exports
|
|
70
91
|
|
|
@@ -73,7 +94,7 @@ import {
|
|
|
73
94
|
MindForgeClient,
|
|
74
95
|
MindForgeEventStream,
|
|
75
96
|
WebSocketEventStream,
|
|
76
|
-
VERSION, // '11.
|
|
97
|
+
VERSION, // '11.9.5'
|
|
77
98
|
} from 'mindforge-sdk';
|
|
78
99
|
|
|
79
100
|
import type {
|
|
@@ -89,7 +110,7 @@ import type {
|
|
|
89
110
|
### Streaming execution
|
|
90
111
|
|
|
91
112
|
```typescript
|
|
92
|
-
import { MindForgeClient
|
|
113
|
+
import { MindForgeClient } from 'mindforge-sdk';
|
|
93
114
|
|
|
94
115
|
const client = new MindForgeClient({ projectRoot: '.' });
|
|
95
116
|
const { stream } = await client.streamExecution(1);
|
package/dist/events.d.ts
CHANGED
|
@@ -33,6 +33,14 @@ export declare class WebSocketEventStream {
|
|
|
33
33
|
private maxReconnectAttempts;
|
|
34
34
|
private listeners;
|
|
35
35
|
constructor(url?: string);
|
|
36
|
+
/**
|
|
37
|
+
* Dispatch to registered listeners. One dispatch path for messages, reconnect failures and
|
|
38
|
+
* stream death, so those three cannot drift apart in how they treat a throwing listener.
|
|
39
|
+
*
|
|
40
|
+
* A missing 'error' listener does NOT mean silence: a reconnect that fails invisibly leaves the
|
|
41
|
+
* consumer believing the stream is live, which is the failure mode this class was already in.
|
|
42
|
+
*/
|
|
43
|
+
private emit;
|
|
36
44
|
connect(): Promise<void>;
|
|
37
45
|
on(eventType: string, handler: EventHandler): void;
|
|
38
46
|
off(eventType: string, handler: EventHandler): void;
|
package/dist/events.js
CHANGED
|
@@ -192,7 +192,37 @@ class WebSocketEventStream {
|
|
|
192
192
|
this.maxReconnectAttempts = 5;
|
|
193
193
|
this.listeners = new Map();
|
|
194
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Dispatch to registered listeners. One dispatch path for messages, reconnect failures and
|
|
197
|
+
* stream death, so those three cannot drift apart in how they treat a throwing listener.
|
|
198
|
+
*
|
|
199
|
+
* A missing 'error' listener does NOT mean silence: a reconnect that fails invisibly leaves the
|
|
200
|
+
* consumer believing the stream is live, which is the failure mode this class was already in.
|
|
201
|
+
*/
|
|
202
|
+
emit(eventType, data) {
|
|
203
|
+
const handlers = this.listeners.get(eventType);
|
|
204
|
+
if (!handlers || handlers.size === 0) {
|
|
205
|
+
if (eventType === 'error' && typeof process !== 'undefined' && process.stderr) {
|
|
206
|
+
const message = data instanceof Error ? data.message : String(data);
|
|
207
|
+
process.stderr.write(`[MindForge SDK] event stream error: ${message}\n`);
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
// A listener that throws must not take the stream — or the process — with it.
|
|
212
|
+
handlers.forEach((handler) => { try {
|
|
213
|
+
handler(data);
|
|
214
|
+
}
|
|
215
|
+
catch { /* listener fault */ } });
|
|
216
|
+
}
|
|
195
217
|
async connect() {
|
|
218
|
+
// Fail fast and legibly. `WebSocket` is declared, not imported, and sdk/package.json has NO
|
|
219
|
+
// dependencies while engines.node is >=18.0.0 — so on Node 18 or 20 the constructor below is a
|
|
220
|
+
// bare `ReferenceError: WebSocket is not defined`, which tells the caller nothing about why.
|
|
221
|
+
if (typeof WebSocket === 'undefined') {
|
|
222
|
+
throw new Error('WebSocketEventStream requires a global WebSocket: Node 22+, a browser, or the optional '
|
|
223
|
+
+ '\'ws\' package installed and assigned to globalThis.WebSocket. This SDK declares no '
|
|
224
|
+
+ 'runtime dependencies, so it does not install one for you.');
|
|
225
|
+
}
|
|
196
226
|
return new Promise((resolve, reject) => {
|
|
197
227
|
this.ws = new WebSocket(this.url);
|
|
198
228
|
this.ws.onopen = () => {
|
|
@@ -203,15 +233,33 @@ class WebSocketEventStream {
|
|
|
203
233
|
this.ws.onmessage = (event) => {
|
|
204
234
|
try {
|
|
205
235
|
const parsed = JSON.parse(String(event.data));
|
|
206
|
-
|
|
207
|
-
handlers.forEach(handler => handler(parsed.data));
|
|
236
|
+
this.emit(parsed.type, parsed.data);
|
|
208
237
|
}
|
|
209
238
|
catch { /* malformed message */ }
|
|
210
239
|
};
|
|
211
240
|
this.ws.onclose = () => {
|
|
212
241
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
213
242
|
this.reconnectAttempts++;
|
|
214
|
-
setTimeout(() =>
|
|
243
|
+
setTimeout(() => {
|
|
244
|
+
// A scheduled reconnect is fire-and-forget, so nothing awaits the promise it returns.
|
|
245
|
+
// Without this .catch(), `connect()` rejecting via onerror is an UNHANDLED REJECTION —
|
|
246
|
+
// and under Node's default mode that is fatal: it TERMINATES THE CALLER'S PROCESS.
|
|
247
|
+
// Reproduced against the compiled module with a stub socket whose reconnect calls
|
|
248
|
+
// onerror: exit code 1, and the line after the wait never ran.
|
|
249
|
+
this.connect().catch((err) => this.emit('error', err));
|
|
250
|
+
}, 1000 * this.reconnectAttempts);
|
|
251
|
+
}
|
|
252
|
+
else if (this.maxReconnectAttempts > 0) {
|
|
253
|
+
// Attempts exhausted. This branch did not exist: the stream simply went quiet, leaving
|
|
254
|
+
// the consumer with no way to learn it was dead.
|
|
255
|
+
//
|
|
256
|
+
// Guarded on maxReconnectAttempts > 0 because disconnect() sets it to 0 (:276). Without
|
|
257
|
+
// the guard, a DELIBERATE disconnect would emit 'close' with reason "reconnect attempts
|
|
258
|
+
// exhausted" — telling the caller their stream died when they closed it themselves.
|
|
259
|
+
this.emit('close', {
|
|
260
|
+
reason: 'reconnect attempts exhausted',
|
|
261
|
+
attempts: this.reconnectAttempts,
|
|
262
|
+
});
|
|
215
263
|
}
|
|
216
264
|
};
|
|
217
265
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MindForge SDK — Public API
|
|
3
|
-
* @module
|
|
3
|
+
* @module mindforge-sdk
|
|
4
4
|
*/
|
|
5
5
|
export { MindForgeClient } from './client';
|
|
6
6
|
export { MindForgeEventStream, WebSocketEventStream } from './events';
|
|
@@ -8,4 +8,4 @@ export { commands, batch } from './commands';
|
|
|
8
8
|
export { MindForgeMemory } from './memory';
|
|
9
9
|
export type { CommandOptions } from './commands';
|
|
10
10
|
export type { MindForgeConfig, PhaseResult, TaskResult, SecurityFinding, GateResult, HealthReport, HealthIssue, MindForgeEvent, AuditLogEntry, WaveExecutionResult, MigrationResult, StreamChunk, StreamingExecutionResult, BatchExecutionRequest, BatchExecutionResult, } from './types';
|
|
11
|
-
export declare const VERSION = "11.
|
|
11
|
+
export declare const VERSION = "11.9.5";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* MindForge SDK — Public API
|
|
4
|
-
* @module
|
|
4
|
+
* @module mindforge-sdk
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.VERSION = exports.MindForgeMemory = exports.batch = exports.commands = exports.WebSocketEventStream = exports.MindForgeEventStream = exports.MindForgeClient = void 0;
|
|
@@ -15,4 +15,4 @@ Object.defineProperty(exports, "commands", { enumerable: true, get: function ()
|
|
|
15
15
|
Object.defineProperty(exports, "batch", { enumerable: true, get: function () { return commands_1.batch; } });
|
|
16
16
|
var memory_1 = require("./memory");
|
|
17
17
|
Object.defineProperty(exports, "MindForgeMemory", { enumerable: true, get: function () { return memory_1.MindForgeMemory; } });
|
|
18
|
-
exports.VERSION = '11.
|
|
18
|
+
exports.VERSION = '11.9.5';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindforge-sdk",
|
|
3
|
-
"version": "11.
|
|
4
|
-
"description": "MindForge SDK
|
|
3
|
+
"version": "11.9.5",
|
|
4
|
+
"description": "MindForge SDK — Programmatic API for embedding MindForge in tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
"sdk"
|
|
33
33
|
],
|
|
34
34
|
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/sairam0424/MindForge.git",
|
|
38
|
+
"directory": "sdk"
|
|
39
|
+
},
|
|
35
40
|
"publishConfig": {
|
|
36
41
|
"access": "public"
|
|
37
42
|
},
|
|
@@ -40,7 +45,7 @@
|
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
47
|
"@eslint/js": "^9.0.0",
|
|
43
|
-
"@types/node": "^
|
|
48
|
+
"@types/node": "^25.9.1",
|
|
44
49
|
"eslint": "^9.0.0",
|
|
45
50
|
"globals": "^15.0.0",
|
|
46
51
|
"typescript": "^5.4.0",
|