@encorearia/install 1.1.0 → 1.2.0

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/bin/install.mjs CHANGED
@@ -1,15 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import process from 'node:process';
3
+ import { readFileSync } from 'node:fs';
3
4
  import { request, ensureDeviceLogin } from '../lib/api.mjs';
4
5
  import { atomicInstall } from '../lib/atomic-install.mjs';
5
6
  import { loadCredentials } from '../lib/credentials.mjs';
6
7
  import { detectTargets, targetRoot } from '../lib/targets.mjs';
7
8
  import { loadTrustedKeys, verifyPackage } from '../lib/verify.mjs';
9
+ import { bindApiOrigin } from '../lib/credentials.mjs';
8
10
 
9
11
  const args = process.argv.slice(2);
10
12
  const baseURL = String(valueAfter('--api') || process.env.ENCOREARIA_API_BASE || 'https://encorearia.com').replace(/\/$/, '');
13
+ bindApiOrigin(baseURL);
11
14
  const targetArg = valueAfter('--target');
12
- const installerVersion = '1.1.0';
15
+ const installerVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
13
16
 
14
17
  if (args.includes('--list')) {
15
18
  const target = (await detectTargets(targetArg ? targetArg.split(',') : []))[0];
@@ -30,18 +33,23 @@ if (args.includes('--list')) {
30
33
  process.exit(0);
31
34
  }
32
35
 
33
- if (positionalArgument()) fail('Usage: npx @encorearia/install [--target codex,claude-code] [--api URL]');
36
+ if (positionalArgument()) fail('用法:npx @encorearia/install [--target codex,claude-code] [--api URL]');
34
37
  const pkg = await request(baseURL, '/api/agent/shell');
35
38
  const trust = await loadTrustedKeys(baseURL);
36
39
  verifyPackage(pkg, trust, installerVersion);
37
40
  const targets = await detectTargets(targetArg ? targetArg.split(',') : []);
38
41
  const primaryTarget = targets[0];
39
42
  await ensureDeviceLogin(baseURL, '', pkg.manifest.shell_version, primaryTarget);
40
- const shellID = pkg.manifest.shell_id || 'encorearia-unified';
43
+ const shellID = pkg.manifest.shell_id || 'encorearia';
41
44
  for (const target of targets) {
42
45
  const destination = await atomicInstall(targetRoot(target), shellID, pkg.files, pkg.manifest);
43
- process.stdout.write(`Installed to ${target}: ${destination}\n`);
46
+ process.stdout.write(`已安装到 ${displayTarget(target)}:${destination}\n`);
44
47
  }
48
+ process.stdout.write('\n安可集已就绪。你可以直接对 AI 说:\n');
49
+ process.stdout.write(' · 看看我的服务\n');
50
+ process.stdout.write(' · 帮我调用 <服务名>\n');
51
+ process.stdout.write(' · 查我的钱包余额\n');
52
+ process.stdout.write('浏览更多服务或充值:https://encorearia.com\n');
45
53
 
46
54
  function valueAfter(flag) {
47
55
  const index = args.indexOf(flag);
@@ -58,6 +66,12 @@ function positionalArgument() {
58
66
  return '';
59
67
  }
60
68
 
69
+ function displayTarget(target) {
70
+ if (target === 'codex') return 'Codex';
71
+ if (target === 'claude-code') return 'Claude Code';
72
+ return target;
73
+ }
74
+
61
75
  function fail(message) {
62
76
  process.stderr.write(message + '\n');
63
77
  process.exit(1);
@@ -2,10 +2,30 @@ import fs from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
 
5
+ import { createHash } from 'node:crypto';
6
+
5
7
  const service = 'encorearia-agent';
6
- const account = 'default';
8
+ export const OFFICIAL_API = 'https://encorearia.com';
9
+ let originSuffix = '';
10
+
11
+ // 凭据按 API 来源隔离:官方地址用默认文件;其它地址仅限本机调试或显式允许,
12
+ // 且各用独立文件——防止 `--api` 指向任意第三方后把官方登录凭据发过去(钓鱼偷 token)。
13
+ export function bindApiOrigin(baseURL) {
14
+ let canonical;
15
+ try { canonical = new URL(String(baseURL || '')).origin; } catch { canonical = String(baseURL || '').replace(/\/+$/, ''); }
16
+ if (canonical === OFFICIAL_API) { originSuffix = ''; return; }
17
+ let host = '';
18
+ try { host = new URL(canonical).hostname; } catch { host = ''; }
19
+ const loopback = host === 'localhost' || host === '127.0.0.1' || host === '::1' || host === '[::1]';
20
+ if (!loopback && process.env.ENCOREARIA_ALLOW_CUSTOM_API !== '1') {
21
+ throw new Error('--api 只允许官方地址或本机调试地址;如确需自定义请设 ENCOREARIA_ALLOW_CUSTOM_API=1(凭据将与官方隔离)');
22
+ }
23
+ originSuffix = '-' + createHash('sha256').update(canonical).digest('hex').slice(0, 12);
24
+ }
25
+
26
+ const account = () => 'default' + originSuffix;
7
27
  export const credentialsDirectory = () => process.env.ENCOREARIA_CONFIG_DIR || path.join(os.homedir(), '.encorearia');
8
- const file = () => path.join(credentialsDirectory(), 'credentials.json');
28
+ const file = () => path.join(credentialsDirectory(), 'credentials' + originSuffix + '.json');
9
29
 
10
30
  async function keytar() {
11
31
  try { return (await import('keytar')).default; } catch { return null; }
@@ -14,7 +34,7 @@ async function keytar() {
14
34
  export async function loadCredentials() {
15
35
  const keychain = await keytar();
16
36
  if (keychain) {
17
- const raw = await keychain.getPassword(service, account);
37
+ const raw = await keychain.getPassword(service, account());
18
38
  if (raw) return JSON.parse(raw);
19
39
  }
20
40
  try { return JSON.parse(await fs.readFile(file(), 'utf8')); } catch { return null; }
@@ -23,7 +43,7 @@ export async function loadCredentials() {
23
43
  export async function saveCredentials(value) {
24
44
  const keychain = await keytar();
25
45
  if (keychain) {
26
- await keychain.setPassword(service, account, JSON.stringify(value));
46
+ await keychain.setPassword(service, account(), JSON.stringify(value));
27
47
  return;
28
48
  }
29
49
  const dir = path.dirname(file());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@encorearia/install",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Verify and install signed Encore Aria call-shell skills for Codex and Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {