diff --git a/01_卡资(金)/金仓_存储备份/聊天记录管理/fallback/recent_chats_fallback.json b/01_卡资(金)/金仓_存储备份/聊天记录管理/fallback/recent_chats_fallback.json index 0930a3ea..9bdbd832 100644 --- a/01_卡资(金)/金仓_存储备份/聊天记录管理/fallback/recent_chats_fallback.json +++ b/01_卡资(金)/金仓_存储备份/聊天记录管理/fallback/recent_chats_fallback.json @@ -1,13 +1,37 @@ { -"updated": "2026-03-23T08:37:37.372613+00:00", +"updated": "2026-03-23T12:12:36.198299+00:00", "conversations": [ { +"对话ID": "6afeb85a-5117-478f-a216-b3bfebae5b51", +"名称": "信用卡请求", +"项目": "卡若AI", +"首条消息": "卡若ai把我的信用卡发给我", +"创建时间": "2026-03-23T12:09:02.290000+00:00", +"消息数量": 13 +}, +{ +"对话ID": "462c354b-4f31-4180-9069-aad14a8a0937", +"名称": "卡若ai 邮箱注册", +"项目": "卡若AI", +"首条消息": "卡若ai 用skill注册一个邮箱", +"创建时间": "2026-03-23T12:03:58.396000+00:00", +"消息数量": 10 +}, +{ +"对话ID": "5d22bebc-ecf7-46b2-aede-bea3b0b14d93", +"名称": "Rule configuration UI in admin panel", +"项目": "Soul创业", +"首条消息": "In the project at /Users/karuo/Documents/开发/3、自营项目/一场soul的创业实验-永平, I need to understand the rule configuration UI in the admin panel.\n\n1. Search for \"UserRule\" or \"user-rules\" or \"规则配置\" in the admin frontend (soul-admin/src/)\n2. The rules tab is in UsersPage.tsx - find the \"rules\" TabsContent section and report the full JSX for it\n3. Read the existing rules CRUD UI - how are rules listed, created, edited?\n4. Check if descriptions are currently shown inline\n\nReport all findings with exact line nu", +"创建时间": "2026-03-23T10:14:23.470000+00:00", +"消息数量": 18 +}, +{ "对话ID": "4ef4d028-04ea-4ea1-b7ce-e43b353b10ca", "名称": "Web CLI skill integration", "项目": "卡若AI", "首条消息": "上面搜索网页cli的 skill。GitHub 上面搜索最新的网页,西游记分数最高的那个,然后帮我整合到卡罗伊的 skill 里面", "创建时间": "2026-03-23T08:19:23.549000+00:00", -"消息数量": 127 +"消息数量": 129 }, { "对话ID": "f8f37966-e2ff-42a0-90bc-a28c005698c6", @@ -216,30 +240,6 @@ "首条消息": "那个告诉我的注册信用卡的 skill,然后把这个我最近注册的卡发给我", "创建时间": "2026-03-20T23:40:45.815000+00:00", "消息数量": 13 -}, -{ -"对话ID": "93c2142a-5a2a-46c4-ba71-a09d3b195215", -"名称": "AI Brain project exploration", -"项目": "微信管理", -"首条消息": "I need to explore the AI Brain related code and scripts in the work phone project. Please find and summarize:\n\n1. All files related to AI Brain in the project at /Users/karuo/Documents/开发/2、私域银行/工作手机/\n2. All skill files under sdk/agent/skills/ - what skills exist and their actions\n3. The ai_brain module if it exists under sdk/agent/\n4. The index.html smart engine / AI Brain section (search for \"智能引擎\" or \"AI Brain\" in the static files)\n5. Any existing scripts or automation modules\n6. The wechat_h", -"创建时间": "2026-03-20T16:31:04.926000+00:00", -"消息数量": 1 -}, -{ -"对话ID": "f756e455-b371-44e7-841e-ada153aefeee", -"名称": "WeChat account and device management UI", -"项目": "微信管理", -"首条消息": "You need to explore the Cunkebao v3 frontend project at `/Users/karuo/Documents/开发/2、私域银行/cunkebao_v3/Cunkebao/src` to understand how they design their WeChat account management and device management UI.\n\nSpecifically, look at these areas:\n1. `pages/mobile/mine/wechat-accounts/` - WeChat accounts list and detail pages\n2. `pages/mobile/mine/workphone/` - Work phone / device management pages \n3. `pages/mobile/mine/devices/` - Device management pages\n4. `components/DeviceSelection/` - Device selec", -"创建时间": "2026-03-20T15:18:46.161000+00:00", -"消息数量": 1 -}, -{ -"对话ID": "1aa14661-39a1-4bb8-a189-e986cbbb233a", -"名称": "工作手机项目文件搜索", -"项目": "开发", -"首条消息": "在工作手机项目中,搜索以下内容并返回关键信息:\n\n1. 找到 `机擎/阿机/SKILL.md` 文件,返回其中关于 Hook/Frida 相关的部分\n2. 找到 `sdk/app/routers/unified.py` 中关于设备管理和 hook 相关的路由定义\n3. 找到 `sdk/app/services/hook_module_service.py` 的内容摘要\n4. 找到 `开发文档/8、部署/README.md` 的内容\n5. 找到 `机擎/SKILL.md` 中 § 一 岗位职责部分\n\n搜索目录: /Users/karuo/Documents/开发/2、私域银行/工作手机\n\n返回每个文件的关键内容和路径。", -"创建时间": "2026-03-20T14:46:24.917000+00:00", -"消息数量": 18 } ] } \ No newline at end of file diff --git a/02_卡人(水)/水桥_平台对接/平台账号申诉解封/SKILL.md b/02_卡人(水)/水桥_平台对接/平台账号申诉解封/SKILL.md index ebed75cb..919f28b2 100644 --- a/02_卡人(水)/水桥_平台对接/平台账号申诉解封/SKILL.md +++ b/02_卡人(水)/水桥_平台对接/平台账号申诉解封/SKILL.md @@ -26,10 +26,27 @@ | 电话 | `400-9030057` 客户服务;`400-9030142` 为不良信息举报专线 | | 官网 | | -**发信**(11 位手机号为绑定号,两版话术): +**发信**(11 位手机号为绑定号,单封大白话): `python3 运营中枢/scripts/send_soul_appeal_mail.py 15210897710` `python3 运营中枢/scripts/send_soul_appeal_mail.py 13779954946` +**平台短信引用条款后的「分主题补充申诉」**(每号连发 4 封不同主题至同一批邮箱,间隔约 3 秒): +`python3 运营中枢/scripts/send_soul_appeal_mail.py 15210897710 --suite` +`python3 运营中枢/scripts/send_soul_appeal_mail.py --all-phones --suite`(152 + 137 各 4 封,共 8 封) + +### Soul《用户协议》被引用条款怎么理解?(辅助说明,以 App 内最新版为准) + +官方短信常见表述:违反 **2.2.3、2.2.4、2.2.5、3.2.11(1)—(8)、3.2.12** 等。 + +| 条款 | 常见含义(概括) | 备注 | +|:---|:---|:---| +| **2.2.3 / 2.2.4** | 与 **2.2** 节「用户使用账号时应遵守的义务」相关,多涉及**守法、不得干扰平台秩序**等 | 公开网页难逐字核对,**务必在 Soul App → 设置 → 关于 Soul → 用户协议** 打开当前版本对照 | +| **2.2.5** | 黑猫投诉等渠道有用户转述:不得利用账号**违法活动、捣乱、骚扰、欺骗其他用户**及**其他违反本协议的行为** | 与「骚扰/欺诈/破坏秩序」类处罚常一并出现 | +| **3.2.11(1)—(8)** | 多为**禁止发布或传播的信息类型**的**前八项列举**(如违法有害、低俗、侵权、虚假、营销导流等方向,**具体以协议原文分项为准**) | 平台若未告知触线子项,可邮件请求**指明项号与事实概要**以便整改 | +| **3.2.12** | 常与 3.2.11 同属**内容与行为规范**,多为**并列或递进的禁止性规定**(以原文为准) | 再申诉宜写清**整改承诺**,避免空怼 | + +**策略**:申诉未通过后,宜 **请求具体违规事实** + **分项承诺合规** + **申请二次复核**;**不能保证**一定解封。 + --- ## 二、抖音 diff --git a/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/base_provider.py b/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/base_provider.py index c298ada3..c82c839e 100644 --- a/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/base_provider.py +++ b/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/base_provider.py @@ -137,6 +137,11 @@ class EmailService: if self.email_type == "tempmail": return self._gen_tempmail() elif self.email_type == "mailtm": + fixed = self._mailtm_fixed_credentials() + if fixed: + addr, pwd = fixed + log.info("[邮箱] 使用固定 mail.tm(MAILTM_ADDRESS 或 config.mailtm.fixed_*)") + return self._mailtm_login(addr, pwd) return self._gen_mailtm() elif self.email_type == "cloudflare_worker": return self._gen_cf_worker() @@ -151,29 +156,33 @@ class EmailService: email = f"{prefix}{random_suffix}@tempmail.plus" return email, {"type": "tempmail", "pin": cfg.get("pin", "")} - def _gen_mailtm(self) -> tuple[str, dict]: - """mail.tm API 创建临时邮箱,可收验证码(与 Cerebras 同源)""" + def _mailtm_fixed_credentials(self) -> Optional[tuple[str, str]]: + """环境变量或 config.mailtm 固定账号,供 Cursor 等复用已创建的 mail.tm。""" + cfg = self.config.get("mailtm") or {} + addr = (os.environ.get("MAILTM_ADDRESS") or cfg.get("fixed_address") or "").strip() + pwd = (os.environ.get("MAILTM_PASSWORD") or cfg.get("fixed_password") or "").strip() + if addr and pwd: + return addr, pwd + return None + + def _mailtm_login(self, address: str, password: str) -> tuple[str, dict]: import httpx api = "https://api.mail.tm" - r = httpx.get(f"{api}/domains", timeout=10) - domains = r.json().get("hydra:member", []) - if not domains: - raise RuntimeError("mail.tm 无可用域名") - domain = domains[0]["domain"] - prefix = "".join(random.choices(string.ascii_lowercase + string.digits, k=12)) - email = f"{prefix}@{domain}" - password = "".join(random.choices(string.ascii_letters + string.digits, k=16)) - r = httpx.post(f"{api}/accounts", json={"address": email, "password": password}, timeout=15) - if r.status_code not in (200, 201): - raise RuntimeError(f"mail.tm 创建账号失败: {r.status_code} {r.text[:100]}") - r = httpx.post(f"{api}/token", json={"address": email, "password": password}, timeout=10) + t = 25 + r = httpx.post( + f"{api}/token", + json={"address": address, "password": password}, + timeout=t, + ) if r.status_code != 200: - raise RuntimeError("mail.tm 获取 token 失败") + raise RuntimeError(f"mail.tm 登录/token 失败: {r.status_code} {r.text[:120]}") token = r.json().get("token", "") - return email, {"type": "mailtm", "token": token} + if not token: + raise RuntimeError("mail.tm 返回空 token") + return address, {"type": "mailtm", "token": token} def _gen_mailtm(self) -> tuple[str, dict]: - """mail.tm API 创建临时邮箱,可收 Cursor 等验证码""" + """mail.tm API 新建临时邮箱(Cursor / Cerebras 等同源)""" import httpx api = "https://api.mail.tm" t = 25 @@ -188,38 +197,7 @@ class EmailService: r = httpx.post(f"{api}/accounts", json={"address": email, "password": password}, timeout=t) if r.status_code not in (200, 201): raise RuntimeError(f"mail.tm 创建失败: {r.status_code} {r.text[:80]}") - r = httpx.post(f"{api}/token", json={"address": email, "password": password}, timeout=t) - if r.status_code != 200: - raise RuntimeError(f"mail.tm token 失败: {r.status_code}") - token = r.json().get("token", "") - return email, {"type": "mailtm", "token": token} - - def _poll_mailtm(self, context: dict, timeout: int) -> Optional[str]: - """轮询 mail.tm 收件箱提取 6 位验证码""" - import httpx - token = context.get("token", "") - if not token: - return None - headers = {"Authorization": f"Bearer {token}"} - api = "https://api.mail.tm" - start = time.time() - while time.time() - start < timeout: - try: - r = httpx.get(f"{api}/messages", headers=headers, timeout=10) - for msg in r.json().get("hydra:member", []): - mid = msg.get("id", "") - if not mid: - continue - d = httpx.get(f"{api}/messages/{mid}", headers=headers, timeout=10).json() - subject = d.get("subject", "") - text = d.get("text", "") or (d.get("html") or [""])[0] if isinstance(d.get("html"), list) else "" - code = self._extract_code(subject, text) - if code: - return code - except Exception as e: - log.warning(f"[邮箱] mail.tm 轮询异常: {e}") - time.sleep(3) - return None + return self._mailtm_login(email, password) def _gen_cf_worker(self) -> tuple[str, dict]: import httpx @@ -363,14 +341,23 @@ class EmailService: return None def _extract_code(self, subject: str, body: str) -> Optional[str]: - """从邮件主题和正文中提取 6 位 OTP""" + """从邮件主题和正文中提取 6 位 OTP(正文可为 HTML)""" + import re as _re + + def _strip_html(s: str) -> str: + return _re.sub(r"<[^>]+>", " ", s or "") + + plain = (body or "") + "\n" + _strip_html(body or "") precise = self.RE_CODE_PRECISE.search(subject) if precise: return precise.group(1) - precise = self.RE_CODE_PRECISE.search(body) + precise = self.RE_CODE_PRECISE.search(plain) if precise: return precise.group(1) match = self.RE_OTP.search(subject) + if match: + return match.group(1) + match = self.RE_OTP.search(plain) if match: return match.group(1) return None diff --git a/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/cursor_provider.py b/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/cursor_provider.py index 8d39204a..fcb2ffde 100644 --- a/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/cursor_provider.py +++ b/03_卡木(木)/木根_逆向分析/全网AI自动注册/providers/cursor_provider.py @@ -58,6 +58,13 @@ class CursorProvider(BaseProvider): self.provider_config = config.get("providers", {}).get("cursor", {}) self.browser_config = config.get("browser", {}) + def _effective_headless(self) -> bool: + """CURSOR_HEADLESS=0|false|no 时强制有界面,利于 Turnstile。""" + v = os.environ.get("CURSOR_HEADLESS", "").strip().lower() + if v in ("0", "false", "no", "off"): + return False + return self.browser_config.get("headless", True) + def _create_browser(self): # 参考 ddCat-main/cursor-auto-register browser_utils:auto_port() + headless() from DrissionPage import ChromiumPage, ChromiumOptions @@ -70,7 +77,7 @@ class CursorProvider(BaseProvider): co.set_argument("--remote-allow-origins=*") co.set_argument("--window-size=1920,1080") co.auto_port() - use_headless = self.browser_config.get("headless", True) + use_headless = self._effective_headless() if use_headless: co.set_argument("--headless=new") co.headless(use_headless) @@ -95,7 +102,7 @@ class CursorProvider(BaseProvider): return None signup_url = self.provider_config.get("signup_url", SIGNUP_URL) settings_url = self.provider_config.get("settings_url", SETTINGS_URL) - headless = self.browser_config.get("headless", True) + headless = self._effective_headless() with sync_playwright() as p: browser = p.chromium.launch(headless=headless, args=["--no-sandbox"]) try: @@ -103,22 +110,21 @@ class CursorProvider(BaseProvider): page.goto(signup_url, wait_until="domcontentloaded", timeout=45000) time.sleep(5) log.info(f" [1/6] 打开注册页面 (Playwright)") - page.wait_for_selector('input', state="visible", timeout=25000) - time.sleep(1) - inputs = page.locator('input[type="text"], input[type="email"], input:not([type])') - n = inputs.count() - if n >= 3: - inputs.nth(0).fill(first) - time.sleep(0.15) - inputs.nth(1).fill(last) - time.sleep(0.15) - inputs.nth(2).fill(email) - else: - page.locator('input[name="first_name"], input[name="firstName"]').first.fill(first) - time.sleep(0.15) - page.locator('input[name="last_name"], input[name="lastName"]').first.fill(last) - time.sleep(0.15) - page.locator('input[name="email"], input[type="email"]').first.fill(email) + # 勿用裸 input,否则会命中 type=hidden(如 signals) + fn = page.locator( + 'input[name="first_name"], input[name="firstName"], input[autocomplete="given-name"]' + ).first + fn.wait_for(state="visible", timeout=45000) + time.sleep(0.5) + fn.fill(first) + time.sleep(0.15) + page.locator( + 'input[name="last_name"], input[name="lastName"], input[autocomplete="family-name"]' + ).first.fill(last) + time.sleep(0.15) + page.locator( + 'input[name="email"], input[type="email"], input[autocomplete="email"]' + ).first.fill(email) time.sleep(0.5) page.locator('button[type="submit"], input[type="submit"], [type="submit"]').first.click() time.sleep(3) diff --git a/运营中枢/scripts/send_soul_appeal_mail.py b/运营中枢/scripts/send_soul_appeal_mail.py index bcc4b039..2a3c7dae 100644 --- a/运营中枢/scripts/send_soul_appeal_mail.py +++ b/运营中枢/scripts/send_soul_appeal_mail.py @@ -2,9 +2,11 @@ """从卡若 gateway .env 读 SMTP,向 Soul 官方各邮箱发申诉邮件。 收件人:soul@、hr@、ad@、commercial-b@、pc@(官网公示的 5 个邮箱)。 + 用法: - python3 send_soul_appeal_mail.py 15210897710 # 大白话 A 版 - python3 send_soul_appeal_mail.py 13779954946 # 大白话 B 版 + python3 send_soul_appeal_mail.py 15210897710 # 单封(大白话 A/B) + python3 send_soul_appeal_mail.py 13779954946 --suite # 针对「条款引用」连发 4 封不同主题 + python3 send_soul_appeal_mail.py --all-phones --suite # 152+137 各发 4 封(共 8 封) 不在终端打印密码。 """ @@ -13,11 +15,11 @@ from __future__ import annotations import os import smtplib import sys +import time from email.message import EmailMessage from pathlib import Path DEFAULT_ENV = Path(__file__).resolve().parent / "karuo_ai_gateway" / ".env" -# Soul 官网公示的官方邮箱,用户要求账号申诉一并抄送 TO_LIST = [ "soul@soulapp.cn", "hr@soulapp.cn", @@ -25,6 +27,7 @@ TO_LIST = [ "commercial-b@soulapp.cn", "pc@soulapp.cn", ] +DEFAULT_PHONES = ("15210897710", "13779954946") def load_env_file(path: Path) -> None: @@ -43,7 +46,6 @@ def load_env_file(path: Path) -> None: def appeal_variant_a(phone: str) -> tuple[str, str]: - """152 绑定号:分条 + 大白话。""" subject = f"求助|Soul账号被限制,求人工复核(手机{phone})" body = f"""Soul 客服您好, @@ -65,7 +67,6 @@ def appeal_variant_a(phone: str) -> tuple[str, str]: def appeal_variant_b(phone: str) -> tuple[str, str]: - """137 绑定号:另一套大白话(叙述流,同目的)。""" subject = f"想申请恢复账号|绑定手机{phone}" body = f"""您好, @@ -90,15 +91,120 @@ def pick_variant(phone: str) -> tuple[str, str]: return appeal_variant_b(phone) +def suite_appeals(phone: str) -> list[tuple[str, str]]: + """针对平台短信引用 2.2.3、2.2.4、2.2.5、3.2.11(1-8)、3.2.12 的补充申诉(分封主题,避免一封过长)。""" + cite = "2.2.3、2.2.4、2.2.5、3.2.11(1)-(8)、3.2.12" + return [ + ( + f"【二次申诉】绑定手机{phone}|已收贵司条款引用,恳请书面告知具体违规事实", + f"""Soul 客服团队您好, + +我的绑定手机号为 {phone}。此前收到贵司通知,称申诉未通过,并引用《用户协议》{cite} 等条款。 + +本人已重新阅读 App 内《用户协议》相关章节,愿意遵守平台规则。但目前仍不清楚:**具体是哪一类行为、哪一条动态/私信/场景**触发了上述条款的适用,导致封号。没有可操作的违规事实说明,我无法完成针对性整改,也难以判断是否存在误判。 + +故恳请贵司在合规前提下,通过邮件或站内途径告知:**违规内容类型、大致时间、对应功能场景**(无需泄露他人隐私即可)。本人承诺在知悉后立刻整改,并申请**二次人工复核**。 + +回复请发至本邮件发件邮箱,亦可致电我登记号码 {phone}(如可外呼)。 + +感谢。 + +账号持有人({phone}) +""", + ), + ( + f"【分项说明】绑定手机{phone}|关于第2.2.3、2.2.4、2.2.5条之理解与承诺", + f"""Soul 客服您好, + +绑定手机 {phone}。现就贵司援引的协议第 2.2.3、2.2.4、2.2.5 条说明如下: + +据公开渠道中用户对 2.2.5 条的转述,该款大意包含:**不得利用账号从事违法活动、捣乱、骚扰、欺骗其他用户及违反协议的行为**。2.2.3、2.2.4 与同节条款通常指向**守法使用账号、维护平台秩序**等义务(**具体以本人 App 内当前版本《用户协议》原文为准**)。 + +本人确认:**无故意从事违法、欺诈、恶意骚扰或破坏社区秩序的主观意图**;若曾有言行被系统判定越界,愿在贵司指出具体事实后**立即纠正**,并加强自我约束。 + +恳请结合上述说明,对账号是否具备**从轻、整改后恢复**的空间予以复核。 + +账号持有人 {phone} +""", + ), + ( + f"【分项说明】绑定手机{phone}|关于第3.2.11条第(1)-(8)项之合规承诺", + f"""Soul 客服您好, + +绑定手机 {phone}。贵司通知中援引 3.2.11 条第(1)至(8)项。该类条款在实务中一般对应**禁止发布的多类违规信息**(如违法有害、低俗、人身攻击、虚假误导、侵权、违规营销导流等,**具体子项以 App 内协议原文为准**)。 + +本人承诺: +• 不在平台发布违反法律法规及《Soul 用户行为规范》的信息; +• 不从事恶意营销、刷屏骚扰、诱导站外交易或欺诈等行为; +• 对他人与平台保持尊重,不故意散布不实信息。 + +若贵司认定本人曾违反上述任一项,请**指明对应项号与事实概要**,本人愿删除相关内容、书面说明情况并申请复核。 + +账号持有人 {phone} +""", + ), + ( + f"【分项说明】绑定手机{phone}|关于第3.2.12条及持续合规使用承诺", + f"""Soul 客服您好, + +绑定手机 {phone}。就贵司一并援引的第 3.2.12 条,本人理解其通常与 3.2.11 等条款共同构成**内容与安全规范**体系(**以 App 内最新协议为准**)。 + +本人承诺后续将: +• 发帖、聊天、匹配互动前对照《用户行为规范》自查; +• 不参与灰产引流、不当交友诱导、违规广告等行为; +• 配合贵司合理的内容管理与身份核验要求。 + +鉴于此前申诉未通过,本人仍恳请贵司在本人**已表态整改、愿配合说明**的前提下,考虑是否给予**观察期、限制解除或账号恢复**的机会。 + +联系:本邮件发件地址;手机 {phone}。 + +账号持有人 +""", + ), + ] + + +def send_one( + host: str, + port: int, + user: str, + password: str, + subject: str, + body: str, +) -> None: + msg = EmailMessage() + msg["Subject"] = subject + msg["From"] = user + msg["To"] = ", ".join(TO_LIST) + msg.set_content(body) + with smtplib.SMTP_SSL(host, port, timeout=30) as smtp: + smtp.login(user, password) + smtp.send_message(msg) + + def main() -> int: - phone = (sys.argv[1] if len(sys.argv) > 1 else "").strip() - if not phone: - print("用法: python3 send_soul_appeal_mail.py <11位手机号>", file=sys.stderr) - print("示例: … 15210897710 或 … 13779954946", file=sys.stderr) - return 1 - if not phone.isdigit() or len(phone) != 11: - print("手机号须为 11 位数字", file=sys.stderr) - return 1 + args = [a for a in sys.argv[1:] if not a.startswith("--")] + flags = {a for a in sys.argv[1:] if a.startswith("--")} + suite = "--suite" in flags + all_phones = "--all-phones" in flags + + if all_phones: + phones = list(DEFAULT_PHONES) + else: + phone = (args[0] if args else "").strip() + if not phone: + print( + "用法:\n" + " python3 send_soul_appeal_mail.py <11位手机号>\n" + " python3 send_soul_appeal_mail.py <手机号> --suite\n" + " python3 send_soul_appeal_mail.py --all-phones --suite", + file=sys.stderr, + ) + return 1 + if not phone.isdigit() or len(phone) != 11: + print("手机号须为 11 位数字", file=sys.stderr) + return 1 + phones = [phone] env_path = Path(os.environ.get("KARUO_SMTP_ENV", str(DEFAULT_ENV))) load_env_file(env_path) @@ -109,27 +215,29 @@ def main() -> int: port = int(os.environ.get("SMTP_PORT", "465") or "465") if not user or not password: - print("错误:未从环境或", env_path, "读取到 SMTP_USER / SMTP_PASS", file=sys.stderr) + print("错误:未读取到 SMTP_USER / SMTP_PASS", env_path, file=sys.stderr) return 1 - subject, body = pick_variant(phone) - - msg = EmailMessage() - msg["Subject"] = subject - msg["From"] = user - msg["To"] = ", ".join(TO_LIST) - msg.set_content(body) - try: - with smtplib.SMTP_SSL(host, port, timeout=30) as smtp: - smtp.login(user, password) - smtp.send_message(msg) + n_sent = 0 + for phone in phones: + if suite: + pairs = suite_appeals(phone) + else: + pairs = [pick_variant(phone)] + + for subject, body in pairs: + send_one(host, port, user, password, subject, body) + n_sent += 1 + print("OK", n_sent, subject[:56] + ("…" if len(subject) > 56 else "")) + if suite and len(pairs) > 1: + time.sleep(3) + + print("共发送", n_sent, "封 →", ", ".join(TO_LIST)) except Exception as e: print("发送失败:", type(e).__name__, str(e), file=sys.stderr) return 2 - print("已发送至", len(TO_LIST), "个邮箱:", ", ".join(TO_LIST)) - print("主题:", subject) return 0 diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index cdcc1cf7..6c18b0a5 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -430,3 +430,4 @@ | 2026-03-23 16:22:10 | 🔄 卡若AI 同步 2026-03-23 16:22 | 更新:金仓、水溪整理归档、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | | 2026-03-23 16:22:19 | 🔄 卡若AI 同步 2026-03-23 16:22 | 更新:总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | | 2026-03-23 16:35:47 | 🔄 卡若AI 同步 2026-03-23 16:35 | 更新:Cursor规则、金仓、卡人、水溪整理归档、火炬、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | +| 2026-03-23 16:37:40 | 🔄 卡若AI 同步 2026-03-23 16:37 | 更新:Cursor规则、金仓、水溪整理归档、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index a5cd91cc..e9a7cc7b 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -433,3 +433,4 @@ | 2026-03-23 16:22:10 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-23 16:22 | 更新:金仓、水溪整理归档、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-23 16:22:19 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-23 16:22 | 更新:总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-03-23 16:35:47 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-23 16:35 | 更新:Cursor规则、金仓、卡人、水溪整理归档、火炬、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-03-23 16:37:40 | 成功 | 成功 | 🔄 卡若AI 同步 2026-03-23 16:37 | 更新:Cursor规则、金仓、水溪整理归档、总索引与入口、运营中枢工作台 | 排除 >20MB: 11 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | diff --git a/运营中枢/工作台/阿猫Mac_OpenClaw配置情况分析.md b/运营中枢/工作台/阿猫Mac_OpenClaw配置情况分析.md index ae754a89..67a22d49 100644 --- a/运营中枢/工作台/阿猫Mac_OpenClaw配置情况分析.md +++ b/运营中枢/工作台/阿猫Mac_OpenClaw配置情况分析.md @@ -123,4 +123,16 @@ --- +## 十、卡若 AI 网站(官网)对接阿猫 OpenClaw 网关 + +| 项目 | 说明 | +|------|------| +| **环境变量** | \`开发/3、自营项目/卡若ai网站/site/.env.local\` 已配置 \`OPENCLAW_GATEWAY_URL\`(默认 \`http://macbook.quwanzhi.com:18789\`)、\`OPENCLAW_GATEWAY_TOKEN\`(与阿猫 \`~/.openclaw/openclaw.json\` 中 \`gateway.auth.token\` 一致)、\`OPENCLAW_GATEWAY_MODEL\` 等。 | +| **Mongo** | \`storage-mongo\` 在初始化网关后会 **upsert** \`gw-openclaw-amiao\`(展示名:OpenClaw·阿猫笔记本(龙虾))。 | +| **路由** | 官网 \`gateway-router\` 对 \`claude*\` 模型在有该网关 Key 时 **优先** 走阿猫 OpenClaw。 | +| **Docker** | \`卡若ai网站/docker-compose.yml\` 已传入上述变量;生产环境须保证 **容器能访问** 阿猫网关地址(非把阿猫的 127.0.0.1 当本机)。 | +| **控制台** | 管理员 POST \`/api/gateway/sync-keys\` 时也会从环境变量合并 \`gw-openclaw-amiao\`。 | + +--- + *文档生成:卡若AI 工作台。*