promptlock-cli 1.0.1 → 1.0.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.
Files changed (3) hide show
  1. package/README.md +25 -0
  2. package/bundle/cli.js +46 -22
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -16,6 +16,31 @@ npx promptlock-cli connect
16
16
  That detects your agents, opens a pairing window for the phone, installs the
17
17
  hooks, and offers to keep a small background daemon running across reboots.
18
18
 
19
+ ### Updating from 1.0.0 or 1.0.1 when the phone finds no accessories
20
+
21
+ Version 1.0.2 keeps the Bluetooth name within eight ASCII bytes so the name and
22
+ service UUID fit together in the initial advertisement. Longer Mac names get a
23
+ stable label such as `PL12AB34`. The pairing command prints the label to look for;
24
+ you must still compare and confirm the six digits on both devices.
25
+
26
+ Close any earlier `connect`, `pair`, or foreground `start` command with Ctrl-C.
27
+ Then update the background helper before pairing:
28
+
29
+ ```
30
+ npx promptlock-cli@1.0.2 service install
31
+ npx promptlock-cli@1.0.2 pair
32
+ ```
33
+
34
+ Leave `pair` running while opening **Pair Mac** on the iPhone. This change does
35
+ not require a new iPhone build. Simply running a newer `pair` command against an
36
+ older running helper does not update its Bluetooth advertisement.
37
+
38
+ If discovery still fails, run `npx promptlock-cli@1.0.2 status` in a second
39
+ terminal. The `ble.localName` field identifies the updated helper's requested
40
+ advertising name. `advertising` means macOS accepted the request; it does not
41
+ prove that the phone received the complete advertisement. `centrals: 0` counts
42
+ no current subscribers, not the phone's entire connection history.
43
+
19
44
  ## Commands
20
45
 
21
46
  ```
package/bundle/cli.js CHANGED
@@ -4077,8 +4077,15 @@ function timingSafeEqualStrings(a, b) {
4077
4077
  return crypto7.timingSafeEqual(x, y);
4078
4078
  }
4079
4079
 
4080
+ // src/transport/ble-name.ts
4081
+ var import_node_crypto = require("node:crypto");
4082
+ var import_node_os = require("node:os");
4083
+ function bleAdvertisementName(name = (0, import_node_os.hostname)().replace(/\.local$/i, "")) {
4084
+ if (/^[\x21-\x7e][\x20-\x7e]{0,7}$/.test(name)) return name;
4085
+ return `PL${(0, import_node_crypto.createHash)("sha256").update(name).digest("hex").slice(0, 6).toUpperCase()}`;
4086
+ }
4087
+
4080
4088
  // src/transport/ble-publisher.ts
4081
- var os5 = __toESM(require("node:os"));
4082
4089
  var import_core9 = __toESM(require_dist());
4083
4090
 
4084
4091
  // src/pairing-service.ts
@@ -4615,6 +4622,7 @@ var PairingService = class {
4615
4622
  this.send({
4616
4623
  e: "opened",
4617
4624
  windowMs: this.opts.windowMs ?? import_core8.PAIRING.windowMs,
4625
+ localName: this.opts.localName,
4618
4626
  bluetooth: bt.state,
4619
4627
  reason: bt.reason
4620
4628
  });
@@ -4631,6 +4639,7 @@ var PairingService = class {
4631
4639
  this.send({
4632
4640
  e: "opened",
4633
4641
  windowMs: this.window.remainingMs,
4642
+ localName: this.opts.localName,
4634
4643
  bluetooth: this.opts.bluetoothState?.().state ?? "unknown",
4635
4644
  reason: this.opts.bluetoothState?.().reason ?? null
4636
4645
  });
@@ -5428,7 +5437,11 @@ var BlePublisher = class {
5428
5437
  return this.pairing;
5429
5438
  }
5430
5439
  advertisedName() {
5431
- return this.opts.localName ?? os5.hostname().replace(/\.local$/i, "");
5440
+ return bleAdvertisementName(this.opts.localName);
5441
+ }
5442
+ /** Requested on-air name; a remote scan is still needed to verify reception. */
5443
+ get localName() {
5444
+ return this.advertisedName();
5432
5445
  }
5433
5446
  /**
5434
5447
  * Where the wifi link lives, computed the same way `LanServer.url` computes
@@ -5771,7 +5784,7 @@ var BlePublisher = class {
5771
5784
  // src/health.ts
5772
5785
  var crypto13 = __toESM(require("node:crypto"));
5773
5786
  var fs13 = __toESM(require("node:fs"));
5774
- var os11 = __toESM(require("node:os"));
5787
+ var os10 = __toESM(require("node:os"));
5775
5788
  var path13 = __toESM(require("node:path"));
5776
5789
  var import_core11 = __toESM(require_dist());
5777
5790
 
@@ -5783,7 +5796,7 @@ var path12 = __toESM(require("node:path"));
5783
5796
  var import_node_child_process6 = require("node:child_process");
5784
5797
  var crypto10 = __toESM(require("node:crypto"));
5785
5798
  var http2 = __toESM(require("node:http"));
5786
- var os6 = __toESM(require("node:os"));
5799
+ var os5 = __toESM(require("node:os"));
5787
5800
  var PairingError = class extends Error {
5788
5801
  constructor(failure, message) {
5789
5802
  super(message);
@@ -5812,7 +5825,7 @@ function openWithFinder(url) {
5812
5825
  async function pairWithRelay(opts) {
5813
5826
  const log = opts.log ?? ((m) => console.log(m));
5814
5827
  const base = opts.relayUrl.replace(/\/+$/, "");
5815
- const deviceName = opts.deviceName ?? os6.hostname();
5828
+ const deviceName = opts.deviceName ?? os5.hostname();
5816
5829
  const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
5817
5830
  const { verifier, challenge } = createPkcePair();
5818
5831
  const state = crypto10.randomBytes(16).toString("base64url");
@@ -5935,12 +5948,12 @@ var path9 = __toESM(require("node:path"));
5935
5948
  // src/service/launchd.ts
5936
5949
  var import_node_child_process8 = require("node:child_process");
5937
5950
  var fs10 = __toESM(require("node:fs"));
5938
- var os8 = __toESM(require("node:os"));
5951
+ var os7 = __toESM(require("node:os"));
5939
5952
 
5940
5953
  // src/service/runtime.ts
5941
5954
  var import_node_child_process7 = require("node:child_process");
5942
5955
  var fs9 = __toESM(require("node:fs"));
5943
- var os7 = __toESM(require("node:os"));
5956
+ var os6 = __toESM(require("node:os"));
5944
5957
  var path8 = __toESM(require("node:path"));
5945
5958
  function shq(value) {
5946
5959
  return `'${value.replace(/'/g, `'\\''`)}'`;
@@ -5951,7 +5964,7 @@ function nodeVersionOf(binary) {
5951
5964
  encoding: "utf8",
5952
5965
  timeout: 1e4,
5953
5966
  stdio: ["ignore", "pipe", "ignore"],
5954
- env: { PATH: "/usr/bin:/bin:/usr/sbin:/sbin", HOME: os7.homedir() }
5967
+ env: { PATH: "/usr/bin:/bin:/usr/sbin:/sbin", HOME: os6.homedir() }
5955
5968
  });
5956
5969
  const version = out.trim();
5957
5970
  return /^v\d+\./.test(version) ? version : null;
@@ -6075,7 +6088,7 @@ fi
6075
6088
  exec "$NODE" "$SCRIPT" start
6076
6089
  `;
6077
6090
  }
6078
- function fallbackNodePaths(home = os7.homedir()) {
6091
+ function fallbackNodePaths(home = os6.homedir()) {
6079
6092
  return [
6080
6093
  "/opt/homebrew/bin/node",
6081
6094
  "/usr/local/bin/node",
@@ -6207,7 +6220,7 @@ function plistXml(opts) {
6207
6220
  <string>Background</string>
6208
6221
 
6209
6222
  <key>WorkingDirectory</key>
6210
- <string>${escapeXml(os8.homedir())}</string>
6223
+ <string>${escapeXml(os7.homedir())}</string>
6211
6224
 
6212
6225
  <!-- Only what the daemon writes before it opens its own rotated log. -->
6213
6226
  <key>StandardOutPath</key>
@@ -6439,7 +6452,7 @@ async function cmdServiceStatus(log = (m) => console.log(m)) {
6439
6452
 
6440
6453
  // src/pairing.ts
6441
6454
  var http3 = __toESM(require("node:http"));
6442
- var os9 = __toESM(require("node:os"));
6455
+ var os8 = __toESM(require("node:os"));
6443
6456
  async function readStatus(port, secret, timeoutMs = 1500) {
6444
6457
  return new Promise((resolve2) => {
6445
6458
  const req = http3.request(
@@ -6488,7 +6501,12 @@ var LocalPairing = class {
6488
6501
  if (existing !== null) {
6489
6502
  const url = typeof existing.lan === "string" ? existing.lan : null;
6490
6503
  const ble = existing.ble;
6491
- return this.target(url, false, ble ? ble.state !== "unavailable" : false);
6504
+ return this.target(
6505
+ url,
6506
+ false,
6507
+ ble ? ble.state !== "unavailable" : false,
6508
+ ble?.localName ?? os8.hostname().replace(/\.local$/i, "")
6509
+ );
6492
6510
  }
6493
6511
  if (!this.startIfDown) return this.target(null, false, bleSupported());
6494
6512
  const bridge = new Bridge({ config: this.config, persist: false, log: this.log, ble: true });
@@ -6541,7 +6559,7 @@ var LocalPairing = class {
6541
6559
  * `packages/core/src/link.ts`, and a QR is not where a protocol constant
6542
6560
  * belongs.
6543
6561
  */
6544
- target(url, startedDaemon, ble) {
6562
+ target(url, startedDaemon, ble, localName = bleLocalName()) {
6545
6563
  const resolved = url ?? `ws://127.0.0.1:${this.config.lanPort}`;
6546
6564
  const params = [
6547
6565
  `url=${encodeURIComponent(resolved)}`,
@@ -6549,7 +6567,7 @@ var LocalPairing = class {
6549
6567
  ];
6550
6568
  if (ble) {
6551
6569
  params.push("ble=1");
6552
- params.push(`blename=${encodeURIComponent(bleLocalName())}`);
6570
+ params.push(`blename=${encodeURIComponent(localName)}`);
6553
6571
  }
6554
6572
  return {
6555
6573
  transport: "lan",
@@ -6568,7 +6586,7 @@ var LocalPairing = class {
6568
6586
  }
6569
6587
  };
6570
6588
  function bleLocalName() {
6571
- return os9.hostname().replace(/\.local$/i, "");
6589
+ return bleAdvertisementName();
6572
6590
  }
6573
6591
 
6574
6592
  // src/pairing-cli.ts
@@ -6610,6 +6628,7 @@ async function runPairingWindow(opts) {
6610
6628
  const onEvent = (event) => {
6611
6629
  switch (event.e) {
6612
6630
  case "opened":
6631
+ if (event.localName) log(` Look for ${event.localName} in the iPhone's accessory picker.`);
6613
6632
  if (event.bluetooth !== "advertising" && event.bluetooth !== "starting") {
6614
6633
  log(` Bluetooth: ${event.bluetooth}${event.reason ? ` \u2014 ${event.reason}` : ""}`);
6615
6634
  }
@@ -6733,7 +6752,7 @@ function restartManagedService(log) {
6733
6752
 
6734
6753
  // src/connection-test.ts
6735
6754
  var crypto12 = __toESM(require("node:crypto"));
6736
- var os10 = __toESM(require("node:os"));
6755
+ var os9 = __toESM(require("node:os"));
6737
6756
  var path11 = __toESM(require("node:path"));
6738
6757
 
6739
6758
  // src/simulate.ts
@@ -6969,7 +6988,7 @@ async function runConnectionTest(opts) {
6969
6988
  const log = opts.log ?? ((m) => console.log(m));
6970
6989
  const speed = opts.speedFactor ?? 1;
6971
6990
  const sessionId = `warpfocus-test-${crypto12.randomUUID().slice(0, 8)}`;
6972
- const workspaceRoot = path11.join(os10.tmpdir(), TEST_PROJECT_NAME);
6991
+ const workspaceRoot = path11.join(os9.tmpdir(), TEST_PROJECT_NAME);
6973
6992
  const problems = [];
6974
6993
  let delivered = true;
6975
6994
  let phones = null;
@@ -7860,7 +7879,7 @@ function untrusted(agent) {
7860
7879
  return trust === "untrusted" || trust === "partial";
7861
7880
  }
7862
7881
  function macId() {
7863
- return crypto13.createHash("sha256").update(`warpfocus:${os11.hostname()}:${os11.userInfo().username}`).digest("hex").slice(0, 32);
7882
+ return crypto13.createHash("sha256").update(`warpfocus:${os10.hostname()}:${os10.userInfo().username}`).digest("hex").slice(0, 32);
7864
7883
  }
7865
7884
  function daemonVersion() {
7866
7885
  try {
@@ -7890,7 +7909,7 @@ function deviceHealthFrom(facts, opts) {
7890
7909
  };
7891
7910
  }
7892
7911
  function hostLabel() {
7893
- const raw = os11.hostname().replace(/\.local$/i, "").trim();
7912
+ const raw = os10.hostname().replace(/\.local$/i, "").trim();
7894
7913
  return raw.length > 0 ? raw : null;
7895
7914
  }
7896
7915
  function healthChanged(a, b) {
@@ -8184,7 +8203,12 @@ var Bridge = class {
8184
8203
  receiver: this.receiver.address,
8185
8204
  lan: this.lan.url,
8186
8205
  cloud: this.cloud === null ? null : { url: this.cloud.url, state: this.cloud.state },
8187
- ble: this.ble === null ? null : { state: this.ble.state, reason: this.ble.reason, centrals: this.ble.centralCount },
8206
+ ble: this.ble === null ? null : {
8207
+ state: this.ble.state,
8208
+ reason: this.ble.reason,
8209
+ centrals: this.ble.centralCount,
8210
+ localName: this.ble.localName
8211
+ },
8188
8212
  health: this.health,
8189
8213
  // How many phones are attached. `connect` reads this to decide whether it
8190
8214
  // can honestly claim the connection test was observed.
@@ -8417,7 +8441,7 @@ var Bridge = class {
8417
8441
 
8418
8442
  // src/doctor.ts
8419
8443
  var crypto17 = __toESM(require("node:crypto"));
8420
- var os12 = __toESM(require("node:os"));
8444
+ var os11 = __toESM(require("node:os"));
8421
8445
  var path16 = __toESM(require("node:path"));
8422
8446
 
8423
8447
  // src/simulate-claude-code.ts
@@ -9092,7 +9116,7 @@ function formatRow(row) {
9092
9116
  }
9093
9117
  async function roundTrip(provider, port, secret) {
9094
9118
  const tag = `warpfocus-doctor-${crypto17.randomUUID().slice(0, 8)}`;
9095
- const root = path16.join(os12.tmpdir(), tag);
9119
+ const root = path16.join(os11.tmpdir(), tag);
9096
9120
  const sessionId = tag;
9097
9121
  const build = (cursorStep, claudeStep, codexStep) => {
9098
9122
  if (provider === "cursor") return cursorPayload(cursorStep, {}, { sessionId, workspaceRoot: root });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "promptlock-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "PromptLock for the Mac: watches Cursor, Claude Code and Codex, and tells your iPhone when an agent is working so it can unlock your apps only while one is.",
5
5
  "license": "MIT",
6
6
  "author": "Mark Guggenheim",