NAME

Developer::Dashboard::CLI::Ticket - private tmux ticket helper for Developer Dashboard

SYNOPSIS

use Developer::Dashboard::CLI::Ticket qw(run_ticket_command);
run_ticket_command( args => \@ARGV );

DESCRIPTION

Provides the shared implementation behind the private ticket helper staged under ~/.developer-dashboard/cli/dd/ so dashboard ticket can stay part of the dashboard toolchain without installing a public top-level executable.

PURPOSE

This module owns the workspace-session runtime behind dashboard workspace. It resolves the requested workspace reference, builds the tmux environment, decides whether the session already exists, creates the session when needed, and attaches the terminal to the chosen workspace session. Logical dotted names are mapped to tmux's underscore-normalized names because tmux parses a period as a session/window target separator. Existing tagged sessions are checked against WORKSPACE_REF to avoid reusing a name collision for another workspace. If concurrent callers race to create the same session, a duplicate-session response is accepted only after a second tmux query confirms the session exists. With -d or --docker plus -c or -C and a registered path alias, it instead starts or reuses the Compose workspace service, adds the alias as /workspace inside the container, and invokes the same workspace helper there. Lowercase -c does not build a stopped service; uppercase -C requests a cached build with progress streamed to the terminal.

WHY IT EXISTS

It exists because ticket-session behavior needs to stay deterministic and testable. Keeping session naming, environment variables, create-vs-attach decisions, and tmux error handling in one module prevents wrappers and prompt helpers from inventing different rules.

WHEN TO USE

Use this file when changing how dashboard ticket chooses the ticket name, what tmux environment variables it seeds, or how create/attach failures are reported back to the user. Use the Docker workspace option when the alias is mounted at /workspace in a Compose service named workspace and the interactive tmux session should run inside that container; use uppercase -C when a stopped service must be built and the live build progress shown.

HOW TO USE

Call run_ticket_command from the staged helper, passing the raw argv list. With an explicit ticket argument, that becomes both the tmux session name and the seeded TICKET_REF/B/OB environment set. Without an explicit argument, the module falls back to $ENV{TICKET_REF} when present. If the session does not exist it creates a detached Code1 window in the current working directory before attaching; if the session already exists it skips creation and attaches directly. Dotted workspace references use underscores in the tmux session name while their original dotted value remains in WORKSPACE_REF. If a normalized name is tagged for another workspace, the command reports the collision instead of attaching to that unrelated session. If another caller creates the session between the initial check and create request, it rechecks the named session and attaches only after confirming the duplicate exists; unrelated create errors remain visible.

The -c option may appear before or after the workspace name. It resolves configured path aliases first, then skill-qualified methods from each installed skill's lib/Folder.pm through the shared validated d2 paths/cdr loader. Dotted nested-skill names are supported at arbitrary installed depth, for example parent.child.work. The session and its layered environment refresh both start in the resolved directory. If no alias resolves, -c fails with an explicit error. If another command creates the session between the initial existence check and the create request, the helper rechecks the exact name and attaches only when that session is confirmed; other create errors remain visible.

For dashboard workspace -c <alias> --docker (or the short -d form), the module changes into the resolved host directory and checks whether the Compose workspace service is already running. A stopped service starts without building by default, including when the configured image is missing:

d2 docker compose up -d --no-build workspace

Use uppercase -C to explicitly build a stopped service:

d2 workspace foobar -d -C
d2 docker compose up -d --build workspace

Build output streams directly to the terminal. An already-running service is reused even with -C, so in-container work is not interrupted. After the service is ready, both forms run these commands in order through the public Docker Compose helper:

d2 docker compose exec -e DEVELOPER_DASHBOARD_CONFIG_OVERLAY=/dev/shm/developer-dashboard-workspace-config workspace d2 path add <alias> /workspace
d2 docker compose exec -it -e DEVELOPER_DASHBOARD_CONFIG_OVERLAY=/dev/shm/developer-dashboard-workspace-config -e TMUX_TMPDIR=/dev/shm workspace d2 workspace <alias> -c

The private config overlay under the container's /dev/shm tmpfs keeps the container path mapping away from bind-mounted host config and temporary directories. It is an additive config layer, so existing container settings remain available while this alias override takes precedence. The host alias continues to point at its original path (for example, /tmp/foobar); only the container-side alias resolves to /workspace. Both in-container commands use the same overlay so the workspace command can see the alias just registered.

The final Compose exec also sets TMUX_TMPDIR=/dev/shm and LC_CTYPE=C.UTF-8 for the inner workspace process. The socket setting makes the container use its writable tmpfs location even when the installed in-container command does not yet include the automatic unwritable-/tmp fallback. The UTF-8 character locale lets the attached tmux client render the non-ASCII prompt and status icons without overriding the user's broader LANG formatting preferences; a POSIX character locale can render those characters as underscores. Newly started servers inherit the locale too; reattaching through d2 workspace passes it to clients even when reusing an existing server. Tmux creates its per-user socket directory under /dev/shm; later clients use the same socket and locale settings. The outer workspace command must come from an installation containing this handoff; an older installed d2 that predates the fix will not pass these settings.

The command stops immediately if the service fails to start or either in-container command fails. Startup errors ask the user to configure a Compose service named workspace; no alias registration or inner workspace command is attempted after a failed start. -d without -c or -C, -C without Docker mode, and Docker mode with a raw absolute path instead of a registered alias are rejected. Without Docker mode the existing local tmux behavior is unchanged. The final Compose exec allocates a TTY and directly inherits the caller's input/output so tmux can attach interactively. Before tmux commands run, the helper honors TMUX_TMPDIR; if it is unset and /tmp is not writable, /dev/shm is selected for the server socket. Later workspace commands make the same selection, allowing them to reconnect to that container-local tmux server. A writable /tmp keeps tmux's default socket directory.

WHAT USES IT

It is used by the dashboard ticket helper, by prompt/bootstrap flows that want consistent ticket-session environment variables, and by regression tests that verify explicit ticket selection, environment fallback, and tmux create/attach error handling.

EXAMPLES

dashboard ticket DD-123
dashboard ticket
TICKET_REF=DD-123 dashboard ticket
dashboard ticket feature-branch-42
dashboard workspace parent.child.work -c
dashboard workspace -c foobar --docker
dashboard workspace foobar -c -d
dashboard workspace foobar -d -C
perl -Ilib -MDeveloper::Dashboard::CLI::Ticket=list_sessions -e 'print join qq(\n), list_sessions()'