UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

201 lines • 10 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { getIssue, listIssueComments, listTeamCycles, listTeamDocuments, listTeamIssues, listTeamLabels, listTeamMembers, listTeamProjects, listTeams, resolveTeam, searchIssues, } from "../../../../core/linear/client.js"; import { normalizeComment, normalizeCycle, normalizeDocument, normalizeIssue, normalizeLabel, normalizeProject, normalizeTeam, normalizeUser, projectIssueRows, } from "../../../../core/linear/normalize.js"; import { jsonBytes } from "../../../../core/render/json.js"; import { enoent } from "../../../../errors/fs.js"; import { IOResult } from "../../../../io/types.js"; import { FlagView } from "../../../spec/flag_view.js"; import { pickString } from "../../../../utils/records.js"; import { firstText, resolveIssue } from "./util.js"; function requireTeam(fl) { const team = fl.asStr('team'); if (team === undefined || team === '') throw new Error('--team is required'); return team; } async function allUsers(accessor) { const teams = await listTeams(accessor.transport); const seen = new Set(); const users = []; for (const team of teams) { const teamId = typeof team.id === 'string' ? team.id : ''; for (const user of await listTeamMembers(accessor.transport, teamId)) { const uid = user.id; if (typeof uid !== 'string' || seen.has(uid)) continue; seen.add(uid); users.push(user); } } return users; } export async function teamList(accessor, _paths, _texts, _ctx) { let teams = await listTeams(accessor.transport); if (accessor.teamIds !== null && accessor.teamIds.length > 0) { const keep = new Set(accessor.teamIds); teams = teams.filter((team) => typeof team.id === 'string' && keep.has(team.id)); } return [jsonBytes(teams.map((team) => normalizeTeam(team))), new IOResult()]; } export async function teamGet(accessor, _paths, texts, _ctx) { const team = await resolveTeam(accessor.transport, firstText(texts, 'team key')); return [jsonBytes(normalizeTeam(team)), new IOResult()]; } export async function teamMembers(accessor, _paths, texts, _ctx) { const team = await resolveTeam(accessor.transport, firstText(texts, 'team key')); const teamId = typeof team.id === 'string' ? team.id : ''; const users = await listTeamMembers(accessor.transport, teamId); return [jsonBytes(users.map((user) => normalizeUser(user))), new IOResult()]; } export async function issueList(accessor, _paths, _texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const issues = await listTeamIssues(accessor.transport, teamId); return [jsonBytes(issues.map((issue) => normalizeIssue(issue))), new IOResult()]; } export async function issueGet(accessor, _paths, texts, _ctx) { const issueId = await resolveIssue(accessor, firstText(texts, 'issue key')); const issue = await getIssue(accessor.transport, issueId); return [jsonBytes(normalizeIssue(issue)), new IOResult()]; } export async function projectList(accessor, _paths, _texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const projects = await listTeamProjects(accessor.transport, teamId); const payload = []; for (const project of projects) { const projectId = typeof project.id === 'string' ? project.id : ''; const rows = projectIssueRows(await listTeamIssues(accessor.transport, teamId, undefined, [projectId]), projectId); payload.push(normalizeProject(project, { teamId, teamKey: pickString(team, 'key'), teamName: pickString(team, 'name'), issues: rows, })); } return [jsonBytes(payload), new IOResult()]; } export async function projectGet(accessor, _paths, texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const projectId = firstText(texts, 'project id'); const projects = await listTeamProjects(accessor.transport, teamId); for (const project of projects) { if (project.id === projectId) { const rows = projectIssueRows(await listTeamIssues(accessor.transport, teamId, undefined, [projectId]), projectId); return [ jsonBytes(normalizeProject(project, { teamId, teamKey: pickString(team, 'key'), teamName: pickString(team, 'name'), issues: rows, })), new IOResult(), ]; } } throw enoent(projectId); } export async function cycleList(accessor, _paths, _texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const cycles = await listTeamCycles(accessor.transport, teamId); return [jsonBytes(cycles.map((cycle) => normalizeCycle(cycle, teamId))), new IOResult()]; } export async function cycleCurrent(accessor, _paths, _texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const cycles = await listTeamCycles(accessor.transport, teamId); let current; for (const cycle of cycles) { if (current === undefined) { current = cycle; continue; } const a = typeof cycle.number === 'number' ? cycle.number : 0; const b = typeof current.number === 'number' ? current.number : 0; if (a > b) current = cycle; } if (current === undefined) throw enoent('cycles'); return [jsonBytes(normalizeCycle(current, teamId)), new IOResult()]; } export async function cycleGet(accessor, _paths, texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const cycleId = firstText(texts, 'cycle id'); const cycles = await listTeamCycles(accessor.transport, teamId); for (const cycle of cycles) { if (cycle.id === cycleId) return [jsonBytes(normalizeCycle(cycle, teamId)), new IOResult()]; } throw enoent(cycleId); } export async function labelList(accessor, _paths, _texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const labels = await listTeamLabels(accessor.transport, teamId); return [jsonBytes(labels.map((label) => normalizeLabel(label))), new IOResult()]; } export async function commentList(accessor, _paths, texts, _ctx) { const issueId = await resolveIssue(accessor, firstText(texts, 'issue key')); const issue = await getIssue(accessor.transport, issueId); const issueKey = typeof issue.identifier === 'string' ? issue.identifier : null; const comments = await listIssueComments(accessor.transport, issueId); return [ jsonBytes(comments.map((comment) => normalizeComment(comment, issueId, issueKey))), new IOResult(), ]; } export async function userList(accessor, _paths, _texts, _ctx) { const users = await allUsers(accessor); return [jsonBytes(users.map((user) => normalizeUser(user))), new IOResult()]; } export async function userGet(accessor, _paths, texts, _ctx) { const email = firstText(texts, 'user email'); for (const user of await allUsers(accessor)) { if (user.email === email) return [jsonBytes(normalizeUser(user)), new IOResult()]; } throw enoent(email); } export async function documentList(accessor, _paths, _texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const documents = await listTeamDocuments(accessor.transport, teamId); return [jsonBytes(documents.map((document) => normalizeDocument(document))), new IOResult()]; } export async function documentGet(accessor, _paths, texts, ctx) { const team = await resolveTeam(accessor.transport, requireTeam(new FlagView(ctx.flags))); const teamId = typeof team.id === 'string' ? team.id : ''; const documentId = firstText(texts, 'document id'); const documents = await listTeamDocuments(accessor.transport, teamId); for (const document of documents) { if (document.id === documentId) return [jsonBytes(normalizeDocument(document)), new IOResult()]; } throw enoent(documentId); } export async function search(accessor, _paths, texts, ctx) { const fl = new FlagView(ctx.flags); const flagQuery = fl.asStr('query'); const query = flagQuery !== undefined && flagQuery !== '' ? flagQuery : (texts[0] ?? null); if (query === null || query === '') throw new Error('a search query is required'); const results = await searchIssues(accessor.transport, query); return [jsonBytes(results), new IOResult()]; } //# sourceMappingURL=reads.js.map