@agentchatme/cli 0.0.131 → 0.0.132

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/index.js CHANGED
@@ -37,6 +37,49 @@ function stopOutput(platform, reason) {
37
37
  }
38
38
  }
39
39
 
40
+ // src/lib/paths.ts
41
+ import * as os from "os";
42
+ import * as path from "path";
43
+ function agentchatHome() {
44
+ const override = process.env["AGENTCHAT_HOME"];
45
+ if (override && override.trim().length > 0) return path.resolve(override);
46
+ return path.join(os.homedir(), ".agentchat");
47
+ }
48
+ function legacyMachineHome() {
49
+ return path.join(os.homedir(), ".agentchat");
50
+ }
51
+ function codexHome() {
52
+ const override = process.env["CODEX_HOME"];
53
+ if (override && override.trim().length > 0) return path.resolve(override);
54
+ return path.join(os.homedir(), ".codex");
55
+ }
56
+ function hostHome(platform) {
57
+ switch (platform) {
58
+ case "claude-code":
59
+ return path.join(os.homedir(), ".claude", "agentchat");
60
+ case "codex":
61
+ return path.join(codexHome(), "agentchat");
62
+ case "cursor":
63
+ return path.join(os.homedir(), ".cursor", "agentchat");
64
+ }
65
+ }
66
+ function bindHostHome(platform) {
67
+ const existing = process.env["AGENTCHAT_HOME"];
68
+ if (existing && existing.trim().length > 0) return path.resolve(existing);
69
+ const home = hostHome(platform);
70
+ process.env["AGENTCHAT_HOME"] = home;
71
+ return home;
72
+ }
73
+ function credentialsPath() {
74
+ return path.join(agentchatHome(), "credentials");
75
+ }
76
+ function pendingPath() {
77
+ return path.join(agentchatHome(), "pending.json");
78
+ }
79
+ function statePath() {
80
+ return path.join(agentchatHome(), "state.json");
81
+ }
82
+
40
83
  // src/lib/log.ts
41
84
  var LEVELS = ["silent", "error", "warn", "info", "debug"];
42
85
  function activeLevel() {
@@ -59,6 +102,7 @@ var log = {
59
102
 
60
103
  // src/lib/credentials.ts
61
104
  import * as fs2 from "fs";
105
+ import * as path3 from "path";
62
106
 
63
107
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
64
108
  var external_exports = {};
@@ -538,8 +582,8 @@ function getErrorMap() {
538
582
 
539
583
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
540
584
  var makeIssue = (params) => {
541
- const { data, path: path8, errorMaps, issueData } = params;
542
- const fullPath = [...path8, ...issueData.path || []];
585
+ const { data, path: path9, errorMaps, issueData } = params;
586
+ const fullPath = [...path9, ...issueData.path || []];
543
587
  const fullIssue = {
544
588
  ...issueData,
545
589
  path: fullPath
@@ -655,11 +699,11 @@ var errorUtil;
655
699
 
656
700
  // ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
657
701
  var ParseInputLazyPath = class {
658
- constructor(parent, value, path8, key) {
702
+ constructor(parent, value, path9, key) {
659
703
  this._cachedPath = [];
660
704
  this.parent = parent;
661
705
  this.data = value;
662
- this._path = path8;
706
+ this._path = path9;
663
707
  this._key = key;
664
708
  }
665
709
  get path() {
@@ -4103,11 +4147,11 @@ var NEVER = INVALID;
4103
4147
 
4104
4148
  // src/lib/fsutil.ts
4105
4149
  import * as fs from "fs";
4106
- import * as path from "path";
4150
+ import * as path2 from "path";
4107
4151
  function atomicWriteFile(filePath, data, mode) {
4108
- const dir = path.dirname(filePath);
4152
+ const dir = path2.dirname(filePath);
4109
4153
  fs.mkdirSync(dir, { recursive: true, mode: 448 });
4110
- const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.tmp`);
4154
+ const tmp = path2.join(dir, `.${path2.basename(filePath)}.${process.pid}.tmp`);
4111
4155
  fs.writeFileSync(tmp, data, mode === void 0 ? {} : { mode });
4112
4156
  fs.renameSync(tmp, filePath);
4113
4157
  if (mode !== void 0) {
@@ -4123,29 +4167,6 @@ function readJsonFile(filePath) {
4123
4167
  }
4124
4168
  }
4125
4169
 
4126
- // src/lib/paths.ts
4127
- import * as os from "os";
4128
- import * as path2 from "path";
4129
- function agentchatHome() {
4130
- const override = process.env["AGENTCHAT_HOME"];
4131
- if (override && override.trim().length > 0) return path2.resolve(override);
4132
- return path2.join(os.homedir(), ".agentchat");
4133
- }
4134
- function credentialsPath() {
4135
- return path2.join(agentchatHome(), "credentials");
4136
- }
4137
- function pendingPath() {
4138
- return path2.join(agentchatHome(), "pending.json");
4139
- }
4140
- function statePath() {
4141
- return path2.join(agentchatHome(), "state.json");
4142
- }
4143
- function codexHome() {
4144
- const override = process.env["CODEX_HOME"];
4145
- if (override && override.trim().length > 0) return path2.resolve(override);
4146
- return path2.join(os.homedir(), ".codex");
4147
- }
4148
-
4149
4170
  // src/lib/credentials.ts
4150
4171
  var DEFAULT_API_BASE = "https://api.agentchat.me";
4151
4172
  var CredentialsSchema = external_exports.object({
@@ -4160,6 +4181,12 @@ function readCredentialsFile() {
4160
4181
  const parsed = CredentialsSchema.safeParse(raw);
4161
4182
  return parsed.success ? parsed.data : null;
4162
4183
  }
4184
+ function readCredentialsFileAt(home) {
4185
+ const raw = readJsonFile(path3.join(home, "credentials"));
4186
+ if (raw === null) return null;
4187
+ const parsed = CredentialsSchema.safeParse(raw);
4188
+ return parsed.success ? parsed.data : null;
4189
+ }
4163
4190
  function resolveIdentity() {
4164
4191
  const envKey = process.env["AGENTCHAT_API_KEY"];
4165
4192
  const envBase = process.env["AGENTCHAT_API_BASE"];
@@ -4510,15 +4537,18 @@ function formatStopPickup(handle, rows) {
4510
4537
  "Handle these per your AgentChat skill, then finish. Reply via agentchat_send_message only where warranted \u2014 if nothing is actionable, simply end the turn (silence is a valid outcome)."
4511
4538
  ].join("\n");
4512
4539
  }
4513
- function formatRegistrationOffer(cliPath) {
4540
+ function formatRegistrationOffer(cliPath, platform) {
4514
4541
  const invoke = cliPath ? `node "${cliPath}"` : "agentchat";
4542
+ const p = platform ? ` --platform ${platform}` : "";
4543
+ const hostNote = platform ? `This ${platform} agent gets its OWN handle (separate from any other coding agent on this machine \u2014 that's what lets them DM each other). Use an email not already tied to another agent.` : "";
4515
4544
  return [
4516
- "The AgentChat plugin is installed but this machine has no AgentChat identity yet.",
4545
+ "The AgentChat plugin is installed but this agent has no AgentChat identity yet.",
4517
4546
  "",
4518
4547
  "AgentChat gives you (the agent) a handle other agents can DM, like a phone number. If the user would like that, offer to set it up conversationally:",
4548
+ ...hostNote ? [hostNote] : [],
4519
4549
  "1. Ask for the email + desired handle (3\u201330 chars, lowercase letters/digits/hyphens, must start with a letter).",
4520
- `2. Run: ${invoke} register --email <email> --handle <handle>`,
4521
- `3. A 6-digit code lands in their email; ask for it, then run: ${invoke} register --code <code>`,
4550
+ `2. Run: ${invoke} register${p} --email <email> --handle <handle>`,
4551
+ `3. A 6-digit code lands in their email; ask for it, then run: ${invoke} register${p} --code <code>`,
4522
4552
  "",
4523
4553
  "Do not push \u2014 one short offer is plenty. If declined, drop the topic for the rest of the session."
4524
4554
  ].join("\n");
@@ -4555,6 +4585,7 @@ function ackableRows(rows) {
4555
4585
  async function runSessionStartHook(platform) {
4556
4586
  try {
4557
4587
  if (hooksDisabled()) return;
4588
+ bindHostHome(platform);
4558
4589
  const input = await readHookInput();
4559
4590
  if (input.source === "compact") return;
4560
4591
  resetSession(`${platform}:${input.sessionId}`);
@@ -4562,7 +4593,7 @@ async function runSessionStartHook(platform) {
4562
4593
  if (identity === null) {
4563
4594
  if (shouldOfferRegistration()) {
4564
4595
  recordRegistrationOffer();
4565
- printJson(sessionStartOutput(platform, formatRegistrationOffer(process.argv[1])));
4596
+ printJson(sessionStartOutput(platform, formatRegistrationOffer(process.argv[1], platform)));
4566
4597
  }
4567
4598
  return;
4568
4599
  }
@@ -4583,6 +4614,7 @@ async function runSessionStartHook(platform) {
4583
4614
  async function runUserPromptHook(platform) {
4584
4615
  try {
4585
4616
  if (hooksDisabled()) return;
4617
+ bindHostHome(platform);
4586
4618
  const input = await readHookInput();
4587
4619
  const identity = resolveIdentity();
4588
4620
  if (identity === null) return;
@@ -4603,6 +4635,7 @@ async function runUserPromptHook(platform) {
4603
4635
  async function runStopHook(platform) {
4604
4636
  try {
4605
4637
  if (hooksDisabled()) return;
4638
+ bindHostHome(platform);
4606
4639
  const input = await readHookInput();
4607
4640
  const identity = resolveIdentity();
4608
4641
  if (identity === null) return;
@@ -4634,7 +4667,7 @@ async function runStopHook(platform) {
4634
4667
 
4635
4668
  // src/commands/identity.ts
4636
4669
  import * as fs5 from "fs";
4637
- import * as path5 from "path";
4670
+ import * as path6 from "path";
4638
4671
  import * as readline from "readline/promises";
4639
4672
 
4640
4673
  // ../node_modules/.pnpm/agentchatme@1.0.2/node_modules/agentchatme/dist/index.js
@@ -4897,8 +4930,8 @@ var HttpTransport = class {
4897
4930
  }
4898
4931
  this.fetchFn = f.bind(globalThis);
4899
4932
  }
4900
- async request(method, path8, opts = {}) {
4901
- const url = `${this.baseUrl}${path8}`;
4933
+ async request(method, path9, opts = {}) {
4934
+ const url = `${this.baseUrl}${path9}`;
4902
4935
  const policy = resolveRetryPolicy(opts.retry, this.retry);
4903
4936
  const canRetry = isRetryEligible(method, opts.idempotencyKey, opts.retry);
4904
4937
  const maxAttempts = canRetry ? policy.maxRetries + 1 : 1;
@@ -5217,31 +5250,31 @@ var AgentChatClient = class _AgentChatClient {
5217
5250
  this.onBacklogWarning = options.onBacklogWarning;
5218
5251
  }
5219
5252
  // ─── Internal request helpers ─────────────────────────────────────────────
5220
- async get(path8, opts) {
5221
- const res = await this.http.request("GET", path8, this.toRequestOpts(opts));
5253
+ async get(path9, opts) {
5254
+ const res = await this.http.request("GET", path9, this.toRequestOpts(opts));
5222
5255
  return res.data;
5223
5256
  }
5224
- async del(path8, opts) {
5225
- const res = await this.http.request("DELETE", path8, this.toRequestOpts(opts));
5257
+ async del(path9, opts) {
5258
+ const res = await this.http.request("DELETE", path9, this.toRequestOpts(opts));
5226
5259
  return res.data;
5227
5260
  }
5228
- async post(path8, body, opts) {
5229
- const res = await this.http.request("POST", path8, {
5261
+ async post(path9, body, opts) {
5262
+ const res = await this.http.request("POST", path9, {
5230
5263
  ...this.toRequestOpts(opts),
5231
5264
  body
5232
5265
  });
5233
5266
  return res.data;
5234
5267
  }
5235
- async patch(path8, body, opts) {
5236
- const res = await this.http.request("PATCH", path8, {
5268
+ async patch(path9, body, opts) {
5269
+ const res = await this.http.request("PATCH", path9, {
5237
5270
  ...this.toRequestOpts(opts),
5238
5271
  body
5239
5272
  });
5240
5273
  return res.data;
5241
5274
  }
5242
- async put(path8, body, opts) {
5275
+ async put(path9, body, opts) {
5243
5276
  const headers = opts?.contentType ? { "Content-Type": opts.contentType } : void 0;
5244
- const res = await this.http.request("PUT", path8, {
5277
+ const res = await this.http.request("PUT", path9, {
5245
5278
  ...this.toRequestOpts(opts),
5246
5279
  body,
5247
5280
  rawBody: opts?.rawBody,
@@ -5905,7 +5938,7 @@ var MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
5905
5938
  // src/lib/anchor.ts
5906
5939
  import * as fs3 from "fs";
5907
5940
  import * as os2 from "os";
5908
- import * as path3 from "path";
5941
+ import * as path4 from "path";
5909
5942
  var ANCHOR_START = "<!-- agentchat:start -->";
5910
5943
  var ANCHOR_END = "<!-- agentchat:end -->";
5911
5944
  var LEGACY_ANCHOR_START = "<!-- agentchat-skill:start -->";
@@ -5913,9 +5946,9 @@ var LEGACY_ANCHOR_END = "<!-- agentchat-skill:end -->";
5913
5946
  function anchorFilePath(platform) {
5914
5947
  switch (platform) {
5915
5948
  case "claude-code":
5916
- return path3.join(os2.homedir(), ".claude", "CLAUDE.md");
5949
+ return path4.join(os2.homedir(), ".claude", "CLAUDE.md");
5917
5950
  case "codex":
5918
- return path3.join(codexHome(), "AGENTS.md");
5951
+ return path4.join(codexHome(), "AGENTS.md");
5919
5952
  case "cursor":
5920
5953
  return null;
5921
5954
  }
@@ -5940,7 +5973,7 @@ function installAnchor(platform, handle) {
5940
5973
  if (filePath === null) return { platform, path: null, action: "unsupported" };
5941
5974
  const trimmedHandle = handle.trim();
5942
5975
  if (!trimmedHandle) throw new Error("installAnchor: handle is empty");
5943
- fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
5976
+ fs3.mkdirSync(path4.dirname(filePath), { recursive: true });
5944
5977
  const existing = fs3.existsSync(filePath) ? fs3.readFileSync(filePath, "utf-8") : "";
5945
5978
  const next = upsertAnchorBlock(existing, renderAnchorBlock(trimmedHandle));
5946
5979
  fs3.writeFileSync(filePath, next, "utf-8");
@@ -6015,18 +6048,21 @@ function stripAllBlocks(existing, start, end) {
6015
6048
 
6016
6049
  // src/lib/codex-config.ts
6017
6050
  import * as fs4 from "fs";
6018
- import * as path4 from "path";
6051
+ import * as path5 from "path";
6019
6052
  var TOML_START = "# agentchat:start";
6020
6053
  var TOML_END = "# agentchat:end";
6021
- var BUNDLE_REL = path4.join("bin", "agentchat.mjs");
6054
+ var BUNDLE_REL = path5.join("bin", "agentchat.mjs");
6022
6055
  function codexConfigPath() {
6023
- return path4.join(codexHome(), "config.toml");
6056
+ return path5.join(codexHome(), "config.toml");
6024
6057
  }
6025
6058
  function codexHooksPath() {
6026
- return path4.join(codexHome(), "hooks.json");
6059
+ return path5.join(codexHome(), "hooks.json");
6060
+ }
6061
+ function codexIdentityHome() {
6062
+ return hostHome("codex");
6027
6063
  }
6028
6064
  function stableBundlePath() {
6029
- return path4.join(agentchatHome(), BUNDLE_REL);
6065
+ return path5.join(codexIdentityHome(), BUNDLE_REL);
6030
6066
  }
6031
6067
  function renderCodexAgents(handle) {
6032
6068
  return [
@@ -6049,7 +6085,11 @@ function renderCodexAgents(handle) {
6049
6085
  ANCHOR_END
6050
6086
  ].join("\n");
6051
6087
  }
6088
+ function tomlString(s) {
6089
+ return '"' + s.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
6090
+ }
6052
6091
  function mcpBlock() {
6092
+ const idHome = codexIdentityHome();
6053
6093
  return [
6054
6094
  TOML_START,
6055
6095
  "[mcp_servers.agentchat]",
@@ -6059,12 +6099,13 @@ function mcpBlock() {
6059
6099
  "# Auto-run AgentChat tools without a prompt, scoped to THIS server only \u2014",
6060
6100
  "# we never touch your global approval_policy or sandbox.",
6061
6101
  'default_tools_approval_mode = "approve"',
6062
- "# Forward our identity env to the server. Codex passes the parent env to",
6063
- "# hooks but NOT to MCP servers unless named here \u2014 without this the server",
6064
- "# and the hooks can resolve DIFFERENT identities. Empty/unset in the",
6065
- "# normal case (server reads ~/.agentchat/credentials); load-bearing only",
6066
- "# when AGENTCHAT_HOME / a key is set in the environment.",
6067
- 'env_vars = ["AGENTCHAT_HOME", "AGENTCHAT_API_KEY", "AGENTCHAT_API_BASE"]',
6102
+ "",
6103
+ "# This Codex agent's OWN identity home. Codex does NOT pass the parent",
6104
+ "# env to MCP servers, so we set it here explicitly \u2014 this is what makes",
6105
+ "# the Codex agent a distinct AgentChat account from any Claude Code",
6106
+ "# agent on the same machine (each host = its own peer).",
6107
+ "[mcp_servers.agentchat.env]",
6108
+ `AGENTCHAT_HOME = ${tomlString(idHome)}`,
6068
6109
  TOML_END
6069
6110
  ].join("\n");
6070
6111
  }
@@ -6135,9 +6176,9 @@ function unmergeHooks(existing) {
6135
6176
  }
6136
6177
  function copyBundle(bundleSrc) {
6137
6178
  const dest = stableBundlePath();
6138
- fs4.mkdirSync(path4.dirname(dest), { recursive: true });
6139
- const srcResolved = path4.resolve(bundleSrc);
6140
- if (srcResolved !== path4.resolve(dest)) {
6179
+ fs4.mkdirSync(path5.dirname(dest), { recursive: true });
6180
+ const srcResolved = path5.resolve(bundleSrc);
6181
+ if (srcResolved !== path5.resolve(dest)) {
6141
6182
  fs4.copyFileSync(srcResolved, dest);
6142
6183
  }
6143
6184
  return dest;
@@ -6182,7 +6223,7 @@ function installCodex(bundleSrc, handle) {
6182
6223
  }
6183
6224
  if (handle) {
6184
6225
  try {
6185
- const agentsPath = path4.join(codexHome(), "AGENTS.md");
6226
+ const agentsPath = path5.join(codexHome(), "AGENTS.md");
6186
6227
  const existing = fs4.existsSync(agentsPath) ? fs4.readFileSync(agentsPath, "utf-8") : "";
6187
6228
  const next = upsertAnchorBlock(existing, renderCodexAgents(handle));
6188
6229
  fs4.writeFileSync(agentsPath, next, "utf-8");
@@ -6260,7 +6301,7 @@ var RESTART_HINT = "Restart your agent session (Claude Code: start a new session
6260
6301
  function autoAnchor(handle) {
6261
6302
  const lines = [];
6262
6303
  const ccFile = anchorFilePath("claude-code");
6263
- if (ccFile !== null && fs5.existsSync(path5.dirname(ccFile))) {
6304
+ if (ccFile !== null && fs5.existsSync(path6.dirname(ccFile))) {
6264
6305
  try {
6265
6306
  installAnchor("claude-code", handle);
6266
6307
  lines.push(` anchor claude-code: written \u2192 ${ccFile}`);
@@ -6507,11 +6548,65 @@ async function runRecover(opts) {
6507
6548
  return 1;
6508
6549
  }
6509
6550
  }
6551
+ async function withHome(home, fn) {
6552
+ const prev = process.env["AGENTCHAT_HOME"];
6553
+ process.env["AGENTCHAT_HOME"] = home;
6554
+ try {
6555
+ return await fn();
6556
+ } finally {
6557
+ if (prev === void 0) delete process.env["AGENTCHAT_HOME"];
6558
+ else process.env["AGENTCHAT_HOME"] = prev;
6559
+ }
6560
+ }
6561
+ var STATUS_HOSTS = [
6562
+ ["claude-code", "Claude Code"],
6563
+ ["codex", "Codex"]
6564
+ ];
6510
6565
  async function runStatus(opts) {
6566
+ const bound = (process.env["AGENTCHAT_HOME"] ?? "").trim().length > 0;
6567
+ if (bound) return statusOne(opts.json ?? false);
6568
+ const rows = [];
6569
+ for (const [platform, label] of STATUS_HOSTS) {
6570
+ const home = hostHome(platform);
6571
+ if (readCredentialsFileAt(home) !== null) rows.push({ label, home });
6572
+ }
6573
+ const legacy = readCredentialsFileAt(legacyMachineHome());
6574
+ if (rows.length === 0 && legacy === null) {
6575
+ console.log(
6576
+ opts.json ? JSON.stringify({ identities: [] }) : "No AgentChat identities on this machine yet. Each coding agent gets its own \u2014 open Claude Code or Codex and it will offer to set one up, or run: agentchat register --platform <claude-code|codex> --email <email> --handle <handle>"
6577
+ );
6578
+ return 0;
6579
+ }
6580
+ if (opts.json) {
6581
+ const out = [];
6582
+ for (const r of rows) out.push({ host: r.label, ...await withHome(r.home, () => statusData()) });
6583
+ if (legacy) out.push({ host: "legacy (~/.agentchat, shared)", handle: legacy.handle, legacy: true });
6584
+ console.log(JSON.stringify({ identities: out }));
6585
+ return 0;
6586
+ }
6587
+ for (const r of rows) {
6588
+ console.log(`\u2500\u2500 ${r.label} \u2500\u2500`);
6589
+ await withHome(r.home, () => statusOne(false));
6590
+ }
6591
+ if (legacy) {
6592
+ console.log("\u2500\u2500 legacy (~/.agentchat, machine-shared) \u2500\u2500");
6593
+ console.log(`@${legacy.handle} \u2014 a pre-per-host identity; \`agentchat install\` migrates it into a host.`);
6594
+ }
6595
+ return 0;
6596
+ }
6597
+ async function statusData() {
6598
+ const identity = resolveIdentity();
6599
+ if (identity === null) return { handle: "?", status: "unconfigured", unread: 0 };
6600
+ const client = new AgentChatClient({ apiKey: identity.apiKey, baseUrl: identity.apiBase });
6601
+ const me = await client.getMe();
6602
+ const rows = await syncPeek({ apiKey: identity.apiKey, apiBase: identity.apiBase }, { limit: 100 });
6603
+ return { handle: me.handle, status: me.status ?? "unknown", unread: rows.length };
6604
+ }
6605
+ async function statusOne(json) {
6511
6606
  const identity = resolveIdentity();
6512
6607
  const pending = readPending();
6513
6608
  if (identity === null) {
6514
- if (opts.json) {
6609
+ if (json) {
6515
6610
  console.log(
6516
6611
  JSON.stringify({ configured: false, pending: pending !== null, pending_kind: pending?.kind ?? null })
6517
6612
  );
@@ -6524,7 +6619,7 @@ async function runStatus(opts) {
6524
6619
  `No identity yet, but a registration for @${pending.handle ?? "?"} is waiting on its emailed code \u2014 finish with: agentchat register --code <code>`
6525
6620
  );
6526
6621
  } else {
6527
- console.log("No AgentChat identity on this machine. Set one up with: agentchat register");
6622
+ console.log("No AgentChat identity for this host. Set one up with: agentchat register");
6528
6623
  }
6529
6624
  return 0;
6530
6625
  }
@@ -6540,7 +6635,7 @@ async function runStatus(opts) {
6540
6635
  "claude-code": hasAnchor("claude-code"),
6541
6636
  codex: hasAnchor("codex")
6542
6637
  };
6543
- if (opts.json) {
6638
+ if (json) {
6544
6639
  console.log(
6545
6640
  JSON.stringify({
6546
6641
  configured: true,
@@ -6571,24 +6666,59 @@ async function runStatus(opts) {
6571
6666
  }
6572
6667
  }
6573
6668
  function runLogout() {
6574
- const removed = clearCredentials();
6669
+ const bound = (process.env["AGENTCHAT_HOME"] ?? "").trim().length > 0;
6575
6670
  const reports = [];
6576
- try {
6577
- const result = removeAnchor("claude-code");
6578
- if (result.action === "removed") reports.push(" Claude Code anchor: removed");
6579
- } catch {
6580
- reports.push(" Claude Code anchor: could not clean up (remove the agentchat block manually)");
6581
- }
6582
- try {
6583
- const codexRemoved = removeCodex();
6584
- if (codexRemoved.length > 0) reports.push(` Codex: removed ${codexRemoved.join(", ")}`);
6585
- } catch {
6586
- reports.push(" Codex: could not fully clean up (check ~/.codex/config.toml + hooks.json)");
6671
+ let any = false;
6672
+ const logoutHost = (platform, label) => {
6673
+ const home = hostHome(platform);
6674
+ const prev = process.env["AGENTCHAT_HOME"];
6675
+ process.env["AGENTCHAT_HOME"] = home;
6676
+ try {
6677
+ if (clearCredentials()) {
6678
+ any = true;
6679
+ reports.push(` ${label}: credentials deleted`);
6680
+ }
6681
+ if (platform === "claude-code") {
6682
+ const r = removeAnchor("claude-code");
6683
+ if (r.action === "removed") reports.push(" Claude Code: anchor removed");
6684
+ } else if (platform === "codex") {
6685
+ const removed = removeCodex();
6686
+ if (removed.length > 0) reports.push(` Codex: removed ${removed.join(", ")}`);
6687
+ }
6688
+ } catch {
6689
+ reports.push(` ${label}: could not fully clean up`);
6690
+ } finally {
6691
+ if (prev === void 0) delete process.env["AGENTCHAT_HOME"];
6692
+ else process.env["AGENTCHAT_HOME"] = prev;
6693
+ }
6694
+ };
6695
+ if (bound) {
6696
+ if (clearCredentials()) any = true;
6697
+ try {
6698
+ removeAnchor("claude-code");
6699
+ } catch {
6700
+ }
6701
+ try {
6702
+ removeCodex();
6703
+ } catch {
6704
+ }
6705
+ } else {
6706
+ logoutHost("claude-code", "Claude Code");
6707
+ logoutHost("codex", "Codex");
6708
+ const prev = process.env["AGENTCHAT_HOME"];
6709
+ process.env["AGENTCHAT_HOME"] = legacyMachineHome();
6710
+ try {
6711
+ if (clearCredentials()) {
6712
+ any = true;
6713
+ reports.push(" legacy (~/.agentchat): credentials deleted");
6714
+ }
6715
+ } finally {
6716
+ if (prev === void 0) delete process.env["AGENTCHAT_HOME"];
6717
+ else process.env["AGENTCHAT_HOME"] = prev;
6718
+ }
6587
6719
  }
6588
6720
  console.log(
6589
- [removed ? "Signed out \u2014 local credentials deleted." : "Nothing to sign out of.", ...reports].join(
6590
- "\n"
6591
- )
6721
+ [any ? "Signed out." : "Nothing to sign out of.", ...reports].join("\n")
6592
6722
  );
6593
6723
  return 0;
6594
6724
  }
@@ -6596,7 +6726,7 @@ function runLogout() {
6596
6726
  // src/commands/install.ts
6597
6727
  import * as fs6 from "fs";
6598
6728
  import * as os3 from "os";
6599
- import * as path6 from "path";
6729
+ import * as path7 from "path";
6600
6730
  import { spawnSync } from "child_process";
6601
6731
  var MARKETPLACE_SLUG = "agentchatme/agentchat-coding-agents";
6602
6732
  var PLUGIN_REF = "agentchat@agentchatme";
@@ -6613,11 +6743,11 @@ function defaultRun(cmd, args) {
6613
6743
  function binaryOnPath(binary, env) {
6614
6744
  const pathVar = env["PATH"] ?? "";
6615
6745
  const exts = process.platform === "win32" ? [".cmd", ".exe", ".bat", ""] : [""];
6616
- for (const dir of pathVar.split(path6.delimiter)) {
6746
+ for (const dir of pathVar.split(path7.delimiter)) {
6617
6747
  if (dir.length === 0) continue;
6618
6748
  for (const ext of exts) {
6619
6749
  try {
6620
- if (fs6.existsSync(path6.join(dir, binary + ext))) return true;
6750
+ if (fs6.existsSync(path7.join(dir, binary + ext))) return true;
6621
6751
  } catch {
6622
6752
  }
6623
6753
  }
@@ -6626,7 +6756,7 @@ function binaryOnPath(binary, env) {
6626
6756
  }
6627
6757
  function detectPlatforms(env, home) {
6628
6758
  return PROBES.filter(
6629
- (p) => binaryOnPath(p.binary, env) || fs6.existsSync(path6.join(home, p.configDir))
6759
+ (p) => binaryOnPath(p.binary, env) || fs6.existsSync(path7.join(home, p.configDir))
6630
6760
  );
6631
6761
  }
6632
6762
  async function runInstall(deps = {}) {
@@ -6666,7 +6796,7 @@ async function runInstall(deps = {}) {
6666
6796
  }
6667
6797
  case "codex": {
6668
6798
  const bundleSrc = process.argv[1] ?? "";
6669
- const handle = resolveIdentity()?.handle ?? null;
6799
+ const handle = readCredentialsFileAt(codexIdentityHome())?.handle ?? null;
6670
6800
  try {
6671
6801
  const { actions, warnings } = installCodex(bundleSrc, handle);
6672
6802
  console.log(` Codex: wired \u2713 (${actions.join(", ") || "no changes"})`);
@@ -6684,27 +6814,36 @@ async function runInstall(deps = {}) {
6684
6814
  break;
6685
6815
  }
6686
6816
  }
6687
- if (resolveIdentity() === null) {
6817
+ const need = [];
6818
+ const have = [];
6819
+ for (const platform of detected) {
6820
+ if (platform.key === "cursor") continue;
6821
+ const handle = readCredentialsFileAt(hostHome(platform.key))?.handle ?? null;
6822
+ if (handle) have.push(`${platform.label} \u2192 @${handle}`);
6823
+ else need.push(platform.key);
6824
+ }
6825
+ if (have.length > 0) console.log(`
6826
+ Signed in: ${have.join(", ")}`);
6827
+ if (need.length > 0) {
6688
6828
  console.log(
6689
6829
  [
6690
6830
  "",
6691
- "Next: give your agent its identity \u2014",
6692
- " agentchat register --email <email> --handle <handle>",
6693
- "or just start a session and let the agent walk you through it."
6831
+ `Each coding agent gets its OWN handle (so your agents can message each other). Still needed: ${need.join(", ")}.`,
6832
+ "Just open the agent and it will offer to set one up, or register per host:",
6833
+ ...need.map((p) => ` agentchat register --platform ${p} --email <email> --handle <handle>`),
6834
+ "(use a separate email per agent)."
6694
6835
  ].join("\n")
6695
6836
  );
6696
- } else {
6697
- console.log("\nExisting identity found \u2014 this machine is already signed in (see `agentchat status`).");
6698
6837
  }
6699
6838
  return failures === 0 ? 0 : 1;
6700
6839
  }
6701
6840
 
6702
6841
  // src/commands/doctor.ts
6703
6842
  import * as fs7 from "fs";
6704
- import * as path7 from "path";
6843
+ import * as path8 from "path";
6705
6844
 
6706
6845
  // src/version.ts
6707
- var VERSION2 = "0.0.131";
6846
+ var VERSION2 = "0.0.132";
6708
6847
 
6709
6848
  // src/commands/doctor.ts
6710
6849
  function fmt(check) {
@@ -6770,7 +6909,7 @@ async function runDoctor() {
6770
6909
  for (const platform of ["claude-code", "codex"]) {
6771
6910
  const file = anchorFilePath(platform);
6772
6911
  if (file === null) continue;
6773
- const hostDir = path7.dirname(file);
6912
+ const hostDir = path8.dirname(file);
6774
6913
  if (!fs7.existsSync(hostDir)) {
6775
6914
  checks.push({ name: `anchor-${platform}`, verdict: "PASS", detail: `${hostDir} absent (host not installed) \u2014 skipped` });
6776
6915
  } else {
@@ -6872,6 +7011,9 @@ async function main(argv = process.argv.slice(2)) {
6872
7011
  return 0;
6873
7012
  }
6874
7013
  const requirePlatform = () => resolvePlatform(values.platform);
7014
+ if (values.platform !== void 0 && isPlatform(values.platform)) {
7015
+ bindHostHome(values.platform);
7016
+ }
6875
7017
  switch (command) {
6876
7018
  case "install":
6877
7019
  return runInstall();