Skip to content
Merged
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
5 changes: 5 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ Copyright 2026 Fabien Penso, licensed under the Apache License, Version 2.0.
Each file with adapted code has a header comment that says so and names the
changes.

The brand marks in assets/icons/brands/ are icons of Simple Icons
(https://github.com/simple-icons/simple-icons), v16.37.0, released under
CC0 1.0 Universal; they are used without changes. The marks belong to their
owners; contr uses them only to show which service a tool call goes to.

The Claude Code mascot (assets/icons/claude-mascot.svg) is the "Claude Code"
icon of LobeHub icons (https://github.com/lobehub/lobe-icons), licensed under
the MIT License; changes: the viewBox is cropped to the shape, and it has one
Expand Down
5 changes: 3 additions & 2 deletions assets/icons.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ package assets
import "embed"

// Icons holds the status icons and the line icons of docs/spec/README.md as
// `icons/<name>.svg`.
// `icons/<name>.svg`, and the brand marks of servers (Simple Icons, CC0) as
// `icons/brands/<name>.svg`.
//
//go:embed icons/*.svg
//go:embed icons/*.svg icons/brands/*.svg
var Icons embed.FS

// Fonts holds the faces of JetBrains Mono and Inter as `fonts/<name>.ttf`.
Expand Down
1 change: 1 addition & 0 deletions assets/icons/brands/atlassian.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/datadog.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/figma.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/github.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/gmail.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/googlecalendar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/googledrive.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/intercom.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/jira.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/linear.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/mixpanel.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/notion.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/slack.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/icons/brands/spotify.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions cmd/contr/e2e_chat_call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func TestChatCallDetail(t *testing.T) {
c.waitLabel(t, "lead, ")
c.settle(t)
c.press(t, "Chat")
c.waitLabel(t, "work group 10 tool calls")
c.press(t, "work group 10 tool calls")
c.waitLabel(t, "work group 12 tool calls")
c.press(t, "work group 12 tool calls")
c.waitLabel(t, "tool call Bash")
c.settle(t)
c.press(t, "tool call Bash")
Expand Down
12 changes: 10 additions & 2 deletions cmd/contr/e2e_see_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,16 @@ var seeFixtures = map[string]seeFixture{
press: []string{"Chat", "wait:image 2"},
},
"chat-tools": {
about: "the chat fixture with a turn of mixed tool calls, its work group open (D274): a call line of each kind with its icon (skill, Slack connector, contr plugin, other MCP, agent, fetch, Bash, Read, Grep), a tool of no kind with an empty slot, the label and key argument of each, and the Bash call open on its detail",
about: "the chat fixture with a turn of mixed tool calls, its work group open (D274): a call line of each kind with its icon (skill, Slack connector, contr plugin, Linear MCP and Notion connector with their brand marks, an unknown MCP server with the connector icon, agent, fetch, Bash, Read, Grep), a tool of no kind with an empty slot, the label and key argument of each, and the Bash call open on its detail",
setup: seeChatTools,
ready: "lead, ",
press: []string{"Chat", "wait:work group 10 tool calls", "work group 10 tool calls", "wait:tool call Grep", "tool call Bash", "wait:call detail Bash"},
press: []string{"Chat", "wait:work group 12 tool calls", "work group 12 tool calls", "wait:tool call Grep", "tool call Bash", "wait:call detail Bash"},
},
"chat-paths": {
about: "the chat fixture with \"Look at @app\" typed in the composer (D279): the popup above the card with the folder and files of the repo whose paths hold app, the paths with a part that starts with it first",
setup: seeChatPaths,
ready: "lead, ",
press: []string{"Chat", "type:Look at @app", "wait:@internal/app/"},
},
"chat-paths": {
about: "the chat fixture with \"Look at @app\" typed in the composer (D279): the popup above the card with the folder and files of the repo whose paths hold app, the paths with a part that starts with it first",
Expand Down Expand Up @@ -468,6 +474,8 @@ func seeChatTools(t *testing.T, h *harness) {
{"mcp__claude_ai_Slack__slack_send_message", map[string]any{"channel": "#dev", "text": "the call line has icons"}},
{"mcp__plugin_contr_contr__send", map[string]any{"to": "b-709", "body": "merge main"}},
{"mcp__linear__list_issues", map[string]any{"query": "chat rows"}},
{"mcp__claude_ai_Notion__notion_search", map[string]any{"query": "chat spec"}},
{"mcp__acme__list_things", map[string]any{"query": "rows"}},
{"Task", map[string]any{"subagent_type": "Explore", "description": "Find the call line"}},
{"WebFetch", map[string]any{"url": "https://example.com/docs/chat"}},
{"Bash", map[string]any{"command": "go test ./internal/app/chatview", "description": "Run the chat tests"}},
Expand Down
Loading
Loading