@alphalawyer/alpha-classic-cli 0.1.1 → 0.1.3

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 @@ Alpha Classic CLI 是为 **Alpha 律所管理系统** 开发的 AI-friendly CLI
5
5
  - CLI 命令能访问 Web 应用 API
6
6
  - Codex 能通过 Skill 理解该怎么调用 CLI
7
7
  - 登录、诊断、业务查询形成最小闭环
8
- - 环境在构建时固化,运行时不能切换,避免误连 dev/prod
8
+ - 默认环境是 `prod`,也可以通过 `env use` 在预设环境间切换
9
9
 
10
10
  ## 安装依赖
11
11
 
@@ -16,10 +16,10 @@ npm install
16
16
  ## 构建
17
17
 
18
18
  ```bash
19
- npm run build:dev
19
+ npm run build
20
20
  ```
21
21
 
22
- 构建脚本会把环境写入产物:
22
+ 默认构建生产环境产物;本地调试也保留按环境构建的脚本:
23
23
 
24
24
  ```bash
25
25
  npm run build:local
@@ -28,10 +28,23 @@ npm run build:test
28
28
  npm run build:prod
29
29
  ```
30
30
 
31
- 当前 dev 环境:
31
+ ## 发布到 npm
32
+
33
+ 正式发布会使用 `build:prod`,避免把 dev 环境固化进 npm 包。
34
+
35
+ ```bash
36
+ npm run release:dry-run
37
+ npm run release:patch
38
+ ```
39
+
40
+ - `release:dry-run`:执行类型检查、测试、生产环境构建和 `npm pack --dry-run`,只检查发包内容,不发布。
41
+ - `release:patch`:先确认 npm 登录用户,再完成发布前检查、自动升级补丁版本、重新生产构建并发布到公开 npm 仓库。
42
+ - 如果 npm 要求 OTP,命令后追加参数即可,例如 `npm run release:patch -- --otp=123456`。
43
+
44
+ 默认 prod 环境:
32
45
 
33
46
  ```text
34
- baseUrl/apiBaseUrl: https://dev.alphalawyer.cn
47
+ baseUrl/apiBaseUrl: https://alphalawyer.cn
35
48
  current user API: GET /im/v1/users/me
36
49
  auth header: token: <token>
37
50
  device header: deviceType: ai
@@ -43,7 +56,10 @@ device header: deviceType: ai
43
56
 
44
57
  ```bash
45
58
  alpha-classic-cli version
59
+ alpha-classic-cli env list
46
60
  alpha-classic-cli env current
61
+ alpha-classic-cli env use test
62
+ alpha-classic-cli env use prod
47
63
  alpha-classic-cli login
48
64
  alpha-classic-cli doctor
49
65
  alpha-classic-cli matter search --keyword 合同 --limit 10
@@ -55,7 +71,7 @@ alpha-classic-cli appro initiators --keyword 张三
55
71
  alpha-classic-cli appro detail --id <审批ID>
56
72
  ```
57
73
 
58
- `env use` 已移除。只保留 `env list` 和 `env current`;切换环境必须重新构建对应环境版本。
74
+ `env use <local|dev|test|prod>` 会写入本地配置并清空旧登录态,切换后需要重新执行 `alpha-classic-cli login`。
59
75
 
60
76
  源码调试时也可以使用:
61
77
 
@@ -208,5 +224,5 @@ alpha-classic-cli capabilities
208
224
  - 默认输出 JSON envelope,方便 AI 解析。
209
225
  - 只支持查询,不执行写操作。
210
226
  - 不在终端输出 token。
211
- - 不接受运行时 baseUrl/apiBaseUrl 参数。
227
+ - 运行时只允许切换内置环境预设,不接受任意 baseUrl/apiBaseUrl 参数。
212
228
  - Skill 负责告诉 AI 什么时候用哪个命令。
@@ -10,7 +10,7 @@
10
10
  - 使用前先运行 `alpha-classic-cli doctor`。
11
11
  - 未登录时提示用户运行 `alpha-classic-cli login`。
12
12
  - Agent 异步登录使用 `alpha-classic-cli login --no-wait --json`,把 `data.verification_url` 原样交给用户;用户确认后运行 `alpha-classic-cli login --device-code <device_code>`。
13
- - 环境由 CLI 构建时固化,运行时不能切换;如环境不对,提示用户重新构建对应环境版本。
13
+ - 默认环境是 `prod`;如环境不对,使用 `alpha-classic-cli env use <local|dev|test|prod>` 切换,并在切换后重新登录。
14
14
 
15
15
  ## 输出处理
16
16
 
@@ -107,7 +107,7 @@ alpha-classic-cli appro detail --id <approId> --comments 10
107
107
 
108
108
  - 除非用户明确要求做 CLI 开发工作,否则只使用查询 / 读取命令。
109
109
  - 不要输出 token 或 refreshToken。
110
- - 不要使用 `env use`;这个命令已经移除,只保留 `env list` 和 `env current`,环境在构建时已经锁定。
110
+ - 默认环境是 `prod`;需要切换时使用 `alpha-classic-cli env use <local|dev|test|prod>`,切换后重新登录。
111
111
  - 优先使用 `matter`,`project` 只是别名。
112
112
  - 在项目详情页里,任务表用 `matter task`。
113
113
  - 最终回答默认隐藏内部 ID,包括 `项目ID`、`审批ID`、`任务ID`、`流程任务ID`、`节点ID`、`字段ID`、`文件ID`、`评论ID`、`动态ID`;这些只留给后续 CLI 调用。`项目编号`、`审批编号` 这类业务编号可以展示。
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ function normalizeBaseUrl(value) {
19
19
  }
20
20
 
21
21
  // src/config/environments.ts
22
- var DEFAULT_ENVIRONMENT_NAME = "dev";
22
+ var DEFAULT_ENVIRONMENT_NAME = "prod";
23
23
  var PRESETS = {
24
24
  local: {
25
25
  label: "Local development",
@@ -68,6 +68,16 @@ function getEnvironmentPresetOrThrow(name) {
68
68
  function getDefaultEnvironmentPreset() {
69
69
  return getEnvironmentPresetOrThrow(BUILD_ENVIRONMENT_NAME);
70
70
  }
71
+ async function getCurrentEnvironmentPreset(configReader) {
72
+ const config = await configReader.getConfig();
73
+ const configuredEnvironment = getEnvironmentPreset(config.environment);
74
+ const fallbackEnvironment = getDefaultEnvironmentPreset();
75
+ const environment = configuredEnvironment ?? fallbackEnvironment;
76
+ return {
77
+ ...environment,
78
+ source: configuredEnvironment ? "config" : "default"
79
+ };
80
+ }
71
81
  function normalizePreset(name, preset) {
72
82
  return {
73
83
  name,
@@ -77,7 +87,7 @@ function normalizePreset(name, preset) {
77
87
  };
78
88
  }
79
89
  function resolveBuildEnvironmentName() {
80
- const rawName = "dev".trim() ? "dev" : DEFAULT_ENVIRONMENT_NAME;
90
+ const rawName = "prod".trim() ? "prod" : DEFAULT_ENVIRONMENT_NAME;
81
91
  const normalized = rawName.trim().toLowerCase();
82
92
  if (normalized in PRESETS) {
83
93
  return normalized;
@@ -220,7 +230,7 @@ var ApiClient = class {
220
230
  if (envelope) {
221
231
  const code = envelope.code ?? envelope.resultCode;
222
232
  const success = envelope.success ?? envelope.isSuccess;
223
- if (success !== false && (code === void 0 || Number(code) === RESULT_CODE_SUCCESS)) {
233
+ if (success !== false && (code === void 0 || isSuccessCode(code))) {
224
234
  return envelope.data;
225
235
  }
226
236
  if (Number(code) === RESULT_CODE_AUTH && retry.allowRefresh) {
@@ -307,16 +317,20 @@ function asResultEnvelope(value) {
307
317
  return null;
308
318
  }
309
319
  const record = value;
310
- const hasModernEnvelope = typeof record.success === "boolean" && (record.code === void 0 || typeof record.code === "number") && (record.msg === void 0 || typeof record.msg === "string");
311
- const hasLegacyEnvelope = typeof record.isSuccess === "boolean" && (record.resultCode === void 0 || typeof record.resultCode === "number" || typeof record.resultCode === "string") && (record.resultMsg === void 0 || typeof record.resultMsg === "string");
320
+ const hasModernEnvelope = (typeof record.success === "boolean" || typeof record.code === "number" || typeof record.code === "string") && (record.code === void 0 || typeof record.code === "number" || typeof record.code === "string") && (record.msg === void 0 || typeof record.msg === "string");
321
+ const hasLegacyEnvelope = (typeof record.isSuccess === "boolean" || typeof record.resultCode === "number" || typeof record.resultCode === "string") && (record.resultCode === void 0 || typeof record.resultCode === "number" || typeof record.resultCode === "string") && (record.resultMsg === void 0 || typeof record.resultMsg === "string") && (record.resultMess === void 0 || typeof record.resultMess === "string");
312
322
  if ("data" in record && (hasModernEnvelope || hasLegacyEnvelope)) {
313
323
  return value;
314
324
  }
315
325
  return null;
316
326
  }
327
+ function isSuccessCode(code) {
328
+ const numericCode2 = Number(code);
329
+ return numericCode2 === 0 || numericCode2 === 1 || numericCode2 === RESULT_CODE_SUCCESS;
330
+ }
317
331
  function throwApiEnvelopeError(envelope, status) {
318
332
  const code = envelope.code ?? envelope.resultCode;
319
- const message = envelope.msg ?? envelope.resultMsg ?? envelope.message ?? "API request failed.";
333
+ const message = envelope.msg ?? envelope.resultMsg ?? envelope.resultMess ?? envelope.message ?? "API request failed.";
320
334
  if (Number(code) === RESULT_CODE_AUTH) {
321
335
  throw new AuthError(message, code, status);
322
336
  }
@@ -364,6 +378,7 @@ async function createLoginDeviceAuthorization(options, sessionStore) {
364
378
  client: CLIENT_NAME,
365
379
  deviceName: buildDeviceName()
366
380
  });
381
+ const normalizedAuth = normalizeDeviceAuthorizationUrls(auth, context.baseUrl);
367
382
  await sessionStore.saveConfig({
368
383
  environment: context.environment.name,
369
384
  baseUrl: context.baseUrl,
@@ -374,7 +389,7 @@ async function createLoginDeviceAuthorization(options, sessionStore) {
374
389
  baseUrl: context.baseUrl,
375
390
  apiBaseUrl: context.apiBaseUrl,
376
391
  timeoutMs: context.timeoutMs,
377
- auth
392
+ auth: normalizedAuth
378
393
  };
379
394
  }
380
395
  async function pollLoginDeviceAuthorization(options, sessionStore, deviceCode) {
@@ -435,7 +450,7 @@ async function runTokenLogin(options, sessionStore) {
435
450
  if (!options.token) {
436
451
  throw new Error("Missing token.");
437
452
  }
438
- const environment = getDefaultEnvironmentPreset();
453
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
439
454
  const currentUser = await verifyToken(environment.apiBaseUrl, options.token);
440
455
  const currentUserData = getCurrentUserData(currentUser);
441
456
  const userId = options.userId ?? currentUserData?.accid ?? currentUserData?.id ?? currentUserData?.user_id;
@@ -464,9 +479,9 @@ async function runTokenLogin(options, sessionStore) {
464
479
  }
465
480
  async function resolveLoginContext(options, sessionStore) {
466
481
  const config = await sessionStore.getConfig();
467
- const environment = getDefaultEnvironmentPreset();
468
- const baseUrl = normalizeBaseUrl(config.baseUrl ?? environment.baseUrl);
469
- const apiBaseUrl = normalizeBaseUrl(config.apiBaseUrl ?? environment.apiBaseUrl);
482
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
483
+ const baseUrl = normalizeBaseUrl(environment.baseUrl);
484
+ const apiBaseUrl = normalizeBaseUrl(environment.apiBaseUrl);
470
485
  const timeoutMs = options.timeoutMs ?? config.timeoutMs ?? DEFAULT_LOGIN_TIMEOUT_MS;
471
486
  const apiClient = options.apiClient ?? new ApiClient({
472
487
  sessionStore,
@@ -569,6 +584,27 @@ ${qrcode}
569
584
  }
570
585
  emitProgress(reporter, `login: open ${auth.verificationUriComplete}`);
571
586
  }
587
+ function normalizeDeviceAuthorizationUrls(auth, baseUrl) {
588
+ return {
589
+ ...auth,
590
+ ...auth.verificationUri ? { verificationUri: replaceUrlOrigin(auth.verificationUri, baseUrl) } : {},
591
+ verificationUriComplete: replaceUrlOrigin(auth.verificationUriComplete, baseUrl)
592
+ };
593
+ }
594
+ function replaceUrlOrigin(value, baseUrl) {
595
+ if (!value.trim()) {
596
+ return value;
597
+ }
598
+ try {
599
+ const currentUrl = new URL(value);
600
+ const targetUrl = new URL(baseUrl);
601
+ currentUrl.protocol = targetUrl.protocol;
602
+ currentUrl.host = targetUrl.host;
603
+ return currentUrl.toString();
604
+ } catch {
605
+ return new URL(value.startsWith("/") ? value : `/${value}`, baseUrl).toString();
606
+ }
607
+ }
572
608
  function emitProgress(reporter, message) {
573
609
  reporter?.(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("zh-CN", { hour12: false })}] ${message}`);
574
610
  }
@@ -639,7 +675,7 @@ function printError(type, message, options) {
639
675
  // src/commands/api.ts
640
676
  async function runApiCommand(method, apiPath, options, sessionStore) {
641
677
  const config = await sessionStore.getConfig();
642
- const environment = getDefaultEnvironmentPreset();
678
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
643
679
  const client = new ApiClient({
644
680
  sessionStore,
645
681
  apiBaseUrl: environment.apiBaseUrl,
@@ -649,7 +685,7 @@ async function runApiCommand(method, apiPath, options, sessionStore) {
649
685
  params: options.params ? parseJsonObject(options.params, "--params") : void 0,
650
686
  data: options.data ? JSON.parse(options.data) : void 0
651
687
  });
652
- printSuccess(data);
688
+ printSuccess(redactSensitiveData(data));
653
689
  }
654
690
  function parseJsonObject(value, flagName) {
655
691
  const parsed = JSON.parse(value);
@@ -658,6 +694,23 @@ function parseJsonObject(value, flagName) {
658
694
  }
659
695
  return parsed;
660
696
  }
697
+ function redactSensitiveData(value) {
698
+ if (Array.isArray(value)) {
699
+ return value.map(redactSensitiveData);
700
+ }
701
+ if (!value || typeof value !== "object") {
702
+ return value;
703
+ }
704
+ return Object.fromEntries(
705
+ Object.entries(value).map(([key, item]) => [
706
+ key,
707
+ isSensitiveKey(key) ? "[REDACTED]" : redactSensitiveData(item)
708
+ ])
709
+ );
710
+ }
711
+ function isSensitiveKey(key) {
712
+ return key.toLowerCase().includes("token");
713
+ }
661
714
 
662
715
  // src/commands/appro.ts
663
716
  var APPRO_SCOPE_TO_ENUM = {
@@ -673,7 +726,7 @@ async function runApproList(options, sessionStore) {
673
726
  const approTypes = parseNumberList(options.approType);
674
727
  const status = parseApproStatus(options.status);
675
728
  const config = await sessionStore.getConfig();
676
- const environment = getDefaultEnvironmentPreset();
729
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
677
730
  const client = new ApiClient({
678
731
  sessionStore,
679
732
  apiBaseUrl: environment.apiBaseUrl,
@@ -726,7 +779,7 @@ async function runApproList(options, sessionStore) {
726
779
  async function runApproInitiators(options, sessionStore) {
727
780
  const limit = clampLimit(options.limit ?? 50);
728
781
  const config = await sessionStore.getConfig();
729
- const environment = getDefaultEnvironmentPreset();
782
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
730
783
  const client = new ApiClient({
731
784
  sessionStore,
732
785
  apiBaseUrl: environment.apiBaseUrl,
@@ -754,7 +807,7 @@ async function runApproDetail(options, sessionStore) {
754
807
  throw new Error("Missing appro id. Use: alpha-classic-cli appro detail --id <approId>");
755
808
  }
756
809
  const config = await sessionStore.getConfig();
757
- const environment = getDefaultEnvironmentPreset();
810
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
758
811
  const client = new ApiClient({
759
812
  sessionStore,
760
813
  apiBaseUrl: environment.apiBaseUrl,
@@ -1954,8 +2007,8 @@ function clampCommentLimit(limit) {
1954
2007
  }
1955
2008
 
1956
2009
  // src/commands/capabilities.ts
1957
- function runCapabilities(version) {
1958
- const environment = getDefaultEnvironmentPreset();
2010
+ async function runCapabilities(version, sessionStore) {
2011
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
1959
2012
  printSuccess({
1960
2013
  "\u5DE5\u5177": {
1961
2014
  "\u540D\u79F0": "alpha-classic-cli",
@@ -1967,8 +2020,9 @@ function runCapabilities(version) {
1967
2020
  "\u5F53\u524D\u73AF\u5883": environment.name,
1968
2021
  "baseUrl": environment.baseUrl,
1969
2022
  "apiBaseUrl": environment.apiBaseUrl,
1970
- "\u662F\u5426\u6784\u5EFA\u65F6\u9501\u5B9A": true,
1971
- "\u5207\u6362\u65B9\u5F0F": "\u91CD\u65B0\u6784\u5EFA\u5BF9\u5E94\u73AF\u5883\u7248\u672C\uFF0C\u4F8B\u5982 npm run build:dev"
2023
+ "\u662F\u5426\u53EF\u8FD0\u884C\u65F6\u5207\u6362": true,
2024
+ "\u73AF\u5883\u6765\u6E90": environment.source,
2025
+ "\u5207\u6362\u65B9\u5F0F": "alpha-classic-cli env use <local|dev|test|prod>"
1972
2026
  },
1973
2027
  "\u8BA4\u8BC1": {
1974
2028
  "\u68C0\u67E5\u767B\u5F55": "alpha-classic-cli doctor",
@@ -1995,7 +2049,7 @@ function runCapabilities(version) {
1995
2049
  "\u5378\u8F7D Claude Code": "alpha-classic-cli uninstall --agent claude",
1996
2050
  "\u5378\u8F7D Alpha-claw": "alpha-classic-cli uninstall --agent alphaclaw",
1997
2051
  "\u5378\u8F7D\u5168\u90E8": "alpha-classic-cli uninstall --agent all",
1998
- "\u8BF4\u660E": "\u7528\u6237\u81EA\u884C\u9009\u62E9\u5B89\u88C5\u76EE\u6807\uFF1BAlpha-claw \u4F1A\u6309 CLI \u6784\u5EFA\u73AF\u5883\u5B89\u88C5\u5230\u5BF9\u5E94 .openclaw-<env>alphaclaw \u5DE5\u4F5C\u533A\u3002"
2052
+ "\u8BF4\u660E": "\u7528\u6237\u81EA\u884C\u9009\u62E9\u5B89\u88C5\u76EE\u6807\uFF1BAlpha-claw \u4F1A\u6309\u5F53\u524D CLI \u73AF\u5883\u5B89\u88C5\u5230\u5BF9\u5E94 .openclaw-<env>alphaclaw \u5DE5\u4F5C\u533A\u3002"
1999
2053
  },
2000
2054
  "\u8F93\u51FA\u534F\u8BAE": {
2001
2055
  "\u6210\u529F": { "ok": true, "data": "\u4E1A\u52A1\u6570\u636E" },
@@ -2279,7 +2333,7 @@ function runCapabilities(version) {
2279
2333
  "\u4E0D\u8981\u8F93\u51FA token\u3002",
2280
2334
  "\u4E0D\u8981\u81EA\u884C\u62FC\u63A5\u540E\u7AEF\u63A5\u53E3\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F7F\u7528 api \u8C03\u8BD5\u547D\u4EE4\u3002",
2281
2335
  "\u4F18\u5148\u4F7F\u7528 capabilities \u4E2D\u58F0\u660E\u7684\u7A33\u5B9A\u4E1A\u52A1\u547D\u4EE4\u3002",
2282
- "\u73AF\u5883\u8FD0\u884C\u65F6\u4E0D\u53EF\u5207\u6362\uFF0C\u907F\u514D\u8BEF\u8FDE dev/prod\u3002"
2336
+ "\u9700\u8981\u5207\u6362\u73AF\u5883\u65F6\u4F7F\u7528 alpha-classic-cli env use\uFF0C\u5E76\u5728\u5207\u6362\u540E\u91CD\u65B0\u767B\u5F55\u3002"
2283
2337
  ]
2284
2338
  });
2285
2339
  }
@@ -2335,11 +2389,10 @@ function resolveClaudeGuidePath(homeDir = os2.homedir()) {
2335
2389
  function resolveClaudeMemoryPath(homeDir = os2.homedir()) {
2336
2390
  return path2.join(homeDir, ".claude", "CLAUDE.md");
2337
2391
  }
2338
- function resolveAlphaClawSkillPath(homeDir = os2.homedir()) {
2339
- const environment = getDefaultEnvironmentPreset();
2392
+ function resolveAlphaClawSkillPath(homeDir = os2.homedir(), environmentName = DEFAULT_ENVIRONMENT_NAME) {
2340
2393
  return path2.join(
2341
2394
  homeDir,
2342
- `.openclaw-${environment.name}alphaclaw`,
2395
+ `.openclaw-${environmentName}alphaclaw`,
2343
2396
  "workspace",
2344
2397
  "skills",
2345
2398
  SKILL_NAME
@@ -2388,8 +2441,8 @@ async function uninstallAgentGuides(options) {
2388
2441
  result.claudeMemoryUpdated = claudeResult.claudeMemoryUpdated;
2389
2442
  }
2390
2443
  if (agent === "alphaclaw" || agent === "all") {
2391
- await fs2.rm(resolveAlphaClawSkillPath(options?.homeDir), { recursive: true, force: true });
2392
- result.alphaClawSkillPath = resolveAlphaClawSkillPath(options?.homeDir);
2444
+ await fs2.rm(resolveAlphaClawSkillPath(options?.homeDir, options?.environmentName), { recursive: true, force: true });
2445
+ result.alphaClawSkillPath = resolveAlphaClawSkillPath(options?.homeDir, options?.environmentName);
2393
2446
  result.alphaClawSkillInstalled = false;
2394
2447
  }
2395
2448
  return result;
@@ -2404,7 +2457,7 @@ async function installCodexSkill(options) {
2404
2457
  };
2405
2458
  }
2406
2459
  async function installAlphaClawSkill(options) {
2407
- const skillPath = resolveAlphaClawSkillPath(options?.homeDir);
2460
+ const skillPath = resolveAlphaClawSkillPath(options?.homeDir, options?.environmentName);
2408
2461
  await fs2.rm(skillPath, { recursive: true, force: true });
2409
2462
  await copyDirectory(SKILL_TEMPLATE_ROOT, skillPath);
2410
2463
  return {
@@ -2461,7 +2514,7 @@ async function inspectInstallState(options) {
2461
2514
  } catch {
2462
2515
  claudeGuideInstalled = false;
2463
2516
  }
2464
- const alphaClawSkillPath = resolveAlphaClawSkillPath(options?.homeDir);
2517
+ const alphaClawSkillPath = resolveAlphaClawSkillPath(options?.homeDir, options?.environmentName);
2465
2518
  let alphaClawSkillInstalled = false;
2466
2519
  try {
2467
2520
  await fs2.access(path2.join(alphaClawSkillPath, "SKILL.md"));
@@ -2528,8 +2581,10 @@ async function removeClaudeImport(memoryPath) {
2528
2581
  async function runDoctor(sessionStore) {
2529
2582
  const config = await sessionStore.getConfig();
2530
2583
  let session = await sessionStore.getSession();
2531
- const environment = getDefaultEnvironmentPreset();
2532
- const installState = await inspectInstallState();
2584
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
2585
+ const installState = await inspectInstallState({
2586
+ environmentName: environment.name
2587
+ });
2533
2588
  let apiCheck = {
2534
2589
  ok: false,
2535
2590
  message: "\u672A\u767B\u5F55\u3002\u8BF7\u6267\u884C\uFF1Aalpha-classic-cli login"
@@ -2563,8 +2618,8 @@ async function runDoctor(sessionStore) {
2563
2618
  environment: environment.name,
2564
2619
  baseUrl: environment.baseUrl,
2565
2620
  apiBaseUrl: environment.apiBaseUrl,
2566
- locked: true,
2567
- source: "build",
2621
+ locked: false,
2622
+ source: environment.source,
2568
2623
  configPath: sessionStore.configPath
2569
2624
  },
2570
2625
  session: session ? {
@@ -2612,30 +2667,52 @@ function getCurrentUserData2(response) {
2612
2667
  }
2613
2668
 
2614
2669
  // src/commands/env.ts
2615
- async function runEnvCommand(action, _name, _sessionStore) {
2670
+ async function runEnvCommand(action, name, sessionStore) {
2616
2671
  const normalizedAction = action?.trim().toLowerCase() ?? "current";
2617
2672
  if (normalizedAction === "list") {
2673
+ const currentEnvironment = await getCurrentEnvironmentPreset(sessionStore);
2618
2674
  printSuccess(listEnvironmentPresets(), {
2619
- count: listEnvironmentPresets().length
2675
+ count: listEnvironmentPresets().length,
2676
+ current: currentEnvironment.name
2620
2677
  });
2621
2678
  return;
2622
2679
  }
2623
2680
  if (normalizedAction === "current") {
2624
- const fallback = getDefaultEnvironmentPreset();
2681
+ const currentEnvironment = await getCurrentEnvironmentPreset(sessionStore);
2625
2682
  printSuccess({
2626
- environment: fallback.name,
2627
- label: fallback.label,
2628
- baseUrl: fallback.baseUrl,
2629
- apiBaseUrl: fallback.apiBaseUrl,
2630
- locked: true,
2631
- source: "build"
2683
+ environment: currentEnvironment.name,
2684
+ label: currentEnvironment.label,
2685
+ baseUrl: currentEnvironment.baseUrl,
2686
+ apiBaseUrl: currentEnvironment.apiBaseUrl,
2687
+ locked: false,
2688
+ source: currentEnvironment.source,
2689
+ configPath: sessionStore.configPath
2632
2690
  });
2633
2691
  return;
2634
2692
  }
2635
2693
  if (normalizedAction === "use") {
2636
- throw new Error(
2637
- "env use has been removed. This CLI only exposes env list and env current."
2638
- );
2694
+ if (!name?.trim()) {
2695
+ throw new Error("Missing environment name. Use: alpha-classic-cli env use <local|dev|test|prod>");
2696
+ }
2697
+ const nextEnvironment = getEnvironmentPresetOrThrow(name);
2698
+ await sessionStore.saveConfig({
2699
+ environment: nextEnvironment.name,
2700
+ baseUrl: nextEnvironment.baseUrl,
2701
+ apiBaseUrl: nextEnvironment.apiBaseUrl
2702
+ });
2703
+ await sessionStore.clearAuthState();
2704
+ printSuccess({
2705
+ environment: nextEnvironment.name,
2706
+ label: nextEnvironment.label,
2707
+ baseUrl: nextEnvironment.baseUrl,
2708
+ apiBaseUrl: nextEnvironment.apiBaseUrl,
2709
+ locked: false,
2710
+ source: "config",
2711
+ session: "cleared",
2712
+ hint: "\u73AF\u5883\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C alpha-classic-cli login\u3002",
2713
+ configPath: sessionStore.configPath
2714
+ });
2715
+ return;
2639
2716
  }
2640
2717
  throw new Error(`Unknown env action: ${normalizedAction}`);
2641
2718
  }
@@ -2643,7 +2720,7 @@ async function runEnvCommand(action, _name, _sessionStore) {
2643
2720
  // src/commands/matter.ts
2644
2721
  async function runMatterSearch(options, sessionStore) {
2645
2722
  const config = await sessionStore.getConfig();
2646
- const environment = getDefaultEnvironmentPreset();
2723
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
2647
2724
  const client = new ApiClient({
2648
2725
  sessionStore,
2649
2726
  apiBaseUrl: environment.apiBaseUrl,
@@ -2694,7 +2771,7 @@ async function runMatterDetail(options, sessionStore) {
2694
2771
  throw new Error("Missing matter id. Use: alpha-classic-cli matter detail --id <matterId>");
2695
2772
  }
2696
2773
  const config = await sessionStore.getConfig();
2697
- const environment = getDefaultEnvironmentPreset();
2774
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
2698
2775
  const client = new ApiClient({
2699
2776
  sessionStore,
2700
2777
  apiBaseUrl: environment.apiBaseUrl,
@@ -2725,7 +2802,7 @@ async function runMatterTaskList(options, sessionStore) {
2725
2802
  throw new Error("Missing matter id. Use: alpha-classic-cli matter task --id <matterId>");
2726
2803
  }
2727
2804
  const config = await sessionStore.getConfig();
2728
- const environment = getDefaultEnvironmentPreset();
2805
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
2729
2806
  const client = new ApiClient({
2730
2807
  sessionStore,
2731
2808
  apiBaseUrl: environment.apiBaseUrl,
@@ -2777,7 +2854,7 @@ async function runMatterTaskDetail(options, sessionStore) {
2777
2854
  throw new Error("Missing task id. Use: alpha-classic-cli matter task-detail --id <taskId>");
2778
2855
  }
2779
2856
  const config = await sessionStore.getConfig();
2780
- const environment = getDefaultEnvironmentPreset();
2857
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
2781
2858
  const client = new ApiClient({
2782
2859
  sessionStore,
2783
2860
  apiBaseUrl: environment.apiBaseUrl,
@@ -2843,18 +2920,21 @@ async function runMatterTaskDetail(options, sessionStore) {
2843
2920
  if (commentResponse.succeed === false) {
2844
2921
  throw new Error(commentResponse.message ?? commentResponse.detail ?? "Matter task comments request failed.");
2845
2922
  }
2846
- const task = detailResponse.data;
2923
+ const task = unwrapEnvelopeData2(detailResponse);
2847
2924
  if (!task) {
2848
2925
  throw new Error("\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5F53\u524D\u7528\u6237\u65E0\u6743\u67E5\u770B\u3002");
2849
2926
  }
2850
- const attachmentPage = attachmentResponse.data ?? {};
2927
+ const checkItems = unwrapEnvelopeData2(checkItemResponse) ?? [];
2928
+ const attachmentPage = unwrapEnvelopeData2(attachmentResponse) ?? {};
2851
2929
  const attachments = attachmentPage.data ?? attachmentPage.items ?? [];
2852
2930
  const attachmentDetails = await fetchDocumentDetailsForAttachments(client, attachments);
2853
- const timingPage = timingResponse.data ?? {};
2854
- const commentPage = commentResponse.result ?? {};
2931
+ const timingPage = unwrapEnvelopeData2(timingResponse) ?? {};
2932
+ const commentPage = commentResponse.result ?? unwrapEnvelopeData2(
2933
+ commentResponse
2934
+ ) ?? {};
2855
2935
  printSuccess({
2856
2936
  "\u4EFB\u52A1\u6982\u89C8": toMatterTaskDetailSummary(task),
2857
- "\u68C0\u67E5\u9879": (checkItemResponse.data ?? []).map(toMatterTaskCheckItemSummary),
2937
+ "\u68C0\u67E5\u9879": checkItems.map(toMatterTaskCheckItemSummary),
2858
2938
  "\u9644\u4EF6": attachments.map(
2859
2939
  (attachment) => toMatterTaskAttachmentSummary(attachment, attachmentDetails.get(getAttachmentDocumentKey(attachment)))
2860
2940
  ),
@@ -3558,7 +3638,7 @@ async function buildJoinedMatterMemberFilter(client, sessionStore) {
3558
3638
  };
3559
3639
  }
3560
3640
  function unwrapEnvelopeData2(response) {
3561
- if (response && typeof response === "object" && "data" in response && ("isSuccess" in response || "resultMsg" in response)) {
3641
+ if (response && typeof response === "object" && "data" in response && ("isSuccess" in response || "resultCode" in response || "resultMsg" in response || "resultMess" in response || "code" in response || "msg" in response)) {
3562
3642
  return response.data;
3563
3643
  }
3564
3644
  return response;
@@ -3796,8 +3876,8 @@ function dateFromTimestamp2(timestamp) {
3796
3876
  }
3797
3877
 
3798
3878
  // src/commands/version.ts
3799
- function runVersion(info) {
3800
- const environment = getDefaultEnvironmentPreset();
3879
+ async function runVersion(info, sessionStore) {
3880
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
3801
3881
  printSuccess({
3802
3882
  "\u540D\u79F0": info.name,
3803
3883
  "\u7248\u672C": info.version,
@@ -3805,7 +3885,8 @@ function runVersion(info) {
3805
3885
  "\u73AF\u5883": environment.name,
3806
3886
  "baseUrl": environment.baseUrl,
3807
3887
  "apiBaseUrl": environment.apiBaseUrl,
3808
- "\u73AF\u5883\u662F\u5426\u6784\u5EFA\u65F6\u9501\u5B9A": true
3888
+ "\u73AF\u5883\u662F\u5426\u53EF\u8FD0\u884C\u65F6\u5207\u6362": true,
3889
+ "\u73AF\u5883\u6765\u6E90": environment.source
3809
3890
  });
3810
3891
  }
3811
3892
 
@@ -3890,22 +3971,33 @@ async function main() {
3890
3971
  program.name("alpha-classic-cli").description("Alpha Classic AI-friendly CLI for Alpha web app").version(packageJson.version ?? "0.0.0");
3891
3972
  program.command("install").description("Install agent guides for Codex, Claude Code, Alpha-claw, or all supported agents").option("--agent <agent>", "Agent target: codex, claude, alphaclaw, all", "codex").action(async (options) => {
3892
3973
  const agent = parseAgentInstallTarget(options.agent);
3893
- const result = await installAgentGuides({ agent });
3974
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
3975
+ const result = await installAgentGuides({
3976
+ agent,
3977
+ environmentName: environment.name
3978
+ });
3894
3979
  printSuccess(result);
3895
3980
  });
3896
3981
  program.command("uninstall").description("Uninstall agent guides for Codex, Claude Code, Alpha-claw, or all supported agents").option("--agent <agent>", "Agent target: codex, claude, alphaclaw, all", "codex").action(async (options) => {
3897
3982
  const agent = parseAgentInstallTarget(options.agent);
3898
- const result = await uninstallAgentGuides({ agent });
3983
+ const environment = await getCurrentEnvironmentPreset(sessionStore);
3984
+ const result = await uninstallAgentGuides({
3985
+ agent,
3986
+ environmentName: environment.name
3987
+ });
3899
3988
  printSuccess(result);
3900
3989
  });
3901
- program.command("capabilities").description("Print machine-readable CLI capabilities for agents").action(() => {
3902
- runCapabilities(packageJson.version ?? "0.0.0");
3990
+ program.command("capabilities").description("Print machine-readable CLI capabilities for agents").action(async () => {
3991
+ await runCapabilities(packageJson.version ?? "0.0.0", sessionStore);
3903
3992
  });
3904
- program.command("version").description("Print machine-readable CLI version").action(() => {
3905
- runVersion({
3906
- name: packageJson.name ?? "alpha-classic-cli",
3907
- version: packageJson.version ?? "0.0.0"
3908
- });
3993
+ program.command("version").description("Print machine-readable CLI version").action(async () => {
3994
+ await runVersion(
3995
+ {
3996
+ name: packageJson.name ?? "alpha-classic-cli",
3997
+ version: packageJson.version ?? "0.0.0"
3998
+ },
3999
+ sessionStore
4000
+ );
3909
4001
  });
3910
4002
  program.command("login").description("Start Alpha CLI device authorization login").option("--token <token>", "Debug fallback token").option("--user-id <id>", "Current user id").option("--office-id <id>", "Current office id").option("--name <name>", "Current user name").option("--no-wait", "Create device authorization and print JSON only").option("--json", "Print final result as JSON envelope").option("--device-code <deviceCode>", "Poll an existing device code").option("--timeout-ms <ms>", "Device authorization wait timeout", parseInteger).option("--no-open-browser", "Do not open browser when token is missing").action(
3911
4003
  async (options) => {
@@ -3968,7 +4060,7 @@ async function main() {
3968
4060
  program.command("doctor").description("Inspect config, session, skill install, and API health").action(async () => {
3969
4061
  await runDoctor(sessionStore);
3970
4062
  });
3971
- program.command("env").description("Inspect the build-time environment").argument("[action]", "Action: list, current").argument("[name]", "Environment name for list/current only").action(async (action, name) => {
4063
+ program.command("env").description("Inspect or switch the current environment").argument("[action]", "Action: list, current, use").argument("[name]", "Environment name for env use: local, dev, test, prod").action(async (action, name) => {
3972
4064
  await runEnvCommand(action, name, sessionStore);
3973
4065
  });
3974
4066
  program.command("api").description("Call a raw API endpoint").argument("<method>", "HTTP method").argument("<path>", "API path").option("--params <json>", "Query params JSON object").option("--data <json>", "Request body JSON").action(