@opticell/workflow-companion 1.8.0 → 1.8.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.
Files changed (3) hide show
  1. package/README.md +87 -14
  2. package/index.js +131 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # WorkFlow Companion
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@opticell/workflow-companion?label=npm)](https://www.npmjs.com/package/@opticell/workflow-companion)
4
+ [![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.TeamDzX%2Fworkflow--companion-4F46E5)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.TeamDzX/workflow-companion)
5
+
6
+ > **This repository** is WorkFlow Companion's home: the source (`src/index.js`,
7
+ > MIT licensed), downloads (`WorkFlow.mcpb` for Claude Desktop) on the
8
+ > [Releases](https://github.com/TeamDzX/workflow-companion/releases) page,
9
+ > and bugs and requests in [Issues](https://github.com/TeamDzX/workflow-companion/issues).
10
+ > The package itself installs from npm. On a Mac, use the open-source
11
+ > [workflow-agent-bridge](https://github.com/TeamDzX/workflow-agent-bridge) instead.
12
+ > All of Opticell's free tools for Claude: [opticell-mcp](https://github.com/TeamDzX/opticell-mcp).
13
+
3
14
  Lets **Claude on Windows or Linux** work in your WorkFlow tasks, notes and
4
15
  projects: reading the queue, replying in threads, ticking checklists, filing
5
16
  notes, updating documents. It works in Claude Code, Claude Desktop, or any MCP
@@ -28,12 +39,23 @@ many devices are on.
28
39
 
29
40
  ## Install
30
41
 
31
- **Windows** (PowerShell): `irm https://raw.githubusercontent.com/TeamDzX/workflow-companion/main/install.ps1 | iex`
42
+ One line installs Node.js if needed, signs this computer in, adds the
43
+ companion to Claude Code and offers to let it start work on its own:
44
+
45
+ **Windows** (PowerShell):
32
46
 
33
- **Mac or Linux:** `curl -fsSL https://raw.githubusercontent.com/TeamDzX/workflow-companion/main/install.sh | sh`
47
+ ```powershell
48
+ irm https://raw.githubusercontent.com/TeamDzX/workflow-companion/main/install.ps1 | iex
49
+ ```
34
50
 
35
- It installs Node.js if needed, signs this computer in, adds the companion to
36
- Claude Code and offers to let it start work on its own. By hand:
51
+ **Mac or Linux** (Terminal):
52
+
53
+ ```sh
54
+ curl -fsSL https://raw.githubusercontent.com/TeamDzX/workflow-companion/main/install.sh | sh
55
+ ```
56
+
57
+ Switch the companion on in WorkFlow first (step 1 below). The steps that
58
+ follow are what the installer does, if you'd rather do them by hand.
37
59
 
38
60
  ## Set up
39
61
 
@@ -158,24 +180,60 @@ npx -y @opticell/workflow-companion wake-on
158
180
  | `workflow-companion` | Runs the MCP server. This is what Claude starts. |
159
181
  | `workflow-companion setup` | Signs this computer in. Takes `--web-token` to skip the prompt. |
160
182
  | `workflow-companion status` | Which device answers, how fresh the snapshot is, any receipts that arrived late. |
183
+ | `workflow-companion doctor` | Checks everything on this computer and says how to fix what's wrong. Start here when something isn't working. |
161
184
  | `workflow-companion keepalive` | Renews the sign-in. The scheduled job runs this. |
162
185
  | `workflow-companion update` | Updates the scheduled jobs' copy to the latest release now, and shows how to keep Claude Code on `@latest`. |
163
186
  | `workflow-companion auto-update on\|off` | Whether the scheduled jobs update themselves (on by default). |
164
187
  | `workflow-companion wake-on` | Starts a Claude Code session on its own when work for its name arrives. See above. |
165
188
  | `workflow-companion wake-off` | Stops that. Work waits until you ask Claude here. |
166
189
  | `workflow-companion wake` | One check of the queue. The scheduled job runs this. |
190
+ | `workflow-companion monitor add\|list\|check\|remove` | Checks this computer runs without using Claude. See below. |
191
+ | `workflow-companion approvals on\|off` | Lets an assistant run one exact command after you reply "approve CODE" (off by default). |
192
+ | `workflow-companion inbox-on\|inbox-off` | Files dropped in a folder become tasks. |
193
+ | `workflow-companion notifications on\|off` | Notices on this computer (on by default). `notify-test` shows one. |
194
+ | `workflow-companion reports on\|off` | A short report attached to the task after each session (on by default). |
167
195
  | `workflow-companion signout` | Deletes the sign-in, cached data and both scheduled jobs. |
168
196
 
169
197
  ## On this computer, by itself (1.8)
170
198
 
171
- In the same 2-minute scheduled job, without using Claude: **monitors**
172
- (`monitor add --http/--port/--disk/--process/--file/--command`, posting
173
- changes on a task and optionally waking a session), **approvals** (an
174
- assistant asks to run one exact command and it runs once you reply
175
- "approve CODE"; off until `approvals on`), an **inbox folder** (`inbox-on`:
176
- dropped files become tasks), **notifications** on the computer, and a
177
- **session report** attached to the task after each session. Details:
178
- <https://github.com/TeamDzX/workflow-companion#on-this-computer-by-itself-18>
199
+ These run in the same 2-minute scheduled job as waking, and cost no Claude
200
+ usage.
201
+
202
+ **Monitors.** Checks that wake Claude only when something changes:
203
+
204
+ ```sh
205
+ workflow-companion monitor add --name site --http https://example.com --task "Server status" --wake
206
+ workflow-companion monitor add --name disk --disk C:\ --min-gb 20 --task "Server status"
207
+ workflow-companion monitor add --name api --port 10.0.0.5:443 --every 2
208
+ workflow-companion monitor add --name backup --file D:\backups\latest.zip --task "Backups"
209
+ workflow-companion monitor add --name nightly --command "check-backups.cmd" --task "Backups" --wake
210
+ ```
211
+
212
+ A change (down, back up, the file changed) is posted on the task, shows a
213
+ notification here, and with `--wake` starts a session about it. An assistant
214
+ can set up website, port, disk, process and file monitors itself
215
+ (`workflow_monitor`), but **only you can add a command monitor**, because it
216
+ runs a command every few minutes.
217
+
218
+ **Approvals.** An assistant can ask to run one exact command on this computer
219
+ (restart a service, install an update). It posts the command on the task with
220
+ a code; reply `approve K7Q2` (or `decline K7Q2`) from your phone. Only a
221
+ person's reply counts, never another assistant's; tasks in shared projects
222
+ can't ask; the command runs once, exactly as shown, within 24 hours. **Off
223
+ until you run `workflow-companion approvals on` on this computer.**
224
+
225
+ **Inbox folder.** `workflow-companion inbox-on` makes `~/WorkFlow Inbox`
226
+ (or `--folder`): drop a file in and it becomes a task with the file attached.
227
+ A subfolder named after a project files it into that project. Filed files
228
+ move to `Filed/<date>`. `--assign` puts them in this assistant's queue.
229
+
230
+ **Notifications.** A notice on this computer when work arrives, a monitor
231
+ changes, an approval is answered, a session needs attention, or the iCloud
232
+ sign-in has ended (with the command that fixes it).
233
+
234
+ **Session reports.** After each session that changed something, a short
235
+ report is attached to its task: what it was asked, what it changed, any
236
+ approved commands it ran, and its last words.
179
237
 
180
238
  ## Worth knowing
181
239
 
@@ -204,11 +262,26 @@ dropped files become tasks), **notifications** on the computer, and a
204
262
 
205
263
  ## Tools
206
264
 
207
- The same 29 tools as the Mac's Agent Bridge MCP server, including:
265
+ 36 tools, including:
208
266
  `workflow_queue`, `workflow_get_task`, `workflow_comment`,
209
267
  `workflow_set_status_line`, `workflow_check_subtasks`, `workflow_update_task`,
210
268
  `workflow_create_task`, `workflow_list_notes`, `workflow_reply_note`,
211
269
  `workflow_list_projects`, `workflow_list_documents`, `workflow_update_document`,
212
- `workflow_draft_email` and `workflow_state`.
270
+ `workflow_draft_email`, `workflow_state`, and from 1.7 and 1.8
271
+ `workflow_hand_off`, `workflow_watch`, `workflow_house_rules`,
272
+ `workflow_monitor`, `workflow_request_approval`, `workflow_check_approval`
273
+ and `workflow_run_approved`.
213
274
 
214
275
  © Opticell Limited · <https://www.opticell-limited.com/companion>
276
+
277
+ ## Source and licence
278
+
279
+ `src/index.js` is the whole server: one file, Node 18 or later, no
280
+ dependencies. It is MIT licensed (see `LICENSE`). The published npm package
281
+ is the same file with WorkFlow's CloudKit API token filled in at build time
282
+ (the token is not a secret: it only lets a signed-in user reach their own
283
+ data). Run from source, `setup` asks for it with `--api-token`.
284
+
285
+ The `Dockerfile` runs the server over stdio. MCP directories use it to check
286
+ that the server starts and lists its tools, which it does without signing in.
287
+
package/index.js CHANGED
@@ -27,7 +27,7 @@ const path = require("path");
27
27
  const os = require("os");
28
28
 
29
29
  const PROTOCOL_VERSION = "2024-11-05";
30
- const SERVER_INFO = { name: "workflow", version: "1.8.0" };
30
+ const SERVER_INFO = { name: "workflow", version: "1.8.1" };
31
31
  // Who the agent is in WorkFlow: the assignee its queue follows, the @name
32
32
  // that calls it, the signature on what it writes. On the Mac it's Claude.
33
33
  // A companion goes by the name chosen at setup (default "Companion"), so a
@@ -1168,6 +1168,12 @@ const TOOLS = [
1168
1168
  return `Ran ${x.code} on ${os.hostname()} (${result.seconds} s): exit ${result.exit}\n${result.output || "(no output)"}`;
1169
1169
  },
1170
1170
  },
1171
+ {
1172
+ name: "workflow_doctor",
1173
+ description: "Check the companion on this computer end to end (sign-in, WorkFlow publishing and answering, version, scheduled jobs, Claude Code, last session, monitors) and say how to fix anything wrong. Use it when something isn't working.",
1174
+ inputSchema: { type: "object", properties: {} },
1175
+ handler: async () => (await doctorReport({ fromTool: true })).text,
1176
+ },
1171
1177
  {
1172
1178
  name: "workflow_ping",
1173
1179
  description: "Confirm the app is watching the bridge (round-trips one command).",
@@ -1878,17 +1884,20 @@ function notify(title, body, onceKey) {
1878
1884
  if (process.env.WF_NOTIFY_LOG) { try { fs.appendFileSync(process.env.WF_NOTIFY_LOG, `${title} | ${body}\n`); } catch (_) {} return; }
1879
1885
  const { spawn } = require("child_process");
1880
1886
  const opts = { detached: true, stdio: "ignore", windowsHide: true, env: Object.assign({}, process.env, { WF_T: title, WF_B: body }) };
1887
+ // A missing notifier (no notify-send on a server) fails asynchronously:
1888
+ // without a listener that error would end the whole process.
1889
+ const quiet = child => { child.on("error", () => {}); child.unref(); };
1881
1890
  try {
1882
1891
  if (process.platform === "win32") {
1883
1892
  const ps = "[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null;" +
1884
1893
  "$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02);" +
1885
1894
  "$x = $t.GetElementsByTagName('text'); $x.Item(0).AppendChild($t.CreateTextNode($env:WF_T)) > $null; $x.Item(1).AppendChild($t.CreateTextNode($env:WF_B)) > $null;" +
1886
1895
  "[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\\WindowsPowerShell\\v1.0\\powershell.exe').Show([Windows.UI.Notifications.ToastNotification]::new($t))";
1887
- spawn("powershell.exe", ["-NoProfile", "-NonInteractive", "-WindowStyle", "Hidden", "-Command", ps], opts).unref();
1896
+ quiet(spawn("powershell.exe", ["-NoProfile", "-NonInteractive", "-WindowStyle", "Hidden", "-Command", ps], opts));
1888
1897
  } else if (process.platform === "darwin") {
1889
- spawn("osascript", ["-e", "display notification (system attribute \"WF_B\") with title (system attribute \"WF_T\")"], opts).unref();
1898
+ quiet(spawn("osascript", ["-e", "display notification (system attribute \"WF_B\") with title (system attribute \"WF_T\")"], opts));
1890
1899
  } else {
1891
- spawn("notify-send", [title, body], opts).unref();
1900
+ quiet(spawn("notify-send", [title, body], opts));
1892
1901
  }
1893
1902
  } catch (_) {}
1894
1903
  }
@@ -2253,6 +2262,122 @@ async function inboxCLI(on) {
2253
2262
  return 0;
2254
2263
  }
2255
2264
 
2265
+ // ------------------------------------------------------------------ doctor (1.8.1)
2266
+ //
2267
+ // Checks the whole chain on this computer in one go and says how to fix
2268
+ // anything that's wrong: Node, the iCloud sign-in, whether WorkFlow is
2269
+ // publishing and answering, the name, the version, the scheduled jobs,
2270
+ // Claude Code, and what the last session did. `fromTool` skips the checks
2271
+ // that would be odd from inside a Claude session (asking Claude Code about
2272
+ // itself).
2273
+ async function doctorReport({ fromTool = false } = {}) {
2274
+ const npx = "npx -y @opticell/workflow-companion@latest";
2275
+ const lines = [`WorkFlow companion ${SERVER_INFO.version} on ${os.hostname()}, as "${AGENT.name}"`, ""];
2276
+ let problems = 0, warnings = 0;
2277
+ const ok = l => lines.push(` ✓ ${l}`);
2278
+ const bad = (l, fix) => { problems++; lines.push(` ✗ ${l}`); if (fix) lines.push(` fix: ${fix}`); };
2279
+ const warn = (l, fix) => { warnings++; lines.push(` ! ${l}`); if (fix) lines.push(` ${fix}`); };
2280
+ const done = () => {
2281
+ lines.push("", problems ? `${problems} problem(s)${warnings ? `, ${warnings} warning(s)` : ""}. Fix the ✗ lines first.`
2282
+ : warnings ? `Working, with ${warnings} warning(s).` : "All good.");
2283
+ return { text: lines.join("\n"), problems, warnings };
2284
+ };
2285
+ const ago = t => { const m = Math.round((Date.now() - t) / 60000); return m < 1 ? "just now" : m < 90 ? `${m} min ago` : m < 2880 ? `${Math.round(m / 60)} h ago` : `${Math.round(m / 1440)} days ago`; };
2286
+ const { spawnSync } = require("child_process");
2287
+
2288
+ const major = parseInt(process.versions.node, 10);
2289
+ major >= 18 ? ok(`Node.js ${process.versions.node}`) : bad(`Node.js ${process.versions.node} is too old (18 or later)`, "install the LTS from https://nodejs.org");
2290
+ if (!CLOUD) { warn("this is the Mac's own bridge, not a companion", "on the Mac, check Settings → Agent Bridge, or run: wf state"); return done(); }
2291
+
2292
+ const cfg = readJSON(CP.config, null);
2293
+ if (!cfg || !fs.existsSync(CP.token)) { bad("not signed in on this computer", `${npx} setup`); return done(); }
2294
+ try {
2295
+ await cloud.call("public/users/caller");
2296
+ ok(`iCloud sign-in works (${cfg.env || COMPANION.env})`);
2297
+ } catch (e) {
2298
+ if (e instanceof SignInNeeded) bad("the iCloud sign-in has ended (Apple ends one left unused for 9 to 14 hours)", `${npx} setup`);
2299
+ else bad(`can't reach iCloud: ${String(e.message).split("\n")[0]}`, "check this computer's internet connection, then run doctor again");
2300
+ return done();
2301
+ }
2302
+
2303
+ try { await cloud.load(true); } catch (e) { bad(`couldn't read WorkFlow's snapshot: ${e.message}`); return done(); }
2304
+ if (!cloudSnap) {
2305
+ bad("WorkFlow hasn't published anything for the companion yet",
2306
+ "switch it on in WorkFlow: iPhone/iPad Settings → Windows Companion → Answer the Companion, or Mac Settings → Agent Bridge → Cloud Bridge");
2307
+ } else {
2308
+ const age = Date.now() - Date.parse(cloudSnap.generatedAt);
2309
+ const line = `${cloudSnap.tasks.length} tasks, published ${ago(Date.parse(cloudSnap.generatedAt))}; answering: ${cloud.macLine()}`;
2310
+ age < 6 * 3600 * 1000 ? ok(line) : warn(line, "nothing has changed in WorkFlow for a while, or the device that answers is asleep or closed: open WorkFlow on it");
2311
+ const clash = nameClash(AGENT.name);
2312
+ clash ? bad(`"${AGENT.name}" is also the name of Claude on ${clash.host}: both would act on @${AGENT.name}`, `${npx} setup --name <another name>`)
2313
+ : ok(`the name "${AGENT.name}" is this computer's alone`);
2314
+ }
2315
+
2316
+ if (!fromTool) {
2317
+ const started = Date.now();
2318
+ try {
2319
+ const r = await send("ping", {}, 30000);
2320
+ r.status === "applied" ? ok(`a test command was applied by WorkFlow in ${Math.max(1, Math.round((Date.now() - started) / 1000))} s`)
2321
+ : warn("a test command got no answer within 30 s", "WorkFlow on the answering device may be asleep or closed. Commands wait safely and run when it next looks; an iPhone can take minutes");
2322
+ } catch (e) { warn(`couldn't send a test command: ${e.message}`); }
2323
+ }
2324
+
2325
+ const rel = await latestRelease(true);
2326
+ if (!rel) warn("couldn't check npm for a newer release");
2327
+ else if (newerVersion(rel.version, SERVER_INFO.version)) warn(`version ${SERVER_INFO.version}; ${rel.version} is out`, `${npx} update (and restart Claude Code)`);
2328
+ else ok(`version ${SERVER_INFO.version} is the latest`);
2329
+ const saved = versionOfScript(SAVED_SCRIPT);
2330
+ if (saved && rel && newerVersion(rel.version, saved)) warn(`the scheduled jobs run ${saved}`, cfg.autoUpdate === false ? `auto-update is off: ${npx} update` : "they update themselves within 6 hours, or now with: " + `${npx} update`);
2331
+
2332
+ const scheduled = name => {
2333
+ if (process.platform === "win32") return spawnSync("schtasks", ["/Query", "/TN", name], { encoding: "utf8", windowsHide: true }).status === 0;
2334
+ const r = spawnSync("crontab", ["-l"], { encoding: "utf8" });
2335
+ return r.status === 0 && r.stdout.includes(name === TASK_NAME ? "workflow-companion keepalive" : "workflow-companion wake");
2336
+ };
2337
+ let lastKeepAlive = "";
2338
+ try { lastKeepAlive = fs.readFileSync(KEEPALIVE_LOG, "utf8").trim().split("\n").pop(); } catch (_) {}
2339
+ scheduled(TASK_NAME) ? ok(`keep-alive scheduled${lastKeepAlive ? `; last run ${lastKeepAlive.split(" ")[0].slice(0, 16).replace("T", " ")}: ${lastKeepAlive.split(" ").slice(1).join(" ")}` : ""}`)
2340
+ : warn("the keep-alive isn't scheduled, so the sign-in can end while Claude isn't running", `${npx} setup (it schedules it)`);
2341
+
2342
+ if (cfg.wakeEnabled) {
2343
+ scheduled(WAKE.taskName) ? ok("waking is on and scheduled every 2 minutes") : bad("waking is on but its scheduled job is missing", `${npx} wake-on`);
2344
+ const bin = cfg.claudeBin || "claude";
2345
+ const v = spawnSync(bin, ["--version"], { encoding: "utf8", timeout: 20000, windowsHide: true, shell: process.platform === "win32" && /\.(cmd|bat)$/i.test(bin) });
2346
+ v.status === 0 ? ok(`Claude Code runs: ${String(v.stdout).trim().split("\n")[0]}`)
2347
+ : bad(`Claude Code at ${bin} doesn't run`, `reinstall or sign in to Claude Code, then: ${npx} wake-on`);
2348
+ let log = [];
2349
+ try { log = fs.readFileSync(WAKE.log, "utf8").trim().split("\n"); } catch (_) {}
2350
+ const last = log.filter(l => / session exited /.test(l)).pop();
2351
+ if (!last) ok("no sessions yet");
2352
+ else {
2353
+ const when = Date.parse(last.split(" ")[0]);
2354
+ const code = (/session exited (-?\d+)/.exec(last) || [])[1];
2355
+ code === "0" && !/time limit/.test(last) ? ok(`last session ${ago(when)} finished normally`)
2356
+ : warn(`last session ${ago(when)} didn't finish normally: ${last.split(" ").slice(1).join(" ").slice(0, 160)}`, `see ${WAKE.log}`);
2357
+ }
2358
+ if (log.slice(-30).some(l => /SIGN-IN ENDED/.test(l))) warn("the sign-in ended recently (it works now)", "if this PC sleeps for long, leave it awake or check it each morning");
2359
+ } else {
2360
+ warn("waking is off: work waits until you ask Claude on this computer", `${npx} wake-on`);
2361
+ }
2362
+
2363
+ if (!fromTool) {
2364
+ const bin = cfg.claudeBin || "claude";
2365
+ const list = spawnSync(bin, ["mcp", "list"], { encoding: "utf8", timeout: 60000, windowsHide: true, shell: process.platform === "win32" && /\.(cmd|bat)$/i.test(bin) });
2366
+ const text = String(list.stdout || "");
2367
+ if (list.status !== 0 && !text) warn("couldn't ask Claude Code which tools it has", `if it isn't installed: ${claudeCodeCommand()}`);
2368
+ else if (!/workflow/i.test(text)) bad("Claude Code doesn't have the companion", claudeCodeCommand());
2369
+ else if (!/@latest/.test(text.split("\n").find(l => /^workflow/i.test(l)) || "")) warn("Claude Code runs a pinned version of the companion", `claude mcp remove workflow -s user, then: ${claudeCodeCommand()}`);
2370
+ else ok("Claude Code has the companion, on @latest");
2371
+ }
2372
+
2373
+ const failing = loadMonitors().filter(m => m.state && !m.state.ok);
2374
+ if (loadMonitors().length) failing.length ? warn(`monitors failing: ${failing.map(m => `${m.name} (${m.state.detail})`).join(", ")}`) : ok(`${loadMonitors().length} monitor(s), all OK`);
2375
+ const pending = loadApprovals().filter(a => a.status === "pending");
2376
+ if (pending.length) warn(`${pending.length} approval(s) waiting for you: ${pending.map(a => `${a.code} on “${a.taskTitle}”`).join(", ")}`);
2377
+ if (cfg.inboxFolder) fs.existsSync(cfg.inboxFolder) ? ok(`inbox folder: ${cfg.inboxFolder}`) : bad(`the inbox folder ${cfg.inboxFolder} is missing`, `${npx} inbox-on --folder "<path>"`);
2378
+ return done();
2379
+ }
2380
+
2256
2381
  // ------------------------------------------------------------------ versions (1.6.1)
2257
2382
 
2258
2383
  // Each companion says which version it runs, and keeps itself current.
@@ -2479,6 +2604,7 @@ const HELP = `WorkFlow companion ${SERVER_INFO.version}
2479
2604
  workflow-companion run the MCP server (what Claude starts)
2480
2605
  workflow-companion setup sign this computer in to iCloud for WorkFlow (--name, --takeover, --no-browser)
2481
2606
  workflow-companion status which device answers, how fresh is the snapshot
2607
+ workflow-companion doctor check everything on this computer and say how to fix what's wrong
2482
2608
  workflow-companion keepalive renew the sign-in (what the scheduled job runs)
2483
2609
  workflow-companion update update the scheduled jobs' copy now, and say how to keep Claude Code current
2484
2610
  workflow-companion auto-update on|off whether the scheduled jobs update themselves (on by default)
@@ -2505,6 +2631,7 @@ Install in one line: see https://github.com/TeamDzX/workflow-companion#install
2505
2631
  if (argv.includes("--print-config")) printConfig();
2506
2632
  else if (argv.includes("--help") || verb === "help") process.stdout.write(HELP);
2507
2633
  else if (verb === "setup") setup().then(c => { process.exitCode = c; }, e => { console.error(e.message || e); process.exitCode = 1; });
2634
+ else if (verb === "doctor") doctorReport().then(r => { console.log(r.text); process.exitCode = r.problems ? 1 : 0; }, e => { console.error(e.message || e); process.exitCode = 1; });
2508
2635
  else if (verb === "status") cloudStateText().then(t => console.log(t), e => { console.error(e.message || e); process.exitCode = 1; });
2509
2636
  else if (verb === "keepalive") keepAlive().then(c => { process.exitCode = c; });
2510
2637
  else if (verb === "update") updateNow().then(c => { process.exitCode = c; }, e => { console.error(e.message || e); process.exitCode = 1; });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opticell/workflow-companion",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "mcpName": "io.github.TeamDzX/workflow-companion",
5
5
  "description": "Lets Claude on Windows or Linux work in your WorkFlow tasks, notes and projects, through WorkFlow for Mac and your own iCloud. An MCP server.",
6
6
  "keywords": [