@rubytech/taskmaster 1.0.43 → 1.0.45

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.
@@ -1,7 +1,9 @@
1
+ import { createSubsystemLogger } from "../../logging/subsystem.js";
1
2
  import { ErrorCodes, errorShape } from "../protocol/index.js";
2
3
  import { registerScreencastFrameListener, removeScreencastFrameListener, getActiveScreencastSession, } from "../../browser/routes/screencast.js";
3
4
  import { stopScreencast } from "../../browser/screencast.js";
4
5
  import { resolveHandoff, getPendingHandoff } from "../../browser/handoff.js";
6
+ const log = createSubsystemLogger("browser").child("screencast-rpc");
5
7
  /**
6
8
  * Gateway RPC handlers for browser screencast.
7
9
  * These relay between the UI WebSocket clients and the browser bridge.
@@ -11,9 +13,11 @@ export const browserScreencastHandlers = {
11
13
  const quality = typeof params.quality === "number" ? params.quality : 60;
12
14
  const maxWidth = typeof params.maxWidth === "number" ? params.maxWidth : 1280;
13
15
  const maxHeight = typeof params.maxHeight === "number" ? params.maxHeight : 720;
16
+ log.info(`screencast.start requested quality=${quality} maxWidth=${maxWidth} maxHeight=${maxHeight}`);
14
17
  // Stop existing session if any
15
18
  const existing = getActiveScreencastSession();
16
19
  if (existing?.active) {
20
+ log.info("stopping existing screencast session");
17
21
  stopScreencast(existing);
18
22
  }
19
23
  // Remove old listener
@@ -30,9 +34,11 @@ export const browserScreencastHandlers = {
30
34
  try {
31
35
  const bridgeUrl = await resolveBridgeUrl(context);
32
36
  if (!bridgeUrl) {
37
+ log.warn("screencast.start failed: bridge URL could not be resolved");
33
38
  respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "Browser bridge not configured"));
34
39
  return;
35
40
  }
41
+ log.info(`forwarding screencast.start to bridge at ${bridgeUrl}`);
36
42
  const res = await fetch(`${bridgeUrl}/screencast/start`, {
37
43
  method: "POST",
38
44
  headers: { "Content-Type": "application/json" },
@@ -40,21 +46,27 @@ export const browserScreencastHandlers = {
40
46
  });
41
47
  if (!res.ok) {
42
48
  const body = (await res.json().catch(() => ({ error: "Unknown error" })));
43
- respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, body?.error ?? `HTTP ${res.status}`));
49
+ const msg = body?.error ?? `HTTP ${res.status}`;
50
+ log.error(`bridge returned error: ${msg}`);
51
+ respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, msg));
44
52
  return;
45
53
  }
46
54
  const result = (await res.json());
55
+ log.info(`screencast started: sessionId=${result.sessionId}`);
47
56
  respond(true, result);
48
57
  }
49
58
  catch (err) {
59
+ log.error(`screencast.start failed: ${err}`);
50
60
  respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
51
61
  }
52
62
  },
53
63
  "browser.screencast.stop": async ({ respond, context }) => {
64
+ log.info("screencast.stop requested");
54
65
  removeScreencastFrameListener("gateway");
55
66
  try {
56
67
  const bridgeUrl = await resolveBridgeUrl(context);
57
68
  if (!bridgeUrl) {
69
+ log.info("screencast.stop: no bridge URL, returning ok");
58
70
  respond(true, { ok: true });
59
71
  return;
60
72
  }
@@ -63,9 +75,11 @@ export const browserScreencastHandlers = {
63
75
  headers: { "Content-Type": "application/json" },
64
76
  body: JSON.stringify({}),
65
77
  });
78
+ log.info("screencast stopped");
66
79
  respond(true, { ok: true });
67
80
  }
68
81
  catch (err) {
82
+ log.error(`screencast.stop failed: ${err}`);
69
83
  respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, String(err)));
70
84
  }
71
85
  },
@@ -133,18 +147,24 @@ export const browserScreencastHandlers = {
133
147
  async function resolveBridgeUrl(context) {
134
148
  const health = context.getHealthCache();
135
149
  const browserUrl = health?.browser?.controlUrl;
136
- if (browserUrl)
150
+ if (browserUrl) {
151
+ log.debug(`bridge URL from health cache: ${browserUrl}`);
137
152
  return browserUrl;
153
+ }
154
+ log.debug("no bridge URL in health cache, resolving from config");
138
155
  try {
139
156
  const { loadConfig } = await import("../../config/config.js");
140
157
  const { resolveBrowserConfig } = await import("../../browser/config.js");
141
158
  const cfg = loadConfig();
142
159
  const resolved = resolveBrowserConfig(cfg.browser);
143
- if (resolved.enabled && resolved.controlUrl)
160
+ if (resolved.enabled && resolved.controlUrl) {
161
+ log.debug(`bridge URL from config: ${resolved.controlUrl}`);
144
162
  return resolved.controlUrl;
163
+ }
164
+ log.warn(`browser config resolved but not usable: enabled=${resolved.enabled} controlUrl=${resolved.controlUrl ?? "null"}`);
145
165
  }
146
- catch {
147
- // ignore
166
+ catch (err) {
167
+ log.error(`failed to resolve browser config: ${err}`);
148
168
  }
149
169
  return null;
150
170
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/taskmaster",
3
- "version": "1.0.43",
3
+ "version": "1.0.45",
4
4
  "description": "AI-powered business assistant for small businesses",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -53,6 +53,8 @@ Take a snapshot and check the page content.
53
53
  - Copy the new key
54
54
  - Screenshot: "Created a new key for you."
55
55
 
56
+ **Send the key as a separate message** — just the key on its own line, nothing else. This lets the user tap and copy it easily from their chat app.
57
+
56
58
  ## Step 6: Add to Taskmaster
57
59
 
58
60
  Tell the user how to add the key:
@@ -44,6 +44,7 @@ Take a snapshot of the dashboard.
44
44
  - If the key is masked, click the eye icon to reveal it
45
45
  - Screenshot: "Here's your Tavily dashboard. Copying your API key..."
46
46
  - Copy the key value
47
+ - **Send the key as a separate message** — just the key on its own line, nothing else. This lets the user tap and copy it easily from their chat app.
47
48
 
48
49
  ## Step 6: Add to Taskmaster
49
50
 
@@ -107,7 +107,7 @@ Once your license is activated:
107
107
  2. Sign in with your Claude Pro account
108
108
  3. Copy the code shown and paste it into the setup page
109
109
  4. Tap **Submit**
110
- 5. When connected, tap **"Continue to WhatsApp"**
110
+ 5. When connected, tap **"Continue to Chat"** to start configuring your assistant
111
111
 
112
112
  > **Don't have Claude Pro?** Click "Or enter your API key" below the Connect button. Paste your Anthropic API key and tap Submit. This is the advanced option — most people find signing in with Claude Pro much easier.
113
113
 
@@ -206,13 +206,16 @@ Taskmaster runs two assistants on the same WhatsApp number, each with a differen
206
206
 
207
207
  **The Public Assistant** handles messages from your customers. It can reply to messages and look up information you've taught it, but it cannot access your files, run commands, or see private notes. If a customer tries to trick it into doing something it shouldn't, it simply can't — those capabilities don't exist for it.
208
208
 
209
- **The Admin Assistant** is your personal assistant. When you message yourself on WhatsApp (or use the Chat page), you're talking to this one. It has full access — it can manage files, browse the web, run scheduled tasks, and read everything.
209
+ **The Admin Assistant** is your personal assistant. When you use the Chat page (or message yourself on WhatsApp), you're talking to this one. It has full access — it can manage files, browse the web, run scheduled tasks, and read everything.
210
210
 
211
211
  ### How does Taskmaster know which is which?
212
212
 
213
- Your phone number (the one you paired during setup) is marked as an admin. Messages from your number go to the admin assistant. Messages from everyone else go to the public assistant.
213
+ There are two concepts to understand:
214
214
 
215
- You can add more admin numbers on the **Admins** page for example, your personal phone, a business partner or manager who should also get full access.
215
+ - **Paired WhatsApp number** the WhatsApp account linked to your Pi during setup. This is the number your customers message. When you send yourself a message on this WhatsApp account (self-chat), it goes to the admin assistant.
216
+ - **Admin phones** — additional phone numbers that get admin access when they message the paired WhatsApp. Useful if you have a separate personal phone, or if a business partner needs admin access from their own number.
217
+
218
+ By default, messages from anyone other than registered admin phones go to the public assistant. You can add admin phones on the **Admins** page.
216
219
 
217
220
  ---
218
221
 
@@ -16,6 +16,7 @@ Explain that there's a second assistant — the **public agent** — that handle
16
16
 
17
17
  Ask conversationally, one thing at a time:
18
18
  - **Owner's name** (the person you're talking to)
19
+ - **Phone number** — their personal mobile number (international format, e.g., +44 7591 215452). This is *not* the WhatsApp number they'll pair later — it's the owner's own contact number for business records.
19
20
  - **Business name**
20
21
  - **Location**
21
22
  - **Working hours**
@@ -23,52 +24,89 @@ Ask conversationally, one thing at a time:
23
24
 
24
25
  ## Step 4: Save Everything
25
26
 
26
- Update these files with the collected info:
27
+ Use your `write` tool to update workspace files and `memory_write` for memory files. Never output shell commands or ask the admin to run terminal commands.
27
28
 
28
29
  **Your files (admin agent):**
29
- 1. **IDENTITY.md** — Replace `[ASSISTANT_NAME]` with your chosen name
30
- 2. **USER.md** — Fill in owner name, business name, location, working hours
30
+ 1. **IDENTITY.md** — Use `write` to replace `[ASSISTANT_NAME]` with your chosen name
31
+ 2. **USER.md** — Use `write` to fill in owner name, phone number, business name, location, working hours
31
32
 
32
33
  **Public agent files** (your counterpart at `../public/`):
33
- 3. **`../public/IDENTITY.md`** — Replace `[ASSISTANT_NAME]` with the public agent's chosen name
34
+ 3. **`../public/IDENTITY.md`** — Use `write` to replace `[ASSISTANT_NAME]` with the public agent's chosen name
34
35
 
35
36
  **Shared memory** (accessible by both agents):
36
- 4. **`memory/shared/business.md`** — Write the key business details: owner name, business name, location, working hours, and anything else relevant. **This is essential** — the public agent doesn't have USER.md and relies on shared memory to know the business owner's name, what the business does, and where it's based. Without this file, the public agent can't answer basic customer questions.
37
+ 4. **`memory/shared/business.md`** — Use `memory_write` to save the key business details: owner name, business name, location, working hours, and anything else relevant. **This is essential** — the public agent doesn't have USER.md and relies on shared memory to know the business owner's name, what the business does, and where it's based. Without this file, the public agent can't answer basic customer questions.
37
38
 
38
39
  **Website summary** (if a website was provided):
39
- 5. **`memory/public/website.md`** — Use `document_read` to fetch the website and write a comprehensive summary covering: what the business does, services offered, pricing (if public), location and coverage area, contact details, opening hours, and any other customer-relevant information. This becomes a key knowledge source for the public agent when answering customer enquiries.
40
+ 5. **`memory/public/website.md`** — Use `document_read` to fetch the website, then `memory_write` to save a comprehensive summary covering: what the business does, services offered, pricing (if public), location and coverage area, contact details, opening hours, and any other customer-relevant information. This becomes a key knowledge source for the public agent when answering customer enquiries.
40
41
 
41
42
  All other files (SOUL.md, AGENTS.md, etc.) are already generic and reference USER.md or shared memory — no changes needed.
42
43
 
43
44
  ## Step 5: Authorize Admin Devices
44
45
 
45
- The paired device (self-chat) already has admin access. Ask if they want to add their personal phone as an additional admin device.
46
+ At this point, WhatsApp has not been paired yet that happens later via the Setup page. No phone numbers have admin access yet.
46
47
 
47
- If yes, use the `authorize_admin` tool with their phone number (international format, e.g., +447504472444).
48
+ Ask the owner whether they'd like to register their personal phone number (the one they gave you in Step 3) as an **admin device**. Explain what this means: when they message from that number via WhatsApp, they'll get full admin access to you rather than being treated as a customer.
49
+
50
+ If they confirm, use the `authorize_admin` tool with their phone number (international format with no spaces, e.g., +447504472444). Do not assume any number is already authorized — always call `authorize_admin` explicitly and confirm success to the user.
51
+
52
+ If they have additional phone numbers they want to authorize (e.g., a business partner), authorize those too.
48
53
 
49
54
  ## Step 6: Help with API Keys
50
55
 
51
- Two free API keys unlock important capabilities. Offer to help the admin get them — use the browser to walk through signup and show screenshots so the user can follow along.
56
+ Two free API keys unlock important capabilities. Offer to walk the admin through getting them — you can use the browser to guide them through signup and show screenshots so they can follow along.
52
57
 
53
- - **Tavily** (web search) — load the `tavily` skill's `references/browser-setup.md` and follow its steps
54
58
  - **Google AI** (voice notes + video) — load the `google-ai` skill's `references/browser-setup.md` and follow its steps
59
+ - **Tavily** (web search) — load the `tavily` skill's `references/browser-setup.md` and follow its steps. The admin can use the same Google email they just set up to register.
55
60
 
56
- If the admin prefers to do it themselves, direct them to their Taskmaster setup page (API Keys section) and explain where to sign up: [app.tavily.com](https://app.tavily.com) for Tavily, [aistudio.google.com](https://aistudio.google.com) for Google AI.
61
+ If the admin prefers to do it themselves later, they can manage API keys through the **Setup page** (API Keys section) this requires logging in with the **admin PIN**, not an account PIN. Direct them to [app.tavily.com](https://app.tavily.com) for Tavily and [aistudio.google.com](https://aistudio.google.com) for Google AI.
57
62
 
58
63
  These keys are optional — the assistant works without them. Don't pressure. If the admin wants to skip this and come back later, that's fine.
59
64
 
60
- ## Step 7: Explain What's Next
65
+ If they need help with anything at all — setup, API keys, or general questions — suggest they reach out to **Dave at Taskmaster** via WhatsApp: [wa.me/447591215452](https://wa.me/447591215452).
66
+
67
+ ## Step 7: Rename the Account
68
+
69
+ The default account is called "taskmaster" in the Setup page header. Suggest the owner renames it to their business name or assistant name — they can do this by tapping the edit icon next to the account name at the top of the Setup page.
70
+
71
+ **Important:** This only changes the display name. Do **not** rename any folders in the filesystem — that will break the system.
72
+
73
+ ## Step 8: Set an Account PIN
74
+
75
+ Suggest the owner sets an **account PIN** for their account. Explain the difference:
76
+
77
+ - The **admin PIN** was set during initial setup (the very first screen). It unlocks full access to all accounts and device settings.
78
+ - An **account PIN** is specific to one account. It lets someone access only that account without seeing others. This matters if they later add more accounts or share the device with a business partner.
79
+
80
+ They can set the account PIN on the Setup page — look for the **Account PIN** row and tap **Set PIN**.
81
+
82
+ ## Step 9: Pair WhatsApp
83
+
84
+ The assistant can't receive customer messages until a WhatsApp number is paired. Explain this to the owner:
85
+
86
+ > "Everything's configured — but to start receiving customer messages, you need to pair a WhatsApp number. This is the business phone number that customers will message. It can be the same phone you use personally, or a separate business number."
87
+
88
+ Guide them to do this via the Setup page:
89
+
90
+ 1. Go to the **Setup page** and find the **WhatsApp** row
91
+ 2. Tap **Link WhatsApp** (or **Relink WhatsApp** if re-pairing)
92
+ 3. Follow the QR code pairing flow on their phone
93
+
94
+ Once paired, any message to that WhatsApp number from an unrecognized number goes to the **public agent**. Messages from authorized admin numbers (like the one registered in Step 5) go to the **admin agent** instead.
95
+
96
+ If they're not ready to pair now, that's fine — they can do it anytime from the Setup page. Everything else is already configured and waiting.
97
+
98
+ ## Step 10: Explain What's Next
61
99
 
62
100
  Tell them:
63
- - They can message anytime to update business info
64
- - Customers who message will get the public agent (restricted access)
65
- - They (admin) get full access to configure everything
101
+ - They can message you anytime to update business info, ask questions, or configure settings
102
+ - Once WhatsApp is paired, customers who message the business number will talk to the public assistant automatically
103
+ - Messages from their authorized phone number will reach you (the admin assistant) instead
66
104
  - You'll learn their business as you go
67
105
 
68
- ## Step 8: Delete This File
106
+ ## Step 11: Delete This File
69
107
 
70
108
  Once setup is complete, create a file called `.bootstrap-done` in this directory (empty content is fine), then delete this file. The `.bootstrap-done` marker prevents this onboarding from reappearing.
71
109
 
72
110
  ---
73
111
 
74
- **Remember:** Be conversational, not robotic. This is WhatsApp, not a form. Ask one thing at a time.
112
+ **Remember:** Be conversational, not robotic. This is a chat, not a form. Ask one thing at a time.