@captionbolt/mcp 0.3.1 → 0.3.2

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
@@ -13,7 +13,7 @@ Pin the reviewed version in your client's STDIO configuration:
13
13
  "mcpServers": {
14
14
  "captionbolt": {
15
15
  "command": "npx",
16
- "args": ["--yes", "@captionbolt/mcp@0.3.1"]
16
+ "args": ["--yes", "@captionbolt/mcp@0.3.2"]
17
17
  }
18
18
  }
19
19
  }
@@ -23,12 +23,13 @@ Run this once in a desktop terminal using the same pinned package version as
23
23
  your MCP configuration:
24
24
 
25
25
  ```sh
26
- npx --yes @captionbolt/mcp@0.3.1 login
26
+ npx --yes @captionbolt/mcp@0.3.2 login
27
27
  ```
28
28
 
29
29
  If installed globally, `captionbolt-mcp login` is equivalent.
30
- The command opens CaptionBolt in your browser (on WSL, the Windows browser via
31
- `explorer.exe`) and prints the link in case no browser opens. An existing website
30
+ The command opens CaptionBolt in your default browser (on Windows and WSL through
31
+ PowerShell) and prints the link in case no browser opens. Open that link on the
32
+ same computer: authorization returns to a local address. An existing website
32
33
  session can skip password entry, but you still approve MCP access. OAuth tokens
33
34
  and the registered client are saved in the macOS Keychain, Windows Credential
34
35
  Manager or a Linux Secret Service keyring. On Linux without Secret Service (common
@@ -41,7 +42,7 @@ If a grant or registered client becomes invalid, run `login` again. The client
41
42
  discards the invalid local credentials and starts a new browser authorization;
42
43
  the callback page confirms success only after the token exchange and account
43
44
  check succeed.
44
- `npx --yes @captionbolt/mcp@0.3.1 logout` (or `captionbolt-mcp logout`)
45
+ `npx --yes @captionbolt/mcp@0.3.2 logout` (or `captionbolt-mcp logout`)
45
46
  deletes local authorization. Revoke server access in
46
47
  CaptionBolt settings when you want to invalidate the grant.
47
48
  `CAPTIONBOLT_API_URL` optionally selects an explicitly trusted HTTPS API origin;
package/dist/index.mjs CHANGED
@@ -504,6 +504,17 @@ function fileStore(origin2, path = join(
504
504
  }
505
505
  };
506
506
  }
507
+ function keyringStore(entry2, location) {
508
+ return {
509
+ location,
510
+ getPassword() {
511
+ const secret = entry2.getSecret();
512
+ return secret && Buffer.from(secret).toString("utf8");
513
+ },
514
+ setPassword: (value) => entry2.setSecret(Buffer.from(value, "utf8")),
515
+ deletePassword: () => entry2.deletePassword()
516
+ };
517
+ }
507
518
  async function entry(origin2) {
508
519
  let Entry;
509
520
  try {
@@ -513,11 +524,11 @@ async function entry(origin2) {
513
524
  if (process.platform === "linux") {
514
525
  try {
515
526
  if (Entry) {
516
- return Object.assign(
527
+ return keyringStore(
517
528
  new Entry("captionbolt-mcp-oauth", origin2.origin, {
518
529
  linux: { store: "secret-service" }
519
530
  }),
520
- { location: "the Secret Service keyring" }
531
+ "the Secret Service keyring"
521
532
  );
522
533
  }
523
534
  } catch {
@@ -530,9 +541,10 @@ async function entry(origin2) {
530
541
  { kind: "invalid-response", code: "CREDENTIAL_STORE_UNAVAILABLE" }
531
542
  );
532
543
  }
533
- return Object.assign(new Entry("captionbolt-mcp-oauth", origin2.origin), {
534
- location: "the system credential store"
535
- });
544
+ return keyringStore(
545
+ new Entry("captionbolt-mcp-oauth", origin2.origin),
546
+ "the system credential store"
547
+ );
536
548
  }
537
549
  async function credentialLocation(origin2) {
538
550
  return (await entry(origin2)).location;
@@ -753,6 +765,7 @@ async function createLoginCallback() {
753
765
  },
754
766
  close() {
755
767
  server.close();
768
+ server.closeAllConnections();
756
769
  }
757
770
  };
758
771
  }
@@ -797,15 +810,33 @@ function isWsl() {
797
810
  return false;
798
811
  }
799
812
  }
813
+ var WSL_POWERSHELL = "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe";
814
+ function browserCommand(url, platform = process.platform, wsl = platform === "linux" && isWsl()) {
815
+ if (platform === "darwin") {
816
+ return ["open", [url.href]];
817
+ }
818
+ if (platform !== "win32" && !wsl) {
819
+ return ["xdg-open", [url.href]];
820
+ }
821
+ const script = `Start-Process '${url.href.replaceAll("'", "''")}'`;
822
+ return [
823
+ // appendWindowsPath=false removes Windows tools from the WSL PATH.
824
+ wsl && existsSync(WSL_POWERSHELL) ? WSL_POWERSHELL : "powershell.exe",
825
+ [
826
+ "-NoProfile",
827
+ "-NonInteractive",
828
+ "-EncodedCommand",
829
+ Buffer.from(script, "utf16le").toString("base64")
830
+ ]
831
+ ];
832
+ }
800
833
  function openBrowser(url) {
801
- const command2 = process.platform === "darwin" ? ["open", url.href] : process.platform === "win32" ? ["cmd", "/c", "start", "", url.href] : isWsl() ? [
802
- // appendWindowsPath=false removes explorer.exe from PATH.
803
- existsSync("/mnt/c/Windows/explorer.exe") ? "/mnt/c/Windows/explorer.exe" : "explorer.exe",
804
- url.href
805
- ] : ["xdg-open", url.href];
806
- const child = spawn(command2[0] ?? "xdg-open", command2.slice(1), {
834
+ const [command2, args] = browserCommand(url);
835
+ const child = spawn(command2, args, {
807
836
  stdio: "ignore",
808
- detached: true
837
+ // A detached PowerShell on native Windows exits without opening the browser.
838
+ detached: process.platform !== "win32",
839
+ windowsHide: true
809
840
  });
810
841
  child.on("error", () => {
811
842
  });
@@ -1308,7 +1339,7 @@ var LocalDownloads = class {
1308
1339
 
1309
1340
  // src/instructions.ts
1310
1341
  var localMcpInstructions = `CaptionBolt adds styled captions to the user's existing videos and keeps the original framing. A typical request is "add captions to <file>".
1311
- 1. Use the exact absolute path of the video the user named. Resolve a relative path or bare file name against your working directory; if that file does not exist, ask for the full path. Never search other folders. Call upload_file right away; it keeps uploading in the background.
1342
+ 1. Use the exact absolute path of the video the user named. Resolve a relative path or bare file name against your working directory; if that file does not exist, ask for the full path. On WSL, a Windows path such as C:\\Users\\... is /mnt/c/Users/... Never search other folders. Call upload_file right away; it keeps uploading in the background.
1312
1343
  2. While it uploads, ask one question unless the user already chose a style or preset or asked you to decide. Offer the list_styles items marked recommended (numbered, name plus one-line description) and at most the first three list_presets entries (most recently updated). The user can reply with a number, describe a look (search list_styles) or say "you decide" (use the first recommended style). Never list the whole catalog. You may mention the remaining minutes (get_account credits.availableCreditsSec / 60).
1313
1344
  3. Poll get_upload_progress. Once uploaded, call create_project with uploadSessionId set to its uploadId, the chosen styleId or presetId, and mode auto-export. The export includes the MP4 and the subtitle files the plan allows. Use review only when the user wants to check captions in the Editor first.
1314
1345
  4. create_project, export_project, retry_project and cancel_project return an operation: poll get_operation until it completes; its resourceId is the projectId. If it fails, report the error and stop. Then call wait_for_project until the project is completed (inspect autoExport if it stays ready). Keep progress updates short.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "private": false,
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22.12.0"