iranti 0.2.21 → 0.2.22
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 +22 -23
- package/dist/scripts/codex-setup.js +11 -5
- package/dist/scripts/iranti-cli.js +225 -15
- package/dist/scripts/iranti-mcp.js +1 -1
- package/dist/src/api/server.js +1 -1
- package/dist/src/lib/dockerCliParsing.d.ts +3 -0
- package/dist/src/lib/dockerCliParsing.d.ts.map +1 -0
- package/dist/src/lib/dockerCliParsing.js +23 -0
- package/dist/src/lib/dockerCliParsing.js.map +1 -0
- package/dist/src/lib/runtimeEnv.d.ts.map +1 -1
- package/dist/src/lib/runtimeEnv.js +7 -5
- package/dist/src/lib/runtimeEnv.js.map +1 -1
- package/package.json +2 -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.21`](https://github.com/nfemmanuel/iranti/releases/tag/v0.2.21)
|
|
13
13
|
Published packages:
|
|
14
|
-
- `iranti@0.2.
|
|
15
|
-
- `@iranti/sdk@0.2.
|
|
14
|
+
- `iranti@0.2.21`
|
|
15
|
+
- `@iranti/sdk@0.2.21`
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -52,27 +52,26 @@ Vector databases answer "what's similar to X?" Iranti answers "what do we know a
|
|
|
52
52
|
|
|
53
53
|
## Benchmark Summary
|
|
54
54
|
|
|
55
|
-
Iranti has now been rerun against a broader benchmark program covering
|
|
55
|
+
Iranti has now been rerun against a broader benchmark program covering 11 active capability tracks in `v0.2.21`. The current picture is stronger and narrower than the early validation story: exact, durable, shared memory is benchmark-backed; broad semantic-memory and autonomous-memory claims still need tighter boundaries.
|
|
56
56
|
|
|
57
57
|
### Confirmed Strengths
|
|
58
58
|
|
|
59
|
-
- **Exact lookup (`iranti_query`)**:
|
|
60
|
-
- **Persistence**: Facts survive
|
|
59
|
+
- **Exact lookup (`iranti_query`)**: Retrieval remains exact and durable across genuine session and process breaks. At tested scale (`N=1938`, about `107k` tokens), the measured advantage is efficiency, not accuracy: Iranti answered `10/10` with zero haystack tokens while the baseline also answered `10/10` after reading the full document.
|
|
60
|
+
- **Persistence across sessions**: Facts survive context-window loss and genuine process boundaries. `iranti_query` remained `8/8` across isolated session breaks in the rerun.
|
|
61
61
|
- **Conflict handling**: Reliable when confidence differentials are large and explicit.
|
|
62
|
-
- **Multi-agent coordination**: Agents can share memory with
|
|
63
|
-
- **Provenance**:
|
|
64
|
-
- **
|
|
65
|
-
- **
|
|
66
|
-
- **Search**: Effective for structured attribute-value retrieval.
|
|
67
|
-
- **Observe / Attend**: Automatic detection and injection behavior improved materially and now works in realistic benchmark conditions.
|
|
62
|
+
- **Multi-agent coordination**: Agents can share memory across genuine subprocess boundaries with zero shared conversational context.
|
|
63
|
+
- **Provenance on writes**: Write-side attribution through stored source metadata is working and benchmark-confirmed.
|
|
64
|
+
- **Ingest**: Prose extraction is accurate on clean entities in `v0.2.21`. Reliability under conflict-heavy transactional conditions should still be treated as a separate, narrower claim.
|
|
65
|
+
- **Observe with hints**: `iranti_observe` recovers facts reliably when given the right entity hint, with higher-confidence facts returned first.
|
|
68
66
|
- **Session recovery**: Interrupted-session recovery now performs substantially better than baseline.
|
|
69
|
-
- **Upgrade safety**: Memory durability was preserved across three version upgrades.
|
|
70
67
|
|
|
71
68
|
### Current Limits
|
|
72
69
|
|
|
73
|
-
- **Search is
|
|
74
|
-
-
|
|
75
|
-
- **
|
|
70
|
+
- **Search is lexical-first today, not semantic multi-hop retrieval.** In the current rerun, hop-value discovery was `0/4`; bare entity-token lookup worked, but `vectorScore` stayed `0` across results.
|
|
71
|
+
- **`iranti_attend` is not yet a reliable autonomous classifier.** Natural-language attend classification still falls back to `classification_parse_failed_default_false`; `forceInject` works as an operator bypass, not as proof of autonomous injection.
|
|
72
|
+
- **Observe performs better with explicit entity hints than with cold-start discovery.**
|
|
73
|
+
- **Upgrade durability should be scoped carefully.** The `v0.2.21` upgrade procedure reinitialized the instance under test; do not assume KB data survives upgrades without an explicit preservation or migration path.
|
|
74
|
+
- **Relationship and provenance reflection surfaces remain partially permission-gated in benchmark sessions.** The rerun did not prove `iranti_relate`, `iranti_related`, `iranti_related_deep`, or `iranti_who_knows` end-to-end under the benchmark session policy.
|
|
76
75
|
|
|
77
76
|
### Practical Position
|
|
78
77
|
|
|
@@ -82,9 +81,8 @@ Iranti is strongest today as **structured memory infrastructure for multi-agent
|
|
|
82
81
|
- provenance-aware writes
|
|
83
82
|
- conflict-aware storage
|
|
84
83
|
- session-aware recovery
|
|
85
|
-
- upgrade-safe persistence
|
|
86
84
|
|
|
87
|
-
It should not yet be described as a fully general semantic-memory or autonomous-
|
|
85
|
+
It should not yet be described as a fully general semantic-memory, semantic-search, or autonomous-memory-injection system.
|
|
88
86
|
|
|
89
87
|
Historical benchmark material remains available here:
|
|
90
88
|
- [`docs/internal/validation_results.md`](docs/internal/validation_results.md)
|
|
@@ -106,7 +104,7 @@ The current competitive case for Iranti is strongest when a team needs memory th
|
|
|
106
104
|
- Explicit per-fact confidence scores
|
|
107
105
|
- Per-agent memory injection through the Attendant
|
|
108
106
|
- Temporal exact lookup with `asOf` and ordered `history()`
|
|
109
|
-
- Relationship primitives through `relate()`, `getRelated()`, and `getRelatedDeep()`
|
|
107
|
+
- Relationship primitives through `relate()`, `getRelated()`, and `getRelatedDeep()` at the product surface, with benchmark confirmation for those MCP-accessible paths still pending
|
|
110
108
|
- Hybrid retrieval when exact keys are unknown
|
|
111
109
|
- Local install + project binding flow for Claude Code and Codex
|
|
112
110
|
- Published npm / PyPI surfaces with machine-level CLI setup
|
|
@@ -163,11 +161,12 @@ The current landscape splits into three buckets:
|
|
|
163
161
|
Iranti is strongest today as infrastructure for developers building multi-agent systems who need shared, structured, queryable memory rather than pure semantic recall. The current benchmark base now supports a more concrete product claim:
|
|
164
162
|
|
|
165
163
|
- exact cross-agent fact transfer works at meaningful context scales
|
|
166
|
-
- facts survive session loss and
|
|
164
|
+
- facts survive session loss and genuine process breaks
|
|
167
165
|
- same-key conflicting writes are serialized and observable
|
|
168
|
-
-
|
|
166
|
+
- prose ingest is accurate on clean entities
|
|
167
|
+
- attended recovery works with explicit hints, while autonomous attend classification remains a known defect
|
|
169
168
|
|
|
170
|
-
That is still not a claim that multi-agent memory is solved. It is a claim that Iranti now has broader evidence for durable, structured, attribution-aware memory with
|
|
169
|
+
That is still not a claim that multi-agent memory is solved. It is a claim that Iranti now has broader evidence for durable, structured, attribution-aware memory with exact retrieval and bounded recovery behavior.
|
|
171
170
|
|
|
172
171
|
The next leverage is still product simplicity: setup, operations, and day-to-day inspection need to be simple enough that real users keep Iranti in the loop.
|
|
173
172
|
|
|
@@ -316,7 +315,7 @@ iranti codex-setup
|
|
|
316
315
|
codex -C /path/to/your/project
|
|
317
316
|
```
|
|
318
317
|
|
|
319
|
-
|
|
318
|
+
By default, `iranti codex-setup` does not pin a project binding globally. `iranti mcp` resolves `.env.iranti` from the active project/workspace at runtime. Use `--project-env` only if you deliberately want to pin Codex globally to one project binding.
|
|
320
319
|
|
|
321
320
|
Alias:
|
|
322
321
|
|
|
@@ -71,7 +71,8 @@ function printHelp() {
|
|
|
71
71
|
'Notes:',
|
|
72
72
|
' - Registers a global Codex MCP entry using `codex mcp add`.',
|
|
73
73
|
' - Prefers the installed CLI path: `iranti mcp`.',
|
|
74
|
-
' -
|
|
74
|
+
' - By default does not pin IRANTI_PROJECT_ENV, so Codex can resolve .env.iranti from the active project/workspace at runtime.',
|
|
75
|
+
' - Use --project-env only when you deliberately want to pin Codex globally to one project binding.',
|
|
75
76
|
' - Use --local-script only if you need to point Codex at this repo build directly.',
|
|
76
77
|
' - Does not store DATABASE_URL in Codex config; iranti-mcp loads project/instance env at runtime.',
|
|
77
78
|
' - Replaces any existing MCP entry with the same name.',
|
|
@@ -141,8 +142,7 @@ function resolveProjectEnv(options) {
|
|
|
141
142
|
}
|
|
142
143
|
return resolved;
|
|
143
144
|
}
|
|
144
|
-
|
|
145
|
-
return node_fs_1.default.existsSync(candidate) ? candidate : undefined;
|
|
145
|
+
return undefined;
|
|
146
146
|
}
|
|
147
147
|
function canUseInstalledIranti(repoRoot) {
|
|
148
148
|
try {
|
|
@@ -204,7 +204,10 @@ function main() {
|
|
|
204
204
|
if (useInstalled) {
|
|
205
205
|
console.log('Registration target: installed CLI (`iranti mcp`)');
|
|
206
206
|
if (projectEnv) {
|
|
207
|
-
console.log(`
|
|
207
|
+
console.log(`Pinned project binding: ${projectEnv}`);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
console.log('Project binding: not pinned; `iranti mcp` will resolve `.env.iranti` from the active project/workspace at runtime.');
|
|
208
211
|
}
|
|
209
212
|
console.log('Launch Codex in the project you want to bind to Iranti, for example:');
|
|
210
213
|
console.log(' codex -C C:\\path\\to\\your\\project');
|
|
@@ -212,7 +215,10 @@ function main() {
|
|
|
212
215
|
else {
|
|
213
216
|
console.log(`Registration target: repo build (${mcpScript})`);
|
|
214
217
|
if (projectEnv) {
|
|
215
|
-
console.log(`
|
|
218
|
+
console.log(`Pinned project binding: ${projectEnv}`);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
console.log('Project binding: not pinned; `iranti mcp` will resolve `.env.iranti` from the active project/workspace at runtime.');
|
|
216
222
|
}
|
|
217
223
|
console.log(`Launch with: codex -C "${repoRoot}"`);
|
|
218
224
|
}
|
|
@@ -16,6 +16,7 @@ const net_1 = __importDefault(require("net"));
|
|
|
16
16
|
const client_1 = require("../src/library/client");
|
|
17
17
|
const apiKeys_1 = require("../src/security/apiKeys");
|
|
18
18
|
const escalationPaths_1 = require("../src/lib/escalationPaths");
|
|
19
|
+
const dockerCliParsing_1 = require("../src/lib/dockerCliParsing");
|
|
19
20
|
const runtimeEnv_1 = require("../src/lib/runtimeEnv");
|
|
20
21
|
const resolutionist_1 = require("../src/resolutionist");
|
|
21
22
|
const chat_1 = require("../src/chat");
|
|
@@ -676,8 +677,9 @@ async function withPromptSession(run) {
|
|
|
676
677
|
secret: async (prompt, currentValue) => {
|
|
677
678
|
const placeholder = currentValue ? `${redactSecret(currentValue)} (enter new value to replace)` : 'leave blank to skip';
|
|
678
679
|
const suffix = placeholder ? ` [${placeholder}]` : '';
|
|
680
|
+
process.stdout.write(`${prompt}${suffix}: `);
|
|
679
681
|
muted = true;
|
|
680
|
-
const answer = (await rl.question(
|
|
682
|
+
const answer = (await rl.question('')).trim();
|
|
681
683
|
muted = false;
|
|
682
684
|
process.stdout.write('\n');
|
|
683
685
|
if (!answer || answer === placeholder)
|
|
@@ -689,8 +691,9 @@ async function withPromptSession(run) {
|
|
|
689
691
|
secretRequired: async (prompt, currentValue) => {
|
|
690
692
|
const placeholder = currentValue ? `${redactSecret(currentValue)} (enter new value to replace)` : 'required';
|
|
691
693
|
const suffix = placeholder ? ` [${placeholder}]` : '';
|
|
694
|
+
process.stdout.write(`${prompt}${suffix}: `);
|
|
692
695
|
muted = true;
|
|
693
|
-
const answer = (await rl.question(
|
|
696
|
+
const answer = (await rl.question('')).trim();
|
|
694
697
|
muted = false;
|
|
695
698
|
process.stdout.write('\n');
|
|
696
699
|
if (!answer || answer === placeholder)
|
|
@@ -840,6 +843,18 @@ async function promptRequiredSecret(session, prompt, currentValue) {
|
|
|
840
843
|
console.log(`${warnLabel()} ${prompt} is required.`);
|
|
841
844
|
}
|
|
842
845
|
}
|
|
846
|
+
async function promptSecretWithDefault(session, prompt, defaultValue) {
|
|
847
|
+
while (true) {
|
|
848
|
+
const value = (await session.secret(`${prompt} (blank uses local-dev default)`, undefined) ?? '').trim();
|
|
849
|
+
if (!value) {
|
|
850
|
+
console.log(`${infoLabel()} Using the local development default for ${prompt}.`);
|
|
851
|
+
return defaultValue;
|
|
852
|
+
}
|
|
853
|
+
if (!detectPlaceholder(value))
|
|
854
|
+
return value;
|
|
855
|
+
console.log(`${warnLabel()} ${prompt} still looks like a placeholder. Enter a real value or leave it blank to use the local-dev default.`);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
843
858
|
function makeLegacyInstanceApiKey(instanceName) {
|
|
844
859
|
const keyId = sanitizeIdentifier(`${instanceName}_${os_1.default.userInfo().username}`, 'iranti');
|
|
845
860
|
return (0, apiKeys_1.formatApiKeyToken)(keyId, (0, apiKeys_1.generateApiKeySecret)());
|
|
@@ -990,6 +1005,76 @@ function resolveAttendMessage(args) {
|
|
|
990
1005
|
return fromPositionals;
|
|
991
1006
|
throw new Error('Missing latest message. Usage: iranti attend [message] [--message <text>] [--context <text>] [--json]');
|
|
992
1007
|
}
|
|
1008
|
+
function parseDelimitedList(raw) {
|
|
1009
|
+
if (!raw?.trim())
|
|
1010
|
+
return [];
|
|
1011
|
+
const delimiter = raw.includes('||') ? '||' : ',';
|
|
1012
|
+
return raw
|
|
1013
|
+
.split(delimiter)
|
|
1014
|
+
.map((item) => item.trim())
|
|
1015
|
+
.filter(Boolean);
|
|
1016
|
+
}
|
|
1017
|
+
function resolveTaskEntity(args) {
|
|
1018
|
+
const entity = (args.subcommand ?? args.positionals[0] ?? getFlag(args, 'entity') ?? '').trim();
|
|
1019
|
+
if (!entity) {
|
|
1020
|
+
throw new Error('Missing task entity. Usage: iranti handoff task/<task_id> --next-step <text> [--json]');
|
|
1021
|
+
}
|
|
1022
|
+
if (!entity.includes('/')) {
|
|
1023
|
+
throw new Error('task entity must use entityType/entityId format.');
|
|
1024
|
+
}
|
|
1025
|
+
return entity;
|
|
1026
|
+
}
|
|
1027
|
+
function buildHandoffSummary(key, value) {
|
|
1028
|
+
switch (key) {
|
|
1029
|
+
case 'status': {
|
|
1030
|
+
const state = typeof value === 'object' && value && 'state' in value ? String(value.state) : 'updated';
|
|
1031
|
+
return `Shared task status is ${state}.`;
|
|
1032
|
+
}
|
|
1033
|
+
case 'current_owner': {
|
|
1034
|
+
const agentId = typeof value === 'object' && value && 'agentId' in value ? String(value.agentId) : 'unassigned';
|
|
1035
|
+
return `Current owner is ${agentId}.`;
|
|
1036
|
+
}
|
|
1037
|
+
case 'next_step': {
|
|
1038
|
+
const instruction = typeof value === 'object' && value && 'instruction' in value ? String(value.instruction) : 'Next step updated.';
|
|
1039
|
+
return truncateText(`Next step: ${instruction}`, 140);
|
|
1040
|
+
}
|
|
1041
|
+
case 'blockers': {
|
|
1042
|
+
const count = typeof value === 'object' && value && 'items' in value && Array.isArray(value.items)
|
|
1043
|
+
? value.items.length
|
|
1044
|
+
: 0;
|
|
1045
|
+
return count === 0 ? 'No blockers recorded.' : `${count} blocker${count === 1 ? '' : 's'} recorded for the shared task.`;
|
|
1046
|
+
}
|
|
1047
|
+
case 'artifacts': {
|
|
1048
|
+
const count = typeof value === 'object' && value && 'files' in value && Array.isArray(value.files)
|
|
1049
|
+
? value.files.length
|
|
1050
|
+
: 0;
|
|
1051
|
+
return count === 0 ? 'No artifacts recorded.' : `${count} artifact${count === 1 ? '' : 's'} recorded for the shared task.`;
|
|
1052
|
+
}
|
|
1053
|
+
case 'notes': {
|
|
1054
|
+
const text = typeof value === 'object' && value && 'text' in value ? String(value.text) : 'Shared handoff notes updated.';
|
|
1055
|
+
return truncateText(`Notes: ${text}`, 140);
|
|
1056
|
+
}
|
|
1057
|
+
case 'active_handoff_task': {
|
|
1058
|
+
const taskEntity = typeof value === 'object' && value && 'taskEntity' in value ? String(value.taskEntity) : 'task';
|
|
1059
|
+
return `Project now points to active handoff ${taskEntity}.`;
|
|
1060
|
+
}
|
|
1061
|
+
default:
|
|
1062
|
+
return 'Shared handoff state updated.';
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
function printHandoffResult(target, taskEntity, writes) {
|
|
1066
|
+
console.log(bold('Iranti handoff'));
|
|
1067
|
+
console.log(` agent ${target.agentId}`);
|
|
1068
|
+
console.log(` env source ${target.envSource}`);
|
|
1069
|
+
if (target.envFile)
|
|
1070
|
+
console.log(` env file ${target.envFile}`);
|
|
1071
|
+
console.log(` task entity ${taskEntity}`);
|
|
1072
|
+
console.log(` writes ${writes.length}`);
|
|
1073
|
+
console.log('');
|
|
1074
|
+
for (const write of writes) {
|
|
1075
|
+
console.log(`- ${write.entity} :: ${write.key} | ${write.summary}`);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
993
1078
|
function printHandshakeResult(target, task, result) {
|
|
994
1079
|
console.log(bold('Iranti handshake'));
|
|
995
1080
|
console.log(` agent ${target.agentId}`);
|
|
@@ -1220,7 +1305,7 @@ function inspectDockerAvailability() {
|
|
|
1220
1305
|
detail: `Docker CLI is installed, but the daemon is not reachable. ${reason}`,
|
|
1221
1306
|
};
|
|
1222
1307
|
}
|
|
1223
|
-
async function isPortAvailable(port, host = '
|
|
1308
|
+
async function isPortAvailable(port, host = '0.0.0.0') {
|
|
1224
1309
|
return await new Promise((resolve) => {
|
|
1225
1310
|
const server = net_1.default.createServer();
|
|
1226
1311
|
server.unref();
|
|
@@ -1230,18 +1315,33 @@ async function isPortAvailable(port, host = '127.0.0.1') {
|
|
|
1230
1315
|
});
|
|
1231
1316
|
});
|
|
1232
1317
|
}
|
|
1233
|
-
|
|
1318
|
+
function listPublishedDockerHostPorts() {
|
|
1319
|
+
const docker = inspectDockerAvailability();
|
|
1320
|
+
if (!docker.daemonReachable)
|
|
1321
|
+
return new Set();
|
|
1322
|
+
const inspect = runCommandCapture('docker', ['ps', '--format', '{{.Ports}}']);
|
|
1323
|
+
if (inspect.status !== 0)
|
|
1324
|
+
return new Set();
|
|
1325
|
+
return (0, dockerCliParsing_1.parsePublishedDockerHostPorts)(inspect.stdout ?? '');
|
|
1326
|
+
}
|
|
1327
|
+
async function isPortUsable(port, host = '0.0.0.0', dockerPublishedPorts = new Set()) {
|
|
1328
|
+
if (dockerPublishedPorts.has(port))
|
|
1329
|
+
return false;
|
|
1330
|
+
return isPortAvailable(port, host);
|
|
1331
|
+
}
|
|
1332
|
+
async function findNextAvailablePort(start, host = '0.0.0.0', maxSteps = 50, dockerPublishedPorts = new Set()) {
|
|
1234
1333
|
for (let port = start; port < start + maxSteps; port += 1) {
|
|
1235
|
-
if (await
|
|
1334
|
+
if (await isPortUsable(port, host, dockerPublishedPorts)) {
|
|
1236
1335
|
return port;
|
|
1237
1336
|
}
|
|
1238
1337
|
}
|
|
1239
1338
|
throw new Error(`No available port found in range ${start}-${start + maxSteps - 1}.`);
|
|
1240
1339
|
}
|
|
1241
1340
|
async function chooseAvailablePort(session, promptText, preferredPort, allowOccupiedCurrent = false) {
|
|
1341
|
+
const dockerPublishedPorts = listPublishedDockerHostPorts();
|
|
1242
1342
|
let suggested = preferredPort;
|
|
1243
|
-
if (!allowOccupiedCurrent && !(await
|
|
1244
|
-
suggested = await findNextAvailablePort(preferredPort + 1);
|
|
1343
|
+
if (!allowOccupiedCurrent && !(await isPortUsable(preferredPort, '0.0.0.0', dockerPublishedPorts))) {
|
|
1344
|
+
suggested = await findNextAvailablePort(preferredPort + 1, '0.0.0.0', 50, dockerPublishedPorts);
|
|
1245
1345
|
console.log(`${warnLabel()} Port ${preferredPort} is already in use. A good next option is ${suggested}.`);
|
|
1246
1346
|
}
|
|
1247
1347
|
while (true) {
|
|
@@ -1254,10 +1354,10 @@ async function chooseAvailablePort(session, promptText, preferredPort, allowOccu
|
|
|
1254
1354
|
if (allowOccupiedCurrent && parsed === preferredPort) {
|
|
1255
1355
|
return parsed;
|
|
1256
1356
|
}
|
|
1257
|
-
if (await
|
|
1357
|
+
if (await isPortUsable(parsed, '0.0.0.0', dockerPublishedPorts)) {
|
|
1258
1358
|
return parsed;
|
|
1259
1359
|
}
|
|
1260
|
-
const next = await findNextAvailablePort(parsed + 1);
|
|
1360
|
+
const next = await findNextAvailablePort(parsed + 1, '0.0.0.0', 50, dockerPublishedPorts);
|
|
1261
1361
|
console.log(`${warnLabel()} Port ${parsed} is already in use. Try ${next} instead.`);
|
|
1262
1362
|
suggested = next;
|
|
1263
1363
|
}
|
|
@@ -1290,16 +1390,14 @@ async function runDockerPostgresContainer(options) {
|
|
|
1290
1390
|
if (!docker.daemonReachable) {
|
|
1291
1391
|
throw new Error(`Docker daemon is not reachable. Start Docker Desktop or Docker Engine, then retry. ${docker.detail}`);
|
|
1292
1392
|
}
|
|
1293
|
-
const inspect =
|
|
1294
|
-
? (0, child_process_1.spawnSync)(process.env.ComSpec ?? 'cmd.exe', ['/d', '/c', `docker ps -a --format "{{.Names}}"`], { encoding: 'utf8' })
|
|
1295
|
-
: (0, child_process_1.spawnSync)('docker', ['ps', '-a', '--format', '{{.Names}}'], { encoding: 'utf8' });
|
|
1393
|
+
const inspect = runCommandCapture('docker', ['ps', '-a', '--format', '{{.Names}}']);
|
|
1296
1394
|
if (inspect.status !== 0) {
|
|
1297
1395
|
throw new Error(`Failed to inspect Docker containers. ${(inspect.stderr ?? inspect.stdout ?? '').trim() || 'docker ps returned a non-zero exit code.'}`);
|
|
1298
1396
|
}
|
|
1299
|
-
const names = (inspect.stdout ?? '')
|
|
1397
|
+
const names = (0, dockerCliParsing_1.parseDockerContainerNames)(inspect.stdout ?? '');
|
|
1300
1398
|
if (names.includes(options.containerName)) {
|
|
1301
1399
|
const start = process.platform === 'win32'
|
|
1302
|
-
? (0, child_process_1.spawnSync)(process.env.ComSpec ?? 'cmd.exe', ['/d', '/c',
|
|
1400
|
+
? (0, child_process_1.spawnSync)(process.env.ComSpec ?? 'cmd.exe', ['/d', '/c', ['docker', 'start', options.containerName].map(quoteForCmd).join(' ')], { stdio: 'inherit' })
|
|
1303
1401
|
: (0, child_process_1.spawnSync)('docker', ['start', options.containerName], { stdio: 'inherit' });
|
|
1304
1402
|
if (start.status !== 0) {
|
|
1305
1403
|
throw new Error(`Failed to start existing Docker container '${options.containerName}'.`);
|
|
@@ -3364,7 +3462,7 @@ async function setupCommand(args) {
|
|
|
3364
3462
|
}
|
|
3365
3463
|
const dbHostPort = await chooseAvailablePort(prompt, 'Docker PostgreSQL host port', 5432, false);
|
|
3366
3464
|
const dbName = sanitizeIdentifier(await promptNonEmpty(prompt, 'Docker PostgreSQL database name', `iranti_${instanceName}`), `iranti_${instanceName}`);
|
|
3367
|
-
const dbPassword = await
|
|
3465
|
+
const dbPassword = await promptSecretWithDefault(prompt, 'Docker PostgreSQL password', 'postgres');
|
|
3368
3466
|
const containerName = sanitizeIdentifier(await promptNonEmpty(prompt, 'Docker container name', `iranti_${instanceName}_db`), `iranti_${instanceName}_db`);
|
|
3369
3467
|
dockerContainerName = containerName;
|
|
3370
3468
|
dbUrl = `postgresql://postgres:${dbPassword}@localhost:${dbHostPort}/${dbName}`;
|
|
@@ -4638,6 +4736,113 @@ async function attendCommand(args) {
|
|
|
4638
4736
|
console.log('');
|
|
4639
4737
|
console.log(`${infoLabel()} This is a manual Attendant inspection tool. Claude Code should still use hooks + MCP in normal operation.`);
|
|
4640
4738
|
}
|
|
4739
|
+
async function handoffCommand(args) {
|
|
4740
|
+
const json = hasFlag(args, 'json');
|
|
4741
|
+
const target = await resolveAttendantCliTarget(args);
|
|
4742
|
+
const taskEntity = resolveTaskEntity(args);
|
|
4743
|
+
const projectEntity = getFlag(args, 'project-entity')?.trim();
|
|
4744
|
+
if (projectEntity && !projectEntity.includes('/')) {
|
|
4745
|
+
throw new Error('project-entity must use entityType/entityId format.');
|
|
4746
|
+
}
|
|
4747
|
+
const nextStep = getFlag(args, 'next-step')?.trim();
|
|
4748
|
+
if (!nextStep) {
|
|
4749
|
+
throw new Error('Missing --next-step. A standardized handoff must record the receiver action.');
|
|
4750
|
+
}
|
|
4751
|
+
const status = getFlag(args, 'status')?.trim() || 'ready_for_handoff';
|
|
4752
|
+
const owner = getFlag(args, 'owner')?.trim();
|
|
4753
|
+
const blockers = parseDelimitedList(getFlag(args, 'blockers'));
|
|
4754
|
+
const artifacts = parseDelimitedList(getFlag(args, 'artifacts'));
|
|
4755
|
+
const notes = getFlag(args, 'notes')?.trim();
|
|
4756
|
+
const source = getFlag(args, 'source')?.trim() || 'CLIHandoff';
|
|
4757
|
+
const confidence = parsePositiveInteger(getFlag(args, 'confidence'), 'confidence') ?? 95;
|
|
4758
|
+
if (confidence > 100) {
|
|
4759
|
+
throw new Error('confidence must be <= 100.');
|
|
4760
|
+
}
|
|
4761
|
+
const writes = [];
|
|
4762
|
+
writes.push({
|
|
4763
|
+
entity: taskEntity,
|
|
4764
|
+
key: 'status',
|
|
4765
|
+
value: { state: status },
|
|
4766
|
+
summary: buildHandoffSummary('status', { state: status }),
|
|
4767
|
+
});
|
|
4768
|
+
writes.push({
|
|
4769
|
+
entity: taskEntity,
|
|
4770
|
+
key: 'next_step',
|
|
4771
|
+
value: { instruction: nextStep },
|
|
4772
|
+
summary: buildHandoffSummary('next_step', { instruction: nextStep }),
|
|
4773
|
+
});
|
|
4774
|
+
if (owner) {
|
|
4775
|
+
writes.push({
|
|
4776
|
+
entity: taskEntity,
|
|
4777
|
+
key: 'current_owner',
|
|
4778
|
+
value: { agentId: owner },
|
|
4779
|
+
summary: buildHandoffSummary('current_owner', { agentId: owner }),
|
|
4780
|
+
});
|
|
4781
|
+
}
|
|
4782
|
+
if (blockers.length > 0) {
|
|
4783
|
+
writes.push({
|
|
4784
|
+
entity: taskEntity,
|
|
4785
|
+
key: 'blockers',
|
|
4786
|
+
value: { items: blockers },
|
|
4787
|
+
summary: buildHandoffSummary('blockers', { items: blockers }),
|
|
4788
|
+
});
|
|
4789
|
+
}
|
|
4790
|
+
if (artifacts.length > 0) {
|
|
4791
|
+
writes.push({
|
|
4792
|
+
entity: taskEntity,
|
|
4793
|
+
key: 'artifacts',
|
|
4794
|
+
value: { files: artifacts },
|
|
4795
|
+
summary: buildHandoffSummary('artifacts', { files: artifacts }),
|
|
4796
|
+
});
|
|
4797
|
+
}
|
|
4798
|
+
if (notes) {
|
|
4799
|
+
writes.push({
|
|
4800
|
+
entity: taskEntity,
|
|
4801
|
+
key: 'notes',
|
|
4802
|
+
value: { text: notes },
|
|
4803
|
+
summary: buildHandoffSummary('notes', { text: notes }),
|
|
4804
|
+
});
|
|
4805
|
+
}
|
|
4806
|
+
if (projectEntity) {
|
|
4807
|
+
writes.push({
|
|
4808
|
+
entity: projectEntity,
|
|
4809
|
+
key: 'active_handoff_task',
|
|
4810
|
+
value: {
|
|
4811
|
+
taskEntity,
|
|
4812
|
+
owner: owner ?? null,
|
|
4813
|
+
status,
|
|
4814
|
+
updatedBy: target.agentId,
|
|
4815
|
+
},
|
|
4816
|
+
summary: buildHandoffSummary('active_handoff_task', { taskEntity }),
|
|
4817
|
+
});
|
|
4818
|
+
}
|
|
4819
|
+
for (const write of writes) {
|
|
4820
|
+
await target.iranti.write({
|
|
4821
|
+
entity: write.entity,
|
|
4822
|
+
key: write.key,
|
|
4823
|
+
value: write.value,
|
|
4824
|
+
summary: write.summary,
|
|
4825
|
+
confidence,
|
|
4826
|
+
source,
|
|
4827
|
+
agent: target.agentId,
|
|
4828
|
+
});
|
|
4829
|
+
}
|
|
4830
|
+
if (json) {
|
|
4831
|
+
console.log(JSON.stringify({
|
|
4832
|
+
agent: target.agentId,
|
|
4833
|
+
envSource: target.envSource,
|
|
4834
|
+
envFile: target.envFile,
|
|
4835
|
+
source,
|
|
4836
|
+
confidence,
|
|
4837
|
+
writes,
|
|
4838
|
+
}, null, 2));
|
|
4839
|
+
process.exit(0);
|
|
4840
|
+
}
|
|
4841
|
+
printHandoffResult(target, taskEntity, writes);
|
|
4842
|
+
console.log('');
|
|
4843
|
+
console.log(`${infoLabel()} Handoffs are shared-memory facts. Pair this with checkpoint() if the sender also needs agent-local recovery.`);
|
|
4844
|
+
process.exit(0);
|
|
4845
|
+
}
|
|
4641
4846
|
function printClaudeSetupHelp() {
|
|
4642
4847
|
console.log([
|
|
4643
4848
|
'Scaffold Claude Code MCP and hook files for the current project.',
|
|
@@ -4936,6 +5141,7 @@ function printHelp() {
|
|
|
4936
5141
|
['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.'],
|
|
4937
5142
|
['iranti handshake [--instance <name> | --project-env <file>] [--agent <id>] [--task <text>] [--recent <msg1||msg2>] [--recent-file <path>] [--json]', 'Manually inspect Attendant handshake output.'],
|
|
4938
5143
|
['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.'],
|
|
5144
|
+
['iranti handoff task/<task_id> [--instance <name> | --project-env <file>] [--agent <id>] --next-step <text> [--status <state>] [--owner <agent-id>] [--blockers <a||b>] [--artifacts <path1||path2>] [--project-entity <entity>] [--notes <text>] [--source <label>] [--confidence <n>] [--json]', 'Write a standardized shared-memory handoff for Claude/Codex collaboration.'],
|
|
4939
5145
|
['iranti chat [--agent <agent-id>] [--provider <provider>] [--model <model>]', 'Open the local interactive chat shell.'],
|
|
4940
5146
|
['iranti resolve [--dir <escalation-dir>]', 'Walk through pending escalation files.'],
|
|
4941
5147
|
]);
|
|
@@ -5162,6 +5368,10 @@ async function main() {
|
|
|
5162
5368
|
await attendCommand(args);
|
|
5163
5369
|
return;
|
|
5164
5370
|
}
|
|
5371
|
+
if (args.command === 'handoff') {
|
|
5372
|
+
await handoffCommand(args);
|
|
5373
|
+
return;
|
|
5374
|
+
}
|
|
5165
5375
|
if (args.command === 'chat') {
|
|
5166
5376
|
await chatCommand(args);
|
|
5167
5377
|
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.22',
|
|
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.22';
|
|
43
43
|
try {
|
|
44
44
|
fs_1.default.mkdirSync(path_1.default.dirname(REQUEST_LOG_FILE), { recursive: true });
|
|
45
45
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dockerCliParsing.d.ts","sourceRoot":"","sources":["../../../src/lib/dockerCliParsing.ts"],"names":[],"mappings":"AAAA,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAWzE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAKlE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parsePublishedDockerHostPorts = parsePublishedDockerHostPorts;
|
|
4
|
+
exports.parseDockerContainerNames = parseDockerContainerNames;
|
|
5
|
+
function parsePublishedDockerHostPorts(output) {
|
|
6
|
+
const ports = new Set();
|
|
7
|
+
for (const line of output.split(/\r?\n/)) {
|
|
8
|
+
for (const match of line.matchAll(/(?:^|,\s*)(?:0\.0\.0\.0|127\.0\.0\.1|\[::\]|localhost):(\d+)->/g)) {
|
|
9
|
+
const parsed = Number.parseInt(match[1] ?? '', 10);
|
|
10
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
11
|
+
ports.add(parsed);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return ports;
|
|
16
|
+
}
|
|
17
|
+
function parseDockerContainerNames(output) {
|
|
18
|
+
return output
|
|
19
|
+
.split(/\r?\n/)
|
|
20
|
+
.map((value) => value.trim())
|
|
21
|
+
.filter(Boolean);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=dockerCliParsing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dockerCliParsing.js","sourceRoot":"","sources":["../../../src/lib/dockerCliParsing.ts"],"names":[],"mappings":";;AAAA,sEAWC;AAED,8DAKC;AAlBD,SAAgB,6BAA6B,CAAC,MAAc;IACxD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,iEAAiE,CAAC,EAAE,CAAC;YACnG,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACnD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAgB,yBAAyB,CAAC,MAAc;IACpD,OAAO,MAAM;SACR,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SAC5B,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeEnv.d.ts","sourceRoot":"","sources":["../../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;
|
|
1
|
+
{"version":3,"file":"runtimeEnv.d.ts","sourceRoot":"","sources":["../../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,KAAK,oBAAoB,GAAG;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AA4DF,wBAAgB,cAAc,CAAC,OAAO,GAAE,iBAAsB,GAAG,oBAAoB,CAuCpF"}
|
|
@@ -11,9 +11,10 @@ function parseEnvFile(filePath) {
|
|
|
11
11
|
const raw = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
12
12
|
return dotenv_1.default.parse(raw);
|
|
13
13
|
}
|
|
14
|
-
function applyEnvVars(vars, initialEnvKeys) {
|
|
14
|
+
function applyEnvVars(vars, initialEnvKeys, options = {}) {
|
|
15
|
+
const { overrideExisting = false } = options;
|
|
15
16
|
for (const [key, value] of Object.entries(vars)) {
|
|
16
|
-
if (initialEnvKeys.has(key))
|
|
17
|
+
if (!overrideExisting && initialEnvKeys.has(key))
|
|
17
18
|
continue;
|
|
18
19
|
process.env[key] = value;
|
|
19
20
|
}
|
|
@@ -61,7 +62,8 @@ function loadRuntimeEnv(options = {}) {
|
|
|
61
62
|
const initialEnvKeys = new Set(Object.keys(process.env));
|
|
62
63
|
const fallbackEnvFile = findFallbackEnvFile(options);
|
|
63
64
|
if (fallbackEnvFile) {
|
|
64
|
-
|
|
65
|
+
const explicitFallback = Boolean(options.explicitEnvFile?.trim() || process.env.IRANTI_ENV_FILE?.trim());
|
|
66
|
+
applyEnvVars(parseEnvFile(fallbackEnvFile), initialEnvKeys, { overrideExisting: explicitFallback });
|
|
65
67
|
loadedFiles.push(fallbackEnvFile);
|
|
66
68
|
}
|
|
67
69
|
const projectEnvFile = findProjectEnvFile(options);
|
|
@@ -75,11 +77,11 @@ function loadRuntimeEnv(options = {}) {
|
|
|
75
77
|
? path_1.default.resolve(instanceEnvFile)
|
|
76
78
|
: undefined;
|
|
77
79
|
if (resolvedInstanceEnvFile) {
|
|
78
|
-
applyEnvVars(parseEnvFile(resolvedInstanceEnvFile), initialEnvKeys);
|
|
80
|
+
applyEnvVars(parseEnvFile(resolvedInstanceEnvFile), initialEnvKeys, { overrideExisting: true });
|
|
79
81
|
loadedFiles.push(resolvedInstanceEnvFile);
|
|
80
82
|
}
|
|
81
83
|
if (projectEnvFile && projectEnv) {
|
|
82
|
-
applyEnvVars(projectEnv, initialEnvKeys);
|
|
84
|
+
applyEnvVars(projectEnv, initialEnvKeys, { overrideExisting: true });
|
|
83
85
|
loadedFiles.push(projectEnvFile);
|
|
84
86
|
}
|
|
85
87
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtimeEnv.js","sourceRoot":"","sources":["../../../src/lib/runtimeEnv.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"runtimeEnv.js","sourceRoot":"","sources":["../../../src/lib/runtimeEnv.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iranti",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.22",
|
|
4
4
|
"description": "Memory infrastructure for multi-agent AI systems",
|
|
5
5
|
"main": "dist/src/sdk/index.js",
|
|
6
6
|
"files": [
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"test:vector-backends": "ts-node tests/vector-backends/run_vector_backend_tests.ts",
|
|
72
72
|
"test:ts-client-smoke": "ts-node --project tests/typescript_client/tsconfig.json tests/typescript_client/smoke_test.ts",
|
|
73
73
|
"test:consistency": "ts-node tests/consistency/run_consistency_tests.ts",
|
|
74
|
+
"test:cross-tool-handoff": "ts-node tests/cross-tool/run_cross_tool_handoff_tests.ts",
|
|
74
75
|
"release:check": "ts-node scripts/check-release-version.ts",
|
|
75
76
|
"release:bump": "ts-node scripts/bump-version.ts",
|
|
76
77
|
"seed:policy": "ts-node scripts/seed_policy.ts",
|