@agentchatme/cli 0.0.131 → 0.0.133
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 +281 -104
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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:
|
|
542
|
-
const fullPath = [...
|
|
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,
|
|
702
|
+
constructor(parent, value, path9, key) {
|
|
659
703
|
this._cachedPath = [];
|
|
660
704
|
this.parent = parent;
|
|
661
705
|
this.data = value;
|
|
662
|
-
this._path =
|
|
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
|
|
4150
|
+
import * as path2 from "path";
|
|
4107
4151
|
function atomicWriteFile(filePath, data, mode) {
|
|
4108
|
-
const dir =
|
|
4152
|
+
const dir = path2.dirname(filePath);
|
|
4109
4153
|
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
4110
|
-
const 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"];
|
|
@@ -4439,6 +4466,23 @@ async function getMeLite(cfg) {
|
|
|
4439
4466
|
return null;
|
|
4440
4467
|
}
|
|
4441
4468
|
}
|
|
4469
|
+
async function markSessionActive(cfg, ttlSeconds) {
|
|
4470
|
+
try {
|
|
4471
|
+
await request(cfg, "PUT", "/v1/reply/active", ttlSeconds !== void 0 ? { ttl_seconds: ttlSeconds } : {});
|
|
4472
|
+
} catch (err) {
|
|
4473
|
+
log.warn(`reply-active mark failed (ignored): ${String(err)}`);
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
async function claimReply(cfg, messageId, holder) {
|
|
4477
|
+
try {
|
|
4478
|
+
const data = await request(cfg, "POST", "/v1/reply/claim", { message_id: messageId, holder });
|
|
4479
|
+
const parsed = external_exports.object({ claimed: external_exports.boolean() }).passthrough().safeParse(data);
|
|
4480
|
+
return parsed.success ? parsed.data.claimed : true;
|
|
4481
|
+
} catch (err) {
|
|
4482
|
+
log.warn(`reply-claim failed (surfacing anyway): ${String(err)}`);
|
|
4483
|
+
return true;
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4442
4486
|
function lastDeliveryId(rows) {
|
|
4443
4487
|
for (let i = rows.length - 1; i >= 0; i--) {
|
|
4444
4488
|
const id = rows[i]?.delivery_id;
|
|
@@ -4510,15 +4554,18 @@ function formatStopPickup(handle, rows) {
|
|
|
4510
4554
|
"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
4555
|
].join("\n");
|
|
4512
4556
|
}
|
|
4513
|
-
function formatRegistrationOffer(cliPath) {
|
|
4557
|
+
function formatRegistrationOffer(cliPath, platform) {
|
|
4514
4558
|
const invoke = cliPath ? `node "${cliPath}"` : "agentchat";
|
|
4559
|
+
const p = platform ? ` --platform ${platform}` : "";
|
|
4560
|
+
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
4561
|
return [
|
|
4516
|
-
"The AgentChat plugin is installed but this
|
|
4562
|
+
"The AgentChat plugin is installed but this agent has no AgentChat identity yet.",
|
|
4517
4563
|
"",
|
|
4518
4564
|
"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:",
|
|
4565
|
+
...hostNote ? [hostNote] : [],
|
|
4519
4566
|
"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>`,
|
|
4567
|
+
`2. Run: ${invoke} register${p} --email <email> --handle <handle>`,
|
|
4568
|
+
`3. A 6-digit code lands in their email; ask for it, then run: ${invoke} register${p} --code <code>`,
|
|
4522
4569
|
"",
|
|
4523
4570
|
"Do not push \u2014 one short offer is plenty. If declined, drop the topic for the rest of the session."
|
|
4524
4571
|
].join("\n");
|
|
@@ -4552,9 +4599,22 @@ function ackableRows(rows) {
|
|
|
4552
4599
|
}
|
|
4553
4600
|
return usable;
|
|
4554
4601
|
}
|
|
4602
|
+
async function claimContiguousPrefix(cfg, rows, holder) {
|
|
4603
|
+
const won = await Promise.all(rows.map((r) => claimReply(cfg, r.id, holder)));
|
|
4604
|
+
const prefix = [];
|
|
4605
|
+
for (let i = 0; i < rows.length; i++) {
|
|
4606
|
+
if (!won[i]) break;
|
|
4607
|
+
prefix.push(rows[i]);
|
|
4608
|
+
}
|
|
4609
|
+
if (prefix.length < rows.length) {
|
|
4610
|
+
log.info(`coexistence: daemon owns ${rows.length - prefix.length} row(s); surfacing ${prefix.length}`);
|
|
4611
|
+
}
|
|
4612
|
+
return prefix;
|
|
4613
|
+
}
|
|
4555
4614
|
async function runSessionStartHook(platform) {
|
|
4556
4615
|
try {
|
|
4557
4616
|
if (hooksDisabled()) return;
|
|
4617
|
+
bindHostHome(platform);
|
|
4558
4618
|
const input = await readHookInput();
|
|
4559
4619
|
if (input.source === "compact") return;
|
|
4560
4620
|
resetSession(`${platform}:${input.sessionId}`);
|
|
@@ -4562,12 +4622,15 @@ async function runSessionStartHook(platform) {
|
|
|
4562
4622
|
if (identity === null) {
|
|
4563
4623
|
if (shouldOfferRegistration()) {
|
|
4564
4624
|
recordRegistrationOffer();
|
|
4565
|
-
printJson(sessionStartOutput(platform, formatRegistrationOffer(process.argv[1])));
|
|
4625
|
+
printJson(sessionStartOutput(platform, formatRegistrationOffer(process.argv[1], platform)));
|
|
4566
4626
|
}
|
|
4567
4627
|
return;
|
|
4568
4628
|
}
|
|
4569
4629
|
const cfg = { apiKey: identity.apiKey, apiBase: identity.apiBase };
|
|
4570
|
-
|
|
4630
|
+
await markSessionActive(cfg);
|
|
4631
|
+
const peeked = ackableRows(await syncPeek(cfg, { limit: SESSION_START_PEEK_LIMIT }));
|
|
4632
|
+
if (peeked.length === 0) return;
|
|
4633
|
+
const rows = await claimContiguousPrefix(cfg, peeked, `session:${input.sessionId}`);
|
|
4571
4634
|
if (rows.length === 0) return;
|
|
4572
4635
|
const handle = await resolveHandle(cfg, identity.handle);
|
|
4573
4636
|
const context = formatSessionStart(handle, rows);
|
|
@@ -4583,6 +4646,7 @@ async function runSessionStartHook(platform) {
|
|
|
4583
4646
|
async function runUserPromptHook(platform) {
|
|
4584
4647
|
try {
|
|
4585
4648
|
if (hooksDisabled()) return;
|
|
4649
|
+
bindHostHome(platform);
|
|
4586
4650
|
const input = await readHookInput();
|
|
4587
4651
|
const identity = resolveIdentity();
|
|
4588
4652
|
if (identity === null) return;
|
|
@@ -4603,17 +4667,21 @@ async function runUserPromptHook(platform) {
|
|
|
4603
4667
|
async function runStopHook(platform) {
|
|
4604
4668
|
try {
|
|
4605
4669
|
if (hooksDisabled()) return;
|
|
4670
|
+
bindHostHome(platform);
|
|
4606
4671
|
const input = await readHookInput();
|
|
4607
4672
|
const identity = resolveIdentity();
|
|
4608
4673
|
if (identity === null) return;
|
|
4609
4674
|
const sessionKey = `${platform}:${input.sessionId}`;
|
|
4675
|
+
const cfg = { apiKey: identity.apiKey, apiBase: identity.apiBase };
|
|
4676
|
+
await markSessionActive(cfg);
|
|
4610
4677
|
const cap = maxContinuations();
|
|
4611
4678
|
if (getContinuations(sessionKey) >= cap) {
|
|
4612
4679
|
log.info(`stop hook: continuation cap (${cap}) reached for ${sessionKey}; leaving inbox queued`);
|
|
4613
4680
|
return;
|
|
4614
4681
|
}
|
|
4615
|
-
const
|
|
4616
|
-
|
|
4682
|
+
const peeked = ackableRows(await syncPeek(cfg, { limit: STOP_PEEK_LIMIT }));
|
|
4683
|
+
if (peeked.length === 0) return;
|
|
4684
|
+
const rows = await claimContiguousPrefix(cfg, peeked, `session:${input.sessionId}`);
|
|
4617
4685
|
if (rows.length === 0) return;
|
|
4618
4686
|
recordContinuation(sessionKey);
|
|
4619
4687
|
const handle = await resolveHandle(cfg, identity.handle);
|
|
@@ -4634,10 +4702,10 @@ async function runStopHook(platform) {
|
|
|
4634
4702
|
|
|
4635
4703
|
// src/commands/identity.ts
|
|
4636
4704
|
import * as fs5 from "fs";
|
|
4637
|
-
import * as
|
|
4705
|
+
import * as path6 from "path";
|
|
4638
4706
|
import * as readline from "readline/promises";
|
|
4639
4707
|
|
|
4640
|
-
// ../node_modules/.pnpm/agentchatme@1.0.
|
|
4708
|
+
// ../node_modules/.pnpm/agentchatme@1.0.2_ws@8.21.1/node_modules/agentchatme/dist/index.js
|
|
4641
4709
|
var ErrorCode = {
|
|
4642
4710
|
AGENT_NOT_FOUND: "AGENT_NOT_FOUND",
|
|
4643
4711
|
AGENT_SUSPENDED: "AGENT_SUSPENDED",
|
|
@@ -4897,8 +4965,8 @@ var HttpTransport = class {
|
|
|
4897
4965
|
}
|
|
4898
4966
|
this.fetchFn = f.bind(globalThis);
|
|
4899
4967
|
}
|
|
4900
|
-
async request(method,
|
|
4901
|
-
const url = `${this.baseUrl}${
|
|
4968
|
+
async request(method, path9, opts = {}) {
|
|
4969
|
+
const url = `${this.baseUrl}${path9}`;
|
|
4902
4970
|
const policy = resolveRetryPolicy(opts.retry, this.retry);
|
|
4903
4971
|
const canRetry = isRetryEligible(method, opts.idempotencyKey, opts.retry);
|
|
4904
4972
|
const maxAttempts = canRetry ? policy.maxRetries + 1 : 1;
|
|
@@ -5217,31 +5285,31 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
5217
5285
|
this.onBacklogWarning = options.onBacklogWarning;
|
|
5218
5286
|
}
|
|
5219
5287
|
// ─── Internal request helpers ─────────────────────────────────────────────
|
|
5220
|
-
async get(
|
|
5221
|
-
const res = await this.http.request("GET",
|
|
5288
|
+
async get(path9, opts) {
|
|
5289
|
+
const res = await this.http.request("GET", path9, this.toRequestOpts(opts));
|
|
5222
5290
|
return res.data;
|
|
5223
5291
|
}
|
|
5224
|
-
async del(
|
|
5225
|
-
const res = await this.http.request("DELETE",
|
|
5292
|
+
async del(path9, opts) {
|
|
5293
|
+
const res = await this.http.request("DELETE", path9, this.toRequestOpts(opts));
|
|
5226
5294
|
return res.data;
|
|
5227
5295
|
}
|
|
5228
|
-
async post(
|
|
5229
|
-
const res = await this.http.request("POST",
|
|
5296
|
+
async post(path9, body, opts) {
|
|
5297
|
+
const res = await this.http.request("POST", path9, {
|
|
5230
5298
|
...this.toRequestOpts(opts),
|
|
5231
5299
|
body
|
|
5232
5300
|
});
|
|
5233
5301
|
return res.data;
|
|
5234
5302
|
}
|
|
5235
|
-
async patch(
|
|
5236
|
-
const res = await this.http.request("PATCH",
|
|
5303
|
+
async patch(path9, body, opts) {
|
|
5304
|
+
const res = await this.http.request("PATCH", path9, {
|
|
5237
5305
|
...this.toRequestOpts(opts),
|
|
5238
5306
|
body
|
|
5239
5307
|
});
|
|
5240
5308
|
return res.data;
|
|
5241
5309
|
}
|
|
5242
|
-
async put(
|
|
5310
|
+
async put(path9, body, opts) {
|
|
5243
5311
|
const headers = opts?.contentType ? { "Content-Type": opts.contentType } : void 0;
|
|
5244
|
-
const res = await this.http.request("PUT",
|
|
5312
|
+
const res = await this.http.request("PUT", path9, {
|
|
5245
5313
|
...this.toRequestOpts(opts),
|
|
5246
5314
|
body,
|
|
5247
5315
|
rawBody: opts?.rawBody,
|
|
@@ -5905,7 +5973,7 @@ var MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
|
|
|
5905
5973
|
// src/lib/anchor.ts
|
|
5906
5974
|
import * as fs3 from "fs";
|
|
5907
5975
|
import * as os2 from "os";
|
|
5908
|
-
import * as
|
|
5976
|
+
import * as path4 from "path";
|
|
5909
5977
|
var ANCHOR_START = "<!-- agentchat:start -->";
|
|
5910
5978
|
var ANCHOR_END = "<!-- agentchat:end -->";
|
|
5911
5979
|
var LEGACY_ANCHOR_START = "<!-- agentchat-skill:start -->";
|
|
@@ -5913,9 +5981,9 @@ var LEGACY_ANCHOR_END = "<!-- agentchat-skill:end -->";
|
|
|
5913
5981
|
function anchorFilePath(platform) {
|
|
5914
5982
|
switch (platform) {
|
|
5915
5983
|
case "claude-code":
|
|
5916
|
-
return
|
|
5984
|
+
return path4.join(os2.homedir(), ".claude", "CLAUDE.md");
|
|
5917
5985
|
case "codex":
|
|
5918
|
-
return
|
|
5986
|
+
return path4.join(codexHome(), "AGENTS.md");
|
|
5919
5987
|
case "cursor":
|
|
5920
5988
|
return null;
|
|
5921
5989
|
}
|
|
@@ -5940,7 +6008,7 @@ function installAnchor(platform, handle) {
|
|
|
5940
6008
|
if (filePath === null) return { platform, path: null, action: "unsupported" };
|
|
5941
6009
|
const trimmedHandle = handle.trim();
|
|
5942
6010
|
if (!trimmedHandle) throw new Error("installAnchor: handle is empty");
|
|
5943
|
-
fs3.mkdirSync(
|
|
6011
|
+
fs3.mkdirSync(path4.dirname(filePath), { recursive: true });
|
|
5944
6012
|
const existing = fs3.existsSync(filePath) ? fs3.readFileSync(filePath, "utf-8") : "";
|
|
5945
6013
|
const next = upsertAnchorBlock(existing, renderAnchorBlock(trimmedHandle));
|
|
5946
6014
|
fs3.writeFileSync(filePath, next, "utf-8");
|
|
@@ -6015,18 +6083,21 @@ function stripAllBlocks(existing, start, end) {
|
|
|
6015
6083
|
|
|
6016
6084
|
// src/lib/codex-config.ts
|
|
6017
6085
|
import * as fs4 from "fs";
|
|
6018
|
-
import * as
|
|
6086
|
+
import * as path5 from "path";
|
|
6019
6087
|
var TOML_START = "# agentchat:start";
|
|
6020
6088
|
var TOML_END = "# agentchat:end";
|
|
6021
|
-
var BUNDLE_REL =
|
|
6089
|
+
var BUNDLE_REL = path5.join("bin", "agentchat.mjs");
|
|
6022
6090
|
function codexConfigPath() {
|
|
6023
|
-
return
|
|
6091
|
+
return path5.join(codexHome(), "config.toml");
|
|
6024
6092
|
}
|
|
6025
6093
|
function codexHooksPath() {
|
|
6026
|
-
return
|
|
6094
|
+
return path5.join(codexHome(), "hooks.json");
|
|
6095
|
+
}
|
|
6096
|
+
function codexIdentityHome() {
|
|
6097
|
+
return hostHome("codex");
|
|
6027
6098
|
}
|
|
6028
6099
|
function stableBundlePath() {
|
|
6029
|
-
return
|
|
6100
|
+
return path5.join(codexIdentityHome(), BUNDLE_REL);
|
|
6030
6101
|
}
|
|
6031
6102
|
function renderCodexAgents(handle) {
|
|
6032
6103
|
return [
|
|
@@ -6049,7 +6120,11 @@ function renderCodexAgents(handle) {
|
|
|
6049
6120
|
ANCHOR_END
|
|
6050
6121
|
].join("\n");
|
|
6051
6122
|
}
|
|
6123
|
+
function tomlString(s) {
|
|
6124
|
+
return '"' + s.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
|
|
6125
|
+
}
|
|
6052
6126
|
function mcpBlock() {
|
|
6127
|
+
const idHome = codexIdentityHome();
|
|
6053
6128
|
return [
|
|
6054
6129
|
TOML_START,
|
|
6055
6130
|
"[mcp_servers.agentchat]",
|
|
@@ -6059,12 +6134,13 @@ function mcpBlock() {
|
|
|
6059
6134
|
"# Auto-run AgentChat tools without a prompt, scoped to THIS server only \u2014",
|
|
6060
6135
|
"# we never touch your global approval_policy or sandbox.",
|
|
6061
6136
|
'default_tools_approval_mode = "approve"',
|
|
6062
|
-
"
|
|
6063
|
-
"#
|
|
6064
|
-
"#
|
|
6065
|
-
"#
|
|
6066
|
-
"#
|
|
6067
|
-
|
|
6137
|
+
"",
|
|
6138
|
+
"# This Codex agent's OWN identity home. Codex does NOT pass the parent",
|
|
6139
|
+
"# env to MCP servers, so we set it here explicitly \u2014 this is what makes",
|
|
6140
|
+
"# the Codex agent a distinct AgentChat account from any Claude Code",
|
|
6141
|
+
"# agent on the same machine (each host = its own peer).",
|
|
6142
|
+
"[mcp_servers.agentchat.env]",
|
|
6143
|
+
`AGENTCHAT_HOME = ${tomlString(idHome)}`,
|
|
6068
6144
|
TOML_END
|
|
6069
6145
|
].join("\n");
|
|
6070
6146
|
}
|
|
@@ -6135,9 +6211,9 @@ function unmergeHooks(existing) {
|
|
|
6135
6211
|
}
|
|
6136
6212
|
function copyBundle(bundleSrc) {
|
|
6137
6213
|
const dest = stableBundlePath();
|
|
6138
|
-
fs4.mkdirSync(
|
|
6139
|
-
const srcResolved =
|
|
6140
|
-
if (srcResolved !==
|
|
6214
|
+
fs4.mkdirSync(path5.dirname(dest), { recursive: true });
|
|
6215
|
+
const srcResolved = path5.resolve(bundleSrc);
|
|
6216
|
+
if (srcResolved !== path5.resolve(dest)) {
|
|
6141
6217
|
fs4.copyFileSync(srcResolved, dest);
|
|
6142
6218
|
}
|
|
6143
6219
|
return dest;
|
|
@@ -6182,7 +6258,7 @@ function installCodex(bundleSrc, handle) {
|
|
|
6182
6258
|
}
|
|
6183
6259
|
if (handle) {
|
|
6184
6260
|
try {
|
|
6185
|
-
const agentsPath =
|
|
6261
|
+
const agentsPath = path5.join(codexHome(), "AGENTS.md");
|
|
6186
6262
|
const existing = fs4.existsSync(agentsPath) ? fs4.readFileSync(agentsPath, "utf-8") : "";
|
|
6187
6263
|
const next = upsertAnchorBlock(existing, renderCodexAgents(handle));
|
|
6188
6264
|
fs4.writeFileSync(agentsPath, next, "utf-8");
|
|
@@ -6260,7 +6336,7 @@ var RESTART_HINT = "Restart your agent session (Claude Code: start a new session
|
|
|
6260
6336
|
function autoAnchor(handle) {
|
|
6261
6337
|
const lines = [];
|
|
6262
6338
|
const ccFile = anchorFilePath("claude-code");
|
|
6263
|
-
if (ccFile !== null && fs5.existsSync(
|
|
6339
|
+
if (ccFile !== null && fs5.existsSync(path6.dirname(ccFile))) {
|
|
6264
6340
|
try {
|
|
6265
6341
|
installAnchor("claude-code", handle);
|
|
6266
6342
|
lines.push(` anchor claude-code: written \u2192 ${ccFile}`);
|
|
@@ -6507,11 +6583,65 @@ async function runRecover(opts) {
|
|
|
6507
6583
|
return 1;
|
|
6508
6584
|
}
|
|
6509
6585
|
}
|
|
6586
|
+
async function withHome(home, fn) {
|
|
6587
|
+
const prev = process.env["AGENTCHAT_HOME"];
|
|
6588
|
+
process.env["AGENTCHAT_HOME"] = home;
|
|
6589
|
+
try {
|
|
6590
|
+
return await fn();
|
|
6591
|
+
} finally {
|
|
6592
|
+
if (prev === void 0) delete process.env["AGENTCHAT_HOME"];
|
|
6593
|
+
else process.env["AGENTCHAT_HOME"] = prev;
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6596
|
+
var STATUS_HOSTS = [
|
|
6597
|
+
["claude-code", "Claude Code"],
|
|
6598
|
+
["codex", "Codex"]
|
|
6599
|
+
];
|
|
6510
6600
|
async function runStatus(opts) {
|
|
6601
|
+
const bound = (process.env["AGENTCHAT_HOME"] ?? "").trim().length > 0;
|
|
6602
|
+
if (bound) return statusOne(opts.json ?? false);
|
|
6603
|
+
const rows = [];
|
|
6604
|
+
for (const [platform, label] of STATUS_HOSTS) {
|
|
6605
|
+
const home = hostHome(platform);
|
|
6606
|
+
if (readCredentialsFileAt(home) !== null) rows.push({ label, home });
|
|
6607
|
+
}
|
|
6608
|
+
const legacy = readCredentialsFileAt(legacyMachineHome());
|
|
6609
|
+
if (rows.length === 0 && legacy === null) {
|
|
6610
|
+
console.log(
|
|
6611
|
+
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>"
|
|
6612
|
+
);
|
|
6613
|
+
return 0;
|
|
6614
|
+
}
|
|
6615
|
+
if (opts.json) {
|
|
6616
|
+
const out = [];
|
|
6617
|
+
for (const r of rows) out.push({ host: r.label, ...await withHome(r.home, () => statusData()) });
|
|
6618
|
+
if (legacy) out.push({ host: "legacy (~/.agentchat, shared)", handle: legacy.handle, legacy: true });
|
|
6619
|
+
console.log(JSON.stringify({ identities: out }));
|
|
6620
|
+
return 0;
|
|
6621
|
+
}
|
|
6622
|
+
for (const r of rows) {
|
|
6623
|
+
console.log(`\u2500\u2500 ${r.label} \u2500\u2500`);
|
|
6624
|
+
await withHome(r.home, () => statusOne(false));
|
|
6625
|
+
}
|
|
6626
|
+
if (legacy) {
|
|
6627
|
+
console.log("\u2500\u2500 legacy (~/.agentchat, machine-shared) \u2500\u2500");
|
|
6628
|
+
console.log(`@${legacy.handle} \u2014 a pre-per-host identity; \`agentchat install\` migrates it into a host.`);
|
|
6629
|
+
}
|
|
6630
|
+
return 0;
|
|
6631
|
+
}
|
|
6632
|
+
async function statusData() {
|
|
6633
|
+
const identity = resolveIdentity();
|
|
6634
|
+
if (identity === null) return { handle: "?", status: "unconfigured", unread: 0 };
|
|
6635
|
+
const client = new AgentChatClient({ apiKey: identity.apiKey, baseUrl: identity.apiBase });
|
|
6636
|
+
const me = await client.getMe();
|
|
6637
|
+
const rows = await syncPeek({ apiKey: identity.apiKey, apiBase: identity.apiBase }, { limit: 100 });
|
|
6638
|
+
return { handle: me.handle, status: me.status ?? "unknown", unread: rows.length };
|
|
6639
|
+
}
|
|
6640
|
+
async function statusOne(json) {
|
|
6511
6641
|
const identity = resolveIdentity();
|
|
6512
6642
|
const pending = readPending();
|
|
6513
6643
|
if (identity === null) {
|
|
6514
|
-
if (
|
|
6644
|
+
if (json) {
|
|
6515
6645
|
console.log(
|
|
6516
6646
|
JSON.stringify({ configured: false, pending: pending !== null, pending_kind: pending?.kind ?? null })
|
|
6517
6647
|
);
|
|
@@ -6524,7 +6654,7 @@ async function runStatus(opts) {
|
|
|
6524
6654
|
`No identity yet, but a registration for @${pending.handle ?? "?"} is waiting on its emailed code \u2014 finish with: agentchat register --code <code>`
|
|
6525
6655
|
);
|
|
6526
6656
|
} else {
|
|
6527
|
-
console.log("No AgentChat identity
|
|
6657
|
+
console.log("No AgentChat identity for this host. Set one up with: agentchat register");
|
|
6528
6658
|
}
|
|
6529
6659
|
return 0;
|
|
6530
6660
|
}
|
|
@@ -6540,7 +6670,7 @@ async function runStatus(opts) {
|
|
|
6540
6670
|
"claude-code": hasAnchor("claude-code"),
|
|
6541
6671
|
codex: hasAnchor("codex")
|
|
6542
6672
|
};
|
|
6543
|
-
if (
|
|
6673
|
+
if (json) {
|
|
6544
6674
|
console.log(
|
|
6545
6675
|
JSON.stringify({
|
|
6546
6676
|
configured: true,
|
|
@@ -6571,24 +6701,59 @@ async function runStatus(opts) {
|
|
|
6571
6701
|
}
|
|
6572
6702
|
}
|
|
6573
6703
|
function runLogout() {
|
|
6574
|
-
const
|
|
6704
|
+
const bound = (process.env["AGENTCHAT_HOME"] ?? "").trim().length > 0;
|
|
6575
6705
|
const reports = [];
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6706
|
+
let any = false;
|
|
6707
|
+
const logoutHost = (platform, label) => {
|
|
6708
|
+
const home = hostHome(platform);
|
|
6709
|
+
const prev = process.env["AGENTCHAT_HOME"];
|
|
6710
|
+
process.env["AGENTCHAT_HOME"] = home;
|
|
6711
|
+
try {
|
|
6712
|
+
if (clearCredentials()) {
|
|
6713
|
+
any = true;
|
|
6714
|
+
reports.push(` ${label}: credentials deleted`);
|
|
6715
|
+
}
|
|
6716
|
+
if (platform === "claude-code") {
|
|
6717
|
+
const r = removeAnchor("claude-code");
|
|
6718
|
+
if (r.action === "removed") reports.push(" Claude Code: anchor removed");
|
|
6719
|
+
} else if (platform === "codex") {
|
|
6720
|
+
const removed = removeCodex();
|
|
6721
|
+
if (removed.length > 0) reports.push(` Codex: removed ${removed.join(", ")}`);
|
|
6722
|
+
}
|
|
6723
|
+
} catch {
|
|
6724
|
+
reports.push(` ${label}: could not fully clean up`);
|
|
6725
|
+
} finally {
|
|
6726
|
+
if (prev === void 0) delete process.env["AGENTCHAT_HOME"];
|
|
6727
|
+
else process.env["AGENTCHAT_HOME"] = prev;
|
|
6728
|
+
}
|
|
6729
|
+
};
|
|
6730
|
+
if (bound) {
|
|
6731
|
+
if (clearCredentials()) any = true;
|
|
6732
|
+
try {
|
|
6733
|
+
removeAnchor("claude-code");
|
|
6734
|
+
} catch {
|
|
6735
|
+
}
|
|
6736
|
+
try {
|
|
6737
|
+
removeCodex();
|
|
6738
|
+
} catch {
|
|
6739
|
+
}
|
|
6740
|
+
} else {
|
|
6741
|
+
logoutHost("claude-code", "Claude Code");
|
|
6742
|
+
logoutHost("codex", "Codex");
|
|
6743
|
+
const prev = process.env["AGENTCHAT_HOME"];
|
|
6744
|
+
process.env["AGENTCHAT_HOME"] = legacyMachineHome();
|
|
6745
|
+
try {
|
|
6746
|
+
if (clearCredentials()) {
|
|
6747
|
+
any = true;
|
|
6748
|
+
reports.push(" legacy (~/.agentchat): credentials deleted");
|
|
6749
|
+
}
|
|
6750
|
+
} finally {
|
|
6751
|
+
if (prev === void 0) delete process.env["AGENTCHAT_HOME"];
|
|
6752
|
+
else process.env["AGENTCHAT_HOME"] = prev;
|
|
6753
|
+
}
|
|
6587
6754
|
}
|
|
6588
6755
|
console.log(
|
|
6589
|
-
[
|
|
6590
|
-
"\n"
|
|
6591
|
-
)
|
|
6756
|
+
[any ? "Signed out." : "Nothing to sign out of.", ...reports].join("\n")
|
|
6592
6757
|
);
|
|
6593
6758
|
return 0;
|
|
6594
6759
|
}
|
|
@@ -6596,7 +6761,7 @@ function runLogout() {
|
|
|
6596
6761
|
// src/commands/install.ts
|
|
6597
6762
|
import * as fs6 from "fs";
|
|
6598
6763
|
import * as os3 from "os";
|
|
6599
|
-
import * as
|
|
6764
|
+
import * as path7 from "path";
|
|
6600
6765
|
import { spawnSync } from "child_process";
|
|
6601
6766
|
var MARKETPLACE_SLUG = "agentchatme/agentchat-coding-agents";
|
|
6602
6767
|
var PLUGIN_REF = "agentchat@agentchatme";
|
|
@@ -6613,11 +6778,11 @@ function defaultRun(cmd, args) {
|
|
|
6613
6778
|
function binaryOnPath(binary, env) {
|
|
6614
6779
|
const pathVar = env["PATH"] ?? "";
|
|
6615
6780
|
const exts = process.platform === "win32" ? [".cmd", ".exe", ".bat", ""] : [""];
|
|
6616
|
-
for (const dir of pathVar.split(
|
|
6781
|
+
for (const dir of pathVar.split(path7.delimiter)) {
|
|
6617
6782
|
if (dir.length === 0) continue;
|
|
6618
6783
|
for (const ext of exts) {
|
|
6619
6784
|
try {
|
|
6620
|
-
if (fs6.existsSync(
|
|
6785
|
+
if (fs6.existsSync(path7.join(dir, binary + ext))) return true;
|
|
6621
6786
|
} catch {
|
|
6622
6787
|
}
|
|
6623
6788
|
}
|
|
@@ -6626,7 +6791,7 @@ function binaryOnPath(binary, env) {
|
|
|
6626
6791
|
}
|
|
6627
6792
|
function detectPlatforms(env, home) {
|
|
6628
6793
|
return PROBES.filter(
|
|
6629
|
-
(p) => binaryOnPath(p.binary, env) || fs6.existsSync(
|
|
6794
|
+
(p) => binaryOnPath(p.binary, env) || fs6.existsSync(path7.join(home, p.configDir))
|
|
6630
6795
|
);
|
|
6631
6796
|
}
|
|
6632
6797
|
async function runInstall(deps = {}) {
|
|
@@ -6666,7 +6831,7 @@ async function runInstall(deps = {}) {
|
|
|
6666
6831
|
}
|
|
6667
6832
|
case "codex": {
|
|
6668
6833
|
const bundleSrc = process.argv[1] ?? "";
|
|
6669
|
-
const handle =
|
|
6834
|
+
const handle = readCredentialsFileAt(codexIdentityHome())?.handle ?? null;
|
|
6670
6835
|
try {
|
|
6671
6836
|
const { actions, warnings } = installCodex(bundleSrc, handle);
|
|
6672
6837
|
console.log(` Codex: wired \u2713 (${actions.join(", ") || "no changes"})`);
|
|
@@ -6684,27 +6849,36 @@ async function runInstall(deps = {}) {
|
|
|
6684
6849
|
break;
|
|
6685
6850
|
}
|
|
6686
6851
|
}
|
|
6687
|
-
|
|
6852
|
+
const need = [];
|
|
6853
|
+
const have = [];
|
|
6854
|
+
for (const platform of detected) {
|
|
6855
|
+
if (platform.key === "cursor") continue;
|
|
6856
|
+
const handle = readCredentialsFileAt(hostHome(platform.key))?.handle ?? null;
|
|
6857
|
+
if (handle) have.push(`${platform.label} \u2192 @${handle}`);
|
|
6858
|
+
else need.push(platform.key);
|
|
6859
|
+
}
|
|
6860
|
+
if (have.length > 0) console.log(`
|
|
6861
|
+
Signed in: ${have.join(", ")}`);
|
|
6862
|
+
if (need.length > 0) {
|
|
6688
6863
|
console.log(
|
|
6689
6864
|
[
|
|
6690
6865
|
"",
|
|
6691
|
-
|
|
6692
|
-
"
|
|
6693
|
-
|
|
6866
|
+
`Each coding agent gets its OWN handle (so your agents can message each other). Still needed: ${need.join(", ")}.`,
|
|
6867
|
+
"Just open the agent and it will offer to set one up, or register per host:",
|
|
6868
|
+
...need.map((p) => ` agentchat register --platform ${p} --email <email> --handle <handle>`),
|
|
6869
|
+
"(use a separate email per agent)."
|
|
6694
6870
|
].join("\n")
|
|
6695
6871
|
);
|
|
6696
|
-
} else {
|
|
6697
|
-
console.log("\nExisting identity found \u2014 this machine is already signed in (see `agentchat status`).");
|
|
6698
6872
|
}
|
|
6699
6873
|
return failures === 0 ? 0 : 1;
|
|
6700
6874
|
}
|
|
6701
6875
|
|
|
6702
6876
|
// src/commands/doctor.ts
|
|
6703
6877
|
import * as fs7 from "fs";
|
|
6704
|
-
import * as
|
|
6878
|
+
import * as path8 from "path";
|
|
6705
6879
|
|
|
6706
6880
|
// src/version.ts
|
|
6707
|
-
var VERSION2 = "0.0.
|
|
6881
|
+
var VERSION2 = "0.0.133";
|
|
6708
6882
|
|
|
6709
6883
|
// src/commands/doctor.ts
|
|
6710
6884
|
function fmt(check) {
|
|
@@ -6770,7 +6944,7 @@ async function runDoctor() {
|
|
|
6770
6944
|
for (const platform of ["claude-code", "codex"]) {
|
|
6771
6945
|
const file = anchorFilePath(platform);
|
|
6772
6946
|
if (file === null) continue;
|
|
6773
|
-
const hostDir =
|
|
6947
|
+
const hostDir = path8.dirname(file);
|
|
6774
6948
|
if (!fs7.existsSync(hostDir)) {
|
|
6775
6949
|
checks.push({ name: `anchor-${platform}`, verdict: "PASS", detail: `${hostDir} absent (host not installed) \u2014 skipped` });
|
|
6776
6950
|
} else {
|
|
@@ -6872,6 +7046,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6872
7046
|
return 0;
|
|
6873
7047
|
}
|
|
6874
7048
|
const requirePlatform = () => resolvePlatform(values.platform);
|
|
7049
|
+
if (values.platform !== void 0 && isPlatform(values.platform)) {
|
|
7050
|
+
bindHostHome(values.platform);
|
|
7051
|
+
}
|
|
6875
7052
|
switch (command) {
|
|
6876
7053
|
case "install":
|
|
6877
7054
|
return runInstall();
|