Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
68ddf72
Add provider skill listing to workspace
Quicksaver Jun 12, 2026
ace7991
Address CodeRabbit review comments
Quicksaver Jun 12, 2026
5bc3d6e
Fix disabled Codex skill listing
Quicksaver Jun 12, 2026
c34dff3
Fix Codex skill listing refresh and validation
Quicksaver Jun 12, 2026
1a1547f
Fix workspace skill refresh state
Quicksaver Jun 12, 2026
b38045b
Remove test skill file
Quicksaver Jun 12, 2026
6acc264
Fix workspace-scoped Codex skill loading
Quicksaver Jun 12, 2026
5b4e534
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 18, 2026
8f06032
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
00cebad
Bound workspace skill discovery requests
juliusmarminge Jun 19, 2026
5c37b87
Preserve workspace skills during refresh
Quicksaver Jun 19, 2026
05e81b6
Harden provider workspace skill cache
Quicksaver Jun 19, 2026
307486b
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
22f37d0
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
e5496d6
Cover provider skill discovery failures
juliusmarminge Jun 19, 2026
f980381
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 19, 2026
be22f74
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 21, 2026
a5fb01d
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 25, 2026
1654062
Stabilize provider skills error messages
Quicksaver Jun 21, 2026
f75f6cd
Port provider skills diagnostic details
Quicksaver Jun 21, 2026
bd73e93
Show workspace skill chips in chat messages
Quicksaver Jun 25, 2026
3199949
Load workspace skills lazily in composer
Quicksaver Jun 25, 2026
3464e42
Restore provider skills failure reason contract
Quicksaver Jun 25, 2026
3e2be11
Add provider skills error cause sanitizer
Quicksaver Jun 25, 2026
973cb5c
Fix provider skills namespace imports
Quicksaver Jun 25, 2026
89984e1
Fix provider skill typecheck fallout
Quicksaver Jun 25, 2026
661a9f3
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 25, 2026
ebe1625
Normalize provider skills error cwd
Quicksaver Jun 26, 2026
8d076f1
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 26, 2026
46a1603
Refactor route-layer dependency options in ws
Quicksaver Jun 26, 2026
8f2dd72
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 27, 2026
c748279
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jun 27, 2026
2dc022d
Merge upstream timeline scroll updates
Quicksaver Jun 30, 2026
2bd42cd
Fix timeline live-follow cancellation
Quicksaver Jun 30, 2026
f5930d6
Retry timeline scroll listener setup
Quicksaver Jun 30, 2026
71a2a69
Fix timeline scroll listener and anchor cleanup
Quicksaver Jun 30, 2026
67a43b9
Fix timeline listener retry exhaustion
Quicksaver Jun 30, 2026
1bc887b
Fix exhausted timeline anchor state
Quicksaver Jun 30, 2026
c8c8dee
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 1, 2026
8bd26b0
Align workspace paths import in provider skills lister
Quicksaver Jul 1, 2026
5a12942
Merge upstream and preserve Codex skill fixes
Quicksaver Jul 3, 2026
34def14
Remove codex skill branch pollution
Quicksaver Jul 3, 2026
4350f99
Merge upstream mobile tasks and Vite Plus updates
Quicksaver Jul 4, 2026
e84b0fb
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 5, 2026
5e9d607
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 10, 2026
0b571ea
Hide publish-only links from Connect discovery
Quicksaver Jul 10, 2026
33581b8
Harden relay activity delivery maintenance
Quicksaver Jul 10, 2026
0b5087f
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 13, 2026
bc17d95
Share workspace-aware provider skills with mobile
Quicksaver Jul 13, 2026
3c78e6c
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 15, 2026
57fc6cf
Surface workspace skill errors with fallbacks
Quicksaver Jul 15, 2026
ba9b5fb
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 16, 2026
fa0563c
Remove remaining codex skills branch pollution
Quicksaver Jul 16, 2026
0f8bc68
Add Codex skill loading branch details
Quicksaver Jul 17, 2026
6b04a4c
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 18, 2026
aa42013
Gate timeline skill loading on sent skill references
Quicksaver Jul 18, 2026
2183032
Recognize trailing skills in timeline loading
Quicksaver Jul 18, 2026
b1af7c3
Improve timeline skill reference detection
Quicksaver Jul 18, 2026
345368c
Unify sent skill token boundaries
Quicksaver Jul 18, 2026
78833da
Update mobile markdown lockfile dependencies
Quicksaver Jul 18, 2026
edda975
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 19, 2026
bbb0343
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 19, 2026
fe0480b
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 19, 2026
823202b
Enable pnpm global virtual store
Quicksaver Jul 19, 2026
b832625
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 20, 2026
58d8eca
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 20, 2026
5798b81
Stop fallback changes from refreshing skill probes
Quicksaver Jul 20, 2026
6d09f51
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 20, 2026
55b7c23
Fix Codex skill probe and refresh state
Quicksaver Jul 20, 2026
eb0650d
Document pending workspace skill isolation
Quicksaver Jul 20, 2026
a973e27
Merge remote-tracking branch 'upstream/main' into fix/codex-skills
Quicksaver Jul 21, 2026
a9b4a6a
Avoid probing skills for future worktrees
Quicksaver Jul 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion apps/server/src/provider/Drivers/CodexDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const httpClient = yield* HttpClient.HttpClient;
const eventLoggers = yield* ProviderEventLoggers;
const serverConfig = yield* ServerConfig;
const processEnv = mergeProviderInstanceEnvironment(environment);
const homeLayout = yield* resolveCodexHomeLayout(config);
const continuationIdentity = codexContinuationIdentity(homeLayout);
Expand Down Expand Up @@ -159,7 +160,12 @@ export const CodexDriver: ProviderDriver<CodexSettings, CodexDriverEnv> = {
// in as instance rebuilds from the registry rather than in-place
// updates. Pre-provide `ChildProcessSpawner` so the check fits
// `makeManagedServerProvider.checkProvider`'s `R = never`.
const checkProvider = checkCodexProviderStatus(effectiveConfig, undefined, processEnv).pipe(
const checkProvider = checkCodexProviderStatus(
effectiveConfig,
serverConfig.cwd,
undefined,
processEnv,
).pipe(
Effect.map(stampIdentity),
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
);
Expand Down
7 changes: 6 additions & 1 deletion apps/server/src/provider/Drivers/CursorDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
const path = yield* Path.Path;
const httpClient = yield* HttpClient.HttpClient;
const eventLoggers = yield* ProviderEventLoggers;
const serverConfig = yield* ServerConfig;
const processEnv = mergeProviderInstanceEnvironment(environment);
const continuationIdentity = defaultProviderContinuationIdentity({
driverKind: DRIVER_KIND,
Expand All @@ -123,7 +124,11 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
});
const textGeneration = yield* makeCursorTextGeneration(effectiveConfig, processEnv);

const checkProvider = checkCursorProviderStatus(effectiveConfig, processEnv).pipe(
const checkProvider = checkCursorProviderStatus(
effectiveConfig,
serverConfig.cwd,
processEnv,
).pipe(
Effect.map(stampIdentity),
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
Effect.provideService(FileSystem.FileSystem, fileSystem),
Expand Down
7 changes: 6 additions & 1 deletion apps/server/src/provider/Drivers/GrokDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const httpClient = yield* HttpClient.HttpClient;
const eventLoggers = yield* ProviderEventLoggers;
const serverConfig = yield* ServerConfig;
const processEnv = mergeProviderInstanceEnvironment(environment);
const continuationIdentity = defaultProviderContinuationIdentity({
driverKind: DRIVER_KIND,
Expand All @@ -105,7 +106,11 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
});
const textGeneration = yield* makeGrokTextGeneration(effectiveConfig, processEnv);

const checkProvider = checkGrokProviderStatus(effectiveConfig, processEnv).pipe(
const checkProvider = checkGrokProviderStatus(
effectiveConfig,
serverConfig.cwd,
processEnv,
).pipe(
Effect.map(stampIdentity),
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
);
Expand Down
56 changes: 55 additions & 1 deletion apps/server/src/provider/Layers/CodexProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,59 @@ const requestAllCodexModels = Effect.fn("requestAllCodexModels")(function* (
return models;
});

export const listCodexProviderSkills = Effect.fn("listCodexProviderSkills")(function* (input: {
readonly binaryPath: string;
readonly homePath?: string;
readonly cwd: string;
readonly environment: NodeJS.ProcessEnv;
}) {
const resolvedHomePath = input.homePath ? expandHomePath(input.homePath) : undefined;
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const environment = {
...input.environment,
...(resolvedHomePath ? { CODEX_HOME: resolvedHomePath } : {}),
};
const spawnCommand = yield* resolveSpawnCommand(input.binaryPath, ["app-server"], {
env: environment,
extendEnv: true,
});
const child = yield* spawner
.spawn(
ChildProcess.make(spawnCommand.command, spawnCommand.args, {
cwd: input.cwd,
env: environment,
extendEnv: true,
forceKillAfter: CODEX_APP_SERVER_PROBE_FORCE_KILL_AFTER,
shell: spawnCommand.shell,
}),
)
.pipe(
Effect.mapError(
(cause) =>
new CodexErrors.CodexAppServerSpawnError({
command: `${input.binaryPath} app-server`,
cause,
}),
),
);
const clientContext = yield* Layer.build(CodexClient.layerChildProcess(child));
const client = yield* Effect.service(CodexClient.CodexAppServerClient).pipe(
Effect.provide(clientContext),
);

yield* client.request("initialize", buildCodexInitializeParams());
yield* client.notify("initialized", undefined);
const accountResponse = yield* client.request("account/read", {});
if (!accountResponse.account && accountResponse.requiresOpenaiAuth) {
return [];
}

const response = yield* client.request("skills/list", {
cwds: [input.cwd],
});
return parseCodexSkillsListResponse(response, input.cwd);
});
Comment thread
cursor[bot] marked this conversation as resolved.

export function buildCodexInitializeParams(): CodexSchema.V1InitializeParams {
return {
clientInfo: {
Expand Down Expand Up @@ -459,6 +512,7 @@ function accountProbeStatus(account: CodexAppServerProviderSnapshot["account"]):

export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(function* (
codexSettings: CodexSettings,
cwd: string,
probe: (input: {
readonly binaryPath: string;
readonly homePath?: string;
Expand Down Expand Up @@ -500,7 +554,7 @@ export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(fu
const probeResult = yield* probe({
binaryPath: codexSettings.binaryPath,
homePath: codexSettings.homePath,
cwd: process.cwd(),
cwd,
customModels: codexSettings.customModels,
environment: resolvedEnvironment,
}).pipe(
Expand Down
31 changes: 19 additions & 12 deletions apps/server/src/provider/Layers/CursorProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ describe("checkCursorProviderStatus", () => {
apiEndpoint: "",
customModels: [],
},
process.cwd(),
{
...process.env,
T3_ACP_REQUEST_LOG_PATH: requestLogPath,
Expand All @@ -444,12 +445,15 @@ describe("discoverCursorModelsViaAcp", () => {
const wrapperPath = await runNode(makeMockAgentWrapper());

const models = await Effect.runPromise(
discoverCursorModelsViaAcp({
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
}).pipe(Effect.provide(NodeServices.layer), Effect.scoped),
discoverCursorModelsViaAcp(
{
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
},
process.cwd(),
).pipe(Effect.provide(NodeServices.layer), Effect.scoped),
);

expect(models.map((model) => model.slug)).toEqual([
Expand All @@ -466,12 +470,15 @@ describe("discoverCursorModelsViaAcp", () => {
);

await Effect.runPromise(
discoverCursorModelsViaAcp({
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
}).pipe(Effect.provide(NodeServices.layer)),
discoverCursorModelsViaAcp(
{
enabled: true,
binaryPath: wrapperPath,
apiEndpoint: "",
customModels: [],
},
process.cwd(),
).pipe(Effect.provide(NodeServices.layer)),
);

const exitLog = await runNode(waitForFileContent(exitLogPath));
Expand Down
16 changes: 11 additions & 5 deletions apps/server/src/provider/Layers/CursorProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ function buildCursorDiscoveredModelsFromAvailableModelsResponse(

const makeCursorAcpProbeRuntime = (
cursorSettings: CursorSettings,
cwd: string,
environment?: NodeJS.ProcessEnv,
) =>
Effect.gen(function* () {
Expand All @@ -407,10 +408,10 @@ const makeCursorAcpProbeRuntime = (
...(cursorSettings.apiEndpoint ? (["-e", cursorSettings.apiEndpoint] as const) : []),
"acp",
],
cwd: process.cwd(),
cwd,
...(environment ? { env: environment } : {}),
},
cwd: process.cwd(),
cwd,
clientInfo: { name: "t3-code-provider-probe", version: "0.0.0" },
authMethodId: "cursor_login",
clientCapabilities: CURSOR_PARAMETERIZED_MODEL_PICKER_CAPABILITIES,
Expand All @@ -421,10 +422,11 @@ const makeCursorAcpProbeRuntime = (

const withCursorAcpProbeRuntime = <A, E, R>(
cursorSettings: CursorSettings,
cwd: string,
useRuntime: (acp: AcpSessionRuntime["Service"]) => Effect.Effect<A, E, R>,
environment?: NodeJS.ProcessEnv,
) =>
makeCursorAcpProbeRuntime(cursorSettings, environment).pipe(
makeCursorAcpProbeRuntime(cursorSettings, cwd, environment).pipe(
Effect.flatMap(useRuntime),
Effect.scoped,
);
Expand Down Expand Up @@ -543,10 +545,12 @@ export function resolveCursorAcpConfigUpdates(

const discoverCursorModelsViaListAvailableModels = (
cursorSettings: CursorSettings,
cwd: string,
environment?: NodeJS.ProcessEnv,
) =>
withCursorAcpProbeRuntime(
cursorSettings,
cwd,
(acp) =>
Effect.gen(function* () {
yield* acp.start();
Expand All @@ -559,8 +563,9 @@ const discoverCursorModelsViaListAvailableModels = (

export const discoverCursorModelsViaAcp = (
cursorSettings: CursorSettings,
cwd: string,
environment?: NodeJS.ProcessEnv,
) => discoverCursorModelsViaListAvailableModels(cursorSettings, environment);
) => discoverCursorModelsViaListAvailableModels(cursorSettings, cwd, environment);

export function getCursorFallbackModels(
cursorSettings: Pick<CursorSettings, "customModels">,
Expand Down Expand Up @@ -970,6 +975,7 @@ const runCursorAboutCommand = (cursorSettings: CursorSettings, environment?: Nod

export const checkCursorProviderStatus = Effect.fn("checkCursorProviderStatus")(function* (
cursorSettings: CursorSettings,
cwd: string,
environment?: NodeJS.ProcessEnv,
): Effect.fn.Return<
ServerProviderDraft,
Expand Down Expand Up @@ -1065,7 +1071,7 @@ export const checkCursorProviderStatus = Effect.fn("checkCursorProviderStatus")(
let discoveryWarning: string | undefined;
if (parsed.auth.status !== "unauthenticated") {
const discoveryExit = yield* Effect.exit(
discoverCursorModelsViaAcp(cursorSettings, environment).pipe(
discoverCursorModelsViaAcp(cursorSettings, cwd, environment).pipe(
Effect.timeoutOption(CURSOR_ACP_MODEL_DISCOVERY_TIMEOUT_MS),
),
);
Expand Down
3 changes: 3 additions & 0 deletions apps/server/src/provider/Layers/GrokProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ it.layer(NodeServices.layer)("checkGrokProviderStatus", (it) => {
enabled: true,
binaryPath: "/definitely/not/installed/grok-binary",
}),
process.cwd(),
);
expect(snapshot.enabled).toBe(true);
expect(snapshot.installed).toBe(false);
Expand All @@ -68,6 +69,7 @@ it.layer(NodeServices.layer)("checkGrokProviderStatus", (it) => {

return yield* checkGrokProviderStatus(
decodeGrokSettings({ enabled: true, binaryPath: grokPath }),
process.cwd(),
);
}),
);
Expand Down Expand Up @@ -95,6 +97,7 @@ it.layer(NodeServices.layer)("checkGrokProviderStatus", (it) => {

return yield* checkGrokProviderStatus(
decodeGrokSettings({ enabled: true, binaryPath: grokPath }),
process.cwd(),
);
}),
);
Expand Down
6 changes: 4 additions & 2 deletions apps/server/src/provider/Layers/GrokProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ function buildGrokDiscoveredModelsFromSessionModelState(

const discoverGrokModelsViaAcp = (
grokSettings: GrokSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
) =>
Effect.gen(function* () {
Expand All @@ -140,7 +141,7 @@ const discoverGrokModelsViaAcp = (
grokSettings,
environment,
childProcessSpawner,
cwd: process.cwd(),
cwd,
clientInfo: { name: "t3-code-provider-probe", version: "0.0.0" },
});
const started = yield* acp.start();
Expand All @@ -167,6 +168,7 @@ const runGrokVersionCommand = (

export const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(function* (
grokSettings: GrokSettings,
cwd: string,
environment: NodeJS.ProcessEnv = process.env,
): Effect.fn.Return<ServerProviderDraft, never, ChildProcessSpawner.ChildProcessSpawner> {
const checkedAt = DateTime.formatIso(yield* DateTime.now);
Expand Down Expand Up @@ -249,7 +251,7 @@ export const checkGrokProviderStatus = Effect.fn("checkGrokProviderStatus")(func
});
}

const discoveryExit = yield* discoverGrokModelsViaAcp(grokSettings, environment).pipe(
const discoveryExit = yield* discoverGrokModelsViaAcp(grokSettings, cwd, environment).pipe(
Effect.timeoutOption(GROK_ACP_MODEL_DISCOVERY_TIMEOUT_MS),
Effect.exit,
);
Expand Down
Loading
Loading