@inixiative/agent-session 0.3.0 → 0.3.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/README.md CHANGED
@@ -96,6 +96,11 @@ const result = await decisions.decide(
96
96
  );
97
97
  ```
98
98
 
99
+ Run Codex decisions on a private `CODEX_HOME` that holds only the login (link
100
+ `auth.json` from the account's home; a copy forks its refresh token): Codex has no
101
+ setting that drops the user's own `AGENTS.md`, and a decision thread that reports
102
+ any instruction source is refused.
103
+
99
104
  Codex hosts every key as a thread of one `app-server` process per account and
100
105
  forks the primed thread per cycle; Claude forks a persisted primed session with
101
106
  a pre-spawned spare. Measured on a ChatGPT login: warm Codex decisions 2.45 s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inixiative/agent-session",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Drive coding-agent CLIs as persistent, streaming, event-captured sessions over interchangeable transports, with primed decision sessions, subscription pools, routing, limit polling and continuity.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -36,7 +36,7 @@
36
36
  "license": "MIT",
37
37
  "devDependencies": {
38
38
  "@biomejs/biome": "2.5.2",
39
- "@inixiative/config": "^0.5.40",
39
+ "@inixiative/config": "^0.5.41",
40
40
  "@types/bun": "1.4.2",
41
41
  "lefthook": "2.1.9",
42
42
  "typescript": "6.0.3"
@@ -75,15 +75,19 @@ export const CODEX_DECISION_DISABLED_FEATURES: readonly string[] = [
75
75
  ];
76
76
 
77
77
  /**
78
- * Per-thread configuration for decisions: no notify hook, no built-in MCP server,
79
- * no project docs or skills, and none of the instruction surfaces that describe
80
- * tools or the environment. Applied on thread/start and thread/fork (verified
81
- * equivalent to launch-level `-c` overrides), so the launch argv carries only
82
- * approval, web-search and feature flags that credential launchers accept.
78
+ * Per-thread configuration for decisions: no notify hook, no project docs or skills,
79
+ * and none of the instruction surfaces that describe tools or the environment.
80
+ * Applied on thread/start and thread/fork (verified equivalent to launch-level `-c`
81
+ * overrides), so the launch argv carries only approval, web-search and feature flags
82
+ * that credential launchers accept.
83
+ *
84
+ * The user's own CODEX_HOME (its AGENTS.md, memories, MCP servers) is not a thread
85
+ * setting: run decisions on a private CODEX_HOME holding only the login. A thread
86
+ * that reports an instruction source is refused, and an MCP server that starts is a
87
+ * violation.
83
88
  */
84
89
  export const CODEX_DECISION_THREAD_CONFIG: Readonly<Record<string, unknown>> = Object.freeze({
85
90
  notify: [],
86
- 'mcp_servers.node_repl.enabled': false,
87
91
  project_doc_max_bytes: 0,
88
92
  'skills.enabled': false,
89
93
  include_permissions_instructions: false,
@@ -213,6 +217,19 @@ interface Branch {
213
217
  wake(): void;
214
218
  }
215
219
 
220
+ /** Instruction files Codex loaded into a thread (the user's AGENTS.md, project docs); a decision allows none. */
221
+ const instructionSources = (response: Record<string, unknown> | undefined): string | undefined => {
222
+ const sources = response?.instructionSources;
223
+ return Array.isArray(sources) && sources.length ? sources.map(String).join(', ') : undefined;
224
+ };
225
+ const instructionLeak = (sources: string) =>
226
+ new DecisionError(
227
+ `Codex loaded instructions into a decision thread (${sources}); run decisions on a private CODEX_HOME`,
228
+ 'violation',
229
+ 'not-dispatched',
230
+ true,
231
+ );
232
+
216
233
  const object = (value: unknown): Record<string, unknown> | undefined =>
217
234
  value !== null && typeof value === 'object' && !Array.isArray(value)
218
235
  ? (value as Record<string, unknown>)
@@ -1045,6 +1062,11 @@ export class CodexPrimedSessions implements PrimedSessions {
1045
1062
  'not-dispatched',
1046
1063
  true,
1047
1064
  );
1065
+ const leaked = instructionSources(started);
1066
+ if (leaked) {
1067
+ void conn.request('thread/delete', { threadId: baseId }, 10_000).catch(() => undefined);
1068
+ throw instructionLeak(leaked);
1069
+ }
1048
1070
  const branch = this._branch(conn, baseId, spec.key);
1049
1071
  let ok = false;
1050
1072
  try {
@@ -1287,6 +1309,8 @@ export class CodexPrimedSessions implements PrimedSessions {
1287
1309
  );
1288
1310
  const id = object(response?.thread)?.id;
1289
1311
  if (typeof id !== 'string' || !id) throw Error('Codex returned no decision thread');
1312
+ const leaked = instructionSources(response);
1313
+ if (leaked) throw instructionLeak(leaked);
1290
1314
  model ??= typeof response?.model === 'string' ? response.model : undefined;
1291
1315
  return { threadId: id, branch: this._branch(conn, id, spec.key) };
1292
1316
  };
@@ -1294,6 +1318,7 @@ export class CodexPrimedSessions implements PrimedSessions {
1294
1318
  if (Date.now() >= deadline || signal?.aborted) throw expired();
1295
1319
  const t1 = performance.now();
1296
1320
  const opened = await openBranch().catch((error) => {
1321
+ if (error instanceof DecisionError) throw error;
1297
1322
  // The runtime refusing the fork means the primed thread is gone: retire it and prime again off-path.
1298
1323
  // A timeout proves nothing about the primed thread.
1299
1324
  if (session && error instanceof JsonRpcError) this._retire(session, 'reprime');