switchroom 0.14.77 → 0.14.79

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.
@@ -18,21 +18,45 @@ if [ -f "$MARKER" ]; then
18
18
  fi
19
19
  # Fire-and-forget refresh via MCP. Timeout bounded by Claude Code hook.
20
20
  # Output nothing on success or failure; errors are surfaced via doctor.
21
+ #
22
+ # Two bugs this fixes (2026-06-07):
23
+ # 1. The Hindsight server is STATELESS (HINDSIGHT_API_MCP_STATELESS=true) and
24
+ # returns NO mcp-session-id header, so the old code's `[ -n "$SESSION" ]`
25
+ # gate was ALWAYS false → the refresh NEVER fired. Stateless MCP needs no
26
+ # session — drop the gate (mirrors src/memory/hindsight.ts, which tolerates
27
+ # a missing session id).
28
+ # 2. refresh_mental_model takes `mental_model_id` (a UUID), NOT `name`. Passing
29
+ # `name` returns isError "Missing required argument: mental_model_id". So we
30
+ # list_mental_models, resolve the `user-profile` model's id, then refresh
31
+ # by id.
21
32
  {
22
- # JSON-RPC flow: initialize tools/call refresh_mental_model
23
- SESSION=$(curl -sS -X POST "$API_URL/mcp/" \
33
+ # initialize (no session id needed on the stateless server).
34
+ curl -sS -X POST "$API_URL/mcp/" \
24
35
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
25
- -H "X-Bank-Id: $BANK_ID" -D /tmp/mm-refresh-$$.headers \
36
+ -H "X-Bank-Id: $BANK_ID" \
26
37
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"mm-refresh","version":"0.1"}}}' \
27
- -m 3 -o /dev/null 2>/dev/null && grep -i mcp-session-id /tmp/mm-refresh-$$.headers | cut -d' ' -f2 | tr -d '\r\n')
28
- if [ -n "$SESSION" ]; then
38
+ -m 3 -o /dev/null 2>/dev/null || true
39
+
40
+ # Resolve the user-profile mental model's id (refresh is by id, not name).
41
+ # list_mental_models returns the items as a JSON STRING nested in
42
+ # .result.structuredContent.result, so parse with jq (fromjson). The agent
43
+ # image ships jq; if it's somehow absent, MM_ID stays empty → skip (the next
44
+ # Stop fires it again; fire-and-forget, no wedge).
45
+ MM_ID=$(curl -sS -X POST "$API_URL/mcp/" \
46
+ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
47
+ -H "X-Bank-Id: $BANK_ID" \
48
+ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_mental_models","arguments":{}}}' \
49
+ -m 5 2>/dev/null \
50
+ | grep '^data:' | sed 's/^data: //' \
51
+ | jq -r '.result.structuredContent.result | fromjson | .items[] | select(.name=="user-profile") | .id' 2>/dev/null | head -1)
52
+
53
+ if [ -n "$MM_ID" ]; then
29
54
  curl -sS -X POST "$API_URL/mcp/" \
30
55
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
31
- -H "X-Bank-Id: $BANK_ID" -H "mcp-session-id: $SESSION" \
32
- -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"refresh_mental_model","arguments":{"name":"user-profile"}}}' \
56
+ -H "X-Bank-Id: $BANK_ID" \
57
+ -d "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"refresh_mental_model\",\"arguments\":{\"mental_model_id\":\"$MM_ID\"}}}" \
33
58
  -m 5 -o /dev/null 2>/dev/null || true
34
59
  fi
35
- rm -f /tmp/mm-refresh-$$.headers 2>/dev/null || true
36
60
  date +%s > "$MARKER"
37
61
  } &
38
62
  exit 0
@@ -14965,8 +14965,12 @@ async function ensureUserProfileMentalModel(apiUrl, bankId, opts) {
14965
14965
  try {
14966
14966
  const listData = await parseSseOrJson(listResponse);
14967
14967
  const models = listData.result?.content?.[0]?.text;
14968
- if (models && typeof models === "string" && models.includes("user-profile")) {
14969
- return { ok: true };
14968
+ if (models && typeof models === "string") {
14969
+ const parsed = JSON.parse(models);
14970
+ const items = Array.isArray(parsed?.items) ? parsed.items : [];
14971
+ if (items.some((m) => m?.name === "user-profile")) {
14972
+ return { ok: true };
14973
+ }
14970
14974
  }
14971
14975
  } catch {}
14972
14976
  }
@@ -14987,7 +14991,7 @@ async function ensureUserProfileMentalModel(apiUrl, bankId, opts) {
14987
14991
  name: "create_mental_model",
14988
14992
  arguments: {
14989
14993
  name: "user-profile",
14990
- query: "What are the key facts, preferences, context, and communication style about the user I talk to? Summarize what matters for making the agent feel like it knows them.",
14994
+ source_query: "What are the key facts, preferences, context, and communication style about the user I talk to? Summarize what matters for making the agent feel like it knows them.",
14991
14995
  types: ["world", "experience"]
14992
14996
  }
14993
14997
  }
@@ -14998,6 +15002,13 @@ async function ensureUserProfileMentalModel(apiUrl, bankId, opts) {
14998
15002
  if (!createResponse.ok) {
14999
15003
  return { ok: false, reason: `Create MM HTTP ${createResponse.status}` };
15000
15004
  }
15005
+ try {
15006
+ const created = await parseSseOrJson(createResponse);
15007
+ if (created.result?.isError === true) {
15008
+ const msg = created.result.content?.[0]?.text ?? "create returned isError";
15009
+ return { ok: false, reason: msg };
15010
+ }
15011
+ } catch {}
15001
15012
  return { ok: true };
15002
15013
  } catch (err) {
15003
15014
  if (err.name === "AbortError") {
@@ -15204,6 +15215,13 @@ async function addMemoryTag(apiUrl, bankId, memoryId, tag, opts) {
15204
15215
  if (!toolResponse.ok) {
15205
15216
  return { ok: false, reason: `Tool call HTTP ${toolResponse.status}` };
15206
15217
  }
15218
+ try {
15219
+ const parsed = await parseSseOrJson(toolResponse);
15220
+ if (parsed.result?.isError === true) {
15221
+ const msg = parsed.result.content?.[0]?.text ?? "tool returned isError";
15222
+ return { ok: false, reason: msg };
15223
+ }
15224
+ } catch {}
15207
15225
  return { ok: true };
15208
15226
  } catch (err) {
15209
15227
  if (err.name === "AbortError") {
@@ -49681,8 +49699,8 @@ var {
49681
49699
  } = import__.default;
49682
49700
 
49683
49701
  // src/build-info.ts
49684
- var VERSION = "0.14.77";
49685
- var COMMIT_SHA = "2473dbbf";
49702
+ var VERSION = "0.14.79";
49703
+ var COMMIT_SHA = "f6c40ab6";
49686
49704
 
49687
49705
  // src/cli/agent.ts
49688
49706
  init_source();
@@ -59174,9 +59192,8 @@ function makeHttpHindsightClient(apiUrl, opts) {
59174
59192
  });
59175
59193
  return { items: res.items ?? [], total: res.total ?? 0 };
59176
59194
  },
59177
- async deleteMemory(bankId, memoryId) {
59178
- const sid = await initSession(bankId);
59179
- await callTool(bankId, sid, "delete_memory", { bank_id: bankId, memory_id: memoryId });
59195
+ async deleteMemory(_bankId, _memoryId) {
59196
+ throw new Error("hindsight exposes no single-memory delete API (delete_memory is not a " + "real tool; a memory id is not a document_id) \u2014 matched secrets cannot " + "be auto-scrubbed; redact manually via the bank UI");
59180
59197
  }
59181
59198
  };
59182
59199
  }
@@ -59206,11 +59223,18 @@ ${mem.context ?? ""}`;
59206
59223
  }
59207
59224
  let deleted = 0;
59208
59225
  if (!opts.dryRun) {
59226
+ let warnedOnce = false;
59209
59227
  for (const m of matched) {
59210
59228
  try {
59211
59229
  await client.deleteMemory(bankId, m.id);
59212
59230
  deleted++;
59213
- } catch {}
59231
+ } catch (err) {
59232
+ if (!warnedOnce) {
59233
+ warnedOnce = true;
59234
+ process.stderr.write(`vault-sweep: ${matched.length} secret(s) matched in bank '${bankId}' but ` + `could NOT be auto-deleted: ${err.message}
59235
+ `);
59236
+ }
59237
+ }
59214
59238
  }
59215
59239
  }
59216
59240
  return { matched, deleted };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switchroom",
3
- "version": "0.14.77",
3
+ "version": "0.14.79",
4
4
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52821,11 +52821,11 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
52821
52821
  }
52822
52822
 
52823
52823
  // ../src/build-info.ts
52824
- var VERSION = "0.14.77";
52825
- var COMMIT_SHA = "2473dbbf";
52826
- var COMMIT_DATE = "2026-06-07T00:02:11+10:00";
52824
+ var VERSION = "0.14.79";
52825
+ var COMMIT_SHA = "f6c40ab6";
52826
+ var COMMIT_DATE = "2026-06-07T09:32:15+10:00";
52827
52827
  var LATEST_PR = null;
52828
- var COMMITS_AHEAD_OF_TAG = 4;
52828
+ var COMMITS_AHEAD_OF_TAG = 2;
52829
52829
 
52830
52830
  // gateway/boot-version.ts
52831
52831
  function formatRelativeAgo(iso) {