@chainpatrol/cli 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/CHANGELOG.md +25 -0
- package/dist/{chunk-T4DYUWUD.js → chunk-S7PQNG4E.js} +28 -4
- package/dist/chunk-ZVM45CTB.js +19 -0
- package/dist/cli.js +5 -5
- package/dist/{login-G7LPHKDR.js → login-ML2EKF44.js} +27 -7
- package/dist/{login-json-LKB72OFY.js → login-json-Y3AIQIIB.js} +5 -1
- package/dist/{setup-skill-ZUZ5MYLI.js → setup-skill-XZRLJE3A.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 06ff227: `chainpatrol login`:
|
|
8
|
+
|
|
9
|
+
- Skip the browser auto-open when running in a headless / cloud context
|
|
10
|
+
(Claude Code on the web, GitHub Codespaces, Gitpod, Replit, CI, plain
|
|
11
|
+
SSH sessions, or Linux without a display server). Detection is opt-in
|
|
12
|
+
overridable with `CHAINPATROL_HEADLESS=1` / `CHAINPATROL_HEADLESS=0`.
|
|
13
|
+
- Print `verification_uri_complete` as the primary, one-step link when
|
|
14
|
+
the server returns it, so a copy-paste to another device (e.g. a
|
|
15
|
+
phone) works without separately typing the user code. The bare
|
|
16
|
+
`verification_uri` + code is shown as a fallback.
|
|
17
|
+
- `login --json` output now includes a `headless` boolean so automation
|
|
18
|
+
can adapt the way it presents the URL.
|
|
19
|
+
|
|
20
|
+
Claude Code skill bundled with the CLI:
|
|
21
|
+
|
|
22
|
+
- Stop hard-coding `/usr/local/bin/chainpatrol`. The "Running the CLI"
|
|
23
|
+
section now documents typical local vs cloud install locations
|
|
24
|
+
(e.g. `/opt/node*/bin/chainpatrol`), includes a command to discover
|
|
25
|
+
the binary path, and tells the assistant to substitute the resolved
|
|
26
|
+
full path in all invocations.
|
|
27
|
+
|
|
3
28
|
## 0.3.1
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -97,15 +97,39 @@ platform using the CLI tool.
|
|
|
97
97
|
|
|
98
98
|
## Running the CLI
|
|
99
99
|
|
|
100
|
-
IMPORTANT: Claude Code's sandbox shell has a minimal PATH
|
|
101
|
-
|
|
100
|
+
IMPORTANT: Claude Code's sandbox shell often has a minimal PATH
|
|
101
|
+
(\`/usr/bin:/bin:/usr/sbin:/sbin\`) that may not include the directory where
|
|
102
|
+
\`chainpatrol\` is installed, so bare \`chainpatrol\` calls may fail with
|
|
103
|
+
"command not found". Always invoke the CLI by its full path.
|
|
104
|
+
|
|
105
|
+
The install location depends on the environment:
|
|
106
|
+
|
|
107
|
+
- **Local installs** typically land at \`/usr/local/bin/chainpatrol\` (when
|
|
108
|
+
installed globally via \`npm install -g @chainpatrol/cli\`).
|
|
109
|
+
- **Cloud / sandboxed environments** (e.g. Claude Code on the web, Cursor
|
|
110
|
+
Cloud) often install Node into \`/opt\` and the binary ends up under a
|
|
111
|
+
Node-version-specific path like \`/opt/node22/bin/chainpatrol\`. Variants
|
|
112
|
+
such as \`/opt/node20/bin/chainpatrol\` or \`/opt/node21/bin/chainpatrol\`
|
|
113
|
+
are also possible depending on which Node version is active.
|
|
114
|
+
|
|
115
|
+
To find the binary, try (in order):
|
|
116
|
+
|
|
117
|
+
\`\`\`bash
|
|
118
|
+
command -v chainpatrol \\
|
|
119
|
+
|| ls /usr/local/bin/chainpatrol /opt/node*/bin/chainpatrol 2>/dev/null \\
|
|
120
|
+
| head -n 1
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
Then use that full path for every subsequent command, e.g.:
|
|
102
124
|
|
|
103
125
|
\`\`\`bash
|
|
126
|
+
/opt/node22/bin/chainpatrol <command> [options]
|
|
127
|
+
# or
|
|
104
128
|
/usr/local/bin/chainpatrol <command> [options]
|
|
105
129
|
\`\`\`
|
|
106
130
|
|
|
107
|
-
All examples below use the short name for readability, but you
|
|
108
|
-
|
|
131
|
+
All examples below use the short name \`chainpatrol\` for readability, but you
|
|
132
|
+
MUST substitute the full resolved path in your Bash commands.
|
|
109
133
|
|
|
110
134
|
## Available Commands
|
|
111
135
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/lib/headless.ts
|
|
2
|
+
function isHeadlessEnv(env = process.env, platform = process.platform) {
|
|
3
|
+
if (env.CHAINPATROL_HEADLESS === "1") return true;
|
|
4
|
+
if (env.CHAINPATROL_HEADLESS === "0") return false;
|
|
5
|
+
if (env.CLAUDE_CODE_REMOTE === "true") return true;
|
|
6
|
+
if (env.CODESPACES === "true") return true;
|
|
7
|
+
if (env.GITPOD_WORKSPACE_ID) return true;
|
|
8
|
+
if (env.REPL_ID) return true;
|
|
9
|
+
if (env.CI === "true") return true;
|
|
10
|
+
if (env.SSH_CONNECTION || env.SSH_TTY) return true;
|
|
11
|
+
if (platform === "linux" && !env.DISPLAY && !env.WAYLAND_DISPLAY && !env.MIR_SOCKET) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
isHeadlessEnv
|
|
19
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getCliVersion,
|
|
14
14
|
isSkillInstalled,
|
|
15
15
|
readInstalledSkillVersion
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-S7PQNG4E.js";
|
|
17
17
|
import "./chunk-IUZB3DQW.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
@@ -746,11 +746,11 @@ async function main() {
|
|
|
746
746
|
);
|
|
747
747
|
}
|
|
748
748
|
if (jsonMode) {
|
|
749
|
-
const { loginJson } = await import("./login-json-
|
|
749
|
+
const { loginJson } = await import("./login-json-Y3AIQIIB.js");
|
|
750
750
|
await loginJson();
|
|
751
751
|
} else {
|
|
752
752
|
const { render } = await import("ink");
|
|
753
|
-
const { default: Login } = await import("./login-
|
|
753
|
+
const { default: Login } = await import("./login-ML2EKF44.js");
|
|
754
754
|
const { default: React } = await import("react");
|
|
755
755
|
render(React.createElement(Login));
|
|
756
756
|
}
|
|
@@ -1029,12 +1029,12 @@ async function main() {
|
|
|
1029
1029
|
case "setup":
|
|
1030
1030
|
case "install":
|
|
1031
1031
|
case "i": {
|
|
1032
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1032
|
+
const { setupSkill } = await import("./setup-skill-XZRLJE3A.js");
|
|
1033
1033
|
setupSkill({ json: jsonMode });
|
|
1034
1034
|
break;
|
|
1035
1035
|
}
|
|
1036
1036
|
case "uninstall": {
|
|
1037
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1037
|
+
const { uninstallSkill } = await import("./setup-skill-XZRLJE3A.js");
|
|
1038
1038
|
uninstallSkill({ json: jsonMode });
|
|
1039
1039
|
break;
|
|
1040
1040
|
}
|
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
ErrorDisplay,
|
|
3
3
|
Spinner
|
|
4
4
|
} from "./chunk-JCMWDZYY.js";
|
|
5
|
+
import {
|
|
6
|
+
isHeadlessEnv
|
|
7
|
+
} from "./chunk-ZVM45CTB.js";
|
|
5
8
|
import {
|
|
6
9
|
fetchUserEmail,
|
|
7
10
|
getCredentials,
|
|
@@ -43,9 +46,11 @@ function Login() {
|
|
|
43
46
|
setState({ phase: "requesting-code" });
|
|
44
47
|
requestDeviceCode().then((deviceCode) => {
|
|
45
48
|
setState({ phase: "waiting-for-approval", deviceCode });
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
if (!isHeadlessEnv()) {
|
|
50
|
+
const uri = deviceCode.verification_uri_complete ?? deviceCode.verification_uri;
|
|
51
|
+
open(uri).catch(() => {
|
|
52
|
+
});
|
|
53
|
+
}
|
|
49
54
|
}).catch((err) => {
|
|
50
55
|
setState({
|
|
51
56
|
phase: "error",
|
|
@@ -130,19 +135,34 @@ function Login() {
|
|
|
130
135
|
] });
|
|
131
136
|
case "requesting-code":
|
|
132
137
|
return /* @__PURE__ */ jsx(Spinner, { label: "Requesting device code..." });
|
|
133
|
-
case "waiting-for-approval":
|
|
138
|
+
case "waiting-for-approval": {
|
|
139
|
+
const completeUri = state.deviceCode.verification_uri_complete;
|
|
134
140
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 1, children: [
|
|
135
141
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
136
|
-
/* @__PURE__ */ jsx(Text, { children: "Your code
|
|
142
|
+
/* @__PURE__ */ jsx(Text, { children: "Your code: " }),
|
|
137
143
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: state.deviceCode.user_code.length === 8 ? `${state.deviceCode.user_code.slice(0, 4)}-${state.deviceCode.user_code.slice(4)}` : state.deviceCode.user_code })
|
|
138
144
|
] }),
|
|
139
|
-
/* @__PURE__ */ jsxs(
|
|
145
|
+
completeUri ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
146
|
+
/* @__PURE__ */ jsx(Text, { children: "Open this URL on any device to approve in one step:" }),
|
|
147
|
+
/* @__PURE__ */ jsxs(Text, { color: "blue", underline: true, children: [
|
|
148
|
+
" ",
|
|
149
|
+
completeUri
|
|
150
|
+
] }),
|
|
151
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
152
|
+
"Or visit ",
|
|
153
|
+
state.deviceCode.verification_uri,
|
|
154
|
+
" and enter the code above."
|
|
155
|
+
] })
|
|
156
|
+
] }) : /* @__PURE__ */ jsxs(Text, { children: [
|
|
140
157
|
"Open this URL in your browser:",
|
|
141
158
|
" ",
|
|
142
|
-
/* @__PURE__ */ jsx(Text, { color: "blue", underline: true, children: state.deviceCode.verification_uri })
|
|
159
|
+
/* @__PURE__ */ jsx(Text, { color: "blue", underline: true, children: state.deviceCode.verification_uri }),
|
|
160
|
+
" ",
|
|
161
|
+
"and enter the code above."
|
|
143
162
|
] }),
|
|
144
163
|
/* @__PURE__ */ jsx(Spinner, { label: "Waiting for approval..." })
|
|
145
164
|
] });
|
|
165
|
+
}
|
|
146
166
|
case "success":
|
|
147
167
|
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
148
168
|
/* @__PURE__ */ jsx(Text, { color: "green", bold: true, children: "\u2713" }),
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isHeadlessEnv
|
|
3
|
+
} from "./chunk-ZVM45CTB.js";
|
|
1
4
|
import {
|
|
2
5
|
fetchUserEmail,
|
|
3
6
|
getCredentials,
|
|
@@ -24,7 +27,8 @@ async function loginJson() {
|
|
|
24
27
|
user_code: deviceCode.user_code,
|
|
25
28
|
verification_uri: deviceCode.verification_uri,
|
|
26
29
|
verification_uri_complete: deviceCode.verification_uri_complete ?? null,
|
|
27
|
-
expires_in: deviceCode.expires_in
|
|
30
|
+
expires_in: deviceCode.expires_in,
|
|
31
|
+
headless: isHeadlessEnv()
|
|
28
32
|
})
|
|
29
33
|
);
|
|
30
34
|
let interval = deviceCode.interval * 1e3;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@chainpatrol/cli",
|
|
3
3
|
"description": "The official ChainPatrol CLI — terminal interface for threat detection",
|
|
4
4
|
"author": "Umar Ahmed <umar@chainpatrol.io>",
|
|
5
|
-
"version": "0.3.
|
|
5
|
+
"version": "0.3.2",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|