@ccpocket/bridge 1.88.5 → 1.90.0

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.
@@ -107,6 +107,8 @@ export interface CodexModelMetadata {
107
107
  }
108
108
  export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
109
109
  private transport;
110
+ private reloadingProject;
111
+ private launchOptions;
110
112
  private _status;
111
113
  private _threadId;
112
114
  private _agentNickname;
@@ -264,6 +266,8 @@ export declare class CodexProcess extends EventEmitter<CodexProcessEvents> {
264
266
  listAvailableModelMetadata(): Promise<CodexModelMetadata[]>;
265
267
  start(projectPath: string, options?: CodexStartOptions): void;
266
268
  initializeOnly(projectPath: string, timeoutMs?: number): Promise<void>;
269
+ trustProject(projectPath: string): Promise<void>;
270
+ trustProjectAndReload(projectPath: string): Promise<void>;
267
271
  readRateLimits(timeoutMs?: number): Promise<CodexRateLimitsResponse>;
268
272
  waitUntilReady(): Promise<void>;
269
273
  stop(): void;
@@ -1,3 +1,4 @@
1
+ import { readCodexAppServerMode } from "./codex-app-server-config.js";
1
2
  import { CodexRecovery } from "./codex-recovery.js";
2
3
  import { EventEmitter } from "node:events";
3
4
  import { randomUUID } from "node:crypto";
@@ -63,6 +64,8 @@ function codexAppServerStartError(err) {
63
64
  }
64
65
  export class CodexProcess extends EventEmitter {
65
66
  transport = null;
67
+ reloadingProject = false;
68
+ launchOptions;
66
69
  _status = "starting";
67
70
  _threadId = null;
68
71
  _agentNickname = null;
@@ -140,7 +143,7 @@ export class CodexProcess extends EventEmitter {
140
143
  return this._status;
141
144
  }
142
145
  get isWaitingForInput() {
143
- return this.inputResolve !== null;
146
+ return !this.reloadingProject && this.inputResolve !== null;
144
147
  }
145
148
  getMessageModel() {
146
149
  return sanitizeCodexModel(this.startModel) ?? "";
@@ -289,7 +292,7 @@ export class CodexProcess extends EventEmitter {
289
292
  cancelRecovery() { this.manualInputVersion++; this.recovery.cancel(); }
290
293
  noteManualInput() { this.manualInputVersion++; this.recovery.manualInput(); }
291
294
  canDispatchRecovery() {
292
- return !this.stopped && this._threadId !== null && this.inputResolve !== null &&
295
+ return !this.stopped && !this.reloadingProject && this._threadId !== null && this.inputResolve !== null &&
293
296
  this.pendingTurnId === null && this.pendingTurnCompletion === null &&
294
297
  this.pendingApprovals.size === 0 && !this.hasBlockingUserInput() &&
295
298
  this.pendingPlanCompletion === null && this._pendingPlanInput === null;
@@ -620,6 +623,7 @@ export class CodexProcess extends EventEmitter {
620
623
  if (this.transport) {
621
624
  this.stop();
622
625
  }
626
+ this.launchOptions = options ? { ...options } : undefined;
623
627
  this.resetReadiness();
624
628
  this.prepareLaunch(projectPath, options);
625
629
  this.launchAppServer(projectPath, options);
@@ -642,6 +646,55 @@ export class CodexProcess extends EventEmitter {
642
646
  throw error;
643
647
  }
644
648
  }
649
+ async trustProject(projectPath) {
650
+ const response = await this.request("config/value/write", {
651
+ keyPath: `projects.${JSON.stringify(projectPath)}.trust_level`,
652
+ value: "trusted",
653
+ mergeStrategy: "replace",
654
+ });
655
+ if (response.overriddenMetadata != null)
656
+ throw new Error("Project trust is overridden by a higher-priority configuration");
657
+ }
658
+ async trustProjectAndReload(projectPath) {
659
+ if (readCodexAppServerMode() !== "private")
660
+ throw new Error("Live trust reload requires a private Codex app-server. Shared app-server sessions must be reopened after configuring project trust.");
661
+ if (!this._threadId || this.status !== "idle" || this.pendingTurnId || this.pendingApprovals.size || this.pendingUserInputs.size || this._pendingPlanInput) {
662
+ throw new Error("Wait until the Codex session is idle before trusting this project");
663
+ }
664
+ const options = {
665
+ ...this.launchOptions,
666
+ threadId: this._threadId,
667
+ model: this.model,
668
+ modelReasoningEffort: this._runtimeModelReasoningEffort,
669
+ serviceTier: this._runtimeServiceTier ?? undefined,
670
+ approvalPolicy: this._approvalPolicy,
671
+ approvalsReviewer: this._approvalsReviewer,
672
+ codexPermissionsMode: this._codexPermissionsMode,
673
+ collaborationMode: this._collaborationMode,
674
+ };
675
+ const recoveryEnabled = this.recovery.state.enabled;
676
+ this.reloadingProject = true;
677
+ this.setStatus("starting");
678
+ try {
679
+ await this.trustProject(projectPath);
680
+ await this._completionFetchInFlight;
681
+ // Only this session's transport is replaced. Late events from the old
682
+ // process must not clear the new transport or mark the session stopped.
683
+ this.transport?.removeAllListeners();
684
+ this.stop();
685
+ this.reloadingProject = false;
686
+ this.start(projectPath, options);
687
+ await this.waitUntilReady();
688
+ this.setRecoveryEnabled(recoveryEnabled);
689
+ }
690
+ catch (error) {
691
+ this.reloadingProject = false;
692
+ this.setStatus("idle");
693
+ if (this.inputResolve)
694
+ this.emit("input_ready");
695
+ throw error;
696
+ }
697
+ }
645
698
  async readRateLimits(timeoutMs = 10_000) {
646
699
  return (await this.request("account/rateLimits/read", undefined, timeoutMs));
647
700
  }