@somacheck/vibecheck 0.6.11 → 0.6.12

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,13 +9,14 @@ 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.11 link <CODE> --client <CLIENT>`
12
+ **What the `link` command does.** `npx -y @somacheck/vibecheck@0.6.12 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
16
16
  connection without printing the token. For Claude Code it also installs an
17
- inspectable user-scoped SomaCheck plugin that can wake the same open session when
18
- the phone result arrives. Setup is not reported ready until the
17
+ inspectable user-scoped SomaCheck plugin and registers the local MCP server as
18
+ a Channel so a phone result can enter the same open conversation as a new
19
+ event. Setup is not reported ready until the
19
20
  selected client has the exact pinned `vibecheck` MCP registration, the backend
20
21
  accepts protocol `5` / toolset `vibecheck-0.6`, and both status and context
21
22
  probes succeed. It contacts exactly one network host: the Supabase project below.
@@ -97,9 +98,9 @@ before the pairing code is redeemed.
97
98
  To configure or repair a client later:
98
99
 
99
100
  ```text
100
- npx -y @somacheck/vibecheck@0.6.11 setup codex
101
- npx -y @somacheck/vibecheck@0.6.11 setup claude
102
- npx -y @somacheck/vibecheck@0.6.11 doctor
101
+ npx -y @somacheck/vibecheck@0.6.12 setup codex
102
+ npx -y @somacheck/vibecheck@0.6.12 setup claude
103
+ npx -y @somacheck/vibecheck@0.6.12 doctor
103
104
  ```
104
105
 
105
106
  Manual registration remains available:
@@ -109,13 +110,25 @@ Manual registration remains available:
109
110
  "mcpServers": {
110
111
  "vibecheck": {
111
112
  "command": "npx",
112
- "args": ["-y", "@somacheck/vibecheck@0.6.11", "serve", "--client", "codex"]
113
+ "args": ["-y", "@somacheck/vibecheck@0.6.12", "serve", "--client", "codex"]
113
114
  }
114
115
  }
115
116
  }
116
117
  ```
117
118
 
118
- For Claude Code: `claude mcp add --scope user vibecheck -- npx -y @somacheck/vibecheck@0.6.11 serve --client claude`
119
+ For Claude Code: `claude mcp add --scope user vibecheck -- npx -y @somacheck/vibecheck@0.6.12 serve --client claude --channel`
120
+
121
+ Claude Channels are currently an Anthropic research preview. Until Anthropic
122
+ approves SomaCheck on its channel allowlist, start Claude Code with:
123
+
124
+ ```text
125
+ claude --dangerously-load-development-channels server:vibecheck
126
+ ```
127
+
128
+ Keep that Claude Code session open. Channel events are queued while Claude is
129
+ busy, but a closed session cannot receive them. Claude does not acknowledge
130
+ channel notifications, so retain the stable `live:<uuid>` request handle as a
131
+ manual recovery path.
119
132
 
120
133
  The link step writes only the bearer token in `~/.sensie/config.json`. The client
121
134
  setup step asks Codex or Claude to add the pinned MCP command to that client's own
@@ -275,14 +288,22 @@ cancellation stops result reads and preserves the backend request and
275
288
  idempotency key, but the cancelled MCP transport may suppress that pending
276
289
  response.
277
290
 
278
- Standard MCP cannot start a new agent turn after a tool call has ended. The
279
- Claude setup therefore installs a normal user-scoped plugin with an async
280
- `PostToolUse` hook. When `request_vibecheck` returns pending, that hook follows
281
- only the exact request and wakes the same open Claude Code session when the
282
- answer, expiry, or cancellation arrives. It passes the constrained result and
283
- opaque handle, never the statement or link token, and cannot create another
284
- phone request. No experimental launch flag is required. Restart Claude Code
285
- once after setup so it loads the plugin.
291
+ Claude Code is the primary local experience. Its registered stdio server
292
+ advertises Anthropic's experimental Channel capability. When
293
+ `request_vibecheck` returns pending, the same local server follows only that
294
+ exact request and emits one `notifications/claude/channel` event when the
295
+ answer, expiry, or cancellation arrives. Claude receives the constrained
296
+ result as conversation input and can continue without another user message.
297
+ The event contains the binary reading, confidence, lifecycle, and opaque
298
+ handle—never the statement, link token, raw motion, or an instruction that
299
+ turns the result into authorization.
300
+
301
+ The installed `PostToolUse` hook remains a compatibility fallback for an
302
+ ordinary non-channel registration. A channel-armed response marks its
303
+ continuation transport explicitly, and the hook abstains, so two watchers
304
+ cannot wake the same turn. During Anthropic's research preview, the channel
305
+ session must be launched with the command above; a closed or non-enabled
306
+ session may silently drop the event.
286
307
 
287
308
  Other standard MCP hosts retain the bounded tool response and stable-handle
288
309
  fallback until they provide an equivalent supported wake mechanism. This
@@ -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.11",
13
+ "version": "0.6.12",
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.11",
4
+ "version": "0.6.12",
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.11 claude-hook await-result",
10
+ "command": "npx -y @somacheck/vibecheck@0.6.12 claude-hook await-result",
11
11
  "asyncRewake": true,
12
12
  "timeout": 900
13
13
  }
@@ -21,6 +21,10 @@ export function parsePendingClaudeAsk(input) {
21
21
  const structured = record(response.structuredContent ?? response.structured_content ?? response);
22
22
  if (structured.state !== "pending" || typeof structured.request_id !== "string")
23
23
  return null;
24
+ // The channel-enabled local server already owns this exact result watch.
25
+ // Abstaining prevents the PostToolUse fallback from waking Claude twice.
26
+ if (structured.continuation_transport === "claude_channel")
27
+ return null;
24
28
  if (structured.delivery_state === "failed" || structured.delivery_state === "skipped")
25
29
  return null;
26
30
  const requestId = parseHandle(structured.request_id);
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
3
3
  import { createInterface } from "node:readline/promises";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { SupabaseAgentApi } from "./api.js";
6
- import { clientDisplayName, detectInstalledClients, detectLegacyHostedRegistration, LocalCommandRunner, manualLegacyHostedRemoveCommand, manualRemoveCommand, manualSetupCommand, parseClientChoice, preflightClientPersistence, registerClient, singleNonInteractiveClientSelection, } from "./client-setup.js";
6
+ import { claudeChannelLaunchCommand, clientDisplayName, detectInstalledClients, detectLegacyHostedRegistration, LocalCommandRunner, manualLegacyHostedRemoveCommand, manualRemoveCommand, manualSetupCommand, parseClientChoice, preflightClientPersistence, registerClient, singleNonInteractiveClientSelection, } from "./client-setup.js";
7
7
  import { configureClaudeContinuationPlugin } from "./claude-plugin-setup.js";
8
8
  import { readConfig } from "./config.js";
9
9
  import { awaitClaudeVibecheckResult } from "./claude-hook.js";
@@ -11,6 +11,7 @@ import { PACKAGE_SPEC, SUPABASE_PUBLISHABLE_KEY, SUPABASE_URL } from "./constant
11
11
  import { LinkPersistenceError, NonInteractiveLinkError, linkAgent } from "./link.js";
12
12
  import { checkReadiness } from "./readiness.js";
13
13
  import { formatRecipeDetail, formatRecipeList, formatRecipePrompt, getRecipeExperience } from "./recipes.js";
14
+ import { parseRuntimeMode } from "./runtime-mode.js";
14
15
  import { createVibecheckServer } from "./server.js";
15
16
  const api = new SupabaseAgentApi(SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY);
16
17
  const runner = new LocalCommandRunner();
@@ -30,6 +31,7 @@ function usage() {
30
31
  " npx -y @somacheck/vibecheck recipes",
31
32
  " npx -y @somacheck/vibecheck recipes --id <id> --format prompt",
32
33
  " npx -y @somacheck/vibecheck recipe <id>",
34
+ " npx -y @somacheck/vibecheck serve --client claude --channel",
33
35
  ].join("\n");
34
36
  }
35
37
  function parseLinkClient(args) {
@@ -46,11 +48,6 @@ function parseLinkClient(args) {
46
48
  return [];
47
49
  throw new Error(usage());
48
50
  }
49
- function parseServeClient(args) {
50
- if (args.length !== 3 || args[0] !== "serve" || args[1] !== "--client")
51
- return null;
52
- return args[2] === "codex" || args[2] === "claude" ? args[2] : null;
53
- }
54
51
  async function promptForClients(installed) {
55
52
  if (installed.length === 0)
56
53
  return [];
@@ -105,6 +102,7 @@ async function configureClients(clients) {
105
102
  throw new ClientPreflightError("Could not configure automatic SomaCheck results for Claude Code. No pairing code was used.");
106
103
  }
107
104
  output(`✓ Automatic Claude result continuation ${plugin.status === "installed" ? "was configured" : "is ready"}.`);
105
+ output(` Start Claude Code with SomaCheck Channels: ${claudeChannelLaunchCommand()}`);
108
106
  }
109
107
  }
110
108
  }
@@ -180,6 +178,7 @@ async function preflightLinkClients(clients, interactive) {
180
178
  ].join("\n"));
181
179
  }
182
180
  output("✓ Automatic Claude result continuation is ready before redeeming the pairing code.");
181
+ output(` Start Claude Code with SomaCheck Channels: ${claudeChannelLaunchCommand()}`);
183
182
  }
184
183
  }
185
184
  return selectedClients;
@@ -201,13 +200,15 @@ async function refreshRuntimeHealth(client) {
201
200
  context_probe_ok: true,
202
201
  });
203
202
  }
204
- async function startServer(runtimeClient) {
203
+ async function startServer(runtime) {
204
+ const runtimeClient = runtime?.client ?? null;
205
205
  const server = createVibecheckServer({
206
206
  api,
207
207
  loadToken: async () => (await readConfig(homedir(), runtimeClient ?? undefined)).token,
208
208
  identity: runtimeClient === null
209
209
  ? { kind: "legacy" }
210
210
  : { kind: "local", client_key: runtimeClient },
211
+ ...(runtime?.claudeChannel ? { claudeChannelWatch: {} } : {}),
211
212
  });
212
213
  await server.connect(new StdioServerTransport());
213
214
  if (runtimeClient !== null) {
@@ -299,9 +300,9 @@ async function main() {
299
300
  throw new Error(usage());
300
301
  return (await runDoctor()) ? 0 : 2;
301
302
  }
302
- const runtimeClient = parseServeClient(args);
303
- if (runtimeClient !== null) {
304
- await startServer(runtimeClient);
303
+ const runtime = parseRuntimeMode(args);
304
+ if (runtime !== null) {
305
+ await startServer(runtime);
305
306
  return 0;
306
307
  }
307
308
  if (args.length !== 0)
@@ -26,7 +26,11 @@ export function clientDisplayName(client) {
26
26
  return client === "codex" ? "Codex / ChatGPT desktop" : "Claude Code";
27
27
  }
28
28
  function mcpServerArgs(client) {
29
- return ["-y", PACKAGE_SPEC, "serve", "--client", client];
29
+ const args = ["-y", PACKAGE_SPEC, "serve", "--client", client];
30
+ return client === "claude" ? [...args, "--channel"] : args;
31
+ }
32
+ export function claudeChannelLaunchCommand() {
33
+ return `claude --dangerously-load-development-channels server:${MCP_SERVER_NAME}`;
30
34
  }
31
35
  export function manualSetupCommand(client) {
32
36
  if (client === "codex") {
@@ -149,7 +153,9 @@ function isManagedSomaCheckRegistration(client, stdout) {
149
153
  || packageArg === "@somacheck/vibecheck@0.6.6"
150
154
  || packageArg === "@somacheck/vibecheck@0.6.7"
151
155
  || packageArg === "@somacheck/vibecheck@0.6.8"
152
- || packageArg === "@somacheck/vibecheck@0.6.9")
156
+ || packageArg === "@somacheck/vibecheck@0.6.9"
157
+ || packageArg === "@somacheck/vibecheck@0.6.10"
158
+ || packageArg === "@somacheck/vibecheck@0.6.11")
153
159
  && args.length === 5
154
160
  && args[0] === "-y"
155
161
  && 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.11";
5
+ export const PACKAGE_VERSION = "0.6.12";
6
6
  export const PACKAGE_SPEC = `${PACKAGE_NAME}@${PACKAGE_VERSION}`;
7
7
  export const SOMACHECK_SETUP_URL = "https://testflight.apple.com/join/C4mAH3zz";
8
8
  export const MCP_SERVER_NAME = "vibecheck";
@@ -0,0 +1,14 @@
1
+ /** Parse only the exact stdio runtime forms installed by this package.
2
+ * Claude Channels are local-only and must never be enabled for Codex. */
3
+ export function parseRuntimeMode(args) {
4
+ if (args[0] !== "serve" || args[1] !== "--client")
5
+ return null;
6
+ if (args.length === 3 && (args[2] === "codex" || args[2] === "claude")) {
7
+ return { client: args[2], claudeChannel: false };
8
+ }
9
+ if (args.length === 4 && args[2] === "claude" && args[3] === "--channel") {
10
+ return { client: "claude", claudeChannel: true };
11
+ }
12
+ return null;
13
+ }
14
+ //# sourceMappingURL=runtime-mode.js.map
package/dist/server.js CHANGED
@@ -105,6 +105,7 @@ const liveAskSchema = {
105
105
  delivery_state: z.enum(["queued", "processing", "sent", "failed", "skipped"]).nullable(),
106
106
  cooldown_until: z.string().datetime({ offset: true }).nullable(),
107
107
  error_code: liveAskErrorCodeSchema.nullable(),
108
+ continuation_transport: z.enum(["poll", "claude_channel"]).nullable().optional(),
108
109
  };
109
110
  const agentContextTypeSchema = z.enum([
110
111
  "goal", "project", "decision", "commitment", "tension", "question",
@@ -381,7 +382,15 @@ export function createVibecheckServer(dependencies) {
381
382
  });
382
383
  });
383
384
  startClaudeChannelWatch(result, token, identity);
384
- const structuredContent = { ...result, error_code: null };
385
+ const channelArmed = supportsClaudeChannel
386
+ && result.state === "pending"
387
+ && result.delivery_state !== "failed"
388
+ && result.delivery_state !== "skipped";
389
+ const structuredContent = {
390
+ ...result,
391
+ error_code: null,
392
+ ...(channelArmed ? { continuation_transport: "claude_channel" } : {}),
393
+ };
385
394
  const text = result.state === "completed"
386
395
  ? `Vibecheck completed: ${result.verdict}, confidence ${formatChannelConfidence(result.confidence)}${formatUserFeedback(result.user_feedback)}.`
387
396
  : result.state === "pending"
@@ -390,7 +399,7 @@ export function createVibecheckServer(dependencies) {
390
399
  + `Open SomaCheck on your phone, signed into the same account, and check Home. `
391
400
  + `If you do not have the app, install it at ${SOMACHECK_SETUP_URL} and finish phone setup. `
392
401
  + `Keep this request ID; do not create a duplicate or claim the phone received it. It expires at ${result.expires_at}.`
393
- : pendingWaitText(result.request_id, result.expires_at, supportsClaudeChannel)
402
+ : pendingWaitText(result.request_id, result.expires_at, channelArmed)
394
403
  : `This vibecheck is ${result.state}.`;
395
404
  return { content: [{ type: "text", text }], structuredContent };
396
405
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somacheck/vibecheck",
3
- "version": "0.6.11",
3
+ "version": "0.6.12",
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": {