lockpicks 0.8.0-go.10 → 0.8.0-go.11

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
@@ -5,7 +5,7 @@ Read your Lockpick results from the terminal, and give coding agents the same ac
5
5
  ## Sign in
6
6
 
7
7
  ```bash
8
- npx lockpicks login --host https://<your-lockpick>
8
+ npx --allow-scripts=lockpicks lockpicks@latest login --host https://<your-lockpick>
9
9
  ```
10
10
 
11
11
  The browser opens a device page. Confirm the code, pick a workspace and approve. To let the key start Pulse scans, tick **Start Pulse scans on sites I own or may test** under **Also allow**; that box is your statement that you own the workspace's sites or may test them, and each Pulse started with the key is recorded under your name. Without it the key only reads. **Add and switch sites** lets the key add sites (`lockpick sites add`) and switch your free site. **Prepare Deep scans I approve** lets the key prepare Deep scans (`lockpick deep`); each still needs a verified ownership proof and your approval of that exact scan in Lockpick. `lockpick login --pulse --sites --deep` marks what the terminal asks for, but the browser never ticks anything for you and the key gets exactly what you tick. `lockpick whoami` shows what the key can do. The terminal receives a key bound to that workspace, stored in your OS keychain (or `~/.config/lockpick/config.json`, mode 0600, when no keychain is available). Each use extends the key; an idle key expires after the workspace's lifetime (30 days by default). Revoke it with `lockpick logout` or in the web app under **Workspace settings → CLI & agent access**.
@@ -13,10 +13,12 @@ The browser opens a device page. Confirm the code, pick a workspace and approve.
13
13
  After an `npx` login, the CLI offers to install itself so you can type `lockpick` (or `lockpicks`) instead of `npx lockpicks`. To do it yourself:
14
14
 
15
15
  ```bash
16
- npm install -g lockpicks
16
+ npm install -g --allow-scripts=lockpicks lockpicks
17
17
  ```
18
18
 
19
- With it installed, `lockpick mcp config` points agents at `lockpick mcp`; without it, at `npx -y lockpicks mcp`.
19
+ `--allow-scripts=lockpicks` lets npm 12 run the install script that makes `lockpick` the native binary; npm 10 and 11 accept it (npm 11 prints a warning you can ignore). With npx it goes before the package name, and the package is `lockpicks@latest`: with a bare name npx runs whatever `lockpicks` is installed globally, however old. In a project, npm 12 refuses the flag: allow the script in `package.json` with `"allowScripts": { "lockpicks": true }` instead.
20
+
21
+ With it installed (the same version you run), `lockpick mcp config` points agents at `lockpick mcp`; otherwise, an older global install included, at `npx -y --allow-scripts=lockpicks lockpicks@latest mcp`.
20
22
 
21
23
  Use HTTPS for a remote Lockpick host; a host without a scheme (`lockpick.app`) means HTTPS, and a local one (`studio-mac:3000`) means HTTP. HTTP is accepted for local network and Tailscale development hosts. The CLI never follows redirects during API calls, so a saved key stays on its selected host: when a host only moves to its canonical address (`lockpick.app` to `www.lockpick.app`), `login`, which sends no key, signs in there and saves that address, and every other command names the address to use. `--host` takes precedence over `LOCKPICK_HOST`, which takes precedence over the last login. Each host has its own saved profile; `lockpick logout --host <url>` revokes and removes only that host's key. When the OS keychain is unavailable, the CLI writes the config through a private temporary file and replaces the old file only after the new one is complete. If the config is damaged, repair it before logging in again; the CLI will not silently discard saved profiles.
22
24
 
@@ -81,7 +83,7 @@ A new link checks every lockfile in the repository (at most 20, the most-used la
81
83
 
82
84
  `lockpick share create <runId>` publishes a completed Pulse result at a public link (a key allowed to start Pulses). Lockpick shows the link only to the call that makes it: run it again and it says the result is already shared, with no link; `--replace` makes a new link and the old one stops working, and `lockpick share revoke` stops sharing. `lockpick export <runId> --out <file>` writes the scan's PDF to exactly that file, creating it so that an existing file is never replaced unless you pass `--force`.
83
85
 
84
- `--fail-on critical|high|medium|low` on `pulse`, `recheck`, `watch`, `deep start` and `findings` exits `8` when open findings are that severe or worse, for CI. `lockpick ci init <site>` writes a GitHub Actions workflow that runs `npx -y lockpicks@<this version> pulse <site> --fail-on high` with the key from the `LOCKPICK_KEY` repository secret; it runs on published releases and by hand only, because each run uses a Pulse.
86
+ `--fail-on critical|high|medium|low` on `pulse`, `recheck`, `watch`, `deep start` and `findings` exits `8` when open findings are that severe or worse, for CI. `lockpick ci init <site>` writes a GitHub Actions workflow that runs `npx -y --allow-scripts=lockpicks lockpicks@<this version> pulse <site> --fail-on high` with the key from the `LOCKPICK_KEY` repository secret; it runs on published releases and by hand only, because each run uses a Pulse.
85
87
 
86
88
  Text from scanned sites and saved briefs can carry terminal escape sequences. The CLI neutralizes every control character in API responses before printing them (an escape shows as `␛`), and keeps only its own colours on the way out, so a scanned page cannot clear your screen, write your clipboard or hide a link. Ids are checked before they go into a URL, and the key is never printed, even when a server error repeats it.
87
89
 
@@ -1,4 +1,4 @@
1
- The lockpicks package contains only Lockpick's own launcher (bin/lockpick.cjs)
2
- and no third-party code. The Lockpick CLI binary it runs comes in the matching
1
+ The lockpicks package contains only Lockpick's own launcher (bin/lockpick.exe)
2
+ and install script (install.cjs), and no third-party code. The Lockpick CLI binary it runs comes in the matching
3
3
  @lockpicks/cli-<os>-<cpu> package, whose THIRD-PARTY-NOTICES.txt lists Go and every
4
4
  module linked into that binary.
@@ -1,14 +1,18 @@
1
1
  #!/usr/bin/env node
2
- // The `lockpicks` npm shim for the Go build of the Lockpick CLI: it finds the
3
- // platform package npm installed (`@lockpicks/cli-<os>-<cpu>`, an optional
4
- // dependency) and runs its binary.
5
- // It has no install scripts. LOCKPICK_LAUNCH tells the binary how it was
6
- // launched, decided from this script's path exactly as the TypeScript CLI's
7
- // launchKind decides it from its own.
2
+ // The `lockpicks` npm launcher for the Go build of the Lockpick CLI, shipped
3
+ // as bin/lockpick.exe: it finds the platform package npm installed
4
+ // (`@lockpicks/cli-<os>-<cpu>`, an optional dependency) and runs its binary.
5
+ // The preinstall script (install.cjs) replaces this file with that binary
6
+ // wherever the package manager allows, so this is the fallback: install
7
+ // scripts skipped (`--ignore-scripts`, pnpm, bun without trust), yarn 2 and
8
+ // later, or yarn 1 and bun on Windows. LOCKPICK_LAUNCH tells the binary how
9
+ // it was launched, decided from this script's path exactly as the TypeScript
10
+ // CLI's launchKind decides it from its own (and as the binary decides it
11
+ // from its own path when it is the command).
8
12
  'use strict';
9
13
 
10
14
  const { spawn } = require('node:child_process');
11
- const { realpathSync } = require('node:fs');
15
+ const { readFileSync, realpathSync } = require('node:fs');
12
16
  const { delimiter, join, sep } = require('node:path');
13
17
 
14
18
  const PACKAGE_DIR = `${sep}lockpicks${sep}`;
@@ -21,7 +25,29 @@ function real(path) {
21
25
  }
22
26
  }
23
27
 
24
- function launchKind(script, pathEnv) {
28
+ // The version of the lockpicks install that holds file, or null.
29
+ function installedVersion(file) {
30
+ const at = file.lastIndexOf(PACKAGE_DIR);
31
+ if (at < 0) return null;
32
+ try {
33
+ const manifest = JSON.parse(
34
+ readFileSync(
35
+ join(file.slice(0, at + PACKAGE_DIR.length), 'package.json'),
36
+ 'utf8'
37
+ )
38
+ );
39
+ return manifest.name === 'lockpicks' && typeof manifest.version === 'string'
40
+ ? manifest.version
41
+ : null;
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ // `path` when a `lockpick` on PATH is this file or another install of this
48
+ // package at this version (an older or newer global must not take over an
49
+ // npx run's MCP entry); then `npx`, `package` or `checkout`.
50
+ function launchKind(script, pathEnv, version) {
25
51
  const self = real(script) ?? script;
26
52
  const parts = self.split(sep);
27
53
  const installed = parts.includes('node_modules');
@@ -32,7 +58,7 @@ function launchKind(script, pathEnv) {
32
58
  : null;
33
59
  return (
34
60
  found !== null &&
35
- (found === self || (installed && found.includes(PACKAGE_DIR)))
61
+ (found === self || (installed && installedVersion(found) === version))
36
62
  );
37
63
  });
38
64
  if (onPath) return 'path';
@@ -45,9 +71,10 @@ function launchKind(script, pathEnv) {
45
71
  // file into its environment before any JavaScript runs: a `NODE_OPTIONS` in
46
72
  // it has already run its preloads by now, and its other variables would
47
73
  // reach the binary. That is Node's behaviour, met by every Node launcher, and
48
- // nothing here can undo it; the CLI's flag for a repository's env file is
49
- // `--dotenv` so no one is told to pass it. Refuse the old name rather than
50
- // hand the binary an environment the file chose.
74
+ // nothing here can undo it (the binary as the command, above, never meets
75
+ // it); the CLI's flag for a repository's env file is `--dotenv` so no one is
76
+ // told to pass it. Refuse the old name rather than hand the binary an
77
+ // environment the file chose.
51
78
  const args = process.argv.slice(2);
52
79
  const end = args.indexOf('--');
53
80
  const nodeEnvFile = (end === -1 ? args : args.slice(0, end)).find((arg) =>
@@ -79,8 +106,8 @@ try {
79
106
  ? `✖ Lockpick's binary for ${process.platform}-${process.arch} (the npm package ${target}) is not installed.\n` +
80
107
  'npm skips it when optional dependencies are turned off (--omit=optional, --no-optional or omit=optional in an npmrc),\n' +
81
108
  'or when a registry mirror does not carry it. Reinstall with optional dependencies:\n' +
82
- ` npm install -g lockpicks@${version} --include=optional (a global install)\n` +
83
- ` npm install lockpicks@${version} --include=optional (in a project)\n` +
109
+ ` npm install -g --allow-scripts=lockpicks lockpicks@${version} --include=optional (a global install)\n` +
110
+ ` npm install lockpicks@${version} --include=optional (in a project)\n` +
84
111
  `If it is still missing, check \`npm config get omit\` and that your registry serves ${target}.\n`
85
112
  : `✖ Lockpick has no build for ${process.platform}-${process.arch}.\n` +
86
113
  'The Node.js build of the CLI runs anywhere Node.js does: npm install -g lockpicks@0.7\n'
@@ -97,7 +124,11 @@ const child = spawn(binary, args, {
97
124
  stdio: 'inherit',
98
125
  env: {
99
126
  ...process.env,
100
- LOCKPICK_LAUNCH: launchKind(process.argv[1] ?? '', process.env.PATH ?? ''),
127
+ LOCKPICK_LAUNCH: launchKind(
128
+ process.argv[1] ?? '',
129
+ process.env.PATH ?? '',
130
+ require('../package.json').version
131
+ ),
101
132
  LOCKPICK_LAUNCHER_PID: String(process.pid),
102
133
  },
103
134
  });
package/install.cjs ADDED
@@ -0,0 +1,81 @@
1
+ // The `lockpicks` preinstall script: it puts this platform's Lockpick binary
2
+ // where npm links the `lockpick` and `lockpicks` commands, so they run the
3
+ // binary itself and Node never reads their arguments (Node loads an
4
+ // `--env-file` named anywhere on its own command line before any JavaScript
5
+ // runs, a `NODE_OPTIONS` preload in it included).
6
+ //
7
+ // bin/lockpick.exe ships as the JavaScript launcher (lockpick.cjs). This
8
+ // script replaces it with a hard link to, or a copy of, the binary in
9
+ // `@lockpicks/cli-<os>-<cpu>`, only where the package manager links the
10
+ // commands after this script runs and runs the file they name as it is:
11
+ //
12
+ // - npm, everywhere (install, ci, update, rebuild, exec and npx link bins
13
+ // after preinstall; on Windows cmd-shim then sees no `#!` and calls the
14
+ // .exe directly). npm 12 runs it only when allowed
15
+ // (`--allow-scripts=lockpicks`, or the `allow-scripts` config);
16
+ // - yarn 1 and bun, on macOS and Linux, which link commands as symlinks.
17
+ //
18
+ // Anywhere else (pnpm, whose command scripts can already say `node <file>`
19
+ // when its build runs, as after `pnpm approve-builds`; yarn 2 and later, which
20
+ // run every bin with Node; yarn 1 and bun on Windows, whose shims are written
21
+ // before the script; `--ignore-scripts` or npm 12 without allow-scripts; a
22
+ // skipped optional dependency) the
23
+ // JavaScript launcher stays and runs the binary as before. Nothing here
24
+ // fails an install, reaches the network or runs the binary.
25
+ 'use strict';
26
+
27
+ const fs = require('node:fs');
28
+ const { dirname, join } = require('node:path');
29
+
30
+ function linksAfterScript(agent, platform) {
31
+ if (/^npm\//.test(agent)) return true;
32
+ return platform !== 'win32' && /^(?:yarn\/1\.|bun\/)/.test(agent);
33
+ }
34
+
35
+ function install() {
36
+ if (
37
+ !linksAfterScript(process.env.npm_config_user_agent ?? '', process.platform)
38
+ )
39
+ return;
40
+ const { version } = require('./package.json');
41
+ const target = `@lockpicks/cli-${process.platform}-${process.arch}`;
42
+ let manifest;
43
+ try {
44
+ manifest = require.resolve(`${target}/package.json`, {
45
+ paths: [__dirname],
46
+ });
47
+ } catch {
48
+ return; // optional dependencies skipped, or no build for this platform
49
+ }
50
+ // A hoisted copy of another version is not this package's binary.
51
+ if (require(manifest).version !== version) return;
52
+ const binary = join(
53
+ dirname(manifest),
54
+ 'bin',
55
+ process.platform === 'win32' ? 'lockpick.exe' : 'lockpick'
56
+ );
57
+ if (!fs.statSync(binary).isFile()) return;
58
+ // Renamed into place, never written through: bun and pnpm hard-link
59
+ // package files from their stores, and a half-written launcher must never
60
+ // be left behind.
61
+ const launcher = join(__dirname, 'bin', 'lockpick.exe');
62
+ const temp = `${launcher}.${process.pid}.tmp`;
63
+ try {
64
+ fs.rmSync(temp, { force: true });
65
+ try {
66
+ fs.linkSync(binary, temp);
67
+ } catch {
68
+ fs.copyFileSync(binary, temp);
69
+ }
70
+ fs.chmodSync(temp, 0o755);
71
+ fs.renameSync(temp, launcher);
72
+ } finally {
73
+ fs.rmSync(temp, { force: true });
74
+ }
75
+ }
76
+
77
+ try {
78
+ install();
79
+ } catch {
80
+ // The JavaScript launcher is still in place and runs the binary.
81
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bin": {
3
- "lockpick": "bin/lockpick.cjs",
4
- "lockpicks": "bin/lockpick.cjs"
3
+ "lockpick": "bin/lockpick.exe",
4
+ "lockpicks": "bin/lockpick.exe"
5
5
  },
6
6
  "description": "Lockpick from the terminal: device login, project status, findings, repair briefs, Pulse scans and an MCP server for coding agents",
7
7
  "engines": {
@@ -9,6 +9,7 @@
9
9
  },
10
10
  "files": [
11
11
  "bin",
12
+ "install.cjs",
12
13
  "README.md",
13
14
  "LICENSE",
14
15
  "THIRD-PARTY-NOTICES.txt"
@@ -23,13 +24,13 @@
23
24
  "license": "SEE LICENSE IN LICENSE",
24
25
  "name": "lockpicks",
25
26
  "optionalDependencies": {
26
- "@lockpicks/cli-darwin-arm64": "0.8.0-go.10",
27
- "@lockpicks/cli-darwin-x64": "0.8.0-go.10",
28
- "@lockpicks/cli-linux-arm": "0.8.0-go.10",
29
- "@lockpicks/cli-linux-arm64": "0.8.0-go.10",
30
- "@lockpicks/cli-linux-x64": "0.8.0-go.10",
31
- "@lockpicks/cli-win32-arm64": "0.8.0-go.10",
32
- "@lockpicks/cli-win32-x64": "0.8.0-go.10"
27
+ "@lockpicks/cli-darwin-arm64": "0.8.0-go.11",
28
+ "@lockpicks/cli-darwin-x64": "0.8.0-go.11",
29
+ "@lockpicks/cli-linux-arm": "0.8.0-go.11",
30
+ "@lockpicks/cli-linux-arm64": "0.8.0-go.11",
31
+ "@lockpicks/cli-linux-x64": "0.8.0-go.11",
32
+ "@lockpicks/cli-win32-arm64": "0.8.0-go.11",
33
+ "@lockpicks/cli-win32-x64": "0.8.0-go.11"
33
34
  },
34
35
  "publishConfig": {
35
36
  "access": "public"
@@ -39,5 +40,8 @@
39
40
  "type": "git",
40
41
  "url": "git+https://github.com/promptadvisers/lockpick.git"
41
42
  },
42
- "version": "0.8.0-go.10"
43
+ "scripts": {
44
+ "preinstall": "node install.cjs"
45
+ },
46
+ "version": "0.8.0-go.11"
43
47
  }