@phantomcodes/cli 1.2.0 → 1.2.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 +3 -16
- package/dist/agents/command.mjs +1 -1
- package/dist/cli/help.mjs +2 -3
- package/dist/cli/run.mjs +7 -1
- package/dist/core/node-trust.mjs +24 -0
- package/dist/core/version.mjs +1 -1
- package/dist/setup/apply.mjs +7 -0
- package/dist/workspace/command.mjs +7 -2
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -19,7 +19,6 @@ phantom setup --agent claude
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
The skill covers workspace setup, funding, spending controls and model routing.
|
|
22
|
-
[Skill docs](docs/guides/agent-skill.md)
|
|
23
22
|
|
|
24
23
|
## Let your agent set it up
|
|
25
24
|
|
|
@@ -65,7 +64,7 @@ key. Restart your agent, or open a new terminal, to use the connection.
|
|
|
65
64
|
|
|
66
65
|
Codex, Claude Code, opencode, Continue, Goose, Aider, GitHub Copilot CLI and Cline
|
|
67
66
|
support saved setup. Cursor gets instructions for its settings screen; pi gets
|
|
68
|
-
the agent skill.
|
|
67
|
+
the agent skill.
|
|
69
68
|
|
|
70
69
|
Preview without changing files with `phantom setup --dry-run`. The Phantom CLI keeps backups;
|
|
71
70
|
undo the changes with `phantom setup --restore`.
|
|
@@ -83,7 +82,6 @@ phantom codex
|
|
|
83
82
|
Both setup options require **Node 24+** and your coding agent installed. Connect, fund your
|
|
84
83
|
workspace, then launch **Codex** (`phantom codex`), **Claude Code** (`phantom claude`),
|
|
85
84
|
**pi** (`phantom pi`), or **any other compatible agent**.
|
|
86
|
-
[Set up other agents](docs/guides/agent-setup.md).
|
|
87
85
|
|
|
88
86
|
Login opens a device approval page and saves a key privately. Funding opens
|
|
89
87
|
checkout; check your workspace balance after payment. Agent runs use temporary
|
|
@@ -103,8 +101,6 @@ phantom fund --amount 10 --coin usdc
|
|
|
103
101
|
|
|
104
102
|
Credit is available after the payment is verified. Check balance anytime with `phantom balance`.
|
|
105
103
|
|
|
106
|
-
[Funding and payment details](docs/guides/buying-credit.md).
|
|
107
|
-
|
|
108
104
|
## Give each agent a budget
|
|
109
105
|
|
|
110
106
|
Create a key with its own cap, sharing your workspace balance:
|
|
@@ -132,7 +128,6 @@ PHANTOM_KEY_NAME=coding phantom route test --table
|
|
|
132
128
|
|
|
133
129
|
Prefer a specific model? Select it in your agent. Policies that apply only to
|
|
134
130
|
`auto` leave explicit model choices alone.
|
|
135
|
-
[Routing](docs/guides/routing.md) covers conditions, fallback and conversation affinity.
|
|
136
131
|
|
|
137
132
|
`phantom-1` picks a tier for each request: economy, standard or frontier. Your key's
|
|
138
133
|
lineup picks the model in each tier, and a fallback model to try when it fails:
|
|
@@ -199,13 +194,7 @@ Exit codes: 0 success, 1 error, 2 rejected key; agent runs return the agent's ex
|
|
|
199
194
|
<details>
|
|
200
195
|
<summary><strong>Advanced tools, integrations and legacy commands</strong></summary>
|
|
201
196
|
|
|
202
|
-
`phantom --help` shows the main workflows. `phantom --help --all`
|
|
203
|
-
[interface reference](docs/reference.md) cover every command.
|
|
204
|
-
|
|
205
|
-
- [Signed receipts](docs/guides/receipts.md): check which model answered with `phantom verify`.
|
|
206
|
-
- [Funding credit](docs/guides/buying-credit.md): `phantom fund` and checking payments.
|
|
207
|
-
- [Saved secrets](docs/guides/saved-secrets.md): macOS Keychain or private files; guest recovery uses `phantom workspace export` and `phantom workspace import`.
|
|
208
|
-
- [Key selection](docs/guides/which-key.md) and [API address](docs/guides/base-url.md): environment overrides and shell integration.
|
|
197
|
+
`phantom --help` shows the main workflows. `phantom --help --all` covers every command.
|
|
209
198
|
|
|
210
199
|
The older `phantom key` commands still work.
|
|
211
200
|
`phantom keys list` reads the workspace; `phantom keys saved` lists local copies.
|
|
@@ -221,11 +210,9 @@ npm ci
|
|
|
221
210
|
npm run typecheck
|
|
222
211
|
npm run build
|
|
223
212
|
npm run coverage
|
|
224
|
-
npm run docs
|
|
225
|
-
node scripts/gen-docs.mjs --check
|
|
226
213
|
```
|
|
227
214
|
|
|
228
|
-
|
|
215
|
+
Report a security problem privately to support@phantom.codes, not in a public issue.
|
|
229
216
|
|
|
230
217
|
</details>
|
|
231
218
|
|
package/dist/agents/command.mjs
CHANGED
|
@@ -26,7 +26,7 @@ export const AGENTS = {
|
|
|
26
26
|
const vars = { ANTHROPIC_BASE_URL: proxy, CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '1', ENABLE_TOOL_SEARCH: 'true' };
|
|
27
27
|
const { ANTHROPIC_AUTH_TOKEN: _auth, ...rest } = env;
|
|
28
28
|
return {
|
|
29
|
-
args: ['--settings', JSON.stringify({ apiKeyHelper: '
|
|
29
|
+
args: ['--settings', JSON.stringify({ apiKeyHelper: 'node -p "process.env.PHANTOM_AGENT_TOKEN || \'\'"', env: vars }), ...args],
|
|
30
30
|
env: { ...rest, ANTHROPIC_BASE_URL: proxy, ANTHROPIC_API_KEY: token, PHANTOM_AGENT_TOKEN: token },
|
|
31
31
|
};
|
|
32
32
|
},
|
package/dist/cli/help.mjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { DEFAULT_BASE_URL } from "../core/request.mjs";
|
|
2
2
|
import { COMMANDS } from "./commands.mjs";
|
|
3
3
|
/**
|
|
4
|
-
* Every environment variable phantom reads. The Environment
|
|
5
|
-
*
|
|
6
|
-
* code reads a variable that is not here.
|
|
4
|
+
* Every environment variable phantom reads. The Environment section of HELP is
|
|
5
|
+
* built from this list.
|
|
7
6
|
*/
|
|
8
7
|
export const ENV_VARS = [
|
|
9
8
|
{ name: 'PHANTOM_API_KEY', about: 'your Phantom AI API key (or save one with login)', secret: true },
|
package/dist/cli/run.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { VERSION } from "../core/version.mjs";
|
|
2
|
+
import { nodeTrustWarning } from "../core/node-trust.mjs";
|
|
2
3
|
import { die } from "../core/errors.mjs";
|
|
3
4
|
import { handleError, parseFlags } from "../core/helpers.mjs";
|
|
4
5
|
import { resolveApiKey } from "../keys/saved.mjs";
|
|
@@ -12,12 +13,17 @@ import { LEGACY_SETUP_HINT, legacySetupFound } from "../setup/legacy.mjs";
|
|
|
12
13
|
* @param argv The arguments after `phantom`.
|
|
13
14
|
* @param env The environment to read settings from.
|
|
14
15
|
* @param io Where output goes, and whether stderr is a terminal (for progress lines).
|
|
16
|
+
* @param node The Node version it runs on; one too old to reject forged
|
|
17
|
+
* eMudhra certificates gets a warning on stderr first.
|
|
15
18
|
*/
|
|
16
19
|
export async function run(argv = process.argv.slice(2), env = process.env, io = {
|
|
17
20
|
stdout: (s) => process.stdout.write(s),
|
|
18
21
|
stderr: (s) => process.stderr.write(s),
|
|
19
22
|
isTTY: Boolean(process.stderr.isTTY),
|
|
20
|
-
}) {
|
|
23
|
+
}, node = process.versions.node) {
|
|
24
|
+
const unsafe = nodeTrustWarning(node);
|
|
25
|
+
if (unsafe)
|
|
26
|
+
io.stderr(unsafe);
|
|
21
27
|
if (argv[0] === '--version' || argv[0] === '-v') {
|
|
22
28
|
io.stdout(VERSION + '\n');
|
|
23
29
|
return 0;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node before 24.22.1 still trusts certificates chained to the eMudhra CA
|
|
3
|
+
* keys found guessable in October 2026, so on a network someone controls, a
|
|
4
|
+
* forged phantom.codes could read the key this CLI sends. 24.22.1 rejects
|
|
5
|
+
* those chains ("tls: reject chains containing blocked public keys").
|
|
6
|
+
*/
|
|
7
|
+
/** The first Node 24 that rejects the compromised chains. */
|
|
8
|
+
const FIXED = [24, 22, 1];
|
|
9
|
+
/**
|
|
10
|
+
* A warning for stderr when `version` (`process.versions.node`) is a Node 24
|
|
11
|
+
* older than 24.22.1, or null. Other majors get none: the CLI needs 24 or newer,
|
|
12
|
+
* and the newer lines carry the fix.
|
|
13
|
+
*/
|
|
14
|
+
export function nodeTrustWarning(version) {
|
|
15
|
+
const [major, minor, patch] = version.split('.').map(Number);
|
|
16
|
+
if (major !== FIXED[0])
|
|
17
|
+
return null;
|
|
18
|
+
if (minor > FIXED[1] || (minor === FIXED[1] && patch >= FIXED[2]))
|
|
19
|
+
return null;
|
|
20
|
+
return (`phantom: Node ${version} still trusts certificates from eMudhra's compromised CA keys, ` +
|
|
21
|
+
`so on an untrusted network a forged phantom.codes could read your key. ` +
|
|
22
|
+
`Update to Node ${FIXED.join('.')} or newer (nvm install 24), or reinstall with ` +
|
|
23
|
+
`curl -fsSL https://phantom.codes/install | sh, which brings its own.\n`);
|
|
24
|
+
}
|
package/dist/core/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** This release of phantom. `npm version` keeps it equal to the version in package.json. */
|
|
2
|
-
export const VERSION = '1.2.
|
|
2
|
+
export const VERSION = '1.2.2';
|
package/dist/setup/apply.mjs
CHANGED
|
@@ -114,6 +114,13 @@ export function applySetup(env, plan) {
|
|
|
114
114
|
from = `${f.file}.phantom.bak`;
|
|
115
115
|
writeFileSync(from, f.before, { mode: 0o600 });
|
|
116
116
|
}
|
|
117
|
+
if (f.before !== null && (f.agent === 'claude' || f.file.endsWith('settings.json'))) {
|
|
118
|
+
const standardBak = `${f.file}.bak`;
|
|
119
|
+
if (!existsSync(standardBak)) {
|
|
120
|
+
const content = from && existsSync(from) ? readFileSync(from, 'utf-8') : f.before;
|
|
121
|
+
writeFileSync(standardBak, content, { mode: 0o600 });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
117
124
|
if (from)
|
|
118
125
|
backup = from;
|
|
119
126
|
if (f.after === null && from === null)
|
|
@@ -7,7 +7,7 @@ import { stateDir } from "../core/state.mjs";
|
|
|
7
7
|
import { writeSecret, readSecret, removeSecret, keychainOn } from "../core/secrets.mjs";
|
|
8
8
|
import { keyCommand } from "../keys/command.mjs";
|
|
9
9
|
import { die } from "../core/errors.mjs";
|
|
10
|
-
import { openUrl } from "../core/helpers.mjs";
|
|
10
|
+
import { openUrl, flagNum } from "../core/helpers.mjs";
|
|
11
11
|
import { keyPath, namedKeyPath, saveApiKey, saveNamedKey } from "../keys/saved.mjs";
|
|
12
12
|
const credentialPath = (env) => path.join(stateDir(env), 'workspace');
|
|
13
13
|
const base = (input) => httpsOnly(input.baseUrl || input.env.PHANTOM_BASE_URL || DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
@@ -184,7 +184,12 @@ export async function workspaceCommand(input) {
|
|
|
184
184
|
die('--pay has been removed. Use --card or --coin.');
|
|
185
185
|
if (!flags.card && !flags.coin)
|
|
186
186
|
die('fund requires --card or --coin.');
|
|
187
|
-
const
|
|
187
|
+
const amount = flagNum(flags, 'amount');
|
|
188
|
+
if (amount === undefined)
|
|
189
|
+
die('fund requires --amount <USD>.');
|
|
190
|
+
if (amount <= 0)
|
|
191
|
+
die('--amount must be greater than 0.');
|
|
192
|
+
const result = await wire(saved.base_url, 'POST', endpoint + '/fund', { method: flags.card ? 'card' : 'crypto', amount_usd: amount, coin: flags.coin ?? 'usdc' }, saved.management_credential);
|
|
188
193
|
io.stdout(JSON.stringify(result) + '\n');
|
|
189
194
|
if (result.checkout_url && !flags['no-browser'])
|
|
190
195
|
openUrl(result.checkout_url);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantomcodes/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "AI inference for your coding agents. Route models, control spending, and fund your workspace.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"phantom",
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
"build": "tsc -p .",
|
|
51
51
|
"coverage": "vitest run --coverage",
|
|
52
52
|
"dev": "node src/phantom.mts",
|
|
53
|
-
"docs": "node scripts/gen-docs.mjs",
|
|
54
53
|
"prepare": "npm run build",
|
|
55
54
|
"test": "vitest run",
|
|
56
55
|
"typecheck": "tsc -p . --noEmit",
|
|
@@ -69,7 +68,6 @@
|
|
|
69
68
|
"devDependencies": {
|
|
70
69
|
"@types/node": "^24.19.1",
|
|
71
70
|
"@vitest/coverage-v8": "^5.0.3",
|
|
72
|
-
"typedoc": "^0.28.20",
|
|
73
71
|
"typescript": "^6.0.3",
|
|
74
72
|
"vitest": "^5.0.2"
|
|
75
73
|
},
|