@ai-matrx/coding-sessions 0.1.85 → 0.1.86

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.
@@ -1,4 +1,5 @@
1
- import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-DEPwyr2j.cjs';
1
+ import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-aavbdzSo.cjs';
2
+ export { e as CodingSessionsAgentsOptions } from '../index-aavbdzSo.cjs';
2
3
  import '@ai-matrx/agents/portable';
3
4
  import '@ai-matrx/data';
4
5
  import '@ai-matrx/agents/portable/mcp';
@@ -1,4 +1,5 @@
1
- import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-DEPwyr2j.js';
1
+ import { C as CodingSessionsMethod, a as CodingSessionsApi, b as CodingEvent, c as CodingSessionsEngine, d as CodingSessionsEngineOptions } from '../index-aavbdzSo.js';
2
+ export { e as CodingSessionsAgentsOptions } from '../index-aavbdzSo.js';
2
3
  import '@ai-matrx/agents/portable';
3
4
  import '@ai-matrx/data';
4
5
  import '@ai-matrx/agents/portable/mcp';
@@ -73,6 +73,22 @@ function createRawBackupScheduler(options) {
73
73
  // src/engine/agent-attach.ts
74
74
  import fs2 from "fs/promises";
75
75
  import path from "path";
76
+
77
+ // src/normalize/agent-block.ts
78
+ var AGENT_BLOCK_MARKER = "<ai_matrx_agent ";
79
+ function stripAgentBlock(text) {
80
+ const removed = text.match(/^<ai_matrx_agent_removed>[\s\S]*?<\/ai_matrx_agent_removed>\s*/);
81
+ if (removed) return text.slice(removed[0].length);
82
+ if (!text.startsWith(AGENT_BLOCK_MARKER)) return text;
83
+ const end = text.indexOf("</ai_matrx_agent>");
84
+ if (end < 0) return text;
85
+ let rest = text.slice(end + "</ai_matrx_agent>".length);
86
+ const skills = rest.match(/^\s*<skills_instructions>[\s\S]*?<\/skills_instructions>/);
87
+ if (skills) rest = rest.slice(skills[0].length);
88
+ return rest.replace(/^\s+/, "");
89
+ }
90
+
91
+ // src/engine/agent-attach.ts
76
92
  var AGENT_MCP_SERVER_NAME = "matrx-agent";
77
93
  var AGENT_PLUGIN_NAME = "matrx-agent";
78
94
  function escapeAttr(value) {
@@ -123,6 +139,17 @@ function renderCodexSkillsList(bundle, skillsRoot) {
123
139
  ];
124
140
  return lines.join("\n");
125
141
  }
142
+ function renderFallbackBlock(bundle, skillsRoot) {
143
+ const skills = renderCodexSkillsList(bundle, skillsRoot);
144
+ const body = renderAgentInstructions(bundle).trim().replace(/^(<ai_matrx_agent [^>]*>)/, "$1\n\nThe instructions below are your AI Matrx agent for this chat from now on; they replace any AI Matrx agent instructions given earlier.");
145
+ return skills ? `${body}
146
+
147
+ ${skills}
148
+
149
+ ` : `${body}
150
+
151
+ `;
152
+ }
126
153
  function tomlString(value) {
127
154
  const scalar = value.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
128
155
  return JSON.stringify(scalar).replace(/\u007f/g, "\\u007f");
@@ -238,16 +265,37 @@ function sessionAgentRecord(bundle, options) {
238
265
  name: bundle.name,
239
266
  definitionHash: bundle.definition_hash,
240
267
  loaded,
241
- unavailable
268
+ unavailable,
269
+ skills: bundle.skills.map((skill) => skill.label),
270
+ tools: options.toolsServed ? bundle.tools.map((tool) => tool.canonical_name) : [],
271
+ ...options.variables ? { variables: options.variables } : {}
242
272
  };
243
273
  }
274
+ var AGENT_REMOVED_BLOCK = "<ai_matrx_agent_removed>The AI Matrx agent instructions given earlier in this chat no longer apply.</ai_matrx_agent_removed>\n\n";
275
+ async function codexCompactionDroppedAgent(rolloutFile, sinceIso) {
276
+ const text = await fs2.readFile(rolloutFile, "utf8").catch(() => "");
277
+ if (!text.includes('"type":"compacted"')) return false;
278
+ let latest = null;
279
+ for (const line of text.split("\n")) {
280
+ if (!line.includes('"type":"compacted"')) continue;
281
+ try {
282
+ const entry = JSON.parse(line);
283
+ if (entry.type === "compacted") latest = entry;
284
+ } catch {
285
+ }
286
+ }
287
+ if (!latest) return false;
288
+ if (sinceIso && latest.timestamp && latest.timestamp <= sinceIso) return false;
289
+ return !JSON.stringify(latest.payload?.replacement_history ?? "").includes(AGENT_BLOCK_MARKER.trim());
290
+ }
244
291
 
245
292
  // src/engine/agents.ts
246
- import { randomBytes, randomUUID } from "crypto";
293
+ import { createHash as createHash2, randomBytes, randomUUID } from "crypto";
247
294
  import fs3 from "fs/promises";
248
295
  import path2 from "path";
249
296
  var DEFAULT_SERVER_URL = "https://server.app.matrxserver.com";
250
297
  var DEFAULT_SUPABASE_URL = "https://db.matrxserver.com";
298
+ var DEFAULT_SUPABASE_KEY = "sb_publishable_scm0jzEJiFUB5ItiqOx5Fg_8BOjB6oA";
251
299
  var AGENT_CATALOG_RPCS = /* @__PURE__ */ new Set([
252
300
  "agx_get_list_full",
253
301
  "agx_search",
@@ -265,6 +313,10 @@ var agentsClient = async () => {
265
313
  ]);
266
314
  return { ...matrx, ...portable, ...mcp };
267
315
  };
316
+ function sortedValues(values) {
317
+ return Object.keys(values).sort().map((key) => [key, values[key]]);
318
+ }
319
+ var BUNDLE_CACHE_MS = 24 * 60 * 60 * 1e3;
268
320
  var SIGNED_OUT_AGENT_MESSAGE = "Sign in to AI Matrx to use your agents.";
269
321
  function userIdOf(credential) {
270
322
  if (!credential || credential.kind !== "user") return null;
@@ -281,21 +333,26 @@ function createAgentConnection(options, dataDir) {
281
333
  const credentials = options?.credentials ?? null;
282
334
  const serverUrl = (options?.serverUrl ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
283
335
  const supabaseUrl = (options?.supabaseUrl ?? DEFAULT_SUPABASE_URL).replace(/\/+$/, "");
284
- const supabaseKey = options?.supabaseKey ?? null;
336
+ const supabaseKey = options?.supabaseKey ?? (options?.supabaseUrl ? null : DEFAULT_SUPABASE_KEY);
285
337
  const root = path2.join(dataDir, "agents");
286
338
  let mcpBaseUrl = null;
287
339
  const handlers = /* @__PURE__ */ new Map();
288
340
  const secretToSession = /* @__PURE__ */ new Map();
289
- const organizationId = () => {
290
- const raw = typeof options?.organizationId === "function" ? options.organizationId() : options?.organizationId;
341
+ const organizationId = async () => {
342
+ const raw = typeof options?.organizationId === "function" ? await options.organizationId() : options?.organizationId;
291
343
  return raw && raw.trim() ? raw.trim() : null;
292
344
  };
293
- const transport = async () => (await agentsClient()).createMatrxTransport({
294
- baseUrl: serverUrl,
295
- ...credentials ? { credentials } : {},
296
- ...organizationId() ? { organizationId: () => organizationId() } : {},
297
- source: "codingSessionsAgents"
298
- });
345
+ const transport = async () => {
346
+ const org = await organizationId();
347
+ return (await agentsClient()).createMatrxTransport({
348
+ baseUrl: serverUrl,
349
+ ...credentials ? { credentials } : {},
350
+ ...org ? { organizationId: org } : {},
351
+ source: "codingSessionsAgents"
352
+ });
353
+ };
354
+ const cacheDir = path2.join(dataDir, "agents", ".bundles");
355
+ const cacheKey = (definitionHash, selection, surface) => createHash2("sha256").update(JSON.stringify([definitionHash, sortedValues(selection.variables ?? {}), surface])).digest("hex");
299
356
  const credential = async () => credentials ? credentials.get() : null;
300
357
  const requireSignedIn = async () => {
301
358
  if (!await credential()) throw new Error(SIGNED_OUT_AGENT_MESSAGE);
@@ -331,7 +388,7 @@ function createAgentConnection(options, dataDir) {
331
388
  configured: credentials !== null && supabaseKey !== null,
332
389
  signedIn: userId !== null,
333
390
  userId,
334
- organizationId: organizationId()
391
+ organizationId: await organizationId().catch(() => null)
335
392
  };
336
393
  },
337
394
  async catalogRpc(request) {
@@ -378,27 +435,39 @@ function createAgentConnection(options, dataDir) {
378
435
  },
379
436
  async details(agentId) {
380
437
  await requireSignedIn();
381
- const { fetchPortableAgent, fetchPortableAgentVersions } = await agentsClient();
382
- const [bundle, versions] = await Promise.all([
383
- fetchPortableAgent(await transport(), { agentId }),
384
- fetchPortableAgentVersions(await transport(), agentId).catch(() => [])
385
- ]);
438
+ const summary = await (await agentsClient()).fetchPortableAgentSummary(await transport(), agentId);
386
439
  return {
387
- agentId: bundle.agent_id,
388
- name: bundle.name,
389
- variables: bundle.variables,
390
- versions: versions.map((v) => ({ id: v.id, versionNumber: v.version_number, changedAt: v.changed_at })).sort((a, b) => b.versionNumber - a.versionNumber),
391
- latestVersionNumber: bundle.version_number
440
+ agentId: summary.agent_id,
441
+ name: summary.name,
442
+ variables: summary.variables,
443
+ versions: summary.versions.map((v) => ({ id: v.id, versionNumber: v.version_number, changedAt: v.changed_at })),
444
+ latestVersionNumber: summary.version_number,
445
+ latestVersionId: summary.version_id
392
446
  };
393
447
  },
394
448
  async loadBundle(selection) {
395
449
  await requireSignedIn();
396
- const { fetchPortableAgent } = await agentsClient();
397
- return fetchPortableAgent(
450
+ const client = await agentsClient();
451
+ const summary = await client.fetchPortableAgentSummary(await transport(), selection.agentId);
452
+ const versionId = selection.versionId ?? summary.version_id;
453
+ const definitionHash = versionId ? summary.versions.find((v) => v.id === versionId)?.definition_hash ?? null : summary.definition_hash;
454
+ const surface = "matrx-user/code-editor";
455
+ const file = definitionHash ? path2.join(cacheDir, `${cacheKey(definitionHash, selection, surface)}.json`) : null;
456
+ if (file) {
457
+ const cached = await fs3.readFile(file, "utf8").then((text) => JSON.parse(text)).catch(() => null);
458
+ const fresh = await fs3.stat(file).then((st) => Date.now() - st.mtimeMs < BUNDLE_CACHE_MS).catch(() => false);
459
+ if (cached && fresh && cached.definition_hash === definitionHash) return cached;
460
+ }
461
+ const bundle = await client.fetchPortableAgent(
398
462
  await transport(),
399
- selection.versionId ? { versionId: selection.versionId } : { agentId: selection.agentId },
400
- { variables: selection.variables ?? {} }
463
+ versionId ? { versionId } : { agentId: selection.agentId },
464
+ { variables: selection.variables ?? {}, surface }
401
465
  );
466
+ if (file && bundle.definition_hash === definitionHash) {
467
+ await fs3.mkdir(cacheDir, { recursive: true, mode: 448 });
468
+ await fs3.writeFile(file, JSON.stringify(bundle), { mode: 384 });
469
+ }
470
+ return bundle;
402
471
  },
403
472
  async saveSessionBundle(sessionId, bundle) {
404
473
  await fs3.mkdir(sessionDir(sessionId), { recursive: true, mode: 448 });
@@ -813,7 +882,7 @@ function rolloutItem(item, fallbackId, at) {
813
882
  const id = str2(item.id) ?? fallbackId;
814
883
  switch (item.type) {
815
884
  case "UserMessage": {
816
- const text = stripCodexInjectedContext(itemText(item.content));
885
+ const text = stripCodexInjectedContext(stripAgentBlock(itemText(item.content)));
817
886
  return text.trim() ? [{ kind: "user", id, text, at }] : [];
818
887
  }
819
888
  case "AgentMessage": {
@@ -896,7 +965,7 @@ function createCodexRolloutNormalizer() {
896
965
  return rolloutItem(payload.item, fallbackId, at);
897
966
  }
898
967
  if (payload.type === "user_message" && !appItems) {
899
- const text = stripCodexInjectedContext(str2(payload.message) ?? "");
968
+ const text = stripCodexInjectedContext(stripAgentBlock(str2(payload.message) ?? ""));
900
969
  return text.trim() ? [{ kind: "user", id: fallbackId, text, at }] : [];
901
970
  }
902
971
  return [];
@@ -2374,6 +2443,12 @@ async function createCodingSessionsEngine(options = {}) {
2374
2443
  if (file) fileOffset = (await fs8.stat(file).catch(() => null))?.size ?? null;
2375
2444
  }
2376
2445
  let agentArgs = [];
2446
+ let cliPrompt = prompt;
2447
+ let delivered = null;
2448
+ if (!session.agent && session.agentRemovedDue) {
2449
+ if (provider === "codex") cliPrompt = `${AGENT_REMOVED_BLOCK}${prompt}`;
2450
+ delivered = { agentRemovedDue: false };
2451
+ }
2377
2452
  if (session.agent) {
2378
2453
  const bundle = await agents.readSessionBundle(session.id);
2379
2454
  if (!bundle) {
@@ -2391,6 +2466,10 @@ async function createCodingSessionsEngine(options = {}) {
2391
2466
  mcpUrl: await agents.mcpUrlFor(session.id)
2392
2467
  });
2393
2468
  agentArgs = agentArgsFor(provider, attachment, { resuming: session.providerSessionId !== null });
2469
+ if (provider === "codex" && session.agent.blockDue) {
2470
+ cliPrompt = `${renderFallbackBlock(bundle, path9.join(attachment.dir, "skills"))}${prompt}`;
2471
+ }
2472
+ delivered = { agent: { ...session.agent, blockDue: false, deliveredAt: run.startedAt } };
2394
2473
  }
2395
2474
  const child = forkWorker();
2396
2475
  const liveRun = {
@@ -2406,6 +2485,10 @@ async function createCodingSessionsEngine(options = {}) {
2406
2485
  };
2407
2486
  live.set(runId, liveRun);
2408
2487
  emitItem(liveRun, { kind: "user", id: `run-${runId}`, text: prompt, at: run.startedAt });
2488
+ if (delivered) {
2489
+ const current = index.session(session.id);
2490
+ if (current) saveSession({ ...current, ...delivered });
2491
+ }
2409
2492
  const splitter = createLineSplitter();
2410
2493
  const claude = provider === "claude" ? createClaudeNormalizer() : null;
2411
2494
  const codex = provider === "codex" ? createCodexStreamNormalizer(runId.slice(0, 8)) : null;
@@ -2444,6 +2527,7 @@ async function createCodingSessionsEngine(options = {}) {
2444
2527
  }
2445
2528
  }
2446
2529
  void pruneDriverScratch();
2530
+ if (provider === "codex" && final.status === "completed") void checkCompaction(session.id);
2447
2531
  };
2448
2532
  let settled = false;
2449
2533
  child.on("message", (raw) => {
@@ -2558,7 +2642,7 @@ async function createCodingSessionsEngine(options = {}) {
2558
2642
  provider,
2559
2643
  runId,
2560
2644
  cwd: session.cwd,
2561
- prompt,
2645
+ prompt: cliPrompt,
2562
2646
  model,
2563
2647
  effort: session.effort ?? null,
2564
2648
  resumeSessionId: session.providerSessionId,
@@ -2569,6 +2653,28 @@ async function createCodingSessionsEngine(options = {}) {
2569
2653
  });
2570
2654
  return run;
2571
2655
  }
2656
+ async function checkCompaction(sessionId) {
2657
+ const session = index.session(sessionId);
2658
+ if (!session?.agent || session.agent.blockDue || !session.providerSessionId) return;
2659
+ const file = await findSessionFile("codex", session.providerSessionId, homes);
2660
+ if (!file || !await codexCompactionDroppedAgent(file, session.agent.deliveredAt ?? null)) return;
2661
+ const current = index.session(sessionId);
2662
+ if (current?.agent) {
2663
+ saveSession({ ...current, agent: { ...current.agent, blockDue: true } });
2664
+ }
2665
+ }
2666
+ async function attachAgent(sessionId, selection, options2) {
2667
+ const bundle = await agents.loadBundle(selection);
2668
+ await agents.saveSessionBundle(sessionId, bundle);
2669
+ return {
2670
+ ...sessionAgentRecord(bundle, {
2671
+ toolsServed: await agents.mcpUrlFor(sessionId) !== null,
2672
+ variables: selection.variables ?? {}
2673
+ }),
2674
+ blockDue: options2.blockDue,
2675
+ deliveredAt: null
2676
+ };
2677
+ }
2572
2678
  function killGroup(liveRun) {
2573
2679
  const target = liveRun.pgid;
2574
2680
  if (target === null) return;
@@ -2825,7 +2931,6 @@ async function createCodingSessionsEngine(options = {}) {
2825
2931
  const prompt = input.prompt.trim();
2826
2932
  if (!prompt) throw new Error("Type what you want done before starting.");
2827
2933
  const cwd = await assertFolder(input.cwd);
2828
- const bundle = input.agent ? await agents.loadBundle(input.agent) : null;
2829
2934
  const draft = newSession({
2830
2935
  provider: input.provider,
2831
2936
  cwd,
@@ -2835,28 +2940,40 @@ async function createCodingSessionsEngine(options = {}) {
2835
2940
  origin: "started",
2836
2941
  providerSessionId: null
2837
2942
  });
2838
- if (bundle) {
2839
- await agents.saveSessionBundle(draft.id, bundle);
2840
- draft.agent = sessionAgentRecord(bundle, { toolsServed: await agents.mcpUrlFor(draft.id) !== null });
2841
- }
2943
+ if (input.agent) draft.agent = await attachAgent(draft.id, input.agent, { blockDue: false });
2842
2944
  const session = saveSession(draft);
2843
2945
  const run = await startRun(session, prompt);
2844
2946
  return { session: index.session(session.id) ?? session, run, queued: false };
2845
2947
  },
2846
2948
  async takeover(input) {
2847
2949
  const existing = index.session(input.providerSessionId);
2848
- if (existing) return existing;
2950
+ if (existing) {
2951
+ if (!input.agent) return existing;
2952
+ return engine.setAgent(existing.id, input.agent);
2953
+ }
2849
2954
  const cwd = await assertFolder(input.cwd);
2850
- return saveSession(
2851
- newSession({
2852
- provider: input.provider,
2853
- cwd,
2854
- title: input.title?.trim() || "Taken-over chat",
2855
- model: null,
2856
- origin: "takeover",
2857
- providerSessionId: input.providerSessionId
2858
- })
2859
- );
2955
+ const draft = newSession({
2956
+ provider: input.provider,
2957
+ cwd,
2958
+ title: input.title?.trim() || "Taken-over chat",
2959
+ model: null,
2960
+ origin: "takeover",
2961
+ providerSessionId: input.providerSessionId
2962
+ });
2963
+ if (input.agent) draft.agent = await attachAgent(draft.id, input.agent, { blockDue: input.provider === "codex" });
2964
+ return saveSession(draft);
2965
+ },
2966
+ async setAgent(sessionId, selection) {
2967
+ const session = index.session(String(sessionId ?? ""));
2968
+ if (!session) throw new Error("This session is not in the list anymore.");
2969
+ if (!selection) {
2970
+ const told = session.provider === "codex" && session.agent?.deliveredAt != null;
2971
+ return saveSession({ ...session, agent: null, agentRemovedDue: told });
2972
+ }
2973
+ const agent = await attachAgent(session.id, selection, {
2974
+ blockDue: session.provider === "codex" && session.providerSessionId !== null
2975
+ });
2976
+ return saveSession({ ...session, agent, agentRemovedDue: false });
2860
2977
  },
2861
2978
  async send(sessionId, rawPrompt) {
2862
2979
  const prompt = rawPrompt.trim();
@@ -2995,7 +3112,8 @@ var BRIDGE_METHODS = [
2995
3112
  "setSessionOptions",
2996
3113
  "agentAccess",
2997
3114
  "agentCatalogRpc",
2998
- "agentDetails"
3115
+ "agentDetails",
3116
+ "setAgent"
2999
3117
  ];
3000
3118
  var BridgeError = class extends Error {
3001
3119
  constructor(message, code) {