iranti 0.2.17 → 0.2.19
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 +14 -7
- package/dist/scripts/iranti-cli.js +693 -0
- package/dist/scripts/iranti-mcp.js +1 -1
- package/dist/src/api/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
Iranti gives agents persistent, identity-based memory. Facts written by one agent are retrievable by any other agent through exact entity+key lookup. Iranti also supports hybrid search (lexical + vector) when exact keys are unknown. Memory persists across sessions and survives context window limits.
|
|
11
11
|
|
|
12
|
-
**Latest release:** [`v0.2.
|
|
12
|
+
**Latest release:** [`v0.2.19`](https://github.com/nfemmanuel/iranti/releases/tag/v0.2.19)
|
|
13
13
|
Published packages:
|
|
14
|
-
- `iranti@0.2.
|
|
15
|
-
- `@iranti/sdk@0.2.
|
|
14
|
+
- `iranti@0.2.19`
|
|
15
|
+
- `@iranti/sdk@0.2.19`
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -71,10 +71,8 @@ Iranti has now been rerun against a broader benchmark program covering 13 capabi
|
|
|
71
71
|
### Current Limits
|
|
72
72
|
|
|
73
73
|
- **Search is not yet full semantic paraphrase retrieval.**
|
|
74
|
-
- **Observe still performs better
|
|
75
|
-
-
|
|
76
|
-
- silent retrieval drop when `/` appears inside certain fact values
|
|
77
|
-
- `user/main` noise from benchmark smoke artifacts
|
|
74
|
+
- **Observe still performs better on confidence ranking than on broad progress-fact discovery.**
|
|
75
|
+
- **Structured search is operational, but not yet broad semantic paraphrase retrieval.**
|
|
78
76
|
|
|
79
77
|
### Practical Position
|
|
80
78
|
|
|
@@ -214,6 +212,15 @@ iranti run --instance local --debug
|
|
|
214
212
|
iranti upgrade --verbose
|
|
215
213
|
```
|
|
216
214
|
|
|
215
|
+
If you want to remove Iranti cleanly:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
iranti uninstall --dry-run
|
|
219
|
+
iranti uninstall --all --yes
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Default uninstall keeps runtime data and project bindings. `--all` removes discovered runtime roots plus project-local Iranti integrations.
|
|
223
|
+
|
|
217
224
|
Advanced/manual path:
|
|
218
225
|
|
|
219
226
|
```bash
|
|
@@ -2352,6 +2352,592 @@ async function executeUpgradeTarget(target, context, options = {}) {
|
|
|
2352
2352
|
}
|
|
2353
2353
|
return { target, steps, verification };
|
|
2354
2354
|
}
|
|
2355
|
+
function resolveUninstallScanRoots(args) {
|
|
2356
|
+
const explicit = getFlag(args, 'scan-root');
|
|
2357
|
+
const candidates = explicit
|
|
2358
|
+
? explicit.split(',').map((value) => path_1.default.resolve(value.trim())).filter(Boolean)
|
|
2359
|
+
: [
|
|
2360
|
+
process.cwd(),
|
|
2361
|
+
path_1.default.join(os_1.default.homedir(), 'Documents', 'Projects'),
|
|
2362
|
+
].filter((value, index, array) => array.indexOf(value) === index);
|
|
2363
|
+
return candidates.filter((candidate, index, array) => candidate.length > 0
|
|
2364
|
+
&& fs_1.default.existsSync(candidate)
|
|
2365
|
+
&& array.indexOf(candidate) === index);
|
|
2366
|
+
}
|
|
2367
|
+
function runtimeRootFromInstanceEnv(envFile) {
|
|
2368
|
+
const normalized = path_1.default.resolve(envFile);
|
|
2369
|
+
const parts = normalized.split(path_1.default.sep);
|
|
2370
|
+
const instancesIndex = parts.lastIndexOf('instances');
|
|
2371
|
+
if (instancesIndex <= 0)
|
|
2372
|
+
return null;
|
|
2373
|
+
return parts.slice(0, instancesIndex).join(path_1.default.sep);
|
|
2374
|
+
}
|
|
2375
|
+
async function discoverRuntimeRoots(root, projectArtifacts, scanRoots) {
|
|
2376
|
+
const discovered = new Map();
|
|
2377
|
+
const add = (candidate, source) => {
|
|
2378
|
+
if (!candidate)
|
|
2379
|
+
return;
|
|
2380
|
+
const resolved = path_1.default.resolve(candidate);
|
|
2381
|
+
if (!fs_1.default.existsSync(resolved))
|
|
2382
|
+
return;
|
|
2383
|
+
if (!discovered.has(resolved)) {
|
|
2384
|
+
discovered.set(resolved, { path: resolved, source });
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
add(root, 'active-root');
|
|
2388
|
+
for (const artifact of projectArtifacts) {
|
|
2389
|
+
if (!artifact.bindingFile || !fs_1.default.existsSync(artifact.bindingFile))
|
|
2390
|
+
continue;
|
|
2391
|
+
try {
|
|
2392
|
+
const binding = await readEnvFile(artifact.bindingFile);
|
|
2393
|
+
add(runtimeRootFromInstanceEnv(binding.IRANTI_INSTANCE_ENV ?? ''), 'binding');
|
|
2394
|
+
}
|
|
2395
|
+
catch {
|
|
2396
|
+
continue;
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
for (const scanRoot of scanRoots) {
|
|
2400
|
+
const queue = [scanRoot];
|
|
2401
|
+
while (queue.length > 0) {
|
|
2402
|
+
const current = queue.shift();
|
|
2403
|
+
let entries = [];
|
|
2404
|
+
try {
|
|
2405
|
+
entries = await promises_1.default.readdir(current, { withFileTypes: true });
|
|
2406
|
+
}
|
|
2407
|
+
catch {
|
|
2408
|
+
continue;
|
|
2409
|
+
}
|
|
2410
|
+
for (const entry of entries) {
|
|
2411
|
+
if (!entry.isDirectory())
|
|
2412
|
+
continue;
|
|
2413
|
+
if (shouldSkipUninstallScanDir(entry.name))
|
|
2414
|
+
continue;
|
|
2415
|
+
const candidate = path_1.default.join(current, entry.name);
|
|
2416
|
+
if ((entry.name === '.iranti' || entry.name === '.iranti-runtime')
|
|
2417
|
+
&& (fs_1.default.existsSync(path_1.default.join(candidate, 'install.json')) || fs_1.default.existsSync(path_1.default.join(candidate, 'instances')))) {
|
|
2418
|
+
add(candidate, 'scan');
|
|
2419
|
+
continue;
|
|
2420
|
+
}
|
|
2421
|
+
queue.push(candidate);
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
return Array.from(discovered.values()).sort((a, b) => a.path.localeCompare(b.path));
|
|
2426
|
+
}
|
|
2427
|
+
async function collectUninstallProcesses(runtimeRoots, context) {
|
|
2428
|
+
const processes = new Map();
|
|
2429
|
+
for (const runtimeRoot of runtimeRoots) {
|
|
2430
|
+
const instances = await collectRuntimeInstanceSummaries(runtimeRoot.path);
|
|
2431
|
+
for (const instance of instances) {
|
|
2432
|
+
const pid = instance.runtime.state?.pid;
|
|
2433
|
+
if (!instance.runtime.running || !pid || pid === process.pid)
|
|
2434
|
+
continue;
|
|
2435
|
+
processes.set(pid, {
|
|
2436
|
+
pid,
|
|
2437
|
+
source: 'runtime',
|
|
2438
|
+
label: `instance:${instance.name}`,
|
|
2439
|
+
command: instance.runtime.state?.healthUrl,
|
|
2440
|
+
});
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
const probe = process.platform === 'win32'
|
|
2444
|
+
? runCommandCapture('powershell', [
|
|
2445
|
+
'-NoProfile',
|
|
2446
|
+
'-Command',
|
|
2447
|
+
'Get-CimInstance Win32_Process | Select-Object ProcessId, CommandLine | ConvertTo-Json -Compress',
|
|
2448
|
+
])
|
|
2449
|
+
: runCommandCapture('ps', ['-ax', '-o', 'pid=', '-o', 'command=']);
|
|
2450
|
+
if (probe.status === 0) {
|
|
2451
|
+
if (process.platform === 'win32') {
|
|
2452
|
+
try {
|
|
2453
|
+
const payload = JSON.parse(probe.stdout);
|
|
2454
|
+
const rows = Array.isArray(payload) ? payload : [payload];
|
|
2455
|
+
const needles = [
|
|
2456
|
+
context.packageRootPath.toLowerCase(),
|
|
2457
|
+
context.globalNpmRoot?.toLowerCase(),
|
|
2458
|
+
'iranti mcp',
|
|
2459
|
+
'iranti run',
|
|
2460
|
+
'iranti-cli',
|
|
2461
|
+
'iranti-mcp',
|
|
2462
|
+
'claude-code-memory-hook',
|
|
2463
|
+
].filter((value) => Boolean(value));
|
|
2464
|
+
for (const row of rows) {
|
|
2465
|
+
const pid = row.ProcessId;
|
|
2466
|
+
const command = row.CommandLine ?? '';
|
|
2467
|
+
if (!pid || pid === process.pid || !command)
|
|
2468
|
+
continue;
|
|
2469
|
+
const lower = command.toLowerCase();
|
|
2470
|
+
if (!needles.some((needle) => lower.includes(needle)))
|
|
2471
|
+
continue;
|
|
2472
|
+
processes.set(pid, {
|
|
2473
|
+
pid,
|
|
2474
|
+
source: 'process-scan',
|
|
2475
|
+
label: 'iranti-process',
|
|
2476
|
+
command,
|
|
2477
|
+
});
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
catch {
|
|
2481
|
+
// best effort only
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
else {
|
|
2485
|
+
const needles = [
|
|
2486
|
+
context.packageRootPath.toLowerCase(),
|
|
2487
|
+
context.globalNpmRoot?.toLowerCase(),
|
|
2488
|
+
'iranti mcp',
|
|
2489
|
+
'iranti run',
|
|
2490
|
+
'iranti-cli',
|
|
2491
|
+
'iranti-mcp',
|
|
2492
|
+
'claude-code-memory-hook',
|
|
2493
|
+
].filter((value) => Boolean(value));
|
|
2494
|
+
for (const line of probe.stdout.split(/\r?\n/)) {
|
|
2495
|
+
const match = line.trim().match(/^(\d+)\s+(.*)$/);
|
|
2496
|
+
if (!match)
|
|
2497
|
+
continue;
|
|
2498
|
+
const pid = Number.parseInt(match[1] ?? '', 10);
|
|
2499
|
+
const command = match[2] ?? '';
|
|
2500
|
+
if (!pid || pid === process.pid)
|
|
2501
|
+
continue;
|
|
2502
|
+
const lower = command.toLowerCase();
|
|
2503
|
+
if (!needles.some((needle) => lower.includes(needle)))
|
|
2504
|
+
continue;
|
|
2505
|
+
processes.set(pid, {
|
|
2506
|
+
pid,
|
|
2507
|
+
source: 'process-scan',
|
|
2508
|
+
label: 'iranti-process',
|
|
2509
|
+
command,
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
return Array.from(processes.values()).sort((a, b) => a.pid - b.pid);
|
|
2515
|
+
}
|
|
2516
|
+
function detectCodexRegistration(name = 'iranti') {
|
|
2517
|
+
if (!hasCodexInstalled())
|
|
2518
|
+
return false;
|
|
2519
|
+
const proc = runCommandCapture('codex', ['mcp', 'get', name, '--json']);
|
|
2520
|
+
return proc.status === 0;
|
|
2521
|
+
}
|
|
2522
|
+
function removeIrantiMcpServerFromValue(value) {
|
|
2523
|
+
const mcpServers = value.mcpServers;
|
|
2524
|
+
if (!mcpServers || typeof mcpServers !== 'object' || Array.isArray(mcpServers))
|
|
2525
|
+
return value;
|
|
2526
|
+
const nextServers = { ...mcpServers };
|
|
2527
|
+
delete nextServers.iranti;
|
|
2528
|
+
if (Object.keys(nextServers).length === 0) {
|
|
2529
|
+
const next = { ...value };
|
|
2530
|
+
delete next.mcpServers;
|
|
2531
|
+
return Object.keys(next).length === 0 ? null : next;
|
|
2532
|
+
}
|
|
2533
|
+
return {
|
|
2534
|
+
...value,
|
|
2535
|
+
mcpServers: nextServers,
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
function removeIrantiClaudeHooksFromValue(value) {
|
|
2539
|
+
const hooks = isClaudeHooksObject(value.hooks) ? value.hooks : null;
|
|
2540
|
+
if (!hooks)
|
|
2541
|
+
return value;
|
|
2542
|
+
const nextHooks = { ...hooks };
|
|
2543
|
+
for (const event of ['SessionStart', 'UserPromptSubmit']) {
|
|
2544
|
+
const entries = hooks[event];
|
|
2545
|
+
if (!Array.isArray(entries))
|
|
2546
|
+
continue;
|
|
2547
|
+
const filtered = entries.filter((entry) => {
|
|
2548
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
2549
|
+
return true;
|
|
2550
|
+
if (isLegacyIrantiClaudeHookEntry(entry))
|
|
2551
|
+
return false;
|
|
2552
|
+
const structured = entry;
|
|
2553
|
+
const nestedHooks = Array.isArray(structured.hooks) ? structured.hooks : [];
|
|
2554
|
+
const remainingNested = nestedHooks.filter((hook) => {
|
|
2555
|
+
if (!hook || typeof hook !== 'object' || Array.isArray(hook))
|
|
2556
|
+
return true;
|
|
2557
|
+
const command = typeof hook.command === 'string'
|
|
2558
|
+
? String(hook.command)
|
|
2559
|
+
: '';
|
|
2560
|
+
return !command.includes('iranti claude-hook');
|
|
2561
|
+
});
|
|
2562
|
+
if (remainingNested.length !== nestedHooks.length) {
|
|
2563
|
+
if (remainingNested.length === 0) {
|
|
2564
|
+
return false;
|
|
2565
|
+
}
|
|
2566
|
+
structured.hooks = remainingNested;
|
|
2567
|
+
}
|
|
2568
|
+
return true;
|
|
2569
|
+
});
|
|
2570
|
+
if (filtered.length === 0) {
|
|
2571
|
+
delete nextHooks[event];
|
|
2572
|
+
}
|
|
2573
|
+
else {
|
|
2574
|
+
nextHooks[event] = filtered;
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
const next = { ...value };
|
|
2578
|
+
if (Object.keys(nextHooks).length === 0) {
|
|
2579
|
+
delete next.hooks;
|
|
2580
|
+
}
|
|
2581
|
+
else {
|
|
2582
|
+
next.hooks = nextHooks;
|
|
2583
|
+
}
|
|
2584
|
+
return Object.keys(next).length === 0 ? null : next;
|
|
2585
|
+
}
|
|
2586
|
+
async function cleanupProjectArtifacts(artifacts) {
|
|
2587
|
+
const results = [];
|
|
2588
|
+
for (const artifact of artifacts) {
|
|
2589
|
+
if (artifact.bindingFile && fs_1.default.existsSync(artifact.bindingFile)) {
|
|
2590
|
+
await promises_1.default.rm(artifact.bindingFile, { force: true });
|
|
2591
|
+
results.push({
|
|
2592
|
+
label: 'project-binding',
|
|
2593
|
+
status: 'pass',
|
|
2594
|
+
detail: `Removed ${artifact.bindingFile}`,
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
if (artifact.mcpFile && fs_1.default.existsSync(artifact.mcpFile)) {
|
|
2598
|
+
const parsed = readJsonFile(artifact.mcpFile);
|
|
2599
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
2600
|
+
const next = removeIrantiMcpServerFromValue(parsed);
|
|
2601
|
+
if (!next) {
|
|
2602
|
+
await promises_1.default.rm(artifact.mcpFile, { force: true });
|
|
2603
|
+
results.push({
|
|
2604
|
+
label: 'project-mcp',
|
|
2605
|
+
status: 'pass',
|
|
2606
|
+
detail: `Removed ${artifact.mcpFile}`,
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
else {
|
|
2610
|
+
await writeText(artifact.mcpFile, `${JSON.stringify(next, null, 2)}\n`);
|
|
2611
|
+
results.push({
|
|
2612
|
+
label: 'project-mcp',
|
|
2613
|
+
status: 'pass',
|
|
2614
|
+
detail: `Removed Iranti MCP entry from ${artifact.mcpFile}`,
|
|
2615
|
+
});
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
else {
|
|
2619
|
+
results.push({
|
|
2620
|
+
label: 'project-mcp',
|
|
2621
|
+
status: 'warn',
|
|
2622
|
+
detail: `Skipped unreadable JSON file ${artifact.mcpFile}`,
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
if (artifact.claudeSettingsFile && fs_1.default.existsSync(artifact.claudeSettingsFile)) {
|
|
2627
|
+
const parsed = readJsonFile(artifact.claudeSettingsFile);
|
|
2628
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
2629
|
+
const next = removeIrantiClaudeHooksFromValue(parsed);
|
|
2630
|
+
if (!next) {
|
|
2631
|
+
await promises_1.default.rm(artifact.claudeSettingsFile, { force: true });
|
|
2632
|
+
results.push({
|
|
2633
|
+
label: 'project-claude',
|
|
2634
|
+
status: 'pass',
|
|
2635
|
+
detail: `Removed ${artifact.claudeSettingsFile}`,
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
else {
|
|
2639
|
+
await writeText(artifact.claudeSettingsFile, `${JSON.stringify(next, null, 2)}\n`);
|
|
2640
|
+
results.push({
|
|
2641
|
+
label: 'project-claude',
|
|
2642
|
+
status: 'pass',
|
|
2643
|
+
detail: `Removed Iranti Claude hooks from ${artifact.claudeSettingsFile}`,
|
|
2644
|
+
});
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
else {
|
|
2648
|
+
results.push({
|
|
2649
|
+
label: 'project-claude',
|
|
2650
|
+
status: 'warn',
|
|
2651
|
+
detail: `Skipped unreadable JSON file ${artifact.claudeSettingsFile}`,
|
|
2652
|
+
});
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
return results;
|
|
2657
|
+
}
|
|
2658
|
+
async function runUninstallCommand(step) {
|
|
2659
|
+
const proc = runCommandCapture(step.executable, step.args, step.cwd);
|
|
2660
|
+
if (proc.status === 0) {
|
|
2661
|
+
return {
|
|
2662
|
+
label: step.label,
|
|
2663
|
+
status: 'pass',
|
|
2664
|
+
detail: `${step.display} completed successfully.`,
|
|
2665
|
+
};
|
|
2666
|
+
}
|
|
2667
|
+
return {
|
|
2668
|
+
label: step.label,
|
|
2669
|
+
status: 'warn',
|
|
2670
|
+
detail: `${step.display} exited with status ${proc.status ?? -1}: ${(proc.stderr || proc.stdout).trim() || 'unknown error'}`,
|
|
2671
|
+
};
|
|
2672
|
+
}
|
|
2673
|
+
async function stopUninstallProcesses(processes) {
|
|
2674
|
+
const results = [];
|
|
2675
|
+
for (const candidate of processes) {
|
|
2676
|
+
const stopped = await stopRuntimeProcess(candidate.pid, 5000);
|
|
2677
|
+
results.push({
|
|
2678
|
+
label: 'stop-process',
|
|
2679
|
+
status: stopped ? 'pass' : 'warn',
|
|
2680
|
+
detail: `${stopped ? 'Stopped' : 'Could not stop'} pid=${candidate.pid} (${candidate.label})`,
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
return results;
|
|
2684
|
+
}
|
|
2685
|
+
function buildDetachedWindowsUninstallScript(options) {
|
|
2686
|
+
const lines = [
|
|
2687
|
+
`$parentPid = ${options.parentPid}`,
|
|
2688
|
+
'while (Get-Process -Id $parentPid -ErrorAction SilentlyContinue) { Start-Sleep -Milliseconds 500 }',
|
|
2689
|
+
];
|
|
2690
|
+
for (const pid of options.stopPids) {
|
|
2691
|
+
lines.push(`taskkill /PID ${pid} /T /F > $null 2>&1`);
|
|
2692
|
+
}
|
|
2693
|
+
if (options.removeCodex) {
|
|
2694
|
+
lines.push("$codexGet = Get-Command codex -ErrorAction SilentlyContinue");
|
|
2695
|
+
lines.push("if ($codexGet) { codex mcp get iranti --json > $null 2>&1; if ($LASTEXITCODE -eq 0) { codex mcp remove iranti > $null 2>&1 } }");
|
|
2696
|
+
}
|
|
2697
|
+
if (options.removeGlobalNpm) {
|
|
2698
|
+
lines.push('& npm uninstall -g iranti');
|
|
2699
|
+
}
|
|
2700
|
+
if (options.python) {
|
|
2701
|
+
const args = options.python.args.map((arg) => `'${escapeForSingleQuotedPowerShell(arg)}'`).join(', ');
|
|
2702
|
+
lines.push(`& '${escapeForSingleQuotedPowerShell(options.python.executable)}' @(${args})`);
|
|
2703
|
+
}
|
|
2704
|
+
for (const filePath of options.artifactFiles) {
|
|
2705
|
+
lines.push(`if (Test-Path -LiteralPath '${escapeForSingleQuotedPowerShell(filePath)}') { Remove-Item -LiteralPath '${escapeForSingleQuotedPowerShell(filePath)}' -Force }`);
|
|
2706
|
+
}
|
|
2707
|
+
for (const dirPath of options.runtimeRoots) {
|
|
2708
|
+
lines.push(`if (Test-Path -LiteralPath '${escapeForSingleQuotedPowerShell(dirPath)}') { Remove-Item -LiteralPath '${escapeForSingleQuotedPowerShell(dirPath)}' -Recurse -Force }`);
|
|
2709
|
+
}
|
|
2710
|
+
lines.push('exit 0');
|
|
2711
|
+
return lines.join('; ');
|
|
2712
|
+
}
|
|
2713
|
+
async function uninstallCommand(args) {
|
|
2714
|
+
const scope = normalizeScope(getFlag(args, 'scope'));
|
|
2715
|
+
const root = resolveInstallRoot(args, scope);
|
|
2716
|
+
const json = hasFlag(args, 'json');
|
|
2717
|
+
const dryRun = hasFlag(args, 'dry-run');
|
|
2718
|
+
const executeFlag = hasFlag(args, 'yes');
|
|
2719
|
+
const removeAll = hasFlag(args, 'all');
|
|
2720
|
+
const keepData = hasFlag(args, 'keep-data');
|
|
2721
|
+
const keepProjectBindings = hasFlag(args, 'keep-project-bindings');
|
|
2722
|
+
const scanRoots = resolveUninstallScanRoots(args);
|
|
2723
|
+
const context = detectUpgradeContext(args);
|
|
2724
|
+
const projectArtifacts = removeAll && !keepProjectBindings
|
|
2725
|
+
? await discoverProjectArtifacts(scanRoots)
|
|
2726
|
+
: [];
|
|
2727
|
+
const runtimeRoots = await discoverRuntimeRoots(root, projectArtifacts, scanRoots);
|
|
2728
|
+
const processes = await collectUninstallProcesses(runtimeRoots, context);
|
|
2729
|
+
const codexRegistration = removeAll && !keepProjectBindings && detectCodexRegistration('iranti');
|
|
2730
|
+
const pythonCommand = context.python
|
|
2731
|
+
? {
|
|
2732
|
+
...context.python,
|
|
2733
|
+
label: 'python uninstall',
|
|
2734
|
+
display: `${context.python.executable}${context.python.args[0] === '-3' ? ' -3' : ''} -m pip uninstall -y iranti`,
|
|
2735
|
+
args: (context.python.args[0] === '-3' ? ['-3', '-m', 'pip'] : ['-m', 'pip']).concat(['uninstall', '-y', 'iranti']),
|
|
2736
|
+
}
|
|
2737
|
+
: null;
|
|
2738
|
+
const actions = {
|
|
2739
|
+
stopProcesses: processes.length > 0,
|
|
2740
|
+
removeGlobalNpm: context.globalNpmInstall,
|
|
2741
|
+
removePython: context.pythonVersion !== null && pythonCommand !== null,
|
|
2742
|
+
removeRuntimeRoots: removeAll && !keepData && runtimeRoots.length > 0,
|
|
2743
|
+
removeProjectBindings: removeAll && !keepProjectBindings && projectArtifacts.length > 0,
|
|
2744
|
+
removeCodexRegistration: codexRegistration,
|
|
2745
|
+
};
|
|
2746
|
+
let execute = executeFlag;
|
|
2747
|
+
let note = null;
|
|
2748
|
+
if (!execute && !dryRun && !json && process.stdin.isTTY && process.stdout.isTTY) {
|
|
2749
|
+
await withPromptSession(async (prompt) => {
|
|
2750
|
+
execute = await promptYesNo(prompt, 'Proceed with uninstall using the plan below?', false);
|
|
2751
|
+
});
|
|
2752
|
+
if (!execute) {
|
|
2753
|
+
note = 'Uninstall cancelled.';
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
else if (!execute && !dryRun) {
|
|
2757
|
+
note = 'Run with --yes to execute the uninstall, or use --dry-run to inspect the plan safely.';
|
|
2758
|
+
}
|
|
2759
|
+
const plannedSteps = [];
|
|
2760
|
+
if (actions.stopProcesses)
|
|
2761
|
+
plannedSteps.push(`Stop ${processes.length} live Iranti process(es)`);
|
|
2762
|
+
if (actions.removeGlobalNpm)
|
|
2763
|
+
plannedSteps.push('Remove global npm install');
|
|
2764
|
+
if (actions.removePython)
|
|
2765
|
+
plannedSteps.push('Remove Python client');
|
|
2766
|
+
if (actions.removeCodexRegistration)
|
|
2767
|
+
plannedSteps.push('Remove Codex MCP registration');
|
|
2768
|
+
if (actions.removeProjectBindings)
|
|
2769
|
+
plannedSteps.push(`Clean ${projectArtifacts.length} project binding/integration surface(s)`);
|
|
2770
|
+
if (actions.removeRuntimeRoots)
|
|
2771
|
+
plannedSteps.push(`Delete ${runtimeRoots.length} runtime root(s)`);
|
|
2772
|
+
const actionLabel = execute ? 'uninstall' : dryRun ? 'dry-run' : 'inspect';
|
|
2773
|
+
const execution = [];
|
|
2774
|
+
const requiresDetachedWindowsSelfUninstall = process.platform === 'win32'
|
|
2775
|
+
&& actions.removeGlobalNpm
|
|
2776
|
+
&& context.runningFromGlobalNpmInstall
|
|
2777
|
+
&& execute
|
|
2778
|
+
&& !dryRun;
|
|
2779
|
+
if (execute && !dryRun) {
|
|
2780
|
+
if (requiresDetachedWindowsSelfUninstall) {
|
|
2781
|
+
const artifactFiles = projectArtifacts.flatMap((artifact) => [artifact.bindingFile, artifact.mcpFile, artifact.claudeSettingsFile]
|
|
2782
|
+
.filter((value) => Boolean(value)));
|
|
2783
|
+
const script = buildDetachedWindowsUninstallScript({
|
|
2784
|
+
parentPid: process.pid,
|
|
2785
|
+
stopPids: processes.map((candidate) => candidate.pid),
|
|
2786
|
+
removeCodex: actions.removeCodexRegistration,
|
|
2787
|
+
python: actions.removePython ? pythonCommand : null,
|
|
2788
|
+
removeGlobalNpm: actions.removeGlobalNpm,
|
|
2789
|
+
runtimeRoots: actions.removeRuntimeRoots ? runtimeRoots.map((entry) => entry.path) : [],
|
|
2790
|
+
artifactFiles,
|
|
2791
|
+
});
|
|
2792
|
+
const child = (0, child_process_1.spawn)('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', script], {
|
|
2793
|
+
detached: true,
|
|
2794
|
+
stdio: 'ignore',
|
|
2795
|
+
windowsHide: true,
|
|
2796
|
+
cwd: os_1.default.homedir(),
|
|
2797
|
+
env: process.env,
|
|
2798
|
+
});
|
|
2799
|
+
child.unref();
|
|
2800
|
+
execution.push({
|
|
2801
|
+
label: 'detached-uninstall',
|
|
2802
|
+
status: 'warn',
|
|
2803
|
+
detail: 'Scheduled detached uninstall because the current Windows CLI cannot remove its own live global npm install in place.',
|
|
2804
|
+
});
|
|
2805
|
+
note = 'Wait a few seconds, then open a new shell and verify `iranti` is gone from PATH.';
|
|
2806
|
+
}
|
|
2807
|
+
else {
|
|
2808
|
+
if (actions.stopProcesses) {
|
|
2809
|
+
execution.push(...await stopUninstallProcesses(processes));
|
|
2810
|
+
}
|
|
2811
|
+
if (actions.removeCodexRegistration) {
|
|
2812
|
+
const proc = runCommandCapture('codex', ['mcp', 'remove', 'iranti']);
|
|
2813
|
+
execution.push({
|
|
2814
|
+
label: 'codex-mcp',
|
|
2815
|
+
status: proc.status === 0 ? 'pass' : 'warn',
|
|
2816
|
+
detail: proc.status === 0
|
|
2817
|
+
? 'Removed Codex MCP registration.'
|
|
2818
|
+
: `Could not remove Codex MCP registration: ${(proc.stderr || proc.stdout).trim() || 'unknown error'}`,
|
|
2819
|
+
});
|
|
2820
|
+
}
|
|
2821
|
+
if (actions.removeGlobalNpm) {
|
|
2822
|
+
execution.push(await runUninstallCommand({
|
|
2823
|
+
label: 'npm uninstall',
|
|
2824
|
+
display: 'npm uninstall -g iranti',
|
|
2825
|
+
executable: 'npm',
|
|
2826
|
+
args: ['uninstall', '-g', 'iranti'],
|
|
2827
|
+
cwd: context.packageRootPath,
|
|
2828
|
+
}));
|
|
2829
|
+
}
|
|
2830
|
+
if (actions.removePython && pythonCommand) {
|
|
2831
|
+
execution.push(await runUninstallCommand(pythonCommand));
|
|
2832
|
+
}
|
|
2833
|
+
if (actions.removeProjectBindings) {
|
|
2834
|
+
execution.push(...await cleanupProjectArtifacts(projectArtifacts));
|
|
2835
|
+
}
|
|
2836
|
+
if (actions.removeRuntimeRoots) {
|
|
2837
|
+
for (const runtimeRoot of runtimeRoots) {
|
|
2838
|
+
await promises_1.default.rm(runtimeRoot.path, { recursive: true, force: true });
|
|
2839
|
+
execution.push({
|
|
2840
|
+
label: 'runtime-root',
|
|
2841
|
+
status: 'pass',
|
|
2842
|
+
detail: `Removed ${runtimeRoot.path}`,
|
|
2843
|
+
});
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
if (json) {
|
|
2849
|
+
console.log(JSON.stringify({
|
|
2850
|
+
currentVersion: context.currentVersion,
|
|
2851
|
+
runtimeRoot: root,
|
|
2852
|
+
scanRoots,
|
|
2853
|
+
removeAll,
|
|
2854
|
+
keepData,
|
|
2855
|
+
keepProjectBindings,
|
|
2856
|
+
install: {
|
|
2857
|
+
globalNpmVersion: context.globalNpmVersion,
|
|
2858
|
+
pythonVersion: context.pythonVersion,
|
|
2859
|
+
runningFromGlobalNpmInstall: context.runningFromGlobalNpmInstall,
|
|
2860
|
+
codexRegistration,
|
|
2861
|
+
},
|
|
2862
|
+
runtimeRoots,
|
|
2863
|
+
projectArtifacts,
|
|
2864
|
+
processes,
|
|
2865
|
+
actions,
|
|
2866
|
+
plan: plannedSteps,
|
|
2867
|
+
action: actionLabel,
|
|
2868
|
+
execution,
|
|
2869
|
+
note,
|
|
2870
|
+
}, null, 2));
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
console.log(sectionTitle('Iranti Uninstall'));
|
|
2874
|
+
console.log(` current_version ${context.currentVersion}`);
|
|
2875
|
+
console.log(` runtime_root ${root}`);
|
|
2876
|
+
console.log(` npm_global ${context.globalNpmVersion ?? paint('not installed', 'gray')}`);
|
|
2877
|
+
console.log(` python ${context.pythonVersion ?? paint('not installed', 'gray')}`);
|
|
2878
|
+
console.log(` codex_registration ${codexRegistration ? paint('yes', 'green') : paint('no', 'gray')}`);
|
|
2879
|
+
console.log(` remove_all ${removeAll ? paint('yes', 'yellow') : paint('no', 'gray')}`);
|
|
2880
|
+
console.log(` keep_data ${keepData ? paint('yes', 'yellow') : paint('no', 'gray')}`);
|
|
2881
|
+
console.log(` keep_project_bindings ${keepProjectBindings ? paint('yes', 'yellow') : paint('no', 'gray')}`);
|
|
2882
|
+
console.log('');
|
|
2883
|
+
console.log(` scan_roots ${scanRoots.length > 0 ? scanRoots.join(', ') : '(none)'}`);
|
|
2884
|
+
console.log(` live_processes ${processes.length}`);
|
|
2885
|
+
console.log(` project_artifacts ${projectArtifacts.length}`);
|
|
2886
|
+
console.log(` runtime_roots ${runtimeRoots.length}`);
|
|
2887
|
+
console.log('');
|
|
2888
|
+
if (plannedSteps.length > 0) {
|
|
2889
|
+
console.log(' plan');
|
|
2890
|
+
for (const step of plannedSteps) {
|
|
2891
|
+
console.log(` - ${step}`);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
else {
|
|
2895
|
+
console.log(' plan');
|
|
2896
|
+
console.log(' - Nothing to remove.');
|
|
2897
|
+
}
|
|
2898
|
+
if (processes.length > 0) {
|
|
2899
|
+
console.log('');
|
|
2900
|
+
console.log(' processes');
|
|
2901
|
+
for (const candidate of processes) {
|
|
2902
|
+
console.log(` - pid=${candidate.pid} ${candidate.label}${candidate.command ? ` :: ${truncateText(candidate.command, 120)}` : ''}`);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
if (projectArtifacts.length > 0) {
|
|
2906
|
+
console.log('');
|
|
2907
|
+
console.log(' project_artifacts');
|
|
2908
|
+
for (const artifact of projectArtifacts) {
|
|
2909
|
+
console.log(` - ${artifact.projectPath}`);
|
|
2910
|
+
if (artifact.bindingFile)
|
|
2911
|
+
console.log(` binding ${artifact.bindingFile}`);
|
|
2912
|
+
if (artifact.mcpFile)
|
|
2913
|
+
console.log(` mcp ${artifact.mcpFile}`);
|
|
2914
|
+
if (artifact.claudeSettingsFile)
|
|
2915
|
+
console.log(` claude ${artifact.claudeSettingsFile}`);
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
if (runtimeRoots.length > 0) {
|
|
2919
|
+
console.log('');
|
|
2920
|
+
console.log(' runtime_roots');
|
|
2921
|
+
for (const runtimeRoot of runtimeRoots) {
|
|
2922
|
+
console.log(` - ${runtimeRoot.path} (${runtimeRoot.source})`);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
if (execution.length > 0) {
|
|
2926
|
+
console.log('');
|
|
2927
|
+
for (const result of execution) {
|
|
2928
|
+
const marker = result.status === 'pass'
|
|
2929
|
+
? okLabel('PASS')
|
|
2930
|
+
: result.status === 'warn'
|
|
2931
|
+
? warnLabel('WARN')
|
|
2932
|
+
: failLabel('FAIL');
|
|
2933
|
+
console.log(`${marker} ${result.detail}`);
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
if (note) {
|
|
2937
|
+
console.log('');
|
|
2938
|
+
console.log(`${infoLabel()} ${note}`);
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2355
2941
|
async function listProviderKeysCommand(args) {
|
|
2356
2942
|
const target = await resolveProviderKeyTarget(args);
|
|
2357
2943
|
const currentProvider = normalizeProvider(target.env.LLM_PROVIDER ?? 'mock');
|
|
@@ -3962,6 +4548,96 @@ function findClaudeProjects(scanDir, recursive) {
|
|
|
3962
4548
|
found.delete(scanDir);
|
|
3963
4549
|
return Array.from(found).sort((a, b) => a.localeCompare(b));
|
|
3964
4550
|
}
|
|
4551
|
+
function shouldSkipUninstallScanDir(name) {
|
|
4552
|
+
if (name.startsWith('.git'))
|
|
4553
|
+
return true;
|
|
4554
|
+
return shouldSkipRecursiveClaudeScanDir(name) || [
|
|
4555
|
+
'.venv',
|
|
4556
|
+
'venv',
|
|
4557
|
+
].includes(name);
|
|
4558
|
+
}
|
|
4559
|
+
function hasIrantiMcpServerConfig(value) {
|
|
4560
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
4561
|
+
return false;
|
|
4562
|
+
const record = value;
|
|
4563
|
+
const mcpServers = record.mcpServers;
|
|
4564
|
+
if (!mcpServers || typeof mcpServers !== 'object' || Array.isArray(mcpServers))
|
|
4565
|
+
return false;
|
|
4566
|
+
return Object.prototype.hasOwnProperty.call(mcpServers, 'iranti');
|
|
4567
|
+
}
|
|
4568
|
+
function hasIrantiClaudeHookSettings(value) {
|
|
4569
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
4570
|
+
return false;
|
|
4571
|
+
const record = value;
|
|
4572
|
+
const hooks = isClaudeHooksObject(record.hooks) ? record.hooks : null;
|
|
4573
|
+
if (!hooks)
|
|
4574
|
+
return false;
|
|
4575
|
+
for (const event of ['SessionStart', 'UserPromptSubmit']) {
|
|
4576
|
+
const entries = hooks[event];
|
|
4577
|
+
if (!Array.isArray(entries))
|
|
4578
|
+
continue;
|
|
4579
|
+
for (const entry of entries) {
|
|
4580
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry))
|
|
4581
|
+
continue;
|
|
4582
|
+
if (isLegacyIrantiClaudeHookEntry(entry))
|
|
4583
|
+
return true;
|
|
4584
|
+
const structured = entry;
|
|
4585
|
+
const nestedHooks = Array.isArray(structured.hooks) ? structured.hooks : [];
|
|
4586
|
+
if (nestedHooks.some((hook) => {
|
|
4587
|
+
if (!hook || typeof hook !== 'object' || Array.isArray(hook))
|
|
4588
|
+
return false;
|
|
4589
|
+
const command = typeof hook.command === 'string'
|
|
4590
|
+
? String(hook.command)
|
|
4591
|
+
: '';
|
|
4592
|
+
return command.includes('iranti claude-hook');
|
|
4593
|
+
})) {
|
|
4594
|
+
return true;
|
|
4595
|
+
}
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
return false;
|
|
4599
|
+
}
|
|
4600
|
+
async function discoverProjectArtifacts(scanRoots) {
|
|
4601
|
+
const projects = new Map();
|
|
4602
|
+
for (const scanRoot of scanRoots) {
|
|
4603
|
+
if (!fs_1.default.existsSync(scanRoot))
|
|
4604
|
+
continue;
|
|
4605
|
+
const queue = [scanRoot];
|
|
4606
|
+
while (queue.length > 0) {
|
|
4607
|
+
const current = queue.shift();
|
|
4608
|
+
let entries = [];
|
|
4609
|
+
try {
|
|
4610
|
+
entries = await promises_1.default.readdir(current, { withFileTypes: true });
|
|
4611
|
+
}
|
|
4612
|
+
catch {
|
|
4613
|
+
continue;
|
|
4614
|
+
}
|
|
4615
|
+
const bindingFile = path_1.default.join(current, '.env.iranti');
|
|
4616
|
+
const mcpFile = path_1.default.join(current, '.mcp.json');
|
|
4617
|
+
const claudeSettingsFile = path_1.default.join(current, '.claude', 'settings.local.json');
|
|
4618
|
+
const artifact = { projectPath: current };
|
|
4619
|
+
if (fs_1.default.existsSync(bindingFile))
|
|
4620
|
+
artifact.bindingFile = bindingFile;
|
|
4621
|
+
if (fs_1.default.existsSync(mcpFile) && hasIrantiMcpServerConfig(readJsonFile(mcpFile))) {
|
|
4622
|
+
artifact.mcpFile = mcpFile;
|
|
4623
|
+
}
|
|
4624
|
+
if (fs_1.default.existsSync(claudeSettingsFile) && hasIrantiClaudeHookSettings(readJsonFile(claudeSettingsFile))) {
|
|
4625
|
+
artifact.claudeSettingsFile = claudeSettingsFile;
|
|
4626
|
+
}
|
|
4627
|
+
if (artifact.bindingFile || artifact.mcpFile || artifact.claudeSettingsFile) {
|
|
4628
|
+
projects.set(current, artifact);
|
|
4629
|
+
}
|
|
4630
|
+
for (const entry of entries) {
|
|
4631
|
+
if (!entry.isDirectory())
|
|
4632
|
+
continue;
|
|
4633
|
+
if (shouldSkipUninstallScanDir(entry.name))
|
|
4634
|
+
continue;
|
|
4635
|
+
queue.push(path_1.default.join(current, entry.name));
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
return Array.from(projects.values()).sort((a, b) => a.projectPath.localeCompare(b.projectPath));
|
|
4640
|
+
}
|
|
3965
4641
|
async function claudeSetupCommand(args) {
|
|
3966
4642
|
if (hasFlag(args, 'help')) {
|
|
3967
4643
|
printClaudeSetupHelp();
|
|
@@ -4097,6 +4773,7 @@ function printHelp() {
|
|
|
4097
4773
|
['iranti doctor [--instance <name>] [--scope user|system] [--env <file>] [--json] [--debug]', 'Run environment and runtime diagnostics.'],
|
|
4098
4774
|
['iranti status [--scope user|system] [--json]', 'Show runtime roots, bindings, and known instances.'],
|
|
4099
4775
|
['iranti upgrade [--check] [--dry-run] [--yes] [--all] [--target auto|npm-global|npm-repo|python[,python]] [--json]', 'Check or run CLI/runtime/package upgrades.'],
|
|
4776
|
+
['iranti uninstall [--dry-run] [--yes] [--all] [--keep-data] [--keep-project-bindings] [--scan-root <dir[,dir2]>] [--json]', 'Remove Iranti packages and, with --all, runtime data and project integrations.'],
|
|
4100
4777
|
['iranti handshake [--instance <name> | --project-env <file>] [--agent <id>] [--task <text>] [--recent <msg1||msg2>] [--recent-file <path>] [--json]', 'Manually inspect Attendant handshake output.'],
|
|
4101
4778
|
['iranti attend [message] [--instance <name> | --project-env <file>] [--agent <id>] [--context <text> | --context-file <path>] [--entity-hint <entity>] [--force] [--max-facts <n>] [--json]', 'Manually inspect turn-level memory injection decisions.'],
|
|
4102
4779
|
['iranti chat [--agent <agent-id>] [--provider <provider>] [--model <model>]', 'Open the local interactive chat shell.'],
|
|
@@ -4135,6 +4812,14 @@ function printSetupHelp() {
|
|
|
4135
4812
|
console.log(' Use `--config <file>` to execute a saved setup plan.');
|
|
4136
4813
|
console.log(' `--projects` and `--claude-code` apply to the non-interactive defaults flow.');
|
|
4137
4814
|
}
|
|
4815
|
+
function printUninstallHelp() {
|
|
4816
|
+
console.log(sectionTitle('Uninstall Command'));
|
|
4817
|
+
console.log(` ${commandText('iranti uninstall [--scope user|system] [--root <path>] [--dry-run] [--yes] [--all] [--keep-data] [--keep-project-bindings] [--scan-root <dir[,dir2]>] [--json]')}`);
|
|
4818
|
+
console.log('');
|
|
4819
|
+
console.log(' Default mode removes installed packages and stops live Iranti processes, but keeps runtime data and project bindings.');
|
|
4820
|
+
console.log(' Add `--all` to also remove discovered runtime roots, `.env.iranti`, `.mcp.json` Iranti entries, and Claude hook settings.');
|
|
4821
|
+
console.log(' Use `--scan-root` to control where project bindings and isolated runtime roots are discovered.');
|
|
4822
|
+
}
|
|
4138
4823
|
function printInstanceHelp() {
|
|
4139
4824
|
console.log(sectionTitle('Instance Commands'));
|
|
4140
4825
|
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>]')}`);
|
|
@@ -4301,6 +4986,14 @@ async function main() {
|
|
|
4301
4986
|
await upgradeCommand(args);
|
|
4302
4987
|
return;
|
|
4303
4988
|
}
|
|
4989
|
+
if (args.command === 'uninstall') {
|
|
4990
|
+
if (hasFlag(args, 'help')) {
|
|
4991
|
+
printUninstallHelp();
|
|
4992
|
+
return;
|
|
4993
|
+
}
|
|
4994
|
+
await uninstallCommand(args);
|
|
4995
|
+
return;
|
|
4996
|
+
}
|
|
4304
4997
|
if (args.command === 'handshake') {
|
|
4305
4998
|
await handshakeCommand(args);
|
|
4306
4999
|
return;
|
|
@@ -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.19',
|
|
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/src/api/server.js
CHANGED
|
@@ -39,7 +39,7 @@ const INSTANCE_DIR = process.env.IRANTI_INSTANCE_DIR?.trim()
|
|
|
39
39
|
const INSTANCE_RUNTIME_FILE = process.env.IRANTI_INSTANCE_RUNTIME_FILE?.trim()
|
|
40
40
|
|| (INSTANCE_DIR ? (0, runtimeLifecycle_1.runtimeFileForInstance)(INSTANCE_DIR) : null);
|
|
41
41
|
const INSTANCE_NAME = process.env.IRANTI_INSTANCE_NAME?.trim() || (INSTANCE_DIR ? path_1.default.basename(INSTANCE_DIR) : 'adhoc');
|
|
42
|
-
const VERSION = '0.2.
|
|
42
|
+
const VERSION = '0.2.19';
|
|
43
43
|
try {
|
|
44
44
|
fs_1.default.mkdirSync(path_1.default.dirname(REQUEST_LOG_FILE), { recursive: true });
|
|
45
45
|
}
|