iranti 0.1.1 → 0.1.3

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
@@ -178,24 +178,24 @@ Release guide: [`docs/guides/releasing.md`](docs/guides/releasing.md)
178
178
  Iranti ships a local stdio MCP server for Claude Code and other MCP clients:
179
179
 
180
180
  ```bash
181
- npm run build
182
- node dist/scripts/iranti-mcp.js
181
+ iranti mcp
183
182
  ```
184
183
 
185
- Use it with a project-local `.mcp.json`, and optionally add the Claude Code hook helper for `SessionStart` and `UserPromptSubmit`.
184
+ Use it with a project-local `.mcp.json`, and optionally add `iranti claude-hook` for `SessionStart` and `UserPromptSubmit`.
186
185
 
187
186
  Guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
188
187
 
189
188
  ### Codex via MCP
190
189
 
191
- Codex uses a global MCP registry rather than a project-local `.mcp.json`. Register Iranti once, then launch Codex in this repo so `AGENTS.md` applies:
190
+ Codex uses a global MCP registry rather than a project-local `.mcp.json`. Register Iranti once, then launch Codex in the bound project so `.env.iranti` is in scope:
192
191
 
193
192
  ```bash
194
- npm run build
195
- npm run codex:setup
196
- npm run codex:run
193
+ iranti codex-setup
194
+ codex -C /path/to/your/project
197
195
  ```
198
196
 
197
+ When `iranti codex-setup` is run from a project directory, it automatically captures that project's `.env.iranti` as `IRANTI_PROJECT_ENV` so Codex resolves the correct Iranti instance consistently.
198
+
199
199
  Guide: [`docs/guides/codex.md`](docs/guides/codex.md)
200
200
 
201
201
  ---
@@ -6,6 +6,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  require("dotenv/config");
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const sdk_1 = require("../src/sdk");
9
+ const runtimeEnv_1 = require("../src/lib/runtimeEnv");
10
+ const MEMORY_NEED_POSITIVE_PATTERNS = [
11
+ /\bwhat(?:'s| is| was)?\s+my\b/i,
12
+ /\bdo you remember\b/i,
13
+ /\bremind me\b/i,
14
+ /\bmy\s+(?:favorite|favourite|name|email|phone|address|city|country|movie|snack|color|colour)\b/i,
15
+ /\bwe decided\b/i,
16
+ /\bearlier\b/i,
17
+ /\bprevious(?:ly)?\b/i,
18
+ /\bagain\b/i,
19
+ ];
20
+ const MEMORY_NEED_NEGATIVE_PATTERNS = [
21
+ /^\s*(hi|hello|hey|yo|sup|good (?:morning|afternoon|evening))\b[!.?\s]*$/i,
22
+ /^\s*(thanks|thank you|cool|great|nice)\b[!.?\s]*$/i,
23
+ ];
9
24
  function printHelp() {
10
25
  console.log([
11
26
  'Claude Code -> Iranti hook helper',
@@ -14,6 +29,11 @@ function printHelp() {
14
29
  ' ts-node scripts/claude-code-memory-hook.ts --event SessionStart',
15
30
  ' ts-node scripts/claude-code-memory-hook.ts --event UserPromptSubmit',
16
31
  '',
32
+ 'Optional flags:',
33
+ ' --project-env <path> Explicit .env.iranti path',
34
+ ' --instance-env <path> Explicit instance env path',
35
+ ' --env-file <path> Explicit base .env path',
36
+ '',
17
37
  'Reads Claude Code hook JSON from stdin and returns hookSpecificOutput.additionalContext on stdout.',
18
38
  ].join('\n'));
19
39
  }
@@ -77,6 +97,9 @@ function getDefaultAgentId(payload) {
77
97
  const explicit = process.env.IRANTI_CLAUDE_AGENT_ID?.trim();
78
98
  if (explicit)
79
99
  return explicit;
100
+ const projectBindingAgent = process.env.IRANTI_AGENT_ID?.trim();
101
+ if (projectBindingAgent)
102
+ return projectBindingAgent;
80
103
  const base = path_1.default.basename(getCwd(payload));
81
104
  return `claude_code_${slugify(base || 'project')}`;
82
105
  }
@@ -85,6 +108,10 @@ function getEntityHints(payload) {
85
108
  const cwd = getCwd(payload);
86
109
  const projectHint = `project/${slugify(path_1.default.basename(cwd) || 'project')}`;
87
110
  out.add(projectHint);
111
+ const memoryEntity = process.env.IRANTI_MEMORY_ENTITY?.trim();
112
+ if (memoryEntity) {
113
+ out.add(memoryEntity);
114
+ }
88
115
  const envHints = (process.env.IRANTI_CLAUDE_ENTITY_HINTS ?? '')
89
116
  .split(',')
90
117
  .map((value) => value.trim())
@@ -105,7 +132,17 @@ async function ensureHookAgent(iranti, payload) {
105
132
  return agentId;
106
133
  }
107
134
  function getPrompt(payload) {
108
- return typeof payload.prompt === 'string' ? payload.prompt.trim() : '';
135
+ const candidates = [
136
+ payload.prompt,
137
+ payload.message,
138
+ payload.text,
139
+ ];
140
+ for (const candidate of candidates) {
141
+ if (typeof candidate === 'string' && candidate.trim()) {
142
+ return candidate.trim();
143
+ }
144
+ }
145
+ return '';
109
146
  }
110
147
  function getMaxFacts() {
111
148
  const raw = Number(process.env.IRANTI_CLAUDE_MAX_FACTS ?? 6);
@@ -113,41 +150,26 @@ function getMaxFacts() {
113
150
  return 6;
114
151
  return Math.min(12, Math.trunc(raw));
115
152
  }
116
- function formatHandshakeContext(brief, cwd) {
117
- const facts = Array.isArray(brief?.workingMemory) ? brief.workingMemory.slice(0, getMaxFacts()) : [];
153
+ function formatSessionContext(facts, cwd) {
154
+ const limited = facts.slice(0, getMaxFacts());
118
155
  const lines = [
119
156
  '[Iranti Session Memory]',
120
157
  `Project: ${path_1.default.basename(cwd)}`,
121
158
  ];
122
- if (typeof brief?.inferredTaskType === 'string' && brief.inferredTaskType) {
123
- lines.push(`Task type: ${brief.inferredTaskType}`);
124
- }
125
- if (facts.length > 0) {
159
+ if (limited.length > 0) {
126
160
  lines.push('Relevant memory:');
127
- for (const fact of facts) {
128
- const label = typeof fact?.entityKey === 'string' ? fact.entityKey : `${fact?.entityType ?? 'entity'}/${fact?.entityId ?? 'unknown'}`;
129
- const summary = typeof fact?.summary === 'string' ? fact.summary : fact?.valueSummary;
130
- if (!summary)
131
- continue;
132
- lines.push(`- ${label}: ${summary}`);
161
+ for (const fact of limited) {
162
+ lines.push(`- ${fact.entity}/${fact.key}: ${fact.summary}`);
133
163
  }
134
164
  }
135
165
  return lines.join('\n');
136
166
  }
137
- function formatAttendContext(attend) {
138
- const facts = Array.isArray(attend?.facts) ? attend.facts.slice(0, getMaxFacts()) : [];
139
- if (!attend?.shouldInject || facts.length === 0)
167
+ function formatPromptContext(facts) {
168
+ if (facts.length === 0)
140
169
  return '';
141
170
  const lines = ['[Iranti Retrieved Memory]'];
142
- if (typeof attend?.reason === 'string' && attend.reason) {
143
- lines.push(`Reason: ${attend.reason}`);
144
- }
145
171
  for (const fact of facts) {
146
- const label = typeof fact?.entityKey === 'string' ? fact.entityKey : `${fact?.entityType ?? 'entity'}/${fact?.entityId ?? 'unknown'}`;
147
- const summary = typeof fact?.summary === 'string' ? fact.summary : fact?.valueSummary;
148
- if (!summary)
149
- continue;
150
- lines.push(`- ${label}: ${summary}`);
172
+ lines.push(`- ${fact.entity}/${fact.key}: ${fact.summary}`);
151
173
  }
152
174
  return lines.join('\n');
153
175
  }
@@ -160,6 +182,98 @@ function emitHookContext(event, additionalContext) {
160
182
  };
161
183
  process.stdout.write(`${JSON.stringify(payload)}\n`);
162
184
  }
185
+ function shouldFetchMemory(prompt) {
186
+ const normalized = prompt.trim();
187
+ if (!normalized)
188
+ return false;
189
+ if (MEMORY_NEED_NEGATIVE_PATTERNS.some((pattern) => pattern.test(normalized))) {
190
+ return false;
191
+ }
192
+ if (MEMORY_NEED_POSITIVE_PATTERNS.some((pattern) => pattern.test(normalized))) {
193
+ return true;
194
+ }
195
+ if (/\b(my|our|we)\b/i.test(normalized)) {
196
+ return true;
197
+ }
198
+ return normalized.includes('/');
199
+ }
200
+ function dedupeFacts(facts) {
201
+ const byKey = new Map();
202
+ for (const fact of facts) {
203
+ const identity = `${fact.entity}/${fact.key}`;
204
+ const existing = byKey.get(identity);
205
+ if (!existing || fact.confidence > existing.confidence) {
206
+ byKey.set(identity, fact);
207
+ }
208
+ }
209
+ return Array.from(byKey.values())
210
+ .sort((a, b) => b.confidence - a.confidence || a.entity.localeCompare(b.entity) || a.key.localeCompare(b.key))
211
+ .slice(0, getMaxFacts());
212
+ }
213
+ async function loadAttendantStateFacts(iranti, agent) {
214
+ const state = await iranti.query(`agent/${agent}`, 'attendant_state');
215
+ if (!state.found || !state.value || typeof state.value !== 'object') {
216
+ return [];
217
+ }
218
+ const workingMemory = Array.isArray(state.value.workingMemory)
219
+ ? state.value.workingMemory
220
+ : [];
221
+ return workingMemory.flatMap((entry) => {
222
+ const entityKey = typeof entry.entityKey === 'string' ? entry.entityKey.trim() : '';
223
+ const summary = typeof entry.summary === 'string' ? entry.summary.trim() : '';
224
+ if (!entityKey || !summary)
225
+ return [];
226
+ const segments = entityKey.split('/');
227
+ if (segments.length < 3)
228
+ return [];
229
+ return [{
230
+ entity: `${segments[0]}/${segments[1]}`,
231
+ key: segments.slice(2).join('/'),
232
+ summary,
233
+ confidence: typeof entry.confidence === 'number' ? entry.confidence : 0,
234
+ source: typeof entry.source === 'string' ? entry.source : 'attendant',
235
+ }];
236
+ });
237
+ }
238
+ async function loadEntityFacts(iranti, entities) {
239
+ const out = [];
240
+ for (const entity of entities) {
241
+ const trimmed = entity.trim();
242
+ if (!trimmed)
243
+ continue;
244
+ const entries = await iranti.queryAll(trimmed).catch(() => []);
245
+ for (const entry of entries) {
246
+ out.push({
247
+ entity: trimmed,
248
+ key: entry.key,
249
+ summary: entry.summary,
250
+ confidence: entry.confidence,
251
+ source: entry.source,
252
+ });
253
+ }
254
+ }
255
+ return out;
256
+ }
257
+ async function searchPromptFacts(iranti, prompt, entityHints) {
258
+ if (!prompt.trim())
259
+ return [];
260
+ const results = await iranti.search({
261
+ query: prompt,
262
+ limit: getMaxFacts(),
263
+ minScore: Number(process.env.IRANTI_CLAUDE_MIN_SEARCH_SCORE ?? 0.05),
264
+ }).catch(() => []);
265
+ const searched = results.map((result) => ({
266
+ entity: result.entity,
267
+ key: result.key,
268
+ summary: result.summary,
269
+ confidence: result.confidence,
270
+ source: result.source,
271
+ }));
272
+ if (searched.length > 0) {
273
+ return searched;
274
+ }
275
+ return loadEntityFacts(iranti, entityHints);
276
+ }
163
277
  async function main() {
164
278
  if (process.argv.includes('--help') || process.argv.includes('-h')) {
165
279
  printHelp();
@@ -171,6 +285,12 @@ async function main() {
171
285
  throw new Error('--event must be SessionStart or UserPromptSubmit');
172
286
  }
173
287
  const payload = parsePayload(await readStdin());
288
+ (0, runtimeEnv_1.loadRuntimeEnv)({
289
+ payloadCwd: getCwd(payload),
290
+ projectEnvFile: args['project-env'],
291
+ instanceEnvFile: args['instance-env'],
292
+ explicitEnvFile: args['env-file'],
293
+ });
174
294
  const cwd = getCwd(payload);
175
295
  const iranti = new sdk_1.Iranti({
176
296
  connectionString: requireConnectionString(),
@@ -179,30 +299,27 @@ async function main() {
179
299
  const agent = await ensureHookAgent(iranti, payload);
180
300
  const entityHints = getEntityHints(payload);
181
301
  if (event === 'SessionStart') {
182
- const task = process.env.IRANTI_CLAUDE_SESSION_TASK?.trim()
183
- || `Claude Code session in ${path_1.default.basename(cwd)}`;
184
- const brief = await iranti.handshake({
185
- agent,
186
- task,
187
- recentMessages: [],
188
- });
189
- emitHookContext(event, formatHandshakeContext(brief, cwd));
190
- return;
302
+ const persistedFacts = await loadAttendantStateFacts(iranti, agent);
303
+ const directFacts = persistedFacts.length > 0
304
+ ? persistedFacts
305
+ : await loadEntityFacts(iranti, entityHints);
306
+ emitHookContext(event, formatSessionContext(dedupeFacts(directFacts), cwd));
307
+ process.exit(0);
191
308
  }
192
309
  const prompt = getPrompt(payload);
193
- if (!prompt)
194
- return;
195
- const attend = await iranti.attend({
196
- agent,
197
- latestMessage: prompt,
198
- currentContext: prompt,
199
- entityHints,
200
- maxFacts: getMaxFacts(),
201
- });
202
- const context = formatAttendContext(attend);
203
- if (!context)
204
- return;
310
+ if (!prompt) {
311
+ process.exit(0);
312
+ }
313
+ if (!shouldFetchMemory(prompt)) {
314
+ process.exit(0);
315
+ }
316
+ const facts = await searchPromptFacts(iranti, prompt, entityHints);
317
+ const context = formatPromptContext(dedupeFacts(facts));
318
+ if (!context) {
319
+ process.exit(0);
320
+ }
205
321
  emitHookContext(event, context);
322
+ process.exit(0);
206
323
  }
207
324
  main().catch((error) => {
208
325
  console.error('[claude-code-memory-hook] fatal:', error instanceof Error ? error.message : String(error));
@@ -11,6 +11,7 @@ function parseArgs(argv) {
11
11
  name: 'iranti',
12
12
  agent: 'codex_code',
13
13
  source: 'Codex',
14
+ useLocalScript: false,
14
15
  };
15
16
  for (let index = 0; index < argv.length; index += 1) {
16
17
  const token = argv[index];
@@ -40,6 +41,15 @@ function parseArgs(argv) {
40
41
  options.provider = next.trim();
41
42
  index += 1;
42
43
  break;
44
+ case '--project-env':
45
+ if (!next)
46
+ throw new Error('--project-env requires a value.');
47
+ options.projectEnv = next.trim();
48
+ index += 1;
49
+ break;
50
+ case '--local-script':
51
+ options.useLocalScript = true;
52
+ break;
43
53
  case '--help':
44
54
  case '-h':
45
55
  printHelp();
@@ -56,20 +66,40 @@ function printHelp() {
56
66
  'Configure Codex to use the local Iranti MCP server.',
57
67
  '',
58
68
  'Usage:',
59
- ' ts-node scripts/codex-setup.ts [--name iranti] [--agent codex_code] [--source Codex] [--provider openai]',
69
+ ' ts-node scripts/codex-setup.ts [--name iranti] [--agent codex_code] [--source Codex] [--provider openai] [--project-env path] [--local-script]',
60
70
  '',
61
71
  'Notes:',
62
72
  ' - Registers a global Codex MCP entry using `codex mcp add`.',
63
- ' - Does not store DATABASE_URL in Codex config; iranti-mcp loads .env from this repo at runtime.',
73
+ ' - Prefers the installed CLI path: `iranti mcp`.',
74
+ ' - Auto-detects .env.iranti from the current working directory and stores it as IRANTI_PROJECT_ENV.',
75
+ ' - Use --local-script only if you need to point Codex at this repo build directly.',
76
+ ' - Does not store DATABASE_URL in Codex config; iranti-mcp loads project/instance env at runtime.',
64
77
  ' - Replaces any existing MCP entry with the same name.',
65
78
  ].join('\n'));
66
79
  }
80
+ function quoteForCmd(arg) {
81
+ if (arg.length === 0)
82
+ return '""';
83
+ if (!/[ \t"&()<>|^]/.test(arg))
84
+ return arg;
85
+ return `"${arg.replace(/"/g, '\\"')}"`;
86
+ }
67
87
  function run(command, args, cwd) {
68
- const result = (0, node_child_process_1.spawnSync)(command, args, {
69
- cwd,
70
- encoding: 'utf8',
71
- stdio: ['ignore', 'pipe', 'pipe'],
72
- });
88
+ const result = process.platform === 'win32'
89
+ ? (0, node_child_process_1.spawnSync)(process.env.ComSpec ?? 'cmd.exe', [
90
+ '/d',
91
+ '/c',
92
+ [command, ...args].map(quoteForCmd).join(' '),
93
+ ], {
94
+ cwd,
95
+ encoding: 'utf8',
96
+ stdio: ['ignore', 'pipe', 'pipe'],
97
+ })
98
+ : (0, node_child_process_1.spawnSync)(command, args, {
99
+ cwd,
100
+ encoding: 'utf8',
101
+ stdio: ['ignore', 'pipe', 'pipe'],
102
+ });
73
103
  if (result.error) {
74
104
  throw result.error;
75
105
  }
@@ -88,14 +118,50 @@ function tryRun(command, args, cwd) {
88
118
  return null;
89
119
  }
90
120
  }
121
+ function findPackageRoot(startDir) {
122
+ let dir = startDir;
123
+ for (let i = 0; i < 6; i += 1) {
124
+ const pkgPath = node_path_1.default.join(dir, 'package.json');
125
+ if (node_fs_1.default.existsSync(pkgPath)) {
126
+ return dir;
127
+ }
128
+ const parent = node_path_1.default.dirname(dir);
129
+ if (parent === dir)
130
+ break;
131
+ dir = parent;
132
+ }
133
+ return node_path_1.default.resolve(startDir, '..');
134
+ }
135
+ function resolveProjectEnv(options) {
136
+ const explicit = options.projectEnv?.trim();
137
+ if (explicit) {
138
+ const resolved = node_path_1.default.resolve(explicit);
139
+ if (!node_fs_1.default.existsSync(resolved)) {
140
+ throw new Error(`Project env file not found: ${resolved}`);
141
+ }
142
+ return resolved;
143
+ }
144
+ const candidate = node_path_1.default.resolve(process.cwd(), '.env.iranti');
145
+ return node_fs_1.default.existsSync(candidate) ? candidate : undefined;
146
+ }
147
+ function canUseInstalledIranti(repoRoot) {
148
+ try {
149
+ run('iranti', ['mcp', '--help'], repoRoot);
150
+ return true;
151
+ }
152
+ catch {
153
+ return false;
154
+ }
155
+ }
91
156
  function main() {
92
157
  const options = parseArgs(process.argv.slice(2));
93
- const repoRoot = node_path_1.default.resolve(__dirname, '..');
158
+ const repoRoot = findPackageRoot(__dirname);
94
159
  const mcpScript = node_path_1.default.join(repoRoot, 'dist', 'scripts', 'iranti-mcp.js');
95
- if (!node_fs_1.default.existsSync(mcpScript)) {
96
- throw new Error(`Missing build artifact: ${mcpScript}. Run "npm run build" first.`);
97
- }
98
160
  run('codex', ['--version'], repoRoot);
161
+ const useInstalled = !options.useLocalScript && canUseInstalledIranti(repoRoot);
162
+ if (!useInstalled && !node_fs_1.default.existsSync(mcpScript)) {
163
+ throw new Error(`Missing build artifact: ${mcpScript}. Run "npm run build" first, or install iranti globally and rerun without --local-script.`);
164
+ }
99
165
  const existing = tryRun('codex', ['mcp', 'get', options.name, '--json'], repoRoot);
100
166
  if (existing !== null) {
101
167
  run('codex', ['mcp', 'remove', options.name], repoRoot);
@@ -109,16 +175,39 @@ function main() {
109
175
  '--env',
110
176
  `IRANTI_MCP_DEFAULT_SOURCE=${options.source}`,
111
177
  ];
178
+ const projectEnv = resolveProjectEnv(options);
179
+ if (projectEnv) {
180
+ addArgs.push('--env', `IRANTI_PROJECT_ENV=${projectEnv}`);
181
+ }
112
182
  if (options.provider) {
113
183
  addArgs.push('--env', `LLM_PROVIDER=${options.provider}`);
114
184
  }
115
- addArgs.push('--', 'node', mcpScript);
185
+ if (useInstalled) {
186
+ addArgs.push('--', 'iranti', 'mcp');
187
+ }
188
+ else {
189
+ addArgs.push('--', 'node', mcpScript);
190
+ }
116
191
  run('codex', addArgs, repoRoot);
117
192
  const registered = run('codex', ['mcp', 'get', options.name], repoRoot);
118
193
  console.log(registered);
119
194
  console.log('');
120
195
  console.log('Codex is now configured to use Iranti through MCP.');
121
- console.log(`Launch with: codex -C "${repoRoot}"`);
196
+ if (useInstalled) {
197
+ console.log('Registration target: installed CLI (`iranti mcp`)');
198
+ if (projectEnv) {
199
+ console.log(`Project binding: ${projectEnv}`);
200
+ }
201
+ console.log('Launch Codex in the project you want to bind to Iranti, for example:');
202
+ console.log(' codex -C C:\\path\\to\\your\\project');
203
+ }
204
+ else {
205
+ console.log(`Registration target: repo build (${mcpScript})`);
206
+ if (projectEnv) {
207
+ console.log(`Project binding: ${projectEnv}`);
208
+ }
209
+ console.log(`Launch with: codex -C "${repoRoot}"`);
210
+ }
122
211
  }
123
212
  main();
124
213
  //# sourceMappingURL=codex-setup.js.map
@@ -8,6 +8,7 @@ const fs_1 = __importDefault(require("fs"));
8
8
  const promises_1 = __importDefault(require("fs/promises"));
9
9
  const os_1 = __importDefault(require("os"));
10
10
  const path_1 = __importDefault(require("path"));
11
+ const child_process_1 = require("child_process");
11
12
  const promises_2 = __importDefault(require("readline/promises"));
12
13
  const stream_1 = require("stream");
13
14
  const client_1 = require("../src/library/client");
@@ -118,6 +119,54 @@ function getPackageVersion() {
118
119
  }
119
120
  return '0.0.0';
120
121
  }
122
+ function builtScriptPath(scriptName) {
123
+ return path_1.default.resolve(__dirname, `${scriptName}.js`);
124
+ }
125
+ async function handoffToScript(scriptName, rawArgs) {
126
+ const builtPath = builtScriptPath(scriptName);
127
+ if (fs_1.default.existsSync(builtPath)) {
128
+ await new Promise((resolve, reject) => {
129
+ const child = (0, child_process_1.spawn)(process.execPath, [builtPath, ...rawArgs], {
130
+ stdio: 'inherit',
131
+ env: process.env,
132
+ });
133
+ child.on('error', reject);
134
+ child.on('exit', (code, signal) => {
135
+ if (signal) {
136
+ reject(new Error(`${scriptName} terminated with signal ${signal}`));
137
+ return;
138
+ }
139
+ if ((code ?? 0) !== 0) {
140
+ process.exit(code ?? 1);
141
+ }
142
+ resolve();
143
+ });
144
+ });
145
+ return;
146
+ }
147
+ const sourcePath = path_1.default.resolve(process.cwd(), 'scripts', `${scriptName}.ts`);
148
+ if (!fs_1.default.existsSync(sourcePath)) {
149
+ throw new Error(`Unable to locate ${scriptName} implementation.`);
150
+ }
151
+ await new Promise((resolve, reject) => {
152
+ const child = (0, child_process_1.spawn)('npx', ['ts-node', sourcePath, ...rawArgs], {
153
+ stdio: 'inherit',
154
+ env: process.env,
155
+ shell: process.platform === 'win32',
156
+ });
157
+ child.on('error', reject);
158
+ child.on('exit', (code, signal) => {
159
+ if (signal) {
160
+ reject(new Error(`${scriptName} terminated with signal ${signal}`));
161
+ return;
162
+ }
163
+ if ((code ?? 0) !== 0) {
164
+ process.exit(code ?? 1);
165
+ }
166
+ resolve();
167
+ });
168
+ });
169
+ }
121
170
  async function ensureDir(dir) {
122
171
  await promises_1.default.mkdir(dir, { recursive: true });
123
172
  }
@@ -1077,7 +1126,12 @@ Diagnostics:
1077
1126
  iranti doctor [--instance <name>] [--scope user|system] [--env <file>] [--json]
1078
1127
  iranti status [--scope user|system] [--json]
1079
1128
  iranti upgrade [--json]
1080
- `);
1129
+
1130
+ Integrations:
1131
+ iranti mcp [--help]
1132
+ iranti claude-hook --event SessionStart|UserPromptSubmit [--project-env <path>] [--instance-env <path>] [--env-file <path>]
1133
+ iranti codex-setup [--name iranti] [--agent codex_code] [--source Codex] [--provider openai] [--project-env <path>] [--local-script]
1134
+ `);
1081
1135
  }
1082
1136
  async function main() {
1083
1137
  const args = parseArgs(process.argv.slice(2));
@@ -1150,6 +1204,18 @@ async function main() {
1150
1204
  await upgradeCommand(args);
1151
1205
  return;
1152
1206
  }
1207
+ if (args.command === 'mcp') {
1208
+ await handoffToScript('iranti-mcp', process.argv.slice(3));
1209
+ return;
1210
+ }
1211
+ if (args.command === 'claude-hook') {
1212
+ await handoffToScript('claude-code-memory-hook', process.argv.slice(3));
1213
+ return;
1214
+ }
1215
+ if (args.command === 'codex-setup') {
1216
+ await handoffToScript('codex-setup', process.argv.slice(3));
1217
+ return;
1218
+ }
1153
1219
  throw new Error(`Unknown command '${args.command}'. Run: iranti help`);
1154
1220
  }
1155
1221
  main().catch((err) => {
@@ -32,35 +32,13 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
- const node_fs_1 = __importDefault(require("node:fs"));
40
- const node_path_1 = __importDefault(require("node:path"));
41
- const dotenv_1 = __importDefault(require("dotenv"));
42
36
  const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
43
37
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
44
38
  const z = __importStar(require("zod/v4"));
45
39
  const sdk_1 = require("../src/sdk");
46
- function loadEnv() {
47
- const explicitPath = process.env.IRANTI_ENV_FILE?.trim();
48
- const candidates = explicitPath
49
- ? [explicitPath]
50
- : [
51
- node_path_1.default.resolve(process.cwd(), '.env'),
52
- node_path_1.default.resolve(__dirname, '..', '.env'),
53
- node_path_1.default.resolve(__dirname, '..', '..', '.env'),
54
- ];
55
- for (const candidate of candidates) {
56
- if (candidate && node_fs_1.default.existsSync(candidate)) {
57
- dotenv_1.default.config({ path: candidate });
58
- return;
59
- }
60
- }
61
- dotenv_1.default.config();
62
- }
63
- loadEnv();
40
+ const runtimeEnv_1 = require("../src/lib/runtimeEnv");
41
+ (0, runtimeEnv_1.loadRuntimeEnv)();
64
42
  function printHelp() {
65
43
  console.log([
66
44
  'Iranti MCP Server',
@@ -72,6 +50,8 @@ function printHelp() {
72
50
  'Environment:',
73
51
  ' DATABASE_URL PostgreSQL connection string (required)',
74
52
  ' LLM_PROVIDER Optional Iranti provider override',
53
+ ' IRANTI_PROJECT_ENV Optional project binding path (.env.iranti)',
54
+ ' IRANTI_INSTANCE_ENV Optional instance env path',
75
55
  ' IRANTI_MCP_DEFAULT_AGENT Default agent id (default: claude_code)',
76
56
  ' IRANTI_MCP_AGENT_NAME Default agent display name',
77
57
  ' IRANTI_MCP_AGENT_DESCRIPTION Default agent description',
@@ -89,7 +69,9 @@ function requireConnectionString() {
89
69
  return connectionString;
90
70
  }
91
71
  function defaultAgentId() {
92
- return process.env.IRANTI_MCP_DEFAULT_AGENT?.trim() || 'claude_code';
72
+ return process.env.IRANTI_MCP_DEFAULT_AGENT?.trim()
73
+ || process.env.IRANTI_AGENT_ID?.trim()
74
+ || 'claude_code';
93
75
  }
94
76
  function defaultWriteSource() {
95
77
  return process.env.IRANTI_MCP_DEFAULT_SOURCE?.trim() || 'ClaudeCode';
@@ -162,7 +144,7 @@ async function main() {
162
144
  await ensureDefaultAgent(iranti);
163
145
  const server = new mcp_js_1.McpServer({
164
146
  name: 'iranti-mcp',
165
- version: '0.1.1',
147
+ version: '0.1.3',
166
148
  });
167
149
  server.registerTool('iranti_handshake', {
168
150
  description: 'Initialize or refresh Claude working memory for the current task.',
@@ -15,7 +15,7 @@ const STAFF_ENTRIES = [
15
15
  entityId: 'librarian',
16
16
  key: 'operating_rules',
17
17
  valueRaw: {
18
- version: '0.1.1',
18
+ version: '0.1.3',
19
19
  rules: [
20
20
  'All writes from external agents go through the Librarian — never directly to the database',
21
21
  'Check for existing entries before every write',
@@ -39,7 +39,7 @@ const STAFF_ENTRIES = [
39
39
  entityId: 'attendant',
40
40
  key: 'operating_rules',
41
41
  valueRaw: {
42
- version: '0.1.1',
42
+ version: '0.1.3',
43
43
  rules: [
44
44
  'Assigned one-per-external-agent — serve the agent, not the user',
45
45
  'On handshake: read AGENTS.md and MCP config, query Librarian for relevant rules and task context',
@@ -61,7 +61,7 @@ const STAFF_ENTRIES = [
61
61
  entityId: 'archivist',
62
62
  key: 'operating_rules',
63
63
  valueRaw: {
64
- version: '0.1.1',
64
+ version: '0.1.3',
65
65
  rules: [
66
66
  'Run on schedule or when conflict flags exceed threshold — not on every write',
67
67
  'Scan for expired, low-confidence, flagged, and duplicate entries',
@@ -82,7 +82,7 @@ const STAFF_ENTRIES = [
82
82
  entityType: 'system',
83
83
  entityId: 'library',
84
84
  key: 'schema_version',
85
- valueRaw: { version: '0.1.1' },
85
+ valueRaw: { version: '0.1.3' },
86
86
  valueSummary: 'Current Library schema version.',
87
87
  confidence: 100,
88
88
  source: 'seed',
@@ -95,7 +95,7 @@ const STAFF_ENTRIES = [
95
95
  key: 'initialization_log',
96
96
  valueRaw: {
97
97
  initializedAt: new Date().toISOString(),
98
- seedVersion: '0.1.1',
98
+ seedVersion: '0.1.3',
99
99
  },
100
100
  valueSummary: 'Record of when and how this Library was initialized.',
101
101
  confidence: 100,
@@ -108,7 +108,7 @@ const STAFF_ENTRIES = [
108
108
  entityId: 'ontology',
109
109
  key: 'core_schema',
110
110
  valueRaw: {
111
- version: '0.1.1',
111
+ version: '0.1.3',
112
112
  states: ['candidate', 'provisional', 'canonical'],
113
113
  coreEntityTypes: [
114
114
  'person',
@@ -156,7 +156,7 @@ const STAFF_ENTRIES = [
156
156
  entityId: 'ontology',
157
157
  key: 'extension_registry',
158
158
  valueRaw: {
159
- version: '0.1.1',
159
+ version: '0.1.3',
160
160
  namespaces: {
161
161
  education: {
162
162
  status: 'provisional',
@@ -187,7 +187,7 @@ const STAFF_ENTRIES = [
187
187
  entityId: 'ontology',
188
188
  key: 'candidate_terms',
189
189
  valueRaw: {
190
- version: '0.1.1',
190
+ version: '0.1.3',
191
191
  terms: [],
192
192
  },
193
193
  valueSummary: 'Staging area for ontology terms detected repeatedly but not yet promoted.',
@@ -201,7 +201,7 @@ const STAFF_ENTRIES = [
201
201
  entityId: 'ontology',
202
202
  key: 'promotion_policy',
203
203
  valueRaw: {
204
- version: '0.1.1',
204
+ version: '0.1.3',
205
205
  candidateToProvisional: {
206
206
  minSeenCount: 3,
207
207
  minDistinctAgents: 2,
@@ -237,7 +237,7 @@ const STAFF_ENTRIES = [
237
237
  entityId: 'ontology',
238
238
  key: 'change_log',
239
239
  valueRaw: {
240
- version: '0.1.1',
240
+ version: '0.1.3',
241
241
  events: [
242
242
  {
243
243
  at: new Date().toISOString(),
@@ -69,7 +69,7 @@ app.use(express_1.default.json({ limit: process.env.IRANTI_MAX_BODY_BYTES ?? '25
69
69
  app.get(ROUTES.health, (_req, res) => {
70
70
  res.json({
71
71
  status: 'ok',
72
- version: '0.1.1',
72
+ version: '0.1.3',
73
73
  provider: process.env.LLM_PROVIDER ?? 'mock',
74
74
  });
75
75
  });
@@ -0,0 +1,15 @@
1
+ type RuntimeEnvOptions = {
2
+ cwd?: string;
3
+ payloadCwd?: string;
4
+ projectEnvFile?: string;
5
+ instanceEnvFile?: string;
6
+ explicitEnvFile?: string;
7
+ };
8
+ type RuntimeEnvLoadResult = {
9
+ loadedFiles: string[];
10
+ projectEnvFile?: string;
11
+ instanceEnvFile?: string;
12
+ };
13
+ export declare function loadRuntimeEnv(options?: RuntimeEnvOptions): RuntimeEnvLoadResult;
14
+ export {};
15
+ //# sourceMappingURL=runtimeEnv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtimeEnv.d.ts","sourceRoot":"","sources":["../../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAuDF,wBAAgB,cAAc,CAAC,OAAO,GAAE,iBAAsB,GAAG,oBAAoB,CAsCpF"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadRuntimeEnv = loadRuntimeEnv;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const dotenv_1 = __importDefault(require("dotenv"));
10
+ function parseEnvFile(filePath) {
11
+ const raw = fs_1.default.readFileSync(filePath, 'utf-8');
12
+ return dotenv_1.default.parse(raw);
13
+ }
14
+ function applyEnvVars(vars, initialEnvKeys) {
15
+ for (const [key, value] of Object.entries(vars)) {
16
+ if (initialEnvKeys.has(key))
17
+ continue;
18
+ process.env[key] = value;
19
+ }
20
+ }
21
+ function dedupePaths(paths) {
22
+ const seen = new Set();
23
+ const out = [];
24
+ for (const candidate of paths) {
25
+ if (!candidate)
26
+ continue;
27
+ const resolved = path_1.default.resolve(candidate);
28
+ if (seen.has(resolved))
29
+ continue;
30
+ seen.add(resolved);
31
+ out.push(resolved);
32
+ }
33
+ return out;
34
+ }
35
+ function findProjectEnvFile(options) {
36
+ const explicit = options.projectEnvFile?.trim() || process.env.IRANTI_PROJECT_ENV?.trim();
37
+ if (explicit && fs_1.default.existsSync(explicit))
38
+ return path_1.default.resolve(explicit);
39
+ const candidates = dedupePaths([
40
+ options.payloadCwd ? path_1.default.join(options.payloadCwd, '.env.iranti') : null,
41
+ options.cwd ? path_1.default.join(options.cwd, '.env.iranti') : null,
42
+ path_1.default.join(process.cwd(), '.env.iranti'),
43
+ ]);
44
+ return candidates.find((candidate) => fs_1.default.existsSync(candidate));
45
+ }
46
+ function findFallbackEnvFile(options) {
47
+ const explicit = options.explicitEnvFile?.trim() || process.env.IRANTI_ENV_FILE?.trim();
48
+ if (explicit && fs_1.default.existsSync(explicit))
49
+ return path_1.default.resolve(explicit);
50
+ const candidates = dedupePaths([
51
+ options.payloadCwd ? path_1.default.join(options.payloadCwd, '.env') : null,
52
+ options.cwd ? path_1.default.join(options.cwd, '.env') : null,
53
+ path_1.default.join(process.cwd(), '.env'),
54
+ path_1.default.resolve(__dirname, '..', '..', '.env'),
55
+ path_1.default.resolve(__dirname, '..', '..', '..', '.env'),
56
+ ]);
57
+ return candidates.find((candidate) => fs_1.default.existsSync(candidate));
58
+ }
59
+ function loadRuntimeEnv(options = {}) {
60
+ const loadedFiles = [];
61
+ const initialEnvKeys = new Set(Object.keys(process.env));
62
+ const fallbackEnvFile = findFallbackEnvFile(options);
63
+ if (fallbackEnvFile) {
64
+ applyEnvVars(parseEnvFile(fallbackEnvFile), initialEnvKeys);
65
+ loadedFiles.push(fallbackEnvFile);
66
+ }
67
+ const projectEnvFile = findProjectEnvFile(options);
68
+ const projectEnv = projectEnvFile && fs_1.default.existsSync(projectEnvFile)
69
+ ? parseEnvFile(projectEnvFile)
70
+ : null;
71
+ const instanceEnvFile = options.instanceEnvFile?.trim()
72
+ || process.env.IRANTI_INSTANCE_ENV?.trim()
73
+ || projectEnv?.IRANTI_INSTANCE_ENV;
74
+ const resolvedInstanceEnvFile = instanceEnvFile && fs_1.default.existsSync(instanceEnvFile)
75
+ ? path_1.default.resolve(instanceEnvFile)
76
+ : undefined;
77
+ if (resolvedInstanceEnvFile) {
78
+ applyEnvVars(parseEnvFile(resolvedInstanceEnvFile), initialEnvKeys);
79
+ loadedFiles.push(resolvedInstanceEnvFile);
80
+ }
81
+ if (projectEnvFile && projectEnv) {
82
+ applyEnvVars(projectEnv, initialEnvKeys);
83
+ loadedFiles.push(projectEnvFile);
84
+ }
85
+ return {
86
+ loadedFiles,
87
+ projectEnvFile,
88
+ instanceEnvFile: resolvedInstanceEnvFile,
89
+ };
90
+ }
91
+ //# sourceMappingURL=runtimeEnv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtimeEnv.js","sourceRoot":"","sources":["../../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iranti",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Memory infrastructure for multi-agent AI systems",
5
5
  "main": "dist/src/sdk/index.js",
6
6
  "files": [