@se-studio/contentful-cms 3.2.0 → 3.3.0
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/CHANGELOG.md +12 -0
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +2 -0
- package/dist/cli/program.js.map +1 -1
- package/dist/commands/media.d.ts +4 -0
- package/dist/commands/media.d.ts.map +1 -0
- package/dist/commands/media.js +124 -0
- package/dist/commands/media.js.map +1 -0
- package/dist/editor-pack/capabilities.d.ts.map +1 -1
- package/dist/editor-pack/capabilities.js +15 -0
- package/dist/editor-pack/capabilities.js.map +1 -1
- package/dist/generated/version.d.ts +1 -1
- package/dist/generated/version.js +1 -1
- package/dist/hosted/index.d.ts +1 -0
- package/dist/hosted/index.d.ts.map +1 -1
- package/dist/hosted/index.js +1 -0
- package/dist/hosted/index.js.map +1 -1
- package/dist/hosted/next/routes/mcp.d.ts.map +1 -1
- package/dist/hosted/next/routes/mcp.js +3 -0
- package/dist/hosted/next/routes/mcp.js.map +1 -1
- package/dist/mcp/prompts/onboarding.d.ts.map +1 -1
- package/dist/mcp/prompts/onboarding.js +11 -8
- package/dist/mcp/prompts/onboarding.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/media.d.ts +4 -0
- package/dist/mcp/tools/media.d.ts.map +1 -0
- package/dist/mcp/tools/media.js +138 -0
- package/dist/mcp/tools/media.js.map +1 -0
- package/dist/media-pipeline/actions.d.ts +30 -0
- package/dist/media-pipeline/actions.d.ts.map +1 -0
- package/dist/media-pipeline/actions.js +257 -0
- package/dist/media-pipeline/actions.js.map +1 -0
- package/dist/media-pipeline/client.d.ts +67 -0
- package/dist/media-pipeline/client.d.ts.map +1 -0
- package/dist/media-pipeline/client.js +75 -0
- package/dist/media-pipeline/client.js.map +1 -0
- package/dist/media-pipeline/config.d.ts +17 -0
- package/dist/media-pipeline/config.d.ts.map +1 -0
- package/dist/media-pipeline/config.js +52 -0
- package/dist/media-pipeline/config.js.map +1 -0
- package/dist/media-pipeline/import.d.ts +19 -0
- package/dist/media-pipeline/import.d.ts.map +1 -0
- package/dist/media-pipeline/import.js +198 -0
- package/dist/media-pipeline/import.js.map +1 -0
- package/dist/media-pipeline/index.d.ts +6 -0
- package/dist/media-pipeline/index.d.ts.map +1 -0
- package/dist/media-pipeline/index.js +6 -0
- package/dist/media-pipeline/index.js.map +1 -0
- package/dist/media-pipeline/job-store.d.ts +41 -0
- package/dist/media-pipeline/job-store.d.ts.map +1 -0
- package/dist/media-pipeline/job-store.js +172 -0
- package/dist/media-pipeline/job-store.js.map +1 -0
- package/dist/media-pipeline/limits.d.ts +14 -0
- package/dist/media-pipeline/limits.d.ts.map +1 -0
- package/dist/media-pipeline/limits.js +14 -0
- package/dist/media-pipeline/limits.js.map +1 -0
- package/dist/media-pipeline/log.d.ts +3 -0
- package/dist/media-pipeline/log.d.ts.map +1 -0
- package/dist/media-pipeline/log.js +12 -0
- package/dist/media-pipeline/log.js.map +1 -0
- package/dist/media-pipeline/validate.d.ts +18 -0
- package/dist/media-pipeline/validate.d.ts.map +1 -0
- package/dist/media-pipeline/validate.js +38 -0
- package/dist/media-pipeline/validate.js.map +1 -0
- package/dist/runtime/context.d.ts +5 -0
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/context.js.map +1 -1
- package/docs/editor-tasks/create-from-document.md +12 -3
- package/docs/editor-tasks/media-pipeline-prepare.md +124 -0
- package/docs/editor-tasks/media-reuse-and-upload.md +12 -3
- package/docs/editor-tasks/source-readiness-review.md +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { MEDIA_TTL_HOURS_MAX, MEDIA_TTL_HOURS_MIN } from './limits.js';
|
|
2
|
+
const DRIVE_FOLDER_RE = /^https:\/\/drive\.google\.com\/drive\/(?:u\/\d+\/)?folders\/([a-zA-Z0-9_-]+)(?:[/?#].*)?$/;
|
|
3
|
+
export function parseDriveFolderUrl(url) {
|
|
4
|
+
const trimmed = url.trim();
|
|
5
|
+
const match = DRIVE_FOLDER_RE.exec(trimmed);
|
|
6
|
+
if (!match) {
|
|
7
|
+
return {
|
|
8
|
+
ok: false,
|
|
9
|
+
error: 'driveFolderUrl must be a Google Drive folder URL (https://drive.google.com/drive/folders/…).',
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
ok: true,
|
|
14
|
+
folderId: match[1],
|
|
15
|
+
url: `https://drive.google.com/drive/folders/${match[1]}`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function clampTtlHours(value, defaultTtl) {
|
|
19
|
+
const raw = value ?? defaultTtl;
|
|
20
|
+
if (!Number.isFinite(raw)) {
|
|
21
|
+
return defaultTtl;
|
|
22
|
+
}
|
|
23
|
+
return Math.min(MEDIA_TTL_HOURS_MAX, Math.max(MEDIA_TTL_HOURS_MIN, Math.floor(raw)));
|
|
24
|
+
}
|
|
25
|
+
export function assertAllowedProfile(profile, allowed) {
|
|
26
|
+
if (!allowed.includes(profile)) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
error: `Profile "${profile}" is not allowed on this host. Allowed: ${allowed.join(', ')}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return { ok: true };
|
|
33
|
+
}
|
|
34
|
+
/** Job ids from media-pipeline are URL-safe tokens; keep validation loose but bounded. */
|
|
35
|
+
export function isPlausibleJobId(jobId) {
|
|
36
|
+
return /^[a-zA-Z0-9_-]{8,128}$/.test(jobId.trim());
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/media-pipeline/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,eAAe,GACnB,2FAA2F,CAAC;AAE9F,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAM7C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EACH,8FAA8F;SACjG,CAAC;IACJ,CAAC;IACD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAE;QACnB,GAAG,EAAE,0CAA0C,KAAK,CAAC,CAAC,CAAE,EAAE;KAC3D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAyB,EAAE,UAAkB;IACzE,MAAM,GAAG,GAAG,KAAK,IAAI,UAAU,CAAC;IAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,OAAiB;IAEjB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,YAAY,OAAO,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SAC1F,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import type { CmsEditConfig } from '../config/types.js';
|
|
3
3
|
import type { IndexCacheStore } from '../index/cache-store.js';
|
|
4
|
+
import type { MediaPipelineJobStore } from '../media-pipeline/job-store.js';
|
|
4
5
|
import type { SessionStore } from '../session/session-store.js';
|
|
5
6
|
import type { StagedUploadStore } from '../staged-upload/store.js';
|
|
6
7
|
export interface ContentfulUserIdentity {
|
|
@@ -18,6 +19,10 @@ export interface CmsEditRuntimeContext {
|
|
|
18
19
|
user?: ContentfulUserIdentity;
|
|
19
20
|
/** Staged file uploads for hosted asset upload (Redis). */
|
|
20
21
|
stagedUploadStore?: StagedUploadStore;
|
|
22
|
+
/** Media pipeline job ownership + rate limits (Redis on hosted). */
|
|
23
|
+
mediaPipelineJobStore?: MediaPipelineJobStore;
|
|
24
|
+
/** Hosted project key (e.g. se2026) for media job bindings / logs. */
|
|
25
|
+
projectKey?: string;
|
|
21
26
|
}
|
|
22
27
|
export declare const cmsEditContext: AsyncLocalStorage<CmsEditRuntimeContext>;
|
|
23
28
|
export declare function getRuntimeContext(): CmsEditRuntimeContext | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,qEAAqE;IACrE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,gEAAgE;IAChE,IAAI,CAAC,EAAE,sBAAsB,CAAC;IAC9B,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,qEAAqE;IACrE,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,2EAA2E;IAC3E,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,gEAAgE;IAChE,IAAI,CAAC,EAAE,sBAAsB,CAAC;IAC9B,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,0CAAiD,CAAC;AAE7E,wBAAgB,iBAAiB,IAAI,qBAAqB,GAAG,SAAS,CAErE;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,qBAAqB,EAC9B,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AA6BrD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,iBAAiB,EAAyB,CAAC;AAE7E,MAAM,UAAU,iBAAiB;IAC/B,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,OAA8B,EAC9B,EAAwB;IAExB,OAAO,cAAc,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -27,14 +27,21 @@
|
|
|
27
27
|
3. On **NO-GO**, stop. On **GO** / **GO-WITH-GAPS**, keep the soft-proof as the build plan.
|
|
28
28
|
4. **Do not rewrite source copy.** Structure and place only.
|
|
29
29
|
|
|
30
|
-
### Phase 1 —
|
|
30
|
+
### Phase 1 — Media pack (when the package has Drive/binary masters)
|
|
31
|
+
|
|
32
|
+
1. If the package includes a **folder of images/videos** (typical case study): run **`task-media-pipeline-prepare`** **before** building blocks.
|
|
33
|
+
2. Prefer pipeline **ready public URLs** + reuse-first import over mid-build staged upload of oversized masters.
|
|
34
|
+
3. Keep the `sourceName → assetId` map for Phase 2 field linking.
|
|
35
|
+
4. Skip this phase only when every needed visual is already in the Contentful library (confirmed via `asset search`).
|
|
36
|
+
|
|
37
|
+
### Phase 2 — Plan and create
|
|
31
38
|
|
|
32
39
|
1. Read `cms-edit://customer/tasks-index` and relevant playbooks (`articles` / `pages`).
|
|
33
40
|
2. Map soft-proof beats to **registered** component types only — prefer **source order** over CMS convenience (do not invent side-by-side pairs unless the source is a true pair).
|
|
34
|
-
3. **Propose plan** (can reuse the soft-proof): slug, title, template/article type, ordered component list, gap/placeholder list — **ask user to confirm** with a light **yes** if not already confirmed.
|
|
41
|
+
3. **Propose plan** (can reuse the soft-proof): slug, title, template/article type, ordered component list, gap/placeholder list, **asset map** — **ask user to confirm** with a light **yes** if not already confirmed.
|
|
35
42
|
4. For pages: `list --type template` — pick template; check template `preContent` / `postContent` so heroes are not duplicated.
|
|
36
43
|
5. For articles: resolve `articleType`; apply site SEO and lab rules from `articles` playbook.
|
|
37
|
-
6. Build `create from-json` payload **or** prefer incremental `open` → `add` / `set` / `rtf` for large multi-block work.
|
|
44
|
+
6. Build `create from-json` payload **or** prefer incremental `open` → `add` / `set` / `rtf` for large multi-block work. Link visuals using the pack map from Phase 1.
|
|
38
45
|
7. `cms_edit ["create", "from-json", "--json", "<compact-json>", "--dry-run", "--strict"]` when using JSON (or `--json-base64` for large payloads).
|
|
39
46
|
8. On approval, create and `save`.
|
|
40
47
|
9. `cms_edit ["preview", "urls", "<slug>"]` — follow **`task-preview-verify`** (including multi-block soft-proof QA when relevant).
|
|
@@ -54,6 +61,7 @@ Use MCP prompts `cms_edit_create_from_doc` or `cms_edit_create_article_from_doc`
|
|
|
54
61
|
- Publish
|
|
55
62
|
- **Rewriting source copy** (flag only)
|
|
56
63
|
- Asset upload without reuse check (see **Media** capability)
|
|
64
|
+
- Mid-article ffmpeg / Drive size thrash — use **`task-media-pipeline-prepare`** first
|
|
57
65
|
- Inventing layout, section titles, or pair collections absent from the source
|
|
58
66
|
|
|
59
67
|
## Related resources
|
|
@@ -61,6 +69,7 @@ Use MCP prompts `cms_edit_create_from_doc` or `cms_edit_create_article_from_doc`
|
|
|
61
69
|
- `cms-edit://customer/components-index`
|
|
62
70
|
- `cms-edit://customer/articles` / `pages`
|
|
63
71
|
- `task-source-readiness-review`
|
|
72
|
+
- `task-media-pipeline-prepare`
|
|
64
73
|
- `task-create-article`
|
|
65
74
|
- `task-create-page`
|
|
66
75
|
- `task-media-reuse-and-upload`
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Capability: Media pipeline — prepare pack
|
|
2
|
+
|
|
3
|
+
Normalize a **folder of designer masters** into short-lived **public HTTPS URLs** under cms-edit upload limits, then import into Contentful with reuse-first.
|
|
4
|
+
|
|
5
|
+
**Never** expect the media pipeline service to write Contentful. Pipeline → ready URLs only. **cms-edit** owns assets/entries.
|
|
6
|
+
|
|
7
|
+
## Intent phrases
|
|
8
|
+
|
|
9
|
+
- process media folder
|
|
10
|
+
- prepare Drive assets for CMS
|
|
11
|
+
- media pipeline pack
|
|
12
|
+
- normalize oversized images/videos
|
|
13
|
+
- process case study assets
|
|
14
|
+
- upload from media pipeline
|
|
15
|
+
|
|
16
|
+
## Requires capabilities
|
|
17
|
+
|
|
18
|
+
`assetSearch` and `assetUpload`
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- Hosted cms-edit with media pipeline **configured on the host** (ops env):
|
|
23
|
+
- `MEDIA_PIPELINE_BASE_URL`
|
|
24
|
+
- `MEDIA_PIPELINE_SERVICE_KEY` (server-only — **never ask the agent/user for this**)
|
|
25
|
+
- `MEDIA_PIPELINE_TENANT` (e.g. `se`, not the cms-edit projectKey)
|
|
26
|
+
- Drive folder shared **Viewer** with pipeline service account
|
|
27
|
+
`media-pipeline-reader@se-media-pipeline.iam.gserviceaccount.com`
|
|
28
|
+
(or “anyone with the link” if using API-key Drive mode on the pipeline)
|
|
29
|
+
- Profile default: `case-study-v1`
|
|
30
|
+
|
|
31
|
+
## When to use
|
|
32
|
+
|
|
33
|
+
| Situation | Action |
|
|
34
|
+
|-----------|--------|
|
|
35
|
+
| Drive/Figma package with large JPEGs/videos | **This task first**, then structure build |
|
|
36
|
+
| Single small image already in library | `task-media-reuse-and-upload` only |
|
|
37
|
+
| Masters already under limits and catalogued | Reuse search only |
|
|
38
|
+
|
|
39
|
+
## Steps (agent — single auth)
|
|
40
|
+
|
|
41
|
+
### 1. Prepare
|
|
42
|
+
|
|
43
|
+
Call MCP tool **`cms_edit_media`**:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"action": "prepare",
|
|
48
|
+
"driveFolderUrl": "https://drive.google.com/drive/folders/…",
|
|
49
|
+
"profile": "case-study-v1"
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
CLI: `cms-edit media prepare --drive-folder "https://drive.google.com/drive/folders/…"`
|
|
54
|
+
|
|
55
|
+
Expect `{ ok: true, jobId, status: "queued", pollHint }`.
|
|
56
|
+
|
|
57
|
+
If `{ ok: false, code: "pipeline_unconfigured" }` → host ops must set env vars. **Do not** ask the user for a pipeline API key.
|
|
58
|
+
|
|
59
|
+
### 2. Wait / status
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{ "action": "wait", "jobId": "<jobId>" }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
or
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{ "action": "status", "jobId": "<jobId>" }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Statuses: `queued` → `running` → `succeeded` | `partial` | `failed`.
|
|
72
|
+
|
|
73
|
+
- **succeeded** — all files ready
|
|
74
|
+
- **partial** — some ready; `gaps[]` lists failures
|
|
75
|
+
- **failed** — nothing usable; stop and report gaps
|
|
76
|
+
|
|
77
|
+
**Do not** invent assets for gaps.
|
|
78
|
+
|
|
79
|
+
### 3. Catalog
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{ "action": "catalog", "jobId": "<jobId>" }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Each asset includes:
|
|
86
|
+
|
|
87
|
+
| Field | Use |
|
|
88
|
+
|-------|-----|
|
|
89
|
+
| `readyUrl` | `asset upload --url` into Contentful |
|
|
90
|
+
| `previewUrl` / `posterUrl` | Agent vision for **title / fileName / alt** (when present) |
|
|
91
|
+
| `altDraft` / `titleDraft` | Filename seeds only — improve before save |
|
|
92
|
+
|
|
93
|
+
### 4. Import into Contentful (reuse-first)
|
|
94
|
+
|
|
95
|
+
After drafting titles/alts from **previewUrl** / **posterUrl**:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"action": "import",
|
|
100
|
+
"jobId": "<jobId>",
|
|
101
|
+
"withMedia": true,
|
|
102
|
+
"overrides": [
|
|
103
|
+
{ "sourceName": "OM1_Hero.jpg", "title": "OM1 hero", "alt": "…" }
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Optional: `"dryRun": true` to preview the map without writing.
|
|
109
|
+
|
|
110
|
+
CLI: `cms-edit media import --job <id> [--dry-run] [--with-media] [--overrides-json '[…]']`
|
|
111
|
+
|
|
112
|
+
Import:
|
|
113
|
+
|
|
114
|
+
1. Searches existing assets by fileName
|
|
115
|
+
2. Else uploads from `readyUrl` as the authenticated Contentful user
|
|
116
|
+
3. Returns `map: { sourceName → { assetId, mediaId?, … } }` for page build
|
|
117
|
+
|
|
118
|
+
Manual `asset upload --url` remains available for one-offs.
|
|
119
|
+
|
|
120
|
+
### Hardening notes (for agents)
|
|
121
|
+
|
|
122
|
+
- Jobs are **owned by the OAuth user** who prepared them — you cannot poll another user’s `jobId`.
|
|
123
|
+
- Rate limits apply (prepares/hour, concurrent jobs).
|
|
124
|
+
- Never document or request `MEDIA_PIPELINE_API_KEY` in chat.
|
|
@@ -28,9 +28,16 @@
|
|
|
28
28
|
|
|
29
29
|
## Upload only when no match
|
|
30
30
|
|
|
31
|
+
### Oversized masters / whole Drive folders
|
|
32
|
+
|
|
33
|
+
If files are near or over **4 MB** (hosted staged) or **10 MB** (URL/local), or the user shared a **Drive folder of masters**, do **not** improvise compression in chat.
|
|
34
|
+
|
|
35
|
+
1. Run **`task-media-pipeline-prepare`** (Drive folder → ready public URLs under limits)
|
|
36
|
+
2. Return here and import with **`--url`** + reuse-first filename search
|
|
37
|
+
|
|
31
38
|
### Hosted MCP (default)
|
|
32
39
|
|
|
33
|
-
**Always use staged upload** for
|
|
40
|
+
**Always use staged upload** for ad-hoc small binaries. Do not pass base64 in `cms_edit` args — hosted MCP rejects `asset upload --base64`.
|
|
34
41
|
|
|
35
42
|
1. `cms_edit_request_staged_upload` with `fileName`, `mimeType`, optional `byteLength`, optional `title`
|
|
36
43
|
2. Run the returned `curlCommand` in a shell (POST file to `uploadUrl`)
|
|
@@ -57,10 +64,10 @@ To rename an existing Media wrapper: `cms_edit ["batch", "set", "<media-entry-id
|
|
|
57
64
|
|
|
58
65
|
Avoid `asset upload --with-media` when multiple entries will share the same image (e.g. news composites) — it creates duplicate Media entries. Upload the asset only, then one shared `create media`, then link the media ID on each entry.
|
|
59
66
|
|
|
60
|
-
**
|
|
67
|
+
**Prefer `--url`** when the file is already on **public HTTPS** under size limits — especially **media-pipeline ready pack URLs**:
|
|
61
68
|
|
|
62
69
|
```
|
|
63
|
-
cms_edit ["asset", "upload", "--url", "https://<public-https-url>/file.png", "--mime", "image/png", "--file-name", "headshot-name-1200.png", "--title", "…"]
|
|
70
|
+
cms_edit ["asset", "upload", "--url", "https://<public-https-url>/file.png", "--mime", "image/png", "--file-name", "headshot-name-1200.png", "--title", "…", "--if-exists-by-filename"]
|
|
64
71
|
```
|
|
65
72
|
|
|
66
73
|
The URL must be fetchable by the hosted MCP server. Do not use local-only URLs.
|
|
@@ -99,5 +106,7 @@ Always `diff` → `save`. Verify with `preview urls` on the public path.
|
|
|
99
106
|
|
|
100
107
|
## Related resources
|
|
101
108
|
|
|
109
|
+
- `task-media-pipeline-prepare`
|
|
110
|
+
|
|
102
111
|
- `cms-edit://customer/defaults` (featured image rules)
|
|
103
112
|
- `cms-edit://customer/people` (person `media` field, when present)
|