diff --git a/scripts/agent-branch-start.sh b/scripts/agent-branch-start.sh index 5a81f1e..0860726 100755 --- a/scripts/agent-branch-start.sh +++ b/scripts/agent-branch-start.sh @@ -105,6 +105,68 @@ sanitize_slug() { printf '%s' "$slug" } +sanitize_optional_slug() { + local raw="$1" + local fallback="${2:-snapshot}" + if [[ -z "$raw" ]]; then + printf '' + return 0 + fi + sanitize_slug "$raw" "$fallback" +} + +normalize_positive_int() { + local raw="$1" + local fallback="$2" + if [[ "$raw" =~ ^[0-9]+$ ]] && [[ "$raw" -gt 0 ]]; then + printf '%s' "$raw" + return 0 + fi + printf '%s' "$fallback" +} + +shorten_slug() { + local slug="$1" + local raw_max="$2" + local max_len + max_len="$(normalize_positive_int "$raw_max" "32")" + if [[ "${#slug}" -le "$max_len" ]]; then + printf '%s' "$slug" + return 0 + fi + local shortened="${slug:0:max_len}" + shortened="$(printf '%s' "$shortened" | sed -E 's/-+$//')" + if [[ -z "$shortened" ]]; then + shortened="${slug:0:max_len}" + fi + printf '%s' "$shortened" +} + +checksum_slug_suffix() { + local raw="$1" + local checksum + checksum="$(printf '%s' "$raw" | cksum | awk '{print $1}')" + printf '%s' "${checksum:0:6}" +} + +compose_branch_descriptor() { + local snapshot_slug="$1" + local task_slug="$2" + local snapshot_max task_max task_part snapshot_part checksum_input checksum_part + snapshot_max="$(normalize_positive_int "${MUSAFETY_BRANCH_SNAPSHOT_SLUG_MAX:-18}" "18")" + task_max="$(normalize_positive_int "${MUSAFETY_BRANCH_TASK_SLUG_MAX:-36}" "36")" + task_part="$(shorten_slug "$task_slug" "$task_max")" + if [[ -n "$snapshot_slug" ]]; then + snapshot_part="$(shorten_slug "$snapshot_slug" "$snapshot_max")" + checksum_input="${snapshot_slug}--${task_slug}" + checksum_part="$(checksum_slug_suffix "$checksum_input")" + printf '%s-%s-%s' "$snapshot_part" "$task_part" "$checksum_part" + return 0 + fi + checksum_part="$(checksum_slug_suffix "$task_slug")" + printf '%s-%s' "$task_part" "$checksum_part" +} + normalize_bool() { local raw="${1:-}" local fallback="${2:-0}" @@ -896,15 +958,13 @@ else fi task_slug="$(sanitize_slug "$TASK_NAME" "task")" -agent_slug="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug_raw="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug="$(shorten_slug "$agent_slug_raw" "${MUSAFETY_BRANCH_AGENT_SLUG_MAX:-24}")" snapshot_name="$(resolve_active_codex_snapshot_name)" -snapshot_slug="$(sanitize_slug "$snapshot_name" "")" +snapshot_slug="$(sanitize_optional_slug "$snapshot_name" "snapshot")" +branch_descriptor="$(compose_branch_descriptor "$snapshot_slug" "$task_slug")" timestamp="$(date +%Y%m%d-%H%M%S)" -if [[ -n "$snapshot_slug" ]]; then - branch_name_base="agent/${agent_slug}/${snapshot_slug}-${task_slug}" -else - branch_name_base="agent/${agent_slug}/${task_slug}" -fi +branch_name_base="agent/${agent_slug}/${branch_descriptor}" branch_name="$branch_name_base" worktree_root="${repo_root}/${WORKTREE_ROOT_REL}" diff --git a/templates/scripts/agent-branch-start.sh b/templates/scripts/agent-branch-start.sh index 9c99e6d..125abf5 100755 --- a/templates/scripts/agent-branch-start.sh +++ b/templates/scripts/agent-branch-start.sh @@ -86,6 +86,68 @@ sanitize_slug() { printf '%s' "$slug" } +sanitize_optional_slug() { + local raw="$1" + local fallback="${2:-snapshot}" + if [[ -z "$raw" ]]; then + printf '' + return 0 + fi + sanitize_slug "$raw" "$fallback" +} + +normalize_positive_int() { + local raw="$1" + local fallback="$2" + if [[ "$raw" =~ ^[0-9]+$ ]] && [[ "$raw" -gt 0 ]]; then + printf '%s' "$raw" + return 0 + fi + printf '%s' "$fallback" +} + +shorten_slug() { + local slug="$1" + local raw_max="$2" + local max_len + max_len="$(normalize_positive_int "$raw_max" "32")" + if [[ "${#slug}" -le "$max_len" ]]; then + printf '%s' "$slug" + return 0 + fi + local shortened="${slug:0:max_len}" + shortened="$(printf '%s' "$shortened" | sed -E 's/-+$//')" + if [[ -z "$shortened" ]]; then + shortened="${slug:0:max_len}" + fi + printf '%s' "$shortened" +} + +checksum_slug_suffix() { + local raw="$1" + local checksum + checksum="$(printf '%s' "$raw" | cksum | awk '{print $1}')" + printf '%s' "${checksum:0:6}" +} + +compose_branch_descriptor() { + local snapshot_slug="$1" + local task_slug="$2" + local snapshot_max task_max task_part snapshot_part checksum_input checksum_part + snapshot_max="$(normalize_positive_int "${MUSAFETY_BRANCH_SNAPSHOT_SLUG_MAX:-18}" "18")" + task_max="$(normalize_positive_int "${MUSAFETY_BRANCH_TASK_SLUG_MAX:-36}" "36")" + task_part="$(shorten_slug "$task_slug" "$task_max")" + if [[ -n "$snapshot_slug" ]]; then + snapshot_part="$(shorten_slug "$snapshot_slug" "$snapshot_max")" + checksum_input="${snapshot_slug}--${task_slug}" + checksum_part="$(checksum_slug_suffix "$checksum_input")" + printf '%s-%s-%s' "$snapshot_part" "$task_part" "$checksum_part" + return 0 + fi + checksum_part="$(checksum_slug_suffix "$task_slug")" + printf '%s-%s' "$task_part" "$checksum_part" +} + normalize_bool() { local raw="${1:-}" local fallback="${2:-0}" @@ -350,15 +412,13 @@ else fi task_slug="$(sanitize_slug "$TASK_NAME" "task")" -agent_slug="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug_raw="$(sanitize_slug "$AGENT_NAME" "agent")" +agent_slug="$(shorten_slug "$agent_slug_raw" "${MUSAFETY_BRANCH_AGENT_SLUG_MAX:-24}")" snapshot_name="$(resolve_active_codex_snapshot_name)" -snapshot_slug="$(sanitize_slug "$snapshot_name" "")" +snapshot_slug="$(sanitize_optional_slug "$snapshot_name" "snapshot")" +branch_descriptor="$(compose_branch_descriptor "$snapshot_slug" "$task_slug")" timestamp="$(date +%Y%m%d-%H%M%S)" -if [[ -n "$snapshot_slug" ]]; then - branch_name_base="agent/${agent_slug}/${snapshot_slug}-${task_slug}" -else - branch_name_base="agent/${agent_slug}/${task_slug}" -fi +branch_name_base="agent/${agent_slug}/${branch_descriptor}" branch_name="$branch_name_base" branch_suffix=2 diff --git a/test/install.test.js b/test/install.test.js index d37546e..6c917b4 100644 --- a/test/install.test.js +++ b/test/install.test.js @@ -1016,7 +1016,7 @@ OUT { env: { PATH: `${fakeBin}:${process.env.PATH || ''}` } }, ); assert.equal(result.status, 0, result.stderr || result.stdout); - assert.match(result.stdout, /Created branch: agent\/planner\/zeus-edix-hu-restore-snapshot(?:-\d+)?/); + assert.match(result.stdout, /Created branch: agent\/planner\/zeus-edix-hu-restore-snapshot-[0-9]{6}(?:-\d+)?/); }); test('setup agent-branch-start supports explicit snapshot override without codex-auth', () => { @@ -1033,7 +1033,34 @@ test('setup agent-branch-start supports explicit snapshot override without codex { env: { MUSAFETY_CODEX_AUTH_SNAPSHOT: 'Prod Snapshot One' } }, ); assert.equal(result.status, 0, result.stderr || result.stdout); - assert.match(result.stdout, /Created branch: agent\/bot\/prod-snapshot-one-ship-fix(?:-\d+)?/); + assert.match(result.stdout, /Created branch: agent\/bot\/prod-snapshot-one-ship-fix-[0-9]{6}(?:-\d+)?/); +}); + +test('setup agent-branch-start compacts long snapshot/task names for readable branch labels', () => { + const repoDir = initRepo(); + + let result = runNode(['setup', '--target', repoDir], repoDir); + assert.equal(result.status, 0, result.stderr || result.stdout); + seedCommit(repoDir); + + result = runCmd( + 'bash', + [ + 'scripts/agent-branch-start.sh', + 'rust-layer-phase7-dashboard-read-name-columns-and-badges', + 'codex-admin-recodee-com', + 'dev', + ], + repoDir, + { env: { MUSAFETY_CODEX_AUTH_SNAPSHOT: 'Zeus Portasmosonmagyarovar Hu Snapshot' } }, + ); + assert.equal(result.status, 0, result.stderr || result.stdout); + const createdBranch = extractCreatedBranch(result.stdout); + assert.match(createdBranch, /^agent\/codex-admin-recodee-com\/[a-z0-9-]+$/); + assert.ok(createdBranch.length <= 100, `branch should stay compact, got: ${createdBranch}`); + const branchLeaf = createdBranch.split('/').pop() || ''; + assert.ok(branchLeaf.length <= 70, `branch leaf should stay compact, got: ${branchLeaf}`); + assert.match(branchLeaf, /^zeus-portasmosonma-rust-layer-phase7-dashboard-read-name-[0-9]{6}(?:-\d+)?$/); }); test('setup agent-branch-start supports optional OpenSpec auto-bootstrap toggles', () => {