@aotter/mantle 0.1.0-alpha.6 → 0.1.0-alpha.7
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/docs/media-uploads.md +7 -0
- package/package.json +5 -5
- package/skills/README.md +1 -0
- package/skills/media-gc/SKILL.md +79 -0
package/docs/media-uploads.md
CHANGED
|
@@ -177,3 +177,10 @@ Preserve source semantics:
|
|
|
177
177
|
- animated GIFs must stay animated;
|
|
178
178
|
- do not silently flatten, resize, or recompress user assets without
|
|
179
179
|
asking.
|
|
180
|
+
|
|
181
|
+
## Cleanup
|
|
182
|
+
|
|
183
|
+
Run the version-matched `media-gc` skill when an upload reached R2 but was
|
|
184
|
+
never committed. It audits first and removes only stale objects without
|
|
185
|
+
`committedAt` metadata after explicit operator confirmation. Do not use an R2
|
|
186
|
+
lifecycle rule: committed and uncommitted media share the same purpose prefix.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aotter/mantle",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
4
|
"description": "Umbrella entry for @aotter/mantle. Adopters install this one package and import from subpaths: /spec, /runtime, /cloudflare, /admin-ui. Sub-packages remain individually installable on npm for tooling and adapter authors.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://mantle.tools/",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"README.md"
|
|
56
56
|
],
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@aotter/mantle-admin-ui": "0.1.0-alpha.
|
|
59
|
-
"@aotter/mantle-cloudflare": "0.1.0-alpha.
|
|
60
|
-
"@aotter/mantle-
|
|
61
|
-
"@aotter/mantle-
|
|
58
|
+
"@aotter/mantle-admin-ui": "0.1.0-alpha.7",
|
|
59
|
+
"@aotter/mantle-cloudflare": "0.1.0-alpha.7",
|
|
60
|
+
"@aotter/mantle-runtime": "0.1.0-alpha.7",
|
|
61
|
+
"@aotter/mantle-spec": "0.1.0-alpha.7"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@cloudflare/workers-oauth-provider": "^0.8.2",
|
package/skills/README.md
CHANGED
|
@@ -5,6 +5,7 @@ Agent-readable skill briefs for consumers of `@aotter/mantle-*`. Discoverable by
|
|
|
5
5
|
| Skill | When to invoke |
|
|
6
6
|
|---|---|
|
|
7
7
|
| [`develop`](develop/SKILL.md) | `mantle:develop`: Core-owned workflow for manifest, runtime, handler, adapter, validation, and MCP work in any Mantle project. |
|
|
8
|
+
| [`media-gc`](media-gc/SKILL.md) | `mantle:media-gc`: audit or remove stale uncommitted public media objects with the connected Cloudflare API. |
|
|
8
9
|
| [`plugin`](plugin/SKILL.md) | `mantle:plugin`: Core-owned marketplace workflow for plan-first capability installs across starters and adapters. |
|
|
9
10
|
| [`theme`](theme/SKILL.md) | `mantle:theme`: Core-owned visual workflow. Reads project context but does not depend on starter-owned skill semantics. |
|
|
10
11
|
| [`update`](update/SKILL.md) | `mantle:update`: Core-owned drift check workflow for SDK, starter snapshots, and plugin lockfiles. |
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: media-gc
|
|
3
|
+
description: Audit and safely remove stale, uncommitted public media uploads from a Mantle Cloudflare R2 bucket. Use when a Mantle operator asks to inspect or clean orphan media objects left after create_media_upload without commit_media_upload.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Mantle Media GC
|
|
7
|
+
|
|
8
|
+
Use the connected Cloudflare API. Audit by default; delete only the exact
|
|
9
|
+
objects approved by the user.
|
|
10
|
+
|
|
11
|
+
## Preflight
|
|
12
|
+
|
|
13
|
+
1. Read the project's Wrangler config and Mantle config. Resolve the R2 bucket
|
|
14
|
+
binding, bucket name, and declared public media purpose names.
|
|
15
|
+
2. Confirm the exact Cloudflare account and bucket. If either is ambiguous,
|
|
16
|
+
ask; never choose by name similarity.
|
|
17
|
+
3. Use the Cloudflare OpenAPI search before execution to resolve the current
|
|
18
|
+
R2 List Objects and Delete Objects endpoints. If the connected account lacks
|
|
19
|
+
access, stop. Do not create, request, or store credentials.
|
|
20
|
+
4. Stop when the project has no public R2 media binding or no declared purpose.
|
|
21
|
+
|
|
22
|
+
## Audit
|
|
23
|
+
|
|
24
|
+
For each declared purpose, list up to 1,000 objects per page under the exact
|
|
25
|
+
`<purpose>/` prefix. Use the API cursor until `is_truncated` is false.
|
|
26
|
+
|
|
27
|
+
An object is a deletion candidate only when all conditions hold:
|
|
28
|
+
|
|
29
|
+
- `last_modified` is more than 24 hours old;
|
|
30
|
+
- `custom_metadata.committedAt` is absent or empty;
|
|
31
|
+
- the key matches the exact Mantle layout
|
|
32
|
+
`<purpose>/<group>/(primary|alternate|fallback).(png|jpg|webp|avif|gif|svg)`,
|
|
33
|
+
where `<purpose>` is declared by this project and `<group>` contains only
|
|
34
|
+
letters, digits, `_`, or `-`.
|
|
35
|
+
|
|
36
|
+
Skip committed, unknown-prefix, unprefixed, malformed, or ambiguous objects.
|
|
37
|
+
Delete only an uncommitted variant, never its whole group.
|
|
38
|
+
|
|
39
|
+
Report the account, bucket, purpose prefixes, UTC cutoff, candidate object and
|
|
40
|
+
group counts, total bytes, skipped count, and a SHA-256 digest of the sorted
|
|
41
|
+
`key + etag` candidate set. Do not print object keys, upload group IDs,
|
|
42
|
+
filenames, public URLs, signed URLs, or secrets.
|
|
43
|
+
|
|
44
|
+
## Apply
|
|
45
|
+
|
|
46
|
+
1. Show the audit summary and get explicit confirmation for that exact account,
|
|
47
|
+
bucket, cutoff, count, byte total, and candidate-set digest.
|
|
48
|
+
2. Re-run the complete audit with the same UTC cutoff. If the candidate count,
|
|
49
|
+
bytes, or digest changed, stop and present the new audit for confirmation.
|
|
50
|
+
3. Call Delete Objects with JSON arrays of exact keys, at most 1,000 keys per
|
|
51
|
+
request. Never send the `prefix` query parameter: an empty prefix can empty
|
|
52
|
+
the bucket.
|
|
53
|
+
4. Do not automatically retry failed keys. Report safe API error codes and
|
|
54
|
+
counts; a later invocation can audit and retry what remains.
|
|
55
|
+
5. Re-list every inspected purpose prefix and report the remaining candidate
|
|
56
|
+
count and bytes.
|
|
57
|
+
|
|
58
|
+
## Don't
|
|
59
|
+
|
|
60
|
+
- Don't create a Worker, Cron Trigger, lifecycle rule, D1 table, or local script.
|
|
61
|
+
- Don't use prefix deletion or empty-bucket operations.
|
|
62
|
+
- Don't delete private-media buckets or objects outside declared purpose
|
|
63
|
+
prefixes.
|
|
64
|
+
- Don't treat missing pagination pages, metadata, or permissions as an empty
|
|
65
|
+
result.
|
|
66
|
+
|
|
67
|
+
## Diagnostics
|
|
68
|
+
|
|
69
|
+
| Symptom | Action |
|
|
70
|
+
|---|---|
|
|
71
|
+
| Multiple matching accounts or buckets | Stop and ask the user to select the exact target. |
|
|
72
|
+
| A page is truncated without a cursor | Stop; do not delete from a partial audit. |
|
|
73
|
+
| A candidate has an unexpected key or metadata shape | Skip it and include it only in the aggregate skipped count. |
|
|
74
|
+
| A delete request partially fails | Report safe error codes and leave the remaining objects for a later audit. |
|
|
75
|
+
|
|
76
|
+
## When You're Done
|
|
77
|
+
|
|
78
|
+
Return whether the run was audit-only or applied, the aggregate before/after
|
|
79
|
+
counts and bytes, and any safely redacted failures.
|