- adapters/fs: FsProxy + fsworker run each file op in a killable subprocess;
progress-stall watchdog (FS_HANG_TIMEOUT_MS) for copy/hash, total timeout for
quick ops; SIGTERM -> SIGKILL -> FsError('TIMEOUT'); stat/checkRoot timeouts
never read as missing
- copyWithVerify: onExisting conflict/skip/replace (hardlink backup + atomic
rename, old file to .umt-trash or deleted), sweep stale partials before write,
document why permissions/owner are not copied
- filesMatch/filesMatchSha256 throw FsError on read failure instead of
match=false; crossDeviceMove skips redundant re-hash after sha256 copy
- FsErrorCode TIMEOUT + fsErrorClass; organize executeRecord routes fs ops
through fsproxy, retries TIMEOUT/IO up to FS_TRANSFER_MAX_ATTEMPTS then opens
a decision without deleting the record; reconcile errors no longer reported
as EEXIST
- domain: subtitle .default marker (ORGANIZE_DEFAULT_SUBTITLE_LANG) and
findOtherVersions (same season/episode/part, video only) as upgrade
disposal candidates
- scripts/bench/fs-bench.ts and benchmark record in porting doc
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Port agentui (MIT, ashish200729/agentui@b2b752b) Message/MessageBubble/MessageScroller,
StreamingResponse, ToolResult/ToolApproval, TodoList, ApprovalCard, CodeBlock/FileDiff,
Citations, PromptInput into components/agentui; drop motion/shiki/Next, switch colors,
type scale, radii, durations and easing to semantic tokens, honour reduced motion
- Conversation: streaming cursor, collapsible thinking, tool cards with kind/scope/risk/
idempotency badges and audit idempotency key, prominent server-rejection state for both
whitelist rejections and unauthorized errors, compaction markers, budget meters with
over-limit state, approval cards (admin session only), two-column final report
(model said vs system verified with task/record links), follow-scroll with jump-to-bottom
- Composer: Enter send / Shift+Enter newline, stop = abort (confirmed), append,
execute/plan_only switch, "execute this plan" from finished plan_only runs
- Session list sidebar with status filter and usage; reconnect/error banners with retry
- Drawer: route-derived context (entity/site/task), minimize to a live mini dock
- Fix stream refetch race when the run switches from loading to finished
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- settings.agent.autoInvestigateMode investigate|recover, investigateMaxAttempts, recoverVerifySec
- new capability download.recheck (execute, replay never): qB force recheck / resume, no source swap/delete
- autoInvestigate moves to agent/investigate.ts: recover mode runs execute with a recovery allowlist
only when an active grant (published policy if bound) covers the recovery actions; otherwise degrades
to read-only investigation and leaves suggestion + recheck option on the decision
- runAgent verifies recovery against business facts (download_task/task/source_release) before finalize;
verified -> decision resolved by system:auto-recover, run summary '已恢复(系统核实)'; otherwise stays
awaiting_user; per-root-cause attempt cap
- e2e E6: missingFiles -> download_failed -> recheck -> verified; no grant degrades; swap rejected;
dedupe; attempts exhausted; budget exceeded keeps attention
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- POST /approvals and PATCH /approvals/{id} require a console admin session
(EndpointDef auth:"session"); API keys incl. admin scope get 403, so an
organize.execute key can no longer approve its own plan (S1)
- tests for single-use approval checks: expired, revision/payload hash
mismatch, consumed, revoked, pending/rejected, plan mismatch; re-approve
after plan change succeeds once and cannot be replayed (S4)
- one redact key table in @umt/contracts shared by server logger and agent
redactForModel: rsskey, torrent_pass, authkey, downhash, c_secure_pass,
passkey variants, x-api-key, cookie headers, nested objects/arrays (S2)
- TMDB network errors: message and cause redacted via redactUrl (S3)
- web Agent ?mock=1 only in DEV builds or when pi.provider is fake (S7)
- EndpointDef auth annotations for /auth/*, asserted against
PUBLIC_AUTH_PATHS (S10); doc drift fixes (S11)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Agent page uses contracts (AgentRun/AgentRunDetail/AgentGoalReport) instead of a local
mirror; ?mock=1 stays as an explicit demo switch; run snapshot refreshes on agent.run_status;
stream auto-follow only while the user stays near the bottom (abort stays reachable)
- settings: Pi provider select incl. fake, new Agent runtime card (budgets, fakeScript)
- download trace uses /tasks?subjectId= and /organization-records?downloadTaskId= instead of
time-window engine run matching and path matching; new business-task tab with cancel/retry
- workbench download dialog posts /acquisition-plans and shows per-slot rejection reasons
- preference tag revision history; subscription search by title/kind; identity/alias/subscription
lists show entity titles; slot cards show current asset summary; policy preview sample titles
- DecisionSummary / IdentityRevisionList / ReleaseIdentityResult / TaskAccepted / PolicyPreviewSummary /
OrganizePlanArtifactContent taken from contracts
- docs: SSE for console (cookie) vs GET /events?after=&limit= JSON replay for API keys
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Capabilities: all 14 registered (AO: inventory.query, download.plan/submit, organize.plan/execute,
policy.preview/apply; agent: task.inspect/retry/cancel); startup asserts count == 14.
Registry injects server-side authorize (automation_grant by action/scope/policy version/budget,
one-shot approval bound to plan id + payload hash + revision + expiry; model claims ignored;
automation switch), audit_event, server idempotency keys and a capability_invocation op ledger
(migration 0021) used for crash reconciliation. download.plan creates draft plans only;
download.submit promotes draft -> reserved after authorization.
- Agent session API: POST/GET /agent/runs, GET /agent/runs/{id} (events by seq, messages, report),
POST .../messages (wake), POST .../abort; automation-grants, approvals, capabilities invoke, tasks.
- runAgent task: Pi or fake provider from settings (apiKey via secrets), events persisted to
agent_run_event then published, resume + ledger reconciliation when pendingOperations > 0,
waits for goal-linked downloads/imports and reports from business tables (submitted != imported).
- Background triggers: decision.created -> bounded plan_only investigation (dedupe per decision);
decision.updated(resolved) -> resolveDecision executes chosen option.
- W2 closure: all OpenAPI routes registered in contracts api.ts (+ subset test); TMDB key from
settings secret_ref with env fallback; PUT /sites/{id}/credentials documented as alias of
/site-accounts; completion events documented as existing status events.
- e2e (real PG + OpenWorkflow + testkit mocks): RSS->library, agent delegation with grant/deny,
background continuation, worker kill -9 recovery (single qB add), auto investigation dedupe.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- rss: port of MP RssHelper._parse_impl/get_rss_link semantics with safe
XML (entities off, DTD/ENTITY rejected, size/item caps), ETag/Last-Modified,
backoff + Retry-After, circuit breaker with manual reset, passkey redaction,
overlap-window GUID+digest dedupe
- sites/spider: TS port of MP SiteSpider (indexer schema, search URL builder,
field DSL, filters, Jinja templates via nunjucks, login-page detection);
audiences definition hand-written as JSON; raw category id preserved;
shared per-site token bucket
- sites/mteam: port of MP MTorrentSpider (params, result mapping, promo
factors, genDlToken flow) without embedding the API key in enclosures;
business code/message checks
- testkit: mock RSS server, mock NexusPHP site, mock M-Team API
- docs: W1-3b migration mapping appended to porting ledger
Co-Authored-By: Claude Fable 5.1 <[email protected]>