Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3255151
fix: stabilize macOS portable startup integration
WilliamWang1721 Sep 21, 2026
b95b36e
merge: resolve PR #128 against latest main
WilliamWang1721 Sep 23, 2026
ec0b411
Merge branch 'main' into codex/macos-portable-startup
WilliamWang1721 Sep 24, 2026
6c108de
ci(ui): capture Windows and macOS review screenshots for PR #128
WilliamWang1721 Sep 25, 2026
f649d65
ci(ui): fix native screenshot capture checks
WilliamWang1721 Sep 25, 2026
7a0cc2f
ci(ui): publish reviewer screenshots outside PR diff
WilliamWang1721 Sep 25, 2026
6b62611
ci(ui): polish screenshots before PR presentation
WilliamWang1721 Sep 25, 2026
e2b8d98
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 26, 2026
64d3e64
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 26, 2026
218b9d9
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 26, 2026
08511f6
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 27, 2026
8868af3
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 28, 2026
eb47088
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 28, 2026
ee07703
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 28, 2026
298f6a4
fix(macos): address portable startup review findings
WilliamWang1721 Sep 28, 2026
ad1a31e
fix(i18n): add portable startup messages
WilliamWang1721 Sep 28, 2026
4eb91ca
Merge remote-tracking branch 'origin/main' into codex/pr128-review
WilliamWang1721 Sep 28, 2026
b2ed8fc
Merge remote-tracking branch 'origin/main' into codex/pr128-review
WilliamWang1721 Sep 28, 2026
be37fa7
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Sep 30, 2026
4465bd6
fix(portable): preserve current locale catalog
WilliamWang1721 Sep 30, 2026
2668d94
fix(macos): preserve current startup and application entry points
WilliamWang1721 Sep 30, 2026
99898d1
Merge latest upstream main for strict PR validation
WilliamWang1721 Sep 30, 2026
d4d453c
fix(macos): keep startup alert from preempting GPUI application initi…
WilliamWang1721 Sep 30, 2026
0ed8ca1
Merge latest upstream main while preserving portable startup fixes
WilliamWang1721 Sep 30, 2026
cf55c0d
Merge current upstream mobile changes without expanding feature scope
WilliamWang1721 Sep 30, 2026
c99efb4
Merge upstream 2.1.0 and theme improvements while retaining verified …
WilliamWang1721 Sep 30, 2026
5fa3815
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Oct 1, 2026
871e16f
Merge current upstream main, preserving reviewed desktop feature beha…
WilliamWang1721 Oct 1, 2026
9659e8f
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Oct 1, 2026
1c6bba3
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Oct 1, 2026
85471af
fix(macOS): update lockfile for CoreFoundation dependency
WilliamWang1721 Oct 1, 2026
8a04b2b
Merge upstream main into codex/macos-portable-startup
WilliamWang1721 Oct 1, 2026
b4fe8af
Merge upstream main into PR #128
WilliamWang1721 Oct 1, 2026
31ebcdf
Merge upstream main into PR #128
WilliamWang1721 Oct 1, 2026
7b10bf5
Merge upstream main into PR #128
WilliamWang1721 Oct 3, 2026
e47de5a
Merge upstream main into PR #128
WilliamWang1721 Oct 3, 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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# macOS portable startup storage

## Status

Implemented; pending review and native dialog acceptance.

## Context

Moving Pebrel.app alone leaves settings on the host. Storage must be selected before migration, logging, path caches or workers start.

## Evidence

The existing shared settings directory controls configuration, sessions and history. A macOS application bundle supplies a stable location from which to derive a sibling data directory after a move. The startup adapter and its focused tests document the current behavior.

Native acceptance on head `99898d1` clicked the startup choices and created the marker, then the application panicked before publishing its runtime endpoint. RFD 0.17.2's synchronous dialog creates the shared NSApplication in its policy manager; GPUI requires its own application subclass and platform ivar when its event loop starts.

## Decision

A macOS bundle outside `/Applications`, `/System/Applications` and `~/Applications` offers portable, normal or quit. Explicit configuration and unbundled executables retain their existing behavior. Portable mode stores data in sibling `Pebrel Data`, remembers acceptance with `.pebrel-portable`, and sets both configuration directory aliases plus `TMPDIR` before workers start. CLI helpers use an existing portable store without a prompt. Portable startup skips host legacy migration. A linked or unwritable data root stops portable startup. An eligible translocated bundle without an explicit override stops before any launch choice rather than falling back to host settings.

Startup uses the same Core Foundation native alert directly, without initializing AppKit. The existing transitive `objc2-core-foundation` dependency becomes an explicit macOS dependency for its typed bindings; no additional library or version is introduced.

## Rejected alternatives

- A new container format would change every persistence consumer.
- Writing inside the signed bundle would make data depend on application replacement.
- Persisting an absolute data path would break when the app and data move together.
- Initializing the GPUI platform before storage selection would start workers before process-wide configuration overrides are set.

## Consequences

Users move Pebrel.app and `Pebrel Data` together after quitting. Existing preferences can be imported using Backup. System credentials, SSH keys, external tools, project files and OS caches remain outside the portable directory; live processes and absolute paths in user configuration do not migrate. Windows and Linux startup remain unchanged.

## Validation

Focused tests cover bundle location, relaunch, folder moves, unavailable or redirected storage, and localized choices. Native compilation and actual dialog interaction require separate evidence.

## Supersedes

None.

## Revisit when

Another platform needs portable storage or automatic profile migration has an explicit compatibility contract and native verification.
1 change: 1 addition & 0 deletions nebula_app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ png = { version = "0.17.5", default-features = false, optional = true }
[target.'cfg(target_os = "macos")'.dependencies]
security-framework = "=3.7.0"
objc2 = "0.6.1"
objc2-core-foundation = { version = "0.3.1", default-features = false, features = ["std", "CFString", "CFUserNotification"] }
objc2-foundation = { version = "0.3.1", default-features = false, features = [
"std",
"NSString",
Expand Down
13 changes: 13 additions & 0 deletions nebula_app/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,19 @@
"relay_invalid": "Invalid configuration. Import connection details exported by pebrel-relay, or complete the address, room, tokens and fingerprint.",
"relay_read_failed": "Reading did not complete. Check the SSH connection and that pebrel-relay is installed."
},
"startup": {
"portable": {
"title": "Portable mode",
"description": "Pebrel is outside Applications. Store its data beside the app in {path}?",
"enable": "Use portable mode",
"normal": "Use normal mode",
"quit": "Quit",
"translocated": "Pebrel is running from a temporary macOS location. Move the app to a trusted folder and reopen it.",
"write_failed": "Could not use the portable data folder {path}: {error}",
"linked_directory": "The portable data folder or its temporary folder is a symbolic link.",
"error_title": "Pebrel could not start"
}
},
"theme": {
"package": {
"entry": "Theme package",
Expand Down
13 changes: 13 additions & 0 deletions nebula_app/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,19 @@
"relay_invalid": "配置格式有误。请导入 pebrel-relay 导出的连接信息,或补全地址、房间号、令牌和指纹。",
"relay_read_failed": "读取未完成。请检查 SSH 主机连接,以及服务器是否已安装 pebrel-relay。"
},
"startup": {
"portable": {
"title": "便携模式",
"description": "Pebrel 位于“应用程序”文件夹之外。是否将数据保存在应用旁的 {path}?",
"enable": "使用便携模式",
"normal": "使用普通模式",
"quit": "退出",
"translocated": "Pebrel 正在从 macOS 临时转译位置运行。请将应用移到可信文件夹后重新打开。",
"write_failed": "无法使用便携数据文件夹 {path}:{error}",
"linked_directory": "便携数据文件夹或其临时文件夹是符号链接。",
"error_title": "Pebrel 无法启动"
}
},
"theme": {
"package": {
"entry": "主题包",
Expand Down
21 changes: 18 additions & 3 deletions nebula_app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,24 @@ fn main() -> Result<(), Box<dyn Error>> {

// Load command line options.
let options = Options::new();
if let Err(error) = nebula_settings::migrate_legacy_data() {
platform::startup::report_error(&error, options.subcommands.is_none());
return Err(error.into());
let startup = platform::startup::prepare_data(&options).and_then(|launch| {
use platform::startup::Launch;
match launch {
Launch::Installed => nebula_settings::migrate_legacy_data().map(|_| true),
Launch::Portable => Ok(true),
Launch::Quit => Ok(false),
}
});
match startup {
Ok(true) => {},
Ok(false) => return Ok(()),
Err(error) => {
platform::startup::report_error(
&error,
options.subcommands.is_none() && !options.daemon,
);
return Err(error.into());
},
}
#[cfg(windows)]
panic::attach_handler();
Expand Down
Loading
Loading