Commit Graph
118 Commits
Author SHA1 Message Date
修雨 b63e1b4469 release: cut 1.0.47 — connector supervision + bot-to-bot @-mention (#548) 2026-07-06 00:46:47 +08:00
e32fa1535c feat(auth): support multi-profile login (#500)
* feat(auth): support multi-profile login

* fix(auth): complete multi-org profile acceptance

* feat(auth): 完成多组织 profile 验收

* docs(auth): 补充多组织 Ralph 验收材料

* feat(auth): 支持 auth switch TUI 切换 profile

* feat(auth): logout 默认清理所有组织

* feat(auth): login 默认新增组织授权

* feat(profile): 使用 profile switch 切换组织

* docs(ralph): 更新 profile switch 验收材料

* fix(profile): 展示全部可切换组织

* feat(profile): support multi-org switch tui

* chore(install): add branch source installer

* fix(profile): keep global profile out of tool params

* feat(profile): support csv multi-profile runtime

* ci: add multi-profile e2e workflow

* ci: run multi-profile e2e on all branches

* docs: document multi-profile e2e ci gate

* docs: remove multi-profile test cases from pr

* ci: harden multi-profile e2e gates

* fix(auth): serialize profiles.json RMW and harden multi-profile persistence

Wrap all profiles.json read-modify-write paths (profile switch/use/remove,
status marking, token save, logout) in the existing dual-layer lock via a new
withProfilesLock helper. Split each writer into a public (locking) entry point
plus a lock-free *Locked variant so the non-reentrant lock is never re-acquired;
the refresh path (oauth_helpers) and the load-path legacy migration now call the
lock-free saver to avoid self-deadlock.

Also: write profiles.json and the token marker via per-write random temp names
(uuid) to stop concurrent writers from corrupting a fixed .tmp file; quarantine
an unparseable profiles.json and rebuild an empty config so the CLI can
self-heal instead of locking out auth reset/logout; make DeleteAllTokenData
proceed even if profiles.json cannot be read; and stop SyncLegacyTokenMirror
from deleting the legacy mirror on a transient keychain read error.

* fix(auth): do not fall back to a different org's legacy token slot

When no explicit --profile is given, LoadTokenDataForProfile resolves the
current/primary profile and reads its per-corp keychain slot. If that slot
read failed, the code silently fell through to the legacy single token slot,
which after any drift between the legacy mirror and the current profile could
belong to a different organization. The command would then run as the wrong
org with no indication to the user.

Reproduction (conceptual):
  - profiles.json currentProfile = corpA
  - corpA's keychain slot is unreadable, legacy single slot still holds corpB
  - any read command (no --profile) silently used corpB's token

Fix: when a profile is resolved but its slot read fails and no --profile was
given, only fall back to the legacy single slot when its CorpID matches the
resolved profile (same org); otherwise return the original error instead of
acting as a different organization. The no-profile legacy path (pre-migration
installs with no resolved profile) is unchanged.

Tests:
  - Covered by the existing internal/auth suite under go test -race; the
    same-org fallback preserves the legacy-mirror case while the cross-org
    case now surfaces the read error.

* feat(skill): document multi-org profile usage and always ship dws-shared

The skills had no guidance on the multi-profile capability, so an agent would
treat the CLI as single-org: when a lookup missed in the current org it would
give up or ask the user instead of searching other logged-in orgs. The multi
skill set also referenced a `dws-shared` prerequisite that was never actually
installed, and the only multi-org hints lived inline in three product skills.

This adds, in source only:
- A "multi-org / profile" section in the mono SKILL.md (concept, commands,
  cross-org rule, aggregation, safety guardrails) plus a decision-tree entry,
  trigger conditions, and a corrected logout danger-table row (logout removes
  all orgs by default; removing the primary silently re-elects a new primary,
  confirm before removing the primary).
- A standalone skills/multi/dingtalk-profile skill mirroring the same content.
- A new skills/multi/dws-shared skill that carries auth, global flags and the
  multi-org rule, so every product skill's PREREQUISITE resolves and all
  read/search skills inherit the cross-org behavior without per-skill edits.
- Cross-org fallback notes on dingtalk-aisearch / chat / contact.

To guarantee the prerequisite actually ships, multi-mode install now force-
includes dws-shared even when --skill / --exclude narrows the set (no-op when
the source has no dws-shared, preserving older layouts).

Tests:
  - internal/app: TestP1SharedAlwaysIncludedWithSkillFilter installs with
    `-s aitable` and asserts dws-shared still lands in the destination;
    TestP1SharedNoopWhenAbsent guards the older-layout no-op.
  - go test -race ./internal/auth/... ./internal/app/... passes.

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
Co-authored-by: qinze <audanye@gmail.com>
2026-06-29 18:27:25 +08:00
修雨 79b8eda3b6 feat(chat): default --ai-tag on so dws-sent messages carry the AI badge
Per req 83667761 (奕皓): messages sent through dws should carry the
「通过AI发送」badge by default, transparently flagging AI/CLI-sent messages.

- `--ai-tag` default flipped false → true on `chat message send` / `reply`, so
  no flag / `--ai-tag` / `--ai-tag=true` all attach clawType (open edition
  `openClaw`); only `--ai-tag=false` omits it (send as the user). The switch name
  is unchanged. reply honors the same default (no longer leaks the wukong
  clawType).
- skill chat.md: concise rule — default-on, pass `--ai-tag=false` to disable.
- tests: default now asserts clawType present; added an `--ai-tag=false` opt-out
  case.
2026-06-29 18:16:20 +08:00
修雨 2dbbca1ec9 docs(skill): align dws skill references with the real CLI
Every documented command / flag / example now matches `dws <svc> --help`:
- drop phantom commands (attendance class/group/vacation/..., contact label,
  ding message list/receiver-status) that map to undeployed tools.
- fix runtime-failure flags (mail --body→--content, doc/calendar/minutes
  pagination, chat send-by-bot @-flags, wiki member --users).
- route role/duty "who is responsible" queries to `aisearch person --dimension
  duty` instead of the removed `contact label`.
- realign the multi/dingtalk-report skill to entry submit / inbox list / outbox
  list.
2026-06-29 10:53:03 +08:00
修雨 4c5f1faeb1 feat: align open CLI with dws-wukong via cedar discovery version code (#509)
Switches the discovery version code bamboo -> cedar and aligns the open edition CLI with dws-wukong across communication (calendar book/acl/attendee, minutes tag, mail folder/template/contact, chat file upload, todo add-attachment, attendance transforms) and structured-office (aitable advperm/view/section/workflow/record, sheet/drive/wiki/doc) domains. Includes output-envelope parity, parse_bool/attendance_class_check_time transforms, --calendar-id support, CHANGELOG 1.0.43 and README command-index refresh. cedar config validated on pre and prod endpoints.
2026-06-26 21:49:38 +08:00
Ariand修雨 f7e8106a72 docs(devapp): add image-upload recipe + "discovering commands" to dingtalk-dev skill (#508)
* docs(devapp): add image-upload recipe + "discovering commands" to dingtalk-dev skill

The dingtalk-dev skill could set an app/robot icon via --icon-media-id but
never documented where a mediaId comes from: the dev command set has no
upload command, so a mediaId must be fetched from DingTalk's OpenAPI. Agents
had to guess the flow. The per-resource refs also lacked a uniform pointer to
self-discover commands and params, so they leaned on memory instead of --help
/ schema.

recipes.md: new "上传图片拿 mediaId" recipe — credentials get -> gettoken ->
OpenAPI /media/upload (multipart field `media`, type=image) -> robot config /
app update --icon-media-id -> read back. Includes a curl example and notes the
token TTL (~7200s, rate-limited) and a square-icon hint.

references/*.md: append a Chinese "发现命令" block to each of the 10 product
refs (app, credentials, webapp, permission, member, security, robot, version,
event, connect). Each block shows that group's own `--help` plus
`dws schema dev.app.<group>.<method>` (connect uses `dws schema dev.connect`),
mirroring SKILL.md's MUST DO.

Verified end-to-end on a real app (unifiedAppId via dws dev): uploaded a PNG
through /media/upload, set the robot icon with the returned mediaId, and
`robot get` reflected the new iconMediaId with robotStatus=ONLINE. All 10
`--help` targets and the 9 `dws schema dev.app.*` paths + `dws schema
dev.connect` resolve.

* docs(changelog): note dingtalk-dev mediaId recipe + command discovery (#508)

---------

Co-authored-by: 修雨 <47820304+PeterGuy326@users.noreply.github.com>
2026-06-25 23:46:48 +08:00
修雨 fbfcd69c2b feat(connect): make /new vs /clear use each channel's real session op
Before, /new and /clear were identical: both just dropped the local
conversationId->sessionId mapping. The agent-side session was never
disposed (opencode sessions leaked), and the two commands had no real
difference beyond their ack text.

Align them to each channel's real capability:
- /new (resetSession): drop the local mapping only; the old agent session
  is left intact and stays resumable where the agent supports it.
- /clear (new sessionClearer): actively dispose the current session via the
  agent's real delete primitive. opencode implements it with
  DELETE /session/:id (idempotent on 404). Channels whose agent exposes no
  delete in the mode DWS drives it (Codex app-server, Qoder stream, Claude
  exec) fall back to resetSession, so /clear behaves like /new there.

Tests pin both directions: /clear issues exactly one DELETE and drops the
mapping; /new (resetSession) issues zero DELETEs so the old session stays
resumable. Doc updated to describe the per-channel behavior.

go build ./... ok; go vet ok; go test ./internal/helpers ok.
2026-06-25 10:43:21 +08:00
xianfeng wang 5e254b4745 Merge pull request #17 from wxianfeng/sync/upstream-main-2026-06-24
sync: merge upstream/main into feat/dws-devapp (1.0.35–1.0.40)
2026-06-24 22:19:42 +08:00
quanming c993086d9d feat(connect): keep qoder sessions on stream-json 2026-06-24 20:36:26 +08:00
修雨 f522a9c2c2 Merge upstream/main into feat/dws-devapp
Sync with DingTalk-Real-AI/main (1.0.35–1.0.40):
- 1.0.35–1.0.39: chat @-mentions, sheet export, doc strip unsafe chars,
  PAT batch grants, devdoc RAG, agent_code detection, AI-tag opt-in
- 1.0.40 (#486): China mirror via Gitee + npmmirror
- (#488) embed skills/ into binary
- (#464) strip duplicate H1 on JSONML doc-create

# Conflicts:
#	.github/workflows/release.yml
#	CHANGELOG.md
#	README.md
#	README_zh.md
#	docs/command-index.md
#	internal/app/runner.go
#	internal/app/runner_test.go
#	internal/auth/channel.go
#	internal/helpers/devdoc.go
#	internal/helpers/devdoc_test.go
#	internal/pat/chmod.go
#	internal/pat/chmod_test.go
#	internal/pat/pat.go
#	internal/transport/client.go
#	scripts/install-skills.sh
#	scripts/install.ps1
#	scripts/install.sh
#	skills/mono/references/products/devdoc.md
#	skills/mono/references/products/simple.md
#	skills/multi/dingtalk-devdoc/references/devdoc.md
#	skills/multi/dingtalk-skill/references/skill.md
#	test/cli_compat/devdoc_test.go
#	test/cli_compat/helpers_test.go
#	test/skill_tests.md
#	test/skill_tests_results.md
#	test/unit/pat_host_owned_signal_test.go
2026-06-24 20:15:53 +08:00
wxianfeng d89649f9bb event search first 2026-06-24 17:53:08 +08:00
Aemeathandquanming f218a05ead [codex] use opencode server sessions for OpenCode connect
Co-authored-by: quanming <quanming@code.alibaba-inc.com>
2026-06-24 17:18:58 +08:00
quanming fc5e4d0d8d fix(connect): align codex and qoder sessions 2026-06-24 15:09:50 +08:00
qinzeandClaude Opus 4.8 91e67e2e45 docs(dev): event.md 事件码改用 event list 查询
去掉"以开放平台文档为准/dev doc search",改成"可订阅事件码通过 event list 查询
(返回 events[] 列出 eventCode/eventName/subscribed)"——event list 本就列出所有可订阅事件,更准。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 09:58:40 +08:00
wxianfeng 029bfdd2ed version publish approval 2026-06-23 19:44:36 +08:00
修雨 aecc0bc588 Merge pull request #11 from PeterGuy326/fix/mono-skill-dev-routing
fix(skill/mono): add dev product routing, prevent robot-creation mis-routing to chat
2026-06-23 14:06:18 +08:00
wxianfeng cfad3bbf4a name 2026-06-23 13:57:21 +08:00
修雨 40736e2ae1 fix(skill/mono): add dev product routing to prevent robot-creation mis-routing to chat
Without a dev entry in the product table and intent tree, agents reading the
mono skill routed 'create robot' / 'connect' requests to dws chat (because
'机器人' appeared in the chat product description), then landed on
dws chat bot search — wrong path.

Changes:
- skills/mono/SKILL.md: add dev row to product table; annotate chat row to
  scope it to IM-only; add dev intent-tree rule covering 创建机器人/建联/
  接入 agent/opencode/…; prepend dev-vs-chat disambiguation rule
- skills/mono/references/products/dev.md: new file — full command reference
  for dws dev app (lifecycle/robot build-号/credentials/permission/event/
  version) and dws dev connect (建联 flags, channel list, dry-run cli check,
  codex gotcha), sourced from dingtalk-dev multi-skill references
2026-06-23 13:53:53 +08:00
修雨 5ed69744cc Merge wxianfeng/feat/dws-devapp into release/dws-devapp
解决 devapp→dev 重构与 connect/数字分身工作的合并冲突,方向:全面对齐
wxianfeng 的 dev 命名空间,保留我方两处实质内容(动态端点 + connect 功能)。

冲突解决要点:
- release.yml:取 wxianfeng 更干净的 npm 守卫(repository_owner + 注释);
  保留我新增的「-dws-devapp 翻成非 prerelease+latest」步骤
- devapp.go / devapp_test.go / 路由文档:取 wxianfeng(新 MCP 工具名
  *_dev_app_*/extension、新增 event 工具、删 robot create、config 合 upsert)
- 端点:保留我方动态 devappMCPEndpoint()(网关 base 推导、生产默认),
  否则会把「建号对所有人打预发」的 bug 倒灌回来;同步修 helper_tool_fetcher.go
  与 direct_runtime_test.go 改用该函数 + wxianfeng 工具名 list_dev_app
- devapp_connect.go:connect 命令对齐 dev connect 命名,保留我方 --agent-cmd
  自研渠道示例(#37),建号引用修正为真实存在的 robot submit
- skills:跟随 wxianfeng 删除旧 dingtalk-devapp(已被重写的 dingtalk-dev 覆盖)
- robot-quickstart.md:命令全改 dws dev(建号两步 submit+result、dev connect),
  下载源改 wxianfeng,去掉写死版本号用 releases/latest

验证:go build ./... 通过;go vet 干净;internal/app、internal/helpers 单测全过
2026-06-23 10:21:29 +08:00
qinze 7cb33e970c Merge branch 'feat/dws-devapp' of https://github.com/wxianfeng/dingtalk-workspace-cli into feat/dws-devapp
# Conflicts:
#	skills/multi/dingtalk-dev/references/event.md
2026-06-23 09:19:27 +08:00
qinzeandClaude Opus 4.8 567cf163f1 docs(dev): event.md 澄清 connect/event 在 Stream 上的差异 + Stream 建立指向官方文档
- 加「connect 与事件订阅的关系」: connect 收机器人消息、event 只是配置订阅,
  dws 当前不消费事件; 两者唯一关联是先 connect 让长连在线 subscribe 才成功
- 「Stream 长连怎么建」改为命令视角 + 指向官方 SDK 文档(事件 RegisterAllEventHandler
  vs 机器人 RegisterChatBotCallbackRouter 别混), 不固化易过时的 SDK 代码

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 09:18:37 +08:00
wxianfeng d9ae15f9a6 Merge branch 'feat/dws-devapp' of github.com:wxianfeng/dingtalk-workspace-cli into feat/dws-devapp 2026-06-22 20:46:12 +08:00
wxianfeng 922745f318 event search 2026-06-22 20:45:14 +08:00
qinzeandClaude Opus 4.8 5d5884a0d7 fix(dev): 校准 dingtalk-dev skill 与真机一致 + 清理重复安装脚本
- skill 订正(以真机/schema 为准): app appStatus 字符串/permission 状态字段与
  apiPreview/credentials 去掉不存在的 showSecret/webapp 结构化空态/connect 去过时
  警告并补 flag/robot 去掉错误的 success 字段; version 用远端结构化审批字段
- 删除重复的 install-dev.sh, 保留 install-devapp.sh 并去掉会误拦用户的 go/make 检查

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:07:14 +08:00
quanming f69d9ed281 fix: align devapp member user ids 2026-06-18 19:37:17 +08:00
wxianfeng f2b2de89f4 fix cr problem 2026-06-18 18:34:12 +08:00
qinze 518b1cb631 Merge remote-tracking branch 'origin/feat/dws-devapp' into feat/dws-devapp
# Conflicts:
#	skills/multi/dingtalk-dev/references/version.md
2026-06-18 10:48:58 +08:00
玉澜 f29655e7e4 fix(devapp): let server assign app version 2026-06-18 10:32:52 +08:00
qinzeandClaude Opus 4.8 cc8a726b0a docs(dev): dingtalk-dev references 二次精简
- permission/robot/version 删 bash 命令示例堆叠(schema/--help 已覆盖),
  保留状态机/枚举语义/链路/gotcha
- 去掉所有 reference 的"概念锚点"自造词标签,保留指向概念地图的引语
- SKILL.md 生效模型去"(最重要)";connect 去加粗

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 09:09:04 +08:00
qinzeandClaude Opus 4.8 70d66daa5f feat(dev): schema 覆盖 dev doc + dingtalk-dev skill 精简
- dws schema 支持 dev.doc.search:fetcher 按 source 取(op-app 钉死 pre/
  devdoc 走运行时解析),给 doc search 叶子加 mcp-tool/mcp-source 注解
- dev doc search flag 对齐 MCP 参数名(--keyword/--size 为主,旧名隐藏兼容)
- dingtalk-dev SKILL.md:顶部加 MUST DO(每次先 --help/schema 查),核心规则
  瘦身、去重、去加粗/箭头符号
- references 精简:删参数表/flag 列表(schema/--help 已实时提供),只留状态机/
  覆盖语义/链路/gotcha;event 补"订阅前需先建联"业务规则;新增 recipes.md
  端到端链路;典型任务收成指针

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 21:56:11 +08:00
qinzeandClaude Opus 4.8 51db546686 Merge origin/feat/dws-devapp into feat/dws-dev
合并远端团队的 MCP 对齐与 CR 修复,与本地 dev 命令重构 + schema 实时拉取 + flag 对齐 MCP 参数名集成。

冲突解决要点:
- 工具名常量:两边已收敛到同一组 op-app 真实工具名,取 dev 子树(ours)标识
- 保留 schema 能力:32 个 annotateDevAppTool 注解 + flag=kebab(MCP参数名)不变
- 吸收远端 CR 修复:normalizeDevAppServiceResult 解包 ServiceResult、
  remove_dev_app_permissions 结果扁平化、生命周期工具状态标记
- 旧 dingtalk-devapp 技能目录保持删除(已重命名为 dingtalk-dev)
- devdoc article search 统一 --page-size/pageSize,--size 留兼容别名

构建/vet/internal 测试全绿(28 包,0 失败)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 17:01:50 +08:00
qinzeandClaude Opus 4.8 6244222adf feat(dev): schema 实时拉取 MCP + flag 全面对齐 MCP 参数名
- 新增 dws schema dev.* 实时从 op-app tools/list 拉取参数(gws 扁平格式),
  description/type/required/default 全部 verbatim 来自服务端,零本地合成
- flag 全部改为 kebab(MCP 参数名),去掉别名,schema 展示与 CLI flag 完全一致,
  修掉 schema 显示假参数名的问题
- CLI 同步新 MCP 契约(工具名复数化、参数名 rename)
- dingtalk-dev skill 文档同步新 flag 名

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 16:43:19 +08:00
wxianfeng 8984f7b8be fix cr problem 2026-06-17 12:13:28 +08:00
wxianfeng dd08db54d8 Merge branch 'feat/dws-devapp' of github.com:wxianfeng/dingtalk-workspace-cli into feat/dws-devapp 2026-06-17 10:03:55 +08:00
wxianfeng 591609fdee fix cr problem 2026-06-17 10:03:04 +08:00
quanming 6447bdd45f fix: align devapp member security app id flag 2026-06-17 09:53:31 +08:00
玉澜 2610c8ce87 Merge branch 'feat/dws-devapp' of https://github.com/wxianfeng/dingtalk-workspace-cli into feat/dws-devapp 2026-06-17 03:32:19 +08:00
玉澜 0e6cb46f58 fix: align devapp mcp compatibility 2026-06-17 03:29:46 +08:00
wxianfeng 410949cdf3 fix cr problem 2026-06-16 21:02:38 +08:00
玉澜 0197dbc81a fix: align devapp DTO field names 2026-06-16 19:18:27 +08:00
qinzeandClaude Opus 4.8 166f665708 chore(dev): devapp→dev 重命名收尾(docs/mono/install/README/gitignore)
删除旧 devapp docs;mono 技能与 intent-guide 去 devapp;install 脚本改名
install-dev.sh;README 更新;.gitignore 放行 skill credentials.md 文档。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:11:50 +08:00
qinzeandClaude Opus 4.8 55f5e0c3d0 chore(dev): 删除旧 skills/multi/dingtalk-devapp
multi 模式旧 devapp 技能整组下线,已被 dingtalk-dev 替代。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:11:32 +08:00
qinzeandClaude Opus 4.8 f58b426381 chore(dev): 删除旧 skills/dingtalk-devapp(root 模式)
devapp 旧技能整组下线,已被 multi/dingtalk-dev 替代。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:11:32 +08:00
qinzeandClaude Opus 4.8 2640338803 docs(dev): dingtalk-dev skill reference (2/2) + dev 功能测试
webapp 产品文档;dev 命令集功能测试用例与报告(测试产物 results.jsonl 不入库)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:11:21 +08:00
qinzeandClaude Opus 4.8 dbcbb1de85 docs(dev): dingtalk-dev skill 概念结构 + 产品 reference (1/2)
SKILL.md 重构为「概念地图 + 核心规则/通用出参约定 + 典型任务 + 产品索引」;
reference 改为一命令组一文件;不在 agent 文档暴露内部 MCP tool 名。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 17:11:09 +08:00
wxianfeng c2f3653ec4 get_extension_robot_config 2026-06-16 14:40:17 +08:00
wxianfeng ef60d99b26 get_robot_config 2026-06-16 12:12:19 +08:00
wxianfeng 1b6e197426 fix conflict 2026-06-16 11:04:12 +08:00
wxianfeng caf672699f tool name rename 2026-06-16 11:01:33 +08:00
玉澜 67ac777657 Merge remote-tracking branch 'origin/feat/dws-devapp' into feat/dws-devapp 2026-06-16 10:13:57 +08:00