dsh-ant 0.6.0 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -6,6 +6,7 @@ import { readFile } from 'node:fs/promises'
6
6
  import { installSkill, listSkills, uninstallSkill } from './skill-install.js'
7
7
  import { readLocalDelegationSettings, recentDelegationStatus, startDelegationHost,
8
8
  writeLocalDelegationSettings } from './delegation.js'
9
+ import { waitForSignal } from './conversation.js'
9
10
 
10
11
  export const inject = []
11
12
 
@@ -29,6 +30,7 @@ const DELEGATION_GRANTS_PATH = '/api/ant-teams/delegation/grants'
29
30
  const DELEGATION_ENROLLED_BOTS_PATH = '/api/ant-teams/delegation/enrolled-bots'
30
31
  const DELEGATION_GROUPS_PATH = '/api/ant-teams/delegation/groups'
31
32
  const DELEGATION_DM_CHAT_PATH = '/api/ant-teams/delegation/dm-chat'
33
+ const DELEGATION_OWNER_CHALLENGE_PATH = '/api/ant-teams/delegation/owner-challenge'
32
34
  const DELEGATION_STATUS_PATH = '/api/ant-teams/delegation/status'
33
35
  const DELEGATION_CARDS_PATH = '/api/ant-teams/delegation/cards'
34
36
  const DELEGATION_RULE_RECOGNITION_PATH = '/api/ant-teams/delegation/recognize'
@@ -319,7 +321,7 @@ async function fetchDelegationBots(request, ctx) {
319
321
  try {
320
322
  const details = await service.describeBot(bot.botId)
321
323
  return {
322
- bot_id: bot.botId, name: details.account?.name || bot.botId,
324
+ bot_id: bot.botId, channel: bot.channel, name: details.account?.name || bot.botId,
323
325
  fingerprint: details.account?.fingerprint,
324
326
  connected: details.connected === true,
325
327
  available: details.capabilities?.includes('exclusive-text-consumer')
@@ -384,14 +386,33 @@ async function fetchDelegationGrants(request, ctx, credentials, settings) {
384
386
  }
385
387
 
386
388
  async function fetchDelegationGroupSettings(request, ctx, credentials, settings, kind, getHost) {
387
- const methods = kind === 'groups' ? ['GET', 'PUT'] : kind === 'dm-chat' ? ['PUT']
388
- : kind === 'challenge' ? ['POST'] : ['GET', 'POST', 'DELETE']
389
+ const methods = kind === 'groups' ? ['GET', 'PUT'] : kind === 'dm-chat' ? ['PUT'] : ['GET', 'POST', 'DELETE']
389
390
  if (!methods.includes(request.method)) return jsonResponse(405, { message: '请求方式不支持。' })
391
+ if (kind === 'challenge' && request.method === 'DELETE') {
392
+ const fingerprint = new URL(request.url).searchParams.get('bot_fingerprint')
393
+ if (typeof fingerprint !== 'string' || !/^[a-f0-9]{64}$/iu.test(fingerprint)) {
394
+ return jsonResponse(400, { message: '请求格式无效。' })
395
+ }
396
+ const host = getHost?.()
397
+ if (!host?.cancelOwnerChallenge) {
398
+ return jsonResponse(503, { message: '本机协作收件尚未就绪,请稍后刷新后重新生成绑定码。' })
399
+ }
400
+ return jsonResponse(200, { cancelled: host.cancelOwnerChallenge(fingerprint) })
401
+ }
390
402
  let connection
391
403
  try { connection = await readMemberConnection(credentials, settings) } catch {
392
404
  return jsonResponse(500, { message: '无法读取 ANT 连接。' })
393
405
  }
394
406
  if (!connection) return jsonResponse(401, { message: '请先连接 ANT 团队。' })
407
+ if (kind === 'challenge' && request.method === 'GET') {
408
+ const fingerprint = new URL(request.url).searchParams.get('bot_fingerprint')
409
+ if (typeof fingerprint !== 'string' || !/^[a-f0-9]{64}$/iu.test(fingerprint)) {
410
+ return jsonResponse(400, { message: '请求格式无效。' })
411
+ }
412
+ const status = getHost?.()?.ownerChallengeStatus?.(fingerprint)
413
+ if (!status) return jsonResponse(503, { message: '本机协作收件尚未就绪,请稍后刷新后重新生成绑定码。' })
414
+ return jsonResponse(200, status)
415
+ }
395
416
  let body = null
396
417
  if (request.method !== 'GET') {
397
418
  try {
@@ -400,7 +421,7 @@ async function fetchDelegationGroupSettings(request, ctx, credentials, settings,
400
421
  body = JSON.parse(raw)
401
422
  } catch { return jsonResponse(400, { message: '请求格式无效。' }) }
402
423
  }
403
- if (kind === 'bots' && request.method === 'POST') {
424
+ if (['bots', 'challenge'].includes(kind) && request.method === 'POST') {
404
425
  const service = dshImService(ctx)
405
426
  if (!service?.describeBot) return jsonResponse(503, { message: '请先安装并启用 DSH-IM。' })
406
427
  try {
@@ -417,6 +438,7 @@ async function fetchDelegationGroupSettings(request, ctx, credentials, settings,
417
438
  }
418
439
  const path = kind === 'groups' ? '/api/me/im-delegations/groups'
419
440
  : kind === 'dm-chat' ? '/api/me/im-delegations/dm-chat'
441
+ : kind === 'challenge' ? '/api/me/im-delegations/owner-challenge'
420
442
  : request.method === 'DELETE'
421
443
  ? `/api/me/im-delegations/bots/${encodeURIComponent(body.bot_id)}`
422
444
  : '/api/me/im-delegations/bots'
@@ -430,6 +452,7 @@ async function fetchDelegationGroupSettings(request, ctx, credentials, settings,
430
452
  method: request.method,
431
453
  headers: { authorization: `Bearer ${connection.token}`, accept: 'application/json',
432
454
  ...(request.method !== 'GET' ? { origin: new URL(connection.serviceUrl).origin } : {}),
455
+ ...(kind === 'challenge' ? { 'x-ant-owner-approval-version': '1' } : {}),
433
456
  ...(['POST', 'PUT'].includes(request.method) ? { 'content-type': 'application/json' } : {}) },
434
457
  ...(['POST', 'PUT'].includes(request.method) ? { body: JSON.stringify(body) } : {}),
435
458
  redirect: 'manual', signal: AbortSignal.timeout(12_000),
@@ -448,6 +471,16 @@ async function fetchDelegationGroupSettings(request, ctx, credentials, settings,
448
471
  }
449
472
  const text = await readLimitedBody(response)
450
473
  if (text === null) return jsonResponse(502, { message: '团队服务响应过大。' })
474
+ if (kind === 'challenge' && request.method === 'POST' && response.ok) {
475
+ let challenge
476
+ try { challenge = JSON.parse(text) } catch {
477
+ return jsonResponse(502, { message: '团队服务返回的绑定码格式无效。' })
478
+ }
479
+ const host = getHost?.()
480
+ if (!host?.rememberOwnerChallenge?.(body.bot_fingerprint, challenge?.code)) {
481
+ return jsonResponse(503, { message: '本机协作收件尚未就绪,请稍后刷新后重新生成绑定码。' })
482
+ }
483
+ }
451
484
  if (kind === 'groups' && request.method === 'GET' && response.ok) {
452
485
  try {
453
486
  const groups = JSON.parse(text)
@@ -563,9 +596,10 @@ async function fetchDelegationCards(request, ctx, credentials, settings) {
563
596
  async function fetchDelegationRuleRecognition(request, credentials, settings, getHost) {
564
597
  if (request.method !== 'POST') return jsonResponse(405, { message: '只支持 POST 请求。' })
565
598
  try {
566
- const connection = await readMemberConnection(credentials, settings)
599
+ request.signal.throwIfAborted()
600
+ const connection = await waitForSignal(readMemberConnection(credentials, settings), request.signal)
567
601
  if (!connection) return jsonResponse(401, { message: '请先连接 ANT 团队。' })
568
- const raw = await request.text()
602
+ const raw = await waitForSignal(request.text(), request.signal)
569
603
  if (raw.length > 8_192) return jsonResponse(413, { message: '规则描述过长。' })
570
604
  let body
571
605
  try { body = JSON.parse(raw) } catch { return jsonResponse(400, { message: '规则识别请求格式无效。' }) }
@@ -574,7 +608,7 @@ async function fetchDelegationRuleRecognition(request, credentials, settings, ge
574
608
  }
575
609
  const host = getHost?.()
576
610
  if (!host?.recognizeRule) return jsonResponse(503, { message: '本机 DSH 协作会话尚未就绪,请稍后重试。' })
577
- return jsonResponse(200, await host.recognizeRule(body.description))
611
+ return jsonResponse(200, await host.recognizeRule(body.description, request.signal))
578
612
  } catch (error) {
579
613
  return jsonResponse(502, { message: error?.message || '任务规则识别失败,请稍后重试。' })
580
614
  }
@@ -602,12 +636,14 @@ async function fetchDelegationExecutors(request, ctx) {
602
636
  if (Array.isArray(listed)) providers = listed
603
637
  } catch {}
604
638
  const available = new Set(providers)
605
- const externalProviderReason = 'DSH 尚未提供可核验的逐任务文件、Git 和网络权限;ANT 暂不把外部子 Agent 用于协作任务。'
639
+ const providerReason = (name) => `DSH 尚未启用 ${name} 子 Agent 提供方。`
606
640
  return jsonResponse(200, [
607
641
  { id: 'dsh', title: 'DSH', available: Boolean(optionalHostService(ctx, 'sessionController')
608
642
  && optionalHostService(ctx, 'agents')) },
609
- { id: 'codex', title: 'Codex', available: false, reason: externalProviderReason },
610
- { id: 'claude-code', title: 'Claude Code', available: false, reason: externalProviderReason },
643
+ { id: 'codex', title: 'Codex', available: available.has('codex'),
644
+ ...(!available.has('codex') ? { reason: providerReason('Codex') } : {}) },
645
+ { id: 'claude-code', title: 'Claude Code', available: available.has('claude-code'),
646
+ ...(!available.has('claude-code') ? { reason: providerReason('Claude Code') } : {}) },
611
647
  { id: 'acp', title: 'DSH ACP', available: available.has('acp') },
612
648
  { id: 'dsh-sdk', title: 'DSH SDK 子代理', available: available.has('dsh-sdk') },
613
649
  ])
@@ -1161,6 +1197,7 @@ export function apply(ctx) {
1161
1197
  [DELEGATION_ENROLLED_BOTS_PATH, ['GET', 'POST', 'DELETE'], 'bots'],
1162
1198
  [DELEGATION_GROUPS_PATH, ['GET', 'PUT'], 'groups'],
1163
1199
  [DELEGATION_DM_CHAT_PATH, ['PUT'], 'dm-chat'],
1200
+ [DELEGATION_OWNER_CHALLENGE_PATH, ['GET', 'POST', 'DELETE'], 'challenge'],
1164
1201
  ]) {
1165
1202
  connectionCtx.effect(() => connectionCtx.connection.fetch.register({
1166
1203
  path, methods, requestBody: 'buffered',