Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| People and teams are front and centre: one directory of people and agents with presence, local time, titles, teams and what each owns; profiles with manager and reports and the agents they work with; an org chart with each team's agents beside the person who leads it; and teams of any mix, with a lead, a channel, a budget agents keep to and the agents on them. Every agent is told its teams each turn (who leads, who owns what, who's around and who to page), and the team page shows exactly what. Member management is Members and invites; the people and teams guide says how. | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import type { DirectoryPerson, DirectoryTeam, PeopleDirectory } from "@g1t/contracts"; | |
| 5 | ||
| 6 | import { | |
| 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 | ||
| 19 | const 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 | ||
| 36 | const 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 | ||
| 51 | const 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 | ||
| 68 | const 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 | ||
| 92 | const 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 | ||
| 98 | test("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 | ||
| 106 | test("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 | ||
| 117 | test("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 | ||
| 129 | test("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 | ||
| 136 | test("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 | ||
| 141 | test("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 | ||
| 150 | test("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 | ||
| 158 | test("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 | }); |