Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions PRODUCT_CAPABILITIES.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@

| 能力域 | 能力 | 用户结果 | 当前状态 |
|---|---|---|---|
| 分享入口 | 在微信转发菜单增加十二个入口 | 无需打开微信流主窗口即可发起场景 | 稳定 |
| 分享入口 | 在微信转发菜单增加十三个入口 | 无需打开微信流主窗口即可发起场景 | 稳定 |
| 分批收集 | 连续接收多批原始 ZIP,最后统一选择目标和场景 | 浮条首尾参考、记录页恢复、冻结交付和失败重试 | 开发版已实现,微信宿主分享链路待实测 |
| 文件接入 | 接收微信导出的 ZIP 和文件型附件 | 原始文件和文件名进入本地批次 | 稳定 |
| 目标转发 | 发给 Codex、Claude、豆包、千问办公、WorkBuddy、WeSight 或自定义应用 | 激活目标 App 并自动粘贴 | 稳定,依赖辅助功能权限 |
| 目标转发 | 发给 Codex、Claude、豆包、千问办公、WorkBuddy、WeSight、DeepSeek Harness、Qoder CN 或自定义应用 | 激活目标 App 并自动粘贴 | 稳定,依赖辅助功能权限 |
| Obsidian | 生成 Markdown 笔记并保存原始归档 | 聊天记录进入本地知识库 | 稳定 |
| 剪贴板 | 文件写入剪贴板 | 用户自行在目标位置粘贴 | 稳定 |
| 记录 | 历史批次、状态、重新发送和清理 | 可以确认文件是否送达 | 稳定 |
Expand Down Expand Up @@ -178,7 +178,7 @@
### 8.2 网络

- 除软件更新外不联网。
- 十二个 Share Extension 均在沙盒中运行。
- 十三个 Share Extension 均在沙盒中运行。
- 扩展没有网络权限。

### 8.3 系统权限
Expand Down Expand Up @@ -219,7 +219,7 @@

| 能力 | 主要实现 |
|---|---|
| 十二个分享入口 | `macos/Scripts/share-slots.sh` |
| 十三个分享入口 | `macos/Scripts/share-slots.sh` |
| Share Extension 接入 | `macos/Sources/WeChatBridgeShare/ShareViewController.swift` |
| 附件复制与命名 | `macos/Sources/WeChatBridgeShare/AttachmentImporter.swift` |
| 目标应用定义 | `macos/Sources/WeChatBridgeCore/ShareAction.swift` |
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ flowchart LR

| 能力 | 使用体验 |
| --- | --- |
| 十二个原生入口 | 在微信转发菜单直接选择目标,无需打开微信流主窗口 |
| 十三个原生入口 | 在微信转发菜单直接选择目标,无需打开微信流主窗口 |
| AI Agent 转发 | 激活目标 App,附加场景指令并自动粘贴聊天归档 |
| Obsidian 沉淀 | 生成 Markdown 笔记,保存原始 ZIP,并按聊天名组织内容 |
| 自定义目标 | 添加任意 macOS 应用,终端类应用可只接收文件路径 |
Expand All @@ -59,6 +59,7 @@ flowchart LR
| 发给 WorkBuddy | 激活 WorkBuddy 并粘贴聊天归档 |
| 发给 WeSight | 激活 WeSight 并粘贴聊天归档 |
| 发给 DeepSeek Harness | 激活 DeepSeek Harness 并粘贴聊天归档 |
| 发给 Qoder CN | 激活 Qoder CN 并粘贴聊天归档 |
| 沉淀到 Obsidian | 创建 Markdown 笔记并保存原始附件,通知可打开笔记 |
| 沉淀到文件夹 | 写入选定目录中的 Markdown 与附件,通知可在访达中定位 |
| 分批收集到微信流 | 连续分享多批原始 ZIP,收齐后一次选择目标和场景 |
Expand All @@ -85,7 +86,7 @@ flowchart LR
<td align="center"><img src="shared/Screenshots/usage-scenes.png" width="420" alt="场景管理页" /></td>
</tr>
<tr>
<td align="center"><sub>十二个入口随时开关,未安装的应用直接标注</sub></td>
<td align="center"><sub>十三个入口随时开关,未安装的应用直接标注</sub></td>
<td align="center"><sub>场景保存提示词与适用 Agent,转发时挑一个</sub></td>
</tr>
<tr>
Expand Down Expand Up @@ -179,7 +180,7 @@ shared/ # 两端共用的资产与契约
site/ # Sparkle 更新源与版本说明
```

项目使用 Swift Package Manager 管理 macOS 源码和 Sparkle 依赖。`macos/Scripts/make-app.sh` 会把主程序与十二个 Share Extension 组装成完整的 `.app`。Windows 侧见 `windows/AGENTS.md` 与 `windows/docs/README.zh-CN.md`。
项目使用 Swift Package Manager 管理 macOS 源码和 Sparkle 依赖。`macos/Scripts/make-app.sh` 会把主程序与十三个 Share Extension 组装成完整的 `.app`。Windows 侧见 `windows/AGENTS.md` 与 `windows/docs/README.zh-CN.md`。

## 开发与验证

Expand Down
7 changes: 4 additions & 3 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ flowchart LR

| Capability | Experience |
| --- | --- |
| Twelve native entries | Pick a destination in WeChat without opening the main app |
| Thirteen native entries | Pick a destination in WeChat without opening the main app |
| AI agent hand-off | Activate the target app, attach a scene prompt, and paste the archive |
| Obsidian archiving | Create a Markdown note, retain the original ZIP, and organize it by chat name |
| Custom destinations | Add any macOS app; terminal-style apps can receive file paths only |
Expand All @@ -59,6 +59,7 @@ flowchart LR
| Send to WorkBuddy | Activate WorkBuddy and paste the conversation archive |
| Send to WeSight | Activate WeSight and paste the conversation archive |
| Send to DeepSeek Harness | Activate DeepSeek Harness and paste the conversation archive |
| Send to Qoder CN | Activate Qoder CN and paste the conversation archive |
| Save to Obsidian | Create a Markdown note and preserve the original attachment |
| Save to folder | Write Markdown and attachments to the selected folder; reveal files from the notification |
| Collect in WeChatBridge | Receive multiple original ZIPs, then choose a target and scene once |
Expand All @@ -83,7 +84,7 @@ Pick a destination straight from WeChat's “Forward to other apps” menu, with
<td align="center"><img src="shared/Screenshots/usage-scenes.png" width="420" alt="Scene management pane" /></td>
</tr>
<tr>
<td align="center"><sub>Toggle any of the twelve entries; missing apps are flagged</sub></td>
<td align="center"><sub>Toggle any of the thirteen entries; missing apps are flagged</sub></td>
<td align="center"><sub>Scenes store prompts and their agents, chosen at forward time</sub></td>
</tr>
<tr>
Expand Down Expand Up @@ -156,7 +157,7 @@ shared/ # Agent logos, design assets, screenshots, and skills
site/ # Sparkle update feed and release notes
```

Swift Package Manager owns the source layout and the Sparkle dependency. `macos/Scripts/make-app.sh` assembles the host executable and twelve Share Extensions into a complete `.app` bundle.
Swift Package Manager owns the source layout and the Sparkle dependency. `macos/Scripts/make-app.sh` assembles the host executable and thirteen Share Extensions into a complete `.app` bundle.

## Development checks

Expand Down
4 changes: 2 additions & 2 deletions USAGE.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

## 转发入口

十二个入口覆盖主流 Agent、笔记软件和剪贴板,随时可以用开关收窄或放开。
十三个入口覆盖主流 Agent、笔记软件和剪贴板,随时可以用开关收窄或放开。

![入口设置页](shared/Screenshots/usage-entries.png)

Expand All @@ -29,7 +29,7 @@

![支持的 Agent](shared/Screenshots/usage-supported-agents.png)

- 发给 Codex / Claude / 豆包 / 千问办公 / WorkBuddy / WeSight:激活目标应用并粘贴聊天归档。
- 发给 Codex / Claude / 豆包 / 千问办公 / WorkBuddy / WeSight / DeepSeek Harness / Qoder CN:激活目标应用并粘贴聊天归档。
- 沉淀到 Obsidian:生成 Markdown 笔记,同时保存微信导出的原始压缩包;通过通知打开笔记。
- 沉淀到文件夹:将 Markdown、原始 ZIP 和附件保存到选定目录,默认位置为下载目录下的「微信流」文件夹。
- 复制到剪贴板:只写文件,不自动粘贴,由你自己决定贴到哪里。
Expand Down
4 changes: 2 additions & 2 deletions USAGE_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ These entries come from WeChatBridge and sit in the same menu as AirDrop, Messag

## Destinations

Twelve entries cover mainstream agents, note-taking apps, and the clipboard. You can narrow or widen the list at any time.
Thirteen entries cover mainstream agents, note-taking apps, and the clipboard. You can narrow or widen the list at any time.

![Entries settings](shared/Screenshots/usage-entries.png)

Expand All @@ -29,7 +29,7 @@ Supported agents:

![Supported agents](shared/Screenshots/usage-supported-agents.png)

- Send to Codex / Claude / Doubao / QwenWork / WorkBuddy / WeSight: activate the target app and paste the archive.
- Send to Codex / Claude / Doubao / QwenWork / WorkBuddy / WeSight / DeepSeek Harness / Qoder CN: activate the target app and paste the archive.
- Save to Obsidian: create a Markdown note and keep the original WeChat export.
- Copy to Clipboard: write the files without pasting, so you decide where they land.
- Send to Custom: add any macOS app; terminal-style apps can receive file paths only.
Expand Down
2 changes: 2 additions & 0 deletions macos/Resources/Localizations/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"发给豆包" = "Send to Doubao";
"发给 WeSight" = "Send to WeSight";
"发给 DeepSeek Harness" = "Send to DeepSeek Harness";
"发给 Qoder CN" = "Send to Qoder CN";
"沉淀到 Obsidian" = "Save to Obsidian";
"沉淀到文件夹" = "Save to Folder";
"添加应用…" = "Add an App…";
Expand Down Expand Up @@ -131,6 +132,7 @@
"激活豆包并直接粘贴到输入框。" = "Brings Doubao forward and pastes straight into its input.";
"激活 WeSight 并直接粘贴到输入框。" = "Brings WeSight forward and pastes straight into its input.";
"激活 DeepSeek Harness 并直接粘贴到输入框。" = "Brings DeepSeek Harness forward and pastes straight into its input.";
"激活 Qoder CN 并直接粘贴到输入框。" = "Brings Qoder CN forward and pastes straight into its input.";
"把聊天记录转成 Markdown,写入选定的 Obsidian 知识库。" = "Turns the chat archive into Markdown and writes it into the selected Obsidian vault.";
"把聊天记录转成 Markdown 和附件,写入选定的文件夹。" = "Turns the chat into Markdown and attachments in the folder you choose.";
"只放进剪贴板,去哪儿按 ⌘V 由你决定。" = "Puts them on the clipboard and leaves the ⌘V to you.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"发给豆包" = "发给豆包";
"发给 WeSight" = "发给 WeSight";
"发给 DeepSeek Harness" = "发给 DeepSeek Harness";
"发给 Qoder CN" = "发给 Qoder CN";
"沉淀到 Obsidian" = "沉淀到 Obsidian";
"沉淀到文件夹" = "沉淀到文件夹";
"添加应用…" = "添加应用…";
Expand Down Expand Up @@ -131,6 +132,7 @@
"激活豆包并直接粘贴到输入框。" = "激活豆包并直接粘贴到输入框。";
"激活 WeSight 并直接粘贴到输入框。" = "激活 WeSight 并直接粘贴到输入框。";
"激活 DeepSeek Harness 并直接粘贴到输入框。" = "激活 DeepSeek Harness 并直接粘贴到输入框。";
"激活 Qoder CN 并直接粘贴到输入框。" = "激活 Qoder CN 并直接粘贴到输入框。";
"把聊天记录转成 Markdown,写入选定的 Obsidian 知识库。" = "把聊天记录转成 Markdown,写入选定的 Obsidian 知识库。";
"把聊天记录转成 Markdown 和附件,写入选定的文件夹。" = "把聊天记录转成 Markdown 和附件,写入选定的文件夹。";
"只放进剪贴板,去哪儿按 ⌘V 由你决定。" = "只放进剪贴板,去哪儿按 ⌘V 由你决定。";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"CFBundleDisplayName" = "Send to Qoder CN";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"CFBundleDisplayName" = "发给 Qoder CN";
4 changes: 2 additions & 2 deletions macos/Scripts/check-release-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ plutil -lint "$APP_INFO" "$SHARE_INFO" "$APP_ENTITLEMENTS" "$SHARE_ENTITLEMENTS"
plutil -lint "$ROOT"/Resources/Localizations/*/*.strings "$ROOT"/Resources/ShareLocalizations/*/*/*.strings >/dev/null
python3 -m json.tool "$SHARED/Skills/catalog.json" >/dev/null

if [ "${#SHARE_SLOTS[@]}" -ne 12 ]; then
echo "expected 12 Share-menu entries, found ${#SHARE_SLOTS[@]}" >&2
if [ "${#SHARE_SLOTS[@]}" -ne 13 ]; then
echo "expected 13 Share-menu entries, found ${#SHARE_SLOTS[@]}" >&2
exit 1
fi

Expand Down
4 changes: 3 additions & 1 deletion macos/Scripts/share-slots.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# same pkd election System Settings → General → Login Items & Extensions →
# Sharing does.
#
# All twelve run the same executable and tell themselves apart by DKShareAction,
# All of them run the same executable and tell themselves apart by DKShareAction,
# so adding an entry costs a row here and a pair of InfoPlist.strings — not a
# second copy of the import code.
#
Expand All @@ -25,6 +25,7 @@ SHARE_SLOTS=(
"WorkBuddy|WeChatBridgeShareWorkBuddy|ShareWorkBuddy|workBuddy|发给 WorkBuddy"
"WeSight|WeChatBridgeShareWeSight|ShareWeSight|weSight|发给 WeSight"
"DeepSeekHarness|WeChatBridgeShareDeepSeekHarness|ShareDeepSeekHarness|deepSeekHarness|发给 DeepSeek Harness"
"QoderCN|WeChatBridgeShareQoderCN|ShareQoderCN|qoderCN|发给 Qoder CN"
"Obsidian|WeChatBridgeShareObsidian|ShareObsidian|obsidian|沉淀到 Obsidian"
"Collection|WeChatBridgeShareCollection|ShareCollection|collect|分批收集到微信流"
"Folder|WeChatBridgeShareFolder|ShareFolder|folder|沉淀到文件夹"
Expand All @@ -42,6 +43,7 @@ share_logo_name() {
QwenWork) printf '%s' "02-qwen.png" ;;
WorkBuddy) printf '%s' "06-workbuddy.png" ;;
WeSight) printf '%s' "07-wesight.png" ;;
QoderCN) printf '%s' "08-qodercn.png" ;;
Obsidian) printf '%s' "05-obsidian.png" ;;
esac
}
2 changes: 1 addition & 1 deletion macos/Sources/WeChatBridgeApp/ActionRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ final class ActionRunner {
// Nothing is shown: the share sheet said 「已复制到剪贴板」 a moment
// ago and is still on screen. A second capsule saying it again is
// WeChatBridge talking over the system.
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .obsidian, .folder, .custom:
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .qoderCN, .obsidian, .folder, .custom:
// Shares and WeChat captures share the same clipboard queue.
//
// Read here rather than where the panel opens. This forward may wait
Expand Down
2 changes: 1 addition & 1 deletion macos/Sources/WeChatBridgeApp/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ final class AppModel: ObservableObject {
// Already copied, by the extension, and already recorded as
// such by `BatchState.initial`. Nothing left to do.
return false
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .obsidian, .folder, .custom:
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .qoderCN, .obsidian, .folder, .custom:
// A forward whose one-shot request is already gone: the file was
// consumed by a run that then died before it could act, or the
// extension never managed to write it. Either way nothing can be
Expand Down
1 change: 1 addition & 0 deletions macos/Sources/WeChatBridgeApp/ForwardTargets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ final class ForwardTargets: ObservableObject {
ForwardDestination(action: .workBuddy, target: nil),
ForwardDestination(action: .weSight, target: nil),
ForwardDestination(action: .deepSeekHarness, target: nil),
ForwardDestination(action: .qoderCN, target: nil),
ForwardDestination(action: .obsidian, target: nil),
] + targets.map { ForwardDestination(action: .custom, target: $0) }
}
Expand Down
2 changes: 1 addition & 1 deletion macos/Sources/WeChatBridgeApp/ShareEntryProbe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ final class ShareEntryProbe: ObservableObject {
///
/// `run` blocks on a `DispatchSemaphore`, and a blocked cooperative thread
/// is gone until it unblocks — the runtime cannot reclaim it. `refresh`
/// probes nine entries in a row, so one cold `pkd` could park a pool thread
/// probes every entry in a row, so one cold `pkd` could park a pool thread
/// for 15 s, and flipping several switches quickly parks more. On a
/// four-core Mac that is most of the pool, and the `Task.sleep` loop
/// `AutoPaste` uses to wait for the target app to come frontmost has a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ struct ShareEntryList: View {
case .qwen: file = "02-qwen.png"
case .workBuddy: file = "06-workbuddy.png"
case .weSight: file = "07-wesight.png"
case .qoderCN: file = "08-qodercn.png"
case .obsidian: file = "05-obsidian.png"
case .deepSeekHarness, .collect, .folder, .clipboard, .custom: return nil
}
Expand All @@ -187,7 +188,7 @@ struct ShareEntryList: View {
/// table of symbols would be a second answer to "which icon is this entry".
static func symbol(for action: ShareAction) -> String {
switch action {
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness: "paperplane"
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .qoderCN: "paperplane"
case .obsidian: "book.closed"
case .collect: "tray.and.arrow.down"
case .folder: "folder"
Expand All @@ -199,7 +200,7 @@ struct ShareEntryList: View {
private func detail(for action: ShareAction) -> String {
if compactDetails {
switch action {
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness:
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .qoderCN:
guard let bundleIdentifier = action.targetBundleIdentifier else {
return L10n.text("未安装")
}
Expand Down Expand Up @@ -231,6 +232,7 @@ struct ShareEntryList: View {
case .workBuddy: return L10n.text("激活 WorkBuddy 并直接粘贴到输入框。")
case .weSight: return L10n.text("激活 WeSight 并直接粘贴到输入框。")
case .deepSeekHarness: return L10n.text("激活 DeepSeek Harness 并直接粘贴到输入框。")
case .qoderCN: return L10n.text("激活 Qoder CN 并直接粘贴到输入框。")
case .obsidian: return L10n.text("把聊天记录转成 Markdown,写入选定的 Obsidian 知识库。")
case .collect: return L10n.text("多次分享,收齐后一起发送")
case .folder: return L10n.text("把聊天记录转成 Markdown 和附件,写入选定的文件夹。")
Expand All @@ -242,7 +244,7 @@ struct ShareEntryList: View {
private func detailIsWarning(for action: ShareAction) -> Bool {
guard compactDetails else { return false }
switch action {
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness:
case .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .qoderCN:
return action.targetBundleIdentifier.map {
!InstalledApp.lookup($0).isInstalled
} ?? true
Expand Down
2 changes: 1 addition & 1 deletion macos/Sources/WeChatBridgeCore/BatchState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public struct BatchState: Codable, Sendable, Hashable {
action: action,
targetName: targetName
)
case .collect, .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .obsidian, .folder, .custom:
case .collect, .codex, .claude, .doubao, .qwen, .workBuddy, .weSight, .deepSeekHarness, .qoderCN, .obsidian, .folder, .custom:
return BatchState(outcome: nil, action: action, targetName: targetName)
}
}
Expand Down
Loading