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.
The Gitee mirror force-pushes main verbatim, so Chinese users saw a
README whose top install commands point at raw.githubusercontent.com
(hard to reach in China) and a coverage badge that fails to render
(the relative .github/badges/coverage.svg can't be served by Gitee —
gitee raw returns a signed, expiring URL with content-type text/plain).
Add a Gitee-only post-process step: build a gitee-main branch on top of
origin/main and rewrite README.md / README_zh.md before pushing —
(1) raw.githubusercontent.com/<repo>/main -> gitee.com/<repo>/raw/main
(2) the coverage badge -> a shields.io static badge whose percentage is
read from the repo's coverage.svg and colored by threshold.
GitHub's README is untouched; only the Gitee copy is rewritten. The
branch is rebuilt from origin/main every run, so it stays a clean
single-commit delta and never drifts.
Resolve-LatestVersion referenced $LatestUrl (lines 185/197) but the
variable was never defined, so on the default GitHub path both
Invoke-WebRequest calls failed with a null Uri. With
$ErrorActionPreference = "Stop" the script then hit Write-Err and
exit 1 — closing freshly-launched PowerShell windows instantly
(the reported "闪退"). Every user on the default `latest` path was
affected; the Bash installer was unaffected because it inlines the URL.
Define $LatestUrl = "https://github.com/$Repo/releases/latest", mirroring
the Bash installer. Verified end-to-end with pwsh 7.5: the script now
resolves the latest tag, downloads, checksum-verifies and installs.
* 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>
Two leftovers referenced the decommissioned wxianfeng fork branch
`feat/dws-devapp`, both now obsolete after the dev-app work landed on main
(v1.0.42) and the installers were repointed to DingTalk-Real-AI (#505):
- .github/workflows/auto-dev-release.yml — triggered only on push to
feat/dws-devapp (a branch that does not exist on this repo, so it never
fires). Its purpose — auto-publishing fork dev-preview releases for
install-devapp.sh — is gone now that install-devapp.sh pulls stable
releases from DingTalk-Real-AI.
- docs/devapp-yulan-command-routing.md — a 2026-06-05 draft design doc
pinned to the fork branch and the pre-rename `devapp` command tree,
superseded by the shipped `dws dev` command set and the rewritten
docs/devapp-agent-install-guide.md.
After this, the repo has zero `wxianfeng` / `feat/dws-devapp` references.
* fix(devapp): point dev installer at DingTalk-Real-AI, drop the fork
install-devapp.sh / .ps1 and the robot quickstart still pulled the dev
binary + dingtalk-dev skill from wxianfeng/dingtalk-workspace-cli's
feat/dws-devapp fork branch. The dev-app work has since landed on main and
shipped in stable v1.0.42 under DingTalk-Real-AI, so the fork dependency is
obsolete.
- DEVAPP_REPO default: wxianfeng/... → DingTalk-Real-AI/...
- Bootstrap URLs in headers + quickstart: fork feat/dws-devapp → main.
- Drop "preview/prerelease" wording — releases are now stable; the
newest-release resolution still works either way.
- Quickstart China note now points at the standard install.sh Gitee
mirror (which carries dws dev in v1.0.42); install-devapp.sh pulls its
binary from github.com, so a gitee-raw script alone would not help China.
Verified: releases?per_page=1 on DingTalk-Real-AI resolves v1.0.42 and the
darwin/skills assets are present.
Note: docs/devapp-agent-install-guide.md is separately stale (describes the
old source-build flow + the pre-rename `dws devapp` command) and needs its
own rewrite — left out of this change.
* docs(devapp): rewrite agent install guide for binary install + `dws dev`
The guide was stale on two axes:
- It described the old source-build flow (clone the fork branch + go/make,
env vars DEVAPP_REPO_URL / DEVAPP_BRANCH / DEVAPP_SOURCE_DIR), but
install-devapp.sh now downloads a pre-built binary (curl + tar, no
git/go/make) from DingTalk-Real-AI.
- Every command used the pre-rename `dws devapp ...`; the command is now
`dws dev app ...`.
Rewrite against the real `dws dev` tree (verified from the binary):
- install: DingTalk-Real-AI binary installer + correct env (DEVAPP_REPO /
DEVAPP_VERSION / DWS_INSTALL_DIR / DWS_NO_SKILLS) + a China Gitee note.
- skill name corrected to `dingtalk-dev`.
- commands: `dws dev app {list,get,create,update,enable,disable,delete,
credentials,permission,member,robot,security,version,webapp,event}` with
real flags (--confirm-name, --scope-values, --user-ids, --redirect-urls,
--version-id/--confirmed-sensitive), async robot create via submit/result,
version publish gated by check-approval.
The China-mirror section documented the main install.sh and the npm
package, but not the standalone install-skills.sh — even though that
script already honours DWS_GITEE_REPO and auto-falls back to Gitee when
GitHub is unreachable. The Skills install section only showed the GitHub
URL, so China users (and docs curated from this README) had no China
entry point for skills.
Add a "Skills only (Gitee mirror)" item to both China-mirror sections and
a pointer next to the Skills install command, in README.md and README_zh.md.
The verify-replace mirror listed attachments via /releases/{id}, whose
"assets" array omits the attach id. DELETE /attach_files/{id} was therefore
called with an empty id and silently no-op'd, so a stale asset was never
removed — instead a second (correct) copy was uploaded. Gitee then serves the
OLDER attachment by name, so the stale darwin binaries kept winning and failed
install.sh's checksums.txt verification on macOS (国内 install broken).
Fix:
- List attachments via the dedicated /attach_files endpoint, which DOES
return the numeric id needed for deletion.
- Treat duplicates: collect every attach id carrying a given name; when >1,
delete them all and upload exactly one fresh, correct file. count==1 still
does the byte-identical skip / stale-replace; count==0 uploads new.
Self-heals the existing v1.0.42 darwin duplicates on the next mirror run.
The v1.0.42 Gitee release served darwin-amd64/arm64 binaries that did NOT
match checksums.txt (the macOS binaries are ad-hoc signed and differed
between the GitHub release and the earlier mirror run), so install.sh's
checksum verification failed for China macOS users. The previous skip-if-name-
present logic could not repair this — it skipped the stale assets.
sync-to-gitee.sh now verifies by content: for each artifact it compares the
sha256 of the asset already on Gitee against the local file (downloaded from
the GitHub release), and
• skips it when byte-identical,
• deletes + re-uploads it when present but stale,
• uploads it when missing,
bringing the Gitee release into byte-for-byte agreement with the GitHub
release that checksums.txt describes. Re-running the Sync-release-to-gitee
workflow now self-heals a mismatched mirror.
bash -n + sha256 helper validated locally.
The v1.0.42 Release job hit timeout-minutes: 30 mid-upload while mirroring
release assets to Gitee, so the Gitee release ended up missing
dws-windows-arm64.zip and checksums.txt. Root cause + fixes:
- sync-to-gitee.sh now skips assets already attached to the Gitee release,
so a re-run only uploads what is missing (instead of re-uploading every
artifact and creating duplicates). It no longer fails when everything is
already present.
- New workflow sync-release-to-gitee.yml (workflow_dispatch, version input)
mirrors a published GitHub release's assets to Gitee on its own — it
downloads the assets from the GitHub release and runs the idempotent sync,
without running GoReleaser or touching the GitHub release (no outage). Use
it to repair an incomplete Gitee mirror.
- Bump the Release job timeout 30 -> 60 so a full Gitee upload has room.
bash -n + YAML validated.
Promote the [Unreleased] section to 1.0.42 (2026-06-25) ahead of封包:
robot connect custom channel, /new vs /clear session commands, and the
opencode 30s timeout fix. A fresh empty [Unreleased] stays on top.
README.md / README_zh.md had no connect coverage at all. Add a short
"connect a robot to your local AI" section above Key Services: the one-line
`dws dev connect` usage, the in-chat /new vs /clear session commands (with
the per-channel real-session-op behaviour, opencode DELETE /session), and a
pointer to docs/robot-quickstart.md. Docs only.
Document this release's two connect changes that landed via #19 and #20:
- CHANGELOG [Unreleased]: Added entry for /new vs /clear using each
channel's real session op (opencode DELETE /session); Fixed entry for
the opencode 30s client-timeout that aborted long agent turns.
- robot-quickstart.md: a 会话指令 section explaining /new (open fresh,
keep old) vs /clear (real per-channel wipe; opencode deletes the
server session).
Docs only; no code change.
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.
The fork's dev branch had the pre-release URL (pre-mcp.dingtalk.com)
hardcoded as the default MCP base, which would leak prepub config into
any release build. Revert to the upstream production default.
🤖 Generated with [Qoder][https://qoder.com]
Rewrite mirror-to-gitee.yml to push main + tags to the Gitee mirror using
HTTPS + GITEE_TOKEN (reusing the existing secret) instead of hub-mirror-action
+ an SSH key. Gated on GITEE_TOKEN; needs GITEE_USER + GITEE_REPO secrets.
Keeps Gitee code/raw in sync automatically on every push to main + tags, so
no more manual git push after each release.
Probe GitHub Releases on startup; if it is unreachable (typical in mainland
China), automatically switch to the Gitee mirror — so a plain
`curl … | sh` (or .ps1 / install-skills.sh) works everywhere with no
DWS_GITEE_REPO env var. Explicit DWS_GITEE_REPO still wins; DWS_NO_FALLBACK=1
disables the probe; local source-checkout installs skip it.
The shared opencode http.Client had a hardcoded 30s Timeout used for every
request including POST /session/{id}/message. Long agent turns (e.g. a web
research report) take longer than 30s, so the client aborted mid-flight with
"context deadline exceeded (Client.Timeout exceeded while awaiting headers)",
even though the per-turn budget (DWS_AGENT_TIMEOUT_MS, default 300s) was far
larger. Retrying hit the same wall.
Drop the client-level deadline (rely on the per-request ctx that doJSON already
wires via http.NewRequestWithContext) and bound only the /global/health probe
with a short 10s timeout so startup detection stays snappy.
Tests: pin Timeout==0 on the default client, and assert a slow reply succeeds
within the turn budget but is cut when the turn ctx is shorter than the reply.
PR #448 stripped a leading H1 matching --name on the markdown path of
`dws doc create`, but the JSONML path (--content-format jsonml) was never
covered. Rich documents — tables, callouts, styled blocks — go through
create_document + update_document(jsonml=...), which writes the body
verbatim, so a leading h1 whose text equals the document name renders the
title twice (the "two headings" effect the doc platform shows because it
already renders --name as the page title).
Add stripLeadingDuplicateTitleJSONML: parse the marshaled JSONML body,
skip an optional ["root", {}, ...] wrapper, and drop the first node when
it is an h1 whose concatenated leaf text equals --name (trimmed,
case-insensitive). Any parse failure or non-match leaves the body
untouched, so a valid write is never blocked. A stderr note mirrors the
markdown path so agents learn the convention.
- CHANGELOG: 1.0.40 (China mirror via Gitee + npmmirror, #486)
- mirror-to-gitee.yml: gate on GITEE_PRIVATE_KEY so it skips cleanly when the
SSH key is unset (code mirror handled by Gitee-side pull-mirror) instead of
failing the run.
go:embed the skills/ tree (mono + multi) into the binary and make
`dws skill setup` install from the embedded bundle by default. Upgrading
the binary now refreshes the installed skill, instead of silently reusing
a stale copy probed from the current working directory. An explicit
--source / DWS_SKILL_SOURCE still overrides for development.
Replants the change from #441 onto main: #441 was stacked on the
abandoned feat/chat-bot-provisioning-openclaw base (PRs #407/#397 closed),
which is why its CI was red. The embedded-bundle test asserted a
connect.md doc that only existed on that dead base; retargeted it to a
reference doc that exists on main.
Add scripts/release/sync-to-oss.sh and wire it into release.yml. After
the GitHub release, artifacts (binaries, checksums, dws-skills.zip) plus
the install scripts are pushed to an OSS bucket in the
<base>/<version>/<file> layout the install.sh DWS_RELEASE_BASE switch
expects, with a latest.txt pointer.
Gated on OSS_* repo secrets: skips cleanly when unset, so forks without
the secrets keep releasing to GitHub only.
When `dev connect` runs with no credentials (no --robot-client-id/secret, no
--unified-app-id) in a real terminal, it now guides the user instead of failing:
- Ask "new app or existing app?".
- Existing: read a unified-app-id (reuses the credentials-get path) or an
explicit clientId/clientSecret pair.
- New: read the app name, robot display name and description, submit the async
robot-create task, then poll for the result to obtain credentials. This has a
real side effect (it provisions a real robot app).
connect_onboarding.go keeps the flow channel-agnostic and io-injected so the
whole decision tree is unit-tested with a mock runner and scripted stdin (no
network, no real provisioning). Non-interactive invocations — scripts, daemons,
pipes, and --dry-run — are unchanged: they still require an explicit credential
flag, so nothing that worked before starts prompting.
Tests cover: existing/unified, existing/raw-creds, new-app submit+poll (asserts
the submit_robot_create_task / query_robot_create_result calls and params),
invalid choice, and a missing required field (no side-effecting call).
Note: the real provisioning path shares the same unverified credential field
names as devAppFetchCredentials (clientId/appKey, clientSecret/appSecret — see
its TODO(verify)); the live create→credentials flow is to be verified on the
pre-prod gateway with the -dws-devapp prerelease before relying on it.