- site.list / site.health_check / site.refresh_login / site.user_data capabilities
over the W9-A site center services; outputs whitelisted (no secret refs,
cookies, passwords, login names); execute kinds need automation grant.
IDs use snake_case (CapabilityId regex); registry count 17 -> 21.
- settings.organize.minSizeBytes (default 50 MiB); file-manager identify /
organize and planImport take request > setting > port default.
- tests and runbook notes (sites, files).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- POST /files/suggest-name renders the effective template (entity > root >
global) with the same variables as organize: file name segment for files,
work/season dir segment for directories; identity_uncertain when no entity
- planImport plan.naming.templateSource/templateVersion now come from
effectiveNaming + the registered template version (fixes the leftover
DEFAULT_TEMPLATES reference after the naming chain landed)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- GET /naming/variables, POST /naming/preview (builtin/fileName/sourceRelease/asset samples,
line:col errors, warnings, binding-aware), GET/PUT /naming/templates,
PUT /library-roots/{id}/naming, PUT /media-entities/{id}/naming-override
- planImport picks templates entity > library root > global, registers the template
version for new path bindings; naming vars include en title, external ids, season/
episode metadata, slot and root names; optional lock of file-name template for bound works
- runbook: docs/runbook/naming.md
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- process_heartbeat / process_heartbeat_sample (0034): api / worker / worker:agent / all
upsert every 15s (event loop lag last/max, concurrency, running runs, SSE connections, memory)
- GET /system/health (admin): processes with 45s stale flag, SSE, DB latency/size/connections,
disks (DATA_DIR / library roots / download dirs, cache thresholds), mount sentinel checks
with IO timeout, engine pending/oldest/24h failure rate, schedules
- GET /system/health/history?hours=: bucketed lag / running / SSE series
- /engine/runs and /engine/runs/{id}: business {kind, refId, title, triggeredBy} joined from
run input / task / agent_run / tasks_run_meta / outbox; businessKind / businessRefId filters
- docs/runbook/ops.md: field meanings and alert thresholds
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- GET /search?q=&scope=all|media|releases|actions&limit=: local works (title_alias
exact/prefix/trgm + name prefix, slot status summary), TMDB candidates (cached,
localEntityId), cross-site releases, page/action jump list; tookMs per group
- cross-site: enabled sites via shared per-site limiter, 15s AbortSignal timeout,
site concurrency cap 4, same-query coalescing, 30s cache; partial + failedSites;
results upserted to source_release; inventory overlay via GET /inventory
- GET /search/releases: site/resolution/source/size/free/H&R filters, sort, cursor,
facets; shares the cache
- POST /search/releases/{siteId}/{siteReleaseId}/plan: forwards in-process to
POST /acquisition-plans (same auth, validation, audit, rejections)
- contracts/search.ts, runbook, tests (partial/timeout, coalesce, cache, overlay,
filters/sort, plan)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
pi.provider / baseUrl / model / thinkingLevel / apiKeySecretRef are now
DEPRECATED_SETTINGS_FIELDS: kept in the schema for stored JSON, dropped
from PATCH /settings and from the settings sections, never read by the
server. runAgent fails with a clear message when no upstream is set.
The agent demo gate checks the default upstream provider; e2e seeds a
fake upstream as default. OpenAPI summaries say Agent upstream.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Pi token refresh (10 min) and auth session cleanup (1 h) no longer run
their own setInterval; both register in the maintain group of the
schedules registry with the same default intervals.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- /console/settings#<section>[/<anchor>]; legacy ?tab= redirected in clientLoader
- SETTINGS_SECTIONS in contracts with field-ownership test
- Agent section: upstream list, create wizard (provider -> credentials/model -> login/test/default),
edit drawer with OAuth browser/device login, test, set default, delete
- sites section with site registration, snapshot/rate-limit drawer and account credentials
- path mappings moved into downloader / media-server drawers; metadata and account sections
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- agent_run gains depth / spawn_reason (0029); agent_run_event types
subagent_spawned / subagent_event / subagent_completed
- agent.spawn (propose, medium, replay never): allowlist ⊆ parent, mode not
above parent, budget carved from parent's remainder, idempotent per run+input;
settings.pi.subagents {enabled, maxConcurrent, maxDepth} (subagentsEnabled kept as alias)
- child runs claim a concurrency slot under an advisory lock (waitForFact while
queued); agent.await polls business tables without calling the model
- parent abort cascades to all descendants; parent runtime budget counts
descendant usage; child events mirrored into the parent stream by parent seq
- authorize caps every child call by all ancestors' allowlists/kinds
- session page shows parent link, inherited info and the subagent tree
- e2e E11; runbook section on subagents
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- downloads.ts observe: re-read download_task FOR UPDATE inside the tx and merge
from the locked row; qB sync could overwrite imported back to importing when
verifyAndImport committed between the sync read and write (E8 flake).
- agent finalize: accept summaryPrefix so the recovery verdict is written with
the terminal status in one update (E6 read a budget_exceeded run before the
"未恢复:…" annotation landed); recover-summary step kept, now idempotent no-op.
- organize.ts: drop local slotComplete and the once-subscription completion
write; completion/history are decided only by applySlotEvent(verify_passed)
(W5-C follow-up, removes double write). Manual slot organize uses the shared
subscriptions.slotComplete.
- vitest: server split into unit (parallel) and pg (file-serial, groupOrder 1)
projects; packages/tasks file-serial; explicit worker concurrency in e2e.
- docs: W6 stabilization record in 04-v0.1-acceptance.md.
Test expectations unchanged. Full `deno task ci` x3 green: 369s / 341s / 337s.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- /files/move|copy go through planImport's new `transfer` variant (keep names, directory
expanded to per-file plan) → organization_record + verifyAndImport/executeRecord: per-file
ledger resumable, fsproxy, cross-volume directory move = per-file copy→verify→delete then
remove empty source dirs; shared plan store + plan_stale; asset_location follows per file,
path_binding revised when a whole directory moved (finalizeTransfer); request waits up to
FILES_TRANSFER_WAIT_SEC, else executed.pending
- /files/organize per-item overrides take effect: season/episodes (domain planOrganize
overrides), contentUnitId coverage, targetDir (no binding), operation, slotId (satisfied
after verify); warnings only for inapplicable overrides
- delete/trash/restore write organization_record (action trash|delete|restore, file-level
results; migration 0026)
- GET /files/download (admin session, nfo/subtitle/image, size cap, streamed, audited)
- GET /files/records?ids|planIds for the organize page
- fs race errors map to 503/404/403/400 instead of 500
- runbook updated
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- main.ts: `--role fsworker` dispatched before the rest of the module graph is
loaded (other imports became dynamic); runs fsWorkerMain from the new
`@umt/adapters/fsworker` export (~150 ms startup in the compiled binary)
- fsproxy: default worker command picked per runtime (deno CLI -> `deno run
fsworker.ts`, compiled binary -> `<execPath> --role fsworker`); stats expose
workerKind; UMT_FS_TEST_HANG_AFTER_BYTES acceptance switch for containers
- compile: --allow-run adds /app/umt-server (spawn self); start task allows deno
- organize: replaced old file moved into the file-manager trash layout
(<root>/.umt-trash/<day>/<uuid>/<rel>) and registered in trash_item, ledger
result follows; organize.transfer log carries fsproxy stats
- settings: autoInvestigateMode (investigate/recover) + max recover attempts
- deploy.md: container verification (subprocess self, TIMEOUT -> SIGKILL x3)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- 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]>