iranti 0.2.10 → 0.2.11
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/dist/scripts/iranti-cli.js +185 -103
- 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
|
@@ -707,7 +707,7 @@ function isSupportedProvider(provider) {
|
|
|
707
707
|
async function promptYesNo(session, prompt, defaultValue) {
|
|
708
708
|
const defaultToken = defaultValue ? 'Y/n' : 'y/N';
|
|
709
709
|
while (true) {
|
|
710
|
-
const answer = (await session.line(`${prompt} (${defaultToken})
|
|
710
|
+
const answer = (await session.line(`${prompt} (${defaultToken})`) ?? '').trim().toLowerCase();
|
|
711
711
|
if (!answer)
|
|
712
712
|
return defaultValue;
|
|
713
713
|
if (['y', 'yes'].includes(answer))
|
|
@@ -730,7 +730,7 @@ async function promptRequiredSecret(session, prompt, currentValue) {
|
|
|
730
730
|
const value = (await session.secretRequired(prompt, currentValue) ?? '').trim();
|
|
731
731
|
if (value.length > 0 && !detectPlaceholder(value))
|
|
732
732
|
return value;
|
|
733
|
-
console.log(`${warnLabel()}
|
|
733
|
+
console.log(`${warnLabel()} ${prompt} is required.`);
|
|
734
734
|
}
|
|
735
735
|
}
|
|
736
736
|
function makeLegacyInstanceApiKey(instanceName) {
|
|
@@ -1466,8 +1466,13 @@ function collectDoctorRemediations(checks, envSource, envFile) {
|
|
|
1466
1466
|
add('Run `iranti setup`, or rerun `iranti doctor` with `--instance <name>` or `--env <file>`.');
|
|
1467
1467
|
}
|
|
1468
1468
|
}
|
|
1469
|
-
if (check.name === 'database configuration' && check.status === 'fail') {
|
|
1470
|
-
|
|
1469
|
+
if ((check.name === 'database configuration' || check.name === 'bound instance database configuration') && check.status === 'fail') {
|
|
1470
|
+
if (check.name === 'bound instance database configuration') {
|
|
1471
|
+
add('Fix the linked instance env, or rerun `iranti setup` / `iranti configure instance` for the bound instance.');
|
|
1472
|
+
}
|
|
1473
|
+
else {
|
|
1474
|
+
add(`Set a real DATABASE_URL in ${envFile ?? 'the target env file'}, or rerun \`iranti setup\` to configure the database again.`);
|
|
1475
|
+
}
|
|
1471
1476
|
}
|
|
1472
1477
|
if (check.name === 'project binding url' && check.status === 'fail') {
|
|
1473
1478
|
add('Run `iranti configure project` to refresh the project binding, or set IRANTI_URL in `.env.iranti`.');
|
|
@@ -1475,15 +1480,18 @@ function collectDoctorRemediations(checks, envSource, envFile) {
|
|
|
1475
1480
|
if (check.name === 'project api key' && check.status === 'fail') {
|
|
1476
1481
|
add('Run `iranti configure project` or set IRANTI_API_KEY in `.env.iranti`.');
|
|
1477
1482
|
}
|
|
1483
|
+
if (check.name === 'bound instance env' && check.status !== 'pass') {
|
|
1484
|
+
add('Run `iranti configure project` to refresh the project binding, or set IRANTI_INSTANCE_ENV in `.env.iranti` so doctor can inspect the bound local instance.');
|
|
1485
|
+
}
|
|
1478
1486
|
if (check.name === 'api key' && check.status !== 'pass') {
|
|
1479
1487
|
add(envSource === 'project-binding'
|
|
1480
1488
|
? 'Set IRANTI_API_KEY in the project binding, or rerun `iranti configure project`.'
|
|
1481
1489
|
: 'Create or rotate an Iranti key with `iranti auth create-key`, then store it in the target env.');
|
|
1482
1490
|
}
|
|
1483
|
-
if (check.name === 'provider credentials' && check.status === 'fail') {
|
|
1491
|
+
if ((check.name === 'provider credentials' || check.name === 'bound instance provider credentials') && check.status === 'fail') {
|
|
1484
1492
|
add('Store or refresh the upstream provider key with `iranti add api-key` or `iranti update api-key`.');
|
|
1485
1493
|
}
|
|
1486
|
-
if (check.name === 'vector backend' && check.status === 'fail') {
|
|
1494
|
+
if ((check.name === 'vector backend' || check.name === 'bound instance vector backend') && check.status === 'fail') {
|
|
1487
1495
|
add('Check the vector backend env vars, or switch back to `IRANTI_VECTOR_BACKEND=pgvector` if the external backend is not ready.');
|
|
1488
1496
|
}
|
|
1489
1497
|
}
|
|
@@ -2341,7 +2349,7 @@ async function setupCommand(args) {
|
|
|
2341
2349
|
await withPromptSession(async (prompt) => {
|
|
2342
2350
|
let setupMode = 'isolated';
|
|
2343
2351
|
while (true) {
|
|
2344
|
-
const chosen = (await prompt.line('
|
|
2352
|
+
const chosen = (await prompt.line('Runtime mode (isolated or shared)', 'isolated') ?? 'isolated').trim().toLowerCase();
|
|
2345
2353
|
if (chosen === 'shared' || chosen === 'isolated') {
|
|
2346
2354
|
setupMode = chosen;
|
|
2347
2355
|
break;
|
|
@@ -2351,12 +2359,12 @@ async function setupCommand(args) {
|
|
|
2351
2359
|
let finalScope = 'user';
|
|
2352
2360
|
let finalRoot = '';
|
|
2353
2361
|
if (setupMode === 'isolated') {
|
|
2354
|
-
finalRoot = path_1.default.resolve(await promptNonEmpty(prompt, '
|
|
2362
|
+
finalRoot = path_1.default.resolve(await promptNonEmpty(prompt, 'Isolated runtime path', explicitRoot ?? path_1.default.join(process.cwd(), '.iranti-runtime')));
|
|
2355
2363
|
finalScope = 'user';
|
|
2356
2364
|
}
|
|
2357
2365
|
else {
|
|
2358
2366
|
while (true) {
|
|
2359
|
-
const chosenScope = (await prompt.line('Install scope
|
|
2367
|
+
const chosenScope = (await prompt.line('Install scope (user or system)', explicitScope ?? 'user') ?? 'user').trim().toLowerCase();
|
|
2360
2368
|
if (chosenScope === 'user' || chosenScope === 'system') {
|
|
2361
2369
|
finalScope = chosenScope;
|
|
2362
2370
|
break;
|
|
@@ -2367,7 +2375,7 @@ async function setupCommand(args) {
|
|
|
2367
2375
|
}
|
|
2368
2376
|
await ensureRuntimeInstalled(finalRoot, finalScope);
|
|
2369
2377
|
console.log(`${okLabel()} Runtime ready at ${finalRoot}`);
|
|
2370
|
-
const instanceName = sanitizeIdentifier(await promptNonEmpty(prompt, '
|
|
2378
|
+
const instanceName = sanitizeIdentifier(await promptNonEmpty(prompt, 'Instance name', setupMode === 'isolated' ? sanitizeIdentifier(path_1.default.basename(process.cwd()), 'local') : 'local'), 'local');
|
|
2371
2379
|
const existingInstance = fs_1.default.existsSync(instancePaths(finalRoot, instanceName).envFile)
|
|
2372
2380
|
? await loadInstanceEnv(finalRoot, instanceName)
|
|
2373
2381
|
: null;
|
|
@@ -2378,7 +2386,7 @@ async function setupCommand(args) {
|
|
|
2378
2386
|
console.log(`${infoLabel()} Creating new instance '${instanceName}'.`);
|
|
2379
2387
|
}
|
|
2380
2388
|
const existingPort = Number.parseInt(existingInstance?.env.IRANTI_PORT ?? '3001', 10);
|
|
2381
|
-
const port = await chooseAvailablePort(prompt, '
|
|
2389
|
+
const port = await chooseAvailablePort(prompt, 'API port', existingPort, Boolean(existingInstance));
|
|
2382
2390
|
const dockerAvailable = hasDockerInstalled();
|
|
2383
2391
|
const psqlAvailable = hasCommandInstalled('psql');
|
|
2384
2392
|
let dbUrl = '';
|
|
@@ -2386,14 +2394,14 @@ async function setupCommand(args) {
|
|
|
2386
2394
|
let databaseMode = recommendedDatabaseMode;
|
|
2387
2395
|
while (true) {
|
|
2388
2396
|
const defaultMode = recommendedDatabaseMode;
|
|
2389
|
-
const dbMode = (await prompt.line('
|
|
2397
|
+
const dbMode = (await prompt.line('Database mode (local, managed, or docker)', defaultMode) ?? defaultMode).trim().toLowerCase();
|
|
2390
2398
|
if (dbMode === 'existing' || dbMode === 'local' || dbMode === 'managed') {
|
|
2391
2399
|
databaseMode = dbMode === 'existing' ? 'local' : dbMode;
|
|
2392
2400
|
const defaultDatabaseUrl = databaseMode === 'local'
|
|
2393
2401
|
? existingInstance?.env.DATABASE_URL ?? deriveDatabaseUrlForMode('local', instanceName)
|
|
2394
2402
|
: existingInstance?.env.DATABASE_URL ?? '';
|
|
2395
2403
|
while (true) {
|
|
2396
|
-
dbUrl = await promptNonEmpty(prompt, '
|
|
2404
|
+
dbUrl = await promptNonEmpty(prompt, 'DATABASE_URL', defaultDatabaseUrl);
|
|
2397
2405
|
if (!detectPlaceholder(dbUrl))
|
|
2398
2406
|
break;
|
|
2399
2407
|
console.log(`${warnLabel()} DATABASE_URL still looks like a placeholder. Enter a real connection string before finishing setup.`);
|
|
@@ -2415,9 +2423,9 @@ async function setupCommand(args) {
|
|
|
2415
2423
|
console.log(`${warnLabel()} Docker is not installed or not on PATH. Choose local or managed instead.`);
|
|
2416
2424
|
continue;
|
|
2417
2425
|
}
|
|
2418
|
-
const dbHostPort = await chooseAvailablePort(prompt, '
|
|
2419
|
-
const dbName = sanitizeIdentifier(await promptNonEmpty(prompt, '
|
|
2420
|
-
const dbPassword = await promptRequiredSecret(prompt, '
|
|
2426
|
+
const dbHostPort = await chooseAvailablePort(prompt, 'Docker PostgreSQL host port', 5432, false);
|
|
2427
|
+
const dbName = sanitizeIdentifier(await promptNonEmpty(prompt, 'Docker PostgreSQL database name', `iranti_${instanceName}`), `iranti_${instanceName}`);
|
|
2428
|
+
const dbPassword = await promptRequiredSecret(prompt, 'Docker PostgreSQL password');
|
|
2421
2429
|
const containerName = sanitizeIdentifier(await promptNonEmpty(prompt, 'Docker container name', `iranti_${instanceName}_db`), `iranti_${instanceName}_db`);
|
|
2422
2430
|
dbUrl = `postgresql://postgres:${dbPassword}@localhost:${dbHostPort}/${dbName}`;
|
|
2423
2431
|
console.log(`${infoLabel()} Docker will be used only for PostgreSQL. Iranti itself does not require Docker once a PostgreSQL database is available.`);
|
|
@@ -2441,7 +2449,7 @@ async function setupCommand(args) {
|
|
|
2441
2449
|
let provider = normalizeProvider(existingInstance?.env.LLM_PROVIDER ?? 'openai') ?? 'openai';
|
|
2442
2450
|
while (true) {
|
|
2443
2451
|
listProviderChoices(provider, existingInstance?.env ?? {});
|
|
2444
|
-
const chosen = normalizeProvider(await promptNonEmpty(prompt, '
|
|
2452
|
+
const chosen = normalizeProvider(await promptNonEmpty(prompt, 'Default LLM provider', provider));
|
|
2445
2453
|
if (chosen && isSupportedProvider(chosen)) {
|
|
2446
2454
|
provider = chosen;
|
|
2447
2455
|
break;
|
|
@@ -2464,7 +2472,7 @@ async function setupCommand(args) {
|
|
|
2464
2472
|
let extraProvider = provider;
|
|
2465
2473
|
while (true) {
|
|
2466
2474
|
listProviderChoices(provider, { ...seedEnv, ...providerKeys });
|
|
2467
|
-
const chosen = normalizeProvider(await promptNonEmpty(prompt, '
|
|
2475
|
+
const chosen = normalizeProvider(await promptNonEmpty(prompt, 'Additional provider', 'claude'));
|
|
2468
2476
|
if (!chosen) {
|
|
2469
2477
|
console.log(`${warnLabel()} Provider is required.`);
|
|
2470
2478
|
continue;
|
|
@@ -2499,9 +2507,9 @@ async function setupCommand(args) {
|
|
|
2499
2507
|
const defaultProjectPath = process.cwd();
|
|
2500
2508
|
let shouldBindProject = await promptYesNo(prompt, 'Bind a project folder to this instance now?', true);
|
|
2501
2509
|
while (shouldBindProject) {
|
|
2502
|
-
const projectPath = path_1.default.resolve(await promptNonEmpty(prompt, '
|
|
2503
|
-
const agentId = sanitizeIdentifier(await promptNonEmpty(prompt, '
|
|
2504
|
-
const memoryEntity = await promptNonEmpty(prompt, '
|
|
2510
|
+
const projectPath = path_1.default.resolve(await promptNonEmpty(prompt, 'Project path to bind', projects.length === 0 ? defaultProjectPath : process.cwd()));
|
|
2511
|
+
const agentId = sanitizeIdentifier(await promptNonEmpty(prompt, 'Project agent ID', projectAgentDefault(projectPath)), 'project_main');
|
|
2512
|
+
const memoryEntity = await promptNonEmpty(prompt, 'Project memory entity', 'user/main');
|
|
2505
2513
|
const claudeCode = await promptYesNo(prompt, 'Create Claude Code project files here now?', true);
|
|
2506
2514
|
projects.push({
|
|
2507
2515
|
path: projectPath,
|
|
@@ -2574,6 +2582,71 @@ async function doctorCommand(args) {
|
|
|
2574
2582
|
const { envFile, envSource } = resolveDoctorEnvTarget(args);
|
|
2575
2583
|
const checks = [];
|
|
2576
2584
|
const version = getPackageVersion();
|
|
2585
|
+
const pushEnvironmentChecks = async (env, prefix = '') => {
|
|
2586
|
+
const databaseUrl = env.DATABASE_URL;
|
|
2587
|
+
checks.push(detectPlaceholder(databaseUrl)
|
|
2588
|
+
? {
|
|
2589
|
+
name: `${prefix}database configuration`,
|
|
2590
|
+
status: 'fail',
|
|
2591
|
+
detail: 'DATABASE_URL is missing or still uses a placeholder value.',
|
|
2592
|
+
}
|
|
2593
|
+
: {
|
|
2594
|
+
name: `${prefix}database configuration`,
|
|
2595
|
+
status: 'pass',
|
|
2596
|
+
detail: 'DATABASE_URL is present and non-placeholder.',
|
|
2597
|
+
});
|
|
2598
|
+
const provider = env.LLM_PROVIDER ?? 'mock';
|
|
2599
|
+
checks.push({
|
|
2600
|
+
name: `${prefix}llm provider`,
|
|
2601
|
+
status: 'pass',
|
|
2602
|
+
detail: `LLM_PROVIDER=${provider}`,
|
|
2603
|
+
});
|
|
2604
|
+
const providerKeyCheck = detectProviderKey(provider, env);
|
|
2605
|
+
checks.push({
|
|
2606
|
+
...providerKeyCheck,
|
|
2607
|
+
name: `${prefix}${providerKeyCheck.name}`,
|
|
2608
|
+
});
|
|
2609
|
+
try {
|
|
2610
|
+
const backendName = (0, backends_1.resolveVectorBackendName)({
|
|
2611
|
+
vectorBackend: env.IRANTI_VECTOR_BACKEND,
|
|
2612
|
+
qdrantUrl: env.IRANTI_QDRANT_URL,
|
|
2613
|
+
qdrantApiKey: env.IRANTI_QDRANT_API_KEY,
|
|
2614
|
+
qdrantCollection: env.IRANTI_QDRANT_COLLECTION,
|
|
2615
|
+
chromaUrl: env.IRANTI_CHROMA_URL,
|
|
2616
|
+
chromaCollection: env.IRANTI_CHROMA_COLLECTION,
|
|
2617
|
+
chromaTenant: env.IRANTI_CHROMA_TENANT,
|
|
2618
|
+
chromaDatabase: env.IRANTI_CHROMA_DATABASE,
|
|
2619
|
+
chromaToken: env.IRANTI_CHROMA_TOKEN,
|
|
2620
|
+
});
|
|
2621
|
+
const backend = (0, backends_1.createVectorBackend)({
|
|
2622
|
+
vectorBackend: backendName,
|
|
2623
|
+
qdrantUrl: env.IRANTI_QDRANT_URL,
|
|
2624
|
+
qdrantApiKey: env.IRANTI_QDRANT_API_KEY,
|
|
2625
|
+
qdrantCollection: env.IRANTI_QDRANT_COLLECTION,
|
|
2626
|
+
chromaUrl: env.IRANTI_CHROMA_URL,
|
|
2627
|
+
chromaCollection: env.IRANTI_CHROMA_COLLECTION,
|
|
2628
|
+
chromaTenant: env.IRANTI_CHROMA_TENANT,
|
|
2629
|
+
chromaDatabase: env.IRANTI_CHROMA_DATABASE,
|
|
2630
|
+
chromaToken: env.IRANTI_CHROMA_TOKEN,
|
|
2631
|
+
});
|
|
2632
|
+
const reachable = await backend.ping();
|
|
2633
|
+
const url = vectorBackendUrl(backendName, env);
|
|
2634
|
+
checks.push({
|
|
2635
|
+
name: `${prefix}vector backend`,
|
|
2636
|
+
status: reachable ? 'pass' : 'warn',
|
|
2637
|
+
detail: url
|
|
2638
|
+
? `${backendName} (${url}) is ${reachable ? 'reachable' : 'unreachable'}`
|
|
2639
|
+
: `${backendName} is ${reachable ? 'reachable' : 'unreachable'}`,
|
|
2640
|
+
});
|
|
2641
|
+
}
|
|
2642
|
+
catch (error) {
|
|
2643
|
+
checks.push({
|
|
2644
|
+
name: `${prefix}vector backend`,
|
|
2645
|
+
status: 'fail',
|
|
2646
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
2647
|
+
});
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2577
2650
|
checks.push({
|
|
2578
2651
|
name: 'node version',
|
|
2579
2652
|
status: Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10) >= 18 ? 'pass' : 'fail',
|
|
@@ -2603,24 +2676,15 @@ async function doctorCommand(args) {
|
|
|
2603
2676
|
}
|
|
2604
2677
|
else {
|
|
2605
2678
|
const env = await readEnvFile(envFile);
|
|
2679
|
+
const treatAsProjectBinding = envSource === 'project-binding'
|
|
2680
|
+
|| path_1.default.basename(envFile).toLowerCase() === '.env.iranti'
|
|
2681
|
+
|| (Boolean(env.IRANTI_URL?.trim()) && detectPlaceholder(env.DATABASE_URL));
|
|
2606
2682
|
checks.push({
|
|
2607
2683
|
name: 'environment file',
|
|
2608
2684
|
status: 'pass',
|
|
2609
2685
|
detail: `${envSource} env loaded from ${envFile}`,
|
|
2610
2686
|
});
|
|
2611
|
-
|
|
2612
|
-
checks.push(detectPlaceholder(databaseUrl)
|
|
2613
|
-
? {
|
|
2614
|
-
name: 'database configuration',
|
|
2615
|
-
status: 'fail',
|
|
2616
|
-
detail: 'DATABASE_URL is missing or still uses a placeholder value.',
|
|
2617
|
-
}
|
|
2618
|
-
: {
|
|
2619
|
-
name: 'database configuration',
|
|
2620
|
-
status: 'pass',
|
|
2621
|
-
detail: 'DATABASE_URL is present and non-placeholder.',
|
|
2622
|
-
});
|
|
2623
|
-
if (envSource === 'project-binding') {
|
|
2687
|
+
if (treatAsProjectBinding) {
|
|
2624
2688
|
checks.push(detectPlaceholder(env.IRANTI_URL)
|
|
2625
2689
|
? {
|
|
2626
2690
|
name: 'project binding url',
|
|
@@ -2633,7 +2697,7 @@ async function doctorCommand(args) {
|
|
|
2633
2697
|
detail: `IRANTI_URL=${env.IRANTI_URL}`,
|
|
2634
2698
|
});
|
|
2635
2699
|
}
|
|
2636
|
-
if (
|
|
2700
|
+
if (treatAsProjectBinding) {
|
|
2637
2701
|
checks.push(detectPlaceholder(env.IRANTI_API_KEY)
|
|
2638
2702
|
? {
|
|
2639
2703
|
name: 'project api key',
|
|
@@ -2645,8 +2709,33 @@ async function doctorCommand(args) {
|
|
|
2645
2709
|
status: 'pass',
|
|
2646
2710
|
detail: 'IRANTI_API_KEY is present in .env.iranti.',
|
|
2647
2711
|
});
|
|
2712
|
+
const linkedInstanceEnv = env.IRANTI_INSTANCE_ENV?.trim();
|
|
2713
|
+
if (!linkedInstanceEnv) {
|
|
2714
|
+
checks.push({
|
|
2715
|
+
name: 'bound instance env',
|
|
2716
|
+
status: 'warn',
|
|
2717
|
+
detail: 'IRANTI_INSTANCE_ENV is not set in .env.iranti. Skipping database and provider checks for the bound instance.',
|
|
2718
|
+
});
|
|
2719
|
+
}
|
|
2720
|
+
else if (!fs_1.default.existsSync(linkedInstanceEnv)) {
|
|
2721
|
+
checks.push({
|
|
2722
|
+
name: 'bound instance env',
|
|
2723
|
+
status: 'warn',
|
|
2724
|
+
detail: `Linked instance env not found: ${linkedInstanceEnv}. Skipping database and provider checks for the bound instance.`,
|
|
2725
|
+
});
|
|
2726
|
+
}
|
|
2727
|
+
else {
|
|
2728
|
+
checks.push({
|
|
2729
|
+
name: 'bound instance env',
|
|
2730
|
+
status: 'pass',
|
|
2731
|
+
detail: `Using ${linkedInstanceEnv} for bound instance diagnostics.`,
|
|
2732
|
+
});
|
|
2733
|
+
const linkedEnv = await readEnvFile(linkedInstanceEnv);
|
|
2734
|
+
await pushEnvironmentChecks(linkedEnv, 'bound instance ');
|
|
2735
|
+
}
|
|
2648
2736
|
}
|
|
2649
2737
|
else {
|
|
2738
|
+
await pushEnvironmentChecks(env);
|
|
2650
2739
|
checks.push(detectPlaceholder(env.IRANTI_API_KEY)
|
|
2651
2740
|
? {
|
|
2652
2741
|
name: 'api key',
|
|
@@ -2659,53 +2748,6 @@ async function doctorCommand(args) {
|
|
|
2659
2748
|
detail: 'IRANTI_API_KEY is present.',
|
|
2660
2749
|
});
|
|
2661
2750
|
}
|
|
2662
|
-
const provider = env.LLM_PROVIDER ?? 'mock';
|
|
2663
|
-
checks.push({
|
|
2664
|
-
name: 'llm provider',
|
|
2665
|
-
status: 'pass',
|
|
2666
|
-
detail: `LLM_PROVIDER=${provider}`,
|
|
2667
|
-
});
|
|
2668
|
-
checks.push(detectProviderKey(provider, env));
|
|
2669
|
-
try {
|
|
2670
|
-
const backendName = (0, backends_1.resolveVectorBackendName)({
|
|
2671
|
-
vectorBackend: env.IRANTI_VECTOR_BACKEND,
|
|
2672
|
-
qdrantUrl: env.IRANTI_QDRANT_URL,
|
|
2673
|
-
qdrantApiKey: env.IRANTI_QDRANT_API_KEY,
|
|
2674
|
-
qdrantCollection: env.IRANTI_QDRANT_COLLECTION,
|
|
2675
|
-
chromaUrl: env.IRANTI_CHROMA_URL,
|
|
2676
|
-
chromaCollection: env.IRANTI_CHROMA_COLLECTION,
|
|
2677
|
-
chromaTenant: env.IRANTI_CHROMA_TENANT,
|
|
2678
|
-
chromaDatabase: env.IRANTI_CHROMA_DATABASE,
|
|
2679
|
-
chromaToken: env.IRANTI_CHROMA_TOKEN,
|
|
2680
|
-
});
|
|
2681
|
-
const backend = (0, backends_1.createVectorBackend)({
|
|
2682
|
-
vectorBackend: backendName,
|
|
2683
|
-
qdrantUrl: env.IRANTI_QDRANT_URL,
|
|
2684
|
-
qdrantApiKey: env.IRANTI_QDRANT_API_KEY,
|
|
2685
|
-
qdrantCollection: env.IRANTI_QDRANT_COLLECTION,
|
|
2686
|
-
chromaUrl: env.IRANTI_CHROMA_URL,
|
|
2687
|
-
chromaCollection: env.IRANTI_CHROMA_COLLECTION,
|
|
2688
|
-
chromaTenant: env.IRANTI_CHROMA_TENANT,
|
|
2689
|
-
chromaDatabase: env.IRANTI_CHROMA_DATABASE,
|
|
2690
|
-
chromaToken: env.IRANTI_CHROMA_TOKEN,
|
|
2691
|
-
});
|
|
2692
|
-
const reachable = await backend.ping();
|
|
2693
|
-
const url = vectorBackendUrl(backendName, env);
|
|
2694
|
-
checks.push({
|
|
2695
|
-
name: 'vector backend',
|
|
2696
|
-
status: reachable ? 'pass' : 'warn',
|
|
2697
|
-
detail: url
|
|
2698
|
-
? `${backendName} (${url}) is ${reachable ? 'reachable' : 'unreachable'}`
|
|
2699
|
-
: `${backendName} is ${reachable ? 'reachable' : 'unreachable'}`,
|
|
2700
|
-
});
|
|
2701
|
-
}
|
|
2702
|
-
catch (error) {
|
|
2703
|
-
checks.push({
|
|
2704
|
-
name: 'vector backend',
|
|
2705
|
-
status: 'fail',
|
|
2706
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
2707
|
-
});
|
|
2708
|
-
}
|
|
2709
2751
|
}
|
|
2710
2752
|
const result = {
|
|
2711
2753
|
version,
|
|
@@ -3173,13 +3215,13 @@ async function configureInstanceCommand(args) {
|
|
|
3173
3215
|
let clearProviderKey = hasFlag(args, 'clear-provider-key');
|
|
3174
3216
|
if (hasFlag(args, 'interactive')) {
|
|
3175
3217
|
await withPromptSession(async (prompt) => {
|
|
3176
|
-
portRaw = await prompt.line('
|
|
3177
|
-
dbUrl = await prompt.line('
|
|
3178
|
-
providerInput = await prompt.line('
|
|
3218
|
+
portRaw = await prompt.line('API port', portRaw ?? env.IRANTI_PORT);
|
|
3219
|
+
dbUrl = await prompt.line('DATABASE_URL', dbUrl ?? env.DATABASE_URL);
|
|
3220
|
+
providerInput = await prompt.line('LLM provider', providerInput ?? env.LLM_PROVIDER ?? 'mock');
|
|
3179
3221
|
const interactiveProvider = normalizeProvider(providerInput ?? env.LLM_PROVIDER ?? 'mock');
|
|
3180
3222
|
const interactiveProviderEnvKey = providerKeyEnv(interactiveProvider);
|
|
3181
3223
|
if (interactiveProvider && interactiveProviderEnvKey) {
|
|
3182
|
-
providerKey = await prompt.secret(
|
|
3224
|
+
providerKey = await prompt.secret(`${providerDisplayName(interactiveProvider)} API key`, providerKey ?? env[interactiveProviderEnvKey]);
|
|
3183
3225
|
}
|
|
3184
3226
|
apiKey = await prompt.secret('Iranti API key', apiKey ?? env.IRANTI_API_KEY);
|
|
3185
3227
|
});
|
|
@@ -3256,12 +3298,12 @@ async function configureProjectCommand(args) {
|
|
|
3256
3298
|
let explicitProjectMode = getFlag(args, 'mode');
|
|
3257
3299
|
if (hasFlag(args, 'interactive')) {
|
|
3258
3300
|
await withPromptSession(async (prompt) => {
|
|
3259
|
-
instanceName = await prompt.line('
|
|
3260
|
-
explicitUrl = await prompt.line('
|
|
3261
|
-
explicitApiKey = await prompt.secret('
|
|
3262
|
-
explicitAgentId = await prompt.line('
|
|
3263
|
-
explicitMemoryEntity = await prompt.line('
|
|
3264
|
-
explicitProjectMode = await prompt.line('
|
|
3301
|
+
instanceName = await prompt.line('Instance name', instanceName);
|
|
3302
|
+
explicitUrl = await prompt.line('Iranti URL', explicitUrl ?? existing.IRANTI_URL);
|
|
3303
|
+
explicitApiKey = await prompt.secret('Project API key', explicitApiKey ?? existing.IRANTI_API_KEY);
|
|
3304
|
+
explicitAgentId = await prompt.line('Project agent ID', explicitAgentId ?? existing.IRANTI_AGENT_ID ?? projectAgentDefault(projectPath));
|
|
3305
|
+
explicitMemoryEntity = await prompt.line('Project memory entity', explicitMemoryEntity ?? existing.IRANTI_MEMORY_ENTITY ?? 'user/main');
|
|
3306
|
+
explicitProjectMode = await prompt.line('Project mode (isolated or shared)', explicitProjectMode ?? existing.IRANTI_PROJECT_MODE ?? inferProjectMode(projectPath, existing.IRANTI_INSTANCE_ENV));
|
|
3265
3307
|
});
|
|
3266
3308
|
}
|
|
3267
3309
|
let instanceEnvFile = existing.IRANTI_INSTANCE_ENV;
|
|
@@ -3675,24 +3717,26 @@ function printHelp() {
|
|
|
3675
3717
|
const printRows = (title, entries) => {
|
|
3676
3718
|
console.log(sectionTitle(title));
|
|
3677
3719
|
for (const [command, description] of entries) {
|
|
3678
|
-
console.log(` ${commandText(command
|
|
3720
|
+
console.log(` ${commandText(command)}`);
|
|
3721
|
+
console.log(` ${description}`);
|
|
3679
3722
|
}
|
|
3680
3723
|
console.log('');
|
|
3681
3724
|
};
|
|
3682
3725
|
console.log(sectionTitle('Iranti CLI'));
|
|
3683
3726
|
console.log('Memory infrastructure for multi-agent systems.');
|
|
3727
|
+
console.log('Most instance-aware commands also accept --root <path> in addition to --scope.');
|
|
3684
3728
|
console.log('');
|
|
3685
3729
|
printRows('Start Here', rows);
|
|
3686
3730
|
printRows('Setup And Runtime', [
|
|
3687
3731
|
['iranti install [--scope user|system] [--root <path>]', 'Initialize the machine-level runtime folders.'],
|
|
3688
|
-
['iranti setup [--scope user|system] [--root <path>] [--mode isolated|shared] [--config <file> | --defaults] [--db-mode local|managed|docker] [--db-url <url>] [--bootstrap-db]', 'Guided setup for runtime, database, instance, keys, and project binding.'],
|
|
3732
|
+
['iranti setup [--scope user|system] [--root <path>] [--mode isolated|shared] [--instance <name>] [--port <n>] [--config <file> | --defaults] [--db-mode local|managed|docker] [--db-url <url>] [--provider <name>] [--api-key <token>] [--projects <path1,path2>] [--claude-code] [--bootstrap-db]', 'Guided setup for runtime, database, instance, keys, and project binding. Run iranti setup --help for the non-interactive flow.'],
|
|
3689
3733
|
['iranti instance create <name> [--port 3001] [--db-url <url>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--scope user|system]', 'Create an instance directly if you want low-level control.'],
|
|
3690
3734
|
['iranti instance list [--scope user|system]', 'List configured instances.'],
|
|
3691
3735
|
['iranti instance show <name> [--scope user|system]', 'Show one instance env, port, and database target.'],
|
|
3692
3736
|
['iranti run --instance <name> [--scope user|system]', 'Start an instance.'],
|
|
3693
3737
|
]);
|
|
3694
3738
|
printRows('Configuration', [
|
|
3695
|
-
['iranti configure instance <name> [--interactive] [--db-url <url>] [--port <n>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--clear-provider-key]', 'Update an instance without editing env files manually.'],
|
|
3739
|
+
['iranti configure instance <name> [--interactive] [--db-url <url>] [--port <n>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--clear-provider-key] [--json]', 'Update an instance without editing env files manually.'],
|
|
3696
3740
|
['iranti project init [path] --instance <name> [--api-key <token>] [--agent-id <id>] [--mode isolated|shared] [--force]', 'Create a new .env.iranti binding for one project.'],
|
|
3697
3741
|
['iranti configure project [path] [--interactive] [--instance <name>] [--url <http://host:port>] [--api-key <token>] [--agent-id <id>] [--memory-entity <entity>] [--mode isolated|shared] [--json]', 'Refresh or retarget an existing project binding.'],
|
|
3698
3742
|
]);
|
|
@@ -3738,22 +3782,31 @@ function printHelp() {
|
|
|
3738
3782
|
console.log(` ${commandText('iranti auth create-key --instance local --key-id app_main --owner \"App Main\" --scopes \"kb:read,kb:write,memory:read,memory:write\"')}`);
|
|
3739
3783
|
console.log(` ${commandText('iranti add api-key openai --instance local --set-default')}`);
|
|
3740
3784
|
}
|
|
3785
|
+
function printSetupHelp() {
|
|
3786
|
+
console.log(sectionTitle('Setup Command'));
|
|
3787
|
+
console.log(` ${commandText('iranti setup [--scope user|system] [--root <path>] [--mode isolated|shared] [--instance <name>] [--port <n>] [--config <file> | --defaults] [--db-mode local|managed|docker] [--db-url <url>] [--provider <name>] [--api-key <token>] [--projects <path1,path2>] [--claude-code] [--bootstrap-db]')}`);
|
|
3788
|
+
console.log('');
|
|
3789
|
+
console.log(' Interactive mode walks through runtime, database, provider keys, API keys, and project binding.');
|
|
3790
|
+
console.log(' Use `--defaults` to build a plan from flags and environment variables without prompts.');
|
|
3791
|
+
console.log(' Use `--config <file>` to execute a saved setup plan.');
|
|
3792
|
+
console.log(' `--projects` and `--claude-code` apply to the non-interactive defaults flow.');
|
|
3793
|
+
}
|
|
3741
3794
|
function printInstanceHelp() {
|
|
3742
3795
|
console.log(sectionTitle('Instance Commands'));
|
|
3743
|
-
console.log(` ${commandText('iranti instance create <name> [--port 3001] [--db-url <url>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--scope user|system]')}`);
|
|
3744
|
-
console.log(` ${commandText('iranti instance list [--scope user|system]')}`);
|
|
3745
|
-
console.log(` ${commandText('iranti instance show <name> [--scope user|system]')}`);
|
|
3796
|
+
console.log(` ${commandText('iranti instance create <name> [--port 3001] [--db-url <url>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--scope user|system] [--root <path>]')}`);
|
|
3797
|
+
console.log(` ${commandText('iranti instance list [--scope user|system] [--root <path>]')}`);
|
|
3798
|
+
console.log(` ${commandText('iranti instance show <name> [--scope user|system] [--root <path>]')}`);
|
|
3746
3799
|
}
|
|
3747
3800
|
function printConfigureHelp() {
|
|
3748
3801
|
console.log(sectionTitle('Configure Commands'));
|
|
3749
|
-
console.log(` ${commandText('iranti configure instance <name> [--interactive] [--db-url <url>] [--port <n>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--clear-provider-key]')}`);
|
|
3750
|
-
console.log(` ${commandText('iranti configure project [path] [--interactive] [--instance <name>] [--url <http://host:port>] [--api-key <token>] [--agent-id <id>] [--memory-entity <entity>] [--mode isolated|shared] [--json]')}`);
|
|
3802
|
+
console.log(` ${commandText('iranti configure instance <name> [--interactive] [--db-url <url>] [--port <n>] [--api-key <token>] [--provider <name>] [--provider-key <token>] [--clear-provider-key] [--scope user|system] [--root <path>] [--json]')}`);
|
|
3803
|
+
console.log(` ${commandText('iranti configure project [path] [--interactive] [--instance <name>] [--url <http://host:port>] [--api-key <token>] [--agent-id <id>] [--memory-entity <entity>] [--mode isolated|shared] [--scope user|system] [--root <path>] [--json]')}`);
|
|
3751
3804
|
}
|
|
3752
3805
|
function printAuthHelp() {
|
|
3753
3806
|
console.log(sectionTitle('Auth Commands'));
|
|
3754
|
-
console.log(` ${commandText('iranti auth create-key --instance <name> --key-id <id> --owner <owner> [--scopes ...] [--description <text>] [--write-instance] [--project <path>] [--agent-id <id>] [--json]')}`);
|
|
3755
|
-
console.log(` ${commandText('iranti auth list-keys --instance <name> [--json]')}`);
|
|
3756
|
-
console.log(` ${commandText('iranti auth revoke-key --instance <name> --key-id <id> [--json]')}`);
|
|
3807
|
+
console.log(` ${commandText('iranti auth create-key --instance <name> --key-id <id> --owner <owner> [--scopes ...] [--description <text>] [--write-instance] [--project <path>] [--agent-id <id>] [--scope user|system] [--root <path>] [--json]')}`);
|
|
3808
|
+
console.log(` ${commandText('iranti auth list-keys --instance <name> [--scope user|system] [--root <path>] [--json]')}`);
|
|
3809
|
+
console.log(` ${commandText('iranti auth revoke-key --instance <name> --key-id <id> [--scope user|system] [--root <path>] [--json]')}`);
|
|
3757
3810
|
}
|
|
3758
3811
|
function printIntegrateHelp() {
|
|
3759
3812
|
console.log(sectionTitle('Integrations'));
|
|
@@ -3761,6 +3814,15 @@ function printIntegrateHelp() {
|
|
|
3761
3814
|
console.log(` ${commandText('iranti integrate claude --scan <dir> [--recursive] [--force]')}`);
|
|
3762
3815
|
console.log(` ${commandText('iranti integrate codex [--name iranti] [--agent codex_code] [--source Codex] [--provider openai] [--project-env <path>] [--local-script]')}`);
|
|
3763
3816
|
}
|
|
3817
|
+
function printProviderKeyHelp() {
|
|
3818
|
+
console.log(sectionTitle('Provider Key Commands'));
|
|
3819
|
+
console.log(` ${commandText('iranti list api-keys [--instance <name>] [--project <path>] [--json]')}`);
|
|
3820
|
+
console.log(` ${commandText('iranti add api-key [provider] [--instance <name>] [--project <path>] [--key <token>] [--set-default] [--json]')}`);
|
|
3821
|
+
console.log(` ${commandText('iranti update api-key [provider] [--instance <name>] [--project <path>] [--key <token>] [--set-default] [--json]')}`);
|
|
3822
|
+
console.log(` ${commandText('iranti remove api-key [provider] [--instance <name>] [--project <path>] [--json]')}`);
|
|
3823
|
+
console.log('');
|
|
3824
|
+
console.log(' Target either an instance env or a project binding. If neither is supplied, the CLI will try the current project first.');
|
|
3825
|
+
}
|
|
3764
3826
|
async function main() {
|
|
3765
3827
|
const args = parseArgs(process.argv.slice(2));
|
|
3766
3828
|
if (!args.command || args.command === 'help' || args.command === '--help') {
|
|
@@ -3772,6 +3834,10 @@ async function main() {
|
|
|
3772
3834
|
return;
|
|
3773
3835
|
}
|
|
3774
3836
|
if (args.command === 'setup') {
|
|
3837
|
+
if (hasFlag(args, 'help')) {
|
|
3838
|
+
printSetupHelp();
|
|
3839
|
+
return;
|
|
3840
|
+
}
|
|
3775
3841
|
await setupCommand(args);
|
|
3776
3842
|
return;
|
|
3777
3843
|
}
|
|
@@ -3833,18 +3899,34 @@ async function main() {
|
|
|
3833
3899
|
throw new Error(`Unknown auth subcommand '${args.subcommand ?? ''}'.`);
|
|
3834
3900
|
}
|
|
3835
3901
|
if (args.command === 'list' && args.subcommand === 'api-keys') {
|
|
3902
|
+
if (hasFlag(args, 'help')) {
|
|
3903
|
+
printProviderKeyHelp();
|
|
3904
|
+
return;
|
|
3905
|
+
}
|
|
3836
3906
|
await listProviderKeysCommand(args);
|
|
3837
3907
|
return;
|
|
3838
3908
|
}
|
|
3839
3909
|
if (args.command === 'add' && args.subcommand === 'api-key') {
|
|
3910
|
+
if (hasFlag(args, 'help')) {
|
|
3911
|
+
printProviderKeyHelp();
|
|
3912
|
+
return;
|
|
3913
|
+
}
|
|
3840
3914
|
await upsertProviderKeyCommand(args, 'add');
|
|
3841
3915
|
return;
|
|
3842
3916
|
}
|
|
3843
3917
|
if (args.command === 'update' && args.subcommand === 'api-key') {
|
|
3918
|
+
if (hasFlag(args, 'help')) {
|
|
3919
|
+
printProviderKeyHelp();
|
|
3920
|
+
return;
|
|
3921
|
+
}
|
|
3844
3922
|
await upsertProviderKeyCommand(args, 'update');
|
|
3845
3923
|
return;
|
|
3846
3924
|
}
|
|
3847
3925
|
if (args.command === 'remove' && args.subcommand === 'api-key') {
|
|
3926
|
+
if (hasFlag(args, 'help')) {
|
|
3927
|
+
printProviderKeyHelp();
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3848
3930
|
await removeProviderKeyCommand(args);
|
|
3849
3931
|
return;
|
|
3850
3932
|
}
|
|
@@ -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.11',
|
|
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.11',
|
|
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.11',
|
|
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.11',
|
|
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.11' },
|
|
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.11',
|
|
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.11',
|
|
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.11',
|
|
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.11',
|
|
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.11',
|
|
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.11',
|
|
241
241
|
events: [
|
|
242
242
|
{
|
|
243
243
|
at: new Date().toISOString(),
|
package/dist/src/api/server.js
CHANGED
|
@@ -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.2.
|
|
72
|
+
version: '0.2.11',
|
|
73
73
|
provider: process.env.LLM_PROVIDER ?? 'mock',
|
|
74
74
|
});
|
|
75
75
|
});
|