iranti 0.2.45 → 0.2.46
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 +324 -6
- package/dist/scripts/iranti-mcp.js +14 -3
- package/dist/scripts/seed.js +13 -8
- package/dist/src/api/server.js +1 -1
- package/dist/src/attendant/AttendantInstance.d.ts +16 -0
- package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
- package/dist/src/attendant/AttendantInstance.js +138 -6
- package/dist/src/attendant/AttendantInstance.js.map +1 -1
- package/dist/src/attendant/index.d.ts +1 -1
- package/dist/src/attendant/index.d.ts.map +1 -1
- package/dist/src/attendant/index.js.map +1 -1
- package/dist/src/lib/autoRemember.d.ts +18 -0
- package/dist/src/lib/autoRemember.d.ts.map +1 -1
- package/dist/src/lib/autoRemember.js +91 -0
- package/dist/src/lib/autoRemember.js.map +1 -1
- package/dist/src/lib/cliHelpCatalog.d.ts.map +1 -1
- package/dist/src/lib/cliHelpCatalog.js +9 -8
- package/dist/src/lib/cliHelpCatalog.js.map +1 -1
- package/dist/src/lib/runtimeLifecycle.d.ts.map +1 -1
- package/dist/src/lib/runtimeLifecycle.js +25 -4
- package/dist/src/lib/runtimeLifecycle.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,6 +29,7 @@ const backends_1 = require("../src/library/backends");
|
|
|
29
29
|
const runtimeLifecycle_1 = require("../src/lib/runtimeLifecycle");
|
|
30
30
|
const sdk_1 = require("../src/sdk");
|
|
31
31
|
const queries_1 = require("../src/library/queries");
|
|
32
|
+
const autoRemember_1 = require("../src/lib/autoRemember");
|
|
32
33
|
class CliError extends Error {
|
|
33
34
|
constructor(code, message, hints = [], details) {
|
|
34
35
|
super(message);
|
|
@@ -766,12 +767,28 @@ async function inspectInstanceConfig(root, name) {
|
|
|
766
767
|
let metaReadable = false;
|
|
767
768
|
let envReadable = false;
|
|
768
769
|
const ownershipIssues = [];
|
|
770
|
+
let rewrittenMeta = false;
|
|
769
771
|
if (metaPresent) {
|
|
770
772
|
try {
|
|
771
773
|
const raw = await promises_1.default.readFile(metaFile, 'utf8');
|
|
772
774
|
const parsed = JSON.parse(raw);
|
|
773
775
|
metaReadable = typeof parsed.name === 'string' && parsed.name.trim().length > 0;
|
|
774
776
|
if (metaReadable) {
|
|
777
|
+
const shouldRewriteOwnership = parsed.name?.trim() === name
|
|
778
|
+
&& ((typeof parsed.instanceDir === 'string' && path_1.default.resolve(parsed.instanceDir) !== path_1.default.resolve(instanceDir))
|
|
779
|
+
|| (typeof parsed.envFile === 'string' && path_1.default.resolve(parsed.envFile) !== path_1.default.resolve(envFile)));
|
|
780
|
+
if (shouldRewriteOwnership) {
|
|
781
|
+
const nextMeta = {
|
|
782
|
+
...parsed,
|
|
783
|
+
name,
|
|
784
|
+
instanceDir,
|
|
785
|
+
envFile,
|
|
786
|
+
};
|
|
787
|
+
await writeText(metaFile, `${JSON.stringify(nextMeta, null, 2)}\n`);
|
|
788
|
+
rewrittenMeta = true;
|
|
789
|
+
parsed.instanceDir = instanceDir;
|
|
790
|
+
parsed.envFile = envFile;
|
|
791
|
+
}
|
|
775
792
|
if (parsed.name?.trim() !== name) {
|
|
776
793
|
ownershipIssues.push(`instance.json name is ${parsed.name}`);
|
|
777
794
|
}
|
|
@@ -781,6 +798,10 @@ async function inspectInstanceConfig(root, name) {
|
|
|
781
798
|
if (typeof parsed.envFile === 'string' && path_1.default.resolve(parsed.envFile) !== path_1.default.resolve(envFile)) {
|
|
782
799
|
ownershipIssues.push(`instance.json envFile points to ${parsed.envFile}`);
|
|
783
800
|
}
|
|
801
|
+
const databaseIntentValidation = parseInstanceDatabaseIntent(parsed.databaseIntent);
|
|
802
|
+
if (databaseIntentValidation.errors.length > 0) {
|
|
803
|
+
ownershipIssues.push(`instance.json databaseIntent invalid: ${databaseIntentValidation.errors.join(', ')}`);
|
|
804
|
+
}
|
|
784
805
|
const dependencyValidation = (0, runtimeDependencies_1.parseInstanceDependencies)(parsed.dependencies);
|
|
785
806
|
if (dependencyValidation.errors.length > 0) {
|
|
786
807
|
ownershipIssues.push(`instance.json dependencies invalid: ${dependencyValidation.errors.join(', ')}`);
|
|
@@ -808,7 +829,9 @@ async function inspectInstanceConfig(root, name) {
|
|
|
808
829
|
}
|
|
809
830
|
else if (metaPresent && envPresent && metaReadable && envReadable) {
|
|
810
831
|
classification = 'complete';
|
|
811
|
-
detail =
|
|
832
|
+
detail = rewrittenMeta
|
|
833
|
+
? 'instance metadata was repaired and env is present'
|
|
834
|
+
: 'instance metadata and env are present';
|
|
812
835
|
}
|
|
813
836
|
else if ((metaPresent && !metaReadable) || (envPresent && !envReadable)) {
|
|
814
837
|
classification = 'invalid';
|
|
@@ -1142,6 +1165,160 @@ function isLocalPostgresHost(hostname) {
|
|
|
1142
1165
|
const normalized = hostname.trim().toLowerCase();
|
|
1143
1166
|
return normalized === 'localhost' || normalized === '127.0.0.1' || normalized === '::1';
|
|
1144
1167
|
}
|
|
1168
|
+
function parseDatabaseIntentStrategy(raw) {
|
|
1169
|
+
const normalized = raw?.trim().toLowerCase() ?? '';
|
|
1170
|
+
if (!normalized)
|
|
1171
|
+
return null;
|
|
1172
|
+
if (normalized === 'dedicated' || normalized === 'dedicated-local')
|
|
1173
|
+
return 'dedicated-local';
|
|
1174
|
+
if (normalized === 'shared' || normalized === 'shared-local')
|
|
1175
|
+
return 'shared-local';
|
|
1176
|
+
if (normalized === 'external' || normalized === 'managed' || normalized === 'external-existing')
|
|
1177
|
+
return 'external-existing';
|
|
1178
|
+
return null;
|
|
1179
|
+
}
|
|
1180
|
+
function parseDatabaseIntentStrategyFlag(raw, label) {
|
|
1181
|
+
const trimmed = raw?.trim() ?? '';
|
|
1182
|
+
if (!trimmed)
|
|
1183
|
+
return null;
|
|
1184
|
+
const parsed = parseDatabaseIntentStrategy(trimmed);
|
|
1185
|
+
if (!parsed) {
|
|
1186
|
+
throw new Error(`Invalid ${label} '${raw}'. Use dedicated, shared, or external.`);
|
|
1187
|
+
}
|
|
1188
|
+
return parsed;
|
|
1189
|
+
}
|
|
1190
|
+
function databaseIntentPromptValue(strategy) {
|
|
1191
|
+
if (strategy === 'dedicated-local')
|
|
1192
|
+
return 'dedicated';
|
|
1193
|
+
if (strategy === 'shared-local')
|
|
1194
|
+
return 'shared';
|
|
1195
|
+
return 'external';
|
|
1196
|
+
}
|
|
1197
|
+
function describeDatabaseIntentStrategy(strategy) {
|
|
1198
|
+
switch (strategy) {
|
|
1199
|
+
case 'dedicated-local':
|
|
1200
|
+
return 'dedicated local database';
|
|
1201
|
+
case 'shared-local':
|
|
1202
|
+
return 'shared local database';
|
|
1203
|
+
case 'external-existing':
|
|
1204
|
+
default:
|
|
1205
|
+
return 'external existing database';
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function inferDatabaseProvisioning(databaseUrl, dependencies = []) {
|
|
1209
|
+
if (dependencies.some((dependency) => dependency.kind === 'docker-container')) {
|
|
1210
|
+
return 'docker';
|
|
1211
|
+
}
|
|
1212
|
+
const parsed = parsePostgresConnectionString(databaseUrl);
|
|
1213
|
+
return isLocalPostgresHost(parsed.hostname) ? 'local' : 'managed';
|
|
1214
|
+
}
|
|
1215
|
+
function inferDatabaseIntentStrategy(options) {
|
|
1216
|
+
const databaseName = postgresDatabaseName(options.databaseUrl);
|
|
1217
|
+
if (options.databaseMode === 'managed') {
|
|
1218
|
+
return 'external-existing';
|
|
1219
|
+
}
|
|
1220
|
+
return databaseName === `iranti_${options.instanceName}`
|
|
1221
|
+
? 'dedicated-local'
|
|
1222
|
+
: 'shared-local';
|
|
1223
|
+
}
|
|
1224
|
+
function buildInstanceDatabaseIntent(options) {
|
|
1225
|
+
const parsed = parsePostgresConnectionString(options.databaseUrl);
|
|
1226
|
+
const strategy = options.strategy ?? inferDatabaseIntentStrategy({
|
|
1227
|
+
instanceName: options.instanceName,
|
|
1228
|
+
databaseMode: options.databaseMode,
|
|
1229
|
+
databaseUrl: options.databaseUrl,
|
|
1230
|
+
});
|
|
1231
|
+
const port = Number.parseInt(parsed.port || '5432', 10);
|
|
1232
|
+
return {
|
|
1233
|
+
strategy,
|
|
1234
|
+
provisioning: options.databaseMode,
|
|
1235
|
+
host: parsed.hostname,
|
|
1236
|
+
...(Number.isFinite(port) && port > 0 ? { port } : {}),
|
|
1237
|
+
database: postgresDatabaseName(options.databaseUrl),
|
|
1238
|
+
...(options.dockerContainerName ? { dockerContainerName: options.dockerContainerName } : {}),
|
|
1239
|
+
};
|
|
1240
|
+
}
|
|
1241
|
+
function parseInstanceDatabaseIntent(raw) {
|
|
1242
|
+
if (raw === undefined || raw === null) {
|
|
1243
|
+
return { intent: null, errors: [] };
|
|
1244
|
+
}
|
|
1245
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
1246
|
+
return { intent: null, errors: ['databaseIntent must be an object'] };
|
|
1247
|
+
}
|
|
1248
|
+
const record = raw;
|
|
1249
|
+
const strategy = parseDatabaseIntentStrategy(typeof record.strategy === 'string' ? record.strategy : undefined);
|
|
1250
|
+
const provisioningRaw = typeof record.provisioning === 'string' ? record.provisioning.trim().toLowerCase() : '';
|
|
1251
|
+
const provisioning = provisioningRaw === 'local' || provisioningRaw === 'managed' || provisioningRaw === 'docker'
|
|
1252
|
+
? provisioningRaw
|
|
1253
|
+
: null;
|
|
1254
|
+
const host = typeof record.host === 'string' ? record.host.trim() : '';
|
|
1255
|
+
const database = typeof record.database === 'string' ? record.database.trim() : '';
|
|
1256
|
+
const portRaw = typeof record.port === 'number'
|
|
1257
|
+
? record.port
|
|
1258
|
+
: typeof record.port === 'string'
|
|
1259
|
+
? Number.parseInt(record.port, 10)
|
|
1260
|
+
: undefined;
|
|
1261
|
+
const dockerContainerName = typeof record.dockerContainerName === 'string'
|
|
1262
|
+
? record.dockerContainerName.trim()
|
|
1263
|
+
: undefined;
|
|
1264
|
+
const errors = [];
|
|
1265
|
+
if (!strategy) {
|
|
1266
|
+
errors.push('databaseIntent.strategy must be dedicated-local, shared-local, or external-existing');
|
|
1267
|
+
}
|
|
1268
|
+
if (!provisioning) {
|
|
1269
|
+
errors.push('databaseIntent.provisioning must be local, managed, or docker');
|
|
1270
|
+
}
|
|
1271
|
+
if (!host) {
|
|
1272
|
+
errors.push('databaseIntent.host is required');
|
|
1273
|
+
}
|
|
1274
|
+
if (!database) {
|
|
1275
|
+
errors.push('databaseIntent.database is required');
|
|
1276
|
+
}
|
|
1277
|
+
if (portRaw !== undefined && (!Number.isFinite(portRaw) || portRaw <= 0)) {
|
|
1278
|
+
errors.push('databaseIntent.port must be a positive integer');
|
|
1279
|
+
}
|
|
1280
|
+
if (errors.length > 0 || !strategy || !provisioning || !host || !database) {
|
|
1281
|
+
return { intent: null, errors };
|
|
1282
|
+
}
|
|
1283
|
+
return {
|
|
1284
|
+
intent: {
|
|
1285
|
+
strategy,
|
|
1286
|
+
provisioning,
|
|
1287
|
+
host,
|
|
1288
|
+
...(portRaw !== undefined ? { port: portRaw } : {}),
|
|
1289
|
+
database,
|
|
1290
|
+
...(dockerContainerName ? { dockerContainerName } : {}),
|
|
1291
|
+
},
|
|
1292
|
+
errors: [],
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
function resolveInstanceDatabaseIntent(options) {
|
|
1296
|
+
const parsedMeta = parseInstanceDatabaseIntent(options.meta?.databaseIntent);
|
|
1297
|
+
if (parsedMeta.intent) {
|
|
1298
|
+
return { intent: parsedMeta.intent, source: 'meta', errors: parsedMeta.errors };
|
|
1299
|
+
}
|
|
1300
|
+
const dbUrl = options.env.DATABASE_URL?.trim();
|
|
1301
|
+
if (!dbUrl || detectPlaceholder(dbUrl)) {
|
|
1302
|
+
return { intent: null, source: 'none', errors: parsedMeta.errors };
|
|
1303
|
+
}
|
|
1304
|
+
const dockerDependency = options.dependencies.find((dependency) => dependency.kind === 'docker-container');
|
|
1305
|
+
return {
|
|
1306
|
+
intent: buildInstanceDatabaseIntent({
|
|
1307
|
+
instanceName: options.instanceName,
|
|
1308
|
+
databaseMode: inferDatabaseProvisioning(dbUrl, options.dependencies),
|
|
1309
|
+
databaseUrl: dbUrl,
|
|
1310
|
+
dockerContainerName: dockerDependency?.name,
|
|
1311
|
+
}),
|
|
1312
|
+
source: 'inferred',
|
|
1313
|
+
errors: parsedMeta.errors,
|
|
1314
|
+
};
|
|
1315
|
+
}
|
|
1316
|
+
function describeInstanceDatabaseIntent(intent, source = 'meta') {
|
|
1317
|
+
const target = `${intent.host}${intent.port ? `:${intent.port}` : ''}/${intent.database}`;
|
|
1318
|
+
const sourceSuffix = source === 'inferred' ? ' (inferred)' : '';
|
|
1319
|
+
const dockerSuffix = intent.dockerContainerName ? `, container ${intent.dockerContainerName}` : '';
|
|
1320
|
+
return `${describeDatabaseIntentStrategy(intent.strategy)} via ${intent.provisioning} -> ${target}${dockerSuffix}${sourceSuffix}`;
|
|
1321
|
+
}
|
|
1145
1322
|
function sanitizeIdentifier(input, fallback) {
|
|
1146
1323
|
const value = input.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '_').replace(/^_+|_+$/g, '');
|
|
1147
1324
|
if (!value && input.trim()) {
|
|
@@ -1286,6 +1463,7 @@ async function ensureInstanceConfigured(root, name, config) {
|
|
|
1286
1463
|
port: config.port,
|
|
1287
1464
|
envFile,
|
|
1288
1465
|
instanceDir,
|
|
1466
|
+
databaseIntent: config.databaseIntent,
|
|
1289
1467
|
...(config.dependencies && config.dependencies.length > 0 ? { dependencies: config.dependencies } : {}),
|
|
1290
1468
|
};
|
|
1291
1469
|
await writeJson(metaFile, meta);
|
|
@@ -1298,6 +1476,7 @@ async function ensureInstanceConfigured(root, name, config) {
|
|
|
1298
1476
|
...config.providerKeys,
|
|
1299
1477
|
});
|
|
1300
1478
|
await syncInstanceMeta(root, name, config.port, {
|
|
1479
|
+
databaseIntent: config.databaseIntent,
|
|
1301
1480
|
...(config.dependencies !== undefined ? { dependencies: config.dependencies } : {}),
|
|
1302
1481
|
});
|
|
1303
1482
|
return { envFile, instanceDir, created };
|
|
@@ -1420,6 +1599,10 @@ function resolveRecentMessages(args) {
|
|
|
1420
1599
|
}
|
|
1421
1600
|
return [];
|
|
1422
1601
|
}
|
|
1602
|
+
function resolveBackfillFile(args) {
|
|
1603
|
+
const backfill = getFlag(args, 'backfill')?.trim();
|
|
1604
|
+
return backfill ? path_1.default.resolve(backfill) : null;
|
|
1605
|
+
}
|
|
1423
1606
|
function parsePositiveInteger(raw, label) {
|
|
1424
1607
|
if (!raw)
|
|
1425
1608
|
return undefined;
|
|
@@ -1529,7 +1712,10 @@ function printHandshakeResult(target, task, result) {
|
|
|
1529
1712
|
console.log(` memory facts ${result.workingMemory.length}`);
|
|
1530
1713
|
console.log(` generated ${result.briefGeneratedAt}`);
|
|
1531
1714
|
console.log('');
|
|
1532
|
-
console.log(
|
|
1715
|
+
console.log('Rules:');
|
|
1716
|
+
for (const line of result.operatingRules.split(/\r?\n/)) {
|
|
1717
|
+
console.log(line.trim().length > 0 ? ` ${line}` : '');
|
|
1718
|
+
}
|
|
1533
1719
|
if (result.workingMemory.length === 0) {
|
|
1534
1720
|
console.log('');
|
|
1535
1721
|
console.log('No working memory entries loaded.');
|
|
@@ -1549,6 +1735,9 @@ function printAttendResult(target, latestMessage, result) {
|
|
|
1549
1735
|
console.log(` message ${truncateText(latestMessage, 120)}`);
|
|
1550
1736
|
console.log(` inject ${result.shouldInject ? 'yes' : 'no'}`);
|
|
1551
1737
|
console.log(` reason ${result.reason}`);
|
|
1738
|
+
if (result.bootstrap?.handshakePerformed) {
|
|
1739
|
+
console.log(` bootstrap handshake auto-ran (${result.bootstrap.task})`);
|
|
1740
|
+
}
|
|
1552
1741
|
console.log(` method ${result.decision.method}`);
|
|
1553
1742
|
console.log(` confidence ${result.decision.confidence}`);
|
|
1554
1743
|
console.log(` explanation ${result.decision.explanation}`);
|
|
@@ -1879,12 +2068,24 @@ async function syncInstanceMeta(root, name, port, options = {}) {
|
|
|
1879
2068
|
const existing = await readInstanceMetaFile(metaFile);
|
|
1880
2069
|
const existingCreatedAt = typeof existing?.createdAt === 'string' ? existing.createdAt : undefined;
|
|
1881
2070
|
const existingDependencies = (0, runtimeDependencies_1.parseInstanceDependencies)(existing?.dependencies).dependencies;
|
|
2071
|
+
const currentDependencies = options.dependencies ?? existingDependencies;
|
|
2072
|
+
const env = fs_1.default.existsSync(envFile)
|
|
2073
|
+
? await readEnvFile(envFile).catch(() => ({}))
|
|
2074
|
+
: {};
|
|
2075
|
+
const resolvedDatabaseIntent = options.databaseIntent
|
|
2076
|
+
?? resolveInstanceDatabaseIntent({
|
|
2077
|
+
instanceName: name,
|
|
2078
|
+
env,
|
|
2079
|
+
meta: existing,
|
|
2080
|
+
dependencies: currentDependencies,
|
|
2081
|
+
}).intent;
|
|
1882
2082
|
const meta = {
|
|
1883
2083
|
name,
|
|
1884
2084
|
createdAt: existingCreatedAt ?? new Date().toISOString(),
|
|
1885
2085
|
port,
|
|
1886
2086
|
envFile,
|
|
1887
2087
|
instanceDir,
|
|
2088
|
+
...(resolvedDatabaseIntent ? { databaseIntent: resolvedDatabaseIntent } : {}),
|
|
1888
2089
|
...(options.dependencies !== undefined
|
|
1889
2090
|
? { dependencies: options.dependencies }
|
|
1890
2091
|
: existingDependencies.length > 0
|
|
@@ -1992,6 +2193,7 @@ async function executeSetupPlan(plan) {
|
|
|
1992
2193
|
const configured = await ensureInstanceConfigured(plan.root, plan.instanceName, {
|
|
1993
2194
|
port: plan.port,
|
|
1994
2195
|
dbUrl: plan.databaseUrl,
|
|
2196
|
+
databaseIntent: plan.databaseIntent,
|
|
1995
2197
|
provider: plan.provider,
|
|
1996
2198
|
providerKeys: plan.providerKeys,
|
|
1997
2199
|
apiKey: plan.apiKey,
|
|
@@ -2070,6 +2272,7 @@ async function executeSetupPlan(plan) {
|
|
|
2070
2272
|
port: plan.port,
|
|
2071
2273
|
mode: plan.mode,
|
|
2072
2274
|
databaseMode: plan.databaseMode,
|
|
2275
|
+
databaseIntent: plan.databaseIntent,
|
|
2073
2276
|
bindings,
|
|
2074
2277
|
};
|
|
2075
2278
|
}
|
|
@@ -2096,6 +2299,7 @@ function parseSetupConfig(filePath) {
|
|
|
2096
2299
|
? 'local'
|
|
2097
2300
|
: (() => { throw new Error(`Unsupported databaseMode in setup config: ${databaseModeRaw}`); })();
|
|
2098
2301
|
const databaseUrl = deriveDatabaseUrlForMode(databaseMode, instanceName, String(raw?.databaseUrl ?? raw?.dbUrl ?? '').trim());
|
|
2302
|
+
const databaseIntentStrategy = parseDatabaseIntentStrategyFlag(String(raw?.databaseIntent ?? raw?.dbIntent ?? '').trim(), 'databaseIntent');
|
|
2099
2303
|
const provider = normalizeProvider(String(raw?.provider ?? 'mock')) ?? 'mock';
|
|
2100
2304
|
if (!isSupportedProvider(provider)) {
|
|
2101
2305
|
throw new Error(`Unsupported provider in setup config: ${provider}`);
|
|
@@ -2134,6 +2338,13 @@ function parseSetupConfig(filePath) {
|
|
|
2134
2338
|
port,
|
|
2135
2339
|
databaseUrl,
|
|
2136
2340
|
databaseMode,
|
|
2341
|
+
databaseIntent: buildInstanceDatabaseIntent({
|
|
2342
|
+
instanceName,
|
|
2343
|
+
databaseMode,
|
|
2344
|
+
databaseUrl,
|
|
2345
|
+
strategy: databaseIntentStrategy,
|
|
2346
|
+
dockerContainerName: typeof raw?.dockerContainerName === 'string' ? raw.dockerContainerName : undefined,
|
|
2347
|
+
}),
|
|
2137
2348
|
provider,
|
|
2138
2349
|
providerKeys,
|
|
2139
2350
|
apiKey,
|
|
@@ -2174,6 +2385,7 @@ function defaultsSetupPlan(args) {
|
|
|
2174
2385
|
throw new Error(`Invalid --db-mode '${explicit}'. Use local, managed, or docker.`);
|
|
2175
2386
|
})();
|
|
2176
2387
|
const databaseUrl = deriveDatabaseUrlForMode(databaseMode, instanceName, (getFlag(args, 'db-url') ?? process.env.DATABASE_URL ?? '').trim());
|
|
2388
|
+
const databaseIntentStrategy = parseDatabaseIntentStrategyFlag(getFlag(args, 'db-intent'), '--db-intent');
|
|
2177
2389
|
const provider = normalizeProvider(getFlag(args, 'provider') ?? process.env.LLM_PROVIDER ?? 'mock') ?? 'mock';
|
|
2178
2390
|
if (!isSupportedProvider(provider)) {
|
|
2179
2391
|
throw new Error(`Unsupported provider '${provider}' for --defaults.`);
|
|
@@ -2215,6 +2427,13 @@ function defaultsSetupPlan(args) {
|
|
|
2215
2427
|
port,
|
|
2216
2428
|
databaseUrl,
|
|
2217
2429
|
databaseMode,
|
|
2430
|
+
databaseIntent: buildInstanceDatabaseIntent({
|
|
2431
|
+
instanceName,
|
|
2432
|
+
databaseMode,
|
|
2433
|
+
databaseUrl,
|
|
2434
|
+
strategy: databaseIntentStrategy,
|
|
2435
|
+
dockerContainerName: getFlag(args, 'docker-container-name'),
|
|
2436
|
+
}),
|
|
2218
2437
|
provider,
|
|
2219
2438
|
providerKeys,
|
|
2220
2439
|
apiKey,
|
|
@@ -4137,6 +4356,7 @@ async function setupCommand(args) {
|
|
|
4137
4356
|
console.log(` instance url http://localhost:${result.port}`);
|
|
4138
4357
|
console.log(` memory mode ${result.mode}`);
|
|
4139
4358
|
console.log(` database mode ${result.databaseMode}`);
|
|
4359
|
+
console.log(` db strategy ${describeInstanceDatabaseIntent(result.databaseIntent)}`);
|
|
4140
4360
|
if (result.bindings.length === 0) {
|
|
4141
4361
|
console.log(` projects ${paint('none bound yet', 'yellow')}`);
|
|
4142
4362
|
}
|
|
@@ -4224,6 +4444,9 @@ async function setupCommand(args) {
|
|
|
4224
4444
|
const existingInstance = fs_1.default.existsSync(instancePaths(finalRoot, instanceName).envFile)
|
|
4225
4445
|
? await loadInstanceEnv(finalRoot, instanceName)
|
|
4226
4446
|
: null;
|
|
4447
|
+
const existingInstanceMeta = fs_1.default.existsSync(instancePaths(finalRoot, instanceName).metaFile)
|
|
4448
|
+
? await readInstanceMetaFile(instancePaths(finalRoot, instanceName).metaFile)
|
|
4449
|
+
: null;
|
|
4227
4450
|
if (existingInstance) {
|
|
4228
4451
|
console.log(`${infoLabel()} Found existing instance '${instanceName}'. Updating it.`);
|
|
4229
4452
|
}
|
|
@@ -4244,6 +4467,7 @@ async function setupCommand(args) {
|
|
|
4244
4467
|
let databaseProvisioned = false;
|
|
4245
4468
|
let dockerContainerName;
|
|
4246
4469
|
let databaseMode = recommendedDatabaseMode;
|
|
4470
|
+
let databaseIntentStrategy = null;
|
|
4247
4471
|
printChoiceGuide('Database Mode Choices', [
|
|
4248
4472
|
{
|
|
4249
4473
|
choice: 'local',
|
|
@@ -4283,6 +4507,13 @@ async function setupCommand(args) {
|
|
|
4283
4507
|
console.log(`${infoLabel()} Iranti will create the local database automatically if it does not already exist.`);
|
|
4284
4508
|
}
|
|
4285
4509
|
}
|
|
4510
|
+
databaseIntentStrategy = parseDatabaseIntentStrategyFlag(await prompt.line('Database intent (dedicated, shared, external)', databaseIntentPromptValue(resolveInstanceDatabaseIntent({
|
|
4511
|
+
instanceName,
|
|
4512
|
+
env: existingInstance?.env ?? { DATABASE_URL: dbUrl },
|
|
4513
|
+
meta: existingInstanceMeta,
|
|
4514
|
+
dependencies: (0, runtimeDependencies_1.parseInstanceDependencies)(existingInstanceMeta?.dependencies).dependencies,
|
|
4515
|
+
}).intent?.strategy
|
|
4516
|
+
?? inferDatabaseIntentStrategy({ instanceName, databaseMode, databaseUrl: dbUrl }))), 'database intent');
|
|
4286
4517
|
bootstrapDatabase = await promptYesNo(prompt, 'Run migrations and seed the database now?', true);
|
|
4287
4518
|
break;
|
|
4288
4519
|
}
|
|
@@ -4298,6 +4529,15 @@ async function setupCommand(args) {
|
|
|
4298
4529
|
const containerName = sanitizeIdentifier(await promptNonEmpty(prompt, 'Docker container name', `iranti_${instanceName}_db`), `iranti_${instanceName}_db`);
|
|
4299
4530
|
dockerContainerName = containerName;
|
|
4300
4531
|
dbUrl = `postgresql://postgres:${dbPassword}@localhost:${dbHostPort}/${dbName}`;
|
|
4532
|
+
databaseIntentStrategy = parseDatabaseIntentStrategyFlag(await prompt.line('Database intent (dedicated, shared, external)', databaseIntentPromptValue(resolveInstanceDatabaseIntent({
|
|
4533
|
+
instanceName,
|
|
4534
|
+
env: existingInstance?.env ?? { DATABASE_URL: dbUrl },
|
|
4535
|
+
meta: existingInstanceMeta,
|
|
4536
|
+
dependencies: dockerContainerName
|
|
4537
|
+
? [{ kind: 'docker-container', name: dockerContainerName, ...(dbHostPort > 0 ? { healthTcpPort: dbHostPort } : {}) }]
|
|
4538
|
+
: (0, runtimeDependencies_1.parseInstanceDependencies)(existingInstanceMeta?.dependencies).dependencies,
|
|
4539
|
+
}).intent?.strategy
|
|
4540
|
+
?? inferDatabaseIntentStrategy({ instanceName, databaseMode, databaseUrl: dbUrl }))), 'database intent');
|
|
4301
4541
|
console.log(`${infoLabel()} Docker will be used only for PostgreSQL. Iranti itself does not require Docker once a PostgreSQL database is available.`);
|
|
4302
4542
|
if (await promptYesNo(prompt, `Start or reuse Docker container '${containerName}' now?`, true)) {
|
|
4303
4543
|
await runDockerPostgresContainer({
|
|
@@ -4442,6 +4682,13 @@ async function setupCommand(args) {
|
|
|
4442
4682
|
port,
|
|
4443
4683
|
databaseUrl: dbUrl,
|
|
4444
4684
|
databaseMode,
|
|
4685
|
+
databaseIntent: buildInstanceDatabaseIntent({
|
|
4686
|
+
instanceName,
|
|
4687
|
+
databaseMode,
|
|
4688
|
+
databaseUrl: dbUrl,
|
|
4689
|
+
strategy: databaseIntentStrategy,
|
|
4690
|
+
dockerContainerName,
|
|
4691
|
+
}),
|
|
4445
4692
|
provider,
|
|
4446
4693
|
providerKeys,
|
|
4447
4694
|
apiKey: defaultApiKey,
|
|
@@ -4472,6 +4719,7 @@ async function setupCommand(args) {
|
|
|
4472
4719
|
console.log(` instance url http://localhost:${finalResult.port}`);
|
|
4473
4720
|
console.log(` memory mode ${finalResult.mode}`);
|
|
4474
4721
|
console.log(` database mode ${finalResult.databaseMode}`);
|
|
4722
|
+
console.log(` db strategy ${describeInstanceDatabaseIntent(finalResult.databaseIntent)}`);
|
|
4475
4723
|
if (finalResult.bindings.length === 0) {
|
|
4476
4724
|
console.log(` projects ${paint('none bound yet', 'yellow')}`);
|
|
4477
4725
|
}
|
|
@@ -5236,6 +5484,12 @@ async function showInstanceCommand(args) {
|
|
|
5236
5484
|
: {};
|
|
5237
5485
|
const meta = await readInstanceMetaFile(instancePaths(root, name).metaFile);
|
|
5238
5486
|
const dependencies = (0, runtimeDependencies_1.parseInstanceDependencies)(meta?.dependencies).dependencies;
|
|
5487
|
+
const databaseIntent = resolveInstanceDatabaseIntent({
|
|
5488
|
+
instanceName: name,
|
|
5489
|
+
env,
|
|
5490
|
+
meta,
|
|
5491
|
+
dependencies,
|
|
5492
|
+
});
|
|
5239
5493
|
const runtime = await readInstanceRuntimeSummary(root, name);
|
|
5240
5494
|
console.log(bold(`Instance: ${name}`));
|
|
5241
5495
|
console.log(` dir : ${instanceDir}`);
|
|
@@ -5243,6 +5497,9 @@ async function showInstanceCommand(args) {
|
|
|
5243
5497
|
console.log(` config: ${describeInstanceConfig(config)}`);
|
|
5244
5498
|
console.log(` port: ${env.IRANTI_PORT ?? '3001'}`);
|
|
5245
5499
|
console.log(` db : ${env.DATABASE_URL ?? '(missing)'}`);
|
|
5500
|
+
if (databaseIntent.intent) {
|
|
5501
|
+
console.log(` db strategy: ${describeInstanceDatabaseIntent(databaseIntent.intent, databaseIntent.source)}`);
|
|
5502
|
+
}
|
|
5246
5503
|
console.log(` esc : ${env.IRANTI_ESCALATION_DIR ?? '(missing)'}`);
|
|
5247
5504
|
if (dependencies.length > 0) {
|
|
5248
5505
|
console.log(` deps: ${dependencies.map((dependency) => (0, runtimeDependencies_1.describeInstanceDependency)(dependency)).join(', ')}`);
|
|
@@ -5371,6 +5628,12 @@ async function configureInstanceCommand(args) {
|
|
|
5371
5628
|
const { instanceDir, envFile, env, config } = await loadInstanceEnv(root, name, { allowRepair: true });
|
|
5372
5629
|
const currentMeta = await readInstanceMetaFile(instancePaths(root, name).metaFile);
|
|
5373
5630
|
const currentDependencies = (0, runtimeDependencies_1.parseInstanceDependencies)(currentMeta?.dependencies).dependencies;
|
|
5631
|
+
const currentDatabaseIntent = resolveInstanceDatabaseIntent({
|
|
5632
|
+
instanceName: name,
|
|
5633
|
+
env,
|
|
5634
|
+
meta: currentMeta,
|
|
5635
|
+
dependencies: currentDependencies,
|
|
5636
|
+
});
|
|
5374
5637
|
const updates = {};
|
|
5375
5638
|
let portRaw = getFlag(args, 'port');
|
|
5376
5639
|
let dbUrl = getFlag(args, 'db-url');
|
|
@@ -5380,6 +5643,7 @@ async function configureInstanceCommand(args) {
|
|
|
5380
5643
|
let clearProviderKey = hasFlag(args, 'clear-provider-key');
|
|
5381
5644
|
let dockerContainerName = getFlag(args, 'docker-container');
|
|
5382
5645
|
let dockerHealthPortRaw = getFlag(args, 'docker-health-port');
|
|
5646
|
+
let dbIntentRaw = getFlag(args, 'db-intent');
|
|
5383
5647
|
const clearDockerContainer = hasFlag(args, 'clear-docker-container');
|
|
5384
5648
|
if (hasFlag(args, 'interactive')) {
|
|
5385
5649
|
await withPromptSession(async (prompt) => {
|
|
@@ -5387,12 +5651,14 @@ async function configureInstanceCommand(args) {
|
|
|
5387
5651
|
'This updates one existing instance in place.',
|
|
5388
5652
|
'API port controls where the Iranti API listens.',
|
|
5389
5653
|
'DATABASE_URL points at the PostgreSQL database for this instance.',
|
|
5654
|
+
'Database intent tells Iranti whether this should be treated as a dedicated local DB, a shared local DB, or an external existing DB.',
|
|
5390
5655
|
'LLM provider and provider key control which model backend Iranti uses.',
|
|
5391
5656
|
'Iranti API key is the client credential other tools and project bindings use to authenticate.',
|
|
5392
5657
|
'Optional Docker dependency settings let `iranti run --instance` start a recorded backing container before the API boots.',
|
|
5393
5658
|
]);
|
|
5394
5659
|
portRaw = await prompt.line('API port', portRaw ?? env.IRANTI_PORT);
|
|
5395
5660
|
dbUrl = await prompt.line('DATABASE_URL', dbUrl ?? env.DATABASE_URL);
|
|
5661
|
+
dbIntentRaw = await prompt.line('Database intent (dedicated, shared, external)', dbIntentRaw ?? databaseIntentPromptValue(currentDatabaseIntent.intent?.strategy));
|
|
5396
5662
|
providerInput = await prompt.line('LLM provider', providerInput ?? env.LLM_PROVIDER ?? 'mock');
|
|
5397
5663
|
const interactiveProvider = normalizeProvider(providerInput ?? env.LLM_PROVIDER ?? 'mock');
|
|
5398
5664
|
const interactiveProviderEnvKey = providerKeyEnv(interactiveProvider);
|
|
@@ -5415,6 +5681,7 @@ async function configureInstanceCommand(args) {
|
|
|
5415
5681
|
}
|
|
5416
5682
|
if (dbUrl)
|
|
5417
5683
|
updates.DATABASE_URL = dbUrl;
|
|
5684
|
+
const requestedDatabaseIntent = parseDatabaseIntentStrategyFlag(dbIntentRaw, '--db-intent');
|
|
5418
5685
|
if (apiKey)
|
|
5419
5686
|
updates.IRANTI_API_KEY = apiKey;
|
|
5420
5687
|
const provider = normalizeProvider(providerInput ?? env.LLM_PROVIDER ?? 'mock');
|
|
@@ -5467,8 +5734,9 @@ async function configureInstanceCommand(args) {
|
|
|
5467
5734
|
}
|
|
5468
5735
|
if (Object.keys(updates).length === 0) {
|
|
5469
5736
|
const dependenciesUnchanged = JSON.stringify(nextDependencies) === JSON.stringify(currentDependencies);
|
|
5470
|
-
|
|
5471
|
-
|
|
5737
|
+
const databaseIntentUnchanged = requestedDatabaseIntent === null;
|
|
5738
|
+
if (dependenciesUnchanged && databaseIntentUnchanged) {
|
|
5739
|
+
throw new Error('No changes provided. Use flags like --provider, --provider-key, --api-key, --db-url, --db-intent, --port, or the Docker dependency flags.');
|
|
5472
5740
|
}
|
|
5473
5741
|
}
|
|
5474
5742
|
const nextEnv = { ...env };
|
|
@@ -5488,9 +5756,19 @@ async function configureInstanceCommand(args) {
|
|
|
5488
5756
|
if (!nextEnv.DATABASE_URL?.trim()) {
|
|
5489
5757
|
throw cliError('IRANTI_INSTANCE_DATABASE_REQUIRED', `Instance '${name}' still needs DATABASE_URL before it can be considered repaired.`, ['Pass `--db-url <postgresql://...>` or rerun `iranti configure instance <name> --interactive`.'], { instance: name, envFile, config: config.classification });
|
|
5490
5758
|
}
|
|
5759
|
+
const nextDatabaseIntent = buildInstanceDatabaseIntent({
|
|
5760
|
+
instanceName: name,
|
|
5761
|
+
databaseMode: inferDatabaseProvisioning(nextEnv.DATABASE_URL, nextDependencies),
|
|
5762
|
+
databaseUrl: nextEnv.DATABASE_URL,
|
|
5763
|
+
strategy: requestedDatabaseIntent ?? currentDatabaseIntent.intent?.strategy,
|
|
5764
|
+
dockerContainerName: nextDependencies.find((dependency) => dependency.kind === 'docker-container')?.name,
|
|
5765
|
+
});
|
|
5491
5766
|
await ensureDir(instanceDir);
|
|
5492
5767
|
await upsertEnvFile(envFile, updates);
|
|
5493
|
-
await syncInstanceMeta(root, name, nextPort, {
|
|
5768
|
+
await syncInstanceMeta(root, name, nextPort, {
|
|
5769
|
+
dependencies: nextDependencies,
|
|
5770
|
+
databaseIntent: nextDatabaseIntent,
|
|
5771
|
+
});
|
|
5494
5772
|
const json = hasFlag(args, 'json');
|
|
5495
5773
|
const result = {
|
|
5496
5774
|
instance: name,
|
|
@@ -5499,6 +5777,7 @@ async function configureInstanceCommand(args) {
|
|
|
5499
5777
|
provider: updates.LLM_PROVIDER ?? env.LLM_PROVIDER ?? 'mock',
|
|
5500
5778
|
apiKeyChanged: Boolean(apiKey),
|
|
5501
5779
|
providerKeyChanged: Boolean(providerKey) || hasFlag(args, 'clear-provider-key'),
|
|
5780
|
+
databaseIntent: nextDatabaseIntent.strategy,
|
|
5502
5781
|
dependencies: nextDependencies.map((dependency) => (0, runtimeDependencies_1.describeInstanceDependency)(dependency)),
|
|
5503
5782
|
};
|
|
5504
5783
|
if (json) {
|
|
@@ -5509,6 +5788,7 @@ async function configureInstanceCommand(args) {
|
|
|
5509
5788
|
console.log(` status ${okLabel()}`);
|
|
5510
5789
|
console.log(` env ${envFile}`);
|
|
5511
5790
|
console.log(` keys ${result.updatedKeys.join(', ')}`);
|
|
5791
|
+
console.log(` db ${describeInstanceDatabaseIntent(nextDatabaseIntent)}`);
|
|
5512
5792
|
if (result.dependencies.length > 0) {
|
|
5513
5793
|
console.log(` deps ${result.dependencies.join(', ')}`);
|
|
5514
5794
|
}
|
|
@@ -5748,7 +6028,24 @@ async function handshakeCommand(args) {
|
|
|
5748
6028
|
const json = hasFlag(args, 'json');
|
|
5749
6029
|
const target = await resolveAttendantCliTarget(args);
|
|
5750
6030
|
const task = getFlag(args, 'task')?.trim() || 'CLI handshake';
|
|
5751
|
-
|
|
6031
|
+
let recentMessages = resolveRecentMessages(args);
|
|
6032
|
+
const backfillFile = resolveBackfillFile(args);
|
|
6033
|
+
let backfillResult = null;
|
|
6034
|
+
if (backfillFile) {
|
|
6035
|
+
const content = fs_1.default.readFileSync(backfillFile, 'utf-8');
|
|
6036
|
+
backfillResult = await (0, autoRemember_1.backfillChatHistory)({
|
|
6037
|
+
iranti: target.iranti,
|
|
6038
|
+
content,
|
|
6039
|
+
agent: target.agentId,
|
|
6040
|
+
source: 'CLIBackfill',
|
|
6041
|
+
});
|
|
6042
|
+
if (recentMessages.length === 0) {
|
|
6043
|
+
recentMessages = (0, autoRemember_1.parseBackfillChatTranscript)(content)
|
|
6044
|
+
.map((message) => message.text.trim())
|
|
6045
|
+
.filter(Boolean)
|
|
6046
|
+
.slice(-12);
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
5752
6049
|
const result = await target.iranti.handshake({
|
|
5753
6050
|
agent: target.agentId,
|
|
5754
6051
|
task,
|
|
@@ -5760,12 +6057,33 @@ async function handshakeCommand(args) {
|
|
|
5760
6057
|
envSource: target.envSource,
|
|
5761
6058
|
envFile: target.envFile,
|
|
5762
6059
|
task,
|
|
6060
|
+
backfillFile,
|
|
6061
|
+
backfillResult,
|
|
5763
6062
|
recentMessages,
|
|
5764
6063
|
result,
|
|
5765
6064
|
}, null, 2));
|
|
5766
6065
|
return;
|
|
5767
6066
|
}
|
|
5768
6067
|
printHandshakeResult(target, task, result);
|
|
6068
|
+
if (backfillResult) {
|
|
6069
|
+
console.log('');
|
|
6070
|
+
console.log('Backfill:');
|
|
6071
|
+
console.log(` file ${backfillFile}`);
|
|
6072
|
+
console.log(` messages ${backfillResult.messagesParsed}`);
|
|
6073
|
+
console.log(` extracted ${backfillResult.extracted}`);
|
|
6074
|
+
console.log(` written ${backfillResult.written}`);
|
|
6075
|
+
if (backfillResult.skipped.length > 0) {
|
|
6076
|
+
console.log(` skipped ${backfillResult.skipped.length}`);
|
|
6077
|
+
}
|
|
6078
|
+
}
|
|
6079
|
+
if (result.backfillSuggestion?.suggested && !backfillFile) {
|
|
6080
|
+
console.log('');
|
|
6081
|
+
console.log('Backfill suggestion:');
|
|
6082
|
+
console.log(` reason ${result.backfillSuggestion.reason}`);
|
|
6083
|
+
console.log(` candidateFacts ${result.backfillSuggestion.candidateFacts}`);
|
|
6084
|
+
console.log(` sample keys ${result.backfillSuggestion.sampleKeys.join(', ')}`);
|
|
6085
|
+
console.log(` command ${result.backfillSuggestion.suggestedCommand}`);
|
|
6086
|
+
}
|
|
5769
6087
|
console.log('');
|
|
5770
6088
|
console.log(`${infoLabel()} This is a manual Attendant inspection tool. Claude Code should still use hooks + MCP in normal operation.`);
|
|
5771
6089
|
}
|
|
@@ -62,6 +62,7 @@ function printHelp() {
|
|
|
62
62
|
' IRANTI_AUTO_REMEMBER Opt-in explicit prompt auto-save before attend()',
|
|
63
63
|
'',
|
|
64
64
|
'This server is intended for Claude Code and other MCP clients over stdio.',
|
|
65
|
+
'If you run `iranti mcp` directly in a terminal, it will stay running and wait for an MCP client.',
|
|
65
66
|
].join('\n'));
|
|
66
67
|
}
|
|
67
68
|
function requireConnectionString() {
|
|
@@ -135,6 +136,9 @@ function normalizeRecentMessages(messages) {
|
|
|
135
136
|
.filter(Boolean)
|
|
136
137
|
.slice(-12);
|
|
137
138
|
}
|
|
139
|
+
function isInteractiveTerminalLaunch() {
|
|
140
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
141
|
+
}
|
|
138
142
|
async function main() {
|
|
139
143
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
140
144
|
printHelp();
|
|
@@ -147,13 +151,15 @@ async function main() {
|
|
|
147
151
|
await ensureDefaultAgent(iranti);
|
|
148
152
|
const server = new mcp_js_1.McpServer({
|
|
149
153
|
name: 'iranti-mcp',
|
|
150
|
-
version: '0.2.
|
|
154
|
+
version: '0.2.46',
|
|
151
155
|
});
|
|
152
156
|
server.registerTool('iranti_handshake', {
|
|
153
157
|
description: `Initialize or refresh an agent's working-memory brief for the current task.
|
|
154
158
|
Call this at session start or when a new task begins, passing the task and
|
|
155
159
|
recent messages. Returns operating rules plus prioritized relevant memory
|
|
156
|
-
for that task.
|
|
160
|
+
for that task. If the recent messages appear to contain durable facts that
|
|
161
|
+
are not yet in shared memory, the result may include a backfill suggestion.
|
|
162
|
+
Do not use this as a per-turn retrieval tool; use iranti_attend.`,
|
|
157
163
|
inputSchema: {
|
|
158
164
|
task: z.string().min(1).describe('The current task or objective.'),
|
|
159
165
|
recentMessages: z.array(z.string()).optional().describe('Recent conversation messages.'),
|
|
@@ -174,7 +180,9 @@ visible context window. If the user is asking you to recall a remembered
|
|
|
174
180
|
fact (for example a preference, decision, blocker, next step, or prior
|
|
175
181
|
project detail), use this before answering instead of guessing or saying
|
|
176
182
|
you do not know. Returns an injection decision plus any facts that should
|
|
177
|
-
be added to context if relevant memory is missing.
|
|
183
|
+
be added to context if relevant memory is missing. If no handshake has been
|
|
184
|
+
performed yet for this agent in the current process, attend will auto-bootstrap
|
|
185
|
+
the session first and report that in the result metadata.
|
|
178
186
|
Omitting currentContext falls back to latestMessage only; pass the
|
|
179
187
|
full visible context when available.`,
|
|
180
188
|
inputSchema: {
|
|
@@ -387,6 +395,9 @@ this for arbitrary prose or every turn.`,
|
|
|
387
395
|
const result = await iranti.whoKnows(entity);
|
|
388
396
|
return textResult(result);
|
|
389
397
|
});
|
|
398
|
+
if (isInteractiveTerminalLaunch()) {
|
|
399
|
+
console.error('[iranti-mcp] stdio server running; waiting for an MCP client. Press Ctrl+C to exit.');
|
|
400
|
+
}
|
|
390
401
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
391
402
|
await server.connect(transport);
|
|
392
403
|
}
|