@motionharness/bridge-davinci 0.0.22 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runner.mjs CHANGED
@@ -1244,11 +1244,11 @@ var require_mtime_precision = __commonJS({
1244
1244
  function probe(file2, fs, callback) {
1245
1245
  const cachedPrecision = fs[cacheSymbol];
1246
1246
  if (cachedPrecision) {
1247
- return fs.stat(file2, (err2, stat9) => {
1247
+ return fs.stat(file2, (err2, stat8) => {
1248
1248
  if (err2) {
1249
1249
  return callback(err2);
1250
1250
  }
1251
- callback(null, stat9.mtime, cachedPrecision);
1251
+ callback(null, stat8.mtime, cachedPrecision);
1252
1252
  });
1253
1253
  }
1254
1254
  const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
@@ -1256,13 +1256,13 @@ var require_mtime_precision = __commonJS({
1256
1256
  if (err2) {
1257
1257
  return callback(err2);
1258
1258
  }
1259
- fs.stat(file2, (err3, stat9) => {
1259
+ fs.stat(file2, (err3, stat8) => {
1260
1260
  if (err3) {
1261
1261
  return callback(err3);
1262
1262
  }
1263
- const precision = stat9.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
1263
+ const precision = stat8.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
1264
1264
  Object.defineProperty(fs, cacheSymbol, { value: precision });
1265
- callback(null, stat9.mtime, precision);
1265
+ callback(null, stat8.mtime, precision);
1266
1266
  });
1267
1267
  });
1268
1268
  }
@@ -1316,14 +1316,14 @@ var require_lockfile = __commonJS({
1316
1316
  if (options.stale <= 0) {
1317
1317
  return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file: file2 }));
1318
1318
  }
1319
- options.fs.stat(lockfilePath, (err3, stat9) => {
1319
+ options.fs.stat(lockfilePath, (err3, stat8) => {
1320
1320
  if (err3) {
1321
1321
  if (err3.code === "ENOENT") {
1322
1322
  return acquireLock(file2, { ...options, stale: 0 }, callback);
1323
1323
  }
1324
1324
  return callback(err3);
1325
1325
  }
1326
- if (!isLockStale(stat9, options)) {
1326
+ if (!isLockStale(stat8, options)) {
1327
1327
  return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file: file2 }));
1328
1328
  }
1329
1329
  removeLock(file2, options, (err4) => {
@@ -1335,8 +1335,8 @@ var require_lockfile = __commonJS({
1335
1335
  });
1336
1336
  });
1337
1337
  }
1338
- function isLockStale(stat9, options) {
1339
- return stat9.mtime.getTime() < Date.now() - options.stale;
1338
+ function isLockStale(stat8, options) {
1339
+ return stat8.mtime.getTime() < Date.now() - options.stale;
1340
1340
  }
1341
1341
  function removeLock(file2, options, callback) {
1342
1342
  options.fs.rmdir(getLockFile(file2, options), (err2) => {
@@ -1354,7 +1354,7 @@ var require_lockfile = __commonJS({
1354
1354
  lock2.updateDelay = lock2.updateDelay || options.update;
1355
1355
  lock2.updateTimeout = setTimeout(() => {
1356
1356
  lock2.updateTimeout = null;
1357
- options.fs.stat(lock2.lockfilePath, (err2, stat9) => {
1357
+ options.fs.stat(lock2.lockfilePath, (err2, stat8) => {
1358
1358
  const isOverThreshold = lock2.lastUpdate + options.stale < Date.now();
1359
1359
  if (err2) {
1360
1360
  if (err2.code === "ENOENT" || isOverThreshold) {
@@ -1363,7 +1363,7 @@ var require_lockfile = __commonJS({
1363
1363
  lock2.updateDelay = 1e3;
1364
1364
  return updateLock(file2, options);
1365
1365
  }
1366
- const isMtimeOurs = lock2.mtime.getTime() === stat9.mtime.getTime();
1366
+ const isMtimeOurs = lock2.mtime.getTime() === stat8.mtime.getTime();
1367
1367
  if (!isMtimeOurs) {
1368
1368
  return setLockAsCompromised(
1369
1369
  file2,
@@ -1488,11 +1488,11 @@ var require_lockfile = __commonJS({
1488
1488
  if (err2) {
1489
1489
  return callback(err2);
1490
1490
  }
1491
- options.fs.stat(getLockFile(file3, options), (err3, stat9) => {
1491
+ options.fs.stat(getLockFile(file3, options), (err3, stat8) => {
1492
1492
  if (err3) {
1493
1493
  return err3.code === "ENOENT" ? callback(null, false) : callback(err3);
1494
1494
  }
1495
- return callback(null, !isLockStale(stat9, options));
1495
+ return callback(null, !isLockStale(stat8, options));
1496
1496
  });
1497
1497
  });
1498
1498
  }
@@ -1538,12 +1538,12 @@ var require_adapter = __commonJS({
1538
1538
  return newFs;
1539
1539
  }
1540
1540
  function toPromise(method) {
1541
- return (...args) => new Promise((resolve11, reject) => {
1541
+ return (...args) => new Promise((resolve12, reject) => {
1542
1542
  args.push((err2, result2) => {
1543
1543
  if (err2) {
1544
1544
  reject(err2);
1545
1545
  } else {
1546
- resolve11(result2);
1546
+ resolve12(result2);
1547
1547
  }
1548
1548
  });
1549
1549
  method(...args);
@@ -1620,8 +1620,8 @@ var require_proper_lockfile = __commonJS({
1620
1620
  import { spawn as spawn2 } from "node:child_process";
1621
1621
  import { closeSync, fstatSync, statSync, writeSync } from "node:fs";
1622
1622
  import { Socket } from "node:net";
1623
- import { open as open5, mkdir as mkdir9, readFile as readFile11, writeFile as writeFile2, copyFile as copyFile4, realpath as realpath6, stat as stat8 } from "node:fs/promises";
1624
- import { basename as basename5, dirname as dirname9, join as join9, resolve as resolve10, sep as sep3 } from "node:path";
1623
+ import { open as open5, mkdir as mkdir9, readFile as readFile11, writeFile as writeFile2, copyFile as copyFile4, realpath as realpath6, stat as stat7 } from "node:fs/promises";
1624
+ import { basename as basename5, dirname as dirname10, join as join9, resolve as resolve11, sep as sep2 } from "node:path";
1625
1625
  import { fileURLToPath as fileURLToPath2 } from "node:url";
1626
1626
 
1627
1627
  // ../../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
@@ -15476,7 +15476,7 @@ async function run(executable, args, options = {}) {
15476
15476
  }
15477
15477
  async function runBytes(executable, args, options = {}) {
15478
15478
  if (options.signal?.aborted) throw new BridgeError("CANCELLED", "\u4EFB\u52A1\u5DF2\u53D6\u6D88\u3002", "process");
15479
- return new Promise((resolve11, reject) => {
15479
+ return new Promise((resolve12, reject) => {
15480
15480
  const child = spawn(executable, args, {
15481
15481
  cwd: options.cwd,
15482
15482
  shell: false,
@@ -15497,7 +15497,7 @@ async function runBytes(executable, args, options = {}) {
15497
15497
  child.kill("SIGINT");
15498
15498
  const grace = options.graceMs ?? 1e4;
15499
15499
  termTimer = setTimeout(() => {
15500
- failure = new BridgeError("PROCESS_OUTCOME_UNKNOWN", "\u5B50\u8FDB\u7A0B\u672A\u786E\u8BA4\u6B63\u5E38\u53D6\u6D88\uFF0C\u5DF2\u7EC8\u6B62\u672C\u4EFB\u52A1\u62E5\u6709\u7684\u8FDB\u7A0B\uFF1BHotion Harness \u5BBF\u4E3B\u7ED3\u679C\u9700\u6838\u5BF9\u3002", "process");
15500
+ failure = new BridgeError("PROCESS_OUTCOME_UNKNOWN", "\u5B50\u8FDB\u7A0B\u672A\u786E\u8BA4\u6B63\u5E38\u53D6\u6D88\uFF0C\u5DF2\u7EC8\u6B62\u672C\u4EFB\u52A1\u62E5\u6709\u7684\u8FDB\u7A0B\uFF1BMotionHarness \u5BBF\u4E3B\u7ED3\u679C\u9700\u6838\u5BF9\u3002", "process");
15501
15501
  child.kill("SIGTERM");
15502
15502
  }, grace);
15503
15503
  killTimer = setTimeout(() => child.kill("SIGKILL"), grace * 2);
@@ -15534,7 +15534,7 @@ async function runBytes(executable, args, options = {}) {
15534
15534
  child.stderr.destroy();
15535
15535
  reject(failure);
15536
15536
  } else if (code !== 0) reject(new BridgeError("PROCESS_FAILED", `${executable} \u6267\u884C\u5931\u8D25\u3002`, "process", false, { code, signal, stderr: stderr.slice(-4e3) }));
15537
- else resolve11({ stdout: Buffer.concat(stdout), stderr });
15537
+ else resolve12({ stdout: Buffer.concat(stdout), stderr });
15538
15538
  };
15539
15539
  child.on("exit", (code, signal) => {
15540
15540
  exited = true;
@@ -16282,7 +16282,7 @@ function observeState(raw, cliVersion, sdkVersion, dependencyHash) {
16282
16282
  const parsed = inspectSchema.safeParse(raw);
16283
16283
  if (!parsed.success) throw new BridgeError("MH_CONTRACT_UNSUPPORTED", "mh inspect \u8FD4\u56DE\u7684\u516C\u5171\u5B57\u6BB5\u4E0D\u7B26\u5408\u5DF2\u5B9E\u73B0\u7684\u9002\u914D\u5951\u7EA6\u3002", "inspect", false, { issues: parsed.error.issues });
16284
16284
  const data = parsed.data;
16285
- assert2(data.sourceCurrent && !data.preparing && !data.error && !data.migration && !data.documentConflict && !data.lifecycle?.saveError, "BUILD_FAILED", "Hotion Harness \u6E90\u7801\u3001\u6784\u5EFA\u3001\u4FDD\u5B58\u6216\u8FC1\u79FB\u72B6\u6001\u5C1A\u672A\u5C31\u7EEA\u3002", { sourceCurrent: data.sourceCurrent, preparing: data.preparing, diagnostic: data.error, migration: data.migration, documentConflict: data.documentConflict, saveError: data.lifecycle?.saveError });
16285
+ assert2(data.sourceCurrent && !data.preparing && !data.error && !data.migration && !data.documentConflict && !data.lifecycle?.saveError, "BUILD_FAILED", "MotionHarness \u6E90\u7801\u3001\u6784\u5EFA\u3001\u4FDD\u5B58\u6216\u8FC1\u79FB\u72B6\u6001\u5C1A\u672A\u5C31\u7EEA\u3002", { sourceCurrent: data.sourceCurrent, preparing: data.preparing, diagnostic: data.error, migration: data.migration, documentConflict: data.documentConflict, saveError: data.lifecycle?.saveError });
16286
16286
  const { revision: _revision, ...document } = data.document;
16287
16287
  const assets = data.sourceAssets.map((a) => ({ hash: a.$asset, kind: a.kind })).sort((a, b) => a.hash.localeCompare(b.hash));
16288
16288
  const audioPresent = Object.values(data.document.instances).some((instance) => data.schema.components[instance.componentId]?.audio != null);
@@ -16312,7 +16312,7 @@ var MhAdapter = class {
16312
16312
  return resolved;
16313
16313
  } catch (error48) {
16314
16314
  if (error48 instanceof BridgeError) throw error48;
16315
- throw new BridgeError("SOURCE_MISSING", "Hotion Harness \u5DE5\u7A0B\u6216 package.json / pnpm-lock.yaml \u4E0D\u5B58\u5728\u3002", "inspect", false, {}, "\u6307\u5B9A\u5B8C\u6574\u7684 Hotion Harness \u5DE5\u7A0B\u76EE\u5F55\uFF1B\u901A\u8FC7\u516C\u5F00 mh unpack \u6062\u590D\u5DE5\u7A0B\u3002");
16315
+ throw new BridgeError("SOURCE_MISSING", "MotionHarness \u5DE5\u7A0B\u6216 package.json / pnpm-lock.yaml \u4E0D\u5B58\u5728\u3002", "inspect", false, {}, "\u6307\u5B9A\u5B8C\u6574\u7684 MotionHarness \u5DE5\u7A0B\u76EE\u5F55\uFF1B\u901A\u8FC7\u516C\u5F00 mh unpack \u6062\u590D\u5DE5\u7A0B\u3002");
16316
16316
  }
16317
16317
  }
16318
16318
  async json(args, project, signal, timeoutMs) {
@@ -16321,7 +16321,7 @@ var MhAdapter = class {
16321
16321
  return parseJson(result2.stdout);
16322
16322
  } catch (error48) {
16323
16323
  if (error48 instanceof BridgeError && String(error48.details.stderr).includes("incompatible with this CLI")) {
16324
- throw new BridgeError("MH_DAEMON_VERSION_CONFLICT", "Hotion Harness CLI \u4E0E\u5F53\u524D\u8FD0\u884C\u7684 daemon \u7248\u672C\u4E0D\u4E00\u81F4\uFF0C\u672A\u505C\u6B62\u73B0\u6709\u4F1A\u8BDD\u3002", "mh", false, { executable: this.executable, diagnostic: error48.details.stderr }, "\u4F7F\u7528\u4E0E\u5F53\u524D\u5BBF\u4E3B\u5339\u914D\u7684\u4E3B Hotion Harness CLI\uFF1B\u5982\u9700\u91CD\u542F\u5BF9\u5E94 daemon\uFF0C\u5148\u4FDD\u5B58\u5E76\u5904\u7406\u73B0\u6709\u4F1A\u8BDD\uFF0C\u6865\u63A5\u4E0D\u4F1A\u81EA\u52A8\u505C\u6B62\u5B83\u4EEC\u3002");
16324
+ throw new BridgeError("MH_DAEMON_VERSION_CONFLICT", "MotionHarness CLI \u4E0E\u5F53\u524D\u8FD0\u884C\u7684 daemon \u7248\u672C\u4E0D\u4E00\u81F4\uFF0C\u672A\u505C\u6B62\u73B0\u6709\u4F1A\u8BDD\u3002", "mh", false, { executable: this.executable, diagnostic: error48.details.stderr }, "\u4F7F\u7528\u4E0E\u5F53\u524D\u5BBF\u4E3B\u5339\u914D\u7684\u4E3B MotionHarness CLI\uFF1B\u5982\u9700\u91CD\u542F\u5BF9\u5E94 daemon\uFF0C\u5148\u4FDD\u5B58\u5E76\u5904\u7406\u73B0\u6709\u4F1A\u8BDD\uFF0C\u6865\u63A5\u4E0D\u4F1A\u81EA\u52A8\u505C\u6B62\u5B83\u4EEC\u3002");
16325
16325
  }
16326
16326
  throw error48;
16327
16327
  }
@@ -16349,7 +16349,7 @@ var MhAdapter = class {
16349
16349
  for (let attempt = 0; attempt < 50; attempt++) {
16350
16350
  const status = state;
16351
16351
  if (!status.preparing && !status.buildsInFlight && status.sourceCurrent) break;
16352
- await new Promise((resolve11) => setTimeout(resolve11, 100));
16352
+ await new Promise((resolve12) => setTimeout(resolve12, 100));
16353
16353
  state = await this.json(["inspect"], project);
16354
16354
  }
16355
16355
  const d = doctor;
@@ -16416,7 +16416,7 @@ var MhAdapter = class {
16416
16416
  async plan(path, spec, sourceDuration) {
16417
16417
  const plan = await this.json(["render", "plan", "--json", JSON.stringify(this.renderOptions(spec, sourceDuration))], path);
16418
16418
  const result2 = external_exports.object({ frameCount: external_exports.number().int().positive(), request: external_exports.object({ width: external_exports.number(), height: external_exports.number(), fps: external_exports.number(), start: external_exports.number(), duration: external_exports.number() }).passthrough() }).parse(plan);
16419
- assert2(result2.frameCount === spec.frameCount, "OUTPUT_SPEC_MISMATCH", "Hotion Harness \u91C7\u6837\u8BA1\u5212\u5E27\u6570\u4E0E\u6865\u63A5\u8BF7\u6C42\u4E0D\u4E00\u81F4\u3002");
16419
+ assert2(result2.frameCount === spec.frameCount, "OUTPUT_SPEC_MISMATCH", "MotionHarness \u91C7\u6837\u8BA1\u5212\u5E27\u6570\u4E0E\u6865\u63A5\u8BF7\u6C42\u4E0D\u4E00\u81F4\u3002");
16420
16420
  return result2;
16421
16421
  }
16422
16422
  renderOptions(spec, sourceDuration) {
@@ -16468,9 +16468,9 @@ var MhAdapter = class {
16468
16468
  const result2 = external_exports.object({ id: external_exports.string(), rendered: external_exports.literal(true), saved: external_exports.literal(true), output: external_exports.string(), format: external_exports.enum(["mp4", "mov"]), progress: external_exports.object({ completed: external_exports.number(), total: external_exports.number() }) }).parse(rendered);
16469
16469
  assert2(result2.format === (spec.format ?? "mp4"), "RENDER_RECEIPT_MISMATCH", "\u5BFC\u51FA\u6587\u4EF6\u683C\u5F0F\u4E0E\u8BF7\u6C42\u4E0D\u4E00\u81F4\u3002");
16470
16470
  const checked = renderStatusSchema.safeParse(await this.json(["render", "status"], path));
16471
- if (!checked.success) throw new BridgeError("MH_RENDER_STATUS_UNVERIFIED", "Hotion Harness \u672A\u786E\u8BA4\u672C\u6B21\u6E32\u67D3\u5DF2\u5B8C\u6210\u3001\u4FDD\u5B58\u5E76\u91CA\u653E\u8D44\u6E90\u3002", "render", false, { issues: checked.error.issues }, "\u4FDD\u7559\u539F\u4EFB\u52A1\u548C\u4EA7\u7269\uFF0C\u901A\u8FC7\u516C\u5F00 mh render status \u6838\u5BF9\u72B6\u6001\uFF1B\u672A\u6838\u5B9E\u524D\u4E0D\u5C06\u6587\u4EF6\u6807\u8BB0\u4E3A\u5DF2\u9A8C\u8BC1\u7248\u672C\u3002");
16471
+ if (!checked.success) throw new BridgeError("MH_RENDER_STATUS_UNVERIFIED", "MotionHarness \u672A\u786E\u8BA4\u672C\u6B21\u6E32\u67D3\u5DF2\u5B8C\u6210\u3001\u4FDD\u5B58\u5E76\u91CA\u653E\u8D44\u6E90\u3002", "render", false, { issues: checked.error.issues }, "\u4FDD\u7559\u539F\u4EFB\u52A1\u548C\u4EA7\u7269\uFF0C\u901A\u8FC7\u516C\u5F00 mh render status \u6838\u5BF9\u72B6\u6001\uFF1B\u672A\u6838\u5B9E\u524D\u4E0D\u5C06\u6587\u4EF6\u6807\u8BB0\u4E3A\u5DF2\u9A8C\u8BC1\u7248\u672C\u3002");
16472
16472
  const status = checked.data;
16473
- assert2(status.id === result2.id && result2.output === output && result2.progress.completed === spec.frameCount && result2.progress.total === spec.frameCount, "RENDER_RECEIPT_MISMATCH", "Hotion Harness \u6E32\u67D3\u56DE\u6267\u3001\u5B8C\u6210\u72B6\u6001\u6216\u5E27\u6570\u4E0D\u5C5E\u4E8E\u672C\u6B21\u8BF7\u6C42\u3002");
16473
+ assert2(status.id === result2.id && result2.output === output && result2.progress.completed === spec.frameCount && result2.progress.total === spec.frameCount, "RENDER_RECEIPT_MISMATCH", "MotionHarness \u6E32\u67D3\u56DE\u6267\u3001\u5B8C\u6210\u72B6\u6001\u6216\u5E27\u6570\u4E0D\u5C5E\u4E8E\u672C\u6B21\u8BF7\u6C42\u3002");
16474
16474
  return { ...result2, status };
16475
16475
  }
16476
16476
  async pack(path, output) {
@@ -16546,6 +16546,10 @@ var ResolveAdapter = class {
16546
16546
  return this.call("inspector", params);
16547
16547
  }
16548
16548
  media(scope, mediaPoolItemId) {
16549
+ return this.call("media_identity", { scope: scoped(scope), mediaPoolItemId });
16550
+ }
16551
+ // Only operations that inspect or change timeline instances need this scan.
16552
+ mediaUsages(scope, mediaPoolItemId) {
16549
16553
  return this.call("media", { scope: scoped(scope), mediaPoolItemId });
16550
16554
  }
16551
16555
  findImport(scope, filePath) {
@@ -16981,29 +16985,31 @@ var Store = class {
16981
16985
  };
16982
16986
 
16983
16987
  // src/version.ts
16984
- var BRIDGE_VERSION = "0.0.22";
16988
+ var BRIDGE_VERSION = "0.0.25";
16985
16989
 
16986
16990
  // src/core/selection.ts
16987
16991
  function selectedSource(catalog, selection) {
16988
16992
  const unavailable = (status, message) => ({ selection, fingerprint: selection.fingerprint, canOpen: false, status, message, target: null });
16989
16993
  if (!selection.scope || !selection.timelineId) return unavailable("no-timeline", "\u8BF7\u6253\u5F00\u5DE5\u7A0B\u4E0E\u65F6\u95F4\u7EBF\u3002");
16990
- if (!selection.selectedCount) return unavailable("no-selection", "\u8BF7\u9009\u62E9\u4E00\u4E2A Hotion Harness \u7247\u6BB5\u3002");
16991
- if (selection.selectedCount !== 1 || !selection.item) return unavailable("multiple-selection", "\u8BF7\u53EA\u9009\u62E9\u4E00\u4E2A Hotion Harness \u7247\u6BB5\u3002");
16994
+ if (!selection.selectedCount) return unavailable("no-selection", "\u8BF7\u9009\u62E9\u4E00\u4E2A MotionHarness \u7247\u6BB5\u3002");
16995
+ if (selection.selectedCount !== 1 || !selection.item) return unavailable("multiple-selection", "\u8BF7\u53EA\u9009\u62E9\u4E00\u4E2A MotionHarness \u7247\u6BB5\u3002");
16992
16996
  let link2;
16993
16997
  try {
16994
16998
  const parsed = JSON.parse(selection.item.bridgeMetadata ?? "null");
16995
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return unavailable("not-linked", "\u6240\u9009\u7247\u6BB5\u672A\u5173\u8054 Hotion Harness \u5DE5\u7A0B\u3002");
16999
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return unavailable("not-linked", "\u6240\u9009\u7247\u6BB5\u672A\u5173\u8054 MotionHarness \u5DE5\u7A0B\u3002");
16996
17000
  link2 = parsed;
16997
17001
  } catch {
16998
- return unavailable("invalid-link", "\u7247\u6BB5\u7684 Hotion Harness \u5173\u8054\u4FE1\u606F\u65E0\u6548\u3002");
17002
+ return unavailable("invalid-link", "\u7247\u6BB5\u7684 MotionHarness \u5173\u8054\u4FE1\u606F\u65E0\u6548\u3002");
16999
17003
  }
17000
- if (link2.schemaVersion !== 1 || typeof link2.bindingId !== "string" || typeof link2.sourceId !== "string") return unavailable("invalid-link", "\u7247\u6BB5\u7684 Hotion Harness \u5173\u8054\u4FE1\u606F\u65E0\u6548\u3002");
17004
+ if (link2.schemaVersion !== 1 || typeof link2.bindingId !== "string" || typeof link2.sourceId !== "string") return unavailable("invalid-link", "\u7247\u6BB5\u7684 MotionHarness \u5173\u8054\u4FE1\u606F\u65E0\u6548\u3002");
17001
17005
  const binding = Object.hasOwn(catalog.bindings, link2.bindingId) ? catalog.bindings[link2.bindingId] : void 0;
17002
17006
  const source = Object.hasOwn(catalog.sources, link2.sourceId) ? catalog.sources[link2.sourceId] : void 0;
17003
17007
  if (!binding || !source) return unavailable("unknown-workspace", "\u5F53\u524D\u6865\u63A5\u5DE5\u4F5C\u76EE\u5F55\u6CA1\u6709\u8FD9\u6BB5\u7D20\u6750\u7684\u5173\u8054\u8BB0\u5F55\u3002");
17004
17008
  if (binding.sourceId !== source.id || binding.resolve.databaseId !== selection.scope.databaseId || binding.resolve.projectId !== selection.scope.projectId || binding.resolve.mediaPoolItemId !== selection.item.mediaPoolItemId || binding.artifactId !== link2.artifactId) return unavailable("binding-conflict", "\u7247\u6BB5\u7684\u5173\u8054\u8EAB\u4EFD\u4E0E\u8BB0\u5F55\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u68C0\u67E5\u7ED1\u5B9A\u3002");
17009
+ if (Object.values(catalog.bindings).filter((item) => digest(item.resolve) === digest(binding.resolve)).length !== 1)
17010
+ return unavailable("binding-conflict", "\u540C\u4E00\u539F\u7D20\u6750\u5B58\u5728\u591A\u4E2A\u5173\u8054\uFF0C\u8BF7\u5148\u6838\u5BF9\u5173\u8054\u8BB0\u5F55\u3002");
17005
17011
  const target = { sourceId: source.id, bindingId: binding.id, sourceName: source.name, sourceRevision: source.revision, bindingRevision: binding.revision };
17006
- return { selection, fingerprint: digest({ selection: selection.fingerprint, target }), canOpen: true, status: "linked", message: "\u5DF2\u5B9A\u4F4D\u5BF9\u5E94 Hotion Harness \u5DE5\u7A0B\u3002", target };
17012
+ return { selection, fingerprint: digest({ selection: selection.fingerprint, target }), canOpen: true, status: "linked", message: "\u5DF2\u5B9A\u4F4D\u5BF9\u5E94 MotionHarness \u5DE5\u7A0B\u3002", target };
17007
17013
  }
17008
17014
 
17009
17015
  // src/core/legacy-conversion.ts
@@ -17391,13 +17397,15 @@ function recordBindingApplication(binding, artifact, actual, revision, mediaRela
17391
17397
  });
17392
17398
  return { bindingId: binding.id, artifactId: artifact.id, revision: binding.revision, state: binding.state, actual, applied: true };
17393
17399
  }
17394
- function assertUsages(media) {
17400
+ function assertInstanceUsages(media) {
17395
17401
  assert2(media.usageScanComplete && media.uses.every((i2) => i2.unsupported.length === 0), "UNSUPPORTED_TIMELINE_ITEM", "\u5F53\u524D\u7247\u6BB5\u5305\u542B\u5C1A\u672A\u9A8C\u8BC1\u7684\u5904\u7406\uFF0C\u672A\u6267\u884C\u81EA\u52A8\u66F4\u65B0\u3002", { uses: media.uses, usageScanComplete: media.usageScanComplete });
17396
17402
  }
17397
- function editUsages(media, offlineRepair = false) {
17398
- return media.uses.map((item) => ({ ...item, unsupported: item.unsupported.filter((reason) => !offlineRepair || reason !== "offline-media-reference") }));
17399
- }
17400
17403
  function checkOwnership(binding, media) {
17404
+ assert2(
17405
+ media.mediaPoolItemId === binding.resolve.mediaPoolItemId && digest(media.scope) === digest({ databaseId: binding.resolve.databaseId, projectId: binding.resolve.projectId }),
17406
+ "VERSION_CONFLICT",
17407
+ "\u8BFB\u53D6\u7684\u539F\u7D20\u6750\u4E0E\u7ED1\u5B9A\u76EE\u6807\u4E0D\u540C\u3002"
17408
+ );
17401
17409
  if (!binding.artifactId) return;
17402
17410
  let link2 = {};
17403
17411
  try {
@@ -17405,12 +17413,12 @@ function checkOwnership(binding, media) {
17405
17413
  if (value && typeof value === "object" && !Array.isArray(value)) link2 = value;
17406
17414
  } catch {
17407
17415
  }
17408
- assert2(link2.bindingId === binding.id && link2.sourceId === binding.sourceId && link2.artifactId === binding.artifactId, "VERSION_CONFLICT", "Resolve \u5173\u8054\u5143\u6570\u636E\u5DF2\u6539\u53D8\uFF0C\u672A\u8986\u76D6\u5176\u4ED6\u63A7\u5236\u7AEF\u7684\u5173\u8054\u3002");
17416
+ assert2(link2.schemaVersion === 1 && link2.bindingId === binding.id && link2.sourceId === binding.sourceId && link2.artifactId === binding.artifactId, "VERSION_CONFLICT", "Resolve \u5173\u8054\u5143\u6570\u636E\u5DF2\u6539\u53D8\uFF0C\u672A\u8986\u76D6\u5176\u4ED6\u63A7\u5236\u7AEF\u7684\u5173\u8054\u3002");
17409
17417
  }
17410
17418
  function checkObservation(obs, spec) {
17411
- assert2(!obs.audioPresent, "AUDIO_UNSUPPORTED", "Hotion Harness \u5DE5\u7A0B\u5305\u542B\u97F3\u9891\u7EC4\u4EF6\u6216\u89C6\u9891\u539F\u4EF6\u97F3\u8F68\uFF0C\u9996\u7248\u753B\u9762\u6865\u63A5\u4E0D\u4E22\u5F03\u8FD9\u4E9B\u58F0\u97F3\u3002");
17419
+ assert2(!obs.audioPresent, "AUDIO_UNSUPPORTED", "MotionHarness \u5DE5\u7A0B\u5305\u542B\u97F3\u9891\u7EC4\u4EF6\u6216\u89C6\u9891\u539F\u4EF6\u97F3\u8F68\uFF0C\u9996\u7248\u753B\u9762\u6865\u63A5\u4E0D\u4E22\u5F03\u8FD9\u4E9B\u58F0\u97F3\u3002");
17412
17420
  assert2([[25, 1], [30, 1], [3e4, 1001]].some(([n, d]) => n * spec.fps.den === spec.fps.num * d), "UNSUPPORTED_FPS", "\u9996\u7248\u652F\u6301 25\u300130 \u548C 30000/1001 fps\u3002");
17413
- assert2((spec.startFrame + spec.frameCount - 1) * spec.fps.den / spec.fps.num < obs.settings.duration + 1e-8, "OUTPUT_SPEC_MISMATCH", "\u6307\u5B9A\u6E90\u533A\u95F4\u8D85\u8FC7 Hotion Harness \u5DE5\u7A0B\u65F6\u957F\u3002");
17421
+ assert2((spec.startFrame + spec.frameCount - 1) * spec.fps.den / spec.fps.num < obs.settings.duration + 1e-8, "OUTPUT_SPEC_MISMATCH", "\u6307\u5B9A\u6E90\u533A\u95F4\u8D85\u8FC7 MotionHarness \u5DE5\u7A0B\u65F6\u957F\u3002");
17414
17422
  }
17415
17423
  function checkReplacementSpec(media, artifact) {
17416
17424
  const properties = media.clipProperties;
@@ -17458,7 +17466,7 @@ var Bridge = class {
17458
17466
  subsequentHostStability: "not-validated",
17459
17467
  reason: "\u542B\u65E7 Fusion \u751F\u6210\u5668\u7684\u9694\u79BB\u5DE5\u7A0B\u5728\u540E\u7EED\u5207\u6362\u65F6\u95F4\u7EBF\u8BBE\u7F6E\u65F6\u51FA\u73B0\u8FC7\u5BBF\u4E3B\u65E0\u54CD\u5E94\uFF1B\u8F6C\u6362\u4EC5\u5728\u590D\u5236\u65F6\u95F4\u7EBF\u4E0A\u8FDB\u884C\u3002"
17460
17468
  },
17461
- limitations: ["\u56FA\u5B9A\u8DEF\u5F84\u66F4\u65B0\u540E\u6682\u505C\u9884\u89C8\u53EF\u80FD\u4FDD\u7559\u65E7\u5E27\uFF1B\u5B9A\u683C\u753B\u9762\u53EF\u80FD\u4ECD\u663E\u793A\u65E7\u7248\u672C\u3002", "\u4FA7\u680F\u5165\u53E3\u81EA\u52A8\u9644\u52A0\u5C1A\u4E0D\u53EF\u7528\uFF1B\u5DF2\u5173\u8054\u4EE3\u7406\u3001\u672A\u77E5\u65F6\u95F4\u6620\u5C04\u548C\u672A\u9A8C\u8BC1\u6548\u679C\u4FDD\u6301\u963B\u6B62\u66F4\u65B0\u3002", "\u65E7\u751F\u6210\u5668\u8F6C\u6362\u4E3A\u5B9E\u9A8C\u6027\u529F\u80FD\uFF0C\u540E\u7EED\u5BBF\u4E3B\u7A33\u5B9A\u6027\u5C1A\u672A\u901A\u8FC7\u9A8C\u6536\u3002"]
17469
+ limitations: ["\u56FA\u5B9A\u8DEF\u5F84\u66F4\u65B0\u540E\u6682\u505C\u9884\u89C8\u53EF\u80FD\u4FDD\u7559\u65E7\u5E27\uFF1B\u5B9A\u683C\u753B\u9762\u53EF\u80FD\u4ECD\u663E\u793A\u65E7\u7248\u672C\u3002", "\u4FA7\u680F\u5165\u53E3\u9700\u624B\u52A8\u9644\u52A0\uFF1B\u5DF2\u5173\u8054\u4EE3\u7406\u7684\u539F\u7D20\u6750\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u66F4\u65B0\u3002", "\u65E7\u751F\u6210\u5668\u8F6C\u6362\u4E3A\u5B9E\u9A8C\u6027\u529F\u80FD\uFF0C\u540E\u7EED\u5BBF\u4E3B\u7A33\u5B9A\u6027\u5C1A\u672A\u901A\u8FC7\u9A8C\u6536\u3002"]
17462
17470
  };
17463
17471
  }
17464
17472
  async bind(input) {
@@ -17491,8 +17499,10 @@ var Bridge = class {
17491
17499
  const importedScope = known && (known.resolve.projectId !== request.resolve.projectId || known.resolve.databaseId !== request.resolve.databaseId);
17492
17500
  assert2(link2.sourceId === source.id && known && (importedScope || known.resolve.mediaPoolItemId === actual.mediaPoolItemId), "BINDING_CONFLICT", "\u8BE5\u5A92\u4F53\u643A\u5E26\u5176\u4ED6\u5DE5\u4F5C\u76EE\u5F55\u6216\u5BF9\u8C61\u7684\u6865\u63A5\u8EAB\u4EFD\uFF1B\u5148\u6062\u590D\u5BF9\u5E94\u6E05\u5355\u6216\u663E\u5F0F\u5904\u7406\u8FC1\u79FB\uFF0C\u672A\u8986\u76D6\u5176\u5173\u8054\u3002");
17493
17501
  }
17494
- binding = Object.values(catalog.bindings).find((b) => digest(b.resolve) === digest(request.resolve));
17495
- assert2(!binding || binding.sourceId === source.id, "BINDING_CONFLICT", "\u8BE5\u5A92\u4F53\u6C60\u5BF9\u8C61\u5DF2\u5173\u8054\u5176\u4ED6 Hotion Harness \u5DE5\u7A0B\u3002");
17502
+ const matches = Object.values(catalog.bindings).filter((b) => digest(b.resolve) === digest(request.resolve));
17503
+ assert2(matches.length <= 1, "BINDING_CONFLICT", "\u540C\u4E00\u539F\u7D20\u6750\u5B58\u5728\u591A\u4E2A\u5173\u8054\uFF0C\u672A\u731C\u6D4B\u76EE\u6807\u3002");
17504
+ binding = matches[0];
17505
+ assert2(!binding || binding.sourceId === source.id, "BINDING_CONFLICT", "\u8BE5\u5A92\u4F53\u6C60\u5BF9\u8C61\u5DF2\u5173\u8054\u5176\u4ED6 MotionHarness \u5DE5\u7A0B\u3002");
17496
17506
  if (!binding) {
17497
17507
  binding = { id: id("binding"), sourceId: source.id, resolve: request.resolve, revision: 1, state: "unbound", lastReadback: actual, createdAt: now() };
17498
17508
  catalog.bindings[binding.id] = binding;
@@ -17510,10 +17520,23 @@ var Bridge = class {
17510
17520
  }
17511
17521
  async inspect(sourceId, bindingId) {
17512
17522
  assert2(Boolean(sourceId) !== Boolean(bindingId), "INVALID_REQUEST", "\u9700\u8981\u4E14\u53EA\u80FD\u63D0\u4F9B sourceId \u6216 bindingId\u3002");
17523
+ if (bindingId) return this.inspectStatus(bindingId);
17524
+ const source = get((await this.store.read()).sources, sourceId, "\u6E90");
17525
+ const present = await stat3(this.store.path(source.locator)).then((info) => info.isDirectory(), () => false);
17526
+ return {
17527
+ source,
17528
+ current: source.observation,
17529
+ contentChecked: false,
17530
+ state: present ? "unbound" : "source-missing",
17531
+ ...!present ? { error: { code: "SOURCE_MISSING", message: "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\u76EE\u5F55\u3002" } } : {}
17532
+ };
17533
+ }
17534
+ // Export requires fresh content and full file evidence. Routine reads do not.
17535
+ async inspectForExport(bindingId) {
17513
17536
  const catalog = await this.store.read();
17514
- const binding = bindingId ? get(catalog.bindings, bindingId, "\u7ED1\u5B9A") : void 0;
17515
- const source = get(catalog.sources, sourceId ?? binding.sourceId, "\u6E90");
17516
- const artifact = binding?.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
17537
+ const binding = get(catalog.bindings, bindingId, "\u7ED1\u5B9A");
17538
+ const source = get(catalog.sources, binding.sourceId, "\u6E90");
17539
+ const artifact = binding.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
17517
17540
  const artifactAvailable = artifact ? await fileDigest(this.store.artifactPath(artifact.relativePath)).then((hash2) => hash2 === artifact.sha256, () => false) : false;
17518
17541
  let current;
17519
17542
  try {
@@ -17526,67 +17549,53 @@ var Bridge = class {
17526
17549
  assert2(saved.revision === source.revision && saved.locator === source.locator, "VERSION_CONFLICT", "\u68C0\u67E5\u671F\u95F4\u5DE5\u7A0B\u4F4D\u7F6E\u5DF2\u6539\u53D8\u3002");
17527
17550
  rememberObservation(saved, current);
17528
17551
  });
17529
- const actual = binding ? await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId) : void 0;
17530
- let state = binding?.state ?? "unbound";
17531
- if (artifact && actual && resolve3(actual.path) !== this.store.bindingPath(binding, artifact)) state = "stale";
17532
- else if (binding?.appliedContentVersion && binding.appliedContentVersion !== current.contentVersion) state = "stale";
17552
+ const actual = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
17553
+ let state = binding.state;
17554
+ if (artifact && resolve3(actual.path) !== this.store.bindingPath(binding, artifact)) state = "stale";
17555
+ else if (binding.appliedContentVersion && binding.appliedContentVersion !== current.contentVersion) state = "stale";
17533
17556
  else if (artifact?.verification === "bridge-verified" && (!current.runtimeIdentity || artifact.receipt?.runtimeIdentity !== current.runtimeIdentity)) state = "stale";
17534
- if (artifact && (!artifactAvailable || binding && await fileDigest(this.store.bindingPath(binding, artifact)).catch(() => null) !== artifact.sha256)) state = "failed";
17535
- if (artifact && actual) {
17557
+ if (artifact && (!artifactAvailable || await fileDigest(this.store.bindingPath(binding, artifact)).catch(() => null) !== artifact.sha256)) state = "failed";
17558
+ if (artifact) {
17536
17559
  try {
17537
- const link2 = JSON.parse(actual.metadata["motionharness.bridge"] ?? "{}");
17538
- if (link2.bindingId !== binding.id || link2.sourceId !== source.id || link2.artifactId !== artifact.id) state = "failed";
17560
+ checkOwnership(binding, actual);
17539
17561
  } catch {
17540
17562
  state = "failed";
17541
17563
  }
17542
- if (!actual.usageScanComplete || actual.uses.some((item) => item.unsupported.some((reason) => reason !== "offline-media-reference"))) state = "unsupported";
17543
- else if (actual.uses.some((item) => item.unsupported.includes("offline-media-reference")) && state !== "failed") state = "stale";
17544
17564
  }
17545
17565
  if (current.audioPresent) state = "unsupported";
17546
- const jobs = Object.values(catalog.jobs).filter((j) => !terminalPhases.includes(j.phase) && JSON.stringify(j.request).includes(binding?.id ?? source.id));
17566
+ const jobs = Object.values(catalog.jobs).filter((j) => !terminalPhases.includes(j.phase) && JSON.stringify(j.request).includes(binding.id));
17547
17567
  return { source, current, binding, artifact, actual, state, activeJobs: jobs, priorArtifactRemainsAvailable: artifactAvailable };
17548
17568
  }
17549
- /** Routine panel state reads never scan timelines, export OTIO or select a UI page. */
17569
+ /** Routine status checks identity and availability, not content or timelines.
17570
+ * Fresh content and complete file validation happen before mutations/export. */
17550
17571
  async inspectStatus(bindingId) {
17551
17572
  const catalog = await this.store.read(), binding = get(catalog.bindings, bindingId, "\u7ED1\u5B9A");
17552
17573
  const source = get(catalog.sources, binding.sourceId, "\u6E90");
17553
17574
  const artifact = binding.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
17554
- const base = { source, binding, artifact };
17575
+ const base = { source, binding, artifact, current: source.observation, contentChecked: false };
17555
17576
  try {
17556
- const [current, available] = await Promise.all([
17557
- this.mh.inspect(this.store.path(source.locator)),
17558
- artifact ? fileDigest(this.store.bindingPath(binding, artifact)).then((value) => value === artifact.sha256, () => false) : Promise.resolve(false)
17559
- ]);
17560
- const identity2 = await this.host.call(
17561
- "media_identity",
17562
- { scope: { databaseId: binding.resolve.databaseId, projectId: binding.resolve.projectId }, mediaPoolItemId: binding.resolve.mediaPoolItemId }
17563
- );
17564
- let link2 = {};
17565
- try {
17566
- const value = JSON.parse(identity2.metadata?.["motionharness.bridge"] ?? "{}");
17567
- if (value && typeof value === "object" && !Array.isArray(value)) link2 = value;
17568
- } catch {
17569
- }
17570
- const associationVerified = Boolean(artifact && available && digest(identity2.scope) === digest({ databaseId: binding.resolve.databaseId, projectId: binding.resolve.projectId }) && identity2.mediaPoolItemId === binding.resolve.mediaPoolItemId && resolve3(identity2.path) === this.store.bindingPath(binding, artifact) && link2.schemaVersion === 1 && link2.bindingId === binding.id && link2.sourceId === source.id && link2.artifactId === artifact.id);
17571
- let state = binding.state;
17572
- if (!associationVerified) state = "failed";
17573
- else if (binding.appliedContentVersion && binding.appliedContentVersion !== current.contentVersion || artifact?.verification === "bridge-verified" && (!current.runtimeIdentity || artifact.receipt?.runtimeIdentity !== current.runtimeIdentity)) state = "stale";
17574
- if (!identity2.validatedHost || current.audioPresent || identity2.clipProperties?.["Proxy Media Path"]) state = "unsupported";
17577
+ const sourcePresent = await stat3(this.store.path(source.locator)).then((info) => info.isDirectory(), () => false);
17578
+ if (!sourcePresent) return { ...base, state: "source-missing", error: { code: "SOURCE_MISSING", message: "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u4ECE\u201C\u66F4\u591A\u2026\u201D\u91CD\u65B0\u5B9A\u4F4D\u3002" } };
17579
+ const identity2 = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
17580
+ checkOwnership(binding, identity2);
17581
+ const associationVerified = Boolean(artifact && artifact.sourceId === source.id && resolve3(identity2.path) === this.store.bindingPath(binding, artifact));
17582
+ assert2(associationVerified, "BINDING_CONFLICT", "\u539F\u7D20\u6750\u7684\u89C6\u9891\u8DEF\u5F84\u4E0E\u5DF2\u8BB0\u5F55\u5173\u8054\u4E0D\u4E00\u81F4\u3002");
17583
+ const mediaPresent = await stat3(identity2.path).then((info) => info.isFile(), () => false);
17575
17584
  const latest = await this.store.read();
17576
17585
  assert2(
17577
17586
  digest(latest.bindings[binding.id]) === digest(binding) && latest.sources[source.id]?.revision === source.revision,
17578
17587
  "VERSION_CONFLICT",
17579
17588
  "\u6838\u5BF9\u671F\u95F4\u5173\u8054\u6216\u6E90\u4F4D\u7F6E\u5DF2\u6539\u53D8\uFF0C\u8BF7\u5237\u65B0\u72B6\u6001\u3002"
17580
17589
  );
17590
+ const knownStale = binding.appliedContentVersion && source.observation && binding.appliedContentVersion !== source.observation.contentVersion;
17581
17591
  return {
17582
17592
  ...base,
17583
- current,
17584
- state,
17593
+ state: !mediaPresent || knownStale ? "stale" : binding.state,
17585
17594
  actual: { associationVerified },
17586
- ...!associationVerified ? { error: { message: "\u5F53\u524D\u89C6\u9891\u4E0E\u5DF2\u8BB0\u5F55\u5173\u8054\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u68C0\u67E5\u5173\u8054\u6216\u91CD\u65B0\u66F4\u65B0\u3002" } } : {}
17595
+ ...!mediaPresent ? { error: { message: "\u64AD\u653E\u89C6\u9891\u7F3A\u5931\uFF0C\u8BF7\u4ECE\u201C\u66F4\u591A\u2026\u201D\u6062\u590D\u5DF2\u5E94\u7528\u7248\u672C\u3002" } } : {}
17587
17596
  };
17588
17597
  } catch (error48) {
17589
- return { ...base, state: error48.code === "SOURCE_MISSING" ? "source-missing" : "failed", error: errorResult(error48) };
17598
+ return { ...base, state: "failed", actual: { associationVerified: false }, error: errorResult(error48) };
17590
17599
  }
17591
17600
  }
17592
17601
  /** Prepare a fixed human-readable action. No catalog writes, tasks or media rendering. */
@@ -17636,7 +17645,6 @@ var Bridge = class {
17636
17645
  const previousSettings = artifact.receipt?.before.settings;
17637
17646
  if (previousSettings) assert2(digest(previousSettings) === digest(current.settings), "OUTPUT_SPEC_MISMATCH", "\u6E90\u65F6\u957F\u3001\u5206\u8FA8\u7387\u6216\u5E27\u7387\u5DF2\u6539\u53D8\uFF0C\u8BF7\u53D1\u9001\u4E3A\u65B0\u7D20\u6750\u3002");
17638
17647
  const actual = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
17639
- assertUsages(actual);
17640
17648
  checkOwnership(binding, actual);
17641
17649
  checkReplacementSpec(actual, artifact);
17642
17650
  const latest = await this.store.read();
@@ -17649,9 +17657,8 @@ var Bridge = class {
17649
17657
  return {
17650
17658
  command: "update",
17651
17659
  title: "\u786E\u8BA4\u66F4\u65B0\u5230\u8FBE\u82AC\u5947",
17652
- message: "\u751F\u6210\u5E76\u66F4\u65B0\u6B64\u7D20\u6750\u7684\u5168\u90E8\u5F15\u7528\uFF0C\u4FDD\u7559\u5F53\u524D\u526A\u8F91\u3002\u786E\u8BA4\u540E\u5F15\u7528\u8303\u56F4\u6216\u52A8\u6548\u5185\u5BB9\u53D8\u5316\u65F6\u4F1A\u505C\u6B62\u3002",
17660
+ message: "\u751F\u6210\u5E76\u66F4\u65B0\u6B64\u7D20\u6750\u7684\u5168\u90E8\u5F15\u7528\uFF0C\u4FDD\u7559\u5F53\u524D\u526A\u8F91\u3002\u786E\u8BA4\u540E\u5173\u8054\u6216\u52A8\u6548\u5185\u5BB9\u53D8\u5316\u65F6\u4F1A\u505C\u6B62\u3002",
17653
17661
  target: { projectName: actual.projectName, mediaName: String(actual.clipProperties?.["Clip Name"] ?? source.name) },
17654
- usageCount: actual.uses.length,
17655
17662
  request: {
17656
17663
  bindingId: binding.id,
17657
17664
  expectedRevision: binding.revision,
@@ -17674,7 +17681,7 @@ var Bridge = class {
17674
17681
  await this.mh.projectPath(this.store.path(catalog.sources[result2.target.sourceId].locator));
17675
17682
  } catch (error48) {
17676
17683
  if (!(error48 instanceof BridgeError) || error48.code !== "SOURCE_MISSING") throw error48;
17677
- return { ...result2, canOpen: false, status: "source-missing", message: "Hotion Harness \u5DE5\u7A0B\u76EE\u5F55\u4E0D\u53EF\u7528\uFF0C\u8BF7\u901A\u8FC7\u66F4\u591A\u6865\u63A5\u64CD\u4F5C\u6062\u590D\u6216\u91CD\u5B9A\u4F4D\u5DE5\u7A0B\u3002" };
17684
+ return { ...result2, canOpen: false, status: "source-missing", message: "MotionHarness \u5DE5\u7A0B\u76EE\u5F55\u4E0D\u53EF\u7528\uFF0C\u8BF7\u901A\u8FC7\u66F4\u591A\u6865\u63A5\u64CD\u4F5C\u6062\u590D\u6216\u91CD\u5B9A\u4F4D\u5DE5\u7A0B\u3002" };
17678
17685
  }
17679
17686
  }
17680
17687
  return result2;
@@ -17848,9 +17855,9 @@ var Bridge = class {
17848
17855
  assert2(catalog.bindings[checkpoint.bindingId]?.revision === checkpoint.expectedRevision || catalog.bindings[checkpoint.bindingId]?.revision === checkpoint.expectedRevision + 1 && catalog.bindings[checkpoint.bindingId]?.artifactId === artifact.id, "RECOVERY_CONFLICT", "\u5173\u8054\u5728\u4EFB\u52A1\u4E2D\u65AD\u540E\u5DF2\u7ECF\u6539\u53D8\u3002");
17849
17856
  if (checkpoint.publication && action2 === "resume" && actual.metadata["motionharness.bridge"] === checkpoint.before.metadata["motionharness.bridge"]) {
17850
17857
  assert2(
17851
- actual.path === checkpoint.before.path && digest(actual.uses) === digest(checkpoint.before.uses) && digest(actual.clipProperties) === digest(checkpoint.before.clipProperties) && digest(actual.playbackPolicy) === digest(checkpoint.before.playbackPolicy),
17858
+ actual.path === checkpoint.before.path && digest(actual.clipProperties) === digest(checkpoint.before.clipProperties),
17852
17859
  "RECOVERY_CONFLICT",
17853
- "\u53D1\u5E03\u4E2D\u65AD\u540E\u7D20\u6750\u7684\u526A\u8F91\u3001\u89E3\u91CA\u6216\u64AD\u653E\u8BBE\u7F6E\u5DF2\u6539\u53D8\u3002"
17860
+ "\u53D1\u5E03\u4E2D\u65AD\u540E\u539F\u7D20\u6750\u7684\u8DEF\u5F84\u6216\u89E3\u91CA\u5DF2\u6539\u53D8\u3002"
17854
17861
  );
17855
17862
  actual = await this.host.replace(
17856
17863
  actual.scope,
@@ -17868,7 +17875,7 @@ var Bridge = class {
17868
17875
  link2 = JSON.parse(encoded ?? "{}");
17869
17876
  } catch {
17870
17877
  }
17871
- if (resolve3(actual.path) === this.store.artifactPath(checkpoint.mediaRelativePath ?? artifact.relativePath) && link2.bindingId === checkpoint.bindingId && link2.artifactId === artifact.id && digest(editUsages(actual, checkpoint.offlineRepair)) === digest(editUsages(checkpoint.before, checkpoint.offlineRepair)) && await fileDigest(actual.path) === artifact.sha256) {
17878
+ if (resolve3(actual.path) === this.store.artifactPath(checkpoint.mediaRelativePath ?? artifact.relativePath) && link2.bindingId === checkpoint.bindingId && link2.sourceId === checkpoint.sourceId && link2.artifactId === artifact.id && await fileDigest(actual.path) === artifact.sha256) {
17872
17879
  await this.store.mutate((c) => {
17873
17880
  const binding = get(c.bindings, checkpoint.bindingId, "\u7ED1\u5B9A");
17874
17881
  assert2(binding.revision === checkpoint.expectedRevision || binding.revision === checkpoint.expectedRevision + 1 && binding.artifactId === artifact.id, "RECOVERY_CONFLICT", "\u672C\u5730\u7ED1\u5B9A\u5728\u4E2D\u65AD\u540E\u53D1\u751F\u5176\u4ED6\u4FEE\u6539\u3002");
@@ -17878,7 +17885,7 @@ var Bridge = class {
17878
17885
  saved.results.push({ ...result2, recovered: true });
17879
17886
  saved.progress.completed = saved.results.filter((r) => r.applied === true).length;
17880
17887
  });
17881
- } else assert2(actual.fingerprint === checkpoint.before.fingerprint || checkpoint.publication && actual.path === checkpoint.before.path && digest(actual.metadata) === digest(checkpoint.before.metadata) && digest(actual.uses) === digest(checkpoint.before.uses) && digest(actual.clipProperties) === digest(checkpoint.before.clipProperties) && digest(actual.playbackPolicy) === digest(checkpoint.before.playbackPolicy) && [checkpoint.publication.sha256, checkpoint.publication.previousSha256].includes(await fileDigest(actual.path)), "RECOVERY_CONFLICT", "\u5BBF\u4E3B\u7ED3\u679C\u65E2\u4E0D\u662F\u65E7\u72B6\u6001\uFF0C\u4E5F\u4E0D\u662F\u53EF\u6838\u5B9E\u7684\u65B0\u7248\u672C\u3002");
17888
+ } else assert2(actual.fingerprint === checkpoint.before.fingerprint || checkpoint.publication && actual.path === checkpoint.before.path && digest(actual.metadata) === digest(checkpoint.before.metadata) && digest(actual.clipProperties) === digest(checkpoint.before.clipProperties) && [checkpoint.publication.sha256, checkpoint.publication.previousSha256].includes(await fileDigest(actual.path)), "RECOVERY_CONFLICT", "\u5BBF\u4E3B\u7ED3\u679C\u65E2\u4E0D\u662F\u65E7\u72B6\u6001\uFF0C\u4E5F\u4E0D\u662F\u53EF\u6838\u5B9E\u7684\u65B0\u7248\u672C\u3002");
17882
17889
  }
17883
17890
  job = get((await this.store.read()).jobs, taskId, "\u4EFB\u52A1");
17884
17891
  if (job.operation === "restore" || job.operation === "update" || job.operation === "apply") reconciled = job.results.some((r) => r.applied === true);
@@ -17887,7 +17894,7 @@ var Bridge = class {
17887
17894
  reconciled = request.targets.every((target) => job.results.some((r) => r.bindingId === target.bindingId && r.applied === true));
17888
17895
  for (const target of request.targets.filter((t) => !job.results.some((r) => r.bindingId === t.bindingId && r.applied === true))) {
17889
17896
  const binding = get((await this.store.read()).bindings, target.bindingId, "\u7ED1\u5B9A"), source = get(catalog.sources, binding.sourceId, "\u6E90");
17890
- assert2(!(await this.mh.renderStatus(this.store.path(source.locator))).locked, "RECOVERY_WAIT", "Hotion Harness \u4ECD\u6709\u6E32\u67D3\u6301\u9501\uFF0C\u8BF7\u7B49\u5F85\u8BE5\u4EFB\u52A1\u91CA\u653E\u540E\u6838\u5BF9\u3002");
17897
+ assert2(!(await this.mh.renderStatus(this.store.path(source.locator))).locked, "RECOVERY_WAIT", "MotionHarness \u4ECD\u6709\u6E32\u67D3\u6301\u9501\uFF0C\u8BF7\u7B49\u5F85\u8BE5\u4EFB\u52A1\u91CA\u653E\u540E\u6838\u5BF9\u3002");
17891
17898
  }
17892
17899
  }
17893
17900
  } else if (job.operation === "render") {
@@ -17899,7 +17906,7 @@ var Bridge = class {
17899
17906
  reconciled = true;
17900
17907
  } else {
17901
17908
  const source = get(catalog.sources, renderSchema.parse(job.request).sourceId, "\u6E90");
17902
- assert2(!(await this.mh.renderStatus(this.store.path(source.locator))).locked, "RECOVERY_WAIT", "Hotion Harness \u4ECD\u6709\u6E32\u67D3\u6301\u9501\uFF0C\u8BF7\u7B49\u5F85\u6E05\u7406\u3002");
17909
+ assert2(!(await this.mh.renderStatus(this.store.path(source.locator))).locked, "RECOVERY_WAIT", "MotionHarness \u4ECD\u6709\u6E32\u67D3\u6301\u9501\uFF0C\u8BF7\u7B49\u5F85\u6E05\u7406\u3002");
17903
17910
  }
17904
17911
  } else if (job.operation === "duplicate") {
17905
17912
  const checkpoint = journal.duplicate;
@@ -17954,7 +17961,7 @@ var Bridge = class {
17954
17961
  const observation = await this.mh.inspect(this.store.path(checkpoint.destination));
17955
17962
  assert2(observation.coverage === "public-package-v1" && observation.contentVersion === checkpoint.contentVersion, "RECOVERY_CONFLICT", "\u526F\u672C\u76EE\u5F55\u4E0D\u5B8C\u6574\u6216\u5185\u5BB9\u5DF2\u6539\u53D8\uFF0C\u4FDD\u7559\u73B0\u573A\u4E14\u4E0D\u91CD\u65B0\u89E3\u5305\u3002");
17956
17963
  await this.store.mutate((c) => {
17957
- const source = c.sources[checkpoint.sourceId] ?? { id: checkpoint.sourceId, name: duplicateSchema.parse(job.request).name ?? "Hotion Harness \u72EC\u7ACB\u526F\u672C", locator: checkpoint.destination, revision: 1, createdAt: now(), observation };
17964
+ const source = c.sources[checkpoint.sourceId] ?? { id: checkpoint.sourceId, name: duplicateSchema.parse(job.request).name ?? "MotionHarness \u72EC\u7ACB\u526F\u672C", locator: checkpoint.destination, revision: 1, createdAt: now(), observation };
17958
17965
  c.sources[source.id] = source;
17959
17966
  if (!("bindingId" in duplicateSchema.parse(job.request))) get(c.jobs, taskId, "\u4EFB\u52A1").results = [{ source, originalSourceId: checkpoint.originalSourceId, independent: true, applied: true, recovered: true }];
17960
17967
  });
@@ -18003,7 +18010,7 @@ var Bridge = class {
18003
18010
  assert2(!nativeFiles.some((name) => name.startsWith(nativePrefix)), "RECOVERY_CONFLICT", "\u53D1\u73B0\u672C\u6B21\u590D\u5236\u7684\u539F\u751F\u4E8B\u52A1\u6587\u4EF6\uFF0C\u5FC5\u987B\u5148\u6838\u5BF9\u8BE5\u4E8B\u52A1\u3002");
18004
18011
  if (instance && binding) {
18005
18012
  assert2(binding.revision === instance.expectedRevision && binding.sourceId === checkpoint.originalSourceId, "RECOVERY_CONFLICT", "\u539F\u5173\u8054\u5728\u590D\u5236\u4E2D\u65AD\u540E\u53D1\u751F\u53D8\u5316\uFF0C\u672A\u81EA\u52A8\u7ED3\u675F\u3002");
18006
- const [timeline, media] = await Promise.all([this.host.timeline(binding.resolve, instance.timelineId), this.host.media(binding.resolve, binding.resolve.mediaPoolItemId)]);
18013
+ const [timeline, media] = await Promise.all([this.host.timeline(binding.resolve, instance.timelineId), this.host.mediaUsages(binding.resolve, binding.resolve.mediaPoolItemId)]);
18007
18014
  assert2(
18008
18015
  timeline.fingerprint === instance.expectedTimelineFingerprint && media.fingerprint === instance.expectedMediaFingerprint,
18009
18016
  "RECOVERY_CONFLICT",
@@ -18056,7 +18063,7 @@ var Bridge = class {
18056
18063
  } catch (error48) {
18057
18064
  if (entered || error48.code !== "ELOCKED") throw error48;
18058
18065
  }
18059
- await new Promise((resolve11) => setTimeout(resolve11, 100));
18066
+ await new Promise((resolve12) => setTimeout(resolve12, 100));
18060
18067
  }
18061
18068
  }
18062
18069
  async runJob(taskId, started) {
@@ -18151,7 +18158,6 @@ var Bridge = class {
18151
18158
  assert2(request.scope || !request.timelineId || request.timelineId === target.timelineId, "INVALID_REQUEST", "\u8DE8\u65F6\u95F4\u7EBF\u63D2\u5165\u9700\u8981\u540C\u65F6\u6307\u5B9A Resolve \u5DE5\u7A0B\u8EAB\u4EFD\u3002");
18152
18159
  assert2(timelineId === target.timelineId || request.recordFrame !== void 0, "INVALID_REQUEST", "\u6307\u5B9A\u5176\u4ED6\u65F6\u95F4\u7EBF\u65F6\uFF0C\u9700\u8981\u660E\u786E\u8BE5\u65F6\u95F4\u7EBF\u7684 recordFrame\u3002");
18153
18160
  const timeline = await this.host.timeline(scope, timelineId);
18154
- assert2(timeline.validatedHost !== false, "CAPABILITY_UNAVAILABLE", "\u6B64 Resolve \u5E73\u53F0\u6216\u6784\u5EFA\u5C1A\u672A\u9A8C\u8BC1\u81EA\u52A8\u63D2\u5165\uFF0C\u672A\u5F00\u59CB\u6E32\u67D3\u3002");
18155
18161
  const recordFrame = request.recordFrame ?? target.recordFrame;
18156
18162
  const timelineFrames = nativeTimelineFrames(spec.frameCount, spec.fps, timeline.fps);
18157
18163
  assert2(timeline.items.every((item) => Number.isFinite(item.startFrame) && Number.isFinite(item.endFrame) && Number.isSafeInteger(item.track)), "UNSUPPORTED_TIMELINE_ITEM", "\u65E0\u6CD5\u5B8C\u6574\u8BFB\u53D6\u8F68\u9053\u5360\u7528\u533A\u95F4\u3002");
@@ -18321,6 +18327,11 @@ var Bridge = class {
18321
18327
  }
18322
18328
  async replacePlayback(taskId, binding, artifact, before, offlineRepair) {
18323
18329
  const catalog = await this.store.read(), previous2 = binding.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
18330
+ assert2(artifact.sourceId === binding.sourceId && (!previous2 || previous2.sourceId === binding.sourceId), "BINDING_CONFLICT", "\u89C6\u9891\u4EA7\u7269\u4E0D\u5C5E\u4E8E\u5173\u8054\u7684\u6E90\u5DE5\u7A0B\u3002");
18331
+ if (previous2 && !offlineRepair) {
18332
+ assert2(resolve3(before.path) === this.store.bindingPath(binding, previous2), "VERSION_CONFLICT", "\u539F\u7D20\u6750\u5DF2\u88AB\u91CD\u65B0\u94FE\u63A5\uFF0C\u672A\u8986\u76D6\u5176\u4ED6\u89C6\u9891\u3002");
18333
+ assert2(await fileDigest(before.path).catch(() => null) === previous2.sha256, "ARTIFACT_CHANGED", "\u5F53\u524D\u64AD\u653E\u89C6\u9891\u4E0E\u5DF2\u767B\u8BB0\u4EA7\u7269\u4E0D\u540C\uFF0C\u672A\u8986\u76D6\u3002");
18334
+ }
18324
18335
  const mediaRelativePath = binding.mediaRelativePath ?? this.store.stableLocator(binding.id, artifact);
18325
18336
  const path = this.store.bindingPath({ ...binding, mediaRelativePath }, artifact);
18326
18337
  const publication = {
@@ -18339,11 +18350,8 @@ var Bridge = class {
18339
18350
  offlineRepair,
18340
18351
  publication
18341
18352
  );
18342
- assert2(
18343
- resolve3(actual.path) === path && digest(editUsages(actual, Boolean(offlineRepair))) === digest(editUsages(before, Boolean(offlineRepair))),
18344
- "APPLY_OUTCOME_UNKNOWN",
18345
- "\u89C6\u9891\u66FF\u6362\u540E\u7684\u8DEF\u5F84\u6216\u526A\u8F91\u72B6\u6001\u8BFB\u56DE\u4E0D\u4E00\u81F4\u3002"
18346
- );
18353
+ checkOwnership({ ...binding, artifactId: artifact.id }, actual);
18354
+ assert2(resolve3(actual.path) === path, "APPLY_OUTCOME_UNKNOWN", "\u89C6\u9891\u66FF\u6362\u540E\u7684\u539F\u7D20\u6750\u8DEF\u5F84\u8BFB\u56DE\u4E0D\u4E00\u81F4\u3002");
18347
18355
  return actual;
18348
18356
  }
18349
18357
  async applyArtifact(taskId, input, restore2 = false) {
@@ -18354,11 +18362,10 @@ var Bridge = class {
18354
18362
  if (binding.artifactId) assert2(sameOutputSpec(get(catalog.artifacts, binding.artifactId, "\u4EA7\u7269").spec, artifact.spec), "OUTPUT_SPEC_MISMATCH", "\u4EBA\u5DE5\u56DE\u586B\u4E0D\u80FD\u6539\u53D8\u5DF2\u5E94\u7528\u7684\u6E90\u533A\u95F4\u6216\u8F93\u51FA\u89C4\u683C\u3002");
18355
18363
  const filePath = this.store.artifactPath(artifact.relativePath);
18356
18364
  await this.phase(taskId, "validating");
18357
- assert2(await fileDigest(filePath) === artifact.sha256, "ARTIFACT_CHANGED", "\u4EA7\u7269\u6587\u4EF6\u5DF2\u6539\u53D8\u3002");
18365
+ assert2(await fileDigest(filePath).catch(() => null) === artifact.sha256, "ARTIFACT_CHANGED", "\u4EA7\u7269\u6587\u4EF6\u7F3A\u5931\u6216\u5DF2\u6539\u53D8\u3002");
18358
18366
  const before = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
18359
- if (request.expectedMediaFingerprint) assert2(before.fingerprint === request.expectedMediaFingerprint, "VERSION_CONFLICT", "\u6240\u786E\u8BA4\u7684\u7D20\u6750\u5F15\u7528\u6216\u526A\u8F91\u72B6\u6001\u5DF2\u7ECF\u6539\u53D8\uFF0C\u672A\u5E94\u7528\u5386\u53F2\u753B\u9762\u3002");
18360
- const offlineRepair = binding.artifactId === artifact.id && binding.lastReadback?.path === before.path && !await stat3(before.path).then(() => true, () => false) && before.usageScanComplete && before.uses.every((item) => item.unsupported.every((reason) => reason === "offline-media-reference"));
18361
- if (!offlineRepair) assertUsages(before);
18367
+ if (request.expectedMediaFingerprint) assert2(before.fingerprint === request.expectedMediaFingerprint, "VERSION_CONFLICT", "\u6240\u786E\u8BA4\u7684\u539F\u7D20\u6750\u8EAB\u4EFD\u6216\u5173\u8054\u5DF2\u7ECF\u6539\u53D8\uFF0C\u672A\u5E94\u7528\u5386\u53F2\u753B\u9762\u3002");
18368
+ const offlineRepair = binding.artifactId === artifact.id && binding.lastReadback?.path === before.path && !await stat3(before.path).then(() => true, () => false);
18362
18369
  checkOwnership(binding, before);
18363
18370
  checkReplacementSpec(before, artifact);
18364
18371
  if (artifact.contentVersion && !restore2) {
@@ -18368,7 +18375,7 @@ var Bridge = class {
18368
18375
  assert2((await this.store.read()).bindings[binding.id]?.revision === binding.revision, "VERSION_CONFLICT", "\u7ED1\u5B9A\u5728\u6821\u9A8C\u671F\u95F4\u5DF2\u6539\u53D8\u3002");
18369
18376
  await this.store.mutate((c) => {
18370
18377
  const job = get(c.jobs, taskId, "\u4EFB\u52A1");
18371
- job.results.push({ bindingId: binding.id, artifactId: artifact.id, affectedUses: before.uses, applied: false });
18378
+ job.results.push({ bindingId: binding.id, artifactId: artifact.id, applied: false });
18372
18379
  job.journal = { apply: { bindingId: binding.id, artifactId: artifact.id, sourceId: binding.sourceId, expectedRevision: binding.revision, before, offlineRepair } };
18373
18380
  });
18374
18381
  await this.phase(taskId, "applying");
@@ -18401,9 +18408,9 @@ var Bridge = class {
18401
18408
  await this.phase(taskId, "applying");
18402
18409
  const actual = existing ? before : await this.host.bind(binding.resolve, binding.resolve.mediaPoolItemId, wanted, before.fingerprint);
18403
18410
  assert2(
18404
- actual.metadata["motionharness.bridge"] === wanted["motionharness.bridge"] && actual.path === before.path && digest(actual.uses) === digest(before.uses),
18411
+ actual.metadata["motionharness.bridge"] === wanted["motionharness.bridge"] && actual.path === before.path,
18405
18412
  "APPLY_OUTCOME_UNKNOWN",
18406
- "\u5173\u8054\u6062\u590D\u540E\u7684\u8EAB\u4EFD\u6216\u526A\u8F91\u8BFB\u56DE\u4E0D\u4E00\u81F4\u3002"
18413
+ "\u5173\u8054\u6062\u590D\u540E\u7684\u539F\u7D20\u6750\u8EAB\u4EFD\u8BFB\u56DE\u4E0D\u4E00\u81F4\u3002"
18407
18414
  );
18408
18415
  await this.finishAssociationRestore(taskId, binding.id, binding.revision, artifact, actual);
18409
18416
  }
@@ -18443,7 +18450,7 @@ var Bridge = class {
18443
18450
  assert2(
18444
18451
  after.contentVersion === observation.contentVersion && after.runtimeIdentity === observation.runtimeIdentity && after.sessionIdentity === observation.sessionIdentity,
18445
18452
  "VERSION_CONFLICT",
18446
- "\u6E32\u67D3\u524D\u540E\u7684 Hotion Harness \u5185\u5BB9\u3001\u8FD0\u884C\u65F6\u6216\u4F1A\u8BDD\u4E0D\u4E00\u81F4\uFF0C\u672A\u5E94\u7528\u65B0\u7ED3\u679C\u3002"
18453
+ "\u6E32\u67D3\u524D\u540E\u7684 MotionHarness \u5185\u5BB9\u3001\u8FD0\u884C\u65F6\u6216\u4F1A\u8BDD\u4E0D\u4E00\u81F4\uFF0C\u672A\u5E94\u7528\u65B0\u7ED3\u679C\u3002"
18447
18454
  );
18448
18455
  await this.store.mutate((catalog) => {
18449
18456
  const current = get(catalog.sources, sourceId, "\u6E90");
@@ -18470,7 +18477,7 @@ var Bridge = class {
18470
18477
  async renderSource(taskId, input, signal) {
18471
18478
  const request = renderSchema.parse(input), source = get((await this.store.read()).sources, request.sourceId, "\u6E90");
18472
18479
  const observation = await this.mh.inspect(this.store.path(source.locator));
18473
- assert2(observation.contentVersion === request.expectedContentVersion, "VERSION_CONFLICT", "Hotion Harness \u5185\u5BB9\u4E0E\u8BF7\u6C42\u7684\u7248\u672C\u4E0D\u4E00\u81F4\u3002");
18480
+ assert2(observation.contentVersion === request.expectedContentVersion, "VERSION_CONFLICT", "MotionHarness \u5185\u5BB9\u4E0E\u8BF7\u6C42\u7684\u7248\u672C\u4E0D\u4E00\u81F4\u3002");
18474
18481
  const artifact = await this.renderArtifact(taskId, source.id, observation, request.outputSpec, request.purpose, signal);
18475
18482
  await this.store.mutate((c) => {
18476
18483
  get(c.jobs, taskId, "\u4EFB\u52A1").results = [{ sourceId: source.id, artifactId: artifact.id, verification: artifact.verification, applied: false }];
@@ -18486,9 +18493,9 @@ var Bridge = class {
18486
18493
  let checkpoint = (await this.job(taskId)).journal?.duplicate;
18487
18494
  if (instance) {
18488
18495
  assert2(originalBinding.revision === instance.expectedRevision && originalBinding.artifactId, "VERSION_CONFLICT", "\u539F\u5B9E\u4F8B\u5173\u8054\u5DF2\u6539\u53D8\u6216\u5C1A\u672A\u5E94\u7528\u89C6\u9891\u3002");
18489
- const [timeline, media] = await Promise.all([this.host.timeline(originalBinding.resolve, instance.timelineId), this.host.media(originalBinding.resolve, originalBinding.resolve.mediaPoolItemId)]);
18496
+ const [timeline, media] = await Promise.all([this.host.timeline(originalBinding.resolve, instance.timelineId), this.host.mediaUsages(originalBinding.resolve, originalBinding.resolve.mediaPoolItemId)]);
18490
18497
  assert2(timeline.fingerprint === instance.expectedTimelineFingerprint && media.fingerprint === instance.expectedMediaFingerprint, "VERSION_CONFLICT", "\u590D\u5236\u524D\u65F6\u95F4\u7EBF\u6216\u7D20\u6750\u5DF2\u6539\u53D8\u3002");
18491
- assertUsages(media);
18498
+ assertInstanceUsages(media);
18492
18499
  checkOwnership(originalBinding, media);
18493
18500
  const target = media.uses.find((item) => item.timelineId === instance.timelineId && item.id === instance.itemId);
18494
18501
  assert2(target && !target.intrinsicEntry && target.kind !== "generator", "UNSUPPORTED_TIMELINE_ITEM", "\u9700\u8981\u660E\u786E\u7684\u666E\u901A\u89C6\u9891\u5B9E\u4F8B\u3002");
@@ -18632,14 +18639,13 @@ var Bridge = class {
18632
18639
  const c = await this.store.read(), binding = get(c.bindings, target.bindingId, "\u7ED1\u5B9A"), source = get(c.sources, binding.sourceId, "\u6E90");
18633
18640
  assert2(binding.revision === target.expectedRevision, "VERSION_CONFLICT", "\u7ED1\u5B9A\u7248\u672C\u5DF2\u6539\u53D8\u3002");
18634
18641
  const obs = await this.mh.inspect(this.store.path(source.locator));
18635
- assert2(obs.contentVersion === target.expectedContentVersion, "VERSION_CONFLICT", "Hotion Harness \u5185\u5BB9\u5DF2\u6539\u53D8\u3002");
18642
+ assert2(obs.contentVersion === target.expectedContentVersion, "VERSION_CONFLICT", "MotionHarness \u5185\u5BB9\u5DF2\u6539\u53D8\u3002");
18636
18643
  checkObservation(obs, request.outputSpec);
18637
18644
  if (binding.artifactId) assert2(sameOutputSpec(get(c.artifacts, binding.artifactId, "\u4EA7\u7269").spec, request.outputSpec), "OUTPUT_SPEC_MISMATCH", "\u540C\u6B65\u4E0D\u80FD\u6539\u53D8\u5DF2\u5E94\u7528\u7684\u5E27\u533A\u95F4\u3001\u5C3A\u5BF8\u3001\u5E27\u7387\u6216\u989C\u8272\u89E3\u91CA\u3002");
18638
18645
  const previousSettings = binding.artifactId ? c.artifacts[binding.artifactId]?.receipt?.before.settings : void 0;
18639
18646
  if (previousSettings && !request.preserveSourceRange) assert2(digest(previousSettings) === digest(obs.settings), "OUTPUT_SPEC_MISMATCH", "\u6E90\u65F6\u957F\u3001\u5206\u8FA8\u7387\u6216\u5E27\u7387\u5DF2\u6539\u53D8\uFF1B\u82E5\u8981\u4FDD\u7559\u539F\u6E90\u533A\u95F4\uFF0C\u8BF7\u663E\u5F0F\u6307\u5B9A preserveSourceRange\u3002", { previousSettings, currentSettings: obs.settings });
18640
18647
  const actual = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
18641
- if (target.expectedMediaFingerprint) assert2(actual.fingerprint === target.expectedMediaFingerprint, "VERSION_CONFLICT", "\u786E\u8BA4\u540E\u7D20\u6750\u5F15\u7528\u6216\u526A\u8F91\u72B6\u6001\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u3002");
18642
- assertUsages(actual);
18648
+ if (target.expectedMediaFingerprint) assert2(actual.fingerprint === target.expectedMediaFingerprint, "VERSION_CONFLICT", "\u786E\u8BA4\u540E\u539F\u7D20\u6750\u7684\u8EAB\u4EFD\u3001\u5173\u8054\u6216\u89C4\u683C\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u3002");
18643
18649
  checkOwnership(binding, actual);
18644
18650
  checkReplacementSpec(actual, { spec: request.outputSpec });
18645
18651
  }
@@ -18664,7 +18670,6 @@ var Bridge = class {
18664
18670
  assert2(binding.revision === target.expectedRevision && observation.contentVersion === target.expectedContentVersion, "VERSION_CONFLICT", "\u6E90\u6216\u7ED1\u5B9A\u5728\u6392\u961F\u671F\u95F4\u5DF2\u6539\u53D8\u3002");
18665
18671
  const before = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
18666
18672
  if (target.expectedMediaFingerprint) assert2(before.fingerprint === target.expectedMediaFingerprint, "VERSION_CONFLICT", "\u51C6\u5907\u5B8C\u6210\u540E\u7D20\u6750\u72B6\u6001\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u3002");
18667
- assertUsages(before);
18668
18673
  checkOwnership(binding, before);
18669
18674
  const appliedArtifact = binding.artifactId ? c.artifacts[binding.artifactId] : void 0;
18670
18675
  if (appliedArtifact && appliedArtifact.verification === "bridge-verified" && observation.runtimeIdentity && appliedArtifact.receipt?.runtimeIdentity === observation.runtimeIdentity && appliedArtifact.contentVersion === observation.contentVersion && sameOutputSpec(appliedArtifact.spec, request.outputSpec) && appliedArtifact.purpose === request.purpose && resolve3(before.path) === this.store.bindingPath(binding, appliedArtifact) && await fileDigest(before.path).then((hash2) => hash2 === appliedArtifact.sha256, () => false)) {
@@ -18683,7 +18688,6 @@ var Bridge = class {
18683
18688
  assert2(latestSource.contentVersion === observation.contentVersion && latest.bindings[binding.id]?.revision === binding.revision && latest.sources[source.id]?.revision === source.revision, "VERSION_CONFLICT", "\u5E94\u7528\u524D\u5185\u5BB9\u3001\u5173\u8054\u6216\u6E90\u4F4D\u7F6E\u53D1\u751F\u53D8\u5316\u3002");
18684
18689
  const latestMedia = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
18685
18690
  assert2(latestMedia.fingerprint === before.fingerprint, "VERSION_CONFLICT", "Resolve \u5728\u6E32\u67D3\u671F\u95F4\u5DF2\u6539\u53D8\u3002");
18686
- assertUsages(latestMedia);
18687
18691
  checkReplacementSpec(latestMedia, artifact);
18688
18692
  if (binding.artifactId === artifact.id && resolve3(latestMedia.path) === this.store.bindingPath(binding, artifact)) {
18689
18693
  assert2(
@@ -18743,7 +18747,7 @@ var Bridge = class {
18743
18747
  if (bindings.some((b) => b.bindingId === binding.id)) continue;
18744
18748
  const fixed = binding.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
18745
18749
  if (request.manualPolicy === "allow-pinned" && fixed?.verification === "manual-pinned") {
18746
- const actual = await this.host.media(binding.resolve, binding.resolve.mediaPoolItemId);
18750
+ const actual = await this.host.mediaUsages(binding.resolve, binding.resolve.mediaPoolItemId);
18747
18751
  const valid = fixed.media.validation?.fullDecode && resolve3(actual.path) === this.store.bindingPath(binding, fixed) && await fileDigest(this.store.bindingPath(binding, fixed)).then((hash2) => hash2 === fixed.sha256, () => false);
18748
18752
  let ownership2 = true;
18749
18753
  try {
@@ -18755,7 +18759,7 @@ var Bridge = class {
18755
18759
  bindings.push({ bindingId: binding.id, revision: binding.revision, sourceId: binding.sourceId, contentVersion: `manual-pinned:${fixed.sha256}`, artifactId: fixed.id, sha256: fixed.sha256, state: "manual-pinned" });
18756
18760
  continue;
18757
18761
  }
18758
- const result2 = await this.inspect(void 0, binding.id);
18762
+ const result2 = await this.inspectForExport(binding.id);
18759
18763
  const pinnedAllowed = request.manualPolicy === "allow-pinned" && result2.state === "manual-pinned";
18760
18764
  if (result2.state !== "ready-final" && !pinnedAllowed) blockers.push({ code: "BINDING_NOT_FINAL", bindingId: binding.id, state: result2.state, error: "error" in result2 ? result2.error : void 0 });
18761
18765
  if (!result2.artifact || !result2.priorArtifactRemainsAvailable || !("current" in result2) || !result2.current) continue;
@@ -18816,7 +18820,7 @@ var Bridge = class {
18816
18820
  await this.patchJob(taskId, { results: [{ resolveJobId: created.jobId, outputPath: output, started: true, status, applied: true }] });
18817
18821
  if (["Complete", "Cancelled", "Failed", "Background Render Cancelled", "Remote Render Cancelled"].includes(String(status.JobStatus))) break;
18818
18822
  if (signal.aborted) await this.host.cancelRender(receipt.request.scope, created.jobId, created.jobFingerprint);
18819
- await new Promise((resolve11) => setTimeout(resolve11, 500));
18823
+ await new Promise((resolve12) => setTimeout(resolve12, 500));
18820
18824
  }
18821
18825
  if (receipt.playbackPolicy) await this.host.finishRender(receipt.request.scope, created.jobId, receipt.playbackPolicy);
18822
18826
  assert2(status.JobStatus === "Complete", status.JobStatus === "Cancelled" ? "CANCELLED" : "RESOLVE_RENDER_FAILED", "\u6307\u5B9A Resolve \u8F93\u51FA\u4EFB\u52A1\u672A\u5B8C\u6210\u3002", { resolveJobId: created.jobId, status });
@@ -18865,7 +18869,7 @@ var Bridge = class {
18865
18869
  await mkdir5(directory, { recursive: true });
18866
18870
  const output = resolve3(directory, "source.png");
18867
18871
  await this.mh.preview(path, time3, output);
18868
- assert2((await this.mh.inspect(path)).contentVersion === before.contentVersion, "VERSION_CONFLICT", "\u622A\u56FE\u671F\u95F4 Hotion Harness \u5185\u5BB9\u5DF2\u6539\u53D8\u3002");
18872
+ assert2((await this.mh.inspect(path)).contentVersion === before.contentVersion, "VERSION_CONFLICT", "\u622A\u56FE\u671F\u95F4 MotionHarness \u5185\u5BB9\u5DF2\u6539\u53D8\u3002");
18869
18873
  const image = await readFile4(output);
18870
18874
  assert2(image.length <= 10 * 1024 * 1024 && image.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])), "INVALID_IMAGE", "\u68C0\u67E5\u56FE\u7247\u4E0D\u662F\u53D7\u652F\u6301\u5927\u5C0F\u7684 PNG\u3002");
18871
18875
  return { origin: "mh-source", sourceId, contentVersion: before.contentVersion, timeSeconds: time3, filePath: output, mimeType: "image/png", data: image.toString("base64"), provesResolveComposite: false };
@@ -20542,36 +20546,298 @@ async function retireLegacyEntries(options, input) {
20542
20546
  });
20543
20547
  }
20544
20548
 
20549
+ // src/i18n.ts
20550
+ import { execFileSync } from "node:child_process";
20551
+
20552
+ // src/i18n/en.json
20553
+ var en_default2 = {
20554
+ "MotionHarness \u6865\u63A5\u7EC4\u4EF6": "MotionHarness Bridge Component",
20555
+ " \u526F\u672C": " Copy",
20556
+ "\u4E3A\u8FD9\u4E2A\u7247\u6BB5\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u2026": "Create an independent copy for this clip\u2026",
20557
+ "\u4EFB\u52A1\u4E0E\u72B6\u6001\u2026": "Tasks and status\u2026",
20558
+ \u4EFB\u52A1\u5DF2\u53D6\u6D88: "Task cancelled",
20559
+ \u4EFB\u52A1\u5DF2\u5B8C\u6210: "Task completed",
20560
+ \u4EFB\u52A1\u5DF2\u6392\u961F: "Task queued",
20561
+ "\u4EFB\u52A1\u5DF2\u6392\u961F\u2026": "Task queued\u2026",
20562
+ "\u4FA7\u680F\u6765\u6E90\u5FEB\u7167\u65E0\u6548\u3002": "The sidebar source snapshot is invalid.",
20563
+ "\u4FA7\u680F\u7BA1\u7406\u5165\u53E3\u4E0D\u80FD\u6DF7\u7528\u76EE\u6807\u5FEB\u7167\u6216\u64CD\u4F5C\u53C2\u6570\u3002": "The sidebar management request cannot mix target snapshots with operation parameters.",
20564
+ "\u4FA7\u680F\u7BA1\u7406\u5165\u53E3\u8BF7\u6C42\u65E0\u6548\u3002": "The sidebar management request is invalid.",
20565
+ "\u4FA7\u680F\u7BA1\u7406\u5165\u53E3\u9700\u8981\u65B0\u7248\u6865\u63A5\u7EC4\u4EF6\uFF0C\u8BF7\u66F4\u65B0\u7EC4\u4EF6\u3002": "Update the MotionHarness Bridge Component to use sidebar management.",
20566
+ "\u4FA7\u680F\u9700\u8981\u652F\u6301\u6E90\u8EAB\u4EFD\u6838\u5BF9\u7684\u65B0\u7248\u6865\u63A5\u7EC4\u4EF6\u3002": "The sidebar requires a newer MotionHarness Bridge Component with source verification.",
20567
+ "\u4FA7\u680F\u9700\u8981\u65B0\u7248\u6865\u63A5\u7EC4\u4EF6\uFF0C\u8BF7\u5148\u66F4\u65B0\u7EC4\u4EF6\u3002\u672A\u53D1\u9001\u8BF7\u6C42\u5230\u65E7\u7248\u5165\u53E3\u3002": "Update the MotionHarness Bridge Component to use the sidebar. No request was sent to the old entry.",
20568
+ \u4FDD\u5B58\u72EC\u7ACB\u5DE5\u7A0B: "Save independent project",
20569
+ "\u4FEE\u590D\u5173\u8054\u2026": "Repair association\u2026",
20570
+ "\u4FEE\u590D\u5DE5\u7A0B\u5173\u8054\u2026": "Repair project association\u2026",
20571
+ "\u5148\u6838\u5BF9\u5DF2\u6709\u7ED3\u679C\uFF0C\u518D\u590D\u7528\u539F\u8BF7\u6C42\u4E0E\u89C6\u9891\u3002\u539F\u4EFB\u52A1\u6D89\u53CA\u7684\u5176\u4ED6\u7D20\u6750\u4E5F\u5728\u6B64\u8303\u56F4\u5185\uFF1B\u5982\u679C\u526A\u8F91\u5DF2\u53D1\u751F\u51B2\u7A81\uFF0C\u64CD\u4F5C\u4F1A\u505C\u6B62\u3002": "Existing results will be checked before reusing the original request and video. This includes other media in the original task. Editing conflicts stop the operation.",
20572
+ "\u5173\u8054\u6807\u8BB0\u4E3A\u6E32\u67D3\u4E2D\uFF0C\u4F46\u672A\u627E\u5230\u6D3B\u8DC3\u4EFB\u52A1\uFF0C\u8BF7\u67E5\u770B\u4EFB\u52A1\u8BE6\u60C5\u3002": "The association is marked as rendering, but no active task was found. Check task details.",
20573
+ "\u5173\u8054\u9700\u8981\u68C0\u67E5\uFF0C\u8BF7\u4ECE\u4FA7\u680F\u201C\u66F4\u591A\u2026\u201D\u67E5\u770B\u3002": "The association needs attention. Open More\u2026 in the sidebar.",
20574
+ "\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u2026": "Create independent copy\u2026",
20575
+ \u5237\u65B0\u7247\u6BB5\u72B6\u6001: "Refresh clip status",
20576
+ \u53D6\u6D88: "Cancel",
20577
+ \u53D6\u6D88\u4EFB\u52A1: "Cancel task",
20578
+ "\u53EF\u5173\u95ED\u7A97\u53E3\uFF0C\u6309\u4E0A\u65B9\u63D0\u793A\u7EE7\u7EED\u64CD\u4F5C\u3002": "You can close this window and follow the instructions above.",
20579
+ "\u53EF\u7EE7\u7EED\u4F7F\u7528\u8FBE\u82AC\u5947\u3002": "You can continue using DaVinci Resolve.",
20580
+ "\u53EF\u7EE7\u7EED\u4F7F\u7528\u8FBE\u82AC\u5947\u3002\u5173\u95ED\u7A97\u53E3\u4E0D\u4F1A\u53D6\u6D88\u4EFB\u52A1\u3002": "You can continue using DaVinci Resolve. Closing this window keeps the task running.",
20581
+ "\u56FE\u6587\u6B65\u9AA4\u6682\u4E0D\u53EF\u7528\uFF0C\u8BF7\u66F4\u65B0\u6865\u63A5\u7EC4\u4EF6\u540E\u91CD\u8BD5\u3002": "The illustrated guide is unavailable. Update the MotionHarness Bridge Component and try again.",
20582
+ "\u5C1A\u672A\u786E\u8BA4\u6240\u9009\u5DE5\u7A0B\u7684\u7F16\u8F91\u5668\u5DF2\u6253\u5F00\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5\u3002": "The editor has not confirmed opening the selected project. Check and try again.",
20583
+ \u5DE5\u7A0B\u5173\u8054\u5DF2\u4FEE\u590D: "Project association repaired",
20584
+ "\u5DE5\u7A0B\u5DF2\u4FEE\u6539\uFF0C\u53EF\u4EE5\u66F4\u65B0\u8FBE\u82AC\u5947\u89C6\u9891\u3002": "The project has changed. You can update the video in DaVinci Resolve.",
20585
+ \u5DE5\u7A0B\u6253\u5F00\u8BF7\u6C42\u5DF2\u5B8C\u6210: "Project opening request completed",
20586
+ \u5DF2\u6253\u5F00\u7F16\u8F91\u5668: "Editor opened",
20587
+ "\u5F53\u524D\u4F7F\u7528\u624B\u52A8\u6307\u5B9A\u7684\u89C6\u9891\u7248\u672C\u3002": "A manually selected video version is in use.",
20588
+ "\u5F53\u524D\u7247\u6BB5\u6682\u4E0D\u652F\u6301\u66F4\u65B0\uFF0C\u8BF7\u67E5\u770B\u4EFB\u52A1\u8BE6\u60C5\u3002": "This clip cannot be updated yet. Check task details.",
20589
+ "\u6062\u590D\u5386\u53F2\u7248\u672C\u2026": "Restore previous version\u2026",
20590
+ \u6062\u590D\u5DF2\u5E94\u7528\u7248\u672C: "Restore applied version",
20591
+ "\u6062\u590D\u7248\u672C\u4F1A\u5F71\u54CD\u6B64\u7D20\u6750\u7684\u5168\u90E8\u5F15\u7528\u3002": "Restoring a version affects every use of this media.",
20592
+ "\u6240\u9009 MotionHarness \u7247\u6BB5": "Selected MotionHarness clip",
20593
+ \u6240\u9009\u7247\u6BB5: "Selected clip",
20594
+ "\u627E\u4E0D\u5230 MotionHarness\u3002\u8BF7\u91CD\u65B0\u5B89\u88C5\u6865\u63A5\u7EC4\u4EF6\u3002": "MotionHarness was not found. Reinstall the MotionHarness Bridge Component.",
20595
+ "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u4ECE\u4FA7\u680F\u201C\u66F4\u591A\u2026\u201D\u91CD\u65B0\u5B9A\u4F4D\u3002": "The source project was not found. Relocate it using More\u2026 in the sidebar.",
20596
+ "\u64CD\u4F5C\u6CA1\u6709\u5B8C\u6210\u3002\u8BF7\u8FD0\u884C\u6865\u63A5\u8BCA\u65AD\u67E5\u770B\u8BE6\u60C5\u3002": "The operation did not complete. Run bridge diagnostics for details.",
20597
+ "\u64CD\u4F5C\u6CA1\u6709\u5B8C\u6210\uFF0C\u8BF7\u68C0\u67E5\u6865\u63A5\u8FDE\u63A5\u3002": "The operation did not complete. Check the bridge connection.",
20598
+ "\u65E0\u6CD5\u4FDD\u5B58\u672C\u5730\u8BF7\u6C42\u72B6\u6001\u3002": "Unable to save the local request state.",
20599
+ "\u65E0\u6CD5\u521B\u5EFA\u672C\u5730\u8BF7\u6C42\u901A\u9053\u3002": "Unable to create the local request channel.",
20600
+ "\u65E0\u6CD5\u542F\u52A8 MotionHarness\uFF0C\u8BF7\u4FEE\u590D\u7EC4\u4EF6\u5B89\u88C5\u3002": "Unable to start MotionHarness. Repair the MotionHarness Bridge Component installation.",
20601
+ "\u65E0\u6CD5\u542F\u52A8 MotionHarness\uFF0C\u8BF7\u91CD\u65B0\u5B89\u88C5\u6865\u63A5\u7EC4\u4EF6\u3002": "Unable to start MotionHarness. Reinstall the MotionHarness Bridge Component.",
20602
+ "\u65E0\u6CD5\u6253\u5F00\u672C\u5730\u8BF7\u6C42\u72B6\u6001\u3002": "Unable to open the local request state.",
20603
+ "\u65E7\u5165\u53E3\u6CA1\u6709\u8FD4\u56DE\u53EF\u6838\u5BF9\u7684\u7247\u6BB5\u8EAB\u4EFD\u3002": "The legacy entry did not return a verifiable clip identity.",
20604
+ "\u65E7\u5165\u53E3\u7F3A\u5C11\u70B9\u51FB\u65F6\u7684\u7247\u6BB5\u8EAB\u4EFD\uFF0C\u8BF7\u4FEE\u590D\u65E7\u5165\u53E3\u8F6C\u53D1\u3002": "The legacy entry lacks the clip identity captured on click. Repair its forwarder.",
20605
+ "\u6682\u65F6\u65E0\u6CD5\u8BFB\u53D6\u76F8\u5173\u4EFB\u52A1\u72B6\u6001\uFF0C\u8BF7\u7A0D\u540E\u5237\u65B0\u7247\u6BB5\u72B6\u6001\u3002": "The related task status is temporarily unavailable. Refresh the clip status later.",
20606
+ "\u66F4\u591A\u2026": "More\u2026",
20607
+ \u66F4\u65B0\u4F1A\u5F71\u54CD\u6B64\u7D20\u6750\u5728\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528: "Updating affects every use of this media in the project",
20608
+ "\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u4EFB\u52A1\u8BE6\u60C5": "Update failed. Check task details",
20609
+ "\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u4EFB\u52A1\u8BE6\u60C5\u3002": "Update failed. Check task details.",
20610
+ \u66F4\u65B0\u5B8C\u6210: "Update completed",
20611
+ \u66F4\u65B0\u6B64\u7D20\u6750: "Update this media",
20612
+ \u66F4\u65B0\u753B\u9762: "Update video",
20613
+ \u66F4\u65B0\u5230\u8FBE\u82AC\u5947: "Update in DaVinci Resolve",
20614
+ "\u66F4\u65B0\u7ED3\u679C\u5F85\u6838\u5B9E\uFF0C\u8BF7\u5148\u67E5\u770B\u4EFB\u52A1\u72B6\u6001\u3002": "The update result needs verification. Check the task status first.",
20615
+ "\u6700\u7EC8\u89C6\u9891\u5DF2\u5173\u8054\uFF0C\u6682\u65E0\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u3002": "The final video is linked. No task is running.",
20616
+ "\u672A\u6536\u5230\u53EF\u786E\u8BA4\u7684\u64CD\u4F5C\uFF0C\u8BF7\u5237\u65B0\u540E\u91CD\u8BD5\u3002": "No verifiable operation was received. Refresh and try again.",
20617
+ "\u672A\u6536\u5230\u5B8C\u6574\u4E14\u4E00\u81F4\u7684\u7247\u6BB5\u8EAB\u4EFD\uFF0C\u8BF7\u5173\u95ED\u7A97\u53E3\u540E\u91CD\u65B0\u9009\u62E9\u7247\u6BB5\u3002": "The clip identity is incomplete or inconsistent. Close this window and select the clip again.",
20618
+ "\u672A\u6536\u5230\u6709\u6548\u72B6\u6001\u3002\u8BF7\u8FD0\u884C\u6865\u63A5\u8BCA\u65AD\u67E5\u770B\u8BE6\u60C5\u3002": "No valid status was received. Run bridge diagnostics for details.",
20619
+ "\u672A\u80FD\u56FA\u5B9A\u5F53\u524D\u9009\u62E9\u3002\u8BF7\u5173\u95ED\u6B64\u7A97\u53E3\uFF0C\u9009\u4E2D\u4E00\u4E2A\u7247\u6BB5\u540E\u91CD\u65B0\u6253\u5F00\u3002": "Unable to capture the current selection. Close this window, select one clip, and reopen it.",
20620
+ "\u672A\u80FD\u6253\u5F00\u56FE\u6587\u6B65\u9AA4\uFF0C\u8BF7\u4ECE Studio \u5BFC\u51FA\u533A\u67E5\u770B\u5E2E\u52A9\u3002": "Unable to open the illustrated guide. Open help in the Studio export panel.",
20621
+ \u67E5\u770B\u72B6\u6001: "Check status",
20622
+ \u6838\u5BF9\u73B0\u6709\u4EFB\u52A1\u72B6\u6001: "Check existing task status",
20623
+ \u6B63\u5728\u51C6\u5907\u5DE5\u7A0B: "Preparing project",
20624
+ "\u6B63\u5728\u51C6\u5907\u5DE5\u7A0B\u2026": "Preparing project\u2026",
20625
+ "\u6B63\u5728\u53D6\u6D88\u2026": "Cancelling\u2026",
20626
+ "\u6B63\u5728\u53D6\u6D88\u4EFB\u52A1\u2026": "Cancelling task\u2026",
20627
+ "\u6B63\u5728\u53D6\u6D88\u4EFB\u52A1\uFF0C\u7B49\u5F85\u786E\u8BA4\u5904\u7406\u7ED3\u679C\u2026": "Cancelling task and waiting for the result\u2026",
20628
+ "\u6B63\u5728\u5B9A\u4F4D\u65E7\u7247\u6BB5\u7684\u5DE5\u7A0B\u2026": "Locating the legacy clip project\u2026",
20629
+ "\u6B63\u5728\u6253\u5F00\u5DE5\u7A0B\u2026": "Opening project\u2026",
20630
+ "\u6B63\u5728\u63D0\u4EA4\u66F4\u65B0\u2026": "Submitting update\u2026",
20631
+ "\u6B63\u5728\u63D0\u4EA4\u8BF7\u6C42\u2026": "Submitting request\u2026",
20632
+ \u6B63\u5728\u66F4\u65B0\u8FBE\u82AC\u5947: "Updating DaVinci Resolve",
20633
+ "\u6B63\u5728\u66F4\u65B0\u8FBE\u82AC\u5947\u2026": "Updating DaVinci Resolve\u2026",
20634
+ "\u6B63\u5728\u6838\u5B9E\u66F4\u65B0\u7ED3\u679C\uFF0C\u8BF7\u52FF\u91CD\u590D\u66F4\u65B0": "Verifying the update result. Do not submit another update",
20635
+ "\u6B63\u5728\u6838\u5BF9\u5E76\u7EE7\u7EED\u539F\u4EFB\u52A1\u2026": "Checking and resuming the original task\u2026",
20636
+ "\u6B63\u5728\u6838\u5BF9\u6E90\u5DE5\u7A0B\u4F4D\u7F6E\u2026": "Checking source project location\u2026",
20637
+ "\u6B63\u5728\u6838\u5BF9\u7247\u6BB5\u4E0E\u5F71\u54CD\u8303\u56F4\u2026": "Checking clip and affected uses\u2026",
20638
+ "\u6B63\u5728\u6838\u5BF9\u73B0\u6709\u4EFB\u52A1\u2026": "Checking existing task\u2026",
20639
+ "\u6B63\u5728\u6838\u5BF9\u7D20\u6750\u5173\u8054\u2026": "Checking media association\u2026",
20640
+ \u6B63\u5728\u68C0\u67E5\u89C6\u9891: "Validating video",
20641
+ "\u6B63\u5728\u68C0\u67E5\u89C6\u9891\u2026": "Validating video\u2026",
20642
+ \u6B63\u5728\u6E32\u67D3\u89C6\u9891: "Rendering video",
20643
+ "\u6B63\u5728\u6E32\u67D3\u89C6\u9891\u2026": "Rendering video\u2026",
20644
+ "\u6B63\u5728\u8BFB\u53D6\u5F53\u524D\u9009\u62E9\uFF0C\u8BF7\u6838\u5BF9\u5DE5\u7A0B\u540E\u64CD\u4F5C\u2026": "Reading current selection. Check the project before continuing\u2026",
20645
+ "\u6B63\u5728\u8BFB\u53D6\u6240\u9009\u7247\u6BB5\u2026": "Reading selected clip\u2026",
20646
+ "\u6B64\u7247\u6BB5\u5C1A\u672A\u5B8C\u6210\u5173\u8054\u3002": "This clip is not fully linked yet.",
20647
+ "\u6CA1\u6709\u627E\u5230\u5DF2\u63D0\u4EA4\u7684\u4EFB\u52A1\u3002\u8BF7\u5237\u65B0\u7247\u6BB5\u72B6\u6001\u540E\u91CD\u8BD5\u3002": "No submitted task was found. Refresh the clip status and try again.",
20648
+ "\u6DFB\u52A0\u4FA7\u680F\u5165\u53E3 \xB7 \u56FE\u6587\u6B65\u9AA4": "Add sidebar entry \xB7 Illustrated guide",
20649
+ \u6E90\u5DE5\u7A0B\u4F4D\u7F6E\u5DF2\u66F4\u65B0: "Source project location updated",
20650
+ \u72B6\u6001: "Status",
20651
+ "\u72B6\u6001\u7A97\u53E3\u8BF7\u6C42\u65E0\u6548\u3002": "The status window request is invalid.",
20652
+ "\u72B6\u6001\u89C1\u63D0\u793A\u7A97\uFF1B\u66F4\u65B0\u5F71\u54CD\u5168\u90E8\u5F15\u7528": "See the status window; updates affect every use",
20653
+ \u72EC\u7ACB\u526F\u672C\u5DF2\u521B\u5EFA: "Independent copy created",
20654
+ "\u76F8\u5173\u4EFB\u52A1\u5DF2\u7ED3\u675F\uFF0C\u6240\u9009\u7247\u6BB5\u72B6\u6001\u9700\u91CD\u65B0\u8BFB\u53D6\u3002": "The related task has ended. Refresh the selected clip status.",
20655
+ "\u76F8\u5173\u4EFB\u52A1\u7684\u7ED3\u679C\u5F85\u6838\u5B9E\uFF0C\u8BF7\u56DE\u5230\u539F\u4EFB\u52A1\u5165\u53E3\u5904\u7406\u540E\u5237\u65B0\u3002": "The related task result needs verification. Resolve it through its original entry, then refresh.",
20656
+ \u76F8\u5173\u6587\u4EF6: "related file",
20657
+ "\u7B49\u5F85\u5DF2\u7ED3\u675F\uFF1B\u8BF7\u6C42\u53EF\u80FD\u4ECD\u5728\u540E\u53F0\u5904\u7406\uFF0C\u8BF7\u5148\u67E5\u770B\u72B6\u6001\u3002": "The wait has ended. The request may still be running in the background. Check its status first.",
20658
+ "\u7B49\u5F85\u8D85\u65F6\u3002\u8BF7\u6C42\u53EF\u80FD\u4ECD\u5728\u5904\u7406\uFF0C\u8BF7\u5148\u67E5\u770B\u73B0\u6709\u4EFB\u52A1\u72B6\u6001\u3002": "The request timed out and may still be running. Check the existing task status first.",
20659
+ "\u7EC4\u4EF6\u672A\u914D\u7F6E\u3002\u8BF7\u8FD0\u884C mh bridge davinci install \u4FEE\u590D\u3002": "The MotionHarness Bridge Component is not configured. Run mh bridge davinci install to repair it.",
20660
+ "\u7EC4\u4EF6\u7F3A\u5C11\u72B6\u6001\u7A97\u53E3\uFF0C\u8BF7\u4FEE\u590D MotionHarness \u6865\u63A5\u7EC4\u4EF6\u5B89\u88C5\u3002": "The status window is missing. Repair the MotionHarness Bridge Component installation.",
20661
+ "\u7EC4\u4EF6\u914D\u7F6E\u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002": "The component configuration path must be absolute.",
20662
+ \u7EE7\u7EED: "Continue",
20663
+ \u7EE7\u7EED\u539F\u4EFB\u52A1: "Resume original task",
20664
+ "\u7EE7\u7EED\u539F\u4EFB\u52A1\u2026": "Resume original task\u2026",
20665
+ "\u7EE7\u7EED\u539F\u4EFB\u52A1\u4E2D\u5C1A\u672A\u5B8C\u6210\u7684\u64CD\u4F5C\uFF1F": "Resume unfinished operations in the original task?",
20666
+ \u7EE7\u7EED\u6838\u5BF9\u6E90\u5DE5\u7A0B\u4F4D\u7F6E: "Continue checking source project location",
20667
+ "\u7F16\u8F91 MotionHarness \u5DE5\u7A0B": "Edit MotionHarness project",
20668
+ \u7F16\u8F91\u5DE5\u7A0B: "Edit project",
20669
+ "\u7F3A\u5C11\u8BF7\u6C42\u53C2\u6570\u3002": "Request parameters are missing.",
20670
+ "\u89C6\u9891\u5DF2\u51C6\u5907\uFF0C\u5C1A\u672A\u66F4\u65B0\u5230\u8FBE\u82AC\u5947\u3002": "The video is ready but has not been updated in DaVinci Resolve.",
20671
+ \u89C6\u9891\u5DF2\u53D1\u9001\u5230\u8FBE\u82AC\u5947: "Video sent to DaVinci Resolve",
20672
+ \u89C6\u9891\u5DF2\u66F4\u65B0: "Video updated",
20673
+ "\u89C6\u9891\u5DF2\u751F\u6210\uFF0C\u5C1A\u672A\u66F4\u65B0\u5230\u8FBE\u82AC\u5947\u3002": "The video has been generated but has not been updated in DaVinci Resolve.",
20674
+ "\u89C6\u9891\u7248\u672C\u5C1A\u5F85\u6838\u5B9E\uFF0C\u8BF7\u67E5\u770B\u4EFB\u52A1\u8BE6\u60C5\u3002": "The video version needs verification. Check task details.",
20675
+ "\u8BF7\u5728\u7BA1\u7406\u7A97\u53E3\u4E2D\u6838\u5BF9\u5DE5\u7A0B\u548C\u67E5\u770B\u72B6\u6001\u3002": "Check the project and status in the management window.",
20676
+ "\u8BF7\u66F4\u65B0\u6865\u63A5\u7EC4\u4EF6\u540E\u4F7F\u7528\u66F4\u591A\u64CD\u4F5C\u3002": "Update the MotionHarness Bridge Component to use more actions.",
20677
+ "\u8BF7\u6C42\u53D6\u6D88\uFF0C\u5E76\u6838\u5BF9\u5DF2\u7ECF\u5B8C\u6210\u7684\u7ED3\u679C\u3002": "Request cancellation and check results already completed.",
20678
+ "\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci doctor \u68C0\u67E5\u8FDE\u63A5\u3002": "The request failed. Run mh bridge davinci doctor to check the connection.",
20679
+ \u8BF7\u6C42\u5DF2\u53D7\u7406: "Request accepted",
20680
+ "\u8BF7\u6C42\u5DF2\u7ED3\u675F\uFF0C\u4F46\u672A\u6536\u5230\u6709\u6548\u72B6\u6001\uFF1B\u8BF7\u67E5\u770B\u8BCA\u65AD\u3002": "The request ended without a valid status. Check diagnostics.",
20681
+ "\u8BF7\u6C42\u6B63\u5728\u5904\u7406\u4E2D\uFF0C\u8BF7\u67E5\u770B\u5DF2\u6709\u72B6\u6001\u63D0\u793A\u3002": "The request is already running. Check the existing status window.",
20682
+ "\u8FBE\u82AC\u5947\u5C1A\u672A\u8FDE\u63A5\uFF0C\u8BF7\u68C0\u67E5\u8FDE\u63A5\u72B6\u6001\u3002": "DaVinci Resolve is not connected. Check the connection.",
20683
+ "\u8FBE\u82AC\u5947\u5DF2\u8FDE\u63A5\uFF0C\u6682\u65E0\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u3002": "DaVinci Resolve is connected. No task is running.",
20684
+ "\u8FBE\u82AC\u5947\u5DF2\u8FDE\u63A5\uFF0C\u672A\u627E\u5230\u6B64\u7247\u6BB5\u7684\u5173\u8054\u3002": "DaVinci Resolve is connected, but this clip has no association.",
20685
+ "\u8FBE\u82AC\u5947\u672A\u63D0\u4F9B\u6B64\u6548\u679C\u7684\u6E90\u89C6\u9891\u8DEF\u5F84\u3002\u8BF7\u4ECE\u5DE5\u4F5C\u533A\u83DC\u5355\u7BA1\u7406\u7247\u6BB5\u3002": "DaVinci Resolve did not provide the source video path for this effect. Manage the clip through the Workspace menu.",
20686
+ "\u8FBE\u82AC\u5947\u6865\u63A5\u7EC4\u4EF6\u5C1A\u672A\u5B89\u88C5\u3002": "The MotionHarness Bridge Component is not installed.",
20687
+ \u8FD9\u4E2A\u7247\u6BB5\u7684\u72EC\u7ACB\u526F\u672C\u5DF2\u521B\u5EFA: "An independent copy has been created for this clip",
20688
+ "\u8FD9\u4E2A\u7248\u672C\u7684\u89C6\u9891\u6587\u4EF6\u5DF2\u4E0D\u53EF\u7528\u3002": "The video file for this version is unavailable.",
20689
+ \u9009\u62E9\u4F4D\u7F6E: "Choose location",
20690
+ \u9009\u62E9\u5DE5\u7A0B: "Choose project",
20691
+ \u9009\u62E9\u79FB\u52A8\u540E\u7684\u6E90\u5DE5\u7A0B: "Choose the relocated source project",
20692
+ "\u91CD\u65B0\u5B9A\u4F4D\u5DE5\u7A0B\u2026": "Relocate project\u2026",
20693
+ "\u91CD\u65B0\u5B9A\u4F4D\u6E90\u5DE5\u7A0B\u2026": "Relocate source project\u2026",
20694
+ "\u9884\u89C8\u672A\u5237\u65B0\u8BF7\u64AD\u653E\uFF1B\u5B9A\u683C\u53EF\u80FD\u4FDD\u7559\u65E7\u753B\u9762\u3002": "Play to refresh the preview. Freeze frames may retain the previous image.",
20695
+ "\u9884\u89C8\u89C6\u9891\u5DF2\u5173\u8054\uFF0C\u6682\u65E0\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u3002": "The preview video is linked. No task is running.",
20696
+ "\u7F3A\u5C11 MotionHarness \u72B6\u6001\u7A97\u53E3\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install \u4FEE\u590D\u7EC4\u4EF6\u3002": "The MotionHarness Bridge Component status window is missing. Run mh bridge davinci install to repair it.",
20697
+ "\u627E\u4E0D\u5230 MotionHarness \u4E3B\u7A0B\u5E8F\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install \u4FEE\u590D\u7EC4\u4EF6\u3002": "The MotionHarness executable was not found. Run mh bridge davinci install to repair the bridge component.",
20698
+ "\u8BF7\u6253\u5F00\u65F6\u95F4\u7EBF\u5E76\u9009\u62E9\u4E00\u4E2A MotionHarness \u7247\u6BB5\u3002": "Open a timeline and select a MotionHarness clip.",
20699
+ "\u8BF7\u53EA\u9009\u62E9\u4E00\u4E2A MotionHarness \u89C6\u9891\u7247\u6BB5\u3002": "Select exactly one MotionHarness video clip.",
20700
+ "\u6240\u9009\u89C6\u9891\u672A\u5173\u8054 MotionHarness \u5DE5\u7A0B\u3002": "The selected video is not linked to a MotionHarness project.",
20701
+ "\u6B63\u5728\u6253\u5F00 MotionHarness \u5DE5\u7A0B\u2026": "Opening MotionHarness project\u2026",
20702
+ "\u6B63\u5728\u8BFB\u53D6\u6240\u9009 MotionHarness \u7247\u6BB5\u2026": "Reading selected MotionHarness clip\u2026",
20703
+ "\u6B63\u5728\u63D0\u4EA4 MotionHarness \u8BF7\u6C42\uFF0C\u72B6\u6001\u7A97\u53E3\u5C06\u663E\u793A\u8FDB\u5EA6\u3002": "Submitting the MotionHarness request. The status window will show progress.",
20704
+ "\u8FBE\u82AC\u5947\u5C1A\u672A\u8FDE\u63A5\u3002\u8BF7\u6253\u5F00\u5DE5\u7A0B\u540E\u91CD\u8BD5\u3002": "DaVinci Resolve is not connected. Open a project and try again.",
20705
+ "\u8FBE\u82AC\u5947\u6B63\u5728\u5BFC\u51FA\uFF0C\u8BF7\u5B8C\u6210\u540E\u91CD\u8BD5\u3002": "DaVinci Resolve is rendering. Try again when it finishes.",
20706
+ "\u6240\u9009\u7247\u6BB5\u6CA1\u6709\u666E\u901A\u89C6\u9891\u7D20\u6750\u3002\u8BF7\u5148\u8F6C\u6362\u65E7\u7248\u751F\u6210\u5668\u3002": "The selected clip has no ordinary video media. Convert the legacy generator first.",
20707
+ "\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u5DE5\u7A0B\u4F4D\u7F6E\uFF0C\u8BF7\u68C0\u67E5\u8FBE\u82AC\u5947\u8FDE\u63A5\u3002": "Unable to verify the current project location. Check the DaVinci Resolve connection.",
20708
+ "\u6240\u9009\u7247\u6BB5\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u70B9\u51FB\u3002": "The selected clip changed. Click again.",
20709
+ "\u5F53\u524D\u5DE5\u7A0B\u4F4D\u7F6E\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u70B9\u51FB\u3002": "The current project location changed. Click again.",
20710
+ "\u6865\u63A5\u5B89\u88C5\u914D\u7F6E\u7F3A\u5931\u6216\u635F\u574F\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install \u4FEE\u590D\u7EC4\u4EF6\u3002": "The bridge configuration is missing or damaged. Run mh bridge davinci install to repair it.",
20711
+ "\u65E0\u6CD5\u8BFB\u53D6\u6240\u9009\u7247\u6BB5\uFF0C\u8BF7\u68C0\u67E5\u8FBE\u82AC\u5947\u811A\u672C\u8FDE\u63A5\u3002": "Unable to read the selected clip. Check the DaVinci Resolve scripting connection.",
20712
+ "\u4E0D\u80FD\u5B8C\u6574\u6838\u5BF9\u8BE5\u7D20\u6750\u7684\u4F7F\u7528\u8303\u56F4\uFF0C\u672A\u51C6\u5907\u4FEE\u6539\u3002": "The uses of this media could not be fully verified. No change was prepared.",
20713
+ "\u4EC5\u4E3A\u8FD9\u4E2A\u7247\u6BB5\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\uFF1F": "Create an independent copy for this clip only?",
20714
+ "\u4EC5\u5F71\u54CD\u9009\u5B9A\u7684\u4E00\u4E2A\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u3002": "Only the selected timeline instance is affected.",
20715
+ "\u4F7F\u7528\u8FD9\u4E2A\u6E90\u5DE5\u7A0B\u4F4D\u7F6E\uFF1F": "Use this source project location?",
20716
+ "\u4FEE\u590D\u6240\u9009\u7D20\u6750\u7684\u5173\u8054\uFF1F": "Repair the selected media association?",
20717
+ "\u51C6\u5907\u64CD\u4F5C\u65F6\u5173\u8054\u7248\u672C\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002": "The association changed while preparing the operation. Reopen clip management.",
20718
+ "\u5355\u5B9E\u4F8B\u72EC\u7ACB\u526F\u672C\u5F53\u524D\u4EC5\u652F\u6301\u5DF2\u9A8C\u8BC1\u7684\u7D20\u6750\u548C\u65F6\u95F4\u7EBF\u5747\u4E3A 30 fps \u7684\u60C5\u51B5\u3002": "Independent instance copies currently require verified 30 fps media and a 30 fps timeline.",
20719
+ "\u5386\u53F2\u89C6\u9891\u4E0E\u5DF2\u8BB0\u5F55\u5185\u5BB9\u4E0D\u540C\u3002": "The historical video differs from the recorded content.",
20720
+ "\u539F\u5173\u8054\u767B\u8BB0\u5DF2\u7ECF\u4E0D\u53EF\u7528\u3002": "The original association record is unavailable.",
20721
+ "\u540C\u4E00\u5A92\u4F53\u8EAB\u4EFD\u5B58\u5728\u591A\u6761\u767B\u8BB0\uFF0C\u672A\u6309\u540D\u79F0\u6216\u5217\u8868\u987A\u5E8F\u731C\u6D4B\u3002": "Multiple records share this media identity. No target was inferred from names or list order.",
20722
+ "\u540C\u4E00\u6E90\u5DE5\u7A0B\u7684\u5176\u4ED6\u4EFB\u52A1\u6B63\u5728\u5904\u7406\uFF1B\u8FD9\u91CC\u4EC5\u67E5\u770B\u72B6\u6001\uFF0C\u8BF7\u4ECE\u539F\u4EFB\u52A1\u5165\u53E3\u7BA1\u7406\u3002": "Another task for this source project is running. This window only shows status. Manage the task through its original entry.",
20723
+ "\u540C\u4E00\u6E90\u5DE5\u7A0B\u7684\u6240\u6709\u5173\u8054\u4F7F\u7528\u65B0\u76EE\u5F55\u3002": "All associations for this source project use the new directory.",
20724
+ "\u5A92\u4F53\u8EAB\u4EFD\u3001\u8DEF\u5F84\u6216\u5185\u5BB9\u4E0D\u7B26\u5408\u539F\u767B\u8BB0\uFF0C\u4E0D\u80FD\u81EA\u52A8\u4FEE\u590D\u3002": "The media identity, path, or content differs from the original record. Automatic repair is unavailable.",
20725
+ "\u5DE5\u7A0B\u5185\u5BB9\u6307\u7EB9\u5DF2\u5339\u914D\u3002\u53EA\u4FEE\u590D\u6E90\u76EE\u5F55\u4F4D\u7F6E\uFF0C\u5F53\u524D\u8FBE\u82AC\u5947\u89C6\u9891\u4FDD\u6301\u539F\u6837\u3002": "The project content fingerprint matches. Only the source directory location will change. The current DaVinci Resolve video stays as it is.",
20726
+ "\u5F53\u524D\u5173\u8054\u65E0\u9700\u4FEE\u590D\uFF0C\u6216\u5DF2\u8BB0\u5F55\u7684\u89C6\u9891\u4E0D\u53EF\u7528\u3002": "The association does not need repair, or its recorded video is unavailable.",
20727
+ "\u5F53\u524D\u7247\u6BB5\u4E0D\u80FD\u6267\u884C\u6B64\u64CD\u4F5C\u3002": "This operation is unavailable for the current clip.",
20728
+ "\u5F53\u524D\u7D20\u6750\u5305\u542B\u65E0\u6CD5\u5B8C\u6574\u4FDD\u7559\u7684\u5904\u7406\u3002": "The current media includes processing that cannot be fully preserved.",
20729
+ "\u6062\u590D\u8FD9\u4E2A\u5DF2\u5E94\u7528\u7248\u672C\uFF1F": "Restore this applied version?",
20730
+ "\u6240\u9009\u5B9E\u4F8B\u4E0D\u518D\u5C5E\u4E8E\u5F53\u524D\u5A92\u4F53\u3002": "The selected instance no longer belongs to this media.",
20731
+ "\u6240\u9009\u5B9E\u4F8B\u7684\u5904\u7406\u4E0D\u80FD\u5B8C\u6574\u4FDD\u7559\uFF0C\u672A\u9000\u56DE\u53EA\u590D\u5236\u6E90\u5DE5\u7A0B\u3002": "The instance processing cannot be fully preserved. No source-only copy was made.",
20732
+ "\u6240\u9009\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u5DF2\u6539\u53D8\u3002": "The selected timeline instance has changed.",
20733
+ "\u6240\u9009\u7247\u6BB5\u4E0D\u662F\u53EF\u76F4\u63A5\u7BA1\u7406\u7684\u666E\u901A\u89C6\u9891\u7D20\u6750\u3002": "The selected clip is not ordinary video media that can be managed directly.",
20734
+ "\u6240\u9009\u7247\u6BB5\u7684\u539F\u751F\u8EAB\u4EFD\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002": "The selected clip identity has changed. Reopen clip management.",
20735
+ "\u6240\u9009\u76EE\u5F55\u7684\u5185\u5BB9\u4E0E\u539F\u5DE5\u7A0B\u6307\u7EB9\u4E0D\u540C\uFF0C\u672A\u6309\u540C\u540D\u76EE\u5F55\u91CD\u65B0\u5173\u8054\u3002": "The selected directory does not match the original project fingerprint. Matching names were not used to relink it.",
20736
+ "\u6253\u5F00\u66F4\u591A\u64CD\u4F5C\u65F6\u5173\u8054\u5DF2\u6539\u53D8\u3002": "The association changed while opening more actions.",
20737
+ "\u6253\u5F00\u66F4\u591A\u64CD\u4F5C\u671F\u95F4\u5DE5\u7A0B\u5DF2\u6539\u53D8\u3002": "The project changed while opening more actions.",
20738
+ "\u6253\u5F00\u7BA1\u7406\u7A97\u53E3\u540E\u5173\u8054\u8EAB\u4EFD\u53D1\u751F\u53D8\u5316\uFF0C\u672A\u6539\u7528\u5176\u4ED6\u76EE\u6807\u3002": "The association identity changed after opening management. No other target was selected.",
20739
+ "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\u3002\u73B0\u6709\u89C6\u9891\u4ECD\u4FDD\u7559\uFF0C\u53EF\u9009\u62E9\u201C\u91CD\u65B0\u5B9A\u4F4D\u6E90\u5DE5\u7A0B\u201D\u3002": "The source project was not found. The existing video is preserved. Choose Relocate source project.",
20740
+ "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u5148\u91CD\u65B0\u5B9A\u4F4D\u3002": "The source project was not found. Relocate it first.",
20741
+ "\u65B0\u4F4D\u7F6E\u5DF2\u7ECF\u5B58\u5728\uFF0C\u672A\u8986\u76D6\u73B0\u6709\u5DE5\u7A0B\u3002": "The new location already exists. The existing project was not overwritten.",
20742
+ "\u65E0\u6CD5\u5B8C\u6574\u6838\u5BF9\u5F53\u524D\u9009\u62E9\uFF0C\u8BF7\u4ECE\u8FBE\u82AC\u5947\u83DC\u5355\u91CD\u65B0\u6253\u5F00\u7BA1\u7406\u3002": "The current selection could not be fully verified. Reopen management from the DaVinci Resolve menu.",
20743
+ \u65F6\u95F4\u7EBF: "Timeline",
20744
+ "\u66F4\u65B0\u6216\u6062\u590D\u7248\u672C\u4F1A\u5F71\u54CD\u6B64\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002": "Updating or restoring a version affects every use of this media in the current DaVinci Resolve project.",
20745
+ "\u6B64\u4EFB\u52A1\u5F71\u54CD\u6240\u9009\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002": "This task affects every use of the selected media in the current DaVinci Resolve project.",
20746
+ "\u6B64\u5173\u8054\u5C1A\u65E0\u53EF\u66F4\u65B0\u7684\u89C6\u9891\u89C4\u683C\u3002": "This association has no video specifications available for an update.",
20747
+ "\u6B64\u7D20\u6750\u5DF2\u6709\u5176\u4ED6\u5173\u8054\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u8986\u76D6\u3002": "This media already has another association identity and cannot be overwritten.",
20748
+ "\u6B64\u7D20\u6750\u643A\u5E26\u4E0D\u540C\u7684\u5173\u8054\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u8986\u76D6\u3002": "This media carries a different association identity and cannot be overwritten.",
20749
+ "\u6B64\u7D20\u6750\u6CA1\u6709\u53EF\u6838\u5BF9\u7684\u672C\u673A\u5173\u8054\u3002": "This media has no verifiable local association.",
20750
+ "\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5DF2\u5E94\u7528\u7248\u672C\uFF0C\u6216\u5386\u53F2\u89C6\u9891\u6587\u4EF6\u4E0D\u53EF\u7528\u3002": "No applied version can be restored, or the historical video file is unavailable.",
20751
+ "\u7247\u6BB5\u5DF2\u5173\u8054 MotionHarness\u3002\u53EF\u4EE5\u7F16\u8F91\u6E90\u5DE5\u7A0B\u6216\u66F4\u65B0\u753B\u9762\u3002": "The clip is linked to MotionHarness. You can edit the source project or update the video.",
20752
+ "\u72EC\u7ACB\u526F\u672C\u9700\u8981\u53EF\u5B8C\u6574\u6821\u9A8C\u7684\u516C\u5F00\u5DE5\u7A0B\u5305\u3002": "An independent copy requires a fully verifiable public project package.",
20753
+ "\u72EC\u7ACB\u526F\u672C\u9700\u8981\u53EF\u7528\u7684\u6E90\u5DE5\u7A0B\u4E0E\u5F53\u524D\u89C6\u9891\u3002": "An independent copy requires the source project and current video to be available.",
20754
+ "\u7BA1\u7406\u6B64\u7D20\u6750\u7684\u5386\u53F2\u7248\u672C\u4E0E\u5DE5\u7A0B\u5173\u8054\u3002": "Manage this media's version history and project association.",
20755
+ "\u7D20\u6750\u4F5C\u7528\u57DF\u5DF2\u6539\u53D8\u3002": "The media scope has changed.",
20756
+ "\u7F3A\u5C11\u539F\u5DE5\u7A0B\u7684\u5185\u5BB9\u6307\u7EB9\uFF0C\u4E0D\u80FD\u6309\u76EE\u5F55\u540D\u91CD\u65B0\u5173\u8054\u3002": "The original project fingerprint is missing. Directory names cannot be used to relink it.",
20757
+ "\u8BF7\u5148\u4FEE\u590D\u6B64\u7D20\u6750\u7684\u5173\u8054\u3002": "Repair this media association first.",
20758
+ "\u8BF7\u5148\u6253\u5F00\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E0E\u65F6\u95F4\u7EBF\u3002": "Open a DaVinci Resolve project and timeline first.",
20759
+ "\u8BF7\u5148\u6838\u5B9E\u5DF2\u6709\u4EFB\u52A1\u7684\u7ED3\u679C\u3002": "Verify the existing task result first.",
20760
+ "\u8BF7\u53EA\u9009\u62E9\u4E00\u4E2A\u666E\u901A\u89C6\u9891\u7247\u6BB5\u3002": "Select exactly one ordinary video clip.",
20761
+ "\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002": "Wait for the current task to finish.",
20762
+ "\u8BF7\u9009\u62E9\u4E00\u4E2A\u666E\u901A\u89C6\u9891\u7247\u6BB5\u3002": "Select an ordinary video clip.",
20763
+ "\u8BF7\u9009\u62E9\u6B64\u5173\u8054\u4EE5\u524D\u786E\u5B9E\u5E94\u7528\u8FC7\u3001\u4E14\u89C4\u683C\u76F8\u540C\u7684\u7248\u672C\u3002": "Select a version previously applied to this association with the same specifications.",
20764
+ "\u8BF7\u9009\u62E9\u6E90\u5DE5\u7A0B\u76EE\u5F55\u3002": "Choose the source project directory.",
20765
+ "\u8BF7\u9009\u62E9\u72EC\u7ACB\u5DE5\u7A0B\u7684\u65B0\u4FDD\u5B58\u4F4D\u7F6E\u3002": "Choose a new location for the independent project.",
20766
+ "\u8BF7\u9009\u62E9\u8981\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u7684\u5177\u4F53\u65F6\u95F4\u7EBF\u7247\u6BB5\u3002": "Select the specific timeline clip for the independent copy.",
20767
+ "\u8BFB\u53D6\u671F\u95F4\u6240\u9009\u7247\u6BB5\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002": "The selected clip changed while reading it. Reopen clip management.",
20768
+ "\u9700\u8981\u5B8C\u6574\u7684\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u6216\u4FA7\u680F\u6E90\u8DEF\u5F84\u3002": "A complete timeline instance or sidebar source path is required.",
20769
+ "\u6B64\u4EFB\u52A1\u6D89\u53CA {0} \u4E2A\u7D20\u6750\uFF1B\u8BF7\u4ECE\u539F\u4EFB\u52A1\u5165\u53E3\u7BA1\u7406\u5B8C\u6574\u8303\u56F4\u3002": "This task includes {0} media items. Manage its full scope through the original task entry.",
20770
+ "{0} \xB7 \u89C6\u9891\u8F68 {1} \xB7 \u8D77\u59CB\u5E27 {2}": "{0} \xB7 Video track {1} \xB7 Start frame {2}",
20771
+ "\u5C06\u5F71\u54CD\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u6B64\u7D20\u6750\u7684 {0} \u5904\u5F15\u7528\u3002": "This affects all {0} uses of this media in the current DaVinci Resolve project.",
20772
+ "{0}\u3002{1}\u6E90\u5DE5\u7A0B\u4FDD\u6301\u5F53\u524D\u5185\u5BB9\u3002": "{0}. {1} The source project keeps its current content.",
20773
+ "\u590D\u5236\u53EF\u7F16\u8F91\u5DE5\u7A0B\uFF0C\u5E76\u53EA\u6539\u53D8\u6240\u9009\u201C{0}\u201D\u7247\u6BB5\u7684\u7D20\u6750\u5173\u8054\u3002\u5176\u4ED6\u5F15\u7528\u7EE7\u7EED\u4F7F\u7528\u539F\u5DE5\u7A0B\u3002": "Copy the editable project and change the media association of the selected \u201C{0}\u201D clip only. Other uses keep the original project.",
20774
+ "\u5DF2\u6309\u539F\u751F\u5A92\u4F53\u8EAB\u4EFD\u548C\u89C6\u9891\u5185\u5BB9\u5339\u914D\u201C{0}\u201D\u3002\u53EA\u8865\u56DE\u5173\u8054\u5143\u6570\u636E\uFF0C\u4E0D\u91CD\u65B0\u751F\u6210\u89C6\u9891\u3002": "Matched \u201C{0}\u201D using the native media identity and video content. Only association metadata will be restored. The video will not be rendered again.",
20775
+ "\u6B64\u7D20\u6750\u6CA1\u6709\u53EF\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u7684\u65F6\u95F4\u7EBF\u7247\u6BB5\u3002": "This media has no timeline clips available for an independent copy.",
20776
+ \u4FEE\u590D\u8FDE\u63A5: "Repair connection",
20777
+ "\u6865\u63A5\u914D\u7F6E\u7F3A\u5931\u6216\u635F\u574F\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install \u4FEE\u590D\u7EC4\u4EF6\u3002": "Bridge configuration is missing or damaged. Run mh bridge davinci install to repair it.",
20778
+ "MotionHarness \u672A\u8FDE\u63A5\uFF0C\u8BF7\u70B9\u51FB\u201C\u4FEE\u590D\u8FDE\u63A5\u201D\u3002": "MotionHarness is disconnected. Click Repair connection.",
20779
+ "MotionHarness \u5165\u53E3\u5C31\u7EEA\uFF1B\u66F4\u65B0\u5F71\u54CD\u5168\u90E8\u5F15\u7528": "MotionHarness is ready; updates affect all references",
20780
+ "\u627E\u4E0D\u5230 MotionHarness \u4E3B\u7A0B\u5E8F\u3002\u8BF7\u5B89\u88C5\u6216\u5347\u7EA7 CLI \u540E\u70B9\u51FB\u201C\u4FEE\u590D\u8FDE\u63A5\u201D\u3002": "MotionHarness could not be found. Install or upgrade the CLI, then click Repair connection.",
20781
+ "\u6B63\u5728\u4FEE\u590D MotionHarness \u8FDE\u63A5\u2026": "Repairing the MotionHarness connection\u2026",
20782
+ "MotionHarness \u8FDE\u63A5\u5DF2\u4FEE\u590D\uFF0C\u53EF\u91CD\u65B0\u70B9\u51FB\u7F16\u8F91\u6216\u66F4\u65B0\u3002": "MotionHarness connection repaired. You can click Edit or Update again.",
20783
+ "\u8FDE\u63A5\u5C1A\u672A\u6062\u590D\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install \u4FEE\u590D\u7EC4\u4EF6\u3002": "The connection is still unavailable. Run mh bridge davinci install to repair the component.",
20784
+ "CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002": "The CLI path must be absolute.",
20785
+ "\u6865\u63A5\u5B89\u88C5\u8BB0\u5F55\u7F3A\u5931\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install\u3002": "The bridge installation record is missing. Run mh bridge davinci install.",
20786
+ "\u6865\u63A5\u914D\u7F6E\u7F3A\u5931\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install\u3002": "The bridge configuration is missing. Run mh bridge davinci install.",
20787
+ "\u6865\u63A5\u914D\u7F6E\u5DF2\u88AB\u4FEE\u6539\uFF0C\u672A\u8986\u76D6\u3002\u8BF7\u68C0\u67E5\u914D\u7F6E\u540E\u91CD\u65B0\u5B89\u88C5\u7EC4\u4EF6\u3002": "The bridge configuration has been modified and was preserved. Check it before reinstalling the component.",
20788
+ "\u6865\u63A5\u5DE5\u5177\u914D\u7F6E\u5DF2\u88AB\u4FEE\u6539\uFF0C\u672A\u8986\u76D6\u3002": "The bridge tool configuration has been modified and was preserved.",
20789
+ \u8FDE\u63A5\u4FEE\u590D\u7ED3\u679C\u89C1\u63D0\u793A\u7A97: "See the status window for the connection repair result"
20790
+ };
20791
+
20792
+ // src/i18n.ts
20793
+ var systemLocale;
20794
+ function bridgeLocale(requested = process.env.MH_UI_LOCALE) {
20795
+ if (typeof requested === "string" && /^en(?:[-_]|$)/i.test(requested)) return "en";
20796
+ if (typeof requested === "string" && /^zh(?:[-_]|$)/i.test(requested)) return "zh-CN";
20797
+ if (systemLocale) return systemLocale;
20798
+ let languages = Intl.DateTimeFormat().resolvedOptions().locale;
20799
+ if (process.platform === "darwin") {
20800
+ try {
20801
+ languages = execFileSync("/usr/bin/defaults", ["read", "-g", "AppleLanguages"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 1e3 });
20802
+ } catch {
20803
+ }
20804
+ }
20805
+ systemLocale = languages.match(/\b(en|zh)(?:[-_]|\b)/i)?.[1]?.toLowerCase() === "en" ? "en" : "zh-CN";
20806
+ return systemLocale;
20807
+ }
20808
+ function bridgeText(source, locale = bridgeLocale()) {
20809
+ return locale === "en" ? en_default2[source] ?? source : source;
20810
+ }
20811
+ function bridgeMessage(source, values, locale = bridgeLocale()) {
20812
+ return bridgeText(source, locale).replace(/\{(\d+)\}/g, (token, index) => values[Number(index)] === void 0 ? token : String(values[Number(index)]));
20813
+ }
20814
+ var bridgeName = (locale = bridgeLocale()) => bridgeText("MotionHarness \u6865\u63A5\u7EC4\u4EF6", locale);
20815
+ var bridgeEnglishCatalog = en_default2;
20816
+
20545
20817
  // src/core/entry-context.ts
20546
20818
  import { randomUUID as randomUUID6 } from "node:crypto";
20547
- import { stat as stat6 } from "node:fs/promises";
20548
- import { isAbsolute as isAbsolute7, resolve as resolve7 } from "node:path";
20819
+ import { stat as stat5 } from "node:fs/promises";
20820
+ import { isAbsolute as isAbsolute7, resolve as resolve8 } from "node:path";
20549
20821
 
20550
20822
  // src/core/ofx-entry.ts
20551
- import { realpath as realpath5, stat as stat5 } from "node:fs/promises";
20552
- import { isAbsolute as isAbsolute6, relative as relative2, sep as sep2 } from "node:path";
20823
+ import { realpath as realpath5 } from "node:fs/promises";
20824
+ import { isAbsolute as isAbsolute6, resolve as resolve7 } from "node:path";
20553
20825
  var ofxSourceSchema = external_exports.strictObject({
20554
20826
  path: external_exports.string().min(1).refine((path) => isAbsolute6(path) && !path.includes("\0"), "\u9700\u8981\u6709\u6548\u7684\u7EDD\u5BF9\u89C6\u9891\u8DEF\u5F84\u3002")
20555
20827
  });
20556
- async function canonicalPath(path, code = "BINDING_CONFLICT") {
20557
- assert2(typeof path === "string" && isAbsolute6(path) && !path.includes("\0"), code, "\u65E0\u6CD5\u6838\u5BF9\u89C6\u9891\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8BF7\u4F7F\u7528\u83DC\u5355\u7BA1\u7406\u7247\u6BB5\u3002");
20558
- const canonical2 = await realpath5(path).catch(() => void 0);
20559
- assert2(canonical2, code, "\u65E0\u6CD5\u6838\u5BF9\u89C6\u9891\u8DEF\u5F84\uFF0C\u672A\u8DF3\u8FC7\u4E0D\u53EF\u8BFB\u53D6\u7684\u5173\u8054\u3002\u8BF7\u4FEE\u590D\u5173\u8054\u540E\u91CD\u8BD5\u3002");
20560
- return canonical2;
20561
- }
20562
- function verifyMetadata(metadata2, binding, artifact, allowMissing = false) {
20563
- assert2(metadata2 && typeof metadata2 === "object" && !Array.isArray(metadata2), "BINDING_CONFLICT", "\u539F\u751F\u7D20\u6750\u7F3A\u5C11\u53EF\u6838\u5BF9\u7684\u5173\u8054\u4FE1\u606F\u3002");
20564
- if (allowMissing && !metadata2["motionharness.bridge"]) return;
20828
+ var canonicalPath = (path) => realpath5(path).catch(() => resolve7(path));
20829
+ function verifyMetadata(metadata2, binding, artifact, allowMissing) {
20830
+ if (allowMissing && !metadata2?.["motionharness.bridge"]) return;
20565
20831
  let link2;
20566
20832
  try {
20567
- const value = JSON.parse(metadata2["motionharness.bridge"] ?? "null");
20833
+ const value = JSON.parse(metadata2?.["motionharness.bridge"] ?? "null");
20568
20834
  if (value && typeof value === "object" && !Array.isArray(value)) link2 = value;
20569
20835
  } catch {
20570
20836
  }
20571
20837
  assert2(
20572
20838
  link2?.schemaVersion === 1 && link2.bindingId === binding.id && link2.sourceId === binding.sourceId && link2.artifactId === artifact.id,
20573
20839
  "BINDING_CONFLICT",
20574
- "\u539F\u751F\u7D20\u6750\u7684\u5173\u8054\u4E0E\u5F53\u524D\u89C6\u9891\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u4ECE\u83DC\u5355\u6838\u5BF9\u5173\u8054\u3002"
20840
+ "\u539F\u7D20\u6750\u7684\u5173\u8054\u7F3A\u5931\u6216\u4E0E\u5F53\u524D\u89C6\u9891\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u4ECE\u83DC\u5355\u6838\u5BF9\u5173\u8054\u3002"
20575
20841
  );
20576
20842
  }
20577
20843
  var OfxEntry = class {
@@ -20582,91 +20848,46 @@ var OfxEntry = class {
20582
20848
  store;
20583
20849
  host;
20584
20850
  async resolve(input, management = false) {
20585
- const request = ofxSourceSchema.parse(input);
20586
- const path = await canonicalPath(request.path);
20851
+ const request = ofxSourceSchema.parse(input), path = await canonicalPath(request.path);
20587
20852
  const catalog = await this.store.read();
20588
- const artifactsRoot = await canonicalPath(this.store.path("artifacts"));
20589
20853
  const candidates = [];
20590
20854
  for (const binding2 of Object.values(catalog.bindings)) {
20591
- if (!binding2.artifactId) continue;
20592
- const artifact2 = catalog.artifacts[binding2.artifactId];
20593
- assert2(
20594
- artifact2 && artifact2.id === binding2.artifactId && artifact2.sourceId === binding2.sourceId,
20595
- "BINDING_CONFLICT",
20596
- "\u6E05\u5355\u4E2D\u5B58\u5728\u65E0\u6CD5\u6838\u5BF9\u7684\u5F53\u524D\u89C6\u9891\u5173\u8054\uFF0C\u672A\u731C\u6D4B\u4FA7\u680F\u76EE\u6807\u3002"
20597
- );
20598
- const currentPath = await canonicalPath(this.store.bindingPath(binding2, artifact2));
20599
- const inside = relative2(artifactsRoot, currentPath);
20855
+ const artifact2 = binding2.artifactId ? catalog.artifacts[binding2.artifactId] : void 0;
20856
+ if (artifact2 && await canonicalPath(this.store.bindingPath(binding2, artifact2)) === path) candidates.push({ binding: binding2, artifact: artifact2 });
20857
+ }
20858
+ if (!candidates.length) {
20600
20859
  assert2(
20601
- inside && !isAbsolute6(inside) && inside !== ".." && !inside.startsWith(`..${sep2}`),
20602
- "BINDING_CONFLICT",
20603
- "\u5F53\u524D\u89C6\u9891\u5B9E\u9645\u4F4D\u7F6E\u4E0D\u5728\u6865\u63A5\u4EA7\u7269\u76EE\u5F55\u5185\uFF0C\u672A\u4F7F\u7528\u6B64\u4FA7\u680F\u5165\u53E3\u3002"
20860
+ !Object.values(catalog.artifacts).some((artifact2) => this.store.artifactPath(artifact2.relativePath) === path),
20861
+ "OFX_SOURCE_STALE",
20862
+ "\u4FA7\u680F\u4ECD\u63D0\u4F9B\u65E7\u7248\u89C6\u9891\u8DEF\u5F84\u3002\u8BF7\u4ECE\u300C\u5DE5\u4F5C\u533A \u2192 \u811A\u672C \u2192 Utility \u2192 MotionHarness \u6865\u63A5\u7EC4\u4EF6\u300D\u4E2D\u7684\u300C\u7F16\u8F91\u5DE5\u7A0B\u300D\u6216\u300C\u66F4\u65B0\u5230\u8FBE\u82AC\u5947\u300D\u7EE7\u7EED\u3002"
20604
20863
  );
20605
- if (currentPath === path) candidates.push({ binding: binding2, artifact: artifact2 });
20606
20864
  }
20607
- if (candidates.length === 0) {
20608
- for (const artifact2 of Object.values(catalog.artifacts)) {
20609
- const historicalPath = await realpath5(this.store.artifactPath(artifact2.relativePath)).catch(() => null);
20610
- assert2(
20611
- historicalPath !== path,
20612
- "OFX_SOURCE_STALE",
20613
- "\u4FA7\u680F\u4ECD\u63D0\u4F9B\u65E7\u7248\u89C6\u9891\u8DEF\u5F84\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u76EE\u6807\u3002\u8BF7\u4ECE\u300C\u5DE5\u4F5C\u533A \u2192 \u811A\u672C \u2192 Utility \u2192 Hotion Harness\u300D\u4E2D\u7684\u300C\u7F16\u8F91\u5DE5\u7A0B\u300D\u6216\u300C\u66F4\u65B0\u5230\u8FBE\u82AC\u5947\u300D\u7EE7\u7EED\u7F16\u8F91\u6216\u66F4\u65B0\u3002"
20614
- );
20615
- }
20616
- }
20617
- assert2(candidates.length === 1, "BINDING_CONFLICT", candidates.length ? "\u591A\u4E2A\u5173\u8054\u4F7F\u7528\u540C\u4E00\u89C6\u9891\uFF0C\u4FA7\u680F\u65E0\u6CD5\u786E\u5B9A\u76EE\u6807\u3002\u8BF7\u4F7F\u7528\u83DC\u5355\u7BA1\u7406\u7247\u6BB5\u3002" : "\u6B64\u89C6\u9891\u6CA1\u6709\u552F\u4E00\u7684\u5F53\u524D\u6865\u63A5\u5173\u8054\u3002\u65E7\u7248\u672C\u89C6\u9891\u4E0D\u80FD\u7528\u4E8E\u5B9A\u4F4D\u65B0\u7684\u5173\u8054\u3002");
20865
+ assert2(candidates.length === 1, "BINDING_CONFLICT", candidates.length ? "\u591A\u4E2A\u5173\u8054\u4F7F\u7528\u540C\u4E00\u89C6\u9891\uFF0C\u4FA7\u680F\u65E0\u6CD5\u786E\u5B9A\u76EE\u6807\u3002\u8BF7\u4F7F\u7528\u83DC\u5355\u7BA1\u7406\u7247\u6BB5\u3002" : "\u6B64\u89C6\u9891\u6CA1\u6709\u552F\u4E00\u7684\u5F53\u524D\u6865\u63A5\u5173\u8054\u3002");
20618
20866
  const { binding, artifact } = candidates[0];
20867
+ assert2(artifact.sourceId === binding.sourceId, "BINDING_CONFLICT", "\u5F53\u524D\u89C6\u9891\u4E0D\u5C5E\u4E8E\u5173\u8054\u7684\u6E90\u5DE5\u7A0B\u3002");
20619
20868
  const source = catalog.sources[binding.sourceId];
20620
- assert2(source && source.id === binding.sourceId, "SOURCE_MISSING", "\u5F53\u524D\u5173\u8054\u7684\u6E90\u5DE5\u7A0B\u767B\u8BB0\u4E0D\u5B58\u5728\u3002");
20621
- const sourcePath = management ? this.store.path(source.locator) : await canonicalPath(this.store.path(source.locator), "SOURCE_MISSING");
20622
- const sourceInfo = await stat5(sourcePath).catch(() => void 0);
20623
- assert2(management || sourceInfo && sourceInfo.isDirectory(), "SOURCE_MISSING", "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\u76EE\u5F55\uFF0C\u8BF7\u4ECE\u4FA7\u680F\u201C\u66F4\u591A\u2026\u201D\u91CD\u65B0\u5B9A\u4F4D\u5DE5\u7A0B\u3002");
20624
- const before = await stat5(path).catch(() => void 0);
20625
- assert2(before && before.isFile() && before.size === artifact.bytes, "ARTIFACT_CHANGED", "\u5F53\u524D\u89C6\u9891\u6587\u4EF6\u7F3A\u5931\u6216\u5927\u5C0F\u4E0E\u5DF2\u767B\u8BB0\u4EA7\u7269\u4E0D\u540C\u3002");
20869
+ assert2(source, "SOURCE_MISSING", "\u5F53\u524D\u5173\u8054\u7684\u6E90\u5DE5\u7A0B\u767B\u8BB0\u4E0D\u5B58\u5728\u3002");
20626
20870
  const scope = { databaseId: binding.resolve.databaseId, projectId: binding.resolve.projectId };
20627
- const params = { scope, mediaPoolItemId: binding.resolve.mediaPoolItemId, path };
20628
- const verifyTarget = async (target) => {
20629
- assert2(target && target.unique === true && digest(target.scope) === digest(scope) && target.mediaPoolItemId === binding.resolve.mediaPoolItemId, "VERSION_CONFLICT", "\u539F\u751F\u89C6\u9891\u8EAB\u4EFD\u4E0D\u552F\u4E00\u6216\u5F53\u524D\u5DE5\u7A0B\u5DF2\u7ECF\u6539\u53D8\u3002");
20630
- assert2(await canonicalPath(target.path) === path, "VERSION_CONFLICT", "\u539F\u751F\u89C6\u9891\u8DEF\u5F84\u5DF2\u7ECF\u6539\u53D8\u3002");
20631
- verifyMetadata(target.metadata, binding, artifact, management);
20632
- };
20633
- await verifyTarget(await this.host.call("ofx_source_target", params));
20634
- const media = await this.host.media(scope, binding.resolve.mediaPoolItemId);
20635
- assert2(
20636
- media && digest(media.scope) === digest(scope) && media.mediaPoolItemId === binding.resolve.mediaPoolItemId && media.usageScanComplete === true && typeof media.fingerprint === "string" && media.fingerprint.length > 0,
20637
- "VERSION_CONFLICT",
20638
- "\u65E0\u6CD5\u5B8C\u6574\u6838\u5BF9\u56FA\u5B9A\u7D20\u6750\u7684\u4F7F\u7528\u8303\u56F4\uFF0C\u672A\u66F4\u65B0\u89C6\u9891\u3002"
20639
- );
20640
- assert2(await canonicalPath(media.path) === path, "VERSION_CONFLICT", "\u8BFB\u53D6\u671F\u95F4\u539F\u751F\u89C6\u9891\u5DF2\u88AB\u91CD\u65B0\u94FE\u63A5\u3002");
20641
- verifyMetadata(media.metadata, binding, artifact, management);
20642
- await verifyTarget(await this.host.call("ofx_source_target", params));
20643
- assert2(await fileDigest(path) === artifact.sha256, "ARTIFACT_CHANGED", "\u5F53\u524D\u89C6\u9891\u5185\u5BB9\u4E0E\u5DF2\u767B\u8BB0\u4EA7\u7269\u4E0D\u540C\u3002");
20644
- const after = await stat5(path).catch(() => void 0);
20645
20871
  assert2(
20646
- after?.isFile() && after.size === before.size && after.dev === before.dev && after.ino === before.ino && after.mtimeMs === before.mtimeMs && after.ctimeMs === before.ctimeMs,
20647
- "ARTIFACT_CHANGED",
20648
- "\u6838\u5BF9\u671F\u95F4\u89C6\u9891\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u4FA7\u680F\u5165\u53E3\u3002"
20872
+ Object.values(catalog.bindings).filter((item) => digest(item.resolve) === digest(binding.resolve)).length === 1,
20873
+ "BINDING_CONFLICT",
20874
+ "\u540C\u4E00\u539F\u7D20\u6750\u5B58\u5728\u591A\u4E2A\u5173\u8054\uFF0C\u672A\u731C\u6D4B\u76EE\u6807\u3002"
20649
20875
  );
20876
+ const target = await this.host.call("ofx_source_target", { scope, mediaPoolItemId: binding.resolve.mediaPoolItemId, path });
20650
20877
  assert2(
20651
- await canonicalPath(request.path) === path && await canonicalPath(this.store.bindingPath(binding, artifact)) === path,
20878
+ target?.unique === true && digest(target.scope) === digest(scope) && target.mediaPoolItemId === binding.resolve.mediaPoolItemId && typeof target.fingerprint === "string" && target.fingerprint.length > 0 && await canonicalPath(target.path) === path,
20652
20879
  "VERSION_CONFLICT",
20653
- "\u6838\u5BF9\u671F\u95F4\u89C6\u9891\u8DEF\u5F84\u53D1\u751F\u53D8\u5316\u3002"
20880
+ "\u539F\u7D20\u6750\u7684\u8EAB\u4EFD\u6216\u89C6\u9891\u8DEF\u5F84\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5165\u53E3\u3002"
20654
20881
  );
20655
- if (!management) {
20656
- const currentSource = await stat5(sourcePath).catch(() => void 0);
20657
- assert2(
20658
- await canonicalPath(this.store.path(source.locator), "SOURCE_MISSING") === sourcePath && currentSource?.isDirectory() && currentSource.dev === sourceInfo.dev && currentSource.ino === sourceInfo.ino,
20659
- "SOURCE_MISSING",
20660
- "\u6838\u5BF9\u671F\u95F4\u6E90\u5DE5\u7A0B\u4F4D\u7F6E\u53D1\u751F\u53D8\u5316\u3002"
20661
- );
20662
- }
20663
- assert2(digest(await this.store.read()) === digest(catalog), "VERSION_CONFLICT", "\u6838\u5BF9\u671F\u95F4\u6865\u63A5\u5173\u8054\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u70B9\u51FB\u4FA7\u680F\u5165\u53E3\u3002");
20882
+ verifyMetadata(target.metadata, binding, artifact, management);
20883
+ assert2(digest((await this.store.read()).bindings[binding.id]) === digest(binding), "VERSION_CONFLICT", "\u6838\u5BF9\u671F\u95F4\u5173\u8054\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u70B9\u51FB\u5165\u53E3\u3002");
20664
20884
  return {
20665
20885
  bindingId: binding.id,
20666
20886
  sourceId: source.id,
20667
20887
  artifactId: artifact.id,
20668
20888
  expectedRevision: binding.revision,
20669
- expectedMediaFingerprint: media.fingerprint
20889
+ expectedMediaFingerprint: target.fingerprint,
20890
+ target
20670
20891
  };
20671
20892
  }
20672
20893
  };
@@ -20683,7 +20904,7 @@ var entrySelectionSchema = external_exports.strictObject({
20683
20904
  artifactId: external_exports.string().min(1).optional()
20684
20905
  });
20685
20906
  var entryInspectSchema = external_exports.union([
20686
- external_exports.strictObject({ selection: entrySelectionSchema }),
20907
+ external_exports.strictObject({ selection: entrySelectionSchema, includeInstances: external_exports.literal(true).optional() }),
20687
20908
  external_exports.strictObject({ currentSelection: external_exports.literal(true) }),
20688
20909
  external_exports.strictObject({ ofxSource: ofxSourceSchema })
20689
20910
  ]);
@@ -20738,7 +20959,7 @@ function activeTaskScope(job, binding, selection) {
20738
20959
  const instance = job.operation === "duplicate" && job.request.bindingId === binding.id && job.request.timelineId === selection.timelineId && job.request.itemId === selection.itemId;
20739
20960
  const canControl = !multiple && Boolean(direct || singleBatch || instance);
20740
20961
  const kind = canControl ? "selected-binding" : multiple ? "multiple-targets" : "other-targets";
20741
- const message = canControl ? instance ? "\u4EC5\u5F71\u54CD\u9009\u5B9A\u7684\u4E00\u4E2A\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u3002" : "\u6B64\u4EFB\u52A1\u5F71\u54CD\u6240\u9009\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002" : multiple ? `\u6B64\u4EFB\u52A1\u6D89\u53CA ${Math.max(bindingIds.length, targets?.length ?? 0)} \u4E2A\u7D20\u6750\uFF1B\u8BF7\u4ECE\u539F\u4EFB\u52A1\u5165\u53E3\u7BA1\u7406\u5B8C\u6574\u8303\u56F4\u3002` : "\u540C\u4E00\u6E90\u5DE5\u7A0B\u7684\u5176\u4ED6\u4EFB\u52A1\u6B63\u5728\u5904\u7406\uFF1B\u8FD9\u91CC\u4EC5\u67E5\u770B\u72B6\u6001\uFF0C\u8BF7\u4ECE\u539F\u4EFB\u52A1\u5165\u53E3\u7BA1\u7406\u3002";
20962
+ const message = canControl ? instance ? bridgeText("\u4EC5\u5F71\u54CD\u9009\u5B9A\u7684\u4E00\u4E2A\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u3002") : bridgeText("\u6B64\u4EFB\u52A1\u5F71\u54CD\u6240\u9009\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002") : multiple ? bridgeMessage("\u6B64\u4EFB\u52A1\u6D89\u53CA {0} \u4E2A\u7D20\u6750\uFF1B\u8BF7\u4ECE\u539F\u4EFB\u52A1\u5165\u53E3\u7BA1\u7406\u5B8C\u6574\u8303\u56F4\u3002", [Math.max(bindingIds.length, targets?.length ?? 0)]) : bridgeText("\u540C\u4E00\u6E90\u5DE5\u7A0B\u7684\u5176\u4ED6\u4EFB\u52A1\u6B63\u5728\u5904\u7406\uFF1B\u8FD9\u91CC\u4EC5\u67E5\u770B\u72B6\u6001\uFF0C\u8BF7\u4ECE\u539F\u4EFB\u52A1\u5165\u53E3\u7BA1\u7406\u3002");
20742
20963
  return { kind, canControl, bindingIds, message };
20743
20964
  }
20744
20965
  function activeTask(catalog, binding, sourcePath) {
@@ -20746,7 +20967,7 @@ function activeTask(catalog, binding, sourcePath) {
20746
20967
  if (terminalPhases.includes(job.phase) && job.phase !== "outcome-unknown") return false;
20747
20968
  const targets = Array.isArray(job.request.targets) ? job.request.targets : [];
20748
20969
  const replacements = job.journal?.legacy?.replacements ?? [];
20749
- return job.request.bindingId === binding.id || job.request.sourceId === binding.sourceId || typeof job.request.bindingId === "string" && catalog.bindings[job.request.bindingId]?.sourceId === binding.sourceId || typeof job.request.projectPath === "string" && resolve7(job.request.projectPath) === sourcePath || targets.some((target) => target.bindingId === binding.id || typeof target.bindingId === "string" && catalog.bindings[target.bindingId]?.sourceId === binding.sourceId) || replacements.some((item) => item.oldBindingId === binding.id || item.sourceId === binding.sourceId);
20970
+ return job.request.bindingId === binding.id || job.request.sourceId === binding.sourceId || typeof job.request.bindingId === "string" && catalog.bindings[job.request.bindingId]?.sourceId === binding.sourceId || typeof job.request.projectPath === "string" && resolve8(job.request.projectPath) === sourcePath || targets.some((target) => target.bindingId === binding.id || typeof target.bindingId === "string" && catalog.bindings[target.bindingId]?.sourceId === binding.sourceId) || replacements.some((item) => item.oldBindingId === binding.id || item.sourceId === binding.sourceId);
20750
20971
  }).sort((a, b) => Number(b.phase === "outcome-unknown") - Number(a.phase === "outcome-unknown") || b.createdAt.localeCompare(a.createdAt))[0];
20751
20972
  }
20752
20973
  var EntryContext = class {
@@ -20759,7 +20980,7 @@ var EntryContext = class {
20759
20980
  host;
20760
20981
  mh;
20761
20982
  async currentSelection(checking = false) {
20762
- const changed = "\u8BFB\u53D6\u671F\u95F4\u6240\u9009\u7247\u6BB5\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002";
20983
+ const changed = bridgeText("\u8BFB\u53D6\u671F\u95F4\u6240\u9009\u7247\u6BB5\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002");
20763
20984
  let raw;
20764
20985
  try {
20765
20986
  raw = await this.host.call("selection", { plainMediaOnly: true });
@@ -20771,23 +20992,23 @@ var EntryContext = class {
20771
20992
  assert2(
20772
20993
  response.success,
20773
20994
  checking ? "VERSION_CONFLICT" : "CAPABILITY_UNAVAILABLE",
20774
- checking ? changed : "\u65E0\u6CD5\u5B8C\u6574\u6838\u5BF9\u5F53\u524D\u9009\u62E9\uFF0C\u8BF7\u4ECE\u8FBE\u82AC\u5947\u83DC\u5355\u91CD\u65B0\u6253\u5F00\u7BA1\u7406\u3002"
20995
+ checking ? changed : bridgeText("\u65E0\u6CD5\u5B8C\u6574\u6838\u5BF9\u5F53\u524D\u9009\u62E9\uFF0C\u8BF7\u4ECE\u8FBE\u82AC\u5947\u83DC\u5355\u91CD\u65B0\u6253\u5F00\u7BA1\u7406\u3002")
20775
20996
  );
20776
20997
  const snapshot = response.data;
20777
20998
  assert2(
20778
20999
  snapshot.scope && snapshot.timelineId,
20779
21000
  checking ? "VERSION_CONFLICT" : "SELECTION_UNAVAILABLE",
20780
- checking ? changed : "\u8BF7\u5148\u6253\u5F00\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E0E\u65F6\u95F4\u7EBF\u3002"
21001
+ checking ? changed : bridgeText("\u8BF7\u5148\u6253\u5F00\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E0E\u65F6\u95F4\u7EBF\u3002")
20781
21002
  );
20782
21003
  assert2(
20783
21004
  snapshot.selectedCount === 1 && snapshot.item,
20784
21005
  checking ? "VERSION_CONFLICT" : "SELECTION_UNAVAILABLE",
20785
- checking ? changed : snapshot.selectedCount === 0 ? "\u8BF7\u9009\u62E9\u4E00\u4E2A\u666E\u901A\u89C6\u9891\u7247\u6BB5\u3002" : "\u8BF7\u53EA\u9009\u62E9\u4E00\u4E2A\u666E\u901A\u89C6\u9891\u7247\u6BB5\u3002"
21006
+ checking ? changed : snapshot.selectedCount === 0 ? bridgeText("\u8BF7\u9009\u62E9\u4E00\u4E2A\u666E\u901A\u89C6\u9891\u7247\u6BB5\u3002") : bridgeText("\u8BF7\u53EA\u9009\u62E9\u4E00\u4E2A\u666E\u901A\u89C6\u9891\u7247\u6BB5\u3002")
20786
21007
  );
20787
21008
  assert2(
20788
21009
  snapshot.item.mediaPoolItemId,
20789
21010
  checking ? "VERSION_CONFLICT" : "UNSUPPORTED_TIMELINE_ITEM",
20790
- checking ? changed : "\u6240\u9009\u7247\u6BB5\u4E0D\u662F\u53EF\u76F4\u63A5\u7BA1\u7406\u7684\u666E\u901A\u89C6\u9891\u7D20\u6750\u3002"
21011
+ checking ? changed : bridgeText("\u6240\u9009\u7247\u6BB5\u4E0D\u662F\u53EF\u76F4\u63A5\u7BA1\u7406\u7684\u666E\u901A\u89C6\u9891\u7D20\u6750\u3002")
20791
21012
  );
20792
21013
  const selection = {
20793
21014
  scope: snapshot.scope,
@@ -20797,17 +21018,17 @@ var EntryContext = class {
20797
21018
  };
20798
21019
  return { snapshot, selection };
20799
21020
  }
20800
- async target(selection) {
20801
- assert2(Boolean(selection.timelineId) === Boolean(selection.itemId) && (selection.timelineId || selection.path), "INVALID_REQUEST", "\u9700\u8981\u5B8C\u6574\u7684\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u6216\u4FA7\u680F\u6E90\u8DEF\u5F84\u3002");
20802
- const native = await this.host.call("entry_target", { selection });
21021
+ async target(selection, resolved) {
21022
+ assert2(Boolean(selection.timelineId) === Boolean(selection.itemId) && (selection.timelineId || selection.path), "INVALID_REQUEST", bridgeText("\u9700\u8981\u5B8C\u6574\u7684\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u6216\u4FA7\u680F\u6E90\u8DEF\u5F84\u3002"));
21023
+ const native = resolved ?? await this.host.call("entry_target", { selection });
20803
21024
  assert2(
20804
21025
  digest(native.scope) === digest(selection.scope) && native.timelineId === selection.timelineId && native.itemId === selection.itemId && native.mediaPoolItemId === selection.mediaPoolItemId && native.metadata && typeof native.metadata === "object" && !Array.isArray(native.metadata),
20805
21026
  "VERSION_CONFLICT",
20806
- "\u6240\u9009\u7247\u6BB5\u7684\u539F\u751F\u8EAB\u4EFD\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002"
21027
+ bridgeText("\u6240\u9009\u7247\u6BB5\u7684\u539F\u751F\u8EAB\u4EFD\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002")
20807
21028
  );
20808
21029
  const catalog = await this.store.read();
20809
21030
  const matches = Object.values(catalog.bindings).filter((binding2) => digest(binding2.resolve) === digest({ ...selection.scope, mediaPoolItemId: selection.mediaPoolItemId }));
20810
- assert2(matches.length <= 1, "BINDING_CONFLICT", "\u540C\u4E00\u5A92\u4F53\u8EAB\u4EFD\u5B58\u5728\u591A\u6761\u767B\u8BB0\uFF0C\u672A\u6309\u540D\u79F0\u6216\u5217\u8868\u987A\u5E8F\u731C\u6D4B\u3002");
21031
+ assert2(matches.length <= 1, "BINDING_CONFLICT", bridgeText("\u540C\u4E00\u5A92\u4F53\u8EAB\u4EFD\u5B58\u5728\u591A\u6761\u767B\u8BB0\uFF0C\u672A\u6309\u540D\u79F0\u6216\u5217\u8868\u987A\u5E8F\u731C\u6D4B\u3002"));
20811
21032
  const binding = matches[0];
20812
21033
  let link2;
20813
21034
  const encoded = native.metadata?.["motionharness.bridge"];
@@ -20820,8 +21041,8 @@ var EntryContext = class {
20820
21041
  }
20821
21042
  const conflict = Boolean(encoded && (!binding || !link2 || link2.schemaVersion !== 1 || link2.bindingId !== binding.id || link2.sourceId !== binding.sourceId || link2.artifactId !== binding.artifactId));
20822
21043
  if (binding) {
20823
- assert2((!selection.bindingId || selection.bindingId === binding.id) && (!selection.sourceId || selection.sourceId === binding.sourceId) && (!selection.artifactId || selection.artifactId === binding.artifactId), "VERSION_CONFLICT", "\u6253\u5F00\u7BA1\u7406\u7A97\u53E3\u540E\u5173\u8054\u8EAB\u4EFD\u53D1\u751F\u53D8\u5316\uFF0C\u672A\u6539\u7528\u5176\u4ED6\u76EE\u6807\u3002");
20824
- } else assert2(!selection.bindingId && !selection.sourceId && !selection.artifactId, "VERSION_CONFLICT", "\u539F\u5173\u8054\u767B\u8BB0\u5DF2\u7ECF\u4E0D\u53EF\u7528\u3002");
21044
+ assert2((!selection.bindingId || selection.bindingId === binding.id) && (!selection.sourceId || selection.sourceId === binding.sourceId) && (!selection.artifactId || selection.artifactId === binding.artifactId), "VERSION_CONFLICT", bridgeText("\u6253\u5F00\u7BA1\u7406\u7A97\u53E3\u540E\u5173\u8054\u8EAB\u4EFD\u53D1\u751F\u53D8\u5316\uFF0C\u672A\u6539\u7528\u5176\u4ED6\u76EE\u6807\u3002"));
21045
+ } else assert2(!selection.bindingId && !selection.sourceId && !selection.artifactId, "VERSION_CONFLICT", bridgeText("\u539F\u5173\u8054\u767B\u8BB0\u5DF2\u7ECF\u4E0D\u53EF\u7528\u3002"));
20825
21046
  const verified = binding ? {
20826
21047
  ...selection,
20827
21048
  bindingId: binding.id,
@@ -20834,10 +21055,12 @@ var EntryContext = class {
20834
21055
  const request = entryInspectSchema.parse(input);
20835
21056
  const captured = "currentSelection" in request ? await this.currentSelection() : void 0;
20836
21057
  let selection;
21058
+ let resolved;
20837
21059
  if ("ofxSource" in request) {
20838
- const resolved = await new OfxEntry(this.store, this.host).resolve(request.ofxSource, true);
20839
- const binding2 = (await this.store.read()).bindings[resolved.bindingId];
20840
- assert2(binding2 && binding2.revision === resolved.expectedRevision, "VERSION_CONFLICT", "\u6253\u5F00\u66F4\u591A\u64CD\u4F5C\u65F6\u5173\u8054\u5DF2\u6539\u53D8\u3002");
21060
+ const entry = await new OfxEntry(this.store, this.host).resolve(request.ofxSource, true);
21061
+ const binding2 = (await this.store.read()).bindings[entry.bindingId];
21062
+ assert2(binding2 && binding2.revision === entry.expectedRevision, "VERSION_CONFLICT", bridgeText("\u6253\u5F00\u66F4\u591A\u64CD\u4F5C\u65F6\u5173\u8054\u5DF2\u6539\u53D8\u3002"));
21063
+ resolved = { ...entry.target, name: String(entry.target.clipProperties?.["Clip Name"] ?? "") };
20841
21064
  selection = {
20842
21065
  scope: { databaseId: binding2.resolve.databaseId, projectId: binding2.resolve.projectId },
20843
21066
  mediaPoolItemId: binding2.resolve.mediaPoolItemId,
@@ -20847,59 +21070,61 @@ var EntryContext = class {
20847
21070
  path: request.ofxSource.path
20848
21071
  };
20849
21072
  } else selection = "selection" in request ? request.selection : captured.selection;
20850
- const target = await this.target(selection), { binding, catalog, conflict, missingAssociation } = target;
21073
+ const target = await this.target(selection, resolved), { binding, catalog, conflict, missingAssociation } = target;
20851
21074
  const source = binding ? catalog.sources[binding.sourceId] : void 0;
20852
21075
  const artifact = binding?.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
20853
- const sourcePresent = source ? await stat6(this.store.path(source.locator)).then((info) => info.isDirectory(), () => false) : false;
20854
- const currentAvailable = artifact ? await stat6(this.store.artifactPath(artifact.relativePath)).then((info) => info.isFile() && info.size === artifact.bytes, () => false) : false;
21076
+ const sourcePresent = source ? await stat5(this.store.path(source.locator)).then((info) => info.isDirectory(), () => false) : false;
21077
+ const currentAvailable = artifact ? await stat5(this.store.artifactPath(artifact.relativePath)).then((info) => info.isFile() && info.size === artifact.bytes, () => false) : false;
20855
21078
  const history = [];
20856
21079
  if (binding && artifact) {
20857
21080
  for (const version2 of appliedHistory(catalog, binding)) {
20858
21081
  const previous2 = catalog.artifacts[version2.artifactId];
20859
21082
  if (previous2.id === artifact.id || !sameOutputSpec(previous2.spec, artifact.spec)) continue;
20860
- const available = await stat6(this.store.artifactPath(previous2.relativePath)).then((info) => info.isFile() && info.size === previous2.bytes, () => false);
21083
+ const available = await stat5(this.store.artifactPath(previous2.relativePath)).then((info) => info.isFile() && info.size === previous2.bytes, () => false);
20861
21084
  const spec = previous2.spec;
20862
21085
  const codec2 = spec.codec === "prores-4444-xq" ? "ProRes 4444 XQ" : spec.format === "mov" ? "ProRes 4444" : "MP4";
20863
- const at = new Date(version2.appliedAt).toLocaleString("zh-CN", { hour12: false });
21086
+ const at = new Date(version2.appliedAt).toLocaleString(bridgeLocale(), { hour12: false });
20864
21087
  history.push({ ...version2, label: `${at} \xB7 ${codec2} \xB7 ${spec.width}\xD7${spec.height}`, current: false, available });
20865
21088
  }
20866
21089
  }
20867
21090
  const instances = [];
20868
- if (selection.path && !conflict) {
20869
- const media = await this.host.media(selection.scope, selection.mediaPoolItemId);
21091
+ const instancesLoaded = "includeInstances" in request && request.includeInstances === true;
21092
+ if (instancesLoaded && !conflict && !missingAssociation) {
21093
+ const media = await this.host.mediaUsages(selection.scope, selection.mediaPoolItemId);
20870
21094
  const discovery = await this.host.call("discover", {});
20871
- assert2(digest(discovery.scope) === digest(selection.scope), "VERSION_CONFLICT", "\u6253\u5F00\u66F4\u591A\u64CD\u4F5C\u671F\u95F4\u5DE5\u7A0B\u5DF2\u6539\u53D8\u3002");
21095
+ assert2(digest(discovery.scope) === digest(selection.scope), "VERSION_CONFLICT", bridgeText("\u6253\u5F00\u66F4\u591A\u64CD\u4F5C\u671F\u95F4\u5DE5\u7A0B\u5DF2\u6539\u53D8\u3002"));
20872
21096
  if (media.usageScanComplete) for (const use of media.uses) instances.push({
20873
21097
  timelineId: use.timelineId,
20874
21098
  itemId: use.id,
20875
- label: `${discovery.timelines.find((timeline) => timeline.id === use.timelineId)?.name ?? "\u65F6\u95F4\u7EBF"} \xB7 \u89C6\u9891\u8F68 ${use.track} \xB7 \u8D77\u59CB\u5E27 ${use.startFrame}`,
21099
+ label: bridgeMessage("{0} \xB7 \u89C6\u9891\u8F68 {1} \xB7 \u8D77\u59CB\u5E27 {2}", [discovery.timelines.find((timeline) => timeline.id === use.timelineId)?.name ?? bridgeText("\u65F6\u95F4\u7EBF"), use.track, use.startFrame]),
20876
21100
  mediaPoolItemId: use.mediaPoolItemId
20877
21101
  });
20878
21102
  }
20879
21103
  const task = binding ? activeTask(catalog, binding, source ? this.store.path(source.locator) : void 0) : void 0;
20880
21104
  const taskScope = task && binding ? activeTaskScope(task, binding, target.selection) : null;
20881
21105
  const ready = Boolean(binding && source && !conflict && !missingAssociation), busy = Boolean(task);
20882
- const blocked = conflict ? "\u6B64\u7D20\u6750\u643A\u5E26\u4E0D\u540C\u7684\u5173\u8054\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u8986\u76D6\u3002" : missingAssociation ? "\u8BF7\u5148\u4FEE\u590D\u6B64\u7D20\u6750\u7684\u5173\u8054\u3002" : !binding || !source ? "\u6B64\u7D20\u6750\u6CA1\u6709\u53EF\u6838\u5BF9\u7684\u672C\u673A\u5173\u8054\u3002" : task?.phase === "outcome-unknown" ? "\u8BF7\u5148\u6838\u5B9E\u5DF2\u6709\u4EFB\u52A1\u7684\u7ED3\u679C\u3002" : busy ? "\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002" : "";
21106
+ const blocked = conflict ? bridgeText("\u6B64\u7D20\u6750\u643A\u5E26\u4E0D\u540C\u7684\u5173\u8054\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u8986\u76D6\u3002") : missingAssociation ? bridgeText("\u8BF7\u5148\u4FEE\u590D\u6B64\u7D20\u6750\u7684\u5173\u8054\u3002") : !binding || !source ? bridgeText("\u6B64\u7D20\u6750\u6CA1\u6709\u53EF\u6838\u5BF9\u7684\u672C\u673A\u5173\u8054\u3002") : task?.phase === "outcome-unknown" ? bridgeText("\u8BF7\u5148\u6838\u5B9E\u5DF2\u6709\u4EFB\u52A1\u7684\u7ED3\u679C\u3002") : busy ? bridgeText("\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002") : "";
20883
21107
  const status = conflict ? "association-conflict" : !binding || !source ? "unlinked" : task?.phase === "outcome-unknown" ? "outcome-unknown" : busy ? "busy" : missingAssociation ? "association-missing" : !sourcePresent ? "source-missing" : "linked";
20884
- const message = blocked || (!sourcePresent ? "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\u3002\u73B0\u6709\u89C6\u9891\u4ECD\u4FDD\u7559\uFF0C\u53EF\u9009\u62E9\u201C\u91CD\u65B0\u5B9A\u4F4D\u6E90\u5DE5\u7A0B\u201D\u3002" : selection.path ? "\u7BA1\u7406\u6B64\u7D20\u6750\u7684\u5386\u53F2\u7248\u672C\u4E0E\u5DE5\u7A0B\u5173\u8054\u3002" : "\u7247\u6BB5\u5DF2\u5173\u8054 Hotion Harness\u3002\u53EF\u4EE5\u7F16\u8F91\u6E90\u5DE5\u7A0B\u6216\u66F4\u65B0\u753B\u9762\u3002");
21108
+ const message = blocked || (!sourcePresent ? bridgeText("\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\u3002\u73B0\u6709\u89C6\u9891\u4ECD\u4FDD\u7559\uFF0C\u53EF\u9009\u62E9\u201C\u91CD\u65B0\u5B9A\u4F4D\u6E90\u5DE5\u7A0B\u201D\u3002") : selection.path ? bridgeText("\u7BA1\u7406\u6B64\u7D20\u6750\u7684\u5386\u53F2\u7248\u672C\u4E0E\u5DE5\u7A0B\u5173\u8054\u3002") : bridgeText("\u7247\u6BB5\u5DF2\u5173\u8054 MotionHarness\u3002\u53EF\u4EE5\u7F16\u8F91\u6E90\u5DE5\u7A0B\u6216\u66F4\u65B0\u753B\u9762\u3002"));
20885
21109
  const location = [target.native.projectName, target.native.timelineName].filter((value) => typeof value === "string" && value.trim().length > 0).join(" / ");
20886
- const scopeMessage = taskScope?.message ?? "\u66F4\u65B0\u6216\u6062\u590D\u7248\u672C\u4F1A\u5F71\u54CD\u6B64\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002";
21110
+ const scopeMessage = taskScope?.message ?? bridgeText("\u66F4\u65B0\u6216\u6062\u590D\u7248\u672C\u4F1A\u5F71\u54CD\u6B64\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002");
20887
21111
  const context = {
20888
21112
  selection: target.selection,
20889
- title: source?.name ?? target.native.name ?? "Hotion Harness",
21113
+ title: source?.name ?? target.native.name ?? "MotionHarness",
20890
21114
  status,
20891
21115
  message,
20892
21116
  sourceDirectory: source && !conflict ? this.store.path(source.locator) : void 0,
20893
21117
  scopeLabel: location ? `${location} \xB7 ${scopeMessage}` : scopeMessage,
20894
21118
  history,
20895
21119
  instances,
21120
+ instancesLoaded,
20896
21121
  actions: {
20897
- edit: action(ready && sourcePresent, blocked || "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u5148\u91CD\u65B0\u5B9A\u4F4D\u3002"),
20898
- update: action(ready && sourcePresent && Boolean(artifact) && !busy, blocked || (!sourcePresent ? "\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u5148\u91CD\u65B0\u5B9A\u4F4D\u3002" : "\u6B64\u5173\u8054\u5C1A\u65E0\u53EF\u66F4\u65B0\u7684\u89C6\u9891\u89C4\u683C\u3002")),
20899
- restore: action(ready && history.some((item) => item.available) && !busy, blocked || "\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5DF2\u5E94\u7528\u7248\u672C\uFF0C\u6216\u5386\u53F2\u89C6\u9891\u6587\u4EF6\u4E0D\u53EF\u7528\u3002"),
20900
- duplicate: action(ready && sourcePresent && currentAvailable && !busy && Boolean(selection.itemId || instances.length), blocked || "\u72EC\u7ACB\u526F\u672C\u9700\u8981\u53EF\u7528\u7684\u6E90\u5DE5\u7A0B\u4E0E\u5F53\u524D\u89C6\u9891\u3002"),
20901
- relink: action(Boolean(binding && source?.observation?.contentVersion && !conflict && !busy), blocked || "\u7F3A\u5C11\u539F\u5DE5\u7A0B\u7684\u5185\u5BB9\u6307\u7EB9\uFF0C\u4E0D\u80FD\u6309\u76EE\u5F55\u540D\u91CD\u65B0\u5173\u8054\u3002"),
20902
- repairAssociation: action(Boolean(binding && missingAssociation && artifact && currentAvailable && !conflict && !busy), blocked || "\u5F53\u524D\u5173\u8054\u65E0\u9700\u4FEE\u590D\uFF0C\u6216\u5DF2\u8BB0\u5F55\u7684\u89C6\u9891\u4E0D\u53EF\u7528\u3002")
21122
+ edit: action(ready && sourcePresent, blocked || bridgeText("\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u5148\u91CD\u65B0\u5B9A\u4F4D\u3002")),
21123
+ update: action(ready && sourcePresent && Boolean(artifact) && !busy, blocked || (!sourcePresent ? bridgeText("\u627E\u4E0D\u5230\u6E90\u5DE5\u7A0B\uFF0C\u8BF7\u5148\u91CD\u65B0\u5B9A\u4F4D\u3002") : bridgeText("\u6B64\u5173\u8054\u5C1A\u65E0\u53EF\u66F4\u65B0\u7684\u89C6\u9891\u89C4\u683C\u3002"))),
21124
+ restore: action(ready && history.some((item) => item.available) && !busy, blocked || bridgeText("\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5DF2\u5E94\u7528\u7248\u672C\uFF0C\u6216\u5386\u53F2\u89C6\u9891\u6587\u4EF6\u4E0D\u53EF\u7528\u3002")),
21125
+ duplicate: action(ready && sourcePresent && currentAvailable && !busy && Boolean(selection.itemId || selection.path && (!instancesLoaded || instances.length)), blocked || bridgeText("\u72EC\u7ACB\u526F\u672C\u9700\u8981\u53EF\u7528\u7684\u6E90\u5DE5\u7A0B\u4E0E\u5F53\u524D\u89C6\u9891\u3002")),
21126
+ relink: action(Boolean(binding && source?.observation?.contentVersion && !conflict && !busy), blocked || bridgeText("\u7F3A\u5C11\u539F\u5DE5\u7A0B\u7684\u5185\u5BB9\u6307\u7EB9\uFF0C\u4E0D\u80FD\u6309\u76EE\u5F55\u540D\u91CD\u65B0\u5173\u8054\u3002")),
21127
+ repairAssociation: action(Boolean(binding && missingAssociation && artifact && currentAvailable && !conflict && !busy), blocked || bridgeText("\u5F53\u524D\u5173\u8054\u65E0\u9700\u4FEE\u590D\uFF0C\u6216\u5DF2\u8BB0\u5F55\u7684\u89C6\u9891\u4E0D\u53EF\u7528\u3002"))
20903
21128
  },
20904
21129
  activeTask: task ? { ...task, taskId: task.id } : null,
20905
21130
  activeTaskScope: taskScope
@@ -20909,7 +21134,7 @@ var EntryContext = class {
20909
21134
  assert2(
20910
21135
  current.snapshot.fingerprint === captured.snapshot.fingerprint && digest(current.selection) === digest(captured.selection) && digest(current.snapshot) === digest(captured.snapshot),
20911
21136
  "VERSION_CONFLICT",
20912
- "\u8BFB\u53D6\u671F\u95F4\u6240\u9009\u7247\u6BB5\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002"
21137
+ bridgeText("\u8BFB\u53D6\u671F\u95F4\u6240\u9009\u7247\u6BB5\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002")
20913
21138
  );
20914
21139
  }
20915
21140
  return context;
@@ -20917,23 +21142,23 @@ var EntryContext = class {
20917
21142
  async prepare(input) {
20918
21143
  const request = entryPrepareSchema.parse(input), context = await this.inspect({ selection: request.selection });
20919
21144
  const key = request.operation === "repair-association" ? "repairAssociation" : request.operation;
20920
- assert2(context.actions[key].enabled, "ENTRY_ACTION_UNAVAILABLE", context.actions[key].reason ?? "\u5F53\u524D\u7247\u6BB5\u4E0D\u80FD\u6267\u884C\u6B64\u64CD\u4F5C\u3002");
21145
+ assert2(context.actions[key].enabled, "ENTRY_ACTION_UNAVAILABLE", context.actions[key].reason ?? bridgeText("\u5F53\u524D\u7247\u6BB5\u4E0D\u80FD\u6267\u884C\u6B64\u64CD\u4F5C\u3002"));
20921
21146
  const catalog = await this.store.read(), binding = catalog.bindings[context.selection.bindingId];
20922
21147
  const source = binding ? catalog.sources[binding.sourceId] : void 0;
20923
21148
  const selection = context.selection, idempotencyKey = randomUUID6();
20924
21149
  assert2(
20925
21150
  binding && source && binding.sourceId === selection.sourceId && binding.artifactId === selection.artifactId && digest(binding.resolve) === digest({ ...selection.scope, mediaPoolItemId: selection.mediaPoolItemId }),
20926
21151
  "VERSION_CONFLICT",
20927
- "\u51C6\u5907\u64CD\u4F5C\u65F6\u5173\u8054\u7248\u672C\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002"
21152
+ bridgeText("\u51C6\u5907\u64CD\u4F5C\u65F6\u5173\u8054\u7248\u672C\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u7247\u6BB5\u7BA1\u7406\u3002")
20928
21153
  );
20929
21154
  if (request.operation === "relink") {
20930
- assert2(request.projectPath && isAbsolute7(request.projectPath) && source.observation?.contentVersion, "INVALID_REQUEST", "\u8BF7\u9009\u62E9\u6E90\u5DE5\u7A0B\u76EE\u5F55\u3002");
20931
- const projectPath = await this.mh.projectPath(resolve7(request.projectPath)), observation = await this.mh.inspect(projectPath);
20932
- assert2(observation.contentVersion === source.observation.contentVersion, "VERSION_CONFLICT", "\u6240\u9009\u76EE\u5F55\u7684\u5185\u5BB9\u4E0E\u539F\u5DE5\u7A0B\u6307\u7EB9\u4E0D\u540C\uFF0C\u672A\u6309\u540C\u540D\u76EE\u5F55\u91CD\u65B0\u5173\u8054\u3002");
21155
+ assert2(request.projectPath && isAbsolute7(request.projectPath) && source.observation?.contentVersion, "INVALID_REQUEST", bridgeText("\u8BF7\u9009\u62E9\u6E90\u5DE5\u7A0B\u76EE\u5F55\u3002"));
21156
+ const projectPath = await this.mh.projectPath(resolve8(request.projectPath)), observation = await this.mh.inspect(projectPath);
21157
+ assert2(observation.contentVersion === source.observation.contentVersion, "VERSION_CONFLICT", bridgeText("\u6240\u9009\u76EE\u5F55\u7684\u5185\u5BB9\u4E0E\u539F\u5DE5\u7A0B\u6307\u7EB9\u4E0D\u540C\uFF0C\u672A\u6309\u540C\u540D\u76EE\u5F55\u91CD\u65B0\u5173\u8054\u3002"));
20933
21158
  return {
20934
- title: "\u4F7F\u7528\u8FD9\u4E2A\u6E90\u5DE5\u7A0B\u4F4D\u7F6E\uFF1F",
20935
- message: "\u5DE5\u7A0B\u5185\u5BB9\u6307\u7EB9\u5DF2\u5339\u914D\u3002\u53EA\u4FEE\u590D\u6E90\u76EE\u5F55\u4F4D\u7F6E\uFF0C\u5F53\u524D\u8FBE\u82AC\u5947\u89C6\u9891\u4FDD\u6301\u539F\u6837\u3002",
20936
- scopeLabel: "\u540C\u4E00\u6E90\u5DE5\u7A0B\u7684\u6240\u6709\u5173\u8054\u4F7F\u7528\u65B0\u76EE\u5F55\u3002",
21159
+ title: bridgeText("\u4F7F\u7528\u8FD9\u4E2A\u6E90\u5DE5\u7A0B\u4F4D\u7F6E\uFF1F"),
21160
+ message: bridgeText("\u5DE5\u7A0B\u5185\u5BB9\u6307\u7EB9\u5DF2\u5339\u914D\u3002\u53EA\u4FEE\u590D\u6E90\u76EE\u5F55\u4F4D\u7F6E\uFF0C\u5F53\u524D\u8FBE\u82AC\u5947\u89C6\u9891\u4FDD\u6301\u539F\u6837\u3002"),
21161
+ scopeLabel: bridgeText("\u540C\u4E00\u6E90\u5DE5\u7A0B\u7684\u6240\u6709\u5173\u8054\u4F7F\u7528\u65B0\u76EE\u5F55\u3002"),
20937
21162
  command: "relink",
20938
21163
  request: {
20939
21164
  sourceId: source.id,
@@ -20945,33 +21170,31 @@ var EntryContext = class {
20945
21170
  }
20946
21171
  };
20947
21172
  }
20948
- const media = await this.host.media(selection.scope, selection.mediaPoolItemId);
21173
+ if (request.operation === "duplicate") assert2(selection.timelineId && selection.itemId, "INVALID_REQUEST", bridgeText("\u8BF7\u9009\u62E9\u8981\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u7684\u5177\u4F53\u65F6\u95F4\u7EBF\u7247\u6BB5\u3002"));
21174
+ const media = request.operation === "duplicate" ? await this.host.mediaUsages(selection.scope, selection.mediaPoolItemId) : await this.host.media(selection.scope, selection.mediaPoolItemId);
20949
21175
  assert2(
20950
21176
  digest(media.scope) === digest(selection.scope) && media.mediaPoolItemId === selection.mediaPoolItemId,
20951
21177
  "VERSION_CONFLICT",
20952
- "\u7D20\u6750\u4F5C\u7528\u57DF\u5DF2\u6539\u53D8\u3002"
21178
+ bridgeText("\u7D20\u6750\u4F5C\u7528\u57DF\u5DF2\u6539\u53D8\u3002")
20953
21179
  );
20954
- assert2(media.usageScanComplete, "UNSUPPORTED_TIMELINE_ITEM", "\u4E0D\u80FD\u5B8C\u6574\u6838\u5BF9\u8BE5\u7D20\u6750\u7684\u4F7F\u7528\u8303\u56F4\uFF0C\u672A\u51C6\u5907\u4FEE\u6539\u3002");
20955
21180
  const target = selection.itemId ? media.uses.filter((item) => item.timelineId === selection.timelineId && item.id === selection.itemId) : [];
20956
- if (selection.itemId) assert2(target.length === 1 && target[0].mediaPoolItemId === selection.mediaPoolItemId, "VERSION_CONFLICT", "\u6240\u9009\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u5DF2\u6539\u53D8\u3002");
20957
- const scopeLabel = `\u5C06\u5F71\u54CD\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u6B64\u7D20\u6750\u7684 ${media.uses.length} \u5904\u5F15\u7528\u3002`;
20958
- const timeline = selection.timelineId ? await this.host.timeline(selection.scope, selection.timelineId) : void 0;
20959
- if (timeline) assert2(timeline.items.some((item) => item.id === selection.itemId && item.mediaPoolItemId === selection.mediaPoolItemId), "VERSION_CONFLICT", "\u6240\u9009\u5B9E\u4F8B\u4E0D\u518D\u5C5E\u4E8E\u5F53\u524D\u5A92\u4F53\u3002");
21181
+ const scopeLabel = bridgeText("\u66F4\u65B0\u6216\u6062\u590D\u7248\u672C\u4F1A\u5F71\u54CD\u6B64\u7D20\u6750\u5728\u5F53\u524D\u8FBE\u82AC\u5947\u5DE5\u7A0B\u4E2D\u7684\u5168\u90E8\u5F15\u7528\u3002");
21182
+ const timeline = request.operation === "duplicate" && selection.timelineId ? await this.host.timeline(selection.scope, selection.timelineId) : void 0;
21183
+ if (timeline) assert2(timeline.items.some((item) => item.id === selection.itemId && item.mediaPoolItemId === selection.mediaPoolItemId), "VERSION_CONFLICT", bridgeText("\u6240\u9009\u5B9E\u4F8B\u4E0D\u518D\u5C5E\u4E8E\u5F53\u524D\u5A92\u4F53\u3002"));
20960
21184
  const guard = { expectedMediaFingerprint: media.fingerprint, ...timeline ? { expectedTimelineFingerprint: timeline.fingerprint } : {} };
20961
21185
  const fixedSelection = { ...selection, ...guard };
20962
21186
  if (request.operation === "restore") {
20963
21187
  assert2(
20964
21188
  request.artifactId && context.history.some((version3) => version3.artifactId === request.artifactId && version3.available),
20965
21189
  "INVALID_REQUEST",
20966
- "\u8BF7\u9009\u62E9\u6B64\u5173\u8054\u4EE5\u524D\u786E\u5B9E\u5E94\u7528\u8FC7\u3001\u4E14\u89C4\u683C\u76F8\u540C\u7684\u7248\u672C\u3002"
21190
+ bridgeText("\u8BF7\u9009\u62E9\u6B64\u5173\u8054\u4EE5\u524D\u786E\u5B9E\u5E94\u7528\u8FC7\u3001\u4E14\u89C4\u683C\u76F8\u540C\u7684\u7248\u672C\u3002")
20967
21191
  );
20968
- assert2(media.uses.every((item) => !item.unsupported.length), "UNSUPPORTED_TIMELINE_ITEM", "\u5F53\u524D\u7D20\u6750\u5305\u542B\u65E0\u6CD5\u5B8C\u6574\u4FDD\u7559\u7684\u5904\u7406\u3002");
20969
21192
  const artifact2 = catalog.artifacts[request.artifactId];
20970
- assert2(await fileDigest(this.store.artifactPath(artifact2.relativePath)) === artifact2.sha256, "ARTIFACT_CHANGED", "\u5386\u53F2\u89C6\u9891\u4E0E\u5DF2\u8BB0\u5F55\u5185\u5BB9\u4E0D\u540C\u3002");
21193
+ assert2(await fileDigest(this.store.artifactPath(artifact2.relativePath)) === artifact2.sha256, "ARTIFACT_CHANGED", bridgeText("\u5386\u53F2\u89C6\u9891\u4E0E\u5DF2\u8BB0\u5F55\u5185\u5BB9\u4E0D\u540C\u3002"));
20971
21194
  const version2 = context.history.find((value) => value.artifactId === artifact2.id);
20972
21195
  return {
20973
- title: "\u6062\u590D\u8FD9\u4E2A\u5DF2\u5E94\u7528\u7248\u672C\uFF1F",
20974
- message: `${version2.label}\u3002${scopeLabel}\u6E90\u5DE5\u7A0B\u4FDD\u6301\u5F53\u524D\u5185\u5BB9\u3002`,
21196
+ title: bridgeText("\u6062\u590D\u8FD9\u4E2A\u5DF2\u5E94\u7528\u7248\u672C\uFF1F"),
21197
+ message: bridgeMessage("{0}\u3002{1}\u6E90\u5DE5\u7A0B\u4FDD\u6301\u5F53\u524D\u5185\u5BB9\u3002", [version2.label, scopeLabel]),
20975
21198
  scopeLabel,
20976
21199
  command: "restore",
20977
21200
  request: {
@@ -20985,31 +21208,36 @@ var EntryContext = class {
20985
21208
  };
20986
21209
  }
20987
21210
  if (request.operation === "duplicate") {
20988
- assert2(timeline && selection.timelineId && selection.itemId, "INVALID_REQUEST", "\u8BF7\u9009\u62E9\u8981\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u7684\u5177\u4F53\u65F6\u95F4\u7EBF\u7247\u6BB5\u3002");
20989
- assert2(request.projectPath && isAbsolute7(request.projectPath), "INVALID_REQUEST", "\u8BF7\u9009\u62E9\u72EC\u7ACB\u5DE5\u7A0B\u7684\u65B0\u4FDD\u5B58\u4F4D\u7F6E\u3002");
20990
- assert2(!await stat6(request.projectPath).then(() => true, () => false), "TARGET_OCCUPIED", "\u65B0\u4F4D\u7F6E\u5DF2\u7ECF\u5B58\u5728\uFF0C\u672A\u8986\u76D6\u73B0\u6709\u5DE5\u7A0B\u3002");
21211
+ assert2(
21212
+ media.usageScanComplete && target.length === 1 && target[0].mediaPoolItemId === selection.mediaPoolItemId,
21213
+ "UNSUPPORTED_TIMELINE_ITEM",
21214
+ bridgeText("\u4E0D\u80FD\u5B8C\u6574\u6838\u5BF9\u8BE5\u7D20\u6750\u7684\u4F7F\u7528\u8303\u56F4\uFF0C\u672A\u51C6\u5907\u4FEE\u6539\u3002")
21215
+ );
21216
+ assert2(timeline && selection.timelineId && selection.itemId, "INVALID_REQUEST", bridgeText("\u8BF7\u9009\u62E9\u8981\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\u7684\u5177\u4F53\u65F6\u95F4\u7EBF\u7247\u6BB5\u3002"));
21217
+ assert2(request.projectPath && isAbsolute7(request.projectPath), "INVALID_REQUEST", bridgeText("\u8BF7\u9009\u62E9\u72EC\u7ACB\u5DE5\u7A0B\u7684\u65B0\u4FDD\u5B58\u4F4D\u7F6E\u3002"));
21218
+ assert2(!await stat5(request.projectPath).then(() => true, () => false), "TARGET_OCCUPIED", bridgeText("\u65B0\u4F4D\u7F6E\u5DF2\u7ECF\u5B58\u5728\uFF0C\u672A\u8986\u76D6\u73B0\u6709\u5DE5\u7A0B\u3002"));
20991
21219
  const observation = await this.mh.inspect(this.store.path(source.locator));
20992
- assert2(observation.coverage === "public-package-v1", "CAPABILITY_UNAVAILABLE", "\u72EC\u7ACB\u526F\u672C\u9700\u8981\u53EF\u5B8C\u6574\u6821\u9A8C\u7684\u516C\u5F00\u5DE5\u7A0B\u5305\u3002");
21220
+ assert2(observation.coverage === "public-package-v1", "CAPABILITY_UNAVAILABLE", bridgeText("\u72EC\u7ACB\u526F\u672C\u9700\u8981\u53EF\u5B8C\u6574\u6821\u9A8C\u7684\u516C\u5F00\u5DE5\u7A0B\u5305\u3002"));
20993
21221
  const artifact2 = binding.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
20994
21222
  assert2(
20995
21223
  artifact2 && artifact2.spec.fps.num === 30 * artifact2.spec.fps.den && timeline.fps.num === 30 * timeline.fps.den,
20996
21224
  "CAPABILITY_UNAVAILABLE",
20997
- "\u5355\u5B9E\u4F8B\u72EC\u7ACB\u526F\u672C\u5F53\u524D\u4EC5\u652F\u6301\u5DF2\u9A8C\u8BC1\u7684\u7D20\u6750\u548C\u65F6\u95F4\u7EBF\u5747\u4E3A 30 fps \u7684\u60C5\u51B5\u3002"
21225
+ bridgeText("\u5355\u5B9E\u4F8B\u72EC\u7ACB\u526F\u672C\u5F53\u524D\u4EC5\u652F\u6301\u5DF2\u9A8C\u8BC1\u7684\u7D20\u6750\u548C\u65F6\u95F4\u7EBF\u5747\u4E3A 30 fps \u7684\u60C5\u51B5\u3002")
20998
21226
  );
20999
21227
  assert2(
21000
21228
  media.uses.every((item) => !item.unsupported.length) && !target[0].intrinsicEntry && target[0].kind === "video",
21001
21229
  "UNSUPPORTED_TIMELINE_ITEM",
21002
- "\u6240\u9009\u5B9E\u4F8B\u7684\u5904\u7406\u4E0D\u80FD\u5B8C\u6574\u4FDD\u7559\uFF0C\u672A\u9000\u56DE\u53EA\u590D\u5236\u6E90\u5DE5\u7A0B\u3002"
21230
+ bridgeText("\u6240\u9009\u5B9E\u4F8B\u7684\u5904\u7406\u4E0D\u80FD\u5B8C\u6574\u4FDD\u7559\uFF0C\u672A\u9000\u56DE\u53EA\u590D\u5236\u6E90\u5DE5\u7A0B\u3002")
21003
21231
  );
21004
21232
  return {
21005
- title: "\u4EC5\u4E3A\u8FD9\u4E2A\u7247\u6BB5\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\uFF1F",
21006
- message: `\u590D\u5236\u53EF\u7F16\u8F91\u5DE5\u7A0B\uFF0C\u5E76\u53EA\u6539\u53D8\u6240\u9009\u201C${context.title}\u201D\u7247\u6BB5\u7684\u7D20\u6750\u5173\u8054\u3002\u5176\u4ED6\u5F15\u7528\u7EE7\u7EED\u4F7F\u7528\u539F\u5DE5\u7A0B\u3002`,
21007
- scopeLabel: "\u4EC5\u5F71\u54CD\u9009\u5B9A\u7684\u4E00\u4E2A\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u3002",
21233
+ title: bridgeText("\u4EC5\u4E3A\u8FD9\u4E2A\u7247\u6BB5\u521B\u5EFA\u72EC\u7ACB\u526F\u672C\uFF1F"),
21234
+ message: bridgeMessage("\u590D\u5236\u53EF\u7F16\u8F91\u5DE5\u7A0B\uFF0C\u5E76\u53EA\u6539\u53D8\u6240\u9009\u201C{0}\u201D\u7247\u6BB5\u7684\u7D20\u6750\u5173\u8054\u3002\u5176\u4ED6\u5F15\u7528\u7EE7\u7EED\u4F7F\u7528\u539F\u5DE5\u7A0B\u3002", [context.title]),
21235
+ scopeLabel: bridgeText("\u4EC5\u5F71\u54CD\u9009\u5B9A\u7684\u4E00\u4E2A\u65F6\u95F4\u7EBF\u5B9E\u4F8B\u3002"),
21008
21236
  command: "duplicate",
21009
21237
  request: {
21010
21238
  bindingId: binding.id,
21011
21239
  sourceId: source.id,
21012
- projectPath: resolve7(request.projectPath),
21240
+ projectPath: resolve8(request.projectPath),
21013
21241
  expectedContentVersion: observation.contentVersion,
21014
21242
  expectedRevision: binding.revision,
21015
21243
  timelineId: selection.timelineId,
@@ -21021,11 +21249,11 @@ var EntryContext = class {
21021
21249
  };
21022
21250
  }
21023
21251
  const artifact = binding.artifactId ? catalog.artifacts[binding.artifactId] : void 0;
21024
- assert2(!media.metadata["motionharness.bridge"], "BINDING_CONFLICT", "\u6B64\u7D20\u6750\u5DF2\u6709\u5176\u4ED6\u5173\u8054\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u8986\u76D6\u3002");
21025
- assert2(artifact && resolve7(media.path) === this.store.bindingPath(binding, artifact) && await fileDigest(media.path).catch(() => null) === artifact.sha256, "RECOVERY_CONFLICT", "\u5A92\u4F53\u8EAB\u4EFD\u3001\u8DEF\u5F84\u6216\u5185\u5BB9\u4E0D\u7B26\u5408\u539F\u767B\u8BB0\uFF0C\u4E0D\u80FD\u81EA\u52A8\u4FEE\u590D\u3002");
21252
+ assert2(!media.metadata["motionharness.bridge"], "BINDING_CONFLICT", bridgeText("\u6B64\u7D20\u6750\u5DF2\u6709\u5176\u4ED6\u5173\u8054\u8EAB\u4EFD\uFF0C\u4E0D\u80FD\u8986\u76D6\u3002"));
21253
+ assert2(artifact && resolve8(media.path) === this.store.bindingPath(binding, artifact) && await fileDigest(media.path).catch(() => null) === artifact.sha256, "RECOVERY_CONFLICT", bridgeText("\u5A92\u4F53\u8EAB\u4EFD\u3001\u8DEF\u5F84\u6216\u5185\u5BB9\u4E0D\u7B26\u5408\u539F\u767B\u8BB0\uFF0C\u4E0D\u80FD\u81EA\u52A8\u4FEE\u590D\u3002"));
21026
21254
  return {
21027
- title: "\u4FEE\u590D\u6240\u9009\u7D20\u6750\u7684\u5173\u8054\uFF1F",
21028
- message: `\u5DF2\u6309\u539F\u751F\u5A92\u4F53\u8EAB\u4EFD\u548C\u89C6\u9891\u5185\u5BB9\u5339\u914D\u201C${context.title}\u201D\u3002\u53EA\u8865\u56DE\u5173\u8054\u5143\u6570\u636E\uFF0C\u4E0D\u91CD\u65B0\u751F\u6210\u89C6\u9891\u3002`,
21255
+ title: bridgeText("\u4FEE\u590D\u6240\u9009\u7D20\u6750\u7684\u5173\u8054\uFF1F"),
21256
+ message: bridgeMessage("\u5DF2\u6309\u539F\u751F\u5A92\u4F53\u8EAB\u4EFD\u548C\u89C6\u9891\u5185\u5BB9\u5339\u914D\u201C{0}\u201D\u3002\u53EA\u8865\u56DE\u5173\u8054\u5143\u6570\u636E\uFF0C\u4E0D\u91CD\u65B0\u751F\u6210\u89C6\u9891\u3002", [context.title]),
21029
21257
  scopeLabel,
21030
21258
  command: "restore",
21031
21259
  request: {
@@ -21042,20 +21270,67 @@ var EntryContext = class {
21042
21270
 
21043
21271
  // src/native-install.ts
21044
21272
  import { homedir as homedir3 } from "node:os";
21045
- import { basename as basename4, delimiter as delimiter3, dirname as dirname8, isAbsolute as isAbsolute8, join as join7, resolve as resolve9 } from "node:path";
21046
- import { access as access3, mkdir as mkdir8, readFile as readFile9, writeFile, rename as rename6, rm as rm7, readdir as readdir2, stat as stat7, lstat as lstat5 } from "node:fs/promises";
21273
+ import { basename as basename4, delimiter as delimiter3, dirname as dirname9, isAbsolute as isAbsolute8, join as join8, resolve as resolve10 } from "node:path";
21274
+ import { access as access3, mkdir as mkdir8, readFile as readFile10, writeFile, rename as rename6, rm as rm7, rmdir, readdir as readdir2, stat as stat6, lstat as lstat5 } from "node:fs/promises";
21047
21275
  import { constants as constants6 } from "node:fs";
21048
21276
  import { randomUUID as randomUUID7 } from "node:crypto";
21049
21277
 
21278
+ // src/sidebar-guide.ts
21279
+ import { readFile as readFile9 } from "node:fs/promises";
21280
+ import { dirname as dirname7, join as join6 } from "node:path";
21281
+ var sidebarHint = {
21282
+ optional: true,
21283
+ title: "\u6DFB\u52A0\u4FA7\u680F\u7F16\u8F91\u5165\u53E3\uFF08\u53EF\u9009\uFF09",
21284
+ message: "\u7D20\u6750\u5DF2\u53D1\u9001\u5E76\u5173\u8054\u5DE5\u7A0B\u3002\u60F3\u4ECE\u8FBE\u82AC\u5947\u4FA7\u680F\u76F4\u63A5\u7F16\u8F91\uFF0C\u53EF\u6DFB\u52A0 MotionHarness \u6865\u63A5\u7EC4\u4EF6\u3002",
21285
+ steps: [
21286
+ "\u5728\u8FBE\u82AC\u5947\u300C\u526A\u8F91\u300D\u9875\u6253\u5F00\u5DE6\u4E0A\u89D2\u300C\u7279\u6548\u5E93\u300D\uFF08\u9B54\u68D2\u56FE\u6807\uFF09\u3002",
21287
+ "\u70B9\u51FB\u653E\u5927\u955C\uFF0C\u641C\u7D22 MotionHarness \u6865\u63A5\u7EC4\u4EF6\uFF0C\u5C06 Open FX \u4E2D\u7684\u540C\u540D\u6548\u679C\u62D6\u5230\u76EE\u6807\u52A8\u6548\u7247\u6BB5\u3002",
21288
+ "\u9009\u4E2D\u7247\u6BB5\uFF0C\u5728\u300C\u68C0\u67E5\u5668 \u2192 \u7279\u6548 \u2192 Open FX\u300D\u4E2D\u70B9\u51FB\u300C\u7F16\u8F91 MotionHarness \u5DE5\u7A0B\u300D\u3002"
21289
+ ],
21290
+ shortcut: "\u4E5F\u53EF\u5148\u9009\u4E2D\u7247\u6BB5\uFF0C\u6309 Shift + Space \u641C\u7D22\u5E76\u6DFB\u52A0\u3002",
21291
+ alternative: "\u4E0D\u6DFB\u52A0\u4E5F\u80FD\u4ECE\u300C\u5DE5\u4F5C\u533A \u2192 \u811A\u672C \u2192 Utility \u2192 MotionHarness \u6865\u63A5\u7EC4\u4EF6 \u2192 \u7F16\u8F91\u5DE5\u7A0B\u300D\u6253\u5F00\u3002",
21292
+ guideCommand: "mh bridge davinci sidebar-guide"
21293
+ };
21294
+ function sidebarHintForLocale(locale = bridgeLocale()) {
21295
+ if (locale !== "en") return sidebarHint;
21296
+ return {
21297
+ ...sidebarHint,
21298
+ title: "Add sidebar entry (optional)",
21299
+ message: `The media is linked to its source project. Add the ${bridgeName(locale)} to edit from the DaVinci Resolve sidebar.`,
21300
+ steps: [
21301
+ "On the Edit page in DaVinci Resolve, open the Effects Library (magic wand icon).",
21302
+ "Search for MotionHarness Bridge Component and drag the Open FX effect onto the target clip.",
21303
+ "Select the clip and click Edit MotionHarness project under Inspector \u2192 Effects \u2192 Open FX."
21304
+ ],
21305
+ shortcut: "You can also select the clip, press Shift + Space, then search and add the effect.",
21306
+ alternative: "You can also open the project from Workspace \u2192 Scripts \u2192 Utility \u2192 MotionHarness Bridge Component \u2192 Edit project."
21307
+ };
21308
+ }
21309
+ async function readSidebarGuideDocument(guidePath) {
21310
+ const html = await readFile9(guidePath, "utf8");
21311
+ const link2 = '<link rel="stylesheet" href="guide.css">';
21312
+ if (!html.includes(link2)) return html;
21313
+ const css = await readFile9(join6(dirname7(guidePath), "guide.css"), "utf8");
21314
+ return html.replace(link2, () => `<style>
21315
+ ${css}</style>`);
21316
+ }
21317
+ async function readSidebarGuide(componentRoot, inline = false, locale = bridgeLocale()) {
21318
+ const directory = join6(componentRoot, "resources/sidebar-help");
21319
+ const guidePath = join6(directory, locale === "en" ? "en.html" : "index.html");
21320
+ const hint = sidebarHintForLocale(locale);
21321
+ if (!inline) return { ...hint, guidePath };
21322
+ return { ...hint, html: await readSidebarGuideDocument(guidePath) };
21323
+ }
21324
+
21050
21325
  // src/native-permissions.ts
21051
21326
  import { access as access2, lstat as lstat4 } from "node:fs/promises";
21052
21327
  import { constants as constants5 } from "node:fs";
21053
- import { dirname as dirname7, join as join6, resolve as resolve8 } from "node:path";
21328
+ import { dirname as dirname8, join as join7, resolve as resolve9 } from "node:path";
21054
21329
  var systemPluginRoot = "/Library/OFX/Plugins";
21055
21330
  async function prepareOfxPermissions(componentRoot, pluginRoot, directories) {
21056
21331
  let writable = true;
21057
21332
  for (const directory of new Set(directories)) {
21058
- let current = resolve8(directory);
21333
+ let current = resolve9(directory);
21059
21334
  while (true) {
21060
21335
  const info2 = await lstat4(current).catch((error48) => {
21061
21336
  if (error48.code === "ENOENT") return null;
@@ -21070,18 +21345,18 @@ async function prepareOfxPermissions(componentRoot, pluginRoot, directories) {
21070
21345
  }
21071
21346
  break;
21072
21347
  }
21073
- const parent = dirname7(current);
21348
+ const parent = dirname8(current);
21074
21349
  assert2(parent !== current, "INSTALL_CONFLICT", "\u627E\u4E0D\u5230 OFX \u5B89\u88C5\u76EE\u5F55\u7684\u7236\u76EE\u5F55\u3002");
21075
21350
  current = parent;
21076
21351
  }
21077
- for (let ancestor = dirname7(current); ancestor !== dirname7(ancestor); ancestor = dirname7(ancestor)) {
21352
+ for (let ancestor = dirname8(current); ancestor !== dirname8(ancestor); ancestor = dirname8(ancestor)) {
21078
21353
  const info2 = await lstat4(ancestor);
21079
21354
  assert2(info2.isDirectory() && !info2.isSymbolicLink(), "INSTALL_CONFLICT", "OFX \u5B89\u88C5\u8DEF\u5F84\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u3002", { path: ancestor });
21080
21355
  }
21081
21356
  }
21082
21357
  if (writable) return { authorized: false };
21083
21358
  const uid = process.getuid?.(), gid = process.getgid?.();
21084
- if (process.platform !== "darwin" || resolve8(pluginRoot) !== systemPluginRoot || !uid || gid === void 0) {
21359
+ if (process.platform !== "darwin" || resolve9(pluginRoot) !== systemPluginRoot || !uid || gid === void 0) {
21085
21360
  throw new BridgeError(
21086
21361
  "OFX_PERMISSION_REQUIRED",
21087
21362
  "OFX \u76EE\u5F55\u4E0D\u53EF\u5199\uFF0C\u672A\u5B89\u88C5\u6216\u5347\u7EA7\u4EFB\u4F55\u5165\u53E3\u6587\u4EF6\u3002",
@@ -21091,7 +21366,7 @@ async function prepareOfxPermissions(componentRoot, pluginRoot, directories) {
21091
21366
  "\u4FEE\u590D\u81EA\u5B9A\u4E49 OFX \u76EE\u5F55\u6743\u9650\u540E\u91CD\u65B0\u8FD0\u884C mh bridge davinci install\uFF1B\u4E0D\u8981\u4EE5 root \u8FD0\u884C\u6574\u4E2A CLI\u3002"
21092
21367
  );
21093
21368
  }
21094
- const helper = join6(componentRoot, "resources/HotionHarnessInstall");
21369
+ const helper = join7(componentRoot, "resources/MotionHarnessInstall");
21095
21370
  const info = await lstat4(helper);
21096
21371
  assert2(info.isFile() && !info.isSymbolicLink(), "INSTALL_CONFLICT", "OFX \u6743\u9650\u52A9\u624B\u5FC5\u987B\u662F\u7ECF\u8FC7\u7EC4\u4EF6\u6821\u9A8C\u7684\u666E\u901A\u53EF\u6267\u884C\u6587\u4EF6\u3002");
21097
21372
  await access2(helper, constants5.X_OK);
@@ -21117,27 +21392,27 @@ end timeout`;
21117
21392
  }
21118
21393
 
21119
21394
  // src/native-install.ts
21120
- var statusAppName = "HotionHarnessStatus.app";
21121
- var statusAppBinary = join7("Contents", "MacOS", "HotionHarnessStatus");
21122
- var recordPath = (root) => join7(root, "native-install.json");
21395
+ var statusAppName = "MotionHarnessBridge.app";
21396
+ var statusAppBinary = join8("Contents", "MacOS", "MotionHarnessBridge");
21397
+ var recordPath = (root) => join8(root, "native-install.json");
21123
21398
  async function previous(root) {
21124
- return readFile9(recordPath(root), "utf8").then(JSON.parse).catch((error48) => {
21399
+ return readFile10(recordPath(root), "utf8").then(JSON.parse).catch((error48) => {
21125
21400
  if (error48.code !== "ENOENT") throw error48;
21126
21401
  return { version: 1, files: [], entry: { automaticAttachment: false, ofx: "unavailable" } };
21127
21402
  });
21128
21403
  }
21129
21404
  async function nativeStatus(configRoot) {
21130
21405
  const manifest = await previous(configRoot);
21131
- const matches = async (file2) => Boolean(file2 && await fileDigest(file2.path).then(async (actual) => actual === file2.sha256 && (process.platform === "win32" || file2.mode === void 0 || ((await stat7(file2.path)).mode & 511) === file2.mode), () => false));
21132
- const helperPath = manifest.statusExecutable ?? join7(configRoot, "bin/HotionHarnessStatus");
21133
- const applicationRoot = join7(configRoot, "bin", statusAppName);
21134
- const application = helperPath === join7(applicationRoot, statusAppBinary);
21406
+ const matches = async (file2) => Boolean(file2 && await fileDigest(file2.path).then(async (actual) => actual === file2.sha256 && (process.platform === "win32" || file2.mode === void 0 || ((await stat6(file2.path)).mode & 511) === file2.mode), () => false));
21407
+ const helperPath = manifest.statusExecutable ?? join8(configRoot, "bin/HotionHarnessStatus");
21408
+ const applicationRoot = join8(configRoot, "bin", statusAppName);
21409
+ const application = helperPath === join8(applicationRoot, statusAppBinary);
21135
21410
  const helper = manifest.files.find((file2) => file2.path === helperPath);
21136
21411
  const applicationFiles = application ? manifest.files.filter((file2) => file2.path.startsWith(applicationRoot + "/")) : [];
21137
- const applicationComplete = !application || applicationFiles.some((file2) => file2.path === join7(applicationRoot, "Contents/Info.plist")) && (await Promise.all(applicationFiles.map(matches))).every(Boolean);
21412
+ const applicationComplete = !application || applicationFiles.some((file2) => file2.path === join8(applicationRoot, "Contents/Info.plist")) && (await Promise.all(applicationFiles.map(matches))).every(Boolean);
21138
21413
  const helperInstalled = manifest.entry.statusHelper === "installed" && await matches(helper) && applicationComplete;
21139
- const names = ["\u7F16\u8F91\u5DE5\u7A0B.py", "\u66F4\u65B0\u5230\u8FBE\u82AC\u5947.py"];
21140
- const menusInstalled = helperInstalled && (await Promise.all(names.map((name) => matches(manifest.files.find((file2) => basename4(file2.path) === name))))).every(Boolean);
21414
+ const names = [["\u7F16\u8F91\u5DE5\u7A0B.py", "Edit project.py"], ["\u66F4\u65B0\u5230\u8FBE\u82AC\u5947.py", "Update in DaVinci Resolve.py"]];
21415
+ const menusInstalled = helperInstalled && (await Promise.all(names.map(async (alternatives) => (await Promise.all(manifest.files.filter((file2) => alternatives.includes(basename4(file2.path))).map(matches))).some(Boolean)))).every(Boolean);
21141
21416
  const pluginFiles = manifest.files.filter((file2) => file2.path.split(/[\\/]/).includes("HotionHarness.ofx.bundle"));
21142
21417
  const pluginInstalled = manifest.entry.ofx === "manual-attachment" && pluginFiles.length > 0 && (await Promise.all(pluginFiles.map(matches))).every(Boolean);
21143
21418
  return {
@@ -21150,7 +21425,7 @@ async function nativeStatus(configRoot) {
21150
21425
  };
21151
21426
  }
21152
21427
  async function publish(path, bytes, mode = 384) {
21153
- await mkdir8(dirname8(path), { recursive: true });
21428
+ await mkdir8(dirname9(path), { recursive: true });
21154
21429
  const pending = `${path}.${randomUUID7()}.pending`;
21155
21430
  try {
21156
21431
  await writeFile(pending, bytes, { flag: "wx", mode });
@@ -21160,25 +21435,66 @@ async function publish(path, bytes, mode = 384) {
21160
21435
  }
21161
21436
  }
21162
21437
  async function toolPath(command) {
21163
- const candidates = isAbsolute8(command) ? [command] : (process.env.PATH ?? "").split(delimiter3).filter(Boolean).map((directory) => resolve9(directory, command));
21438
+ const candidates = isAbsolute8(command) ? [command] : (process.env.PATH ?? "").split(delimiter3).filter(Boolean).map((directory) => resolve10(directory, command));
21164
21439
  for (const candidate of candidates) {
21165
21440
  try {
21166
21441
  await access3(candidate, constants6.X_OK);
21167
- if ((await stat7(candidate)).isFile()) return candidate;
21442
+ if ((await stat6(candidate)).isFile()) return candidate;
21168
21443
  } catch {
21169
21444
  }
21170
21445
  }
21171
21446
  return void 0;
21172
21447
  }
21448
+ async function cliLauncher(cliPath) {
21449
+ const packageJson = process.env.MH_NPM_PACKAGE_JSON;
21450
+ if (!packageJson || !isAbsolute8(packageJson)) return void 0;
21451
+ const pkg = JSON.parse(await readFile10(packageJson, "utf8"));
21452
+ if (pkg.name !== "@motionharness/cli" || typeof pkg.bin?.mh !== "string") return void 0;
21453
+ const script = resolve10(dirname9(packageJson), pkg.bin.mh);
21454
+ if (!script.startsWith(dirname9(packageJson) + "/") || !(await stat6(script)).isFile()) return void 0;
21455
+ assert2(isAbsolute8(cliPath), "INSTALL_CONFLICT", "CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002");
21456
+ return { executable: process.execPath, script };
21457
+ }
21458
+ async function repairNativeConnection(options) {
21459
+ await finishNativeInstall(options.configRoot);
21460
+ const record2 = await readNativeFile(recordPath(options.configRoot));
21461
+ assert2(record2, "INSTALL_MISSING", "\u6865\u63A5\u5B89\u88C5\u8BB0\u5F55\u7F3A\u5931\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install\u3002");
21462
+ const manifest = JSON.parse(record2.bytes.toString("utf8"));
21463
+ assert2(manifest.nativeConfig, "INSTALL_MISSING", "\u6865\u63A5\u914D\u7F6E\u7F3A\u5931\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install\u3002");
21464
+ const config2 = await readNativeFile(manifest.nativeConfig);
21465
+ assert2(config2, "INSTALL_MISSING", "\u6865\u63A5\u914D\u7F6E\u7F3A\u5931\uFF0C\u8BF7\u8FD0\u884C mh bridge davinci install\u3002");
21466
+ const saved = manifest.files.find((file2) => file2.path === manifest.nativeConfig);
21467
+ assert2(
21468
+ saved?.sha256 === "sha256:" + config2.sha256 && (saved.mode === void 0 || saved.mode === config2.mode),
21469
+ "INSTALL_CONFLICT",
21470
+ "\u6865\u63A5\u914D\u7F6E\u5DF2\u88AB\u4FEE\u6539\uFF0C\u672A\u8986\u76D6\u3002\u8BF7\u68C0\u67E5\u914D\u7F6E\u540E\u91CD\u65B0\u5B89\u88C5\u7EC4\u4EF6\u3002"
21471
+ );
21472
+ const value = JSON.parse(config2.bytes.toString("utf8"));
21473
+ const launcher = await cliLauncher(options.cliPath);
21474
+ const tools = { ...value.tools, node: process.execPath };
21475
+ const toolDirectories = [...new Set(Object.values(tools).filter((path) => typeof path === "string" && isAbsolute8(path)).map(dirname9))];
21476
+ const bytes = JSON.stringify({ ...value, cliPath: options.cliPath, ...launcher ? { cliLauncher: launcher } : {}, tools, toolDirectories }, null, 2) + "\n";
21477
+ const toolchainPath = join8(options.configRoot, "toolchain.json");
21478
+ const toolchain = await readNativeFile(toolchainPath), savedTools = manifest.files.find((file2) => file2.path === toolchainPath);
21479
+ assert2(toolchain && savedTools?.sha256 === "sha256:" + toolchain.sha256 && (savedTools.mode === void 0 || savedTools.mode === toolchain.mode), "INSTALL_CONFLICT", "\u6865\u63A5\u5DE5\u5177\u914D\u7F6E\u5DF2\u88AB\u4FEE\u6539\uFF0C\u672A\u8986\u76D6\u3002");
21480
+ const changes = [
21481
+ { path: manifest.nativeConfig, bytes, mode: config2.mode, expectedBefore: nativeFileState(config2) },
21482
+ { path: toolchainPath, bytes: JSON.stringify({ schemaVersion: 1, tools, toolDirectories }, null, 2) + "\n", mode: toolchain.mode, expectedBefore: nativeFileState(toolchain) }
21483
+ ];
21484
+ for (const change of changes) manifest.files = manifest.files.map((file2) => file2.path === change.path ? { ...file2, sha256: "sha256:" + sha256(change.bytes), mode: change.mode } : file2);
21485
+ changes.push({ path: recordPath(options.configRoot), bytes: JSON.stringify(manifest), mode: record2.mode, expectedBefore: nativeFileState(record2) });
21486
+ await publishNativeFiles(options.configRoot, changes);
21487
+ return { repaired: true, restartResolveRequired: false };
21488
+ }
21173
21489
  async function bundleFiles(source, destination, executable) {
21174
21490
  const files = [];
21175
21491
  for (const item of await readdir2(source, { withFileTypes: true })) {
21176
- const path = join7(source, item.name), output = join7(destination, item.name);
21492
+ const path = join8(source, item.name), output = join8(destination, item.name);
21177
21493
  assert2(!item.isSymbolicLink(), "INSTALL_CONFLICT", "\u539F\u751F\u5B89\u88C5\u8D44\u6E90\u4E0D\u80FD\u5305\u542B\u7B26\u53F7\u94FE\u63A5\u3002");
21178
21494
  if (item.isDirectory()) files.push(...await bundleFiles(path, output, executable));
21179
21495
  else {
21180
21496
  assert2(item.isFile(), "INSTALL_CONFLICT", "\u539F\u751F\u5B89\u88C5\u8D44\u6E90\u53EA\u80FD\u5305\u542B\u666E\u901A\u6587\u4EF6\u3002");
21181
- files.push({ path: output, bytes: await readFile9(path), mode: output === executable || (await stat7(path)).mode & 73 ? 493 : 420 });
21497
+ files.push({ path: output, bytes: await readFile10(path), mode: output === executable || (await stat6(path)).mode & 73 ? 493 : 420 });
21182
21498
  }
21183
21499
  }
21184
21500
  return files;
@@ -21187,19 +21503,20 @@ async function installNative(options) {
21187
21503
  assert2(!options.requireComplete || process.platform === "darwin", "PLATFORM_UNSUPPORTED", "\u5305\u542B\u83DC\u5355\u3001\u5C0F\u7A97\u53E3\u4E0E OFX \u7684\u6865\u63A5\u5B89\u88C5\u76EE\u524D\u53EA\u652F\u6301 macOS\u3002");
21188
21504
  assert2(!options.requireComplete || process.getuid?.() !== 0, "INSTALL_AS_USER", "\u8BF7\u4EE5\u666E\u901A\u7528\u6237\u8FD0\u884C mh bridge davinci install\uFF1B\u9700\u8981\u7CFB\u7EDF\u6743\u9650\u65F6\u4F1A\u5355\u72EC\u8BF7\u6C42\u6388\u6743\u3002");
21189
21505
  await finishNativeInstall(options.configRoot);
21190
- const previousRecord = await readFile9(recordPath(options.configRoot)).catch((error48) => {
21506
+ const previousRecord = await readFile10(recordPath(options.configRoot)).catch((error48) => {
21191
21507
  if (error48.code === "ENOENT") return null;
21192
21508
  throw error48;
21193
21509
  });
21194
21510
  const old = previousRecord ? JSON.parse(previousRecord.toString("utf8")) : { version: 1, files: [], entry: { automaticAttachment: false, ofx: "unavailable" } };
21195
21511
  const oldByPath = new Map(old.files.map((file2) => [file2.path, file2]));
21196
- const expectedRecord = previousRecord ? { sha256: sha256(previousRecord), mode: (await stat7(recordPath(options.configRoot))).mode & 511 } : null;
21512
+ const expectedRecord = previousRecord ? { sha256: sha256(previousRecord), mode: (await stat6(recordPath(options.configRoot))).mode & 511 } : null;
21197
21513
  const validated = /* @__PURE__ */ new Map();
21198
- const scriptsRoot = process.env.MH_DAVINCI_SCRIPTS_DIR ?? (process.platform === "darwin" ? join7(homedir3(), "Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Scripts/Utility/Hotion Harness") : process.platform === "win32" ? join7(process.env.APPDATA ?? homedir3(), "Blackmagic Design/DaVinci Resolve/Support/Fusion/Scripts/Utility/Hotion Harness") : join7(homedir3(), ".local/share/DaVinciResolve/Fusion/Scripts/Utility/Hotion Harness"));
21199
- const nativeConfig = process.env.MH_DAVINCI_NATIVE_CONFIG ?? (process.platform === "darwin" ? join7(homedir3(), "Library/Application Support/Hotion Harness/bridge/davinci/native-entry.json") : join7(options.configRoot, "native-entry.json"));
21200
- const template = await readFile9(join7(options.componentRoot, "resources/menu-entry.py"), "utf8");
21201
- const helper = join7(options.componentRoot, "resources/HotionHarnessStatus");
21202
- const application = join7(options.componentRoot, "resources", statusAppName);
21514
+ const locale = bridgeLocale(), label = bridgeName(locale);
21515
+ const scriptsRoot = process.env.MH_DAVINCI_SCRIPTS_DIR ?? (process.platform === "darwin" ? join8(homedir3(), "Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Scripts/Utility", label) : process.platform === "win32" ? join8(process.env.APPDATA ?? homedir3(), "Blackmagic Design/DaVinci Resolve/Support/Fusion/Scripts/Utility", label) : join8(homedir3(), ".local/share/DaVinciResolve/Fusion/Scripts/Utility", label));
21516
+ const nativeConfig = process.env.MH_DAVINCI_NATIVE_CONFIG ?? (process.platform === "darwin" ? join8(homedir3(), "Library/Application Support/Hotion Harness/bridge/davinci/native-entry.json") : join8(options.configRoot, "native-entry.json"));
21517
+ const template = await readFile10(join8(options.componentRoot, "resources/menu-entry.py"), "utf8");
21518
+ const helper = join8(options.componentRoot, "resources/HotionHarnessStatus");
21519
+ const application = join8(options.componentRoot, "resources", statusAppName);
21203
21520
  const resourceInfo = async (path) => process.platform === "darwin" ? lstat5(path).catch((error48) => {
21204
21521
  if (error48.code === "ENOENT") return null;
21205
21522
  throw error48;
@@ -21208,63 +21525,69 @@ async function installNative(options) {
21208
21525
  assert2(!applicationInfo || applicationInfo.isDirectory(), "INSTALL_CONFLICT", "\u72B6\u6001\u7A97\u53E3\u5E94\u7528\u5FC5\u987B\u662F\u666E\u901A\u76EE\u5F55\u3002");
21209
21526
  const helperInfo = applicationInfo ? null : await resourceInfo(helper);
21210
21527
  assert2(!helperInfo || helperInfo.isFile(), "INSTALL_CONFLICT", "\u72B6\u6001\u7A97\u53E3\u8D44\u6E90\u5FC5\u987B\u662F\u666E\u901A\u53EF\u6267\u884C\u6587\u4EF6\u3002");
21211
- const statusExecutable = applicationInfo ? join7(options.configRoot, "bin", statusAppName, statusAppBinary) : helperInfo ? join7(options.configRoot, "bin/HotionHarnessStatus") : void 0;
21528
+ const statusExecutable = applicationInfo ? join8(options.configRoot, "bin", statusAppName, statusAppBinary) : helperInfo ? join8(options.configRoot, "bin/HotionHarnessStatus") : void 0;
21212
21529
  const tools = {
21213
21530
  node: process.execPath,
21214
21531
  pnpm: await toolPath(process.platform === "win32" ? "pnpm.cmd" : "pnpm"),
21215
21532
  ffmpeg: await toolPath(process.env.MH_FFMPEG ?? "ffmpeg"),
21216
21533
  ffprobe: await toolPath(process.env.MH_FFPROBE ?? "ffprobe")
21217
21534
  };
21218
- const toolDirectories = [...new Set(Object.values(tools).filter((path) => Boolean(path)).map(dirname8))];
21535
+ const toolDirectories = [...new Set(Object.values(tools).filter((path) => Boolean(path)).map(dirname9))];
21219
21536
  const toolchain = { schemaVersion: 1, tools, toolDirectories };
21220
21537
  const desired = [];
21221
- const guideNames = ["index.html", "resolve-sidebar.png"];
21222
- const guideDirectory = join7(options.componentRoot, "resources/sidebar-help");
21223
- const guideAvailable = (await Promise.all(guideNames.map((name) => lstat5(join7(guideDirectory, name)).then((info) => info.isFile(), (error48) => {
21538
+ const translationsPath = join8(options.configRoot, "i18n/en.json");
21539
+ desired.push({ path: translationsPath, bytes: JSON.stringify(bridgeEnglishCatalog), mode: 420 });
21540
+ const guideNames = ["index.html", "en.html"];
21541
+ const guideDirectory = join8(options.componentRoot, "resources/sidebar-help");
21542
+ const guideAvailable = (await Promise.all(guideNames.map((name) => lstat5(join8(guideDirectory, name)).then((info) => info.isFile(), (error48) => {
21224
21543
  if (error48.code === "ENOENT") return false;
21225
21544
  throw error48;
21226
21545
  })))).every(Boolean);
21227
- const sidebarGuidePath = guideAvailable ? join7(options.configRoot, "help/sidebar/index.html") : void 0;
21546
+ const sidebarGuidePath = guideAvailable ? join8(options.configRoot, "help/sidebar", locale === "en" ? "en.html" : "index.html") : void 0;
21228
21547
  if (guideAvailable) for (const name of guideNames) desired.push({
21229
- path: join7(options.configRoot, "help/sidebar", name),
21230
- bytes: await readFile9(join7(guideDirectory, name)),
21548
+ path: join8(options.configRoot, "help/sidebar", name),
21549
+ bytes: await readSidebarGuideDocument(join8(guideDirectory, name)),
21231
21550
  mode: 420
21232
21551
  });
21233
21552
  if (applicationInfo) {
21234
- desired.push(...await bundleFiles(application, join7(options.configRoot, "bin", statusAppName), statusExecutable));
21553
+ desired.push(...await bundleFiles(application, join8(options.configRoot, "bin", statusAppName), statusExecutable));
21235
21554
  assert2(
21236
- desired.some((file2) => file2.path === statusExecutable) && desired.some((file2) => file2.path === join7(options.configRoot, "bin", statusAppName, "Contents/Info.plist")),
21555
+ desired.some((file2) => file2.path === statusExecutable) && desired.some((file2) => file2.path === join8(options.configRoot, "bin", statusAppName, "Contents/Info.plist")),
21237
21556
  "INSTALL_CONFLICT",
21238
21557
  "\u72B6\u6001\u7A97\u53E3\u5E94\u7528\u7F3A\u5C11\u53EF\u6267\u884C\u6587\u4EF6\u6216 Info.plist\u3002"
21239
21558
  );
21240
- } else if (statusExecutable) desired.push({ path: statusExecutable, bytes: await readFile9(helper), mode: 493 });
21241
- desired.push({ path: join7(options.configRoot, "toolchain.json"), bytes: JSON.stringify(toolchain, null, 2) + "\n", mode: 384 });
21559
+ } else if (statusExecutable) desired.push({ path: statusExecutable, bytes: await readFile10(helper), mode: 493 });
21560
+ desired.push({ path: join8(options.configRoot, "toolchain.json"), bytes: JSON.stringify(toolchain, null, 2) + "\n", mode: 384 });
21561
+ const launcher = await cliLauncher(options.cliPath);
21242
21562
  desired.push({ path: nativeConfig, bytes: JSON.stringify({
21243
21563
  schemaVersion: 1,
21244
21564
  ofxSourceProtocol: 1,
21245
21565
  ofxManagementProtocol: 1,
21246
21566
  ofxSelectionReviewProtocol: 1,
21247
21567
  cliPath: options.cliPath,
21568
+ ...launcher ? { cliLauncher: launcher } : {},
21248
21569
  workspace: options.workspace,
21249
- bridgeDirectory: dirname8(options.configRoot),
21570
+ bridgeDirectory: dirname9(options.configRoot),
21250
21571
  tools,
21251
21572
  toolDirectories,
21573
+ locale,
21574
+ translationsPath,
21252
21575
  ...sidebarGuidePath ? { sidebarGuidePath } : {},
21253
21576
  ...statusExecutable ? { statusExecutable } : {}
21254
21577
  }, null, 2) + "\n", mode: 384 });
21255
- for (const [label, action2] of statusExecutable ? [["\u7F16\u8F91\u5DE5\u7A0B", "edit"], ["\u66F4\u65B0\u5230\u8FBE\u82AC\u5947", "update"]] : []) {
21256
- desired.push({ path: join7(scriptsRoot, `${label}.py`), bytes: template.replaceAll("__HOTION_ACTION_JSON__", JSON.stringify(action2)).replaceAll("__HOTION_CONFIG_PATH_JSON__", JSON.stringify(nativeConfig)).replaceAll("__HOTION_STATUS_PATH_JSON__", JSON.stringify(statusExecutable)), mode: 384 });
21578
+ for (const [label2, action2] of statusExecutable ? [["\u7F16\u8F91\u5DE5\u7A0B", "edit"], ["\u66F4\u65B0\u5230\u8FBE\u82AC\u5947", "update"]] : []) {
21579
+ desired.push({ path: join8(scriptsRoot, `${bridgeText(label2, locale)}.py`), bytes: template.replaceAll("__HOTION_ACTION_JSON__", JSON.stringify(action2)).replaceAll("__HOTION_CONFIG_PATH_JSON__", JSON.stringify(nativeConfig)).replaceAll("__HOTION_STATUS_PATH_JSON__", JSON.stringify(statusExecutable)), mode: 384 });
21257
21580
  }
21258
21581
  const registeredForwarder = await prepareRegisteredForwarder(options, old, statusExecutable, nativeConfig);
21259
21582
  if (registeredForwarder) desired.push(registeredForwarder.file);
21260
- const bundle = join7(options.componentRoot, "resources", "HotionHarness.ofx.bundle");
21583
+ const bundle = join8(options.componentRoot, "resources", "HotionHarness.ofx.bundle");
21261
21584
  const bundleInfo = process.platform === "darwin" ? await lstat5(bundle).catch((error48) => {
21262
21585
  if (error48.code === "ENOENT") return null;
21263
21586
  throw error48;
21264
21587
  }) : null;
21265
21588
  assert2(!bundleInfo || bundleInfo.isDirectory(), "INSTALL_CONFLICT", "OFX \u5B89\u88C5\u8D44\u6E90\u5FC5\u987B\u662F\u666E\u901A\u76EE\u5F55\u3002");
21266
21589
  const pluginRoot = process.env.MH_DAVINCI_OFX_DIR ?? (process.platform === "darwin" ? "/Library/OFX/Plugins" : void 0);
21267
- const pluginFiles = bundleInfo && pluginRoot ? await bundleFiles(bundle, join7(pluginRoot, "HotionHarness.ofx.bundle")) : [];
21590
+ const pluginFiles = bundleInfo && pluginRoot ? await bundleFiles(bundle, join8(pluginRoot, "HotionHarness.ofx.bundle")) : [];
21268
21591
  if (options.requireComplete) {
21269
21592
  assert2(
21270
21593
  applicationInfo && pluginFiles.some((file2) => file2.path.endsWith("/Contents/MacOS/HotionHarness.ofx")) && pluginFiles.some((file2) => file2.path.endsWith("/Contents/Info.plist")),
@@ -21291,12 +21614,12 @@ async function installNative(options) {
21291
21614
  const recorded = oldByPath.get(file2.path), expected = "sha256:" + sha256(file2.bytes);
21292
21615
  assert2(existing === recorded?.sha256 || existing === expected, "INSTALL_CONFLICT", "\u5B89\u88C5\u8DEF\u5F84\u5305\u542B\u975E\u672C\u7EC4\u4EF6\u6587\u4EF6\u6216\u7528\u6237\u4FEE\u6539\uFF0C\u672A\u8986\u76D6\u3002", { path: file2.path });
21293
21616
  if (process.platform !== "win32" && recorded?.mode !== void 0) assert2(
21294
- ((await stat7(file2.path)).mode & 511) === recorded.mode,
21617
+ ((await stat6(file2.path)).mode & 511) === recorded.mode,
21295
21618
  "INSTALL_CONFLICT",
21296
21619
  "\u7528\u6237\u4FEE\u6539\u4E86\u5B89\u88C5\u6587\u4EF6\u6743\u9650\uFF0C\u672A\u8986\u76D6\u3002",
21297
21620
  { path: file2.path }
21298
21621
  );
21299
- validated.set(file2.path, { sha256: existing.slice("sha256:".length), mode: (await stat7(file2.path)).mode & 511 });
21622
+ validated.set(file2.path, { sha256: existing.slice("sha256:".length), mode: (await stat6(file2.path)).mode & 511 });
21300
21623
  }
21301
21624
  };
21302
21625
  await validate(desired);
@@ -21306,7 +21629,7 @@ async function installNative(options) {
21306
21629
  } catch (error48) {
21307
21630
  if (!["EACCES", "EPERM"].includes(error48.code ?? "")) throw error48;
21308
21631
  }
21309
- await prepareOfxPermissions(options.componentRoot, pluginRoot, pluginFiles.map((file2) => dirname8(file2.path)));
21632
+ await prepareOfxPermissions(options.componentRoot, pluginRoot, pluginFiles.map((file2) => dirname9(file2.path)));
21310
21633
  }
21311
21634
  let pluginAccessible = true;
21312
21635
  try {
@@ -21335,11 +21658,11 @@ async function installNative(options) {
21335
21658
  owned.delete(file2.path);
21336
21659
  continue;
21337
21660
  }
21338
- if (actual !== file2.sha256 || process.platform !== "win32" && file2.mode !== void 0 && ((await stat7(file2.path)).mode & 511) !== file2.mode) {
21661
+ if (actual !== file2.sha256 || process.platform !== "win32" && file2.mode !== void 0 && ((await stat6(file2.path)).mode & 511) !== file2.mode) {
21339
21662
  retained.push(file2.path);
21340
21663
  continue;
21341
21664
  }
21342
- changes.push({ path: file2.path, bytes: null, expectedBefore: { sha256: actual.slice("sha256:".length), mode: (await stat7(file2.path)).mode & 511 } });
21665
+ changes.push({ path: file2.path, bytes: null, expectedBefore: { sha256: actual.slice("sha256:".length), mode: (await stat6(file2.path)).mode & 511 } });
21343
21666
  owned.delete(file2.path);
21344
21667
  removed.push(file2.path);
21345
21668
  }
@@ -21360,12 +21683,19 @@ async function installNative(options) {
21360
21683
  if (options.requireComplete) throw error48;
21361
21684
  const failure = error48;
21362
21685
  const within = (child, parent) => child === parent || child.startsWith(parent + "/");
21363
- const failedPath = typeof failure.path === "string" ? resolve9(failure.path) : void 0;
21364
- const pluginPath = pluginRoot ? resolve9(pluginRoot) : void 0;
21365
- const optionalPath = failedPath && pluginPath && (within(failedPath, pluginPath) || within(pluginPath, failedPath) && !desired.some((file2) => within(resolve9(file2.path), failedPath)));
21686
+ const failedPath = typeof failure.path === "string" ? resolve10(failure.path) : void 0;
21687
+ const pluginPath = pluginRoot ? resolve10(pluginRoot) : void 0;
21688
+ const optionalPath = failedPath && pluginPath && (within(failedPath, pluginPath) || within(pluginPath, failedPath) && !desired.some((file2) => within(resolve10(file2.path), failedPath)));
21366
21689
  if (!pluginAccessible || !["EACCES", "EPERM", "EROFS"].includes(failure.code ?? "") || !optionalPath) throw error48;
21367
21690
  await apply(false);
21368
21691
  }
21692
+ const retiredGroups = ["Hotion Harness", "Motion Harness", "Motion Harness \u6865\u63A5\u7EC4\u4EF6", "Motion Harness Bridge Component", "MotionHarness", "MotionHarness \u6865\u63A5\u7EC4\u4EF6", "MotionHarness Bridge Component"];
21693
+ for (const directory of new Set(removed.map(dirname9))) {
21694
+ if (directory === scriptsRoot || !retiredGroups.includes(basename4(directory)) || basename4(dirname9(directory)) !== "Utility") continue;
21695
+ await rmdir(directory).catch((error48) => {
21696
+ if (!["ENOENT", "ENOTEMPTY", "EEXIST", "EACCES", "EPERM"].includes(error48.code)) throw error48;
21697
+ });
21698
+ }
21369
21699
  return {
21370
21700
  installed: true,
21371
21701
  complete: Boolean(statusExecutable && pluginFiles.length && entry.ofx === "manual-attachment"),
@@ -21387,7 +21717,7 @@ async function uninstallNative({ configRoot }) {
21387
21717
  throw error48;
21388
21718
  });
21389
21719
  if (!actual) continue;
21390
- if (actual !== file2.sha256 || process.platform !== "win32" && file2.mode !== void 0 && ((await stat7(file2.path)).mode & 511) !== file2.mode) {
21720
+ if (actual !== file2.sha256 || process.platform !== "win32" && file2.mode !== void 0 && ((await stat6(file2.path)).mode & 511) !== file2.mode) {
21391
21721
  retained.push(file2);
21392
21722
  continue;
21393
21723
  }
@@ -21398,42 +21728,17 @@ async function uninstallNative({ configRoot }) {
21398
21728
  return { installed: false, removed, retained: retained.map((file2) => file2.path), associationsPreserved: true, legacyForwarder };
21399
21729
  }
21400
21730
 
21401
- // src/sidebar-guide.ts
21402
- import { readFile as readFile10 } from "node:fs/promises";
21403
- import { join as join8 } from "node:path";
21404
- var sidebarHint = {
21405
- optional: true,
21406
- title: "\u6DFB\u52A0\u4FA7\u680F\u7F16\u8F91\u5165\u53E3\uFF08\u53EF\u9009\uFF09",
21407
- message: "\u7D20\u6750\u5DF2\u53D1\u9001\u5E76\u5173\u8054\u5DE5\u7A0B\u3002\u60F3\u4ECE\u8FBE\u82AC\u5947\u4FA7\u680F\u76F4\u63A5\u7F16\u8F91\uFF0C\u53EF\u6DFB\u52A0 Hotion Harness \u6548\u679C\u3002",
21408
- steps: [
21409
- "\u5728\u8FBE\u82AC\u5947\u300C\u526A\u8F91\u300D\u9875\u6253\u5F00\u5DE6\u4E0A\u89D2\u300C\u7279\u6548\u5E93\u300D\uFF08\u9B54\u68D2\u56FE\u6807\uFF09\u3002",
21410
- "\u70B9\u51FB\u653E\u5927\u955C\uFF0C\u641C\u7D22 Hotion Harness\uFF0C\u5C06 Open FX \u4E2D\u7684\u540C\u540D\u6548\u679C\u62D6\u5230\u76EE\u6807\u52A8\u6548\u7247\u6BB5\u3002",
21411
- "\u9009\u4E2D\u7247\u6BB5\uFF0C\u5728\u300C\u68C0\u67E5\u5668 \u2192 \u7279\u6548 \u2192 Open FX\u300D\u4E2D\u70B9\u51FB\u300C\u7F16\u8F91 Hotion Harness \u5DE5\u7A0B\u300D\u3002"
21412
- ],
21413
- shortcut: "\u4E5F\u53EF\u5148\u9009\u4E2D\u7247\u6BB5\uFF0C\u6309 Shift + Space \u641C\u7D22\u5E76\u6DFB\u52A0\u3002",
21414
- alternative: "\u4E0D\u6DFB\u52A0\u4E5F\u80FD\u4ECE\u300C\u5DE5\u4F5C\u533A \u2192 \u811A\u672C \u2192 Utility \u2192 Hotion Harness \u2192 \u7F16\u8F91\u5DE5\u7A0B\u300D\u6253\u5F00\u3002",
21415
- guideCommand: "mh bridge davinci sidebar-guide"
21416
- };
21417
- async function readSidebarGuide(componentRoot, inline = false) {
21418
- const directory = join8(componentRoot, "resources/sidebar-help");
21419
- const guidePath = join8(directory, "index.html"), screenshotPath = join8(directory, "resolve-sidebar.png");
21420
- if (!inline) return { ...sidebarHint, guidePath, screenshotPath };
21421
- const html = await readFile10(guidePath, "utf8");
21422
- const image = (await readFile10(screenshotPath)).toString("base64");
21423
- return { ...sidebarHint, html: html.replaceAll('src="resolve-sidebar.png"', `src="data:image/png;base64,${image}"`) };
21424
- }
21425
-
21426
21731
  // src/runner.ts
21427
21732
  var taskView = (job) => ({
21428
21733
  ...job,
21429
21734
  taskId: job.id,
21430
21735
  message: job.error?.message ?? job.progress.stage,
21431
- ...job.operation === "send" && job.phase === "completed" && job.results.some((result2) => result2.applied === true && result2.bindingId) ? { sidebarHint } : {}
21736
+ ...job.operation === "send" && job.phase === "completed" && job.results.some((result2) => result2.applied === true && result2.bindingId) ? { sidebarHint: sidebarHintForLocale() } : {}
21432
21737
  });
21433
21738
  var jobOperations = { send: "send", update: "update", insert: "insert", render: "render", adopt: "adopt", apply: "apply", restore: "restore", duplicate: "duplicate", sync: "sync", "legacy-convert": "legacy-convert" };
21434
21739
  function assertJobScope(bridge, catalog, job, projectPath, readOnly = false) {
21435
21740
  if (!projectPath) return;
21436
- const path = resolve10(projectPath);
21741
+ const path = resolve11(projectPath);
21437
21742
  const sourceIds = new Set(Object.values(catalog.sources).filter((source) => bridge.store.path(source.locator) === path).map((source) => source.id));
21438
21743
  const bindingIds = new Set(Object.values(catalog.bindings).filter((binding) => sourceIds.has(binding.sourceId)).map((binding) => binding.id));
21439
21744
  const targets = Array.isArray(job.request.targets) ? job.request.targets : [];
@@ -21503,14 +21808,14 @@ async function launchWorker(bridge, taskId, request) {
21503
21808
  shell: false,
21504
21809
  env: process.env
21505
21810
  });
21506
- const cleaned = child.exitCode !== null || child.signalCode !== null ? Promise.resolve(child.signalCode === null) : new Promise((resolve11) => {
21507
- child.once("exit", (_code, signal) => resolve11(signal === null));
21508
- child.once("error", () => resolve11(child.pid === void 0));
21811
+ const cleaned = child.exitCode !== null || child.signalCode !== null ? Promise.resolve(child.signalCode === null) : new Promise((resolve12) => {
21812
+ child.once("exit", (_code, signal) => resolve12(signal === null));
21813
+ child.once("error", () => resolve12(child.pid === void 0));
21509
21814
  });
21510
21815
  const readiness = child.stdio[4];
21511
21816
  try {
21512
21817
  assert2(readiness, "WORKER_LEASE_REQUIRED", "\u540E\u53F0\u76D1\u7763\u8FDB\u7A0B\u7F3A\u5C11\u542F\u52A8\u786E\u8BA4\u901A\u9053\u3002");
21513
- await new Promise((resolve11, reject) => {
21818
+ await new Promise((resolve12, reject) => {
21514
21819
  let text = "", settled = false;
21515
21820
  const finish = (error48) => {
21516
21821
  if (settled) return;
@@ -21521,7 +21826,7 @@ async function launchWorker(bridge, taskId, request) {
21521
21826
  readiness.off("end", ended);
21522
21827
  readiness.off("error", failed);
21523
21828
  if (error48) reject(error48);
21524
- else resolve11();
21829
+ else resolve12();
21525
21830
  };
21526
21831
  const failed = (error48) => finish(error48);
21527
21832
  const ended = () => finish(new BridgeError("WORKER_START_FAILED", "\u540E\u53F0 worker \u672A\u786E\u8BA4\u9886\u53D6\u4EFB\u52A1\uFF1B\u8BF7\u67E5\u8BE2\u539F taskId\uFF0C\u672A\u91CD\u590D\u521B\u5EFA\u4EFB\u52A1\u3002"));
@@ -21546,8 +21851,8 @@ async function launchWorker(bridge, taskId, request) {
21546
21851
  } catch (error48) {
21547
21852
  if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM");
21548
21853
  let cleanupTimer;
21549
- const cleanupObserved = await Promise.race([cleaned, new Promise((resolve11) => {
21550
- cleanupTimer = setTimeout(() => resolve11(false), 3e3);
21854
+ const cleanupObserved = await Promise.race([cleaned, new Promise((resolve12) => {
21855
+ cleanupTimer = setTimeout(() => resolve12(false), 3e3);
21551
21856
  })]);
21552
21857
  clearTimeout(cleanupTimer);
21553
21858
  if (cleanupObserved) await recordWorkerStartFailure(bridge, taskId, error48);
@@ -21589,7 +21894,7 @@ async function execute(request) {
21589
21894
  }
21590
21895
  if (requestedOperation === "send") {
21591
21896
  payload2.projectPath ??= request.projectPath;
21592
- if (typeof payload2.projectPath === "string") payload2.projectPath = resolve10(payload2.projectPath);
21897
+ if (typeof payload2.projectPath === "string") payload2.projectPath = resolve11(payload2.projectPath);
21593
21898
  }
21594
21899
  if (requestedOperation === "update" && !payload2.bindingId) payload2.bindingId = catalog.jobs[String(receipt.result.taskId)]?.request.bindingId;
21595
21900
  return replayTask(bridge, request, catalog, requestedOperation, payload2, selectionHash);
@@ -21648,9 +21953,9 @@ async function execute(request) {
21648
21953
  if (selection.expectedMediaFingerprint) assert2(
21649
21954
  (await bridge.host.media(selection.scope, selection.mediaPoolItemId)).fingerprint === selection.expectedMediaFingerprint,
21650
21955
  "VERSION_CONFLICT",
21651
- "\u786E\u8BA4\u540E\u7684\u7D20\u6750\u4F7F\u7528\u8303\u56F4\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u3002"
21956
+ "\u786E\u8BA4\u540E\u7684\u539F\u7D20\u6750\u8EAB\u4EFD\u6216\u5173\u8054\u5DF2\u6539\u53D8\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u3002"
21652
21957
  );
21653
- if (selection.expectedTimelineFingerprint) {
21958
+ if (request.operation === "duplicate" && selection.expectedTimelineFingerprint) {
21654
21959
  assert2(selection.timelineId, "INVALID_REQUEST", "\u65F6\u95F4\u7EBF\u6307\u7EB9\u7F3A\u5C11\u5BF9\u5E94\u5B9E\u4F8B\u3002");
21655
21960
  assert2(
21656
21961
  (await bridge.host.timeline(selection.scope, selection.timelineId)).fingerprint === selection.expectedTimelineFingerprint,
@@ -21674,7 +21979,7 @@ async function execute(request) {
21674
21979
  assert2(await realpath6(bridge.store.path(catalog.sources[binding.sourceId].locator)) === requestedProject, "VERSION_CONFLICT", "\u5173\u8054\u4E0D\u5C5E\u4E8E\u5F53\u524D Studio \u5DE5\u7A0B\u3002");
21675
21980
  }
21676
21981
  if (request.operation === "install-complete") return finishNativeInstall(request.configRoot);
21677
- if (request.operation === "sidebar-guide") return readSidebarGuide(request.componentRoot, input.inline === true);
21982
+ if (request.operation === "sidebar-guide") return readSidebarGuide(request.componentRoot, input.inline === true, bridgeLocale(input.locale));
21678
21983
  if (request.operation === "install") {
21679
21984
  assert2(!Object.values((await bridge.store.read()).jobs).some((job) => !terminalPhases.includes(job.phase)), "TASK_BUSY", "\u6865\u63A5\u4ECD\u6709\u4EFB\u52A1\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5B8C\u6210\u6216\u53D6\u6D88\u540E\u4FEE\u590D\u5B89\u88C5\u3002");
21680
21985
  return installNative({ cliPath: request.cliPath, componentRoot: request.componentRoot, configRoot: request.configRoot, workspace: request.workspace, requireComplete: true, activationToken: typeof input.activationToken === "string" ? input.activationToken : void 0 });
@@ -21689,10 +21994,17 @@ async function execute(request) {
21689
21994
  assert2(Object.hasOwn(schemas, name), "INVALID_REQUEST", "\u672A\u77E5\u4FEE\u6539\u64CD\u4F5C\u3002", { operations: Object.keys(schemas) });
21690
21995
  return { operation: name, cli: `mh bridge davinci ${name.startsWith("legacy-retire-") ? name.replaceAll("-", " ") : name.replace(/^(legacy|entry|action)-/, "$1 ")} --json <JSON>`, requestSchema: external_exports.toJSONSchema(schemas[name], { io: "input" }) };
21691
21996
  }
21692
- if (request.operation === "doctor") return bridge.capabilities();
21997
+ if (request.operation === "doctor") {
21998
+ if (input.repairConnection === true) {
21999
+ const connection = await repairNativeConnection(request);
22000
+ const native = await bridge.host.call("connection");
22001
+ return { ...connection, ...native };
22002
+ }
22003
+ return bridge.capabilities();
22004
+ }
21693
22005
  if (request.operation === "status") {
21694
22006
  const catalog = await bridge.store.read();
21695
- const projectPath = request.projectPath ? await realpath6(request.projectPath).catch(() => resolve10(request.projectPath)) : void 0;
22007
+ const projectPath = request.projectPath ? await realpath6(request.projectPath).catch(() => resolve11(request.projectPath)) : void 0;
21696
22008
  const sources = Object.values(catalog.sources).filter((source) => !projectPath || bridge.store.path(source.locator) === projectPath);
21697
22009
  const sourceIds = new Set(sources.map((source) => source.id));
21698
22010
  const bindings = Object.values(catalog.bindings).filter((binding) => sourceIds.has(binding.sourceId)).map((binding) => {
@@ -21711,7 +22023,7 @@ async function execute(request) {
21711
22023
  state: binding.state,
21712
22024
  name,
21713
22025
  outputSpec: spec,
21714
- lastKnownUsageCount: binding.lastReadback?.uses.length ?? null
22026
+ lastKnownUsageCount: binding.lastReadback?.usageScanComplete ? binding.lastReadback.uses.length : null
21715
22027
  };
21716
22028
  });
21717
22029
  const tasks = Object.values(catalog.jobs).filter((job) => {
@@ -21809,18 +22121,18 @@ async function execute(request) {
21809
22121
  const key = digest(sourceId).slice(7), marker = bridge.store.path(`.scratch/editor-${key}.json`);
21810
22122
  return bridge.store.withLock(`editor-${key}`, async () => {
21811
22123
  if (bindingId) {
21812
- await mkdir9(dirname9(marker), { recursive: true });
22124
+ await mkdir9(dirname10(marker), { recursive: true });
21813
22125
  await writeFile2(bridge.store.path(`.scratch/edit-context-${key}.json`), JSON.stringify({ bindingId, nonce: randomUUID8(), at: Date.now() }), { mode: 384 });
21814
22126
  }
21815
22127
  const previous2 = await readFile11(marker, "utf8").then(JSON.parse).catch(() => null);
21816
22128
  if (previous2?.at && Date.now() - previous2.at < 1500) return { opened: true, reused: true, sourceId };
21817
22129
  await bridge.openStudio(sourceId);
21818
- await mkdir9(dirname9(marker), { recursive: true });
22130
+ await mkdir9(dirname10(marker), { recursive: true });
21819
22131
  await writeFile2(marker, JSON.stringify({ at: Date.now() }), { mode: 384 });
21820
22132
  return { opened: true, sourceId };
21821
22133
  });
21822
22134
  }
21823
- if (request.operation === "entry-restore") throw new BridgeError("CAPABILITY_UNAVAILABLE", "\u8FBE\u82AC\u5947\u516C\u5F00\u63A5\u53E3\u5C1A\u4E0D\u652F\u6301\u81EA\u52A8\u91CD\u65B0\u9644\u52A0\u4FA7\u680F\u5165\u53E3\u3002\u5DE5\u7A0B\u5173\u8054\u4ECD\u4FDD\u7559\uFF0C\u53EF\u4ECE\u300C\u5DE5\u4F5C\u533A \u2192 \u811A\u672C \u2192 Utility \u2192 Hotion Harness\u300D\u7F16\u8F91\u6216\u66F4\u65B0\u3002", "entry", false, { automaticAttachment: false }, "\u4F7F\u7528\u56FA\u5B9A\u811A\u672C\u83DC\u5355\u7EE7\u7EED\u7F16\u8F91\u3002\u5B9E\u9A8C\u4FA7\u680F\u53EA\u53EF\u5728\u5BBF\u4E3B\u63D0\u4F9B\u6709\u6548\u6E90\u8DEF\u5F84\u5E76\u5B8C\u6210\u4E25\u683C\u8EAB\u4EFD\u6838\u5BF9\u65F6\u5904\u7406\u8BF7\u6C42\uFF0C\u81EA\u52A8\u9644\u52A0\u4ECD\u672A\u5F00\u653E\u3002");
22135
+ if (request.operation === "entry-restore") throw new BridgeError("CAPABILITY_UNAVAILABLE", "\u8FBE\u82AC\u5947\u516C\u5F00\u63A5\u53E3\u5C1A\u4E0D\u652F\u6301\u81EA\u52A8\u91CD\u65B0\u9644\u52A0\u4FA7\u680F\u5165\u53E3\u3002\u5DE5\u7A0B\u5173\u8054\u4ECD\u4FDD\u7559\uFF0C\u53EF\u4ECE\u300C\u5DE5\u4F5C\u533A \u2192 \u811A\u672C \u2192 Utility \u2192 MotionHarness \u6865\u63A5\u7EC4\u4EF6\u300D\u7F16\u8F91\u6216\u66F4\u65B0\u3002", "entry", false, { automaticAttachment: false }, "\u4F7F\u7528\u56FA\u5B9A\u811A\u672C\u83DC\u5355\u7EE7\u7EED\u7F16\u8F91\u3002\u5B9E\u9A8C\u4FA7\u680F\u53EA\u53EF\u5728\u5BBF\u4E3B\u63D0\u4F9B\u6709\u6548\u6E90\u8DEF\u5F84\u5E76\u5B8C\u6210\u4E25\u683C\u8EAB\u4EFD\u6838\u5BF9\u65F6\u5904\u7406\u8BF7\u6C42\uFF0C\u81EA\u52A8\u9644\u52A0\u4ECD\u672A\u5F00\u653E\u3002");
21824
22136
  if (request.operation === "relink") return bridge.relink(input);
21825
22137
  if (request.operation === "recover") {
21826
22138
  const checked = reconcileSchema.parse(input);
@@ -21839,7 +22151,7 @@ async function execute(request) {
21839
22151
  const payload = { ...input };
21840
22152
  if (operation === "send") {
21841
22153
  payload.projectPath ??= request.projectPath;
21842
- if (typeof payload.projectPath === "string") payload.projectPath = resolve10(payload.projectPath);
22154
+ if (typeof payload.projectPath === "string") payload.projectPath = resolve11(payload.projectPath);
21843
22155
  }
21844
22156
  if (operation === "update" && !payload.bindingId) {
21845
22157
  const selected = await bridge.selectedSource();
@@ -21864,7 +22176,7 @@ async function execute(request) {
21864
22176
  ...Array.isArray(value.targets) ? value.targets.map((target) => catalog.bindings[target.bindingId]?.sourceId) : []
21865
22177
  ].filter((value2) => Boolean(value2)));
21866
22178
  return /* @__PURE__ */ new Set([
21867
- ...typeof value.projectPath === "string" ? [resolve10(value.projectPath)] : [],
22179
+ ...typeof value.projectPath === "string" ? [resolve11(value.projectPath)] : [],
21868
22180
  ...[...sourceIds].map((sourceId) => catalog.sources[sourceId] ? bridge.store.path(catalog.sources[sourceId].locator) : `source:${sourceId}`)
21869
22181
  ]);
21870
22182
  };
@@ -21917,14 +22229,14 @@ function assertMigrationReady(blockers, old) {
21917
22229
  );
21918
22230
  }
21919
22231
  async function proposedWorkspaceRoot(path) {
21920
- let existing = resolve10(path);
22232
+ let existing = resolve11(path);
21921
22233
  const suffix = [];
21922
22234
  for (; ; ) {
21923
22235
  try {
21924
- return resolve10(await realpath6(existing), ...suffix);
22236
+ return resolve11(await realpath6(existing), ...suffix);
21925
22237
  } catch (error48) {
21926
22238
  if (error48.code !== "ENOENT") throw error48;
21927
- const parent = dirname9(existing);
22239
+ const parent = dirname10(existing);
21928
22240
  if (parent === existing) throw error48;
21929
22241
  suffix.unshift(basename5(existing));
21930
22242
  existing = parent;
@@ -21932,7 +22244,7 @@ async function proposedWorkspaceRoot(path) {
21932
22244
  }
21933
22245
  }
21934
22246
  function assertSeparateMigrationRoots(oldRoot, targetRoot) {
21935
- const prefix = (root) => root.endsWith(sep3) ? root : root + sep3;
22247
+ const prefix = (root) => root.endsWith(sep2) ? root : root + sep2;
21936
22248
  assert2(
21937
22249
  targetRoot !== oldRoot && !targetRoot.startsWith(prefix(oldRoot)) && !oldRoot.startsWith(prefix(targetRoot)),
21938
22250
  "INVALID_REQUEST",
@@ -21970,7 +22282,7 @@ async function withLegacyMigrationLocks(old, action2) {
21970
22282
  function legacyMcpGate() {
21971
22283
  const inspect = async (root) => {
21972
22284
  const old = new Store(root);
21973
- const locks = await stat8(old.path("locks"));
22285
+ const locks = await stat7(old.path("locks"));
21974
22286
  assert2(locks.isDirectory(), "LEGACY_LOCKS_MISSING", "\u65E7\u76EE\u5F55\u7F3A\u5C11\u534F\u4F5C\u9501\u76EE\u5F55\uFF0C\u672A\u9000\u5F79\u914D\u7F6E\u3002");
21975
22287
  const snapshot = await migrationSnapshot(old);
21976
22288
  assertMigrationReady(migrationTaskBlockers(snapshot.catalog), old);
@@ -21995,7 +22307,7 @@ async function migrate(bridge, input) {
21995
22307
  assertSeparateMigrationRoots(old.root, targetRoot);
21996
22308
  const snapshot = await migrationSnapshot(old), catalog = snapshot.catalog;
21997
22309
  const blockers = migrationTaskBlockers(catalog);
21998
- const locksDirectory = await stat8(old.path("locks")).catch((error48) => {
22310
+ const locksDirectory = await stat7(old.path("locks")).catch((error48) => {
21999
22311
  if (error48.code === "ENOENT") return void 0;
22000
22312
  throw error48;
22001
22313
  });
@@ -22065,14 +22377,14 @@ async function migrate(bridge, input) {
22065
22377
  const source = old.artifactPath(artifact.relativePath);
22066
22378
  assert2(await fileDigest(source) === artifact.sha256, "ARTIFACT_CHANGED", "\u65E7\u7248\u4E0D\u53EF\u53D8\u4EA7\u7269\u6821\u9A8C\u5931\u8D25\uFF0C\u539F\u6587\u4EF6\u672A\u6539\u53D8\u3002");
22067
22379
  const destination = bridge.store.artifactPath(artifact.relativePath);
22068
- await mkdir9(dirname9(destination), { recursive: true });
22380
+ await mkdir9(dirname10(destination), { recursive: true });
22069
22381
  try {
22070
22382
  await copyFile4(source, destination, 1);
22071
22383
  } catch (error48) {
22072
22384
  if (error48.code !== "EEXIST" || await fileDigest(destination) !== artifact.sha256) throw error48;
22073
22385
  }
22074
22386
  assert2(
22075
- (await stat8(destination)).size === artifact.bytes && await fileDigest(destination) === artifact.sha256,
22387
+ (await stat7(destination)).size === artifact.bytes && await fileDigest(destination) === artifact.sha256,
22076
22388
  "ARTIFACT_CHANGED",
22077
22389
  "\u8FC1\u79FB\u526F\u672C\u6821\u9A8C\u5931\u8D25\u3002"
22078
22390
  );
@@ -22145,7 +22457,7 @@ if (process.argv[2] === "--worker") {
22145
22457
  } finally {
22146
22458
  supervisor?.write(Buffer.from([0]));
22147
22459
  }
22148
- } else if (process.argv[1] && resolve10(process.argv[1]) === fileURLToPath2(import.meta.url)) {
22460
+ } else if (process.argv[1] && resolve11(process.argv[1]) === fileURLToPath2(import.meta.url)) {
22149
22461
  try {
22150
22462
  let text = "";
22151
22463
  for await (const chunk of process.stdin) {