@dev-mainsequence/codex-plugin 0.3.0 → 0.7.9

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.
Files changed (39) hide show
  1. package/.codex-plugin/plugin.json +6 -5
  2. package/.mcp.json +17 -0
  3. package/README.md +49 -11
  4. package/assets/mainsequence-mark.svg +453 -0
  5. package/build-info.json +3 -3
  6. package/dist/hosts/codexPresentation.js +1 -0
  7. package/dist/hosts/discovery.js +252 -0
  8. package/dist/hosts/messaging.js +63 -0
  9. package/dist/hosts/panel/panel.html +265 -0
  10. package/dist/hosts/workspace.js +107 -0
  11. package/dist/panel-server.js +223 -0
  12. package/dist/vendor/devtools/index.js +45 -1
  13. package/dist/vendor/devtools/package.json +1 -1
  14. package/dist/vendor/devtools/shared/accountScope.js +19 -0
  15. package/dist/vendor/devtools/shared/actions.js +44 -7
  16. package/dist/vendor/devtools/shared/agentAssets.js +38 -0
  17. package/dist/vendor/devtools/shared/agentDelivery.js +477 -0
  18. package/dist/vendor/devtools/shared/agentIcon.js +43 -0
  19. package/dist/vendor/devtools/shared/agents.js +18 -7
  20. package/dist/vendor/devtools/shared/arguments.js +16 -9
  21. package/dist/vendor/devtools/shared/deployments.js +214 -0
  22. package/dist/vendor/devtools/shared/environments.js +38 -0
  23. package/dist/vendor/devtools/shared/mcp.js +237 -46
  24. package/dist/vendor/devtools/shared/mcpTransport.js +79 -23
  25. package/dist/vendor/devtools/shared/organizationProjectWorkspace.js +8 -3
  26. package/dist/vendor/devtools/shared/organizationProjects.js +2 -13
  27. package/dist/vendor/devtools/shared/projectTools.js +437 -0
  28. package/dist/vendor/devtools/shared/repositories.js +2 -2
  29. package/dist/vendor/devtools/shared/session.js +133 -14
  30. package/dist/vendor/devtools/shared/sharedTransport.js +506 -0
  31. package/dist/vendor/devtools/shared/stateDirectory.js +44 -0
  32. package/dist/vendor/devtools/shared/workingDirectory.js +13 -0
  33. package/dist/vendor/devtools/shared/workspaceSettings.js +96 -0
  34. package/docs/agents-tools-panel.md +522 -0
  35. package/docs/codex-verification.md +37 -0
  36. package/docs/conversational-mcp.md +16 -3
  37. package/package.json +9 -5
  38. package/skills/mainsequence-mcp/SKILL.md +19 -4
  39. package/skills/ms/assets/mainsequence-mark.svg +453 -0
@@ -0,0 +1,506 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createSharedTransport = createSharedTransport;
37
+ /** Opt-in, per-user HTTP owner for desktop hosts with one process per chat.
38
+ * Credentials and cached responses stay in memory. The private Unix socket is
39
+ * local IPC, not a new login, backend, public listener, or autonomous poller.
40
+ */
41
+ const net = __importStar(require("node:net"));
42
+ const http = __importStar(require("node:http"));
43
+ const https = __importStar(require("node:https"));
44
+ const fs = __importStar(require("node:fs"));
45
+ const path = __importStar(require("node:path"));
46
+ const os = __importStar(require("node:os"));
47
+ const node_crypto_1 = require("node:crypto");
48
+ const node_child_process_1 = require("node:child_process");
49
+ const node_stream_1 = require("node:stream");
50
+ const mcpTransport_1 = require("./mcpTransport.js");
51
+ const PROTOCOL = 2, MAX_BYTES = 8_000_000, MAX_FRAME = 12_000_000;
52
+ const unavailable = () => new Error('Shared MainSequence transport disconnected. No request was replayed. Read the saved operation receipt before recovery.');
53
+ const hash = (input) => (0, node_crypto_1.createHash)('sha256').update(input).digest('hex');
54
+ function headerPairs(headers) { const pairs = []; headers.forEach((value, key) => pairs.push([key, value])); return pairs; }
55
+ function privateDirectory(directory) {
56
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
57
+ const stat = fs.lstatSync(directory);
58
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 0o077))
59
+ throw new Error('Shared transport requires a private directory owned by the current user.');
60
+ }
61
+ function frames(socket, receive) {
62
+ let buffer = '';
63
+ socket.setEncoding('utf8');
64
+ socket.on('data', chunk => {
65
+ buffer += chunk;
66
+ if (buffer.length > MAX_FRAME) {
67
+ socket.destroy();
68
+ return;
69
+ }
70
+ let end;
71
+ while ((end = buffer.indexOf('\n')) >= 0) {
72
+ const line = buffer.slice(0, end);
73
+ buffer = buffer.slice(end + 1);
74
+ try {
75
+ receive(JSON.parse(line));
76
+ }
77
+ catch {
78
+ socket.destroy();
79
+ return;
80
+ }
81
+ }
82
+ });
83
+ }
84
+ /** All participating processes share one owner. No fallback creates a private pool. */
85
+ function createSharedTransport(options = {}) {
86
+ if (process.platform === 'win32')
87
+ throw new Error('Shared MainSequence transport currently requires Unix-domain sockets.');
88
+ const directory = options.directory ?? path.join(os.tmpdir(), `ms-http-v${PROTOCOL}-${process.getuid()}-${hash(os.homedir()).slice(0, 12)}`);
89
+ const socketPath = path.join(directory, 'transport.sock');
90
+ // Capture the worker and its two internal dependencies now. Codex can remove
91
+ // this installation while a chat is alive; a later reconnect still works.
92
+ const modules = Object.fromEntries(['sharedTransport', 'mcpTransport', 'models'].map(name => [name, fs.readFileSync(path.join(__dirname, name + '.js'), 'utf8')]));
93
+ const workerSource = `const sources=${JSON.stringify(modules)},cache={};function load(name){if(cache[name])return cache[name].exports;const m={exports:{}};cache[name]=m;const r=id=>id.startsWith('./')?load(id.slice(2).replace(/\\.js$/,'')):require(id);r.main=name==='sharedTransport'?m:null;new Function('require','module','exports','__filename','__dirname',sources[name])(r,m,m.exports,'sharedTransport.js','.');return m.exports;}process.argv=['node','worker','--shared-http-worker',${JSON.stringify(directory)}];load('sharedTransport');`;
94
+ let socket, connecting, closed = false;
95
+ const pending = new Map();
96
+ async function connect() {
97
+ if (closed)
98
+ throw unavailable();
99
+ if (socket && !socket.destroyed)
100
+ return socket;
101
+ if (connecting)
102
+ return connecting;
103
+ connecting = (async () => {
104
+ privateDirectory(directory);
105
+ const attempt = () => new Promise((resolve, reject) => {
106
+ const next = net.createConnection(socketPath);
107
+ next.once('error', reject);
108
+ next.once('connect', () => { next.removeListener('error', reject); resolve(next); });
109
+ });
110
+ let next;
111
+ try {
112
+ next = await attempt();
113
+ }
114
+ catch {
115
+ // The worker takes an exclusive lock before listening; concurrent clients
116
+ // may start contenders but only one can own the upstream connection pool.
117
+ const worker = (0, node_child_process_1.spawn)(process.execPath, ['-'], { cwd: os.homedir(), detached: true, stdio: ['pipe', 'ignore', 'ignore'], env: { PATH: process.env.PATH, HOME: os.homedir() } });
118
+ worker.stdin.on('error', () => { });
119
+ worker.stdin.end(workerSource);
120
+ worker.on('error', () => { });
121
+ worker.unref();
122
+ for (let n = 0; n < 100 && !next; n++) {
123
+ await new Promise(resolve => setTimeout(resolve, 30));
124
+ try {
125
+ next = await attempt();
126
+ }
127
+ catch { /* startup, not an HTTP replay */ }
128
+ }
129
+ }
130
+ if (!next)
131
+ throw unavailable();
132
+ if (closed) {
133
+ next.destroy();
134
+ throw unavailable();
135
+ }
136
+ socket = next;
137
+ next.on('error', () => { });
138
+ next.on('close', () => { if (socket === next)
139
+ socket = undefined; for (const task of pending.values())
140
+ task.reject(unavailable()); pending.clear(); });
141
+ frames(next, message => {
142
+ const task = pending.get(message.id);
143
+ if (!task)
144
+ return;
145
+ pending.delete(message.id);
146
+ if (!pending.size)
147
+ next.unref();
148
+ if (message.error)
149
+ task.reject(new Error(message.error));
150
+ else
151
+ task.resolve(message.result);
152
+ });
153
+ next.unref();
154
+ return next;
155
+ })().finally(() => { connecting = undefined; });
156
+ return connecting;
157
+ }
158
+ async function rpc(op, request, signal) {
159
+ signal?.throwIfAborted();
160
+ const connection = await connect();
161
+ signal?.throwIfAborted();
162
+ const id = (0, node_crypto_1.randomUUID)();
163
+ return new Promise((resolve, reject) => {
164
+ const abort = () => { pending.delete(id); connection.write(JSON.stringify({ op: 'cancel', id }) + '\n'); if (!pending.size)
165
+ connection.unref(); reject(signal?.reason ?? unavailable()); };
166
+ pending.set(id, { resolve: value => { signal?.removeEventListener('abort', abort); resolve(value); }, reject: error => { signal?.removeEventListener('abort', abort); reject(error); } });
167
+ signal?.addEventListener('abort', abort, { once: true });
168
+ connection.ref();
169
+ connection.write(JSON.stringify({ id, op, request }) + '\n');
170
+ });
171
+ }
172
+ const transport = async (input, init = {}) => {
173
+ if (input instanceof Request || (init.body !== undefined && init.body !== null && typeof init.body !== 'string'))
174
+ throw new Error('Shared transport accepts URL requests with optional text bodies.');
175
+ const request = { url: String(input), method: init.method ?? 'GET', headers: headerPairs(new Headers(init.headers)),
176
+ ...(typeof init.body === 'string' ? { body: init.body } : {}), read: init.cache === 'force-cache', fresh: init.cache === 'reload' };
177
+ const value = await rpc('fetch', request, init.signal);
178
+ return new Response([204, 205, 304].includes(value.status) ? null : Buffer.from(value.body, 'base64'), { status: value.status, headers: value.headers });
179
+ };
180
+ const sessionLock = async (backend, run, signal) => {
181
+ const key = hash(backend), lease = await rpc('acquire', { key }, signal);
182
+ try {
183
+ signal?.throwIfAborted();
184
+ return await run();
185
+ }
186
+ finally {
187
+ await rpc('release', { key, lease }).catch(() => { });
188
+ }
189
+ };
190
+ return { fetch: transport, sessionLock, status: () => rpc('status'), invalidate: () => rpc('invalidate'), close() { closed = true; socket?.destroy(); } };
191
+ }
192
+ function cacheTtl(request) {
193
+ const url = new URL(request.url);
194
+ if (request.method === 'POST')
195
+ return request.read ? 30_000 : 0;
196
+ if (request.method !== 'GET')
197
+ return 0;
198
+ if (url.pathname === '/api/v1/users/me/')
199
+ return 5_000;
200
+ if (/^\/api\/v1\/command-center\/agents\/[a-f0-9-]+\/icon\/$/.test(url.pathname))
201
+ return 300_000;
202
+ if (/^\/api\/v1\/(organization-environments|command-center\/agents|code-repositories|code-repository-branches|organization-projects)\//.test(url.pathname))
203
+ return 30_000;
204
+ return 0;
205
+ }
206
+ function readKey(request) {
207
+ // IDs are transport correlation only; share reads and restore each caller's ID.
208
+ let body = request.body;
209
+ if (request.read && body) {
210
+ const value = JSON.parse(body);
211
+ delete value.id;
212
+ body = JSON.stringify(value);
213
+ }
214
+ return hash(JSON.stringify([request.url, request.method, [...request.headers].sort(), body]));
215
+ }
216
+ function responseFor(value, request) {
217
+ if (!request.read || !request.body || value.status !== 200)
218
+ return value;
219
+ const body = JSON.parse(request.body);
220
+ if (!Object.hasOwn(body, 'id'))
221
+ return value;
222
+ const response = JSON.parse(Buffer.from(value.body, 'base64').toString());
223
+ return { ...value, body: Buffer.from(JSON.stringify({ ...response, id: body.id })).toString('base64') };
224
+ }
225
+ async function runWorker(directory) {
226
+ privateDirectory(directory);
227
+ const lock = path.join(directory, 'owner.json'), socketPath = path.join(directory, 'transport.sock');
228
+ try {
229
+ fs.writeFileSync(lock, JSON.stringify({ pid: process.pid }), { flag: 'wx', mode: 0o600 });
230
+ }
231
+ catch {
232
+ try {
233
+ const owner = JSON.parse(fs.readFileSync(lock, 'utf8'));
234
+ process.kill(owner.pid, 0);
235
+ return;
236
+ }
237
+ catch (error) {
238
+ if (error.code !== 'ESRCH')
239
+ return;
240
+ // Serialize stale recovery too; never unlink another contender's new lock.
241
+ const recovery = path.join(directory, 'recover.lock');
242
+ let fd;
243
+ try {
244
+ fd = fs.openSync(recovery, 'wx', 0o600);
245
+ }
246
+ catch {
247
+ return;
248
+ }
249
+ try {
250
+ const owner = JSON.parse(fs.readFileSync(lock, 'utf8'));
251
+ try {
252
+ process.kill(owner.pid, 0);
253
+ return;
254
+ }
255
+ catch (e) {
256
+ if (e.code !== 'ESRCH')
257
+ return;
258
+ }
259
+ fs.unlinkSync(lock);
260
+ }
261
+ finally {
262
+ fs.closeSync(fd);
263
+ fs.unlinkSync(recovery);
264
+ }
265
+ return runWorker(directory);
266
+ }
267
+ }
268
+ const httpAgent = new http.Agent({ keepAlive: true, maxSockets: 2, maxTotalSockets: 8, maxFreeSockets: 2 });
269
+ const httpsAgent = new https.Agent({ keepAlive: true, maxSockets: 2, maxTotalSockets: 8, maxFreeSockets: 2 });
270
+ const sockets = new Set(), cache = new Map();
271
+ const jobs = new Map();
272
+ let epoch = 0, requests = 0, cacheHits = 0, coalesced = 0, bytes = 0;
273
+ const instanceId = (0, node_crypto_1.randomUUID)(), invalidate = () => { epoch++; cache.clear(); bytes = 0; };
274
+ const leases = new Map();
275
+ function grant(key) { const first = leases.get(key)?.[0]; if (first)
276
+ send(first.socket, first.id, first.token);
277
+ else
278
+ leases.delete(key); }
279
+ function releaseFor(socket, id) {
280
+ for (const [key, queue] of leases) {
281
+ const first = queue[0];
282
+ const keep = queue.filter(lease => lease.socket !== socket || id && lease.id !== id);
283
+ leases.set(key, keep);
284
+ if (keep[0] !== first)
285
+ grant(key);
286
+ }
287
+ }
288
+ const upstream = async (request, signal) => {
289
+ requests++;
290
+ const url = new URL(request.url);
291
+ const response = await new Promise((resolve, reject) => {
292
+ const call = (url.protocol === 'https:' ? https : http).request(url, { method: request.method, headers: Object.fromEntries(request.headers),
293
+ agent: url.protocol === 'https:' ? httpsAgent : httpAgent, signal, timeout: 300_000 }, result => {
294
+ const headers = new Headers();
295
+ for (const [key, value] of Object.entries(result.headers))
296
+ if (value !== undefined)
297
+ headers.set(key, Array.isArray(value) ? value.join(', ') : value);
298
+ resolve(new Response([204, 205, 304].includes(result.statusCode) ? null : node_stream_1.Readable.toWeb(result), { status: result.statusCode, headers }));
299
+ if ([204, 205, 304].includes(result.statusCode))
300
+ result.resume();
301
+ });
302
+ call.on('timeout', () => call.destroy(new Error('HTTP timeout')));
303
+ call.on('error', reject);
304
+ call.end(request.body);
305
+ });
306
+ const headers = headerPairs(response.headers);
307
+ if (request.method === 'POST' && /json|event-stream/.test(response.headers.get('content-type') ?? '') && request.body && response.ok) {
308
+ let message;
309
+ try {
310
+ message = JSON.parse(request.body);
311
+ }
312
+ catch { /* regular POST */ }
313
+ if (message?.jsonrpc === '2.0') {
314
+ const body = await (0, mcpTransport_1.readMcpResponse)(response, message);
315
+ return { status: response.status, headers: headers.filter(([key]) => !['content-type', 'content-length', 'content-encoding'].includes(key)).concat([['content-type', 'application/json']]), body: body === undefined ? '' : Buffer.from(JSON.stringify(body)).toString('base64') };
316
+ }
317
+ }
318
+ const reader = response.body?.getReader();
319
+ let size = 0;
320
+ const parts = [];
321
+ if (reader)
322
+ try {
323
+ while (true) {
324
+ const next = await reader.read();
325
+ if (next.done)
326
+ break;
327
+ size += next.value.length;
328
+ if (size > MAX_BYTES)
329
+ throw new Error('Response size exceeded');
330
+ parts.push(Buffer.from(next.value));
331
+ }
332
+ }
333
+ finally {
334
+ await reader.cancel().catch(() => { });
335
+ }
336
+ return { status: response.status, headers, body: Buffer.concat(parts).toString('base64') };
337
+ };
338
+ function send(socket, id, result, error) { if (!socket.destroyed)
339
+ socket.write(JSON.stringify({ id, ...(error ? { error } : { result }) }) + '\n'); }
340
+ const server = net.createServer(socket => {
341
+ sockets.add(socket);
342
+ const identity = (0, node_crypto_1.randomUUID)();
343
+ socket.on('error', () => { });
344
+ const detach = (id) => { for (const job of jobs.values()) {
345
+ for (const [key, listener] of job.listeners)
346
+ if (listener.socket === socket && (!id || listener.id === id))
347
+ job.listeners.delete(key);
348
+ if (!job.listeners.size)
349
+ job.controller.abort();
350
+ } };
351
+ socket.on('close', () => { sockets.delete(socket); detach(); releaseFor(socket); });
352
+ frames(socket, message => {
353
+ const id = message.id;
354
+ if (typeof id !== 'string' || id.length > 100) {
355
+ socket.destroy();
356
+ return;
357
+ }
358
+ if (message.op === 'cancel') {
359
+ detach(id);
360
+ releaseFor(socket, id);
361
+ return;
362
+ }
363
+ if (message.op === 'acquire' || message.op === 'release') {
364
+ const key = message.request?.key;
365
+ if (typeof key !== 'string' || !/^[a-f0-9]{64}$/.test(key)) {
366
+ socket.destroy();
367
+ return;
368
+ }
369
+ const queue = leases.get(key) || [];
370
+ if (message.op === 'acquire') {
371
+ if (queue.length >= 256) {
372
+ send(socket, id, undefined, 'Too many pending session operations.');
373
+ return;
374
+ }
375
+ queue.push({ socket, id, token: (0, node_crypto_1.randomUUID)() });
376
+ leases.set(key, queue);
377
+ if (queue.length === 1)
378
+ grant(key);
379
+ }
380
+ else {
381
+ if (queue[0]?.socket === socket && queue[0].token === message.request.lease) {
382
+ queue.shift();
383
+ grant(key);
384
+ }
385
+ send(socket, id);
386
+ }
387
+ return;
388
+ }
389
+ if (message.op === 'invalidate') {
390
+ invalidate();
391
+ send(socket, id);
392
+ return;
393
+ }
394
+ if (message.op === 'status') {
395
+ const count = (agent) => [...Object.values(agent.sockets), ...Object.values(agent.freeSockets)].reduce((sum, values) => sum + (values?.length || 0), 0);
396
+ send(socket, id, { protocol: PROTOCOL, instanceId, pid: process.pid, clients: sockets.size, requests, cacheHits, coalesced, active: jobs.size, connections: count(httpAgent) + count(httpsAgent), maxConnectionsPerOrigin: 2 });
397
+ return;
398
+ }
399
+ if (message.op !== 'fetch' || jobs.size >= 256) {
400
+ send(socket, id, undefined, 'Shared transport is busy or the operation is unsupported.');
401
+ return;
402
+ }
403
+ const request = message.request;
404
+ let url;
405
+ try {
406
+ url = new URL(request.url);
407
+ }
408
+ catch {
409
+ socket.destroy();
410
+ return;
411
+ }
412
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || !['GET', 'POST'].includes(request.method) || !Array.isArray(request.headers) || (request.body && Buffer.byteLength(request.body) > 1_000_000)) {
413
+ socket.destroy();
414
+ return;
415
+ }
416
+ const renewal = request.method === 'POST' && url.pathname === '/auth/jwt-token/token/refresh/';
417
+ const read = request.method === 'GET' || request.read || renewal, key = read ? readKey(request) : (0, node_crypto_1.randomUUID)();
418
+ if (!read || request.fresh)
419
+ invalidate();
420
+ const flightKey = epoch + ':' + key;
421
+ const found = cache.get(key);
422
+ if (found && found.until > Date.now()) {
423
+ cacheHits++;
424
+ send(socket, id, responseFor(found.value, request));
425
+ return;
426
+ }
427
+ if (found) {
428
+ bytes -= found.value.body.length;
429
+ cache.delete(key);
430
+ }
431
+ let job = jobs.get(flightKey);
432
+ if (job?.controller.signal.aborted)
433
+ job = undefined;
434
+ if (job)
435
+ coalesced++;
436
+ else {
437
+ const controller = new AbortController(), startedEpoch = epoch;
438
+ job = { controller, listeners: new Map(), promise: upstream(request, controller.signal) };
439
+ jobs.set(flightKey, job);
440
+ const owned = job;
441
+ void owned.promise.then(value => {
442
+ if (!read || value.status === 401 || value.status === 403)
443
+ invalidate();
444
+ let ttl = cacheTtl(request);
445
+ const auth = request.headers.find(([name]) => name === 'authorization')?.[1];
446
+ try {
447
+ const exp = JSON.parse(Buffer.from(auth.split('.')[1], 'base64url').toString()).exp;
448
+ if (typeof exp === 'number')
449
+ ttl = Math.min(ttl, exp * 1000 - Date.now() - 5000);
450
+ }
451
+ catch { /* opaque token: bounded TTL */ }
452
+ let success = value.status >= 200 && value.status < 300;
453
+ if (request.read && value.body) {
454
+ try {
455
+ const result = JSON.parse(Buffer.from(value.body, 'base64').toString());
456
+ success = success && !result.error && !result.result?.isError;
457
+ }
458
+ catch {
459
+ success = false;
460
+ }
461
+ }
462
+ if (success && ttl > 0 && epoch === startedEpoch && !controller.signal.aborted) {
463
+ while (cache.size >= 256 || bytes + value.body.length > 24_000_000) {
464
+ const oldest = cache.keys().next().value;
465
+ if (!oldest)
466
+ break;
467
+ bytes -= cache.get(oldest).value.body.length;
468
+ cache.delete(oldest);
469
+ }
470
+ cache.set(key, { value, until: Date.now() + ttl, epoch });
471
+ bytes += value.body.length;
472
+ }
473
+ for (const listener of owned.listeners.values())
474
+ send(listener.socket, listener.id, responseFor(value, listener.request));
475
+ }, () => { if (!read)
476
+ invalidate(); for (const listener of owned.listeners.values())
477
+ send(listener.socket, listener.id, undefined, 'MainSequence HTTP request failed. It was not replayed.'); }).finally(() => { if (jobs.get(flightKey) === owned)
478
+ jobs.delete(flightKey); });
479
+ }
480
+ job.listeners.set(identity + id, { socket, id, request });
481
+ });
482
+ });
483
+ const cleanup = () => { for (const job of jobs.values())
484
+ job.controller.abort(); httpAgent.destroy(); httpsAgent.destroy(); server.close(); try {
485
+ fs.unlinkSync(socketPath);
486
+ fs.unlinkSync(lock);
487
+ }
488
+ catch { /* already cleaned */ } };
489
+ for (const signal of ['SIGINT', 'SIGTERM'])
490
+ process.once(signal, () => { cleanup(); process.exit(0); });
491
+ try {
492
+ fs.unlinkSync(socketPath);
493
+ }
494
+ catch { /* first launch */ }
495
+ server.on('error', () => { cleanup(); process.exitCode = 1; });
496
+ server.listen(socketPath, () => fs.chmodSync(socketPath, 0o600));
497
+ let idleSince = Date.now();
498
+ setInterval(() => { if (sockets.size || jobs.size)
499
+ idleSince = Date.now();
500
+ else if (Date.now() - idleSince > 30_000) {
501
+ cleanup();
502
+ process.exit(0);
503
+ } }, 1000).unref();
504
+ }
505
+ if (require.main === module && process.argv[2] === '--shared-http-worker')
506
+ void runWorker(process.argv[3]).catch(() => { process.exitCode = 1; });
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.mainSequenceStateDirectory = mainSequenceStateDirectory;
37
+ const os = __importStar(require("node:os"));
38
+ const path = __importStar(require("node:path"));
39
+ /** The one place that knows where shared MainSequence CLI state lives: the SDKs' configuration,
40
+ * the saved MCP connections and the project tool catalog (ADR 0004). */
41
+ function mainSequenceStateDirectory(env = process.env, home = os.homedir()) {
42
+ return process.platform === 'darwin' ? path.join(home, 'Library', 'Application Support', 'MainSequenceCLI')
43
+ : process.platform === 'win32' ? path.join(env.APPDATA || home, 'MainSequenceCLI') : path.join(home, '.config', 'mainsequence');
44
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.currentDirectory = currentDirectory;
4
+ const models_1 = require("./models.js");
5
+ /** Only consult the working directory for actions that actually need a project. */
6
+ function currentDirectory() {
7
+ try {
8
+ return process.cwd();
9
+ }
10
+ catch {
11
+ throw new models_1.ToolingError('CURRENT_DIRECTORY_UNAVAILABLE', 'The working directory is no longer available. Change to an existing directory or reload the plugin host; for MCP actions, pass an explicit backend.');
12
+ }
13
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.readDesktopPreferences = readDesktopPreferences;
37
+ exports.writeWorkspacePreferences = writeWorkspacePreferences;
38
+ const fs = __importStar(require("node:fs/promises"));
39
+ const path = __importStar(require("node:path"));
40
+ const os = __importStar(require("node:os"));
41
+ const node_crypto_1 = require("node:crypto");
42
+ const models_1 = require("./models.js");
43
+ const session_1 = require("./session.js");
44
+ const repositories_1 = require("./repositories.js");
45
+ function location(options) {
46
+ const home = options.homeDir ?? os.homedir(), env = options.env ?? process.env;
47
+ return options.configPath ?? path.join(process.platform === 'darwin' ? path.join(home, 'Library', 'Application Support', 'MainSequenceCLI') : process.platform === 'win32' ? path.join(env.APPDATA || home, 'MainSequenceCLI') : path.join(home, '.config', 'mainsequence'), 'config.json');
48
+ }
49
+ async function read(file) {
50
+ try {
51
+ const stat = await fs.lstat(file);
52
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1000000)
53
+ throw Error();
54
+ const value = JSON.parse(await fs.readFile(file, 'utf8'));
55
+ if (!value || Array.isArray(value) || typeof value !== 'object')
56
+ throw Error();
57
+ return value;
58
+ }
59
+ catch (e) {
60
+ if (e.code === 'ENOENT')
61
+ return {};
62
+ throw new models_1.ToolingError('STORE_ERROR', 'Workspace settings could not be read safely. Existing settings were preserved.');
63
+ }
64
+ }
65
+ async function readDesktopPreferences(options = {}) {
66
+ const config = await read(location(options));
67
+ return { ...await (0, repositories_1.readWorkspacePreferences)(options), commandCenterUrl: typeof config.command_center_url === 'string' ? config.command_center_url : '' };
68
+ }
69
+ /** Updates only non-secret workspace fields, preserving existing CLI settings. */
70
+ async function writeWorkspacePreferences(input, options = {}) {
71
+ const backend = (0, session_1.requireBackend)(input.backend);
72
+ if (!path.isAbsolute(input.baseDir) || /[\0\r\n]/.test(input.baseDir))
73
+ throw new models_1.ToolingError('INVALID_REQUEST', 'Repositories folder must be an absolute path.');
74
+ const commandCenterUrl = input.commandCenterUrl ? (0, session_1.requireBackend)(input.commandCenterUrl) : '';
75
+ const file = location(options);
76
+ await fs.mkdir(path.dirname(file), { recursive: true });
77
+ let lock;
78
+ try {
79
+ lock = await fs.open(file + '.preferences.lock', 'wx', 0o600);
80
+ }
81
+ catch {
82
+ throw new models_1.ToolingError('PROJECT_BUSY', 'Another settings update is in progress. Try again after it finishes.');
83
+ }
84
+ const temporary = file + '.' + (0, node_crypto_1.randomUUID)() + '.tmp';
85
+ try {
86
+ const config = await read(file);
87
+ await fs.writeFile(temporary, JSON.stringify({ ...config, backend_url: backend, mainsequence_path: path.resolve(input.baseDir), command_center_url: commandCenterUrl }, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
88
+ await fs.rename(temporary, file);
89
+ return readDesktopPreferences(options);
90
+ }
91
+ finally {
92
+ await fs.rm(temporary, { force: true });
93
+ await lock.close();
94
+ await fs.unlink(file + '.preferences.lock');
95
+ }
96
+ }