mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
DingTalk can receive interactive card callbacks, but the card UI still depends on a published template, so the adapter now supports a template-backed card path with text commands as the reliable fallback. Telegram and WeChat use the same allow-once, allow-always, and deny semantics so manual authorization behaves the same across platforms. Constraint: DingTalk button rendering requires an operator-provided interactive card template id Rejected: Treat the existing AI streaming card template as a permission card | it cannot guarantee visible action buttons Confidence: high Scope-risk: moderate Directive: Do not remove the text approval fallback unless DingTalk card template provisioning is guaranteed Tested: bun test adapters/common/__tests__/permission.test.ts adapters/dingtalk/__tests__/permission-card.test.ts adapters/telegram/__tests__/telegram.test.ts adapters/common/__tests__/config.test.ts src/server/__tests__/adapters.test.ts Tested: bunx tsc -p adapters/tsconfig.json --noEmit Tested: bun run check:adapters Tested: cd desktop && bun run build Tested: bun run check:server Tested: bun run check:docs Tested: git diff --check Not-tested: bun run quality:pr is blocked by existing CLI core approval policy; see artifacts/quality-runs/2026-05-03T13-19-56-232Z/report.md
48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
import { describe, expect, it } from 'bun:test'
|
|
import {
|
|
buildDingTalkPermissionCardParams,
|
|
parseDingTalkPermissionCardAction,
|
|
} from '../permission-card.js'
|
|
|
|
describe('DingTalk permission card helpers', () => {
|
|
it('builds template params with three permission actions', () => {
|
|
const params = buildDingTalkPermissionCardParams('Bash', { command: 'npm test' }, 'req-1')
|
|
|
|
expect(params.requestId).toBe('req-1')
|
|
expect(params.toolName).toBe('Bash')
|
|
expect(String(params.inputPreview)).toContain('npm test')
|
|
expect(JSON.parse(String(params.allowValue))).toEqual({ action: 'permit', requestId: 'req-1', allowed: true })
|
|
expect(JSON.parse(String(params.alwaysValue))).toEqual({ action: 'permit', requestId: 'req-1', allowed: true, rule: 'always' })
|
|
expect(JSON.parse(String(params.denyValue))).toEqual({ action: 'permit', requestId: 'req-1', allowed: false })
|
|
})
|
|
|
|
it('parses nested card private params', () => {
|
|
const action = parseDingTalkPermissionCardAction({
|
|
outTrackId: 'permission_req-1',
|
|
content: JSON.stringify({
|
|
cardPrivateData: {
|
|
params: {
|
|
action: 'permit',
|
|
requestId: 'req-1',
|
|
allowed: true,
|
|
rule: 'always',
|
|
},
|
|
},
|
|
}),
|
|
})
|
|
|
|
expect(action).toEqual({ requestId: 'req-1', allowed: true, rule: 'always' })
|
|
})
|
|
|
|
it('parses compact callback values', () => {
|
|
expect(parseDingTalkPermissionCardAction({ actionValue: 'permit:req-2:no' })).toEqual({
|
|
requestId: 'req-2',
|
|
allowed: false,
|
|
})
|
|
})
|
|
|
|
it('ignores callbacks without permission action data', () => {
|
|
expect(parseDingTalkPermissionCardAction({ action: 'open_url', url: 'https://example.com' })).toBeNull()
|
|
})
|
|
})
|