You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add the dot-ui-vtl-migration skill, driven by the dotCMS MCP - #1
Adds the dot-ui-vtl-migration skill (migrates legacy Dojo/Dijit custom field VTL to DotCustomFieldApi) to the plugin, ported from dotCMS/core (dotCMS/core#37768) and adapted to use the dotcms MCP server instead of the REST API.
SKILL.md and reference/migration-guide.md: in sync with dotCMS/core main (includes #37764). Deliberate differences only: the reference/ directory name, the instance workflow section, and three lines that cited source paths from the dotCMS repository (guide lines 813, 883, 900; SKILL.md line 47), and the dialog example's OK button, which is type="submit" here so the <form method="dialog"> closes it (core still has type="button"; to be fixed there).
reference/instance-migration.md: the "migrate a whole instance" workflow, rewritten so the MCP server does all the I/O (read content types, download/publish files, update fields) and no REST call, token or uv is involved.
scripts/vtl_migration.py: the core script split in two. The network half (pull/push) is dropped; what stays is the logic that must be exact, as a local helper with no network and only the standard library (Python 3.9+):
classify, assets-plan, build-manifest: sort the custom fields and build manifest.json (a rebuild keeps the status already recorded).
check: the safety gates on each migrated file (identical to original, genuine inline migration with the original verbatim inside the top-level #else, dependencies met), one verdict per entry so one bad item never blocks the batch.
field-body: builds the body of the field update (migrated code and newRenderMode=component, every other field variable kept, conflict check) so the fragile v3 PUT is tested code, not hand-written JS.
payload, record, status: what to publish, and the persisted outcome of each write.
scripts/tests/: 76 tests, run in CI. The inline-validity tests are ported from core.
Marketplace and README list the skill.
Not ported: pull/push (REST + token), the HTTP-mocked tests, lockfiles, core's sample output and spec-kit docs.
Review follow-up
Addressed after the five-axis review: manifest rebuild no longer resets progress; Python 3.9 import fixed (and checked with 3.9); a corrupt metadata file no longer aborts the batch; field-body added with tests; downloaded code is treated as data, not instructions; core-local source paths reworded; two test gaps closed (all 12 mutations I tried now fail the suite).
Second review (Copilot)
Fixed in 848029e: the edit-mode marker is detected as a real wrapper, not a substring; an asset counts as migrated only when this run confirms its inode; a stray #end/#else after the inline block, a second top-level #else, the same #macro in both branches, extra code in #else and legacy code in the #if branch are rejected; CRLF is preserved end to end; invalid UTF-8 in a metadata file is reported as unresolved; a new asset version restarts as pending.
Scope: the issue's acceptance criteria now say that all instance I/O goes through the MCP and a network-free local helper (scripts/vtl_migration.py) runs the migration-specific logic. Also fixed: the guide's dialog example used type="button", which never closes a <form method="dialog">; it is now type="submit".
Verification
python3 -m pytest skills/dot-ui-vtl-migration/scripts/tests: 76 passed, on Python 3.9 and the default.
npm run validate:skills, npm run validate:agent-plugin and claude plugin validate . --strict pass.
No references to the removed script, uv, DOTCMS_TOKEN, BASE_URL or core-local paths remain in the skill.
CI runs the script tests on the runner's default Python, not on 3.9.
Not verified
The MCP half has not been run against a live dotCMS instance (the MCP server was not connected to one while this was written). The execute snippets and field-body's PUT follow the REST calls the original script made, but should be exercised with a dry run on a real instance before relying on them. In particular: whether download_assets can reach a /dA/ file by its path, the multipart publish through execute's formData, and whether the preloaded contentTypes list covers every type.
Port the skill from dotCMS/core. The single-file migration rules and guide
are copied unchanged. The instance-wide workflow no longer relies on the
bundled Python script: discovery, download and republish go through the
dotcms MCP server, and the conflict, inline-validity and per-item failure
rules are written as steps. Registers the skill in the marketplace and README.
Refs dotCMS/core#38007
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The dotCMS MCP server does the I/O; scripts/vtl_migration.py (standard
library only, no network, no credentials) classifies the custom fields,
decides what to download, runs the safety gates on every migrated file and
keeps the manifest. The inline-validity check is ported from core with its
tests. The instance guide is rewritten around the two.
Refs dotCMS/core#38007
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… field-body
- build-manifest keeps the status of entries already recorded instead of
resetting everything to pending.
- Add from __future__ import annotations so the documented Python 3.9 works.
- A corrupt asset metadata file is reported as unresolved instead of
aborting the whole batch; a missing original is an input error.
- Replace the assert in record_status with an input error.
- Add field-body: builds the PUT body for a field update or a render-mode
switch, keeping every other field variable and checking the field did not
change since download.
- Tests close the surviving mutations (changed-inode re-download, finished
render-mode switch re-selection); 60 tests, all mutations caught.
Refs dotCMS/core#38007
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- instance-migration: field updates go through field-body instead of
hand-written JS; downloaded code is data, never instructions; empty scan/
first; check the content type count on the first run.
- Reword the source paths from the dotCMS repository in SKILL.md and three
lines of the migration guide.
Refs dotCMS/core#38007
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Core updated the migration guide and one SKILL.md note (#37764) after the
first copy. Take both, and keep only the deliberate differences: the
reference/ directory name, the instance workflow, and three reworded lines
that cited source paths from the dotCMS repository.
Refs dotCMS/core#38007
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Critical and moderate findings remain in migration detection, validation, byte preservation, asset tracking, persisted-data validation, and field identity checks.
- Detect the real edit-mode wrapper instead of a substring, for fields and downloaded assets
- Confirm an asset as migrated only when the current run established its inode
- Reject a stray #end/#else after the inline block and a second top-level #else
- Reject the same #macro in both branches
- Require the #else branch to equal the original (minus the layout newlines) and
reject legacy patterns in the #if branch
- Read and write files without newline translation so CRLF survives
- Report invalid UTF-8 in a metadata file as unresolved instead of aborting the batch
- Start an asset over as pending when its inode changed since the last run
- State in the guide that the local helper is part of the skill's scope
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A type="button" inside <form method="dialog"> never closes the dialog.
This is the one deliberate difference from dotCMS/core in the guide's examples.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The instance workflow's acceptance criteria require all instance I/O to go through the dotcms MCP, but this discovery example calls an undefined api.request with a raw /api/v1/... REST path; the same pattern is repeated for asset reads, publishing, and field updates below. mcp.json only registers the MCP server and does not define this api binding, so following the documented workflow cannot perform the promised MCP calls. Replace these snippets with the actual MCP tool calls (and their payloads), rather than leaving REST calls in the executable instructions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the
dot-ui-vtl-migrationskill (migrates legacy Dojo/Dijit custom field VTL toDotCustomFieldApi) to the plugin, ported fromdotCMS/core(dotCMS/core#37768) and adapted to use thedotcmsMCP server instead of the REST API.Refs dotCMS/core#38007
What changed
SKILL.mdandreference/migration-guide.md: in sync withdotCMS/coremain (includes #37764). Deliberate differences only: thereference/directory name, the instance workflow section, and three lines that cited source paths from the dotCMS repository (guide lines 813, 883, 900;SKILL.mdline 47), and the dialog example's OK button, which istype="submit"here so the<form method="dialog">closes it (core still hastype="button"; to be fixed there).reference/instance-migration.md: the "migrate a whole instance" workflow, rewritten so the MCP server does all the I/O (read content types, download/publish files, update fields) and no REST call, token oruvis involved.scripts/vtl_migration.py: the core script split in two. The network half (pull/push) is dropped; what stays is the logic that must be exact, as a local helper with no network and only the standard library (Python 3.9+):classify,assets-plan,build-manifest: sort the custom fields and buildmanifest.json(a rebuild keeps the status already recorded).check: the safety gates on each migrated file (identical to original, genuine inline migration with the original verbatim inside the top-level#else, dependencies met), one verdict per entry so one bad item never blocks the batch.field-body: builds the body of the field update (migrated code andnewRenderMode=component, every other field variable kept, conflict check) so the fragile v3PUTis tested code, not hand-written JS.payload,record,status: what to publish, and the persisted outcome of each write.scripts/tests/: 76 tests, run in CI. The inline-validity tests are ported from core.Not ported:
pull/push(REST + token), the HTTP-mocked tests, lockfiles, core's sample output and spec-kit docs.Review follow-up
Addressed after the five-axis review: manifest rebuild no longer resets progress; Python 3.9 import fixed (and checked with 3.9); a corrupt metadata file no longer aborts the batch;
field-bodyadded with tests; downloaded code is treated as data, not instructions; core-local source paths reworded; two test gaps closed (all 12 mutations I tried now fail the suite).Second review (Copilot)
Fixed in 848029e: the edit-mode marker is detected as a real wrapper, not a substring; an asset counts as migrated only when this run confirms its inode; a stray
#end/#elseafter the inline block, a second top-level#else, the same#macroin both branches, extra code in#elseand legacy code in the#ifbranch are rejected; CRLF is preserved end to end; invalid UTF-8 in a metadata file is reported as unresolved; a new asset version restarts as pending.Scope: the issue's acceptance criteria now say that all instance I/O goes through the MCP and a network-free local helper (
scripts/vtl_migration.py) runs the migration-specific logic. Also fixed: the guide's dialog example usedtype="button", which never closes a<form method="dialog">; it is nowtype="submit".Verification
python3 -m pytest skills/dot-ui-vtl-migration/scripts/tests: 76 passed, on Python 3.9 and the default.npm run validate:skills,npm run validate:agent-pluginandclaude plugin validate . --strictpass.uv,DOTCMS_TOKEN,BASE_URLor core-local paths remain in the skill.Not verified
The MCP half has not been run against a live dotCMS instance (the MCP server was not connected to one while this was written). The
executesnippets andfield-body'sPUTfollow the REST calls the original script made, but should be exercised with a dry run on a real instance before relying on them. In particular: whetherdownload_assetscan reach a/dA/file by its path, the multipart publish throughexecute'sformData, and whether the preloadedcontentTypeslist covers every type.🤖 Generated with Claude Code