@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 +871 -602
- package/dist/client/assets/{DiffPanel-DoGJuNGg.js → DiffPanel-Clrv5Oc9.js} +2 -2
- package/dist/client/assets/{FilePreviewPanel-C-7-kFxk.js → FilePreviewPanel-CPswWlzH.js} +2 -2
- package/dist/client/assets/{PreviewPanel-D7QbAZuj.js → PreviewPanel-AIlEywQK.js} +2 -2
- package/dist/client/assets/{PullRequestCodeTab-H8SBSXwX.js → PullRequestCodeTab-DJgw64uV.js} +2 -2
- package/dist/client/assets/{fileCommentAnnotations-BXeKe2rU.js → fileCommentAnnotations-DSyTaqP7.js} +2 -2
- package/dist/client/assets/index-CbyMk5N4.css +1 -0
- package/dist/client/assets/{index-CqFqaFmU.js → index-ChiJJUm2.js} +240 -230
- package/dist/client/assets/{renderFileChildren-9PJn-4fW.js → renderFileChildren-BFvLnmNZ.js} +2 -2
- package/dist/client/assets/{toggle-group-Bk2OyiTO.js → toggle-group-DkLWU3bB.js} +2 -2
- package/dist/client/index.html +2 -2
- package/package.json +1 -1
- package/dist/client/assets/index-BozSpIis.css +0 -1
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.
|
|
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
|
-
|
|
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
|
|
87577
|
-
|
|
87578
|
-
|
|
87579
|
-
|
|
87580
|
-
|
|
87581
|
-
|
|
87582
|
-
|
|
87583
|
-
const
|
|
87584
|
-
|
|
87585
|
-
|
|
87586
|
-
|
|
87587
|
-
|
|
87588
|
-
|
|
87589
|
-
|
|
87590
|
-
|
|
87591
|
-
|
|
87592
|
-
|
|
87593
|
-
|
|
87594
|
-
|
|
87595
|
-
|
|
87596
|
-
|
|
87597
|
-
|
|
87598
|
-
|
|
87599
|
-
|
|
87600
|
-
|
|
87601
|
-
|
|
87602
|
-
|
|
87603
|
-
|
|
87604
|
-
|
|
87605
|
-
|
|
87606
|
-
|
|
87607
|
-
|
|
87608
|
-
|
|
87609
|
-
|
|
87610
|
-
|
|
87611
|
-
|
|
87612
|
-
|
|
87613
|
-
|
|
87614
|
-
|
|
87615
|
-
|
|
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
|
-
|
|
87643
|
-
|
|
87133
|
+
};
|
|
87134
|
+
visit(root, 0);
|
|
87644
87135
|
return {
|
|
87645
|
-
|
|
87646
|
-
|
|
87647
|
-
|
|
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 =
|
|
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
|