Files
zkxw/.agents/skills/personal-dev/scripts/pda/worker_dispatch.py
T
zlwu 42301730ef chore(agents): 更新个人智能体至官方 main eb4c320
固定协议 6 安装内容与来源摘要,保留试点工程配置及既有授权,为合入 V2.0 提供可复现版本。
2026-11-02 11:59:53 +08:00

156 lines
9.0 KiB
Python

"""CLI routing for per-conversation workers; legacy recovery remains explicit."""
from .issue_queue import (Queue, Delivery, GitLease, STOP, DIRECTORY as LEGACY_DIRECTORY,
configuration, main_project, git, validate_delivery_storage)
from .issue_workers import WorkerQueue, DIRECTORY
from .issue_claims import Claims
from .issue_tracker import Tracker
from .permissions import Permissions
from .transaction import InstallError, safe_path
def validate_storage(root, worker):
for directory in (DIRECTORY, LEGACY_DIRECTORY):
if git(root,'ls-files','--',directory): raise InstallError('worker/queue state must not be Git-tracked')
paths=[STOP]
if worker.owner: paths += [worker._path(name) for name in ('state.json','stop','write.lock')]
for path in paths:
safe_path(root,path)
git(root,'check-ignore','--quiet','--',path)
def validate_checkpoint_storage(root, repository, branch, record, stage):
if record and record.get('commit') and (stage == 'waiting_user' or
(record.get('stage') in ('ready_to_merge', 'merging') and
stage not in ('ready_to_merge', 'merging'))):
# Invalidation writes the accepted record commit, not the requested new commit.
validate_delivery_storage(root, Delivery(root, repository, branch),
record['number'], record['commit'])
CONTROL_PERMISSIONS = ('manage_claims', 'update_issue_labels')
def scope_issue(state, requested=None):
current = state.get('current')
scope = state.get('issue_scope')
if current and scope is not None and current['number'] != scope:
raise InstallError('current issue is outside worker scope')
if requested is not None and scope is not None and requested != scope:
raise InstallError('requested issue is outside worker scope')
return current['number'] if current else (scope if scope is not None else requested)
def bind_authorization(worker):
def check(state):
def before_write():
# Local checks only: never recurse into claims.ensure from a transport hook.
config, _, repository, branch = configuration(worker.root)
if repository != state['repository'] or branch != state['integration_branch']:
raise InstallError('permission repository or integration branch changed')
return Permissions(worker.root, repository, branch, worker.owner).require(
config.get('permissions', {}), scope_issue(state), CONTROL_PERMISSIONS)
effective = before_write()
worker.tracker.before_write = before_write
worker.claims.before_write = before_write
return effective
worker.authorization = check
def permission_dispatch(root, args, config, repository, branch):
permissions = Permissions(root, repository, branch, args.owner)
action = args.action.split('-', 1)[1]
if action == 'status': return dict(record=permissions.status(), project_permissions=config.get('permissions', {}))
if action == 'revoke': return permissions.revoke(args.issue, args.evidence, apply=args.apply)
if action == 'grant':
allow = args.allow.split(',') if args.allow else []
deny = args.deny.split(',') if args.deny else []
return permissions.grant(args.issue, allow, deny, args.evidence, apply=args.apply)
capabilities = args.capability.split(',')
effective = permissions.require(config.get('permissions', {}), args.issue, capabilities)
return dict(status='allowed', owner=args.owner, issue=args.issue, capabilities=capabilities,
permissions=effective)
def dispatch(root,args):
root=main_project(root)
worker=WorkerQueue(root,owner=args.owner)
action=args.action.split('-',1)[1]
delivery_action=args.action.startswith('delivery-')
permission_action=args.action.startswith('permissions-')
if action=='status' and not delivery_action and not permission_action: return worker.status()
if action in ('stop','legacy-stop'):
validate_storage(root,worker)
return Queue(root).stop() if action=='legacy-stop' else worker.stop()
config,settings,repository,branch=configuration(root)
if permission_action: return permission_dispatch(root,args,config,repository,branch)
if delivery_action:
delivery=Delivery(root,repository,branch)
if action=='status':
if args.issue is not None: return delivery.status(args.issue)
safe_path(root,'.local/agent/delivery/write.lock')
numbers=sorted(int(p.stem) for p in (root/'.local/agent/delivery').glob('*.json') if p.stem.isdigit())
return dict(status='inventory',tasks=[delivery.status(n) for n in numbers])
validate_delivery_storage(root,delivery,args.issue,args.commit if action=='record' else None)
if action=='record': return delivery.record(args.issue,args.commit,args.stage,args.evidence)
old=Queue(root).status()
tasks=WorkerQueue(root).status()['workers']
if any(s.get('current',{}).get('number')==args.issue for s in [old]+tasks if s.get('current')):
raise InstallError('current issue must use queue-finish with its owner')
if delivery.status(args.issue)['record'] is None: raise InstallError('missing delivery record')
if action == 'transfer' and not args.apply:
return dict(status='preview', project=str(root), repository=repository, integration_branch=branch,
source_owner=args.owner, target_owner=args.target_owner,
effect='transfer the stopped source worker current issue to the target owner; retain task checkpoints',
needs=['explicit user transfer', 'source stopped and shared resources released',
'Git/API write access', 'manage_claims and update_issue_labels permissions'])
if action == 'start' and not args.apply:
return dict(status='preview',project=str(root),repository=repository,integration_branch=branch,
label='ai-ready',effect='per-issue remote claims, compatibility gate and stage labels; may trigger branch CI',
needs=['explicit user start','Git/API write access','manage_claims and update_issue_labels permissions'])
if not delivery_action:
state = worker.status()
if action not in ('start','transfer') and not state['enabled']: raise InstallError('queue is stopped')
requested = getattr(args, 'issue', None) if action in ('start','claim','retry') else None
issue = scope_issue(state, requested)
Permissions(root, repository, branch, args.owner).require(config.get('permissions', {}), issue, CONTROL_PERMISSIONS)
validate_storage(root,worker)
if action == 'checkpoint':
# Reject unsafe known local targets before any tracker or remote access.
validate_checkpoint_storage(root, repository, branch, worker.status().get('current'), args.stage)
if action == 'retry':
delivery = Delivery(root, repository, branch)
proof = delivery.status(args.issue)['record']
if proof:
# Retry clears acceptance on the existing proof commit, without changing revision.
validate_delivery_storage(root, delivery, args.issue, proof['commit'])
credentials=config.get('environment',{}).get('secrets')
if credentials in (None,'','.local/secrets/access.json','external-controlled-storage'): credentials=None
worker.tracker=Tracker(settings['kind'],repository,root,credentials_path=credentials)
worker.lease,worker.branch,worker.claims=GitLease(root,repository),branch,Claims(root,repository)
if delivery_action:
if worker.claims.get('issues/'+str(args.issue)):
raise InstallError('remote claimed issue must use owner queue-finish')
return delivery.check(args.issue,args.commit,worker.tracker,worker.lease)
bind_authorization(worker)
if action=='start': return worker.start(issue=getattr(args,'issue',None))
if action=='transfer': return worker.transfer(args.target_owner,args.evidence)
if action=='next': return worker.next()
if action=='claim': return worker.claim(args.issue)
if action=='guard': return worker.guard()
if action=='cleanup-guard': return worker.cleanup_guard()
if action=='checkpoint':
# The remote stage/commit can be newer when a prior label sync was interrupted.
record = worker._owned(worker.status())
validate_checkpoint_storage(root, repository, branch, record, args.stage)
return worker.checkpoint(args.stage,args.branch,args.worktree,args.commit)
if action=='resource-acquire': return worker.resource(args.resource,True)
if action=='resource-release': return worker.resource(args.resource,False)
if action=='block': return worker.block(args.reason)
if action=='retry': return worker.retry(args.issue)
if action=='finish':
current=worker.status()['current']
if current: validate_delivery_storage(root,Delivery(root,repository,branch),current['number'])
return worker.finish(args.commit,args.evidence)
raise InstallError('unknown worker action')