takomi 2.1.37 → 2.1.39
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/plugins/marketplace.json +32 -0
- package/.pi/agents/architect.md +4 -2
- package/.pi/agents/designer.md +2 -0
- package/.pi/agents/orchestrator.md +4 -0
- package/.pi/prompts/design-prompt.md +3 -1
- package/.pi/prompts/genesis-prompt.md +2 -0
- package/.pi/prompts/takomi-prompt.md +6 -3
- package/.pi/takomi/policies/subagent-routing.md +9 -1
- package/.pi/takomi/policies/takomi-lifecycle-routing.md +3 -1
- package/README.md +27 -5
- package/assets/.agent/skills/takomi-flow/SKILL.md +235 -0
- package/assets/.agent/workflows/README.md +3 -3
- package/assets/.agent/workflows/mode-architect.md +7 -5
- package/assets/.agent/workflows/vibe-design.md +3 -1
- package/assets/.agent/workflows/vibe-genesis.md +2 -0
- package/assets/Takomi-Agents/custom_modes.yaml +1253 -1252
- package/assets/Takomi-Agents/vibe-architect.yaml +11 -6
- package/assets/Takomi-Agents/vibe-orchestrator.yaml +2 -2
- package/docs/features/TakomiFlow_Portable_Plugin.md +78 -0
- package/docs/takomi-flow-onboarding.md +76 -0
- package/docs/takomi-flow-public-distribution.md +94 -0
- package/package.json +19 -2
- package/plugins/takomi-codex/.codex-plugin/plugin.json +37 -0
- package/plugins/takomi-codex/assets/composer-icon.png +0 -0
- package/plugins/takomi-codex/assets/logo-dark.png +0 -0
- package/plugins/takomi-codex/assets/logo.png +0 -0
- package/plugins/takomi-codex/scripts/takomi-board.ps1 +197 -0
- package/plugins/takomi-codex/scripts/takomi-detect.ps1 +125 -0
- package/plugins/takomi-codex/scripts/takomi-doctor.ps1 +88 -0
- package/plugins/takomi-codex/scripts/takomi-harness.ps1 +52 -0
- package/plugins/takomi-codex/scripts/takomi-pi-dispatch.ps1 +93 -0
- package/plugins/takomi-codex/scripts/takomi-policy.ps1 +108 -0
- package/plugins/takomi-codex/skills/takomi-codex/SKILL.md +194 -0
- package/plugins/takomi-flow/.codex-plugin/plugin.json +36 -0
- package/plugins/takomi-flow/.mcp.json +11 -0
- package/plugins/takomi-flow/assets/capabilities.json +171 -0
- package/plugins/takomi-flow/assets/collection.schema.json +29 -0
- package/plugins/takomi-flow/assets/composer-icon.png +0 -0
- package/plugins/takomi-flow/assets/examples.json +94 -0
- package/plugins/takomi-flow/assets/logo-dark.png +0 -0
- package/plugins/takomi-flow/assets/logo.png +0 -0
- package/plugins/takomi-flow/assets/request.schema.json +67 -0
- package/plugins/takomi-flow/assets/result.schema.json +45 -0
- package/plugins/takomi-flow/assets/templates/image-request.json +13 -0
- package/plugins/takomi-flow/assets/templates/video-request.json +15 -0
- package/plugins/takomi-flow/package.json +38 -0
- package/plugins/takomi-flow/pnpm-lock.yaml +813 -0
- package/plugins/takomi-flow/references/flow-provider-contract.md +326 -0
- package/plugins/takomi-flow/scripts/lib/agent-plan.mjs +130 -0
- package/plugins/takomi-flow/scripts/lib/api.mjs +113 -0
- package/plugins/takomi-flow/scripts/lib/args.mjs +57 -0
- package/plugins/takomi-flow/scripts/lib/audit.mjs +65 -0
- package/plugins/takomi-flow/scripts/lib/browser.mjs +39 -0
- package/plugins/takomi-flow/scripts/lib/capabilities.mjs +11 -0
- package/plugins/takomi-flow/scripts/lib/collect.mjs +53 -0
- package/plugins/takomi-flow/scripts/lib/commands.mjs +175 -0
- package/plugins/takomi-flow/scripts/lib/doctor.mjs +77 -0
- package/plugins/takomi-flow/scripts/lib/examples.mjs +17 -0
- package/plugins/takomi-flow/scripts/lib/flow-outcome.mjs +90 -0
- package/plugins/takomi-flow/scripts/lib/flow-ui.mjs +165 -0
- package/plugins/takomi-flow/scripts/lib/generation.mjs +90 -0
- package/plugins/takomi-flow/scripts/lib/inspect.mjs +81 -0
- package/plugins/takomi-flow/scripts/lib/mcp-prompts.mjs +39 -0
- package/plugins/takomi-flow/scripts/lib/mcp-resources.mjs +16 -0
- package/plugins/takomi-flow/scripts/lib/mcp-tools.mjs +150 -0
- package/plugins/takomi-flow/scripts/lib/media.mjs +78 -0
- package/plugins/takomi-flow/scripts/lib/observe.mjs +54 -0
- package/plugins/takomi-flow/scripts/lib/paths.mjs +37 -0
- package/plugins/takomi-flow/scripts/lib/playwright-loader.mjs +23 -0
- package/plugins/takomi-flow/scripts/lib/prompts.mjs +72 -0
- package/plugins/takomi-flow/scripts/lib/report.mjs +141 -0
- package/plugins/takomi-flow/scripts/lib/request-validator.mjs +58 -0
- package/plugins/takomi-flow/scripts/lib/request.mjs +55 -0
- package/plugins/takomi-flow/scripts/lib/resource-files.mjs +69 -0
- package/plugins/takomi-flow/scripts/lib/result.mjs +31 -0
- package/plugins/takomi-flow/scripts/lib/review.mjs +44 -0
- package/plugins/takomi-flow/scripts/lib/selftest.mjs +153 -0
- package/plugins/takomi-flow/scripts/lib/settings-plan.mjs +39 -0
- package/plugins/takomi-flow/scripts/lib/templates.mjs +37 -0
- package/plugins/takomi-flow/scripts/lib/trusted-chrome.mjs +67 -0
- package/plugins/takomi-flow/scripts/lib/workflow.mjs +56 -0
- package/plugins/takomi-flow/scripts/mcp-server.mjs +18 -0
- package/plugins/takomi-flow/scripts/mcp-smoke.mjs +142 -0
- package/plugins/takomi-flow/scripts/takomi-flow.mjs +17 -0
- package/plugins/takomi-flow/skills/takomi-flow/SKILL.md +235 -0
- package/plugins/takomi-flow/skills/takomi-flow/agents/openai.yaml +7 -0
- package/scripts/install-takomi-flow.ps1 +85 -0
- package/src/pi-takomi-core/orchestration.ts +1 -1
- package/src/pi-takomi-core/workflows.ts +4 -4
- package/src/skills-catalog.js +11 -7
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# TakomiFlow Provider Contract
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
TakomiFlow gives agents a stable interface for asking Google Flow to create assets through a browser profile the user controls.
|
|
6
|
+
|
|
7
|
+
## Surfaces
|
|
8
|
+
|
|
9
|
+
- Skill: route Codex behavior and safety rules.
|
|
10
|
+
- CLI: run browser workflows, request preparation, validation, and asset inspection.
|
|
11
|
+
- MCP: expose safe no-spend commands as callable agent tools.
|
|
12
|
+
|
|
13
|
+
MCP server:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
node scripts/mcp-server.mjs
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Smoke test:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node scripts/mcp-smoke.mjs
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
MCP tools mirror stable JSON operations: capabilities, doctor, audit, examples, template, prepare, workflow, validate, observe, generate, selftest, inspect, latest, runs, assets, review, collect, and report.
|
|
26
|
+
|
|
27
|
+
Browser-capable MCP tools require explicit `allowBrowser=true`. Generation also requires the normal spend guard.
|
|
28
|
+
|
|
29
|
+
MCP resources:
|
|
30
|
+
|
|
31
|
+
- `takomi-flow://contract`
|
|
32
|
+
- `takomi-flow://capabilities`
|
|
33
|
+
- `takomi-flow://examples`
|
|
34
|
+
- `takomi-flow://schemas/request`
|
|
35
|
+
- `takomi-flow://schemas/result`
|
|
36
|
+
- `takomi-flow://schemas/collection`
|
|
37
|
+
- `takomi-flow://templates/video`
|
|
38
|
+
- `takomi-flow://templates/image`
|
|
39
|
+
|
|
40
|
+
MCP prompts:
|
|
41
|
+
|
|
42
|
+
- `takomi_flow_video_workflow`
|
|
43
|
+
- `takomi_flow_image_workflow`
|
|
44
|
+
- `takomi_flow_review_workflow`
|
|
45
|
+
- `takomi_flow_collect_workflow`
|
|
46
|
+
|
|
47
|
+
## Agent Preflight
|
|
48
|
+
|
|
49
|
+
Run this before browser work when reliability matters:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node scripts/takomi-flow.mjs doctor
|
|
53
|
+
node scripts/takomi-flow.mjs audit
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`audit` is the preferred agent preflight. It reports readiness, safe no-spend actions, gated browser/spend actions, recent runs, and recommended next steps.
|
|
57
|
+
|
|
58
|
+
First-run agents should also check for an existing trusted Chrome DevTools endpoint before launching a new browser:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
curl http://127.0.0.1:9222/json/version
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If the endpoint exists, reuse it with `--cdp-url http://127.0.0.1:9222`. If it does not exist, run `trusted-chrome` and ask the user to sign into Google Flow manually. MCP is optional; every MCP operation has a CLI equivalent through `node scripts/takomi-flow.mjs`.
|
|
65
|
+
|
|
66
|
+
Run this after install or edits:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
node scripts/takomi-flow.mjs selftest
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Discover supported agent options:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
node scripts/takomi-flow.mjs capabilities
|
|
76
|
+
node scripts/takomi-flow.mjs examples
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Observe the current Flow UI without spending credits:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
node scripts/takomi-flow.mjs observe
|
|
83
|
+
node scripts/takomi-flow.mjs observe --browser-channel chrome
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If Google login shows "This browser or app may not be secure", rerun browser commands with
|
|
87
|
+
`trusted-chrome`. Playwright-launched Chrome can still expose automation flags such as
|
|
88
|
+
`--no-sandbox`; `trusted-chrome` starts Chrome directly with a remote debugging port and a dedicated
|
|
89
|
+
TakomiFlow profile. After manual login, pass `--cdp-url http://127.0.0.1:9222` so TakomiFlow attaches
|
|
90
|
+
to the trusted browser session instead of automating credential entry.
|
|
91
|
+
|
|
92
|
+
Verified signed-in observation currently sees a Flow dashboard with project cards, `PRO` account
|
|
93
|
+
state, and a `New project` button. Treat this as the preferred selector discovery starting point.
|
|
94
|
+
The project editor currently exposes a prompt textbox with text `What do you want to create?`, plus
|
|
95
|
+
`Agent`, `Agent Instructions`, `Settings`, file input, and `Create` buttons. Prompt filling has been
|
|
96
|
+
verified without pressing Create.
|
|
97
|
+
Live video durations are `4`, `6`, `8`, and `10` seconds. If the agent asks for an unsupported
|
|
98
|
+
duration, Flow may ask a follow-up. A verified generation also asked for explicit approval before
|
|
99
|
+
spending 7 credits for one video. After output creation, opening the generated media reveals a
|
|
100
|
+
toolbar `download` button that saves the MP4.
|
|
101
|
+
|
|
102
|
+
Use templates when starting a request from scratch:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
node scripts/takomi-flow.mjs template --kind video
|
|
106
|
+
node scripts/takomi-flow.mjs template --kind image
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Validate before generation:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
node scripts/takomi-flow.mjs validate --request <request.json>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
One-call agent workflow:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
node scripts/takomi-flow.mjs workflow --kind video --prompt "cinematic AI lab scene" --variations 2
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`workflow` prepares and validates a request in one call. Add `--submit --allow-browser --allow-spend` only after explicit user approval; the normal spend guard still applies.
|
|
122
|
+
|
|
123
|
+
## Request JSON
|
|
124
|
+
|
|
125
|
+
Agents can read `takomi-flow://schemas/request` for the JSON Schema version of this shape.
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"schemaVersion": 1,
|
|
130
|
+
"kind": "video",
|
|
131
|
+
"prompt": "cinematic AI lab scene with practical lighting",
|
|
132
|
+
"variations": 2,
|
|
133
|
+
"aspectRatio": "16:9",
|
|
134
|
+
"durationSeconds": 8,
|
|
135
|
+
"mode": "text-to-video",
|
|
136
|
+
"modelHint": "best-available",
|
|
137
|
+
"outputDir": "C:/Users/johno/.takomi-flow/runs",
|
|
138
|
+
"allowSpend": false,
|
|
139
|
+
"extractFrames": 4,
|
|
140
|
+
"notes": "Optional agent notes for traceability."
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Fields
|
|
145
|
+
|
|
146
|
+
Agents can discover the same fields from `capabilities.requestFields`.
|
|
147
|
+
|
|
148
|
+
- `kind`: `video` or `image`.
|
|
149
|
+
- `prompt`: Required non-empty generation prompt.
|
|
150
|
+
- `variations`: Positive integer. Defaults to `1`.
|
|
151
|
+
- `aspectRatio`: Optional UI hint such as `16:9`, `9:16`, or `1:1`.
|
|
152
|
+
- `durationSeconds`: Optional video duration hint.
|
|
153
|
+
- `mode`: Optional Flow mode hint such as `text-to-video`, `image-to-video`, or `text-to-image`.
|
|
154
|
+
- `modelHint`: Optional human-readable model or quality hint.
|
|
155
|
+
- `outputDir`: Optional base output directory.
|
|
156
|
+
- `allowSpend`: Must be `true` for generation submission.
|
|
157
|
+
- `extractFrames`: Optional number of review frames to extract from downloaded videos.
|
|
158
|
+
- `sourceAssets`: Optional array of local file paths for future image/video-to-video flows.
|
|
159
|
+
|
|
160
|
+
## Validation JSON
|
|
161
|
+
|
|
162
|
+
`validate` normalizes request values, checks them against `capabilities`, verifies source asset paths, and reports spend-guard state:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"schemaVersion": 1,
|
|
167
|
+
"status": "ok",
|
|
168
|
+
"normalized": {},
|
|
169
|
+
"errors": [],
|
|
170
|
+
"warnings": []
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Result JSON
|
|
175
|
+
|
|
176
|
+
Agents can read `takomi-flow://schemas/result` for the JSON Schema version of run metadata.
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"schemaVersion": 1,
|
|
181
|
+
"status": "manual_action_required",
|
|
182
|
+
"runId": "20260701-120000-flow",
|
|
183
|
+
"kind": "video",
|
|
184
|
+
"prompt": "cinematic AI lab scene with practical lighting",
|
|
185
|
+
"projectUrl": "https://labs.google/fx/tools/flow/project/example",
|
|
186
|
+
"settingsPlan": {
|
|
187
|
+
"requested": {
|
|
188
|
+
"mode": "text-to-video",
|
|
189
|
+
"variations": 2,
|
|
190
|
+
"aspectRatio": "16:9",
|
|
191
|
+
"durationSeconds": 8
|
|
192
|
+
},
|
|
193
|
+
"automatic": ["prompt", "download folder", "metadata", "asset catalog"],
|
|
194
|
+
"selectorDependent": [
|
|
195
|
+
{ "field": "aspectRatio", "value": "16:9" }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
"assets": [],
|
|
199
|
+
"assetCatalogPath": "C:/Users/johno/.takomi-flow/runs/20260701-120000-flow/assets.json",
|
|
200
|
+
"screenshots": [],
|
|
201
|
+
"errors": [],
|
|
202
|
+
"manualActions": [
|
|
203
|
+
"Complete Google login or Flow consent in the opened browser."
|
|
204
|
+
],
|
|
205
|
+
"metadataPath": "C:/Users/johno/.takomi-flow/runs/20260701-120000-flow/run.json"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`projectUrl` records the exact Flow project/editor URL used for the run so agents do not lose track of generated projects. `settingsPlan` preserves the user's requested Flow options in run metadata. Prompt entry, downloads, metadata, asset cataloging, and frame extraction are automated. Mode, aspect ratio, duration, model controls, source assets, and multi-variation UI selection are selector-dependent until `observe` captures the live Flow controls.
|
|
210
|
+
|
|
211
|
+
## Status Values
|
|
212
|
+
|
|
213
|
+
- `prepared`: Request file created; no browser action happened.
|
|
214
|
+
- `ok`: Command completed and artifacts were written.
|
|
215
|
+
- `downloaded`: One or more assets were downloaded.
|
|
216
|
+
- `manual_action_required`: User action is required in the browser.
|
|
217
|
+
- `blocked`: Flow showed quota, safety, captcha, account, or unsupported UI state.
|
|
218
|
+
- `failed`: Script error or unrecoverable automation failure.
|
|
219
|
+
|
|
220
|
+
## Safety Invariants
|
|
221
|
+
|
|
222
|
+
- Never store Google credentials.
|
|
223
|
+
- Never submit generation unless request `allowSpend` is true or `TAKOMI_FLOW_ALLOW_SPEND=true`.
|
|
224
|
+
- Never bypass Google account, captcha, safety, or quota controls.
|
|
225
|
+
- Always write a result file, even on failure.
|
|
226
|
+
- Always save downloads into the run directory unless the request explicitly overrides it.
|
|
227
|
+
|
|
228
|
+
## Asset Catalog
|
|
229
|
+
|
|
230
|
+
Run:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
node scripts/takomi-flow.mjs assets --run <run.json|run-dir> --frames 4
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The command writes `assets.json` next to `run.json`. Video assets are probed with `ffprobe` when available, and review frames are extracted with `ffmpeg` when `--frames` is greater than zero.
|
|
237
|
+
|
|
238
|
+
## Run Review
|
|
239
|
+
|
|
240
|
+
Run:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
node scripts/takomi-flow.mjs review --run <run.json|run-dir> --frames 4
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
`review` is the preferred post-generation agent command. It inspects the run, catalogs downloaded assets, extracts review frames, writes a Markdown report, and returns next actions.
|
|
247
|
+
|
|
248
|
+
## Collection
|
|
249
|
+
|
|
250
|
+
Run:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
node scripts/takomi-flow.mjs collect --run <run.json|run-dir> --target-dir <path> --frames 4 --include-frames
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
`collect` reviews a run, copies assets/report/optional frames into a downstream target folder, and writes `takomi-flow-collection.json` as a manifest.
|
|
257
|
+
|
|
258
|
+
Agents can read `takomi-flow://schemas/collection` for the JSON Schema version of the collection manifest.
|
|
259
|
+
|
|
260
|
+
## Markdown Reports
|
|
261
|
+
|
|
262
|
+
Run:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
node scripts/takomi-flow.mjs report --run <run.json|run-dir>
|
|
266
|
+
node scripts/takomi-flow.mjs report --output-dir <runs-dir> --limit 10
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
The command writes `report.md` next to a single run, or `takomi-flow-report.md` in a runs directory. Reports include status, metadata paths, screenshots, assets, errors, manual actions, and catalog details when `assets.json` exists.
|
|
270
|
+
|
|
271
|
+
## Diagnostics JSON
|
|
272
|
+
|
|
273
|
+
`doctor` returns:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"schemaVersion": 1,
|
|
278
|
+
"status": "ok",
|
|
279
|
+
"flowUrl": "https://labs.google/fx/tools/flow",
|
|
280
|
+
"profileDir": "C:/Users/johno/.takomi-flow/browser-profile",
|
|
281
|
+
"outputDir": "C:/Users/johno/.takomi-flow/runs",
|
|
282
|
+
"checks": [],
|
|
283
|
+
"recommendations": []
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Capabilities JSON
|
|
288
|
+
|
|
289
|
+
`capabilities` returns supported kinds, modes, variation limits, aspect ratios, output artifact names, safety invariants, and available commands. Agents should prefer this over hard-coded assumptions.
|
|
290
|
+
|
|
291
|
+
## Observation JSON
|
|
292
|
+
|
|
293
|
+
`observe` writes a normal `run.json` and includes a `controls` object:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"controls": {
|
|
298
|
+
"buttons": [],
|
|
299
|
+
"inputs": [],
|
|
300
|
+
"links": []
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Use it to tune Flow selectors after Google changes the UI.
|
|
306
|
+
|
|
307
|
+
## Self-Test JSON
|
|
308
|
+
|
|
309
|
+
`selftest` runs a deterministic no-spend verification pass:
|
|
310
|
+
|
|
311
|
+
- doctor diagnostics
|
|
312
|
+
- readiness audit
|
|
313
|
+
- capability loading
|
|
314
|
+
- example loading
|
|
315
|
+
- video/image template loading
|
|
316
|
+
- request preparation
|
|
317
|
+
- one-call workflow preparation/validation
|
|
318
|
+
- settings-plan metadata for requested Flow options
|
|
319
|
+
- request validation
|
|
320
|
+
- spend-guard expectation
|
|
321
|
+
- synthetic MP4 cataloging and frame extraction
|
|
322
|
+
- Markdown report generation
|
|
323
|
+
- one-call run review
|
|
324
|
+
- downstream asset collection
|
|
325
|
+
|
|
326
|
+
It writes artifacts under `<outputDir>/selftest`.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { loadCapabilities } from './capabilities.mjs';
|
|
2
|
+
import { normalizeRequest } from './request.mjs';
|
|
3
|
+
|
|
4
|
+
export function createAgentPlan(args = {}) {
|
|
5
|
+
const request = normalizeRequest(args);
|
|
6
|
+
const capabilities = loadCapabilities();
|
|
7
|
+
const submit = Boolean(args.submit);
|
|
8
|
+
const collectTarget = args.targetDir || args['target-dir'];
|
|
9
|
+
return {
|
|
10
|
+
schemaVersion: 1,
|
|
11
|
+
status: 'ready',
|
|
12
|
+
provider: capabilities.provider,
|
|
13
|
+
summary: `${request.kind} ${request.mode} Flow job with ${request.variations} variation(s).`,
|
|
14
|
+
request,
|
|
15
|
+
gates: gates(request, submit),
|
|
16
|
+
mcpSequence: mcpSequence(request, { submit, collectTarget }),
|
|
17
|
+
cliSequence: cliSequence(request, { submit, collectTarget }),
|
|
18
|
+
expectedOutputs: expectedOutputs(request, collectTarget),
|
|
19
|
+
nextActions: nextActions(submit, collectTarget),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function gates(request, submit) {
|
|
24
|
+
const items = [
|
|
25
|
+
{
|
|
26
|
+
name: 'spend',
|
|
27
|
+
required: submit,
|
|
28
|
+
satisfied: request.allowSpend,
|
|
29
|
+
note: 'Generation submission may spend Flow credits and requires allowSpend=true.',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'browser',
|
|
33
|
+
required: submit,
|
|
34
|
+
satisfied: false,
|
|
35
|
+
note: 'Browser-opening MCP tools require allowBrowser=true at call time.',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
return submit ? items : items.map(item => ({ ...item, required: false }));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function mcpSequence(request, options) {
|
|
42
|
+
const workflowArgs = {
|
|
43
|
+
kind: request.kind,
|
|
44
|
+
prompt: request.prompt,
|
|
45
|
+
variations: request.variations,
|
|
46
|
+
aspectRatio: request.aspectRatio,
|
|
47
|
+
durationSeconds: request.durationSeconds,
|
|
48
|
+
mode: request.mode,
|
|
49
|
+
modelHint: request.modelHint,
|
|
50
|
+
outputDir: request.outputDir,
|
|
51
|
+
allowSpend: request.allowSpend,
|
|
52
|
+
extractFrames: request.extractFrames,
|
|
53
|
+
sourceAssets: request.sourceAssets,
|
|
54
|
+
submit: options.submit,
|
|
55
|
+
allowBrowser: options.submit,
|
|
56
|
+
};
|
|
57
|
+
const steps = [
|
|
58
|
+
{ tool: 'takomi_flow_audit', arguments: { outputDir: request.outputDir } },
|
|
59
|
+
{ tool: 'takomi_flow_workflow', arguments: compact(workflowArgs) },
|
|
60
|
+
{ tool: 'takomi_flow_review', arguments: { run: '<run.json|run-dir>', frames: request.extractFrames || 0 } },
|
|
61
|
+
];
|
|
62
|
+
if (options.collectTarget) {
|
|
63
|
+
steps.push({
|
|
64
|
+
tool: 'takomi_flow_collect',
|
|
65
|
+
arguments: {
|
|
66
|
+
run: '<run.json|run-dir>',
|
|
67
|
+
targetDir: options.collectTarget,
|
|
68
|
+
frames: request.extractFrames || 0,
|
|
69
|
+
includeFrames: true,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return steps;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function cliSequence(request, options) {
|
|
77
|
+
const base = [
|
|
78
|
+
'node scripts/takomi-flow.mjs audit',
|
|
79
|
+
`node scripts/takomi-flow.mjs workflow --kind ${request.kind} --prompt "${escapeArg(request.prompt)}"${optionArgs(request, options.submit)}`,
|
|
80
|
+
`node scripts/takomi-flow.mjs review --run <run.json|run-dir> --frames ${request.extractFrames || 0}`,
|
|
81
|
+
];
|
|
82
|
+
if (options.collectTarget) {
|
|
83
|
+
base.push(`node scripts/takomi-flow.mjs collect --run <run.json|run-dir> --target-dir "${escapeArg(options.collectTarget)}" --frames ${request.extractFrames || 0} --include-frames`);
|
|
84
|
+
}
|
|
85
|
+
return base;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function optionArgs(request, submit) {
|
|
89
|
+
const args = [];
|
|
90
|
+
if (request.variations) args.push(`--variations ${request.variations}`);
|
|
91
|
+
if (request.aspectRatio) args.push(`--aspect-ratio ${request.aspectRatio}`);
|
|
92
|
+
if (request.durationSeconds) args.push(`--duration ${request.durationSeconds}`);
|
|
93
|
+
if (request.mode) args.push(`--mode ${request.mode}`);
|
|
94
|
+
if (request.modelHint) args.push(`--model "${escapeArg(request.modelHint)}"`);
|
|
95
|
+
if (request.outputDir) args.push(`--output-dir "${escapeArg(request.outputDir)}"`);
|
|
96
|
+
if (request.extractFrames) args.push(`--extract-frames ${request.extractFrames}`);
|
|
97
|
+
if (request.sourceAssets.length) args.push(`--assets "${escapeArg(request.sourceAssets.join(','))}"`);
|
|
98
|
+
if (submit) args.push('--submit --allow-browser --allow-spend');
|
|
99
|
+
return args.length ? ` ${args.join(' ')}` : '';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function expectedOutputs(request, collectTarget) {
|
|
103
|
+
const outputs = [
|
|
104
|
+
`${request.outputDir}/requests/<timestamp>-request.json`,
|
|
105
|
+
`${request.outputDir}/<runId>/run.json`,
|
|
106
|
+
`${request.outputDir}/<runId>/downloads/`,
|
|
107
|
+
`${request.outputDir}/<runId>/assets.json`,
|
|
108
|
+
`${request.outputDir}/<runId>/report.md`,
|
|
109
|
+
];
|
|
110
|
+
if (request.extractFrames) outputs.push(`${request.outputDir}/<runId>/frames/`);
|
|
111
|
+
if (collectTarget) outputs.push(`${collectTarget}/takomi-flow-collection.json`);
|
|
112
|
+
return outputs;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function nextActions(submit, collectTarget) {
|
|
116
|
+
const actions = ['Run the audit step first and treat missing profile as a bootstrap/login gate.'];
|
|
117
|
+
if (!submit) actions.push('Use the workflow step without submit to prepare and validate the request without spending credits.');
|
|
118
|
+
if (submit) actions.push('Confirm the user explicitly approved spending Flow credits before running the submit step.');
|
|
119
|
+
actions.push('After generation, review run metadata, errors, screenshots, and downloaded assets.');
|
|
120
|
+
if (collectTarget) actions.push('Collect reviewed outputs into the downstream target folder for pipeline reuse.');
|
|
121
|
+
return actions;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function compact(value) {
|
|
125
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function escapeArg(value) {
|
|
129
|
+
return String(value).replaceAll('"', '\\"');
|
|
130
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createPreparedRequest } from './request.mjs';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { validateRequestFile } from './request-validator.mjs';
|
|
5
|
+
import { runDoctor } from './doctor.mjs';
|
|
6
|
+
import { loadCapabilities } from './capabilities.mjs';
|
|
7
|
+
import { listTemplates, loadTemplate, writeTemplate } from './templates.mjs';
|
|
8
|
+
import { runSelfTest } from './selftest.mjs';
|
|
9
|
+
import { inspectRun, latestRun, listRuns, resolveRun } from './inspect.mjs';
|
|
10
|
+
import { catalogAssets } from './media.mjs';
|
|
11
|
+
import { observeFlow } from './observe.mjs';
|
|
12
|
+
import { generateFromRequest } from './generation.mjs';
|
|
13
|
+
import { createReport } from './report.mjs';
|
|
14
|
+
import { runWorkflow } from './workflow.mjs';
|
|
15
|
+
import { reviewRun } from './review.mjs';
|
|
16
|
+
import { runAudit } from './audit.mjs';
|
|
17
|
+
import { collectRun } from './collect.mjs';
|
|
18
|
+
import { loadExamples } from './examples.mjs';
|
|
19
|
+
import { createAgentPlan } from './agent-plan.mjs';
|
|
20
|
+
|
|
21
|
+
export async function doctor(args = {}) {
|
|
22
|
+
return runDoctor({ profileDir: args.profileDir, outputDir: args.outputDir });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function capabilities() {
|
|
26
|
+
return loadCapabilities();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function observe(args = {}) {
|
|
30
|
+
return observeFlow({
|
|
31
|
+
profileDir: args.profileDir,
|
|
32
|
+
outputDir: args.outputDir,
|
|
33
|
+
browserChannel: args.browserChannel,
|
|
34
|
+
cdpUrl: args.cdpUrl,
|
|
35
|
+
headless: Boolean(args.headless),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function template(args = {}) {
|
|
40
|
+
if (!args.kind) return { templates: listTemplates() };
|
|
41
|
+
if (args.outputDir) return writeTemplate(args.kind, args.outputDir);
|
|
42
|
+
return loadTemplate(args.kind);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function prepare(args = {}) {
|
|
46
|
+
const { request, requestPath } = createPreparedRequest(args);
|
|
47
|
+
return { status: 'prepared', requestPath, request };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function validate(args = {}) {
|
|
51
|
+
return validateRequestFile(args.request);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function selftest(args = {}) {
|
|
55
|
+
return runSelfTest({ outputDir: args.outputDir });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function inspect(args = {}) {
|
|
59
|
+
return inspectRun(args.run);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function latest(args = {}) {
|
|
63
|
+
return latestRun(args.outputDir);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function runs(args = {}) {
|
|
67
|
+
return listRuns(args.outputDir, args.limit);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function assets(args = {}) {
|
|
71
|
+
const run = resolveRun(args.run);
|
|
72
|
+
return catalogAssets(run, assetPathsForRun(run), { frames: args.frames || 0 });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function generate(args = {}) {
|
|
76
|
+
return generateFromRequest(args);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function report(args = {}) {
|
|
80
|
+
return createReport(args);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function workflow(args = {}) {
|
|
84
|
+
return runWorkflow(args);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function review(args = {}) {
|
|
88
|
+
return reviewRun(args);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function audit(args = {}) {
|
|
92
|
+
return runAudit(args);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function collect(args = {}) {
|
|
96
|
+
return collectRun(args);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function examples(args = {}) {
|
|
100
|
+
return loadExamples(args.name);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function plan(args = {}) {
|
|
104
|
+
return createAgentPlan(args);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function assetPathsForRun(run) {
|
|
108
|
+
if (run.data.assets?.length) return run.data.assets;
|
|
109
|
+
if (!fs.existsSync(run.downloadsDir)) return [];
|
|
110
|
+
return fs.readdirSync(run.downloadsDir)
|
|
111
|
+
.map(name => path.join(run.downloadsDir, name))
|
|
112
|
+
.filter(filePath => fs.statSync(filePath).isFile());
|
|
113
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function parseArgs(argv) {
|
|
2
|
+
const args = { _: [] };
|
|
3
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
4
|
+
const token = argv[i];
|
|
5
|
+
if (!token.startsWith('--')) {
|
|
6
|
+
args._.push(token);
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
const key = token.slice(2);
|
|
10
|
+
const next = argv[i + 1];
|
|
11
|
+
if (!next || next.startsWith('--')) {
|
|
12
|
+
args[key] = true;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
args[key] = next;
|
|
16
|
+
i += 1;
|
|
17
|
+
}
|
|
18
|
+
return args;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function printUsage() {
|
|
22
|
+
console.log(`
|
|
23
|
+
TakomiFlow
|
|
24
|
+
|
|
25
|
+
Usage:
|
|
26
|
+
node scripts/takomi-flow.mjs bootstrap [--profile-dir <path>] [--browser-channel chrome] [--cdp-url <url>] [--headless]
|
|
27
|
+
node scripts/takomi-flow.mjs doctor [--profile-dir <path>] [--output-dir <path>]
|
|
28
|
+
node scripts/takomi-flow.mjs audit [--profile-dir <path>] [--output-dir <path>]
|
|
29
|
+
node scripts/takomi-flow.mjs capabilities
|
|
30
|
+
node scripts/takomi-flow.mjs examples [--name <example-name>]
|
|
31
|
+
node scripts/takomi-flow.mjs trusted-chrome [--port 9222] [--profile-dir <path>] [--chrome-path <path>]
|
|
32
|
+
node scripts/takomi-flow.mjs plan --kind <video|image> --prompt <text> [--submit --target-dir <path>]
|
|
33
|
+
node scripts/takomi-flow.mjs observe [--profile-dir <path>] [--output-dir <path>] [--browser-channel chrome] [--cdp-url <url>] [--headless]
|
|
34
|
+
node scripts/takomi-flow.mjs smoke [--profile-dir <path>] [--output-dir <path>] [--browser-channel chrome] [--cdp-url <url>]
|
|
35
|
+
node scripts/takomi-flow.mjs prepare --kind <video|image> --prompt <text> [--variations 1]
|
|
36
|
+
node scripts/takomi-flow.mjs workflow --kind <video|image> --prompt <text> [--submit --allow-browser --allow-spend]
|
|
37
|
+
node scripts/takomi-flow.mjs template --kind <video|image> [--output-dir <path>]
|
|
38
|
+
node scripts/takomi-flow.mjs validate --request <path>
|
|
39
|
+
node scripts/takomi-flow.mjs generate --request <path>
|
|
40
|
+
node scripts/takomi-flow.mjs selftest [--output-dir <path>]
|
|
41
|
+
node scripts/takomi-flow.mjs inspect --run <run.json|run-dir>
|
|
42
|
+
node scripts/takomi-flow.mjs latest [--output-dir <path>]
|
|
43
|
+
node scripts/takomi-flow.mjs runs [--output-dir <path>] [--limit 20]
|
|
44
|
+
node scripts/takomi-flow.mjs assets --run <run.json|run-dir> [--frames 4]
|
|
45
|
+
node scripts/takomi-flow.mjs review --run <run.json|run-dir> [--frames 4]
|
|
46
|
+
node scripts/takomi-flow.mjs collect --run <run.json|run-dir> --target-dir <path> [--frames 4 --include-frames]
|
|
47
|
+
node scripts/takomi-flow.mjs report [--run <run.json|run-dir>] [--output-dir <path>]
|
|
48
|
+
|
|
49
|
+
Spend guard:
|
|
50
|
+
generation submits only when request allowSpend=true or TAKOMI_FLOW_ALLOW_SPEND=true.
|
|
51
|
+
|
|
52
|
+
Google login note:
|
|
53
|
+
If Google says the browser may not be secure, use trusted Chrome attach mode:
|
|
54
|
+
node scripts/takomi-flow.mjs trusted-chrome
|
|
55
|
+
Then log in manually and attach with --cdp-url http://127.0.0.1:9222.
|
|
56
|
+
`);
|
|
57
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { runDoctor } from './doctor.mjs';
|
|
3
|
+
import { loadCapabilities } from './capabilities.mjs';
|
|
4
|
+
import { listRuns } from './inspect.mjs';
|
|
5
|
+
|
|
6
|
+
export async function runAudit(args = {}) {
|
|
7
|
+
const doctor = await runDoctor({
|
|
8
|
+
profileDir: args.profileDir,
|
|
9
|
+
outputDir: args.outputDir,
|
|
10
|
+
});
|
|
11
|
+
const capabilities = loadCapabilities();
|
|
12
|
+
const history = listRuns(doctor.outputDir, args.limit || 5);
|
|
13
|
+
const profileReady = fs.existsSync(doctor.profileDir);
|
|
14
|
+
const browserReady = doctor.checks.every(check => (
|
|
15
|
+
check.name === 'profileDir' || check.status !== 'failed'
|
|
16
|
+
));
|
|
17
|
+
return {
|
|
18
|
+
schemaVersion: 1,
|
|
19
|
+
status: doctor.status === 'failed' ? 'failed' : 'ok',
|
|
20
|
+
readiness: {
|
|
21
|
+
browserAutomation: browserReady,
|
|
22
|
+
flowProfile: profileReady,
|
|
23
|
+
mediaReview: hasCheck(doctor, 'ffmpeg') && hasCheck(doctor, 'ffprobe'),
|
|
24
|
+
mcpTools: capabilities.mcpTools.length,
|
|
25
|
+
mcpResources: capabilities.mcpResources.length,
|
|
26
|
+
},
|
|
27
|
+
safeActions: [
|
|
28
|
+
'capabilities',
|
|
29
|
+
'examples',
|
|
30
|
+
'plan',
|
|
31
|
+
'template',
|
|
32
|
+
'workflow without submit',
|
|
33
|
+
'validate',
|
|
34
|
+
'runs',
|
|
35
|
+
'inspect',
|
|
36
|
+
'assets',
|
|
37
|
+
'review',
|
|
38
|
+
'collect',
|
|
39
|
+
'report',
|
|
40
|
+
'selftest',
|
|
41
|
+
],
|
|
42
|
+
gatedActions: [
|
|
43
|
+
'bootstrap requires a headed browser and manual Google login',
|
|
44
|
+
'observe requires allowBrowser=true',
|
|
45
|
+
'generate requires allowBrowser=true and allowSpend=true',
|
|
46
|
+
'workflow submit requires allowBrowser=true and allowSpend=true',
|
|
47
|
+
],
|
|
48
|
+
doctor,
|
|
49
|
+
recentRuns: history.runs,
|
|
50
|
+
nextActions: nextActions(doctor, profileReady, history.runs),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function hasCheck(doctor, name) {
|
|
55
|
+
return doctor.checks.some(check => check.name === name && check.status === 'ok');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function nextActions(doctor, profileReady, runs) {
|
|
59
|
+
const actions = [...doctor.recommendations];
|
|
60
|
+
if (!profileReady) actions.push('Run bootstrap in headed mode and log into Google Flow manually.');
|
|
61
|
+
if (!runs.length) actions.push('Run workflow to prepare the first request, or smoke after login.');
|
|
62
|
+
if (runs.some(run => run.status === 'downloaded')) actions.push('Run review on downloaded runs before reusing assets.');
|
|
63
|
+
if (!actions.length) actions.push('TakomiFlow is ready for safe no-spend workflow preparation.');
|
|
64
|
+
return [...new Set(actions)];
|
|
65
|
+
}
|