takomi 2.1.39 → 2.1.41

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.
Files changed (68) hide show
  1. package/.agents/plugins/marketplace.json +22 -22
  2. package/README.md +217 -422
  3. package/assets/.agent/skills/remotion/rules/assets/charts-bar-chart.tsx +173 -173
  4. package/assets/.agent/skills/remotion/rules/assets/text-animations-typewriter.tsx +100 -100
  5. package/assets/.agent/skills/remotion/rules/text-animations.md +20 -20
  6. package/assets/.agent/skills/remotion/rules/videos.md +171 -171
  7. package/assets/.agent/skills/remotion-real-ui-video/SKILL.md +264 -0
  8. package/assets/.agent/skills/remotion-real-ui-video/references/anti-patterns.md +114 -0
  9. package/assets/.agent/skills/remotion-real-ui-video/references/completion-checklist.md +75 -0
  10. package/assets/.agent/skills/remotion-real-ui-video/references/real-ui-bridge-example.md +93 -0
  11. package/assets/.agent/skills/takomi-flow/SKILL.md +244 -235
  12. package/docs/features/TakomiFlow_Portable_Plugin.md +82 -78
  13. package/docs/takomi-flow-onboarding.md +86 -76
  14. package/docs/takomi-flow-public-distribution.md +94 -94
  15. package/package.json +1 -1
  16. package/plugins/takomi-flow/.mcp.json +11 -11
  17. package/plugins/takomi-flow/assets/capabilities.json +203 -171
  18. package/plugins/takomi-flow/assets/collection.schema.json +29 -29
  19. package/plugins/takomi-flow/assets/examples.json +94 -94
  20. package/plugins/takomi-flow/assets/request.schema.json +91 -67
  21. package/plugins/takomi-flow/assets/result.schema.json +46 -45
  22. package/plugins/takomi-flow/assets/templates/image-request.json +17 -13
  23. package/plugins/takomi-flow/assets/templates/video-request.json +19 -15
  24. package/plugins/takomi-flow/package.json +38 -38
  25. package/plugins/takomi-flow/pnpm-lock.yaml +813 -813
  26. package/plugins/takomi-flow/references/flow-provider-contract.md +349 -326
  27. package/plugins/takomi-flow/scripts/lib/agent-plan.mjs +140 -130
  28. package/plugins/takomi-flow/scripts/lib/api.mjs +113 -113
  29. package/plugins/takomi-flow/scripts/lib/args.mjs +66 -57
  30. package/plugins/takomi-flow/scripts/lib/audit.mjs +65 -65
  31. package/plugins/takomi-flow/scripts/lib/browser.mjs +78 -39
  32. package/plugins/takomi-flow/scripts/lib/capabilities.mjs +11 -11
  33. package/plugins/takomi-flow/scripts/lib/collect.mjs +53 -53
  34. package/plugins/takomi-flow/scripts/lib/commands.mjs +192 -175
  35. package/plugins/takomi-flow/scripts/lib/doctor.mjs +77 -77
  36. package/plugins/takomi-flow/scripts/lib/examples.mjs +17 -17
  37. package/plugins/takomi-flow/scripts/lib/flow-media.mjs +39 -0
  38. package/plugins/takomi-flow/scripts/lib/flow-outcome.mjs +115 -90
  39. package/plugins/takomi-flow/scripts/lib/flow-project-session.mjs +153 -0
  40. package/plugins/takomi-flow/scripts/lib/flow-ui.mjs +204 -165
  41. package/plugins/takomi-flow/scripts/lib/generation.mjs +190 -90
  42. package/plugins/takomi-flow/scripts/lib/inspect.mjs +81 -81
  43. package/plugins/takomi-flow/scripts/lib/mcp-prompts.mjs +39 -39
  44. package/plugins/takomi-flow/scripts/lib/mcp-resources.mjs +16 -16
  45. package/plugins/takomi-flow/scripts/lib/mcp-tools.mjs +165 -150
  46. package/plugins/takomi-flow/scripts/lib/media.mjs +78 -78
  47. package/plugins/takomi-flow/scripts/lib/observe.mjs +54 -54
  48. package/plugins/takomi-flow/scripts/lib/paths.mjs +37 -37
  49. package/plugins/takomi-flow/scripts/lib/playwright-loader.mjs +23 -23
  50. package/plugins/takomi-flow/scripts/lib/prompts.mjs +72 -72
  51. package/plugins/takomi-flow/scripts/lib/report.mjs +141 -141
  52. package/plugins/takomi-flow/scripts/lib/request-validator.mjs +73 -58
  53. package/plugins/takomi-flow/scripts/lib/request.mjs +66 -55
  54. package/plugins/takomi-flow/scripts/lib/resource-files.mjs +69 -69
  55. package/plugins/takomi-flow/scripts/lib/result.mjs +31 -31
  56. package/plugins/takomi-flow/scripts/lib/review.mjs +44 -44
  57. package/plugins/takomi-flow/scripts/lib/selftest.mjs +153 -153
  58. package/plugins/takomi-flow/scripts/lib/settings-plan.mjs +44 -39
  59. package/plugins/takomi-flow/scripts/lib/templates.mjs +37 -37
  60. package/plugins/takomi-flow/scripts/lib/trusted-chrome.mjs +67 -67
  61. package/plugins/takomi-flow/scripts/lib/workflow.mjs +56 -56
  62. package/plugins/takomi-flow/scripts/mcp-server.mjs +18 -18
  63. package/plugins/takomi-flow/scripts/mcp-smoke.mjs +144 -142
  64. package/plugins/takomi-flow/scripts/takomi-flow.mjs +17 -17
  65. package/plugins/takomi-flow/skills/takomi-flow/SKILL.md +244 -235
  66. package/plugins/takomi-flow/skills/takomi-flow/agents/openai.yaml +7 -7
  67. package/scripts/install-takomi-flow.ps1 +85 -85
  68. package/src/skills-catalog.js +10 -9
@@ -1,56 +1,56 @@
1
- import { createPreparedRequest } from './request.mjs';
2
- import { validateRequestFile } from './request-validator.mjs';
3
- import { generateFromRequest } from './generation.mjs';
4
- import { createSettingsPlan } from './settings-plan.mjs';
5
-
6
- export async function runWorkflow(args = {}) {
7
- const { request, requestPath } = createPreparedRequest(args);
8
- const validation = validateRequestFile(requestPath);
9
- const result = {
10
- schemaVersion: 1,
11
- status: validation.status === 'ok' ? 'prepared' : 'failed',
12
- requestPath,
13
- request,
14
- settingsPlan: createSettingsPlan(request),
15
- validation,
16
- generation: null,
17
- nextActions: nextActions(args, validation),
18
- };
19
- if (validation.status !== 'ok' || !args.submit) return result;
20
- if (!args.allowBrowser) {
21
- result.status = 'blocked';
22
- result.nextActions = ['Set allowBrowser=true to permit opening Flow for generation.'];
23
- return result;
24
- }
25
- result.generation = await generateFromRequest({
26
- request: requestPath,
27
- profileDir: args.profileDir,
28
- browserChannel: args.browserChannel,
29
- cdpUrl: args.cdpUrl,
30
- headless: Boolean(args.headless),
31
- });
32
- result.status = result.generation.status;
33
- result.nextActions = afterGeneration(result.generation);
34
- return result;
35
- }
36
-
37
- function nextActions(args, validation) {
38
- if (validation.status !== 'ok') return ['Fix request validation errors before opening Flow.'];
39
- if (!args.submit) {
40
- return [
41
- 'Review the prepared request file.',
42
- 'Run generate with explicit spend approval when ready.',
43
- ];
44
- }
45
- if (!args.allowBrowser) return ['Set allowBrowser=true to permit opening Flow for generation.'];
46
- return ['Generation was requested; TakomiFlow will still enforce the spend guard.'];
47
- }
48
-
49
- function afterGeneration(generation) {
50
- const actions = [];
51
- if (generation.manualActions?.length) actions.push(...generation.manualActions);
52
- if (generation.errors?.length) actions.push('Review generation errors in run metadata.');
53
- if (generation.assets?.length) actions.push('Run assets/report to catalog downloads and create a handoff.');
54
- if (!actions.length) actions.push('Inspect the run metadata and screenshots.');
55
- return actions;
56
- }
1
+ import { createPreparedRequest } from './request.mjs';
2
+ import { validateRequestFile } from './request-validator.mjs';
3
+ import { generateFromRequest } from './generation.mjs';
4
+ import { createSettingsPlan } from './settings-plan.mjs';
5
+
6
+ export async function runWorkflow(args = {}) {
7
+ const { request, requestPath } = createPreparedRequest(args);
8
+ const validation = validateRequestFile(requestPath);
9
+ const result = {
10
+ schemaVersion: 1,
11
+ status: validation.status === 'ok' ? 'prepared' : 'failed',
12
+ requestPath,
13
+ request,
14
+ settingsPlan: createSettingsPlan(request),
15
+ validation,
16
+ generation: null,
17
+ nextActions: nextActions(args, validation),
18
+ };
19
+ if (validation.status !== 'ok' || !args.submit) return result;
20
+ if (!args.allowBrowser) {
21
+ result.status = 'blocked';
22
+ result.nextActions = ['Set allowBrowser=true to permit opening Flow for generation.'];
23
+ return result;
24
+ }
25
+ result.generation = await generateFromRequest({
26
+ request: requestPath,
27
+ profileDir: args.profileDir,
28
+ browserChannel: args.browserChannel,
29
+ cdpUrl: args.cdpUrl,
30
+ headless: Boolean(args.headless),
31
+ });
32
+ result.status = result.generation.status;
33
+ result.nextActions = afterGeneration(result.generation);
34
+ return result;
35
+ }
36
+
37
+ function nextActions(args, validation) {
38
+ if (validation.status !== 'ok') return ['Fix request validation errors before opening Flow.'];
39
+ if (!args.submit) {
40
+ return [
41
+ 'Review the prepared request file.',
42
+ 'Run generate with explicit spend approval when ready.',
43
+ ];
44
+ }
45
+ if (!args.allowBrowser) return ['Set allowBrowser=true to permit opening Flow for generation.'];
46
+ return ['Generation was requested; TakomiFlow will still enforce the spend guard.'];
47
+ }
48
+
49
+ function afterGeneration(generation) {
50
+ const actions = [];
51
+ if (generation.manualActions?.length) actions.push(...generation.manualActions);
52
+ if (generation.errors?.length) actions.push('Review generation errors in run metadata.');
53
+ if (generation.assets?.length) actions.push('Run assets/report to catalog downloads and create a handoff.');
54
+ if (!actions.length) actions.push('Inspect the run metadata and screenshots.');
55
+ return actions;
56
+ }
@@ -1,18 +1,18 @@
1
- #!/usr/bin/env node
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { registerPrompts } from './lib/mcp-prompts.mjs';
5
- import { registerResources } from './lib/mcp-resources.mjs';
6
- import { registerTools } from './lib/mcp-tools.mjs';
7
-
8
- const server = new McpServer({
9
- name: 'takomi-flow',
10
- version: '0.1.0',
11
- });
12
-
13
- registerTools(server);
14
- registerResources(server);
15
- registerPrompts(server);
16
-
17
- const transport = new StdioServerTransport();
18
- await server.connect(transport);
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { registerPrompts } from './lib/mcp-prompts.mjs';
5
+ import { registerResources } from './lib/mcp-resources.mjs';
6
+ import { registerTools } from './lib/mcp-tools.mjs';
7
+
8
+ const server = new McpServer({
9
+ name: 'takomi-flow',
10
+ version: '0.1.0',
11
+ });
12
+
13
+ registerTools(server);
14
+ registerResources(server);
15
+ registerPrompts(server);
16
+
17
+ const transport = new StdioServerTransport();
18
+ await server.connect(transport);
@@ -1,142 +1,144 @@
1
- #!/usr/bin/env node
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
6
- import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
7
-
8
- const client = new Client({ name: 'takomi-flow-smoke', version: '0.1.0' });
9
- const reviewRunDir = path.join(os.tmpdir(), 'takomi-flow-mcp-smoke-review');
10
- const transport = new StdioClientTransport({
11
- command: 'node',
12
- args: ['scripts/mcp-server.mjs'],
13
- });
14
-
15
- try {
16
- prepareReviewRun(reviewRunDir);
17
- await client.connect(transport);
18
- const tools = await client.listTools();
19
- const capabilities = await client.callTool({
20
- name: 'takomi_flow_capabilities',
21
- arguments: {},
22
- });
23
- const audit = await client.callTool({
24
- name: 'takomi_flow_audit',
25
- arguments: { outputDir: 'C:/Users/johno/.takomi-flow/runs', limit: 3 },
26
- });
27
- const examples = await client.callTool({
28
- name: 'takomi_flow_examples',
29
- arguments: { name: 'cinematic-video' },
30
- });
31
- const plan = await client.callTool({
32
- name: 'takomi_flow_plan',
33
- arguments: {
34
- kind: 'video',
35
- prompt: 'MCP smoke test planned video prompt',
36
- variations: 2,
37
- extractFrames: 2,
38
- },
39
- });
40
- const workflow = await client.callTool({
41
- name: 'takomi_flow_workflow',
42
- arguments: {
43
- kind: 'image',
44
- prompt: 'MCP smoke test image prompt',
45
- variations: 1,
46
- outputDir: 'C:/Users/johno/.takomi-flow/runs',
47
- },
48
- });
49
- const observeBlocked = await client.callTool({
50
- name: 'takomi_flow_observe',
51
- arguments: { allowBrowser: false },
52
- });
53
- const runs = await client.callTool({
54
- name: 'takomi_flow_runs',
55
- arguments: { outputDir: 'C:/Users/johno/.takomi-flow/runs', limit: 3 },
56
- });
57
- const report = await client.callTool({
58
- name: 'takomi_flow_report',
59
- arguments: {
60
- outputDir: 'C:/Users/johno/.takomi-flow/runs',
61
- limit: 3,
62
- reportPath: 'C:/Users/johno/.takomi-flow/runs/mcp-smoke-report.md',
63
- },
64
- });
65
- const review = await client.callTool({
66
- name: 'takomi_flow_review',
67
- arguments: { run: reviewRunDir, frames: 0 },
68
- });
69
- const collect = await client.callTool({
70
- name: 'takomi_flow_collect',
71
- arguments: {
72
- run: reviewRunDir,
73
- targetDir: path.join(reviewRunDir, 'collected'),
74
- frames: 0,
75
- },
76
- });
77
- const resources = await client.listResources();
78
- const contract = await client.readResource({ uri: 'takomi-flow://contract' });
79
- const examplesResource = await client.readResource({ uri: 'takomi-flow://examples' });
80
- const requestSchema = await client.readResource({ uri: 'takomi-flow://schemas/request' });
81
- const resultSchema = await client.readResource({ uri: 'takomi-flow://schemas/result' });
82
- const collectionSchema = await client.readResource({ uri: 'takomi-flow://schemas/collection' });
83
- const prompts = await client.listPrompts();
84
- const videoPrompt = await client.getPrompt({
85
- name: 'takomi_flow_video_workflow',
86
- arguments: { topic: 'test video', variations: '1' },
87
- });
88
- const reviewPrompt = await client.getPrompt({
89
- name: 'takomi_flow_review_workflow',
90
- arguments: { run: reviewRunDir, frames: '2' },
91
- });
92
- const collectPrompt = await client.getPrompt({
93
- name: 'takomi_flow_collect_workflow',
94
- arguments: { run: reviewRunDir, targetDir: path.join(reviewRunDir, 'collected') },
95
- });
96
- console.log(JSON.stringify({
97
- status: 'ok',
98
- toolCount: tools.tools.length,
99
- toolNames: tools.tools.map(tool => tool.name),
100
- capabilitiesStatus: capabilities.structuredContent?.provider || 'unknown',
101
- auditStatus: audit.structuredContent?.status || 'unknown',
102
- examplesStatus: examples.structuredContent?.example?.name || 'unknown',
103
- planStatus: plan.structuredContent?.status || 'unknown',
104
- workflowStatus: workflow.structuredContent?.status || 'unknown',
105
- observeBlockedStatus: observeBlocked.structuredContent?.status || 'unknown',
106
- runsStatus: runs.structuredContent?.schemaVersion || 'unknown',
107
- reportStatus: report.structuredContent?.status || 'unknown',
108
- reviewStatus: review.structuredContent?.status || 'unknown',
109
- collectStatus: collect.structuredContent?.status || 'unknown',
110
- resourceCount: resources.resources.length,
111
- contractBytes: contract.contents?.[0]?.text?.length || 0,
112
- examplesBytes: examplesResource.contents?.[0]?.text?.length || 0,
113
- requestSchemaBytes: requestSchema.contents?.[0]?.text?.length || 0,
114
- resultSchemaBytes: resultSchema.contents?.[0]?.text?.length || 0,
115
- collectionSchemaBytes: collectionSchema.contents?.[0]?.text?.length || 0,
116
- promptCount: prompts.prompts.length,
117
- videoPromptMessages: videoPrompt.messages?.length || 0,
118
- reviewPromptMessages: reviewPrompt.messages?.length || 0,
119
- collectPromptMessages: collectPrompt.messages?.length || 0,
120
- }, null, 2));
121
- } finally {
122
- await client.close();
123
- }
124
-
125
- function prepareReviewRun(runDir) {
126
- const downloadsDir = path.join(runDir, 'downloads');
127
- fs.mkdirSync(downloadsDir, { recursive: true });
128
- const assetPath = path.join(downloadsDir, 'sample.png');
129
- fs.writeFileSync(assetPath, 'takomi-flow-smoke-image');
130
- fs.writeFileSync(path.join(runDir, 'run.json'), `${JSON.stringify({
131
- schemaVersion: 1,
132
- status: 'downloaded',
133
- runId: 'mcp-smoke-review',
134
- command: 'mcp-smoke',
135
- kind: 'image',
136
- assets: [assetPath],
137
- screenshots: [],
138
- errors: [],
139
- manualActions: [],
140
- metadataPath: path.join(runDir, 'run.json'),
141
- }, null, 2)}\n`);
142
- }
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
6
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
7
+
8
+ const client = new Client({ name: 'takomi-flow-smoke', version: '0.1.0' });
9
+ const pluginRoot = path.resolve(import.meta.dirname, '..');
10
+ const reviewRunDir = path.join(os.tmpdir(), 'takomi-flow-mcp-smoke-review');
11
+ const transport = new StdioClientTransport({
12
+ command: 'node',
13
+ args: ['scripts/mcp-server.mjs'],
14
+ cwd: pluginRoot,
15
+ });
16
+
17
+ try {
18
+ prepareReviewRun(reviewRunDir);
19
+ await client.connect(transport);
20
+ const tools = await client.listTools();
21
+ const capabilities = await client.callTool({
22
+ name: 'takomi_flow_capabilities',
23
+ arguments: {},
24
+ });
25
+ const audit = await client.callTool({
26
+ name: 'takomi_flow_audit',
27
+ arguments: { outputDir: 'C:/Users/johno/.takomi-flow/runs', limit: 3 },
28
+ });
29
+ const examples = await client.callTool({
30
+ name: 'takomi_flow_examples',
31
+ arguments: { name: 'cinematic-video' },
32
+ });
33
+ const plan = await client.callTool({
34
+ name: 'takomi_flow_plan',
35
+ arguments: {
36
+ kind: 'video',
37
+ prompt: 'MCP smoke test planned video prompt',
38
+ variations: 2,
39
+ extractFrames: 2,
40
+ },
41
+ });
42
+ const workflow = await client.callTool({
43
+ name: 'takomi_flow_workflow',
44
+ arguments: {
45
+ kind: 'image',
46
+ prompt: 'MCP smoke test image prompt',
47
+ variations: 1,
48
+ outputDir: 'C:/Users/johno/.takomi-flow/runs',
49
+ },
50
+ });
51
+ const observeBlocked = await client.callTool({
52
+ name: 'takomi_flow_observe',
53
+ arguments: { allowBrowser: false },
54
+ });
55
+ const runs = await client.callTool({
56
+ name: 'takomi_flow_runs',
57
+ arguments: { outputDir: 'C:/Users/johno/.takomi-flow/runs', limit: 3 },
58
+ });
59
+ const report = await client.callTool({
60
+ name: 'takomi_flow_report',
61
+ arguments: {
62
+ outputDir: 'C:/Users/johno/.takomi-flow/runs',
63
+ limit: 3,
64
+ reportPath: 'C:/Users/johno/.takomi-flow/runs/mcp-smoke-report.md',
65
+ },
66
+ });
67
+ const review = await client.callTool({
68
+ name: 'takomi_flow_review',
69
+ arguments: { run: reviewRunDir, frames: 0 },
70
+ });
71
+ const collect = await client.callTool({
72
+ name: 'takomi_flow_collect',
73
+ arguments: {
74
+ run: reviewRunDir,
75
+ targetDir: path.join(reviewRunDir, 'collected'),
76
+ frames: 0,
77
+ },
78
+ });
79
+ const resources = await client.listResources();
80
+ const contract = await client.readResource({ uri: 'takomi-flow://contract' });
81
+ const examplesResource = await client.readResource({ uri: 'takomi-flow://examples' });
82
+ const requestSchema = await client.readResource({ uri: 'takomi-flow://schemas/request' });
83
+ const resultSchema = await client.readResource({ uri: 'takomi-flow://schemas/result' });
84
+ const collectionSchema = await client.readResource({ uri: 'takomi-flow://schemas/collection' });
85
+ const prompts = await client.listPrompts();
86
+ const videoPrompt = await client.getPrompt({
87
+ name: 'takomi_flow_video_workflow',
88
+ arguments: { topic: 'test video', variations: '1' },
89
+ });
90
+ const reviewPrompt = await client.getPrompt({
91
+ name: 'takomi_flow_review_workflow',
92
+ arguments: { run: reviewRunDir, frames: '2' },
93
+ });
94
+ const collectPrompt = await client.getPrompt({
95
+ name: 'takomi_flow_collect_workflow',
96
+ arguments: { run: reviewRunDir, targetDir: path.join(reviewRunDir, 'collected') },
97
+ });
98
+ console.log(JSON.stringify({
99
+ status: 'ok',
100
+ toolCount: tools.tools.length,
101
+ toolNames: tools.tools.map(tool => tool.name),
102
+ capabilitiesStatus: capabilities.structuredContent?.provider || 'unknown',
103
+ auditStatus: audit.structuredContent?.status || 'unknown',
104
+ examplesStatus: examples.structuredContent?.example?.name || 'unknown',
105
+ planStatus: plan.structuredContent?.status || 'unknown',
106
+ workflowStatus: workflow.structuredContent?.status || 'unknown',
107
+ observeBlockedStatus: observeBlocked.structuredContent?.status || 'unknown',
108
+ runsStatus: runs.structuredContent?.schemaVersion || 'unknown',
109
+ reportStatus: report.structuredContent?.status || 'unknown',
110
+ reviewStatus: review.structuredContent?.status || 'unknown',
111
+ collectStatus: collect.structuredContent?.status || 'unknown',
112
+ resourceCount: resources.resources.length,
113
+ contractBytes: contract.contents?.[0]?.text?.length || 0,
114
+ examplesBytes: examplesResource.contents?.[0]?.text?.length || 0,
115
+ requestSchemaBytes: requestSchema.contents?.[0]?.text?.length || 0,
116
+ resultSchemaBytes: resultSchema.contents?.[0]?.text?.length || 0,
117
+ collectionSchemaBytes: collectionSchema.contents?.[0]?.text?.length || 0,
118
+ promptCount: prompts.prompts.length,
119
+ videoPromptMessages: videoPrompt.messages?.length || 0,
120
+ reviewPromptMessages: reviewPrompt.messages?.length || 0,
121
+ collectPromptMessages: collectPrompt.messages?.length || 0,
122
+ }, null, 2));
123
+ } finally {
124
+ await client.close();
125
+ }
126
+
127
+ function prepareReviewRun(runDir) {
128
+ const downloadsDir = path.join(runDir, 'downloads');
129
+ fs.mkdirSync(downloadsDir, { recursive: true });
130
+ const assetPath = path.join(downloadsDir, 'sample.png');
131
+ fs.writeFileSync(assetPath, 'takomi-flow-smoke-image');
132
+ fs.writeFileSync(path.join(runDir, 'run.json'), `${JSON.stringify({
133
+ schemaVersion: 1,
134
+ status: 'downloaded',
135
+ runId: 'mcp-smoke-review',
136
+ command: 'mcp-smoke',
137
+ kind: 'image',
138
+ assets: [assetPath],
139
+ screenshots: [],
140
+ errors: [],
141
+ manualActions: [],
142
+ metadataPath: path.join(runDir, 'run.json'),
143
+ }, null, 2)}\n`);
144
+ }
@@ -1,17 +1,17 @@
1
- #!/usr/bin/env node
2
- import { parseArgs, printUsage } from './lib/args.mjs';
3
- import { handleCommand } from './lib/commands.mjs';
4
-
5
- const args = parseArgs(process.argv.slice(2));
6
- const command = args._[0];
7
-
8
- try {
9
- if (!command || args.help) {
10
- printUsage();
11
- } else {
12
- await handleCommand(command, args);
13
- }
14
- } catch (error) {
15
- console.error(`[TakomiFlow] ${error.message}`);
16
- process.exitCode = 1;
17
- }
1
+ #!/usr/bin/env node
2
+ import { parseArgs, printUsage } from './lib/args.mjs';
3
+ import { handleCommand } from './lib/commands.mjs';
4
+
5
+ const args = parseArgs(process.argv.slice(2));
6
+ const command = args._[0];
7
+
8
+ try {
9
+ if (!command || args.help) {
10
+ printUsage();
11
+ } else {
12
+ await handleCommand(command, args);
13
+ }
14
+ } catch (error) {
15
+ console.error(`[TakomiFlow] ${error.message}`);
16
+ process.exitCode = 1;
17
+ }