Skip to content
164 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import type { DirectoryPerson, DirectoryTeam, PeopleDirectory } from "@g1t/contracts";
5
6import {
7 type PeopleAgent,
8 agentIdsOn,
9 budgetFromText,
10 codeAccessWords,
11 directoryEntries,
12 managerChoices,
13 orgChart,
14 ownsFromText,
15 teamBlock,
16 teamsOfAgent,
17} from "./people.ts";
18
19const person = (username: string, extra: Partial<DirectoryPerson> = {}): DirectoryPerson => ({
20 user_id: `usr_${username}`,
21 username,
22 name: null,
23 avatar: null,
24 bio: null,
25 location: null,
26 pronouns: null,
27 timezone: null,
28 role: "member",
29 title: null,
30 manager: null,
31 owns: [],
32 joined_at: "2026-10-01T00:00:00Z",
33 ...extra,
34});
35
36const team = (slug: string, name: string, extra: Partial<DirectoryTeam> = {}): DirectoryTeam => ({
37 slug,
38 name,
39 description: null,
40 visibility: "visible",
41 parent: null,
42 lead: null,
43 channel: null,
44 budget_micros: null,
45 people: [],
46 agent_ids: [],
47 repos_count: 0,
48 ...extra,
49});
50
51const agent = (id: string, handle: string, extra: Partial<PeopleAgent> = {}): PeopleAgent => ({
52 id,
53 handle,
54 display_name: handle[0]!.toUpperCase() + handle.slice(1),
55 avatar: null,
56 avatar_seed: handle,
57 title: "",
58 role: "",
59 team: null,
60 department: "",
61 status: "idle",
62 responsibilities: [],
63 builtin: false,
64 spent_month_micros: 0,
65 ...extra,
66});
67
68const directory: PeopleDirectory = {
69 people: [
70 person("chase", { name: "Chase Pierce", title: "Founder", role: "owner" }),
71 person("sofia", { name: "Sofia Reyes", title: "Head of Sales", manager: "chase", owns: ["the forecast"] }),
72 person("jordan", { name: "Jordan Lee", title: "Account Executive", manager: "sofia", owns: ["Halcyon", "Bluebird"] }),
73 person("kai", { name: "Kai Nakamura", title: "Product Designer", manager: "chase" }),
74 ],
75 teams: [
76 team("sales", "Sales", {
77 lead: { kind: "user", username: "sofia", name: "Sofia Reyes", avatar: null },
78 people: [
79 { username: "sofia", role: "maintainer" },
80 { username: "jordan", role: "member" },
81 ],
82 agent_ids: ["agt_david"],
83 repos_count: 0,
84 }),
85 team("design", "Design", { people: [{ username: "kai", role: "maintainer" }], repos_count: 2 }),
86 team("night-shift", "Night shift", { lead: { kind: "agent", agent_id: "agt_atlas" }, agent_ids: ["agt_atlas"] }),
87 ],
88 base_permission: "read",
89 can_manage: true,
90};
91
92const agents = [
93 agent("agt_david", "david", { title: "CRM keeper", team: "sales" }),
94 agent("agt_atlas", "atlas", { title: "Night watch" }),
95 agent("agt_sentinel", "sentinel", { title: "Error watch", team: "night-shift", responsibilities: ["Watches errors"] }),
96];
97
98test("an agent is on the teams it was added to and its home team", () => {
99 assert.deepEqual(agentIdsOn(directory.teams[2]!, agents), ["agt_atlas", "agt_sentinel"]);
100 assert.deepEqual(
101 teamsOfAgent(directory.teams, agents[2]!).map((t) => t.slug),
102 ["night-shift"],
103 );
104});
105
106test("the directory finds people and agents in one search", () => {
107 const names = (query: string, kind: "everyone" | "people" | "agents" = "everyone") =>
108 directoryEntries(directory, agents, query, kind).map((e) => (e.kind === "person" ? e.person.username : `@${e.agent.handle}`));
109 assert.deepEqual(names("sales"), ["sofia", "jordan", "@david"]);
110 assert.deepEqual(names("halcyon"), ["jordan"]);
111 assert.deepEqual(names("errors"), ["@sentinel"]);
112 assert.deepEqual(names("", "agents"), ["@david", "@atlas", "@sentinel"]);
113 assert.deepEqual(names("night"), ["@atlas", "@sentinel"]);
114 assert.equal(names("nobody here").length, 0);
115});
116
117test("the org chart follows reporting lines, with each team's agents beside its lead", () => {
118 const chart = orgChart(directory, agents);
119 assert.deepEqual(chart.roots.map((n) => n.person.username), ["chase"]);
120 const chase = chart.roots[0]!;
121 assert.deepEqual(chase.reports.map((n) => n.person.username), ["sofia", "kai"]);
122 const sofia = chase.reports[0]!;
123 assert.deepEqual(sofia.agents.map((a) => a.handle), ["david"]);
124 assert.deepEqual(sofia.reports.map((n) => n.person.username), ["jordan"]);
125 // A team an agent leads sits apart, with its agents.
126 assert.deepEqual(chart.unled.map((u) => [u.team.slug, u.agents.map((a) => a.handle)]), [["night-shift", ["atlas", "sentinel"]]]);
127});
128
129test("no one goes missing from the org chart, even in a loop", () => {
130 const looped: PeopleDirectory = { ...directory, people: [person("a", { manager: "b" }), person("b", { manager: "a" })] };
131 const chart = orgChart(looped, []);
132 const all = (nodes: typeof chart.roots): string[] => nodes.flatMap((n) => [n.person.username, ...all(n.reports)]);
133 assert.deepEqual(all(chart.roots).sort(), ["a", "b"]);
134});
135
136test("someone can report to anyone but themselves and the people under them", () => {
137 assert.deepEqual(managerChoices(directory.people, "sofia").map((p) => p.username), ["chase", "kai"]);
138 assert.deepEqual(managerChoices(directory.people, "jordan").map((p) => p.username), ["chase", "sofia", "kai"]);
139});
140
141test("forms read plainly", () => {
142 assert.deepEqual(ownsFromText("storefront\n the release process ,, billing"), ["storefront", "the release process", "billing"]);
143 assert.equal(budgetFromText(""), 0);
144 assert.equal(budgetFromText("$150"), 150_000_000);
145 assert.equal(budgetFromText("1,250.50"), 1_250_500_000);
146 assert.equal(budgetFromText("lots"), null);
147 assert.equal(budgetFromText("-5"), null);
148});
149
150test("access to Code says where it comes from", () => {
151 assert.equal(codeAccessWords({ role: "owner" }, "read", []).summary, "Admin on every repository, as an owner");
152 const kai = codeAccessWords({ role: "member" }, "read", [directory.teams[1]!]);
153 assert.equal(kai.summary, "Read on every repository, the workspace's base permission");
154 assert.deepEqual(kai.through, ["Roles on 2 repositories through Design"]);
155 assert.equal(codeAccessWords({ role: "member" }, "none", []).summary, "Only repositories they're given a role on");
156});
157
158test("a team's part of what an agent is told", () => {
159 const told = "## Your teams\n\nIntro.\n\n### Sales\n\nLed by Sofia.\n- @sofia\n\n### Support\n\n- @dev";
160 assert.equal(teamBlock(told, "Sales"), "### Sales\n\nLed by Sofia.\n- @sofia");
161 assert.equal(teamBlock(told, "Support"), "### Support\n\n- @dev");
162 assert.equal(teamBlock(told, "Design"), null);
163 assert.equal(teamBlock(null, "Sales"), null);
164});