@typeroll/mcp-server 0.45.76 → 0.45.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -2
- package/README.md +18 -0
- package/dist/bundled-content.js +35 -10
- package/dist/init.js +1 -1
- package/dist/tools/deploy.js +2 -1
- package/dist/tools/media.js +1 -1
- package/dist/tools/migration.js +4 -2
- package/dist/tools/pages.js +1 -1
- package/dist/tools/preview.js +1 -1
- package/dist/tools/working-copy.js +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace.js +34 -10
- package/package.json +3 -2
- package/skills/tr-header-footer.md +95 -41
- package/skills/tr-import-url.md +6 -6
- package/skills/tr-migrate-astro.md +3 -3
- package/skills/tr-migrate-multisite.md +4 -4
- package/skills/tr-migrate-wp.md +28 -12
- package/skills/tr-migration-evidence.md +35 -23
- package/skills/tr-new-site.md +5 -7
- package/workspace-templates/brief/interview.md +18 -0
- package/workspace-templates/brief/migration.md +42 -0
- package/workspace-templates/qa/checklist.md +35 -0
- package/workspace-templates/qa/typeroll-platform-feedback.md +11 -0
- package/workspace-templates/scripts/README.md +85 -0
- package/workspace-templates/scripts/typeroll/browser.cjs +50 -0
- package/workspace-templates/scripts/typeroll/call.py +12 -0
- package/workspace-templates/scripts/typeroll/capture_text.cjs +17 -0
- package/workspace-templates/scripts/typeroll/card-stacking-check.cjs +27 -0
- package/workspace-templates/scripts/typeroll/check_assets.py +72 -0
- package/workspace-templates/scripts/typeroll/check_unsaved.py +13 -0
- package/workspace-templates/scripts/typeroll/check_url_parity.py +74 -0
- package/workspace-templates/scripts/typeroll/compare_text.py +59 -0
- package/workspace-templates/scripts/typeroll/contact_sheet.py +20 -0
- package/workspace-templates/scripts/typeroll/layout_trace.cjs +33 -0
- package/workspace-templates/scripts/typeroll/shoot_hosted.cjs +26 -0
- package/workspace-templates/scripts/typeroll/shootframe.cjs +16 -0
- package/workspace-templates/scripts/typeroll/sweep_blocks.example.py +23 -0
- package/workspace-templates/scripts/typeroll/trlib.py +212 -0
- package/workspace-templates/workflows/design.md +30 -0
- package/workspace-templates/workflows/interview.md +72 -0
- package/workspace-templates/workflows/migration.md +84 -0
- package/workspace-templates/workflows/new-site.md +17 -0
package/dist/init.js
CHANGED
|
@@ -48,7 +48,7 @@ export async function runInitCli(args) {
|
|
|
48
48
|
try {
|
|
49
49
|
const result = await runInit({ dir, update, recipes, client });
|
|
50
50
|
console.log(JSON.stringify(result, null, 2));
|
|
51
|
-
console.log('Next:
|
|
51
|
+
console.log('Next: read AGENTS.md. For guidance, start/resume workflows/interview.md; otherwise use workflows/new-site.md or workflows/migration.md. Record decisions in brief/, connect hosted MCP at https://app.typeroll.com/api/mcp?tools=compact, create/select your Site, record its IDs/Version in typeroll.json, then run typeroll doctor. Local MCP uses an injected TYPEROLL_API_KEY; no key is stored by init. See README.md.');
|
|
52
52
|
return 0;
|
|
53
53
|
}
|
|
54
54
|
catch {
|
package/dist/tools/deploy.js
CHANGED
|
@@ -15,6 +15,7 @@ export const deployTools = [
|
|
|
15
15
|
description: "Enqueue a deploy (static-page build → hosting) of the currently active version. Returns a job_id immediately; poll get_deploy_status until the status leaves queued/running. NOT for previewing iterative design/content edits — that's what get_preview_link is for (it renders live from the DB with no build). Reserve trigger_deploy for publishing, a stakeholder link to the compiled site, or pre-merge validation. Deploys build SAVED content only — unsaved drafts (working copies) are excluded, so commit_working_copy (or save:true on your writes) before deploying, or your changes won't ship. Customer publishing freezes a consistent saved source, then resumes source/Git/build-dispatch checkpoints without recapturing later edits. GitHub or Cloudflare performs rendering and media work. With dry_run:true, customer publishing validates frozen source without a Git push or external build; it does not prove an Astro build succeeds. Other self-hosted adapters may build locally without upload. Check the reported phase.",
|
|
16
16
|
inputSchema: {
|
|
17
17
|
environment: z.enum(['production', 'staging']).optional(),
|
|
18
|
+
allow_unsaved: z.boolean().optional().describe('Explicitly publish saved content while leaving the reported unsaved Pages/partials untouched. Only after owner confirmation.'),
|
|
18
19
|
dry_run: z.boolean().optional().describe('Validate without publishing. Customer publishing checks frozen source only; other adapters may build locally without upload.'),
|
|
19
20
|
version: versionParam,
|
|
20
21
|
},
|
|
@@ -40,7 +41,7 @@ export const deployTools = [
|
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
43
|
name: 'get_deploy_status',
|
|
43
|
-
description: "Status of a single deploy job. Returns { job, queued_for_seconds, queue_timeout_seconds }. job.status is one of queued | running | succeeded | failed. On a failed build, job.error names the failed step and the cause the step printed, job.failure.code is the reported code (e.g. media_build_process_exit_1) and job.failure.diagnostic holds { cause, lines } (the last 40 lines that step printed, credentials removed). On the Cloudflare build engine job.failure.provider_log also holds { step, build_id, summary, lines } from the provider's build log (last 60 lines). Read them before retrying; retrying does not fix a cause that is in the content or the build engine. Polling cadence: ~5s for queued/running. job.render_report, when present, reports actual HTML mode (full/partial), rendered, reused, total and removed route counts plus a fallback reason. From Core 0.2.17, custom blocks and consumed image metadata are tracked per route; older caches require one full build. It does not measure media or provider startup savings. job.coordinator, when present, reports the last completed CMS phase and duration_ms for that attempt; external build waiting is excluded. Keep observing the same job across checkpoints; do not trigger duplicate deploys. A job stuck in 'queued' for longer than queue_timeout_seconds (default 300s) auto-flips to failed with phase='queue_timeout' — so a single poll past that timestamp returns the terminal state and you can stop polling.",
|
|
44
|
+
description: "Status of a single deploy job. Optional top-level build_progress reports the exact task status, attempt, step and completed/total files; not an overall percentage or ETA. Returns { job, queued_for_seconds, queue_timeout_seconds }. job.status is one of queued | running | succeeded | failed. On a failed build, job.error names the failed step and the cause the step printed, job.failure.code is the reported code (e.g. media_build_process_exit_1) and job.failure.diagnostic holds { cause, lines } (the last 40 lines that step printed, credentials removed). On the Cloudflare build engine job.failure.provider_log also holds { step, build_id, summary, lines } from the provider's build log (last 60 lines). Read them before retrying; retrying does not fix a cause that is in the content or the build engine. Polling cadence: ~5s for queued/running. job.render_report, when present, reports actual HTML mode (full/partial), rendered, reused, total and removed route counts plus a fallback reason. From Core 0.2.17, custom blocks and consumed image metadata are tracked per route; older caches require one full build. It does not measure media or provider startup savings. job.coordinator, when present, reports the last completed CMS phase and duration_ms for that attempt; external build waiting is excluded. Keep observing the same job across checkpoints; do not trigger duplicate deploys. A job stuck in 'queued' for longer than queue_timeout_seconds (default 300s) auto-flips to failed with phase='queue_timeout' — so a single poll past that timestamp returns the terminal state and you can stop polling.",
|
|
44
45
|
inputSchema: { job_id: z.string(), include_provider: z.boolean().optional().describe('Also read the exact Git commit and Cloudflare build stages for a customer Git publication. Does not return build secrets.') },
|
|
45
46
|
handler: withErrorBoundary(async (args, { client, siteId }) => {
|
|
46
47
|
const res = await client.get(siteId, `deploys/${encodeURIComponent(args.job_id)}`);
|
package/dist/tools/media.js
CHANGED
|
@@ -206,7 +206,7 @@ export const mediaTools = [
|
|
|
206
206
|
},
|
|
207
207
|
{
|
|
208
208
|
name: 'finalize_media',
|
|
209
|
-
description: 'Post-upload finalize for a single image: (1) applies immutable Cache-Control (public, max-age=31536000) to the R2 original via in-place CopyObject so the CDN caches it for a year, and (2) generates AVIF/WebP responsive variants if not already present. Call this immediately after a successful upload (the presigned PUT does NOT set cache headers — without finalize, Cloudflare defaults to ~4h and every visit re-fetches the original). Idempotent: safe to call twice. Skips variant work when variants already exist on the doc. INTEGRITY: the result
|
|
209
|
+
description: 'Post-upload finalize for a single image: (1) applies immutable Cache-Control (public, max-age=31536000) to the R2 original via in-place CopyObject so the CDN caches it for a year, and (2) generates AVIF/WebP responsive variants if not already present. Call this immediately after a successful upload (the presigned PUT does NOT set cache headers — without finalize, Cloudflare defaults to ~4h and every visit re-fetches the original). Idempotent: safe to call twice. Skips variant work when variants already exist on the doc. INTEGRITY: the response is { ok, result: { sha256, size_bytes, ... } }; read result.sha256 and result.size_bytes for the stored original — compare against your source file to catch transit corruption before referencing the asset. Better: pass expected_sha256 (hash the file yourself first, e.g. `shasum -a 256 file`) and the server rejects a mismatch with a 422 so corrupted bytes never get blessed with immutable cache headers. Truncated SVGs are rejected outright.',
|
|
210
210
|
inputSchema: {
|
|
211
211
|
media_id: z.string(),
|
|
212
212
|
expected_sha256: z.string().regex(/^[0-9a-fA-F]{64}$/).optional()
|
package/dist/tools/migration.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ok, withErrorBoundary, versionParam } from './helpers.js';
|
|
3
|
-
const STATUS = z.enum(['migrated', 'redirected', 'excluded', 'unhandled']);
|
|
3
|
+
const STATUS = z.enum(['migrated', 'redirected', 'excluded', 'unhandled', 'matched_draft']);
|
|
4
4
|
const PLAIN_TEXT_REPAIR_FIELD = z.enum(['title', 'seo_title', 'seo_description', 'excerpt']);
|
|
5
5
|
export const migrationTools = [
|
|
6
6
|
{
|
|
@@ -8,6 +8,8 @@ export const migrationTools = [
|
|
|
8
8
|
description: 'Import an explicit sitemap URL into the migration URL inventory. Sitemap indexes are followed recursively; URLs outside source_origin are rejected and reported.',
|
|
9
9
|
inputSchema: {
|
|
10
10
|
url: z.string().url().describe('Absolute URL of a sitemap or sitemap index.'),
|
|
11
|
+
include_wordpress: z.boolean().optional().describe('Also enumerate public WordPress REST pages/posts/types. No helper installation required; incomplete discovery is reported.'),
|
|
12
|
+
crawl_pages: z.number().int().min(0).max(50).optional().describe('With include_wordpress, crawl up to this many source pages for same-origin legacy links. Default 0; bounded discovery is not an authoritative old-slug export.'),
|
|
11
13
|
source_origin: z.string().url().optional().describe('Expected legacy-site origin. Defaults to the sitemap origin.'),
|
|
12
14
|
},
|
|
13
15
|
handler: withErrorBoundary(async (args, { client, siteId }) => {
|
|
@@ -69,7 +71,7 @@ export const migrationTools = [
|
|
|
69
71
|
},
|
|
70
72
|
{
|
|
71
73
|
name: 'list_migration_urls',
|
|
72
|
-
description: "The legacy site's URL inventory with LIVE coverage status. Every entry is classified on read against the site's current pages + redirects: `migrated` (a Page answers at that path), `redirected` (a redirect rule covers it), `excluded` (signed off as an intentional 404), `unhandled` (nothing covers it — the work list). Returns a summary over the whole inventory plus a page of entries, sorted worst-first then by GSC clicks. Use `status: \"unhandled\"` to get exactly what's left to do before cutover. Coverage is computed, never stored, so it's current the moment you create a redirect.",
|
|
74
|
+
description: "The legacy site's URL inventory with LIVE coverage status. Every entry is classified on read against the site's current pages + redirects: `migrated` (a Page answers at that path), `redirected` (a redirect rule covers it), `excluded` (signed off as an intentional 404), `matched_draft` (a saved but unpublished Page owns the path; not launch-ready), `unhandled` (nothing covers it — the work list). Returns a summary over the whole inventory plus a page of entries, sorted worst-first then by GSC clicks. Use `status: \"unhandled\"` to get exactly what's left to do before cutover. Coverage is computed, never stored, so it's current the moment you create a redirect.",
|
|
73
75
|
inputSchema: {
|
|
74
76
|
status: STATUS.optional().describe('Only return entries with this coverage status.'),
|
|
75
77
|
limit: z.number().int().positive().max(1000).optional().describe('Default 200.'),
|
package/dist/tools/pages.js
CHANGED
|
@@ -223,7 +223,7 @@ export const pageTools = [
|
|
|
223
223
|
},
|
|
224
224
|
{
|
|
225
225
|
name: 'batch_update_pages',
|
|
226
|
-
description: 'Apply per-page patches in one call (up to 200 entries). Each entry is { page_id, patch, save?, answer_sources? }; failures are reported per-row, the rest still apply. BUFFER MODEL: content patches land in each page\'s unsaved draft; per-entry save:true (or the top-level save flag) commits — typical for a user-approved sweep. content_mode is rejected per-row; switch each page with set_page_mode.',
|
|
226
|
+
description: 'Apply per-page patches in one call (up to 200 entries). Each entry is { page_id, patch, save?, answer_sources? }; failures are reported per-row, the rest still apply. BUFFER MODEL: content patches land in each page\'s unsaved draft; per-entry save:true (or the top-level save flag) commits — typical for a user-approved sweep. Returns results with saved (whether this patch reached saved storage), staged (draft field names), and applied_immediately (status/schedule field names). A status-only patch is saved immediately and does not commit earlier drafts. content_mode is rejected per-row; switch each page with set_page_mode.',
|
|
227
227
|
inputSchema: {
|
|
228
228
|
updates: z
|
|
229
229
|
.array(z.object({
|
package/dist/tools/preview.js
CHANGED
|
@@ -17,7 +17,7 @@ export const previewTools = [
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
name: 'get_preview_link',
|
|
20
|
-
description: 'Mint a signed URL the user (or your own browser tool) can open to SEE the rendered preview. Renders LIVE from the database with NO build — this is the PREFERRED way to preview design/content changes as you iterate; reach for this, not trigger_deploy, when previewing. BUFFER MODEL: your edits are unsaved drafts, so for the iteration loop mint the link with include_working_copy:true (drafts visible); a plain link shows SAVED content only — right for stakeholders reviewing what will deploy. Mint ONCE and REUSE that single URL across edits — internal links keep the token so it navigates the whole branch, and it stays valid until the TTL lapses (24h default and max). Target a page (page_id), or a raw slug; omit all for the home page. Forms on the page can be clicked through end to end — validation, steps, success message or the named redirect target — without creating submissions or running actions ("Preview – nothing is sent"). (For a permanent public link, complete Publishing setup and wait for a verified deployment on the organization or site domain.)',
|
|
20
|
+
description: 'Returns url (normal wrapper) and frame_url (signed sandboxed frame for rendering-only QA; use the wrapper for Extension host interactions). Mint a signed URL the user (or your own browser tool) can open to SEE the rendered preview. Renders LIVE from the database with NO build — this is the PREFERRED way to preview design/content changes as you iterate; reach for this, not trigger_deploy, when previewing. BUFFER MODEL: your edits are unsaved drafts, so for the iteration loop mint the link with include_working_copy:true (drafts visible); a plain link shows SAVED content only — right for stakeholders reviewing what will deploy. Mint ONCE and REUSE that single URL across edits — internal links keep the token so it navigates the whole branch, and it stays valid until the TTL lapses (24h default and max). Target a page (page_id), or a raw slug; omit all for the home page. Forms on the page can be clicked through end to end — validation, steps, success message or the named redirect target — without creating submissions or running actions ("Preview – nothing is sent"). (For a permanent public link, complete Publishing setup and wait for a verified deployment on the organization or site domain.)',
|
|
21
21
|
inputSchema: {
|
|
22
22
|
page_id: z.string().optional(),
|
|
23
23
|
slug: z.string().optional(),
|
|
@@ -29,7 +29,7 @@ function wcPath(t) {
|
|
|
29
29
|
export const workingCopyTools = [
|
|
30
30
|
{
|
|
31
31
|
name: 'read_working_copy',
|
|
32
|
-
description: 'Read a doc\'s unsaved draft (working copy) as a raw field diff — { working_copy: null } means everything is saved. read_page/get_page_blocks already return the draft VIEW; use this when you need to know exactly WHICH fields are unsaved, e.g. before discarding (the draft may hold the user\'s in-progress editor work, not just yours).',
|
|
32
|
+
description: 'Templates save immediately and do not use this tool. Use target: {kind: page|partial, id: ...}, not page_id. Read a doc\'s unsaved draft (working copy) as a raw field diff — { working_copy: null } means everything is saved. read_page/get_page_blocks already return the draft VIEW; use this when you need to know exactly WHICH fields are unsaved, e.g. before discarding (the draft may hold the user\'s in-progress editor work, not just yours).',
|
|
33
33
|
inputSchema: {
|
|
34
34
|
target: wcTargetSchema,
|
|
35
35
|
version: versionParam,
|
package/dist/version.js
CHANGED
package/dist/workspace.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { VERSION } from './version.js';
|
|
6
|
+
import { BUNDLED_WORKSPACE_TEMPLATES } from './bundled-content.js';
|
|
6
7
|
import { ApiError, TyperollClient } from './client.js';
|
|
7
8
|
export const workspaceSchema = z.object({
|
|
8
9
|
schema_version: z.literal(1),
|
|
@@ -17,14 +18,24 @@ export const workspaceSchema = z.object({
|
|
|
17
18
|
export const defaultWorkspace = { schema_version: 1, portal: 'https://app.typeroll.com', organization_id: null, site_id: null, version: 'main', tool_mode: 'compact' };
|
|
18
19
|
const lockSchema = z.object({ schema_version: z.literal(1), generator_version: z.string(), files: z.record(z.string(), z.string().regex(/^[a-f0-9]{64}$/)) }).strict();
|
|
19
20
|
const hash = (value) => createHash('sha256').update(value).digest('hex');
|
|
20
|
-
export const ignores = ['.typeroll/', '.env', '.env.*', '!.env.example', '.mcp.json', '.cursor/mcp.json', '.vscode/mcp.json', 'qa/reports/', 'sources/private/'];
|
|
21
|
+
export const ignores = ['.typeroll/', '.env', '.env.*', '!.env.example', '.mcp.json', '.cursor/mcp.json', '.vscode/mcp.json', 'qa/reports/', 'sources/private/', '**/__pycache__/', 'scripts/typeroll/node_modules/'];
|
|
21
22
|
export const agentInstructions = `# Working on this website
|
|
22
23
|
|
|
23
|
-
Read typeroll.json, brief/ and decisions.md.
|
|
24
|
+
Read typeroll.json, brief/site.md, brief/rules.md and decisions.md first. Read
|
|
25
|
+
other brief/ files and workflows/ only when relevant. Confirm the portal, Organization,
|
|
24
26
|
Site and working Version before writes. This workspace is not the generated
|
|
25
27
|
publication repository. The CMS owns current content and configuration; local
|
|
26
28
|
sources are proposals unless the user explicitly adopts them.
|
|
27
29
|
|
|
30
|
+
## Guided start
|
|
31
|
+
|
|
32
|
+
When the owner needs guidance or a material decision is missing, start or resume
|
|
33
|
+
workflows/interview.md. Read brief/interview.md and existing answers first; ask
|
|
34
|
+
one short question at a time and save progress. Do not repeat confirmed questions
|
|
35
|
+
or treat silence as approval. For a complete brief, proceed directly to
|
|
36
|
+
workflows/new-site.md or workflows/migration.md. All kickoff prompts live here
|
|
37
|
+
in the workspace; public docs explain the flow and link to these source files.
|
|
38
|
+
|
|
28
39
|
## Discover only what the task needs
|
|
29
40
|
|
|
30
41
|
With compact MCP, search_tools then describe_tool; call_read_tool,
|
|
@@ -60,12 +71,24 @@ Public documentation: https://typeroll.com/docs/llms.txt
|
|
|
60
71
|
## Migrations
|
|
61
72
|
|
|
62
73
|
Read tr-migration-evidence, then the source-specific recipe (tr-migrate-wp,
|
|
63
|
-
tr-import-url, tr-migrate-astro or tr-migrate-multisite). Record preserve or renew
|
|
64
|
-
|
|
74
|
+
tr-import-url, tr-migrate-astro or tr-migrate-multisite). Record text_intent and design_intent separately as preserve or renew
|
|
75
|
+
in brief/migration.md; design includes images. Ask if either is unclear. Standard blocks first, reviewed
|
|
65
76
|
custom types next, documented HTML exceptions last. Preserve or meaningfully
|
|
66
77
|
redirect every old public URL. Import completion is not block reconstruction
|
|
67
|
-
or launch acceptance. Compare
|
|
68
|
-
approved design
|
|
78
|
+
or launch acceptance. Compare text and design/images separately: preserved dimensions to the source,
|
|
79
|
+
renewed dimensions to their approved brief. New design never permits rewriting preserved text. Start with workflows/migration.md for the kickoff
|
|
80
|
+
prompt. The agent rebuilds imported HTML using ordinary block tools; the owner
|
|
81
|
+
does not need to manually convert each Page. No automatic converter is available.
|
|
82
|
+
Discover tools and recipes on demand. Read scripts/README.md for version-bound
|
|
83
|
+
pre-deploy and hosted QA tools. Follow workflows/design.md for layout defaults.
|
|
84
|
+
|
|
85
|
+
## Project rules and search strategy
|
|
86
|
+
|
|
87
|
+
Record the owner's preferences and durable constraints in brief/rules.md; put
|
|
88
|
+
approved search intent, topic coverage and URL/indexing strategy in brief/seo.md.
|
|
89
|
+
These are project decisions, not CMS settings or permission to publish. If a
|
|
90
|
+
request conflicts with an agreed rule, ask and record the resulting decision.
|
|
91
|
+
Use workflows/README.md to find the relevant routine, not load every recipe.
|
|
69
92
|
|
|
70
93
|
## Everyday requests
|
|
71
94
|
|
|
@@ -82,16 +105,17 @@ Store credentials in the client's private settings or injected environment.
|
|
|
82
105
|
Run the workspace doctor after setup and after changing the binding.
|
|
83
106
|
`;
|
|
84
107
|
export const workspaceTemplates = {
|
|
108
|
+
...BUNDLED_WORKSPACE_TEMPLATES,
|
|
85
109
|
'AGENTS.md': agentInstructions,
|
|
86
|
-
'README.md': `# Website workspace\n\nKeep project intent here; edit the website through Typeroll CMS.\n\n1.
|
|
110
|
+
'README.md': `# Website workspace\n\nKeep project intent here; edit the website through Typeroll CMS.\n\n1. Read AGENTS.md. For guidance, ask your agent to start or resume workflows/interview.md. Otherwise use workflows/new-site.md or workflows/migration.md. Save confirmed goals, rules and SEO strategy in brief/; record text and design/image choices separately for migrations.\n2. Connect hosted MCP at https://app.typeroll.com/api/mcp?tools=compact.\n3. Use an Organization key to create a site, or select an existing one.\n4. Record its IDs and working version in typeroll.json. No secrets belong there.\n5. Run npx @typeroll/mcp-server doctor . (inject TYPEROLL_API_KEY privately).\n\nStart guide: https://typeroll.com/docs/getting-started/agent-workspace/\n\nUpdate the generated scaffold with npx @typeroll/mcp-server init . --update.\nEdited files are preserved and reported for manual reconciliation. Optional local\nrecipes: init . --recipes. They are reference Markdown, not automatically loaded.\n`,
|
|
87
111
|
'brief/site.md': '# Site brief\n\n## Purpose and audience\n\n## Languages and scope\n\n## Primary user journeys\n\n## Content authority and sources\n\n## Editorial constraints and forbidden internal markers\n',
|
|
88
112
|
'brief/brand.md': '# Brand\n\n## Voice and tone\n\n## Visual direction and references\n\n## Typography, colors and image policy\n\n## Desktop and mobile navigation\n\nRecord intent here; current design tokens belong in CMS settings.\n',
|
|
89
113
|
'brief/content-model.md': '# Content model\n\n## Page types and routes\n\n## Fields and references\n\n## Shared templates and partials\n\n## Taxonomy and navigation\n\nUse the current CMS schema. This document describes decisions, not a second schema store.\n',
|
|
90
|
-
'brief/
|
|
114
|
+
'brief/rules.md': "# Owner preferences and project rules\n\n## Confirmed rules\n\nRecord each rule, its scope, who approved it and the date. Separate confirmed rules from proposals.\n\n## Writing and factual accuracy\n\nVoice, terminology, prohibited claims, source requirements and legal copy that must not be rewritten.\n\n## Design and editing\n\nBrand constraints, accessibility, editable content, standard/custom blocks and documented HTML exceptions.\n\n## Operations and approval\n\nWho may approve content, publication, DNS changes and messages? Credentials stay outside this repository.\n\n## Exceptions and superseded rules\n\nLink decisions.md; do not silently override a confirmed rule. Project notes do not grant permissions beyond the user's authorization or account access.\n",
|
|
115
|
+
'brief/seo.md': "# SEO strategy\n\n## Business goals, audience, markets and languages\n\n## Search intent and topic coverage\n\nRecord research sources and dates. Distinguish evidence from assumptions; do not invent traffic or ranking forecasts.\n\n## Page roles and URL plan\n\nContent types, useful landing pages, taxonomy, internal links and routes to preserve or redirect. Avoid near-duplicate pages created only for keyword variants.\n\n## Indexing and canonical policy\n\nWhich pages should be indexable, public noindex, or private? Record deliberate canonical overrides and sitemap policy; actual values live in the CMS.\n\n## Editorial standards and structured data\n\nUnique useful copy, supported claims, descriptive titles and links, accessible image text, schema matching visible content. No fixed title length or word count is a hard SEO rule.\n\n## Measurement and review\n\nBaseline, analytics/consent decisions, measures of success and review dates. Never store credentials or private analytics exports here.\n",
|
|
116
|
+
'workflows/README.md': "# Project routines\n\nRead only the relevant routine and discover current tool schemas through MCP.\nProject files record intent; the CMS owns current content and configuration.\n\n| Task | Project context | On-demand recipe |\n| --- | --- | --- |\n| Guided start | workflows/interview.md, brief/interview.md | Ask one question at a time; resume confirmed answers |\n| New website | workflows/new-site.md, brief/site.md, brief/brand.md, brief/content-model.md | tr-new-site, tr-starter-design |\n| Migration | workflows/migration.md, brief/migration.md | tr-migration-evidence, then tr-migrate-wp or the matching source recipe |\n| Everyday editing | brief/rules.md and the relevant Page | tr-edit-site |\n| SEO | brief/seo.md and current site settings | tr-seo |\n| New reusable block | brief/brand.md and recorded editing needs | tr-custom-blocks |\n| Verification and publication | qa/checklist.md, decisions.md | Current preview/deploy tools and publishing readiness |\n\nAdd project-specific routines here with inputs, steps, acceptance evidence and approval boundaries. Do not copy the complete Typeroll manual or private app guides. Discover enabled app guidance with read_app_documentation. Load a recipe when needed so instructions stay current and context stays small.\n",
|
|
91
117
|
'decisions.md': '# Decisions\n\nRecord date, decision, reason, approved scope and alternatives when useful.\n',
|
|
92
118
|
'sources/README.md': '# Sources\n\nStore research references and copy proposals. Record source URLs and dates.\nPrivate extracts belong in ignored private/ or an approved external store.\nDo not treat local drafts as current CMS content or commit media libraries.\n',
|
|
93
|
-
'scripts/README.md': '# Project automation\n\nKeep repeatable imports and QA scripts here. Use the authenticated REST API\nfor scripted work; keep credentials outside files and inject them at runtime.\nMCP remains the interactive interface. Typeroll currently has no general site CRUD CLI.\n',
|
|
94
|
-
'qa/checklist.md': '# Verification\n\n- Confirm Site, Version and deployed/source identity.\n- Read back saved content and inspect desktop/mobile previews.\n- Exercise menus, keyboard focus, links and enabled app states.\n- Verify routes, metadata, media and publishing readiness before launch.\n- Check that structured data (FAQ, recipe, event) matches what each page shows.\n- Record tested pages, viewports, results and unresolved issues.\n- Store screenshots and private runtime reports in ignored reports/.\n- Publishing validation does not prove visual or editorial completeness.\n',
|
|
95
119
|
};
|
|
96
120
|
export async function readWorkspace(dir) {
|
|
97
121
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typeroll/mcp-server",
|
|
3
|
-
"version": "0.45.
|
|
3
|
+
"version": "0.45.79",
|
|
4
4
|
"description": "Typeroll CMS MCP server – connect AI agents to the REST API to manage content and publish static websites.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"dist",
|
|
30
30
|
"AGENTS.md",
|
|
31
31
|
"README.md",
|
|
32
|
-
"skills"
|
|
32
|
+
"skills",
|
|
33
|
+
"workspace-templates"
|
|
33
34
|
],
|
|
34
35
|
"scripts": {
|
|
35
36
|
"gen": "node scripts/embed-content.mjs",
|
|
@@ -5,11 +5,10 @@ description: Build accessible native header and footer partials with the site lo
|
|
|
5
5
|
|
|
6
6
|
# Native header and footer compositions
|
|
7
7
|
|
|
8
|
-
Use block-mode partials for new work.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
tenant HTML, CSS, or JavaScript.
|
|
8
|
+
Use block-mode partials for new work. Prefer `get_composition_starter`
|
|
9
|
+
for the current native header tree: `template/site_logo`, `core/navigation_menu`
|
|
10
|
+
and `core/navigation_links`. Use the menu's dialog/drawer rather than an inline
|
|
11
|
+
mobile expansion that moves the logo. Existing `core/navigation` remains supported.
|
|
13
12
|
|
|
14
13
|
## Preconditions
|
|
15
14
|
|
|
@@ -31,51 +30,106 @@ read it back. Localize both accessible labels and every link label.
|
|
|
31
30
|
[
|
|
32
31
|
{
|
|
33
32
|
"type": "core/section",
|
|
34
|
-
"data": {
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
33
|
+
"data": {
|
|
34
|
+
"width": "wide",
|
|
35
|
+
"padding_y": "compact"
|
|
36
|
+
},
|
|
37
|
+
"children": [
|
|
38
|
+
{
|
|
39
|
+
"type": "core/container",
|
|
40
|
+
"data": {
|
|
41
|
+
"direction": "row",
|
|
42
|
+
"wrap": "nowrap",
|
|
43
|
+
"align_main": "space-between",
|
|
44
|
+
"align_cross": "center",
|
|
45
|
+
"width": "full"
|
|
46
|
+
},
|
|
47
|
+
"children": [
|
|
48
|
+
{
|
|
49
|
+
"type": "template/site_logo",
|
|
50
|
+
"data": {
|
|
51
|
+
"height": "md",
|
|
52
|
+
"link_to_home": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "core/navigation_menu",
|
|
57
|
+
"data": {
|
|
58
|
+
"aria_label": "Main navigation",
|
|
59
|
+
"menu_label": "Open menu",
|
|
60
|
+
"close_label": "Close menu",
|
|
61
|
+
"collapse_below": "1024"
|
|
62
|
+
},
|
|
63
|
+
"slots": [
|
|
64
|
+
[
|
|
65
|
+
{
|
|
66
|
+
"type": "core/navigation_links",
|
|
67
|
+
"data": {
|
|
68
|
+
"direction": "row",
|
|
69
|
+
"links": [
|
|
70
|
+
{
|
|
71
|
+
"label": "Home",
|
|
72
|
+
"href": "/"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"label": "About",
|
|
76
|
+
"href": "/about/"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"label": "Contact",
|
|
80
|
+
"href": "/contact/"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
[
|
|
87
|
+
{
|
|
88
|
+
"type": "core/navigation_links",
|
|
89
|
+
"data": {
|
|
90
|
+
"direction": "column",
|
|
91
|
+
"links": [
|
|
92
|
+
{
|
|
93
|
+
"label": "Home",
|
|
94
|
+
"href": "/"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"label": "About",
|
|
98
|
+
"href": "/about/"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"label": "Contact",
|
|
102
|
+
"href": "/contact/"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
57
108
|
]
|
|
58
109
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
]
|
|
62
113
|
}
|
|
63
114
|
]
|
|
64
115
|
```
|
|
65
116
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
visible and
|
|
117
|
+
The first slot is desktop; the second is the optional mobile composition.
|
|
118
|
+
The default is drawer below 1024 px and inline from 1024 px. For responsive
|
|
119
|
+
link fields use matching `responsive_breakpoints` (tablet 768, laptop 1024,
|
|
120
|
+
desktop 1280, wide 1536); do not independently hide all links at the menu boundary.
|
|
121
|
+
Verify 1023/1024 px, Tab/Shift-Tab, Enter/Space, Escape returning focus,
|
|
122
|
+
visible focus, long labels, no-JavaScript links and no horizontal overflow.
|
|
72
123
|
|
|
73
124
|
## Footer tree and consent
|
|
74
125
|
|
|
75
|
-
Use
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
126
|
+
Use an accessible footer navigation landmark and `core/navigation_links`, not
|
|
127
|
+
a second header drawer. If the footer has running about text, give it a separate,
|
|
128
|
+
wider column beside a nested link grid. An equal four-column grid is rarely a
|
|
129
|
+
good fit for one dense paragraph and three short link lists. Start with
|
|
130
|
+
`core/columns` ratio `1-2`, put flow containers inside the slots, and tune the
|
|
131
|
+
gap and readable text width to the actual content. Stack on mobile. Inspect at
|
|
132
|
+
390, 1024, 1280 and 1536 px; do not copy one site's pixel values blindly.
|
|
79
133
|
|
|
80
134
|
Cookie consent is a site feature, not a footer widget. Configure it separately:
|
|
81
135
|
|
package/skills/tr-import-url.md
CHANGED
|
@@ -10,10 +10,10 @@ another MCP client) working through MCP and the public API. The portal's built-i
|
|
|
10
10
|
AI assistant has no migration tools: it does not import, convert or verify sites.
|
|
11
11
|
|
|
12
12
|
**Before import or reconstruction:** read `tr-migration-evidence` with
|
|
13
|
-
`read_skill`. Choose preserve
|
|
14
|
-
record the brief and verify one prototype per active template before bulk writes.
|
|
13
|
+
`read_skill`. Choose preserve or renew independently for text and design/images,
|
|
14
|
+
record text_intent and design_intent in the brief and verify one prototype per active template before bulk writes.
|
|
15
15
|
Use standard blocks first, reviewed custom types next, rare documented HTML last.
|
|
16
|
-
|
|
16
|
+
All four combinations must preserve or meaningfully redirect every old public URL. That
|
|
17
17
|
shared contract defines acceptance; this recipe only adds source-specific steps.
|
|
18
18
|
|
|
19
19
|
|
|
@@ -81,7 +81,7 @@ list_pages limit=5
|
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
Read existing target data to avoid overwriting work. Compare prototypes to the
|
|
84
|
-
source
|
|
84
|
+
source when design_intent is preserve, or to the agreed new design when it is renew. Review text separately. Validate
|
|
85
85
|
standard/custom blocks using `tr-migration-evidence` before mass writes.
|
|
86
86
|
|
|
87
87
|
### 3. Fetch and clean each source page
|
|
@@ -123,8 +123,8 @@ omit it. Inventory PDFs, download hrefs, srcsets and backgrounds as well.
|
|
|
123
123
|
|
|
124
124
|
**d. Adapt to the target's design.**
|
|
125
125
|
Use standard blocks first, then reusable custom types with editable fields.
|
|
126
|
-
|
|
127
|
-
and
|
|
126
|
+
Review appearance and text independently according to design_intent and text_intent;
|
|
127
|
+
compare each preserved dimension to the source and each renewed dimension to its approved brief. Raw HTML is the documented last resort.
|
|
128
128
|
|
|
129
129
|
### 4. Create pages as drafts
|
|
130
130
|
|
|
@@ -10,10 +10,10 @@ another MCP client) working through MCP and the public API. The portal's built-i
|
|
|
10
10
|
AI assistant has no migration tools: it does not import, convert or verify sites.
|
|
11
11
|
|
|
12
12
|
**Before import or reconstruction:** read `tr-migration-evidence` with
|
|
13
|
-
`read_skill`. Choose preserve
|
|
14
|
-
record the brief and verify one prototype per active template before bulk writes.
|
|
13
|
+
`read_skill`. Choose preserve or renew independently for text and design/images,
|
|
14
|
+
record text_intent and design_intent in the brief and verify one prototype per active template before bulk writes.
|
|
15
15
|
Use standard blocks first, reviewed custom types next, rare documented HTML last.
|
|
16
|
-
|
|
16
|
+
All four combinations must preserve or meaningfully redirect every old public URL. That
|
|
17
17
|
shared contract defines acceptance; this recipe only adds source-specific steps.
|
|
18
18
|
|
|
19
19
|
|
|
@@ -10,10 +10,10 @@ another MCP client) working through MCP and the public API. The portal's built-i
|
|
|
10
10
|
AI assistant has no migration tools: it does not import, convert or verify sites.
|
|
11
11
|
|
|
12
12
|
**Before import or reconstruction:** read `tr-migration-evidence` with
|
|
13
|
-
`read_skill`. Choose preserve
|
|
14
|
-
record the brief and verify one prototype per active template before bulk writes.
|
|
13
|
+
`read_skill`. Choose preserve or renew independently for text and design/images,
|
|
14
|
+
record text_intent and design_intent in the brief and verify one prototype per active template before bulk writes.
|
|
15
15
|
Use standard blocks first, reviewed custom types next, rare documented HTML last.
|
|
16
|
-
|
|
16
|
+
All four combinations must preserve or meaningfully redirect every old public URL. That
|
|
17
17
|
shared contract defines acceptance; this recipe only adds source-specific steps.
|
|
18
18
|
|
|
19
19
|
|
|
@@ -69,7 +69,7 @@ required before import; GitHub/build/domain readiness is checked separately for
|
|
|
69
69
|
publication. Do not infer that every Site shares the same blockers.
|
|
70
70
|
|
|
71
71
|
Ask explicitly:
|
|
72
|
-
- Which
|
|
72
|
+
- Which text_intent and design_intent apply per Site, each preserve or renew? Which source or approved
|
|
73
73
|
prototype is the **design reference**? Build that one properly first.
|
|
74
74
|
- Are the sites **translations of each other** (same page structure) or
|
|
75
75
|
independent? This decides whether hreflang clusters are mechanical or
|
package/skills/tr-migrate-wp.md
CHANGED
|
@@ -10,10 +10,10 @@ another MCP client) working through MCP and the public API. The portal's built-i
|
|
|
10
10
|
AI assistant has no migration tools: it does not import, convert or verify sites.
|
|
11
11
|
|
|
12
12
|
**Before import or reconstruction:** read `tr-migration-evidence` with
|
|
13
|
-
`read_skill`. Choose preserve
|
|
14
|
-
record the brief and verify one prototype per active template before bulk writes.
|
|
13
|
+
`read_skill`. Choose preserve or renew independently for text and design/images,
|
|
14
|
+
record text_intent and design_intent in the brief and verify one prototype per active template before bulk writes.
|
|
15
15
|
Use standard blocks first, reviewed custom types next, rare documented HTML last.
|
|
16
|
-
|
|
16
|
+
All four combinations must preserve or meaningfully redirect every old public URL. That
|
|
17
17
|
shared contract defines acceptance; this recipe only adds source-specific steps.
|
|
18
18
|
|
|
19
19
|
|
|
@@ -80,7 +80,7 @@ Then the ordinary preconditions:
|
|
|
80
80
|
REST API disabled" if not — common for hardened hosts).
|
|
81
81
|
- The target exists. Establish the source design baseline first, then prove
|
|
82
82
|
representative target templates using `tr-migration-evidence`. Preserve
|
|
83
|
-
appearance
|
|
83
|
+
appearance when design_intent is preserve; use the approved design brief when it is renew. Review text against its separate choice.
|
|
84
84
|
- If the target already has content, you must NOT clobber it — always
|
|
85
85
|
`list_pages` first and only write to slugs that don't already exist.
|
|
86
86
|
Pass the slug explicitly: `create_page` then refuses an address that is
|
|
@@ -148,12 +148,28 @@ place. Do not preserve them as classed raw HTML in text blocks.
|
|
|
148
148
|
|
|
149
149
|
For each source URL:
|
|
150
150
|
|
|
151
|
-
a.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
151
|
+
a. Choose access based on missing evidence, not a mandatory plugin install:
|
|
152
|
+
|
|
153
|
+
| Source requirement | Access path |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| Public Pages, posts, media and rendered builder content exposed in REST | Public paginated `/wp-json/wp/v2/pages`, `/posts`, `/media` and rendered HTML can suffice |
|
|
156
|
+
| SEO exposed in `yoast_head_json`, visible menus/backgrounds | Public REST + rendered HTML/CSS; verify actual coverage |
|
|
157
|
+
| Private/draft content, REST-hidden types, ACF/custom fields, exact menus | Authenticated helper/export when available and authorized |
|
|
158
|
+
| REST blocked by security policy | Owner-approved helper/export; do not bypass access controls |
|
|
159
|
+
| Authoritative old slugs or plugin redirects | Owner export/helper **if supported**; a public crawl only approximates them |
|
|
160
|
+
|
|
161
|
+
Do not ask the owner to install the helper when public sources cover the scope.
|
|
162
|
+
Inventory both Pages and posts (including sitemap-excluded public records),
|
|
163
|
+
crawl internal links and inspect redirects, menus and CSS background images.
|
|
164
|
+
Do not claim the helper exports a field without reading its current contract.
|
|
165
|
+
The helper is distributed through Typeroll's documented package; do not claim
|
|
166
|
+
WordPress.org availability. Listing it there is separate publication work.
|
|
167
|
+
|
|
168
|
+
b. Clean the HTML. Parse HTML and discard comments before extracting text or
|
|
169
|
+
constructing blocks (comments may contain old phone-plugin metadata). Do not
|
|
170
|
+
use regex tag removal as a text parser. Resolve relative `../` links against
|
|
171
|
+
the source URL; preserve query strings and fragments. Report missing targets
|
|
172
|
+
instead of pointing everything at the home page. Strip Elementor / Gutenberg / Breakdance class
|
|
157
173
|
soup. Drop empty `<div>` and `<span>` wrappers. Keep semantic tags,
|
|
158
174
|
tables, iframes from known hosts (YouTube / Vimeo / Calendly).
|
|
159
175
|
Remove every `<script>`: plugin and theme JavaScript is never copied.
|
|
@@ -165,10 +181,10 @@ c. Migrate referenced images with `upload_media_from_url`. The customer's
|
|
|
165
181
|
media reference only after verification. Stop and report a failed required
|
|
166
182
|
transfer; do not silently hotlink the WordPress source.
|
|
167
183
|
|
|
168
|
-
The managed importer stores cleaned HTML. Typeroll does not convert HTML into blocks, and `set_page_mode` never rewrites HTML.
|
|
184
|
+
The managed importer stores cleaned HTML. Typeroll does not convert HTML into blocks, and `set_page_mode` never rewrites HTML. You, the external agent, rebuild the imported content with ordinary block tools. The owner does not need to convert every Page manually. There is no editor conversion preview; it was removed in Core 0.2.58. Preserve the complete source before switching modes and never publish the empty intermediate Page.
|
|
169
185
|
|
|
170
186
|
d. Rebuild into editable blocks according to the selected intent. Preserve exact
|
|
171
|
-
wording
|
|
187
|
+
wording when text_intent is preserve; track approved changes when it is renew, independently of design. Map headings,
|
|
172
188
|
prose, images, buttons and layout to standard fields first, then create
|
|
173
189
|
reviewed custom types where needed. Use raw HTML only for a documented,
|
|
174
190
|
exceptional fragment. Preserve anchors and map every old URL in either mode.
|