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.
- package/README.md +25 -0
- package/bundle/cli.js +46 -22
- 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
|
|
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
|
|
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
|
|
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 ??
|
|
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
|
|
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
|
|
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:
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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:${
|
|
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 =
|
|
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 : {
|
|
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
|
|
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(
|
|
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.
|
|
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",
|