@remixmate/cli 0.9.71 → 0.9.73

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 (181) hide show
  1. package/LICENSE +45 -21
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/dist/argv.js +1 -51
  5. package/dist/auth/auth-lock.js +1 -100
  6. package/dist/auth/auto-login.js +7 -75
  7. package/dist/auth/commands.js +40 -290
  8. package/dist/auth/credential-store.js +1 -143
  9. package/dist/auth/device-flow-runner.js +13 -110
  10. package/dist/auth/device-flow.js +1 -132
  11. package/dist/auth/ensure.js +1 -62
  12. package/dist/auth/environment.js +1 -69
  13. package/dist/auth/pending-store.js +1 -45
  14. package/dist/auth/resolve.js +1 -44
  15. package/dist/billing.js +3 -76
  16. package/dist/capabilities.js +1 -75
  17. package/dist/cli.js +39 -211
  18. package/dist/diagnostics.js +2 -70
  19. package/dist/doctor.js +9 -188
  20. package/dist/errors.js +1 -33
  21. package/dist/exec.js +4 -47
  22. package/dist/handlers/gen-digital-human.js +33 -264
  23. package/dist/handlers/gen-image.js +9 -113
  24. package/dist/handlers/gen-post.js +15 -188
  25. package/dist/handlers/gen-video.js +7 -185
  26. package/dist/handlers/gen-voice.js +19 -133
  27. package/dist/handlers/index.js +1 -20
  28. package/dist/handlers/shared.js +1 -66
  29. package/dist/handlers/template-init.js +1 -21
  30. package/dist/http.js +3 -155
  31. package/dist/index.js +1 -8
  32. package/dist/install.js +40 -448
  33. package/dist/manifest.json +53 -13
  34. package/dist/progress.js +2 -15
  35. package/dist/project/commands.js +34 -156
  36. package/dist/project/host.js +1 -151
  37. package/dist/project/resolve.js +1 -65
  38. package/dist/project/store.js +2 -97
  39. package/dist/project/take.js +1 -106
  40. package/dist/project/trace.js +5 -278
  41. package/dist/registry.js +3 -70
  42. package/dist/runner.js +7 -225
  43. package/dist/skill-schema.js +1 -194
  44. package/dist/template/args.js +1 -69
  45. package/dist/template/check.js +2 -30
  46. package/dist/template/commands.js +34 -163
  47. package/dist/template/constants.js +1 -46
  48. package/dist/template/init.js +5 -133
  49. package/dist/template/list.js +1 -46
  50. package/dist/template/preview.js +7 -318
  51. package/dist/template/proc.js +1 -43
  52. package/dist/template/project.js +6 -161
  53. package/dist/template/publish.js +5 -185
  54. package/dist/template/render-client.js +2 -79
  55. package/dist/template/upgrade.js +4 -123
  56. package/dist/text.js +1 -15
  57. package/package.json +2 -35
  58. package/skills/doc-parse/scripts/extract_via_render.py +32 -32
  59. package/skills/export-jianying/scripts/gen_jianying_draft.py +188 -188
  60. package/skills/gen-post/SKILL.md +23 -13
  61. package/skills/gen-post/skill.json +9 -10
  62. package/skills/gen-script/SKILL.md +23 -1
  63. package/skills/gen-script/scripts/gen_script.py +644 -551
  64. package/skills/gen-script/skill.json +12 -0
  65. package/skills/gen-script/version.json +1 -1
  66. package/skills/prepare-video-assets/scripts/prepare_video_assets.py +21 -21
  67. package/skills/render-video/scripts/_chrome_vendor.py +17 -17
  68. package/skills/render-video/scripts/_digital_human_segments.py +34 -34
  69. package/skills/render-video/scripts/_video_probe.py +33 -33
  70. package/skills/render-video/scripts/_vod_polling.py +13 -13
  71. package/skills/render-video/scripts/remote_renderer_client.py +42 -42
  72. package/skills/render-video/scripts/render_video.py +639 -639
  73. package/skills/render-video/scripts/required_props.py +37 -37
  74. package/skills/render-video/scripts/upload_video.py +35 -35
  75. package/skills/render-video/version.json +1 -1
  76. package/skills/template-registry/SKILL.md +16 -0
  77. package/skills/template-registry/scripts/countdown_spec.py +92 -92
  78. package/skills/template-registry/scripts/doc_extract.py +40 -40
  79. package/skills/template-registry/scripts/list_templates.py +303 -191
  80. package/skills/template-registry/scripts/log_diagnostics.py +1 -1
  81. package/skills/template-registry/scripts/match_template.py +87 -87
  82. package/skills/template-registry/scripts/payload_hydrator.py +89 -89
  83. package/skills/template-registry/scripts/registry_loader.py +159 -159
  84. package/skills/template-registry/scripts/render_job_client.py +75 -75
  85. package/skills/template-registry/scripts/showcase_loader.py +44 -44
  86. package/skills/template-registry/skill.json +4 -1
  87. package/skills/template-registry/version.json +1 -1
  88. package/skills/template-registry/video_dsl/runtime/__init__.py +8 -8
  89. package/skills/template-registry/video_dsl/runtime/dsl_validator.py +329 -329
  90. package/skills/template-registry/video_dsl/runtime/narration_budget.py +36 -36
  91. package/skills/template-registry/video_dsl/runtime/payload_contract.py +7 -7
  92. package/skills/template-registry/video_dsl/runtime/prompt_enhancer.py +98 -98
  93. package/skills/template-registry/video_dsl/runtime/timeline_compiler.py +127 -127
  94. package/skills/template-registry/video_dsl/schema/video-dsl-v1alpha1.json +14 -1
  95. package/skills/video-parser/scripts/analyze_video.py +173 -173
  96. package/skills/video-parser/scripts/deconstruct_video.py +91 -91
  97. package/skills/video-parser/scripts/parse_via_render.py +21 -21
  98. package/skills/web-screenshot/scripts/_media_screenshot/__init__.py +4 -4
  99. package/skills/web-screenshot/scripts/_media_screenshot/bootstrap.py +7 -7
  100. package/skills/web-screenshot/scripts/_media_screenshot/browser.py +4 -4
  101. package/skills/web-screenshot/scripts/_media_screenshot/cli_args.py +4 -4
  102. package/skills/web-screenshot/scripts/_media_screenshot/js_loader.py +2 -2
  103. package/skills/web-screenshot/scripts/_media_screenshot/overlay.py +1 -1
  104. package/skills/web-screenshot/scripts/_media_screenshot/reader.py +40 -40
  105. package/skills/web-screenshot/scripts/_media_screenshot/recording.py +11 -11
  106. package/skills/web-screenshot/scripts/_media_screenshot/scenes/__init__.py +8 -8
  107. package/skills/web-screenshot/scripts/_media_screenshot/scenes/arrow.py +2 -2
  108. package/skills/web-screenshot/scripts/_media_screenshot/scenes/caption.py +1 -1
  109. package/skills/web-screenshot/scripts/_media_screenshot/scenes/click.py +1 -1
  110. package/skills/web-screenshot/scripts/_media_screenshot/scenes/code_lines.py +5 -5
  111. package/skills/web-screenshot/scripts/_media_screenshot/scenes/focus.py +1 -1
  112. package/skills/web-screenshot/scripts/_media_screenshot/scenes/highlight.py +3 -3
  113. package/skills/web-screenshot/scripts/_media_screenshot/scenes/hover.py +1 -1
  114. package/skills/web-screenshot/scripts/_media_screenshot/scenes/redact.py +1 -1
  115. package/skills/web-screenshot/scripts/_media_screenshot/scenes/scroll.py +1 -1
  116. package/skills/web-screenshot/scripts/_media_screenshot/scenes/sequence.py +1 -1
  117. package/skills/web-screenshot/scripts/_media_screenshot/scenes/title_card.py +1 -1
  118. package/skills/web-screenshot/scripts/_media_screenshot/scenes/type.py +1 -1
  119. package/skills/web-screenshot/scripts/_media_screenshot/scenes/wait.py +1 -1
  120. package/skills/web-screenshot/scripts/_media_screenshot/scenes/zoom.py +2 -2
  121. package/skills/web-screenshot/scripts/_media_screenshot/screenshot.py +15 -15
  122. package/skills/web-screenshot/scripts/_media_screenshot/storyboard.py +2 -2
  123. package/skills/web-screenshot/scripts/_media_screenshot/template.py +11 -11
  124. package/skills/web-screenshot/scripts/_media_screenshot/trim.py +10 -10
  125. package/skills/web-screenshot/scripts/_media_screenshot/urlguard.py +22 -22
  126. package/skills/web-screenshot/scripts/_media_upload.py +33 -33
  127. package/skills/web-screenshot/scripts/read_page.py +15 -15
  128. package/skills/web-screenshot/scripts/record.py +26 -26
  129. package/skills/web-screenshot/scripts/screenshot.py +5 -5
  130. package/dist/argv.d.ts +0 -15
  131. package/dist/auth/auth-lock.d.ts +0 -26
  132. package/dist/auth/auto-login.d.ts +0 -20
  133. package/dist/auth/commands.d.ts +0 -8
  134. package/dist/auth/credential-store.d.ts +0 -60
  135. package/dist/auth/device-flow-runner.d.ts +0 -58
  136. package/dist/auth/device-flow.d.ts +0 -52
  137. package/dist/auth/ensure.d.ts +0 -55
  138. package/dist/auth/environment.d.ts +0 -38
  139. package/dist/auth/pending-store.d.ts +0 -33
  140. package/dist/auth/resolve.d.ts +0 -30
  141. package/dist/billing.d.ts +0 -44
  142. package/dist/capabilities.d.ts +0 -63
  143. package/dist/cli.d.ts +0 -13
  144. package/dist/diagnostics.d.ts +0 -24
  145. package/dist/doctor.d.ts +0 -22
  146. package/dist/errors.d.ts +0 -29
  147. package/dist/exec.d.ts +0 -18
  148. package/dist/handlers/gen-digital-human.d.ts +0 -17
  149. package/dist/handlers/gen-image.d.ts +0 -20
  150. package/dist/handlers/gen-post.d.ts +0 -21
  151. package/dist/handlers/gen-video.d.ts +0 -19
  152. package/dist/handlers/gen-voice.d.ts +0 -26
  153. package/dist/handlers/index.d.ts +0 -20
  154. package/dist/handlers/shared.d.ts +0 -26
  155. package/dist/handlers/template-init.d.ts +0 -10
  156. package/dist/http.d.ts +0 -72
  157. package/dist/index.d.ts +0 -9
  158. package/dist/install.d.ts +0 -71
  159. package/dist/progress.d.ts +0 -23
  160. package/dist/project/commands.d.ts +0 -19
  161. package/dist/project/host.d.ts +0 -91
  162. package/dist/project/resolve.d.ts +0 -43
  163. package/dist/project/store.d.ts +0 -31
  164. package/dist/project/take.d.ts +0 -50
  165. package/dist/project/trace.d.ts +0 -98
  166. package/dist/registry.d.ts +0 -30
  167. package/dist/runner.d.ts +0 -39
  168. package/dist/skill-schema.d.ts +0 -138
  169. package/dist/template/args.d.ts +0 -25
  170. package/dist/template/check.d.ts +0 -23
  171. package/dist/template/commands.d.ts +0 -25
  172. package/dist/template/constants.d.ts +0 -39
  173. package/dist/template/init.d.ts +0 -28
  174. package/dist/template/list.d.ts +0 -23
  175. package/dist/template/preview.d.ts +0 -60
  176. package/dist/template/proc.d.ts +0 -26
  177. package/dist/template/project.d.ts +0 -47
  178. package/dist/template/publish.d.ts +0 -43
  179. package/dist/template/render-client.d.ts +0 -39
  180. package/dist/template/upgrade.d.ts +0 -44
  181. package/dist/text.d.ts +0 -8
package/dist/progress.js CHANGED
@@ -1,15 +1,2 @@
1
- /**
2
- * Progress reporting — emits __progress__ JSON lines that ab-agent's
3
- * executor parses (see apps/ab-agent/src/skills/executor.ts).
4
- *
5
- * Always writes to stdout because the consumer reads stdout line-by-line.
6
- * Each event is a single JSON object on its own line, with the marker
7
- * field `__progress__: true` so non-progress stdout content is ignored.
8
- *
9
- * The consumer flattens the entire parsed JSON into `extra`, so any
10
- * additional context (model id, generationId, ...) can be passed as
11
- * top-level keys and will reach the SSE client unchanged.
12
- */
13
- export function emitProgress(ev) {
14
- process.stdout.write(JSON.stringify({ __progress__: true, ...ev }) + '\n');
15
- }
1
+ var e=Object.defineProperty;var s=(r,t)=>e(r,"name",{value:t,configurable:!0});function i(r){process.stdout.write(JSON.stringify({__progress__:!0,...r})+`
2
+ `)}s(i,"emitProgress");export{i as emitProgress};
@@ -1,156 +1,34 @@
1
- /**
2
- * `remixmate project ...` and `remixmate host probe`.
3
- *
4
- * `project use` is the low-friction way to keep CLI output out of 「未分类」:
5
- * say it once per repo (or once globally) instead of passing --project on every
6
- * call — an agent won't pass a flag it wasn't told about.
7
- *
8
- * `host probe` exists so onboarding an unknown agent shell is a minute's work
9
- * rather than a reverse-engineering session: run it inside the new host, read
10
- * off the session variable, add one row to HOST_PROVIDERS.
11
- */
12
- import { EXIT, SkillError } from '../errors.js';
13
- import { resolveApiBaseUrl, resolveHttpContext } from '../http.js';
14
- import { detectHostLabel, probeSessionVarNames, resolveTakeKey } from './host.js';
15
- import { fetchDefaultProject, listProjects } from './resolve.js';
16
- import { clearBinding, readBinding, writeBinding, PROJECTS_FILE } from './store.js';
17
- export const PROJECT_VERB = 'project';
18
- export const HOST_VERB = 'host';
19
- function projectLabel(p) {
20
- return p.displayName || p.fullName || p.sourceUrl || '(未命名)';
21
- }
22
- async function ctxFor(sub) {
23
- return await resolveHttpContext(`project-${sub}`);
24
- }
25
- async function cmdList() {
26
- const ctx = await ctxFor('list');
27
- const projects = await listProjects(ctx);
28
- if (projects.length === 0) {
29
- process.stdout.write('(还没有项目。渲染一次即可自动创建「未分类」)\n');
30
- return EXIT.OK;
31
- }
32
- const bound = await readBinding(ctx.apiBaseUrl);
33
- for (const p of projects) {
34
- const marks = [p.isDefault ? '默认' : '', bound?.projectId === p.id ? '← 当前绑定' : '']
35
- .filter(Boolean)
36
- .join(' ');
37
- process.stdout.write(` ${p.id.padEnd(20)} ${projectLabel(p)}${marks ? ` ${marks}` : ''}\n`);
38
- }
39
- return EXIT.OK;
40
- }
41
- async function cmdUse(args) {
42
- const global = args.includes('--global');
43
- const projectId = args.find((a) => !a.startsWith('-'));
44
- if (!projectId) {
45
- process.stderr.write('用法: remixmate project use <prj_xxx> [--global]\n');
46
- return EXIT.USAGE;
47
- }
48
- const ctx = await ctxFor('use');
49
- // Verify before persisting: a typo'd uid would otherwise sit in the config and
50
- // silently send every later render to the default project.
51
- const projects = await listProjects(ctx);
52
- const match = projects.find((p) => p.id === projectId);
53
- if (!match) {
54
- process.stderr.write(`❌ 项目不存在或不属于当前账号: ${projectId}\n 用 remixmate project list 查看可用项目。\n`);
55
- return EXIT.USAGE;
56
- }
57
- await writeBinding(ctx.apiBaseUrl, projectId, global ? 'default' : 'path');
58
- const scopeText = global ? '全局默认' : `当前目录 (${process.cwd()})`;
59
- process.stdout.write(`✅ 已绑定到 ${projectLabel(match)} [${projectId}]\n 作用域: ${scopeText}\n`);
60
- if (!global) {
61
- // Not a hypothetical: WorkBuddy spawns ~/WorkBuddy/<timestamp> per conversation,
62
- // so a path binding made there is gone by the next conversation.
63
- process.stdout.write(' 提示: 若宿主每次会话都换工作目录,请改用 --global。\n');
64
- }
65
- return EXIT.OK;
66
- }
67
- async function cmdUnuse(args) {
68
- const global = args.includes('--global');
69
- const apiBaseUrl = resolveApiBaseUrl();
70
- const removed = await clearBinding(apiBaseUrl, global ? 'default' : 'path');
71
- process.stdout.write(removed ? '✅ 绑定已清除\n' : 'ℹ️ 没有可清除的绑定\n');
72
- return EXIT.OK;
73
- }
74
- async function cmdShow() {
75
- const apiBaseUrl = resolveApiBaseUrl();
76
- const bound = await readBinding(apiBaseUrl);
77
- process.stdout.write(`后端: ${apiBaseUrl}\n`);
78
- process.stdout.write(`配置文件: ${PROJECTS_FILE}\n`);
79
- if (bound) {
80
- const scope = bound.scope === 'path' ? `目录绑定 (${process.cwd()})` : '全局默认绑定';
81
- process.stdout.write(`绑定项目: ${bound.projectId} [${scope}]\n`);
82
- }
83
- else {
84
- process.stdout.write('绑定项目: (无) — 产物会落进默认项目「未分类」\n');
85
- }
86
- const envOverride = (process.env.REMIXMATE_PROJECT_ID ?? '').trim();
87
- if (envOverride) {
88
- process.stdout.write(`⚠️ REMIXMATE_PROJECT_ID=${envOverride} 会覆盖上面的绑定\n`);
89
- }
90
- return EXIT.OK;
91
- }
92
- async function cmdDefault() {
93
- const ctx = await ctxFor('default');
94
- const p = await fetchDefaultProject(ctx);
95
- process.stdout.write(`${p.id} ${projectLabel(p)}\n`);
96
- return EXIT.OK;
97
- }
98
- export async function runProjectCommand(argv) {
99
- const sub = argv[0] ?? 'show';
100
- try {
101
- switch (sub) {
102
- case 'list':
103
- return await cmdList();
104
- case 'use':
105
- return await cmdUse(argv.slice(1));
106
- case 'unuse':
107
- return await cmdUnuse(argv.slice(1));
108
- case 'show':
109
- return await cmdShow();
110
- case 'default':
111
- return await cmdDefault();
112
- default:
113
- process.stderr.write(`❌ 未知子命令: ${sub}\n用法: remixmate project <list|use|unuse|show|default>\n`);
114
- return EXIT.USAGE;
115
- }
116
- }
117
- catch (err) {
118
- if (err instanceof SkillError) {
119
- process.stderr.write(err.message + '\n');
120
- return err.exitCode;
121
- }
122
- process.stderr.write(`❌ ${err.message}\n`);
123
- return EXIT.ERROR;
124
- }
125
- }
126
- /**
127
- * Report what the CLI can see about its host. Prints variable NAMES only —
128
- * an environment dump is a routine way to leak tokens into a chat transcript.
129
- */
130
- export async function runHostCommand(argv) {
131
- const sub = argv[0] ?? 'probe';
132
- if (sub !== 'probe') {
133
- process.stderr.write(`❌ 未知子命令: ${sub}\n用法: remixmate host probe\n`);
134
- return EXIT.USAGE;
135
- }
136
- const host = detectHostLabel();
137
- const take = resolveTakeKey(undefined);
138
- process.stdout.write(`识别宿主: ${host || '(未识别)'}\n`);
139
- process.stdout.write(`分组键: ${take.key || '(无 — 每次渲染会各自成为一个 take)'}\n`);
140
- process.stdout.write(`来源: ${take.source}\n`);
141
- const names = probeSessionVarNames();
142
- process.stdout.write('\n环境里疑似会话标识的变量(仅名称,不含取值):\n');
143
- if (names.length === 0) {
144
- process.stdout.write(' (无)\n');
145
- }
146
- else {
147
- for (const n of names)
148
- process.stdout.write(` ${n}\n`);
149
- }
150
- if (!host && names.length > 0) {
151
- process.stdout.write('\n宿主未被识别。若上面某个变量在整个会话期间保持不变,可以:\n' +
152
- ' 1) 临时方案: export REMIXMATE_TAKE_KEY="$该变量"\n' +
153
- ' 2) 长期方案: 在 src/project/host.ts 的 HOST_PROVIDERS 里加一行\n');
154
- }
155
- return EXIT.OK;
156
- }
1
+ var m=Object.defineProperty;var n=(t,e)=>m(t,"name",{value:e,configurable:!0});import{EXIT as o,SkillError as $}from"../errors.js";import{resolveApiBaseUrl as d,resolveHttpContext as E}from"../http.js";import{detectHostLabel as h,probeSessionVarNames as x,resolveTakeKey as j}from"./host.js";import{fetchDefaultProject as b,listProjects as l}from"./resolve.js";import{clearBinding as O,readBinding as w,writeBinding as R,PROJECTS_FILE as T}from"./store.js";const k="project",D="host";function u(t){return t.displayName||t.fullName||t.sourceUrl||"(未命名)"}n(u,"projectLabel");async function p(t){return await E(`project-${t}`)}n(p,"ctxFor");async function y(){const t=await p("list"),e=await l(t);if(e.length===0)return process.stdout.write(`(还没有项目。渲染一次即可自动创建「未分类」)
2
+ `),o.OK;const s=await w(t.apiBaseUrl);for(const r of e){const c=[r.isDefault?"默认":"",s?.projectId===r.id?"← 当前绑定":""].filter(Boolean).join(" ");process.stdout.write(` ${r.id.padEnd(20)} ${u(r)}${c?` ${c}`:""}
3
+ `)}return o.OK}n(y,"cmdList");async function U(t){const e=t.includes("--global"),s=t.find(a=>!a.startsWith("-"));if(!s)return process.stderr.write(`用法: remixmate project use <prj_xxx> [--global]
4
+ `),o.USAGE;const r=await p("use"),i=(await l(r)).find(a=>a.id===s);if(!i)return process.stderr.write(`❌ 项目不存在或不属于当前账号: ${s}
5
+ 用 remixmate project list 查看可用项目。
6
+ `),o.USAGE;await R(r.apiBaseUrl,s,e?"default":"path");const f=e?"全局默认":`当前目录 (${process.cwd()})`;return process.stdout.write(`✅ 已绑定到 ${u(i)} [${s}]
7
+ 作用域: ${f}
8
+ `),e||process.stdout.write(` 提示: 若宿主每次会话都换工作目录,请改用 --global。
9
+ `),o.OK}n(U,"cmdUse");async function g(t){const e=t.includes("--global"),s=d(),r=await O(s,e?"default":"path");return process.stdout.write(r?`✅ 绑定已清除
10
+ `:`ℹ️ 没有可清除的绑定
11
+ `),o.OK}n(g,"cmdUnuse");async function B(){const t=d(),e=await w(t);if(process.stdout.write(`后端: ${t}
12
+ `),process.stdout.write(`配置文件: ${T}
13
+ `),e){const r=e.scope==="path"?`目录绑定 (${process.cwd()})`:"全局默认绑定";process.stdout.write(`绑定项目: ${e.projectId} [${r}]
14
+ `)}else process.stdout.write(`绑定项目: (无) — 产物会落进默认项目「未分类」
15
+ `);const s=(process.env.REMIXMATE_PROJECT_ID??"").trim();return s&&process.stdout.write(`⚠️ REMIXMATE_PROJECT_ID=${s} 会覆盖上面的绑定
16
+ `),o.OK}n(B,"cmdShow");async function I(){const t=await p("default"),e=await b(t);return process.stdout.write(`${e.id} ${u(e)}
17
+ `),o.OK}n(I,"cmdDefault");async function M(t){const e=t[0]??"show";try{switch(e){case"list":return await y();case"use":return await U(t.slice(1));case"unuse":return await g(t.slice(1));case"show":return await B();case"default":return await I();default:return process.stderr.write(`❌ 未知子命令: ${e}
18
+ 用法: remixmate project <list|use|unuse|show|default>
19
+ `),o.USAGE}}catch(s){return s instanceof $?(process.stderr.write(s.message+`
20
+ `),s.exitCode):(process.stderr.write(`❌ ${s.message}
21
+ `),o.ERROR)}}n(M,"runProjectCommand");async function v(t){const e=t[0]??"probe";if(e!=="probe")return process.stderr.write(`❌ 未知子命令: ${e}
22
+ 用法: remixmate host probe
23
+ `),o.USAGE;const s=h(),r=j(void 0);process.stdout.write(`识别宿主: ${s||"(未识别)"}
24
+ `),process.stdout.write(`分组键: ${r.key||"(无 — 每次渲染会各自成为一个 take)"}
25
+ `),process.stdout.write(`来源: ${r.source}
26
+ `);const c=x();if(process.stdout.write(`
27
+ 环境里疑似会话标识的变量(仅名称,不含取值):
28
+ `),c.length===0)process.stdout.write(` (无)
29
+ `);else for(const i of c)process.stdout.write(` ${i}
30
+ `);return!s&&c.length>0&&process.stdout.write(`
31
+ 宿主未被识别。若上面某个变量在整个会话期间保持不变,可以:
32
+ 1) 临时方案: export REMIXMATE_TAKE_KEY="$该变量"
33
+ 2) 长期方案: 在 src/project/host.ts 的 HOST_PROVIDERS 里加一行
34
+ `),o.OK}n(v,"runHostCommand");export{D as HOST_VERB,k as PROJECT_VERB,v as runHostCommand,M as runProjectCommand};
@@ -1,151 +1 @@
1
- /**
2
- * Host detection — which agent shell is this CLI running inside, and what is
3
- * its conversation id?
4
- *
5
- * The id is used as the *grouping key* for takes: every render fired from the
6
- * same host conversation lands in one VideoProject as successive takes. The
7
- * creative loop ("generate → watch → shorten the intro → re-render") spans
8
- * multiple skill invocations and multiple render jobs, so the conversation —
9
- * not the render job — is its natural boundary.
10
- *
11
- * Everything here reads the **child process environment only**. We deliberately
12
- * do not speak any host's private IPC (Codex exposes its thread id through an
13
- * App Server JSON-RPC channel, and finding "the current thread" there means
14
- * matching on cwd + status + recency — a heuristic, not an identity lookup,
15
- * which would silently group takes wrong). A host that hands us nothing simply
16
- * degrades one rung; see resolveTakeKey().
17
- *
18
- * See docs/product/cli/cli-project-binding-design.md §5.1 and appendix A.
19
- */
20
- /**
21
- * Adding a host is a data-only change: append a row, touch nothing else.
22
- * Run `remixmate host probe` inside the new host to discover its variable names.
23
- *
24
- * ⚠️ ORDER IS LOAD-BEARING. CodeBuddy also sets `CLAUDE_SESSION_ID` (same value
25
- * as its own id), while real Claude Code uses the longer `CLAUDE_CODE_*` prefix.
26
- * Detecting Claude Code first — or matching on a bare `CLAUDE_` prefix — would
27
- * mislabel every CodeBuddy session.
28
- *
29
- * ⚠️ Prefer the ROOT session over a child/sub-agent one. Claude Code exposes
30
- * both (`CLAUDE_CODE_HOST_SESSION_ID` alongside a per-subagent
31
- * `CLAUDE_CODE_SESSION_ID`); grouping must follow the root so a render fired
32
- * from a subagent still joins the main take.
33
- */
34
- export const HOST_PROVIDERS = [
35
- {
36
- host: 'codebuddy',
37
- detect: (e) => !!e.CODEBUDDY_SESSION_ID || e.CODEBUDDY_HOST != null,
38
- sessionVars: ['CODEBUDDY_SESSION_ID'],
39
- },
40
- {
41
- host: 'claude-code',
42
- detect: (e) => e.CLAUDECODE === '1' || !!e.CLAUDE_CODE_SESSION_ID,
43
- sessionVars: ['CLAUDE_CODE_HOST_SESSION_ID', 'CLAUDE_CODE_SESSION_ID'],
44
- },
45
- // Untested placeholders — verify with `remixmate host probe` before trusting.
46
- { host: 'qoder', detect: (e) => !!e.QODER_SESSION_ID, sessionVars: ['QODER_SESSION_ID'] },
47
- { host: 'trae', detect: (e) => !!e.TRAE_SESSION_ID, sessionVars: ['TRAE_SESSION_ID'] },
48
- ];
49
- /** Identify the host and its root session id, or null when unrecognised. */
50
- export function detectHostSession(env = process.env) {
51
- for (const provider of HOST_PROVIDERS) {
52
- if (!provider.detect(env))
53
- continue;
54
- for (const name of provider.sessionVars) {
55
- const value = (env[name] ?? '').trim();
56
- if (value)
57
- return { host: provider.host, sessionId: value };
58
- }
59
- // Recognised the host but it gave us no id — don't fall through to a later
60
- // provider, that would mislabel. Report the host, leave grouping to a lower rung.
61
- return null;
62
- }
63
- return null;
64
- }
65
- /**
66
- * Explicit host declaration, checked *before* the detection table.
67
- *
68
- * Two callers, both of which detection cannot serve:
69
- *
70
- * - **WorkBuddy (ab-agent)** spawns this CLI itself. Sniffing our own process
71
- * would turn a fact we already know into a guess — and a fragile one, since
72
- * the generic variables it injects (CONVERSATION_ID …) are exactly the kind
73
- * another host might also set. It declares `REMIXMATE_HOST=workbuddy`.
74
- * - **Codex** does not expose anything: per the appendix-A survey it
75
- * "官方明确不通过环境变量暴露". No `detect()` we could write would be honest.
76
- * A user or the host itself can export `REMIXMATE_HOST=codex` and get the
77
- * provenance label without waiting for a CLI release.
78
- *
79
- * Symmetric with `REMIXMATE_TAKE_KEY`: that one overrides *grouping*, this one
80
- * overrides *identity*. They are independent — declaring a host does not group,
81
- * and grouping does not imply a host.
82
- */
83
- const HOST_OVERRIDE_VAR = 'REMIXMATE_HOST';
84
- /**
85
- * Normalise a declared host label.
86
- *
87
- * `video_project.client_host` is `varchar(32)`, and the value is rendered as a
88
- * badge, so free-form input gets slugified rather than trusted: lowercase,
89
- * non-alphanumerics collapsed to `-`, capped at 32. Anything that normalises to
90
- * empty is treated as absent — an unusable label should degrade to "no badge",
91
- * never to a garbage one.
92
- */
93
- export function normaliseHostLabel(raw) {
94
- return (raw ?? '')
95
- .trim()
96
- .toLowerCase()
97
- .replace(/[^a-z0-9]+/g, '-')
98
- .replace(/^-+|-+$/g, '')
99
- .slice(0, 32);
100
- }
101
- /**
102
- * Host label for provenance, even when no session id could be read.
103
- *
104
- * Declaration wins over detection: the declaring party knows, the table guesses.
105
- */
106
- export function detectHostLabel(env = process.env) {
107
- const declared = normaliseHostLabel(env[HOST_OVERRIDE_VAR]);
108
- if (declared)
109
- return declared;
110
- return HOST_PROVIDERS.find((p) => p.detect(env))?.host ?? '';
111
- }
112
- /**
113
- * Resolve the take grouping key.
114
- *
115
- * 1. a recognised host's root session id → "<host>:<id>"
116
- * 2. REMIXMATE_TAKE_KEY → "custom:<value>"
117
- * 3. the render job id → "job:<id>"
118
- *
119
- * Rung 2 is the escape hatch that matters: an unsupported host (or a user on
120
- * Codex) can export one variable and get correct grouping without waiting for a
121
- * CLI release. Rung 3 keeps the feature working everywhere, at the cost of
122
- * splitting one video's iterations across takes — acceptable as a floor, not as
123
- * a default.
124
- */
125
- export function resolveTakeKey(jobId, env = process.env) {
126
- const host = detectHostLabel(env);
127
- const detected = detectHostSession(env);
128
- if (detected) {
129
- // key 的命名空间用**探测到的**宿主,不用声明值:它是既有分组的命名空间,
130
- // 跟着声明变会把同一会话的 take 拆成两组。而 host(溯源标签)以声明为准。
131
- return { key: `${detected.host}:${detected.sessionId}`, host, source: 'host' };
132
- }
133
- const override = (env.REMIXMATE_TAKE_KEY ?? '').trim();
134
- if (override)
135
- return { key: `custom:${override}`, host, source: 'env-override' };
136
- if (jobId && jobId > 0)
137
- return { key: `job:${jobId}`, host, source: 'render-job' };
138
- return { key: '', host, source: 'none' };
139
- }
140
- /**
141
- * Environment variable names that look like a session/thread identifier.
142
- * Used by `remixmate host probe` to onboard an unknown host in a minute.
143
- * Returns NAMES ONLY — values may carry tokens and are never printed.
144
- */
145
- export function probeSessionVarNames(env = process.env) {
146
- const interesting = /(SESSION|THREAD|CONVERSATION|CHAT|TASK)/i;
147
- const secretish = /(TOKEN|KEY|SECRET|AUTH|PASSWORD|COOKIE|CREDENTIAL)/i;
148
- return Object.keys(env)
149
- .filter((name) => interesting.test(name) && !secretish.test(name))
150
- .sort();
151
- }
1
+ var E=Object.defineProperty;var o=(e,t)=>E(e,"name",{value:t,configurable:!0});const c=[{host:"codebuddy",detect:o(e=>!!e.CODEBUDDY_SESSION_ID||e.CODEBUDDY_HOST!=null,"detect"),sessionVars:["CODEBUDDY_SESSION_ID"]},{host:"claude-code",detect:o(e=>e.CLAUDECODE==="1"||!!e.CLAUDE_CODE_SESSION_ID,"detect"),sessionVars:["CLAUDE_CODE_HOST_SESSION_ID","CLAUDE_CODE_SESSION_ID"]},{host:"qoder",detect:o(e=>!!e.QODER_SESSION_ID,"detect"),sessionVars:["QODER_SESSION_ID"]},{host:"trae",detect:o(e=>!!e.TRAE_SESSION_ID,"detect"),sessionVars:["TRAE_SESSION_ID"]}];function S(e=process.env){for(const t of c)if(t.detect(e)){for(const s of t.sessionVars){const r=(e[s]??"").trim();if(r)return{host:t.host,sessionId:r}}return null}return null}o(S,"detectHostSession");const i="REMIXMATE_HOST";function D(e){return(e??"").trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,32)}o(D,"normaliseHostLabel");function O(e=process.env){const t=D(e[i]);return t||(c.find(s=>s.detect(e))?.host??"")}o(O,"detectHostLabel");function u(e,t=process.env){const s=O(t),r=S(t);if(r)return{key:`${r.host}:${r.sessionId}`,host:s,source:"host"};const n=(t.REMIXMATE_TAKE_KEY??"").trim();return n?{key:`custom:${n}`,host:s,source:"env-override"}:e&&e>0?{key:`job:${e}`,host:s,source:"render-job"}:{key:"",host:s,source:"none"}}o(u,"resolveTakeKey");function I(e=process.env){const t=/(SESSION|THREAD|CONVERSATION|CHAT|TASK)/i,s=/(TOKEN|KEY|SECRET|AUTH|PASSWORD|COOKIE|CREDENTIAL)/i;return Object.keys(e).filter(r=>t.test(r)&&!s.test(r)).sort()}o(I,"probeSessionVarNames");export{c as HOST_PROVIDERS,O as detectHostLabel,S as detectHostSession,D as normaliseHostLabel,I as probeSessionVarNames,u as resolveTakeKey};
@@ -1,65 +1 @@
1
- /**
2
- * Project resolution ladder — which Project does this invocation's output
3
- * belong to? First rung that matches wins.
4
- *
5
- * 0. CONVERSATION_ID already set → do nothing at all (cloud ab-agent path)
6
- * 1. --project prj_xxx → explicit flag
7
- * 2. REMIXMATE_PROJECT_ID → explicit env
8
- * 3. ~/.config/remixmate/projects.json → `project use` binding (byPath → default)
9
- * 4. the default project 「未分类」 → lazily created server-side
10
- *
11
- * Only "explicit" and "fallback" — there is deliberately no inference step in
12
- * between. Deriving a project from the git remote reads well until you notice
13
- * it *creates* one on every unfamiliar repo (`/project/create` is an upsert),
14
- * and that its rules have to keep growing for private remotes, non-GitHub
15
- * remotes, monorepos and repos with no origin — each misfire silently filing
16
- * output under a project the user never made.
17
- *
18
- * See docs/product/cli/cli-project-binding-design.md §3.
19
- */
20
- import { mmPost } from '../http.js';
21
- import { readBinding } from './store.js';
22
- /** POST /project/default — get-or-lazily-create 「未分类」. */
23
- export async function fetchDefaultProject(ctx) {
24
- return await mmPost(ctx, '/project/default', {});
25
- }
26
- /** POST /project/list — for `remixmate project list`. */
27
- export async function listProjects(ctx) {
28
- const data = await mmPost(ctx, '/project/list', {});
29
- if (Array.isArray(data))
30
- return data;
31
- return data?.list ?? [];
32
- }
33
- export async function resolveProject(ctx, opts = {}) {
34
- const env = opts.env ?? process.env;
35
- const flag = (opts.flagProjectId ?? '').trim();
36
- if (flag)
37
- return { projectId: flag, source: 'flag' };
38
- const fromEnv = (env.REMIXMATE_PROJECT_ID ?? '').trim();
39
- if (fromEnv)
40
- return { projectId: fromEnv, source: 'env' };
41
- const bound = await readBinding(ctx.apiBaseUrl, opts.cwd);
42
- if (bound) {
43
- return {
44
- projectId: bound.projectId,
45
- source: bound.scope === 'path' ? 'binding-path' : 'binding-default',
46
- };
47
- }
48
- const fallback = await fetchDefaultProject(ctx);
49
- return { projectId: fallback.id, source: 'default-project' };
50
- }
51
- /** Human-readable label for `doctor` / `project show`. */
52
- export function describeProjectSource(source) {
53
- switch (source) {
54
- case 'flag':
55
- return '--project 参数';
56
- case 'env':
57
- return 'REMIXMATE_PROJECT_ID 环境变量';
58
- case 'binding-path':
59
- return `${process.cwd()} 的目录绑定`;
60
- case 'binding-default':
61
- return '全局默认绑定';
62
- case 'default-project':
63
- return '默认项目「未分类」';
64
- }
65
- }
1
+ var s=Object.defineProperty;var t=(r,e)=>s(r,"name",{value:e,configurable:!0});import{mmPost as a}from"../http.js";import{readBinding as u}from"./store.js";async function f(r){return await a(r,"/project/default",{})}t(f,"fetchDefaultProject");async function I(r){const e=await a(r,"/project/list",{});return Array.isArray(e)?e:e?.list??[]}t(I,"listProjects");async function g(r,e={}){const i=e.env??process.env,n=(e.flagProjectId??"").trim();if(n)return{projectId:n,source:"flag"};const o=(i.REMIXMATE_PROJECT_ID??"").trim();if(o)return{projectId:o,source:"env"};const c=await u(r.apiBaseUrl,e.cwd);return c?{projectId:c.projectId,source:c.scope==="path"?"binding-path":"binding-default"}:{projectId:(await f(r)).id,source:"default-project"}}t(g,"resolveProject");function m(r){switch(r){case"flag":return"--project 参数";case"env":return"REMIXMATE_PROJECT_ID 环境变量";case"binding-path":return`${process.cwd()} 的目录绑定`;case"binding-default":return"全局默认绑定";case"default-project":return"默认项目「未分类」"}}t(m,"describeProjectSource");export{m as describeProjectSource,f as fetchDefaultProject,I as listProjects,g as resolveProject};
@@ -1,97 +1,2 @@
1
- /**
2
- * Persistent project binding — which Project should this machine's CLI output
3
- * belong to?
4
- *
5
- * Stored at ~/.config/remixmate/projects.json, NOT in credentials.json: that
6
- * file is a 0600 secret store keyed by API base URL, with different lifetime
7
- * and different blast radius on corruption.
8
- *
9
- * Two layers, because host cwd semantics are not uniform:
10
- * - `byPath` — keyed by absolute cwd. Hosts that run inside the user's real
11
- * repo (Codex, Claude Code) get per-repo bindings.
12
- * - `default` — a single fallback. Hosts that spawn a throwaway working
13
- * directory per conversation (WorkBuddy uses
14
- * ~/WorkBuddy/<timestamp>) would never hit a byPath entry, so a
15
- * cwd-only design silently degrades to nothing for them.
16
- *
17
- * See docs/product/cli/cli-project-binding-design.md §3.
18
- */
19
- import { homedir } from 'node:os';
20
- import { dirname, join, resolve } from 'node:path';
21
- import { promises as fs } from 'node:fs';
22
- export const CONFIG_DIR = join(homedir(), '.config', 'remixmate');
23
- export const PROJECTS_FILE = join(CONFIG_DIR, 'projects.json');
24
- /**
25
- * Must build a NEW object every call, not spread a shared constant: `backends`
26
- * would then be one object aliased by every "empty" read, and writeBinding
27
- * mutates it — so a later read of a missing/corrupt file would hand back
28
- * bindings accumulated earlier in the process instead of nothing.
29
- */
30
- function emptyFile() {
31
- return { version: 1, backends: {} };
32
- }
33
- async function readFile() {
34
- try {
35
- const raw = await fs.readFile(PROJECTS_FILE, 'utf-8');
36
- const parsed = JSON.parse(raw);
37
- if (!parsed || typeof parsed !== 'object' || !parsed.backends)
38
- return emptyFile();
39
- return parsed;
40
- }
41
- catch {
42
- // Missing or corrupt → behave as unbound. A broken binding file must never
43
- // block a render; the resolution ladder just falls through to the default project.
44
- return emptyFile();
45
- }
46
- }
47
- async function writeFile(data) {
48
- await fs.mkdir(dirname(PROJECTS_FILE), { recursive: true, mode: 0o700 });
49
- await fs.writeFile(PROJECTS_FILE, JSON.stringify(data, null, 2) + '\n', { mode: 0o600 });
50
- }
51
- /** Look up the binding for a cwd: exact byPath match first, then the default. */
52
- export async function readBinding(apiBaseUrl, cwd = process.cwd()) {
53
- const file = await readFile();
54
- const entry = file.backends[apiBaseUrl];
55
- if (!entry)
56
- return null;
57
- const byPath = entry.byPath?.[resolve(cwd)];
58
- if (byPath)
59
- return { projectId: byPath, scope: 'path' };
60
- if (entry.default)
61
- return { projectId: entry.default, scope: 'default' };
62
- return null;
63
- }
64
- /** Bind a project to this cwd (`scope: 'path'`) or as the fallback (`'default'`). */
65
- export async function writeBinding(apiBaseUrl, projectId, scope, cwd = process.cwd()) {
66
- const file = await readFile();
67
- const entry = file.backends[apiBaseUrl] ?? {};
68
- if (scope === 'default') {
69
- entry.default = projectId;
70
- }
71
- else {
72
- entry.byPath = { ...(entry.byPath ?? {}), [resolve(cwd)]: projectId };
73
- }
74
- file.backends[apiBaseUrl] = entry;
75
- await writeFile(file);
76
- }
77
- /** Drop a binding. Returns true when something was actually removed. */
78
- export async function clearBinding(apiBaseUrl, scope, cwd = process.cwd()) {
79
- const file = await readFile();
80
- const entry = file.backends[apiBaseUrl];
81
- if (!entry)
82
- return false;
83
- let removed = false;
84
- if (scope === 'default') {
85
- removed = entry.default != null;
86
- delete entry.default;
87
- }
88
- else {
89
- const key = resolve(cwd);
90
- removed = entry.byPath?.[key] != null;
91
- if (entry.byPath)
92
- delete entry.byPath[key];
93
- }
94
- if (removed)
95
- await writeFile(file);
96
- return removed;
97
- }
1
+ var m=Object.defineProperty;var i=(n,e)=>m(n,"name",{value:e,configurable:!0});import{homedir as w}from"node:os";import{dirname as b,join as u,resolve as s}from"node:path";import{promises as c}from"node:fs";const h=u(w(),".config","remixmate"),f=u(h,"projects.json");function p(){return{version:1,backends:{}}}i(p,"emptyFile");async function l(){try{const n=await c.readFile(f,"utf-8"),e=JSON.parse(n);return!e||typeof e!="object"||!e.backends?p():e}catch{return p()}}i(l,"readFile");async function y(n){await c.mkdir(b(f),{recursive:!0,mode:448}),await c.writeFile(f,JSON.stringify(n,null,2)+`
2
+ `,{mode:384})}i(y,"writeFile");async function g(n,e=process.cwd()){const r=(await l()).backends[n];if(!r)return null;const t=r.byPath?.[s(e)];return t?{projectId:t,scope:"path"}:r.default?{projectId:r.default,scope:"default"}:null}i(g,"readBinding");async function j(n,e,o,r=process.cwd()){const t=await l(),a=t.backends[n]??{};o==="default"?a.default=e:a.byPath={...a.byPath??{},[s(r)]:e},t.backends[n]=a,await y(t)}i(j,"writeBinding");async function v(n,e,o=process.cwd()){const r=await l(),t=r.backends[n];if(!t)return!1;let a=!1;if(e==="default")a=t.default!=null,delete t.default;else{const d=s(o);a=t.byPath?.[d]!=null,t.byPath&&delete t.byPath[d]}return a&&await y(r),a}i(v,"clearBinding");export{h as CONFIG_DIR,f as PROJECTS_FILE,v as clearBinding,g as readBinding,j as writeBinding};
@@ -1,106 +1 @@
1
- /**
2
- * Take creation — turn a render invocation into a VideoProject the web app can
3
- * show, and hand its conversation id down to the skill.
4
- *
5
- * Why this exists at all: ab-web derives a video's project from
6
- * `file.conversation_id → media_video_project → media_project`. A render whose
7
- * upload carries no conversation id is stored correctly but belongs to nothing,
8
- * so it shows up only in the raw asset list. The cloud agent injects
9
- * CONVERSATION_ID for its own runs; locally, nobody did — that is the bug this
10
- * module fixes.
11
- *
12
- * Idempotency lives on the server (`/video-project/ensure` is get-or-create on
13
- * `(user_id, client_session_key)`), not in a local state file: a pipeline is N
14
- * separate CLI processes, sometimes concurrent, and a local cache would have to
15
- * solve staleness and write races that a unique index solves for free.
16
- *
17
- * See docs/product/cli/cli-project-binding-design.md §5.
18
- */
19
- import { mmPost } from '../http.js';
20
- import { resolveTakeKey } from './host.js';
21
- import { resolveProject } from './resolve.js';
22
- /**
23
- * Pull title / aspectRatio / templateId off the persisted render job.
24
- *
25
- * The VideoProject row needs them at creation time, but this runs in Node
26
- * before the Python renderer is spawned, so the DSL itself isn't in reach —
27
- * `render_jobs.dsl_meta` is the summary of exactly those fields. Best-effort:
28
- * a take with a placeholder title beats no take at all.
29
- */
30
- async function fetchJobMeta(ctx, jobId) {
31
- try {
32
- const detail = await mmPost(ctx, '/renderJob/get', { jobId });
33
- return detail?.dslMeta ?? {};
34
- }
35
- catch {
36
- return {};
37
- }
38
- }
39
- /**
40
- * Look up the take for the current grouping key without creating anything.
41
- *
42
- * Used by pipeline skills that should attach to a take when one exists but must
43
- * never bring one into being: someone running `remixmate gen-image` on its own
44
- * isn't making a video, and an empty VideoProject is worse clutter than an
45
- * unattributed image.
46
- *
47
- * Deliberately does NOT resolve a project — resolveProject()'s last rung
48
- * lazily *creates* 「未分类」, which a read-only lookup has no business doing.
49
- */
50
- export async function findTake(ctx) {
51
- const takeKey = resolveTakeKey(undefined);
52
- if (!takeKey.key)
53
- return null;
54
- const res = await mmPost(ctx, '/video-project/find-by-session', {
55
- clientSessionKey: takeKey.key,
56
- });
57
- if (!res?.conversationId)
58
- return null;
59
- return {
60
- conversationId: res.conversationId,
61
- videoProjectId: res.id,
62
- projectId: res.projectId ?? '',
63
- created: false,
64
- attempt: res.attempt ?? 0,
65
- sessionKey: takeKey.key,
66
- host: takeKey.host,
67
- };
68
- }
69
- /**
70
- * Resolve project + grouping key, then get-or-create the take.
71
- * Returns null when this invocation shouldn't own a take.
72
- */
73
- export async function ensureTake(ctx, opts) {
74
- const jobId = opts.jobId && opts.jobId > 0 ? opts.jobId : undefined;
75
- const takeKey = resolveTakeKey(jobId);
76
- // No grouping key at all → don't create. Only reachable for a take-creating
77
- // skill that has no jobId (prepare-video-assets) on a host that exposes no
78
- // session id. Creating here would produce an ungrouped take that the later
79
- // render-video call — which *does* have a jobId, hence the `job:N` key —
80
- // could not join, leaving two takes for one video.
81
- if (!takeKey.key)
82
- return null;
83
- const { projectId } = await resolveProject(ctx, { flagProjectId: opts.flagProjectId });
84
- const meta = jobId ? await fetchJobMeta(ctx, jobId) : {};
85
- const res = await mmPost(ctx, '/video-project/ensure', {
86
- projectId,
87
- clientSessionKey: takeKey.key,
88
- clientHost: takeKey.host,
89
- jobId: jobId ?? 0,
90
- title: meta?.title ?? '',
91
- archetype: meta?.archetype ?? '',
92
- aspectRatio: meta?.aspectRatio ?? '',
93
- templateId: meta?.templateId ?? '',
94
- });
95
- if (!res?.conversationId)
96
- return null;
97
- return {
98
- conversationId: res.conversationId,
99
- videoProjectId: res.id,
100
- projectId,
101
- created: res.created,
102
- attempt: res.attempt,
103
- sessionKey: takeKey.key,
104
- host: takeKey.host,
105
- };
106
- }
1
+ var l=Object.defineProperty;var i=(o,e)=>l(o,"name",{value:e,configurable:!0});import{mmPost as s}from"../http.js";import{resolveTakeKey as d}from"./host.js";import{resolveProject as y}from"./resolve.js";async function I(o,e){try{return(await s(o,"/renderJob/get",{jobId:e}))?.dslMeta??{}}catch{return{}}}i(I,"fetchJobMeta");async function m(o){const e=d(void 0);if(!e.key)return null;const t=await s(o,"/video-project/find-by-session",{clientSessionKey:e.key});return t?.conversationId?{conversationId:t.conversationId,videoProjectId:t.id,projectId:t.projectId??"",created:!1,attempt:t.attempt??0,sessionKey:e.key,host:e.host}:null}i(m,"findTake");async function v(o,e){const t=e.jobId&&e.jobId>0?e.jobId:void 0,n=d(t);if(!n.key)return null;const{projectId:c}=await y(o,{flagProjectId:e.flagProjectId}),a=t?await I(o,t):{},r=await s(o,"/video-project/ensure",{projectId:c,clientSessionKey:n.key,clientHost:n.host,jobId:t??0,title:a?.title??"",archetype:a?.archetype??"",aspectRatio:a?.aspectRatio??"",templateId:a?.templateId??""});return r?.conversationId?{conversationId:r.conversationId,videoProjectId:r.id,projectId:c,created:r.created,attempt:r.attempt,sessionKey:n.key,host:n.host}:null}i(v,"ensureTake");export{v as ensureTake,m as findTake};