Skip to content

feat(files): advanced agent file management — editor, import, proposals in chat (CLEAN-112) - #110

Merged
maksymhryzodub-prog merged 9 commits into
mainfrom
feat/CLEAN-112-advanced-file-management
Sep 24, 2026
Merged

maksymhryzodub-prog merged 9 commits into
mainfrom
feat/CLEAN-112-advanced-file-management

Conversation

@maksymhryzodub-prog

@maksymhryzodub-prog maksymhryzodub-prog commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Jira: CLEAN-112 [ADMIN][APP]
Spec: specs/017-advanced-file-management/ (spec, plan, research, data-model, contracts, quickstart, tasks)

What changes

Files tab (admin)

  • Any text format is viewable and editable (extension allowlist + byte sniff, one list on the API); binary files get Download / Open full only.
  • Large files stream in slices as you scroll — no Load more; slices never split a UTF-8 character; editing unlocks when the whole file is loaded and it is under the editable cap.
  • Open full: short-lived JWT link, raw file streamed by the API as text/plain with nosniff + CSP: sandbox (never renders agent-written HTML/JS on the API origin).
  • Monaco editor (lazy, client-only, its own chunk), JSON validity badge, Ctrl/⌘+S, Ln/Col, drafts and tabs kept in the store, 412 conflict dialog on save.
  • Import a workspace zip: staged once, plan preview (add / change / unchanged / remove / skip), Merge by default, Replace double-acknowledged, sessions/ skipped unless included, result + Restart now / Later.
  • Explorer: filter (⌘P), size/modified columns, checkboxes with bulk Download / Delete (refuses to empty the workspace without a second ack), New file, tabs with unsaved dots, "Agent copy is newer — Sync now" pill.

Agent tools (api) — topic Agent workspace: list_agent_files, read_agent_file, write_agent_file, create_agent_file, import_agent_files. Writes are confirm-by-proposal: the first call creates a FileChangeProposal and writes nothing; the confirming call carries confirm: true and the proposalId. The direct list/read/write tools in rancher.tool.ts are removed (the file slice owns them now). Documented in docs/agent-tools.md.

Chat cards (bridle, admin + app) — new hub→browser events proposal / proposal_update published by the API into the active turn (CLEAN-74 pattern, no runtime change); the transcript endpoint returns proposals for reload. Admin card: inline diff, Apply / Edit before applying / Skip, ?proposal= editor flow with side-by-side diff, Restart now / Later. App card: read-only twin, strings in en.json + generated ru.json.

Limits live in one module (file.limits.ts, env RANCH_FILES_*) and are served by GET /agents/:id/files/limits: inline diff ≤ 200 changed lines / 100 KB, no diff above 1 MiB, set cards list ≤ 50 rows, archives ≤ 100 MB / 2000 entries / 25 MB per file.

Twin consoles

  • bridle: touched in both consoles (admin renders the actionable card; app renders the same card read-only — the write tools are operator-only and the app has no Files tab).
  • Files tab: admin only — there is no twin; templateFile keeps its own plain viewer.

Data

  • Prisma model FileChangeProposal + migration 20260923140000_file_change_proposal (additive, cascades with the agent).
  • New S3 prefixes outside agent prefixes: imports/<agentId>/<importId>.zip (staged archives, swept after 60 min) and proposals/<id>/content.

Verification

  • API: jest src/slices/agent/file src/slices/bridle src/slices/mcp — 404 tests green (incl. the boot-time tool metadata contract); tsc clean.
  • Admin: bun test slices 65 green; nuxt typecheck clean; nuxt build OK — Monaco is in its own chunks (core 2.65 MB + LSP client 1.17 MB + per-language workers, TS worker 6.9 MB) and is only import()ed from the Files-tab chunk.
  • App: bun test slices + nuxt typecheck clean; bun run i18n:check in sync.
  • Not run here: the manual quickstart scenarios 1–5 (need a stand with S3, Postgres and a running agent). Please run them before merging; specs/017-advanced-file-management/quickstart.md lists each step.

Tools checklist (docs/agent-tools.md)

  • topic / title / template on every new tool; destructive: true + confirm on write/create/import
  • tools call the same services as the controllers (IFileGateway, WorkspaceArchiveService, FileProposalService)
  • specs beside the tools (file.tool.spec.ts, file.tool.proposals.spec.ts)
  • no secrets in results; the local file picker is the one console-only action and import_agent_files says so

🤖 Generated with Claude Code

maksymhryzodub-prog and others added 9 commits September 23, 2026 17:32
API: kind/editable classification, UTF-8-safe slices, createOnly/ifUnmodifiedSince
saves, bulk delete/export bodies, limits route, open-link JWT + hardened raw
stream, workspace archive service and import routes.
Admin: Monaco editor (lazy, client-only), auto-loading slices, tabs and drafts
in the store, Open full, binary panel, save-conflict dialog.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… file tools (CLEAN-112)

API: FileChangeProposal model + migration, proposal service with capped diffs,
proposal routes, bridle proposal/proposal_update events, transcript carries
proposals; list/read/write/create/import tools with confirm-by-proposalId.
Admin: import dialog (stage → plan → merge/replace → result), proposal store
and data layer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tion and tabs (CLEAN-112)

Admin: proposal store, ProposalCard with bounded inline diff and Apply /
Edit before applying / Skip, transcript merge, ?proposal= editor flow with
side-by-side DiffView, Explorer (filter, checkboxes, size/modified, bulk
download/delete), New file, tabs util. App: read-only ProposalCard, store and
mapper handlers, en/ru strings. Rancher's direct file tools move to the file
slice behind proposals; docs/agent-tools.md records the confirm-by-proposal
convention.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…EAN-112)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…by link (CLEAN-112)

The private-range check resolved the host once and fetch resolved it again,
which a DNS-rebinding host could split. The download now connects to the
address that passed the check, refuses redirects and credentials in the
link, and still validates TLS against the hostname.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Wider explorer column (360-420px, 460px on xl), narrower size/date columns,
tighter indent steps, full path on folder hover.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An agent with the Owner role could PUT/DELETE files or apply an import over
REST with its own token and skip the proposal card. Those routes now answer
403 to agent tokens and point at write_agent_file / create_agent_file /
import_agent_files; people at the console are unaffected.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…in specs (CLEAN-112)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@maksymhryzodub-prog
maksymhryzodub-prog merged commit 40eaf56 into main Sep 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant