slashvibe-mcp 0.8.8 → 0.8.9

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/auth-store.js CHANGED
@@ -61,13 +61,43 @@ function hydrate() {
61
61
  const config = require('./config');
62
62
  const cfg = config.load();
63
63
 
64
- _token = cfg.authToken || cfg.privyToken || null;
65
64
  _oneLiner = cfg.one_liner || cfg.workingOn || null;
66
65
 
67
- // Cross-client: if no token from config.json, check terminal/buddy auth.json
68
- if (!_token) {
69
- const terminalAuth = config.loadTerminalAuth();
70
- if (terminalAuth?.token) _token = terminalAuth.token;
66
+ // ONE IDENTITY, ONE AUTHORITY — and the authority is whichever credential still WORKS.
67
+ //
68
+ // This used to take cfg.authToken unconditionally and only look at auth.json when
69
+ // config.json had no token at all. So a machine holding a DEAD token in config.json
70
+ // and a LIVE one in auth.json hydrated with the dead one and reported
71
+ // isAuthenticated() === true. Reproduced before this change:
72
+ //
73
+ // hydrate chose: expired | isAuthenticated(): true
74
+ //
75
+ // Presence order is unchanged — config.json still wins when it is usable. What
76
+ // changed is that "present" is no longer mistaken for "usable". Falling back only on
77
+ // ABSENCE means the freshest credential loses to the first one on disk, which is
78
+ // precisely the "several credentials for one identity" failure canon law 3 exists to
79
+ // prevent (§4). With 30-day logins every machine eventually holds a stale one, so
80
+ // this is a matter of when, not whether.
81
+ //
82
+ // Deliberately local: inspectToken decodes `exp` rather than asking the server,
83
+ // because hydrate runs at boot where the network may be the broken thing. It cannot
84
+ // prove a token is GOOD — only the server can, and markVerified() records that later.
85
+ // It reliably rejects one that is definitively over.
86
+ const candidates = [
87
+ cfg.authToken,
88
+ cfg.privyToken,
89
+ config.loadTerminalAuth()?.token,
90
+ ].filter(Boolean);
91
+
92
+ _token = candidates.find((t) => inspectToken(t).ok) || null;
93
+
94
+ if (!_token && candidates.length > 0) {
95
+ // Every credential we hold is unusable. That is signed OUT, not signed in as the
96
+ // least-bad option — and it must be distinguishable from having none at all, so a
97
+ // remembered handle does not step in to name a session nothing backs (#110).
98
+ const why = inspectToken(candidates[0]).reason;
99
+ console.error(`[auth-store] No usable credential (${candidates.length} found, first is ${why})`);
100
+ _rejected = true;
71
101
  }
72
102
 
73
103
  // THE TOKEN IS THE IDENTITY.
package/index.js CHANGED
@@ -99,6 +99,24 @@ function inferPromptFromArgs(toolName, args) {
99
99
  }
100
100
  }
101
101
 
102
+ // TERMINAL ESCAPES ARE OPT-IN, and default to OFF.
103
+ //
104
+ // An MCP server CANNOT know what renders its output. These OSC sequences assume an
105
+ // iTerm-like terminal; every other client shows them as literal junk on the end of every
106
+ // tool result:
107
+ //
108
+ // ]0;vibe: 2 online · @pastelle]1337;SetBadgeFormat=4peL
109
+ //
110
+ // The comment that used to sit here claimed they were "invisible in the transcript".
111
+ // They are not — they were visible throughout a full working session in Claude Code, on
112
+ // every single vibe tool call. That is a claim about a state nobody verified, which is
113
+ // the exact defect class this codebase keeps paying for (canon law 2), and it is worse
114
+ // than usual here because the claim is what stopped anyone looking.
115
+ //
116
+ // Client-agnostic payloads are the rule. Someone on iTerm who wants a live title and
117
+ // badge can ask for it; nobody else should pay for it.
118
+ const TERM_ESCAPES = ['1', 'true'].includes(String(process.env.VIBE_TERM_ESCAPES || '').toLowerCase());
119
+
102
120
  // Generate terminal title escape sequence (OSC 0)
103
121
  function getTerminalTitle(onlineCount, unreadCount, lastActivity) {
104
122
  const parts = [];
@@ -235,9 +253,10 @@ async function getPresenceFooter() {
235
253
 
236
254
  // Terminal title + badge: ambient by nature, invisible in the transcript.
237
255
  const lastActivity = others.length > 0 ? `@${others[0].handle}` : null;
238
- const escapes =
239
- getTerminalTitle(onlineCount, unreadCount, lastActivity) +
240
- getBadgeSequence(onlineCount, unreadCount);
256
+ const escapes = TERM_ESCAPES
257
+ ? getTerminalTitle(onlineCount, unreadCount, lastActivity) +
258
+ getBadgeSequence(onlineCount, unreadCount)
259
+ : '';
241
260
 
242
261
  // The status line. Counts only — no mood inference, no nudges.
243
262
  const parts = ['vibe'];
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "slashvibe-mcp",
3
- "version": "0.8.8",
3
+ "version": "0.8.9",
4
4
  "mcpName": "io.github.vibecodinginc/vibe",
5
5
  "description": "Presence + messaging for terminal coding agents (Claude Code, Codex, Cursor) — the /vibe kernel",
6
6
  "main": "index.js",
7
7
  "bin": {
8
- "slashvibe-mcp": "./cli.js",
9
- "vibe-setup": "./setup.js"
8
+ "slashvibe-mcp": "cli.js",
9
+ "vibe-setup": "setup.js"
10
10
  },
11
11
  "scripts": {
12
12
  "start": "node index.js",
package/version.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
- "version": "0.8.8",
3
- "updated": "2026-08-01",
4
- "changelog": "A credential that names you is being signed in. A config could end up holding a perfectly good token and no username — and once that happened nothing put it back — so `vibe dm` answered \"Not initialized, run vibe init\" in the same breath as the footer showing who was online. One reply, two answers. Signing in now records whose token it is, so the file can never go anonymous.",
2
+ "version": "0.8.9",
3
+ "updated": "2026-08-02",
4
+ "changelog": "One machine can hold more than one saved /vibe credential. Until now the first token on disk won even when it had expired, stranding a working 30-day login in the other file. /vibe now chooses a credential that is still locally usable, reports signed out when every saved credential is expired, and keeps terminal-specific title and badge escapes off unless they are explicitly enabled.",
5
5
  "features": [
6
- "A valid credential counts as being signed in, no matter what the file says",
7
- "Signing in records the handle with the token, so it cannot be lost",
8
- "Sign-in fails with a clear message instead of a crash page when storage is down"
6
+ "A working saved credential wins over an expired credential in another config file",
7
+ "All expired credentials report signed out instead of impersonating a live session",
8
+ "Terminal title and badge escapes are opt-in with VIBE_TERM_ESCAPES=1"
9
9
  ],
10
10
  "deprecated": [],
11
11
  "breaking": false,