| author | |
| committer | |
| log | d249e628eef2cd8dcd4c5b9c79c443b77ca4a851 |
| tree | 99a406364bd226570073d20525f3bc83270b313d |
| parent | 40fcb6bdf8d726f35c6d3aec82d0cce6345c9dcd |
| signature | Signed by PGP key B5690EEEBB952194 |
* Stage production icons for desktop builds and publish
- add shared brand asset paths and a Windows .ico asset
- stage Linux/Windows icons in desktop artifact builds
- override and restore publish favicon during server CLI publish
* 'blip'
* Fix PR review issues for publish icon staging
* Refactor brand assets and harden Windows desktop build setup
* Apply remaining server orchestration updates
* Fix production mac icon asset
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Theo Browne <t3dotgg@users.noreply.github.com>46 files changed, 267 insertions(+), 90 deletions(-)
apps/server/integration/OrchestrationEngineHarness.integration.ts+5-10| ... | @@ -406,19 +406,14 @@ export const makeOrchestrationIntegrationHarness = ( | ... | @@ -406,19 +406,14 @@ export const makeOrchestrationIntegrationHarness = ( |
| 406 | disposed = true; | 406 | disposed = true; |
| 407 | 407 | ||
| 408 | const shutdown = Effect.gen(function* () { | 408 | const shutdown = Effect.gen(function* () { |
| 409 | const stopAllExit = yield* Effect.exit( | ||
| 410 | Effect.promise(() => runtime.runPromise(providerService.stopAll())), | ||
| 411 | ); | ||
| 412 | const closeScopeExit = yield* Effect.exit(Scope.close(scope, Exit.void)); | 409 | const closeScopeExit = yield* Effect.exit(Scope.close(scope, Exit.void)); |
| 413 | const disposeRuntimeExit = yield* Effect.exit(Effect.promise(() => runtime.dispose())); | 410 | const disposeRuntimeExit = yield* Effect.exit(Effect.promise(() => runtime.dispose())); |
| 414 | 411 | ||
| 415 | const failureCause = Exit.isFailure(stopAllExit) | 412 | const failureCause = Exit.isFailure(closeScopeExit) |
| 416 | ? stopAllExit.cause | 413 | ? closeScopeExit.cause |
| 417 | : Exit.isFailure(closeScopeExit) | 414 | : Exit.isFailure(disposeRuntimeExit) |
| 418 | ? closeScopeExit.cause | 415 | ? disposeRuntimeExit.cause |
| 419 | : Exit.isFailure(disposeRuntimeExit) | 416 | : null; |
| 420 | ? disposeRuntimeExit.cause | ||
| 421 | : null; | ||
| 422 | 417 | ||
| 423 | if (failureCause) { | 418 | if (failureCause) { |
| 424 | return yield* Effect.failCause(failureCause); | 419 | return yield* Effect.failCause(failureCause); |
apps/server/scripts/cli.ts+95-6| ... | @@ -6,6 +6,7 @@ import { Data, Effect, FileSystem, Logger, Option, Path } from "effect"; | ... | @@ -6,6 +6,7 @@ import { Data, Effect, FileSystem, Logger, Option, Path } from "effect"; |
| 6 | import { Command, Flag } from "effect/unstable/cli"; | 6 | import { Command, Flag } from "effect/unstable/cli"; |
| 7 | import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; | 7 | import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; |
| 8 | 8 | ||
| 9 | import { DEVELOPMENT_ICON_OVERRIDES, PUBLISH_ICON_OVERRIDES } from "../../../scripts/lib/brand-assets.ts"; | ||
| 9 | import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts"; | 10 | import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts"; |
| 10 | import rootPackageJson from "../../../package.json" with { type: "json" }; | 11 | import rootPackageJson from "../../../package.json" with { type: "json" }; |
| 11 | import serverPackageJson from "../package.json" with { type: "json" }; | 12 | import serverPackageJson from "../package.json" with { type: "json" }; |
| ... | @@ -31,6 +32,84 @@ const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.Comm | ... | @@ -31,6 +32,84 @@ const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.Comm |
| 31 | } | 32 | } |
| 32 | }); | 33 | }); |
| 33 | 34 | ||
| 35 | interface PublishIconBackup { | ||
| 36 | readonly targetPath: string; | ||
| 37 | readonly backupPath: string; | ||
| 38 | } | ||
| 39 | |||
| 40 | const applyPublishIconOverrides = Effect.fn("applyPublishIconOverrides")(function* ( | ||
| 41 | repoRoot: string, | ||
| 42 | serverDir: string, | ||
| 43 | ) { | ||
| 44 | const path = yield* Path.Path; | ||
| 45 | const fs = yield* FileSystem.FileSystem; | ||
| 46 | const backups: PublishIconBackup[] = []; | ||
| 47 | |||
| 48 | for (const override of PUBLISH_ICON_OVERRIDES) { | ||
| 49 | const sourcePath = path.join(repoRoot, override.sourceRelativePath); | ||
| 50 | const targetPath = path.join(serverDir, override.targetRelativePath); | ||
| 51 | const backupPath = `${targetPath}.publish-bak`; | ||
| 52 | |||
| 53 | if (!(yield* fs.exists(sourcePath))) { | ||
| 54 | return yield* new CliError({ | ||
| 55 | message: `Missing publish icon source: ${sourcePath}`, | ||
| 56 | }); | ||
| 57 | } | ||
| 58 | if (!(yield* fs.exists(targetPath))) { | ||
| 59 | return yield* new CliError({ | ||
| 60 | message: `Missing publish icon target: ${targetPath}. Run the build subcommand first.`, | ||
| 61 | }); | ||
| 62 | } | ||
| 63 | |||
| 64 | yield* fs.copyFile(targetPath, backupPath); | ||
| 65 | yield* fs.copyFile(sourcePath, targetPath); | ||
| 66 | backups.push({ targetPath, backupPath }); | ||
| 67 | } | ||
| 68 | |||
| 69 | yield* Effect.log("[cli] Applied publish icon overrides to dist/client"); | ||
| 70 | return backups as ReadonlyArray<PublishIconBackup>; | ||
| 71 | }); | ||
| 72 | |||
| 73 | const restorePublishIconOverrides = Effect.fn("restorePublishIconOverrides")(function* ( | ||
| 74 | backups: ReadonlyArray<PublishIconBackup>, | ||
| 75 | ) { | ||
| 76 | const fs = yield* FileSystem.FileSystem; | ||
| 77 | for (const backup of backups) { | ||
| 78 | if (!(yield* fs.exists(backup.backupPath))) { | ||
| 79 | continue; | ||
| 80 | } | ||
| 81 | yield* fs.rename(backup.backupPath, backup.targetPath); | ||
| 82 | } | ||
| 83 | }); | ||
| 84 | |||
| 85 | const applyDevelopmentIconOverrides = Effect.fn("applyDevelopmentIconOverrides")(function* ( | ||
| 86 | repoRoot: string, | ||
| 87 | serverDir: string, | ||
| 88 | ) { | ||
| 89 | const path = yield* Path.Path; | ||
| 90 | const fs = yield* FileSystem.FileSystem; | ||
| 91 | |||
| 92 | for (const override of DEVELOPMENT_ICON_OVERRIDES) { | ||
| 93 | const sourcePath = path.join(repoRoot, override.sourceRelativePath); | ||
| 94 | const targetPath = path.join(serverDir, override.targetRelativePath); | ||
| 95 | |||
| 96 | if (!(yield* fs.exists(sourcePath))) { | ||
| 97 | return yield* new CliError({ | ||
| 98 | message: `Missing development icon source: ${sourcePath}`, | ||
| 99 | }); | ||
| 100 | } | ||
| 101 | if (!(yield* fs.exists(targetPath))) { | ||
| 102 | return yield* new CliError({ | ||
| 103 | message: `Missing development icon target: ${targetPath}. Build web first.`, | ||
| 104 | }); | ||
| 105 | } | ||
| 106 | |||
| 107 | yield* fs.copyFile(sourcePath, targetPath); | ||
| 108 | } | ||
| 109 | |||
| 110 | yield* Effect.log("[cli] Applied development icon overrides to dist/client"); | ||
| 111 | }); | ||
| 112 | |||
| 34 | // --------------------------------------------------------------------------- | 113 | // --------------------------------------------------------------------------- |
| 35 | // build subcommand | 114 | // build subcommand |
| 36 | // --------------------------------------------------------------------------- | 115 | // --------------------------------------------------------------------------- |
| ... | @@ -61,6 +140,7 @@ const buildCmd = Command.make( | ... | @@ -61,6 +140,7 @@ const buildCmd = Command.make( |
| 61 | 140 | ||
| 62 | if (yield* fs.exists(webDist)) { | 141 | if (yield* fs.exists(webDist)) { |
| 63 | yield* fs.copy(webDist, clientTarget); | 142 | yield* fs.copy(webDist, clientTarget); |
| 143 | yield* applyDevelopmentIconOverrides(repoRoot, serverDir); | ||
| 64 | yield* Effect.log("[cli] Bundled web app into dist/client"); | 144 | yield* Effect.log("[cli] Bundled web app into dist/client"); |
| 65 | } else { | 145 | } else { |
| 66 | yield* Effect.logWarning("[cli] Web dist not found — skipping client bundle."); | 146 | yield* Effect.logWarning("[cli] Web dist not found — skipping client bundle."); |
| ... | @@ -104,10 +184,8 @@ const publishCmd = Command.make( | ... | @@ -104,10 +184,8 @@ const publishCmd = Command.make( |
| 104 | yield* Effect.acquireUseRelease( | 184 | yield* Effect.acquireUseRelease( |
| 105 | // Acquire: backup package.json, resolve catalog: deps, strip devDependencies/scripts | 185 | // Acquire: backup package.json, resolve catalog: deps, strip devDependencies/scripts |
| 106 | Effect.gen(function* () { | 186 | Effect.gen(function* () { |
| 107 | const original = yield* fs.readFileString(packageJsonPath); | 187 | // Resolve catalog dependencies before any file mutations. If this throws, |
| 108 | yield* fs.writeFileString(backupPath, original); | 188 | // acquire fails and no release hook runs, so filesystem must still be untouched. |
| 109 | |||
| 110 | // Build package.json for publish | ||
| 111 | const version = Option.getOrElse(config.appVersion, () => serverPackageJson.version); | 189 | const version = Option.getOrElse(config.appVersion, () => serverPackageJson.version); |
| 112 | const pkg = { | 190 | const pkg = { |
| 113 | name: serverPackageJson.name, | 191 | name: serverPackageJson.name, |
| ... | @@ -120,15 +198,19 @@ const publishCmd = Command.make( | ... | @@ -120,15 +198,19 @@ const publishCmd = Command.make( |
| 120 | dependencies: serverPackageJson.dependencies as Record<string, unknown>, | 198 | dependencies: serverPackageJson.dependencies as Record<string, unknown>, |
| 121 | }; | 199 | }; |
| 122 | 200 | ||
| 123 | // Resolve catalog: entries in production dependencies | ||
| 124 | pkg.dependencies = resolveCatalogDependencies( | 201 | pkg.dependencies = resolveCatalogDependencies( |
| 125 | pkg.dependencies, | 202 | pkg.dependencies, |
| 126 | rootPackageJson.workspaces.catalog, | 203 | rootPackageJson.workspaces.catalog, |
| 127 | "apps/server dependencies", | 204 | "apps/server dependencies", |
| 128 | ); | 205 | ); |
| 129 | 206 | ||
| 207 | const original = yield* fs.readFileString(packageJsonPath); | ||
| 208 | yield* fs.writeFileString(backupPath, original); | ||
| 130 | yield* fs.writeFileString(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`); | 209 | yield* fs.writeFileString(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`); |
| 131 | yield* Effect.log("[cli] Resolved package.json for publish"); | 210 | yield* Effect.log("[cli] Resolved package.json for publish"); |
| 211 | |||
| 212 | const iconBackups = yield* applyPublishIconOverrides(repoRoot, serverDir); | ||
| 213 | return { iconBackups }; | ||
| 132 | }), | 214 | }), |
| 133 | // Use: npm publish | 215 | // Use: npm publish |
| 134 | () => | 216 | () => |
| ... | @@ -147,8 +229,15 @@ const publishCmd = Command.make( | ... | @@ -147,8 +229,15 @@ const publishCmd = Command.make( |
| 147 | ); | 229 | ); |
| 148 | }), | 230 | }), |
| 149 | // Release: restore | 231 | // Release: restore |
| 150 | () => | 232 | (resource: { readonly iconBackups: ReadonlyArray<PublishIconBackup> }) => |
| 151 | Effect.gen(function* () { | 233 | Effect.gen(function* () { |
| 234 | yield* restorePublishIconOverrides(resource.iconBackups).pipe( | ||
| 235 | Effect.catch((error) => | ||
| 236 | Effect.logError( | ||
| 237 | `[cli] Failed to restore publish icon overrides: ${String(error)}`, | ||
| 238 | ), | ||
| 239 | ), | ||
| 240 | ); | ||
| 152 | yield* fs.rename(backupPath, packageJsonPath); | 241 | yield* fs.rename(backupPath, packageJsonPath); |
| 153 | if (config.verbose) yield* Effect.log("[cli] Restored original package.json"); | 242 | if (config.verbose) yield* Effect.log("[cli] Restored original package.json"); |
| 154 | }), | 243 | }), |
apps/server/src/orchestration/Layers/CheckpointReactor.test.ts-1| ... | @@ -91,7 +91,6 @@ function createProviderServiceHarness( | ... | @@ -91,7 +91,6 @@ function createProviderServiceHarness( |
| 91 | listSessions, | 91 | listSessions, |
| 92 | getCapabilities: () => Effect.succeed({ sessionModelSwitch: "in-session" }), | 92 | getCapabilities: () => Effect.succeed({ sessionModelSwitch: "in-session" }), |
| 93 | rollbackConversation, | 93 | rollbackConversation, |
| 94 | stopAll: () => Effect.void, | ||
| 95 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), | 94 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), |
| 96 | }; | 95 | }; |
| 97 | 96 |
apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts-1| ... | @@ -188,7 +188,6 @@ describe("ProviderCommandReactor", () => { | ... | @@ -188,7 +188,6 @@ describe("ProviderCommandReactor", () => { |
| 188 | sessionModelSwitch: provider === "codex" ? "in-session" : "in-session", | 188 | sessionModelSwitch: provider === "codex" ? "in-session" : "in-session", |
| 189 | }), | 189 | }), |
| 190 | rollbackConversation: () => unsupported(), | 190 | rollbackConversation: () => unsupported(), |
| 191 | stopAll: () => Effect.void, | ||
| 192 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), | 191 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), |
| 193 | }; | 192 | }; |
| 194 | 193 |
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts-1| ... | @@ -65,7 +65,6 @@ function createProviderServiceHarness() { | ... | @@ -65,7 +65,6 @@ function createProviderServiceHarness() { |
| 65 | listSessions: () => Effect.succeed([]), | 65 | listSessions: () => Effect.succeed([]), |
| 66 | getCapabilities: () => Effect.succeed({ sessionModelSwitch: "in-session" }), | 66 | getCapabilities: () => Effect.succeed({ sessionModelSwitch: "in-session" }), |
| 67 | rollbackConversation: () => unsupported(), | 67 | rollbackConversation: () => unsupported(), |
| 68 | stopAll: () => Effect.void, | ||
| 69 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), | 68 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), |
| 70 | }; | 69 | }; |
| 71 | 70 |
apps/server/src/provider/Layers/ProviderService.test.ts+3-16| ... | @@ -356,11 +356,6 @@ it.effect( | ... | @@ -356,11 +356,6 @@ it.effect( |
| 356 | }); | 356 | }); |
| 357 | }).pipe(Effect.provide(firstProviderLayer)); | 357 | }).pipe(Effect.provide(firstProviderLayer)); |
| 358 | 358 | ||
| 359 | yield* Effect.gen(function* () { | ||
| 360 | const provider = yield* ProviderService; | ||
| 361 | yield* provider.stopAll(); | ||
| 362 | }).pipe(Effect.provide(firstProviderLayer)); | ||
| 363 | |||
| 364 | const persistedAfterStopAll = yield* Effect.gen(function* () { | 359 | const persistedAfterStopAll = yield* Effect.gen(function* () { |
| 365 | const repository = yield* ProviderSessionRuntimeRepository; | 360 | const repository = yield* ProviderSessionRuntimeRepository; |
| 366 | return yield* repository.getByThreadId({ threadId: startedSession.threadId }); | 361 | return yield* repository.getByThreadId({ threadId: startedSession.threadId }); |
| ... | @@ -549,7 +544,7 @@ routing.layer("ProviderServiceLive routing", (it) => { | ... | @@ -549,7 +544,7 @@ routing.layer("ProviderServiceLive routing", (it) => { |
| 549 | runtimeMode: "full-access", | 544 | runtimeMode: "full-access", |
| 550 | }); | 545 | }); |
| 551 | 546 | ||
| 552 | yield* provider.stopAll(); | 547 | yield* routing.codex.stopAll(); |
| 553 | routing.codex.startSession.mockClear(); | 548 | routing.codex.startSession.mockClear(); |
| 554 | routing.codex.sendTurn.mockClear(); | 549 | routing.codex.sendTurn.mockClear(); |
| 555 | 550 | ||
| ... | @@ -578,7 +573,7 @@ routing.layer("ProviderServiceLive routing", (it) => { | ... | @@ -578,7 +573,7 @@ routing.layer("ProviderServiceLive routing", (it) => { |
| 578 | }), | 573 | }), |
| 579 | ); | 574 | ); |
| 580 | 575 | ||
| 581 | it.effect("stops all sessions and clears adapter runtime", () => | 576 | it.effect("lists no sessions after adapter runtime clears", () => |
| 582 | Effect.gen(function* () { | 577 | Effect.gen(function* () { |
| 583 | const provider = yield* ProviderService; | 578 | const provider = yield* ProviderService; |
| 584 | 579 | ||
| ... | @@ -593,7 +588,7 @@ routing.layer("ProviderServiceLive routing", (it) => { | ... | @@ -593,7 +588,7 @@ routing.layer("ProviderServiceLive routing", (it) => { |
| 593 | runtimeMode: "full-access", | 588 | runtimeMode: "full-access", |
| 594 | }); | 589 | }); |
| 595 | 590 | ||
| 596 | yield* provider.stopAll(); | 591 | yield* routing.codex.stopAll(); |
| 597 | 592 | ||
| 598 | const remaining = yield* provider.listSessions(); | 593 | const remaining = yield* provider.listSessions(); |
| 599 | assert.equal(remaining.length, 0); | 594 | assert.equal(remaining.length, 0); |
| ... | @@ -641,14 +636,6 @@ routing.layer("ProviderServiceLive routing", (it) => { | ... | @@ -641,14 +636,6 @@ routing.layer("ProviderServiceLive routing", (it) => { |
| 641 | } | 636 | } |
| 642 | } | 637 | } |
| 643 | 638 | ||
| 644 | yield* provider.stopAll(); | ||
| 645 | const stoppedRuntime = yield* runtimeRepository.getByThreadId({ | ||
| 646 | threadId: session.threadId, | ||
| 647 | }); | ||
| 648 | assert.equal(Option.isSome(stoppedRuntime), true); | ||
| 649 | if (Option.isSome(stoppedRuntime)) { | ||
| 650 | assert.equal(stoppedRuntime.value.status, "stopped"); | ||
| 651 | } | ||
| 652 | }), | 639 | }), |
| 653 | ); | 640 | ); |
| 654 | }); | 641 | }); |
apps/server/src/provider/Layers/ProviderService.ts+7-2| ... | @@ -471,7 +471,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => | ... | @@ -471,7 +471,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => |
| 471 | }); | 471 | }); |
| 472 | }); | 472 | }); |
| 473 | 473 | ||
| 474 | const stopAll: ProviderServiceShape["stopAll"] = () => | 474 | const runStopAll = () => |
| 475 | Effect.gen(function* () { | 475 | Effect.gen(function* () { |
| 476 | const threadIds = yield* directory.listThreadIds(); | 476 | const threadIds = yield* directory.listThreadIds(); |
| 477 | yield* Effect.forEach(adapters, (adapter) => adapter.stopAll()).pipe(Effect.asVoid); | 477 | yield* Effect.forEach(adapters, (adapter) => adapter.stopAll()).pipe(Effect.asVoid); |
| ... | @@ -497,6 +497,12 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => | ... | @@ -497,6 +497,12 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => |
| 497 | yield* analytics.flush; | 497 | yield* analytics.flush; |
| 498 | }); | 498 | }); |
| 499 | 499 | ||
| 500 | yield* Effect.addFinalizer(() => | ||
| 501 | Effect.catch(runStopAll(), (cause) => | ||
| 502 | Effect.logWarning("failed to stop provider service", { cause }), | ||
| 503 | ), | ||
| 504 | ); | ||
| 505 | |||
| 500 | return { | 506 | return { |
| 501 | startSession, | 507 | startSession, |
| 502 | sendTurn, | 508 | sendTurn, |
| ... | @@ -507,7 +513,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => | ... | @@ -507,7 +513,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => |
| 507 | listSessions, | 513 | listSessions, |
| 508 | getCapabilities, | 514 | getCapabilities, |
| 509 | rollbackConversation, | 515 | rollbackConversation, |
| 510 | stopAll, | ||
| 511 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), | 516 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), |
| 512 | } satisfies ProviderServiceShape; | 517 | } satisfies ProviderServiceShape; |
| 513 | }); | 518 | }); |
apps/server/src/provider/Services/ProviderService.ts-10| ... | @@ -99,16 +99,6 @@ export interface ProviderServiceShape { | ... | @@ -99,16 +99,6 @@ export interface ProviderServiceShape { |
| 99 | readonly numTurns: number; | 99 | readonly numTurns: number; |
| 100 | }) => Effect.Effect<void, ProviderServiceError>; | 100 | }) => Effect.Effect<void, ProviderServiceError>; |
| 101 | 101 | ||
| 102 | /** | ||
| 103 | * Stop all active provider sessions. | ||
| 104 | * | ||
| 105 | * Persisted session bindings remain so stale sessions can be resumed after | ||
| 106 | * process restart. | ||
| 107 | * | ||
| 108 | * Runtime alias mappings are cleared as part of shutdown. | ||
| 109 | */ | ||
| 110 | readonly stopAll: () => Effect.Effect<void, ProviderServiceError>; | ||
| 111 | |||
| 112 | /** | 102 | /** |
| 113 | * Canonical provider runtime event stream. | 103 | * Canonical provider runtime event stream. |
| 114 | * | 104 | * |
apps/server/src/serverLogger.ts+3-6| ... | @@ -1,18 +1,15 @@ | ... | @@ -1,18 +1,15 @@ |
| 1 | import fs from "node:fs"; | 1 | import fs from "node:fs"; |
| 2 | import path from "node:path"; | 2 | import path from "node:path"; |
| 3 | 3 | ||
| 4 | import { Effect, Logger, Option } from "effect"; | 4 | import { Effect, Logger } from "effect"; |
| 5 | import * as Layer from "effect/Layer"; | 5 | import * as Layer from "effect/Layer"; |
| 6 | 6 | ||
| 7 | import { ServerConfig } from "./config"; | 7 | import { ServerConfig } from "./config"; |
| 8 | 8 | ||
| 9 | export const ServerLoggerLive = Effect.gen(function* () { | 9 | export const ServerLoggerLive = Effect.gen(function* () { |
| 10 | const config = yield* Effect.serviceOption(ServerConfig); | 10 | const config = yield* ServerConfig; |
| 11 | if (Option.isNone(config)) { | ||
| 12 | return Logger.layer([Logger.defaultLogger]); | ||
| 13 | } | ||
| 14 | 11 | ||
| 15 | const logDir = path.join(config.value.stateDir, "logs"); | 12 | const logDir = path.join(config.stateDir, "logs"); |
| 16 | const logPath = path.join(logDir, "server.log"); | 13 | const logPath = path.join(logDir, "server.log"); |
| 17 | 14 | ||
| 18 | yield* Effect.sync(() => { | 15 | yield* Effect.sync(() => { |
apps/server/src/wsServer.test.ts-1| ... | @@ -1171,7 +1171,6 @@ describe("WebSocket Server", () => { | ... | @@ -1171,7 +1171,6 @@ describe("WebSocket Server", () => { |
| 1171 | listSessions: () => Effect.succeed([]), | 1171 | listSessions: () => Effect.succeed([]), |
| 1172 | getCapabilities: () => Effect.succeed({ sessionModelSwitch: "in-session" }), | 1172 | getCapabilities: () => Effect.succeed({ sessionModelSwitch: "in-session" }), |
| 1173 | rollbackConversation: () => unsupported(), | 1173 | rollbackConversation: () => unsupported(), |
| 1174 | stopAll: () => Effect.void, | ||
| 1175 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), | 1174 | streamEvents: Stream.fromPubSub(runtimeEventPubSub), |
| 1176 | }; | 1175 | }; |
| 1177 | const providerLayer = Layer.succeed(ProviderService, providerService); | 1176 | const providerLayer = Layer.succeed(ProviderService, providerService); |
apps/server/src/wsServer.ts-6| ... | @@ -568,7 +568,6 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< | ... | @@ -568,7 +568,6 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< |
| 568 | const orchestrationEngine = yield* OrchestrationEngineService; | 568 | const orchestrationEngine = yield* OrchestrationEngineService; |
| 569 | const projectionReadModelQuery = yield* ProjectionSnapshotQuery; | 569 | const projectionReadModelQuery = yield* ProjectionSnapshotQuery; |
| 570 | const checkpointDiffQuery = yield* CheckpointDiffQuery; | 570 | const checkpointDiffQuery = yield* CheckpointDiffQuery; |
| 571 | const liveProviderService = yield* ProviderService; | ||
| 572 | const orchestrationReactor = yield* OrchestrationReactor; | 571 | const orchestrationReactor = yield* OrchestrationReactor; |
| 573 | const { openInEditor } = yield* Open; | 572 | const { openInEditor } = yield* Open; |
| 574 | 573 | ||
| ... | @@ -660,11 +659,6 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< | ... | @@ -660,11 +659,6 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< |
| 660 | } | 659 | } |
| 661 | 660 | ||
| 662 | const runPromise = yield* Effect.map(Effect.services<never>(), Effect.runPromiseWith); | 661 | const runPromise = yield* Effect.map(Effect.services<never>(), Effect.runPromiseWith); |
| 663 | yield* Effect.addFinalizer(() => | ||
| 664 | Effect.catch(liveProviderService.stopAll(), (cause) => | ||
| 665 | Effect.logWarning("failed to stop provider service", { cause }), | ||
| 666 | ), | ||
| 667 | ); | ||
| 668 | 662 | ||
| 669 | const unsubscribeTerminalEvents = yield* terminalManager.subscribe( | 663 | const unsubscribeTerminalEvents = yield* terminalManager.subscribe( |
| 670 | (event) => void Effect.runPromise(onTerminalEvent(event)), | 664 | (event) => void Effect.runPromise(onTerminalEvent(event)), |
apps/web/public/apple-touch-icon.png| Binary files a/apps/web/public/apple-touch-icon.png and b/apps/web/public/apple-touch-icon.png differ | |||
apps/web/public/favicon-16x16.png| Binary files a/apps/web/public/favicon-16x16.png and b/apps/web/public/favicon-16x16.png differ | |||
apps/web/public/favicon-32x32.png| Binary files a/apps/web/public/favicon-32x32.png and b/apps/web/public/favicon-32x32.png differ | |||
apps/web/public/favicon.ico| Binary files a/apps/web/public/favicon.ico and b/apps/web/public/favicon.ico differ | |||
apps/web/public/favicon.svg deleted-4| ... | @@ -1,4 +0,0 @@ | ||
| 1 | <svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | <path d="M0 10C0 4.47715 4.47715 0 10 0H118C123.523 0 128 4.47715 128 10V118C128 123.523 123.523 128 118 128H10C4.47715 128 0 123.523 0 118V10Z" fill="black"/> | ||
| 3 | <path d="M33.4509 93V47.56H15.5309V37H64.3309V47.56H46.4109V93H33.4509ZM86.7253 93.96C82.832 93.96 78.9653 93.4533 75.1253 92.44C71.2853 91.3733 68.032 89.88 65.3653 87.96L70.4053 78.04C72.5386 79.5867 75.0186 80.8133 77.8453 81.72C80.672 82.6267 83.5253 83.08 86.4053 83.08C89.6586 83.08 92.2186 82.44 94.0853 81.16C95.952 79.88 96.8853 78.12 96.8853 75.88C96.8853 73.7467 96.0586 72.0667 94.4053 70.84C92.752 69.6133 90.0853 69 86.4053 69H80.4853V60.44L96.0853 42.76L97.5253 47.4H68.1653V37H107.365V45.4L91.8453 63.08L85.2853 59.32H89.0453C95.9253 59.32 101.125 60.8667 104.645 63.96C108.165 67.0533 109.925 71.0267 109.925 75.88C109.925 79.0267 109.099 81.9867 107.445 84.76C105.792 87.48 103.259 89.6933 99.8453 91.4C96.432 93.1067 92.0586 93.96 86.7253 93.96Z" fill="white"/> | ||
| 4 | </svg> | ||
assets/T3 Code blueprint-macOS-Default-1024x1024@1x.png deleted| Binary files a/assets/T3 Code blueprint-macOS-Default-1024x1024@1x.png and /dev/null differ | |||
assets/T3 Code blueprint-macOS-Default-1024x1024@2x.png deleted| Binary files a/assets/T3 Code blueprint-macOS-Default-1024x1024@2x.png and /dev/null differ | |||
assets/T3 Code logo.svg	 deleted-4| ... | @@ -1,4 +0,0 @@ | ||
| 1 | <svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | <path d="M0 10C0 4.47715 4.47715 0 10 0H118C123.523 0 128 4.47715 128 10V118C128 123.523 123.523 128 118 128H10C4.47715 128 0 123.523 0 118V10Z" fill="black"/> | ||
| 3 | <path d="M33.4509 93V47.56H15.5309V37H64.3309V47.56H46.4109V93H33.4509ZM86.7253 93.96C82.832 93.96 78.9653 93.4533 75.1253 92.44C71.2853 91.3733 68.032 89.88 65.3653 87.96L70.4053 78.04C72.5386 79.5867 75.0186 80.8133 77.8453 81.72C80.672 82.6267 83.5253 83.08 86.4053 83.08C89.6586 83.08 92.2186 82.44 94.0853 81.16C95.952 79.88 96.8853 78.12 96.8853 75.88C96.8853 73.7467 96.0586 72.0667 94.4053 70.84C92.752 69.6133 90.0853 69 86.4053 69H80.4853V60.44L96.0853 42.76L97.5253 47.4H68.1653V37H107.365V45.4L91.8453 63.08L85.2853 59.32H89.0453C95.9253 59.32 101.125 60.8667 104.645 63.96C108.165 67.0533 109.925 71.0267 109.925 75.88C109.925 79.0267 109.099 81.9867 107.445 84.76C105.792 87.48 103.259 89.6933 99.8453 91.4C96.432 93.1067 92.0586 93.96 86.7253 93.96Z" fill="white"/> | ||
| 4 | </svg> | ||
assets/T3 Code logo@16x.png deleted| Binary files a/assets/T3 Code logo@16x.png and /dev/null differ | |||
assets/T3 Code logo@32x.png deleted| Binary files a/assets/T3 Code logo@32x.png and /dev/null differ | |||
assets/T3 Code logo@8x.png deleted| Binary files a/assets/T3 Code logo@8x.png and /dev/null differ | |||
assets/T3 Code-macOS-Default-1024x1024@1x.png deleted| Binary files a/assets/T3 Code-macOS-Default-1024x1024@1x.png and /dev/null differ | |||
assets/T3 Code-macOS-Default-1024x1024@4x.png deleted| Binary files a/assets/T3 Code-macOS-Default-1024x1024@4x.png and /dev/null differ | |||
assets/dev/blueprint-ios-1024.png created| Binary files /dev/null and b/assets/dev/blueprint-ios-1024.png differ | |||
assets/dev/blueprint-macos-1024.png created| Binary files /dev/null and b/assets/dev/blueprint-macos-1024.png differ | |||
assets/dev/blueprint-universal-1024.png created| Binary files /dev/null and b/assets/dev/blueprint-universal-1024.png differ | |||
assets/dev/blueprint-web-apple-touch-180.png created| Binary files /dev/null and b/assets/dev/blueprint-web-apple-touch-180.png differ | |||
assets/dev/blueprint-web-favicon-16x16.png created| Binary files /dev/null and b/assets/dev/blueprint-web-favicon-16x16.png differ | |||
assets/dev/blueprint-web-favicon-32x32.png created| Binary files /dev/null and b/assets/dev/blueprint-web-favicon-32x32.png differ | |||
assets/dev/blueprint-web-favicon.ico created| Binary files /dev/null and b/assets/dev/blueprint-web-favicon.ico differ | |||
assets/dev/blueprint-windows.ico created| Binary files /dev/null and b/assets/dev/blueprint-windows.ico differ | |||
assets/logo-1024.png deleted| Binary files a/assets/logo-1024.png and /dev/null differ | |||
assets/logo.svg deleted-4| ... | @@ -1,4 +0,0 @@ | ||
| 1 | <svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | <path d="M0 10C0 4.47715 4.47715 0 10 0H118C123.523 0 128 4.47715 128 10V118C128 123.523 123.523 128 118 128H10C4.47715 128 0 123.523 0 118V10Z" fill="black"/> | ||
| 3 | <path d="M33.4509 93V47.56H15.5309V37H64.3309V47.56H46.4109V93H33.4509ZM86.7253 93.96C82.832 93.96 78.9653 93.4533 75.1253 92.44C71.2853 91.3733 68.032 89.88 65.3653 87.96L70.4053 78.04C72.5386 79.5867 75.0186 80.8133 77.8453 81.72C80.672 82.6267 83.5253 83.08 86.4053 83.08C89.6586 83.08 92.2186 82.44 94.0853 81.16C95.952 79.88 96.8853 78.12 96.8853 75.88C96.8853 73.7467 96.0586 72.0667 94.4053 70.84C92.752 69.6133 90.0853 69 86.4053 69H80.4853V60.44L96.0853 42.76L97.5253 47.4H68.1653V37H107.365V45.4L91.8453 63.08L85.2853 59.32H89.0453C95.9253 59.32 101.125 60.8667 104.645 63.96C108.165 67.0533 109.925 71.0267 109.925 75.88C109.925 79.0267 109.099 81.9867 107.445 84.76C105.792 87.48 103.259 89.6933 99.8453 91.4C96.432 93.1067 92.0586 93.96 86.7253 93.96Z" fill="white"/> | ||
| 4 | </svg> | ||
assets/macos-icon-1024.png deleted| Binary files a/assets/macos-icon-1024.png and /dev/null differ | |||
assets/prod/black-ios-1024.png created| Binary files /dev/null and b/assets/prod/black-ios-1024.png differ | |||
assets/prod/black-macos-1024.png created| Binary files /dev/null and b/assets/prod/black-macos-1024.png differ | |||
assets/prod/black-universal-1024.png created| Binary files /dev/null and b/assets/prod/black-universal-1024.png differ | |||
assets/prod/logo.svg created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | <svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | <path d="M0 10C0 4.47715 4.47715 0 10 0H118C123.523 0 128 4.47715 128 10V118C128 123.523 123.523 128 118 128H10C4.47715 128 0 123.523 0 118V10Z" fill="black"/> | ||
| 3 | <path d="M33.4509 93V47.56H15.5309V37H64.3309V47.56H46.4109V93H33.4509ZM86.7253 93.96C82.832 93.96 78.9653 93.4533 75.1253 92.44C71.2853 91.3733 68.032 89.88 65.3653 87.96L70.4053 78.04C72.5386 79.5867 75.0186 80.8133 77.8453 81.72C80.672 82.6267 83.5253 83.08 86.4053 83.08C89.6586 83.08 92.2186 82.44 94.0853 81.16C95.952 79.88 96.8853 78.12 96.8853 75.88C96.8853 73.7467 96.0586 72.0667 94.4053 70.84C92.752 69.6133 90.0853 69 86.4053 69H80.4853V60.44L96.0853 42.76L97.5253 47.4H68.1653V37H107.365V45.4L91.8453 63.08L85.2853 59.32H89.0453C95.9253 59.32 101.125 60.8667 104.645 63.96C108.165 67.0533 109.925 71.0267 109.925 75.88C109.925 79.0267 109.099 81.9867 107.445 84.76C105.792 87.48 103.259 89.6933 99.8453 91.4C96.432 93.1067 92.0586 93.96 86.7253 93.96Z" fill="white"/> | ||
| 4 | </svg> | ||
assets/prod/t3-black-web-apple-touch-180.png created| Binary files /dev/null and b/assets/prod/t3-black-web-apple-touch-180.png differ | |||
assets/prod/t3-black-web-favicon-16x16.png created| Binary files /dev/null and b/assets/prod/t3-black-web-favicon-16x16.png differ | |||
assets/prod/t3-black-web-favicon-32x32.png created| Binary files /dev/null and b/assets/prod/t3-black-web-favicon-32x32.png differ | |||
assets/prod/t3-black-web-favicon.ico created| Binary files /dev/null and b/assets/prod/t3-black-web-favicon.ico differ | |||
assets/prod/t3-black-windows.ico created| Binary files /dev/null and b/assets/prod/t3-black-windows.ico differ | |||
scripts/build-desktop-artifact.ts+93-18| ... | @@ -1,11 +1,14 @@ | ... | @@ -1,11 +1,14 @@ |
| 1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
| 2 | 2 | ||
| 3 | import { spawnSync } from "node:child_process"; | 3 | import { spawnSync } from "node:child_process"; |
| 4 | import { existsSync } from "node:fs"; | ||
| 5 | import { join } from "node:path"; | ||
| 4 | 6 | ||
| 5 | import rootPackageJson from "../package.json" with { type: "json" }; | 7 | import rootPackageJson from "../package.json" with { type: "json" }; |
| 6 | import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" }; | 8 | import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" }; |
| 7 | import serverPackageJson from "../apps/server/package.json" with { type: "json" }; | 9 | import serverPackageJson from "../apps/server/package.json" with { type: "json" }; |
| 8 | 10 | ||
| 11 | import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts"; | ||
| 9 | import { resolveCatalogDependencies } from "./lib/resolve-catalog.ts"; | 12 | import { resolveCatalogDependencies } from "./lib/resolve-catalog.ts"; |
| 10 | 13 | ||
| 11 | import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; | 14 | import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; |
| ... | @@ -20,8 +23,18 @@ const BuildArch = Schema.Literals(["arm64", "x64", "universal"]); | ... | @@ -20,8 +23,18 @@ const BuildArch = Schema.Literals(["arm64", "x64", "universal"]); |
| 20 | const RepoRoot = Effect.service(Path.Path).pipe( | 23 | const RepoRoot = Effect.service(Path.Path).pipe( |
| 21 | Effect.flatMap((path) => path.fromFileUrl(new URL("..", import.meta.url))), | 24 | Effect.flatMap((path) => path.fromFileUrl(new URL("..", import.meta.url))), |
| 22 | ); | 25 | ); |
| 23 | const IconSource = Effect.zipWith(RepoRoot, Effect.service(Path.Path), (repoRoot, path) => | 26 | const ProductionMacIconSource = Effect.zipWith(RepoRoot, Effect.service(Path.Path), (repoRoot, path) => |
| 24 | path.join(repoRoot, "assets/macos-icon-1024.png"), | 27 | path.join(repoRoot, BRAND_ASSET_PATHS.productionMacIconPng), |
| 28 | ); | ||
| 29 | const ProductionLinuxIconSource = Effect.zipWith( | ||
| 30 | RepoRoot, | ||
| 31 | Effect.service(Path.Path), | ||
| 32 | (repoRoot, path) => path.join(repoRoot, BRAND_ASSET_PATHS.productionLinuxIconPng), | ||
| 33 | ); | ||
| 34 | const ProductionWindowsIconSource = Effect.zipWith( | ||
| 35 | RepoRoot, | ||
| 36 | Effect.service(Path.Path), | ||
| 37 | (repoRoot, path) => path.join(repoRoot, BRAND_ASSET_PATHS.productionWindowsIconIco), | ||
| 25 | ); | 38 | ); |
| 26 | const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString); | 39 | const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString); |
| 27 | 40 | ||
| ... | @@ -104,6 +117,39 @@ function resolveGitCommitHash(repoRoot: string): string { | ... | @@ -104,6 +117,39 @@ function resolveGitCommitHash(repoRoot: string): string { |
| 104 | return hash.toLowerCase(); | 117 | return hash.toLowerCase(); |
| 105 | } | 118 | } |
| 106 | 119 | ||
| 120 | function resolvePythonForNodeGyp(): string | undefined { | ||
| 121 | const configured = process.env.npm_config_python ?? process.env.PYTHON; | ||
| 122 | if (configured && existsSync(configured)) { | ||
| 123 | return configured; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (process.platform === "win32") { | ||
| 127 | const localAppData = process.env.LOCALAPPDATA; | ||
| 128 | if (localAppData) { | ||
| 129 | for (const version of ["Python313", "Python312", "Python311", "Python310"]) { | ||
| 130 | const candidate = join(localAppData, "Programs", "Python", version, "python.exe"); | ||
| 131 | if (existsSync(candidate)) { | ||
| 132 | return candidate; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | const probe = spawnSync("python", ["-c", "import sys;print(sys.executable)"], { | ||
| 139 | encoding: "utf8", | ||
| 140 | }); | ||
| 141 | if (probe.status !== 0) { | ||
| 142 | return undefined; | ||
| 143 | } | ||
| 144 | |||
| 145 | const executable = probe.stdout.trim(); | ||
| 146 | if (!executable || !existsSync(executable)) { | ||
| 147 | return undefined; | ||
| 148 | } | ||
| 149 | |||
| 150 | return executable; | ||
| 151 | } | ||
| 152 | |||
| 107 | interface ResolvedBuildOptions { | 153 | interface ResolvedBuildOptions { |
| 108 | readonly platform: typeof BuildPlatform.Type; | 154 | readonly platform: typeof BuildPlatform.Type; |
| 109 | readonly target: string; | 155 | readonly target: string; |
| ... | @@ -261,7 +307,7 @@ function stageMacIcons(stageResourcesDir: string, verbose: boolean) { | ... | @@ -261,7 +307,7 @@ function stageMacIcons(stageResourcesDir: string, verbose: boolean) { |
| 261 | return Effect.gen(function* () { | 307 | return Effect.gen(function* () { |
| 262 | const fs = yield* FileSystem.FileSystem; | 308 | const fs = yield* FileSystem.FileSystem; |
| 263 | const path = yield* Path.Path; | 309 | const path = yield* Path.Path; |
| 264 | const iconSource = yield* IconSource; | 310 | const iconSource = yield* ProductionMacIconSource; |
| 265 | if (!(yield* fs.exists(iconSource))) { | 311 | if (!(yield* fs.exists(iconSource))) { |
| 266 | return yield* new BuildScriptError({ | 312 | return yield* new BuildScriptError({ |
| 267 | message: `Production icon source is missing at ${iconSource}`, | 313 | message: `Production icon source is missing at ${iconSource}`, |
| ... | @@ -285,6 +331,38 @@ function stageMacIcons(stageResourcesDir: string, verbose: boolean) { | ... | @@ -285,6 +331,38 @@ function stageMacIcons(stageResourcesDir: string, verbose: boolean) { |
| 285 | }); | 331 | }); |
| 286 | } | 332 | } |
| 287 | 333 | ||
| 334 | function stageLinuxIcons(stageResourcesDir: string) { | ||
| 335 | return Effect.gen(function* () { | ||
| 336 | const fs = yield* FileSystem.FileSystem; | ||
| 337 | const path = yield* Path.Path; | ||
| 338 | const iconSource = yield* ProductionLinuxIconSource; | ||
| 339 | if (!(yield* fs.exists(iconSource))) { | ||
| 340 | return yield* new BuildScriptError({ | ||
| 341 | message: `Production icon source is missing at ${iconSource}`, | ||
| 342 | }); | ||
| 343 | } | ||
| 344 | |||
| 345 | const iconPath = path.join(stageResourcesDir, "icon.png"); | ||
| 346 | yield* fs.copyFile(iconSource, iconPath); | ||
| 347 | }); | ||
| 348 | } | ||
| 349 | |||
| 350 | function stageWindowsIcons(stageResourcesDir: string) { | ||
| 351 | return Effect.gen(function* () { | ||
| 352 | const fs = yield* FileSystem.FileSystem; | ||
| 353 | const path = yield* Path.Path; | ||
| 354 | const iconSource = yield* ProductionWindowsIconSource; | ||
| 355 | if (!(yield* fs.exists(iconSource))) { | ||
| 356 | return yield* new BuildScriptError({ | ||
| 357 | message: `Production Windows icon source is missing at ${iconSource}`, | ||
| 358 | }); | ||
| 359 | } | ||
| 360 | |||
| 361 | const iconPath = path.join(stageResourcesDir, "icon.ico"); | ||
| 362 | yield* fs.copyFile(iconSource, iconPath); | ||
| 363 | }); | ||
| 364 | } | ||
| 365 | |||
| 288 | function validateBundledClientAssets(clientDir: string) { | 366 | function validateBundledClientAssets(clientDir: string) { |
| 289 | return Effect.gen(function* () { | 367 | return Effect.gen(function* () { |
| 290 | const fs = yield* FileSystem.FileSystem; | 368 | const fs = yield* FileSystem.FileSystem; |
| ... | @@ -416,31 +494,18 @@ const assertPlatformBuildResources = Effect.fn("assertPlatformBuildResources")(f | ... | @@ -416,31 +494,18 @@ const assertPlatformBuildResources = Effect.fn("assertPlatformBuildResources")(f |
| 416 | stageResourcesDir: string, | 494 | stageResourcesDir: string, |
| 417 | verbose: boolean, | 495 | verbose: boolean, |
| 418 | ) { | 496 | ) { |
| 419 | const fs = yield* FileSystem.FileSystem; | ||
| 420 | const path = yield* Path.Path; | ||
| 421 | |||
| 422 | if (platform === "mac") { | 497 | if (platform === "mac") { |
| 423 | yield* stageMacIcons(stageResourcesDir, verbose); | 498 | yield* stageMacIcons(stageResourcesDir, verbose); |
| 424 | return; | 499 | return; |
| 425 | } | 500 | } |
| 426 | 501 | ||
| 427 | if (platform === "linux") { | 502 | if (platform === "linux") { |
| 428 | const iconPath = path.join(stageResourcesDir, "icon.png"); | 503 | yield* stageLinuxIcons(stageResourcesDir); |
| 429 | if (!(yield* fs.exists(iconPath))) { | ||
| 430 | return yield* new BuildScriptError({ | ||
| 431 | message: `Missing Linux icon at ${iconPath}`, | ||
| 432 | }); | ||
| 433 | } | ||
| 434 | return; | 504 | return; |
| 435 | } | 505 | } |
| 436 | 506 | ||
| 437 | if (platform === "win") { | 507 | if (platform === "win") { |
| 438 | const iconPath = path.join(stageResourcesDir, "icon.ico"); | 508 | yield* stageWindowsIcons(stageResourcesDir); |
| 439 | if (!(yield* fs.exists(iconPath))) { | ||
| 440 | return yield* new BuildScriptError({ | ||
| 441 | message: `Missing Windows icon at ${iconPath}`, | ||
| 442 | }); | ||
| 443 | } | ||
| 444 | } | 509 | } |
| 445 | }); | 510 | }); |
| 446 | 511 | ||
| ... | @@ -597,6 +662,16 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( | ... | @@ -597,6 +662,16 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( |
| 597 | delete buildEnv.APPLE_API_ISSUER; | 662 | delete buildEnv.APPLE_API_ISSUER; |
| 598 | } | 663 | } |
| 599 | 664 | ||
| 665 | if (process.platform === "win32") { | ||
| 666 | const python = resolvePythonForNodeGyp(); | ||
| 667 | if (python) { | ||
| 668 | buildEnv.PYTHON = python; | ||
| 669 | buildEnv.npm_config_python = python; | ||
| 670 | } | ||
| 671 | buildEnv.npm_config_msvs_version = buildEnv.npm_config_msvs_version ?? "2022"; | ||
| 672 | buildEnv.GYP_MSVS_VERSION = buildEnv.GYP_MSVS_VERSION ?? "2022"; | ||
| 673 | } | ||
| 674 | |||
| 600 | yield* Effect.log( | 675 | yield* Effect.log( |
| 601 | `[desktop-artifact] Building ${options.platform}/${options.target} (arch=${options.arch}, version=${appVersion})...`, | 676 | `[desktop-artifact] Building ${options.platform}/${options.target} (arch=${options.arch}, version=${appVersion})...`, |
| 602 | ); | 677 | ); |
scripts/lib/brand-assets.ts created+57| ... | @@ -0,0 +1,57 @@ | ||
| 1 | export const BRAND_ASSET_PATHS = { | ||
| 2 | productionMacIconPng: "assets/prod/black-macos-1024.png", | ||
| 3 | productionLinuxIconPng: "assets/prod/black-universal-1024.png", | ||
| 4 | productionWindowsIconIco: "assets/prod/t3-black-windows.ico", | ||
| 5 | productionWebFaviconIco: "assets/prod/t3-black-web-favicon.ico", | ||
| 6 | productionWebFavicon16Png: "assets/prod/t3-black-web-favicon-16x16.png", | ||
| 7 | productionWebFavicon32Png: "assets/prod/t3-black-web-favicon-32x32.png", | ||
| 8 | productionWebAppleTouchIconPng: "assets/prod/t3-black-web-apple-touch-180.png", | ||
| 9 | developmentWindowsIconIco: "assets/dev/blueprint-windows.ico", | ||
| 10 | developmentWebFaviconIco: "assets/dev/blueprint-web-favicon.ico", | ||
| 11 | developmentWebFavicon16Png: "assets/dev/blueprint-web-favicon-16x16.png", | ||
| 12 | developmentWebFavicon32Png: "assets/dev/blueprint-web-favicon-32x32.png", | ||
| 13 | developmentWebAppleTouchIconPng: "assets/dev/blueprint-web-apple-touch-180.png", | ||
| 14 | } as const; | ||
| 15 | |||
| 16 | export interface IconOverride { | ||
| 17 | readonly sourceRelativePath: string; | ||
| 18 | readonly targetRelativePath: string; | ||
| 19 | } | ||
| 20 | |||
| 21 | export const DEVELOPMENT_ICON_OVERRIDES: ReadonlyArray<IconOverride> = [ | ||
| 22 | { | ||
| 23 | sourceRelativePath: BRAND_ASSET_PATHS.developmentWebFaviconIco, | ||
| 24 | targetRelativePath: "dist/client/favicon.ico", | ||
| 25 | }, | ||
| 26 | { | ||
| 27 | sourceRelativePath: BRAND_ASSET_PATHS.developmentWebFavicon16Png, | ||
| 28 | targetRelativePath: "dist/client/favicon-16x16.png", | ||
| 29 | }, | ||
| 30 | { | ||
| 31 | sourceRelativePath: BRAND_ASSET_PATHS.developmentWebFavicon32Png, | ||
| 32 | targetRelativePath: "dist/client/favicon-32x32.png", | ||
| 33 | }, | ||
| 34 | { | ||
| 35 | sourceRelativePath: BRAND_ASSET_PATHS.developmentWebAppleTouchIconPng, | ||
| 36 | targetRelativePath: "dist/client/apple-touch-icon.png", | ||
| 37 | }, | ||
| 38 | ]; | ||
| 39 | |||
| 40 | export const PUBLISH_ICON_OVERRIDES: ReadonlyArray<IconOverride> = [ | ||
| 41 | { | ||
| 42 | sourceRelativePath: BRAND_ASSET_PATHS.productionWebFaviconIco, | ||
| 43 | targetRelativePath: "dist/client/favicon.ico", | ||
| 44 | }, | ||
| 45 | { | ||
| 46 | sourceRelativePath: BRAND_ASSET_PATHS.productionWebFavicon16Png, | ||
| 47 | targetRelativePath: "dist/client/favicon-16x16.png", | ||
| 48 | }, | ||
| 49 | { | ||
| 50 | sourceRelativePath: BRAND_ASSET_PATHS.productionWebFavicon32Png, | ||
| 51 | targetRelativePath: "dist/client/favicon-32x32.png", | ||
| 52 | }, | ||
| 53 | { | ||
| 54 | sourceRelativePath: BRAND_ASSET_PATHS.productionWebAppleTouchIconPng, | ||
| 55 | targetRelativePath: "dist/client/apple-touch-icon.png", | ||
| 56 | }, | ||
| 57 | ]; | ||