@xbongbong/xbbcli 2.4.1 → 2.4.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 CHANGED
@@ -98,6 +98,20 @@ xbbcli auth-login --keepOpen # 登录成功后保留浏览器窗口(默
98
98
  - `--debug` 输出请求体、返回体与浏览器信息(密钥只显示掩码),`--raw` 输出换取 API token 接口的原始响应
99
99
  - 失败时返回合成错误行:`NO_BROWSER`、`BROWSER_CLOSED`、`LOGIN_TIMEOUT`、`API_TOKEN_FAILED`、`CORPID_MISMATCH`、`SAVE_FAILED` 等
100
100
 
101
+ ### 刷新本地缓存(auth-refresh-cache)
102
+
103
+ `token-set` / `auth-login` 保存凭证时会顺带刷新三份本地缓存。插件升级(新增命令导致命令映射变化)、缓存过期或被删除后,可以单独重刷,不需要重新输入 token:
104
+
105
+ ```bash
106
+ xbbcli auth-refresh-cache -f json
107
+ ```
108
+
109
+ - 刷新范围(仅当前启用公司):`~/.xbbcli/<corpid>.formlist.json`(表单清单)、`~/.xbbcli/<corpid>.command-map.md`(命令映射)、`~/.xbbcli/<corpid>.department-user.json`(部门/员工清单),并把 `corpName` / `userName` 回填进 `config.env`
110
+ - 环境变量模式(`XBB_*`)下同样可用:只刷新缓存文件,不回填 `config.env`
111
+ - 只支持当前启用公司:底层接口一律使用启用公司的凭证,切换公司请先用 `xbbcli token-use`
112
+ - `--userId` 覆盖用于匹配 `userName` 的员工 id(默认取配置里的 `userId`);`--debug` 在 stderr 输出配置来源、corpid 与三份缓存文件路径
113
+ - 失败时返回 `status=error`、`code=CACHE_REFRESH_FAILED`,`message` 以「步骤 formlist / command-map / department-user / profile」指出中断位置,已完成的部分照常在对应列输出
114
+
101
115
  `token-set` 会按 `corpid` 新增或覆盖一家公司,并把该公司置为 `enable=true`(其余公司自动置为 `false`),同时写入公司名称 `corpName`(取部门 `id` 为 `1` 的部门名称)和操作人姓名 `userName`(从员工列表中按 `userId` 匹配)。除 `token-set`、`token-list`、`token-use`、`token-del`、`auth-status`、`auth-logout` 外,其余命令都使用 `enable` 为 `true` 的公司配置。
102
116
 
103
117
  同时会自动拉取两份表单清单并合并缓存到:
@@ -145,7 +159,7 @@ xbbcli user-list --pageSize 200 -f json
145
159
  xbbcli auth-status # 回显当前激活的配置(token 默认掩码)
146
160
  xbbcli auth-status --showToken # 需要完整 token 时
147
161
  xbbcli auth-logout # 登出:删除激活的那一家配置 + 清除 XBB_* 环境变量
148
- xbbcli auth-logout --noEnv # 只删 config.env,保留环境变量
162
+ xbbcli auth-logout --env 0 # 只删 config.env,保留环境变量
149
163
  ```
150
164
 
151
165
  - `auth-status` 以 `key` / `value` 两列回显当前生效的配置值,固定 6 行:`corpid`、`corpName`、`userName`、`userId`、`baseurl`、`token`;不再输出 `status`、`source`、`message`、`enable`、`companyCount`、`envActive`、`configFile`、`code`、`msg` 这些元信息列。
@@ -166,7 +180,7 @@ note 以上取值来自环境变量 XBB_*(config.env 中没有启用公
166
180
  - `auth-status` 默认把 token 掩码为「前 6 + `***` + 后 4」(长度不足 11 时只保留前 2 位),只有 `--showToken` 才输出明文。
167
181
  - `auth-logout` 只删除 `enable=true` 的那一条,**不会**把其他公司自动提升为启用:登出后本地可能一个启用公司都没有,需要 `xbbcli token-use --corpid <CORPID>` 或重新 `auth-login` / `token-set`。想保留其他公司并可切换时,用 `xbbcli token-del --corpid <CORPID>`(它会保证剩余配置仍有且仅有一个启用)。
168
182
  - 删除前 `config.env` 会整份备份到 `~/.xbbcli/config.env.bak`(每次登出覆盖),`backupFile` 列给出路径;误删把 `.bak` 复制回 `config.env` 即可恢复。
169
- - 默认**同时**清除 `XBB_*` 环境变量:Windows 用 `reg delete HKCU\Environment` 删除用户级变量(已打开的终端要重开才生效,`envStored` 为 `user`,原本就不存在时为 `none`);macOS/Linux 清理 `~/.xbbcli/env.sh` 里的 `export XBB_*` 行(文件清空则删除,`envStored` 为 `cleared` / `removed` / `none`)。加 `--noEnv`(或 `--env=false`)时只删 `config.env`,此时若环境变量仍在,`message` 会提示「业务命令会回落到它,本次不算彻底登出」(`XBB_ENV_ONLY=1` 时提示为「已强制只用环境变量」)。
183
+ - 默认**同时**清除 `XBB_*` 环境变量:Windows 用 `reg delete HKCU\Environment` 删除用户级变量(已打开的终端要重开才生效,`envStored` 为 `user`,原本就不存在时为 `none`);macOS/Linux 清理 `~/.xbbcli/env.sh` 里的 `export XBB_*` 行(文件清空则删除,`envStored` 为 `cleared` / `removed` / `none`)。传 `--env 0` 时只删 `config.env`,此时若环境变量仍在,`message` 会提示「业务命令会回落到它,本次不算彻底登出」(`XBB_ENV_ONLY=1` 时提示为「已强制只用环境变量」)。
170
184
  - `config.env` 没有启用公司时:只有在环境变量确实存在时才只清环境变量(`config.env` 保持不动);两者都不存在则返回 `NO_ACTIVE_CONFIG`,不写任何文件。
171
185
  - 任何情况都不改动 `<corpid>.formlist.json` / `<corpid>.command-map.md` / `<corpid>.department-user.json` 三份缓存,重新启用该公司时无需再次拉取。
172
186
 
@@ -204,7 +218,8 @@ note 以上取值来自环境变量 XBB_*(config.env 中没有启用公
204
218
 
205
219
  - `auth-login`:拉起本地浏览器完成交互式登录(账号密码 / 短信 / 扫码均可),自动读取 Web 会话、换取 API token 并复用 `token-set` 落盘;支持 `--browser`、`--timeout`、`--corpid`、`--keepOpen`、`--env`、`--debug`、`--raw`
206
220
  - `auth-status`:以 `key` / `value` 两列回显当前激活配置的 `corpid`、`corpName`、`userName`、`userId`、`baseurl`、`token`(token 默认中间掩码,`--showToken` 出明文),来源与冲突提醒以 `note` 行追加,无生效配置时六个值留空并给出 `note`;`--debug` 在 stderr 输出配置文件路径、公司数量与生效的环境变量名
207
- - `auth-logout`:删除 `config.env` 中 `enable=true` 的那一条配置,删除前整份备份为 `~/.xbbcli/config.env.bak`;不自动把其他公司提升为启用;默认同时清除 `XBB_*` 环境变量(`--noEnv` / `--env=false` 跳过,返回 `envStored` / `envFile`);既无启用公司又无环境变量时返回 `NO_ACTIVE_CONFIG` 且不改动文件
221
+ - `auth-logout`:删除 `config.env` 中 `enable=true` 的那一条配置,删除前整份备份为 `~/.xbbcli/config.env.bak`;不自动把其他公司提升为启用;默认同时清除 `XBB_*` 环境变量(`--env 0` 跳过,返回 `envStored` / `envFile`);既无启用公司又无环境变量时返回 `NO_ACTIVE_CONFIG` 且不改动文件
222
+ - `auth-refresh-cache`:对当前启用公司重新拉取表单缓存、命令映射与部门/员工缓存,并回填 `corpName` / `userName`;失败时返回 `code=CACHE_REFRESH_FAILED`,`message` 注明中断步骤(`formlist` / `command-map` / `department-user` / `profile`),已完成的部分照常输出;支持 `--userId`、`--debug`
208
223
  - `token-set`:保存个人 token、`corpid`、`userId`、`baseurl`,并刷新本地表单缓存、命令映射文件与部门/员工缓存;传入的 token 不以 `user_` 开头时,会先为该 `userId` 刷新并保存个人 token;`--env` 控制存储方式:`0`(默认)仅写入本地文件,`1` 仅写入 `XBB_*` 环境变量(Windows 用 `setx`,其他平台写 `~/.xbbcli/env.sh`)且不写任何本地文件;返回 `envStored` / `envFile` 两列
209
224
  - `token-list`:列出本地保存的所有公司配置和唯一启用的公司(含 `corpName` 公司名称与 `userName` 操作人姓名,`source` 列标记来源 `config`/`env`);`--showToken` 显示完整 token(默认脱敏);环境变量模式下单行显示
210
225
  - `token-use`:切换当前启用的公司(`xbbcli token-use --corpid <CORPID>`),保证仅且只有一个公司被启用
@@ -452,7 +467,7 @@ note 以上取值来自环境变量 XBB_*(config.env 中没有启用公
452
467
  ## 通用行为
453
468
 
454
469
  - 先执行一次 `token-set`(或 `auth-login`)保存有效的 `corpid`、`token`、`userId`
455
- - 用 `xbbcli auth-status` 查看当前生效的配置来自 `config.env` 还是环境变量;`xbbcli auth-logout` 删除激活配置并默认清除 `XBB_*` 环境变量(`--noEnv` 保留)
470
+ - 用 `xbbcli auth-status` 查看当前生效的配置来自 `config.env` 还是环境变量;`xbbcli auth-logout` 删除激活配置并默认清除 `XBB_*` 环境变量(`--env 0` 保留)
456
471
  - 除 `token-set` 外,其余命令都会从 `~/.xbbcli/config.env` 读取 `corpid`
457
472
  - 大部分命令会从 `~/.xbbcli/config.env` 读取 `token`
458
473
  - 未配置 `config.env`(或其中没有启用公司)时,命令会回落到 `XBB_CORPID` / `XBB_TOKEN` / `XBB_BASEURL` / `XBB_USERID` / `XBB_CORPNAME` / `XBB_USERNAME` 环境变量;`XBB_ENV_ONLY=1` 可强制只用环境变量
package/auth-login.js CHANGED
@@ -287,7 +287,7 @@ async function authLogin(kwargs) {
287
287
  cli({
288
288
  site: 'xbb',
289
289
  name: 'auth-login',
290
- description: '打开浏览器完成销帮帮登录授权(等价于token-set)',
290
+ description: '打开浏览器完成销帮帮登录授权',
291
291
  strategy: Strategy.PUBLIC,
292
292
  access: 'write',
293
293
  browser: false,
package/auth-logout.js CHANGED
@@ -61,7 +61,7 @@ function previewCorpids(companies) {
61
61
  }
62
62
 
63
63
  async function authLogout(kwargs) {
64
- const alsoEnv = !kwargs.noEnv && kwargs.env !== false;
64
+ const alsoEnv = String(kwargs.env ?? '1').trim() !== '0';
65
65
  const companies = readCompanies();
66
66
  const index = companies.findIndex((item) => item && item.enable === true);
67
67
  const envPresent = hasEnvConfig();
@@ -76,7 +76,7 @@ async function authLogout(kwargs) {
76
76
  ? `本地共 ${companies.length} 家公司(${previewCorpids(companies)})且均未启用;要登出某家请先用 xbbcli token-use --corpid <CORPID> 启用,或改用 xbbcli token-del --corpid <CORPID> 直接删除`
77
77
  : '本地没有任何公司配置';
78
78
  const envNote = envPresent
79
- ? '环境变量 XBB_* 仍存在,本次未清除(去掉 --noEnv / --env=false 即可一并清除)'
79
+ ? '环境变量 XBB_* 仍存在,本次未清除(用 --env 1 或不指定该参数即可一并清除)'
80
80
  : '环境变量 XBB_* 也不存在,本次无可清除内容';
81
81
  const hint = `${scope};${envNote}`;
82
82
  return createRow({
@@ -139,7 +139,7 @@ async function authLogout(kwargs) {
139
139
  }
140
140
  } else if (envBefore) {
141
141
  const forced = isEnvOnly() ? '且 XBB_ENV_ONLY=1 已强制只用环境变量' : '业务命令会回落到它';
142
- parts.push(`注意:环境变量 XBB_*(corpid=${envBefore})仍然有效,${forced},本次不算彻底登出;如需一并清除请去掉 --noEnv(auth-logout 默认会清除环境变量)`);
142
+ parts.push(`注意:环境变量 XBB_*(corpid=${envBefore})仍然有效,${forced},本次不算彻底登出;如需一并清除请改用 --env 1(或不指定该参数,auth-logout 默认会清除环境变量)`);
143
143
  }
144
144
 
145
145
  const remainingCompanies = target ? remaining : readCompanies();
@@ -166,8 +166,7 @@ cli({
166
166
  browser: false,
167
167
  domain: 'proapi.xbongbong.com',
168
168
  args: [
169
- { name: 'env', type: 'bool', default: true, help: '同时清除 XBB_* 环境变量(默认开启;--env=false 跳过)。Windows 删除用户级变量,其他平台清理 ~/.xbbcli/env.sh' },
170
- { name: 'noEnv', type: 'bool', default: false, help: '不清除环境变量,仅删除 config.env 中的激活配置(等价于 --env=false)' },
169
+ { name: 'env', type: 'str', default: '1', help: '是否同时清除 XBB_* 环境变量:1 清除(默认),0 仅删除 config.env 保留环境变量。Windows 删除用户级变量,其他平台清理 ~/.xbbcli/env.sh' },
171
170
  { name: 'debug', type: 'bool', default: false, help: '输出配置文件、备份路径与生效的环境变量名(不打印 token)' },
172
171
  ],
173
172
  columns: ['status', 'message', 'configFile', 'backupFile', 'corpid', 'corpName', 'userId', 'companyCount', 'hasActive', 'envStored', 'envFile', 'code', 'msg'],
@@ -0,0 +1,117 @@
1
+ import { cli, Strategy } from './xbb-registry.js';
2
+ import { readActiveConfig, isEnvActive } from './xbb-config.js';
3
+ import {
4
+ refreshLocalCaches,
5
+ getFormlistFile,
6
+ getCommandMapFile,
7
+ getDepartmentUserFile,
8
+ } from './xbb-token-store.js';
9
+
10
+ function trim(value) {
11
+ return String(value ?? '').trim();
12
+ }
13
+
14
+ // 统一输出:成功时给出三份缓存与回填结果,失败时回落到合成错误行(不抛异常)
15
+ function makeRow(fields) {
16
+ return [{
17
+ status: '',
18
+ message: '',
19
+ corpid: '',
20
+ userId: '',
21
+ corpName: '',
22
+ userName: '',
23
+ formlistFile: '',
24
+ formlistCount: '',
25
+ commandMapFile: '',
26
+ departmentUserFile: '',
27
+ departmentCount: '',
28
+ userCount: '',
29
+ profileUpdated: '',
30
+ code: '',
31
+ msg: '',
32
+ ...fields,
33
+ }];
34
+ }
35
+
36
+ function makeErrorRow(code, msg, extra = {}) {
37
+ return makeRow({ status: 'error', code, msg, message: msg, ...extra });
38
+ }
39
+
40
+ async function authRefreshCache(kwargs) {
41
+ const active = readActiveConfig();
42
+ const corpid = trim(active.corpid);
43
+ const userId = trim(kwargs.userId) || trim(active.userId);
44
+
45
+ if (kwargs.debug) {
46
+ const source = isEnvActive() ? 'env' : 'config';
47
+ process.stderr.write(`[debug] ConfigSource: ${source}\n[debug] Corpid: ${corpid || '(none)'}\n[debug] UserId: ${userId || '(none)'}\n[debug] FormlistFile: ${corpid ? getFormlistFile(corpid) : ''}\n[debug] CommandMapFile: ${corpid ? getCommandMapFile(corpid) : ''}\n[debug] DepartmentUserFile: ${corpid ? getDepartmentUserFile(corpid) : ''}\n`);
48
+ }
49
+
50
+ if (!corpid) {
51
+ return makeErrorRow('NO_ACTIVE_CONFIG', '没有生效的配置:config.env 中不存在 enable=true 的公司,环境变量 XBB_* 也为空;请先执行 xbbcli auth-login 或 xbbcli token-set');
52
+ }
53
+
54
+ let cache;
55
+ try {
56
+ cache = await refreshLocalCaches(corpid, userId);
57
+ } catch (error) {
58
+ const partial = error.cache || {};
59
+ const step = trim(error.step) || 'unknown';
60
+ const message = `刷新本地缓存失败(步骤 ${step}):${error.message || error}`;
61
+ return makeRow({
62
+ status: 'error',
63
+ code: 'CACHE_REFRESH_FAILED',
64
+ msg: message,
65
+ message,
66
+ corpid,
67
+ userId,
68
+ corpName: partial.corpName ?? '',
69
+ userName: partial.userName ?? '',
70
+ formlistFile: partial.formlistFile ?? '',
71
+ formlistCount: partial.formlistCount ?? '',
72
+ commandMapFile: partial.commandMapFile ?? '',
73
+ departmentUserFile: partial.departmentUserFile ?? '',
74
+ departmentCount: partial.departmentCount ?? '',
75
+ userCount: partial.userCount ?? '',
76
+ profileUpdated: partial.profileUpdated ?? '',
77
+ });
78
+ }
79
+
80
+ const message = cache.profileUpdated
81
+ ? '已刷新表单清单缓存、命令映射与部门/员工缓存,并回填 corpName/userName 到 config.env'
82
+ : isEnvActive()
83
+ ? '已刷新表单清单缓存、命令映射与部门/员工缓存;当前为环境变量模式,corpName/userName 未回填 config.env'
84
+ : '已刷新表单清单缓存、命令映射与部门/员工缓存;该公司不在 config.env 中,corpName/userName 未回填';
85
+
86
+ return makeRow({
87
+ status: 'ok',
88
+ message,
89
+ corpid,
90
+ userId,
91
+ corpName: cache.corpName,
92
+ userName: cache.userName,
93
+ formlistFile: cache.formlistFile,
94
+ formlistCount: cache.formlistCount,
95
+ commandMapFile: cache.commandMapFile,
96
+ departmentUserFile: cache.departmentUserFile,
97
+ departmentCount: cache.departmentCount,
98
+ userCount: cache.userCount,
99
+ profileUpdated: cache.profileUpdated,
100
+ });
101
+ }
102
+
103
+ cli({
104
+ site: 'xbb',
105
+ name: 'auth-refresh-cache',
106
+ description: '刷新当前启用公司的本地缓存(表单清单、命令映射等)',
107
+ strategy: Strategy.PUBLIC,
108
+ access: 'write',
109
+ browser: false,
110
+ domain: 'proapi.xbongbong.com',
111
+ args: [
112
+ { name: 'userId', type: 'str', default: '', help: '操作人 id,用于从员工清单匹配 userName;默认取当前启用配置的 userId' },
113
+ { name: 'debug', type: 'bool', default: false, help: '在 stderr 输出配置来源、corpid 与三份缓存文件路径' },
114
+ ],
115
+ columns: ['status', 'message', 'corpid', 'userId', 'corpName', 'userName', 'formlistFile', 'formlistCount', 'commandMapFile', 'departmentUserFile', 'departmentCount', 'userCount', 'profileUpdated', 'code', 'msg'],
116
+ func: authRefreshCache,
117
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbongbong/xbbcli",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "销帮帮 CRM 的独立命令行工具",
5
5
  "type": "module",
6
6
  "bin": {
@@ -109,7 +109,7 @@ async function writeFormlistFile(corpid) {
109
109
  const mergedRows = [...customForms, ...systemForms];
110
110
 
111
111
  fs.writeFileSync(formlistFile, JSON.stringify(mergedRows, null, 2) + '\n', 'utf8');
112
- return formlistFile;
112
+ return { file: formlistFile, count: mergedRows.length };
113
113
  }
114
114
 
115
115
  async function fetchAllRows(name, pageSize) {
@@ -178,7 +178,7 @@ async function writeDepartmentUserFile(corpid, userId) {
178
178
  const file = getDepartmentUserFile(corpid);
179
179
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
180
180
  fs.writeFileSync(file, JSON.stringify(payload, null, 2) + '\n', 'utf8');
181
- return { file, corpName: getCorpName(departmentRows), userName: getUserName(userRows, userId) };
181
+ return { file, corpName: getCorpName(departmentRows), userName: getUserName(userRows, userId), departmentCount: departmentRows.length, userCount: userRows.length };
182
182
  }
183
183
 
184
184
  function getCorpName(departmentRows) {
@@ -196,16 +196,89 @@ function getUserName(userRows, userId) {
196
196
  return matched ? String(matched.name || '').trim() : '';
197
197
  }
198
198
 
199
+ // 把 corpName / userName 合并进 config.env 对应公司,返回是否真的写过文件
200
+ // config.env 里没有这家公司的条目时(纯环境变量模式)直接跳过,避免凭空生成一份只有 corpName 的 config.env
199
201
  export function writeCompanyProfile(corpid, profile) {
202
+ const target = String(corpid || '').trim();
200
203
  const fields = Object.entries(profile).filter(([, value]) => String(value || '').trim() !== '');
201
- if (!fields.length) {
202
- return;
204
+ if (!target || !fields.length) {
205
+ return false;
206
+ }
207
+ const companies = readCompanies();
208
+ const index = companies.findIndex((item) => String(item.corpid || '').trim() === target);
209
+ if (index === -1) {
210
+ return false;
203
211
  }
204
212
  const patch = Object.fromEntries(fields);
205
- const companies = readCompanies().map((item) => (
206
- String(item.corpid || '').trim() === corpid ? { ...item, ...patch } : item
207
- ));
208
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(companies, null, 2) + '\n', 'utf8');
213
+ const next = companies.map((item, itemIndex) => (itemIndex === index ? { ...item, ...patch } : item));
214
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(next, null, 2) + '\n', 'utf8');
215
+ return true;
216
+ }
217
+
218
+ // token-set / auth-login / auth-refresh-cache 共用:刷新三份本地缓存并回填 corpName、userName
219
+ // 失败时抛出的 error 上带 step(formlist/command-map/department-user/profile)与已完成部分的 cache,便于命令回显进度
220
+ export async function refreshLocalCaches(corpid, userId) {
221
+ const target = String(corpid || '').trim();
222
+ if (!target) {
223
+ const error = new Error('缺少 corpid,无法确定要刷新哪家公司的缓存');
224
+ error.step = 'formlist';
225
+ error.cache = { formlistFile: '', commandMapFile: '', departmentUserFile: '', formlistCount: '', departmentCount: '', userCount: '', corpName: '', userName: '', profileUpdated: false };
226
+ throw error;
227
+ }
228
+ const cache = {
229
+ formlistFile: getFormlistFile(target),
230
+ commandMapFile: '',
231
+ departmentUserFile: '',
232
+ formlistCount: '',
233
+ departmentCount: '',
234
+ userCount: '',
235
+ corpName: '',
236
+ userName: '',
237
+ profileUpdated: false,
238
+ };
239
+
240
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
241
+
242
+ try {
243
+ const formlist = await writeFormlistFile(target);
244
+ cache.formlistFile = formlist.file;
245
+ cache.formlistCount = formlist.count;
246
+ } catch (error) {
247
+ error.step = 'formlist';
248
+ error.cache = cache;
249
+ throw error;
250
+ }
251
+
252
+ try {
253
+ cache.commandMapFile = writeCommandMap(target);
254
+ } catch (error) {
255
+ error.step = 'command-map';
256
+ error.cache = cache;
257
+ throw error;
258
+ }
259
+
260
+ try {
261
+ const departmentUser = await writeDepartmentUserFile(target, userId);
262
+ cache.departmentUserFile = departmentUser.file;
263
+ cache.corpName = departmentUser.corpName;
264
+ cache.userName = departmentUser.userName;
265
+ cache.departmentCount = departmentUser.departmentCount;
266
+ cache.userCount = departmentUser.userCount;
267
+ } catch (error) {
268
+ error.step = 'department-user';
269
+ error.cache = cache;
270
+ throw error;
271
+ }
272
+
273
+ try {
274
+ cache.profileUpdated = writeCompanyProfile(target, { corpName: cache.corpName, userName: cache.userName });
275
+ } catch (error) {
276
+ error.step = 'profile';
277
+ error.cache = cache;
278
+ throw error;
279
+ }
280
+
281
+ return cache;
209
282
  }
210
283
 
211
284
  function normalizeBusinessType(value) {
@@ -373,15 +446,13 @@ export async function saveCompanyCredentials(kwargs) {
373
446
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(companies, null, 2) + '\n', 'utf8');
374
447
 
375
448
  try {
376
- const formlistFile = await writeFormlistFile(corpid);
377
- const commandMapFile = writeCommandMap(corpid);
378
- const { file: departmentUserFile, corpName, userName } = await writeDepartmentUserFile(corpid, userId);
379
- writeCompanyProfile(corpid, { corpName, userName });
449
+ const cache = await refreshLocalCaches(corpid, userId);
450
+ const { formlistFile, commandMapFile, departmentUserFile, corpName, userName } = cache;
380
451
  return createResult('ok', '已保存 corpid、token、baseurl、userId,并同步表单模板缓存、命令映射文件与部门/员工缓存', corpid, baseurl, userId, formlistFile, commandMapFile, true, companies.length, departmentUserFile, corpName, userName, 'skipped', '');
381
452
  } catch (error) {
382
453
  return createResult(
383
454
  'partial',
384
- `已保存 corpid、token、baseurl、userId,但同步缓存失败:${error.message}`,
455
+ `已保存 corpid、token、baseurl、userId,但同步缓存失败${error.step ? `(步骤 ${error.step})` : ''}:${error.message}`,
385
456
  corpid,
386
457
  baseurl,
387
458
  userId,