memoryrouter-codex 1.0.0 → 1.1.0

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
@@ -2,15 +2,17 @@
2
2
 
3
3
  Native Codex integration for durable MemoryRouter memory. It uses Codex's current MCP, lifecycle hooks, and `AGENTS.md` surfaces rather than pretending that model-selected MCP calls alone are automatic memory.
4
4
 
5
+ > **Release status:** `memoryrouter-codex@1.1.0` is the published npm release. Its automatic capture is message-only: one user request plus the final assistant response, with no tool payloads.
6
+
5
7
  ## What this integration does
6
8
 
7
9
  | Layer | Behavior |
8
10
  | --- | --- |
9
11
  | `UserPromptSubmit` hook | Searches MemoryRouter before every prompt and injects bounded, project-scoped context as developer context. |
10
- | `PostToolUse` + `Stop` hooks | Captures the user request, stable hook-provided tool inputs/results, and final answer after each completed turn. |
12
+ | `Stop` hook | Captures only the user request and final assistant response after each completed turn. Tool names, inputs, and results are excluded. |
11
13
  | `SubagentStop` hook | Captures the stable final outcome of completed subagents without parsing their unstable transcript files. |
12
- | `PreCompact` / compact `SessionStart` | Checkpoints work before compaction and recalls context before Codex continues after compaction. |
13
- | `SessionEnd` | Best-effort final checkpoint within Codex's three-second SessionEnd budget. |
14
+ | `PreCompact` / compact `SessionStart` | Checkpoints only the current user request and final assistant response when present, then recalls context before Codex continues after compaction. |
15
+ | `SessionEnd` | Best-effort message-only final checkpoint within Codex's three-second SessionEnd budget. |
14
16
  | Remote MCP | OAuth-based explicit search/store through `https://mcp.memoryrouter.ai/mcp`. |
15
17
  | Local MCP fallback | API-key-authenticated stdio tools with strict project filtering, handles, local suppression, status, and full-vault clear confirmation. |
16
18
  | `AGENTS.md` | Tells Codex when to recall/store and how MemoryRouter coexists with native Memories. |
@@ -37,7 +39,7 @@ Obtain a MemoryRouter memory key from your account. Pass it on stdin so it does
37
39
 
38
40
  ```bash
39
41
  printf '%s' "$MEMORYROUTER_API_KEY" | \
40
- npx -y memoryrouter-codex@1.0.0 init --scope user --auth oauth --api-key-stdin
42
+ npx -y memoryrouter-codex@1.1.0 init --scope user --auth oauth --api-key-stdin
41
43
 
42
44
  codex mcp login memoryrouter
43
45
  memoryrouter-codex doctor --scope user
@@ -59,7 +61,7 @@ If you prefer not to persist the key, omit `--api-key-stdin` and ensure `MEMORYR
59
61
  ```bash
60
62
  cd /path/to/repository
61
63
  printf '%s' "$MEMORYROUTER_API_KEY" | \
62
- npx -y memoryrouter-codex@1.0.0 init --scope project --auth oauth --api-key-stdin
64
+ npx -y memoryrouter-codex@1.1.0 init --scope project --auth oauth --api-key-stdin
63
65
  codex mcp login memoryrouter
64
66
  ```
65
67
 
@@ -69,7 +71,7 @@ This writes managed blocks/files under the repository's `AGENTS.md` and `.codex/
69
71
 
70
72
  ```bash
71
73
  printf '%s' "$MEMORYROUTER_API_KEY" | \
72
- npx -y memoryrouter-codex@1.0.0 init --scope user --auth api-key --api-key-stdin
74
+ npx -y memoryrouter-codex@1.1.0 init --scope user --auth api-key --api-key-stdin
73
75
  ```
74
76
 
75
77
  This uses a local stdio MCP server and the MemoryRouter API. It does not put the memory key in Codex config. The fallback tools are:
@@ -126,6 +128,10 @@ Automatic memories use an envelope containing project handle, stable memory hand
126
128
 
127
129
  Set `retrievalScope` to `"vault"` in the private config only if you intentionally want unscoped automatic recall.
128
130
 
131
+ ## Historical import boundary
132
+
133
+ The Codex package captures future work after installation. It does not ship a deterministic importer for ChatGPT exports or prior Codex conversations. A local Codex workflow can inspect an extracted export and curate selected facts, but that is experimental guided curation, not checkpointed/resumable/reconciled archive ingestion. Remote MCP OAuth connection by itself never imports history.
134
+
129
135
  ## Handles, deduplication, retries, and forgetting
130
136
 
131
137
  - Handles (`mrh_...`) are content-derived from project, kind, and normalized content.
@@ -142,7 +148,7 @@ Set `retrievalScope` to `"vault"` in the private config only if you intentionall
142
148
  - Hook `additionalContextLimit`: approximately 3,500 tokens, so Codex can spill unexpectedly large context safely instead of consuming the whole model window.
143
149
  - Candidate search default: 12 before strict project filtering.
144
150
  - All hook entrypoints exit zero on missing credentials, malformed input, API errors, and timeouts. Memory never blocks Codex work.
145
- - Hook status is recorded without secrets in `~/.memoryrouter/codex/health.json`. Search/store/forget outcomes (metadata only, never memory content or keys) append to a rotating 5 MiB local `~/.memoryrouter/codex/audit.jsonl`. `memory_status` exposes both locations. This is a host-local integration audit, not a server-wide team access log. Session/trace state older than 30 days is pruned at session start.
151
+ - Hook status is recorded without secrets in `~/.memoryrouter/codex/health.json`. Search/store/forget outcomes (metadata only, never memory content or keys) append to a rotating 5 MiB local `~/.memoryrouter/codex/audit.jsonl`. `memory_status` exposes both locations. This is a host-local integration audit, not a server-wide team access log. Session state and any legacy pre-1.1 trace files older than 30 days are pruned at session start. Version 1.1 creates no tool trace files.
146
152
  - Set `MEMORYROUTER_DEBUG=1` for hook errors on stderr. Debug is off by default.
147
153
 
148
154
  ## Codex native Memories coexistence
@@ -172,7 +178,7 @@ Live verification with official `@openai/codex` **0.146.0** established:
172
178
  5. Codex generates an authorization URL with PKCE S256, `memories:read memories:write`, the exact RFC 8707 resource, and a loopback callback.
173
179
  6. The browser consent/token step was deliberately not completed by the package test because it is account-specific. Therefore `doctor` verifies discovery compatibility but never reports an OAuth session as logged in without user consent. Use `codex mcp login memoryrouter` and `/mcp verbose` to complete/verify it.
174
180
 
175
- The remote server currently negotiates legacy MCP `2025-11-25`. Codex 0.146 remains dual-era and initializes it successfully today. MemoryRouter's MCP server still needs its separate `2026-07-28` protocol modernization; this client integration does not hide that server limitation.
181
+ The production server supports modern stateless MCP `2026-07-28` and still accepts `2025-11-25`, `2025-06-18`, and `2025-03-26` for handshake-era clients. Codex 0.146 initializes the compatibility path successfully. Do not infer Codex support from protocol negotiation alone; verify OAuth login, `/mcp verbose`, and the actual tool inventory.
176
182
 
177
183
  ## Doctor
178
184
 
@@ -189,15 +195,15 @@ Doctor checks Codex version, managed config, runtime version, hook count, `AGENT
189
195
  Upgrade idempotently by re-running the pinned/new package:
190
196
 
191
197
  ```bash
192
- npx -y memoryrouter-codex@1.0.0 init --scope user
198
+ npx -y memoryrouter-codex@1.1.0 init --scope user
193
199
  ```
194
200
 
195
201
  Uninstall:
196
202
 
197
203
  ```bash
198
- npx -y memoryrouter-codex@1.0.0 uninstall --scope user
204
+ npx -y memoryrouter-codex@1.1.0 uninstall --scope user
199
205
  # or
200
- npx -y memoryrouter-codex@1.0.0 uninstall --scope project --project-dir /repo
206
+ npx -y memoryrouter-codex@1.1.0 uninstall --scope project --project-dir /repo
201
207
  ```
202
208
 
203
209
  Uninstall deliberately retains `~/.memoryrouter/codex/` because another project installation may use the credentials and local suppression state. Delete that private directory manually only when no integration uses it.
@@ -205,8 +211,8 @@ Uninstall deliberately retains `~/.memoryrouter/codex/` because another project
205
211
  ## Honest limitations
206
212
 
207
213
  - Hooks are the deterministic automatic path. Remote MCP alone remains model-invoked, not guaranteed every turn.
208
- - The transcript file path supplied to hooks is documented as unstable, so this integration does **not** parse Codex transcript JSONL. It captures only stable hook fields: prompt, tool input/result, and final assistant message.
209
- - Hosted tools such as web search do not currently emit `PostToolUse`; their detailed output is not automatically captured unless reflected in the final response.
214
+ - The transcript file path supplied to hooks is documented as unstable, so this integration does **not** parse Codex transcript JSONL. Version 1.1 captures only the stable user prompt and `last_assistant_message`.
215
+ - Tool-call records are intentionally excluded. MemoryRouter does not store tool names, tool IDs, tool inputs, tool results, commands, patches, or other `PostToolUse` payloads from automatic Codex capture. Important outcomes must appear in the final assistant response to be retained.
210
216
  - Some specialized tool paths can opt out of hooks. Codex documents hooks as a useful extension surface, not a complete enforcement boundary.
211
217
  - SessionEnd can happen after a 30-minute idle period and has a three-second maximum. It is a best-effort checkpoint; normal `Stop` capture is the primary write path.
212
218
  - Project scoping is strict for this package's automatic retrieval/local MCP. The existing hosted remote MCP server has no first-class project argument, so use local tools/hooks when cross-project isolation is required.
package/RESEARCH.md CHANGED
@@ -17,7 +17,7 @@ Verified 2026-07-31. This is engineering evidence, not public marketing copy.
17
17
  ## Platform findings used in the architecture
18
18
 
19
19
  - Current Codex supports command hooks for `SessionStart`, `SessionEnd`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `UserPromptSubmit`, `SubagentStart`, `SubagentStop`, and `Stop`.
20
- - Hook transcript paths are explicitly documented as unstable. The integration therefore uses stable event fields and an append-only local tool trace rather than parsing transcript JSONL.
20
+ - Hook transcript paths are explicitly documented as unstable. Version 1.0 used stable event fields plus an append-only local `PostToolUse` trace. Version 1.1 removes that trace and its hook entirely: completed-turn storage is composed only from the `UserPromptSubmit` prompt and Stop's stable `last_assistant_message`.
21
21
  - Hooks are enabled by default and project hooks require trust. `features.codex_hooks` is only a deprecated alias; the current canonical key is `features.hooks`.
22
22
  - Remote MCP OAuth no longer needs `experimental_use_rmcp_client` in current Codex. That key is absent from the current configuration reference.
23
23
  - The local CLI, desktop Codex host, and IDE extension share Codex config. ChatGPT web uses hosted plugin tools and does not inherit local config.
@@ -54,4 +54,8 @@ npm run typecheck
54
54
  npm pack --dry-run
55
55
  ```
56
56
 
57
- The integration suite covers config migration/backup, foreign-config preservation, corrupt config fail-closed behavior, idempotent upgrades, uninstall, project/worktree identity, project-vs-vault filtering, native-memory config coexistence, OAuth/local fallback configuration, read retries, write deduplication, hook fail-open behavior, full stable-field turn capture, context budgets, local suppression, and MCP tool annotations.
57
+ The integration suite covers config migration/backup, foreign-config preservation, corrupt config fail-closed behavior, idempotent upgrades, uninstall, project/worktree identity, project-vs-vault filtering, native-memory config coexistence, OAuth/local fallback configuration, read retries, write deduplication, hook fail-open behavior, prompt/final-only turn and checkpoint capture, explicit exclusion of tool payloads, context budgets, local suppression, and MCP tool annotations.
58
+
59
+ ## Version 1.1 capture decision
60
+
61
+ `PostToolUse` is not registered by the installer in 1.1. The runtime no longer defines or reads trace files, and health records no longer count tool calls. Normal Stop capture requires `last_assistant_message`; PreCompact and SessionEnd may preserve the cached user prompt when no final response is available. `SubagentStop` remains separate and stores only its stable final outcome plus non-payload agent identifiers.
package/lib/hooks.cjs CHANGED
@@ -52,7 +52,6 @@ function managedGroups(runtimeDir, scope) {
52
52
  return {
53
53
  SessionStart: [{ matcher: 'startup|resume|clear|compact', hooks: [handler('session-start', 8, 'Recalling MemoryRouter context', 3500)] }],
54
54
  UserPromptSubmit: [{ hooks: [handler('inject', 8, 'Searching project memory', 3500)] }],
55
- PostToolUse: [{ hooks: [handler('trace', 3)] }],
56
55
  Stop: [{ hooks: [handler('capture', 18, 'Saving durable project memory')] }],
57
56
  SubagentStop: [{ hooks: [handler('capture-subagent', 15, 'Saving durable subagent outcome')] }],
58
57
  PreCompact: [{ matcher: 'manual|auto', hooks: [handler('flush', 18, 'Saving memory before compaction')] }],
package/lib/installer.cjs CHANGED
@@ -11,7 +11,7 @@ const {
11
11
  installToml, uninstallToml, installAgents, uninstallAgents, readText, replaceBlock,
12
12
  hasUnmanagedMemoryRouterTable, TOML_START, TOML_END, AGENTS_START, AGENTS_END,
13
13
  } = require('./managed.cjs');
14
- const { installHooks, uninstallHooks, isOwnedHook, parseHooks } = require('./hooks.cjs');
14
+ const { installHooks, uninstallHooks, isOwnedHook, managedGroups, parseHooks } = require('./hooks.cjs');
15
15
 
16
16
  function resolveLayout(options = {}) {
17
17
  const env = options.env || process.env;
@@ -176,7 +176,8 @@ async function doctor(options = {}) {
176
176
  let hooks = null;
177
177
  try { hooks = hooksText ? JSON.parse(hooksText) : null; } catch { /* handled */ }
178
178
  const owned = hooks ? Object.values(hooks.hooks || {}).flat().flatMap(group => group.hooks || []).filter(isOwnedHook) : [];
179
- addCheck(checks, 'hooks', owned.length >= 7 ? 'pass' : 'error', owned.length ? `${owned.length} managed lifecycle hooks found.` : 'Managed lifecycle hooks are missing or hooks.json is invalid.');
179
+ const expectedOwned = Object.values(managedGroups(layout.runtimeDir, layout.scope)).flat().flatMap(group => group.hooks || []).length;
180
+ addCheck(checks, 'hooks', owned.length === expectedOwned ? 'pass' : 'error', owned.length ? `${owned.length} of ${expectedOwned} managed lifecycle hooks found.` : 'Managed lifecycle hooks are missing or hooks.json is invalid.');
180
181
  addCheck(checks, 'agents', agentsText.includes(AGENTS_START) ? 'pass' : 'warn', agentsText.includes(AGENTS_START) ? 'Managed AGENTS.md guidance is present.' : 'Managed AGENTS.md guidance is missing.');
181
182
 
182
183
  const cfg = loadConfig(options.env);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memoryrouter-codex",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Automatic, project-scoped MemoryRouter memory for OpenAI Codex",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -74,10 +74,6 @@ function sessionStatePath(sessionId, env = process.env) {
74
74
  return path.join(stateDir(env), `${safeId(sessionId)}.json`);
75
75
  }
76
76
 
77
- function tracePath(sessionId, turnId, env = process.env) {
78
- return path.join(stateDir(env), `${safeId(sessionId)}-${safeId(turnId)}.trace.jsonl`);
79
- }
80
-
81
77
  function loadSessionState(sessionId, env = process.env) {
82
78
  try {
83
79
  const value = JSON.parse(fs.readFileSync(sessionStatePath(sessionId, env), 'utf8'));
@@ -154,7 +150,6 @@ module.exports = {
154
150
  safeId,
155
151
  stateDir,
156
152
  sessionStatePath,
157
- tracePath,
158
153
  loadSessionState,
159
154
  saveSessionState,
160
155
  pruneState,
@@ -1,13 +1,11 @@
1
1
  'use strict';
2
2
 
3
- const INTEGRATION_VERSION = '1.0.0';
3
+ const INTEGRATION_VERSION = '1.1.0';
4
4
  const RUNTIME_SCHEMA_VERSION = 1;
5
5
  const API_BASE = 'https://api.memoryrouter.ai';
6
6
  const MCP_ENDPOINT = 'https://mcp.memoryrouter.ai/mcp';
7
7
  const DEFAULT_CONTEXT_CHARS = 12000;
8
8
  const DEFAULT_SEARCH_RESULTS = 12;
9
- const MAX_TRACE_RECORD_CHARS = 8000;
10
- const MAX_TRACE_TOTAL_CHARS = 60000;
11
9
  const ENVELOPE_HEADER = '[MemoryRouter Codex Memory v1]';
12
10
 
13
11
  module.exports = {
@@ -17,7 +15,5 @@ module.exports = {
17
15
  MCP_ENDPOINT,
18
16
  DEFAULT_CONTEXT_CHARS,
19
17
  DEFAULT_SEARCH_RESULTS,
20
- MAX_TRACE_RECORD_CHARS,
21
- MAX_TRACE_TOTAL_CHARS,
22
18
  ENVELOPE_HEADER,
23
19
  };
package/runtime/hook.cjs CHANGED
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const fs = require('fs');
5
- const { loadConfig, getApiKey, loadSessionState, saveSessionState, tracePath, pruneState, recordHealth } = require('./config.cjs');
4
+ const { loadConfig, getApiKey, loadSessionState, saveSessionState, pruneState, recordHealth } = require('./config.cjs');
6
5
  const { resolveProject } = require('./project.cjs');
7
6
  const { searchScoped, storeScoped, memoryHandle } = require('./memory.cjs');
8
- const { MAX_TRACE_RECORD_CHARS, MAX_TRACE_TOTAL_CHARS } = require('./constants.cjs');
9
7
 
10
8
  function debug(...values) {
11
9
  if (process.env.MEMORYROUTER_DEBUG) console.error('[memoryrouter-codex]', ...values);
@@ -22,7 +20,7 @@ function readStdin(timeoutMs = 1500) {
22
20
  });
23
21
  }
24
22
 
25
- function truncate(value, limit = MAX_TRACE_RECORD_CHARS) {
23
+ function truncate(value, limit = 8000) {
26
24
  let text;
27
25
  try { text = typeof value === 'string' ? value : JSON.stringify(value); } catch { text = String(value); }
28
26
  if (text.length <= limit) return text;
@@ -38,61 +36,16 @@ function emitContext(eventName, context) {
38
36
  return true;
39
37
  }
40
38
 
41
- function appendTrace(input, env = process.env) {
42
- if (!input.session_id || !input.turn_id) return;
43
- const record = {
44
- at: new Date().toISOString(),
45
- turn_id: input.turn_id,
46
- tool_name: input.tool_name,
47
- tool_use_id: input.tool_use_id,
48
- input: truncate(input.tool_input),
49
- response: truncate(input.tool_response),
50
- };
51
- const file = tracePath(input.session_id, input.turn_id, env);
52
- fs.appendFileSync(file, `${JSON.stringify(record)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'a' });
53
- }
54
-
55
- function readTrace(sessionId, turnId, env = process.env) {
56
- const file = tracePath(sessionId, turnId, env);
57
- let text;
58
- try { text = fs.readFileSync(file, 'utf8'); } catch { return []; }
59
- const records = [];
60
- let total = 0;
61
- for (const line of text.split('\n')) {
62
- if (!line.trim()) continue;
63
- try {
64
- const record = JSON.parse(line);
65
- const size = JSON.stringify(record).length;
66
- if (total + size > MAX_TRACE_TOTAL_CHARS) break;
67
- records.push(record);
68
- total += size;
69
- } catch { /* tolerate partial concurrent append */ }
70
- }
71
- return records;
72
- }
73
-
74
- function removeTrace(sessionId, turnId, env = process.env) {
75
- try { fs.unlinkSync(tracePath(sessionId, turnId, env)); } catch { /* absent */ }
76
- }
77
-
78
- function turnContent(input, state, records, partial = false) {
39
+ function turnContent(input, state) {
79
40
  const prompt = state.prompts?.[input.turn_id] || state.lastPrompt || '';
80
- const parts = [
81
- partial ? 'Codex work checkpoint before compaction/session end.' : 'Completed Codex turn.',
82
- prompt ? `User request:\n${truncate(prompt, 40000)}` : null,
83
- ];
84
- if (records.length) {
85
- parts.push(`Tool activity (${records.length} calls):`);
86
- for (const record of records) {
87
- parts.push([
88
- `- ${record.tool_name || 'tool'} (${record.tool_use_id || 'unknown'})`,
89
- ` input: ${record.input}`,
90
- ` result: ${record.response}`,
91
- ].join('\n'));
92
- }
93
- }
94
- if (input.last_assistant_message) parts.push(`Final assistant response:\n${truncate(input.last_assistant_message, 60000)}`);
95
- return parts.filter(Boolean).join('\n\n');
41
+ return [
42
+ prompt ? `User request:
43
+ ${truncate(prompt, 40000)}` : null,
44
+ input.last_assistant_message
45
+ ? `Final assistant response:
46
+ ${truncate(input.last_assistant_message, 60000)}`
47
+ : null,
48
+ ].filter(Boolean).join('\n\n');
96
49
  }
97
50
 
98
51
  async function handleInject(input, context) {
@@ -142,9 +95,10 @@ async function captureTurn(input, context, partial = false) {
142
95
  if (!partial && state.capturedTurns?.[turnId]) {
143
96
  return { ok: true, skipped: 'deduplicated', handle: state.capturedTurns[turnId] };
144
97
  }
145
- const records = readTrace(sessionId, turnId, context.env);
146
- if (!input.last_assistant_message && records.length === 0) return { ok: true, skipped: 'empty' };
147
- const content = turnContent({ ...input, turn_id: turnId }, state, records, partial);
98
+ const prompt = state.prompts?.[turnId] || state.lastPrompt || '';
99
+ if (!partial && !input.last_assistant_message) return { ok: true, skipped: 'empty' };
100
+ if (partial && !prompt && !input.last_assistant_message) return { ok: true, skipped: 'empty' };
101
+ const content = turnContent({ ...input, turn_id: turnId }, state);
148
102
  const kind = partial ? 'checkpoint' : 'turn';
149
103
  const handle = memoryHandle(context.project.handle, kind, content);
150
104
  if ((state.capturedHandles || []).includes(handle)) return { ok: true, skipped: 'deduplicated', handle };
@@ -166,14 +120,14 @@ async function captureTurn(input, context, partial = false) {
166
120
  if (!partial && state.prompts) delete state.prompts[turnId];
167
121
  state.lastCaptureAt = new Date().toISOString();
168
122
  saveSessionState(sessionId, state, context.env);
169
- if (!partial) removeTrace(sessionId, turnId, context.env);
170
123
  }
171
124
  recordHealth(partial ? 'flush' : 'capture', {
172
125
  ok: result.ok,
173
126
  status: result.status,
174
127
  project: context.project.handle,
175
128
  handle,
176
- toolCalls: records.length,
129
+ hasPrompt: Boolean(prompt),
130
+ hasFinalResponse: Boolean(input.last_assistant_message),
177
131
  }, context.env);
178
132
  return result;
179
133
  }
@@ -222,7 +176,6 @@ async function run(kind, input, options = {}) {
222
176
  switch (kind) {
223
177
  case 'inject': return handleInject(input, context);
224
178
  case 'session-start': return handleSessionStart(input, context);
225
- case 'trace': appendTrace(input, env); return;
226
179
  case 'capture': return captureTurn(input, context, false);
227
180
  case 'capture-subagent': return captureSubagent(input, context);
228
181
  case 'flush': return captureTurn(input, context, true);
@@ -232,7 +185,7 @@ async function run(kind, input, options = {}) {
232
185
 
233
186
  async function main() {
234
187
  const kind = process.argv[2];
235
- const wallClock = setTimeout(() => process.exit(0), kind === 'trace' ? 2500 : kind === 'inject' ? 7500 : 18000);
188
+ const wallClock = setTimeout(() => process.exit(0), kind === 'inject' ? 7500 : 18000);
236
189
  wallClock.unref();
237
190
  let input = {};
238
191
  try { input = JSON.parse((await readStdin()) || '{}'); } catch { debug('invalid hook JSON'); }
@@ -247,9 +200,6 @@ module.exports = {
247
200
  readStdin,
248
201
  truncate,
249
202
  emitContext,
250
- appendTrace,
251
- readTrace,
252
- removeTrace,
253
203
  turnContent,
254
204
  handleInject,
255
205
  handleSessionStart,