vidpipe 1.3.12 → 1.3.13

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/cli.js CHANGED
@@ -56,7 +56,7 @@ function findRoot(startDir) {
56
56
  }
57
57
  }
58
58
  function projectRoot() {
59
- if (!_cachedRoot) _cachedRoot = findRoot(__dirname);
59
+ if (!_cachedRoot) _cachedRoot = findRoot(__dirname2);
60
60
  return _cachedRoot;
61
61
  }
62
62
  function assetsDir(...segments) {
@@ -70,11 +70,11 @@ function modelsDir() {
70
70
  const bundled = resolve2(projectRoot(), "dist", "models");
71
71
  return existsSync(bundled) ? bundled : assetsDir("models");
72
72
  }
73
- var __dirname, _cachedRoot;
73
+ var __dirname2, _cachedRoot;
74
74
  var init_paths = __esm({
75
75
  "src/L1-infra/paths/paths.ts"() {
76
76
  "use strict";
77
- __dirname = dirname2(fileURLToPath2(import.meta.url));
77
+ __dirname2 = dirname2(fileURLToPath2(import.meta.url));
78
78
  }
79
79
  });
80
80
 
@@ -415,8 +415,9 @@ var init_globalConfig = __esm({
415
415
 
416
416
  // src/L1-infra/config/configResolver.ts
417
417
  import { join as join4 } from "path";
418
- function resolveString(...sources) {
419
- for (const source of sources) {
418
+ function resolveString(cliValue, ...fallbacks) {
419
+ if (cliValue !== void 0) return cliValue;
420
+ for (const source of fallbacks) {
420
421
  if (source !== void 0 && source !== "") {
421
422
  return source;
422
423
  }
@@ -434,7 +435,11 @@ function resolveBoolean(cliValue, envValue, defaultValue) {
434
435
  }
435
436
  function resolveConfig(cliOptions = {}) {
436
437
  const globalConfig = loadGlobalConfig();
437
- const repoRoot = process.env.REPO_ROOT || process.cwd();
438
+ const repoRoot = resolveString(
439
+ cliOptions.repoRoot,
440
+ process.env.REPO_ROOT,
441
+ process.cwd()
442
+ );
438
443
  return {
439
444
  OPENAI_API_KEY: resolveString(
440
445
  cliOptions.openaiKey,
@@ -448,14 +453,22 @@ function resolveConfig(cliOptions = {}) {
448
453
  join4(repoRoot, "watch")
449
454
  ),
450
455
  REPO_ROOT: repoRoot,
451
- FFMPEG_PATH: resolveString(process.env.FFMPEG_PATH, "ffmpeg"),
452
- FFPROBE_PATH: resolveString(process.env.FFPROBE_PATH, "ffprobe"),
456
+ FFMPEG_PATH: resolveString(
457
+ cliOptions.ffmpegPath,
458
+ process.env.FFMPEG_PATH,
459
+ "ffmpeg"
460
+ ),
461
+ FFPROBE_PATH: resolveString(
462
+ cliOptions.ffprobePath,
463
+ process.env.FFPROBE_PATH,
464
+ "ffprobe"
465
+ ),
453
466
  EXA_API_KEY: resolveString(
454
467
  cliOptions.exaKey,
455
468
  process.env.EXA_API_KEY,
456
469
  globalConfig.credentials.exaApiKey
457
470
  ),
458
- EXA_MCP_URL: resolveString(process.env.EXA_MCP_URL, "https://mcp.exa.ai/mcp"),
471
+ EXA_MCP_URL: resolveString(void 0, process.env.EXA_MCP_URL, "https://mcp.exa.ai/mcp"),
459
472
  YOUTUBE_API_KEY: resolveString(
460
473
  cliOptions.youtubeKey,
461
474
  process.env.YOUTUBE_API_KEY,
@@ -467,12 +480,18 @@ function resolveConfig(cliOptions = {}) {
467
480
  globalConfig.credentials.perplexityApiKey
468
481
  ),
469
482
  LLM_PROVIDER: resolveString(
483
+ cliOptions.llmProvider,
470
484
  process.env.LLM_PROVIDER,
471
485
  globalConfig.defaults.llmProvider,
472
486
  "copilot"
473
487
  ),
474
- LLM_MODEL: resolveString(process.env.LLM_MODEL, globalConfig.defaults.llmModel),
488
+ LLM_MODEL: resolveString(
489
+ cliOptions.llmModel,
490
+ process.env.LLM_MODEL,
491
+ globalConfig.defaults.llmModel
492
+ ),
475
493
  ANTHROPIC_API_KEY: resolveString(
494
+ cliOptions.anthropicKey,
476
495
  process.env.ANTHROPIC_API_KEY,
477
496
  globalConfig.credentials.anthropicApiKey
478
497
  ),
@@ -489,7 +508,6 @@ function resolveConfig(cliOptions = {}) {
489
508
  join4(repoRoot, "brand.json")
490
509
  ),
491
510
  VERBOSE: cliOptions.verbose ?? false,
492
- SKIP_GIT: resolveBoolean(cliOptions.git === void 0 ? void 0 : !cliOptions.git, process.env.SKIP_GIT, false),
493
511
  SKIP_SILENCE_REMOVAL: resolveBoolean(
494
512
  cliOptions.silenceRemoval === void 0 ? void 0 : !cliOptions.silenceRemoval,
495
513
  process.env.SKIP_SILENCE_REMOVAL,
@@ -536,10 +554,12 @@ function resolveConfig(cliOptions = {}) {
536
554
  false
537
555
  ),
538
556
  GEMINI_API_KEY: resolveString(
557
+ cliOptions.geminiKey,
539
558
  process.env.GEMINI_API_KEY,
540
559
  globalConfig.credentials.geminiApiKey
541
560
  ),
542
561
  GEMINI_MODEL: resolveString(
562
+ cliOptions.geminiModel,
543
563
  process.env.GEMINI_MODEL,
544
564
  globalConfig.defaults.geminiModel,
545
565
  "gemini-2.5-pro"
@@ -554,9 +574,19 @@ function resolveConfig(cliOptions = {}) {
554
574
  cliOptions.githubToken,
555
575
  process.env.GITHUB_TOKEN,
556
576
  globalConfig.credentials.githubToken
557
- )
577
+ ),
578
+ MODEL_OVERRIDES: resolveModelOverrides()
558
579
  };
559
580
  }
581
+ function resolveModelOverrides() {
582
+ const overrides = {};
583
+ for (const [key, value] of Object.entries(process.env)) {
584
+ if (key.startsWith("MODEL_") && value) {
585
+ overrides[key] = value;
586
+ }
587
+ }
588
+ return overrides;
589
+ }
560
590
  var init_configResolver = __esm({
561
591
  "src/L1-infra/config/configResolver.ts"() {
562
592
  "use strict";
@@ -572,7 +602,7 @@ __export(environment_exports, {
572
602
  validateRequiredKeys: () => validateRequiredKeys
573
603
  });
574
604
  function validateRequiredKeys() {
575
- if (!config?.OPENAI_API_KEY && !process.env.OPENAI_API_KEY) {
605
+ if (!config?.OPENAI_API_KEY) {
576
606
  throw new Error("Missing required: OPENAI_API_KEY (set via --openai-key, env var, or vidpipe configure)");
577
607
  }
578
608
  }
@@ -720,8 +750,7 @@ var init_types = __esm({
720
750
  { stage: "short-posts" /* ShortPosts */, name: "Short Posts", stageNumber: 12 },
721
751
  { stage: "medium-clip-posts" /* MediumClipPosts */, name: "Medium Clip Posts", stageNumber: 13 },
722
752
  { stage: "queue-build" /* QueueBuild */, name: "Queue Build", stageNumber: 14 },
723
- { stage: "blog" /* Blog */, name: "Blog", stageNumber: 15 },
724
- { stage: "git-push" /* GitPush */, name: "Git Push", stageNumber: 16 }
753
+ { stage: "blog" /* Blog */, name: "Blog", stageNumber: 15 }
725
754
  ];
726
755
  TOTAL_STAGES = PIPELINE_STAGES.length;
727
756
  PLATFORM_CHAR_LIMITS = {
@@ -870,7 +899,7 @@ var require_messages = __commonJS({
870
899
  ErrorCodes2.jsonrpcReservedErrorRangeEnd = -32e3;
871
900
  ErrorCodes2.serverErrorEnd = -32e3;
872
901
  })(ErrorCodes || (exports.ErrorCodes = ErrorCodes = {}));
873
- var ResponseError = class _ResponseError extends Error {
902
+ var ResponseError2 = class _ResponseError extends Error {
874
903
  constructor(code, message, data) {
875
904
  super(message);
876
905
  this.code = is.number(code) ? code : ErrorCodes.UnknownErrorCode;
@@ -888,7 +917,7 @@ var require_messages = __commonJS({
888
917
  return result;
889
918
  }
890
919
  };
891
- exports.ResponseError = ResponseError;
920
+ exports.ResponseError = ResponseError2;
892
921
  var ParameterStructures = class _ParameterStructures {
893
922
  constructor(kind) {
894
923
  this.kind = kind;
@@ -2441,14 +2470,14 @@ var require_connection = __commonJS({
2441
2470
  ConnectionErrors2[ConnectionErrors2["Disposed"] = 2] = "Disposed";
2442
2471
  ConnectionErrors2[ConnectionErrors2["AlreadyListening"] = 3] = "AlreadyListening";
2443
2472
  })(ConnectionErrors || (exports.ConnectionErrors = ConnectionErrors = {}));
2444
- var ConnectionError = class _ConnectionError extends Error {
2473
+ var ConnectionError2 = class _ConnectionError extends Error {
2445
2474
  constructor(code, message) {
2446
2475
  super(message);
2447
2476
  this.code = code;
2448
2477
  Object.setPrototypeOf(this, _ConnectionError.prototype);
2449
2478
  }
2450
2479
  };
2451
- exports.ConnectionError = ConnectionError;
2480
+ exports.ConnectionError = ConnectionError2;
2452
2481
  var ConnectionStrategy;
2453
2482
  (function(ConnectionStrategy2) {
2454
2483
  function is(value) {
@@ -3071,15 +3100,15 @@ ${JSON.stringify(message, null, 4)}`);
3071
3100
  }
3072
3101
  function throwIfClosedOrDisposed() {
3073
3102
  if (isClosed()) {
3074
- throw new ConnectionError(ConnectionErrors.Closed, "Connection is closed.");
3103
+ throw new ConnectionError2(ConnectionErrors.Closed, "Connection is closed.");
3075
3104
  }
3076
3105
  if (isDisposed()) {
3077
- throw new ConnectionError(ConnectionErrors.Disposed, "Connection is disposed.");
3106
+ throw new ConnectionError2(ConnectionErrors.Disposed, "Connection is disposed.");
3078
3107
  }
3079
3108
  }
3080
3109
  function throwIfListening() {
3081
3110
  if (isListening()) {
3082
- throw new ConnectionError(ConnectionErrors.AlreadyListening, "Connection is already listening");
3111
+ throw new ConnectionError2(ConnectionErrors.AlreadyListening, "Connection is already listening");
3083
3112
  }
3084
3113
  }
3085
3114
  function throwIfNotListening() {
@@ -4064,6 +4093,67 @@ var require_node = __commonJS({
4064
4093
  }
4065
4094
  });
4066
4095
 
4096
+ // node_modules/@github/copilot-sdk/dist/generated/rpc.js
4097
+ function createServerRpc(connection) {
4098
+ return {
4099
+ ping: async (params) => connection.sendRequest("ping", params),
4100
+ models: {
4101
+ list: async () => connection.sendRequest("models.list", {})
4102
+ },
4103
+ tools: {
4104
+ list: async (params) => connection.sendRequest("tools.list", params)
4105
+ },
4106
+ account: {
4107
+ getQuota: async () => connection.sendRequest("account.getQuota", {})
4108
+ }
4109
+ };
4110
+ }
4111
+ function createSessionRpc(connection, sessionId) {
4112
+ return {
4113
+ model: {
4114
+ getCurrent: async () => connection.sendRequest("session.model.getCurrent", { sessionId }),
4115
+ switchTo: async (params) => connection.sendRequest("session.model.switchTo", { sessionId, ...params })
4116
+ },
4117
+ mode: {
4118
+ get: async () => connection.sendRequest("session.mode.get", { sessionId }),
4119
+ set: async (params) => connection.sendRequest("session.mode.set", { sessionId, ...params })
4120
+ },
4121
+ plan: {
4122
+ read: async () => connection.sendRequest("session.plan.read", { sessionId }),
4123
+ update: async (params) => connection.sendRequest("session.plan.update", { sessionId, ...params }),
4124
+ delete: async () => connection.sendRequest("session.plan.delete", { sessionId })
4125
+ },
4126
+ workspace: {
4127
+ listFiles: async () => connection.sendRequest("session.workspace.listFiles", { sessionId }),
4128
+ readFile: async (params) => connection.sendRequest("session.workspace.readFile", { sessionId, ...params }),
4129
+ createFile: async (params) => connection.sendRequest("session.workspace.createFile", { sessionId, ...params })
4130
+ },
4131
+ fleet: {
4132
+ start: async (params) => connection.sendRequest("session.fleet.start", { sessionId, ...params })
4133
+ },
4134
+ agent: {
4135
+ list: async () => connection.sendRequest("session.agent.list", { sessionId }),
4136
+ getCurrent: async () => connection.sendRequest("session.agent.getCurrent", { sessionId }),
4137
+ select: async (params) => connection.sendRequest("session.agent.select", { sessionId, ...params }),
4138
+ deselect: async () => connection.sendRequest("session.agent.deselect", { sessionId })
4139
+ },
4140
+ compaction: {
4141
+ compact: async () => connection.sendRequest("session.compaction.compact", { sessionId })
4142
+ },
4143
+ tools: {
4144
+ handlePendingToolCall: async (params) => connection.sendRequest("session.tools.handlePendingToolCall", { sessionId, ...params })
4145
+ },
4146
+ permissions: {
4147
+ handlePendingPermissionRequest: async (params) => connection.sendRequest("session.permissions.handlePendingPermissionRequest", { sessionId, ...params })
4148
+ }
4149
+ };
4150
+ }
4151
+ var init_rpc = __esm({
4152
+ "node_modules/@github/copilot-sdk/dist/generated/rpc.js"() {
4153
+ "use strict";
4154
+ }
4155
+ });
4156
+
4067
4157
  // node_modules/@github/copilot-sdk/dist/sdkProtocolVersion.js
4068
4158
  function getSdkProtocolVersion() {
4069
4159
  return SDK_PROTOCOL_VERSION;
@@ -4072,15 +4162,17 @@ var SDK_PROTOCOL_VERSION;
4072
4162
  var init_sdkProtocolVersion = __esm({
4073
4163
  "node_modules/@github/copilot-sdk/dist/sdkProtocolVersion.js"() {
4074
4164
  "use strict";
4075
- SDK_PROTOCOL_VERSION = 2;
4165
+ SDK_PROTOCOL_VERSION = 3;
4076
4166
  }
4077
4167
  });
4078
4168
 
4079
4169
  // node_modules/@github/copilot-sdk/dist/session.js
4080
- var CopilotSession;
4170
+ var import_node, CopilotSession;
4081
4171
  var init_session = __esm({
4082
4172
  "node_modules/@github/copilot-sdk/dist/session.js"() {
4083
4173
  "use strict";
4174
+ import_node = __toESM(require_node(), 1);
4175
+ init_rpc();
4084
4176
  CopilotSession = class {
4085
4177
  /**
4086
4178
  * Creates a new CopilotSession instance.
@@ -4101,6 +4193,16 @@ var init_session = __esm({
4101
4193
  permissionHandler;
4102
4194
  userInputHandler;
4103
4195
  hooks;
4196
+ _rpc = null;
4197
+ /**
4198
+ * Typed session-scoped RPC methods.
4199
+ */
4200
+ get rpc() {
4201
+ if (!this._rpc) {
4202
+ this._rpc = createSessionRpc(this.connection, this.sessionId);
4203
+ }
4204
+ return this._rpc;
4205
+ }
4104
4206
  /**
4105
4207
  * Path to the session workspace directory when infinite sessions are enabled.
4106
4208
  * Contains checkpoints/, plan.md, and files/ subdirectories.
@@ -4117,7 +4219,7 @@ var init_session = __esm({
4117
4219
  *
4118
4220
  * @param options - The message options including the prompt and optional attachments
4119
4221
  * @returns A promise that resolves with the message ID of the response
4120
- * @throws Error if the session has been destroyed or the connection fails
4222
+ * @throws Error if the session has been disconnected or the connection fails
4121
4223
  *
4122
4224
  * @example
4123
4225
  * ```typescript
@@ -4150,7 +4252,7 @@ var init_session = __esm({
4150
4252
  * @returns A promise that resolves with the final assistant message when the session becomes idle,
4151
4253
  * or undefined if no assistant message was received
4152
4254
  * @throws Error if the timeout is reached before the session becomes idle
4153
- * @throws Error if the session has been destroyed or the connection fails
4255
+ * @throws Error if the session has been disconnected or the connection fails
4154
4256
  *
4155
4257
  * @example
4156
4258
  * ```typescript
@@ -4224,11 +4326,13 @@ var init_session = __esm({
4224
4326
  }
4225
4327
  /**
4226
4328
  * Dispatches an event to all registered handlers.
4329
+ * Also handles broadcast request events internally (external tool calls, permissions).
4227
4330
  *
4228
4331
  * @param event - The session event to dispatch
4229
4332
  * @internal This method is for internal use by the SDK.
4230
4333
  */
4231
4334
  _dispatchEvent(event) {
4335
+ this._handleBroadcastEvent(event);
4232
4336
  const typedHandlers = this.typedEventHandlers.get(event.type);
4233
4337
  if (typedHandlers) {
4234
4338
  for (const handler of typedHandlers) {
@@ -4245,6 +4349,85 @@ var init_session = __esm({
4245
4349
  }
4246
4350
  }
4247
4351
  }
4352
+ /**
4353
+ * Handles broadcast request events by executing local handlers and responding via RPC.
4354
+ * Handlers are dispatched as fire-and-forget — rejections propagate as unhandled promise
4355
+ * rejections, consistent with standard EventEmitter / event handler semantics.
4356
+ * @internal
4357
+ */
4358
+ _handleBroadcastEvent(event) {
4359
+ if (event.type === "external_tool.requested") {
4360
+ const { requestId, toolName } = event.data;
4361
+ const args = event.data.arguments;
4362
+ const toolCallId = event.data.toolCallId;
4363
+ const handler = this.toolHandlers.get(toolName);
4364
+ if (handler) {
4365
+ void this._executeToolAndRespond(requestId, toolName, toolCallId, args, handler);
4366
+ }
4367
+ } else if (event.type === "permission.requested") {
4368
+ const { requestId, permissionRequest } = event.data;
4369
+ if (this.permissionHandler) {
4370
+ void this._executePermissionAndRespond(requestId, permissionRequest);
4371
+ }
4372
+ }
4373
+ }
4374
+ /**
4375
+ * Executes a tool handler and sends the result back via RPC.
4376
+ * @internal
4377
+ */
4378
+ async _executeToolAndRespond(requestId, toolName, toolCallId, args, handler) {
4379
+ try {
4380
+ const rawResult = await handler(args, {
4381
+ sessionId: this.sessionId,
4382
+ toolCallId,
4383
+ toolName,
4384
+ arguments: args
4385
+ });
4386
+ let result;
4387
+ if (rawResult == null) {
4388
+ result = "";
4389
+ } else if (typeof rawResult === "string") {
4390
+ result = rawResult;
4391
+ } else {
4392
+ result = JSON.stringify(rawResult);
4393
+ }
4394
+ await this.rpc.tools.handlePendingToolCall({ requestId, result });
4395
+ } catch (error) {
4396
+ const message = error instanceof Error ? error.message : String(error);
4397
+ try {
4398
+ await this.rpc.tools.handlePendingToolCall({ requestId, error: message });
4399
+ } catch (rpcError) {
4400
+ if (!(rpcError instanceof import_node.ConnectionError || rpcError instanceof import_node.ResponseError)) {
4401
+ throw rpcError;
4402
+ }
4403
+ }
4404
+ }
4405
+ }
4406
+ /**
4407
+ * Executes a permission handler and sends the result back via RPC.
4408
+ * @internal
4409
+ */
4410
+ async _executePermissionAndRespond(requestId, permissionRequest) {
4411
+ try {
4412
+ const result = await this.permissionHandler(permissionRequest, {
4413
+ sessionId: this.sessionId
4414
+ });
4415
+ await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result });
4416
+ } catch (_error) {
4417
+ try {
4418
+ await this.rpc.permissions.handlePendingPermissionRequest({
4419
+ requestId,
4420
+ result: {
4421
+ kind: "denied-no-approval-rule-and-could-not-request-from-user"
4422
+ }
4423
+ });
4424
+ } catch (rpcError) {
4425
+ if (!(rpcError instanceof import_node.ConnectionError || rpcError instanceof import_node.ResponseError)) {
4426
+ throw rpcError;
4427
+ }
4428
+ }
4429
+ }
4430
+ }
4248
4431
  /**
4249
4432
  * Registers custom tool handlers for this session.
4250
4433
  *
@@ -4310,13 +4493,14 @@ var init_session = __esm({
4310
4493
  this.hooks = hooks;
4311
4494
  }
4312
4495
  /**
4313
- * Handles a permission request from the Copilot CLI.
4496
+ * Handles a permission request in the v2 protocol format (synchronous RPC).
4497
+ * Used as a back-compat adapter when connected to a v2 server.
4314
4498
  *
4315
4499
  * @param request - The permission request data from the CLI
4316
4500
  * @returns A promise that resolves with the permission decision
4317
4501
  * @internal This method is for internal use by the SDK.
4318
4502
  */
4319
- async _handlePermissionRequest(request) {
4503
+ async _handlePermissionRequestV2(request) {
4320
4504
  if (!this.permissionHandler) {
4321
4505
  return { kind: "denied-no-approval-rule-and-could-not-request-from-user" };
4322
4506
  }
@@ -4387,7 +4571,7 @@ var init_session = __esm({
4387
4571
  * assistant responses, tool executions, and other session events.
4388
4572
  *
4389
4573
  * @returns A promise that resolves with an array of all session events
4390
- * @throws Error if the session has been destroyed or the connection fails
4574
+ * @throws Error if the session has been disconnected or the connection fails
4391
4575
  *
4392
4576
  * @example
4393
4577
  * ```typescript
@@ -4406,22 +4590,27 @@ var init_session = __esm({
4406
4590
  return response.events;
4407
4591
  }
4408
4592
  /**
4409
- * Destroys this session and releases all associated resources.
4593
+ * Disconnects this session and releases all in-memory resources (event handlers,
4594
+ * tool handlers, permission handlers).
4410
4595
  *
4411
- * After calling this method, the session can no longer be used. All event
4412
- * handlers and tool handlers are cleared. To continue the conversation,
4413
- * use {@link CopilotClient.resumeSession} with the session ID.
4596
+ * Session state on disk (conversation history, planning state, artifacts) is
4597
+ * preserved, so the conversation can be resumed later by calling
4598
+ * {@link CopilotClient.resumeSession} with the session ID. To permanently
4599
+ * remove all session data including files on disk, use
4600
+ * {@link CopilotClient.deleteSession} instead.
4414
4601
  *
4415
- * @returns A promise that resolves when the session is destroyed
4602
+ * After calling this method, the session object can no longer be used.
4603
+ *
4604
+ * @returns A promise that resolves when the session is disconnected
4416
4605
  * @throws Error if the connection fails
4417
4606
  *
4418
4607
  * @example
4419
4608
  * ```typescript
4420
- * // Clean up when done
4421
- * await session.destroy();
4609
+ * // Clean up when done — session can still be resumed later
4610
+ * await session.disconnect();
4422
4611
  * ```
4423
4612
  */
4424
- async destroy() {
4613
+ async disconnect() {
4425
4614
  await this.connection.sendRequest("session.destroy", {
4426
4615
  sessionId: this.sessionId
4427
4616
  });
@@ -4430,6 +4619,22 @@ var init_session = __esm({
4430
4619
  this.toolHandlers.clear();
4431
4620
  this.permissionHandler = void 0;
4432
4621
  }
4622
+ /**
4623
+ * @deprecated Use {@link disconnect} instead. This method will be removed in a future release.
4624
+ *
4625
+ * Disconnects this session and releases all in-memory resources.
4626
+ * Session data on disk is preserved for later resumption.
4627
+ *
4628
+ * @returns A promise that resolves when the session is disconnected
4629
+ * @throws Error if the connection fails
4630
+ */
4631
+ async destroy() {
4632
+ return this.disconnect();
4633
+ }
4634
+ /** Enables `await using session = ...` syntax for automatic cleanup. */
4635
+ async [Symbol.asyncDispose]() {
4636
+ return this.disconnect();
4637
+ }
4433
4638
  /**
4434
4639
  * Aborts the currently processing message in this session.
4435
4640
  *
@@ -4437,7 +4642,7 @@ var init_session = __esm({
4437
4642
  * and can continue to be used for new messages.
4438
4643
  *
4439
4644
  * @returns A promise that resolves when the abort request is acknowledged
4440
- * @throws Error if the session has been destroyed or the connection fails
4645
+ * @throws Error if the session has been disconnected or the connection fails
4441
4646
  *
4442
4647
  * @example
4443
4648
  * ```typescript
@@ -4455,6 +4660,20 @@ var init_session = __esm({
4455
4660
  sessionId: this.sessionId
4456
4661
  });
4457
4662
  }
4663
+ /**
4664
+ * Change the model for this session.
4665
+ * The new model takes effect for the next message. Conversation history is preserved.
4666
+ *
4667
+ * @param model - Model ID to switch to
4668
+ *
4669
+ * @example
4670
+ * ```typescript
4671
+ * await session.setModel("gpt-4.1");
4672
+ * ```
4673
+ */
4674
+ async setModel(model) {
4675
+ await this.rpc.model.switchTo({ modelId: model });
4676
+ }
4458
4677
  };
4459
4678
  }
4460
4679
  });
@@ -4475,18 +4694,26 @@ function toJsonSchema(parameters) {
4475
4694
  }
4476
4695
  return parameters;
4477
4696
  }
4697
+ function getNodeExecPath() {
4698
+ if (process.versions.bun) {
4699
+ return "node";
4700
+ }
4701
+ return process.execPath;
4702
+ }
4478
4703
  function getBundledCliPath() {
4479
4704
  const sdkUrl = import.meta.resolve("@github/copilot/sdk");
4480
4705
  const sdkPath = fileURLToPath3(sdkUrl);
4481
4706
  return join5(dirname3(dirname3(sdkPath)), "index.js");
4482
4707
  }
4483
- var import_node, CopilotClient;
4708
+ var import_node2, MIN_PROTOCOL_VERSION, CopilotClient;
4484
4709
  var init_client = __esm({
4485
4710
  "node_modules/@github/copilot-sdk/dist/client.js"() {
4486
4711
  "use strict";
4487
- import_node = __toESM(require_node(), 1);
4712
+ import_node2 = __toESM(require_node(), 1);
4713
+ init_rpc();
4488
4714
  init_sdkProtocolVersion();
4489
4715
  init_session();
4716
+ MIN_PROTOCOL_VERSION = 2;
4490
4717
  CopilotClient = class {
4491
4718
  cliProcess = null;
4492
4719
  connection = null;
@@ -4495,6 +4722,8 @@ var init_client = __esm({
4495
4722
  actualHost = "localhost";
4496
4723
  state = "disconnected";
4497
4724
  sessions = /* @__PURE__ */ new Map();
4725
+ stderrBuffer = "";
4726
+ // Captures CLI stderr for error messages
4498
4727
  options;
4499
4728
  isExternalServer = false;
4500
4729
  forceStopping = false;
@@ -4502,6 +4731,23 @@ var init_client = __esm({
4502
4731
  modelsCacheLock = Promise.resolve();
4503
4732
  sessionLifecycleHandlers = /* @__PURE__ */ new Set();
4504
4733
  typedLifecycleHandlers = /* @__PURE__ */ new Map();
4734
+ _rpc = null;
4735
+ processExitPromise = null;
4736
+ // Rejects when CLI process exits
4737
+ negotiatedProtocolVersion = null;
4738
+ /**
4739
+ * Typed server-scoped RPC methods.
4740
+ * @throws Error if the client is not connected
4741
+ */
4742
+ get rpc() {
4743
+ if (!this.connection) {
4744
+ throw new Error("Client is not connected. Call start() first.");
4745
+ }
4746
+ if (!this._rpc) {
4747
+ this._rpc = createServerRpc(this.connection);
4748
+ }
4749
+ return this._rpc;
4750
+ }
4505
4751
  /**
4506
4752
  * Creates a new CopilotClient instance.
4507
4753
  *
@@ -4527,6 +4773,11 @@ var init_client = __esm({
4527
4773
  if (options.cliUrl && (options.useStdio === true || options.cliPath)) {
4528
4774
  throw new Error("cliUrl is mutually exclusive with useStdio and cliPath");
4529
4775
  }
4776
+ if (options.isChildProcess && (options.cliUrl || options.useStdio === false)) {
4777
+ throw new Error(
4778
+ "isChildProcess must be used in conjunction with useStdio and not with cliUrl"
4779
+ );
4780
+ }
4530
4781
  if (options.cliUrl && (options.githubToken || options.useLoggedInUser !== void 0)) {
4531
4782
  throw new Error(
4532
4783
  "githubToken and useLoggedInUser cannot be used with cliUrl (external server manages its own auth)"
@@ -4538,6 +4789,9 @@ var init_client = __esm({
4538
4789
  this.actualPort = port;
4539
4790
  this.isExternalServer = true;
4540
4791
  }
4792
+ if (options.isChildProcess) {
4793
+ this.isExternalServer = true;
4794
+ }
4541
4795
  this.options = {
4542
4796
  cliPath: options.cliPath || getBundledCliPath(),
4543
4797
  cliArgs: options.cliArgs ?? [],
@@ -4545,6 +4799,7 @@ var init_client = __esm({
4545
4799
  port: options.port || 0,
4546
4800
  useStdio: options.cliUrl ? false : options.useStdio ?? true,
4547
4801
  // Default to stdio unless cliUrl is provided
4802
+ isChildProcess: options.isChildProcess ?? false,
4548
4803
  cliUrl: options.cliUrl,
4549
4804
  logLevel: options.logLevel || "debug",
4550
4805
  autoStart: options.autoStart ?? true,
@@ -4616,10 +4871,14 @@ var init_client = __esm({
4616
4871
  * Stops the CLI server and closes all active sessions.
4617
4872
  *
4618
4873
  * This method performs graceful cleanup:
4619
- * 1. Destroys all active sessions with retry logic
4874
+ * 1. Closes all active sessions (releases in-memory resources)
4620
4875
  * 2. Closes the JSON-RPC connection
4621
4876
  * 3. Terminates the CLI server process (if spawned by this client)
4622
4877
  *
4878
+ * Note: session data on disk is preserved, so sessions can be resumed later.
4879
+ * To permanently remove session data before stopping, call
4880
+ * {@link deleteSession} for each session first.
4881
+ *
4623
4882
  * @returns A promise that resolves with an array of errors encountered during cleanup.
4624
4883
  * An empty array indicates all cleanup succeeded.
4625
4884
  *
@@ -4638,7 +4897,7 @@ var init_client = __esm({
4638
4897
  let lastError = null;
4639
4898
  for (let attempt = 1; attempt <= 3; attempt++) {
4640
4899
  try {
4641
- await session.destroy();
4900
+ await session.disconnect();
4642
4901
  lastError = null;
4643
4902
  break;
4644
4903
  } catch (error) {
@@ -4652,7 +4911,7 @@ var init_client = __esm({
4652
4911
  if (lastError) {
4653
4912
  errors.push(
4654
4913
  new Error(
4655
- `Failed to destroy session ${sessionId} after 3 attempts: ${lastError.message}`
4914
+ `Failed to disconnect session ${sessionId} after 3 attempts: ${lastError.message}`
4656
4915
  )
4657
4916
  );
4658
4917
  }
@@ -4669,6 +4928,7 @@ var init_client = __esm({
4669
4928
  );
4670
4929
  }
4671
4930
  this.connection = null;
4931
+ this._rpc = null;
4672
4932
  }
4673
4933
  this.modelsCache = null;
4674
4934
  if (this.socket) {
@@ -4697,6 +4957,8 @@ var init_client = __esm({
4697
4957
  }
4698
4958
  this.state = "disconnected";
4699
4959
  this.actualPort = null;
4960
+ this.stderrBuffer = "";
4961
+ this.processExitPromise = null;
4700
4962
  return errors;
4701
4963
  }
4702
4964
  /**
@@ -4733,6 +4995,7 @@ var init_client = __esm({
4733
4995
  } catch {
4734
4996
  }
4735
4997
  this.connection = null;
4998
+ this._rpc = null;
4736
4999
  }
4737
5000
  this.modelsCache = null;
4738
5001
  if (this.socket) {
@@ -4751,6 +5014,8 @@ var init_client = __esm({
4751
5014
  }
4752
5015
  this.state = "disconnected";
4753
5016
  this.actualPort = null;
5017
+ this.stderrBuffer = "";
5018
+ this.processExitPromise = null;
4754
5019
  }
4755
5020
  /**
4756
5021
  * Creates a new conversation session with the Copilot CLI.
@@ -4766,10 +5031,11 @@ var init_client = __esm({
4766
5031
  * @example
4767
5032
  * ```typescript
4768
5033
  * // Basic session
4769
- * const session = await client.createSession();
5034
+ * const session = await client.createSession({ onPermissionRequest: approveAll });
4770
5035
  *
4771
5036
  * // Session with model and tools
4772
5037
  * const session = await client.createSession({
5038
+ * onPermissionRequest: approveAll,
4773
5039
  * model: "gpt-4",
4774
5040
  * tools: [{
4775
5041
  * name: "get_weather",
@@ -4780,7 +5046,12 @@ var init_client = __esm({
4780
5046
  * });
4781
5047
  * ```
4782
5048
  */
4783
- async createSession(config2 = {}) {
5049
+ async createSession(config2) {
5050
+ if (!config2?.onPermissionRequest) {
5051
+ throw new Error(
5052
+ "An onPermissionRequest handler is required when creating a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }."
5053
+ );
5054
+ }
4784
5055
  if (!this.connection) {
4785
5056
  if (this.options.autoStart) {
4786
5057
  await this.start();
@@ -4791,22 +5062,25 @@ var init_client = __esm({
4791
5062
  const response = await this.connection.sendRequest("session.create", {
4792
5063
  model: config2.model,
4793
5064
  sessionId: config2.sessionId,
5065
+ clientName: config2.clientName,
4794
5066
  reasoningEffort: config2.reasoningEffort,
4795
5067
  tools: config2.tools?.map((tool) => ({
4796
5068
  name: tool.name,
4797
5069
  description: tool.description,
4798
- parameters: toJsonSchema(tool.parameters)
5070
+ parameters: toJsonSchema(tool.parameters),
5071
+ overridesBuiltInTool: tool.overridesBuiltInTool
4799
5072
  })),
4800
5073
  systemMessage: config2.systemMessage,
4801
5074
  availableTools: config2.availableTools,
4802
5075
  excludedTools: config2.excludedTools,
4803
5076
  provider: config2.provider,
4804
- requestPermission: !!config2.onPermissionRequest,
5077
+ requestPermission: true,
4805
5078
  requestUserInput: !!config2.onUserInputRequest,
4806
5079
  hooks: !!(config2.hooks && Object.values(config2.hooks).some(Boolean)),
4807
5080
  workingDirectory: config2.workingDirectory,
4808
5081
  streaming: config2.streaming,
4809
5082
  mcpServers: config2.mcpServers,
5083
+ envValueMode: "direct",
4810
5084
  customAgents: config2.customAgents,
4811
5085
  configDir: config2.configDir,
4812
5086
  skillDirectories: config2.skillDirectories,
@@ -4816,9 +5090,7 @@ var init_client = __esm({
4816
5090
  const { sessionId, workspacePath } = response;
4817
5091
  const session = new CopilotSession(sessionId, this.connection, workspacePath);
4818
5092
  session.registerTools(config2.tools);
4819
- if (config2.onPermissionRequest) {
4820
- session.registerPermissionHandler(config2.onPermissionRequest);
4821
- }
5093
+ session.registerPermissionHandler(config2.onPermissionRequest);
4822
5094
  if (config2.onUserInputRequest) {
4823
5095
  session.registerUserInputHandler(config2.onUserInputRequest);
4824
5096
  }
@@ -4843,15 +5115,21 @@ var init_client = __esm({
4843
5115
  * @example
4844
5116
  * ```typescript
4845
5117
  * // Resume a previous session
4846
- * const session = await client.resumeSession("session-123");
5118
+ * const session = await client.resumeSession("session-123", { onPermissionRequest: approveAll });
4847
5119
  *
4848
5120
  * // Resume with new tools
4849
5121
  * const session = await client.resumeSession("session-123", {
5122
+ * onPermissionRequest: approveAll,
4850
5123
  * tools: [myNewTool]
4851
5124
  * });
4852
5125
  * ```
4853
5126
  */
4854
- async resumeSession(sessionId, config2 = {}) {
5127
+ async resumeSession(sessionId, config2) {
5128
+ if (!config2?.onPermissionRequest) {
5129
+ throw new Error(
5130
+ "An onPermissionRequest handler is required when resuming a session. For example, to allow all permissions, use { onPermissionRequest: approveAll }."
5131
+ );
5132
+ }
4855
5133
  if (!this.connection) {
4856
5134
  if (this.options.autoStart) {
4857
5135
  await this.start();
@@ -4861,6 +5139,7 @@ var init_client = __esm({
4861
5139
  }
4862
5140
  const response = await this.connection.sendRequest("session.resume", {
4863
5141
  sessionId,
5142
+ clientName: config2.clientName,
4864
5143
  model: config2.model,
4865
5144
  reasoningEffort: config2.reasoningEffort,
4866
5145
  systemMessage: config2.systemMessage,
@@ -4869,16 +5148,18 @@ var init_client = __esm({
4869
5148
  tools: config2.tools?.map((tool) => ({
4870
5149
  name: tool.name,
4871
5150
  description: tool.description,
4872
- parameters: toJsonSchema(tool.parameters)
5151
+ parameters: toJsonSchema(tool.parameters),
5152
+ overridesBuiltInTool: tool.overridesBuiltInTool
4873
5153
  })),
4874
5154
  provider: config2.provider,
4875
- requestPermission: !!config2.onPermissionRequest,
5155
+ requestPermission: true,
4876
5156
  requestUserInput: !!config2.onUserInputRequest,
4877
5157
  hooks: !!(config2.hooks && Object.values(config2.hooks).some(Boolean)),
4878
5158
  workingDirectory: config2.workingDirectory,
4879
5159
  configDir: config2.configDir,
4880
5160
  streaming: config2.streaming,
4881
5161
  mcpServers: config2.mcpServers,
5162
+ envValueMode: "direct",
4882
5163
  customAgents: config2.customAgents,
4883
5164
  skillDirectories: config2.skillDirectories,
4884
5165
  disabledSkills: config2.disabledSkills,
@@ -4888,9 +5169,7 @@ var init_client = __esm({
4888
5169
  const { sessionId: resumedSessionId, workspacePath } = response;
4889
5170
  const session = new CopilotSession(resumedSessionId, this.connection, workspacePath);
4890
5171
  session.registerTools(config2.tools);
4891
- if (config2.onPermissionRequest) {
4892
- session.registerPermissionHandler(config2.onPermissionRequest);
4893
- }
5172
+ session.registerPermissionHandler(config2.onPermissionRequest);
4894
5173
  if (config2.onUserInputRequest) {
4895
5174
  session.registerUserInputHandler(config2.onUserInputRequest);
4896
5175
  }
@@ -4908,7 +5187,7 @@ var init_client = __esm({
4908
5187
  * @example
4909
5188
  * ```typescript
4910
5189
  * if (client.getState() === "connected") {
4911
- * const session = await client.createSession();
5190
+ * const session = await client.createSession({ onPermissionRequest: approveAll });
4912
5191
  * }
4913
5192
  * ```
4914
5193
  */
@@ -4986,22 +5265,29 @@ var init_client = __esm({
4986
5265
  }
4987
5266
  }
4988
5267
  /**
4989
- * Verify that the server's protocol version matches the SDK's expected version
5268
+ * Verify that the server's protocol version is within the supported range
5269
+ * and store the negotiated version.
4990
5270
  */
4991
5271
  async verifyProtocolVersion() {
4992
- const expectedVersion = getSdkProtocolVersion();
4993
- const pingResult = await this.ping();
5272
+ const maxVersion = getSdkProtocolVersion();
5273
+ let pingResult;
5274
+ if (this.processExitPromise) {
5275
+ pingResult = await Promise.race([this.ping(), this.processExitPromise]);
5276
+ } else {
5277
+ pingResult = await this.ping();
5278
+ }
4994
5279
  const serverVersion = pingResult.protocolVersion;
4995
5280
  if (serverVersion === void 0) {
4996
5281
  throw new Error(
4997
- `SDK protocol version mismatch: SDK expects version ${expectedVersion}, but server does not report a protocol version. Please update your server to ensure compatibility.`
5282
+ `SDK protocol version mismatch: SDK supports versions ${MIN_PROTOCOL_VERSION}-${maxVersion}, but server does not report a protocol version. Please update your server to ensure compatibility.`
4998
5283
  );
4999
5284
  }
5000
- if (serverVersion !== expectedVersion) {
5285
+ if (serverVersion < MIN_PROTOCOL_VERSION || serverVersion > maxVersion) {
5001
5286
  throw new Error(
5002
- `SDK protocol version mismatch: SDK expects version ${expectedVersion}, but server reports version ${serverVersion}. Please update your SDK or server to ensure compatibility.`
5287
+ `SDK protocol version mismatch: SDK supports versions ${MIN_PROTOCOL_VERSION}-${maxVersion}, but server reports version ${serverVersion}. Please update your SDK or server to ensure compatibility.`
5003
5288
  );
5004
5289
  }
5290
+ this.negotiatedProtocolVersion = serverVersion;
5005
5291
  }
5006
5292
  /**
5007
5293
  * Gets the ID of the most recently updated session.
@@ -5016,7 +5302,7 @@ var init_client = __esm({
5016
5302
  * ```typescript
5017
5303
  * const lastId = await client.getLastSessionId();
5018
5304
  * if (lastId) {
5019
- * const session = await client.resumeSession(lastId);
5305
+ * const session = await client.resumeSession(lastId, { onPermissionRequest: approveAll });
5020
5306
  * }
5021
5307
  * ```
5022
5308
  */
@@ -5028,10 +5314,12 @@ var init_client = __esm({
5028
5314
  return response.sessionId;
5029
5315
  }
5030
5316
  /**
5031
- * Deletes a session and its data from disk.
5317
+ * Permanently deletes a session and all its data from disk, including
5318
+ * conversation history, planning state, and artifacts.
5032
5319
  *
5033
- * This permanently removes the session and all its conversation history.
5034
- * The session cannot be resumed after deletion.
5320
+ * Unlike {@link CopilotSession.disconnect}, which only releases in-memory
5321
+ * resources and preserves session data for later resumption, this method
5322
+ * is irreversible. The session cannot be resumed after deletion.
5035
5323
  *
5036
5324
  * @param sessionId - The ID of the session to delete
5037
5325
  * @returns A promise that resolves when the session is deleted
@@ -5056,33 +5344,31 @@ var init_client = __esm({
5056
5344
  this.sessions.delete(sessionId);
5057
5345
  }
5058
5346
  /**
5059
- * Lists all available sessions known to the server.
5060
- *
5061
- * Returns metadata about each session including ID, timestamps, and summary.
5347
+ * List all available sessions.
5062
5348
  *
5063
- * @returns A promise that resolves with an array of session metadata
5064
- * @throws Error if the client is not connected
5349
+ * @param filter - Optional filter to limit returned sessions by context fields
5065
5350
  *
5066
5351
  * @example
5067
- * ```typescript
5352
+ * // List all sessions
5068
5353
  * const sessions = await client.listSessions();
5069
- * for (const session of sessions) {
5070
- * console.log(`${session.sessionId}: ${session.summary}`);
5071
- * }
5072
- * ```
5354
+ *
5355
+ * @example
5356
+ * // List sessions for a specific repository
5357
+ * const sessions = await client.listSessions({ repository: "owner/repo" });
5073
5358
  */
5074
- async listSessions() {
5359
+ async listSessions(filter) {
5075
5360
  if (!this.connection) {
5076
5361
  throw new Error("Client not connected");
5077
5362
  }
5078
- const response = await this.connection.sendRequest("session.list", {});
5363
+ const response = await this.connection.sendRequest("session.list", { filter });
5079
5364
  const { sessions } = response;
5080
5365
  return sessions.map((s) => ({
5081
5366
  sessionId: s.sessionId,
5082
5367
  startTime: new Date(s.startTime),
5083
5368
  modifiedTime: new Date(s.modifiedTime),
5084
5369
  summary: s.summary,
5085
- isRemote: s.isRemote
5370
+ isRemote: s.isRemote,
5371
+ context: s.context
5086
5372
  }));
5087
5373
  }
5088
5374
  /**
@@ -5161,6 +5447,7 @@ var init_client = __esm({
5161
5447
  */
5162
5448
  async startCLIServer() {
5163
5449
  return new Promise((resolve3, reject) => {
5450
+ this.stderrBuffer = "";
5164
5451
  const args = [
5165
5452
  ...this.options.cliArgs,
5166
5453
  "--headless",
@@ -5192,16 +5479,18 @@ var init_client = __esm({
5192
5479
  const stdioConfig = this.options.useStdio ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
5193
5480
  const isJsFile = this.options.cliPath.endsWith(".js");
5194
5481
  if (isJsFile) {
5195
- this.cliProcess = spawn(process.execPath, [this.options.cliPath, ...args], {
5482
+ this.cliProcess = spawn(getNodeExecPath(), [this.options.cliPath, ...args], {
5196
5483
  stdio: stdioConfig,
5197
5484
  cwd: this.options.cwd,
5198
- env: envWithoutNodeDebug
5485
+ env: envWithoutNodeDebug,
5486
+ windowsHide: true
5199
5487
  });
5200
5488
  } else {
5201
5489
  this.cliProcess = spawn(this.options.cliPath, args, {
5202
5490
  stdio: stdioConfig,
5203
5491
  cwd: this.options.cwd,
5204
- env: envWithoutNodeDebug
5492
+ env: envWithoutNodeDebug,
5493
+ windowsHide: true
5205
5494
  });
5206
5495
  }
5207
5496
  let stdout = "";
@@ -5221,6 +5510,7 @@ var init_client = __esm({
5221
5510
  });
5222
5511
  }
5223
5512
  this.cliProcess.stderr?.on("data", (data) => {
5513
+ this.stderrBuffer += data.toString();
5224
5514
  const lines = data.toString().split("\n");
5225
5515
  for (const line of lines) {
5226
5516
  if (line.trim()) {
@@ -5232,13 +5522,54 @@ var init_client = __esm({
5232
5522
  this.cliProcess.on("error", (error) => {
5233
5523
  if (!resolved) {
5234
5524
  resolved = true;
5235
- reject(new Error(`Failed to start CLI server: ${error.message}`));
5525
+ const stderrOutput = this.stderrBuffer.trim();
5526
+ if (stderrOutput) {
5527
+ reject(
5528
+ new Error(
5529
+ `Failed to start CLI server: ${error.message}
5530
+ stderr: ${stderrOutput}`
5531
+ )
5532
+ );
5533
+ } else {
5534
+ reject(new Error(`Failed to start CLI server: ${error.message}`));
5535
+ }
5236
5536
  }
5237
5537
  });
5538
+ this.processExitPromise = new Promise((_, rejectProcessExit) => {
5539
+ this.cliProcess.on("exit", (code) => {
5540
+ setTimeout(() => {
5541
+ const stderrOutput = this.stderrBuffer.trim();
5542
+ if (stderrOutput) {
5543
+ rejectProcessExit(
5544
+ new Error(
5545
+ `CLI server exited with code ${code}
5546
+ stderr: ${stderrOutput}`
5547
+ )
5548
+ );
5549
+ } else {
5550
+ rejectProcessExit(
5551
+ new Error(`CLI server exited unexpectedly with code ${code}`)
5552
+ );
5553
+ }
5554
+ }, 50);
5555
+ });
5556
+ });
5557
+ this.processExitPromise.catch(() => {
5558
+ });
5238
5559
  this.cliProcess.on("exit", (code) => {
5239
5560
  if (!resolved) {
5240
5561
  resolved = true;
5241
- reject(new Error(`CLI server exited with code ${code}`));
5562
+ const stderrOutput = this.stderrBuffer.trim();
5563
+ if (stderrOutput) {
5564
+ reject(
5565
+ new Error(
5566
+ `CLI server exited with code ${code}
5567
+ stderr: ${stderrOutput}`
5568
+ )
5569
+ );
5570
+ } else {
5571
+ reject(new Error(`CLI server exited with code ${code}`));
5572
+ }
5242
5573
  } else if (this.options.autoRestart && this.state === "connected") {
5243
5574
  void this.reconnect();
5244
5575
  }
@@ -5255,16 +5586,18 @@ var init_client = __esm({
5255
5586
  * Connect to the CLI server (via socket or stdio)
5256
5587
  */
5257
5588
  async connectToServer() {
5258
- if (this.options.useStdio) {
5259
- return this.connectViaStdio();
5589
+ if (this.options.isChildProcess) {
5590
+ return this.connectToParentProcessViaStdio();
5591
+ } else if (this.options.useStdio) {
5592
+ return this.connectToChildProcessViaStdio();
5260
5593
  } else {
5261
5594
  return this.connectViaTcp();
5262
5595
  }
5263
5596
  }
5264
5597
  /**
5265
- * Connect via stdio pipes
5598
+ * Connect to child via stdio pipes
5266
5599
  */
5267
- async connectViaStdio() {
5600
+ async connectToChildProcessViaStdio() {
5268
5601
  if (!this.cliProcess) {
5269
5602
  throw new Error("CLI process not started");
5270
5603
  }
@@ -5273,9 +5606,23 @@ var init_client = __esm({
5273
5606
  throw err;
5274
5607
  }
5275
5608
  });
5276
- this.connection = (0, import_node.createMessageConnection)(
5277
- new import_node.StreamMessageReader(this.cliProcess.stdout),
5278
- new import_node.StreamMessageWriter(this.cliProcess.stdin)
5609
+ this.connection = (0, import_node2.createMessageConnection)(
5610
+ new import_node2.StreamMessageReader(this.cliProcess.stdout),
5611
+ new import_node2.StreamMessageWriter(this.cliProcess.stdin)
5612
+ );
5613
+ this.attachConnectionHandlers();
5614
+ this.connection.listen();
5615
+ }
5616
+ /**
5617
+ * Connect to parent via stdio pipes
5618
+ */
5619
+ async connectToParentProcessViaStdio() {
5620
+ if (this.cliProcess) {
5621
+ throw new Error("CLI child process was unexpectedly started in parent process mode");
5622
+ }
5623
+ this.connection = (0, import_node2.createMessageConnection)(
5624
+ new import_node2.StreamMessageReader(process.stdin),
5625
+ new import_node2.StreamMessageWriter(process.stdout)
5279
5626
  );
5280
5627
  this.attachConnectionHandlers();
5281
5628
  this.connection.listen();
@@ -5290,9 +5637,9 @@ var init_client = __esm({
5290
5637
  return new Promise((resolve3, reject) => {
5291
5638
  this.socket = new Socket();
5292
5639
  this.socket.connect(this.actualPort, this.actualHost, () => {
5293
- this.connection = (0, import_node.createMessageConnection)(
5294
- new import_node.StreamMessageReader(this.socket),
5295
- new import_node.StreamMessageWriter(this.socket)
5640
+ this.connection = (0, import_node2.createMessageConnection)(
5641
+ new import_node2.StreamMessageReader(this.socket),
5642
+ new import_node2.StreamMessageWriter(this.socket)
5296
5643
  );
5297
5644
  this.attachConnectionHandlers();
5298
5645
  this.connection.listen();
@@ -5315,11 +5662,11 @@ var init_client = __esm({
5315
5662
  });
5316
5663
  this.connection.onRequest(
5317
5664
  "tool.call",
5318
- async (params) => await this.handleToolCallRequest(params)
5665
+ async (params) => await this.handleToolCallRequestV2(params)
5319
5666
  );
5320
5667
  this.connection.onRequest(
5321
5668
  "permission.request",
5322
- async (params) => await this.handlePermissionRequest(params)
5669
+ async (params) => await this.handlePermissionRequestV2(params)
5323
5670
  );
5324
5671
  this.connection.onRequest(
5325
5672
  "userInput.request",
@@ -5367,7 +5714,41 @@ var init_client = __esm({
5367
5714
  }
5368
5715
  }
5369
5716
  }
5370
- async handleToolCallRequest(params) {
5717
+ async handleUserInputRequest(params) {
5718
+ if (!params || typeof params.sessionId !== "string" || typeof params.question !== "string") {
5719
+ throw new Error("Invalid user input request payload");
5720
+ }
5721
+ const session = this.sessions.get(params.sessionId);
5722
+ if (!session) {
5723
+ throw new Error(`Session not found: ${params.sessionId}`);
5724
+ }
5725
+ const result = await session._handleUserInputRequest({
5726
+ question: params.question,
5727
+ choices: params.choices,
5728
+ allowFreeform: params.allowFreeform
5729
+ });
5730
+ return result;
5731
+ }
5732
+ async handleHooksInvoke(params) {
5733
+ if (!params || typeof params.sessionId !== "string" || typeof params.hookType !== "string") {
5734
+ throw new Error("Invalid hooks invoke payload");
5735
+ }
5736
+ const session = this.sessions.get(params.sessionId);
5737
+ if (!session) {
5738
+ throw new Error(`Session not found: ${params.sessionId}`);
5739
+ }
5740
+ const output = await session._handleHooksInvoke(params.hookType, params.input);
5741
+ return { output };
5742
+ }
5743
+ // ========================================================================
5744
+ // Protocol v2 backward-compatibility adapters
5745
+ // ========================================================================
5746
+ /**
5747
+ * Handles a v2-style tool.call RPC request from the server.
5748
+ * Looks up the session and tool handler, executes it, and returns the result
5749
+ * in the v2 response format.
5750
+ */
5751
+ async handleToolCallRequestV2(params) {
5371
5752
  if (!params || typeof params.sessionId !== "string" || typeof params.toolCallId !== "string" || typeof params.toolName !== "string") {
5372
5753
  throw new Error("Invalid tool call payload");
5373
5754
  }
@@ -5377,25 +5758,28 @@ var init_client = __esm({
5377
5758
  }
5378
5759
  const handler = session.getToolHandler(params.toolName);
5379
5760
  if (!handler) {
5380
- return { result: this.buildUnsupportedToolResult(params.toolName) };
5761
+ return {
5762
+ result: {
5763
+ textResultForLlm: `Tool '${params.toolName}' is not supported by this client instance.`,
5764
+ resultType: "failure",
5765
+ error: `tool '${params.toolName}' not supported`,
5766
+ toolTelemetry: {}
5767
+ }
5768
+ };
5381
5769
  }
5382
- return await this.executeToolCall(handler, params);
5383
- }
5384
- async executeToolCall(handler, request) {
5385
5770
  try {
5386
5771
  const invocation = {
5387
- sessionId: request.sessionId,
5388
- toolCallId: request.toolCallId,
5389
- toolName: request.toolName,
5390
- arguments: request.arguments
5772
+ sessionId: params.sessionId,
5773
+ toolCallId: params.toolCallId,
5774
+ toolName: params.toolName,
5775
+ arguments: params.arguments
5391
5776
  };
5392
- const result = await handler(request.arguments, invocation);
5393
- return { result: this.normalizeToolResult(result) };
5777
+ const result = await handler(params.arguments, invocation);
5778
+ return { result: this.normalizeToolResultV2(result) };
5394
5779
  } catch (error) {
5395
5780
  const message = error instanceof Error ? error.message : String(error);
5396
5781
  return {
5397
5782
  result: {
5398
- // Don't expose detailed error information to the LLM for security reasons
5399
5783
  textResultForLlm: "Invoking this tool produced an error. Detailed information is not available.",
5400
5784
  resultType: "failure",
5401
5785
  error: message,
@@ -5404,7 +5788,10 @@ var init_client = __esm({
5404
5788
  };
5405
5789
  }
5406
5790
  }
5407
- async handlePermissionRequest(params) {
5791
+ /**
5792
+ * Handles a v2-style permission.request RPC request from the server.
5793
+ */
5794
+ async handlePermissionRequestV2(params) {
5408
5795
  if (!params || typeof params.sessionId !== "string" || !params.permissionRequest) {
5409
5796
  throw new Error("Invalid permission request payload");
5410
5797
  }
@@ -5413,7 +5800,7 @@ var init_client = __esm({
5413
5800
  throw new Error(`Session not found: ${params.sessionId}`);
5414
5801
  }
5415
5802
  try {
5416
- const result = await session._handlePermissionRequest(params.permissionRequest);
5803
+ const result = await session._handlePermissionRequestV2(params.permissionRequest);
5417
5804
  return { result };
5418
5805
  } catch (_error) {
5419
5806
  return {
@@ -5423,33 +5810,7 @@ var init_client = __esm({
5423
5810
  };
5424
5811
  }
5425
5812
  }
5426
- async handleUserInputRequest(params) {
5427
- if (!params || typeof params.sessionId !== "string" || typeof params.question !== "string") {
5428
- throw new Error("Invalid user input request payload");
5429
- }
5430
- const session = this.sessions.get(params.sessionId);
5431
- if (!session) {
5432
- throw new Error(`Session not found: ${params.sessionId}`);
5433
- }
5434
- const result = await session._handleUserInputRequest({
5435
- question: params.question,
5436
- choices: params.choices,
5437
- allowFreeform: params.allowFreeform
5438
- });
5439
- return result;
5440
- }
5441
- async handleHooksInvoke(params) {
5442
- if (!params || typeof params.sessionId !== "string" || typeof params.hookType !== "string") {
5443
- throw new Error("Invalid hooks invoke payload");
5444
- }
5445
- const session = this.sessions.get(params.sessionId);
5446
- if (!session) {
5447
- throw new Error(`Session not found: ${params.sessionId}`);
5448
- }
5449
- const output = await session._handleHooksInvoke(params.hookType, params.input);
5450
- return { output };
5451
- }
5452
- normalizeToolResult(result) {
5813
+ normalizeToolResultV2(result) {
5453
5814
  if (result === void 0 || result === null) {
5454
5815
  return {
5455
5816
  textResultForLlm: "Tool returned no result",
@@ -5471,14 +5832,6 @@ var init_client = __esm({
5471
5832
  isToolResultObject(value) {
5472
5833
  return typeof value === "object" && value !== null && "textResultForLlm" in value && typeof value.textResultForLlm === "string" && "resultType" in value;
5473
5834
  }
5474
- buildUnsupportedToolResult(toolName) {
5475
- return {
5476
- textResultForLlm: `Tool '${toolName}' is not supported by this client instance.`,
5477
- resultType: "failure",
5478
- error: `tool '${toolName}' not supported`,
5479
- toolTelemetry: {}
5480
- };
5481
- }
5482
5835
  /**
5483
5836
  * Attempt to reconnect to the server
5484
5837
  */
@@ -5495,9 +5848,11 @@ var init_client = __esm({
5495
5848
  });
5496
5849
 
5497
5850
  // node_modules/@github/copilot-sdk/dist/types.js
5851
+ var approveAll;
5498
5852
  var init_types2 = __esm({
5499
5853
  "node_modules/@github/copilot-sdk/dist/types.js"() {
5500
5854
  "use strict";
5855
+ approveAll = () => ({ kind: "approved" });
5501
5856
  }
5502
5857
  });
5503
5858
 
@@ -5512,6 +5867,33 @@ var init_dist = __esm({
5512
5867
  });
5513
5868
 
5514
5869
  // src/L1-infra/ai/copilot.ts
5870
+ import { existsSync as existsSync5 } from "fs";
5871
+ import { join as join6, dirname as dirname4 } from "path";
5872
+ import { createRequire as createRequire2 } from "module";
5873
+ function resolveCopilotCliPath() {
5874
+ const platform = process.platform;
5875
+ const arch = process.arch;
5876
+ const binaryName = platform === "win32" ? "copilot.exe" : "copilot";
5877
+ const platformPkg = `@github/copilot-${platform}-${arch}`;
5878
+ try {
5879
+ const require_ = createRequire2(import.meta.url);
5880
+ const searchPaths = require_.resolve.paths(platformPkg) ?? [];
5881
+ for (const base of searchPaths) {
5882
+ const candidate = join6(base, platformPkg, binaryName);
5883
+ if (existsSync5(candidate)) return candidate;
5884
+ }
5885
+ } catch {
5886
+ }
5887
+ let dir = dirname4(import.meta.dirname ?? __dirname);
5888
+ for (let i = 0; i < 10; i++) {
5889
+ const candidate = join6(dir, "node_modules", platformPkg, binaryName);
5890
+ if (existsSync5(candidate)) return candidate;
5891
+ const parent = dirname4(dir);
5892
+ if (parent === dir) break;
5893
+ dir = parent;
5894
+ }
5895
+ return void 0;
5896
+ }
5515
5897
  var init_copilot = __esm({
5516
5898
  "src/L1-infra/ai/copilot.ts"() {
5517
5899
  "use strict";
@@ -5539,14 +5921,25 @@ var init_ai = __esm({
5539
5921
  });
5540
5922
 
5541
5923
  // src/L2-clients/llm/CopilotProvider.ts
5542
- var DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, CopilotProvider, CopilotSessionWrapper;
5924
+ function buildChildEnv() {
5925
+ const env = { ...process.env };
5926
+ const flag = "--disable-warning=ExperimentalWarning";
5927
+ const current = env.NODE_OPTIONS ?? "";
5928
+ if (!current.includes(flag)) {
5929
+ env.NODE_OPTIONS = current ? `${current} ${flag}` : flag;
5930
+ }
5931
+ return env;
5932
+ }
5933
+ var DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, SESSION_CREATE_TIMEOUT_MS, CopilotProvider, CopilotSessionWrapper;
5543
5934
  var init_CopilotProvider = __esm({
5544
5935
  "src/L2-clients/llm/CopilotProvider.ts"() {
5545
5936
  "use strict";
5546
5937
  init_ai();
5938
+ init_copilot();
5547
5939
  init_configLogger();
5548
5940
  DEFAULT_MODEL = "claude-opus-4.5";
5549
5941
  DEFAULT_TIMEOUT_MS = 3e5;
5942
+ SESSION_CREATE_TIMEOUT_MS = 3e4;
5550
5943
  CopilotProvider = class {
5551
5944
  name = "copilot";
5552
5945
  client = null;
@@ -5558,21 +5951,57 @@ var init_CopilotProvider = __esm({
5558
5951
  }
5559
5952
  async createSession(config2) {
5560
5953
  if (!this.client) {
5561
- this.client = createCopilotClient({ autoStart: true, logLevel: "error" });
5954
+ const cliPath = resolveCopilotCliPath();
5955
+ if (cliPath) {
5956
+ logger_default.info(`[CopilotProvider] Using native CLI binary: ${cliPath}`);
5957
+ }
5958
+ this.client = createCopilotClient({
5959
+ autoStart: true,
5960
+ autoRestart: true,
5961
+ logLevel: "error",
5962
+ env: buildChildEnv(),
5963
+ ...cliPath ? { cliPath } : {}
5964
+ });
5562
5965
  }
5563
- const copilotSession = await this.client.createSession({
5564
- model: config2.model,
5565
- mcpServers: config2.mcpServers,
5566
- systemMessage: { mode: "replace", content: config2.systemPrompt },
5567
- tools: config2.tools.map((t) => ({
5568
- name: t.name,
5569
- description: t.description,
5570
- parameters: t.parameters,
5571
- handler: t.handler
5572
- })),
5573
- streaming: config2.streaming ?? true,
5574
- onUserInputRequest: config2.onUserInputRequest ? (request) => config2.onUserInputRequest(request) : void 0
5575
- });
5966
+ logger_default.info("[CopilotProvider] Creating session\u2026");
5967
+ let copilotSession;
5968
+ try {
5969
+ copilotSession = await new Promise((resolve3, reject) => {
5970
+ const timeoutId = setTimeout(
5971
+ () => reject(new Error(
5972
+ `[CopilotProvider] createSession timed out after ${SESSION_CREATE_TIMEOUT_MS / 1e3}s \u2014 the Copilot SDK language server may not be reachable. Check GitHub authentication and network connectivity.`
5973
+ )),
5974
+ SESSION_CREATE_TIMEOUT_MS
5975
+ );
5976
+ this.client.createSession({
5977
+ model: config2.model,
5978
+ mcpServers: config2.mcpServers,
5979
+ systemMessage: { mode: "replace", content: config2.systemPrompt },
5980
+ tools: config2.tools.map((t) => ({
5981
+ name: t.name,
5982
+ description: t.description,
5983
+ parameters: t.parameters,
5984
+ handler: t.handler
5985
+ })),
5986
+ streaming: config2.streaming ?? true,
5987
+ onPermissionRequest: approveAll,
5988
+ onUserInputRequest: config2.onUserInputRequest ? (request) => config2.onUserInputRequest(request) : void 0
5989
+ }).then(
5990
+ (session) => {
5991
+ clearTimeout(timeoutId);
5992
+ resolve3(session);
5993
+ },
5994
+ (err) => {
5995
+ clearTimeout(timeoutId);
5996
+ reject(err);
5997
+ }
5998
+ );
5999
+ });
6000
+ } catch (err) {
6001
+ this.client = null;
6002
+ throw err;
6003
+ }
6004
+ logger_default.info("[CopilotProvider] Session created successfully");
5576
6005
  return new CopilotSessionWrapper(
5577
6006
  copilotSession,
5578
6007
  config2.timeoutMs ?? DEFAULT_TIMEOUT_MS
@@ -5928,7 +6357,8 @@ var init_OpenAIProvider = __esm({
5928
6357
  return "gpt-4o";
5929
6358
  }
5930
6359
  async createSession(config2) {
5931
- const client = createOpenAI();
6360
+ const appConfig = getConfig();
6361
+ const client = createOpenAI({ apiKey: appConfig.OPENAI_API_KEY });
5932
6362
  const model = config2.model ?? this.getDefaultModel();
5933
6363
  logger_default.info(`OpenAI session created (model=${model}, tools=${config2.tools.length})`);
5934
6364
  return new OpenAISession(client, config2, model);
@@ -6192,12 +6622,13 @@ var init_providerFactory = __esm({
6192
6622
 
6193
6623
  // src/L1-infra/config/modelConfig.ts
6194
6624
  function getModelForAgent(agentName) {
6625
+ const config2 = getConfig();
6195
6626
  const envKey = `MODEL_${agentName.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase()}`;
6196
- const envOverride = process.env[envKey];
6627
+ const envOverride = config2.MODEL_OVERRIDES[envKey];
6197
6628
  if (envOverride) return envOverride;
6198
6629
  const mapped = AGENT_MODEL_MAP[agentName];
6199
6630
  if (mapped) return mapped;
6200
- const global = getConfig().LLM_MODEL;
6631
+ const global = config2.LLM_MODEL;
6201
6632
  if (global) return global;
6202
6633
  return void 0;
6203
6634
  }
@@ -7330,6 +7761,7 @@ init_environment();
7330
7761
  // src/L1-infra/progress/progressEmitter.ts
7331
7762
  var ProgressEmitter = class {
7332
7763
  enabled = false;
7764
+ listeners = /* @__PURE__ */ new Set();
7333
7765
  /** Turn on progress event output to stderr. */
7334
7766
  enable() {
7335
7767
  this.enabled = true;
@@ -7338,17 +7770,31 @@ var ProgressEmitter = class {
7338
7770
  disable() {
7339
7771
  this.enabled = false;
7340
7772
  }
7341
- /** Whether the emitter is currently active. */
7773
+ /** Whether the emitter is currently active (stderr or listeners). */
7342
7774
  isEnabled() {
7343
- return this.enabled;
7775
+ return this.enabled || this.listeners.size > 0;
7776
+ }
7777
+ /** Register a programmatic listener for progress events. */
7778
+ addListener(fn) {
7779
+ this.listeners.add(fn);
7780
+ }
7781
+ /** Remove a previously registered listener. */
7782
+ removeListener(fn) {
7783
+ this.listeners.delete(fn);
7344
7784
  }
7345
7785
  /**
7346
- * Write a progress event as a single JSON line to stderr.
7347
- * No-op when the emitter is disabled.
7786
+ * Write a progress event as a single JSON line to stderr (if enabled)
7787
+ * and dispatch to all registered listeners.
7788
+ * No-op when neither stderr output nor listeners are active.
7348
7789
  */
7349
7790
  emit(event) {
7350
- if (!this.enabled) return;
7351
- process.stderr.write(JSON.stringify(event) + "\n");
7791
+ if (!this.enabled && this.listeners.size === 0) return;
7792
+ if (this.enabled) {
7793
+ process.stderr.write(JSON.stringify(event) + "\n");
7794
+ }
7795
+ for (const listener of this.listeners) {
7796
+ listener(event);
7797
+ }
7352
7798
  }
7353
7799
  };
7354
7800
  var progressEmitter = new ProgressEmitter();
@@ -7446,9 +7892,6 @@ function execFileRaw(cmd, args, opts, callback) {
7446
7892
  callback(error, String(stdout ?? ""), String(stderr ?? ""));
7447
7893
  });
7448
7894
  }
7449
- function execCommandSync(cmd, opts) {
7450
- return nodeExecSync(cmd, { encoding: "utf-8", ...opts }).toString().trim();
7451
- }
7452
7895
  function spawnCommand(cmd, args, opts) {
7453
7896
  return nodeSpawnSync(cmd, args, { encoding: "utf-8", ...opts });
7454
7897
  }
@@ -8672,6 +9115,8 @@ function transcodeToMp4(inputPath, outputPath) {
8672
9115
  createFFmpeg(inputPath).outputOptions([
8673
9116
  "-c:v",
8674
9117
  "libx264",
9118
+ "-pix_fmt",
9119
+ "yuv420p",
8675
9120
  "-preset",
8676
9121
  "ultrafast",
8677
9122
  "-crf",
@@ -10468,6 +10913,7 @@ var BaseAgent = class _BaseAgent {
10468
10913
  for (let attempt = 1; attempt <= _BaseAgent.MAX_RETRIES; attempt++) {
10469
10914
  try {
10470
10915
  if (!this.session) {
10916
+ logger_default.info(`[${this.agentName}] Creating LLM session (provider=${this.provider.name})\u2026`);
10471
10917
  this.session = await this.provider.createSession({
10472
10918
  systemPrompt: this.systemPrompt,
10473
10919
  tools: this.getTools(),
@@ -10478,6 +10924,7 @@ var BaseAgent = class _BaseAgent {
10478
10924
  onUserInputRequest: this.getUserInputHandler()
10479
10925
  });
10480
10926
  this.setupEventHandlers(this.session);
10927
+ logger_default.info(`[${this.agentName}] LLM session ready`);
10481
10928
  }
10482
10929
  logger_default.info(`[${this.agentName}] Sending message (attempt ${attempt}/${_BaseAgent.MAX_RETRIES}): ${userMessage.substring(0, 80)}\u2026`);
10483
10930
  costTracker.setAgent(this.agentName);
@@ -10515,11 +10962,12 @@ var BaseAgent = class _BaseAgent {
10515
10962
  }
10516
10963
  /** Check if an error message indicates a transient/retryable failure. */
10517
10964
  static isRetryableError(message) {
10518
- const retryablePatterns = [
10965
+ const lower = message.toLowerCase();
10966
+ return [
10519
10967
  "missing finish_reason",
10520
- "ECONNRESET",
10521
- "ETIMEDOUT",
10522
- "ECONNREFUSED",
10968
+ "econnreset",
10969
+ "etimedout",
10970
+ "econnrefused",
10523
10971
  "socket hang up",
10524
10972
  "network error",
10525
10973
  "rate limit",
@@ -10529,10 +10977,9 @@ var BaseAgent = class _BaseAgent {
10529
10977
  "503",
10530
10978
  "504",
10531
10979
  "stream ended",
10532
- "aborted"
10533
- ];
10534
- const lower = message.toLowerCase();
10535
- return retryablePatterns.some((p) => lower.includes(p.toLowerCase()));
10980
+ "aborted",
10981
+ "cli server exited"
10982
+ ].some((p) => lower.includes(p));
10536
10983
  }
10537
10984
  /** Wire up session event listeners for logging. Override for custom display. */
10538
10985
  setupEventHandlers(session) {
@@ -13000,32 +13447,6 @@ async function markFailed(slug, error) {
13000
13447
  logger_default.info(`[ProcessingState] Marked failed: ${slug} \u2014 ${error}`);
13001
13448
  }
13002
13449
 
13003
- // src/L3-services/gitOperations/gitOperations.ts
13004
- init_environment();
13005
- init_configLogger();
13006
- async function commitAndPush(videoSlug, message) {
13007
- const { REPO_ROOT } = getConfig();
13008
- const commitMessage = message || `Auto-processed video: ${videoSlug}`;
13009
- try {
13010
- logger_default.info(`Staging all changes in ${REPO_ROOT}`);
13011
- execCommandSync("git add -A", { cwd: REPO_ROOT, stdio: "pipe" });
13012
- logger_default.info(`Committing: ${commitMessage}`);
13013
- execCommandSync(`git commit -m "${commitMessage}"`, { cwd: REPO_ROOT, stdio: "pipe" });
13014
- const branch = execCommandSync("git rev-parse --abbrev-ref HEAD", { cwd: REPO_ROOT, stdio: "pipe" });
13015
- logger_default.info(`Pushing to origin ${branch}`);
13016
- execCommandSync(`git push origin ${branch}`, { cwd: REPO_ROOT, stdio: "pipe" });
13017
- logger_default.info("Git commit and push completed successfully");
13018
- } catch (error) {
13019
- const msg = error instanceof Error ? error.message : String(error);
13020
- if (msg.includes("nothing to commit")) {
13021
- logger_default.info("Nothing to commit, working tree clean");
13022
- return;
13023
- }
13024
- logger_default.error(`Git operation failed: ${msg}`);
13025
- throw error;
13026
- }
13027
- }
13028
-
13029
13450
  // src/L3-services/queueBuilder/queueBuilder.ts
13030
13451
  init_fileSystem();
13031
13452
  init_paths();
@@ -13643,9 +14064,6 @@ function markCompleted2(...args) {
13643
14064
  function markFailed2(...args) {
13644
14065
  return markFailed(...args);
13645
14066
  }
13646
- function commitAndPush2(...args) {
13647
- return commitAndPush(...args);
13648
- }
13649
14067
  function buildPublishQueue2(...args) {
13650
14068
  return buildPublishQueue(...args);
13651
14069
  }
@@ -14793,12 +15211,6 @@ var MainVideoAsset = class _MainVideoAsset extends VideoAsset {
14793
15211
  async buildQueue(shorts, mediumClips, socialPosts, captionedVideoPath) {
14794
15212
  await this.buildPublishQueueData(shorts, mediumClips, socialPosts, captionedVideoPath);
14795
15213
  }
14796
- /**
14797
- * Commit and push all generated assets via git.
14798
- */
14799
- async commitAndPushChanges(message) {
14800
- return commitAndPush2(this.slug, message);
14801
- }
14802
15214
  };
14803
15215
 
14804
15216
  // src/L2-clients/late/lateApi.ts
@@ -17480,11 +17892,6 @@ async function processVideo(videoPath, ideas) {
17480
17892
  skipStage("queue-build" /* QueueBuild */, "NO_SOCIAL_POSTS");
17481
17893
  }
17482
17894
  const blogPost = await trackStage("blog" /* Blog */, () => asset.getBlog());
17483
- if (!cfg.SKIP_GIT) {
17484
- await trackStage("git-push" /* GitPush */, () => asset.commitAndPushChanges());
17485
- } else {
17486
- skipStage("git-push" /* GitPush */, "SKIP_GIT");
17487
- }
17488
17895
  const totalDuration = Date.now() - pipelineStart;
17489
17896
  const report = costTracker3.getReport();
17490
17897
  if (report.records.length > 0) {
@@ -17866,6 +18273,7 @@ async function checkScheduleConfig() {
17866
18273
  // src/L7-app/commands/init.ts
17867
18274
  init_fileSystem();
17868
18275
  init_paths();
18276
+ init_environment();
17869
18277
 
17870
18278
  // src/L3-services/diagnostics/diagnostics.ts
17871
18279
  function getFFmpegPath3(...args) {
@@ -17915,7 +18323,7 @@ async function runInit() {
17915
18323
  console.log(" \u274C FFprobe not found");
17916
18324
  }
17917
18325
  console.log("\nStep 2/5: OpenAI (Required for transcription)");
17918
- const currentOpenAI = existingVars.OPENAI_API_KEY || process.env.OPENAI_API_KEY;
18326
+ const currentOpenAI = existingVars.OPENAI_API_KEY || getConfig().OPENAI_API_KEY;
17919
18327
  const hint = currentOpenAI ? ` (current: ${currentOpenAI.slice(0, 8)}...)` : "";
17920
18328
  const openaiKey = await ask(` ? OpenAI API key${hint}: `);
17921
18329
  if (openaiKey.trim()) {
@@ -19281,7 +19689,7 @@ function createRouter() {
19281
19689
  // src/L7-app/review/server.ts
19282
19690
  init_environment();
19283
19691
  init_configLogger();
19284
- var __dirname2 = dirname(fileURLToPath(import.meta.url));
19692
+ var __dirname3 = dirname(fileURLToPath(import.meta.url));
19285
19693
  async function startReviewServer(options = {}) {
19286
19694
  const app = default8();
19287
19695
  const port = options.port || 3847;
@@ -19292,7 +19700,7 @@ async function startReviewServer(options = {}) {
19292
19700
  const publishedDir = join(cfg.OUTPUT_DIR, "published");
19293
19701
  app.use("/media/queue", default8.static(queueDir));
19294
19702
  app.use("/media/published", default8.static(publishedDir));
19295
- const publicDir = join(__dirname2, "public");
19703
+ const publicDir = join(__dirname3, "public");
19296
19704
  app.use(default8.static(publicDir));
19297
19705
  app.get("/{*splat}", (req, res) => {
19298
19706
  if (!req.path.startsWith("/api/") && !req.path.startsWith("/media/")) {
@@ -19412,7 +19820,7 @@ program.command("configure [subcommand]").description("Manage global configurati
19412
19820
  await runConfigure(subcommand, args);
19413
19821
  process.exit(process.exitCode ?? 0);
19414
19822
  });
19415
- var defaultCmd = program.command("process", { isDefault: true }).argument("[video-path]", "Path to a video file to process (implies --once)").option("--watch-dir <path>", "Folder to watch for new recordings (default: env WATCH_FOLDER)").option("--output-dir <path>", "Output directory for processed videos (default: ./recordings)").option("--openai-key <key>", "OpenAI API key (default: env OPENAI_API_KEY)").option("--exa-key <key>", "Exa AI API key for web search (default: env EXA_API_KEY)").option("--youtube-key <key>", "YouTube API key (default: env YOUTUBE_API_KEY)").option("--perplexity-key <key>", "Perplexity API key (default: env PERPLEXITY_API_KEY)").option("--once", "Process a single video and exit (no watching)").option("--brand <path>", "Path to brand.json config (default: ./brand.json)").option("--no-git", "Skip git commit/push stage").option("--no-silence-removal", "Skip silence removal stage").option("--no-shorts", "Skip shorts generation").option("--no-medium-clips", "Skip medium clip generation").option("--no-social", "Skip social media post generation").option("--no-captions", "Skip caption generation/burning").option("--no-visual-enhancement", "Skip visual enhancement (AI image overlays)").option("--no-social-publish", "Skip social media publishing/queue-build stage").option("--late-api-key <key>", "Late API key (default: env LATE_API_KEY)").option("--late-profile-id <id>", "Late profile ID (default: env LATE_PROFILE_ID)").option("--ideas <ids>", "Comma-separated idea IDs to link to this video").option("-v, --verbose", "Verbose logging").option("--progress", "Emit structured JSON progress events to stderr").option("--doctor", "Check all prerequisites and exit").action(async (videoPath) => {
19823
+ var defaultCmd = program.command("process", { isDefault: true }).argument("[video-path]", "Path to a video file to process (implies --once)").option("--watch-dir <path>", "Folder to watch for new recordings (default: env WATCH_FOLDER)").option("--output-dir <path>", "Output directory for processed videos (default: ./recordings)").option("--openai-key <key>", "OpenAI API key (default: env OPENAI_API_KEY)").option("--exa-key <key>", "Exa AI API key for web search (default: env EXA_API_KEY)").option("--youtube-key <key>", "YouTube API key (default: env YOUTUBE_API_KEY)").option("--perplexity-key <key>", "Perplexity API key (default: env PERPLEXITY_API_KEY)").option("--once", "Process a single video and exit (no watching)").option("--brand <path>", "Path to brand.json config (default: ./brand.json)").option("--no-silence-removal", "Skip silence removal stage").option("--no-shorts", "Skip shorts generation").option("--no-medium-clips", "Skip medium clip generation").option("--no-social", "Skip social media post generation").option("--no-captions", "Skip caption generation/burning").option("--no-visual-enhancement", "Skip visual enhancement (AI image overlays)").option("--no-social-publish", "Skip social media publishing/queue-build stage").option("--late-api-key <key>", "Late API key (default: env LATE_API_KEY)").option("--late-profile-id <id>", "Late profile ID (default: env LATE_PROFILE_ID)").option("--ideas <ids>", "Comma-separated idea IDs to link to this video").option("-v, --verbose", "Verbose logging").option("--progress", "Emit structured JSON progress events to stderr").option("--doctor", "Check all prerequisites and exit").action(async (videoPath) => {
19416
19824
  const opts = defaultCmd.opts();
19417
19825
  if (opts.doctor) {
19418
19826
  await runDoctor();
@@ -19428,7 +19836,6 @@ var defaultCmd = program.command("process", { isDefault: true }).argument("[vide
19428
19836
  perplexityKey: opts.perplexityKey,
19429
19837
  brand: opts.brand,
19430
19838
  verbose: opts.verbose,
19431
- git: opts.git,
19432
19839
  silenceRemoval: opts.silenceRemoval,
19433
19840
  shorts: opts.shorts,
19434
19841
  mediumClips: opts.mediumClips,