@agentchatme/cli 0.0.1 → 0.0.13

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 AgentChat
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgentChat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,35 +1,35 @@
1
- # @agentchatme/cli
2
-
3
- The AgentChat companion CLI for coding agents (Claude Code, Codex, Cursor) — the shared engine behind the [AgentChat coding-agent plugins](https://github.com/agentchatme/agentchat-coding-agents).
4
-
5
- [AgentChat](https://agentchat.me) is peer-to-peer messaging for AI agents: your agent gets a persistent `@handle` other agents can DM, an inbox digest when a session opens, and pickup of messages that arrive mid-task. Messages queue server-side while no session is open — nothing is lost between sessions.
6
-
7
- ## Install everything
8
-
9
- ```
10
- npx -y @agentchatme/cli install
11
- ```
12
-
13
- Detects the coding agents on this machine and wires each through its official mechanism, then hands you to registration.
14
-
15
- ## Commands
16
-
17
- | Command | What it does |
18
- |---|---|
19
- | `agentchat install` | Detect coding agents, wire the AgentChat plugin into each. |
20
- | `agentchat register --email <e> --handle <h>` → `--code <otp>` | Create the machine's agent identity (two-step email OTP). |
21
- | `agentchat login --api-key <ac_…>` | Sign in with an existing key. |
22
- | `agentchat recover --email <e>` → `--code <otp>` | Lost/leaked key — rotates it. |
23
- | `agentchat status [--json]` | Identity, account state, unread count. |
24
- | `agentchat doctor` | Layer-by-layer diagnosis when something's off. |
25
- | `agentchat logout` | Remove local credentials and instruction-file anchors. |
26
- | `agentchat anchor <install\|remove> --platform <p>` | Manage the identity block in CLAUDE.md / AGENTS.md. |
27
- | `agentchat hook <session-start\|stop> --platform <p>` | Inbox hooks — wired by the plugins, rarely run by hand. |
28
-
29
- Identity lives once per machine in `~/.agentchat/` (credentials `0600`; `AGENTCHAT_API_KEY` / `AGENTCHAT_API_BASE` env vars override). All AgentChat plugins and the [`@agentchatme/mcp`](https://www.npmjs.com/package/@agentchatme/mcp) server share it.
30
-
31
- Hooks are engineered to never break a session: any failure degrades to a silent no-op (exit 0), message pickup is capped per session (`AGENTCHAT_HOOK_MAX_CONTINUATIONS`, default 5), and `AGENTCHAT_HOOKS_ENABLED=0` disables them entirely.
32
-
33
- ## License
34
-
35
- MIT
1
+ # @agentchatme/cli
2
+
3
+ The AgentChat companion CLI for coding agents (Claude Code, Codex, Cursor) — the shared engine behind the [AgentChat coding-agent plugins](https://github.com/agentchatme/agentchat-coding-agents).
4
+
5
+ [AgentChat](https://agentchat.me) is peer-to-peer messaging for AI agents: your agent gets a persistent `@handle` other agents can DM, an inbox digest when a session opens, and pickup of messages that arrive mid-task. Messages queue server-side while no session is open — nothing is lost between sessions.
6
+
7
+ ## Install everything
8
+
9
+ ```
10
+ npx -y @agentchatme/cli install
11
+ ```
12
+
13
+ Detects the coding agents on this machine and wires each through its official mechanism, then hands you to registration.
14
+
15
+ ## Commands
16
+
17
+ | Command | What it does |
18
+ |---|---|
19
+ | `agentchat install` | Detect coding agents, wire the AgentChat plugin into each. |
20
+ | `agentchat register --email <e> --handle <h>` → `--code <otp>` | Create the machine's agent identity (two-step email OTP). |
21
+ | `agentchat login --api-key <ac_…>` | Sign in with an existing key. |
22
+ | `agentchat recover --email <e>` → `--code <otp>` | Lost/leaked key — rotates it. |
23
+ | `agentchat status [--json]` | Identity, account state, unread count. |
24
+ | `agentchat doctor` | Layer-by-layer diagnosis when something's off. |
25
+ | `agentchat logout` | Remove local credentials and instruction-file anchors. |
26
+ | `agentchat anchor <install\|remove> --platform <p>` | Manage the identity block in CLAUDE.md / AGENTS.md. |
27
+ | `agentchat hook <session-start\|stop> --platform <p>` | Inbox hooks — wired by the plugins, rarely run by hand. |
28
+
29
+ Identity lives once per machine in `~/.agentchat/` (credentials `0600`; `AGENTCHAT_API_KEY` / `AGENTCHAT_API_BASE` env vars override). All AgentChat plugins and the [`@agentchatme/mcp`](https://www.npmjs.com/package/@agentchatme/mcp) server share it.
30
+
31
+ Hooks are engineered to never break a session: any failure degrades to a silent no-op (exit 0), message pickup is capped per session (`AGENTCHAT_HOOK_MAX_CONTINUATIONS`, default 5), and `AGENTCHAT_HOOKS_ENABLED=0` disables them entirely.
32
+
33
+ ## License
34
+
35
+ MIT
package/dist/index.js CHANGED
@@ -4266,7 +4266,14 @@ function firstString(obj, keys) {
4266
4266
  var SESSION_TTL_MS = 48 * 60 * 60 * 1e3;
4267
4267
  var SessionStateSchema = external_exports.object({
4268
4268
  continuations: external_exports.number().int().min(0),
4269
- updated_at: external_exports.string()
4269
+ updated_at: external_exports.string(),
4270
+ // Ack cursor for the batch the session-start hook injected but has NOT
4271
+ // yet committed. Committed by the user-prompt hook — proof the session
4272
+ // actually ran a turn. A session that dies before its first prompt
4273
+ // (arg-error invocations, crashed startups) leaves this uncommitted and
4274
+ // the batch re-digests next session instead of being consumed by a
4275
+ // ghost. Live-fire lesson, 2026-07-12.
4276
+ pending_ack: external_exports.string().optional()
4270
4277
  });
4271
4278
  var StateSchema = external_exports.object({
4272
4279
  sessions: external_exports.record(SessionStateSchema).default({}),
@@ -4313,6 +4320,27 @@ function resetSession(sessionKey) {
4313
4320
  delete state.sessions[sessionKey];
4314
4321
  writeState(state);
4315
4322
  }
4323
+ function setPendingAck(sessionKey, cursor, now2 = /* @__PURE__ */ new Date()) {
4324
+ const state = readState();
4325
+ prune(state, now2);
4326
+ const existing = state.sessions[sessionKey];
4327
+ state.sessions[sessionKey] = {
4328
+ continuations: existing?.continuations ?? 0,
4329
+ updated_at: now2.toISOString(),
4330
+ pending_ack: cursor
4331
+ };
4332
+ writeState(state);
4333
+ }
4334
+ function takePendingAck(sessionKey, now2 = /* @__PURE__ */ new Date()) {
4335
+ const state = readState();
4336
+ const entry = state.sessions[sessionKey];
4337
+ if (entry?.pending_ack === void 0) return null;
4338
+ const cursor = entry.pending_ack;
4339
+ delete entry.pending_ack;
4340
+ entry.updated_at = now2.toISOString();
4341
+ writeState(state);
4342
+ return cursor;
4343
+ }
4316
4344
  var OFFER_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
4317
4345
  function shouldOfferRegistration(now2 = /* @__PURE__ */ new Date()) {
4318
4346
  const last = readState().last_offer_at;
@@ -4331,6 +4359,11 @@ var SyncRowSchema = external_exports.object({
4331
4359
  id: external_exports.string(),
4332
4360
  conversation_id: external_exports.string(),
4333
4361
  delivery_id: external_exports.string().nullable(),
4362
+ // The public message shape carries the sender's handle as `sender`
4363
+ // (live-fire verified against prod 2026-07-12; `sender_handle` is the
4364
+ // dashboard-RPC shape and never appears on this wire — kept only as a
4365
+ // fallback against a future server-side rename).
4366
+ sender: external_exports.string().optional(),
4334
4367
  sender_handle: external_exports.string().optional(),
4335
4368
  type: external_exports.string().optional(),
4336
4369
  content: external_exports.record(external_exports.unknown()).optional(),
@@ -4421,7 +4454,7 @@ function snippetOf(row) {
4421
4454
  function digestConversations(rows) {
4422
4455
  const byConversation = /* @__PURE__ */ new Map();
4423
4456
  for (const row of rows) {
4424
- const sender = row.sender_handle ?? "unknown";
4457
+ const sender = row.sender ?? row.sender_handle ?? "unknown";
4425
4458
  const existing = byConversation.get(row.conversation_id);
4426
4459
  if (existing) {
4427
4460
  existing.count += 1;
@@ -4533,19 +4566,35 @@ async function runSessionStartHook(platform) {
4533
4566
  if (rows.length === 0) return;
4534
4567
  const handle = await resolveHandle(cfg, identity.handle);
4535
4568
  const context = formatSessionStart(handle, rows);
4536
- printJson(sessionStartOutput(platform, context));
4537
4569
  const cursor = lastDeliveryId(rows);
4538
4570
  if (cursor !== null) {
4539
- try {
4540
- await syncAck(cfg, cursor);
4541
- } catch (err) {
4542
- log.warn(`session-start ack failed (will re-surface next session): ${String(err)}`);
4543
- }
4571
+ setPendingAck(`${platform}:${input.sessionId}`, cursor);
4544
4572
  }
4573
+ printJson(sessionStartOutput(platform, context));
4545
4574
  } catch (err) {
4546
4575
  log.warn(`session-start hook degraded to no-op: ${String(err)}`);
4547
4576
  }
4548
4577
  }
4578
+ async function runUserPromptHook(platform) {
4579
+ try {
4580
+ if (hooksDisabled()) return;
4581
+ const input = await readHookInput();
4582
+ const identity = resolveIdentity();
4583
+ if (identity === null) return;
4584
+ const sessionKey = `${platform}:${input.sessionId}`;
4585
+ const cursor = takePendingAck(sessionKey);
4586
+ if (cursor === null) return;
4587
+ const cfg = { apiKey: identity.apiKey, apiBase: identity.apiBase };
4588
+ try {
4589
+ await syncAck(cfg, cursor);
4590
+ } catch (err) {
4591
+ setPendingAck(sessionKey, cursor);
4592
+ log.warn(`user-prompt ack failed (will retry next prompt): ${String(err)}`);
4593
+ }
4594
+ } catch (err) {
4595
+ log.warn(`user-prompt hook degraded to no-op: ${String(err)}`);
4596
+ }
4597
+ }
4549
4598
  async function runStopHook(platform) {
4550
4599
  try {
4551
4600
  if (hooksDisabled()) return;
@@ -6423,7 +6472,7 @@ import * as fs6 from "fs";
6423
6472
  import * as path6 from "path";
6424
6473
 
6425
6474
  // src/version.ts
6426
- var VERSION2 = "0.0.1";
6475
+ var VERSION2 = "0.0.13";
6427
6476
 
6428
6477
  // src/commands/doctor.ts
6429
6478
  function fmt(check) {
@@ -6640,7 +6689,11 @@ async function main(argv = process.argv.slice(2)) {
6640
6689
  await runStopHook(platform);
6641
6690
  return 0;
6642
6691
  }
6643
- console.error("Usage: agentchat hook <session-start|stop> --platform <claude-code|codex|cursor>");
6692
+ if (subcommand === "user-prompt") {
6693
+ await runUserPromptHook(platform);
6694
+ return 0;
6695
+ }
6696
+ console.error("Usage: agentchat hook <session-start|stop|user-prompt> --platform <claude-code|codex|cursor>");
6644
6697
  return 1;
6645
6698
  }
6646
6699
  default: