feat(agents): add narrowly-scoped agent sort shim and install at plugin entry

OpenCode 1.4.x ignores the agent `order` field (sst/opencode#19127), so its
`Agent.list()` sorts purely by `agent.name` via Remeda `sortBy` which uses
native string `<`/`>` comparison. Without intervention, the four core agents
fall into alphabetical order (Atlas -> Hephaestus -> Prometheus -> Sisyphus),
which is not the canonical sisyphus -> hephaestus -> prometheus -> atlas order
the project ships.

Prior attempts to bias the sort key with invisible characters (ZWSP,
U+2060 WORD JOINER, U+00AD SOFT HYPHEN, ANSI escape) all caused
`Bun.stringWidth()` vs terminal-width drift, producing visible gaps and
column truncation in the TUI status bar (#3259, #3238).

Solution: a narrowly-scoped shim of `Array.prototype.toSorted` and
`Array.prototype.sort` that activates only when the array contains two or
more agent objects whose `.name` matches a canonical core display name.
The activation predicate guards against mixed-type arrays so unrelated
`.sort()` / `.toSorted()` calls (string arrays, number arrays, mixed
objects) execute native behavior unchanged. Install is idempotent.

Cubic P1 mitigations from PR #3267:
- `isAgentArray` rejects any array with non-object or null elements,
  eliminating the throw-on-mixed-array failure mode.
- Strict activation predicate (>= 2 ranked elements) keeps the global
  prototype patch from affecting unrelated sort calls.

Remove this shim once OpenCode honors the agent `order` field
(sst/opencode#19127).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-27 16:39:37 +09:00
parent 557d66fc4c
commit dffe5a305b
3 changed files with 286 additions and 0 deletions
+168
View File
@@ -0,0 +1,168 @@
/// <reference types="bun-types" />
import { beforeAll, describe, expect, test } from "bun:test"
import { installAgentSortShim } from "./agent-sort-shim"
describe("agent-sort-shim", () => {
beforeAll(() => {
installAgentSortShim()
})
describe("#given an array of all 4 core agent objects in random order", () => {
describe("#when toSorted with alphabetical compareFn", () => {
test("#then returns canonical sisyphus->hephaestus->prometheus->atlas order", () => {
// given
const sisyphus = { name: "Sisyphus - Ultraworker" }
const hephaestus = { name: "Hephaestus - Deep Agent" }
const prometheus = { name: "Prometheus - Plan Builder" }
const atlas = { name: "Atlas - Plan Executor" }
const input = [atlas, prometheus, hephaestus, sisyphus]
// when
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
// then
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas])
})
})
})
describe("#given 4 core agents mixed with 2 non-core agent objects", () => {
describe("#when toSorted with alphabetical compareFn", () => {
test("#then core agents come first in canonical order followed by non-core agents alphabetically", () => {
// given
const sisyphus = { name: "Sisyphus - Ultraworker" }
const hephaestus = { name: "Hephaestus - Deep Agent" }
const prometheus = { name: "Prometheus - Plan Builder" }
const atlas = { name: "Atlas - Plan Executor" }
const build = { name: "build" }
const plan = { name: "plan" }
const input = [atlas, build, prometheus, plan, hephaestus, sisyphus]
// when
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
// then
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas, build, plan])
})
})
})
describe("#given an array with only one core agent and several non-core agent-like objects", () => {
describe("#when toSorted with case-sensitive string-comparison compareFn", () => {
test("#then activation predicate fails and result is ASCII-sensitive order with capital S before lowercase letters", () => {
// given
const oracle = { name: "oracle" }
const librarian = { name: "librarian" }
const sisyphus = { name: "Sisyphus - Ultraworker" }
const explore = { name: "explore" }
const input = [oracle, librarian, sisyphus, explore]
// when
const result = input.toSorted((a, b) =>
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
)
// then
expect(result).toEqual([sisyphus, explore, librarian, oracle])
})
})
})
describe("#given a mixed-type array containing null, objects, a string, and a number", () => {
describe("#when toSorted with a string-coercing compareFn", () => {
test("#then activation predicate fails, shim does not throw, and result matches native semantics", () => {
// given
const sisyphusObj = { name: "Sisyphus - Ultraworker" }
const hephaestusObj = { name: "Hephaestus - Deep Agent" }
const input: unknown[] = [null, sisyphusObj, "string", 42, hephaestusObj]
const compare = (a: unknown, b: unknown): number => {
const sa = String(a)
const sb = String(b)
if (sa < sb) return -1
if (sa > sb) return 1
return 0
}
// when
const result = input.toSorted(compare)
// then
expect(result).toEqual([42, sisyphusObj, hephaestusObj, null, "string"])
})
})
})
describe("#given a plain string array", () => {
describe("#when toSorted with no compareFn", () => {
test("#then returns native alphabetical ordering untouched", () => {
// given
const input = ["zebra", "apple", "mango"]
// when
const result = input.toSorted()
// then
expect(result).toEqual(["apple", "mango", "zebra"])
})
})
})
describe("#given a number array", () => {
describe("#when sort with numeric compareFn (in-place)", () => {
test("#then mutates the array and returns the same reference in ascending order", () => {
// given
const input = [3, 1, 4, 1, 5, 9, 2, 6]
// when
const result = input.sort((a, b) => a - b)
// then
expect(result).toBe(input)
expect(input).toEqual([1, 1, 2, 3, 4, 5, 6, 9])
})
})
})
describe("#given agent objects with all 4 core display names in random order", () => {
describe("#when sort with alphabetical compareFn (in-place)", () => {
test("#then mutates the original array to canonical order", () => {
// given
const sisyphus = { name: "Sisyphus - Ultraworker" }
const hephaestus = { name: "Hephaestus - Deep Agent" }
const prometheus = { name: "Prometheus - Plan Builder" }
const atlas = { name: "Atlas - Plan Executor" }
const input = [atlas, prometheus, hephaestus, sisyphus]
// when
const result = input.sort((a, b) => a.name.localeCompare(b.name))
// then
expect(result).toBe(input)
expect(input).toEqual([sisyphus, hephaestus, prometheus, atlas])
})
})
})
describe("#given installAgentSortShim has been invoked multiple times", () => {
describe("#when toSorted is called on core agents after duplicate installs", () => {
test("#then result is canonical order with no double-wrapping side effects", () => {
// given
installAgentSortShim()
installAgentSortShim()
const sisyphus = { name: "Sisyphus - Ultraworker" }
const hephaestus = { name: "Hephaestus - Deep Agent" }
const prometheus = { name: "Prometheus - Plan Builder" }
const atlas = { name: "Atlas - Plan Executor" }
const input = [atlas, prometheus, hephaestus, sisyphus]
// when
const result = input.toSorted((a, b) => a.name.localeCompare(b.name))
// then
expect(result).toEqual([sisyphus, hephaestus, prometheus, atlas])
})
})
})
})