Files
Peter Schilling 3a00cc7604 Accept team names and IDs, and state names, wherever the CLI takes them
Every command that takes a team now accepts its key, name, or UUID through
one shared resolver (findTeam / resolveTeam / resolveTeams), replacing the
key-only getTeamIdByKey and the ad-hoc uppercasing spread across commands.
One aliased ResolveTeam operation looks up key, name, and (for UUID-shaped
input) id in a single round trip; precedence is key, then id, then name,
applied client-side so a reference that equals one team's key and another
team's name always means the key. Keys stay the canonical downstream form:
filters that matched on team.key still do, with the server's uppercase key,
and callers that need a UUID take it from the same resolved object. An
unknown team now errors with the list of valid keys instead of an empty
result or a raw "Entity not found" from the API.

Only explicit input goes through the resolver. The configured default team
is already a normalized key, and resolving it would add a round trip to
every default-team invocation of the most-used commands for no gain. In
issue create, the interactive substring picker survives only for that
default; an explicit --team that matches nothing errors like everywhere
else.

issue query --state and issue mine --state take a workflow state name or
ID as well as the six type tokens. Names and IDs are resolved within the
queried scope (the team, the teams, or the whole workspace under
--all-teams, where a name matches every team's same-named state), so a
state from another team errors instead of silently matching nothing, and
the error lists the scope's states. Type-only input still sends the same
{ type: { in } } filter with no extra request; a mix of types and names
becomes an or-filter.

The MCP server already describes these parameters as "key, name, or ID"
and "type, name, or ID"; this brings the CLI to parity so an agent does
not need a preliminary team list to translate a name into a key.

Claude-Session: https://claude.ai/code/session_01A9qEGri4p2HZMQSuYsBmub
2026-09-05 07:19:38 -07:00

62 lines
1.7 KiB
TypeScript

import { MockLinearServer } from "./mock_linear_server.ts"
// Common Deno args for permissions used across all tests
export const commonDenoArgs = ["--allow-all", "--quiet"]
// Helper function to set up mock Linear server with common environment
export async function setupMockLinearServer(
mockResponses: Array<{
queryName: string
queryIncludes?: string
variables?: Record<string, unknown>
response: Record<string, unknown>
}>,
envVars?: Record<string, string>,
): Promise<{ server: MockLinearServer; cleanup: () => Promise<void> }> {
const server = new MockLinearServer(mockResponses)
await server.start()
Deno.env.set("LINEAR_GRAPHQL_ENDPOINT", server.getEndpoint())
Deno.env.set("LINEAR_API_KEY", "Bearer test-token")
// Set any additional environment variables
if (envVars) {
for (const [key, value] of Object.entries(envVars)) {
Deno.env.set(key, value)
}
}
const cleanup = async () => {
await server.stop()
Deno.env.delete("LINEAR_GRAPHQL_ENDPOINT")
Deno.env.delete("LINEAR_API_KEY")
// Clean up additional environment variables
if (envVars) {
for (const key of Object.keys(envVars)) {
Deno.env.delete(key)
}
}
}
return { server, cleanup }
}
export const ENG_TEAM = { id: "team-eng-id", key: "ENG", name: "Engineering" }
/**
* Mock for the shared team resolver's key/name lookup. The server matches
* keys and names case-insensitively, so pass the exact reference the test
* sends and the team it should resolve to.
*/
export function resolveTeamMock(
reference: string,
team: { id: string; key: string; name: string } = ENG_TEAM,
) {
return {
queryName: "ResolveTeam",
variables: { reference },
response: { data: { teams: { nodes: [team] } } },
}
}