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.
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 4 | import { pagePath, underWorkspace, workspacePage, workspaceRedirect } from "./workspace-nav.ts"; |
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 5 | |
| Merge branch 'worktree-agent-ad7c6d88d93adc817' | 6 | test("a path is one of the workspace's pages, or none", () => { |
| 7 | assert.equal(workspacePage("/acme", "acme"), "overview"); | |
| 8 | assert.equal(workspacePage("/Acme/", "acme"), "overview"); | |
| 9 | assert.equal(workspacePage("/acme.data", "acme"), "overview"); | |
| 10 | assert.equal(workspacePage("/acme/-/projects", "acme"), "projects"); | |
| 11 | assert.equal(workspacePage("/acme/-/people", "acme"), "people"); | |
| 12 | assert.equal(workspacePage("/acme/-/packages", "acme"), "packages"); | |
| 13 | assert.equal(workspacePage("/acme/-/teams", "acme"), "teams"); | |
| 14 | assert.equal(workspacePage("/acme/-/insights", "acme"), "insights"); | |
| 15 | // One package or team has a page of its own; settings and the rest have headings. | |
| 16 | assert.equal(workspacePage("/acme/-/packages/npm/web", "acme"), null); | |
| 17 | assert.equal(workspacePage("/acme/-/teams/web", "acme"), null); | |
| 18 | assert.equal(workspacePage("/acme/-/settings", "acme"), null); | |
| 19 | assert.equal(workspacePage("/acme/-/agents", "acme"), null); | |
| 20 | assert.equal(workspacePage("/acme/web", "acme"), null); | |
| 21 | assert.equal(workspacePage("/other", "acme"), null); | |
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 22 | }); |
| 23 | ||
| 24 | test("old addresses go to where their pages are now", () => { | |
| 25 | assert.equal(workspaceRedirect("/acme/-/members"), "/acme/-/people"); | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 26 | assert.equal(workspaceRedirect("/acme/-/home", "?x=1"), "/acme/-/today?x=1"); |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 27 | // Code's Overview lives at -/overview now: not an old address. |
| 28 | assert.equal(workspaceRedirect("/acme/-/overview"), null); | |
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 29 | assert.equal(workspaceRedirect("/acme/-/soon/teams"), "/acme/-/teams"); |
| 30 | assert.equal(workspaceRedirect("/acme/-/soon/insights", "?x=1"), "/acme/-/insights?x=1"); | |
| 31 | assert.equal(workspaceRedirect("/acme/-/soon/board"), null); | |
| 32 | assert.equal(workspaceRedirect("/acme/-/people"), null); | |
| 33 | assert.equal(workspaceRedirect("/acme/web"), null); | |
| 34 | }); | |
| 35 | ||
| Merge branch 'worktree-agent-ad7c6d88d93adc817' | 36 | test("?tab= opens that page, keeping the rest of the query", () => { |
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 37 | assert.equal(workspaceRedirect("/acme", "?tab=repositories"), "/acme/-/projects"); |
| 38 | assert.equal(workspaceRedirect("/acme", "?tab=projects&q=api"), "/acme/-/projects?q=api"); | |
| 39 | assert.equal(workspaceRedirect("/acme", "?tab=members"), "/acme/-/people"); | |
| 40 | assert.equal(workspaceRedirect("/acme", "?tab=overview"), "/acme"); | |
| Merge branch 'worktree-agent-ad7c6d88d93adc817' | 41 | assert.equal(workspaceRedirect("/acme", "?tab=settings"), "/acme/-/settings"); |
| Navigation: the workspace's own page with tabs, pins and recent in the sidebar | 42 | assert.equal(workspaceRedirect("/acme", "?tab=nonsense"), null); |
| 43 | assert.equal(workspaceRedirect("/acme", ""), null); | |
| 44 | }); | |
| Billing: credits with a kind and expiry, discounts instead of comped, and safer charging | 45 | |
| 46 | test("a click's data request is for the same page as a full load", () => { | |
| 47 | assert.equal(pagePath("/acme/-/insights.data"), "/acme/-/insights"); | |
| 48 | assert.equal(pagePath("/acme/-/insights/"), "/acme/-/insights"); | |
| 49 | assert.equal(workspaceRedirect("/acme/-/members.data", "?_routes=routes%2Fworkspace%2Fmoved-members"), "/acme/-/people"); | |
| 50 | assert.equal(workspaceRedirect("/acme/-/members.data", "?_routes=x&q=ada"), "/acme/-/people?q=ada"); | |
| 51 | }); | |
| Merge branch 'worktree-agent-a8385d293d42c913a' | 52 | |
| 53 | test("an alias or old name leads to the same page under the workspace", () => { | |
| 54 | assert.equal(underWorkspace("/g1t", "", "flagon-io"), "/flagon-io"); | |
| 55 | assert.equal(underWorkspace("/g1t/g1t/issues", "?q=is%3Aopen", "flagon-io"), "/flagon-io/g1t/issues?q=is%3Aopen"); | |
| 56 | assert.equal(underWorkspace("/g1t/g1t/blob/main/README.md", "", "flagon-io"), "/flagon-io/g1t/blob/main/README.md"); | |
| 57 | assert.equal(underWorkspace("/g1t/-/people/", "", "flagon-io"), "/flagon-io/-/people"); | |
| 58 | }); | |
| 59 | ||
| 60 | test("a click's data request for an alias leads to the page, not its data", () => { | |
| 61 | assert.equal(underWorkspace("/g1t.data", "?_routes=routes%2Fworkspace%2Flayout", "flagon-io"), "/flagon-io"); | |
| 62 | assert.equal( | |
| 63 | underWorkspace("/g1t/g1t/pulls.data", "?_routes=routes%2Frepo%2Flayout&state=closed", "flagon-io"), | |
| 64 | "/flagon-io/g1t/pulls?state=closed", | |
| 65 | ); | |
| 66 | }); | |
| Chat and workspace agents: channels, DMs and named agents you talk to | 67 | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 68 | test("the dock's mode follows the address", async () => { |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 69 | const { modeOf, modeHome, homePath } = await import("./workspace-nav.ts"); |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 70 | assert.equal(modeOf("/", "acme"), "today"); |
| 71 | assert.equal(modeOf("/acme", "acme"), "today"); | |
| 72 | assert.equal(modeOf("/acme/-/today", "acme"), "today"); | |
| Chat controls, public profiles, shadcn selects, and no Docs tab in a project | 73 | // g1t's own public pages light no mode. |
| 74 | assert.equal(modeOf("/explore", "acme"), "site"); | |
| 75 | assert.equal(modeOf("/u/ada", "acme"), "site"); | |
| 76 | assert.equal(modeOf("/search.data", "acme"), "site"); | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 77 | assert.equal(modeOf("/notifications", "acme"), "notifications"); |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 78 | assert.equal(modeOf("/settings/emails", "acme"), "account"); |
| Chat and workspace agents: channels, DMs and named agents you talk to | 79 | assert.equal(modeOf("/acme/-/chat/general", "acme"), "chat"); |
| 80 | assert.equal(modeOf("/acme/-/chat/dm/c1.data", "acme"), "chat"); | |
| 81 | assert.equal(modeOf("/acme/-/agents", "acme"), "agents"); | |
| 82 | assert.equal(modeOf("/acme/-/agents/ship/profile", "acme"), "agents"); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 83 | assert.equal(modeOf("/acme/-/context", "acme"), "agents"); |
| 84 | assert.equal(modeOf("/acme/-/memory", "acme"), "agents"); | |
| Artifacts is a mode in the rail, the shell and the phone's tab bar in place of Docs: its home lists everything you can open by day or as cards under All, Yours and Shared with you, with search, filters and tiles to start a doc (slides, designs and dashboards say they are coming soon), and its sidebar holds favorites, spaces, Private, Shared, projects' docs and the trash. | 85 | assert.equal(modeOf("/acme/-/artifacts", "acme"), "artifacts"); |
| 86 | assert.equal(modeOf("/acme/-/artifacts/spaces/general", "acme"), "artifacts"); | |
| 87 | // Docs mode is gone: its old addresses are nobody's mode, so they fall to Code's not-found page. | |
| 88 | assert.equal(modeOf("/acme/-/docs", "acme"), "code"); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 89 | assert.equal(modeOf("/acme/-/overview", "acme"), "code"); |
| 90 | assert.equal(modeOf("/acme/-/projects", "acme"), "code"); | |
| 91 | assert.equal(modeOf("/acme/-/security", "acme"), "code"); | |
| 92 | assert.equal(modeOf("/acme/-/security/settings", "acme"), "workspace"); | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 93 | assert.equal(modeOf("/acme/-/people", "acme"), "people"); |
| 94 | assert.equal(modeOf("/acme/-/teams/web", "acme"), "people"); | |
| 95 | assert.equal(modeOf("/acme/-/apps", "acme"), "apps"); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 96 | assert.equal(modeOf("/acme/-/billing", "acme"), "workspace"); |
| 97 | assert.equal(modeOf("/acme/-/tokens", "acme"), "workspace"); | |
| 98 | assert.equal(modeOf("/acme/-/workspace", "acme"), "workspace"); | |
| Chat and workspace agents: channels, DMs and named agents you talk to | 99 | assert.equal(modeOf("/acme/web/pulls", "acme"), "code"); |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 100 | assert.equal(modeOf("/new", "acme"), "code"); |
| 101 | // Another workspace's chat is not this one's mode; its repositories are Code's. | |
| Chat and workspace agents: channels, DMs and named agents you talk to | 102 | assert.equal(modeOf("/other/-/chat", "acme"), "code"); |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 103 | assert.equal(modeHome("today", "acme"), "/acme/-/today"); |
| 104 | assert.equal(modeHome("notifications", "acme"), "/notifications"); | |
| 105 | assert.equal(modeHome("people", "acme"), "/acme/-/people"); | |
| 106 | assert.equal(modeHome("apps", "acme"), "/acme/-/apps"); | |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 107 | assert.equal(modeHome("code", "acme"), "/acme/-/overview"); |
| 108 | assert.equal(modeHome("workspace", "acme"), "/acme/-/workspace"); | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 109 | assert.equal(homePath("acme"), "/acme/-/today"); |
| Merge the workspace shell: navigation and phone shell, g1t as orchestrator, agents in roles with audience-checked reads, reactions and custom emoji, live notifications and browser push, the homepage tour (agents 0002, chat 0002) | 110 | assert.equal(homePath("acme", "?agent=new"), "/acme/-/overview?agent=new"); |
| 111 | assert.equal(homePath("acme", "?tab=landed&_routes=x"), "/acme/-/overview?tab=landed"); | |
| Chat and workspace agents: channels, DMs and named agents you talk to | 112 | }); |
| 113 | ||
| 114 | test("a member without Code access is sent around Code's pages", async () => { | |
| 115 | const { codeGate } = await import("./workspace-nav.ts"); | |
| 116 | const none = ["acme"]; | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 117 | assert.equal(codeGate("/", "", none, "acme"), "/acme/-/today"); |
| Chat and workspace agents: channels, DMs and named agents you talk to | 118 | assert.equal(codeGate("/", "", none, "other"), null); |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 119 | assert.equal(codeGate("/acme", "", none, "acme"), "/acme/-/today"); |
| Chat and workspace agents: channels, DMs and named agents you talk to | 120 | assert.equal(codeGate("/acme/web/pull/3", "?x=1", none, "acme"), "/acme/-/code-access?from=%2Facme%2Fweb%2Fpull%2F3%3Fx%3D1"); |
| 121 | assert.equal(codeGate("/acme/-/projects", "", none, "acme"), "/acme/-/code-access?from=%2Facme%2F-%2Fprojects"); | |
| 122 | assert.equal(codeGate("/acme/-/chat/general", "", none, "acme"), null); | |
| 123 | assert.equal(codeGate("/acme/-/code-access", "", none, "acme"), null); | |
| 124 | assert.equal(codeGate("/other/web", "", none, "acme"), null); | |
| 125 | assert.equal(codeGate("/acme/web", "", [], "acme"), null); | |
| 126 | }); |
This file's history is long; its oldest lines are credited to the oldest commit read.