Repository navigation
cmux NEXT: New Cloud Space, a space that is one Cloud machine #27810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat-cmux-next
Are you sure you want to change the base?
Changes from all commits
3e95edb
c14447c
eefffde
6512ca0
5aa55b4
0e379d2
d7126ed
65dbcf4
7eb1ca8
bf39da2
64d4b88
5d39eb0
27b2e57
a5a5f98
3f3693f
c79ce70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -152,17 +152,26 @@ extension AppActions { | |
| let target: String? = show || !hasOpenWindow ? windows.targetWindow(preferring: sourceID ?? sourceWindow?.state.id) : nil | ||
| // `machine` (App machine id; the CLI's `--session`): born on that | ||
| // session's daemon (plans/cmux-next/data-model.md 1.3). | ||
| let daemon = (invocation["machine"]?.targetValue?.id ?? invocation["machine"]?.stringValue).flatMap(services.machines.daemon(machine:)) | ||
| if invocation["machine"] != nil, daemon?.connection == nil { | ||
| let asked = (invocation["machine"]?.targetValue?.id ?? invocation["machine"]?.stringValue).flatMap(services.machines.daemon(machine:)) | ||
| // With none asked for, a person's create (or one naming a space) goes where the space creates; a script's | ||
| // stays on this Mac, so a `cmux new-workspace` never wakes a paused Cloud machine of the space shown. | ||
| let daemon = asked ?? (invocation.origin == .user || spawn.profile != nil ? nil : services.daemon) | ||
| // A named machine that does not resolve (unknown, or Cloud off) is refused, never made on this Mac instead. | ||
| if invocation["machine"] != nil, asked?.connection == nil { | ||
| services.registry.track(Task { ActionWorkFailure(WorkspaceVerbStrings.machineNotConnected) }) | ||
| return | ||
| } | ||
| // With no machine asked for, the create goes where the space creates (a Cloud space's machine), so the page | ||
| // decision and the key hold below are that daemon's. | ||
| let spaceDaemon = windows.spaceCreation(spawn, into: target).daemon ?? services.daemon | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: For an unresolved space, Prompt for AI agents |
||
| // A person's Cmd-N onto the New Tab page in the window they type in: every key from this | ||
| // moment waits for the new page's field, in order (cx-kql5h), not for the workspace to show. | ||
| let input = services.keyRouter.newTabInputCoordinator | ||
| let opensPage = show && hasOpenWindow && spawn.opensNewTabPage && spawn.command == nil && spawn.firstChat == nil | ||
| && spawn.firstSession == nil && services.agentTabs.opensFirstPage(on: daemon ?? services.daemon) | ||
| let keys = opensPage && target == sourceWindow?.state.id ? input.beginIncoming(in: sourceWindow?.window) : nil | ||
| && spawn.firstSession == nil && services.agentTabs.opensFirstPage(on: daemon ?? spaceDaemon) | ||
| // A Cloud space's machine still waking would hold the keys for its whole resume: only a connected one holds them. | ||
| let keys = opensPage && target == sourceWindow?.state.id && (daemon ?? spaceDaemon).connection != nil | ||
| ? input.beginIncoming(in: sourceWindow?.window) : nil | ||
| spawn.inputToken = keys | ||
| // In this turn: the row, and for Cmd-N's page the workspace itself, show before any daemon reply. | ||
| let create = BenchSpans.measure("cmdN.start") { windows.startWorkspace(spawn, on: daemon, into: target) } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,4 @@ | ||||||||||
| import CmuxNextActions | ||||||||||
| import CmuxNextCloud | ||||||||||
| import CmuxNextCloudCredentials | ||||||||||
| import CmuxNextDaemon | ||||||||||
|
|
@@ -539,3 +540,23 @@ final class CloudMachineSession { | |||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| extension CloudMachineSession { | ||||||||||
| /// Wakes this machine for a Cloud space (a paused machine resumes, an ended link connects) and returns once its | ||||||||||
| /// daemon is connected. A failed resume ends the wait at once with its reason; the bound is `CloudMove`'s. | ||||||||||
| func connectedForSpace() async throws { | ||||||||||
| // A machine the person disconnected stays so until they connect it (its menu's Connect): no wait for it. | ||||||||||
| if disconnected { throw ActionFailure(message: CloudStrings.notConnected) } | ||||||||||
| // A failure left from an earlier attempt must not end this wait before this attempt's own resume runs. | ||||||||||
| resumeFailure = nil | ||||||||||
| if daemon.connection == nil { | ||||||||||
| await refreshIfMaybePaused() | ||||||||||
| if machine.status == .paused { attach(origin: .user) } else { connect(origin: .user) } | ||||||||||
| } | ||||||||||
| let daemon = daemon | ||||||||||
| guard await CloudMove.holds(within: .seconds(180), until: { [weak self] in | ||||||||||
| self?.resumeFailure != nil || daemon.connection != nil | ||||||||||
| }) else { throw DaemonError.notConnected } | ||||||||||
|
Comment on lines
+558
to
+559
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: A disconnect during this wait leaves Prompt for AI agents
Suggested change
|
||||||||||
| if let failure = resumeFailure { throw ActionFailure(message: failure) } | ||||||||||
| } | ||||||||||
| } | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: This adds
space.newCloudtocliNamed, which changes the CLI surface, butplans/cmux-next/action-surfaces.jsonwas not regenerated. The export check inActionSurfaceParityTests.exportIsFreshwill fail in CI with "action-surfaces.json is stale". Regenerate withCMUX_UPDATE_ACTION_SURFACES=1 swift test --filter ActionSurfaceParityTests, and refreshweb/data/next-docs/cli-reference.generated.jsonas well if the docs generator requires it.Prompt for AI agents