@gentbajko/slopify 3.16.0 → 3.18.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/dist/edge/http/actions.js +2 -2
- package/dist/edge/http/actor.js +10 -0
- package/dist/edge/http/app.js +21 -0
- package/dist/edge/http/checkpoints.js +14 -6
- package/dist/edge/http/external-reviews.js +95 -0
- package/dist/edge/http/projects.js +36 -18
- package/dist/edge/http/reviews.js +53 -18
- package/dist/edge/http/revisions.js +5 -1
- package/dist/edge/http/settings.js +9 -1
- package/dist/edge/http/starts.js +41 -0
- package/dist/edge/http/studio.js +5 -130
- package/dist/edge/mcp/attribution.js +38 -0
- package/dist/edge/mcp/call-route.js +203 -0
- package/dist/edge/mcp/excluded-routes.js +95 -0
- package/dist/edge/mcp/file-tools.js +141 -0
- package/dist/edge/mcp/http.js +79 -0
- package/dist/edge/mcp/instructions.js +17 -0
- package/dist/edge/mcp/library-tools.js +143 -0
- package/dist/edge/mcp/remake-tools.js +90 -0
- package/dist/edge/mcp/review-tools.js +64 -0
- package/dist/edge/mcp/route-tool.js +61 -0
- package/dist/edge/mcp/server.js +48 -0
- package/dist/edge/mcp/state-shapes.js +60 -0
- package/dist/edge/mcp/tools-channels.js +153 -0
- package/dist/edge/mcp/tools-library.js +151 -0
- package/dist/edge/mcp/tools-planning.js +137 -0
- package/dist/edge/mcp/tools-projects.js +167 -0
- package/dist/edge/mcp/tools-publishing.js +148 -0
- package/dist/edge/mcp/tools-runs.js +94 -0
- package/dist/edge/mcp/tools-schedules.js +143 -0
- package/dist/edge/mcp/tools-setup.js +234 -0
- package/dist/edge/mcp/tools-storage.js +99 -0
- package/dist/edge/mcp/tools.js +21 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/kernel/db/migrations/0055-external-reviews.sql +56 -0
- package/dist/kernel/db/migrations/0056-agent-actions.sql +20 -0
- package/dist/kernel/db/migrations/0057-agent-action-once.sql +5 -0
- package/dist/kernel/db/migrations/0058-revision-work-admission.sql +3 -0
- package/dist/kernel/db/migrations/0059-external-review-canceled.sql +29 -0
- package/dist/kernel/db/migrations/0060-reservation-work.sql +4 -0
- package/dist/kernel/db/migrations/0061-project-control-counts.sql +4 -0
- package/dist/kernel/db/migrations/0062-told-failures.sql +8 -0
- package/dist/kernel/pipeline.js +6 -0
- package/dist/kernel/runner/graph.js +37 -2
- package/dist/kernel/runner/index.js +6 -3
- package/dist/main.js +29 -13
- package/dist/patch-notes/3.17.0.md +10 -0
- package/dist/patch-notes/3.18.0.md +13 -0
- package/dist/patch-notes/index.json +12 -0
- package/dist/slices/admission/admitted-work.js +53 -0
- package/dist/slices/admission/heads.js +5 -0
- package/dist/slices/admission/repo.js +47 -29
- package/dist/slices/admission/schema.js +1 -0
- package/dist/slices/admission/stage-writes.js +21 -0
- package/dist/slices/admission/start.js +2 -1
- package/dist/slices/admission/state-words.js +110 -0
- package/dist/slices/agents/attention-work.js +233 -0
- package/dist/slices/agents/attention.js +168 -0
- package/dist/slices/agents/connection.js +15 -0
- package/dist/slices/agents/model.js +29 -0
- package/dist/slices/agents/repo.js +66 -0
- package/dist/slices/cancel/index.js +4 -1
- package/dist/slices/control/index.js +2 -1
- package/dist/slices/episodes/summarize.js +2 -1
- package/dist/slices/estimate/index.js +6 -2
- package/dist/slices/images/run.js +2 -1
- package/dist/slices/library/transfer.js +69 -0
- package/dist/slices/narration/run.js +2 -1
- package/dist/slices/notifications/address.js +40 -0
- package/dist/slices/notifications/notifier.js +43 -10
- package/dist/slices/notifications/rules.js +111 -45
- package/dist/slices/notifications/server.js +14 -0
- package/dist/slices/notifications/settings.js +1 -1
- package/dist/slices/notifications/subject.js +30 -0
- package/dist/slices/notifications/told.js +33 -0
- package/dist/slices/play-drafts/readiness.js +9 -2
- package/dist/slices/play-drafts/schema.js +2 -1
- package/dist/slices/rebuild/narration-words.js +76 -0
- package/dist/slices/rebuild/recipe-model.js +1 -0
- package/dist/slices/rebuild/recipe-reviews.js +44 -23
- package/dist/slices/rebuild/recovery-repo.js +0 -20
- package/dist/slices/rebuild/recovery-selection.js +14 -3
- package/dist/slices/rebuild/recovery.js +5 -2
- package/dist/slices/rebuild/remake-outdated.js +27 -0
- package/dist/slices/rebuild/repo.js +7 -2
- package/dist/slices/rebuild/review-redo.js +12 -0
- package/dist/slices/rebuild/runtime-agent-review.js +121 -0
- package/dist/slices/rebuild/runtime-export-inputs.js +26 -11
- package/dist/slices/rebuild/runtime-review.js +12 -2
- package/dist/slices/rebuild/runtime-run.js +11 -2
- package/dist/slices/rebuild/runtime-store.js +32 -5
- package/dist/slices/reruns/index.js +2 -1
- package/dist/slices/research/run.js +2 -1
- package/dist/slices/reviews/external-model.js +21 -0
- package/dist/slices/reviews/external-release.js +38 -0
- package/dist/slices/reviews/external-repo.js +109 -0
- package/dist/slices/reviews/external-rows.js +68 -0
- package/dist/slices/reviews/external-waiting.js +75 -0
- package/dist/slices/reviews/holds.js +144 -0
- package/dist/slices/reviews/model.js +14 -0
- package/dist/slices/reviews/repo.js +27 -10
- package/dist/slices/reviews/rules.js +5 -3
- package/dist/slices/reviews/verdict.js +18 -8
- package/dist/slices/revisions/repo.js +3 -0
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/schedules/agenda.js +47 -17
- package/dist/slices/schedules/prepare.js +6 -0
- package/dist/slices/schedules/schema.js +13 -1
- package/dist/slices/storage/consequences.js +27 -0
- package/dist/slices/storage/portable.js +3 -0
- package/dist/slices/storage/project-files.js +66 -0
- package/dist/slices/studio/settings.js +0 -35
- package/dist/slices/studio/stats.js +2 -34
- package/dist/slices/subtitles/prepare.js +2 -1
- package/dist/slices/uploads/repo.js +12 -6
- package/dist/slices/uploads/rules.js +5 -0
- package/dist/slices/video/write-export.js +1 -1
- package/dist/slices/video/write-subtitles.js +1 -1
- package/dist/tutorials/Agents-MCP.md +168 -0
- package/dist/tutorials/Calendar.md +2 -1
- package/dist/tutorials/First-Launch-and-Welcome.md +1 -0
- package/dist/tutorials/Home-and-Projects.md +16 -9
- package/dist/tutorials/Home.md +1 -0
- package/dist/tutorials/Notifications.md +25 -6
- package/dist/tutorials/Project-Page.md +8 -2
- package/dist/tutorials/Publishing-to-YouTube.md +1 -0
- package/dist/tutorials/Recovery-and-Retries.md +17 -3
- package/dist/tutorials/Reviews-and-Checkpoints.md +22 -5
- package/dist/tutorials/Schedules.md +1 -1
- package/dist/tutorials/Settings-Reference.md +15 -0
- package/dist/tutorials/Troubleshooting.md +3 -1
- package/dist/tutorials/Your-First-Short.md +1 -0
- package/dist/tutorials/_Sidebar.md +1 -0
- package/dist/web/assets/{index-VbpUYLAp.css → index-BKbZIxAq.css} +1 -1
- package/dist/web/assets/index-Drth_MfQ.js +325 -0
- package/dist/web/assets/{pdf-C6KhxeKQ.js → pdf-CQFUyijy.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/slices/studio/performance.js +0 -83
- package/dist/slices/studio/report-stats.js +0 -39
- package/dist/slices/studio/report.js +0 -172
- package/dist/web/assets/index-Dvz8bsiD.js +0 -325
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { formBody } from "./route-tool.js";
|
|
2
|
+
const description = [
|
|
3
|
+
{
|
|
4
|
+
name: "get_description_edits",
|
|
5
|
+
route: "GET /api/projects/:id/youtube-edits",
|
|
6
|
+
title: "Read description edits",
|
|
7
|
+
description: "The YouTube description, tags, pinned comment and titles as written, with the person's hand edits.",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: "get_project_channel_links",
|
|
11
|
+
route: "GET /api/projects/:id/channel-links",
|
|
12
|
+
title: "Read the project's channel links",
|
|
13
|
+
description: "The links the description's {{Name}} placeholders fill from for this project.",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "edit_description_field",
|
|
17
|
+
route: "PUT /api/projects/:id/youtube-edits/fields/:field",
|
|
18
|
+
title: "Edit a description field",
|
|
19
|
+
description: "Hand-edits one field (field: a name get_description_edits lists). Body: {text: the new text, base: the text you edited from}.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "reset_description_field",
|
|
23
|
+
route: "DELETE /api/projects/:id/youtube-edits/fields/:field",
|
|
24
|
+
title: "Drop a description edit",
|
|
25
|
+
description: "Drops the hand edit of one field; the written text comes back.",
|
|
26
|
+
confirm: "This drops your hand edit of this field for good; the text Slopify wrote comes back.",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "set_description_links",
|
|
30
|
+
route: "PUT /api/projects/:id/youtube-edits/links",
|
|
31
|
+
title: "Set the description's links",
|
|
32
|
+
description: "The links this project's description fills its {{Name}} placeholders from. Body: {links: [{name, url}]}.",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
const uploadPrep = [
|
|
36
|
+
{
|
|
37
|
+
name: "get_upload_pack",
|
|
38
|
+
route: "GET /api/studio/packs/:projectId",
|
|
39
|
+
title: "Read the upload pack",
|
|
40
|
+
description: "Prepare upload: the title, description, tags, thumbnails, playlists and release time of each upload (the video and each short), and the plan's free slots. The agent's work ends here, at Ready to upload: uploading is the person's.",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "set_pack_slot",
|
|
44
|
+
route: "PUT /api/studio/packs/:projectId/slot",
|
|
45
|
+
title: "Choose the release slot",
|
|
46
|
+
description: "Prepare upload's slot picker: one of the free slots get_upload_pack lists, or none. Body: {slot: {row, longAt} | null}.",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "set_pack_real_footage",
|
|
50
|
+
route: "PUT /api/studio/packs/:projectId/real-footage",
|
|
51
|
+
title: "Set the altered-content answer",
|
|
52
|
+
description: "Prepare upload's AI use tick: the project's uploaded clips are real footage. Body: {realFootage: true | false}.",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "set_pack_pick",
|
|
56
|
+
route: "PUT /api/studio/packs/:projectId/pick",
|
|
57
|
+
title: "Pick the title and thumbnail",
|
|
58
|
+
description: "Prepare upload's pick: which title and thumbnail the upload carries (the A/B test tries the others once the video is public). Body: {title: 0-9, thumbnail: 0-9}.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "set_pack_playlists",
|
|
62
|
+
route: "PUT /api/studio/packs/:projectId/playlists",
|
|
63
|
+
title: "Set the pack's playlists",
|
|
64
|
+
description: "Prepare upload's playlist ticks. Body: {playlists: [names] | null for the channel's defaults}.",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "get_fill_queue",
|
|
68
|
+
route: "GET /api/studio/queue",
|
|
69
|
+
title: "Read the Studio fill queue",
|
|
70
|
+
description: "What waits for the person's Slopify Studio extension, oldest first.",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "remove_from_fill_queue",
|
|
74
|
+
route: "POST /api/studio/queue/remove",
|
|
75
|
+
title: "Remove from the fill queue",
|
|
76
|
+
description: "Takes an upload off the extension's queue (agents never add one). Body: {projectId, short: a short's number or null for the video}.",
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
const releases = [
|
|
80
|
+
{
|
|
81
|
+
name: "get_releases",
|
|
82
|
+
route: "GET /api/studio/releases",
|
|
83
|
+
title: "Read Calendar → Releases",
|
|
84
|
+
description: "The coming weeks' long videos and shorts with their release time, upload-by time and state (not-ready, ready, late = \"Late · upload now\", filled, scheduled), the posting plan's free times and the finished projects that could fill them. Query: {weeks?: 1-8}.",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "get_project_releases",
|
|
88
|
+
route: "GET /api/studio/releases/:projectId",
|
|
89
|
+
title: "Read a project's release times",
|
|
90
|
+
description: "The project page's Release block: the release time and upload-by time of the video and each short, and the plan's free times for its series.",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "swap_releases",
|
|
94
|
+
route: "POST /api/studio/releases/:projectId/swap",
|
|
95
|
+
title: "Swap with…",
|
|
96
|
+
description: "Swap with…: two videos trade their release times; their shorts follow each. Body: {with: the other project's id}.",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "set_release",
|
|
100
|
+
route: "PUT /api/studio/releases/:projectId",
|
|
101
|
+
title: "Set a release time",
|
|
102
|
+
description: "Moves one release (short 0 is the long video), sets it to Not scheduled (at: null), or Take this time: puts the project into a free time of the plan (short 0 with that time's line). Body: {short, at: an ISO time | null, line?}.",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "get_posting_plan",
|
|
106
|
+
route: "GET /api/studio/plan",
|
|
107
|
+
title: "Read the posting plan",
|
|
108
|
+
description: "The posting plan's lines, its lead time and the series the projects use.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "set_posting_plan",
|
|
112
|
+
route: "PUT /api/studio/plan",
|
|
113
|
+
title: "Save the posting plan",
|
|
114
|
+
description: formBody("Calendar → Releases' posting plan"),
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "set_lead_time",
|
|
118
|
+
route: "PUT /api/studio/settings/lead-hours",
|
|
119
|
+
title: "Set the lead time",
|
|
120
|
+
description: "How many hours before its release a video must be uploaded. Body: {hours}.",
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
const youtube = [
|
|
124
|
+
{
|
|
125
|
+
name: "get_youtube_videos",
|
|
126
|
+
route: "GET /api/studio/videos/:projectId",
|
|
127
|
+
title: "Read On YouTube",
|
|
128
|
+
description: "The YouTube videos a project's uploads became: upload state, checks, the A/B test and the finishing touches (end screen, captions, related video, pinned comment) with any failure message.",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "set_youtube_link",
|
|
132
|
+
route: "PUT /api/studio/videos/:projectId",
|
|
133
|
+
title: "Set or forget a YouTube link",
|
|
134
|
+
description: "Records the YouTube link of an upload made without the extension, or with an empty link is Deleted on YouTube: Slopify forgets the video so it can be uploaded again. Body: {short: a short's number or null for the video, link}.",
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "get_ab_results",
|
|
138
|
+
route: "GET /api/studio/ab-results",
|
|
139
|
+
title: "Read A/B results",
|
|
140
|
+
description: "Library → A/B results: every finished title and thumbnail test.",
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
export const publishingTools = [
|
|
144
|
+
...description,
|
|
145
|
+
...uploadPrep,
|
|
146
|
+
...releases,
|
|
147
|
+
...youtube,
|
|
148
|
+
];
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { control } from "./route-tool.js";
|
|
2
|
+
const runs = [
|
|
3
|
+
{
|
|
4
|
+
name: "pause_project",
|
|
5
|
+
route: "POST /api/projects/:id/pause",
|
|
6
|
+
title: "Pause",
|
|
7
|
+
description: `Pause: the run stops after the steps already sent finish; nothing starts until resume_project. ${control}`,
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: "resume_project",
|
|
11
|
+
route: "POST /api/projects/:id/resume",
|
|
12
|
+
title: "Continue the run",
|
|
13
|
+
description: `Continue the run: starts the project's held and unfinished work, including work a saved edit left waiting. On a canceled run it resumes the whole run, the canceled steps too; once a step of it was taken up again (retry_stage), only the steps taken up again go on and the rest stay canceled. ${control}`,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "cancel_project",
|
|
17
|
+
route: "POST /api/projects/:id/cancel",
|
|
18
|
+
title: "Cancel run",
|
|
19
|
+
description: `Cancel run: stops every running stage of the project. ${control}`,
|
|
20
|
+
confirm: "Cancel this run? It stops every running stage; finished outputs are kept.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "retry_stage",
|
|
24
|
+
route: "POST /api/projects/:id/stages/:kind/retry",
|
|
25
|
+
title: "Try again",
|
|
26
|
+
description: `Try again on a failed step (kind: research, article, audio, images, thumbnail, video or document), keeping what it already made. ${control}`,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "soften_stage",
|
|
30
|
+
route: "POST /api/projects/:id/stages/:kind/soften",
|
|
31
|
+
title: "Soften and retry",
|
|
32
|
+
description: `Soften and retry, for a picture a content filter refused (kind images or thumbnail, or video for a short's picture): rewords the refused prompts and draws them again. ${control}`,
|
|
33
|
+
confirm: "Your project's AI model rewrites each refused prompt without what a content filter could flag, keeping the scene and style. The image is then drawn again from the new wording, which it keeps as its prompt. The AI call and the new image are charged like any other.",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "rerun_stage",
|
|
37
|
+
route: "POST /api/projects/:id/stages/:kind/rerun",
|
|
38
|
+
title: "Re-run a stage",
|
|
39
|
+
description: `Re-run section: makes a stage again and everything built on it. A re-run that costs money is refused until it is reviewed: use preview_rebuild (Choose what to remake), then start_rebuild. ${control}`,
|
|
40
|
+
confirm: "Re-run this stage? It generates the stage and its dependent outputs again, which costs what the stage cost the first time; previous outputs stay in History.",
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
const revisions = [
|
|
44
|
+
{
|
|
45
|
+
name: "prepare_revision",
|
|
46
|
+
route: "POST /api/projects/:id/revisions/prepare",
|
|
47
|
+
title: "Prepare an older project for editing",
|
|
48
|
+
description: "Saves the first version of a project made before versions existed; nothing is generated.",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "list_revisions",
|
|
52
|
+
route: "GET /api/projects/:id/revisions",
|
|
53
|
+
title: "Read project history",
|
|
54
|
+
description: "Every saved version of the project, newest first, as Project history lists them (byAgent marks one an agent saved), and agentActions: what agents did in the project.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "get_revision",
|
|
58
|
+
route: "GET /api/projects/:id/revisions/:revisionId",
|
|
59
|
+
title: "Read a version",
|
|
60
|
+
description: "One version in full: revision.config and revision.content (send them back as save_revision's edit.config and edit.content), its outputs, pieces and text parts.",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "read_narration_chunks",
|
|
64
|
+
route: "GET /api/projects/:id/revisions/:revisionId/narration-chunks",
|
|
65
|
+
title: "Read narration chunk keys",
|
|
66
|
+
description: 'The narration chunk keys in spoken order, per segment: {chunks: {intro?, body?, outro?}}. "Narration chunk 5 of 10" in an error is chunks.body[4] (an intro or outro chunk is named after its segment); the key is what save_revision\'s edit.regenerate and content.narrationOverrides take.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "save_revision",
|
|
70
|
+
route: "POST /api/projects/:id/revisions",
|
|
71
|
+
title: "Save an edit",
|
|
72
|
+
description: "Saves an edit as a new version, like Save in Edit project; it starts nothing. Body: {baseRevisionId, idempotencyKey: a new UUID, edit: {config, content, regenerate?: [work keys to make again, such as a narration chunk key], uploads?: [{stagedFileId, destination}]}}; send get_revision's revision.config and revision.content with your change. One chunk's wording or delivery note is content.narrationOverrides[chunk key] = {kind: \"text\", text, direction?}. Finished shorts kept through a new pick are content.shortsKeep: leave one out to pick a new moment for it, and lower config.shorts.count as well to drop it. Then preview_rebuild (Choose what to remake) says what it makes and costs, and start_rebuild starts it.",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: "restore_revision",
|
|
76
|
+
route: "POST /api/projects/:id/revisions/restore",
|
|
77
|
+
title: "Restore a version",
|
|
78
|
+
description: "Makes an earlier version current again, like Restore this revision; it starts nothing. Body: {baseRevisionId, idempotencyKey: a new UUID, targetRevisionId}.",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: "preview_rebuild",
|
|
82
|
+
route: "POST /api/projects/:id/rebuild/preview",
|
|
83
|
+
title: "Choose what to remake",
|
|
84
|
+
description: 'Choose what to remake: what a remake makes again, reuses or leaves blocked, each output\'s estimate and the total, like the project\'s Choose what to remake. Body: {baseRevisionId, request: {kind: "allAffected"} | {kind: "selected", workKeys: [...]}}. Nothing starts; start_rebuild does, with this preview\'s id.',
|
|
85
|
+
unrecorded: true,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "start_rebuild",
|
|
89
|
+
route: "POST /api/projects/:id/rebuild",
|
|
90
|
+
title: "Start a remake",
|
|
91
|
+
description: "Starts the remake you previewed: the acknowledgement Choose what to remake asks for. Body: {baseRevisionId, idempotencyKey: a new UUID, previewId: the preview's id, acknowledgeUnknownCosts: true only after reading the preview's unknown costs, confirmedProvidedWorkKeys: the preview's providedReuseRequired keys you accept replacing}.",
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
export const runTools = [...runs, ...revisions];
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { formBody } from "./route-tool.js";
|
|
2
|
+
export const scheduleTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "list_schedules",
|
|
5
|
+
route: "GET /api/schedules",
|
|
6
|
+
title: "List schedules",
|
|
7
|
+
description: "Schedules with their next runs, release lines and topic queues.",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: "create_schedule",
|
|
11
|
+
route: "POST /api/schedules",
|
|
12
|
+
title: "Create a schedule",
|
|
13
|
+
description: `${formBody("the schedule editor")} Duplicate on a schedule is this with get_schedule's settings, a new id, a new name ending "(copy)" and items: [], then pause_schedule on the copy.`,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "get_schedule",
|
|
17
|
+
route: "GET /api/schedules/:id",
|
|
18
|
+
title: "Read a schedule",
|
|
19
|
+
description: "One schedule with its topic queue and release lines.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "update_schedule",
|
|
23
|
+
route: "PUT /api/schedules/:id",
|
|
24
|
+
title: "Save a schedule",
|
|
25
|
+
description: `${formBody("the schedule editor")} Its release lines set when each run's videos are released.`,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "pause_schedule",
|
|
29
|
+
route: "POST /api/schedules/:id/pause",
|
|
30
|
+
title: "Pause a schedule",
|
|
31
|
+
description: "No run starts from it until resume_schedule.",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "resume_schedule",
|
|
35
|
+
route: "POST /api/schedules/:id/resume",
|
|
36
|
+
title: "Resume a schedule",
|
|
37
|
+
description: "Runs start from it again at its times.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "cancel_schedule",
|
|
41
|
+
route: "POST /api/schedules/:id/cancel",
|
|
42
|
+
title: "Cancel a schedule",
|
|
43
|
+
description: "Cancel schedule, as the schedule's page does.",
|
|
44
|
+
confirm: "Stops future scheduled runs. Existing projects and run history are kept.",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "delete_schedule",
|
|
48
|
+
route: "DELETE /api/schedules/:id",
|
|
49
|
+
title: "Delete a schedule",
|
|
50
|
+
description: "Moves the schedule to the trash.",
|
|
51
|
+
confirm: "Moves this schedule to the trash for 30 days (Settings → Trash). Its run history is kept.",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "list_held_topics",
|
|
55
|
+
route: "GET /api/schedules/:id/topics/held",
|
|
56
|
+
title: "Read suggested topics",
|
|
57
|
+
description: "Topics the schedule generated and holds for approval, as Calendar → Suggested topics lists them.",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: "list_prepared_topics",
|
|
61
|
+
route: "GET /api/schedules/:id/prepared",
|
|
62
|
+
title: "Read prepared topics",
|
|
63
|
+
description: "Which queued topics are Prepared ahead, and their projects.",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "prepare_topic",
|
|
67
|
+
route: "POST /api/schedules/:id/topics/prepare",
|
|
68
|
+
title: "Prepare a topic",
|
|
69
|
+
description: "Prepare, from the schedule's topics or Open on calendar: makes the topic's project now, exactly as the schedule would, and runs everything but the video, which its scheduled day renders. It spends what Play's review estimates and is refused over the schedule's spend limit. Body: {topic: the topic's title}.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "generate_topics",
|
|
73
|
+
route: "POST /api/schedules/:id/topics/generate",
|
|
74
|
+
title: "Suggest topics",
|
|
75
|
+
description: "Asks the schedule's text model for topics, a paid call, like Suggest topics.",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "approve_all_topics",
|
|
79
|
+
route: "POST /api/schedules/:id/topics/held/approve-all",
|
|
80
|
+
title: "Approve every suggested topic",
|
|
81
|
+
description: "Moves every held topic into the queue.",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "approve_topics",
|
|
85
|
+
route: "POST /api/schedules/:id/topics/held/approve",
|
|
86
|
+
title: "Approve selected topics",
|
|
87
|
+
description: "Approve selected: moves these held topics into the queue. Body: {ids: [held topic ids]}.",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "reject_topics",
|
|
91
|
+
route: "POST /api/schedules/:id/topics/held/reject",
|
|
92
|
+
title: "Reject selected topics",
|
|
93
|
+
description: "Reject selected, or Reject all with every id shown: later generations won't suggest them again. Body: {ids: [held topic ids]}.",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "restore_topics",
|
|
97
|
+
route: "POST /api/schedules/:id/topics/held/restore",
|
|
98
|
+
title: "Bring rejected topics back",
|
|
99
|
+
description: `The Undo after a rejection: puts turned-down topics back. ${formBody("the Undo in the rejection's message")}`,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: "approve_topic",
|
|
103
|
+
route: "POST /api/schedules/:id/topics/held/:topicId/approve",
|
|
104
|
+
title: "Approve a topic",
|
|
105
|
+
description: formBody("Approve in Calendar → Suggested topics"),
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "reject_topic",
|
|
109
|
+
route: "POST /api/schedules/:id/topics/held/:topicId/reject",
|
|
110
|
+
title: "Reject a topic",
|
|
111
|
+
description: "Turns down one suggested topic.",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "edit_held_topic",
|
|
115
|
+
route: "PUT /api/schedules/:id/topics/held/:topicId",
|
|
116
|
+
title: "Edit a suggested topic",
|
|
117
|
+
description: formBody("the suggested topic's editor"),
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: "set_topic_queue",
|
|
121
|
+
route: "PUT /api/schedules/:id/topics",
|
|
122
|
+
title: "Set the topic queue",
|
|
123
|
+
description: `${formBody("the schedule's topic queue")} Bulk paste is this with the pasted topics added to the queue.`,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "move_topic",
|
|
127
|
+
route: "POST /api/schedules/:id/topics/move",
|
|
128
|
+
title: "Move a topic",
|
|
129
|
+
description: `Reorders the queue. ${formBody("the topic queue's move")}`,
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: "transfer_topic",
|
|
133
|
+
route: "POST /api/schedules/:id/topics/transfer",
|
|
134
|
+
title: "Move a topic to another schedule",
|
|
135
|
+
description: formBody("the topic queue's move to another schedule"),
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
name: "get_calendar",
|
|
139
|
+
route: "GET /api/calendar",
|
|
140
|
+
title: "Read the calendar",
|
|
141
|
+
description: "Upcoming scheduled runs (each with its prepared project, if any) and projects, each with needs (failed, paused, stopped, review) and readyToUpload. Query: {from, to: ISO times at most 92 days apart}.",
|
|
142
|
+
},
|
|
143
|
+
];
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readinessIsUsable } from "../../kernel/ports/model.js";
|
|
3
|
+
import { formBody } from "./route-tool.js";
|
|
4
|
+
const readinessShape = z.discriminatedUnion("kind", [
|
|
5
|
+
z.object({ kind: z.literal("keyed"), hasKey: z.boolean() }).loose(),
|
|
6
|
+
z
|
|
7
|
+
.object({ kind: z.literal("cli"), installed: z.boolean(), issue: z.string().optional() })
|
|
8
|
+
.loose(),
|
|
9
|
+
z
|
|
10
|
+
.object({ kind: z.literal("local"), available: z.boolean(), issue: z.string().optional() })
|
|
11
|
+
.loose(),
|
|
12
|
+
]);
|
|
13
|
+
const providerList = z.object({
|
|
14
|
+
providers: z.array(z.object({
|
|
15
|
+
id: z.string(),
|
|
16
|
+
family: z.string(),
|
|
17
|
+
displayName: z.string(),
|
|
18
|
+
readiness: z.custom((value) => readinessShape.safeParse(value).success),
|
|
19
|
+
})),
|
|
20
|
+
});
|
|
21
|
+
// Providers as agents see them: set up or not, never whether a key exists or where a CLI is.
|
|
22
|
+
export function configuredOrMissing(value) {
|
|
23
|
+
const parsed = providerList.safeParse(value);
|
|
24
|
+
if (!parsed.success)
|
|
25
|
+
return { providers: [] };
|
|
26
|
+
return {
|
|
27
|
+
providers: parsed.data.providers.map((provider) => ({
|
|
28
|
+
id: provider.id,
|
|
29
|
+
family: provider.family,
|
|
30
|
+
displayName: provider.displayName,
|
|
31
|
+
state: readinessIsUsable(provider.readiness) ? "configured" : "missing",
|
|
32
|
+
})),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// The Studio settings without the extension's pairing token (a credential) and its unpacked
|
|
36
|
+
// folder (host setup).
|
|
37
|
+
export function withoutExtensionSecrets(value) {
|
|
38
|
+
const parsed = z.record(z.string(), z.unknown()).safeParse(value);
|
|
39
|
+
return parsed.success
|
|
40
|
+
? Object.fromEntries(Object.entries(parsed.data).filter(([key]) => key !== "pairing" && key !== "unpacked"))
|
|
41
|
+
: {};
|
|
42
|
+
}
|
|
43
|
+
// The Notification URL can carry a secret (a webhook's token, a private ntfy topic): agents are
|
|
44
|
+
// told only whether one is set, and change it with set_notification_url.
|
|
45
|
+
export function notificationUrlState(value) {
|
|
46
|
+
const parsed = z.object({ url: z.string().nullable() }).loose().safeParse(value);
|
|
47
|
+
const url = parsed.success ? parsed.data.url : null;
|
|
48
|
+
return { notificationUrl: url === null || url.trim() === "" ? "missing" : "configured" };
|
|
49
|
+
}
|
|
50
|
+
const settings = [
|
|
51
|
+
{
|
|
52
|
+
name: "get_settings",
|
|
53
|
+
route: "GET /api/settings",
|
|
54
|
+
title: "Read production defaults",
|
|
55
|
+
description: "Settings → Production defaults: silence gap, appearance and loudness.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "update_settings",
|
|
59
|
+
route: "PUT /api/settings",
|
|
60
|
+
title: "Save production defaults",
|
|
61
|
+
description: "Body: {silenceGapSeconds, appearance: system | light | dark, loudness?: {enabled, videoLufs, audioFilesLufs}}.",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "get_default_channel_links",
|
|
65
|
+
route: "GET /api/settings/channel-links",
|
|
66
|
+
title: "Read the default channel links",
|
|
67
|
+
description: "Settings → Channel links: the links a description's {{Name}} placeholders fill from.",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "set_default_channel_links",
|
|
71
|
+
route: "PUT /api/settings/channel-links",
|
|
72
|
+
title: "Save the default channel links",
|
|
73
|
+
description: "Body: {links: [{name, url}]}.",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "get_notification_url",
|
|
77
|
+
route: "GET /api/settings/notifications",
|
|
78
|
+
title: "Check the Notification URL",
|
|
79
|
+
description: "Whether run notifications have somewhere to go: configured or missing. The address itself is never shown to agents.",
|
|
80
|
+
shape: notificationUrlState,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "set_notification_url",
|
|
84
|
+
route: "PUT /api/settings/notifications",
|
|
85
|
+
title: "Save the Notification URL",
|
|
86
|
+
description: "Body: {url: an http(s) address, or empty to stop}. Answers configured or missing, never the address.",
|
|
87
|
+
shape: notificationUrlState,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "send_test_notification",
|
|
91
|
+
route: "POST /api/settings/notifications/test",
|
|
92
|
+
title: "Send a test notification",
|
|
93
|
+
description: "Body: {url}.",
|
|
94
|
+
unrecorded: true,
|
|
95
|
+
reachesOut: "sends",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "list_voices",
|
|
99
|
+
route: "GET /api/settings/voices",
|
|
100
|
+
title: "List voices",
|
|
101
|
+
description: "Settings → Voices.",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "add_voice",
|
|
105
|
+
route: "POST /api/settings/voices",
|
|
106
|
+
title: "Add a voice",
|
|
107
|
+
description: "Body: {provider, name, voiceId, languages?: [primary language codes]}.",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
name: "set_voice_languages",
|
|
111
|
+
route: "PUT /api/settings/voices/:id/languages",
|
|
112
|
+
title: "Set a voice's languages",
|
|
113
|
+
description: formBody("Settings → Voices' languages"),
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "set_voice_real_person",
|
|
117
|
+
route: "PUT /api/settings/voices/:id/real-person",
|
|
118
|
+
title: "Mark a voice as a real person's",
|
|
119
|
+
description: formBody("Settings → Voices' real-person box"),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "remove_voice",
|
|
123
|
+
route: "DELETE /api/settings/voices/:id",
|
|
124
|
+
title: "Remove a voice",
|
|
125
|
+
description: "Removes the voice from Settings → Voices.",
|
|
126
|
+
confirm: "Projects that used this voice keep the audio they made with it.",
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "quote_voice_sample",
|
|
130
|
+
route: "POST /api/auditions/quote",
|
|
131
|
+
title: "Price a voice sample",
|
|
132
|
+
description: "Try a sample's price, as Play shows it before playing one. Body: {lines: [{speaker, provider, model, text}]}.",
|
|
133
|
+
unrecorded: true,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "get_usage",
|
|
137
|
+
route: "GET /api/usage",
|
|
138
|
+
title: "Read usage",
|
|
139
|
+
description: "Settings → Usage: this machine's usage counters.",
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: "get_diagnostics",
|
|
143
|
+
route: "GET /api/diagnostics",
|
|
144
|
+
title: "Download diagnostics",
|
|
145
|
+
description: "What Download diagnostics saves: versions, secret-free provider readiness, the project count and the model catalogue's state.",
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "get_studio_settings",
|
|
149
|
+
route: "GET /api/studio/settings",
|
|
150
|
+
title: "Read YouTube Studio settings",
|
|
151
|
+
description: "Settings → YouTube Studio: the playlists upload packs name, and whether the comment is posted.",
|
|
152
|
+
shape: withoutExtensionSecrets,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "set_studio_playlists",
|
|
156
|
+
route: "PUT /api/studio/settings/playlists",
|
|
157
|
+
title: "Save playlist kinds",
|
|
158
|
+
description: "Playlist kinds: the playlists upload packs name (long videos, shorts or both), for every channel or one. Body: {playlists: [{name, byDefault, for?: long | shorts | both}], channelId?}.",
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "get_agent_connection",
|
|
162
|
+
route: "GET /api/settings/agents",
|
|
163
|
+
title: "Read Settings → Connections → Agents (MCP)",
|
|
164
|
+
description: "When an agent last connected to Slopify's MCP endpoint, and the latest changes agents made, as Settings → Connections → Agents (MCP) lists them.",
|
|
165
|
+
},
|
|
166
|
+
];
|
|
167
|
+
const providers = [
|
|
168
|
+
{
|
|
169
|
+
name: "list_providers",
|
|
170
|
+
route: "GET /api/providers",
|
|
171
|
+
title: "List providers",
|
|
172
|
+
description: "Each provider as configured or missing.",
|
|
173
|
+
shape: configuredOrMissing,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "list_models",
|
|
177
|
+
route: "GET /api/providers/:id/models",
|
|
178
|
+
title: "List a provider's models",
|
|
179
|
+
description: "The models Slopify offers for the provider, with prices where known.",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: "list_system_voices",
|
|
183
|
+
route: "GET /api/providers/system-voice/voices",
|
|
184
|
+
title: "List the computer's voices",
|
|
185
|
+
description: "Voices of the computer's own speech program.",
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
name: "check_providers",
|
|
189
|
+
route: "POST /api/providers/health",
|
|
190
|
+
title: "Check providers",
|
|
191
|
+
description: "Settings → Providers' Check all: which providers answer and which CLIs are signed in.",
|
|
192
|
+
unrecorded: true,
|
|
193
|
+
reachesOut: "asks",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: "get_catalogue",
|
|
197
|
+
route: "GET /api/providers/catalogue",
|
|
198
|
+
title: "Read the model catalogue",
|
|
199
|
+
description: "When the model catalogue was updated and any warning.",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
name: "check_catalogue",
|
|
203
|
+
route: "POST /api/providers/catalogue/check",
|
|
204
|
+
title: "Check the model catalogue",
|
|
205
|
+
description: "Checks the published model catalogue and merges what changed into models.yaml (Settings → Models, Check now).",
|
|
206
|
+
reachesOut: "asks",
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "refresh_catalogue",
|
|
210
|
+
route: "POST /api/providers/catalogue/refresh",
|
|
211
|
+
title: "Refresh the model catalogue",
|
|
212
|
+
description: "Downloads the newest model catalogue.",
|
|
213
|
+
reachesOut: "asks",
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: "list_retired_models",
|
|
217
|
+
route: "GET /api/providers/catalogue/retired",
|
|
218
|
+
title: "List retired models in use",
|
|
219
|
+
description: "Templates, drafts and schedules that use a retired model.",
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: "switch_retired_model",
|
|
223
|
+
route: "POST /api/providers/catalogue/retired/switch",
|
|
224
|
+
title: "Switch a retired model",
|
|
225
|
+
description: formBody("Settings → Models' Switch"),
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "switch_all_retired_models",
|
|
229
|
+
route: "POST /api/providers/catalogue/retired/switch-all",
|
|
230
|
+
title: "Switch every retired model",
|
|
231
|
+
description: "Switches every use of a retired model to its suggested replacement.",
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
export const setupTools = [...settings, ...providers];
|