@mastra/code-sdk 1.10.1 → 1.11.0-alpha.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.
- package/dist/agents/mastracode-gateway.d.ts +4 -1
- package/dist/agents/mastracode-gateway.d.ts.map +1 -1
- package/dist/agents/mastracode-gateway.js +13 -9
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.d.ts.map +1 -1
- package/dist/agents/memory.js +7 -2
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.d.ts +2 -0
- package/dist/agents/model.d.ts.map +1 -1
- package/dist/agents/model.js +1 -0
- package/dist/agents/model.js.map +1 -1
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -8
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic-prompt-cache.d.ts +19 -0
- package/dist/providers/anthropic-prompt-cache.d.ts.map +1 -0
- package/dist/providers/anthropic-prompt-cache.js +11 -0
- package/dist/providers/anthropic-prompt-cache.js.map +1 -0
- package/dist/providers/claude-max.d.ts +4 -2
- package/dist/providers/claude-max.d.ts.map +1 -1
- package/dist/providers/claude-max.js +8 -7
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/utils/notification-dispatch.d.ts +59 -0
- package/dist/utils/notification-dispatch.d.ts.map +1 -0
- package/dist/utils/notification-dispatch.js +109 -0
- package/dist/utils/notification-dispatch.js.map +1 -0
- package/dist/utils/signals-pubsub.d.ts +42 -13
- package/dist/utils/signals-pubsub.d.ts.map +1 -1
- package/dist/utils/signals-pubsub.js +141 -38
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/package.json +8 -8
|
@@ -2,37 +2,134 @@ import { join } from "path";
|
|
|
2
2
|
import { mkdir } from "fs/promises";
|
|
3
3
|
import { PubSub, UnixSocketPubSub } from "@mastra/core/events";
|
|
4
4
|
//#region src/utils/signals-pubsub.ts
|
|
5
|
+
const DEFAULT_SOCKET_ROOT = "/tmp/mc";
|
|
6
|
+
const SHARED_SCOPE_DIR = "_shared";
|
|
5
7
|
const THREAD_STREAM_PREFIX = "agent.thread-stream.";
|
|
8
|
+
const THREAD_KEY_SEPARATOR = "\0";
|
|
9
|
+
const THREAD_CLAIM_LEASE_PREFIX = "thread-claim:";
|
|
10
|
+
const NOTIFICATION_DISPATCH_LEASE_PREFIX = "notification-dispatch:";
|
|
11
|
+
const OWNER_DISCOVERY_TOPIC = "agent.thread-owner-discovery";
|
|
12
|
+
const MAX_PATH_SEGMENT_LENGTH = 128;
|
|
13
|
+
/**
|
|
14
|
+
* Whether an id can name a single directory: no path separators or control
|
|
15
|
+
* characters, not `.`/`..`, and bounded in length.
|
|
16
|
+
*/
|
|
17
|
+
function isSafePathSegment(value) {
|
|
18
|
+
if (!value || value.length > MAX_PATH_SEGMENT_LENGTH || value === "." || value === "..") return false;
|
|
19
|
+
for (const char of value) {
|
|
20
|
+
const code = char.charCodeAt(0);
|
|
21
|
+
if (char === "/" || char === "\\" || code < 32 || code === 127) return false;
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
/** The resource a thread key (`<resourceId>\0<threadId>`) belongs to. */
|
|
26
|
+
function resourceOfThreadKey(key) {
|
|
27
|
+
const separatorIdx = key.indexOf(THREAD_KEY_SEPARATOR);
|
|
28
|
+
if (separatorIdx <= 0) return void 0;
|
|
29
|
+
const resourceId = key.slice(0, separatorIdx);
|
|
30
|
+
return isSafePathSegment(resourceId) ? resourceId : void 0;
|
|
31
|
+
}
|
|
32
|
+
/** Decodes `agent.thread-stream.<encoded resourceId\0threadId>[...]`. */
|
|
33
|
+
function decodeThreadTopic(topic) {
|
|
34
|
+
if (!topic.startsWith(THREAD_STREAM_PREFIX)) return void 0;
|
|
35
|
+
try {
|
|
36
|
+
return decodeURIComponent(topic.slice(20));
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The lease that lets exactly one process dispatch a resource's due
|
|
43
|
+
* notifications. Held in that resource's directory, so every process serving
|
|
44
|
+
* the resource contends for it whichever project it was started in.
|
|
45
|
+
*/
|
|
46
|
+
function notificationDispatchLeaseKey(resourceId) {
|
|
47
|
+
return `${NOTIFICATION_DISPATCH_LEASE_PREFIX}${resourceId}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The resource a lease key belongs to: a thread's run lease and claim lease,
|
|
51
|
+
* and a resource's notification dispatch lease.
|
|
52
|
+
*/
|
|
53
|
+
function resourceOfLeaseKey(key) {
|
|
54
|
+
if (key.startsWith(NOTIFICATION_DISPATCH_LEASE_PREFIX)) {
|
|
55
|
+
const resourceId = key.slice(22);
|
|
56
|
+
return isSafePathSegment(resourceId) ? resourceId : void 0;
|
|
57
|
+
}
|
|
58
|
+
return resourceOfThreadKey(key.startsWith(THREAD_CLAIM_LEASE_PREFIX) ? key.slice(13) : key);
|
|
59
|
+
}
|
|
60
|
+
function isOwnerDiscoveryTopic(topic) {
|
|
61
|
+
return topic === OWNER_DISCOVERY_TOPIC || topic.startsWith(`${OWNER_DISCOVERY_TOPIC}.`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Derive a filesystem-safe key for the topic. Thread-stream topics embed
|
|
65
|
+
* a threadId; all other topics use a sanitized version of the topic name.
|
|
66
|
+
*/
|
|
67
|
+
function topicKey(topic) {
|
|
68
|
+
const decoded = decodeThreadTopic(topic);
|
|
69
|
+
if (decoded !== void 0) {
|
|
70
|
+
const separatorIdx = decoded.indexOf(THREAD_KEY_SEPARATOR);
|
|
71
|
+
if (separatorIdx !== -1) return decoded.slice(separatorIdx + 1);
|
|
72
|
+
}
|
|
73
|
+
return topic.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
74
|
+
}
|
|
6
75
|
/**
|
|
7
76
|
* A PubSub that manages one Unix socket per topic for cross-process signal
|
|
8
|
-
* coordination
|
|
77
|
+
* coordination between mastracode processes on this machine.
|
|
78
|
+
*
|
|
79
|
+
* Socket paths use `<root>/<dir>/<sanitized-topic>.sock` (root `/tmp/mc`)
|
|
80
|
+
* for inspectability and automatic OS cleanup. Each topic gets its own
|
|
81
|
+
* socket, so broker election and message routing are per-topic.
|
|
9
82
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
83
|
+
* Every process shares one database, so any process can act on any project's
|
|
84
|
+
* thread — the notification dispatcher, for one, delivers whatever is due.
|
|
85
|
+
* Whatever coordinates a thread therefore lives with the thread, not with the
|
|
86
|
+
* process touching it:
|
|
87
|
+
*
|
|
88
|
+
* - A thread's stream topic and its leases (the run lease and the claim
|
|
89
|
+
* lease) live in the directory of the resource that owns the thread, so a
|
|
90
|
+
* process from another project sees that thread's active run and claim.
|
|
91
|
+
* - Thread-owner discovery lives in `<root>/_shared/`, so a process that finds
|
|
92
|
+
* a thread claimed can reach the owner and hand it the signal. It only
|
|
93
|
+
* answers for a thread the asker names, so it discloses nothing new.
|
|
94
|
+
* - Everything else, including peer discovery (which lists threads), stays in
|
|
95
|
+
* this process's own resource directory.
|
|
14
96
|
*
|
|
15
97
|
* Stale sockets from crashed processes are handled by
|
|
16
98
|
* {@link UnixSocketPubSub}'s built-in election logic: it detects
|
|
17
99
|
* ECONNREFUSED on a dead broker socket, unlinks it, and re-elects.
|
|
18
100
|
* No blanket cleanup is needed here — that would break concurrent
|
|
19
|
-
* mc instances sharing
|
|
101
|
+
* mc instances sharing a directory.
|
|
20
102
|
*/
|
|
21
103
|
var SignalsPubSub = class extends PubSub {
|
|
22
104
|
#resourceId;
|
|
23
|
-
#
|
|
105
|
+
#rootDir;
|
|
106
|
+
#leaseSockets = /* @__PURE__ */ new Map();
|
|
24
107
|
#sockets = /* @__PURE__ */ new Map();
|
|
25
108
|
#pending = /* @__PURE__ */ new Map();
|
|
109
|
+
#leaseProvider;
|
|
26
110
|
#closed = false;
|
|
27
|
-
constructor(resourceId) {
|
|
111
|
+
constructor(resourceId, options = {}) {
|
|
28
112
|
super();
|
|
29
113
|
this.#resourceId = resourceId;
|
|
30
|
-
this.#
|
|
114
|
+
this.#rootDir = options.rootDir ?? DEFAULT_SOCKET_ROOT;
|
|
115
|
+
this.#leasesFor(resourceId);
|
|
116
|
+
const route = (key) => this.#leasesFor(resourceOfLeaseKey(key) ?? this.#resourceId);
|
|
117
|
+
this.#leaseProvider = {
|
|
118
|
+
acquireLease: (key, owner, ttlMs) => route(key).acquireLease(key, owner, ttlMs),
|
|
119
|
+
getLeaseOwner: (key) => route(key).getLeaseOwner(key),
|
|
120
|
+
releaseLease: (key, owner) => route(key).releaseLease(key, owner),
|
|
121
|
+
renewLease: (key, owner, ttlMs) => route(key).renewLease(key, owner, ttlMs),
|
|
122
|
+
transferLease: (key, fromOwner, toOwner, ttlMs) => route(key).transferLease(key, fromOwner, toOwner, ttlMs)
|
|
123
|
+
};
|
|
31
124
|
}
|
|
32
125
|
get supportedModes() {
|
|
33
126
|
return ["push"];
|
|
34
127
|
}
|
|
35
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* Filesystem leases. A thread's run and claim leases are held in the
|
|
130
|
+
* directory of the thread's resource, so every process contends for the
|
|
131
|
+
* same lease; any other key stays in this resource's directory.
|
|
132
|
+
*/
|
|
36
133
|
getLeaseProvider() {
|
|
37
134
|
return this.#leaseProvider;
|
|
38
135
|
}
|
|
@@ -43,7 +140,7 @@ var SignalsPubSub = class extends PubSub {
|
|
|
43
140
|
await (await this.#getOrCreate(topic)).subscribe(topic, cb, options);
|
|
44
141
|
}
|
|
45
142
|
async unsubscribe(topic, cb) {
|
|
46
|
-
const socket = this.#sockets.get(this.#
|
|
143
|
+
const socket = this.#sockets.get(this.#socketKey(topic));
|
|
47
144
|
if (!socket) return;
|
|
48
145
|
await socket.unsubscribe(topic, cb);
|
|
49
146
|
}
|
|
@@ -52,16 +149,35 @@ var SignalsPubSub = class extends PubSub {
|
|
|
52
149
|
}
|
|
53
150
|
async close() {
|
|
54
151
|
this.#closed = true;
|
|
55
|
-
await Promise.allSettled([this.#
|
|
152
|
+
await Promise.allSettled([...[...this.#leaseSockets.values()].map((s) => s.close()), ...[...this.#sockets.values()].map((s) => s.close())]);
|
|
56
153
|
this.#sockets.clear();
|
|
154
|
+
this.#leaseSockets.clear();
|
|
57
155
|
}
|
|
58
156
|
/** Get the underlying socket for a topic (for testing/inspection). */
|
|
59
157
|
getSocket(topic) {
|
|
60
|
-
return this.#sockets.get(this.#
|
|
158
|
+
return this.#sockets.get(this.#socketKey(topic));
|
|
159
|
+
}
|
|
160
|
+
#leasesFor(resourceId) {
|
|
161
|
+
let socket = this.#leaseSockets.get(resourceId);
|
|
162
|
+
if (!socket) {
|
|
163
|
+
socket = new UnixSocketPubSub(join(this.#rootDir, resourceId, ".leases.sock"));
|
|
164
|
+
this.#leaseSockets.set(resourceId, socket);
|
|
165
|
+
}
|
|
166
|
+
return socket;
|
|
167
|
+
}
|
|
168
|
+
/** The directory, under the root, that holds a topic's socket. */
|
|
169
|
+
#dirFor(topic) {
|
|
170
|
+
if (isOwnerDiscoveryTopic(topic)) return SHARED_SCOPE_DIR;
|
|
171
|
+
const decoded = decodeThreadTopic(topic);
|
|
172
|
+
if (decoded !== void 0) return resourceOfThreadKey(decoded) ?? this.#resourceId;
|
|
173
|
+
return this.#resourceId;
|
|
174
|
+
}
|
|
175
|
+
#socketKey(topic) {
|
|
176
|
+
return `${this.#dirFor(topic)}/${topicKey(topic)}`;
|
|
61
177
|
}
|
|
62
178
|
async #getOrCreate(topic) {
|
|
63
179
|
if (this.#closed) throw new Error("SignalsPubSub is closed");
|
|
64
|
-
const key = this.#
|
|
180
|
+
const key = this.#socketKey(topic);
|
|
65
181
|
const existing = this.#sockets.get(key);
|
|
66
182
|
if (existing) return existing;
|
|
67
183
|
let inflight = this.#pending.get(key);
|
|
@@ -85,8 +201,8 @@ var SignalsPubSub = class extends PubSub {
|
|
|
85
201
|
}
|
|
86
202
|
}
|
|
87
203
|
async #socketPath(topic) {
|
|
88
|
-
let key =
|
|
89
|
-
const dir = join(
|
|
204
|
+
let key = topicKey(topic);
|
|
205
|
+
const dir = join(this.#rootDir, this.#dirFor(topic));
|
|
90
206
|
await mkdir(dir, { recursive: true });
|
|
91
207
|
const candidate = join(dir, `${key}.sock`);
|
|
92
208
|
if (Buffer.byteLength(candidate) > 104) {
|
|
@@ -95,34 +211,21 @@ var SignalsPubSub = class extends PubSub {
|
|
|
95
211
|
}
|
|
96
212
|
return candidate;
|
|
97
213
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Derive a filesystem-safe key for the topic. Thread-stream topics embed
|
|
100
|
-
* a threadId; all other topics use a sanitized version of the topic name.
|
|
101
|
-
*/
|
|
102
|
-
#topicKey(topic) {
|
|
103
|
-
if (topic.startsWith(THREAD_STREAM_PREFIX)) {
|
|
104
|
-
const encoded = topic.slice(20);
|
|
105
|
-
try {
|
|
106
|
-
const decoded = decodeURIComponent(encoded);
|
|
107
|
-
const separatorIdx = decoded.indexOf("\0");
|
|
108
|
-
if (separatorIdx !== -1) return decoded.slice(separatorIdx + 1);
|
|
109
|
-
} catch {}
|
|
110
|
-
}
|
|
111
|
-
return topic.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
112
|
-
}
|
|
113
214
|
};
|
|
114
215
|
/**
|
|
115
216
|
* Creates a per-topic PubSub backed by Unix sockets for cross-process signal
|
|
116
|
-
* and workflow event coordination
|
|
217
|
+
* and workflow event coordination between mastracode processes.
|
|
117
218
|
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* {@link
|
|
219
|
+
* Topics live under `/tmp/mc/<resourceId>/`, except that a thread's stream and
|
|
220
|
+
* leases live under its own resource's directory and thread-owner discovery
|
|
221
|
+
* under `/tmp/mc/_shared/` (see {@link SignalsPubSub}). Stale sockets from
|
|
222
|
+
* crashed processes are handled by the underlying {@link UnixSocketPubSub}'s
|
|
223
|
+
* broker election logic.
|
|
121
224
|
*/
|
|
122
|
-
function createSignalsPubSub(resourceId) {
|
|
123
|
-
return new SignalsPubSub(resourceId);
|
|
225
|
+
function createSignalsPubSub(resourceId, options) {
|
|
226
|
+
return new SignalsPubSub(resourceId, options);
|
|
124
227
|
}
|
|
125
228
|
//#endregion
|
|
126
|
-
export { createSignalsPubSub };
|
|
229
|
+
export { createSignalsPubSub, notificationDispatchLeaseKey };
|
|
127
230
|
|
|
128
231
|
//# sourceMappingURL=signals-pubsub.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signals-pubsub.js","names":["#resourceId","#leaseProvider","#sockets","#pending","#getOrCreate","#topicKey","#closed","#initSocket","#socketPath"],"sources":["../../src/utils/signals-pubsub.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { PubSub, UnixSocketPubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, LeaseProvider, PubSubDeliveryMode, SubscribeOptions } from '@mastra/core/events';\n\nconst THREAD_STREAM_PREFIX = 'agent.thread-stream.';\n\n/**\n * A PubSub that manages one Unix socket per topic for cross-process signal\n * coordination within a mastracode resource.\n *\n * Socket paths use `/tmp/mc/<resourceId>/<sanitized-topic>.sock` for\n * inspectability and automatic OS cleanup. Each topic gets its own isolated\n * socket so broker election and message routing are per-topic. A dedicated\n * resource-wide socket exposes filesystem leases shared by every topic.\n *\n * Stale sockets from crashed processes are handled by\n * {@link UnixSocketPubSub}'s built-in election logic: it detects\n * ECONNREFUSED on a dead broker socket, unlinks it, and re-elects.\n * No blanket cleanup is needed here — that would break concurrent\n * mc instances sharing the same resourceId.\n */\nclass SignalsPubSub extends PubSub {\n readonly #resourceId: string;\n readonly #leaseProvider: UnixSocketPubSub;\n readonly #sockets = new Map<string, UnixSocketPubSub>();\n readonly #pending = new Map<string, Promise<UnixSocketPubSub>>();\n #closed = false;\n\n constructor(resourceId: string) {\n super();\n this.#resourceId = resourceId;\n this.#leaseProvider = new UnixSocketPubSub(join('/tmp/mc', resourceId, '.leases.sock'));\n }\n\n override get supportedModes(): ReadonlyArray<PubSubDeliveryMode> {\n return ['push'];\n }\n\n /** Exposes the resource-wide filesystem lease provider shared by every topic socket. */\n getLeaseProvider(): LeaseProvider {\n return this.#leaseProvider;\n }\n\n async publish(\n topic: string,\n event: Omit<Event, 'id' | 'createdAt'>,\n options?: { localOnly?: boolean },\n ): Promise<void> {\n const socket = await this.#getOrCreate(topic);\n await socket.publish(topic, event, options);\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n const socket = await this.#getOrCreate(topic);\n await socket.subscribe(topic, cb, options);\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n const socket = this.#sockets.get(this.#topicKey(topic));\n if (!socket) return;\n await socket.unsubscribe(topic, cb);\n }\n\n async flush(): Promise<void> {\n await Promise.all([...this.#sockets.values()].map(s => s.flush()));\n }\n\n async close(): Promise<void> {\n this.#closed = true;\n await Promise.allSettled([this.#leaseProvider.close(), ...[...this.#sockets.values()].map(s => s.close())]);\n this.#sockets.clear();\n }\n\n /** Get the underlying socket for a topic (for testing/inspection). */\n getSocket(topic: string): UnixSocketPubSub | undefined {\n return this.#sockets.get(this.#topicKey(topic));\n }\n\n async #getOrCreate(topic: string): Promise<UnixSocketPubSub> {\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n const key = this.#topicKey(topic);\n const existing = this.#sockets.get(key);\n if (existing) return existing;\n // Deduplicate concurrent callers so only one socket is created per topic.\n let inflight = this.#pending.get(key);\n if (!inflight) {\n inflight = this.#initSocket(topic, key);\n this.#pending.set(key, inflight);\n }\n const socket = await inflight;\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n return socket;\n }\n\n async #initSocket(topic: string, key: string): Promise<UnixSocketPubSub> {\n try {\n const socketPath = await this.#socketPath(topic);\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n const socket = new UnixSocketPubSub(socketPath);\n this.#sockets.set(key, socket);\n return socket;\n } finally {\n this.#pending.delete(key);\n }\n }\n\n async #socketPath(topic: string): Promise<string> {\n let key = this.#topicKey(topic);\n const dir = join('/tmp/mc', this.#resourceId);\n await mkdir(dir, { recursive: true });\n const candidate = join(dir, `${key}.sock`);\n // macOS sun_path limit is 104 bytes; Linux is 108. Use 104 as the\n // conservative bound. When the path is too long, replace the key with\n // a short hash so the socket can still be created.\n if (Buffer.byteLength(candidate) > 104) {\n key = Buffer.from(await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(key)))\n .toString('hex')\n .slice(0, 16);\n return join(dir, `${key}.sock`);\n }\n return candidate;\n }\n\n /**\n * Derive a filesystem-safe key for the topic. Thread-stream topics embed\n * a threadId; all other topics use a sanitized version of the topic name.\n */\n #topicKey(topic: string): string {\n if (topic.startsWith(THREAD_STREAM_PREFIX)) {\n const encoded = topic.slice(THREAD_STREAM_PREFIX.length);\n try {\n const decoded = decodeURIComponent(encoded);\n const separatorIdx = decoded.indexOf('\\0');\n if (separatorIdx !== -1) {\n return decoded.slice(separatorIdx + 1);\n }\n } catch {\n // Malformed URI — fall through to sanitized fallback.\n }\n }\n // Fallback: use the topic directly (sanitized for filesystem)\n return topic.replace(/[^a-zA-Z0-9_-]/g, '_');\n }\n}\n\n/**\n * Creates a per-topic PubSub backed by Unix sockets for cross-process signal\n * and workflow event coordination within a mastracode resource.\n *\n * Each topic gets its own Unix socket under `/tmp/mc/<resourceId>/`.\n * Stale sockets from crashed processes are handled by the underlying\n * {@link UnixSocketPubSub}'s broker election logic.\n */\nexport function createSignalsPubSub(resourceId: string): SignalsPubSub {\n return new SignalsPubSub(resourceId);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signals-pubsub.js","names":["#resourceId","#rootDir","#leaseSockets","#sockets","#pending","#leaseProvider","#leasesFor","#getOrCreate","#socketKey","#closed","#dirFor","#initSocket","#socketPath"],"sources":["../../src/utils/signals-pubsub.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { PubSub, UnixSocketPubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, LeaseProvider, PubSubDeliveryMode, SubscribeOptions } from '@mastra/core/events';\n\nconst DEFAULT_SOCKET_ROOT = '/tmp/mc';\nconst SHARED_SCOPE_DIR = '_shared';\nconst THREAD_STREAM_PREFIX = 'agent.thread-stream.';\nconst THREAD_KEY_SEPARATOR = '\\0';\nconst THREAD_CLAIM_LEASE_PREFIX = 'thread-claim:';\nconst NOTIFICATION_DISPATCH_LEASE_PREFIX = 'notification-dispatch:';\nconst OWNER_DISCOVERY_TOPIC = 'agent.thread-owner-discovery';\nconst MAX_PATH_SEGMENT_LENGTH = 128;\n\nexport type SignalsPubSubOptions = {\n /** Directory that holds every resource's socket directory. Defaults to `/tmp/mc`. */\n rootDir?: string;\n};\n\n/**\n * Whether an id can name a single directory: no path separators or control\n * characters, not `.`/`..`, and bounded in length.\n */\nfunction isSafePathSegment(value: string): boolean {\n if (!value || value.length > MAX_PATH_SEGMENT_LENGTH || value === '.' || value === '..') return false;\n for (const char of value) {\n const code = char.charCodeAt(0);\n if (char === '/' || char === '\\\\' || code < 0x20 || code === 0x7f) return false;\n }\n return true;\n}\n\n/** The resource a thread key (`<resourceId>\\0<threadId>`) belongs to. */\nfunction resourceOfThreadKey(key: string): string | undefined {\n const separatorIdx = key.indexOf(THREAD_KEY_SEPARATOR);\n if (separatorIdx <= 0) return undefined;\n const resourceId = key.slice(0, separatorIdx);\n return isSafePathSegment(resourceId) ? resourceId : undefined;\n}\n\n/** Decodes `agent.thread-stream.<encoded resourceId\\0threadId>[...]`. */\nfunction decodeThreadTopic(topic: string): string | undefined {\n if (!topic.startsWith(THREAD_STREAM_PREFIX)) return undefined;\n try {\n return decodeURIComponent(topic.slice(THREAD_STREAM_PREFIX.length));\n } catch {\n return undefined;\n }\n}\n\n/**\n * The lease that lets exactly one process dispatch a resource's due\n * notifications. Held in that resource's directory, so every process serving\n * the resource contends for it whichever project it was started in.\n */\nexport function notificationDispatchLeaseKey(resourceId: string): string {\n return `${NOTIFICATION_DISPATCH_LEASE_PREFIX}${resourceId}`;\n}\n\n/**\n * The resource a lease key belongs to: a thread's run lease and claim lease,\n * and a resource's notification dispatch lease.\n */\nfunction resourceOfLeaseKey(key: string): string | undefined {\n if (key.startsWith(NOTIFICATION_DISPATCH_LEASE_PREFIX)) {\n const resourceId = key.slice(NOTIFICATION_DISPATCH_LEASE_PREFIX.length);\n return isSafePathSegment(resourceId) ? resourceId : undefined;\n }\n return resourceOfThreadKey(\n key.startsWith(THREAD_CLAIM_LEASE_PREFIX) ? key.slice(THREAD_CLAIM_LEASE_PREFIX.length) : key,\n );\n}\n\nfunction isOwnerDiscoveryTopic(topic: string): boolean {\n return topic === OWNER_DISCOVERY_TOPIC || topic.startsWith(`${OWNER_DISCOVERY_TOPIC}.`);\n}\n\n/**\n * Derive a filesystem-safe key for the topic. Thread-stream topics embed\n * a threadId; all other topics use a sanitized version of the topic name.\n */\nfunction topicKey(topic: string): string {\n const decoded = decodeThreadTopic(topic);\n if (decoded !== undefined) {\n const separatorIdx = decoded.indexOf(THREAD_KEY_SEPARATOR);\n if (separatorIdx !== -1) return decoded.slice(separatorIdx + 1);\n }\n return topic.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/**\n * A PubSub that manages one Unix socket per topic for cross-process signal\n * coordination between mastracode processes on this machine.\n *\n * Socket paths use `<root>/<dir>/<sanitized-topic>.sock` (root `/tmp/mc`)\n * for inspectability and automatic OS cleanup. Each topic gets its own\n * socket, so broker election and message routing are per-topic.\n *\n * Every process shares one database, so any process can act on any project's\n * thread — the notification dispatcher, for one, delivers whatever is due.\n * Whatever coordinates a thread therefore lives with the thread, not with the\n * process touching it:\n *\n * - A thread's stream topic and its leases (the run lease and the claim\n * lease) live in the directory of the resource that owns the thread, so a\n * process from another project sees that thread's active run and claim.\n * - Thread-owner discovery lives in `<root>/_shared/`, so a process that finds\n * a thread claimed can reach the owner and hand it the signal. It only\n * answers for a thread the asker names, so it discloses nothing new.\n * - Everything else, including peer discovery (which lists threads), stays in\n * this process's own resource directory.\n *\n * Stale sockets from crashed processes are handled by\n * {@link UnixSocketPubSub}'s built-in election logic: it detects\n * ECONNREFUSED on a dead broker socket, unlinks it, and re-elects.\n * No blanket cleanup is needed here — that would break concurrent\n * mc instances sharing a directory.\n */\nclass SignalsPubSub extends PubSub {\n readonly #resourceId: string;\n readonly #rootDir: string;\n readonly #leaseSockets = new Map<string, UnixSocketPubSub>();\n readonly #sockets = new Map<string, UnixSocketPubSub>();\n readonly #pending = new Map<string, Promise<UnixSocketPubSub>>();\n readonly #leaseProvider: LeaseProvider;\n #closed = false;\n\n constructor(resourceId: string, options: SignalsPubSubOptions = {}) {\n super();\n this.#resourceId = resourceId;\n this.#rootDir = options.rootDir ?? DEFAULT_SOCKET_ROOT;\n // Created eagerly, as before, so this resource's lease socket exists from the start.\n this.#leasesFor(resourceId);\n const route = (key: string) => this.#leasesFor(resourceOfLeaseKey(key) ?? this.#resourceId);\n this.#leaseProvider = {\n acquireLease: (key, owner, ttlMs) => route(key).acquireLease(key, owner, ttlMs),\n getLeaseOwner: key => route(key).getLeaseOwner(key),\n releaseLease: (key, owner) => route(key).releaseLease(key, owner),\n renewLease: (key, owner, ttlMs) => route(key).renewLease(key, owner, ttlMs),\n transferLease: (key, fromOwner, toOwner, ttlMs) => route(key).transferLease(key, fromOwner, toOwner, ttlMs),\n };\n }\n\n override get supportedModes(): ReadonlyArray<PubSubDeliveryMode> {\n return ['push'];\n }\n\n /**\n * Filesystem leases. A thread's run and claim leases are held in the\n * directory of the thread's resource, so every process contends for the\n * same lease; any other key stays in this resource's directory.\n */\n getLeaseProvider(): LeaseProvider {\n return this.#leaseProvider;\n }\n\n async publish(\n topic: string,\n event: Omit<Event, 'id' | 'createdAt'>,\n options?: { localOnly?: boolean },\n ): Promise<void> {\n const socket = await this.#getOrCreate(topic);\n await socket.publish(topic, event, options);\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n const socket = await this.#getOrCreate(topic);\n await socket.subscribe(topic, cb, options);\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n const socket = this.#sockets.get(this.#socketKey(topic));\n if (!socket) return;\n await socket.unsubscribe(topic, cb);\n }\n\n async flush(): Promise<void> {\n await Promise.all([...this.#sockets.values()].map(s => s.flush()));\n }\n\n async close(): Promise<void> {\n this.#closed = true;\n await Promise.allSettled([\n ...[...this.#leaseSockets.values()].map(s => s.close()),\n ...[...this.#sockets.values()].map(s => s.close()),\n ]);\n this.#sockets.clear();\n this.#leaseSockets.clear();\n }\n\n /** Get the underlying socket for a topic (for testing/inspection). */\n getSocket(topic: string): UnixSocketPubSub | undefined {\n return this.#sockets.get(this.#socketKey(topic));\n }\n\n #leasesFor(resourceId: string): UnixSocketPubSub {\n let socket = this.#leaseSockets.get(resourceId);\n if (!socket) {\n socket = new UnixSocketPubSub(join(this.#rootDir, resourceId, '.leases.sock'));\n this.#leaseSockets.set(resourceId, socket);\n }\n return socket;\n }\n\n /** The directory, under the root, that holds a topic's socket. */\n #dirFor(topic: string): string {\n if (isOwnerDiscoveryTopic(topic)) return SHARED_SCOPE_DIR;\n const decoded = decodeThreadTopic(topic);\n if (decoded !== undefined) return resourceOfThreadKey(decoded) ?? this.#resourceId;\n return this.#resourceId;\n }\n\n #socketKey(topic: string): string {\n return `${this.#dirFor(topic)}/${topicKey(topic)}`;\n }\n\n async #getOrCreate(topic: string): Promise<UnixSocketPubSub> {\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n const key = this.#socketKey(topic);\n const existing = this.#sockets.get(key);\n if (existing) return existing;\n // Deduplicate concurrent callers so only one socket is created per topic.\n let inflight = this.#pending.get(key);\n if (!inflight) {\n inflight = this.#initSocket(topic, key);\n this.#pending.set(key, inflight);\n }\n const socket = await inflight;\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n return socket;\n }\n\n async #initSocket(topic: string, key: string): Promise<UnixSocketPubSub> {\n try {\n const socketPath = await this.#socketPath(topic);\n if (this.#closed) throw new Error('SignalsPubSub is closed');\n const socket = new UnixSocketPubSub(socketPath);\n this.#sockets.set(key, socket);\n return socket;\n } finally {\n this.#pending.delete(key);\n }\n }\n\n async #socketPath(topic: string): Promise<string> {\n let key = topicKey(topic);\n const dir = join(this.#rootDir, this.#dirFor(topic));\n await mkdir(dir, { recursive: true });\n const candidate = join(dir, `${key}.sock`);\n // macOS sun_path limit is 104 bytes; Linux is 108. Use 104 as the\n // conservative bound. When the path is too long, replace the key with\n // a short hash so the socket can still be created.\n if (Buffer.byteLength(candidate) > 104) {\n key = Buffer.from(await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(key)))\n .toString('hex')\n .slice(0, 16);\n return join(dir, `${key}.sock`);\n }\n return candidate;\n }\n}\n\n/**\n * Creates a per-topic PubSub backed by Unix sockets for cross-process signal\n * and workflow event coordination between mastracode processes.\n *\n * Topics live under `/tmp/mc/<resourceId>/`, except that a thread's stream and\n * leases live under its own resource's directory and thread-owner discovery\n * under `/tmp/mc/_shared/` (see {@link SignalsPubSub}). Stale sockets from\n * crashed processes are handled by the underlying {@link UnixSocketPubSub}'s\n * broker election logic.\n */\nexport function createSignalsPubSub(resourceId: string, options?: SignalsPubSubOptions): SignalsPubSub {\n return new SignalsPubSub(resourceId, options);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/code-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0-alpha.1",
|
|
4
4
|
"description": "Mastra Code SDK: the agent core behind Mastra Code (everything except the TUI) — build your own UIs and surfaces on top of it",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -62,20 +62,20 @@
|
|
|
62
62
|
"vscode-languageserver-protocol": "^3.17.5",
|
|
63
63
|
"yaml": "^2.7.1",
|
|
64
64
|
"zod": "^4.6.4",
|
|
65
|
-
"@mastra/agent-browser": "0.5.3",
|
|
66
|
-
"@mastra/core": "1.74.0",
|
|
67
65
|
"@mastra/duckdb": "1.12.1",
|
|
68
|
-
"@mastra/
|
|
66
|
+
"@mastra/agent-browser": "0.5.3",
|
|
69
67
|
"@mastra/github-signals": "0.5.1",
|
|
68
|
+
"@mastra/fastembed": "1.3.2",
|
|
70
69
|
"@mastra/libsql": "1.25.0",
|
|
71
70
|
"@mastra/mcp": "2.1.2",
|
|
72
|
-
"@mastra/
|
|
71
|
+
"@mastra/core": "1.75.0-alpha.1",
|
|
72
|
+
"@mastra/memory": "1.36.0-alpha.1",
|
|
73
73
|
"@mastra/observability": "1.18.3",
|
|
74
74
|
"@mastra/parallel": "0.1.2",
|
|
75
|
-
"@mastra/pg": "1.
|
|
75
|
+
"@mastra/pg": "1.30.0-alpha.0",
|
|
76
|
+
"@mastra/tavily": "1.1.2",
|
|
76
77
|
"@mastra/schema-compat": "1.3.13",
|
|
77
|
-
"@mastra/stagehand": "0.3.5"
|
|
78
|
-
"@mastra/tavily": "1.1.2"
|
|
78
|
+
"@mastra/stagehand": "0.3.5"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@libsql/client": "^0.18.0",
|