cicy-desktop 2.1.36 → 2.1.37

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.36",
3
+ "version": "2.1.37",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -59,7 +59,11 @@ function writePrivateChromeConfig(nextConfig) {
59
59
  if (!fs.existsSync(dir)) {
60
60
  fs.mkdirSync(dir, { recursive: true });
61
61
  }
62
- fs.writeFileSync(PRIVATE_CHROME_JSON, JSON.stringify(nextConfig || {}, null, 2));
62
+ // chrome.json now holds per-account passwords + TOTP secrets — keep it
63
+ // owner-only (0600). mode on writeFileSync only applies on create, so chmod
64
+ // explicitly to also tighten a pre-existing world/group-readable file.
65
+ fs.writeFileSync(PRIVATE_CHROME_JSON, JSON.stringify(nextConfig || {}, null, 2), { mode: 0o600 });
66
+ try { fs.chmodSync(PRIVATE_CHROME_JSON, 0o600); } catch {}
63
67
  }
64
68
 
65
69
  function listPrivateChromeEntries({ includeHidden = false } = {}) {
@@ -97,14 +101,19 @@ function normalizePrivateChromeEntry(profileKey, accountIdx, entry) {
97
101
  const port = typeof safeEntry.port === "number" ? safeEntry.port : null;
98
102
  const proxyUrl = normalizePrivateProxy(safeEntry.proxy);
99
103
  const platform = safeEntry.platform && typeof safeEntry.platform === "object" ? safeEntry.platform : {};
100
- // Free-text note + a service→account map (e.g. {github:"octocat",
101
- // gmail:"me@gmail.com"}) for `list profile with <svc>` — written via
102
- // chrome_set_profile_meta. Legacy array values normalize to {}.
104
+ // Free-text note + a service→credentials map for `list profile with <svc>` —
105
+ // written via chrome_set_profile_meta. Each value is {account,password,totp}.
106
+ // Legacy normalization: array {}; a bare string value → {account:<string>}.
103
107
  const note = typeof safeEntry.note === "string" ? safeEntry.note : "";
104
- const accounts =
108
+ const rawAccounts =
105
109
  safeEntry.accounts && typeof safeEntry.accounts === "object" && !Array.isArray(safeEntry.accounts)
106
110
  ? safeEntry.accounts
107
111
  : {};
112
+ const accounts = {};
113
+ for (const [svc, val] of Object.entries(rawAccounts)) {
114
+ if (typeof val === "string") accounts[svc] = { account: val };
115
+ else if (val && typeof val === "object" && !Array.isArray(val)) accounts[svc] = val;
116
+ }
108
117
 
109
118
  return {
110
119
  profileKey,
@@ -666,14 +675,24 @@ function registerChromeTools(registerTool) {
666
675
 
667
676
  registerTool(
668
677
  "chrome_set_profile_meta",
669
- "设置 ~/cicy-ai/db/chrome.json 中指定 accountIdx 的 note(备注)/ accounts(服务→账号 map,用于 list profile with <svc>)",
678
+ "设置 ~/cicy-ai/db/chrome.json 中指定 accountIdx 的 note(备注)/ accounts(服务→{account,password,totp} map,用于 list profile with <svc> + 自动 2FA)",
670
679
  z.object({
671
680
  accountIdx: z.number().describe("账户索引"),
672
681
  note: z.string().optional().describe("自由文本备注;省略则不动"),
673
682
  accounts: z
674
- .record(z.string())
683
+ .record(
684
+ z
685
+ .object({
686
+ account: z.string().optional(),
687
+ password: z.string().optional(),
688
+ totp: z.string().optional(),
689
+ })
690
+ .partial()
691
+ )
675
692
  .optional()
676
- .describe("服务→账号 map,如 {github:'octocat',gmail:'me@gmail.com'};空值删除该服务;省略则整体不动;与现有合并"),
693
+ .describe(
694
+ "服务→{account,password,totp} map,如 {github:{account:'octocat',password:'..',totp:'BASE32'}};字段级合并,字段空值删该字段,svc 清空则删该服务;省略则整体不动"
695
+ ),
677
696
  }),
678
697
  async ({ accountIdx, note, accounts } = {}) => {
679
698
  const data = readPrivateChromeConfig();
@@ -683,18 +702,27 @@ function registerChromeTools(registerTool) {
683
702
  }
684
703
  const patch = { ...data[key], ...(note !== undefined ? { note: String(note) } : {}) };
685
704
  if (accounts !== undefined) {
686
- // Merge into the existing service→account map; empty value deletes a service.
687
- const cur =
705
+ // Field-level merge into the existing service→credentials map.
706
+ // Empty field value deletes that field; a service with no fields left
707
+ // is removed entirely. Legacy string value normalizes to {account}.
708
+ const base =
688
709
  data[key].accounts && typeof data[key].accounts === "object" && !Array.isArray(data[key].accounts)
689
710
  ? data[key].accounts
690
711
  : {};
691
- const next = { ...cur };
692
- for (const [k, v] of Object.entries(accounts)) {
693
- const svc = String(k).trim().toLowerCase();
694
- const val = String(v ?? "").trim();
712
+ const next = { ...base };
713
+ for (const [rawSvc, fieldPatch] of Object.entries(accounts)) {
714
+ const svc = String(rawSvc).trim().toLowerCase();
695
715
  if (!svc) continue;
696
- if (val === "") delete next[svc];
697
- else next[svc] = val;
716
+ let cur = next[svc];
717
+ if (typeof cur === "string") cur = { account: cur }; // 1.3.0 compat
718
+ cur = cur && typeof cur === "object" && !Array.isArray(cur) ? { ...cur } : {};
719
+ for (const [f, v] of Object.entries(fieldPatch || {})) {
720
+ const val = String(v ?? "").trim();
721
+ if (val === "") delete cur[f];
722
+ else cur[f] = val;
723
+ }
724
+ if (Object.keys(cur).length === 0) delete next[svc];
725
+ else next[svc] = cur;
698
726
  }
699
727
  patch.accounts = next;
700
728
  }