@vibeframe/cli 0.106.4 → 0.106.6

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/index.js CHANGED
@@ -7844,7 +7844,7 @@ function errorMessage(error) {
7844
7844
  return error instanceof Error ? error.message : "Unknown error";
7845
7845
  }
7846
7846
  function sleep(ms) {
7847
- return new Promise((resolve81) => setTimeout(resolve81, ms));
7847
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
7848
7848
  }
7849
7849
  var ProviderHttpError;
7850
7850
  var init_http = __esm({
@@ -12238,7 +12238,7 @@ var init_RunwayProvider = __esm({
12238
12238
  * Sleep helper
12239
12239
  */
12240
12240
  sleep(ms) {
12241
- return new Promise((resolve81) => setTimeout(resolve81, ms));
12241
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
12242
12242
  }
12243
12243
  };
12244
12244
  RunwayProvider.API_VERSION = "2024-11-06";
@@ -12679,7 +12679,7 @@ var init_KlingProvider = __esm({
12679
12679
  * Sleep helper
12680
12680
  */
12681
12681
  sleep(ms) {
12682
- return new Promise((resolve81) => setTimeout(resolve81, ms));
12682
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
12683
12683
  }
12684
12684
  };
12685
12685
  klingProvider = new KlingProvider();
@@ -12997,7 +12997,7 @@ var init_GrokProvider = __esm({
12997
12997
  }
12998
12998
  }
12999
12999
  sleep(ms) {
13000
- return new Promise((resolve81) => setTimeout(resolve81, ms));
13000
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
13001
13001
  }
13002
13002
  };
13003
13003
  grokProvider = new GrokProvider();
@@ -13032,11 +13032,11 @@ var require_middleware = __commonJS({
13032
13032
  "use strict";
13033
13033
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
13034
13034
  function adopt(value) {
13035
- return value instanceof P ? value : new P(function(resolve81) {
13036
- resolve81(value);
13035
+ return value instanceof P ? value : new P(function(resolve83) {
13036
+ resolve83(value);
13037
13037
  });
13038
13038
  }
13039
- return new (P || (P = Promise))(function(resolve81, reject) {
13039
+ return new (P || (P = Promise))(function(resolve83, reject) {
13040
13040
  function fulfilled(value) {
13041
13041
  try {
13042
13042
  step(generator.next(value));
@@ -13052,7 +13052,7 @@ var require_middleware = __commonJS({
13052
13052
  }
13053
13053
  }
13054
13054
  function step(result) {
13055
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
13055
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
13056
13056
  }
13057
13057
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13058
13058
  });
@@ -13137,11 +13137,11 @@ var require_response = __commonJS({
13137
13137
  "use strict";
13138
13138
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
13139
13139
  function adopt(value) {
13140
- return value instanceof P ? value : new P(function(resolve81) {
13141
- resolve81(value);
13140
+ return value instanceof P ? value : new P(function(resolve83) {
13141
+ resolve83(value);
13142
13142
  });
13143
13143
  }
13144
- return new (P || (P = Promise))(function(resolve81, reject) {
13144
+ return new (P || (P = Promise))(function(resolve83, reject) {
13145
13145
  function fulfilled(value) {
13146
13146
  try {
13147
13147
  step(generator.next(value));
@@ -13157,7 +13157,7 @@ var require_response = __commonJS({
13157
13157
  }
13158
13158
  }
13159
13159
  function step(result) {
13160
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
13160
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
13161
13161
  }
13162
13162
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13163
13163
  });
@@ -13264,11 +13264,11 @@ var require_utils = __commonJS({
13264
13264
  "use strict";
13265
13265
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
13266
13266
  function adopt(value) {
13267
- return value instanceof P ? value : new P(function(resolve81) {
13268
- resolve81(value);
13267
+ return value instanceof P ? value : new P(function(resolve83) {
13268
+ resolve83(value);
13269
13269
  });
13270
13270
  }
13271
- return new (P || (P = Promise))(function(resolve81, reject) {
13271
+ return new (P || (P = Promise))(function(resolve83, reject) {
13272
13272
  function fulfilled(value) {
13273
13273
  try {
13274
13274
  step(generator.next(value));
@@ -13284,7 +13284,7 @@ var require_utils = __commonJS({
13284
13284
  }
13285
13285
  }
13286
13286
  function step(result) {
13287
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
13287
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
13288
13288
  }
13289
13289
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13290
13290
  });
@@ -13377,7 +13377,7 @@ var require_utils = __commonJS({
13377
13377
  }
13378
13378
  function sleep4(ms) {
13379
13379
  return __awaiter(this, void 0, void 0, function* () {
13380
- return new Promise((resolve81) => setTimeout(resolve81, ms));
13380
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
13381
13381
  });
13382
13382
  }
13383
13383
  }
@@ -13389,11 +13389,11 @@ var require_retry = __commonJS({
13389
13389
  "use strict";
13390
13390
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
13391
13391
  function adopt(value) {
13392
- return value instanceof P ? value : new P(function(resolve81) {
13393
- resolve81(value);
13392
+ return value instanceof P ? value : new P(function(resolve83) {
13393
+ resolve83(value);
13394
13394
  });
13395
13395
  }
13396
- return new (P || (P = Promise))(function(resolve81, reject) {
13396
+ return new (P || (P = Promise))(function(resolve83, reject) {
13397
13397
  function fulfilled(value) {
13398
13398
  try {
13399
13399
  step(generator.next(value));
@@ -13409,7 +13409,7 @@ var require_retry = __commonJS({
13409
13409
  }
13410
13410
  }
13411
13411
  function step(result) {
13412
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
13412
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
13413
13413
  }
13414
13414
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13415
13415
  });
@@ -13616,11 +13616,11 @@ var require_request = __commonJS({
13616
13616
  "use strict";
13617
13617
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
13618
13618
  function adopt(value) {
13619
- return value instanceof P ? value : new P(function(resolve81) {
13620
- resolve81(value);
13619
+ return value instanceof P ? value : new P(function(resolve83) {
13620
+ resolve83(value);
13621
13621
  });
13622
13622
  }
13623
- return new (P || (P = Promise))(function(resolve81, reject) {
13623
+ return new (P || (P = Promise))(function(resolve83, reject) {
13624
13624
  function fulfilled(value) {
13625
13625
  try {
13626
13626
  step(generator.next(value));
@@ -13636,7 +13636,7 @@ var require_request = __commonJS({
13636
13636
  }
13637
13637
  }
13638
13638
  function step(result) {
13639
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
13639
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
13640
13640
  }
13641
13641
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13642
13642
  });
@@ -13723,11 +13723,11 @@ var require_storage = __commonJS({
13723
13723
  "use strict";
13724
13724
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
13725
13725
  function adopt(value) {
13726
- return value instanceof P ? value : new P(function(resolve81) {
13727
- resolve81(value);
13726
+ return value instanceof P ? value : new P(function(resolve83) {
13727
+ resolve83(value);
13728
13728
  });
13729
13729
  }
13730
- return new (P || (P = Promise))(function(resolve81, reject) {
13730
+ return new (P || (P = Promise))(function(resolve83, reject) {
13731
13731
  function fulfilled(value) {
13732
13732
  try {
13733
13733
  step(generator.next(value));
@@ -13743,7 +13743,7 @@ var require_storage = __commonJS({
13743
13743
  }
13744
13744
  }
13745
13745
  function step(result) {
13746
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
13746
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
13747
13747
  }
13748
13748
  step((generator = generator.apply(thisArg, _arguments || [])).next());
13749
13749
  });
@@ -14071,11 +14071,11 @@ var require_auth = __commonJS({
14071
14071
  "use strict";
14072
14072
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
14073
14073
  function adopt(value) {
14074
- return value instanceof P ? value : new P(function(resolve81) {
14075
- resolve81(value);
14074
+ return value instanceof P ? value : new P(function(resolve83) {
14075
+ resolve83(value);
14076
14076
  });
14077
14077
  }
14078
- return new (P || (P = Promise))(function(resolve81, reject) {
14078
+ return new (P || (P = Promise))(function(resolve83, reject) {
14079
14079
  function fulfilled(value) {
14080
14080
  try {
14081
14081
  step(generator.next(value));
@@ -14091,7 +14091,7 @@ var require_auth = __commonJS({
14091
14091
  }
14092
14092
  }
14093
14093
  function step(result) {
14094
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
14094
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
14095
14095
  }
14096
14096
  step((generator = generator.apply(thisArg, _arguments || [])).next());
14097
14097
  });
@@ -14130,11 +14130,11 @@ var require_streaming = __commonJS({
14130
14130
  "use strict";
14131
14131
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
14132
14132
  function adopt(value) {
14133
- return value instanceof P ? value : new P(function(resolve81) {
14134
- resolve81(value);
14133
+ return value instanceof P ? value : new P(function(resolve83) {
14134
+ resolve83(value);
14135
14135
  });
14136
14136
  }
14137
- return new (P || (P = Promise))(function(resolve81, reject) {
14137
+ return new (P || (P = Promise))(function(resolve83, reject) {
14138
14138
  function fulfilled(value) {
14139
14139
  try {
14140
14140
  step(generator.next(value));
@@ -14150,7 +14150,7 @@ var require_streaming = __commonJS({
14150
14150
  }
14151
14151
  }
14152
14152
  function step(result) {
14153
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
14153
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
14154
14154
  }
14155
14155
  step((generator = generator.apply(thisArg, _arguments || [])).next());
14156
14156
  });
@@ -14383,7 +14383,7 @@ var require_streaming = __commonJS({
14383
14383
  query: options.queryParams
14384
14384
  });
14385
14385
  this.options = options;
14386
- this.donePromise = new Promise((resolve81, reject) => {
14386
+ this.donePromise = new Promise((resolve83, reject) => {
14387
14387
  if (this.streamClosed) {
14388
14388
  reject(new response_1.ApiError({
14389
14389
  message: "Streaming connection is already closed.",
@@ -14394,11 +14394,11 @@ var require_streaming = __commonJS({
14394
14394
  }
14395
14395
  this.signal.addEventListener("abort", () => {
14396
14396
  var _a2;
14397
- resolve81((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
14397
+ resolve83((_a2 = this.currentData) !== null && _a2 !== void 0 ? _a2 : {});
14398
14398
  });
14399
14399
  this.on("done", (data) => {
14400
14400
  this.streamClosed = true;
14401
- resolve81(data);
14401
+ resolve83(data);
14402
14402
  });
14403
14403
  this.on("error", (error) => {
14404
14404
  this.streamClosed = true;
@@ -14423,7 +14423,7 @@ var require_streaming = __commonJS({
14423
14423
  if (data) {
14424
14424
  yield yield __await(data);
14425
14425
  }
14426
- yield __await(new Promise((resolve81) => setTimeout(resolve81, 16)));
14426
+ yield __await(new Promise((resolve83) => setTimeout(resolve83, 16)));
14427
14427
  }
14428
14428
  });
14429
14429
  }
@@ -14468,11 +14468,11 @@ var require_queue = __commonJS({
14468
14468
  "use strict";
14469
14469
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
14470
14470
  function adopt(value) {
14471
- return value instanceof P ? value : new P(function(resolve81) {
14472
- resolve81(value);
14471
+ return value instanceof P ? value : new P(function(resolve83) {
14472
+ resolve83(value);
14473
14473
  });
14474
14474
  }
14475
- return new (P || (P = Promise))(function(resolve81, reject) {
14475
+ return new (P || (P = Promise))(function(resolve83, reject) {
14476
14476
  function fulfilled(value) {
14477
14477
  try {
14478
14478
  step(generator.next(value));
@@ -14488,7 +14488,7 @@ var require_queue = __commonJS({
14488
14488
  }
14489
14489
  }
14490
14490
  function step(result) {
14491
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
14491
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
14492
14492
  }
14493
14493
  step((generator = generator.apply(thisArg, _arguments || [])).next());
14494
14494
  });
@@ -14623,7 +14623,7 @@ var require_queue = __commonJS({
14623
14623
  }
14624
14624
  return doneStatus;
14625
14625
  }
14626
- return new Promise((resolve81, reject) => {
14626
+ return new Promise((resolve83, reject) => {
14627
14627
  var _a;
14628
14628
  let pollingTimeoutId;
14629
14629
  const pollInterval = "pollInterval" in options && typeof options.pollInterval === "number" ? (_a = options.pollInterval) !== null && _a !== void 0 ? _a : DEFAULT_POLL_INTERVAL : DEFAULT_POLL_INTERVAL;
@@ -14655,7 +14655,7 @@ var require_queue = __commonJS({
14655
14655
  }
14656
14656
  if (requestStatus.status === "COMPLETED") {
14657
14657
  clearScheduledTasks();
14658
- resolve81(requestStatus);
14658
+ resolve83(requestStatus);
14659
14659
  return;
14660
14660
  }
14661
14661
  pollingTimeoutId = setTimeout(poll, pollInterval);
@@ -16616,11 +16616,11 @@ var require_realtime = __commonJS({
16616
16616
  "use strict";
16617
16617
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
16618
16618
  function adopt(value) {
16619
- return value instanceof P ? value : new P(function(resolve81) {
16620
- resolve81(value);
16619
+ return value instanceof P ? value : new P(function(resolve83) {
16620
+ resolve83(value);
16621
16621
  });
16622
16622
  }
16623
- return new (P || (P = Promise))(function(resolve81, reject) {
16623
+ return new (P || (P = Promise))(function(resolve83, reject) {
16624
16624
  function fulfilled(value) {
16625
16625
  try {
16626
16626
  step(generator.next(value));
@@ -16636,7 +16636,7 @@ var require_realtime = __commonJS({
16636
16636
  }
16637
16637
  }
16638
16638
  function step(result) {
16639
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
16639
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
16640
16640
  }
16641
16641
  step((generator = generator.apply(thisArg, _arguments || [])).next());
16642
16642
  });
@@ -16961,11 +16961,11 @@ var require_client = __commonJS({
16961
16961
  "use strict";
16962
16962
  var __awaiter = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
16963
16963
  function adopt(value) {
16964
- return value instanceof P ? value : new P(function(resolve81) {
16965
- resolve81(value);
16964
+ return value instanceof P ? value : new P(function(resolve83) {
16965
+ resolve83(value);
16966
16966
  });
16967
16967
  }
16968
- return new (P || (P = Promise))(function(resolve81, reject) {
16968
+ return new (P || (P = Promise))(function(resolve83, reject) {
16969
16969
  function fulfilled(value) {
16970
16970
  try {
16971
16971
  step(generator.next(value));
@@ -16981,7 +16981,7 @@ var require_client = __commonJS({
16981
16981
  }
16982
16982
  }
16983
16983
  function step(result) {
16984
- result.done ? resolve81(result.value) : adopt(result.value).then(fulfilled, rejected);
16984
+ result.done ? resolve83(result.value) : adopt(result.value).then(fulfilled, rejected);
16985
16985
  }
16986
16986
  step((generator = generator.apply(thisArg, _arguments || [])).next());
16987
16987
  });
@@ -17666,7 +17666,7 @@ var init_ReplicateProvider = __esm({
17666
17666
  * Sleep helper
17667
17667
  */
17668
17668
  sleep(ms) {
17669
- return new Promise((resolve81) => setTimeout(resolve81, ms));
17669
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
17670
17670
  }
17671
17671
  /**
17672
17672
  * Generate music from text prompt using MusicGen
@@ -21601,7 +21601,7 @@ var require_timestamp2 = __commonJS({
21601
21601
  resolve: (str) => parseSexagesimal(str, false),
21602
21602
  stringify: stringifySexagesimal
21603
21603
  };
21604
- var timestamp = {
21604
+ var timestamp2 = {
21605
21605
  identify: (value) => value instanceof Date,
21606
21606
  default: true,
21607
21607
  tag: "tag:yaml.org,2002:timestamp",
@@ -21610,7 +21610,7 @@ var require_timestamp2 = __commonJS({
21610
21610
  // assumed to be 00:00:00Z (start of day, UTC).
21611
21611
  test: RegExp("^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})(?:(?:t|T|[ \\t]+)([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?)?$"),
21612
21612
  resolve(str) {
21613
- const match = str.match(timestamp.test);
21613
+ const match = str.match(timestamp2.test);
21614
21614
  if (!match)
21615
21615
  throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
21616
21616
  const [, year, month, day, hour, minute, second] = match.map(Number);
@@ -21629,7 +21629,7 @@ var require_timestamp2 = __commonJS({
21629
21629
  };
21630
21630
  exports.floatTime = floatTime;
21631
21631
  exports.intTime = intTime;
21632
- exports.timestamp = timestamp;
21632
+ exports.timestamp = timestamp2;
21633
21633
  }
21634
21634
  });
21635
21635
 
@@ -21649,7 +21649,7 @@ var require_schema3 = __commonJS({
21649
21649
  var omap = require_omap();
21650
21650
  var pairs = require_pairs();
21651
21651
  var set = require_set();
21652
- var timestamp = require_timestamp2();
21652
+ var timestamp2 = require_timestamp2();
21653
21653
  var schema = [
21654
21654
  map.map,
21655
21655
  seq.seq,
@@ -21669,9 +21669,9 @@ var require_schema3 = __commonJS({
21669
21669
  omap.omap,
21670
21670
  pairs.pairs,
21671
21671
  set.set,
21672
- timestamp.intTime,
21673
- timestamp.floatTime,
21674
- timestamp.timestamp
21672
+ timestamp2.intTime,
21673
+ timestamp2.floatTime,
21674
+ timestamp2.timestamp
21675
21675
  ];
21676
21676
  exports.schema = schema;
21677
21677
  }
@@ -21696,7 +21696,7 @@ var require_tags = __commonJS({
21696
21696
  var pairs = require_pairs();
21697
21697
  var schema$2 = require_schema3();
21698
21698
  var set = require_set();
21699
- var timestamp = require_timestamp2();
21699
+ var timestamp2 = require_timestamp2();
21700
21700
  var schemas = /* @__PURE__ */ new Map([
21701
21701
  ["core", schema.schema],
21702
21702
  ["failsafe", [map.map, seq.seq, string.string]],
@@ -21710,11 +21710,11 @@ var require_tags = __commonJS({
21710
21710
  float: float.float,
21711
21711
  floatExp: float.floatExp,
21712
21712
  floatNaN: float.floatNaN,
21713
- floatTime: timestamp.floatTime,
21713
+ floatTime: timestamp2.floatTime,
21714
21714
  int: int.int,
21715
21715
  intHex: int.intHex,
21716
21716
  intOct: int.intOct,
21717
- intTime: timestamp.intTime,
21717
+ intTime: timestamp2.intTime,
21718
21718
  map: map.map,
21719
21719
  merge: merge.merge,
21720
21720
  null: _null.nullTag,
@@ -21722,7 +21722,7 @@ var require_tags = __commonJS({
21722
21722
  pairs: pairs.pairs,
21723
21723
  seq: seq.seq,
21724
21724
  set: set.set,
21725
- timestamp: timestamp.timestamp
21725
+ timestamp: timestamp2.timestamp
21726
21726
  };
21727
21727
  var coreKnownTags = {
21728
21728
  "tag:yaml.org,2002:binary": binary.binary,
@@ -21730,7 +21730,7 @@ var require_tags = __commonJS({
21730
21730
  "tag:yaml.org,2002:omap": omap.omap,
21731
21731
  "tag:yaml.org,2002:pairs": pairs.pairs,
21732
21732
  "tag:yaml.org,2002:set": set.set,
21733
- "tag:yaml.org,2002:timestamp": timestamp.timestamp
21733
+ "tag:yaml.org,2002:timestamp": timestamp2.timestamp
21734
21734
  };
21735
21735
  function getTags(customTags, schemaName, addMergeTag) {
21736
21736
  const schemaTags = schemas.get(schemaName);
@@ -26132,7 +26132,7 @@ async function prompt(question, hidden = false) {
26132
26132
  input: process.stdin,
26133
26133
  output: process.stdout
26134
26134
  });
26135
- return new Promise((resolve81) => {
26135
+ return new Promise((resolve83) => {
26136
26136
  if (hidden && process.stdin.isTTY) {
26137
26137
  process.stdout.write(question);
26138
26138
  let input = "";
@@ -26146,7 +26146,7 @@ async function prompt(question, hidden = false) {
26146
26146
  process.stdin.removeListener("data", onData);
26147
26147
  process.stdout.write("\n");
26148
26148
  rl.close();
26149
- resolve81(input);
26149
+ resolve83(input);
26150
26150
  } else if (char === "") {
26151
26151
  process.exit(1);
26152
26152
  } else if (char === "\x7F" || char === "\b") {
@@ -26161,7 +26161,7 @@ async function prompt(question, hidden = false) {
26161
26161
  } else {
26162
26162
  rl.question(question, (answer) => {
26163
26163
  rl.close();
26164
- resolve81(answer);
26164
+ resolve83(answer);
26165
26165
  });
26166
26166
  }
26167
26167
  });
@@ -26758,6 +26758,18 @@ a host agent's built-in image/audio generation tool for VibeFrame project
26758
26758
  assets unless the user explicitly requests an external, non-VibeFrame
26759
26759
  asset.
26760
26760
 
26761
+ ## App host setup
26762
+
26763
+ VibeFrame is CLI-first, not terminal-only. Codex, Claude Code, and Cursor can
26764
+ drive this project through shell commands, and app hosts can use the MCP server
26765
+ as a typed tool surface.
26766
+
26767
+ \`\`\`bash
26768
+ vibe host setup all # print Codex/Claude/Cursor snippets
26769
+ vibe host setup all --write # write project/app config
26770
+ vibe host doctor all --json # verify readiness
26771
+ \`\`\`
26772
+
26761
26773
  ## Skills \u2014 USE THESE FIRST
26762
26774
 
26763
26775
  @SKILL.md
@@ -33269,16 +33281,16 @@ async function prompt2(question) {
33269
33281
  input,
33270
33282
  output: process.stdout
33271
33283
  });
33272
- return new Promise((resolve81) => {
33284
+ return new Promise((resolve83) => {
33273
33285
  rl.question(question, (answer) => {
33274
33286
  rl.close();
33275
- resolve81(answer);
33287
+ resolve83(answer);
33276
33288
  });
33277
33289
  });
33278
33290
  }
33279
33291
  async function promptHidden(question, opts = {}) {
33280
33292
  const input = getTTYInputStream();
33281
- return new Promise((resolve81) => {
33293
+ return new Promise((resolve83) => {
33282
33294
  let value = "";
33283
33295
  if (typeof input.setRawMode === "function") {
33284
33296
  input.setRawMode(true);
@@ -33292,7 +33304,7 @@ async function promptHidden(question, opts = {}) {
33292
33304
  input.setRawMode(false);
33293
33305
  input.removeListener("data", onData);
33294
33306
  process.stdout.write("\n");
33295
- resolve81(value);
33307
+ resolve83(value);
33296
33308
  } else if (char === "") {
33297
33309
  input.setRawMode(false);
33298
33310
  process.stdout.write("\n");
@@ -33318,7 +33330,7 @@ async function promptHidden(question, opts = {}) {
33318
33330
  const rl = createInterface2({ input, output: process.stdout });
33319
33331
  rl.question(question, (answer) => {
33320
33332
  rl.close();
33321
- resolve81(answer);
33333
+ resolve83(answer);
33322
33334
  });
33323
33335
  }
33324
33336
  });
@@ -33326,7 +33338,7 @@ async function promptHidden(question, opts = {}) {
33326
33338
  async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
33327
33339
  const input = getTTYInputStream();
33328
33340
  if (typeof input.setRawMode === "function") {
33329
- return new Promise((resolve81) => {
33341
+ return new Promise((resolve83) => {
33330
33342
  let selected = defaultIndex;
33331
33343
  const render = () => {
33332
33344
  if (renderCount > 0) {
@@ -33354,7 +33366,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
33354
33366
  input.setRawMode(false);
33355
33367
  input.removeListener("data", onData);
33356
33368
  process.stdout.write("\n");
33357
- resolve81(selected);
33369
+ resolve83(selected);
33358
33370
  } else if (char === "") {
33359
33371
  input.setRawMode(false);
33360
33372
  process.stdout.write("\n");
@@ -33364,7 +33376,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
33364
33376
  input.setRawMode(false);
33365
33377
  input.removeListener("data", onData);
33366
33378
  process.stdout.write("\n");
33367
- resolve81(opts.backIndex);
33379
+ resolve83(opts.backIndex);
33368
33380
  } else if (char === "\x1B[A" || char === "k") {
33369
33381
  selected = (selected - 1 + options.length) % options.length;
33370
33382
  render();
@@ -33378,7 +33390,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
33378
33390
  input.removeListener("data", onData);
33379
33391
  render();
33380
33392
  process.stdout.write("\n");
33381
- resolve81(selected);
33393
+ resolve83(selected);
33382
33394
  }
33383
33395
  };
33384
33396
  const onData = (chunk) => {
@@ -33402,7 +33414,7 @@ async function promptSelect(_question, options, defaultIndex = 0, opts = {}) {
33402
33414
  async function promptConfirm(question, defaultYes = true) {
33403
33415
  const input = getTTYInputStream();
33404
33416
  if (typeof input.setRawMode === "function") {
33405
- return new Promise((resolve81) => {
33417
+ return new Promise((resolve83) => {
33406
33418
  const options = ["Yes", "No"];
33407
33419
  let selected = defaultYes ? 0 : 1;
33408
33420
  let renderCount = 0;
@@ -33432,7 +33444,7 @@ async function promptConfirm(question, defaultYes = true) {
33432
33444
  finished = true;
33433
33445
  input.setRawMode(false);
33434
33446
  input.removeListener("data", onData);
33435
- resolve81(selected === 0);
33447
+ resolve83(selected === 0);
33436
33448
  } else if (char === "") {
33437
33449
  input.setRawMode(false);
33438
33450
  process.stdout.write("\n");
@@ -33446,14 +33458,14 @@ async function promptConfirm(question, defaultYes = true) {
33446
33458
  input.setRawMode(false);
33447
33459
  input.removeListener("data", onData);
33448
33460
  render();
33449
- resolve81(true);
33461
+ resolve83(true);
33450
33462
  } else if (char === "n" || char === "N") {
33451
33463
  selected = 1;
33452
33464
  finished = true;
33453
33465
  input.setRawMode(false);
33454
33466
  input.removeListener("data", onData);
33455
33467
  render();
33456
- resolve81(false);
33468
+ resolve83(false);
33457
33469
  }
33458
33470
  };
33459
33471
  const onData = (chunk) => {
@@ -33472,7 +33484,7 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
33472
33484
  const input = getTTYInputStream();
33473
33485
  const selected = options.map((_, i) => Boolean(defaultSelected[i]));
33474
33486
  if (typeof input.setRawMode === "function") {
33475
- return new Promise((resolve81) => {
33487
+ return new Promise((resolve83) => {
33476
33488
  let cursor = 0;
33477
33489
  let renderCount = 0;
33478
33490
  let userToggled = false;
@@ -33502,7 +33514,7 @@ async function promptMultiSelect(_question, options, defaultSelected = [], opts
33502
33514
  for (let i = 0; i < selected.length; i++) {
33503
33515
  if (selected[i]) result.push(i);
33504
33516
  }
33505
- resolve81(result);
33517
+ resolve83(result);
33506
33518
  };
33507
33519
  let finished = false;
33508
33520
  const handleChar = (char) => {
@@ -33816,7 +33828,7 @@ var init_speech = __esm({
33816
33828
  import { writeFile as writeFile19, unlink, rename } from "node:fs/promises";
33817
33829
  import { resolve as resolve22, basename as basename4 } from "node:path";
33818
33830
  function sleep2(ms) {
33819
- return new Promise((resolve81) => setTimeout(resolve81, ms));
33831
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
33820
33832
  }
33821
33833
  async function uploadToImgbb(imageBuffer, apiKey) {
33822
33834
  try {
@@ -35506,7 +35518,7 @@ function unique(items) {
35506
35518
  ];
35507
35519
  }
35508
35520
  function sleep3(ms) {
35509
- return new Promise((resolve81) => setTimeout(resolve81, ms));
35521
+ return new Promise((resolve83) => setTimeout(resolve83, ms));
35510
35522
  }
35511
35523
  var init_status_jobs = __esm({
35512
35524
  "src/commands/_shared/status-jobs.ts"() {
@@ -36015,20 +36027,20 @@ async function executeThumbnailBestFrame(options) {
36015
36027
  if (!jsonMatch) {
36016
36028
  return { success: false, error: `Could not parse timestamp from Gemini response: ${result.response.slice(0, 200)}` };
36017
36029
  }
36018
- const timestamp = parseFloat(jsonMatch[1]);
36030
+ const timestamp2 = parseFloat(jsonMatch[1]);
36019
36031
  let reason;
36020
36032
  const reasonMatch = result.response.match(/"reason"\s*:\s*"([^"]+)"/);
36021
36033
  if (reasonMatch) {
36022
36034
  reason = reasonMatch[1];
36023
36035
  }
36024
- await execSafe("ffmpeg", ["-ss", String(timestamp), "-i", videoPath, "-frames:v", "1", "-q:v", "2", outputPath, "-y"], { timeout: 6e4, maxBuffer: 50 * 1024 * 1024 });
36036
+ await execSafe("ffmpeg", ["-ss", String(timestamp2), "-i", videoPath, "-frames:v", "1", "-q:v", "2", outputPath, "-y"], { timeout: 6e4, maxBuffer: 50 * 1024 * 1024 });
36025
36037
  if (!existsSync16(outputPath)) {
36026
36038
  return { success: false, error: "FFmpeg failed to extract frame" };
36027
36039
  }
36028
36040
  return {
36029
36041
  success: true,
36030
36042
  outputPath,
36031
- timestamp,
36043
+ timestamp: timestamp2,
36032
36044
  reason
36033
36045
  };
36034
36046
  } catch (error) {
@@ -39557,8 +39569,8 @@ function parseSRT(content) {
39557
39569
  }
39558
39570
  return segments;
39559
39571
  }
39560
- function parseSRTTimestamp(timestamp) {
39561
- const normalized = timestamp.replace(",", ".");
39572
+ function parseSRTTimestamp(timestamp2) {
39573
+ const normalized = timestamp2.replace(",", ".");
39562
39574
  const parts = normalized.split(":");
39563
39575
  const hours = parseInt(parts[0], 10);
39564
39576
  const mins = parseInt(parts[1], 10);
@@ -47096,6 +47108,7 @@ var init_product_surface = __esm({
47096
47108
  build: { surface: "public", note: "Primary storyboard-to-video build engine." },
47097
47109
  render: { surface: "public", note: "Project render entrypoint." },
47098
47110
  doctor: { surface: "public", note: "System and provider health check." },
47111
+ host: { surface: "public", note: "Codex, Claude, and Cursor app integration setup." },
47099
47112
  guide: { surface: "public", note: "Workflow chooser and first-run guidance." },
47100
47113
  demo: { surface: "advanced", note: "Smoke-test/demo helper, not a core workflow." },
47101
47114
  run: { surface: "agent", note: "Automation surface for YAML pipelines." },
@@ -50855,11 +50868,11 @@ var init_FrameParser = __esm({
50855
50868
  const nullStr = _FrameParser.readNullTerminatedString(uint8Array, syltHeader.encoding);
50856
50869
  uint8Array = uint8Array.subarray(nullStr.len);
50857
50870
  if (readSyllables) {
50858
- const timestamp = UINT32_BE.get(uint8Array, 0);
50871
+ const timestamp2 = UINT32_BE.get(uint8Array, 0);
50859
50872
  uint8Array = uint8Array.subarray(UINT32_BE.len);
50860
50873
  result.syncText.push({
50861
50874
  text: nullStr.text,
50862
- timestamp
50875
+ timestamp: timestamp2
50863
50876
  });
50864
50877
  } else {
50865
50878
  result.descriptor = nullStr.text;
@@ -56854,8 +56867,8 @@ var init_detect = __esm({
56854
56867
  let match;
56855
56868
  scenes.push({ timestamp: 0, score: 1 });
56856
56869
  while ((match = regex2.exec(output)) !== null) {
56857
- const timestamp = parseFloat(match[1]);
56858
- scenes.push({ timestamp, score: threshold });
56870
+ const timestamp2 = parseFloat(match[1]);
56871
+ scenes.push({ timestamp: timestamp2, score: threshold });
56859
56872
  }
56860
56873
  const totalDuration = await ffprobeDuration(absPath);
56861
56874
  spinner2.succeed(source_default.green(`Detected ${scenes.length} scenes`));
@@ -58464,14 +58477,14 @@ var init_adapters = __esm({
58464
58477
  });
58465
58478
 
58466
58479
  // src/commands/_shared/storyboard-revise.ts
58467
- import { existsSync as existsSync41 } from "node:fs";
58468
- import { readFile as readFile38, writeFile as writeFile45 } from "node:fs/promises";
58469
- import { join as join19, resolve as resolve54 } from "node:path";
58480
+ import { existsSync as existsSync42 } from "node:fs";
58481
+ import { readFile as readFile39, writeFile as writeFile46 } from "node:fs/promises";
58482
+ import { join as join20, resolve as resolve55 } from "node:path";
58470
58483
  async function executeStoryboardRevision(opts) {
58471
- const projectDir = resolve54(opts.projectDir);
58472
- const storyboardPath2 = join19(projectDir, "STORYBOARD.md");
58484
+ const projectDir = resolve55(opts.projectDir);
58485
+ const storyboardPath2 = join20(projectDir, "STORYBOARD.md");
58473
58486
  const retryWith = [`vibe storyboard revise ${projectDir} --from "<request>" --dry-run --json`];
58474
- if (!existsSync41(storyboardPath2)) {
58487
+ if (!existsSync42(storyboardPath2)) {
58475
58488
  return failureResult({
58476
58489
  projectDir,
58477
58490
  storyboardPath: storyboardPath2,
@@ -58481,7 +58494,7 @@ async function executeStoryboardRevision(opts) {
58481
58494
  retryWith: [`vibe init ${projectDir} --from "<brief>" --json`]
58482
58495
  });
58483
58496
  }
58484
- const currentStoryboard = await readFile38(storyboardPath2, "utf-8");
58497
+ const currentStoryboard = await readFile39(storyboardPath2, "utf-8");
58485
58498
  const projectConfig = await readProjectConfig(projectDir);
58486
58499
  const explicitComposer = opts.composer ?? projectConfig.config.providers.composer ?? void 0;
58487
58500
  let provider = explicitComposer ?? "claude";
@@ -58580,7 +58593,7 @@ async function executeStoryboardRevision(opts) {
58580
58593
  }
58581
58594
  const storyboardMd = normalizeMarkdown(payload.storyboardMd);
58582
58595
  if (!opts.dryRun) {
58583
- await writeFile45(storyboardPath2, storyboardMd, "utf-8");
58596
+ await writeFile46(storyboardPath2, storyboardMd, "utf-8");
58584
58597
  }
58585
58598
  const changedBeats = unique2([...diffChangedBeats(currentStoryboard, storyboardMd), ...payload.changedBeats]);
58586
58599
  return stripUndefined3({
@@ -58703,18 +58716,18 @@ function diffChangedBeats(before, after) {
58703
58716
  return ids.filter((id) => JSON.stringify(beforeBeats.get(id) ?? null) !== JSON.stringify(afterBeats.get(id) ?? null));
58704
58717
  }
58705
58718
  async function readRevisionContext(projectDir) {
58706
- const designMd = await readOptionalText(join19(projectDir, "DESIGN.md"));
58707
- const buildReportJson = await readOptionalJsonText(join19(projectDir, "build-report.json"));
58719
+ const designMd = await readOptionalText(join20(projectDir, "DESIGN.md"));
58720
+ const buildReportJson = await readOptionalJsonText(join20(projectDir, "build-report.json"));
58708
58721
  return { designMd, buildReportJson };
58709
58722
  }
58710
58723
  async function readOptionalText(path2) {
58711
- if (!existsSync41(path2)) return null;
58712
- return readFile38(path2, "utf-8");
58724
+ if (!existsSync42(path2)) return null;
58725
+ return readFile39(path2, "utf-8");
58713
58726
  }
58714
58727
  async function readOptionalJsonText(path2) {
58715
- if (!existsSync41(path2)) return null;
58728
+ if (!existsSync42(path2)) return null;
58716
58729
  try {
58717
- const parsed = JSON.parse(await readFile38(path2, "utf-8"));
58730
+ const parsed = JSON.parse(await readFile39(path2, "utf-8"));
58718
58731
  return JSON.stringify(parsed, null, 2);
58719
58732
  } catch {
58720
58733
  return null;
@@ -58762,8 +58775,8 @@ var init_storyboard_revise = __esm({
58762
58775
  });
58763
58776
 
58764
58777
  // src/commands/_shared/build-asset-reference.ts
58765
- import { existsSync as existsSync43 } from "node:fs";
58766
- import { extname as extname13, isAbsolute as isAbsolute5, relative as relative10, resolve as resolve56, sep } from "node:path";
58778
+ import { existsSync as existsSync44 } from "node:fs";
58779
+ import { extname as extname13, isAbsolute as isAbsolute5, relative as relative10, resolve as resolve57, sep } from "node:path";
58767
58780
  function resolveTypedAssetReference(projectDir, kind, value) {
58768
58781
  const raw = stringOrUndefined2(value);
58769
58782
  if (!raw || !looksLikeAssetPath(raw)) return null;
@@ -58790,10 +58803,10 @@ function isReadyAssetReference(reference) {
58790
58803
  function resolveReference(projectDir, kind, raw, source, forcedError) {
58791
58804
  const ext = extname13(raw).toLowerCase();
58792
58805
  const inferred = inferAssetKind(raw);
58793
- const absPath = isAbsolute5(raw) ? resolve56(raw) : resolve56(projectDir, raw);
58794
- const rel = relative10(resolve56(projectDir), absPath);
58806
+ const absPath = isAbsolute5(raw) ? resolve57(raw) : resolve57(projectDir, raw);
58807
+ const rel = relative10(resolve57(projectDir), absPath);
58795
58808
  const withinProject = rel.length > 0 && !rel.startsWith("..") && !isAbsolute5(rel);
58796
- const exists = withinProject && existsSync43(absPath);
58809
+ const exists = withinProject && existsSync44(absPath);
58797
58810
  let error = forcedError;
58798
58811
  if (!error && inferred && inferred !== kind && !isNarrationAudioReference(kind, ext)) {
58799
58812
  error = `Asset reference "${raw}" is a ${inferred} asset, not ${kind}.`;
@@ -58952,19 +58965,19 @@ var init_build_backdrop_prompt = __esm({
58952
58965
  });
58953
58966
 
58954
58967
  // src/commands/_shared/build-plan.ts
58955
- import { existsSync as existsSync44 } from "node:fs";
58956
- import { readFile as readFile40 } from "node:fs/promises";
58957
- import { dirname as dirname19, join as join20, resolve as resolve57 } from "node:path";
58968
+ import { existsSync as existsSync45 } from "node:fs";
58969
+ import { readFile as readFile41 } from "node:fs/promises";
58970
+ import { dirname as dirname20, join as join21, resolve as resolve58 } from "node:path";
58958
58971
  async function createBuildPlan(opts) {
58959
- const projectDir = resolve57(opts.projectDir);
58972
+ const projectDir = resolve58(opts.projectDir);
58960
58973
  loadPlanEnv(projectDir);
58961
58974
  const stage = opts.stage ?? "all";
58962
58975
  const config2 = await readProjectConfig(projectDir);
58963
- const storyboardPath2 = join20(projectDir, "STORYBOARD.md");
58976
+ const storyboardPath2 = join21(projectDir, "STORYBOARD.md");
58964
58977
  const warnings = [];
58965
58978
  const retryWith = [];
58966
58979
  const providerResolution = [];
58967
- if (!existsSync44(storyboardPath2)) {
58980
+ if (!existsSync45(storyboardPath2)) {
58968
58981
  const validation2 = {
58969
58982
  ok: false,
58970
58983
  issues: [
@@ -58993,7 +59006,7 @@ async function createBuildPlan(opts) {
58993
59006
  validation: validation2
58994
59007
  });
58995
59008
  }
58996
- const storyboardMd = await readFile40(storyboardPath2, "utf-8");
59009
+ const storyboardMd = await readFile41(storyboardPath2, "utf-8");
58997
59010
  const validation = validateStoryboardMarkdown(storyboardMd);
58998
59011
  const validationIssues = [...validation.issues];
58999
59012
  const parsed = parseStoryboard(storyboardMd);
@@ -59019,7 +59032,7 @@ async function createBuildPlan(opts) {
59019
59032
  const imageQuality = opts.imageQuality ?? config2.config.build.imageQuality ?? "hd";
59020
59033
  const imageSize2 = opts.imageSize ?? config2.config.build.imageSize ?? "1536x1024";
59021
59034
  const imageRatio = imageRatioForSize(imageSize2);
59022
- const needsComposer = includeCompose && mode !== "agent" && sourceBeats.some((beat) => !existsSync44(join20(projectDir, `compositions/scene-${beat.id}.html`)));
59035
+ const needsComposer = includeCompose && mode !== "agent" && sourceBeats.some((beat) => !existsSync45(join21(projectDir, `compositions/scene-${beat.id}.html`)));
59023
59036
  const resolved = await resolvePlanProviders({
59024
59037
  projectDir,
59025
59038
  config: config2,
@@ -59140,7 +59153,7 @@ async function createBuildPlan(opts) {
59140
59153
  active: includeAssets
59141
59154
  }) : null;
59142
59155
  const compositionPath = `compositions/scene-${beat.id}.html`;
59143
- const compositionExists = existsSync44(join20(projectDir, compositionPath));
59156
+ const compositionExists = existsSync45(join21(projectDir, compositionPath));
59144
59157
  for (const asset of [narration, backdrop, video, music]) {
59145
59158
  if (!asset) continue;
59146
59159
  if (asset.referenceError) {
@@ -59207,7 +59220,7 @@ async function createBuildPlan(opts) {
59207
59220
  }
59208
59221
  }
59209
59222
  const validationOk = !validationIssues.some((issue) => issue.severity === "error");
59210
- if (!existsSync44(join20(projectDir, config2.config.composition.entry))) {
59223
+ if (!existsSync45(join21(projectDir, config2.config.composition.entry))) {
59211
59224
  missing.add("root-composition");
59212
59225
  if (validationOk) retryWith.push(`vibe build ${projectDir} --stage sync --json`);
59213
59226
  }
@@ -59339,8 +59352,8 @@ function assetPlan(opts) {
59339
59352
  reason: ready ? "referenced-asset" : "invalid-reference"
59340
59353
  };
59341
59354
  }
59342
- const canonicalExists = existsSync44(join20(opts.projectDir, opts.path));
59343
- const cacheHit = opts.cache ? existsSync44(join20(opts.projectDir, opts.cache.path)) : false;
59355
+ const canonicalExists = existsSync45(join21(opts.projectDir, opts.path));
59356
+ const cacheHit = opts.cache ? existsSync45(join21(opts.projectDir, opts.cache.path)) : false;
59344
59357
  const freshness = assetFreshnessFromMetadata({
59345
59358
  projectDir: opts.projectDir,
59346
59359
  kind: opts.kind,
@@ -59534,7 +59547,7 @@ async function firstConfiguredComposer(projectDir) {
59534
59547
  }
59535
59548
  function firstExisting2(projectDir, paths) {
59536
59549
  for (const path2 of paths) {
59537
- if (existsSync44(join20(projectDir, path2))) return path2;
59550
+ if (existsSync45(join21(projectDir, path2))) return path2;
59538
59551
  }
59539
59552
  return null;
59540
59553
  }
@@ -59575,15 +59588,15 @@ function unique3(items) {
59575
59588
  return [...new Set(items.filter((item) => item.length > 0))];
59576
59589
  }
59577
59590
  function loadPlanEnv(projectDir) {
59578
- (0, import_dotenv3.config)({ path: join20(projectDir, ".env"), quiet: true });
59579
- (0, import_dotenv3.config)({ path: resolve57(process.cwd(), ".env"), quiet: true });
59591
+ (0, import_dotenv3.config)({ path: join21(projectDir, ".env"), quiet: true });
59592
+ (0, import_dotenv3.config)({ path: resolve58(process.cwd(), ".env"), quiet: true });
59580
59593
  let dir = process.cwd();
59581
- while (dir !== dirname19(dir)) {
59582
- if (existsSync44(join20(dir, "pnpm-workspace.yaml"))) {
59583
- (0, import_dotenv3.config)({ path: join20(dir, ".env"), quiet: true });
59594
+ while (dir !== dirname20(dir)) {
59595
+ if (existsSync45(join21(dir, "pnpm-workspace.yaml"))) {
59596
+ (0, import_dotenv3.config)({ path: join21(dir, ".env"), quiet: true });
59584
59597
  return;
59585
59598
  }
59586
- dir = dirname19(dir);
59599
+ dir = dirname20(dir);
59587
59600
  }
59588
59601
  }
59589
59602
  var import_dotenv3, BACKDROP_COST_USD, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
@@ -59611,8 +59624,8 @@ var init_build_plan = __esm({
59611
59624
  });
59612
59625
 
59613
59626
  // src/commands/_shared/scene-audio-scan.ts
59614
- import { readFile as readFile41 } from "node:fs/promises";
59615
- import { resolve as resolve59 } from "node:path";
59627
+ import { readFile as readFile42 } from "node:fs/promises";
59628
+ import { resolve as resolve60 } from "node:path";
59616
59629
  function parseRootClips(rootHtml) {
59617
59630
  const clips = [];
59618
59631
  const clipRegex = /<div\b[^>]*class="clip"[^>]*>/gi;
@@ -59650,9 +59663,9 @@ function parseSceneAudios(compositionHtml) {
59650
59663
  }
59651
59664
  function makeFsCompositionReader(projectDir) {
59652
59665
  return async (compositionSrcRel) => {
59653
- const abs = resolve59(projectDir, compositionSrcRel);
59666
+ const abs = resolve60(projectDir, compositionSrcRel);
59654
59667
  try {
59655
- return await readFile41(abs, "utf-8");
59668
+ return await readFile42(abs, "utf-8");
59656
59669
  } catch {
59657
59670
  return null;
59658
59671
  }
@@ -59669,7 +59682,7 @@ async function scanSceneAudio(opts) {
59669
59682
  for (const audio of audios) {
59670
59683
  out.push({
59671
59684
  srcRel: audio.srcRel,
59672
- srcAbs: resolve59(opts.projectDir, audio.srcRel),
59685
+ srcAbs: resolve60(opts.projectDir, audio.srcRel),
59673
59686
  absoluteStart: clip.start + audio.localStart,
59674
59687
  durationHint: audio.durationHint,
59675
59688
  clipDurationCap: clip.duration - audio.localStart,
@@ -59684,7 +59697,7 @@ async function scanSceneAudio(opts) {
59684
59697
  for (const audio of rootAudios) {
59685
59698
  out.push({
59686
59699
  srcRel: audio.srcRel,
59687
- srcAbs: resolve59(opts.projectDir, audio.srcRel),
59700
+ srcAbs: resolve60(opts.projectDir, audio.srcRel),
59688
59701
  absoluteStart: audio.localStart,
59689
59702
  durationHint: audio.durationHint,
59690
59703
  clipDurationCap: Math.max(0, maxClipEnd - audio.localStart),
@@ -59719,7 +59732,7 @@ var init_scene_audio_scan = __esm({
59719
59732
 
59720
59733
  // src/commands/_shared/scene-audio-mux.ts
59721
59734
  import { rename as rename4, unlink as unlink3 } from "node:fs/promises";
59722
- import { resolve as resolve60, dirname as dirname20, extname as extname14, basename as basename20 } from "node:path";
59735
+ import { resolve as resolve61, dirname as dirname21, extname as extname14, basename as basename20 } from "node:path";
59723
59736
  function buildAudioMuxFilter(audios) {
59724
59737
  if (audios.length === 0) return null;
59725
59738
  const labels = [];
@@ -59779,8 +59792,8 @@ async function muxAudioIntoVideo(opts) {
59779
59792
  return { success: true, outputPath: opts.videoPath, audioCount: 0 };
59780
59793
  }
59781
59794
  const ext = extname14(opts.videoPath) || `.${opts.format}`;
59782
- const tmpPath = resolve60(
59783
- dirname20(opts.videoPath),
59795
+ const tmpPath = resolve61(
59796
+ dirname21(opts.videoPath),
59784
59797
  `.${basename20(opts.videoPath, ext)}.muxing${ext}`
59785
59798
  );
59786
59799
  const args = ["-y", "-loglevel", "error", "-i", opts.videoPath];
@@ -59850,9 +59863,9 @@ __export(scene_render_exports, {
59850
59863
  prepareBeatRenderRoot: () => prepareBeatRenderRoot,
59851
59864
  qualityToCrf: () => qualityToCrf2
59852
59865
  });
59853
- import { existsSync as existsSync45 } from "node:fs";
59854
- import { mkdir as mkdir23, readFile as readFile42, stat as stat8, writeFile as writeFile47 } from "node:fs/promises";
59855
- import { resolve as resolve61, relative as relative11, dirname as dirname21, basename as basename21, join as join21, isAbsolute as isAbsolute6 } from "node:path";
59866
+ import { existsSync as existsSync46 } from "node:fs";
59867
+ import { mkdir as mkdir24, readFile as readFile43, stat as stat8, writeFile as writeFile48 } from "node:fs/promises";
59868
+ import { resolve as resolve62, relative as relative11, dirname as dirname22, basename as basename21, join as join22, isAbsolute as isAbsolute6 } from "node:path";
59856
59869
  import {
59857
59870
  createRenderJob,
59858
59871
  executeRenderJob
@@ -59864,9 +59877,9 @@ function defaultOutputPath(opts) {
59864
59877
  const fmt = opts.format ?? "mp4";
59865
59878
  const now = opts.now ?? /* @__PURE__ */ new Date();
59866
59879
  const stamp = now.toISOString().replace(/[:T]/g, "-").replace(/\..+$/, "");
59867
- const name = (opts.projectName ?? basename21(resolve61(opts.projectDir))) || "scene";
59880
+ const name = (opts.projectName ?? basename21(resolve62(opts.projectDir))) || "scene";
59868
59881
  const beat = opts.beatId ? `-${sanitizeFileSegment2(opts.beatId)}` : "";
59869
- return resolve61(opts.projectDir, "renders", `${name}${beat}-${stamp}.${fmt}`);
59882
+ return resolve62(opts.projectDir, "renders", `${name}${beat}-${stamp}.${fmt}`);
59870
59883
  }
59871
59884
  function buildRenderConfig(opts) {
59872
59885
  const quality = opts.quality ?? "standard";
@@ -59880,7 +59893,7 @@ function buildRenderConfig(opts) {
59880
59893
  };
59881
59894
  }
59882
59895
  async function executeSceneRender(opts = {}) {
59883
- const projectDir = resolve61(opts.projectDir ?? ".");
59896
+ const projectDir = resolve62(opts.projectDir ?? ".");
59884
59897
  const projectConfig = await readProjectConfig(projectDir);
59885
59898
  const engine = projectConfig.config.composition.engine;
59886
59899
  if (engine !== "hyperframes") {
@@ -59926,7 +59939,7 @@ async function executeSceneRender(opts = {}) {
59926
59939
  kind: "render",
59927
59940
  beat: opts.beatId ?? null,
59928
59941
  root,
59929
- error: `Root composition not found: ${resolve61(projectDir, root)}. Run \`vibe scene init\` first.`
59942
+ error: `Root composition not found: ${resolve62(projectDir, root)}. Run \`vibe scene init\` first.`
59930
59943
  };
59931
59944
  }
59932
59945
  const chrome = await preflightChrome();
@@ -59940,8 +59953,8 @@ async function executeSceneRender(opts = {}) {
59940
59953
  };
59941
59954
  }
59942
59955
  const projectName = projectConfig.config.name;
59943
- const outputPath = opts.output ? resolve61(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
59944
- await mkdir23(dirname21(outputPath), { recursive: true });
59956
+ const outputPath = opts.output ? resolve62(projectDir, opts.output) : defaultOutputPath({ projectDir, projectName, format: opts.format, beatId: opts.beatId });
59957
+ await mkdir24(dirname22(outputPath), { recursive: true });
59945
59958
  const config2 = buildRenderConfig({
59946
59959
  fps: opts.fps,
59947
59960
  quality: opts.quality,
@@ -59973,7 +59986,7 @@ async function executeSceneRender(opts = {}) {
59973
59986
  let audioMuxWarning;
59974
59987
  try {
59975
59988
  opts.onProgress?.(0.95, "Mixing audio");
59976
- const rootHtml = await readFile42(resolve61(projectDir, root), "utf-8");
59989
+ const rootHtml = await readFile43(resolve62(projectDir, root), "utf-8");
59977
59990
  const audios = await scanSceneAudio({ projectDir, rootHtml });
59978
59991
  audioCount = audios.length;
59979
59992
  if (audios.length > 0) {
@@ -60027,11 +60040,11 @@ async function safeStat(p) {
60027
60040
  }
60028
60041
  async function prepareBeatRenderRoot(opts) {
60029
60042
  const root = `.vibeframe/tmp/render-beat-${sanitizeFileSegment2(opts.beatId)}.html`;
60030
- const reportPath = join21(opts.projectDir, "build-report.json");
60043
+ const reportPath = join22(opts.projectDir, "build-report.json");
60031
60044
  const retryWith = [
60032
60045
  `vibe build ${opts.projectDir} --beat ${opts.beatId} --stage sync --json`
60033
60046
  ];
60034
- if (!existsSync45(reportPath)) {
60047
+ if (!existsSync46(reportPath)) {
60035
60048
  return {
60036
60049
  success: false,
60037
60050
  root,
@@ -60042,7 +60055,7 @@ async function prepareBeatRenderRoot(opts) {
60042
60055
  }
60043
60056
  let report;
60044
60057
  try {
60045
- report = JSON.parse(await readFile42(reportPath, "utf-8"));
60058
+ report = JSON.parse(await readFile43(reportPath, "utf-8"));
60046
60059
  } catch (error) {
60047
60060
  return {
60048
60061
  success: false,
@@ -60111,8 +60124,8 @@ async function prepareBeatRenderRoot(opts) {
60111
60124
  durationSec,
60112
60125
  narrationPath
60113
60126
  });
60114
- await mkdir23(dirname21(join21(opts.projectDir, root)), { recursive: true });
60115
- await writeFile47(join21(opts.projectDir, root), html, "utf-8");
60127
+ await mkdir24(dirname22(join22(opts.projectDir, root)), { recursive: true });
60128
+ await writeFile48(join22(opts.projectDir, root), html, "utf-8");
60116
60129
  return {
60117
60130
  success: true,
60118
60131
  root,
@@ -60176,9 +60189,9 @@ function reportedBeatAssetPaths(beat) {
60176
60189
  ]);
60177
60190
  }
60178
60191
  async function writeRenderReport(projectDir, result) {
60179
- const reportPath = join21(projectDir, "render-report.json");
60192
+ const reportPath = join22(projectDir, "render-report.json");
60180
60193
  try {
60181
- await writeFile47(
60194
+ await writeFile48(
60182
60195
  reportPath,
60183
60196
  JSON.stringify(
60184
60197
  {
@@ -60210,8 +60223,8 @@ async function writeRenderReport(projectDir, result) {
60210
60223
  }
60211
60224
  }
60212
60225
  function pathExists3(projectDir, value) {
60213
- const abs = isAbsolute6(value) ? value : resolve61(projectDir, value);
60214
- return existsSync45(abs);
60226
+ const abs = isAbsolute6(value) ? value : resolve62(projectDir, value);
60227
+ return existsSync46(abs);
60215
60228
  }
60216
60229
  function stringValue(value) {
60217
60230
  return typeof value === "string" && value.length > 0 ? value : void 0;
@@ -60264,12 +60277,12 @@ __export(scene_build_exports, {
60264
60277
  executeSceneBuild: () => executeSceneBuild,
60265
60278
  resolveSceneBuildMode: () => resolveSceneBuildMode
60266
60279
  });
60267
- import { existsSync as existsSync46 } from "node:fs";
60268
- import { copyFile as copyFile5, mkdir as mkdir24, readFile as readFile43, writeFile as writeFile48 } from "node:fs/promises";
60269
- import { dirname as dirname22, join as join22, resolve as resolve62 } from "node:path";
60280
+ import { existsSync as existsSync47 } from "node:fs";
60281
+ import { copyFile as copyFile5, mkdir as mkdir25, readFile as readFile44, writeFile as writeFile49 } from "node:fs/promises";
60282
+ import { dirname as dirname23, join as join23, resolve as resolve63 } from "node:path";
60270
60283
  async function executeSceneBuild(opts) {
60271
60284
  const startedAt = Date.now();
60272
- const projectDir = resolve62(opts.projectDir);
60285
+ const projectDir = resolve63(opts.projectDir);
60273
60286
  const onProgress = opts.onProgress ?? (() => {
60274
60287
  });
60275
60288
  const mode = resolveSceneBuildMode(opts);
@@ -60278,7 +60291,7 @@ async function executeSceneBuild(opts) {
60278
60291
  const warnings = [];
60279
60292
  const retryWith = [];
60280
60293
  let sceneRepair = skippedSceneRepairSummary();
60281
- const storyboardPath2 = join22(projectDir, "STORYBOARD.md");
60294
+ const storyboardPath2 = join23(projectDir, "STORYBOARD.md");
60282
60295
  const buildPlan = await createBuildPlan({
60283
60296
  projectDir,
60284
60297
  stage: selectedStage,
@@ -60306,8 +60319,8 @@ async function executeSceneBuild(opts) {
60306
60319
  });
60307
60320
  if (!buildPlan.validation.ok) {
60308
60321
  let invalidBeats = [];
60309
- if (existsSync46(storyboardPath2)) {
60310
- invalidBeats = parseStoryboard(await readFile43(storyboardPath2, "utf-8")).beats;
60322
+ if (existsSync47(storyboardPath2)) {
60323
+ invalidBeats = parseStoryboard(await readFile44(storyboardPath2, "utf-8")).beats;
60311
60324
  }
60312
60325
  return finishBuildResult({
60313
60326
  success: false,
@@ -60331,7 +60344,7 @@ async function executeSceneBuild(opts) {
60331
60344
  totalLatencyMs: Date.now() - startedAt
60332
60345
  });
60333
60346
  }
60334
- if (!existsSync46(storyboardPath2)) {
60347
+ if (!existsSync47(storyboardPath2)) {
60335
60348
  return finishBuildResult({
60336
60349
  success: false,
60337
60350
  phase: "failed",
@@ -60345,7 +60358,7 @@ async function executeSceneBuild(opts) {
60345
60358
  totalLatencyMs: Date.now() - startedAt
60346
60359
  });
60347
60360
  }
60348
- const storyboardMd = await readFile43(storyboardPath2, "utf-8");
60361
+ const storyboardMd = await readFile44(storyboardPath2, "utf-8");
60349
60362
  const parsed = parseStoryboard(storyboardMd);
60350
60363
  if (parsed.beats.length === 0) {
60351
60364
  return finishBuildResult({
@@ -60513,9 +60526,9 @@ async function executeSceneBuild(opts) {
60513
60526
  let composeData;
60514
60527
  if (shouldRunStage(selectedStage, "compose")) {
60515
60528
  if (mode === "agent") {
60516
- const compositionsDir = join22(projectDir, "compositions");
60529
+ const compositionsDir = join23(projectDir, "compositions");
60517
60530
  const missingBeats = activeBeats.filter(
60518
- (b) => !existsSync46(join22(compositionsDir, `scene-${b.id}.html`))
60531
+ (b) => !existsSync47(join23(compositionsDir, `scene-${b.id}.html`))
60519
60532
  );
60520
60533
  if (missingBeats.length > 0) {
60521
60534
  const plan = await getComposePrompts({ projectDir, beatId: opts.beatId });
@@ -60651,7 +60664,7 @@ async function executeSceneBuild(opts) {
60651
60664
  });
60652
60665
  }
60653
60666
  if (shouldRunStage(selectedStage, "sync")) {
60654
- if (!existsSync46(join22(projectDir, "index.html"))) {
60667
+ if (!existsSync47(join23(projectDir, "index.html"))) {
60655
60668
  await scaffoldSceneProject({
60656
60669
  dir: projectDir,
60657
60670
  name: projectDir.split(/[\\/]/).filter(Boolean).pop(),
@@ -60910,7 +60923,7 @@ async function dispatchNarration(beat, ctx) {
60910
60923
  return {
60911
60924
  status: "cached",
60912
60925
  path: existingRel,
60913
- durationSec: await safeAudioDuration(join22(ctx.projectDir, existingRel)),
60926
+ durationSec: await safeAudioDuration(join23(ctx.projectDir, existingRel)),
60914
60927
  provider: metadata?.provider,
60915
60928
  cachePath: metadata?.cachePath,
60916
60929
  cacheKey: metadata?.cacheKey,
@@ -60934,9 +60947,9 @@ async function dispatchNarration(beat, ctx) {
60934
60947
  voice,
60935
60948
  ext: resolution.audioExtension
60936
60949
  });
60937
- const cacheAbs = join22(ctx.projectDir, cache.path);
60950
+ const cacheAbs = join23(ctx.projectDir, cache.path);
60938
60951
  const rel = `assets/narration-${beat.id}.${resolution.audioExtension}`;
60939
- const abs = join22(ctx.projectDir, rel);
60952
+ const abs = join23(ctx.projectDir, rel);
60940
60953
  if (existingRel && !ctx.force && isFreshCanonicalAsset({
60941
60954
  projectDir: ctx.projectDir,
60942
60955
  kind: "narration",
@@ -60950,7 +60963,7 @@ async function dispatchNarration(beat, ctx) {
60950
60963
  return {
60951
60964
  status: "cached",
60952
60965
  path: existingRel,
60953
- durationSec: await safeAudioDuration(join22(ctx.projectDir, existingRel)),
60966
+ durationSec: await safeAudioDuration(join23(ctx.projectDir, existingRel)),
60954
60967
  provider: resolution.provider,
60955
60968
  cachePath: cache.path,
60956
60969
  cacheKey: cache.key,
@@ -60958,8 +60971,8 @@ async function dispatchNarration(beat, ctx) {
60958
60971
  freshness: "fresh"
60959
60972
  };
60960
60973
  }
60961
- if (existsSync46(cacheAbs) && !ctx.force) {
60962
- await mkdir24(dirname22(abs), { recursive: true });
60974
+ if (existsSync47(cacheAbs) && !ctx.force) {
60975
+ await mkdir25(dirname23(abs), { recursive: true });
60963
60976
  await copyFile5(cacheAbs, abs);
60964
60977
  await writeAssetMetadata({
60965
60978
  projectDir: ctx.projectDir,
@@ -60990,10 +61003,10 @@ async function dispatchNarration(beat, ctx) {
60990
61003
  ctx.onProgress({ type: "narration-failed", beatId: beat.id, error });
60991
61004
  return { status: "failed", error };
60992
61005
  }
60993
- await mkdir24(dirname22(abs), { recursive: true });
60994
- await writeFile48(abs, result.audioBuffer);
60995
- await mkdir24(dirname22(cacheAbs), { recursive: true });
60996
- await writeFile48(cacheAbs, result.audioBuffer);
61006
+ await mkdir25(dirname23(abs), { recursive: true });
61007
+ await writeFile49(abs, result.audioBuffer);
61008
+ await mkdir25(dirname23(cacheAbs), { recursive: true });
61009
+ await writeFile49(cacheAbs, result.audioBuffer);
60997
61010
  await writeAssetMetadata({
60998
61011
  projectDir: ctx.projectDir,
60999
61012
  kind: "narration",
@@ -61029,7 +61042,7 @@ async function dispatchBackdrop(beat, ctx) {
61029
61042
  if (!cue) return { status: "no-cue" };
61030
61043
  const prompt3 = augmentBackdropPrompt(cue);
61031
61044
  const rel = `assets/backdrop-${beat.id}.png`;
61032
- const abs = join22(ctx.projectDir, rel);
61045
+ const abs = join23(ctx.projectDir, rel);
61033
61046
  const size = ctx.imageSize ?? "1536x1024";
61034
61047
  const ratio = imageRatioForSize(size);
61035
61048
  const metadataOptions = { quality: ctx.imageQuality, size, ratio };
@@ -61042,7 +61055,7 @@ async function dispatchBackdrop(beat, ctx) {
61042
61055
  ratio
61043
61056
  });
61044
61057
  const metadataPath = assetMetadataPath("backdrop", beat.id);
61045
- if (existsSync46(abs) && !ctx.force) {
61058
+ if (existsSync47(abs) && !ctx.force) {
61046
61059
  const metadata = readAssetMetadata(ctx.projectDir, "backdrop", beat.id);
61047
61060
  if (!metadata || isFreshCanonicalAsset({
61048
61061
  projectDir: ctx.projectDir,
@@ -61065,9 +61078,9 @@ async function dispatchBackdrop(beat, ctx) {
61065
61078
  };
61066
61079
  }
61067
61080
  }
61068
- const cacheAbs = join22(ctx.projectDir, cache.path);
61069
- if (existsSync46(cacheAbs) && !ctx.force) {
61070
- await mkdir24(dirname22(abs), { recursive: true });
61081
+ const cacheAbs = join23(ctx.projectDir, cache.path);
61082
+ if (existsSync47(cacheAbs) && !ctx.force) {
61083
+ await mkdir25(dirname23(abs), { recursive: true });
61071
61084
  await copyFile5(cacheAbs, abs);
61072
61085
  await writeAssetMetadata({
61073
61086
  projectDir: ctx.projectDir,
@@ -61097,11 +61110,11 @@ async function dispatchBackdrop(beat, ctx) {
61097
61110
  ctx.onProgress({ type: "backdrop-failed", beatId: beat.id, error });
61098
61111
  return { status: "failed", error };
61099
61112
  }
61100
- await mkdir24(dirname22(abs), { recursive: true });
61113
+ await mkdir25(dirname23(abs), { recursive: true });
61101
61114
  const buffer = generated.buffer;
61102
- await writeFile48(abs, buffer);
61103
- await mkdir24(dirname22(cacheAbs), { recursive: true });
61104
- await writeFile48(cacheAbs, buffer);
61115
+ await writeFile49(abs, buffer);
61116
+ await mkdir25(dirname23(cacheAbs), { recursive: true });
61117
+ await writeFile49(cacheAbs, buffer);
61105
61118
  await writeAssetMetadata({
61106
61119
  projectDir: ctx.projectDir,
61107
61120
  kind: "backdrop",
@@ -61192,7 +61205,7 @@ async function dispatchVideo(beat, ctx) {
61192
61205
  const prompt3 = stringOrUndefined4(beat.cues?.video);
61193
61206
  if (!prompt3) return { status: "no-cue" };
61194
61207
  const rel = `assets/video-${beat.id}.mp4`;
61195
- const abs = join22(ctx.projectDir, rel);
61208
+ const abs = join23(ctx.projectDir, rel);
61196
61209
  const cache = videoCacheDescriptor({
61197
61210
  beatId: beat.id,
61198
61211
  cue: prompt3,
@@ -61200,7 +61213,7 @@ async function dispatchVideo(beat, ctx) {
61200
61213
  duration: normalizeVideoDuration(beat.duration)
61201
61214
  });
61202
61215
  const metadataPath = assetMetadataPath("video", beat.id);
61203
- if (existsSync46(abs) && !ctx.force) {
61216
+ if (existsSync47(abs) && !ctx.force) {
61204
61217
  const metadata = readAssetMetadata(ctx.projectDir, "video", beat.id);
61205
61218
  if (!metadata || isFreshCanonicalAsset({
61206
61219
  projectDir: ctx.projectDir,
@@ -61223,9 +61236,9 @@ async function dispatchVideo(beat, ctx) {
61223
61236
  };
61224
61237
  }
61225
61238
  }
61226
- const cacheAbs = join22(ctx.projectDir, cache.path);
61227
- if (existsSync46(cacheAbs) && !ctx.force) {
61228
- await mkdir24(dirname22(abs), { recursive: true });
61239
+ const cacheAbs = join23(ctx.projectDir, cache.path);
61240
+ if (existsSync47(cacheAbs) && !ctx.force) {
61241
+ await mkdir25(dirname23(abs), { recursive: true });
61229
61242
  await copyFile5(cacheAbs, abs);
61230
61243
  await writeAssetMetadata({
61231
61244
  projectDir: ctx.projectDir,
@@ -61264,8 +61277,8 @@ async function dispatchVideo(beat, ctx) {
61264
61277
  ctx.onProgress({ type: "video-failed", beatId: beat.id, error });
61265
61278
  return { status: "failed", error };
61266
61279
  }
61267
- if (result.status === "completed" && existsSync46(abs)) {
61268
- await mkdir24(dirname22(cacheAbs), { recursive: true });
61280
+ if (result.status === "completed" && existsSync47(abs)) {
61281
+ await mkdir25(dirname23(cacheAbs), { recursive: true });
61269
61282
  await copyFile5(abs, cacheAbs);
61270
61283
  await writeAssetMetadata({
61271
61284
  projectDir: ctx.projectDir,
@@ -61332,7 +61345,7 @@ async function dispatchMusic(beat, ctx) {
61332
61345
  const prompt3 = stringOrUndefined4(beat.cues?.music);
61333
61346
  if (!prompt3) return { status: "no-cue" };
61334
61347
  const rel = `assets/music-${beat.id}.mp3`;
61335
- const abs = join22(ctx.projectDir, rel);
61348
+ const abs = join23(ctx.projectDir, rel);
61336
61349
  const duration = normalizeMusicDuration(beat.duration);
61337
61350
  const cache = musicCacheDescriptor({
61338
61351
  beatId: beat.id,
@@ -61341,7 +61354,7 @@ async function dispatchMusic(beat, ctx) {
61341
61354
  duration
61342
61355
  });
61343
61356
  const metadataPath = assetMetadataPath("music", beat.id);
61344
- if (existsSync46(abs) && !ctx.force) {
61357
+ if (existsSync47(abs) && !ctx.force) {
61345
61358
  const metadata = readAssetMetadata(ctx.projectDir, "music", beat.id);
61346
61359
  if (!metadata || isFreshCanonicalAsset({
61347
61360
  projectDir: ctx.projectDir,
@@ -61365,9 +61378,9 @@ async function dispatchMusic(beat, ctx) {
61365
61378
  };
61366
61379
  }
61367
61380
  }
61368
- const cacheAbs = join22(ctx.projectDir, cache.path);
61369
- if (existsSync46(cacheAbs) && !ctx.force) {
61370
- await mkdir24(dirname22(abs), { recursive: true });
61381
+ const cacheAbs = join23(ctx.projectDir, cache.path);
61382
+ if (existsSync47(cacheAbs) && !ctx.force) {
61383
+ await mkdir25(dirname23(abs), { recursive: true });
61371
61384
  await copyFile5(cacheAbs, abs);
61372
61385
  await writeAssetMetadata({
61373
61386
  projectDir: ctx.projectDir,
@@ -61440,12 +61453,12 @@ async function dispatchMusic(beat, ctx) {
61440
61453
  metadataPath
61441
61454
  };
61442
61455
  }
61443
- if (!existsSync46(abs)) {
61456
+ if (!existsSync47(abs)) {
61444
61457
  const error = result.outputPath ? `music output was not written at ${abs}` : "music generation did not return an output file";
61445
61458
  ctx.onProgress({ type: "music-failed", beatId: beat.id, error });
61446
61459
  return { status: "failed", error };
61447
61460
  }
61448
- await mkdir24(dirname22(cacheAbs), { recursive: true });
61461
+ await mkdir25(dirname23(cacheAbs), { recursive: true });
61449
61462
  await copyFile5(abs, cacheAbs);
61450
61463
  await writeAssetMetadata({
61451
61464
  projectDir: ctx.projectDir,
@@ -61476,15 +61489,15 @@ async function dispatchMusic(beat, ctx) {
61476
61489
  };
61477
61490
  }
61478
61491
  function loadSceneBuildEnv(projectDir) {
61479
- (0, import_dotenv4.config)({ path: join22(projectDir, ".env"), quiet: true });
61480
- (0, import_dotenv4.config)({ path: resolve62(process.cwd(), ".env"), quiet: true });
61492
+ (0, import_dotenv4.config)({ path: join23(projectDir, ".env"), quiet: true });
61493
+ (0, import_dotenv4.config)({ path: resolve63(process.cwd(), ".env"), quiet: true });
61481
61494
  let dir = process.cwd();
61482
- while (dir !== dirname22(dir)) {
61483
- if (existsSync46(join22(dir, "pnpm-workspace.yaml"))) {
61484
- (0, import_dotenv4.config)({ path: join22(dir, ".env"), quiet: true });
61495
+ while (dir !== dirname23(dir)) {
61496
+ if (existsSync47(join23(dir, "pnpm-workspace.yaml"))) {
61497
+ (0, import_dotenv4.config)({ path: join23(dir, ".env"), quiet: true });
61485
61498
  return;
61486
61499
  }
61487
- dir = dirname22(dir);
61500
+ dir = dirname23(dir);
61488
61501
  }
61489
61502
  }
61490
61503
  async function skipped(kind, beatId, reason, ctx) {
@@ -61690,7 +61703,7 @@ function mergeBeatOutcomes(base, updates) {
61690
61703
  }
61691
61704
  function firstExisting3(projectDir, relPaths) {
61692
61705
  for (const rel of relPaths) {
61693
- if (existsSync46(join22(projectDir, rel))) return rel;
61706
+ if (existsSync47(join23(projectDir, rel))) return rel;
61694
61707
  }
61695
61708
  return null;
61696
61709
  }
@@ -61721,7 +61734,7 @@ async function apiKeyForVideoProvider(provider, projectDir) {
61721
61734
  return getApiKeyFromConfig(providerKey, { cwd: projectDir });
61722
61735
  }
61723
61736
  async function finalizeBuildResult(projectDir, startedAt, result) {
61724
- const reportPath = join22(projectDir, "build-report.json");
61737
+ const reportPath = join23(projectDir, "build-report.json");
61725
61738
  if (result.stageReports) {
61726
61739
  for (const report of Object.values(result.stageReports)) {
61727
61740
  if (report.status === "pending") report.status = "skipped";
@@ -61737,7 +61750,7 @@ async function finalizeBuildResult(projectDir, startedAt, result) {
61737
61750
  totalLatencyMs: Date.now() - startedAt
61738
61751
  };
61739
61752
  try {
61740
- await writeFile48(
61753
+ await writeFile49(
61741
61754
  reportPath,
61742
61755
  JSON.stringify(toBuildReport(projectDir, withMeta), null, 2) + "\n",
61743
61756
  "utf-8"
@@ -61880,7 +61893,7 @@ function normalizeReportDuration(value) {
61880
61893
  }
61881
61894
  function buildReportComposition(projectDir, result, beatId) {
61882
61895
  const path2 = `compositions/scene-${beatId}.html`;
61883
- const exists = existsSync46(join22(projectDir, path2));
61896
+ const exists = existsSync47(join23(projectDir, path2));
61884
61897
  const written = composeWrittenEntry(result, beatId);
61885
61898
  if (written) {
61886
61899
  return {
@@ -61937,8 +61950,8 @@ function summarizeBuildBeats(projectDir, beats) {
61937
61950
  let compositionsReady = 0;
61938
61951
  for (const beat of beats) {
61939
61952
  if (beatAssetsReady(beat)) assetsReady += 1;
61940
- const compositionPath = join22(projectDir, "compositions", `scene-${beat.beatId}.html`);
61941
- if (existsSync46(compositionPath)) {
61953
+ const compositionPath = join23(projectDir, "compositions", `scene-${beat.beatId}.html`);
61954
+ if (existsSync47(compositionPath)) {
61942
61955
  compositionsReady += 1;
61943
61956
  } else {
61944
61957
  needsAuthor.push(beat.beatId);
@@ -61972,7 +61985,7 @@ async function resolveBeatDuration(opts) {
61972
61985
  const storyboardMin = opts.beatDuration ?? 3;
61973
61986
  if (!opts.narrationPath) return Number(storyboardMin.toFixed(2));
61974
61987
  try {
61975
- const audioDuration = await getAudioDuration(join22(opts.projectDir, opts.narrationPath));
61988
+ const audioDuration = await getAudioDuration(join23(opts.projectDir, opts.narrationPath));
61976
61989
  return Number(Math.max(storyboardMin, audioDuration + 0.5).toFixed(2));
61977
61990
  } catch {
61978
61991
  return Number(storyboardMin.toFixed(2));
@@ -62076,19 +62089,19 @@ __export(ai_audio_exports, {
62076
62089
  executeTranscribe: () => executeTranscribe,
62077
62090
  executeVoiceClone: () => executeVoiceClone
62078
62091
  });
62079
- import { resolve as resolve69, dirname as dirname24, basename as basename22, extname as extname15 } from "node:path";
62080
- import { readFile as readFile45, writeFile as writeFile49 } from "node:fs/promises";
62081
- import { existsSync as existsSync51 } from "node:fs";
62092
+ import { resolve as resolve71, dirname as dirname25, basename as basename22, extname as extname15 } from "node:path";
62093
+ import { readFile as readFile46, writeFile as writeFile50 } from "node:fs/promises";
62094
+ import { existsSync as existsSync52 } from "node:fs";
62082
62095
  async function executeTranscribe(options) {
62083
62096
  const { audioPath, language, output, format, apiKey } = options;
62084
62097
  try {
62085
62098
  const key = apiKey || process.env.OPENAI_API_KEY;
62086
62099
  if (!key) return { success: false, error: "OPENAI_API_KEY required" };
62087
- const absPath = resolve69(process.cwd(), audioPath);
62088
- if (!existsSync51(absPath)) return { success: false, error: `File not found: ${absPath}` };
62100
+ const absPath = resolve71(process.cwd(), audioPath);
62101
+ if (!existsSync52(absPath)) return { success: false, error: `File not found: ${absPath}` };
62089
62102
  const whisper = new WhisperProvider();
62090
62103
  await whisper.initialize({ apiKey: key });
62091
- const audioBuffer = await readFile45(absPath);
62104
+ const audioBuffer = await readFile46(absPath);
62092
62105
  const audioBlob = new Blob([audioBuffer]);
62093
62106
  const result = await whisper.transcribe(audioBlob, language);
62094
62107
  if (result.status === "failed") {
@@ -62096,10 +62109,10 @@ async function executeTranscribe(options) {
62096
62109
  }
62097
62110
  let outputPath;
62098
62111
  if (output) {
62099
- outputPath = resolve69(process.cwd(), output);
62112
+ outputPath = resolve71(process.cwd(), output);
62100
62113
  const fmt = detectFormat(output, format);
62101
62114
  const content = formatTranscript(result, fmt);
62102
- await writeFile49(outputPath, content, "utf-8");
62115
+ await writeFile50(outputPath, content, "utf-8");
62103
62116
  }
62104
62117
  return {
62105
62118
  success: true,
@@ -62117,17 +62130,17 @@ async function executeIsolate(options) {
62117
62130
  try {
62118
62131
  const key = apiKey || process.env.ELEVENLABS_API_KEY;
62119
62132
  if (!key) return { success: false, error: "ELEVENLABS_API_KEY required" };
62120
- const absPath = resolve69(process.cwd(), audioPath);
62121
- if (!existsSync51(absPath)) return { success: false, error: `File not found: ${absPath}` };
62122
- const audioBuffer = await readFile45(absPath);
62133
+ const absPath = resolve71(process.cwd(), audioPath);
62134
+ if (!existsSync52(absPath)) return { success: false, error: `File not found: ${absPath}` };
62135
+ const audioBuffer = await readFile46(absPath);
62123
62136
  const elevenlabs = new ElevenLabsProvider();
62124
62137
  await elevenlabs.initialize({ apiKey: key });
62125
62138
  const result = await elevenlabs.isolateVocals(audioBuffer);
62126
62139
  if (!result.success || !result.audioBuffer) {
62127
62140
  return { success: false, error: result.error || "Audio isolation failed" };
62128
62141
  }
62129
- const outputPath = resolve69(process.cwd(), output);
62130
- await writeFile49(outputPath, result.audioBuffer);
62142
+ const outputPath = resolve71(process.cwd(), output);
62143
+ await writeFile50(outputPath, result.audioBuffer);
62131
62144
  return { success: true, outputPath };
62132
62145
  } catch (error) {
62133
62146
  return { success: false, error: `Audio isolation failed: ${error instanceof Error ? error.message : String(error)}` };
@@ -62143,9 +62156,9 @@ async function executeVoiceClone(options) {
62143
62156
  }
62144
62157
  const audioBuffers = [];
62145
62158
  for (const samplePath of samplePaths) {
62146
- const absPath = resolve69(process.cwd(), samplePath);
62147
- if (!existsSync51(absPath)) return { success: false, error: `File not found: ${samplePath}` };
62148
- const buffer = await readFile45(absPath);
62159
+ const absPath = resolve71(process.cwd(), samplePath);
62160
+ if (!existsSync52(absPath)) return { success: false, error: `File not found: ${samplePath}` };
62161
+ const buffer = await readFile46(absPath);
62149
62162
  audioBuffers.push(buffer);
62150
62163
  }
62151
62164
  const elevenlabs = new ElevenLabsProvider();
@@ -62165,8 +62178,8 @@ async function executeVoiceClone(options) {
62165
62178
  async function executeDub(options) {
62166
62179
  const { mediaPath, language, source, voice, analyzeOnly, output } = options;
62167
62180
  try {
62168
- const absPath = resolve69(process.cwd(), mediaPath);
62169
- if (!existsSync51(absPath)) return { success: false, error: `File not found: ${absPath}` };
62181
+ const absPath = resolve71(process.cwd(), mediaPath);
62182
+ if (!existsSync52(absPath)) return { success: false, error: `File not found: ${absPath}` };
62170
62183
  const openaiKey = process.env.OPENAI_API_KEY;
62171
62184
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
62172
62185
  const elevenlabsKey = process.env.ELEVENLABS_API_KEY;
@@ -62177,13 +62190,13 @@ async function executeDub(options) {
62177
62190
  const isVideo = [".mp4", ".mov", ".avi", ".mkv", ".webm"].includes(ext);
62178
62191
  let audioPath = absPath;
62179
62192
  if (isVideo) {
62180
- const tempAudioPath = resolve69(dirname24(absPath), `temp-audio-${Date.now()}.mp3`);
62193
+ const tempAudioPath = resolve71(dirname25(absPath), `temp-audio-${Date.now()}.mp3`);
62181
62194
  execSafeSync("ffmpeg", ["-i", absPath, "-vn", "-acodec", "mp3", "-y", tempAudioPath]);
62182
62195
  audioPath = tempAudioPath;
62183
62196
  }
62184
62197
  const whisper = new WhisperProvider();
62185
62198
  await whisper.initialize({ apiKey: openaiKey });
62186
- const audioBuffer = await readFile45(audioPath);
62199
+ const audioBuffer = await readFile46(audioPath);
62187
62200
  const audioBlob = new Blob([audioBuffer]);
62188
62201
  const transcriptResult = await whisper.transcribe(audioBlob, source);
62189
62202
  if (transcriptResult.status === "failed" || !transcriptResult.segments) {
@@ -62226,7 +62239,7 @@ ${segmentTexts}`,
62226
62239
  }
62227
62240
  if (analyzeOnly) {
62228
62241
  if (output) {
62229
- const timingPath = resolve69(process.cwd(), output);
62242
+ const timingPath = resolve71(process.cwd(), output);
62230
62243
  const timingData = {
62231
62244
  sourcePath: absPath,
62232
62245
  sourceLanguage: transcriptResult.detectedLanguage || source || "auto",
@@ -62238,14 +62251,14 @@ ${segmentTexts}`,
62238
62251
  translated: translatedSegments[i]?.text || s.text
62239
62252
  }))
62240
62253
  };
62241
- await writeFile49(timingPath, JSON.stringify(timingData, null, 2));
62254
+ await writeFile50(timingPath, JSON.stringify(timingData, null, 2));
62242
62255
  }
62243
62256
  return {
62244
62257
  success: true,
62245
62258
  sourceLanguage: transcriptResult.detectedLanguage || source || "auto",
62246
62259
  targetLanguage: language,
62247
62260
  segmentCount: segments.length,
62248
- outputPath: output ? resolve69(process.cwd(), output) : void 0
62261
+ outputPath: output ? resolve71(process.cwd(), output) : void 0
62249
62262
  };
62250
62263
  }
62251
62264
  const elevenlabs = new ElevenLabsProvider();
@@ -62259,9 +62272,9 @@ ${segmentTexts}`,
62259
62272
  }
62260
62273
  const combinedBuffer = Buffer.concat(dubbedBuffers);
62261
62274
  const outputExt = isVideo ? ".mp3" : extname15(absPath);
62262
- const defaultOutputPath2 = resolve69(dirname24(absPath), `${basename22(absPath, extname15(absPath))}-${language}${outputExt}`);
62263
- const finalOutputPath = resolve69(process.cwd(), output || defaultOutputPath2);
62264
- await writeFile49(finalOutputPath, combinedBuffer);
62275
+ const defaultOutputPath2 = resolve71(dirname25(absPath), `${basename22(absPath, extname15(absPath))}-${language}${outputExt}`);
62276
+ const finalOutputPath = resolve71(process.cwd(), output || defaultOutputPath2);
62277
+ await writeFile50(finalOutputPath, combinedBuffer);
62265
62278
  if (isVideo && audioPath !== absPath) {
62266
62279
  try {
62267
62280
  const { unlink: unlink5 } = await import("node:fs/promises");
@@ -62292,12 +62305,12 @@ async function executeDuck(options) {
62292
62305
  } = options;
62293
62306
  try {
62294
62307
  if (!commandExists("ffmpeg")) return { success: false, error: "FFmpeg not found" };
62295
- const absMusicPath = resolve69(process.cwd(), musicPath);
62296
- const absVoicePath = resolve69(process.cwd(), voicePath);
62297
- if (!existsSync51(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
62298
- if (!existsSync51(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
62299
- const defaultOutput = resolve69(dirname24(absMusicPath), `${basename22(absMusicPath, extname15(absMusicPath))}-ducked${extname15(absMusicPath)}`);
62300
- const outputPath = resolve69(process.cwd(), output || defaultOutput);
62308
+ const absMusicPath = resolve71(process.cwd(), musicPath);
62309
+ const absVoicePath = resolve71(process.cwd(), voicePath);
62310
+ if (!existsSync52(absMusicPath)) return { success: false, error: `Music file not found: ${absMusicPath}` };
62311
+ if (!existsSync52(absVoicePath)) return { success: false, error: `Voice file not found: ${absVoicePath}` };
62312
+ const defaultOutput = resolve71(dirname25(absMusicPath), `${basename22(absMusicPath, extname15(absMusicPath))}-ducked${extname15(absMusicPath)}`);
62313
+ const outputPath = resolve71(process.cwd(), output || defaultOutput);
62301
62314
  const filter = `[1:a]asplit=2[sc][mix];[0:a][sc]sidechaincompress=threshold=${threshold}dB:ratio=${ratio}:attack=${attack}:release=${release}[ducked];[ducked][mix]amix=inputs=2:duration=longest`;
62302
62315
  await execSafe("ffmpeg", [
62303
62316
  "-i",
@@ -62309,7 +62322,7 @@ async function executeDuck(options) {
62309
62322
  "-y",
62310
62323
  outputPath
62311
62324
  ], { timeout: 12e4, maxBuffer: 50 * 1024 * 1024 });
62312
- if (!existsSync51(outputPath)) return { success: false, error: "FFmpeg failed to create output" };
62325
+ if (!existsSync52(outputPath)) return { success: false, error: "FFmpeg failed to create output" };
62313
62326
  return { success: true, outputPath };
62314
62327
  } catch (error) {
62315
62328
  return { success: false, error: `Audio ducking failed: ${error instanceof Error ? error.message : String(error)}` };
@@ -62325,9 +62338,9 @@ var init_ai_audio = __esm({
62325
62338
  });
62326
62339
 
62327
62340
  // src/pipeline/executor.ts
62328
- import { resolve as resolve70 } from "node:path";
62329
- import { readFile as readFile46, writeFile as writeFile50, mkdir as mkdir26 } from "node:fs/promises";
62330
- import { existsSync as existsSync52 } from "node:fs";
62341
+ import { resolve as resolve72 } from "node:path";
62342
+ import { readFile as readFile47, writeFile as writeFile51, mkdir as mkdir27 } from "node:fs/promises";
62343
+ import { existsSync as existsSync53 } from "node:fs";
62331
62344
  function maxCostFor(action) {
62332
62345
  const cmd = ACTION_METADATA[action]?.command;
62333
62346
  if (!cmd) return 0;
@@ -62338,9 +62351,9 @@ function registerAction(action, handler) {
62338
62351
  }
62339
62352
  function getOutput(params, outputDir, defaultName) {
62340
62353
  if (params.output && typeof params.output === "string") {
62341
- return resolve70(outputDir, params.output);
62354
+ return resolve72(outputDir, params.output);
62342
62355
  }
62343
- return resolve70(outputDir, defaultName);
62356
+ return resolve72(outputDir, defaultName);
62344
62357
  }
62345
62358
  function stringParam(value) {
62346
62359
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
@@ -62591,7 +62604,7 @@ async function ensureActionsRegistered() {
62591
62604
  const { executeSceneBuild: executeSceneBuild2 } = await Promise.resolve().then(() => (init_scene_build(), scene_build_exports));
62592
62605
  const projectRel = params.project ?? ".";
62593
62606
  const r = await executeSceneBuild2({
62594
- projectDir: resolve70(outputDir, projectRel),
62607
+ projectDir: resolve72(outputDir, projectRel),
62595
62608
  mode: params.mode,
62596
62609
  effort: params.effort,
62597
62610
  composer: params.composer,
@@ -62617,7 +62630,7 @@ async function ensureActionsRegistered() {
62617
62630
  const { executeSceneRender: executeSceneRender2 } = await Promise.resolve().then(() => (init_scene_render(), scene_render_exports));
62618
62631
  const projectRel = params.project ?? ".";
62619
62632
  const r = await executeSceneRender2({
62620
- projectDir: resolve70(outputDir, projectRel),
62633
+ projectDir: resolve72(outputDir, projectRel),
62621
62634
  root: params.root,
62622
62635
  output: params.output,
62623
62636
  fps: params.fps,
@@ -62641,11 +62654,11 @@ async function ensureActionsRegistered() {
62641
62654
  });
62642
62655
  }
62643
62656
  async function loadPipeline(filePath) {
62644
- const absPath = resolve70(process.cwd(), filePath);
62645
- if (!existsSync52(absPath)) {
62657
+ const absPath = resolve72(process.cwd(), filePath);
62658
+ if (!existsSync53(absPath)) {
62646
62659
  throw new Error(`Pipeline file not found: ${absPath}`);
62647
62660
  }
62648
- const content = await readFile46(absPath, "utf-8");
62661
+ const content = await readFile47(absPath, "utf-8");
62649
62662
  const manifest2 = (0, import_yaml8.parse)(content);
62650
62663
  if (!manifest2.name) throw new Error("Pipeline missing 'name' field");
62651
62664
  if (!manifest2.steps || !Array.isArray(manifest2.steps)) throw new Error("Pipeline missing 'steps' array");
@@ -62660,15 +62673,15 @@ async function loadPipeline(filePath) {
62660
62673
  }
62661
62674
  async function executePipeline(manifest2, options = {}) {
62662
62675
  await ensureActionsRegistered();
62663
- const outputDir = resolve70(process.cwd(), options.outputDir || `${manifest2.name}-output`);
62664
- await mkdir26(outputDir, { recursive: true });
62676
+ const outputDir = resolve72(process.cwd(), options.outputDir || `${manifest2.name}-output`);
62677
+ await mkdir27(outputDir, { recursive: true });
62665
62678
  const completedSteps = /* @__PURE__ */ new Map();
62666
62679
  const results = [];
62667
62680
  const startTime = Date.now();
62668
62681
  if (options.resume) {
62669
- const checkpointPath = resolve70(outputDir, CHECKPOINT_FILE);
62670
- if (existsSync52(checkpointPath)) {
62671
- const checkpointContent = await readFile46(checkpointPath, "utf-8");
62682
+ const checkpointPath = resolve72(outputDir, CHECKPOINT_FILE);
62683
+ if (existsSync53(checkpointPath)) {
62684
+ const checkpointContent = await readFile47(checkpointPath, "utf-8");
62672
62685
  const checkpoint = (0, import_yaml8.parse)(checkpointContent);
62673
62686
  for (const cs of checkpoint.completedSteps) {
62674
62687
  completedSteps.set(cs.id, {
@@ -62786,8 +62799,8 @@ async function executePipeline(manifest2, options = {}) {
62786
62799
  data: s.data
62787
62800
  }))
62788
62801
  };
62789
- await writeFile50(
62790
- resolve70(outputDir, CHECKPOINT_FILE),
62802
+ await writeFile51(
62803
+ resolve72(outputDir, CHECKPOINT_FILE),
62791
62804
  (0, import_yaml8.stringify)(checkpoint, { indent: 2 }),
62792
62805
  "utf-8"
62793
62806
  );
@@ -67041,7 +67054,7 @@ var init_define_tool = __esm({
67041
67054
  });
67042
67055
 
67043
67056
  // src/tools/manifest/scene.ts
67044
- import { resolve as resolve71, relative as relative12 } from "node:path";
67057
+ import { resolve as resolve73, relative as relative12 } from "node:path";
67045
67058
  function summariseLint(result) {
67046
67059
  return {
67047
67060
  ok: result.ok,
@@ -67063,7 +67076,7 @@ function summariseLint(result) {
67063
67076
  fixed: result.fixed
67064
67077
  };
67065
67078
  }
67066
- var SCENE_PRESETS2, sceneStylesSchema, sceneStylesTool, sceneInitSchema, sceneInitTool, sceneAddSchema, sceneAddTool, sceneLintSchema, sceneLintTool, sceneRepairSchema, sceneRepairTool, sceneRenderSchema, sceneRenderTool, sceneBuildSchema, sceneBuildTool, sceneInstallSkillSchema, sceneInstallSkillTool, sceneComposePromptsSchema, sceneComposePromptsTool, sceneTools;
67079
+ var SCENE_PRESETS2, PROJECT_DIR_DESCRIPTION, INIT_DIR_DESCRIPTION, sceneStylesSchema, sceneStylesTool, sceneInitSchema, sceneInitTool, sceneAddSchema, sceneAddTool, sceneLintSchema, sceneLintTool, sceneRepairSchema, sceneRepairTool, sceneRenderSchema, sceneRenderTool, sceneBuildSchema, sceneBuildTool, sceneInstallSkillSchema, sceneInstallSkillTool, sceneComposePromptsSchema, sceneComposePromptsTool, sceneTools;
67067
67080
  var init_scene2 = __esm({
67068
67081
  "src/tools/manifest/scene.ts"() {
67069
67082
  "use strict";
@@ -67086,6 +67099,8 @@ var init_scene2 = __esm({
67086
67099
  "kinetic-type",
67087
67100
  "product-shot"
67088
67101
  ];
67102
+ PROJECT_DIR_DESCRIPTION = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
67103
+ INIT_DIR_DESCRIPTION = "Project directory to create. Prefer a project name or workspace-relative path; in MCP hosts, relative paths resolve under the configured server workspace. Do not use /tmp or /home/claude unless the user explicitly asks.";
67089
67104
  sceneStylesSchema = external_exports.object({
67090
67105
  name: external_exports.string().optional().describe("Style name or slug (e.g. 'Swiss Pulse', 'swiss-pulse'). Omit to list all 8.")
67091
67106
  });
@@ -67145,7 +67160,7 @@ var init_scene2 = __esm({
67145
67160
  }
67146
67161
  });
67147
67162
  sceneInitSchema = external_exports.object({
67148
- dir: external_exports.string().describe("Project directory (created if missing)."),
67163
+ dir: external_exports.string().describe(INIT_DIR_DESCRIPTION),
67149
67164
  name: external_exports.string().optional().describe("Project name. Defaults to the directory basename."),
67150
67165
  aspect: external_exports.enum(["16:9", "9:16", "1:1", "4:5"]).optional().describe("Aspect ratio. Default 16:9."),
67151
67166
  duration: external_exports.number().optional().describe("Default root composition duration in seconds. Default 10.")
@@ -67157,7 +67172,7 @@ var init_scene2 = __esm({
67157
67172
  description: "Scaffold a new VibeFrame video scene project. Supports minimal, agent, and full profiles; full includes the current HTML render backend metadata. Idempotent: re-running keeps user-authored files and merges backend config instead of overwriting. No API keys required.",
67158
67173
  schema: sceneInitSchema,
67159
67174
  async execute(args, ctx) {
67160
- const dir = resolve71(ctx.workingDirectory, args.dir);
67175
+ const dir = resolve73(ctx.workingDirectory, args.dir);
67161
67176
  const result = await scaffoldSceneProject({
67162
67177
  dir,
67163
67178
  name: args.name,
@@ -67192,7 +67207,7 @@ var init_scene2 = __esm({
67192
67207
  visuals: external_exports.string().optional().describe("Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider."),
67193
67208
  headline: external_exports.string().optional().describe("Visible headline text. Defaults to the humanised scene name."),
67194
67209
  kicker: external_exports.string().optional().describe("Small label above the headline (used by 'explainer' and 'product-shot' presets)."),
67195
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
67210
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION),
67196
67211
  insertInto: external_exports.string().optional().describe("Root composition file (relative to projectDir). Default 'index.html'."),
67197
67212
  imageProvider: external_exports.enum(["gemini", "openai"]).optional().describe("Image provider for visuals. Default 'gemini'."),
67198
67213
  voice: external_exports.string().optional().describe("ElevenLabs voice id or name."),
@@ -67207,7 +67222,7 @@ var init_scene2 = __esm({
67207
67222
  description: "Add a single scene to an existing scene project. Optionally generates narration audio (ElevenLabs) and/or a backdrop image (Gemini/OpenAI), then emits compositions/scene-<id>.html with a paused GSAP timeline and splices a clip reference into the root index.html. Use skipAudio:true and skipImage:true for text-only scenes that need no API calls.",
67208
67223
  schema: sceneAddSchema,
67209
67224
  async execute(args, ctx) {
67210
- const projectDir = args.projectDir ? resolve71(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67225
+ const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67211
67226
  const result = await executeSceneAdd({
67212
67227
  name: args.name,
67213
67228
  preset: args.preset ?? "simple",
@@ -67253,7 +67268,7 @@ var init_scene2 = __esm({
67253
67268
  }
67254
67269
  });
67255
67270
  sceneLintSchema = external_exports.object({
67256
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
67271
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION),
67257
67272
  root: external_exports.string().optional().describe("Root composition file relative to projectDir. Default 'index.html'."),
67258
67273
  fix: external_exports.boolean().optional().describe('Apply mechanical auto-fixes (currently: missing class="clip").')
67259
67274
  });
@@ -67264,7 +67279,7 @@ var init_scene2 = __esm({
67264
67279
  description: "Validate every scene file in a project against the public Hyperframes lint rules (in-process, no Chrome required). Returns errors, warnings, and info findings per file. Optional fix:true mechanically repairs `timed_element_missing_clip_class` only \u2014 other issues surface with fixHints.",
67265
67280
  schema: sceneLintSchema,
67266
67281
  async execute(args, ctx) {
67267
- const projectDir = args.projectDir ? resolve71(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67282
+ const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67268
67283
  const result = await runProjectLint({
67269
67284
  projectDir,
67270
67285
  rootRel: args.root,
@@ -67290,7 +67305,7 @@ var init_scene2 = __esm({
67290
67305
  }
67291
67306
  });
67292
67307
  sceneRepairSchema = external_exports.object({
67293
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
67308
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION),
67294
67309
  root: external_exports.string().optional().describe("Root composition file relative to projectDir. Default 'index.html'."),
67295
67310
  dryRun: external_exports.boolean().optional().describe("Preview deterministic repairs without writing files.")
67296
67311
  });
@@ -67301,7 +67316,7 @@ var init_scene2 = __esm({
67301
67316
  description: "Apply deterministic mechanical scene repairs. Currently uses the safe lint auto-fix allow-list and never performs semantic creative rewrites.",
67302
67317
  schema: sceneRepairSchema,
67303
67318
  async execute(args, ctx) {
67304
- const projectDir = args.projectDir ? resolve71(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67319
+ const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67305
67320
  const result = await executeSceneRepair({
67306
67321
  projectDir,
67307
67322
  rootRel: args.root,
@@ -67319,7 +67334,7 @@ var init_scene2 = __esm({
67319
67334
  }
67320
67335
  });
67321
67336
  sceneRenderSchema = external_exports.object({
67322
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
67337
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION),
67323
67338
  root: external_exports.string().optional().describe("Root composition file relative to projectDir. Default 'index.html'."),
67324
67339
  beat: external_exports.string().optional().describe("Render only one storyboard beat using a temporary root."),
67325
67340
  output: external_exports.string().optional().describe("Output file path (relative paths resolve against projectDir)."),
@@ -67335,7 +67350,7 @@ var init_scene2 = __esm({
67335
67350
  description: "Render a scene project to MP4/WebM/MOV via the Hyperframes producer. Requires Chrome installed locally. Output defaults to renders/<projectName>-<isoStamp>.<format>.",
67336
67351
  schema: sceneRenderSchema,
67337
67352
  async execute(args, ctx) {
67338
- const projectDir = args.projectDir ? resolve71(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67353
+ const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67339
67354
  const result = await executeSceneRender({
67340
67355
  projectDir,
67341
67356
  root: args.root,
@@ -67374,7 +67389,7 @@ var init_scene2 = __esm({
67374
67389
  });
67375
67390
  sceneBuildSchema = external_exports.object({
67376
67391
  projectDir: external_exports.string().optional().describe(
67377
- "Project directory containing STORYBOARD.md, DESIGN.md, index.html. Defaults to the surface's cwd."
67392
+ "Project directory containing STORYBOARD.md, DESIGN.md, index.html. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace."
67378
67393
  ),
67379
67394
  stage: external_exports.enum(["assets", "compose", "sync", "render", "all"]).optional().describe("Build stage to run. Default all."),
67380
67395
  beat: external_exports.string().optional().describe("Restrict asset/compose work to one beat id."),
@@ -67409,7 +67424,7 @@ var init_scene2 = __esm({
67409
67424
  description: "v0.60 one-shot orchestrator: read STORYBOARD.md per-beat YAML cues (narration / backdrop / duration), dispatch TTS + image generation per beat, compose scene HTML via the compose-scenes-with-skills pipeline, then render to MP4. Use this instead of chaining init + scene_add + render manually. Caches by SHA256 of (DESIGN.md + cue body) so re-runs are idempotent and cheap.",
67410
67425
  schema: sceneBuildSchema,
67411
67426
  async execute(args, ctx) {
67412
- const projectDir = args.projectDir ? resolve71(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67427
+ const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
67413
67428
  const result = await executeSceneBuild({
67414
67429
  projectDir,
67415
67430
  stage: args.stage,
@@ -67489,7 +67504,7 @@ var init_scene2 = __esm({
67489
67504
  });
67490
67505
  sceneInstallSkillSchema = external_exports.object({
67491
67506
  projectDir: external_exports.string().describe(
67492
- "Project directory containing STORYBOARD.md / DESIGN.md. Required to keep cross-host calls explicit and prevent accidental installs in unintended cwd."
67507
+ "Project directory containing STORYBOARD.md / DESIGN.md. Required to keep cross-host calls explicit; in MCP hosts, relative paths resolve under the configured server workspace."
67493
67508
  ),
67494
67509
  host: external_exports.enum(["claude-code", "cursor", "auto", "all"]).optional().describe(
67495
67510
  "Host layout target. 'auto' (default) detects installed agent hosts; 'all' writes every layout; 'claude-code' / 'cursor' force a single host. Codex / Aider read the universal SKILL.md via AGENTS.md so don't need a host-specific layout."
@@ -67506,7 +67521,7 @@ var init_scene2 = __esm({
67506
67521
  description: "Install the vendored Hyperframes skill bundle into a scene project so the host agent (Claude Code, Cursor, Codex, Aider) can read framework rules + house style directly. Writes a universal SKILL.md + references/ at the project root, plus per-host layouts (.claude/skills/hyperframes/ for Claude Code, .cursor/rules/hyperframes.mdc for Cursor) when those hosts are detected. Phase H1 of the agentic-native composer plan \u2014 once installed, the host agent itself can author scene HTML using the rules instead of relying on vibe's internal LLM call.",
67507
67522
  schema: sceneInstallSkillSchema,
67508
67523
  async execute(args, ctx) {
67509
- const projectDir = resolve71(ctx.workingDirectory, args.projectDir);
67524
+ const projectDir = resolve73(ctx.workingDirectory, args.projectDir);
67510
67525
  const hostFlag = args.host ?? "auto";
67511
67526
  const hosts = (() => {
67512
67527
  if (hostFlag === "all") return ["all"];
@@ -67539,7 +67554,7 @@ var init_scene2 = __esm({
67539
67554
  });
67540
67555
  sceneComposePromptsSchema = external_exports.object({
67541
67556
  projectDir: external_exports.string().describe(
67542
- "Project directory containing STORYBOARD.md / DESIGN.md. Required to keep cross-host calls explicit."
67557
+ "Project directory containing STORYBOARD.md / DESIGN.md. Required to keep cross-host calls explicit; in MCP hosts, relative paths resolve under the configured server workspace."
67543
67558
  ),
67544
67559
  beat: external_exports.string().optional().describe(
67545
67560
  "Restrict the plan to a single beat by id (e.g. 'hook', '1'). Omit to emit every beat in the storyboard."
@@ -67552,7 +67567,7 @@ var init_scene2 = __esm({
67552
67567
  description: "Emit the per-beat compose plan for the host agent to author scene HTML itself. Reads STORYBOARD.md + DESIGN.md and returns each beat's outputPath + userPrompt + cues + body, plus references to the project's SKILL.md (Hyperframes rules) and DESIGN.md (visual identity). The host agent writes each compositions/scene-<id>.html file directly \u2014 VibeFrame makes NO LLM call here. Pairs with scene_install_skill (Phase H1). Phase H2 of the agentic-native composer plan; the internal-LLM batch path (build) remains as a fallback for non-agent contexts.",
67553
67568
  schema: sceneComposePromptsSchema,
67554
67569
  async execute(args, ctx) {
67555
- const projectDir = resolve71(ctx.workingDirectory, args.projectDir);
67570
+ const projectDir = resolve73(ctx.workingDirectory, args.projectDir);
67556
67571
  const result = await getComposePrompts({
67557
67572
  projectDir,
67558
67573
  beatId: args.beat
@@ -68180,14 +68195,14 @@ var init_edit = __esm({
68180
68195
  });
68181
68196
 
68182
68197
  // src/commands/ai-suggest-edit.ts
68183
- import { readFile as readFile47, writeFile as writeFile51 } from "node:fs/promises";
68184
- import { resolve as resolve72 } from "node:path";
68198
+ import { readFile as readFile48, writeFile as writeFile52 } from "node:fs/promises";
68199
+ import { resolve as resolve74 } from "node:path";
68185
68200
  async function executeSuggestEdit(options) {
68186
68201
  try {
68187
68202
  const apiKey = options.apiKey ?? process.env.GOOGLE_API_KEY;
68188
68203
  if (!apiKey) return { success: false, error: "GOOGLE_API_KEY required for suggest" };
68189
- const filePath = resolve72(process.cwd(), options.projectPath);
68190
- const content = await readFile47(filePath, "utf-8");
68204
+ const filePath = resolve74(process.cwd(), options.projectPath);
68205
+ const content = await readFile48(filePath, "utf-8");
68191
68206
  const data = JSON.parse(content);
68192
68207
  const project = Project.fromJSON(data);
68193
68208
  const gemini = new GeminiProvider();
@@ -68198,7 +68213,7 @@ async function executeSuggestEdit(options) {
68198
68213
  const first = suggestions[0];
68199
68214
  const applied = applySuggestion(project, first);
68200
68215
  if (applied) {
68201
- await writeFile51(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
68216
+ await writeFile52(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
68202
68217
  return {
68203
68218
  success: true,
68204
68219
  suggestions,
@@ -68227,8 +68242,8 @@ var init_ai_suggest_edit = __esm({
68227
68242
  });
68228
68243
 
68229
68244
  // src/tools/manifest/inspect.ts
68230
- import { resolve as resolve73 } from "node:path";
68231
- var inspectProjectTool, inspectRenderTool, analyzeMediaTool, analyzeVideoTool, analyzeReviewTool, analyzeSuggestTool, inspectTools;
68245
+ import { resolve as resolve75 } from "node:path";
68246
+ var PROJECT_DIR_DESCRIPTION2, inspectProjectTool, inspectRenderTool, analyzeMediaTool, analyzeVideoTool, analyzeReviewTool, analyzeSuggestTool, inspectTools;
68232
68247
  var init_inspect = __esm({
68233
68248
  "src/tools/manifest/inspect.ts"() {
68234
68249
  "use strict";
@@ -68239,28 +68254,33 @@ var init_inspect = __esm({
68239
68254
  init_ai_suggest_edit();
68240
68255
  init_scene_inspect();
68241
68256
  init_render_inspect();
68257
+ PROJECT_DIR_DESCRIPTION2 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
68242
68258
  inspectProjectTool = defineTool({
68243
68259
  name: "inspect_project",
68244
68260
  category: "analyze",
68245
68261
  cost: "free",
68246
68262
  description: "Local project inspection: checks STORYBOARD.md, DESIGN.md, config, build-report, scene lint, composition files, and referenced assets. Writes review-report.json by default.",
68247
68263
  schema: external_exports.object({
68248
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
68264
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION2),
68249
68265
  beat: external_exports.string().optional().describe("Inspect only one storyboard beat where beat-scoped checks apply."),
68250
68266
  outputPath: external_exports.string().optional().describe("Optional review report path. Defaults to <project>/review-report.json."),
68251
68267
  report: external_exports.boolean().optional().describe("Write review-report.json. Default true.")
68252
68268
  }),
68253
68269
  async execute(args, ctx) {
68254
- const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68270
+ const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68255
68271
  const result = await inspectProject({
68256
68272
  projectDir,
68257
68273
  beatId: args.beat,
68258
- outputPath: args.outputPath ? resolve73(ctx.workingDirectory, args.outputPath) : void 0,
68274
+ outputPath: args.outputPath ? resolve75(ctx.workingDirectory, args.outputPath) : void 0,
68259
68275
  writeReport: args.report !== false
68260
68276
  });
68261
68277
  return {
68262
68278
  success: result.status !== "fail",
68263
- data: result,
68279
+ data: {
68280
+ ...result,
68281
+ workingDirectory: ctx.workingDirectory,
68282
+ projectDir
68283
+ },
68264
68284
  error: result.status === "fail" ? `${result.issues.filter((issue) => issue.severity === "error").length} project inspection error(s)` : void 0,
68265
68285
  humanLines: [
68266
68286
  `${result.status === "pass" ? "\u2705" : result.status === "warn" ? "\u26A0\uFE0F" : "\u274C"} Project inspection ${result.status} \u2014 score ${result.score}/100`,
@@ -68275,7 +68295,7 @@ var init_inspect = __esm({
68275
68295
  cost: "low",
68276
68296
  description: "Render inspection: runs cheap local video checks by default, optionally adds Gemini AI review with ai: true, and writes review-report.json by default.",
68277
68297
  schema: external_exports.object({
68278
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
68298
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION2),
68279
68299
  beat: external_exports.string().optional().describe("Inspect a render for one storyboard beat."),
68280
68300
  videoPath: external_exports.string().optional().describe("Rendered video path. Defaults to build-report outputPath or latest renders/* video."),
68281
68301
  outputPath: external_exports.string().optional().describe("Optional review report path. Defaults to <project>/review-report.json."),
@@ -68285,20 +68305,24 @@ var init_inspect = __esm({
68285
68305
  dryRun: external_exports.boolean().optional().describe("Preview resolved inputs without probing video or calling Gemini.")
68286
68306
  }),
68287
68307
  async execute(args, ctx) {
68288
- const projectDir = args.projectDir ? resolve73(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68308
+ const projectDir = args.projectDir ? resolve75(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68289
68309
  if (args.dryRun) {
68290
68310
  const result2 = await previewInspectRender({
68291
68311
  projectDir,
68292
68312
  beatId: args.beat,
68293
- videoPath: args.videoPath ? resolve73(ctx.workingDirectory, args.videoPath) : void 0,
68294
- outputPath: args.outputPath ? resolve73(ctx.workingDirectory, args.outputPath) : void 0,
68313
+ videoPath: args.videoPath ? resolve75(ctx.workingDirectory, args.videoPath) : void 0,
68314
+ outputPath: args.outputPath ? resolve75(ctx.workingDirectory, args.outputPath) : void 0,
68295
68315
  writeReport: args.report !== false,
68296
68316
  ai: args.ai === true,
68297
68317
  model: args.model
68298
68318
  });
68299
68319
  return {
68300
68320
  success: true,
68301
- data: result2,
68321
+ data: {
68322
+ ...result2,
68323
+ workingDirectory: ctx.workingDirectory,
68324
+ projectDir
68325
+ },
68302
68326
  humanLines: [
68303
68327
  `Render inspection dry-run \u2014 ${result2.videoPath ? "render found" : "render missing"}`,
68304
68328
  ...result2.reportPath ? [`report: ${result2.reportPath}`] : []
@@ -68308,15 +68332,19 @@ var init_inspect = __esm({
68308
68332
  const result = await inspectRender({
68309
68333
  projectDir,
68310
68334
  beatId: args.beat,
68311
- videoPath: args.videoPath ? resolve73(ctx.workingDirectory, args.videoPath) : void 0,
68312
- outputPath: args.outputPath ? resolve73(ctx.workingDirectory, args.outputPath) : void 0,
68335
+ videoPath: args.videoPath ? resolve75(ctx.workingDirectory, args.videoPath) : void 0,
68336
+ outputPath: args.outputPath ? resolve75(ctx.workingDirectory, args.outputPath) : void 0,
68313
68337
  writeReport: args.report !== false,
68314
68338
  ai: args.ai === true,
68315
68339
  model: args.model
68316
68340
  });
68317
68341
  return {
68318
68342
  success: result.status !== "fail",
68319
- data: result,
68343
+ data: {
68344
+ ...result,
68345
+ workingDirectory: ctx.workingDirectory,
68346
+ projectDir
68347
+ },
68320
68348
  error: result.status === "fail" ? `${result.issues.filter((issue) => issue.severity === "error").length} render inspection error(s)` : void 0,
68321
68349
  humanLines: [
68322
68350
  `${result.status === "pass" ? "\u2705" : result.status === "warn" ? "\u26A0\uFE0F" : "\u274C"} Render inspection ${result.status} \u2014 score ${result.score}/100`,
@@ -68700,7 +68728,7 @@ var init_generate2 = __esm({
68700
68728
  schema: external_exports.object({
68701
68729
  description: external_exports.string().describe("Background description / image prompt."),
68702
68730
  aspect: external_exports.enum(["16:9", "9:16", "1:1"]).optional().describe("Aspect ratio. Default '16:9'."),
68703
- output: external_exports.string().optional().describe("Output PNG path. Relative paths resolve against the surface's cwd.")
68731
+ output: external_exports.string().optional().describe("Output PNG path. Relative paths resolve against the surface's cwd; in MCP hosts, that is the configured server workspace.")
68704
68732
  }),
68705
68733
  async execute(args) {
68706
68734
  const result = await executeBackground(args);
@@ -68899,15 +68927,15 @@ var init_generate2 = __esm({
68899
68927
  });
68900
68928
 
68901
68929
  // src/tools/manifest/storyboard.ts
68902
- import { existsSync as existsSync53 } from "node:fs";
68903
- import { readFile as readFile48, writeFile as writeFile52 } from "node:fs/promises";
68904
- import { resolve as resolve74 } from "node:path";
68930
+ import { existsSync as existsSync54 } from "node:fs";
68931
+ import { readFile as readFile49, writeFile as writeFile53 } from "node:fs/promises";
68932
+ import { resolve as resolve76 } from "node:path";
68905
68933
  async function readStoryboard2(projectDir) {
68906
- const path2 = resolve74(projectDir, "STORYBOARD.md");
68907
- if (!existsSync53(path2)) return null;
68908
- return { path: path2, markdown: await readFile48(path2, "utf-8") };
68934
+ const path2 = resolve76(projectDir, "STORYBOARD.md");
68935
+ if (!existsSync54(path2)) return null;
68936
+ return { path: path2, markdown: await readFile49(path2, "utf-8") };
68909
68937
  }
68910
- var projectDirSchema, storyboardListTool, storyboardValidateTool, storyboardGetTool, storyboardSetTool, storyboardMoveTool, storyboardReviseTool, planTool, storyboardTools;
68938
+ var PROJECT_DIR_DESCRIPTION3, projectDirSchema, storyboardListTool, storyboardValidateTool, storyboardGetTool, storyboardSetTool, storyboardMoveTool, storyboardReviseTool, planTool, storyboardTools;
68911
68939
  var init_storyboard2 = __esm({
68912
68940
  "src/tools/manifest/storyboard.ts"() {
68913
68941
  "use strict";
@@ -68917,8 +68945,9 @@ var init_storyboard2 = __esm({
68917
68945
  init_storyboard_edit();
68918
68946
  init_storyboard_revise();
68919
68947
  init_build_plan();
68948
+ PROJECT_DIR_DESCRIPTION3 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
68920
68949
  projectDirSchema = external_exports.object({
68921
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd.")
68950
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3)
68922
68951
  });
68923
68952
  storyboardListTool = defineTool({
68924
68953
  name: "storyboard_list",
@@ -68927,7 +68956,7 @@ var init_storyboard2 = __esm({
68927
68956
  description: "List beats, ids, durations, and cue blocks from a project's STORYBOARD.md.",
68928
68957
  schema: projectDirSchema,
68929
68958
  async execute(args, ctx) {
68930
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68959
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68931
68960
  const file = await readStoryboard2(projectDir);
68932
68961
  if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
68933
68962
  const parsed = parseStoryboard(file.markdown);
@@ -68953,7 +68982,7 @@ var init_storyboard2 = __esm({
68953
68982
  description: "Validate STORYBOARD.md beat ids and cue blocks.",
68954
68983
  schema: projectDirSchema,
68955
68984
  async execute(args, ctx) {
68956
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68985
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68957
68986
  const file = await readStoryboard2(projectDir);
68958
68987
  if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
68959
68988
  const result = validateStoryboardMarkdown(file.markdown);
@@ -68982,11 +69011,11 @@ var init_storyboard2 = __esm({
68982
69011
  cost: "free",
68983
69012
  description: "Return one STORYBOARD.md beat as structured data.",
68984
69013
  schema: external_exports.object({
68985
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
69014
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3),
68986
69015
  beat: external_exports.string().describe("Beat id to return.")
68987
69016
  }),
68988
69017
  async execute(args, ctx) {
68989
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69018
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
68990
69019
  const file = await readStoryboard2(projectDir);
68991
69020
  if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
68992
69021
  const beat = getStoryboardBeat(file.markdown, args.beat);
@@ -69004,7 +69033,7 @@ var init_storyboard2 = __esm({
69004
69033
  cost: "free",
69005
69034
  description: "Set or unset one cue on one beat in STORYBOARD.md.",
69006
69035
  schema: external_exports.object({
69007
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
69036
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3),
69008
69037
  beat: external_exports.string().describe("Beat id to mutate."),
69009
69038
  key: external_exports.string().describe("Cue key to set."),
69010
69039
  value: external_exports.string().optional().describe("Cue value. Required unless unset is true."),
@@ -69012,7 +69041,7 @@ var init_storyboard2 = __esm({
69012
69041
  unset: external_exports.boolean().optional().describe("Remove the cue key.")
69013
69042
  }),
69014
69043
  async execute(args, ctx) {
69015
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69044
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69016
69045
  const file = await readStoryboard2(projectDir);
69017
69046
  if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
69018
69047
  try {
@@ -69023,7 +69052,7 @@ var init_storyboard2 = __esm({
69023
69052
  value,
69024
69053
  unset: args.unset
69025
69054
  });
69026
- await writeFile52(file.path, next, "utf-8");
69055
+ await writeFile53(file.path, next, "utf-8");
69027
69056
  return {
69028
69057
  success: true,
69029
69058
  data: { beat: args.beat, key: args.key },
@@ -69040,12 +69069,12 @@ var init_storyboard2 = __esm({
69040
69069
  cost: "free",
69041
69070
  description: "Move one beat after another beat in STORYBOARD.md.",
69042
69071
  schema: external_exports.object({
69043
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
69072
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3),
69044
69073
  beat: external_exports.string().describe("Beat id to move."),
69045
69074
  after: external_exports.string().describe("Beat id that should precede the moved beat.")
69046
69075
  }),
69047
69076
  async execute(args, ctx) {
69048
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69077
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69049
69078
  const file = await readStoryboard2(projectDir);
69050
69079
  if (!file) return { success: false, error: `STORYBOARD.md not found in ${projectDir}` };
69051
69080
  try {
@@ -69053,7 +69082,7 @@ var init_storyboard2 = __esm({
69053
69082
  beatId: args.beat,
69054
69083
  afterBeatId: args.after
69055
69084
  });
69056
- await writeFile52(file.path, next, "utf-8");
69085
+ await writeFile53(file.path, next, "utf-8");
69057
69086
  return {
69058
69087
  success: true,
69059
69088
  data: { beat: args.beat, after: args.after },
@@ -69070,14 +69099,14 @@ var init_storyboard2 = __esm({
69070
69099
  cost: "low",
69071
69100
  description: "Revise an existing STORYBOARD.md from a natural-language request. Reads project context, validates the revised storyboard, and writes unless dryRun is true.",
69072
69101
  schema: external_exports.object({
69073
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
69102
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3),
69074
69103
  request: external_exports.string().describe("Revision request, e.g. 'make the hook punchier and shorten to 30 seconds'."),
69075
69104
  durationSec: external_exports.number().optional().describe("Target total duration in seconds."),
69076
69105
  composer: external_exports.enum(["claude", "openai", "gemini"]).optional().describe("Revision LLM provider. Defaults to project config or available API keys."),
69077
69106
  dryRun: external_exports.boolean().optional().describe("Preview the revised storyboard without writing.")
69078
69107
  }),
69079
69108
  async execute(args, ctx) {
69080
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69109
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69081
69110
  const result = await executeStoryboardRevision({
69082
69111
  projectDir,
69083
69112
  request: args.request,
@@ -69101,7 +69130,7 @@ var init_storyboard2 = __esm({
69101
69130
  cost: "free",
69102
69131
  description: "Read STORYBOARD.md and return the build plan, missing artifacts, provider needs, and estimated cost.",
69103
69132
  schema: external_exports.object({
69104
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
69133
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION3),
69105
69134
  stage: external_exports.enum(["assets", "compose", "sync", "render", "all"]).optional().describe("Stage to plan. Default all."),
69106
69135
  beat: external_exports.string().optional().describe("Restrict the plan to one beat id."),
69107
69136
  mode: external_exports.enum(["agent", "batch", "auto"]).optional().describe("Build mode. Default auto."),
@@ -69120,7 +69149,7 @@ var init_storyboard2 = __esm({
69120
69149
  force: external_exports.boolean().optional().describe("Plan regeneration even when outputs exist.")
69121
69150
  }),
69122
69151
  async execute(args, ctx) {
69123
- const projectDir = args.projectDir ? resolve74(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69152
+ const projectDir = args.projectDir ? resolve76(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
69124
69153
  const plan = await createBuildPlan({
69125
69154
  projectDir,
69126
69155
  stage: args.stage,
@@ -69163,9 +69192,9 @@ var init_storyboard2 = __esm({
69163
69192
  });
69164
69193
 
69165
69194
  // src/tools/manifest/remix.ts
69166
- import { writeFile as writeFile53 } from "node:fs/promises";
69195
+ import { writeFile as writeFile54 } from "node:fs/promises";
69167
69196
  import { tmpdir as tmpdir4 } from "node:os";
69168
- import { join as join24 } from "node:path";
69197
+ import { join as join25 } from "node:path";
69169
69198
  var pipelineHighlightsTool, pipelineAutoShortsTool, pipelineRunTool, pipelineRegenerateSceneTool, remixTools;
69170
69199
  var init_remix = __esm({
69171
69200
  "src/tools/manifest/remix.ts"() {
@@ -69273,8 +69302,8 @@ var init_remix = __esm({
69273
69302
  let resolvedPath = args.pipelinePath;
69274
69303
  let tempPath;
69275
69304
  if (args.pipelineYaml) {
69276
- tempPath = join24(tmpdir4(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
69277
- await writeFile53(tempPath, args.pipelineYaml, "utf-8");
69305
+ tempPath = join25(tmpdir4(), `vibe-mcp-pipeline-${Date.now()}.yaml`);
69306
+ await writeFile54(tempPath, args.pipelineYaml, "utf-8");
69278
69307
  resolvedPath = tempPath;
69279
69308
  }
69280
69309
  try {
@@ -69441,15 +69470,15 @@ var init_detect2 = __esm({
69441
69470
  });
69442
69471
 
69443
69472
  // src/tools/manifest/_project-io.ts
69444
- import { readFile as readFile49, writeFile as writeFile54 } from "node:fs/promises";
69473
+ import { readFile as readFile50, writeFile as writeFile55 } from "node:fs/promises";
69445
69474
  async function loadProject2(projectPath, cwd) {
69446
69475
  const absPath = await resolveTimelineFile(projectPath, cwd);
69447
- const content = await readFile49(absPath, "utf-8");
69476
+ const content = await readFile50(absPath, "utf-8");
69448
69477
  const data = JSON.parse(content);
69449
69478
  return { project: Project.fromJSON(data), absPath };
69450
69479
  }
69451
69480
  async function saveProject(absPath, project) {
69452
- await writeFile54(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
69481
+ await writeFile55(absPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
69453
69482
  }
69454
69483
  var init_project_io = __esm({
69455
69484
  "src/tools/manifest/_project-io.ts"() {
@@ -69460,8 +69489,8 @@ var init_project_io = __esm({
69460
69489
  });
69461
69490
 
69462
69491
  // src/tools/manifest/timeline.ts
69463
- import { mkdir as mkdir27, writeFile as writeFile55 } from "node:fs/promises";
69464
- import { basename as basename23, resolve as resolve75 } from "node:path";
69492
+ import { mkdir as mkdir28, writeFile as writeFile56 } from "node:fs/promises";
69493
+ import { basename as basename23, resolve as resolve77 } from "node:path";
69465
69494
  var MEDIA_TYPES, timelineCreateTool, timelineInfoTool, timelineAddSourceTool, timelineAddClipTool, timelineSplitClipTool, timelineTrimClipTool, timelineMoveClipTool, timelineDeleteClipTool, timelineDuplicateClipTool, timelineAddEffectTool, timelineAddTrackTool, timelineListTool, timelineTools;
69466
69495
  var init_timeline = __esm({
69467
69496
  "src/tools/manifest/timeline.ts"() {
@@ -69497,18 +69526,18 @@ var init_timeline = __esm({
69497
69526
  fps: external_exports.number().optional().describe("Frames per second (default: 30)")
69498
69527
  }),
69499
69528
  async execute(args, ctx) {
69500
- const projectName = args.name === "." ? basename23(ctx.workingDirectory) : basename23(resolve75(ctx.workingDirectory, args.name));
69529
+ const projectName = args.name === "." ? basename23(ctx.workingDirectory) : basename23(resolve77(ctx.workingDirectory, args.name));
69501
69530
  const project = new Project(projectName);
69502
69531
  if (args.fps) project.setFrameRate(args.fps);
69503
69532
  let outputPath;
69504
69533
  if (args.outputPath) {
69505
- outputPath = resolve75(ctx.workingDirectory, args.outputPath);
69534
+ outputPath = resolve77(ctx.workingDirectory, args.outputPath);
69506
69535
  } else {
69507
- const dirPath = resolve75(ctx.workingDirectory, args.name);
69508
- await mkdir27(dirPath, { recursive: true });
69509
- outputPath = resolve75(dirPath, TIMELINE_FILENAME);
69536
+ const dirPath = resolve77(ctx.workingDirectory, args.name);
69537
+ await mkdir28(dirPath, { recursive: true });
69538
+ outputPath = resolve77(dirPath, TIMELINE_FILENAME);
69510
69539
  }
69511
- await writeFile55(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
69540
+ await writeFile56(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
69512
69541
  return {
69513
69542
  success: true,
69514
69543
  data: { name: projectName, outputPath },
@@ -69556,7 +69585,7 @@ var init_timeline = __esm({
69556
69585
  }),
69557
69586
  async execute(args, ctx) {
69558
69587
  const { project, absPath } = await loadProject2(args.projectPath, ctx.workingDirectory);
69559
- const mediaPath = resolve75(ctx.workingDirectory, args.mediaPath);
69588
+ const mediaPath = resolve77(ctx.workingDirectory, args.mediaPath);
69560
69589
  const ext = mediaPath.split(".").pop()?.toLowerCase() ?? "";
69561
69590
  const source = project.addSource({
69562
69591
  name: args.name ?? mediaPath.split("/").pop() ?? "media",
@@ -69784,8 +69813,8 @@ var init_timeline = __esm({
69784
69813
  });
69785
69814
 
69786
69815
  // src/tools/manifest/project.ts
69787
- import { resolve as resolve76 } from "node:path";
69788
- import { writeFile as writeFile56 } from "node:fs/promises";
69816
+ import { resolve as resolve78 } from "node:path";
69817
+ import { writeFile as writeFile57 } from "node:fs/promises";
69789
69818
  var projectCreateTool, projectInfoTool, projectTools;
69790
69819
  var init_project2 = __esm({
69791
69820
  "src/tools/manifest/project.ts"() {
@@ -69807,10 +69836,10 @@ var init_project2 = __esm({
69807
69836
  fps: external_exports.number().optional().describe("Frames per second (default: 30)")
69808
69837
  }),
69809
69838
  async execute(args, ctx) {
69810
- const outputPath = resolve76(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
69839
+ const outputPath = resolve78(ctx.workingDirectory, args.outputPath ?? `${args.name}.vibe.json`);
69811
69840
  const project = new Project(args.name);
69812
69841
  if (args.fps) project.setFrameRate(args.fps);
69813
- await writeFile56(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
69842
+ await writeFile57(outputPath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
69814
69843
  return {
69815
69844
  success: true,
69816
69845
  data: { name: args.name, outputPath },
@@ -69853,8 +69882,8 @@ var init_project2 = __esm({
69853
69882
  });
69854
69883
 
69855
69884
  // src/commands/export.ts
69856
- import { readFile as readFile50, access as access7 } from "node:fs/promises";
69857
- import { resolve as resolve77, basename as basename24 } from "node:path";
69885
+ import { readFile as readFile51, access as access7 } from "node:fs/promises";
69886
+ import { resolve as resolve79, basename as basename24 } from "node:path";
69858
69887
  import { spawn as spawn3 } from "node:child_process";
69859
69888
  function timelineBaseName(path2) {
69860
69889
  const name = basename24(path2);
@@ -69922,7 +69951,7 @@ async function runExport(projectPath, outputPath, options = {}) {
69922
69951
  };
69923
69952
  }
69924
69953
  const filePath = await resolveTimelineFile(projectPath);
69925
- const content = await readFile50(filePath, "utf-8");
69954
+ const content = await readFile51(filePath, "utf-8");
69926
69955
  const data = JSON.parse(content);
69927
69956
  const project = Project.fromJSON(data);
69928
69957
  const summary = project.getSummary();
@@ -69932,7 +69961,7 @@ async function runExport(projectPath, outputPath, options = {}) {
69932
69961
  message: "Project has no clips to export"
69933
69962
  };
69934
69963
  }
69935
- const finalOutputPath = resolve77(process.cwd(), outputPath);
69964
+ const finalOutputPath = resolve79(process.cwd(), outputPath);
69936
69965
  const basePresetSettings = getPresetSettings(preset, summary.aspectRatio);
69937
69966
  const presetSettings = applyCustomOverrides(basePresetSettings, { bitrate, fps, resolution, codec });
69938
69967
  const clips = project.getClips().sort((a, b) => a.startTime - b.startTime);
@@ -70328,7 +70357,7 @@ function buildFFmpegArgs(clips, sources, presetSettings, outputPath, options, so
70328
70357
  return args;
70329
70358
  }
70330
70359
  function runFFmpegProcess(ffmpegPath, args, onProgress) {
70331
- return new Promise((resolve81, reject) => {
70360
+ return new Promise((resolve83, reject) => {
70332
70361
  const ffmpeg = spawn3(ffmpegPath, args, {
70333
70362
  stdio: ["pipe", "pipe", "pipe"]
70334
70363
  });
@@ -70352,7 +70381,7 @@ function runFFmpegProcess(ffmpegPath, args, onProgress) {
70352
70381
  });
70353
70382
  ffmpeg.on("close", (code) => {
70354
70383
  if (code === 0) {
70355
- resolve81();
70384
+ resolve83();
70356
70385
  } else {
70357
70386
  const errorMatch = stderr.match(/Error.*$/m);
70358
70387
  const errorMsg = errorMatch ? errorMatch[0] : `FFmpeg exited with code ${code}`;
@@ -70488,17 +70517,17 @@ function getPresetSettings(preset, aspectRatio2) {
70488
70517
  }
70489
70518
  async function runHyperframesExport(projectPath, options, spinner2, startedAt) {
70490
70519
  spinner2.text = "Loading project...";
70491
- const { readFile: readFile52 } = await import("node:fs/promises");
70492
- const { resolve: resolve81 } = await import("node:path");
70520
+ const { readFile: readFile53 } = await import("node:fs/promises");
70521
+ const { resolve: resolve83 } = await import("node:path");
70493
70522
  const { Project: Project2 } = await Promise.resolve().then(() => (init_engine(), engine_exports));
70494
70523
  const { createHyperframesBackend: createHyperframesBackend2 } = await Promise.resolve().then(() => (init_hyperframes(), hyperframes_exports));
70495
70524
  const { exitWithError: exitWithError2, generalError: generalError2, outputSuccess: outputSuccess2 } = await Promise.resolve().then(() => (init_output(), output_exports));
70496
70525
  const chalk2 = (await Promise.resolve().then(() => (init_source(), source_exports))).default;
70497
70526
  const filePath = await resolveTimelineFile(projectPath);
70498
- const content = await readFile52(filePath, "utf-8");
70527
+ const content = await readFile53(filePath, "utf-8");
70499
70528
  const project = Project2.fromJSON(JSON.parse(content));
70500
70529
  const state = project.getState();
70501
- const outputPath = options.output ? resolve81(process.cwd(), options.output) : resolve81(process.cwd(), `${timelineBaseName(projectPath)}.${options.format ?? "mp4"}`);
70530
+ const outputPath = options.output ? resolve83(process.cwd(), options.output) : resolve83(process.cwd(), `${timelineBaseName(projectPath)}.${options.format ?? "mp4"}`);
70502
70531
  const quality = ["draft", "standard", "high"].includes(options.preset ?? "") ? options.preset : "standard";
70503
70532
  const backend = createHyperframesBackend2();
70504
70533
  spinner2.text = "Rendering with Hyperframes...";
@@ -70617,7 +70646,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
70617
70646
  }
70618
70647
  spinner2.text = "Loading project...";
70619
70648
  const filePath = await resolveTimelineFile(projectPath);
70620
- const content = await readFile50(filePath, "utf-8");
70649
+ const content = await readFile51(filePath, "utf-8");
70621
70650
  const data = JSON.parse(content);
70622
70651
  const project = Project.fromJSON(data);
70623
70652
  const summary = project.getSummary();
@@ -70625,7 +70654,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
70625
70654
  spinner2.fail("Project has no clips to export");
70626
70655
  exitWithError(usageError("Project has no clips to export"));
70627
70656
  }
70628
- const outputPath = options.output ? resolve77(process.cwd(), options.output) : resolve77(
70657
+ const outputPath = options.output ? resolve79(process.cwd(), options.output) : resolve79(
70629
70658
  process.cwd(),
70630
70659
  `${timelineBaseName(projectPath)}.${options.format}`
70631
70660
  );
@@ -70709,7 +70738,7 @@ Run 'vibe schema export' for structured parameter info.`).action(async (projectP
70709
70738
  });
70710
70739
 
70711
70740
  // src/tools/manifest/export.ts
70712
- import { resolve as resolve78 } from "node:path";
70741
+ import { resolve as resolve80 } from "node:path";
70713
70742
  var exportVideoTool, exportTools;
70714
70743
  var init_export2 = __esm({
70715
70744
  "src/tools/manifest/export.ts"() {
@@ -70730,8 +70759,8 @@ var init_export2 = __esm({
70730
70759
  overwrite: external_exports.boolean().optional().describe("Overwrite existing output file (default: false)")
70731
70760
  }),
70732
70761
  async execute(args, ctx) {
70733
- const projectPath = resolve78(ctx.workingDirectory, args.projectPath);
70734
- const outputPath = resolve78(ctx.workingDirectory, args.outputPath);
70762
+ const projectPath = resolve80(ctx.workingDirectory, args.projectPath);
70763
+ const outputPath = resolve80(ctx.workingDirectory, args.outputPath);
70735
70764
  const result = await runExport(projectPath, outputPath, {
70736
70765
  preset: args.preset,
70737
70766
  format: args.format,
@@ -70750,8 +70779,8 @@ var init_export2 = __esm({
70750
70779
  });
70751
70780
 
70752
70781
  // src/tools/manifest/agent-only.ts
70753
- import { readFile as readFile51, writeFile as writeFile57, readdir as readdir7, stat as stat9, access as access8, unlink as unlink4 } from "node:fs/promises";
70754
- import { resolve as resolve79, join as join25, basename as basename25, extname as extname16 } from "node:path";
70782
+ import { readFile as readFile52, writeFile as writeFile58, readdir as readdir7, stat as stat9, access as access8, unlink as unlink4 } from "node:fs/promises";
70783
+ import { resolve as resolve81, join as join26, basename as basename25, extname as extname16 } from "node:path";
70755
70784
  function matchPattern(filename, pattern) {
70756
70785
  const regex2 = new RegExp(
70757
70786
  "^" + pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".") + "$",
@@ -70829,12 +70858,12 @@ var init_agent_only = __esm({
70829
70858
  async execute(args, ctx) {
70830
70859
  const dirPath = args.path ?? ".";
70831
70860
  try {
70832
- const absPath = resolve79(ctx.workingDirectory, dirPath);
70861
+ const absPath = resolve81(ctx.workingDirectory, dirPath);
70833
70862
  const entries = await readdir7(absPath, { withFileTypes: true });
70834
70863
  const results = [];
70835
70864
  for (const entry of entries) {
70836
70865
  if (args.pattern && !matchPattern(entry.name, args.pattern)) continue;
70837
- const fullPath = join25(absPath, entry.name);
70866
+ const fullPath = join26(absPath, entry.name);
70838
70867
  const stats = await stat9(fullPath);
70839
70868
  if (entry.isDirectory()) {
70840
70869
  results.push(`[DIR] ${entry.name}/`);
@@ -70860,8 +70889,8 @@ var init_agent_only = __esm({
70860
70889
  }),
70861
70890
  async execute(args, ctx) {
70862
70891
  try {
70863
- const absPath = resolve79(ctx.workingDirectory, args.path);
70864
- const content = await readFile51(absPath, "utf-8");
70892
+ const absPath = resolve81(ctx.workingDirectory, args.path);
70893
+ const content = await readFile52(absPath, "utf-8");
70865
70894
  const maxLength = 4e3;
70866
70895
  const truncated = content.length > maxLength;
70867
70896
  const output = truncated ? content.substring(0, maxLength) + "\n... (truncated)" : content;
@@ -70883,8 +70912,8 @@ var init_agent_only = __esm({
70883
70912
  }),
70884
70913
  async execute(args, ctx) {
70885
70914
  try {
70886
- const absPath = resolve79(ctx.workingDirectory, args.path);
70887
- await writeFile57(absPath, args.content, "utf-8");
70915
+ const absPath = resolve81(ctx.workingDirectory, args.path);
70916
+ await writeFile58(absPath, args.content, "utf-8");
70888
70917
  return { success: true, data: { bytes: args.content.length }, humanLines: [`File written: ${args.path} (${formatSize(args.content.length)})`] };
70889
70918
  } catch (error) {
70890
70919
  return { success: false, error: `Failed to write file: ${error instanceof Error ? error.message : String(error)}` };
@@ -70901,7 +70930,7 @@ var init_agent_only = __esm({
70901
70930
  path: external_exports.string().describe("Path to check")
70902
70931
  }),
70903
70932
  async execute(args, ctx) {
70904
- const absPath = resolve79(ctx.workingDirectory, args.path);
70933
+ const absPath = resolve81(ctx.workingDirectory, args.path);
70905
70934
  try {
70906
70935
  await access8(absPath);
70907
70936
  const stats = await stat9(absPath);
@@ -70927,11 +70956,11 @@ var init_agent_only = __esm({
70927
70956
  }),
70928
70957
  async execute(args, ctx) {
70929
70958
  try {
70930
- const filePath = resolve79(ctx.workingDirectory, args.project);
70931
- const content = await readFile51(filePath, "utf-8");
70959
+ const filePath = resolve81(ctx.workingDirectory, args.project);
70960
+ const content = await readFile52(filePath, "utf-8");
70932
70961
  const data = JSON.parse(content);
70933
70962
  const project = Project.fromJSON(data);
70934
- const dirPath = resolve79(ctx.workingDirectory, args.directory);
70963
+ const dirPath = resolve81(ctx.workingDirectory, args.directory);
70935
70964
  const filterExts = args.filter ? args.filter.split(",").map((e) => e.trim().toLowerCase()) : null;
70936
70965
  const imageDuration = args.imageDuration ?? 5;
70937
70966
  const recursive = args.recursive ?? false;
@@ -70939,7 +70968,7 @@ var init_agent_only = __esm({
70939
70968
  const scanDir = async (dir) => {
70940
70969
  const entries = await readdir7(dir, { withFileTypes: true });
70941
70970
  for (const entry of entries) {
70942
- const entryPath = join25(dir, entry.name);
70971
+ const entryPath = join26(dir, entry.name);
70943
70972
  if (entry.isDirectory() && recursive) {
70944
70973
  await scanDir(entryPath);
70945
70974
  } else if (entry.isFile()) {
@@ -70966,7 +70995,7 @@ var init_agent_only = __esm({
70966
70995
  const source = project.addSource({ name: mediaName, type: mediaType, url: mediaFile, duration });
70967
70996
  addedSources.push({ id: source.id, name: mediaName, type: mediaType });
70968
70997
  }
70969
- await writeFile57(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
70998
+ await writeFile58(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
70970
70999
  return {
70971
71000
  success: true,
70972
71001
  data: { count: addedSources.length, sources: addedSources },
@@ -70997,8 +71026,8 @@ var init_agent_only = __esm({
70997
71026
  }),
70998
71027
  async execute(args, ctx) {
70999
71028
  try {
71000
- const filePath = resolve79(ctx.workingDirectory, args.project);
71001
- const content = await readFile51(filePath, "utf-8");
71029
+ const filePath = resolve81(ctx.workingDirectory, args.project);
71030
+ const content = await readFile52(filePath, "utf-8");
71002
71031
  const data = JSON.parse(content);
71003
71032
  const project = Project.fromJSON(data);
71004
71033
  const sourceIds = args.sourceIds ?? [];
@@ -71034,7 +71063,7 @@ var init_agent_only = __esm({
71034
71063
  createdClips.push({ id: clip.id, sourceName: source.name, startTime: currentTime, duration: source.duration });
71035
71064
  currentTime += source.duration + gap;
71036
71065
  }
71037
- await writeFile57(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71066
+ await writeFile58(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71038
71067
  const totalDuration = currentTime - gap - startTime;
71039
71068
  return {
71040
71069
  success: true,
@@ -71066,8 +71095,8 @@ var init_agent_only = __esm({
71066
71095
  }),
71067
71096
  async execute(args, ctx) {
71068
71097
  try {
71069
- const filePath = resolve79(ctx.workingDirectory, args.project);
71070
- const content = await readFile51(filePath, "utf-8");
71098
+ const filePath = resolve81(ctx.workingDirectory, args.project);
71099
+ const content = await readFile52(filePath, "utf-8");
71071
71100
  const data = JSON.parse(content);
71072
71101
  const project = Project.fromJSON(data);
71073
71102
  const clipIds = args.clipIds ?? [];
@@ -71095,7 +71124,7 @@ var init_agent_only = __esm({
71095
71124
  });
71096
71125
  if (effect) appliedEffects.push({ clipId: clip.id, effectId: effect.id });
71097
71126
  }
71098
- await writeFile57(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71127
+ await writeFile58(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71099
71128
  return {
71100
71129
  success: true,
71101
71130
  data: { applied: appliedEffects.length, effectType: args.effectType },
@@ -71120,7 +71149,7 @@ var init_agent_only = __esm({
71120
71149
  async execute(args, ctx) {
71121
71150
  try {
71122
71151
  const filePath = await resolveTimelineFile(args.project, ctx.workingDirectory);
71123
- const content = await readFile51(filePath, "utf-8");
71152
+ const content = await readFile52(filePath, "utf-8");
71124
71153
  const data = JSON.parse(content);
71125
71154
  const project = Project.fromJSON(data);
71126
71155
  const what = args.what ?? "clips";
@@ -71162,7 +71191,7 @@ var init_agent_only = __esm({
71162
71191
  removed.sources++;
71163
71192
  }
71164
71193
  }
71165
- await writeFile57(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71194
+ await writeFile58(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71166
71195
  const parts = [];
71167
71196
  if (removed.clips > 0) parts.push(`${removed.clips} clips`);
71168
71197
  if (removed.tracks > 0) parts.push(`${removed.tracks} tracks`);
@@ -71195,7 +71224,7 @@ var init_agent_only = __esm({
71195
71224
  async execute(args, ctx) {
71196
71225
  try {
71197
71226
  const filePath = await resolveTimelineFile(args.projectPath, ctx.workingDirectory);
71198
- const content = await readFile51(filePath, "utf-8");
71227
+ const content = await readFile52(filePath, "utf-8");
71199
71228
  const data = JSON.parse(content);
71200
71229
  const project = Project.fromJSON(data);
71201
71230
  const updates = [];
@@ -71211,7 +71240,7 @@ var init_agent_only = __esm({
71211
71240
  project.setFrameRate(args.fps);
71212
71241
  updates.push(`Frame Rate: ${args.fps} fps`);
71213
71242
  }
71214
- await writeFile57(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71243
+ await writeFile58(filePath, JSON.stringify(project.toJSON(), null, 2), "utf-8");
71215
71244
  return {
71216
71245
  success: true,
71217
71246
  data: { updates },
@@ -71344,7 +71373,7 @@ var init_agent_only = __esm({
71344
71373
  }),
71345
71374
  async execute(args, ctx) {
71346
71375
  try {
71347
- const absPath = resolve79(ctx.workingDirectory, args.path);
71376
+ const absPath = resolve81(ctx.workingDirectory, args.path);
71348
71377
  const { stdout } = await execSafe(
71349
71378
  "ffprobe",
71350
71379
  ["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", absPath],
@@ -71431,10 +71460,10 @@ Audio:`);
71431
71460
  }),
71432
71461
  async execute(args, ctx) {
71433
71462
  try {
71434
- const absInput = resolve79(ctx.workingDirectory, args.input);
71463
+ const absInput = resolve81(ctx.workingDirectory, args.input);
71435
71464
  const ext = args.input.split(".").pop() || "mp4";
71436
71465
  const baseName = args.input.replace(/\.[^/.]+$/, "");
71437
- const outputPath = args.output ? resolve79(ctx.workingDirectory, args.output) : resolve79(ctx.workingDirectory, `${baseName}-compressed.${ext}`);
71466
+ const outputPath = args.output ? resolve81(ctx.workingDirectory, args.output) : resolve81(ctx.workingDirectory, `${baseName}-compressed.${ext}`);
71438
71467
  const crfValues = { low: 28, medium: 23, high: 18 };
71439
71468
  const crf = crfValues[args.quality ?? "medium"];
71440
71469
  await execSafe(
@@ -71457,8 +71486,8 @@ Audio:`);
71457
71486
  ],
71458
71487
  { maxBuffer: 50 * 1024 * 1024 }
71459
71488
  );
71460
- const inputBuf = await readFile51(absInput);
71461
- const outputBuf = await readFile51(outputPath);
71489
+ const inputBuf = await readFile52(absInput);
71490
+ const outputBuf = await readFile52(outputPath);
71462
71491
  const inputSize = inputBuf.length;
71463
71492
  const outputSize = outputBuf.length;
71464
71493
  const reduction = (inputSize - outputSize) / inputSize * 100;
@@ -71492,8 +71521,8 @@ Audio:`);
71492
71521
  }),
71493
71522
  async execute(args, ctx) {
71494
71523
  try {
71495
- const absInput = resolve79(ctx.workingDirectory, args.input);
71496
- const absOutput = resolve79(ctx.workingDirectory, args.output);
71524
+ const absInput = resolve81(ctx.workingDirectory, args.input);
71525
+ const absOutput = resolve81(ctx.workingDirectory, args.output);
71497
71526
  const codecMap = {
71498
71527
  h264: "libx264",
71499
71528
  h265: "libx265",
@@ -71544,11 +71573,11 @@ Audio:`);
71544
71573
  };
71545
71574
  }
71546
71575
  try {
71547
- const absOutput = resolve79(ctx.workingDirectory, args.output);
71576
+ const absOutput = resolve81(ctx.workingDirectory, args.output);
71548
71577
  if (args.reencode) {
71549
71578
  const ffmpegArgs = [];
71550
71579
  for (const i of args.inputs) {
71551
- ffmpegArgs.push("-i", resolve79(ctx.workingDirectory, i));
71580
+ ffmpegArgs.push("-i", resolve81(ctx.workingDirectory, i));
71552
71581
  }
71553
71582
  const filterComplex = args.inputs.map((_, i) => `[${i}:v][${i}:a]`).join("");
71554
71583
  ffmpegArgs.push(
@@ -71563,9 +71592,9 @@ Audio:`);
71563
71592
  );
71564
71593
  await execSafe("ffmpeg", ffmpegArgs, { maxBuffer: 100 * 1024 * 1024 });
71565
71594
  } else {
71566
- const tempList = resolve79(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
71567
- const listContent = args.inputs.map((i) => `file '${resolve79(ctx.workingDirectory, i)}'`).join("\n");
71568
- await writeFile57(tempList, listContent, "utf-8");
71595
+ const tempList = resolve81(ctx.workingDirectory, `concat-list-${Date.now()}.txt`);
71596
+ const listContent = args.inputs.map((i) => `file '${resolve81(ctx.workingDirectory, i)}'`).join("\n");
71597
+ await writeFile58(tempList, listContent, "utf-8");
71569
71598
  try {
71570
71599
  await execSafe(
71571
71600
  "ffmpeg",
@@ -71659,14 +71688,15 @@ var init_walkthrough = __esm({
71659
71688
  });
71660
71689
 
71661
71690
  // src/tools/manifest/status.ts
71662
- import { resolve as resolve80 } from "node:path";
71663
- var statusJobTool, statusProjectTool, statusTools;
71691
+ import { resolve as resolve82 } from "node:path";
71692
+ var PROJECT_DIR_DESCRIPTION4, statusJobTool, statusProjectTool, statusTools;
71664
71693
  var init_status = __esm({
71665
71694
  "src/tools/manifest/status.ts"() {
71666
71695
  "use strict";
71667
71696
  init_zod();
71668
71697
  init_define_tool();
71669
71698
  init_status_jobs();
71699
+ PROJECT_DIR_DESCRIPTION4 = "Project directory. Defaults to the surface's cwd; in MCP hosts, relative paths resolve under the configured server workspace.";
71670
71700
  statusJobTool = defineTool({
71671
71701
  name: "status_job",
71672
71702
  category: "status",
@@ -71674,13 +71704,13 @@ var init_status = __esm({
71674
71704
  description: "Read one local async job record and optionally refresh supported provider status. Supports Runway/Kling video and Replicate music live checks.",
71675
71705
  schema: external_exports.object({
71676
71706
  jobId: external_exports.string().describe("Local job id returned by a no-wait command."),
71677
- projectDir: external_exports.string().optional().describe("Project directory containing .vibeframe/jobs. Defaults to nearest project root."),
71707
+ projectDir: external_exports.string().optional().describe("Project directory containing .vibeframe/jobs. Defaults to nearest project root; in MCP hosts, relative paths resolve under the configured server workspace."),
71678
71708
  refresh: external_exports.boolean().optional().describe("Call provider status APIs when supported. Default true."),
71679
71709
  wait: external_exports.boolean().optional().describe("Wait for completion when supported."),
71680
71710
  output: external_exports.string().optional().describe("Download result media to this path when complete.")
71681
71711
  }),
71682
71712
  async execute(args, ctx) {
71683
- const projectDir = args.projectDir ? resolve80(ctx.workingDirectory, args.projectDir) : findProjectRoot(ctx.workingDirectory);
71713
+ const projectDir = args.projectDir ? resolve82(ctx.workingDirectory, args.projectDir) : findProjectRoot(ctx.workingDirectory);
71684
71714
  const record = await readJobRecord(args.jobId, projectDir);
71685
71715
  if (!record) return { success: false, error: `Job not found: ${args.jobId}` };
71686
71716
  const result = args.refresh === false ? makeJobStatusResult(record, {
@@ -71689,7 +71719,7 @@ var init_status = __esm({
71689
71719
  warnings: []
71690
71720
  }) : await refreshJobRecord(record, {
71691
71721
  wait: args.wait,
71692
- output: args.output ? resolve80(ctx.workingDirectory, args.output) : void 0,
71722
+ output: args.output ? resolve82(ctx.workingDirectory, args.output) : void 0,
71693
71723
  workingDirectory: ctx.workingDirectory
71694
71724
  });
71695
71725
  return {
@@ -71708,15 +71738,19 @@ var init_status = __esm({
71708
71738
  cost: "free",
71709
71739
  description: "Summarize build-report.json, review-report.json, and local async job records for a VibeFrame project.",
71710
71740
  schema: external_exports.object({
71711
- projectDir: external_exports.string().optional().describe("Project directory. Defaults to the surface's cwd."),
71741
+ projectDir: external_exports.string().optional().describe(PROJECT_DIR_DESCRIPTION4),
71712
71742
  refresh: external_exports.boolean().optional().describe("Refresh active supported jobs before summarizing. Default false.")
71713
71743
  }),
71714
71744
  async execute(args, ctx) {
71715
- const projectDir = args.projectDir ? resolve80(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
71745
+ const projectDir = args.projectDir ? resolve82(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
71716
71746
  const result = await inspectProjectStatus(projectDir, { refresh: args.refresh === true });
71717
71747
  return {
71718
71748
  success: true,
71719
- data: result,
71749
+ data: {
71750
+ ...result,
71751
+ workingDirectory: ctx.workingDirectory,
71752
+ projectDir
71753
+ },
71720
71754
  humanLines: [
71721
71755
  `Project status: ${result.status} (${result.currentStage}), ${result.jobs.active} active job(s), ${result.jobs.failed} failed job(s)`,
71722
71756
  ...result.build ? [`build: ${result.build.phase ?? "unknown"}`] : [],
@@ -71994,8 +72028,8 @@ init_source();
71994
72028
  // package.json
71995
72029
  var package_default = {
71996
72030
  name: "@vibeframe/cli",
71997
- version: "0.106.4",
71998
- description: "VibeFrame CLI - natural language video editing from the terminal",
72031
+ version: "0.106.6",
72032
+ description: "VibeFrame CLI - agentic video workflow runtime",
71999
72033
  private: false,
72000
72034
  license: "MIT",
72001
72035
  repository: {
@@ -78013,9 +78047,9 @@ function parseLrc(lrcString) {
78013
78047
  const minutes = Number.parseInt(match[1], 10);
78014
78048
  const seconds = Number.parseInt(match[2], 10);
78015
78049
  const ms = match[3].length === 3 ? Number.parseInt(match[3], 10) : Number.parseInt(match[3], 10) * 10;
78016
- const timestamp = (minutes * 60 + seconds) * 1e3 + ms;
78050
+ const timestamp2 = (minutes * 60 + seconds) * 1e3 + ms;
78017
78051
  const text = line.replace(TIMESTAMP_REGEX, "").trim();
78018
- syncText.push({ timestamp, text });
78052
+ syncText.push({ timestamp: timestamp2, text });
78019
78053
  }
78020
78054
  }
78021
78055
  return {
@@ -79170,12 +79204,12 @@ function resolveCopier() {
79170
79204
  async function copyToClipboard(text) {
79171
79205
  const opener = resolveCopier();
79172
79206
  if (!opener) return false;
79173
- return new Promise((resolve81) => {
79207
+ return new Promise((resolve83) => {
79174
79208
  let settled = false;
79175
79209
  const finish = (ok) => {
79176
79210
  if (settled) return;
79177
79211
  settled = true;
79178
- resolve81(ok);
79212
+ resolve83(ok);
79179
79213
  };
79180
79214
  try {
79181
79215
  const child = spawn2(opener.command, opener.args, {
@@ -80428,9 +80462,9 @@ init_source();
80428
80462
  init_agent_host_detect();
80429
80463
  init_scene_project();
80430
80464
  init_visual_styles();
80431
- import { existsSync as existsSync40 } from "node:fs";
80432
- import { mkdir as mkdir22, readFile as readFile37, writeFile as writeFile44 } from "node:fs/promises";
80433
- import { basename as basename19, dirname as dirname18, resolve as resolve53 } from "node:path";
80465
+ import { existsSync as existsSync41 } from "node:fs";
80466
+ import { mkdir as mkdir23, readFile as readFile38, writeFile as writeFile45 } from "node:fs/promises";
80467
+ import { basename as basename19, dirname as dirname19, resolve as resolve54 } from "node:path";
80434
80468
 
80435
80469
  // src/commands/_shared/storyboard-draft.ts
80436
80470
  init_scene_project();
@@ -80588,6 +80622,306 @@ function escapeRegExp2(value) {
80588
80622
  init_project_config();
80589
80623
  init_install_skill();
80590
80624
 
80625
+ // src/commands/_shared/host-integration.ts
80626
+ import { existsSync as existsSync40 } from "node:fs";
80627
+ import { mkdir as mkdir22, readFile as readFile37, writeFile as writeFile44 } from "node:fs/promises";
80628
+ import { homedir as homedir6 } from "node:os";
80629
+ import { dirname as dirname18, join as join19, resolve as resolve53 } from "node:path";
80630
+ var HOST_SELECTIONS = [
80631
+ "codex",
80632
+ "claude",
80633
+ "claude-code",
80634
+ "claude-desktop",
80635
+ "cursor",
80636
+ "all"
80637
+ ];
80638
+ var VIBEFRAME_MCP_JSON = {
80639
+ command: "npx",
80640
+ args: ["-y", "@vibeframe/mcp-server"]
80641
+ };
80642
+ var CODEX_MCP_BLOCK = `[mcp_servers.vibeframe]
80643
+ command = "npx"
80644
+ args = ["-y", "@vibeframe/mcp-server"]
80645
+ enabled = true
80646
+ `;
80647
+ var CODEX_MANAGED_START = "# >>> VibeFrame MCP server >>>";
80648
+ var CODEX_MANAGED_END = "# <<< VibeFrame MCP server <<<";
80649
+ function hostDefinitions(_projectDir = process.cwd()) {
80650
+ return [
80651
+ {
80652
+ id: "codex",
80653
+ label: "OpenAI Codex",
80654
+ surfaces: ["shell", "project-guidance", "mcp"],
80655
+ guidanceFiles: ["AGENTS.md"],
80656
+ configPath: (dir) => join19(resolve53(dir), ".codex", "config.toml"),
80657
+ configKind: "codex-toml",
80658
+ notes: [
80659
+ "Codex reads AGENTS.md and can also load project-scoped .codex/config.toml after the project is trusted.",
80660
+ "Keep provider/auth keys in VibeFrame config or environment, not in project-local Codex config."
80661
+ ]
80662
+ },
80663
+ {
80664
+ id: "claude-code",
80665
+ label: "Claude Code",
80666
+ surfaces: ["shell", "project-guidance", "mcp"],
80667
+ guidanceFiles: ["AGENTS.md", "CLAUDE.md", ".claude/skills/hyperframes/"],
80668
+ configPath: (dir) => join19(resolve53(dir), ".mcp.json"),
80669
+ configKind: "mcp-json",
80670
+ notes: [
80671
+ "Claude Code can drive vibe directly through shell plus AGENTS.md/CLAUDE.md.",
80672
+ "The MCP entry is optional and gives Claude Code a typed tool surface."
80673
+ ]
80674
+ },
80675
+ {
80676
+ id: "claude-desktop",
80677
+ label: "Claude Desktop",
80678
+ surfaces: ["mcp"],
80679
+ guidanceFiles: [],
80680
+ configPath: (_dir) => claudeDesktopConfigPath(),
80681
+ configKind: "mcp-json",
80682
+ notes: [
80683
+ "Claude Desktop uses MCP config rather than project shell commands.",
80684
+ "With --write, VibeFrame backs up the existing config before merging."
80685
+ ]
80686
+ },
80687
+ {
80688
+ id: "cursor",
80689
+ label: "Cursor",
80690
+ surfaces: ["shell", "project-guidance", "mcp"],
80691
+ guidanceFiles: ["AGENTS.md", ".cursor/rules/hyperframes.mdc"],
80692
+ configPath: (dir) => join19(resolve53(dir), ".cursor", "mcp.json"),
80693
+ configKind: "mcp-json",
80694
+ notes: [
80695
+ "Cursor can use AGENTS.md/rules for shell-driven work and .cursor/mcp.json for typed MCP tools."
80696
+ ]
80697
+ }
80698
+ ];
80699
+ }
80700
+ function resolveHostSelection(selection) {
80701
+ if (selection === "all") return ["codex", "claude-code", "claude-desktop", "cursor"];
80702
+ if (selection === "claude") return ["claude-code", "claude-desktop"];
80703
+ return [selection];
80704
+ }
80705
+ function vibeframeMcpJson(host, projectDir) {
80706
+ return host.id === "claude-desktop" ? { ...VIBEFRAME_MCP_JSON, cwd: resolve53(projectDir) } : { ...VIBEFRAME_MCP_JSON };
80707
+ }
80708
+ function renderHostSnippet(host, projectDir) {
80709
+ if (host.configKind === "codex-toml") return CODEX_MCP_BLOCK.trimEnd();
80710
+ return JSON.stringify({ mcpServers: { vibeframe: vibeframeMcpJson(host, projectDir) } }, null, 2);
80711
+ }
80712
+ function claudeCodeAddCommand() {
80713
+ return "claude mcp add vibeframe --scope project -- npx -y @vibeframe/mcp-server";
80714
+ }
80715
+ async function planHostSetup(host, projectDir, opts) {
80716
+ const configPath = host.configPath(projectDir);
80717
+ const snippet = renderHostSnippet(host, projectDir);
80718
+ const files = [];
80719
+ const warnings = [];
80720
+ const nextSteps = hostNextSteps(host);
80721
+ for (const relPath of host.guidanceFiles.filter((p) => !p.endsWith("/"))) {
80722
+ const absPath = join19(resolve53(projectDir), relPath);
80723
+ files.push({
80724
+ path: absPath,
80725
+ status: existsSync40(absPath) ? "skipped-exists" : "missing",
80726
+ reason: existsSync40(absPath) ? "already present" : "run vibe init --agent all first"
80727
+ });
80728
+ }
80729
+ if (!opts.write || opts.dryRun) {
80730
+ files.push({
80731
+ path: configPath,
80732
+ status: opts.write ? "would-merge" : "would-write",
80733
+ reason: opts.write ? "dry run" : "snippet only; pass --write to modify"
80734
+ });
80735
+ return { host, snippet, command: host.id === "claude-code" ? claudeCodeAddCommand() : void 0, configPath, files, warnings, nextSteps };
80736
+ }
80737
+ try {
80738
+ const action = host.configKind === "codex-toml" ? await mergeCodexToml(configPath, { force: opts.force === true }) : await mergeMcpJson(configPath, {
80739
+ server: vibeframeMcpJson(host, projectDir),
80740
+ force: opts.force === true,
80741
+ backup: host.id === "claude-desktop"
80742
+ });
80743
+ files.push(action);
80744
+ } catch (error) {
80745
+ warnings.push(error instanceof Error ? error.message : String(error));
80746
+ }
80747
+ return { host, snippet, command: host.id === "claude-code" ? claudeCodeAddCommand() : void 0, configPath, files, warnings, nextSteps };
80748
+ }
80749
+ async function inspectHost(host, projectDir) {
80750
+ const configPath = host.configPath(projectDir);
80751
+ const warnings = [];
80752
+ const nextSteps = hostNextSteps(host);
80753
+ const guidanceFiles = host.guidanceFiles.map((relPath) => {
80754
+ const absPath = relPath.endsWith("/") ? join19(resolve53(projectDir), relPath) : join19(resolve53(projectDir), relPath);
80755
+ return {
80756
+ path: absPath,
80757
+ status: existsSync40(absPath) ? "skipped-exists" : "missing",
80758
+ reason: existsSync40(absPath) ? "present" : "missing"
80759
+ };
80760
+ });
80761
+ let configured = false;
80762
+ if (existsSync40(configPath)) {
80763
+ try {
80764
+ const content = await readFile37(configPath, "utf-8");
80765
+ if (host.configKind === "codex-toml") {
80766
+ configured = /\[mcp_servers\.vibeframe\]/.test(content);
80767
+ } else {
80768
+ const json = JSON.parse(content);
80769
+ configured = hasVibeframeMcpServer(json);
80770
+ const server = readVibeframeMcpServer(json);
80771
+ if (host.id === "claude-desktop" && configured && !server?.cwd) {
80772
+ warnings.push(
80773
+ "Claude Desktop vibeframe MCP config has no cwd; run `vibe host setup claude-desktop <workspace> --write` to anchor relative paths."
80774
+ );
80775
+ }
80776
+ }
80777
+ } catch (error) {
80778
+ warnings.push(error instanceof Error ? error.message : String(error));
80779
+ }
80780
+ }
80781
+ return { host, configPath, configured, guidanceFiles, warnings, nextSteps };
80782
+ }
80783
+ async function mergeMcpJson(configPath, opts) {
80784
+ let root = {};
80785
+ const exists = existsSync40(configPath);
80786
+ if (exists) {
80787
+ const raw = await readFile37(configPath, "utf-8");
80788
+ try {
80789
+ root = raw.trim() ? JSON.parse(raw) : {};
80790
+ } catch (error) {
80791
+ throw new Error(`Invalid JSON in ${configPath}: ${error instanceof Error ? error.message : String(error)}`);
80792
+ }
80793
+ }
80794
+ const mcpServers = typeof root.mcpServers === "object" && root.mcpServers !== null && !Array.isArray(root.mcpServers) ? root.mcpServers : {};
80795
+ if (mcpServers.vibeframe && !opts.force) {
80796
+ const existing = mcpServers.vibeframe;
80797
+ if (canAddMissingCwd(existing, opts.server)) {
80798
+ root.mcpServers = {
80799
+ ...mcpServers,
80800
+ vibeframe: { ...existing, cwd: opts.server.cwd }
80801
+ };
80802
+ await mkdir22(dirname18(configPath), { recursive: true });
80803
+ if (exists && opts.backup) {
80804
+ await writeFile44(`${configPath}.bak-${timestamp()}`, await readFile37(configPath, "utf-8"), "utf-8");
80805
+ }
80806
+ await writeFile44(configPath, JSON.stringify(root, null, 2) + "\n", "utf-8");
80807
+ return { path: configPath, status: "merged", reason: "added cwd to existing vibeframe MCP server" };
80808
+ }
80809
+ return {
80810
+ path: configPath,
80811
+ status: "skipped-exists",
80812
+ reason: "vibeframe MCP server already exists; pass --force to replace"
80813
+ };
80814
+ }
80815
+ root.mcpServers = { ...mcpServers, vibeframe: opts.server };
80816
+ await mkdir22(dirname18(configPath), { recursive: true });
80817
+ if (exists && opts.backup) {
80818
+ await writeFile44(`${configPath}.bak-${timestamp()}`, await readFile37(configPath, "utf-8"), "utf-8");
80819
+ }
80820
+ await writeFile44(configPath, JSON.stringify(root, null, 2) + "\n", "utf-8");
80821
+ return { path: configPath, status: exists ? "merged" : "wrote" };
80822
+ }
80823
+ async function mergeCodexToml(configPath, opts) {
80824
+ const exists = existsSync40(configPath);
80825
+ const block = `${CODEX_MANAGED_START}
80826
+ ${CODEX_MCP_BLOCK}${CODEX_MANAGED_END}`;
80827
+ if (!exists) {
80828
+ await mkdir22(dirname18(configPath), { recursive: true });
80829
+ await writeFile44(configPath, `#:schema https://developers.openai.com/codex/config-schema.json
80830
+
80831
+ ${block}
80832
+ `, "utf-8");
80833
+ return { path: configPath, status: "wrote" };
80834
+ }
80835
+ const raw = await readFile37(configPath, "utf-8");
80836
+ if (raw.includes(CODEX_MANAGED_START)) {
80837
+ const updated = raw.replace(
80838
+ new RegExp(`${escapeRegExp3(CODEX_MANAGED_START)}[\\s\\S]*?${escapeRegExp3(CODEX_MANAGED_END)}`),
80839
+ block
80840
+ );
80841
+ await writeFile44(configPath, ensureTrailingNewline(updated), "utf-8");
80842
+ return { path: configPath, status: "merged", reason: "updated managed VibeFrame block" };
80843
+ }
80844
+ if (/\[mcp_servers\.vibeframe\]/.test(raw)) {
80845
+ if (!opts.force) {
80846
+ return {
80847
+ path: configPath,
80848
+ status: "skipped-exists",
80849
+ reason: "vibeframe MCP table already exists; pass --force to replace"
80850
+ };
80851
+ }
80852
+ const updated = raw.replace(/\n?\[mcp_servers\.vibeframe\][\s\S]*?(?=\n\[|$)/, `
80853
+ ${block}
80854
+ `);
80855
+ await writeFile44(configPath, ensureTrailingNewline(updated), "utf-8");
80856
+ return { path: configPath, status: "merged", reason: "replaced existing VibeFrame MCP table" };
80857
+ }
80858
+ await writeFile44(configPath, `${ensureTrailingNewline(raw)}
80859
+ ${block}
80860
+ `, "utf-8");
80861
+ return { path: configPath, status: "merged" };
80862
+ }
80863
+ function hasVibeframeMcpServer(value) {
80864
+ if (!value || typeof value !== "object") return false;
80865
+ const root = value;
80866
+ if (!root.mcpServers || typeof root.mcpServers !== "object") return false;
80867
+ return Object.prototype.hasOwnProperty.call(root.mcpServers, "vibeframe");
80868
+ }
80869
+ function readVibeframeMcpServer(value) {
80870
+ if (!value || typeof value !== "object") return null;
80871
+ const root = value;
80872
+ if (!root.mcpServers || typeof root.mcpServers !== "object" || Array.isArray(root.mcpServers)) return null;
80873
+ const server = root.mcpServers.vibeframe;
80874
+ if (!server || typeof server !== "object" || Array.isArray(server)) return null;
80875
+ return server;
80876
+ }
80877
+ function canAddMissingCwd(existing, target) {
80878
+ if (!target.cwd) return false;
80879
+ if (!existing || typeof existing !== "object" || Array.isArray(existing)) return false;
80880
+ const current = existing;
80881
+ if (current.cwd) return false;
80882
+ if (current.command !== target.command) return false;
80883
+ if (!Array.isArray(current.args)) return false;
80884
+ return JSON.stringify(current.args) === JSON.stringify(target.args);
80885
+ }
80886
+ function hostNextSteps(host) {
80887
+ if (host.id === "codex") {
80888
+ return [
80889
+ "Trust the project in Codex so .codex/config.toml is loaded.",
80890
+ "Run /mcp in Codex to confirm the vibeframe server is connected."
80891
+ ];
80892
+ }
80893
+ if (host.id === "claude-code") {
80894
+ return [
80895
+ "Restart Claude Code or run /mcp to approve the project-scoped server.",
80896
+ "Use AGENTS.md/CLAUDE.md for shell-driven vibe workflows."
80897
+ ];
80898
+ }
80899
+ if (host.id === "claude-desktop") {
80900
+ return ["Restart Claude Desktop after updating its MCP config."];
80901
+ }
80902
+ return ["Restart Cursor or reload MCP servers, then ask Cursor to use the vibeframe MCP tools."];
80903
+ }
80904
+ function claudeDesktopConfigPath() {
80905
+ const home = homedir6();
80906
+ if (process.platform === "darwin") {
80907
+ return join19(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
80908
+ }
80909
+ if (process.platform === "win32") {
80910
+ return join19(process.env.APPDATA ?? join19(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
80911
+ }
80912
+ return join19(home, ".config", "Claude", "claude_desktop_config.json");
80913
+ }
80914
+ function timestamp() {
80915
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
80916
+ }
80917
+ function ensureTrailingNewline(value) {
80918
+ return value.endsWith("\n") ? value : `${value}
80919
+ `;
80920
+ }
80921
+ function escapeRegExp3(value) {
80922
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
80923
+ }
80924
+
80591
80925
  // src/commands/_shared/init-templates.ts
80592
80926
  var AGENTS_MD = `# AGENTS.md
80593
80927
 
@@ -80628,6 +80962,8 @@ vibe schema --list # full machine-readable catalog (80+)
80628
80962
  vibe schema --list --surface public # small first-run/product command surface
80629
80963
  vibe schema generate.video # JSON Schema for any single command
80630
80964
  vibe doctor # available providers + system health
80965
+ vibe host setup all # print Codex/Claude/Cursor app integration snippets
80966
+ vibe host doctor all --json # verify project guidance + MCP config
80631
80967
  vibe guide motion # choose text-overlay vs motion-overlay vs generate motion
80632
80968
  vibe guide scene # step-by-step authoring guide (scene)
80633
80969
  vibe guide pipeline # step-by-step authoring guide (pipeline)
@@ -80752,6 +81088,22 @@ unless the user explicitly asks for a non-VibeFrame asset.
80752
81088
  \`.env\` is still supported as a gitignored fallback. Copy \`.env.example\`
80753
81089
  to start if you prefer environment variables.
80754
81090
 
81091
+ ## App host setup
81092
+
81093
+ VibeFrame is CLI-first, not terminal-only. Codex, Claude Code, and Cursor can
81094
+ drive the same project through shell commands, and app hosts can also use
81095
+ VibeFrame's MCP server as a typed tool surface.
81096
+
81097
+ \`\`\`bash
81098
+ vibe host setup all # print snippets only
81099
+ vibe host setup all --write # write project/app config
81100
+ vibe host doctor all --json # verify readiness
81101
+ \`\`\`
81102
+
81103
+ Default setup is snippet-only; use \`--write\` when you want VibeFrame to merge
81104
+ the generated config. Keep provider keys in \`.vibeframe/config.yaml\`, user
81105
+ config, or env files \u2014 not in app host config.
81106
+
80755
81107
  ### Composition rules (scene HTML)
80756
81108
 
80757
81109
  \`vibe init\` installs local composition rules into your project. The
@@ -80942,7 +81294,7 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
80942
81294
  ).option(
80943
81295
  "--from <brief>",
80944
81296
  "Draft STORYBOARD.md and DESIGN.md from a brief string or text/markdown file"
80945
- ).option("-r, --ratio <ratio>", "Scene aspect ratio: 16:9, 9:16, 1:1, 4:5", "16:9").option("-d, --duration <sec>", "Default scene/root duration in seconds", "10").option("--visual-style <name>", "Seed scene DESIGN.md from a named style").option("--agent <id>", `Agent target: ${VALID_AGENTS.join(" | ")}`, "auto").option("--force", "Overwrite existing files instead of skipping").option("--dry-run", "Print the file list without writing anything").action(async (projectDirArg, options) => {
81297
+ ).option("-r, --ratio <ratio>", "Scene aspect ratio: 16:9, 9:16, 1:1, 4:5", "16:9").option("-d, --duration <sec>", "Default scene/root duration in seconds", "10").option("--visual-style <name>", "Seed scene DESIGN.md from a named style").option("--agent <id>", `Agent target: ${VALID_AGENTS.join(" | ")}`, "auto").option("--mcp", "Also write project-scoped MCP config for Codex/Claude Code/Cursor").option("--force", "Overwrite existing files instead of skipping").option("--dry-run", "Print the file list without writing anything").action(async (projectDirArg, options) => {
80946
81298
  const startedAt = Date.now();
80947
81299
  const initType = String(options.type ?? "scene");
80948
81300
  if (initType !== "scene" && initType !== "agent") {
@@ -80958,14 +81310,14 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
80958
81310
  usageError(`Invalid --agent: ${agent}`, `Must be one of: ${VALID_AGENTS.join(", ")}`)
80959
81311
  );
80960
81312
  }
80961
- const projectDir = resolve53(projectDirArg);
81313
+ const projectDir = resolve54(projectDirArg);
80962
81314
  const projectName = basename19(projectDir);
80963
81315
  const targetHosts = resolveTargets(agent);
80964
81316
  const wantsClaude = targetHosts.includes("claude-code");
80965
81317
  const wantsGemini = targetHosts.includes("gemini-cli");
80966
81318
  const wantsCrossTool = targetHosts.some((h) => h !== "claude-code");
80967
81319
  const actions = [];
80968
- if (!existsSync40(projectDir)) {
81320
+ if (!existsSync41(projectDir)) {
80969
81321
  if (options.dryRun) {
80970
81322
  actions.push({
80971
81323
  path: projectDir,
@@ -80973,13 +81325,13 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
80973
81325
  reason: "(would create directory)"
80974
81326
  });
80975
81327
  } else {
80976
- await mkdir22(projectDir, { recursive: true });
81328
+ await mkdir23(projectDir, { recursive: true });
80977
81329
  }
80978
81330
  }
80979
81331
  if (wantsCrossTool || !wantsClaude) {
80980
81332
  actions.push(
80981
81333
  await writeIfMissing(
80982
- resolve53(projectDir, "AGENTS.md"),
81334
+ resolve54(projectDir, "AGENTS.md"),
80983
81335
  AGENTS_MD,
80984
81336
  options.force,
80985
81337
  options.dryRun
@@ -80989,7 +81341,7 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
80989
81341
  if (wantsClaude) {
80990
81342
  actions.push(
80991
81343
  await writeIfMissing(
80992
- resolve53(projectDir, "CLAUDE.md"),
81344
+ resolve54(projectDir, "CLAUDE.md"),
80993
81345
  CLAUDE_MD,
80994
81346
  options.force,
80995
81347
  options.dryRun
@@ -80999,7 +81351,7 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
80999
81351
  if (wantsGemini) {
81000
81352
  actions.push(
81001
81353
  await writeIfMissing(
81002
- resolve53(projectDir, "GEMINI.md"),
81354
+ resolve54(projectDir, "GEMINI.md"),
81003
81355
  GEMINI_MD,
81004
81356
  options.force,
81005
81357
  options.dryRun
@@ -81008,18 +81360,18 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
81008
81360
  }
81009
81361
  actions.push(
81010
81362
  await writeIfMissing(
81011
- resolve53(projectDir, ".env.example"),
81363
+ resolve54(projectDir, ".env.example"),
81012
81364
  renderEnvExample(),
81013
81365
  options.force,
81014
81366
  options.dryRun
81015
81367
  )
81016
81368
  );
81017
81369
  actions.push(
81018
- await mergeGitignore(resolve53(projectDir, ".gitignore"), GITIGNORE_ADDITIONS, options.dryRun)
81370
+ await mergeGitignore(resolve54(projectDir, ".gitignore"), GITIGNORE_ADDITIONS, options.dryRun)
81019
81371
  );
81020
81372
  actions.push(
81021
81373
  await writeIfMissing(
81022
- resolve53(projectDir, VIBE_CONFIG_FILENAME),
81374
+ resolve54(projectDir, VIBE_CONFIG_FILENAME),
81023
81375
  projectConfigJson({ name: projectName }),
81024
81376
  options.force,
81025
81377
  options.dryRun
@@ -81027,12 +81379,20 @@ var initCommand = new Command("init").description("Scaffold a VibeFrame project
81027
81379
  );
81028
81380
  actions.push(
81029
81381
  await writeIfMissing(
81030
- resolve53(projectDir, "vibe.project.yaml"),
81382
+ resolve54(projectDir, "vibe.project.yaml"),
81031
81383
  renderProjectYaml({ name: projectName }),
81032
81384
  options.force,
81033
81385
  options.dryRun
81034
81386
  )
81035
81387
  );
81388
+ if (options.mcp === true) {
81389
+ actions.push(
81390
+ ...await setupProjectMcpTargets(projectDir, targetHosts, {
81391
+ force: options.force === true,
81392
+ dryRun: options.dryRun === true
81393
+ })
81394
+ );
81395
+ }
81036
81396
  if (isJsonMode()) {
81037
81397
  outputSuccess({
81038
81398
  command: "init",
@@ -81117,7 +81477,7 @@ async function runSceneInit(projectDirArg, options, startedAt) {
81117
81477
  )
81118
81478
  );
81119
81479
  }
81120
- const projectDir = resolve53(projectDirArg);
81480
+ const projectDir = resolve54(projectDirArg);
81121
81481
  const projectName = basename19(projectDir);
81122
81482
  const groups = describeSceneScaffold({ dir: projectDir, profile });
81123
81483
  const fromBrief = typeof options.from === "string" && options.from.trim() ? await readBriefOrLiteral(String(options.from), process.cwd()) : null;
@@ -81170,14 +81530,14 @@ async function runSceneInit(projectDirArg, options, startedAt) {
81170
81530
  aspect,
81171
81531
  visualStyle
81172
81532
  });
81173
- const storyboardPath2 = resolve53(projectDir, "STORYBOARD.md");
81174
- const designPath = resolve53(projectDir, "DESIGN.md");
81175
- if (options.force || result.created.includes(storyboardPath2) || !existsSync40(storyboardPath2)) {
81176
- await writeFile44(storyboardPath2, draft.storyboardMd, "utf-8");
81533
+ const storyboardPath2 = resolve54(projectDir, "STORYBOARD.md");
81534
+ const designPath = resolve54(projectDir, "DESIGN.md");
81535
+ if (options.force || result.created.includes(storyboardPath2) || !existsSync41(storyboardPath2)) {
81536
+ await writeFile45(storyboardPath2, draft.storyboardMd, "utf-8");
81177
81537
  if (!result.created.includes(storyboardPath2)) result.created.push(storyboardPath2);
81178
81538
  }
81179
- if (options.force || result.created.includes(designPath) || !existsSync40(designPath)) {
81180
- await writeFile44(designPath, draft.designMd, "utf-8");
81539
+ if (options.force || result.created.includes(designPath) || !existsSync41(designPath)) {
81540
+ await writeFile45(designPath, draft.designMd, "utf-8");
81181
81541
  if (!result.created.includes(designPath)) result.created.push(designPath);
81182
81542
  }
81183
81543
  draftWarnings.push(...draft.warnings);
@@ -81187,6 +81547,10 @@ async function runSceneInit(projectDirArg, options, startedAt) {
81187
81547
  projectDir,
81188
81548
  hosts: deriveInstallHosts(detectedIds)
81189
81549
  }) : { success: true, files: [], bundleVersion: "not-installed" };
81550
+ const mcpActions = options.mcp === true ? await setupProjectMcpTargets(projectDir, detectedIds, {
81551
+ force: options.force === true,
81552
+ dryRun: false
81553
+ }) : [];
81190
81554
  if (isJsonMode()) {
81191
81555
  outputSuccess({
81192
81556
  command: "init",
@@ -81206,6 +81570,7 @@ async function runSceneInit(projectDirArg, options, startedAt) {
81206
81570
  groups: result.groups,
81207
81571
  skillFiles: skillResult.files,
81208
81572
  skillBundleVersion: skillResult.bundleVersion,
81573
+ mcpFiles: mcpActions,
81209
81574
  warnings: draftWarnings
81210
81575
  }
81211
81576
  });
@@ -81243,6 +81608,10 @@ async function runSceneInit(projectDirArg, options, startedAt) {
81243
81608
  for (const f of skillResult.files.filter((f2) => f2.status === "wrote")) {
81244
81609
  console.log(source_default.green(` + ${f.path.replace(projectDir + "/", "")}`));
81245
81610
  }
81611
+ for (const f of mcpActions) {
81612
+ const icon = f.status === "wrote" || f.status === "merged" ? source_default.green("+") : source_default.dim("\xB7");
81613
+ console.log(`${icon} ${f.path.replace(projectDir + "/", "")} ${source_default.dim(`(${f.status})`)}`);
81614
+ }
81246
81615
  console.log();
81247
81616
  console.log(source_default.dim(`Tip: cd ${projectDirArg} before running the next commands.`));
81248
81617
  console.log();
@@ -81290,9 +81659,9 @@ function printGroup(label, files, projectDir) {
81290
81659
  }
81291
81660
  }
81292
81661
  async function readBriefOrLiteral(value, cwd) {
81293
- const candidate = resolve53(cwd, value);
81294
- if (existsSync40(candidate)) {
81295
- return readFile37(candidate, "utf-8");
81662
+ const candidate = resolve54(cwd, value);
81663
+ if (existsSync41(candidate)) {
81664
+ return readFile38(candidate, "utf-8");
81296
81665
  }
81297
81666
  return value;
81298
81667
  }
@@ -81311,32 +81680,65 @@ function resolveTargets(agent) {
81311
81680
  }
81312
81681
  return [agent];
81313
81682
  }
81683
+ async function setupProjectMcpTargets(projectDir, targetHosts, opts) {
81684
+ const ids = /* @__PURE__ */ new Set();
81685
+ if (targetHosts.includes("codex")) ids.add("codex");
81686
+ if (targetHosts.includes("claude-code")) ids.add("claude-code");
81687
+ if (targetHosts.includes("cursor")) ids.add("cursor");
81688
+ if (targetHosts.length === 0) {
81689
+ ids.add("codex");
81690
+ ids.add("claude-code");
81691
+ ids.add("cursor");
81692
+ }
81693
+ const actions = [];
81694
+ for (const host of hostDefinitions(projectDir).filter((h) => ids.has(h.id))) {
81695
+ const plan = await planHostSetup(host, projectDir, {
81696
+ write: true,
81697
+ dryRun: opts.dryRun,
81698
+ force: opts.force
81699
+ });
81700
+ const configAction = plan.files.find((file) => file.path === plan.configPath);
81701
+ if (!configAction) continue;
81702
+ actions.push({
81703
+ path: configAction.path,
81704
+ status: normalizeHostAction(configAction.status),
81705
+ reason: configAction.reason
81706
+ });
81707
+ }
81708
+ return actions;
81709
+ }
81710
+ function normalizeHostAction(status) {
81711
+ if (status === "merged") return "merged";
81712
+ if (status === "wrote") return "wrote";
81713
+ if (status === "skipped-exists") return "skipped-exists";
81714
+ return "would-write";
81715
+ }
81314
81716
  async function writeIfMissing(absPath, content, force, dryRun) {
81315
- const exists = existsSync40(absPath);
81717
+ const exists = existsSync41(absPath);
81316
81718
  if (exists && !force) {
81317
81719
  return { path: absPath, status: "skipped-exists", reason: "(use --force to overwrite)" };
81318
81720
  }
81319
81721
  if (dryRun) {
81320
81722
  return { path: absPath, status: "would-write" };
81321
81723
  }
81322
- await mkdir22(dirname18(absPath), { recursive: true });
81323
- await writeFile44(absPath, content, "utf-8");
81724
+ await mkdir23(dirname19(absPath), { recursive: true });
81725
+ await writeFile45(absPath, content, "utf-8");
81324
81726
  return { path: absPath, status: "wrote" };
81325
81727
  }
81326
81728
  async function mergeGitignore(absPath, additions, dryRun) {
81327
81729
  const marker = "# VibeFrame";
81328
- if (!existsSync40(absPath)) {
81730
+ if (!existsSync41(absPath)) {
81329
81731
  if (dryRun) return { path: absPath, status: "would-write" };
81330
- await writeFile44(absPath, additions.trimStart(), "utf-8");
81732
+ await writeFile45(absPath, additions.trimStart(), "utf-8");
81331
81733
  return { path: absPath, status: "wrote" };
81332
81734
  }
81333
- const existing = await readFile37(absPath, "utf-8");
81735
+ const existing = await readFile38(absPath, "utf-8");
81334
81736
  if (existing.includes(marker)) {
81335
81737
  return { path: absPath, status: "skipped-exists", reason: "(already has VibeFrame block)" };
81336
81738
  }
81337
81739
  if (dryRun) return { path: absPath, status: "merged" };
81338
81740
  const trailing = existing.endsWith("\n") ? "" : "\n";
81339
- await writeFile44(absPath, existing + trailing + additions, "utf-8");
81741
+ await writeFile45(absPath, existing + trailing + additions, "utf-8");
81340
81742
  return { path: absPath, status: "merged" };
81341
81743
  }
81342
81744
  function formatStatusIcon(status) {
@@ -81363,9 +81765,9 @@ init_storyboard_revise();
81363
81765
  init_composer_resolve();
81364
81766
  init_cost_tier();
81365
81767
  init_output();
81366
- import { readFile as readFile39, writeFile as writeFile46 } from "node:fs/promises";
81367
- import { existsSync as existsSync42 } from "node:fs";
81368
- import { resolve as resolve55 } from "node:path";
81768
+ import { readFile as readFile40, writeFile as writeFile47 } from "node:fs/promises";
81769
+ import { existsSync as existsSync43 } from "node:fs";
81770
+ import { resolve as resolve56 } from "node:path";
81369
81771
  var storyboardCommand = new Command("storyboard").description("Read, validate, and safely mutate STORYBOARD.md cue blocks").addHelpText("after", `
81370
81772
  Examples:
81371
81773
  $ vibe storyboard validate my-video --json
@@ -81377,7 +81779,7 @@ Examples:
81377
81779
  `);
81378
81780
  storyboardCommand.command("list").description("List beats, ids, cues, and durations from STORYBOARD.md").argument("[project-dir]", "Project directory", ".").action(async (projectDirArg) => {
81379
81781
  const startedAt = Date.now();
81380
- const projectDir = resolve55(projectDirArg);
81782
+ const projectDir = resolve56(projectDirArg);
81381
81783
  const md = await readStoryboard(projectDir);
81382
81784
  const parsed = parseStoryboard(md);
81383
81785
  const data = {
@@ -81399,7 +81801,7 @@ storyboardCommand.command("list").description("List beats, ids, cues, and durati
81399
81801
  });
81400
81802
  storyboardCommand.command("get").description("Print one beat as structured JSON").argument("<project-dir>", "Project directory").argument("<beat>", "Beat id").action(async (projectDirArg, beatId) => {
81401
81803
  const startedAt = Date.now();
81402
- const projectDir = resolve55(projectDirArg);
81804
+ const projectDir = resolve56(projectDirArg);
81403
81805
  const md = await readStoryboard(projectDir);
81404
81806
  const beat = getStoryboardBeat(md, beatId);
81405
81807
  if (!beat) {
@@ -81422,7 +81824,7 @@ storyboardCommand.command("get").description("Print one beat as structured JSON"
81422
81824
  });
81423
81825
  storyboardCommand.command("set").description("Update one cue in one beat without raw Markdown editing").argument("<project-dir>", "Project directory").argument("<beat>", "Beat id").argument("<key>", `Cue key: ${STORYBOARD_CUE_KEYS.join(" | ")}`).argument("[value...]", "Cue value. Use --json-value to pass a JSON scalar/object.").option("--json-value", "Parse value as JSON instead of a string").option("--unset", "Remove the cue key from the beat").action(async (projectDirArg, beatId, key, valueParts, options) => {
81424
81826
  const startedAt = Date.now();
81425
- const projectDir = resolve55(projectDirArg);
81827
+ const projectDir = resolve56(projectDirArg);
81426
81828
  if (!options.unset && (!valueParts || valueParts.length === 0)) {
81427
81829
  exitWithError(usageError("Cue value is required unless --unset is passed."));
81428
81830
  }
@@ -81441,7 +81843,7 @@ storyboardCommand.command("set").description("Update one cue in one beat without
81441
81843
  } catch (error) {
81442
81844
  exitWithError(usageError(error instanceof Error ? error.message : String(error)));
81443
81845
  }
81444
- await writeFile46(storyboardPath(projectDir), next, "utf-8");
81846
+ await writeFile47(storyboardPath(projectDir), next, "utf-8");
81445
81847
  const beat = getStoryboardBeat(next, beatId);
81446
81848
  outputSuccess({
81447
81849
  command: "storyboard set",
@@ -81457,7 +81859,7 @@ storyboardCommand.command("set").description("Update one cue in one beat without
81457
81859
  });
81458
81860
  storyboardCommand.command("move").description("Reorder beats safely").argument("<project-dir>", "Project directory").argument("<beat>", "Beat id to move").requiredOption("--after <beat>", "Place the beat after this beat id").action(async (projectDirArg, beatId, options) => {
81459
81861
  const startedAt = Date.now();
81460
- const projectDir = resolve55(projectDirArg);
81862
+ const projectDir = resolve56(projectDirArg);
81461
81863
  const md = await readStoryboard(projectDir);
81462
81864
  let next;
81463
81865
  try {
@@ -81465,7 +81867,7 @@ storyboardCommand.command("move").description("Reorder beats safely").argument("
81465
81867
  } catch (error) {
81466
81868
  exitWithError(usageError(error instanceof Error ? error.message : String(error)));
81467
81869
  }
81468
- await writeFile46(storyboardPath(projectDir), next, "utf-8");
81870
+ await writeFile47(storyboardPath(projectDir), next, "utf-8");
81469
81871
  const parsed = parseStoryboard(next);
81470
81872
  outputSuccess({
81471
81873
  command: "storyboard move",
@@ -81480,7 +81882,7 @@ storyboardCommand.command("move").description("Reorder beats safely").argument("
81480
81882
  });
81481
81883
  storyboardCommand.command("revise").description("Revise STORYBOARD.md from a request or source file").argument("<project-dir>", "Project directory").requiredOption("--from <brief>", "Revision request or path to a text/markdown file").option("-d, --duration <sec>", "Target total duration in seconds").option("--composer <provider>", "Revision LLM provider: claude|openai|gemini").option("--dry-run", "Preview the revised storyboard without writing").action(async (projectDirArg, options) => {
81482
81884
  const startedAt = Date.now();
81483
- const projectDir = resolve55(projectDirArg);
81885
+ const projectDir = resolve56(projectDirArg);
81484
81886
  const brief = await readBrief(options.from, process.cwd());
81485
81887
  const duration = options.duration ? Number.parseFloat(options.duration) : void 0;
81486
81888
  if (duration !== void 0 && (!Number.isFinite(duration) || duration <= 0)) {
@@ -81512,7 +81914,7 @@ storyboardCommand.command("revise").description("Revise STORYBOARD.md from a req
81512
81914
  });
81513
81915
  storyboardCommand.command("validate").description("Validate cue blocks and beat ids").argument("[project-dir]", "Project directory", ".").action(async (projectDirArg) => {
81514
81916
  const startedAt = Date.now();
81515
- const projectDir = resolve55(projectDirArg);
81917
+ const projectDir = resolve56(projectDirArg);
81516
81918
  const md = await readStoryboard(projectDir);
81517
81919
  const result = validateStoryboardMarkdown(md);
81518
81920
  if (isJsonMode()) {
@@ -81547,13 +81949,13 @@ storyboardCommand.command("validate").description("Validate cue blocks and beat
81547
81949
  });
81548
81950
  async function readStoryboard(projectDir) {
81549
81951
  const path2 = storyboardPath(projectDir);
81550
- if (!existsSync42(path2)) {
81952
+ if (!existsSync43(path2)) {
81551
81953
  exitWithError(generalError(`STORYBOARD.md not found at ${path2}`, `Run 'vibe init ${projectDir} --from "<brief>"' first.`));
81552
81954
  }
81553
- return readFile39(path2, "utf-8");
81955
+ return readFile40(path2, "utf-8");
81554
81956
  }
81555
81957
  function storyboardPath(projectDir) {
81556
- return resolve55(projectDir, "STORYBOARD.md");
81958
+ return resolve56(projectDir, "STORYBOARD.md");
81557
81959
  }
81558
81960
  function parseComposer(value) {
81559
81961
  if (value === void 0) return void 0;
@@ -81561,9 +81963,9 @@ function parseComposer(value) {
81561
81963
  exitWithError(usageError(`Invalid --composer: ${value}`, "Must be one of: claude, openai, gemini"));
81562
81964
  }
81563
81965
  async function readBrief(value, cwd) {
81564
- const candidate = resolve55(cwd, value);
81565
- if (existsSync42(candidate)) {
81566
- return readFile39(candidate, "utf-8");
81966
+ const candidate = resolve56(cwd, value);
81967
+ if (existsSync43(candidate)) {
81968
+ return readFile40(candidate, "utf-8");
81567
81969
  }
81568
81970
  return value;
81569
81971
  }
@@ -81596,7 +81998,7 @@ init_esm();
81596
81998
  init_source();
81597
81999
  init_build_plan();
81598
82000
  init_output();
81599
- import { resolve as resolve58 } from "node:path";
82001
+ import { resolve as resolve59 } from "node:path";
81600
82002
  var VALID_STAGES = ["assets", "compose", "sync", "render", "all"];
81601
82003
  var VALID_MODES = ["agent", "batch", "auto"];
81602
82004
  var VALID_TTS_PROVIDERS = ["auto", "elevenlabs", "kokoro"];
@@ -81644,7 +82046,7 @@ var planCommand = new Command("plan").description("Read STORYBOARD.md and show b
81644
82046
  )
81645
82047
  );
81646
82048
  }
81647
- const projectDir = resolve58(projectDirArg);
82049
+ const projectDir = resolve59(projectDirArg);
81648
82050
  const plan = await createBuildPlan({
81649
82051
  projectDir,
81650
82052
  stage,
@@ -81789,8 +82191,8 @@ init_scene_build();
81789
82191
  init_build_plan();
81790
82192
  init_storyboard_parse();
81791
82193
  init_output();
81792
- import { resolve as resolve63, join as join23 } from "node:path";
81793
- import { readFileSync as readFileSync3, existsSync as existsSync47 } from "node:fs";
82194
+ import { resolve as resolve64, join as join24 } from "node:path";
82195
+ import { readFileSync as readFileSync3, existsSync as existsSync48 } from "node:fs";
81794
82196
  var VALID_MODES2 = ["agent", "batch", "auto"];
81795
82197
  var VALID_STAGES2 = ["assets", "compose", "sync", "render", "all"];
81796
82198
  var VALID_IMAGE_PROVIDERS2 = ["openai", "gemini", "grok"];
@@ -81807,7 +82209,7 @@ Examples:
81807
82209
  Advanced equivalent: \`vibe scene build\`.`
81808
82210
  ).action(async (projectDirArg, options) => {
81809
82211
  const startedAt = Date.now();
81810
- const projectDir = resolve63(projectDirArg);
82212
+ const projectDir = resolve64(projectDirArg);
81811
82213
  const mode = String(options.mode ?? "auto");
81812
82214
  if (!VALID_MODES2.includes(mode)) {
81813
82215
  exitWithError(
@@ -82153,8 +82555,8 @@ function buildPlanValidationFailureData(plan) {
82153
82555
  };
82154
82556
  }
82155
82557
  function estimateBuildCost(params) {
82156
- const storyboardPath2 = join23(params.projectDir, "STORYBOARD.md");
82157
- if (!existsSync47(storyboardPath2)) return null;
82558
+ const storyboardPath2 = join24(params.projectDir, "STORYBOARD.md");
82559
+ if (!existsSync48(storyboardPath2)) return null;
82158
82560
  let beats = 0;
82159
82561
  try {
82160
82562
  const md = readFileSync3(storyboardPath2, "utf-8");
@@ -82298,7 +82700,7 @@ init_source();
82298
82700
  init_ora();
82299
82701
  init_scene_render();
82300
82702
  init_output();
82301
- import { resolve as resolve64 } from "node:path";
82703
+ import { resolve as resolve65 } from "node:path";
82302
82704
  var VALID_FPS = [24, 30, 60];
82303
82705
  var VALID_QUALITIES = ["draft", "standard", "high"];
82304
82706
  var VALID_FORMATS = ["mp4", "webm", "mov"];
@@ -82309,7 +82711,7 @@ Examples:
82309
82711
 
82310
82712
  Alias note: this is the project-level entrypoint for \`vibe scene render\`.`).action(async (projectDirArg, options) => {
82311
82713
  const startedAt = Date.now();
82312
- const projectDir = resolve64(projectDirArg);
82714
+ const projectDir = resolve65(projectDirArg);
82313
82715
  const fps = parseFps(String(options.fps));
82314
82716
  const quality = parseQuality(String(options.quality));
82315
82717
  const format = parseFormat(String(options.format));
@@ -82432,7 +82834,7 @@ init_source();
82432
82834
  init_cost_tier();
82433
82835
  init_status_jobs();
82434
82836
  init_output();
82435
- import { resolve as resolve65 } from "node:path";
82837
+ import { resolve as resolve66 } from "node:path";
82436
82838
  var statusCommand = new Command("status").description("Inspect local async jobs and project workflow status").addHelpText("after", `
82437
82839
  Examples:
82438
82840
  $ vibe status job job_abc123 --json
@@ -82443,7 +82845,7 @@ Examples:
82443
82845
  statusCommand.command("job").description("Show one async job status").argument("<job-id>", "Local job id from a no-wait command").option("--project <dir>", "Project directory containing .vibeframe/jobs").option("--no-refresh", "Read local job record only; do not call provider APIs").option("--wait", "Wait for completion when the provider status helper supports it").option("-o, --output <path>", "Download result media when complete").action(async (jobId, options) => {
82444
82846
  const startedAt = Date.now();
82445
82847
  try {
82446
- const projectDir = options.project ? resolve65(options.project) : findProjectRoot();
82848
+ const projectDir = options.project ? resolve66(options.project) : findProjectRoot();
82447
82849
  const record = await readJobRecord(jobId, projectDir);
82448
82850
  if (!record) {
82449
82851
  exitWithError(generalError(`Job not found: ${jobId}`, `Run 'vibe status project ${projectDir} --json' to list known jobs.`));
@@ -82471,7 +82873,7 @@ applyTier(statusCommand.commands[statusCommand.commands.length - 1], "free");
82471
82873
  statusCommand.command("project").description("Summarize build, review, and async job status for a project").argument("[project-dir]", "VibeFrame project directory", ".").option("--refresh", "Refresh active supported jobs before summarizing").action(async (projectDirArg, options) => {
82472
82874
  const startedAt = Date.now();
82473
82875
  try {
82474
- const result = await inspectProjectStatus(resolve65(projectDirArg), {
82876
+ const result = await inspectProjectStatus(resolve66(projectDirArg), {
82475
82877
  refresh: options.refresh === true
82476
82878
  });
82477
82879
  if (isJsonMode()) {
@@ -82567,8 +82969,8 @@ init_composer_resolve();
82567
82969
  init_cost_tier();
82568
82970
  init_scene_build_mode();
82569
82971
  init_output();
82570
- import { existsSync as existsSync48 } from "node:fs";
82571
- import { resolve as resolve66 } from "node:path";
82972
+ import { existsSync as existsSync49 } from "node:fs";
82973
+ import { resolve as resolve67 } from "node:path";
82572
82974
  var COMMAND_KEY_MAP = getCommandKeyMap();
82573
82975
  var FREE_COMMANDS = [
82574
82976
  "edit silence-cut",
@@ -82695,14 +83097,14 @@ async function runDiagnostics() {
82695
83097
  installed = false;
82696
83098
  }
82697
83099
  } else if (toolName === "chrome") {
82698
- const { existsSync: existsSync54 } = await import("node:fs");
82699
- const { homedir: homedir6 } = await import("node:os");
82700
- const { join: join26 } = await import("node:path");
83100
+ const { existsSync: existsSync55 } = await import("node:fs");
83101
+ const { homedir: homedir7 } = await import("node:os");
83102
+ const { join: join27 } = await import("node:path");
82701
83103
  const chromePaths = [
82702
83104
  process.env.HYPERFRAMES_CHROME_PATH,
82703
83105
  process.env.CHROME_PATH,
82704
- join26(
82705
- homedir6(),
83106
+ join27(
83107
+ homedir7(),
82706
83108
  ".cache",
82707
83109
  "puppeteer",
82708
83110
  "chrome-headless-shell",
@@ -82716,7 +83118,7 @@ async function runDiagnostics() {
82716
83118
  "/usr/bin/chromium",
82717
83119
  "/usr/bin/chromium-browser"
82718
83120
  ];
82719
- installed = chromePaths.some((p) => p && existsSync54(p));
83121
+ installed = chromePaths.some((p) => p && existsSync55(p));
82720
83122
  } else {
82721
83123
  installed = commandExists(toolName);
82722
83124
  }
@@ -82756,7 +83158,7 @@ async function runDiagnostics() {
82756
83158
  }
82757
83159
  const projectFiles = ["AGENTS.md", "CLAUDE.md", "vibe.project.yaml"].map((rel) => ({
82758
83160
  path: rel,
82759
- exists: existsSync48(resolve66(cwd, rel))
83161
+ exists: existsSync49(resolve67(cwd, rel))
82760
83162
  }));
82761
83163
  const projectInitialized = projectFiles.some((f) => f.exists);
82762
83164
  const nearestProjectConfigPath = await findProjectConfigPath(cwd);
@@ -82775,8 +83177,8 @@ async function runDiagnostics() {
82775
83177
  } catch (err) {
82776
83178
  if (!(err instanceof ComposerResolveError)) throw err;
82777
83179
  }
82778
- const sceneProjectInCwd = existsSync48(resolve66(cwd, "STORYBOARD.md"));
82779
- const skillInstalled = existsSync48(resolve66(cwd, "SKILL.md"));
83180
+ const sceneProjectInCwd = existsSync49(resolve67(cwd, "STORYBOARD.md"));
83181
+ const skillInstalled = existsSync49(resolve67(cwd, "SKILL.md"));
82780
83182
  return {
82781
83183
  system: {
82782
83184
  node: { version: nodeVersion, ok: true },
@@ -83123,6 +83525,198 @@ function pickNextStep(results, hasMissingProviders) {
83123
83525
  return null;
83124
83526
  }
83125
83527
 
83528
+ // src/commands/host.ts
83529
+ init_esm();
83530
+ init_source();
83531
+ init_exec_safe();
83532
+ init_cost_tier();
83533
+ import { resolve as resolve68 } from "node:path";
83534
+ init_output();
83535
+ var hostCommand = new Command("host").description("Set up Codex, Claude, and Cursor app integrations").addHelpText(
83536
+ "after",
83537
+ `
83538
+ Examples:
83539
+ $ vibe host list --json
83540
+ $ vibe host setup all Print MCP/project config snippets
83541
+ $ vibe host setup cursor --write Write .cursor/mcp.json
83542
+ $ vibe host doctor all --json Check host-app readiness
83543
+ `
83544
+ );
83545
+ hostCommand.command("list").description("List supported app hosts and integration surfaces").action(() => {
83546
+ const startedAt = Date.now();
83547
+ const hosts = hostDefinitions(resolve68(".")).map((host) => ({
83548
+ id: host.id,
83549
+ label: host.label,
83550
+ surfaces: host.surfaces,
83551
+ guidanceFiles: host.guidanceFiles,
83552
+ notes: host.notes
83553
+ }));
83554
+ if (isJsonMode()) {
83555
+ outputSuccess({ command: "host list", startedAt, data: { hosts } });
83556
+ return;
83557
+ }
83558
+ console.log();
83559
+ console.log(source_default.bold.cyan("Supported Host Apps"));
83560
+ console.log(source_default.dim("\u2500".repeat(60)));
83561
+ for (const host of hosts) {
83562
+ console.log(` ${source_default.bold(host.label)} ${source_default.dim(`(${host.id})`)}`);
83563
+ console.log(source_default.dim(` surfaces: ${host.surfaces.join(", ")}`));
83564
+ if (host.guidanceFiles.length > 0) {
83565
+ console.log(source_default.dim(` files: ${host.guidanceFiles.join(", ")}`));
83566
+ }
83567
+ }
83568
+ console.log();
83569
+ });
83570
+ applyTier(hostCommand.commands[hostCommand.commands.length - 1], "free");
83571
+ hostCommand.command("setup").description("Print or write Codex/Claude/Cursor MCP and project integration config").argument("[host]", `Host target: ${HOST_SELECTIONS.join(" | ")}`, "all").argument("[project-dir]", "Project directory for project-scoped config", ".").option("--write", "Write config files instead of printing snippets only").option("--dry-run", "Show file actions without writing").option("--force", "Replace an existing vibeframe MCP entry").action(async (hostArg, projectDirArg, options) => {
83572
+ const startedAt = Date.now();
83573
+ const selection = validateHostSelection(hostArg);
83574
+ const projectDir = resolve68(projectDirArg);
83575
+ const ids = resolveHostSelection(selection);
83576
+ const defs = hostDefinitions(projectDir).filter((host) => ids.includes(host.id));
83577
+ const plans = [];
83578
+ for (const host of defs) {
83579
+ plans.push(
83580
+ await planHostSetup(host, projectDir, {
83581
+ write: Boolean(options.write),
83582
+ dryRun: Boolean(options.dryRun),
83583
+ force: Boolean(options.force)
83584
+ })
83585
+ );
83586
+ }
83587
+ if (isJsonMode()) {
83588
+ outputSuccess({
83589
+ command: "host setup",
83590
+ startedAt,
83591
+ ...options.dryRun ? { dryRun: true } : {},
83592
+ data: {
83593
+ projectDir,
83594
+ selection,
83595
+ write: Boolean(options.write),
83596
+ hosts: plans.map(serializeSetupPlan)
83597
+ },
83598
+ warnings: plans.flatMap((plan) => plan.warnings)
83599
+ });
83600
+ return;
83601
+ }
83602
+ printSetupPlans(plans, { write: Boolean(options.write), dryRun: Boolean(options.dryRun) });
83603
+ });
83604
+ applyTier(hostCommand.commands[hostCommand.commands.length - 1], "free");
83605
+ hostCommand.command("doctor").description("Check Codex/Claude/Cursor app integration readiness").argument("[host]", `Host target: ${HOST_SELECTIONS.join(" | ")}`, "all").argument("[project-dir]", "Project directory to inspect", ".").action(async (hostArg, projectDirArg) => {
83606
+ const startedAt = Date.now();
83607
+ const selection = validateHostSelection(hostArg);
83608
+ const projectDir = resolve68(projectDirArg);
83609
+ const ids = resolveHostSelection(selection);
83610
+ const defs = hostDefinitions(projectDir).filter((host) => ids.includes(host.id));
83611
+ const hosts = await Promise.all(defs.map((host) => inspectHost(host, projectDir)));
83612
+ const system = {
83613
+ vibe: commandExists("vibe"),
83614
+ npx: commandExists("npx")
83615
+ };
83616
+ const warnings = [
83617
+ ...system.vibe ? [] : ["vibe binary not found on PATH"],
83618
+ ...system.npx ? [] : ["npx not found on PATH; MCP stdio config needs npx"],
83619
+ ...hosts.flatMap((host) => host.warnings)
83620
+ ];
83621
+ if (isJsonMode()) {
83622
+ outputSuccess({
83623
+ command: "host doctor",
83624
+ startedAt,
83625
+ data: {
83626
+ projectDir,
83627
+ selection,
83628
+ system,
83629
+ hosts: hosts.map(serializeDoctorResult)
83630
+ },
83631
+ warnings
83632
+ });
83633
+ return;
83634
+ }
83635
+ printDoctor(hosts, system, warnings);
83636
+ });
83637
+ applyTier(hostCommand.commands[hostCommand.commands.length - 1], "free");
83638
+ function validateHostSelection(value) {
83639
+ if (HOST_SELECTIONS.includes(value)) return value;
83640
+ exitWithError(
83641
+ usageError(`Invalid host target: ${value}`, `Must be one of: ${HOST_SELECTIONS.join(", ")}`)
83642
+ );
83643
+ }
83644
+ function serializeSetupPlan(plan) {
83645
+ return {
83646
+ id: plan.host.id,
83647
+ label: plan.host.label,
83648
+ surfaces: plan.host.surfaces,
83649
+ configPath: plan.configPath,
83650
+ snippet: plan.snippet,
83651
+ ...plan.command ? { command: plan.command } : {},
83652
+ files: plan.files,
83653
+ warnings: plan.warnings,
83654
+ nextSteps: plan.nextSteps
83655
+ };
83656
+ }
83657
+ function serializeDoctorResult(result) {
83658
+ return {
83659
+ id: result.host.id,
83660
+ label: result.host.label,
83661
+ surfaces: result.host.surfaces,
83662
+ configPath: result.configPath,
83663
+ configured: result.configured,
83664
+ guidanceFiles: result.guidanceFiles,
83665
+ warnings: result.warnings,
83666
+ nextSteps: result.nextSteps
83667
+ };
83668
+ }
83669
+ function printSetupPlans(plans, opts) {
83670
+ console.log();
83671
+ console.log(source_default.bold.cyan("VibeFrame Host Setup"));
83672
+ console.log(source_default.dim("\u2500".repeat(60)));
83673
+ if (!opts.write) {
83674
+ console.log(source_default.dim("Snippet mode \u2014 no files were changed. Pass --write to apply."));
83675
+ } else if (opts.dryRun) {
83676
+ console.log(source_default.dim("Dry run \u2014 no files were changed."));
83677
+ }
83678
+ for (const plan of plans) {
83679
+ console.log();
83680
+ console.log(source_default.bold(plan.host.label) + source_default.dim(` (${plan.host.id})`));
83681
+ console.log(source_default.dim(`Config: ${plan.configPath}`));
83682
+ if (plan.command) console.log(source_default.dim(`Command: ${plan.command}`));
83683
+ console.log();
83684
+ console.log(plan.snippet);
83685
+ if (plan.files.length > 0) {
83686
+ console.log();
83687
+ for (const file of plan.files) {
83688
+ console.log(` ${formatAction(file.status)} ${file.path}${file.reason ? source_default.dim(` ${file.reason}`) : ""}`);
83689
+ }
83690
+ }
83691
+ for (const warning of plan.warnings) console.log(source_default.yellow(` Warning: ${warning}`));
83692
+ }
83693
+ console.log();
83694
+ }
83695
+ function printDoctor(hosts, system, warnings) {
83696
+ console.log();
83697
+ console.log(source_default.bold.cyan("VibeFrame Host Doctor"));
83698
+ console.log(source_default.dim("\u2500".repeat(60)));
83699
+ console.log(` vibe: ${system.vibe ? source_default.green("OK") : source_default.red("MISSING")}`);
83700
+ console.log(` npx: ${system.npx ? source_default.green("OK") : source_default.red("MISSING")}`);
83701
+ console.log();
83702
+ for (const host of hosts) {
83703
+ console.log(source_default.bold(host.host.label) + source_default.dim(` (${host.host.id})`));
83704
+ console.log(` MCP config: ${host.configured ? source_default.green("OK") : source_default.yellow("missing")} ${source_default.dim(host.configPath)}`);
83705
+ for (const file of host.guidanceFiles) {
83706
+ const ok = file.status !== "missing";
83707
+ console.log(` ${ok ? source_default.green("OK") : source_default.yellow("MISSING")} ${source_default.dim(file.path)}`);
83708
+ }
83709
+ console.log();
83710
+ }
83711
+ for (const warning of warnings) console.log(source_default.yellow(`Warning: ${warning}`));
83712
+ }
83713
+ function formatAction(status) {
83714
+ if (status === "wrote" || status === "merged") return source_default.green("\u2713");
83715
+ if (status.startsWith("would")) return source_default.cyan("\u2192");
83716
+ if (status === "missing") return source_default.yellow("!");
83717
+ return source_default.dim("\u25CB");
83718
+ }
83719
+
83126
83720
  // src/commands/demo.ts
83127
83721
  init_esm();
83128
83722
  init_source();
@@ -83131,10 +83725,10 @@ init_exec_safe();
83131
83725
  init_detect();
83132
83726
  init_ai_edit();
83133
83727
  init_output();
83134
- import { resolve as resolve67 } from "node:path";
83135
- import { existsSync as existsSync49 } from "node:fs";
83136
- import { mkdir as mkdir25, rm as rm4 } from "node:fs/promises";
83137
- var DEMO_DIR = resolve67(process.cwd(), ".vibeframe-demo");
83728
+ import { resolve as resolve69 } from "node:path";
83729
+ import { existsSync as existsSync50 } from "node:fs";
83730
+ import { mkdir as mkdir26, rm as rm4 } from "node:fs/promises";
83731
+ var DEMO_DIR = resolve69(process.cwd(), ".vibeframe-demo");
83138
83732
  async function generateTestVideo(outputPath) {
83139
83733
  const filter = [
83140
83734
  // Video: color bars with text
@@ -83163,7 +83757,7 @@ async function generateTestVideo(outputPath) {
83163
83757
  "-y",
83164
83758
  outputPath
83165
83759
  ], { timeout: 3e4, maxBuffer: 50 * 1024 * 1024 });
83166
- return existsSync49(outputPath);
83760
+ return existsSync50(outputPath);
83167
83761
  } catch {
83168
83762
  try {
83169
83763
  await execSafe("ffmpeg", [
@@ -83189,7 +83783,7 @@ async function generateTestVideo(outputPath) {
83189
83783
  "-y",
83190
83784
  outputPath
83191
83785
  ], { timeout: 3e4, maxBuffer: 50 * 1024 * 1024 });
83192
- return existsSync49(outputPath);
83786
+ return existsSync50(outputPath);
83193
83787
  } catch {
83194
83788
  return false;
83195
83789
  }
@@ -83213,8 +83807,8 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
83213
83807
  console.log(source_default.dim(" " + "\u2500".repeat(50)));
83214
83808
  console.log();
83215
83809
  }
83216
- await mkdir25(DEMO_DIR, { recursive: true });
83217
- const testVideo = resolve67(DEMO_DIR, "test-input.mp4");
83810
+ await mkdir26(DEMO_DIR, { recursive: true });
83811
+ const testVideo = resolve69(DEMO_DIR, "test-input.mp4");
83218
83812
  const genSpinner = !isJson ? ora("Generating test video...").start() : null;
83219
83813
  const generated = await generateTestVideo(testVideo);
83220
83814
  if (!generated) {
@@ -83243,7 +83837,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
83243
83837
  name: "Silence Cut",
83244
83838
  description: "Removing silent segments",
83245
83839
  run: async () => {
83246
- const output = resolve67(DEMO_DIR, "silence-cut.mp4");
83840
+ const output = resolve69(DEMO_DIR, "silence-cut.mp4");
83247
83841
  const r = await executeSilenceCut({ videoPath: testVideo, outputPath: output, padding: 0.1 });
83248
83842
  if (r.success && r.totalDuration && r.silentDuration) {
83249
83843
  return { success: true, detail: `Removed ${r.silentDuration.toFixed(1)}s silence (${r.totalDuration.toFixed(1)}s \u2192 ${(r.totalDuration - r.silentDuration).toFixed(1)}s)` };
@@ -83255,7 +83849,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
83255
83849
  name: "Noise Reduce",
83256
83850
  description: "Reducing background noise",
83257
83851
  run: async () => {
83258
- const output = resolve67(DEMO_DIR, "noise-reduced.mp4");
83852
+ const output = resolve69(DEMO_DIR, "noise-reduced.mp4");
83259
83853
  const r = await executeNoiseReduce({ inputPath: testVideo, outputPath: output, strength: "medium" });
83260
83854
  return { success: r.success, detail: r.success ? `Cleaned audio \u2192 ${output}` : r.error };
83261
83855
  }
@@ -83264,7 +83858,7 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
83264
83858
  name: "Fade Effects",
83265
83859
  description: "Adding fade in/out",
83266
83860
  run: async () => {
83267
- const output = resolve67(DEMO_DIR, "faded.mp4");
83861
+ const output = resolve69(DEMO_DIR, "faded.mp4");
83268
83862
  const r = await executeFade({ videoPath: testVideo, outputPath: output, fadeIn: 1, fadeOut: 1 });
83269
83863
  return { success: r.success, detail: r.success ? `1s fade in + 1s fade out \u2192 ${output}` : r.error };
83270
83864
  }
@@ -83331,20 +83925,20 @@ var demoCommand = new Command("demo").description("Run sample edits on a test vi
83331
83925
 
83332
83926
  // src/commands/context.ts
83333
83927
  init_esm();
83334
- import { existsSync as existsSync50 } from "node:fs";
83335
- import { readFile as readFile44 } from "node:fs/promises";
83336
- import { resolve as resolve68, dirname as dirname23 } from "node:path";
83928
+ import { existsSync as existsSync51 } from "node:fs";
83929
+ import { readFile as readFile45 } from "node:fs/promises";
83930
+ import { resolve as resolve70, dirname as dirname24 } from "node:path";
83337
83931
  import { fileURLToPath as fileURLToPath2 } from "node:url";
83338
83932
  var __filename = fileURLToPath2(import.meta.url);
83339
- var __dirname = dirname23(__filename);
83933
+ var __dirname = dirname24(__filename);
83340
83934
  function resolveContextPath(baseDir = __dirname) {
83341
83935
  const candidates = [
83342
83936
  // Bundled package layout: packages/cli/dist/index.js -> packages/cli/CONTEXT.md
83343
- resolve68(baseDir, "../CONTEXT.md"),
83937
+ resolve70(baseDir, "../CONTEXT.md"),
83344
83938
  // Source/dev layout: packages/cli/src/commands/context.ts -> packages/cli/CONTEXT.md
83345
- resolve68(baseDir, "../../CONTEXT.md")
83939
+ resolve70(baseDir, "../../CONTEXT.md")
83346
83940
  ];
83347
- return candidates.find((candidate) => existsSync50(candidate)) ?? null;
83941
+ return candidates.find((candidate) => existsSync51(candidate)) ?? null;
83348
83942
  }
83349
83943
  var contextCommand = new Command("context").description("Print CLI context/guidelines for AI agent integration").option("--format <format>", "Output format: markdown | json", "markdown").action(async (_options, cmd) => {
83350
83944
  const options = {
@@ -83434,7 +84028,7 @@ var contextCommand = new Command("context").description("Print CLI context/guide
83434
84028
  try {
83435
84029
  const contextPath = resolveContextPath();
83436
84030
  if (!contextPath) throw new Error("CONTEXT.md not found");
83437
- const content = await readFile44(contextPath, "utf-8");
84031
+ const content = await readFile45(contextPath, "utf-8");
83438
84032
  console.log(
83439
84033
  content.replace(
83440
84034
  "## Mental model",
@@ -84376,7 +84970,7 @@ async function startAgent(options = {}) {
84376
84970
  console.log();
84377
84971
  console.log(source_default.dim(" Commands: exit \xB7 reset \xB7 tools \xB7 context"));
84378
84972
  console.log();
84379
- return new Promise((resolve81) => {
84973
+ return new Promise((resolve83) => {
84380
84974
  if (typeof process.stdin.ref === "function") {
84381
84975
  process.stdin.ref();
84382
84976
  }
@@ -84483,7 +85077,7 @@ async function startAgent(options = {}) {
84483
85077
  clearInterval(keepalive);
84484
85078
  console.log();
84485
85079
  console.log(source_default.dim("Goodbye!"));
84486
- resolve81();
85080
+ resolve83();
84487
85081
  });
84488
85082
  rl.prompt();
84489
85083
  });
@@ -84756,8 +85350,8 @@ init_source();
84756
85350
  init_config();
84757
85351
  init_schema();
84758
85352
  init_api_key();
84759
- import { access as access9, writeFile as writeFile58, mkdir as mkdir28 } from "node:fs/promises";
84760
- import { dirname as dirname25 } from "node:path";
85353
+ import { access as access9, writeFile as writeFile59, mkdir as mkdir29 } from "node:fs/promises";
85354
+ import { dirname as dirname26 } from "node:path";
84761
85355
  var BANNER_SHOWN_PATH = `${USER_CONFIG_DIR}/.banner-shown`;
84762
85356
  async function isFirstRun() {
84763
85357
  try {
@@ -84776,8 +85370,8 @@ async function isFirstRun() {
84776
85370
  }
84777
85371
  async function markBannerShown() {
84778
85372
  try {
84779
- await mkdir28(dirname25(BANNER_SHOWN_PATH), { recursive: true });
84780
- await writeFile58(BANNER_SHOWN_PATH, (/* @__PURE__ */ new Date()).toISOString());
85373
+ await mkdir29(dirname26(BANNER_SHOWN_PATH), { recursive: true });
85374
+ await writeFile59(BANNER_SHOWN_PATH, (/* @__PURE__ */ new Date()).toISOString());
84781
85375
  } catch {
84782
85376
  }
84783
85377
  }
@@ -84912,6 +85506,7 @@ this section shows the typical entry points by use case):
84912
85506
  vibe schema --list --surface public Compact first-run command catalog
84913
85507
  vibe schema generate.video JSON schema for any command
84914
85508
  vibe context Agent integration quickstart
85509
+ vibe host setup all Configure Codex/Claude/Cursor app integrations
84915
85510
  vibe agent Optional built-in agent when you do not use Claude Code/Codex/etc.
84916
85511
 
84917
85512
  Common-flag note: most commands accept --dry-run to preview cost/output
@@ -85013,6 +85608,7 @@ program2.addCommand(buildCommand);
85013
85608
  program2.addCommand(renderCommand);
85014
85609
  program2.addCommand(statusCommand);
85015
85610
  program2.addCommand(doctorCommand);
85611
+ program2.addCommand(hostCommand);
85016
85612
  program2.addCommand(demoCommand, { hidden: true });
85017
85613
  program2.addCommand(runCommand);
85018
85614
  program2.addCommand(agentCommand);