iranti 0.2.5 → 0.2.7
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 +12 -0
- package/dist/scripts/codex-setup.js +9 -1
- package/dist/scripts/iranti-cli.js +284 -46
- package/dist/scripts/iranti-mcp.js +1 -1
- package/dist/scripts/seed.js +10 -10
- package/dist/src/api/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -305,6 +305,12 @@ iranti mcp
|
|
|
305
305
|
|
|
306
306
|
Use it with a project-local `.mcp.json`, and optionally add `iranti claude-hook` for `SessionStart` and `UserPromptSubmit`.
|
|
307
307
|
|
|
308
|
+
Fast path:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
iranti claude-setup
|
|
312
|
+
```
|
|
313
|
+
|
|
308
314
|
Guide: [`docs/guides/claude-code.md`](docs/guides/claude-code.md)
|
|
309
315
|
|
|
310
316
|
### Codex via MCP
|
|
@@ -318,6 +324,12 @@ codex -C /path/to/your/project
|
|
|
318
324
|
|
|
319
325
|
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.
|
|
320
326
|
|
|
327
|
+
Alias:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
iranti integrate codex
|
|
331
|
+
```
|
|
332
|
+
|
|
321
333
|
Guide: [`docs/guides/codex.md`](docs/guides/codex.md)
|
|
322
334
|
|
|
323
335
|
### Resolve Pending Escalations
|
|
@@ -153,11 +153,19 @@ function canUseInstalledIranti(repoRoot) {
|
|
|
153
153
|
return false;
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
+
function ensureCodexInstalled(repoRoot) {
|
|
157
|
+
try {
|
|
158
|
+
run('codex', ['--version'], repoRoot);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
throw new Error('Codex CLI is not installed or not on PATH. Install Codex first, confirm `codex --version` works, then rerun `iranti codex-setup`.');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
156
164
|
function main() {
|
|
157
165
|
const options = parseArgs(process.argv.slice(2));
|
|
158
166
|
const repoRoot = findPackageRoot(__dirname);
|
|
159
167
|
const mcpScript = node_path_1.default.join(repoRoot, 'dist', 'scripts', 'iranti-mcp.js');
|
|
160
|
-
|
|
168
|
+
ensureCodexInstalled(repoRoot);
|
|
161
169
|
const useInstalled = !options.useLocalScript && canUseInstalledIranti(repoRoot);
|
|
162
170
|
if (!useInstalled && !node_fs_1.default.existsSync(mcpScript)) {
|
|
163
171
|
throw new Error(`Missing build artifact: ${mcpScript}. Run "npm run build" first, or install iranti globally and rerun without --local-script.`);
|
|
@@ -644,39 +644,95 @@ async function ensureInstanceConfigured(root, name, config) {
|
|
|
644
644
|
});
|
|
645
645
|
return { envFile, instanceDir, created };
|
|
646
646
|
}
|
|
647
|
-
|
|
647
|
+
function makeIrantiMcpServerConfig() {
|
|
648
|
+
return {
|
|
649
|
+
command: 'iranti',
|
|
650
|
+
args: ['mcp'],
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function makeClaudeHookSettings(projectEnvPath) {
|
|
654
|
+
const hookArgs = (event) => {
|
|
655
|
+
const args = ['claude-hook', '--event', event];
|
|
656
|
+
if (projectEnvPath) {
|
|
657
|
+
args.push('--project-env', projectEnvPath);
|
|
658
|
+
}
|
|
659
|
+
return args;
|
|
660
|
+
};
|
|
661
|
+
return {
|
|
662
|
+
hooks: {
|
|
663
|
+
SessionStart: [
|
|
664
|
+
{
|
|
665
|
+
command: 'iranti',
|
|
666
|
+
args: hookArgs('SessionStart'),
|
|
667
|
+
},
|
|
668
|
+
],
|
|
669
|
+
UserPromptSubmit: [
|
|
670
|
+
{
|
|
671
|
+
command: 'iranti',
|
|
672
|
+
args: hookArgs('UserPromptSubmit'),
|
|
673
|
+
},
|
|
674
|
+
],
|
|
675
|
+
},
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
async function writeClaudeCodeProjectFiles(projectPath, projectEnvPath, force = false) {
|
|
648
679
|
const mcpFile = path_1.default.join(projectPath, '.mcp.json');
|
|
680
|
+
let mcpStatus = 'unchanged';
|
|
681
|
+
const irantiMcpServer = makeIrantiMcpServerConfig();
|
|
649
682
|
if (!fs_1.default.existsSync(mcpFile)) {
|
|
650
683
|
await writeText(mcpFile, `${JSON.stringify({
|
|
651
684
|
mcpServers: {
|
|
652
|
-
iranti:
|
|
653
|
-
command: 'iranti',
|
|
654
|
-
args: ['mcp'],
|
|
655
|
-
},
|
|
685
|
+
iranti: irantiMcpServer,
|
|
656
686
|
},
|
|
657
687
|
}, null, 2)}\n`);
|
|
688
|
+
mcpStatus = 'created';
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
const existing = readJsonFile(mcpFile);
|
|
692
|
+
if (!existing || typeof existing !== 'object' || Array.isArray(existing)) {
|
|
693
|
+
if (!force) {
|
|
694
|
+
throw new Error(`Existing .mcp.json is not valid JSON. Re-run with --force to overwrite it: ${mcpFile}`);
|
|
695
|
+
}
|
|
696
|
+
await writeText(mcpFile, `${JSON.stringify({
|
|
697
|
+
mcpServers: {
|
|
698
|
+
iranti: irantiMcpServer,
|
|
699
|
+
},
|
|
700
|
+
}, null, 2)}\n`);
|
|
701
|
+
mcpStatus = 'updated';
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
const existingServers = existing.mcpServers && typeof existing.mcpServers === 'object' && !Array.isArray(existing.mcpServers)
|
|
705
|
+
? existing.mcpServers
|
|
706
|
+
: {};
|
|
707
|
+
const hasIranti = Object.prototype.hasOwnProperty.call(existingServers, 'iranti');
|
|
708
|
+
if (!hasIranti || force) {
|
|
709
|
+
await writeText(mcpFile, `${JSON.stringify({
|
|
710
|
+
...existing,
|
|
711
|
+
mcpServers: {
|
|
712
|
+
...existingServers,
|
|
713
|
+
iranti: irantiMcpServer,
|
|
714
|
+
},
|
|
715
|
+
}, null, 2)}\n`);
|
|
716
|
+
mcpStatus = 'updated';
|
|
717
|
+
}
|
|
718
|
+
}
|
|
658
719
|
}
|
|
659
720
|
const claudeDir = path_1.default.join(projectPath, '.claude');
|
|
660
721
|
await ensureDir(claudeDir);
|
|
661
722
|
const settingsFile = path_1.default.join(claudeDir, 'settings.local.json');
|
|
723
|
+
let settingsStatus = 'unchanged';
|
|
662
724
|
if (!fs_1.default.existsSync(settingsFile)) {
|
|
663
|
-
await writeText(settingsFile, `${JSON.stringify(
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
},
|
|
670
|
-
],
|
|
671
|
-
UserPromptSubmit: [
|
|
672
|
-
{
|
|
673
|
-
command: 'iranti',
|
|
674
|
-
args: ['claude-hook', '--event', 'UserPromptSubmit'],
|
|
675
|
-
},
|
|
676
|
-
],
|
|
677
|
-
},
|
|
678
|
-
}, null, 2)}\n`);
|
|
725
|
+
await writeText(settingsFile, `${JSON.stringify(makeClaudeHookSettings(projectEnvPath), null, 2)}\n`);
|
|
726
|
+
settingsStatus = 'created';
|
|
727
|
+
}
|
|
728
|
+
else if (force) {
|
|
729
|
+
await writeText(settingsFile, `${JSON.stringify(makeClaudeHookSettings(projectEnvPath), null, 2)}\n`);
|
|
730
|
+
settingsStatus = 'updated';
|
|
679
731
|
}
|
|
732
|
+
return {
|
|
733
|
+
mcp: mcpStatus,
|
|
734
|
+
settings: settingsStatus,
|
|
735
|
+
};
|
|
680
736
|
}
|
|
681
737
|
function hasCodexInstalled() {
|
|
682
738
|
try {
|
|
@@ -1133,21 +1189,29 @@ function isPathInside(parentDir, childDir) {
|
|
|
1133
1189
|
const child = normalizePathForCompare(childDir);
|
|
1134
1190
|
return child === parent || child.startsWith(`${parent}/`);
|
|
1135
1191
|
}
|
|
1136
|
-
function
|
|
1137
|
-
if (
|
|
1138
|
-
return
|
|
1139
|
-
if (
|
|
1140
|
-
return
|
|
1141
|
-
|
|
1142
|
-
return 'npx.cmd';
|
|
1143
|
-
return executable;
|
|
1192
|
+
function quoteForCmd(arg) {
|
|
1193
|
+
if (arg.length === 0)
|
|
1194
|
+
return '""';
|
|
1195
|
+
if (!/[ \t"&()<>|^]/.test(arg))
|
|
1196
|
+
return arg;
|
|
1197
|
+
return `"${arg.replace(/"/g, '\\"')}"`;
|
|
1144
1198
|
}
|
|
1145
1199
|
function runCommandCapture(executable, args, cwd) {
|
|
1146
|
-
const proc =
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1200
|
+
const proc = process.platform === 'win32'
|
|
1201
|
+
? (0, child_process_1.spawnSync)(process.env.ComSpec ?? 'cmd.exe', [
|
|
1202
|
+
'/d',
|
|
1203
|
+
'/c',
|
|
1204
|
+
[executable, ...args].map(quoteForCmd).join(' '),
|
|
1205
|
+
], {
|
|
1206
|
+
cwd,
|
|
1207
|
+
encoding: 'utf8',
|
|
1208
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
1209
|
+
})
|
|
1210
|
+
: (0, child_process_1.spawnSync)(executable, args, {
|
|
1211
|
+
cwd,
|
|
1212
|
+
encoding: 'utf8',
|
|
1213
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
1214
|
+
});
|
|
1151
1215
|
return {
|
|
1152
1216
|
status: proc.status,
|
|
1153
1217
|
stdout: proc.stdout ?? '',
|
|
@@ -1155,10 +1219,19 @@ function runCommandCapture(executable, args, cwd) {
|
|
|
1155
1219
|
};
|
|
1156
1220
|
}
|
|
1157
1221
|
function runCommandInteractive(step) {
|
|
1158
|
-
const proc =
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1222
|
+
const proc = process.platform === 'win32'
|
|
1223
|
+
? (0, child_process_1.spawnSync)(process.env.ComSpec ?? 'cmd.exe', [
|
|
1224
|
+
'/d',
|
|
1225
|
+
'/c',
|
|
1226
|
+
[step.executable, ...step.args].map(quoteForCmd).join(' '),
|
|
1227
|
+
], {
|
|
1228
|
+
cwd: step.cwd,
|
|
1229
|
+
stdio: 'inherit',
|
|
1230
|
+
})
|
|
1231
|
+
: (0, child_process_1.spawnSync)(step.executable, step.args, {
|
|
1232
|
+
cwd: step.cwd,
|
|
1233
|
+
stdio: 'inherit',
|
|
1234
|
+
});
|
|
1162
1235
|
return proc.status;
|
|
1163
1236
|
}
|
|
1164
1237
|
function detectPythonLauncher() {
|
|
@@ -1294,8 +1367,8 @@ function detectUpgradeContext(args) {
|
|
|
1294
1367
|
const repoCheckout = fs_1.default.existsSync(path_1.default.join(packageRootPath, '.git'));
|
|
1295
1368
|
const repoDirty = repoCheckout ? repoIsDirty(packageRootPath) : false;
|
|
1296
1369
|
const globalNpmRoot = detectGlobalNpmRoot();
|
|
1297
|
-
const
|
|
1298
|
-
const
|
|
1370
|
+
const globalNpmVersion = detectGlobalNpmInstalledVersion();
|
|
1371
|
+
const globalNpmInstall = globalNpmVersion !== null;
|
|
1299
1372
|
const python = detectPythonLauncher();
|
|
1300
1373
|
const pythonVersion = detectPythonInstalledVersion(python);
|
|
1301
1374
|
const availableTargets = [];
|
|
@@ -1384,16 +1457,16 @@ function describeUpgradeTarget(target) {
|
|
|
1384
1457
|
const latest = target.latestVersion ?? 'unknown';
|
|
1385
1458
|
if (target.target === 'npm-repo') {
|
|
1386
1459
|
return target.blockedReason
|
|
1387
|
-
? `repo checkout (${current})
|
|
1388
|
-
: `repo checkout (${current})
|
|
1460
|
+
? `repo checkout (${current}) — ${target.blockedReason}`
|
|
1461
|
+
: `repo checkout (${current}) — refresh local checkout and rebuild`;
|
|
1389
1462
|
}
|
|
1390
1463
|
if (target.upToDate === true) {
|
|
1391
|
-
return `${target.target} (${current})
|
|
1464
|
+
return `${target.target} (${current}) — already at latest ${latest}`;
|
|
1392
1465
|
}
|
|
1393
1466
|
if (target.blockedReason) {
|
|
1394
|
-
return `${target.target} (${current})
|
|
1467
|
+
return `${target.target} (${current}) — ${target.blockedReason}`;
|
|
1395
1468
|
}
|
|
1396
|
-
return `${target.target} (${current})
|
|
1469
|
+
return `${target.target} (${current}) — latest ${latest}`;
|
|
1397
1470
|
}
|
|
1398
1471
|
async function chooseInteractiveUpgradeTargets(statuses) {
|
|
1399
1472
|
const selected = [];
|
|
@@ -2063,7 +2136,7 @@ async function doctorCommand(args) {
|
|
|
2063
2136
|
: check.status === 'warn'
|
|
2064
2137
|
? warnLabel('WARN')
|
|
2065
2138
|
: failLabel('FAIL');
|
|
2066
|
-
console.log(`${marker} ${check.name}
|
|
2139
|
+
console.log(`${marker} ${check.name} — ${check.detail}`);
|
|
2067
2140
|
}
|
|
2068
2141
|
if (result.remediations.length > 0) {
|
|
2069
2142
|
console.log('');
|
|
@@ -2736,6 +2809,151 @@ async function resolveCommand(args) {
|
|
|
2736
2809
|
const escalationDir = explicitDir ? path_1.default.resolve(explicitDir) : (0, escalationPaths_1.getEscalationPaths)().root;
|
|
2737
2810
|
await (0, resolutionist_1.resolveInteractive)(escalationDir);
|
|
2738
2811
|
}
|
|
2812
|
+
function printClaudeSetupHelp() {
|
|
2813
|
+
console.log([
|
|
2814
|
+
'Scaffold Claude Code MCP and hook files for the current project.',
|
|
2815
|
+
'',
|
|
2816
|
+
'Usage:',
|
|
2817
|
+
' iranti claude-setup [path] [--project-env <path>] [--force]',
|
|
2818
|
+
' iranti claude-setup --scan <dir> [--recursive] [--force]',
|
|
2819
|
+
' iranti integrate claude [path] [--project-env <path>] [--force]',
|
|
2820
|
+
' iranti integrate claude --scan <dir> [--recursive] [--force]',
|
|
2821
|
+
'',
|
|
2822
|
+
'Notes:',
|
|
2823
|
+
' - Expects a project binding at .env.iranti unless --project-env is supplied.',
|
|
2824
|
+
' - Writes .mcp.json and .claude/settings.local.json.',
|
|
2825
|
+
' - Adds the Iranti MCP server to existing .mcp.json files without removing other servers.',
|
|
2826
|
+
' - Leaves existing Claude hook files untouched unless --force is supplied.',
|
|
2827
|
+
'',
|
|
2828
|
+
'Scan mode (--scan):',
|
|
2829
|
+
' - Scans immediate subdirectories of the given dir by default.',
|
|
2830
|
+
' - Add --recursive to scan nested project trees too.',
|
|
2831
|
+
' - Only scaffolds projects that already have a .claude subfolder.',
|
|
2832
|
+
' - No .env.iranti required - skips the per-project binding check.',
|
|
2833
|
+
' - Scan mode adds or merges .mcp.json and only creates hook settings when missing.',
|
|
2834
|
+
].join('\n'));
|
|
2835
|
+
}
|
|
2836
|
+
function shouldSkipRecursiveClaudeScanDir(name) {
|
|
2837
|
+
if (name.startsWith('.'))
|
|
2838
|
+
return true;
|
|
2839
|
+
return [
|
|
2840
|
+
'node_modules',
|
|
2841
|
+
'dist',
|
|
2842
|
+
'build',
|
|
2843
|
+
'out',
|
|
2844
|
+
'coverage',
|
|
2845
|
+
'.next',
|
|
2846
|
+
'.turbo',
|
|
2847
|
+
'.cache',
|
|
2848
|
+
].includes(name);
|
|
2849
|
+
}
|
|
2850
|
+
function findClaudeProjects(scanDir, recursive) {
|
|
2851
|
+
if (!recursive) {
|
|
2852
|
+
return fs_1.default.readdirSync(scanDir, { withFileTypes: true })
|
|
2853
|
+
.filter((entry) => entry.isDirectory())
|
|
2854
|
+
.map((entry) => path_1.default.join(scanDir, entry.name))
|
|
2855
|
+
.filter((candidate) => fs_1.default.existsSync(path_1.default.join(candidate, '.claude')));
|
|
2856
|
+
}
|
|
2857
|
+
const found = new Set();
|
|
2858
|
+
const queue = [scanDir];
|
|
2859
|
+
while (queue.length > 0) {
|
|
2860
|
+
const current = queue.shift();
|
|
2861
|
+
let entries = [];
|
|
2862
|
+
try {
|
|
2863
|
+
entries = fs_1.default.readdirSync(current, { withFileTypes: true });
|
|
2864
|
+
}
|
|
2865
|
+
catch {
|
|
2866
|
+
continue;
|
|
2867
|
+
}
|
|
2868
|
+
if (fs_1.default.existsSync(path_1.default.join(current, '.claude'))) {
|
|
2869
|
+
found.add(current);
|
|
2870
|
+
}
|
|
2871
|
+
for (const entry of entries) {
|
|
2872
|
+
if (!entry.isDirectory())
|
|
2873
|
+
continue;
|
|
2874
|
+
if (shouldSkipRecursiveClaudeScanDir(entry.name))
|
|
2875
|
+
continue;
|
|
2876
|
+
queue.push(path_1.default.join(current, entry.name));
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
found.delete(scanDir);
|
|
2880
|
+
return Array.from(found).sort((a, b) => a.localeCompare(b));
|
|
2881
|
+
}
|
|
2882
|
+
async function claudeSetupCommand(args) {
|
|
2883
|
+
if (hasFlag(args, 'help')) {
|
|
2884
|
+
printClaudeSetupHelp();
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
const force = hasFlag(args, 'force');
|
|
2888
|
+
if (args.flags.has('scan')) {
|
|
2889
|
+
const recursive = hasFlag(args, 'recursive');
|
|
2890
|
+
const dirArg = getFlag(args, 'scan')
|
|
2891
|
+
?? args.positionals[0]
|
|
2892
|
+
?? (args.command === 'claude-setup' ? args.subcommand ?? undefined : undefined);
|
|
2893
|
+
const scanDir = path_1.default.resolve(dirArg ?? process.cwd());
|
|
2894
|
+
if (!fs_1.default.existsSync(scanDir)) {
|
|
2895
|
+
throw new Error(`Scan directory not found: ${scanDir}`);
|
|
2896
|
+
}
|
|
2897
|
+
const candidates = findClaudeProjects(scanDir, recursive);
|
|
2898
|
+
if (candidates.length === 0) {
|
|
2899
|
+
console.log(`${infoLabel()} No ${recursive ? 'nested project directories' : 'subdirectories'} with a .claude folder found in ${scanDir}`);
|
|
2900
|
+
return;
|
|
2901
|
+
}
|
|
2902
|
+
console.log(`${okLabel()} Scanning ${scanDir} - found ${candidates.length} project(s) with .claude${recursive ? ' (recursive)' : ''}`);
|
|
2903
|
+
let createdMcp = 0;
|
|
2904
|
+
let updatedMcp = 0;
|
|
2905
|
+
let createdSettings = 0;
|
|
2906
|
+
let updatedSettings = 0;
|
|
2907
|
+
let unchanged = 0;
|
|
2908
|
+
for (const projectPath of candidates) {
|
|
2909
|
+
const result = await writeClaudeCodeProjectFiles(projectPath, undefined, force);
|
|
2910
|
+
if (result.mcp === 'created')
|
|
2911
|
+
createdMcp += 1;
|
|
2912
|
+
if (result.mcp === 'updated')
|
|
2913
|
+
updatedMcp += 1;
|
|
2914
|
+
if (result.settings === 'created')
|
|
2915
|
+
createdSettings += 1;
|
|
2916
|
+
if (result.settings === 'updated')
|
|
2917
|
+
updatedSettings += 1;
|
|
2918
|
+
if (result.mcp === 'unchanged' && result.settings === 'unchanged')
|
|
2919
|
+
unchanged += 1;
|
|
2920
|
+
console.log(` ${projectPath}`);
|
|
2921
|
+
console.log(` mcp ${result.mcp}`);
|
|
2922
|
+
console.log(` settings ${result.settings}`);
|
|
2923
|
+
}
|
|
2924
|
+
console.log('');
|
|
2925
|
+
console.log('Summary:');
|
|
2926
|
+
console.log(` projects ${candidates.length}`);
|
|
2927
|
+
console.log(` mcp created ${createdMcp}`);
|
|
2928
|
+
console.log(` mcp updated ${updatedMcp}`);
|
|
2929
|
+
console.log(` settings created ${createdSettings}`);
|
|
2930
|
+
console.log(` settings updated ${updatedSettings}`);
|
|
2931
|
+
console.log(` unchanged ${unchanged}`);
|
|
2932
|
+
console.log(`${infoLabel()} Done. Open each project in Claude Code to verify Iranti tools are available.`);
|
|
2933
|
+
return;
|
|
2934
|
+
}
|
|
2935
|
+
const projectArg = args.positionals[0] ?? (args.command === 'claude-setup' ? args.subcommand ?? undefined : undefined);
|
|
2936
|
+
const projectPath = path_1.default.resolve(projectArg ?? process.cwd());
|
|
2937
|
+
const explicitProjectEnv = getFlag(args, 'project-env');
|
|
2938
|
+
const projectEnvPath = explicitProjectEnv
|
|
2939
|
+
? path_1.default.resolve(explicitProjectEnv)
|
|
2940
|
+
: path_1.default.join(projectPath, '.env.iranti');
|
|
2941
|
+
if (!fs_1.default.existsSync(projectPath)) {
|
|
2942
|
+
throw new Error(`Project path not found: ${projectPath}`);
|
|
2943
|
+
}
|
|
2944
|
+
if (!fs_1.default.existsSync(projectEnvPath)) {
|
|
2945
|
+
throw new Error(`Project binding not found at ${projectEnvPath}. Run \`iranti project init\` or \`iranti configure project\` first.`);
|
|
2946
|
+
}
|
|
2947
|
+
const result = await writeClaudeCodeProjectFiles(projectPath, projectEnvPath, force);
|
|
2948
|
+
console.log(`${okLabel()} Claude Code integration scaffolded`);
|
|
2949
|
+
console.log(` project ${projectPath}`);
|
|
2950
|
+
console.log(` binding ${projectEnvPath}`);
|
|
2951
|
+
console.log(` mcp ${path_1.default.join(projectPath, '.mcp.json')}`);
|
|
2952
|
+
console.log(` settings ${path_1.default.join(projectPath, '.claude', 'settings.local.json')}`);
|
|
2953
|
+
console.log(` mcp status ${result.mcp}`);
|
|
2954
|
+
console.log(` settings status ${result.settings}`);
|
|
2955
|
+
console.log(`${infoLabel()} Next: open Claude Code in this project and verify Iranti tools are available.`);
|
|
2956
|
+
}
|
|
2739
2957
|
async function chatCommand(args) {
|
|
2740
2958
|
const provider = normalizeProvider(getFlag(args, 'provider'));
|
|
2741
2959
|
if (provider && !isSupportedProvider(provider)) {
|
|
@@ -2788,8 +3006,13 @@ Project-level:
|
|
|
2788
3006
|
|
|
2789
3007
|
Integrations:
|
|
2790
3008
|
iranti mcp [--help]
|
|
3009
|
+
iranti claude-setup [path] [--project-env <path>] [--force]
|
|
3010
|
+
iranti claude-setup --scan <dir> [--force]
|
|
2791
3011
|
iranti claude-hook --event SessionStart|UserPromptSubmit [--project-env <path>] [--instance-env <path>] [--env-file <path>]
|
|
2792
3012
|
iranti codex-setup [--name iranti] [--agent codex_code] [--source Codex] [--provider openai] [--project-env <path>] [--local-script]
|
|
3013
|
+
iranti integrate claude [path] [--project-env <path>] [--force]
|
|
3014
|
+
iranti integrate claude --scan <dir> [--force]
|
|
3015
|
+
iranti integrate codex [--name iranti] [--agent codex_code] [--source Codex] [--provider openai] [--project-env <path>] [--local-script]
|
|
2793
3016
|
`);
|
|
2794
3017
|
}
|
|
2795
3018
|
async function main() {
|
|
@@ -2895,6 +3118,10 @@ async function main() {
|
|
|
2895
3118
|
await handoffToScript('iranti-mcp', process.argv.slice(3));
|
|
2896
3119
|
return;
|
|
2897
3120
|
}
|
|
3121
|
+
if (args.command === 'claude-setup') {
|
|
3122
|
+
await claudeSetupCommand(args);
|
|
3123
|
+
return;
|
|
3124
|
+
}
|
|
2898
3125
|
if (args.command === 'claude-hook') {
|
|
2899
3126
|
await handoffToScript('claude-code-memory-hook', process.argv.slice(3));
|
|
2900
3127
|
return;
|
|
@@ -2903,6 +3130,17 @@ async function main() {
|
|
|
2903
3130
|
await handoffToScript('codex-setup', process.argv.slice(3));
|
|
2904
3131
|
return;
|
|
2905
3132
|
}
|
|
3133
|
+
if (args.command === 'integrate') {
|
|
3134
|
+
if (args.subcommand === 'claude') {
|
|
3135
|
+
await claudeSetupCommand(args);
|
|
3136
|
+
return;
|
|
3137
|
+
}
|
|
3138
|
+
if (args.subcommand === 'codex') {
|
|
3139
|
+
await handoffToScript('codex-setup', process.argv.slice(4));
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
throw new Error(`Unknown integrate target '${args.subcommand ?? ''}'. Use 'claude' or 'codex'.`);
|
|
3143
|
+
}
|
|
2906
3144
|
throw new Error(`Unknown command '${args.command}'. Run: iranti help`);
|
|
2907
3145
|
}
|
|
2908
3146
|
main().catch((err) => {
|
|
@@ -144,7 +144,7 @@ async function main() {
|
|
|
144
144
|
await ensureDefaultAgent(iranti);
|
|
145
145
|
const server = new mcp_js_1.McpServer({
|
|
146
146
|
name: 'iranti-mcp',
|
|
147
|
-
version: '0.2.
|
|
147
|
+
version: '0.2.7',
|
|
148
148
|
});
|
|
149
149
|
server.registerTool('iranti_handshake', {
|
|
150
150
|
description: `Initialize or refresh an agent's working-memory brief for the current task.
|
package/dist/scripts/seed.js
CHANGED
|
@@ -15,7 +15,7 @@ const STAFF_ENTRIES = [
|
|
|
15
15
|
entityId: 'librarian',
|
|
16
16
|
key: 'operating_rules',
|
|
17
17
|
valueRaw: {
|
|
18
|
-
version: '0.2.
|
|
18
|
+
version: '0.2.7',
|
|
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.2.
|
|
42
|
+
version: '0.2.7',
|
|
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.2.
|
|
64
|
+
version: '0.2.7',
|
|
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.2.
|
|
85
|
+
valueRaw: { version: '0.2.7' },
|
|
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.2.
|
|
98
|
+
seedVersion: '0.2.7',
|
|
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.2.
|
|
111
|
+
version: '0.2.7',
|
|
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.2.
|
|
159
|
+
version: '0.2.7',
|
|
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.2.
|
|
190
|
+
version: '0.2.7',
|
|
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.2.
|
|
204
|
+
version: '0.2.7',
|
|
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.2.
|
|
240
|
+
version: '0.2.7',
|
|
241
241
|
events: [
|
|
242
242
|
{
|
|
243
243
|
at: new Date().toISOString(),
|
package/dist/src/api/server.js
CHANGED