Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
131 changes: 131 additions & 0 deletions extensions/cli/src/constants/agent-session-ordering.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { describe, expect, it } from "vitest";

import {
AGENT_STATUS_ORDER,
compareAgentStatus,
compareAlphabetical,
comparePRStatus,
getAgentStatusSortIndex,
getPRStatusSortIndex,
PR_STATUS_ORDER,
} from "./agent-session-ordering.js";

describe("agent-session-ordering", () => {
describe("PR_STATUS_ORDER", () => {
it("should have the correct order", () => {
expect(PR_STATUS_ORDER).toEqual([
"No PR",
"Draft",
"Open",
"Merged",
"Closed",
]);
});
});

describe("AGENT_STATUS_ORDER", () => {
it("should have the correct order", () => {
expect(AGENT_STATUS_ORDER).toEqual([
"Planning",
"Working",
"Blocked",
"Done",
]);
});
});

describe("getPRStatusSortIndex", () => {
it("should return correct indices for known statuses", () => {
expect(getPRStatusSortIndex("No PR")).toBe(0);
expect(getPRStatusSortIndex("Draft")).toBe(1);
expect(getPRStatusSortIndex("Open")).toBe(2);
expect(getPRStatusSortIndex("Merged")).toBe(3);
expect(getPRStatusSortIndex("Closed")).toBe(4);
});

it("should return Infinity for unknown statuses", () => {
expect(getPRStatusSortIndex("Unknown")).toBe(Infinity);
expect(getPRStatusSortIndex("Pending")).toBe(Infinity);
});
});

describe("getAgentStatusSortIndex", () => {
it("should return correct indices for known statuses", () => {
expect(getAgentStatusSortIndex("Planning")).toBe(0);
expect(getAgentStatusSortIndex("Working")).toBe(1);
expect(getAgentStatusSortIndex("Blocked")).toBe(2);
expect(getAgentStatusSortIndex("Done")).toBe(3);
});

it("should be case-insensitive", () => {
expect(getAgentStatusSortIndex("PLANNING")).toBe(0);
expect(getAgentStatusSortIndex("planning")).toBe(0);
expect(getAgentStatusSortIndex("PlAnNiNg")).toBe(0);
expect(getAgentStatusSortIndex("WORKING")).toBe(1);
expect(getAgentStatusSortIndex("working")).toBe(1);
});

it("should return Infinity for unknown statuses", () => {
expect(getAgentStatusSortIndex("Unknown")).toBe(Infinity);
expect(getAgentStatusSortIndex("Pending")).toBe(Infinity);
});
});

describe("comparePRStatus", () => {
it("should sort PR statuses in the correct order", () => {
const statuses = ["Closed", "No PR", "Open", "Draft", "Merged"];
const sorted = statuses.sort(comparePRStatus);
expect(sorted).toEqual(["No PR", "Draft", "Open", "Merged", "Closed"]);
});

it("should place unknown statuses at the end", () => {
const statuses = ["Open", "Unknown", "Draft", "Pending"];
const sorted = statuses.sort(comparePRStatus);
expect(sorted.slice(0, 2)).toEqual(["Draft", "Open"]);
// Unknown statuses should be at the end, alphabetically sorted
expect(sorted.slice(2)).toEqual(["Pending", "Unknown"]);
});

it("should sort unknown statuses alphabetically", () => {
const statuses = ["Zebra", "Apple", "No PR"];
const sorted = statuses.sort(comparePRStatus);
expect(sorted).toEqual(["No PR", "Apple", "Zebra"]);
});
});

describe("compareAgentStatus", () => {
it("should sort agent statuses in the correct order", () => {
const statuses = ["Done", "Planning", "Blocked", "Working"];
const sorted = statuses.sort(compareAgentStatus);
expect(sorted).toEqual(["Planning", "Working", "Blocked", "Done"]);
});

it("should handle case-insensitive sorting", () => {
const statuses = ["DONE", "planning", "BLOCKED", "Working"];
const sorted = statuses.sort(compareAgentStatus);
expect(sorted).toEqual(["planning", "Working", "BLOCKED", "DONE"]);
});

it("should place unknown statuses at the end", () => {
const statuses = ["Working", "Unknown", "Planning", "Pending"];
const sorted = statuses.sort(compareAgentStatus);
expect(sorted.slice(0, 2)).toEqual(["Planning", "Working"]);
// Unknown statuses should be at the end, alphabetically sorted
expect(sorted.slice(2)).toEqual(["Pending", "Unknown"]);
});
});

describe("compareAlphabetical", () => {
it("should sort strings alphabetically", () => {
const items = ["Zebra", "Apple", "Banana"];
const sorted = items.sort(compareAlphabetical);
expect(sorted).toEqual(["Apple", "Banana", "Zebra"]);
});

it("should be case-sensitive by default", () => {
const items = ["zebra", "Apple", "banana"];
const sorted = items.sort(compareAlphabetical);
expect(sorted).toEqual(["Apple", "banana", "zebra"]);
});
});
});
88 changes: 88 additions & 0 deletions extensions/cli/src/constants/agent-session-ordering.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* Agent session categorization and ordering constants for hub.continue.dev
*
* These define the canonical ordering for agent session categories in the
* kanban board view.
*/

/**
* PR Status ordering
* Unknown values should appear after these defined states
*/
export const PR_STATUS_ORDER = [
"No PR",
"Draft",
"Open",
"Merged",
"Closed",
] as const;

export type PRStatus = (typeof PR_STATUS_ORDER)[number];

/**
* Agent Status ordering
* Unknown values should appear after these defined states
*/
export const AGENT_STATUS_ORDER = [
"Planning",
"Working",
"Blocked",
"Done",
] as const;

export type AgentStatus = (typeof AGENT_STATUS_ORDER)[number];

/**
* Get the sort index for a PR status
* @param status The PR status string
* @returns Sort index (lower = earlier in list), or Infinity for unknown values
*/
export function getPRStatusSortIndex(status: string): number {
const index = PR_STATUS_ORDER.indexOf(status as PRStatus);
return index === -1 ? Infinity : index;
}

/**
* Get the sort index for an agent status
* @param status The agent status string (case-insensitive)
* @returns Sort index (lower = earlier in list), or Infinity for unknown values
*/
export function getAgentStatusSortIndex(status: string): number {
const normalized =
status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();
const index = AGENT_STATUS_ORDER.indexOf(normalized as AgentStatus);
return index === -1 ? Infinity : index;
}

/**
* Comparator for sorting by PR status
*/
export function comparePRStatus(a: string, b: string): number {
const indexA = getPRStatusSortIndex(a);
const indexB = getPRStatusSortIndex(b);
if (indexA !== indexB) {
return indexA - indexB;
}
// Fallback to alphabetical for unknown values
return a.localeCompare(b);
}

/**
* Comparator for sorting by agent status
*/
export function compareAgentStatus(a: string, b: string): number {
const indexA = getAgentStatusSortIndex(a);
const indexB = getAgentStatusSortIndex(b);
if (indexA !== indexB) {
return indexA - indexB;
}
// Fallback to alphabetical for unknown values
return a.localeCompare(b);
}

/**
* For Creator and Repository groupings, use alphabetical sorting
*/
export function compareAlphabetical(a: string, b: string): number {
return a.localeCompare(b);
}
2 changes: 2 additions & 0 deletions extensions/cli/src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./agent-session-ordering.js";
export * from "./session.js";
Loading
Loading