cicy-desktop 2.1.35 → 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 +1 -1
- package/src/tools/chrome-tools.js +59 -13
package/package.json
CHANGED
|
@@ -59,7 +59,11 @@ function writePrivateChromeConfig(nextConfig) {
|
|
|
59
59
|
if (!fs.existsSync(dir)) {
|
|
60
60
|
fs.mkdirSync(dir, { recursive: true });
|
|
61
61
|
}
|
|
62
|
-
|
|
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,10 +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
|
|
101
|
-
//
|
|
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>}.
|
|
102
107
|
const note = typeof safeEntry.note === "string" ? safeEntry.note : "";
|
|
103
|
-
const
|
|
108
|
+
const rawAccounts =
|
|
109
|
+
safeEntry.accounts && typeof safeEntry.accounts === "object" && !Array.isArray(safeEntry.accounts)
|
|
110
|
+
? safeEntry.accounts
|
|
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
|
+
}
|
|
104
117
|
|
|
105
118
|
return {
|
|
106
119
|
profileKey,
|
|
@@ -662,11 +675,24 @@ function registerChromeTools(registerTool) {
|
|
|
662
675
|
|
|
663
676
|
registerTool(
|
|
664
677
|
"chrome_set_profile_meta",
|
|
665
|
-
"设置 ~/cicy-ai/db/chrome.json 中指定 accountIdx 的 note(备注)/ accounts
|
|
678
|
+
"设置 ~/cicy-ai/db/chrome.json 中指定 accountIdx 的 note(备注)/ accounts(服务→{account,password,totp} map,用于 list profile with <svc> + 自动 2FA)",
|
|
666
679
|
z.object({
|
|
667
680
|
accountIdx: z.number().describe("账户索引"),
|
|
668
681
|
note: z.string().optional().describe("自由文本备注;省略则不动"),
|
|
669
|
-
accounts: z
|
|
682
|
+
accounts: z
|
|
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
|
+
)
|
|
692
|
+
.optional()
|
|
693
|
+
.describe(
|
|
694
|
+
"服务→{account,password,totp} map,如 {github:{account:'octocat',password:'..',totp:'BASE32'}};字段级合并,字段空值删该字段,svc 清空则删该服务;省略则整体不动"
|
|
695
|
+
),
|
|
670
696
|
}),
|
|
671
697
|
async ({ accountIdx, note, accounts } = {}) => {
|
|
672
698
|
const data = readPrivateChromeConfig();
|
|
@@ -674,13 +700,33 @@ function registerChromeTools(registerTool) {
|
|
|
674
700
|
if (!data[key]) {
|
|
675
701
|
return toToolResult({ error: `Missing chrome.json entry: ${key}` }, { isError: true });
|
|
676
702
|
}
|
|
677
|
-
data[key]
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
703
|
+
const patch = { ...data[key], ...(note !== undefined ? { note: String(note) } : {}) };
|
|
704
|
+
if (accounts !== undefined) {
|
|
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 =
|
|
709
|
+
data[key].accounts && typeof data[key].accounts === "object" && !Array.isArray(data[key].accounts)
|
|
710
|
+
? data[key].accounts
|
|
711
|
+
: {};
|
|
712
|
+
const next = { ...base };
|
|
713
|
+
for (const [rawSvc, fieldPatch] of Object.entries(accounts)) {
|
|
714
|
+
const svc = String(rawSvc).trim().toLowerCase();
|
|
715
|
+
if (!svc) continue;
|
|
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;
|
|
726
|
+
}
|
|
727
|
+
patch.accounts = next;
|
|
728
|
+
}
|
|
729
|
+
data[key] = patch;
|
|
684
730
|
writePrivateChromeConfig(data);
|
|
685
731
|
return toToolResult({ success: true, profileKey: key, privateConfig: data[key] });
|
|
686
732
|
},
|