codiedev 0.9.32 → 0.9.33

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/cli.js CHANGED
@@ -228,9 +228,13 @@ codiedev inbox — show messages from teammates
228
228
  Usage:
229
229
  codiedev inbox [--unread] [--limit N]
230
230
 
231
- Lists pings with sender, subject artifact, and preview. Each row
231
+ Lists pings with sender, subject artifact, and preview. Each ping row
232
232
  shows a ping-id you can pass to 'codiedev read'.
233
233
 
234
+ Also lists feed posts and comments where a teammate @-mentioned you.
235
+ Those rows end in a portal link — the thread lives in the feed, so
236
+ read and reply to it there.
237
+
234
238
  Unread rows show as ● ; read rows as · .
235
239
 
236
240
  Examples:
@@ -1,2 +1,3 @@
1
- export declare function runInbox(args: string[]): Promise<void>;
1
+ import type { CodiedevConfig } from "../utils";
2
+ export declare function runInbox(args: string[], configOverride?: CodiedevConfig): Promise<void>;
2
3
  export declare function runRead(args: string[]): Promise<void>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runInbox = runInbox;
4
4
  exports.runRead = runRead;
5
5
  const shared_1 = require("./shared");
6
+ const inboxFormat_1 = require("../inboxFormat");
6
7
  function parseInboxArgs(args) {
7
8
  let unreadOnly = false;
8
9
  let limit;
@@ -23,9 +24,9 @@ function parseInboxArgs(args) {
23
24
  }
24
25
  return { unreadOnly, limit };
25
26
  }
26
- async function runInbox(args) {
27
+ async function runInbox(args, configOverride) {
27
28
  const { unreadOnly, limit } = parseInboxArgs(args);
28
- const config = (0, shared_1.requireConfig)();
29
+ const config = configOverride ?? (0, shared_1.requireConfig)();
29
30
  const start = Date.now();
30
31
  try {
31
32
  const res = await (0, shared_1.apiRequest)("GET", "/api/cli/inbox", {
@@ -40,26 +41,14 @@ async function runInbox(args) {
40
41
  ok: true,
41
42
  latencyMs: Date.now() - start,
42
43
  });
43
- const pings = res.pings;
44
- const unreadCount = pings.filter((p) => !p.readAt).length;
45
- if (pings.length === 0) {
46
- console.log(unreadOnly ? "No unread messages." : "Inbox is empty.");
47
- return;
48
- }
49
- console.log(`Inbox · ${pings.length} ${unreadOnly ? "unread" : "recent"}${unreadOnly ? "" : ` · ${unreadCount} unread`}`);
50
- console.log();
51
- for (const p of pings) {
52
- const dot = p.readAt ? "·" : "●";
53
- const from = p.from?.name ?? "unknown";
54
- const when = (0, shared_1.timeAgo)(p.createdAt);
55
- const where = p.subjectKey ? ` · on ${p.subjectKey}` : "";
56
- const preview = p.preview || "(no body)";
57
- console.log(`${dot} ${from}${where} · ${when}`);
58
- console.log(` ${preview}`);
59
- console.log(` id: ${p.pingId}`);
60
- console.log();
44
+ for (const line of (0, inboxFormat_1.formatInbox)({
45
+ pings: res.pings,
46
+ mentions: res.mentions,
47
+ unreadOnly,
48
+ limit,
49
+ })) {
50
+ console.log(line);
61
51
  }
62
- console.log(`Mark read: codiedev read <ping-id>`);
63
52
  }
64
53
  catch (err) {
65
54
  (0, shared_1.recordAgentEvent)(config, {
@@ -0,0 +1,38 @@
1
+ export interface InboxPing {
2
+ pingId: string;
3
+ createdAt: number;
4
+ readAt?: number;
5
+ from: {
6
+ name: string;
7
+ email: string;
8
+ } | null;
9
+ subjectKey: string | null;
10
+ subject: {
11
+ title?: string;
12
+ } | null;
13
+ preview: string;
14
+ }
15
+ export interface InboxMention {
16
+ mentionId: string;
17
+ createdAt: number;
18
+ readAt?: number | null;
19
+ from: {
20
+ name: string;
21
+ email: string;
22
+ } | null;
23
+ postTitle: string | null;
24
+ preview: string | null;
25
+ url: string | null;
26
+ }
27
+ /**
28
+ * Render the inbox for BOTH surfaces — `codiedev inbox` and the MCP
29
+ * `codiedev_inbox` tool an agent calls for "any messages?". Shared so the
30
+ * agent path can never drift back to pings-only while the human path shows
31
+ * mentions.
32
+ */
33
+ export declare function formatInbox(opts: {
34
+ pings: InboxPing[];
35
+ mentions?: InboxMention[];
36
+ unreadOnly: boolean;
37
+ limit?: number;
38
+ }): string[];
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatInbox = formatInbox;
4
+ const shared_1 = require("./commands/shared");
5
+ /**
6
+ * Render the inbox for BOTH surfaces — `codiedev inbox` and the MCP
7
+ * `codiedev_inbox` tool an agent calls for "any messages?". Shared so the
8
+ * agent path can never drift back to pings-only while the human path shows
9
+ * mentions.
10
+ */
11
+ function formatInbox(opts) {
12
+ const mentions = opts.mentions ?? [];
13
+ // The backend applies `limit` to each source independently, so asking for N
14
+ // can return up to 2N — and with no `--limit` it defaults to 50 per source,
15
+ // i.e. 100 rows, twice the pre-change maximum. Cap the COMBINED list by
16
+ // recency, always (matching the backend's own default), so the header is
17
+ // truthful and `--limit` actually holds.
18
+ //
19
+ // Selected by identity rather than by a `createdAt >= cutoff` filter: rows
20
+ // tied on the cutoff millisecond are reachable (Convex freezes Date.now()
21
+ // per transaction, and seeded activity carries synthetic stamps) and a
22
+ // threshold filter lets every tied row through, overshooting the limit.
23
+ const DEFAULT_LIMIT = 50;
24
+ const cap = opts.limit ?? DEFAULT_LIMIT;
25
+ // Pings claim the budget first, then mentions fill whatever is left — both
26
+ // newest-first. Before this change pings owned the whole budget, so this is
27
+ // purely additive and can never hide a ping that used to be visible. A flat
28
+ // recency cap would instead let a busy feed evict every direct ping, and
29
+ // pings are the actionable half: they carry the id you reply to, and losing
30
+ // them all takes the mark-read footer with them.
31
+ const byRecency = (xs) => [...xs].sort((a, b) => b.createdAt - a.createdAt);
32
+ const keptPings = byRecency(opts.pings).slice(0, cap);
33
+ const keptMentions = byRecency(mentions).slice(0, Math.max(0, cap - keptPings.length));
34
+ const total = keptPings.length + keptMentions.length;
35
+ if (total === 0) {
36
+ return [opts.unreadOnly ? "No unread messages." : "Inbox is empty."];
37
+ }
38
+ const unreadCount = keptPings.filter((p) => !p.readAt).length +
39
+ keptMentions.filter((m) => !m.readAt).length;
40
+ const lines = [
41
+ `Inbox · ${total} ${opts.unreadOnly ? "unread" : "recent"}${opts.unreadOnly ? "" : ` · ${unreadCount} unread`}`,
42
+ "",
43
+ ];
44
+ for (const p of keptPings) {
45
+ const dot = p.readAt ? "·" : "●";
46
+ const from = p.from?.name ?? "unknown";
47
+ const where = p.subjectKey ? ` · on ${p.subjectKey}` : "";
48
+ lines.push(`${dot} ${from}${where} · ${(0, shared_1.timeAgo)(p.createdAt)}`);
49
+ lines.push(` ${p.preview || "(no body)"}`);
50
+ lines.push(` id: ${p.pingId}`);
51
+ lines.push("");
52
+ }
53
+ // Mentions carry no CLI-side body to reply to — the thread lives in the feed
54
+ // — so each row ends in the deep link rather than an id.
55
+ for (const m of keptMentions) {
56
+ const dot = m.readAt ? "·" : "●";
57
+ const from = m.from?.name ?? "someone";
58
+ const where = m.postTitle ? ` · on “${m.postTitle}”` : "";
59
+ lines.push(`${dot} ${from} mentioned you${where} · ${(0, shared_1.timeAgo)(m.createdAt)}`);
60
+ if (m.preview)
61
+ lines.push(` ${m.preview}`);
62
+ if (m.url)
63
+ lines.push(` ${m.url}`);
64
+ lines.push("");
65
+ }
66
+ if (keptPings.length > 0)
67
+ lines.push("Mark read: codiedev read <ping-id>");
68
+ return lines;
69
+ }
package/dist/mcp.js CHANGED
@@ -51,6 +51,7 @@ const fs = __importStar(require("fs"));
51
51
  const path = __importStar(require("path"));
52
52
  const utils_1 = require("./utils");
53
53
  const shared_1 = require("./commands/shared");
54
+ const inboxFormat_1 = require("./inboxFormat");
54
55
  const PKG_NAME = "codiedev";
55
56
  // Read version from the bundled package.json so the startup log + tool reports
56
57
  // always reflect the actually-installed version, rather than a stale constant.
@@ -748,33 +749,16 @@ async function handleInbox(args, config) {
748
749
  config,
749
750
  query: { unreadOnly: unreadOnly ? "1" : undefined, limit },
750
751
  });
751
- if (res.pings.length === 0) {
752
- return {
753
- content: [
754
- {
755
- type: "text",
756
- text: unreadOnly ? "No unread messages." : "Inbox is empty.",
757
- },
758
- ],
759
- };
760
- }
761
- const unreadCount = res.pings.filter((p) => !p.readAt).length;
762
- const lines = [
763
- `Inbox · ${res.pings.length} ${unreadOnly ? "unread" : "recent"}${unreadOnly ? "" : ` · ${unreadCount} unread`}`,
764
- "",
765
- ];
766
- for (const p of res.pings) {
767
- const status = p.readAt ? "·" : "●";
768
- const from = p.from?.name ?? "unknown";
769
- const where = p.subjectKey ? ` · on ${p.subjectKey}` : "";
770
- lines.push(`${status} ${from}${where} · ${(0, shared_1.timeAgo)(p.createdAt)}`);
771
- lines.push(` ${p.preview || "(no body)"}`);
772
- lines.push(` id: ${p.pingId}`);
773
- lines.push("");
774
- }
775
- return {
776
- content: [{ type: "text", text: lines.join("\n") }],
777
- };
752
+ // Shared with `codiedev inbox` so this agent-facing path can never drift
753
+ // back to pings-only. CLAUDE.md routes "any messages?" here, so a
754
+ // mentions-blind version reproduces the bug for agents.
755
+ const text = (0, inboxFormat_1.formatInbox)({
756
+ pings: res.pings,
757
+ mentions: res.mentions,
758
+ unreadOnly,
759
+ limit,
760
+ }).join("\n");
761
+ return { content: [{ type: "text", text }] };
778
762
  }
779
763
  async function handleNote(args, config) {
780
764
  const body = asString(args.body);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.32",
3
+ "version": "0.9.33",
4
4
  "description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
5
5
  "bin": {
6
6
  "codiedev": "dist/cli.js",