@agentchatme/cli 0.0.136 → 0.0.137
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 +192 -149
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4554,6 +4554,9 @@ function formatStopPickup(handle, rows) {
|
|
|
4554
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)."
|
|
4555
4555
|
].join("\n");
|
|
4556
4556
|
}
|
|
4557
|
+
function formatAlwaysOnDown(platform) {
|
|
4558
|
+
return `\u26A0 Always-on is down \u2014 while you are away I won\u2019t be able to answer messages (they queue for your next session, nothing is lost). Turn it back on: \`agentchat daemon install --platform ${platform}\``;
|
|
4559
|
+
}
|
|
4557
4560
|
function formatRegistrationOffer(cliPath, platform) {
|
|
4558
4561
|
const invoke = cliPath ? `node "${cliPath}"` : "agentchat";
|
|
4559
4562
|
const p = platform ? ` --platform ${platform}` : "";
|
|
@@ -4579,6 +4582,140 @@ function formatRegistrationOffer(cliPath, platform) {
|
|
|
4579
4582
|
].join("\n");
|
|
4580
4583
|
}
|
|
4581
4584
|
|
|
4585
|
+
// src/commands/daemon.ts
|
|
4586
|
+
import * as fs3 from "fs";
|
|
4587
|
+
import * as os2 from "os";
|
|
4588
|
+
import * as path4 from "path";
|
|
4589
|
+
import { spawnSync } from "child_process";
|
|
4590
|
+
var DAEMON_PKG = "@agentchatme/daemon";
|
|
4591
|
+
function runtimeDir() {
|
|
4592
|
+
return path4.join(os2.homedir(), ".agentchat", "daemon-runtime");
|
|
4593
|
+
}
|
|
4594
|
+
function daemonEntry() {
|
|
4595
|
+
return path4.join(runtimeDir(), "node_modules", "@agentchatme", "daemon", "dist", "index.js");
|
|
4596
|
+
}
|
|
4597
|
+
var ALWAYS_ON_WANTED = "always-on.wanted";
|
|
4598
|
+
var HEARTBEAT_FILE = "daemon.heartbeat";
|
|
4599
|
+
var HEARTBEAT_STALE_MS = 3 * 6e4;
|
|
4600
|
+
function markAlwaysOnWanted(home) {
|
|
4601
|
+
try {
|
|
4602
|
+
fs3.mkdirSync(home, { recursive: true });
|
|
4603
|
+
fs3.writeFileSync(path4.join(home, ALWAYS_ON_WANTED), "");
|
|
4604
|
+
} catch {
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
function clearAlwaysOnWanted(home) {
|
|
4608
|
+
try {
|
|
4609
|
+
fs3.rmSync(path4.join(home, ALWAYS_ON_WANTED), { force: true });
|
|
4610
|
+
} catch {
|
|
4611
|
+
}
|
|
4612
|
+
}
|
|
4613
|
+
function alwaysOnHealth(home) {
|
|
4614
|
+
if (!fs3.existsSync(path4.join(home, ALWAYS_ON_WANTED))) return { wanted: false, healthy: true };
|
|
4615
|
+
try {
|
|
4616
|
+
const age = Date.now() - fs3.statSync(path4.join(home, HEARTBEAT_FILE)).mtimeMs;
|
|
4617
|
+
return { wanted: true, healthy: age <= HEARTBEAT_STALE_MS };
|
|
4618
|
+
} catch {
|
|
4619
|
+
return { wanted: true, healthy: false };
|
|
4620
|
+
}
|
|
4621
|
+
}
|
|
4622
|
+
function ensureDaemon() {
|
|
4623
|
+
if (fs3.existsSync(daemonEntry())) return { ok: true };
|
|
4624
|
+
const dir = runtimeDir();
|
|
4625
|
+
try {
|
|
4626
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
4627
|
+
} catch (err) {
|
|
4628
|
+
return { ok: false, detail: `could not create ${dir}: ${String(err)}` };
|
|
4629
|
+
}
|
|
4630
|
+
const r = spawnSync(
|
|
4631
|
+
"npm",
|
|
4632
|
+
["install", DAEMON_PKG, "--prefix", dir, "--no-save", "--no-audit", "--no-fund"],
|
|
4633
|
+
{ encoding: "utf-8", timeout: 18e4 }
|
|
4634
|
+
);
|
|
4635
|
+
if (r.error || r.status !== 0) {
|
|
4636
|
+
const why = (r.stderr || r.error && r.error.message || "unknown error").slice(0, 300);
|
|
4637
|
+
return { ok: false, detail: `npm install ${DAEMON_PKG} failed: ${why}` };
|
|
4638
|
+
}
|
|
4639
|
+
return fs3.existsSync(daemonEntry()) ? { ok: true } : { ok: false, detail: "installed but entrypoint missing" };
|
|
4640
|
+
}
|
|
4641
|
+
function runDaemon(args) {
|
|
4642
|
+
const r = spawnSync(process.execPath, [daemonEntry(), ...args], { stdio: "inherit" });
|
|
4643
|
+
return r.status ?? 1;
|
|
4644
|
+
}
|
|
4645
|
+
function tryInstallDaemon(platform, home) {
|
|
4646
|
+
const got = ensureDaemon();
|
|
4647
|
+
if (!got.ok) return { ok: false, detail: got.detail ?? "runtime fetch failed" };
|
|
4648
|
+
const r = spawnSync(
|
|
4649
|
+
process.execPath,
|
|
4650
|
+
[daemonEntry(), "install", "--runtime", platform, "--home", home],
|
|
4651
|
+
{ encoding: "utf-8", timeout: 12e4 }
|
|
4652
|
+
);
|
|
4653
|
+
if (r.error || r.status !== 0) {
|
|
4654
|
+
const raw = r.stderr || r.stdout || r.error?.message || "";
|
|
4655
|
+
return { ok: false, detail: raw.slice(0, 300).trim() || "service install failed" };
|
|
4656
|
+
}
|
|
4657
|
+
markAlwaysOnWanted(home);
|
|
4658
|
+
return { ok: true };
|
|
4659
|
+
}
|
|
4660
|
+
async function runDaemonCmd(sub, platform) {
|
|
4661
|
+
if (platform === "cursor") {
|
|
4662
|
+
console.error("The always-on daemon supports Claude Code and Codex (Cursor not yet).");
|
|
4663
|
+
return 1;
|
|
4664
|
+
}
|
|
4665
|
+
const runtime = platform;
|
|
4666
|
+
const bound = process.env["AGENTCHAT_HOME"]?.trim();
|
|
4667
|
+
const home = bound && bound.length > 0 ? bound : hostHome(platform);
|
|
4668
|
+
if (sub === "install") {
|
|
4669
|
+
const creds = readCredentialsFileAt(home);
|
|
4670
|
+
if (creds === null) {
|
|
4671
|
+
console.error(
|
|
4672
|
+
`No AgentChat identity for ${platform} yet. Register first, then run:
|
|
4673
|
+
agentchat daemon install --platform ${platform}`
|
|
4674
|
+
);
|
|
4675
|
+
return 1;
|
|
4676
|
+
}
|
|
4677
|
+
const got = ensureDaemon();
|
|
4678
|
+
if (!got.ok) {
|
|
4679
|
+
console.error(`Couldn't set up always-on automatically: ${got.detail}`);
|
|
4680
|
+
console.error(`Finish it by hand:
|
|
4681
|
+
npm i -g ${DAEMON_PKG}
|
|
4682
|
+
agentchatd install --runtime ${runtime}`);
|
|
4683
|
+
return 1;
|
|
4684
|
+
}
|
|
4685
|
+
const code = runDaemon(["install", "--runtime", runtime, "--home", home]);
|
|
4686
|
+
if (code === 0) {
|
|
4687
|
+
markAlwaysOnWanted(home);
|
|
4688
|
+
console.log(
|
|
4689
|
+
[
|
|
4690
|
+
"",
|
|
4691
|
+
`Always-on is ON for @${creds.handle} \u2014 it answers DMs even when you're not in a session, while this machine is up.`,
|
|
4692
|
+
`Want session-only instead? Turn it off any time: agentchat daemon disable --platform ${platform}`
|
|
4693
|
+
].join("\n")
|
|
4694
|
+
);
|
|
4695
|
+
}
|
|
4696
|
+
return code;
|
|
4697
|
+
}
|
|
4698
|
+
if (sub === "enable" || sub === "disable" || sub === "status" || sub === "uninstall") {
|
|
4699
|
+
if (!fs3.existsSync(daemonEntry())) {
|
|
4700
|
+
if (sub === "status") {
|
|
4701
|
+
console.log("Always-on: not installed (session-only). Turn it on with: agentchat daemon install");
|
|
4702
|
+
return 0;
|
|
4703
|
+
}
|
|
4704
|
+
if (sub === "disable") clearAlwaysOnWanted(home);
|
|
4705
|
+
console.error(`Always-on isn't set up yet. Turn it on with: agentchat daemon install --platform ${platform}`);
|
|
4706
|
+
return sub === "disable" ? 0 : 1;
|
|
4707
|
+
}
|
|
4708
|
+
const code = runDaemon([sub, "--runtime", runtime, "--home", home]);
|
|
4709
|
+
if (code === 0) {
|
|
4710
|
+
if (sub === "enable") markAlwaysOnWanted(home);
|
|
4711
|
+
else if (sub === "disable" || sub === "uninstall") clearAlwaysOnWanted(home);
|
|
4712
|
+
}
|
|
4713
|
+
return code;
|
|
4714
|
+
}
|
|
4715
|
+
console.error("Usage: agentchat daemon <install|enable|disable|status|uninstall> --platform <claude-code|codex>");
|
|
4716
|
+
return 1;
|
|
4717
|
+
}
|
|
4718
|
+
|
|
4582
4719
|
// src/commands/hook.ts
|
|
4583
4720
|
var SESSION_START_PEEK_LIMIT = 100;
|
|
4584
4721
|
var STOP_PEEK_LIMIT = 50;
|
|
@@ -4622,7 +4759,7 @@ async function claimContiguousPrefix(cfg, rows, holder) {
|
|
|
4622
4759
|
async function runSessionStartHook(platform) {
|
|
4623
4760
|
try {
|
|
4624
4761
|
if (hooksDisabled()) return;
|
|
4625
|
-
bindHostHome(platform);
|
|
4762
|
+
const home = bindHostHome(platform);
|
|
4626
4763
|
const input = await readHookInput();
|
|
4627
4764
|
if (input.source === "compact") return;
|
|
4628
4765
|
resetSession(`${platform}:${input.sessionId}`);
|
|
@@ -4636,12 +4773,19 @@ async function runSessionStartHook(platform) {
|
|
|
4636
4773
|
}
|
|
4637
4774
|
const cfg = { apiKey: identity.apiKey, apiBase: identity.apiBase };
|
|
4638
4775
|
await markSessionActive(cfg);
|
|
4776
|
+
const h = alwaysOnHealth(home);
|
|
4777
|
+
const alert = h.wanted && !h.healthy ? formatAlwaysOnDown(platform) : null;
|
|
4639
4778
|
const peeked = ackableRows(await syncPeek(cfg, { limit: SESSION_START_PEEK_LIMIT }));
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4779
|
+
const rows = peeked.length > 0 ? await claimContiguousPrefix(cfg, peeked, `session:${input.sessionId}`) : [];
|
|
4780
|
+
if (rows.length === 0) {
|
|
4781
|
+
if (alert !== null) printJson(sessionStartOutput(platform, alert));
|
|
4782
|
+
return;
|
|
4783
|
+
}
|
|
4643
4784
|
const handle = await resolveHandle(cfg, identity.handle);
|
|
4644
|
-
const
|
|
4785
|
+
const digest = formatSessionStart(handle, rows);
|
|
4786
|
+
const context = alert !== null ? `${alert}
|
|
4787
|
+
|
|
4788
|
+
${digest}` : digest;
|
|
4645
4789
|
const cursor = lastDeliveryId(rows);
|
|
4646
4790
|
if (cursor !== null) {
|
|
4647
4791
|
setPendingAck(`${platform}:${input.sessionId}`, cursor);
|
|
@@ -5979,9 +6123,9 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
5979
6123
|
var MAX_ATTACHMENT_SIZE = 25 * 1024 * 1024;
|
|
5980
6124
|
|
|
5981
6125
|
// src/lib/anchor.ts
|
|
5982
|
-
import * as
|
|
5983
|
-
import * as
|
|
5984
|
-
import * as
|
|
6126
|
+
import * as fs4 from "fs";
|
|
6127
|
+
import * as os3 from "os";
|
|
6128
|
+
import * as path5 from "path";
|
|
5985
6129
|
var ANCHOR_START = "<!-- agentchat:start -->";
|
|
5986
6130
|
var ANCHOR_END = "<!-- agentchat:end -->";
|
|
5987
6131
|
var LEGACY_ANCHOR_START = "<!-- agentchat-skill:start -->";
|
|
@@ -5989,9 +6133,9 @@ var LEGACY_ANCHOR_END = "<!-- agentchat-skill:end -->";
|
|
|
5989
6133
|
function anchorFilePath(platform) {
|
|
5990
6134
|
switch (platform) {
|
|
5991
6135
|
case "claude-code":
|
|
5992
|
-
return
|
|
6136
|
+
return path5.join(os3.homedir(), ".claude", "CLAUDE.md");
|
|
5993
6137
|
case "codex":
|
|
5994
|
-
return
|
|
6138
|
+
return path5.join(codexHome(), "AGENTS.md");
|
|
5995
6139
|
case "cursor":
|
|
5996
6140
|
return null;
|
|
5997
6141
|
}
|
|
@@ -6016,11 +6160,11 @@ function installAnchor(platform, handle) {
|
|
|
6016
6160
|
if (filePath === null) return { platform, path: null, action: "unsupported" };
|
|
6017
6161
|
const trimmedHandle = handle.trim();
|
|
6018
6162
|
if (!trimmedHandle) throw new Error("installAnchor: handle is empty");
|
|
6019
|
-
|
|
6020
|
-
const existing =
|
|
6163
|
+
fs4.mkdirSync(path5.dirname(filePath), { recursive: true });
|
|
6164
|
+
const existing = fs4.existsSync(filePath) ? fs4.readFileSync(filePath, "utf-8") : "";
|
|
6021
6165
|
const next = upsertAnchorBlock(existing, renderAnchorBlock(trimmedHandle));
|
|
6022
|
-
|
|
6023
|
-
const verify =
|
|
6166
|
+
fs4.writeFileSync(filePath, next, "utf-8");
|
|
6167
|
+
const verify = fs4.readFileSync(filePath, "utf-8");
|
|
6024
6168
|
if (!verify.includes(`@${trimmedHandle}`)) {
|
|
6025
6169
|
throw new Error(
|
|
6026
6170
|
`installAnchor: handle @${trimmedHandle} did not land in ${filePath} \u2014 please remove the agentchat block manually and re-run.`
|
|
@@ -6031,17 +6175,17 @@ function installAnchor(platform, handle) {
|
|
|
6031
6175
|
function removeAnchor(platform) {
|
|
6032
6176
|
const filePath = anchorFilePath(platform);
|
|
6033
6177
|
if (filePath === null) return { platform, path: null, action: "unsupported" };
|
|
6034
|
-
if (!
|
|
6035
|
-
const existing =
|
|
6178
|
+
if (!fs4.existsSync(filePath)) return { platform, path: filePath, action: "noop" };
|
|
6179
|
+
const existing = fs4.readFileSync(filePath, "utf-8");
|
|
6036
6180
|
const next = stripAnchorBlock(existing);
|
|
6037
6181
|
if (next === existing) return { platform, path: filePath, action: "noop" };
|
|
6038
|
-
|
|
6182
|
+
fs4.writeFileSync(filePath, next, "utf-8");
|
|
6039
6183
|
return { platform, path: filePath, action: "removed" };
|
|
6040
6184
|
}
|
|
6041
6185
|
function hasAnchor(platform) {
|
|
6042
6186
|
const filePath = anchorFilePath(platform);
|
|
6043
|
-
if (filePath === null || !
|
|
6044
|
-
const content =
|
|
6187
|
+
if (filePath === null || !fs4.existsSync(filePath)) return false;
|
|
6188
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
6045
6189
|
return findBlock(content, ANCHOR_START, ANCHOR_END) !== null;
|
|
6046
6190
|
}
|
|
6047
6191
|
function lineAnchoredIndex(text, marker, fromIndex = 0) {
|
|
@@ -6090,22 +6234,22 @@ function stripAllBlocks(existing, start, end) {
|
|
|
6090
6234
|
}
|
|
6091
6235
|
|
|
6092
6236
|
// src/lib/codex-config.ts
|
|
6093
|
-
import * as
|
|
6094
|
-
import * as
|
|
6237
|
+
import * as fs5 from "fs";
|
|
6238
|
+
import * as path6 from "path";
|
|
6095
6239
|
var TOML_START = "# agentchat:start";
|
|
6096
6240
|
var TOML_END = "# agentchat:end";
|
|
6097
|
-
var BUNDLE_REL =
|
|
6241
|
+
var BUNDLE_REL = path6.join("bin", "agentchat.mjs");
|
|
6098
6242
|
function codexConfigPath() {
|
|
6099
|
-
return
|
|
6243
|
+
return path6.join(codexHome(), "config.toml");
|
|
6100
6244
|
}
|
|
6101
6245
|
function codexHooksPath() {
|
|
6102
|
-
return
|
|
6246
|
+
return path6.join(codexHome(), "hooks.json");
|
|
6103
6247
|
}
|
|
6104
6248
|
function codexIdentityHome() {
|
|
6105
6249
|
return hostHome("codex");
|
|
6106
6250
|
}
|
|
6107
6251
|
function stableBundlePath() {
|
|
6108
|
-
return
|
|
6252
|
+
return path6.join(codexIdentityHome(), BUNDLE_REL);
|
|
6109
6253
|
}
|
|
6110
6254
|
function renderCodexAgents(handle) {
|
|
6111
6255
|
return [
|
|
@@ -6219,17 +6363,17 @@ function unmergeHooks(existing) {
|
|
|
6219
6363
|
}
|
|
6220
6364
|
function copyBundle(bundleSrc) {
|
|
6221
6365
|
const dest = stableBundlePath();
|
|
6222
|
-
|
|
6223
|
-
const srcResolved =
|
|
6224
|
-
if (srcResolved !==
|
|
6225
|
-
|
|
6366
|
+
fs5.mkdirSync(path6.dirname(dest), { recursive: true });
|
|
6367
|
+
const srcResolved = path6.resolve(bundleSrc);
|
|
6368
|
+
if (srcResolved !== path6.resolve(dest)) {
|
|
6369
|
+
fs5.copyFileSync(srcResolved, dest);
|
|
6226
6370
|
}
|
|
6227
6371
|
return dest;
|
|
6228
6372
|
}
|
|
6229
6373
|
function installCodex(bundleSrc, handle) {
|
|
6230
6374
|
const actions = [];
|
|
6231
6375
|
const warnings = [];
|
|
6232
|
-
|
|
6376
|
+
fs5.mkdirSync(codexHome(), { recursive: true });
|
|
6233
6377
|
let bundle;
|
|
6234
6378
|
try {
|
|
6235
6379
|
bundle = copyBundle(bundleSrc);
|
|
@@ -6241,36 +6385,36 @@ function installCodex(bundleSrc, handle) {
|
|
|
6241
6385
|
);
|
|
6242
6386
|
}
|
|
6243
6387
|
const cfgPath = codexConfigPath();
|
|
6244
|
-
const existingCfg =
|
|
6388
|
+
const existingCfg = fs5.existsSync(cfgPath) ? fs5.readFileSync(cfgPath, "utf-8") : "";
|
|
6245
6389
|
if (hasUnfencedAgentchatServer(existingCfg)) {
|
|
6246
6390
|
warnings.push(
|
|
6247
6391
|
`${cfgPath} already defines [mcp_servers.agentchat] outside our block \u2014 left it untouched; remove it and re-run if it isn't ours`
|
|
6248
6392
|
);
|
|
6249
6393
|
} else {
|
|
6250
|
-
|
|
6394
|
+
fs5.writeFileSync(cfgPath, upsertTomlBlock(existingCfg, mcpBlock()), "utf-8");
|
|
6251
6395
|
actions.push(`config.toml \u2190 [mcp_servers.agentchat]`);
|
|
6252
6396
|
}
|
|
6253
6397
|
const hooksPath = codexHooksPath();
|
|
6254
6398
|
let existingHooks = null;
|
|
6255
|
-
if (
|
|
6399
|
+
if (fs5.existsSync(hooksPath)) {
|
|
6256
6400
|
try {
|
|
6257
|
-
existingHooks = JSON.parse(
|
|
6401
|
+
existingHooks = JSON.parse(fs5.readFileSync(hooksPath, "utf-8"));
|
|
6258
6402
|
} catch {
|
|
6259
6403
|
warnings.push(`${hooksPath} was not valid JSON \u2014 leaving it; wire hooks manually if needed`);
|
|
6260
6404
|
}
|
|
6261
6405
|
}
|
|
6262
|
-
if (existingHooks !== null || !
|
|
6406
|
+
if (existingHooks !== null || !fs5.existsSync(hooksPath)) {
|
|
6263
6407
|
const merged = mergeHooks(existingHooks, bundle);
|
|
6264
|
-
|
|
6408
|
+
fs5.writeFileSync(hooksPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
6265
6409
|
actions.push("hooks.json \u2190 SessionStart + Stop + UserPromptSubmit");
|
|
6266
6410
|
}
|
|
6267
6411
|
if (handle) {
|
|
6268
6412
|
try {
|
|
6269
|
-
const agentsPath =
|
|
6270
|
-
const existing =
|
|
6413
|
+
const agentsPath = path6.join(codexHome(), "AGENTS.md");
|
|
6414
|
+
const existing = fs5.existsSync(agentsPath) ? fs5.readFileSync(agentsPath, "utf-8") : "";
|
|
6271
6415
|
const next = upsertAnchorBlock(existing, renderCodexAgents(handle));
|
|
6272
|
-
|
|
6273
|
-
if (!
|
|
6416
|
+
fs5.writeFileSync(agentsPath, next, "utf-8");
|
|
6417
|
+
if (!fs5.readFileSync(agentsPath, "utf-8").includes(`@${handle}`)) {
|
|
6274
6418
|
throw new Error("handle did not land in AGENTS.md");
|
|
6275
6419
|
}
|
|
6276
6420
|
actions.push(`AGENTS.md \u2190 identity + etiquette (@${handle})`);
|
|
@@ -6286,17 +6430,17 @@ function installCodex(bundleSrc, handle) {
|
|
|
6286
6430
|
function removeCodex() {
|
|
6287
6431
|
const removed = [];
|
|
6288
6432
|
const cfgPath = codexConfigPath();
|
|
6289
|
-
if (
|
|
6290
|
-
const stripped = stripTomlBlock(
|
|
6291
|
-
|
|
6433
|
+
if (fs5.existsSync(cfgPath)) {
|
|
6434
|
+
const stripped = stripTomlBlock(fs5.readFileSync(cfgPath, "utf-8"));
|
|
6435
|
+
fs5.writeFileSync(cfgPath, stripped, "utf-8");
|
|
6292
6436
|
removed.push("config.toml [mcp_servers.agentchat]");
|
|
6293
6437
|
}
|
|
6294
6438
|
const hooksPath = codexHooksPath();
|
|
6295
|
-
if (
|
|
6439
|
+
if (fs5.existsSync(hooksPath)) {
|
|
6296
6440
|
try {
|
|
6297
|
-
const next = unmergeHooks(JSON.parse(
|
|
6298
|
-
if (next === null)
|
|
6299
|
-
else
|
|
6441
|
+
const next = unmergeHooks(JSON.parse(fs5.readFileSync(hooksPath, "utf-8")));
|
|
6442
|
+
if (next === null) fs5.unlinkSync(hooksPath);
|
|
6443
|
+
else fs5.writeFileSync(hooksPath, JSON.stringify(next, null, 2) + "\n", "utf-8");
|
|
6300
6444
|
removed.push("hooks.json entries");
|
|
6301
6445
|
} catch {
|
|
6302
6446
|
}
|
|
@@ -6306,107 +6450,6 @@ function removeCodex() {
|
|
|
6306
6450
|
return removed;
|
|
6307
6451
|
}
|
|
6308
6452
|
|
|
6309
|
-
// src/commands/daemon.ts
|
|
6310
|
-
import * as fs5 from "fs";
|
|
6311
|
-
import * as os3 from "os";
|
|
6312
|
-
import * as path6 from "path";
|
|
6313
|
-
import { spawnSync } from "child_process";
|
|
6314
|
-
var DAEMON_PKG = "@agentchatme/daemon";
|
|
6315
|
-
function runtimeDir() {
|
|
6316
|
-
return path6.join(os3.homedir(), ".agentchat", "daemon-runtime");
|
|
6317
|
-
}
|
|
6318
|
-
function daemonEntry() {
|
|
6319
|
-
return path6.join(runtimeDir(), "node_modules", "@agentchatme", "daemon", "dist", "index.js");
|
|
6320
|
-
}
|
|
6321
|
-
function ensureDaemon() {
|
|
6322
|
-
if (fs5.existsSync(daemonEntry())) return { ok: true };
|
|
6323
|
-
const dir = runtimeDir();
|
|
6324
|
-
try {
|
|
6325
|
-
fs5.mkdirSync(dir, { recursive: true });
|
|
6326
|
-
} catch (err) {
|
|
6327
|
-
return { ok: false, detail: `could not create ${dir}: ${String(err)}` };
|
|
6328
|
-
}
|
|
6329
|
-
const r = spawnSync(
|
|
6330
|
-
"npm",
|
|
6331
|
-
["install", DAEMON_PKG, "--prefix", dir, "--no-save", "--no-audit", "--no-fund"],
|
|
6332
|
-
{ encoding: "utf-8", timeout: 18e4 }
|
|
6333
|
-
);
|
|
6334
|
-
if (r.error || r.status !== 0) {
|
|
6335
|
-
const why = (r.stderr || r.error && r.error.message || "unknown error").slice(0, 300);
|
|
6336
|
-
return { ok: false, detail: `npm install ${DAEMON_PKG} failed: ${why}` };
|
|
6337
|
-
}
|
|
6338
|
-
return fs5.existsSync(daemonEntry()) ? { ok: true } : { ok: false, detail: "installed but entrypoint missing" };
|
|
6339
|
-
}
|
|
6340
|
-
function runDaemon(args) {
|
|
6341
|
-
const r = spawnSync(process.execPath, [daemonEntry(), ...args], { stdio: "inherit" });
|
|
6342
|
-
return r.status ?? 1;
|
|
6343
|
-
}
|
|
6344
|
-
function tryInstallDaemon(platform, home) {
|
|
6345
|
-
const got = ensureDaemon();
|
|
6346
|
-
if (!got.ok) return { ok: false, detail: got.detail ?? "runtime fetch failed" };
|
|
6347
|
-
const r = spawnSync(
|
|
6348
|
-
process.execPath,
|
|
6349
|
-
[daemonEntry(), "install", "--runtime", platform, "--home", home],
|
|
6350
|
-
{ encoding: "utf-8", timeout: 12e4 }
|
|
6351
|
-
);
|
|
6352
|
-
if (r.error || r.status !== 0) {
|
|
6353
|
-
const raw = r.stderr || r.stdout || r.error?.message || "";
|
|
6354
|
-
return { ok: false, detail: raw.slice(0, 300).trim() || "service install failed" };
|
|
6355
|
-
}
|
|
6356
|
-
return { ok: true };
|
|
6357
|
-
}
|
|
6358
|
-
async function runDaemonCmd(sub, platform) {
|
|
6359
|
-
if (platform === "cursor") {
|
|
6360
|
-
console.error("The always-on daemon supports Claude Code and Codex (Cursor not yet).");
|
|
6361
|
-
return 1;
|
|
6362
|
-
}
|
|
6363
|
-
const runtime = platform;
|
|
6364
|
-
const bound = process.env["AGENTCHAT_HOME"]?.trim();
|
|
6365
|
-
const home = bound && bound.length > 0 ? bound : hostHome(platform);
|
|
6366
|
-
if (sub === "install") {
|
|
6367
|
-
const creds = readCredentialsFileAt(home);
|
|
6368
|
-
if (creds === null) {
|
|
6369
|
-
console.error(
|
|
6370
|
-
`No AgentChat identity for ${platform} yet. Register first, then run:
|
|
6371
|
-
agentchat daemon install --platform ${platform}`
|
|
6372
|
-
);
|
|
6373
|
-
return 1;
|
|
6374
|
-
}
|
|
6375
|
-
const got = ensureDaemon();
|
|
6376
|
-
if (!got.ok) {
|
|
6377
|
-
console.error(`Couldn't set up always-on automatically: ${got.detail}`);
|
|
6378
|
-
console.error(`Finish it by hand:
|
|
6379
|
-
npm i -g ${DAEMON_PKG}
|
|
6380
|
-
agentchatd install --runtime ${runtime}`);
|
|
6381
|
-
return 1;
|
|
6382
|
-
}
|
|
6383
|
-
const code = runDaemon(["install", "--runtime", runtime, "--home", home]);
|
|
6384
|
-
if (code === 0) {
|
|
6385
|
-
console.log(
|
|
6386
|
-
[
|
|
6387
|
-
"",
|
|
6388
|
-
`Always-on is ON for @${creds.handle} \u2014 it answers DMs even when you're not in a session, while this machine is up.`,
|
|
6389
|
-
`Want session-only instead? Turn it off any time: agentchat daemon disable --platform ${platform}`
|
|
6390
|
-
].join("\n")
|
|
6391
|
-
);
|
|
6392
|
-
}
|
|
6393
|
-
return code;
|
|
6394
|
-
}
|
|
6395
|
-
if (sub === "enable" || sub === "disable" || sub === "status" || sub === "uninstall") {
|
|
6396
|
-
if (!fs5.existsSync(daemonEntry())) {
|
|
6397
|
-
if (sub === "status") {
|
|
6398
|
-
console.log("Always-on: not installed (session-only). Turn it on with: agentchat daemon install");
|
|
6399
|
-
return 0;
|
|
6400
|
-
}
|
|
6401
|
-
console.error(`Always-on isn't set up yet. Turn it on with: agentchat daemon install --platform ${platform}`);
|
|
6402
|
-
return sub === "disable" ? 0 : 1;
|
|
6403
|
-
}
|
|
6404
|
-
return runDaemon([sub, "--runtime", runtime, "--home", home]);
|
|
6405
|
-
}
|
|
6406
|
-
console.error("Usage: agentchat daemon <install|enable|disable|status|uninstall> --platform <claude-code|codex>");
|
|
6407
|
-
return 1;
|
|
6408
|
-
}
|
|
6409
|
-
|
|
6410
6453
|
// src/commands/identity.ts
|
|
6411
6454
|
var HANDLE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
6412
6455
|
function describeApiError(err) {
|
|
@@ -7014,7 +7057,7 @@ import * as fs8 from "fs";
|
|
|
7014
7057
|
import * as path9 from "path";
|
|
7015
7058
|
|
|
7016
7059
|
// src/version.ts
|
|
7017
|
-
var VERSION2 = "0.0.
|
|
7060
|
+
var VERSION2 = "0.0.137";
|
|
7018
7061
|
|
|
7019
7062
|
// src/commands/doctor.ts
|
|
7020
7063
|
function fmt(check) {
|