Commit Graph
44 Commits
Author SHA1 Message Date
修雨 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
shangguanxuan.sgx 493ca36e08 fix(pat): carry agentCode in batch auth args 2026-06-18 13:08:15 +08:00
patrickmen 497e4f87d8 feat: support to disable auto open browser (#365) 2026-06-16 20:08:29 +08:00
修雨 ece91bfa3c feat(agent): accurate agent_code detection + per-channel agentId for stats (#467)
Tag each MCP request with which agent host is driving dws (agent_code) and a
per-(machine × agent_code) instance id, so usage can be sliced by channel and
instance in the data warehouse. Root cause it fixes: agent_code was only sent
when the host injected DINGTALK_DWS_AGENTCODE (~99.98% empty), so the gateway
logged none.

Detection ladder (every signature observed on a real host / official docs, not
guessed; unknown -> custom):
  T0 explicit DINGTALK_DWS_AGENTCODE
  T1 verified env signatures: claudecode (CLAUDECODE), codex (CODEX_SANDBOX),
     openclaw (OPENCLAW_BUNDLE_ROOT), hermes (HERMES_HOME)
  T2 VSCODE_BRAND value (covers the whole VS Code fork family)
  T3 macOS __CFBundleIdentifier map (qoder/cursor/vscode/workbuddy)
  T4 custom fallback

identity.json v2 (machineId + per-agent_code agents map), deterministic
dwsa_<base62> derivation, transparent v1 migration. Backward-compatible wiring:
x-dws-agent-id stays machine-level; new x-dws-agent-instance-id carries the
per-channel id; X-Cli-Version emitted so old/new clients are distinguishable.

Trust boundary (docs/agent-code.md): agent_code and the ids are self-reported
and spoofable — fit for statistics ONLY, never for auth/limit/billing.

Includes unit tests for every tier and the integration doc.
2026-06-16 17:55:29 +08:00
xuanandshangguanxuan.sgx 2a82d07311 fix(pat): support batch agentCode and guarded grants (#455)
* fix(pat): carry agentCode in batch auth args

* fix(pat): let core default missing agent code

* fix(pat): require yes for batch grants

* test(pat): cover cli authorization matrix

* fix(pat): keep canonical agent code env only

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
2026-06-11 19:21:25 +08:00
56a5edecef feat(pat): support batch chmod authorization flows (#389)
* feat(pat): support batch chmod flows

* feat: use server default agentCode for chmod

* feat: surface tool auth metadata

* feat: infer product grant auth metadata

* chore: update coverage badge [skip ci]

* feat(pat): summarize chmod output by default

* chore: update coverage badge [skip ci]

* fix(pat): preserve batch session metadata

* fix(pat): align dry-run session and schema docs

* chore(config): use public example MCP override URL

* fix(pat): align chmod session env handling

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 20:54:55 +08:00
4e58e45d30 feat(auth): add export/import for portable sandbox credentials (#357)
* feat(auth): add export/import for portable sandbox credentials

Enable migrating encrypted keychain and config between Linux sandboxes so refresh tokens survive beyond the 2-hour access token window.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(auth): harden portable export/import per PR review

按 PR 审查意见加固可迁移认证包流程:macOS 默认 Keychain
场景拒绝导出;导入需 --force 覆盖已有登录态;解析 manifest
并在 OS 不匹配时告警;export 参数校验前置;flag 描述中文化;
移除已弃用的 tar.TypeRegA;导出文件后提示删除敏感包。

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(auth): require auth-token.enc before portable export

修复 staticcheck S1030(测试改用 exported.Bytes())。
导出前校验 auth-token.enc 存在,避免无登录态时生成
仅含 dek 的无效 bundle;CLI 提示先运行 dws auth login。

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: 洛丘 <wangketing.wkt@antgroup.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 09:19:11 +08:00
c6edc84e40 fix(auth): partition app.json filename by edition to isolate credentials (#300)
* fix(auth): partition app.json filename by edition to isolate credentials

Two dws binaries sharing the same config directory (typically ~/.dws or
DWS_CONFIG_DIR) previously read and wrote a single app.json. Editions
that pin AuthClientID via hooks still go through the open-core
post-login persistence path, which records a bare ClientID without a
paired ClientSecret. The sibling edition reading the same path would
then adopt that foreign clientID via ResolveAppCredentials.

Mirror the strategy already used by the cache loader
(pkg/config.EditionPartition): GetAppConfigPath returns a filename
suffixed with the active edition name. Open-source keeps "app.json" for
backwards compatibility; sibling editions land on "app-<edition>.json".
LoadAppConfig / SaveAppConfig / HasAppConfig / DeleteAppConfig all
route through GetAppConfigPath, so this single change physically
isolates credential files end-to-end without any read-time heuristics.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(auth): address app config partition review

* fix(auth): clean legacy sibling app config

* test(auth): cover legacy app config cleanup guards

* fix(auth): close app config review follow-ups

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 17:43:20 +08:00
ybc❤️zyrand猷诺 efb61cae02 fix: restore unconditional MCP re-fetch in login to prevent stale clientId errors (#213)
PR #184 merge conflict resolution inadvertently introduced a conditional
branch that preserved stale clientID from previous login sessions instead
of always re-fetching from MCP server. This caused exchangeCode() to use
direct DingTalk API mode (which requires clientSecret) instead of MCP
proxy mode, resulting in 'clientId或者clientSecret错误' errors.

This commit restores the original PR #157 logic: both DeviceFlowProvider
and OAuthProvider unconditionally call resetCredentialState() followed by
FetchClientIDFromMCP() + SetClientIDFromMCP(), ensuring exchangeCode()
always uses the MCP proxy path regardless of prior login state.

Root cause: the conditional branch treated any non-empty clientID (from
runtimeClientID or app.json) as a user-provided --client-id flag value,
skipping MCP re-fetch and leaving clientIDFromMCP=false after reset.

Affected scenarios:
- OAuth login → device flow login
- Any login → --force login
- New terminal with existing app.json → device flow login

Fixes regression introduced in PR #184 (commit 46192d6).
Restores fix from PR #157 (commit ad33a46).

Co-authored-by: 猷诺 <bicheng.ybc@alibaba-inc.com>
2026-05-04 09:26:25 +08:00
xuanandshangguanxuan.sgx da2522c8ca feat(pat)!: A-core loop for host-owned PAT (#142)
* feat(pat): A-core minimum viable loop for host-owned PAT

Enables third-party agents to integrate PAT via the smallest possible
contract surface. The flow a host needs to ship end-to-end:

  1. Export DINGTALK_DWS_AGENTCODE in the spawned shell.
  2. Run any `dws ...` business command.
  3. On PAT hit, CLI exits with code 4 and writes a single-line stderr
     JSON following docs/pat/contract.md §2.
  4. Host parses the JSON and invokes `dws pat chmod <scope>...
     --agentCode ... --grant-type ...` to grant.
  5. Host replays the original command.

This PR intentionally ships ONLY the chmod path plus the host-owned
switch; the async flow (apply / status / scopes + authRequestId
registry + PAT_SCOPE_AUTH_REQUIRED active-request branch) lands in a
follow-up stacked PR (A-ext).

Scope of A-core:
- Host-owned PAT trigger: auth.HostOwnsPATFlow() keyed exclusively on
  DINGTALK_DWS_AGENTCODE (DINGTALK_AGENT / DWS_CHANNEL / claw-type do
  NOT participate).
- claw-type: hard-wired to "openClaw" in pkg/edition/default.go
  MergeHeaders hook, matching historical main behavior and decoupled
  from DINGTALK_AGENT.
- dws pat chmod: factory-built (newChmodCommand) so the PAT subcommand
  tree has no shared package-level caller.
- stderr JSON classifier: internal/errors/pat.go covers PAT_NO_PERMISSION
  / PAT_LOW_RISK / PAT_MEDIUM_RISK / PAT_HIGH_RISK / PAT_SCOPE_*
  selectors and fills data.hostControl for host consumption.
- Env contract: DINGTALK_SESSION_ID / DINGTALK_TRACE_ID /
  DINGTALK_MESSAGE_ID carry HTTP trace headers (Chain B);
  DWS_SESSION_ID (+ REWIND_SESSION_ID alias) is the lone fallback for
  `dws pat chmod --session-id` (Chain A). The two chains are
  independent; aliases do not cross-pollinate.
- Docs: docs/pat/{README,contract,host-integration}.md + refreshed
  docs/architecture.md "PAT Architecture" chapter + docs/reference.md
  PAT section. error-catalog.md folded into contract.md §6.
- Tests: host-owned signal, stderr contract, classifier, chmod factory,
  retry / poll loop for the CLI-owned chmod path.

Compatibility: no breaking changes on main. All non-PAT commands are
untouched.

Follow-up PRs (in order):
- codex/pat-ext  : dws pat apply / status / scopes + AsyncRegistry.
- codex/pat-oss-refactor (aka PR B) : oauth_helpers / secure_store
  refactors split out per code review.

Made-with: Cursor

* fix(pat): unify host-owned stderr contract

* revert: drop PAT docs and changelog from pat core PR

* fix(pat): pin behavior auth endpoint

* fix(pat): recognize legacy tool miss

* fix(pat): fallback on gateway diagnostics

* fix(pat): treat authorization uri as opaque

* fix(pat): accept result envelope in device-flow polling

* feat(pat): add browser policy and poll compatibility

* fix(pat): keep CLI and host PAT contracts separate

* test(pat): isolate opaque uri retry env

* fix(pat): harden PAT result routing

* fix(pat): harden host-owned flow and runtime fallback

* fix(pat): preserve chmod failure on empty grant result

* refactor(pat): drop dead doc anchors, dedupe stderr injection helpers

Address two reviewer findings on top of the PAT-core series.

Fix:
- chmod: resolveSessionIDFromEnv silently selects DWS_SESSION_ID; drop
  the slog.Warn that emitted both raw session ids into stderr /
  ~/.dws/logs.
- Remove every docs/pat/contract.md / error-catalog.md /
  host-integration.md anchor from comments, help, and tests; those
  files were never added by this branch. Comments are now self-contained
  or point to docs/reference.md where applicable.

Refactor:
- internal/errors/pat.go: extract lookupCodeIn so getPATErrorCode and
  getDWSGatewayErrorCode share one traversal; have ClassifyPatAuthCheck
  delegate to getPATErrorCode instead of repeating the enum walk.
- internal/errors/pat.go + internal/app/pat_auth_retry.go: extract
  ApplyHostMutations as the single injection point for data.hostControl
  + data.openBrowser; cleanPATJSON and enrichPATErrorForHostControl now
  share it so the two stderr-JSON write paths cannot drift.
- internal/app/pat_auth_retry.go: drop buildPATScopeHostJSON and
  buildHostControlState dead 1-line wrappers.
- internal/pat/chmod.go: drop unused patApply/Status/Scopes constants;
  derive legacyToolArgs from toolArgs by clone + scopes->scope rename so
  the two payloads stay in lock-step on every other field.

Net 15 files, +176 / -193. Verification:

  env -u DINGTALK_DWS_AGENTCODE go test \
    ./internal/errors ./internal/auth ./internal/pat ./test/unit
  env -u DINGTALK_DWS_AGENTCODE go test ./internal/app \
    -run 'Test(IsPat|ExtractPat|PrintPat|PollPat|HandlePat|RetryWithPat|EnrichPAT|BuildPAT|DirectRuntime|ResolveIdentityHeaders)'
  env -u DINGTALK_DWS_AGENTCODE go test -race \
    ./internal/pat ./internal/errors ./test/unit
  env -u DINGTALK_DWS_AGENTCODE go test -race ./internal/app \
    -run 'Test(HandlePat|RetryWithPat|EnrichPAT|BuildPAT|ResolveIdentityHeaders|DirectRuntime)'
  go vet ./... && go build ./...

All green.

Made-with: Cursor

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
2026-04-28 21:17:23 +08:00
fantiu 41396426d0 Merge pull request #184 from fantiu/feat-rawapi
feat(api): add raw DingTalk OpenAPI command with dual-version token support
2026-04-27 21:14:15 +08:00
fantiu 6946929e0b feat(api): add raw DingTalk OpenAPI command with dual-version token support 2026-04-27 20:54:57 +08:00
xuanandshangguanxuan.sgx 6756ead38a fix: preserve PAT authorization uri and accept result poll envelope (#182)
* fix(pat): treat authorization uri as opaque

* fix(pat): accept result envelope in device-flow polling

* docs(pat): clarify empty-uri guard intent

* fix(pat): guard poll debug output and lock envelope priority

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
2026-04-27 20:04:01 +08:00
fantiu e06b1d68ff feat: raw API update README. 2026-04-27 17:08:32 +08:00
fantiu 592749c986 feat: The token retrieval interface is now unified to one. 2026-04-27 15:11:12 +08:00
fantiu 46192d68ba feat(api):client logic fixed. 2026-04-24 17:04:09 +08:00
fantiu eeb1782f7a feat(api): add raw DingTalk OpenAPI command with dual-version token support 2026-04-24 16:40:13 +08:00
ybc❤️zyrand猷诺 ad33a46883 fix: device flow defensively resets credentials before login (#155) (#157)
Device flow now always clears stale credential state and re-fetches
clientID from MCP server, regardless of what previous login methods
(OAuth scan, PAT, etc.) left in app.json or runtime globals.

This replaces the previous Source-field approach with a simpler
defensive reset that is future-proof against new login methods.

Root cause: after OAuth login saved app.json without MCP source marker,
subsequent --device login reused the stale clientID without setting
clientIDFromMCP flag, causing exchangeCode() to use direct mode which
requires clientSecret.

Changes:
- Add resetCredentialState() to DeviceFlowProvider
- Login() always calls resetCredentialState() + FetchClientIDFromMCP()
- Remove AppConfig.Source field (no longer needed)
- Remove app_config_source_test.go (replaced by device_flow_reset_test.go)
- Add 5 tests covering OAuth→device, legacy→device, direct→device scenarios

Co-authored-by: 猷诺 <bicheng.ybc@alibaba-inc.com>
2026-04-24 14:11:16 +08:00
xianfeng wang bbca507792 feat(discovery): MCP discovery service abstraction with positional params, examples, defaults, and schema v3 extensions (#156)
* discovery

* discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* wk discovery

* discovery example and default

* position param

* Fix test

* dev auto login

* fix test

* fix conflict
2026-04-24 14:08:17 +08:00
xuan 89c5038446 fix(auth): restore device_code polling when flowId is absent (#145)
* fix(auth): fallback to device_code when flowId is missing

* chore(auth): remove dead helper and harden fallback tests
2026-04-22 15:13:40 +08:00
fantiuandgithub-actions[bot] e0544579d2 fix(auth): attribute CLI auth denial to channel before user scope (#144)
* chore: update coverage badge [skip ci]

* chore: update coverage badge [skip ci]

* fix(auth): attribute CLI auth denial to channel before user scope

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-22 12:05:30 +08:00
shangguanxuan633-labandshangguanxuan.sgx 725577103d feat: PAT scope error visualization and auto-retry with authorization polling (#113)
* feat: PAT scope error visualization and auto-retry with authorization polling

1. PAT error result visualization (non-JSON)
   - Human-readable error output matching lark-cli style
   - Shows error type, message, hint, and authorization command
   - JSON output also available via --format json

2. Auto-retry with polling after authorization wall
   - Detects missing_scope / insufficient_scope / permission errors
   - Polls every 5s for token update after user completes auth
   - 10 minute timeout before giving up
   - Automatically retries the original command after successful auth

Changes:
- internal/app/pat_auth_retry.go: Core PAT error handling and retry logic
- internal/app/pat_auth_retry_test.go: 11 unit tests
- internal/app/runner.go: Integration with executeInvocation error path
- internal/auth/device_flow.go: Add SetScope() method

* feat: migrate PAT (Permission Authorization) infrastructure to open-source core

Move PAT permission management code from dws-wukong overlay to the
open-source dingtalk-workspace-cli core. This enables PAT handling
in the public distribution while keeping dws-wukong fully compatible
through the edition.Hooks mechanism.

Changes:
- pkg/edition: add 6 new Hooks fields (AuthClientID, AuthClientFromMCP,
  SaveToken, LoadToken, DeleteToken, ClassifyToolResult) for overlay
  extensions to inject custom auth/token/error behaviour
- internal/errors/pat: new PATError type with ExitCode()=4 and
  RawStderr() for embedded-mode passthrough, plus ClassifyToolResultContent
  and ClassifyMCPResponseText classification functions
- internal/pat: new command group (pat chmod) with tool result handling
- internal/app/root: register PAT commands before RegisterExtraCommands hook
- internal/app/runner: integrate ClassifyToolResult hook in the
  callResult.IsError branch so overlays can intercept PAT/gateway errors
  before generic handling

The dws-wukong overlay remains unchanged — its existing pat/ package and
RegisterExtraCommands hook continue to work. Through the go.mod replace
directive and deduplicateCommands mechanism, both codebases coexist
without conflict.

* feat(pat): add PAT auth check with device flow polling and auto-retry

- Add ClassifyPatAuthCheck / AsPatAuthCheckError in pat.go for
  AGENT_CODE_NOT_EXISTS error detection
- Add handlePatAuthCheck in pat_auth_retry.go: inject clientId as
  x-robot-uid header, poll device flow endpoint, auto-retry on APPROVED
- Integrate PAT check into runner.go executeInvocation pipeline
  (edition hook + open-source fallback)
- Add patAuthRequiredCodes map for extensible auth-required code matching
- Remove test_parse.go (temporary test script)

* fix(pat): update poll path to /cli/oauth/device/poll and add x-user-access-token header

- Change DevicePollPath from /api/dingtalk-workspace-cli/oauth/device/poll
  to /cli/oauth/device/poll (aligning with backend endpoint convention)
- Add x-user-access-token header to poll requests (loaded from stored token)

* feat(auth): PAT device flow improvements and flowId empty guard

- pat_auth_retry: fix JSON field parsing (result -> data) using DevicePollResponse
- pat_auth_retry: fix elapsed time calculation based on start timestamp
- device_flow: add flowId empty guard - skip polling and show auth URL for manual handling
- device_flow: unify terminalBaseURL to GetMCPBaseURL for polling endpoint
- device_flow: remove unused PollFlowApproval dead code
- runner: integrate DWS_CLIENT_ID env and app.json persistence
- oauth_provider: add x-robot-uid header removal on logout
- client: add request/response logging for transport debugging

* feat(env): switch all service discovery URLs from pre-release to production

- endpoints: pre-login/pre-api/pre-mcp/pre-open-dev -> login/api/mcp/open-dev
- loader: DefaultMarketBaseURL -> mcp.dingtalk.com
- registry: defaultBaseURL -> mcp.dingtalk.com
- constants: DefaultTerminalBaseURL -> open-dev.dingtalk.com

* fix: remove residual merge conflict markers and duplicate Hooks fields in edition.go; unify developer-settings URL via config helper in device_flow.go

* chore: remove lark-cli reference from PrintPatAuthError comment

* test: add comprehensive unit tests for PAT auth modules

- Create internal/errors/pat_test.go (38 tests): covers ClassifyToolResultContent,
  ClassifyMCPResponseText, ClassifyPatAuthCheck, AsPatAuthCheckError, cleanPATJSON,
  stripClassFields, getDWSGatewayErrorCode, isNotLoggedInError, isBusinessError,
  IsPATError, IsPATNoPermissionCode, suggestForBusinessErrorText
- Supplement pat_auth_retry_test.go (+7 tests): IsPatRetrying context checks,
  pollPatDeviceFlow edge cases (server error fallback, SSO redirect skip),
  extractPatScopeError nil/identity extraction

* feat(pat): exchange authCode for fresh token after PAT APPROVED

Previously pollPatDeviceFlow discarded the authCode from the poll
response, so handlePatAuthCheck retried with the stale token after
APPROVED. This mirrors device_flow.go loginOnce which calls
exchangeCode → SaveTokenData.

Changes:
- pollPatDeviceFlow: return (status, authCode, error) instead of
  (status, error); extract Data.AuthCode on APPROVED
- handlePatAuthCheck APPROVED path: call ExchangeCodeForToken +
  SaveTokenData before ResetRuntimeTokenCache, with graceful
  fallback on exchange failure
- Update all 6 poll test cases for new 3-return signature; add
  authCode assertions for APPROVED/REJECTED/EXPIRED/CANCELLED/
  ServerError scenarios

* fix(pat): CR round-2 must-fix items

- scopeValueRegex: support multi-segment scopes (mail:a.b:send)
  Updated regex to ([a-zA-Z][a-zA-Z0-9_.]*(?::[a-zA-Z][a-zA-Z0-9_.]*)+)

- handlePatAuthCheck: add 3 integration tests (APPROVED/REJECTED/EmptyFlowID)
  Covers the 132-line main orchestrator with mock runner + httptest server

- Extract ParseDeviceFlowStatus + status constants to auth package
  Eliminates string literal duplication across device_flow.go and pat_auth_retry.go

* fix(pat): use direct OAuth path when clientSecret is provided

When PAT error response includes both clientId and clientSecret,
use SetClientID() (direct DingTalk API mode) instead of
SetClientIDFromMCP() (MCP proxy mode). The MCP proxy does not
hold the secret for the PAT-assigned app, causing HTTP 400
'invalidParameter.idOrSecret.notFound' on token exchange.

Now: clientSecret present → direct mode; absent → MCP proxy mode.

---------

Co-authored-by: shangguanxuan.sgx <shangguanxuan.sgx@alibaba-inc.com>
2026-04-19 19:12:34 +08:00
fantiu 4f1ee37508 fix(auth): improve login UX for terminal auth denial cases 2026-04-17 10:20:35 +08:00
fantiu fec0347cd6 feat(auth):improve login UX for terminal auth denial cases 2026-04-17 10:15:04 +08:00
fantiu 95d495f290 feat: supports claw-like products. 2026-04-16 19:49:28 +08:00
fantiu b78dd19cf9 feat: centralize scattered configs and add dws config list 2026-04-12 14:23:11 +08:00
wxianfeng c49583836b feat(auth): delegate token persistence to edition hooks with keychain fallback
Add SaveToken, LoadToken, and DeleteToken hook fields to edition.Hooks so overlay builds can provide custom token storage. Refactor SaveTokenData, LoadTokenData, and DeleteTokenData to delegate to hooks when present, falling back to default keychain-based storage.
2026-04-10 23:33:11 +08:00
wxianfeng aec852f971 feat(auth): add edition overlay auth credentials and token marker for embedded mode
- Add AuthClientID and AuthClientFromMCP fields to edition Hooks, allowing overlays to override the default OAuth client ID and route auth through MCP endpoints.

- Introduce token marker file (token.json) mechanism so the host application in embedded mode can detect authentication state without accessing the keychain.

- Update SaveTokenData/DeleteTokenData to write/remove the marker file when running in embedded mode.

- Update ClientID() and IsClientIDFromMCP() to respect edition overrides.
2026-04-10 17:02:18 +08:00
fantiu 7c4932154c fix:auth check test file gofmt. 2026-04-02 11:20:06 +08:00
fantiu e2dbaa7c78 feat(auth): unify MCP retry constant and add retry to remaining endpoints 2026-04-02 11:10:49 +08:00
fantiu 11a0dbc84a feat(auth): unify MCP retry constant and add retry to remaining endpoints 2026-04-02 10:55:51 +08:00
fantiu ee441643dd fix(auth): switch CLI auth check from fail-open to fail-closed
Previously, when the /cli/cliAuthEnabled API was unreachable (network
error, timeout, 5xx, etc.), both OAuth and Device Flow login modes
silently assumed CLI access was enabled (fail-open). This allowed users
to "successfully" log in even when their organization had not granted
CLI data access, leading to confusing failures on subsequent API calls.

Changes:
- Reverse the check logic in OAuth callback: treat any error as
  "not enabled" instead of "enabled", showing the permission request
  page so users can take action.
- Block login in Device Flow when the check fails, with a clear
  error message asking users to verify network connectivity.
- Add retry with backoff (3 attempts, 0s/1s/2s) to
  CheckCLIAuthEnabled to tolerate transient network issues.
- Add retry with backoff (3 attempts) to FetchClientIDFromMCP
  (/cli/clientId) for the same transient-error resilience.
- Add i18n entries (en/zh) for new error messages.
- Add 19 tests covering server error, connection refused, malformed
  JSON, timeout, transient-then-recovery, business error, and full
  Device Flow loginOnce integration scenarios for both endpoints.

Made-with: Cursor
2026-04-02 10:55:51 +08:00
xianfeng wang 5c0d2b274c Merge branch 'DingTalk-Real-AI:main' into feature/wk_merge 2026-04-01 21:05:35 +08:00
fantiu 15d495e56e style(auth): redesign OAuth authorization pages UI 2026-04-01 20:21:05 +08:00
fantiu 8406355e7f fix(auth): prevent auth code expiration error on OAuth callback page refresh 2026-04-01 14:48:58 +08:00
fantiu 2a056cc5d0 feat(auth): persist OAuth credentials for reliable token refresh 2026-04-01 11:03:08 +08:00
wxianfeng 933615003c merge upstream main 2026-04-01 09:53:18 +08:00
fantiu 773804ee80 feat(auth): enhance device flow with CLI auth check and admin guidance 2026-04-01 00:47:49 +08:00
wxianfeng 3c75c66d4d chore: group pkg imports per goimports
Move pkg/config next to other pkg/* imports after local internal packages.

Made-with: Cursor
2026-03-31 15:32:50 +08:00
wxianfeng 93d6fdb17e feat: edition layer for Wukong overlay; promote shared code to pkg/
Introduce a build-time edition hook so downstream overlays (e.g. Wukong)
can customize auth UX, config dir, static server list, visible products,
and extra root commands while keeping the default open-source behavior.

- Add pkg/edition (defaults) and pkg/editiontest contract tests; Makefile
  target edition-test; CI job edition-tests.
- Root: optional RegisterExtraCommands with tool caller adapter; inject
  static servers to skip market discovery when configured; deduplicate
  top-level commands so overlay wins; extend hideNonDirectRuntimeCommands
  with edition VisibleProducts and static commands (recovery/schema/mcp).
- Auth/config: gate login subcommand and auth login hints for embedded
  editions; optional token auto-purge; edition ConfigDir override.
- version: human-readable multi-line output plus JSON with edition,
  architecture, build, commit.
- Relocate internal/{config,convert,validate} to pkg/; add pkg/cli and
  pkg/cmdutil (flags/time helpers).
- CI: optional notify-downstream job (GitLab trigger via secrets) on main
  push; open_source_policy_test adjusted for new layout.

Secrets (repo settings): WUKONG_TRIGGER_TOKEN, WUKONG_TRIGGER_URL — optional;
if unset, downstream step is skipped.

Made-with: Cursor
2026-03-31 15:29:21 +08:00
fantiu 26263f8a17 feat(auth): persist client credentials and optimize keychain access
- Auto-persist client-id/client-secret after successful login (stored in keychain)
- Enhanced logout to clean up app.json, keychain secrets, and token.json
- Fixed OAuth callback race condition (write response before sending code)
- Added credentials cache to avoid repeated keychain access (improves CLI speed)
- Updated README with credential priority docs and bumped to v1.0.4
2026-03-30 11:57:07 +08:00
fantiu 964855373e feat(auth): persist client credentials for token refresh
When logging in with --client-id and --client-secret, credentials are now
automatically persisted to enable automatic token refresh after expiration.
Client secret is securely stored in system Keychain, config file only
contains a reference.
2026-03-30 10:53:26 +08:00
柏荣 a1dffe454d 逻辑优化 2026-03-28 17:51:22 +08:00
tianlei.qjb 5f938d3675 init 2026-03-27 17:55:57 +08:00