Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .agents/upstream-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Historical groups are indexed in the linked archive. This file migration changes
| Live activity motion parity / `6c583620ff7ad3235b135af7107c0543467eecfa` | Corrects Pylon's rendering of already-classified `c7c1dfe4df` (#9709), `ce4712d5b0` (#9799) and the #444 port of `6cf0c6ea55` (#9093) / `c3b8825bf4` (#9606) | Pylon had diverged: `cdde7f3150` gave every active row the sweeping overlay and deleted `live-tool-shine`, while upstream reserves the overlay for label-only rows (`active && shimmer`, passed only by the Thinking row) and keeps the shine for tool labels. Restores upstream's `shimmer` prop, `animated = active && !failed` guard, row-level observer ref, overlay on worktree setup and compaction, and both CSS utilities byte-identical to upstream. That same commit also deleted `@utility visible-animate-spin` as dead while `spinner.tsx` and `refresh-icon.tsx` still applied it, so every spinner and refresh glyph was static; restored. Preserved: Pylon's `workingStepLabel`, and the `document.hasFocus()` gate AGENTS.md requires and upstream lacks. Cursor unchanged. | [Live activity parity #452](https://github.com/pylon-code/pylon/pull/452); 161 focused tests, web typecheck, scoped lint/format, region diffed against `t3code-upstream/main`. |
| Skeleton loading pulse / `6c583620ff7ad3235b135af7107c0543467eecfa` | `21b9dda5afb00a33e228a68d2ccc885bba7285dc` (#9448) | Adopted. The shared `Skeleton` drops its swept gradient band for upstream's single stepped opacity pulse, whose keyframes were already byte-identical to the `ghost-pulse` Pylon ran on the pull-request ghosts; `ghost-pulse` is retired and every loading state now uses `animate-skeleton`. Preserve Pylon's `!seed` gate on the detail ghost, so a panel already showing real content does not breathe, and Pylon's own usage fill-in timing. The maintainer chose upstream theming and styling with only the logo staying Pylon's, which settles this kind of visual divergence in upstream's favour by default. Cursor unchanged. | [Skeleton pulse #451](https://github.com/pylon-code/pylon/pull/451); 339 focused tests, web typecheck, scoped lint/format. |
| Panel links, markdown galleries, shared title model, usage columns, sidebar file drops, terminal link overrides, Codex limit naming and turn token telemetry / `6c583620ff7ad3235b135af7107c0543467eecfa` | Full ten-source list in PR #458, from #9132 through #10060 | Nine adopted; `b5d89038ae72142038dfa8cf69d49b7a607fe98e` is already covered as an empty duplicate of #7892. Turn telemetry stays inert without a Pylon PostHog key, is recorded only after runtime generation and session incarnation fences, and treats Prime, Cursor, Grok and Antigravity usage as unavailable; OpenCode uses the final #10116 step-retention design. Codex limit errors carry the session incarnation and Pylon keeps relaying every rate-limit notification. Preserve Pylon PR detection, environment-scoped PR caches, provider-instance settings writes, hub account keys, older-server window names, change-request row props and terminal external-browser fallback. New product analytics and usage data docs. Cursor unchanged. | [Web panels #458](https://github.com/pylon-code/pylon/pull/458); 1,687 focused tests, six package typechecks (web, server, shared, client-runtime, contracts, mobile), scoped lint/format; upstream UI evidence linked, no local client pass. |
| Mobile Android: provider setup removal, Material You, Keychain group, Android notifications / `6c583620ff7ad3235b135af7107c0543467eecfa` | Full ten-source list in #456, from #9721 through #10416 | Adopted #9721 (mobile Antigravity setup from the #440 port removed; Pylon's Prime host maintenance status kept), #3665 (team via `$(AppIdentifierPrefix)`), #10691, #10692, #10859 and #10416 (FCM relay delivery, Android ongoing activity, `/v2/client/devices`, additive relay migration). #10598 and #10620 already covered: Pylon's exporter fixed launcher cropping and its splash mark fits the Android 12+ mask; T3 background artwork layers left to the maintainer. Two version bumps skipped. Adaptations: Pylon EAS OTA gate, package IDs, signed-bundle Keychain group, relay hourly cron, Effect `TaggedErrorClass`; notification switches need Firebase config and a registered push token; Hermes cookie assertion belongs to #10851. Firebase/FCM not provisioned; rollback needs a forward fix. Cursor unchanged. | [Mobile Android #456](https://github.com/pylon-code/pylon/pull/456); 258 focused tests, five package typechecks, scoped lint/format, generated-theme and icon checks. |

## Deferred register

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-relay.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ jobs:
AXIOM_TOKEN: ${{ secrets.AXIOM_TOKEN }}
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
APNS_PRIVATE_KEY: ${{ secrets.APNS_PRIVATE_KEY }}
FCM_SERVICE_ACCOUNT: ${{ secrets.FCM_SERVICE_ACCOUNT }}

- name: Publish relay deploy commit status
uses: actions/github-script@v8
Expand Down
39 changes: 30 additions & 9 deletions apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ const appleTeamId = repoEnv.PYLON_APPLE_TEAM_ID?.trim() || repoEnv.APPLE_TEAM_ID
const easProjectId = repoEnv.PYLON_EAS_PROJECT_ID?.trim() ?? "";
const easOwner = repoEnv.PYLON_EAS_OWNER?.trim() ?? "";

// Firebase config for Android push. Pylon ships none by default; builds without
// it still work but cannot receive agent notifications.
const androidGoogleServicesFile = repoEnv.T3CODE_ANDROID_GOOGLE_SERVICES_FILE?.trim() ?? "";

const VARIANT_CONFIG = {
development: {
appName: "Pylon Dev",
Expand Down Expand Up @@ -212,15 +216,17 @@ const config: ExpoConfig = {
userInterfaceStyle: "automatic",
// Over-the-air updates follow the configured EAS project. Off until one is
// set: an update URL is a remote code channel, and inheriting T3's would let
// their bundles run inside Pylon.
updates: easProjectId
? {
enabled: true,
url: `https://u.expo.dev/${easProjectId}`,
checkAutomatically: "ON_LOAD",
fallbackToCacheTimeout: 0,
}
: { enabled: false },
// their bundles run inside Pylon. `T3CODE_MOBILE_UPDATES_ENABLED=0` also turns
// them off for a private binary built against a configured project.
updates:
easProjectId && repoEnv.T3CODE_MOBILE_UPDATES_ENABLED !== "0"
? {
enabled: true,
url: `https://u.expo.dev/${easProjectId}`,
checkAutomatically: "ON_LOAD",
fallbackToCacheTimeout: 0,
}
: { enabled: false },
ios: {
icon: variant.assets.iosIcon,
supportsTablet: true,
Expand All @@ -243,6 +249,13 @@ const config: ExpoConfig = {
],
}
: {}),
// SecureStore keeps connection credentials in the Keychain. The group is the
// bundle ID this build actually signs with, including a personal-team
// override, and `$(AppIdentifierPrefix)` resolves to the signing team at
// build time, so no team ID is pinned here.
entitlements: {
"keychain-access-groups": [`$(AppIdentifierPrefix)${iosBundleIdentifier}`],
},
infoPlist: {
NSAppTransportSecurity: {
NSAllowsArbitraryLoads: true,
Expand Down Expand Up @@ -271,6 +284,7 @@ const config: ExpoConfig = {
android: {
icon: variant.assets.appIcon,
package: variant.androidPackage,
...(androidGoogleServicesFile ? { googleServicesFile: androidGoogleServicesFile } : {}),
adaptiveIcon: {
backgroundColor: variant.assets.androidAdaptiveBackgroundColor,
foregroundImage: variant.assets.androidAdaptiveForeground,
Expand Down Expand Up @@ -375,6 +389,10 @@ const config: ExpoConfig = {
[
"expo-build-properties",
{
android: {
// Keep the supported floor explicit and covered by native notification tests.
minSdkVersion: 24,
},
ios: {
deploymentTarget: "18.0",
// AppCheckCore 11.3+ includes Swift and needs module maps for these Objective-C dependencies.
Expand Down Expand Up @@ -404,6 +422,9 @@ const config: ExpoConfig = {
extra: {
appVariant: APP_VARIANT,
iosPersonalTeamBuild: isIosPersonalTeamBuild,
// Without Firebase config the app never gets an FCM token, so Settings must
// not offer Android notifications it cannot deliver.
androidPushConfigured: androidGoogleServicesFile.length > 0,
relay: {
url: repoEnv.T3CODE_RELAY_URL ?? null,
},
Expand Down
14 changes: 14 additions & 0 deletions apps/mobile/generated-uniwind-default-theme-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
"--color-card": "#ffffff",
"--color-card-alt": "#f5f5f5",
"--color-card-translucent": "rgba(255, 255, 255, 0.8)",
"--color-thread-canvas": "#f5f5f5",
"--color-thread-selected": "#ffffff",
"--color-thread-selected-foreground": "#262626",
"--color-thread-selected-foreground-muted": "#737373",
"--color-composer-panel": "rgba(245, 245, 245, 0.88)",
"--color-composer-surface": "rgba(255, 255, 255, 0.94)",
"--color-composer-border": "rgba(0, 0, 0, 0.1)",
"--color-foreground": "#262626",
"--color-foreground-secondary": "#525252",
"--color-foreground-muted": "#737373",
Expand Down Expand Up @@ -76,6 +83,13 @@
"--color-card": "#171717",
"--color-card-alt": "#1c1c1c",
"--color-card-translucent": "rgba(17, 17, 17, 0.8)",
"--color-thread-canvas": "#1c1c1c",
"--color-thread-selected": "#171717",
"--color-thread-selected-foreground": "#f5f5f5",
"--color-thread-selected-foreground-muted": "#8e8e93",
"--color-composer-panel": "rgba(28, 28, 28, 0.92)",
"--color-composer-surface": "rgba(23, 23, 23, 0.9)",
"--color-composer-border": "rgba(255, 255, 255, 0.08)",
"--color-foreground": "#f5f5f5",
"--color-foreground-secondary": "#a3a3a3",
"--color-foreground-muted": "#8e8e93",
Expand Down
70 changes: 70 additions & 0 deletions apps/mobile/generated-uniwind-themes.css
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@
--color-card: #fdfafd;
--color-card-alt: #faf3fb;
--color-card-translucent: rgba(253, 250, 253, 0.8);
--color-thread-canvas: #faf3fb;
--color-thread-selected: #fdfafd;
--color-thread-selected-foreground: #501854;
--color-thread-selected-foreground-muted: #ac1668;
--color-composer-panel: rgba(250, 243, 251, 0.88);
--color-composer-surface: rgba(253, 250, 253, 0.94);
--color-composer-border: rgba(238, 225, 237, 0.54);
--color-foreground: #501854;
--color-foreground-secondary: #ac1668;
--color-foreground-muted: #8d1255;
Expand Down Expand Up @@ -283,6 +290,13 @@
--color-card: #2c2631;
--color-card-alt: #29232d;
--color-card-translucent: rgba(44, 38, 49, 0.8);
--color-thread-canvas: #29232d;
--color-thread-selected: #2c2631;
--color-thread-selected-foreground: #f9f8fb;
--color-thread-selected-foreground-muted: #e7d0dd;
--color-composer-panel: rgba(41, 35, 45, 0.92);
--color-composer-surface: rgba(44, 38, 49, 0.9);
--color-composer-border: rgba(39, 36, 44, 0.46);
--color-foreground: #f9f8fb;
--color-foreground-secondary: #e7d0dd;
--color-foreground-muted: #e7d0dd;
Expand Down Expand Up @@ -420,6 +434,13 @@
--color-card: #ecefed;
--color-card-alt: #f3f7f4;
--color-card-translucent: rgba(236, 239, 237, 0.8);
--color-thread-canvas: #f3f7f4;
--color-thread-selected: #ecefed;
--color-thread-selected-foreground: #241523;
--color-thread-selected-foreground-muted: #746c73;
--color-composer-panel: rgba(243, 247, 244, 0.88);
--color-composer-surface: rgba(236, 239, 237, 0.94);
--color-composer-border: rgba(203, 213, 209, 0.54);
--color-foreground: #241523;
--color-foreground-secondary: #746c73;
--color-foreground-muted: #6e696f;
Expand Down Expand Up @@ -557,6 +578,13 @@
--color-card: #36413c;
--color-card-alt: #1b2821;
--color-card-translucent: rgba(54, 65, 60, 0.8);
--color-thread-canvas: #1b2821;
--color-thread-selected: #36413c;
--color-thread-selected-foreground: #fffaff;
--color-thread-selected-foreground-muted: #919595;
--color-composer-panel: rgba(27, 40, 33, 0.92);
--color-composer-surface: rgba(54, 65, 60, 0.9);
--color-composer-border: rgba(65, 95, 79, 0.46);
--color-foreground: #fffaff;
--color-foreground-secondary: #919595;
--color-foreground-muted: #9da5a2;
Expand Down Expand Up @@ -694,6 +722,13 @@
--color-card: #edeff1;
--color-card-alt: #f5f7f8;
--color-card-translucent: rgba(237, 239, 241, 0.8);
--color-thread-canvas: #f5f7f8;
--color-thread-selected: #edeff1;
--color-thread-selected-foreground: #241523;
--color-thread-selected-foreground-muted: #746c75;
--color-composer-panel: rgba(245, 247, 248, 0.88);
--color-composer-surface: rgba(237, 239, 241, 0.94);
--color-composer-border: rgba(205, 212, 220, 0.54);
--color-foreground: #241523;
--color-foreground-secondary: #746c75;
--color-foreground-muted: #6f6873;
Expand Down Expand Up @@ -831,6 +866,13 @@
--color-card: #333b45;
--color-card-alt: #17212b;
--color-card-translucent: rgba(51, 59, 69, 0.8);
--color-thread-canvas: #17212b;
--color-thread-selected: #333b45;
--color-thread-selected-foreground: #fffaff;
--color-thread-selected-foreground-muted: #8d8f97;
--color-composer-panel: rgba(23, 33, 43, 0.92);
--color-composer-surface: rgba(51, 59, 69, 0.9);
--color-composer-border: rgba(64, 85, 103, 0.46);
--color-foreground: #fffaff;
--color-foreground-secondary: #8d8f97;
--color-foreground-muted: #969ca6;
Expand Down Expand Up @@ -968,6 +1010,13 @@
--color-card: #f1efee;
--color-card-alt: #f9f7f5;
--color-card-translucent: rgba(241, 239, 238, 0.8);
--color-thread-canvas: #f9f7f5;
--color-thread-selected: #f1efee;
--color-thread-selected-foreground: #241523;
--color-thread-selected-foreground-muted: #766c74;
--color-composer-panel: rgba(249, 247, 245, 0.88);
--color-composer-surface: rgba(241, 239, 238, 0.94);
--color-composer-border: rgba(221, 210, 206, 0.54);
--color-foreground: #241523;
--color-foreground-secondary: #766c74;
--color-foreground-muted: #74686f;
Expand Down Expand Up @@ -1105,6 +1154,13 @@
--color-card: #433835;
--color-card-alt: #291e1a;
--color-card-translucent: rgba(67, 56, 53, 0.8);
--color-thread-canvas: #291e1a;
--color-thread-selected: #433835;
--color-thread-selected-foreground: #fffaff;
--color-thread-selected-foreground-muted: #968e8f;
--color-composer-panel: rgba(41, 30, 26, 0.92);
--color-composer-surface: rgba(67, 56, 53, 0.9);
--color-composer-border: rgba(102, 76, 63, 0.46);
--color-foreground: #fffaff;
--color-foreground-secondary: #968e8f;
--color-foreground-muted: #a59996;
Expand Down Expand Up @@ -1242,6 +1298,13 @@
--color-card: #f0eff2;
--color-card-alt: #f8f7f9;
--color-card-translucent: rgba(240, 239, 242, 0.8);
--color-thread-canvas: #f8f7f9;
--color-thread-selected: #f0eff2;
--color-thread-selected-foreground: #241523;
--color-thread-selected-foreground-muted: #766c76;
--color-composer-panel: rgba(248, 247, 249, 0.88);
--color-composer-surface: rgba(240, 239, 242, 0.94);
--color-composer-border: rgba(214, 209, 222, 0.54);
--color-foreground: #241523;
--color-foreground-secondary: #766c76;
--color-foreground-muted: #726874;
Expand Down Expand Up @@ -1379,6 +1442,13 @@
--color-card: #383443;
--color-card-alt: #1d1929;
--color-card-translucent: rgba(56, 52, 67, 0.8);
--color-thread-canvas: #1d1929;
--color-thread-selected: #383443;
--color-thread-selected-foreground: #fffaff;
--color-thread-selected-foreground-muted: #8e8a95;
--color-composer-panel: rgba(29, 25, 41, 0.92);
--color-composer-surface: rgba(56, 52, 67, 0.9);
--color-composer-border: rgba(77, 67, 102, 0.46);
--color-foreground: #fffaff;
--color-foreground-secondary: #8e8a95;
--color-foreground-muted: #9690a1;
Expand Down
14 changes: 14 additions & 0 deletions apps/mobile/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
--color-card: #ffffff;
--color-card-alt: #f5f5f5;
--color-card-translucent: rgba(255, 255, 255, 0.8);
--color-thread-canvas: #f5f5f5;
--color-thread-selected: #ffffff;
--color-thread-selected-foreground: #262626;
--color-thread-selected-foreground-muted: #737373;
--color-composer-panel: rgba(245, 245, 245, 0.88);
--color-composer-surface: rgba(255, 255, 255, 0.94);
--color-composer-border: rgba(0, 0, 0, 0.1);

/* Text */
--color-foreground: #262626;
Expand Down Expand Up @@ -123,6 +130,13 @@
--color-card: #171717;
--color-card-alt: #1c1c1c;
--color-card-translucent: rgba(17, 17, 17, 0.8);
--color-thread-canvas: #1c1c1c;
--color-thread-selected: #171717;
--color-thread-selected-foreground: #f5f5f5;
--color-thread-selected-foreground-muted: #8e8e93;
--color-composer-panel: rgba(28, 28, 28, 0.92);
--color-composer-surface: rgba(23, 23, 23, 0.9);
--color-composer-border: rgba(255, 255, 255, 0.08);

/* Text */
--color-foreground: #f5f5f5;
Expand Down
34 changes: 34 additions & 0 deletions apps/mobile/modules/t3-agent-notifications/android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
plugins {
id 'com.android.library'
id 'expo-module-gradle-plugin'
}

group = 'com.t3tools.agentnotifications'
version = '0.0.0'

android {
namespace 'expo.modules.t3agentnotifications'
defaultConfig {
versionCode 1
versionName '0.0.0'
}
testOptions {
unitTests.includeAndroidResources = true
}
}

dependencies {
implementation project(':expo-notifications')
implementation 'com.google.firebase:firebase-messaging:25.0.1'
implementation 'androidx.core:core:1.17.0'
implementation 'androidx.lifecycle:lifecycle-process:2.9.3'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.16.1'
}

// Expo compiles modules with Java 17; Robolectric's Android 16 runtime needs 21.
tasks.withType(Test).configureEach {
javaLauncher = javaToolchains.launcherFor {
languageVersion = JavaLanguageVersion.of(21)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.POST_PROMOTED_NOTIFICATIONS" />
<application>
<service android:name="expo.modules.notifications.service.ExpoFirebaseMessagingService" tools:node="remove" />
<service android:name=".AgentMessagingService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver android:name=".AgentActivityDismissReceiver" android:exported="false" />
<receiver android:name=".AgentActivityExpiryReceiver" android:exported="false" />
</application>
</manifest>
Loading
Loading