@adapt-toolkit/a2adapt 0.8.1 → 0.9.0
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/cli.js +120 -1
- package/dist/index.js +52 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import * as fs2 from "node:fs";
|
|
|
13
13
|
// src/config.ts
|
|
14
14
|
import * as fs from "node:fs";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
|
-
import { resolve, join, dirname } from "node:path";
|
|
16
|
+
import { resolve, join, dirname, basename } from "node:path";
|
|
17
17
|
var DEFAULT_CONFIG = {
|
|
18
18
|
brokerUrl: "ws://a2adapt.adaptframework.solutions/broker",
|
|
19
19
|
port: 3030,
|
|
@@ -70,6 +70,29 @@ function writeConfig(cfg) {
|
|
|
70
70
|
}
|
|
71
71
|
return path;
|
|
72
72
|
}
|
|
73
|
+
var IDENTITY_FILENAME = ".a2adapt-identity";
|
|
74
|
+
function buildIdentityFile(opts) {
|
|
75
|
+
if (!opts.name.trim()) throw new Error("identity name must not be empty");
|
|
76
|
+
const obj = { identity: opts.name.trim() };
|
|
77
|
+
if (opts.force) obj.force = true;
|
|
78
|
+
obj.expose_local = opts.exposeLocal ?? true;
|
|
79
|
+
obj.local_auto_accept = opts.localAutoAccept ?? true;
|
|
80
|
+
return obj;
|
|
81
|
+
}
|
|
82
|
+
function resolveIdentityFilePath(target) {
|
|
83
|
+
const abs = resolve(target);
|
|
84
|
+
return basename(abs) === IDENTITY_FILENAME ? abs : join(abs, IDENTITY_FILENAME);
|
|
85
|
+
}
|
|
86
|
+
function writeIdentityFile(target, opts, overwrite = false) {
|
|
87
|
+
const obj = buildIdentityFile(opts);
|
|
88
|
+
const path = resolveIdentityFilePath(target);
|
|
89
|
+
if (!overwrite && fs.existsSync(path)) {
|
|
90
|
+
throw new Error(`${path} already exists \u2014 pass overwrite to replace it`);
|
|
91
|
+
}
|
|
92
|
+
fs.mkdirSync(dirname(path), { recursive: true });
|
|
93
|
+
fs.writeFileSync(path, JSON.stringify(obj, null, 2) + "\n");
|
|
94
|
+
return path;
|
|
95
|
+
}
|
|
73
96
|
|
|
74
97
|
// src/cli.ts
|
|
75
98
|
var CONFIG = loadConfig();
|
|
@@ -274,6 +297,93 @@ daemon is running (pid ${pid}); restart now to apply? [y/N]: `)).trim().toLowerC
|
|
|
274
297
|
const r = spawnSync(process.execPath, [SELF, "start"], { stdio: "inherit" });
|
|
275
298
|
if (r.status !== 0) process.exit(r.status ?? 1);
|
|
276
299
|
}
|
|
300
|
+
function flagPair(argv, on, off) {
|
|
301
|
+
if (argv.includes(off)) return { value: false, set: true };
|
|
302
|
+
if (argv.includes(on)) return { value: true, set: true };
|
|
303
|
+
return { value: void 0, set: false };
|
|
304
|
+
}
|
|
305
|
+
function flagValue(argv, name) {
|
|
306
|
+
const i = argv.indexOf(name);
|
|
307
|
+
return i >= 0 && i + 1 < argv.length ? argv[i + 1] : void 0;
|
|
308
|
+
}
|
|
309
|
+
async function cmdDefineLocalIdentityFile(argv) {
|
|
310
|
+
const name = flagValue(argv, "--name");
|
|
311
|
+
const force = flagPair(argv, "--force-bind", "--no-force-bind");
|
|
312
|
+
const localBook = flagPair(argv, "--local-book", "--no-local-book");
|
|
313
|
+
const autoAccept = flagPair(argv, "--auto-accept-local", "--no-auto-accept-local");
|
|
314
|
+
const overwrite = argv.includes("--overwrite");
|
|
315
|
+
const print = argv.includes("--print");
|
|
316
|
+
const target = flagValue(argv, "--path") ?? flagValue(argv, "--dir") ?? process.cwd();
|
|
317
|
+
const nonInteractive = name !== void 0 || force.set || localBook.set || autoAccept.set || print;
|
|
318
|
+
let opts;
|
|
319
|
+
if (nonInteractive) {
|
|
320
|
+
if (!name || !name.trim()) {
|
|
321
|
+
err("define-local-identity-file: --name is required in non-interactive mode.");
|
|
322
|
+
process.exit(1);
|
|
323
|
+
}
|
|
324
|
+
opts = {
|
|
325
|
+
name: name.trim(),
|
|
326
|
+
force: force.value ?? false,
|
|
327
|
+
exposeLocal: localBook.value ?? true,
|
|
328
|
+
localAutoAccept: autoAccept.value ?? true
|
|
329
|
+
};
|
|
330
|
+
} else {
|
|
331
|
+
opts = await runIdentitySurvey();
|
|
332
|
+
}
|
|
333
|
+
if (print) {
|
|
334
|
+
out(JSON.stringify(buildIdentityFile(opts), null, 2));
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const path = resolveIdentityFilePath(target);
|
|
338
|
+
if (!overwrite && fs2.existsSync(path)) {
|
|
339
|
+
if (nonInteractive) {
|
|
340
|
+
err(`define-local-identity-file: ${path} already exists \u2014 pass --overwrite to replace it.`);
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
343
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
344
|
+
let ok = false;
|
|
345
|
+
try {
|
|
346
|
+
const ans = (await rl.question(`
|
|
347
|
+
${path} already exists \u2014 overwrite? [y/N]: `)).trim().toLowerCase();
|
|
348
|
+
ok = ans === "y" || ans === "yes";
|
|
349
|
+
} finally {
|
|
350
|
+
rl.close();
|
|
351
|
+
}
|
|
352
|
+
if (!ok) {
|
|
353
|
+
out("aborted \u2014 nothing written.");
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const written = writeIdentityFile(target, opts, true);
|
|
358
|
+
out("");
|
|
359
|
+
out(`wrote ${written}:`);
|
|
360
|
+
out(JSON.stringify(buildIdentityFile(opts), null, 2));
|
|
361
|
+
}
|
|
362
|
+
async function runIdentitySurvey() {
|
|
363
|
+
out(`a2adapt-mcp define-local-identity-file \u2014 interactive`);
|
|
364
|
+
out(`Answer the prompts; the result is written to ${join2(process.cwd(), IDENTITY_FILENAME)}.`);
|
|
365
|
+
out("");
|
|
366
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
367
|
+
try {
|
|
368
|
+
const askYesNo = async (label, def) => {
|
|
369
|
+
const hint = def ? "Y/n" : "y/N";
|
|
370
|
+
const ans = (await rl.question(` ${label} [${hint}]: `)).trim().toLowerCase();
|
|
371
|
+
if (ans === "") return def;
|
|
372
|
+
return ans === "y" || ans === "yes";
|
|
373
|
+
};
|
|
374
|
+
let name = "";
|
|
375
|
+
while (!name) {
|
|
376
|
+
name = (await rl.question(" Identity name: ")).trim();
|
|
377
|
+
if (!name) out(" (name is required)");
|
|
378
|
+
}
|
|
379
|
+
const force = await askYesNo("Force-bind (pin pre-authorizes evicting another session)?", false);
|
|
380
|
+
const exposeLocal = await askYesNo("Add to the host-local contact book?", true);
|
|
381
|
+
const localAutoAccept = await askYesNo("Auto-accept local invites/introductions?", true);
|
|
382
|
+
return { name, force, exposeLocal, localAutoAccept };
|
|
383
|
+
} finally {
|
|
384
|
+
rl.close();
|
|
385
|
+
}
|
|
386
|
+
}
|
|
277
387
|
function cmdWatch(which) {
|
|
278
388
|
const offsets = /* @__PURE__ */ new Map();
|
|
279
389
|
const scan = (initial) => {
|
|
@@ -482,6 +592,12 @@ function usage() {
|
|
|
482
592
|
out(" serve run in the foreground (used by start; handy for debugging)");
|
|
483
593
|
out(" watch [identity] stream one line per new inbound message (wake source for a Monitor)");
|
|
484
594
|
out("");
|
|
595
|
+
out(" define-local-identity-file write a .a2adapt-identity workspace pin");
|
|
596
|
+
out(" interactive (default): 4-question survey, writes to CWD");
|
|
597
|
+
out(" scripted: --name <s> [--force-bind] [--local-book] [--auto-accept-local]");
|
|
598
|
+
out(" negate with --no-force-bind / --no-local-book / --no-auto-accept-local");
|
|
599
|
+
out(" --dir <path> | --path <file> (default CWD) \xB7 --overwrite \xB7 --print");
|
|
600
|
+
out("");
|
|
485
601
|
out(" install-service install + start a boot-persistent service (systemd/launchd)");
|
|
486
602
|
out(" uninstall-service stop + remove that service");
|
|
487
603
|
out("");
|
|
@@ -531,6 +647,9 @@ async function main() {
|
|
|
531
647
|
case "setup":
|
|
532
648
|
await cmdSetup();
|
|
533
649
|
break;
|
|
650
|
+
case "define-local-identity-file":
|
|
651
|
+
await cmdDefineLocalIdentityFile(process.argv.slice(3));
|
|
652
|
+
break;
|
|
534
653
|
case "watch":
|
|
535
654
|
cmdWatch(process.argv[3]);
|
|
536
655
|
break;
|
package/dist/index.js
CHANGED
|
@@ -22427,7 +22427,7 @@ var StreamableHTTPServerTransport = class {
|
|
|
22427
22427
|
};
|
|
22428
22428
|
|
|
22429
22429
|
// src/index.ts
|
|
22430
|
-
import { resolve as resolve2, join as join2, dirname as dirname2 } from "node:path";
|
|
22430
|
+
import { resolve as resolve2, join as join2, dirname as dirname2, isAbsolute } from "node:path";
|
|
22431
22431
|
import { fileURLToPath } from "node:url";
|
|
22432
22432
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
22433
22433
|
import { createServer as createHttpServer } from "node:http";
|
|
@@ -22440,7 +22440,7 @@ import { object_to_adapt_value } from "@adapt-toolkit/sdk/wrapper";
|
|
|
22440
22440
|
// src/config.ts
|
|
22441
22441
|
import * as fs from "node:fs";
|
|
22442
22442
|
import { homedir } from "node:os";
|
|
22443
|
-
import { resolve, join, dirname } from "node:path";
|
|
22443
|
+
import { resolve, join, dirname, basename } from "node:path";
|
|
22444
22444
|
var DEFAULT_CONFIG = {
|
|
22445
22445
|
brokerUrl: "ws://a2adapt.adaptframework.solutions/broker",
|
|
22446
22446
|
port: 3030,
|
|
@@ -22487,9 +22487,32 @@ function loadConfig() {
|
|
|
22487
22487
|
gcIntervalMs: envInt("A2ADAPT_GC_INTERVAL_MS") ?? file.gcIntervalMs ?? DEFAULT_CONFIG.gcIntervalMs
|
|
22488
22488
|
};
|
|
22489
22489
|
}
|
|
22490
|
+
var IDENTITY_FILENAME = ".a2adapt-identity";
|
|
22491
|
+
function buildIdentityFile(opts) {
|
|
22492
|
+
if (!opts.name.trim()) throw new Error("identity name must not be empty");
|
|
22493
|
+
const obj = { identity: opts.name.trim() };
|
|
22494
|
+
if (opts.force) obj.force = true;
|
|
22495
|
+
obj.expose_local = opts.exposeLocal ?? true;
|
|
22496
|
+
obj.local_auto_accept = opts.localAutoAccept ?? true;
|
|
22497
|
+
return obj;
|
|
22498
|
+
}
|
|
22499
|
+
function resolveIdentityFilePath(target) {
|
|
22500
|
+
const abs = resolve(target);
|
|
22501
|
+
return basename(abs) === IDENTITY_FILENAME ? abs : join(abs, IDENTITY_FILENAME);
|
|
22502
|
+
}
|
|
22503
|
+
function writeIdentityFile(target, opts, overwrite = false) {
|
|
22504
|
+
const obj = buildIdentityFile(opts);
|
|
22505
|
+
const path = resolveIdentityFilePath(target);
|
|
22506
|
+
if (!overwrite && fs.existsSync(path)) {
|
|
22507
|
+
throw new Error(`${path} already exists \u2014 pass overwrite to replace it`);
|
|
22508
|
+
}
|
|
22509
|
+
fs.mkdirSync(dirname(path), { recursive: true });
|
|
22510
|
+
fs.writeFileSync(path, JSON.stringify(obj, null, 2) + "\n");
|
|
22511
|
+
return path;
|
|
22512
|
+
}
|
|
22490
22513
|
|
|
22491
22514
|
// src/index.ts
|
|
22492
|
-
var VERSION = true ? "0.
|
|
22515
|
+
var VERSION = true ? "0.9.0" : "0.0.0-dev";
|
|
22493
22516
|
var CONFIG = loadConfig();
|
|
22494
22517
|
var STATE_DIR = CONFIG.stateDir;
|
|
22495
22518
|
var BROKER_URL = CONFIG.brokerUrl;
|
|
@@ -23049,6 +23072,32 @@ function createMcpServer(getSessionId) {
|
|
|
23049
23072
|
}
|
|
23050
23073
|
}
|
|
23051
23074
|
);
|
|
23075
|
+
server.tool(
|
|
23076
|
+
"define_local_identity_file",
|
|
23077
|
+
"Write a `.a2adapt-identity` workspace-pin file that ties a directory to an identity, so a future Claude Code session here auto-binds it (and the SessionStart hook arms the right Monitor). Use this instead of hand-writing the file. Because this daemon is shared and its CWD is not the user's project, you MUST pass an absolute `path` (the target directory, or the full path ending in .a2adapt-identity). Refuses to overwrite unless overwrite=true.",
|
|
23078
|
+
{
|
|
23079
|
+
name: external_exports.string().min(1).describe("Identity name the workspace belongs to."),
|
|
23080
|
+
path: external_exports.string().min(1).describe("Absolute target: a directory (file is created inside it) or a full path ending in .a2adapt-identity."),
|
|
23081
|
+
force: external_exports.boolean().default(false).describe("Pin pre-authorizes force-binding (evicting another session) \u2014 no user prompt at bind time."),
|
|
23082
|
+
expose_local: external_exports.boolean().default(true).describe("Publish this identity in the host-local contact book."),
|
|
23083
|
+
local_auto_accept: external_exports.boolean().default(true).describe("Auto-accept local contact-book introductions (false = they queue for approval)."),
|
|
23084
|
+
overwrite: external_exports.boolean().default(false).describe("Replace an existing .a2adapt-identity file.")
|
|
23085
|
+
},
|
|
23086
|
+
async ({ name, path, force, expose_local, local_auto_accept, overwrite }) => {
|
|
23087
|
+
if (!isAbsolute(path)) {
|
|
23088
|
+
return textResult(`define_local_identity_file failed: path must be absolute (got "${path}").`, true);
|
|
23089
|
+
}
|
|
23090
|
+
const opts = { name, force, exposeLocal: expose_local, localAutoAccept: local_auto_accept };
|
|
23091
|
+
try {
|
|
23092
|
+
const written = writeIdentityFile(path, opts, overwrite);
|
|
23093
|
+
const json = JSON.stringify(buildIdentityFile(opts), null, 2);
|
|
23094
|
+
return textResult(`Wrote ${written}:
|
|
23095
|
+
${json}`);
|
|
23096
|
+
} catch (err) {
|
|
23097
|
+
return textResult(`define_local_identity_file failed: ${String(err)}`, true);
|
|
23098
|
+
}
|
|
23099
|
+
}
|
|
23100
|
+
);
|
|
23052
23101
|
server.tool(
|
|
23053
23102
|
"choose_identity",
|
|
23054
23103
|
"Bind an existing identity to this session so the messaging tools act as it. Binding is exclusive: if the identity is already in use by another session, this is declined unless force=true, which evicts the other session. Never pass force=true on your own initiative \u2014 ask the user and get an explicit confirmation first.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adapt-toolkit/a2adapt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "MCP server daemon for a2adapt — one native ADAPT wrapper hosting N self-sovereign identities, exposing secure agent-to-agent messaging tools over HTTP (Streamable HTTP). Run `a2adapt-mcp start`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|