@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,4 @@
1
- export { c as CodingSessionsEngine, d as CodingSessionsEngineOptions, E as EFFORT_LEVELS, P as PreferenceStore, e as ProviderHomes, R as RAW_TRANSCRIPT_MAX_BYTES, f as RawBackupPolicy, g as RawBackupSink, h as RunStatus, i as buildCleanEnv, j as claudeDefaults, k as codexDefaults, l as createAiMatrxRawBackupSink, m as createCodingSessionsEngine, n as createRawBackupScheduler, o as defaultProviderHomes, p as describeActivity, q as describeProviderStatus, r as discoverLocalSessions, s as endsWithOpenToolCall, t as findDrivingProcess, u as findSessionFile, v as isAllowedEnvName, w as listProcesses, x as readSessionFile, y as searchLocalChats, z as sessionActivity, A as snippetAround } from '../index-DEPwyr2j.cjs';
1
+ export { e as CodingSessionsAgentsOptions, c as CodingSessionsEngine, d as CodingSessionsEngineOptions, D as DEFAULT_SERVER_URL, f as DEFAULT_SUPABASE_URL, E as EFFORT_LEVELS, P as PreferenceStore, g as ProviderHomes, R as RAW_TRANSCRIPT_MAX_BYTES, h as RawBackupPolicy, i as RawBackupSink, j as RunStatus, k as buildCleanEnv, l as claudeDefaults, m as codexDefaults, n as createAiMatrxRawBackupSink, o as createCodingSessionsEngine, p as createRawBackupScheduler, q as defaultProviderHomes, r as describeActivity, s as describeProviderStatus, t as discoverLocalSessions, u as endsWithOpenToolCall, v as findDrivingProcess, w as findSessionFile, x as isAllowedEnvName, y as listProcesses, z as readSessionFile, A as searchLocalChats, B as sessionActivity, F as snippetAround } from '../index-aavbdzSo.cjs';
2
2
  import '@ai-matrx/agents/portable/mcp';
3
3
  import '@ai-matrx/agents/portable';
4
4
  import '@ai-matrx/data';
@@ -1,4 +1,4 @@
1
- export { c as CodingSessionsEngine, d as CodingSessionsEngineOptions, E as EFFORT_LEVELS, P as PreferenceStore, e as ProviderHomes, R as RAW_TRANSCRIPT_MAX_BYTES, f as RawBackupPolicy, g as RawBackupSink, h as RunStatus, i as buildCleanEnv, j as claudeDefaults, k as codexDefaults, l as createAiMatrxRawBackupSink, m as createCodingSessionsEngine, n as createRawBackupScheduler, o as defaultProviderHomes, p as describeActivity, q as describeProviderStatus, r as discoverLocalSessions, s as endsWithOpenToolCall, t as findDrivingProcess, u as findSessionFile, v as isAllowedEnvName, w as listProcesses, x as readSessionFile, y as searchLocalChats, z as sessionActivity, A as snippetAround } from '../index-DEPwyr2j.js';
1
+ export { e as CodingSessionsAgentsOptions, c as CodingSessionsEngine, d as CodingSessionsEngineOptions, D as DEFAULT_SERVER_URL, f as DEFAULT_SUPABASE_URL, E as EFFORT_LEVELS, P as PreferenceStore, g as ProviderHomes, R as RAW_TRANSCRIPT_MAX_BYTES, h as RawBackupPolicy, i as RawBackupSink, j as RunStatus, k as buildCleanEnv, l as claudeDefaults, m as codexDefaults, n as createAiMatrxRawBackupSink, o as createCodingSessionsEngine, p as createRawBackupScheduler, q as defaultProviderHomes, r as describeActivity, s as describeProviderStatus, t as discoverLocalSessions, u as endsWithOpenToolCall, v as findDrivingProcess, w as findSessionFile, x as isAllowedEnvName, y as listProcesses, z as readSessionFile, A as searchLocalChats, B as sessionActivity, F as snippetAround } from '../index-aavbdzSo.js';
2
2
  import '@ai-matrx/agents/portable/mcp';
3
3
  import '@ai-matrx/agents/portable';
4
4
  import '@ai-matrx/data';
@@ -101,6 +101,22 @@ function createAiMatrxRawBackupSink(options) {
101
101
  // src/engine/agent-attach.ts
102
102
  import fs2 from "fs/promises";
103
103
  import path from "path";
104
+
105
+ // src/normalize/agent-block.ts
106
+ var AGENT_BLOCK_MARKER = "<ai_matrx_agent ";
107
+ function stripAgentBlock(text) {
108
+ const removed = text.match(/^<ai_matrx_agent_removed>[\s\S]*?<\/ai_matrx_agent_removed>\s*/);
109
+ if (removed) return text.slice(removed[0].length);
110
+ if (!text.startsWith(AGENT_BLOCK_MARKER)) return text;
111
+ const end = text.indexOf("</ai_matrx_agent>");
112
+ if (end < 0) return text;
113
+ let rest = text.slice(end + "</ai_matrx_agent>".length);
114
+ const skills = rest.match(/^\s*<skills_instructions>[\s\S]*?<\/skills_instructions>/);
115
+ if (skills) rest = rest.slice(skills[0].length);
116
+ return rest.replace(/^\s+/, "");
117
+ }
118
+
119
+ // src/engine/agent-attach.ts
104
120
  var AGENT_MCP_SERVER_NAME = "matrx-agent";
105
121
  var AGENT_PLUGIN_NAME = "matrx-agent";
106
122
  function escapeAttr(value) {
@@ -151,6 +167,17 @@ function renderCodexSkillsList(bundle, skillsRoot) {
151
167
  ];
152
168
  return lines.join("\n");
153
169
  }
170
+ function renderFallbackBlock(bundle, skillsRoot) {
171
+ const skills = renderCodexSkillsList(bundle, skillsRoot);
172
+ 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.");
173
+ return skills ? `${body}
174
+
175
+ ${skills}
176
+
177
+ ` : `${body}
178
+
179
+ `;
180
+ }
154
181
  function tomlString(value) {
155
182
  const scalar = value.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD");
156
183
  return JSON.stringify(scalar).replace(/\u007f/g, "\\u007f");
@@ -266,16 +293,37 @@ function sessionAgentRecord(bundle, options) {
266
293
  name: bundle.name,
267
294
  definitionHash: bundle.definition_hash,
268
295
  loaded,
269
- unavailable
296
+ unavailable,
297
+ skills: bundle.skills.map((skill) => skill.label),
298
+ tools: options.toolsServed ? bundle.tools.map((tool) => tool.canonical_name) : [],
299
+ ...options.variables ? { variables: options.variables } : {}
270
300
  };
271
301
  }
302
+ 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";
303
+ async function codexCompactionDroppedAgent(rolloutFile, sinceIso) {
304
+ const text = await fs2.readFile(rolloutFile, "utf8").catch(() => "");
305
+ if (!text.includes('"type":"compacted"')) return false;
306
+ let latest = null;
307
+ for (const line of text.split("\n")) {
308
+ if (!line.includes('"type":"compacted"')) continue;
309
+ try {
310
+ const entry = JSON.parse(line);
311
+ if (entry.type === "compacted") latest = entry;
312
+ } catch {
313
+ }
314
+ }
315
+ if (!latest) return false;
316
+ if (sinceIso && latest.timestamp && latest.timestamp <= sinceIso) return false;
317
+ return !JSON.stringify(latest.payload?.replacement_history ?? "").includes(AGENT_BLOCK_MARKER.trim());
318
+ }
272
319
 
273
320
  // src/engine/agents.ts
274
- import { randomBytes, randomUUID } from "crypto";
321
+ import { createHash as createHash2, randomBytes, randomUUID } from "crypto";
275
322
  import fs3 from "fs/promises";
276
323
  import path2 from "path";
277
324
  var DEFAULT_SERVER_URL = "https://server.app.matrxserver.com";
278
325
  var DEFAULT_SUPABASE_URL = "https://db.matrxserver.com";
326
+ var DEFAULT_SUPABASE_KEY = "sb_publishable_scm0jzEJiFUB5ItiqOx5Fg_8BOjB6oA";
279
327
  var AGENT_CATALOG_RPCS = /* @__PURE__ */ new Set([
280
328
  "agx_get_list_full",
281
329
  "agx_search",
@@ -293,6 +341,10 @@ var agentsClient = async () => {
293
341
  ]);
294
342
  return { ...matrx, ...portable, ...mcp };
295
343
  };
344
+ function sortedValues(values) {
345
+ return Object.keys(values).sort().map((key) => [key, values[key]]);
346
+ }
347
+ var BUNDLE_CACHE_MS = 24 * 60 * 60 * 1e3;
296
348
  var SIGNED_OUT_AGENT_MESSAGE = "Sign in to AI Matrx to use your agents.";
297
349
  function userIdOf(credential) {
298
350
  if (!credential || credential.kind !== "user") return null;
@@ -309,21 +361,26 @@ function createAgentConnection(options, dataDir) {
309
361
  const credentials = options?.credentials ?? null;
310
362
  const serverUrl = (options?.serverUrl ?? DEFAULT_SERVER_URL).replace(/\/+$/, "");
311
363
  const supabaseUrl = (options?.supabaseUrl ?? DEFAULT_SUPABASE_URL).replace(/\/+$/, "");
312
- const supabaseKey = options?.supabaseKey ?? null;
364
+ const supabaseKey = options?.supabaseKey ?? (options?.supabaseUrl ? null : DEFAULT_SUPABASE_KEY);
313
365
  const root = path2.join(dataDir, "agents");
314
366
  let mcpBaseUrl = null;
315
367
  const handlers = /* @__PURE__ */ new Map();
316
368
  const secretToSession = /* @__PURE__ */ new Map();
317
- const organizationId = () => {
318
- const raw = typeof options?.organizationId === "function" ? options.organizationId() : options?.organizationId;
369
+ const organizationId = async () => {
370
+ const raw = typeof options?.organizationId === "function" ? await options.organizationId() : options?.organizationId;
319
371
  return raw && raw.trim() ? raw.trim() : null;
320
372
  };
321
- const transport = async () => (await agentsClient()).createMatrxTransport({
322
- baseUrl: serverUrl,
323
- ...credentials ? { credentials } : {},
324
- ...organizationId() ? { organizationId: () => organizationId() } : {},
325
- source: "codingSessionsAgents"
326
- });
373
+ const transport = async () => {
374
+ const org = await organizationId();
375
+ return (await agentsClient()).createMatrxTransport({
376
+ baseUrl: serverUrl,
377
+ ...credentials ? { credentials } : {},
378
+ ...org ? { organizationId: org } : {},
379
+ source: "codingSessionsAgents"
380
+ });
381
+ };
382
+ const cacheDir = path2.join(dataDir, "agents", ".bundles");
383
+ const cacheKey = (definitionHash, selection, surface) => createHash2("sha256").update(JSON.stringify([definitionHash, sortedValues(selection.variables ?? {}), surface])).digest("hex");
327
384
  const credential = async () => credentials ? credentials.get() : null;
328
385
  const requireSignedIn = async () => {
329
386
  if (!await credential()) throw new Error(SIGNED_OUT_AGENT_MESSAGE);
@@ -359,7 +416,7 @@ function createAgentConnection(options, dataDir) {
359
416
  configured: credentials !== null && supabaseKey !== null,
360
417
  signedIn: userId !== null,
361
418
  userId,
362
- organizationId: organizationId()
419
+ organizationId: await organizationId().catch(() => null)
363
420
  };
364
421
  },
365
422
  async catalogRpc(request) {
@@ -406,27 +463,39 @@ function createAgentConnection(options, dataDir) {
406
463
  },
407
464
  async details(agentId) {
408
465
  await requireSignedIn();
409
- const { fetchPortableAgent, fetchPortableAgentVersions } = await agentsClient();
410
- const [bundle, versions] = await Promise.all([
411
- fetchPortableAgent(await transport(), { agentId }),
412
- fetchPortableAgentVersions(await transport(), agentId).catch(() => [])
413
- ]);
466
+ const summary = await (await agentsClient()).fetchPortableAgentSummary(await transport(), agentId);
414
467
  return {
415
- agentId: bundle.agent_id,
416
- name: bundle.name,
417
- variables: bundle.variables,
418
- versions: versions.map((v) => ({ id: v.id, versionNumber: v.version_number, changedAt: v.changed_at })).sort((a, b) => b.versionNumber - a.versionNumber),
419
- latestVersionNumber: bundle.version_number
468
+ agentId: summary.agent_id,
469
+ name: summary.name,
470
+ variables: summary.variables,
471
+ versions: summary.versions.map((v) => ({ id: v.id, versionNumber: v.version_number, changedAt: v.changed_at })),
472
+ latestVersionNumber: summary.version_number,
473
+ latestVersionId: summary.version_id
420
474
  };
421
475
  },
422
476
  async loadBundle(selection) {
423
477
  await requireSignedIn();
424
- const { fetchPortableAgent } = await agentsClient();
425
- return fetchPortableAgent(
478
+ const client = await agentsClient();
479
+ const summary = await client.fetchPortableAgentSummary(await transport(), selection.agentId);
480
+ const versionId = selection.versionId ?? summary.version_id;
481
+ const definitionHash = versionId ? summary.versions.find((v) => v.id === versionId)?.definition_hash ?? null : summary.definition_hash;
482
+ const surface = "matrx-user/code-editor";
483
+ const file = definitionHash ? path2.join(cacheDir, `${cacheKey(definitionHash, selection, surface)}.json`) : null;
484
+ if (file) {
485
+ const cached = await fs3.readFile(file, "utf8").then((text) => JSON.parse(text)).catch(() => null);
486
+ const fresh = await fs3.stat(file).then((st) => Date.now() - st.mtimeMs < BUNDLE_CACHE_MS).catch(() => false);
487
+ if (cached && fresh && cached.definition_hash === definitionHash) return cached;
488
+ }
489
+ const bundle = await client.fetchPortableAgent(
426
490
  await transport(),
427
- selection.versionId ? { versionId: selection.versionId } : { agentId: selection.agentId },
428
- { variables: selection.variables ?? {} }
491
+ versionId ? { versionId } : { agentId: selection.agentId },
492
+ { variables: selection.variables ?? {}, surface }
429
493
  );
494
+ if (file && bundle.definition_hash === definitionHash) {
495
+ await fs3.mkdir(cacheDir, { recursive: true, mode: 448 });
496
+ await fs3.writeFile(file, JSON.stringify(bundle), { mode: 384 });
497
+ }
498
+ return bundle;
430
499
  },
431
500
  async saveSessionBundle(sessionId, bundle) {
432
501
  await fs3.mkdir(sessionDir(sessionId), { recursive: true, mode: 448 });
@@ -841,7 +910,7 @@ function rolloutItem(item, fallbackId, at) {
841
910
  const id = str2(item.id) ?? fallbackId;
842
911
  switch (item.type) {
843
912
  case "UserMessage": {
844
- const text = stripCodexInjectedContext(itemText(item.content));
913
+ const text = stripCodexInjectedContext(stripAgentBlock(itemText(item.content)));
845
914
  return text.trim() ? [{ kind: "user", id, text, at }] : [];
846
915
  }
847
916
  case "AgentMessage": {
@@ -924,7 +993,7 @@ function createCodexRolloutNormalizer() {
924
993
  return rolloutItem(payload.item, fallbackId, at);
925
994
  }
926
995
  if (payload.type === "user_message" && !appItems) {
927
- const text = stripCodexInjectedContext(str2(payload.message) ?? "");
996
+ const text = stripCodexInjectedContext(stripAgentBlock(str2(payload.message) ?? ""));
928
997
  return text.trim() ? [{ kind: "user", id: fallbackId, text, at }] : [];
929
998
  }
930
999
  return [];
@@ -2402,6 +2471,12 @@ async function createCodingSessionsEngine(options = {}) {
2402
2471
  if (file) fileOffset = (await fs8.stat(file).catch(() => null))?.size ?? null;
2403
2472
  }
2404
2473
  let agentArgs = [];
2474
+ let cliPrompt = prompt;
2475
+ let delivered = null;
2476
+ if (!session.agent && session.agentRemovedDue) {
2477
+ if (provider === "codex") cliPrompt = `${AGENT_REMOVED_BLOCK}${prompt}`;
2478
+ delivered = { agentRemovedDue: false };
2479
+ }
2405
2480
  if (session.agent) {
2406
2481
  const bundle = await agents.readSessionBundle(session.id);
2407
2482
  if (!bundle) {
@@ -2419,6 +2494,10 @@ async function createCodingSessionsEngine(options = {}) {
2419
2494
  mcpUrl: await agents.mcpUrlFor(session.id)
2420
2495
  });
2421
2496
  agentArgs = agentArgsFor(provider, attachment, { resuming: session.providerSessionId !== null });
2497
+ if (provider === "codex" && session.agent.blockDue) {
2498
+ cliPrompt = `${renderFallbackBlock(bundle, path9.join(attachment.dir, "skills"))}${prompt}`;
2499
+ }
2500
+ delivered = { agent: { ...session.agent, blockDue: false, deliveredAt: run.startedAt } };
2422
2501
  }
2423
2502
  const child = forkWorker();
2424
2503
  const liveRun = {
@@ -2434,6 +2513,10 @@ async function createCodingSessionsEngine(options = {}) {
2434
2513
  };
2435
2514
  live.set(runId, liveRun);
2436
2515
  emitItem(liveRun, { kind: "user", id: `run-${runId}`, text: prompt, at: run.startedAt });
2516
+ if (delivered) {
2517
+ const current = index.session(session.id);
2518
+ if (current) saveSession({ ...current, ...delivered });
2519
+ }
2437
2520
  const splitter = createLineSplitter();
2438
2521
  const claude = provider === "claude" ? createClaudeNormalizer() : null;
2439
2522
  const codex = provider === "codex" ? createCodexStreamNormalizer(runId.slice(0, 8)) : null;
@@ -2472,6 +2555,7 @@ async function createCodingSessionsEngine(options = {}) {
2472
2555
  }
2473
2556
  }
2474
2557
  void pruneDriverScratch();
2558
+ if (provider === "codex" && final.status === "completed") void checkCompaction(session.id);
2475
2559
  };
2476
2560
  let settled = false;
2477
2561
  child.on("message", (raw) => {
@@ -2586,7 +2670,7 @@ async function createCodingSessionsEngine(options = {}) {
2586
2670
  provider,
2587
2671
  runId,
2588
2672
  cwd: session.cwd,
2589
- prompt,
2673
+ prompt: cliPrompt,
2590
2674
  model,
2591
2675
  effort: session.effort ?? null,
2592
2676
  resumeSessionId: session.providerSessionId,
@@ -2597,6 +2681,28 @@ async function createCodingSessionsEngine(options = {}) {
2597
2681
  });
2598
2682
  return run;
2599
2683
  }
2684
+ async function checkCompaction(sessionId) {
2685
+ const session = index.session(sessionId);
2686
+ if (!session?.agent || session.agent.blockDue || !session.providerSessionId) return;
2687
+ const file = await findSessionFile("codex", session.providerSessionId, homes);
2688
+ if (!file || !await codexCompactionDroppedAgent(file, session.agent.deliveredAt ?? null)) return;
2689
+ const current = index.session(sessionId);
2690
+ if (current?.agent) {
2691
+ saveSession({ ...current, agent: { ...current.agent, blockDue: true } });
2692
+ }
2693
+ }
2694
+ async function attachAgent(sessionId, selection, options2) {
2695
+ const bundle = await agents.loadBundle(selection);
2696
+ await agents.saveSessionBundle(sessionId, bundle);
2697
+ return {
2698
+ ...sessionAgentRecord(bundle, {
2699
+ toolsServed: await agents.mcpUrlFor(sessionId) !== null,
2700
+ variables: selection.variables ?? {}
2701
+ }),
2702
+ blockDue: options2.blockDue,
2703
+ deliveredAt: null
2704
+ };
2705
+ }
2600
2706
  function killGroup(liveRun) {
2601
2707
  const target = liveRun.pgid;
2602
2708
  if (target === null) return;
@@ -2853,7 +2959,6 @@ async function createCodingSessionsEngine(options = {}) {
2853
2959
  const prompt = input.prompt.trim();
2854
2960
  if (!prompt) throw new Error("Type what you want done before starting.");
2855
2961
  const cwd = await assertFolder(input.cwd);
2856
- const bundle = input.agent ? await agents.loadBundle(input.agent) : null;
2857
2962
  const draft = newSession({
2858
2963
  provider: input.provider,
2859
2964
  cwd,
@@ -2863,28 +2968,40 @@ async function createCodingSessionsEngine(options = {}) {
2863
2968
  origin: "started",
2864
2969
  providerSessionId: null
2865
2970
  });
2866
- if (bundle) {
2867
- await agents.saveSessionBundle(draft.id, bundle);
2868
- draft.agent = sessionAgentRecord(bundle, { toolsServed: await agents.mcpUrlFor(draft.id) !== null });
2869
- }
2971
+ if (input.agent) draft.agent = await attachAgent(draft.id, input.agent, { blockDue: false });
2870
2972
  const session = saveSession(draft);
2871
2973
  const run = await startRun(session, prompt);
2872
2974
  return { session: index.session(session.id) ?? session, run, queued: false };
2873
2975
  },
2874
2976
  async takeover(input) {
2875
2977
  const existing = index.session(input.providerSessionId);
2876
- if (existing) return existing;
2978
+ if (existing) {
2979
+ if (!input.agent) return existing;
2980
+ return engine.setAgent(existing.id, input.agent);
2981
+ }
2877
2982
  const cwd = await assertFolder(input.cwd);
2878
- return saveSession(
2879
- newSession({
2880
- provider: input.provider,
2881
- cwd,
2882
- title: input.title?.trim() || "Taken-over chat",
2883
- model: null,
2884
- origin: "takeover",
2885
- providerSessionId: input.providerSessionId
2886
- })
2887
- );
2983
+ const draft = newSession({
2984
+ provider: input.provider,
2985
+ cwd,
2986
+ title: input.title?.trim() || "Taken-over chat",
2987
+ model: null,
2988
+ origin: "takeover",
2989
+ providerSessionId: input.providerSessionId
2990
+ });
2991
+ if (input.agent) draft.agent = await attachAgent(draft.id, input.agent, { blockDue: input.provider === "codex" });
2992
+ return saveSession(draft);
2993
+ },
2994
+ async setAgent(sessionId, selection) {
2995
+ const session = index.session(String(sessionId ?? ""));
2996
+ if (!session) throw new Error("This session is not in the list anymore.");
2997
+ if (!selection) {
2998
+ const told = session.provider === "codex" && session.agent?.deliveredAt != null;
2999
+ return saveSession({ ...session, agent: null, agentRemovedDue: told });
3000
+ }
3001
+ const agent = await attachAgent(session.id, selection, {
3002
+ blockDue: session.provider === "codex" && session.providerSessionId !== null
3003
+ });
3004
+ return saveSession({ ...session, agent, agentRemovedDue: false });
2888
3005
  },
2889
3006
  async send(sessionId, rawPrompt) {
2890
3007
  const prompt = rawPrompt.trim();
@@ -2999,6 +3116,8 @@ function openFolderIn(folder, target) {
2999
3116
  });
3000
3117
  }
3001
3118
  export {
3119
+ DEFAULT_SERVER_URL,
3120
+ DEFAULT_SUPABASE_URL,
3002
3121
  EFFORT_LEVELS,
3003
3122
  PreferenceStore,
3004
3123
  RAW_TRANSCRIPT_MAX_BYTES,