diff --git a/apps/server/src/cli/thread.ts b/apps/server/src/cli/thread.ts index ff27441dc089..53b42063b5df 100644 --- a/apps/server/src/cli/thread.ts +++ b/apps/server/src/cli/thread.ts @@ -69,6 +69,9 @@ export class ThreadCliError extends Schema.TaggedErrorClass()("T const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown)); const isThreadCliError = Schema.is(ThreadCliError); +const currentThreadIdForHome = (home: string): string | undefined => + process.env.T3CODE_HOME?.trim() === home ? process.env.T3CODE_THREAD_ID?.trim() : undefined; + const ThreadIdentity = Schema.Struct({ environmentId: Schema.String, threadId: Schema.String, @@ -890,6 +893,7 @@ const runThreadSend = Effect.fn("runThreadSend")(function* ( Effect.mapError((cause) => new ThreadSendServerUnavailableError({ cause })), ); const minimumLogLevel = config.logLevel; + const currentThreadId = currentThreadIdForHome(config.baseDir); return yield* Effect.gen(function* () { const auth = yield* EnvironmentAuth.EnvironmentAuth; @@ -956,12 +960,10 @@ const runThreadSend = Effect.fn("runThreadSend")(function* ( commandId, messageId, createdAt: DateTime.formatIso(yield* DateTime.now), - ...(process.env.T3CODE_THREAD_ID?.trim() - ? { sourceThreadId: ThreadId.make(process.env.T3CODE_THREAD_ID.trim()) } - : {}), + ...(currentThreadId ? { sourceThreadId: ThreadId.make(currentThreadId) } : {}), ...(waitForCompletion ? { trackRequestCorrelation: true as const } : {}), - ...(waitForCompletion && process.env.T3CODE_THREAD_ID?.trim() - ? { rejectWaitForThreadId: ThreadId.make(process.env.T3CODE_THREAD_ID.trim()) } + ...(waitForCompletion && currentThreadId + ? { rejectWaitForThreadId: ThreadId.make(currentThreadId) } : {}), }, ); @@ -1046,7 +1048,7 @@ const runThreadWait = Effect.fn("runThreadWait")(function* ( ), }); } - const currentThreadId = process.env.T3CODE_THREAD_ID?.trim(); + const currentThreadId = currentThreadIdForHome(config.baseDir); const waitingOnCurrentThread = currentThreadId === waitHandle.threadId; return yield* Effect.gen(function* () { const auth = yield* EnvironmentAuth.EnvironmentAuth; diff --git a/apps/server/src/persistence/Migrations/016_CanonicalizeModelSelections.test.ts b/apps/server/src/persistence/Migrations/016_CanonicalizeModelSelections.test.ts index 451351496880..fff5a738622d 100644 --- a/apps/server/src/persistence/Migrations/016_CanonicalizeModelSelections.test.ts +++ b/apps/server/src/persistence/Migrations/016_CanonicalizeModelSelections.test.ts @@ -381,11 +381,11 @@ layer("016_CanonicalizeModelSelections", (it) => { ); }); -layer("053_ClearAutomaticProjectModelDefaults", (it) => { +layer("044_ClearAutomaticProjectModelDefaults", (it) => { it.effect("clears create-time seeds and preserves explicit project defaults", () => Effect.gen(function* () { const sql = yield* SqlClient.SqlClient; - yield* runMigrations({ toMigrationInclusive: 52 }); + yield* runMigrations({ toMigrationInclusive: 43 }); yield* sql` INSERT INTO projection_projects ( @@ -429,7 +429,7 @@ layer("053_ClearAutomaticProjectModelDefaults", (it) => { ('event-explicit-update', 'project', 'project-explicit', 1, 'project.meta-updated', '2026-08-02T00:00:00.000Z', 'command-explicit-update', NULL, 'command-explicit-update', 'client', '{"defaultModelSelection":{"instanceId":"codex","model":"gpt-5.6-sol","options":[{"id":"reasoningEffort","value":"high"}]}}', '{}') `; - yield* runMigrations({ toMigrationInclusive: 53 }); + yield* runMigrations({ toMigrationInclusive: 44 }); const projects = yield* sql<{ readonly projectId: string; diff --git a/apps/server/src/persistence/Migrations/046_RepairAutomaticSettlementTimestamps.test.ts b/apps/server/src/persistence/Migrations/046_RepairAutomaticSettlementTimestamps.test.ts index 069799502507..f562fa655a11 100644 --- a/apps/server/src/persistence/Migrations/046_RepairAutomaticSettlementTimestamps.test.ts +++ b/apps/server/src/persistence/Migrations/046_RepairAutomaticSettlementTimestamps.test.ts @@ -10,11 +10,11 @@ const layer = it.layer(Layer.mergeAll(NodeSqliteClient.layerMemory())); const MODEL_SELECTION = '{"instanceId":"codex","model":"gpt-5.6-sol"}'; -layer("055_RepairAutomaticSettlementTimestamps", (it) => { +layer("046_RepairAutomaticSettlementTimestamps", (it) => { it.effect("repairs automatic stamps and leaves manual settlement alone", () => Effect.gen(function* () { const sql = yield* SqlClient.SqlClient; - yield* runMigrations({ toMigrationInclusive: 54 }); + yield* runMigrations({ toMigrationInclusive: 45 }); yield* sql` INSERT INTO projection_threads ( @@ -164,7 +164,7 @@ layer("055_RepairAutomaticSettlementTimestamps", (it) => { const eventsBefore = yield* sql`SELECT payload_json FROM orchestration_events ORDER BY event_id`; - yield* runMigrations({ toMigrationInclusive: 55 }); + yield* runMigrations({ toMigrationInclusive: 46 }); const threads = yield* sql<{ readonly threadId: string; diff --git a/apps/server/src/provider/Layers/CursorProvider.test.ts b/apps/server/src/provider/Layers/CursorProvider.test.ts index 98983b4b4434..ac9837d43ebd 100644 --- a/apps/server/src/provider/Layers/CursorProvider.test.ts +++ b/apps/server/src/provider/Layers/CursorProvider.test.ts @@ -368,18 +368,19 @@ describe("Cursor skills", () => { "not a directory", ); + const realWorkspace = yield* fileSystem.realPath(workspace); const skills = yield* discoverCursorSkills(workspace, { HOME: userHome }); expect(skills).toEqual([ { name: "internal", - path: path.join(workspace, ".cursor", "skills", "internal", "SKILL.md"), + path: path.join(realWorkspace, ".cursor", "skills", "internal", "SKILL.md"), scope: "project", enabled: true, userInvocable: false, }, { name: "oversized", - path: path.join(workspace, ".cursor", "skills", "oversized", "SKILL.md"), + path: path.join(realWorkspace, ".cursor", "skills", "oversized", "SKILL.md"), scope: "project", enabled: true, }, @@ -387,7 +388,7 @@ describe("Cursor skills", () => { name: "review", displayName: "Review changes", description: "project review", - path: path.join(workspace, ".agents", "skills", "nested", "review", "SKILL.md"), + path: path.join(realWorkspace, ".agents", "skills", "nested", "review", "SKILL.md"), scope: "project", enabled: true, }, diff --git a/scripts/lastcode-local-update.mjs b/scripts/lastcode-local-update.mjs index c490d87ee68d..e10ef5c78e4d 100644 --- a/scripts/lastcode-local-update.mjs +++ b/scripts/lastcode-local-update.mjs @@ -688,7 +688,9 @@ function buildUnlocked(options, updateRoot) { if (!NodeFS.existsSync(installer)) { throw new Error(`Checkpoint automation dependencies are missing at ${installer}.`); } - run(worktreePath, installer, ["install", "--frozen-lockfile"], { logFd }); + // The retained build worktree can otherwise keep stale snapshots of local + // file dependencies when their source changes without a lockfile change. + run(worktreePath, installer, ["install", "--frozen-lockfile", "--force"], { logFd }); const mise = resolveMise(options.home); const nodeCommand = ["exec", "node@24.13.1", "--", "node"]; const nodeExecutable = run(worktreePath, mise, [...nodeCommand, "-p", "process.execPath"]);