@p4code/cli 0.2.23 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.mjs CHANGED
@@ -238,7 +238,7 @@ const make$90 = () => {
238
238
  const layer$81 = Layer.sync(NetService, make$90);
239
239
  //#endregion
240
240
  //#region package.json
241
- var version = "0.2.23";
241
+ var version = "0.2.25";
242
242
  //#endregion
243
243
  //#region src/config.ts
244
244
  /**
@@ -42880,8 +42880,32 @@ const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function* (conf
42880
42880
  const homePath = config.homePath.trim();
42881
42881
  return path.resolve(homePath.length > 0 ? expandHomePath$3(homePath) : NodeOS.homedir());
42882
42882
  });
42883
+ /**
42884
+ * The macOS login keychain stores the CLI's OAuth credentials under the account
42885
+ * name in `USER`. A server started outside a login shell — a desktop app
42886
+ * launched from Finder, a launchd job — can hand the child an environment
42887
+ * without it, and the CLI then reports no subscription at all rather than
42888
+ * failing: `/usage` quietly answers with the session cost report instead of the
42889
+ * account's limits. Filling the name back in keeps the lookup working.
42890
+ */
42891
+ function withProcessUserName(env) {
42892
+ if (env.USER?.trim() && env.LOGNAME?.trim()) return env;
42893
+ const username = (() => {
42894
+ try {
42895
+ return NodeOS.userInfo().username;
42896
+ } catch {
42897
+ return "";
42898
+ }
42899
+ })();
42900
+ if (username.length === 0) return env;
42901
+ return {
42902
+ ...env,
42903
+ ...env.USER?.trim() ? {} : { USER: username },
42904
+ ...env.LOGNAME?.trim() ? {} : { LOGNAME: username }
42905
+ };
42906
+ }
42883
42907
  const makeClaudeEnvironment = Effect.fn("makeClaudeEnvironment")(function* (config, baseEnv) {
42884
- const resolvedBaseEnv = baseEnv ?? process.env;
42908
+ const resolvedBaseEnv = withProcessUserName(baseEnv ?? process.env);
42885
42909
  if (config.homePath.trim().length === 0) return resolvedBaseEnv;
42886
42910
  const resolvedHomePath = yield* resolveClaudeHomePath(config);
42887
42911
  return {
@@ -66107,7 +66131,7 @@ const makePendingClaudeProvider = (claudeSettings) => Effect.gen(function* () {
66107
66131
  */
66108
66132
  const CLAUDE_TIMEOUT_MS = 18e4;
66109
66133
  /** The usage report is a local lookup, so it should return in seconds, not minutes. */
66110
- const USAGE_REPORT_TIMEOUT_MS = 6e4;
66134
+ const USAGE_REPORT_TIMEOUT_MS$1 = 6e4;
66111
66135
  /**
66112
66136
  * Schema for the wrapper JSON returned by `claude -p --output-format json`.
66113
66137
  * We only care about `structured_output`.
@@ -66118,6 +66142,16 @@ const ClaudeOutputEnvelope = Schema$1.Struct({ structured_output: Schema$1.Unkno
66118
66142
  * CLI-local command, so this costs no turn and no tokens.
66119
66143
  */
66120
66144
  const ClaudeResultEnvelope = Schema$1.Struct({ result: Schema$1.String });
66145
+ const USAGE_LIMIT_LINE = /^.+:\s+\d+(?:\.\d+)?%\s+used/mu;
66146
+ /**
66147
+ * When the CLI cannot resolve the account behind its config directory it does
66148
+ * not fail: it prints the session's own cost summary — all zeroes for a
66149
+ * one-shot run — in place of the account's limits. Only a report that carries a
66150
+ * limit line is the report that was asked for.
66151
+ */
66152
+ function isClaudeUsageReport(report) {
66153
+ return USAGE_LIMIT_LINE.test(report);
66154
+ }
66121
66155
  const encodeJsonString$2 = Schema$1.encodeEffect(Schema$1.UnknownFromJsonString);
66122
66156
  const decodeClaudeOutputEnvelope = Schema$1.decodeEffect(Schema$1.fromJsonString(ClaudeOutputEnvelope));
66123
66157
  const decodeClaudeResultEnvelope = Schema$1.decodeEffect(Schema$1.fromJsonString(ClaudeResultEnvelope));
@@ -66305,18 +66339,23 @@ const makeClaudeTextGeneration = Effect.fn("makeClaudeTextGeneration")(function*
66305
66339
  });
66306
66340
  }
66307
66341
  return stdout;
66308
- })().pipe(Effect.scoped, Effect.timeoutOption(USAGE_REPORT_TIMEOUT_MS), Effect.flatMap(Option.match({
66342
+ })().pipe(Effect.scoped, Effect.timeoutOption(USAGE_REPORT_TIMEOUT_MS$1), Effect.flatMap(Option.match({
66309
66343
  onNone: () => Effect.fail(new TextGenerationError({
66310
66344
  operation,
66311
66345
  detail: "Claude CLI request timed out."
66312
66346
  })),
66313
66347
  onSome: (value) => Effect.succeed(value)
66314
66348
  })));
66315
- return { report: (yield* decodeClaudeResultEnvelope(rawStdout).pipe(Effect.catchTags({ SchemaError: (cause) => Effect.fail(new TextGenerationError({
66349
+ const report = (yield* decodeClaudeResultEnvelope(rawStdout).pipe(Effect.catchTags({ SchemaError: (cause) => Effect.fail(new TextGenerationError({
66316
66350
  operation,
66317
66351
  detail: "Claude CLI returned unexpected output format.",
66318
66352
  cause
66319
- })) }))).result.trim() };
66353
+ })) }))).result.trim();
66354
+ if (!isClaudeUsageReport(report)) return yield* new TextGenerationError({
66355
+ operation,
66356
+ detail: "Claude CLI answered with its session cost summary instead of the account report. That means it could not read the subscription behind its config directory - run `claude /login` for this instance's CLAUDE_CONFIG_DIR and try again."
66357
+ });
66358
+ return { report };
66320
66359
  })
66321
66360
  };
66322
66361
  });
@@ -69588,529 +69627,6 @@ const ClaudeDriver = {
69588
69627
  };
69589
69628
  })
69590
69629
  };
69591
- const resolveCodexLaunchArgs = (launchArgs, environment = process.env) => environment["P4CODE_CODEX_LAUNCH_ARGS"]?.trim() || launchArgs?.trim() || "";
69592
- const codexLaunchArgv = (launchArgs) => tokenizeCliArgs(launchArgs);
69593
- const codexAppServerArgs = (launchArgs) => ["app-server", ...codexLaunchArgv(launchArgs)];
69594
- const codexExecLaunchArgs = (launchArgs) => {
69595
- const args = codexLaunchArgv(launchArgs);
69596
- const execArgs = [];
69597
- for (let index = 0; index < args.length; index++) {
69598
- const arg = args[index];
69599
- if (arg === void 0) continue;
69600
- if (arg === "--strict-config" || arg.startsWith("--config=") || arg.startsWith("-c=")) execArgs.push(arg);
69601
- else if (arg === "--config" || arg === "-c" || arg === "--enable" || arg === "--disable") {
69602
- const value = args[index + 1];
69603
- if (value !== void 0 && !value.startsWith("-")) {
69604
- execArgs.push(arg, value);
69605
- index++;
69606
- }
69607
- } else if (arg.startsWith("--enable=") || arg.startsWith("--disable=")) execArgs.push(arg);
69608
- }
69609
- return execArgs;
69610
- };
69611
- const codexSessionAppServerArgs = (appServerArgs, launchArgs) => {
69612
- const launchAppServerArgs = codexAppServerArgs(launchArgs);
69613
- return appServerArgs ? [...launchAppServerArgs, ...appServerArgs] : launchAppServerArgs;
69614
- };
69615
- //#endregion
69616
- //#region src/codexModelOptions.ts
69617
- function getCodexServiceTierOptionValue(modelSelection) {
69618
- return getModelSelectionStringOptionValue(modelSelection, "serviceTier") ?? (getModelSelectionBooleanOptionValue(modelSelection, "fastMode") === true ? "fast" : void 0);
69619
- }
69620
- //#endregion
69621
- //#region src/textGeneration/CodexTextGeneration.ts
69622
- const CODEX_GIT_TEXT_GENERATION_REASONING_EFFORT = "low";
69623
- const CODEX_TIMEOUT_MS = 18e4;
69624
- const encodeJsonString$1 = Schema$1.encodeEffect(Schema$1.UnknownFromJsonString);
69625
- /**
69626
- * Build a Codex text-generation closure bound to a specific `CodexSettings`
69627
- * payload. See `makeCodexAdapter` for the overall per-instance rationale.
69628
- */
69629
- const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(function* (codexConfig, environment) {
69630
- const fileSystem = yield* FileSystem.FileSystem;
69631
- const path = yield* Path.Path;
69632
- const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
69633
- const serverConfig = yield* Effect.service(ServerConfig$1);
69634
- const resolvedEnvironment = environment ?? process.env;
69635
- const readStreamAsString = (operation, stream) => stream.pipe(Stream.decodeText(), Stream.runFold(() => "", (acc, chunk) => acc + chunk), Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to collect process output")));
69636
- const writeTempFile = (operation, prefix, content) => fileSystem.makeTempFileScoped({ prefix: `p4code-${prefix}-${process.pid}-` }).pipe(Effect.tap((filePath) => fileSystem.writeFileString(filePath, content)), Effect.mapError((cause) => new TextGenerationError({
69637
- operation,
69638
- detail: `Failed to write temp file`,
69639
- cause
69640
- })));
69641
- const safeUnlink = (filePath) => fileSystem.remove(filePath).pipe(Effect.catch(() => Effect.void));
69642
- const encodeJsonForOperation = (operation, value) => encodeJsonString$1(value).pipe(Effect.mapError((cause) => new TextGenerationError({
69643
- operation,
69644
- detail: "Failed to encode structured output schema.",
69645
- cause
69646
- })));
69647
- const materializeImageAttachments = Effect.fn("materializeImageAttachments")(function* (_operation, attachments) {
69648
- if (!attachments || attachments.length === 0) return { imagePaths: [] };
69649
- const imagePaths = [];
69650
- for (const attachment of attachments) {
69651
- if (attachment.type !== "image") continue;
69652
- const resolvedPath = resolveAttachmentPath({
69653
- attachmentsDir: serverConfig.attachmentsDir,
69654
- attachment
69655
- });
69656
- if (!resolvedPath || !path.isAbsolute(resolvedPath)) continue;
69657
- const fileInfo = yield* fileSystem.stat(resolvedPath).pipe(Effect.orElseSucceed(() => null));
69658
- if (!fileInfo || fileInfo.type !== "File") continue;
69659
- imagePaths.push(resolvedPath);
69660
- }
69661
- return { imagePaths };
69662
- });
69663
- const runCodexJson = Effect.fn("runCodexJson")(function* ({ operation, cwd, prompt, outputSchemaJson, imagePaths = [], cleanupPaths = [], modelSelection }) {
69664
- const schemaJson = yield* encodeJsonForOperation(operation, toJsonSchemaObject(outputSchemaJson));
69665
- const schemaPath = yield* writeTempFile(operation, "codex-schema", schemaJson);
69666
- const outputPath = yield* writeTempFile(operation, "codex-output", "");
69667
- const runCodexCommand = Effect.fn("runCodexJson.runCodexCommand")(function* () {
69668
- const launchArgs = resolveCodexLaunchArgs(codexConfig.launchArgs, resolvedEnvironment);
69669
- const reasoningEffort = getModelSelectionStringOptionValue(modelSelection, "reasoningEffort") ?? CODEX_GIT_TEXT_GENERATION_REASONING_EFFORT;
69670
- const serviceTier = getCodexServiceTierOptionValue(modelSelection);
69671
- const spawnCommand = yield* resolveSpawnCommand(codexConfig.binaryPath || "codex", [
69672
- "exec",
69673
- ...codexExecLaunchArgs(launchArgs),
69674
- "--ephemeral",
69675
- "--skip-git-repo-check",
69676
- "-s",
69677
- "read-only",
69678
- "--model",
69679
- modelSelection.model,
69680
- "--config",
69681
- `model_reasoning_effort="${reasoningEffort}"`,
69682
- ...serviceTier ? ["--config", `service_tier="${serviceTier}"`] : [],
69683
- "--output-schema",
69684
- schemaPath,
69685
- "--output-last-message",
69686
- outputPath,
69687
- ...imagePaths.flatMap((imagePath) => ["--image", imagePath]),
69688
- "-"
69689
- ], { env: resolvedEnvironment });
69690
- const command = ChildProcess.make(spawnCommand.command, spawnCommand.args, {
69691
- env: {
69692
- ...resolvedEnvironment,
69693
- ...codexConfig.homePath ? { CODEX_HOME: expandHomePath$3(codexConfig.homePath) } : {}
69694
- },
69695
- cwd,
69696
- shell: spawnCommand.shell,
69697
- stdin: { stream: Stream.encodeText(Stream.make(prompt)) }
69698
- });
69699
- const child = yield* commandSpawner.spawn(command).pipe(Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to spawn Codex CLI process")));
69700
- const [stdout, stderr, exitCode] = yield* Effect.all([
69701
- readStreamAsString(operation, child.stdout),
69702
- readStreamAsString(operation, child.stderr),
69703
- child.exitCode.pipe(Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to read Codex CLI exit code")))
69704
- ], { concurrency: "unbounded" });
69705
- if (exitCode !== 0) {
69706
- const stderrDetail = stderr.trim();
69707
- const stdoutDetail = stdout.trim();
69708
- const detail = stderrDetail.length > 0 ? stderrDetail : stdoutDetail;
69709
- return yield* new TextGenerationError({
69710
- operation,
69711
- detail: detail.length > 0 ? `Codex CLI command failed: ${detail}` : `Codex CLI command failed with code ${exitCode}.`
69712
- });
69713
- }
69714
- });
69715
- const cleanup = Effect.all([
69716
- schemaPath,
69717
- outputPath,
69718
- ...cleanupPaths
69719
- ].map((filePath) => safeUnlink(filePath)), { concurrency: "unbounded" }).pipe(Effect.asVoid);
69720
- return yield* Effect.gen(function* () {
69721
- yield* runCodexCommand().pipe(Effect.scoped, Effect.timeoutOption(CODEX_TIMEOUT_MS), Effect.flatMap(Option.match({
69722
- onNone: () => Effect.fail(new TextGenerationError({
69723
- operation,
69724
- detail: "Codex CLI request timed out."
69725
- })),
69726
- onSome: () => Effect.void
69727
- })));
69728
- const decodeOutput = Schema$1.decodeEffect(Schema$1.fromJsonString(outputSchemaJson));
69729
- return yield* fileSystem.readFileString(outputPath).pipe(Effect.mapError((cause) => new TextGenerationError({
69730
- operation,
69731
- detail: "Failed to read Codex output file.",
69732
- cause
69733
- })), Effect.flatMap(decodeOutput), Effect.catchTags({ SchemaError: (cause) => Effect.fail(new TextGenerationError({
69734
- operation,
69735
- detail: "Codex returned invalid structured output.",
69736
- cause
69737
- })) }));
69738
- }).pipe(Effect.ensuring(cleanup));
69739
- });
69740
- return {
69741
- generateCommitMessage: Effect.fn("CodexTextGeneration.generateCommitMessage")(function* (input) {
69742
- const { prompt, outputSchema } = buildCommitMessagePrompt({
69743
- branch: input.branch,
69744
- stagedSummary: input.stagedSummary,
69745
- stagedPatch: input.stagedPatch,
69746
- includeBranch: input.includeBranch === true,
69747
- policy: input.policy
69748
- });
69749
- const generated = yield* runCodexJson({
69750
- operation: "generateCommitMessage",
69751
- cwd: input.cwd,
69752
- prompt,
69753
- outputSchemaJson: outputSchema,
69754
- modelSelection: input.modelSelection
69755
- });
69756
- return {
69757
- subject: sanitizeCommitSubject(generated.subject),
69758
- body: generated.body.trim(),
69759
- ..."branch" in generated && typeof generated.branch === "string" ? { branch: sanitizeFeatureBranchName(generated.branch) } : {}
69760
- };
69761
- }),
69762
- generatePrContent: Effect.fn("CodexTextGeneration.generatePrContent")(function* (input) {
69763
- const { prompt, outputSchema } = buildPrContentPrompt({
69764
- baseBranch: input.baseBranch,
69765
- headBranch: input.headBranch,
69766
- commitSummary: input.commitSummary,
69767
- diffSummary: input.diffSummary,
69768
- diffPatch: input.diffPatch,
69769
- policy: input.policy,
69770
- changeRequestTemplate: input.changeRequestTemplate
69771
- });
69772
- const generated = yield* runCodexJson({
69773
- operation: "generatePrContent",
69774
- cwd: input.cwd,
69775
- prompt,
69776
- outputSchemaJson: outputSchema,
69777
- modelSelection: input.modelSelection
69778
- });
69779
- return {
69780
- title: sanitizePrTitle(generated.title),
69781
- body: generated.body.trim()
69782
- };
69783
- }),
69784
- generateBranchName: Effect.fn("CodexTextGeneration.generateBranchName")(function* (input) {
69785
- const { imagePaths } = yield* materializeImageAttachments("generateBranchName", input.attachments);
69786
- const { prompt, outputSchema } = buildBranchNamePrompt({
69787
- message: input.message,
69788
- attachments: input.attachments
69789
- });
69790
- return { branch: sanitizeBranchFragment((yield* runCodexJson({
69791
- operation: "generateBranchName",
69792
- cwd: input.cwd,
69793
- prompt,
69794
- outputSchemaJson: outputSchema,
69795
- imagePaths,
69796
- modelSelection: input.modelSelection
69797
- })).branch) };
69798
- }),
69799
- generateThreadTitle: Effect.fn("CodexTextGeneration.generateThreadTitle")(function* (input) {
69800
- const { imagePaths } = yield* materializeImageAttachments("generateThreadTitle", input.attachments);
69801
- const { prompt, outputSchema } = buildThreadTitlePrompt({
69802
- message: input.message,
69803
- attachments: input.attachments
69804
- });
69805
- return { title: sanitizeThreadTitle((yield* runCodexJson({
69806
- operation: "generateThreadTitle",
69807
- cwd: input.cwd,
69808
- prompt,
69809
- outputSchemaJson: outputSchema,
69810
- imagePaths,
69811
- modelSelection: input.modelSelection
69812
- })).title) };
69813
- })
69814
- };
69815
- });
69816
- //#endregion
69817
- //#region ../../packages/effect-codex-app-server/src/errors.ts
69818
- const CodexAppServerRequestOperation = Schema$1.Literals([
69819
- "decode-payload",
69820
- "encode-payload",
69821
- "handle-request",
69822
- "receive-response"
69823
- ]);
69824
- const CodexAppServerSchemaIssueKind = Schema$1.Literals([
69825
- "Filter",
69826
- "Encoding",
69827
- "Pointer",
69828
- "Composite",
69829
- "AnyOf",
69830
- "InvalidType",
69831
- "InvalidValue",
69832
- "MissingKey",
69833
- "UnexpectedKey",
69834
- "Forbidden",
69835
- "OneOf"
69836
- ]);
69837
- const schemaIssueDiagnostics$1 = (root) => {
69838
- let issueCount = 0;
69839
- let maximumPathDepth = 0;
69840
- const issueKinds = /* @__PURE__ */ new Set();
69841
- const visit = (issue, pathDepth) => {
69842
- issueCount += 1;
69843
- issueKinds.add(issue._tag);
69844
- maximumPathDepth = Math.max(maximumPathDepth, pathDepth);
69845
- switch (issue._tag) {
69846
- case "Filter":
69847
- case "Encoding":
69848
- visit(issue.issue, pathDepth);
69849
- break;
69850
- case "Pointer":
69851
- visit(issue.issue, pathDepth + issue.path.length);
69852
- break;
69853
- case "Composite":
69854
- case "AnyOf":
69855
- for (const child of issue.issues) visit(child, pathDepth);
69856
- break;
69857
- }
69858
- };
69859
- visit(root, 0);
69860
- return {
69861
- issueCount,
69862
- issueKinds: [...issueKinds],
69863
- maximumPathDepth
69864
- };
69865
- };
69866
- const CodexAppServerPayloadKind = Schema$1.Literals([
69867
- "null",
69868
- "array",
69869
- "string",
69870
- "number",
69871
- "boolean",
69872
- "bigint",
69873
- "object",
69874
- "symbol",
69875
- "function",
69876
- "undefined"
69877
- ]);
69878
- const payloadKind = (payload) => {
69879
- if (payload === null) return "null";
69880
- if (Array.isArray(payload)) return "array";
69881
- return typeof payload;
69882
- };
69883
- const protocolMessageFields = [
69884
- "id",
69885
- "method",
69886
- "params",
69887
- "result",
69888
- "error"
69889
- ];
69890
- const CodexAppServerProtocolMessageField = Schema$1.Literals(protocolMessageFields);
69891
- const CodexAppServerProtocolParseOperation = Schema$1.Literals([
69892
- "encode-wire-message",
69893
- "decode-wire-message",
69894
- "route-wire-message",
69895
- "decode-notification-payload",
69896
- "decode-request-payload",
69897
- "decode-response-payload"
69898
- ]);
69899
- const CodexAppServerTransportOperation = Schema$1.Literals(["read-input-stream", "read-process-exit-status"]);
69900
- const CodexAppServerIdentifierPurpose = Schema$1.Literals([
69901
- "provider-event",
69902
- "command-approval-request",
69903
- "file-change-approval-request",
69904
- "user-input-request"
69905
- ]);
69906
- var CodexAppServerSpawnError = class extends Schema$1.TaggedErrorClass()("CodexAppServerSpawnError", {
69907
- command: Schema$1.optional(Schema$1.String),
69908
- cause: Schema$1.Defect()
69909
- }) {
69910
- get message() {
69911
- return this.command ? `Failed to spawn Codex App Server process for command: ${this.command}` : "Failed to spawn Codex App Server process";
69912
- }
69913
- };
69914
- var CodexAppServerProcessExitedError = class extends Schema$1.TaggedErrorClass()("CodexAppServerProcessExitedError", {
69915
- code: Schema$1.optional(Schema$1.Number),
69916
- pid: Schema$1.optionalKey(Schema$1.Int),
69917
- cause: Schema$1.optional(Schema$1.Defect())
69918
- }) {
69919
- get message() {
69920
- return this.code === void 0 ? "Codex App Server process exited" : `Codex App Server process exited with code ${this.code}`;
69921
- }
69922
- };
69923
- var CodexAppServerProtocolParseError = class CodexAppServerProtocolParseError extends Schema$1.TaggedErrorClass()("CodexAppServerProtocolParseError", {
69924
- operation: CodexAppServerProtocolParseOperation,
69925
- method: Schema$1.optionalKey(Schema$1.String),
69926
- requestId: Schema$1.optionalKey(Schema$1.String),
69927
- payloadKind: Schema$1.optionalKey(CodexAppServerPayloadKind),
69928
- presentFields: Schema$1.optionalKey(Schema$1.Array(CodexAppServerProtocolMessageField)),
69929
- issueCount: Schema$1.optionalKey(Schema$1.Number),
69930
- issueKinds: Schema$1.optionalKey(Schema$1.Array(CodexAppServerSchemaIssueKind)),
69931
- maximumPathDepth: Schema$1.optionalKey(Schema$1.Number),
69932
- cause: Schema$1.optional(Schema$1.Defect())
69933
- }) {
69934
- get message() {
69935
- const method = this.method === void 0 ? "" : ` for method '${this.method}'`;
69936
- return `Codex App Server protocol operation '${this.operation}' failed${method}.`;
69937
- }
69938
- static fromSchemaError(operation, cause, context = {}) {
69939
- return new CodexAppServerProtocolParseError({
69940
- operation,
69941
- ...context,
69942
- ...schemaIssueDiagnostics$1(cause.issue),
69943
- cause
69944
- });
69945
- }
69946
- static fromRequestError(operation, method, cause) {
69947
- return new CodexAppServerProtocolParseError({
69948
- operation,
69949
- method,
69950
- ...cause.issueCount === void 0 ? {} : { issueCount: cause.issueCount },
69951
- ...cause.issueKinds === void 0 ? {} : { issueKinds: cause.issueKinds },
69952
- ...cause.maximumPathDepth === void 0 ? {} : { maximumPathDepth: cause.maximumPathDepth },
69953
- cause
69954
- });
69955
- }
69956
- static fromUnroutableMessage(message) {
69957
- const diagnostics = { payloadKind: payloadKind(message) };
69958
- if (typeof message !== "object" || message === null || Array.isArray(message)) return new CodexAppServerProtocolParseError({
69959
- operation: "route-wire-message",
69960
- ...diagnostics
69961
- });
69962
- const presentFields = protocolMessageFields.filter((field) => field in message);
69963
- const method = "method" in message && typeof message.method === "string" ? message.method : void 0;
69964
- const requestId = "id" in message && (typeof message.id === "string" || typeof message.id === "number") ? String(message.id) : void 0;
69965
- return new CodexAppServerProtocolParseError({
69966
- operation: "route-wire-message",
69967
- ...diagnostics,
69968
- presentFields,
69969
- ...method === void 0 ? {} : { method },
69970
- ...requestId === void 0 ? {} : { requestId }
69971
- });
69972
- }
69973
- };
69974
- var CodexAppServerTransportError = class extends Schema$1.TaggedErrorClass()("CodexAppServerTransportError", {
69975
- operation: CodexAppServerTransportOperation,
69976
- pid: Schema$1.optionalKey(Schema$1.Int),
69977
- cause: Schema$1.Defect()
69978
- }) {
69979
- get message() {
69980
- return `Codex App Server transport operation '${this.operation}' failed.`;
69981
- }
69982
- };
69983
- var CodexAppServerIdentifierGenerationError = class extends Schema$1.TaggedErrorClass()("CodexAppServerIdentifierGenerationError", {
69984
- purpose: CodexAppServerIdentifierPurpose,
69985
- cause: Schema$1.Defect()
69986
- }) {
69987
- get message() {
69988
- return `Failed to generate Codex App Server identifier for ${this.purpose}.`;
69989
- }
69990
- };
69991
- var CodexAppServerInputStreamEndedError = class extends Schema$1.TaggedErrorClass()("CodexAppServerInputStreamEndedError", {}) {
69992
- get message() {
69993
- return "Codex App Server input stream ended.";
69994
- }
69995
- };
69996
- var CodexAppServerRequestError = class CodexAppServerRequestError extends Schema$1.TaggedErrorClass()("CodexAppServerRequestError", {
69997
- code: Schema$1.Number,
69998
- errorMessage: Schema$1.String,
69999
- data: Schema$1.optional(Schema$1.Unknown),
70000
- method: Schema$1.optionalKey(Schema$1.String),
70001
- requestId: Schema$1.optionalKey(Schema$1.String),
70002
- operation: Schema$1.optionalKey(CodexAppServerRequestOperation),
70003
- issueCount: Schema$1.optionalKey(Schema$1.Number),
70004
- issueKinds: Schema$1.optionalKey(Schema$1.Array(CodexAppServerSchemaIssueKind)),
70005
- maximumPathDepth: Schema$1.optionalKey(Schema$1.Number),
70006
- payloadKind: Schema$1.optionalKey(CodexAppServerPayloadKind),
70007
- cause: Schema$1.optionalKey(Schema$1.Defect())
70008
- }) {
70009
- get message() {
70010
- return this.errorMessage;
70011
- }
70012
- static fromProtocolError(error, method, requestId) {
70013
- return new CodexAppServerRequestError({
70014
- code: error.code,
70015
- errorMessage: error.message,
70016
- ...error.data !== void 0 ? { data: error.data } : {},
70017
- method,
70018
- requestId,
70019
- operation: "receive-response",
70020
- cause: error
70021
- });
70022
- }
70023
- static fromAppServerError(error, method) {
70024
- if (error._tag === "CodexAppServerRequestError") return error;
70025
- return CodexAppServerRequestError.internalError(`Codex App Server request handler failed for method '${method}'`, void 0, {
70026
- method,
70027
- operation: "handle-request",
70028
- cause: error
70029
- });
70030
- }
70031
- static parseError(message = "Parse error", data) {
70032
- return new CodexAppServerRequestError({
70033
- code: -32700,
70034
- errorMessage: message,
70035
- ...data !== void 0 ? { data } : {}
70036
- });
70037
- }
70038
- static invalidRequest(message = "Invalid request", data) {
70039
- return new CodexAppServerRequestError({
70040
- code: -32600,
70041
- errorMessage: message,
70042
- ...data !== void 0 ? { data } : {}
70043
- });
70044
- }
70045
- static methodNotFound(method) {
70046
- return new CodexAppServerRequestError({
70047
- code: -32601,
70048
- errorMessage: `Method not found: ${method}`
70049
- });
70050
- }
70051
- static invalidParams(message = "Invalid params", data, diagnostics = {}) {
70052
- return new CodexAppServerRequestError({
70053
- code: -32602,
70054
- errorMessage: message,
70055
- ...data !== void 0 ? { data } : {},
70056
- ...diagnostics
70057
- });
70058
- }
70059
- static invalidPayload(method, operation, cause) {
70060
- const diagnostics = schemaIssueDiagnostics$1(cause.issue);
70061
- return new CodexAppServerRequestError({
70062
- code: -32602,
70063
- errorMessage: `Invalid payload for method '${method}' during '${operation}'`,
70064
- data: diagnostics,
70065
- method,
70066
- operation,
70067
- ...diagnostics,
70068
- cause
70069
- });
70070
- }
70071
- static unexpectedPayload(method, operation, payload) {
70072
- const diagnostics = { payloadKind: payloadKind(payload) };
70073
- return new CodexAppServerRequestError({
70074
- code: -32602,
70075
- errorMessage: `Method '${method}' does not accept a payload during '${operation}'`,
70076
- data: diagnostics,
70077
- method,
70078
- operation,
70079
- ...diagnostics
70080
- });
70081
- }
70082
- static internalError(message = "Internal error", data, diagnostics = {}) {
70083
- return new CodexAppServerRequestError({
70084
- code: -32603,
70085
- errorMessage: message,
70086
- ...data !== void 0 ? { data } : {},
70087
- ...diagnostics
70088
- });
70089
- }
70090
- static overloaded(message = "Server overloaded; retry later.", data) {
70091
- return new CodexAppServerRequestError({
70092
- code: -32001,
70093
- errorMessage: message,
70094
- ...data !== void 0 ? { data } : {}
70095
- });
70096
- }
70097
- toProtocolError() {
70098
- return {
70099
- code: this.code,
70100
- message: this.errorMessage,
70101
- ...this.data !== void 0 ? { data: this.data } : {}
70102
- };
70103
- }
70104
- };
70105
- const CodexAppServerError = Schema$1.Union([
70106
- CodexAppServerRequestError,
70107
- CodexAppServerSpawnError,
70108
- CodexAppServerProcessExitedError,
70109
- CodexAppServerProtocolParseError,
70110
- CodexAppServerTransportError,
70111
- CodexAppServerIdentifierGenerationError,
70112
- CodexAppServerInputStreamEndedError
70113
- ]);
70114
69630
  //#endregion
70115
69631
  //#region ../../packages/effect-codex-app-server/src/_generated/schema.gen.ts
70116
69632
  const ApplyPatchApprovalParams__FileChange = Schema$1.Union([
@@ -87573,80 +87089,303 @@ const SERVER_NOTIFICATION_PARAMS = {
87573
87089
  "account/login/completed": V2AccountLoginCompletedNotification
87574
87090
  };
87575
87091
  //#endregion
87576
- //#region src/provider/Layers/codexMcpArgs.ts
87577
- /** Codex's own name for the token variable of p4code's built-in server. */
87578
- const CODEX_P4CODE_BEARER_TOKEN_ENV_VAR = "P4_MCP_BEARER_TOKEN";
87579
- /** Prefix for the per-server variables the registered servers get. */
87580
- const BEARER_TOKEN_ENV_VAR_PREFIX = "P4_MCP_BEARER_TOKEN_";
87581
- /** TOML bare keys; anything else has to be quoted inside the dotted path. */
87582
- const BARE_KEY = /^[A-Za-z0-9_-]+$/;
87583
- const AUTHORIZATION_HEADER = "authorization";
87584
- const BEARER_PREFIX = /^Bearer\s+/;
87585
- const configKey = (name, field) => `mcp_servers.${BARE_KEY.test(name) ? name : JSON.stringify(name)}.${field}`;
87586
- /**
87587
- * A variable name derived from the server's, uniquely.
87588
- *
87589
- * Uppercased with every character a shell would not accept replaced, which can
87590
- * collide (`a.b` and `a-b`), so the sanitized name is the prefix and the index
87591
- * keeps it unique. The index is stable within one call, which is all that is
87592
- * needed: the variable and the reference to it are emitted together.
87593
- */
87594
- const bearerTokenEnvVar = (name, index) => `${BEARER_TOKEN_ENV_VAR_PREFIX}${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_${index}`;
87595
- /**
87596
- * @param resolved - Servers keyed by name, as the registry resolved them.
87597
- * @param exclude - Names p4code declares itself. A registration cannot displace
87598
- * the built-in `p4-code` server, whose per-thread credential is the only
87599
- * thing that makes `task_current` and the thread tools work.
87600
- */
87601
- const toCodexMcpConfig = (resolved, exclude = /* @__PURE__ */ new Set()) => {
87602
- const args = [];
87603
- const env = {};
87604
- const skipped = [];
87605
- const push = (name, field, value) => {
87606
- args.push("-c", `${configKey(name, field)}=${value}`);
87607
- };
87608
- let index = 0;
87609
- for (const [name, server] of Object.entries(resolved)) {
87610
- if (exclude.has(name)) continue;
87611
- if (server.type === "stdio") {
87612
- push(name, "command", JSON.stringify(server.command));
87613
- push(name, "args", JSON.stringify(server.args));
87614
- if (Object.keys(server.env).length > 0) push(name, "env", `{ ${Object.entries(server.env).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }`);
87615
- index += 1;
87616
- continue;
87617
- }
87618
- if (server.type === "sse") {
87619
- skipped.push({
87620
- name,
87621
- reason: "Codex speaks streamable HTTP, not SSE."
87622
- });
87623
- continue;
87624
- }
87625
- const headerNames = Object.keys(server.headers);
87626
- const authorization = headerNames.find((key) => key.toLowerCase() === AUTHORIZATION_HEADER);
87627
- const otherHeaders = headerNames.filter((key) => key !== authorization);
87628
- if (otherHeaders.length > 0) {
87629
- skipped.push({
87630
- name,
87631
- reason: `Codex sends no custom headers, and this server needs ${otherHeaders.join(", ")}.`
87632
- });
87633
- continue;
87634
- }
87635
- push(name, "url", JSON.stringify(server.url));
87636
- if (authorization !== void 0) {
87637
- const token = server.headers[authorization]?.replace(BEARER_PREFIX, "") ?? "";
87638
- const variable = bearerTokenEnvVar(name, index);
87639
- env[variable] = token;
87640
- push(name, "bearer_token_env_var", JSON.stringify(variable));
87092
+ //#region ../../packages/effect-codex-app-server/src/errors.ts
87093
+ const CodexAppServerRequestOperation = Schema$1.Literals([
87094
+ "decode-payload",
87095
+ "encode-payload",
87096
+ "handle-request",
87097
+ "receive-response"
87098
+ ]);
87099
+ const CodexAppServerSchemaIssueKind = Schema$1.Literals([
87100
+ "Filter",
87101
+ "Encoding",
87102
+ "Pointer",
87103
+ "Composite",
87104
+ "AnyOf",
87105
+ "InvalidType",
87106
+ "InvalidValue",
87107
+ "MissingKey",
87108
+ "UnexpectedKey",
87109
+ "Forbidden",
87110
+ "OneOf"
87111
+ ]);
87112
+ const schemaIssueDiagnostics$1 = (root) => {
87113
+ let issueCount = 0;
87114
+ let maximumPathDepth = 0;
87115
+ const issueKinds = /* @__PURE__ */ new Set();
87116
+ const visit = (issue, pathDepth) => {
87117
+ issueCount += 1;
87118
+ issueKinds.add(issue._tag);
87119
+ maximumPathDepth = Math.max(maximumPathDepth, pathDepth);
87120
+ switch (issue._tag) {
87121
+ case "Filter":
87122
+ case "Encoding":
87123
+ visit(issue.issue, pathDepth);
87124
+ break;
87125
+ case "Pointer":
87126
+ visit(issue.issue, pathDepth + issue.path.length);
87127
+ break;
87128
+ case "Composite":
87129
+ case "AnyOf":
87130
+ for (const child of issue.issues) visit(child, pathDepth);
87131
+ break;
87641
87132
  }
87642
- index += 1;
87643
- }
87133
+ };
87134
+ visit(root, 0);
87644
87135
  return {
87645
- args,
87646
- env,
87647
- skipped
87136
+ issueCount,
87137
+ issueKinds: [...issueKinds],
87138
+ maximumPathDepth
87648
87139
  };
87649
87140
  };
87141
+ const CodexAppServerPayloadKind = Schema$1.Literals([
87142
+ "null",
87143
+ "array",
87144
+ "string",
87145
+ "number",
87146
+ "boolean",
87147
+ "bigint",
87148
+ "object",
87149
+ "symbol",
87150
+ "function",
87151
+ "undefined"
87152
+ ]);
87153
+ const payloadKind = (payload) => {
87154
+ if (payload === null) return "null";
87155
+ if (Array.isArray(payload)) return "array";
87156
+ return typeof payload;
87157
+ };
87158
+ const protocolMessageFields = [
87159
+ "id",
87160
+ "method",
87161
+ "params",
87162
+ "result",
87163
+ "error"
87164
+ ];
87165
+ const CodexAppServerProtocolMessageField = Schema$1.Literals(protocolMessageFields);
87166
+ const CodexAppServerProtocolParseOperation = Schema$1.Literals([
87167
+ "encode-wire-message",
87168
+ "decode-wire-message",
87169
+ "route-wire-message",
87170
+ "decode-notification-payload",
87171
+ "decode-request-payload",
87172
+ "decode-response-payload"
87173
+ ]);
87174
+ const CodexAppServerTransportOperation = Schema$1.Literals(["read-input-stream", "read-process-exit-status"]);
87175
+ const CodexAppServerIdentifierPurpose = Schema$1.Literals([
87176
+ "provider-event",
87177
+ "command-approval-request",
87178
+ "file-change-approval-request",
87179
+ "user-input-request"
87180
+ ]);
87181
+ var CodexAppServerSpawnError = class extends Schema$1.TaggedErrorClass()("CodexAppServerSpawnError", {
87182
+ command: Schema$1.optional(Schema$1.String),
87183
+ cause: Schema$1.Defect()
87184
+ }) {
87185
+ get message() {
87186
+ return this.command ? `Failed to spawn Codex App Server process for command: ${this.command}` : "Failed to spawn Codex App Server process";
87187
+ }
87188
+ };
87189
+ var CodexAppServerProcessExitedError = class extends Schema$1.TaggedErrorClass()("CodexAppServerProcessExitedError", {
87190
+ code: Schema$1.optional(Schema$1.Number),
87191
+ pid: Schema$1.optionalKey(Schema$1.Int),
87192
+ cause: Schema$1.optional(Schema$1.Defect())
87193
+ }) {
87194
+ get message() {
87195
+ return this.code === void 0 ? "Codex App Server process exited" : `Codex App Server process exited with code ${this.code}`;
87196
+ }
87197
+ };
87198
+ var CodexAppServerProtocolParseError = class CodexAppServerProtocolParseError extends Schema$1.TaggedErrorClass()("CodexAppServerProtocolParseError", {
87199
+ operation: CodexAppServerProtocolParseOperation,
87200
+ method: Schema$1.optionalKey(Schema$1.String),
87201
+ requestId: Schema$1.optionalKey(Schema$1.String),
87202
+ payloadKind: Schema$1.optionalKey(CodexAppServerPayloadKind),
87203
+ presentFields: Schema$1.optionalKey(Schema$1.Array(CodexAppServerProtocolMessageField)),
87204
+ issueCount: Schema$1.optionalKey(Schema$1.Number),
87205
+ issueKinds: Schema$1.optionalKey(Schema$1.Array(CodexAppServerSchemaIssueKind)),
87206
+ maximumPathDepth: Schema$1.optionalKey(Schema$1.Number),
87207
+ cause: Schema$1.optional(Schema$1.Defect())
87208
+ }) {
87209
+ get message() {
87210
+ const method = this.method === void 0 ? "" : ` for method '${this.method}'`;
87211
+ return `Codex App Server protocol operation '${this.operation}' failed${method}.`;
87212
+ }
87213
+ static fromSchemaError(operation, cause, context = {}) {
87214
+ return new CodexAppServerProtocolParseError({
87215
+ operation,
87216
+ ...context,
87217
+ ...schemaIssueDiagnostics$1(cause.issue),
87218
+ cause
87219
+ });
87220
+ }
87221
+ static fromRequestError(operation, method, cause) {
87222
+ return new CodexAppServerProtocolParseError({
87223
+ operation,
87224
+ method,
87225
+ ...cause.issueCount === void 0 ? {} : { issueCount: cause.issueCount },
87226
+ ...cause.issueKinds === void 0 ? {} : { issueKinds: cause.issueKinds },
87227
+ ...cause.maximumPathDepth === void 0 ? {} : { maximumPathDepth: cause.maximumPathDepth },
87228
+ cause
87229
+ });
87230
+ }
87231
+ static fromUnroutableMessage(message) {
87232
+ const diagnostics = { payloadKind: payloadKind(message) };
87233
+ if (typeof message !== "object" || message === null || Array.isArray(message)) return new CodexAppServerProtocolParseError({
87234
+ operation: "route-wire-message",
87235
+ ...diagnostics
87236
+ });
87237
+ const presentFields = protocolMessageFields.filter((field) => field in message);
87238
+ const method = "method" in message && typeof message.method === "string" ? message.method : void 0;
87239
+ const requestId = "id" in message && (typeof message.id === "string" || typeof message.id === "number") ? String(message.id) : void 0;
87240
+ return new CodexAppServerProtocolParseError({
87241
+ operation: "route-wire-message",
87242
+ ...diagnostics,
87243
+ presentFields,
87244
+ ...method === void 0 ? {} : { method },
87245
+ ...requestId === void 0 ? {} : { requestId }
87246
+ });
87247
+ }
87248
+ };
87249
+ var CodexAppServerTransportError = class extends Schema$1.TaggedErrorClass()("CodexAppServerTransportError", {
87250
+ operation: CodexAppServerTransportOperation,
87251
+ pid: Schema$1.optionalKey(Schema$1.Int),
87252
+ cause: Schema$1.Defect()
87253
+ }) {
87254
+ get message() {
87255
+ return `Codex App Server transport operation '${this.operation}' failed.`;
87256
+ }
87257
+ };
87258
+ var CodexAppServerIdentifierGenerationError = class extends Schema$1.TaggedErrorClass()("CodexAppServerIdentifierGenerationError", {
87259
+ purpose: CodexAppServerIdentifierPurpose,
87260
+ cause: Schema$1.Defect()
87261
+ }) {
87262
+ get message() {
87263
+ return `Failed to generate Codex App Server identifier for ${this.purpose}.`;
87264
+ }
87265
+ };
87266
+ var CodexAppServerInputStreamEndedError = class extends Schema$1.TaggedErrorClass()("CodexAppServerInputStreamEndedError", {}) {
87267
+ get message() {
87268
+ return "Codex App Server input stream ended.";
87269
+ }
87270
+ };
87271
+ var CodexAppServerRequestError = class CodexAppServerRequestError extends Schema$1.TaggedErrorClass()("CodexAppServerRequestError", {
87272
+ code: Schema$1.Number,
87273
+ errorMessage: Schema$1.String,
87274
+ data: Schema$1.optional(Schema$1.Unknown),
87275
+ method: Schema$1.optionalKey(Schema$1.String),
87276
+ requestId: Schema$1.optionalKey(Schema$1.String),
87277
+ operation: Schema$1.optionalKey(CodexAppServerRequestOperation),
87278
+ issueCount: Schema$1.optionalKey(Schema$1.Number),
87279
+ issueKinds: Schema$1.optionalKey(Schema$1.Array(CodexAppServerSchemaIssueKind)),
87280
+ maximumPathDepth: Schema$1.optionalKey(Schema$1.Number),
87281
+ payloadKind: Schema$1.optionalKey(CodexAppServerPayloadKind),
87282
+ cause: Schema$1.optionalKey(Schema$1.Defect())
87283
+ }) {
87284
+ get message() {
87285
+ return this.errorMessage;
87286
+ }
87287
+ static fromProtocolError(error, method, requestId) {
87288
+ return new CodexAppServerRequestError({
87289
+ code: error.code,
87290
+ errorMessage: error.message,
87291
+ ...error.data !== void 0 ? { data: error.data } : {},
87292
+ method,
87293
+ requestId,
87294
+ operation: "receive-response",
87295
+ cause: error
87296
+ });
87297
+ }
87298
+ static fromAppServerError(error, method) {
87299
+ if (error._tag === "CodexAppServerRequestError") return error;
87300
+ return CodexAppServerRequestError.internalError(`Codex App Server request handler failed for method '${method}'`, void 0, {
87301
+ method,
87302
+ operation: "handle-request",
87303
+ cause: error
87304
+ });
87305
+ }
87306
+ static parseError(message = "Parse error", data) {
87307
+ return new CodexAppServerRequestError({
87308
+ code: -32700,
87309
+ errorMessage: message,
87310
+ ...data !== void 0 ? { data } : {}
87311
+ });
87312
+ }
87313
+ static invalidRequest(message = "Invalid request", data) {
87314
+ return new CodexAppServerRequestError({
87315
+ code: -32600,
87316
+ errorMessage: message,
87317
+ ...data !== void 0 ? { data } : {}
87318
+ });
87319
+ }
87320
+ static methodNotFound(method) {
87321
+ return new CodexAppServerRequestError({
87322
+ code: -32601,
87323
+ errorMessage: `Method not found: ${method}`
87324
+ });
87325
+ }
87326
+ static invalidParams(message = "Invalid params", data, diagnostics = {}) {
87327
+ return new CodexAppServerRequestError({
87328
+ code: -32602,
87329
+ errorMessage: message,
87330
+ ...data !== void 0 ? { data } : {},
87331
+ ...diagnostics
87332
+ });
87333
+ }
87334
+ static invalidPayload(method, operation, cause) {
87335
+ const diagnostics = schemaIssueDiagnostics$1(cause.issue);
87336
+ return new CodexAppServerRequestError({
87337
+ code: -32602,
87338
+ errorMessage: `Invalid payload for method '${method}' during '${operation}'`,
87339
+ data: diagnostics,
87340
+ method,
87341
+ operation,
87342
+ ...diagnostics,
87343
+ cause
87344
+ });
87345
+ }
87346
+ static unexpectedPayload(method, operation, payload) {
87347
+ const diagnostics = { payloadKind: payloadKind(payload) };
87348
+ return new CodexAppServerRequestError({
87349
+ code: -32602,
87350
+ errorMessage: `Method '${method}' does not accept a payload during '${operation}'`,
87351
+ data: diagnostics,
87352
+ method,
87353
+ operation,
87354
+ ...diagnostics
87355
+ });
87356
+ }
87357
+ static internalError(message = "Internal error", data, diagnostics = {}) {
87358
+ return new CodexAppServerRequestError({
87359
+ code: -32603,
87360
+ errorMessage: message,
87361
+ ...data !== void 0 ? { data } : {},
87362
+ ...diagnostics
87363
+ });
87364
+ }
87365
+ static overloaded(message = "Server overloaded; retry later.", data) {
87366
+ return new CodexAppServerRequestError({
87367
+ code: -32001,
87368
+ errorMessage: message,
87369
+ ...data !== void 0 ? { data } : {}
87370
+ });
87371
+ }
87372
+ toProtocolError() {
87373
+ return {
87374
+ code: this.code,
87375
+ message: this.errorMessage,
87376
+ ...this.data !== void 0 ? { data: this.data } : {}
87377
+ };
87378
+ }
87379
+ };
87380
+ const CodexAppServerError = Schema$1.Union([
87381
+ CodexAppServerRequestError,
87382
+ CodexAppServerSpawnError,
87383
+ CodexAppServerProcessExitedError,
87384
+ CodexAppServerProtocolParseError,
87385
+ CodexAppServerTransportError,
87386
+ CodexAppServerIdentifierGenerationError,
87387
+ CodexAppServerInputStreamEndedError
87388
+ ]);
87650
87389
  //#endregion
87651
87390
  //#region ../../packages/effect-codex-app-server/src/_internal/shared.ts
87652
87391
  const JsonRpcId$1 = Schema$1.Union([Schema$1.Number, Schema$1.String]);
@@ -87697,9 +87436,9 @@ function isIncomingNotification(value) {
87697
87436
  function isIncomingResponse(value) {
87698
87437
  return isJsonRpcResponseEnvelope(value);
87699
87438
  }
87700
- const encodeJsonString = Schema$1.encodeUnknownEffect(Schema$1.UnknownFromJsonString);
87439
+ const encodeJsonString$1 = Schema$1.encodeUnknownEffect(Schema$1.UnknownFromJsonString);
87701
87440
  const decodeJsonString = Schema$1.decodeUnknownEffect(Schema$1.UnknownFromJsonString);
87702
- const encodeWireMessage = (message) => encodeJsonString(message).pipe(Effect.map((encoded) => `${encoded}\n`), Effect.mapError((cause) => {
87441
+ const encodeWireMessage = (message) => encodeJsonString$1(message).pipe(Effect.map((encoded) => `${encoded}\n`), Effect.mapError((cause) => {
87703
87442
  const method = typeof message.method === "string" ? message.method : void 0;
87704
87443
  const requestId = typeof message.id === "string" || typeof message.id === "number" ? String(message.id) : void 0;
87705
87444
  return CodexAppServerProtocolParseError.fromSchemaError("encode-wire-message", cause, {
@@ -87955,6 +87694,30 @@ const makeChildProcessClient = Effect.fn("effect-codex-app-server/CodexAppServer
87955
87694
  yield* Stream.runDrain(handle.stderr).pipe(Effect.ignore, Effect.forkScoped);
87956
87695
  return yield* make$8(makeChildStdio$1(handle), options, makeTerminationError$1(handle));
87957
87696
  });
87697
+ const resolveCodexLaunchArgs = (launchArgs, environment = process.env) => environment["P4CODE_CODEX_LAUNCH_ARGS"]?.trim() || launchArgs?.trim() || "";
87698
+ const codexLaunchArgv = (launchArgs) => tokenizeCliArgs(launchArgs);
87699
+ const codexAppServerArgs = (launchArgs) => ["app-server", ...codexLaunchArgv(launchArgs)];
87700
+ const codexExecLaunchArgs = (launchArgs) => {
87701
+ const args = codexLaunchArgv(launchArgs);
87702
+ const execArgs = [];
87703
+ for (let index = 0; index < args.length; index++) {
87704
+ const arg = args[index];
87705
+ if (arg === void 0) continue;
87706
+ if (arg === "--strict-config" || arg.startsWith("--config=") || arg.startsWith("-c=")) execArgs.push(arg);
87707
+ else if (arg === "--config" || arg === "-c" || arg === "--enable" || arg === "--disable") {
87708
+ const value = args[index + 1];
87709
+ if (value !== void 0 && !value.startsWith("-")) {
87710
+ execArgs.push(arg, value);
87711
+ index++;
87712
+ }
87713
+ } else if (arg.startsWith("--enable=") || arg.startsWith("--disable=")) execArgs.push(arg);
87714
+ }
87715
+ return execArgs;
87716
+ };
87717
+ const codexSessionAppServerArgs = (appServerArgs, launchArgs) => {
87718
+ const launchAppServerArgs = codexAppServerArgs(launchArgs);
87719
+ return appServerArgs ? [...launchAppServerArgs, ...appServerArgs] : launchAppServerArgs;
87720
+ };
87958
87721
  //#endregion
87959
87722
  //#region src/provider/Layers/CodexProvider.ts
87960
87723
  const isCodexAppServerSpawnError = Schema$1.is(CodexAppServerSpawnError);
@@ -88322,6 +88085,507 @@ const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(function*
88322
88085
  });
88323
88086
  });
88324
88087
  //#endregion
88088
+ //#region src/provider/Layers/CodexAccountUsage.ts
88089
+ /**
88090
+ * Codex has no `/usage` command: the limits live behind the app-server's
88091
+ * `account/*` requests. A short-lived app-server is spawned for the question and
88092
+ * torn down with the scope, the same way the capability probe does it, so asking
88093
+ * about the account never touches a running session.
88094
+ *
88095
+ * @module CodexAccountUsage
88096
+ */
88097
+ const CODEX_ACCOUNT_USAGE_FORCE_KILL_AFTER = "2 seconds";
88098
+ const readCodexAccountUsage = Effect.fn("readCodexAccountUsage")(function* (input) {
88099
+ const resolvedHomePath = input.homePath ? expandHomePath$3(input.homePath) : void 0;
88100
+ const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
88101
+ const environment = {
88102
+ ...input.environment,
88103
+ ...resolvedHomePath ? { CODEX_HOME: resolvedHomePath } : {}
88104
+ };
88105
+ const spawnCommand = yield* resolveSpawnCommand(input.binaryPath, codexAppServerArgs(input.launchArgs), {
88106
+ env: environment,
88107
+ extendEnv: true
88108
+ });
88109
+ const child = yield* spawner.spawn(ChildProcess$1.make(spawnCommand.command, spawnCommand.args, {
88110
+ cwd: input.cwd,
88111
+ env: environment,
88112
+ extendEnv: true,
88113
+ forceKillAfter: CODEX_ACCOUNT_USAGE_FORCE_KILL_AFTER,
88114
+ shell: spawnCommand.shell
88115
+ })).pipe(Effect.mapError((cause) => new CodexAppServerSpawnError({
88116
+ command: `${input.binaryPath} app-server`,
88117
+ cause
88118
+ })));
88119
+ const clientContext = yield* Layer.build(layerChildProcess$1(child));
88120
+ const client = yield* Effect.service(CodexAppServerClient).pipe(Effect.provide(clientContext));
88121
+ yield* client.request("initialize", buildCodexInitializeParams());
88122
+ yield* client.notify("initialized", void 0);
88123
+ return {
88124
+ rateLimits: yield* client.request("account/rateLimits/read", void 0),
88125
+ usage: yield* client.request("account/usage/read", void 0).pipe(Effect.orElseSucceed(() => null))
88126
+ };
88127
+ });
88128
+ //#endregion
88129
+ //#region src/codexModelOptions.ts
88130
+ function getCodexServiceTierOptionValue(modelSelection) {
88131
+ return getModelSelectionStringOptionValue(modelSelection, "serviceTier") ?? (getModelSelectionBooleanOptionValue(modelSelection, "fastMode") === true ? "fast" : void 0);
88132
+ }
88133
+ //#endregion
88134
+ //#region src/textGeneration/codexUsageReport.ts
88135
+ const MINUTES_PER_HOUR = 60;
88136
+ const MINUTES_PER_DAY = 1440;
88137
+ const TOP_DAY_COUNT = 3;
88138
+ const PLAN_LABELS = {
88139
+ free: "Free",
88140
+ go: "Go",
88141
+ plus: "Plus",
88142
+ pro: "Pro",
88143
+ prolite: "Pro Lite",
88144
+ team: "Team",
88145
+ business: "Business",
88146
+ enterprise: "Enterprise",
88147
+ edu: "Edu"
88148
+ };
88149
+ function formatNumber(value) {
88150
+ return Math.round(value).toLocaleString("en-US");
88151
+ }
88152
+ /** `10080` reads as `7d`, `300` as `5h`: the window label the limit lines carry. */
88153
+ function formatWindowDuration(minutes) {
88154
+ if (minutes === void 0 || minutes === null || minutes <= 0) return null;
88155
+ if (minutes % MINUTES_PER_DAY === 0) return `${minutes / MINUTES_PER_DAY}d`;
88156
+ if (minutes % MINUTES_PER_HOUR === 0) return `${minutes / MINUTES_PER_HOUR}h`;
88157
+ return `${minutes}m`;
88158
+ }
88159
+ const MILLISECONDS_PER_SECOND = 1e3;
88160
+ function formatResetTime(resetsAt, timeZone) {
88161
+ if (resetsAt === void 0 || resetsAt === null || !Number.isFinite(resetsAt)) return null;
88162
+ const epochMs = resetsAt * MILLISECONDS_PER_SECOND;
88163
+ return `resets ${new Intl.DateTimeFormat("en-US", {
88164
+ month: "short",
88165
+ day: "numeric",
88166
+ timeZone
88167
+ }).format(epochMs)} at ${new Intl.DateTimeFormat("en-US", {
88168
+ hour: "numeric",
88169
+ minute: "2-digit",
88170
+ hour12: true,
88171
+ timeZone
88172
+ }).format(epochMs).replace(/\s/g, "").toLowerCase()} (${timeZone})`;
88173
+ }
88174
+ function limitLabel(snapshot, fallbackId) {
88175
+ const name = snapshot.limitName?.trim();
88176
+ if (name) return name;
88177
+ const id = snapshot.limitId?.trim() || fallbackId;
88178
+ return id === "codex" ? "Codex" : id;
88179
+ }
88180
+ function limitLine(label, window, timeZone) {
88181
+ if (!window) return null;
88182
+ const duration = formatWindowDuration(window.windowDurationMins);
88183
+ const resets = formatResetTime(window.resetsAt, timeZone);
88184
+ return `${duration ? `${label} (${duration})` : label}: ${window.usedPercent}% used${resets ? ` · ${resets}` : ""}`;
88185
+ }
88186
+ /**
88187
+ * Every limit Codex knows about, not just the account-wide one: model-specific
88188
+ * limits arrive under `rateLimitsByLimitId` and are the ones that actually stop
88189
+ * a turn.
88190
+ */
88191
+ function collectRateLimitSnapshots(response) {
88192
+ const activeId = response.rateLimits.limitId ?? "codex";
88193
+ const byId = response.rateLimitsByLimitId;
88194
+ if (byId && Object.keys(byId).length > 0) return Object.entries(byId).map(([id, snapshot]) => ({
88195
+ id,
88196
+ snapshot
88197
+ })).sort((left, right) => Number(right.id === activeId) - Number(left.id === activeId));
88198
+ return [{
88199
+ id: activeId,
88200
+ snapshot: response.rateLimits
88201
+ }];
88202
+ }
88203
+ function planSentence(response) {
88204
+ const planType = response.rateLimits.planType;
88205
+ if (!planType || planType === "unknown") return null;
88206
+ return `You are currently using your Codex ${PLAN_LABELS[planType] ?? planType} plan.`;
88207
+ }
88208
+ function creditsSentence(response) {
88209
+ const credits = response.rateLimits.credits;
88210
+ if (!credits) return null;
88211
+ if (credits.unlimited) return "Credits: unlimited.";
88212
+ if (!credits.hasCredits) return null;
88213
+ return credits.balance ? `Credits: ${credits.balance} available.` : "Credits available.";
88214
+ }
88215
+ function resetCreditSentence(response) {
88216
+ const available = response.rateLimitResetCredits?.availableCount ?? 0;
88217
+ if (available <= 0) return null;
88218
+ return available === 1 ? "1 rate limit reset is available on this account." : `${available} rate limit resets are available on this account.`;
88219
+ }
88220
+ const MONTH_NAMES = [
88221
+ "Jan",
88222
+ "Feb",
88223
+ "Mar",
88224
+ "Apr",
88225
+ "May",
88226
+ "Jun",
88227
+ "Jul",
88228
+ "Aug",
88229
+ "Sep",
88230
+ "Oct",
88231
+ "Nov",
88232
+ "Dec"
88233
+ ];
88234
+ /** A stat line only earns its place when the account actually reports the number. */
88235
+ function countStat(value, label) {
88236
+ if (value === void 0 || value === null || value <= 0) return null;
88237
+ return `${formatNumber(value)} ${label}`;
88238
+ }
88239
+ /** Buckets are calendar days (`2026-08-17`), read as written rather than as an instant. */
88240
+ function formatBucketDay(startDate) {
88241
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(startDate);
88242
+ const month = MONTH_NAMES[Number(match?.[2]) - 1];
88243
+ if (!match || !month) return startDate;
88244
+ return `${month} ${Number(match[3])}`;
88245
+ }
88246
+ function usageWindowLines(usage) {
88247
+ const lines = [];
88248
+ const buckets = (usage.dailyUsageBuckets ?? []).filter((bucket) => bucket.tokens > 0);
88249
+ const bucketTotal = buckets.reduce((total, bucket) => total + bucket.tokens, 0);
88250
+ if (buckets.length > 0 && bucketTotal > 0) {
88251
+ const perDay = Math.round(bucketTotal / buckets.length);
88252
+ lines.push(`Last ${buckets.length}d · ${formatNumber(bucketTotal)} tokens · ${formatNumber(perDay)} tokens per day`);
88253
+ const topDays = [...buckets].sort((left, right) => right.tokens - left.tokens).slice(0, TOP_DAY_COUNT).map((bucket) => `${formatBucketDay(bucket.startDate)} ${Math.round(bucket.tokens / bucketTotal * 100)}%`);
88254
+ if (topDays.length > 0) lines.push(` Top days: ${topDays.join(", ")}`);
88255
+ }
88256
+ const summary = usage.summary;
88257
+ const allTimeStats = [
88258
+ countStat(summary.lifetimeTokens, "tokens"),
88259
+ countStat(summary.peakDailyTokens, "peak daily tokens"),
88260
+ countStat(summary.currentStreakDays, "day streak")
88261
+ ].filter((stat) => stat !== null);
88262
+ if (allTimeStats.length > 0) lines.push(`All time · ${allTimeStats.join(" · ")}`);
88263
+ return lines;
88264
+ }
88265
+ /**
88266
+ * Render the Codex account report. `timeZone` is the server's, matching how the
88267
+ * Claude CLI stamps its own reset times.
88268
+ */
88269
+ function formatCodexUsageReport(input) {
88270
+ const { rateLimits, usage, timeZone } = input;
88271
+ const sections = [];
88272
+ const intro = [
88273
+ planSentence(rateLimits),
88274
+ creditsSentence(rateLimits),
88275
+ resetCreditSentence(rateLimits)
88276
+ ].filter((sentence) => sentence !== null).join("\n");
88277
+ if (intro.length > 0) sections.push(intro);
88278
+ const limits = collectRateLimitSnapshots(rateLimits).flatMap(({ id, snapshot }) => {
88279
+ const label = limitLabel(snapshot, id);
88280
+ return [limitLine(label, snapshot.primary, timeZone), limitLine(label, snapshot.secondary, timeZone)].filter((line) => line !== null);
88281
+ });
88282
+ if (limits.length > 0) sections.push(limits.join("\n"));
88283
+ const windows = usage ? usageWindowLines(usage) : [];
88284
+ if (windows.length > 0) {
88285
+ sections.push(["What's contributing to your limits usage?", "Token totals Codex reports for this account. Day shares are of the tokens in that window."].join("\n"));
88286
+ sections.push(windows.join("\n"));
88287
+ }
88288
+ return sections.join("\n\n");
88289
+ }
88290
+ //#endregion
88291
+ //#region src/textGeneration/CodexTextGeneration.ts
88292
+ const CODEX_GIT_TEXT_GENERATION_REASONING_EFFORT = "low";
88293
+ const CODEX_TIMEOUT_MS = 18e4;
88294
+ /** The account report is a local lookup, so it should return in seconds, not minutes. */
88295
+ const USAGE_REPORT_TIMEOUT_MS = 3e4;
88296
+ const encodeJsonString = Schema$1.encodeEffect(Schema$1.UnknownFromJsonString);
88297
+ /**
88298
+ * Build a Codex text-generation closure bound to a specific `CodexSettings`
88299
+ * payload. See `makeCodexAdapter` for the overall per-instance rationale.
88300
+ */
88301
+ const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(function* (codexConfig, environment) {
88302
+ const fileSystem = yield* FileSystem.FileSystem;
88303
+ const path = yield* Path.Path;
88304
+ const commandSpawner = yield* ChildProcessSpawner.ChildProcessSpawner;
88305
+ const serverConfig = yield* Effect.service(ServerConfig$1);
88306
+ const resolvedEnvironment = environment ?? process.env;
88307
+ const readStreamAsString = (operation, stream) => stream.pipe(Stream.decodeText(), Stream.runFold(() => "", (acc, chunk) => acc + chunk), Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to collect process output")));
88308
+ const writeTempFile = (operation, prefix, content) => fileSystem.makeTempFileScoped({ prefix: `p4code-${prefix}-${process.pid}-` }).pipe(Effect.tap((filePath) => fileSystem.writeFileString(filePath, content)), Effect.mapError((cause) => new TextGenerationError({
88309
+ operation,
88310
+ detail: `Failed to write temp file`,
88311
+ cause
88312
+ })));
88313
+ const safeUnlink = (filePath) => fileSystem.remove(filePath).pipe(Effect.catch(() => Effect.void));
88314
+ const encodeJsonForOperation = (operation, value) => encodeJsonString(value).pipe(Effect.mapError((cause) => new TextGenerationError({
88315
+ operation,
88316
+ detail: "Failed to encode structured output schema.",
88317
+ cause
88318
+ })));
88319
+ const materializeImageAttachments = Effect.fn("materializeImageAttachments")(function* (_operation, attachments) {
88320
+ if (!attachments || attachments.length === 0) return { imagePaths: [] };
88321
+ const imagePaths = [];
88322
+ for (const attachment of attachments) {
88323
+ if (attachment.type !== "image") continue;
88324
+ const resolvedPath = resolveAttachmentPath({
88325
+ attachmentsDir: serverConfig.attachmentsDir,
88326
+ attachment
88327
+ });
88328
+ if (!resolvedPath || !path.isAbsolute(resolvedPath)) continue;
88329
+ const fileInfo = yield* fileSystem.stat(resolvedPath).pipe(Effect.orElseSucceed(() => null));
88330
+ if (!fileInfo || fileInfo.type !== "File") continue;
88331
+ imagePaths.push(resolvedPath);
88332
+ }
88333
+ return { imagePaths };
88334
+ });
88335
+ const runCodexJson = Effect.fn("runCodexJson")(function* ({ operation, cwd, prompt, outputSchemaJson, imagePaths = [], cleanupPaths = [], modelSelection }) {
88336
+ const schemaJson = yield* encodeJsonForOperation(operation, toJsonSchemaObject(outputSchemaJson));
88337
+ const schemaPath = yield* writeTempFile(operation, "codex-schema", schemaJson);
88338
+ const outputPath = yield* writeTempFile(operation, "codex-output", "");
88339
+ const runCodexCommand = Effect.fn("runCodexJson.runCodexCommand")(function* () {
88340
+ const launchArgs = resolveCodexLaunchArgs(codexConfig.launchArgs, resolvedEnvironment);
88341
+ const reasoningEffort = getModelSelectionStringOptionValue(modelSelection, "reasoningEffort") ?? CODEX_GIT_TEXT_GENERATION_REASONING_EFFORT;
88342
+ const serviceTier = getCodexServiceTierOptionValue(modelSelection);
88343
+ const spawnCommand = yield* resolveSpawnCommand(codexConfig.binaryPath || "codex", [
88344
+ "exec",
88345
+ ...codexExecLaunchArgs(launchArgs),
88346
+ "--ephemeral",
88347
+ "--skip-git-repo-check",
88348
+ "-s",
88349
+ "read-only",
88350
+ "--model",
88351
+ modelSelection.model,
88352
+ "--config",
88353
+ `model_reasoning_effort="${reasoningEffort}"`,
88354
+ ...serviceTier ? ["--config", `service_tier="${serviceTier}"`] : [],
88355
+ "--output-schema",
88356
+ schemaPath,
88357
+ "--output-last-message",
88358
+ outputPath,
88359
+ ...imagePaths.flatMap((imagePath) => ["--image", imagePath]),
88360
+ "-"
88361
+ ], { env: resolvedEnvironment });
88362
+ const command = ChildProcess.make(spawnCommand.command, spawnCommand.args, {
88363
+ env: {
88364
+ ...resolvedEnvironment,
88365
+ ...codexConfig.homePath ? { CODEX_HOME: expandHomePath$3(codexConfig.homePath) } : {}
88366
+ },
88367
+ cwd,
88368
+ shell: spawnCommand.shell,
88369
+ stdin: { stream: Stream.encodeText(Stream.make(prompt)) }
88370
+ });
88371
+ const child = yield* commandSpawner.spawn(command).pipe(Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to spawn Codex CLI process")));
88372
+ const [stdout, stderr, exitCode] = yield* Effect.all([
88373
+ readStreamAsString(operation, child.stdout),
88374
+ readStreamAsString(operation, child.stderr),
88375
+ child.exitCode.pipe(Effect.mapError((cause) => normalizeCliError("codex", operation, cause, "Failed to read Codex CLI exit code")))
88376
+ ], { concurrency: "unbounded" });
88377
+ if (exitCode !== 0) {
88378
+ const stderrDetail = stderr.trim();
88379
+ const stdoutDetail = stdout.trim();
88380
+ const detail = stderrDetail.length > 0 ? stderrDetail : stdoutDetail;
88381
+ return yield* new TextGenerationError({
88382
+ operation,
88383
+ detail: detail.length > 0 ? `Codex CLI command failed: ${detail}` : `Codex CLI command failed with code ${exitCode}.`
88384
+ });
88385
+ }
88386
+ });
88387
+ const cleanup = Effect.all([
88388
+ schemaPath,
88389
+ outputPath,
88390
+ ...cleanupPaths
88391
+ ].map((filePath) => safeUnlink(filePath)), { concurrency: "unbounded" }).pipe(Effect.asVoid);
88392
+ return yield* Effect.gen(function* () {
88393
+ yield* runCodexCommand().pipe(Effect.scoped, Effect.timeoutOption(CODEX_TIMEOUT_MS), Effect.flatMap(Option.match({
88394
+ onNone: () => Effect.fail(new TextGenerationError({
88395
+ operation,
88396
+ detail: "Codex CLI request timed out."
88397
+ })),
88398
+ onSome: () => Effect.void
88399
+ })));
88400
+ const decodeOutput = Schema$1.decodeEffect(Schema$1.fromJsonString(outputSchemaJson));
88401
+ return yield* fileSystem.readFileString(outputPath).pipe(Effect.mapError((cause) => new TextGenerationError({
88402
+ operation,
88403
+ detail: "Failed to read Codex output file.",
88404
+ cause
88405
+ })), Effect.flatMap(decodeOutput), Effect.catchTags({ SchemaError: (cause) => Effect.fail(new TextGenerationError({
88406
+ operation,
88407
+ detail: "Codex returned invalid structured output.",
88408
+ cause
88409
+ })) }));
88410
+ }).pipe(Effect.ensuring(cleanup));
88411
+ });
88412
+ return {
88413
+ generateCommitMessage: Effect.fn("CodexTextGeneration.generateCommitMessage")(function* (input) {
88414
+ const { prompt, outputSchema } = buildCommitMessagePrompt({
88415
+ branch: input.branch,
88416
+ stagedSummary: input.stagedSummary,
88417
+ stagedPatch: input.stagedPatch,
88418
+ includeBranch: input.includeBranch === true,
88419
+ policy: input.policy
88420
+ });
88421
+ const generated = yield* runCodexJson({
88422
+ operation: "generateCommitMessage",
88423
+ cwd: input.cwd,
88424
+ prompt,
88425
+ outputSchemaJson: outputSchema,
88426
+ modelSelection: input.modelSelection
88427
+ });
88428
+ return {
88429
+ subject: sanitizeCommitSubject(generated.subject),
88430
+ body: generated.body.trim(),
88431
+ ..."branch" in generated && typeof generated.branch === "string" ? { branch: sanitizeFeatureBranchName(generated.branch) } : {}
88432
+ };
88433
+ }),
88434
+ generatePrContent: Effect.fn("CodexTextGeneration.generatePrContent")(function* (input) {
88435
+ const { prompt, outputSchema } = buildPrContentPrompt({
88436
+ baseBranch: input.baseBranch,
88437
+ headBranch: input.headBranch,
88438
+ commitSummary: input.commitSummary,
88439
+ diffSummary: input.diffSummary,
88440
+ diffPatch: input.diffPatch,
88441
+ policy: input.policy,
88442
+ changeRequestTemplate: input.changeRequestTemplate
88443
+ });
88444
+ const generated = yield* runCodexJson({
88445
+ operation: "generatePrContent",
88446
+ cwd: input.cwd,
88447
+ prompt,
88448
+ outputSchemaJson: outputSchema,
88449
+ modelSelection: input.modelSelection
88450
+ });
88451
+ return {
88452
+ title: sanitizePrTitle(generated.title),
88453
+ body: generated.body.trim()
88454
+ };
88455
+ }),
88456
+ generateBranchName: Effect.fn("CodexTextGeneration.generateBranchName")(function* (input) {
88457
+ const { imagePaths } = yield* materializeImageAttachments("generateBranchName", input.attachments);
88458
+ const { prompt, outputSchema } = buildBranchNamePrompt({
88459
+ message: input.message,
88460
+ attachments: input.attachments
88461
+ });
88462
+ return { branch: sanitizeBranchFragment((yield* runCodexJson({
88463
+ operation: "generateBranchName",
88464
+ cwd: input.cwd,
88465
+ prompt,
88466
+ outputSchemaJson: outputSchema,
88467
+ imagePaths,
88468
+ modelSelection: input.modelSelection
88469
+ })).branch) };
88470
+ }),
88471
+ generateThreadTitle: Effect.fn("CodexTextGeneration.generateThreadTitle")(function* (input) {
88472
+ const { imagePaths } = yield* materializeImageAttachments("generateThreadTitle", input.attachments);
88473
+ const { prompt, outputSchema } = buildThreadTitlePrompt({
88474
+ message: input.message,
88475
+ attachments: input.attachments
88476
+ });
88477
+ return { title: sanitizeThreadTitle((yield* runCodexJson({
88478
+ operation: "generateThreadTitle",
88479
+ cwd: input.cwd,
88480
+ prompt,
88481
+ outputSchemaJson: outputSchema,
88482
+ imagePaths,
88483
+ modelSelection: input.modelSelection
88484
+ })).title) };
88485
+ }),
88486
+ getUsageReport: Effect.fn("CodexTextGeneration.getUsageReport")(function* () {
88487
+ const operation = "getUsageReport";
88488
+ const snapshot = yield* readCodexAccountUsage({
88489
+ binaryPath: codexConfig.binaryPath || "codex",
88490
+ ...codexConfig.homePath ? { homePath: codexConfig.homePath } : {},
88491
+ launchArgs: resolveCodexLaunchArgs(codexConfig.launchArgs, resolvedEnvironment),
88492
+ cwd: serverConfig.cwd,
88493
+ environment: resolvedEnvironment
88494
+ }).pipe(Effect.mapError((cause) => new TextGenerationError({
88495
+ operation,
88496
+ detail: "Codex CLI could not read this account's usage.",
88497
+ cause
88498
+ })), Effect.scoped, Effect.timeoutOption(USAGE_REPORT_TIMEOUT_MS), Effect.flatMap(Option.match({
88499
+ onNone: () => Effect.fail(new TextGenerationError({
88500
+ operation,
88501
+ detail: "Codex CLI request timed out."
88502
+ })),
88503
+ onSome: (value) => Effect.succeed(value)
88504
+ })), Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, commandSpawner));
88505
+ return { report: formatCodexUsageReport({
88506
+ rateLimits: snapshot.rateLimits,
88507
+ usage: snapshot.usage,
88508
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
88509
+ }) };
88510
+ })
88511
+ };
88512
+ });
88513
+ //#endregion
88514
+ //#region src/provider/Layers/codexMcpArgs.ts
88515
+ /** Codex's own name for the token variable of p4code's built-in server. */
88516
+ const CODEX_P4CODE_BEARER_TOKEN_ENV_VAR = "P4_MCP_BEARER_TOKEN";
88517
+ /** Prefix for the per-server variables the registered servers get. */
88518
+ const BEARER_TOKEN_ENV_VAR_PREFIX = "P4_MCP_BEARER_TOKEN_";
88519
+ /** TOML bare keys; anything else has to be quoted inside the dotted path. */
88520
+ const BARE_KEY = /^[A-Za-z0-9_-]+$/;
88521
+ const AUTHORIZATION_HEADER = "authorization";
88522
+ const BEARER_PREFIX = /^Bearer\s+/;
88523
+ const configKey = (name, field) => `mcp_servers.${BARE_KEY.test(name) ? name : JSON.stringify(name)}.${field}`;
88524
+ /**
88525
+ * A variable name derived from the server's, uniquely.
88526
+ *
88527
+ * Uppercased with every character a shell would not accept replaced, which can
88528
+ * collide (`a.b` and `a-b`), so the sanitized name is the prefix and the index
88529
+ * keeps it unique. The index is stable within one call, which is all that is
88530
+ * needed: the variable and the reference to it are emitted together.
88531
+ */
88532
+ const bearerTokenEnvVar = (name, index) => `${BEARER_TOKEN_ENV_VAR_PREFIX}${name.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_${index}`;
88533
+ /**
88534
+ * @param resolved - Servers keyed by name, as the registry resolved them.
88535
+ * @param exclude - Names p4code declares itself. A registration cannot displace
88536
+ * the built-in `p4-code` server, whose per-thread credential is the only
88537
+ * thing that makes `task_current` and the thread tools work.
88538
+ */
88539
+ const toCodexMcpConfig = (resolved, exclude = /* @__PURE__ */ new Set()) => {
88540
+ const args = [];
88541
+ const env = {};
88542
+ const skipped = [];
88543
+ const push = (name, field, value) => {
88544
+ args.push("-c", `${configKey(name, field)}=${value}`);
88545
+ };
88546
+ let index = 0;
88547
+ for (const [name, server] of Object.entries(resolved)) {
88548
+ if (exclude.has(name)) continue;
88549
+ if (server.type === "stdio") {
88550
+ push(name, "command", JSON.stringify(server.command));
88551
+ push(name, "args", JSON.stringify(server.args));
88552
+ if (Object.keys(server.env).length > 0) push(name, "env", `{ ${Object.entries(server.env).map(([key, value]) => `${JSON.stringify(key)} = ${JSON.stringify(value)}`).join(", ")} }`);
88553
+ index += 1;
88554
+ continue;
88555
+ }
88556
+ if (server.type === "sse") {
88557
+ skipped.push({
88558
+ name,
88559
+ reason: "Codex speaks streamable HTTP, not SSE."
88560
+ });
88561
+ continue;
88562
+ }
88563
+ const headerNames = Object.keys(server.headers);
88564
+ const authorization = headerNames.find((key) => key.toLowerCase() === AUTHORIZATION_HEADER);
88565
+ const otherHeaders = headerNames.filter((key) => key !== authorization);
88566
+ if (otherHeaders.length > 0) {
88567
+ skipped.push({
88568
+ name,
88569
+ reason: `Codex sends no custom headers, and this server needs ${otherHeaders.join(", ")}.`
88570
+ });
88571
+ continue;
88572
+ }
88573
+ push(name, "url", JSON.stringify(server.url));
88574
+ if (authorization !== void 0) {
88575
+ const token = server.headers[authorization]?.replace(BEARER_PREFIX, "") ?? "";
88576
+ const variable = bearerTokenEnvVar(name, index);
88577
+ env[variable] = token;
88578
+ push(name, "bearer_token_env_var", JSON.stringify(variable));
88579
+ }
88580
+ index += 1;
88581
+ }
88582
+ return {
88583
+ args,
88584
+ env,
88585
+ skipped
88586
+ };
88587
+ };
88588
+ //#endregion
88325
88589
  //#region src/provider/CodexDeveloperInstructions.ts
88326
88590
  const P4_CODE_BROWSER_TOOL_INSTRUCTIONS = `
88327
88591
 
@@ -105085,6 +105349,7 @@ const HANDLED_TURN_START_KEY_MAX = 1e4;
105085
105349
  const HANDLED_TURN_START_KEY_TTL = Duration.minutes(30);
105086
105350
  const DEFAULT_RUNTIME_MODE = "full-access";
105087
105351
  const DEFAULT_THREAD_TITLE = "New thread";
105352
+ const FUSION_BUILDER_INSTRUCTIONS = `You are the Builder in a Fusion pair. Consult your Supervisor whenever you have a question, doubt, unresolved ambiguity, or decision you cannot make confidently. Continue independently when the available evidence is sufficient. Treat Supervisor advice as a decision to evaluate and follow unless it conflicts with the user's request or verified repository state.`;
105088
105353
  function providerErrorLabel(value) {
105089
105354
  const normalized = value?.trim();
105090
105355
  return normalized && normalized.length > 0 ? normalized : "unknown";
@@ -105536,6 +105801,8 @@ const make$3 = Effect.gen(function* () {
105536
105801
  "Attached PDF files are available at these local paths. Read them before answering:",
105537
105802
  ...documentReferenceLines
105538
105803
  ].filter((part) => part !== void 0).join("\n\n");
105804
+ const isFusionBuilder = ((yield* projectionSnapshotQuery.getCommandReadModel()).threadPairs ?? []).some((pair) => pair.detachedAt === null && pair.implementerThreadId === input.threadId);
105805
+ const fusionInput = expandedInputWithDocuments !== void 0 && isFusionBuilder ? `${FUSION_BUILDER_INSTRUCTIONS}\n\n${expandedInputWithDocuments}` : expandedInputWithDocuments;
105539
105806
  const activeSession = yield* providerService.listSessions().pipe(Effect.map((sessions) => sessions.find((session) => session.threadId === input.threadId)));
105540
105807
  const sessionModelSwitch = activeSession === void 0 ? "in-session" : activeSession.providerInstanceId === void 0 ? yield* new ProviderAdapterRequestError({
105541
105808
  provider: providerErrorLabel(activeSession.provider),
@@ -105558,7 +105825,7 @@ const make$3 = Effect.gen(function* () {
105558
105825
  staleRulesetMode: sessionRulesetMode
105559
105826
  });
105560
105827
  if (levelChangedMidSession) threadSessionRulesetModes.set(input.threadId, compressMode);
105561
- const inputWithCompressPrefix = expandedInputWithDocuments !== void 0 && compressPrefix !== void 0 ? `${compressPrefix}\n\n${expandedInputWithDocuments}` : expandedInputWithDocuments;
105828
+ const inputWithCompressPrefix = fusionInput !== void 0 && compressPrefix !== void 0 ? `${compressPrefix}\n\n${fusionInput}` : fusionInput;
105562
105829
  return {
105563
105830
  threadId: input.threadId,
105564
105831
  ...inputWithCompressPrefix ? { input: inputWithCompressPrefix } : {},
@@ -106391,6 +106658,8 @@ const watcherPowers = (implementerThreadId) => `You can steer the builder:
106391
106658
  - thread_advise with threadId ${implementerThreadId} posts advice into the builder thread. Use it when the builder should change course, and whenever the user asks you to tell, instruct or guide the builder.
106392
106659
  - thread_advise with interrupt: true cancels the builder's running turn before the advice lands. Reserve it for scope drift or work that is causing damage right now.
106393
106660
 
106661
+ Decide questions from available evidence when you can. Ask the user when a choice needs human authority. For design-related uncertainty, spawn the provider-native Designer subagent with exact scope and relevant paths. Evaluate its result, make the decision, and return that decision to the builder with thread_advise. Designer advises you; it does not replace your judgment or communicate with the builder directly.
106662
+
106394
106663
  Never call thread_watch_events repeatedly to wait for new activity, and never wait for the builder to respond: deliver your review and any advice, then end your turn. The server wakes you at the next turn boundary.`;
106395
106664
  /**
106396
106665
  * The delivery loop, restated in every review wake for the same reason the