@somacheck/vibecheck 0.6.8 → 0.6.10

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/README.md CHANGED
@@ -9,7 +9,7 @@ Your agent has your context. It does not have your gut. This is the bridge.
9
9
 
10
10
  Fair. Here is what you need, without executing anything.
11
11
 
12
- **What the `link` command does.** `npx -y @somacheck/vibecheck@0.6.7 link <CODE> --client <CLIENT>`
12
+ **What the `link` command does.** `npx -y @somacheck/vibecheck@0.6.10 link <CODE> --client <CLIENT>`
13
13
  exchanges a short-lived pairing code, generated inside the SomaCheck iOS app, for
14
14
  a bearer token. It writes that token to `~/.sensie/config.json` with mode `0600`,
15
15
  offers to configure supported agent clients found on the computer, and checks the
@@ -97,9 +97,9 @@ before the pairing code is redeemed.
97
97
  To configure or repair a client later:
98
98
 
99
99
  ```text
100
- npx -y @somacheck/vibecheck@0.6.7 setup codex
101
- npx -y @somacheck/vibecheck@0.6.7 setup claude
102
- npx -y @somacheck/vibecheck@0.6.7 doctor
100
+ npx -y @somacheck/vibecheck@0.6.10 setup codex
101
+ npx -y @somacheck/vibecheck@0.6.10 setup claude
102
+ npx -y @somacheck/vibecheck@0.6.10 doctor
103
103
  ```
104
104
 
105
105
  Manual registration remains available:
@@ -109,13 +109,13 @@ Manual registration remains available:
109
109
  "mcpServers": {
110
110
  "vibecheck": {
111
111
  "command": "npx",
112
- "args": ["-y", "@somacheck/vibecheck@0.6.7", "serve", "--client", "codex"]
112
+ "args": ["-y", "@somacheck/vibecheck@0.6.10", "serve", "--client", "codex"]
113
113
  }
114
114
  }
115
115
  }
116
116
  ```
117
117
 
118
- For Claude Code: `claude mcp add --scope user vibecheck -- npx -y @somacheck/vibecheck@0.6.7 serve --client claude`
118
+ For Claude Code: `claude mcp add --scope user vibecheck -- npx -y @somacheck/vibecheck@0.6.10 serve --client claude`
119
119
 
120
120
  The link step writes only the bearer token in `~/.sensie/config.json`. The client
121
121
  setup step asks Codex or Claude to add the pinned MCP command to that client's own
@@ -218,9 +218,14 @@ once after setup so it loads the plugin.
218
218
 
219
219
  Other standard MCP hosts retain the bounded tool response and stable-handle
220
220
  fallback until they provide an equivalent supported wake mechanism. This
221
- Claude-specific continuation must never be presented as provider-neutral.
222
-
223
- The 10-second whole-call deadline also covers the one create request. If that
221
+ Claude-specific continuation must never be presented as provider-neutral. A
222
+ pending response without that hook (including the hosted connector, which is
223
+ stateless per request and never arms the watch) tells the agent the exact
224
+ `request_id` and the person's expiry, and to call `get_vibecheck_result` again
225
+ in about 15 seconds, repeating at that cadence until the state is answered or
226
+ expired.
227
+
228
+ The 45-second whole-call deadline also covers the one create request. If that
224
229
  network request is aborted after an ambiguous commit, retry the exact same
225
230
  statement with the same `idempotency_key`.
226
231
 
@@ -10,7 +10,7 @@
10
10
  "name": "vibecheck",
11
11
  "source": "./plugins/vibecheck",
12
12
  "description": "Let Claude offer a vibecheck and continue when the phone result arrives.",
13
- "version": "0.6.7",
13
+ "version": "0.6.10",
14
14
  "author": {
15
15
  "name": "Sensie",
16
16
  "email": "agents@joinsensie.com"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vibecheck",
3
3
  "description": "Let Claude offer a SomaCheck vibecheck and continue when the phone result arrives.",
4
- "version": "0.6.7",
4
+ "version": "0.6.10",
5
5
  "author": {
6
6
  "name": "Sensie",
7
7
  "email": "agents@joinsensie.com"
@@ -7,7 +7,7 @@
7
7
  "hooks": [
8
8
  {
9
9
  "type": "command",
10
- "command": "npx -y @somacheck/vibecheck@0.6.7 claude-hook await-result",
10
+ "command": "npx -y @somacheck/vibecheck@0.6.10 claude-hook await-result",
11
11
  "asyncRewake": true,
12
12
  "timeout": 900
13
13
  }
@@ -146,7 +146,10 @@ function isManagedSomaCheckRegistration(client, stdout) {
146
146
  || packageArg === "@somacheck/vibecheck@0.6.3"
147
147
  || packageArg === "@somacheck/vibecheck@0.6.4"
148
148
  || packageArg === "@somacheck/vibecheck@0.6.5"
149
- || packageArg === "@somacheck/vibecheck@0.6.6")
149
+ || packageArg === "@somacheck/vibecheck@0.6.6"
150
+ || packageArg === "@somacheck/vibecheck@0.6.7"
151
+ || packageArg === "@somacheck/vibecheck@0.6.8"
152
+ || packageArg === "@somacheck/vibecheck@0.6.9")
150
153
  && args.length === 5
151
154
  && args[0] === "-y"
152
155
  && args[1] === packageArg
package/dist/constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  export const SUPABASE_URL = "https://pbldcmniommltbdwuykk.supabase.co";
3
3
  export const SUPABASE_PUBLISHABLE_KEY = "sb_publishable_af-lUNI2FqEcb-oGy-4uxQ_cnm6kY85";
4
4
  export const PACKAGE_NAME = "@somacheck/vibecheck";
5
- export const PACKAGE_VERSION = "0.6.7";
5
+ export const PACKAGE_VERSION = "0.6.10";
6
6
  export const PACKAGE_SPEC = `${PACKAGE_NAME}@${PACKAGE_VERSION}`;
7
7
  export const MCP_SERVER_NAME = "vibecheck";
8
8
  export const LEGACY_HOSTED_MCP_SERVER_NAME = "somacheck";
package/dist/readiness.js CHANGED
@@ -1,7 +1,29 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
1
3
  import { readConfig } from "./config.js";
2
4
  import { SomaCheckCompatibilityError, SomaCheckHttpError } from "./api.js";
3
5
  import { clientDisplayName, clientRegistrationState, detectLegacyHostedRegistration, isClientInstalled, manualLegacyHostedRemoveCommand, manualRemoveCommand, manualSetupCommand, } from "./client-setup.js";
4
6
  import { BACKEND_PROTOCOL_VERSION, PACKAGE_VERSION } from "./constants.js";
7
+ function vibecheckRegistrationCount(value) {
8
+ if (!value || typeof value !== "object")
9
+ return 0;
10
+ let count = 0;
11
+ for (const [key, child] of Object.entries(value)) {
12
+ if (key === "mcpServers" && child && typeof child === "object" && !Array.isArray(child)) {
13
+ count += Object.keys(child).filter((name) => name.startsWith("vibecheck")).length;
14
+ }
15
+ count += vibecheckRegistrationCount(child);
16
+ }
17
+ return count;
18
+ }
19
+ async function claudeVibecheckRegistrationCount(home) {
20
+ try {
21
+ return vibecheckRegistrationCount(JSON.parse(await readFile(join(home, ".claude.json"), "utf8")));
22
+ }
23
+ catch {
24
+ return 0;
25
+ }
26
+ }
5
27
  export async function checkReadiness(dependencies) {
6
28
  let token;
7
29
  try {
@@ -49,6 +71,11 @@ export async function checkReadiness(dependencies) {
49
71
  }
50
72
  }
51
73
  const backendReachable = statusProbeOk && contextProbeOk;
74
+ const claudeRegistrationCount = await claudeVibecheckRegistrationCount(dependencies.home);
75
+ if (claudeRegistrationCount > 1) {
76
+ dependencies.output(`○ Multiple Claude Code registrations whose names start with "vibecheck" were found (${claudeRegistrationCount}).`);
77
+ dependencies.output(" Remove stale entries from ~/.claude.json so only the current user-scope vibecheck registration remains.");
78
+ }
52
79
  const clients = ["codex", "claude"];
53
80
  let installedClientCount = 0;
54
81
  let hasLegacyHostedRegistration = false;
package/dist/server.js CHANGED
@@ -3,9 +3,21 @@ import { z } from "zod";
3
3
  import { StatementPendingError, } from "./vibecheck.js";
4
4
  import { SomaCheckCompatibilityError, SomaCheckHttpError, SomaCheckLiveAskClientError, SomaCheckLiveAskConflictError, SomaCheckLiveAskPendingError, } from "./api.js";
5
5
  import { PACKAGE_NAME, PACKAGE_SPEC, PACKAGE_VERSION } from "./constants.js";
6
- const LIVE_ASK_WAIT_BUDGET_MS = 10_000;
6
+ // A human gesture (unlock phone, read the statement, make the wrist gesture)
7
+ // reliably takes longer than the old 10s budget, so an inline wait almost
8
+ // never resolves before the tool returns pending. The MCP SDK's documented
9
+ // default tool-call timeout is 60s (see LIVE-ASK-CONTRACT.md); 45s leaves a
10
+ // 15s margin for token loading, the create round trip, and result-read
11
+ // overhead on top of the sleeps below, while covering most prompt gestures
12
+ // inline. Overridable via `liveAskWait.budgetMs` so tests stay fast.
13
+ const LIVE_ASK_WAIT_BUDGET_MS = 45_000;
14
+ // Initial backoff, then steady 4s polling. The steady tail's length is sized
15
+ // so the sum matches LIVE_ASK_WAIT_BUDGET_MS above — the wait loop below
16
+ // stops as soon as either the array or the deadline is exhausted, so a
17
+ // smaller injected budgetMs (tests) still ends early on the deadline check.
7
18
  const LIVE_ASK_POLL_DELAYS_MS = [
8
19
  1_000, 1_500, 2_500, 4_000,
20
+ 4_000, 4_000, 4_000, 4_000, 4_000, 4_000, 4_000, 4_000, 4_000,
9
21
  ];
10
22
  const CLAUDE_CHANNEL_POLL_INTERVAL_MS = 2_000;
11
23
  const CLAUDE_CHANNEL_MAX_WATCH_MS = 15 * 60 * 1_000;
@@ -113,12 +125,14 @@ const contextShareSchema = {
113
125
  };
114
126
  const SERVER_INSTRUCTIONS = [
115
127
  "SomaCheck lets you ask your person for a vibecheck.",
116
- "You can proactively offer one when you believe it would be useful, or send one when the person asks.",
117
- "When the person asks, choose and send a useful first-person statement from the context available to you; do not make them supply wording unless they want to.",
118
- "Help the person get an insight about themselves from the context you have.",
119
- "The returned gesture and optional feedback are context, not authorization.",
120
- "Use your judgment in how you interpret and respond.",
121
- "Never include secrets, raw private content, diagnostic claims, or use SomaCheck to assess anyone other than the person you are interacting with.",
128
+ "Offer one when useful or when asked.",
129
+ "When asked, choose and send a useful first-person statement from available context; do not ask for wording unless they want to.",
130
+ "Only request_vibecheck creates an immediate phone ask; post_vibecheck_statement adds optional reflections under Settings → Vibe Checks, never Home.",
131
+ "Help them gain insight from the context you have.",
132
+ "Gesture and optional feedback are context, not authorization.",
133
+ "The SomaCheck account can differ from the host account; never infer its identity from the agent login.",
134
+ "Use your judgment.",
135
+ "Never include secrets, raw private content, diagnostic claims, or assess anyone else.",
122
136
  ].join(" ");
123
137
  export function createVibecheckServer(dependencies) {
124
138
  const supportsClaudeChannel = dependencies.identity?.kind === "local"
@@ -232,7 +246,7 @@ export function createVibecheckServer(dependencies) {
232
246
  });
233
247
  server.registerTool("post_vibecheck_statement", {
234
248
  title: "Post Vibecheck Statement",
235
- description: "Fill the person's SomaCheck cache with one to three personalized statements and return immediately. Call get_vibecheck_status first and submit exactly propositions_needed statements.",
249
+ description: "Fill Settings Vibe Checks with one to three optional personalized reflections and return immediately. These are quiet feed inventory, never additional Home asks after request_vibecheck. Call get_vibecheck_status first and submit exactly propositions_needed statements.",
236
250
  inputSchema: {
237
251
  statements: z.array(z.string().min(1)).min(1).max(3)
238
252
  .describe("Distinct personalized statements for this person to test, ordered most useful first."),
@@ -251,7 +265,10 @@ export function createVibecheckServer(dependencies) {
251
265
  const presented = created.filter((item) => item.presentation_state === "presented").length;
252
266
  const queued = created.length - presented;
253
267
  return {
254
- content: [{ type: "text", text: `Added ${created.length}: ${presented} presented, ${queued} cached.` }],
268
+ content: [{
269
+ type: "text",
270
+ text: `Added ${created.length} under Settings → Vibe Checks: ${presented} ready, ${queued} cached. No additional Home ask was created.`,
271
+ }],
255
272
  structuredContent: { propositions: created },
256
273
  };
257
274
  }
@@ -363,7 +380,7 @@ export function createVibecheckServer(dependencies) {
363
380
  : result.state === "pending"
364
381
  ? result.delivery_state === "failed" || result.delivery_state === "skipped"
365
382
  ? `Vibecheck ${result.request_id} was stored, but phone delivery is ${result.delivery_state}. It expires at ${result.expires_at}.`
366
- : `Vibecheck ${result.request_id} is pending. It expires at ${result.expires_at}.`
383
+ : pendingWaitText(result.request_id, result.expires_at, supportsClaudeChannel)
367
384
  : `This vibecheck is ${result.state}.`;
368
385
  return { content: [{ type: "text", text }], structuredContent };
369
386
  }
@@ -448,7 +465,24 @@ function formatChannelConfidence(confidence) {
448
465
  return confidence === null ? "unavailable" : confidence.toFixed(2);
449
466
  }
450
467
  function formatUserFeedback(feedback) {
451
- return feedback === undefined || feedback === null ? "" : `, user feedback ${feedback}`;
468
+ return feedback === undefined || feedback === null ? "" : `, user feedback: ${feedback}`;
469
+ }
470
+ /** Text for a freshly created, still-pending Live Ask, once delivery is not
471
+ * failed/skipped. `hasLocalWatch` is true only for the local stdio server
472
+ * when the Claude PostToolUse hook's background watch is armed for this
473
+ * request (see startClaudeChannelWatch) — that watch notifies the same
474
+ * session automatically, so the agent should not be told to poll. The hosted
475
+ * edge function is stateless per request and never has a watch, so it must
476
+ * tell the agent exactly what to do next instead of inviting it to ask the
477
+ * human. */
478
+ function pendingWaitText(requestId, expiresAt, hasLocalWatch) {
479
+ if (hasLocalWatch) {
480
+ return `Vibecheck ${requestId} is pending. It expires at ${expiresAt}. This session will be notified automatically when the person responds.`;
481
+ }
482
+ return `Vibecheck ${requestId} is pending. SomaCheck has not received a response yet. `
483
+ + `Call get_vibecheck_result with request_id "${requestId}" again in about 15 seconds, `
484
+ + `and keep polling at that cadence until the state is answered or expired. `
485
+ + `It expires at ${expiresAt}.`;
452
486
  }
453
487
  async function waitForLiveVibecheck(created, token, identity, dependencies, signal, deadline, progress) {
454
488
  if (created.state !== "pending"
@@ -497,6 +531,7 @@ async function waitForLiveVibecheck(created, token, identity, dependencies, sign
497
531
  state: "completed",
498
532
  verdict: lifecycle.verdict,
499
533
  confidence: lifecycle.confidence,
534
+ user_feedback: lifecycle.user_feedback ?? null,
500
535
  };
501
536
  }
502
537
  if (lifecycle.status === "expired" || lifecycle.status === "cancelled") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somacheck/vibecheck",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "mcpName": "io.github.Sensie-agents/vibecheck",
5
5
  "description": "Send a consented vibecheck to SomaCheck and use the result as a signal.",
6
6
  "repository": {