diff --git a/internal/common/task_utils.go b/internal/common/task_utils.go index 1542912..c6733c4 100644 --- a/internal/common/task_utils.go +++ b/internal/common/task_utils.go @@ -65,6 +65,21 @@ func AugmentArgsForTask(task *types.Task, args []string, opts TaskAugmentOptions args = append(args, "--harness", harness) } } + + // Pass public session-sharing if configured. This is additive to the + // collaborator-oriented --share args already set by the worker launcher + // (team:edit). The bundled Warp client applies an anyone-with-link ACL + // after the session bootstraps; the workspace-level + // AnyoneWithLinkSharingEnabled setting still gates whether the ACL + // write succeeds. FULL is rejected at the public API layer, so we only + // expect VIEWER or EDITOR here and silently skip unsupported values + // as a defensive fallback. + if task.AgentConfigSnapshot.SessionSharing != nil && + task.AgentConfigSnapshot.SessionSharing.PublicAccess != nil { + if level := shareAccessLevelForEmission(*task.AgentConfigSnapshot.SessionSharing.PublicAccess); level != "" { + args = append(args, "--share", fmt.Sprintf("public:%s", level)) + } + } } if task.AgentConfigSnapshot != nil && task.AgentConfigSnapshot.EnvironmentID != nil { @@ -86,6 +101,21 @@ func AugmentArgsForTask(task *types.Task, args []string, opts TaskAugmentOptions return args } +// shareAccessLevelForEmission maps an internal AccessLevel to the string +// accepted by the CLI's --share flag. Returns empty string for values that +// the CLI cannot represent (e.g. FULL), in which case the caller should +// omit the emission entirely. +func shareAccessLevelForEmission(access types.AccessLevel) string { + switch access { + case types.AccessLevelViewer: + return "view" + case types.AccessLevelEditor: + return "edit" + default: + return "" + } +} + func resolveIdleOnComplete(task *types.Task, opts TaskAugmentOptions) (string, bool) { if task != nil && task.AgentConfigSnapshot != nil && diff --git a/internal/common/task_utils_test.go b/internal/common/task_utils_test.go index 1e47bef..36b548d 100644 --- a/internal/common/task_utils_test.go +++ b/internal/common/task_utils_test.go @@ -7,8 +7,9 @@ import ( "github.com/warpdotdev/oz-agent-worker/internal/types" ) -func strPtr(v string) *string { return &v } -func intPtr(v int) *int { return &v } +func strPtr(v string) *string { return &v } +func intPtr(v int) *int { return &v } +func accessPtr(v types.AccessLevel) *types.AccessLevel { return &v } func TestAugmentArgsForTask_IdleOnCompletePrecedence(t *testing.T) { baseArgs := []string{"agent", "run"} @@ -86,6 +87,60 @@ func TestAugmentArgsForTask_IdleOnCompletePrecedence(t *testing.T) { opts: TaskAugmentOptions{}, expected: []string{"agent", "run", "--model", "claude-sonnet-4", "--idle-on-complete", "12m"}, }, + { + name: "adds --share public:view when session_sharing.public_access is VIEWER", + task: &types.Task{ + AgentConfigSnapshot: &types.AmbientAgentConfig{ + SessionSharing: &types.SessionSharingConfig{ + PublicAccess: accessPtr(types.AccessLevelViewer), + }, + }, + }, + opts: TaskAugmentOptions{}, + expected: []string{"agent", "run", "--share", "public:view", "--idle-on-complete"}, + }, + { + name: "adds --share public:edit when session_sharing.public_access is EDITOR", + task: &types.Task{ + AgentConfigSnapshot: &types.AmbientAgentConfig{ + SessionSharing: &types.SessionSharingConfig{ + PublicAccess: accessPtr(types.AccessLevelEditor), + }, + }, + }, + opts: TaskAugmentOptions{}, + expected: []string{"agent", "run", "--share", "public:edit", "--idle-on-complete"}, + }, + { + name: "skips --share public when session_sharing is absent", + task: &types.Task{ + AgentConfigSnapshot: &types.AmbientAgentConfig{}, + }, + opts: TaskAugmentOptions{}, + expected: []string{"agent", "run", "--idle-on-complete"}, + }, + { + name: "skips --share public when public_access is nil", + task: &types.Task{ + AgentConfigSnapshot: &types.AmbientAgentConfig{ + SessionSharing: &types.SessionSharingConfig{}, + }, + }, + opts: TaskAugmentOptions{}, + expected: []string{"agent", "run", "--idle-on-complete"}, + }, + { + name: "silently omits --share public for unsupported access levels (defensive: FULL rejected earlier)", + task: &types.Task{ + AgentConfigSnapshot: &types.AmbientAgentConfig{ + SessionSharing: &types.SessionSharingConfig{ + PublicAccess: accessPtr(types.AccessLevel("FULL")), + }, + }, + }, + opts: TaskAugmentOptions{}, + expected: []string{"agent", "run", "--idle-on-complete"}, + }, } for _, tt := range tests { diff --git a/internal/types/messages.go b/internal/types/messages.go index 3763e05..d131378 100644 --- a/internal/types/messages.go +++ b/internal/types/messages.go @@ -78,6 +78,24 @@ type HarnessAuthSecrets struct { ClaudeAuthSecretName *string `json:"claude_auth_secret_name,omitempty"` } +// AccessLevel is the serialized access-level string used inside SessionSharingConfig. +// Values mirror warp-server's model/types/enums.AccessLevel JSON representation. +type AccessLevel string + +const ( + AccessLevelViewer AccessLevel = "VIEWER" + AccessLevelEditor AccessLevel = "EDITOR" +) + +// SessionSharingConfig mirrors warp-server's sources.SessionSharingConfig and +// carries the session-sharing choices snapshotted onto the run. +type SessionSharingConfig struct { + // PublicAccess, when set, causes the worker to emit --share public: + // so the bundled Warp client applies an anyone-with-link ACL after the + // shared session bootstraps. + PublicAccess *AccessLevel `json:"public_access,omitempty"` +} + // AmbientAgentConfig represents the agent configuration. type AmbientAgentConfig struct { EnvironmentID *string `json:"environment_id,omitempty"` @@ -90,6 +108,7 @@ type AmbientAgentConfig struct { IdleTimeoutMinutes *int `json:"idle_timeout_minutes,omitempty"` Harness *Harness `json:"harness,omitempty"` HarnessAuthSecrets *HarnessAuthSecrets `json:"harness_auth_secrets,omitempty"` + SessionSharing *SessionSharingConfig `json:"session_sharing,omitempty"` } // Task represents an ambient agent job.