@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 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.8.1" : "0.0.0-dev";
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.8.1",
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",