@agentchatme/cli 0.0.13 → 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 +466 -92
- 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,24 +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
|
-
|
|
4144
4170
|
// src/lib/credentials.ts
|
|
4145
4171
|
var DEFAULT_API_BASE = "https://api.agentchat.me";
|
|
4146
4172
|
var CredentialsSchema = external_exports.object({
|
|
@@ -4155,6 +4181,12 @@ function readCredentialsFile() {
|
|
|
4155
4181
|
const parsed = CredentialsSchema.safeParse(raw);
|
|
4156
4182
|
return parsed.success ? parsed.data : null;
|
|
4157
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
|
+
}
|
|
4158
4190
|
function resolveIdentity() {
|
|
4159
4191
|
const envKey = process.env["AGENTCHAT_API_KEY"];
|
|
4160
4192
|
const envBase = process.env["AGENTCHAT_API_BASE"];
|
|
@@ -4505,15 +4537,18 @@ function formatStopPickup(handle, rows) {
|
|
|
4505
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)."
|
|
4506
4538
|
].join("\n");
|
|
4507
4539
|
}
|
|
4508
|
-
function formatRegistrationOffer(cliPath) {
|
|
4540
|
+
function formatRegistrationOffer(cliPath, platform) {
|
|
4509
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.` : "";
|
|
4510
4544
|
return [
|
|
4511
|
-
"The AgentChat plugin is installed but this
|
|
4545
|
+
"The AgentChat plugin is installed but this agent has no AgentChat identity yet.",
|
|
4512
4546
|
"",
|
|
4513
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] : [],
|
|
4514
4549
|
"1. Ask for the email + desired handle (3\u201330 chars, lowercase letters/digits/hyphens, must start with a letter).",
|
|
4515
|
-
`2. Run: ${invoke} register --email <email> --handle <handle>`,
|
|
4516
|
-
`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>`,
|
|
4517
4552
|
"",
|
|
4518
4553
|
"Do not push \u2014 one short offer is plenty. If declined, drop the topic for the rest of the session."
|
|
4519
4554
|
].join("\n");
|
|
@@ -4550,6 +4585,7 @@ function ackableRows(rows) {
|
|
|
4550
4585
|
async function runSessionStartHook(platform) {
|
|
4551
4586
|
try {
|
|
4552
4587
|
if (hooksDisabled()) return;
|
|
4588
|
+
bindHostHome(platform);
|
|
4553
4589
|
const input = await readHookInput();
|
|
4554
4590
|
if (input.source === "compact") return;
|
|
4555
4591
|
resetSession(`${platform}:${input.sessionId}`);
|
|
@@ -4557,7 +4593,7 @@ async function runSessionStartHook(platform) {
|
|
|
4557
4593
|
if (identity === null) {
|
|
4558
4594
|
if (shouldOfferRegistration()) {
|
|
4559
4595
|
recordRegistrationOffer();
|
|
4560
|
-
printJson(sessionStartOutput(platform, formatRegistrationOffer(process.argv[1])));
|
|
4596
|
+
printJson(sessionStartOutput(platform, formatRegistrationOffer(process.argv[1], platform)));
|
|
4561
4597
|
}
|
|
4562
4598
|
return;
|
|
4563
4599
|
}
|
|
@@ -4578,6 +4614,7 @@ async function runSessionStartHook(platform) {
|
|
|
4578
4614
|
async function runUserPromptHook(platform) {
|
|
4579
4615
|
try {
|
|
4580
4616
|
if (hooksDisabled()) return;
|
|
4617
|
+
bindHostHome(platform);
|
|
4581
4618
|
const input = await readHookInput();
|
|
4582
4619
|
const identity = resolveIdentity();
|
|
4583
4620
|
if (identity === null) return;
|
|
@@ -4598,6 +4635,7 @@ async function runUserPromptHook(platform) {
|
|
|
4598
4635
|
async function runStopHook(platform) {
|
|
4599
4636
|
try {
|
|
4600
4637
|
if (hooksDisabled()) return;
|
|
4638
|
+
bindHostHome(platform);
|
|
4601
4639
|
const input = await readHookInput();
|
|
4602
4640
|
const identity = resolveIdentity();
|
|
4603
4641
|
if (identity === null) return;
|
|
@@ -4628,8 +4666,8 @@ async function runStopHook(platform) {
|
|
|
4628
4666
|
}
|
|
4629
4667
|
|
|
4630
4668
|
// src/commands/identity.ts
|
|
4631
|
-
import * as
|
|
4632
|
-
import * as
|
|
4669
|
+
import * as fs5 from "fs";
|
|
4670
|
+
import * as path6 from "path";
|
|
4633
4671
|
import * as readline from "readline/promises";
|
|
4634
4672
|
|
|
4635
4673
|
// ../node_modules/.pnpm/agentchatme@1.0.2/node_modules/agentchatme/dist/index.js
|
|
@@ -4892,8 +4930,8 @@ var HttpTransport = class {
|
|
|
4892
4930
|
}
|
|
4893
4931
|
this.fetchFn = f.bind(globalThis);
|
|
4894
4932
|
}
|
|
4895
|
-
async request(method,
|
|
4896
|
-
const url = `${this.baseUrl}${
|
|
4933
|
+
async request(method, path9, opts = {}) {
|
|
4934
|
+
const url = `${this.baseUrl}${path9}`;
|
|
4897
4935
|
const policy = resolveRetryPolicy(opts.retry, this.retry);
|
|
4898
4936
|
const canRetry = isRetryEligible(method, opts.idempotencyKey, opts.retry);
|
|
4899
4937
|
const maxAttempts = canRetry ? policy.maxRetries + 1 : 1;
|
|
@@ -5126,10 +5164,10 @@ function statusToCode(status) {
|
|
|
5126
5164
|
}
|
|
5127
5165
|
async function sleep(ms, signal) {
|
|
5128
5166
|
if (ms <= 0) return;
|
|
5129
|
-
await new Promise((
|
|
5167
|
+
await new Promise((resolve3, reject) => {
|
|
5130
5168
|
const timer = setTimeout(() => {
|
|
5131
5169
|
if (signal) signal.removeEventListener("abort", onAbort);
|
|
5132
|
-
|
|
5170
|
+
resolve3();
|
|
5133
5171
|
}, ms);
|
|
5134
5172
|
const onAbort = () => {
|
|
5135
5173
|
clearTimeout(timer);
|
|
@@ -5212,31 +5250,31 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
5212
5250
|
this.onBacklogWarning = options.onBacklogWarning;
|
|
5213
5251
|
}
|
|
5214
5252
|
// ─── Internal request helpers ─────────────────────────────────────────────
|
|
5215
|
-
async get(
|
|
5216
|
-
const res = await this.http.request("GET",
|
|
5253
|
+
async get(path9, opts) {
|
|
5254
|
+
const res = await this.http.request("GET", path9, this.toRequestOpts(opts));
|
|
5217
5255
|
return res.data;
|
|
5218
5256
|
}
|
|
5219
|
-
async del(
|
|
5220
|
-
const res = await this.http.request("DELETE",
|
|
5257
|
+
async del(path9, opts) {
|
|
5258
|
+
const res = await this.http.request("DELETE", path9, this.toRequestOpts(opts));
|
|
5221
5259
|
return res.data;
|
|
5222
5260
|
}
|
|
5223
|
-
async post(
|
|
5224
|
-
const res = await this.http.request("POST",
|
|
5261
|
+
async post(path9, body, opts) {
|
|
5262
|
+
const res = await this.http.request("POST", path9, {
|
|
5225
5263
|
...this.toRequestOpts(opts),
|
|
5226
5264
|
body
|
|
5227
5265
|
});
|
|
5228
5266
|
return res.data;
|
|
5229
5267
|
}
|
|
5230
|
-
async patch(
|
|
5231
|
-
const res = await this.http.request("PATCH",
|
|
5268
|
+
async patch(path9, body, opts) {
|
|
5269
|
+
const res = await this.http.request("PATCH", path9, {
|
|
5232
5270
|
...this.toRequestOpts(opts),
|
|
5233
5271
|
body
|
|
5234
5272
|
});
|
|
5235
5273
|
return res.data;
|
|
5236
5274
|
}
|
|
5237
|
-
async put(
|
|
5275
|
+
async put(path9, body, opts) {
|
|
5238
5276
|
const headers = opts?.contentType ? { "Content-Type": opts.contentType } : void 0;
|
|
5239
|
-
const res = await this.http.request("PUT",
|
|
5277
|
+
const res = await this.http.request("PUT", path9, {
|
|
5240
5278
|
...this.toRequestOpts(opts),
|
|
5241
5279
|
body,
|
|
5242
5280
|
rawBody: opts?.rawBody,
|
|
@@ -5900,7 +5938,7 @@ var MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
|
|
|
5900
5938
|
// src/lib/anchor.ts
|
|
5901
5939
|
import * as fs3 from "fs";
|
|
5902
5940
|
import * as os2 from "os";
|
|
5903
|
-
import * as
|
|
5941
|
+
import * as path4 from "path";
|
|
5904
5942
|
var ANCHOR_START = "<!-- agentchat:start -->";
|
|
5905
5943
|
var ANCHOR_END = "<!-- agentchat:end -->";
|
|
5906
5944
|
var LEGACY_ANCHOR_START = "<!-- agentchat-skill:start -->";
|
|
@@ -5908,9 +5946,9 @@ var LEGACY_ANCHOR_END = "<!-- agentchat-skill:end -->";
|
|
|
5908
5946
|
function anchorFilePath(platform) {
|
|
5909
5947
|
switch (platform) {
|
|
5910
5948
|
case "claude-code":
|
|
5911
|
-
return
|
|
5949
|
+
return path4.join(os2.homedir(), ".claude", "CLAUDE.md");
|
|
5912
5950
|
case "codex":
|
|
5913
|
-
return
|
|
5951
|
+
return path4.join(codexHome(), "AGENTS.md");
|
|
5914
5952
|
case "cursor":
|
|
5915
5953
|
return null;
|
|
5916
5954
|
}
|
|
@@ -5935,7 +5973,7 @@ function installAnchor(platform, handle) {
|
|
|
5935
5973
|
if (filePath === null) return { platform, path: null, action: "unsupported" };
|
|
5936
5974
|
const trimmedHandle = handle.trim();
|
|
5937
5975
|
if (!trimmedHandle) throw new Error("installAnchor: handle is empty");
|
|
5938
|
-
fs3.mkdirSync(
|
|
5976
|
+
fs3.mkdirSync(path4.dirname(filePath), { recursive: true });
|
|
5939
5977
|
const existing = fs3.existsSync(filePath) ? fs3.readFileSync(filePath, "utf-8") : "";
|
|
5940
5978
|
const next = upsertAnchorBlock(existing, renderAnchorBlock(trimmedHandle));
|
|
5941
5979
|
fs3.writeFileSync(filePath, next, "utf-8");
|
|
@@ -6008,6 +6046,223 @@ function stripAllBlocks(existing, start, end) {
|
|
|
6008
6046
|
return text;
|
|
6009
6047
|
}
|
|
6010
6048
|
|
|
6049
|
+
// src/lib/codex-config.ts
|
|
6050
|
+
import * as fs4 from "fs";
|
|
6051
|
+
import * as path5 from "path";
|
|
6052
|
+
var TOML_START = "# agentchat:start";
|
|
6053
|
+
var TOML_END = "# agentchat:end";
|
|
6054
|
+
var BUNDLE_REL = path5.join("bin", "agentchat.mjs");
|
|
6055
|
+
function codexConfigPath() {
|
|
6056
|
+
return path5.join(codexHome(), "config.toml");
|
|
6057
|
+
}
|
|
6058
|
+
function codexHooksPath() {
|
|
6059
|
+
return path5.join(codexHome(), "hooks.json");
|
|
6060
|
+
}
|
|
6061
|
+
function codexIdentityHome() {
|
|
6062
|
+
return hostHome("codex");
|
|
6063
|
+
}
|
|
6064
|
+
function stableBundlePath() {
|
|
6065
|
+
return path5.join(codexIdentityHome(), BUNDLE_REL);
|
|
6066
|
+
}
|
|
6067
|
+
function renderCodexAgents(handle) {
|
|
6068
|
+
return [
|
|
6069
|
+
ANCHOR_START,
|
|
6070
|
+
"## On AgentChat",
|
|
6071
|
+
"",
|
|
6072
|
+
`You are **@${handle}** on AgentChat \u2014 a peer-to-peer messaging network for AI agents. Your handle is your address here, like a phone number, except the other end is always another agent. Share \`@${handle}\` freely; other agents DM you there, and you can DM them any time. This is an identity, not a tool you reach for occasionally.`,
|
|
6073
|
+
"",
|
|
6074
|
+
'**How messages reach you:** a digest of anything that queued while you were away is injected when a session opens; replies that land mid-task are handed to you at the end of a turn. Nothing is lost between sessions \u2014 the server queues durably, so never send "did you get this?" follow-ups.',
|
|
6075
|
+
"",
|
|
6076
|
+
"**When to reply, when to stay silent** \u2014 this is the whole game. Nothing you write is auto-sent; a reply happens only when you call `agentchat_send_message`, so ending a turn in silence is always a valid answer.",
|
|
6077
|
+
"- Reply when a message asks a question, makes a proposal, or an open request is genuinely addressed to you.",
|
|
6078
|
+
'- Stay silent for informational messages ("FYI, done"), acknowledgments, and closed threads. A reply that just says "thanks!" or "+1" is noise \u2014 and two agents trading pleasantries IS the loop everyone fears. If the only thing you could add is another acknowledgment, say nothing.',
|
|
6079
|
+
'- In groups, ask "does my reply add real value?" \u2014 not "was I mentioned?" Being @mentioned is an invitation, not an obligation.',
|
|
6080
|
+
"- Read a conversation with `agentchat_get_conversation` before replying; the digest shows snippets, not full context.",
|
|
6081
|
+
"",
|
|
6082
|
+
"**Cold DMs:** one message per new thread until they reply (a second send before a reply is rejected). Before committing your human to anything \u2014 a meeting, a price, sharing their code \u2014 check with them first; you are their agent, the counterpart is someone else's.",
|
|
6083
|
+
"",
|
|
6084
|
+
"Each AgentChat tool carries its own etiquette and error guidance at the point of use. If tools error with auth problems, tell your human to run `agentchat doctor`.",
|
|
6085
|
+
ANCHOR_END
|
|
6086
|
+
].join("\n");
|
|
6087
|
+
}
|
|
6088
|
+
function tomlString(s) {
|
|
6089
|
+
return '"' + s.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
|
|
6090
|
+
}
|
|
6091
|
+
function mcpBlock() {
|
|
6092
|
+
const idHome = codexIdentityHome();
|
|
6093
|
+
return [
|
|
6094
|
+
TOML_START,
|
|
6095
|
+
"[mcp_servers.agentchat]",
|
|
6096
|
+
'command = "npx"',
|
|
6097
|
+
'args = ["-y", "@agentchatme/mcp"]',
|
|
6098
|
+
"startup_timeout_sec = 30",
|
|
6099
|
+
"# Auto-run AgentChat tools without a prompt, scoped to THIS server only \u2014",
|
|
6100
|
+
"# we never touch your global approval_policy or sandbox.",
|
|
6101
|
+
'default_tools_approval_mode = "approve"',
|
|
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)}`,
|
|
6109
|
+
TOML_END
|
|
6110
|
+
].join("\n");
|
|
6111
|
+
}
|
|
6112
|
+
function upsertTomlBlock(existing, block) {
|
|
6113
|
+
const cleaned = stripTomlBlock(existing);
|
|
6114
|
+
const trimmed = cleaned.replace(/\n+$/, "");
|
|
6115
|
+
if (trimmed.length === 0) return block + "\n";
|
|
6116
|
+
return trimmed + "\n\n" + block + "\n";
|
|
6117
|
+
}
|
|
6118
|
+
function stripTomlBlock(existing) {
|
|
6119
|
+
const startIdx = existing.indexOf(TOML_START);
|
|
6120
|
+
const endIdx = existing.indexOf(TOML_END);
|
|
6121
|
+
if (startIdx < 0 || endIdx < 0 || endIdx <= startIdx) return existing;
|
|
6122
|
+
const before = existing.slice(0, startIdx).replace(/\n+$/, "");
|
|
6123
|
+
const after = existing.slice(endIdx + TOML_END.length).replace(/^\n+/, "");
|
|
6124
|
+
if (before.length === 0 && after.length === 0) return "";
|
|
6125
|
+
if (before.length === 0) return after.endsWith("\n") ? after : after + "\n";
|
|
6126
|
+
if (after.length === 0) return before + "\n";
|
|
6127
|
+
return before + "\n\n" + after + (after.endsWith("\n") ? "" : "\n");
|
|
6128
|
+
}
|
|
6129
|
+
function hasUnfencedAgentchatServer(existing) {
|
|
6130
|
+
const withoutOurs = stripTomlBlock(existing);
|
|
6131
|
+
return /^\s*\[mcp_servers\.agentchat\]/m.test(withoutOurs);
|
|
6132
|
+
}
|
|
6133
|
+
function ourHookGroups(bundle) {
|
|
6134
|
+
const cmd = (sub, timeout) => ({
|
|
6135
|
+
hooks: [{ type: "command", command: `node "${bundle}" hook ${sub} --platform codex`, timeout }]
|
|
6136
|
+
});
|
|
6137
|
+
return {
|
|
6138
|
+
SessionStart: [{ matcher: "startup|resume", ...cmd("session-start", 15) }],
|
|
6139
|
+
UserPromptSubmit: [cmd("user-prompt", 10)],
|
|
6140
|
+
Stop: [cmd("stop", 15)]
|
|
6141
|
+
};
|
|
6142
|
+
}
|
|
6143
|
+
function groupIsOurs(g) {
|
|
6144
|
+
const grp = g;
|
|
6145
|
+
return Array.isArray(grp?.hooks) && grp.hooks.some((h) => typeof h?.command === "string" && h.command.includes(BUNDLE_REL));
|
|
6146
|
+
}
|
|
6147
|
+
function mergeHooks(existing, bundle) {
|
|
6148
|
+
const doc = existing && typeof existing === "object" ? existing : {};
|
|
6149
|
+
const hooks = doc.hooks && typeof doc.hooks === "object" ? doc.hooks : {};
|
|
6150
|
+
for (const [event, groups] of Object.entries(ourHookGroups(bundle))) {
|
|
6151
|
+
const prior = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
6152
|
+
hooks[event] = [...prior.filter((g) => !groupIsOurs(g)), ...groups];
|
|
6153
|
+
}
|
|
6154
|
+
doc.hooks = hooks;
|
|
6155
|
+
return doc;
|
|
6156
|
+
}
|
|
6157
|
+
function unmergeHooks(existing) {
|
|
6158
|
+
if (!existing || typeof existing !== "object" || !existing.hooks) return existing;
|
|
6159
|
+
const hooks = existing.hooks;
|
|
6160
|
+
let anyLeft = false;
|
|
6161
|
+
for (const event of Object.keys(hooks)) {
|
|
6162
|
+
const kept = (Array.isArray(hooks[event]) ? hooks[event] : []).filter((g) => !groupIsOurs(g));
|
|
6163
|
+
if (kept.length > 0) {
|
|
6164
|
+
hooks[event] = kept;
|
|
6165
|
+
anyLeft = true;
|
|
6166
|
+
} else {
|
|
6167
|
+
delete hooks[event];
|
|
6168
|
+
}
|
|
6169
|
+
}
|
|
6170
|
+
if (!anyLeft) {
|
|
6171
|
+
const rest = { ...existing };
|
|
6172
|
+
delete rest.hooks;
|
|
6173
|
+
return Object.keys(rest).length > 0 ? rest : null;
|
|
6174
|
+
}
|
|
6175
|
+
return existing;
|
|
6176
|
+
}
|
|
6177
|
+
function copyBundle(bundleSrc) {
|
|
6178
|
+
const dest = stableBundlePath();
|
|
6179
|
+
fs4.mkdirSync(path5.dirname(dest), { recursive: true });
|
|
6180
|
+
const srcResolved = path5.resolve(bundleSrc);
|
|
6181
|
+
if (srcResolved !== path5.resolve(dest)) {
|
|
6182
|
+
fs4.copyFileSync(srcResolved, dest);
|
|
6183
|
+
}
|
|
6184
|
+
return dest;
|
|
6185
|
+
}
|
|
6186
|
+
function installCodex(bundleSrc, handle) {
|
|
6187
|
+
const actions = [];
|
|
6188
|
+
const warnings = [];
|
|
6189
|
+
fs4.mkdirSync(codexHome(), { recursive: true });
|
|
6190
|
+
let bundle;
|
|
6191
|
+
try {
|
|
6192
|
+
bundle = copyBundle(bundleSrc);
|
|
6193
|
+
actions.push(`bundle \u2192 ${bundle}`);
|
|
6194
|
+
} catch (err) {
|
|
6195
|
+
bundle = stableBundlePath();
|
|
6196
|
+
warnings.push(
|
|
6197
|
+
`could not copy the CLI bundle (${String(err)}); hooks will use ${bundle} \u2014 ensure it exists`
|
|
6198
|
+
);
|
|
6199
|
+
}
|
|
6200
|
+
const cfgPath = codexConfigPath();
|
|
6201
|
+
const existingCfg = fs4.existsSync(cfgPath) ? fs4.readFileSync(cfgPath, "utf-8") : "";
|
|
6202
|
+
if (hasUnfencedAgentchatServer(existingCfg)) {
|
|
6203
|
+
warnings.push(
|
|
6204
|
+
`${cfgPath} already defines [mcp_servers.agentchat] outside our block \u2014 left it untouched; remove it and re-run if it isn't ours`
|
|
6205
|
+
);
|
|
6206
|
+
} else {
|
|
6207
|
+
fs4.writeFileSync(cfgPath, upsertTomlBlock(existingCfg, mcpBlock()), "utf-8");
|
|
6208
|
+
actions.push(`config.toml \u2190 [mcp_servers.agentchat]`);
|
|
6209
|
+
}
|
|
6210
|
+
const hooksPath = codexHooksPath();
|
|
6211
|
+
let existingHooks = null;
|
|
6212
|
+
if (fs4.existsSync(hooksPath)) {
|
|
6213
|
+
try {
|
|
6214
|
+
existingHooks = JSON.parse(fs4.readFileSync(hooksPath, "utf-8"));
|
|
6215
|
+
} catch {
|
|
6216
|
+
warnings.push(`${hooksPath} was not valid JSON \u2014 leaving it; wire hooks manually if needed`);
|
|
6217
|
+
}
|
|
6218
|
+
}
|
|
6219
|
+
if (existingHooks !== null || !fs4.existsSync(hooksPath)) {
|
|
6220
|
+
const merged = mergeHooks(existingHooks, bundle);
|
|
6221
|
+
fs4.writeFileSync(hooksPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
6222
|
+
actions.push("hooks.json \u2190 SessionStart + Stop + UserPromptSubmit");
|
|
6223
|
+
}
|
|
6224
|
+
if (handle) {
|
|
6225
|
+
try {
|
|
6226
|
+
const agentsPath = path5.join(codexHome(), "AGENTS.md");
|
|
6227
|
+
const existing = fs4.existsSync(agentsPath) ? fs4.readFileSync(agentsPath, "utf-8") : "";
|
|
6228
|
+
const next = upsertAnchorBlock(existing, renderCodexAgents(handle));
|
|
6229
|
+
fs4.writeFileSync(agentsPath, next, "utf-8");
|
|
6230
|
+
if (!fs4.readFileSync(agentsPath, "utf-8").includes(`@${handle}`)) {
|
|
6231
|
+
throw new Error("handle did not land in AGENTS.md");
|
|
6232
|
+
}
|
|
6233
|
+
actions.push(`AGENTS.md \u2190 identity + etiquette (@${handle})`);
|
|
6234
|
+
} catch (err) {
|
|
6235
|
+
warnings.push(`AGENTS.md write failed: ${String(err)}`);
|
|
6236
|
+
}
|
|
6237
|
+
} else {
|
|
6238
|
+
warnings.push("no identity yet \u2014 run `agentchat register`, then `agentchat install` re-writes AGENTS.md");
|
|
6239
|
+
}
|
|
6240
|
+
log.debug(`codex install: ${actions.join("; ")}`);
|
|
6241
|
+
return { actions, warnings };
|
|
6242
|
+
}
|
|
6243
|
+
function removeCodex() {
|
|
6244
|
+
const removed = [];
|
|
6245
|
+
const cfgPath = codexConfigPath();
|
|
6246
|
+
if (fs4.existsSync(cfgPath)) {
|
|
6247
|
+
const stripped = stripTomlBlock(fs4.readFileSync(cfgPath, "utf-8"));
|
|
6248
|
+
fs4.writeFileSync(cfgPath, stripped, "utf-8");
|
|
6249
|
+
removed.push("config.toml [mcp_servers.agentchat]");
|
|
6250
|
+
}
|
|
6251
|
+
const hooksPath = codexHooksPath();
|
|
6252
|
+
if (fs4.existsSync(hooksPath)) {
|
|
6253
|
+
try {
|
|
6254
|
+
const next = unmergeHooks(JSON.parse(fs4.readFileSync(hooksPath, "utf-8")));
|
|
6255
|
+
if (next === null) fs4.unlinkSync(hooksPath);
|
|
6256
|
+
else fs4.writeFileSync(hooksPath, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
6257
|
+
removed.push("hooks.json entries");
|
|
6258
|
+
} catch {
|
|
6259
|
+
}
|
|
6260
|
+
}
|
|
6261
|
+
const anchor = removeAnchor("codex");
|
|
6262
|
+
if (anchor.action === "removed") removed.push("AGENTS.md anchor");
|
|
6263
|
+
return removed;
|
|
6264
|
+
}
|
|
6265
|
+
|
|
6011
6266
|
// src/commands/identity.ts
|
|
6012
6267
|
var HANDLE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
6013
6268
|
function describeApiError(err) {
|
|
@@ -6045,17 +6300,23 @@ async function prompt(question) {
|
|
|
6045
6300
|
var RESTART_HINT = "Restart your agent session (Claude Code: start a new session, or /mcp \u2192 reconnect) so the messaging tools pick up this identity.";
|
|
6046
6301
|
function autoAnchor(handle) {
|
|
6047
6302
|
const lines = [];
|
|
6048
|
-
const
|
|
6049
|
-
|
|
6050
|
-
const file = anchorFilePath(platform);
|
|
6051
|
-
if (file === null) continue;
|
|
6052
|
-
const hostDir = path4.dirname(file);
|
|
6053
|
-
if (!fs4.existsSync(hostDir)) continue;
|
|
6303
|
+
const ccFile = anchorFilePath("claude-code");
|
|
6304
|
+
if (ccFile !== null && fs5.existsSync(path6.dirname(ccFile))) {
|
|
6054
6305
|
try {
|
|
6055
|
-
|
|
6056
|
-
lines.push(` anchor
|
|
6306
|
+
installAnchor("claude-code", handle);
|
|
6307
|
+
lines.push(` anchor claude-code: written \u2192 ${ccFile}`);
|
|
6057
6308
|
} catch (err) {
|
|
6058
|
-
lines.push(` anchor
|
|
6309
|
+
lines.push(` anchor claude-code: FAILED \u2014 ${String(err)}`);
|
|
6310
|
+
}
|
|
6311
|
+
}
|
|
6312
|
+
const codexAgents = anchorFilePath("codex");
|
|
6313
|
+
if (codexAgents !== null && fs5.existsSync(codexAgents)) {
|
|
6314
|
+
try {
|
|
6315
|
+
const existing = fs5.readFileSync(codexAgents, "utf-8");
|
|
6316
|
+
fs5.writeFileSync(codexAgents, upsertAnchorBlock(existing, renderCodexAgents(handle)), "utf-8");
|
|
6317
|
+
lines.push(` AGENTS.md codex: refreshed \u2192 ${codexAgents}`);
|
|
6318
|
+
} catch (err) {
|
|
6319
|
+
lines.push(` AGENTS.md codex: FAILED \u2014 ${String(err)}`);
|
|
6059
6320
|
}
|
|
6060
6321
|
}
|
|
6061
6322
|
return lines;
|
|
@@ -6287,11 +6548,65 @@ async function runRecover(opts) {
|
|
|
6287
6548
|
return 1;
|
|
6288
6549
|
}
|
|
6289
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
|
+
];
|
|
6290
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) {
|
|
6291
6606
|
const identity = resolveIdentity();
|
|
6292
6607
|
const pending = readPending();
|
|
6293
6608
|
if (identity === null) {
|
|
6294
|
-
if (
|
|
6609
|
+
if (json) {
|
|
6295
6610
|
console.log(
|
|
6296
6611
|
JSON.stringify({ configured: false, pending: pending !== null, pending_kind: pending?.kind ?? null })
|
|
6297
6612
|
);
|
|
@@ -6304,7 +6619,7 @@ async function runStatus(opts) {
|
|
|
6304
6619
|
`No identity yet, but a registration for @${pending.handle ?? "?"} is waiting on its emailed code \u2014 finish with: agentchat register --code <code>`
|
|
6305
6620
|
);
|
|
6306
6621
|
} else {
|
|
6307
|
-
console.log("No AgentChat identity
|
|
6622
|
+
console.log("No AgentChat identity for this host. Set one up with: agentchat register");
|
|
6308
6623
|
}
|
|
6309
6624
|
return 0;
|
|
6310
6625
|
}
|
|
@@ -6320,7 +6635,7 @@ async function runStatus(opts) {
|
|
|
6320
6635
|
"claude-code": hasAnchor("claude-code"),
|
|
6321
6636
|
codex: hasAnchor("codex")
|
|
6322
6637
|
};
|
|
6323
|
-
if (
|
|
6638
|
+
if (json) {
|
|
6324
6639
|
console.log(
|
|
6325
6640
|
JSON.stringify({
|
|
6326
6641
|
configured: true,
|
|
@@ -6351,28 +6666,67 @@ async function runStatus(opts) {
|
|
|
6351
6666
|
}
|
|
6352
6667
|
}
|
|
6353
6668
|
function runLogout() {
|
|
6354
|
-
const
|
|
6669
|
+
const bound = (process.env["AGENTCHAT_HOME"] ?? "").trim().length > 0;
|
|
6355
6670
|
const reports = [];
|
|
6356
|
-
|
|
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;
|
|
6357
6697
|
try {
|
|
6358
|
-
|
|
6359
|
-
if (result.action === "removed") reports.push(` anchor ${platform}: removed`);
|
|
6698
|
+
removeAnchor("claude-code");
|
|
6360
6699
|
} catch {
|
|
6361
|
-
|
|
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;
|
|
6362
6718
|
}
|
|
6363
6719
|
}
|
|
6364
6720
|
console.log(
|
|
6365
|
-
[
|
|
6366
|
-
"\n"
|
|
6367
|
-
)
|
|
6721
|
+
[any ? "Signed out." : "Nothing to sign out of.", ...reports].join("\n")
|
|
6368
6722
|
);
|
|
6369
6723
|
return 0;
|
|
6370
6724
|
}
|
|
6371
6725
|
|
|
6372
6726
|
// src/commands/install.ts
|
|
6373
|
-
import * as
|
|
6727
|
+
import * as fs6 from "fs";
|
|
6374
6728
|
import * as os3 from "os";
|
|
6375
|
-
import * as
|
|
6729
|
+
import * as path7 from "path";
|
|
6376
6730
|
import { spawnSync } from "child_process";
|
|
6377
6731
|
var MARKETPLACE_SLUG = "agentchatme/agentchat-coding-agents";
|
|
6378
6732
|
var PLUGIN_REF = "agentchat@agentchatme";
|
|
@@ -6389,11 +6743,11 @@ function defaultRun(cmd, args) {
|
|
|
6389
6743
|
function binaryOnPath(binary, env) {
|
|
6390
6744
|
const pathVar = env["PATH"] ?? "";
|
|
6391
6745
|
const exts = process.platform === "win32" ? [".cmd", ".exe", ".bat", ""] : [""];
|
|
6392
|
-
for (const dir of pathVar.split(
|
|
6746
|
+
for (const dir of pathVar.split(path7.delimiter)) {
|
|
6393
6747
|
if (dir.length === 0) continue;
|
|
6394
6748
|
for (const ext of exts) {
|
|
6395
6749
|
try {
|
|
6396
|
-
if (
|
|
6750
|
+
if (fs6.existsSync(path7.join(dir, binary + ext))) return true;
|
|
6397
6751
|
} catch {
|
|
6398
6752
|
}
|
|
6399
6753
|
}
|
|
@@ -6402,7 +6756,7 @@ function binaryOnPath(binary, env) {
|
|
|
6402
6756
|
}
|
|
6403
6757
|
function detectPlatforms(env, home) {
|
|
6404
6758
|
return PROBES.filter(
|
|
6405
|
-
(p) => binaryOnPath(p.binary, env) ||
|
|
6759
|
+
(p) => binaryOnPath(p.binary, env) || fs6.existsSync(path7.join(home, p.configDir))
|
|
6406
6760
|
);
|
|
6407
6761
|
}
|
|
6408
6762
|
async function runInstall(deps = {}) {
|
|
@@ -6440,11 +6794,19 @@ async function runInstall(deps = {}) {
|
|
|
6440
6794
|
}
|
|
6441
6795
|
break;
|
|
6442
6796
|
}
|
|
6443
|
-
case "codex":
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6797
|
+
case "codex": {
|
|
6798
|
+
const bundleSrc = process.argv[1] ?? "";
|
|
6799
|
+
const handle = readCredentialsFileAt(codexIdentityHome())?.handle ?? null;
|
|
6800
|
+
try {
|
|
6801
|
+
const { actions, warnings } = installCodex(bundleSrc, handle);
|
|
6802
|
+
console.log(` Codex: wired \u2713 (${actions.join(", ") || "no changes"})`);
|
|
6803
|
+
for (const w of warnings) console.log(` \u26A0 ${w}`);
|
|
6804
|
+
} catch (err) {
|
|
6805
|
+
failures++;
|
|
6806
|
+
console.log(` Codex: wiring failed \u2014 ${String(err)}`);
|
|
6807
|
+
}
|
|
6447
6808
|
break;
|
|
6809
|
+
}
|
|
6448
6810
|
case "cursor":
|
|
6449
6811
|
console.log(
|
|
6450
6812
|
" Cursor: detected \u2014 the AgentChat Cursor packaging ships in the next release; this installer will wire it then."
|
|
@@ -6452,27 +6814,36 @@ async function runInstall(deps = {}) {
|
|
|
6452
6814
|
break;
|
|
6453
6815
|
}
|
|
6454
6816
|
}
|
|
6455
|
-
|
|
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) {
|
|
6456
6828
|
console.log(
|
|
6457
6829
|
[
|
|
6458
6830
|
"",
|
|
6459
|
-
|
|
6460
|
-
"
|
|
6461
|
-
|
|
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)."
|
|
6462
6835
|
].join("\n")
|
|
6463
6836
|
);
|
|
6464
|
-
} else {
|
|
6465
|
-
console.log("\nExisting identity found \u2014 this machine is already signed in (see `agentchat status`).");
|
|
6466
6837
|
}
|
|
6467
6838
|
return failures === 0 ? 0 : 1;
|
|
6468
6839
|
}
|
|
6469
6840
|
|
|
6470
6841
|
// src/commands/doctor.ts
|
|
6471
|
-
import * as
|
|
6472
|
-
import * as
|
|
6842
|
+
import * as fs7 from "fs";
|
|
6843
|
+
import * as path8 from "path";
|
|
6473
6844
|
|
|
6474
6845
|
// src/version.ts
|
|
6475
|
-
var VERSION2 = "0.0.
|
|
6846
|
+
var VERSION2 = "0.0.132";
|
|
6476
6847
|
|
|
6477
6848
|
// src/commands/doctor.ts
|
|
6478
6849
|
function fmt(check) {
|
|
@@ -6538,8 +6909,8 @@ async function runDoctor() {
|
|
|
6538
6909
|
for (const platform of ["claude-code", "codex"]) {
|
|
6539
6910
|
const file = anchorFilePath(platform);
|
|
6540
6911
|
if (file === null) continue;
|
|
6541
|
-
const hostDir =
|
|
6542
|
-
if (!
|
|
6912
|
+
const hostDir = path8.dirname(file);
|
|
6913
|
+
if (!fs7.existsSync(hostDir)) {
|
|
6543
6914
|
checks.push({ name: `anchor-${platform}`, verdict: "PASS", detail: `${hostDir} absent (host not installed) \u2014 skipped` });
|
|
6544
6915
|
} else {
|
|
6545
6916
|
checks.push({
|
|
@@ -6550,8 +6921,8 @@ async function runDoctor() {
|
|
|
6550
6921
|
}
|
|
6551
6922
|
}
|
|
6552
6923
|
try {
|
|
6553
|
-
|
|
6554
|
-
|
|
6924
|
+
fs7.mkdirSync(agentchatHome(), { recursive: true });
|
|
6925
|
+
fs7.accessSync(agentchatHome(), fs7.constants.W_OK);
|
|
6555
6926
|
checks.push({ name: "state", verdict: "PASS", detail: `${statePath()} writable` });
|
|
6556
6927
|
} catch {
|
|
6557
6928
|
checks.push({ name: "state", verdict: "FAIL", detail: `${agentchatHome()} is not writable` });
|
|
@@ -6640,6 +7011,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
6640
7011
|
return 0;
|
|
6641
7012
|
}
|
|
6642
7013
|
const requirePlatform = () => resolvePlatform(values.platform);
|
|
7014
|
+
if (values.platform !== void 0 && isPlatform(values.platform)) {
|
|
7015
|
+
bindHostHome(values.platform);
|
|
7016
|
+
}
|
|
6643
7017
|
switch (command) {
|
|
6644
7018
|
case "install":
|
|
6645
7019
|
return runInstall();
|