poke-browser 0.4.0 → 0.4.1

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.
@@ -43,6 +43,11 @@ const POKE_TERMINAL_ONLY_INSTRUCTION =
43
43
  "Be strict: immediately start the browser process and proceed with the requested browser actions.\n" +
44
44
  "[END BROWSER EXTENSION SESSION]\n\n";
45
45
 
46
+ const POKE_TERMINAL_FALLBACK_INSTRUCTION =
47
+ "[BROWSER SESSION]\n" +
48
+ "No chat reply. No iMessage/SMS/Telegram reply.\n" +
49
+ "Start browser actions immediately and respond only through tool/terminal channel.\n\n";
50
+
46
51
  function logCommand(direction, summary) {
47
52
  commandLog.unshift({ ts: Date.now(), direction, summary });
48
53
  if (commandLog.length > LOG_MAX) commandLog.length = LOG_MAX;
@@ -64,6 +69,47 @@ function logCommand(direction, summary) {
64
69
  }
65
70
  }
66
71
 
72
+ /**
73
+ * @param {string} apiKey
74
+ * @param {string} message
75
+ */
76
+ async function postPokeMessage(apiKey, message) {
77
+ const resp = await fetch("https://poke.com/api/v1/inbound/api-message", {
78
+ method: "POST",
79
+ headers: {
80
+ Authorization: `Bearer ${apiKey}`,
81
+ "Content-Type": "application/json",
82
+ },
83
+ body: JSON.stringify({ message }),
84
+ });
85
+
86
+ if (resp.ok) {
87
+ const data = await resp.json().catch(() => null);
88
+ return { ok: true, data };
89
+ }
90
+
91
+ const bodyText = await resp.text();
92
+ let serverMsg = "";
93
+ try {
94
+ const parsed = JSON.parse(bodyText);
95
+ serverMsg =
96
+ typeof parsed?.error === "string"
97
+ ? parsed.error
98
+ : typeof parsed?.message === "string"
99
+ ? parsed.message
100
+ : "";
101
+ } catch {
102
+ /* non-json response body */
103
+ }
104
+
105
+ return {
106
+ ok: false,
107
+ status: resp.status,
108
+ statusText: resp.statusText || "",
109
+ serverMsg: serverMsg || bodyText.slice(0, 300),
110
+ };
111
+ }
112
+
67
113
  async function getWsPort() {
68
114
  const { wsPort } = await chrome.storage.local.get("wsPort");
69
115
  if (typeof wsPort === "number" && Number.isFinite(wsPort) && wsPort > 0 && wsPort < 65536) {
@@ -1993,37 +2039,45 @@ const RUNTIME_HANDLERS = {
1993
2039
  return;
1994
2040
  }
1995
2041
  try {
1996
- const fullMessage = `${POKE_TERMINAL_ONLY_INSTRUCTION}${userMessage}`;
1997
- const resp = await fetch("https://poke.com/api/v1/inbound/api-message", {
1998
- method: "POST",
1999
- headers: {
2000
- Authorization: `Bearer ${apiKey}`,
2001
- "Content-Type": "application/json",
2002
- },
2003
- body: JSON.stringify({ message: fullMessage }),
2004
- });
2005
- if (!resp.ok) {
2006
- const bodyText = await resp.text();
2007
- let serverMsg = "";
2008
- try {
2009
- const parsed = JSON.parse(bodyText);
2010
- serverMsg =
2011
- typeof parsed?.error === "string"
2012
- ? parsed.error
2013
- : typeof parsed?.message === "string"
2014
- ? parsed.message
2015
- : "";
2016
- } catch {
2017
- /* keep raw status */
2042
+ const primary = await postPokeMessage(
2043
+ apiKey,
2044
+ `${POKE_TERMINAL_ONLY_INSTRUCTION}${userMessage}`,
2045
+ );
2046
+
2047
+ if (primary.ok) {
2048
+ sendResponse({ ok: true, data: primary.data });
2049
+ return;
2050
+ }
2051
+
2052
+ // If backend fails with a 5xx, retry once with shorter strict instruction.
2053
+ if (primary.status >= 500) {
2054
+ const fallback = await postPokeMessage(
2055
+ apiKey,
2056
+ `${POKE_TERMINAL_FALLBACK_INSTRUCTION}${userMessage}`,
2057
+ );
2058
+ if (fallback.ok) {
2059
+ sendResponse({
2060
+ ok: true,
2061
+ data: fallback.data,
2062
+ warning: `Primary prompt failed with ${primary.status}; fallback succeeded.`,
2063
+ });
2064
+ return;
2018
2065
  }
2019
2066
  sendResponse({
2020
2067
  ok: false,
2021
- error: serverMsg || `Poke API error (${resp.status}).`,
2068
+ error:
2069
+ `Poke API error (${fallback.status}). ` +
2070
+ (fallback.serverMsg || fallback.statusText || "Unknown server error."),
2022
2071
  });
2023
2072
  return;
2024
2073
  }
2025
- const data = await resp.json().catch(() => null);
2026
- sendResponse({ ok: true, data });
2074
+
2075
+ sendResponse({
2076
+ ok: false,
2077
+ error:
2078
+ `Poke API error (${primary.status}). ` +
2079
+ (primary.serverMsg || primary.statusText || "Unknown server error."),
2080
+ });
2027
2081
  } catch (err) {
2028
2082
  sendResponse({
2029
2083
  ok: false,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "poke-browser",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "description": "Browser automation bridge for MCP agents via WebSocket.",
6
6
  "permissions": [
7
7
  "tabs",
@@ -260,6 +260,20 @@
260
260
  min-height: 14px;
261
261
  }
262
262
 
263
+ .inline-link {
264
+ margin-top: 6px;
265
+ font-size: 11px;
266
+ }
267
+
268
+ .inline-link a {
269
+ color: #a78bfa;
270
+ text-decoration: none;
271
+ }
272
+
273
+ .inline-link a:hover {
274
+ text-decoration: underline;
275
+ }
276
+
263
277
  .toggle-label {
264
278
  font-size: 13px;
265
279
  color: var(--text-primary);
@@ -489,6 +503,9 @@
489
503
  <button type="button" id="save-api-key-btn" class="btn">Save key</button>
490
504
  <button type="button" id="clear-api-key-btn" class="btn">Clear key</button>
491
505
  </div>
506
+ <div class="inline-link">
507
+ <a href="https://poke.com/kitchen/api-keys" target="_blank" rel="noopener noreferrer">Get an API key from Poke Kitchen</a>
508
+ </div>
492
509
  <div class="mini-status" id="api-key-status"></div>
493
510
  </section>
494
511
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poke-browser",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "MCP server + WebSocket bridge for the poke-browser Chrome extension",
5
5
  "type": "module",
6
6
  "engines": {